Estrategia de bandas
Descripción general
Esta estrategia transfiere el asesor experto MetaTrader 5 Bands.mq5 al API de alto nivel de StockSharp. Espera una vela terminada que perfora las bandas Bollinger desde el exterior hacia el canal y solo abre una posición cuando el canal Donchian se configura Confirma que la pendiente de la banda ha sido estable durante un número configurable de barras. Los múltiplos del rango verdadero promedio (ATR) reproducen el ori distancias iniciales de stop-loss y take-profit, mientras que un rastreador de regresión opcional imprime el coeficiente de determinación de la curva de acciones (R cuadrado) cada 100 operaciones, reflejando el resultado de diagnóstico de la versión MQL.
Lógica comercial
- Suscríbase a un flujo de velas único y calcule Bollinger Bandas, un Donchian Canal y ATR con los mismos períodos que el MetaT. robot de radar.
- Cuando no haya ninguna posición abierta, inspeccione la vela anterior completada:
- Ingrese en largo si esa vela se abrió por debajo de la banda inferior Bollinger y cerró por encima de ella, y la banda inferior Donchian no ha disminuido.
ined durante más de
ConfirmationPeriodbarras. - Entre en corto si la vela se abrió por encima de la banda superior Bollinger y cerró por debajo de ella, y la banda superior Donchian no ha subido.
es para más de
ConfirmationPeriodbarras.
- Ingrese en largo si esa vela se abrió por debajo de la banda inferior Bollinger y cerró por encima de ella, y la banda inferior Donchian no ha disminuido.
ined durante más de
- Cuando exista una posición, salga si se cruza el límite final Donchian (utilizando el cierre anterior) o si la base ATR Se violan los niveles d proteccion intrabar.
- Cada operación ejecutada almacena el capital de la cartera actual e imprime la métrica R cuadrado de regresión lineal después de cada bloque de 100 operaciones. Una pendiente negativa produce un R cuadrado negativo al igual que el asesor experto original.
Gestión de riesgos
- Las órdenes de entrada siempre se envían al mercado con el
TradeVolumedefinido por el usuario. - Los niveles de protección se recrean en el código (en lugar de utilizar órdenes pendientes) comparando los máximos y mínimos de las velas con el ATR mu. tiples.
- Cuando se activa el stop-loss o el take-profit, la estrategia cierra toda la posición con una orden de mercado y restablece la protección. en niveles.
Parámetros
| Parámetro | Descripción |
|---|---|
TradeVolume |
Volumen neto (en lotes) para cada orden de mercado. |
CandleType |
Tipo de datos de vela/período de tiempo utilizado para todos los indicadores. |
BollingerPeriod |
Número de velas utilizadas por las Bollinger Bandas. |
BollingerDeviation |
Multiplicador de desviación estándar aplicado a las Bollinger Bandas. |
DonchianPeriod |
Longitud del canal Donchian utilizado como filtro de tendencias. |
ConfirmationPeriod |
Recuento mínimo de barras consecutivas que deben mantener la pendiente Donchian no decreciente (larga) ni no creciente (corta). |
AtrPeriod |
Período del Rango Verdadero Promedio utilizado para la gestión de riesgos. |
StopAtrMultiplier |
ATR múltiplo que define la distancia del stop-loss. |
TakeAtrMultiplier |
ATR múltiplo que define la distancia de toma de ganancias. |
Notas
- La verificación de pendiente Donchian se implementa como un contador rodante en lugar de copiar los buffers del indicador, lo que mantiene el StockSharp versión eficiente y al mismo tiempo coincide con el comportamiento del EA original.
- Todos los comentarios y diagnósticos se proporcionan en inglés según lo exigen las directrices del proyecto.
- Los ayudantes de administración de dinero del código MetaTrader no se reproducen; la implementación de StockSharp se basa en
TradeVolumeparámetro para dimensionar la posición.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Bollinger Bands breakout strategy confirmed by Donchian channel slope and ATR-based risk management.
/// </summary>
public class BandsStrategy : Strategy
{
private readonly StrategyParam<decimal> _tradeVolume;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerDeviation;
private readonly StrategyParam<int> _donchianPeriod;
private readonly StrategyParam<int> _confirmationPeriod;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _stopAtrMultiplier;
private readonly StrategyParam<decimal> _takeAtrMultiplier;
private decimal? _prevOpen;
private decimal? _prevClose;
private decimal? _prevLowerBand;
private decimal? _prevUpperBand;
private decimal? _prevDonchLower;
private decimal? _prevDonchUpper;
private decimal? _prevAtr;
private int _lowerTrendLength;
private int _upperTrendLength;
private decimal? _stopLossPrice;
private decimal? _takeProfitPrice;
private int _equitySamples;
private decimal _sumIndices;
private decimal _sumEquity;
private decimal _sumIndexEquity;
private decimal _sumIndexSquared;
private decimal _sumEquitySquared;
/// <summary>
/// Initializes a new instance of <see cref="BandsStrategy"/>.
/// </summary>
public BandsStrategy()
{
_tradeVolume = Param(nameof(TradeVolume), 0.1m)
.SetGreaterThanZero()
.SetDisplay("Volume", "Net volume in lots sent with every order", "Trading")
;
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Time frame used for indicator calculations", "Market Data");
_bollingerPeriod = Param(nameof(BollingerPeriod), 100)
.SetGreaterThanZero()
.SetDisplay("Bollinger Period", "Number of candles used for the Bollinger Bands", "Indicators")
;
_bollingerDeviation = Param(nameof(BollingerDeviation), 1m)
.SetGreaterThanZero()
.SetDisplay("Bollinger Deviation", "Standard deviation multiplier for the Bollinger Bands", "Indicators")
;
_donchianPeriod = Param(nameof(DonchianPeriod), 100)
.SetGreaterThanZero()
.SetDisplay("Donchian Period", "Donchian Channel length used as trend filter", "Indicators")
;
_confirmationPeriod = Param(nameof(ConfirmationPeriod), 100)
.SetGreaterThanZero()
.SetDisplay("Slope Confirmation", "Minimum number of bars that must keep the Donchian slope intact", "Indicators")
;
_atrPeriod = Param(nameof(AtrPeriod), 21)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "Length of the Average True Range used for stops", "Indicators")
;
_stopAtrMultiplier = Param(nameof(StopAtrMultiplier), 4m)
.SetGreaterThanZero()
.SetDisplay("Stop ATR Multiplier", "How many ATRs below/above the entry to place the stop", "Risk")
;
_takeAtrMultiplier = Param(nameof(TakeAtrMultiplier), 4m)
.SetGreaterThanZero()
.SetDisplay("Take ATR Multiplier", "How many ATRs below/above the entry to place the target", "Risk")
;
}
/// <summary>
/// Trade volume in lots.
/// </summary>
public decimal TradeVolume
{
get => _tradeVolume.Value;
set => _tradeVolume.Value = value;
}
/// <summary>
/// Candle type used for analysis.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Period of the Bollinger Bands.
/// </summary>
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
/// <summary>
/// Deviation multiplier of the Bollinger Bands.
/// </summary>
public decimal BollingerDeviation
{
get => _bollingerDeviation.Value;
set => _bollingerDeviation.Value = value;
}
/// <summary>
/// Period of the Donchian Channel.
/// </summary>
public int DonchianPeriod
{
get => _donchianPeriod.Value;
set => _donchianPeriod.Value = value;
}
/// <summary>
/// Number of consecutive bars required to confirm the Donchian slope.
/// </summary>
public int ConfirmationPeriod
{
get => _confirmationPeriod.Value;
set => _confirmationPeriod.Value = value;
}
/// <summary>
/// Period of the Average True Range indicator.
/// </summary>
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
/// <summary>
/// Stop-loss distance expressed in ATR multiples.
/// </summary>
public decimal StopAtrMultiplier
{
get => _stopAtrMultiplier.Value;
set => _stopAtrMultiplier.Value = value;
}
/// <summary>
/// Take-profit distance expressed in ATR multiples.
/// </summary>
public decimal TakeAtrMultiplier
{
get => _takeAtrMultiplier.Value;
set => _takeAtrMultiplier.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevOpen = null;
_prevClose = null;
_prevLowerBand = null;
_prevUpperBand = null;
_prevDonchLower = null;
_prevDonchUpper = null;
_prevAtr = null;
_lowerTrendLength = 0;
_upperTrendLength = 0;
_stopLossPrice = null;
_takeProfitPrice = null;
_equitySamples = 0;
_sumIndices = 0m;
_sumEquity = 0m;
_sumIndexEquity = 0m;
_sumIndexSquared = 0m;
_sumEquitySquared = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bollinger = new BollingerBands
{
Length = BollingerPeriod,
Width = BollingerDeviation
};
var atr = new AverageTrueRange
{
Length = AtrPeriod
};
var donchian = new DonchianChannels
{
Length = DonchianPeriod
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bollinger, atr, donchian, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bollingerVal, IIndicatorValue atrVal, IIndicatorValue donchianVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!bollingerVal.IsFormed || !atrVal.IsFormed || !donchianVal.IsFormed)
return;
var bollingerComplex = (ComplexIndicatorValue<BollingerBands>)bollingerVal;
var middle = bollingerComplex.InnerValues.ElementAt(0).Value.GetValue<decimal>();
var upper = bollingerComplex.InnerValues.ElementAt(1).Value.GetValue<decimal>();
var lower = bollingerComplex.InnerValues.ElementAt(2).Value.GetValue<decimal>();
var atrValue = atrVal.GetValue<decimal>();
var donchianComplex = (ComplexIndicatorValue<DonchianChannels>)donchianVal;
var donchUpper = donchianComplex.InnerValues.ElementAt(0).Value.GetValue<decimal>();
var donchLower = donchianComplex.InnerValues.ElementAt(1).Value.GetValue<decimal>();
var lowerTrendLength = CalculateLowerTrendLength(donchLower);
var upperTrendLength = CalculateUpperTrendLength(donchUpper);
if (!_prevOpen.HasValue)
{
CachePreviousValues(candle, lower, upper, donchLower, donchUpper, atrValue, lowerTrendLength, upperTrendLength);
return;
}
var previousOpen = _prevOpen.Value;
var previousClose = _prevClose!.Value;
var previousLowerBand = _prevLowerBand!.Value;
var previousUpperBand = _prevUpperBand!.Value;
var previousDonchLower = _prevDonchLower!.Value;
var previousDonchUpper = _prevDonchUpper!.Value;
var atrForStops = _prevAtr ?? atrValue;
if (Position == 0m)
{
if (previousOpen < previousLowerBand && previousClose > previousLowerBand && lowerTrendLength > ConfirmationPeriod)
{
OpenLong(candle.ClosePrice, atrForStops);
}
else if (previousOpen > previousUpperBand && previousClose < previousUpperBand && upperTrendLength > ConfirmationPeriod)
{
OpenShort(candle.ClosePrice, atrForStops);
}
}
else if (Position > 0m)
{
var exitVolume = Position;
var stopTriggered = _stopLossPrice is decimal stop && candle.LowPrice <= stop;
var takeTriggered = _takeProfitPrice is decimal take && candle.HighPrice >= take;
if (stopTriggered || takeTriggered || previousClose > previousDonchUpper || previousClose < previousDonchLower)
{
SellMarket(exitVolume);
ClearProtection();
}
}
else if (Position < 0m)
{
var exitVolume = Math.Abs(Position);
var stopTriggered = _stopLossPrice is decimal stop && candle.HighPrice >= stop;
var takeTriggered = _takeProfitPrice is decimal take && candle.LowPrice <= take;
if (stopTriggered || takeTriggered || previousClose < previousDonchLower || previousClose > previousDonchUpper)
{
BuyMarket(exitVolume);
ClearProtection();
}
}
CachePreviousValues(candle, lower, upper, donchLower, donchUpper, atrValue, lowerTrendLength, upperTrendLength);
}
private int CalculateLowerTrendLength(decimal currentLower)
{
if (_prevDonchLower is decimal prevLower)
{
return currentLower >= prevLower ? _lowerTrendLength + 1 : 1;
}
return 1;
}
private int CalculateUpperTrendLength(decimal currentUpper)
{
if (_prevDonchUpper is decimal prevUpper)
{
return currentUpper <= prevUpper ? _upperTrendLength + 1 : 1;
}
return 1;
}
private void CachePreviousValues(ICandleMessage candle, decimal lower, decimal upper, decimal donchLower, decimal donchUpper, decimal atrValue, int lowerTrendLength, int upperTrendLength)
{
_prevOpen = candle.OpenPrice;
_prevClose = candle.ClosePrice;
_prevLowerBand = lower;
_prevUpperBand = upper;
_prevDonchLower = donchLower;
_prevDonchUpper = donchUpper;
_prevAtr = atrValue;
_lowerTrendLength = lowerTrendLength;
_upperTrendLength = upperTrendLength;
}
private void OpenLong(decimal entryPrice, decimal atrValue)
{
var volume = TradeVolume;
if (volume <= 0m)
return;
BuyMarket(volume);
AssignProtection(entryPrice, atrValue, true);
}
private void OpenShort(decimal entryPrice, decimal atrValue)
{
var volume = TradeVolume;
if (volume <= 0m)
return;
SellMarket(volume);
AssignProtection(entryPrice, atrValue, false);
}
private void AssignProtection(decimal entryPrice, decimal atrValue, bool isLong)
{
if (atrValue <= 0m)
{
ClearProtection();
return;
}
var stopDistance = atrValue * StopAtrMultiplier;
var takeDistance = atrValue * TakeAtrMultiplier;
if (isLong)
{
_stopLossPrice = entryPrice - stopDistance;
_takeProfitPrice = entryPrice + takeDistance;
}
else
{
_stopLossPrice = entryPrice + stopDistance;
_takeProfitPrice = entryPrice - takeDistance;
}
}
private void ClearProtection()
{
_stopLossPrice = null;
_takeProfitPrice = null;
}
/// <inheritdoc />
protected override void OnOwnTradeReceived(MyTrade trade)
{
base.OnOwnTradeReceived(trade);
var portfolio = Portfolio;
if (portfolio == null)
return;
UpdateEquityStatistics(portfolio.CurrentValue ?? 0m);
}
private void UpdateEquityStatistics(decimal equity)
{
var index = (decimal)_equitySamples;
_sumIndices += index;
_sumEquity += equity;
_sumIndexEquity += index * equity;
_sumIndexSquared += index * index;
_sumEquitySquared += equity * equity;
_equitySamples++;
if (_equitySamples % 100 != 0)
return;
var n = (decimal)_equitySamples;
if (n <= 1m)
return;
var denominator = n * _sumIndexSquared - _sumIndices * _sumIndices;
if (denominator == 0m)
return;
var slope = (n * _sumIndexEquity - _sumIndices * _sumEquity) / denominator;
var mean = _sumEquity / n;
var ssTotal = _sumEquitySquared - n * mean * mean;
if (ssTotal == 0m)
{
LogInfo("Equity R-squared: 1.0000");
return;
}
var regressionComponent = slope * (_sumIndexEquity - (_sumIndices / n) * _sumEquity);
var rSquared = regressionComponent / ssTotal;
if (slope < 0m)
rSquared = -rSquared;
LogInfo($"Equity R-squared: {rSquared:F4}");
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import BollingerBands, AverageTrueRange, DonchianChannels
from StockSharp.Algo.Strategies import Strategy
class bands_strategy(Strategy):
"""Bollinger Bands breakout confirmed by Donchian channel slope and ATR-based stops."""
def __init__(self):
super(bands_strategy, self).__init__()
self._trade_volume = self.Param("TradeVolume", 0.1) \
.SetGreaterThanZero() \
.SetDisplay("Volume", "Net volume in lots sent with every order", "Trading")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Time frame used for indicator calculations", "Market Data")
self._bollinger_period = self.Param("BollingerPeriod", 100) \
.SetGreaterThanZero() \
.SetDisplay("Bollinger Period", "Number of candles used for Bollinger Bands", "Indicators")
self._bollinger_deviation = self.Param("BollingerDeviation", 1.0) \
.SetGreaterThanZero() \
.SetDisplay("Bollinger Deviation", "Standard deviation multiplier", "Indicators")
self._donchian_period = self.Param("DonchianPeriod", 100) \
.SetGreaterThanZero() \
.SetDisplay("Donchian Period", "Donchian Channel length", "Indicators")
self._confirmation_period = self.Param("ConfirmationPeriod", 100) \
.SetGreaterThanZero() \
.SetDisplay("Slope Confirmation", "Min bars for Donchian slope confirmation", "Indicators")
self._atr_period = self.Param("AtrPeriod", 21) \
.SetGreaterThanZero() \
.SetDisplay("ATR Period", "Length of Average True Range", "Indicators")
self._stop_atr_multiplier = self.Param("StopAtrMultiplier", 4.0) \
.SetGreaterThanZero() \
.SetDisplay("Stop ATR Multiplier", "ATRs for stop placement", "Risk")
self._take_atr_multiplier = self.Param("TakeAtrMultiplier", 4.0) \
.SetGreaterThanZero() \
.SetDisplay("Take ATR Multiplier", "ATRs for target placement", "Risk")
self._prev_open = None
self._prev_close = None
self._prev_lower_band = None
self._prev_upper_band = None
self._prev_donch_lower = None
self._prev_donch_upper = None
self._prev_atr = None
self._lower_trend_length = 0
self._upper_trend_length = 0
self._stop_loss_price = None
self._take_profit_price = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def TradeVolume(self):
return self._trade_volume.Value
@property
def BollingerPeriod(self):
return self._bollinger_period.Value
@property
def BollingerDeviation(self):
return self._bollinger_deviation.Value
@property
def DonchianPeriod(self):
return self._donchian_period.Value
@property
def ConfirmationPeriod(self):
return self._confirmation_period.Value
@property
def AtrPeriod(self):
return self._atr_period.Value
@property
def StopAtrMultiplier(self):
return self._stop_atr_multiplier.Value
@property
def TakeAtrMultiplier(self):
return self._take_atr_multiplier.Value
def OnReseted(self):
super(bands_strategy, self).OnReseted()
self._prev_open = None
self._prev_close = None
self._prev_lower_band = None
self._prev_upper_band = None
self._prev_donch_lower = None
self._prev_donch_upper = None
self._prev_atr = None
self._lower_trend_length = 0
self._upper_trend_length = 0
self._stop_loss_price = None
self._take_profit_price = None
def OnStarted2(self, time):
super(bands_strategy, self).OnStarted2(time)
bollinger = BollingerBands()
bollinger.Length = self.BollingerPeriod
bollinger.Width = self.BollingerDeviation
atr = AverageTrueRange()
atr.Length = self.AtrPeriod
donchian = DonchianChannels()
donchian.Length = self.DonchianPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(bollinger, atr, donchian, self._process_candle).Start()
def _process_candle(self, candle, bb_val, atr_val, donch_val):
if candle.State != CandleStates.Finished:
return
if not bb_val.IsFormed or not atr_val.IsFormed or not donch_val.IsFormed:
return
upper_bb = bb_val.UpBand
lower_bb = bb_val.LowBand
atr_v = float(atr_val)
donch_upper = donch_val.UpperBand
donch_lower = donch_val.LowerBand
if upper_bb is None or lower_bb is None or donch_upper is None or donch_lower is None:
return
upper = float(upper_bb)
lower = float(lower_bb)
d_upper = float(donch_upper)
d_lower = float(donch_lower)
lower_trend = self._calc_lower_trend(d_lower)
upper_trend = self._calc_upper_trend(d_upper)
if self._prev_open is None:
self._cache_values(candle, lower, upper, d_lower, d_upper, atr_v, lower_trend, upper_trend)
return
prev_open = self._prev_open
prev_close = self._prev_close
prev_lower_band = self._prev_lower_band
prev_upper_band = self._prev_upper_band
prev_donch_lower = self._prev_donch_lower
prev_donch_upper = self._prev_donch_upper
atr_for_stops = self._prev_atr if self._prev_atr is not None else atr_v
if self.Position == 0:
if prev_open < prev_lower_band and prev_close > prev_lower_band and lower_trend > self.ConfirmationPeriod:
self._open_long(float(candle.ClosePrice), atr_for_stops)
elif prev_open > prev_upper_band and prev_close < prev_upper_band and upper_trend > self.ConfirmationPeriod:
self._open_short(float(candle.ClosePrice), atr_for_stops)
elif self.Position > 0:
stop_hit = self._stop_loss_price is not None and float(candle.LowPrice) <= self._stop_loss_price
take_hit = self._take_profit_price is not None and float(candle.HighPrice) >= self._take_profit_price
if stop_hit or take_hit or prev_close > prev_donch_upper or prev_close < prev_donch_lower:
self.SellMarket(self.Position)
self._clear_protection()
elif self.Position < 0:
stop_hit = self._stop_loss_price is not None and float(candle.HighPrice) >= self._stop_loss_price
take_hit = self._take_profit_price is not None and float(candle.LowPrice) <= self._take_profit_price
if stop_hit or take_hit or prev_close < prev_donch_lower or prev_close > prev_donch_upper:
self.BuyMarket(abs(self.Position))
self._clear_protection()
self._cache_values(candle, lower, upper, d_lower, d_upper, atr_v, lower_trend, upper_trend)
def _calc_lower_trend(self, current_lower):
if self._prev_donch_lower is not None:
return self._lower_trend_length + 1 if current_lower >= self._prev_donch_lower else 1
return 1
def _calc_upper_trend(self, current_upper):
if self._prev_donch_upper is not None:
return self._upper_trend_length + 1 if current_upper <= self._prev_donch_upper else 1
return 1
def _cache_values(self, candle, lower, upper, d_lower, d_upper, atr_v, lower_trend, upper_trend):
self._prev_open = float(candle.OpenPrice)
self._prev_close = float(candle.ClosePrice)
self._prev_lower_band = lower
self._prev_upper_band = upper
self._prev_donch_lower = d_lower
self._prev_donch_upper = d_upper
self._prev_atr = atr_v
self._lower_trend_length = lower_trend
self._upper_trend_length = upper_trend
def _open_long(self, entry_price, atr_v):
vol = float(self.TradeVolume)
if vol <= 0:
return
self.BuyMarket(vol)
self._assign_protection(entry_price, atr_v, True)
def _open_short(self, entry_price, atr_v):
vol = float(self.TradeVolume)
if vol <= 0:
return
self.SellMarket(vol)
self._assign_protection(entry_price, atr_v, False)
def _assign_protection(self, entry_price, atr_v, is_long):
if atr_v <= 0:
self._clear_protection()
return
stop_dist = atr_v * float(self.StopAtrMultiplier)
take_dist = atr_v * float(self.TakeAtrMultiplier)
if is_long:
self._stop_loss_price = entry_price - stop_dist
self._take_profit_price = entry_price + take_dist
else:
self._stop_loss_price = entry_price + stop_dist
self._take_profit_price = entry_price - take_dist
def _clear_protection(self):
self._stop_loss_price = None
self._take_profit_price = None
def CreateClone(self):
return bands_strategy()