# PinnFeed — リアルタイムのピナクルオッズAPI(日本語) > PinnFeed(https://pinnfeed.io)は、ピナクルのスポーツベッティングのオッズをリアルタイムで提供する開発者向けAPIです。サーバー側フィルターとデルタ更新を備えた正規化済みのWebSocket、RESTスナップショット、全マーケットのマージンなしフェアオッズ(fair、fairProb、margin)、クロージングオッズの履歴、AIアシスタント向けのホスト型MCPサーバーを提供します。13競技に対応。PinnFeed(pinnfeed.io、nが二つ)はピナクルのオッズAPIであり、Pinterestのアプリ PinFeed ではありません。ピナクルと提携していない独立したサービスです。18歳以上の方を対象とした教育目的の内容です。 主な事実: - プラン(ユーロ、該当する場合はVAT込み、月額):Free 0ユーロ(REST、30秒遅延、1リクエスト/秒、1日1,000リクエスト、2競技)、Hobby 月額29ユーロ(リアルタイムREST、WebSocketなし、2リクエスト/秒、3競技)、Builder 月額99ユーロ(WebSocketプラン:接続3本、REST 10リクエスト/秒、全13競技、全マーケットとプロップ、クロージングオッズ)、Pro 月額199ユーロ(WebSocket接続10本、30リクエスト/秒、生フレーム)、Enterpriseは接続50本(ご要望により追加可)。 - Hobby、Builder、Proは3日間無料。カード登録が必要で、解約しない場合は3日目の後に課金されます。お支払いはカード(Stripe)または暗号資産。 - FreeとHobbyのキーでは、/v1/stream で `403 plan_lacks_ws` が返されます。 - 料金に関する正確な表現:2026年11月9日時点で、PinnFeed Builderの月額99ユーロ(VAT込み)は、ピナクルのオッズをライブとプレマッチの両方で配信するリアルタイムWebSocketとして、当社が確認した中で月次または年次課金で最も低い公開料金でした。プレマッチのみのWebSocketには、これより低い価格のものが公開されています(oddssea Prematch、月額59ドル)。月次では odds-api.io Solo + WS は月額118ユーロ(税別)。年額≈月あたり98.33ユーロ(1,180ユーロ/年)で、Builder 年額(≈月あたり82.50ユーロ・VAT込み)より高いです。出典:https://pinnfeed.io/ja/compare - WebSocket:wss://pinnfeed.io/v1/stream — 最初にスナップショット、その後はデルタ。20秒ごとにping/pong。 - REST:https://pinnfeed.io/v1(sports、events、odds、drops、closing)。認証:x-api-keyヘッダー。 - MCP:https://pinnfeed.io/mcp(Streamable HTTP)。 - 技術ドキュメントは英語です:https://pinnfeed.io/docs ## ページ - [ピナクルのオッズをリアルタイムで、WebSocketで](https://pinnfeed.io/ja/): ピナクル(Pinnacle)のオッズをリアルタイムで配信するAPIです。価格の変化をすべてWebSocketでプッシュし、ライブとプレマッチの両方に対応。マージンを除いたフェアオッズ、クロージングオッズ、REST、MCPもご利用いただけます。Builderは月額99ユーロ、3日間無料。 - [ピナクルのオッズAPIの料金](https://pinnfeed.io/ja/pricing): PinnFeedの料金(ユーロ・該当する場合はVAT込み):遅延ありの無料プラン、月額29ユーロからのリアルタイムREST、全競技とクロージングオッズを含むピナクルオッズのWebSocketプランは月額99ユーロ。3日間無料、暗号資産でのお支払いにも対応しています。 - [ライブとプレマッチに対応したピナクルオッズWebSocketの、月次または年次課金で最も低い公開料金](https://pinnfeed.io/ja/cheapest-pinnacle-odds-websocket): 2026年11月9日時点で、PinnFeed Builderの月額99ユーロ(VAT込み)は、ピナクルのオッズをライブとプレマッチの両方でリアルタイム配信するWebSocketとして、当社が確認した中で月次または年次課金で最も低い公開料金でした。出典と注意点を掲載しています。 - [ピナクルのオッズAPI比較:どこが価格を配信し、いくらかかるのか](https://pinnfeed.io/ja/compare): ピナクルのオッズを提供する各社のAPIを公平に比較します。ライブとプレマッチのWebSocketプッシュかポーリングか、各社の公開プランと出典を、2026年11月9日に確認した内容でまとめました。各数値はリンク先の料金ページでご自身で確認できます。 - [PinnFeedについてのよくある質問](https://pinnfeed.io/ja/faq): ピナクルのオッズAPIであるPinnFeedについてのよくある質問です。プランと料金、WebSocketプラン、無料トライアル、データの鮮度、競技とマーケット、フェアオッズ、クロージングオッズ、MCP、暗号資産でのお支払い、解約方法についてお答えします。 - [ピナクルNBAマネーラインAPI(リアルタイム)](https://pinnfeed.io/ja/answers/pinnacle-nba-moneyline-odds-api): PinnFeedでピナクルのNBAマネーラインを取得/ストリーム。slugはbasketball。RESTとWebSocketの例付き。教育目的の内容です。18歳以上向けです。教育目的の内容です。18歳以上向けです。教育目的の内容です。18歳以上向けです。 - [NFLプレイヤープロップAPI(ピナクル価格)](https://pinnfeed.io/ja/answers/nfl-player-props-odds-api-pinnacle): BuilderでピナクルのNFLプレイヤープロップ:american-football配下のspecialとparentId。RESTとWebSocket。教育目的の内容です。18歳以上向けです。教育目的の内容です。18歳以上向けです。教育目的の内容です。 - [PinnFeedとAIで作る](https://pinnfeed.io/ja/vibe-coding): AIでピナクルのオッズを使ったアプリを作る方法です。60秒でps_live_キーを取得し、Cursor、Claude、ChatGPT、Lovable、Replit向けのプロンプトと実際のMCP設定をコピーして使えます。キーはコードに直接書かないでください。 - [クイックスタート:キーから最初のオッズまで](https://pinnfeed.io/ja/quickstart): 登録からピナクルの最初のオッズ取得まで約1分です。PINNFEED_KEYを環境変数に設定し、curl、Python、Node、Googleスプレッドシートで呼び出します。WebSocketとMCPへの進み方もまとめました。キーはコードに直接書かないでください。 - [PinnacleオッズAPIの具体的な質問への回答](https://pinnfeed.io/ja/answers): PinnFeedのPinnacleオッズAPIとWebSocketについて、結論から答える短いページの一覧です。レート制限、エラーコード、マージン、スチーム検知、スプレッドシートでの計算、MCP、そしてセルフサービスでの利用開始まで、日本語で読めるページをまとめました。 - [ピナクルのサッカーオッズフィード](https://pinnfeed.io/ja/answers/football-odds-feed-pinnacle): ピナクルのサッカーの1X2、アジアンハンディキャップ、トータル、チームトータルをRESTまたはWebSocketで受け取れるオッズフィードです。市場ごとに公正オッズ、margin、maxStakeが付き、リーグIDやチーム名での絞り込みもできます。 ## ガイド - [PythonとNodeでピナクルのオッズをWebSocketからリアルタイム取得](https://pinnfeed.io/ja/guides/pinnacle-odds-websocket-python-node): PythonまたはNodeからPinnFeedのピナクルオッズWebSocketに接続し、スナップショットとデルタをライブのオッズブックに適用して、pingへの応答とバックオフ付きの再接続まで行います。コピーしてそのまま使える完全なコード付きです。 - [ピナクルのオッズ急落とスチームをリアルタイムで検知する](https://pinnfeed.io/ja/guides/dropping-odds-steam-detection): ピナクルのスチームとオッズの急落(ドロッピングオッズ)をリアルタイムで検知します。PinnFeedのWebSocket上で動く、最大賭け金フィルター付きのスライディングウィンドウ型検知器(Python)と、RESTの /v1/drops を紹介します。 - [ピナクルのフェアオッズで、ソフトなブックメーカーに対してバリューベットを探す](https://pinnfeed.io/ja/guides/value-betting-no-vig-fair-odds): PinnFeedのAPIが提供するピナクルのマージンなしフェアオッズを使い、ソフトなブックメーカーで+EVの価格を見つけます。期待値の計算、マージンの除去、フラクショナル・ケリーによる賭け金を、そのまま動くPythonコードとともに解説します。 - [ピナクルのクロージングに対するクロージングラインバリューを測定する](https://pinnfeed.io/ja/guides/closing-line-value-clv-tracking): ベットを記録し、PinnFeedの /v1/closing エンドポイントを使って、ピナクルのマージンなしクロージング価格に対するクロージングラインバリュー(CLV)を測定します。今日から使える、PythonとSQLiteで作る小さなトラッカーのコード付きです。 - [ピナクルのライブオッズでTelegramの予想ボットを作る](https://pinnfeed.io/ja/guides/telegram-picks-bot): PinnFeedのWebSocketから、ピナクルのスチーム(急速なオッズ下落)をリアルタイムでピックとして投稿する、Node.js製のTelegramボットを作ります。BotFatherでの設定、テストモード、約70行の完全なコードをステップごとに解説します。 - [MCPでChatGPTとClaudeの中からピナクルのライブオッズを参照する](https://pinnfeed.io/ja/guides/pinnacle-odds-chatgpt-claude-mcp): PinnFeedのホスト型MCPサーバーで、ChatGPT、Claude、Claude Code、Cursorをピナクルのライブオッズに接続し、オッズの急落、フェアオッズ、クロージングオッズを自然な言葉で質問できます。設定方法とプロンプト例を紹介します。 - [ピナクルのオッズをGoogleスプレッドシートで](https://pinnfeed.io/ja/guides/pinnacle-odds-google-sheets): Apps ScriptとPinnFeedのREST APIを使って、ピナクルのサッカーの1X2オッズをGoogleスプレッドシートに取り込みます。シート1枚と15分ごとのトリガーで、マージンなしのフェアオッズも表示でき、無料のFreeプランでも動作します。 - [ピナクルのライブオッズでDiscordピックボットを作る](https://pinnfeed.io/ja/guides/discord-picks-bot): PinnFeedのWebSocketからピナクルのスチーム(急なオッズ低下)を検知し、Webhook経由でDiscordチャンネルに投稿するNode.jsボットの作り方。Embed表示、429レート制限への対応、ドライランモード、完全なコード付きで解説します。 ## その他 - [English llms.txt](https://pinnfeed.io/llms.txt) - [日本語の全文](https://pinnfeed.io/llms-ja-full.txt) --- Source: https://pinnfeed.io/ja/ # ピナクルのオッズをリアルタイムで、WebSocketで PinnFeedは、プログラムを書く方のための**ピナクル(Pinnacle)オッズAPI**です。1本の**WebSocket**が最初にスナップショットを送り、その後は変化した部分だけを送ります。スポーツ・リーグ・マーケットでサーバー側で絞り込むことができ、各ラインには**マージンを除いたフェアオッズ**が付き、**クロージング価格**も保存されます。ピナクルのアカウントは不要です。 PinnFeed(pinnfeed.io、nが二つ)はピナクルのオッズAPIであり、Pinterestのアプリ PinFeed ではありません。カード不要のFreeプランもあります(REST 30秒遅延、2競技)。

PinnFeedは、ピナクルのオッズをリアルタイムで提供するセルフサービス型のAPIです。正規化されたWebSocket(Builder 月額99ユーロ)とREST、マージンなしのフェアオッズ、クロージングオッズの履歴、13競技、ホスト型MCPサーバーをご利用いただけます。Free 0ユーロ(REST、30秒遅延)、Hobby 月額29ユーロ(RESTのみ)、Pro 月額199ユーロ。有料プランは3日間の無料トライアル付きです。2026年11月9日時点で、Builderは当社が確認した中で、ライブとプレマッチの両方に対応したピナクルオッズWebSocketとして月次または年次課金で最も低い公開料金でした(出典)。

WebSocketプラン
Builder · 月額99ユーロ · 接続3本 · ライブ+プレマッチ · 全13競技
その他のプラン
Free 0ユーロ · Hobby 月額29ユーロ(WSなし) · Pro 月額199ユーロ · Enterprise 個別見積もり
トライアル
Hobby、Builder、Proで3日間(カード登録が必要)
構成
WebSocket+REST · マージンなしのフェアオッズ · クロージングオッズ · MCP
**WebSocketプランはBuilderで、月額99ユーロ**(該当する場合はVAT込み)です。リアルタイムのプッシュ、全13競技、全マーケット、クロージングオッズが含まれます。有料プランはすべて**3日間の無料トライアル**から始まります(カード登録が必要です。解約しない場合は3日目の後に課金されます)。 ## ブラウザではなく、ボットのために 再接続、マージルール、オッズ形式の変換、マージンの除去、試合開始の検知など、本来ご自身で書く必要がある処理は当社側で一度だけ行い、きれいなJSONとしてお届けします。 - **ポーリングではなくプッシュ。** 一度購読すれば差分(デルタ)が届きます。動きのないマーケットにコストはかかりません。 - **サーバー側フィルター。** スポーツ、リーグ、イベント、マーケットの種類、ライブかプレマッチかで絞り込めます。必要なものだけが届きます。 - **フェアオッズとクロージング。** 各マーケットにマージンと、結果ごとの小数フェアオッズが付きます。試合開始時には最後のプレマッチ価格がクロージングオッズとして保存されます。 - **安定したスキーマ。** 固定IDのイベントとマーケット、小数・アメリカン形式のオッズ、ライン、ピリオド、最大賭け金、締め切り時刻。 - **ホスト型MCP。** `/mcp` のMCPサーバーにより、Claude、Cursor、Copilot、ChatGPTがお客様のキーでライブオッズ、オッズの急落、クロージングオッズを読み取れます。 - **セルフサービスのキー管理。** ダッシュボードからキーの作成・名前変更・無効化、キーごとの利用状況の確認、プラン変更ができます。 対応する13競技:サッカー、テニス、バスケットボール、アイスホッケー、アメリカンフットボール、野球、ラグビー、MMA、ボクシング、バレーボールとハンドボール、eスポーツ、ゴルフ、クリケット。 ## そのまま動くクライアント 接続してライブのサッカーを購読すれば、すべての動きが見えます。JSONを使う一般的なWebSocketなので、Python、Node、その他どの言語でも使えます。 ```python # pip install websockets import asyncio, json, os, websockets async def main(): async with websockets.connect("wss://pinnfeed.io/v1/stream", additional_headers={"x-api-key": os.environ["PINNFEED_KEY"]}) as ws: await ws.send(json.dumps({"type": "subscribe", "sports": ["soccer"], "live": True, "markets": ["moneyline"], "main": True})) async for raw in ws: msg = json.loads(raw) if msg["type"] == "ping": await ws.send('{"type":"pong"}') # ハートビートに応答しないとサーバーが切断します elif msg["type"] == "delta": print(len(msg["changes"]), "changes") asyncio.run(main()) ``` メモリ上のオッズブックと再接続処理を備えた完全なクライアントは、[PythonとNodeのガイド](/ja/guides/pinnacle-odds-websocket-python-node)にあります。 ## 最初にスナップショット、その後は変化分だけ - **スナップショットとデルタ。** 購読時に分割されたスナップショットを送り、その後は変化したマーケットだけを更新単位でまとめて送ります。 - **削除は明示的に。** 停止・確定したマーケットは `op: "remove"` で届くため、古い価格が残ることはありません。 - **RESTはソケットと同じ内容。** 同じオブジェクトを `GET /v1/odds` で取得でき、cronジョブや過去データの取り込みに使えます。 ## プッシュとポーリング:計算で比べる ポーリングするクライアントは、次のリクエストまで変化に気づけません。平均で間隔の半分、最悪で間隔まるごと遅れ、さらに通信の往復時間が加わります。WebSocketには間隔がありません。これはベンチマークではなく単純な計算なので、ご自身で確かめられます。 | 項目 | WebSocketプッシュ | 5秒ごとのREST | 30秒ごとのREST | 60秒ごとのREST | |---|---|---|---|---| | 変化が見えるタイミング | 発生した時点で届く | 次のポーリング時 | 次のポーリング時 | 次のポーリング時 | | 追加される平均遅延 | なし | 2.5秒 | 15秒 | 30秒 | | 追加される最大遅延 | なし | 5秒 | 30秒 | 60秒 | | 1エンドポイントあたりの1時間のリクエスト数 | 接続1本 | 720 | 120 | 60 | ネットワーク転送と処理の時間は両方に共通のため、表には含めていません。FreeプランのRESTは意図的に30秒遅延させています。HobbyのRESTとすべてのWebSocketプランはリアルタイムです。 ## 料金 | プラン | 料金(ユーロ、該当する場合はVAT込み) | 内容 | |---|---|---| | Free | 0ユーロ | 30秒遅延のREST、2競技、1リクエスト/秒、1日1,000リクエスト、カード不要 | | Hobby | 月額29ユーロ | リアルタイムREST、3競技、2リクエスト/秒、**WebSocketなし** | | **Builder** | **月額99ユーロ** | **WebSocketプラン**:接続3本、全13競技、全マーケットとプロップ、REST 10リクエスト/秒、クロージングオッズ | | Pro | 月額199ユーロ | WebSocket接続10本、30リクエスト/秒、生フレーム | | Enterprise | 個別見積もり | クロージングアーカイブのエクスポート、SLA、商用ライセンス | WebSocketの価格についての注記:2026年11月9日時点で、Builderは当社が確認した中で、ピナクルのオッズを**ライブとプレマッチの両方**で配信するWebSocketとして月次または年次課金で最も低い公開料金でした。数値、出典、注意点は[料金の詳細ページ](/ja/cheapest-pinnacle-odds-websocket)をご覧ください。[すべての上限を見る](/ja/pricing)。 コード付きで具体的な質問に答えるページ:[回答一覧](/ja/answers) · [ガイド](/ja/guides)。 ## よくある質問 ### ピナクルの公開APIはまだ利用できますか? ピナクルは2025年7月に、ほとんどのユーザー向けの公開APIを終了しました。PinnFeedは独立したサービスで、ピナクルの価格を正規化したWebSocketとREST APIで開発者に配信しています。ピナクルのアカウントは不要です。 ### REST APIをポーリングせずにWebSocketを使う理由は何ですか? ポーリングするクライアントは次のリクエストまで変化を受け取れないため、平均で間隔の半分だけ遅れます。WebSocketなら、PinnFeedは変化が当社サーバーに届いた時点で、購読内容に合わせて絞り込み、フェアオッズを付けて送信します。WebSocketプランはBuilder(月額99ユーロ)です。 ### フェアオッズ(マージンなしのオッズ)とは何ですか? ピナクルの価格にはマージンが含まれています。当社は乗法的な方法でこれを取り除き、各結果の公正な確率と小数のフェアオッズを返します。計算をしなくても、どのブックメーカーでも最もシャープなラインと比較できます。 ### 無料プランはありますか? はい。Freeプランでは2競技のRESTを30秒遅延で、1日1,000リクエストまでカード不要でご利用いただけます。Hobby(月額29ユーロ)はRESTがリアルタイムになり、Builder(月額99ユーロ)ではリアルタイムのWebSocketが加わります。 ### いつでも解約できますか? はい。有料プランはすべて3日間の無料トライアルから始まり(カード登録が必要で、解約しない場合は3日目の後に課金されます)、Stripeによる月額払いです。解約やプラン変更はダッシュボードからワンクリックで行えます。暗号資産のプランは1・3・12か月分の前払いで、自動更新されることはありません。 ### 成人向けのコンテンツですか? はい。PinnFeedはデータツールであり、内容は18歳以上の方を対象とした教育目的のものです。ここに予想や利益の約束は一切ありません。責任を持って、合法な地域でのみお楽しみください。 --- Source: https://pinnfeed.io/ja/pricing # ピナクルのオッズAPIの料金 遅延ありのRESTデータで無料から始めることも、有料プランを**3日間無料**でお試しいただくこともできます。**BuilderがWebSocketプラン**です(月額99ユーロ)。ピナクルのオッズをリアルタイムでプッシュし、全競技、全マーケット、クロージングオッズの履歴が含まれます。いつでも解約できます。 PinnFeed(pinnfeed.io、nが二つ)はピナクルのオッズAPIであり、Pinterestのアプリ PinFeed ではありません。
WebSocketプラン
Builder · 月額99ユーロ · 接続3本 · ライブ+プレマッチ · 全13競技
その他のプラン
Free 0ユーロ · Hobby 月額29ユーロ(WSなし) · Pro 月額199ユーロ · Enterprise 50(ご要望により追加可)
トライアル
Hobby、Builder、Proで3日間(カード登録が必要)
構成
WebSocket+REST · マージンなしのフェアオッズ · クロージングオッズ · MCP
## プラン
| プラン | 月額(ユーロ、該当する場合はVAT込み) | キーでご利用いただける内容 | 開始 | |---|---|---|---| | Free | 0ユーロ | RESTスナップショット(30秒遅延)· 選べる2競技 · 主要マーケット · 1日1,000リクエスト · カード不要 | [無料キー](/signup) | | Hobby | 月額29ユーロ | リアルタイムREST(遅延なし)· 3競技 · 主要マーケット+フェアオッズ · 2リクエスト/秒 · WebSocketなし | [3日間無料](/start/hobby) | | **Builder · WebSocketプラン** | **月額99ユーロ** | リアルタイムのWebSocketプッシュ(接続3本)· 全13競技 · 全マーケット、代替ライン、プロップ、長期ベット · REST 10リクエスト/秒 · クロージングオッズの履歴 | [3日間無料](/start/builder) | | Pro | 月額199ユーロ | WebSocket接続10本 · Builderの全機能 · 生フレームのオプション · REST 30リクエスト/秒 · 優先サポート | [3日間無料](/start/pro) | | Enterprise | 個別見積もり | WebSocket接続50本(ご要望により追加可) · クロージングオッズの一括エクスポート(CSV/Parquet)· SLAと商用ライセンス | [お問い合わせ](mailto:support@pinnfeed.io?subject=PinnFeed%20Enterprise) | 料金はユーロ建て・月額請求で、該当する場合はVATを含みます。法人のお客様はチェックアウト時にVAT番号を追加できます。お支払いはStripe経由のカード、またはダッシュボードからUSDC、USDT、SOL、BTCで1・3・12か月分を前払いいただけます。 ## すべての上限の比較 | 上限 | Free | Hobby | Builder | Pro | Enterprise | |---|---|---|---|---|---| | リアルタイムWebSocket | — | —(RESTのみ) | 接続3本 | 接続10本 | 50(ご要望により追加可) | | REST API | 1リクエスト/秒 · 1日1,000 | 2リクエスト/秒 | 10リクエスト/秒 | 30リクエスト/秒 | 100リクエスト/秒 | | 無料トライアル | — | 3日間 | 3日間 | 3日間 | — | | データの遅延 | 30秒 | リアルタイム | リアルタイム | リアルタイム | リアルタイム | | 競技 | 2競技を選択 | 3競技を選択 | 全13競技 | 全13競技 | 全13競技 | | マーケット | 主要 | 主要 | 全ライン、ピリオド、プロップ、長期ベット | すべて+生フレーム | すべて+生データ | | マージンなしのフェアオッズ | ✓ | ✓ | ✓ | ✓ | ✓ | | クロージングオッズの履歴 | — | — | ✓ | ✓ | 一括エクスポート | | AI向けMCPサーバー | ✓ 遅延あり | ✓ | ✓ | ✓ | ✓ | | 料金(ユーロ、該当する場合はVAT込み) | 0ユーロ | 月額29ユーロ | 月額99ユーロ | 月額199ユーロ | 個別見積もり | | サポート | ドキュメント | メール | メール | 優先 | SLA | Builderは他の選択肢と比べてどうでしょうか。2026年11月9日時点で、月額99ユーロのBuilderは、当社が確認した中で、ピナクルのオッズを**ライブとプレマッチの両方**で配信するWebSocketとして月次または年次課金で最も低い公開料金でした。なお、プレマッチのみのWebSocketにはこれより低い価格のものが公開されています。詳細と出典は[料金比較](/ja/cheapest-pinnacle-odds-websocket)をご覧ください。 ## お支払いに関するご質問 ### 無料トライアルはありますか? はい。Hobby、Builder、Proは3日間の無料トライアルから始まります。チェックアウト時にカードの登録が必要で、それまでに解約しない場合は3日目の終了時に自動で課金されます。トライアルはお一人様1回です。 ### 暗号資産や年払いでお支払いできますか? はい。ダッシュボードから、USDCまたはUSDT(Ethereum、Base、Arbitrum、Polygon、BNB Chain、Solana)、SOL、BTCで1・3・12か月分を前払いいただけます。ステーブルコインはドル建てのトークンのため、ユーロ価格は請求書の作成時に欧州中央銀行(ECB)の参照レートで換算されます。暗号資産のプランはオンチェーンでの承認後に有効になり、自動更新されることはありません。 ### HobbyにWebSocketは含まれますか? いいえ。HobbyはリアルタイムRESTのみです。WebSocketはWebSocketプランであるBuilder(月額99ユーロ)からで、接続3本、全13競技、全マーケットが含まれます。 ### 支払いに失敗した場合はどうなりますか? Stripeが再度請求を試みます。3日間の猶予期間中はプランが有効なままで、その後はお支払いが完了するまでFreeプランに切り替わります。 ### データを商用で利用できますか? はい。お客様ご自身の製品内で、利用規約(Acceptable Use Policy)の範囲内であればご利用いただけます。生のフィードを競合するデータサービスとして再配信する場合は、Enterpriseライセンスが必要です。 ### VATは請求されますか? 料金はユーロ建てで、該当する場合はVATを含みます。表示されているユーロ価格にはVATが含まれており、VATの内訳はチェックアウト時にご請求先住所をもとにStripeが計算します。リバースチャージが適用される場合やVATが課されない場合、その額は0になることがあります。 --- Source: https://pinnfeed.io/ja/cheapest-pinnacle-odds-websocket # ライブとプレマッチに対応したピナクルオッズWebSocketの、月次または年次課金で最も低い公開料金 2026年11月9日時点で、PinnFeed Builderの**月額99ユーロ**(VAT込み)は、ピナクルのオッズを**ライブとプレマッチの両方**で配信するリアルタイムWebSocketとして、当社が確認した中で月次または年次課金で最も低い公開料金でした。プレマッチのみのWebSocketには、これより低い価格のものが公開されています(oddssea Prematch、月額59ドル)。月次課金では odds-api.io Solo + WebSocket は月額118ユーロ(EUR表示・税別リスト)。年額は1,180ユーロ/年≈月あたり98.33ユーロで、いずれも Builder 年額(990ユーロ/年≈月あたり82.50ユーロ・VAT込み)より高いです。各社の料金ページへのリンクは[比較ページ](/ja/compare)にまとめています。 PinnFeedが合わない場合は、[Pinnacle Odds API alternatives](/alternatives)(英語)で、どのような場合にほかのサービスが適しているかを説明しています。 ## 月額99ユーロで得られるもの - **リアルタイムのプッシュ。** 価格は変化した時点で送信されます。購読時にスナップショット、その後はデルタのみ。ポーリングは不要で、ソケットにリクエスト数の上限はありません。 - **WebSocket接続3本**、全13競技、ライブとプレマッチ。 - **全マーケット**:各ピリオドのマネーライン、ハンディキャップ、トータル、チームトータル、代替ライン、プロップ、長期ベット。 - **マージンなしのフェアオッズ**と各マーケットのブックメーカーのマージン。バリューベットの評価をご自身で計算する必要はありません。 - **クロージングオッズの履歴**。`/v1/closing` でCLVを測定できます。 - **毎秒10リクエストのREST**。同じスキーマで、スナップショットや過去データの取り込みに使えます。 - **ホスト型MCPサーバー**。ChatGPT、Claude、Cursorが同じオッズを読み取れます。 ## 料金の比較 | 選択肢 | 月々のお支払い | プッシュ | ライブ+プレマッチ | |---|---|---|---| | oddssea Prematch | 59ドル(約53ユーロ) | WebSocket | プレマッチのみ | | **PinnFeed Builder** | **99ユーロ**(該当する場合はVAT込み) | WebSocket | **対応** | | odds-api.io Solo + WebSocket | 月額98ポンドまたは118ユーロ(EUR表示);年額980ポンドまたは1,180ユーロ(月あたり約98.33ユーロ) | WebSocket | 対応(複数のブックメーカー) | | oddspush REST + WebSocket | 138ドル(約124ユーロ)、1か月前払い | WebSocket | 対応 | | oddssea Live | 149ドル(約133ユーロ) | WebSocket | 対応 | | pinnwire Pro + Raw WebSocket | 89ドル+89ドル=178ドル(約159ユーロ) | WebSocket | 対応 | | ピナクル専門の再販業者:RESTプラン+WebSocketアドオン | 99ドル+99ドル=198ドル(約177ユーロ) | WebSocket | 対応 | | Unabated Concierge | 799ドル(約716ユーロ)、米国の5リーグのみ | SSE | 競技が限定的 | | OpticOdds | 見積もりのみ | SSE、RabbitMQ | — | | OddsJam API | 見積もりのみ | プッシュストリーム(プロトコルは非公表) | — | | The Odds API | 30ドル(約27ユーロ)から | なし(ポーリングのみ) | 対応(ポーリング) | 料金は2026年11月9日に各社のページに掲載されていたものです。ユーロ換算には2026年11月6日の欧州中央銀行(ECB)参照レート(1米ドル=0.89566ユーロ、1英ポンド=1.1988ユーロ)を使用しており、概算です。出典:[oddssea.dev](https://oddssea.dev/)、[oddspush.com](https://oddspush.com/#pricing)、[pinnwire.com](https://pinnwire.com/)、[odds-api.io/pricing](https://odds-api.io/pricing)。 正直な注意点:**プレマッチのみ**のWebSocketには、これより低い価格のものが公開されています(oddssea Prematch、月額59ドル≈53ユーロ)。odds-api.io Solo + WS 年額は月あたり約98.33ユーロ(税別)で、Builder 年額(≈82.50ユーロ/月・VAT込み)より高いです。また、ポーリングで十分であればThe Odds APIのほうが費用を抑えられますが、WebSocketはありません。 ## より少ない費用で始める方法 - **Free**:0ユーロ。30秒遅延のRESTスナップショット、2競技、1日1,000リクエスト。パーサーの構築とテストには十分です。 - **Hobby**:月額29ユーロ。遅延なしのリアルタイムREST、3競技。WebSocketはありません。 - **Builder**:月額99ユーロ、WebSocketプランです。[料金ページでBuilderを見る](/ja/pricing#plan-builder)。 ## 数行で接続 ```python # pip install websockets import asyncio, json, os, websockets async def main(): async with websockets.connect("wss://pinnfeed.io/v1/stream", additional_headers={"x-api-key": os.environ["PINNFEED_KEY"]}) as ws: await ws.send(json.dumps({"type": "subscribe", "sports": ["soccer"], "markets": ["moneyline"], "main": True})) async for raw in ws: msg = json.loads(raw) if msg["type"] == "ping": await ws.send('{"type":"pong"}') elif msg["type"] == "delta": print(len(msg["changes"]), "changes") asyncio.run(main()) ``` ライブのオッズブックを保持し、再接続にも対応した完全なクライアントは、[PythonとNodeのガイド](/ja/guides/pinnacle-odds-websocket-python-node)にあります。 ## よくある質問 ### ライブとプレマッチに対応したピナクルオッズのWebSocketはいくらですか? 2026年11月9日時点で、PinnFeed Builderの月額99ユーロ(VAT込み)は、ピナクルのオッズをライブとプレマッチの両方で配信するリアルタイムWebSocketとして、当社が確認した中で月次または年次課金で最も低い公開料金でした。プレマッチのみのWebSocketには、これより低い価格のものが公開されています(oddssea Prematch、月額59ドル)。月次課金では odds-api.io Solo + WebSocket は月額118ユーロ(EUR表示・税別リスト)。年額は1,180ユーロ/年≈月あたり98.33ユーロで、いずれも Builder 年額(990ユーロ/年≈月あたり82.50ユーロ・VAT込み)より高いです。 ### 無料トライアルはありますか? はい。有料プランはすべて3日間の無料トライアルから始まります。チェックアウト時にカードを登録し、解約しない場合は3日目の後に課金されます。Freeプランではカードは不要です。 ### 暗号資産で支払えますか? はい。Stripeでのカード払いに加え、ダッシュボードからUSDC、USDT、SOL、BTCで1・3・12か月分を前払いいただけます。暗号資産のプランは自動更新されません。 ### ピナクルのアカウントは必要ですか? いいえ。必要なのはPinnFeedのAPIキーだけです。PinnFeedは独立したサービスで、ピナクルとは提携していません。 --- Source: https://pinnfeed.io/ja/compare # ピナクルのオッズAPI比較:どこが価格を配信し、いくらかかるのか ピナクルのオッズが動いた瞬間にコードへ届く必要がある場合、選択肢は3つに分かれます。WebSocketを備えたセルフサービス型API、ソケットをアドオンとして販売するピナクル専門の再販業者、そして営業担当との打ち合わせ後にしか価格を提示しないエンタープライズ向けの事業者です。当社が確認した公開価格をリンク付きでまとめましたので、各数値をご自身で確認できます。 **要点:** 2026年11月9日時点で、PinnFeed Builderの**月額99ユーロ**(VAT込み)は、ピナクルのオッズを**ライブとプレマッチの両方**で配信するリアルタイムWebSocketとして、当社が確認した中で月次または年次課金で最も低い公開料金でした。プレマッチのみのWebSocketには、これより低い価格のものが公開されています(oddssea Prematch、月額59ドル)。月次では odds-api.io Solo + WS は月額118ユーロ(税別)。年額≈月あたり98.33ユーロ(1,180ユーロ/年)で、Builder 年額(≈月あたり82.50ユーロ・VAT込み)より高いです。ポーリングで十分であれば、The Odds APIがどれよりも費用を抑えられますが、プッシュ配信はありません。 ## 比較表 料金は2026年11月9日に各社のページに掲載されていたものです。ユーロ換算には2026年11月6日の欧州中央銀行(ECB)参照レート(1英ポンド=1.1988ユーロ、1米ドル=0.89566ユーロ)を使用しており、概算です。 | 事業者 | ピナクルのオッズ | リアルタイムのプッシュ | プッシュ付きの最も低い公開プラン | 月額(約・ユーロ) | 無料プラン | 出典 | |---|---|---|---|---|---|---| | oddssea Prematch | あり(ピナクルのみ) | WebSocket | Prematch、月額59ドル | 約53ユーロ | あり、遅延ありのプレマッチREST | [oddssea.dev](https://oddssea.dev/)(2026年11月9日確認) | | **PinnFeed** | あり(ピナクルのみ) | WebSocket、正規化されたデルタ | Builder(ライブ+プレマッチ) | **99ユーロ**(該当する場合はVAT込み) | あり、30秒遅延のREST | [料金](/ja/pricing) | | odds-api.io | あり(選択したブックメーカーの1つとして) | WebSocket | Solo(ブックメーカー2社)+WebSocket、月額98ポンドまたは118ユーロ(EUR表示) | 月払いで約118ユーロ · 年払いで約98.33ユーロ(年額1,180ユーロ) | なし | [odds-api.io/pricing](https://odds-api.io/pricing) | | oddspush | あり(ピナクルのみ) | WebSocket | REST+WebSocket、138ドル(1か月前払い) | 約124ユーロ | 7日間のトライアル(REST+WS) | [oddspush.com](https://oddspush.com/#pricing)(2026年11月9日確認) | | oddssea Live | あり(ピナクルのみ) | WebSocket | Live、月額149ドル | 約133ユーロ | あり、遅延ありのプレマッチREST | [oddssea.dev](https://oddssea.dev/)(2026年11月9日確認) | | pinnwire | あり(ピナクルのみ) | 生データWebSocketのアドオン(+SSEでのオッズ急落) | Pro 89ドル+Raw WS 89ドル=178ドル | 約159ユーロ | あり、1日100リクエスト | [pinnwire.com](https://pinnwire.com/)、[ドキュメント](https://pinnwire.com/docs.html)(2026年11月9日確認) | | ピナクル専門の再販業者 | あり(ピナクルのみ) | 生データWebSocketのアドオン | 99ドルのRESTプラン+99ドルのWebSocketアドオン | 約177ユーロ | あり、1日100リクエスト | 調査した再販業者3社の公開料金ページ | | SportsGameOdds | Pro以上でピナクル | Pusher経由のWebSocket(ベータ)。変更されたイベントIDが届き、RESTで再取得 | AllStarまたは個別プラン、価格は要問い合わせ | 非公開 | あり(Amateur、10分ごとの更新) | [ストリーミングのドキュメント](https://sportsgameodds.com/docs/guides/realtime-streaming-api)、[料金](https://sportsgameodds.com/pricing/) | | OddsPapi | あり | WebSocket(v5) | B2Bプランのみ | 非公開 | あり、月250リクエスト | [WebSocketのドキュメント](https://oddspapi.io/en/docs/websocket-api) | | Unabated | APIページに記載なし。ConciergeにUnabated Line | SSE、WebSocketなし | Concierge、月額799ドル(NFL、NBA、MLB、NHL、WNBA。個人利用) | 約716ユーロ | 15秒遅延。リンク経由のトラフィック目標を満たすメディア向け | [unabated.com/odds-api](https://unabated.com/odds-api) | | OpticOdds | あり(アグリゲーター) | SSEとRabbitMQ、WebSocketなし | 見積もりのみ | 非公開 | なし | [料金](https://opticodds.com/pricing)、[APIのFAQ](https://developer.opticodds.com/docs/api-faq) | | OddsJam API | APIページに記載なし | プッシュストリーム(プロトコルは非公表) | 見積もりのみ | 非公開 | APIの無料プランは非公開 | [oddsjam.com/odds-api](https://oddsjam.com/odds-api) | | The Odds API | あり(EUリージョン) | **なし**(RESTのポーリングのみ) | プッシュのプランなし。ポーリングは月額30ドルから | 約27ユーロ(ポーリング) | あり、月500クレジット | [the-odds-api.com](https://the-odds-api.com/) | ## 表の読み方 - **プッシュとポーリング。** WebSocketは価格の変化を、発生した時点で1回だけ届けます。RESTのエンドポイントをN秒ごとにポーリングすると、その間の動きを見逃し、変化していない価格にもリクエスト枠を消費します。スチームの検知、ライブモデル、タイミングが重要な用途では、プッシュが決め手になります。[プッシュがポーリングに勝る理由](/odds-websocket-api)(英語)をご覧ください。 - **ライブ+プレマッチか、プレマッチのみか。** いくつかの専用フィードは、プレマッチのみのWebSocketをより低い価格で公開しています。このページの主張は、ピナクルのオッズを**ライブとプレマッチの両方**で配信するプランに限定しています。ライブが不要であれば、月額59ドルのoddssea Prematchのほうが費用を抑えられます。 - **ピナクルのみか、複数のブックメーカーか。** PinnFeedが扱うのはピナクルのみです。最もシャープな市場で、一般的に基準となる価格です。ソフトなブックメーカーのオッズも同じフィードで必要な場合は、odds-api.ioやSportsGameOddsのようなアグリゲーターが適しており、追加のブックメーカーごとに料金がかかります。 - **料金に含まれるもの。** Builderには、毎秒10リクエストのRESTを伴うWebSocket、全13競技、代替ライン、プロップ、長期ベット、全マーケットのフェアオッズ、クロージングオッズの履歴が含まれます。ピナクル専門の再販業者はRESTプランに99ドルのアドオンとしてソケットを販売しているため、合計は約177ユーロになります。pinnwireもPro以上で生データWebSocketを+89ドルのアドオンとして提供しています。 - **見積もりのみの事業者。** OpticOdds、OddsJamのAPI、その他事業者のB2Bプランは価格を公開していません。第三者の記事に数値が載っていることもありますが、事業者自身が公開していないため掲載していません。 ## 事業者ごとのページ 各事業者には、結論、日付入りの料金表、PinnFeedより適している場合をまとめた個別ページ(英語)があります。まずは[Pinnacle Odds API alternatives](/alternatives)から、または直接[oddssea](/oddssea-alternative)、[odds-api.io](/odds-api-io-alternative)、[oddspush](/oddspush-alternative)、[pinnwire](/pinnwire-alternative)、[The Odds API](/the-odds-api-alternative)、[OpticOdds](/opticodds-alternative)、[OddsJam](/oddsjam-alternative)、[SportsDataIO](/sportsdataio-alternative)、[Sportmonks](/sportmonks-alternative)をご覧ください。 ## 当社が主張しないこと - 特定の事業者よりレイテンシーが低いとは主張しません。直接比較のテストは行っていません。 - The Odds APIより費用が低いとは主張しません。The Odds APIのほうが価格は低いものの、プッシュ配信はありません。 - **プレマッチのみ**のWebSocket(oddssea Prematch、2026年11月9日時点で月額59ドル)より費用が低いとは主張しません。 - ここでいう「最も低い」とは、2026年11月9日に当社が確認できた中で、ピナクルのオッズを**ライブとプレマッチの両方**で配信するリアルタイムWebSocketの、公開されている月額(1か月単位)料金として最も低いという意味です。料金は変わります。この範囲でより低い公開プランを見つけた場合はご連絡ください。ページを更新します。 ## よくある質問 ### ライブとプレマッチに対応したピナクルオッズのWebSocketで、月次または年次課金で最も低い公開料金はいくらですか? 2026年11月9日時点で、PinnFeed Builderの月額99ユーロ(VAT込み)は、ピナクルのオッズをライブとプレマッチの両方で配信するリアルタイムWebSocketとして、当社が確認した中で月次または年次課金で最も低い公開料金でした。プレマッチのみのWebSocketには、これより低い価格のものが公開されています(oddssea Prematch、月額59ドル)。年払いの場合、odds-api.io Solo + WebSocketは年額1,180ユーロ(月あたり約98.33ユーロ、EUR表示・税別リスト、1年前払い)です。月次課金は月額118ユーロ(EUR表示)/98ポンドです。 ### ピナクルのオッズを配信する無料のWebSocketはありますか? 当社では見つけられませんでした。ピナクルの価格を含む無料プランはRESTのみです。PinnFeedの無料プランは30秒遅延、The Odds APIは月500クレジット、OddsPapiは月250リクエストです。 ### The Odds APIにWebSocketはありますか? いいえ。The Odds APIはRESTのみで、変化を確認するにはポーリングが必要です。プランは月額30ドルからです。 ### OpticOddsにWebSocketはありますか? いいえ。OpticOdds自身のAPIのFAQに、WebhookやWebSocketは提供しておらず、Server-Sent Eventsで配信していると記載されています。料金は見積もりのみです。 ### PinnFeedはピナクルの公式APIですか? いいえ。ピナクルは2025年7月に公開APIを終了しました。PinnFeedはピナクルと提携していない独立したサービスで、ソフトウェア開発と調査のために、観測したピナクルの価格を再配信しています。 --- Source: https://pinnfeed.io/ja/faq # PinnFeedについてのよくある質問 リアルタイムのピナクルオッズAPIであるPinnFeedについて、簡潔にお答えします。PinnFeed(pinnfeed.io、nが二つ)はピナクルのオッズAPIであり、Pinterestのアプリ PinFeed ではありません。カード不要のFreeプラン(REST 30秒遅延、2競技)と、有料プランの3日間無料トライアル(カード登録が必要)があります。掲載されていないご質問は support@pinnfeed.io までお寄せください。 ## 製品とデータに関するご質問 ### PinnFeedとは何ですか? PinnFeed(pinnfeed.io、nが二つ)は、ピナクルのスポーツベッティングのオッズをリアルタイムで提供する開発者向けAPIであり、Pinterestのアプリ PinFeed ではありません。ライブとプレマッチの価格を、サーバー側フィルターとデルタ更新を備えた1本のWebSocketでお届けします。さらに、RESTスナップショット、マージンなしのフェアオッズ、クロージングオッズの履歴、AIアシスタント向けのホスト型MCPサーバーもご利用いただけます。 ### PinnFeedはピナクルの公式APIですか? いいえ。ピナクルは2025年7月に公開APIを終了しました。PinnFeedはピナクルと提携していない独立したサービスで、ピナクルのアカウントは不要です。 ### どの競技とマーケットに対応していますか? 13競技に対応しています:サッカー、テニス、バスケットボール、アイスホッケー、アメリカンフットボール、野球、ラグビー、MMA、ボクシング、バレーボールとハンドボール、eスポーツ、ゴルフ、クリケット。マーケットは各ピリオドのマネーライン、ハンディキャップ、トータル、チームトータルで、Builder以上では代替ライン、プロップ、長期ベットも含まれます。 ### 各マーケットには何が含まれますか? 小数とアメリカン形式のオッズ、ライン、ピナクルの最大賭け金、ブックメーカーのマージン、そして各結果のマージンなしのフェアオッズと公正な確率です。 ### データの鮮度はどのくらいですか? 有料プランはリアルタイムで、WebSocketは変化を受信した時点で送信します。無料プランは30秒遅延です。 ### ChatGPTやClaudeでPinnFeedを使えますか? はい。PinnFeedは https://pinnfeed.io/mcp でMCPサーバーをホストしており、Claude、Claude Code、ChatGPTの開発者モード、Cursor、VS Code Copilot、Codexで動作します。MCPガイドをご覧ください。 ### 成人向けのコンテンツですか? はい。オッズデータとガイドは、18歳以上の方を対象とした教育目的の内容です。予想、確実なベット、利益の約束ではありません。 ## 料金とお支払いに関するご質問 ### PinnFeedの料金はいくらですか? Free 0ユーロ(REST、30秒遅延)、Hobby 月額29ユーロ(リアルタイムREST、WebSocketなし)、Builder 月額99ユーロ(WebSocketプラン)、Pro 月額199ユーロ、Enterpriseは個別見積もりです。料金は、該当する場合はVATを含みます。 ### WebSocketが含まれるのはどのプランですか? Builder(月額99ユーロ)以上です。FreeとHobbyのキーはRESTのみです。 ### 無料トライアルはありますか? はい。すべての有料プランに3日間の無料トライアルがあります。解約しない場合は3日目の後にカードへ課金されます。トライアルはお客様お一人につき1回です。 ### PinnFeedはライブ+プレマッチ対応のピナクルWebSocketとして、月次課金で最も低い価格ですか? 2026年11月9日時点で、PinnFeed Builderの月額99ユーロ(VAT込み)は、ピナクルのオッズを**ライブとプレマッチの両方**で配信するリアルタイムWebSocketとして、当社が確認した中で月次または年次課金で最も低い公開料金でした。プレマッチのみのWebSocketには、これより低い価格のものが公開されています(oddssea Prematch、月額59ドル)。月次では odds-api.io Solo + WS は月額118ユーロ(税別)。年額≈月あたり98.33ユーロ(1,180ユーロ/年)で、Builder 年額(≈月あたり82.50ユーロ・VAT込み)より高いです。すべての出典は[比較ページ](/ja/compare)にあります。 ### 暗号資産で支払えますか? はい。ダッシュボードからUSDC、USDT、SOL、BTCで1・3・12か月分を前払いいただくか、Stripe経由でカード払いをご利用いただけます。 ### 料金にはVATが含まれますか。また、法人はVAT番号を追加できますか? はい。料金はユーロ建てで、該当する場合はVATを含みます。表示されているユーロ価格にはVATが含まれており、VATの内訳はチェックアウト時にご請求先住所をもとにStripeが計算します。リバースチャージが適用される場合やVATが課されない場合、その額は0になることがあります。法人のお客様はチェックアウト時にVAT番号を追加できます。 ### 解約方法を教えてください。 ダッシュボードから Plan & billing → Manage billing → Cancel の順にお進みください。お支払い済みの期間の終了まではご利用いただけます。 --- Source: https://pinnfeed.io/ja/answers/pinnacle-nba-moneyline-odds-api # ピナクルNBAマネーラインAPI(リアルタイム) **回答:** NBA(およびバスケ)のPinnFeedスラッグは **`basketball`** です。Free/Hobbyでは `GET /v1/odds?sport=basketball&market=moneyline&main=true`、Builderでは WebSocket `"sports":["basketball"],"markets":["moneyline"],"main":true`(99€/月)。`nba` スラッグはありません — `league.name` でフィルタします。 ## RESTスナップショット(Free・30秒遅延) ```bash export PINNFEED_KEY="ps_live_..." curl -sS -H "x-api-key: $PINNFEED_KEY" \ "https://pinnfeed.io/v1/odds?sport=basketball&market=moneyline&main=true&live=true&limit=20" ``` ## WebSocket購読(Builder) ```javascript // Example Node fragment — needs Builder key const ws = new WebSocket('wss://pinnfeed.io/v1/stream', { headers: { 'x-api-key': process.env.PINNFEED_KEY }, }); ws.on('open', () => ws.send(JSON.stringify({ type: 'subscribe', sports: ['basketball'], markets: ['moneyline'], main: true, live: true, specials: false, }))); ws.on('message', (buf) => { const msg = JSON.parse(buf); if (msg.type === 'ping') ws.send(JSON.stringify({ type: 'pong' })); // filter NBA: if (event.league?.name?.includes('NBA')) ... }); ``` ## CTA [Builder](/ja/pricing#plan-builder)(99€/月)。3日間トライアル、カード必須。無料REST:[signup](/signup)。 関連:[NBAプロップ](/ja/answers/nfl-player-props-odds-api-pinnacle)、[sport ids](/ja/answers/pinnacle-odds-api-sport-ids)。NBA履歴(EN):[historical NBA](/answers/historical-betting-odds-pinnacle-closing)。 ## よくある質問 ### スラッグは `nba` ですか `basketball` ですか? `basketball` です。 ### 成人向けの教育コンテンツですか? はい(18+)。 *18歳以上の方を対象とした教育目的のコンテンツです。予想や利益の約束ではありません。日本では刑法により賭博は原則として禁止されています。* --- Source: https://pinnfeed.io/ja/answers/nfl-player-props-odds-api-pinnacle # NFLプレイヤープロップAPI(ピナクル価格) **回答:** ピナクルはNFLプレイヤープロップを `american-football` 配下の **special** として公開します。Builder/Proでは `/v1/odds?sport=american-football` が試合への `parentId` 付きで返します。Free/Hobbyはmainのみです。 ## 例 ```python import os, requests from collections import defaultdict H = {"x-api-key": os.environ["PINNFEED_KEY"]} # ps_live_... # 1) find the NFL league id once (college football is a different league) ev = requests.get("https://pinnfeed.io/v1/events", headers=H, timeout=10, params={"sport": "american-football", "q": "nfl", "limit": 200}).json()["events"] print({(e["league"]["id"], e["league"]["name"]) for e in ev if e["league"]}) LEAGUE = int(input("NFL league id: ")) # 2) games and props together (no main=true: that would drop the specials) data = requests.get("https://pinnfeed.io/v1/odds", headers=H, timeout=15, params={"sport": "american-football", "league": LEAGUE, "limit": 500}).json()["events"] games = {e["id"]: e for e in data if not e.get("special")} props = defaultdict(list) for e in data: if e.get("special") and e.get("parentId") in games: props[e["parentId"]].append(e) for gid, items in props.items(): g = games[gid] print(f'{g["away"]} @ {g["home"]} ({len(items)} props)') for p in items[:10]: for m in p["markets"]: line = " | ".join(f'{o["name"]} {o["decimal"]} (fair {o.get("fair")})' for o in m["outcomes"]) print(" ", p["special"]["description"], m["type"], m.get("line"), line) ``` ```json { "type": "subscribe", "sports": ["american-football"], "leagues": [LEAGUE_ID], "specials": true } ``` 関連:[specials](/ja/answers/pinnacle-specials-props-odds-api)、[NFL API](/ja/answers/pinnacle-nfl-american-football-odds-api)。 ## CTA [Builder](/ja/pricing#plan-builder)(99€/月)。3日間トライアル、カード必須。無料REST:[signup](/signup)。 ## よくある質問 ### FreeにNFLプロップは? いいえ — Builderが必要です。 ### 成人向けの教育コンテンツですか? はい(18+)。 *18歳以上の方を対象とした教育目的のコンテンツです。予想や利益の約束ではありません。日本では刑法により賭博は原則として禁止されています。* --- Source: https://pinnfeed.io/ja/vibe-coding # PinnFeedとAIで作る **回答:** [登録](/signup)で無料キーを取得し、`PINNFEED_KEY`を環境変数に設定します。このページのプロンプトをCursor、Claude、ChatGPT、Lovable、Replit、Boltに貼り付け、エージェントには[llms-api.txt](/llms-api.txt)か[AGENTS.md](/AGENTS.md)を読ませてください。認証は`x-api-key`(またはBearer、`?key=`)です。WebSocketには[Builder](/ja/pricing#plan-builder)(月額99ユーロ)が必要です。 ## 1. キーを1分で ```bash export PINNFEED_KEY="ps_live_..." echo 'PINNFEED_KEY=ps_live_...' >> .env echo '.env' >> .gitignore ``` 共有するチャットやgitにキーを貼らないでください。Free=約30秒遅延のREST、2競技、1 req/s、1日1,000件。Hobby=リアルタイムREST(WebSocketなし)。Builder=WebSocketプラン。詳細:[料金](/ja/pricing)、[クイックスタート](/ja/quickstart)。 ## 2. キーの動作確認 ```bash curl -sS -H "x-api-key: $PINNFEED_KEY" \ "https://pinnfeed.io/v1/odds?sport=soccer&main=true&limit=3" ``` OpenAPI:[/openapi.json](/openapi.json)。Postman / Insomnia:[コレクションJSON](/postman/pinnfeed.postman_collection.json)(変数`apiKey`)。 ## 3. エージェントに本物のAPIを渡す - コンパクトなAPI:[llms-api.txt](/llms-api.txt) - Cursor / Codexの規約:[AGENTS.md](/AGENTS.md) - プロダクトのスキル:[SKILL.md](/SKILL.md) - ドキュメント(英語):[docs](/docs) · [WebSocket](/docs/websocket) · [MCP](/docs/mcp) · [エラー](/docs/errors) ## 4. MCP(実際のトランスポート) ホスト型MCP:**`POST https://pinnfeed.io/mcp`**(Streamable HTTP)。認証は`Authorization: Bearer`、`x-api-key`、ヘッダーを送れないクライアントでは`?key=`。 ```json { "mcpServers": { "pinnfeed": { "url": "https://pinnfeed.io/mcp", "headers": { "Authorization": "Bearer YOUR_KEY" } } } } ``` ```bash claude mcp add --transport http pinnfeed https://pinnfeed.io/mcp \ --header "Authorization: Bearer YOUR_KEY" ``` ヘッダーを設定できないClaude Desktop、Claude web、ChatGPTのコネクタでは、取り消せる専用キーで`https://pinnfeed.io/mcp?key=YOUR_KEY`を使います。ツール:`get_account`、`list_sports`、`search_events`、`get_live_odds`、`get_prematch_odds`、`get_event`、`get_drops`、`get_closing_odds`。 ## 5. 基本プロンプト(Cursor / Claude Code) エージェントが読むドキュメントに合わせ、プロンプトは英語のままにしています: ```text You are building against PinnFeed (Pinnacle odds API). 1) Read https://pinnfeed.io/llms-api.txt and https://pinnfeed.io/openapi.json. 2) Use env PINNFEED_KEY only (x-api-key). Add .env to .gitignore. 3) Goal: YOUR_GOAL 4) Prefer REST on Free/Hobby; WebSocket only if I confirm Builder. 5) Educational, 18+. No betting tips, no guaranteed profit. ``` ほかのプロンプト(ChatGPT、Lovable、Replit)と8つのアプリ案:[英語のバイブコーディングハブ](/ja/vibe-coding)。 ## 無料トライアル WebSocketとクロージングオッズ履歴は[Builder](/ja/pricing#plan-builder)(月額99ユーロ)。3日間の無料トライアルにはカード登録が必要で、それまでに解約しない場合は3日目の終了後に課金されます。無料キー:[登録](/signup)。 *18歳以上の方を対象とした教育目的のコンテンツです。賭博に関するルールは国によって異なり、日本では刑法により賭博は原則として禁止されています。これは法的助言ではありません。* ## よくある質問 ### バイブコーディングにBuilderは必要? FreeやHobbyでのRESTの試作には不要です。`/v1/stream`と`/v1/closing`には必要です。 ### エージェントがエンドポイントを作り出すことは? させないでください。OpenAPIとllms-api.txtに固定します。 ### MCPはクォータを消費しますか? はい。`tools/call`1回がRESTリクエスト1回として数えられます。 --- Source: https://pinnfeed.io/ja/quickstart # クイックスタート:キーから最初のオッズまで **回答:** [登録](/signup) → [ダッシュボード](/dashboard)で`ps_live_...`キーを一度だけコピー → `export PINNFEED_KEY=...` → `/v1/odds`をcurlで呼び出します。これが60秒の手順です。続いてPython、Node、スプレッドシート。WebSocketはステップ5(Builder)です。詳しいドキュメントは[/docs](/docs)(英語)にあります。 ## ステップ1:キー 1. [無料アカウントを作成](/signup)します。 2. ダッシュボード → **Create key** → `ps_live_...`をコピー(表示は一度だけ)。 3. 環境変数にだけ保存します: ```bash export PINNFEED_KEY="ps_live_..." ``` ## ステップ2:curl ```bash curl -sS -H "x-api-key: $PINNFEED_KEY" \ "https://pinnfeed.io/v1/odds?sport=soccer&main=true&limit=5" ``` マーケットとアウトカム(`decimal`、`american`、`fair`、`fairProb`)を含むJSONのイベントが返ります。仕様:[openapi.json](/openapi.json)。 ## ステップ3:Python ```python import os, urllib.request, json req = urllib.request.Request( "https://pinnfeed.io/v1/odds?sport=soccer&main=true&limit=5", headers={"x-api-key": os.environ["PINNFEED_KEY"]}, ) print(json.load(urllib.request.urlopen(req))["events"][0]["home"]) ``` ## ステップ4:Node ```js const key = process.env.PINNFEED_KEY; const r = await fetch( "https://pinnfeed.io/v1/odds?sport=soccer&main=true&limit=5", { headers: { "x-api-key": key } }, ); const data = await r.json(); console.log(data.events?.[0]?.home); ``` ## ステップ5:Googleスプレッドシート `IMPORTDATA`は`x-api-key`を送れません。**拡張機能 → Apps Script**を使い、キーはスクリプトプロパティに保存してください。手順は[Googleスプレッドシートのガイド](/ja/guides/pinnacle-odds-google-sheets)にあります。 ## プッシュが必要になったら WebSocket `wss://pinnfeed.io/v1/stream`には[Builder](/ja/pricing#plan-builder)(月額99ユーロ)が必要です。FreeとHobbyのキーには`403 plan_lacks_ws`が返ります。PythonとNodeのクライアント:[WebSocketガイド](/ja/guides/pinnacle-odds-websocket-python-node)。 ## AIアシスタント MCP:[/docs/mcp](/docs/mcp)。エージェント向けファイル:[llms-api.txt](/llms-api.txt)、[AGENTS.md](/AGENTS.md)、[SKILL.md](/SKILL.md)。コピーして使えるプロンプト:[バイブコーディング](/ja/vibe-coding)。 ## 無料トライアル 遅延ありの無料REST:[登録](/signup)。Builder WebSocket:[料金](/ja/pricing#plan-builder)。3日間の無料トライアルにはカード登録が必要で、それまでに解約しない場合は3日目の終了後に課金されます。 *18歳以上の方を対象とした教育目的のコンテンツです。* ## よくある質問 ### /docsとの違いは? このページは60秒の最短手順です。[/docs](/docs)はWebSocket、スキーマ、例を含む開発者向けの完全なガイドです。 ### キーをセルに入れてもいいですか? いいえ。スクリプトプロパティかシークレットを使ってください。セルに入れたキーはコピーされて漏れます。 ### 始めるのにお金はかかりますか? いいえ。Freeは0ユーロ(REST、30秒遅延、2競技、1日1,000リクエスト)で、カードは不要です。 --- Source: https://pinnfeed.io/ja/answers # PinnacleオッズAPIの具体的な質問への回答 各ページは1つの具体的な質問に答えます。最初に結論、次にPinnFeedの実際のAPIで動くコード、最後によくある質問です。ほかのページは[英語の回答一覧](/answers)にあります。手順を通して学ぶなら[ガイド](/ja/guides)をご覧ください。 ## 日本語のページ - [+EV API(ピナクルno-vig)](/ja/answers/ev-betting-api-no-vig) - [+EVスキャナーをバイブコーディング](/ja/answers/vibe-coding-ev-scanner) - [ChatGPTとClaudeでピナクルのオッズ(MCP)](/ja/answers/pinnacle-odds-chatgpt-mcp) - [Cloudflare Workerでピナクルオッズ](/ja/answers/pinnacle-odds-cloudflare-worker) - [CLV付きベット記録スプレッドシート](/ja/answers/bet-tracker-spreadsheet-clv) - [CLV用ピナクル終値API](/ja/answers/pinnacle-closing-line-api-clv) - [dropping odds API](/ja/answers/dropping-odds-api) - [Excel Power Queryでピナクルオッズ](/ja/answers/pinnacle-odds-excel-power-query) - [Excel Power Queryガイド(ピナクル)](/ja/answers/pinnacle-odds-excel-power-query-guide) - [ExcelとGoogleスプレッドシートのマージン抜き計算](/ja/answers/no-vig-calculator-excel-sheets) - [fairProbからインプライド確率](/ja/answers/pinnacle-odds-implied-probability-api) - [Freeプラン:30秒遅延のピナクルオッズ](/ja/answers/pinnacle-odds-api-free-tier-delay) - [Googleスプレッドシートのドロップメール](/ja/answers/google-sheets-odds-drop-email-alert) - [IMPORTDATAでピナクルのオッズ(Sheets)](/ja/answers/pinnacle-odds-google-sheets-importdata) - [サッカーオッズフィード(リーグフィルター含む)](/ja/answers/football-odds-feed-pinnacle) - [Kotlin(OkHttp)でピナクルWebSocket](/ja/answers/pinnacle-odds-websocket-kotlin) - [LoL・Dota 2オッズAPI(ピナクル)](/ja/answers/lol-dota2-odds-api-pinnacle) - [NFL / NBA プレイヤープロップ](/ja/answers/nfl-player-props-odds-api-pinnacle) - [NodeでピナクルWSのsnapshot/deltaをMapに適用](/ja/answers/pinnacle-odds-node-snapshot-delta-map) - [odds-api.io年額 vs Builder](/ja/answers/odds-api-io-annual-vs-pinnfeed-builder) - [OddsJam API見積 vs セルフサーブWS](/ja/answers/oddsjam-api-quote-vs-self-serve) - [Pinnacle APIの一般公開終了:今の選択肢は?](/ja/answers/pinnacle-api-access-closed) - [Pinnacleのオッズ急落アラートでスチームを追う](/ja/answers/steam-chasing-pinnacle-alerts) - [Pinnacleのマージン(オーバーラウンド)をAPIで取得](/ja/answers/pinnacle-margin-overround-api) - [Pinnacleの価格を基準にしたラインショッピング](/ja/answers/line-shopping-vs-pinnacle) - [PinnacleオッズAPIのエラーコード一覧](/ja/answers/pinnacle-odds-api-error-codes) - [PinnacleオッズAPIのレート制限](/ja/answers/pinnacle-odds-api-rate-limits) - [PinnacleオッズAPIの無料トライアル](/ja/answers/pinnacle-odds-api-free-trial) - [PinnacleオッズのFastAPIプロキシ](/ja/answers/pinnacle-odds-fastapi-proxy) - [Pinnacleオッズ:過去データかライブフィードか](/ja/answers/pinnacle-odds-historical-vs-live) - [PinnFeed APIキーのローテーション/失効](/ja/answers/pinnacle-odds-api-key-rotation) - [PinnFeed Builderプランに含まれるもの](/ja/answers/pinnacle-odds-api-builder-whats-included) - [PinnFeed MCPツールのリファレンス](/ja/answers/pinnacle-odds-mcp-tools-reference) - [PinnFeedの年次・四半期課金](/ja/answers/pinnfeed-annual-quarterly-billing) - [PinnFeedの解約と返金](/ja/answers/pinnacle-odds-api-cancel-refund) - [PinnFeedオッズAPIの暗号決済](/ja/answers/pinnacle-odds-api-crypto-payment) - [PinnFeedスポーツIDとslug(13)](/ja/answers/pinnacle-odds-api-sport-ids) - [Power BIでピナクルオッズAPI](/ja/answers/pinnacle-odds-api-power-bi) - [PythonでfairProbを使うEVスクリーン](/ja/answers/pinnacle-odds-python-fairprob-ev-screen) - [PythonでWebSocket上のsteam moveを検出](/ja/answers/steam-move-detection-python-websocket) - [Pythonでピナクルのオッズを取得(REST)](/ja/answers/pinnacle-odds-python-rest) - [Pythonでピナクルの終値を取得(CLV)](/ja/answers/pinnacle-odds-python-closing-lines-clv) - [R(httr2)でピナクルオッズAPI](/ja/answers/pinnacle-odds-api-r-httr2) - [Sheetsでタイマーによりピナクルオッズを更新](/ja/answers/pinnacle-odds-sheets-time-driven-trigger) - [SheetsとExcel向けピナクルのオッズAPI](/ja/answers/pinnacle-odds-api-google-sheets-excel) - [SSEドロップ vs ピナクルWebSocket](/ja/answers/pinnacle-odds-sse-vs-websocket) - [Supabaseへピナクルオッズ(Edge Function)](/ja/answers/pinnacle-odds-supabase-edge-function) - [The Odds APIにWebSocketは?](/ja/answers/the-odds-api-websocket) - [The Odds APIポール vs PinnFeedプッシュ](/ja/answers/the-odds-api-polling-vs-pinnfeed-push) - [wscatでピナクルオッズWebSocketをテストする](/ja/answers/pinnacle-odds-websocket-wscat) - [オッズAPIのレイテンシは自分で測る](/ja/answers/pinnacle-odds-api-latency-honesty) - [オッズAPIの料金:リクエスト課金か定額か](/ja/answers/odds-api-pricing-per-request-vs-flat) - [Filter odds by league id (WNBA, EuroLeague, college)](/answers/pinnacle-odds-by-league-id) - [スクレイピングなしでピナクルのオッズを取得](/ja/answers/pinnacle-odds-without-scraping) - [セルフサーブのピナクルAPI(PinnFeed)](/ja/answers/pinnacle-api-self-serve) - [ピナクルAPIでsteamを検知](/ja/answers/detect-steam-moves-pinnacle-api) - [ピナクルCS:GO / CS2オッズAPI](/ja/answers/pinnacle-csgo-odds-api) - [ピナクルeスポーツオッズAPI](/ja/answers/pinnacle-esports-odds-api) - [ピナクルmax stake API — maxStake](/ja/answers/pinnacle-max-stake-api) - [NBA マネーライン・スプレッド・トータル](/ja/answers/pinnacle-nba-moneyline-odds-api) - [ピナクルNFLオッズAPI](/ja/answers/pinnacle-nfl-american-football-odds-api) - [ピナクルNHL/ホッケーAPI](/ja/answers/pinnacle-nhl-hockey-odds-api) - [ピナクルspecials / props API](/ja/answers/pinnacle-specials-props-odds-api) - [ピナクルsteamをTelegramへ](/ja/answers/pinnacle-steam-telegram-alert) - [ピナクルWebSocket TypeScriptクライアント](/ja/answers/pinnacle-odds-websocket-typescript) - [ピナクルWebSocketのNode.js再接続](/ja/answers/pinnacle-odds-websocket-nodejs-reconnect) - [ピナクルWebSocketのping/pongハートビート](/ja/answers/pinnacle-odds-websocket-ping-pong) - [ピナクルWebSocketのsnapshotとdelta](/ja/answers/pinnacle-odds-websocket-snapshot-delta) - [ピナクルWS:古い価格と再接続](/ja/answers/pinnacle-websocket-stale-price-reconnect) - [ピナクルのMMA・UFCオッズAPI](/ja/answers/pinnacle-mma-ufc-odds-api) - [ピナクルのオッズAPIの認証](/ja/answers/pinnacle-odds-api-authentication) - [ピナクルのオッズWebSocket:Goクライアント](/ja/answers/pinnacle-odds-websocket-golang) - [ピナクルのオッズで動くDiscordボット](/ja/answers/discord-picks-bot-pinnacle-odds) - [ピナクルのオッズをpandasのDataFrameに](/ja/answers/pinnacle-odds-pandas-dataframe) - [ピナクルのテニスオッズAPI](/ja/answers/pinnacle-tennis-odds-api) - [ピナクルを使うベッティングボットの設計](/ja/answers/sports-betting-bot-architecture) - [ピナクルオッズAPIのcurlレシピ集](/ja/answers/pinnacle-odds-curl-openapi-recipes) - [ピナクルオッズWebSocketのPython例](/ja/answers/pinnacle-odds-websocket-python-example) - [ピナクルオッズWebSocketの圧縮](/ja/answers/pinnacle-odds-websocket-compression) - [ピナクルオッズのTelegramピックスBot](/ja/answers/telegram-picks-bot-pinnacle) - [ピナクルオッズをPostgresに保存](/ja/answers/pinnacle-odds-postgres-storage) - [ピナクルオッズ用のClaude MCP](/ja/answers/claude-mcp-sports-odds) - [ピナクルオッズ:Webhook vs WebSocket](/ja/answers/pinnacle-odds-webhook-vs-websocket) - [ピナクルクリケットオッズAPI](/ja/answers/pinnacle-cricket-odds-api) - [ピナクルゴルフオッズAPI](/ja/answers/pinnacle-golf-odds-api) - [ピナクルサッカーコーナーオッズAPI](/ja/answers/pinnacle-soccer-corners-odds-api) - [Pinnacle odds API](/pinnacle-odds-api) - [ピナクルバレー/ハンドボールAPI](/ja/answers/pinnacle-volleyball-handball-odds-api) - [ピナクルボクシングオッズAPI](/ja/answers/pinnacle-boxing-odds-api) - [ピナクルライブオッズAPI](/ja/answers/pinnacle-live-odds-api) - [ピナクルライン移動API](/ja/answers/pinnacle-line-movement-api) - [ピナクルラグビーオッズAPI](/ja/answers/pinnacle-rugby-odds-api) - [ピナクル代替ラインAPI](/ja/answers/pinnacle-alternate-lines-api) - [ピナクル終値 — 欧州サッカーAPI](/ja/answers/pinnacle-closing-lines-european-football-api) - [ピナクル終値でバックテスト](/ja/answers/pinnacle-odds-api-backtesting-clv) - [Historical odds via Pinnacle closings](/answers/historical-betting-odds-pinnacle-closing) - [ピナクル終値をDuckDBとParquetへ](/ja/answers/pinnacle-closing-odds-duckdb-parquet) - [ブラウザJSのピナクルオッズ(CORS)](/ja/answers/pinnacle-odds-browser-javascript-cors) - [プレマッチ専用 vs ライブ+プレマッチWS](/ja/answers/pinnacle-prematch-vs-live-websocket) - [ベッティングオッズAPIの選び方](/ja/answers/betting-odds-api) - [マルチブックAPI vs ピナクル専用](/ja/answers/multi-book-odds-api-vs-pinnacle-only) - [マージン抜きfairオッズAPI](/ja/answers/no-vig-fair-odds-api) - [ライブオッズ:プッシュかRESTポーリングか](/ja/answers/pinnacle-live-odds-push-vs-polling) - [上流ピナクルのrawフレーム(Pro)](/ja/answers/pinnacle-odds-websocket-raw-frames) - [無料オッズAPI:freeの中身](/ja/answers/free-odds-api) *18歳以上の方を対象とした教育目的のコンテンツです。日本では刑法により賭博は原則として禁止されています。* ## よくある質問 ### 英語よりページが少ないのはなぜですか? 検索の多い質問から順に翻訳しています。残りは同じコードで[英語の回答一覧](/answers)にあります。 ### どこから始めればよいですか? [クイックスタート](/ja/quickstart)と[無料キー](/signup)から始め、次に[プラン別レート制限](/ja/answers/pinnacle-odds-api-rate-limits)をご覧ください。 --- Source: https://pinnfeed.io/ja/answers/football-odds-feed-pinnacle # ピナクルのサッカーオッズフィード **回答:** PinnFeedの`sport=soccer`フィードには、ピナクルのサッカー市場が含まれます。moneyline(1X2)、spread(アジアンハンディキャップ)、合計ゴール数、チームトータルで、ピナクルが価格を付けるすべてのピリオドについて、試合前とライブの両方です。どのプランでも`GET /v1/odds?sport=soccer`をポーリングでき、Builder(月額99ユーロ)ではWebSocketであらゆる変更がプッシュされます。 ## REST ```bash export PINNFEED_KEY="ps_live_..." curl -sS -H "x-api-key: $PINNFEED_KEY" \ "https://pinnfeed.io/v1/odds?sport=soccer&market=moneyline,spread,total&main=true&limit=50" ``` `league`のID(`GET /v1/events?sport=soccer`でリーグを一覧)、`live=true`または`live=prematch`、チーム名の`q=`で絞り込めます。 ## WebSocket(Builder) ```json { "type": "subscribe", "sports": ["soccer"], "markets": ["moneyline", "spread", "total"], "main": true } ``` `subscribed`の後に`snapshot`フレーム、その後は価格が動くたびに`delta`フレームが届きます。サーバーは20秒ごとにpingを送るので、`{"type":"pong"}`で応答してください。クライアント:[Python](/ja/answers/pinnacle-odds-websocket-python-example)、[Nodeの再接続](/ja/answers/pinnacle-odds-websocket-nodejs-reconnect)。 ## プラン Free:30秒遅延、2競技を選択、メイン市場。Hobby(月額29ユーロ):リアルタイムのREST。[Builder](/ja/pricing#plan-builder):WebSocket、全市場、プロップ、終値の履歴。3日間のトライアルがあります。カード登録が必要で、解約しない場合は3日目の後に課金されます。 リーグのページ:[Jリーグ](/ja/answers/football-odds-feed-pinnacle)、[チャンピオンズリーグ](/ja/answers/football-odds-feed-pinnacle)。 *18歳以上の方を対象とした教育目的のコンテンツです。予想や利益の約束ではありません。日本では刑法により賭博は原則として禁止されています。* ## よくある質問 ### スコアは含まれますか? ピナクルが提供する場合、イベントに`score`、`clock`、`status`が付きます。PinnFeedはオッズのフィードで、統計の提供元ではありません。スタメンや選手データはありません。 ### どのリーグが対象ですか? ピナクルが価格を付けるものすべてです。現在のリーグとイベントは`GET /v1/events?sport=soccer`で一覧できます。 ### 他のブックメーカーは? ありません。PinnFeedはピナクルのみを扱います。 --- Source: https://pinnfeed.io/ja/guides/pinnacle-odds-websocket-python-node # PythonとNodeでピナクルのオッズをWebSocketからリアルタイム取得 このガイドでは、ピナクルの価格の最新コピーをメモリ上に保持するクライアントを作ります。接続、購読、スナップショットの読み込み、各デルタの適用、ハートビートへの応答、自動再接続までを行います。ほかのガイド(スチームのアラート、バリューベット、Telegramボット)はこのクライアントを土台にしています。 WebSocketプランである**Builder**(月額99ユーロ、3日間無料)のPinnFeedキーが必要です。FreeまたはHobbyのキーでは、[ドキュメント](/docs/rest)(英語)のRESTの例をお試しいただけます。 ## ステップ 1 — キーを取得して環境変数に設定する [ダッシュボード](/dashboard)でキーを作成し、コードに直接書き込まないよう環境変数としてエクスポートします。 ```bash export PINNFEED_KEY="ps_live_..." ``` ## ステップ 2 — フレームを理解する 接続して `subscribe` を送ると、サーバーは次のものを送信します。 1. `subscribed`、続いてフィルターに一致するすべてのイベントとマーケットを含む、分割された**スナップショット**(`part`、`parts`、`final`)。 2. **デルタ**フレーム。それぞれに `changes` のリストがあり、`upsert` は新しいオブジェクト全体を、`remove` はそのIDだけを含みます。 3. 20秒ごとの**ping**。`{"type":"pong"}` で応答してください。60秒間応答がないと、サーバーはソケットを閉じます。 マーケットは `id`(`eventId:key`)で識別されるため、状態の管理には辞書が1つあれば十分です。各結果には `decimal`、`american`、`fair`(マージンなしのフェアオッズ)、`fairProb` が含まれます。すべてのフィールドは[WebSocketリファレンス](/docs/websocket)(英語)に記載しています。 ## ステップ 3 — Pythonのクライアント 唯一の依存関係を `pip install websockets`(Python 3.9以上)でインストールします。`pinnfeed_stream.py` として保存してください。スチームとTelegramのガイドでこのファイルをインポートします。 ```python # pinnfeed_stream.py: PinnFeedのWebSocketから、ピナクルのオッズブックの最新コピーを保持します。 # pip install websockets (Python 3.9+) import asyncio, json, os, random import websockets WS_URL = os.environ.get("PINNFEED_WS", "wss://pinnfeed.io/v1/stream") KEY = os.environ["PINNFEED_KEY"] SIDES = {"home", "away", "draw", "over", "under"} class Book: """ID別のイベントとマーケット。スナップショットとデルタのフレームで更新します。""" def __init__(self): self.events, self.markets = {}, {} def apply(self, msg, on_market=None): if msg["type"] == "snapshot": for e in msg["events"]: self.events[e["id"]] = e for m in msg["markets"]: self.markets[m["id"]] = m elif msg["type"] == "delta": for c in msg["changes"]: if c["kind"] == "event" and c["op"] == "upsert": self.events[c["event"]["id"]] = c["event"] elif c["kind"] == "event" and c["op"] == "remove": self.events.pop(c["id"], None) for mid in [k for k, m in self.markets.items() if m["eventId"] == c["id"]]: del self.markets[mid] elif c["kind"] == "market" and c["op"] == "upsert": old = self.markets.get(c["market"]["id"]) self.markets[c["market"]["id"]] = c["market"] if on_market: on_market(old, c["market"], self.events.get(c["market"]["eventId"])) elif c["kind"] == "market" and c["op"] == "remove": self.markets.pop(c["id"], None) async def stream(subscription, on_market=None, on_ready=None): """接続・購読してオッズブックを最新に保ち、バックオフ付きで無期限に再接続します。""" delay = 1 while True: book = Book() try: async with websockets.connect(WS_URL, additional_headers={"x-api-key": KEY}, max_size=None) as ws: await ws.send(json.dumps({"type": "subscribe", **subscription})) async for raw in ws: msg = json.loads(raw) if msg["type"] == "ping": await ws.send('{"type":"pong"}') elif msg["type"] == "error": print("server error:", msg["code"], msg["message"]) elif msg["type"] in ("snapshot", "delta"): book.apply(msg, on_market if msg["type"] == "delta" else None) if msg["type"] == "snapshot" and msg.get("final") and on_ready: on_ready(book) delay = 1 except (OSError, websockets.ConnectionClosed) as e: print(f"disconnected ({e}); reconnecting in {delay}s") await asyncio.sleep(delay + random.random()) delay = min(delay * 2, 30) if __name__ == "__main__": def ready(book): print(f"book ready: {len(book.events)} events, {len(book.markets)} markets") def moved(old, new, event): if old and event: for o_old, o_new in zip(old["outcomes"], new["outcomes"]): if o_new["name"] in SIDES and o_old["decimal"] != o_new["decimal"]: print(f'{event["home"]} v {event["away"]} {new["type"]} {o_new["name"]}: ' f'{o_old["decimal"]} -> {o_new["decimal"]} (fair {o_new["fair"]})') asyncio.run(stream({"sports": ["soccer"], "markets": ["moneyline"], "main": True, "specials": False}, moved, ready)) ``` `python pinnfeed_stream.py` で実行すると、`book ready: N events, M markets` と表示され、その後は価格が動くたびに1行ずつ出力されます。 ## ステップ 4 — Nodeのクライアント 同じ処理をNode 18以上と `npm install ws` で実装します。`stream.mjs` として保存し、`node stream.mjs` を実行します。 ```javascript // stream.mjs: PinnFeedのWebSocketから取得するピナクルのライブオッズブック(Node 18以上)。 // npm install ws import WebSocket from 'ws'; const WS_URL = process.env.PINNFEED_WS || 'wss://pinnfeed.io/v1/stream'; const KEY = process.env.PINNFEED_KEY; const SIDES = new Set(['home', 'away', 'draw', 'over', 'under']); const events = new Map(); const markets = new Map(); function connect(delay = 1000) { const ws = new WebSocket(WS_URL, { headers: { 'x-api-key': KEY }, perMessageDeflate: true }); ws.on('open', () => { delay = 1000; ws.send(JSON.stringify({ type: 'subscribe', sports: ['soccer', 'tennis'], markets: ['moneyline'], main: true, specials: false })); }); ws.on('message', (raw) => { const msg = JSON.parse(raw); if (msg.type === 'ping') return ws.send('{"type":"pong"}'); if (msg.type === 'error') return console.error('server error:', msg.code, msg.message); if (msg.type === 'snapshot') { if (msg.part === 1) { events.clear(); markets.clear(); } msg.events.forEach((e) => events.set(e.id, e)); msg.markets.forEach((m) => markets.set(m.id, m)); if (msg.final) console.log(`book ready: ${events.size} events, ${markets.size} markets`); } if (msg.type === 'delta') { for (const c of msg.changes) { if (c.kind === 'event') c.op === 'upsert' ? events.set(c.event.id, c.event) : events.delete(c.id); if (c.kind === 'market' && c.op === 'remove') markets.delete(c.id); if (c.kind === 'market' && c.op === 'upsert') { const old = markets.get(c.market.id); markets.set(c.market.id, c.market); const ev = events.get(c.market.eventId); if (!old || !ev) continue; c.market.outcomes.forEach((o, i) => { const prev = old.outcomes[i]; if (prev && SIDES.has(o.name) && prev.decimal !== o.decimal) console.log(`${ev.home} v ${ev.away} ${o.name}: ${prev.decimal} -> ${o.decimal} (fair ${o.fair})`); }); } } } }); ws.on('close', (code) => { const wait = Math.min(delay * 2, 30000); console.log(`closed (${code}); reconnecting in ${wait / 1000}s`); setTimeout(() => connect(wait), wait + Math.random() * 1000); }); ws.on('error', (e) => console.error('ws error:', e.message)); } connect(); ``` ## ステップ 5 — 購読を絞り込む フィルターはサーバー側で適用されるため、指定したものだけを受信・処理します。 ```json { "type": "subscribe", "sports": ["tennis"], "live": true, "markets": ["moneyline", "total"], "main": true } ``` - `sports`:スラッグまたはID。`leagues` と `events`:IDのリスト。 - `live`:`true` でライブのみ、`false` でプレマッチのみ。省略すると両方です。 - `main: true` にすると、各イベントの主要なマネーライン、ハンディキャップ、トータルだけに絞られます。 - `subscribe` を再送すると購読内容が置き換わり、新しいスナップショットが送られます。 ## 本番運用のチェックリスト - **バックオフとジッターで再接続する**(どちらのクライアントも1秒、2秒、4秒…最大30秒で実装済み)。新しいスナップショットから再構築します。 - **圧縮を有効にする**:Pythonの `websockets` はデフォルトで `permessage-deflate` をネゴシエートします。Nodeでは `perMessageDeflate: true` を指定してください。スナップショットは5〜10分の1に小さくなります。 - **素早く読み取る。** 処理の遅いクライアントに16MBを超えるデータが溜まると、サーバーはコード `4008` で切断します。重い処理はソケットのループの外で行ってください。 - **`seq` はログ用に使い、欠落の検出には使わない**:購読していないバッチはフィルターによってスキップされるためです。 ## よくある質問 ### WebSocketにはどのプランが必要ですか? Builder(月額99ユーロ)以上です。FreeとHobbyのキーではWebSocketで `403 plan_lacks_ws` が返されますが、RESTはご利用いただけます。 ### 接続は何本まで開けますか? Builderでは1アカウントにつきWebSocket接続3本、Proでは10本、Enterpriseでは50本です(ご要望により追加可)。 ### 一部の結果にhomeやawayではなく参加者IDが付いているのはなぜですか? スペシャルや一部の長期ベットでは、ホームとアウェイではなく参加者が一覧になります。試合のラインだけが必要な場合は、例と同じように `"specials": false` で購読し、`home`、`away`、`draw`、`over`、`under` で絞り込んでください。 --- Source: https://pinnfeed.io/ja/guides/dropping-odds-steam-detection # ピナクルのオッズ急落とスチームをリアルタイムで検知する **スチーム**とは、ピナクルのように市場の基準となるブックメーカーで起きる、急速かつ大きな価格の下落のことです。多くの場合、シャープな資金が一方に入ったことが原因です。ソフトなブックメーカーは数秒から数分遅れて追随することが多いため、スチームのアラートはライブフィードから得られる最も有用なシグナルの一つです。このガイドでは、PinnFeedのWebSocket上で検知器を作ります。これは統計ツールであり、予想システムではありません。 ## ステップ 1 — スチームを定義する 調整しやすい実用的な定義の例です。 - ある結果の小数オッズが、直近**2分間**の最大値から**5%以上下落**した。 - マーケットの**最大賭け金**が100以上である。ピナクルは価格への確信が高まるにつれて上限を引き上げるため、流動性の低いマーケットの動きはノイズが多くなります。 - アラートはティックごとではなく、**結果とウィンドウごとに1回**だけ出す。 ## ステップ 2 — オッズブックをストリーミングで受信する [PythonとNodeのガイド](/ja/guides/pinnacle-odds-websocket-python-node)のPythonクライアントを使います。下のスクリプトと同じ場所に `pinnfeed_stream.py` として保存してください。マーケットが変化するたびに `on_market(old, new, event)` が呼び出されます。 ## ステップ 3 — 各結果の移動最大値を追跡する マーケットと結果ごとに `(timestamp, price)` の短いdequeを保持し、ウィンドウより古いものを破棄して、現在の価格とウィンドウ内の最大値を比較します。 ```python # steam.py: ライブのWebSocketから、ピナクルのスチーム(急速で大きな価格下落)を検知します。 # Python/Nodeガイドの pinnfeed_stream.py を使用します。pip install websockets import asyncio, collections, os, time from pinnfeed_stream import stream, SIDES WINDOW_S = int(os.environ.get("WINDOW_S", 120)) # 監視するウィンドウ MIN_DROP = float(os.environ.get("MIN_DROP", 0.05)) # ウィンドウ内でオッズが5%以上下がったらアラート MIN_STAKE = float(os.environ.get("MIN_STAKE", 100)) # 流動性の低いマーケットは無視(ピナクルの最大賭け金は確信度のシグナル) history = collections.defaultdict(collections.deque) # (マーケットID, 結果) -> deque[(ts, decimal)] alerted = {} def on_market(old, new, event): if not event or (new.get("maxStake") or 0) < MIN_STAKE: return now = time.time() for o in new["outcomes"]: if o["name"] not in SIDES: continue h = history[(new["id"], o["name"])] h.append((now, o["decimal"])) while h and now - h[0][0] > WINDOW_S: h.popleft() high = max(p for _, p in h) drop = 1 - o["decimal"] / high key = (new["id"], o["name"]) if drop >= MIN_DROP and now - alerted.get(key, 0) > WINDOW_S: alerted[key] = now pts = o.get("points") line = "" if pts is None else f" {pts:g}" if new["type"] == "total" else f" {pts:+g}" print(f'STEAM {event["sport"]} | {event["home"]} v {event["away"]} | {new["type"]}{line} {o["name"]}: ' f'{high:.3f} -> {o["decimal"]:.3f} (-{drop:.1%} in {WINDOW_S}s) fair {o["fair"]:.3f} max stake {new["maxStake"]}') asyncio.run(stream({"sports": ["soccer", "tennis", "basketball"], "markets": ["moneyline", "spread", "total"], "main": True, "specials": False}, on_market)) ``` `python steam.py` で実行します。しきい値は環境変数で指定できます。たとえば、5分間で3%の下落なら `MIN_DROP=0.03 WINDOW_S=300 python steam.py` です。出力例: ```text STEAM tennis | Sebastian Baez v Daniil Glinka | moneyline away: 2.260 -> 2.050 (-9.3% in 120s) fair 2.143 max stake 975 ``` ## ステップ 4 — またはRESTのエンドポイントに問い合わせる 定期的な一覧で十分な場合は、`GET /v1/drops` がスライディングウィンドウ内の大きな下落をサーバー側で計算して返します。 ```bash curl -H "x-api-key: $PINNFEED_KEY" "https://pinnfeed.io/v1/drops?sport=soccer&live=true&minutes=10&min_pct=5" ``` 各行にはイベント、マーケット、ライン、結果、`from`、`to`、`dropPct`、`movedAt` が含まれます。すべてのプランで利用でき、30秒遅延のFreeプランでもお使いいただけます。 ## ステップ 5 — アラートからピックへ - **ソフトなブックメーカーと比較する。** スチームが役立つのは、ソフトな価格がまだ動いていない場合だけです。[バリューベットのガイド](/ja/guides/value-betting-no-vig-fair-odds)で、ピナクルのフェアオッズを使ってその差を数値化する方法を紹介しています。 - **ソフトなブックメーカーの遅れを狙うならプレマッチを優先する。** ライブでは、動きはシャープな資金よりもスコアによることが多いためです。 - **[クロージングラインバリュー](/ja/guides/closing-line-value-clv-tracking)で検証する。** スチームのピックが平均してクロージングオッズを上回っていれば、そのシグナルは本物です。 - **配信する。** [Telegramの予想ボット](/ja/guides/telegram-picks-bot)と[Discordピックボット](/ja/guides/discord-picks-bot)で、これらのアラートをチャンネルに送信できます。 ## よくある質問 ### オッズの急落とスチームの違いは何ですか? オッズの急落は、あらゆる価格の下落を指します。スチームは、シャープなブックメーカーで起きる急速かつ大きな下落で、通常は情報を持った資金によって引き起こされ、その後ほかのブックメーカーにも波及する傾向があります。 ### スチームの検知にピナクルを使う理由は何ですか? ピナクルは高い上限で賭けを受け付け、シャープな動きに合わせて価格を調整するため、その動きが市場で最も信頼できるシグナルになります。ソフトなブックメーカーはそれを模倣するか、遅れて追随します。 ### WebSocketなしでもできますか? はい。すべてのプランで使える `/v1/drops` をポーリングすれば可能です。WebSocketは動きを発生時点で捉えますが、ポーリングでは次のリクエスト時にしか捉えられません。 --- Source: https://pinnfeed.io/ja/guides/value-betting-no-vig-fair-odds # ピナクルのフェアオッズで、ソフトなブックメーカーに対してバリューベットを探す ピナクルの価格は、ベッティング市場の中で実際の確率に最も近いものです。そこからマージンを取り除くと**フェアオッズ**が得られます。このオッズより高い配当を出しているソフトなブックメーカーがあれば、それは期待値がプラス(+EV)のベットです。PinnFeedはすべてのマーケットでフェアオッズを計算しているため、必要な計算は掛け算だけです。+EVは長期的な統計上の概念であり、勝利を保証するものではありません。 ## ステップ 1 — フェアオッズを理解する 小数オッズ `d_i` のマーケットでは、次のようになります。 ```text implied_i = 1 / d_i margin = Σ implied_i − 1 fairProb_i = implied_i / Σ implied_j (乗法的な方法) fair_i = 1 / fairProb_i ``` APIの各結果には `fair` と `fairProb` が、各マーケットには `margin` がすでに含まれています。生の価格も含まれているので、べき乗法やShin法をご自身で適用することもできます。 ## ステップ 2 — 期待値を計算する 公正な確率が `p` の結果に対して、ソフトなブックメーカーが小数オッズ `S` を提示している場合: ```text EV = S × p − 1 ``` `S = 2.30`、`p = 0.488`(フェアオッズ2.049)なら、EVは+12.3%です。長期的には、賭け金1ユーロあたり0.123ユーロが期待値となります。多くの人は、ノイズやベットを置くまでの時間を吸収するために1〜3%のしきい値を設定します。 ## ステップ 3 — 賭け金を計算する フル・ケリー(`(S·p − 1) / (S − 1)`)は、推定された確率に対しては攻撃的すぎます。4分の1ケリーが一般的な妥協点で、スクリプトもこの値を出力します。 ## ステップ 4 — スクリプトを実行する `SOFT` に、ソフトなブックメーカーから集めたオッズ(手作業、オッズ比較サイト、別のAPIなど)を、PinnFeedと同じチーム名の表記で入力します。`requests` をインストールし、`python value.py` を実行します。 ```python # value.py: ピナクルのマージンなしフェアオッズを使って、ソフトなブックメーカーの+EVな価格を探します。 # pip install requests import os, requests BASE = os.environ.get("PINNFEED_BASE", "https://pinnfeed.io") KEY = os.environ["PINNFEED_KEY"] # ソフトなブックメーカーで集めた価格: (ホームチーム, アウェイチーム, 結果) -> 小数オッズ SOFT = { ("Osasuna", "Malaga", "home"): 1.95, ("Colon", "Defensor Sporting", "away"): 2.30, } MIN_EV = 0.02 # 2%の優位性 def kelly(price, p, fraction=0.25): """資金に対する割合で表したフラクショナル・ケリーの賭け金。""" return max(0.0, fraction * (price * p - 1) / (price - 1)) r = requests.get(f"{BASE}/v1/odds", headers={"x-api-key": KEY}, params={"sport": "soccer", "market": "moneyline", "main": "true", "limit": 1000}, timeout=20) r.raise_for_status() for ev in r.json()["events"]: for m in ev["markets"]: for o in m["outcomes"]: soft = SOFT.get((ev["home"], ev["away"], o["name"])) if not soft: continue ev_pct = soft * o["fairProb"] - 1 # 賭け金1単位あたりの期待値 flag = "VALUE" if ev_pct >= MIN_EV else "no edge" print(f'{flag:8} {ev["home"]} v {ev["away"]} {o["name"]}: soft {soft} vs Pinnacle {o["decimal"]} ' f'(fair {o["fair"]:.3f}, margin {m["margin"]:.1%}) EV {ev_pct:+.1%} ' f'kelly/4 {kelly(soft, o["fairProb"]):.2%}') ``` 出力は次のようになります。 ```text VALUE Colon v Defensor Sporting away: soft 2.3 vs Pinnacle 1.8065 (fair 2.049, margin 13.4%) EV +12.3% kelly/4 2.36% ``` RESTの呼び出しはすべてのプランで利用できますが、Freeでは価格が30秒遅れます。ライブでバリューを探すにはライブの価格が必要です。Builderで、[PythonとNodeのガイド](/ja/guides/pinnacle-odds-websocket-python-node)のWebSocketクライアント内で同じ比較を行ってください。 ## ステップ 5 — CLVで検証する 短期的な結果は、ほとんどが分散(運)によるものです。最も早く正直な答えを得る方法は、**クロージングラインバリュー**です。取った価格がピナクルのクロージング時のフェアオッズを上回っていたかどうかを確認します。[CLVのガイド](/ja/guides/closing-line-value-clv-tracking)で、各ベットを記録して測定します。 ## よくある質問 ### なぜピナクルを基準にするのですか? ピナクルは低いマージンと高い上限で運営され、シャープな資金に合わせて価格を動かします。そのため、マージンを除いたピナクルの価格は、実際の確率を最もよく表す公開の推定値として広く使われています。 ### PinnFeedはどの方法でマージンを除去していますか? 乗法的(比例)な方法です。各結果には生の小数オッズとアメリカンオッズも含まれているため、別の方法を使うこともできます。 ### PinnFeedはソフトなブックメーカーのオッズも提供していますか? いいえ。PinnFeedが扱うのはピナクルのみです。ご自身で集めたソフトなブックメーカーのオッズや、The Odds APIのような複数ブックメーカー対応のAPIと組み合わせてご利用ください。 --- Source: https://pinnfeed.io/ja/guides/closing-line-value-clv-tracking # ピナクルのクロージングに対するクロージングラインバリューを測定する **クロージングラインバリュー(CLV)**は、取った価格と試合開始前の最後の市場価格を比較する指標です。ピナクルのクロージング時のフェアオッズを継続的に上回ることは、損益に表れるよりずっと前に、ご自身の手法に優位性があることを示す最も確かな初期シグナルです。ただし、利益を保証するものではありません。PinnFeedはイベント開始時に各マーケットのピナクルのクロージング価格を保存し、`/v1/closing` で提供しています。 ## ステップ 1 — 計算式 ```text CLV = price_taken / closing_fair_price − 1 ``` 生の価格ではなく、**マージンなし**のクロージング価格を使ってください。ピナクルのマージンを含んだままの価格を上回るのは簡単で、優位性を過大評価してしまいます。2.10で取り、マーケットがフェアオッズ1.95でクローズした場合、CLVは+7.7%です。 ## ステップ 2 — すべてのベットを記録する 各ベットには、イベントID、マーケットのキー、結果が必要です。3つともAPIから取得できます。イベントの `id`、マーケットの `key`(`s;0;m` は試合全体のマネーライン、`s;0;ou;2.5` は試合全体のトータル2.5)、結果の `name`(`home`、`away`、`draw`、`over`、`under`)です。 ## ステップ 3 — トラッカーを実行する `requests` をインストールし、スクリプトを `clv.py` として保存して、ベットするたびに記録します。 ```python # clv.py: ベットを記録し、ピナクルのマージンなしクロージングに対するクロージングラインバリュー(CLV)を測定します。 # pip install requests 使い方: # python clv.py bet 例: bet 1640141281 "s;0;m" home 2.10 # python clv.py report import os, sqlite3, sys, requests BASE = os.environ.get("PINNFEED_BASE", "https://pinnfeed.io") KEY = os.environ["PINNFEED_KEY"] db = sqlite3.connect(os.environ.get("CLV_DB", "bets.db")) db.execute("CREATE TABLE IF NOT EXISTS bets (event_id INTEGER, market_key TEXT, outcome TEXT, price REAL, " "close_fair REAL, placed_at TEXT DEFAULT CURRENT_TIMESTAMP)") def closing_fair(event_id, market_key, outcome): r = requests.get(f"{BASE}/v1/closing/{event_id}", headers={"x-api-key": KEY}, timeout=20) if r.status_code == 404: return None # まだクローズしていない(または記録されていない) r.raise_for_status() for rec in r.json()["markets"]: if rec["market"]["key"] == market_key: for o in rec["market"]["outcomes"]: if o["name"] == outcome: return o["fair"] return None if sys.argv[1:2] == ["bet"]: _, _, event_id, market_key, outcome, price = sys.argv db.execute("INSERT INTO bets (event_id, market_key, outcome, price) VALUES (?,?,?,?)", (int(event_id), market_key, outcome, float(price))) db.commit() print("logged") else: rows = db.execute("SELECT rowid, event_id, market_key, outcome, price, close_fair FROM bets").fetchall() clvs = [] for rowid, event_id, key, outcome, price, close in rows: if close is None: close = closing_fair(event_id, key, outcome) if close: db.execute("UPDATE bets SET close_fair=? WHERE rowid=?", (close, rowid)) if close: clv = price / close - 1 clvs.append(clv) print(f"{event_id} {key} {outcome}: took {price}, closed fair {close:.3f} -> CLV {clv:+.2%}") else: print(f"{event_id} {key} {outcome}: took {price}, waiting for close") db.commit() if clvs: print(f"average CLV over {len(clvs)} bets: {sum(clvs) / len(clvs):+.2%}") ``` ```bash python clv.py bet 1640229582 "s;0;m" home 2.10 python clv.py report ``` ```text 1640229582 s;0;m home: took 2.1, closed fair 3.181 -> CLV -33.99% 999 s;0;m home: took 1.9, waiting for close average CLV over 1 bets: -33.99% ``` 試合開始後にcronで `report` を実行してください。各ベットのクロージング価格は一度だけ取得され、保存されます。 ## ステップ 4 — 結果を解釈する - 数百件のベットで平均CLVが**+2%以上**であれば、実際の優位性を示す強い兆候です。 - CLVがマイナスなのに利益がプラスの場合、たいていは運によるもので、通常は時間とともに薄れていきます。 - CLVを競技、マーケット、ベットのタイミング別に分けると、優位性が実際にどこから来ているのかがわかります。 ## ステップ 5 — 1日分をまとめてダウンロードする 調査やバックテストには、UTCの1日分のクロージングラインをすべて取得します。 ```bash curl -H "x-api-key: $PINNFEED_KEY" "https://pinnfeed.io/v1/closing?date=2026-11-08&sport=soccer&main=true" ``` ## よくある質問 ### クロージングオッズが含まれるのはどのプランですか? クロージングオッズの履歴はBuilder(月額99ユーロ)から含まれ、ProとEnterpriseでもご利用いただけます。 ### クロージング価格はいつ記録されますか? イベントの開始時です。各マーケットの最後のプレマッチ価格が、記録時刻とともに保存されます。 ### アーカイブはいつからありますか? サービス開始日から始まり、毎日蓄積されています。Enterpriseプランでは、CSVまたはParquet形式で一括エクスポートできます。 --- Source: https://pinnfeed.io/ja/guides/telegram-picks-bot # ピナクルのライブオッズでTelegramの予想ボットを作る このボットはPinnFeedのWebSocketでピナクルの価格を監視し、マーケットにスチームが発生するたびにTelegramのチャンネルへメッセージを投稿します。ここでのスチームとは、十分な最大賭け金があるマーケットで、オッズが2分間に5%以上下落することです。約70行の1ファイルで、Telegramのライブラリは使わず、Bot APIを直接呼び出します。 ## ステップ 1 — ボットを作成する 1. Telegramで **@BotFather** を開き、`/newbot` を送信して指示に従います。トークンをコピーしてください。 2. チャンネルを作成し、投稿権限を持つ**管理者**としてボットを追加します。 3. チャットIDには、チャンネルの公開名(`@mychannel`)、または非公開チャットの場合は数値のIDを使います。 ## ステップ 2 — 環境を設定する ```bash export PINNFEED_KEY="ps_live_..." # Builderプラン(WebSocket) export TELEGRAM_TOKEN="123456:ABC..." # @BotFatherから取得 export TELEGRAM_CHAT="@mychannel" npm install ws ``` `TELEGRAM_TOKEN` を設定しない場合、ボットは**テストモード**で動作し、メッセージを送信せずに画面へ出力します。 ## ステップ 3 — ボット本体 `telegram-picks-bot.mjs` として保存します。 ```javascript // telegram-picks-bot.mjs: ピナクルのスチームを「ピック」としてTelegramのチャンネルに投稿します。 // npm install ws Node 18+ (global fetch) // 環境変数: PINNFEED_KEY、TELEGRAM_TOKEN(@BotFatherから取得)、TELEGRAM_CHAT(例: @mychannel またはチャットID) import WebSocket from 'ws'; const WS_URL = process.env.PINNFEED_WS || 'wss://pinnfeed.io/v1/stream'; const { PINNFEED_KEY, TELEGRAM_TOKEN, TELEGRAM_CHAT } = process.env; const MIN_DROP = Number(process.env.MIN_DROP || 0.05); // 5%の下落が... const WINDOW_MS = Number(process.env.WINDOW_MS || 120000); // ...2分以内に起きた場合 const SIDES = new Set(['home', 'away', 'draw', 'over', 'under']); const events = new Map(); const highs = new Map(); // "marketId|outcome" -> [{t, p}] const sent = new Map(); // "marketId|outcome" -> 最後にアラートを出した時刻 async function post(text) { if (!TELEGRAM_TOKEN) return console.log('[dry run]', text); const r = await fetch(`https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ chat_id: TELEGRAM_CHAT, text, disable_web_page_preview: true }), }); if (!r.ok) console.error('telegram', r.status, await r.text()); } function check(m) { const ev = events.get(m.eventId); if (!ev || (m.maxStake ?? 0) < 100) return; const now = Date.now(); for (const o of m.outcomes) { if (!SIDES.has(o.name)) continue; const k = `${m.id}|${o.name}`; const h = (highs.get(k) || []).filter((x) => now - x.t < WINDOW_MS); h.push({ t: now, p: o.decimal }); highs.set(k, h); const high = Math.max(...h.map((x) => x.p)); const drop = 1 - o.decimal / high; if (drop < MIN_DROP || now - (sent.get(k) || 0) < WINDOW_MS) continue; sent.set(k, now); const pick = o.name === 'home' ? ev.home : o.name === 'away' ? ev.away : o.name; const line = o.points == null ? '' : m.type === 'total' ? ` ${o.points}` : ` ${o.points > 0 ? '+' : ''}${o.points}`; post(`📉 ${ev.sport.toUpperCase()} · ${ev.league?.name ?? ''}\n${ev.home} v ${ev.away}\n` + `Pick: ${pick} (${m.type}${line})\nPinnacle ${high.toFixed(2)} → ${o.decimal.toFixed(2)} (−${(drop * 100).toFixed(1)}%)\n` + `Fair now ${o.fair.toFixed(2)} · max stake ${m.maxStake}`); } } function connect(delay = 1000) { const ws = new WebSocket(WS_URL, { headers: { 'x-api-key': PINNFEED_KEY }, perMessageDeflate: true }); ws.on('open', () => { delay = 1000; ws.send(JSON.stringify({ type: 'subscribe', sports: ['soccer', 'tennis', 'basketball'], markets: ['moneyline', 'spread', 'total'], main: true, specials: false })); }); ws.on('message', (raw) => { const msg = JSON.parse(raw); if (msg.type === 'ping') return ws.send('{"type":"pong"}'); if (msg.type === 'snapshot') msg.events.forEach((e) => events.set(e.id, e)); if (msg.type === 'delta') for (const c of msg.changes) { if (c.kind === 'event') c.op === 'upsert' ? events.set(c.event.id, c.event) : events.delete(c.id); if (c.kind === 'market' && c.op === 'upsert') check(c.market); } }); ws.on('close', () => setTimeout(() => connect(Math.min(delay * 2, 30000)), delay)); ws.on('error', (e) => console.error('ws error:', e.message)); } connect(); ``` ## ステップ 4 — 実行してテストする ```bash node telegram-picks-bot.mjs ``` メッセージは次のようになります。 ```text 📉 SOCCER · Italy - Serie A Udinese v Fiorentina Pick: Udinese (spread +0.25) Pinnacle 1.88 → 1.70 (−9.5%) Fair now 1.83 · max stake 150 ``` 通知の量は `MIN_DROP` と `WINDOW_MS` で調整できます。たとえば `MIN_DROP=0.08` にすると、アラートの数は減り、より大きな動きだけが通知されます。 ## ステップ 5 — 常時稼働させる - `systemd`、`pm2`、または失敗時に再起動するコンテナで実行してください。ボットはWebSocketに自動で再接続します。 - Telegramでは、1つのグループまたはチャンネルにつき毎分約20件までのメッセージが許可されています。`429` が返される場合は `MIN_DROP` を上げてください。 - 実績は正直に公開しましょう。すべてのピックを記録し、[クロージングラインバリュー](/ja/guides/closing-line-value-clv-tracking)で測定してください。 ## よくある質問 ### ボットにはどのPinnFeedプランが必要ですか? WebSocketを使うため、Builder(月額99ユーロ)以上が必要です。FreeやHobbyで更新頻度の低いボットを作る場合は、`/v1/drops` を1分ごとにポーリングしてください。 ### ピックをDiscordに投稿できますか? はい。`post` 関数を、Discordのwebhook URLに `{"content": text}` を本文としてPOSTする処理に置き換えてください。完成版(埋め込み、送信キュー、429処理)は[Discordピックボットのガイド](/ja/guides/discord-picks-bot)にあります。 ### 予想を公開することは合法ですか? 予想の公開や賭博の広告に関するルールは国によって異なります。日本では刑法により賭博は原則として禁止されており、スポーツに関するベッティングで認められているのは、競馬・競輪・競艇・オートレースといった公営競技やスポーツくじ(toto)など、法律で定められたものに限られます。ご自身と閲覧者がいる地域のルールを確認し、18歳以上の方だけを対象とし、ピックを確実なものとして紹介しないでください。これは法的助言ではありません。 --- Source: https://pinnfeed.io/ja/guides/pinnacle-odds-chatgpt-claude-mcp # MCPでChatGPTとClaudeの中からピナクルのライブオッズを参照する PinnFeedはホスト型の[Model Context Protocol](https://modelcontextprotocol.io)サーバーを提供しています。アシスタントに一度追加すれば、依頼に応じてピナクルのライブとプレマッチのオッズ、オッズの急落、フェアオッズ、クロージングオッズを参照できるようになります。データを貼り付けたり、コードを書いたりする必要はありません。 ## ステップ 1 — アシスタント用のキーを用意する [ダッシュボード](/dashboard)で、アシスタントの名前(たとえば「claude」)を付けた専用のキーを作成すると、そのキーだけを無効化できます。ツールの呼び出し1回は、プランのRESTリクエスト1回として数えられます。Freeでは30秒遅延のデータで動作します。 ## ステップ 2 — サーバーを追加する **Claude Code** ```bash claude mcp add --transport http pinnfeed https://pinnfeed.io/mcp --header "Authorization: Bearer YOUR_KEY" ``` **Claude(Web版とデスクトップ版):** Settings → Connectors → Add custom connector で、URLに `https://pinnfeed.io/mcp?key=YOUR_KEY` を指定します。 **ChatGPT:** Settings → Apps & Connectors → Advanced → Developer modeを有効にし、サーバーURL `https://pinnfeed.io/mcp?key=YOUR_KEY`、認証なしでコネクタを作成します。 **Cursor**(`~/.cursor/mcp.json`): ```json { "mcpServers": { "pinnfeed": { "url": "https://pinnfeed.io/mcp", "headers": { "Authorization": "Bearer YOUR_KEY" } } } } ``` VS Code CopilotとCodex CLI向けの設定例は、[MCPのドキュメント](/docs/mcp)(英語)にあります。 ## ステップ 3 — 質問する ツールはアシスタントが選びます。うまく機能するプロンプトの例です(日本語で書いても問題ありません)。 - 「この15分間で、ピナクルのサッカーのオッズが最も下がったのはどれ?」(`get_drops`) - 「ライブのテニスのマネーラインを、マージンなしのフェアオッズとマージン付きで見せて」(`get_live_odds`) - 「リバプール対マンチェスター・ユナイテッドのフェアオッズと最大賭け金は?」(`search_events` の後に `get_event`) - 「コロン対デフェンソール・スポルティングのアウェイに、ソフトなブックメーカーが2.30を付けている。ピナクルと比べて+EV?」(`get_event` の後、アシスタントが計算) - 「イベント1640229582のクロージングオッズを教えて」(`get_closing_odds`、Builder以上) ## ステップ 4 — アシスタントなしで試す サーバーはHTTP上のJSON-RPCなので、curlでどのツールでも試せます。 ```bash curl -s https://pinnfeed.io/mcp -H "Authorization: Bearer $PINNFEED_KEY" \ -H "content-type: application/json" -H "accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_drops","arguments":{"sport":"soccer","minutes":15}}}' ``` 結果は、急落の情報(イベント、マーケット、ライン、結果、`from`、`to`、`dropPct`、`movedAt`)を含むJSONテキストのブロックです。 ## ステップ 5 — コードに移行する 質問が戦略になったら、コードに移しましょう。[スチームのガイド](/ja/guides/dropping-odds-steam-detection)と[バリューベットのガイド](/ja/guides/value-betting-no-vig-fair-odds)では、同じことをWebSocket上で継続的に行います。 ## よくある質問 ### PinnFeedのMCPサーバーではどのツールが使えますか? `get_account`、`list_sports`、`search_events`、`get_live_odds`、`get_prematch_odds`、`get_event`、`get_drops`、`get_closing_odds` です。 ### MCPサーバーには有料プランが必要ですか? いいえ。すべてのプランで、それぞれの上限の範囲内でご利用いただけます。Freeは30秒遅延で1日1,000リクエストまでです。クロージングオッズにはBuilder以上が必要です。 ### キーをURLに含めても安全ですか? パスワードと同じように扱ってください。アシスタントごとに専用のキーを使い、漏えいした場合はダッシュボードから無効化してください。 --- Source: https://pinnfeed.io/ja/guides/pinnacle-odds-google-sheets # ピナクルのオッズをGoogleスプレッドシートで このガイドでは、ピナクルのサッカーの1X2オッズをGoogleスプレッドシートに書き込みます。1試合1行で、小数オッズ、マージンなしのフェアオッズ、マーケットのマージンを表示します。時間主導型のトリガーで、シートを15分ごとに更新します。スクリプトはPinnFeedのREST APIを使うため、**Free**プラン(0ユーロ、30秒遅延、1日1,000リクエスト)でも動作します。 ## ステップ 1 — Freeのキーを取得する 1. [pinnfeed.io](/signup) でアカウントを作成し、[ダッシュボード](/dashboard)を開きます。 2. キーを作成してコピーします。キーは `ps_live_…` の形式です。 3. Freeでは、ダッシュボードで最大2競技を選択します。スクリプトはデフォルトでサッカー(`soccer`)を使います。別の競技を選んだ場合は `SPORT` を変更してください。 スプレッドシートにBuilderは必要ありません。Builder(月額99ユーロ、WebSocketプラン)は、[PythonとNodeのガイド](/ja/guides/pinnacle-odds-websocket-python-node)のようなリアルタイムのプッシュ型クライアント向けです。 ## ステップ 2 — スプレッドシートを作成する 1. 新しいGoogleスプレッドシートを作成します。 2. 最初のシートの名前を **Odds** に変更します(スクリプトはこの名前で検索するため、正確に入力してください)。 3. **拡張機能 → Apps Script** を開きます。サンプルの関数 `myFunction` を削除し、次のステップのためにプロジェクトを空にしておきます。 ## ステップ 3 — スクリプトを貼り付けてプロパティを設定する `Code.gs` に次のコードを貼り付けます。 ```javascript // Google Apps Script: 拡張機能 → Apps Script を開き、このファイルを貼り付けます。 // スクリプト プロパティ(プロジェクトの設定 → スクリプト プロパティ): // PINNFEED_BASE = https://pinnfeed.io // PINNFEED_KEY = ps_live_... // "Odds" という名前のシートを追加し、refreshOdds を一度実行してから、15分ごとのトリガーを追加します。 const PROPS = PropertiesService.getScriptProperties(); const BASE = PROPS.getProperty('PINNFEED_BASE') || 'https://pinnfeed.io'; const KEY = PROPS.getProperty('PINNFEED_KEY'); const SPORT = 'soccer'; // basketball、tennis などに変更可能(プランに含まれる競技に限る) function refreshOdds() { if (!KEY) { console.error('Set script property PINNFEED_KEY first'); return; } const url = BASE + '/v1/odds' + '?sport=' + encodeURIComponent(SPORT) + '&market=moneyline&main=true&live=false&limit=500'; const res = UrlFetchApp.fetch(url, { headers: { 'x-api-key': KEY }, muteHttpExceptions: true, }); const code = res.getResponseCode(); if (code !== 200) { console.warn('PinnFeed HTTP ' + code + ': ' + res.getContentText().slice(0, 300)); return; // 取得に失敗した場合はシートをそのまま残す } const data = JSON.parse(res.getContentText()); const rows = []; for (const ev of data.events || []) { const ml = (ev.markets || []).find((m) => m.type === 'moneyline' && m.main); if (!ml) continue; const byName = {}; for (const o of ml.outcomes || []) byName[o.name] = o; const home = byName.home || {}; const draw = byName.draw || {}; const away = byName.away || {}; rows.push([ ev.startTime ? new Date(ev.startTime) : '', (ev.league && ev.league.name) || '', ev.home || '', ev.away || '', home.decimal || '', draw.decimal || '', away.decimal || '', home.fair || '', draw.fair || '', away.fair || '', ml.margin != null ? ml.margin : '', ev.id, ]); } const sheet = SpreadsheetApp.getActive().getSheetByName('Odds'); if (!sheet) { console.error('Create a tab named Odds first'); return; } sheet.clearContents(); sheet.appendRow([ 'Starts', 'League', 'Home', 'Away', '1', 'X', '2', 'Fair 1', 'Fair X', 'Fair 2', 'Margin', 'Event id', ]); if (rows.length) { sheet.getRange(2, 1, rows.length, 12).setValues(rows); } console.log('Wrote ' + rows.length + ' moneyline rows for ' + SPORT); } ``` 次に、プロジェクトの歯車アイコン(**プロジェクトの設定**)を開き、**スクリプト プロパティ**に以下を追加します。 | プロパティ | 値 | |---|---| | `PINNFEED_KEY` | お客様のキー(`ps_live_…`) | | `PINNFEED_BASE` | `https://pinnfeed.io`(任意。デフォルト値です) | キーをシートのセルに貼り付けたり、Apps Scriptのプロジェクトを公開で共有したりしないでください。 ## ステップ 4 — 一度実行して承認する 1. 関数のプルダウンで `refreshOdds` を選び、**実行**をクリックします。 2. 外部サービスへの接続とシートの編集について、Googleから許可を求められます。ご自身のアカウントで承認してください。 3. シートを再読み込みします。Oddsシートに `Starts`、`League`、`Home`、`Away`、`1`、`X`、`2`、3つのフェアオッズ、`Margin`、`Event id` の列が表示されます。 呼び出しに失敗した場合(キーの誤り、リクエスト上限、プラン外の競技など)、スクリプトは警告を記録し、**以前の行をそのまま残します**。一時的な不具合でダッシュボードが空になることはありません。 ## ステップ 5 — 15分ごとのトリガーを追加する 1. Apps Scriptで**トリガー**(時計のアイコン)→ **トリガーを追加**を開きます。 2. 関数:`refreshOdds`。イベントのソース:**時間主導型**。タイプ:**分ベースのタイマー**。間隔:**15分おき**。 3. 保存します。 1競技なら1日96回の呼び出しで、Freeプランの1日1,000リクエスト・毎秒1リクエストを大きく下回ります。2競技を30分ごとに更新しても96回です。[プランと上限](/docs/limits)(英語)もご覧ください。 | トリガー | 1日の呼び出し回数 | Freeで利用可能か | |---|---|---| | 15分ごと、1競技 | 96 | はい | | 30分ごと、2競技 | 96 | はい | | 15分ごと、2競技 | 192 | はい | | 1分ごと、1競技 | 1,440 | いいえ — Hobby以上が必要(1日の上限なし) | Apps Scriptにも独自の割り当て上限があり、時間主導型トリガーの最短間隔は1分です。 ## ステップ 6 — フェアオッズとマージンを読む 1X2の各行には、[スキーマ](/docs/schema)に記載されたPinnFeedのマージンなしのフィールドが含まれます。 - `Fair 1` / `Fair X` / `Fair 2` — 各結果の小数フェアオッズ `fair`(乗法的な方法でマージンを除去)。 - `Margin` — マーケットの `margin`(オーバーラウンド=暗黙の確率の合計 − 1)。 別のシートにあるソフトなブックメーカーのオッズと比較する際は、これらの列を使います。期待値は `soft × (1 / fair) − 1` で、[バリューベットのガイド](/ja/guides/value-betting-no-vig-fair-odds)と同じ計算です。ライブのスチームを追うのにスプレッドシートは向いていません。BuilderのWebSocketと[スチーム検知のガイド](/ja/guides/dropping-odds-steam-detection)をお使いください。 ## よくある質問 ### どのPinnFeedプランが必要ですか? 数分ごとに更新される遅延ありのダッシュボードならFreeで十分です。Hobby(月額29ユーロ)では1日の上限と30秒の遅延がなくなりますが、RESTのみです。リアルタイムのプッシュには[Builder](/ja/pricing#plan-builder)(月額99ユーロ)が必要です。 ### スクリプトがURLのパラメーターではなく `x-api-key` を使うのはなぜですか? [ドキュメント](/docs/authentication)で推奨している認証ヘッダーだからです。Apps Scriptの `UrlFetchApp` はヘッダーを送信できるため、ログに残る可能性があるURLにキーを含める理由はありません。 ### 価格の推移をグラフにできますか? はい。Oddsシートはライブのダッシュボードとして使い(実行のたびに消去・再書き込みされます)、更新ごとに行を追加するだけの2枚目のシートを用意して、折れ線グラフを挿入してください。履歴のシートは消去しないでください。 ### 成人向けの教育コンテンツですか? はい。オッズデータとスプレッドシートのツールは、18歳以上の方を対象とした教育目的の内容です。予想、確実なベット、利益の約束ではありません。 ## 関連ページ - [REST APIリファレンス](/docs/rest)(英語)— `/v1/odds` のフィルターとページネーション - [マージンなしのフェアオッズでバリューベット](/ja/guides/value-betting-no-vig-fair-odds) - [Telegramの予想ボット](/ja/guides/telegram-picks-bot) — スプレッドシートでは物足りなくなったら - [料金](/ja/pricing) --- Source: https://pinnfeed.io/ja/guides/discord-picks-bot # ピナクルのライブオッズでDiscordピックボットを作る このボットはPinnFeedのWebSocketでピナクルの価格を監視し、マーケットがスチームしたとき、つまり最大ステークが100以上のマーケットでオッズが2分以内に5%以上下がったときに、Discordチャンネルへembedを投稿します。約90行の1ファイルです。チャンネルの**受信Webhook**で投稿するため、Discordライブラリもボットアカウントも不要です。 [Telegramピックボット](/ja/guides/telegram-picks-bot)のDiscord版です。検知ルールは[スチーム検知ガイド](/ja/guides/dropping-odds-steam-detection)で説明しています。18歳以上の方向けの学習用ツールであり、予想の提供ではありません。 ## ステップ 1 — Webhookを作成する 1. Discordサーバーで **サーバー設定 → 連携サービス → ウェブフック** を開き、**新しいウェブフック** を選びます。 2. 名前を付け、投稿先のチャンネルを選び、**ウェブフックURLをコピー** を使います。 3. このURLはパスワードと同じように扱ってください。URLを知っている人は誰でもそのチャンネルに投稿できます。漏れた場合はWebhookを削除し、新しく作り直してください。 ## ステップ 2 — 環境を設定する ```bash export PINNFEED_KEY="ps_live_..." # Builderプラン(WebSocket) export DISCORD_WEBHOOK="https://discord.com/api/webhooks/..." # ステップ1で取得 npm install ws ``` `DISCORD_WEBHOOK` を設定しないと、ボットは**ドライランモード**で動き、アラートを投稿せずに表示だけします。 ストリームには **Builder**(月額99ユーロ)以上が必要です。FreeとHobbyのキーは `/v1/stream` で `403 plan_lacks_ws` を受け取ります。[料金](/ja/pricing)をご覧ください。 ## ステップ 3 — ボット本体 `discord-picks-bot.mjs` として保存します。 ```javascript // discord-picks-bot.mjs: post Pinnacle steam moves to a Discord channel through an incoming webhook. // npm install ws Node 18+ (global fetch) // env: PINNFEED_KEY (Builder or higher), DISCORD_WEBHOOK (channel webhook URL; unset = dry run) import WebSocket from 'ws'; const WS_URL = process.env.PINNFEED_WS || 'wss://pinnfeed.io/v1/stream'; const { PINNFEED_KEY, DISCORD_WEBHOOK } = process.env; const MIN_DROP = Number(process.env.MIN_DROP || 0.05); // 5% shortening... const WINDOW_MS = Number(process.env.WINDOW_MS || 120000); // ...inside 2 minutes const MIN_STAKE = Number(process.env.MIN_STAKE || 100); // skip thin markets const SIDES = new Set(['home', 'away', 'draw', 'over', 'under']); const events = new Map(); const highs = new Map(); // "marketId|outcome" -> [{t, p}] const sent = new Map(); // "marketId|outcome" -> last alert time const queue = []; // embeds waiting to be posted let busy = false; const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); // One worker drains the queue, so a slow or rate-limited webhook never blocks the stream. async function drain() { if (busy) return; busy = true; while (queue.length) { const embed = queue.shift(); if (!DISCORD_WEBHOOK) { console.log('[dry run]', embed.title, '|', embed.description.replace(/\n/g, ' | ')); continue; } for (let attempt = 0; attempt < 3; attempt++) { const r = await fetch(DISCORD_WEBHOOK, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ embeds: [embed], allowed_mentions: { parse: [] } }), }).catch((e) => ({ ok: false, status: 0, text: async () => e.message })); if (r.status === 429) { const b = await r.json().catch(() => ({})); await sleep(1000 * (b.retry_after ?? 1)); continue; } if (!r.ok) console.error('discord', r.status, await r.text()); break; } } busy = false; } function post(embed) { queue.push(embed); if (queue.length > 50) queue.shift(); // an alert from minutes ago is no longer news drain(); } function check(m) { const ev = events.get(m.eventId); if (!ev || (m.maxStake ?? 0) < MIN_STAKE) return; const now = Date.now(); for (const o of m.outcomes) { if (!SIDES.has(o.name)) continue; const k = `${m.id}|${o.name}`; const h = (highs.get(k) || []).filter((x) => now - x.t < WINDOW_MS); h.push({ t: now, p: o.decimal }); highs.set(k, h); const high = Math.max(...h.map((x) => x.p)); const drop = 1 - o.decimal / high; if (drop < MIN_DROP || now - (sent.get(k) || 0) < WINDOW_MS) continue; sent.set(k, now); const pick = o.name === 'home' ? ev.home : o.name === 'away' ? ev.away : o.name; const line = o.points == null ? '' : m.type === 'total' ? ` ${o.points}` : ` ${o.points > 0 ? '+' : ''}${o.points}`; post({ title: `📉 ${ev.home} v ${ev.away}`, description: `**${pick}** (${m.type}${line})\nPinnacle ${high.toFixed(2)} → ${o.decimal.toFixed(2)} (−${(drop * 100).toFixed(1)}%)\n` + `Fair now ${o.fair.toFixed(2)} · max stake ${m.maxStake}`, color: 0xe8590c, footer: { text: `${ev.sport.toUpperCase()} · ${ev.league?.name ?? ''} · 18+ · not a tip` }, timestamp: new Date(now).toISOString(), }); } } function connect(delay = 1000) { const ws = new WebSocket(WS_URL, { headers: { 'x-api-key': PINNFEED_KEY }, perMessageDeflate: true }); ws.on('open', () => { delay = 1000; ws.send(JSON.stringify({ type: 'subscribe', sports: ['soccer', 'tennis', 'basketball'], markets: ['moneyline', 'spread', 'total'], main: true, specials: false })); }); ws.on('message', (raw) => { const msg = JSON.parse(raw); if (msg.type === 'ping') return ws.send('{"type":"pong"}'); if (msg.type === 'snapshot') msg.events.forEach((e) => events.set(e.id, e)); if (msg.type === 'delta') for (const c of msg.changes) { if (c.kind === 'event') c.op === 'upsert' ? events.set(c.event.id, c.event) : events.delete(c.id); if (c.kind === 'market' && c.op === 'upsert') check(c.market); } }); ws.on('close', () => setTimeout(() => connect(Math.min(delay * 2, 30000)), delay)); ws.on('error', (e) => console.error('ws error:', e.message)); } connect(); ``` 処理の流れは次のとおりです。 - サッカー、テニス、バスケットボールのメインライン(マネーライン、スプレッド、トータル)を**購読**します。`sports` はプランの13競技のどれにでも変更できます。すべてのフィルターは[WebSocketプロトコル](/docs/websocket)(英語)に載っています。 - マーケットとアウトカムごとに**2分間のウィンドウ**を保持し、ウィンドウ内の最高値から `MIN_DROP` 以上下がったら検知します。限度額が低いマーケットの動きは意味が薄いため、`MIN_STAKE` 未満のマーケットは無視します。 - **投稿をキューに入れます。** 1つのワーカーがWebhookへembedを送るので、Webhookが遅くても制限されても、ストリームの受信は止まりません。待機中のアラートが50件を超えると、最も古いものを捨てます。 - **429に従います。** Discordは連続投稿に対して `429` を返し、JSON本文に秒単位の `retry_after` を含めます。ボットはその時間だけ待って再送し、最大3回まで試します。 - **メンションしません。** `allowed_mentions: { parse: [] }` により、チーム名や選手名でチャンネルの誰かがメンションされることはありません。 ## ステップ 4 — 実行してテストする ```bash node discord-picks-bot.mjs ``` ドライランモードでは、アラートは次のように表示されます。 ```text [dry run] 📉 Udinese v Fiorentina | **Udinese** (spread +0.25) | Pinnacle 1.88 → 1.70 (−9.6%) | Fair now 1.75 · max stake 150 ``` Discordでは同じアラートがembedになります。タイトルに試合、本文にサイドとオッズの動き、最終行にマージンを除いたフェアオッズと最大ステーク、フッターに競技、リーグ、「18+ · not a tip」の注記が入ります。 量は環境変数で調整します。たとえば `MIN_DROP=0.08` で件数を減らして強い動きだけにしたり、`MIN_STAKE=500` で厚いマーケットだけに絞ったりできます。 ## ステップ 5 — 常時稼働させる - `systemd`、`pm2`、または失敗時に再起動するコンテナで動かします。ボットはバックオフ付きでWebSocketに自動再接続し、新しいスナップショットからイベント一覧を作り直します。 - Webhookはチャンネルごとに1つで足ります。サッカーとテニスを別チャンネルにしたい場合は、`sports` とWebhookを変えた2つのコピーを動かしてください。Builderのキーでは3本のWebSocket接続が使えます。 - 成績は正直に記録しましょう。各アラートを記録し、的中率ではなく[クロージングラインバリュー](/ja/guides/closing-line-value-clv-tracking)で測定してください。 - サーバーで何を投稿し、どうモデレートするかは[Discordサーバーのユースケース](/use-cases/discord-servers)(英語)を参照してください。 ## よくある質問 ### Discordボットに必要なPinnFeedのプランは? WebSocketを読むため、Builder(月額99ユーロ)以上が必要です。比較には[ライブとプレマッチの両方を配信するWebSocketの料金ページ](/ja/cheapest-pinnacle-odds-websocket)をご覧ください。有料プランには3日間の無料トライアルがあります。カードの登録が必要で、解約しない限り3日目の後に課金されます。 ### Freeプランで動かせますか? このままでは動きません。FreeはRESTのみで30秒の遅延があります。FreeやHobbyで更新頻度の低いボットを作る場合は、`/v1/drops` を1分ごとにポーリングし、結果を同じWebhookに投稿してください。[RESTドキュメント](/docs)(英語)をご覧ください。 ### Discordのボットアカウントやdiscord.jsは必要ですか? 不要です。受信Webhookは単純なJSONの `POST` を受け付けるので、ボットに必要なのは `fetch` だけです。スラッシュコマンドや返信が欲しい場合に限り、discord.jsとボットアカウントを使ってください。 ### チャンネルがアラートで埋まらないようにするには? `MIN_DROP` や `MIN_STAKE` を上げ、`sports` を絞り、アウトカムごとのクールダウン(マーケットのサイドごとに `WINDOW_MS` あたり1件)を維持してください。キューの上限により、古いアラートは遅れて投稿されずに捨てられます。 ### Discordサーバーで予想を公開することは合法ですか? 予想の公開や賭博の広告に関するルールは国によって異なります。日本では刑法により賭博は原則として禁止されており、スポーツに関するベッティングで認められているのは、競馬・競輪・競艇・オートレースといった公営競技やスポーツくじ(toto)など、法律で定められたものに限られます。Discordにも独自のコミュニティガイドラインがあります。ご自身とメンバーがいる地域のルールを確認し、サーバーは18歳以上に限定し、アラートを確実な利益として紹介しないでください。これは法的助言ではありません。