Estrategia ATR MACD
ATR MACD utiliza la volatilidad del Average True Range para ajustar el tamaño de la posición mientras opera los cruces del MACD. Lecturas más altas del ATR resultan en un tamaño de operación menor, manteniendo el riesgo consistente en diferentes regímenes de mercado.
Las pruebas indican un rendimiento anual promedio de aproximadamente 154%. Funciona mejor en el mercado de acciones.
Las entradas ocurren cuando el MACD cruza su línea de señal, con salidas activadas por el cruce opuesto o un stop basado en volatilidad.
Esta combinación busca capturar momentum mientras se tiene en cuenta la volatilidad cambiante.
Detalles
- Criterios de entrada: señal de indicador
- Largo/Corto: Ambos
- Criterios de salida: stop-loss o señal opuesta
- Stops: Sí, basado en porcentaje
- Valores predeterminados:
CandleType= 15 minuteStopLoss= 2%
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Ambos
- Indicadores: ATR, MACD
- Stops: Sí
- 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 that uses ATR for volatility detection and MACD for trend direction.
/// Enters when MACD confirms trend direction.
/// </summary>
public class AtrMacdStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private decimal _atrValue;
private int _cooldown;
/// <summary>
/// Candle type for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Strategy constructor.
/// </summary>
public AtrMacdStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 100)
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
.SetRange(5, 500);
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_atrValue = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var atr = new AverageTrueRange { Length = 14 };
var macd = new MovingAverageConvergenceDivergenceSignal();
var subscription = SubscribeCandles(CandleType);
// Bind ATR to capture value
subscription.BindEx(atr, OnAtr);
// Bind MACD for main logic
subscription
.BindEx(macd, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var atrArea = CreateChartArea();
if (atrArea != null)
DrawIndicator(atrArea, atr);
var macdArea = CreateChartArea();
if (macdArea != null)
DrawIndicator(macdArea, macd);
}
}
private void OnAtr(ICandleMessage candle, IIndicatorValue atrValue)
{
if (atrValue.IsFormed)
_atrValue = atrValue.ToDecimal();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (macdValue is not MovingAverageConvergenceDivergenceSignalValue macdTyped)
return;
if (macdTyped.Macd is not decimal macdLine || macdTyped.Signal is not decimal signalLine)
return;
if (_cooldown > 0)
{
_cooldown--;
return;
}
// Entry: MACD bullish crossover
if (macdLine > signalLine && Position == 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
// Entry: MACD bearish crossover
else if (macdLine < signalLine && Position == 0)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit on MACD crossover against position
if (Position > 0 && macdLine < signalLine)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && macdLine > signalLine)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
}
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 AverageTrueRange, MovingAverageConvergenceDivergenceSignal
from StockSharp.Algo.Strategies import Strategy
class atr_macd_strategy(Strategy):
"""
ATR + MACD strategy.
Uses ATR for volatility detection and MACD for trend direction.
Enters when MACD confirms trend direction.
"""
def __init__(self):
super(atr_macd_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 100).SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._atr_value = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(atr_macd_strategy, self).OnReseted()
self._atr_value = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(atr_macd_strategy, self).OnStarted2(time)
self._atr_value = 0.0
self._cooldown = 0
atr = AverageTrueRange()
atr.Length = 14
macd = MovingAverageConvergenceDivergenceSignal()
subscription = self.SubscribeCandles(self.candle_type)
# Bind ATR to capture value
subscription.BindEx(atr, self._on_atr)
# Bind MACD for main logic
subscription.BindEx(macd, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
atr_area = self.CreateChartArea()
if atr_area is not None:
self.DrawIndicator(atr_area, atr)
macd_area = self.CreateChartArea()
if macd_area is not None:
self.DrawIndicator(macd_area, macd)
def _on_atr(self, candle, atr_iv):
if atr_iv.IsFormed:
self._atr_value = float(atr_iv.Value)
def _process_candle(self, candle, macd_iv):
if candle.State != CandleStates.Finished:
return
if macd_iv.Macd is None or macd_iv.Signal is None:
return
macd_line = float(macd_iv.Macd)
signal_line = float(macd_iv.Signal)
cd = self._cooldown_bars.Value
if self._cooldown > 0:
self._cooldown -= 1
return
# Entry: MACD bullish crossover
if macd_line > signal_line and self.Position == 0:
self.BuyMarket()
self._cooldown = cd
# Entry: MACD bearish crossover
elif macd_line < signal_line and self.Position == 0:
self.SellMarket()
self._cooldown = cd
# Exit on MACD crossover against position
if self.Position > 0 and macd_line < signal_line:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and macd_line > signal_line:
self.BuyMarket()
self._cooldown = cd
def CreateClone(self):
return atr_macd_strategy()