Estrategia de Ruptura de EMA Adaptativa
La estrategia Adaptive EMA Breakout está construida alrededor de la ruptura de la EMA Adaptativa con confirmación de tendencia.
Las pruebas indican un retorno anual promedio de aproximadamente el 166%. Funciona mejor en el mercado de acciones.
Las señales se disparan cuando sus indicadores confirman oportunidades de ruptura en datos intradía (5m). Esto hace que el método sea adecuado para traders activos.
Los stops se basan en múltiplos de ATR y factores como Fast, Slow. Ajuste estos valores predeterminados para equilibrar el riesgo y la recompensa.
Detalles
- Criterios de entrada: ver implementación para las condiciones del indicador.
- Largo/Corto: Ambos.
- Criterios de salida: señal opuesta o lógica de stop.
- Stops: Sí, usando cálculos basados en indicadores.
- Valores predeterminados:
Fast = 2Slow = 30Lookback = 10StopMultiplier = 2mCandleType = TimeSpan.FromMinutes(5).TimeFrame()
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Ambos
- Indicadores: múltiples indicadores
- Stops: Sí
- Complejidad: Intermedio
- 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>
/// Adaptive EMA (Kaufman) breakout with trend confirmation.
/// Buys when price closes above a rising adaptive EMA and sells when it closes below a falling one.
/// Positions are reversed on the opposite signal and protected by an ATR-multiple stop.
/// </summary>
public class AdaptiveEmaBreakoutStrategy : Strategy
{
private const int _atrPeriod = 14;
private readonly StrategyParam<int> _fast;
private readonly StrategyParam<int> _slow;
private readonly StrategyParam<int> _lookback;
private readonly StrategyParam<decimal> _stopMultiplier;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevAdaptiveEma;
private decimal _stopPrice;
/// <summary>
/// Fast smoothing period of the adaptive EMA.
/// </summary>
public int Fast
{
get => _fast.Value;
set => _fast.Value = value;
}
/// <summary>
/// Slow smoothing period of the adaptive EMA.
/// </summary>
public int Slow
{
get => _slow.Value;
set => _slow.Value = value;
}
/// <summary>
/// Efficiency ratio lookback of the adaptive EMA.
/// </summary>
public int Lookback
{
get => _lookback.Value;
set => _lookback.Value = value;
}
/// <summary>
/// Stop-loss distance in ATR multiples.
/// </summary>
public decimal StopMultiplier
{
get => _stopMultiplier.Value;
set => _stopMultiplier.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize <see cref="AdaptiveEmaBreakoutStrategy"/>.
/// </summary>
public AdaptiveEmaBreakoutStrategy()
{
_fast = Param(nameof(Fast), 2)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast smoothing period of the adaptive EMA", "Indicators");
_slow = Param(nameof(Slow), 30)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow smoothing period of the adaptive EMA", "Indicators");
_lookback = Param(nameof(Lookback), 10)
.SetGreaterThanZero()
.SetDisplay("Lookback", "Efficiency ratio lookback of the adaptive EMA", "Indicators");
_stopMultiplier = Param(nameof(StopMultiplier), 2m)
.SetNotNegative()
.SetDisplay("Stop Multiplier", "Stop-loss distance in ATR multiples", "Risk Management");
_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();
_prevAdaptiveEma = null;
_stopPrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var adaptiveEma = new KaufmanAdaptiveMovingAverage
{
Length = Lookback,
FastSCPeriod = Fast,
SlowSCPeriod = Slow,
};
var atr = new AverageTrueRange { Length = _atrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(adaptiveEma, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, adaptiveEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal adaptiveEmaValue, decimal atrValue)
{
if (candle.State != CandleStates.Finished)
return;
var prevAdaptiveEma = _prevAdaptiveEma;
_prevAdaptiveEma = adaptiveEmaValue;
if (prevAdaptiveEma is not decimal prev)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (CheckStop(candle))
return;
var close = candle.ClosePrice;
var stopDistance = StopMultiplier * atrValue;
if (close > adaptiveEmaValue && adaptiveEmaValue > prev && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
_stopPrice = stopDistance > 0 ? close - stopDistance : 0m;
}
else if (close < adaptiveEmaValue && adaptiveEmaValue < prev && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
_stopPrice = stopDistance > 0 ? close + stopDistance : 0m;
}
}
private bool CheckStop(ICandleMessage candle)
{
if (_stopPrice == 0m)
return false;
if ((Position > 0 && candle.LowPrice <= _stopPrice) || (Position < 0 && candle.HighPrice >= _stopPrice))
{
if (Position > 0)
SellMarket(Position);
else
BuyMarket(-Position);
_stopPrice = 0m;
return true;
}
return false;
}
}
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 KaufmanAdaptiveMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
ATR_PERIOD = 14
class adaptive_ema_breakout_strategy(Strategy):
"""
Adaptive EMA (Kaufman) breakout with trend confirmation.
Buys when price closes above a rising adaptive EMA and sells when it closes below a falling one.
Positions are reversed on the opposite signal and protected by an ATR-multiple stop.
"""
def __init__(self):
super(adaptive_ema_breakout_strategy, self).__init__()
self._fast = self.Param("Fast", 2) \
.SetGreaterThanZero() \
.SetDisplay("Fast Period", "Fast smoothing period of the adaptive EMA", "Indicators")
self._slow = self.Param("Slow", 30) \
.SetGreaterThanZero() \
.SetDisplay("Slow Period", "Slow smoothing period of the adaptive EMA", "Indicators")
self._lookback = self.Param("Lookback", 10) \
.SetGreaterThanZero() \
.SetDisplay("Lookback", "Efficiency ratio lookback of the adaptive EMA", "Indicators")
self._stop_multiplier = self.Param("StopMultiplier", 2.0) \
.SetNotNegative() \
.SetDisplay("Stop Multiplier", "Stop-loss distance in ATR multiples", "Risk Management")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_adaptive_ema = None
self._stop_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
def GetWorkingSecurities(self):
return [(self.Security, self.CandleType)]
def OnReseted(self):
super(adaptive_ema_breakout_strategy, self).OnReseted()
self._prev_adaptive_ema = None
self._stop_price = 0.0
def OnStarted2(self, time):
super(adaptive_ema_breakout_strategy, self).OnStarted2(time)
adaptive_ema = KaufmanAdaptiveMovingAverage()
adaptive_ema.Length = self._lookback.Value
adaptive_ema.FastSCPeriod = self._fast.Value
adaptive_ema.SlowSCPeriod = self._slow.Value
atr = AverageTrueRange()
atr.Length = ATR_PERIOD
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(adaptive_ema, atr, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, adaptive_ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle, adaptive_ema_value, atr_value):
if candle.State != CandleStates.Finished:
return
adaptive_ema_value = float(adaptive_ema_value)
atr_value = float(atr_value)
prev = self._prev_adaptive_ema
self._prev_adaptive_ema = adaptive_ema_value
if prev is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self._check_stop(candle):
return
close = float(candle.ClosePrice)
stop_distance = float(self._stop_multiplier.Value) * atr_value
if close > adaptive_ema_value and adaptive_ema_value > prev and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._stop_price = close - stop_distance if stop_distance > 0 else 0.0
elif close < adaptive_ema_value and adaptive_ema_value < prev and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._stop_price = close + stop_distance if stop_distance > 0 else 0.0
def _check_stop(self, candle):
if self._stop_price == 0.0:
return False
if (self.Position > 0 and float(candle.LowPrice) <= self._stop_price) or \
(self.Position < 0 and float(candle.HighPrice) >= self._stop_price):
if self.Position > 0:
self.SellMarket(self.Position)
else:
self.BuyMarket(-self.Position)
self._stop_price = 0.0
return True
return False
def CreateClone(self):
return adaptive_ema_breakout_strategy()