Ver en GitHub

Estrategia PZ Parabolic SAR EA

Esta estrategia replica el asesor experto PZ Parabolic SAR. Emplea dos indicadores Parabolic SAR con diferentes configuraciones de paso y aceleración máxima. El SAR de "operación" detecta la dirección de la tendencia para las entradas, mientras que el SAR de "stop" sigue el precio más de cerca y activa las salidas cuando la tendencia se revierte.

El control del riesgo se gestiona mediante el Average True Range (ATR). Se establece un stop inicial basado en ATR cuando se abre una posición. Opcionalmente, un trailing stop basado en ATR puede ajustar el stop a medida que el precio se mueve a favor de la operación. La estrategia también admite cierre parcial: una vez que el beneficio supera la distancia del stop inicial, se cierra la mitad de la posición y el stop se mueve a break-even.

La estrategia opera en dirección larga y corta y solo funciona con velas completadas. Utiliza órdenes de mercado sin colocar órdenes de stop reales.

Detalles

  • Criterios de entrada: Precio por encima/debajo del SAR de operación y del SAR de stop en la misma dirección.
  • Largo/Corto: Ambas direcciones.
  • Criterios de salida: SAR de stop cruzando el precio o trailing stop ATR alcanzado.
  • Stops: Stop basado en ATR con trailing y break-even opcionales.
  • Valores predeterminados:
    • TradeStep = 0.002
    • TradeMax = 0.2
    • StopStep = 0.004
    • StopMax = 0.4
    • AtrPeriod = 30
    • AtrMultiplier = 2.5
    • UseTrailing = false
    • TrailingAtrPeriod = 30
    • TrailingAtrMultiplier = 1.75
    • PartialClosing = true
    • PercentageToClose = 0.5
    • BreakEven = true
    • LotSize = 0.1
    • CandleType = TimeFrame(5m)
  • Filtros:
    • Categoría: Tendencia
    • Dirección: Ambos
    • Indicadores: Parabolic SAR, ATR
    • Stops: ATR, Trailing
    • Complejidad: Intermedio
    • Marco temporal: Intradía (5m)
    • 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 crossover strategy.
/// </summary>
public class PzParabolicSarEaStrategy : Strategy
{
	private readonly StrategyParam<decimal> _sarStep;
	private readonly StrategyParam<decimal> _sarMax;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevClose;
	private decimal _prevSar;
	private bool _hasPrev;

	public decimal SarStep { get => _sarStep.Value; set => _sarStep.Value = value; }
	public decimal SarMax { get => _sarMax.Value; set => _sarMax.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public PzParabolicSarEaStrategy()
	{
		_sarStep = Param(nameof(SarStep), 0.02m)
			.SetDisplay("SAR Step", "Acceleration step", "Indicators");
		_sarMax = Param(nameof(SarMax), 0.2m)
			.SetDisplay("SAR Max", "Maximum acceleration", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevClose = 0;
		_prevSar = 0;
		_hasPrev = false;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var sar = new ParabolicSar { AccelerationStep = SarStep, AccelerationMax = SarMax };

		SubscribeCandles(CandleType)
			.Bind(sar, ProcessCandle)
			.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal sarVal)
	{
		if (candle.State != CandleStates.Finished) return;

		var close = candle.ClosePrice;

		if (!_hasPrev)
		{
			_prevClose = close;
			_prevSar = sarVal;
			_hasPrev = true;
			return;
		}

		var crossUp = _prevClose <= _prevSar && close > sarVal;
		var crossDown = _prevClose >= _prevSar && close < sarVal;

		if (crossUp && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (crossDown && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevClose = close;
		_prevSar = sarVal;
	}
}