View on GitHub

Line Order Single Entry Strategy

Line Order strategy is a translation of the MQL4 script "LineOrder" (10715). The strategy opens a position when the market price reaches a predefined entry line and then manages the position with stop-loss, take-profit, and optional trailing stop.

Parameters

  • Entry Price – price level that triggers a position.
  • Stop Loss (pips) – distance from entry to initial stop loss.
  • Take Profit (pips) – distance from entry to take profit.
  • Trailing Stop (pips) – optional trailing stop distance. When set to zero, trailing is disabled.
  • Candle Type – type of candles used for processing.

Trading Logic

  1. The strategy subscribes to the selected candle series.
  2. When a finished candle closes above the entry price, a long position is opened. When it closes below the entry price, a short position is opened.
  3. After entering, stop-loss and take-profit levels are calculated using the instrument's price step.
  4. If trailing stop is enabled, the stop level moves in the trade's direction.
  5. The position is closed when price hits either the stop-loss or take-profit level.

This is a simplified port of the original MQL script, focusing on automated order execution at a user-defined line.

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>
/// Line order strategy that enters when price crosses a predefined level.
/// Uses SMA as the dynamic entry line.
/// </summary>
public class LineOrderSingleEntryStrategy : Strategy
{
	private readonly StrategyParam<int> _smaLength;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevClose;
	private decimal _prevSma;
	private bool _hasPrev;

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

	public LineOrderSingleEntryStrategy()
	{
		_smaLength = Param(nameof(SmaLength), 20)
			.SetGreaterThanZero()
			.SetDisplay("SMA Length", "Moving average period", "Parameters");

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

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevClose = 0;
		_prevSma = 0;
		_hasPrev = false;
	}

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

		var sma = new SimpleMovingAverage { Length = SmaLength };

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

	private void ProcessCandle(ICandleMessage candle, decimal smaValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var close = candle.ClosePrice;

		if (_hasPrev)
		{
			// Cross above SMA
			if (_prevClose <= _prevSma && close > smaValue && Position <= 0)
			{
				BuyMarket();
			}
			// Cross below SMA
			else if (_prevClose >= _prevSma && close < smaValue && Position >= 0)
			{
				SellMarket();
			}
		}

		_prevClose = close;
		_prevSma = smaValue;
		_hasPrev = true;
	}
}