Estrategia MA MACD BB BackTester
Estrategia que combina tres indicadores seleccionables: cruce de media móvil simple, cruce de MACD o ruptura de Bandas de Bollinger. Solo un modo de indicador está activo a la vez, y la dirección de la operación puede ser largo o corto.
Parámetros
CandleType— marco temporal de las velas.Indicator— indicador a utilizar (MA, MACD, BB).Direction— dirección de la operación (Long o Short).MaLength— período de la media móvil.FastLength— longitud de la EMA rápida del MACD.SlowLength— longitud de la EMA lenta del MACD.SignalLength— longitud de la señal del MACD.BbLength— período de las Bandas de Bollinger.BbMultiplier— multiplicador de las Bandas de Bollinger.StartDate— fecha de inicio.EndDate— fecha de fin.
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;
/// <summary>
/// Strategy using MA crossover with price for entry/exit.
/// </summary>
public class MaMacdBbBackTesterStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maLength;
private ExponentialMovingAverage _ma;
private decimal _prevClose;
private decimal _prevMa;
private bool _initialized;
private int _cooldown;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int MaLength { get => _maLength.Value; set => _maLength.Value = value; }
public MaMacdBbBackTesterStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_maLength = Param(nameof(MaLength), 20)
.SetDisplay("MA Length", "MA period", "Indicators");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = default;
_prevMa = default;
_initialized = false;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_ma = new ExponentialMovingAverage { Length = MaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_ma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _ma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal maVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!_ma.IsFormed)
return;
if (!_initialized)
{
_prevClose = candle.ClosePrice;
_prevMa = maVal;
_initialized = true;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevClose = candle.ClosePrice;
_prevMa = maVal;
return;
}
var crossUp = _prevClose <= _prevMa && candle.ClosePrice > maVal;
var crossDown = _prevClose >= _prevMa && candle.ClosePrice < maVal;
if (crossUp && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_cooldown = 10;
}
else if (crossDown && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_cooldown = 10;
}
_prevClose = candle.ClosePrice;
_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 DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class ma_macd_bb_back_tester_strategy(Strategy):
def __init__(self):
super(ma_macd_bb_back_tester_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candles", "General")
self._ma_length = self.Param("MaLength", 20) \
.SetDisplay("MA Length", "MA period", "Indicators")
self._prev_close = 0.0
self._prev_ma = 0.0
self._initialized = False
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(ma_macd_bb_back_tester_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_ma = 0.0
self._initialized = False
self._cooldown = 0
def OnStarted2(self, time):
super(ma_macd_bb_back_tester_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._prev_ma = 0.0
self._initialized = False
self._cooldown = 0
self._ma = ExponentialMovingAverage()
self._ma.Length = self._ma_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._ma, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._ma)
self.DrawOwnTrades(area)
def OnProcess(self, candle, ma_val):
if candle.State != CandleStates.Finished:
return
if not self._ma.IsFormed:
return
mv = float(ma_val)
close = float(candle.ClosePrice)
if not self._initialized:
self._prev_close = close
self._prev_ma = mv
self._initialized = True
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_close = close
self._prev_ma = mv
return
cross_up = self._prev_close <= self._prev_ma and close > mv
cross_down = self._prev_close >= self._prev_ma and close < mv
if cross_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown = 10
elif cross_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown = 10
self._prev_close = close
self._prev_ma = mv
def CreateClone(self):
return ma_macd_bb_back_tester_strategy()