A EA estratégia de identificação de gráfico OBJPROP recria o comportamento focado em gráfico do exemplo original MetaTrader 5 exibindo Donchian envelopes de canal em três períodos de tempo sincronizados. O gráfico principal hospeda o período de negociação enquanto dois painéis auxiliares visualizam o contexto H4 e Diário. Esta configuração reflete o Expert Advisor original, que empilhou vários gráficos e indicadores em um único espaço de trabalho para análise visual.
Principais recursos
Visualização de vários períodos de tempo – assina automaticamente velas primárias, H4 e diárias para o título selecionado.
Comprimento de canal Donchian unificado – aplica o mesmo período de canal a cada período de tempo para manter os envelopes comparáveis.
Integração de gráficos de alto nível – depende de áreas do gráfico StockSharp para renderizar séries de preços, canais Donchian e negociações executadas, reproduzindo o layout MQL sem manipulação de objetos de baixo nível.
Base extensível – armazena os limites de canal mais recentes para cada período de tempo, facilitando a extensão da estratégia com lógica de ruptura ou confirmação no futuro.
Parâmetros
Parâmetro
Descrição
Categoria
Padrão
ChannelLength
Duração do canal Donchian usado em todos os períodos inscritos.
Indicadores
22
PrimaryCandleType
Período principal usado para negociação e como painel superior do gráfico.
Geral
Velas de 30 minutos
H4CandleType
Período auxiliar H4 exibido em painel secundário.
Geral
Velas de 4 horas
DailyCandleType
Período auxiliar diário exibido em painel terciário.
Geral
Velas de 1 dia
Todos os parâmetros estão disponíveis por meio da IU de parâmetro StockSharp, suportam otimização e podem ser ajustados sem alterar o código.
Lógica da estratégia
Inicializa três indicadores de canal Donchian com o mesmo parâmetro de comprimento.
Assina as séries de velas primárias, H4 e diárias selecionadas para o título atual.
Vincula cada assinatura ao seu respectivo indicador de canal usando o API de alto nível, garantindo que os valores do indicador sejam calculados de forma incremental.
Cria uma área principal do gráfico e até duas áreas auxiliares onde são desenhadas velas, canais e negociações da estratégia.
Armazena os limites superiores e inferiores mais recentes do canal para cada período de tempo, permitindo que regras de decisão personalizadas sejam adicionadas posteriormente.
A implementação atual é apenas de visualização e não envia pedidos. Isso reflete o código original MetaTrader, que se concentrava na composição de um painel de gráficos sem lógica de negociação automatizada.
Notas de uso
Certifique-se de que o título selecionado tenha dados históricos para cada período usado pela estratégia para preencher todas as áreas do gráfico.
Você pode alterar qualquer um dos parâmetros do período de tempo para outros tipos de dados TimeFrame (por exemplo, 15 minutos ou velas semanais) se forem necessários painéis de contexto diferentes.
Lógica comercial adicional pode ser colocada em camadas nos métodos de processamento (ProcessPrimary, ProcessH4, ProcessDaily) reagindo aos níveis de canal armazenados.
Notas de conversão
O exemplo MetaTrader criou gráficos filhos por meio de objetos OBJ_CHART; a versão StockSharp substitui isso por áreas de gráfico criadas pelo API de alto nível, que é melhor integrado à plataforma.
O gerenciamento do indicador é realizado por meio de chamadas BindEx em vez da criação manual de identificadores, garantindo que os valores sejam sincronizados com as velas recebidas.
As rotinas de exclusão de objetos não são necessárias porque StockSharp descarta automaticamente assinaturas e ligações de gráficos quando a estratégia é interrompida.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// EA Objprop Chart Id strategy: Standard Deviation breakout.
/// Buys when StdDev crosses above threshold with bullish candle, sells on bearish cross.
/// </summary>
public class EaObjpropChartIdStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private readonly StrategyParam<int> _signalCooldownCandles;
private decimal _prevStdDev;
private decimal _prevRange;
private int _candlesSinceTrade;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int Period { get => _period.Value; set => _period.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public EaObjpropChartIdStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_period = Param(nameof(Period), 50)
.SetGreaterThanZero()
.SetDisplay("Period", "EMA period", "Indicators");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 4)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevStdDev = 0;
_prevRange = 0;
_candlesSinceTrade = SignalCooldownCandles;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevStdDev = 0;
_prevRange = 0;
_candlesSinceTrade = SignalCooldownCandles;
_hasPrev = false;
var stdDev = new ExponentialMovingAverage { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(stdDev, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal stdDevValue)
{
if (candle.State != CandleStates.Finished) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
var range = candle.HighPrice - candle.LowPrice;
if (range <= 0)
return;
if (_hasPrev && stdDevValue > 0 && _prevRange > 0)
{
var expanding = range > _prevRange * 1.2m;
var bullish = candle.ClosePrice > candle.OpenPrice;
var bearish = candle.ClosePrice < candle.OpenPrice;
if (expanding && bullish && candle.ClosePrice > stdDevValue && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (expanding && bearish && candle.ClosePrice < stdDevValue && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
_prevStdDev = stdDevValue;
_prevRange = range;
_hasPrev = true;
}
}
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
from StockSharp.Algo.Strategies import Strategy
class ea_objprop_chart_id_strategy(Strategy):
def __init__(self):
super(ea_objprop_chart_id_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._period = self.Param("Period", 50)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 4)
self._prev_std_dev = 0.0
self._prev_range = 0.0
self._candles_since_trade = 4
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 Period(self):
return self._period.Value
@Period.setter
def Period(self, value):
self._period.Value = value
@property
def SignalCooldownCandles(self):
return self._signal_cooldown_candles.Value
@SignalCooldownCandles.setter
def SignalCooldownCandles(self, value):
self._signal_cooldown_candles.Value = value
def OnReseted(self):
super(ea_objprop_chart_id_strategy, self).OnReseted()
self._prev_std_dev = 0.0
self._prev_range = 0.0
self._candles_since_trade = self.SignalCooldownCandles
self._has_prev = False
def OnStarted2(self, time):
super(ea_objprop_chart_id_strategy, self).OnStarted2(time)
self._prev_std_dev = 0.0
self._prev_range = 0.0
self._candles_since_trade = self.SignalCooldownCandles
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self.Period
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, self._process_candle).Start()
def _process_candle(self, candle, std_dev_value):
if candle.State != CandleStates.Finished:
return
if self._candles_since_trade < self.SignalCooldownCandles:
self._candles_since_trade += 1
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
std_val = float(std_dev_value)
range_val = high - low
if range_val <= 0:
return
if self._has_prev and std_val > 0 and self._prev_range > 0:
expanding = range_val > self._prev_range * 1.2
bullish = close > open_price
bearish = close < open_price
if expanding and bullish and close > std_val and self.Position <= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.BuyMarket()
self._candles_since_trade = 0
elif expanding and bearish and close < std_val and self.Position >= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
self._prev_std_dev = std_val
self._prev_range = range_val
self._has_prev = True
def CreateClone(self):
return ea_objprop_chart_id_strategy()