DEV Community

Cover image for 世界最大の予測市場ポリマーケットのAPIデザインパターン
Akira
Akira

Posted on • Originally published at apidog.com

世界最大の予測市場ポリマーケットのAPIデザインパターン

予測市場は、APIを構築する上で技術的に最も要求の厳しい領域の一つです。有効期限のある金融商品、リアルタイムで価格が変動する確率、複雑な資本関係を持つ複数の結果を伴うイベント、そしてUIをクリックする人間とアービトラージ戦略を実行する自動取引ボットの両方を含むユーザーベースを扱います。あらゆる設計上の決定が即座にストレステストされます。

今すぐApidogを試す

現在、取引量で世界最大の予測市場プラットフォームであるPolymarketは、まさにこの理由から研究に値するAPIエコシステムを構築しています。それは単なるデータベース上のCRUD APIではありません。オープン性とセキュリティ、リアルタイムデータと履歴データ、伝統的な金融パターンと暗号通貨ネイティブのプリミティブという緊張関係を処理する、注意深く層化されたアーキテクチャです。

以下では、Polymarketの設計から抽出できる8つのパターンと、実装時に確認すべきポイントを説明します。


パターン1:ドメイン分離型APIレイヤー

Polymarketは、それぞれ明確なドメインを持つ3つのAPIを公開しています。

  • Gamma API (gamma-api.polymarket.com) — 市場発見、イベント、タグ、検索
  • CLOB API (clob.polymarket.com) — オーダーブックデータ、価格設定、注文発注
  • Data API (data-api.polymarket.com) — ユーザーポジション、取引、分析、リーダーボード

これは単なる命名規則ではありません。各APIには異なる認証要件、更新頻度、利用者プロファイルがあります。

  • Gamma APIは完全公開で、ブラウジングと発見に最適化されている
  • CLOB APIには公開エンドポイントと認証済みエンドポイントがある
  • Data APIは公開されているが、ウォレットアドレスを指定してポジションを照会する

設計上の教訓は、エンティティではなくドメインでAPIを分離することです。

素朴な設計では、/markets/orders/usersをすべて1つのAPIにまとめがちです。しかし実際には、発見・取引・分析ではアクセスパターンもレイテンシー要件も異なります。

実装チェックリスト

APIを分割する際は、リソース名ではなく次の問いで境界を決めます。

  1. このAPIの主な利用者は誰か
  2. 読み取り中心か、書き込み中心か
  3. 低レイテンシーが必要か
  4. 認証・認可の要件は何か
  5. 独立してスケール、デプロイ、変更する必要があるか

たとえば、次のようにベースURLごとに責務を切り分けると、クライアント実装も明確になります。

const gammaBaseUrl = "https://gamma-api.polymarket.com";
const clobBaseUrl = "https://clob.polymarket.com";
const dataBaseUrl = "https://data-api.polymarket.com";
Enter fullscreen mode Exit fullscreen mode

パターン2:パブリックファーストのデータアクセス

市場データ(価格、オーダーブック、イベントメタデータ、履歴取引)に関する情報は完全に公開されています。

curl "https://gamma-api.polymarket.com/events?limit=5"
Enter fullscreen mode Exit fullscreen mode

APIキーもOAuthも不要です。読み取りエンドポイントにレート制限もありません。必要なデータをすぐに取得できます。

これは、伝統的な金融プラットフォームとは異なる選択です。多くの取引所は市場データを収益源として保護します。一方でPolymarketは、市場データをインフラとして扱っています。

より多くの開発者がデータを読み取り、その上にアプリケーションや分析ツールを構築できれば、市場の流動性と有用性は高まります。

実装の原則

認証をすべてのエンドポイントへ一律に適用するのではなく、読み取りと書き込みを分けて設計します。

公開:
- 市場一覧
- イベント詳細
- 現在価格
- オーダーブック
- 履歴取引

認証必須:
- 注文作成
- 注文キャンセル
- 残高操作
- アカウント設定の変更
Enter fullscreen mode Exit fullscreen mode

データ消費がデータ生成を大きく上回るサービスでは、この分離が重要です。市場価格の取得に資格情報を要求しなければ、最初のAPI呼び出しまでの摩擦を大幅に減らせます。

認証は、実際に高リスクな操作を行うタイミングで追加します。


パターン3:真の信頼を反映する2段階認証

取引エンドポイントには認証が必要です。しかしPolymarketの認証モデルは、目的の異なる2つのレベルに分かれています。

L1認証は、ユーザーの秘密鍵から生成するEIP-712署名です。これはウォレットの所有権を証明し、API資格情報を導出するために1回、または低頻度で使用します。

// L1: 秘密鍵を使用してAPI資格情報を導出する
const credentials = await client.createOrDeriveApiKey();

// → { key: "...", secret: "...", passphrase: "..." }
Enter fullscreen mode Exit fullscreen mode

L2認証は、導出済み資格情報によるHMAC-SHA256署名です。日常的な取引リクエストごとに添付します。

// すべての取引リクエストのL2ヘッダー
{
  "POLY_ADDRESS": "0x...",
  "POLY_SIGNATURE": "<hmac-sha256>",
  "POLY_TIMESTAMP": "1716000000",
  "POLY_API_KEY": "550e8400-...",
  "POLY_PASSPHRASE": "..."
}
Enter fullscreen mode Exit fullscreen mode

重要なのは、異なる操作には異なるセキュリティ強度が必要だという点です。

  • API資格情報の作成: ウォレットを制御していることを証明する高リスク操作
  • 注文リクエスト: 高頻度で発生するため、軽量なセッション資格情報を使う操作

実装の考え方

このモデルは暗号通貨以外にも適用できます。

レベル 目的
L1 本人性・所有権の強い証明 秘密鍵署名、パスキー、ハードウェアトークン
L2 個別リクエストの署名・検証 HMAC、短命トークン、セッション資格情報

実装上は、L1資格情報を通常のリクエストパスに置かないことが重要です。秘密鍵や強い認証情報を毎回使う設計は、性能面だけでなく秘密情報の露出範囲も広げます。


パターン4:API呼び出しではなく、署名付きメッセージとしての注文

予測市場が従来のAPI設計と大きく異なるのは注文処理です。

Polymarketで注文を出すとき、単にサーバーへ注文データを送っているわけではありません。強制力のある金融コミットメントとなる暗号署名付きメッセージを作成しています。

const response = await client.createAndPostOrder(
  {
    tokenID: "71321045679...",
    price: 0.65,
    size: 100,
    side: Side.BUY,
  },
  {
    tickSize: "0.01",
    negRisk: false,
  },
  OrderType.GTC
);
Enter fullscreen mode Exit fullscreen mode

内部ではSDKがEIP-712型データ構造を構築し、秘密鍵で署名してから注文を送信します。

マッチングエンジンはオフチェーンで動作しますが、注文がマッチングされると、それらの署名を使用してPolygon経由でオンチェーン決済されます。オペレーターは取引を捏造したり、資金を移動したりできません。署名済みメッセージ自体が承認となるためです。

API設計への応用

通常のAPIでは、エンドポイントへのPOSTは次の意味になります。

私の代わりにこの操作を実行してください。

署名済み注文では、意味が変わります。

この取引を承認する署名済みの証書です。

このモデルでは、APIは意思決定を行う主体ではなく、暗号的に承認済みのメッセージを中継する役割になります。

金融システム、法的文書、高リスクな管理操作では、トランスポート層の認証だけでなく、ペイロード自体に承認情報を持たせる設計を検討できます。


パターン5:データモデルにおける明示的なオントロジー

Polymarketは、イベントマーケットという2つのオブジェクトを中心にデータを構築しています。この区別は重要です。

  • イベント: 質問やテーマ 例: 「2026年のペンシルベニア州上院選で誰が勝つか?」
  • マーケット: イベント内で取引可能な個別のバイナリ結果 例: 「ボブ・ケーシーは勝つか?」

1つのイベントには、複数のマーケットが含まれる場合があります。

{
  "id": "501",
  "title": "2026 Pennsylvania Senate Race",
  "negRisk": true,
  "markets": [
    {
      "id": "2301",
      "question": "Will Bob Casey win?",
      "outcomePrices": "[\"0.42\", \"0.58\"]"
    },
    {
      "id": "2302",
      "question": "Will Dave McCormick win?",
      "outcomePrices": "[\"0.35\", \"0.65\"]"
    },
    {
      "id": "2303",
      "question": "Will a third candidate win?",
      "outcomePrices": "[\"0.23\", \"0.77\"]"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

これは明示的なオントロジーです。APIは単にデータを保存するのではなく、エンティティ間の概念的な関係をエンコードしています。

たとえば価格は、インデックス位置を結合規則とする並列配列として表現されます。

outcomes[0]      <-> outcomePrices[0]
outcomes[1]      <-> outcomePrices[1]
Enter fullscreen mode Exit fullscreen mode

また、イベントレベルのnegRiskフラグは、各マーケットが独立していないこと、つまり資本上の関係があることを示します。

実装時の注意

自動取引クライアントを作るなら、関係性を無視してデータを平坦化しないことが重要です。

type Market = {
  id: string;
  question: string;
  outcomePrices: string;
};

type Event = {
  id: string;
  title: string;
  negRisk: boolean;
  markets: Market[];
};
Enter fullscreen mode Exit fullscreen mode

特にnegRisk: trueを見落とすと、誤ったポジションモデルを構築する可能性があります。ドメイン上重要な関係は、クライアントの型と検証ロジックにも反映させるべきです。


パターン6:NegRisk — 資本関係を第一級の懸念事項として扱う

イベントのnegRiskフラグは、Polymarketの興味深いAPI設計パターンの一つです。金融上の等価性をプログラマブルにしています。

標準的な複数結果イベントでは、各マーケットは独立しています。

しかしNegRiskイベントでは、正確に1つの結果だけが勝つため、ポジション間に数学的な関係が存在します。

結果AのNoトークン1つ ≡ 他のすべての結果のYesトークン1つ

これは単なる数学上の説明ではありません。スマートコントラクトで実装され、APIを通じて明示されています。

たとえばペンシルベニア州上院選で「その他」のNoポジションを保有している場合、次のように変換できます。

変更前 変更後
1× No (その他) 1× Yes (ケーシー) + 1× Yes (マコーミック)

APIでは、この関係が2つの場所で明示されます。

  1. マーケットオブジェクトのnegRisk: true
  2. 注文作成時のオプションで指定するnegRisk: true
const orderOptions = {
  tickSize: "0.01",
  negRisk: true,
};
Enter fullscreen mode Exit fullscreen mode

これを誤ると、注文は拒否されるか、誤って決済されます。

実装の原則

ドメイン不変条件をドキュメントの脚注だけに残さず、型付きAPIフィールドとしてエンコードすることが重要です。

negRiskは便利な補助情報ではありません。省略すると誤動作につながる、取引の正しさに関わる状態です。

次のような制約があるドメインでは、制約をAPIサーフェスに出すべきです。

  • 1つの結果だけが成立する
  • ポジション間に変換可能な等価性がある
  • 複数のリソースが同じ資本を共有する
  • 操作の順序によって有効性が変わる

パターン7:市場の状態としての動的なティックサイズ

多くの金融APIはティックサイズを静的な設定として扱います。Polymarketでは、ティックサイズが市場価格に基づいて動的に変化し、APIがその変更をリアルタイムイベントとして公開します。

市場価格が極端な値、つまり0.96以上または0.04以下に近づくと、最小ティックサイズは0.01から0.001に狭まります。

{
  "event_type": "tick_size_change",
  "asset_id": "65818619657...",
  "old_tick_size": "0.01",
  "new_tick_size": "0.001",
  "timestamp": "100000000"
}
Enter fullscreen mode Exit fullscreen mode

理由は明確です。極端な確率では、1セントのティックは大きすぎます。

0.04 -> 0.03 は 25% の変動
Enter fullscreen mode Exit fullscreen mode

この粒度では意味のある価格発見が難しくなります。極端な値の近くでティックを細かくすれば、97%に丸めるのではなく、97.3%のような確率を表現できます。

クライアント実装例

ティックサイズをハードコードせず、市場ごとの状態として保持します。

const tickSizeByAsset = new Map<string, string>();

function handleTickSizeChange(event: {
  asset_id: string;
  new_tick_size: string;
}) {
  tickSizeByAsset.set(event.asset_id, event.new_tick_size);
}
Enter fullscreen mode Exit fullscreen mode

注文作成時には、最新の状態を参照します。

function getOrderOptions(assetId: string, negRisk: boolean) {
  return {
    tickSize: tickSizeByAsset.get(assetId) ?? "0.01",
    negRisk,
  };
}
Enter fullscreen mode Exit fullscreen mode

ティックサイズ変更イベントを購読せず、常に0.01を使う実装では、注文が拒否される可能性があります。

設計上の教訓

金融システムでは、状態を第一級の概念として扱う必要があります。

  • 市場パラメータは変化する
  • 解決ルールは更新される
  • 結果は明確化される
  • 取引可能な条件は動的に変わる

APIはこれらの状態遷移を明示的に伝えるべきです。クライアントがエラー応答を受け取って初めて変化に気づく設計は避けるべきです。


パターン8:異なる利用者プロファイルのための2つのWebSocketレイヤー

Polymarketは2つの別々のWebSocketシステムを運用しています。この分離は、利用者ごとの要求が異なることを反映しています。

マーケットチャンネルwss://ws-subscriptions-clob.polymarket.com/ws/market)は、取引利用者向けです。

トークンIDでサブスクライブし、以下のような情報を受信します。

  • オーダーブックのスナップショット
  • 価格変動
  • 取引約定
  • ティックサイズ変更

すべてはアセットIDに紐付き、低レイテンシーの注文構築に最適化されています。

{
  "assets_ids": [
    "65818619657568813474341868652308942079804919287380422192892211131408793125422"
  ],
  "type": "market"
}
Enter fullscreen mode Exit fullscreen mode

リアルタイムデータソケットwss://ws-live-data.polymarket.com)は、別の利用者プロファイル向けです。

  • コメント
  • BinanceおよびChainlinkからの暗号通貨価格
  • 株式価格
  • ソーシャルインタラクションイベント

こちらはトピック単位でサブスクライブします。

{
  "action": "subscribe",
  "subscriptions": [
    {
      "topic": "crypto_prices",
      "type": "update",
      "filters": "btcusdt,ethusd"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

なぜWebSocketを分けるのか

2つの利用者は、求める品質特性が根本的に異なります。

利用者 必要なデータ 主な要求
マーケットメーカー オーダーブック差分、約定、ティックサイズ 低レイテンシー、一貫性
UI・ダッシュボード コメント、価格、ソーシャルイベント 広い情報量、購読の柔軟性

これらを1つのWebSocketエンドポイントに統合すると、どちらかが犠牲になります。

  • ソーシャルフィードを取引グレードのレイテンシー要件で過剰設計する
  • オーダーブックをソーシャルフィード相当の信頼性で扱ってしまう

実装の原則

リアルタイム利用者に、次のような意味のある差があるなら、インフラも分けるべきです。

  • レイテンシー許容度
  • データ量
  • メッセージ形式
  • 再接続戦略
  • 順序保証の要件
  • 障害時の許容範囲

複数目的を満たそうとする共有WebSocketは、複雑さでは最大公約数になり、性能では最小公約数になりやすいです。


これらのパターンに共通すること

PolymarketのAPI設計は、APIがドメインの実際の構造を抽象化して隠すのではなく、可視化すべきだという哲学を反映しています。

  • 3層アーキテクチャは実際のドメイン境界に対応している
  • パブリックファーストのアクセスは予測市場の価値の流れを反映している
  • 2段階認証は本人確認と行動承認の違いを反映している
  • 署名付きメッセージとしての注文は非カストディアルな保証をエンコードしている
  • イベント/マーケット階層とNegRiskフラグは、見えにくい関係性を公開している
  • 動的ティックサイズはクライアント状態を市場状態と同期させる
  • 分離されたWebSocketレイヤーは異なるオーディエンスに対応している

多くのAPI設計の議論は、エルゴノミクスに焦点を当てます。

  • 呼び出しやすいか
  • 命名は一貫しているか
  • エラー処理は予測可能か
  • SDKは使いやすいか

これらは重要です。しかしPolymarketのより興味深い点は、ドメインへの忠実性です。

ドメインに意味のある区別があるなら、APIもそれを表現します。ドメインに制約があるなら、APIもそれを強制します。ドメインに変化する状態があるなら、APIもそれをブロードキャストします。

その結果、利用者により多くの理解を要求するAPIになります。しかし、正しく実装すれば、クライアントは取引対象のシステムを実際に理解できます。

予測市場では、価格が情報を反映することが重要です。市場の構造を理解することを要求するAPIは、その目的に沿った設計だといえます。

Top comments (0)