ADX para BTC
La estrategia utiliza el Average Directional Index (ADX) con un filtro de tendencia SMA opcional para capturar movimientos fuertes en Bitcoin.
Las pruebas indican un rendimiento anual promedio de aproximadamente el 80%. Funciona mejor en el mercado cripto.
El sistema compra cuando el ADX cruza por encima del nivel de entrada y el filtro de tendencia es alcista. La posición se cierra cuando el ADX cae por debajo del nivel de salida.
Detalles
- Criterios de entrada: ADX cruza por encima de
EntryLevely (si está activado) SMA rápida > SMA lenta. - Largo/Corto: Solo largos.
- Criterios de salida: ADX cruza por debajo de
ExitLevel. - Stops: No.
- Valores predeterminados:
EntryLevel= 14mExitLevel= 45mSmaFilter= trueSmaLength= 200CandleType= TimeSpan.FromMinutes(5)
- Filtros:
- Categoría: Tendencia
- Dirección: Solo largos
- Indicadores: ADX, SMA
- Stops: No
- Complejidad: Básico
- Marco temporal: Intradía (5m)
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
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()