GitHub で見る

Three Neural Networks戦略

概要

この戦略は、MetaTraderエキスパートアドバイザー「Three neural networks」のStockSharp高レベルポート版です。StockSharpのローソク足サブスクリプションAPIを通じて完全に動作し、元の実装の3つのニューラル層をエミュレートするために組み込みのSmoothedMovingAverageインジケーターを再利用します。戦略は3つの異なる時間軸(H1、H4、D1)で動作し、各平滑化平均の傾きを分析して集合的な取引決定を導出します。

ワークフロー

  1. 戦略が開始すると、H1、H4、D1時間軸のローソク足をサブスクライブし、中央値価格を使用する平滑化移動平均をバインドします。これはMetaTraderのiMA(..., MODE_SMMA, PRICE_MEDIAN)呼び出しを反映します。
  2. 各時間軸は設定されたシフトを尊重するローリング履歴を維持します。4つのシフトされた値が利用可能になると、アルゴリズムはEAとまったく同じ重み付き差分公式を使用して3つのニューラル出力を計算し、結果を小数点以下4桁に丸めます。
  3. H1ローソク足が終了した後、戦略はニューラル出力を組み合わせます:
    • 3つの値すべてが正の場合 → ロングポジションを開くか維持する。
    • H1出力が正でH4とD1出力が負の場合 → ショートポジションを開くか維持する。
  4. ポジションは固定ロットまたはリスクパーセンテージモデルでサイズ設定されます。リスクモードでは、戦略はポートフォリオ価値のVolumeOrRiskパーセントを割り当て、現在の価格で割ってボリュームに変換します。
  5. 保護ロジックはEAのコントロールを再現します:ポジション方向が変わった直後にストップロスとテイクプロフィットがローカル変数に設定され、価格がトレーリング距離と設定されたステップを超えて進んだ場合、H1バーがクローズするたびにトレーリングストップが調整されます。
  6. 各完成H1ローソク足は最初に現在のストップロスまたはテイクプロフィットのレベルが違反されているかを確認し、必要に応じて市場注文でポジションをクローズします。オプションの詳細ログは元のInpPrintLogフラグを再現します。

パラメーター

名前 デフォルト 説明
StopLossPips 50 pipsでの保護ストップ距離。ストップロスを無効にするには0に設定。
TakeProfitPips 50 pipsでのテイクプロフィット距離。ターゲットを無効にするには0に設定。
TrailingStopPips 15 現在の価格とトレーリングストップの間の距離。
TrailingStepPips 5 トレーリングストップを再度移動する前に必要な最小改善。
ManagementMode RiskPercent ボリュームサイジングモード。FixedLotは値を直接ロットサイズとして使用;RiskPercentはポートフォリオ資産のパーセンテージとして使用。
VolumeOrRisk 1 資金管理モードに応じたロットサイズまたはリスクパーセンテージ。
H1Period, H1Shift 2, 5 H1平滑化移動平均の期間とシフト。
H4Period, H4Shift 2, 5 H4平滑化移動平均の期間とシフト。
D1Period, D1Shift 2, 5 D1平滑化移動平均の期間とシフト。
P1, P2, P3 0.1 3つのH1ニューラルコンポーネントに適用される重み。
Q1, Q2, Q3 0.1 3つのH4ニューラルコンポーネントに適用される重み。
K1, K2, K3 0.1 3つのD1ニューラルコンポーネントに適用される重み。
EnableDetailedLog false EAのログ出力を反映する詳細な診断メッセージを有効にします。

リスク管理

  • ストップロスとテイクプロフィットのレベルは、元のコードと同一の自動3/5桁調整を持つ検出されたpipサイズを使用してpip距離から変換され、ポジション方向が変わった直後に適用されます。
  • トレーリングロジックはMetaTraderの条件に従います:価格がエントリーからTrailingStopPips + TrailingStepPips以上離れると有効になり、改善が設定されたステップを超えた場合のみ進みます。
  • 高レベルAPIではサーバー側のストップ/リミット注文が利用できないため、すべてのエグジットはClosePosition()市場注文で実行されます。

備考

  • EAのフリーズ/ストップレベルの検証はStockSharpでは利用できないため、戦略はVolumeStepVolumeMinVolumeMaxを通じたpipサイズ変換とボリューム正規化のみに依存します。
  • リスクベースのサイジングは現在のポートフォリオ価値とエントリー価格を使用してMetaTraderのマージンチェックを近似します。これはブローカー固有のマージン計算機に依存せずに一般的な動作を反映します。
  • オプションのログはMetaTraderのInpPrintLogに類似したステップバイステップ診断のためにEnableDetailedLogを通じて有効にできます。
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;

public class ThreeNeuralNetworksStrategy : 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 ThreeNeuralNetworksStrategy()
	{
		_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;
	}
}