ADX für BTC
Die Strategie verwendet den Average Directional Index (ADX) mit einem optionalen SMA-Trendfilter, um starke Bewegungen in Bitcoin zu erfassen.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 80%. Am besten funktioniert sie auf dem Kryptomarkt.
Das System kauft, wenn der ADX das Einstiegsniveau nach oben kreuzt und der Trendfilter bullisch ist. Die Position schließt sich, wenn der ADX unter das Ausstiegsniveau fällt.
Details
- Einstiegskriterien: ADX kreuzt
EntryLevelnach oben und (falls aktiviert) schnelle SMA > langsame SMA. - Long/Short: Nur Long.
- Ausstiegskriterien: ADX kreuzt
ExitLevelnach unten. - Stops: Nein.
- Standardwerte:
EntryLevel= 14mExitLevel= 45mSmaFilter= trueSmaLength= 200CandleType= TimeSpan.FromMinutes(5)
- Filter:
- Kategorie: Trend
- Richtung: Nur Long
- Indikatoren: ADX, SMA
- Stops: Nein
- Komplexität: Grundlegend
- Zeitrahmen: Intraday (5m)
- 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>
/// ADX for BTC strategy.
/// Long only: buys when ADX(14) crosses above EntryLevel while, with SmaFilter enabled, the close is above SMA(SmaLength), and closes
/// the long when ADX crosses below ExitLevel.
/// </summary>
public class AdxForBtcStrategy : Strategy
{
private const int _adxLength = 14;
private readonly StrategyParam<decimal> _entryLevel;
private readonly StrategyParam<decimal> _exitLevel;
private readonly StrategyParam<bool> _smaFilter;
private readonly StrategyParam<int> _smaLength;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevAdx;
/// <summary>
/// ADX level whose upward cross opens a long.
/// </summary>
public decimal EntryLevel
{
get => _entryLevel.Value;
set => _entryLevel.Value = value;
}
/// <summary>
/// ADX level whose downward cross closes the long.
/// </summary>
public decimal ExitLevel
{
get => _exitLevel.Value;
set => _exitLevel.Value = value;
}
/// <summary>
/// Require the close above the SMA.
/// </summary>
public bool SmaFilter
{
get => _smaFilter.Value;
set => _smaFilter.Value = value;
}
/// <summary>
/// SMA period of the trend filter.
/// </summary>
public int SmaLength
{
get => _smaLength.Value;
set => _smaLength.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public AdxForBtcStrategy()
{
_entryLevel = Param(nameof(EntryLevel), 14m)
.SetDisplay("Entry Level", "ADX level whose upward cross opens a long", "ADX");
_exitLevel = Param(nameof(ExitLevel), 45m)
.SetDisplay("Exit Level", "ADX level whose downward cross closes the long", "ADX");
_smaFilter = Param(nameof(SmaFilter), true)
.SetDisplay("SMA Filter", "Require the close above the SMA", "Filters");
_smaLength = Param(nameof(SmaLength), 200)
.SetGreaterThanZero()
.SetDisplay("SMA Length", "SMA period of the trend filter", "Filters");
_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();
_prevAdx = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevAdx = null;
var adx = new AverageDirectionalIndex { Length = _adxLength };
var sma = new SimpleMovingAverage { Length = SmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(adx, sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
DrawIndicator(oscillators, adx);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue adxValue, IIndicatorValue smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!adxValue.IsFormed || ((IAverageDirectionalIndexValue)adxValue).MovingAverage is not decimal adx)
return;
var prevAdx = _prevAdx;
_prevAdx = adx;
if (!smaValue.IsFormed || prevAdx is not decimal prev)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var trendOk = !SmaFilter || candle.ClosePrice > smaValue.ToDecimal();
if (Position == 0 && prev <= EntryLevel && adx > EntryLevel && trendOk)
BuyMarket(Volume);
else if (Position > 0 && prev >= ExitLevel && adx < ExitLevel)
SellMarket(Position);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import AverageDirectionalIndex, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
ADX_LENGTH = 14
class adx_for_btc_strategy(Strategy):
"""
ADX for BTC strategy.
Long only: buys when ADX(14) crosses above EntryLevel while, with SmaFilter enabled, the close is above SMA(SmaLength), and closes
the long when ADX crosses below ExitLevel.
"""
def __init__(self):
super(adx_for_btc_strategy, self).__init__()
self._entry_level = self.Param("EntryLevel", 14.0).SetDisplay("Entry Level", "ADX level whose upward cross opens a long", "ADX")
self._exit_level = self.Param("ExitLevel", 45.0).SetDisplay("Exit Level", "ADX level whose downward cross closes the long", "ADX")
self._sma_filter = self.Param("SmaFilter", True).SetDisplay("SMA Filter", "Require the close above the SMA", "Filters")
self._sma_length = self.Param("SmaLength", 200).SetGreaterThanZero().SetDisplay("SMA Length", "SMA period of the trend filter", "Filters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_adx = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(adx_for_btc_strategy, self).OnReseted()
self._prev_adx = None
def OnStarted2(self, time):
super(adx_for_btc_strategy, self).OnStarted2(time)
self._prev_adx = None
adx = AverageDirectionalIndex()
adx.Length = ADX_LENGTH
sma = SimpleMovingAverage()
sma.Length = self._sma_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(adx, sma, 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, adx)
def _process_candle(self, candle, adx_value, sma_value):
if candle.State != CandleStates.Finished:
return
if not adx_value.IsFormed or adx_value.MovingAverage is None:
return
adx = adx_value.MovingAverage
prev = self._prev_adx
self._prev_adx = adx
if not sma_value.IsFormed or prev is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
entry = Decimal(self._entry_level.Value)
exit_level = Decimal(self._exit_level.Value)
trend_ok = not self._sma_filter.Value or candle.ClosePrice > sma_value.GetValue[Decimal](None)
if self.Position == 0 and prev <= entry and adx > entry and trend_ok:
self.BuyMarket(self.Volume)
elif self.Position > 0 and prev >= exit_level and adx < exit_level:
self.SellMarket(self.Position)
def CreateClone(self):
return adx_for_btc_strategy()