Diese Strategie ist eine direkte Konvertierung des MetaTrader "HTH Trader" Expert Advisors. Sie handelt einen Vier-Bein-Forex-Korb und versucht, die tägliche Mean Reversion zwischen EURUSD und einem gespiegelten Korb aus USDCHF, GBPUSD und AUDUSD zu erfassen. Der StockSharp-Port behält die ursprünglichen Risikokontrollen und Zeitregeln bei und verwendet die High-Level-API für den Multi-Security-Handel.
Hauptmerkmale:
Öffnet einen abgesicherten Korb einmal pro Tag zwischen 00:05 und 00:12 Terminalzeit.
Verwendet die vorherigen zwei täglichen Schlusskurse von EURUSD, um die Korbrichtung zu bestimmen.
Verwaltet vier Instrumente gleichzeitig: EURUSD (primäre Sicherheit), USDCHF, GBPUSD und AUDUSD.
Verfolgt den offenen Gewinn in Pips und unterstützt korbweite Gewinn- und Verlustziele.
Enthält eine Notfall-Verdoppelungsfunktion, die profitable Beine hinzufügt, wenn der Korb-Drawdown einen Schwellenwert überschreitet.
Schließt alle Trades um 23:00 Terminalzeit oder wenn der Korb konfigurierte Gewinn-/Verlustgrenzen erreicht.
Datenanforderungen
Intraday-Kerzen: Alle vier Symbole müssen Intraday-Kerzen für den in IntradayCandleType konfigurierten Zeitrahmen liefern (Standard 5 Minuten). Diese Kerzen liefern den neuesten Preis und die Sessionsuhr.
Tageskerzen: Jedes Symbol muss Tageskerzen bereitstellen, damit die Strategie die letzten zwei abgeschlossenen Tagesschlusskurse überwachen kann.
Handelslogik
Am Ende jeder abgeschlossenen Intraday-Kerze prüft die Strategie den aktuellen offenen Gewinn:
Wenn AllowEmergencyTrading aktiviert ist und der gesamte offene Gewinn ≤ -EmergencyLossPips, verdoppelt die Strategie jedes Bein, das aktuell profitabel ist, und deaktiviert weitere Notfalltrades für diesen Tag.
Wenn UseProfitTarget aktiviert ist und der gesamte offene Gewinn ≥ ProfitTargetPips, wird der Korb sofort geschlossen.
Wenn UseLossLimit aktiviert ist und der gesamte offene Gewinn ≤ -LossLimitPips, wird der Korb sofort geschlossen.
Sobald die Uhr 23:00 erreicht, wird der Korb unabhängig vom Gewinn geschlossen.
Wenn keine Positionen offen sind und die Uhr im Fenster 00:05–00:12 liegt, prüft die Strategie die letzten zwei abgeschlossenen Tagesschlusskurse des primären Symbols (EURUSD standardmäßig):
Wenn die tägliche prozentuale Veränderung positiv ist, öffnet die Strategie: Long EURUSD, Long USDCHF, Short GBPUSD, Long AUDUSD.
Wenn die Veränderung negativ ist, öffnet sie: Short EURUSD, Short USDCHF, Long GBPUSD, Short AUDUSD.
Wenn die Veränderung null ist oder ein Tagesschlusskurs fehlt, überspringt die Strategie den Handel für diesen Tag.
Alle Positionen werden mit Marktorders über ClosePosition geschlossen.
Parameter
Name
Beschreibung
Standard
TradeEnabled
Aktiviert oder deaktiviert die Orderplatzierung.
true
ShowProfitInfo
Protokolliert den Korbgewinn in Pips bei jedem Update, während Positionen offen sind.
true
UseProfitTarget
Aktiviert das automatische Schließen, wenn ProfitTargetPips erreicht wird.
false
UseLossLimit
Aktiviert das automatische Schließen, wenn LossLimitPips erreicht wird.
false
AllowEmergencyTrading
Erlaubt die Notfall-Verdoppelungsfunktion.
true
EmergencyLossPips
Korb-Drawdown (in Pips), der die Notfallverdopplung auslöst.
60
ProfitTargetPips
Korbgewinn (in Pips), der das Schließen auslöst, wenn UseProfitTarget aktiviert ist.
80
LossLimitPips
Korbverlust (in Pips), der das Schließen auslöst, wenn UseLossLimit aktiviert ist.
40
TradingVolume
Ordervolumen für jedes Bein.
0.01
Symbol2
Zweite Sicherheit (USDCHF standardmäßig).
null
Symbol3
Dritte Sicherheit (GBPUSD standardmäßig).
null
Symbol4
Vierte Sicherheit (AUDUSD standardmäßig).
null
IntradayCandleType
Intraday-Zeitrahmen für Zeitplanung und Preisupdates.
5-Minuten-Kerzen
Verwendungshinweise
Weisen Sie die primäre Sicherheit (Strategy.Security) EURUSD (oder dem gewünschten führenden Paar) zu und ordnen Sie Symbol2, Symbol3, Symbol4 den korrelierten Instrumenten zu, bevor Sie starten.
Stellen Sie sicher, dass jede Sicherheit einen gültigen PriceStep hat; andernfalls können Gewinnberechnungen in Pips nicht durchgeführt werden und die Notfalllogik bleibt inaktiv.
Die Notfall-Verdoppelungsfunktion fügt nur Beinen hinzu, die aktuell profitabel sind; verlierende Beine werden unberührt gelassen, um den Drawdown nicht zu verstärken.
Die Implementierung geht davon aus, dass Marktorders nahe dem letzten Kerzenschluss ausgeführt werden. Für eine genaue Buchführung verbinden Sie die Strategie mit einem Datenfeed, der zeitnahe Intraday-Kerzen liefert.
Da die Logik durch eine einzelne Kerze pro Minute (oder gewähltem Zeitrahmen) gesteuert wird, kann das ursprüngliche Tick-für-Tick-MQL-Verhalten beim Ausführungszeitpunkt leicht abweichen, aber die Trade-Sequenzierung und Bedingungen stimmen mit dem Referenz-Expert-Advisor überein.
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>
/// Hedge strategy simplified from HTH Trader. Trades based on daily close deviation.
/// </summary>
public class HthTraderStrategy : Strategy
{
private readonly StrategyParam<bool> _tradeEnabled;
private readonly StrategyParam<bool> _useProfitTarget;
private readonly StrategyParam<bool> _useLossLimit;
private readonly StrategyParam<int> _profitTargetPips;
private readonly StrategyParam<int> _lossLimitPips;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose1;
private decimal _prevClose2;
private decimal _entryPrice;
private decimal _priceStep;
/// <summary>
/// Enable automated trading.
/// </summary>
public bool TradeEnabled
{
get => _tradeEnabled.Value;
set => _tradeEnabled.Value = value;
}
/// <summary>
/// Enable closing by reaching the profit target.
/// </summary>
public bool UseProfitTarget
{
get => _useProfitTarget.Value;
set => _useProfitTarget.Value = value;
}
/// <summary>
/// Enable closing by reaching the loss limit.
/// </summary>
public bool UseLossLimit
{
get => _useLossLimit.Value;
set => _useLossLimit.Value = value;
}
/// <summary>
/// Profit target in pips.
/// </summary>
public int ProfitTargetPips
{
get => _profitTargetPips.Value;
set => _profitTargetPips.Value = value;
}
/// <summary>
/// Loss limit in pips.
/// </summary>
public int LossLimitPips
{
get => _lossLimitPips.Value;
set => _lossLimitPips.Value = value;
}
/// <summary>
/// Candle type for monitoring.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes parameters.
/// </summary>
public HthTraderStrategy()
{
_tradeEnabled = Param(nameof(TradeEnabled), true)
.SetDisplay("Trade Enabled", "Allow the strategy to submit orders", "General");
_useProfitTarget = Param(nameof(UseProfitTarget), true)
.SetDisplay("Use Profit Target", "Close when profit target is reached", "Risk");
_useLossLimit = Param(nameof(UseLossLimit), true)
.SetDisplay("Use Loss Limit", "Close when loss limit is reached", "Risk");
_profitTargetPips = Param(nameof(ProfitTargetPips), 80)
.SetDisplay("Profit Target (pips)", "Profit target in pips", "Risk");
_lossLimitPips = Param(nameof(LossLimitPips), 40)
.SetDisplay("Loss Limit (pips)", "Loss limit in pips", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for monitoring", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, CandleType);
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose1 = 0m;
_prevClose2 = 0m;
_entryPrice = 0m;
_priceStep = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_priceStep = Security?.PriceStep ?? 0.0001m;
if (_priceStep <= 0m)
_priceStep = 0.0001m;
SubscribeCandles(CandleType)
.Bind(ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (!TradeEnabled)
return;
// Check exit conditions
if (Position != 0 && _entryPrice > 0m)
{
var priceDiff = Position > 0
? candle.ClosePrice - _entryPrice
: _entryPrice - candle.ClosePrice;
var pipsDiff = priceDiff / _priceStep;
if (UseProfitTarget && pipsDiff >= ProfitTargetPips)
{
if (Position > 0) SellMarket();
else BuyMarket();
_entryPrice = 0m;
return;
}
if (UseLossLimit && pipsDiff <= -LossLimitPips)
{
if (Position > 0) SellMarket();
else BuyMarket();
_entryPrice = 0m;
return;
}
}
// Entry logic based on daily close deviation
if (Position == 0 && _prevClose1 > 0m && _prevClose2 > 0m)
{
var deviation = (100m * _prevClose1 / _prevClose2) - 100m;
if (deviation > 0.1m)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
}
else if (deviation < -0.1m)
{
SellMarket();
_entryPrice = candle.ClosePrice;
}
}
_prevClose2 = _prevClose1;
_prevClose1 = candle.ClosePrice;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class hth_trader_strategy(Strategy):
def __init__(self):
super(hth_trader_strategy, self).__init__()
self._trade_enabled = self.Param("TradeEnabled", True)
self._use_profit_target = self.Param("UseProfitTarget", True)
self._use_loss_limit = self.Param("UseLossLimit", True)
self._profit_target_pips = self.Param("ProfitTargetPips", 80)
self._loss_limit_pips = self.Param("LossLimitPips", 40)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._prev_close1 = 0.0
self._prev_close2 = 0.0
self._entry_price = 0.0
self._price_step = 0.0
@property
def TradeEnabled(self):
return self._trade_enabled.Value
@TradeEnabled.setter
def TradeEnabled(self, value):
self._trade_enabled.Value = value
@property
def UseProfitTarget(self):
return self._use_profit_target.Value
@UseProfitTarget.setter
def UseProfitTarget(self, value):
self._use_profit_target.Value = value
@property
def UseLossLimit(self):
return self._use_loss_limit.Value
@UseLossLimit.setter
def UseLossLimit(self, value):
self._use_loss_limit.Value = value
@property
def ProfitTargetPips(self):
return self._profit_target_pips.Value
@ProfitTargetPips.setter
def ProfitTargetPips(self, value):
self._profit_target_pips.Value = value
@property
def LossLimitPips(self):
return self._loss_limit_pips.Value
@LossLimitPips.setter
def LossLimitPips(self, value):
self._loss_limit_pips.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(hth_trader_strategy, self).OnStarted2(time)
self._price_step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 0.0001
if self._price_step <= 0.0:
self._price_step = 0.0001
self._prev_close1 = 0.0
self._prev_close2 = 0.0
self._entry_price = 0.0
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
if not self.TradeEnabled:
return
close = float(candle.ClosePrice)
# Check exit conditions
if self.Position != 0 and self._entry_price > 0.0:
if self.Position > 0:
price_diff = close - self._entry_price
else:
price_diff = self._entry_price - close
pips_diff = price_diff / self._price_step
if self.UseProfitTarget and pips_diff >= int(self.ProfitTargetPips):
if self.Position > 0:
self.SellMarket()
else:
self.BuyMarket()
self._entry_price = 0.0
return
if self.UseLossLimit and pips_diff <= -int(self.LossLimitPips):
if self.Position > 0:
self.SellMarket()
else:
self.BuyMarket()
self._entry_price = 0.0
return
# Entry logic
if self.Position == 0 and self._prev_close1 > 0.0 and self._prev_close2 > 0.0:
deviation = (100.0 * self._prev_close1 / self._prev_close2) - 100.0
if deviation > 0.1:
self.BuyMarket()
self._entry_price = close
elif deviation < -0.1:
self.SellMarket()
self._entry_price = close
self._prev_close2 = self._prev_close1
self._prev_close1 = close
def OnReseted(self):
super(hth_trader_strategy, self).OnReseted()
self._prev_close1 = 0.0
self._prev_close2 = 0.0
self._entry_price = 0.0
self._price_step = 0.0
def CreateClone(self):
return hth_trader_strategy()