|
1 | 1 | @inline function update_valuation!(acc::Account, pos::Position, close_price) |
2 | 2 | # update position valuation and account equity using delta of old and new value |
| 3 | + inst = pos.inst |
3 | 4 | new_pnl = calc_pnl_local(pos, close_price) |
4 | | - new_value = new_pnl |
| 5 | + if inst.settlement == SettlementStyle.Asset |
| 6 | + new_value = pos.quantity * close_price * inst.multiplier |
| 7 | + else |
| 8 | + new_value = new_pnl |
| 9 | + end |
5 | 10 | value_delta = new_value - pos.value_local |
6 | | - quote_cash_index = pos.inst.quote_cash_index |
| 11 | + quote_cash_index = inst.quote_cash_index |
7 | 12 | @inbounds acc.equities[quote_cash_index] += value_delta |
8 | 13 | pos.pnl_local = new_pnl |
9 | 14 | pos.value_local = new_value |
|
30 | 35 | commission::Price=0.0, # fixed commission in quote (local) currency |
31 | 36 | commission_pct::Price=0.0, # percentage commission of nominal order value, e.g. 0.001 = 0.1% |
32 | 37 | )::Trade{TTime,OData,IData} where {TTime<:Dates.AbstractTime,OData,IData,CData} |
| 38 | + inst = order.inst |
33 | 39 | # get quote asset index |
34 | | - quote_cash_index = order.inst.quote_cash_index |
| 40 | + quote_cash_index = inst.quote_cash_index |
35 | 41 |
|
36 | 42 | # positions are netted using weighted average price, |
37 | 43 | # hence only one static position per instrument is maintained |
38 | | - pos = get_position(acc, order.inst) |
| 44 | + pos = get_position(acc, inst) |
39 | 45 | pos_qty = pos.quantity |
40 | 46 |
|
41 | 47 | # set fill quantity if not provided |
42 | 48 | fill_qty = fill_qty > 0 ? fill_qty : order.quantity |
43 | 49 | remaining_qty = order.quantity - fill_qty |
44 | 50 |
|
45 | 51 | # calculate absolute paid commissions in quote currency |
46 | | - nominal_value = fill_price * abs(fill_qty) * order.inst.multiplier |
| 52 | + nominal_value = fill_price * abs(fill_qty) * inst.multiplier |
47 | 53 | commission += commission_pct * nominal_value |
48 | 54 |
|
49 | 55 | # realized P&L |
50 | 56 | realized_qty = calc_realized_qty(pos_qty, fill_qty) |
51 | | - realized_pnl = 0.0 |
| 57 | + realized_pnl_gross = 0.0 |
52 | 58 | if realized_qty != 0.0 |
53 | 59 | # order is reducing exposure (covering), calculate realized P&L |
54 | | - realized_pnl = (fill_price - pos.avg_price) * realized_qty |
55 | | - |
56 | | - # add realized P&L to account balance |
57 | | - @inbounds acc.balances[quote_cash_index] += realized_pnl |
| 60 | + realized_pnl_gross = (fill_price - pos.avg_price) * realized_qty * inst.multiplier |
| 61 | + end |
58 | 62 |
|
59 | | - # remove realized P&L from position P&L |
60 | | - pos.pnl_local -= realized_pnl |
61 | | - pos.value_local -= realized_pnl |
| 63 | + if inst.settlement == SettlementStyle.Asset |
| 64 | + cash_delta = -(fill_price * fill_qty * inst.multiplier) - commission |
| 65 | + else |
| 66 | + cash_delta = realized_pnl_gross - commission |
62 | 67 | end |
63 | | - realized_pnl -= commission |
| 68 | + @inbounds begin |
| 69 | + acc.balances[quote_cash_index] += cash_delta |
| 70 | + acc.equities[quote_cash_index] += cash_delta |
| 71 | + end |
| 72 | + realized_pnl = realized_pnl_gross - commission |
64 | 73 |
|
65 | 74 | # generate trade sequence number |
66 | 75 | tid = tid!(acc) |
|
104 | 113 | # update position quantity |
105 | 114 | pos.quantity = new_exposure |
106 | 115 |
|
107 | | - # subtract paid commissions from account balance and equity |
108 | | - @inbounds acc.balances[quote_cash_index] -= commission |
109 | | - @inbounds acc.equities[quote_cash_index] -= commission |
110 | | - |
111 | | - # update P&L of position and account equity (w/o commissions, already accounted for) |
| 116 | + # update P&L of position and account equity |
112 | 117 | update_pnl!(acc, pos, fill_price) |
113 | 118 |
|
114 | 119 | push!(acc.trades, trade) |
|
0 commit comments