Donchian-Kanal
Strategie basierend auf dem Donchian-Kanal.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 52%. Die Strategie funktioniert am besten im Kryptomarkt.
Der Donchian-Kanal-Ausbruch handelt neue Hochs und Tiefs basierend auf dem Kanalbereich. Ein Schlusskurs über dem oberen Band signalisiert Stärke, während ein Fall unter das untere Band Shorts einlädt. Ausstiege erfolgen, wenn der Preis zum Mittelpunkt zurückkommt.
Der Kanal wird aus dem höchsten Hoch und dem niedrigsten Tief über ein Lookback-Fenster berechnet. Wenn der Preis diese Grenzen durchbricht, erwartet das System eine Volatilitätsexpansion und positioniert sich entsprechend.
Details
- Einstiegskriterien: Signale basierend auf Price Action.
- Long/Short: Beide Richtungen.
- Ausstiegskriterien: Gegensätzliches Signal.
- Stops: Nein.
- Standardwerte:
ChannelPeriod= 20CandleType= TimeSpan.FromMinutes(5)
- Filter:
- Kategorie: Trend
- Richtung: Beide
- Indikatoren: Price Action
- Stops: Nein
- Komplexität: Grundlegend
- Zeitrahmen: Intraday (5m)
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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>
/// Strategy based on Donchian Channel.
/// It enters long position when price breaks through the upper band and short position when price breaks through the lower band.
/// </summary>
public class DonchianChannelStrategy : Strategy
{
private readonly StrategyParam<int> _channelPeriod;
private readonly StrategyParam<DataType> _candleType;
// Current state
private decimal _prevClosePrice;
private decimal _prevUpperBand;
private decimal _prevLowerBand;
/// <summary>
/// Period for Donchian Channel.
/// </summary>
public int ChannelPeriod
{
get => _channelPeriod.Value;
set => _channelPeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize the Donchian Channel strategy.
/// </summary>
public DonchianChannelStrategy()
{
_channelPeriod = Param(nameof(ChannelPeriod), 1000)
.SetDisplay("Channel Period", "Period for Donchian Channel calculation", "Indicators")
.SetOptimize(10, 50, 5);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).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();
_prevClosePrice = default;
_prevUpperBand = default;
_prevLowerBand = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicators
var donchian = new DonchianChannels { Length = ChannelPeriod };
// Create subscription and bind indicators
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(donchian, ProcessCandle)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, donchian);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue donchianValue)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Check if strategy is ready to trade
if (!IsFormedAndOnlineAndAllowTrading())
return;
var donchianTyped = (DonchianChannelsValue)donchianValue;
if (donchianTyped.UpperBand is not decimal upperValue ||
donchianTyped.LowerBand is not decimal lowerValue ||
donchianTyped.Middle is not decimal midValue)
{
return;
}
// Skip the first received value for proper comparison
if (_prevUpperBand == 0)
{
_prevClosePrice = candle.ClosePrice;
_prevUpperBand = upperValue;
_prevLowerBand = lowerValue;
return;
}
// Check for breakouts
var isUpperBreakout = candle.ClosePrice > _prevUpperBand && _prevClosePrice <= _prevUpperBand;
var isLowerBreakout = candle.ClosePrice < _prevLowerBand && _prevClosePrice >= _prevLowerBand;
// Entry logic - breakout reversal
if (isUpperBreakout && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
}
else if (isLowerBreakout && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
}
// Update previous values
_prevClosePrice = candle.ClosePrice;
_prevUpperBand = upperValue;
_prevLowerBand = lowerValue;
}
}
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_channel_strategy(Strategy):
"""
Strategy based on Donchian Channel.
Enters long when price breaks above upper band, short when price breaks below lower band.
"""
def __init__(self):
super(donchian_channel_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 1000).SetDisplay("Channel Period", "Period for Donchian Channel calculation", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_close_price = 0.0
self._prev_upper_band = 0.0
self._prev_lower_band = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(donchian_channel_strategy, self).OnReseted()
self._prev_close_price = 0.0
self._prev_upper_band = 0.0
self._prev_lower_band = 0.0
def OnStarted2(self, time):
super(donchian_channel_strategy, self).OnStarted2(time)
donchian = DonchianChannels()
donchian.Length = self._channel_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_val):
if candle.State != CandleStates.Finished:
return
if donchian_val.UpperBand is None or donchian_val.LowerBand is None or donchian_val.Middle is None:
return
upper = float(donchian_val.UpperBand)
lower = float(donchian_val.LowerBand)
if self._prev_upper_band == 0:
self._prev_close_price = float(candle.ClosePrice)
self._prev_upper_band = upper
self._prev_lower_band = lower
return
close = float(candle.ClosePrice)
is_upper_breakout = close > self._prev_upper_band and self._prev_close_price <= self._prev_upper_band
is_lower_breakout = close < self._prev_lower_band and self._prev_close_price >= self._prev_lower_band
if is_upper_breakout and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif is_lower_breakout and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._prev_close_price = close
self._prev_upper_band = upper
self._prev_lower_band = lower
def CreateClone(self):
return donchian_channel_strategy()