Стратегия ColorXvaMA Digit StDev
Обзор
Стратегия торгует на отклонении цены от экспоненциальной скользящей средней (EMA). Два множителя отклонения (K1 и K2) формируют внутреннюю и внешнюю полосы, рассчитанные по стандартному отклонению цены.
Когда цена превышает EMA на K2 стандартных отклонения, стратегия открывает длинную позицию. Когда цена опускается ниже EMA на K2 стандартных отклонения, открывается короткая позиция. Существующие позиции закрываются, когда отклонение возвращается в пределы внутренней полосы K1.
Параметры
- EMA Length – период экспоненциальной скользящей средней.
- StdDev Length – период стандартного отклонения.
- Deviation K1 – множитель внутренней полосы для выхода из позиции.
- Deviation K2 – множитель внешней полосы для входа.
- Candle Type – таймфрейм свечей.
Индикаторы
- Exponential Moving Average
- StandardDeviation
Как работает
- Подписка на свечи выбранного таймфрейма.
- Расчёт EMA и стандартного отклонения цены.
- Вычисление отклонения цены от EMA.
- Вход в длинную/короткую позицию, когда отклонение превышает ±K2×StdDev.
- Закрытие позиции при возврате отклонения в диапазон ±K1×StdDev.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that enters positions based on price deviation from EMA and standard deviation.
/// Opens long when price is above EMA by K2*StdDev and short when below by K2*StdDev.
/// Closes positions when deviation returns within K1*StdDev.
/// </summary>
public class ColorXvaMaDigitStDevStrategy : Strategy
{
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<int> _stdLength;
private readonly StrategyParam<decimal> _k1;
private readonly StrategyParam<decimal> _k2;
private readonly StrategyParam<DataType> _candleType;
/// <summary>
/// EMA period length.
/// </summary>
public int MaLength { get => _maLength.Value; set => _maLength.Value = value; }
/// <summary>
/// Standard deviation period.
/// </summary>
public int StdLength { get => _stdLength.Value; set => _stdLength.Value = value; }
/// <summary>
/// Inner deviation multiplier.
/// </summary>
public decimal K1 { get => _k1.Value; set => _k1.Value = value; }
/// <summary>
/// Outer deviation multiplier.
/// </summary>
public decimal K2 { get => _k2.Value; set => _k2.Value = value; }
/// <summary>
/// Candle type used by the strategy.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Initializes parameters.
/// </summary>
public ColorXvaMaDigitStDevStrategy()
{
_maLength = Param(nameof(MaLength), 15)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "Period for the exponential moving average", "Parameters");
_stdLength = Param(nameof(StdLength), 9)
.SetGreaterThanZero()
.SetDisplay("StdDev Length", "Period for standard deviation", "Parameters");
_k1 = Param(nameof(K1), 1.5m)
.SetDisplay("Deviation K1", "Inner band multiplier", "Parameters");
_k2 = Param(nameof(K2), 2.5m)
.SetDisplay("Deviation K2", "Outer band multiplier", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for market data", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = MaLength };
var std = new StandardDeviation { Length = StdLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, std, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue, decimal stdValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (stdValue == 0m)
return;
var deviation = candle.ClosePrice - emaValue;
var filter1 = K1 * stdValue;
var filter2 = K2 * stdValue;
// Open long when price exceeds the upper band
if (Position <= 0 && deviation > filter2)
{
BuyMarket();
}
// Open short when price falls below the lower band
else if (Position >= 0 && deviation < -filter2)
{
SellMarket();
}
// Close long when price returns inside inner band
else if (Position > 0 && deviation < filter1)
{
SellMarket();
}
// Close short when price returns inside inner band
else if (Position < 0 && deviation > -filter1)
{
BuyMarket();
}
}
}
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, StandardDeviation
from StockSharp.Algo.Strategies import Strategy
class color_xva_ma_digit_st_dev_strategy(Strategy):
def __init__(self):
super(color_xva_ma_digit_st_dev_strategy, self).__init__()
self._ma_length = self.Param("MaLength", 15) \
.SetDisplay("EMA Length", "Period for the exponential moving average", "Parameters")
self._std_length = self.Param("StdLength", 9) \
.SetDisplay("StdDev Length", "Period for standard deviation", "Parameters")
self._k1 = self.Param("K1", 1.5) \
.SetDisplay("Deviation K1", "Inner band multiplier", "Parameters")
self._k2 = self.Param("K2", 2.5) \
.SetDisplay("Deviation K2", "Outer band multiplier", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for market data", "General")
@property
def ma_length(self):
return self._ma_length.Value
@property
def std_length(self):
return self._std_length.Value
@property
def k1(self):
return self._k1.Value
@property
def k2(self):
return self._k2.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(color_xva_ma_digit_st_dev_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = int(self.ma_length)
std = StandardDeviation()
std.Length = int(self.std_length)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, std, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
def process_candle(self, candle, ema_value, std_value):
if candle.State != CandleStates.Finished:
return
ema_value = float(ema_value)
std_value = float(std_value)
if std_value == 0:
return
close = float(candle.ClosePrice)
deviation = close - ema_value
k1 = float(self.k1)
k2 = float(self.k2)
filter1 = k1 * std_value
filter2 = k2 * std_value
if self.Position <= 0 and deviation > filter2:
self.BuyMarket()
elif self.Position >= 0 and deviation < -filter2:
self.SellMarket()
elif self.Position > 0 and deviation < filter1:
self.SellMarket()
elif self.Position < 0 and deviation > -filter1:
self.BuyMarket()
def CreateClone(self):
return color_xva_ma_digit_st_dev_strategy()