Slow Stochastic Mode Strategy — это перенос эксперта MetaTrader Exp_Slow-Stoch.mq5 на высокоуровневый API StockSharp. Система работает по закрытию сформированных свечей и использует сглаженный стохастический осциллятор для поиска смены режима. Трейдер может выбрать один из трёх алгоритмов сигналов: пробой уровня, разворот импульса или пересечение линий.
Основная идея
Стратегия анализирует линии %K и %D стохастика, дополнительно сглажённые параметром Slowing. В зависимости от выбранного режима сигнала (Mode) алгоритм оценивает значения индикатора на одной или нескольких прошедших свечах (SignalBar) и при выполнении условий открывает позицию либо закрывает противоположную. Все заявки отправляются рыночными приказами.
Режимы сигналов
Breakdown — отслеживает пробой уровня 50 линией %K. Пересечение снизу вверх открывает длинную позицию и закрывает короткую. Пересечение сверху вниз открывает короткую позицию и закрывает длинную.
Twist — реагирует на изменение направления %K. Если два бара назад осциллятор снижался, а на анализируемой свече развернулся вверх, стратегия входит или переворачивается в лонг. Обратная ситуация формирует сигнал на шорт.
CloudTwist — контролирует смену цвета «облака» стохастика через пересечение %K и %D. Бычье пересечение (%K выше %D) открывает и защищает длинные позиции, медвежье (%K ниже %D) делает противоположное.
Все режимы учитывают четыре флага разрешений: входы и выходы для лонгов и шортов можно включать или выключать независимо.
Параметры
Параметр
По умолчанию
Описание
CandleType
Таймфрейм H4
Тип свечей для расчётов.
KPeriod
5
Длина периода для линии %K.
DPeriod
3
Период усреднения %D.
Slowing
3
Дополнительное сглаживание %K.
SignalBar
1
Сколько закрытых баров назад анализируется сигнал.
StopLossPoints
1000
Размер стоп-лосса в шагах цены (0 — отключить).
TakeProfitPoints
2000
Размер тейк-профита в шагах цены (0 — отключить).
EnableLongEntries
true
Разрешение открывать длинные позиции.
EnableShortEntries
true
Разрешение открывать короткие позиции.
EnableLongExits
true
Разрешение закрывать лонги по сигналу.
EnableShortExits
true
Разрешение закрывать шорты по сигналу.
Mode
Twist
Выбранный режим сигналов.
Используется встроенный индикатор StockSharp StochasticOscillator. Параметр SignalBar позволяет повторить поведение MetaTrader: по умолчанию анализируется предыдущая свеча (значение 1), а при нуле стратегия реагирует на последнюю завершённую свечу.
Управление сделками
Приказы выставляются методами BuyMarket и SellMarket. При перевороте объём увеличивается на абсолютное значение текущей позиции, чтобы закрыть старую и открыть новую.
Защитные стоп-лосс и тейк-профит подключаются через StartProtection. Значения трактуются как количество тиков и автоматически переводятся в абсолютное расстояние с учётом шага цены инструмента.
Трейлинг не используется: уровни защиты остаются неизменными до их срабатывания или принудительного выхода.
Логика выхода
В режиме Breakdown тот же пробой уровня, который открывает позицию в одном направлении, закрывает противоположную.
В режиме Twist фиксация разворота импульса сначала закрывает текущую позицию, затем открывает новую в обратную сторону.
В режиме CloudTwist пересечение линий одновременно даёт сигнал на вход и закрывает позицию противоположного типа.
Если разрешения на входы отключены, стратегия продолжает работать только в режиме управления уже существующими позициями, используя соответствующие правила выхода.
Особенности реализации
Значения стохастика сохраняются во внутренних буферах, что позволяет обращаться к нужным смещениям по барам, как в оригинальном советнике.
Расчёты выполняются только на полностью сформированных свечах (candle.State == Finished).
При наличии графической подсистемы выводятся свечи, стохастик и сделки стратегии.
Конверсия сохраняет логику MQL5-версии и использует преимущества StockSharp: гибкие параметры, высокоуровневые подписки и встроенные инструменты управления риском.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Slow Stochastic Mode strategy. Uses EMA crossover for trend following.
/// </summary>
public class SlowStochasticModeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast;
private decimal? _prevSlow;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public SlowStochasticModeStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
if (_prevFast == null || _prevSlow == null)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fastVal > slowVal;
_prevFast = fastVal;
_prevSlow = slowVal;
if (!prevAbove && currAbove && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (prevAbove && !currAbove && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class slow_stochastic_mode_strategy(Strategy):
def __init__(self):
super(slow_stochastic_mode_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 5) \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 14) \
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(slow_stochastic_mode_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(slow_stochastic_mode_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
if not prev_above and curr_above and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif prev_above and not curr_above and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return slow_stochastic_mode_strategy()