Ver no GitHub

Parabolic SAR Bug

The Parabolic SAR Bug strategy trades trend reversals using the Parabolic SAR indicator. When the SAR flips below price the strategy enters long, and when the SAR flips above price it enters short. Optional reverse mode inverts signals. Protective stop loss, take profit, and trailing stop are supported through the built-in position protection module.

Details

  • Entry Criteria: Parabolic SAR direction change.
  • Long/Short: Both directions.
  • Exit Criteria: Opposite SAR signal or protective stop.
  • Stops: Stop loss, take profit, optional trailing stop.
  • Default Values:
    • Step = 0.02
    • MaxStep = 0.2
    • StopLossPercent = 2
    • TakeProfitPercent = 1
    • UseTrailingStop = false
    • Reverse = false
    • CloseOnSar = true
    • CandleType = TimeSpan.FromMinutes(5)
  • Filters:
    • Category: Trend
    • Direction: Both
    • Indicators: Parabolic SAR
    • Stops: Stop loss, take profit
    • Complexity: Basic
    • 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.
/// Buys when price crosses above SAR, sells when price crosses below.
/// </summary>
public class ParabolicSarBugStrategy : Strategy
{
	private readonly StrategyParam<decimal> _step;
	private readonly StrategyParam<decimal> _maxStep;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevSar;
	private decimal _prevClose;
	private bool _initialized;

	public decimal Step { get => _step.Value; set => _step.Value = value; }
	public decimal MaxStep { get => _maxStep.Value; set => _maxStep.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public ParabolicSarBugStrategy()
	{
		_step = Param(nameof(Step), 0.02m)
			.SetDisplay("Step", "Acceleration factor", "Indicator");

		_maxStep = Param(nameof(MaxStep), 0.2m)
			.SetDisplay("Max Step", "Maximum acceleration", "Indicator");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

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

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

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

		var sar = new ParabolicSar
		{
			Acceleration = Step,
			AccelerationMax = MaxStep
		};

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

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

		var close = candle.ClosePrice;

		if (!_initialized)
		{
			_prevSar = sarValue;
			_prevClose = close;
			_initialized = true;
			return;
		}

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

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

		_prevSar = sarValue;
		_prevClose = close;
	}
}