TakeProfitTimeGuardStrategy emuliert das Verhalten des MetaTrader-Experten Exp_GTakeProfit_Tm, indem es den Gewinn auf Kontoebene überwacht und außerhalb eines konfigurierbaren Handelszeitplans eine flache Positionierung erzwingt. Die Strategie öffnet selbst keine Positionen. Stattdessen dient sie als Risikomanagement-Überlagerung, die automatisch alle bestehenden Positionen schließt, sobald das Gewinnziel erreicht wird oder wenn der Handel außerhalb des erlaubten Zeitfensters gestoppt werden muss.
Kernlogik
Abonniert einen konfigurierbaren Kerzen-Stream (Standard 1 Minute), um realisierten und unrealisierten PnL anhand des neuesten Schlusskurses zu bewerten.
Berechnet den Gesamtgewinn als Summe aus realisiertem PnL (Strategy.PnL) und dem schwebenden PnL, der aus dem aktuellen durchschnittlichen Positionspreis abgeleitet wird.
Ignoriert Verluste, während das Handelsfenster offen ist, entsprechend dem Originalverhalten des Expert Advisors.
Sobald das Take-Profit-Ziel erreicht ist, setzt es ein internes Stop-Flag und liquidiert wiederholt alle verbleibenden Positionen, bis das Konto flach ist. Das Stop-Flag wird zurückgesetzt, nachdem das Portfolio zur Null-Position zurückgekehrt ist.
Wenn das optionale Handelsfenster aktiviert ist, schließt die Strategie alle Positionen, wenn die aktuelle Zeit außerhalb des erlaubten Bereichs liegt, und wartet ebenfalls, bis das Buch flach ist, bevor der Handel wieder aktiviert wird.
Parameter
Parameter
Typ
Standard
Beschreibung
CandleType
DataType
1-Minuten-Zeitrahmen
Kerzenserie zur Bewertung der Gewinn- und Zeitplanlogik.
TargetMode
ProfitTargetModes (Percent/Currency)
Percent
Legt fest, ob TakeProfitValue als Prozentsatz des Kontokapitals oder als absoluter Währungsbetrag interpretiert wird.
TakeProfitValue
decimal
100
Gewinnzielschwellenwert. Wird gemäß TargetMode interpretiert. Muss größer als null sein.
UseTradingWindow
bool
true
Aktiviert oder deaktiviert den Zeitfilter.
StartTime
TimeSpan
00:00:00
Beginn des erlaubten Handelsfensters (inklusiv).
EndTime
TimeSpan
23:59:00
Ende des erlaubten Handelsfensters. Wenn die Startzeit größer als die Endzeit ist, erstreckt sich das Fenster über Mitternacht.
Verhaltenshinweise
Der anfängliche Portfoliowert wird beim Start der Strategie erfasst (oder bei der ersten Aktualisierung, wenn der Wert null war) und als Referenz für das Prozentziel verwendet.
Die Strategie berechnet den schwebenden PnL anhand des neuesten Kerzenschlusskurses; die Ergebnisse hängen von der ausgewählten Kerzen-Granularität ab.
Wenn das Gewinnziel erreicht ist, sendet die Strategie weiterhin Marktorders, um die Position zu glätten, bis das Buch leer ist. Sie protokolliert den Grund für die Schließung des Buches.
Wenn UseTradingWindow aktiviert ist und die Uhr außerhalb des Fensters liegt, wird dieselbe Glättungsroutine ausgeführt, auch wenn das Gewinnziel nicht erreicht wurde.
Das Stop-Flag (_stop) wird erst gelöscht, nachdem die Position auf null zurückgekehrt ist, sodass der Handel wieder aufgenommen werden kann, wenn die Bedingungen es erlauben.
Unterschiede zur originalen MQL-Strategie
Verwendet die StockSharp High-Level-API (SubscribeCandles) statt Tick-Handler.
Berechnet schwebenden Gewinn aus dem durchschnittlichen Positionspreis, der durch Strategy.PositionPrice bereitgestellt wird.
Protokolliert Take-Profit-Ereignisse für einfacheres Monitoring.
Der Zeitvergleich basiert auf DateTimeOffset.CloseTime der abonnierten Kerzen.
Verwendungshinweise
Hängen Sie die Strategie an ein Portfolio, das bereits eine andere Handelsstrategie ausführt, um als Guard-Schicht zu fungieren.
Wählen Sie einen Kerzen-Zeitrahmen, der der für die Gewinnbewertung erforderlichen Reaktionsfähigkeit entspricht (z.B. 1 Minute für schnelle Kontrolle).
Stellen Sie sicher, dass die Portfolio-Informationen (insbesondere CurrentValue) verfügbar sind; andernfalls setzen Sie vor dem Ausführen von Prozentzielen ein explizites Anfangsguthaben.
Die Strategie kann mit StartProtection() in einer anderen primären Strategie kombiniert werden, um weitere Risikokontrollen hinzuzufügen.
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>
/// Take Profit Time Guard strategy (simplified). Uses CCI momentum
/// with session time awareness for entries and profit management.
/// </summary>
public class TakeProfitTimeGuardStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciLength;
private readonly StrategyParam<decimal> _upperLevel;
private readonly StrategyParam<decimal> _lowerLevel;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int CciLength
{
get => _cciLength.Value;
set => _cciLength.Value = value;
}
public decimal UpperLevel
{
get => _upperLevel.Value;
set => _upperLevel.Value = value;
}
public decimal LowerLevel
{
get => _lowerLevel.Value;
set => _lowerLevel.Value = value;
}
public TakeProfitTimeGuardStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_cciLength = Param(nameof(CciLength), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Length", "CCI period", "Indicators");
_upperLevel = Param(nameof(UpperLevel), 100m)
.SetDisplay("Upper Level", "CCI level for sell signal", "Logic");
_lowerLevel = Param(nameof(LowerLevel), -100m)
.SetDisplay("Lower Level", "CCI level for buy signal", "Logic");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var cci = new CommodityChannelIndex { Length = CciLength };
decimal prevCci = 0;
var hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(cci, (ICandleMessage candle, decimal cciVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!hasPrev)
{
prevCci = cciVal;
hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
prevCci = cciVal;
return;
}
// CCI crosses up from below lower level
if (prevCci < LowerLevel && cciVal >= LowerLevel && Position <= 0)
BuyMarket();
// CCI crosses down from above upper level
else if (prevCci > UpperLevel && cciVal <= UpperLevel && Position >= 0)
SellMarket();
prevCci = cciVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var cciArea = CreateChartArea();
if (cciArea != null)
DrawIndicator(cciArea, cci);
}
}
}
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 CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
class take_profit_time_guard_strategy(Strategy):
def __init__(self):
super(take_profit_time_guard_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candles", "General")
self._cci_length = self.Param("CciLength", 14) \
.SetDisplay("CCI Length", "CCI period", "Indicators")
self._upper_level = self.Param("UpperLevel", 100.0) \
.SetDisplay("Upper Level", "CCI level for sell signal", "Logic")
self._lower_level = self.Param("LowerLevel", -100.0) \
.SetDisplay("Lower Level", "CCI level for buy signal", "Logic")
self._prev_cci = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def CciLength(self):
return self._cci_length.Value
@property
def UpperLevel(self):
return self._upper_level.Value
@property
def LowerLevel(self):
return self._lower_level.Value
def OnReseted(self):
super(take_profit_time_guard_strategy, self).OnReseted()
self._prev_cci = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(take_profit_time_guard_strategy, self).OnStarted2(time)
self._prev_cci = 0.0
self._has_prev = False
cci = CommodityChannelIndex()
cci.Length = self.CciLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(cci, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle, cci_value):
if candle.State != CandleStates.Finished:
return
cv = float(cci_value)
if not self._has_prev:
self._prev_cci = cv
self._has_prev = True
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_cci = cv
return
if self._prev_cci < self.LowerLevel and cv >= self.LowerLevel and self.Position <= 0:
self.BuyMarket()
elif self._prev_cci > self.UpperLevel and cv <= self.UpperLevel and self.Position >= 0:
self.SellMarket()
self._prev_cci = cv
def CreateClone(self):
return take_profit_time_guard_strategy()