Открыть на GitHub

Стратегия RSI & CCI Divergence

Описание

RSI & CCI Divergence — адаптация советника RSI&CCI_DIVERGENCE.mq4 (MQL ID 22266) под инфраструктуру StockSharp. Стратегия ищет бычьи и медвежьи расхождения между экстремумами цены и осцилляторов CCI/RSI, подтверждает тренд линейно-взвешенными скользящими средними, затем проверяет согласованность MACD на трёх таймфреймах и оценивает силу импульса с помощью индикатора Momentum на старшем горизонте. Дополнительно предусмотрены опциональные абсолютные уровни стоп-лосса и тейк-профита.

Реализация построена на высокоуровневом API StockSharp: индикаторы привязываются непосредственно к подпискам на свечи, что избавляет от ручного доступа к их значениям и обеспечивает работу в режиме потоковой обработки данных.

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

  1. Фильтр тренда — две LWMA на основном таймфрейме задают направление (бычий режим, если быстрая LWMA выше медленной; медвежий — наоборот).
  2. Выявление расхождений — последняя закрытая свеча сравнивается с CandlesToRetrace предыдущими свечами; фиксируются ситуации, когда индикатор делает более высокий минимум (или более низкий максимум), а цена — противоположное движение.
  3. Подтверждение MACD — индикатор MACD (12/26/9 по умолчанию) рассчитывается на основном, дополнительном и макро таймфреймах; для открытия позиции необходимо, чтобы на всех горизонтах MACD находился по одну сторону от сигнальной линии.
  4. Проверка импульса — на старшем таймфрейме рассчитывается Momentum. Абсолютное отклонение нескольких последних значений от уровня 100 должно превышать заданные пороги MomentumBuyThreshold/MomentumSellThreshold.
  5. Ценовые условия — чтобы повторить оригинальный советник, дополнительно проверяются отношения последних максимумов/минимумов (аналог условий Low[2] < High[1] и Low[1] < High[2]).
  6. Исполнение — при выполнении всех фильтров стратегия отправляет рыночный ордер, увеличивая объём на величину текущей позиции, что позволяет мгновенно переворачиваться.
  7. Риск-менеджмент — если заданы значения StopLoss или TakeProfit, при достижении уровня формируется встречный рыночный ордер на полный объём позиции.

Параметры

Параметр Значение по умолчанию Описание
FastMaLength 6 Период быстрой LWMA.
SlowMaLength 85 Период медленной LWMA.
CciLength 14 Период осциллятора CCI.
RsiLength 14 Период осциллятора RSI.
CandlesToRetrace 10 Количество завершённых свечей для поиска расхождений.
MacdFastPeriod 12 Быстрый период MACD.
MacdSlowPeriod 26 Медленный период MACD.
MacdSignalPeriod 9 Период сигнальной линии MACD.
MomentumLength 14 Период индикатора Momentum.
MomentumBuyThreshold 0.3 Минимальное отклонение от 100 для подтверждения бычьего импульса.
MomentumSellThreshold 0.3 Минимальное отклонение от 100 для подтверждения медвежьего импульса.
StopLoss 0 Абсолютный стоп-лосс (0 — выключен).
TakeProfit 0 Абсолютный тейк-профит (0 — выключен).
CandleType 15 минут Основной таймфрейм для анализа.
MomentumCandleType 1 час Таймфрейм для расчёта Momentum.
HigherMacdCandleType 1 час Дополнительный таймфрейм MACD.
MacroMacdCandleType 30 дней Макро таймфрейм MACD (при необходимости измените под доступные данные).

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

  • Убедитесь, что поставщик данных предоставляет все запрошенные таймфреймы; при отсутствии свечей смените тип данных в параметрах.
  • Значения стоп-лосса/тейк-профита по умолчанию равны нулю, чтобы повторить поведение оригинального советника, использовавшего тралы и контроль по эквити. При желании задайте положительные значения.
  • Momentum проверяет отклонение относительно уровня 100. Если используется другая методика нормализации, скорректируйте пороги MomentumBuyThreshold и MomentumSellThreshold.
  • Стратегия работает исключительно с рыночными ордерами (как при входе, так и при выходе).

Особенности портирования

  • Использована привязка индикаторов через SubscribeCandles().Bind(...); никаких вызовов GetValue().
  • Функционал управления капиталом (equity stop, trailing), уведомления и почтовые рассылки из MQL-версии не перенесены.
  • Для анализа расхождений поддерживается компактный список последних значений цены и индикаторов — этого достаточно для корректной идентификации паттернов без перерасхода памяти.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

public class RsiCciDivergenceStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _cciPeriod;
	private decimal? _prevRsi, _prevCci;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }

	public RsiCciDivergenceStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_rsiPeriod = Param(nameof(RsiPeriod), 14).SetGreaterThanZero().SetDisplay("RSI Period", "RSI lookback", "Indicators");
		_cciPeriod = Param(nameof(CciPeriod), 14).SetGreaterThanZero().SetDisplay("CCI Period", "CCI lookback", "Indicators");
	}

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

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

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevRsi = null; _prevCci = null;
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var cci = new CommodityChannelIndex { Length = CciPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, cci, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal cciVal)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevRsi = rsiVal; _prevCci = cciVal; return; }
		if (_prevRsi == null || _prevCci == null) { _prevRsi = rsiVal; _prevCci = cciVal; return; }
		var buySignal = (_prevRsi.Value < 30m && rsiVal >= 30m) || (_prevCci.Value < -100m && cciVal >= -100m);
		var sellSignal = (_prevRsi.Value > 70m && rsiVal <= 70m) || (_prevCci.Value > 100m && cciVal <= 100m);
		_prevRsi = rsiVal; _prevCci = cciVal;
		if (buySignal && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (sellSignal && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}