Die Daily STP Entry Frame-Strategie repliziert das Verhalten des ursprünglichen MetaTrader-Expertenberaters „Daily STP Entry Frame“ unter Verwendung des StockSharp-High-Levels API. Das System bereitet zu Beginn jedes neuen Handelstages Breakout-Stop-Orders vor. Die Einstiegspreise werden aus den Höchst- und Tiefstständen des Vortages abgeleitet, mit zusätzlichen Filtern, um sicherzustellen, dass sich der Markt in der Nähe dieser Extremwerte positioniert, bevor Aufträge erteilt werden. Die Logik ist auf Instrumente im Forex-Stil zugeschnitten, bei denen „Basispunkte“ einem Zehntel Pip für fünfstellige Kurse entsprechen.
Kern-Workflow
Tägliche Range-Verfolgung – Die Strategie abonniert tägliche Kerzen, um sich an die Höchst- und Tiefststände der vorherigen Sitzung zu erinnern.
Echtzeitüberwachung – Level1-Daten liefern die aktuellen Geld-, Brief- und letzten Handelspreise für das Intraday-Management.
Order-Aktivierung – Wenn zu Beginn eines neuen Tages der letzte Preis mindestens ThresholdPoints vom gestrigen Hoch/Tief entfernt liegt und die Eröffnung des aktuellen Tages auf der richtigen Seite dieses Extrems liegt, wird eine Stop-Order übermittelt:
Kaufstopp bei High + SpreadPoints / 2 (umgerechnet in Preiseinheiten).
Verkaufsstopp bei Low - SpreadPoints / 2.
Risikovalidierung – Neue Aufträge werden blockiert, wenn der Aktienrückgang MaximumDrawdownPercent überschreitet oder die Zeitfilter den Handel nicht zulassen (Wochenenden, Stundenfilter oder Tagesfilter).
Positionsmanagement – sobald ein Handel aktiv ist, erzwingt die Strategie Folgendes:
Statische Stop-Loss- und Take-Profit-Distanzen.
Optionaler zeitbasierter Exit nach CloseAfterSeconds.
Optionaler Trailing-Stop, der den ursprünglichen Parameter „SL-Steigung“ emuliert.
Hygiene am Ende des Tages – ausstehende Orders werden nach NoNewOrdersHour (oder dem entsprechenden Freitagsschluss) und bei jeder Änderung des Kalendertags storniert.
Handelsregeln
Lange Einträge
Zulässig, wenn SideFilter0 (beide) oder 1 (nur lang) ist.
Höchststand des Vortages minus aktueller Preis ≥ ThresholdPoints.
Der heutige Eröffnungskurs liegt unter dem gestrigen Hoch.
Der berechnete Einstiegspreis muss den Mindestabstand zum aktuellen Brief einhalten.
Kurze Einträge
Zulässig, wenn SideFilter0 (beide) oder -1 (nur kurz) ist.
Aktueller Preis minus Tiefststand des Vortages ≥ ThresholdPoints.
Der heutige Eröffnungskurs liegt über dem gestrigen Tief.
Der berechnete Einstiegspreis muss den Mindestabstand zum aktuellen Gebot einhalten.
Geldmanagement
Bei der dynamischen Volumengröße wird ein Prozentsatz des kumulierten Gewinns (PercentOfProfit) verwendet.
Die resultierende Größe wird durch MinVolume und MaxVolume begrenzt und an der VolumeStep des Instruments ausgerichtet.
Der Handel wird automatisch unterbrochen, sobald der gemessene Drawdown MaximumDrawdownPercent überschreitet.
Schutzlogik
Stop-Loss- und Take-Profit-Level werden in Basispunkten ausgedrückt und anhand der Pip-Größe des Instruments in Preisversätze umgerechnet.
Trailing Stop ist nur aktiv, wenn TrailingSlope < 1. Es verschiebt die Schutzschwelle näher an den Preis, wenn der nicht realisierte Gewinn wächst.
Lebenszeitausgänge schließen alle offenen Positionen, sobald die konfigurierte Anzahl von Sekunden verstrichen ist.
Parameter
Name
Beschreibung
CandleType
Zeitrahmen, der zum Abrufen der Referenzkerzen verwendet wird (standardmäßig täglich).
StopLossPoints
Stop-Loss-Distanz in Basispunkten.
TakeProfitPoints
Take-Profit-Distanz in Basispunkten.
TrailingSlope
Teil des Gewinns, der während des Trailings einbehalten wird; ≥ 1 deaktiviert die Funktion.
SideFilter
-1 nur kurz, 0 beide Richtungen, 1 nur lang.
ThresholdPoints
Minimale Lücke zwischen dem aktuellen Preis und dem vorherigen Extrem, die erforderlich ist, um einen Stopp zu aktivieren.
SpreadPoints
Zusätzlicher Versatz (die Hälfte wird über/unter dem Extremwert verwendet), um die Streuung auszugleichen.
SlippagePoints
Sicherheitspuffer zur Prüfung des Mindestanhaltewegs hinzugefügt.
NoNewOrdersHour
Stunde (Plattformzeit), um ausstehende Orders an regulären Tagen zu stornieren.
NoNewOrdersHourFriday
Freitagsspezifische Stornierungsstunde.
EarliestOrderHour
Früheste Stunde des Tages, zu der neue Aufträge erstellt werden können.
DayFilter
6 für alle Tage oder 0-5, um nur von Sonntag bis Freitag zu handeln.
CloseAfterSeconds
Optionaler zeitbasierter Exit (0 deaktiviert).
PercentOfProfit
Bruchteil des kumulierten Gewinns, der zur Skalierung der Positionsgröße verwendet wird.
MinVolume / MaxVolume
Feste Grenzen für das berechnete Volumen.
MaximumDrawdownPercent
Drawdown-Schwelle, die neue Aufträge blockiert.
Konvertierungshinweise
Die Pip-Konvertierung spiegelt die MetaTrader-Implementierung wider: Wenn die Sicherheit 3 oder 5 Dezimalstellen offenlegt, wird der Basispunkt zu PriceStep * 10.
Das Stopp-Order-Stornierungsfenster reproduziert die abendliche Aufräumaktion des Experten, einschließlich des separaten Freitags-Cutoffs.
Die Trailing-Logik folgt der ursprünglichen Steigungsformel (newStop = Bid - StopLoss - Slope * (Bid - Entry) für Longs).
Eigenkapitalbenachrichtigungen aus der Version MQL werden durch Strategieprotokollmeldungen ersetzt.
Die StockSharp-Implementierung hält ausstehende Aufträge auch dann aktiv, wenn eine Position offen ist, und entspricht damit dem Verhalten der Quelle.
Nutzungstipps
Weisen Sie ein Forex-Instrument mit den ordnungsgemäß konfigurierten Werten PriceStep, StepPrice und VolumeStep zu, um eine genaue Größenbestimmung sicherzustellen.
Kombinieren Sie die Strategie mit StockSharp Risikokontrollen (Portfoliolimits, Schutzmaßnahmen auf Connector-Ebene), wenn Sie live laufen.
Optimieren Sie ThresholdPoints, TrailingSlope und PercentOfProfit mit Designer oder Runner, um die Breakout-Empfindlichkeit an bestimmte Symbole anzupassen.
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>
/// Daily breakout strategy that enters on price crossing previous session extremes.
/// Converted from "Daily STP Entry Frame" MetaTrader expert.
/// Uses market orders when price breaks above previous high or below previous low.
/// </summary>
public class DailyStpEntryFrameStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _stopLossPoints;
private readonly StrategyParam<decimal> _takeProfitPoints;
private decimal _pipSize;
private decimal _stopLossOffset;
private decimal _takeProfitOffset;
private decimal? _previousDayHigh;
private decimal? _previousDayLow;
private decimal _currentDayHigh;
private decimal _currentDayLow;
private DateTime? _currentTradingDay;
private bool _tradedToday;
private decimal _entryPrice;
private decimal? _longStop;
private decimal? _longTake;
private decimal? _shortStop;
private decimal? _shortTake;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public decimal StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
public decimal TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
public DailyStpEntryFrameStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Time-frame for monitoring", "General");
_stopLossPoints = Param(nameof(StopLossPoints), 80m)
.SetNotNegative()
.SetDisplay("Stop-Loss (points)", "Stop-loss distance", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 200m)
.SetNotNegative()
.SetDisplay("Take-Profit (points)", "Take-profit distance", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_pipSize = 0m;
_stopLossOffset = 0m;
_takeProfitOffset = 0m;
_previousDayHigh = null;
_previousDayLow = null;
_currentDayHigh = 0m;
_currentDayLow = 0m;
_currentTradingDay = null;
_tradedToday = false;
_entryPrice = 0m;
_longStop = null;
_longTake = null;
_shortStop = null;
_shortTake = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_pipSize = Security?.PriceStep ?? 0.01m;
if (_pipSize <= 0) _pipSize = 0.01m;
_stopLossOffset = StopLossPoints * _pipSize;
_takeProfitOffset = TakeProfitPoints * _pipSize;
_previousDayHigh = null;
_previousDayLow = null;
_currentTradingDay = null;
_tradedToday = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var date = candle.OpenTime.Date;
// Track daily high/low
if (_currentTradingDay != date)
{
// Save previous day's range
if (_currentTradingDay != null)
{
_previousDayHigh = _currentDayHigh;
_previousDayLow = _currentDayLow;
}
_currentTradingDay = date;
_currentDayHigh = candle.HighPrice;
_currentDayLow = candle.LowPrice;
_tradedToday = false;
}
else
{
_currentDayHigh = Math.Max(_currentDayHigh, candle.HighPrice);
_currentDayLow = Math.Min(_currentDayLow, candle.LowPrice);
}
// Manage existing position
ManagePosition(candle);
// Check for breakout entries
if (_previousDayHigh is null || _previousDayLow is null)
return;
if (_tradedToday || Position != 0)
return;
var close = candle.ClosePrice;
// Breakout above previous day high => buy
if (close > _previousDayHigh.Value)
{
_entryPrice = close;
_longStop = _stopLossOffset > 0 ? close - _stopLossOffset : null;
_longTake = _takeProfitOffset > 0 ? close + _takeProfitOffset : null;
_shortStop = null;
_shortTake = null;
BuyMarket();
_tradedToday = true;
}
// Breakout below previous day low => sell
else if (close < _previousDayLow.Value)
{
_entryPrice = close;
_shortStop = _stopLossOffset > 0 ? close + _stopLossOffset : null;
_shortTake = _takeProfitOffset > 0 ? close - _takeProfitOffset : null;
_longStop = null;
_longTake = null;
SellMarket();
_tradedToday = true;
}
}
private void ManagePosition(ICandleMessage candle)
{
if (Position > 0)
{
if (_longStop is decimal stop && candle.LowPrice <= stop)
{
SellMarket();
_longStop = null;
_longTake = null;
return;
}
if (_longTake is decimal take && candle.HighPrice >= take)
{
SellMarket();
_longStop = null;
_longTake = null;
}
}
else if (Position < 0)
{
if (_shortStop is decimal stop && candle.HighPrice >= stop)
{
BuyMarket();
_shortStop = null;
_shortTake = null;
return;
}
if (_shortTake is decimal take && candle.LowPrice <= take)
{
BuyMarket();
_shortStop = null;
_shortTake = null;
}
}
}
}
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.Strategies import Strategy
class daily_stp_entry_frame_strategy(Strategy):
def __init__(self):
super(daily_stp_entry_frame_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Time-frame for monitoring", "General")
self._stop_loss_points = self.Param("StopLossPoints", 80.0) \
.SetDisplay("Stop-Loss (points)", "Stop-loss distance", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 200.0) \
.SetDisplay("Take-Profit (points)", "Take-profit distance", "Risk")
self._prev_day_high = None
self._prev_day_low = None
self._cur_day_high = 0.0
self._cur_day_low = 0.0
self._current_day = None
self._traded_today = False
self._entry_price = 0.0
self._long_stop = None
self._long_take = None
self._short_stop = None
self._short_take = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def StopLossPoints(self):
return float(self._stop_loss_points.Value)
@property
def TakeProfitPoints(self):
return float(self._take_profit_points.Value)
def OnStarted2(self, time):
super(daily_stp_entry_frame_strategy, self).OnStarted2(time)
self._pip_size = 0.01
sec = self.Security
if sec is not None:
ps = sec.PriceStep
if ps is not None and float(ps) > 0:
self._pip_size = float(ps)
self._sl_offset = self.StopLossPoints * self._pip_size
self._tp_offset = self.TakeProfitPoints * self._pip_size
self._prev_day_high = None
self._prev_day_low = None
self._current_day = None
self._traded_today = False
self._entry_price = 0.0
self._long_stop = None
self._long_take = None
self._short_stop = None
self._short_take = None
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
dt = candle.OpenTime
day = dt.Date
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
if self._current_day is None or self._current_day != day:
if self._current_day is not None:
self._prev_day_high = self._cur_day_high
self._prev_day_low = self._cur_day_low
self._current_day = day
self._cur_day_high = high
self._cur_day_low = low
self._traded_today = False
else:
if high > self._cur_day_high:
self._cur_day_high = high
if low < self._cur_day_low:
self._cur_day_low = low
# manage position
if self.Position > 0:
if self._long_stop is not None and low <= self._long_stop:
self.SellMarket()
self._long_stop = None
self._long_take = None
return
if self._long_take is not None and high >= self._long_take:
self.SellMarket()
self._long_stop = None
self._long_take = None
return
elif self.Position < 0:
if self._short_stop is not None and high >= self._short_stop:
self.BuyMarket()
self._short_stop = None
self._short_take = None
return
if self._short_take is not None and low <= self._short_take:
self.BuyMarket()
self._short_stop = None
self._short_take = None
return
# entries
if self._prev_day_high is None or self._prev_day_low is None:
return
if self._traded_today or self.Position != 0:
return
if close > self._prev_day_high:
self._entry_price = close
self._long_stop = close - self._sl_offset if self._sl_offset > 0 else None
self._long_take = close + self._tp_offset if self._tp_offset > 0 else None
self._short_stop = None
self._short_take = None
self.BuyMarket()
self._traded_today = True
elif close < self._prev_day_low:
self._entry_price = close
self._short_stop = close + self._sl_offset if self._sl_offset > 0 else None
self._short_take = close - self._tp_offset if self._tp_offset > 0 else None
self._long_stop = None
self._long_take = None
self.SellMarket()
self._traded_today = True
def OnReseted(self):
super(daily_stp_entry_frame_strategy, self).OnReseted()
self._prev_day_high = None
self._prev_day_low = None
self._cur_day_high = 0.0
self._cur_day_low = 0.0
self._current_day = None
self._traded_today = False
self._entry_price = 0.0
self._long_stop = None
self._long_take = None
self._short_stop = None
self._short_take = None
def CreateClone(self):
return daily_stp_entry_frame_strategy()