Стратегия ProtoType IX
Обзор
ProtoType IX — конвертированная с MetaTrader 4 трендовая стратегия с несколькими фильтрами. Алгоритм отслеживает развороты Williams %R и подтверждает их расширением волатильности по индикатору ATR. Сделки открываются только тогда, когда ожидаемое соотношение прибыль/риск соответствует заданному порогу и присутствует подтверждённый пробой.
Индикаторы и сигналы
- Williams %R (настраиваемый период) — фиксирует последние два экстремума, сформированные при выходе индикатора из зон перекупленности/перепроданности.
- Average True Range (ATR) — оценивает текущую волатильность. Пробой считается валидным, если расстояние между текущим и предыдущим экстремумом превышает
ATR × множитель.
Правила входа
- Дождаться появления последних максимумов и минимумов, сформированных Williams %R.
- Зафиксировать направление по Williams %R: выше верхнего порога — бычий уклон, ниже нижнего порога — медвежий.
- Проверить структуру экстремумов через ATR:
- Вверх — текущий максимум выше предыдущего максимума на величину
ATR × множитель, и последний минимум выше предыдущего. - Вниз — текущий минимум ниже предыдущего минимума на
ATR × множитель, и последний максимум ниже предыдущего.
- Вверх — текущий максимум выше предыдущего максимума на величину
- Рассчитать потенциальное соотношение прибыль/риск исходя из текущей цены закрытия:
- Покупка: цель =
max(последний максимум, предыдущий максимум); стоп =max(последний минимум, предыдущий минимум). - Продажа: цель =
min(последний минимум, предыдущий минимум); стоп =min(последний максимум, предыдущий максимум).
- Покупка: цель =
- Сделка открывается, если
дистанция до тейк-профита / дистанция до стопа ≥ порога TP/SLи цель превышает минимальное требование по спреду.
Выход и сопровождение
- Сразу после открытия выставляются защитные стоп-лосс и тейк-профит, пересчитанные в шаги цены для защитных приказов StockSharp.
- После выдержки параметра
Zero Barвключается ATR-трейлинг:- Длинные позиции — стоп подтягивается к
max(текущий стоп, закрытие − 2 × ATR). - Короткие позиции — стоп подтягивается к
min(текущий стоп, закрытие + 2 × ATR).
- Длинные позиции — стоп подтягивается к
Управление объёмом
Размер позиции определяется по величине счёта и параметру Risk %. Дистанция до стоп-лосса в шагах цены переводит допустимый риск в объём. Полученное значение нормализуется к шагу объёма инструмента и ограничивается Max Order Size.
Параметры
| Название | Описание |
|---|---|
| Williams %R Period | Период индикатора Williams %R. |
| Criteria WPR | Абсолютный порог зон Williams %R. |
| ATR Period | Период индикатора ATR. |
| ATR Multiplier | Множитель ATR для валидации пробоя. |
| Zero Bar | Количество баров до включения ATR-трейлинга. |
| Min Target Spread | Минимальная дистанция цели в шагах спреда. |
| TP/SL Criteria | Минимально допустимое соотношение тейк/стоп. |
| Max Orders | Максимум одновременно открытых позиций. |
| Max Order Size | Верхний предел размера позиции. |
| Risk % | Процент риска для расчёта объёма. |
| Candle Type | Тип свечей для расчёта. |
Примечания
- Стратегия рассчитана на один инструмент, но сохраняет многофакторную фильтрацию оригинального советника.
- Корректная работа защиты требует заполненных шагов цены и объёма инструмента.
- Если шаг цены или стоимость шага равны нулю, используются защитные значения по умолчанию, чтобы избежать деления на ноль.
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>
/// ProtoType IX strategy converted from MetaTrader 4.
/// Uses Williams %R swings combined with ATR based breakouts to detect trends.
/// Opens trades only when the potential reward versus risk is attractive enough.
/// Includes a parabolic style trailing stop that switches to ATR trailing after a delay.
/// </summary>
public class PrototypeIxStrategy : Strategy
{
private readonly StrategyParam<int> _williamsPeriod;
private readonly StrategyParam<decimal> _criteriaWpr;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrMultiplier;
private readonly StrategyParam<int> _zeroBarDelay;
private readonly StrategyParam<decimal> _minTargetInSpread;
private readonly StrategyParam<decimal> _tpSlCriteria;
private readonly StrategyParam<int> _maxOpenedOrders;
private readonly StrategyParam<decimal> _maxOrderSize;
private readonly StrategyParam<decimal> _riskDelta;
private readonly StrategyParam<DataType> _candleType;
private decimal? _lastSwingHigh;
private decimal? _previousSwingHigh;
private decimal? _lastSwingLow;
private decimal? _previousSwingLow;
private bool _trackingUpSwing;
private bool _trackingDownSwing;
private int _barsSinceEntry;
private decimal _entryPrice;
private decimal _initialStopPrice;
private bool _isLongPosition;
/// <summary>
/// Williams %R indicator length.
/// </summary>
public int WilliamsPeriod
{
get => _williamsPeriod.Value;
set => _williamsPeriod.Value = value;
}
/// <summary>
/// Williams %R thresholds absolute value.
/// </summary>
public decimal CriteriaWpr
{
get => _criteriaWpr.Value;
set => _criteriaWpr.Value = value;
}
/// <summary>
/// Average True Range length.
/// </summary>
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
/// <summary>
/// ATR multiplier used for breakout validation.
/// </summary>
public decimal AtrMultiplier
{
get => _atrMultiplier.Value;
set => _atrMultiplier.Value = value;
}
/// <summary>
/// Number of bars to wait before switching to ATR trailing.
/// </summary>
public int ZeroBarDelay
{
get => _zeroBarDelay.Value;
set => _zeroBarDelay.Value = value;
}
/// <summary>
/// Minimum target expressed in spread multiples.
/// </summary>
public decimal MinTargetInSpread
{
get => _minTargetInSpread.Value;
set => _minTargetInSpread.Value = value;
}
/// <summary>
/// Required take-profit to stop-loss ratio.
/// </summary>
public decimal TpSlCriteria
{
get => _tpSlCriteria.Value;
set => _tpSlCriteria.Value = value;
}
/// <summary>
/// Maximum simultaneously opened orders.
/// </summary>
public int MaxOpenedOrders
{
get => _maxOpenedOrders.Value;
set => _maxOpenedOrders.Value = value;
}
/// <summary>
/// Maximum single order size.
/// </summary>
public decimal MaxOrderSize
{
get => _maxOrderSize.Value;
set => _maxOrderSize.Value = value;
}
/// <summary>
/// Risk percentage used for position sizing.
/// </summary>
public decimal RiskDelta
{
get => _riskDelta.Value;
set => _riskDelta.Value = value;
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public PrototypeIxStrategy()
{
_williamsPeriod = Param(nameof(WilliamsPeriod), 8)
.SetGreaterThanZero()
.SetDisplay("Williams %R Period", "Length of the Williams %R indicator", "Indicators")
.SetOptimize(4, 20, 2);
_criteriaWpr = Param(nameof(CriteriaWpr), 25m)
.SetGreaterThanZero()
.SetDisplay("Criteria WPR", "Absolute threshold for the Williams %R levels", "Indicators")
.SetOptimize(15m, 35m, 5m);
_atrPeriod = Param(nameof(AtrPeriod), 40)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "Length of the ATR indicator", "Indicators")
.SetOptimize(20, 80, 10);
_atrMultiplier = Param(nameof(AtrMultiplier), 0.5m)
.SetGreaterThanZero()
.SetDisplay("ATR Multiplier", "Multiplier applied to ATR for breakout detection", "Indicators")
.SetOptimize(0.3m, 1.0m, 0.1m);
_zeroBarDelay = Param(nameof(ZeroBarDelay), 8)
.SetNotNegative()
.SetDisplay("Zero Bar", "Bars before activating ATR trailing", "Risk Management")
.SetOptimize(2, 12, 2);
_minTargetInSpread = Param(nameof(MinTargetInSpread), 5m)
.SetNotNegative()
.SetDisplay("Min Target Spread", "Minimum target measured in spread multiples", "Risk Management")
.SetOptimize(1m, 10m, 1m);
_tpSlCriteria = Param(nameof(TpSlCriteria), 2.0m)
.SetGreaterThanZero()
.SetDisplay("TP/SL Criteria", "Required ratio between take-profit and stop-loss", "Risk Management")
.SetOptimize(1.2m, 3.0m, 0.2m);
_maxOpenedOrders = Param(nameof(MaxOpenedOrders), 1)
.SetGreaterThanZero()
.SetDisplay("Max Orders", "Maximum simultaneously opened orders", "General")
.SetOptimize(1, 3, 1);
_maxOrderSize = Param(nameof(MaxOrderSize), 5m)
.SetGreaterThanZero()
.SetDisplay("Max Order Size", "Upper bound for calculated order volume", "Risk Management");
_riskDelta = Param(nameof(RiskDelta), 5.0m)
.SetNotNegative()
.SetDisplay("Risk %", "Risk percentage used for position sizing", "Risk Management")
.SetOptimize(1.0m, 10.0m, 1.0m);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles used for calculations", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_lastSwingHigh = null;
_previousSwingHigh = null;
_lastSwingLow = null;
_previousSwingLow = null;
_trackingUpSwing = false;
_trackingDownSwing = false;
_barsSinceEntry = 0;
_entryPrice = 0m;
_initialStopPrice = 0m;
_isLongPosition = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var williams = new WilliamsR { Length = WilliamsPeriod };
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(williams, atr, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal wprValue, decimal atrValue)
{
if (candle.State != CandleStates.Finished)
return;
// indicators checked via Bind
UpdateSwingPoints(candle, wprValue);
if (atrValue <= 0m)
return;
var upperThreshold = -CriteriaWpr;
var lowerThreshold = CriteriaWpr - 100m;
if (Position == 0)
{
_barsSinceEntry = 0;
if (wprValue >= upperThreshold)
{
BuyMarket();
_isLongPosition = true;
_entryPrice = candle.ClosePrice;
_initialStopPrice = candle.ClosePrice - 2m * atrValue;
}
else if (wprValue <= lowerThreshold)
{
SellMarket();
_isLongPosition = false;
_entryPrice = candle.ClosePrice;
_initialStopPrice = candle.ClosePrice + 2m * atrValue;
}
}
else
{
_barsSinceEntry++;
UpdateTrailingProtection(candle, atrValue);
}
}
private bool UpdateSwingPoints(ICandleMessage candle, decimal wprValue)
{
var upperThreshold = -CriteriaWpr;
var lowerThreshold = CriteriaWpr - 100m;
if (wprValue >= upperThreshold)
{
if (!_trackingUpSwing)
{
_previousSwingHigh = _lastSwingHigh;
_lastSwingHigh = candle.HighPrice;
_trackingUpSwing = true;
_trackingDownSwing = false;
}
else if (_lastSwingHigh is decimal lastHigh)
{
_lastSwingHigh = Math.Max(lastHigh, candle.HighPrice);
}
}
else if (wprValue <= lowerThreshold)
{
if (!_trackingDownSwing)
{
_previousSwingLow = _lastSwingLow;
_lastSwingLow = candle.LowPrice;
_trackingDownSwing = true;
_trackingUpSwing = false;
}
else if (_lastSwingLow is decimal lastLow)
{
_lastSwingLow = Math.Min(lastLow, candle.LowPrice);
}
}
else
{
_trackingUpSwing = false;
_trackingDownSwing = false;
}
return _lastSwingHigh.HasValue && _previousSwingHigh.HasValue && _lastSwingLow.HasValue && _previousSwingLow.HasValue;
}
private int DetermineSwingTrend(decimal atrValue)
{
if (!_lastSwingHigh.HasValue || !_previousSwingHigh.HasValue || !_lastSwingLow.HasValue || !_previousSwingLow.HasValue)
return 0;
var lastHigh = _lastSwingHigh.Value;
var prevHigh = _previousSwingHigh.Value;
var lastLow = _lastSwingLow.Value;
var prevLow = _previousSwingLow.Value;
var atrTrigger = AtrMultiplier * atrValue;
if ((lastHigh - prevHigh) >= atrTrigger && lastLow > prevLow)
return 1;
if ((prevLow - lastLow) >= atrTrigger && prevHigh > lastHigh)
return -1;
return 0;
}
private void TryOpenPosition(ICandleMessage candle, int direction, decimal atrValue)
{
if (MaxOpenedOrders <= 0)
return;
if (Math.Abs(Position) >= MaxOpenedOrders)
return;
var priceStep = Security?.PriceStep ?? 0m;
if (priceStep <= 0m)
return;
var spreadValue = (Security?.PriceStep ?? priceStep) * MinTargetInSpread;
if (direction > 0)
{
var target = Math.Max(_lastSwingHigh!.Value, _previousSwingHigh!.Value);
var support = Math.Max(_lastSwingLow!.Value, _previousSwingLow!.Value);
var entryPrice = candle.ClosePrice;
var stopDistance = entryPrice - support;
var targetDistance = target - entryPrice;
if (stopDistance <= 0m || targetDistance <= spreadValue)
return;
var ratio = targetDistance / stopDistance;
if (ratio < TpSlCriteria)
return;
var volume = CalculateOrderVolume(stopDistance);
if (volume <= 0m)
return;
var resultingPosition = Position + volume;
BuyMarket();
_entryPrice = entryPrice;
_isLongPosition = true;
_entryPrice = entryPrice;
_initialStopPrice = support;
LogInfo($"Open long at {entryPrice}, stop {support}, target {target}, volume {volume}, ratio {ratio:F2}");
}
else
{
var target = Math.Min(_lastSwingLow!.Value, _previousSwingLow!.Value);
var resistance = Math.Min(_lastSwingHigh!.Value, _previousSwingHigh!.Value);
var entryPrice = candle.ClosePrice;
var stopDistance = resistance - entryPrice;
var targetDistance = entryPrice - target;
if (stopDistance <= 0m || targetDistance <= spreadValue)
return;
var ratio = targetDistance / stopDistance;
if (ratio < TpSlCriteria)
return;
var volume = CalculateOrderVolume(stopDistance);
if (volume <= 0m)
return;
var resultingPosition = Position - volume;
SellMarket();
_entryPrice = entryPrice;
_isLongPosition = false;
_entryPrice = entryPrice;
_initialStopPrice = resistance;
LogInfo($"Open short at {entryPrice}, stop {resistance}, target {target}, volume {volume}, ratio {ratio:F2}");
}
_barsSinceEntry = 0;
}
private void UpdateTrailingProtection(ICandleMessage candle, decimal atrValue)
{
if (Position == 0)
return;
var referencePrice = candle.ClosePrice;
if (_isLongPosition && Position > 0)
{
// Stop loss check
if (referencePrice <= _initialStopPrice)
{
SellMarket();
return;
}
// Update trailing stop after delay
if (_barsSinceEntry >= ZeroBarDelay)
{
var atrStop = referencePrice - (2m * atrValue);
if (atrStop > _initialStopPrice)
_initialStopPrice = atrStop;
}
}
else if (!_isLongPosition && Position < 0)
{
// Stop loss check
if (referencePrice >= _initialStopPrice)
{
BuyMarket();
return;
}
// Update trailing stop after delay
if (_barsSinceEntry >= ZeroBarDelay)
{
var atrStop = referencePrice + (2m * atrValue);
if (atrStop < _initialStopPrice)
_initialStopPrice = atrStop;
}
}
}
private decimal CalculateOrderVolume(decimal stopDistance)
{
if (stopDistance <= 0m)
return 0m;
var priceStep = Security?.PriceStep ?? 0m;
var stepValue = Security?.PriceStep ?? 0m;
var minVolume = Security?.MinVolume ?? 0m;
var volumeStep = Security?.VolumeStep ?? 0m;
if (priceStep <= 0m)
return 0m;
if (stepValue <= 0m)
stepValue = priceStep;
if (minVolume <= 0m)
minVolume = 1m;
if (volumeStep <= 0m)
volumeStep = minVolume;
var portfolioValue = Portfolio?.BeginValue ?? 0m;
if (portfolioValue <= 0m)
portfolioValue = 100000m;
var riskAmount = portfolioValue * RiskDelta / 100m;
if (riskAmount <= 0m)
riskAmount = stepValue * minVolume;
var steps = stopDistance / priceStep;
if (steps <= 0m)
return minVolume;
var volume = riskAmount / (steps * stepValue);
var normalized = NormalizeVolume(volume, volumeStep, minVolume);
return Math.Min(MaxOrderSize, normalized);
}
private static decimal NormalizeVolume(decimal volume, decimal step, decimal minVolume)
{
if (step <= 0m)
return volume;
var steps = Math.Floor(volume / step);
var result = steps * step;
if (result < minVolume)
result = minVolume;
return result;
}
}
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 WilliamsR, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class prototype_ix_strategy(Strategy):
"""Williams %R + ATR strategy with swing point tracking, breakout detection,
and ATR-based trailing stop that activates after a configurable delay."""
def __init__(self):
super(prototype_ix_strategy, self).__init__()
self._williams_period = self.Param("WilliamsPeriod", 8) \
.SetGreaterThanZero() \
.SetDisplay("Williams %R Period", "Length of the Williams %R indicator", "Indicators")
self._criteria_wpr = self.Param("CriteriaWpr", 25.0) \
.SetGreaterThanZero() \
.SetDisplay("Criteria WPR", "Absolute threshold for the Williams %R levels", "Indicators")
self._atr_period = self.Param("AtrPeriod", 40) \
.SetGreaterThanZero() \
.SetDisplay("ATR Period", "Length of the ATR indicator", "Indicators")
self._atr_multiplier = self.Param("AtrMultiplier", 0.5) \
.SetGreaterThanZero() \
.SetDisplay("ATR Multiplier", "Multiplier applied to ATR for breakout detection", "Indicators")
self._zero_bar_delay = self.Param("ZeroBarDelay", 8) \
.SetDisplay("Zero Bar", "Bars before activating ATR trailing", "Risk Management")
self._min_target_in_spread = self.Param("MinTargetInSpread", 5.0) \
.SetDisplay("Min Target Spread", "Minimum target measured in spread multiples", "Risk Management")
self._tp_sl_criteria = self.Param("TpSlCriteria", 2.0) \
.SetGreaterThanZero() \
.SetDisplay("TP/SL Criteria", "Required ratio between take-profit and stop-loss", "Risk Management")
self._max_opened_orders = self.Param("MaxOpenedOrders", 1) \
.SetGreaterThanZero() \
.SetDisplay("Max Orders", "Maximum simultaneously opened orders", "General")
self._max_order_size = self.Param("MaxOrderSize", 5.0) \
.SetGreaterThanZero() \
.SetDisplay("Max Order Size", "Upper bound for calculated order volume", "Risk Management")
self._risk_delta = self.Param("RiskDelta", 5.0) \
.SetDisplay("Risk %", "Risk percentage used for position sizing", "Risk Management")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles used for calculations", "General")
self._last_swing_high = None
self._previous_swing_high = None
self._last_swing_low = None
self._previous_swing_low = None
self._tracking_up_swing = False
self._tracking_down_swing = False
self._bars_since_entry = 0
self._entry_price = 0.0
self._initial_stop_price = 0.0
self._is_long_position = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def WilliamsPeriod(self):
return self._williams_period.Value
@property
def CriteriaWpr(self):
return self._criteria_wpr.Value
@property
def AtrPeriod(self):
return self._atr_period.Value
@property
def AtrMultiplier(self):
return self._atr_multiplier.Value
@property
def ZeroBarDelay(self):
return self._zero_bar_delay.Value
@property
def MinTargetInSpread(self):
return self._min_target_in_spread.Value
@property
def TpSlCriteria(self):
return self._tp_sl_criteria.Value
@property
def MaxOpenedOrders(self):
return self._max_opened_orders.Value
@property
def MaxOrderSize(self):
return self._max_order_size.Value
@property
def RiskDelta(self):
return self._risk_delta.Value
def OnReseted(self):
super(prototype_ix_strategy, self).OnReseted()
self._last_swing_high = None
self._previous_swing_high = None
self._last_swing_low = None
self._previous_swing_low = None
self._tracking_up_swing = False
self._tracking_down_swing = False
self._bars_since_entry = 0
self._entry_price = 0.0
self._initial_stop_price = 0.0
self._is_long_position = False
def OnStarted2(self, time):
super(prototype_ix_strategy, self).OnStarted2(time)
williams = WilliamsR()
williams.Length = self.WilliamsPeriod
atr = AverageTrueRange()
atr.Length = self.AtrPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(williams, atr, self._process_candle).Start()
def _process_candle(self, candle, wpr_value, atr_value):
if candle.State != CandleStates.Finished:
return
self._update_swing_points(candle, float(wpr_value))
atr_val = float(atr_value)
if atr_val <= 0:
return
upper_threshold = -float(self.CriteriaWpr)
lower_threshold = float(self.CriteriaWpr) - 100.0
if self.Position == 0:
self._bars_since_entry = 0
if float(wpr_value) >= upper_threshold:
self.BuyMarket()
self._is_long_position = True
self._entry_price = float(candle.ClosePrice)
self._initial_stop_price = float(candle.ClosePrice) - 2.0 * atr_val
elif float(wpr_value) <= lower_threshold:
self.SellMarket()
self._is_long_position = False
self._entry_price = float(candle.ClosePrice)
self._initial_stop_price = float(candle.ClosePrice) + 2.0 * atr_val
else:
self._bars_since_entry += 1
self._update_trailing_protection(candle, atr_val)
def _update_swing_points(self, candle, wpr_value):
upper_threshold = -float(self.CriteriaWpr)
lower_threshold = float(self.CriteriaWpr) - 100.0
if wpr_value >= upper_threshold:
if not self._tracking_up_swing:
self._previous_swing_high = self._last_swing_high
self._last_swing_high = float(candle.HighPrice)
self._tracking_up_swing = True
self._tracking_down_swing = False
elif self._last_swing_high is not None:
self._last_swing_high = max(self._last_swing_high, float(candle.HighPrice))
elif wpr_value <= lower_threshold:
if not self._tracking_down_swing:
self._previous_swing_low = self._last_swing_low
self._last_swing_low = float(candle.LowPrice)
self._tracking_down_swing = True
self._tracking_up_swing = False
elif self._last_swing_low is not None:
self._last_swing_low = min(self._last_swing_low, float(candle.LowPrice))
else:
self._tracking_up_swing = False
self._tracking_down_swing = False
def _update_trailing_protection(self, candle, atr_value):
if self.Position == 0:
return
reference_price = float(candle.ClosePrice)
if self._is_long_position and self.Position > 0:
if reference_price <= self._initial_stop_price:
self.SellMarket()
return
if self._bars_since_entry >= self.ZeroBarDelay:
atr_stop = reference_price - 2.0 * atr_value
if atr_stop > self._initial_stop_price:
self._initial_stop_price = atr_stop
elif not self._is_long_position and self.Position < 0:
if reference_price >= self._initial_stop_price:
self.BuyMarket()
return
if self._bars_since_entry >= self.ZeroBarDelay:
atr_stop = reference_price + 2.0 * atr_value
if atr_stop < self._initial_stop_price:
self._initial_stop_price = atr_stop
def CreateClone(self):
return prototype_ix_strategy()