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
The strategy subscribes to the selected candle series.
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.
After entering, stop-loss and take-profit levels are calculated using the instrument's price step.
If trailing stop is enabled, the stop level moves in the trade's direction.
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;
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class line_order_single_entry_strategy(Strategy):
def __init__(self):
super(line_order_single_entry_strategy, self).__init__()
self._sma_length = self.Param("SmaLength", 20) \
.SetDisplay("SMA Length", "Moving average period", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_close = 0.0
self._prev_sma = 0.0
self._has_prev = False
@property
def sma_length(self):
return self._sma_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(line_order_single_entry_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_sma = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(line_order_single_entry_strategy, self).OnStarted2(time)
sma = SimpleMovingAverage()
sma.Length = self.sma_length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
close = candle.ClosePrice
if self._has_prev:
# Cross above SMA
if self._prev_close <= self._prev_sma and close > sma_value and self.Position <= 0:
self.BuyMarket()
# Cross below SMA
elif self._prev_close >= self._prev_sma and close < sma_value and self.Position >= 0:
self.SellMarket()
self._prev_close = close
self._prev_sma = sma_value
self._has_prev = True
def CreateClone(self):
return line_order_single_entry_strategy()