“期货投资管理”分仓软件,听起来像是个金融行业的黑话,但拆开来看,它本质上是给资管团队或者交易团队用的多账户管理系统。我最早接触这类项目,是因为团队里管着十几个交易账户,每个账户的资金规模、交易权限、风控参数都不一样,还经常有人问“我这个账户还剩多少可用资金”“为什么这笔单子被拒了”。单靠手工记账和人工轮询,根本扛不住。后来我们自己做了一套分仓软件,核心思路就是把一个主账户在系统内部拆成多个子账户,每个子账户独立验资、独立风控、独立清算,下单时由系统把子账户的指令合并到主账户出去。这个项目做完之后,我把整个构成架构和功能实现重新梳理了一遍,很多东西对做量化、做资管、做交易系统的人都挺有参考价值。
这篇东西适合三类人看:一是正在规划自建资管系统的技术负责人,二是给交易团队做工具开发的程序员,三是对交易系统内部结构好奇但又不想啃源码的朋友。我会从总体设计思路讲到子账户的资金模型,再讲交易链路和常见坑,尽量把逻辑讲透,方便你直接落地参考。
1. 项目定位:分仓软件到底在解决什么问题
1.1 从主账户到子账户的追源
先说场景。你有一个主账户,可能是开在某期货公司的资金账户,里面有真金白银。传统做法是所有人都用这一个账户下单,但问题立刻来了:张三和李四各往里入了一笔钱,怎么区分各自的盈亏?张三是做趋势的,李四是做高频的,风控规则完全不一样,怎么分别限制?更麻烦的是,如果张三的止损规则只在交易员的脑子里,下单手一抖就超了,亏损算谁的?
分仓软件就是冲着这些问题来的。它在主账户之上做逻辑拆分:一个主账户下面挂多个子账户,每个子账户有自己独立的资金、仓位、权限、费率、风控参数。子账户并不是真实存在的期货账户,它只是系统内部的一套账务和权限控制单位。交易员操作的是子账户,但所有指令会汇总到主账户统一发往交易所。子账户之间互不干扰,张三赚不到李四的钱,也动不了李四的仓位。
这里有个容易混淆的点:分仓和“子账号”不是一回事。子账号可能只是登录凭证,而分仓是账务隔离。真正的分仓软件,核心一定得有一本极其严密的内部账本,能够准确回答“每个子账户现在到底有多少钱、多少持仓、多少可开仓手数”,而不是简单地给几个人开几个登录名。
1.2 子账户不是削萝卜——权限和资金的双重隔离
我们当初做需求调研时,业务方提了很多话:“我要能看到每个小账户的实时盈亏”“我要能限制某个人只能做螺纹,不能做其他品种”“我要能批额度给某个子账户,用完就停了”。听上去很散,但归纳下来就是两件事:资金隔离和权限隔离。
资金隔离说的是每个子账户的资金状态要独立计算。你存了五十万进来,系统里就给你记五十万的期初权益;你做了几笔交易,系统要实时算出浮动盈亏、手续费、保证金占用、可用资金。这些全都是子账户维度的,不能和其他人混在一起。
权限隔离说的是功能层面。某个子账户允许交易哪些品种、单笔最大手数、当日最大亏损、是否允许夜盘、是否允许开仓、是否允许出金,这些都要能配置。配置是黑名单还是白名单,取决于业务习惯,但底层逻辑必须支持到非常细的粒度。
权限和资金为什么要双重隔离?因为只靠资金隔离,你没法阻止某个交易员在情绪上头时一把梭;只靠权限隔离,又没法回答“账上到底亏了多少”。两者组合起来才是一个完整的子账户模型。
1.3 这个系统适合谁来用
分仓软件的应用场景很清晰:多交易员协同的公司、家族资金管理、多策略产品内部拆分、以及对外提供资管服务的机构。如果你只是自己炒期货,一个账户就够了,没必要上这套系统。但如果涉及“别人的钱”或“不同策略的钱”混在一个主账户里,分仓几乎是唯一干净的解法。
2. 整体架构思路与分层设计
2.1 分层架构:接入层、业务层、数据层
我把整体架构分成四层,从上到下依次是:客户端接入层、核心业务层、数据服务层、行情与交易接入层。这个分层不是拍脑袋定的,而是根据实际迭代踩坑后调整的结果,每一层都有明确边界。
客户端接入层主要管终端,包括PC端交易界面、风控管理端、移动端查询端。管理层要看的是整体资金曲线和各子账户实时状态,交易员要的是快速下单和持仓查询,两边诉求完全不一样,所以接入层特意做了多端适配。
核心业务层是整个系统的中枢,它管订单、管账户、管风控、管清算。我建议把订单服务和账户服务拆成两个独立进程,因为订单是高频写入,账户是高频读取,如果混在一起,查询账户的时候容易被下单事务阻塞。我们第一版就吃过这个亏,查一个子账户权益居然要等几百毫秒,后来拆开才解决。
数据服务层负责持久化,包括资金流水、成交记录、持仓快照、日终快照。数据层要支撑两类查询:一类是交易员查“我现在有多少钱”,必须快;另一类是财务查“某天谁成交了什么”,需要稳定。所以我在存储设计上用了“实时表+归档表”的组合方案。实时表只保留最近几天的热数据,归档表按月分表,查询走时间范围路由。实测下来,单日十万笔成交的规模下,归档查询可以控制在秒级。
行情与交易接入层负责和柜台打交道。不同期货公司的柜台接口风格差异非常大,所以要封装一层适配器。这层设计得好不好,直接决定后续对接新柜台的工作量。我见过很多系统把柜台API硬编码到业务代码里,换一个柜台等于重写一遍,这是在给自己埋坑。
2.2 为什么必须独立出风控模块
风控是分仓软件里最容易出问题的地方。它不像订单服务那样只有一条链路,风控是多环节、多条件的组合判断。在下单前要有事前风控,在持仓中要有实时风控,在日终还要有静态风控。如果风控逻辑和交易逻辑耦合在一起,改一个限制条件就要重启交易服务,这在实盘中是不可接受的。
我把风控做成了一个独立的服务,内部跑规则引擎。每个子账户可以配置一组规则,比如“螺纹钢单品种持仓不超过总资金的两倍”“单日累计亏损超过五万元禁止开仓”“单笔下单量不超过五十手”。这些规则按照优先级依次执行,全部通过才允许下单。如果触发其中任何一条,直接返回拒绝原因,这笔单子可以精确告诉你“为什么被拒”。
还有一个容易被忽略的点:风控规则必须支持热更新。业务方不会只在系统上线前提需求,他们会在盘中突然说“今天把某品种的权限全部关掉”。如果你不支持热更新,就得等收盘后改配置再重启,这类需求一旦满足不了,团队分分钟炸毛。
独立风控模块的另一个好处是可以做全局风控。比如系统层面设置“所有子账户合计螺纹钢持仓不能超过多少手”,这种维度跨子账户,单看任何一个子账户都发现不了问题,只有独立风控服务能汇总全局数据进行判断。
2.3 数据如何落地:库表设计的关键点
分仓软件的数据模型,我拆成五大块:账户表、资金流水表、订单表、持仓表和配置表。理解了这五块,基本上就掌握了整个系统的数据骨架。
账户表记录子账户基本信息,包括账号、所属主账户、持有人、初始资金、当前权益、保证金占用、可用资金、状态。这里有一个关键设计:账户表的权益字段只是缓存,不能直接信它。每次真正计算可用资金时,要基于资金流水和持仓重新推导。为什么?因为缓存的数值可能会因为并发写入或者异常回滚而不准确,如果直接信缓存,可能出现“系统说有钱,但实际没额度”的诡异问题。
资金流水表是所有账务变动的原始记录,入金、出金、手续费、盈亏、资金调整都要记一条流水。每一笔流水都带一个业务编号和关联的单号,方便追溯。这块我建议做成只追加、不允许修改,即使要调整,也新增一条反向流水去冲正,保证账目可审计。
订单表相对简单,记录子账户提交的每一笔委托,包括品种、方向、手数、价格、状态、拒绝原因。订单表和子账户是强关联的,所以索引上要建“子账户+时间”的联合索引,方便当日查询。
持仓表要做的是“双空间”存储:一边是子账户维度的逻辑持仓,一边是主账户维度的实际持仓。为什么要有主账户维度的实际持仓?因为同一个品种可能多个子账户都在交易,他们之间的对冲关系只有在主账户维度才能看清楚。我们做清算时,要定期把两个维度做对账,一旦出现不一致,立刻报警人工介入。
3. 子账户的构成与资金模型详解
3.1 父子账户的绑定关系设计
绑定关系是分仓软件最基础的关系设计。一个主账户下面可以挂多个子账户,但一个子账户只能归属一个主账户。这个设计遵循的是金融记账里最基本的“账套”概念,所有核算都从子账户出发,再汇总到主账户。
我在实际项目里增加了一个“子账户组”的层级。什么意思呢?就是允许把多个子账户归到一个组里,按组来配置共用风控参数。比如一个策略组下面有五个子账户,它们共享一个总止损线。这个设计在业务上非常有用,因为很多团队是按策略类型分组的,同一策略的账户必须共进退,你不可能让五个账户用五套完全不同的规则。
表结构上,子账户表里加一个父级编号字段,形成树形结构。树的深度不用很深,三级以内就够用了。再深,要么是你业务设计过度拆分,要么是数据管理会变得非常难维护,得不偿失。
3.2 资金模型:初始权益、可用资金、占用保证金、冻结
子账户的资金模型是整个系统的灵魂。我平时给别人讲资金公式时,会直接用一句话概括:可用资金等于当前权益减去保证金占用再减去冻结金额。看起来简单,但每个词后面都有细节。
当前权益怎么算?它是初始权益加上累计入金出金,再加上累计平仓盈亏和浮动盈亏,再减去累计手续费。这里有个细节:浮动盈亏的计算要按逐笔盯市还是逐日盯市?国内期货大多采用逐日盯市,就是每个交易日结束后按照当日结算价重新计算持仓盈亏。系统里要区分“盯市浮动盈亏”和“持仓成本盈亏”,否则日终结算时账会算不平。
保证金占用怎么算?每一笔未平仓的合约,按照最新价或结算价乘以合约乘数乘以保证金比例,累加起来。不同品种的保证金比例不一样,而且交易所会临时调整,所以系统里要维护一张可人工覆盖的保证金参数表,不能硬编码。
冻结金额是很容易被忽略的一块。子账户提交了委托但还没成交时,这部分保证金要先冻结,防止可用资金被重复使用。初始冻结按照委托价估算,实际成交后多退少补。如果忽略了冻结这一环,会发现一个账户能开出的手数远超实际资金承受能力,这是分仓系统里非常严重的问题。
3.3 交易指令的流转路由
子账户提交一笔下单指令后,系统做的事情比想象中复杂。第一步是合法性校验,包括账户状态是否正常、该品种是否有交易权限、当前是否在交易时间内。第二步是资金校验,计算这笔单子大概需要多少保证金,冻结后可用资金是否仍然为正。第三步是风控校验,跑所有配置好的规则。三步全过,才允许进入指令队列。
进入指令队列之后,就要考虑主账户的实际下单量了。多个子账户同时下单时,指令不能乱发,否则可能造成超买超卖。系统会按“子账户→主账户”的映射关系,把子账户的委托转换为带内部标记的主账户委托,再发送到柜台。
这里我踩过一个比较大的坑:重发。柜台接口有时会返回超时,但实际上单子已经进去了。如果你简单重发,就可能产生双倍仓位。解决方案是给每一笔委托生成全局唯一的业务编号,并在重发前先做一次状态查询,以查询结果为准。这个机制叫“查询确认再重发”,是实盘系统中必不可少的保护措施。
4. 功能清单与实际落地细节
4.1 账户管理功能:开子账户、入金出金、资金调拨
账户管理模块听起来简单,但细节特别多。先说开子账户。开一个子账户要设置的信息包括:账户名、初始资金、所属策略组、可交易品种列表、单笔手数上限、单日开仓次数上限、止损线、是否允许入金出金等。这个配置过程不能设计成一张大表单让用户从头填到尾,最好是先填必填项创建账户,后续其他参数默认继承组配置,个别账户再单独覆盖。
入金出金功能要有审批流。子账户入金不是交易员自己做主,而是要经过管理端审核。为什么?因为资金是从主账户划过去的,主账户的钱是全国粮票,一旦划错,影响的是所有子账户。审批流做简单一点就行:申请人提交,管理员确认,然后资金流水记账。重点是要在流水里记录申请人和审批人,出了纠纷可以查责任。
资金调拨是指某个子账户的多余资金调到另一个子账户。这种操作必须做二次校验,比如转出方的可用资金是否足够、转入方是否在正常状态。我在资金调拨这里加了“资金锁定”机制:发起调拨时先冻结转出方的对应金额,等调拨完成才解冻并记账,避免调拨过程中对方又把这笔钱下进去。
4.2 风险控制功能:事前、事中、事后三层拦截
分仓软件的风控功能一定要按时间维度分成三层来设计。事前风控在下单请求到达订单服务之前执行,它查的是“这一单能不能下”;事中风控以定时任务的方式运行,比如每隔三秒扫描所有子账户的持仓和资金,查的是“当前整体有没有超限”;事后风控是日终跑批,查的是“今天有没有违反规则”。
事前风控里面,除了前面说的资金校验和权限校验,我建议再加上“品种级风控”和“组合级风控”两层。品种级是说某个品种对这个子账户的持仓手数上限,组合级是考虑各品种相关性之后的总风险敞口上限。组合级风控比较复杂,需要持仓和行情数据配合,但在资管场景下非常值得做。
事中风控有一个容易忽视的动作:触发风控后除了拦截还要通知。系统要有消息推送机制,把风控命中结果推给管理员。管理员看到通知后,可以选择手动强平或临时调高限额。实测下来,相比发邮件,推送消息的效率高得多,风控人员几乎要秒回。
事后风控是冰冷的证据归档。每天收盘后,要生成绩效报表和风控日志,记录每条规则被触发的次数、每次触发涉及的单据、当时的权益和持仓等上下文。这个功能可能看起来不重要,但一旦遇到账户纠纷,这些日志就是唯一能说清楚事实的材料。
4.3 对账与清结算:日终跑批怎么做
对账清算是分仓软件里最需要耐心打磨的功能,它把一天的交易结果整理成让人信服的账目。跑批时间一般选在收盘后和结算价公布之后,因为此时持仓有了最终的结算依据。
跑批的第一步是核对主账户的成交记录和子账户的成交记录,确保每一笔子账户委托在主账户侧都有对应的成交。对不上的原因五花八门:柜台接口漏推送、网络中断导致的回执丢失、废单处理差异。因此对账必须支持按业务编号重拉,把漏掉的记录补回来。
第二步是计算每个子账户的当日盈亏。平仓盈亏按平仓价格与开仓价格之差计算,持仓盈亏按当日结算价与上一交易日结算价之差计算,再把手续费分摊到各子账户。这样每个子账户可以独立生成一份当日结算单,内容包括期初权益、出入金、盈亏、手续费、期末权益。
第三步是主账户层面的汇总校验。所有子账户的期末权益之和,加上主账户层面的净持仓盈亏和费用,应该等于主账户的实际权益。偏差在几分钱以内是正常,因为可能存在四舍五入差异;如果偏差超过了一块钱,就要逐笔排查。我建议把“汇总校验”放在跑批的最前面,先把大的对不上问题暴露出来,再深入细节找到差异点,这样可以节省不少排障时间。
5. 实战链路与经验复盘
5.1 一个下单请求的完整生命周期
我把一个子账户从发起到成交的完整链路串一遍,能帮助理解前面所有的设计。
交易员在终端上看到行情,点击买入开仓,选择子账户A,输入手数,点击下单。终端立刻调用订单服务的下单接口,带上子账户编号和委托参数。订单服务先做基础校验,校验通过后生成全局唯一的业务编号,并写入订单表的待报状态。
接着进入资金校验模块。系统读取子账户A的实时权益和当前保证金占用,预估这笔委托冻结的保证金,模拟计算新的可用资金。如果可用资金变为负数,拒绝下单并返回“资金不足,缺口多少钱”。这里必须用事务锁定账户记录,否则两个并发单子会同时通过校验,造成资金超用。
资金校验通过后进入风控服务。风控规则的执行顺序是有讲究的,我先校验账户级规则,再校验品种级规则,最后校验组合级规则,因为组合级计算最慢,放后面可以尽可能减少无用计算。全部通过后,委托进入发送队列。
指令发送服务将子账户委托转换为实际交易柜台指令,记录转换关系并推送柜台。柜台返回报单成功或拒绝后,系统更新订单状态,同时在资金流水里登记保证金冻结或解冻记录。委托成交后,柜台会推送成交回报,系统根据回报更新持仓和资金,并生成子账户成交记录。到这里,一次完整的下单链路结束。
5.2 常见的拦路问题与排查手册
在开发分仓软件的过程中,我整理了一张问题排查表,很多问题是业务上线后逐步暴露出来的,记录下来对后来人非常有用。
第一类问题是资金对不上。子账户的权益与主账户权益不一致,大多数原因是漏记了手续费或者浮动盈亏计算口径不一致。排查时要先从资金流水表重建一遍子账户权益,再对比主账户实际权益,差异往往出现在某个时间段的手续费缺失。解决方法是让柜台手续费回执和子账户手续费流水做严格的一对一关联。
第二类问题是委托状态卡死。某笔委托一直显示“待报”或“已报”,但柜台侧已经成交。这种情况基本是回执丢失或者顺序错乱。根治办法是增加定时对账任务,比如每三十秒拉取一次柜台的当日委托,与本地订单表做比对,发现差异自动修正。这个机制虽然增加了一点柜台压力,但换来的状态准确性非常值。
第三类问题是并发导致的资金超用。两个子账户同时下大单,在极端情况下可能出现校验时资金够、实际成交后资金为负。解决思路是在资金校验时加锁,锁的粒度是关键。我的实践是对“主账户”维度的资金记录加分布式锁,而不是对子账户加锁,因为多个子账户共用主账户资金,锁子账户解决不了根本问题。
第四类问题是夜盘切换的日期错乱。系统交易日期和自然日期不完全一致,夜盘属于下一个交易日。如果不处理,日终结算和报表统计会错位。处理办法是全局维护一个“交易日服务”,所有订单、流水都挂交易日期,用交易日期而不是自然日期做报表聚合。
5.3 几个让我印象深刻的工程细节
第一个是数据量增长的速度远比预期快。一个多品种活跃的团队,一天的委托记录就能轻松到几万笔,持仓快照也是每分钟在产生。如果实时表和归档表不做分区分表,三个月后查询就会明显变慢。一定要提前把清理和归档机制做好,别等到卡出问题再动手。
第二个是行情接入的重要性往往被低估。分仓软件里,风控模块需要实时行情来计算浮动盈亏和保证金占用,如果行情中断,风控很容易误判或漏判。我给行情模块加了双路接入,主用和备用自动切换。实际用下来,备用线路虽然平时用不上,但真到了主线路出问题的时候,唯一的存续希望就是它。
第三个是权限系统的细粒度问题。刚开始我们只有“允许交易品种、单笔手数、日亏损上限”这几项,后来业务方不断加需求,比如“某个子账户只允许平仓不允许开仓”“夜盘时段禁止新开仓但允许平仓”“不同子账户的费率不同”。权限系统如果一开始就设计成可扩展的规则结构,后续加需求会轻松很多。
第四个是监控告警。分仓软件作为一个实盘系统,必须有完善的监控体系。我做了三层告警:系统层监控进程和网络,业务层监控订单失败率和资金异常,风控层监控规则触发情况。告警渠道用群机器人推送,分不同的级别。有一次凌晨,正是靠告警发现了柜台连接断开,及时切换备用接入,没有影响客户交易。
6. 后续扩展的方向与一点个人体会
分仓软件做扎实之后,整个系统往量化方向扩展会顺手很多。子账户体系本身就是一套完美的策略隔离单元,你可以把每个子账户直接对应一个策略实例,把风险参数挂在子账户上,策略自动下单也走同一套订单服务和风控服务。这也是我当初选这套架构的一个重要原因。
如果后续还要做多主账户支持,架构层面要提前留好扩展点。现在主账户和子账户是强绑定,但如果业务扩张到不同账户归属不同实体时,就需要在主账户层引入“账户组”概念,把清算和风控的维度从主账户提升到账户组。这个改动不算小,但数据库层面加一张账户组表就能平滑过渡。
另外,移动端查询功能值得考虑。交易员不可能一直待在PC前,他们想知道当前持仓和权益时,手机端给一个简洁的查询入口就够了。实际开发中,我发现移动端查询和PC端查询的接口可以完全复用,只是展示层不同,成本并不会很高。
最后分享一点个人体会。写这类系统的代码不难,难的是把账务逻辑梳理清楚并保持敬畏。每一个数字背后都是真金白银,容不得半点马虎。我每次改资金相关的代码,都必须重新跑一遍完整的历史数据回放,确认账目平衡才敢上实盘。这种谨慎,不能丢。真要出问题,技术债可以慢慢还,账不平的信任债,可能永远还不清。