Стратегия Stochastic Accelerator — это конверсия эксперта MetaTrader 5 #2 stoch mt5. Оригинальный советник анализирует три
осциллятора Stochastic совместно с осциллятором Accelerator Билла Уильямса и Awesome Oscillator. Длинная позиция открывается
только тогда, когда все стохастические фильтры указывают на бычью инерцию, а Accelerator Oscillator пробивает вверх заданный
порог. Короткие позиции используют симметричные условия. После входа контроль импульса передаётся Awesome Oscillator — при
обратном пересечении заданного уровня позиция закрывается. Портирование на StockSharp повторяет эту логику, применяя
высокоуровневые подписки на свечи и привязку индикаторов через API.
Стратегия сохраняет структуру управления капиталом оригинала. Входы выполняются фиксированным лотом, а стоп-лосс и тейк-профит
заданы в метатрейдеровских пунктах. В реализации StockSharp используется StartProtection, поэтому защитные уровни прикрепляются
к каждой новой позиции автоматически. Размер шага цены преобразуется в пункты MetaTrader, что обеспечивает одинаковые защитные
расстояния у разных брокеров.
Логика торговли
Подписаться на свечи типа CandleType и обрабатывать только закрытые бары, как делает эксперт на MetaTrader.
Питать три экземпляра StochasticOscillator:
Сигнальный стохастик проверяет, находится ли %K выше или ниже %D.
Стохастик входа убеждается, что бычьи сигналы находятся выше EntryLevel (для продаж используется 100 - EntryLevel).
Стохастик фильтра ограничивает бычьи сигналы, требуя, чтобы %K оставался ниже FilterLevel (для продаж — выше 100 - FilterLevel).
Отслеживать Accelerator Oscillator и требовать пересечения уровня AcceleratorLevel вверх для покупок и вниз через -AcceleratorLevel для продаж.
Закрывать открытую позицию, когда Awesome Oscillator пересекает уровень AwesomeLevel в противоположном направлении.
После выхода открывать новую позицию только в том случае, если условия выполнены ровно по одной стороне. Объём корректируется
под шаг лота инструмента, чтобы заявки принимались реальным брокером.
Применять стоп-лосс и тейк-профит через StartProtection, сохраняя пунктовую систему рисков MetaTrader.
Верхний уровень ограничения покупок (для продаж используется 100 - FilterLevel).
AcceleratorLevel
decimal
0.0002
Минимальная амплитуда Accelerator Oscillator для входа.
AwesomeLevel
decimal
0.0013
Порог Awesome Oscillator, при котором позиция закрывается.
Отличия от оригинального эксперта MetaTrader
Вместо многократных вызовов CopyBuffer используются свечные подписки и привязка индикаторов StockSharp.
Управление позициями ведётся в неттинговом режиме: при необходимости разворота текущая позиция сначала закрывается, затем
отправляется рыночная заявка в противоположную сторону.
Стоп-лосс и тейк-профит подключаются через StartProtection, при этом расстояния вычисляются в пунктах на основе шага цены
инструмента — это избавляет от ручной модификации ордеров и сохраняет эквивалентность метатрейдеровским настройкам.
Запрашиваемый объём нормализуется по VolumeStep, MinVolume и MaxVolume, чтобы код можно было сразу использовать в
реальной торговле.
Рекомендации по использованию
Перед запуском настройте TradeVolume под минимальный шаг лота инструмента.
Совместно подбирайте уровни стохастиков (EntryLevel, FilterLevel) и пороги осцилляторов, чтобы добиться нужной строгости
фильтров на вашем рынке.
При возможности включайте отображение на графике, чтобы видеть три стохастика, Accelerator Oscillator, Awesome Oscillator и
совершённые сделки.
Так как расчёт ведётся на закрытых свечах, сигналы появляются в момент закрытия бара. Используйте тестер с тем же таймфреймом
для сопоставимых результатов.
Индикаторы
Три экземпляра StochasticOscillator с независимыми параметрами сглаживания и уровнями.
AcceleratorOscillator для подтверждения входа.
AwesomeOscillator для фиксации момента выхода.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Stochastic Accelerator strategy: Rate of Change crossover.
/// Buys when ROC crosses above zero, sells when ROC crosses below zero.
/// </summary>
public class StochasticAcceleratorStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private readonly StrategyParam<decimal> _rocLevel;
private readonly StrategyParam<int> _signalCooldownCandles;
private decimal _prevRoc;
private int _candlesSinceTrade;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int Period { get => _period.Value; set => _period.Value = value; }
public decimal RocLevel { get => _rocLevel.Value; set => _rocLevel.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public StochasticAcceleratorStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_period = Param(nameof(Period), 12)
.SetGreaterThanZero()
.SetDisplay("Period", "ROC period", "Indicators");
_rocLevel = Param(nameof(RocLevel), 0.2m)
.SetDisplay("ROC Level", "ROC threshold for crossover", "Signals");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 4)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRoc = 0;
_candlesSinceTrade = SignalCooldownCandles;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevRoc = 0;
_candlesSinceTrade = SignalCooldownCandles;
_hasPrev = false;
var roc = new RateOfChange { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(roc, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rocValue)
{
if (candle.State != CandleStates.Finished) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
if (_hasPrev)
{
if (_prevRoc <= -RocLevel && rocValue > -RocLevel && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (_prevRoc >= RocLevel && rocValue < RocLevel && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
_prevRoc = rocValue;
_hasPrev = true;
}
}