jev-trader 能实盘交易吗?
它包含真实下单路径,也提供模拟模式;能下单不等于策略经过验证,更不等于可以盈利。
jev-trader 是把有界模型判断接入 Monad/Kuru 订单簿的实验:Jev 选择方向,普通代码决定能否下单、价格、数量与回执处理。它适合学习事件驱动的判断层,不足以证明预测优势或交易收益。
本文核对固定提交,并在替换网络、市场和文件系统后测试其中的局部行为。没有安装运行完整上游应用,没有请求真实 Jev、连接钱包、广播交易或测量盈利;不把这些局部测试升级为完整项目复现。
一次区块如何变成订单
- 接收区块
onBlock 先启动旧订单回执查询。若上一轮仍忙,本轮只记 late/hold,不再开启第二个模型请求。
- 准备证据
读取订单簿、保存中间价、构造 TradeState;成交日志在热路径外更新。
- 只问方向
一个 Choice 在 buy/sell 中选方向。Jev 不生成订单代码,不计算报价。
- 代码再裁决
allowed 检查持仓、已挂订单与在途订单;实盘模式再检查保证金。选中方向不允许时,尝试另一方向;两边都不允许则没有新报价。
- 提交不等于成交
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 超时或失效关闭保障。
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。模拟成交也只是用成交打印是否穿越报价来推断,没有证明真实排队优先级或成交机会。因此费用、成交假设与模型贡献要分开核算,不能凭截图判断获利。
只运行模拟模式
需要 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 教程里的变量名)。这会产生真实模型请求与可能的费用;本站未执行,也不在本文提供实盘启动步骤。
本站验证了什么
本站保留了 MIT 许可和固定提交的 config.ts、model.ts、trader.ts。测试转译原始 TypeScript,在隔离执行环境替换市场、模型传输、文件写入和 Bun 等待;不是重新手写一套“看起来相同”的算法。
- mock 与 dry-run 独立;提供私钥会改变默认模拟状态。
- 缺失概率时补成 one-hot;请求只有 buy/sell。
- MockModel 主动请求 80ms 等待。
- 仓位覆盖方向后,原始概率保留。
- busy 时发出 hold,但旧请求恢复后仍可继续。
- 模型抛错不发新订单,busy 会释放。
- 显示的 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 这七项离线行为测试通过,不代表订单编码、链上成交、真实接口兼容性或策略安全已通过验证。证据等级仍为源码核验,不升级为完整实测。
如何设计进一步验证
如果要判断 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 延迟口径