Estrategia de Reversión Heikin-Ashi
Las velas Heikin-Ashi suavizan el ruido y destacan la dirección de la tendencia. Un cambio de una serie de velas HA bajistas a una alcista, o viceversa, puede indicar un cambio de momentum. Esta estrategia opera esos cambios de color y utiliza un stop porcentual para protección.
Las pruebas indican una rentabilidad anual media de aproximadamente el 145%. Funciona mejor en el mercado de criptomonedas.
La lógica calcula los valores Heikin-Ashi a partir de las velas regulares. Cuando el cierre HA cruza por encima de la apertura HA tras una secuencia bajista, se toma una posición larga. Un cruce por debajo tras una racha alcista abre una posición corta. El stop se coloca a un porcentaje fijo desde la entrada.
El método es simple pero efectivo durante oscilaciones irregulares cuando los gráficos de velas tradicionales son ruidosos.
Detalles
- Criterios de entrada: La vela Heikin-Ashi cambia de color.
- Largo/Corto: Ambos.
- Criterios de salida: Stop-loss.
- Stops: Sí, basado en porcentaje.
- Valores predeterminados:
CandleType= 15 minuteStopLoss= 2%
- Filtros:
- Categoría: Reversión
- Dirección: Ambos
- Indicadores: Heikin-Ashi
- Stops: Sí
- Complejidad: Básico
- Marco temporal: Intradía
- 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>
/// Heikin Ashi Reversal strategy.
/// Computes Heikin-Ashi candles from regular candles.
/// Enters long when HA switches from bearish to bullish.
/// Enters short when HA switches from bullish to bearish.
/// Uses SMA for exit confirmation.
/// </summary>
public class HeikinAshiReversalStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private decimal _haOpen;
private decimal _haClose;
private bool? _prevBullish;
private int _cooldown;
/// <summary>
/// MA Period.
/// </summary>
public int MAPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public HeikinAshiReversalStrategy()
{
_maPeriod = Param(nameof(MAPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Period for SMA", "Indicators");
_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();
_haOpen = default;
_haClose = default;
_prevBullish = null;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_haOpen = 0;
_haClose = 0;
_prevBullish = null;
_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;
// Compute Heikin-Ashi values
var newHaClose = (candle.OpenPrice + candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 4;
decimal newHaOpen;
if (_haOpen == 0)
{
// First candle
newHaOpen = (candle.OpenPrice + candle.ClosePrice) / 2;
}
else
{
newHaOpen = (_haOpen + _haClose) / 2;
}
_haOpen = newHaOpen;
_haClose = newHaClose;
var isBullish = newHaClose > newHaOpen;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevBullish = isBullish;
return;
}
if (_prevBullish == null)
{
_prevBullish = isBullish;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevBullish = isBullish;
return;
}
// Reversal detection
var bullishReversal = _prevBullish == false && isBullish;
var bearishReversal = _prevBullish == true && !isBullish;
if (Position == 0 && bullishReversal)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && bearishReversal)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && candle.ClosePrice < smaValue)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && candle.ClosePrice > smaValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevBullish = isBullish;
}
}
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 heikin_ashi_reversal_strategy(Strategy):
"""
Heikin Ashi Reversal strategy.
Computes Heikin-Ashi candles from regular candles.
Enters long when HA switches from bearish to bullish.
Enters short when HA switches from bullish to bearish.
Uses SMA for exit confirmation.
"""
def __init__(self):
super(heikin_ashi_reversal_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._ha_open = 0.0
self._ha_close = 0.0
self._prev_bullish = None
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(heikin_ashi_reversal_strategy, self).OnReseted()
self._ha_open = 0.0
self._ha_close = 0.0
self._prev_bullish = None
self._cooldown = 0
def OnStarted2(self, time):
super(heikin_ashi_reversal_strategy, self).OnStarted2(time)
self._ha_open = 0.0
self._ha_close = 0.0
self._prev_bullish = None
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
# Compute Heikin-Ashi values
new_ha_close = (float(candle.OpenPrice) + float(candle.HighPrice) + float(candle.LowPrice) + float(candle.ClosePrice)) / 4.0
if self._ha_open == 0:
# First candle
new_ha_open = (float(candle.OpenPrice) + float(candle.ClosePrice)) / 2.0
else:
new_ha_open = (self._ha_open + self._ha_close) / 2.0
self._ha_open = new_ha_open
self._ha_close = new_ha_close
is_bullish = new_ha_close > new_ha_open
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_bullish = is_bullish
return
if self._prev_bullish is None:
self._prev_bullish = is_bullish
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_bullish = is_bullish
return
# Reversal detection
bullish_reversal = self._prev_bullish == False and is_bullish
bearish_reversal = self._prev_bullish == True and not is_bullish
sv = float(sma_val)
close = float(candle.ClosePrice)
cd = self._cooldown_bars.Value
if self.Position == 0 and bullish_reversal:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and bearish_reversal:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and close < sv:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and close > sv:
self.BuyMarket()
self._cooldown = cd
self._prev_bullish = is_bullish
def CreateClone(self):
return heikin_ashi_reversal_strategy()