LeMan-Trend-Strategie
Die LeMan-Trend-Strategie leitet bullischen und bearischen Druck aus den jüngsten Hochs und Tiefs ab. Sie berechnet den Abstand zwischen der aktuellen Kerze und den höchsten Hochs sowie den tiefsten Tiefs über drei verschiedene Rückblickperioden. Diese Abstände werden mit einem exponentiellen gleitenden Durchschnitt (EMA) geglättet, um zwei Linien zu bilden: Bullen und Bären. Ein Kreuzungspunkt zwischen diesen Linien signalisiert potenzielle Trendwechsel.
Wenn die Bullenlinie die Bärenlinie von unten nach oben kreuzt, öffnet die Strategie eine Long-Position oder schließt eine bestehende Short-Position. Umgekehrt, wenn die Bärenlinie über die Bullenlinie steigt, öffnet sie eine Short-Position oder verlässt eine Long-Position. Die Methode verwendet keine zusätzlichen Filter und konzentriert sich ausschließlich auf die relative Stärke der jüngsten Hochs und Tiefs.
Details
- Einstiegskriterien
- Long: Bullenlinie kreuzt über die Bärenlinie.
- Short: Bärenlinie kreuzt über die Bullenlinie.
- Long/Short: Beide Seiten unterstützt.
- Ausstiegskriterien
- Die entgegengesetzte Kreuzung schließt die aktive Position.
- Stops: Standardmäßig keine.
- Standardwerte
Min= 13Midle= 21Max= 34EMA period= 3Time frame= 4 hours
- Filter
- Kategorie: Trendfolge
- Richtung: Beide
- Indikatoren: Highest, Lowest, EMA
- Stops: Nein
- Komplexität: Moderat
- Zeitrahmen: Mittelfristig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Moderat
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Leman Trend strategy using high/low differences smoothed by EMA.
/// Opens long when bullish pressure exceeds bearish, short otherwise.
/// </summary>
public class LeManTrendStrategy : Strategy
{
private readonly StrategyParam<int> _min;
private readonly StrategyParam<int> _midle;
private readonly StrategyParam<int> _max;
private readonly StrategyParam<int> _periodEma;
private readonly StrategyParam<DataType> _candleType;
private Highest _highMin;
private Highest _highMidle;
private Highest _highMax;
private Lowest _lowMin;
private Lowest _lowMidle;
private Lowest _lowMax;
private ExponentialMovingAverage _bullsEma;
private ExponentialMovingAverage _bearsEma;
private decimal _prevBulls;
private decimal _prevBears;
public int Min
{
get => _min.Value;
set => _min.Value = value;
}
public int Midle
{
get => _midle.Value;
set => _midle.Value = value;
}
public int Max
{
get => _max.Value;
set => _max.Value = value;
}
public int PeriodEma
{
get => _periodEma.Value;
set => _periodEma.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public LeManTrendStrategy()
{
_min = Param(nameof(Min), 13)
.SetGreaterThanZero()
.SetDisplay("Min Period", "Minimum lookback for highs/lows", "Indicator")
.SetOptimize(5, 25, 1);
_midle = Param(nameof(Midle), 21)
.SetGreaterThanZero()
.SetDisplay("Middle Period", "Middle lookback for highs/lows", "Indicator")
.SetOptimize(10, 40, 1);
_max = Param(nameof(Max), 34)
.SetGreaterThanZero()
.SetDisplay("Max Period", "Maximum lookback for highs/lows", "Indicator")
.SetOptimize(20, 60, 1);
_periodEma = Param(nameof(PeriodEma), 3)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "Smoothing period for bulls/bears", "Indicator")
.SetOptimize(2, 10, 1);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Time frame for calculations", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
protected override void OnReseted()
{
base.OnReseted();
_highMin = default;
_highMidle = default;
_highMax = default;
_lowMin = default;
_lowMidle = default;
_lowMax = default;
_bullsEma = default;
_bearsEma = default;
_prevBulls = default;
_prevBears = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_highMin = new Highest { Length = Min };
_highMidle = new Highest { Length = Midle };
_highMax = new Highest { Length = Max };
_lowMin = new Lowest { Length = Min };
_lowMidle = new Lowest { Length = Midle };
_lowMax = new Lowest { Length = Max };
_bullsEma = new ExponentialMovingAverage { Length = PeriodEma };
_bearsEma = new ExponentialMovingAverage { Length = PeriodEma };
Indicators.Add(_highMin);
Indicators.Add(_highMidle);
Indicators.Add(_highMax);
Indicators.Add(_lowMin);
Indicators.Add(_lowMidle);
Indicators.Add(_lowMax);
Indicators.Add(_bullsEma);
Indicators.Add(_bearsEma);
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var closeInput = new DecimalIndicatorValue(_highMin, candle.ClosePrice, candle.OpenTime) { IsFinal = true };
var highMinVal = _highMin.Process(closeInput).ToDecimal();
var highMidleVal = _highMidle.Process(new DecimalIndicatorValue(_highMidle, candle.ClosePrice, candle.OpenTime) { IsFinal = true }).ToDecimal();
var highMaxVal = _highMax.Process(new DecimalIndicatorValue(_highMax, candle.ClosePrice, candle.OpenTime) { IsFinal = true }).ToDecimal();
var lowMinVal = _lowMin.Process(new DecimalIndicatorValue(_lowMin, candle.ClosePrice, candle.OpenTime) { IsFinal = true }).ToDecimal();
var lowMidleVal = _lowMidle.Process(new DecimalIndicatorValue(_lowMidle, candle.ClosePrice, candle.OpenTime) { IsFinal = true }).ToDecimal();
var lowMaxVal = _lowMax.Process(new DecimalIndicatorValue(_lowMax, candle.ClosePrice, candle.OpenTime) { IsFinal = true }).ToDecimal();
if (!_highMax.IsFormed || !_lowMax.IsFormed)
return;
var hh = (candle.HighPrice - highMinVal) + (candle.HighPrice - highMidleVal) + (candle.HighPrice - highMaxVal);
var ll = (lowMinVal - candle.LowPrice) + (lowMidleVal - candle.LowPrice) + (lowMaxVal - candle.LowPrice);
var bullsVal = _bullsEma.Process(new DecimalIndicatorValue(_bullsEma, hh, candle.OpenTime) { IsFinal = true }).ToDecimal();
var bearsVal = _bearsEma.Process(new DecimalIndicatorValue(_bearsEma, ll, candle.OpenTime) { IsFinal = true }).ToDecimal();
if (!_bullsEma.IsFormed || !_bearsEma.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_prevBulls <= _prevBears && bullsVal > bearsVal && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (_prevBulls >= _prevBears && bullsVal < bearsVal && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevBulls = bullsVal;
_prevBears = bearsVal;
}
}
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, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class le_man_trend_strategy(Strategy):
def __init__(self):
super(le_man_trend_strategy, self).__init__()
self._min = self.Param("Min", 13) \
.SetDisplay("Min Period", "Minimum lookback for highs/lows", "Indicator")
self._midle = self.Param("Midle", 21) \
.SetDisplay("Middle Period", "Middle lookback for highs/lows", "Indicator")
self._max = self.Param("Max", 34) \
.SetDisplay("Max Period", "Maximum lookback for highs/lows", "Indicator")
self._period_ema = self.Param("PeriodEma", 3) \
.SetDisplay("EMA Period", "Smoothing period for bulls/bears", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Time frame for calculations", "General")
self._high_min = None
self._high_midle = None
self._high_max = None
self._low_min = None
self._low_midle = None
self._low_max = None
self._bulls_ema = None
self._bears_ema = None
self._prev_bulls = 0.0
self._prev_bears = 0.0
@property
def min_period(self):
return self._min.Value
@property
def midle_period(self):
return self._midle.Value
@property
def max_period(self):
return self._max.Value
@property
def period_ema(self):
return self._period_ema.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(le_man_trend_strategy, self).OnReseted()
self._high_min = None
self._high_midle = None
self._high_max = None
self._low_min = None
self._low_midle = None
self._low_max = None
self._bulls_ema = None
self._bears_ema = None
self._prev_bulls = 0.0
self._prev_bears = 0.0
def OnStarted2(self, time):
super(le_man_trend_strategy, self).OnStarted2(time)
self._high_min = Highest()
self._high_min.Length = self.min_period
self._high_midle = Highest()
self._high_midle.Length = self.midle_period
self._high_max = Highest()
self._high_max.Length = self.max_period
self._low_min = Lowest()
self._low_min.Length = self.min_period
self._low_midle = Lowest()
self._low_midle.Length = self.midle_period
self._low_max = Lowest()
self._low_max.Length = self.max_period
self._bulls_ema = ExponentialMovingAverage()
self._bulls_ema.Length = self.period_ema
self._bears_ema = ExponentialMovingAverage()
self._bears_ema.Length = self.period_ema
self.Indicators.Add(self._high_min)
self.Indicators.Add(self._high_midle)
self.Indicators.Add(self._high_max)
self.Indicators.Add(self._low_min)
self.Indicators.Add(self._low_midle)
self.Indicators.Add(self._low_max)
self.Indicators.Add(self._bulls_ema)
self.Indicators.Add(self._bears_ema)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
close_val = candle.ClosePrice
t = candle.OpenTime
high_min_val = float(process_float(self._high_min, close_val, t, True))
high_midle_val = float(process_float(self._high_midle, close_val, t, True))
high_max_val = float(process_float(self._high_max, close_val, t, True))
low_min_val = float(process_float(self._low_min, close_val, t, True))
low_midle_val = float(process_float(self._low_midle, close_val, t, True))
low_max_val = float(process_float(self._low_max, close_val, t, True))
if not self._high_max.IsFormed or not self._low_max.IsFormed:
return
high = float(candle.HighPrice)
low = float(candle.LowPrice)
hh = (high - high_min_val) + (high - high_midle_val) + (high - high_max_val)
ll = (low_min_val - low) + (low_midle_val - low) + (low_max_val - low)
bulls_val = float(process_float(self._bulls_ema, hh, t, True))
bears_val = float(process_float(self._bears_ema, ll, t, True))
if not self._bulls_ema.IsFormed or not self._bears_ema.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self._prev_bulls <= self._prev_bears and bulls_val > bears_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_bulls >= self._prev_bears and bulls_val < bears_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_bulls = bulls_val
self._prev_bears = bears_val
def CreateClone(self):
return le_man_trend_strategy()