kiteconnect_async_wasm/models/orders/
order_history.rs

1use super::OrderStatus;
2use crate::models::common::{Exchange, OrderType, Product, TransactionType, Validity};
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6/// Trade data structure
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct Trade {
9    /// Trade ID
10    #[serde(rename = "trade_id")]
11    pub trade_id: String,
12
13    /// Order ID
14    #[serde(rename = "order_id")]
15    pub order_id: String,
16
17    /// Exchange order ID
18    #[serde(rename = "exchange_order_id")]
19    pub exchange_order_id: String,
20
21    /// Trading symbol
22    #[serde(rename = "tradingsymbol")]
23    pub trading_symbol: String,
24
25    /// Exchange
26    pub exchange: Exchange,
27
28    /// Instrument token
29    #[serde(rename = "instrument_token")]
30    pub instrument_token: u32,
31
32    /// Product type
33    pub product: Product,
34
35    /// Average price at which the trade was executed
36    #[serde(rename = "average_price")]
37    pub average_price: f64,
38
39    /// Quantity traded
40    pub quantity: u32,
41
42    /// Fill timestamp
43    #[serde(rename = "fill_timestamp")]
44    pub fill_timestamp: DateTime<Utc>,
45
46    /// Exchange timestamp
47    #[serde(rename = "exchange_timestamp")]
48    pub exchange_timestamp: DateTime<Utc>,
49
50    /// Transaction type (BUY/SELL)
51    #[serde(rename = "transaction_type")]
52    pub transaction_type: TransactionType,
53}
54
55/// Order history entry
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct OrderHistoryEntry {
58    /// Account ID
59    pub account_id: String,
60
61    /// Order ID
62    #[serde(rename = "order_id")]
63    pub order_id: String,
64
65    /// Exchange order ID
66    #[serde(rename = "exchange_order_id")]
67    pub exchange_order_id: Option<String>,
68
69    /// Parent order ID
70    #[serde(rename = "parent_order_id")]
71    pub parent_order_id: Option<String>,
72
73    /// Order status
74    pub status: OrderStatus,
75
76    /// Status message
77    #[serde(rename = "status_message")]
78    pub status_message: Option<String>,
79
80    /// Raw status message from exchange
81    #[serde(rename = "status_message_raw")]
82    pub status_message_raw: Option<String>,
83
84    /// Order timestamp
85    #[serde(rename = "order_timestamp")]
86    pub order_timestamp: DateTime<Utc>,
87
88    /// Exchange timestamp
89    #[serde(rename = "exchange_timestamp")]
90    pub exchange_timestamp: Option<DateTime<Utc>>,
91
92    /// Exchange update timestamp
93    #[serde(rename = "exchange_update_timestamp")]
94    pub exchange_update_timestamp: Option<DateTime<Utc>>,
95
96    /// Trading symbol
97    #[serde(rename = "tradingsymbol")]
98    pub trading_symbol: String,
99
100    /// Exchange
101    pub exchange: Exchange,
102
103    /// Instrument token
104    #[serde(rename = "instrument_token")]
105    pub instrument_token: u32,
106
107    /// Order type
108    #[serde(rename = "order_type")]
109    pub order_type: OrderType,
110
111    /// Transaction type
112    #[serde(rename = "transaction_type")]
113    pub transaction_type: TransactionType,
114
115    /// Validity
116    pub validity: Validity,
117
118    /// Product
119    pub product: Product,
120
121    /// Quantity
122    pub quantity: u32,
123
124    /// Disclosed quantity
125    #[serde(rename = "disclosed_quantity")]
126    pub disclosed_quantity: u32,
127
128    /// Price
129    pub price: f64,
130
131    /// Trigger price
132    #[serde(rename = "trigger_price")]
133    pub trigger_price: f64,
134
135    /// Average price
136    #[serde(rename = "average_price")]
137    pub average_price: f64,
138
139    /// Filled quantity
140    #[serde(rename = "filled_quantity")]
141    pub filled_quantity: u32,
142
143    /// Pending quantity
144    #[serde(rename = "pending_quantity")]
145    pub pending_quantity: u32,
146
147    /// Cancelled quantity
148    #[serde(rename = "cancelled_quantity")]
149    pub cancelled_quantity: u32,
150
151    /// Market protection
152    #[serde(rename = "market_protection")]
153    pub market_protection: f64,
154
155    /// Tag
156    pub tag: Option<String>,
157
158    /// GUID
159    pub guid: String,
160
161    /// Variety (regular, bo, co, amo)
162    pub variety: Option<String>,
163}
164
165/// Order history container
166#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct OrderHistory {
168    /// List of order history entries
169    pub entries: Vec<OrderHistoryEntry>,
170}
171
172/// Trade history container
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct TradeHistory {
175    /// List of trades
176    pub trades: Vec<Trade>,
177}
178
179/// Order book (list of all orders)
180#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct OrderBook {
182    /// List of orders
183    pub orders: Vec<super::Order>,
184}
185
186/// Trade book (list of all trades)
187#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct TradeBook {
189    /// List of trades
190    pub trades: Vec<Trade>,
191}
192
193/// Order placement response
194#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct OrderResponse {
196    /// Order ID assigned by the system
197    #[serde(rename = "order_id")]
198    pub order_id: String,
199}
200
201impl Trade {
202    /// Calculate the total value of the trade
203    pub fn total_value(&self) -> f64 {
204        self.average_price * self.quantity as f64
205    }
206
207    /// Check if this is a buy trade
208    pub fn is_buy(&self) -> bool {
209        self.transaction_type == TransactionType::BUY
210    }
211
212    /// Check if this is a sell trade
213    pub fn is_sell(&self) -> bool {
214        self.transaction_type == TransactionType::SELL
215    }
216}
217
218impl OrderHistory {
219    /// Get the latest status of the order
220    pub fn latest_status(&self) -> Option<&OrderStatus> {
221        self.entries
222            .iter()
223            .max_by_key(|entry| &entry.order_timestamp)
224            .map(|entry| &entry.status)
225    }
226
227    /// Get all status transitions
228    pub fn status_transitions(&self) -> Vec<(&OrderStatus, &DateTime<Utc>)> {
229        let mut entries: Vec<_> = self
230            .entries
231            .iter()
232            .map(|entry| (&entry.status, &entry.order_timestamp))
233            .collect();
234
235        entries.sort_by_key(|(_, timestamp)| *timestamp);
236        entries
237    }
238
239    /// Check if order was ever rejected
240    pub fn was_rejected(&self) -> bool {
241        self.entries
242            .iter()
243            .any(|entry| entry.status == OrderStatus::Rejected)
244    }
245
246    /// Check if order was cancelled
247    pub fn was_cancelled(&self) -> bool {
248        self.entries
249            .iter()
250            .any(|entry| entry.status == OrderStatus::Cancelled)
251    }
252
253    /// Get total filled quantity across all fills
254    pub fn total_filled_quantity(&self) -> u32 {
255        self.entries
256            .iter()
257            .map(|entry| entry.filled_quantity)
258            .max()
259            .unwrap_or(0)
260    }
261}
262
263impl TradeHistory {
264    /// Calculate total traded value
265    pub fn total_value(&self) -> f64 {
266        self.trades.iter().map(|trade| trade.total_value()).sum()
267    }
268
269    /// Calculate total quantity traded
270    pub fn total_quantity(&self) -> u32 {
271        self.trades.iter().map(|trade| trade.quantity).sum()
272    }
273
274    /// Calculate average price across all trades
275    pub fn average_price(&self) -> f64 {
276        let total_value = self.total_value();
277        let total_quantity = self.total_quantity();
278
279        if total_quantity > 0 {
280            total_value / total_quantity as f64
281        } else {
282            0.0
283        }
284    }
285
286    /// Get trades by transaction type
287    pub fn trades_by_type(&self, transaction_type: TransactionType) -> Vec<&Trade> {
288        self.trades
289            .iter()
290            .filter(|trade| trade.transaction_type == transaction_type)
291            .collect()
292    }
293
294    /// Get buy trades
295    pub fn buy_trades(&self) -> Vec<&Trade> {
296        self.trades_by_type(TransactionType::BUY)
297    }
298
299    /// Get sell trades
300    pub fn sell_trades(&self) -> Vec<&Trade> {
301        self.trades_by_type(TransactionType::SELL)
302    }
303}
304
305impl OrderBook {
306    /// Get orders by status
307    pub fn orders_by_status(&self, status: OrderStatus) -> Vec<&super::Order> {
308        self.orders
309            .iter()
310            .filter(|order| order.status == status)
311            .collect()
312    }
313
314    /// Get open orders
315    pub fn open_orders(&self) -> Vec<&super::Order> {
316        self.orders.iter().filter(|order| order.is_open()).collect()
317    }
318
319    /// Get completed orders
320    pub fn completed_orders(&self) -> Vec<&super::Order> {
321        self.orders
322            .iter()
323            .filter(|order| order.is_complete())
324            .collect()
325    }
326
327    /// Get cancelled orders
328    pub fn cancelled_orders(&self) -> Vec<&super::Order> {
329        self.orders
330            .iter()
331            .filter(|order| order.is_cancelled())
332            .collect()
333    }
334
335    /// Get rejected orders
336    pub fn rejected_orders(&self) -> Vec<&super::Order> {
337        self.orders
338            .iter()
339            .filter(|order| order.is_rejected())
340            .collect()
341    }
342
343    /// Find order by ID
344    pub fn find_order(&self, order_id: &str) -> Option<&super::Order> {
345        self.orders.iter().find(|order| order.order_id == order_id)
346    }
347
348    /// Get orders by trading symbol
349    pub fn orders_by_symbol(&self, symbol: &str) -> Vec<&super::Order> {
350        self.orders
351            .iter()
352            .filter(|order| order.trading_symbol == symbol)
353            .collect()
354    }
355}
356
357impl TradeBook {
358    /// Calculate total traded value
359    pub fn total_value(&self) -> f64 {
360        self.trades.iter().map(|trade| trade.total_value()).sum()
361    }
362
363    /// Calculate total quantity traded
364    pub fn total_quantity(&self) -> u32 {
365        self.trades.iter().map(|trade| trade.quantity).sum()
366    }
367
368    /// Get trades by trading symbol
369    pub fn trades_by_symbol(&self, symbol: &str) -> Vec<&Trade> {
370        self.trades
371            .iter()
372            .filter(|trade| trade.trading_symbol == symbol)
373            .collect()
374    }
375
376    /// Get trades by transaction type
377    pub fn trades_by_type(&self, transaction_type: TransactionType) -> Vec<&Trade> {
378        self.trades
379            .iter()
380            .filter(|trade| trade.transaction_type == transaction_type)
381            .collect()
382    }
383
384    /// Group trades by trading symbol
385    pub fn group_by_symbol(&self) -> std::collections::HashMap<String, Vec<&Trade>> {
386        let mut grouped = std::collections::HashMap::new();
387
388        for trade in &self.trades {
389            grouped
390                .entry(trade.trading_symbol.clone())
391                .or_insert_with(Vec::new)
392                .push(trade);
393        }
394
395        grouped
396    }
397}