La estrategia FT TIME BIGDOG es un sistema de ruptura de sesión de Londres convertido del MetaTrader 4 asesores expertos FT_TIME_BIGDOG.mq4 (directorio MQL/9259).
Mide el rango de consolidación que se forma entre las horas de inicio y finalización configuradas y luego coloca órdenes de detención por encima y por debajo de ese rango una vez que se cierra la ventana.
La versión StockSharp mantiene el comportamiento original al tiempo que expone parámetros configurables para el tiempo de ruptura, la distancia de las órdenes y la gestión de riesgos.
Lógica de trading
Cada día de negociación, la estrategia registra el máximo más alto y el mínimo más bajo de las velas terminadas cuya hora de apertura se encuentra entre StartHour y StopHour (inclusive).
Después de que finalice la vela de la hora de parada, si el rango acumulado es menor que RangeLimitPoints, dos órdenes de parada pendientes se vuelven elegibles:
Una parada de compra en el máximo registrado.
Una parada de venta en el mínimo registrado.
Las órdenes se crean solo si el precio de mercado está al menos OrderBufferPoints lejos del nivel de entrada. Los mejores precios de oferta/demanda se utilizan cuando están disponibles; de lo contrario, se utiliza el último cierre de vela.
Cada orden pendiente incluye un stop de protección en el lado opuesto del rango y una compensación de toma de ganancias definida por TakeProfitPoints.
Cuando se abre una posición, se cancela la orden pendiente opuesta. La posición activa se monitorea en velas terminadas: si el precio toca el nivel de stop loss almacenado o de toma de ganancias, la posición se cierra en el mercado.
El ciclo se ejecuta como máximo una vez al día; Todo el estado se restablece al comienzo del siguiente día de negociación.
Parámetros
Parámetro
Predeterminado
Descripción
StartHour
14
Hora (0–23) que marca el inicio de la ventana de acumulación.
StopHour
16
Hora en la que los pedidos pendientes se vuelven elegibles. Debe ser mayor o igual a StartHour.
RangeLimitPoints
50
Ancho máximo del rango de sesión en puntos del corredor (puntos × PointMultiplier). No se realizan pedidos si el rango es más amplio.
TakeProfitPoints
50
Distancia de obtención de beneficios aplicada a las posiciones activadas, expresada en puntos del corredor.
OrderBufferPoints
20
Distancia mínima requerida entre el precio de mercado y una orden pendiente. Evita que los pedidos se realicen demasiado cerca del precio actual.
PointMultiplier
1
Multiplicador aplicado al tamaño del punto del instrumento. Establezca en 10 para símbolos de divisas de cinco dígitos.
Volume
0.1
Volumen de órdenes para ambas órdenes stop.
CandleType
1 hora
Serie de velas utilizadas para medir el alcance y evaluar la señal de accionamiento.
Gestión de riesgos y comercio
El stop loss para operaciones largas equivale al mínimo de la sesión; el stop loss para operaciones cortas es igual al máximo de la sesión.
Los niveles de toma de ganancias se calculan a partir del precio de ruptura usando TakeProfitPoints y el tamaño en puntos del instrumento.
Todos los controles de riesgo se ejecutan en los eventos de cierre de velas; Las excursiones dentro de la barra más allá de los niveles de parada pueden provocar salidas retrasadas.
Diferencias vs. Asesor Experto Original
La versión MetaTrader opera en eventos de tick, mientras que este puerto depende de velas terminadas y actualizaciones de nivel 1. Por lo tanto, el comportamiento dentro de una vela puede variar ligeramente.
La conversión de puntos utiliza Security.PriceStep multiplicado por PointMultiplier. Verifique esta combinación antes de ejecutar en vivo.
Los pedidos se realizan únicamente cuando StartHour <= StopHour. Este puerto no admite ventanas de medianoche.
Notas de uso
Asigne la seguridad deseada y verifique que los datos de nivel 1 estén disponibles para realizar comprobaciones precisas del buffer.
Configure el horario de negociación según la zona horaria del corredor.
Primero ejecute la simulación para validar la conversión de puntos y el tiempo en relación con su fuente de datos.
Restablezca o detenga la estrategia antes de modificar manualmente las órdenes pendientes para evitar estados conflictivos.
Archivos
CS/FtTimeBigdogStrategy.cs: implementación principal de StockSharp con comentarios detallados en línea.
MQL/9259/FT_TIME_BIGDOG.mq4: fuente original MetaTrader utilizada para la conversión.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// FT Time Bigdog: Range breakout using N-bar high/low channel with ATR stops.
/// </summary>
public class FtTimeBigdogStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _channelLength;
private readonly StrategyParam<int> _atrLength;
private decimal _entryPrice;
private decimal _highest;
private decimal _lowest;
private int _barCount;
private readonly decimal[] _highs = new decimal[20];
private readonly decimal[] _lows = new decimal[20];
public FtTimeBigdogStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_channelLength = Param(nameof(ChannelLength), 20)
.SetDisplay("Channel Length", "Lookback for high/low channel.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int ChannelLength
{
get => _channelLength.Value;
set => _channelLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0;
_barCount = 0;
_highest = 0;
_lowest = 0;
Array.Clear(_highs, 0, _highs.Length);
Array.Clear(_lows, 0, _lows.Length);
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_entryPrice = 0;
_barCount = 0;
_highest = 0;
_lowest = 0;
Array.Clear(_highs, 0, _highs.Length);
Array.Clear(_lows, 0, _lows.Length);
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
var len = Math.Min(ChannelLength, _highs.Length);
var idx = _barCount % len;
_highs[idx] = candle.HighPrice;
_lows[idx] = candle.LowPrice;
_barCount++;
if (_barCount < len || atrVal <= 0)
return;
var high = decimal.MinValue;
var low = decimal.MaxValue;
for (var i = 0; i < len; i++)
{
if (_highs[i] > high) high = _highs[i];
if (_lows[i] < low) low = _lows[i];
}
var prevHigh = _highest;
var prevLow = _lowest;
_highest = high;
_lowest = low;
if (prevHigh == 0 || prevLow == 0)
return;
var close = candle.ClosePrice;
if (Position > 0)
{
if (close >= _entryPrice + atrVal * 3m || close <= _entryPrice - atrVal * 2m)
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0)
{
if (close <= _entryPrice - atrVal * 3m || close >= _entryPrice + atrVal * 2m)
{
BuyMarket();
_entryPrice = 0;
}
}
if (Position == 0)
{
if (close > prevHigh)
{
_entryPrice = close;
BuyMarket();
}
else if (close < prevLow)
{
_entryPrice = close;
SellMarket();
}
}
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import AverageTrueRange
class ft_time_bigdog_strategy(Strategy):
def __init__(self):
super(ft_time_bigdog_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._channel_length = self.Param("ChannelLength", 20) \
.SetDisplay("Channel Length", "Lookback for high/low channel.", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period.", "Indicators")
self._entry_price = 0.0
self._highest = 0.0
self._lowest = 0.0
self._bar_count = 0
self._highs = []
self._lows = []
@property
def CandleType(self):
return self._candle_type.Value
@property
def ChannelLength(self):
return self._channel_length.Value
@property
def AtrLength(self):
return self._atr_length.Value
def OnStarted2(self, time):
super(ft_time_bigdog_strategy, self).OnStarted2(time)
self._entry_price = 0.0
self._bar_count = 0
self._highest = 0.0
self._lowest = 0.0
self._highs = [0.0] * 20
self._lows = [0.0] * 20
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, atr_val):
if candle.State != CandleStates.Finished:
return
av = float(atr_val)
length = min(self.ChannelLength, 20)
idx = self._bar_count % length
self._highs[idx] = float(candle.HighPrice)
self._lows[idx] = float(candle.LowPrice)
self._bar_count += 1
if self._bar_count < length or av <= 0:
return
high = max(self._highs[i] for i in range(length))
low = min(self._lows[i] for i in range(length))
prev_high = self._highest
prev_low = self._lowest
self._highest = high
self._lowest = low
if prev_high == 0 or prev_low == 0:
return
close = float(candle.ClosePrice)
if self.Position > 0:
if close >= self._entry_price + av * 3.0 or close <= self._entry_price - av * 2.0:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if close <= self._entry_price - av * 3.0 or close >= self._entry_price + av * 2.0:
self.BuyMarket()
self._entry_price = 0.0
if self.Position == 0:
if close > prev_high:
self._entry_price = close
self.BuyMarket()
elif close < prev_low:
self._entry_price = close
self.SellMarket()
def OnReseted(self):
super(ft_time_bigdog_strategy, self).OnReseted()
self._entry_price = 0.0
self._bar_count = 0
self._highest = 0.0
self._lowest = 0.0
self._highs = []
self._lows = []
def CreateClone(self):
return ft_time_bigdog_strategy()