La EA estrategia de ID de gráfico OBJPROP recrea el comportamiento centrado en el gráfico del ejemplo original MetaTrader 5 al mostrar Donchian envolventes de canal en tres períodos de tiempo sincronizados. El gráfico principal alberga el período de tiempo de negociación, mientras que dos paneles auxiliares visualizan el contexto H4 y diario. Esta configuración refleja el Asesor Experto original que apilaba múltiples gráficos e indicadores en un único espacio de trabajo para el análisis visual.
Características clave
Visualización de múltiples períodos de tiempo: se suscribe automáticamente a velas primarias, H4 y diarias para el valor seleccionado.
Longitud del canal Donchian unificada: aplica el mismo período de canal a cada período de tiempo para mantener las envolventes comparables.
Integración de gráficos de alto nivel: se basa en StockSharp áreas del gráfico para representar series de precios, Donchian canales y operaciones ejecutadas, reproduciendo el diseño MQL sin manipulación de objetos de bajo nivel.
Base extensible: almacena los límites de canal más recientes para cada período de tiempo, lo que facilita extender la estrategia con lógica de ruptura o confirmación en el futuro.
Parámetros
Parámetro
Descripción
categoría
Predeterminado
ChannelLength
Longitud del canal Donchian utilizado en todos los períodos de tiempo suscritos.
Indicadores
22
PrimaryCandleType
Marco de tiempo principal utilizado para el comercio y como panel de gráfico superior.
generales
velas de 30 minutos
H4CandleType
Periodo de tiempo auxiliar H4 mostrado en un panel secundario.
generales
velas de 4 horas
DailyCandleType
Auxiliar Horario diario mostrado en un panel terciario.
generales
velas de 1 dia
Todos los parámetros están disponibles a través de la interfaz de usuario de parámetros StockSharp, admiten optimización y se pueden ajustar sin cambiar el código.
Lógica de la estrategia
Inicializa tres indicadores de canal Donchian con el mismo parámetro de longitud.
Se suscribe a las series de velas primarias, H4 y diarias seleccionadas para el valor actual.
Vincula cada suscripción a su indicador de canal respectivo utilizando el nivel alto API, asegurando que los valores del indicador se calculen de forma incremental.
Crea un área de gráfico principal y hasta dos áreas auxiliares donde se dibujan velas, canales y las operaciones de la estrategia.
Almacena los límites de canal superior e inferior más recientes para cada período de tiempo, lo que permite agregar reglas de decisión personalizadas más adelante.
La implementación actual es solo de visualización y no envía pedidos. Esto refleja el código original MetaTrader, que se centraba en componer un panel de gráficos sin lógica comercial automatizada.
Notas de uso
Asegúrese de que el valor seleccionado tenga datos históricos para cada período de tiempo utilizado por la estrategia para completar todas las áreas del gráfico.
Puede cambiar cualquiera de los parámetros del período de tiempo a otros tipos de datos TimeFrame (por ejemplo, 15 minutos o velas semanales) si se requieren diferentes paneles de contexto.
Se puede superponer una lógica comercial adicional en los métodos de procesamiento (ProcessPrimary, ProcessH4, ProcessDaily) reaccionando a los niveles de canal almacenados.
Notas de conversión
El ejemplo de MetaTrader creó gráficos secundarios a través de objetos OBJ_CHART; la versión StockSharp la reemplaza con áreas de gráficos creadas por el nivel alto API, que está mejor integrado con la plataforma.
La gestión de indicadores se realiza mediante llamadas BindEx en lugar de la creación manual de identificadores, lo que garantiza que los valores estén sincronizados con las velas entrantes.
Las rutinas de eliminación de objetos no son necesarias porque StockSharp elimina automáticamente las suscripciones y los enlaces de gráficos cuando se detiene la estrategia.
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()