Стратегия TRIX Crossover
Стратегия использует два индикатора TRIX с разными периодами для определения возможных разворотных точек. Длинная позиция открывается, когда быстрый TRIX формирует локальное дно и медленный TRIX растёт. Короткая позиция открывается, когда быстрый TRIX формирует локальную вершину и медленный TRIX падает.
Параметры
- Fast TRIX Period – период быстрого индикатора TRIX.
- Slow TRIX Period – период медленного индикатора TRIX.
- Take Profit – целевая прибыль в абсолютных ценовых единицах.
- Stop Loss – максимально допустимый убыток в абсолютных ценовых единицах.
- Candle Type – тип или таймфрейм используемых свечей.
Логика торговли
- Подписка на выбранный тип свечей.
- Расчёт значений быстрого и медленного TRIX на каждой завершённой свече.
- Вход в длинную позицию при условии, что текущее значение быстрого TRIX выше предыдущего, предыдущее ниже значения до него, а медленный TRIX растёт.
- Вход в короткую позицию при обратном условии.
- Одновременно удерживается только одна позиция.
- Стоп‑лосс и тейк‑профит применяются автоматически.
Примечания
Стратегия является адаптацией скрипта MQL5 и демонстрирует работу с индикатором TRIX в рамках StockSharp.
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>
/// Strategy based on fast and slow TRIX indicator signals.
/// A long position opens when the fast TRIX forms a local bottom and the slow TRIX is rising.
/// A short position opens when the fast TRIX forms a local top and the slow TRIX is falling.
/// </summary>
public class TrixCrossoverStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<decimal> _minTrix;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<DataType> _candleType;
// Store previous TRIX values for decision making
private decimal _fastTrixPrev1;
private decimal _fastTrixPrev2;
private decimal _slowTrixPrev;
private decimal _prevFastTema;
private decimal _prevSlowTema;
private TripleExponentialMovingAverage _fastTema = null!;
private TripleExponentialMovingAverage _slowTema = null!;
/// <summary>
/// Fast TRIX period.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow TRIX period.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Minimum TRIX value required for a signal.
/// </summary>
public decimal MinTrix
{
get => _minTrix.Value;
set => _minTrix.Value = value;
}
/// <summary>
/// Take profit size in absolute price units.
/// </summary>
public decimal TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
/// <summary>
/// Stop loss size in absolute price units.
/// </summary>
public decimal StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes <see cref="TrixCrossoverStrategy"/>.
/// </summary>
public TrixCrossoverStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 9)
.SetGreaterThanZero()
.SetDisplay("Fast TRIX Period", "Period for the fast TRIX indicator", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 21)
.SetGreaterThanZero()
.SetDisplay("Slow TRIX Period", "Period for the slow TRIX indicator", "Indicators");
_minTrix = Param(nameof(MinTrix), 0.0005m)
.SetGreaterThanZero()
.SetDisplay("Min TRIX", "Minimum TRIX magnitude for signals", "Indicators");
_takeProfit = Param(nameof(TakeProfit), 1500m)
.SetNotNegative()
.SetDisplay("Take Profit", "Take profit in absolute price units", "Risk Management");
_stopLoss = Param(nameof(StopLoss), 500m)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop loss in absolute price units", "Risk Management");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fastTrixPrev1 = 0m;
_fastTrixPrev2 = 0m;
_slowTrixPrev = 0m;
_prevFastTema = 0m;
_prevSlowTema = 0m;
_fastTema = null!;
_slowTema = null!;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fastTrixPrev1 = 0m;
_fastTrixPrev2 = 0m;
_slowTrixPrev = 0m;
_prevFastTema = 0m;
_prevSlowTema = 0m;
_fastTema = new TripleExponentialMovingAverage { Length = FastPeriod };
_slowTema = new TripleExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_fastTema, _slowTema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _fastTema);
DrawIndicator(area, _slowTema);
DrawOwnTrades(area);
}
StartProtection(new Unit(TakeProfit, UnitTypes.Absolute), new Unit(StopLoss, UnitTypes.Absolute));
}
private void ProcessCandle(ICandleMessage candle, decimal fastTemaValue, decimal slowTemaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevFastTema == 0m || _prevSlowTema == 0m)
{
_prevFastTema = fastTemaValue;
_prevSlowTema = slowTemaValue;
return;
}
var fastTrix = (fastTemaValue - _prevFastTema) / _prevFastTema;
var slowTrix = (slowTemaValue - _prevSlowTema) / _prevSlowTema;
_prevFastTema = fastTemaValue;
_prevSlowTema = slowTemaValue;
var prevFastTrix = _fastTrixPrev1;
_fastTrixPrev2 = _fastTrixPrev1;
_fastTrixPrev1 = fastTrix;
var slowTrixPrev = _slowTrixPrev;
_slowTrixPrev = slowTrix;
if (_fastTrixPrev2 == 0m || slowTrixPrev == 0m)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var crossUp = prevFastTrix <= 0 && fastTrix > 0;
var crossDown = prevFastTrix >= 0 && fastTrix < 0;
if (crossUp && slowTrix > MinTrix && Position <= 0)
BuyMarket();
else if (crossDown && slowTrix < -MinTrix && Position >= 0)
SellMarket();
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import TripleExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class trix_crossover_strategy(Strategy):
def __init__(self):
super(trix_crossover_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 9) \
.SetDisplay("Fast TRIX Period", "Period for the fast TRIX indicator", "Indicators")
self._slow_period = self.Param("SlowPeriod", 21) \
.SetDisplay("Slow TRIX Period", "Period for the slow TRIX indicator", "Indicators")
self._min_trix = self.Param("MinTrix", 0.0005) \
.SetDisplay("Min TRIX", "Minimum TRIX magnitude for signals", "Indicators")
self._take_profit = self.Param("TakeProfit", 1500.0) \
.SetDisplay("Take Profit", "Take profit in absolute price units", "Risk Management")
self._stop_loss = self.Param("StopLoss", 500.0) \
.SetDisplay("Stop Loss", "Stop loss in absolute price units", "Risk Management")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._fast_trix_prev1 = 0.0
self._fast_trix_prev2 = 0.0
self._slow_trix_prev = 0.0
self._prev_fast_tema = 0.0
self._prev_slow_tema = 0.0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def min_trix(self):
return self._min_trix.Value
@property
def take_profit(self):
return self._take_profit.Value
@property
def stop_loss(self):
return self._stop_loss.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(trix_crossover_strategy, self).OnReseted()
self._fast_trix_prev1 = 0.0
self._fast_trix_prev2 = 0.0
self._slow_trix_prev = 0.0
self._prev_fast_tema = 0.0
self._prev_slow_tema = 0.0
def OnStarted2(self, time):
super(trix_crossover_strategy, self).OnStarted2(time)
self._fast_trix_prev1 = 0.0
self._fast_trix_prev2 = 0.0
self._slow_trix_prev = 0.0
self._prev_fast_tema = 0.0
self._prev_slow_tema = 0.0
fast_tema = TripleExponentialMovingAverage()
fast_tema.Length = int(self.fast_period)
slow_tema = TripleExponentialMovingAverage()
slow_tema.Length = int(self.slow_period)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_tema, slow_tema, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_tema)
self.DrawIndicator(area, slow_tema)
self.DrawOwnTrades(area)
self.StartProtection(
takeProfit=Unit(float(self.take_profit), UnitTypes.Absolute),
stopLoss=Unit(float(self.stop_loss), UnitTypes.Absolute))
def process_candle(self, candle, fast_tema_value, slow_tema_value):
if candle.State != CandleStates.Finished:
return
fast_tema_value = float(fast_tema_value)
slow_tema_value = float(slow_tema_value)
if self._prev_fast_tema == 0.0 or self._prev_slow_tema == 0.0:
self._prev_fast_tema = fast_tema_value
self._prev_slow_tema = slow_tema_value
return
fast_trix = (fast_tema_value - self._prev_fast_tema) / self._prev_fast_tema if self._prev_fast_tema != 0 else 0.0
slow_trix = (slow_tema_value - self._prev_slow_tema) / self._prev_slow_tema if self._prev_slow_tema != 0 else 0.0
self._prev_fast_tema = fast_tema_value
self._prev_slow_tema = slow_tema_value
prev_fast_trix = self._fast_trix_prev1
self._fast_trix_prev2 = self._fast_trix_prev1
self._fast_trix_prev1 = fast_trix
slow_trix_prev = self._slow_trix_prev
self._slow_trix_prev = slow_trix
if self._fast_trix_prev2 == 0.0 or slow_trix_prev == 0.0:
return
mt = float(self.min_trix)
cross_up = prev_fast_trix <= 0 and fast_trix > 0
cross_down = prev_fast_trix >= 0 and fast_trix < 0
if cross_up and slow_trix > mt and self.Position <= 0:
self.BuyMarket()
elif cross_down and slow_trix < -mt and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return trix_crossover_strategy()