Kumulativer Delta-Ausbruch (Cumulative Delta Breakout)
Das Cumulative Delta summiert die Differenz zwischen Kauf- und Verkaufsvolumen. Diese Strategie überwacht den laufenden Gesamtwert und handelt, wenn er seinen höchsten Wert überschreitet oder seinen niedrigsten Wert innerhalb des Rückblickzeitraums unterschreitet.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 49 %. Die Strategie eignet sich am besten für den Kryptomarkt.
Ein Ausbruch des kumulativen Deltas geht oft einer Kursbewegung voraus. Die Strategie schließt Trades, wenn das Delta wieder durch null kreuzt oder ein Stop-Loss-Level erreicht wird.
Details
- Einstiegskriterien: Das kumulative Delta überschreitet den höchsten oder unterschreitet den niedrigsten Wert im Rückblickzeitraum.
- Long/Short: Beide Richtungen.
- Ausstiegskriterien: Das Delta kreuzt null oder Stop.
- Stops: Ja.
- Standardwerte:
LookbackPeriod= 20CandleType= TimeSpan.FromMinutes(5)
- Filter:
- Kategorie: Ausbruch
- Richtung: Beide
- Indikatoren: Cumulative Delta
- Stops: Ja
- Komplexität: Mittel
- Zeitrahmen: Intraday
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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>
/// Cumulative Delta Breakout strategy.
/// Estimates delta from candle direction and volume.
/// Long: Cumulative delta rising and price above SMA.
/// Short: Cumulative delta falling and price below SMA.
/// </summary>
public class CumulativeDeltaBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private decimal _cumulativeDelta;
private decimal _prevDelta;
private int _cooldown;
/// <summary>
/// MA Period.
/// </summary>
public int MAPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Candle type 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 <see cref="CumulativeDeltaBreakoutStrategy"/>.
/// </summary>
public CumulativeDeltaBreakoutStrategy()
{
_maPeriod = Param(nameof(MAPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Period for SMA", "Indicators")
.SetOptimize(10, 50, 10);
_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();
_cumulativeDelta = default;
_prevDelta = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_cumulativeDelta = 0;
_prevDelta = 0;
_cooldown = 0;
var sma = new SimpleMovingAverage { Length = MAPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Estimate delta from candle: bullish candle adds volume, bearish subtracts
var delta = candle.ClosePrice >= candle.OpenPrice
? candle.TotalVolume
: -candle.TotalVolume;
_cumulativeDelta += delta;
if (_prevDelta == 0)
{
_prevDelta = _cumulativeDelta;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevDelta = _cumulativeDelta;
return;
}
var deltaRising = _cumulativeDelta > _prevDelta;
if (Position == 0)
{
if (deltaRising && candle.ClosePrice > smaValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (!deltaRising && candle.ClosePrice < smaValue)
{
SellMarket();
_cooldown = CooldownBars;
}
}
else if (Position > 0 && !deltaRising)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && deltaRising)
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevDelta = _cumulativeDelta;
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class cumulative_delta_breakout_strategy(Strategy):
"""
Cumulative Delta Breakout strategy.
Estimates delta from candle direction and volume.
Long: Cumulative delta rising and price above SMA.
Short: Cumulative delta falling and price below SMA.
"""
def __init__(self):
super(cumulative_delta_breakout_strategy, self).__init__()
self._ma_period = self.Param("MAPeriod", 20).SetDisplay("MA Period", "Period for SMA", "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._cumulative_delta = 0.0
self._prev_delta = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(cumulative_delta_breakout_strategy, self).OnReseted()
self._cumulative_delta = 0.0
self._prev_delta = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(cumulative_delta_breakout_strategy, self).OnStarted2(time)
self._cumulative_delta = 0.0
self._prev_delta = 0.0
self._cooldown = 0
sma = SimpleMovingAverage()
sma.Length = self._ma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(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, sma_val):
if candle.State != CandleStates.Finished:
return
# Estimate delta from candle: bullish adds volume, bearish subtracts
vol = float(candle.TotalVolume)
if float(candle.ClosePrice) >= float(candle.OpenPrice):
delta = vol
else:
delta = -vol
self._cumulative_delta += delta
if self._prev_delta == 0:
self._prev_delta = self._cumulative_delta
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_delta = self._cumulative_delta
return
delta_rising = self._cumulative_delta > self._prev_delta
close = float(candle.ClosePrice)
sv = float(sma_val)
cd = self._cooldown_bars.Value
if self.Position == 0:
if delta_rising and close > sv:
self.BuyMarket()
self._cooldown = cd
elif not delta_rising and close < sv:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and not delta_rising:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and delta_rising:
self.BuyMarket()
self._cooldown = cd
self._prev_delta = self._cumulative_delta
def CreateClone(self):
return cumulative_delta_breakout_strategy()