Стратегия EA Trix
Общее описание
EA Trix воспроизводит логику советника MetaTrader 5, который использует индикатор TRIX ARROWS вместе с базовыми инструментами управления рисками. Стратегия отслеживает пересечения тройной экспоненциальной средней (TRIX) и её сигнальной линии, после чего открывает позицию. В зависимости от настроек можно выполнять сделки сразу по закрытию бара с сигналом либо переносить их на следующую свечу, как это предусмотрено в оригинальном советнике («торговля на закрытии бара»).
Торговая логика
- Формируются два тройных экспоненциальных сглаживания:
- TRIX рассчитывается как три последовательно применённых EMA длиной TRIX EMA к цене закрытия с последующим вычислением изменения третьей EMA за один бар.
- Сигнальная линия строится аналогично, но с использованием периода Signal EMA.
- Определяются направления по пересечениям:
- Сигнальная линия пересекает TRIX снизу вверх — подготавливается вход в покупку.
- Сигнальная линия пересекает TRIX сверху вниз — подготавливается вход в продажу.
- В зависимости от параметра Trade On Close стратегия:
- Либо исполняет ордер по цене закрытия свечи с сигналом;
- Либо ставит сигнал в очередь и исполняет его по цене открытия следующего бара.
- Перед открытием новой позиции алгоритм закрывает противоположную позицию, поэтому в рынке всегда находится только одно чистое направление.
Управление позицией
- Stop Loss — фиксированное расстояние от цены входа. Значение
0отключает защитный стоп. - Take Profit — целевая прибыль. Значение
0отключает тейк-профит. - Break Even — при достижении указанного расстояния в прибыль стоп переносится в точку входа.
- Trailing Stop — после прохождения ценой заданного расстояния стоп следует за ценой с шагом не менее Trailing Step.
- Контроль защитных условий выполняется на каждой закрытой свече по экстремумам (High/Low). При срабатывании условия позиция закрывается рыночной заявкой.
Параметры
| Параметр | Описание |
|---|---|
CandleType |
Тип/таймфрейм свечей, с которыми работает стратегия. |
Volume |
Объём новой позиции. При наличии противоположной позиции её объём автоматически учитывается для реверса. |
EmaPeriod |
Длина EMA для вычисления кривой TRIX. |
SignalPeriod |
Длина EMA для сигнальной кривой. |
TradeOnCloseBar |
true — исполнение на следующем баре; false — немедленное исполнение на текущей свече. |
StopLoss |
Расстояние защитного стопа от цены входа. 0 — отключено. |
TakeProfit |
Расстояние до тейк-профита. 0 — отключено. |
TrailingStop |
Дистанция активации трейлинг-стопа. 0 — отключено. |
TrailingStep |
Минимальный шаг обновления трейлинг-стопа. |
BreakEven |
Дистанция для переноса стопа в безубыток. 0 — отключено. |
Практические рекомендации
- Стратегия подписывается только на один поток свечей и обрабатывает исключительно закрытые бары, что соответствует требованиям высокоуровневого API StockSharp.
- Значения стопов и тейк-профита задаются в ценовых единицах. Подбирайте их с учётом шага цены выбранного инструмента.
- При тестировании ордера исполняются по цене закрытия (или по цене открытия следующей свечи для отложенных сигналов), так как используются рыночные заявки.
Особенности конверсии
- В оригинальном коде MT5 задействован внешний индикатор TRIX ARROWS (код 19056). В версии StockSharp его расчёт выполнен через
стандартные
ExponentialMovingAverageи вычисление изменения за бар без обращения к индикаторным буферам. - Биржевые стопы/тейки, использовавшиеся в MT5, заменены контролем экстремумов свечей и последующей отправкой рыночных заявок.
- Система оповещений, звуков и брокерские параметры не перенесены, поскольку они не влияют на основную торговую логику.
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>
/// TRIX cross strategy based on the "TRIX ARROWS" expert advisor.
/// Opens a long position when the signal line crosses above TRIX and a short position on the opposite crossover.
/// Includes optional stop loss, take profit, break-even and trailing stop logic.
/// </summary>
public class EaTrixStrategy : Strategy
{
private enum SignalDirections
{
Buy,
Sell,
}
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _trailingStop;
private readonly StrategyParam<decimal> _trailingStep;
private readonly StrategyParam<decimal> _breakEven;
private readonly StrategyParam<bool> _tradeOnCloseBar;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _signalPeriod;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _trixEma1 = null!;
private ExponentialMovingAverage _trixEma2 = null!;
private ExponentialMovingAverage _trixEma3 = null!;
private ExponentialMovingAverage _signalEma1 = null!;
private ExponentialMovingAverage _signalEma2 = null!;
private ExponentialMovingAverage _signalEma3 = null!;
private decimal? _prevThirdTrix;
private decimal? _prevThirdSignal;
private decimal? _prevTrix;
private decimal? _prevSignal;
private SignalDirections? _pendingSignal;
private decimal? _entryPrice;
private decimal? _stopPrice;
private decimal? _takePrice;
/// <summary>
/// Stop loss distance in price units. Set to zero to disable.
/// </summary>
public decimal StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Take profit distance in price units. Set to zero to disable.
/// </summary>
public decimal TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
/// <summary>
/// Trailing stop distance in price units. Set to zero to disable.
/// </summary>
public decimal TrailingStop
{
get => _trailingStop.Value;
set => _trailingStop.Value = value;
}
/// <summary>
/// Minimal step for trailing stop updates.
/// </summary>
public decimal TrailingStep
{
get => _trailingStep.Value;
set => _trailingStep.Value = value;
}
/// <summary>
/// Break-even trigger distance. The stop is moved to the entry price when the distance is reached.
/// </summary>
public decimal BreakEven
{
get => _breakEven.Value;
set => _breakEven.Value = value;
}
/// <summary>
/// Trade using signals confirmed on the previous closed bar.
/// When disabled the strategy reacts immediately on the bar that generated the crossover.
/// </summary>
public bool TradeOnCloseBar
{
get => _tradeOnCloseBar.Value;
set => _tradeOnCloseBar.Value = value;
}
/// <summary>
/// EMA length used to build the TRIX series.
/// </summary>
public int EmaPeriod
{
get => _emaPeriod.Value;
set => _emaPeriod.Value = value;
}
/// <summary>
/// EMA length used to build the signal series.
/// </summary>
public int SignalPeriod
{
get => _signalPeriod.Value;
set => _signalPeriod.Value = value;
}
/// <summary>
/// Candle type processed by the strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="EaTrixStrategy"/>.
/// </summary>
public EaTrixStrategy()
{
_stopLoss = Param(nameof(StopLoss), 50m)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop loss distance", "Risk")
;
_takeProfit = Param(nameof(TakeProfit), 150m)
.SetNotNegative()
.SetDisplay("Take Profit", "Take profit distance", "Risk")
;
_trailingStop = Param(nameof(TrailingStop), 10m)
.SetNotNegative()
.SetDisplay("Trailing Stop", "Trailing stop distance", "Risk")
;
_trailingStep = Param(nameof(TrailingStep), 1m)
.SetNotNegative()
.SetDisplay("Trailing Step", "Minimal trailing step", "Risk")
;
_breakEven = Param(nameof(BreakEven), 2m)
.SetNotNegative()
.SetDisplay("Break Even", "Break-even trigger distance", "Risk")
;
_tradeOnCloseBar = Param(nameof(TradeOnCloseBar), true)
.SetDisplay("Trade On Close", "Confirm signals on closed bars", "General");
_emaPeriod = Param(nameof(EmaPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("TRIX EMA", "TRIX EMA length", "Indicators")
;
_signalPeriod = Param(nameof(SignalPeriod), 8)
.SetGreaterThanZero()
.SetDisplay("Signal EMA", "Signal EMA length", "Indicators")
;
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for calculations", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevThirdTrix = null;
_prevThirdSignal = null;
_prevTrix = null;
_prevSignal = null;
_pendingSignal = null;
ClearPositionState();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// no protection
_trixEma1 = new ExponentialMovingAverage { Length = EmaPeriod };
_trixEma2 = new ExponentialMovingAverage { Length = EmaPeriod };
_trixEma3 = new ExponentialMovingAverage { Length = EmaPeriod };
_signalEma1 = new ExponentialMovingAverage { Length = SignalPeriod };
_signalEma2 = new ExponentialMovingAverage { Length = SignalPeriod };
_signalEma3 = new ExponentialMovingAverage { Length = SignalPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
HandlePendingSignal(candle);
ManageActivePosition(candle);
if (!TryCalculateIndicators(candle, out var trix, out var signal))
return;
if (_prevTrix is null || _prevSignal is null)
{
_prevTrix = trix;
_prevSignal = signal;
return;
}
if (!_trixEma3.IsFormed || !_signalEma3.IsFormed)
{
_prevTrix = trix;
_prevSignal = signal;
return;
}
var crossUp = _prevSignal < _prevTrix && signal > trix;
var crossDown = _prevSignal > _prevTrix && signal < trix;
if (crossUp)
{
if (TradeOnCloseBar)
_pendingSignal = SignalDirections.Buy;
else
ExecuteSignal(SignalDirections.Buy, candle, candle.ClosePrice);
}
else if (crossDown)
{
if (TradeOnCloseBar)
_pendingSignal = SignalDirections.Sell;
else
ExecuteSignal(SignalDirections.Sell, candle, candle.ClosePrice);
}
_prevTrix = trix;
_prevSignal = signal;
}
private void HandlePendingSignal(ICandleMessage candle)
{
if (_pendingSignal is null)
return;
if (!_trixEma3.IsFormed || !_signalEma3.IsFormed)
return;
ExecuteSignal(_pendingSignal.Value, candle, candle.OpenPrice);
_pendingSignal = null;
}
private void ExecuteSignal(SignalDirections direction, ICandleMessage candle, decimal fillPrice)
{
if (Volume <= 0m)
return;
var volume = Volume;
switch (direction)
{
case SignalDirections.Buy:
if (Position < 0m)
volume += Math.Abs(Position);
if (volume > 0m)
BuyMarket();
_entryPrice = fillPrice;
_stopPrice = StopLoss > 0m ? fillPrice - StopLoss : null;
_takePrice = TakeProfit > 0m ? fillPrice + TakeProfit : null;
break;
case SignalDirections.Sell:
if (Position > 0m)
volume += Position;
if (volume > 0m)
SellMarket();
_entryPrice = fillPrice;
_stopPrice = StopLoss > 0m ? fillPrice + StopLoss : null;
_takePrice = TakeProfit > 0m ? fillPrice - TakeProfit : null;
break;
}
}
private void ManageActivePosition(ICandleMessage candle)
{
if (Position > 0m && _entryPrice is decimal longEntry)
{
if (BreakEven > 0m && candle.HighPrice - longEntry >= BreakEven && (_stopPrice is null || _stopPrice < longEntry))
_stopPrice = longEntry;
if (TrailingStop > 0m)
{
var move = candle.HighPrice - longEntry;
if (move >= TrailingStop)
{
var newStop = candle.HighPrice - TrailingStop;
if (_stopPrice is null || newStop - _stopPrice >= TrailingStep)
_stopPrice = newStop;
}
}
if (_takePrice is decimal tp && candle.HighPrice >= tp)
{
SellMarket();
ClearPositionState();
return;
}
if (_stopPrice is decimal sl && candle.LowPrice <= sl)
{
SellMarket();
ClearPositionState();
}
}
else if (Position < 0m && _entryPrice is decimal shortEntry)
{
if (BreakEven > 0m && shortEntry - candle.LowPrice >= BreakEven && (_stopPrice is null || _stopPrice > shortEntry))
_stopPrice = shortEntry;
if (TrailingStop > 0m)
{
var move = shortEntry - candle.LowPrice;
if (move >= TrailingStop)
{
var newStop = candle.LowPrice + TrailingStop;
if (_stopPrice is null || _stopPrice - newStop >= TrailingStep)
_stopPrice = newStop;
}
}
if (_takePrice is decimal tp && candle.LowPrice <= tp)
{
BuyMarket();
ClearPositionState();
return;
}
if (_stopPrice is decimal sl && candle.HighPrice >= sl)
{
BuyMarket();
ClearPositionState();
}
}
else if (Position == 0m)
{
ClearPositionState();
}
}
private bool TryCalculateIndicators(ICandleMessage candle, out decimal trix, out decimal signal)
{
trix = 0m;
signal = 0m;
var ema1 = _trixEma1.Process(new DecimalIndicatorValue(_trixEma1, candle.ClosePrice, candle.OpenTime) { IsFinal = true }).ToDecimal();
var ema2 = _trixEma2.Process(new DecimalIndicatorValue(_trixEma2, ema1, candle.OpenTime) { IsFinal = true }).ToDecimal();
var ema3 = _trixEma3.Process(new DecimalIndicatorValue(_trixEma3, ema2, candle.OpenTime) { IsFinal = true }).ToDecimal();
if (_prevThirdTrix is null)
{
_prevThirdTrix = ema3;
return false;
}
trix = _prevThirdTrix != 0m ? (ema3 - _prevThirdTrix.Value) / _prevThirdTrix.Value : 0m;
_prevThirdTrix = ema3;
var signal1 = _signalEma1.Process(new DecimalIndicatorValue(_signalEma1, candle.ClosePrice, candle.OpenTime) { IsFinal = true }).ToDecimal();
var signal2 = _signalEma2.Process(new DecimalIndicatorValue(_signalEma2, signal1, candle.OpenTime) { IsFinal = true }).ToDecimal();
var signalBase = _signalEma3.Process(new DecimalIndicatorValue(_signalEma3, signal2, candle.OpenTime) { IsFinal = true }).ToDecimal();
if (_prevThirdSignal is null)
{
_prevThirdSignal = signalBase;
return false;
}
signal = _prevThirdSignal != 0m ? (signalBase - _prevThirdSignal.Value) / _prevThirdSignal.Value : 0m;
_prevThirdSignal = signalBase;
return true;
}
private void ClearPositionState()
{
_entryPrice = null;
_stopPrice = null;
_takePrice = null;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from indicator_extensions import *
class ea_trix_strategy(Strategy):
"""TRIX cross strategy: signal line crosses above/below TRIX with SL/TP, break-even and trailing."""
# Signal directions
_BUY = 1
_SELL = -1
def __init__(self):
super(ea_trix_strategy, self).__init__()
self._stop_loss = self.Param("StopLoss", 50.0) \
.SetDisplay("Stop Loss", "Stop loss distance", "Risk")
self._take_profit = self.Param("TakeProfit", 150.0) \
.SetDisplay("Take Profit", "Take profit distance", "Risk")
self._trailing_stop = self.Param("TrailingStop", 10.0) \
.SetDisplay("Trailing Stop", "Trailing stop distance", "Risk")
self._trailing_step = self.Param("TrailingStep", 1.0) \
.SetDisplay("Trailing Step", "Minimal trailing step", "Risk")
self._break_even = self.Param("BreakEven", 2.0) \
.SetDisplay("Break Even", "Break-even trigger distance", "Risk")
self._trade_on_close_bar = self.Param("TradeOnCloseBar", True) \
.SetDisplay("Trade On Close", "Confirm signals on closed bars", "General")
self._ema_period = self.Param("EmaPeriod", 14) \
.SetGreaterThanZero() \
.SetDisplay("TRIX EMA", "TRIX EMA length", "Indicators")
self._signal_period = self.Param("SignalPeriod", 8) \
.SetGreaterThanZero() \
.SetDisplay("Signal EMA", "Signal EMA length", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for calculations", "General")
self._prev_third_trix = None
self._prev_third_signal = None
self._prev_trix = None
self._prev_signal = None
self._pending_signal = None
self._entry_price = None
self._stop_price = None
self._take_price = None
@property
def StopLoss(self):
return float(self._stop_loss.Value)
@property
def TakeProfit(self):
return float(self._take_profit.Value)
@property
def TrailingStop(self):
return float(self._trailing_stop.Value)
@property
def TrailingStep(self):
return float(self._trailing_step.Value)
@property
def BreakEven(self):
return float(self._break_even.Value)
@property
def TradeOnCloseBar(self):
return self._trade_on_close_bar.Value
@property
def EmaPeriod(self):
return int(self._ema_period.Value)
@property
def SignalPeriod(self):
return int(self._signal_period.Value)
@property
def CandleType(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(ea_trix_strategy, self).OnStarted2(time)
self._prev_third_trix = None
self._prev_third_signal = None
self._prev_trix = None
self._prev_signal = None
self._pending_signal = None
self._clear_position_state()
self._trix_ema1 = ExponentialMovingAverage()
self._trix_ema1.Length = self.EmaPeriod
self._trix_ema2 = ExponentialMovingAverage()
self._trix_ema2.Length = self.EmaPeriod
self._trix_ema3 = ExponentialMovingAverage()
self._trix_ema3.Length = self.EmaPeriod
self._signal_ema1 = ExponentialMovingAverage()
self._signal_ema1.Length = self.SignalPeriod
self._signal_ema2 = ExponentialMovingAverage()
self._signal_ema2.Length = self.SignalPeriod
self._signal_ema3 = ExponentialMovingAverage()
self._signal_ema3.Length = self.SignalPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
self._handle_pending_signal(candle)
self._manage_active_position(candle)
result = self._try_calculate_indicators(candle)
if result is None:
return
trix, signal = result
if self._prev_trix is None or self._prev_signal is None:
self._prev_trix = trix
self._prev_signal = signal
return
if not self._trix_ema3.IsFormed or not self._signal_ema3.IsFormed:
self._prev_trix = trix
self._prev_signal = signal
return
cross_up = self._prev_signal < self._prev_trix and signal > trix
cross_down = self._prev_signal > self._prev_trix and signal < trix
if cross_up:
if self.TradeOnCloseBar:
self._pending_signal = self._BUY
else:
self._execute_signal(self._BUY, candle, float(candle.ClosePrice))
elif cross_down:
if self.TradeOnCloseBar:
self._pending_signal = self._SELL
else:
self._execute_signal(self._SELL, candle, float(candle.ClosePrice))
self._prev_trix = trix
self._prev_signal = signal
def _handle_pending_signal(self, candle):
if self._pending_signal is None:
return
if not self._trix_ema3.IsFormed or not self._signal_ema3.IsFormed:
return
self._execute_signal(self._pending_signal, candle, float(candle.OpenPrice))
self._pending_signal = None
def _execute_signal(self, direction, candle, fill_price):
if direction == self._BUY:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = fill_price
self._stop_price = fill_price - self.StopLoss if self.StopLoss > 0 else None
self._take_price = fill_price + self.TakeProfit if self.TakeProfit > 0 else None
elif direction == self._SELL:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = fill_price
self._stop_price = fill_price + self.StopLoss if self.StopLoss > 0 else None
self._take_price = fill_price - self.TakeProfit if self.TakeProfit > 0 else None
def _manage_active_position(self, candle):
h = float(candle.HighPrice)
lo = float(candle.LowPrice)
if self.Position > 0 and self._entry_price is not None:
long_entry = self._entry_price
# Break-even
if self.BreakEven > 0 and h - long_entry >= self.BreakEven:
if self._stop_price is None or self._stop_price < long_entry:
self._stop_price = long_entry
# Trailing stop
if self.TrailingStop > 0:
move = h - long_entry
if move >= self.TrailingStop:
new_stop = h - self.TrailingStop
if self._stop_price is None or new_stop - self._stop_price >= self.TrailingStep:
self._stop_price = new_stop
# Take profit
if self._take_price is not None and h >= self._take_price:
self.SellMarket()
self._clear_position_state()
return
# Stop loss
if self._stop_price is not None and lo <= self._stop_price:
self.SellMarket()
self._clear_position_state()
elif self.Position < 0 and self._entry_price is not None:
short_entry = self._entry_price
# Break-even
if self.BreakEven > 0 and short_entry - lo >= self.BreakEven:
if self._stop_price is None or self._stop_price > short_entry:
self._stop_price = short_entry
# Trailing stop
if self.TrailingStop > 0:
move = short_entry - lo
if move >= self.TrailingStop:
new_stop = lo + self.TrailingStop
if self._stop_price is None or self._stop_price - new_stop >= self.TrailingStep:
self._stop_price = new_stop
# Take profit
if self._take_price is not None and lo <= self._take_price:
self.BuyMarket()
self._clear_position_state()
return
# Stop loss
if self._stop_price is not None and h >= self._stop_price:
self.BuyMarket()
self._clear_position_state()
elif self.Position == 0:
self._clear_position_state()
def _make_div(self, ind, val, t):
return float(process_float(ind, Decimal(val), t, True).Value)
def _try_calculate_indicators(self, candle):
close = float(candle.ClosePrice)
t = candle.ServerTime
ema1_val = self._make_div(self._trix_ema1, close, t)
ema2_val = self._make_div(self._trix_ema2, ema1_val, t)
ema3_val = self._make_div(self._trix_ema3, ema2_val, t)
if self._prev_third_trix is None:
self._prev_third_trix = ema3_val
return None
trix = (ema3_val - self._prev_third_trix) / self._prev_third_trix if self._prev_third_trix != 0 else 0.0
self._prev_third_trix = ema3_val
sig1_val = self._make_div(self._signal_ema1, close, t)
sig2_val = self._make_div(self._signal_ema2, sig1_val, t)
sig_base = self._make_div(self._signal_ema3, sig2_val, t)
if self._prev_third_signal is None:
self._prev_third_signal = sig_base
return None
signal = (sig_base - self._prev_third_signal) / self._prev_third_signal if self._prev_third_signal != 0 else 0.0
self._prev_third_signal = sig_base
return (trix, signal)
def _clear_position_state(self):
self._entry_price = None
self._stop_price = None
self._take_price = None
def OnReseted(self):
super(ea_trix_strategy, self).OnReseted()
self._prev_third_trix = None
self._prev_third_signal = None
self._prev_trix = None
self._prev_signal = None
self._pending_signal = None
self._clear_position_state()
def CreateClone(self):
return ea_trix_strategy()