La estrategia Surefirething recrea el clásico asesor experto de MetaTrader 5 que coloca órdenes límite simétricas de compra y venta alrededor del cierre de la vela más reciente. El sistema reconstruye constantemente la cuadrícula después de cada vela completada, gestiona los stops de protección en unidades de pip, y fuerza una posición completamente plana diez minutos antes de la medianoche, hora del servidor.
Procesamiento de velas
Funciona con un tipo de vela configurable (predeterminado: marco temporal de 1 hora).
Después de cada vela terminada, la estrategia calcula un rango amplificado: range = (high - low) * 1.1.
Deriva dos niveles de ruptura de ese rango:
L4 = close - range / 2 para la orden límite de compra.
H4 = close + range / 2 para la orden límite de venta.
Las órdenes pendientes existentes se cancelan antes de publicar la nueva cuadrícula, por lo que solo una orden límite de compra y una de venta permanecen activas.
Gestión de órdenes
La orden límite de compra en L4 y la orden límite de venta en H4 se registran con el volumen de orden configurado.
Una vez que se abre una posición, la orden pendiente opuesta se cancela inmediatamente.
Cada día a las 23:50 (hora del servidor), la estrategia:
Cancela cualquier orden pendiente restante.
Cierra la posición abierta al mercado, si la hay.
Restablece todos los rastreadores de stop/take-profit para comenzar la próxima sesión limpiamente.
Gestión de riesgos
Las distancias de stop-loss y take-profit se definen en pips y se traducen en precios usando el paso de precio del instrumento (los símbolos de 5 dígitos y 3 dígitos se ajustan a las unidades pip clásicas automáticamente).
Se puede habilitar un trailing stop (también en pips). Cada vez que el precio se mueve más allá de TrailingStopPips + TrailingStepPips, el stop avanza a precio actual - TrailingStopPips para posiciones largas o precio actual + TrailingStopPips para posiciones cortas.
Ambos niveles de protección se monitorean en cada vela. Si la vela opera a través del stop o el objetivo, la estrategia sale de la posición usando órdenes de mercado.
Parámetros
OrderVolume – volumen base para ambas órdenes límite (predeterminado: 0.1).
StopLossPips – distancia del stop-loss en pips (predeterminado: 50).
TakeProfitPips – distancia del take-profit en pips (predeterminado: 50).
TrailingStopPips – distancia del trailing stop en pips (predeterminado: 25).
TrailingStepPips – movimiento adicional en pips requerido antes de que se mueva el trailing stop (predeterminado: 1). Debe ser mayor que cero cuando el trailing stop está habilitado.
CandleType – tipo de datos de vela usado para los cálculos (predeterminado: marco temporal de 1 hora).
Notas
La implementación coincide con la lógica MQL original al garantizar que el paso de trailing sea diferente de cero siempre que el trailing esté activo.
No se proporciona implementación Python para esta estrategia.
namespace StockSharp.Samples.Strategies;
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Surefirething breakout strategy.
/// Buys when price breaks above the previous candle's high, sells when price breaks below the previous candle's low.
/// Uses EMA as a trend filter.
/// </summary>
public class SurefirethingStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private decimal _prevHigh;
private decimal _prevLow;
private bool _initialized;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int EmaPeriod
{
get => _emaPeriod.Value;
set => _emaPeriod.Value = value;
}
public SurefirethingStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Time frame used for signals", "General");
_emaPeriod = Param(nameof(EmaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "Trend filter EMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh = 0m;
_prevLow = 0m;
_initialized = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHigh = 0;
_prevLow = 0;
_initialized = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (!_initialized)
{
_prevHigh = candle.HighPrice;
_prevLow = candle.LowPrice;
_initialized = true;
return;
}
// Breakout above previous high with EMA filter
if (candle.ClosePrice > _prevHigh && candle.ClosePrice > emaValue && Position <= 0)
{
BuyMarket();
}
// Breakout below previous low with EMA filter
else if (candle.ClosePrice < _prevLow && candle.ClosePrice < emaValue && Position >= 0)
{
SellMarket();
}
_prevHigh = candle.HighPrice;
_prevLow = candle.LowPrice;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class surefirething_strategy(Strategy):
def __init__(self):
super(surefirething_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Time frame used for signals", "General")
self._ema_period = self.Param("EmaPeriod", 20) \
.SetDisplay("EMA Period", "Trend filter EMA period", "Indicators")
self._prev_high = 0.0
self._prev_low = 0.0
self._initialized = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def EmaPeriod(self):
return self._ema_period.Value
def OnReseted(self):
super(surefirething_strategy, self).OnReseted()
self._prev_high = 0.0
self._prev_low = 0.0
self._initialized = False
def OnStarted2(self, time):
super(surefirething_strategy, self).OnStarted2(time)
self._prev_high = 0.0
self._prev_low = 0.0
self._initialized = False
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(ema, self._on_process) \
.Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
ev = float(ema_value)
close = float(candle.ClosePrice)
if not self._initialized:
self._prev_high = float(candle.HighPrice)
self._prev_low = float(candle.LowPrice)
self._initialized = True
return
if close > self._prev_high and close > ev and self.Position <= 0:
self.BuyMarket()
elif close < self._prev_low and close < ev and self.Position >= 0:
self.SellMarket()
self._prev_high = float(candle.HighPrice)
self._prev_low = float(candle.LowPrice)
def CreateClone(self):
return surefirething_strategy()