GitHub で見る

数独 UI 戦略

概要

この戦略は、MetaTrader 5 スクリプト SudokuUI.mq5 の StockSharp 移植です。オリジナルの MQL プログラムは、パズルの生成、シャッフル、自動更新を制御するパラメーターを備えたグラフィカルな Sudoku パズル インターフェイスを公開します。 StockSharp 環境はインタラクティブなチャート ウィジェットではなく自動取引に重点を置いているため、ポートは基礎となる概念をパズル統計によって駆動されるグリッドベースの平均回帰戦略に再利用します。

Sudoku ボードは、9x9 の数字の行列として解釈されます。列平均は、単純移動平均 (SMA) を中心とした対称偏差しきい値を定義します。これらの数独由来のレベルを超えて価格が SMA から逸脱すると、戦略は反対方向のポジションに入り、平均値への戻りを求めます。ニュートラルゾーンに戻るとポジションが閉じられ、ボードをリセットする元のツールの機能を模倣します。

取引ロジック

  1. パズルの準備

    • この戦略では、ファイルまたは生の文字列から 81 桁の Sudoku 仕様をロードできます。数字以外の文字は無視され、ゼロはスキップされ、数独の数字の要件に一致します。
    • 有効なパズルが提供されない場合、数字プールを繰り返しシャッフルすることによって擬似ランダム ボードが生成されます。このロジックは、トレーダーが再現可能なレイアウトを取得できるように、MQL バージョンで公開された シャッフル シードと 合成 シードの両方を尊重します。
    • 統計を計算する前に、特定の数字を削除できます。これは、特定のラベルを非表示にする元の GUI オプションを模倣し、アクティブなグリッドを縮小する簡単な方法を提供します。
  2. レベルの構造

    • 各パズル列は、消去ステップ後に平均化されます。平均は [-1, 1] の範囲に正規化され、ThresholdRange を乗算され、SMA 値の分数で表される価格偏差レベルが得られます。
    • パズルが SMA の片側にのみ値を生成する場合、フォールバックの負または正のレベルが挿入され、長いトリガーと短いトリガーの両方が存在することが保証されます。
  3. 信号生成

    • この戦略は、構成されたローソク足タイプをサブスクライブし、それを SMA インジケーターにバインドします。 StockSharp のベスト プラクティスに従って、完成したキャンドルのみが処理されます。
    • 終値と SMA の間のパーセンテージ距離が最もマイナスのレベルを下回ると、(ショートをフラット化した後) ロングポジションがオープンされます。最高のプラスレベルを超えると、同様にショートポジションがオープンします。
    • 偏差ゼロ付近のニュートラルバンド (NeutralBand) は、フラット露出を強制します。これは、パズルの状態を自動的に調整する Sudoku の「アシスタント」に代わるものです。
  4. 自動更新

    • EnableAutoUpdatetrue に設定すると、毎取引日の開始時に数独グリッドが再生成されます。シャッフル シード、除外設定、およびシャッフル カウントはすべて、再計算されたしきい値に影響を与え、動的でありながら再現可能なグリッドを提供します。

パラメーター

パラメータ 説明
PuzzleDefinition レベルの計算に使用される数独パズルを説明するファイル パスまたはインライン数字。
ShufflingRandomSeed パズル生成の主要シード。 -1 は取引日からシードを取得します。
CompositionRandomSeed 代替レイアウトを作成するためにシャッフル プロセスを混乱させる二次シード。
ShufflingCycles 桁プールに適用される追加のシャッフル パスの数。値を大きくすると、よりランダム化されたボードが作成されます。
EliminateLabel 平均を計算する前に、数字 (1 ~ 9) がボードから削除されます。 0 はすべての数字を保持します。
EnableAutoUpdate 取引日が変わったらパズルレベルを再構築します。
SmaPeriod 復帰アンカーとして使用される SMA インジケーターの長さ。
ThresholdRange パズルによって生成される最大絶対偏差 (価格の分数として表されます)。
NeutralBand 価格が再びそこに入るときにポジションの平坦化を引き起こす偏差ゾーン。
Volume 市場参入のための注文量。
CandleType インジケーターの更新に使用されるキャンドルのサブスクリプション。

使用上の注意

  • この戦略は完全に形成されたローソク足にのみ反応し、ゼロ価格を無視するため、データプロバイダー全体で安定した動作が保証されます。
  • MetaTrader バージョンの Sudoku ボードを正確に再現するには、81 文字の数字列 (ゼロを除く) またはそのような数字を含むテキスト ファイルを提供します。
  • 固定グリッドが必要な場合は、EnableAutoUpdate を無効にし、明示的なシードを設定します。このオプションを有効にすると、ボードとユーザーのアクションの同期を維持する MQL の「自動アシスタント」が反映されます。
  • しきい値は列の統計から導出されます。非対称パズルの場合は、売買範囲のバランスを維持するために、支配的な数字を削除することを検討してください。

オリジナル脚本との違い

  • すべてのユーザー インターフェイス機能 (ダイアログ ウィンドウ、ボタン、チャート イベント) が削除されます。機能的に等価なものは戦略パラメーターとして公開されます。
  • 数独パズルを手動で解く代わりに、ボードはアルゴリズムの取引レベルに影響を与えます。同じランダム性制御により、それらのレベルがどの程度積極的になるか、または保守的になるかが決まります。
  • StockSharp バージョンは自律的に実行されます。自動更新はボタンのクリックではなく取引日に反応するようになり、ポジション管理は標準の BuyMarket/SellMarket/ClosePosition 呼び出しによって行われます。
using System;

using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Sudoku UI strategy: SMA mean reversion.
/// Buys when close < SMA - offset. Sells when close > SMA + offset.
/// </summary>
public class SudokuUiStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _smaPeriod;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int SmaPeriod
	{
		get => _smaPeriod.Value;
		set => _smaPeriod.Value = value;
	}

	public SudokuUiStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_smaPeriod = Param(nameof(SmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("SMA Period", "SMA period", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var sma = new SimpleMovingAverage { Length = SmaPeriod };

		decimal? prevClose = null;
		decimal? prevSma = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sma, (candle, smaVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var close = candle.ClosePrice;

				if (prevClose.HasValue && prevSma.HasValue)
				{
					var crossBelow = prevClose.Value >= prevSma.Value && close < smaVal;
					var crossAbove = prevClose.Value <= prevSma.Value && close > smaVal;

					if (crossBelow && Position <= 0)
						BuyMarket();
					else if (crossAbove && Position >= 0)
						SellMarket();
				}

				prevClose = close;
				prevSma = smaVal;
			})
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, sma);
			DrawOwnTrades(area);
		}
	}
}