Ver en GitHub

Estrategia PricerEA

Descripción general

La Estrategia PricerEA recrea el comportamiento del MetaTrader 4 experto "PricerEA v1.0" usando la API de alto nivel de StockSharp. Coloca hasta cuatro órdenes pendientes (stop de compra, stop de venta, límite de compra y límite de venta) a niveles de precios definidos manualmente. Una vez cualquiera orden pendiente se completa, la estrategia adjunta órdenes protectoras de stop-loss y take-profit, habilitando opcionalmente un trailing stop y ajuste de equilibrio para seguir el Asesor Experto original.

como funciona

  1. Órdenes pendientes: la estrategia lee los niveles de precios absolutos de las entradas y envía únicamente las órdenes pendientes correspondientes. una vez al inicio. La caducidad opcional se puede configurar en minutos.
  2. Selección de volumen: los usuarios pueden mantener el tamaño de lote manual fijo o cambiar al modo automático desde donde se deriva el volumen. el saldo de la cartera y el análogo del factor de riesgo MT4.
  3. Protección: después de completar una orden de entrada, la estrategia crea órdenes de limitación de pérdidas y toma de ganancias a la distancia configurada. (expresado en puntos de precio). Cuando se habilitan tanto el seguimiento como el punto de equilibrio, la parada sigue las condiciones originales MQL: es se mueve solo después de que el precio cubre la distancia de equilibrio más la parada inicial.
  4. Mantenimiento de pedidos: los pedidos pendientes se cancelan automáticamente cuando expira su vida útil o cuando se detiene la estrategia.

Parámetros

Parámetro Descripción
BuyStopPrice, SellStopPrice, BuyLimitPrice, SellLimitPrice Precios absolutos de las correspondientes órdenes pendientes. Un valor de 0 deshabilita el pedido.
TakeProfitPoints Distancia desde el precio de entrada hasta la orden de toma de ganancias, medida en puntos de precio (Security.PriceStep).
StopLossPoints Distancia desde el precio de entrada hasta la orden de stop-loss, también medida en puntos de precio.
EnableTrailingStop Habilita la lógica del trailing stop.
TrailingStepPoints Se requiere un movimiento mínimo (en puntos) antes de mover el tope móvil.
EnableBreakEven Habilita la regla de equilibrio que eleva el stop por encima/por debajo de la entrada después de obtener ganancias suficientes.
BreakEvenTriggerPoints Se requiere ganancia adicional (puntos) antes de que se mueva el tope para alcanzar el punto de equilibrio.
PendingExpiryMinutes Vida útil de las órdenes pendientes en minutos. 0 los mantiene vivos hasta que se llenen o se cancelen manualmente.
VolumeMode Elige entre volumen manual y dimensionamiento automático.
RiskFactor Multiplicador de riesgo utilizado por el dimensionamiento automático (refleja la entrada MQL).
ManualVolume Tamaño de lote fijo utilizado cuando VolumeMode se establece en Manual.

Diferencias vs. la versión MT4

  • El cálculo automático del volumen utiliza el saldo de la cartera StockSharp y el multiplicador del contrato de valores. Diferentes corredores Puede utilizar fórmulas distintas, por lo que el valor resultante puede diferir ligeramente de MetaTrader.
  • Las órdenes de protección se realizan a través de StockSharp ayudantes y respetan el paso de volumen del lugar, el volumen mínimo y máximo.
  • La caducidad se implementa dentro de la estrategia (MetaTrader depende de la caducidad de la orden del lado del servidor).

Notas de uso

  • Configura los niveles de precios antes de iniciar la estrategia. Valores iguales a cero dejan inhabilitado el orden correspondiente.
  • Para imitar la lógica de "Dígitos" de MT4, los parámetros basados en puntos operan en Security.PriceStep unidades.
  • Combine la estrategia con la cartera y las herramientas de registro de StockSharp para monitorear las órdenes pendientes y las paradas de protección.
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// PricerEA strategy: Bollinger Bands mean reversion with RSI filter.
/// Buys at lower band when RSI is oversold, sells at upper band when overbought.
/// </summary>
public class PricerEaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _bbPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<int> _signalCooldownCandles;
	private int _candlesSinceTrade;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int BbPeriod { get => _bbPeriod.Value; set => _bbPeriod.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public PricerEaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_bbPeriod = Param(nameof(BbPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "ATR period for adaptive band distance", "Indicators");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 8)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_candlesSinceTrade = SignalCooldownCandles;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_candlesSinceTrade = SignalCooldownCandles;
		var sma = new SimpleMovingAverage { Length = BbPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var atr = new AverageTrueRange { Length = AtrPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(sma, rsi, atr, ProcessCandle).Start();
	}

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

		var close = candle.ClosePrice;
		var bandDistance = atr * 2.5m;

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		if (Position > 0 && (close >= sma || rsi >= 50))
		{
			SellMarket();
			_candlesSinceTrade = 0;
		}
		else if (Position < 0 && (close <= sma || rsi <= 50))
		{
			BuyMarket();
			_candlesSinceTrade = 0;
		}
		else if (Position == 0 && _candlesSinceTrade >= SignalCooldownCandles && close <= sma - bandDistance && rsi < 30)
		{
			BuyMarket();
			_candlesSinceTrade = 0;
		}
		else if (Position == 0 && _candlesSinceTrade >= SignalCooldownCandles && close >= sma + bandDistance && rsi > 70)
		{
			SellMarket();
			_candlesSinceTrade = 0;
		}
	}
}