交易和簿记基本模型
交易和簿记基本模型涵盖了交易和簿记时发生的事件,其目的是:
- 准确的头寸
- 没有未解释的 PnL
- 生成 PnL 报告
每个 trader 都需要能够解释他们的 PnL(利润和损失)。例如,今天投资组合价值的 5% 增长是来自于现有头寸的价格变动还是新的交易活动的结果(或两者都是)?
什么是 Order?
Order 就是字面上的意思 - 是客户希望对某种产品进行买卖下新的订单。
这个动作类比于电商平台相当于电商收到客户的订单。电商在收到订单后需要查看订单内容确认交易商品,查询仓库是否有货等等;证券交易员收到订单后同样需要确认订单中的交易内容,根据合约内容检查合规,确认订单交易类型等等。
以简单的证券交易为例,以限价单购买 [email protected] 600519.SH 茅台,订单中至少应包含以下信息:
order = {
"order_book": "12345"
"instrument": "600519.SH",
"quantity": 1000,
"operation": "Buy; Limit; Fill or Kill",
"trade_date": "2022-02-02",
"others": "500 to sub-account I; 500 to sub-account II",
"fulfilled": false,
"created_at": "2022-02-02 14:30:23 HKT"
}
交易员收到该订单后,明白该客户想要以限价单全部成交或取消订单的方式交易 1000 股茅台,并且如果交易成功后将股票平均分配到两个子账户中。
其中 order_book
字段对应的为该客户某种类型的 Orders 的记账本,其代表了某种类型的 Orders 的集合。这个记账本的字段一般有
{ "book": {
"id": ": "12345",
"displayName": "Client A",
"description": "Client A Cash Equity",
"type": "HIGH_TOUCH",
...
}
其中的字段可根据业务要求高度定制,比如 type
字段可以定制为
- HIGH_TOUCH: 需要 trader 主动人工操作
- LOW_TOUCH: 半人工操作
- NO_TOUCH: 系统自动向交易所或者其他 broker 撮合订单
- DMA: 客户自己向交易所发送订单
从最简单的情况上来看,这为某一个 legal entity 提供了查看其名下所有 orders 的集合。
举个例子,机构客户 A 与一家 broker B 的下单系统通过 FIX 协议对接, A 客户下的 order 会首先在 B 的 order book 系统中对应 A 客户的 book 中出现并标记 fulfilled
为 false。系统根据 order 类型进行自动或者手动进行 Order Routing 到交易所或者其他 broker,通过 FAST 协议获取 Market Data, 并执行交易。
注意作为 broker B 不需要有 Order Matching Engine。关于 Order Matching Engine 可以参考
什么是 Trade?
Trade 就是成功成交后的 Order。以上面例子中的 Order 为例,假设 Trader 同意向客户 A 卖出 1000 600519.SH 并执行了交易 ,
tradeDetails = orderService.execute(order);
该交易的细节为如下数据结构
tradeDetails = [
{
"book_a": "Broker B Delta One",
"book_b": "Client A I",
"trader": "Sammy Bruce",
"tradeType": "SELL", // 从 book_a 的角度,一般 broker 总是把自己的 trading book 放在 book_a
"quantity": 500
"quantityUnit": "600519.SH"
"unitPrice": 1000
"unitCurrency": "RMB" // 交易货币
...
},
{
"book_a": "Broker B Delta One",
"book_b": "Client A II",
"trader": "Sammy Bruce",
"tradeType": "SELL", // 从 book_a 的角度,一般 broker 总是把自己的 trading book 放在 book_a
"quantity": 500
"quantityUnit": "600519.SH"
"unitPrice": 1000
"unitCurrency": "RMB" // 交易货币
...
},
]
什么是 Trade Book?
首先注意 Order Book 和 Trade Book 的区别:
- Order 总是由客户单方面发起的,同时它代表还未执行的交易,所以一般单边记账
- 而一笔 Trade 交易总是在两方之间执行的,这两方各自有一个账本,同时它代表已经执行的交易,从性质上比较重要,需要双边记账 (Double Entry Bookkeeping) 保证数据的准确性
一个 Trade Book 一般有以下属性:
- 名称和描述
- 账簿类型,例如
- trading book:与产生收入和 PnL 的交易员风险账户/利润中心有关
- customer book:与客户有关
- 负责账簿的交易员或柜台主管
- 公司(法律实体)
- 报告的货币:默认的结算货币
一个客户的每条 book record 至少有三种状态(同 cash ledger 蕾西): receivable, onhand, payable。
{ "book": {
"id": ": "123456",
"displayName": "Broker B Delta One",
"description": "Cash Equity",
"type": "Trading Book",
"trader": "Sammy Bruce",
"legal_entity": "Broker B HK",
"denominated": "USD",
...
}
Trade Book 的基本操作
在 Trade Book 中可以根据业务需要定制许多功能。
簿记 Booking
有了交易细节 tradeDetails 和记账本 trade books, 下一步就是对 trade 进行簿记,
trades = tradeService.book(tradeDetails);
在上面的例子中,由于需要将 1000 股分配到 Client A 名下的两个子账户中,总共会生成 4 条 trades,
Book Name: Broker B Delta One
Quantity: -500
UnitPrice: 1000
Instrument: 600519.SH
Book Name: Client A I
Quantity: 500
UnitPrice: 1000
Instrument: 600519.SH
Book Name: Broker B Delta One
Quantity: -500
UnitPrice: 1000
Instrument: 600519.SH
Book Name: Client A II
Quantity: 500
UnitPrice: 1000
Instrument: 600519.SH
交易修改了两个账本之间的头寸,一个账本增加,另一个账本减少买入/卖出的数量, 对两个账本的净影响应始终为零。
获取持仓 Retrieving Instruments
book("Broker B Delta One").instruments()
---
{ "name": "600519.SH", "price": 900,000, ...},
{ "name" "TSLA", "price": 541.21, ...}
...
计算头寸 Position Calculation
假设在交易前 Broker B Delta One 记账本中 600519.SH 头寸为 2000,
{ "book": "Broker B Delta One", "instrument": "600519.SH", "quantity": 2000, "price": 1,800,000, "trading_ccy": "RMB" }
那么交易之后则会变更为
book("Broker B Delta One").instrument("600519.SH").position()
---
{ "book": "Broker B Delta One", "instrument": "600519.SH", "quantity": 1000, "price": 900,000, "trading_ccy": "RMB"
"trades" [
{ "id:" 1, "quantity": 2000, "counterparty": "Broker C", "price": 1,800,000, ...},
{ "id:" 2, "quantity": -500, "counterparty": "Client A I", "price": 500,000, ...},
{ "id:" 3, "quantity": -500, "counterparty": "Client A II", "price": 500,000, ...}
]
}
注意这里的 price 为 price = sum {unit price of trade * quantity of trade} over the instrument
,同时 unit price = price / quantuty
。
计算 PnL
假设当前茅台价格为 980 RMB。
book("Broker B Ledger").realizedPnl() // or Closed PnL, 500,000 + 500,000 - 900,000,注意这应该在 Cash Ledger book 中计算
---
100,000 RMB
book("Broker B Delta One").unrealizedPnl() // or Open PnL, 980 * 1000 - 900,000
---
80,000 RMB
// PnL = realized PnL + UnrealizedPnL
---
180,000 RMB
其他簿记
Margin: Unrealized PnL = Instrument Unrealized PNL + Margin Loan Interest + Cash Dividend
Fully Funded: Unrealized PnL = Market Value + Dividend
Realized PnL 是从 cash ledger 中计算的
1, 2, 3 三条记录由 Transaction Event 生成。
- Cash Dividend event 在 ex date 生成,指明 settle date;ex date 簿记入 book; settle date 簿记入 ledger
- Stock Dividend event 在 ex date 生成,指明 settle date; ex date 簿记入 book
- Hedging Interest 在 pre reset date 生成,指明 reset date; pre reset date 簿记入 book, settle date 簿记入 ledger
注意 book record 的 Trade Date, Settle Date 等信息用于判断 receivable, onhand, payable 等状态。
- Margin Rebate: 与 instrument 持仓无关,只与 cash account 有关,应该簿记在 cash ledger 然后通过 event ID 和 Rebate Event 关联。