LeManトレンド戦略
LeManトレンド戦略は、直近の高値と安値から強気・弱気の圧力を導き出します。現在のローソク足と3つの異なるルックバック期間における最高値・最安値との距離を計算します。これらの距離は指数移動平均(EMA)で平滑化され、2本のライン(強気線と弱気線)を形成します。これらのラインのクロスオーバーは潜在的なトレンド転換を示します。
強気線が弱気線を上回ってクロスすると、戦略はロングポジションを開くか、既存のショートポジションを決済します。逆に、弱気線が強気線を上回ると、ショートポジションを開くかロングポジションを終了します。この手法は追加フィルターを使用せず、直近の高値と安値の相対的な強さのみに焦点を当てています。
詳細
- エントリー条件
- ロング: 強気線が弱気線を上抜け。
- ショート: 弱気線が強気線を上抜け。
- ロング/ショート: 両方向対応。
- エグジット条件
- 反対方向のクロスオーバーで現在のポジションを決済。
- ストップ: デフォルトなし。
- デフォルト値
Min= 13Midle= 21Max= 34EMA period= 3Time frame= 4 hours
- フィルター
- カテゴリ: トレンドフォロー
- 方向: 両方
- インジケーター: Highest, Lowest, EMA
- ストップ: いいえ
- 複雑さ: 中程度
- 時間軸: 中期
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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()