Donchian チャネル幅ブレイクアウト戦略
Donchian チャネル幅ブレイクアウト戦略は、Donchian の急激な拡張を観察します。読み値が平均的な範囲を超えてジャンプすると、価格はしばしば新しい動きを開始します。
テストでは年平均リターン約61%を示しています。暗号通貨市場で最もよく機能します。
インジケーターが最近のデータと偏差乗数から導かれたバンドを突き抜けると、ポジションが開きます。ストップを付けたロングとショートの両取引が可能です。
このシステムは早期ブレイクアウトを求めるモメンタムトレーダーに適しています。Donchian が平均に戻るとトレードはクローズされます。デフォルト値は DonchianPeriod = 20 から始まります。
詳細
- エントリー条件: インジケーターが偏差乗数分だけ平均を上回る。
- ロング/ショート: 両方向。
- エグジット条件: インジケーターが平均に戻る。
- ストップ: はい。
- デフォルト値:
DonchianPeriod= 20AvgPeriod= 20Multiplier= 2.0mCandleType= TimeSpan.FromMinutes(5)StopLoss= 2.0m
- フィルター:
- カテゴリ: ブレイクアウト
- 方向: 両方
- インジケーター: Donchian
- ストップ: はい
- 複雑さ: 中級
- 時間軸: 短期
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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>
/// Donchian Channel width breakout.
/// Enters when the channel width exceeds its average by a standard deviation multiplier,
/// in the direction of the close relative to the channel middle.
/// Exits when the width falls back below its average.
/// </summary>
public class DonchianWidthBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _donchianPeriod;
private readonly StrategyParam<int> _avgPeriod;
private readonly StrategyParam<decimal> _multiplier;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _stopLoss;
private SimpleMovingAverage _widthAverage;
private StandardDeviation _widthStdDev;
/// <summary>
/// Donchian Channel period.
/// </summary>
public int DonchianPeriod
{
get => _donchianPeriod.Value;
set => _donchianPeriod.Value = value;
}
/// <summary>
/// Period for the width average and standard deviation.
/// </summary>
public int AvgPeriod
{
get => _avgPeriod.Value;
set => _avgPeriod.Value = value;
}
/// <summary>
/// Standard deviation multiplier for the width breakout.
/// </summary>
public decimal Multiplier
{
get => _multiplier.Value;
set => _multiplier.Value = value;
}
/// <summary>
/// Candle type for strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Stop-loss percentage.
/// </summary>
public decimal StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Initialize <see cref="DonchianWidthBreakoutStrategy"/>.
/// </summary>
public DonchianWidthBreakoutStrategy()
{
_donchianPeriod = Param(nameof(DonchianPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Donchian Period", "Period of the Donchian Channel", "Indicators");
_avgPeriod = Param(nameof(AvgPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Average Period", "Period for width average and deviation", "Strategy");
_multiplier = Param(nameof(Multiplier), 2.0m)
.SetGreaterThanZero()
.SetDisplay("Multiplier", "Standard deviation multiplier for breakout", "Strategy");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_stopLoss = Param(nameof(StopLoss), 2.0m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop-loss percentage", "Risk Management");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_widthAverage = null;
_widthStdDev = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var highest = new Highest { Length = DonchianPeriod };
var lowest = new Lowest { Length = DonchianPeriod };
_widthAverage = new SimpleMovingAverage { Length = AvgPeriod };
_widthStdDev = new StandardDeviation { Length = AvgPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, ProcessCandle)
.Start();
StartProtection(
takeProfit: null,
stopLoss: StopLoss > 0 ? new Unit(StopLoss, UnitTypes.Percent) : null
);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, highest);
DrawIndicator(area, lowest);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal highestValue, decimal lowestValue)
{
if (candle.State != CandleStates.Finished)
return;
var width = highestValue - lowestValue;
var avgWidth = _widthAverage.Process(width, candle.ServerTime, true).ToDecimal();
var stdWidth = _widthStdDev.Process(width, candle.ServerTime, true).ToDecimal();
if (!_widthAverage.IsFormed || !_widthStdDev.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var middle = (highestValue + lowestValue) / 2m;
if (width > avgWidth + Multiplier * stdWidth)
{
if (close > middle && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
return;
}
if (close < middle && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
return;
}
}
if (width < avgWidth)
{
if (Position > 0)
SellMarket(Position);
else if (Position < 0)
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
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import Highest, Lowest, SimpleMovingAverage, StandardDeviation
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class donchian_width_breakout_strategy(Strategy):
"""
Donchian Channel width breakout.
Enters when the channel width exceeds its average by a standard deviation multiplier,
in the direction of the close relative to the channel middle.
Exits when the width falls back below its average.
"""
def __init__(self):
super(donchian_width_breakout_strategy, self).__init__()
self._donchian_period = self.Param("DonchianPeriod", 20) \
.SetGreaterThanZero() \
.SetDisplay("Donchian Period", "Period of the Donchian Channel", "Indicators")
self._avg_period = self.Param("AvgPeriod", 20) \
.SetGreaterThanZero() \
.SetDisplay("Average Period", "Period for width average and deviation", "Strategy")
self._multiplier = self.Param("Multiplier", 2.0) \
.SetGreaterThanZero() \
.SetDisplay("Multiplier", "Standard deviation multiplier for breakout", "Strategy")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._stop_loss = self.Param("StopLoss", 2.0) \
.SetNotNegative() \
.SetDisplay("Stop Loss %", "Stop-loss percentage", "Risk Management")
self._width_average = None
self._width_std_dev = None
@property
def CandleType(self):
return self._candle_type.Value
def GetWorkingSecurities(self):
return [(self.Security, self.CandleType)]
def OnReseted(self):
super(donchian_width_breakout_strategy, self).OnReseted()
self._width_average = None
self._width_std_dev = None
def OnStarted2(self, time):
super(donchian_width_breakout_strategy, self).OnStarted2(time)
highest = Highest()
highest.Length = self._donchian_period.Value
lowest = Lowest()
lowest.Length = self._donchian_period.Value
self._width_average = SimpleMovingAverage()
self._width_average.Length = self._avg_period.Value
self._width_std_dev = StandardDeviation()
self._width_std_dev.Length = self._avg_period.Value
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._process_candle).Start()
stop = float(self._stop_loss.Value)
self.StartProtection(None, Unit(stop, UnitTypes.Percent) if stop > 0 else None)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, highest)
self.DrawIndicator(area, lowest)
self.DrawOwnTrades(area)
def _process_candle(self, candle, highest_value, lowest_value):
if candle.State != CandleStates.Finished:
return
highest_value = float(highest_value)
lowest_value = float(lowest_value)
width = highest_value - lowest_value
avg_width = float(process_float(self._width_average, width, candle.ServerTime, True))
std_width = float(process_float(self._width_std_dev, width, candle.ServerTime, True))
if not self._width_average.IsFormed or not self._width_std_dev.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
close = float(candle.ClosePrice)
middle = (highest_value + lowest_value) / 2.0
if width > avg_width + float(self._multiplier.Value) * std_width:
if close > middle and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
return
if close < middle and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
return
if width < avg_width:
if self.Position > 0:
self.SellMarket(self.Position)
elif self.Position < 0:
self.BuyMarket(-self.Position)
def CreateClone(self):
return donchian_width_breakout_strategy()