Conversión del MetaTrader 4 asesor experto Spazm (8683) al StockSharp alto nivel API.
Negocia rupturas adaptativas comparando el último cierre con sobres de volatilidad alrededor del máximo y mínimo más recientes.
Mantiene anotaciones de gráficos opcionales que unen pivotes alcistas y bajistas consecutivos como la visualización original MQL.
Preparación de datos
La estrategia se suscribe a la serie de velas especificada por el parámetro CandleType para el valor activo.
Cada vela terminada proporciona la muestra del rango bruto utilizado para la estimación de la volatilidad:
De forma predeterminada, el rango es igual a High - Low.
Cuando UseOpenCloseRange está habilitado, se utiliza el tamaño absoluto del cuerpo |Open - Close|.
La muestra de rango se convierte en incrementos de precios utilizando el instrumento PriceStep para que la lógica permanezca invariante entre los símbolos.
El indicador definido por UseWeightedVolatility procesa la secuencia de muestras de rango:
Deshabilitado → media móvil simple con longitud VolatilityPeriod.
Habilitado → media móvil ponderada lineal (más peso para velas recientes).
El rango suavizado (expresado en pasos) se multiplica por VolatilityMultiplier y finalmente se reduce a unidades de precio. El valor resultante es el umbral de ruptura adaptativo aplicado a ambos lados del mercado.
Durante la fase de calentamiento, la estrategia también registra los máximos y mínimos extremos más recientes junto con sus marcas de tiempo. Una vez que se procesan las velas VolatilityPeriod * 3, el momento relativo de esos extremos determina la dirección de la tendencia inicial.
Parámetros
Nombre
Predeterminado
Descripción
Volume
1
Volumen de orden enviado cada vez que la estrategia abre o revierte una posición.
VolatilityMultiplier
5
Multiplicador aplicado a la volatilidad promedio para construir la distancia de ruptura.
VolatilityPeriod
24
Número de velas utilizadas tanto para el estimador de volatilidad como para sembrar los extremos de oscilación iniciales.
UseWeightedVolatility
false
Cambia el estimador de volatilidad de un promedio móvil ponderado simple a uno lineal.
UseOpenCloseRange
false
Utiliza el movimiento absoluto de apertura y cierre en lugar del rango alto-bajo al medir la volatilidad.
StopLossMultiplier
0
Multiplicador aplicado al umbral de ruptura para calcular una distancia de parada protectora. Se aplica un mínimo de tres niveles de precios. Establezca en 0 para deshabilitar las paradas.
DrawSwingLines
true
Cuando está habilitada, la estrategia traza una línea entre los últimos pivotes alcistas y bajistas, imitando los objetos MQL.
CandleType
4 hour time frame
Tipo de vela (período de tiempo u otro tipo de datos) que alimenta los cálculos.
Lógica de trading
Inicialización
Mientras se procesan las primeras velas VolatilityPeriod * 3, la estrategia actualiza _highestPrice, _lowestPrice, _highestTime y _lowestTime para capturar los últimos extremos.
Después de que lleguen suficientes velas, el más reciente de los dos extremos define la tendencia inicial: si el último mínimo es más nuevo que el último máximo, la estrategia comienza en modo alcista; de lo contrario, comienza en modo bajista.
Los extremos también se almacenan como el primer par de anclajes del swing para que las líneas del gráfico se puedan dibujar inmediatamente después del calentamiento.
Seguimiento de la volatilidad
Cada vela terminada empuja su rango dentro del promedio móvil seleccionado para producir el umbral adaptativo.
El umbral es siempre al menos un paso de precio para evitar sobres de distancia cero.
Mantenimiento de columpios
En cada vela, el algoritmo actualiza el máximo y el mínimo almacenados cada vez que se imprime un nuevo máximo o mínimo absoluto.
Cuando la tendencia cambia, el extremo relevante se registra como un pivote y, si el gráfico está habilitado, se conecta con el pivote opuesto mediante una línea.
Reglas de ruptura
Régimen alcista (_isTrendUp == true): un cierre por debajo de _highestPrice - threshold desencadena una reversión a corto. El tamaño de la orden es igual a Volume + |Position|, por lo que la exposición existente se reduce y se abre una nueva posición corta en una sola llamada.
Régimen bajista (_isTrendUp == false): un cierre por encima de _lowestPrice + threshold refleja la lógica y se invierte en largo.
Detener gestión
Cuando StopLossMultiplier es mayor que cero, el precio de entrada se compensa con threshold * StopLossMultiplier (limitado a al menos tres pasos de precio) para derivar un nivel de parada sintético.
Si una vela atraviesa el stop largo con su mínimo o el stop corto con su máximo, la posición se aplana mediante una orden de mercado.
Infraestructura
StartProtection() habilita los mecanismos de seguridad integrados StockSharp tan pronto como se lanza la estrategia.
Todas las acciones son impulsadas por velas terminadas para emular el ciclo de recálculo barra por barra del asesor experto original.
Diferencias con la versión MQL
El experto MetaTrader recalcula en cada tick, mientras que este puerto opera con velas completadas porque las suscripciones a velas son la fuente de datos idiomáticos en el nivel alto API.
Las restricciones específicas del corredor, como MODE_STOPLEVEL, no están disponibles; en cambio, la compensación de parada está limitada por tres pasos de precio para proporcionar un retroceso conservador.
Las órdenes se revierten combinando las cantidades de cierre y apertura en una única llamada BuyMarket/SellMarket en lugar de iterar sobre las posiciones existentes.
La visualización se basa en StockSharp primitivas del gráfico (DrawLine) en lugar de objetos de plataforma, pero la disposición de las líneas de pivote a pivote coincide con la salida del indicador original.
Notas de uso
Asegúrese de que la seguridad seleccionada exponga un PriceStep válido. Cuando falta, el código predeterminado es 1, que puede necesitar ajustes para ciertos instrumentos.
Debido a que la estrategia depende de velas completadas, los plazos extremadamente pequeños reducen la confiabilidad de la estimación de volatilidad. Considere alinear CandleType con el período de tiempo utilizado originalmente por EA (H4 de forma predeterminada).
Las paradas son opcionales. Dejar StopLossMultiplier en cero replica la gestión de riesgos sin límites del script MQL.
El algoritmo sigue tendencias por diseño y no impone objetivos de obtención de beneficios; las salidas se producen sólo mediante la reversión del régimen o la activación de un stop-loss.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Volatility breakout strategy that tracks swing extremes and reverses
/// when price breaks beyond an ATR-based volatility band.
/// </summary>
public class SpazmVolatilityBreakoutStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _atrLength;
private readonly StrategyParam<decimal> _multiplier;
private decimal _swingHigh;
private decimal _swingLow;
private bool _trendUp;
private bool _initialized;
public SpazmVolatilityBreakoutStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for analysis.", "General");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "Period for ATR volatility.", "Indicators");
_multiplier = Param(nameof(Multiplier), 2.0m)
.SetDisplay("Multiplier", "ATR multiplier for breakout threshold.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
public decimal Multiplier
{
get => _multiplier.Value;
set => _multiplier.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_swingHigh = 0;
_swingLow = decimal.MaxValue;
_trendUp = true;
_initialized = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, atr);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal atrValue)
{
if (candle.State != CandleStates.Finished)
return;
if (atrValue <= 0)
return;
var close = candle.ClosePrice;
var high = candle.HighPrice;
var low = candle.LowPrice;
var threshold = atrValue * Multiplier;
if (!_initialized)
{
_swingHigh = high;
_swingLow = low;
_initialized = true;
return;
}
if (_trendUp)
{
// Track swing high
if (high > _swingHigh)
_swingHigh = high;
// Reversal: price breaks below swing high minus threshold
if (close < _swingHigh - threshold)
{
_trendUp = false;
_swingLow = low;
// Enter short on trend reversal
if (Position > 0)
SellMarket();
if (Position == 0)
SellMarket();
}
}
else
{
// Track swing low
if (low < _swingLow)
_swingLow = low;
// Reversal: price breaks above swing low plus threshold
if (close > _swingLow + threshold)
{
_trendUp = true;
_swingHigh = high;
// Enter long on trend reversal
if (Position < 0)
BuyMarket();
if (Position == 0)
BuyMarket();
}
}
}
}
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 AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class spazm_volatility_breakout_strategy(Strategy):
def __init__(self):
super(spazm_volatility_breakout_strategy, self).__init__()
self._atr_length = self.Param("AtrLength", 14).SetDisplay("ATR Length", "Period for ATR volatility", "Indicators")
self._multiplier = self.Param("Multiplier", 2.0).SetDisplay("Multiplier", "ATR multiplier for breakout threshold", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))).SetDisplay("Candle Type", "Timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(spazm_volatility_breakout_strategy, self).OnReseted()
self._swing_high = 0
self._swing_low = 999999999
self._trend_up = True
self._initialized = False
def OnStarted2(self, time):
super(spazm_volatility_breakout_strategy, self).OnStarted2(time)
self._swing_high = 0
self._swing_low = 999999999
self._trend_up = True
self._initialized = False
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, atr)
self.DrawOwnTrades(area)
def OnProcess(self, candle, atr_val):
if candle.State != CandleStates.Finished:
return
if atr_val <= 0:
return
close = float(candle.ClosePrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
threshold = atr_val * self._multiplier.Value
if not self._initialized:
self._swing_high = high
self._swing_low = low
self._initialized = True
return
if self._trend_up:
if high > self._swing_high:
self._swing_high = high
if close < self._swing_high - threshold:
self._trend_up = False
self._swing_low = low
if self.Position > 0:
self.SellMarket()
if self.Position == 0:
self.SellMarket()
else:
if low < self._swing_low:
self._swing_low = low
if close > self._swing_low + threshold:
self._trend_up = True
self._swing_high = high
if self.Position < 0:
self.BuyMarket()
if self.Position == 0:
self.BuyMarket()
def CreateClone(self):
return spazm_volatility_breakout_strategy()