去年 Alpha Arena 那阵子,几个 AI 模型下场交易,赚了亏了都能引来一轮讨论。做量化的看得尤其起劲,毕竟平时研究半天的东西,现在有人直接让模型拿着钱去试了。今年又来了个 Jev,最近看到一位大神把它接到 Monad 上的 Kuru 订单簿,按大约 300 毫秒一个区块的节奏做买卖决策,代码和前端都开源了。传播的那张图也挺有意思,一边说技术惊艳,一边写着“跑了 14 个小时,亏了 300% 多”。不过截图标着 dry run,是模拟运行,这个百分比也得核对计算口径,不能直接当成真实账户亏掉了三倍本金。
热闹看完,确实也有点手痒。去年 AI 交易刷屏,今年又出了专门做判断的模型,咱们做量化的,高低得接到自己的策略里试一下。于是有了这套跑在发明者量化上的币安 U 本位永续策略,现在已经在 ONE_USDT 上实盘运行。最近主要放在大家常说的妖币行情里观察,盘口和短线走势的特征更明显,也更容易看出策略哪里没配合好。下面就结合代码和实盘,聊聊这次怎么接、为什么改,以及跑起来以后看到了什么。
让它看盘口,先把交易分工理顺
Jev 的用法可以用一句话讲明白:给它当前状态,再给几个明确的问题,它返回选项、概率或者分数,程序拿到以后继续处理。对这次尝试来说,这个接口形态就够了。做短线的人对这些画面都不陌生:买盘看着挺厚,价格却一直上不去;上面的卖单不断被吃掉,但又有人补单;刚才还安静,突然连续几笔主动买入,价格跟着抬起来。单看其中一项,往往都能写成指标,难的是几种情况碰到一起该怎么判断。我想试的,就是把这些线索整理好,让 Jev 做几项具体判断。官方快速上手
喂给它的数据主要是买卖盘、最近成交、短时间内的价格变化和波动情况,数据缺失也会标出来,不能把“没拿到数据”写成“买卖刚好平衡”。账户仓位、下单数量和交易限制则留在本地处理。这样一笔没做成,至少能查清是模型没给出足够强的信号,还是费用、仓位、行情过期这些条件挡住了。执行上选择挂单,也就是 Maker,希望拿到好一点的成交价。但挂单的人都知道,看对了未必能成交,真成交了,又可能是行情已经往不利方向走了。后面几次修改,基本都围着这个问题展开。
最有用的一次修改,是把“买不买”拆开问
最初很容易图省事,把行情、费用、持仓都塞进去,最后问一句“现在买、卖,还是等”。答案能拿到,可它一直回答“等”,人就犯嘀咕:到底是觉得要跌,还是觉得涨幅不够手续费?是怕追高,还是顾虑手里的仓位?后来参考《Jev 怎么用:三种提问原语与分层阈值》,再对照官方文档,才把分工理顺。那篇里对策略最有帮助的,是把大问题拆成几项小判断,在代码里把答案组合起来。下面几段摘自策略的核心逻辑,为了方便阅读,省略了部分字段说明、日志和外围检查。官方设计模式
先问方向和空间,用 Choice。比如过 30 秒,价格更可能落在大幅下跌、小幅下跌、窄幅变化、小幅上涨、大幅上涨中的哪一档。这里的区间提前由程序划好,模型给每一档分配概率。为什么还要问幅度?我们都遇到过方向看对了、扣完费用却没剩多少钱的单子,只知道涨跌还不够。代码会同时问几个周期,主要交易周期是 30 秒,其余周期留下来对照。
javascript
forecastHorizons().forEach(function (h) {
questions["market_" + h] = {
type: "choice",
instructions: {
question: "从 state.timestamp 起 " + h / 1000 +
" 秒后,R = 10000*(未来中间价/state.mid - 1) 落在哪个区间?"
},
criteria: criteria // 预先定义好的五个涨跌区间
};
});
再问成交以后会不会吃亏,用 Score。挂买单经常遇到的情况是,刚才怎么也买不到,一买到就往下掉;挂卖单则反过来,刚卖出去,价格继续往上冲。所以我把买卖两侧分开评估,问挂单成交后,接下来几秒出现不利走势的风险有多强。档位也不能只写“低、中、高”,得把具体情形说清楚:主动成交和价格变化有没有一起指向不利方向,是只有一条线索,还是几条线索都在提醒我们小心。下面的 book 是该侧最优报价,adverse 在买侧表示下跌,在卖侧表示上涨。
javascript
questions["toxicity_" + side] = {
type: "score",
instructions: {
question: "在 " + book + " 并成交后,5 秒内价格" +
adverse + "超过 " + bounds.neutral + " bps 的严重程度?"
},
criteria: [
"微价格、主动成交与已实现价格路径都没有指向" + adverse,
"证据互相冲突,或成交笔数与深度不足以判断",
"微价格偏移指向" + adverse + ",且主动成交持续打向该侧",
"微价格、主动成交与已实现价格路径三者同时指向" + adverse
]
};
还得补上能不能成交这一问,用 Noul。它返回 0 到 1 之间的数,表示模型估计的成交可能性;接近 0.5,意味着对成交与否没有明显倾向。这个估计用来过滤那些看起来很难成交的开仓候选,也参与报价位置的选择。不过,模型并不知道我们的真实排队位置,盘口快照也还原不了完整的撤单和成交过程,所以这个数得和后面的挂单记录对照着看,不能拿到就当真。
javascript
questions["fill_" + side] = {
type: "noul",
instructions: {
question: "现在在 " + book + ",未来 " +
Math.round(CFG.signalTtlMs / 1000) + " 秒内是否会成交?"
},
criteria: { "true": "该挂单会被对手方吃掉", "false": "该挂单仍未成交" }
};
这三类问题放在同一次请求里,就比较像我们自己盯盘时会琢磨的事:方向和空间怎么样,挂上去能不能成交,成交以后会不会难受。回来以后,程序把这些答案用在不同地方:方向判断够不够开仓,成交机会是不是太低,风险偏高时能不能往更有利的位置挂。拆开之后,修改也有了抓手。觉得报价太激进,就查风险判断和挂单位置;一直没订单,就看哪一道条件没过。三种提问方式
妖币动起来,固定的那把尺子就不够用了
目前跑 ONE 这段行情,一个直观感受是短线特征更容易看见:买卖力量的变化、连续成交、拉升和回撤,能在比较短的时间里显出来。但行情动得大,也会把挂单和退出时的问题放大。最先需要调整的,就是判断幅度的那把尺子。同样一小段涨幅,在安静的行情里可能已经算明显上涨,放到正在猛拉猛砸的币上,可能只是普通抖动。所有品种都用固定边界,模型回答的虽然还是“大涨、小涨、横盘”,实际对应的行情却差得很远。
此前策略就出现过长时间观望的情况。检查以后发现,我们一边要求它预测很短时间里出现不小的涨幅,一边又要求它对此相当有把握。条件和当前波动不匹配,等半天没有交易也很正常。后来就把区间边界改成随近期波动调整,同时保留费用和缓冲的下限。下面这几行决定了“大幅变动”初始边界的来源,后面再做上下限约束。波动换算用的是近似,尤其在妖币跳涨跳跌的时候,不能把它理解成对未来幅度的精确预测。
javascript
VOL.sigmaHorizonBps = VOL.sigma1mBps *
Math.sqrt(CFG.signalHorizonMs / 60000);
var z = inverseNormal(1 - CFG.tailTargetRate);
var outer = Math.max(z * VOL.sigmaHorizonBps, minimumEdgeBps());
撤单重挂也是这个道理。价格动一点就撤,看起来反应很快,实际可能一直在重新排队。因此重报价距离也要结合波动和最小价格单位来算。参数就不逐个展开了,价格和数量精度、最小下单要求,尽量从交易所读取;能从行情估计的距离,让程序随行情调整。人主要决定交易什么、每次下多少、最多持有多少仓位。这样换品种时能少犯些手工设置的错,实际效果仍然要逐个品种看。
模型偏空,也不等于现在就该开空
参考文章里还有一点很适合交易:动作不同,门槛也应该不同。比如手里已经有多单,模型开始偏空,这点把握也许还不值得直接开空,却可能值得先减掉一部分多单。所以代码把开仓和减仓的方向概率门槛分开了,开新仓要求更强的判断,还要检查分布是否太分散、挂单成交机会是否太低;减仓使用较低的方向门槛。下面是挑选门槛的核心几行,行情有效性、信号时效和其他检查仍在外围执行。官方置信度文档
javascript
var required = plan.reducing ? CFG.reduceThreshold : CFG.openThreshold;
decision.requiredProbability = required;
if (tail < required) {
decision.reasonCode = "probability";
return decision; // 保留默认的观望动作
}
面板也按这个分工来排。“信号与决策”把方向概率、开仓和减仓门槛、两侧成交估计、逆向风险分数放到一起,最后一列写明本轮决策的原因。看这张表,就能沿着模型的答案查到本地执行条件,不用再猜它为什么一直等。下面的“各周期预测概率”则把几个时间尺度展开,方便比较模型在短周期和稍长周期上的判断。这里要分清,方向概率对应具体行情事件,confidence 反映答案分布有多集中,不能直接当成交易胜率;预测偏多或偏空,也要经过本地条件检查才能变成订单。

图 1:从实盘页面截取的信号板块。上半部分用于检查交易条件,下半部分用于比较不同周期的行情判断;数值会随运行更新。
跑起来以后,得能看清它在做什么
策略已经在实盘运行,面板主要用来帮我找问题。比如模型给出一个判断,等预测的时间到了,实际价格落在哪一档,这件事会记到“预测验证”里。它按周期列出样本数、五分类正确率,还摆了一条“始终猜窄幅”的简单基线作为对照。旁边的 Brier 分数用来检查整组概率预测的误差,非重叠样本则减少连续预测覆盖同一段行情的问题。这些指标各看一部分,不能只挑一个数字评价整个策略;把它们放在一起,才方便继续查哪个周期、哪类行情值得深入看。

图 2:预测验证板块,用同一套区间定义核对模型判断和实际走势,同时保留简单基线与非重叠样本,方便后续复盘。
挂单还得单独看成交质量,所以另外留了“成交后价格表现”。它记录发现成交后几个时间点的价格变化,买入后上涨、卖出后下跌算有利移动,反过来就是不利移动。如果经常刚成交就往反方向走,可以回头检查报价是不是太靠前,风险判断有没有起作用。这个板块从本地发现成交时开始计时,未扣费用,主要帮助观察挂单是否容易吃亏,不能直接当成每笔交易的净收益。

图 3:成交后价格表现板块,把成交后的短时走势单独留下来,便于对照前面的风险评分和报价选择。
查问题时,还会把“盘口与订单流”“数据与请求健康”以及订单记录对起来看。前者说明模型当时看到了什么,健康检查说明数据是否新鲜、请求有没有异常,持仓和委托记录则说明最后执行到了哪一步。有信号却没下单,先看决策原因和数据状态;订单挂上去一直没成交,再看报价和成交估计。这样读面板,每一块都能对应到前面的一段策略逻辑。
目前这套实现还有需要继续补的地方。持仓超时后会尝试挂只减仓单,但挂出去不代表能立即平掉,完整的硬止损、日亏损熔断和强平距离检查也还没补齐。继续跑这套策略,我更想弄清楚的是 Jev 在哪些盘口状态下能提供有用的判断,以及这些判断到了真实挂单环节还剩多少作用。把输入、判断、执行和验证都留下来,后面才有东西可复盘,也才知道下一次该改哪里。
- 1



