La estrategia SurefireThing es una StockSharp versión de alto nivel del MetaTrader 4 asesor experto Surefirething. Opera con velas completadas, calcula los niveles de órdenes pendientes del rango de la sesión anterior y restablece la exposición al final de cada día de negociación. La lógica se centra en desplegar un par simétrico de órdenes límite que intentan capturar la reversión a la media alrededor del cierre anterior.
Lógica de trading
Al cierre de cada día de negociación, la estrategia intenta aplanar la posición y cancela cualquier orden pendiente activa.
Usando la última vela completada del día anterior, mide el rango de precios (High - Low) y lo multiplica por RangeMultiplier (el valor predeterminado es 1,1 como en el EA original).
La mitad del rango ajustado se suma al cierre anterior para obtener el precio de entrada límite de venta. La misma distancia se resta del cierre para colocar la orden de límite de compra.
Las compensaciones de stop-loss y take-profit se expresan en incrementos de precios. Cuando el instrumento expone un Security.Step válido, se convierten a distancias absolutas y se administran a través de StartProtection para que las posiciones ocupadas reciban órdenes de protección automáticamente.
Las órdenes se envían una vez por día de negociación. Si se llena, las manijas de protección adjuntas salen; de lo contrario, los pedidos permanecen activos hasta el próximo reinicio diario.
Parámetros
Parámetro
Descripción
Predeterminado
OrderVolume
Volumen presentado con cada orden pendiente.
0.1
TakeProfitPoints
Distancia (en pasos de precio) al objetivo de beneficio. Se convierte en un desplazamiento absoluto cuando se conoce el paso.
10
StopLossPoints
Distancia (en pasos de precio) hasta el tope de protección. Convertido de la misma manera que el objetivo de ganancias.
15
RangeMultiplier
Factor aplicado al rango de velas anterior antes de calcular los precios de entrada.
1.1
CandleType
Plazo primario procesado por la estrategia. El valor predeterminado es velas de 1 minuto, pero se puede ajustar para que coincida con el gráfico original.
TimeSpan.FromMinutes(1)
Notas de implementación
API de alto nivel: las velas se consumen hasta SubscribeCandles(CandleType) y se procesan en el controlador ProcessCandle una vez terminadas.
Restablecimiento diario: CloseForNewDay cancela las órdenes pendientes y cierra posiciones cada vez que se detecta un nuevo día calendario a partir de las marcas de tiempo de las velas.
Lógica de protección: ConfigureProtection traduce los controles de riesgo basados en puntos en Unit instancias y activa StartProtection para que las órdenes de stop-loss y take-profit se vuelvan a crear automáticamente después de ejecutarse.
Ciclo de vida del pedido: las referencias a los pedidos pendientes se almacenan y borran a través de CancelPendingOrder, así como también de OnOrderChanged cuando los pedidos finalizan o se cancelan.
Normalización de precios: Security.ShrinkPrice se utiliza para redondear los precios calculados al tamaño del tick del instrumento antes de enviar nuevos pedidos.
Recomendaciones de uso
Alinee CandleType con el marco temporal utilizado por el EA original (normalmente el gráfico donde se adjuntó) para mantener las mismas velas de referencia.
Ajuste RangeMultiplier cuando los instrumentos muestren diferentes características de volatilidad para que las órdenes pendientes permanezcan dentro de distancias realistas.
Si el corredor impone distancias mínimas de parada, asegúrese de que TakeProfitPoints y StopLossPoints respeten esas restricciones después de la conversión a precios absolutos.
La estrategia asume datos intradiarios continuos. Cuando se producen grandes brechas (fines de semana, días festivos), la siguiente vela disponible aún activa un reinicio y la colocación de una nueva orden basada en la última barra observada.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Daily range breakout strategy.
/// Calculates buy/sell levels from previous day's range.
/// Buys when price drops below the lower level, sells when above the upper level.
/// Closes position at end of day.
/// </summary>
public class SurefireThingStrategy : Strategy
{
private readonly StrategyParam<decimal> _rangeMultiplier;
private readonly StrategyParam<DataType> _candleType;
private DateTime? _currentDay;
private decimal _buyLevel;
private decimal _sellLevel;
private bool _levelsReady;
private decimal _prevDayClose;
private decimal _prevDayHigh;
private decimal _prevDayLow;
private decimal _dayHigh;
private decimal _dayLow;
private decimal _dayClose;
private bool _hasPrevDay;
private bool _tradedToday;
public decimal RangeMultiplier
{
get => _rangeMultiplier.Value;
set => _rangeMultiplier.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public SurefireThingStrategy()
{
_rangeMultiplier = Param(nameof(RangeMultiplier), 0.5m)
.SetDisplay("Range Mult", "Multiplier for range-based levels", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle series", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_currentDay = null;
_buyLevel = 0m;
_sellLevel = 0m;
_levelsReady = false;
_prevDayClose = 0m;
_prevDayHigh = 0m;
_prevDayLow = 0m;
_dayHigh = 0m;
_dayLow = 0m;
_dayClose = 0m;
_hasPrevDay = false;
_tradedToday = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_currentDay = null;
_levelsReady = false;
_hasPrevDay = false;
_tradedToday = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var day = candle.OpenTime.Date;
// New day detected
if (_currentDay == null || day > _currentDay.Value)
{
// Close position at end of previous day
if (Position > 0)
SellMarket();
else if (Position < 0)
BuyMarket();
// Save previous day stats
if (_currentDay != null)
{
_prevDayClose = _dayClose;
_prevDayHigh = _dayHigh;
_prevDayLow = _dayLow;
_hasPrevDay = true;
}
// Calculate new levels
if (_hasPrevDay)
{
var range = _prevDayHigh - _prevDayLow;
if (range > 0)
{
var halfRange = range * RangeMultiplier;
_buyLevel = _prevDayClose - halfRange;
_sellLevel = _prevDayClose + halfRange;
_levelsReady = true;
}
}
_currentDay = day;
_dayHigh = candle.HighPrice;
_dayLow = candle.LowPrice;
_dayClose = candle.ClosePrice;
_tradedToday = false;
}
else
{
if (candle.HighPrice > _dayHigh) _dayHigh = candle.HighPrice;
if (candle.LowPrice < _dayLow) _dayLow = candle.LowPrice;
_dayClose = candle.ClosePrice;
}
if (!_levelsReady)
return;
var price = candle.ClosePrice;
// Only one trade per day per direction
if (!_tradedToday && Position == 0)
{
if (price <= _buyLevel)
{
BuyMarket();
_tradedToday = true;
}
else if (price >= _sellLevel)
{
SellMarket();
_tradedToday = 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, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class surefire_thing_strategy(Strategy):
"""Daily range breakout strategy. Calculates buy/sell levels from previous day's range.
Buys when price drops below the lower level, sells when above the upper level.
Closes position at end of day."""
def __init__(self):
super(surefire_thing_strategy, self).__init__()
self._range_multiplier = self.Param("RangeMultiplier", 0.5) \
.SetDisplay("Range Mult", "Multiplier for range-based levels", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candle series", "General")
self._current_day = None
self._buy_level = 0.0
self._sell_level = 0.0
self._levels_ready = False
self._prev_day_close = 0.0
self._prev_day_high = 0.0
self._prev_day_low = 0.0
self._day_high = 0.0
self._day_low = 0.0
self._day_close = 0.0
self._has_prev_day = False
self._traded_today = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RangeMultiplier(self):
return self._range_multiplier.Value
def OnReseted(self):
super(surefire_thing_strategy, self).OnReseted()
self._current_day = None
self._buy_level = 0.0
self._sell_level = 0.0
self._levels_ready = False
self._prev_day_close = 0.0
self._prev_day_high = 0.0
self._prev_day_low = 0.0
self._day_high = 0.0
self._day_low = 0.0
self._day_close = 0.0
self._has_prev_day = False
self._traded_today = False
def OnStarted2(self, time):
super(surefire_thing_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._process_candle).Start()
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
day = candle.OpenTime.Date
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
# New day detected
if self._current_day is None or day > self._current_day:
# Close position at end of previous day
if self.Position > 0:
self.SellMarket()
elif self.Position < 0:
self.BuyMarket()
# Save previous day stats
if self._current_day is not None:
self._prev_day_close = self._day_close
self._prev_day_high = self._day_high
self._prev_day_low = self._day_low
self._has_prev_day = True
# Calculate new levels
if self._has_prev_day:
day_range = self._prev_day_high - self._prev_day_low
if day_range > 0:
half_range = day_range * float(self.RangeMultiplier)
self._buy_level = self._prev_day_close - half_range
self._sell_level = self._prev_day_close + half_range
self._levels_ready = True
self._current_day = day
self._day_high = high
self._day_low = low
self._day_close = close
self._traded_today = False
else:
if high > self._day_high:
self._day_high = high
if low < self._day_low:
self._day_low = low
self._day_close = close
if not self._levels_ready:
return
# Only one trade per day
if not self._traded_today and self.Position == 0:
if close <= self._buy_level:
self.BuyMarket()
self._traded_today = True
elif close >= self._sell_level:
self.SellMarket()
self._traded_today = True
def CreateClone(self):
return surefire_thing_strategy()