Estrategia de Ruptura de Volatilidad
La estrategia de Ruptura de Volatilidad busca movimientos direccionales fuertes cuando el precio escapa de su rango promedio. Midiendo la distancia desde una media móvil simple usando el ATR, el algoritmo define umbrales de ruptura que escalan con la volatilidad.
Las pruebas indican un retorno anual promedio de aproximadamente 97%. Funciona mejor en el mercado de criptomonedas.
Una orden de compra se activa cuando el cierre sube por encima de la SMA en más de Multiplier veces el ATR. Una señal de venta aparece cuando el cierre cae por debajo de la SMA la misma distancia. Las posiciones permanecen abiertas hasta que se produce una ruptura opuesta o se alcanza un stop de protección.
Esta técnica está orientada a los traders intradía que prosperan con los impulsos de momentum. Usar umbrales basados en ATR ayuda a filtrar el ruido para que solo los movimientos significativos generen operaciones.
Detalles
- Criterios de entrada:
- Largo: Close > SMA + Multiplier * ATR
- Corto: Close < SMA - Multiplier * ATR
- Largo/Corto: Ambos lados.
- Criterios de salida:
- Largo: Salir cuando se activa una ruptura opuesta o se alcanza el stop-loss
- Corto: Salir cuando se activa una ruptura opuesta o se alcanza el stop-loss
- Stops: Sí, stop-loss a
Multiplier * ATR desde la entrada.
- Valores predeterminados:
Period = 20
Multiplier = 2.0m
CandleType = TimeSpan.FromMinutes(5)
- Filtros:
- Categoría: Ruptura
- Dirección: Ambos
- Indicadores: SMA, ATR
- Stops: Sí
- Complejidad: Intermedio
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Volatility Breakout strategy. Enters trades when price breaks out from average price with volatility threshold.
/// </summary>
public class VolatilityBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _periodParam;
private readonly StrategyParam<decimal> _multiplierParam;
private readonly StrategyParam<DataType> _candleTypeParam;
private SimpleMovingAverage _sma;
private AverageTrueRange _atr;
private decimal _prevSma;
private decimal _prevAtr;
/// <summary>
/// Period for SMA and ATR calculations.
/// </summary>
public int Period
{
get => _periodParam.Value;
set => _periodParam.Value = value;
}
/// <summary>
/// Volatility multiplier for breakout threshold.
/// </summary>
public decimal Multiplier
{
get => _multiplierParam.Value;
set => _multiplierParam.Value = value;
}
/// <summary>
/// Candle type for strategy.
/// </summary>
public DataType CandleType
{
get => _candleTypeParam.Value;
set => _candleTypeParam.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public VolatilityBreakoutStrategy()
{
_periodParam = Param(nameof(Period), 20)
.SetGreaterThanZero()
.SetDisplay("Period", "Period for SMA and ATR", "Parameters")
.SetOptimize(10, 50, 5);
_multiplierParam = Param(nameof(Multiplier), 2.0m)
.SetRange(0.1m, decimal.MaxValue)
.SetDisplay("Multiplier", "Volatility multiplier for breakout threshold", "Parameters")
.SetOptimize(1.0m, 3.0m, 0.5m);
_candleTypeParam = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle type for strategy", "Common");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_sma = null;
_atr = null;
_prevSma = 0;
_prevAtr = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicators
_sma = new SMA { Length = Period };
_atr = new AverageTrueRange { Length = Period };
// Create subscription and bind indicators
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_sma, _atr, ProcessCandle)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _sma);
DrawOwnTrades(area);
}
// Enable position protection
StartProtection(
takeProfit: new Unit(0, UnitTypes.Absolute), // No take profit
stopLoss: new Unit(Multiplier, UnitTypes.Absolute) // Stop loss at 2*ATR
);
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue, decimal atrValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Save values for the next candle
var currentSma = smaValue;
var currentAtr = atrValue;
// Skip first candle after indicators become formed
if (_prevSma == 0 || _prevAtr == 0)
{
_prevSma = currentSma;
_prevAtr = currentAtr;
return;
}
// Calculate volatility threshold
var threshold = Multiplier * currentAtr;
// Check for long setup - price breaks above SMA + threshold
if (candle.ClosePrice > currentSma + threshold && Position <= 0)
{
// Close any short position and open long
BuyMarket(Volume + Math.Abs(Position));
}
// Check for short setup - price breaks below SMA - threshold
else if (candle.ClosePrice < currentSma - threshold && Position >= 0)
{
// Close any long position and open short
SellMarket(Volume + Math.Abs(Position));
}
// Update previous values for next candle
_prevSma = currentSma;
_prevAtr = currentAtr;
}
}
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, UnitTypes, Unit, ICandleMessage, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class volatility_breakout_strategy(Strategy):
"""
Volatility Breakout strategy. Enters trades when price breaks out from average price with volatility threshold.
"""
def __init__(self):
super(volatility_breakout_strategy, self).__init__()
# Period for SMA and ATR calculations.
self._period_param = self.Param("Period", 20) \
.SetGreaterThanZero() \
.SetDisplay("Period", "Period for SMA and ATR", "Parameters") \
.SetCanOptimize(True) \
.SetOptimize(10, 50, 5)
# Volatility multiplier for breakout threshold.
self._multiplier_param = self.Param("Multiplier", 2.0) \
.SetRange(0.1, float('inf')) \
.SetDisplay("Multiplier", "Volatility multiplier for breakout threshold", "Parameters") \
.SetCanOptimize(True) \
.SetOptimize(1.0, 3.0, 0.5)
# Candle type for strategy.
self._candle_type_param = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Candle type for strategy", "Common")
# Indicators and state variables
self._sma = None
self._atr = None
self._prev_sma = 0.0
self._prev_atr = 0.0
@property
def Period(self):
"""Period for SMA and ATR calculations."""
return self._period_param.Value
@Period.setter
def Period(self, value):
self._period_param.Value = value
@property
def Multiplier(self):
"""Volatility multiplier for breakout threshold."""
return self._multiplier_param.Value
@Multiplier.setter
def Multiplier(self, value):
self._multiplier_param.Value = value
@property
def CandleType(self):
"""Candle type for strategy."""
return self._candle_type_param.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type_param.Value = value
def GetWorkingSecurities(self):
"""See base class for details."""
return [(self.Security, self.CandleType)]
def OnReseted(self):
super(volatility_breakout_strategy, self).OnReseted()
self._sma = None
self._atr = None
self._prev_sma = 0.0
self._prev_atr = 0.0
def OnStarted2(self, time):
"""Called when the strategy starts."""
super(volatility_breakout_strategy, self).OnStarted2(time)
# Create indicators
self._sma = SimpleMovingAverage()
self._sma.Length = self.Period
self._atr = AverageTrueRange()
self._atr.Length = self.Period
# Create subscription and bind indicators
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._sma, self._atr, self.ProcessCandle).Start()
# Setup chart visualization if available
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._sma)
self.DrawOwnTrades(area)
# Enable position protection
self.StartProtection(
takeProfit=Unit(0, UnitTypes.Absolute),
stopLoss=Unit(self.Multiplier, UnitTypes.Absolute)
)
def ProcessCandle(self, candle, sma_value, atr_value):
"""Process candle with SMA and ATR values."""
# Skip unfinished candles
if candle.State != CandleStates.Finished:
return
# Save values for the next candle
current_sma = sma_value
current_atr = atr_value
# Skip first candle after indicators become formed
if self._prev_sma == 0 or self._prev_atr == 0:
self._prev_sma = current_sma
self._prev_atr = current_atr
return
# Calculate volatility threshold
threshold = self.Multiplier * current_atr
# Check for long setup - price breaks above SMA + threshold
if candle.ClosePrice > current_sma + threshold and self.Position <= 0:
# Close any short position and open long
self.BuyMarket(self.Volume + Math.Abs(self.Position))
# Check for short setup - price breaks below SMA - threshold
elif candle.ClosePrice < current_sma - threshold and self.Position >= 0:
# Close any long position and open short
self.SellMarket(self.Volume + Math.Abs(self.Position))
# Update previous values for next candle
self._prev_sma = current_sma
self._prev_atr = current_atr
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return volatility_breakout_strategy()