La estrategia Above Below MA replica el asesor experto de MetaTrader Above Below MA (barabashkakvn's edition). Monitorea qué tan lejos se encuentran los precios actuales con respecto a una media móvil configurable y permite operaciones únicamente cuando el precio está en el lado "incorrecto" de la media por al menos una distancia definida, mientras que la propia media sigue la dirección anticipada. La lógica ha sido portada a la API de alto nivel de StockSharp y se ejecuta exclusivamente en velas completadas.
Descripción general
Régimen de mercado: Funciona mejor en instrumentos que frecuentemente retestean una media móvil antes de retomar la tendencia.
Instrumentos: Cualquier instrumento compatible con su conexión StockSharp. Los pares de Forex se benefician más porque el script original medía la distancia en pips.
Marco temporal: Ajustable mediante el parámetro Candle Type (marco temporal de 1 minuto por defecto).
Dirección de posición: Se admiten operaciones largas y cortas, pero solo puede existir una posición neta en un momento dado.
Lógica de la estrategia
Se calcula una media móvil sobre la serie de velas seleccionada. El método de promediado (SMA, EMA, SMMA, WMA), el precio aplicado (close, open, high, low, median, typical, weighted) y el desplazamiento hacia adelante replican las entradas de MetaTrader.
Se convierte la distancia mínima expresada en pips en un desplazamiento de precio real usando el PriceStep del instrumento. Si el broker no publica un paso de precio, el filtro de distancia se omite automáticamente.
En cada vela finalizada:
Configuración larga:
La apertura y el cierre de la vela deben estar al menos a la distancia configurada por debajo de la media móvil desplazada.
La media móvil debe estar subiendo comparada con la vela anterior.
Configuración corta:
La apertura y el cierre de la vela deben estar al menos a la distancia configurada por encima de la media móvil desplazada.
La media móvil debe estar bajando comparada con la vela anterior.
La estrategia cierra cualquier posición opuesta antes de enviar una nueva orden de mercado en la dirección de la señal. No se permite exposición simultánea larga/corta.
Todas las decisiones de trading se toman en velas completadas para evitar entradas repetidas dentro de una barra en formación. Las órdenes se ejecutan mediante BuyMarket o SellMarket con el volumen configurado.
Parámetros
Parámetro
Descripción
MaPeriod
Longitud de la media móvil. Por defecto 6.
MaShift
Número de velas para desplazar la media móvil hacia adelante. Un valor de 0 usa la barra actual, n usa el valor de hace n barras. Por defecto 0.
MaMethod
Tipo de media móvil: Simple, Exponential, Smoothed o Weighted. Por defecto Exponential.
AppliedPrice
Fuente de precio: close, open, high, low, median, typical o weighted. Por defecto Typical.
MinimumDistancePips
Distancia requerida en pips entre los precios de la vela y la media móvil. Se convierte usando PriceStep. Por defecto 5.
CandleType
Tipo de vela que impulsa las actualizaciones del indicador. Marco temporal de 1 minuto por defecto.
TradeVolume
Volumen de la orden para nuevas entradas. Por defecto 1.
Notas adicionales
No se incluye lógica de stop-loss ni take-profit. La gestión del riesgo debe implementarse mediante la configuración de la cartera o módulos externos.
El búfer de desplazamiento de la media móvil se mantiene mínimo y respeta la directriz de "sin colecciones" almacenando solo los valores requeridos para el desplazamiento especificado.
Cuando PriceStep no está disponible, el filtro de distancia mínima no puede evaluarse, por lo que las entradas dependen únicamente de las condiciones de la media móvil.
La estrategia dibuja la serie de velas, el indicador de media móvil y sus operaciones en el área del gráfico predeterminada cuando hay un contenedor de gráfico disponible.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Above/Below MA strategy. Trades when price crosses above or below a moving average.
/// </summary>
public class AboveBelowMaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maPeriod;
private decimal? _prevClose;
private decimal? _prevMa;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
public AboveBelowMaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_maPeriod = Param(nameof(MaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Moving average period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = null;
_prevMa = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = null;
_prevMa = null;
var sma = new SimpleMovingAverage { Length = MaPeriod };
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 maVal)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevClose = close;
_prevMa = maVal;
return;
}
if (_prevClose == null || _prevMa == null)
{
_prevClose = close;
_prevMa = maVal;
return;
}
// Price crosses above MA → buy
if (_prevClose.Value <= _prevMa.Value && close > maVal && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Price crosses below MA → sell
else if (_prevClose.Value >= _prevMa.Value && close < maVal && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevClose = close;
_prevMa = maVal;
}
}
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 CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class above_below_ma_strategy(Strategy):
"""
Above/Below MA strategy. Trades when price crosses above or below a moving average.
"""
def __init__(self):
super(above_below_ma_strategy, self).__init__()
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._ma_period = self.Param("MaPeriod", 20) \
.SetGreaterThanZero() \
.SetDisplay("MA Period", "Moving average period", "Indicators")
self._prev_close = None
self._prev_ma = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def MaPeriod(self):
return self._ma_period.Value
@MaPeriod.setter
def MaPeriod(self, value):
self._ma_period.Value = value
def OnReseted(self):
super(above_below_ma_strategy, self).OnReseted()
self._prev_close = None
self._prev_ma = None
def OnStarted2(self, time):
super(above_below_ma_strategy, self).OnStarted2(time)
self._prev_close = None
self._prev_ma = None
sma = SimpleMovingAverage()
sma.Length = self.MaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(sma, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, ma_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
if self._prev_close is None or self._prev_ma is None:
self._prev_close = close
self._prev_ma = ma_val
return
# Price crosses above MA -> buy
if self._prev_close <= self._prev_ma and close > ma_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Price crosses below MA -> sell
elif self._prev_close >= self._prev_ma and close < ma_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_close = close
self._prev_ma = ma_val
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return above_below_ma_strategy()