Esta estrategia replica el asesor experto original de MetaTrader "MACD and SAR". Evalúa la relación entre las líneas principal y de señal del MACD junto con el nivel del SAR Parabólico en cada vela completada. Interruptores configurables permiten invertir cada comparación para que la misma plantilla pueda usarse tanto para configuraciones a contratendencia como a favor de tendencia. Se permiten múltiples entradas siempre que no se supere el número máximo configurado de posiciones apiladas.
Cuando aparece una señal de compra, la exposición corta existente se cierra y se abre un nuevo lote largo (si no se ha alcanzado el límite). Del mismo modo, una señal corta cierra primero los largos y luego añade un lote corto. No hay órdenes adicionales de stop-loss o take-profit; las operaciones se cierran únicamente cuando se genera la señal opuesta.
Lógica de la estrategia
Esperar una vela completada del marco temporal configurado.
Leer los valores del MACD (principal, señal, histograma) y el nivel del SAR Parabólico calculado sobre precios de cierre.
Evaluar las siguientes comparaciones, cada una de las cuales puede invertirse con su correspondiente parámetro booleano:
Línea principal del MACD vs. línea de señal.
Línea de señal del MACD vs. el nivel cero.
SAR Parabólico vs. precio de cierre.
Si las tres comparaciones para el lado largo se cumplen y la estrategia aún tiene margen para apilar nuevas posiciones, comprar el tamaño de lote especificado (incluyendo el volumen necesario para cerrar cortos).
Si las tres comparaciones para el lado corto se cumplen y el límite de apilamiento lo permite, vender el tamaño de lote especificado (incluyendo el volumen necesario para cerrar largos).
Parámetros
TradeVolume — volumen por operación individual (predeterminado 0.1).
MaxPositions — número máximo de posiciones apiladas en una dirección (predeterminado 10).
MacdFastPeriod — período de la EMA rápida del MACD (predeterminado 12).
MacdSlowPeriod — período de la EMA lenta del MACD (predeterminado 26).
MacdSignalPeriod — período de suavizado de la señal del MACD (predeterminado 9).
SarStep — paso de aceleración del SAR Parabólico (predeterminado 0.02).
SarMaximum — aceleración máxima del SAR Parabólico (predeterminado 0.2).
BuyMacdGreaterSignal — si es true, requiere MACD principal > señal para largos; de lo contrario espera lo contrario (predeterminado true).
BuySignalPositive — si es true, requiere MACD señal > 0 para largos; de lo contrario espera señal < 0 (predeterminado false).
BuySarAbovePrice — si es true, requiere SAR por encima del precio para largos; de lo contrario espera precio por encima del SAR (predeterminado false).
SellMacdGreaterSignal — si es true, requiere MACD principal > señal para cortos; de lo contrario espera MACD principal < señal (predeterminado false).
SellSignalPositive — si es true, requiere MACD señal > 0 para cortos; de lo contrario espera señal < 0 (predeterminado true).
SellSarAbovePrice — si es true, requiere SAR por encima del precio para cortos; de lo contrario espera precio por encima del SAR (predeterminado true).
CandleType — tipo/marco temporal de vela usado para el procesamiento de datos (predeterminado 15 minutos).
Notas adicionales
La estrategia depende únicamente de los cruces de indicadores; no hay stops de protección ni objetivos de beneficio.
El apilamiento de posiciones se implementa comparando el volumen absoluto de la posición con MaxPositions * TradeVolume con una pequeña tolerancia para manejar el redondeo.
Todas las operaciones se ejecutan con órdenes de mercado. Asegúrese de que la configuración de volumen de la cartera coincida con los instrumentos que planea operar.
Añada reglas opcionales de protección de cartera si necesita límites de drawdown o stops de seguimiento; ninguno está incluido por defecto.
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>
/// MACD and Parabolic SAR trend-following strategy (simplified).
/// Uses EMA crossover as MACD proxy and ParabolicSar for trend confirmation.
/// </summary>
public class MacdAndSarStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public MacdAndSarStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candles used for analysis", "General");
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastEma = new ExponentialMovingAverage { Length = FastPeriod };
var slowEma = new ExponentialMovingAverage { Length = SlowPeriod };
decimal prevFast = 0, prevSlow = 0;
bool hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, (ICandleMessage candle, decimal fastValue, decimal slowValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!hasPrev)
{
prevFast = fastValue;
prevSlow = slowValue;
hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
prevFast = fastValue;
prevSlow = slowValue;
return;
}
// Crossover detection (MACD-like)
if (prevFast <= prevSlow && fastValue > slowValue && Position <= 0)
{
BuyMarket();
}
else if (prevFast >= prevSlow && fastValue < slowValue && Position >= 0)
{
SellMarket();
}
prevFast = fastValue;
prevSlow = slowValue;
})
.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
class macd_and_sar_strategy(Strategy):
def __init__(self):
super(macd_and_sar_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 26) \
.SetDisplay("Slow Period", "Slow EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candles used for analysis", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
@property
def CandleType(self):
return self._candle_type.Value
def OnReseted(self):
super(macd_and_sar_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(macd_and_sar_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastPeriod
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowPeriod
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)
if not self._has_prev:
self._prev_fast = fv
self._prev_slow = sv
self._has_prev = True
return
if self._prev_fast <= self._prev_slow and fv > sv and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fv < sv and self.Position >= 0:
self.SellMarket()
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return macd_and_sar_strategy()