USD/CHF CCI Channel Stop — перенос советника MetaTrader 4 UsdChf_new на высокоуровневый API StockSharp. Стратегия анализирует готовые H4-свечи, вычисляет показатель Commodity Channel Index (CCI) и при пробое каналов ±CCI Channel выставляет отложенные стоп-ордера над/под ценой. После активации позиция сопровождается теми же правилами управления риском, что и в оригинале: фиксированный стоп-лосс, удаление устаревших заявок, перевод в безубыток и трал.
Вся логика реализована через высокоуровневые механизмы StockSharp — подписку на свечи, привязку индикаторов и вспомогательные методы регистрации ордеров (BuyStop, SellStop, BuyMarket, SellMarket). Настройки по-прежнему задаются в пунктах, что удобно для форекс-трейдеров.
Логика торговли
Сигналы по CCI
На каждой завершённой H4-свече рассчитывается CCI с заданным периодом.
Хранится предыдущее значение, что позволяет отслеживать факт пересечения уровней.
Пересечение снизу вверх уровня -CCI Channel → подготовка buy stop выше цены.
Пересечение сверху вниз уровня +CCI Channel → подготовка sell stop ниже цены.
Управление отложенными ордерами
Цена размещения сдвигается на Entry Indent (pips) и округляется по шагу цены инструмента.
Одновременно может быть активен только один стоп-ордер — новый сигнал отменяет противоположный.
Если рынок ушёл дальше чем на Cancel Distance (pips), заявка отменяется, чтобы не догонять цену.
Сопровождение позиции
После исполнения стоп-ордера фиксируется стартовый стоп-лосс.
При прибыли больше Break Even (pips) защитный стоп переносится на цену входа.
Как только прибыль превысит Trailing Stop (pips), стоп подтягивается вслед за ценой, сохраняя указанную дистанцию.
Обратное пересечение CCI закрывает позицию по рынку и ставит новую отложенную заявку в противоположном направлении.
Параметры
Параметр
Назначение
Значение по умолчанию
Оптимизация
CandleType
Тип свечей для сигналов (по умолчанию H4).
4 часа
Нет
CciPeriod
Период усреднения CCI.
73
Да
CciChannel
Абсолютная граница канала CCI.
120
Да
EntryIndentPips
Смещение стоп-ордера от рынка в пунктах.
30
Да
StopLossPips
Размер первоначального стоп-лосса.
95
Да
CancelDistancePips
Допустимое удаление цены до отмены заявки.
30
Да
TrailingStopPips
Дистанция трейлинг-стопа.
110
Да
BreakEvenPips
Прибыль для перевода в безубыток.
60
Да
Пересчёт пунктов в цену выполняется автоматически: для инструментов с 3/5 знаками после запятой 1 пункт = 10 шагам цены, иначе 1 пункт = 1 шагу.
Рекомендации по применению
Подключите стратегию к инструменту USD/CHF или другому форекс-активу с пунктовой котировкой.
Настройте объём через стандартное свойство Strategy.Volume.
Скорректируйте пунктовые параметры под спецификацию брокера.
Перед реальной торговлей выполните бэктест в Designer/Tester для проверки поведения.
Особенности конверсии
В MT4 советник перебирал все ордера через OrdersTotal. В StockSharp используются ссылки на конкретные pending-заявки и методы отмены.
Стоп-лосс, безубыток и трал реализованы через рыночные выходы, так как высокоуровневый API не модифицирует брокерские ордера напрямую.
Все комментарии переписаны на английский и дополнены пояснениями по работе со StockSharp.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class UsdChfNewStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
private int _cooldownRemaining;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public UsdChfNewStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 20).SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 80).SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_cooldownCandles = Param(nameof(CooldownCandles), 100).SetDisplay("Cooldown", "Candles between signals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = default;
_prevSlow = default;
_hasPrev = default;
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
_cooldownRemaining = 0;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevFast = fast;
_prevSlow = slow;
return;
}
if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
_prevFast = fast;
_prevSlow = slow;
}
}