源文件:research/quant_digests/2026-04-16_0018_positive-streak-netcarry-shell.md
short 高 funding leg + long 低 funding leg 的 delta-neutral 对冲配对,赚 funding spread,而不是赌方向。这次主看的是 kohtabeloff/funding-arb-bot(2026)。表面上它像个 Telegram 交易机器人:连 5 家交易所、给你发信号、还能手动点按钮开平仓。
但如果只把它读成“执行面板”,就会错过它真正对我们 desk 更有价值的部分:它把一条早就知道存在的 cross-venue funding carry,往“什么样的 spread 值得上、上了以后什么时候该滚、什么时候该硬关”推进了一步。
它最值得 intake 的,不是“跨所 funding 有差异”这个老结论,而是 repo 给了一套更像能直接上线的 admission + protection 壳:
MIN_PAIR_APR >= 50% 的 pair;pair_streak);4h 宽限;-50%,或者任一腿离强平太近,就自动平仓;翻成人话: 这份 repo 真正可带走的,不是“哪里 funding 高”这种排行榜,而是“同一条 cross-venue carry alpha,怎样用持续性准入 + 负 carry 宽限退出,把它从扫描器推进到更像 production 的完整壳”。
---
> 这份 repo 最值钱的,不是又证明了一次 same-underlier cross-venue net carry 能做,而是把它写成了更像 production 的版本:50%+ net APR 准入、positive streak、4h negative-hours stop、15% liquidation-distance auto-close。对 short-cycle desk,下一步最值得先测的不是“每次 funding diff 为正就开”,而是“只做持续为正且没明显恶化的 pair”。
---
先把话说死:
repo 里的关键函数 find_pair_opportunities(...) 已经把这个写得很直白:
net_apr = |apr_a| + |apr_b|;net_apr = ||apr_a| - |apr_b||;LONG、哪边 SHORT;所以它不是“风控先于 alpha”的材料,恰恰相反: 它先承认 base alpha 就是 cross-venue carry,然后再在 admission / hold / forced-exit 层补全。
这对我们 desk 是对的,因为当前更缺的不是“funding differential 存不存在”,而是:
---
positive net APR streak:不是只看当前数值,而是看它活了多久repo 在 main.py 里专门维护了一个 _funding_streak 状态表:
_update_pair_net_streaks(...)get_pair_streak_hours(...)FUNDING_DIP_TOLERANCE_HOURS = 4.0逻辑非常直接:
pair_streak,例如 Net APR ~38.5% ⏱ 47h。这件事的重要性在于:
它把“当前很肥”与“已经持续存在”分开了。
很多 funding spread 看起来大,只是某个时点临时抽风;但 desk 真正想拿的是:
所以这轮最值得复现的不是 plain net_apr 排名,而是:
> positive-streak gated net carry:只做 net_apr 为正且持续时间够长、并允许短暂 dip 的 pair。
这比“只要当前 diff 为正就开”更接近真实可活的 short-cycle carry pocket。
negative-hours stop:不要一负就砍,也不要无限死扛repo 的保护阈值写得很死:
NEG_APR_HARD_CLOSE = -50.0NEG_APR_WAIT_HOURS = 4.0README 也明确写了自动平仓条件:
-50% 以下:立即关;这其实是在回答一个很实战的问题:
carry pair 的恶化,并不一定要等到价格层面完全炸开才处理。
更诚实的持仓管理是:
这比很多 funding 策略里常见的“开了以后只等 settlement / 只看手动关”更完整。
liquidation-distance auto-close:把“市场中性”当成有杠杆风险的仓位来管repo 还明确做了强平距离保护:
LIQ_WARN_PCT = 20.0LIQ_AUTO_CLOSE_PCT = 15.0PRICE_WARN_PCT = 10.0PRICE_AUTO_CLOSE_PCT = 15.0即:
20% 先报警;15% 自动平;这很重要,因为 cross-venue carry 最容易自欺的一点就是:
> “反正我两边对冲了,所以方向风险很小。”
实际上并不是。
不同 venue 的:
都不一样。pair 在组合层面接近中性,不等于任一单腿不会先被炸掉。
repo 至少诚实地把这件事写进了自动化规则里,而不是假设“对冲 = 安全”。
repo 不是只有扫描器。db/database.py 里有:
positions / funding_history / settings 表;README 里还明确暴露了:
POSITION_SIZE_USD = 100Add 加仓;10~15 USD / leg。这意味着它不是“讲一个 carry 故事”的 repo,而是已经把 entry / monitoring / scaling / exit / logging 串起来了。
对我们来说,这正是“可直接落地完整策略”的标准之一。
---
要老实讲: base alpha 本身并不新。
此前 digest 已经覆盖过:
2026-03-30_1919_perp-perp-funding-diff-nethurdle-alpha.md2026-04-02_1734_feecoverage-gated-crossvenue-funding-carry-alpha.md2026-04-12_0830_crossvenue-netcarry-ranking-alpha.md2026-04-13_0435_cexdex-fundingarb-shell.md2026-04-15_2326_cexdex-fundingspread-shockreversion-alpha.md所以这次不能再把主题写成泛泛的“跨所 funding differential 又能套利”。那样就是重复。
这次真正新增的 intake 点是:
positive-streak admission:不是只看当前 spread,而是看它持续了多久;negative-hours stop:不是刚翻负就砍,也不是一直扛;liq-distance auto-close:把组合中性的幻想,拆回单腿真实风险;所以这篇更准确的定位不是“又一个 funding differential 研究”,而是:
> 同一条 raw alpha,在 repo 层终于出现了一个更像 production 的 admission + hold + forced-exit 壳。
这就足够构成一次新的 intake。
---
从 repo 直接可见的默认参数:
MIN_PAIR_APR = 50:只报 net APR 至少 50% 的 pairSCAN_INTERVAL_SECONDS = 60POSITION_SIZE_USD = 100:默认每腿 100 USDSIGNAL_COOLDOWN_HOURS = 4APR_GROWTH_THRESHOLD = 0.5:若 APR 较上次增长 50%+ 可再次报信号FUNDING_DIP_TOLERANCE_HOURS = 4.0NEG_APR_HARD_CLOSE = -50.0NEG_APR_WAIT_HOURS = 4.0LIQ_WARN_PCT = 20.0LIQ_AUTO_CLOSE_PCT = 15.0PRICE_WARN_PCT = 10.0PRICE_AUTO_CLOSE_PCT = 15.0支持的 venue:
README 还写明:任意交易所都可以两两配对,bot 自动找最优组合。
---
这条策略虽然收益结算事件还是 funding clock,但它对我们短周期 desk 依然有直接意义,因为它回答的不是“8 小时后收多少钱”这么单一的问题,而是:
1m / 3m / 5m 可以做 admission / monitoring 层短周期分辨率主要用来监控:
也就是:
monitor / protection / recheckadmission / hold-or-close verdict当前最值得先验证的不是 long-run APR,而是:
net_apr 排名开仓;net_apr + pair_streak 联合准入开仓;negative-hours stop;也就是说,要把这份 repo 的新增价值拆开测,而不是一股脑打包。
---
这条策略的数据需求分两层:
层 A:最小公开复现实验
1h 或 8h);1m 或更快;层 B:更贴 repo 的实盘化实验
先不要追求 5 家 venue 全上。第一轮建议:
BTC, ETH 先做2~3 家 funding public path 比较顺的 venue 做 proxy1m5m30~60d#### A. baseline:plain net carry
net_apr 最高的 same-underlier pair;net_apr >= threshold 则开;H 小时 / 或简单 net carry 翻负退出。#### B. streak admission
pair_streak >= {2h, 4h, 8h, 12h};{0h, 2h, 4h}。#### C. streak + negative-hours stop
grace_hours,继续持有;grace_hours 才退出;hard_close = {-25%, -50%, -75%}。#### D. streak + negative-hours + risk veto
entry-price adverse move proxy 近似。不要先盯年化收益,第一轮更该看:
post-cost pnl / pairavg holding timefraction of pairs surviving to next funding eventfalse-positive rate of fresh spreads(刚出现就消失的 pair 占比)streak bucket -> realized outcomeorphan risk / one-leg forced close incidents---
first verdict:值得 intake,而且更像“实盘组件拆解”意义上的强候选。
但要把话讲清:
streak admissionnegative-hours stopsingle-leg risk honestyDB-backed execution loop如果你现在让我只从这份 repo 拿走一句最有用的话,那就是:
> 别再把 cross-venue funding carry 写成“谁 net APR 高就做谁”;先测“持续为正多久”再决定要不要上。
---
streak admission 的最小回放先做最小版,不碰真实下单:
1m 抓 funding / mark;5m 计算 all-pair net_apr;positive_since / dip_since;plain net_apr thresholdnet_apr + streak >= Xnegative-hours stop 是否有边际价值对同一批 admission 过的 pair,比较:
flip-negative immediately exitwait 1hwait 2hwait 4hhard_close only核心问题是:
短暂负 carry 是可忍噪声,还是恶化前兆?
若 public path 拿不到强平价,就先做替代版:
> x% veto;> y bps veto;不要因为没有真实 liquidation price,就假装这部分风险不存在。
---
config.pymain.pycore/analyzer.pycore/executor.pydb/database.py.env.examplekohtabeloff/funding-arb-bot2026-03-302026-04-14Telegram bot for delta-neutral funding rate arbitrage on crypto perpetual exchanges---
如果后面真要进复现队列,最值得先写成独立模块的不是 Telegram,不是 DB,而是这 3 个函数层:
calc_net_apr(pair)update_positive_streak(pair)exit_if_negative_too_long / exit_if_leg_risk_too_high也就是说,真正该拿进我们自己代码库的,应该是:
这才是这篇 intake 的核心。