Tendencia Hull MA
Estrategia basada en la tendencia de la Hull Moving Average.
Las pruebas indican un retorno anual promedio de aproximadamente 61%. Funciona mejor en el mercado de criptomonedas.
La estrategia de Tendencia Hull MA monitorea la pendiente de la Hull Moving Average. Las pendientes ascendentes provocan largos y las pendientes descendentes provocan cortos, con un stop trailing de ATR protegiendo cada operación.
Su cálculo receptivo reduce el rezago en comparación con las medias móviles tradicionales, permitiendo al sistema reaccionar rápidamente al nuevo momentum. El stop de ATR ayuda a evitar grandes drawdowns si la pendiente cambia abruptamente.
Detalles
- Criterios de entrada: Señales basadas en MA, ATR.
- Largo/Corto: Ambos directions.
- Criterios de salida: Señal opuesta o stop.
- Stops: Sí.
- Valores predeterminados:
HmaPeriod= 9AtrPeriod= 14AtrMultiplier= 2mCandleType= TimeSpan.FromMinutes(5)
- Filtros:
- Categoría: Tendencia
- Dirección: Ambos
- Indicadores: MA, ATR
- Stops: Sí
- Complejidad: Básico
- Marco temporal: Intradía (5m)
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
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 Hull Moving Average trend.
/// It enters long position when Hull MA is rising and short position when Hull MA is falling.
/// </summary>
public class HullMaTrendStrategy : Strategy
{
private readonly StrategyParam<int> _hmaPeriod;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrMultiplier;
private readonly StrategyParam<DataType> _candleType;
// Current state
private decimal _prevHmaValue;
/// <summary>
/// Period for Hull Moving Average.
/// </summary>
public int HmaPeriod
{
get => _hmaPeriod.Value;
set => _hmaPeriod.Value = value;
}
/// <summary>
/// Period for ATR calculation (stop-loss).
/// </summary>
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
/// <summary>
/// Multiplier for ATR to determine stop-loss distance.
/// </summary>
public decimal AtrMultiplier
{
get => _atrMultiplier.Value;
set => _atrMultiplier.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize the Hull MA Trend strategy.
/// </summary>
public HullMaTrendStrategy()
{
_hmaPeriod = Param(nameof(HmaPeriod), 500)
.SetDisplay("HMA Period", "Period for Hull Moving Average", "Indicators")
.SetOptimize(5, 15, 2);
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetDisplay("ATR Period", "Period for Average True Range (stop-loss)", "Risk parameters")
.SetOptimize(10, 20, 2);
_atrMultiplier = Param(nameof(AtrMultiplier), 2m)
.SetDisplay("ATR Multiplier", "Multiplier for ATR to determine stop-loss distance", "Risk parameters")
.SetOptimize(1, 3, 0.5m);
_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();
_prevHmaValue = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicators
var hma = new HullMovingAverage { Length = HmaPeriod };
var atr = new AverageTrueRange { Length = AtrPeriod };
// Create subscription and bind indicators
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(hma, atr, ProcessCandle)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, hma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal hmaValue, decimal atrValue)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Check if strategy is ready to trade
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Skip the first received value for proper trend determination
if (_prevHmaValue == 0)
{
_prevHmaValue = hmaValue;
return;
}
// Determine HMA direction with minimum slope threshold
var slopeThreshold = _prevHmaValue * 0.0002m; // 0.02% minimum change
var isHmaRising = hmaValue - _prevHmaValue > slopeThreshold;
var isHmaFalling = _prevHmaValue - hmaValue > slopeThreshold;
// Trading logic - only on significant direction changes
if (isHmaRising && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
}
else if (isHmaFalling && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
}
// Update previous HMA value
_prevHmaValue = hmaValue;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import HullMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class hull_ma_trend_strategy(Strategy):
def __init__(self):
super(hull_ma_trend_strategy, self).__init__()
self._hma_period = self.Param("HmaPeriod", 500) \
.SetDisplay("HMA Period", "Period for Hull Moving Average", "Indicators")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "Period for Average True Range (stop-loss)", "Risk parameters")
self._atr_multiplier = self.Param("AtrMultiplier", 2.0) \
.SetDisplay("ATR Multiplier", "Multiplier for ATR to determine stop-loss distance", "Risk parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_hma_value = 0.0
@property
def HmaPeriod(self):
return self._hma_period.Value
@HmaPeriod.setter
def HmaPeriod(self, value):
self._hma_period.Value = value
@property
def AtrPeriod(self):
return self._atr_period.Value
@AtrPeriod.setter
def AtrPeriod(self, value):
self._atr_period.Value = value
@property
def AtrMultiplier(self):
return self._atr_multiplier.Value
@AtrMultiplier.setter
def AtrMultiplier(self, value):
self._atr_multiplier.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(hull_ma_trend_strategy, self).OnStarted2(time)
self._prev_hma_value = 0.0
hma = HullMovingAverage()
hma.Length = self.HmaPeriod
atr = AverageTrueRange()
atr.Length = self.AtrPeriod
self.SubscribeCandles(self.CandleType) \
.Bind(hma, atr, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, hma_value, atr_value):
if candle.State != CandleStates.Finished:
return
hma_f = float(hma_value)
if self._prev_hma_value == 0:
self._prev_hma_value = hma_f
return
slope_threshold = self._prev_hma_value * 0.0002
is_hma_rising = hma_f - self._prev_hma_value > slope_threshold
is_hma_falling = self._prev_hma_value - hma_f > slope_threshold
if is_hma_rising and self.Position <= 0:
self.BuyMarket(self.Volume + Math.Abs(self.Position))
elif is_hma_falling and self.Position >= 0:
self.SellMarket(self.Volume + Math.Abs(self.Position))
self._prev_hma_value = hma_f
def OnReseted(self):
super(hull_ma_trend_strategy, self).OnReseted()
self._prev_hma_value = 0.0
def CreateClone(self):
return hull_ma_trend_strategy()