Estrategia del Sistema de Impulso Elder
Esta estrategia replica el Sistema de Impulso Elder que combina la dirección de una Media Móvil Exponencial (EMA) con el momentum del histograma MACD. Abre operaciones cuando el impulso alcista o bajista se desvanece en velas de marcos temporales superiores.
El enfoque observa impulsos codificados por colores derivados de la pendiente de la EMA y la dinámica del histograma MACD:
- Verde (2) — EMA subiendo y el histograma MACD subiendo y positivo.
- Rojo (1) — EMA bajando y el histograma MACD bajando y negativo.
- Azul (0) — cualquier otro estado.
Se abre una posición larga cuando un impulso alcista previo (verde) se debilita, mientras que las posiciones cortas aparecen después de que un impulso bajista (rojo) se debilita. Las posiciones opuestas se cierran cuando se detecta el impulso correspondiente.
Detalles
- Criterios de entrada: Cambio de color de Elder Impulse en velas finalizadas.
- Largo/Corto: Ambas direcciones.
- Criterios de salida: Impulso opuesto o protección de posición.
- Stops: Usa
StartProtectioncon stop y take profit del 2% por defecto. - Valores predeterminados:
EmaPeriod= 13MacdFastPeriod= 12MacdSlowPeriod= 26MacdSignalPeriod= 9CandleType= TimeSpan.FromHours(4)
- Filtros:
- Categoría: Momentum
- Dirección: Ambos
- Indicadores: EMA, MACD
- Stops: Sí
- Complejidad: Intermedio
- Marco temporal: 4H
- 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 implementing Elder Impulse System logic.
/// </summary>
public class ElderImpulseSystemStrategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _macdFastPeriod;
private readonly StrategyParam<int> _macdSlowPeriod;
private readonly StrategyParam<int> _macdSignalPeriod;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private decimal? _previousEma;
private decimal? _previousMacdHist;
private int? _previousColor;
private int _barsSinceTrade;
/// <summary>
/// EMA period.
/// </summary>
public int EmaPeriod
{
get => _emaPeriod.Value;
set => _emaPeriod.Value = value;
}
/// <summary>
/// MACD fast period.
/// </summary>
public int MacdFastPeriod
{
get => _macdFastPeriod.Value;
set => _macdFastPeriod.Value = value;
}
/// <summary>
/// MACD slow period.
/// </summary>
public int MacdSlowPeriod
{
get => _macdSlowPeriod.Value;
set => _macdSlowPeriod.Value = value;
}
/// <summary>
/// MACD signal period.
/// </summary>
public int MacdSignalPeriod
{
get => _macdSignalPeriod.Value;
set => _macdSignalPeriod.Value = value;
}
/// <summary>
/// Bars to wait after a completed trade.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Candle type used by the strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="ElderImpulseSystemStrategy"/>.
/// </summary>
public ElderImpulseSystemStrategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 13)
.SetDisplay("EMA Period", "Period for EMA calculation", "Indicators")
.SetOptimize(8, 21, 1);
_macdFastPeriod = Param(nameof(MacdFastPeriod), 12)
.SetDisplay("MACD Fast Period", "Fast EMA period for MACD", "Indicators")
.SetOptimize(8, 20, 1);
_macdSlowPeriod = Param(nameof(MacdSlowPeriod), 26)
.SetDisplay("MACD Slow Period", "Slow EMA period for MACD", "Indicators")
.SetOptimize(20, 40, 1);
_macdSignalPeriod = Param(nameof(MacdSignalPeriod), 9)
.SetDisplay("MACD Signal Period", "Signal EMA period for MACD", "Indicators")
.SetOptimize(5, 15, 1);
_cooldownBars = Param(nameof(CooldownBars), 1)
.SetDisplay("Cooldown Bars", "Bars to wait after a completed trade", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).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();
_previousEma = null;
_previousMacdHist = null;
_previousColor = null;
_barsSinceTrade = CooldownBars;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = MacdFastPeriod },
LongMa = { Length = MacdSlowPeriod }
},
SignalMa = { Length = MacdSignalPeriod }
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(ema, macd, ProcessCandle)
.Start();
StartProtection(new Unit(2, UnitTypes.Percent), new Unit(2, UnitTypes.Percent));
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawIndicator(area, macd);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue emaValue, IIndicatorValue macdValue)
{
// Process only finished candles
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_barsSinceTrade < CooldownBars)
_barsSinceTrade++;
var ema = emaValue.ToDecimal();
var macdTyped = (MovingAverageConvergenceDivergenceSignalValue)macdValue;
if (macdTyped.Macd is not decimal macd || macdTyped.Signal is not decimal signal)
return;
var macdHist = macd - signal;
if (_previousEma is null || _previousMacdHist is null)
{
_previousEma = ema;
_previousMacdHist = macdHist;
return;
}
var emaDelta = ema - _previousEma.Value;
var macdDelta = macdHist - _previousMacdHist.Value;
var color = 0;
if (emaDelta > 0 && macdHist > 0 && macdDelta > 0)
color = 2;
else if (emaDelta < 0 && macdHist < 0 && macdDelta < 0)
color = 1;
if (_previousColor.HasValue && _barsSinceTrade >= CooldownBars)
{
if (_previousColor.Value == 2 && color != 2)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
if (Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
_barsSinceTrade = 0;
}
}
else if (_previousColor.Value == 1 && color != 1)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
if (Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
_barsSinceTrade = 0;
}
}
}
_previousColor = color;
_previousEma = ema;
_previousMacdHist = macdHist;
}
}
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, Unit, UnitTypes, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, MovingAverageConvergenceDivergenceSignal
from StockSharp.Algo.Strategies import Strategy
class elder_impulse_system_strategy(Strategy):
def __init__(self):
super(elder_impulse_system_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 13) \
.SetDisplay("EMA Period", "Period for EMA calculation", "Indicators")
self._macd_fast_period = self.Param("MacdFastPeriod", 12) \
.SetDisplay("MACD Fast Period", "Fast EMA period for MACD", "Indicators")
self._macd_slow_period = self.Param("MacdSlowPeriod", 26) \
.SetDisplay("MACD Slow Period", "Slow EMA period for MACD", "Indicators")
self._macd_signal_period = self.Param("MacdSignalPeriod", 9) \
.SetDisplay("MACD Signal Period", "Signal EMA period for MACD", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 1) \
.SetDisplay("Cooldown Bars", "Bars to wait after a completed trade", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._previous_ema = None
self._previous_macd_hist = None
self._previous_color = None
self._bars_since_trade = 0
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
@property
def MacdFastPeriod(self):
return self._macd_fast_period.Value
@MacdFastPeriod.setter
def MacdFastPeriod(self, value):
self._macd_fast_period.Value = value
@property
def MacdSlowPeriod(self):
return self._macd_slow_period.Value
@MacdSlowPeriod.setter
def MacdSlowPeriod(self, value):
self._macd_slow_period.Value = value
@property
def MacdSignalPeriod(self):
return self._macd_signal_period.Value
@MacdSignalPeriod.setter
def MacdSignalPeriod(self, value):
self._macd_signal_period.Value = value
@property
def CooldownBars(self):
return self._cooldown_bars.Value
@CooldownBars.setter
def CooldownBars(self, value):
self._cooldown_bars.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(elder_impulse_system_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self.MacdFastPeriod
macd.Macd.LongMa.Length = self.MacdSlowPeriod
macd.SignalMa.Length = self.MacdSignalPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.BindEx(ema, macd, self.ProcessCandle) \
.Start()
self.StartProtection(
Unit(2, UnitTypes.Percent),
Unit(2, UnitTypes.Percent))
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawIndicator(area, macd)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, ema_value, macd_value):
if candle.State != CandleStates.Finished:
return
if self._bars_since_trade < self.CooldownBars:
self._bars_since_trade += 1
ema = float(ema_value)
macd_raw = macd_value.Macd
signal_raw = macd_value.Signal
if macd_raw is None or signal_raw is None:
return
macd_val = float(macd_raw)
signal_val = float(signal_raw)
macd_hist = macd_val - signal_val
if self._previous_ema is None or self._previous_macd_hist is None:
self._previous_ema = ema
self._previous_macd_hist = macd_hist
return
ema_delta = ema - self._previous_ema
macd_delta = macd_hist - self._previous_macd_hist
color = 0
if ema_delta > 0 and macd_hist > 0 and macd_delta > 0:
color = 2
elif ema_delta < 0 and macd_hist < 0 and macd_delta < 0:
color = 1
if self._previous_color is not None and self._bars_since_trade >= self.CooldownBars:
if self._previous_color == 2 and color != 2:
pos = self.Position
if pos < 0:
self.BuyMarket(abs(pos))
if self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._bars_since_trade = 0
elif self._previous_color == 1 and color != 1:
pos = self.Position
if pos > 0:
self.SellMarket(abs(pos))
if self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._bars_since_trade = 0
self._previous_color = color
self._previous_ema = ema
self._previous_macd_hist = macd_hist
def OnReseted(self):
super(elder_impulse_system_strategy, self).OnReseted()
self._previous_ema = None
self._previous_macd_hist = None
self._previous_color = None
self._bars_since_trade = self.CooldownBars
def CreateClone(self):
return elder_impulse_system_strategy()