Uma estratégia de price action que reage a lacunas de abertura entre velas consecutivas. Ela espera que uma nova barra abra além
da máxima ou mínima anterior por uma distância configurável em pips, entra na direção da reversão esperada e gerencia a operação
com stops fixos, alvos e um trailing stop escalonado opcional.
Como funciona
A estratégia monitora um único símbolo usando o período selecionado.
Quando uma nova vela é formada, ela compara o preço de abertura com a vela anterior:
Se a abertura estiver abaixo da mínima anterior menos GapPips, a estratégia entra em uma posição comprada esperando um recuo altista.
Se a abertura estiver acima da máxima anterior mais GapPips, ela entra em uma posição vendida antecipando uma correção descendente.
Dentro de uma operação, o gerenciamento de risco é tratado inteiramente dentro da estratégia:
Um stop-loss fixo é colocado a StopLossPips abaixo (para comprado) ou acima (para vendido) do preço de entrada.
Um take-profit fixo é definido a TakeProfitPips do preço de entrada na direção da operação.
Um trailing stop pode ser ativado; ele só se move depois que o preço avançou TrailingStopPips + TrailingStepPips e então
bloqueia lucros mantendo o stop a TrailingStopPips do preço mais favorável.
Os níveis de proteção são avaliados em cada vela concluída usando os extremos de máxima/mínima para que toques intrabarra disparem saídas de forma confiável.
Ordens abertas são canceladas antes de tomar uma nova posição, e reversões de posição fecham automaticamente o lado oposto.
Parâmetros
OrderVolume = 0.1 — volume de trading em lotes para cada nova posição.
StopLossPips = 50 — distância do preço de entrada ao nível de stop-loss em pips. Definir como 0 para desabilitar o stop.
TakeProfitPips = 50 — distância do preço de entrada ao nível de take-profit em pips. Definir como 0 para desabilitar o alvo.
TrailingStopPips = 5 — tamanho do trailing stop em pips. Definir como 0 para desativar o trailing.
TrailingStepPips = 5 — melhoria mínima de preço (em pips) necessária antes que o trailing stop se mova novamente.
GapPips = 1 — lacuna de abertura mínima, expressa em pips, necessária para gerar um sinal de entrada.
CandleType = período de 1 hora — velas usadas para detecção de lacunas e gerenciamento de posições.
Notas de implementação
Entradas baseadas em pips são convertidas para distâncias de preço absolutas usando o tamanho de tick do instrumento. Cotações
forex de cinco e três dígitos são ajustadas automaticamente para trabalhar com valores reais de pip.
A lógica de trailing stop requer que TrailingStepPips seja positivo quando TrailingStopPips está habilitado; caso contrário, a estratégia lança
uma exceção na inicialização, espelhando a validação MQL original.
A estratégia avalia controles de risco apenas em velas terminadas de acordo com as diretrizes da API de alto nível do StockSharp.
O gerenciamento manual de stop e alvo depende de ordens de mercado, portanto não há ordens de proteção separadas no livro.
As configurações padrão assumem instrumentos forex; ajuste as distâncias em pips ao negociar ativos com volatilidade ou tamanhos de tick diferentes.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Gap trading strategy. Detects price gaps between candles and trades the gap fill.
/// </summary>
public class GapsStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _gapPercent;
private decimal? _prevClose;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public decimal GapPercent
{
get => _gapPercent.Value;
set => _gapPercent.Value = value;
}
public GapsStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_gapPercent = Param(nameof(GapPercent), 0.05m)
.SetDisplay("Gap Percent", "Minimum gap size as percentage", "Trading");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(1, UnitTypes.Percent)
);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevClose == null)
{
_prevClose = candle.ClosePrice;
return;
}
var prevClose = _prevClose.Value;
var open = candle.OpenPrice;
var close = candle.ClosePrice;
_prevClose = close;
if (prevClose == 0)
return;
var gapPct = (open - prevClose) / prevClose * 100;
// Gap up detected - sell expecting gap fill
if (gapPct > GapPercent && Position == 0)
{
SellMarket();
}
// Gap down detected - buy expecting gap fill
else if (gapPct < -GapPercent && Position == 0)
{
BuyMarket();
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class gaps_strategy(Strategy):
def __init__(self):
super(gaps_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._gap_percent = self.Param("GapPercent", 0.05) \
.SetDisplay("Gap Percent", "Minimum gap size as percentage", "Trading")
self._prev_close = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def GapPercent(self):
return self._gap_percent.Value
def OnReseted(self):
super(gaps_strategy, self).OnReseted()
self._prev_close = None
def OnStarted2(self, time):
super(gaps_strategy, self).OnStarted2(time)
self._prev_close = None
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
if self._prev_close is None:
self._prev_close = close
return
prev_close = self._prev_close
self._prev_close = close
if prev_close == 0:
return
gap_pct = (open_price - prev_close) / prev_close * 100.0
gp = float(self.GapPercent)
# Gap up detected - sell expecting gap fill
if gap_pct > gp and self.Position == 0:
self.SellMarket()
# Gap down detected - buy expecting gap fill
elif gap_pct < -gp and self.Position == 0:
self.BuyMarket()
def CreateClone(self):
return gaps_strategy()