This strategy reproduces the MetaTrader expert Expert_ABC_WS_Stoch.mq5, which combines classical three-candle reversal patterns with Stochastic oscillator confirmation. A long signal requires the bullish "Three White Soldiers" formation together with an oversold Stochastic signal line, while a short signal relies on the bearish "Three Black Crows" confirmed by an overbought Stochastic. The exit logic monitors crossovers of the signal line through configurable bands to close positions.
Trading Logic
Pattern detection
Track the latest three completed candles.
Identify Three White Soldiers when all three candles are bullish and each close is higher than the previous one.
Identify Three Black Crows when all three candles are bearish and each close is lower than the previous one.
Oscillator confirmation
Calculate a Stochastic oscillator with %K, %D, and Slowing periods identical to the original expert (47, 9, 13 by default).
Use the signal line (%D) as confirmation:
Enter long if the previous signal line value is below the oversold threshold (default 30).
Enter short if the previous signal line value is above the overbought threshold (default 70).
Exit conditions
Close a long trade when the signal line crosses above either the lower or upper exit thresholds (default 20 and 80).
Close a short trade when the signal line crosses back below these thresholds.
Both exit checks rely on the previous and pre-previous signal line values to detect genuine crossovers.
Parameters
Name
Default
Description
CandleType
1h time frame
Time frame for the candle subscription.
StochKPeriod
47
Lookback period for %K.
StochDPeriod
9
Moving average length for the signal line.
StochSlowing
13
Additional smoothing applied to %K.
OversoldLevel
30
Signal line level required to confirm a long entry.
OverboughtLevel
70
Signal line level required to confirm a short entry.
ExitLowerLevel
20
Lower bound used for long exit crossovers.
ExitUpperLevel
80
Upper bound used for short exit crossovers.
All numeric parameters support optimization ranges matching the MetaTrader template, so the behavior can be fine-tuned through the Strategy Designer.
Order Management
The strategy reverses positions when an opposite signal appears by adding the absolute size of the current position to the configured Volume.
StartProtection() is enabled to integrate with the platform risk controls, although no explicit stop-loss or take-profit levels are enforced by default.
Visualization
When executed inside the Strategy Designer, the strategy draws:
Price candles for the selected symbol and time frame.
The configured Stochastic oscillator.
Trade markers to highlight entries and exits.
Usage Notes
Confirm that the instrument provides enough history for the Stochastic oscillator to warm up before expecting signals.
Consider pairing the strategy with additional risk filters (volatility, session filters, etc.) when deploying live.
The thresholds are exposed as parameters, enabling rapid experimentation with different confirmation bands without editing code.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Three Soldiers Stochastic strategy: detects three consecutive bullish/bearish candles
/// confirmed by RSI levels.
/// </summary>
public class ThreeSoldiersStochasticStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _signalCooldownCandles;
private int _bullCount;
private int _bearCount;
private int _candlesSinceTrade;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public ThreeSoldiersStochasticStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period for confirmation", "Indicators");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_bullCount = 0;
_bearCount = 0;
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_bullCount = 0;
_bearCount = 0;
_candlesSinceTrade = SignalCooldownCandles;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsi)
{
if (candle.State != CandleStates.Finished) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
if (candle.ClosePrice > candle.OpenPrice)
{
_bullCount++;
_bearCount = 0;
}
else if (candle.ClosePrice < candle.OpenPrice)
{
_bearCount++;
_bullCount = 0;
}
else
{
_bullCount = 0;
_bearCount = 0;
}
if (_bullCount >= 3 && rsi < 65 && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_bullCount = 0;
_candlesSinceTrade = 0;
}
else if (_bearCount >= 3 && rsi > 35 && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_bearCount = 0;
_candlesSinceTrade = 0;
}
}
}
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 RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class three_soldiers_stochastic_strategy(Strategy):
def __init__(self):
super(three_soldiers_stochastic_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period for confirmation", "Indicators")
self._signal_cooldown = self.Param("SignalCooldownCandles", 6) \
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading")
self._rsi = None
self._bull_count = 0
self._bear_count = 0
self._candles_since_trade = 0
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def signal_cooldown(self):
return self._signal_cooldown.Value
def OnReseted(self):
super(three_soldiers_stochastic_strategy, self).OnReseted()
self._rsi = None
self._bull_count = 0
self._bear_count = 0
self._candles_since_trade = self.signal_cooldown
def OnStarted2(self, time):
super(three_soldiers_stochastic_strategy, self).OnStarted2(time)
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.rsi_period
self._bull_count = 0
self._bear_count = 0
self._candles_since_trade = self.signal_cooldown
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(60)))
subscription.Bind(self._rsi, self._process_candle)
subscription.Start()
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
if not self._rsi.IsFormed:
return
rsi_val = float(rsi_value)
if self._candles_since_trade < self.signal_cooldown:
self._candles_since_trade += 1
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
if close > open_p:
self._bull_count += 1
self._bear_count = 0
elif close < open_p:
self._bear_count += 1
self._bull_count = 0
else:
self._bull_count = 0
self._bear_count = 0
if self._bull_count >= 3 and rsi_val < 65.0 and self.Position <= 0 and self._candles_since_trade >= self.signal_cooldown:
self.BuyMarket()
self._bull_count = 0
self._candles_since_trade = 0
elif self._bear_count >= 3 and rsi_val > 35.0 and self.Position >= 0 and self._candles_since_trade >= self.signal_cooldown:
self.SellMarket()
self._bear_count = 0
self._candles_since_trade = 0
def CreateClone(self):
return three_soldiers_stochastic_strategy()