输入/搜索内容
8
关注
1375
关注者
网格不该决定仓位:用分数凯利给只做多网格加一道资金预算
交流分享
创建于 2026-08-20 15:46:20  更新于 2026-08-24 11:32:56
 0
 3

img

网格负责回答“价格走到哪里做一次动作”,凯利负责回答“整套策略最多能用多少钱”。把这两件事分开,才有可能让网格从一组补仓规则,变成一套可以回测、可以对账、也知道什么时候应该停手的系统。

本文讨论一个只做多的动态网格原型,适用于 FMZ 支持的线性永续合约。它既可以用于传统 Crypto 标的,也可以研究 NVDA 等 TradFi 映射类永续产品,但不依赖某一家交易平台的私有接口。

先说明边界:本文展示的是策略结构和 FMZ 工程实现,不提供收益承诺,也没有用一张漂亮的全样本曲线代替样本外验证。网格在持续下跌中会积累库存,凯利估计也会受到样本误差影响,两者叠加并不会自动变成低风险策略。

策略仅为文章思路实现、思路策略版本,可能后续需要继续升级更新,仅用于学习、交流。

策略源码: https://www.fmz.com/strategy/547981


一、我真正想解决的,不是“网格间距设多少”

做网格时,人很容易把注意力全部放在格距上:0.5% 还是 1%,五层还是十层,等距还是指数间距。

但真正决定策略能不能活下来的,往往不是这些参数,而是另一个更基本的问题:

如果价格一路向下,这套网格最多允许占用多少资金?

传统网格经常把“每层买多少”和“价格跌多少”写在一起。第一层一手,第二层两手,第三层四手。表面上是在优化持仓均价,实际上是在用价格下跌自动扩大风险预算。

这套原型刻意把两个职责拆开:

  • 网格层只决定何时买、何时退出;
  • 凯利层只决定整套网格当前允许使用的总资金比例;
  • 执行层负责把报价币预算换成合约张数,并处理部分成交和订单对账;
  • 风控层有权停止新增风险,必要时逐批退出。

网格没有资格自行增加总预算。价格即使连续穿过五层,五层资金之和也不能超过凯利层给出的上限。


二、为什么设计成只做多

这不是因为“只做多一定赚钱”,而是因为本策略想研究一种明确的结构:在具有长期正向漂移假设的资产上,用回撤网格改善入场与退出,而不是同时维护两套方向相反的库存。

对于 NVDA 等股票映射类永续,这个假设来自标的公司价值长期增长的可能性;对于主流 Crypto 标的,则来自另一套更不稳定的长期采用假设。但无论是哪一种,正向漂移都是待验证假设,不是自然定律

只做多也不等于一直买。原型要求:

text
FastEMA >= SlowEMA 并且 Close >= SlowEMA

只有满足这个多头环境,策略才允许新增网格。价格向下穿越某一层时买入,之后反弹一个入场时的网格间距,退出对应批次。

每一批仓位都有自己的成交均价和退出目标:

text
TargetPrice = ActualEntryPrice × (1 + EntrySpacing)

这里有一个容易忽略的细节:已经成交批次的目标不再随着 ATR 改动。

ATR 可以改变未来尚未成交的网格,却不能回头修改一笔已经承担风险的交易计划。否则价格波动一放大,止盈线也跟着越跑越远,动态参数就变成了拖延退出的借口。

锚点也只允许在空仓、无活动订单且趋势健康时向上移动。持仓期间不向下追踪价格,避免网格一边下跌、一边把“参考起点”往下挪,最后连硬止损的基准都失去意义。


三、网格间距先覆盖成本,再讨论波动

网格太窄,交易次数会很好看,但毛利可能全部交给手续费和滑点;网格太宽,又可能长期没有动作。

原型把间距写成三条约束的最大值:

text
Spacing = clamp( max( MinGridPct, ATR / Price × AtrMultiplier, 2 × (FeePerSide + SlippagePerSide) × CostFloorMultiple ), MinGridPct, MaxGridPct )

三部分分别回答:

  1. 策略允许的最小业务间距是多少;
  2. 当前行情实际波动到了什么尺度;
  3. 一次买入加一次退出的估计成本,需要留下多大安全余量。

假设单边手续费和滑点分别都是 0.05%,安全倍数为 2,那么成本下限为:

text
2 × (0.05% + 0.05%) × 2 = 0.4%

即使 ATR 暂时很低,网格也不会收窄到 0.4% 以下。这不能保证每次交易都有利润,但至少不会在参数层面主动设计一个“毛利还没有成本高”的格子。


四、不要拿“完成网格的胜率”计算凯利

这是整套设计最关键的地方。

一笔网格交易只要完成,通常就是小额盈利;亏损最大的库存,往往恰好还没有完成。如果只统计已经退出的批次,很容易得到这样的数据:

text
完成网格 93 次 盈利 90 次 亏损 3 次 胜率 96.8%

随后把这个胜率代入经典二项式凯利公式,结果可能会建议一个非常激进的仓位。

问题在于,那些仍然躺在账户里的浮亏没有进入样本。策略把未实现亏损藏在统计样本之外,再用一个被筛选过的高胜率指导仓位,这是典型的自我欺骗。

因此,本原型不把“完成一格”当作凯利事件,而是定期采样包含浮动盈亏的盯市权益

text
EquityReturn = Equity_t / Equity_(t-1) - 1 AverageExposure = (ExposureFraction_t + ExposureFraction_(t-1)) / 2 UnitRiskReturn = EquityReturn / AverageExposure

ExposureFraction 是当前名义敞口占固定参考权益的比例。这样做的目的,是把不同持仓规模下的权益变化尽量还原为“承担一单位风险时,策略得到的收益分布”。

然后不再使用只适合二项式赌局的简化公式,而是在历史经验样本上搜索:

text
f_raw = argmax mean(log(1 + f × UnitRiskReturn)) f ∈ [0, 1]

如果某个候选 f 会令任一样本中的 1 + f × r <= 0,它直接无效。若所有正仓位候选的平均对数增长都不高于空仓,最优结果就是 f_raw = 0

这并不意味着估计已经可靠。真实使用比例还要继续打折:

text
Confidence = min(1, SampleCount / (2 × MinSamples)) f_used = min( MaxStrategyEquityPct, f_raw × KellyFraction × Confidence )

原型默认使用四分之一凯利,也就是 KellyFraction = 0.25。样本刚达到最低数量时,置信折扣仍然只有一半;随着有效样本继续积累,折扣才逐渐放开。

凯利样本不足时,策略使用一个较小的预热资金比例。没有这一步,策略会陷入一个悖论:没有仓位就没有策略收益样本,没有样本又永远不能产生仓位。


五、凯利管总预算,不直接计算每一层

假设固定参考权益为 100000 USDT,预热比例为 10%,那么整套网格当前最多使用 10000 USDT 名义预算。

五层网格的权重不是越跌越大,而是按 0.85 递减:

text
1.0000, 0.8500, 0.7225, 0.6141, 0.5220

归一化以后,各层大约占总预算:

层级预算权重约占总预算预热期示例预算
11.000026.96%2696 USDT
20.850022.92%2292 USDT
30.722519.49%1949 USDT
40.614116.56%1656 USDT
50.522014.08%1408 USDT

这样设计不是为了让深层网格“更安全”,而是明确拒绝传统马丁结构:价格越不利,新增的单层风险反而越小。

如果后续经验分布给出 f_raw = 40%,四分之一凯利系数为 0.25,当前置信折扣为 0.75

text
f_used = 40% × 0.25 × 0.75 = 7.5%

新的整套网格预算变成 7500 USDT。如果现有名义敞口明显超过新预算和再平衡缓冲,策略会从较深批次开始逐批缩仓,而不是继续等待每一层原来的止盈目标。

这里需要强调:凯利下降时的缩仓本身也会产生换手和滑点。因此设置缓冲区很重要,不能让一个有噪声的估计器每次小幅变化都触发交易。


六、报价币预算怎样换成 FMZ 合约张数

策略界面输入的是资金预算,但 FMZ 合约下单的 amount 通常是合约数量。不能把 1000 USDT 直接作为 amount 传给下单函数。

原型通过 exchange.GetMarkets() 读取市场结构,重点检查:

  • CtVal:每张合约代表多少基础资产;
  • CtValCcy:合约价值单位;
  • AmountSize:数量精度或步长;
  • MinQty:最小数量;
  • MinNotional:最小名义金额。

v0.1.0 只接受 CtValCcy 等于基础资产的线性合约。此时可以按下面的方式估算数量:

text
RawAmount = QuoteBudget / (Price × CtVal) Amount = floor_to_step(RawAmount, AmountStep)

向下量化以后,再检查最小数量和最小名义金额。只要合约价值单位无法确认,策略就拒绝启动,而不是猜测一个换算方法。

Symbol 也使用 FMZ 完整格式,例如:

text
BTC_USDT.swap

研究股票映射类永续时,只需要把它替换为目标 FMZ 交易所实际提供的完整 Symbol。策略本身不切换交易所,不在代码里修改杠杆、逐仓/全仓或单双向持仓模式,也不传交易所专属的下单参数。


七、真正麻烦的不是公式,而是订单状态

策略公式写完,工程只完成了一半。

一次 exchange.CreateOrder() 请求可能出现这些情况:

  • 返回订单 ID,但订单只成交了一部分;
  • 请求到达交易所,响应却超时;
  • 撤单请求成功返回,但订单在撤单前又成交了一部分;
  • 策略进程在发单后重启;
  • 账户里存在人工订单或另一个策略的仓位。

如果程序遇到空返回就再次发送,很可能制造重复订单。原型采用的是更保守的路径:

text
先持久化 PendingIntent ↓ 调用 CreateOrder ↓ 拿到有效 ID → 保存 ActiveOrder → 清除 PendingIntent ↓ 没有拿到 ID → 保留 Intent → 进入 SAFE_HALT → 禁止盲目重发

部分成交也不能把 DealAmount 每次都完整加一遍,因为它通常是累计值。正确做法是只处理增量:

text
DeltaAmount = CurrentDealAmount - PreviousDealAmount

如果接口给出的 AvgPrice 也是累计均价,可以反推出本次新增成交的价格:

text
DeltaPrice = (CurrentDealAmount × CurrentAvgPrice - PreviousDealAmount × PreviousAvgPrice) / DeltaAmount

订单超时以后,策略只有在它仍然出现在 GetOrders(Symbol) 中时才请求撤单。CancelOrder 的返回值不等于订单已经进入终态,下一轮仍需查询最终累计成交量。

为降低归属歧义,这个原型一次只允许一个活动订单,也强烈建议使用专用账户或子账户。通用性不等于能安全接管一个混有人工仓位和其他策略订单的账户。


八、三种“停止”不能混成一个开关

策略参数设置:
img

img

原型把异常状态分为三层:

javascript
function runtimeStateName(runtime) { var state = runtime.state if (state.safeHalt) { return "SAFE_HALT" } if (state.riskHalt) { return "RISK_HALT" } if (state.dataFreeze) { return "DATA_FREEZE" } if (state.activeOrder) { return state.activeOrder.intent.kind + "_PENDING" } if (state.lots.length) { if (runtime.trendBroken) { return "DEFENSE" } return runtime.trendHealthy ? "HOLDING" : "PROBE_HOLDING" } if (runtime.trendHealthy) { return "GRID_READY" } return runtime.probeEligible ? "PROBE_READY" : "WAIT_TREND" }

1. DATA_FREEZE

连续行情错误、未知挂单或持仓与本地账本不一致时触发。它只冻结新增风险,已有仓位的退出、活动订单查询和对账仍继续执行。连续若干健康周期后可以自动恢复。

2. RISK_HALT

价格相对锚点达到硬止损,或者会话权益相对峰值回撤超过上限时触发。它会逐批退出,并保持锁存;空仓以后仍不能自动恢复,必须先“预备解除”,再在 60 秒内二次确认。

3. SAFE_HALT

发单结果未知、持久化状态损坏,或者检测到空头/未知方向仓位时触发。这个状态不应该被普通网络恢复自动清除,因为程序已经无法证明自己掌握真实订单和仓位状态。

这三种状态的区别可以概括为:

text
DATA_FREEZE:数据暂时不可信,先别增加风险 RISK_HALT:策略风险条件已经触发,退出后保持停机 SAFE_HALT:订单或状态归属无法证明,禁止自动猜测

九、这套结构有没有交易优势,必须这样验证

凯利只能放大或缩小已有的收益分布,不能把负期望策略变成正期望策略。动态网格看起来更聪明,也不代表它真的比简单持有更好。

至少需要同时比较五组基线:

版本网格间距仓位方法
A固定固定
BATR + 成本下限固定
CATR + 成本下限四分之一凯利
DATR + 成本下限半凯利
E不使用网格相同风险水平的简单多头

评估指标不能只看累计收益,还应包含:

  • 最大回撤、年化波动和 Calmar;
  • 平均对数增长;
  • 总换手和费用占毛利比例;
  • 平均与最大持仓层数;
  • 趋势退出和风险停止次数;
  • 凯利估计归零的次数;
  • 参数在相邻区间、相邻周期和不同标的上的稳定性。

训练和测试也不能混在一起。比较合适的流程是:

text
训练窗口估计参数 ↓ 固定参数运行下一段样本外区间 ↓ 窗口向前滚动 ↓ 汇总所有未参与拟合的样本外结果

如果只有全样本最优参数好看,轻微改变 ATR 倍数、EMA 周期或成本假设,结论就消失,那么策略更可能是在适应历史噪声。


十、放到股票映射类永续上,还要补哪些东西

这个通用原型故意没有硬编码某一家平台的产品机制。因此用于 NVDA 一类 TradFi 映射永续时,还存在几项不能忽略的第二阶段工作:

  1. 交易时段差异:永续可能持续交易,但现货股票有明确的主要价格发现时段;
  2. 隔夜与周末定价:参考市场关闭后,盘口深度、价差和价格锚定机制可能明显变化;
  3. 财报和公司事件:跳空风险不是 ATR 网格能够完整吸收的;
  4. 资金费率和溢价:长期只做多的持有成本可能吞掉网格毛利;
  5. 产品跟踪机制:指数价格、预言机、停牌处理和上下架规则可能因平台而异。

这些问题需要稳定、可验证的数据接口后再加入。为了“看起来完整”而读取某一家平台的私有字段,反而会破坏策略的通用边界。


结语:凯利不是油门,而是预算审批

img

我更愿意把这套策略里的凯利理解成一个预算审批器,而不是自动加速器。

网格说:“价格已经走到第二层,我想再买一次。”

凯利层回答的不是“买多少倍”,而是:

当前样本支持的整套风险预算还有多少?这次动作会不会让总敞口越界?

如果样本不支持正的对数增长,答案可以是零;如果已有仓位超过新预算,答案也可以是先减仓。只有把“什么时候交易”和“最多承担多少风险”拆开,网格才不至于在最不利的时候自动给自己扩权。

下一步真正有价值的工作,不是继续增加公式,而是完成 FMZ 导入验证、建立五组基线,并把手续费、滑点、资金成本和样本外区间全部放进同一张结果表。到那时,我们才能回答这个题材最重要的问题:

网格加分数凯利,究竟改善了资金增长与回撤的权衡,还是只是让策略看起来更复杂?


风险提示:本文仅用于量化策略研究、程序设计和平台接口交流,不构成投资建议。永续合约可能涉及杠杆、强平、资金费率、流动性、跳空、跟踪偏差及平台技术故障风险。研究原型必须经过回测、样本外验证、模拟盘和极小资金测试,不能直接用于生产资金。

感谢您的阅读与支持!

相关推荐
评论
全部评论 (0)
暂无数据
暂无数据
  • 1
社区
回测系统
APP 下载
iPhone 下载
© 2015 - ∞ INVENTOR PTE LTD (SG)