Parabolic SAR con Confirmación de MACD
Esta estrategia combina el indicador Parabolic SAR con la confirmación del MACD. Se abre una posición cuando el precio cruza el SAR en una dirección respaldada por el MACD, con el objetivo de capturar reversiones de tendencia.
Detalles
- Criterios de entrada: El precio cruza el SAR y la línea MACD está en el mismo lado que su línea de señal.
- Largo/Corto: Ambas direcciones.
- Criterios de salida: Cruce opuesto de precio/SAR o MACD.
- Stops: No.
- Valores predeterminados:
SarStart= 0.02mSarIncrement= 0.02mSarMax= 0.2mMacdFast= 12MacdSlow= 26MacdSignal= 9CandleType= TimeSpan.FromMinutes(5)
- Filtros:
- Categoría: Tendencia
- Dirección: Ambos
- Indicadores: Parabolic SAR, MACD
- Stops: No
- 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>
/// Parabolic SAR with MACD confirmation.
/// A close crossing above the Parabolic SAR while the MACD line is above its signal line goes long, a close crossing below the SAR
/// while MACD is below its signal goes short, reversing an opposite position. A position is closed on the opposite price/SAR
/// crossover or on the opposite MACD/signal crossover.
/// </summary>
public class ParabolicSarMacdTrendZoneStrategy : Strategy
{
private readonly StrategyParam<decimal> _sarStart;
private readonly StrategyParam<decimal> _sarIncrement;
private readonly StrategyParam<decimal> _sarMax;
private readonly StrategyParam<int> _macdFast;
private readonly StrategyParam<int> _macdSlow;
private readonly StrategyParam<int> _macdSignal;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevClose;
private decimal? _prevSar;
private decimal? _prevMacd;
private decimal? _prevSignal;
/// <summary>
/// Initial SAR acceleration factor.
/// </summary>
public decimal SarStart
{
get => _sarStart.Value;
set => _sarStart.Value = value;
}
/// <summary>
/// SAR acceleration factor increment.
/// </summary>
public decimal SarIncrement
{
get => _sarIncrement.Value;
set => _sarIncrement.Value = value;
}
/// <summary>
/// Maximum SAR acceleration factor.
/// </summary>
public decimal SarMax
{
get => _sarMax.Value;
set => _sarMax.Value = value;
}
/// <summary>
/// Fast EMA period of MACD.
/// </summary>
public int MacdFast
{
get => _macdFast.Value;
set => _macdFast.Value = value;
}
/// <summary>
/// Slow EMA period of MACD.
/// </summary>
public int MacdSlow
{
get => _macdSlow.Value;
set => _macdSlow.Value = value;
}
/// <summary>
/// Signal line period of MACD.
/// </summary>
public int MacdSignal
{
get => _macdSignal.Value;
set => _macdSignal.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public ParabolicSarMacdTrendZoneStrategy()
{
_sarStart = Param(nameof(SarStart), 0.02m)
.SetGreaterThanZero()
.SetDisplay("SAR Start", "Initial SAR acceleration factor", "Indicators");
_sarIncrement = Param(nameof(SarIncrement), 0.02m)
.SetGreaterThanZero()
.SetDisplay("SAR Increment", "SAR acceleration factor increment", "Indicators");
_sarMax = Param(nameof(SarMax), 0.2m)
.SetGreaterThanZero()
.SetDisplay("SAR Max", "Maximum SAR acceleration factor", "Indicators");
_macdFast = Param(nameof(MacdFast), 12)
.SetGreaterThanZero()
.SetDisplay("MACD Fast", "Fast EMA period of MACD", "Indicators");
_macdSlow = Param(nameof(MacdSlow), 26)
.SetGreaterThanZero()
.SetDisplay("MACD Slow", "Slow EMA period of MACD", "Indicators");
_macdSignal = Param(nameof(MacdSignal), 9)
.SetGreaterThanZero()
.SetDisplay("MACD Signal", "Signal line period of MACD", "Indicators");
_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();
ResetState();
}
private void ResetState()
{
_prevClose = null;
_prevSar = null;
_prevMacd = null;
_prevSignal = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var sar = new ParabolicSar
{
Acceleration = SarStart,
AccelerationStep = SarIncrement,
AccelerationMax = SarMax
};
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = MacdFast },
LongMa = { Length = MacdSlow },
},
SignalMa = { Length = MacdSignal }
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(sar, macd, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sar);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
DrawIndicator(oscillators, macd);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue sarValue, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!sarValue.IsFormed || !macdValue.IsFormed)
return;
if (macdValue is not IMovingAverageConvergenceDivergenceSignalValue { Macd: decimal macdLine, Signal: decimal signalLine })
return;
var sar = sarValue.ToDecimal();
var close = candle.ClosePrice;
var prevClose = _prevClose;
var prevSar = _prevSar;
var prevMacd = _prevMacd;
var prevSignal = _prevSignal;
_prevClose = close;
_prevSar = sar;
_prevMacd = macdLine;
_prevSignal = signalLine;
if (prevClose is not decimal pc || prevSar is not decimal ps || prevMacd is not decimal pm || prevSignal is not decimal pSig)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var crossUp = pc <= ps && close > sar;
var crossDown = pc >= ps && close < sar;
var macdCrossUp = pm <= pSig && macdLine > signalLine;
var macdCrossDown = pm >= pSig && macdLine < signalLine;
if (crossUp && macdLine > signalLine && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (crossDown && macdLine < signalLine && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
else if (Position > 0 && (crossDown || macdCrossDown))
SellMarket(Position);
else if (Position < 0 && (crossUp || macdCrossUp))
BuyMarket(-Position);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ParabolicSar, MovingAverageConvergenceDivergenceSignal
from StockSharp.Algo.Strategies import Strategy
class parabolic_sar_macd_trend_zone_strategy(Strategy):
"""
Parabolic SAR with MACD confirmation.
A close crossing above the Parabolic SAR while the MACD line is above its signal line goes long, a close crossing below the SAR
while MACD is below its signal goes short, reversing an opposite position. A position is closed on the opposite price/SAR
crossover or on the opposite MACD/signal crossover.
"""
def __init__(self):
super(parabolic_sar_macd_trend_zone_strategy, self).__init__()
self._sar_start = self.Param("SarStart", 0.02).SetGreaterThanZero().SetDisplay("SAR Start", "Initial SAR acceleration factor", "Indicators")
self._sar_increment = self.Param("SarIncrement", 0.02).SetGreaterThanZero().SetDisplay("SAR Increment", "SAR acceleration factor increment", "Indicators")
self._sar_max = self.Param("SarMax", 0.2).SetGreaterThanZero().SetDisplay("SAR Max", "Maximum SAR acceleration factor", "Indicators")
self._macd_fast = self.Param("MacdFast", 12).SetGreaterThanZero().SetDisplay("MACD Fast", "Fast EMA period of MACD", "Indicators")
self._macd_slow = self.Param("MacdSlow", 26).SetGreaterThanZero().SetDisplay("MACD Slow", "Slow EMA period of MACD", "Indicators")
self._macd_signal = self.Param("MacdSignal", 9).SetGreaterThanZero().SetDisplay("MACD Signal", "Signal line period of MACD", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._prev_close = None
self._prev_sar = None
self._prev_macd = None
self._prev_signal = None
def OnReseted(self):
super(parabolic_sar_macd_trend_zone_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(parabolic_sar_macd_trend_zone_strategy, self).OnStarted2(time)
self._reset_state()
sar = ParabolicSar()
sar.Acceleration = Decimal(self._sar_start.Value)
sar.AccelerationStep = Decimal(self._sar_increment.Value)
sar.AccelerationMax = Decimal(self._sar_max.Value)
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self._macd_fast.Value
macd.Macd.LongMa.Length = self._macd_slow.Value
macd.SignalMa.Length = self._macd_signal.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(sar, macd, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sar)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, macd)
def _process_candle(self, candle, sar_value, macd_value):
if candle.State != CandleStates.Finished:
return
if not sar_value.IsFormed or not macd_value.IsFormed:
return
macd_line = macd_value.Macd
signal_line = macd_value.Signal
if macd_line is None or signal_line is None:
return
sar = sar_value.GetValue[Decimal](None)
close = candle.ClosePrice
prev_close = self._prev_close
prev_sar = self._prev_sar
prev_macd = self._prev_macd
prev_signal = self._prev_signal
self._prev_close = close
self._prev_sar = sar
self._prev_macd = macd_line
self._prev_signal = signal_line
if prev_close is None or prev_sar is None or prev_macd is None or prev_signal is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
cross_up = prev_close <= prev_sar and close > sar
cross_down = prev_close >= prev_sar and close < sar
macd_cross_up = prev_macd <= prev_signal and macd_line > signal_line
macd_cross_down = prev_macd >= prev_signal and macd_line < signal_line
if cross_up and macd_line > signal_line and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif cross_down and macd_line < signal_line and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
elif self.Position > 0 and (cross_down or macd_cross_down):
self.SellMarket(self.Position)
elif self.Position < 0 and (cross_up or macd_cross_up):
self.BuyMarket(-self.Position)
def CreateClone(self):
return parabolic_sar_macd_trend_zone_strategy()