Открыть на GitHub

Стратегия CorrTime

CorrTime — это односессионная стратегия, перенесённая из одноимённого советника MetaTrader. Она отслеживает корреляцию между ценой закрытия и порядком появления баров, чтобы выявлять ускорение тренда или потенциальный разворот. Работа ведётся только по завершённым свечам и включает три уровня фильтрации:

  1. Фильтр волатильности. Ширина полос Боллинджера должна находиться внутри заданного диапазона. Так исключаются как боковые периоды, так и чрезмерно бурные участки.
  2. Фильтр силы тренда. Значение индикатора ADX должно быть выше порога, прежде чем будет проверен сигнал корреляции.
  3. Корреляционные триггеры. Коэффициенты Пирсона, Спирмена, Кендалла или Фехнера измеряют, насколько тесно цена связана со временем. Резкое изменение коэффициента приводит к торговому действию.

Оригинальный робот работал на EURUSD с таймфреймом H1. Перенос для StockSharp оставляет все параметры настраиваемыми, но значения по умолчанию соответствуют источнику (часовые свечи, корреляция Фехнера, режим обратной торговли).

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

  1. Подписаться на выбранный CandleType и дождаться закрытия бара.
  2. Обновить значения полос Боллинджера и ADX для новой свечи.
  3. Пропустить бар, если выполняется хотя бы одно условие:
    • Ширина полос, выраженная в пунктах, вне диапазона [BollingerSpreadMin, BollingerSpreadMax].
    • Значение ADX ниже AdxLevel.
    • Время открытия свечи находится вне торгового окна [EntryHour, EntryHour + OpenHours] (поддерживается переход через полночь).
  4. Накапливать историю закрытий и пересчитывать корреляцию для окон CorrelationRangeTrend и CorrelationRangeReverse. Хранятся три последних значения, что позволяет отследить факт пересечения порога — точно как в оригинальной библиотеке с буферами.
  5. Режим следования тренду (TradeMode = TrendFollow или Both):
    • Покупка. Корреляция была ниже CorrLimitTrendBuy, остаётся ниже на предыдущем баре и пробивает верхний порог на текущем.
    • Продажа. Корреляция была выше -CorrLimitTrendSell, остаётся выше на предыдущем баре и падает ниже -CorrLimitTrendSell на текущем.
  6. Режим разворота (TradeMode = Reverse или Both):
    • Покупка. Корреляция была ниже -CorrLimitReverseBuy, остаётся ниже на предыдущем баре и поднимается выше -CorrLimitReverseBuy на текущем.
    • Продажа. Корреляция была выше CorrLimitReverseSell, остаётся выше на предыдущем баре и опускается ниже CorrLimitReverseSell на текущем.
  7. Если одновременно получены сигналы в обе стороны, они взаимно отменяются, как и в MetaTrader.
  8. При включённом флаге CloseTradeOnOppositeSignal стратегия закрывает противоположную позицию до открытия новой.
  9. Размер входа задаётся параметром Volume. Ограничение MaxOpenOrders не позволяет накопить позицию больше Volume * MaxOpenOrders в любую сторону.
  10. Риск контролируется методом StartProtection: стоп-лосс и тейк-профит переводятся из пунктов в цену, а при наличии трейлинга используется тот же шаг.

Параметры

Параметр Описание
CandleType Таймфрейм, по которому строятся свечи и рассчитываются индикаторы.
CloseTradeOnOppositeSignal Закрывать ли текущую позицию при появлении противоположного сигнала.
EntryHour, OpenHours Торговое окно в часах. Значение OpenHours = 0 оставляет окно открытым на один час.
BollingerPeriod, BollingerDeviation Настройки полос Боллинджера по ценам закрытия.
BollingerSpreadMin, BollingerSpreadMax Допустимый диапазон ширины канала в пунктах.
AdxPeriod, AdxLevel Период ADX и минимальное значение силы тренда.
TradeMode Выбор режима торговли: по тренду, на разворот или комбинация.
CorrelationRangeTrend, CorrelationRangeReverse Длины окон для вычисления корреляции.
CorrelationType Выбор коэффициента: Пирсон, Спирмен, Кендалл или Фехнер.
CorrLimitTrendBuy, CorrLimitTrendSell Пороговые значения для сигналов по тренду.
CorrLimitReverseBuy, CorrLimitReverseSell Пороговые значения для сигналов на разворот.
TakeProfitPips, StopLossPips, TrailingStopPips Риск-параметры в пунктах, автоматически переводятся в цену инструмента.
MaxOpenOrders Максимальное количество агрегированных входов (ограничение по объёму Volume * MaxOpenOrders).

Практические замечания

  • Размер пункта вычисляется по количеству знаков инструмента. Для пяти и трёх знаков используется множитель ×10, что полностью повторяет обработку Point и MULT в оригинале.
  • Для проверки пересечения порога необходим минимум окно + 2 закрытых свечи. В фазе прогрева стратегия бездействует.
  • Вся логика основана на завершённых барах, поэтому результаты совпадают с подходом iTime/iClose в MetaTrader и не подвержены внутрибарах шуму.
  • Если стратегия запускается в составе портфеля, дополнительно ограничьте общий риск, поскольку исходный советник также учитывал количество ордеров на других символах.
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// CorrTime strategy: Bollinger Bands mean reversion.
/// Buys when close drops below lower BB.
/// Sells when close rises above upper BB.
/// </summary>
public class CorrTimeStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _bbPeriod;
	private readonly StrategyParam<decimal> _bbWidth;

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

	public int BbPeriod
	{
		get => _bbPeriod.Value;
		set => _bbPeriod.Value = value;
	}

	public decimal BbWidth
	{
		get => _bbWidth.Value;
		set => _bbWidth.Value = value;
	}

	public CorrTimeStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_bbPeriod = Param(nameof(BbPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");

		_bbWidth = Param(nameof(BbWidth), 2m)
			.SetDisplay("BB Width", "Bollinger Bands width", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var bb = new BollingerBands { Length = BbPeriod, Width = BbWidth };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(bb, ProcessCandle)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var bbv = (BollingerBandsValue)bbVal;
		if (bbv.UpBand is not decimal upper ||
			bbv.LowBand is not decimal lower)
			return;

		var close = candle.ClosePrice;

		if (close < lower && Position <= 0)
			BuyMarket();
		else if (close > upper && Position >= 0)
			SellMarket();
	}
}