Simple 2 MA I es una estrategia de seguimiento de tendencia que replica la lógica central del asesor experto original de MetaTrader. Usa un par de medias móviles ponderadas lineales (LWMAs) calculadas sobre precios típicos para identificar la tendencia dominante. La confirmación de momentum y los filtros de dirección MACD eliminan señales débiles. La estrategia puede gestionar opcionalmente el riesgo mediante stop-loss automático, take-profit, movimientos a break-even y trailing stops basados en velas.
Lógica de trading
Configuración larga
La LWMA rápida está por encima de la LWMA lenta, confirmando una tendencia alcista.
El mínimo de la vela de hace dos barras está por debajo del máximo de la barra anterior, señalando una nueva estructura alcista.
Al menos una de las tres últimas lecturas de tasa de cambio está por encima del umbral de momentum configurado.
La línea MACD está por encima de la línea de señal.
El volumen neto de posición es inferior al límite Max Net Volume.
Cuando se cumplen todas las condiciones, la estrategia cierra la exposición corta (si la hay) y compra a mercado.
Configuración corta
La LWMA rápida está por debajo de la LWMA lenta, confirmando una tendencia bajista.
El mínimo de la barra anterior está por debajo del máximo de la barra de hace dos períodos, indicando estructura bajista.
Al menos una de las tres últimas lecturas de tasa de cambio está por encima del umbral de momentum (valor absoluto).
La línea MACD está por debajo de la línea de señal.
El volumen neto de posición es inferior a Max Net Volume.
Cuando las condiciones se mantienen, la estrategia cubre largos (si los hay) y vende a mercado.
Gestión de riesgos
Stop-loss / take-profit: distancias fijas opcionales definidas en puntos relativos al precio de entrada.
Break-even: cuando el precio alcanza la distancia de disparo en ganancia, el stop se mueve a entrada ± desplazamiento.
Trailing por vela: después de alcanzar la distancia de activación, el stop sigue los extremos de la vela con un buffer configurable.
Las órdenes de protección se cancelan automáticamente cuando la posición se cierra.
Parámetros
Nombre
Descripción
Predeterminado
Candle Type
Marco temporal usado para cálculos de indicadores.
Velas de 15 minutos
Fast LWMA
Período de la LWMA rápida.
6
Slow LWMA
Período de la LWMA lenta.
85
Momentum Length
Período retrospectivo del indicador de tasa de cambio.
14
Momentum Threshold
Valor absoluto mínimo de tasa de cambio requerido.
0.3
MACD Fast
Longitud de EMA rápida usada en MACD.
12
MACD Slow
Longitud de EMA lenta usada en MACD.
26
MACD Signal
Longitud de EMA de señal usada en MACD.
9
Use Stop-Loss
Habilita la colocación de órdenes stop-loss.
true
Stop-Loss (points)
Distancia hasta el stop-loss desde el precio de entrada.
20
Use Take-Profit
Habilita la colocación de órdenes take-profit.
true
Take-Profit (points)
Distancia hasta el take-profit desde el precio de entrada.
50
Use Break-Even
Habilita el movimiento automático a break-even.
true
Break-Even Trigger
Ganancia (puntos) necesaria antes de break-even.
30
Break-Even Offset
Desplazamiento (puntos) añadido al mover a break-even.
30
Use Candle Trailing
Habilita trailing stops basados en extremos de velas.
true
Trailing Activation
Ganancia (puntos) requerida antes de activar trailing.
40
Trailing Padding
Distancia extra (puntos) añadida al extremo de la vela.
10
Max Net Volume
Volumen neto absoluto máximo permitido.
1
Notas
Todas las distancias de precio se expresan en pasos de precio del valor (puntos). La estrategia multiplica automáticamente los valores de los parámetros por el tamaño de tick del valor.
La asignación predeterminada de marcos temporales sigue los valores por defecto del experto original, pero puede ajustarse libremente.
La estrategia espera velas terminadas. Las barras no finalizadas se ignoran para mantener coherencia con el EA 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 Simple2MaIStrategy : 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 Simple2MaIStrategy()
{
_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 simple2_ma_i_strategy(Strategy):
def __init__(self):
super(simple2_ma_i_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(simple2_ma_i_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(simple2_ma_i_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 simple2_ma_i_strategy()