Ver en GitHub

Estrategia de errores de Psar

Descripción general

La Psar Bug Strategy es una adaptación directa del MetaTrader 4 asesor experto pSAR_bug.mq4. Reacciona al primer punto Parabolic SAR que aparece en el lado opuesto del precio e inmediatamente invierte la posición. La implementación StockSharp se suscribe a velas, evalúa solo barras completadas y utiliza el API de alto nivel para realizar órdenes de mercado y gestionar paradas de protección.

Lógica de trading

  • Calcula el Parabolic SAR con un paso de aceleración de 0.02 y una aceleración máxima de 0.2 (ambas configurables).
  • Espere a que termine una vela donde el valor Parabolic SAR cambie en relación con el cierre:
    • Entrada larga: el valor actual de SAR está por debajo del precio de cierre mientras que el valor anterior de SAR estaba por encima del cierre anterior.
    • Entrada corta: el valor actual de SAR está por encima del precio de cierre mientras que el valor anterior de SAR estaba por debajo del precio de cierre anterior.
  • Invertir la exposición existente en cada señal. Cuando aparece una señal de compra, cualquier posición corta abierta se aplana y se reemplaza con una posición larga del tamaño configurado. Lo contrario se aplica a las señales de venta.
  • Aplique distancias fijas de stop-loss y take-profit expresadas en incrementos del precio del instrumento. La protección se implementa con StartProtection para que los parámetros de riesgo se adjunten automáticamente a cada nueva posición.

Parámetros

Nombre Descripción
TradeVolume Volumen de pedidos en lotes utilizados para las entradas. El valor predeterminado es 0.1 lotes.
StopLossPoints Distancia desde el precio de entrada hasta el stop-loss expresada en incrementos de precio. Refleja la entrada MetaTrader StopLoss.
TakeProfitPoints Distancia desde el precio de entrada hasta la obtención de beneficios expresada en incrementos de precio. Refleja la entrada MetaTrader TakeProfit.
SarAccelerationStep Factor de aceleración inicial del indicador Parabolic SAR.
SarAccelerationMax Factor de aceleración máximo para el cálculo Parabolic SAR.
CandleType Tipo de datos de vela (período de tiempo) utilizado para los cálculos del indicador. Por defecto, la estrategia funciona con velas de 15 minutos.

Notas sobre la conversión

  • El experto original hace referencia directamente al símbolo del gráfico actual y al período de tiempo. La versión StockSharp expone el tipo de vela como parámetro para que el período de tiempo se pueda cambiar sin volver a compilar.
  • Las paradas de protección se representan como compensaciones de precios absolutas. Se inicializan una vez al inicio y la plataforma los administra automáticamente.
  • La gestión de órdenes se basa en la lógica de compensación: comprar Volume + |Position| lotes cierra el corto anterior y abre el nuevo largo, reproduciendo el comportamiento MetaTrader de cerrar antes de abrir en la dirección opuesta.

Uso

  1. Configure los parámetros de seguridad, plazo (CandleType) y riesgo que desee dentro de StockSharp Designer o Backtester.
  2. Asegúrese de que los datos del mercado estén disponibles e inicie la estrategia. Las señales se evalúan únicamente en velas terminadas.
  3. Supervise las posiciones y el rendimiento a través de las herramientas estándar StockSharp. Los gráficos muestran velas, el indicador Parabolic SAR y operaciones ejecutadas para la validación visual de las señales de reversión.
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// PsarBug: EMA trend with RSI confirmation and ATR stops.
/// </summary>
public class PsarBugStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaLength;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevClose;
	private decimal _entryPrice;

	public PsarBugStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_emaLength = Param(nameof(EmaLength), 30)
			.SetDisplay("EMA Length", "Trend filter.", "Indicators");

		_rsiLength = Param(nameof(RsiLength), 14)
			.SetDisplay("RSI Length", "RSI period.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int EmaLength
	{
		get => _emaLength.Value;
		set => _emaLength.Value = value;
	}

	public int RsiLength
	{
		get => _rsiLength.Value;
		set => _rsiLength.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

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

		_prevClose = 0;
		_entryPrice = 0;
	}

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

		_prevClose = 0;
		_entryPrice = 0;

		var ema = new ExponentialMovingAverage { Length = EmaLength };
		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, rsi, atr, ProcessCandle)
			.Start();

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

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

		var close = candle.ClosePrice;

		if (_prevClose == 0 || atrVal <= 0)
		{
			_prevClose = close;
			return;
		}

		if (Position > 0)
		{
			if (close >= _entryPrice + atrVal * 2.5m || close <= _entryPrice - atrVal * 1.5m || close < emaVal)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			if (close <= _entryPrice - atrVal * 2.5m || close >= _entryPrice + atrVal * 1.5m || close > emaVal)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		if (Position == 0)
		{
			if (close > emaVal && _prevClose <= emaVal && rsiVal > 50)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (close < emaVal && _prevClose >= emaVal && rsiVal < 50)
			{
				_entryPrice = close;
				SellMarket();
			}
		}

		_prevClose = close;
	}
}