GitHub で見る

Wajdyss Ichimoku Candle MMRec Strategy

Overview

This strategy is a direct port of the MetaTrader expert Exp_wajdyss_Ichimoku_Candle_MMRec. It recreates the "wajdyss Ichimoku candle" indicator by computing the Ichimoku base line (Kijun) and classifying each finished candle into one of four color states. The system then looks for a reversal in those colors to fade the most recent move. When the previous bar was above the Kijun and the latest signal bar falls below it, the algorithm closes any short exposure and opens a long trade. The opposite transition flips into a short position. An adaptive money management module replicates the original MMRec logic by shrinking the position size after a configurable number of losing trades in the same direction.

The converted version uses the StockSharp high-level API. Candles are supplied through a single SubscribeCandles call, and the Kijun level is calculated with Highest/Lowest indicators. Trading decisions are only evaluated on finished candles to keep the behaviour deterministic across real-time and historical modes.

Candle coloring logic

Each closed candle is assigned a numeric color index that matches the original MQL5 indicator:

Color Condition Meaning
0 Close below Kijun and a bearish body Strong bearish sentiment below the base line
1 Close below Kijun but a bullish body Weak bullish reaction underneath the base line
2 Close above Kijun but a bearish body Weak bearish reaction above the base line
3 Close above Kijun and a bullish body Strong bullish continuation above the base line

Signal logic

Signals are generated on finished candles by comparing the color of two historical bars:

  • Long setup: the bar at SignalBarShift + 1 had a color greater than 1 (price above Kijun) and the bar at SignalBarShift has a color below 2 (price moved below Kijun). The strategy optionally closes any open short position and can open a new long.
  • Short setup: the bar at SignalBarShift + 1 had a color below 2 (price below Kijun) while the bar at SignalBarShift prints a color above 1 (price moved above Kijun). The strategy optionally closes existing longs and can enter a short position.

The SignalBarShift parameter corresponds to the SignalBar input of the MetaTrader version. The default value 1 means that the signal uses the last fully closed candle and the one before it. Increasing the shift delays entries by the requested number of bars.

Money management

The MMRec module keeps a short history of trade outcomes per direction. If the last LossTriggerCount trades in one direction were all losers, the strategy switches to the reduced order size (ReducedVolume). After a profitable trade, or when fewer than the requested number of trades are available, the default volume (NormalVolume) is restored. This mirrors the behaviour of BuyTradeMMRecounter and SellTradeMMRecounter from the original MQL library.

Risk management

Protective stop-loss and take-profit levels are expressed in price steps. When a long position is open, the strategy checks whether the candle low reached entry - StopLossPoints * PriceStep or whether the high touched entry + TakeProfitPoints * PriceStep. The short side mirrors the logic. The stops are evaluated once per finished candle, similar to the source EA which relied on server-side orders with a fixed distance.

Parameters

Parameter Description Default
CandleType Candle data type (time-frame) used for the indicator 1 hour candles
KijunLength Lookback of the Ichimoku base line 26
SignalBarShift Number of closed bars to skip before evaluating the color transition 1
BuyPosOpen / SellPosOpen Enable or disable opening positions in each direction true
BuyPosClose / SellPosClose Allow closing existing positions on the opposite signal true
NormalVolume Default order volume 1
ReducedVolume Order volume after the configured number of losses 0.1
LossTriggerCount Number of losing trades in a row before reducing size 2
StopLossPoints Stop distance in price steps (set to 0 to disable) 1000
TakeProfitPoints Take-profit distance in price steps (set to 0 to disable) 2000

Usage notes

  • The strategy opens trades only when the color transition indicates exhaustion and the relevant direction is enabled.
  • Volume scaling requires that the platform reports trade results; in backtests the exits generated by the strategy will update the loss history automatically.
  • If no price step is defined for the security, the stop-loss and take-profit inputs are ignored.
  • Setting SignalBarShift to 0 mimics an immediate reaction to the latest finished candle but increases the risk of whipsaws.
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;
	}
}