La estrategia de VLT Trader es una StockSharp conversión del MetaTrader 4 asesor experto "VLT_TRADER". La idea original busca un período de volatilidad extremadamente baja y luego prepara una ruptura alrededor de la vela más reciente. Cuando la última vela completada tiene el rango más pequeño en comparación con un número configurable de velas anteriores, la estrategia coloca órdenes de parada por encima y por debajo de esa vela en anticipación de una expansión de la volatilidad.
Lógica comercial
Suscríbase a la serie de velas configuradas y calcule el rango (máximo menos mínimo) para cada barra.
Realice un seguimiento del rango mínimo entre las barras LookbackCandles anteriores utilizando el indicador Lowest.
Una vez que la vela finalizada más reciente tenga un rango menor que este mínimo histórico, prepare las órdenes de ruptura para la siguiente sesión.
Coloque un stop de compra por encima del máximo anterior más EntryOffsetPoints y un stop de venta por debajo del mínimo anterior menos el mismo desplazamiento.
Adjunte paradas y objetivos de distancia fija a cada orden pendiente (StopLossPoints y TakeProfitPoints).
Deje activas ambas órdenes pendientes. Cualquiera que sea el lado que se active primero se convierte en una posición de mercado, mientras que el stop opuesto permanece en el libro y puede activarse más tarde si el mercado se revierte.
Cuando se completa o cancela una orden pendiente, la referencia correspondiente se borra para que se puedan crear nuevas opciones después de que se cierren todas las posiciones y órdenes.
Gestión de riesgos
El tamaño de la operación se controla a través de OrderVolume y se redondea al paso y los límites de volumen del instrumento.
Las distancias de parada de pérdidas y toma de ganancias se expresan en pasos de precio (puntos) y se convierten a precios reales utilizando el PriceStep del instrumento.
Parámetros
Parámetro
Descripción
OrderVolume
Tamaño de lote utilizado al crear las órdenes pendientes.
EntryOffsetPoints
Se agregaron puntos adicionales al máximo/mínimo anterior al realizar entradas de stop.
TakeProfitPoints
Tomar distancia de ganancia adjunta a cada orden.
StopLossPoints
Distancia de stop loss adjunta a cada orden.
LookbackCandles
Número de velas anteriores utilizadas para medir el rango histórico mínimo.
CandleType
Cronograma de la serie de velas que alimenta la estrategia.
Notas
La estrategia requiere un PriceStep válido en el instrumento; de lo contrario no se realizan pedidos.
Debido a que los niveles de parada y toma de ganancias se transmiten junto con las órdenes pendientes, los precios de ejecución en StockSharp pueden diferir ligeramente de MetaTrader dependiendo de las reglas de ejecución del corredor.
La implementación se basa exclusivamente en API de alto nivel (SubscribeCandles + Bind) y el indicador estándar Lowest para reflejar la verificación de volatilidad del EA original.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class VltTraderStraddleStrategy : Strategy
{
private readonly StrategyParam<int> _channelPeriod;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose;
private decimal _prevMid;
private bool _hasPrev;
private int _cooldownRemaining;
public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public VltTraderStraddleStrategy()
{
_channelPeriod = Param(nameof(ChannelPeriod), 48).SetDisplay("Channel Period", "Breakout lookback", "Indicators");
_atrPeriod = Param(nameof(AtrPeriod), 14).SetDisplay("ATR Period", "ATR lookback", "Indicators");
_cooldownCandles = Param(nameof(CooldownCandles), 150).SetDisplay("Cooldown", "Candles between signals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = default;
_prevMid = default;
_hasPrev = default;
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = 0;
_prevMid = 0;
_hasPrev = false;
_cooldownRemaining = 0;
var highest = new Highest { Length = ChannelPeriod };
var lowest = new Lowest { Length = ChannelPeriod };
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(highest, lowest, atr, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal highest, decimal lowest, decimal atr)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
var mid = (highest + lowest) / 2;
if (!_hasPrev) { _prevClose = close; _prevMid = mid; _hasPrev = true; return; }
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevClose = close;
_prevMid = mid;
return;
}
if (_prevClose <= _prevMid && close > mid && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (_prevClose >= _prevMid && close < mid && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
_prevClose = close;
_prevMid = mid;
}
}