This strategy trades based on the BrakeExp indicator, which builds an exponential channel around price movements. The indicator switches between long and short regimes and generates buy or sell signals when price crosses the dynamic channel borders.
How It Works
The indicator maintains an exponential curve that follows price.
When the curve is below price (uptrend), the strategy looks for buy signals.
When the curve is above price (downtrend), the strategy looks for sell signals.
A crossing from one side to the other produces an entry signal in the new direction and closes the opposite position.
Parameters
Candle Type – timeframe of processed candles.
Volume – order volume used for market entries.
A, B – parameters defining the shape of the BrakeExp curve.
Buy Open / Sell Open – permission to open long or short positions.
Buy Close / Sell Close – permission to close short or long positions.
Notes
This implementation focuses on the core logic of the BrakeExp indicator and does not include stop-loss or take-profit management. Additional risk controls can be added if required.
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>
/// Channel breakout strategy using EMA and price crossover.
/// </summary>
public class BrakeExpChannelStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private decimal _prevClose;
private decimal _prevEma;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public BrakeExpChannelStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
_emaPeriod = Param(nameof(EmaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0;
_prevEma = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
SubscribeCandles(CandleType)
.Bind(ema, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal emaVal)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (!_hasPrev)
{
_prevClose = close;
_prevEma = emaVal;
_hasPrev = true;
return;
}
var crossUp = _prevClose <= _prevEma && close > emaVal;
var crossDown = _prevClose >= _prevEma && close < emaVal;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevClose = close;
_prevEma = emaVal;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class brake_exp_channel_strategy(Strategy):
def __init__(self):
super(brake_exp_channel_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle type", "General")
self._ema_period = self.Param("EmaPeriod", 20) \
.SetDisplay("EMA Period", "EMA period", "Indicators")
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
@property
def candle_type(self):
return self._candle_type.Value
@property
def ema_period(self):
return self._ema_period.Value
def OnReseted(self):
super(brake_exp_channel_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(brake_exp_channel_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
self.SubscribeCandles(self.candle_type).Bind(ema, self.process_candle).Start()
def process_candle(self, candle, ema_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ev = float(ema_val)
if not self._has_prev:
self._prev_close = close
self._prev_ema = ev
self._has_prev = True
return
cross_up = self._prev_close <= self._prev_ema and close > ev
cross_down = self._prev_close >= self._prev_ema and close < ev
if cross_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif cross_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_close = close
self._prev_ema = ev
def CreateClone(self):
return brake_exp_channel_strategy()