第四章:核心业务模型——订单生命周期与金融产品模型
这一章,我们来聊聊券商电子交易系统里最核心的两个东西:订单怎么走完一生,以及股票、期货、期权这些产品在系统里长什么样。
说实话,我见过不少团队,一上来就撸代码,结果订单状态机画得乱七八糟,产品模型耦合得跟 spaghetti 一样。嗯,最后都得返工。所以,咱们先把地基打牢。
4.1 订单生命周期:从出生到入土
一个订单,从用户点击「买入」那一刻起,到最终变成持仓或现金,中间要经历好几个阶段。我习惯把它分成五个核心步骤:创建 → 校验 → 路由 → 成交 → 清算。
核心观点:订单生命周期是一个严格的状态机。每个状态转换都必须有明确的触发条件和幂等性保证。我在项目中遇到过因为状态机没设计好,导致一笔订单被重复成交的惨案……
4.1.1 创建(Creation)
用户提交订单请求,系统生成一个唯一的订单ID。这一步看似简单,其实坑不少。
- 唯一性:分布式环境下,订单ID必须全局唯一。我建议用「雪花算法」或「UUID + 业务前缀」。
- 快照保存:创建时就要把原始请求完整存下来。为什么?因为后面校验、路由出问题时,你得能回溯。
- 状态初始:订单状态设为「待校验」或「已创建」。
避坑指南:我曾经遇到过一个案例,订单创建时没保存用户IP和终端信息。结果后来发生纠纷,根本没法定位是谁下的单。所以,创建时多存几个字段,没坏处。
4.1.2 校验(Validation)
校验环节,说白了就是检查这个订单「能不能发出去」。我把它分为两层:
| 校验层级 | 检查内容 | 典型失败原因 |
|---|---|---|
| 基础校验 | 证券代码是否存在、买卖方向是否合法、数量是否为正整数 | 代码停牌、数量超过单笔上限 |
| 风控校验 | 资金是否足够、持仓是否足够、是否超过日内交易限额 | 资金不足、持仓不足、触发反洗钱规则 |
校验通过,订单状态变为「已校验」;不通过,直接变为「已拒绝」,并记录拒绝原因。
你想想看,如果校验逻辑写得不够严谨,一个资金不足的订单流到交易所,会怎么样?轻则废单,重则被交易所处罚。所以,这块我建议用独立的校验服务,别跟业务逻辑混在一起。
4.1.3 路由(Routing)
路由,就是决定这个订单「该发到哪个交易所或交易通道」。不同的产品、不同的市场,路由逻辑完全不同。
- 股票:根据证券代码的前三位,路由到对应的交易所(上交所、深交所、北交所)。
- 期货:根据合约代码,路由到对应的期货交易所(中金所、上期所、大商所、郑商所)。
- 期权:类似期货,但要注意区分股票期权和商品期权。
我个人习惯在路由层做一次「智能路由」:如果主通道拥堵,自动切换到备用通道。嗯,这个功能在行情火爆时特别有用。
警告:路由层必须做超时控制。我曾经见过一个系统,路由请求发出去后一直等交易所回复,结果线程池被打满,整个系统挂了。设置一个合理的超时时间(比如5秒),超时后走「路由失败」流程。
4.1.4 成交(Execution)
订单到达交易所后,交易所会返回成交结果。这里有两种情况:
- 全部成交:订单状态变为「全部成交」。
- 部分成交:订单状态变为「部分成交」,剩余未成交部分继续挂在市场上。
成交回报的处理,我建议用异步消息队列。为什么?因为交易所的成交回报是流式推送的,如果同步处理,很容易成为性能瓶颈。
4.1.5 清算(Clearing)
清算,是订单生命周期的最后一站。它负责更新用户的资金和持仓。
- 资金清算:买入扣钱,卖出加钱。注意要扣除手续费和印花税。
- 持仓清算:买入加仓,卖出减仓。注意要区分「可卖数量」和「冻结数量」。
清算环节,我建议用「两阶段提交」或「TCC模式」来保证数据一致性。你想想看,如果资金扣了但持仓没加上,用户会怎么投诉你?
4.2 金融产品模型:股票、期货、期权
不同的金融产品,在系统里的数据结构差异很大。我见过最糟糕的设计,是把所有产品的字段都塞到一张表里,结果字段多到几百个,维护起来想死的心都有。
我的建议是:用「产品基类 + 产品子类」的继承模型。
4.2.1 股票模型
股票是最简单的产品。核心字段包括:
- 证券代码(如:600001.SH)
- 证券名称
- 市场类型(上海、深圳、北京)
- 交易状态(正常、停牌、退市)
- 最小交易单位(1手 = 100股)
- 价格精度(0.01元)
股票模型没什么复杂的,但要注意一点:除权除息。股票分红送股后,价格会调整。如果你没处理好,用户的持仓成本会算错。
4.2.2 期货模型
期货比股票复杂一些,因为它有「合约」的概念。核心字段包括:
- 合约代码(如:IF2406)
- 合约名称
- 交易所
- 合约月份
- 合约乘数(如:沪深300股指期货乘数是300)
- 最小变动价位(如:0.2点)
- 保证金比例
- 涨跌停板幅度
期货还有一个特殊概念:持仓限额。每个投资者对同一合约的持仓不能超过一定数量。这个在风控校验时一定要检查。
个人经验:我在做期货系统时,曾经因为合约乘数配置错误,导致用户的盈亏计算差了10倍。嗯,从那以后,我要求所有产品参数必须经过「双人复核」才能上线。
4.2.3 期权模型
期权是最复杂的产品。它不仅有合约,还有「行权价」、「到期日」、「合约类型(看涨/看跌)」等概念。
核心字段包括:
- 期权代码(如:510050C2406M03000)
- 标的证券代码
- 合约类型(Call / Put)
- 行权价
- 到期日
- 合约单位(如:10000股/张)
- 行权方式(欧式/美式)
期权模型的设计,我建议把「合约」和「持仓」分开。合约是静态的,持仓是动态的。这样设计,查询合约信息时不用关联持仓数据,性能会好很多。
4.3 核心逻辑流程图
下面这张图,展示了订单从创建到清算的完整流程,以及金融产品模型在其中的作用。
4.4 总结与避坑
好了,这一章的内容就这些。我最后再唠叨几句:
- 订单状态机一定要画清楚。我见过太多团队,状态机画得模棱两可,结果上线后各种bug。
- 产品模型一定要解耦。股票、期货、期权,它们的差异远大于共性。别偷懒,分开设计。
- 清算环节一定要保证一致性。资金和持仓,要么都更新,要么都不更新。没有中间状态。
最后一个小技巧:如果你在设计订单系统,建议先画一张「订单状态转换图」,贴在墙上。每次开会都看一眼,确保所有人都理解一致。这招我用了很多年,效果很好。