Ver no GitHub

Estratégia de previsão de mercado

Visão geral

A estratégia Market Predictor é uma adaptação de alto nível do consultor especialista MarketPredictor original MetaTrader. A lógica se concentra em reestimar continuamente o movimento de preços esperado, combinando uma previsão de Monte Carlo com parâmetros estatísticos adaptativos coletados de velas recentes. A estratégia assina velas do período selecionado e processa apenas barras concluídas para evitar sinais prematuros.

Conceitos Básicos

  • Estimativa média adaptativa: A estratégia mantém um preço médio dinâmico (mu) atualizado a partir de uma média móvel simples. Isso reflete a etapa de otimização de parâmetros do consultor especialista original.
  • Amplitude orientada pela volatilidade: O ATR da mesma série de velas controla o coeficiente de amplitude (alpha), mantendo a previsão responsiva aos picos de volatilidade.
  • Projeção de Monte Carlo: Para cada vela concluída, a estratégia executa um número configurável de simulações aleatórias para estimar o preço esperado (P_t1). A previsão é igual à média dos preços simulados.
  • Decisão direcional: As ordens de mercado são enviadas quando a previsão se desvia do último fechamento em mais do que o limite de sigma. A direção da posição é invertida somente depois que a exposição anterior estiver totalmente fechada.

Regras de negociação

  1. Espere a vela terminar e confirme se todos os indicadores estão formados.
  2. Atualize mu com o valor SMA e alpha com a amplitude baseada em ATR.
  3. Realize simulações de Monte Carlo em torno do último preço de fechamento.
  4. Se o preço médio simulado estiver acima de Close + sigma, insira uma posição longa com uma ordem de mercado quando nenhuma posição estiver aberta.
  5. Se o preço médio simulado estiver abaixo de Close - sigma, insira uma posição curta com uma ordem de mercado quando nenhuma posição estiver aberta.
  6. Mantenha a posição até que o sinal oposto seja produzido.

Parâmetros

  • InitialAlpha – Amplitude padrão usada antes de ATR ficar disponível.
  • InitialBeta – Coeficiente de placeholder mantido para compatibilidade com o Expert Advisor original (não utilizado diretamente nos cálculos).
  • InitialGamma – Constante de amortecimento do espaço reservado preservada para consistência da documentação (não usada diretamente).
  • Kappa – Parâmetro de sensibilidade para o conceito de componente sigmóide subjacente. Ele é armazenado para referência e futuras extensões.
  • InitialMu – Preço médio padrão até a formação da média móvel.
  • Sigma – Desvio necessário entre o preço previsto e o último fechamento para acionar entradas no mercado.
  • MonteCarloSimulations – Número de simulações utilizadas para estimar o próximo preço.
  • CandleType – Período da série de velas.

Notas

  • O StockSharp API de alto nível lida com assinaturas de velas, vinculação de indicadores e execução de ordens de mercado.
  • Os comentários no código-fonte explicam cada etapa do processo para facilitar a manutenção.
  • A porta Python é omitida intencionalmente conforme 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();
		}
	}
}