Die Linien-Order-Strategie löst eine Marktorder aus, wenn der Preis eine benutzerdefinierte horizontale Linie kreuzt. Sie ist als vereinfachte Umsetzung des ursprünglichen MQL-Skripts LineOrder.mq4 konzipiert und stellt manuelle Linienhandel-Funktionalität über die High-Level-API von StockSharp bereit.
Die Strategie bietet Parameter zur Steuerung von Richtung, Einstiegsniveau und Risikomanagement. Nach dem Einstieg in eine Position werden optionale Stop-Loss-, Take-Profit- und Trailing-Stop-Niveaus bei jeder abgeschlossenen Kerze überwacht. Die Logik ist vollständig ereignisgesteuert und pflegt keine eigenen Sammlungen.
Parameter
LinePrice – Preisniveau für die Orderplatzierung.
IsBuy – true für Long-Einstiege, false für Short-Einstiege.
StopLoss – Stop-Loss-Abstand in Preiseinheiten (0 deaktiviert).
TakeProfit – Take-Profit-Abstand in Preiseinheiten (0 deaktiviert).
TrailingStop – Trailing-Stop-Abstand in Preiseinheiten (0 deaktiviert).
Volume – Ordervolumen.
CandleType – Kerzentyp zur Preisüberwachung.
Handelsregeln
Einstieg: wenn der Schlusskurs LinePrice in der gewählten Richtung kreuzt.
Stop-Loss: schließt die Position, wenn der Verlust den StopLoss-Abstand vom Einstieg überschreitet.
Take-Profit: schließt die Position, wenn der Gewinn die TakeProfit-Distanz erreicht.
Trailing Stop: nach dem Einstieg passt sich dieser dem günstigsten Preis an und schließt, wenn sich der Preis um TrailingStop gegen die Position bewegt.
Hinweise
Funktioniert mit jedem von StockSharp unterstützten Wertpapier.
Für Bildungszwecke konzipiert, um die Übertragung von manuellem Linienhandel aus MQL zu veranschaulichen.
Die Python-Version ist absichtlich weggelassen.
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>
/// Executes a market order when price crosses a moving average "line".
/// Manages stop-loss and take-profit via candle monitoring.
/// </summary>
public class LineOrderStrategy : Strategy
{
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<decimal> _stopLossPct;
private readonly StrategyParam<decimal> _takeProfitPct;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
private decimal _prevClose;
private decimal _prevMa;
private bool _hasPrev;
public int MaLength { get => _maLength.Value; set => _maLength.Value = value; }
public decimal StopLossPct { get => _stopLossPct.Value; set => _stopLossPct.Value = value; }
public decimal TakeProfitPct { get => _takeProfitPct.Value; set => _takeProfitPct.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public LineOrderStrategy()
{
_maLength = Param(nameof(MaLength), 20)
.SetGreaterThanZero()
.SetDisplay("MA Length", "Moving average period for line", "Indicators");
_stopLossPct = Param(nameof(StopLossPct), 2m)
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");
_takeProfitPct = Param(nameof(TakeProfitPct), 3m)
.SetDisplay("Take Profit %", "Take profit percentage", "Risk");
_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();
_entryPrice = 0;
_prevClose = 0;
_prevMa = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ma = new SimpleMovingAverage { Length = MaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ma, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal maVal)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (!_hasPrev)
{
_prevClose = close;
_prevMa = maVal;
_hasPrev = true;
return;
}
// Check stop-loss / take-profit for existing positions
if (Position > 0 && _entryPrice > 0)
{
if (close <= _entryPrice * (1 - StopLossPct / 100m) ||
close >= _entryPrice * (1 + TakeProfitPct / 100m))
{
SellMarket();
_entryPrice = 0;
_prevClose = close;
_prevMa = maVal;
return;
}
}
else if (Position < 0 && _entryPrice > 0)
{
if (close >= _entryPrice * (1 + StopLossPct / 100m) ||
close <= _entryPrice * (1 - TakeProfitPct / 100m))
{
BuyMarket();
_entryPrice = 0;
_prevClose = close;
_prevMa = maVal;
return;
}
}
// Cross above MA line -> buy
if (_prevClose <= _prevMa && close > maVal)
{
if (Position < 0)
{
BuyMarket();
_entryPrice = 0;
}
if (Position <= 0)
{
BuyMarket();
_entryPrice = close;
}
}
// Cross below MA line -> sell
else if (_prevClose >= _prevMa && close < maVal)
{
if (Position > 0)
{
SellMarket();
_entryPrice = 0;
}
if (Position >= 0)
{
SellMarket();
_entryPrice = close;
}
}
_prevClose = close;
_prevMa = maVal;
}
}
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_strategy(Strategy):
def __init__(self):
super(line_order_strategy, self).__init__()
self._ma_length = self.Param("MaLength", 20) \
.SetDisplay("MA Length", "Moving average period for line", "Indicators")
self._stop_loss_pct = self.Param("StopLossPct", 2.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk")
self._take_profit_pct = self.Param("TakeProfitPct", 3.0) \
.SetDisplay("Take Profit %", "Take profit percentage", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._entry_price = 0.0
self._prev_close = 0.0
self._prev_ma = 0.0
self._has_prev = False
@property
def ma_length(self):
return self._ma_length.Value
@property
def stop_loss_pct(self):
return self._stop_loss_pct.Value
@property
def take_profit_pct(self):
return self._take_profit_pct.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(line_order_strategy, self).OnReseted()
self._entry_price = 0.0
self._prev_close = 0.0
self._prev_ma = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(line_order_strategy, self).OnStarted2(time)
ma = SimpleMovingAverage()
ma.Length = self.ma_length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ma, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle, ma_val):
if candle.State != CandleStates.Finished:
return
close = candle.ClosePrice
if not self._has_prev:
self._prev_close = close
self._prev_ma = ma_val
self._has_prev = True
return
# Check stop-loss / take-profit for existing positions
if self.Position > 0 and self._entry_price > 0:
if (close <= self._entry_price * (1 - self.stop_loss_pct / 100.0) or
close >= self._entry_price * (1 + self.take_profit_pct / 100.0)):
self.SellMarket()
self._entry_price = 0
self._prev_close = close
self._prev_ma = ma_val
return
elif self.Position < 0 and self._entry_price > 0:
if (close >= self._entry_price * (1 + self.stop_loss_pct / 100.0) or
close <= self._entry_price * (1 - self.take_profit_pct / 100.0)):
self.BuyMarket()
self._entry_price = 0
self._prev_close = close
self._prev_ma = ma_val
return
# Cross above MA line -> buy
if self._prev_close <= self._prev_ma and close > ma_val:
if self.Position < 0:
self.BuyMarket()
self._entry_price = 0
if self.Position <= 0:
self.BuyMarket()
self._entry_price = close
# Cross below MA line -> sell
elif self._prev_close >= self._prev_ma and close < ma_val:
if self.Position > 0:
self.SellMarket()
self._entry_price = 0
if self.Position >= 0:
self.SellMarket()
self._entry_price = close
self._prev_close = close
self._prev_ma = ma_val
def CreateClone(self):
return line_order_strategy()