LANZ-Strategie 5.0
Die LANZ-Strategie 5.0 handelt in Richtung eines 200-Perioden-EMA und erfordert drei aufeinanderfolgende Kerzen derselben Farbe. Sie begrenzt die Trades nach täglicher Anzahl, New Yorker Zeitfenster und Mindestabstand zwischen Einstiegen.
Details
- Einstiegskriterien:
- Preis über EMA und drei bullische Kerzen für Long-Einstiege.
- Preis unter EMA und drei bärische Kerzen für Short-Einstiege (optional).
- Long/Short: Standard Long.
- Ausstiegskriterien:
- Fester Stop-Loss oder Take-Profit.
- Manuelles Schließen zur konfigurierten Zeit.
- Stops:
- Stop Loss = 40 Pips.
- Take Profit = 120 Pips.
- Standardwerte:
EmaPeriod= 200MaxTrades= 99MinDistancePips= 25StopLossPips= 40TakeProfitPips= 120StartHour= 19EndHour= 15
- Filter:
- Kategorie: Trend
- Richtung: Long
- Indikatoren: EMA
- Stops: Ja
- Komplexität: Moderat
- Zeitrahmen: Beliebig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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>
/// LANZ Strategy 5.0.
/// Three consecutive bullish candles closing above the EmaPeriod EMA go long; with EnableSell, three bearish candles below it go short,
/// reversing an opposite position. Entries are allowed only between StartHour and EndHour (UTC, the window may cross midnight), at most
/// MaxTrades per day and at least MinDistancePips price steps away from the previous entry. A fixed stop and target in price steps protect
/// each position, and any open position is closed once the window ends.
/// </summary>
public class Lanz50Strategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _maxTrades;
private readonly StrategyParam<decimal> _minDistancePips;
private readonly StrategyParam<decimal> _stopLossPips;
private readonly StrategyParam<decimal> _takeProfitPips;
private readonly StrategyParam<int> _startHour;
private readonly StrategyParam<int> _endHour;
private readonly StrategyParam<bool> _enableBuy;
private readonly StrategyParam<bool> _enableSell;
private readonly StrategyParam<DataType> _candleType;
private decimal? _lastEntryPrice;
private int _dailyTrades;
private DateTime _currentDay;
private int _bullishCount;
private int _bearishCount;
/// <summary>
/// EMA trend filter period.
/// </summary>
public int EmaPeriod
{
get => _emaPeriod.Value;
set => _emaPeriod.Value = value;
}
/// <summary>
/// Maximum entries per day.
/// </summary>
public int MaxTrades
{
get => _maxTrades.Value;
set => _maxTrades.Value = value;
}
/// <summary>
/// Minimum distance from the previous entry in price steps.
/// </summary>
public decimal MinDistancePips
{
get => _minDistancePips.Value;
set => _minDistancePips.Value = value;
}
/// <summary>
/// Stop loss in price steps.
/// </summary>
public decimal StopLossPips
{
get => _stopLossPips.Value;
set => _stopLossPips.Value = value;
}
/// <summary>
/// Take profit in price steps.
/// </summary>
public decimal TakeProfitPips
{
get => _takeProfitPips.Value;
set => _takeProfitPips.Value = value;
}
/// <summary>
/// Hour (UTC) the trading window opens.
/// </summary>
public int StartHour
{
get => _startHour.Value;
set => _startHour.Value = value;
}
/// <summary>
/// Hour (UTC) the trading window closes and positions are closed.
/// </summary>
public int EndHour
{
get => _endHour.Value;
set => _endHour.Value = value;
}
/// <summary>
/// Allow long entries.
/// </summary>
public bool EnableBuy
{
get => _enableBuy.Value;
set => _enableBuy.Value = value;
}
/// <summary>
/// Allow short entries.
/// </summary>
public bool EnableSell
{
get => _enableSell.Value;
set => _enableSell.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize <see cref="Lanz50Strategy"/>.
/// </summary>
public Lanz50Strategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 200)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA trend filter period", "Indicators");
_maxTrades = Param(nameof(MaxTrades), 99)
.SetGreaterThanZero()
.SetDisplay("Max Trades", "Maximum entries per day", "Risk");
_minDistancePips = Param(nameof(MinDistancePips), 25m)
.SetNotNegative()
.SetDisplay("Min Distance", "Minimum distance from the previous entry in price steps", "Risk");
_stopLossPips = Param(nameof(StopLossPips), 40m)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop loss in price steps", "Risk");
_takeProfitPips = Param(nameof(TakeProfitPips), 120m)
.SetNotNegative()
.SetDisplay("Take Profit", "Take profit in price steps", "Risk");
_startHour = Param(nameof(StartHour), 19)
.SetRange(0, 23)
.SetDisplay("Start Hour", "Hour (UTC) the trading window opens", "Time");
_endHour = Param(nameof(EndHour), 15)
.SetRange(0, 23)
.SetDisplay("End Hour", "Hour (UTC) the trading window closes and positions are closed", "Time");
_enableBuy = Param(nameof(EnableBuy), true)
.SetDisplay("Enable Buy", "Allow long entries", "Mode");
_enableSell = Param(nameof(EnableSell), false)
.SetDisplay("Enable Sell", "Allow short entries", "Mode");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
ResetState();
}
private void ResetState()
{
_lastEntryPrice = null;
_dailyTrades = 0;
_currentDay = default;
_bullishCount = 0;
_bearishCount = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, ProcessCandle)
.Start();
var step = Security?.PriceStep ?? 1m;
StartProtection(
TakeProfitPips > 0m ? new Unit(TakeProfitPips * step, UnitTypes.Absolute) : new Unit(),
StopLossPips > 0m ? new Unit(StopLossPips * step, UnitTypes.Absolute) : new Unit(),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
_bullishCount = candle.ClosePrice > candle.OpenPrice ? _bullishCount + 1 : 0;
_bearishCount = candle.ClosePrice < candle.OpenPrice ? _bearishCount + 1 : 0;
var time = candle.OpenTime;
if (time.Date != _currentDay)
{
_currentDay = time.Date;
_dailyTrades = 0;
}
if (!IsFormedAndOnlineAndAllowTrading())
return;
var hour = time.Hour;
var inWindow = StartHour <= EndHour
? hour >= StartHour && hour < EndHour
: hour >= StartHour || hour < EndHour;
if (!inWindow)
{
if (Position > 0)
SellMarket(Position);
else if (Position < 0)
BuyMarket(-Position);
return;
}
if (_dailyTrades >= MaxTrades)
return;
var close = candle.ClosePrice;
var step = Security.PriceStep ?? 1m;
if (_lastEntryPrice is decimal lastEntry && Math.Abs(close - lastEntry) < MinDistancePips * step)
return;
if (EnableBuy && _bullishCount >= 3 && close > emaValue && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
_dailyTrades++;
_lastEntryPrice = close;
}
else if (EnableSell && _bearishCount >= 3 && close < emaValue && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
_dailyTrades++;
_lastEntryPrice = close;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class lanz_50_strategy(Strategy):
"""
LANZ Strategy 5.0.
Three consecutive bullish candles closing above the EmaPeriod EMA go long; with EnableSell, three bearish candles below it go short,
reversing an opposite position. Entries are allowed only between StartHour and EndHour (UTC, the window may cross midnight), at most
MaxTrades per day and at least MinDistancePips price steps away from the previous entry. A fixed stop and target in price steps protect
each position, and any open position is closed once the window ends.
"""
def __init__(self):
super(lanz_50_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 200).SetGreaterThanZero().SetDisplay("EMA Period", "EMA trend filter period", "Indicators")
self._max_trades = self.Param("MaxTrades", 99).SetGreaterThanZero().SetDisplay("Max Trades", "Maximum entries per day", "Risk")
self._min_distance_pips = self.Param("MinDistancePips", 25.0).SetNotNegative().SetDisplay("Min Distance", "Minimum distance from the previous entry in price steps", "Risk")
self._stop_loss_pips = self.Param("StopLossPips", 40.0).SetNotNegative().SetDisplay("Stop Loss", "Stop loss in price steps", "Risk")
self._take_profit_pips = self.Param("TakeProfitPips", 120.0).SetNotNegative().SetDisplay("Take Profit", "Take profit in price steps", "Risk")
self._start_hour = self.Param("StartHour", 19).SetRange(0, 23).SetDisplay("Start Hour", "Hour (UTC) the trading window opens", "Time")
self._end_hour = self.Param("EndHour", 15).SetRange(0, 23).SetDisplay("End Hour", "Hour (UTC) the trading window closes and positions are closed", "Time")
self._enable_buy = self.Param("EnableBuy", True).SetDisplay("Enable Buy", "Allow long entries", "Mode")
self._enable_sell = self.Param("EnableSell", False).SetDisplay("Enable Sell", "Allow short entries", "Mode")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._last_entry_price = None
self._daily_trades = 0
self._current_day = None
self._bullish_count = 0
self._bearish_count = 0
def OnReseted(self):
super(lanz_50_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(lanz_50_strategy, self).OnStarted2(time)
self._reset_state()
ema = ExponentialMovingAverage()
ema.Length = self._ema_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, self._process_candle).Start()
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
tp = float(self._take_profit_pips.Value)
sl = float(self._stop_loss_pips.Value)
self.StartProtection(
Unit(Decimal(tp * step), UnitTypes.Absolute) if tp > 0 else Unit(),
Unit(Decimal(sl * step), UnitTypes.Absolute) if sl > 0 else Unit(),
useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
open_p = float(candle.OpenPrice)
close = float(candle.ClosePrice)
ema = float(ema_value)
self._bullish_count = self._bullish_count + 1 if close > open_p else 0
self._bearish_count = self._bearish_count + 1 if close < open_p else 0
time = candle.OpenTime
if self._current_day is None or time.Date != self._current_day:
self._current_day = time.Date
self._daily_trades = 0
if not self.IsFormedAndOnlineAndAllowTrading():
return
hour = time.Hour
start = self._start_hour.Value
end = self._end_hour.Value
if start <= end:
in_window = start <= hour < end
else:
in_window = hour >= start or hour < end
if not in_window:
if self.Position > 0:
self.SellMarket(self.Position)
elif self.Position < 0:
self.BuyMarket(-self.Position)
return
if self._daily_trades >= self._max_trades.Value:
return
step = float(self.Security.PriceStep) if self.Security.PriceStep is not None else 1.0
if self._last_entry_price is not None and abs(close - self._last_entry_price) < float(self._min_distance_pips.Value) * step:
return
if self._enable_buy.Value and self._bullish_count >= 3 and close > ema and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._daily_trades += 1
self._last_entry_price = close
elif self._enable_sell.Value and self._bearish_count >= 3 and close < ema and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._daily_trades += 1
self._last_entry_price = close
def CreateClone(self):
return lanz_50_strategy()