Die Lbs V12-Strategie ist eine Konvertierung des MetaTrader Expert Advisors LBS_V12.mq4. Es öffnet ein Paar Breakout-Stop-Orders rund um die vorherige 15-Minuten-Kerze, wenn die konfigurierte Triggerstunde beginnt. Beide Orders werden durch den aktuellen Average True Range (ATR)-Wert ausgeglichen, um kurzfristige Volatilität zu berücksichtigen. Die Strategie versucht, den ersten Impuls der Handelssitzung zu erfassen und verwaltet Ausstiege durch virtuelle Stop-Loss-, Take-Profit- und Trailing-Regeln, die für jede abgeschlossene Kerze ausgewertet werden.
Handelslogik
Die Strategie überwacht fertige Kerzen des ausgewählten Zeitrahmens (standardmäßig 15 Minuten).
Wenn eine neue Kerze mit der Minute 00 am konfigurierten TriggerHour erscheint, wird die vorherige Kerze zum Referenzbereich.
Wenn für den aktuellen Tag keine offenen Positionen und keine funktionierenden Orders vorhanden sind, werden zwei Stop-Orders gesendet:
Kaufstopp über dem Referenzhoch plus dem Instrumenten-Spread, einem Preisschritt und dem letzten ATR-Wert.
Verkaufsstopp unterhalb des Referenztiefs abzüglich der gleichen Puffer.
Schutzpreisniveaus für jede Seite werden intern gespeichert:
Der Stop-Loss wird jenseits des entgegengesetzten Extrems der Referenzkerze platziert.
Der Take-Profit wird anhand der Punktentfernung im MetaTrader-Stil berechnet.
Ein Trailing Stop wird aktiviert, sobald sich der Handel weiter als die konfigurierte Distanz bewegt.
Wenn eine Long- oder Short-Position eröffnet wird, wird die entgegengesetzte Stop-Order aufgehoben. Der gesamte Schutz wird virtuell angewendet: Kerzenhochs und -tiefs werden mit den gespeicherten Stop/Take-Werten verglichen und die Position wird mit Marktaufträgen geschlossen, wenn die Limits erreicht sind.
Die Strategie wird nur einmal pro Tag ausgeführt. Alle ausstehenden Aufträge und der interne Status werden zu Beginn eines neuen Handelsdatums gelöscht.
Parameter
Name
Beschreibung
Standard
Volume
Handelsvolumen in Lots.
1
TriggerHour
Stunde des Tages (Terminalzeitzone), zu der die Breakout-Orders gesendet werden sollen.
9
TakeProfitPoints
MetaTrader-ähnliche Punkte zwischen dem Einstiegspreis und dem Take-Profit-Ziel.
100
TrailingStopPoints
Punkte im MetaTrader-Stil, die für den Trailing Stop verwendet werden, nachdem der Trade in die Gewinnzone übergeht.
20
AtrPeriod
Zeitraum des Indikators ATR, der die ausstehenden Aufträge ausgleicht.
3
CandleType
Kerzentyp, der für Signalberechnungen verwendet wird. Der Standardwert sind Kerzen mit einem Zeitrahmen von 15 Minuten.
15m timeframe
Risikomanagement
Ausstiege werden durch Marktaufträge ausgeführt, wenn die Kerzenextreme die virtuellen Stop-Loss- oder Take-Profit-Niveaus berühren.
Der Trailing Stop erhöht (für Long-Positionen) oder verringert (für Short-Positionen) das Schutzniveau, wenn der Trade mehr als die konfigurierte Distanz gewinnt.
Durch das tägliche Zurücksetzen wird sichergestellt, dass die Strategie nicht mehrere Positionen oder veraltete ausstehende Aufträge ansammelt.
Notizen
Genaue Bid/Ask-Aktualisierungen verbessern die Spread-Kompensation, die zu den Breakout-Preisen hinzugefügt wird. Wenn keine Spread-Daten verfügbar sind, fällt die Strategie auf einen Preisschritt zurück.
Die Konvertierung behält die ursprünglichen MetaTrader-Standardwerte bei, passt jedoch die Take-Profit-Behandlung für Short-Positionen an, sodass das Ziel immer in die profitable Richtung gelegt wird.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// LBS V12 strategy - ATR channel breakout with EMA trend.
/// Buys when close breaks above EMA + ATR.
/// Sells when close breaks below EMA - ATR.
/// </summary>
public class LbsV12Strategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrMultiplier;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private int _cooldownRemaining;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public decimal AtrMultiplier { get => _atrMultiplier.Value; set => _atrMultiplier.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public LbsV12Strategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 50)
.SetDisplay("EMA Period", "EMA lookback", "Indicators");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetDisplay("ATR Period", "ATR lookback", "Indicators");
_atrMultiplier = Param(nameof(AtrMultiplier), 3m)
.SetDisplay("ATR Multiplier", "Channel width multiplier", "Indicators");
_cooldownCandles = Param(nameof(CooldownCandles), 100)
.SetDisplay("Cooldown", "Candles between signals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_cooldownRemaining = 0;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, atr, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema, decimal atr)
{
if (candle.State != CandleStates.Finished) return;
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
return;
}
var close = candle.ClosePrice;
var mult = AtrMultiplier;
if (close > ema + atr * mult && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (close < ema - atr * mult && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
}
}
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 ExponentialMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class lbs_v12_strategy(Strategy):
def __init__(self):
super(lbs_v12_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 50) \
.SetDisplay("EMA Period", "EMA lookback", "Indicators")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR lookback", "Indicators")
self._atr_multiplier = self.Param("AtrMultiplier", 3.0) \
.SetDisplay("ATR Multiplier", "Channel width multiplier", "Indicators")
self._cooldown_candles = self.Param("CooldownCandles", 100) \
.SetDisplay("Cooldown", "Candles between signals", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._cooldown_remaining = 0
@property
def ema_period(self):
return self._ema_period.Value
@property
def atr_period(self):
return self._atr_period.Value
@property
def atr_multiplier(self):
return self._atr_multiplier.Value
@property
def cooldown_candles(self):
return self._cooldown_candles.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(lbs_v12_strategy, self).OnReseted()
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(lbs_v12_strategy, self).OnStarted2(time)
self._cooldown_remaining = 0
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
atr = AverageTrueRange()
atr.Length = self.atr_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, atr, self.process_candle).Start()
def process_candle(self, candle, ema, atr):
if candle.State != CandleStates.Finished:
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
return
close = float(candle.ClosePrice)
ema_val = float(ema)
atr_val = float(atr)
mult = float(self.atr_multiplier)
if close > ema_val + atr_val * mult and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown_remaining = self.cooldown_candles
elif close < ema_val - atr_val * mult and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown_remaining = self.cooldown_candles
def CreateClone(self):
return lbs_v12_strategy()