1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/******************************************************************************
Author: Joaquín Béjar García
Email: jb@taunais.com
Date: 15/9/25
******************************************************************************/
use crate::model::instrument::InstrumentKind;
use crate::model::order::OrderSide;
use pretty_simple_display::{DebugPretty, DisplaySimple};
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
/// Trade execution
#[skip_serializing_none]
#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
pub struct TradeExecution {
/// Trade amount
pub amount: f64,
/// Trade direction (buy/sell)
pub direction: String,
/// Trading fee paid
pub fee: f64,
/// Currency of the trading fee
pub fee_currency: String,
/// Index price at execution time
pub index_price: f64,
/// Name of the traded instrument
pub instrument_name: String,
/// Implied volatility (for options)
pub iv: Option<f64>,
/// User-defined label for the trade
pub label: String,
/// Liquidity type (maker/taker)
pub liquidity: String,
/// Mark price at execution time
pub mark_price: f64,
/// Matching engine identifier
pub matching_id: Option<String>,
/// Order ID that generated this trade
pub order_id: String,
/// Type of the order that generated this trade
pub order_type: String,
/// Original order type before modifications
pub original_order_type: Option<String>,
/// Execution price
pub price: f64,
/// Whether this was a self trade
pub self_trade: bool,
/// Current state of the trade
pub state: String,
/// Price tick direction (1=up, -1=down, 0=no change)
pub tick_direction: i32,
/// Execution timestamp
pub timestamp: u64,
/// Unique trade identifier
pub trade_id: String,
/// Trade sequence number
pub trade_seq: u64,
/// Underlying asset price (for derivatives)
pub underlying_price: Option<f64>,
}
/// User trade information
#[skip_serializing_none]
#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
pub struct UserTrade {
/// Trade amount in base currency units
pub amount: f64,
/// Whether the order was placed via API
pub api: Option<bool>,
/// Number of contracts traded
pub contracts: Option<f64>,
/// Trade direction (buy/sell)
pub direction: String,
/// Trading fee paid
pub fee: f64,
/// Currency of the trading fee
pub fee_currency: String,
/// Index price at execution time
pub index_price: f64,
/// Name of the traded instrument
pub instrument_name: String,
/// Implied volatility (for options)
pub iv: Option<f64>,
/// User-defined label for the trade
pub label: Option<String>,
/// Liquidity type (M=maker, T=taker)
pub liquidity: String,
/// Mark price at execution time
pub mark_price: f64,
/// Matching engine identifier
pub matching_id: Option<String>,
/// Whether Market Maker Protection was active
pub mmp: Option<bool>,
/// Order ID that generated this trade
pub order_id: String,
/// Type of the order that generated this trade
pub order_type: String,
/// Original order type before modifications
pub original_order_type: Option<String>,
/// Whether this was a post-only order
pub post_only: Option<bool>,
/// Execution price
pub price: f64,
/// Profit or loss from this trade
pub profit_loss: Option<f64>,
/// Whether this was a reduce-only order
pub reduce_only: Option<bool>,
/// Whether this trade was risk reducing
pub risk_reducing: Option<bool>,
/// Whether this was a self trade
pub self_trade: bool,
/// Current state of the trade
pub state: String,
/// Price tick direction (1=up, -1=down, 0=no change)
pub tick_direction: i32,
/// Execution timestamp (milliseconds since UNIX epoch)
pub timestamp: u64,
/// Unique trade identifier
pub trade_id: String,
/// Trade sequence number
pub trade_seq: u64,
/// Underlying asset price (for derivatives)
pub underlying_price: Option<f64>,
/// User ID who executed the trade
pub user_id: Option<u64>,
}
/// Last trade
#[skip_serializing_none]
#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
pub struct LastTrade {
/// Trade amount
pub amount: f64,
/// Trade direction (buy/sell)
pub direction: String,
/// Index price at execution time
pub index_price: f64,
/// Name of the traded instrument
pub instrument_name: String,
/// Implied volatility (for options)
pub iv: Option<f64>,
/// Liquidity information
pub liquid: Option<String>,
/// Execution price
pub price: f64,
/// Price tick direction (1=up, -1=down, 0=no change)
pub tick_direction: i32,
/// Execution timestamp
pub timestamp: u64,
/// Unique trade identifier
pub trade_id: String,
/// Trade sequence number
pub trade_seq: u64,
}
/// Liquidity type enumeration
#[derive(DebugPretty, DisplaySimple, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Liquidity {
/// Maker (provided liquidity)
#[serde(rename = "M")]
Maker,
/// Taker (consumed liquidity)
#[serde(rename = "T")]
Taker,
/// Mixed (both maker and taker in same trade)
#[serde(rename = "MT")]
Mixed,
}
/// Trade execution information
#[skip_serializing_none]
#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
pub struct Trade {
/// Unique trade identifier
pub trade_id: String,
/// Instrument name
pub instrument_name: String,
/// Order ID that generated this trade
pub order_id: String,
/// Trade direction (buy/sell)
pub direction: OrderSide,
/// Trade amount
pub amount: f64,
/// Execution price
pub price: f64,
/// Trade timestamp
pub timestamp: i64,
/// Fee amount
pub fee: f64,
/// Fee currency
pub fee_currency: String,
/// Liquidity type (maker/taker)
pub liquidity: Liquidity,
/// Mark price at time of trade
pub mark_price: f64,
/// Index price at time of trade
pub index_price: f64,
/// Instrument kind
pub instrument_kind: Option<InstrumentKind>,
/// Trade sequence number
pub trade_seq: Option<u64>,
/// User role in the trade
pub user_role: Option<String>,
/// Whether this is a block trade
pub block_trade: Option<bool>,
/// Underlying price (for options)
pub underlying_price: Option<f64>,
/// Implied volatility (for options)
pub iv: Option<f64>,
/// Label associated with the order
pub label: Option<String>,
/// Profit and loss from this trade
pub profit_loss: Option<f64>,
/// Tick direction
pub tick_direction: Option<i32>,
/// Whether this trade was self-traded
pub self_trade: Option<bool>,
}
impl Trade {
/// Calculate the notional value of the trade
pub fn notional_value(&self) -> f64 {
self.amount * self.price
}
/// Check if this was a maker trade
pub fn is_maker(&self) -> bool {
matches!(self.liquidity, Liquidity::Maker | Liquidity::Mixed)
}
/// Check if this was a taker trade
pub fn is_taker(&self) -> bool {
matches!(self.liquidity, Liquidity::Taker | Liquidity::Mixed)
}
/// Check if this is a buy trade
pub fn is_buy(&self) -> bool {
self.direction == OrderSide::Buy
}
/// Check if this is a sell trade
pub fn is_sell(&self) -> bool {
self.direction == OrderSide::Sell
}
/// Get fee as percentage of notional
pub fn fee_percentage(&self) -> f64 {
if self.notional_value() != 0.0 {
(self.fee / self.notional_value()) * 100.0
} else {
0.0
}
}
}
/// Trade statistics
#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
pub struct TradeStats {
/// Total number of trades
pub count: u64,
/// Total volume
pub volume: f64,
/// Total fees paid
pub total_fees: f64,
/// Average price
pub avg_price: f64,
/// Profit and loss
pub pnl: f64,
/// Number of winning trades
pub winning_trades: u64,
/// Number of losing trades
pub losing_trades: u64,
}
impl TradeStats {
/// Create empty trade statistics
pub fn new() -> Self {
Self {
count: 0,
volume: 0.0,
total_fees: 0.0,
avg_price: 0.0,
pnl: 0.0,
winning_trades: 0,
losing_trades: 0,
}
}
/// Calculate win rate as percentage
pub fn win_rate(&self) -> f64 {
if self.count > 0 {
(self.winning_trades as f64 / self.count as f64) * 100.0
} else {
0.0
}
}
}
impl Default for TradeStats {
fn default() -> Self {
Self::new()
}
}
/// Trade allocation structure for Block RFQ pre-allocation
#[skip_serializing_none]
#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
pub struct TradeAllocation {
/// Amount allocated to this user
pub amount: f64,
/// Optional client allocation info for brokers
pub client_info: Option<ClientInfo>,
/// Fee for the allocated part of the trade
pub fee: f64,
/// User ID to which part of the trade is allocated. For brokers the User ID is obstructed.
pub user_id: u64,
}
/// Client information structure for broker allocations
#[skip_serializing_none]
#[derive(DebugPretty, DisplaySimple, Clone, Serialize, Deserialize)]
pub struct ClientInfo {
/// ID of a client; available to broker. Represents a group of users under a common name.
pub client_id: u64,
/// ID assigned to a single user in a client; available to broker.
pub client_link_id: u64,
/// Name of the linked user within the client; available to broker.
pub name: String,
}