Стратегия представляет собой перенос советника Exp_wajdyss_Ichimoku_Candle_MMRec с платформы MetaTrader. В StockSharp она заново
вычисляет базовую линию Ишимоку (Kijun) с помощью индикаторов Highest и Lowest и окрашивает каждую закрытую свечу в один из четырех
состояний. Когда предыдущая свеча находилась выше Kijun, а сигнальная свеча опускается ниже линии, алгоритм закрывает короткие позиции и
открывает длинную. Обратный переход формирует вход в шорт. Модуль MMRec уменьшает торговый объем после заданного количества убыточных
сделок в одном направлении, полностью воспроизводя логику оригинального советника.
Переведенная версия использует высокоуровневый API StockSharp. Исторические и онлайн данные подключаются через SubscribeCandles, решения
принимаются только по завершенным свечам, что обеспечивает одинаковое поведение в тестере и в реальном времени.
Логика окраски свечей
Каждая закрытая свеча получает числовой код, совпадающий с индикатором wajdyss Ichimoku Candle:
Цвет
Условие
Интерпретация
0
Закрытие ниже Kijun и медвежье тело
Сильный медвежий импульс ниже базовой линии
1
Закрытие ниже Kijun, но бычье тело
Слабый отскок под линией
2
Закрытие выше Kijun, но медвежье тело
Слабое давление продавцов над линией
3
Закрытие выше Kijun и бычье тело
Сильное бычье продолжение над линией
Торговые сигналы
Сигналы формируются по двум последним закрытым свечам:
Вход в лонг: свеча на позиции SignalBarShift + 1 имела цвет больше 1 (цена была выше Kijun), а свеча SignalBarShift
окрасилась в цвет ниже 2 (цена ушла ниже Kijun). Стратегия при необходимости закрывает короткую позицию и может открыть новую длинную.
Вход в шорт: свеча на позиции SignalBarShift + 1 имела цвет ниже 2, а свеча SignalBarShift получила цвет выше 1.
В этом случае закрываются лонги и открывается короткая позиция (если направление разрешено).
Параметр SignalBarShift соответствует входу SignalBar в оригинале. Значение 1 означает работу с двумя последними полностью закрытыми
свечами; увеличение сдвига задерживает входы на указанное количество баров.
Управление объемом
Блок MMRec ведет короткую историю результатов по каждому направлению. Если последние LossTriggerCount сделок по лонгам (или шортам)
оказались убыточными, объем заявок уменьшается до ReducedVolume. После прибыльной сделки или при отсутствии необходимого количества
истории стратегия возвращается к основному объему NormalVolume. Это повторяет функции BuyTradeMMRecounter и SellTradeMMRecounter из
библиотеки MQL5.
Управление риском
Стоп-лосс и тейк-профит задаются в шагах цены. Для длинной позиции проверяется достижение уровней вход - StopLossPoints * PriceStep и
вход + TakeProfitPoints * PriceStep. Для короткой позиции логика зеркальна. Контроль выполняется один раз на закрытии свечи, что соответствует
работе исходного советника с фиксированными ордерами на сервере.
Параметры
Параметр
Описание
Значение по умолчанию
CandleType
Таймфрейм свечей
Свечи 1H
KijunLength
Длина окна для линии Kijun
26
SignalBarShift
Сдвиг сигнальной свечи относительно текущей
1
BuyPosOpen / SellPosOpen
Разрешение на открытие позиций в каждом направлении
true
BuyPosClose / SellPosClose
Разрешение закрывать позиции по обратному сигналу
true
NormalVolume
Базовый объем сделки
1
ReducedVolume
Объем после серии убытков
0.1
LossTriggerCount
Количество убытков подряд для снижения объема
2
StopLossPoints
Стоп-лосс в шагах цены (0 — отключен)
1000
TakeProfitPoints
Тейк-профит в шагах цены (0 — отключен)
2000
Рекомендации по использованию
Входы совершаются только по изменению цвета свечи; можно отключить любое направление через параметры.
Для корректной работы модуля MMRec необходимы данные о результатах сделок, которые стратегия генерирует автоматически при закрытии позиций.
Если у инструмента не задан шаг цены, стоп и тейк-профит игнорируются.
Значение SignalBarShift = 0 дает более ранние сигналы, но повышает вероятность ложных входов.
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>
/// Ichimoku-inspired strategy using Highest/Lowest midline (Kijun-Sen concept).
/// Trades when price crosses above/below the midline.
/// </summary>
public class WajdyssIchimokuCandleMmrecStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private decimal? _prevMid;
private decimal? _prevClose;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int Period
{
get => _period.Value;
set => _period.Value = value;
}
public WajdyssIchimokuCandleMmrecStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_period = Param(nameof(Period), 26)
.SetGreaterThanZero()
.SetDisplay("Period", "Kijun-Sen lookback period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMid = null;
_prevClose = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMid = null;
_prevClose = null;
var middle = new SimpleMovingAverage { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(middle, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, middle);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal mid)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevMid = mid;
_prevClose = candle.ClosePrice;
return;
}
var close = candle.ClosePrice;
if (_prevMid == null || _prevClose == null)
{
_prevMid = mid;
_prevClose = close;
return;
}
// Price crosses above midline → buy
if (_prevClose.Value <= _prevMid.Value && close > mid && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Price crosses below midline → sell
else if (_prevClose.Value >= _prevMid.Value && close < mid && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevMid = mid;
_prevClose = close;
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class wajdyss_ichimoku_candle_mmrec_strategy(Strategy):
def __init__(self):
super(wajdyss_ichimoku_candle_mmrec_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._period = self.Param("Period", 26) \
.SetDisplay("Period", "Kijun-Sen lookback period", "Indicators")
self._prev_mid = None
self._prev_close = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def Period(self):
return self._period.Value
def OnReseted(self):
super(wajdyss_ichimoku_candle_mmrec_strategy, self).OnReseted()
self._prev_mid = None
self._prev_close = None
def OnStarted2(self, time):
super(wajdyss_ichimoku_candle_mmrec_strategy, self).OnStarted2(time)
self._prev_mid = None
self._prev_close = None
middle = SimpleMovingAverage()
middle.Length = self.Period
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(middle, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, middle)
self.DrawOwnTrades(area)
def _on_process(self, candle, mid_value):
if candle.State != CandleStates.Finished:
return
mv = float(mid_value)
close = float(candle.ClosePrice)
if self._prev_mid is None or self._prev_close is None:
self._prev_mid = mv
self._prev_close = close
return
# Price crosses above midline
if self._prev_close <= self._prev_mid and close > mv and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Price crosses below midline
elif self._prev_close >= self._prev_mid and close < mv and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_mid = mv
self._prev_close = close
def CreateClone(self):
return wajdyss_ichimoku_candle_mmrec_strategy()