Esta estrategia recrea el asesor experto original de MetaTrader de "breakdown". Coloca órdenes de stop alrededor del rango del día anterior y actualiza continuamente las órdenes cada sesión. Un motor de trailing-stop replica la lógica de trailing escalonado del script fuente, manteniendo los stops ajustados una vez que la posición comienza a moverse en la dirección rentable.
Cómo Funciona
Preparación diaria – Cuando una vela diaria cierra, la estrategia almacena el máximo y el mínimo. Al inicio de la siguiente sesión cancela las órdenes restantes y envía un buy stop por encima del máximo anterior y un sell stop por debajo del mínimo anterior. El parámetro Min Distance (ticks) desplaza las órdenes lejos de los niveles brutos para evitar ruido.
Actualización de órdenes – Cada vez que las órdenes pendientes se ejecutan o comienza un nuevo día, las órdenes restantes se cancelan y se envía un nuevo par usando los mismos niveles del día anterior. El comportamiento refleja el experto MQL que mantiene continuamente entradas de stop en ambos lados del mercado.
Controles de riesgo – Las posiciones ejecutadas inicializan objetivos de stop-loss y take-profit basados en distancias en ticks. Una regla de trailing escalonado sube/baja el stop solo después de que el precio gana al menos Trailing Stop (ticks) + Trailing Step (ticks) desde la entrada, exactamente como la implementación original de trailing-stop.
Salidas – Las posiciones se cierran inmediatamente cuando el precio toca el stop o el objetivo activo. El trailing manual cierra posiciones a mercado cuando se viola el nivel de trailing, coincidiendo con la lógica de MetaTrader que modificaba stops en cada tick.
Parámetros
Parámetro
Descripción
Working Candles
Marco temporal usado para monitorear la acción del precio y gestionar stops (predeterminado: velas de 15 minutos).
Stop Loss (ticks)
Distancia de stop protector inicial convertida a precio absoluto usando el tamaño del tick del instrumento. Establecer en cero para deshabilitar.
Take Profit (ticks)
Distancia inicial de take-profit. Establecer en cero para deshabilitar.
Trailing Stop (ticks)
Distancia principal del trailing-stop. Establecer en cero para deshabilitar el trailing.
Trailing Step (ticks)
Beneficio adicional requerido antes de que el trailing stop se mueva.
Min Distance (ticks)
Offset agregado al máximo/mínimo del día anterior al colocar las órdenes pendientes.
Order Volume
Cantidad enviada con ambas órdenes de stop.
Notas de Uso
Configurar la estrategia en instrumentos que publiquen velas diarias para obtener el rango de la sesión anterior.
La lógica asume un tamaño de tick constante. Para instrumentos con incrementos de tick variables, ajustar los valores predeterminados en consecuencia.
La estrategia no implementa el dimensionamiento basado en porcentaje del script MQL original; el volumen se define explícitamente a través del parámetro Order Volume.
Aún no se proporciona una versión Python para esta estrategia.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Breakout strategy using Highest/Lowest channel.
/// Enters long when price breaks above the channel high, enters short when price breaks below the channel low.
/// </summary>
public class BreakdownPendingStopStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private decimal? _prevHigh;
private decimal? _prevLow;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int Period
{
get => _period.Value;
set => _period.Value = value;
}
public BreakdownPendingStopStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_period = Param(nameof(Period), 20)
.SetGreaterThanZero()
.SetDisplay("Period", "Channel lookback period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh = null;
_prevLow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHigh = null;
_prevLow = null;
var highest = new Highest { Length = Period };
var lowest = new Lowest { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, highest);
DrawIndicator(area, lowest);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal high, decimal low)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevHigh = high;
_prevLow = low;
return;
}
if (_prevHigh == null || _prevLow == null)
{
_prevHigh = high;
_prevLow = low;
return;
}
var close = candle.ClosePrice;
if (close > _prevHigh.Value && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (close < _prevLow.Value && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevHigh = high;
_prevLow = low;
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class breakdown_pending_stop_strategy(Strategy):
def __init__(self):
super(breakdown_pending_stop_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._period = self.Param("Period", 20) \
.SetDisplay("Period", "Channel lookback period", "Indicators")
self._prev_high = None
self._prev_low = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def Period(self):
return self._period.Value
def OnReseted(self):
super(breakdown_pending_stop_strategy, self).OnReseted()
self._prev_high = None
self._prev_low = None
def OnStarted2(self, time):
super(breakdown_pending_stop_strategy, self).OnStarted2(time)
self._prev_high = None
self._prev_low = None
highest = Highest()
highest.Length = self.Period
lowest = Lowest()
lowest.Length = self.Period
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, highest)
self.DrawIndicator(area, lowest)
self.DrawOwnTrades(area)
def _on_process(self, candle, high_value, low_value):
if candle.State != CandleStates.Finished:
return
hv = float(high_value)
lv = float(low_value)
if self._prev_high is None or self._prev_low is None:
self._prev_high = hv
self._prev_low = lv
return
close = float(candle.ClosePrice)
if close > self._prev_high and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif close < self._prev_low and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_high = hv
self._prev_low = lv
def CreateClone(self):
return breakdown_pending_stop_strategy()