Стратегия Altarius RSI Stochastic Dual
Обзор
Стратегия Altarius RSI Stochastic Dual представляет собой перенос советника MetaTrader AltariusRSIxampnSTOH на платформу StockSharp. Торговая логика сочетает два стохастика с разными периодами и короткий RSI. Медленный стохастик определяет направление и зоны перекупленности/перепроданности, быстрый стохастик измеряет силу импульса, а RSI совместно с линией сигнала медленного стохастика управляют выходом из позиции. Дополнительно реализованы элементы управления капиталом из исходного MQL-скрипта: снижение объёма после убыточных сделок и принудительное закрытие при критической просадке по капиталу.
Торговая логика
- Источники данных – работа ведётся по настраиваемым свечам (по умолчанию 15-минутные). Все расчёты выполняются по цене закрытия свечи.
- Условия входа
- Покупка: основная линия медленного стохастика (15,8,8) находится выше сигнальной, но остаётся ниже
BuyStochasticLimit(50). Разница между линиями быстрого стохастика (10,3,3) по модулю большеStochasticDifferenceThreshold(5), что подтверждает импульс. - Продажа: основная линия медленного стохастика ниже сигнальной, но выше
SellStochasticLimit(55). Разница между линиями быстрого стохастика также должна превышать порог импульса.
- Покупка: основная линия медленного стохастика (15,8,8) находится выше сигнальной, но остаётся ниже
- Условия выхода
- Закрытие длинной позиции: RSI (период 4) выше
ExitRsiHigh(60), а сигнальная линия медленного стохастика опускается ниже предыдущего значения и остаётся вышеExitStochasticHigh(70). - Закрытие короткой позиции: RSI ниже
ExitRsiLow(40), сигнальная линия медленного стохастика поднимается выше предыдущего значения и остаётся нижеExitStochasticLow(30). - Выход по риску: при превышении допустимой просадки по плавающей прибыли (
MaximumRiskPercent) стратегия немедленно закрывает позиции.
- Закрытие длинной позиции: RSI (период 4) выше
- Управление объёмом – стартовый объём задаётся параметром
BaseVolume. После последовательных убытков объём уменьшается пропорциональноDecreaseFactor. При расчёте учитываются шаг и ограничения по объёму инструмента.
Параметры
| Параметр | Описание |
|---|---|
BaseVolume |
Базовый объём заявки до применения правил управления риском. |
MaximumRiskPercent |
Допустимая доля просадки по капиталу, при превышении которой позиции закрываются. |
DecreaseFactor |
Делитель, определяющий скорость сокращения объёма после серии убытков. |
RsiPeriod |
Период RSI для сигналов выхода. |
SlowStochasticPeriod, SlowStochasticK, SlowStochasticD |
Настройки медленного стохастика. |
FastStochasticPeriod, FastStochasticK, FastStochasticD |
Настройки быстрого стохастика. |
StochasticDifferenceThreshold |
Минимальная разница между линиями быстрого стохастика, подтверждающая импульс. |
BuyStochasticLimit, SellStochasticLimit |
Допустимые уровни медленного стохастика для открытия позиций. |
ExitRsiHigh, ExitRsiLow |
RSI-уровни, инициирующие выход из длинных и коротких позиций. |
ExitStochasticHigh, ExitStochasticLow |
Уровни сигнальной линии медленного стохастика, подтверждающие выход. |
CandleType |
Тип свечей, применяемых при расчётах. |
Примечания
- Стратегия одновременно держит только одну позицию, как и оригинальный советник.
- Просадка и сокращение объёмов рассчитываются по текущим данным портфеля в StockSharp.
- При наличии графика стратегия отрисовывает свечи, оба стохастика и собственные сделки для визуального контроля.
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>
/// Strategy converted from AltariusRSIxampnSTOH MQL4 expert advisor.
/// Combines dual stochastic filters with RSI based exits and dynamic position sizing.
/// </summary>
public class AltariusRsiStochasticDualStrategy : Strategy
{
private readonly StrategyParam<decimal> _baseVolume;
private readonly StrategyParam<decimal> _maximumRiskPercent;
private readonly StrategyParam<decimal> _decreaseFactor;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _slowStochPeriod;
private readonly StrategyParam<int> _slowStochK;
private readonly StrategyParam<int> _slowStochD;
private readonly StrategyParam<int> _fastStochPeriod;
private readonly StrategyParam<int> _fastStochK;
private readonly StrategyParam<int> _fastStochD;
private readonly StrategyParam<decimal> _differenceThreshold;
private readonly StrategyParam<decimal> _buyLimit;
private readonly StrategyParam<decimal> _sellLimit;
private readonly StrategyParam<decimal> _exitRsiHigh;
private readonly StrategyParam<decimal> _exitRsiLow;
private readonly StrategyParam<decimal> _exitStochHigh;
private readonly StrategyParam<decimal> _exitStochLow;
private readonly StrategyParam<DataType> _candleType;
private decimal _previousSlowSignal;
private bool _hasPreviousSlowSignal;
private decimal _lastRealizedPnL;
private int _consecutiveLosses;
/// <summary>
/// Base order volume before risk and loss adjustments.
/// </summary>
public decimal BaseVolume
{
get => _baseVolume.Value;
set => _baseVolume.Value = value;
}
/// <summary>
/// Maximum share of account equity allowed to be lost before forcing an exit.
/// </summary>
public decimal MaximumRiskPercent
{
get => _maximumRiskPercent.Value;
set => _maximumRiskPercent.Value = value;
}
/// <summary>
/// Factor controlling how quickly the volume shrinks after consecutive losses.
/// </summary>
public decimal DecreaseFactor
{
get => _decreaseFactor.Value;
set => _decreaseFactor.Value = value;
}
/// <summary>
/// Period for the RSI exit filter.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// Period for the slow stochastic oscillator used to open trades.
/// </summary>
public int SlowStochasticPeriod
{
get => _slowStochPeriod.Value;
set => _slowStochPeriod.Value = value;
}
/// <summary>
/// %K smoothing length for the slow stochastic.
/// </summary>
public int SlowStochasticK
{
get => _slowStochK.Value;
set => _slowStochK.Value = value;
}
/// <summary>
/// %D smoothing length for the slow stochastic.
/// </summary>
public int SlowStochasticD
{
get => _slowStochD.Value;
set => _slowStochD.Value = value;
}
/// <summary>
/// Period for the fast stochastic oscillator used as momentum filter.
/// </summary>
public int FastStochasticPeriod
{
get => _fastStochPeriod.Value;
set => _fastStochPeriod.Value = value;
}
/// <summary>
/// %K smoothing length for the fast stochastic.
/// </summary>
public int FastStochasticK
{
get => _fastStochK.Value;
set => _fastStochK.Value = value;
}
/// <summary>
/// %D smoothing length for the fast stochastic.
/// </summary>
public int FastStochasticD
{
get => _fastStochD.Value;
set => _fastStochD.Value = value;
}
/// <summary>
/// Minimum distance between fast stochastic main and signal lines to allow entries.
/// </summary>
public decimal StochasticDifferenceThreshold
{
get => _differenceThreshold.Value;
set => _differenceThreshold.Value = value;
}
/// <summary>
/// Upper bound on the slow stochastic main line when opening long trades.
/// </summary>
public decimal BuyStochasticLimit
{
get => _buyLimit.Value;
set => _buyLimit.Value = value;
}
/// <summary>
/// Lower bound on the slow stochastic main line when opening short trades.
/// </summary>
public decimal SellStochasticLimit
{
get => _sellLimit.Value;
set => _sellLimit.Value = value;
}
/// <summary>
/// RSI threshold that triggers exit for long positions.
/// </summary>
public decimal ExitRsiHigh
{
get => _exitRsiHigh.Value;
set => _exitRsiHigh.Value = value;
}
/// <summary>
/// RSI threshold that triggers exit for short positions.
/// </summary>
public decimal ExitRsiLow
{
get => _exitRsiLow.Value;
set => _exitRsiLow.Value = value;
}
/// <summary>
/// Stochastic level that confirms the exit of long positions.
/// </summary>
public decimal ExitStochasticHigh
{
get => _exitStochHigh.Value;
set => _exitStochHigh.Value = value;
}
/// <summary>
/// Stochastic level that confirms the exit of short positions.
/// </summary>
public decimal ExitStochasticLow
{
get => _exitStochLow.Value;
set => _exitStochLow.Value = value;
}
/// <summary>
/// Candle type used for indicator calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public AltariusRsiStochasticDualStrategy()
{
_baseVolume = Param(nameof(BaseVolume), 1m)
.SetNotNegative()
.SetDisplay("Base Volume", "Initial volume before money management rules", "Trading")
.SetOptimize(0.1m, 2m, 0.1m);
_maximumRiskPercent = Param(nameof(MaximumRiskPercent), 0.1m)
.SetNotNegative()
.SetDisplay("Max Risk %", "Equity drawdown percentage that forces position closure", "Risk Management")
.SetOptimize(0.05m, 0.3m, 0.05m);
_decreaseFactor = Param(nameof(DecreaseFactor), 3m)
.SetNotNegative()
.SetDisplay("Decrease Factor", "Loss streak divider applied to volume", "Risk Management")
.SetOptimize(1m, 5m, 1m);
_rsiPeriod = Param(nameof(RsiPeriod), 4)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Length of RSI used for exits", "Indicators")
.SetOptimize(2, 8, 1);
_slowStochPeriod = Param(nameof(SlowStochasticPeriod), 15)
.SetGreaterThanZero()
.SetDisplay("Slow Stochastic Period", "Main period of slow stochastic", "Indicators")
.SetOptimize(10, 25, 1);
_slowStochK = Param(nameof(SlowStochasticK), 8)
.SetGreaterThanZero()
.SetDisplay("Slow Stochastic %K", "Smoothing of %K for slow stochastic", "Indicators");
_slowStochD = Param(nameof(SlowStochasticD), 8)
.SetGreaterThanZero()
.SetDisplay("Slow Stochastic %D", "Smoothing of %D for slow stochastic", "Indicators");
_fastStochPeriod = Param(nameof(FastStochasticPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast Stochastic Period", "Main period of fast stochastic", "Indicators")
.SetOptimize(5, 15, 1);
_fastStochK = Param(nameof(FastStochasticK), 3)
.SetGreaterThanZero()
.SetDisplay("Fast Stochastic %K", "Smoothing of %K for fast stochastic", "Indicators");
_fastStochD = Param(nameof(FastStochasticD), 3)
.SetGreaterThanZero()
.SetDisplay("Fast Stochastic %D", "Smoothing of %D for fast stochastic", "Indicators");
_differenceThreshold = Param(nameof(StochasticDifferenceThreshold), 5m)
.SetNotNegative()
.SetDisplay("Momentum Threshold", "Minimum difference between fast stochastic lines", "Trading")
.SetOptimize(2m, 10m, 1m);
_buyLimit = Param(nameof(BuyStochasticLimit), 50m)
.SetDisplay("Buy Stochastic Limit", "Upper bound of slow stochastic for longs", "Trading");
_sellLimit = Param(nameof(SellStochasticLimit), 55m)
.SetDisplay("Sell Stochastic Limit", "Lower bound of slow stochastic for shorts", "Trading");
_exitRsiHigh = Param(nameof(ExitRsiHigh), 60m)
.SetDisplay("Exit RSI High", "RSI threshold to exit longs", "Exits");
_exitRsiLow = Param(nameof(ExitRsiLow), 40m)
.SetDisplay("Exit RSI Low", "RSI threshold to exit shorts", "Exits");
_exitStochHigh = Param(nameof(ExitStochasticHigh), 70m)
.SetDisplay("Exit Stochastic High", "Slow stochastic signal level confirming long exit", "Exits");
_exitStochLow = Param(nameof(ExitStochasticLow), 30m)
.SetDisplay("Exit Stochastic Low", "Slow stochastic signal level confirming short exit", "Exits");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candles used for calculations", "Market Data");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_previousSlowSignal = 0m;
_hasPreviousSlowSignal = false;
_lastRealizedPnL = PnLManager?.RealizedPnL ?? 0m;
_consecutiveLosses = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_lastRealizedPnL = PnLManager?.RealizedPnL ?? 0m;
var rsi = new RelativeStrengthIndex
{
Length = RsiPeriod,
};
var slowStochastic = new StochasticOscillator();
slowStochastic.K.Length = SlowStochasticK;
slowStochastic.D.Length = SlowStochasticD;
var fastStochastic = new StochasticOscillator();
fastStochastic.K.Length = FastStochasticK;
fastStochastic.D.Length = FastStochasticD;
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(rsi, slowStochastic, fastStochastic, ProcessIndicators)
.Start();
var chartArea = CreateChartArea();
if (chartArea != null)
{
DrawCandles(chartArea, subscription);
DrawIndicator(chartArea, rsi);
DrawIndicator(chartArea, slowStochastic);
DrawIndicator(chartArea, fastStochastic);
DrawOwnTrades(chartArea);
}
}
private void ProcessIndicators(ICandleMessage candle, IIndicatorValue rsiValue, IIndicatorValue slowValue, IIndicatorValue fastValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (MaximumRiskPercent > 0m)
{
var unrealizedPnL = PnLManager?.UnrealizedPnL ?? 0m;
if (unrealizedPnL < 0m)
{
var portfolio = Portfolio;
var equity = portfolio?.CurrentValue ?? portfolio?.BeginValue ?? 0m;
if (equity > 0m)
{
var allowedLoss = equity * MaximumRiskPercent;
if (Math.Abs(unrealizedPnL) >= allowedLoss)
{
CloseCurrentPosition();
return;
}
}
}
}
if (rsiValue.IsEmpty || slowValue.IsEmpty || fastValue.IsEmpty)
return;
var rsi = rsiValue.ToDecimal();
var slow = slowValue as StochasticOscillatorValue;
var fast = fastValue as StochasticOscillatorValue;
if (slow == null || fast == null)
return;
if (slow.K is not decimal slowMainValue ||
slow.D is not decimal slowSignalValue ||
fast.K is not decimal fastMainValue ||
fast.D is not decimal fastSignalValue)
{
return;
}
if (!_hasPreviousSlowSignal)
{
_previousSlowSignal = slowSignalValue;
_hasPreviousSlowSignal = true;
return;
}
if (Position == 0m)
{
var momentum = Math.Abs(fastMainValue - fastSignalValue);
if (slowMainValue > slowSignalValue && slowMainValue < BuyStochasticLimit && momentum > StochasticDifferenceThreshold)
{
EnterPosition(Sides.Buy);
}
else if (slowMainValue < slowSignalValue && slowMainValue > SellStochasticLimit && momentum > StochasticDifferenceThreshold)
{
EnterPosition(Sides.Sell);
}
}
else if (Position > 0m)
{
if (rsi > ExitRsiHigh && slowSignalValue < _previousSlowSignal && slowSignalValue > ExitStochasticHigh)
{
ExitPosition(Sides.Buy);
}
}
else if (Position < 0m)
{
if (rsi < ExitRsiLow && slowSignalValue > _previousSlowSignal && slowSignalValue < ExitStochasticLow)
{
ExitPosition(Sides.Sell);
}
}
_previousSlowSignal = slowSignalValue;
}
private void EnterPosition(Sides side)
{
var volume = CalculateOrderVolume();
if (volume <= 0m)
return;
if (side == Sides.Buy)
{
BuyMarket(volume);
}
else
{
SellMarket(volume);
}
}
private void ExitPosition(Sides side)
{
var position = Position;
if (position == 0m)
return;
if (side == Sides.Buy && position > 0m)
{
SellMarket(position);
}
else if (side == Sides.Sell && position < 0m)
{
BuyMarket(Math.Abs(position));
}
}
private void CloseCurrentPosition()
{
var position = Position;
if (position > 0m)
{
SellMarket(position);
}
else if (position < 0m)
{
BuyMarket(Math.Abs(position));
}
}
private decimal CalculateOrderVolume()
{
var volume = BaseVolume;
if (DecreaseFactor > 0m && _consecutiveLosses > 1)
{
var reduction = volume * _consecutiveLosses / DecreaseFactor;
volume -= reduction;
}
if (volume <= 0m)
volume = BaseVolume;
var security = Security;
if (security != null)
{
var step = security.VolumeStep ?? 0m;
if (step <= 0m)
step = 0.1m;
var minVolume = security.MinVolume ?? step;
var maxVolume = security.MaxVolume;
var steps = decimal.Floor(volume / step);
if (steps < 1m)
steps = 1m;
volume = steps * step;
if (volume < minVolume)
volume = minVolume;
if (maxVolume is decimal max && max > 0m && volume > max)
volume = max;
}
return volume;
}
/// <inheritdoc />
protected override void OnOwnTradeReceived(MyTrade trade)
{
base.OnOwnTradeReceived(trade);
if (Position == 0m)
{
var realizedPnL = PnLManager?.RealizedPnL ?? 0m;
var gain = realizedPnL - _lastRealizedPnL;
_lastRealizedPnL = realizedPnL;
if (gain > 0m)
{
_consecutiveLosses = 0;
}
else if (gain < 0m)
{
_consecutiveLosses++;
}
}
}
}
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, Sides
from StockSharp.Algo.Indicators import RelativeStrengthIndex, StochasticOscillator
from StockSharp.Algo.Strategies import Strategy
class altarius_rsi_stochastic_dual_strategy(Strategy):
"""
Strategy converted from AltariusRSIxampnSTOH MQL4 expert advisor.
Combines dual stochastic filters with RSI based exits and dynamic position sizing.
"""
def __init__(self):
super(altarius_rsi_stochastic_dual_strategy, self).__init__()
self._base_volume = self.Param("BaseVolume", 1.0) \
.SetDisplay("Base Volume", "Initial volume before money management rules", "Trading")
self._rsi_period = self.Param("RsiPeriod", 4) \
.SetGreaterThanZero() \
.SetDisplay("RSI Period", "Length of RSI used for exits", "Indicators")
self._slow_stoch_k = self.Param("SlowStochasticK", 8) \
.SetGreaterThanZero() \
.SetDisplay("Slow Stochastic %K", "Smoothing of %K for slow stochastic", "Indicators")
self._slow_stoch_d = self.Param("SlowStochasticD", 8) \
.SetGreaterThanZero() \
.SetDisplay("Slow Stochastic %D", "Smoothing of %D for slow stochastic", "Indicators")
self._fast_stoch_k = self.Param("FastStochasticK", 3) \
.SetGreaterThanZero() \
.SetDisplay("Fast Stochastic %K", "Smoothing of %K for fast stochastic", "Indicators")
self._fast_stoch_d = self.Param("FastStochasticD", 3) \
.SetGreaterThanZero() \
.SetDisplay("Fast Stochastic %D", "Smoothing of %D for fast stochastic", "Indicators")
self._diff_threshold = self.Param("StochasticDifferenceThreshold", 5.0) \
.SetDisplay("Momentum Threshold", "Minimum difference between fast stochastic lines", "Trading")
self._buy_limit = self.Param("BuyStochasticLimit", 50.0) \
.SetDisplay("Buy Stochastic Limit", "Upper bound of slow stochastic for longs", "Trading")
self._sell_limit = self.Param("SellStochasticLimit", 55.0) \
.SetDisplay("Sell Stochastic Limit", "Lower bound of slow stochastic for shorts", "Trading")
self._exit_rsi_high = self.Param("ExitRsiHigh", 60.0) \
.SetDisplay("Exit RSI High", "RSI threshold to exit longs", "Exits")
self._exit_rsi_low = self.Param("ExitRsiLow", 40.0) \
.SetDisplay("Exit RSI Low", "RSI threshold to exit shorts", "Exits")
self._exit_stoch_high = self.Param("ExitStochasticHigh", 70.0) \
.SetDisplay("Exit Stochastic High", "Slow stochastic signal level confirming long exit", "Exits")
self._exit_stoch_low = self.Param("ExitStochasticLow", 30.0) \
.SetDisplay("Exit Stochastic Low", "Slow stochastic signal level confirming short exit", "Exits")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candles used for calculations", "Market Data")
self._prev_slow_signal = 0.0
self._has_prev_slow_signal = False
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, v): self._candle_type.Value = v
def OnReseted(self):
super(altarius_rsi_stochastic_dual_strategy, self).OnReseted()
self._prev_slow_signal = 0.0
self._has_prev_slow_signal = False
def OnStarted2(self, time):
super(altarius_rsi_stochastic_dual_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_period.Value
slow_stoch = StochasticOscillator()
slow_stoch.K.Length = self._slow_stoch_k.Value
slow_stoch.D.Length = self._slow_stoch_d.Value
fast_stoch = StochasticOscillator()
fast_stoch.K.Length = self._fast_stoch_k.Value
fast_stoch.D.Length = self._fast_stoch_d.Value
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(rsi, slow_stoch, fast_stoch, self.ProcessIndicators).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, rsi)
self.DrawOwnTrades(area)
def ProcessIndicators(self, candle, rsi_value, slow_value, fast_value):
if candle.State != CandleStates.Finished:
return
if rsi_value.IsEmpty or slow_value.IsEmpty or fast_value.IsEmpty:
return
rsi = float(rsi_value)
slow_k_raw = slow_value.K if hasattr(slow_value, 'K') else None
slow_d_raw = slow_value.D if hasattr(slow_value, 'D') else None
fast_k_raw = fast_value.K if hasattr(fast_value, 'K') else None
fast_d_raw = fast_value.D if hasattr(fast_value, 'D') else None
if slow_k_raw is None or slow_d_raw is None or fast_k_raw is None or fast_d_raw is None:
return
slow_k = float(slow_k_raw)
slow_d = float(slow_d_raw)
fast_k = float(fast_k_raw)
fast_d = float(fast_d_raw)
if not self._has_prev_slow_signal:
self._prev_slow_signal = slow_d
self._has_prev_slow_signal = True
return
if self.Position == 0:
momentum = abs(fast_k - fast_d)
if slow_k > slow_d and slow_k < self._buy_limit.Value and momentum > self._diff_threshold.Value:
self.BuyMarket(self.Volume)
elif slow_k < slow_d and slow_k > self._sell_limit.Value and momentum > self._diff_threshold.Value:
self.SellMarket(self.Volume)
elif self.Position > 0:
if rsi > self._exit_rsi_high.Value and slow_d < self._prev_slow_signal and slow_d > self._exit_stoch_high.Value:
self.SellMarket(self.Position)
elif self.Position < 0:
if rsi < self._exit_rsi_low.Value and slow_d > self._prev_slow_signal and slow_d < self._exit_stoch_low.Value:
self.BuyMarket(Math.Abs(self.Position))
self._prev_slow_signal = slow_d
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return altarius_rsi_stochastic_dual_strategy()