代码仓库分析

jev-trader

拆解 jev-trader 的 Jev 请求与订单循环,核对提示词和订单类型差异、概率补值、仓位覆盖与 P&L;附七项离线行为测试和模拟运行步骤。

E2 · 资料已核对已检查公开资料或源码证据;仅有固定提交链接并经对应源码核对,才可称固定版本核验。不代表本站运行过、认可性能或保证安全。

本站核对范围:固定版本源码阅读 · 离线契约检查;具体限制见下文。

Stars
2,240
Forks
420
协议
MIT
最近提交
2026-09-17

源码核对与离线测试 · · commit b587759

jev-trader 能实盘交易吗?

它包含真实下单路径,也提供模拟模式;能下单不等于策略经过验证,更不等于可以盈利。

jev-trader 是把有界模型判断接入 Monad/Kuru 订单簿的实验:Jev 选择方向,普通代码决定能否下单、价格、数量与回执处理。它适合学习事件驱动的判断层,不足以证明预测优势或交易收益。

本文核对固定提交,并在替换网络、市场和文件系统后测试其中的局部行为。没有安装运行完整上游应用,没有请求真实 Jev、连接钱包、广播交易或测量盈利;不把这些局部测试升级为完整项目复现。

一次区块如何变成订单

  1. 接收区块

    onBlock 先启动旧订单回执查询。若上一轮仍忙,本轮只记 late/hold,不再开启第二个模型请求。

  2. 准备证据

    读取订单簿、保存中间价、构造 TradeState;成交日志在热路径外更新。

  3. 只问方向

    一个 Choice 在 buy/sell 中选方向。Jev 不生成订单代码,不计算报价。

  4. 代码再裁决

    allowed 检查持仓、已挂订单与在途订单;实盘模式再检查保证金。选中方向不允许时,尝试另一方向;两边都不允许则没有新报价。

  5. 提交不等于成交

    market 在一个 batchUpdate 中撤旧单、挂新 post-only 限价单。sent 是提交意图,placed 是回执状态,实际成交来自 Trade 日志;dry-run 则按后续成交穿越报价来模拟。

trader.ts: onBlock / allowed / harvest · market.ts: send / encode / pollPending

Jev 究竟看什么、回答什么

下面是按 TradeState 接口人工构造的教学输入,不是链上采样、API 请求日志或推荐交易参数。目标是读懂每组字段的职责。

{
  "market": "MON-USDC",
  "block": 100,
  "horizonBlocks": 100,
  "blockMs": 300,
  "mid": 1.01,
  "spreadBps": 198.02,
  "bookImbalance": 0,
  "depth": {
    "10bps": {
      "bid": 0,
      "ask": 0
    }
  },
  "book": {
    "bids": [
      "1.000000 x 200"
    ],
    "asks": [
      "1.020000 x 200"
    ]
  },
  "returnsBps": {
    "last1": 0,
    "last5": 0,
    "last20": 0,
    "last100": 0
  },
  "recentMids": "1.010000",
  "trades": {
    "count": 0,
    "buyMon": 0,
    "sellMon": 0,
    "cvdMon": 0,
    "vwap": null,
    "lastPrice": null,
    "lastSide": null
  },
  "recentTrades": [],
  "allowed": {
    "buy": true,
    "sell": true
  }
}
mid / spreadBps
中间价与买卖价差;由代码计算,模型不负责算术。
book / depth / bookImbalance
前五档报价、多个距离内的深度与近端买卖不平衡。
returnsBps / recentMids
不同回看长度的价格变化与抽样价格路径;不是外部新闻。
trades / recentTrades
成交量、主动买卖净流量和最近成交;后台异步更新,不能假定与订单簿原子同步。
horizonBlocks / allowed
预测窗口和代码计算的方向约束。默认窗口为 100 个区块;upIn10 字段名不代表真的预测 10 个区块。

JevModel 通过 @ai-sdk/typesafe-ai 的 evaluationModel 调用 experimental_evaluate,请求名为 direction 的 Choice,maxRetries=0。问题要求比较预测窗口结束后的价格与当前中间价;criteria 只有 buy、sell,没有“拿不准”。它不是输出 buy/sell/hold 的三分类模型。

读取结果时须区分 a.choice、a.probabilities 和执行层改写后的 decision.action。upIn10 只是 buy 概率的别名,不是额外的 Noul,也不是收益置信度。 model.ts ↗

源码中的六个关键发现

1. 提示词与实际订单类型不一致

固定版本的问题描述假定跨价差、下一块执行 IOC 市价单;market.encode 实际把 postOnly 设为 true,并由 quotePrice 尽量避免穿越对手价。前者与等待别人来成交的挂单有不同假设。差异可由源码确认,但对策略结果的影响尚未测量。修改自己的分支时,应先统一问题与执行契约,再做对照,而不是只调概率阈值。

model.ts: QUESTIONS · market.ts: quotePrice / encode

2. 概率为 1 可能是缺失值兜底

如果提供方没有返回 probabilities,代码会把胜出方向补成 1、其他方向补成 0。离线测试复现了这一分支;这不是模型给出的校准概率。下游应保留“模型原值 / 程序补值”的来源标记,缺失时转未知,而不是展示为 100% 确定。这里是改进建议,不是上游已实现的行为。

3. 最终方向与展示概率可能指向不同决策

当 buy 被仓位约束拒绝而 sell 可用时,代码把 action 改成 sell、设置 capped=true,却保留原来的买卖概率。测试中买入概率 0.8 与最终卖出同时存在。这说明执行策略覆盖了模型,而不是模型自相矛盾;日志分析必须同时查看 capped、quote.side 和原始概率。

model.ts: decide · trader.ts: onBlock

4. late/hold 不是总超时,也不是撤单保护

busy 分支只跳过新来的区块,不取消仍在运行的旧请求。测试先挂起模型请求,再送入新区块:会出现 hold;旧请求返回后仍继续提交。这个局部循环没有显式的“结果已过期就丢弃”判断。提供方报错时 catch 仅记录错误、finally 释放 busy,也没有在这里撤销所有旧挂单。不能把“每块一次”理解为严格的 300ms 超时或失效关闭保障。

trader.ts: onBlock / emit

5. mock 的延迟不能代表 Jev 延迟

MockModel 使用价格变化、订单簿不平衡、成交流和确定性噪声计算方向,并显式 Bun.sleep(80)。测试确认了等待参数,没有测真实延迟。README 的相关 dry-run/mock 时间也不能当作本站 Jev 性能基准。严谨比较应分别报告 mock、真实模型请求和完整循环的耗时、样本数与失败率。

model.ts: MockModel · README: latency context

6. 界面的 P&L 不是全成本净收益

emit 中 pnlUsd 为已实现收益加未实现收益再减 gasUsd;单独累计的 jevUsd 没有在这条公式里扣除。测试构造已实现 10、gas 2、模型费用 3,输出 pnlUsd=8 而不是 5。模拟成交也只是用成交打印是否穿越报价来推断,没有证明真实排队优先级或成交机会。因此费用、成交假设与模型贡献要分开核算,不能凭截图判断获利。

trader.ts: simFills / emit

只运行模拟模式

需要 Git、Bun 与可访问的 Monad RPC。以下步骤依据固定源码整理,本站未执行完整联网启动。使用独立、没有钱包密钥的测试环境;服务具有开放 CORS,不应直接暴露到公网。先检查依赖和脚本,再安装。

git clone https://github.com/jarrodwatts/jev-trader.git
cd jev-trader
git checkout --detach b587759e459ea049590102e54a0b07800864cdc3
bun --version
bun install --frozen-lockfile
# No wallet, no model key, no live orders. RPC reads still use the network.
DRY_RUN=true MODEL=mock PRIVATE_KEY= TYPESAFE_AI_API_KEY= PORT=3000 bun run start

在另一个终端检查状态。/ 返回 JSON 快照,不是网页交易面板。启动未完成时 latest 可能为 null;有区块后才检查 quote 和 decision。

curl --fail http://127.0.0.1:3000/
curl --fail http://127.0.0.1:3000/history
curl --max-time 5 -N http://127.0.0.1:3000/events
  • 必须看到 model="mock"、dryRun=true、wallet=null;不一致就停止,不填写真实私钥。
  • 报价存在时应为 status="sim";无新报价可能是双向约束,late=true 则查看上一轮是否仍在运行。
  • SSE 的 curl 五秒后超时退出是这里主动设置的停止条件,不等于服务器故障。Ctrl+C 停止本地进程。

真实 Jev 的 dry-run 是另一阶段:仍保持 DRY_RUN=true 和 PRIVATE_KEY 为空,才将 MODEL 改为 jev,并按该仓库的 .env.example 配置 TYPESAFE_AI_API_KEY(注意多了 AI,不是官方 SDK 教程里的变量名)。这会产生真实模型请求与可能的费用;本站未执行,也不在本文提供实盘启动步骤。

.env.example · config.ts · server.ts · package.json

本站验证了什么

本站保留了 MIT 许可和固定提交的 config.ts、model.ts、trader.ts。测试转译原始 TypeScript,在隔离执行环境替换市场、模型传输、文件写入和 Bun 等待;不是重新手写一套“看起来相同”的算法。

  1. mock 与 dry-run 独立;提供私钥会改变默认模拟状态。
  2. 缺失概率时补成 one-hot;请求只有 buy/sell。
  3. MockModel 主动请求 80ms 等待。
  4. 仓位覆盖方向后,原始概率保留。
  5. busy 时发出 hold,但旧请求恢复后仍可继续。
  6. 模型抛错不发新订单,busy 会释放。
  7. 显示的 P&L 未扣除单独统计的模型费用。
# In the Jev Tutorial repository, not the upstream trader repository:
npm ci --prefix examples --ignore-scripts
cd examples
node --test jev-trader-contract.test.mjs

这七项离线行为测试通过,不代表订单编码、链上成交、真实接口兼容性或策略安全已通过验证。证据等级仍为源码核验,不升级为完整实测。

本站测试源码 ↗ · MIT · Jarrod Watts

如何设计进一步验证

如果要判断 Jev 是否带来增量,不能只运行一次后看收益截图。先修正问题与执行假设,再在相同记录上比较 mock、简单确定性基线与 Jev;按时间划分开发区间和未参与调整的验证区间。下面是建议协议,并非本站已完成的结果。

  • 决策层:保存原始选项、概率是否来自提供方、模型 ID、预测窗口与独立标签;按同一个定义评价方向判断。
  • 执行层:分别记录模型方向与最终方向、覆盖原因、sent/placed/reverted/lost、成交比例与挂单撤销。
  • 可靠性:报告模型请求与完整循环的 p50/p95、late 比例、异常数和过期结果,不能把 mock 人工等待计入 Jev 性能。
  • 费用与损益:把模型账单、gas、其他适用费用、库存浮动和成交模拟假设逐项披露;不把尚未扣齐成本的 pnlUsd 叫净收益。

可迁移的工程经验是:保留判断与执行的边界,并记录策略什么时候覆盖模型。值得借鉴的是可审计的分工,不是“加上 Jev 就能交易获利”。

继续:有界重试、过期结果与失败回退 · 继续:如何校准概率门槛

源码阅读地图

以下均固定到同一提交;对新版本应重新核对,不能假定这里的发现仍然成立。Stars、Forks 等来自目录快照,不是本次测试产出。

src/config.ts ↗
默认值、dryRun 条件、仓位与窗口配置
src/model.ts ↗
Choice 问题、概率兜底、mock 的 80ms 等待
src/trader.ts ↗
busy 分支、方向覆盖、模拟成交与 P&L
src/market.ts ↗
报价、post-only 编码、回执与启动资金操作
src/server.ts ↗
快照、历史与 SSE 输出格式
README.md ↗
作者运行说明与 mock 延迟口径