Estrategia Dual Supertrend MACD
La estrategia Dual Supertrend MACD combina dos indicadores Supertrend con un filtro MACD. Se abre una posición larga cuando el precio opera por encima de ambas líneas Supertrend y el histograma MACD es positivo. Las posiciones cortas aparecen cuando el precio está por debajo de ambas líneas y el histograma es negativo. Las posiciones se cierran una vez que cualquier Supertrend cambia de dirección o el histograma MACD cruza cero.
Detalles
- Datos: Velas de precio.
- Criterios de entrada:
- Largo:
Close > Supertrend1 && Close > Supertrend2 && MACD Histogram > 0 - Corto:
Close < Supertrend1 && Close < Supertrend2 && MACD Histogram < 0
- Largo:
- Criterios de salida:
- Largo:
Close < Supertrend1 || Close < Supertrend2 || MACD Histogram < 0 - Corto:
Close > Supertrend1 || Close > Supertrend2 || MACD Histogram > 0
- Largo:
- Stops: Ninguno por defecto.
- Valores predeterminados:
MacdFast= 12MacdSlow= 26MacdSignal= 9OscillatorMaType= ExponentialSignalMaType= ExponentialAtrPeriod1= 10Factor1= 3.0AtrPeriod2= 20Factor2= 5.0TradeDirection= "Both"
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Configurable
- Indicadores: Supertrend, MACD
- Complejidad: Intermedio
- 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>
/// Dual Supertrend MACD strategy.
/// The MACD line is the fast minus the slow moving average of the close (OscillatorMaType) and the histogram is the MACD line minus
/// its signal average (SignalMaType). Long: close above both Supertrend lines and a positive histogram. Short: close below both lines
/// and a negative histogram. A long closes when the close falls below either line or the histogram turns negative, a short when the
/// close rises above either line or the histogram turns positive. TradeDirection limits the sides that may be opened.
/// </summary>
public class DualSupertrendMacdStrategy : Strategy
{
/// <summary>
/// Moving average types of the MACD.
/// </summary>
public enum MaTypes
{
/// <summary>
/// Simple moving average.
/// </summary>
Simple,
/// <summary>
/// Exponential moving average.
/// </summary>
Exponential,
}
private readonly StrategyParam<int> _macdFast;
private readonly StrategyParam<int> _macdSlow;
private readonly StrategyParam<int> _macdSignal;
private readonly StrategyParam<MaTypes> _oscillatorMaType;
private readonly StrategyParam<MaTypes> _signalMaType;
private readonly StrategyParam<int> _atrPeriod1;
private readonly StrategyParam<decimal> _factor1;
private readonly StrategyParam<int> _atrPeriod2;
private readonly StrategyParam<decimal> _factor2;
private readonly StrategyParam<string> _tradeDirection;
private readonly StrategyParam<DataType> _candleType;
private IIndicator _signalMa;
/// <summary>
/// Fast MACD period.
/// </summary>
public int MacdFast
{
get => _macdFast.Value;
set => _macdFast.Value = value;
}
/// <summary>
/// Slow MACD period.
/// </summary>
public int MacdSlow
{
get => _macdSlow.Value;
set => _macdSlow.Value = value;
}
/// <summary>
/// Signal MACD period.
/// </summary>
public int MacdSignal
{
get => _macdSignal.Value;
set => _macdSignal.Value = value;
}
/// <summary>
/// Moving average type of the MACD line.
/// </summary>
public MaTypes OscillatorMaType
{
get => _oscillatorMaType.Value;
set => _oscillatorMaType.Value = value;
}
/// <summary>
/// Moving average type of the signal line.
/// </summary>
public MaTypes SignalMaType
{
get => _signalMaType.Value;
set => _signalMaType.Value = value;
}
/// <summary>
/// ATR period of the first Supertrend.
/// </summary>
public int AtrPeriod1
{
get => _atrPeriod1.Value;
set => _atrPeriod1.Value = value;
}
/// <summary>
/// Factor of the first Supertrend.
/// </summary>
public decimal Factor1
{
get => _factor1.Value;
set => _factor1.Value = value;
}
/// <summary>
/// ATR period of the second Supertrend.
/// </summary>
public int AtrPeriod2
{
get => _atrPeriod2.Value;
set => _atrPeriod2.Value = value;
}
/// <summary>
/// Factor of the second Supertrend.
/// </summary>
public decimal Factor2
{
get => _factor2.Value;
set => _factor2.Value = value;
}
/// <summary>
/// Sides that may be opened: Long, Short or Both.
/// </summary>
public string TradeDirection
{
get => _tradeDirection.Value;
set => _tradeDirection.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public DualSupertrendMacdStrategy()
{
_macdFast = Param(nameof(MacdFast), 12)
.SetGreaterThanZero()
.SetDisplay("MACD Fast", "Fast MACD period", "MACD");
_macdSlow = Param(nameof(MacdSlow), 26)
.SetGreaterThanZero()
.SetDisplay("MACD Slow", "Slow MACD period", "MACD");
_macdSignal = Param(nameof(MacdSignal), 9)
.SetGreaterThanZero()
.SetDisplay("MACD Signal", "Signal MACD period", "MACD");
_oscillatorMaType = Param(nameof(OscillatorMaType), MaTypes.Exponential)
.SetDisplay("Oscillator MA Type", "Moving average type of the MACD line", "MACD");
_signalMaType = Param(nameof(SignalMaType), MaTypes.Exponential)
.SetDisplay("Signal MA Type", "Moving average type of the signal line", "MACD");
_atrPeriod1 = Param(nameof(AtrPeriod1), 10)
.SetGreaterThanZero()
.SetDisplay("ATR Period 1", "ATR period of the first Supertrend", "Supertrend");
_factor1 = Param(nameof(Factor1), 3.0m)
.SetGreaterThanZero()
.SetDisplay("Factor 1", "Factor of the first Supertrend", "Supertrend");
_atrPeriod2 = Param(nameof(AtrPeriod2), 20)
.SetGreaterThanZero()
.SetDisplay("ATR Period 2", "ATR period of the second Supertrend", "Supertrend");
_factor2 = Param(nameof(Factor2), 5.0m)
.SetGreaterThanZero()
.SetDisplay("Factor 2", "Factor of the second Supertrend", "Supertrend");
_tradeDirection = Param(nameof(TradeDirection), "Both")
.SetDisplay("Trade Direction", "Sides that may be opened: Long, Short or Both", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
private static IIndicator CreateMa(MaTypes type, int length)
{
return type == MaTypes.Simple
? new SimpleMovingAverage { Length = length }
: new ExponentialMovingAverage { Length = length };
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastMa = CreateMa(OscillatorMaType, MacdFast);
var slowMa = CreateMa(OscillatorMaType, MacdSlow);
_signalMa = CreateMa(SignalMaType, MacdSignal);
var superTrend1 = new SuperTrend { Length = AtrPeriod1, Multiplier = Factor1 };
var superTrend2 = new SuperTrend { Length = AtrPeriod2, Multiplier = Factor2 };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(fastMa, slowMa, superTrend1, superTrend2, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, superTrend1);
DrawIndicator(area, superTrend2);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue fastValue, IIndicatorValue slowValue, IIndicatorValue st1Value, IIndicatorValue st2Value)
{
if (candle.State != CandleStates.Finished)
return;
if (!fastValue.IsFormed || !slowValue.IsFormed)
return;
var macd = fastValue.GetValue<decimal>() - slowValue.GetValue<decimal>();
var signalValue = _signalMa.Process(new DecimalIndicatorValue(_signalMa, macd, candle.OpenTime) { IsFinal = true });
if (!signalValue.IsFormed || !st1Value.IsFormed || !st2Value.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var histogram = macd - signalValue.GetValue<decimal>();
var st1 = st1Value.GetValue<decimal>();
var st2 = st2Value.GetValue<decimal>();
var close = candle.ClosePrice;
var direction = TradeDirection;
var allowLong = direction.EqualsIgnoreCase("Both") || direction.EqualsIgnoreCase("Long");
var allowShort = direction.EqualsIgnoreCase("Both") || direction.EqualsIgnoreCase("Short");
var longEntry = close > st1 && close > st2 && histogram > 0;
var shortEntry = close < st1 && close < st2 && histogram < 0;
var longExit = close < st1 || close < st2 || histogram < 0;
var shortExit = close > st1 || close > st2 || histogram > 0;
if (Position > 0)
{
if (!longExit)
return;
if (shortEntry && allowShort)
SellMarket(Volume + Position);
else
SellMarket(Position);
}
else if (Position < 0)
{
if (!shortExit)
return;
if (longEntry && allowLong)
BuyMarket(Volume - Position);
else
BuyMarket(-Position);
}
else if (longEntry && allowLong)
BuyMarket(Volume);
else if (shortEntry && allowShort)
SellMarket(Volume);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage, ExponentialMovingAverage, SuperTrend, DecimalIndicatorValue
from StockSharp.Algo.Strategies import Strategy
class MaTypes:
"""Moving average types of the MACD."""
Simple = 0
Exponential = 1
class dual_supertrend_macd_strategy(Strategy):
"""
Dual Supertrend MACD strategy.
The MACD line is the fast minus the slow moving average of the close (OscillatorMaType) and the histogram is the MACD line minus
its signal average (SignalMaType). Long: close above both Supertrend lines and a positive histogram. Short: close below both lines
and a negative histogram. A long closes when the close falls below either line or the histogram turns negative, a short when the
close rises above either line or the histogram turns positive. TradeDirection limits the sides that may be opened.
"""
def __init__(self):
super(dual_supertrend_macd_strategy, self).__init__()
self._macd_fast = self.Param("MacdFast", 12).SetGreaterThanZero().SetDisplay("MACD Fast", "Fast MACD period", "MACD")
self._macd_slow = self.Param("MacdSlow", 26).SetGreaterThanZero().SetDisplay("MACD Slow", "Slow MACD period", "MACD")
self._macd_signal = self.Param("MacdSignal", 9).SetGreaterThanZero().SetDisplay("MACD Signal", "Signal MACD period", "MACD")
self._oscillator_ma_type = self.Param("OscillatorMaType", MaTypes.Exponential).SetDisplay("Oscillator MA Type", "Moving average type of the MACD line", "MACD")
self._signal_ma_type = self.Param("SignalMaType", MaTypes.Exponential).SetDisplay("Signal MA Type", "Moving average type of the signal line", "MACD")
self._atr_period1 = self.Param("AtrPeriod1", 10).SetGreaterThanZero().SetDisplay("ATR Period 1", "ATR period of the first Supertrend", "Supertrend")
self._factor1 = self.Param("Factor1", 3.0).SetGreaterThanZero().SetDisplay("Factor 1", "Factor of the first Supertrend", "Supertrend")
self._atr_period2 = self.Param("AtrPeriod2", 20).SetGreaterThanZero().SetDisplay("ATR Period 2", "ATR period of the second Supertrend", "Supertrend")
self._factor2 = self.Param("Factor2", 5.0).SetGreaterThanZero().SetDisplay("Factor 2", "Factor of the second Supertrend", "Supertrend")
self._trade_direction = self.Param("TradeDirection", "Both").SetDisplay("Trade Direction", "Sides that may be opened: Long, Short or Both", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._signal_ma = None
@property
def candle_type(self):
return self._candle_type.Value
@staticmethod
def _create_ma(ma_type, length):
ma = SimpleMovingAverage() if ma_type == MaTypes.Simple else ExponentialMovingAverage()
ma.Length = length
return ma
def OnStarted2(self, time):
super(dual_supertrend_macd_strategy, self).OnStarted2(time)
fast_ma = self._create_ma(self._oscillator_ma_type.Value, self._macd_fast.Value)
slow_ma = self._create_ma(self._oscillator_ma_type.Value, self._macd_slow.Value)
self._signal_ma = self._create_ma(self._signal_ma_type.Value, self._macd_signal.Value)
super_trend1 = SuperTrend()
super_trend1.Length = self._atr_period1.Value
super_trend1.Multiplier = Decimal(self._factor1.Value)
super_trend2 = SuperTrend()
super_trend2.Length = self._atr_period2.Value
super_trend2.Multiplier = Decimal(self._factor2.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(fast_ma, slow_ma, super_trend1, super_trend2, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, super_trend1)
self.DrawIndicator(area, super_trend2)
self.DrawOwnTrades(area)
def _process_candle(self, candle, fast_value, slow_value, st1_value, st2_value):
if candle.State != CandleStates.Finished:
return
if not fast_value.IsFormed or not slow_value.IsFormed:
return
macd = fast_value.GetValue[Decimal](None) - slow_value.GetValue[Decimal](None)
signal_input = DecimalIndicatorValue(self._signal_ma, macd, candle.OpenTime)
signal_input.IsFinal = True
signal_value = self._signal_ma.Process(signal_input)
if not signal_value.IsFormed or not st1_value.IsFormed or not st2_value.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
histogram = macd - signal_value.GetValue[Decimal](None)
st1 = st1_value.GetValue[Decimal](None)
st2 = st2_value.GetValue[Decimal](None)
close = candle.ClosePrice
direction = str(self._trade_direction.Value).lower()
allow_long = direction == "both" or direction == "long"
allow_short = direction == "both" or direction == "short"
long_entry = close > st1 and close > st2 and histogram > 0
short_entry = close < st1 and close < st2 and histogram < 0
long_exit = close < st1 or close < st2 or histogram < 0
short_exit = close > st1 or close > st2 or histogram > 0
if self.Position > 0:
if not long_exit:
return
if short_entry and allow_short:
self.SellMarket(self.Volume + self.Position)
else:
self.SellMarket(self.Position)
elif self.Position < 0:
if not short_exit:
return
if long_entry and allow_long:
self.BuyMarket(self.Volume - self.Position)
else:
self.BuyMarket(-self.Position)
elif long_entry and allow_long:
self.BuyMarket(self.Volume)
elif short_entry and allow_short:
self.SellMarket(self.Volume)
def CreateClone(self):
return dual_supertrend_macd_strategy()