Diese Strategie wendet den True Strength Index (TSI) auf Kerzendaten an und vergleicht ihn mit einer exponentiellen gleitenden Durchschnittssignallinie. Eine Long-Position wird eröffnet, wenn der TSI die Signallinie von unten nach oben kreuzt, während eine Short-Position eröffnet wird, wenn er darunter kreuzt.
Parameter
Candle Type – Zeitrahmen der für Berechnungen verwendeten Kerzen.
Short Length – schnelle Glättungsperiode des TSI.
Long Length – langsame Glättungsperiode des TSI.
Signal Length – Periode des EMA, der als Signallinie verwendet wird.
Logik
Kerzen des gewählten Zeitrahmens abonnieren.
TSI für jede abgeschlossene Kerze berechnen.
TSI durch einen EMA verarbeiten, um eine Signallinie zu erhalten.
Wenn der TSI die Signallinie von unten nach oben kreuzt, Long eingehen (dabei eventuell bestehende Short-Position schließen).
Wenn der TSI die Signallinie von oben nach unten kreuzt, Short eingehen (dabei eventuell bestehende Long-Position schließen).
Die Strategie ist eine Anpassung des MQL-Beispiels "exp_ergodic_ticks_volume_indicator.mq5" und verwendet ausschließlich integrierte StockSharp-Indikatoren.
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 True Strength Index crossovers of the signal line.
/// </summary>
public class ErgodicTicksVolumeIndicatorStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _firstLength;
private readonly StrategyParam<int> _secondLength;
private readonly StrategyParam<int> _signalLength;
private decimal _prevTsi;
private decimal _prevSignal;
private bool _prevReady;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FirstLength { get => _firstLength.Value; set => _firstLength.Value = value; }
public int SecondLength { get => _secondLength.Value; set => _secondLength.Value = value; }
public int SignalLength { get => _signalLength.Value; set => _signalLength.Value = value; }
public ErgodicTicksVolumeIndicatorStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
_firstLength = Param(nameof(FirstLength), 25)
.SetGreaterThanZero()
.SetDisplay("First Length", "First smoothing length", "Indicator");
_secondLength = Param(nameof(SecondLength), 13)
.SetGreaterThanZero()
.SetDisplay("Second Length", "Second smoothing length", "Indicator");
_signalLength = Param(nameof(SignalLength), 7)
.SetGreaterThanZero()
.SetDisplay("Signal Length", "Signal line length", "Indicator");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevTsi = default;
_prevSignal = default;
_prevReady = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var tsi = new TrueStrengthIndex
{
FirstLength = FirstLength,
SecondLength = SecondLength,
SignalLength = SignalLength
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(tsi, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
var tsiVal = (ITrueStrengthIndexValue)value;
if (tsiVal.Tsi is not decimal tsi || tsiVal.Signal is not decimal signal)
return;
if (!_prevReady)
{
_prevTsi = tsi;
_prevSignal = signal;
_prevReady = true;
return;
}
// TSI crosses above signal - buy
if (_prevTsi <= _prevSignal && tsi > signal && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// TSI crosses below signal - sell
else if (_prevTsi >= _prevSignal && tsi < signal && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevTsi = tsi;
_prevSignal = signal;
}
}
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
from StockSharp.Algo.Indicators import TrueStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class ergodic_ticks_volume_indicator_strategy(Strategy):
def __init__(self):
super(ergodic_ticks_volume_indicator_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._first_length = self.Param("FirstLength", 25) \
.SetDisplay("First Length", "First smoothing length", "Indicator")
self._second_length = self.Param("SecondLength", 13) \
.SetDisplay("Second Length", "Second smoothing length", "Indicator")
self._signal_length = self.Param("SignalLength", 7) \
.SetDisplay("Signal Length", "Signal line length", "Indicator")
self._prev_tsi = 0.0
self._prev_signal = 0.0
self._prev_ready = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def FirstLength(self):
return self._first_length.Value
@FirstLength.setter
def FirstLength(self, value):
self._first_length.Value = value
@property
def SecondLength(self):
return self._second_length.Value
@SecondLength.setter
def SecondLength(self, value):
self._second_length.Value = value
@property
def SignalLength(self):
return self._signal_length.Value
@SignalLength.setter
def SignalLength(self, value):
self._signal_length.Value = value
def OnStarted2(self, time):
super(ergodic_ticks_volume_indicator_strategy, self).OnStarted2(time)
tsi = TrueStrengthIndex()
tsi.FirstLength = self.FirstLength
tsi.SecondLength = self.SecondLength
tsi.SignalLength = self.SignalLength
self.SubscribeCandles(self.CandleType) \
.BindEx(tsi, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, value):
if candle.State != CandleStates.Finished:
return
tsi_val = value.Tsi
signal_val = value.Signal
if tsi_val is None or signal_val is None:
return
tsi = float(tsi_val)
signal = float(signal_val)
if not self._prev_ready:
self._prev_tsi = tsi
self._prev_signal = signal
self._prev_ready = True
return
if self._prev_tsi <= self._prev_signal and tsi > signal and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_tsi >= self._prev_signal and tsi < signal and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_tsi = tsi
self._prev_signal = signal
def OnReseted(self):
super(ergodic_ticks_volume_indicator_strategy, self).OnReseted()
self._prev_tsi = 0.0
self._prev_signal = 0.0
self._prev_ready = False
def CreateClone(self):
return ergodic_ticks_volume_indicator_strategy()