Ver en GitHub

Estrategia SAR Automatizada

Este ejemplo demuestra un enfoque de trading simple basado en el indicador Parabolic SAR. La estrategia abre una posición larga cuando el precio actual está por encima del valor SAR y abre una posición corta cuando el precio está por debajo del SAR. Las características adicionales de gestión de riesgos incluyen stop-loss fijo, take-profit y un trailing stop opcional.

Parámetros

  • SarStep – factor de aceleración para el cálculo del SAR.
  • SarMax – factor de aceleración máximo para el SAR.
  • StopLoss – distancia del stop-loss en unidades de precio.
  • TakeProfit – distancia del take-profit en unidades de precio.
  • TrailingStop – distancia del trailing stop en unidades de precio.
  • CandleType – tipo de velas utilizadas para los cálculos del indicador.

Lógica de trading

  1. Suscribirse a las velas y calcular los valores del Parabolic SAR.
  2. Entrada:
    • Ir largo cuando SAR esté por debajo del precio de cierre y no exista posición.
    • Ir corto cuando SAR esté por encima del precio de cierre y no exista posición.
  3. Salida:
    • Cerrar la posición cuando el precio alcance el nivel SAR opuesto.
    • Aplicar las reglas de stop-loss, take-profit y trailing stop.

Esta estrategia está destinada a fines educativos y muestra cómo usar indicadores y controles de riesgo con la API de alto nivel de StockSharp.

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>
/// Simple Parabolic SAR based strategy with optional stop-loss,
/// take-profit and trailing stop management.
/// </summary>
public class SarAutomatedStrategy : Strategy
{
	private readonly StrategyParam<decimal> _sarStep;
	private readonly StrategyParam<decimal> _sarMax;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<decimal> _takeProfit;
	private readonly StrategyParam<decimal> _trailingStop;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _entryPrice;
	private decimal _highestPrice;
	private decimal _lowestPrice;

	/// <summary>
	/// Parabolic SAR acceleration step.
	/// </summary>
	public decimal SarStep
	{
		get => _sarStep.Value;
		set => _sarStep.Value = value;
	}

	/// <summary>
	/// Parabolic SAR maximum acceleration.
	/// </summary>
	public decimal SarMax
	{
		get => _sarMax.Value;
		set => _sarMax.Value = value;
	}

	/// <summary>
	/// Stop loss in price units.
	/// </summary>
	public decimal StopLoss
	{
		get => _stopLoss.Value;
		set => _stopLoss.Value = value;
	}

	/// <summary>
	/// Take profit in price units.
	/// </summary>
	public decimal TakeProfit
	{
		get => _takeProfit.Value;
		set => _takeProfit.Value = value;
	}

	/// <summary>
	/// Trailing stop in price units.
	/// </summary>
	public decimal TrailingStop
	{
		get => _trailingStop.Value;
		set => _trailingStop.Value = value;
	}

	/// <summary>
	/// Candle type for calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initialize <see cref="SarAutomatedStrategy"/>.
	/// </summary>
	public SarAutomatedStrategy()
	{
		_sarStep = Param(nameof(SarStep), 0.002m)
			.SetDisplay("SAR Step", "Acceleration factor for SAR", "Indicators");

		_sarMax = Param(nameof(SarMax), 0.02m)
			.SetDisplay("SAR Max", "Maximum acceleration for SAR", "Indicators");

		_stopLoss = Param(nameof(StopLoss), 3500m)
			.SetDisplay("Stop Loss", "Stop loss in price units", "Risk Management");

		_takeProfit = Param(nameof(TakeProfit), 6500m)
			.SetDisplay("Take Profit", "Take profit in price units", "Risk Management");

		_trailingStop = Param(nameof(TrailingStop), 800m)
			.SetDisplay("Trailing Stop", "Trailing stop in price units", "Risk Management");

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

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_entryPrice = 0m;
		_highestPrice = 0m;
		_lowestPrice = 0m;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

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

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sar, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, sar);
			DrawOwnTrades(area);
		}
	}

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (Position == 0)
		{
			if (sarValue < candle.ClosePrice)
			{
				BuyMarket();
				_entryPrice = candle.ClosePrice;
				_highestPrice = candle.ClosePrice;
				_lowestPrice = candle.ClosePrice;
			}
			else if (sarValue > candle.ClosePrice)
			{
				SellMarket();
				_entryPrice = candle.ClosePrice;
				_highestPrice = candle.ClosePrice;
				_lowestPrice = candle.ClosePrice;
			}
		}
		else if (Position > 0)
		{
			_highestPrice = Math.Max(_highestPrice, candle.HighPrice);

			if (candle.HighPrice - _entryPrice >= TakeProfit)
			{
				SellMarket();
				return;
			}

			if (_entryPrice - candle.LowPrice >= StopLoss)
			{
				SellMarket();
				return;
			}

			if (TrailingStop > 0m && _highestPrice - candle.ClosePrice >= TrailingStop)
			{
				SellMarket();
				return;
			}

			if (sarValue > candle.ClosePrice)
			{
				SellMarket();
			}
		}
		else if (Position < 0)
		{
			_lowestPrice = Math.Min(_lowestPrice, candle.LowPrice);

			if (_entryPrice - candle.LowPrice >= TakeProfit)
			{
				BuyMarket();
				return;
			}

			if (candle.HighPrice - _entryPrice >= StopLoss)
			{
				BuyMarket();
				return;
			}

			if (TrailingStop > 0m && candle.ClosePrice - _lowestPrice >= TrailingStop)
			{
				BuyMarket();
				return;
			}

			if (sarValue < candle.ClosePrice)
			{
				BuyMarket();
			}
		}
	}
}