Fisher Transform X2-Strategie
Diese Strategie verwendet den Fisher Transform-Indikator auf zwei verschiedenen Zeitrahmen. Der höhere Zeitrahmen definiert den Gesamttrend, während der niedrigere Zeitrahmen Einstiege generiert, wenn Fisher seinen vorherigen Wert gegen diesen Trend kreuzt. Optionale Parameter erlauben das Schließen von Positionen bei Trendwechsel oder bei Kreuzsignalen.
Details
- Einstiegskriterien:
- Long:
Trend Fisher steigt&&Signal Fisher kreuzt seinen vorherigen Wert nach unten - Short:
Trend Fisher fällt&&Signal Fisher kreuzt seinen vorherigen Wert nach oben
- Long:
- Long/Short: Beide
- Ausstiegskriterien:
- Optionales Schließen bei Trendumkehr
- Optionales Schließen bei entgegengesetztem Fisher-Kreuz auf dem Signal-Zeitrahmen
- Stops: Take Profit und Stop Loss in Punkten
- Standardwerte:
Trend Length= 10Signal Length= 10Trend Timeframe= 6 StundenSignal Timeframe= 30 MinutenTake Profit= 2000 PunkteStop Loss= 1000 Punkte
- Filter:
- Kategorie: Trendfolge
- Richtung: Beide
- Indikatoren: Fisher Transform
- Stops: Ja
- Komplexität: Mittel
- Zeitrahmen: Multi-Zeitrahmen
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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>
/// Fisher Transform strategy using two Fisher indicators (trend + signal).
/// Trend Fisher defines direction; Signal Fisher generates entries.
/// Both use same timeframe but different lengths.
/// </summary>
public class FisherTransformX2Strategy : Strategy
{
private readonly StrategyParam<int> _trendLength;
private readonly StrategyParam<int> _signalLength;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<DataType> _candleType;
private EhlersFisherTransform _trendFisher;
private EhlersFisherTransform _signalFisher;
private decimal _prevTrend;
private decimal _prevSignal;
private decimal _prevPrevSignal;
private int _trendDirection;
private int _count;
public int TrendLength { get => _trendLength.Value; set => _trendLength.Value = value; }
public int SignalLength { get => _signalLength.Value; set => _signalLength.Value = value; }
public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public FisherTransformX2Strategy()
{
_trendLength = Param(nameof(TrendLength), 40)
.SetGreaterThanZero()
.SetDisplay("Trend Length", "Fisher length for trend", "Parameters")
.SetOptimize(10, 30, 2);
_signalLength = Param(nameof(SignalLength), 20)
.SetGreaterThanZero()
.SetDisplay("Signal Length", "Fisher length for signal", "Parameters")
.SetOptimize(5, 20, 1);
_takeProfit = Param(nameof(TakeProfit), 2000m)
.SetGreaterThanZero()
.SetDisplay("Take Profit", "Take profit in price units", "Risk");
_stopLoss = Param(nameof(StopLoss), 1000m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss", "Stop loss in price units", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevTrend = 0m;
_prevSignal = 0m;
_prevPrevSignal = 0m;
_trendDirection = 0;
_count = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_trendFisher = new EhlersFisherTransform { Length = TrendLength };
_signalFisher = new EhlersFisherTransform { Length = SignalLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(_signalFisher, ProcessCandle)
.Start();
StartProtection(
new Unit(TakeProfit, UnitTypes.Absolute),
new Unit(StopLoss, UnitTypes.Absolute));
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _signalFisher);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue signalResult)
{
if (candle.State != CandleStates.Finished)
return;
// Process trend Fisher manually with the candle
var trendResult = _trendFisher.Process(candle);
if (!_trendFisher.IsFormed || !_signalFisher.IsFormed)
return;
var signalVal = ((IEhlersFisherTransformValue)signalResult).MainLine ?? 0m;
var trendVal = ((IEhlersFisherTransformValue)trendResult).MainLine ?? 0m;
_count++;
if (_count < 3)
{
_prevPrevSignal = _prevSignal;
_prevSignal = signalVal;
_prevTrend = trendVal;
return;
}
// Update trend direction
if (trendVal > _prevTrend)
_trendDirection = 1;
else if (trendVal < _prevTrend)
_trendDirection = -1;
// Signal crossover
var signalCrossUp = signalVal > _prevSignal && _prevSignal <= _prevPrevSignal && signalVal < 0m;
var signalCrossDown = signalVal < _prevSignal && _prevSignal >= _prevPrevSignal && signalVal > 0m;
if (_trendDirection > 0 && signalCrossUp && Position <= 0)
BuyMarket();
else if (_trendDirection < 0 && signalCrossDown && Position >= 0)
SellMarket();
_prevTrend = trendVal;
_prevPrevSignal = _prevSignal;
_prevSignal = signalVal;
}
}
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 EhlersFisherTransform, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
class fisher_transform_x2_strategy(Strategy):
"""
Fisher Transform X2: Dual Fisher indicator strategy.
Trend Fisher defines direction; Signal Fisher generates entries.
Uses StartProtection for SL/TP.
"""
def __init__(self):
super(fisher_transform_x2_strategy, self).__init__()
self._trend_length = self.Param("TrendLength", 40) \
.SetDisplay("Trend Length", "Fisher length for trend", "Parameters")
self._signal_length = self.Param("SignalLength", 20) \
.SetDisplay("Signal Length", "Fisher length for signal", "Parameters")
self._take_profit = self.Param("TakeProfit", 2000.0) \
.SetDisplay("Take Profit", "Take profit in price units", "Risk")
self._stop_loss = self.Param("StopLoss", 1000.0) \
.SetDisplay("Stop Loss", "Stop loss in price units", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._trend_fisher = None
self._prev_trend = 0.0
self._prev_signal = 0.0
self._prev_prev_signal = 0.0
self._trend_direction = 0
self._count = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(fisher_transform_x2_strategy, self).OnReseted()
self._prev_trend = 0.0
self._prev_signal = 0.0
self._prev_prev_signal = 0.0
self._trend_direction = 0
self._count = 0
def OnStarted2(self, time):
super(fisher_transform_x2_strategy, self).OnStarted2(time)
self._trend_fisher = EhlersFisherTransform()
self._trend_fisher.Length = self._trend_length.Value
self.Indicators.Add(self._trend_fisher)
signal_fisher = EhlersFisherTransform()
signal_fisher.Length = self._signal_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(signal_fisher, self._process_candle).Start()
tp = self._take_profit.Value
sl = self._stop_loss.Value
self.StartProtection(
Unit(tp, UnitTypes.Absolute),
Unit(sl, UnitTypes.Absolute))
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, signal_fisher)
self.DrawOwnTrades(area)
def _process_candle(self, candle, signal_result):
if candle.State != CandleStates.Finished:
return
trend_input = CandleIndicatorValue(self._trend_fisher, candle)
trend_input.IsFinal = True
trend_result = self._trend_fisher.Process(trend_input)
if not self._trend_fisher.IsFormed:
return
signal_main = signal_result.MainLine
trend_main = trend_result.MainLine
signal_val = float(signal_main) if signal_main is not None else 0.0
trend_val = float(trend_main) if trend_main is not None else 0.0
self._count += 1
if self._count < 3:
self._prev_prev_signal = self._prev_signal
self._prev_signal = signal_val
self._prev_trend = trend_val
return
if trend_val > self._prev_trend:
self._trend_direction = 1
elif trend_val < self._prev_trend:
self._trend_direction = -1
signal_cross_up = signal_val > self._prev_signal and self._prev_signal <= self._prev_prev_signal and signal_val < 0
signal_cross_down = signal_val < self._prev_signal and self._prev_signal >= self._prev_prev_signal and signal_val > 0
if self._trend_direction > 0 and signal_cross_up and self.Position <= 0:
self.BuyMarket()
elif self._trend_direction < 0 and signal_cross_down and self.Position >= 0:
self.SellMarket()
self._prev_trend = trend_val
self._prev_prev_signal = self._prev_signal
self._prev_signal = signal_val
def CreateClone(self):
return fisher_transform_x2_strategy()