Стратегия Volatility Breakout
Стратегия Volatility Breakout ищет сильные направленные движения, когда цена выходит за пределы своего среднего диапазона. Измеряя расстояние от простой скользящей средней с помощью ATR, алгоритм задаёт порог breakout, который масштабируется в зависимости от волатильности.
Тестирование показывает среднегодичную доходность около 97%. Стратегию лучше запускать на крипторынке.
Покупка происходит, когда закрытие поднимается выше SMA более чем на Multiplier * ATR. Сигнал на продажу появляется, когда закрытие опускается ниже SMA на такое же расстояние. Позиции остаются открытыми до противоположного пробоя или срабатывания защитного стопа.
Такой подход ориентирован на внутридневных трейдеров, работающих на импульсных движениях. Порог на основе ATR помогает фильтровать шум, чтобы сделки открывались только при значимых движениях.
Детали
- Условия входа:
- Лонг: Close > SMA + Multiplier * ATR
- Шорт: Close < SMA - Multiplier * ATR
- Лонг/Шорт: обе стороны.
- Условия выхода:
- Лонг: Закрыть при противоположном пробое или срабатывании стопа
- Шорт: Закрыть при противоположном пробое или срабатывании стопа
- Стопы: да, стоп‑лосс на расстоянии
Multiplier * ATRот входа. - Значения по умолчанию:
Period= 20Multiplier= 2.0mCandleType= TimeSpan.FromMinutes(5)
- Фильтры:
- Категория: Breakout
- Направление: Оба
- Индикаторы: SMA, ATR
- Стопы: Да
- Сложность: Средняя
- Таймфрейм: Внутридневной
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
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()