ThreeMaBunnyCrossStrategy es una conversión del MetaTrader 4 asesor experto "3MA Bunny Cross". Negocia cambios de tendencia basados en el cruce entre dos promedios móviles ponderados lineales (LWMA) calculados sobre los precios de cierre del período de tiempo seleccionado. La versión StockSharp mantiene la idea original de revertir la posición inmediatamente después de un cruce y agrega comodidades API de alto nivel, como vinculación de indicadores y protección contra riesgos incorporada.
Original MQL Descripción
El asesor experto fuente utiliza dos LWMA con períodos 5 y 20. Cuando la LWMA rápida cruza la LWMA lenta, el asesor cierra la posición opuesta, si existe, e inmediatamente abre una nueva operación en la dirección del cruce. Sólo se permite una posición en cualquier momento. El script original también verifica un número mínimo de barras y margen libre antes de operar.
StockSharp Detalles de implementación
La estrategia se suscribe a velas definidas por el parámetro CandleType (período de tiempo de 15 minutos por defecto) y las vincula a dos indicadores LinearWeightedMovingAverage.
Los valores del indicador se proporcionan directamente al método de procesamiento a través de Bind, lo que elimina la necesidad de manejo manual del búfer.
Los valores rápidos y lentos anteriores se almacenan en caché para detectar cruces usando la misma lógica que la versión MQL (fast cruzando por encima o por debajo de slow).
Cuando se produce un cruce alcista y la posición actual es plana o corta, la estrategia envía una orden de compra de mercado del tamaño necesario para cerrar cualquier exposición corta y abrir una nueva larga (Volume + |Position|). El cruce bajista se comporta simétricamente para las ventas.
StartProtection() se llama una vez al inicio para habilitar las rutinas de protección de posición integradas.
La visualización del gráfico muestra las velas fuente junto con las dos medias móviles y las operaciones propias de la estrategia.
Parámetros
CandleType: tipo de datos que describe la serie de velas a la que suscribirse (el valor predeterminado es un período de tiempo de 15 minutos).
FastPeriod – período de la LWMA rápida. Valor predeterminado: 5. Optimizable.
SlowPeriod – período de la LWMA lenta. Predeterminado: 20. Optimizable.
Indicadores
LinearWeightedMovingAverage (rápido, período 5 por defecto).
LinearWeightedMovingAverage (lento, período 20 por defecto).
Reglas de trading
Espere a que termine una vela y verifique que la estrategia esté formada, en línea y permitida para operar.
Detecte un cruce alcista cuando la LWMA rápida estaba por debajo o igual a la LWMA lenta en la vela anterior y está por encima o igual a ella en la vela actual. En este caso, cierre cualquier posición corta existente y abra una larga.
Detecte un cruce bajista cuando la LWMA rápida estaba por encima o igual a la LWMA lenta en la vela anterior y está por debajo o igual a ella en la vela actual. En este caso, cierre cualquier posición larga existente y abra una corta.
Cada nuevo tamaño de orden se calcula como Volume + |Position| para revertir completamente cualquier exposición pendiente, garantizando que solo exista una posición direccional a la vez.
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>
/// 3MA Bunny Cross strategy using weighted moving average crossover.
/// Goes long on fast WMA crossing above slow WMA, short on opposite.
/// </summary>
public class ThreeMaBunnyCrossStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ThreeMaBunnyCrossStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 5)
.SetDisplay("Fast WMA", "Fast weighted MA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 20)
.SetDisplay("Slow WMA", "Slow weighted MA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0m;
_prevSlow = 0m;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fast = new WeightedMovingAverage { Length = FastPeriod };
var slow = new WeightedMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (!_hasPrev)
{
_prevFast = fast;
_prevSlow = slow;
_hasPrev = true;
return;
}
var crossUp = _prevFast <= _prevSlow && fast > slow;
var crossDown = _prevFast >= _prevSlow && fast < slow;
if (crossUp && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevFast = fast;
_prevSlow = slow;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class three_ma_bunny_cross_strategy(Strategy):
"""3MA Bunny Cross strategy using weighted moving average crossover.
Goes long on fast WMA crossing above slow WMA, short on opposite."""
def __init__(self):
super(three_ma_bunny_cross_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 5) \
.SetDisplay("Fast WMA", "Fast weighted MA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 20) \
.SetDisplay("Slow WMA", "Slow weighted MA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(three_ma_bunny_cross_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(three_ma_bunny_cross_strategy, self).OnStarted2(time)
self._has_prev = False
fast = WeightedMovingAverage()
fast.Length = self.FastPeriod
slow = WeightedMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._process_candle).Start()
def _process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast)
slow_val = float(slow)
if not self._has_prev:
self._prev_fast = fast_val
self._prev_slow = slow_val
self._has_prev = True
return
cross_up = self._prev_fast <= self._prev_slow and fast_val > slow_val
cross_down = self._prev_fast >= self._prev_slow and fast_val < slow_val
if cross_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif cross_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return three_ma_bunny_cross_strategy()