Client Onboarding
ODTS 13 — 客户上线:从电话到第一笔交易
业务流程
客户在交易之前必须经过上线 (onboarding) 流程:
第 1 步:销售找到客户
第 2 步:KYC (Know Your Client) — 了解客户身份和资金来源
第 3 步:ISDA/CSA 谈判 — 管辖 OTC 交易的法律协议
第 4 步:授信额度审批 — 交易台可以承担多少敞口
第 5 步:运营设置 — 客户代码、联系人名单、交割指令
第 6 步:系统设置 — 添加至系统、分配角色/权限
第 7 步:第一笔交易
时间线: 2 周(理想情况)到 6 个月(复杂的中资机构客户)。
延迟上线的机会成本: 一个机构客户准备入场做 1 亿 RMB TRS(100bp spread),年化收入贡献约 100 万 RMB。如果上线拖了 3 个月(常见的中资机构走合规审批速度),交易台损失 2 个月的交易时间 ≈ 17 万 RMB。一年 10 个这样的新客户,就是 170 万的机会成本。更糟的是,有些客户因为上线太慢直接就走了——销售口中”客户等不了,去了 XYZ 证券”的故事,每个销售都能讲两三个。
系统在哪里介入
系统参与第 5 步和第 6 步:
系统不做:
- KYC(独立的合规系统)
- ISDA/CSA 谈判(Word 文档、邮件)
系统做:
- 客户主数据(名称、代码、联系人)
- 授信额度跟踪
- 交割指令 (settlement instructions)
- 交易簿记权限控制
客户在系统中如何表示
客户记录
ClientController.java
一个客户在系统中:
clientId: "CLT0001"
shortName: "UBP_HK" (内部讨论时用)
legalName: "Union Bancaire Privée, Hong Kong Branch"
clientType: "PRIVATE_BANK" (用于保证金规则和报告)
riskRating: "A" (A/B/C — 驱动 ISDA CSA 保证金阈值)
creditLimit: 500,000,000 (RMB — 最大敞口)
客户代码
一个客户有多个不同用途的代码:
clientId: "CLT0001"
├── isdaMasterAgreement: "ISDA-CLT-0001-2018" (法律文件引用)
├── settlementInstructions:
│ ├── CNY: "BOC SHANGHAI, ACC 12345678"
│ └── USD: "CITI HK, ACC 87654321"
├── fixingsSources:
│ └── CNY: "CFETS 4:30 PM"
└── clientContact:
├── trading: "trader@client.com" (交易确认发送至此)
├── operations: "ops@client.com" (追保通知发送至此)
└── compliance: "compliance@client.com"
代码位置:
eds-web-app/src/com/cicc/edsBoot/dao/ClientDao.java
ContractClientInfo 表
系统不记录什么
系统的客户模型很薄。它不知道:
- 客户的实益拥有人是谁(KYC 详情在合规系统)
- 客户的投资策略是什么(销售知道,系统不知道)
- 客户以前是否违约过(风控知道,系统不会标记)
- 客户和哪些其他交易台交易(外汇台、固收台各有一套系统)
缺口: 如果客户 A 在外汇交易上违约(在其他系统簿记),股权交易台不知道。我们系统中的授信额度没有变。违约后的第一笔交易可能超过实际风险承受能力。这个缺口存在是因为系统之间不共享交易对手数据。
实际案例——信用风险盲区: 某年,一个机构客户在另一个交易台的外汇 NDF 上发生了交割违约。外汇台暂停了该客户的交易。但股权衍生品交易台不受影响——因为两个交易台的授信系统相互独立。该客户的股权 TRS 敞口在违约消息传出后不仅没有被冻结,反而因为在系统层面仍被视为”正常”,销售又撮合了两笔新交易。直到月底风控汇总报表时,才发现该客户的总敞口(外汇 + 股权)已超过公司层面的授信上限。这个”系统隔阂”导致超额敞口维持了整整 3 周才被发现。
客户发起申请 (Counterparty Apply) 工作流
新客户上线通过交易对手申请流程 (Counterparty Apply) 驱动。这个流程在系统中有专门的收件箱 (Inbox) 机制:
counterpartyApply 状态流转:
DRAFT(草稿)
→ SUBMITTED(已提交)
→ 合规反洗钱通过 (CPAML PASS, status=27) → 授信审批
→ 合规反洗钱拒绝 (CPAML REJECT, status=28) → 退回
→ 合规反洗钱回退 (CPAML RETURN, status=29) → 修改后重提
→ 授信审批通过 → 系统设置完成 → 客户上线
数据库中通过 EDS_COUNTERPARTYAPPLY_INBOX 全局常量配置收件箱类型,EDS_ELEMENTDICT_INPUTTYPE 定义输入类型(如”日期列表”)。合规反洗钱检查是上线流程中的第一个硬关卡——系统通过 Inbox 机制将申请推送到合规团队的待办事项列表中。
KYC 与 AML
KYC/AML 检查不在 ODTS 系统中完成。合规团队使用独立的系统进行客户尽职调查:
ODTS 的角色:
发起申请 → 发送到合规 Inbox → 等待合规结果
合规通过 → 继续上线流程
合规拒绝 → 终止上线流程
合规的角色:
接收 ODTS 推送的申请
在独立系统中进行背景调查
将结果反馈到 ODTS Inbox(通过/拒绝/回退)
但有一个整合点:EDS_COUNTERPARTYAPPLY_INBOX 配置了 CPAML 作为收件箱类型,意味着 ODTS 通过这个 Inbox 机制与合规系统集成——ODTS 发送申请,合规操作后更新状态码。
结算指令——一个小失误的放大效应
客户上线流程中最容易被忽视但代价最高的细节是结算指令 (settlement instructions) 的准确性。
结算指令告诉系统:当你需要从这个客户收钱或付钱时,资金应该走哪家银行、哪个账号、哪个 SWIFT 代码。如果这个信息错了,后果很直接:
场景:客户入金 1000 万 RMB 作为保证金
运营按系统记录的结算指令发了付款指示
银行按账号处理 → 资金去了另一个客户的账户
发现错误 → 联系银行追回 → 银行需要客户授权 → 3-5 个工作日
这 3-5 天里,客户的保证金不足
交易台不能开新仓,或者需要临时降低信用额度
这种结算指令错误的常见原因:
- 客户提供了新账号,但邮件被销售转发时遗漏了附件(每年至少 1–2 次)
- 运营手动录入时抄错了一位数字(每年 2–3 次,但大部分被银行端的风控拦截)
- 客户更换了结算银行,但没有正式通知(占比较小,但发生时最棘手)
真实案例——账号抄错一位数: 某年,运营录入某客户的 USD 结算账号时,28 位账号的最后一位抄错了。第一笔 500 万美元的入金因此失败,银行在 2 个小时后返回”账号不存在”的错误。运营花了 2 小时核实、更正、重新发送。当天晚些时候客户说他们其实已经更改了收款行——但只通知了销售,销售忘了转给运营。这个失误总耗时 4 小时,涉及 3 个人(运营 × 2、销售 × 1),但核心问题是流程本身——没有”客户结算指令变更必须通过正式渠道”的硬性规定。
客户门户 (Client Portal)
目前状态:无门户
客户目前没有自助门户。他们通过以下方式看到自己的数据:
1. 月度客户账单 (PDF)
生成:eds-web-app
模板:Word (.docx) 通过 Apache POI 生成
发送:运营人工发送(没有自动投递)
2. 投资组合报告 (Excel)
生成:eds-web-app
格式:按客户定制的 Excel
频率:头部 20 家客户每日发送,其他每周
3. 追保通知 (邮件/电话)
生成:hedging-as 保证金引擎
发送:运营(邮件模板)
尚未构建:
- 客户门户(客户网页端查看头寸)
- 自动报告投递
- 供客户系统直接拉取数据的 API
这样做的影响:2023 年交易台花了 1.5 个全职员工的人力来回答客户的持仓和保证金问题。一个客户门户可以节省这笔成本,但从未被优先于创收功能。
这 1.5 个人的工作量拆解:
- 每天约 10–15 个客户邮件/电话问”我现在的 P&L 是多少?“——客户看不到系统,只能问。每个回答需要运营查系统、写邮件、发出去,平均 10 分钟。
- 每天 3–5 个追保相关问题——“为什么保证金涨了?""我还有多少额度?“平均 15 分钟。
- 每周 2–3 次定制报告请求——客户要某个特定时间范围的交易明细,运营手动从系统导出 Excel,调整格式,发出去。每次 30–60 分钟。
- 每月初集中发送客户账单——运营花 2–3 天生成和发送 50+ 份 PDF 客户账单。
这些工作每一个单独看都不大,但加起来每年就是 1.5 个人的全部时间。交易台的人工成本是 50–80 万/人/年,所以回答客户问题这件事本身的直接成本就是 75–120 万/年。还没有算客户的等待体验和销售因此花在安抚客户上的时间。
Protobuf 客户端接口
虽然没有客户门户,但系统通过 Protobuf 协议向外部系统暴露了一些客户端接口:
MsgGwClientInfo.proto — 客户端信息网关消息
MsgClientLogin.proto — 客户端登录
MsgClientLoginInfo.proto — 客户端登录信息
MsgClientResetPwd.proto — 客户端密码重置
MsgSwapClientList.proto — 互换客户端列表
这些接口服务于内部客户端(如 FUXI 前台系统),而非终端零售客户。tradedesign/gateway/msg/MsgGwClientInfo.proto 和 tradedesignapp/gateway/msg/MsgGwClientInfo.proto 两处有重复定义——这是网关模块与交易设计模块之间的接口定义复制问题。
CRM 功能
ODTS 没有内置 CRM (客户关系管理)。客户联系信息存储在 ContractClientInfo 表中,但管理系统是:
功能缺失:
- 客户互动历史(没有电话记录、会议纪要)
- 客户生命周期管理(没有"沉睡客户"标记)
- 客户分群和标签(没有按策略分组)
- 销售业绩追踪(没有按客户统计 P&L)
这意味着:销售团队使用 Excel 跟踪客户关系,与交易系统物理隔离。如果需要回答”招商银行这个月给我们贡献了多少收入?“,需要从交易系统导出 P&L 数据,到 Excel 中按客户汇总。
ISDA/CSA 工作流
ISDA — International Swaps and Derivatives Association 主协议。它是 OTC 衍生品交易的法律框架。
CSA — Credit Support Annex(信用支持附件)。它定义了如何交换保证金 (collateral)。
影响系统的关键 CSA 条款:
- Threshold: 低于此额免交保证金(如 5000 万 RMB)
- Minimum Transfer Amount: 最小追保金额(如 100 万 RMB)
- Rounding: 保证金取整到最近的 1 万
- Eligible Collateral: 什么可以作为保证金(仅现金?国债?)
- Haircuts: 担保品的折扣率(如国债打 95 折)
在系统中:
eds-web-app/src/com/cicc/edsBoot/dao/CsaDao.java
ContractCsaInfo 表
字段:
threshold, minTransferAmount, rounding
eligibleCollateral (枚举: CASH, GOVT_BOND, STOCK, LETTER_OF_CREDIT)
haircutPercent
系统根据 CSA 条款计算追保。但如果系统中的 CSA 没有更新(如手动录入的字段过期了),追保金额可能不对。
“纸面协议”问题
一半的客户的 CSA 条款从来没有被正确地录入系统。
为什么: 法务团队用 Word 谈判 CSA。运营团队手动将条款录入系统。交易员也有自己的理解。这三个版本经常不一致。
法务的 CSA(签署文件):
Threshold: 5000 万 RMB
MTA: 100 万 RMB
Rounding: 1 万
系统的 CSA(数据录入):
Threshold: 4500 万 RMB (笔误——有人录入了 45 而不是 50)
MTA: 100 万 RMB
Rounding: 1 万
交易员的记忆:
Threshold: 5000 万 RMB
MTA: 100 万 RMB
Rounding: 1 万
每日追保使用系统中(错误的)CSA。客户收到 4500 万的追保通知而不是 5000 万。客户打电话给运营。运营花了 30 分钟找出原因。
修复方案(从未实现): “CSA 对账”流程——每月将法律 CSA 与系统 CSA 对比一次,标记所有差异。
此类问题的累积成本: 系统 CSA 与法律 CSA 不一致的情况在运营中出现的频率大概是每月 1–2 次。每次的处理流程是:客户收到追保通知后有疑问 → 客户致电运营 → 运营查找纸质 CSA 对比系统数据 → 发现差异 → 手动修正系统 → 重新生成追保通知。一次处理 30–60 分钟。一个月就是 30–120 分钟。一年 10–24 次差异 = 运营 5–24 小时的处理时间。时间本身不多,但每次差异都让客户感到系统不可靠——客户信任的消耗是线性累积的,而信任崩塌是瞬间的。
客户 P&L
系统通过 ClientTradePnl 模型跟踪客户级别的 P&L:
eds-utility/src/com/domian/ClientTradePnl.java
extends TradePnl
这个类扩展了通用 P&L 模型,增加了客户维度。ClientTradePnlService 提供按客户汇总 P&L 的功能。
但 P&L 是按客户汇总的,而不是按”交易员-客户”维度。如果一个交易员管理多个客户,系统无法区分哪个客户贡献了多少收入。这对于销售激励(谁带来最多收入?)和客户盈利能力分析(哪个客户成本最高?)都是关键缺口。
一个实际影响: 某次,管理团队要求分析”哪些客户在盈亏平衡线以下”——即扣除融资成本和运营成本后,哪些客户是亏钱的。因为系统不按客户维护运营成本(如这个客户每天产生多少对账工作量),分析团队只能手动估算:拿 Excel 导出每个客户的 P&L,然后按交易笔数平均分摊运营成本。这个过程花了数据分析师 3 天。结果发现有两个中小客户,交易量不大但运营成本特别高(因为它们的结算指令经常变,每次都需要人工更新),实际上在亏损。但因为没有系统层面的客户盈利分析,这两个客户一直没有被标记为”需重新定价”。
关键文件
| 组件 | 路径 |
|---|---|
| 客户 DAO | eds-web-app/src/.../dao/ClientDao.java |
| CSA DAO | eds-web-app/src/.../dao/CsaDao.java |
| 客户信息表 | ContractClientInfo |
| CSA 信息表 | ContractCsaInfo |
| CPAML 收件箱 | EDS_COUNTERPARTYAPPLY_INBOX(全局常量) |
| CPAML 迁移脚本 | eds-web-app/db/EDS/arch/V1.3/EDS20170412130001_INSERT_GC_FOR_CPAML.sql |
| 客户 P&L 模型 | eds-utility/src/.../domian/ClientTradePnl.java |
| 客户 P&L 服务 | eds-utility/src/.../service/ClientTradePnlService.java |
| 客户登录 Proto | tradedesign/gateway/msg/MsgClientLogin.proto |
| 客户信息 Proto | tradedesign/gateway/msg/MsgGwClientInfo.proto |
| 客户信息 Proto (app) | tradedesignapp/gateway/msg/MsgGwClientInfo.proto |
业务影响: 客户上线是系统流程和人工流程的混合体。系统管了客户主数据和信用额度,但 KYC 在外部系统、ISDA 谈判在 Word 文档里、客户门户不存在。1.5 个全职人力花在回答客户问题上——这是一笔可以自动化但未被优先考虑的成本。