Открыть на GitHub

Стратегия FT CCI

Стратегия представляет собой порт Expert Advisor MetaTrader 5 «FT_CCI (barabashkakvn's edition)», переписанный под StockSharp. В основе лежит индикатор Commodity Channel Index (CCI), который отлавливает резкие развороты, когда осциллятор заметно удаляется от средней. При пробое нижней границы стратегия переворачивается в покупки, при пробое верхней — в продажи. Стоп-лосс и тейк-профит задаются в пунктах (pips) и автоматически пересчитываются в абсолютный ценовой шаг.

Общие сведения

  • Базовый индикатор: Commodity Channel Index с настраиваемым периодом усреднения (по умолчанию 14).
  • Направление торговли: симметричное. Открывается максимум одна нетто-позиция, при смене сигнала выполняется разворот.
  • Исполнение: рыночные заявки на закрытии сформировавшихся свечей выбранного таймфрейма.
  • Управление риском: опциональные стоп-лосс и тейк-профит в пунктах. Нулевое значение отключает соответствующий защитный ордер.
  • Таймфрейм по умолчанию: свечи 30 минут (аналогично Period() в оригинальном советнике).

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

Вход в лонг

  1. Подписка на завершённые свечи выбранного таймфрейма.
  2. Расчёт CCI по типичной цене (Typical Price).
  3. Если CCI опускается до нижнего порога или ниже (по умолчанию -210):
    • Закрываются все открытые шорты.
    • Открывается или наращивается длинная позиция указанным объёмом.
  4. Позиция удерживается до появления противоположного сигнала, срабатывания стоп-ордера или ручной остановки стратегии.

Вход в шорт

  1. Контроль значений CCI на тех же закрытых свечах.
  2. Если CCI поднимается до верхнего порога или выше (по умолчанию +210):
    • Закрываются все лонги.
    • Открывается или усиливается короткая позиция настроенным объёмом.
  3. Шорт удерживается до противоположного сигнала или до срабатывания защитных ордеров.

Сопровождение сделки

  • Значения стоп-лосса и тейк-профита задаются в пунктах и умножаются на рассчитанный размер пункта (ценовой шаг, умноженный на 10 для инструментов с 3 и 5 знаками после запятой). Полученный абсолютный оффсет передаётся в StartProtection.
  • Защита активируется однократно при запуске, поэтому каждая новая сделка автоматически наследует заданные стоп и цель от цены входа.
  • Перевороты выполняются рыночными ордерами объёмом настроенный объём + |текущая позиция|, что одновременно закрывает старую позицию и открывает новую в противоположную сторону.

Параметры

Имя Описание
Candle Type Таймфрейм, используемый для расчётов и сигналов.
Trade Volume Торговый объём (лоты) для новых позиций. Используется и при переворотах.
CCI Period Период усреднения индикатора CCI.
CCI Upper Threshold Уровень CCI для открытия коротких позиций.
CCI Lower Threshold Уровень CCI для открытия длинных позиций.
Stop Loss (pips) Расстояние до защитного стопа в пунктах. Ноль — отключить.
Take Profit (pips) Расстояние до тейк-профита в пунктах. Ноль — отключить.

Все параметры доступны для оптимизации через менеджер параметров StockSharp.

Рекомендации по использованию

  • Лучше всего работает на ликвидных валютных парах и индексах, где экстремумы CCI ярко выражены на свечах от 30 минут до 4 часов.
  • Пороговые значения ±210 повторяют настройки FT_CCI. Уменьшение делает систему более чувствительной, увеличение — фильтрует только самые сильные движения.
  • Убедитесь, что инструмент содержит корректный PriceStep. Именно он используется для перевода пунктов в абсолютное ценовое расстояние.
  • Стратегия рассчитана на неттинговую модель (одна суммарная позиция). В хеджинговых аккаунтах подбирайте объём так, чтобы переворот полностью закрывал предыдущую позицию.

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

  • Сигналы учитываются только после формирования индикатора. Первые свечи игнорируются, пока CCI не накопит достаточную историю.
  • Стоп-ордера необязательны. Если оставить оба значения нулевыми, стратегия будет закрываться только по противоположным сигналам, как в оригинале.
  • При подключении к графику в StockSharp автоматически отображаются свечи, индикатор CCI и совершённые сделки, что упрощает визуальный анализ.
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>
/// CCI breakout strategy. Opens long when CCI drops below lower band, shorts when above upper band.
/// </summary>
public class FtCciStrategy : Strategy
{
	private readonly StrategyParam<int> _cciPeriod;
	private readonly StrategyParam<decimal> _upperThreshold;
	private readonly StrategyParam<decimal> _lowerThreshold;
	private readonly StrategyParam<DataType> _candleType;

	public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
	public decimal UpperThreshold { get => _upperThreshold.Value; set => _upperThreshold.Value = value; }
	public decimal LowerThreshold { get => _lowerThreshold.Value; set => _lowerThreshold.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public FtCciStrategy()
	{
		_cciPeriod = Param(nameof(CciPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("CCI Period", "Averaging period for CCI", "Indicator");

		_upperThreshold = Param(nameof(UpperThreshold), 210m)
			.SetDisplay("CCI Upper", "CCI level for short entries", "Indicator");

		_lowerThreshold = Param(nameof(LowerThreshold), -210m)
			.SetDisplay("CCI Lower", "CCI level for long entries", "Indicator");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle Type", "General");
	}

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

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

		var cci = new CommodityChannelIndex { Length = CciPeriod };

		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 (cciValue <= LowerThreshold && Position <= 0)
			BuyMarket();
		else if (cciValue >= UpperThreshold && Position >= 0)
			SellMarket();

		// Exit when CCI returns to zero
		if (Position > 0 && cciValue >= 0)
			SellMarket();
		else if (Position < 0 && cciValue <= 0)
			BuyMarket();
	}
}