Открыть на GitHub

Стратегия OHLC Stochastic

Стратегия следования за импульсом, использующая классический стохастик %K/%D на OHLC-свечах. Алгоритм реагирует на пересечения в зонах перекупленности/перепроданности и защищает сделки наращиваемым трейлинг-стопом в ценовых шагах.

Подробности

  • Основная идея: использовать смену импульса, когда %K пересекает %D в экстремальных зонах.
  • Условия входа:
    • Лонг:
      • %K пересекает %D снизу вверх, и хотя бы одна линия находится ниже порога LevelDown.
      • Если открыта короткая позиция, она закрывается и сразу переворачивается в лонг.
    • Шорт:
      • %K пересекает %D сверху вниз, и хотя бы одна линия выше порога LevelUp.
      • Если открыта длинная позиция, она закрывается и переворачивается в шорт.
  • Условия выхода:
    • Срабатывание трейлинг-стопа (использует расстояние TrailingStopSteps и требование улучшения TrailingStepSteps).
    • Появление противоположного сигнала, запускающего разворот позиции.
  • Логика трейлинга:
    • Расстояние и шаг домножаются на PriceStep инструмента для перевода пипсов/шагов в абсолютную цену.
    • Стоп подтягивается только после того, как цена уйдёт дальше, чем TrailingStopSteps + TrailingStepSteps от входа.
    • Отдельная обработка трейлинга для длинной и короткой стороны.
  • Индикаторы:
  • Направление: Лонг и шорт.
  • Стопы: Только трейлинг (фиксированных SL/TP нет).
  • Размер позиции: Используется параметр Volume; при развороте отправляется объём Volume + |Position|.
  • Параметры по умолчанию:
    • CandleType = TimeSpan.FromHours(12).TimeFrame()
    • KPeriod = 5
    • DPeriod = 3
    • Slowing = 3
    • LevelUp = 70
    • LevelDown = 30
    • TrailingStopSteps = 5 (ценовых шага)
    • TrailingStepSteps = 2 (ценовых шага)
  • Визуализация:
    • При наличии графиков отображаются свечи, стохастик и сделки.

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

  1. Перед запуском задайте нужный инструмент и таймфрейм.
  2. Подгоняйте TrailingStopSteps под шаг цены инструмента, чтобы соответствовать реальным пипсам.
  3. Метод StartProtection() позволяет добавлять внешние правила управления риском.
  4. Наиболее эффективна на трендовых участках, где стохастик заранее показывает разворот импульса.
  5. Для внутридневных инструментов стоит уменьшать расстояние трейлинга, чтобы избежать преждевременных выходов.
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 OhlcStochasticStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private decimal? _prevRsi;

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

	public OhlcStochasticStrategy()
	{
		_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");
	}

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

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

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

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