Auf GitHub ansehen

Marktvorhersagestrategie

Überblick

Die Market Predictor-Strategie ist eine umfassende Adaption des ursprünglichen MetaTrader MarketPredictor-Expertenberaters. Die Logik konzentriert sich auf die kontinuierliche Neuschätzung der erwarteten Preisbewegung durch die Kombination einer Monte-Carlo-Prognose mit adaptiven statistischen Parametern, die aus aktuellen Kerzen gewonnen werden. Die Strategie abonniert Kerzen des ausgewählten Zeitrahmens und verarbeitet nur fertige Balken, um vorzeitige Signale zu vermeiden.

Kernkonzepte

  • Adaptive Mittelwertschätzung: Die Strategie verwaltet einen dynamischen Durchschnittspreis (mu), der anhand eines einfachen gleitenden Durchschnitts aktualisiert wird. Dies spiegelt den Parameteroptimierungsschritt des ursprünglichen Expert Advisors wider.
  • Volatilitätsgesteuerte Amplitude: Der ATR derselben Kerzenserie steuert den Amplitudenkoeffizienten (alpha) und sorgt dafür, dass die Vorhersage auf Volatilitätsspitzen reagiert.
  • Monte-Carlo-Projektion: Für jede abgeschlossene Kerze führt die Strategie eine konfigurierbare Anzahl zufälliger Simulationen durch, um den erwarteten Preis (P_t1) zu schätzen. Die Prognose entspricht dem Durchschnitt der simulierten Preise.
  • Richtungsentscheidung: Marktaufträge werden gesendet, wenn die Prognose um mehr als den Schwellenwert sigma vom letzten Schlusskurs abweicht. Die Positionsrichtung wird erst umgekehrt, nachdem die vorherige Belichtung vollständig geschlossen wurde.

Handelsregeln

  1. Warten Sie, bis die Kerze fertig ist, und bestätigen Sie, dass alle Indikatoren gebildet sind.
  2. Aktualisieren Sie mu mit dem Wert SMA und alpha mit der ATR-basierten Amplitude.
  3. Führen Sie Monte-Carlo-Simulationen rund um den letzten Schlusskurs durch.
  4. Wenn der durchschnittliche simulierte Preis über Close + sigma liegt, geben Sie eine Long-Position mit einer Marktorder ein, wenn keine Position offen ist.
  5. Wenn der durchschnittliche simulierte Preis unter Close - sigma liegt, geben Sie eine Short-Position mit einer Marktorder ein, wenn keine Position offen ist.
  6. Halten Sie die Position, bis das entgegengesetzte Signal erzeugt wird.

Parameter

  • InitialAlpha – Standardamplitude, die verwendet wird, bevor ATR verfügbar wird.
  • InitialBeta – Platzhalterkoeffizient, der aus Kompatibilitätsgründen mit dem ursprünglichen Expert Advisor beibehalten wird (wird nicht direkt in den Berechnungen verwendet).
  • InitialGamma – Platzhalter-Dämpfungskonstante, die aus Gründen der Dokumentationskonsistenz beibehalten wird (nicht direkt verwendet).
  • Kappa – Empfindlichkeitsparameter für das zugrunde liegende Sigmoid-Komponentenkonzept. Es wird zu Referenzzwecken und für zukünftige Erweiterungen gespeichert.
  • InitialMu – Standardmittelpreis bis zur Bildung des gleitenden Durchschnitts.
  • Sigma – Erforderliche Abweichung zwischen dem prognostizierten Preis und dem letzten Schlusskurs, um Markteintritte auszulösen.
  • MonteCarloSimulations – Anzahl der Simulationen, die zur Schätzung des nächsten Preises verwendet werden.
  • CandleType – Zeitrahmen der Kerzenserie.

Notizen

  • Das übergeordnete StockSharp API verwaltet Kerzenabonnements, Indikatorbindung und Marktauftragsausführung.
  • Kommentare im Quellcode erläutern jeden Schritt des Prozesses, um die Wartung zu erleichtern.
  • Der Python-Port wird wie gewünscht bewusst weggelassen.
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();
		}
	}
}