Ver en GitHub

PZ Parabolic SAR EA

This strategy replicates the PZ Parabolic SAR expert advisor. It employs two Parabolic SAR indicators with different step and maximum acceleration settings. The "trade" SAR detects trend direction for entries, while the "stop" SAR follows price more closely and triggers exits when the trend reverses.

Risk control is handled through the Average True Range (ATR). An initial ATR-based stop is set when a position opens. Optionally, a trailing stop based on ATR can tighten the stop as price moves in the trade's favor. The strategy also supports partial closing: once the profit exceeds the initial stop distance, half of the position is closed and the stop is moved to break-even.

The strategy works in both long and short directions and operates on finished candles only. It uses market orders without placing actual stop orders.

Details

  • Entry Criteria: Price above/below trade SAR and stop SAR in the same direction.
  • Long/Short: Both directions.
  • Exit Criteria: Stop SAR crossing price or ATR trailing stop hit.
  • Stops: ATR-based stop with optional trailing and break-even.
  • Default Values:
    • 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)
  • Filters:
    • Category: Trend
    • Direction: Both
    • Indicators: Parabolic SAR, ATR
    • Stops: ATR, Trailing
    • Complexity: Intermediate
    • Timeframe: Intraday (5m)
    • Seasonality: No
    • Neural Networks: No
    • Divergence: No
    • Risk Level: Medium
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;
	}
}