Estrategias Paralelas
Sistema de ruptura Heikin Ashi con MACD que opera en ambas direcciones. Entra cuando una nueva tendencia Heikin Ashi se alinea con una ruptura por encima o por debajo del Canal Donchian y el MACD confirma el impulso.
Combinar la identificación de tendencia de Heikin Ashi con la detección de rupturas mantiene las operaciones alineadas con movimientos frescos. El MACD actúa como filtro de impulso para evitar señales falsas.
Ideal para traders que buscan entradas tempranas de ruptura tras una reversión de tendencia. Funciona en marcos temporales intradía.
Detalles
- Criterios de entrada:
- Largo:
Trend turns bullish && Close > DonchianHigh && MACD > Signal - Corto:
Trend turns bearish && Close < DonchianLow && MACD < Signal
- Largo:
- Largo/Corto: Ambos
- Criterios de salida:
- Señal de ruptura opuesta
- Stops: No definidos
- Valores predeterminados:
DonchianPeriod= 5MacdFast= 12MacdSlow= 26MacdSignal= 9CandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filtros:
- Categoría: Ruptura
- Dirección: Ambos
- Indicadores: Heikin Ashi, Donchian Channel, MACD
- Stops: No
- Complejidad: Intermedio
- 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>
/// Strategy combining Heikin Ashi trend reversals with Donchian Channel breakouts and MACD confirmation.
/// </summary>
public class ParallelStrategiesStrategy : Strategy
{
private readonly StrategyParam<int> _donchianPeriod;
private readonly StrategyParam<int> _macdFast;
private readonly StrategyParam<int> _macdSlow;
private readonly StrategyParam<int> _macdSignal;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevUpper;
private decimal? _prevLower;
private int? _prevTrend;
// Heikin Ashi state
private decimal _haOpen;
private decimal _haClose;
private bool _haInitialized;
public int DonchianPeriod { get => _donchianPeriod.Value; set => _donchianPeriod.Value = value; }
public int MacdFast { get => _macdFast.Value; set => _macdFast.Value = value; }
public int MacdSlow { get => _macdSlow.Value; set => _macdSlow.Value = value; }
public int MacdSignal { get => _macdSignal.Value; set => _macdSignal.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ParallelStrategiesStrategy()
{
_donchianPeriod = Param(nameof(DonchianPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Donchian Period", "Lookback for breakout calculation", "Indicators");
_macdFast = Param(nameof(MacdFast), 12)
.SetGreaterThanZero()
.SetDisplay("MACD Fast", "Fast EMA period", "Indicators");
_macdSlow = Param(nameof(MacdSlow), 26)
.SetGreaterThanZero()
.SetDisplay("MACD Slow", "Slow EMA period", "Indicators");
_macdSignal = Param(nameof(MacdSignal), 9)
.SetGreaterThanZero()
.SetDisplay("MACD Signal", "Signal line period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Time frame for candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevUpper = null;
_prevLower = null;
_prevTrend = null;
_haOpen = 0;
_haClose = 0;
_haInitialized = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var donchian = new DonchianChannels { Length = DonchianPeriod };
var macd = new MovingAverageConvergenceDivergenceSignal(
new MovingAverageConvergenceDivergence(
new ExponentialMovingAverage { Length = MacdSlow },
new ExponentialMovingAverage { Length = MacdFast }),
new ExponentialMovingAverage { Length = MacdSignal });
SubscribeCandles(CandleType)
.BindEx(donchian, macd, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue donchianValue, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished)
return;
var dc = (IDonchianChannelsValue)donchianValue;
var macdV = (IMovingAverageConvergenceDivergenceSignalValue)macdValue;
if (dc.UpperBand is not decimal upper || dc.LowerBand is not decimal lower)
return;
if (macdV.Macd is not decimal macdLine || macdV.Signal is not decimal signalLine)
return;
// Compute Heikin Ashi manually
var haCloseNew = (candle.OpenPrice + candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 4m;
decimal haOpenNew;
if (!_haInitialized)
{
haOpenNew = (candle.OpenPrice + candle.ClosePrice) / 2m;
_haInitialized = true;
}
else
{
haOpenNew = (_haOpen + _haClose) / 2m;
}
_haOpen = haOpenNew;
_haClose = haCloseNew;
var trend = haOpenNew < haCloseNew ? 1 : -1;
if (_prevTrend is int prevTrend)
{
if (trend > 0 && prevTrend < 0 && macdLine > signalLine && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (trend < 0 && prevTrend > 0 && macdLine < signalLine && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
}
_prevUpper = upper;
_prevLower = lower;
_prevTrend = trend;
}
}
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 (
DonchianChannels, ExponentialMovingAverage,
MovingAverageConvergenceDivergence, MovingAverageConvergenceDivergenceSignal
)
from StockSharp.Algo.Strategies import Strategy
class parallel_strategies_strategy(Strategy):
def __init__(self):
super(parallel_strategies_strategy, self).__init__()
self._donchian_period = self.Param("DonchianPeriod", 5) \
.SetDisplay("Donchian Period", "Lookback for breakout calculation", "Indicators")
self._macd_fast = self.Param("MacdFast", 12) \
.SetDisplay("MACD Fast", "Fast EMA period", "Indicators")
self._macd_slow = self.Param("MacdSlow", 26) \
.SetDisplay("MACD Slow", "Slow EMA period", "Indicators")
self._macd_signal = self.Param("MacdSignal", 9) \
.SetDisplay("MACD Signal", "Signal line period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Time frame for candles", "General")
self._prev_upper = None
self._prev_lower = None
self._prev_trend = None
self._ha_open = 0.0
self._ha_close = 0.0
self._ha_initialized = False
@property
def DonchianPeriod(self):
return self._donchian_period.Value
@DonchianPeriod.setter
def DonchianPeriod(self, value):
self._donchian_period.Value = value
@property
def MacdFast(self):
return self._macd_fast.Value
@MacdFast.setter
def MacdFast(self, value):
self._macd_fast.Value = value
@property
def MacdSlow(self):
return self._macd_slow.Value
@MacdSlow.setter
def MacdSlow(self, value):
self._macd_slow.Value = value
@property
def MacdSignal(self):
return self._macd_signal.Value
@MacdSignal.setter
def MacdSignal(self, value):
self._macd_signal.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(parallel_strategies_strategy, self).OnStarted2(time)
donchian = DonchianChannels()
donchian.Length = self.DonchianPeriod
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.MacdSlow
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.MacdFast
macd_core = MovingAverageConvergenceDivergence(slow_ema, fast_ema)
sig_ema = ExponentialMovingAverage()
sig_ema.Length = self.MacdSignal
macd = MovingAverageConvergenceDivergenceSignal(macd_core, sig_ema)
self.SubscribeCandles(self.CandleType) \
.BindEx(donchian, macd, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, donchian_value, macd_value):
if candle.State != CandleStates.Finished:
return
upper_raw = donchian_value.UpperBand
lower_raw = donchian_value.LowerBand
if upper_raw is None or lower_raw is None:
return
macd_raw = macd_value.Macd
signal_raw = macd_value.Signal
if macd_raw is None or signal_raw is None:
return
upper = float(upper_raw)
lower = float(lower_raw)
macd_line = float(macd_raw)
signal_line = float(signal_raw)
ha_close_new = (float(candle.OpenPrice) + float(candle.HighPrice)
+ float(candle.LowPrice) + float(candle.ClosePrice)) / 4.0
if not self._ha_initialized:
ha_open_new = (float(candle.OpenPrice) + float(candle.ClosePrice)) / 2.0
self._ha_initialized = True
else:
ha_open_new = (self._ha_open + self._ha_close) / 2.0
self._ha_open = ha_open_new
self._ha_close = ha_close_new
trend = 1 if ha_open_new < ha_close_new else -1
if self._prev_trend is not None:
if trend > 0 and self._prev_trend < 0 and macd_line > signal_line and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif trend < 0 and self._prev_trend > 0 and macd_line < signal_line and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_upper = upper
self._prev_lower = lower
self._prev_trend = trend
def OnReseted(self):
super(parallel_strategies_strategy, self).OnReseted()
self._prev_upper = None
self._prev_lower = None
self._prev_trend = None
self._ha_open = 0.0
self._ha_close = 0.0
self._ha_initialized = False
def CreateClone(self):
return parallel_strategies_strategy()