ドンチャンチャネル リバーサルストラテジー
Donchian Channelは選択した期間の直近の高値と安値をマークします。それらの境界を突き抜けてから反転する価格は枯渇を示す可能性があります。この戦略は短いブレイクアウトの後にチャネル内に戻る終値を観察します。
テストでは年平均リターン約157%を示しています。暗号通貨市場で最も優れたパフォーマンスを発揮します。
前の終値が下限バンドを下回り、現在の終値がその上に戻ると、ロングトレードが取られます。逆に、前の終値が上限バンドを上回り、価格が戻って内側に落ちると、ショートが開かれます。パーセンテージストップが両方のケースでリスクを管理します。
失敗したブレイクアウトの後にのみ取引することで、このアプローチは素早く反転する偽の動きを捉えようとします。
詳細
- エントリー条件: 価格が上限または下限バンドを突破した後、Donchian Channel内に戻って終値をつける。
- ロング/ショート: 両方。
- エグジット条件: ストップロス。
- ストップ: はい、パーセンテージベース。
- デフォルト値:
Period= 20StopLoss= 2%CandleType= 15 minute
- フィルター:
- カテゴリ: リバーサル
- 方向: 両方
- インジケーター: Donchian Channel
- ストップ: はい
- 複雑さ: 基本
- 時間軸: イントラデイ
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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 Reversal strategy.
/// Enters long when price bounces from the lower Donchian Channel band.
/// Enters short when price bounces from the upper Donchian Channel band.
/// Exits at middle band.
/// Uses cooldown to control trade frequency.
/// </summary>
public class DonchianReversalStrategy : Strategy
{
private readonly StrategyParam<int> _period;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private decimal _prevClose;
private int _cooldown;
/// <summary>
/// Donchian period.
/// </summary>
public int Period
{
get => _period.Value;
set => _period.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public DonchianReversalStrategy()
{
_period = Param(nameof(Period), 20)
.SetRange(10, 40)
.SetDisplay("Period", "Period for Donchian Channel", "Indicators");
_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();
_prevClose = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = 0;
_cooldown = 0;
var donchian = new DonchianChannels { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(donchian, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, donchian);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue donchianIv)
{
if (candle.State != CandleStates.Finished)
return;
if (!donchianIv.IsFormed)
return;
var dv = (IDonchianChannelsValue)donchianIv;
if (dv.UpperBand is not decimal upper ||
dv.LowerBand is not decimal lower ||
dv.Middle is not decimal middle)
return;
if (_prevClose == 0)
{
_prevClose = candle.ClosePrice;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevClose = candle.ClosePrice;
return;
}
// Bounce from lower band = bullish
var bouncedFromLower = _prevClose <= lower && candle.ClosePrice > lower;
// Bounce from upper band = bearish
var bouncedFromUpper = _prevClose >= upper && candle.ClosePrice < upper;
if (Position == 0 && bouncedFromLower)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && bouncedFromUpper)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && candle.ClosePrice >= middle && bouncedFromUpper)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && candle.ClosePrice <= middle && bouncedFromLower)
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevClose = candle.ClosePrice;
}
}
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 DonchianChannels
from StockSharp.Algo.Strategies import Strategy
class donchian_reversal_strategy(Strategy):
"""
Donchian Reversal strategy.
Enters long when price bounces from the lower Donchian Channel band.
Enters short when price bounces from the upper Donchian Channel band.
Exits at middle band.
Uses cooldown to control trade frequency.
"""
def __init__(self):
super(donchian_reversal_strategy, self).__init__()
self._period = self.Param("Period", 20).SetDisplay("Period", "Period for Donchian Channel", "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._prev_close = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(donchian_reversal_strategy, self).OnReseted()
self._prev_close = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(donchian_reversal_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._cooldown = 0
donchian = DonchianChannels()
donchian.Length = self._period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(donchian, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, donchian)
self.DrawOwnTrades(area)
def _process_candle(self, candle, donchian_iv):
if candle.State != CandleStates.Finished:
return
if not donchian_iv.IsFormed:
return
upper_val = donchian_iv.UpperBand
lower_val = donchian_iv.LowerBand
middle_val = donchian_iv.Middle
if upper_val is None or lower_val is None or middle_val is None:
return
upper = float(upper_val)
lower = float(lower_val)
middle = float(middle_val)
close = float(candle.ClosePrice)
if self._prev_close == 0:
self._prev_close = close
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_close = close
return
cd = self._cooldown_bars.Value
# Bounce from lower band = bullish
bounced_from_lower = self._prev_close <= lower and close > lower
# Bounce from upper band = bearish
bounced_from_upper = self._prev_close >= upper and close < upper
if self.Position == 0 and bounced_from_lower:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and bounced_from_upper:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and close >= middle and bounced_from_upper:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and close <= middle and bounced_from_lower:
self.BuyMarket()
self._cooldown = cd
self._prev_close = close
def CreateClone(self):
return donchian_reversal_strategy()