Estrategia de Tendencia MA PSAR ATR
La estrategia de Tendencia MA PSAR ATR combina un cruce de medias móviles con un filtro Parabolic SAR diario. Las operaciones se realizan solo cuando el precio se alinea por encima o por debajo de ambas medias y el PSAR coincide. Un stop basado en ATR controla el riesgo.
El método es adecuado para traders que buscan seguimiento de tendencia con stops dinámicos. Las señales se activan en velas de 5 minutos por defecto.
Detalles
- Criterios de entrada:
- Largo: MA rápida > MA lenta, Cierre > MA rápida, Mínimo > PSAR diario
- Corto: MA rápida < MA lenta, Cierre < MA rápida, Máximo < PSAR diario
- Largo/Corto: Ambos lados.
- Criterios de salida:
- Largo: La tendencia se vuelve bajista o el precio cae por debajo del stop ATR
- Corto: La tendencia se vuelve alcista o el precio sube por encima del stop ATR
- Stops: Sí, basado en ATR.
- Valores predeterminados:
FastMaPeriod= 40SlowMaPeriod= 160SarStep= 0.02mSarMaxStep= 0.2mAtrPeriod= 14AtrMultiplierLong= 2mAtrMultiplierShort= 2mUsePsarFilter= trueCandleType= TimeSpan.FromMinutes(5)
- Filtros:
- Categoría: Tendencia
- Dirección: Ambos
- Indicadores: MA, Parabolic SAR, ATR
- Stops: Sí
- Complejidad: Intermedio
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Moving Average Crossover with Parabolic SAR filter and ATR stop.
/// Buys when fast MA > slow MA + price > fast MA + price > PSAR.
/// Sells when fast MA < slow MA + price < fast MA + price < PSAR.
/// Uses ATR-based stop loss.
/// </summary>
public class MaPsarAtrTrendStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastMaPeriod;
private readonly StrategyParam<int> _slowMaPeriod;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrMultiplier;
private readonly StrategyParam<int> _cooldownBars;
private ExponentialMovingAverage _fastMa;
private ExponentialMovingAverage _slowMa;
private AverageTrueRange _atr;
private ParabolicSar _psar;
private decimal _stopPrice;
private int _cooldownRemaining;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastMaPeriod
{
get => _fastMaPeriod.Value;
set => _fastMaPeriod.Value = value;
}
public int SlowMaPeriod
{
get => _slowMaPeriod.Value;
set => _slowMaPeriod.Value = value;
}
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
public decimal AtrMultiplier
{
get => _atrMultiplier.Value;
set => _atrMultiplier.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
public MaPsarAtrTrendStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_fastMaPeriod = Param(nameof(FastMaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Fast MA Period", "Fast EMA period", "MA");
_slowMaPeriod = Param(nameof(SlowMaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Slow MA Period", "Slow EMA period", "MA");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period", "ATR");
_atrMultiplier = Param(nameof(AtrMultiplier), 2m)
.SetDisplay("ATR Multiplier", "ATR stop multiplier", "Risk");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fastMa = null;
_slowMa = null;
_atr = null;
_psar = null;
_stopPrice = 0;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fastMa = new ExponentialMovingAverage { Length = FastMaPeriod };
_slowMa = new ExponentialMovingAverage { Length = SlowMaPeriod };
_atr = new AverageTrueRange { Length = AtrPeriod };
_psar = new ParabolicSar();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_fastMa, _slowMa, _atr, _psar, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _fastMa);
DrawIndicator(area, _slowMa);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal atrVal, decimal psarVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!_fastMa.IsFormed || !_slowMa.IsFormed || !_atr.IsFormed || !_psar.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
return;
}
var price = candle.ClosePrice;
var bullishTrend = fastVal > slowVal && price > fastVal;
var bearishTrend = fastVal < slowVal && price < fastVal;
var psarBull = price > psarVal;
var psarBear = price < psarVal;
// Check stop loss
if (Position > 0 && price <= _stopPrice)
{
SellMarket(Math.Abs(Position));
_stopPrice = 0;
_cooldownRemaining = CooldownBars;
return;
}
else if (Position < 0 && price >= _stopPrice)
{
BuyMarket(Math.Abs(Position));
_stopPrice = 0;
_cooldownRemaining = CooldownBars;
return;
}
// Entry long
if (bullishTrend && psarBull && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_stopPrice = price - atrVal * AtrMultiplier;
_cooldownRemaining = CooldownBars;
}
// Entry short
else if (bearishTrend && psarBear && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_stopPrice = price + atrVal * AtrMultiplier;
_cooldownRemaining = CooldownBars;
}
// Exit long on trend reversal
else if (Position > 0 && bearishTrend)
{
SellMarket(Math.Abs(Position));
_stopPrice = 0;
_cooldownRemaining = CooldownBars;
}
// Exit short on trend reversal
else if (Position < 0 && bullishTrend)
{
BuyMarket(Math.Abs(Position));
_stopPrice = 0;
_cooldownRemaining = 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, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, AverageTrueRange, ParabolicSar
from StockSharp.Algo.Strategies import Strategy
class ma_psar_atr_trend_strategy(Strategy):
"""Moving Average Crossover with Parabolic SAR filter and ATR stop."""
def __init__(self):
super(ma_psar_atr_trend_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._fast_ma_period = self.Param("FastMaPeriod", 20) \
.SetDisplay("Fast MA Period", "Fast EMA period", "MA")
self._slow_ma_period = self.Param("SlowMaPeriod", 50) \
.SetDisplay("Slow MA Period", "Slow EMA period", "MA")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR period", "ATR")
self._atr_multiplier = self.Param("AtrMultiplier", 2.0) \
.SetDisplay("ATR Multiplier", "ATR stop multiplier", "Risk")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk")
self._fast_ma = None
self._slow_ma = None
self._atr = None
self._psar = None
self._stop_price = 0.0
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ma_psar_atr_trend_strategy, self).OnReseted()
self._fast_ma = None
self._slow_ma = None
self._atr = None
self._psar = None
self._stop_price = 0.0
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(ma_psar_atr_trend_strategy, self).OnStarted2(time)
self._fast_ma = ExponentialMovingAverage()
self._fast_ma.Length = int(self._fast_ma_period.Value)
self._slow_ma = ExponentialMovingAverage()
self._slow_ma.Length = int(self._slow_ma_period.Value)
self._atr = AverageTrueRange()
self._atr.Length = int(self._atr_period.Value)
self._psar = ParabolicSar()
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ma, self._slow_ma, self._atr, self._psar, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._fast_ma)
self.DrawIndicator(area, self._slow_ma)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_val, slow_val, atr_val, psar_val):
if candle.State != CandleStates.Finished:
return
if not self._fast_ma.IsFormed or not self._slow_ma.IsFormed or not self._atr.IsFormed or not self._psar.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
return
price = float(candle.ClosePrice)
fast_v = float(fast_val)
slow_v = float(slow_val)
atr_v = float(atr_val)
psar_v = float(psar_val)
atr_mult = float(self._atr_multiplier.Value)
cooldown = int(self._cooldown_bars.Value)
bullish_trend = fast_v > slow_v and price > fast_v
bearish_trend = fast_v < slow_v and price < fast_v
psar_bull = price > psar_v
psar_bear = price < psar_v
if self.Position > 0 and price <= self._stop_price:
self.SellMarket(Math.Abs(self.Position))
self._stop_price = 0.0
self._cooldown_remaining = cooldown
return
elif self.Position < 0 and price >= self._stop_price:
self.BuyMarket(Math.Abs(self.Position))
self._stop_price = 0.0
self._cooldown_remaining = cooldown
return
if bullish_trend and psar_bull and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._stop_price = price - atr_v * atr_mult
self._cooldown_remaining = cooldown
elif bearish_trend and psar_bear and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._stop_price = price + atr_v * atr_mult
self._cooldown_remaining = cooldown
elif self.Position > 0 and bearish_trend:
self.SellMarket(Math.Abs(self.Position))
self._stop_price = 0.0
self._cooldown_remaining = cooldown
elif self.Position < 0 and bullish_trend:
self.BuyMarket(Math.Abs(self.Position))
self._stop_price = 0.0
self._cooldown_remaining = cooldown
def CreateClone(self):
return ma_psar_atr_trend_strategy()