Открыть на GitHub

Стратегия CAi Standard Deviation

Данная стратегия является портом с MQL5 эксперта Exp_i-CAi_StDev на платформу StockSharp. Она использует скользящую среднюю и полосы стандартного отклонения для поиска пробоев и последующих возвратов к средним значениям.

Логика стратегии

  1. Рассчитывается простая скользящая средняя (SMA) за заданный период.
  2. Вычисляется стандартное отклонение цен закрытия за тот же период.
  3. Строятся две пары полос вокруг SMA:
    • Полосы входа: SMA ± OpenMultiplier × StdDev.
    • Полосы выхода: SMA ± CloseMultiplier × StdDev.
  4. Открывается длинная позиция при закрытии цены выше верхней полосы входа.
  5. Открывается короткая позиция при закрытии цены ниже нижней полосы входа.
  6. Длинная позиция закрывается, когда цена опускается ниже верхней полосы выхода.
  7. Короткая позиция закрывается, когда цена поднимается выше нижней полосы выхода.

Параметры

Имя Описание Значение
MaLength Период расчёта SMA и стандартного отклонения 12
StdDevPeriod Период индикатора стандартного отклонения 9
OpenMultiplier Множитель для полос входа 2.5
CloseMultiplier Множитель для полос выхода 1.5
CandleType Тип свечей, используемых стратегией 5-минутные свечи

Примечания

  • Стратегия использует высокоуровневый API и механизм Bind для получения значений индикаторов.
  • Обрабатываются только закрытые свечи, чтобы избегать ложных сигналов.
  • Все комментарии в исходном коде написаны на английском языке.
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 based on moving average and standard deviation bands.
/// Opens positions when price breaks outside a wide band
/// and closes them when price returns inside a narrower band.
/// </summary>
public class CaiStandardDeviationStrategy : Strategy
{
	private readonly StrategyParam<int> _maLength;
	private readonly StrategyParam<int> _stdDevPeriod;
	private readonly StrategyParam<decimal> _openMultiplier;
	private readonly StrategyParam<decimal> _closeMultiplier;
	private readonly StrategyParam<DataType> _candleType;

	public int MaLength { get => _maLength.Value; set => _maLength.Value = value; }
	public int StdDevPeriod { get => _stdDevPeriod.Value; set => _stdDevPeriod.Value = value; }
	public decimal OpenMultiplier { get => _openMultiplier.Value; set => _openMultiplier.Value = value; }
	public decimal CloseMultiplier { get => _closeMultiplier.Value; set => _closeMultiplier.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public CaiStandardDeviationStrategy()
	{
		_maLength = Param(nameof(MaLength), 12)
			.SetDisplay("MA Length", "Moving average length", "Parameters")
			.SetOptimize(5, 50, 5);

		_stdDevPeriod = Param(nameof(StdDevPeriod), 9)
			.SetDisplay("StdDev Period", "Standard deviation period", "Parameters")
			.SetOptimize(5, 50, 5);

		_openMultiplier = Param(nameof(OpenMultiplier), 2.5m)
			.SetDisplay("Open Multiplier", "StdDev multiplier for entries", "Parameters")
			.SetOptimize(1m, 3m, 0.5m);

		_closeMultiplier = Param(nameof(CloseMultiplier), 1.5m)
			.SetDisplay("Close Multiplier", "StdDev multiplier for exits", "Parameters")
			.SetOptimize(0.5m, 2m, 0.5m);

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles used", "Parameters");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var sma = new SimpleMovingAverage { Length = MaLength };
		var stdDev = new StandardDeviation { Length = StdDevPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sma, stdDev, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, sma);
			DrawIndicator(area, stdDev);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal smaValue, decimal stdDevValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var upperOpen = smaValue + OpenMultiplier * stdDevValue;
		var lowerOpen = smaValue - OpenMultiplier * stdDevValue;
		var upperClose = smaValue + CloseMultiplier * stdDevValue;
		var lowerClose = smaValue - CloseMultiplier * stdDevValue;

		if (Position <= 0 && candle.ClosePrice > upperOpen)
			BuyMarket();

		if (Position >= 0 && candle.ClosePrice < lowerOpen)
			SellMarket();

		if (Position > 0 && candle.ClosePrice < upperClose)
			SellMarket();

		if (Position < 0 && candle.ClosePrice > lowerClose)
			BuyMarket();
	}
}