dflow-kalshi-market-scanner について
dflow-kalshi-market-scannerは、DFlow Metadata APIを使ってKalshi市場を検索・順位付けするスキャンを定義したスキルです。価格、出来高、スプレッド、モメンタム、終了時刻を扱い、スナップショットとストリーミングの両方に対応します。
主な機能
- 01名前付きの絞り込み・順位付けレシピ
- 02価格・裁定機会のスキャン
- 03出来高・スプレッド・モメンタムのスキャン
- 04RESTスナップショットとWebSocketストリーム
- 05市場・イベント・シリーズの検索
活用シーン
- 01価格やスプレッド条件に合う市場の検索
- 02出来高による市場の順位付け
- 03価格変動のリアルタイム監視
- 04イベント内の結果の比較
MCP 対応
APIパラメーター、ページネーション、レスポンス形式の確認に、https://pond.dflow.net/mcp のDFlow docs MCPを使います。スキャン自体はRESTまたはWebSocketでDFlow Metadata APIに問い合わせます。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dflowprotocol/ dflow-skills --skill dflow-kalshi-market-scannerインストール後、Claude Code で/dflow-kalshi-market-scannerを入力して読み込まれたか確認します。
詳細
DFlow Kalshi Market Scanner
条件に一致するKalshi市場を見つけます。このスキルは、DFlow Metadata APIに対する名前付きのスキャン(フィルターとランキングのレシピ)で構成されています。
前提条件
- DFlow docs MCP(
https://pond.dflow.net/mcp)— リポジトリのREADMEに従ってインストールしてください。このスキルはレシピであり、MCPはリファレンスです。正確なクエリパラメーター、ページネーション、レスポンスの形式など、フィールドレベルの情報はsearch_d_flow/query_docs_filesystem_d_flowで調べてください。推測しないでください。
対象
ここで紹介するすべてのスキャンはMetadata API(https://pond.dflow.net/resources/metadata-api)に対して実行します。これは、特定時点のクエリにはREST、継続的なストリームにはWebSocketを使用します。コマンドラインからの手早い curl、Node/Pythonスクリプト、cronジョブ、バックエンドサービス、ブラウザーUIのリクエストをプロキシするNext.jsルートなど、どこからでも両方を呼び出せます。
ユーザーが「ターミナルから実行して」と言った場合、dflow CLIは使わないでください。ディスカバリー用のサブコマンドはありません。代わりに、Metadata APIにアクセスする短いHTTP/WSスクリプトを作成してください。
スキャナーの基本構成
すべてのスキャンは、同じ4つのステップで構成されます。このパターンを基本にしてください。スキャンごとに作り直す必要はありません。
-
対象全体を列挙する —
GET /api/v1/markets(フラット形式)またはGET /api/v1/events?withNestedMarkets=true(グループ形式)を使用します。status=activeでフィルターします。完了するまでページを取得してください({ markets, cursor }形式に関するページネーションの注意点を参照)。ユーザーが「今すぐ」DFlowで取引可能な市場を求めている場合に限り、isInitialized=trueを指定してください(「注意点」を参照)。 -
市場ごとのシグナルを取得する。 最良気配値のスキャンでは、シグナルはすでに市場オブジェクトに含まれています。
yesBid/yesAsk/noBid/noAsk(小数点以下4桁の確率文字列)、volume24hFp/volumeFp/openInterestFp(ドル相当額の文字列)、closeTime(Unix時刻)があり、オーダーブックの呼び出しは不要です。モメンタムの分析には、ローソク足またはprices/tradesWebSocketチャンネルを使用します。注文板の厚みには/api/v1/orderbook/by-mint/{mint}を使用します。直近の約定には/api/v1/tradesまたはtradesチャンネルを使用します。 -
指標を計算する。
-
フィルターしてランキングする。 上位N件を返します(デフォルトは10件です。さらに多く必要かユーザーに確認してください)。
ポーリングとストリーミング
意図に合ったモードを選択します。
- ポーリング(REST) — ユーザーがスナップショットを求めている場合(「今すぐ上位10件を表示して」「Xに一致する市場をすべて一覧表示して」)に適しています。最新状態を保ちたい場合は、一定間隔で再実行します。
- ストリーミング(WebSocket) — ユーザーがイベント発生時にアクションを起こしたい場合(「YES+NOが1ドルを下回ったら通知して」「1分以内に5%以上動いた市場を知らせて」「Xが約定したら取引して」)に適しています。
wss://<host>/api/v1/wsで関連チャンネル(prices、trades、orderbook)を購読し、更新ごとに指標を計算します。ストリーミングの仕組み全般(再接続、バックオフ、サブスクリプションのライフサイクル)については、dflow-kalshi-market-dataに引き継いでください。
正確なエンドポイントパラメーター、チャンネルのペイロード、ページネーションについては、docs MCPを参照してください。
提案するスキャン
各スキャンは、ユーザーの質問と指標の組み合わせです。指標を基本構成に当てはめてください。
固定の数値しきい値より、順位に基づくフィルターを優先してください。 Kalshiの取引高は、アクティブな市場間で5桁以上の幅があります。固定のドル下限をハードコードすると、低すぎて素通りするか、高すぎてすべてを除外するかのどちらかになり、プラットフォームの成長に伴って状況も変わります。スキャンで「取引が活発」「安い」「大きく動いた」などを判定する必要がある場合は、ここに固定値を埋め込まず、スキャン結果(現在の対象全体におけるパーセンタイル)からしきい値を算出してください。
固定値を使うのは、意味上定まる場合に限ってください。たとえば、裁定取引における YES + NO < $1.00(調整可能なしきい値ではなく、裁定なしを成り立たせる不変条件)や、status=active(しきい値ではなく、フィールドの値)です。ユーザーが具体的な数値を指定した場合は、その数値を使ってください。ユーザーの表現が具体的なしきい値を示唆しているものの、その値がわからない場合(「かなりの取引高」「大きく動いた市場」など)は、推測せずにユーザーに確認してください。
1. アービトラージ — YES + NO < $1
「両方の側を合計1ドル未満で購入できる市場を探してください。」
- 指標:
parseFloat(yesAsk) + parseFloat(noAsk) < 1.00。裁定取引がないことを示す意味上のしきい値です。この値は固定してください。 - 順位付け:差額(
1 - sum)が大きい順です。 yesAskまたはnoAskのいずれかが null の行は除外してください(その側に未約定の売り注文がなく、実際のアービトラージではありません)。
2. ロングショットの YES
「実際に取引されている、安価な YES。」
parseFloat(volume24hFp)の降順で順位付けし、アクティブな市場の上位四分位を「実際に取引されている」市場群として選びます(スキャン結果から75パーセンタイルのしきい値を算出し、ドル金額をハードコードしないでください)。- その市場群の中で
parseFloat(yesAsk)の昇順に並べ、最も安いものから上位N件を返します。ユーザーが上限(「20¢未満」「3¢未満」など)を指定した場合はそれに従います。指定がなければ順位付けのみとし、セント単位の上限を勝手に設定しないでください。「安価」は固定の値ではありません。何をロングショットとみなすかは、ユーザーがどこまで許容するかによって異なります。 - 「期待ペイオフが最良」の場合は、別の順位付けとして
parseFloat(volume24hFp) / parseFloat(yesAsk)を使います。活発であることと安価であることを同時に考慮します。意図が曖昧な場合は、どちらを希望するかユーザーに尋ねてください。 - 出来高のない安価な市場は、ロングショットではなくゾンビ銘柄です。まず出来高で順位付けし、その後に価格を確認してください。この順序でノイズを除外します。
3. 近いうちに満期を迎える、ほぼ確実な YES
「97¢を超える YES のうち、まもなく終了するもの――セータを稼ぐ。」
- フィルター:
parseFloat(yesAsk)がユーザー指定のしきい値を超えるものです。「ほぼ確実」は表現であって数値ではありません。ユーザーが97¢と言った場合は0.97、99¢と言った場合は0.99を使います。数値を指定せず「ほぼ確実」とだけ言った場合は、どの水準を希望するか(95¢か99¢かなど)尋ねてください。デフォルトのしきい値を勝手に設定しないでください。 - 順位付け:
closeTimeの昇順で、終了が最も近いものを先にします。 - 上位N件を返します。ユーザーが期間(「48時間以内」「今週中」など)を指定した場合は、それを上書き条件として適用してください。デフォルトの期間を勝手に設定しないでください。
4. モメンタム
「直近1時間で何が動きましたか?」、または*「何かが動いたら知らせてください」*
- ポーリング:各市場について、最小間隔で
/api/v1/market/{ticker}/candlesticks(または/market/by-mint/{mint}/candlesticks)を呼び出し、最新の終値とN分前の終値を比較します。市場ごとに処理するためコストが高くなります。まず出来高上位に絞り込み(スキャン#6の順位を再利用し、出来高上位の市場からN件を選択)、その市場でモメンタムを計算してください。 - ストリーミング:
pricesチャネル(all: trueまたはティッカーのリスト)を購読し、メモリ内でローリング変化率を計算します。「Xが起きたらアラート」のパターンでははるかに低コストです。「市場がN%を超えて動いたら取引する」機能を組み込む場合もこの方法を使い、一致した市場をdflow-kalshi-tradingに渡します。 - ユーザー指定の期間における絶対変化率(両方向)または符号付き変化率(方向あり)で順位付けします。ユーザーが指定しない場合は60分をデフォルトにしますが、変化率のしきい値にデフォルトは設けません。上位N件を返します。ユーザーが「N%を超えて動いた」と言った場合、Nはユーザーが指定します。
5. ビッド・アスク・スプレッドが最も大きい市場
「非効率な市場――マーケットメイクするか、避けてください。」
- 指標:
parseFloat(yesAsk) - parseFloat(yesBid)(NO側も同様です)。 - 順位付け:スプレッドの降順です。
- データ元:市場オブジェクト。追加の呼び出しは不要です。
6. 出来高が最も多い市場
「どこが盛り上がっていますか?」
- 指標:
parseFloat(volume24hFp)(24時間のドル換算額)、またはカットオフ以降の/api/v1/tradesの合計(日中)。ライブフィードではtradesチャネルを購読し、ローリング期間で集計します。 - 順位付け:出来高の降順です。
7. 終了が最も近い市場
「セータのカウントダウン。」
- 指標:
closeTime - now。 - 順位付け:昇順です。
- スキャン3(「ほぼ確実かつ終了間近」)またはスキャン6(「出来高が多く、終了間近」)と組み合わせると、特に便利です。
8. イベント単位・シリーズ単位のスキャン
「このイベントの全アウトカムで最も安いYESは?」「相互排他的な結果の合計が1を超えているか?」
- 1つのイベント内(例:「FRBが金利をX bps引き上げる」で、結果ごとにバケットがある場合):
GET /api/v1/event/{eventTicker}?withNestedMarkets=trueを取得し、ネストされたマーケット全体を対象に集計します(min(yesAsk)、Σ yesAskなど)。イベントは、単一勝者のスキャンに適した自然な範囲です。 - シリーズ全体:
GET /api/v1/series/{seriesTicker}とそのイベントを取得し、集計します。 - シリーズやイベントに
mutuallyExclusiveフラグはありません。 結果全体のYESを合計する意味があるのは、結果が1つの将来の可能性を網羅する分割になっている場合(必ずいずれか1つが起こり、同時に複数は起こりえない場合)だけです。これはイベント/シリーズのタイトルと契約条件から判断するものであり、フィールドを参照してわかるものではありません。判断に迷う場合は、数値を提示し、その前提をユーザーに明示してください。
個別検索(N=1)
ユーザーが対象のマーケットをすでに決めている場合は、概要取得を省略します。
- ティッカー指定:
GET /api/v1/market/{ticker}(複数形ではなく単数形のmarket)。 - アウトカムのミント指定:
GET /api/v1/market/by-mint/{mint}(ハイフンではなくスラッシュ)。 - イベントティッカー指定:
GET /api/v1/event/{eventTicker}?withNestedMarkets=true(単数形のevent)。 - 自由入力テキスト:
GET /api/v1/search(自然言語からイベント/マーケットを検索)。
複数形(/markets、/events)はリストエンドポイントで、ページネーションには ?cursor=&limit= を指定します。単数形はIDによる個別検索です。取り違えると404になります。
ユーザーに尋ねること(尋ねてはいけないこと)
クエリの形式 — 曖昧でなければ推測し、曖昧なら確認します。
- どのスキャンか(または、スキャンに対応付けられる平易な言葉での意図)。
- ユーザーが指定する閾値 — 指定どおりに使います。 「> 5%」「2¢未満」「今週」などと言われた場合は、その数値を使います。指定がない場合は、各スキャンで定められた順位ベースのデフォルト(出来高の上位四分位など)を使います。独自の固定数値の閾値を提案してはいけません。 ユーザーの表現がスキャンで定義されていない閾値を示唆する場合(「大きく動いている」「相当な出来高」など)は、数値を推測せず、ユーザーに尋ねてください。
- ポーリングかストリーミングか — 「今すぐ見せて」のような意図ならREST、「通知して/発生したら反応して」のような意図ならWebSocketを使います。
- 上位N件(デフォルトは10件)。
インフラ — 必ず質問し、推測してはいけません。
- DFlow APIキー — スクリプトの検索/HTTP部分にのみ必要です。CLIのシェル呼び出しは独自に認証します(下記の「2つの認証経路」の注意点を参照)。簡潔で中立的な質問をしてください:「スキャナー/検索側で使うDFlow APIキーはありますか?」 キーの保存場所を決めつけてはいけません。「環境変数にありますか?」「
DFLOW_API_KEYは設定されていますか?」といった聞き方は、ユーザーが求めていない環境変数のデフォルトへ誘導してしまいます。選択肢を提示し、環境変数やdevへ暗黙にフォールバックしてはいけません。DFlowキーはどこでも同じものを使います。同じx-api-keyでTrade APIとMetadata API、RESTとWebSocketのすべてが利用できます。キーがある場合は、本番ホスト(RESTはhttps://prediction-markets-api.dflow.net、WSはwss://prediction-markets-api.dflow.net/api/v1/ws)を使い、すべてのリクエスト(RESTとWSのアップグレード)にx-api-keyを付けます。キーがない場合は、レート制限のあるdevホスト(https://dev-prediction-markets-api.dflow.net、wss://dev-prediction-markets-api.dflow.net/api/v1/ws)を使い、本番キーの取得先としてhttps://pond.dflow.net/get-started/api-keyを案内してください。スクリプトを生成する場合は、起動時に解決済みのホストとキーの有無をログに出力してください(Using prod Metadata API/Using dev Metadata API — rate-limited)。これにより、ユーザーはコードを読み込まなくても、どの接続先を使っているか確認できます。
尋ねてはいけないこと:
- RPC、ウォレット、署名 — このスキルは読み取り専用の公開メタデータを扱います。トランザクションはありません。
- 決済ミント/スリッページ/手数料 — これらは取引側の事項です。ユーザーが提示したマーケットでの注文に話題を移した場合は、
dflow-kalshi-tradingに引き継いでください。
注意点(ドキュメントMCPでは自発的に提示されない情報)
- 最良気配はマーケットオブジェクトにあります。
yesBid/yesAsk/noBid/noAskはすでに含まれています。最良価格を取得するためだけに、オーダーブックエンドポイントを繰り返し呼び出す必要はありません。 - 価格と出来高はマーケット全体に適用され、取引はレールごとに行われます。 初期化済みの各マーケットには、
market.accountsの下に USDC レールと CASH レールがあり、それぞれ独自のmarketLedger/yesMint/noMintを持ちます。スキャンのyesBid/yesAsk/volume24hFpは共有の Kalshi オーダーブックから取得され、どのレールで取引するかは示しません。dflow-kalshi-tradingに渡す際はマーケットティッカーを渡し、取引ステップでレールを選択させてください(デフォルト:USDC)。スキャン出力でレールを暗黙に事前選択しないでください。選択する場合は明示してください。 - オーダーブックが返すのはビッドのラダーのみです(
yes_bids、no_bids)。最良の YES アスク は1 - max(no_bids keys)で算出します(価格pの NO ビッドは、価格1-pの YES オファーです)。ラダーの厚みをユーザーが知りたい場合にのみ関係します。 - 価格スケールは 2 種類あります。 マーケット/オーダーブックの価格は、小数点以下 4 桁の確率文字列(
"0.4200")です。取引価格(REST とtradesチャネル)は 0~10000 の整数で、yes_price_dollars/no_price_dollarsの文字列フィールドも併せて含まれます。計算前に正規化してください。 market.titleは、多くの場合マーケット固有ではなくイベントレベルのタイトルです。 複数結果のイベント(候補者ごと、利上げ幅の区分ごと、試合の勝者ごとなど、結果ごとにマーケットがあるイベント)では、そのイベント配下のすべてのマーケットで同じtitleが共有されます。結果固有の表記はyesSubTitle(およびnoSubTitle)にあります。スキャン出力にtitleだけを表示すると、隣接する行が同じに見え、ユーザーがどの結果なのかを判別できません。title — yesSubTitleと表示してください(単純な二者択一マーケットで発生するように、yesSubTitleが null /空の場合はtitleのみを表示します)。マーケットを取引プロンプトに渡す場合も同様です。複数結果イベントでtitleだけを表示する「X に YES を購入」という確認は曖昧です。- 出来高フィールド — 文字列、ドル換算値、
volume24hはありません。 マーケットオブジェクトにはvolume(整数、累積の生単位)、volumeFp(文字列、累積ドル換算値)、volume24hFp(文字列、24 時間のドル換算値)があります。volume24hフィールドはありません。比較前に*Fpフィールドを必ずparseFloatで数値に変換してください。openInterest/openInterestFpも同じ形式です。 isInitializedフィルター。 短期間のマーケット(15 分間の暗号資産マーケットなど)は、Kalshi では取引可能でも DFlow ではまだトークン化されていないことがよくあります。このフィルターがないとスキャンに含まれますが、isInitialized=trueを指定すると、現時点で DFlow で取引可能なマーケットだけに絞られます。通常はtrueを指定します。- ビッド/アスクが null の場合。 流動性の低いマーケットでは、最良気配フィールドが null になります。これらを読み取るスキャンでは、null をゼロとして扱わず、必ずスキップしてください。
- メンテナンス時間帯 — Kalshi は**木曜日の午前 3:00~5:00(ET)**にオフラインになります。この時間帯には、最良気配や出来高のフィールドが古くなったり、欠落したりすることがあります。WS の更新が途絶えることもあります。この時間帯にスキャン結果が空になったり、不自然に間違って見えたりする場合は、それが原因です。
- ページネーションの形式。
/markets(および/events)は{ markets: [...], cursor: <number> }を返します。最初の呼び出しではcursorを省略するか、cursor=0を渡します。どちらも同じです。返されたcursorは次のページのオフセット(これまでの行数)です。次の呼び出しでは?cursor=Nとして渡してください。markets.length < limitになったら終了します(標準の方法)。next === cursorのチェックを追加しても問題ありませんが、通常は不要です。limitの上限は 255 です。limit=256以上では HTTP 400"number too large to fit in target type"が返されます(バックエンドではu8です)。ドキュメントでは控えめなデフォルトとして200を使用していますが、実際の上限は255です。ページネーションを行わない大規模なスキャンでは、一致した項目が通知なく欠落します。 - WebSocket の
all: trueは大量のデータを流します。 負荷の高いチャネル(特にprices)でall: trueを指定して購読すると、すべてのマーケットの更新がすべてストリーミングされます。スキャン対象が決まった集合の場合はティッカーリストを優先し、本当に全マーケットが対象のスキャンに限りall: trueを使用してください。 - 「スキャンしてから購入」は、対話式スクリプト 1 つで実行し、成果物を 2 つに分けません。 ユーザーがコマンドラインからマーケットを見つけ、その結果に基づいて操作したい場合は、スキャンして順位付きリストを表示し、ユーザーに 1 つ選択させ(または各行で y/N の確認を求め)、その後
dflow tradeを呼び出す単一のスクリプトを出力してください。非対話式のスキャンスクリプトを作成して、ユーザーに「1 つ選んで、自分でdflow tradeを実行してください」と伝えるのは避けてください。ユーザーに作業を中断させ、識別子をコピーさせることになります。Node のreadlineプロンプトや Python のinput()で問題ありません。行ごとのプロンプトなしで全自動化する場合も、スクリプトは 1 つにまとめ、「確認なし」で実行する動作を最初に明示してください。 dflow tradeに渡す形式。 スキャン結果はマーケットオブジェクトであり、そのまま CLI に渡せる呼び出し形式ではありません。CLI の--marketフラグにはmarket.accounts[<settlementMint>].marketLedgerのmarketLedgerを指定します。market.ticker、yesMint/noMint、トップレベルのミントではありません。ユーザーが CASH を指定しない限り、USDC レールをデフォルトにしてください(上記の「価格と出来高はマーケット全体に適用され、取引はレールごとに行われます」を参照)。YES と NO の購入には同じmarketLedgerを使用します。サイドの選択には--marketを変えるのではなく、--side yes|noを使用します。CLI 引数の詳しい形式(決済ミントからmarketLedgerを検索する方法、最小単位への変換、優先手数料フラグ、「整数単位で N 枚のコントラクトを購入する」イディオム)については、dflow-kalshi-tradingを参照してください。ここで改めて説明する必要はありません。- 複数のサーフェスを使うスクリプト:認証経路は 1 つではなく 2 つです。 このスキルと
dflow-kalshi-tradingを組み合わせる自然な方法は、Metadata API でマーケットを探索し、その後dflow tradeを呼び出して実行するスクリプトです。各処理は個別に認証します。- 探索(Metadata API HTTP) — 通常の
fetch/curlを使用します。スクリプトの環境変数または設定に DFlow API キーが必要です(#5 を参照)。キーがない場合は開発用ホストになり、レート制限が適用されます。 - 実行(
dflow tradeの呼び出し) — CLI がdflow setupで保存した情報(キー、ウォレット、RPC)を使用します。スクリプトから CLI 呼び出しに渡す情報はありません。 ユーザーが「CLI はすでに設定済みです」と言った場合、それでカバーされているのは実行側であり、発見側ではありません。API キーについては、「スキャナー/発見機能のために、DFlow API キーをお持ちですか?」 と尋ねてください。「CLI だけでは不十分なので、別のキーが必要です」 と伝えるのではありません。この 2 つは独立しています。DFlow キーは 1 つで、設定箇所は 2 つです。
- 探索(Metadata API HTTP) — 通常の
当てはまらない場合
上記でカバーされていない内容(すべてのパラメーターリスト、ページネーショントークン、レスポンススキーマ、WS の再接続仕様、まれに使うフィルター(スポーツ、タグ、カテゴリー、シリーズ検索)、ローソク足の間隔)については、ドキュメント MCP(search_d_flow、query_docs_filesystem_d_flow)に問い合わせてください。推測しないでください。
関連スキル
ユーザーが発見から実行に移る場合は、次のスキルに引き継いでください。
dflow-kalshi-trading— ここで見つけた市場で実際に購入/売却/償還します。dflow-kalshi-portfolio— ユーザー自身のポジションと損益を表示します。dflow-kalshi-market-data— 「名前付きスキャン」の形式以外で、一般的なリアルタイムのオーダーブック/取引/価格ストリーミングを扱います(再接続パターン、完全なペイロードスキーマ、試合中のライブデータ)。dflow-proof-kyc— ウォレットを検証し、提示した市場を実際に購入できるようにします。