# PnL Spec
## 風險控管
目前只需要先實作底下幾個功能即可:
1. 限制 portfolio 只能 buy (sell-locked)
2. 限制 portfolio 只能 sell (buy-locked)
3. 限制 portfolio 不能 buy/sell (trade-locked)
4. 限制 Portfolio 在 Total PnL 達到一個數值的時候不能 buy/sell
這些功能都是沒有時間限制的, 直到 manager 重啟
以上四個功能的進階版就是限制到對某個 position, 例如不能 buy BTC, 那所有 btc/usdt, btc/eth, ... 的 buy order 都不能送
## PnL 基本概念
PnL (損益) 的基本組成:
1. Name/Id = Order/Quotation/Position/Portfolio/Account level
2. Bought Qty = Sum of buy orders ( Qty )
3. Bought Cost = Sum of buy orders ( Qty * Price + fee/commissions/spread )
4. Avg Bought Price = Bought Cost / Bought Qty
5. Sold Qty = Sum of sell orders ( Qty )
6. Sold Cost = Sum of sell orders ( Qty * Price - fee/commissions/spread )
7. Avg Sold Price = Sold Cost / Sold Qty
8. Total Qty = Bought Qty - Sold Qty
9. Total Cost = Sold Cost - Bought Cost
10. Mark Price
11. PnL = Mark Price * Total Qty - Total Cost
所以 PnL 是 Orders 與 Mark Prices (簡稱 Marks) 的函數 **PnL = f(orders, marks)**
在 order/quotation level, 只會有 orders, 是市場上 trade 來的
在 position/portfolio/account level, 會有 ledger (例如被空投, 收利息, 內部轉帳 ...etc.)
ledger 在 PnL 計算上可以等同 order (但 ledger trade 的資訊可能和 order 不同) 要算進來
ledger trade 的 volume = order qty
ledger 的 cost_basis = order price
ledger 的 fee/commissions/spread = order fee/commissions/spread
## 不同的 PnL
不同的 PnL 基本上就是對於 orders 的不同篩選方式, 以及可能使用不同的 mark price
基於時間切分:
1. incoming pnl = f(到昨晚 GMT 00:00 以前 opened orders, 現在的 price)
2. trading pnl = f(昨晚 GMT 00:00 到現在的 opened orders = 今天開到的 orders, 現在的 price)
3. optimistic pnl f(昨晚 GMT 00:00 到現在所有 opened/pending orders = 假設所有單都開的 orders, 現在的 price)
4. net pnl = incoming pnl + trading pnl
基於損益是否實現切分 (買了之後賣掉):
1. realized pnl = f(所有買->賣/賣->買的 orders) ※ realized 不用 mark price
2. unrealized pnl = f(剩下的買/賣的 orders, 現在的 price)
3. total pnl = realized pnl + unrealized pnl
基於損益切分是最困難的, 因為會跨 order, 例如:
1. buy 1 btc @ 30000 , cost 是 30002
2. buy 2 btc @ 30000, cost 是 60003 (個位數表示一些 fee)
3. sell 1.5 btc @ 40000, cost 是 59997 (個位數表示一些 fee)
如果選擇 FIFO, sell 1.5 btc 會對應到舊到新 buy 1 和 buy 2 中的 0.5 個, realized pnl = 59997 - 30002 - 0.5/2 * 60003 = 14994.25
如果選擇 LIFO, sell 1.5 btc 會對應到新到舊 buy 2 中的 1.5 個, realized pnl = 59997 - 1.5/2 * 60003 = 14994.75
現在的 price 可以每五分鐘更新一次
## PnL 的歷史走勢
PnL 的歷史走勢是被一系列的 Mark price 決定, mark price 不能簡單看成只是歷史 price
mark to market 是一種權力, 原則上在 mark price 確定的 24 小時內, manager 是可以更改他的, 直到 24 小時過去, manager 就不能更改
初期可以先簡單起見, 歷史 mark price 只需要存 daily 的 (GMT 00:00), 即時的 PnL 計算可以直接拿當前報價來算, 然後 manager 可以改最近一天的 daily 的 mark price
## Mark Price 的來源
原則上 Mark Price 需要來自一個穩定的地方, 例如 coinmarketcap, 但初期可以先給大家設置 mark from: [ Binance USDT pair ] 之類的, 用 BTC/USDT 來 mark BTC position, 通常來說, mark price 應該是類似 BTCUSD 這種, 用這個 price 去 mark BTC position, 而 BTC position 可能買賣來自 BTC/USDT, BTC/BUSD, BTC/USDC, BTC/ETH 這些地方
## PnL 的 quote currency 的選擇
如果有一個單是買賣在 BTC/ETH, 你應該要同時記錄當下的 ETH/USD 價格在這個 order 上, 方便換算, quote currency 的選擇就是前面的 mark from 的選擇
如果你選擇了 USDT pair 當作 quote currency, 那 USDC 也需要透握 USDC/USDT 算出 PnL, 而 USDC 可能來自於 Ledger trade, 所以 ledger trade 也是可能需要補當時的 mark price 上去
## 突然出現在 position 中 ledger trade 怎辦?
例如你突然被空投了 ETH, account 突然增加, 那就需要丟出一個 notification 說, account 的 position size 和系統的不同, 如果交易所也沒辦法撈到 ledger, 那就需要 manager 去手動登錄這筆 ledger trade: 該 position 的 qty, cost_basis, fee ...
## 總結
所以總共有 7 種 pnl 要算:
1. incoming pnl
2. trading pnl
3. optimisic pnl
4. net pnl
5. realized pnl
6. unrealized pnl
7. total pnl
這 7 種 pnl 要算在 order/quotation/position/portfolio/account 這些 level
realized pnl/unrealized pnl 只需要從 position level 開始算即可
portfolio, account level 應該只需要把 position level 的各項 PnL 加起來就好, 不應該再算
原則上 total pnl = net pnl, 但有時候可能會有一些誤差, 是 OK 的