市场怎么判定输赢

加密涨跌市场按 Chainlink 的流判定,不按盘口。用哪条流是市场自己的属性,而归档里已经带齐了你自己重算一遍所需要的全部东西。

两个必须知道的口径

结算规则变过,别按日期推

2026-08-07(UTC) 之前用瞬时 Chainlink 流判定,之后改用 TWAP 流:当时 5 分钟市场用 30 秒回看、15 分钟用 60 秒;2026-08-14(UTC) 之后 5 分钟市场也改成了 60 秒,现在两种周期都判定在 twap60s 上。所以该用哪条流,要看这个市场自己的 raw.cryptoMarketConfig(twapEnabled 与 twapLookbackSeconds=30 或 60),不要按日期推——同一天里不同配置的市场是并存的。twap30s 仍在逐日归档,只是不再是任何市场的判定线。

帧是按收到的样子存的

乱序也照存,我们不在归档期做重排。要按时间顺序处理,请在查询时自己排序

自己重算一遍结果

这一步不需要你信我们的话——strike、窗口、判定用的那条流,全都在你已经下载的文件里。

1读市场那一行:start_sec、end_sec、strike_value,以及 raw.cryptoMarketConfig.twapLookbackSeconds。
2按那个回看秒数挑流——60 对应 twap60s,30 对应 twap30s——取它在窗口收尾时刻的值。
3与 strike_value 比较。Polymarket 侧两者都是 1e18 定点,所以两边都转成整数再比,不要比浮点、也不要按字符串比:value 是为了查询方便,只要 relay 发布过,该用来判定的是 full_accuracy_value。
4拿同一行的 outcome_prices 核对自己算的结果。["1","0"] 是 Up,["0","1"] 是 Down。

上面四步写成代码

读你已经下载的那两个文件,逐个市场打印结论。它按时间戳取收尾那一条,而不是按它在文件里的位置——帧是按到达顺序归档的。

import gzip, json, csv

MARKETS = "BTC-5m-markets.jsonl.gz"      # one line per market, as downloaded
STREAMS = {                              # each market names the one it settles on
    60: "BTCUSD-twap60s-prices.csv.gz",
    30: "BTCUSD-twap30s-prices.csv.gz",
    0:  "BTCUSD-prices.csv.gz",          # before TWAP, the instantaneous feed
}

_loaded = {}
def stream(lookback):
    if lookback not in _loaded:
        with gzip.open(STREAMS[lookback], "rt") as f:
            _loaded[lookback] = list(csv.DictReader(f))
    return _loaded[lookback]

for line in gzip.open(MARKETS, "rt"):
    m = json.loads(line)
    # strike_value is null when it could not be established honestly
    if not m.get("resolved") or m.get("strike_value") is None:
        continue

    # Read the stream off the MARKET, never off the date: configs coexist on
    # one day. A MISSING config is a record we could not read — not evidence
    # of the pre-TWAP era — so it is skipped. Only an explicit null or 0 says
    # "this one settled on the instantaneous stream".
    raw = m.get("raw")
    cfg = raw.get("cryptoMarketConfig") if isinstance(raw, dict) else None
    if not isinstance(cfg, dict) or "twapLookbackSeconds" not in cfg:
        continue
    lookback = cfg["twapLookbackSeconds"]
    if lookback is None:
        lookback = 0
    if lookback not in STREAMS:
        continue                         # unknown config: refuse rather than guess

    open_ms, close_ms = m["start_sec"] * 1000, m["end_sec"] * 1000
    window = [t for t in stream(lookback)
              if open_ms <= int(t["feed_ts_ms"]) <= close_ms]
    if not window:
        continue

    # by timestamp, not by file order: frames are archived as received
    last = max(window, key=lambda t: int(t["feed_ts_ms"]))

    # full_accuracy_value is 1e18 fixed point ONLY when the relay published it;
    # otherwise the collector wrote str(value) and the archive cannot tell you
    fixed = last["full_accuracy_value"]
    if not fixed.isdigit():
        continue                         # a decimal fallback, not fixed point
    settled = int(fixed)
    if abs(settled / 1e18 - float(last["value"])) > 1e-6:
        continue                         # an integer, but not at the 1e18 scale

    # only a COMPLETE binary pair is an outcome; anything else is bad metadata
    prices = m.get("outcome_prices")
    if prices not in (["1", "0"], ["0", "1"]):
        continue

    # the market resolves Up when the close is >= the strike, not > it
    mine   = "UP" if settled >= int(m["strike_value"]) else "DOWN"
    theirs = "UP" if prices[0] == "1" else "DOWN"
    print(m["slug"], mine, "matches" if mine == theirs else "DIFFERS")

Predict.fun 的判定方式不一样

Predict.fun 的市场行带 start_price 与 end_price 两个普通十进制数,结果由两者比较得出。判断有没有结算要看 end_price,不要看 status:status 是上游最后一次报的状态,而市场一旦拿到 end_price 就退出重读队列,所以一个已经结算的市场,status 可能还停在 OPEN。end_price 与 start_price 相等是平局,那是第三种结果,不是任何一侧获胜。

相关: Polymarket 盘口数据 · Chainlink 结算价数据 · Predict.fun 历史数据 · 与其他服务商的对比