Recria a lógica de ruptura e reversão do consultor especialista Noah10pips2006 MetaTrader 4 original.
Constrói canais de preços da sessão anterior e coloca ordens stop em torno do ponto médio.
Aplica rastreamento de lucro seguro, dimensionamento de posição dinâmico opcional e uma negociação de reversão opcional após o fechamento da primeira posição.
Lógica de negociação
Cálculo do intervalo de sessões
No início de cada novo dia de negociação (após aplicar a compensação de fuso horário configurada), a estratégia registra a máxima e a mínima da sessão anterior. Esses níveis são usados para calcular:
O ponto médio entre alto e baixo.
Um buffer de "aprovação" posicionado 20 pips acima/abaixo do intervalo.
Um canal de entrada obtido subtraindo/adicionando 40 pips (ou 25% do intervalo se o intervalo for maior que 160 pips).
Pedido inicial pendente
Quando o mercado entra na janela de negociação, a estratégia verifica o último fechamento:
Se o fechamento estiver entre o ponto médio e o buffer superior, um stop de venda será colocado no ponto médio.
Se o fechamento estiver entre o buffer inferior e o ponto médio, um buy stop será colocado no ponto médio.
A largura do intervalo deve exceder o mínimo configurado antes de qualquer pedido ser feito.
Segundo pedido pendente
Se apenas uma ordem stop permanecer ativa, o sistema adiciona a ordem de direção oposta ao buffer correspondente (buffer superior para um stop de compra, buffer inferior para um stop de venda). Isso reflete o comportamento original EA e prepara a estratégia para rompimentos em ambos os lados do intervalo.
Gerenciamento de posição
As ordens protetoras de stop-loss e take-profit são criadas após o preenchimento de uma entrada.
Assim que o lucro flutuante atinge o limite de acionamento seguro, o stop loss é movido para bloquear o lucro seguro configurado.
Quando o bloqueio seguro está ativo, um trailing stop opcional continua acompanhando o preço na distância especificada.
Desligamento diário
Todas as ordens pendentes e posições abertas serão fechadas quando a janela de negociação terminar ou quando o limite de sexta-feira for atingido.
Negociação de reversão
A primeira posição concluída pode acionar uma ordem de mercado na direção oposta, reproduzindo o comportamento “reverso após stop” do código original. A reversão é ignorada se o ajuste de lucro seguro já tiver garantido ganhos.
Parâmetros
Parâmetro
Descrição
CandleType
Série de velas usada para conduzir cálculos e tempo. Padrão: velas de 1 hora.
TimeZoneOffset
Turno (em horas) aplicado para trocar carimbos de data/hora antes dos cálculos diários.
StartHour, StartMinute
Horário de abertura da janela de negociação no fuso horário alterado.
EndHour, EndMinute
Hora de fechamento da janela de negociação. Novas entradas não são colocadas posteriormente.
FridayEndHour
Hora na sexta-feira em que as posições são fechadas à força.
TradeFriday
Habilita ou desabilita a abertura de novas posições na sexta-feira.
StopLossPips, TakeProfitPips
Distância (em pips) das ordens de proteção criadas após a entrada.
TrailingStopPips
Distância do trailing-stop usada após a etapa de lucro seguro. Defina como 0 para desativar o rastreamento.
SecureProfitPips
Lucro bloqueado quando o gatilho seguro é ativado.
TrailSecureProfitPips
Limite de lucro necessário antes de mover o stop para o nível seguro.
MinimumRangePips
Largura mínima do canal de entrada necessária para realizar pedidos.
StartYear, StartMonth
Ignore os dados de mercado anteriores a esta data.
MinVolume, MaxVolume
Limites aplicados ao volume de pedido calculado.
MaximumRiskPercent
Porcentagem do valor do portfólio arriscado por negociação quando o dimensionamento dinâmico está habilitado.
FixedVolume
Quando true, a estratégia usa a propriedade Volume em vez do modelo de risco.
Notas práticas
O instrumento deve fornecer valores PriceStep e StepPrice válidos quando o modo de dimensionamento de posição baseado em risco for usado.
Os ajustes de lucro seguro e de rastreamento dependem de velas concluídas, portanto, os preenchimentos intrabarras são processados na próxima vela concluída.
A estratégia cancela e substitui as ordens de proteção sempre que a lógica móvel atualiza o preço stop.
Certifique-se de que o deslocamento do fuso horário corresponda à fonte dos dados históricos; caso contrário, o intervalo do dia anterior pode ser diferente do especialista MT4 original.
Advertências de conversão
Os objetos de desenho visual da versão MT4 foram omitidos; use os níveis fornecidos ou adicione anotações de gráfico personalizadas, se necessário.
O algoritmo assume cotação Forex de quatro dígitos ao converter os buffers fixos de 20/40 pip; ajustar parâmetros para diferentes classes de ativos.
As negociações reversas são executadas no mercado com o modelo de volume atual, correspondendo ao comportamento do EA original após a exclusão de ordens pendentes opostas.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Noah 10 Pips 2006 - session breakout strategy.
/// Tracks the previous session's high/low range.
/// Buys on breakout above the midpoint, sells on breakout below.
/// Uses Highest/Lowest indicators as channel reference.
/// </summary>
public class Noah10Pips2006Strategy : Strategy
{
private readonly StrategyParam<int> _channelPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevHigh;
private decimal _prevLow;
private decimal _prevMid;
private decimal _prevClose;
private bool _hasPrev;
public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Noah10Pips2006Strategy()
{
_channelPeriod = Param(nameof(ChannelPeriod), 24)
.SetDisplay("Channel Period", "Lookback for high/low channel", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh = 0m;
_prevLow = 0m;
_prevMid = 0m;
_prevClose = 0m;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var highest = new Highest { Length = ChannelPeriod };
var lowest = new Lowest { Length = ChannelPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal high, decimal low)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
var mid = (high + low) / 2m;
if (!_hasPrev)
{
_prevHigh = high;
_prevLow = low;
_prevMid = mid;
_prevClose = close;
_hasPrev = true;
return;
}
// Breakout above channel high - buy
if (_prevClose <= _prevHigh && close > high && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Breakout below channel low - sell
else if (_prevClose >= _prevLow && close < low && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
// Cross above midpoint from below - buy signal
else if (_prevClose <= _prevMid && close > mid && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Cross below midpoint from above - sell signal
else if (_prevClose >= _prevMid && close < mid && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevHigh = high;
_prevLow = low;
_prevMid = mid;
_prevClose = close;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class noah10_pips2006_strategy(Strategy):
"""Session breakout strategy. Tracks channel high/low/midpoint.
Buys on breakout above channel high or cross above midpoint.
Sells on breakout below channel low or cross below midpoint."""
def __init__(self):
super(noah10_pips2006_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 24) \
.SetDisplay("Channel Period", "Lookback for high/low channel", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_high = 0.0
self._prev_low = 0.0
self._prev_mid = 0.0
self._prev_close = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def ChannelPeriod(self):
return self._channel_period.Value
def OnReseted(self):
super(noah10_pips2006_strategy, self).OnReseted()
self._prev_high = 0.0
self._prev_low = 0.0
self._prev_mid = 0.0
self._prev_close = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(noah10_pips2006_strategy, self).OnStarted2(time)
self._has_prev = False
highest = Highest()
highest.Length = self.ChannelPeriod
lowest = Lowest()
lowest.Length = self.ChannelPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._process_candle).Start()
def _process_candle(self, candle, high, low):
if candle.State != CandleStates.Finished:
return
high_val = float(high)
low_val = float(low)
close = float(candle.ClosePrice)
mid = (high_val + low_val) / 2.0
if not self._has_prev:
self._prev_high = high_val
self._prev_low = low_val
self._prev_mid = mid
self._prev_close = close
self._has_prev = True
return
# Breakout above channel high - buy
if self._prev_close <= self._prev_high and close > high_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Breakout below channel low - sell
elif self._prev_close >= self._prev_low and close < low_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
# Cross above midpoint from below - buy
elif self._prev_close <= self._prev_mid and close > mid and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Cross below midpoint from above - sell
elif self._prev_close >= self._prev_mid and close < mid and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_high = high_val
self._prev_low = low_val
self._prev_mid = mid
self._prev_close = close
def CreateClone(self):
return noah10_pips2006_strategy()