Esta estrategia es una adaptación del asesor experto de MetaTrader "MyLineOrder" para la API de StockSharp. Permite al trader definir niveles de precio horizontales que activan órdenes de mercado automáticas cuando el precio los toca. Las distancias opcionales de stop loss, take profit y trailing stop se expresan en pips, y el volumen de la operación es configurable.
Cuando el precio de mercado alcanza el nivel BuyPrice, la estrategia entra en una posición larga. Al tocar el nivel SellPrice se abre una posición corta. Tras la entrada, la estrategia supervisa la posición y sale cuando se cumple una de las condiciones de protección: stop loss, take profit o trailing stop.
Detalles
Criterios de entrada:
Largo: El precio toca o supera BuyPrice.
Corto: El precio toca o cae por debajo de SellPrice.
Largo/Corto: Ambos.
Criterios de salida:
Stop loss, take profit o trailing stop.
Stops:
StopLossPips, TakeProfitPips, TrailingStopPips.
Filtros:
Ninguno.
Parámetros:
BuyPrice – nivel para entrada larga.
SellPrice – nivel para entrada corta.
StopLossPips – distancia de stop loss en pips.
TakeProfitPips – distancia de take profit en pips.
TrailingStopPips – distancia de trailing stop en pips.
TradeVolume – volumen de la orden.
CandleType – marco temporal de las velas para la monitorización del precio.
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>
/// Dual-level breakout strategy using SMA and ATR for dynamic support/resistance levels.
/// Buys when price breaks above SMA + ATR, sells when breaks below SMA - ATR.
/// Exits on mean reversion to SMA.
/// </summary>
public class LineOrderDualLevelStrategy : Strategy
{
private readonly StrategyParam<int> _smaPeriod;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrMult;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
public int SmaPeriod { get => _smaPeriod.Value; set => _smaPeriod.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public decimal AtrMult { get => _atrMult.Value; set => _atrMult.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public LineOrderDualLevelStrategy()
{
_smaPeriod = Param(nameof(SmaPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "SMA period", "Indicators");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period", "Indicators");
_atrMult = Param(nameof(AtrMult), 1.0m)
.SetDisplay("ATR Mult", "ATR multiplier for levels", "Indicators");
_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;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma = new SimpleMovingAverage { Length = SmaPeriod };
var atr = new StandardDeviation { Length = AtrPeriod };
SubscribeCandles(CandleType)
.Bind(sma, atr, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal smaVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished) return;
if (atrVal <= 0) return;
var close = candle.ClosePrice;
var upperLevel = smaVal + atrVal * AtrMult;
var lowerLevel = smaVal - atrVal * AtrMult;
// Breakout above upper level => long
if (close > upperLevel && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_entryPrice = close;
}
// Breakout below lower level => short
else if (close < lowerLevel && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_entryPrice = close;
}
// Exit long at SMA or if loss > 2*ATR
else if (Position > 0)
{
if (close <= smaVal || (_entryPrice > 0 && close <= _entryPrice - atrVal * 2))
{
SellMarket();
_entryPrice = 0;
}
}
// Exit short at SMA or if loss > 2*ATR
else if (Position < 0)
{
if (close >= smaVal || (_entryPrice > 0 && close >= _entryPrice + atrVal * 2))
{
BuyMarket();
_entryPrice = 0;
}
}
}
}
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, StandardDeviation
from StockSharp.Algo.Strategies import Strategy
class line_order_dual_level_strategy(Strategy):
def __init__(self):
super(line_order_dual_level_strategy, self).__init__()
self._sma_period = self.Param("SmaPeriod", 10) \
.SetDisplay("SMA Period", "SMA period", "Indicators")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR period", "Indicators")
self._atr_mult = self.Param("AtrMult", 1.0) \
.SetDisplay("ATR Mult", "ATR multiplier for levels", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._entry_price = 0.0
@property
def sma_period(self):
return self._sma_period.Value
@property
def atr_period(self):
return self._atr_period.Value
@property
def atr_mult(self):
return self._atr_mult.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(line_order_dual_level_strategy, self).OnReseted()
self._entry_price = 0.0
def OnStarted2(self, time):
super(line_order_dual_level_strategy, self).OnStarted2(time)
sma = SimpleMovingAverage()
sma.Length = self.sma_period
atr = StandardDeviation()
atr.Length = self.atr_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, atr, 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_val, atr_val):
if candle.State != CandleStates.Finished:
return
if atr_val <= 0:
return
close = candle.ClosePrice
upper_level = sma_val + atr_val * self.atr_mult
lower_level = sma_val - atr_val * self.atr_mult
# Breakout above upper level => long
if close > upper_level and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
# Breakout below lower level => short
elif close < lower_level and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
# Exit long at SMA or if loss > 2*ATR
elif self.Position > 0:
if close <= sma_val or (self._entry_price > 0 and close <= self._entry_price - atr_val * 2):
self.SellMarket()
self._entry_price = 0
# Exit short at SMA or if loss > 2*ATR
elif self.Position < 0:
if close >= sma_val or (self._entry_price > 0 and close >= self._entry_price + atr_val * 2):
self.BuyMarket()
self._entry_price = 0
def CreateClone(self):
return line_order_dual_level_strategy()