GitHub で見る

LeMan Trend Hist Strategy

This strategy is a simplified conversion of the original MQL5 expert "LeManTrendHist". It relies on an EMA-based histogram to generate trading signals.

Idea

The original algorithm calculates a custom histogram derived from price extremes and smoothed ranges. For this sample the histogram is approximated by an exponential moving average of candle ranges.

Strategy Logic

  1. Compute EMA value for each finished candle.
  2. Compare the last three EMA values.
  3. When the middle value is lower than the oldest and the newest value rises above it, a long position is opened and short positions are closed.
  4. When the middle value is higher than the oldest and the newest value falls below it, a short position is opened and long positions are closed.

Parameters

  • Candle Type – timeframe of processed candles.
  • EMA Period – length of the EMA used in the placeholder histogram.
  • Signal Bar – historical shift for indicator values (kept for compatibility, not used in simplified logic).
  • Buy/Sell Open – enable long or short entries.
  • Buy/Sell Close – enable closing of existing positions.

Notes

The true LeManTrendHist indicator uses complex smoothing algorithms that are not yet implemented. The current implementation acts as a placeholder and should be replaced with the full indicator for production use.

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>
/// LeManTrendHist strategy using EMA slope changes as trend signals.
/// </summary>
public class LeManTrendHistStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;

	private decimal? _value1;
	private decimal? _value2;
	private decimal? _value3;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int EmaPeriod
	{
		get => _emaPeriod.Value;
		set => _emaPeriod.Value = value;
	}

	public LeManTrendHistStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");

		_emaPeriod = Param(nameof(EmaPeriod), 3)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA length", "Parameters");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_value1 = null;
		_value2 = null;
		_value3 = null;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, ProcessCandle).Start();

		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;

		_value3 = _value2;
		_value2 = _value1;
		_value1 = emaValue;

		if (_value1 is null || _value2 is null || _value3 is null)
			return;

		// EMA turned up (was falling, now rising)
		if (_value2 < _value3 && _value1 > _value2)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		// EMA turned down (was rising, now falling)
		else if (_value2 > _value3 && _value1 < _value2)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}
	}
}