第四章:核心业务模型——订单生命周期与金融产品模型

这一章,我们来聊聊券商电子交易系统里最核心的两个东西:订单怎么走完一生,以及股票、期货、期权这些产品在系统里长什么样

说实话,我见过不少团队,一上来就撸代码,结果订单状态机画得乱七八糟,产品模型耦合得跟 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 核心逻辑流程图

下面这张图,展示了订单从创建到清算的完整流程,以及金融产品模型在其中的作用。

订单生命周期与产品模型核心逻辑 1. 订单创建 2. 校验(基础+风控) 3. 路由(智能路由) 4. 成交(全成/部成) 5. 清算(资金+持仓) 金融产品模型 股票:代码+市场+状态 期货:合约+乘数+保证金 期权:行权价+到期日+类型 产品模型影响: 校验规则 路由逻辑 清算算法 注:虚线表示产品模型对订单流程的约束和影响 订单状态机 已创建 → 已校验 已校验 → 已路由 已路由 → 已成交 已成交 → 已清算 异常路径: 已创建 → 已拒绝 已路由 → 路由失败 已成交 → 清算失败 每个状态转换必须幂等

4.4 总结与避坑

好了,这一章的内容就这些。我最后再唠叨几句:

  • 订单状态机一定要画清楚。我见过太多团队,状态机画得模棱两可,结果上线后各种bug。
  • 产品模型一定要解耦。股票、期货、期权,它们的差异远大于共性。别偷懒,分开设计。
  • 清算环节一定要保证一致性。资金和持仓,要么都更新,要么都不更新。没有中间状态。

最后一个小技巧:如果你在设计订单系统,建议先画一张「订单状态转换图」,贴在墙上。每次开会都看一眼,确保所有人都理解一致。这招我用了很多年,效果很好。

专注资料整理