SQL (ANSI)ProgrammingシニアSQLデベロッパー

ANSI SQL:2016による複雑な連続パターンを検出するアプローチを特徴付けてください。特に、順序付けられた金融ティックデータ内での「ダブルディップ」形成(厳密に減少、増加、減少、増加の動き)をMATCH_RECOGNIZE句を利用して、再帰的CTEや手続きロジックなしで特定する方法について詳しく説明してください。

Hintsage AIアシスタントで面接を突破

質問への回答。

質問の歴史。

SQL:2016標準の以前は、順序付けられたデータセット内での複数行の連続パターンの特定には、複雑な自己結合、カーソルベースの手続きロジック、または有限状態マシンをシミュレートする再帰的CTEが必要でした。これらのアプローチは組み合わせ爆発、パフォーマンスの低下、メンテナンスの難しさに悩まされていました。MATCH_RECOGNIZE句の導入により、行パターン認識のための明示的で数学的に厳密な構文が提供され、関係データベースエンジン内で直接複雑なイベント処理が可能になりました。

問題。

特定の可変長シーケンスの検出(W字型価格形成など)は、各行を複数の前および後の行と比較しながら、シーケンス全体を通じてコンテキスト状態を維持する必要があります。標準のウィンドウ関数は固定オフセット(例:LAG 1LEAD 1)のみを参照できるため、脚の期間が異なるパターンを扱うことができません。再帰的CTEは理論的には状態遷移を追跡できますが、計算コストが高くなり、厳密な順序制約を持つ複雑なパターンを扱う場合、構文が長くなりすぎてしまいます。

解決策。

MATCH_RECOGNIZEは、ブール条件を使用してパターン変数を定義し、ターゲットパターンを正規表現構文(例:A B+ C+ D+ E+)を介して指定し、一致した行に対して集計測定を計算することを可能にします。パーティショニング、順序付け、ナビゲーション機能(PREVNEXTFIRSTLAST)をネイティブでサポートします。

SELECT * FROM stock_ticks MATCH_RECOGNIZE ( PARTITION BY symbol ORDER BY tick_time MEASURES STRT.price AS start_price, FINAL LAST(DOWN1.price) AS first_trough, FINAL LAST(UP1.price) AS middle_peak, FINAL LAST(DOWN2.price) AS second_trough, FINAL LAST(UP2.price) AS end_price, MATCH_NUMBER() AS pattern_id ONE ROW PER MATCH AFTER MATCH SKIP TO LAST UP2 PATTERN (STRT DOWN1+ UP1+ DOWN2+ UP2+) DEFINE DOWN1 AS DOWN1.price < PREV(DOWN1.price), UP1 AS UP1.price > PREV(UP1.price), DOWN2 AS DOWN2.price < PREV(DOWN2.price) AND DOWN2.price < FIRST(UP1.price), -- 中間ピークを下回る必要があります UP2 AS UP2.price > PREV(UP2.price) ) AS pattern_matches;

生活からの状況

コンテキスト。

ある定量的取引会社は、ハイフリケンシーの外国為替データ(ティックごと)におけるW字型のダブルボトムパターンを検出する必要があり、ロングポジションのエントリポイントを自動化するために具体的でした。このパターンは、ピークによって分かれている2つの明確なトラフが必要であり、各脚は少なくとも0.5%の価格変動を示します。

問題。

データセットには、50の通貨ペアにわたって1日あたり1000万行が含まれていました。Pythonベースの検出は、毎時ギガバイトのデータを転送する際にネットワークの遅延やメモリ制約を引き起こしました。標準SQLアプローチでは、複数のLAG()/LEAD()自己結合を使用することで、Wパターンの4つの脚を相関させようとすると、デカルト積が生成され、クエリが10分後にタイムアウトしました。

解決策1:クライアント側Python処理。

チームは最初に、ピークとトラフを検出するためにpandasを使用したカスタムループロジックを用いました。利点: 豊富な分析ライブラリ、容易な単体テスト。欠点: 大量データ転送のボトルネック(数時間の遅延)、完全な市場履歴を処理する際のアプリケーションサーバーでのメモリ枯渇、リアルタイムで反応できないこと。

解決策2:再帰的CTE状態マシン。

彼らは、5つの状態(0=開始の検出、1=最初の減少、2=最初の上昇、3=2回目の減少、4=2回目の上昇)を追跡する再帰的CTEを試みました。利点: ピュアSQL、論理的に厳密。欠点: データベースエンジンでの単一スレッド実行、深い再帰による指数関数的遅延、理解不能な300行以上のSQLで、変動の大きいシーケンスではスタックオーバーフローエラーが発生しやすい。

解決策3:MATCH_RECOGNIZEの実装。

チームは、上記のSQL:2016パターンマッチングクエリを実装しました。利点: ネイティブエンジンの最適化(ベクトル化実行)、数学的パターン定義を正確に反映する簡潔な25行のクエリ、量子(+)を用いた可変長の脚の自動処理、および重複検出を防ぐための効率的なスキップ。欠点: SQL:2016機能をサポートするOracle 19cへのデータベース移行が必要で、SQLにおける正規表現構文に不慣れな開発者への初期トレーニングが必要でした。

選択された解決策と結果。

解決策3は、歴史的なバックテストにおいてサブ秒のパフォーマンスを発揮したため選択されました。AFTER MATCH SKIP TO LAST UP2句は、Wパターンが完了した後、重複する検出を避けるためにパターンの末尾からスキャンを再開しました。このシステムは、99.8%の手動検証済みWパターンを成功裏に特定し、検出遅延を45分(Python)から800ミリ秒に短縮し、リアルタイムアルゴリズミック取引を可能にしました。


候補者が見逃すことが多いこと

AFTER MATCH SKIP句は、一致後の再開ポイントをどのように決定し、なぜSKIP TO NEXT ROWとSKIP PAST LAST ROWが重複パターンにとって重要なのですか?

AFTER MATCH SKIPは、パターンマッチャーがスキャンを続ける場所を決定します。SKIP PAST LAST ROW(デフォルト)は、現在の一致の最終行の後から再開し、いかなる行も複数の一致に参加できないようにします-これは異なるイベントの検出に適しています。対照的に、SKIP TO NEXT ROWは、一致の開始行の直後の行から再開し、重複する一致を許可します。これは、金融時系列において単一のトラフが二つの連続するWパターンの底を形成する可能性があるため重要です(重複ウィンドウ)。候補者の多くは標準のスキップにデフォルトを設定し、有効な重複信号をフィルタリングしてしまい、検出感度を低下させます。

MEASURES句におけるRUNNINGとFINALセマンティクスの違いは何ですか、そしてこれは可変長パターン内の集計計算にどのように影響しますか?

RUNNINGは、一致が構築される各連続行で式を評価します(例:減少脚中に移動平均を計算)。FINALは、完全な一致の最終行でのみ式を評価し、すべてのパターン変数に対して最終的な境界値を使用します(例:パターンの開始から終了までの合計パーセンテージ変化を計算)。候補者は、MAX(leg_price) - MIN(leg_price)のような全パターンメトリックを計算する際にFINALキーワードを頻繁に欠落させ、不完全な一致からの中間値が返され、それが誤った取引信号計算につながります。

空の一致をどのように処理し、デバッグ目的で一致しない行が出力に表示されることを保証しますか?

デフォルトでは、MATCH_RECOGNIZEは、いかなる一致にも参加しない行をフィルタリングします。一致しない行を含めるには(特定のシーケンスがパターン基準を満たさなかった理由を監査するために不可欠です)、ALL ROWS PER MATCHを指定し、SHOW EMPTY MATCHESと組み合わせる必要があります。このモードでは、すべての入力行が出力を生成し、パターン測定はマッチ外の行に対してNULLを返します。さらに、MATCH_NUMBER()は、一致しない行に対してNULLを返します。候補者はしばしば「データが不足している」とのデバッグに苦労し、厳密なDEFINE条件が有効な行をフィルタリングしていることに気づかず、SHOW EMPTY MATCHESを利用して特定のブール条件(例:2つ目のトラフが最初のトラフよりも低くならなかったこと)がパターン拒否を引き起こした原因を診断できません。