Tendencia Parabolic SAR
Estrategia basada en el indicador Parabolic SAR. La Tendencia Parabolic SAR sigue los puntos del indicador Parabolic SAR. Un cambio del precio de un lado del SAR al otro marca un posible cambio de tendencia. Si el precio cruza de vuelta, la operación se cierra.
Las pruebas indican un retorno anual promedio de aproximadamente 49%. Funciona mejor en el mercado de criptomonedas.
Dado que los puntos del SAR siguen el precio, naturalmente proporcionan un punto de salida cuando la tendencia cambia. El método opera tanto en largo como en corto sin utilizar stops adicionales más allá de la reversión del SAR.
Detalles
- Criterios de entrada: Señales basadas en Parabolic, SAR.
- Largo/Corto: Ambos directions.
- Criterios de salida: Señal opuesta.
- Stops: No.
- Valores predeterminados:
AccelerationFactor= 0.02mMaxAccelerationFactor= 0.2mCandleType= TimeSpan.FromMinutes(5)
- Filtros:
- Categoría: Tendencia
- Dirección: Ambos
- Indicadores: Parabolic, SAR
- Stops: No
- Complejidad: Básico
- Marco temporal: Intradía (5m)
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy based on Parabolic SAR indicator.
/// It enters long position when price is above SAR and short position when price is below SAR.
/// </summary>
public class ParabolicSarTrendStrategy : Strategy
{
private readonly StrategyParam<decimal> _accelerationFactor;
private readonly StrategyParam<decimal> _maxAccelerationFactor;
private readonly StrategyParam<DataType> _candleType;
// Current state
private decimal _prevSarValue;
private bool _prevIsPriceAboveSar;
/// <summary>
/// Initial acceleration factor for SAR.
/// </summary>
public decimal AccelerationFactor
{
get => _accelerationFactor.Value;
set => _accelerationFactor.Value = value;
}
/// <summary>
/// Maximum acceleration factor for SAR.
/// </summary>
public decimal MaxAccelerationFactor
{
get => _maxAccelerationFactor.Value;
set => _maxAccelerationFactor.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize the Parabolic SAR Trend strategy.
/// </summary>
public ParabolicSarTrendStrategy()
{
_accelerationFactor = Param(nameof(AccelerationFactor), 0.02m)
.SetGreaterThanZero()
.SetDisplay("Acceleration Factor", "Initial acceleration factor for SAR calculation", "Indicators")
.SetOptimize(0.01m, 0.05m, 0.01m);
_maxAccelerationFactor = Param(nameof(MaxAccelerationFactor), 0.2m)
.SetGreaterThanZero()
.SetDisplay("Max Acceleration Factor", "Maximum acceleration factor for SAR calculation", "Indicators")
.SetOptimize(0.1m, 0.5m, 0.1m);
_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();
_prevSarValue = 0;
_prevIsPriceAboveSar = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create Parabolic SAR indicator
var parabolicSar = new ParabolicSar
{
Acceleration = AccelerationFactor,
AccelerationMax = MaxAccelerationFactor
};
// Create subscription and bind indicator
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(parabolicSar, ProcessCandle)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, parabolicSar);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal sarValue)
{
if (candle.State != CandleStates.Finished || sarValue <= 0)
return;
var isPriceAboveSar = candle.ClosePrice > sarValue;
// A flip is a change of side between two consecutive finished candles.
var flipped = _prevSarValue > 0 && isPriceAboveSar != _prevIsPriceAboveSar;
_prevSarValue = sarValue;
_prevIsPriceAboveSar = isPriceAboveSar;
if (!flipped || !IsFormedAndOnlineAndAllowTrading())
return;
var volume = Volume + Math.Abs(Position);
if (isPriceAboveSar && Position <= 0)
{
BuyMarket(volume);
LogInfo($"Buy signal: Price {candle.ClosePrice} crossed above SAR {sarValue}");
}
else if (!isPriceAboveSar && Position >= 0)
{
SellMarket(volume);
LogInfo($"Sell signal: Price {candle.ClosePrice} crossed below SAR {sarValue}");
}
}
}
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
from StockSharp.Algo.Strategies import Strategy
class parabolic_sar_trend_strategy(Strategy):
"""
Strategy based on Parabolic SAR indicator.
Enters long when price crosses above SAR, short when price crosses below SAR.
"""
def __init__(self):
super(parabolic_sar_trend_strategy, self).__init__()
self._acceleration_factor = self.Param("AccelerationFactor", 0.02).SetGreaterThanZero().SetDisplay("Acceleration Factor", "Initial acceleration factor for SAR calculation", "Indicators")
self._max_acceleration_factor = self.Param("MaxAccelerationFactor", 0.2).SetGreaterThanZero().SetDisplay("Max Acceleration Factor", "Maximum acceleration factor for SAR calculation", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_sar_value = None
self._prev_is_price_above_sar = False
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(parabolic_sar_trend_strategy, self).OnReseted()
self._prev_sar_value = None
self._prev_is_price_above_sar = False
def OnStarted2(self, time):
super(parabolic_sar_trend_strategy, self).OnStarted2(time)
sar = ParabolicSar()
sar.Acceleration = Decimal(self._acceleration_factor.Value)
sar.AccelerationMax = Decimal(self._max_acceleration_factor.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sar, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sar)
self.DrawOwnTrades(area)
def _process_candle(self, candle, sar_val):
if candle.State != CandleStates.Finished or sar_val <= 0:
return
is_price_above_sar = candle.ClosePrice > sar_val
# A flip is a change of side between two consecutive finished candles.
flipped = self._prev_sar_value is not None and is_price_above_sar != self._prev_is_price_above_sar
self._prev_sar_value = sar_val
self._prev_is_price_above_sar = is_price_above_sar
if not flipped or not self.IsFormedAndOnlineAndAllowTrading():
return
volume = self.Volume + abs(self.Position)
if is_price_above_sar and self.Position <= 0:
self.BuyMarket(volume)
elif not is_price_above_sar and self.Position >= 0:
self.SellMarket(volume)
def CreateClone(self):
return parabolic_sar_trend_strategy()