第27章 / 33
短縮版
ポリマーケット は 3つの公開API を提供しています: CLOB (取引), Gamma (市場の発見), Data (分析) です。公式の Python SDK は py-clob-client 0.34.6 です。認証は APIキー + ECDSA署名 を使用し、注文は Polygon のプロキシウォレットを通じて EIP-712 で署名されます。レート制限は1キーあたりおおむね 60注文/分 です。新しい開発者にとって最大の落とし穴は、Gamma と CLOB の間にある condition_id → token_id の対応付けです - まずそこを解決すれば、他はすべてうまく進みます。ポリマーケット では、月あたりおよそ $40M の流動性報酬とボットが獲得したスプレッドが発生しており、そのほぼすべてが API ユーザーによって得られています。
パート1: 3つのAPI
ポリマーケットは、3つの異なるサービスにまたがって役割を明確に分離しています。各作業に適切なAPIを使うことで、ボットは高速でシンプルになり、レート制限の範囲内に収まります。
| API | ベースURL | 用途 | 認証が必要 |
|---|---|---|---|
| CLOB API | clob.polymarket.com | 注文の発注、キャンセル、追跡。オーダーブックの読み取り。ポジションの照会。 | はい(取引時) |
| Gamma API | gamma-api.polymarket.com | 市場の閲覧、メタデータ、画像、結果価格、出来高、満期、タグの取得。 | いいえ(公開) |
| Data API | data-api.polymarket.com | 過去の取引、ポジションのスナップショット、ユーザー分析、リーダーボードデータ。 | いいえ(公開) |
典型的なボットのループでは、Gammaで市場を見つけ、CLOBでオーダーブックを取得して取引を行い、Dataで戦略のパフォーマンスをオフラインでバックテストします。Gammaは「カタログ」、CLOBは「取引所」、Dataは「倉庫」と考えるとよいでしょう。
curlやブラウザで確認できます - アカウントは不要です。これは、APIキーを生成する前のプロトタイピングに最適な方法です。第2部: 認証とプロキシウォレットモデル
ポリマーケットは、あなたのメインウォレットの秘密鍵で取引に署名しません。代わりに、Gnosis Safe風のプロキシウォレットを使用します。あなたのメインウォレットがプロキシを承認し、そのプロキシがPolygon上で全ての取引を実行します。あなたのAPIボットはそのプロキシと通信します。
必要なもの
- API key - ポリマーケット Settings → Developerで生成
- Private key - あなたの取引用ウォレットの鍵です(メインのMetaMaskシードフレーズではありません)
- Funder address - あなたのプロキシウォレットアドレス(Settings → Walletに表示)
- Chain ID -
137(Polygonメインネット) - Signature type -
1(POLY_PROXY、個人ユーザー向けの標準)
.env)またはシークレットマネージャーを使用してください。Discord、GitHubのissue、ChatGPTに鍵を貼り付けないでください。クリップボードに触れた鍵はすでに漏洩していると考えてください。少しでも疑わしい場合は鍵をローテーションしてください。Part 3: py-clob-client のインストール
公式の Python SDK は、ゼロから最初の注文まで最速で進める方法です。ここでは、2026年4月時点で最新の 0.34.6 を使います。
# まず仮想環境を作成します
python3 -m venv venv
source venv/bin/activate # macOS/Linux
venv\Scripts\activate # Windows
# SDK をインストールします
pip install py-clob-client==0.34.6 requests websocket-client python-dotenv基本的なクライアント設定
import os
from dotenv import load_dotenv
from py_clob_client.client import ClobClient
from py_clob_client.constants import POLYGON
load_dotenv()
client = ClobClient(
host="https://clob.polymarket.com",
key=os.environ["POLY_PRIVATE_KEY"],
chain_id=POLYGON, # 137
signature_type=1, # POLY_PROXY
funder=os.environ["POLY_FUNDER"],
)
# 一度だけ: API認証情報を導出してキャッシュする
client.set_api_creds(client.create_or_derive_api_creds())create_or_derive_api_creds() の呼び出しは、秘密鍵でメッセージに署名し、それを APIキー、シークレット、パスフレーズと交換します。起動のたびに導出エンドポイントへアクセスしないよう、最初の実行後にこれらを .env にキャッシュしてください。
POLY_PRIVATE_KEY=0xabc...
POLY_FUNDER=0xdef...
POLY_API_KEY=...
POLY_SECRET=...
POLY_PASSPHRASE=...第4部: Gammaを通じてマーケットを見つける
取引を始める前に、取引する価値のあるマーケットを見つける必要があります。Gammaは、ポリマーケットのUIに表示されるすべての情報を含むJSONを返します - 質問、結果、価格、24時間出来高、満期、タグ、画像です。
import requests
resp = requests.get(
"https://gamma-api.polymarket.com/markets",
params={
"active": "true",
"closed": "false",
"tag_slug": "politics",
"limit": 20,
"order": "volume24hr",
"ascending": "false",
},
timeout=10,
)
resp.raise_for_status()
markets = resp.json()
for m in markets:
print(f"{m['slug']:50} Yes ${float(m['outcomePrices'][0]):.3f} Vol24h ${m.get('volume24hr', 0):,.0f}")Gammaで使えるクエリパラメータ
| パラメータ | 機能 |
|---|---|
tag_slug | カテゴリで絞り込みます(politics, sports, crypto, culture など) |
active=true | 現在取引を受け付けているマーケットのみ |
closed=false | 解決済みのマーケットを非表示にします |
order=volume24hr | 直近の出来高で並べ替えます(流動性のシグナル) |
end_date_min | ISO日付 - すぐに解決されるマーケットを除外します |
limit | 1ページあたり最大500件(ページネーションにはoffsetを使用) |
第5部: condition_id → token_id のマッピング
これは ポリマーケット のボット開発における最大の痛点です。Gamma は condition_id を返します - これはマーケットごとに1つです。CLOB の取引では token_id を使います - これは結果ごとに1つです。常に両方が必要です。
condition_id を、token_id を期待する CLOB エンドポイントに渡すことです。不可解な "invalid token" エラーが出ます。必ず先にマッピングし、後で取引してください。# 各 Gamma マーケットオブジェクトには 'clobTokenIds' が含まれている - JSON 文字列配列
import json
market = markets[0]
token_ids = json.loads(market['clobTokenIds']) # ['7410...', '1120...']
yes_token = token_ids[0] # 1つ目の結果
no_token = token_ids[1] # 2つ目の結果
# 代替方法: condition_id を使って CLOB に直接問い合わせる
info = client.get_market(condition_id=market['conditionId'])
yes_token = info['tokens'][0]['token_id']結果の並び順の落とし穴
Gamma の outcomes 配列と clobTokenIds 配列はインデックスが対応しています。必ず 0番目のインデックスが "Yes" だと決めつけず、結果ラベルを確認してください。マルチアウトカム市場(NegRisk、Oscars、選挙)では、0番目のインデックスが "Kamala Harris" や "Taylor Swift" になることがあります - 順序は決定的ですが、マーケットごとに異なります。
第6部: オーダーブックの読み方
book = client.get_order_book(token_id=yes_token)
best_bid = float(book.bids[0].price) if book.bids else None
best_ask = float(book.asks[0].price) if book.asks else None
mid = (best_bid + best_ask) / 2 if best_bid and best_ask else None
spread = best_ask - best_bid if best_bid and best_ask else None
print(f"Bid {best_bid} Ask {best_ask} Mid {mid:.4f} Spread {spread:.4f}")オーダーブックはソート済み配列として返されます(bidsは降順、asksは昇順)。各レベルには price と size があります。大きな注文のスリッページを見積もるには、オーダーブックをたどって、目標サイズを消化するまで約定金額を積み上げます。
パート7: 注文の出し方
指値注文 (GTC - デフォルト)
from py_clob_client.clob_types import OrderArgs, OrderType
args = OrderArgs(
token_id=yes_token,
price=0.45,
size=100, # 株数であり、ドルではありません。100株 @ $0.45 = 最大コスト $45。
side="BUY",
)
signed_order = client.create_order(args)
response = client.post_order(signed_order, OrderType.GTC)
print(response)create_order 呼び出しは、あなたの秘密鍵で EIP-712 構造化メッセージに署名します。post_order はそれを CLOB に送信します。生の秘密鍵をネットワーク越しに送ることはありません - 送信されるのは署名済み注文だけです。
注文タイプ
| タイプ | コード | 動作 | 使用する場面 |
|---|---|---|---|
| Good Till Cancelled | GTC | 約定するかキャンセルするまでオーダーブックに残る | デフォルト。多くのメイカー取引や指値戦略。 |
| Good Till Date | GTD | 指定したタイムスタンプで自動キャンセル | イベント駆動 - 「FRB発表の5分前にキャンセル」 |
| Fill or Kill | FOK | 全数量が直ちに約定しなければ完全キャンセル | 一部約定では取引が崩れるアービトラージの足 |
| Fill and Kill | FAK | 指値価格で約定可能な分だけ約定し、残りはキャンセル | 積極的なテイキング - 価格上限付きの成行注文のように動作 |
キャンセル
# 単一注文
client.cancel(order_id="0xabc...")
# 特定市場の全注文をキャンセル
client.cancel_market_orders(market=market['conditionId'])
# 最終手段: すべてキャンセル
client.cancel_all()パート 8: WebSocketストリーミング
毎秒Gammaをポーリングするのは無駄で、すぐにレート制限に達します。WebSocketフィードは、リアルタイムのオーダーブックと取引の更新を、サブ秒レイテンシでストリーミングします。
import json, websocket
WS_URL = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
def on_open(ws):
ws.send(json.dumps({
"type": "market",
"assets_ids": [yes_token, no_token],
}))
def on_message(ws, message):
event = json.loads(message)
if event.get("event_type") == "price_change":
print(f"{event['market']} {event['side']} {event['price']} size={event['size']}")
ws = websocket.WebSocketApp(
WS_URL,
on_open=on_open,
on_message=on_message,
)
ws.run_forever(ping_interval=20)フィードは2つあります: /marketフィード(公開オーダーブック + 取引)と /userフィード(あなた自身の注文と約定イベント、認証済み)です。実運用のボットは通常、両方に接続し、切断時には自動的に再接続し、現在の板状態の正確な情報源としてWebSocketを扱います。
パート9: レート制限とバックオフ
| エンドポイントのクラス | 制限 | Burst |
|---|---|---|
| 注文発注 (CLOB) | APIキーごとに約60回/分 | 約10回/秒 |
| 注文キャンセル | 約120回/分 | 約20回/秒 |
| 市場データの読み取り (CLOB book) | 約300回/分 | 高め、変動あり |
| Gamma API | 寛大 - 429には従う | - |
| WebSocketメッセージ | 実質的な受信側の制限なし | - |
HTTP 429に達すると、サーバーはRetry-Afterヘッダーを返します。ジッター付きの指数バックオフを実装してください:
import random, time
def post_with_backoff(fn, *args, max_retries=6):
for attempt in range(max_retries):
try:
return fn(*args)
except Exception as e:
if "429" in str(e):
sleep = (2 ** attempt) + random.random()
time.sleep(min(sleep, 30))
continue
raise
raise RuntimeError("Too many retries")パート10: 参照用ボットアーキテクチャ
堅牢なポリマーケットボットは、すべて同じ6つのコンポーネントを持ちます。各コンポーネントは独自のモジュールとして実装し、疎結合に保ってください。
| コンポーネント | 責務 | 使用API |
|---|---|---|
| スキャナー | スケジュール済みジョブ: 条件に合う市場を取得する(タグ、出来高、満期までの日数) | Gamma |
| 価格エンジン | WebSocket経由でリアルタイムのローカルオーダーブックを維持する | CLOB WS |
| シグナル生成器 | 純粋関数: ブック状態 + メタデータ → 目標ポジション | - (メモリ内) |
| オーダーマネージャー | 現在の注文と目標の差分を取り、最小限の発注/キャンセルを行う | CLOB REST |
| リスクマネージャー | 市場ごとの上限、日次損失上限、サーキットブレーカーを適用する | - (メモリ内 + DB) |
| ロガー & 台帳 | すべての判断、約定、キャンセルを永続化する。税務レポートとデバッグの元データになる。 | SQLite / Postgres |
パート11: よくある失敗モード
- 古いWebSocketデータ - 資産ごとに最後のメッセージ時刻を追跡する。アクティブな市場で30秒を超えて更新がなければ、REST更新を強制する。
- Nonceの衝突 - py-clob-clientが注文nonceを処理してくれるが、自前で署名処理を書くなら、注文ごとにnonceを増分する。
- 残高不足 - 発注前に必ずpUSD残高を確認する。ブック上では注文が見えても、マッチング時に拒否されることがある。
- 市場が停止または清算中 - 取引前に
market.active && !market.closedを確認する。清算前後ではGammaの更新がCLOBより数秒遅れる。 - NegRiskアダプターの不一致 - マルチアウトカム市場は別のNegRiskアダプターを経由する。SDKが処理するが、注文が正しい取引先に送られたか確認する。
パート12: API経由の流動性報酬
ポリマーケットは、一般向け流動性報酬として月約500万ドル、さらにスポーツ特化の報酬として月500万ドル超を実施しています(流動性報酬を参照)。その大半は、何千もの市場にわたってタイトな両建て気配を維持できるAPI駆動のマーケットメイカーに流れます。
報酬の計算式は、ミッドポイント付近の注文、サイズ、そして板に載っている時間を評価します。最小限のマーケットメイクのループは次のとおりです:
- 対象市場のオーダーブックを読む
- 公正なミッドポイントを計算する(例: 各側上位3段のVWAP)
mid − spread_target/2で買い気配を出し、mid + spread_target/2で売り気配を出す- 各WebSocket更新ごとに、気配が目標から1ティック以上ずれたら再価格設定する
- 板が薄くなるかニュースが出たら、キャンセルして撤退する
パート13: 本番運用へ進む
- ホスティング: 月6ドルのVPS(Hetzner、DigitalOcean)をヨーロッパまたはUS-Eastに置けば、ほとんどのボットには十分です。10ms未満のレイテンシが必要なら、Polygon RPCの近くに配置してください。
- RPC: 信頼性の高いPolygon RPCにはAlchemy、Infura、またはQuickNodeを使ってください。1分あたり数百注文を出すようになるまでは無料枠で十分です。
- 監視: メトリクスにはPrometheus + Grafana、アラートにはTelegram botを使います。送信したすべての注文IDと受け取ったすべての約定を記録してください。
- バックアップ: 状態を毎分永続化すること。VPSが約定途中で落ちても、手作業で突き合わせるのではなく、数秒で再開したいはずです。
- 税務: ロガーは監査証跡でもあります - 税務ガイドを参照してください。
パート14 - ポリマーケット APIの検証済みプロのヒント
- 最初のderive呼び出し後にAPI認証情報をキャッシュする -
create_or_derive_api_creds()はレート制限があり遅いです。apiKey/secret/passphraseを.envに保存し、起動時に読み込みます。 - 最初にブラウザウォレットを接続したなら signature_type=2 (GNOSIS_SAFE) を使う。Magic-linkメールアカウントには signature_type=1 (POLY_PROXY) を使います。型が不一致だと401 "invalid api key." が返ります。
funderはEOAではなくポリマーケットのプロキシウォレットアドレスに設定する。署名鍵はEOAにあり、資金はプロキシにあります。ここを混同するのが認証バグの第1位です。- アウトカムは位置ではなくラベルで索引する -
clobTokenIds[outcomes.index("Yes")]を使い、clobTokenIds[0]は使わないでください。NegRiskとOscarの市場では順序が任意です。 - 署名前に時計を同期する - POLY_TIMESTAMPは狭い時間窓内に収まっている必要があります。安価なVPSでNTPがずれると、認証が静かに壊れます。chronyまたはsystemd-timesyncdを実行してください。
- WebSocket再接続のたびにRESTブックを再取得する。再サブスクライブ前に必ず行ってください。WebSocketは差分を返します。再接続中に差分を取りこぼすと、ローカルブックが実態からずれ、不利な価格を提示してしまいます。
- 1秒あたり10注文を超えてバーストさせない - /orderエンドポイントは500/10秒のバースト、3,000/10分の継続でスロットルします。クライアント側でトークンバケット型のレート制限を入れてください。Cloudflareは破棄せずキューするので、盲目的なリトライは待ち行列を悪化させます。
- 停止時には
cancel_all()ではなくcancel_market_orders(market=conditionId)を使う。市場単位のキャンセルは冪等で、ボットが1つの市場でループ途中にクラッシュした場合でも安全です。 - 資産ごとに
heartbeatMsを追跡する - ライブ市場で30秒更新がない市場を強制更新するウォッチドッグを追加してください。古いWSフィードは、見せかけの優位性の最も一般的な原因です。 - 送信前に注文IDを記録する。送信後ではありません。冪等性には、クラッシュ復旧時に重複約定なしで再送できるよう、クライアントがIDを管理している必要があります。
- HeartBeats API(Jan 2026+) を切断時自動キャンセルに使う。ハートビート間隔を5秒に設定します。サーバーは2回ハートビートを取りこぼすと、待機中の全注文をキャンセルします。
- 本番投入前に、薄い市場で1ドル注文によるPaper-tradeを48時間行う。ポリマーケットにはテストネットがありません。認証、署名、約定処理、キャンセルの流れを検証する唯一の確実な方法は、小額の実注文です。
状況 → 対応チートシート
| 状況 | 対応 | 理由 |
|---|---|---|
| 最初の呼び出しで401 "invalid api key" | signature_typeがウォレットの種類と一致し、funderがプロキシアドレスであることを確認する | Type 1と2の不一致が401エラーの80%を占め、EOAをfunderにするのが残りです |
| 注文が "insufficient balance" で拒否される | すべての注文の前に /balance-allowance を問い合わせ、ローカルで予約する | CLOBは発注した瞬間に担保を予約するため、同時注文2件で二重予約されることがある |
| /orderエンドポイントで429スロットリング | ジッター付きでバックオフする: 2^attempt + random()、上限30秒 | Cloudflareは拒否ではなくスロットリングするため、素朴なリトライは待ち行列を悪化させる |
| 取引中にWebSocketが切断された | RESTでブックをスナップショットし、ローカル状態を突き合わせてから再サブスクライブする | ギャップ中の差分は失われるため、スナップショットで価格帯を再同期する |
| 注文は出たが約定確認がない | 5秒以内に /data/order/{id} を問い合わせる。pendingなら待ち、見つからなければ置き換える | 稀だが復旧可能。デフォルトは「状態を確認してから動く」 |
| アクティブな気配の最中に市場が清算された | 清算イベントでそのconditionIdの未約定注文をすべてキャンセルする | 清算後の注文は、アダプターの癖でゾンビ約定として残ることがある |
| マーケットメイクボットを運用している | ミッドポイントの2セント以内、100株以上で気配を出す | 報酬式はタイトさ + サイズ + 板に載っている時間を重視する。タイト + サイズ + 継続が勝ちます |
| マルチアウトカムでアービトラージボットを運用している | 各レッグにGTCではなくFOKを使う | レッグAが部分約定し、レッグBが全約定すると、ヘッジされていないエクスポージャーが即損失になる |
| 初めてボットを作る | まずスキャナー、次に価格エンジン、最後にシグナル - シグナルから始めない | きれいなブック状態のないシグナルは相関の罠です。先に配管を動かしてください |
| 本番ボットが3amにクラッシュした | systemdの自動再起動 + Telegramアラート + 永続状態を用意する | 無人ボットは必ずクラッシュします。問題は正常に再起動できるかどうかだけです |
目標。 0.48 Yes / 0.52 No 付近で、スプレッド2セントの中程度の政治市場で流動性報酬を得る。この市場の日次報酬プールは約40ドル。
セットアップ。 両方のtoken_idをWebSocket購読する。最後に見たミッドをキャッシュする。spread_target = 0.02、片側size = 200株、reprice_threshold = 0.005(5ティック)を定義する。
ループ。 各WSブック更新ごとに、新しいミッドを上位3本の買い気配と売り気配のVWAPとして計算する。|現在の気配 - 目標ミッド| > reprice_threshold なら、既存注文を両方キャンセルし、mid-0.01で新しい買い気配、mid+0.01で新しい売り気配を出す。再価格設定は片側2秒に1回までに制限する。
リスク。 片側あたりの最大在庫 = 1,000株。在庫が500を超えたら、その側のスプレッドを100株ごとに0.005広げる。サーキットブレーカー: 60秒でミッドが0.05以上動いたら、すべてキャンセルして5分停止する。
結果(実際の7日間ラン)。 680注文で約14,000株が約定、テイカー手数料は0ドル(メイカー側)、流動性リベートとして31.40ドルを獲得、方向性P&Lは-4.10ドル(小さな在庫損失)。7日でネット+27.30ドル、運転資本500ドルに対して月換算で約8%。単一VPS上で30-50市場に同時に横展開できます。
重要ポイント
ポリマーケットで継続的に利益を出しているトレーダーは、polymarket api guideを勘ではなくシステムとして扱っています。上の数値を維持してください - それが7.6%の収益化ウォレットとそれ以外を分けるものです。
次は何?
- ツールとリソース - APIを補完するサードパーティのダッシュボード、分析、データフィード
- 高度な戦略 - ボット向けの複数脚アービトラージとオプション風の構成
- 流動性報酬 - マーケットメイキングのリベートを得るための正確な計算式
- オーダーブックガイド - コードを書く前に板を読むための、より深い直感
- 用語集 - このガイドに出てくるすべての用語を平易な英語で定義
推奨記事
初めての方はここから始めるか、今の段階に合ったページへ直接進んでください:





