AutoAdjustingStrategy replica el experto MetaTrader Aouto Adjusting1 usando la API de alto nivel de StockSharp. El puerto conserva el filtro de momentum multitemporal original, la confirmación de tendencia MACD mensual y una pila de tres EMA para detectar retrocesos con la tendencia. Los stops y objetivos se proyectan desde los extremos de oscilación recientes y se ajustan automáticamente en cada vela completada.
Lógica principal
Estructura de tendencia – tres medias móviles exponenciales en el marco temporal de trading (6, 14, 26) deben estar alineadas (EMA6 < EMA14 < EMA26 para largos, invertido para cortos). La vela anterior debe tocar la EMA media, mientras que la vela anterior a esa forma un mínimo más alto / máximo más bajo para confirmar un retroceso.
Confirmación de momentum – el momentum en el marco temporal superior (mapeado desde el marco temporal de trading, p.ej., H1 → D1) debe desviarse al menos MomentumBuyThreshold / MomentumSellThreshold de 100 en cualquiera de las últimas tres barras completadas.
Filtro macro – una señal MACD(12, 26, 9) mensual asegura que las operaciones se alineen con la tendencia dominante (MACD > Señal para compras, < para ventas).
Ejecución – las órdenes de mercado se envían una vez que todos los filtros están de acuerdo y no hay exposición opuesta presente. Las posiciones opuestas se aplanan antes de entrar en la nueva dirección.
Protección – los niveles de stop-loss se colocan un número configurable de pips más allá del mínimo más bajo / máximo más alto de las últimas barras CandlesBack. Las distancias de take-profit se escalan por RewardRatio. Tanto el stop como el objetivo se reactivan en cada cierre de vela mientras la posición está activa.
Riesgo y dimensionamiento de posición
La estrategia refleja la parametrización de riesgo original:
RiskPercent calcula un tamaño de posición adaptativo cuando están disponibles el valor del portafolio y los metadatos del paso de precio. El algoritmo divide la pérdida monetaria permitida por la pérdida por unidad implicada por la distancia de stop actual.
Cuando el dimensionamiento basado en riesgo no puede evaluarse (p.ej., estadísticas de portafolio faltantes), el motor recurre al parámetro TradeVolume fijo.
Parámetros
Nombre
Tipo
Por defecto
Descripción
CandleType
DataType
TimeFrame(H1)
Marco temporal de trading usado para la pila EMA.
MomentumCandleType
DataType
Derivado de CandleType
Marco temporal superior que alimenta el indicador de momentum (H1→D1, H4→W1, etc.).
MacroMacdCandleType
DataType
TimeFrame(30 days)
Marco temporal para la confirmación MACD macro (mensual por defecto).
PadAmount
decimal
3
Pips extra más allá de los extremos de oscilación al calcular los stops.
RiskPercent
decimal
0.1
Porcentaje del capital del portafolio arriesgado por operación.
RewardRatio
decimal
2
Multiplicador aplicado a la distancia de stop para colocar el take-profit.
CandlesBack
int
3
Número de velas inspeccionadas para la detección de máximos/mínimos de oscilación.
MomentumBuyThreshold
decimal
0.3
Desviación mínima de momentum requerida para habilitar entradas largas.
MomentumSellThreshold
decimal
0.3
Desviación mínima de momentum requerida para habilitar entradas cortas.
TradeVolume
decimal
1
Tamaño de lote de respaldo cuando el dimensionamiento basado en riesgo no está disponible.
Gráficos y visualización
Suscribirse al marco temporal de trading y trazar las tres EMAs para observar los retrocesos.
Seguir la serie de momentum en su panel de marco temporal superior para confirmar los umbrales de energía.
Monitorizar los valores de MACD del marco temporal macro para validar el filtro de tendencia.
Notas
El mapeo automático de marcos temporales coincide con el experto MQL: M1→M15, M5→M30, M15→H1, M30→H4, H1→D1, H4→W1, D1→MN1. Otros marcos conservan su valor original.
La estrategia evita las llamadas a GetValue de indicadores almacenando los valores más recientes dentro de la estrategia y alimentándolos a través de los callbacks de bind.
El comportamiento de trailing refleja el EA original recalculando los niveles protectores cada vez que se cierra una vela.
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 AutoAdjustingStrategy : 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 AutoAdjustingStrategy()
{
_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 auto_adjusting_strategy(Strategy):
def __init__(self):
super(auto_adjusting_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(auto_adjusting_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(auto_adjusting_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 auto_adjusting_strategy()