Conversão do consultor especialista MetaTrader 4 Spazm (8683) para o StockSharp API de alto nível.
Negocia rompimentos adaptativos comparando o fechamento mais recente com envelopes do tamanho da volatilidade em torno da oscilação máxima e mínima mais recente.
Mantém anotações de gráfico opcionais que unem pivôs consecutivos de alta e baixa, assim como a visualização original MQL.
Preparação de Dados
A estratégia assina a série de velas especificada pelo parâmetro CandleType para o título ativo.
Cada vela finalizada fornece a amostra bruta usada para estimativa de volatilidade:
Por padrão, o intervalo é igual a High - Low.
Quando UseOpenCloseRange está ativado, o tamanho absoluto do corpo |Open - Close| é usado.
A amostra de intervalo é convertida em etapas de preço usando o instrumento PriceStep para que a lógica permaneça invariante entre os símbolos.
O indicador definido por UseWeightedVolatility processa a sequência de amostras de intervalo:
Desativado → média móvel simples com comprimento VolatilityPeriod.
Ativado → média móvel ponderada linear (mais peso para velas recentes).
O intervalo suavizado (expresso em etapas) é multiplicado por VolatilityMultiplier e finalmente reduzido para unidades de preço. O valor resultante é o limite de ruptura adaptativo aplicado a ambos os lados do mercado.
Durante a fase de aquecimento, a estratégia também registra os máximos e mínimos extremos mais recentes, juntamente com seus carimbos de data e hora. Depois que VolatilityPeriod * 3 velas são processadas, o tempo relativo desses extremos determina a direção da tendência inicial.
Parâmetros
Nome
Padrão
Descrição
Volume
1
Volume de ordens enviado sempre que a estratégia abre ou reverte uma posição.
VolatilityMultiplier
5
Multiplicador aplicado à volatilidade média para construir a distância de rompimento.
VolatilityPeriod
24
Número de velas usadas tanto para o estimador de volatilidade quanto para semear os extremos iniciais da oscilação.
UseWeightedVolatility
false
Muda o estimador de volatilidade de uma média móvel ponderada simples para uma média linear ponderada.
UseOpenCloseRange
false
Usa o movimento absoluto de abertura e fechamento em vez da faixa máxima-baixa ao medir a volatilidade.
StopLossMultiplier
0
Multiplicador aplicado ao limite de ruptura para calcular uma distância de parada protetora. Um mínimo de três etapas de preço é aplicado. Defina como 0 para desativar paradas.
DrawSwingLines
true
Quando ativada, a estratégia traça uma linha entre os últimos pivôs de alta e baixa, imitando os objetos MQL.
CandleType
4 hour time frame
Tipo de vela (período de tempo ou outro tipo de dado) que alimenta os cálculos.
Lógica de negociação
Inicialização
Enquanto as primeiras velas VolatilityPeriod * 3 são processadas, a estratégia atualiza _highestPrice, _lowestPrice, _highestTime e _lowestTime para capturar os extremos mais recentes.
Após a chegada de velas suficientes, o mais recente dos dois extremos define a tendência inicial: se a última mínima for mais recente que a última máxima, a estratégia começa no modo de alta, caso contrário, começa em baixa.
Os extremos também são armazenados como o primeiro par de âncoras de balanço, para que as linhas do gráfico possam ser desenhadas imediatamente após o aquecimento.
Acompanhamento de volatilidade
Cada vela finalizada empurra seu alcance para a média móvel selecionada para produzir o limite adaptativo.
O limite é sempre de pelo menos uma etapa de preço para evitar envelopes de distância zero.
Manutenção do balanço
Em cada vela, o algoritmo atualiza a oscilação máxima e mínima armazenada sempre que uma nova máxima ou mínima absoluta é impressa.
Quando a tendência muda, o extremo relevante é registrado como um pivô e, se o gráfico estiver habilitado, conectado ao pivô oposto por uma linha.
Regras de discussão
Regime de alta (_isTrendUp == true): um fechamento abaixo de _highestPrice - threshold desencadeia uma reversão para venda. O tamanho do pedido é igual a Volume + |Position|, portanto a exposição existente é nivelada e uma nova posição curta é aberta em uma chamada.
Regime de baixa (_isTrendUp == false): um fechamento acima de _lowestPrice + threshold reflete a lógica e reverte para longo.
Parar gerenciamento
Quando StopLossMultiplier é maior que zero, o preço de entrada é compensado por threshold * StopLossMultiplier (limitado a pelo menos três etapas de preço) para derivar um nível de stop sintético.
Se uma vela perfurar o stop longo com sua mínima ou o stop curto com sua máxima, a posição será achatada por meio de uma ordem de mercado.
Infraestrutura
StartProtection() ativa mecanismos de segurança StockSharp integrados assim que a estratégia é lançada.
Todas as ações são conduzidas por velas finalizadas para emular o ciclo de recálculo barra por barra do consultor especialista original.
Diferenças da versão MQL
O especialista MetaTrader recalcula a cada tick, enquanto esta porta opera em velas concluídas porque as assinaturas de velas são a fonte de dados idiomática no nível superior API.
Restrições específicas do corretor, como MODE_STOPLEVEL, não estão disponíveis; em vez disso, a compensação do stop é limitada por três etapas de preço para fornecer uma alternativa conservadora.
Os pedidos são revertidos combinando as quantidades de fechamento e abertura em uma única chamada BuyMarket/SellMarket em vez de iterar sobre as posições existentes.
A visualização depende de StockSharp gráficos primitivos (DrawLine) em vez de objetos de plataforma, mas o arranjo das linhas pivô a pivô corresponde à saída do indicador original.
Notas para uso
Certifique-se de que a segurança selecionada exponha um PriceStep válido. Quando ausente, o código padrão é 1, o que pode precisar de ajustes para determinados instrumentos.
Como a estratégia depende de velas concluídas, prazos extremamente pequenos reduzem a confiabilidade da estimativa de volatilidade. Considere alinhar CandleType com o período originalmente usado pelo EA (H4 por padrão).
As paradas são opcionais. Deixar StopLossMultiplier em zero replica o gerenciamento de risco ilimitado do script MQL.
O algoritmo segue tendências por design e não impõe metas de lucro; as saídas ocorrem apenas por reversão de regime ou ativação de 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()