Ver en GitHub

Estrategia JK BullP AutoTrader

Descripción general

JK BullP AutoTrader es un asesor experto que sigue el impulso escrito originalmente para MetaTrader 4. Supervisa el poder de Elder Bulls indicador y reacciona cuando la presión alcista se debilita o se vuelve negativa. El puerto StockSharp mantiene la lógica sencilla del original al tiempo que proporciona parámetros explícitos, gestión de seguimiento detallada y controles de riesgo compatibles con la plataforma.

Lógica comercial

  1. La estrategia se suscribe a una serie de velas configurables (velas de 1 hora por defecto) y calcula una exponencial de 13 períodos. media móvil (EMA) para replicar la línea de base de Bulls Power.
  2. Para cada vela completa, Bulls Power se mide como la diferencia entre el máximo de la vela y el valor EMA.
  3. Se comparan dos lecturas consecutivas de Bulls Power:
    • Si el valor anterior está por encima del valor más reciente y el valor más reciente sigue siendo positivo, la estrategia abre una posición corta.
    • Si el último valor de Bulls Power cae por debajo de cero, la estrategia abre una posición larga.
  4. Solo puede haber una posición activa a la vez, reflejando al experto original MQL que bloqueaba nuevas órdenes mientras las operaciones estaban abiertas.

Gestión de riesgos y salidas.

  • Stop-loss/take-profit inicial: Las distancias se configuran en pips y se convierten a unidades de precio utilizando el paso del precio del valor. Ambas protecciones se habilitan a través del asistente StartProtection de StockSharp, manteniendo el comportamiento cerca de las entradas de MetaTrader.
  • Parada dinámica: Una vez que el beneficio flotante excede la distancia de seguimiento especificada, el nivel de parada se mueve vela por vela. En lugar de modificar las órdenes stop existentes (como en MetaTrader), el puerto emite una orden de mercado para salir de la posición cuando el precio cierra más allá del umbral final. Esto garantiza salidas oportunas incluso cuando las órdenes de protección no sean respaldadas por el lugar.

Parámetros

Nombre Descripción Predeterminado
OrderVolume Tamaño de orden de mercado utilizado para las entradas. 8.5
TakeProfitPips Distancia de obtención de beneficios en pips (convertida a unidades de precio). 500
StopLossPips Distancia de stop-loss en pips. 20
TrailingStopPips Distancia de beneficio en pips que activa y mantiene el trailing stop. 10
EmaPeriod Longitud del EMA utilizado por el cálculo de Bulls Power. 13
CandleType Tipo de datos de velas que impulsan la estrategia (plazo de tiempo predeterminado de 1 hora). velas de 1 hora

Notas de implementación

  • Las entradas no utilizadas (Patr, Prange, Kstop, kts, Vts) del script original se omitieron intencionalmente porque tenían ningún efecto en la lógica MetaTrader.
  • Las distancias de pip dependen del instrumento PriceStep. Si los datos del paso no están disponibles, se utiliza un valor de 1 como valor predeterminado conservador.
  • La estrategia utiliza StockSharp de alto nivel Bind API, procesa solo velas terminadas y mantiene el estado interno (_previousBullsPower) para que coincida con los cálculos basados en turnos de MT4.
  • La lógica de seguimiento se restablece automáticamente después de cada salida para evitar niveles de parada obsoletos cuando se abre una nueva posición.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// JK BullP AutoTrader: RSI momentum with EMA filter and ATR stops.
/// </summary>
public class JkBullPAutoTraderStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _emaLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevRsi;
	private decimal _entryPrice;

	public JkBullPAutoTraderStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");
		_rsiLength = Param(nameof(RsiLength), 13)
			.SetDisplay("RSI Length", "RSI period.", "Indicators");
		_emaLength = Param(nameof(EmaLength), 20)
			.SetDisplay("EMA Length", "Trend filter.", "Indicators");
		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
	public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
	public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }

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

		_prevRsi = 0; _entryPrice = 0;
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevRsi = 0; _entryPrice = 0;
		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var ema = new ExponentialMovingAverage { Length = EmaLength };
		var atr = new AverageTrueRange { Length = AtrLength };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ema, atr, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, ema); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal emaVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished) return;
		if (_prevRsi == 0 || atrVal <= 0) { _prevRsi = rsiVal; return; }
		var close = candle.ClosePrice;

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

		if (Position == 0)
		{
			if (rsiVal > 55 && _prevRsi <= 55 && close > emaVal) { _entryPrice = close; BuyMarket(); }
			else if (rsiVal < 45 && _prevRsi >= 45 && close < emaVal) { _entryPrice = close; SellMarket(); }
		}
		_prevRsi = rsiVal;
	}
}