Прорыв по исторической волатильности
Этот метод прорыва использует историческую волатильность для установки динамических уровней. Когда цена проходит выше или ниже контрольного уровня больше, чем текущая волатильность, это указывает на возможный тренд.
Тестирование показывает среднегодичную доходность около 154%. Стратегию лучше запускать на фондовом рынке.
Стратегия сравнивает цену с уровнями, основанными на стандартном отклонении и простой скользящей средней. Прорывы выше или ниже этих уровней запускают сделки.
Выходы происходят, когда цена пересекает скользящую среднюю в обратную сторону или срабатывает стоп.
Подробности
- Условия входа: цена пробивает уровень, основанный на HV.
- Длинные/короткие позиции: обе стороны.
- Условия выхода: цена пересекает MA или стоп.
- Стопы: да.
- Значения по умолчанию:
HvPeriod= 20MAPeriod= 20StopLossPercent= 2.0mCandleType= TimeSpan.FromMinutes(5)
- Фильтры:
- Категория: Breakout
- Направление: обе стороны
- Индикаторы: HV, MA
- Стопы: да
- Сложность: средняя
- Таймфрейм: внутридневной
- Сезонность: нет
- Нейросети: нет
- Дивергенция: нет
- Уровень риска: средний
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that trades breakouts based on historical volatility.
/// It calculates price levels for breakouts using the historical volatility
/// and enters positions when price breaks above or below those levels.
/// </summary>
public class HvBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _hvPeriod;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private decimal _referencePrice;
private bool _isReferenceSet;
private int _cooldown;
/// <summary>
/// Period for Historical Volatility calculation.
/// </summary>
public int HvPeriod
{
get => _hvPeriod.Value;
set => _hvPeriod.Value = value;
}
/// <summary>
/// Period for Moving Average calculation for exit.
/// </summary>
public int MAPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Type of candles used for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Initialize the Historical Volatility Breakout strategy.
/// </summary>
public HvBreakoutStrategy()
{
_hvPeriod = Param(nameof(HvPeriod), 20)
.SetDisplay("HV Period", "Period for Historical Volatility calculation", "Indicators")
.SetOptimize(10, 30, 5);
_maPeriod = Param(nameof(MAPeriod), 20)
.SetDisplay("MA Period", "Period for Moving Average calculation for exit", "Indicators")
.SetOptimize(10, 50, 5);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_referencePrice = default;
_isReferenceSet = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_referencePrice = 0;
_isReferenceSet = false;
_cooldown = 0;
var standardDeviation = new StandardDeviation { Length = HvPeriod };
var sma = new SimpleMovingAverage { Length = MAPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(standardDeviation, sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal stdDevValue, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var hv = candle.ClosePrice > 0 ? stdDevValue / candle.ClosePrice : 0;
if (!_isReferenceSet)
{
_referencePrice = candle.ClosePrice;
_isReferenceSet = true;
return;
}
if (_cooldown > 0)
{
_cooldown--;
return;
}
var upperBreakoutLevel = _referencePrice * (1 + hv);
var lowerBreakoutLevel = _referencePrice * (1 - hv);
if (Position == 0)
{
if (candle.ClosePrice > upperBreakoutLevel)
{
BuyMarket();
_cooldown = CooldownBars;
_referencePrice = candle.ClosePrice;
}
else if (candle.ClosePrice < lowerBreakoutLevel)
{
SellMarket();
_cooldown = CooldownBars;
_referencePrice = candle.ClosePrice;
}
}
else if (Position > 0)
{
if (candle.ClosePrice < smaValue)
{
SellMarket();
_cooldown = CooldownBars;
}
}
else if (Position < 0)
{
if (candle.ClosePrice > smaValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
}
}
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 StandardDeviation, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class hv_breakout_strategy(Strategy):
"""
Strategy that trades breakouts based on historical volatility.
Calculates price levels for breakouts using HV and enters positions
when price breaks above or below those levels.
"""
def __init__(self):
super(hv_breakout_strategy, self).__init__()
self._hv_period = self.Param("HvPeriod", 20).SetDisplay("HV Period", "Period for Historical Volatility calculation", "Indicators")
self._ma_period = self.Param("MAPeriod", 20).SetDisplay("MA Period", "Period for Moving Average calculation for exit", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._reference_price = 0.0
self._is_reference_set = False
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(hv_breakout_strategy, self).OnReseted()
self._reference_price = 0.0
self._is_reference_set = False
self._cooldown = 0
def OnStarted2(self, time):
super(hv_breakout_strategy, self).OnStarted2(time)
self._reference_price = 0.0
self._is_reference_set = False
self._cooldown = 0
std_dev = StandardDeviation()
std_dev.Length = self._hv_period.Value
sma = SimpleMovingAverage()
sma.Length = self._ma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(std_dev, sma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, std_dev_val, sma_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
hv = float(std_dev_val) / close if close > 0 else 0.0
if not self._is_reference_set:
self._reference_price = close
self._is_reference_set = True
return
if self._cooldown > 0:
self._cooldown -= 1
return
upper_breakout = self._reference_price * (1.0 + hv)
lower_breakout = self._reference_price * (1.0 - hv)
sv = float(sma_val)
cd = self._cooldown_bars.Value
if self.Position == 0:
if close > upper_breakout:
self.BuyMarket()
self._cooldown = cd
self._reference_price = close
elif close < lower_breakout:
self.SellMarket()
self._cooldown = cd
self._reference_price = close
elif self.Position > 0:
if close < sv:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0:
if close > sv:
self.BuyMarket()
self._cooldown = cd
def CreateClone(self):
return hv_breakout_strategy()