Die GPF TCPivotLimit-Strategie erstellt den MetaTrader 4 Expert Advisor gpfTCPivotLimit.mq4 innerhalb des StockSharp-Frameworks neu. Das System handelt auf stündlichen Kerzen und reagiert auf Umkehrungen um klassische tägliche Pivot-Levels. An jedem neuen Handelstag berechnet die Strategie den Pivot, drei Widerstandsniveaus (R1–R3) und drei Unterstützungsniveaus (S1–S3) aus dem Hoch, Tief und Schlusskurs des Vortages. Sobald der nächste Tag beginnt, wertet es die letzten beiden abgeschlossenen Stundenkerzen aus, um zu entscheiden, ob der Preis eine Widerstands- oder Unterstützungszone abgelehnt hat, und eröffnet eine Marktorder in die entgegengesetzte Richtung.
Handelslogik
Pivot-Berechnung – Wenn eine neue tägliche Sitzung beginnt, speichert die Strategie die Höchst-, Tiefst- und Schlusskurse des Vortages und berechnet dann:
Eingabebestätigung – zu Beginn des neuen Tages werden die letzten beiden geschlossenen Stundenkerzen (t-2 und t-1) überprüft.
Ein Short wird eröffnet, wenn die Kerze t-2 über dem ausgewählten Widerstand (hoch über oder nahe dem Niveau) liegt, sich darunter öffnet und die Kerze t-1 wieder unter dem Niveau schließt.
Ein Long wird eröffnet, wenn die Kerze t-2 unter die ausgewählte Unterstützung fällt (Tief unter oder Schluss auf dem Niveau), darüber öffnet und die Kerze t-1 wieder über dem Niveau schließt.
Zielvorgaben – der ursprüngliche Expert Advisor stellt fünf Gewinn-/Stopp-Layouts vor. Die folgende Tabelle zeigt die genaue Zuordnung, die in diesem Port erhalten bleibt.
TargetMode
Langer Abzug
Langer Stopp
Langes Ziel
Kurzer Auslöser
Kurzer Stopp
Kurzes Ziel
1
S1
S2
R1
R1
R2
S1
2
S1
S2
R2
R1
R2
S2
3
S2
S3
R1
R2
R3
S1
4
S2
S3
R2
R2
R3
S2
5
S2
S3
R3
R2
R3
S3
Risikomanagement – schützende Stop-Loss- und Take-Profit-Prüfungen werden bei jeder abgeschlossenen Kerze durchgeführt. Die optionale Trailing-Stop-Logik emuliert das MT4-Verhalten: Sobald der nicht realisierte Gewinn die konfigurierte Distanz überschreitet, wird der Stop zugunsten des Handels verschoben. Ein optionaler Ausstieg am Ende des Tages flacht die Position um 23:00 Uhr Bahnsteigzeit ab.
Lautstärkeanpassung – der MetaTrader-Eingang isFloatLots wird durch den UseDynamicVolume-Schalter gespiegelt. Wenn diese Option aktiviert ist, wird die Positionsgröße nach aufeinanderfolgenden Verlustgeschäften mithilfe der Eingaben DrawdownFactor und RiskPercentage reduziert.
Parameter
Name
Beschreibung
Standard
BaseVolume
Mit jeder Marktorder übermitteltes Basisvolumen vor Risikoanpassungen.
1
UseDynamicVolume
Reduziert die Handelsgröße nach mehr als einem aufeinanderfolgenden Verlust.
false
RiskPercentage
Referenz-Risiko-pro-Trade-Verhältnis zur Skalierung des Basisvolumens (MetaTrader MaxR).
0.02
DrawdownFactor
Divisor wird angewendet, wenn das Volumen nach einer Pechsträhne verkleinert wird (MetaTrader DcF).
3
TargetMode
Wählt die oben aufgeführte Widerstands-/Unterstützungskombination aus (MetaTrader TgtProfit).
1
TrailingPoints
Trailing-Stop-Distanz, ausgedrückt in Instrumentenpunkten. Zum Deaktivieren auf 0 setzen.
30
CloseAtSessionEnd
Bei true werden alle Positionen zum Kerzenschluss um 23:00 Uhr geschlossen.
false
LogSignals
Druckt Pivot-Werte, Ein- und Ausgänge im Strategieprotokoll.
false
CandleType
Für die Analyse verwendeter Kerzendatentyp (standardmäßig 1-Stunden-Kerzen).
TimeFrameCandleMessage(1h)
Notizen
Die Strategie gibt Marktaufträge genau wie das Original EA aus und platziert keine ausstehenden Aufträge.
Stop-Loss- und Take-Profit-Ereignisse werden mit Marktausstiegen ausgeführt, um mit allen StockSharp-Konnektoren kompatibel zu bleiben.
Nachlaufentfernungen hängen vom Instrument PriceStep ab. Fehlt die Stufe, wird der Nachlaufmechanismus automatisch deaktiviert.
Das E-Mail-Benachrichtigungsflag der MT4-Version wird durch LogSignals dargestellt und erzeugt Protokollnachrichten anstelle von E-Mails.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class GpfTcpPivotLimitStrategy : Strategy
{
private readonly StrategyParam<int> _channelPeriod;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose; private decimal _prevMid; private bool _hasPrev;
private int _cooldown;
public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public GpfTcpPivotLimitStrategy()
{
_channelPeriod = Param(nameof(ChannelPeriod), 20).SetDisplay("Channel Period", "Pivot lookback", "Indicators");
_emaPeriod = Param(nameof(EmaPeriod), 14).SetDisplay("EMA Period", "EMA filter", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = default;
_prevMid = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var highest = new Highest { Length = ChannelPeriod };
var lowest = new Lowest { Length = ChannelPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(highest, lowest, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal highest, decimal lowest)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) return;
var close = candle.ClosePrice;
var mid = (highest + lowest) / 2;
if (!_hasPrev) { _prevClose = close; _prevMid = mid; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevClose = close; _prevMid = mid;
return;
}
if (_prevClose <= _prevMid && close > mid && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 2;
}
else if (_prevClose >= _prevMid && close < mid && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 2;
}
_prevClose = close; _prevMid = mid;
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class gpf_tcp_pivot_limit_strategy(Strategy):
"""
GPF TCP Pivot Limit: Donchian channel midline crossover.
Buys when close crosses above channel midpoint.
Sells when close crosses below channel midpoint.
"""
def __init__(self):
super(gpf_tcp_pivot_limit_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 20) \
.SetDisplay("Channel Period", "Pivot lookback", "Indicators")
self._ema_period = self.Param("EmaPeriod", 14) \
.SetDisplay("EMA Period", "EMA filter", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(gpf_tcp_pivot_limit_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
self._cooldown = 0
def OnStarted2(self, time):
super(gpf_tcp_pivot_limit_strategy, self).OnStarted2(time)
highest = Highest()
highest.Length = self._channel_period.Value
lowest = Lowest()
lowest.Length = self._channel_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(highest, lowest, self._process_candle).Start()
def _process_candle(self, candle, highest_val, lowest_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
h = float(highest_val)
l = float(lowest_val)
mid = (h + l) / 2.0
if not self._has_prev:
self._prev_close = close
self._prev_mid = mid
self._has_prev = True
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_close = close
self._prev_mid = mid
return
if self._prev_close <= self._prev_mid and close > mid and self.Position <= 0:
self.BuyMarket()
self._cooldown = 2
elif self._prev_close >= self._prev_mid and close < mid and self.Position >= 0:
self.SellMarket()
self._cooldown = 2
self._prev_close = close
self._prev_mid = mid
def CreateClone(self):
return gpf_tcp_pivot_limit_strategy()