La Estrategia de Área MACD evalúa el equilibrio entre el impulso alcista y bajista usando la línea principal del MACD. Para cada vela, la estrategia acumula la suma de todos los valores positivos del MACD y la suma absoluta de todos los valores negativos del MACD durante una ventana de historial configurable. El lado dominante define la dirección de trading: un área positiva más fuerte favorece las posiciones largas, mientras que un área negativa más fuerte favorece la exposición corta. Un interruptor inverso permite operar contra la tendencia detectada cuando sea necesario.
La implementación utiliza la API de alto nivel de StockSharp con suscripciones de velas y vínculos de indicadores. Solo se procesan las velas completadas y toda la lógica de trading está encapsulada dentro del manejador ProcessCandle.
Indicadores y Datos
MACD (Media Móvil de Convergencia/Divergencia) con períodos rápido, lento y de señal configurables.
Velas de un marco temporal definido por el usuario (30 minutos por defecto).
Reglas de Trading
Entrada Larga – Cuando el área positiva acumulada del MACD es mayor que el área negativa absoluta acumulada. Si el modo inverso está habilitado, la condición se invierte.
Entrada Corta – Cuando el área negativa absoluta acumulada del MACD domina. El modo inverso intercambia el comportamiento.
Gestión de Posición – Cuando aparece una nueva señal de entrada, la estrategia cierra cualquier posición opuesta antes de abrir la nueva para que solo se mantenga una única posición direccional.
Gestión de Riesgo
Stop Loss – Distancia fija en pips medida desde el precio de entrada. Convertida automáticamente a unidades de precio usando el paso de precio del instrumento.
Take Profit – Objetivo de ganancia fijo en pips usando las mismas reglas de conversión.
Trailing Stop – Stop de seguimiento opcional que se activa una vez que la posición se mueve en ganancias por TrailingStopPips + TrailingStepPips. El stop luego sigue el precio con una brecha definida por TrailingStopPips y solo se mueve hacia adelante cuando el precio avanza al menos TrailingStepPips más. Ambos valores deben ser mayores que cero para habilitar la lógica de trailing.
Parámetros
Nombre
Descripción
Predeterminado
OrderVolume
Volumen de orden usado para entradas de mercado.
1
HistoryLength
Número de velas almacenadas para la comparación de área MACD.
60
MacdFastLength
Período de EMA rápida para el MACD.
12
MacdSlowLength
Período de EMA lenta para el MACD.
26
MacdSignalLength
Período de EMA de señal para el MACD.
9
ReverseSignals
Si está habilitado, intercambia las condiciones de entrada larga y corta.
false
StopLossPips
Distancia de stop loss expresada en pips.
100
TakeProfitPips
Distancia de take profit en pips.
150
TrailingStopPips
Distancia del trailing stop en pips. Establecer en cero para deshabilitar el trailing.
5
TrailingStepPips
Progreso adicional requerido antes de actualizar el trailing stop. Establecer en cero para deshabilitar el trailing.
5
CandleType
Marco temporal de velas usado por la suscripción.
Marco temporal de 30 minutos
Notas de Uso
Adjuntar la estrategia a un portafolio y un instrumento, luego ajustar los parámetros para el mercado objetivo.
Asegurarse de que tanto TrailingStopPips como TrailingStepPips sean mayores que cero para habilitar la protección de trailing. De lo contrario, el trailing se ignora y solo los niveles de stop loss/take profit están activos.
Monitorear los mensajes de registro para información sobre eventos de stop-loss, take-profit y trailing. Todos los registros se producen en inglés según lo requerido.
Idea Original
La conversión se basa en el asesor experto de MetaTrader 5 "Area MACD". La versión StockSharp mantiene el concepto central de comparar áreas MACD mientras integra la gestión de riesgo y el manejo de indicadores a través de la API de alto nivel del framework.
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>
/// Area MACD strategy (simplified). Tracks cumulative positive/negative
/// areas of fast-slow EMA difference to determine trend direction.
/// </summary>
public class AreaMacdStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<int> _historyLength;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
public int HistoryLength
{
get => _historyLength.Value;
set => _historyLength.Value = value;
}
public AreaMacdStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_fastLength = Param(nameof(FastLength), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Length", "Fast EMA period", "Indicators");
_slowLength = Param(nameof(SlowLength), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Length", "Slow EMA period", "Indicators");
_historyLength = Param(nameof(HistoryLength), 20)
.SetGreaterThanZero()
.SetDisplay("History Length", "Area accumulation window", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastEma = new ExponentialMovingAverage { Length = FastLength };
var slowEma = new ExponentialMovingAverage { Length = SlowLength };
var diffHistory = new Queue<decimal>();
decimal posArea = 0, negArea = 0;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, (ICandleMessage candle, decimal fastValue, decimal slowValue) =>
{
if (candle.State != CandleStates.Finished)
return;
var diff = fastValue - slowValue;
diffHistory.Enqueue(diff);
if (diff > 0) posArea += diff;
else negArea += Math.Abs(diff);
if (diffHistory.Count > HistoryLength)
{
var old = diffHistory.Dequeue();
if (old > 0) posArea -= old;
else negArea -= Math.Abs(old);
}
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (diffHistory.Count < HistoryLength)
return;
// Bullish area dominates
if (posArea > negArea * 1.25m && Position <= 0)
BuyMarket();
// Bearish area dominates
else if (negArea > posArea * 1.25m && Position >= 0)
SellMarket();
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
}
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from collections import deque
class area_macd_strategy(Strategy):
def __init__(self):
super(area_macd_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles", "General")
self._fast_length = self.Param("FastLength", 12) \
.SetDisplay("Fast Length", "Fast EMA period", "Indicators")
self._slow_length = self.Param("SlowLength", 26) \
.SetDisplay("Slow Length", "Slow EMA period", "Indicators")
self._history_length = self.Param("HistoryLength", 20) \
.SetDisplay("History Length", "Area accumulation window", "Indicators")
self._diff_history = deque()
self._pos_area = 0.0
self._neg_area = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastLength(self):
return self._fast_length.Value
@property
def SlowLength(self):
return self._slow_length.Value
@property
def HistoryLength(self):
return self._history_length.Value
def OnReseted(self):
super(area_macd_strategy, self).OnReseted()
self._diff_history = deque()
self._pos_area = 0.0
self._neg_area = 0.0
def OnStarted2(self, time):
super(area_macd_strategy, self).OnStarted2(time)
self._diff_history = deque()
self._pos_area = 0.0
self._neg_area = 0.0
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastLength
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ema, slow_ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
diff = fv - sv
self._diff_history.append(diff)
if diff > 0:
self._pos_area += diff
else:
self._neg_area += abs(diff)
if len(self._diff_history) > self.HistoryLength:
old = self._diff_history.popleft()
if old > 0:
self._pos_area -= old
else:
self._neg_area -= abs(old)
if len(self._diff_history) < self.HistoryLength:
return
if self._pos_area > self._neg_area * 1.25 and self.Position <= 0:
self.BuyMarket()
elif self._neg_area > self._pos_area * 1.25 and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return area_macd_strategy()