A strategy that opens layered positions when the Stochastic oscillator reaches extreme values on four-hour candles. It places an initial market order followed by a grid of limit orders. Positions are closed once a profit target is reached and the trend is confirmed by moving averages and Bollinger Bands.
Entry Rules
Use Stochastic oscillator (%K length 21, smoothing 3) on H4 candles.
When %K ≥ Overbought level:
Sell at market.
Place up to eight additional SellLimit orders above the current price at configured pip distances.
When %K ≤ Oversold level:
Buy at market.
Place up to eight additional BuyLimit orders below the current price at configured pip distances.
Exit Rules
Realized profit reaches ProfitTarget and price confirms trend:
Long positions exit when price is above the lower Bollinger Band and the 200‑period SMA is above the 55‑period SMA.
Short positions exit when price is below the upper Bollinger Band and the 200‑period SMA is below the 55‑period SMA.
Pending buy limits are cancelled when %K ≥ 90 and the 200‑period SMA ≤ 55‑period SMA.
Pending sell limits are cancelled when %K ≤ 10 and the 200‑period SMA ≥ 55‑period SMA.
Parameters
StochLength – %K period for Stochastic.
OverboughtLevel – level to start selling.
OversoldLevel – level to start buying.
ProfitTarget – realized profit required to close open positions.
Order2Offset … Order9Offset – pip distances for additional limit orders.
CandleType – timeframe of candles, default 4 hours.
Indicators
StochasticOscillator
BollingerBands
SMA (200 and 55)
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>
/// EMA crossover strategy inspired by Elliott wave concept.
/// </summary>
public class ElliottTraderStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ElliottTraderStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
SubscribeCandles(CandleType)
.Bind(fast, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev)
{
_prevFast = fastVal;
_prevSlow = slowVal;
_hasPrev = true;
return;
}
var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}