市場予測戦略
概要
Market Predictor 戦略は、元の MetaTrader MarketPredictor エキスパート アドバイザーを高度に適応させたものです。このロジックは、モンテカルロ予測と最近のローソク足から収集した適応統計パラメーターを組み合わせることにより、予想される価格変動を継続的に再推定することに重点を置いています。この戦略は、選択した時間枠のローソク足をサブスクライブし、終了したバーのみを処理して時期尚早のシグナルを回避します。
中心となる概念
- 適応平均推定: この戦略は、単純移動平均から更新された動的平均価格 (
mu) を維持します。これは、元の Expert Advisor のパラメーター最適化ステップを反映しています。 - ボラティリティ主導の振幅: 同じローソク足シリーズの ATR は振幅係数 (
alpha) を制御し、ボラティリティのスパイクに対する予測の応答性を維持します。 - モンテカルロ投影: 完了したキャンドルごとに、ストラテジーは設定可能な数のランダムなシミュレーションを実行して、予想価格 (
P_t1) を推定します。予測は、シミュレーションされた価格の平均と等しくなります。 - 方向性の決定: 予測が最新の終値から
sigmaのしきい値を超えて逸脱した場合、成行注文が送信されます。位置方向は、前の露出が完全に閉じられた後にのみ反転されます。
取引ルール
- ローソク足が終了するのを待ち、すべてのインジケーターが形成されていることを確認します。
muを SMA の値で更新し、alphaを ATR ベースの振幅で更新します。- 最新の終値付近でモンテカルロ シミュレーションを実行します。
- シミュレートされた平均価格が
Close + sigmaを超えている場合は、ポジションがないときに成行注文でロング ポジションを入力してください。 - シミュレートされた平均価格が
Close - sigmaを下回っている場合は、ポジションがないときに成行注文でショート ポジションを入力してください。 - 反対の信号が生成されるまでその位置を保持します。
パラメーター
- InitialAlpha – ATR が使用可能になる前に使用されるデフォルトの振幅。
- InitialBeta – 元の Expert Advisor との互換性のために保持されるプレースホルダー係数 (計算には直接使用されません)。
- InitialGamma – ドキュメントの一貫性のために保存されるプレースホルダーの減衰定数 (直接使用されません)。
- Kappa – 基礎となるシグモイド コンポーネントの概念の感度パラメーター。これは、参照および将来の拡張のために保存されます。
- InitialMu – 移動平均が形成されるまでのデフォルトの平均価格。
- シグマ – 予測価格と市場エントリーをトリガーするための最新終値との間の必要な偏差。
- MonteCarloSimulations – 次の価格を推定するために使用されるシミュレーションの数。
- CandleType – キャンドル シリーズのタイムフレーム。
注意事項
- 高レベルの StockSharp API は、ローソク足のサブスクリプション、指標のバインディング、成行注文の実行を処理します。
- ソース コード内のコメントは、メンテナンスを容易にするためにプロセスの各ステップを説明します。
- Python ポートは、要求に応じて意図的に省略されています。
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();
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class market_predictor_strategy(Strategy):
def __init__(self):
super(market_predictor_strategy, self).__init__()
self._initial_alpha = self.Param("InitialAlpha", 0.1) \
.SetDisplay("Initial Alpha", "Default amplitude before ATR is formed", "Prediction")
self._initial_beta = self.Param("InitialBeta", 0.1) \
.SetDisplay("Initial Beta", "Fractal weight placeholder coefficient", "Prediction")
self._initial_gamma = self.Param("InitialGamma", 0.1) \
.SetDisplay("Initial Gamma", "Fractal damping constant", "Prediction")
self._kappa = self.Param("Kappa", 1.0) \
.SetDisplay("Kappa", "Sigmoid sensitivity parameter", "Prediction")
self._initial_mu = self.Param("InitialMu", 1.0) \
.SetDisplay("Initial Mu", "Fallback mean price", "Prediction")
self._sigma = self.Param("Sigma", 10.0) \
.SetGreaterThanZero() \
.SetDisplay("Sigma", "Deviation threshold for trades", "Trading")
self._monte_carlo_sims = self.Param("MonteCarloSimulations", 1000) \
.SetGreaterThanZero() \
.SetDisplay("Monte Carlo Simulations", "Number of simulations per candle", "Prediction")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for candle subscription", "General")
self._alpha = 0.1
self._mu = 1.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(market_predictor_strategy, self).OnReseted()
self._alpha = float(self._initial_alpha.Value)
self._mu = float(self._initial_mu.Value)
def OnStarted2(self, time):
super(market_predictor_strategy, self).OnStarted2(time)
self._alpha = float(self._initial_alpha.Value)
self._mu = float(self._initial_mu.Value)
self._sma = SimpleMovingAverage()
self._sma.Length = 14
self._atr = AverageTrueRange()
self._atr.Length = 14
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._sma, self._atr, self.process_candle).Start()
def process_candle(self, candle, sma_value, atr_value):
if candle.State != CandleStates.Finished:
return
sma_val = float(sma_value)
atr_val = float(atr_value)
if self._sma.IsFormed:
self._mu = sma_val
else:
self._mu = float(self._initial_mu.Value)
if self._atr.IsFormed and atr_val > 0:
self._alpha = atr_val * 0.1
else:
self._alpha = float(self._initial_alpha.Value)
current_price = float(candle.ClosePrice)
sigma = float(self._sigma.Value)
deviation = sigma * self._alpha if self._alpha > 0 else sigma
if current_price < self._mu - deviation and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif current_price > self._mu + deviation and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
elif self.Position > 0 and current_price >= self._mu:
self.SellMarket()
elif self.Position < 0 and current_price <= self._mu:
self.BuyMarket()
def CreateClone(self):
return market_predictor_strategy()