Ver en GitHub

Estrategia de predicción del mercado

Descripción general

La estrategia Market Predictor es una adaptación de alto nivel del asesor experto original MetaTrader MarketPredictor. La lógica se centra en reestimar continuamente el movimiento de precios esperado combinando un pronóstico de Monte Carlo con parámetros estadísticos adaptativos recopilados de velas recientes. La estrategia se suscribe a velas del período de tiempo seleccionado y procesa solo barras terminadas para evitar señales prematuras.

Conceptos básicos

  • Estimación de la media adaptativa: La estrategia mantiene un precio medio dinámico (mu) actualizado a partir de una media móvil simple. Esto refleja el paso de optimización de parámetros del asesor experto original.
  • Amplitud impulsada por la volatilidad: El ATR de la misma serie de velas controla el coeficiente de amplitud (alpha), lo que mantiene la predicción sensible a los picos de volatilidad.
  • Proyección de Monte Carlo: Para cada vela completada, la estrategia ejecuta un número configurable de simulaciones aleatorias para estimar el precio esperado (P_t1). El pronóstico es igual al promedio de los precios simulados.
  • Decisión direccional: Las órdenes de mercado se envían cuando el pronóstico se desvía del último cierre en más del umbral sigma. La dirección de la posición se invierte sólo después de que la exposición anterior esté completamente cerrada.

Reglas de trading

  1. Espere a que termine la vela y confirme que todos los indicadores estén formados.
  2. Actualice mu con el valor SMA y alpha con la amplitud basada en ATR.
  3. Realice simulaciones de Monte Carlo en torno al último precio de cierre.
  4. Si el precio promedio simulado es superior a Close + sigma, ingrese una posición larga con una orden de mercado cuando no haya ninguna posición abierta.
  5. Si el precio promedio simulado es inferior a Close - sigma, ingrese una posición corta con una orden de mercado cuando no haya ninguna posición abierta.
  6. Mantenga la posición hasta que se produzca la señal opuesta.

Parámetros

  • InitialAlpha: amplitud predeterminada utilizada antes de que ATR esté disponible.
  • InitialBeta: coeficiente de marcador de posición mantenido por compatibilidad con el Asesor Experto original (no se utiliza directamente en los cálculos).
  • InitialGamma: constante de amortiguación del marcador de posición conservada para mantener la coherencia de la documentación (no se usa directamente).
  • Kappa: parámetro de sensibilidad para el concepto del componente sigmoideo subyacente. Se almacena para referencia y futuras extensiones.
  • InitialMu – Precio medio predeterminado hasta que se forma la media móvil.
  • Sigma: desviación requerida entre el precio previsto y el último cierre para activar las entradas al mercado.
  • MonteCarloSimulaciones: número de simulaciones utilizadas para estimar el próximo precio.
  • CandleType: período de tiempo de la serie de velas.

Notas

  • El StockSharp API de alto nivel maneja las suscripciones de velas, la vinculación de indicadores y la ejecución de órdenes de mercado.
  • Los comentarios en el código fuente explican cada paso del proceso para facilitar el mantenimiento.
  • El puerto de Python se omite intencionalmente según lo solicitado.
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>
/// Strategy that adapts the MarketPredictor expert advisor logic to StockSharp.
/// It recalculates statistical parameters from finished candles and
/// runs a Monte Carlo forecast to determine directional bias.
/// </summary>
public class MarketPredictorStrategy : Strategy
{
	private readonly StrategyParam<decimal> _initialAlpha;
	private readonly StrategyParam<decimal> _initialBeta;
	private readonly StrategyParam<decimal> _initialGamma;
	private readonly StrategyParam<decimal> _kappa;
	private readonly StrategyParam<decimal> _initialMu;
	private readonly StrategyParam<decimal> _sigma;
	private readonly StrategyParam<int> _monteCarloSimulations;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _alpha;
	private decimal _mu;

	/// <summary>
	/// Default amplitude used before ATR values become available.
	/// </summary>
	public decimal InitialAlpha
	{
		get => _initialAlpha.Value;
		set => _initialAlpha.Value = value;
	}

	/// <summary>
	/// Placeholder coefficient retained from the original expert advisor.
	/// </summary>
	public decimal InitialBeta
	{
		get => _initialBeta.Value;
		set => _initialBeta.Value = value;
	}

	/// <summary>
	/// Placeholder damping constant retained for documentation purposes.
	/// </summary>
	public decimal InitialGamma
	{
		get => _initialGamma.Value;
		set => _initialGamma.Value = value;
	}

	/// <summary>
	/// Sensitivity parameter associated with the sigmoid concept.
	/// </summary>
	public decimal Kappa
	{
		get => _kappa.Value;
		set => _kappa.Value = value;
	}

	/// <summary>
	/// Default mean price used until the moving average is formed.
	/// </summary>
	public decimal InitialMu
	{
		get => _initialMu.Value;
		set => _initialMu.Value = value;
	}

	/// <summary>
	/// Required deviation between forecast and latest close to trigger entries.
	/// </summary>
	public decimal Sigma
	{
		get => _sigma.Value;
		set => _sigma.Value = value;
	}

	/// <summary>
	/// Number of Monte Carlo simulations used to forecast the next price.
	/// </summary>
	public int MonteCarloSimulations
	{
		get => _monteCarloSimulations.Value;
		set => _monteCarloSimulations.Value = value;
	}

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

	/// <summary>
	/// Initializes parameters with defaults matching the original EA configuration.
	/// </summary>
	public MarketPredictorStrategy()
	{
		_initialAlpha = Param(nameof(InitialAlpha), 0.1m)
			.SetDisplay("Initial Alpha", "Default amplitude before ATR is formed", "Prediction")
			
			.SetOptimize(0.05m, 0.5m, 0.05m);

		_initialBeta = Param(nameof(InitialBeta), 0.1m)
			.SetDisplay("Initial Beta", "Fractal weight placeholder", "Prediction")
			;

		_initialGamma = Param(nameof(InitialGamma), 0.1m)
			.SetDisplay("Initial Gamma", "Fractal damping placeholder", "Prediction")
			;

		_kappa = Param(nameof(Kappa), 1.0m)
			.SetDisplay("Kappa", "Sigmoid sensitivity placeholder", "Prediction")
			;

		_initialMu = Param(nameof(InitialMu), 1.0m)
			.SetDisplay("Initial Mu", "Fallback mean price", "Prediction")
			
			.SetOptimize(0.5m, 2.0m, 0.25m);

		_sigma = Param(nameof(Sigma), 10.0m)
			.SetGreaterThanZero()
			.SetDisplay("Sigma", "Deviation threshold for trades", "Trading")
			
			.SetOptimize(1.0m, 30.0m, 1.0m);

		_monteCarloSimulations = Param(nameof(MonteCarloSimulations), 1000)
			.SetGreaterThanZero()
			.SetDisplay("Monte Carlo Simulations", "Number of simulations per candle", "Prediction")
			
			.SetOptimize(100, 2000, 100);

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for candle subscription", "General");
	}

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

		_alpha = InitialAlpha;
		_mu = InitialMu;
	}

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

		_alpha = InitialAlpha;
		_mu = InitialMu;

		var sma = new SimpleMovingAverage { Length = 14 };
		var atr = new AverageTrueRange { Length = 14 };

		var subscription = SubscribeCandles(CandleType);

		subscription
			.Bind(sma, atr, (candle, smaValue, atrValue) => ProcessCandle(candle, sma, atr, smaValue, atrValue))
			.Start();
	}

	private void ProcessCandle(ICandleMessage candle, SimpleMovingAverage sma, AverageTrueRange atr, decimal smaValue, decimal atrValue)
	{
		// Process only finished candles to avoid premature trading decisions.
		if (candle.State != CandleStates.Finished)
			return;

		// Confirm that the strategy is allowed to trade and all prerequisites are met.
		// Update adaptive mean when the moving average is formed.
		if (sma.IsFormed)
		{
			_mu = smaValue;
		}
		else
		{
			_mu = InitialMu;
		}

		// Adjust amplitude based on volatility when ATR values are reliable.
		if (atr.IsFormed && atrValue > 0m)
		{
			_alpha = atrValue * 0.1m;
		}
		else
		{
			_alpha = InitialAlpha;
		}

		var currentPrice = candle.ClosePrice;
		ExecuteTrade(currentPrice);
	}

	private void ExecuteTrade(decimal currentPrice)
	{
		var deviation = _alpha > 0 ? Sigma * _alpha : Sigma;

		// Mean-reversion: buy when significantly below mean, sell when significantly above
		if (currentPrice < _mu - deviation && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (currentPrice > _mu + deviation && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}
		// Exit when price returns to mean
		else if (Position > 0 && currentPrice >= _mu)
		{
			SellMarket();
		}
		else if (Position < 0 && currentPrice <= _mu)
		{
			BuyMarket();
		}
	}
}