ボラティリティ・ブレイクアウト戦略
ボラティリティ・ブレイクアウト戦略は、価格が平均レンジから脱出したときの強い方向性のある動きを捉えます。ATRを使用して単純移動平均からの距離を測定することで、アルゴリズムはボラティリティに応じてスケールするブレイクアウト閾値を定義します。
テストによると、平均年間リターンは約97%です。暗号通貨市場で最も高いパフォーマンスを発揮します。
終値がSMAをMultiplier倍のATR以上上回ると買いオーダーが発動されます。終値が同じ距離だけSMAを下回ると売りシグナルが現れます。反対方向のブレイクアウトが発生するか保護的なストップに達するまでポジションは開いたままです。
この手法は、モメンタムの急騰で利益を得る日中トレーダー向けです。ATRベースの閾値を使用することで、重要な動きだけが取引を生成するようノイズのフィルタリングに役立ちます。
詳細
- エントリー条件:
- ロング: Close > SMA + Multiplier * ATR
- ショート: Close < SMA - Multiplier * ATR
- ロング/ショート: 両方。
- エグジット条件:
- ロング: 反対方向のブレイクアウトが発動するかストップロスに達した時に決済
- ショート: 反対方向のブレイクアウトが発動するかストップロスに達した時に決済
- ストップ: あり、エントリーから
Multiplier * ATRのストップロス。 - デフォルト値:
Period= 20Multiplier= 2 ストップはエントリー時の終値からPeriod本のATRのMultiplier倍離れた位置に置かれ、ローソク足の終値で確認されます。 保有ポジションと逆方向のエントリーシグナルはドテンになります。CandleType= TimeSpan.FromMinutes(5)
- フィルター:
- カテゴリ: ブレイクアウト
- 方向: 両方
- インジケーター: SMA, ATR
- ストップ: あり
- 複雑さ: 中級
- 時間軸: イントラデイ
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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>
/// Volatility Breakout strategy.
/// A close more than Multiplier times the Period ATR above the Period simple moving average goes long and one that far below it goes short,
/// reversing an opposite position. The position stays open until the opposite breakout, or until the stop Multiplier ATR from the entry
/// close is hit, checked on candle closes.
/// </summary>
public class VolatilityBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _period;
private readonly StrategyParam<decimal> _multiplier;
private readonly StrategyParam<DataType> _candleType;
private decimal _stopPrice;
/// <summary>
/// Period for SMA and ATR.
/// </summary>
public int Period
{
get => _period.Value;
set => _period.Value = value;
}
/// <summary>
/// ATR multiplier for the breakout threshold and the stop.
/// </summary>
public decimal Multiplier
{
get => _multiplier.Value;
set => _multiplier.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public VolatilityBreakoutStrategy()
{
_period = Param(nameof(Period), 20)
.SetGreaterThanZero()
.SetDisplay("Period", "Period for SMA and ATR", "Parameters");
_multiplier = Param(nameof(Multiplier), 2m)
.SetGreaterThanZero()
.SetDisplay("Multiplier", "ATR multiplier for the breakout threshold and the stop", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_stopPrice = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_stopPrice = default;
var sma = new SimpleMovingAverage { Length = Period };
var atr = new AverageTrueRange { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(sma, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
{
DrawIndicator(oscillators, atr);
}
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue smaValue, IIndicatorValue atrValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!smaValue.IsFormed || !atrValue.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var sma = smaValue.GetValue<decimal>();
var distance = Multiplier * atrValue.GetValue<decimal>();
var close = candle.ClosePrice;
if (close > sma + distance && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
_stopPrice = close - distance;
}
else if (close < sma - distance && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
_stopPrice = close + distance;
}
else if (Position > 0 && close <= _stopPrice)
{
SellMarket(Position);
}
else if (Position < 0 && close >= _stopPrice)
{
BuyMarket(-Position);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class volatility_breakout_strategy(Strategy):
"""
Volatility Breakout strategy.
A close more than Multiplier times the Period ATR above the Period simple moving average goes long and one that far below it goes short,
reversing an opposite position. The position stays open until the opposite breakout, or until the stop Multiplier ATR from the entry
close is hit, checked on candle closes.
"""
def __init__(self):
super(volatility_breakout_strategy, self).__init__()
self._period = self.Param("Period", 20).SetGreaterThanZero().SetDisplay("Period", "Period for SMA and ATR", "Parameters")
self._multiplier = self.Param("Multiplier", 2.0).SetGreaterThanZero().SetDisplay("Multiplier", "ATR multiplier for the breakout threshold and the stop", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._stop_price = Decimal(0)
def OnReseted(self):
super(volatility_breakout_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(volatility_breakout_strategy, self).OnStarted2(time)
self._reset_state()
sma = SimpleMovingAverage()
sma.Length = self._period.Value
atr = AverageTrueRange()
atr.Length = self._period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(sma, atr, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, atr)
def _process_candle(self, candle, sma_value, atr_value):
if candle.State != CandleStates.Finished:
return
if not sma_value.IsFormed or not atr_value.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
sma = sma_value.GetValue[Decimal](None)
distance = Decimal(self._multiplier.Value) * atr_value.GetValue[Decimal](None)
close = candle.ClosePrice
if close > sma + distance and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._stop_price = close - distance
elif close < sma - distance and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._stop_price = close + distance
elif self.Position > 0 and close <= self._stop_price:
self.SellMarket(self.Position)
elif self.Position < 0 and close >= self._stop_price:
self.BuyMarket(-self.Position)
def CreateClone(self):
return volatility_breakout_strategy()