文档

参与 Quant Arena 需要知道的全部内容:提交什么、策略契约、数据、评分,以及你会拿到什么结果。

快速开始

从收到邀请到看到自己的成绩,最短的路径。每一步都指向详细说明的章节。

  1. 拿到账号。 打开我们发来的邀请链接,设置用户名和密码;或者直接用飞书登录。如何参加

  2. 添加你的模型。 agent 运行调用你自己的模型:在模型页面添加它的 endpoint、API key 和模型名。你的模型

  3. 安装 SDK。 wheel 随邀请一起给你。

python -m pip install 'navers_quant_sdk-<版本>-py3-none-any.whl[flight]'
  1. 写一个策略:main.py 中的 POLICY,它的 score_day 为每只股票返回一个分数。每次运行都给一个策略打分:在 agent 基准上由你的 agent(或基准的 harness)在运行中写出(Harness),在策略基准上由你提交。策略契约
import pyarrow as pa
import pyarrow.compute as pc
from navers_quant_sdk.eval import DataSpec, Policy


class MyPolicy(Policy):
    data = DataSpec(daily=["close"], history_days=20)

    def score_day(self, today, history, date, info):
        bars = history["daily"]
        rows = pa.table({"symbol": bars["symbol"], "session": bars["session"],
                         "close": pc.cast(bars["close"], pa.float64())})
        # 每只股票在窗口内第一个和最后一个收盘价(行不按时间排序)。
        last = (rows.sort_by([("symbol", "ascending"), ("session", "ascending")])
                .group_by("symbol", use_threads=False)
                .aggregate([("close", "first"), ("close", "last")]))
        # 反转:窗口内跌得越多,分数越高。
        return pa.table({"instrument": last["symbol"],
                         "score": pc.subtract(last["close_first"], last["close_last"])})


POLICY = MyPolicy
  1. 发起运行:在 Eval 页面选择基准;agent 基准再选择赛道和你的一个模型,harness 赛道还要选择代码(上传代码包、在编辑器里写 main.py、复用已有提交,或使用赛道的 harness)。在策略基准上,命令行可以做同样的事:
export NAVERS_QUANT_ARENA_URL=<邀请中的站点地址>
navers-arena login
navers-arena submit ./my_strategy --suite <基准 id> --wait
  1. 看结果。 运行页面给出评分卡、结果和净值;navers-arena result <run-id> --output ./result 下载评分卡和结果文件。上榜的运行出现在场次中该基准的排行榜上。运行与结果

概览

Quant Arena 评测完整的量化研究过程。你提交一个调用你自己模型的研究 agent(harness),或让基准的 harness 驱动你的模型,或者在策略基准上直接提交一个策略。agent 在 cutoff 之前的公开数据上做研究,并交出一个策略;平台随后在研究中不可见的时段上逐日给这个策略打分,把分数当作组合回放,并算出结果。同一基准的每次运行都在相同的注册条件下评测。方法见论文(论文与引用)。

2.1 基准、运行与排行榜

术语接口中的名字含义
基准suite一场比赛,设定冻结:数据版本、评测日、作业及其上限、模型额度和评分权重。设定改变就是新基准
提交submission你交出的东西:代码包(harness 或策略)。一个提交可以跑多个基准
赛道track参加 agent 基准的方式:平台循环驱动你的模型(轮数由平台设定,一轮即 one-shot),或由 harness(你的或赛道的)调用你的模型
运行episode在基准的一个赛道上的一次评测:agent 作业、每个评测日一个作业,然后平台的评分作业和评分卡
排行榜leaderboard一个赛道上已完成运行的排名:每位参赛者每个模型取最好的一次

一次运行依次是 queued、running、scoring,最后是 completed、failed 或 cancelled;运行中可以暂停,之后再继续(失败与恢复)。

如何参加

评测目前仅限受邀参与。 如需申请,请发邮件至 nana@einsia.ai。 本文档和公开排行榜无需账号即可阅读。

账号有两种。邀请注册: 我们会给你发一个对应邮箱的链接,打开后填入该邮箱并设置用户名和密码,之后用其中任一方式登录。用户名就是你在排行榜上的显示名,之后不能修改。飞书单点登录: 直接用飞书账号登录。如果飞书账号的邮箱与邀请一致,两种方式进入同一个账号。排行榜不会显示你的邮箱地址。

3.1 邀请里有什么

项目用途
SDK wheel策略基类、navers-arena 命令行和 agent 工具
基准 id你受邀参加的基准,用于 --suite
站点地址NAVERS_QUANT_ARENA_URL,即本页所在的域名

API key(Arena 的和你的模型供应商的)请放在只有你能读的文件里,不要写进代码、代码包、URL 或日志。

3.2 命令行登录

navers-arena login 会打印一个链接;在已登录的浏览器里打开它,输入终端显示的配对码并确认。命令行随后拿到一个 API key,保存在只有你能读的文件里(默认 ~/.config/navers-quant/arena-api-key);navers-arena logout 会撤销它。也可以在 API keys 页面创建和撤销。key 只显示一次,以 Authorization: Bearer nqk_… 发送,权限按范围划分:arena:read 读取你的账号、提交、运行和排行榜,arena:submit 上传提交并开始、暂停、继续或取消你的运行。

提交什么

每次运行评测一个策略,属于基准的一个赛道。赛道决定你交什么、策略由谁写:

赛道你提交谁写策略
Vanilla iteration你的一个模型,不带代码平台循环按设定的轮数调用你的模型;一轮即 one-shot
Harness一个带 main.py 的 agent 代码包,以及你的一个模型你的 agent,在运行中调用你的模型
Harness你的一个模型,不带代码赛道的 harness(例如 Claude Code)调用你的模型
策略基准一个带 main.py 的策略代码包你自己,在运行之前

每个赛道有自己的轮数、评估次数和 token 额度,Eval 页面会显示。

平台不提供模型:agent 运行调用你自己的模型之一,在开始运行时选择。

无论哪种,被打分的策略都遵守策略契约,在每天之前的数据上逐日打分。只有平台的评测算数,agent 自己的检查不会进入结果。

4.1 Harness

harness 就是你的研究 agent:一个 main.py 位于顶层的 .zip 或 .tar.gz,运行开始时在一个 sandbox 作业,即这次运行的 agent 作业里,以 python main.py 启动一次。在这个作业里,agent 用 SDK 的数据客户端读取基准在 agent cutoff 之前的公开数据(每个作业能读到什么),通过平台的模型网关、在本次运行的 token 额度内调用本次运行的模型,把候选策略交给平台评估(研究评估),最后选定一个已完成的 trial。没有选定时,以 write_strategy 写出的策略为准;什么都没交的 agent 使这次运行失败。

from pathlib import Path
from navers_quant_sdk.arena import openai_client
from navers_quant_sdk.arena.agent import Research

client = openai_client()   # 指向本次作业模型网关与凭证的 openai.OpenAI 客户端
reply = client.chat.completions.create(
    model="<你为本次运行选择的模型>",
    messages=[{"role": "user", "content": "提出一个日频选股因子 ..."}],
)
# ... 把方案写进 candidate/main.py ...
research = Research()
trial = research.evaluate(Path("candidate"), key="round-1")   # 由平台评估
trial = research.wait(trial["trial_ref"])                     # 反馈,或失败报告
research.finish(trial["trial_ref"])                           # 这次运行要打分的策略

模型网关在 SDK 的重试之间保持同一个 Idempotency-Key,所以连接中断后重试的调用会拿到已记录的答复,而不是重复计费;同一个 key 配不同的请求会被拒绝。超出剩余额度的调用返回 429,budget() 显示还剩多少。工具在你自己的 agent 里执行:供应商侧工具、远程 URL 和供应商文件引用都会被拒绝,图片和文档必须内联。按你的 endpoint 的协议调用:chat、responses 或 messages(budget()["protocol"] 给出协议);在作业使用 agent 镜像的基准上,main.py 可以用 agent_cli.run("claude_code") 把研究交给 Claude Code。完整清单见 SDK、命令行与 HTTP API。

4.2 研究评估

每个赛道设定一次运行的研究评估次数:迭代和 harness 赛道为 5 次,one-shot 没有。平台在 sandbox 中、在基准的研究窗口上评估候选策略,使用完整的评测数据和与最终评估相同的回放;agent 读不到这些数据,只拿到反馈:

  • 窗口指标(比率保留 4 位小数)、按名字至多 32 个声明特征的摘要、执行、覆盖和多样性摘要(K 和合格特征数)、资格,以及剩余评估次数;
  • 主组合按年的摘要及最好、最差的月份;monthly_returns、monthly_ic、quantile_groups、signal_validity、execution_issues 各节逐个读取,不占评估次数;
  • 策略失败时,Python 内置异常名和你代码中的文件与行号,或拒绝结果的输出检查。不返回异常消息、打印输出和日志。

评估完成和策略失败各用一次;平台故障不用,可以再次提交同一个候选。同时只评估一个。agent 最后选定一个已完成的 trial,它的策略冻结后原样打分;没有选定时,平台循环和 Claude Code harness 选定最近一个已完成的 trial。特征值、个股和成交都不是反馈,最终窗口也不是。

4.3 你的模型

在模型页面添加你的模型:一个 endpoint 包括公网可访问的 https base URL、协议(OpenAI Chat Completions、OpenAI Responses 或 Anthropic Messages)、API key,以及在这里调用的模型名。开始 agent 运行时,你选择一个 endpoint 和它的一个模型。你的 agent 按名称调用这个模型,平台用你的 key 把每次调用转发到你的 endpoint。不带自己的 agent 时,由基准的 harness(基准为该协议提供时)驱动这个模型。

调用由你的供应商计费。平台记录每次调用的请求、响应和 token 用量,基准限制一次运行的调用次数和 token。模型页面按 endpoint 和运行列出输入、输出 token;运行页面列出它的调用。key 加密保存,只用于这些调用,不再显示(只显示最后四个字符)也不写日志,可以替换。只访问公网地址,不跟随重定向。删除被运行用过的 endpoint 时,它仍为那些运行保留。

4.4 代码包与 sandbox

代码包是一个 main.py 位于顶层的 .zip 或 .tar.gz,harness 和策略格式相同。Eval 页面可以上传代码包、复用已有提交,或打包在页面编辑器里写的 main.py。只接受普通文件和普通相对路径的目录(不允许链接、绝对路径和 ..);被拒绝的代码包会逐条列出问题和对应路径。

代码在 Python 3.14(Linux x86-64)中运行,没有网络,也不能安装包。sandbox 预装 navers-quant-sdk、pyarrow 26.0.0、numpy 2.5.4、pandas 3.1.0、polars 2.0.0、duckdb 2.0.0、scipy 1.18.1、statsmodels 0.15.0、numba 0.68.0、scikit-learn 1.9.1、lightgbm 4.7.0、matplotlib 3.11.2、orjson 3.13.0、tqdm 4.70.1、python-dateutil、pytz 和 openai 3.37.0;本地请使用相同版本。不要把凭证放进代码包,也不要打包基准允许范围之外的行情数据(参赛条款 §5.1)。提交只保留一段时间,已在排行榜上的运行对应的提交除外。

策略契约

策略是一段 Python 代码:main.py 定义 POLICY,它是 navers_quant_sdk.eval.Policy 的子类。策略用 DataSpec 声明需要的数据;平台读取这些数据,并在每个评测日调用 score_day,score_day 为每只股票返回一个分数。策略自己不读数据、不持有凭证,也没有网络访问。

import pyarrow as pa
from navers_quant_sdk.eval import DataSpec, Policy


class MyPolicy(Policy):
    data = DataSpec(quotes=["bid_volume_1", "ask_volume_1"], intraday=("14:50", "14:56:59"), history_days=5)

    def __init__(self, info):                  # 可选:加载或训练模型
        ...

    def score_day(self, today, history, date, info):
        ...
        return pa.table({"instrument": symbols, "score": scores})


POLICY = MyPolicy                              # 是类本身,不是实例

agent 交出的也是同一个策略,直接提交给策略基准的也是它。

5.1 DataSpec

类上的 data = DataSpec(...) 是必需的,只接受关键字参数:daily、quotes、trades、orders、order_queues 和 auction 接受不重复的非空字段名列表(数据集与字段);intraday 接受一对 ("HH:MM", "HH:MM")(可带秒)、若干互不重叠的对,或 None 表示全天;history_days 取 0 到 250(默认 0);instruments 取 None(当天股票池)或代码列表。身份列 symbol、session 和 event_time 会自动带上。

  • intraday 包含起点,终点只到该秒的第 0 毫秒:("14:50", "14:56:59") 读到 14:56:59.000,("14:55", "15:00") 包含 15:00:00.000 但不含 15:00:03 的收盘快照(要读它请写 "15:00:05")。它作用于 quotes、trades、orders 和 order_queues。
  • DataSpec 写错时在导入 main.py 时就失败;基准数据里没有某个数据集或字段时在任何数据被读取之前失败。两种情况下这次运行都失败。
  • 只声明需要的东西。 全市场约 3 秒一条、全字段的快照一天可达数 GB,而且评测要为窗口的每一天读一遍。

5.2 score_day 及其输出

score_day(self, today, history, date, info) 是必需的:

参数内容
todaydict[str, pyarrow.Table]:当天的数据,每个声明的数据集一张表,含声明的字段和身份列。行不保证按时间排序
historydate 之前 history_days 个交易日的同样数据集,按序拼接;用 session 区分是哪一天
datetoday 对应的交易日,YYYY-MM-DD
infocutoff、universe、calendar、window、data_version、contract_version、scratch(可写目录,也是工作目录)和 restart

__init__(self, info) 是可选的,最先运行,info 的键相同;info["history"] 是作业打分那天之前的交易日。可以用它加载或训练模型。

返回值是 pyarrow.Table、pyarrow.RecordBatch 或 pandas.DataFrame,含 instrument 列(代码,每只股票最多一行)和 score 列(float64,越大越有吸引力;null 表示没有看法,否则必须有限)。只有分数的次序有意义,大小和正负都无所谓;当天股票池之外的股票行会被丢弃,没有行的股票当天没有分数。空表是合法的。返回 None、缺少列、类型不对、代码格式错误或重复、分数非有限,或超过 10 万行,都会让当天无效。

  • 价格和成交量是精确十进制数。计算前请在 pyarrow 里转成 float64(pyarrow.compute.cast(column, pa.float64())):对 decimal 列调用 to_pandas() 会得到很慢的、由 Python Decimal 组成的 object 列。

5.3 声明的特征

instrument 和 score 之外的列是声明的特征,评分中的多样性由它们算出:最多 300 个 float64 数值列,名字匹配 [A-Za-z][A-Za-z0-9_]{0,63} 且不是 session 或 score,取值有限或为 null,数值越大表示预期收益越高。每个评测日返回同一组特征;某天不同就使这次运行失败。只有真正被分数使用的独立特征组才计入,而且多样性在基准的聚类上限处饱和,所以多声明特征并不会提高它。

return pa.table({"instrument": symbols, "score": score, "momentum": momentum, "reversal": reversal})

5.4 评测日如何运行

每个评测窗口是一个 sandbox 作业,给窗口里的每一天打分,并且第 D 天的分数只用 D 之前的数据:

sD=f(FP),P=第 D 天之前的最后一个交易日s_D = f(\mathcal{F}_P), \qquad P = \text{第 } D \text{ 天之前的最后一个交易日}
  • 对第 D 天,作业给 P 打分:today 是 P 截至收盘的数据(含 P 的日线),history 是 P 之前的交易日,date 是 P。分数记为 D,平台从 D 起据此交易。也就是说,策略用一个收盘为止的数据给下一个交易日的股票排序。
  • 作业把窗口的交易日分成连续的几段并行打分,每段在自己的隔离进程里。进程开始时调用一次 __init__(history 为它第一天之前的数据),然后按顺序对它的每一天调用 score_day。分段方式由基准固定,但崩溃的进程会重启并再次调用 __init__,所以某一天的分数应只取决于传进来的东西。需要更早的日期时,通过 history_days 从 history 取。
  • 进程只能看到自己那一天的数据。进程之间、与网络和模型网关之间都不通;只有作业的 harness 读取数据服务。
  • 每次 score_day 有 15 分钟。一个窗口的整个作业有每个评测日 15 分钟再加 5 分钟,最多 4 小时。
  • 任何一天失败——异常、超时、崩溃或输出无效(包括声明的特征与第一个打分成功的日子不同)——都会使这次运行失败。数据服务拒绝读取的日子记为没有分数的失败日,其余日子照常进行。

5.5 一个完整的策略

收盘前十档盘口失衡

14:50 到 14:56:59 之间,买量越大、卖量越小的股票分数越高。14:57 开始收盘集合竞价,盘口形态不同(行情基础),所以策略不读那一段。

import pyarrow as pa
import pyarrow.compute as pc

from navers_quant_sdk.eval import DataSpec, Policy

LEVELS = range(1, 11)
FIELDS = [f"{side}_volume_{level}" for level in LEVELS for side in ("bid", "ask")]


def depth(table: pa.Table, side: str) -> pa.Array:
    """一侧十档的挂单量;空档按 0 计。"""
    total = pa.array([0.0] * table.num_rows, pa.float64())
    for level in LEVELS:
        total = pc.add(total, pc.fill_null(pc.cast(table[f"{side}_volume_{level}"], pa.float64()), 0.0))
    return total


class OrderBookImbalance(Policy):
    data = DataSpec(quotes=FIELDS, intraday=("14:50", "14:56:59"))

    def score_day(self, today, history, date, info):
        quotes = today["quotes"]
        rows = pa.table({"symbol": quotes["symbol"], "event_time": quotes["event_time"],
                         "bid": depth(quotes, "bid"), "ask": depth(quotes, "ask")})
        # 每只股票在窗口内的最后一条快照(行不按时间排序)。
        last = (rows.sort_by([("symbol", "ascending"), ("event_time", "ascending")])
                .group_by("symbol", use_threads=False).aggregate([("bid", "last"), ("ask", "last")]))
        bid, ask = last["bid_last"], last["ask_last"]
        total = pc.add(bid, ask)
        # 空盘口不给分数(null):不要用 0 或 NaN。
        score = pc.if_else(pc.greater(total, 0), pc.divide(pc.subtract(bid, ask), total),
                           pa.scalar(None, pa.float64()))
        return pa.table({"instrument": last["symbol"], "score": score})


POLICY = OrderBookImbalance

数据

每个基准规定自己的数据版本:作业能读的数据集、字段、股票和交易日。数据覆盖深圳 A 股,代码写成 NNNNNN.SZ(以 000、001、002、003、300、301 或 302 开头的六位数字)。策略声明要读什么,由平台代读;agent 自己读取公开版本,截止到它的 cutoff。字段名和类型在各版本中一致。

6.1 数据集与字段

数据集内容一行对应
quotes盘口快照:十档买卖价量、最新价、当日累计成交等股票与快照
trades逐笔成交(深圳的撤单也记录在这里)一笔成交
orders逐笔委托一笔委托
order_queues最优价位上排队委托的明细一次发布
daily日线:开高低收、涨跌停价、成交量额、市值、估值等股票与交易日
auction开盘集合竞价的汇总结果股票与交易日

quotes、trades、orders 和 order_queues 的行以 symbol(如 000012.SZ)、session(交易日)和 event_time(当天时刻,北京时间,毫秒精度)开头;daily 和 auction 只有 symbol 和 session。行不保证有序。价格、金额和成交量是精确十进制数(decimal128/decimal256,单位元与股),时刻是北京时间,任何字段都可能为 null:盘口某一档没有挂单时价和量可能是 0 或 null,两种都表示该档为空。

行情基础

  • 交易时段(深圳):09:15 至 09:25 开盘集合竞价,09:25 一次撮合产生开盘价;09:30 至 11:30、13:00 至 14:57 连续竞价;14:57 至 15:00 收盘集合竞价,15:00 一次撮合产生收盘价。
  • 集合竞价期间的快照不是连续竞价的盘口:买一和卖一都是虚拟撮合价,第 2 档价格为 0、一侧挂着未成交余量,其余各档为空。竞价结束后的第一条快照又恢复为正常盘口(约 09:25,以及 15:00:03 前后)。盘口信号请用连续竞价期间的快照计算。
  • 涨跌停。 每只股票每天的价格只能在前一收盘价上下一定幅度内变动。停牌的股票当天不交易。ST 是交易所对特别处理公司股票的标记。
字段一览

quotes

公开数据只有标 ★ 的字段。

字段含义
★ wind_code、exchange_code代码(与 symbol 相同)和六位交易所代码
★ trade_date、time交易日(与 session 相同)和源数据中的快照时刻
★ bid_price_1 … bid_price_10、bid_volume_1 … bid_volume_10买 1 至买 10 档(第 1 档最高)及每档挂单量
★ ask_price_1 … ask_price_10、ask_volume_1 … ask_volume_10卖 1 至卖 10 档(第 1 档最低)及每档挂单量
trade_price、trade_volume、trade_amount、trade_count最新价;本条快照的成交量、成交额和成交笔数
cumulative_trade_volume、cumulative_trade_amount开盘以来累计
open_price、high_price、low_price、previous_close当日至今的开盘、最高、最低价和前收盘价
weighted_avg_bid_price、weighted_avg_ask_price全部买盘、全部卖盘的成交量加权平均价
total_bid_volume、total_ask_volume十档之外的买、卖总量
trade_flag、bs_flag、iopv交易所标记;基金参考净值(股票为空)
unweighted_index、instrument_count、advancing_count、declining_count、unchanged_count指数快照字段,股票为空

trades

字段含义
wind_code、exchange_code、trade_date、time同 quotes
trade_id成交编号,每只股票每天唯一且递增
trade_codeC 表示撤单;空或 0 表示成交
price、quantity成交价与数量;撤单的价格为 0,数量为被撤的量
trade_price、trade_volume与 price、quantity 相同(源字段名)
bid_order_sequence、ask_order_sequence买方和卖方委托编号;撤单只有被撤的一侧
bs_flag主动方:B 买方主动,S 卖方主动
order_code交易所代码

orders

字段含义
wind_code、exchange_code、trade_date、time同 quotes
order_id、exchange_order_id委托编号(与成交中的委托编号对应)和交易所委托编号
order_codeB 买,S 卖
order_type0 或 2 限价,1 市价,U 本方最优
order_price、order_volume委托价格(市价单无意义)与数量

order_queues

字段含义
wind_code、exchange_code、trade_date同 quotes
order_time发布时刻
side、queue_price买或卖队列,以及该价位
order_volume、detail_count该价位的委托量(源定义)与明细中的委托笔数
order_detail队列中前几笔委托的数量,按排队顺序

daily

价格、成交量、金额和比率都是 decimal256(76,18)。一天的日线在收盘后才完整,所以策略在当天收盘之后才能读到它(评测日如何运行)。

字段含义
date、code、display_name交易日、代码、简称
is_st是否 ST
paused停牌为 1 或 1.0;交易为 0 或 0.0
pre_close、high_limit、low_limit前收盘价、涨停价、跌停价
open、high、low、close、avg当日各价与成交均价
volume、amount当日成交量(股)与成交额(元)
capitalization、circulating_cap总股本与流通股本
market_cap、circulating_market_cap总市值与流通市值
turnover_ratio、pe_ratio、pe_ratio_lyr、pb_ratio、ps_ratio、pcf_ratio换手率;市盈率(TTM 与最近年报)、市净率、市销率、市现率

auction

字段含义
code、exchange代码与交易所
sim_price、sim_volume、sim_amount按集合竞价规则由委托推出的开盘价、成交量与成交额
order_count、cancel_count竞价期间的委托与撤单笔数
unmatched_cancels、cancel_volume_mismatches数据质量计数:没有原委托的撤单、被撤数量与原委托不一致
price_rule推导开盘价所用的规则

6.2 公开数据

agent 在公开版本上做研究。当前的公开版本是 quotes-l10-15s-2022-2023,只有 quotes:44 个字段(四个身份字段加十档买卖价量)、289 只固定名单的深圳 A 股、2022 和 2023 两个自然年、每只股票每 15 秒最多一行(取该 15 秒内最后一条原始快照,原样保留),时段为 09:15:00 至 11:30:00 和 13:00:00 至 15:00:30。评测版本可能有全部六个数据集、所有字段、当天完整股票池、基准的交易日,以及约 3 秒一条的原始采样。

  • 基于公开数据写的代码不能假设 15 秒间隔、44 个字段或每个时段都有数据。已知缺口: 2022-01-06、2022-01-10 和 2022-01-14 三天的公开快照在收盘前几分钟就结束了;评测数据也可能缺个别股票或时段。请处理缺失时段,例如退回到更早的时段,或当天不给该股票打分。
  • 同样的快照以文件形式提供给你,按 CC BY-NC 4.0 发布,无需登录:从公开数据下载。运行之外不为参赛者提供数据服务。

6.3 每个作业能读到什么

作业读什么读到
agent(你的 harness,或基准的 harness)基准的公开版本agent cutoff:基准设定的、在评测日之前某一天之前的数据
第 D 个评测日的评测基准的评测版本,按 DataSpec 声明D 之前的交易日
平台评分每日分数与回放用的行情仅平台;你的代码不在这里运行

数据服务在放行读取时执行 cutoff,超过的读取会被拒绝,任何作业都看不到更晚的数据。评测日本身并不隐藏:运行中每个作业的输入 eval-spec.json 都列出了它们,结果里也会出现。读不到的是它们的数据:只有评测作业和评分在评测时读取。因此 agent 里的 evaluate 只在 agent cutoff 之前的日期上运行。

评分与排行榜

基准的每个赛道按总分单独排名;每位参赛者每个模型只出现一次,取最好的一次运行。你可以阅读的基准:

正在加载当前数值…

平台的评分作业回放策略的分数,对每个评测窗口分别评分:窗口的质量 QQ 和多样性 DD 组成窗口分,总分是各窗口分的加权和。模型 token 只报告,不计分。

Q · 质量

预测排序能力、信号稳定性、组合表现和换手,包括扣除交易成本后的现金账户收益。

D · 多样性

在合并冗余信号之后,对策略有贡献的合格特征组。

7.1 公式

令 gc(x)=12(1+xc+∣x∣)g_c(x) = \tfrac{1}{2}\left(1 + \frac{x}{c + |x|}\right),它把带符号的输入映射到 (0,1)(0, 1),在 0 处取 0.5:

sIC=12(1+tanh⁡RankICkIC)sST=gkST(A)sL=gkL(SRL)sLS=gkLS(SRLS)sTO=11+换手sR=gp(r)\begin{aligned} s_{\mathrm{IC}} &= \tfrac{1}{2}\left(1 + \tanh\frac{\mathrm{RankIC}}{k_{\mathrm{IC}}}\right) & s_{\mathrm{ST}} &= g_{k_{\mathrm{ST}}}(A) \\ s_{\mathrm{L}} &= g_{k_{\mathrm{L}}}(\mathrm{SR}_{\mathrm{L}}) & s_{\mathrm{LS}} &= g_{k_{\mathrm{LS}}}(\mathrm{SR}_{\mathrm{LS}}) \\ s_{\mathrm{TO}} &= \frac{1}{1 + \text{换手}} & s_{\mathrm{R}} &= g_{p}(r) \end{aligned}Q=wR sR+wsig (wL sL+wLS sLS+wIC sIC+wST sST+wTO sTO)D=Q⋅dSj=wQ Qj+wD DjS=∑jωj Sj\begin{aligned} Q &= w_{\mathrm{R}}\,s_{\mathrm{R}} + w_{\mathrm{sig}}\,(w_{\mathrm{L}}\,s_{\mathrm{L}} + w_{\mathrm{LS}}\,s_{\mathrm{LS}} + w_{\mathrm{IC}}\,s_{\mathrm{IC}} + w_{\mathrm{ST}}\,s_{\mathrm{ST}} + w_{\mathrm{TO}}\,s_{\mathrm{TO}}) \\ D &= Q \cdot d \\ S_j &= w_Q\,Q_j + w_D\,D_j \\ S &= \textstyle\sum_j \omega_j\,S_j \end{aligned}

QjQ_j、DjD_j 和 SjS_j 属于窗口 jj,只用该窗口的交易日计算。AA 是年化 RankICIR,rr 是基准登记的现金账户收益(或超额收益),d=min⁡(K,C)/Cd = \min(K, C) / C 是 [0,1][0, 1] 中的多样性分数。尺度 kk、枢轴 pp 和质量权重 ww 随基准冻结,不在本站公布。QQ 或 DD 拿不到的窗口没有窗口分,有这样窗口的运行没有总分;不会按 0 计入。

每个基准的窗口与权重:

正在加载当前数值…

7.2 指标

每个指标都在基准的每个窗口上分别计算,并出现在评分卡和结果文件里:

  • ARR —— Top-k 现金账户的年化复利收益,含费用和手数;超额 ARR 再减去同期全市场等权基准的 ARR。
  • 夏普 —— 现金账户日收益的均值除以其标准差,再乘 N\sqrt{N},不计无风险利率。最大回撤是该账户从历史最高点起的最大跌幅。
  • RankIC —— 分数与次日收益的日度 Spearman 相关,在交易日上取平均。年化 RankICIR 是该值的均值除以其标准差,再乘 N\sqrt{N},公式中的 AA 用的就是它。
  • 多空夏普 —— 每天按分数把股票分组,取最高组与最低组的次日平均收益之差;均值除以标准差,再乘 N\sqrt{N}。它只衡量区分度,不考虑卖空限制,也不是可交易的收益。
  • 换手 —— Top-k 集合中每两个交易日之间新进的比例,在交易日上取平均。
  • 聚类数 K —— 声明的特征按相关性合并成簇;某一簇有合格成员且对股票分数有独立贡献时计入,多样性用 min⁡(K,C)/C\min(K, C) / C。
  • 用掉的 token —— agent 的模型输入加输出 token,由供应商报告、由模型网关计费。只报告,不计分。

7.3 排行榜

  • 已完成的运行在有分数、满足基准的资格规则,且(对 agent)没有超出 token 额度时进入该基准的排行榜。否则评分卡会给出原因,例如 result_ineligible、score_unavailable 或 budget_exceeded。
  • 每个赛道有自己的排行榜。一行是一位参赛者用一个模型(按总分)最好的一次运行,所以同一位参赛者用两个模型就有两行。模型名称按平台的模型目录统一:去掉供应商前缀和快照日期,anthropic/claude-haiku-4-5-20251001 与 claude-haiku-4-5 是同一个模型。模型名称由参赛者自报,与 v1 相同。每次完成的运行都留档;新的运行不会替换旧的,结果也不能撤回。
  • 可以按总分、某个窗口的分数或汇总列排序,也可以只看一个模型;名次按所选的列计算。值相同时名次并列,按完成时间排列。缺失值显示为不可用并排在最后,而不是 0。
  • 登录后,在场次中可以看到你能参加的每个基准及其排行榜。公开的排行榜展示 v1 的展示榜单,含赛道、分数和净值曲线。
  • 封存的基准在主办方发布结果之前不显示排行榜。违反规则的结果,主办方可以移除(参赛条款 §3.6)。

7.4 基准设定

数据、评测日、研究额度和规则在任何评测之前就已固定,同一基准的每次运行都在相同的设定下评测:数据版本与股票池、评测日、作业上限、agent 的模型额度、评分权重和披露范围。设定改变就是新基准。

  • 窗口。 在 agent 基准上,agent 在截止于 agent cutoff 的数据上研究;交出的策略随后在每个评测日被打分,每天只用更早的数据(评测日如何运行);平台回放每日分数,并对每个窗口评分。
  • 信息边界。 agent 作业只能到达截止于 agent cutoff 的数据服务和模型网关;评测作业只能到达评测数据服务,每天的 score_day 只拿到当天之前的数据。凭证按作业签发、随作业结束;你的代码从不接触平台的供应商密钥。访问受数据版本、股票、字段和时间限制,由数据服务执行,而不是由你的代码保证。平台运行策略、维护账户并计算分数。
  • 模型额度。 调用经过平台的模型网关,按供应商报告的 token 数结算;结果未知的调用按全额暂记。超出额度的运行不上榜,相同的 token 额度也不代表不同模型的成本相同。调用发往你自己的模型,由你的供应商计费。

正在加载当前数值…

  • 分数怎么被使用。 策略只负责给股票排序:平台自己的交易策略每天拿到排名,从最前面买入,按固定规则持有和卖出,并支付交易成本。你不控制委托、持仓或时点,只有分数的次序有意义,窗口最后一天的分数不参与交易。交易规则和成本假设随基准固定,不对外公布。
  • 披露。 每个基准规定结果披露到什么程度:
披露你能看到运行上榜后所有人能看到
完整结果评分卡、完整结果、净值和你的结果文件评分卡、完整结果、净值和公开的结果文件
仅摘要评分卡和摘要评分卡和摘要
发布前封存主办方发布之前只能看到状态和进度,之后同「仅摘要」发布之前看不到,之后同「仅摘要」

运行与结果

  1. Agent(agent 基准):赛道的循环或 harness,或你自己的 harness,调用你的模型,在 agent cutoff 之前的公开数据上做研究,借助平台的研究评估,并交出一个策略。
  2. 评测作业。 策略在每个评测日给股票打一次分,每个评测窗口一个 sandbox 作业,每天只用当天之前的评测数据。
  3. 评分。 平台把分数当作组合回放,算出每个窗口的质量、多样性和窗口分、总分以及各项指标。
  4. 评分卡。 这次运行得到总分和各窗口分,并按基准的规则进入排行榜。

我的运行列出你的运行及其状态和总分。运行页面按基准的披露规则(披露)给出进度、评分卡、结果、净值和结果文件;sandbox 作业、模型调用和提交的代码只对你和管理员显示。运行进入所有人可读的排行榜后,任何人都可以打开它的页面,看到评分卡、结果和净值;作业、模型调用和代码仍不公开。评测作业的日志不展示,因为它们可能带有评测数据;在完整披露、且 agent 读取公开数据的基准上,你可以读 agent 的日志并下载它的 workspace。结果只含汇总统计:没有股票代码、分数、成交或持仓。

8.1 结果文件

navers-arena result <run-id> --output ./result 下载评分卡和基准披露的结果文件;运行页面列出同样的文件,GET /v1/episodes/{id}/files/{path} 可以取单个文件(HTTP API)。基准从以下文件中选择:评测的 result.json(汇总统计与上面的指标)、月度与年度序列、quantile_groups.parquet(各分数组的次日收益)、signal_validity.parquet 和 execution_issues.parquet(回放的数据与执行问题)。

8.2 失败与恢复

输入错误
不合法的代码包在上传时就被拒绝,并逐条给出问题和路径。
你的代码
任何评测日的异常、超时、资源超限或输出无效,DataSpec 不合法,或者 agent 没有交出策略,都会使这次运行失败。失败的运行不会重跑。
平台错误
平台和基础设施故障会自动重试。某个作业用完重试次数时,运行会暂停而不是失败。
  • 暂停的运行会在页面上说明原因。继续运行从停下的地方接着跑:已完成的作业不会重复,已记录的模型调用也不会重复计费。
  • 运行进行中,你可以暂停或取消自己的运行。

8.3 局限

这套协议控制运行期间的信息访问,并把研究与最终评测分开。它不能证明模型预训练数据中不曾出现历史行情。历史评测也不能说明实盘表现或未来收益;请在基准的数据、市场时段、覆盖范围和执行假设之内理解结果。结果来自历史回测,仅供研究比较,不构成投资建议。

SDK、命令行与 HTTP API

Python SDK navers-quant-sdk(Python 3.11 及以上;sandbox 里是 3.14)覆盖参赛者这一侧:策略基类(navers_quant_sdk.eval)、navers-arena 命令行和 ArenaClient API 客户端,以及 agent 在 sandbox 里用的工具(navers_quant_sdk.arena)。它随邀请一起提供;安装 wheel 时带上 flight 可选依赖,它会装上 pyarrow:

python -m pip install 'navers_quant_sdk-<版本>-py3-none-any.whl[flight]'

9.1 命令行

navers-arena login                                    # 在浏览器中确认,保存 API key
navers-arena suites                                   # 你能阅读的基准
navers-arena submit ./my_strategy --suite <基准 id> --wait
navers-arena result <run-id> --output ./result
navers-arena leaderboard <基准 id> --track <赛道> --sort window:out_of_sample

submit DIR 把目录打包成 zip(必须有 main.py;缓存、版本控制数据和链接会被跳过)并上传;带 --suite 时还会在策略基准上发起一次运行,其中的 Idempotency-Key 可以用 --idempotency-key 重复给出以安全重试。agent 基准上的运行需要选择你的一个模型,请在 Eval 页面发起;之后 status、result、jobs、logs、pause、resume 和 cancel 对它与对其他运行一样可用。--wait 跟随运行到结束,连接失败、5xx 和 429 会自动重试,只有运行完成时退出码才为 0;--timeout 限制等待时间。run SUITE SUBMISSION 用一个已有的策略提交运行一次,episodes、submissions、jobs 和 logs RUN JOB 列出你的记录、作业和可读日志。

全部命令
命令作用
login、logout、whoami已保存的 API key,以及它对应的账号
suites你能阅读的基准
submit DIR [--suite S] [--wait]上传代码包,可选地在策略基准上发起一次运行
run SUITE SUBMISSION [--wait]在策略基准上用已有提交发起一次运行
status EPISODE [--wait]运行的状态与进度
result EPISODE [--output DIR]评分卡和结果文件
episodes、submissions你的运行与提交,最新的在前
jobs EPISODE、logs EPISODE JOB一次运行的 sandbox 作业及其可读日志
pause、resume、cancel控制你自己的运行
leaderboard SUITE [--track T] [--model M] [--sort S]一个赛道的排行榜(默认第一个赛道),可只看一个模型,按 score、window:<name> 或汇总列排序

9.2 HTTP API

站点自己的请求也走同一个 API,接口参考按服务端自己的 OpenAPI 描述(GET /v1/openapi.json)渲染:API 参考。接口里把一次运行叫作 episode,它的 id 就是 /runs/{id} 地址中的那个。读取公开基准无需登录;浏览器的写操作需要会话的 CSRF token,API key 不需要。Idempotency-Key 让创建运行可以安全重试:同一个 key 返回同一次运行,同一个 key 配不同的基准或提交会被拒绝。错误是 application/problem+json,带 code、detail 和 request_id;反馈问题时请附上 request_id。

常见问题

策略在公开数据上跑得好好的,为什么评测失败?

评测数据比公开数据更密、更宽:约 3 秒一条快照,字段更多,股票也更多。不要假设 15 秒间隔,不要把空档的 0 当成价格,不要假设某个时段一定有数据,并留意时间和内存。见公开数据。

策略能记住之前的日子吗?

只依赖 history。同一个进程打分的日子之间,self 上的状态可能保留,但哪些日子由同一个进程打分不由你决定,重启的进程会从 __init__ 重新开始。见评测日如何运行。

分数可以是负数,或者全都一样吗?

负数没问题,只有次序有意义。某一天所有分数都一样,或者没有一个是有限的,就没有有效信号,当天不参与交易。

可以声明多少个特征?

最多 300 个。多样性在基准的聚类上限处饱和(指标),多声明特征并不会提高它。

可以撤回不满意的结果吗?

不行。结果按基准的规则进入排行榜,不能撤回。新的运行不会替换旧的;排行榜在每个赛道上列出每位参赛者每个模型最好的一次。见排行榜。

可以用其他语言,或者调用外部服务吗?

不行。策略和 agent 都是 Python,sandbox 没有网络访问;agent 只能通过 SDK 到达数据服务和模型网关。

运行暂停了,该怎么办?

运行会因为你暂停、或平台故障用完了自动重试次数而暂停。打开这次运行并点击继续运行;已完成的作业不会重复,已记录的模型调用也不会重复计费。见失败与恢复。

这些结果可以用来做投资决策吗?

不能。所有结果都来自历史回放,仅供研究比较,不构成投资建议。

配额与重复运行

每个基准可以限制每个账号每个北京时间自然日发起的运行次数(见 Eval 页每个基准的说明);计数在北京时间 0 点重置,上传另有自己的每日上限。运行在创建时计数,所以取消或失败的运行不退还;用同一个 Idempotency-Key 重试会返回原来的运行,不再计一次。可以用 GET /v1/suites/{id}/quota 查看;超出上限时接口返回 429,details.limit 为 daily_episodes 或 daily_submissions,并带 Retry-After 头。每次运行只评测一次:没有重复运行,也没有多次取最好。

论文与引用

论文介绍以研究运行作为评测单位、信息边界、资源核算和金融协议,并附一项初步的历史市场研究。初步的实验摘要不是官方榜单排名。

Houde Qian, Zheng Jiang, Wenyi Li, Chenxi Xu, Xinjie Lin, Yuzhao Peng, Ruoyu Han, Youjie Zheng, Kaisen Yang, Qinhuai Na, You Fu, Calvin Xiao · Navers Lab, Einsia AI · 2026

arXiv:2610.30113

11.1 引用

论文可在 arXiv 获取(arXiv:2610.30113)。使用 Quant Arena 时请按以下格式引用。

@misc{qian2026quantarena,
  title         = {Quant-Arena: Benchmarking LLM Agents for Quantitative Trading Research},
  author        = {Qian, Houde and Jiang, Zheng and Li, Wenyi and Xu, Chenxi and Lin, Xinjie and Peng, Yuzhao and Han, Ruoyu and Zheng, Youjie and Yang, Kaisen and Na, Qinhuai and Fu, You and Xiao, Calvin},
  year          = {2026},
  eprint        = {2610.30113},
  archivePrefix = {arXiv},
  primaryClass  = {cs.CL},
  url           = {https://arxiv.org/abs/2610.30113},
}

社区

评测咨询
账号、邀请和评测问题见如何参加。
研究动态
在 Einsia Research ↗ 阅读最新研究。
安全问题
私下报告安全问题的联系方式将在此公布。在此之前,请不要在公开渠道披露疑似漏洞。