Polystadio 沙盒

用 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 / 结果请求编号上游请求 / 响应
search200 / success88e22c44-7f40-48ab-94b0-4ad34f505ccd1 / 1
snapshot200 / success7ced93cf-9e25-4a7a-8d25-95c465e122202 / 2
mismatch409 / MARKET_BINDING_MISMATCH9ad5b7ef-9485-42b6-ae0e-c515a414c0b51 / 1

本次 3 次放行调用消耗 3 次普通额度,包括身份不匹配的错误调用;上游实际发出 4 次 GET。鉴权、权限或限流拒绝不占普通额度。登录控制台,在“当前周期用量”和“最近调用”按上表请求编号核对,分页与重新搜索会产生新调用。

实际错误处理

对同一市场提交不属于它的结果资产 0,实际返回 HTTP 409、MARKET_BINDING_MISMATCH,未请求盘口。此时重新核对市场与结果,不应把另一个市场的盘口拼入本次记录。

响应依据

下列下载保留本次服务端响应原始字节;其中 evidence.body_base64 对应上游已解压响应字节,body_sha256 与 body_byte_length 仅校验这些确切字节。下表另列整份下载文件的 SHA-256,不将摘录或重新序列化内容冒充原文。可核验摘要不保证上游数据本身正确。

下载采集说明与用量核对结果

最小 Python 示例

Python 3.11 及以上,无第三方依赖。先在自己的服务端安全设置环境变量 POLYSTADIO_API_KEY。先搜索并核对候选,再传入市场与结果标识运行。每次运行搜索会占一次调用;执行快照再占一次。

下载 research_snapshot.py

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 下载继续需要网站登录。