MA MACD BB BackTester
Стратегия позволяет выбрать один из трех индикаторов: пересечение скользящей средней, пересечение линий MACD или выход за пределы полос Боллинджера. В каждый момент активен только один режим, направление торговли можно выбрать длинное или короткое.
Параметры
CandleType— таймфрейм свечей.Indicator— используемый индикатор (MA, MACD, BB).Direction— направление торговли (Long или Short).MaLength— период скользящей средней.FastLength— быстрый период EMA для MACD.SlowLength— медленный период EMA для MACD.SignalLength— период сигнальной линии MACD.BbLength— период полос Боллинджера.BbMultiplier— множитель полос Боллинджера.StartDate— дата начала работы.EndDate— дата завершения работы.
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()