This strategy is a conversion of the MQL expert exp_3xma_ishimoku. It uses the Ichimoku indicator with shortened periods and acts contrarian to cloud breakouts.
The Kijun line is compared to the Ichimoku cloud boundaries. When Kijun falls from above the cloud into it, the strategy closes short positions and opens a long one if buying is allowed. When Kijun rises from below the cloud into it, long positions are closed and a short position may be opened.
The default timeframe for analysis is 4-hour candles.
Parameters
Tenkan Period – length of the Tenkan-sen line.
Kijun Period – length of the Kijun-sen line.
Senkou Span B Period – period for the second Senkou span.
Allow Buy – enable opening long positions.
Allow Sell – enable opening short positions.
Candle Type – candle series used for indicator calculation.
How It Works
Subscribes to the selected candle series and binds the Ichimoku indicator.
Processes only finished candles.
Detects when the Kijun line crosses the cloud borders.
Closes opposite positions and opens a new one in the signal direction if allowed.
Disclaimer
This example is for educational purposes and does not constitute financial advice. Use at your own risk.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Ichimoku cloud strategy.
/// Buys when Kijun crosses down into cloud, sells on opposite.
/// </summary>
public class Exp3XmaIshimokuStrategy : Strategy
{
private readonly StrategyParam<int> _tenkanPeriod;
private readonly StrategyParam<int> _kijunPeriod;
private readonly StrategyParam<int> _senkouSpanPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevKijun;
private decimal? _prevUpper;
private decimal? _prevLower;
public int TenkanPeriod { get => _tenkanPeriod.Value; set => _tenkanPeriod.Value = value; }
public int KijunPeriod { get => _kijunPeriod.Value; set => _kijunPeriod.Value = value; }
public int SenkouSpanPeriod { get => _senkouSpanPeriod.Value; set => _senkouSpanPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Exp3XmaIshimokuStrategy()
{
_tenkanPeriod = Param(nameof(TenkanPeriod), 3)
.SetGreaterThanZero()
.SetDisplay("Tenkan Period", "Tenkan-sen period", "Ichimoku");
_kijunPeriod = Param(nameof(KijunPeriod), 6)
.SetGreaterThanZero()
.SetDisplay("Kijun Period", "Kijun-sen period", "Ichimoku");
_senkouSpanPeriod = Param(nameof(SenkouSpanPeriod), 9)
.SetGreaterThanZero()
.SetDisplay("Senkou B Period", "Senkou Span B period", "Ichimoku");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevKijun = null;
_prevUpper = null;
_prevLower = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ichimoku = new Ichimoku();
ichimoku.Tenkan.Length = TenkanPeriod;
ichimoku.Kijun.Length = KijunPeriod;
ichimoku.SenkouB.Length = SenkouSpanPeriod;
SubscribeCandles(CandleType)
.BindEx(ichimoku, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue ichimokuValue)
{
if (candle.State != CandleStates.Finished)
return;
var ich = (IIchimokuValue)ichimokuValue;
if (ich.Kijun is not decimal kijun ||
ich.SenkouA is not decimal senkouA ||
ich.SenkouB is not decimal senkouB)
return;
var upper = Math.Max(senkouA, senkouB);
var lower = Math.Min(senkouA, senkouB);
if (_prevKijun is null)
{
_prevKijun = kijun;
_prevUpper = upper;
_prevLower = lower;
return;
}
// Buy when Kijun crosses down into cloud
var crossDown = _prevKijun > _prevUpper && kijun <= upper;
// Sell when Kijun crosses up out of cloud
var crossUp = _prevKijun < _prevLower && kijun >= lower;
if (crossDown && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossUp && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevKijun = kijun;
_prevUpper = upper;
_prevLower = lower;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import Ichimoku
from StockSharp.Algo.Strategies import Strategy
class exp3_xma_ishimoku_strategy(Strategy):
def __init__(self):
super(exp3_xma_ishimoku_strategy, self).__init__()
self._tenkan_period = self.Param("TenkanPeriod", 3) \
.SetDisplay("Tenkan Period", "Tenkan-sen period", "Ichimoku")
self._kijun_period = self.Param("KijunPeriod", 6) \
.SetDisplay("Kijun Period", "Kijun-sen period", "Ichimoku")
self._senkou_span_period = self.Param("SenkouSpanPeriod", 9) \
.SetDisplay("Senkou B Period", "Senkou Span B period", "Ichimoku")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle type", "General")
self._prev_kijun = None
self._prev_upper = None
self._prev_lower = None
@property
def TenkanPeriod(self):
return self._tenkan_period.Value
@TenkanPeriod.setter
def TenkanPeriod(self, value):
self._tenkan_period.Value = value
@property
def KijunPeriod(self):
return self._kijun_period.Value
@KijunPeriod.setter
def KijunPeriod(self, value):
self._kijun_period.Value = value
@property
def SenkouSpanPeriod(self):
return self._senkou_span_period.Value
@SenkouSpanPeriod.setter
def SenkouSpanPeriod(self, value):
self._senkou_span_period.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(exp3_xma_ishimoku_strategy, self).OnStarted2(time)
ichimoku = Ichimoku()
ichimoku.Tenkan.Length = self.TenkanPeriod
ichimoku.Kijun.Length = self.KijunPeriod
ichimoku.SenkouB.Length = self.SenkouSpanPeriod
self.SubscribeCandles(self.CandleType) \
.BindEx(ichimoku, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, ichimoku_value):
if candle.State != CandleStates.Finished:
return
kijun_raw = ichimoku_value.Kijun
senkou_a_raw = ichimoku_value.SenkouA
senkou_b_raw = ichimoku_value.SenkouB
if kijun_raw is None or senkou_a_raw is None or senkou_b_raw is None:
return
kijun = float(kijun_raw)
senkou_a = float(senkou_a_raw)
senkou_b = float(senkou_b_raw)
upper = max(senkou_a, senkou_b)
lower = min(senkou_a, senkou_b)
if self._prev_kijun is None:
self._prev_kijun = kijun
self._prev_upper = upper
self._prev_lower = lower
return
cross_down = self._prev_kijun > self._prev_upper and kijun <= upper
cross_up = self._prev_kijun < self._prev_lower and kijun >= lower
if cross_down and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif cross_up and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_kijun = kijun
self._prev_upper = upper
self._prev_lower = lower
def OnReseted(self):
super(exp3_xma_ishimoku_strategy, self).OnReseted()
self._prev_kijun = None
self._prev_upper = None
self._prev_lower = None
def CreateClone(self):
return exp3_xma_ishimoku_strategy()