Ver en GitHub

Estrategia de Day Trading PAMXA

Descripción

La estrategia Day Trading PAMXA reproduce el asesor experto de MetaTrader 5 que combina reversiones de momentum del Awesome Oscillator de Bill Williams con un filtro estocástico. El port de StockSharp conserva el diseño multitemporal original:

  • El bucle de decisión principal se ejecuta en el marco temporal de Velas de señal (por defecto 1 hora).
  • El Awesome Oscillator se evalúa en un marco temporal separado de Velas AO (por defecto 1 día) para obtener momentum de marco temporal superior.
  • El oscilador estocástico utiliza su propio marco temporal de Velas estocásticas (por defecto 1 hora) para que los niveles %K/%D estén alineados con los ajustes originales.

La estrategia mantiene como máximo una posición a la vez. Cuando aparece una configuración alcista, primero cubre cualquier corto activo antes de entrar en largo, y viceversa para configuraciones bajistas.

Lógica de entrada

  1. Calcular los valores de Awesome Oscillator más recientes terminados en el marco temporal AO.
  2. Calcular los valores más recientes terminados de %K y %D del oscilador estocástico en el marco temporal estocástico.
  3. En cada vela de señal terminada:
    • Configuración alcista: se activa cuando la barra AO anterior estaba por debajo de cero y la última barra cerró por encima de cero (reversión de momentum) mientras %K o %D está por debajo del umbral Nivel estocástico bajo (condición de sobreventa). Cualquier corto abierto se cubre y se abre un nuevo largo si no queda posición.
    • Configuración bajista: se activa cuando la barra AO anterior estaba por encima de cero y la última barra cerró por debajo de cero mientras %K o %D está por encima del umbral Nivel estocástico alto (condición de sobrecompra). Cualquier largo abierto se cierra y, si está plano, se abre una nueva posición corta.

Salida y gestión de riesgo

  • Un stop-loss y take-profit basados en pips se adjuntan en la entrada. Cuando el mínimo de la vela (para largos) o el máximo (para cortos) supera el nivel de stop, la posición se liquida inmediatamente. La misma lógica aplica al objetivo de beneficio.
  • Un trailing stop opcional se activa cuando el precio se ha movido Trailing Stop + Trailing Step pips a favor de la posición. Para largos el stop sigue el máximo más alto menos la distancia de trailing; para cortos sigue el mínimo más bajo más la distancia de trailing. El ajuste del trailing ocurre solo cuando el movimiento supera el paso de trailing, replicando el comportamiento original del EA.
  • La gestión monetaria puede operar en dos modos:
    • FixedVolume: usa el parámetro Order Volume directamente.
    • RiskPercent: calcula el volumen de modo que el porcentaje configurado del valor del portafolio se perdería si se alcanza el stop-loss. El cálculo usa la distancia de stop en pips y redondea al paso de volumen más cercano.
  • La estrategia nunca hace pirámide – una vez que existe una posición, la próxima señal opuesta la aplanará antes de considerar cualquier nueva entrada.

Parámetros

Parámetro Descripción
Stop Loss Distancia de stop-loss en pips. Cero desactiva el stop protector.
Take Profit Distancia de take-profit en pips. Cero desactiva el objetivo de beneficio.
Trailing Stop Distancia de activación del trailing stop en pips. Cero desactiva el trailing.
Trailing Step Pips adicionales requeridos antes de que el trailing stop avance. Debe ser positivo cuando el trailing está activado.
Money Mode Selecciona entre dimensionamiento FixedVolume y RiskPercent.
Money Value Interpretado como tamaño de lote con volumen fijo, o como porcentaje de riesgo con dimensionamiento basado en riesgo.
Order Volume Volumen base usado cuando Money Mode es FixedVolume.
Stochastic %K Longitud del periodo de cálculo estocástico %K.
Stochastic %D Longitud de suavizado para la línea estocástica %D.
Stochastic Slow Factor de suavizado final aplicado al oscilador estocástico.
Level Up Umbral estocástico superior que habilita entradas cortas.
Level Down Umbral estocástico inferior que habilita entradas largas.
Signal Candles Marco temporal que impulsa el bucle principal de trading.
Stochastic Candles Marco temporal que alimenta el oscilador estocástico.
AO Candles Marco temporal que alimenta el Awesome Oscillator.
AO Fast / AO Slow Períodos para las medias móviles internas del Awesome Oscillator.

Notas de implementación

  • El cálculo del valor del pip emula la lógica de MetaTrader: cuando el instrumento usa 3 o 5 decimales, un pip equivale a diez pasos de precio; de lo contrario equivale a un paso de precio.
  • El oscilador estocástico de StockSharp no expone una selección dedicada de "campo de precio"; el port usa el cálculo basado en cierre predeterminado mientras conserva los parámetros de suavizado configurables.
  • El manejo del trailing stop se implementa como una verificación virtual en los máximos/mínimos de las velas. Esto replica los ajustes de stop del lado servidor realizados en MetaTrader sin registrar órdenes de stop explícitas.
  • El código se suscribe a todos los marcos temporales de velas requeridos a través de GetWorkingSecurities, permitiendo al motor solicitar datos para los marcos temporales de señal, estocástico y AO concurrentemente.
  • Los comentarios en inglés documentan las decisiones de flujo de control más importantes para un mantenimiento más fácil.

Consejos de uso

  • Alinee el marco temporal de Signal Candles con el marco temporal en el que planea hacer backtesting o trading. Mantenga Stochastic Candles y AO Candles iguales a los valores predeterminados originales cuando quiera replicar exactamente el experto MQL5.
  • Al cambiar a dimensionamiento RiskPercent, asegúrese de que la distancia de stop-loss sea distinta de cero; de lo contrario la estrategia cae de vuelta a Order Volume.
  • La configuración de trailing predeterminada refleja el EA original (trailing stop de 25 pips con paso de 5 pips). Establezca Trailing Stop en cero si prefiere un stop-loss estático.
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>
/// Day Trading PAMXA strategy using EMA crossover.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class DayTradingPamxaStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public DayTradingPamxaStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}