用 Python 留存市场研究依据
搜索事件,核对市场与结果资产,再保存盘口、源时间、观测时间和原始响应。适合研究记录、数据对照和应用接入评估。
无需登录即可阅读本案例;运行代码需要有效付费套餐和只读 API Key。页面不代你调用接口,也不提供匿名调试器。
一次实际运行
采集时间:。执行环境:AWS 爱尔兰节点,HTTPS 客户接口;非国内用户环境。这是单次技术记录,不代表国内可达性、持续成功率或交易资格。上游当前 v2 canary 市场;本次成功不代表所有常规市场或流动性覆盖。
- 搜索词
- Bahcesehir Koleji
- 搜索返回的事件
- 1218745
- 市场
- 5931598 · Bahcesehir Koleji vs. Besiktas
- 结果
- Bahcesehir Koleji ·
534431567902566368018385983072631079381328077538165832970367261582458617856 - 身份核对
- matched
- 盘口源时间
- 2026-10-24T18:48:59.579Z
- 源时间解析器
- clob-book.v2.unix-ms@1
- 观测完成时间
- 2026-10-25T00:11:23.348770Z
- 买卖盘档数
- {'bids': 1, 'asks': 0}
搜索返回事件关联;市场详情未返回event_ids,未补填,未完成事件关联的二次核验。 该次盘口买盘 1 档、卖盘 0 档;空的一侧如实保留,不代表可成交性。
源时间原始值:1792867739579。
源时间来自上游可验证时间戳;观测时间来自本服务接收过程,两者不能互相替代。未返回或未验证的源时间保留为 null。
盘口必要字段摘录
bids: [{'price': '0.05', 'size': '5'}]
asks: []
binding_status: matched
quote_freshness: not_guaranteed上方为便于阅读的字段摘录,不是原始响应字节;SHA-256以下载文件和evidence指定字节为准。
请求与用量
| 调用 | HTTP / 结果 | 请求编号 | 上游请求 / 响应 |
|---|---|---|---|
| search | 200 / success | 88e22c44-7f40-48ab-94b0-4ad34f505ccd | 1 / 1 |
| snapshot | 200 / success | 7ced93cf-9e25-4a7a-8d25-95c465e12220 | 2 / 2 |
| mismatch | 409 / MARKET_BINDING_MISMATCH | 9ad5b7ef-9485-42b6-ae0e-c515a414c0b5 | 1 / 1 |
本次 3 次放行调用消耗 3 次普通额度,包括身份不匹配的错误调用;上游实际发出 4 次 GET。鉴权、权限或限流拒绝不占普通额度。登录控制台,在“当前周期用量”和“最近调用”按上表请求编号核对,分页与重新搜索会产生新调用。
实际错误处理
对同一市场提交不属于它的结果资产 0,实际返回 HTTP 409、MARKET_BINDING_MISMATCH,未请求盘口。此时重新核对市场与结果,不应把另一个市场的盘口拼入本次记录。
响应依据
下列下载保留本次服务端响应原始字节;其中 evidence.body_base64 对应上游已解压响应字节,body_sha256 与 body_byte_length 仅校验这些确切字节。下表另列整份下载文件的 SHA-256,不将摘录或重新序列化内容冒充原文。可核验摘要不保证上游数据本身正确。
- search.response.json · 298144 字节 ·
77f764ca7d210eaf93e2a21c94a73f16aaa97ee242592d921980d80f4bc1858b - snapshot.response.json · 9909 字节 ·
5ee9984a15e632a88de992ee6a9900efa769f036308b8def67de8907042cc915 - mismatch.response.json · 5835 字节 ·
236e7e38be83fd032768d813fcde54cb6e598df2e90541c7d2f6315ef2c5e6bc
最小 Python 示例
Python 3.11 及以上,无第三方依赖。先在自己的服务端安全设置环境变量 POLYSTADIO_API_KEY。先搜索并核对候选,再传入市场与结果标识运行。每次运行搜索会占一次调用;执行快照再占一次。
python3 research_snapshot.py "事件关键词"
python3 research_snapshot.py "事件关键词" --market-id MARKET_ID --outcome-id OUTCOME_ID查看完整示例代码
#!/usr/bin/env python3
"""Read-only research example. Python 3.11+, standard library, paid read API Key.
POLYSTADIO_API_KEY is read only from the environment and is never printed.
Historical identifiers and a successful prior capture do not promise a live book.
"""
import argparse
import base64
import hashlib
import json
import os
from pathlib import Path
from urllib.error import HTTPError
from urllib.request import Request, urlopen
ORIGIN = 'https://api.polystadio.com'
def call(operation, payload, output):
request = Request(ORIGIN + '/v1/market-data/polymarket/' + operation,
data=json.dumps(payload).encode(), method='POST',
headers={'Authorization': 'Bearer ' + os.environ['POLYSTADIO_API_KEY'],
'Content-Type': 'application/json'})
try:
response = urlopen(request, timeout=25)
except HTTPError as error:
response = error
with response:
raw = response.read()
status = response.status
# Exact service response bytes, before json.loads or reserialization.
(output / (operation + '.response.json')).write_bytes(raw)
result = json.loads(raw)
for receipt in result['evidence']:
if receipt['body_base64'] is not None:
body = base64.b64decode(receipt['body_base64'], validate=True)
assert len(body) == receipt['body_byte_length']
assert hashlib.sha256(body).hexdigest() == receipt['body_sha256']
print(json.dumps({'http_status': status, 'request_id': result['request_id'],
'error': result['error'], 'upstream': result['upstream_summary']}, ensure_ascii=False))
if status != 200:
code = (result.get('error') or {}).get('code')
if code == 'MARKET_BINDING_MISMATCH':
raise SystemExit('市场与结果标识不匹配,请重新核对搜索结果,不要跨市场拼接盘口。')
if status in (401, 403):
raise SystemExit('请核对Key权限、套餐有效期和服务端环境变量;API Key不能替代网站登录。')
raise SystemExit('调用未成功,请用请求编号在控制台核对;不要盲目循环重试。')
return result
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('query', help='事件关键词;搜索有界,不保证穷尽全部市场')
parser.add_argument('--market-id', help='从搜索结果明确选择市场,不能仅凭名称猜测')
parser.add_argument('--outcome-id', help='从选中市场的outcomes明确选择结果资产')
parser.add_argument('--output', type=Path, default=Path('research-evidence'))
args = parser.parse_args()
if not os.environ.get('POLYSTADIO_API_KEY'):
parser.error('请先在本机安全设置环境变量 POLYSTADIO_API_KEY,不要将Key发到聊天或写入源码。')
args.output.mkdir(parents=True, exist_ok=True)
search = call('search', {'query': args.query, 'limit': 10}, args.output)
candidates = search['data']['candidates']
print(json.dumps(candidates, ensure_ascii=False, indent=2))
selected = [c for c in candidates if c['market_id'] == args.market_id]
if len(selected) != 1 or args.outcome_id not in {o['outcome_id'] for o in selected[0]['outcomes']}:
raise SystemExit('搜索已保存。请核对上述事件、市场和结果后,传入--market-id与--outcome-id重新运行。')
market = selected[0]
snapshot = call('snapshot', {'market_id': market['market_id'], 'outcome_id': args.outcome_id,
'identifier_schema': market['identifier_schema']}, args.output)
data = snapshot['data']
assert data['binding_status'] == 'matched'
print(json.dumps({'market': data['market']['question'], 'event_ids': data['market']['event_ids'],
'selected_outcome_id': data['market']['selected_outcome_id'],
'source_book_at': data['orderbook']['source_book_at'],
'observed_at': data['collection_completed_at'],
'levels': data['orderbook']['returned_count']}, ensure_ascii=False, indent=2))
if __name__ == '__main__':
main()
下一步
已有账户请登录,确认套餐生效后创建 Key。完整文档与 OpenAPI 下载继续需要网站登录。