[原创] 套利新玩法:海力士套利狂热之后,还有机会藏在 EWY 里

海力士最近把"套利"两个字又炒热了。

随着股票永续合约上线,SK 海力士、三星电子这些原本只在 KRX 撮合的标的,多出了一条 USDT 本位、24 小时连续报价的敞口通道。公开资料显示,币安在 2026 年 6 月 2 日上线了 SKHYNIXUSDT、SAMSUNGUSDT 和 HYUNDAIUSDT;一份 7 月发布的行业报告提到,SK 海力士韩国现货收盘价与币安合约在部分时段的基差曾达到 3%—5%,不同加密平台之间的合约价差也一度超过 2%。价差摆在屏幕上,量化团队自然会闻风而来。但我把这条路走了一遍之后,最终交易的并不是它——而是一个更冷清、但三条腿都能在同一个账户里执行的组合:EWY、三星电子、SK 海力士

这篇文章讲清楚这套策略的原理:为什么放弃跨市场基差、这三个标的之间的关系凭什么可交易、回归式在做什么、残差为什么才是交易对象、仓位比例由什么决定、哪些数据必须拒绝交易,以及当前版本还差哪些东西才谈得上实盘。策略已在发明者量化平台以模拟盘运行,源码在文末。


一、被炒热的基差,和它背后的时间错配

首先要澄清一个常见的表述错误:股票永续合约的上线,并没有延长 SK 海力士现货的交易时间。

KRX 收盘后,底层股票停在最后一笔成交上,而以其为参考的永续合约仍在连续报价,继续吸收隔夜的宏观数据、费城半导体指数波动和汇率变化。参考资产冻结、衍生品继续定价——这种时段错配,才是近期基差的主要来源。

也正因为如此,闭市之后所谓的"公允价格"是不可观测的。永续合约的偏离可能来自两种完全相反的成因:

  • 它在提前交易隔夜信息 → 现货开盘会向它靠拢,此时做收敛是逆势接刀;
  • 它只是被稀薄流动性推离锚点 → 现货开盘会把它拉回,此时做收敛才成立。

在盘口上,这两种情况长得一模一样。 分不清就**,交易的就不是收敛,而是在替市场承接一次新的价格发现。


二、为什么我没有去做跨市场搬砖

即便撇开定价模糊的问题,把"韩股现货 ↔ 加密永续"这条腿真正搭起来,也要逐项穿过下面这些摩擦:

3% 的名义价差,未必有 3% 能落进口袋。而且最显眼的裂缝往往也是最拥挤的裂缝。

所以我换了个思路:保留"相对价值"的方法论,但把所有腿都放进同一个执行环境里。 这样做不能消除策略风险,但至少可以先消除掉账户、通道、时区和结算货币这几层工程摩擦,让研究聚焦在统计关系本身。


三、标的:EWY 和它的两块砝码

图 1:EWY 像一个装着多家韩国公司的资产篮子,三星和海力士是其中最重的两块砝码。回归试图用这两块砝码解释篮子的主要变化,橙色波动则代表暂时无法被解释的残差。

EWY 是跟踪韩国股票市场的 ETF。根据 iShares 2026 年 7 月 17 日披露的持仓:

两家合计接近 45%——足以解释 EWY 的大部分方向性波动,但远不足以完全决定它。剩下的部分,加上汇率、时段错位、资金流和各合约自身的基差,构成了可供交易的偏离

选这个组合的理由不是"三条曲线长得像",而是偏离有经济学上的归因:两只股票本来就是这只 ETF 的核心持仓,统计关系背后有持仓结构支撑,讨论"收敛"才有意义。如果只是从几千个合约里暴力筛相关系数,很容易找到一堆漂亮但没有经济含义的伪相关,市场状态一变,关系就消失了。

研究问题因此变得具体:

当 EWY 偏离由三星和海力士给出的"隐含价格"时,这段偏离是否具有回归倾向?

策略在同一账户内交易三个 USDT 本位线性合约:

var SYMBOLS = "EWY_USDT.swap,SAMSUNG_USDT.swap,SKHYNIX_USDT.swap";
var LABELS  = "EWY,三星电子,SK海力士";   // 第 1 个 = 目标腿,其余 = 对冲腿

必须说清楚:这不是无风险套利,而是押注统计关系延续的相对价值交易。


四、模型:用两块砝码去解释篮子

4.1 回归式,以及为什么取对数

ln(EWY) = c + β₁·ln(三星电子) + β₂·ln(SK海力士) + ε

用对数价格而不是原始价格,有两个实际理由:

第一,β 变成了弹性系数。 β₁ = 0.5 的含义是"三星涨 1%,EWY 涨 0.5%",与三者各自的绝对价位无关。这样得到的对冲比例可以直接换算成名义金额,而不需要再乘以价格比。

第二,残差 ε 变成了相对偏离。 ε = 0.008 意味着"EWY 比模型隐含值贵了约 0.8%",是一个百分比。如果用原始价格回归,残差是一个绝对金额差,价格水平一变它的量纲就变了,跨时间根本没法比较,标准化出来的 z 值也失去意义。

4.2 代码实现

策略的数学核心只有一个函数。它不仅返回 β₁β₂,还把窗口内每一根 K 线的残差完整保留下来——因为交易信号来自残差序列,而不是来自系数本身:

function regressSpread(lnTarget, lnRefs) {
    var k = lnRefs.length, n = lnTarget.length, dim = k + 1;
    var XtX = [], Xty = new Array(dim).fill(0);
    for (var i = 0; i < dim; i++) XtX.push(new Array(dim).fill(0));

    function col(j, t) { return j === 0 ? 1 : lnRefs[j - 1][t]; }

    // 累加正规方程 XᵀX 和 Xᵀy
    for (var t = 0; t < n; t++) {
        for (var i = 0; i < dim; i++) {
            Xty[i] += col(i, t) * lnTarget[t];
            for (var j = 0; j < dim; j++) XtX[i][j] += col(i, t) * col(j, t);
        }
    }
    var beta = solveLinearSystem(XtX, Xty);
    if (!beta) return null;

    // 逐根还原残差:实际值 − 模型隐含值
    var resid = [];
    for (var t = 0; t < n; t++) {
        var pred = beta[0];
        for (var j = 0; j < k; j++) pred += beta[j + 1] * lnRefs[j][t];
        resid.push(lnTarget[t] - pred);
    }
    return { c: beta[0], betas: beta.slice(1), resid: resid };
}

solveLinearSystem() 是带部分主元的高斯消元。当主元绝对值小于 1e-12(即两条对冲腿高度共线、正规方程近奇异)时直接返回 null,本轮信号作废——这一步不是数值洁癖:三星和海力士同属韩国半导体,共线性本来就高,一次病态求解足以把 β 推到荒谬的量级。

4.3 交易对象是 ε,不是价格

ε 是"EWY 的价格中,三星和海力士的同步变化解释不了的那部分"。它可能来自 ETF 内其余成分股(现代汽车、金融股),也可能来自汇率、时段错位、资金费率或流动性噪声。

这正是这套策略与方向性交易的分界线:我们不预测韩国股市涨跌,只押注"篮子与砝码之间的短期脱节会收敛"。三星和海力士的共同涨跌被对冲腿抵消掉了,剩下的敞口只有 ε。

策略取最近 480 根 15 分钟 K 线(约 5 个交易日)做滚动回归,把最新残差标准化:

z = (最新残差 − 窗口残差均值) / 窗口残差标准差

这里有一个必须承认的方法论缺陷:回归是在窗口内做全样本拟合的,最新残差本身也参与了这次拟合,因此它天然被"拉向"回归面,z 值被系统性压缩。同时窗口每根 K 线滚动一次,β 也随之变化,严格来说残差序列并不是同一模型下的可比序列。这不是致命问题(滚动 OLS 在配对交易中是常见做法),但它意味着 z 的绝对数值不能按标准正态去解读,阈值只能靠实证校准,不能拿"±2σ 对应 95%"这类课本结论直接套用。


五、信号:三态状态机

图 2:残差进入上下极端区域时建立价差仓位,回到均值附近时退出。图中的回归箭头表达的是交易假设,不代表残差必然收敛。

信号是一个很小的状态机:空仓时只有越过进场阈值才开仓;持仓后不会因为 z 仍在同一侧而反复加仓,只等它回到离场带内,或者触发最大持仓时长。

var state = _G('bh_state') || 'FLAT';
var holdHours = state !== 'FLAT' ? (now - entryTime) / 3600000 : 0;
var forceExit = state !== 'FLAT' && MAX_HOLD_HOURS > 0 && holdHours > MAX_HOLD_HOURS;

var newState = state;
if (state === 'FLAT') {
    if (zLatest > ENTRY_Z)       newState = 'SHORT_SPREAD';  // EWY 偏贵 → 空 EWY、多两条对冲腿
    else if (zLatest < -ENTRY_Z) newState = 'LONG_SPREAD';   // EWY 偏便宜 → 多 EWY、空两条对冲腿
} else {
    if (forceExit) { newState = 'FLAT'; Log('⏰ 超过最大持仓时长,强制离场'); }
    else if (Math.abs(zLatest) < EXIT_Z) { newState = 'FLAT'; Log(' z 回归至离场带内,平仓'); }
}

进场与离场阈值不对称(1.0 / 0.5)是有意的:如果两者相等,z 在阈值附近抖动就会反复开平,手续费吃掉全部利润。0.5 的缓冲带保证了每次交易至少要走完半个标准差的回归幅度才落袋。

这个状态机有两个需要明说的设计取舍:

  1. 没有基于 z 的止损。 持仓期间若 z 继续朝不利方向扩大(持 SHORT_SPREAD 时 z 从 1.2 涨到 3),代码既不加仓也不止损,只等 |z| < 0.5 或 48 小时超时。这是均值回归策略的经典形态,也是它经典的死法——关系一旦真的破裂,亏损没有上界。
  2. 不反手。 持 SHORT_SPREAD 期间若 z 直接穿越到 −1.5,else 分支只检查 |z| < 0.5 和超时,两者都不满足,仓位会原地保持到 48 小时到期。这是明确的行为边界,不是 bug,但实盘前应重新评估。

MAX_HOLD_HOURS = 48 的作用正是防止把一次短线错位熬成长期信仰——它是这个版本里唯一对"关系已经失效"这种情形的硬性认输机制。


六、仓位:β 决定配比

三腿策略最容易写错的地方,是方向看对了,配比配错了

6.1 对冲比例的来源

假设信号判定 EWY 偏贵,我们做空 1 单位 EWY 的名义金额。此时组合暴露在什么风险下?根据回归式,EWY 的变化中有 β₁ 份来自三星、β₂ 份来自海力士。要把这两个共同因子抵消掉,就必须同时买入 β₁ 单位的三星和 β₂ 单位的海力士

代码里就是这一行:

var wr = -reg.betas[j] * wTarget;   // 对冲腿方向与规模,由 β 反向决定

三条腿的名义金额之比因此是 1 : β₁ : β₂,再统一归一化到总敞口预算:

var dir = state === 'SHORT_SPREAD' ? -1 : 1;
var wTarget = dir * 1.0;
var wRefs = [], gross = Math.abs(wTarget);
for (var j = 0; j < reg.betas.length; j++) {
    var wr = -reg.betas[j] * wTarget;
    wRefs.push(wr); gross += Math.abs(wr);
}
var scale = gross > 0 ? (GROSS_EXPOSURE / gross) : 0;   // Σ|w| 归一化到 0.7
weights[0] = wTarget * scale;
for (var j = 0; j < wRefs.length; j++) weights[j + 1] = wRefs[j] * scale;

最后按 名义金额 = 权重 × LEVERAGE × 权益 换算成下单量,杠杆取 3 倍。

这一步的目的不是让组合永不亏损,而是让它只对 ε 敏感。 韩国股市整体涨跌、半导体板块共振、美元韩元波动——这些同时作用于三条腿的因子,理论上都被 β 配比抵消掉了。剩下的,才是我们想赚的那块相对价值。

6.2 什么时候才真的下单

每轮循环都会重算 β 和权重,但不是每轮都调仓。只有两种情况触发:

// ① 任一腿方向翻转
if ((sig.weights[i] >= 0) !== (lastWeights[i] >= 0) && (sig.weights[i] !== 0 || lastWeights[i] !== 0)) {
    needRebal = true; break;
}
// ② 任一腿权重绝对值漂移超过 20%
var lw = Math.abs(lastWeights[i]);
if (lw > 1e-9 && Math.abs(Math.abs(sig.weights[i]) - lw) / lw > DRIFT_THRESHOLD) {
    needRebal = true; break;
}

β 漂移正是通过 ② 被捕捉的:β 变了 → 权重变了 → 超过 20% 阈值 → 重新对冲。这层节流的意义是承认"β 的小幅抖动是估计噪声,不是信息"——如果每次微小变化都去调仓,手续费会先于残差收敛把账户耗光。

MIN_REBAL_USDT = 3 则承担了双重角色:既是"偏差太小就不动"的阈值,也是离场时的平仓开关——状态转 FLAT 后三腿权重归零,目标名义低于 3 USDT,调仓逻辑据此执行全平。


七、数据卫生:拒绝交易的门槛

新上线的 TradFi 合约历史短、休市时段价格可能冻结,对冲腿之间又高度共线。一个异常价格就足以把 β 和 z 推到荒谬的水平,然后让系统以为发现了百年一遇的机会。

所以在信号成形之前,代码设了几道硬门槛。它们不负责创造收益,只负责在数据明显不可信时拒绝交易

// ① 价格冻结检测:对冲腿在整个窗口内几乎无变化(休市 / 标记价格不动)
//    这会让回归极不稳定,把残差标准差压到接近 0,z 就可能被除出天文数字
if (refMax - refMin < MIN_REF_LOGRANGE) {          // 1e-6
    Log(' ' + LABELS[j + 1] + ' 窗口内价格几乎无变化(可能休市/冻结),本轮跳过');
    return null;
}

// ② 共线检测:正规方程近奇异,高斯消元返回 null
var reg = regressSpread(lnTarget, lnRefs);
if (!reg) { Log(' 回归矩阵奇异,本轮跳过'); return null; }

// ③ 残差标准差下限:过小意味着回归不可靠,z 的分母会把噪声放大成信号
var sd = stdev(reg.resid);
if (!(sd > MIN_RESID_STD)) { return null; }        // 5e-4

// ④ z 值合理性上限:极端值更可能来自坏数据而非真实机会
if (!isFinite(zLatest) || Math.abs(zLatest) > Z_SANITY_CAP) {   // 15
    Log(' z 值异常(' + zLatest + '),视为计算故障,本轮忽略信号');
    return null;
}

第 ① 道和第 ③ 道是同一个风险的两端:韩股休市时,参考合约的价格可能长时间不动,窗口内残差标准差被压到接近零。此时 z 的分母趋近 0,任何微小的分子都会被放大成天文数字——一个看起来"千载难逢"的 z = 40,实际上只是除以了一个不该出现的小数。这类信号如果不拦,第一次触发就足以打光账户。

配套的还有整条数据链的对齐:alignData() 取三条 K 线时间戳的交集,只保留三个标的都有收盘价的时刻,并要求至少 490 根共同 K 线才允许计算。任一腿出现 0、负数或非数字价格,本轮同样作废。

所有中间量都带 [DEBUG] 前缀打日志——最新收盘价、各腿窗口内 ln 价格极差、回归系数、残差均值与标准差、原始 z 值。z 一旦异常,日志能直接定位是哪一环出的问题,不需要靠猜。


八、风险边界

除了 z 离场和 48 小时超时,代码里唯一的主动风控是逐腿异常波动减仓:某条已持仓腿在两次检查之间出现超过 6% 的不利变动,就单独砍掉一半仓位。

var drop = pos.side === 'long' ? (last - cur) / last : (cur - last) / last;
if (drop >= EMERGENCY_DROP) {                    // 0.06
    Log('紧急风险! [' + label + '][' + pos.side + '] 不利变动:', _N(drop * 100, 2) + '%');
    // ... 减仓 50%
}

关于它的边界,有三点必须说清楚:

① 它按单腿判断,不看组合。 对冲组合里某条腿单独跌 6% 完全可能是正常的——另一条腿同时在涨,组合净敞口根本没变。这道熔断会在这种情况下误伤对冲结构,砍掉一半对冲腿之后,剩下的敞口反而不再是残差,而是裸的方向性风险。这是当前版本最需要改的一处。

② 参考价的更新是有条件的。 bh_lastCheckPrices 只在本轮没有任何腿触发时才整体更新。一旦触发,参考价保持不变,下一轮仍以旧价比较——单边行情里可能连续触发、连续减半。这是刻意的保守设计,但会让减仓比预期更激进。

③ 它是事后防线。 三条腿不可能在同一微秒、同一理想价格成交。第一条腿成交后,另外两条腿还暴露在市场里——这就是单腿风险。行情越快,原本想赚的那点残差越可能被执行误差吞掉。逐腿熔断是在损失已经发生后削减敞口,它无法替代一套真正的三腿成交协调机制。


九、参数总表

源码中 POLL_MS 的注释写的是"5 分钟",实际值是 1 * 60 * 1000(1 分钟)。1 分钟的轮询配合 15 分钟 K 线,意味着同一根未收盘 K 线会被反复计算,DRIFT_THRESHOLD 因此承担了比设计预期更重的节流职责。实盘前应当统一。


十、两天模拟盘,以及它不能证明什么

原型在发明者量化的模拟盘运行,初始资金 400 USDT。两天测试下来,账户取得了一定的正收益。

这是一个让人愿意继续研究的结果,但远不能作为盈利能力的证明

  • 样本长度不够。 两天可能只覆盖了一种市场状态,甚至只是碰巧遇上一次顺利收敛。以 48 小时的最大持仓时限计算,这个样本里完整的交易周期屈指可数。
  • 模拟成交比真实市场友好。 按最新价即时全额成交,不计手续费、不计滑点、不模拟排队与部分成交。三腿策略对这几项恰恰最敏感。
  • 资金费率完全没有建模。 三条腿的资金费率不会一致,多空组合会产生额外的 carry 损益,不会自动抵消。持仓时间越长,这项偏差越大。
  • 单腿风险没有被计入。 模拟盘里三腿是"同时"成交的,真实执行中不存在这回事。

正收益在这个阶段的正确读法是:流程跑通了,没有触发异常熔断,z 和 β 处于合理范围。 仅此而已。


十一、当前版本未实现的部分

把"公式能跑"和"资金可托付"分开的,就是下面这份清单。这些都不在当前代码里,实盘前需要逐项补齐:

统计有效性

  1. 协整检验缺失。 代码做了滚动 OLS,但"做了回归"不等于"存在协整"。需要补 ADF 或 Engle–Granger 检验确认残差平稳,否则所谓均值回归可能只是短样本里的视觉错觉。
  2. 半衰期未估计。 没有对残差拟合 OU 过程估计回归半衰期,MAX_HOLD_HOURS = 48 目前是拍脑袋定的,本应由半衰期反推。
  3. 无样本外验证。 没有滚动前推(walk-forward)检验,也没有分市场状态的参数稳定性分析。ENTRY_Z = 1.0 和 LOOKBACK = 480 都还没经过样本外校准。

成本与执行

  1. 手续费与滑点未建模,需要重新评估残差的平均收敛幅度是否还有安全垫。
  2. 资金费率 carry 未建模,需要单独跟踪三条合约的费率,判断组合是否长期偏向某一边。
  3. 三腿成交协调机制缺失——分腿成交、拒单、延迟、部分成交时如何在限定时间内补齐或撤回整个组合。
  4. 下单精度未对齐,没有按合约的 stepSize 与最小名义值取整。
  5. 无交易日历,未识别 KRX 休市、财报窗口、指数调仓等 β 可能突变的时点。

十二、这套思路可以往哪里外推

同样的框架并不局限于韩国市场:

  • 指数 vs 高权重行业篮子:标普 500 与其中若干高权重行业 ETF 的短期偏离;
  • 龙头内部轮动:"七姐妹"里 leader 与 follower 的相对错位;
  • 行业 ETF vs 核心成分股:用几只核心持仓构造 ETF 的隐含价值。

模型也不必固定三条腿,标的池可以扩展成"一个目标 + 多个解释因子"。但组合越大不代表越高级:每增加一条腿,就多一份盘口、成交、资金费率和故障风险,而每条腿的执行误差都会直接侵蚀你想赚的那点残差。

一个真正可交易的组合应当同时满足三件事:

  1. 经济关系说得通——偏离有归因,不是伪相关;
  2. 统计关系经得住样本外检验——不是短样本里的巧合;
  3. 执行成本没有吃掉预期收益——净的,不是毛的。

少一项,都只能算研究素材,不能算可交易机会。


结语

海力士的基差提醒了市场:新的交易载体会制造新的价格裂缝。但套利机会从来不只存在于最热闹的那一道裂缝里。指数与成分股、ETF 与龙头篮子、同一主题里的 leader 与 follower,都可能短暂失去同步。

公式负责描述偏离,工具负责发现和执行,风控负责让我们有机会等到下一次偏离。至于眼前这点模拟盘收益,最合适的态度不是庆祝,而是把它当成下一步优化清单的起点。

 

 

 

 

 

免责声明:信息仅供参考,不构成投资及交易建议。投资者据此操作,风险自担。
如果觉得文章对你有用,请随意赞赏收藏
相关推荐
相关下载
登录后评论
Copyright © 2019 宽客在线