This strategy is a simplified StockSharp port of the MetaTrader expert i-CAiChannel System Digit.
The algorithm monitors a volatility channel built from a moving average and standard deviation (Bollinger Bands).
When a candle closes outside the channel and the next candle returns inside, the strategy trades in the direction of the re-entry.
Parameters
Length – period of the moving average.
Width – standard deviation multiplier.
Candle Type – timeframe for processing.
Trading Logic
Subscribe to candles of the selected timeframe.
Calculate Bollinger Bands with the specified parameters.
If the previous candle closed above the upper band and the current candle closes back inside, go long.
If the previous candle closed below the lower band and the current candle closes back inside, go short.
The position is reversed when the opposite signal occurs.
All signals are generated only on finished candles.
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>
/// CAiChannel System Digit strategy using Bollinger Bands.
/// Buys when price returns inside from above the upper band.
/// Sells when price returns inside from below the lower band.
/// </summary>
public class CaiChannelSystemDigitStrategy : Strategy
{
private readonly StrategyParam<int> _length;
private readonly StrategyParam<decimal> _width;
private readonly StrategyParam<DataType> _candle;
private bool _prevUp;
private bool _prevDown;
public int Length { get => _length.Value; set => _length.Value = value; }
public decimal Width { get => _width.Value; set => _width.Value = value; }
public DataType CandleType { get => _candle.Value; set => _candle.Value = value; }
public CaiChannelSystemDigitStrategy()
{
_length = Param(nameof(Length), 12).SetGreaterThanZero();
_width = Param(nameof(Width), 2m).SetGreaterThanZero();
_candle = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame());
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevUp = false;
_prevDown = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevUp = false;
_prevDown = false;
var bb = new BollingerBands { Length = Length, Width = Width };
var sub = SubscribeCandles(CandleType);
sub.BindEx(bb, Process).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, sub);
DrawIndicator(area, bb);
DrawOwnTrades(area);
}
}
private void Process(ICandleMessage candle, IIndicatorValue bbVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (bbVal is not IBollingerBandsValue bb || bb.UpBand is not decimal up || bb.LowBand is not decimal down)
return;
if (_prevUp && candle.ClosePrice <= up && Position <= 0)
BuyMarket();
else if (_prevDown && candle.ClosePrice >= down && Position >= 0)
SellMarket();
_prevUp = candle.ClosePrice > up;
_prevDown = candle.ClosePrice < down;
}
}
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 BollingerBands
from StockSharp.Algo.Strategies import Strategy
class cai_channel_system_digit_strategy(Strategy):
def __init__(self):
super(cai_channel_system_digit_strategy, self).__init__()
self._length = self.Param("Length", 12) \
.SetDisplay("Length", "BB period", "Indicator")
self._width = self.Param("Width", 2.0) \
.SetDisplay("Width", "BB width", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_up = False
self._prev_down = False
@property
def length(self):
return self._length.Value
@property
def width(self):
return self._width.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(cai_channel_system_digit_strategy, self).OnReseted()
self._prev_up = False
self._prev_down = False
def OnStarted2(self, time):
super(cai_channel_system_digit_strategy, self).OnStarted2(time)
self._prev_up = False
self._prev_down = False
bb = BollingerBands()
bb.Length = self.length
bb.Width = self.width
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bb, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bb)
self.DrawOwnTrades(area)
def process_candle(self, candle, bb_val):
if candle.State != CandleStates.Finished:
return
up = bb_val.UpBand
down = bb_val.LowBand
if up is None or down is None:
return
up = float(up)
down = float(down)
close_price = float(candle.ClosePrice)
if self._prev_up and close_price <= up and self.Position <= 0:
self.BuyMarket()
elif self._prev_down and close_price >= down and self.Position >= 0:
self.SellMarket()
self._prev_up = close_price > up
self._prev_down = close_price < down
def CreateClone(self):
return cai_channel_system_digit_strategy()