Intraday v2 Strategy
This strategy implements an intraday mean reversion approach using two sets of Bollinger Bands. The outer bands (deviation 2.4) define entry zones while the inner bands (deviation 1) manage exits. Optional stop-loss and take-profit levels close positions when price moves against the trade by a configurable amount.
Details
- Entry Criteria:
- Long: Close price falls below the outer lower band.
- Short: Close price rises above the outer upper band.
- Long/Short: Both.
- Exit Criteria:
- Long: Price crosses above the inner lower band or hits stop-loss/take-profit.
- Short: Price crosses below the inner upper band or hits stop-loss/take-profit.
- Stops: Configurable absolute stop-loss and take-profit.
- Filters: None.
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>
/// Intraday mean reversion strategy using SMA and standard deviation bands.
/// Buys when price touches lower band, sells when touching upper band.
/// </summary>
public class IntradayV2Strategy : Strategy
{
private readonly StrategyParam<int> _bandLength;
private readonly StrategyParam<DataType> _candleType;
private readonly List<decimal> _closes = new();
public int BandLength { get => _bandLength.Value; set => _bandLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public IntradayV2Strategy()
{
_bandLength = Param(nameof(BandLength), 20)
.SetGreaterThanZero()
.SetDisplay("Band Length", "Band period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_closes.Clear();
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma = new SimpleMovingAverage { Length = BandLength };
var stdev = new StandardDeviation { Length = BandLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, stdev, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal smaVal, decimal stdevVal)
{
if (candle.State != CandleStates.Finished)
return;
if (stdevVal <= 0)
return;
var close = candle.ClosePrice;
var upper = smaVal + 2m * stdevVal;
var lower = smaVal - 2m * stdevVal;
// Mean reversion: buy at lower band
if (close < lower && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Mean reversion: sell at upper band
else if (close > upper && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
// Exit long at middle (SMA)
if (Position > 0 && close > smaVal)
{
SellMarket();
}
// Exit short at middle (SMA)
else if (Position < 0 && close < smaVal)
{
BuyMarket();
}
}
}
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, StandardDeviation
from StockSharp.Algo.Strategies import Strategy
class intraday_v2_strategy(Strategy):
def __init__(self):
super(intraday_v2_strategy, self).__init__()
self._band_length = self.Param("BandLength", 20) \
.SetDisplay("Band Length", "Band period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
@property
def band_length(self):
return self._band_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(intraday_v2_strategy, self).OnReseted()
def OnStarted2(self, time):
super(intraday_v2_strategy, self).OnStarted2(time)
sma = SimpleMovingAverage()
sma.Length = self.band_length
stdev = StandardDeviation()
stdev.Length = self.band_length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, stdev, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle, sma_val, stdev_val):
if candle.State != CandleStates.Finished:
return
if stdev_val <= 0:
return
close = candle.ClosePrice
upper = sma_val + 2 * stdev_val
lower = sma_val - 2 * stdev_val
# Mean reversion: buy at lower band
if close < lower and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Mean reversion: sell at upper band
elif close > upper and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
# Exit long at middle (SMA)
if self.Position > 0 and close > sma_val:
self.SellMarket()
# Exit short at middle (SMA)
elif self.Position < 0 and close < sma_val:
self.BuyMarket()
def CreateClone(self):
return intraday_v2_strategy()