Стратегия Color LeMan Trend
Стратегия является портом оригинального советника MQL5 ColorLeManTrend. Индикатор строит бычью и медвежью линии на основе экстремумов цен за три разные глубины и сглаживает их экспоненциальным средним.
Идея
- Если на предыдущей свече бычья линия была выше медвежьей, а на текущей свече бычья линия опускается ниже медвежьей, формируется сигнал покупки.
- Если на предыдущей свече бычья линия была ниже медвежьей, а на текущей свече поднимается выше, формируется сигнал продажи.
- Дополнительные параметры позволяют разрешать или запрещать открытие и закрытие позиций.
Параметры
CandleType– таймфрейм для расчёта индикатора.Min– период расчёта коротких экстремумов.Midle– период расчёта средних экстремумов.Max– период расчёта длинных экстремумов.PeriodEma– период сглаживания линий.StopLossPoints– стоп‑лосс в пунктах.TakeProfitPoints– тейк‑профит в пунктах.AllowBuy– разрешить открытия длинных позиций.AllowSell– разрешить открытия коротких позиций.AllowBuyClose– разрешить закрытие длинных позиций.AllowSellClose– разрешить закрытие коротких позиций.Volume– объём сделки.
Примечания
Стратегия обрабатывает только завершённые свечи и использует рыночные заявки. Стоп‑лосс и тейк‑профит устанавливаются стандартным механизмом защиты позиции.
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>
/// Strategy based on the Color LeMan Trend indicator.
/// </summary>
public class ColorLemanTrendStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _minPeriod;
private readonly StrategyParam<int> _midPeriod;
private readonly StrategyParam<int> _maxPeriod;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<decimal> _stopLossPoints;
private readonly StrategyParam<decimal> _takeProfitPoints;
private readonly StrategyParam<bool> _allowBuy;
private readonly StrategyParam<bool> _allowSell;
private readonly StrategyParam<bool> _allowBuyClose;
private readonly StrategyParam<bool> _allowSellClose;
private ExponentialMovingAverage _bullsEma;
private ExponentialMovingAverage _bearsEma;
private decimal? _prevBulls;
private decimal? _prevBears;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int Min { get => _minPeriod.Value; set => _minPeriod.Value = value; }
public int Midle { get => _midPeriod.Value; set => _midPeriod.Value = value; }
public int Max { get => _maxPeriod.Value; set => _maxPeriod.Value = value; }
public int PeriodEma { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public decimal StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public decimal TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public bool AllowBuy { get => _allowBuy.Value; set => _allowBuy.Value = value; }
public bool AllowSell { get => _allowSell.Value; set => _allowSell.Value = value; }
public bool AllowBuyClose { get => _allowBuyClose.Value; set => _allowBuyClose.Value = value; }
public bool AllowSellClose { get => _allowSellClose.Value; set => _allowSellClose.Value = value; }
/// <summary>
/// Initializes a new instance of <see cref="ColorLemanTrendStrategy"/>.
/// </summary>
public ColorLemanTrendStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for indicator", "General");
_minPeriod = Param(nameof(Min), 13)
.SetGreaterThanZero()
.SetDisplay("Min", "Shortest period", "Indicator")
;
_midPeriod = Param(nameof(Midle), 21)
.SetGreaterThanZero()
.SetDisplay("Midle", "Middle period", "Indicator")
;
_maxPeriod = Param(nameof(Max), 34)
.SetGreaterThanZero()
.SetDisplay("Max", "Longest period", "Indicator")
;
_emaPeriod = Param(nameof(PeriodEma), 3)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "Smoothing length", "Indicator")
;
_stopLossPoints = Param(nameof(StopLossPoints), 1000m)
.SetDisplay("Stop Loss", "Stop loss in points", "Protection")
;
_takeProfitPoints = Param(nameof(TakeProfitPoints), 2000m)
.SetDisplay("Take Profit", "Take profit in points", "Protection")
;
_allowBuy = Param(nameof(AllowBuy), true)
.SetDisplay("Allow Buy", "Enable long entries", "Trading");
_allowSell = Param(nameof(AllowSell), true)
.SetDisplay("Allow Sell", "Enable short entries", "Trading");
_allowBuyClose = Param(nameof(AllowBuyClose), true)
.SetDisplay("Allow Buy Close", "Allow closing longs", "Trading");
_allowSellClose = Param(nameof(AllowSellClose), true)
.SetDisplay("Allow Sell Close", "Allow closing shorts", "Trading");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_bullsEma?.Reset();
_bearsEma?.Reset();
_bullsEma = null!;
_bearsEma = null!;
_prevBulls = null;
_prevBears = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_bullsEma = new EMA { Length = PeriodEma };
_bearsEma = new EMA { Length = PeriodEma };
var highestMin = new Highest { Length = Min };
var highestMid = new Highest { Length = Midle };
var highestMax = new Highest { Length = Max };
var lowestMin = new Lowest { Length = Min };
var lowestMid = new Lowest { Length = Midle };
var lowestMax = new Lowest { Length = Max };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highestMin, highestMid, highestMax, lowestMin, lowestMid, lowestMax, ProcessCandle)
.Start();
StartProtection(
new Unit(TakeProfitPoints, UnitTypes.Absolute),
new Unit(StopLossPoints, UnitTypes.Absolute),
false);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle,
decimal highestMin, decimal highestMid, decimal highestMax,
decimal lowestMin, decimal lowestMid, decimal lowestMax)
{
if (candle.State != CandleStates.Finished)
return;
var hh = 3m * candle.HighPrice - (highestMin + highestMid + highestMax);
var ll = (lowestMin + lowestMid + lowestMax) - 3m * candle.LowPrice;
var bullsValue = _bullsEma.Process(hh, candle.OpenTime, true);
var bearsValue = _bearsEma.Process(ll, candle.OpenTime, true);
if (!bullsValue.IsFinal || !bearsValue.IsFinal || bullsValue.IsEmpty || bearsValue.IsEmpty)
return;
if (!_bullsEma.IsFormed || !_bearsEma.IsFormed)
return;
var bulls = bullsValue.ToDecimal();
var bears = bearsValue.ToDecimal();
bool buyOpen = false;
bool sellOpen = false;
bool buyClose = false;
bool sellClose = false;
if (_prevBulls is decimal prevUp && _prevBears is decimal prevDn)
{
if (prevUp > prevDn)
{
if (AllowBuy && bulls <= bears)
buyOpen = true;
if (AllowSellClose)
sellClose = true;
}
if (prevUp < prevDn)
{
if (AllowSell && bulls >= bears)
sellOpen = true;
if (AllowBuyClose)
buyClose = true;
}
}
_prevBulls = bulls;
_prevBears = bears;
if (sellClose && Position < 0)
BuyMarket(Volume);
if (buyClose && Position > 0)
SellMarket(Volume);
if (buyOpen && Position <= 0)
BuyMarket(Volume);
if (sellOpen && Position >= 0)
SellMarket(Volume);
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage, Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class color_leman_trend_strategy(Strategy):
def __init__(self):
super(color_leman_trend_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for indicator", "General")
self._min_period = self.Param("Min", 13) \
.SetDisplay("Min", "Shortest period", "Indicator")
self._mid_period = self.Param("Midle", 21) \
.SetDisplay("Midle", "Middle period", "Indicator")
self._max_period = self.Param("Max", 34) \
.SetDisplay("Max", "Longest period", "Indicator")
self._ema_period = self.Param("PeriodEma", 3) \
.SetDisplay("EMA Period", "Smoothing length", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 1000.0) \
.SetDisplay("Stop Loss", "Stop loss in points", "Protection")
self._take_profit_points = self.Param("TakeProfitPoints", 2000.0) \
.SetDisplay("Take Profit", "Take profit in points", "Protection")
self._allow_buy = self.Param("AllowBuy", True) \
.SetDisplay("Allow Buy", "Enable long entries", "Trading")
self._allow_sell = self.Param("AllowSell", True) \
.SetDisplay("Allow Sell", "Enable short entries", "Trading")
self._allow_buy_close = self.Param("AllowBuyClose", True) \
.SetDisplay("Allow Buy Close", "Allow closing longs", "Trading")
self._allow_sell_close = self.Param("AllowSellClose", True) \
.SetDisplay("Allow Sell Close", "Allow closing shorts", "Trading")
self._bulls_ema = None
self._bears_ema = None
self._prev_bulls = None
self._prev_bears = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def Min(self):
return self._min_period.Value
@Min.setter
def Min(self, value):
self._min_period.Value = value
@property
def Midle(self):
return self._mid_period.Value
@Midle.setter
def Midle(self, value):
self._mid_period.Value = value
@property
def Max(self):
return self._max_period.Value
@Max.setter
def Max(self, value):
self._max_period.Value = value
@property
def PeriodEma(self):
return self._ema_period.Value
@PeriodEma.setter
def PeriodEma(self, value):
self._ema_period.Value = value
@property
def StopLossPoints(self):
return self._stop_loss_points.Value
@StopLossPoints.setter
def StopLossPoints(self, value):
self._stop_loss_points.Value = value
@property
def TakeProfitPoints(self):
return self._take_profit_points.Value
@TakeProfitPoints.setter
def TakeProfitPoints(self, value):
self._take_profit_points.Value = value
@property
def AllowBuy(self):
return self._allow_buy.Value
@AllowBuy.setter
def AllowBuy(self, value):
self._allow_buy.Value = value
@property
def AllowSell(self):
return self._allow_sell.Value
@AllowSell.setter
def AllowSell(self, value):
self._allow_sell.Value = value
@property
def AllowBuyClose(self):
return self._allow_buy_close.Value
@AllowBuyClose.setter
def AllowBuyClose(self, value):
self._allow_buy_close.Value = value
@property
def AllowSellClose(self):
return self._allow_sell_close.Value
@AllowSellClose.setter
def AllowSellClose(self, value):
self._allow_sell_close.Value = value
def OnStarted2(self, time):
super(color_leman_trend_strategy, self).OnStarted2(time)
self._bulls_ema = ExponentialMovingAverage()
self._bulls_ema.Length = self.PeriodEma
self._bears_ema = ExponentialMovingAverage()
self._bears_ema.Length = self.PeriodEma
highest_min = Highest()
highest_min.Length = self.Min
highest_mid = Highest()
highest_mid.Length = self.Midle
highest_max = Highest()
highest_max.Length = self.Max
lowest_min = Lowest()
lowest_min.Length = self.Min
lowest_mid = Lowest()
lowest_mid.Length = self.Midle
lowest_max = Lowest()
lowest_max.Length = self.Max
self.SubscribeCandles(self.CandleType) \
.Bind(highest_min, highest_mid, highest_max, lowest_min, lowest_mid, lowest_max, self.ProcessCandle) \
.Start()
self.StartProtection(
takeProfit=Unit(self.TakeProfitPoints, UnitTypes.Absolute),
stopLoss=Unit(self.StopLossPoints, UnitTypes.Absolute)
)
def ProcessCandle(self, candle, h_min, h_mid, h_max, l_min, l_mid, l_max):
if candle.State != CandleStates.Finished:
return
high = float(candle.HighPrice)
low = float(candle.LowPrice)
hh = 3.0 * high - (float(h_min) + float(h_mid) + float(h_max))
ll = (float(l_min) + float(l_mid) + float(l_max)) - 3.0 * low
t = candle.OpenTime
bulls_result = process_float(self._bulls_ema, hh, t, True)
bears_result = process_float(self._bears_ema, ll, t, True)
if bulls_result.IsEmpty or bears_result.IsEmpty:
return
if not self._bulls_ema.IsFormed or not self._bears_ema.IsFormed:
return
bulls = float(bulls_result)
bears = float(bears_result)
buy_open = False
sell_open = False
buy_close = False
sell_close = False
if self._prev_bulls is not None and self._prev_bears is not None:
if self._prev_bulls > self._prev_bears:
if self.AllowBuy and bulls <= bears:
buy_open = True
if self.AllowSellClose:
sell_close = True
if self._prev_bulls < self._prev_bears:
if self.AllowSell and bulls >= bears:
sell_open = True
if self.AllowBuyClose:
buy_close = True
self._prev_bulls = bulls
self._prev_bears = bears
if sell_close and self.Position < 0:
self.BuyMarket()
if buy_close and self.Position > 0:
self.SellMarket()
if buy_open and self.Position <= 0:
self.BuyMarket()
if sell_open and self.Position >= 0:
self.SellMarket()
def OnReseted(self):
super(color_leman_trend_strategy, self).OnReseted()
self._bulls_ema = None
self._bears_ema = None
self._prev_bulls = None
self._prev_bears = None
def CreateClone(self):
return color_leman_trend_strategy()