Эта стратегия использует индикатор BrakeExp, строящий экспоненциальный канал вокруг цены. Индикатор переключается между восходящим и нисходящим режимами и генерирует сигналы покупки или продажи при пробое границ динамического канала.
Как это работает
Индикатор ведёт экспоненциальную кривую, следящую за ценой.
Когда кривая ниже цены (восходящий тренд), стратегия ищет сигналы на покупку.
Когда кривая выше цены (нисходящий тренд), стратегия ищет сигналы на продажу.
Пересечение из одного режима в другой создаёт сигнал входа в новом направлении и закрывает противоположную позицию.
Параметры
Candle Type – таймфрейм обрабатываемых свечей.
Volume – объём заявки для рыночных входов.
A, B – параметры, определяющие форму кривой BrakeExp.
Buy Open / Sell Open – разрешение на открытие длинных или коротких позиций.
Buy Close / Sell Close – разрешение на закрытие коротких или длинных позиций.
Примечания
Данная реализация охватывает основную логику индикатора BrakeExp и не включает управление стоп-лоссом или тейк-профитом. При необходимости можно добавить дополнительные механизмы управления рисками.
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()