Открыть на GitHub

Стратегия iCHO Trend CCIDualOnMA Filter

Эта стратегия — перенос на StockSharp эксперта MetaTrader «iCHO Trend CCIDualOnMA Filter». Она объединяет фильтр по нулевой линии осциллятора Chaikin с подтверждением двух индикаторов Commodity Channel Index (CCI), вычисляемых на сглаженной цене. Такой подход позволяет работать по тренду, но при этом требовать согласованного импульса от пары CCI перед входом в сделку.

Логика работы

  1. Основа Chaikin. Линия накопления/распределения сглаживается двумя настраиваемыми скользящими средними. Их разность воспроизводит осциллятор Chaikin. Пересечения нулевой линии показывают смену доминирующего потока капитала.
  2. Двойной CCI. Оба индикатора CCI используют одну и ту же сглаженную цену, но с разными периодами. Для лонга быстрый CCI должен выйти из отрицательной зоны и пересечь медленный сверху при положительном значении Chaikin. Для шорта условия зеркальны.
  3. Инверсия сигналов. Как и в оригинале, флаг «Reverse» меняет местами условия лонга и шорта, что позволяет тестировать контртрендовый режим.
  4. Управление позицией. Дополнительные настройки закрывают противоположные позиции перед входом и ограничивают стратегию одной открытой позицией. Правило «не более одной сделки на бар» соответствует реализации в MetaTrader.
  5. Торговая сессия. Сделки могут ограничиваться внутридневным окном, включая периоды, переходящие через полуночь.

Параметры

Параметр Описание
FastChaikinLength Период быстрой средней внутри осциллятора Chaikin.
SlowChaikinLength Период медленной средней внутри осциллятора Chaikin.
ChaikinMethod Тип скользящей средней (Simple, Exponential, Smoothed, LinearWeighted) для линии накопления/распределения.
FastCciLength Период быстрого CCI.
SlowCciLength Период медленного CCI.
MaLength Длина предварительной скользящей средней, подающей данные в CCI.
MaMethod Тип скользящей средней для предварительного сглаживания цены.
MaPrice Используемый тип цены (close, open, high, low, median, typical, weighted).
UseClosedBar Обрабатывать только полностью сформированные свечи (аналог SignalsBarCurrent = bar_1).
ReverseSignals Инвертировать лонговые и шортовые условия.
CloseOpposite Закрывать встречную позицию перед входом.
OnlyOnePosition Разрешать только одну открытую позицию.
TradeMode Ограничение направлений торговли (BuyOnly, SellOnly, BuyAndSell).
UseTimeFilter Включить фильтр торговой сессии.
StartHour, StartMinute, EndHour, EndMinute Границы торгового окна в биржевом времени (начало включительно, конец исключительно), поддерживаются ночные переходы.
CandleType Таймфрейм свечей, подаваемых в индикаторы.

Дополнительно

  • Стратегия работает только через высокоуровневый SubscribeCandles и штатные индикаторы — дополнительные буферы не требуются.
  • Сглаживание цены перед расчётом CCI повторяет схему оригинального индикатора CCIDualOnMA.
  • Значения по умолчанию соответствуют исходному советнику: Chaikin EMA 3/10, CCI 14 и 50, сглаживание SMA(12) и торговое окно 10:01–15:02.
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Combines a Chaikin oscillator zero-line filter with CCI confirmation.
/// Buys when Chaikin crosses above zero and CCI is rising, sells on opposite.
/// </summary>
public class iCHO_Trend_CCIDualOnMA_FilterStrategy : Strategy
{
	private readonly StrategyParam<int> _cciLength;
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<decimal> _cciLevel;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private decimal? _prevCci;
	private decimal? _prevPrevCci;
	private int _candlesSinceTrade;

	public int CciLength
	{
		get => _cciLength.Value;
		set => _cciLength.Value = value;
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public decimal CciLevel
	{
		get => _cciLevel.Value;
		set => _cciLevel.Value = value;
	}

	public int SignalCooldownCandles
	{
		get => _signalCooldownCandles.Value;
		set => _signalCooldownCandles.Value = value;
	}

	public iCHO_Trend_CCIDualOnMA_FilterStrategy()
	{
		_cciLength = Param(nameof(CciLength), 14)
			.SetGreaterThanZero()
			.SetDisplay("CCI Length", "CCI period", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Primary candle series", "Data");

		_cciLevel = Param(nameof(CciLevel), 100m)
			.SetDisplay("CCI Level", "CCI threshold for entry", "Indicators");

		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 4)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between entries", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevCci = null;
		_prevPrevCci = null;
		_candlesSinceTrade = SignalCooldownCandles;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevCci = null;
		_prevPrevCci = null;
		_candlesSinceTrade = SignalCooldownCandles;

		var cci = new CommodityChannelIndex { Length = CciLength };

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

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

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		if (_prevCci.HasValue && _prevPrevCci.HasValue)
		{
			if (_prevPrevCci.Value < -CciLevel && _prevCci.Value < -CciLevel && cciValue > -CciLevel && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
			else if (_prevPrevCci.Value > CciLevel && _prevCci.Value > CciLevel && cciValue < CciLevel && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
		}

		_prevPrevCci = _prevCci;
		_prevCci = cciValue;
	}
}