A Estratégia de intervalo de hora sincronizada é uma versão StockSharp do MetaTrader 4 consultor especialista JK_sinkhro1. Ele analisa o equilíbrio das velas de alta e de baixa durante a janela de negociação recente e negocia apenas durante dois horários de sincronização cuidadosamente selecionados (por padrão, 19h e 22h, mais um deslocamento). A estratégia se concentra na captura de rupturas direcionais e, ao mesmo tempo, na aplicação de regras conservadoras de gerenciamento de risco semelhantes às do EA original.
Lógica de negociação
Funciona na série de velas selecionada pelo parâmetro Candle Type (padrão: velas de 1 hora).
Mantém uma janela deslizante das últimas Analysis Period velas concluídas e conta quantas velas fechadas de alta versus baixa.
Quando a contagem de alta excede a contagem de baixa, a estratégia se prepara para um longo rompimento durante a primeira hora de sincronização (22 + Hour Offset).
Quando a contagem de baixa excede a contagem de alta, ela se prepara para um pequeno rompimento durante a segunda hora de sincronização (19 + Hour Offset).
Os sinais só são válidos nos primeiros cinco minutos da hora para que a ordem seja sincronizada com a nova barra aberta, como no MQL original.
Novas negociações serão ignoradas se já houver Max Active Orders registrado ou se houver uma posição aberta.
Gestão de Risco e Gestão Comercial
As posições são abertas com um tamanho de lote fixo (Fixed Volume) ou um tamanho baseado em risco usando o dinheiro da conta e o parâmetro Risk %. O modelo de risco divide o risco monetário permitido pela distância de stop em etapas de preço para aproximar o comportamento da fonte EA.
Cada posição usa três camadas de lógica de saída:
Um lucro primário de Take Profit (pts) do preço de entrada.
Um take-profit secundário mais rápido em Secondary TP (pts) para imitar o fechamento manual inicial no código original.
Um stop loss rígido em Stop Loss (pts) abaixo/acima do preço de entrada.
Trailing stop opcional: quando o preço avança mais de Trailing Stop (pts), o limite móvel segue o extremo favorável e fecha a posição se o preço recuar além da distância móvel.
O estado da posição é redefinido após cada saída completa para preparar a próxima janela de sincronização.
Parâmetros
Parâmetro
Descrição
Take Profit (pts)
Distância primária de lucro nas etapas de preços de títulos.
Secondary TP (pts)
Distância de take-profit mais rápida acionada antes do alvo principal.
Stop Loss (pts)
Distância de stop-loss medida em etapas de preço.
Trailing Stop (pts)
Distância de parada final; definido como 0 para desabilitar.
Analysis Period
Número de velas recentes inspecionadas ao contar fechamentos de alta/baixa.
Hour Offset
Compensação adicionada ao horário de negociação original das 19h e 22h.
Max Active Orders
Número máximo de ordens ativas simultaneamente permitidas antes que novas entradas sejam bloqueadas.
Fixed Volume
Volume de negociação usado quando o dimensionamento baseado em risco está desativado.
Use Risk Volume
Permite o dimensionamento dinâmico da posição com base no caixa do portfólio e na distância do stop.
Risk %
Porcentagem do caixa do portfólio arriscado por negociação no modo baseado em risco.
Candle Type
Tipo/período de vela usado para cálculos e geração de sinal.
Notas de uso
A configuração padrão emula a versão MetaTrader que negociou EURUSD durante a sessão de Nova York; ajuste o deslocamento de hora para corresponder ao fuso horário do seu corretor/servidor.
Certifique-se de que a definição de segurança forneça valores PriceStep, VolumeStep e MinVolume precisos para que o dimensionamento de posição baseado em risco possa alinhar os volumes com os incrementos do lote de troca.
Como a estratégia depende de dados de fechamento de velas, anexe-a a um provedor de histórico ou feed de dados ao vivo que possa entregar a série de velas selecionada com atraso mínimo.
A saída final usa preços de fechamento de velas finalizadas, que se aproximam da lógica de rastreamento baseada em ticks da fonte EA, enquanto permanece compatível com o API de alto nível de StockSharp.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class SynchronizedHourBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose;
private decimal _prevEma;
private bool _hasPrev;
private int _cooldownRemaining;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public SynchronizedHourBreakoutStrategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 50).SetDisplay("EMA Period", "EMA lookback", "Indicators");
_atrPeriod = Param(nameof(AtrPeriod), 14).SetDisplay("ATR Period", "ATR lookback", "Indicators");
_cooldownCandles = Param(nameof(CooldownCandles), 200).SetDisplay("Cooldown", "Candles between signals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = default;
_prevEma = default;
_hasPrev = default;
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = 0;
_prevEma = 0;
_hasPrev = false;
_cooldownRemaining = 0;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, atr, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema, decimal atr)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (!_hasPrev) { _prevClose = close; _prevEma = ema; _hasPrev = true; return; }
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevClose = close;
_prevEma = ema;
return;
}
if (_prevClose <= _prevEma && close > ema && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (_prevClose >= _prevEma && close < ema && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
_prevClose = close;
_prevEma = ema;
}
}
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.Indicators import ExponentialMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class synchronized_hour_breakout_strategy(Strategy):
def __init__(self):
super(synchronized_hour_breakout_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 50) \
.SetDisplay("EMA Period", "EMA lookback", "Indicators")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR lookback", "Indicators")
self._cooldown_candles = self.Param("CooldownCandles", 200) \
.SetDisplay("Cooldown", "Candles between signals", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
self._cooldown_remaining = 0
@property
def ema_period(self):
return self._ema_period.Value
@property
def atr_period(self):
return self._atr_period.Value
@property
def cooldown_candles(self):
return self._cooldown_candles.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(synchronized_hour_breakout_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(synchronized_hour_breakout_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
self._cooldown_remaining = 0
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
atr = AverageTrueRange()
atr.Length = self.atr_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, atr, self.process_candle).Start()
def process_candle(self, candle, ema, atr):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ema_val = float(ema)
if not self._has_prev:
self._prev_close = close
self._prev_ema = ema_val
self._has_prev = True
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_close = close
self._prev_ema = ema_val
return
if self._prev_close <= self._prev_ema and close > ema_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown_remaining = self.cooldown_candles
elif self._prev_close >= self._prev_ema and close < ema_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown_remaining = self.cooldown_candles
self._prev_close = close
self._prev_ema = ema_val
def CreateClone(self):
return synchronized_hour_breakout_strategy()