Esta estrategia replica el asesor experto de MetaTrader Exp_DynamicRS_C usando la API de alto nivel de StockSharp. Evalúa las transiciones de color del indicador personalizado DynamicRS_C para detectar soporte y resistencia dinámicos. Cuando la línea se vuelve magenta (índice de color 0) favorece configuraciones alcistas, y cuando se vuelve azul-violeta (índice de color 2) favorece configuraciones bajistas. El port de StockSharp mantiene el mismo tiempo de señal, indicadores de permiso y estructura stop/take que el robot fuente.
Detalles
Criterios de entrada:
Largo: La vela terminada seleccionada por SignalBar cambia el color del indicador de cualquier cosa excepto 0 a 0. La estrategia opcionalmente cierra un corto existente antes de entrar, replicando la compuerta SellPosClose original, y luego abre un largo si AllowBuyEntry está habilitado.
Corto: La vela evaluada cambia el color del indicador de cualquier cosa excepto 2 a 2. La estrategia opcionalmente cierra un largo existente (AllowBuyExit) y luego abre un corto si AllowSellEntry está habilitado.
Largo/Corto: Opera en ambas direcciones con interruptores independientes para entradas y salidas.
Criterios de salida:
Las posiciones largas se cierran cuando aparece una señal corta y AllowBuyExit es verdadero, o cuando se alcanzan los límites de stop-loss / take-profit.
Las posiciones cortas se cierran cuando aparece una señal larga y AllowSellExit es verdadero, o cuando se activan los límites de riesgo.
Stops: StopLossPoints y TakeProfitPoints son desplazamientos de precio absolutos desde el precio de entrada. Establecer cualquier valor en cero desactiva esa protección.
Filtros:
SignalBar determina cuántas velas completadas hacia atrás se inspeccionan para un cambio de color, imitando la búsqueda del buffer original (CopyBuffer(..., SignalBar, 2)).
CandleType selecciona el marco temporal usado tanto para el indicador como para la lógica de negociación (por defecto: velas de 4 horas, coincidiendo con el EA).
Parámetros
CandleType – Serie de velas procesada por la estrategia.
Length – Profundidad de retrovisión usada por el indicador DynamicRS_C para comparar máximos/mínimos (Length en MQL).
SignalBar – Número de velas completamente cerradas hacia atrás usadas para la evaluación de señales (equivalente a la entrada del EA SignalBar).
AllowBuyEntry / AllowSellEntry – Permite abrir posiciones largas/cortas en sus respectivas señales.
AllowBuyExit / AllowSellExit – Permite cerrar posiciones largas/cortas existentes cuando aparece la señal opuesta.
StopLossPoints – Distancia de pérdida absoluta desde el precio de entrada. Cuando es positivo cierra largos por debajo y cortos por encima de la entrada.
TakeProfitPoints – Distancia de ganancia absoluta desde el precio de entrada. Cuando es positivo cierra largos por encima y cortos por debajo de la entrada.
Volume – Tamaño de orden base heredado de Strategy.Volume. La cantidad adicional se agrega automáticamente para aplanar posiciones opuestas cuando la señal solicita una reversión.
Lógica del indicador
El DynamicRsCIndicator incluido reproduce el comportamiento del buffer de color del script MetaTrader:
Rastrea los últimos máximos y mínimos sobre la ventana Length configurada y la barra inmediatamente anterior.
Cuando un máximo local es menor que el máximo anterior y el máximo hace Length barras, y también está por debajo del valor anterior del indicador, el buffer cambia al color 0 (magenta) y el valor se ajusta a ese máximo.
Cuando un mínimo local es mayor que el mínimo anterior y el mínimo hace Length barras, y está por encima del valor anterior del indicador, el buffer cambia al color 2 (azul-violeta) y el valor se ajusta a ese mínimo.
De lo contrario, el indicador mantiene su valor anterior. El color neutro 1 actúa como puente entre los estados de tendencia exactamente como en el algoritmo original.
Al vincular este indicador a través de BindEx, la estrategia recibe tanto el valor numérico como el índice de color discreto, asegurando que la evaluación de señales y el tiempo de operación coincidan con el comportamiento del experto fuente.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class DynamicRsCStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public DynamicRsCStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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 dynamic_rs_c_strategy(Strategy):
def __init__(self):
super(dynamic_rs_c_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(dynamic_rs_c_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(dynamic_rs_c_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return dynamic_rs_c_strategy()