共和分株式による統計的裁定取引(第5回):スクリーニング
はじめに
本連載は、まず半導体業界の株式の中から、執筆時点でNVDA (Nvidia Corporation)と高い相関を持つ株式を見つけるヒューリスティックから始まりました。その後、いくつかの共和分株に絞り込み、データベース設定やサンプル例で使用しました。これらの株式は本連載では「ポートフォリオ」として扱われ、デモンストレーションの目的やプロセス理解に大いに役立ちました。
現在では、Metatrader 5サービスを実装してデータベースを継続的に更新できるようになり、エキスパートアドバイザー(EA)も中断なくリアルタイムで自動更新できる状態となりました。これにより、本格的な共和分株ポートフォリオの構築に取り掛かる準備が整い、スクリーニングを開始する時期が来たと言えます。
「スクリーニングとは、大量の株式やその他金融商品から、投資家やトレーダーが設定した特定の基準やパラメータを満たすものを選別するプロセスを指します。このプロセスは、利用可能な膨大な選択肢を絞り込み、特定の投資戦略や取引目的に合致するものに焦点を当てるために重要です。」(Investing.com)
私たちの戦略は平均回帰型(ミーンリバージョン)の統計的裁定取引であり、Nasdaq株式のうちNVDAと共和分関係にある株を選定し、ポートフォリオ比率に従って同時に売買することで市場中立性を目指します。対象となる株式はNasdaq上の全銘柄です。具体的に満たすべき基準は以下の通りです。
- エングル=グレンジャー検定およびジョハンセン検定による共和分の強さ
- ポートフォリオ比率の安定性
- ADFおよびKPSS検定によるスプレッドの定常性の質
- 資産の流動性
これら4つの基準は、スコアリングシステムを構築するのに十分です。スコアリングシステムは、長期的に価格が安定して共に動く株式グループを特定することで、取引上の優位性をもたらします。すべてのペアやグループが目的に適しているわけではないため、スコアリングシステムが必要です。数百、あるいは数千の株式のあらゆる組み合わせを単純にテストすれば、潜在的なペアやバスケットの数は爆発的に増加します。私たちは、この統計的裁定取引フレームワークを、一般的なノートパソコンと通常のネットワーク帯域で利用する平均的な個人投資家向けに開発していることを忘れてはなりません。全組み合わせを最初からテストすれば、計算コストは初期段階から非常に高くなります。スコアリングシステムを導入することで、短期的な相関しか持たないペアや、流動性や取引コストの問題で実際に取引できないペアに資金を投じるリスクを避けられます。
スコアリングを伴うスクリーニングプロセスを比喩的に表現するなら、「じょうご」が適しています。まず広範な候補からスタートし、セクターや業界の類似性で不適切な候補を除外し、その後、相関、共和分、定常性に基づいてスコアリングをおこないます。最後に、リスク管理や資金管理の観点から取引不可能なものを除外します。このプロセスにより、統計的に有意であるだけでなく、経済的にも意味があり、実際に取引可能なバスケットを見つけられる可能性が高まります。
スクリーニングとスコアリングは、ブローカーで取引可能なすべての株式リストを、厳選された取引機会の集合へと変換します。これにより、バックテストやデモ口座での取引など、同様に重要なステップでの時間とリソースの節約にもつながります。
図1は、スクリーニングプロセスのフロー図を示しています。

図1:スクリーニングプロセスの概念的フロー図
初期ユニバースの定義
前節で挙げた4つの基準のうち、最後の基準である資産の流動性は、ゼロからスクリーニングを開始する場合、通常は最初に用いられます。流動性は、スプレッドなどを通じて取引コストに影響を与えるだけでなく、戦略の内容によっては取引そのものの可否にも影響します。本戦略は株式の空売りが可能であることを前提としているため、流動性は排除条件となります。
出発点として、S&P 500やNasdaq-100といった主要株価指数を用いることも可能です。これらの指数は、すでに流動性や市場での重要性に基づいたフィルタリングが施されています。あるいは、最低時価総額、平均日次取引量、買値と売値の差の小ささといった基準を用いて、カスタムユニバースを構築することも可能です。どちらの方法も、初期ユニバースを定義する手段としては妥当です。しかし、ここでの私の主な関心は、付属のサンプルコードを用いてこのプロセスを再現しようとする読者の皆さんが、できる限り簡単かつ分かりやすく体験できることにあります。そのため、私はデータソースとしてMetaQuotes-Demoサーバーを使用しています。これは、すべてのMetaTrader 5ユーザーが自由に利用できるものだと考えられるからです。私の確認する限りでは、MetaQuotes-Demoサーバーには、S&P 500構成銘柄やNasdaq-100構成銘柄専用のパス(下図参照)は存在しません。その代わりに、Nasdaqに上場する株式全体を含むパスが提供されています。
図2:Nasdaq/Stockパスが強調表示されたMetaTrader 5の銘柄ウィンドウ
仮にNasdaq-100銘柄のみに限定して開始するとした場合、指数構成銘柄の入れ替えや比率のリバランスがおこなわれるたびに更新が必要となる、厳選された銘柄リストを自前で管理しなければなりません。その結果、例示コードはすぐに時代遅れになってしまいます。したがって、ここでの目的においては、Nasdaq/Stockパスが出発点、すなわち初期ユニバースとして理想的な選択となります。
その数は、6,000を超える銘柄に及びます。
図3:MetaQuotes-Demoサーバーにおけるグループ別銘柄数
セクターおよび業種によるフィルタリング
初期ユニバースを定義した後の次のステップは、市場に関する知識や経験、常識を活用して対象を絞り込むことです。これらから分かるのは、同じセクターや業種に属する株式は、同一のサプライチェーンの一部であったり、中央銀行の金利政策に依存していたりするなど、共通のドライバーを持つことが多いという点です。こうした共通要因は、価格が安定した形で共に動く可能性を高めます。たとえば、銀行株は金利変動に対して似た反応を示す傾向があり、また本稿のケースである半導体企業は、世界的な半導体需要の影響を受ける可能性があります。
このような、ほとんど直感的とも言える市場知識と常識こそが、Nvidiaと共和分関係にある最初の株式バスケットを選択する際に用いたヒューリスティックの基盤となっていました。
データ分析に使用できるよう、フィルタリングされた株式は、関連するメタデータとともにsymbolテーブルに保存します。ただしその前に、テーブルにsource列を追加します。
これは、MetaTrader 5のパスや銘柄のメタデータが、ブローカーやサーバーを変更した際に異なる可能性が高いためです。異なるブローカーからのデータを分析する際には、データソースごとに市場データをフィルタリングする必要があります。
ALTER TABLE symbol ADD source TEXT CHECK(LENGTH(source) <= 50) DEFAULT ('MetaQuotes') NOT NULL; また、特定のパスから銘柄をデータベースに取り込むためのMQL5スクリプト(SymbolImporter.mql5)を用意します。
図4:パラメータが表示されたMetaTrader 5 SymbolImporterダイアログ
このスクリプトにより、データベース作成時に未設定のまま残していた項目、すなわち資産タイプ、取引所、業種、セクターといった情報が補完されます。また、上で新たに追加したフィールドに、データのソース情報も併せて追加されます。
//+------------------------------------------------------------------+ //| Insert a symbol into the database | //+------------------------------------------------------------------+ bool InsertSymbol(int db_handle, string ticker, string source) { ResetLastError(); // Get symbol information string exchange = SymbolInfoString(ticker, SYMBOL_EXCHANGE); string asset_type = GetAssetType(ticker); string sector = SymbolInfoString(ticker, SYMBOL_SECTOR_NAME); string industry = SymbolInfoString(ticker, SYMBOL_INDUSTRY_NAME); string currency = SymbolInfoString(ticker, SYMBOL_CURRENCY_BASE); if(currency == "") currency = SymbolInfoString(ticker, SYMBOL_CURRENCY_PROFIT); // Prepare SQL insert statement (symbol_id is auto-generated by SQLite) string req = StringFormat( "INSERT INTO symbol(ticker, exchange, asset_type, sector, industry, currency, source)" " VALUES( '%s', '%s', '%s', '%s', '%s', '%s', '%s')", ticker, exchange, asset_type, sector, industry, currency, source); if(!DatabaseExecute(db_handle, req)) { printf("Failed to insert symbol: %d", GetLastError()); return false; } return true; }
パスからアセットタイプの取得を試みます。
//+------------------------------------------------------------------+ //| Determine asset type based on symbol characteristics | //+------------------------------------------------------------------+ string GetAssetType(string symbol_name) { ResetLastError(); // Simple asset type detection - you may want to enhance this string description = SymbolInfoString(symbol_name, SYMBOL_DESCRIPTION); string path = SymbolInfoString(symbol_name, SYMBOL_PATH); if(StringFind(path, "Forex") != -1) return "Forex"; if(StringFind(path, "Stock") != -1) return "Stock"; if(StringFind(path, "Index") != -1) return "Index"; if(StringFind(path, "Future") != -1) return "Future"; if(StringFind(path, "CFD") != -1) return "CFD"; if(StringFind(path, "Crypto") != -1) return "Cryptocurrency"; // Fallback based on symbol name patterns if(StringLen(symbol_name) == 6 && StringFind(symbol_name, "USD") != -1) return "Forex"; if(StringFind(symbol_name, ".", 0) != -1) return "Stock"; return "Other"; }
すべてがうまくいけば[エキスパート]タブのログに次のような内容が表示されます。
図5:銘柄のインポートが正常に完了した後のSymbolImportログを表示したMetaTrader 5の[エキスパート]タブ
そしてデータベースを確認すれば、このサーバー(この場合はMetaQuotes-Demo)で利用可能な、Nasdaqに上場するすべての株式が格納されているはずです。
図6: Nasdaq株式のメタデータのサンプルを表示したMetaEditorのデータベースインターフェース
インポートされた株式銘柄の総数は、「SELECT count()」文で確認できます。
図7:SQLiteデータベースにインポートされたNasdaq株式の総数を表示したMetaEditorのデータベースインターフェース
そのうち、約700銘柄がテクノロジーセクターに属しています。
図8:テクノロジーセクターに属するNasdaq株式の総数を表示したMetaEditorのデータベースインターフェース
しかし、半導体業界に属する銘柄は、60銘柄強にすぎません。
図9:半導体セクターに属するNasdaq株式の総数を表示したMetaEditorのデータベースインターフェース
これら63銘柄の半導体業界に属するNasdaq株式こそが、私たちが注目すべき対象です。将来的には、セクターや業界の交差領域を探ることで新たな機会へと拡張することも可能ですが、現時点で必要なのは、より強く同調して価格変動しやすい銘柄に集中することです。これらの銘柄こそが、継続的な統計検定を実行するために、私たちの労力を注ぐに値する対象なのです。
相関分析
セクターや業種によって初期ユニバースを絞り込んだ後の次のステップは、株式が実際に価格面で一緒に動くかどうかを確認することです。最も簡単な方法は、相関係数を計算することです。本連載記事の初回から、私たちはピアソン相関を用いており、今後もこれを継続します。ピアソン相関は計算が高速で、解釈も容易なため、スクリーニングに実用的なツールとなります。
ピアソン相関検定については、本連載第2回および第3回の記事で詳しく解説していますので、ここで再度説明する意味はありません。もしこのトピックに不慣れであれば、そちらの記事を参照してください。ここで覚えておくべき重要な点は1つです。
相関は共和分と同じではありません。株価は通常、非定常時系列であり、非定常時系列は短期的には高い相関を示すことがありますが、長期的に共和分関係にあるとは限りません。
スピアマン相関検定も非常に一般的で、補助的チェックとして明確で特定の用途がありますが、ここでは扱いません。後ほど、特定のユースケース向けの改善策としてスピアマン相関を見る予定です。
相関検定の結果は、データベース内の専用テーブルに保存します。このテーブルは予想通りcorr_pearsonという名前にします。
-- corr_pearson definition CREATE TABLE corr_pearson ( tstamp INTEGER NOT NULL, ref_ticker TEXT CHECK(LENGTH(ref_ticker) <= 10) NOT NULL, corr_ticker TEXT CHECK(LENGTH(corr_ticker) <= 10) NOT NULL, timeframe TEXT CHECK(LENGTH(timeframe) <= 10) NOT NULL, lookback INTEGER NOT NULL, coefficient REAL NOT NULL, CONSTRAINT corr_pearson_pk PRIMARY KEY(tstamp, ref_ticker, corr_ticker) ) STRICT;
技術的には、これらの予備計算の結果を保存する必要は必ずしもありません。しかし、統計的裁定取引においては、データは中核となります。私たちは、半導体株とNvidia Corp.の間の相関係数を、H4時間足で180日間のルックバック期間を使って計算しています。しかし、すぐに他の時間足やルックバック期間についても計算することになるでしょう。おそらく、NVDA以外の基準銘柄についても同じプロセスを繰り返すことになります。データ分析が進むにつれて、ピアソン相関、エングル=グレンジャーやジョハンセンの共和分、さらにはその他の中間計算の結果など、大量の処理済みデータが蓄積されていきます。
ポイントは明白です。これらすべての計算は、後で保存、クロスチェック、再利用すべき貴重な情報を出力しています。したがって、統計的裁定取引を真剣におこなうのであれば、一時的なデータを安易に受け入れず、すべての中間計算結果を捨てない習慣を身につけるべきです。将来役立つ可能性があるものはすべて保存しましょう。そして、まだ納得できない場合は、この言葉を思い浮かべてください:機械学習。いずれ必ずそこに到達します。😀
図10:corr_pearsonテーブルのフィールドを表示したMetaEditorデータベースインターフェース
ここでも再び、複合主キーを使用しています。今回は、挿入タイムスタンプ、参照ティッカー、相関ティッカーの3つを組み合わせています。これにより、この特定の銘柄ペアに対して相関係数が計算された正確な時点を把握できます。こうしておけば、異なる時間足であっても、すべての銘柄の相関を安全に再計算できます。
図11:異なる時間足でソートされたcorr_pearsonテーブルの表示
図11を見ると、同じルックバック期間であっても、銘柄によってはH4からD1に移ると相関が上昇するものもあれば、逆に低下するものもあることが分かります。これを複数の時間足やルックバック期間に拡張すると、非常に強力な分析ツールになります。さらに、このデータはある意味であなた独自のデータになります。なぜなら、どの銘柄をどのパラメータで分析するかを決めるのは、他でもないあなた自身だからです。このデータ分析から導かれる結論が、取引上の優位性をもたらすかどうかは別として、ここでのアイデアはその理解にあります。
後ほど、各銘柄とNVDAの相関の時間的変化も追跡できます。ここでは、Broadcom Inc. (AVGO)とNVDAの相関の変化を示しています。ルックバック期間は1年(252日)から1か月(30日)まで、途中180、120、90、60日のルックバック期間を経ています。係数でソートした結果から、このペアではD1が最適な時間足であること、時間足が短くなると相関が低下すること、さらに90日未満では急激に低下することが明確にわかります。これは非常に多くの情報であり、表面的な部分に過ぎません。
注意:1年(252日)以外のルックバック期間は、ここでの可視化を簡単にするために月単位で丸めています。
図12:Broadcom Inc. (AVGO)とNvidia Corp. (NVDA)のD1時間足における、1年から1か月のルックバック期間までのcorr_pearsonの変化
この単純な相関テーブルの価値がお分かりでしょうか。単純な例として、H4時間足を除外し、日次相関のみを残してプロットしました。 
図13:Broadcom Inc. (AVGO)とNvidia Corp. (NVDA)のD1時間足における、1年から1か月のルックバック期間までのピアソン相関の推移プロット
相関を予備的なフィルターとして用いることは一般的ですが、相関は共和分を示すものではありません。したがって、NVDAとの相関が低い銘柄が共和分関係にないと仮定することはできません。では、相関検定の目的は何でしょうか。相関の計算は、時間の経過に伴う価格の変動パターンを理解するのに役立ちます。しかし、相関があるからといって共和分関係が保証されるわけではありません。実務ではどのように活用すればよいのでしょうか。下位時間足と短期ルックバック期間で相関を計算しつつ、同時に上位時間足と長期ルックバック期間で共和分をテストするという方法です。ここでいう下位と上位は、あくまで相対的な概念です。取引においては常にそうですが、統計的手法を用いた取引であっても、万能のレシピは存在しません。各銘柄ペアやグループに対して、相関検定と共和分検定のパラメータの最適な組み合わせを見つけるために、テスト、実験、バックテスト、評価を繰り返す必要があります。市場知識、常識、計算リソースを賢く活用してください。そして、繰り返し実行することが重要です。
スクリプト自体は、特殊なPythonクラスとして構造化されました。
図14:Pythonスクリプトエディタのアウトラインからクラスメソッドを表示したスクリーンショット
次に、スクリーニングプロセスにおいて共和分検定をどのように組み合わせるかを見ていきましょう。
共和分検定
エングル=グレンジャー
エングル=グレンジャー検定は、シンプルで軽量です。1980年代にクオンツトレーダーの間で初めて人気を博し、次の10年間でジョハンセン検定が登場した後も、なお広く使われています(後述)。 前述のとおり、本連載の第2回および第3回の記事で共和分検定について詳細に解説しているため、ここで繰り返すことはしません。ここでは、スクリーニングプロセスにおける実装と活用に焦点を当てます。もしこのトピックが初めてであれば、そちらの記事を参照してください。
覚えておくべき点は一つです。2つの資産(銘柄)の場合、通常はエングル=グレンジャー検定を用います。これは、2つの価格系列の線形回帰の残差が定常かどうかを確認するものです。ただし、この検定は1つの共和分関係しか扱えないため、ペアごとにしか適用できません。
ピアソン相関と同様に、エングル=グレンジャー共和分検定の結果も専用のデータベーステーブルcoint_egに保存します。
-- coint_eg definition CREATE TABLE coint_eg ( tstamp INTEGER NOT NULL, ref_ticker TEXT CHECK(LENGTH(ref_ticker) <= 10) NOT NULL, coint_ticker TEXT CHECK(LENGTH(coint_ticker) <= 10) NOT NULL, timeframe TEXT CHECK(LENGTH(timeframe) <= 10) NOT NULL, lookback INTEGER NOT NULL, pvalue REAL NOT NULL, test_stat REAL NOT NULL, crit_val_1 REAL NOT NULL, crit_val_5 REAL NOT NULL, crit_val_10 REAL NOT NULL, hedge_ratio REAL, is_coint INTEGER NOT NULL, CONSTRAINT coint_eg_pk PRIMARY KEY(tstamp, ref_ticker, coint_ticker) ) STRICT;
is_cointフィールドはブール値ですが、SQLiteには専用のBooleanデータ型はありません。その代わりに、1または0として整数で格納します。入力としてTRUEまたはFALSEも受け付けます。
「ほとんどのSQL実装とは異なり、SQLiteには専用のBOOLEAN型は存在しません。その代わり、TRUEおよびFALSEは通常、整数の1および0として表されます。」(SQLiteドキュメント)
図15:corr_egテーブルのフィールドを表示したMetaEditorデータベースインターフェース
執筆時点では、全62銘柄のうち、Aeluma Inc. (ALMU)のみが、日次時間足と365日ルックバック期間でNvidia Corp. (NVDA)と共和分関係にあります。
図16:NVDAと共和分関係にある銘柄ALMUが表示されたcoint_egテーブル
corr_pearsonと同様に、ここでも複合主キーを使用しています。挿入タイムスタンプ、参照ティッカー、共和分ティッカーの組み合わせです。理由は同じです。共和分検定のタイムスタンプを参照ティッカーおよび共和分ティッカーに関連付けて保持することで、すべての銘柄に対して、異なる時間足やルックバック期間でも再度共和分検定をおこなうことが可能になります。
このテーブルは、次に紹介するcoint_johとともに、スクリーニングプロセスの中核となります。例として、H4時間足での機会を見てみましょう。
図17:MetaEditorデータベースインターフェースにおけるcoint_egテーブルの表示。H4時間足および異なるルックバック期間でNvidia Corp. (NVDA)と共和分関係にある17銘柄を示す。
図17のテーブルはp値でソートされています。執筆時点では、最初の銘柄、Silicon Laboratories Inc. (SLAB)が30日ルックバック期間でNVDAと最も高い共和分関係にあります。しかし、これらの銘柄はいずれも、各自のルックバック期間においてH4時間足でNVDAとのペアトレード候補として有望です。つまり、この時点で、NVDAと共和分関係にある銘柄の堅実なポートフォリオが形成されており、各銘柄のヘッジ比率も設定済みです。ここで止めても、共和分強度でランク付けされたポートフォリオが完成しており、あとはスプレッドの定常性を検定し、バックテストで検証するだけです。
ジョハンセン
ジョハンセン法は、エングル=グレンジャー検定の直後、1980年代末に開発されました。1990年代には学術界で標準的な手法となり、21世紀初頭には世界中のヘッジファンドのクオンツチームによって徐々に採用されました。
エングル=グレンジャー検定が2つの時系列、すなわち2つの資産のみを対象としているのに対し、ジョハンセン検定は複数の時系列を対象として設計されています(もちろん2つの時系列も扱えます)。これにより、2銘柄、3銘柄、4銘柄以上のバスケットをスクリーニングする際に、複数の異なる長期関係が共存する場合でも対応できる、非常に強力な手法となります。
ジョハンセン検定は、主にトレース統計量と最大固有値統計量の2つの統計量を算出します。これらの統計量により、共和分ランク、すなわち資産群間に存在する独立した定常関係の数が決定されます。
- ランク = 0:共和分関係なし
- ランク = 1:1つの安定したスプレッド。これまでの記事ではすべてこのケースを扱っています。
- ランク > 1:複数の独立したスプレッドが存在し、ポートフォリオ構築においてより柔軟性が得られます。季節性や異常値を扱う際にこのケースを詳しく見ていきます。
検定は、これらの定常関係に対応する一連の固有ベクトルを提供します。各固有ベクトルは、時間的に定常となる株式の線形結合の比率を示します。この比率こそが、ヘッジ比率として使用されます。つまり、資産をどの割合で組み合わせて合成の平均回帰スプレッドを形成するかを教えてくれるのです。このヘッジ比率を用いることで、共和分銘柄間のスプレッドを構築できます。第2回の記事では、半導体業界の4銘柄グループをバックテストする際にこの機能を使用しました。
これまでの2つの検定と同様に、ジョハンセン検定のパラメータと出力も専用テーブルに保存し、後の分析に備えます。ただし、今回は2つのテーブルが必要になります。
1つ目のテーブル:各検定実行のメタデータを保存するメインのcoint_johansen_testテーブル
-- coint_johansen_test definition CREATE TABLE coint_johansen_test ( test_id INTEGER PRIMARY KEY AUTOINCREMENT, tstamp INTEGER NOT NULL, timeframe TEXT CHECK(LENGTH(timeframe) <= 10) NOT NULL, lookback INTEGER NOT NULL, num_assets INTEGER NOT NULL, trace_stats_json TEXT NOT NULL, trace_crit_vals_json TEXT NOT NULL, eigen_stats_json TEXT NOT NULL, eigen_crit_vals_json TEXT NOT NULL, coint_rank INTEGER NOT NULL, CONSTRAINT coint_johansen_test_unique UNIQUE (tstamp, timeframe, lookback) ) STRICT;
相関検定やエングル=グレンジャー共和分検定のテーブルで用いたような、資産ティッカーを使った複合主キーの代わりに、メインテーブルでは単一の自動インクリメントtest_idを主キーとして使用します。下記のcoint_johansen_test_assetsテーブルは、各検定実行に含まれる資産ごとに1行を保持します。これにより、テーブル構造を変更することなく任意の数の資産に対して検定を実行できます。もしこの手法の詳細や理論的背景に興味がある場合は、データベース正規化に関するウィキペディアの関係の正規化を参照してください。
テストのタイムスタンプ、時間足、およびルックバック期間が全体として一意であることを要求する制約により、異なる時間足とルックバック期間で、同じ銘柄のテストをいつでも再実行することができ、各テスト出力は一意になります。
ジョハンセン検定は、トレース統計量および最大固有値統計量に対して複数の値とその臨界値を出力します。単一のフィールド(例:trace_stat)に格納することはできません。そこで、JSON列(trace_stats_json、trace_crit_vals_jsonなど)を使い、結果の配列全体を文字列として保存します。SQLiteにはネイティブの配列型がないため、クリティカル値やトレース統計量の配列はJSON形式の文字列をTEXTフィールドに格納します。詳細は前回の記事で解説した通り、SQLiteの制約をどのように扱い、MQL5でJSON文字列を読み取り、解析するかを参照してください。
次のステップでは、これらの臨界値(trace_crit_vals_json)を活用し、自動スクリーニングで株式グループをバックテストする方法を見ていきます。現時点では、これらの値が各有意水準(1%、5%、10%)でのトレース統計量(trace_stats_json)との比較に使われ、共和分関係の数を決定することを覚えておいてください。
is_cointのブールフィールドだけでは十分ではありません。複数資産のジョハンセン検定の主要な結果は、共和分関係の数、すなわちランク(r)です。新しいcoint_rankフィールドに、この整数値を保存します。
2つ目のテーブル:coint_johansen_test_assetsは、各検定実行を該当する資産と関連付けるためのテーブルです。
-- coint_johansen_test_assets definition CREATE TABLE coint_johansen_test_assets ( test_id INTEGER NOT NULL, symbol_id INTEGER NOT NULL, CONSTRAINT coint_johansen_test_assets_pk PRIMARY KEY(test_id, symbol_id), CONSTRAINT coint_johansen_test_assets_test_fk FOREIGN KEY(test_id) REFERENCES coint_johansen_test(test_id) ON DELETE CASCADE, CONSTRAINT coint_johansen_test_assets_symbol_fk FOREIGN KEY(symbol_id) REFERENCES symbol(symbol_id) ON DELETE CASCADE ) STRICT;
coint_johansen_test_assetsテーブルでは、ティッカーではなくsymbol_idを使用して、symbolテーブルとの外部キー関係を構築しています。これにより、検定対象の資産が常にシステム内に存在することが保証されます。それに加えて、データベースにおいて整数キー(symbol_id)でジョインをおこなう方が、テキストフィールド(ticker)よりも一般的に効率が良いため、パフォーマンス向上の効果も得られます。この点は現時点では大きな重要性はありませんし、システムが稼働する前は焦点ではありません。しかし、覚えておく価値はありますし、追加コストは発生していません。🙂
さらに、market_dataテーブルはすでにsymbolテーブルと関連付けられています。ジョハンセン検定の出力をsymbolテーブルに接続することで、将来的に整備される予定の「キュレーション済み」市場データとも間接的に接続され、データベースの一貫性を保つことに役立ちます。
ここで疑問に思うかもしれません。では、なぜピアソン相関やエングル=グレンジャー検定の結果では同じようにsymbol_idを使わず、tickerを用いてシステムに接続したのでしょうか。
理由は2つあります。1つ目は少し特殊ですが、ピアソン相関やエングル=グレンジャー検定をペアトレード用にできるだけ簡単に実行できるようにしたいということです。Metatraderから事前に銘柄をデータベースにインポートする手間を気にせずに済むようにしています。
2つ目の理由は、ジョハンセン検定が自動化システムのメインツールとなる予定だからです。相関とエングル=グレンジャー検定は、手動でのスクリーニングに限定され、ポートフォリオ内の株式バスケットを扱う際にはジョハンセン検定を使用します。
図18:corr_johansen_testテーブルのフィールドを表示したMetaEditorデータベースインターフェース
図18は、ジョハンセン共和分検定テーブルをすべてのフィールドと共に示しており、ヘッジ比率やポートフォリオ比率として使用する共和分ベクトルを含む1つの検定結果も確認できます。より詳細には、次の図19で確認できます。
図19:MetaEditorデータベースインターフェースにおけるcoint_johansen_testテーブルの表示。共和分で陽性となった1件の検定結果と、推奨ヘッジ比率(ポートフォリオ比率)を示す。
図20:MetaEditorデータベースインターフェースにおけるcoint_johansen_testテーブルの表示。D1時間足および異なるルックバック期間で、異なる共和分ランクを持つ7件の共和分陽性テスト結果を示す。
ここで、半導体業界の株式で構成された、月次から年間、半年、四半期などの主要ルックバック期間に対応する堅実な共和分ポートフォリオが揃っています。同じルックバック期間の株式グループは、株式バスケットの一部としてテスト可能です。
これらのデータは、前回の記事で示したように、strategyテーブルで使用され、リアルタイムでモデルを更新する際に用いられます。次の記事で実行するバックテストの基盤となる部分です。
重要な点は、ジョハンセン検定がエングル=グレンジャー検定を不要にしたわけではないということです。どちらも、長期的に複数価格が一緒に動くかどうかを確認する検定ですが、アプローチが異なります。エングル=グレンジャーはよりシンプルで、2資産ずつの検定に適しています。一方、ジョハンセンは複数資産をまとめて検定する際に強力です。実務では、状況に応じてどちらを使うかを判断し、場合によっては両方を確認して結果の信頼性を高めることが推奨されます。
エングル=グレンジャー検定
| ✔️長所 | ❌短所 |
|---|---|
|
|
表1:エングル=グレンジャー共和分検定の長所と短所の箇条書きリスト
ジョハンセン検定
| ✔️長所 | ❌短所 |
|---|---|
|
|
表2:ジョハンセン共和分検定の長所と短所の箇条書きリスト
経験則として、2銘柄を素早く確認する場合はエングル=グレンジャー検定を使用し、ポートフォリオや2資産以上のより詳細な検定にはジョハンセン検定を使用します。
ランク付けシステムを構築する前の最後のステップは、スプレッドの定常性を検証することです。
定常性の検証
特定の時間足とルックバック期間で、株式群に共和分関係があることを確認したら、最後のステップはスプレッドが本当に定常かどうかを検証することです。定常性の性質は、スプレッドが安定した平均値の周りで変動し、時間とともに逸脱しないことを保証します。このステップは非常に重要です。なぜなら、定常でなければ平均回帰が発生するとは限らず、平均回帰こそが私たちの戦略の核であり、ここに裁定機会(アービトラージ)が存在するからです。
スプレッドの定常性を検証するために用いているのは、ADF (Augmented Dickey–Fuller)検定とKPSS (Kwiatkowski–Phillips–Schmidt–Shin)検定です。両方の検定結果を合わせて解釈することで、より信頼性の高い判断が可能になります。両者の結果が一致すれば、スプレッドが確かに平均回帰的である強い証拠となります。一方、結果が一致しない場合は、不安定な挙動を示していることが多く、注意が必要です。これはレッドフラッグと考えられます。
これまでの検定と同様に、定常性検定の結果を保存するための専用テーブルcoint_adf_kpssも用意しています。
-- coint_adf_kpss definition CREATE TABLE "coint_adf_kpss" ( test_id INTEGER NOT NULL, symbol_id INTEGER NOT NULL, adf_stat REAL NOT NULL, adf_pvalue REAL NOT NULL, is_adf_stationary INTEGER NOT NULL, kpss_stat REAL NOT NULL, kpss_pvalue REAL NOT NULL, is_kpss_stationary INTEGER NOT NULL, CONSTRAINT coint_adf_kpss_pk PRIMARY KEY (test_id, symbol_id), CONSTRAINT coint_adf_kpss_test_fk FOREIGN KEY (test_id) REFERENCES coint_johansen_test(test_id) ON DELETE CASCADE, CONSTRAINT coint_adf_kpss_symbol_fk FOREIGN KEY (symbol_id) REFERENCES symbol(symbol_id) ON DELETE CASCADE ) STRICT;
再び複合主キーを使用しますが、今回は各テストを一意にするのはテスト実行のタイムスタンプ/時間足/ルックバック期間の組み合わせではなく、ジョハンセン検定のIDと銘柄との接続です(銘柄はその組み合わせによって一意に決まります)。この方法により、定常性検定をジョハンセン検定とリンクさせると同時に、ADF/KPSS検定は前回の共和分検定で少なくとも1つの共和分ベクトルが存在することに依存する形になります。
前回の共和分検定に少なくとも1つの共和分ベクトルが必要であるという依存関係は、Pythonコード上でも明示されています。
def get_coint_groups(self): """ Retrieves information for all Johansen tests with a cointegrating rank > 0. Returns a list of dictionaries, each containing test_id, timeframe, lookback, and a list of symbol_ids. """ if not self.conn: print("Database connection not established.") return [] try: query = """ SELECT test_id, timeframe, lookback FROM coint_johansen_test WHERE coint_rank > 0 """ df_tests = pd.read_sql_query(query, self.conn) if df_tests.empty: print("No cointegrated groups found in the database.") return []
これは設計上の選択です。理論的には、ADF検定を単独で実行することを妨げるものはありません。しかし、私たちのパイプラインではそれは意味がありません。共和分関係にあるグループだけに対して実行する方が、リソースの面で効率的です。というのも、まもなく私たちは数千銘柄に対して24時間365日、異なる時間足やルックバック期間の組み合わせで検定をおこなうことになるからです。
図21:MetaEditorデータベースインターフェースにおけるcoint_adf_kpssテーブルの表示。ADFおよびKPSSスプレッド定常性検定で陽性となった1件の結果を示す。
このテストID(20)から、ジョハンセン共和分検定で使用した銘柄、時間足、ルックバック期間を取得でき、さらにその検定によって返された共和分ベクトル(ポートフォリオ比率)も確認できます。
SELECT
t1.test_id,
t3.ticker,
t2.timeframe,
t2.lookback,
t2.coint_vectors_json
FROM coint_johansen_test_assets AS t1
JOIN coint_johansen_test AS t2
ON t1.test_id = t2.test_id
JOIN symbol AS t3
ON t1.symbol_id = t3.symbol_id
WHERE t1.test_id = 123;
このクエリは2つのJOIN操作を伴うため、比較的コストの高い処理です。しかし、考慮すべき点は、このクエリはごく少数しか実行しないということです。すなわち、前段階のすべてのフィルターを通過した資産グループが見つかった場合にのみ実行されます。つまり、このクエリはパイプラインの最後に位置します。ここから、すでに安定したスプレッドを持つ共和分株式バスケットが得られ、それをstrategyテーブルにコピーできます。EAはこのstrategyテーブルを読み込み、リアルタイムで自身のパラメータを更新します(前回の記事参照)。
図22:MetaEditorデータベースインターフェースにおけるcoint_johansen_testテーブルの表示。特定のテストIDにおいて、ADFおよびKPSS検定が陽性となった詳細を示す。
この例では、ADFおよびKPSSの定常性検定がテストID #20で陽性となっているため、AMD、INTC、LAES、RMBS、TSM、WOLFは日次(D1)時間足で取引可能であり、対応するポートフォリオ比率はcoint_vectors_jsonに保存されています。
この時点で、データベーススキーマは大きく変化しています。

図23:statarb-0.3スキーマバージョンを示すエンティティリレーションシップ図(ERD)
ご覧の通り、現時点ではデータベースインデックスはまだ設定されていません。これは意図的です。私たちはボトムアップ設計を選択しているため、現時点ではどのクエリに対してインデックスが必要になるかをある程度予測することはできます(たとえば、複合主キーの一部がTEXTフィールドである場合などの高負荷クエリ)。しかし、過剰に考えすぎて過剰設計になるのを避けるため、どのクエリが本当に高負荷または最も多く使用されるかが分かってからインデックスを追加する方針です。
バスケットの選択 - スコアリングシステムの構築
上の図22に示された株式群は、ポートフォリオに組み込まれる1つの株式バスケットを表しています。私たちのポートフォリオには、少なくとも十数個のバスケットが必要とされます。その理由は、ポートフォリオをローテーションさせる必要があるからです。つまり、あるバスケット(バスケット1)よりも、将来の期待リターンの観点でより有望なバスケット(バスケット2)が見つかった場合、いつでも1を2に置き換えられるようにする必要があります。市場の変化、企業イベント、あるいは自身の取引判断(例えば、株Xの取引停止)に対応できる十分な規模のポートフォリオが求められます。
私たちは、約1万銘柄のユニバース(教育目的で株以外の資産タイプも含む)から、この特定のタイムフレームおよび特定のルックバック期間で有効な共和分関係を持つ6銘柄の狭いバスケットまで絞り込みをおこないました。各ステップの詳細を説明したのは理解を助けるためですが、覚えておくべき点は、このプロセスは自動化モードでフルタイム稼働し、これら3つの変数(銘柄、時間足、ルックバック期間)の多くの組み合わせをテストするということです。この組み合わせにより、1つのバスケット以上の結果が期待されます。待機列には、ポートフォリオに組み入れられるのを待つ数十のバスケットが存在することになります。では、次にどのバスケットを採用し、どのバスケットを待機列の最後に送るかはどう決めるのでしょうか。答えは、ランキングシステムです。
以下は、バスケット選定において考慮できるランキング基準の一部です。
共和分の強さ:ジョハンセン統計量(トレース統計量および最大固有値統計量)を用いて、銘柄群がどの程度強く共和分しているかを評価できます。統計量が大きいほど、長期的な関係がより信頼できることを示します。
共和分ベクトルの数(ランク):共和分ベクトルの数を考慮することで、構築するシステムの複雑さを評価できます。
- ランク = 1:単一の安定したスプレッド。監視が容易。
- ランク > 1:複数の可能なスプレッド。柔軟性は高いが複雑さも増す。
ポートフォリオ比率の安定性:サンプル期間ごとにヘッジ比率が大きく変動する場合は、関係性が脆弱である可能性があります。安定した比率を持つバスケットを好むことが望ましいです。
妥当なスプレッド:スプレッドは経済的に妥当であるべきです。特定の銘柄に極端に大きなポジションを持つことは避けます。
平均回帰の速度:平均回帰の半減期を計算することで、スプレッドがどの程度早く均衡に戻るかを評価できます。
流動性:流動性は不可欠な基準です。流動性の低い銘柄を含むスプレッドは、取引コストが高くなる可能性があります。
取引コスト:これは非常に個別性の高いランキング基準です。各自の目的や取引システムに依存しますが、ここでは完全性のために含めています。
上記の基準のすべて、あるいは一部を組み合わせて、スコアリングシステムを構築することができます。たとえば、共和分の強さ、ポートフォリオ比率の安定性、平均スプレッドに重みを付けて評価する方法です。結局のところ、バスケット選定とは、統計的フィルタリング、市場知識、取引可能性のバランスを見つける作業です。
ただし、このスコアリングシステムは実践で意味を持つものです。次の記事では、構築中の自動取引システムのバックテストを中心に扱うため、まずは上記の基準の一部に基づくスコアリングシステムを開発してテストします。こうすることで、EAや異なるバスケット構成とともに、スコアリングシステム自体のテストもおこなうことができます
結論
共和分株を用いた統計的裁定取引に基づく取引戦略のための簡易的な資産スクリーニングの構築方法を見てきました。取引プラットフォームやブローカーサーバー上で利用可能な数千銘柄の大規模ユニバースから出発し、段階的なフィルタリングを経て、共和分ベクトル1つ、定常スプレッドを持つ6銘柄の単一バスケットに到達しました。
まず、経済セクターと産業分類によるフィルタリングをおこない、その後、半導体業界内で最も相関の高い銘柄を選定しました。そして、最終的なバスケットはジョハンセン共和分検定とADF/KPSS定常性検定に基づいて構築しました。
この過程で、各検定結果を保存して後の分析に活用できるよう、データベースに専用テーブルを追加しました。また、これまで使用してきたスクリプトを置き換えるために、モジュール化されたPythonクラスも開発しました。
ここまでで、スコアリングシステムの実験準備が整いました。次のステップでは、ここで開発したスクリーニング手法を用いてシステムをバックテストしながら、このスコアリングシステムのテストをおこないます。
添付コードについてのやや個人的な注記
添付のコード(主にPython)は、Metatrader 5、VS Code、その他の統合AIアシスタントの広範なサポートを受けて作成されました。
私は、コード開発におけるAIを、現代における最も高水準の言語と考えています。AIを使うからといって、プログラミングの知識が不要になるわけではありません。むしろ、開発者にはシステム全体の理解と、いわゆるユーザー要件の明確な理解が求められます。開発者は、何を依頼すべきか、どのように依頼すべきかを非常に正確に理解している必要があります。そして何よりも重要なのは、アシスタントが提供したコードが要求を満たしているか、つまりコードが期待通りに動作するかを確認できることです。これができれば、アシスタントは強化版のジュニア開発者、あるいは場合によってはシニア開発者として機能します。どの程度そのように機能するかは、AIモデル、プロンプト、そして使用するプログラミング言語によって異なります。
例えるなら、コード開発におけるAIはC言語の登場に似ています。プログラミングの知識が不要になるわけではなく、単にアセンブリを書く必要がなくなるだけです。AIアシスタントはすでに、より良いコードを、より短時間で、テストやドキュメント付きで生成することが可能です。
私たちの場合、比較的「低水準」のプログラミング言語はPythonやMQL5です。
| ファイル名 | 説明 |
|---|---|
| Files\StatArb\schema-0.3.sql | SQLiteデータベースバージョン0.3のSQLスキーマ(DDL) |
| Scripts\StatArb\db-setup.mq5 | データベースをセットアップするためのMQL5スクリプト(上記のスキーマファイルを読み取る) |
| Scripts\StatArb\SymbolImporter.mq5 | MetaTrader 5からSQLiteデータベースへ銘柄メタデータをインポートするMQL5スクリプト |
| coint_adf_kpss_to_db.py | ADFおよびKPSS定常性テストを実行するためのメソッドを備えたPythonクラス |
| coint_eg_to_db.py | エングル=グレンジャー共和分検定を実行するためのメソッドを備えたPythonクラス |
| coint_johansen_to_db.py | ジョハンセン共和分検定を実行するためのメソッドを備えたPythonクラス |
| corr_pearson_to_db.py | ピアソン相関検定を実行するためのメソッドを備えたPythonクラス |
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/19626
警告: これらの資料についてのすべての権利はMetaQuotes Ltd.が保有しています。これらの資料の全部または一部の複製や再プリントは禁じられています。
この記事はサイトのユーザーによって執筆されたものであり、著者の個人的な見解を反映しています。MetaQuotes Ltdは、提示された情報の正確性や、記載されているソリューション、戦略、または推奨事項の使用によって生じたいかなる結果についても責任を負いません。
MQL5での取引戦略の自動化(第34回):R²適合度を用いたトレンドラインブレイクアウトシステム
MQL5での取引戦略の自動化(第33回):プライスアクションに基づくシャークハーモニックパターンシステムの作成
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
知っておくべきMQL5ウィザードのテクニック(第80回):TD3強化学習で一目均衡表とADX-Wilderのパターンを使用する
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索