4.4 断言机制:在关键风险点埋设不可绕过的检查

📅 2026/7/11 1:53:22
4.4 断言机制:在关键风险点埋设不可绕过的检查
1998年长期资本管理公司的办公室里聚集着全世界最聪明的一群人。这家对冲基金的合伙人包括两位诺贝尔经济学奖得主——罗伯特·默顿和迈伦·斯科尔斯正是他们发明了期权定价的布莱克-斯科尔斯公式。基金的核心策略极其精巧用默顿自己的话说是把金融市场当成一个巨大的数学模型来套利。他们用历史数据做了无数次回测计算出了每一种资产组合在每一个置信区间下的最大可能亏损。他们给这套系统起了个名字叫“风险管理”。1998年8月俄罗斯宣布债务违约。这个事件在他们的模型里被标记为“一个标准差以外的小概率事件”——大约相当于七级地震发生在核电站正下方的概率。他们算过这个概率认为它小到不值得专门为它准备预案。然后这个小概率事件就发生了。两个月之内长期资本管理公司亏掉了46亿美元被迫由美联储出面组织华尔街银行集体接盘才避免了系统性崩溃。在事后的听证会上默顿说了一句让所有做技术的人后背发凉的话“我们的模型不是错了。我们只是没有为模型覆盖不到的尾端风险准备一个硬性的退出机制。我们假定那些极端事件发生的时候我们还有时间和理性去手动处理。但当它们真的发生时我们既没有时间也没有理性。”“我们假定自己还有时间和理性。”这句话是你所有没有预设断言规则的投资操作的共同墓志铭。断言语句在理性的时候给不理性的自己戴上镣铐在C语言里assert是一个极其简单也极其暴力的宏。你给它一个表达式如果表达式求值为真程序继续执行就像什么都没发生过。如果表达式求值为假程序直接终止在stderr上打印一条错误信息告诉你断言在哪个文件的哪一行失败了然后毫不留情地退出。注意这个设计里最核心的特征断言失败之后没有恢复流程。没有try-catch没有onError回调没有“你是否确定要继续执行”的确认对话框。表达式为假程序直接死。这不是缺陷这是设计意图。断言的存在逻辑是某些条件如果不再成立说明系统已经进入了一个绝对不应该进入的状态。在这个状态下继续运行的危害远大于立即停止。你的投资系统里有哪些条件是“一旦不成立就绝对不应该继续运行”的第一个应该被写进断言语句的条件是你预设的止损线。不是“差不多该止损了”的心理模糊区域是一个精确到百分比和触发条件的硬断言。比如“如果任何单只股票的持仓亏损超过买入成本的15%则必须在下一个交易日开盘的30分钟内全部卖出。不分析不等反弹不研究基本面有没有变化。”这句话的每一个部分都是不能分割的——15%是阈值下一个交易日开盘30分钟内是执行时间不分析不等待是执行纪律。它就是你写在投资日志里的assert(position.unrealizedLoss 0.15)。只要这个断言还成立你可以继续持有。断言失败的那一刻你唯一合法的操作就是执行它定义好的退出动作。你有没有发现我在这里的描述里刻意回避了“你应该考虑止损”或者“建议你设一个止损线”这种软性措辞因为建议不是断言。建议是你可听可不听的断言是程序不听就崩溃的。你的投资系统里现在有多少条规则是以“建议”的形式存在的又有几条是被你写成了断言的形式把“建议”升级为“断言”是你从散户思维转向系统思维的最关键的一步。第二个断言语句应该埋在仓位管理上。你在第二章第五节设了单票10%、单行业30%的仓位上限。这些上限现在是什么形态是你的“目标比例”还是“绝对不可逾越的红线”如果它们只是目标比例那你上周在某只股票涨得很好时把仓位加到了12%也不算违规——你只是“暂时偏离目标”。但这种“暂时偏离”就是没有被断言保护的代码路径。你应该把仓位上限写成assert(portfolio.singleStockWeight 0.10)一旦超出系统必须拒绝执行任何新的买入指令直到仓位通过卖出或者新增资金稀释回到红线以内。第三个断言应该埋在市场整体状态的判断上。这句话可能会让很多技术分析怀疑者不舒服但它是一个久经考验的系统性风控工具当大盘指数——比如沪深300——跌破200日均线并且在接下来的一周内无法重新站回均线之上你的总权益仓位必须降到30%以下。这不是在预测市场。这是在进行系统降级运行。你不需要相信200日均线有什么魔力你只需要理解这个断言背后的工程逻辑当一台服务器的健康检查连续失败三次之后负载均衡器不会分析这台服务器到底还能不能抢救一下它会直接把它从集群里摘掉。200日均线就是你的市场健康检查探测器。它连续发出失败信号你的系统就应该自动降级把更多的资源从应用层收回到内核层和系统服务层。你没有在做市场预测。你在做负载管理。不可绕过性断言失败程序必须崩溃退出在Java里有一种反模式叫“捕获异常后什么都不做”。你见过这种代码吗一个try块包裹着一个可能抛异常的操作catch块里只有一行注释// 忽略此异常不影响主流程。写这段代码的工程师通常有一个听起来很合理的理由“这个异常发生的概率极低真发生了也不是致命错误没必要为它中断用户体验。”然后这个被静默吞噬的异常在生产环境里埋了一个隐藏了三年的数据错误直到某一天因为一个完全不相关的代码变更被触发整个服务全线崩溃。没有人能把这次崩溃和三年那个被忽略的异常联系起来因为异常被吃了日志里什么都没有。你给自己的断言设置“例外情况”就是在你的投资系统里写了一个空的catch块。“大盘跌破200日均线必须减仓——但这次跌破是因为突然的疫情冲击不是经济基本面恶化所以这次可以例外。”这句话就是你那个空的catch块。你自己可能没有意识到但当你给一个断言加上了“除非”之后它就不再是断言了。它是你留给自己在不理性时刻的一条秘密通道。当真正的恐慌来临时你根本不会记得你预设的“除非”条件本来有多么严格。你的大脑会在恐惧中把任何条件都解释成“特殊情况”。断言不可绕过的唯一实现方法是在断言被触发之前就把绕过它的能力从自己手里夺走。你需要在你的交易系统外部——不是在脑子里不是在日志本里是在你无法临时更改的物理机制里——设置断言失败的自动执行逻辑。券商的条件单就是这种自动执行逻辑的最基础实现。你在买入一只股票之后立刻设置一个止损条件单如果股价跌破X元则以市价卖出全部。这个条件单一旦设置好就不要再去改它。它就是你在这只股票上写的assert宏。触发的时候不需要你手动确认不需要你临时判断不需要你在恐惧和贪婪之间再做一次选择。断言失败程序直接执行退出。条件单只能覆盖价格触发型的断言但已经覆盖了最重要的一类——止损。其他类型的断言比如仓位超限、大盘跌破关键均线你需要依赖的是另一种不可绕过机制时间锁定。在你的季度架构评审日上你把下个季度的所有断言规则写在一张纸上签上名字把它交给你的配偶或者一个你信任的朋友。下个季度内如果你想修改其中任何一条规则你必须先等72小时冷静期然后必须有那个人在场共同签字才能生效。这个机制没有技术含量但它有一个你独自面对市场时不具备的优势它在你的不理性自我和你的交易账户之间加装了一个第三方验证节点。编译期类型检查被套牢的价值投资者大多数是短线交易者冒充的在强类型语言里如果你声明了一个函数接受一个int类型的参数编译器不会允许你传一个string进去。编译阶段就给你报错程序根本跑不起来你连在运行时报错的机会都没有。这个机制叫编译期类型检查。它消灭了一大类在动态语言里极其常见但在强类型语言里不可能出现的运行时错误。你的每一笔交易也应该有一个编译期的类型声明。在买入之前你必须写下这笔交易的类型。只有两种合法类型可选短线交易或者长线持有。短线交易的定义是你的买入理由基于的是技术指标、市场情绪、事件驱动或者任何你预期会在三个月以内被市场消化的短期信息。长线持有的定义是你的买入理由基于的是企业基本面——它的商业模式、行业地位、长期盈利能力和护城河——并且你预期至少持有三年以上。两种类型都可以做没有谁比谁高级。但它们各自对应的退出条件是完全不同的就像int和string在内存里的存储方式和可执行的操作完全不同一样。短线交易的退出条件是价格触发——止盈止损线到了就执行没到就等和基本面无关。长线持有的退出条件是逻辑触发——你买入时依赖的核心逻辑不再成立才卖出价格波动不应该直接触发卖出。这条编译期规则在你买入的时候就锁定交易的类型。如果你在买入时声明这是一笔长线持有那么三个月后它跌了20%你不能把它卖掉然后说自己是在“短线止损”。类型不匹配编译器应该直接拒绝这个操作。如果你声明这是一笔短线交易那么它跌了20%但你觉得这家公司挺好的决定继续拿着同样类型不匹配——短线变长线的唯一合法途径是卖出现在仓位重新写一份长线买入日志然后重新买入。你可能觉得这个规矩太苛刻了现实中谁能严格遵守我告诉你谁遵守了。巴菲特在2016年开始买入苹果他声明这是基于苹果的生态护城河和消费者忠诚度的长线投资。2018年苹果股价跌了超过30%2020年疫情期间再次大幅波动他加仓了。2024年他减持了部分苹果仓位理由是估值已经偏高税后收益的性价比在下降。从买进到减持他对苹果的每一步操作都符合他最初声明的类型定义。他没有在2018年因为跌了30%就“止损”因为那不是一笔需要止损的交易。而大多数声称自己在做“价值投资”的散户他们的行为轨迹其实是这样的买入的时候自称基于基本面长线持有跌了15%之后开始研究技术指标寻找支撑位跌了30%之后卸载软件假装自己是永久股东反弹到只亏5%的时候赶紧清仓松了一口气。他们在一个交易周期里把这个类型从长线改成了短线又从短线改成了鸵鸟又从鸵鸟改成了止损。他们的类型系统是动态弱类型的——编译器允许任何隐式转换运行时报错了才后悔。而运行时报错的代价是真金白银。从下一笔交易开始在你的买入日志里加一行只有两个选项的下拉菜单这笔交易的类型是短线还是长线选一个。选完之后后续所有操作都必须通过类型检查。如果你发现自己想做的操作和当初的类型声明不匹配那不是你操作的时机到了是你需要重新设计交易计划的时候。断言不会让你不犯错。断言只会让你犯的错在第一时间就暴露在编译器的报错信息里而不是埋在生产环境的日志深处等你三年后才发现。在下一节我会带你把你过去所有的错误分门别类——用二分法把你亏损最密集的资产类别、操作模式和心理状态精确地定位出来。到那时候你可能会发现一个你不想面对但必须面对的事实你亏损最多的那个模块也许根本就不应该存在在你的系统里。