La estrategia inversa MA es una StockSharp conversión del simple MetaTrader 4 asesor experto "MA_Reverse". El robot original
monitorea cuánto tiempo el precio de oferta permanece por encima o por debajo de un promedio móvil simple de 14 períodos (SMA). Después de una racha bastante larga en uno
dirección, abre una posición apostando a una reversión de corto plazo. El puerto StockSharp mantiene la misma idea al contar el número
de velas terminadas consecutivas que cierran por encima o por debajo del SMA y ejecutan una orden de mercado tan pronto como se alcanza el umbral configurado
alcanzado.
Lógica comercial
Suscríbase a velas del período de tiempo seleccionado y calcule una media móvil simple con el período definido por SmaPeriod.
Mantener un contador de números enteros (StreakThreshold controla la longitud objetivo) que se incrementa mientras el cierre de la vela permanece por encima
la media móvil y disminuye mientras el cierre se mantiene por debajo de ella. Al tocar la media móvil se reinicia el contador.
Una vez que el contador llega a StreakThreshold y el cierre está al menos MinimumDeviation por encima del SMA, la estrategia vende con un
orden del mercado. Se supone que es probable que una excursión alcista prolongada desde la media móvil se revierta.
Cuando el contador llega a -StreakThreshold y el cierre es al menos MinimumDeviation por debajo del SMA, la lógica refleja la
comportamiento y abre una posición larga.
Después de cada operación, el contador mantiene su valor actual, al igual que la fuente EA, de modo que pueda comenzar a medir inmediatamente el
siguiente racha.
Gestión de pedidos
Las entradas al mercado utilizan el parámetro TradeVolume. Si hay una posición opuesta en el libro, la estrategia primero la cierra y
luego abre la nueva operación en una orden de mercado única para que las reversiones coincidan con el comportamiento MetaTrader.
Una toma de ganancias global se configura a través del asistente StartProtection de StockSharp. La distancia es igual a TakeProfitPoints
multiplicado por el paso del precio del valor, reproduciendo el objetivo de ganancia de "30 * Puntos" del código MQL. Cuando se alcanza el objetivo,
La posición se cierra con una orden de mercado.
No se implementa ningún stop-loss en el experto original y, por lo tanto, no se agrega ninguno en el puerto. El control de riesgos está íntegramente a cargo de
la toma de ganancias y por la configuración de administración del dinero del usuario.
Parámetros
Parámetro
Descripción
TradeVolume
Tamaño de lote utilizado para cada entrada al mercado. El valor también se utiliza para dimensionar las inversiones al cambiar de dirección.
SmaPeriod
Número de velas utilizadas por la media móvil simple. El valor predeterminado coincide con la media móvil de 14 períodos del EA.
StreakThreshold
Número de cierres consecutivos que deben permanecer en un lado del SMA antes de que se permita una orden de reversión.
MinimumDeviation
Distancia mínima absoluta entre el cierre y el SMA que confirma la condición de ruptura.
TakeProfitPoints
Distancia de obtención de beneficios expresada en incrementos de precio. Se multiplica por el PriceStep del instrumento para obtener la compensación de precio absoluta.
CandleType
Tipo de vela (período de tiempo) utilizado para calcular el SMA y evaluar los contadores de racha.
Notas
La lógica contraria funciona con velas terminadas proporcionadas por SubscribeCandles, lo que hace que la implementación sea sólida y
compatible con las pruebas históricas. El comportamiento coincide con la versión MetaTrader basada en ticks siempre que las velas estén bien
lo suficientemente granulado como para capturar excursiones de corta duración.
Debido a que StockSharp agrega posiciones de forma predeterminada, varias entradas consecutivas se administran como una única posición con un único
distancia flotante de toma de ganancias. Esto equivale a que MetaTrader realice la misma toma de ganancias en cada orden porque el
La distancia con respecto al precio medio de entrada actual se mantiene constante.
La estrategia no agrega su propio indicador a Strategy.Indicators porque la infraestructura vinculante administra el indicador
vida útil automáticamente.
Valide siempre la configuración de paso de precio y volumen para los símbolos de su corredor específicos para que el parámetro TakeProfitPoints
produce el tamaño objetivo absoluto deseado.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Moving average reversal strategy converted from the MetaTrader MA_Reverse expert advisor.
/// Counts how many consecutive closes remain on one side of the SMA and opens a trade once the streak is long enough.
/// </summary>
public class MaReverseStrategy : Strategy
{
private readonly StrategyParam<int> _smaPeriod;
private readonly StrategyParam<int> _streakThreshold;
private readonly StrategyParam<decimal> _minimumDeviation;
private readonly StrategyParam<DataType> _candleType;
private int _streak;
public MaReverseStrategy()
{
_smaPeriod = Param(nameof(SmaPeriod), 14)
.SetDisplay("SMA Period", "Number of candles used by the moving average.", "Indicator");
_streakThreshold = Param(nameof(StreakThreshold), 3)
.SetDisplay("Streak Threshold", "Number of consecutive closes required before reversing.", "Logic");
_minimumDeviation = Param(nameof(MinimumDeviation), 0.0001m)
.SetDisplay("Minimum Deviation", "Minimum distance between price and SMA to confirm the reversal.", "Logic");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe used for SMA calculation.", "General");
}
public int SmaPeriod
{
get => _smaPeriod.Value;
set => _smaPeriod.Value = value;
}
public int StreakThreshold
{
get => _streakThreshold.Value;
set => _streakThreshold.Value = value;
}
public decimal MinimumDeviation
{
get => _minimumDeviation.Value;
set => _minimumDeviation.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_streak = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_streak = 0;
var sma = new SimpleMovingAverage { Length = SmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
var closePrice = candle.ClosePrice;
var deviation = closePrice - smaValue;
if (deviation == 0m)
{
_streak = 0;
return;
}
if (deviation > 0m)
{
// Price above SMA
if (_streak < 0)
_streak = 0;
_streak++;
if (_streak >= StreakThreshold && deviation > MinimumDeviation)
{
// Long streak above SMA => sell (reversal)
if (Position >= 0)
{
SellMarket();
_streak = 0;
}
}
}
else
{
// Price below SMA
if (_streak > 0)
_streak = 0;
_streak--;
if (-_streak >= StreakThreshold && -deviation > MinimumDeviation)
{
// Long streak below SMA => buy (reversal)
if (Position <= 0)
{
BuyMarket();
_streak = 0;
}
}
}
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class ma_reverse_strategy(Strategy):
"""
MA reversal: counts consecutive closes on one side of SMA.
After streak threshold, opens a reversal trade.
"""
def __init__(self):
super(ma_reverse_strategy, self).__init__()
self._sma_period = self.Param("SmaPeriod", 14).SetDisplay("SMA Period", "SMA period", "Indicators")
self._streak_threshold = self.Param("StreakThreshold", 3).SetDisplay("Streak", "Consecutive closes needed", "Logic")
self._min_deviation = self.Param("MinDeviation", 0.0001).SetDisplay("Min Deviation", "Min distance from SMA", "Logic")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Timeframe", "General")
self._streak = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ma_reverse_strategy, self).OnReseted()
self._streak = 0
def OnStarted2(self, time):
super(ma_reverse_strategy, self).OnStarted2(time)
sma = SimpleMovingAverage()
sma.Length = self._sma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, sma_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
sma = float(sma_val)
deviation = close - sma
if deviation == 0:
self._streak = 0
return
if deviation > 0:
if self._streak < 0:
self._streak = 0
self._streak += 1
if self._streak >= self._streak_threshold.Value and deviation > self._min_deviation.Value:
if self.Position >= 0:
self.SellMarket()
self._streak = 0
else:
if self._streak > 0:
self._streak = 0
self._streak -= 1
if -self._streak >= self._streak_threshold.Value and -deviation > self._min_deviation.Value:
if self.Position <= 0:
self.BuyMarket()
self._streak = 0
def CreateClone(self):
return ma_reverse_strategy()