kiteconnect_async_wasm/connect/
orders.rs

1//! # Orders Module
2//!
3//! This module provides comprehensive order management capabilities for the KiteConnect API v1.0.3,
4//! offering complete control over trade execution with both simple and advanced order types.
5//!
6//! ## Overview
7//!
8//! The orders module is the core component for executing trades on the KiteConnect platform.
9//! It provides access to order placement, modification, cancellation, and monitoring with
10//! both legacy JSON-based and modern strongly-typed APIs for enhanced developer experience.
11//!
12//! ## Key Features
13//!
14//! ### 🔄 **Dual API Support**
15//! - **Legacy API**: Returns `JsonValue` for backward compatibility
16//! - **Typed API**: Returns structured types with compile-time safety (methods ending in `_typed`)
17//!
18//! ### 📊 **Complete Order Management**
19//! - **Order Placement**: Market, limit, stop-loss, and bracket orders
20//! - **Order Modification**: Update price, quantity, and order parameters
21//! - **Order Cancellation**: Cancel pending orders and exit positions
22//! - **Order Monitoring**: Real-time status updates and fill information
23//!
24//! ### 💡 **Advanced Order Types**
25//! - **Regular Orders**: Basic buy/sell orders
26//! - **Bracket Orders**: Auto stop-loss and profit booking
27//! - **Cover Orders**: Built-in stop-loss protection
28//! - **Iceberg Orders**: Large order execution in smaller chunks
29//! - **GTT Orders**: Good Till Triggered conditional orders
30//!
31//! ### 🛠️ **Builder Patterns**
32//! - **OrderBuilder**: Fluent API for constructing orders
33//! - **BracketOrderBuilder**: Specialized builder for bracket orders
34//! - **Type Safety**: Compile-time validation of order parameters
35//!
36//! ## Available Methods
37//!
38//! ### Order Placement
39//! - [`place_order()`](KiteConnect::place_order) / [`place_order_typed()`](KiteConnect::place_order_typed) - Place new orders
40//! - [`modify_order()`](KiteConnect::modify_order) - Modify existing orders
41//! - [`cancel_order()`](KiteConnect::cancel_order) - Cancel pending orders
42//!
43//! ### Order Information
44//! - [`orders()`](KiteConnect::orders) / [`orders_typed()`](KiteConnect::orders_typed) - Get all orders
45//! - [`order_history()`](KiteConnect::order_history) - Get order execution history
46//! - [`trades()`](KiteConnect::trades) / [`trades_typed()`](KiteConnect::trades_typed) - Get trade book
47//!
48//! ### Position Management
49//! - [`convert_position()`](KiteConnect::convert_position) - Convert product types
50//! - Position tracking and P&L monitoring
51//!
52//! ## Usage Examples
53//!
54//! ### Basic Order Placement
55//! ```rust,no_run
56//! use kiteconnect_async_wasm::connect::KiteConnect;
57//! use kiteconnect_async_wasm::models::orders::OrderParams;
58//! use kiteconnect_async_wasm::models::common::{Exchange, TransactionType, OrderType, Product, Validity};
59//!
60//! # #[tokio::main]
61//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
62//! let client = KiteConnect::new("api_key", "access_token");
63//!
64//! // Method 1: Direct order parameters
65//! let order_params = OrderParams {
66//!     exchange: Exchange::NSE,
67//!     trading_symbol: "RELIANCE".to_string(),
68//!     transaction_type: TransactionType::BUY,
69//!     quantity: 10,
70//!     order_type: OrderType::LIMIT,
71//!     product: Product::CNC,
72//!     price: Some(2500.0),
73//!     validity: Some(Validity::DAY),
74//!     disclosed_quantity: None,
75//!     trigger_price: None,
76//!     tag: Some("MyOrder".to_string()),
77//!     squareoff: None,
78//!     stoploss: None,
79//!     trailing_stoploss: None,
80//!     market_protection: None,
81//!     iceberg_legs: None,
82//!     iceberg_quantity: None,
83//!     auction_number: None,
84//! };
85//!
86//! let response = client.place_order_typed("regular", &order_params).await?;
87//! println!("🎯 Order placed successfully!");
88//! println!("   Order ID: {}", response.order_id);
89//! # Ok(())
90//! # }
91//! ```
92//!
93//! ### Using Order Builder (Recommended)
94//! ```rust,no_run
95//! use kiteconnect_async_wasm::connect::KiteConnect;
96//! use kiteconnect_async_wasm::models::orders::OrderBuilder;
97//! use kiteconnect_async_wasm::models::common::{Exchange, TransactionType, OrderType, Product, Validity};
98//!
99//! # #[tokio::main]
100//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
101//! let client = KiteConnect::new("api_key", "access_token");
102//!
103//! // Fluent builder pattern for better ergonomics
104//! let order = OrderBuilder::new()
105//!     .trading_symbol("TCS")
106//!     .exchange(Exchange::NSE)
107//!     .transaction_type(TransactionType::BUY)
108//!     .quantity(5)
109//!     .order_type(OrderType::MARKET)
110//!     .product(Product::MIS)
111//!     .validity(Validity::DAY)
112//!     .tag("QuickBuy")
113//!     .build()?;
114//!
115//! let response = client.place_order_typed("regular", &order).await?;
116//! println!("🚀 Market order executed!");
117//! println!("   Order ID: {}", response.order_id);
118//! # Ok(())
119//! # }
120//! ```
121//!
122//! ### Advanced Order Types
123//! ```rust,no_run
124//! use kiteconnect_async_wasm::connect::KiteConnect;
125//! use kiteconnect_async_wasm::models::orders::{OrderBuilder, BracketOrderBuilder};
126//! use kiteconnect_async_wasm::models::common::{Exchange, TransactionType, OrderType, Product};
127//!
128//! # #[tokio::main]
129//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
130//! let client = KiteConnect::new("api_key", "access_token");
131//!
132//! // Stop-Loss Order
133//! let sl_order = OrderBuilder::new()
134//!     .trading_symbol("INFY")
135//!     .exchange(Exchange::NSE)
136//!     .transaction_type(TransactionType::SELL)
137//!     .quantity(20)
138//!     .order_type(OrderType::SL)
139//!     .product(Product::MIS)
140//!     .price(1450.0)
141//!     .trigger_price(1440.0)
142//!     .build()?;
143//!
144//! let sl_response = client.place_order_typed("regular", &sl_order).await?;
145//! println!("🛡️ Stop-loss order placed: {}", sl_response.order_id);
146//!
147//! // Bracket Order (Buy with auto profit booking and stop-loss)
148//! let bracket_order = BracketOrderBuilder::new()
149//!     .trading_symbol("HDFC")
150//!     .exchange(Exchange::NSE)
151//!     .transaction_type(TransactionType::BUY)
152//!     .quantity(10)
153//!     .price(1600.0)
154//!     .squareoff(1650.0)    // Take profit at +50
155//!     .stoploss(1580.0)     // Stop loss at -20
156//!     .trailing_stoploss(5.0) // Trail by 5 points
157//!     .build()?;
158//!
159//! let bo_response = client.place_order_typed("bo", &bracket_order.order_params).await?;
160//! println!("🎯 Bracket order placed: {}", bo_response.order_id);
161//!
162//! // Iceberg Order (Large order in small chunks)
163//! let iceberg_order = OrderBuilder::new()
164//!     .trading_symbol("SBIN")
165//!     .exchange(Exchange::NSE)
166//!     .transaction_type(TransactionType::BUY)
167//!     .quantity(1000)        // Total quantity
168//!     .order_type(OrderType::LIMIT)
169//!     .product(Product::CNC)
170//!     .price(250.0)
171//!     .iceberg(10, 100)      // 10 legs of 100 shares each
172//!     .build()?;
173//!
174//! let iceberg_response = client.place_order_typed("iceberg", &iceberg_order).await?;
175//! println!("🧊 Iceberg order placed: {}", iceberg_response.order_id);
176//! # Ok(())
177//! # }
178//! ```
179//!
180//! ### Order Monitoring and Management
181//! ```rust,no_run
182//! use kiteconnect_async_wasm::connect::KiteConnect;
183//! use kiteconnect_async_wasm::models::orders::OrderStatus;
184//!
185//! # #[tokio::main]
186//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
187//! let client = KiteConnect::new("api_key", "access_token");
188//!
189//! // Get all orders for the day
190//! let orders = client.orders_typed().await?;
191//!
192//! println!("📋 Today's Orders ({}):", orders.len());
193//! println!("================================");
194//!
195//! for order in &orders {
196//!     let status_icon = match order.status {
197//!         OrderStatus::Complete => "✅",
198//!         OrderStatus::Open | OrderStatus::TriggerPending => "⏳",
199//!         OrderStatus::Cancelled => "❌",
200//!         OrderStatus::Rejected => "🚫",
201//!         _ => "❓",
202//!     };
203//!
204//!     println!("{} {} ({:?})", status_icon, order.order_id, order.status);
205//!     println!("   📊 {:?} {} {} @ ₹{:.2}",
206//!         order.transaction_type,
207//!         order.quantity,
208//!         order.trading_symbol,
209//!         order.price);
210//!
211//!     if order.is_partially_filled() {
212//!         println!("   📈 Partial fill: {}/{} ({:.1}%)",
213//!             order.filled_quantity,
214//!             order.quantity,
215//!             order.fill_percentage());
216//!     }
217//!
218//!     if order.is_complete() && order.filled_quantity > 0 {
219//!         println!("   💰 Avg fill price: ₹{:.2}",
220//!             order.average_price);
221//!     }
222//!     println!();
223//! }
224//! # Ok(())
225//! # }
226//! ```
227//!
228//! ### Order Modification and Cancellation
229//! ```rust,no_run
230//! use kiteconnect_async_wasm::connect::KiteConnect;
231//!
232//! # #[tokio::main]
233//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
234//! let client = KiteConnect::new("api_key", "access_token");
235//!
236//! let order_id = "210429000000001"; // Replace with actual order ID
237//!
238//! // Modify order price
239//! let modify_result = client.modify_order(
240//!     order_id,
241//!     "regular",           // variety
242//!     None,               // quantity (unchanged)
243//!     Some("2550.0"),     // new price
244//!     None,               // order_type (unchanged)
245//!     None,               // validity (unchanged)
246//!     None,               // disclosed_quantity
247//!     None,               // trigger_price
248//!     None,               // parent_order_id
249//! ).await;
250//!
251//! match modify_result {
252//!     Ok(_) => println!("✅ Order {} modified successfully", order_id),
253//!     Err(e) => println!("❌ Failed to modify order: {}", e),
254//! }
255//!
256//! // Cancel order if modification fails or no longer needed
257//! let cancel_result = client.cancel_order(order_id, "regular", None).await;
258//! match cancel_result {
259//!     Ok(_) => println!("🗑️ Order {} cancelled successfully", order_id),
260//!     Err(e) => println!("❌ Failed to cancel order: {}", e),
261//! }
262//! # Ok(())
263//! # }
264//! ```
265//!
266//! ### Trade Book Analysis
267//! ```rust,no_run
268//! use kiteconnect_async_wasm::connect::KiteConnect;
269//!
270//! # #[tokio::main]
271//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
272//! let client = KiteConnect::new("api_key", "access_token");
273//!
274//! // Get all trades for the day
275//! let trades = client.trades_typed().await?;
276//!
277//! println!("💼 Trade Book Analysis ({} trades):", trades.len());
278//! println!("=====================================");
279//!
280//! let mut total_turnover = 0.0;
281//! let mut buy_trades = 0;
282//! let mut sell_trades = 0;
283//!
284//! for trade in &trades {
285//!     let trade_value = trade.total_value();
286//!     total_turnover += trade_value;
287//!
288//!     if trade.is_buy() {
289//!         buy_trades += 1;
290//!     } else {
291//!         sell_trades += 1;
292//!     }
293//!
294//!     println!("🔄 {} {}: {} @ ₹{:.2} (₹{:.2})",
295//!         trade.fill_timestamp.format("%H:%M:%S"),
296//!         trade.trading_symbol,
297//!         if trade.is_buy() { "BUY" } else { "SELL" },
298//!         trade.average_price,
299//!         trade_value);
300//! }
301//!
302//! println!();
303//! println!("📊 Summary:");
304//! println!("   Total trades: {} (Buy: {}, Sell: {})", trades.len(), buy_trades, sell_trades);
305//! println!("   Total turnover: ₹{:.2}", total_turnover);
306//! println!("   Average trade size: ₹{:.2}",
307//!     if !trades.is_empty() { total_turnover / trades.len() as f64 } else { 0.0 });
308//! # Ok(())
309//! # }
310//! ```
311//!
312//! ## Data Models
313//!
314//! ### Order Types
315//! The [`Order`] struct represents order information with comprehensive status tracking:
316//! - **Order Status**: Open, complete, cancelled, rejected states
317//! - **Fill Information**: Partial and complete fill tracking
318//! - **Execution Details**: Average price, timestamps, and exchange data
319//! - **Order Analysis**: Helper methods for status checking and calculations
320//!
321//! ### Order Parameters
322//! The [`OrderParams`] struct defines order placement requirements:
323//! - **Required Fields**: Symbol, exchange, transaction type, quantity
324//! - **Optional Fields**: Price, validity, disclosed quantity, tags
325//! - **Advanced Features**: Stop-loss, iceberg, bracket order parameters
326//! - **Validation**: Built-in parameter validation and error checking
327//!
328//! ### Trade Information
329//! The [`Trade`] struct represents executed trades:
330//! - **Execution Data**: Fill price, quantity, and timestamp
331//! - **Order Linkage**: Connection to parent order information
332//! - **Value Calculations**: Trade value and commission tracking
333//! - **Direction Analysis**: Buy/sell identification and analysis
334//!
335//! ## Error Handling
336//!
337//! All methods return `Result<T>` with comprehensive error information:
338//!
339//! ```rust,no_run
340//! use kiteconnect_async_wasm::models::common::KiteError;
341//!
342//! # #[tokio::main]
343//! # async fn main() {
344//! # let client = kiteconnect_async_wasm::connect::KiteConnect::new("", "");
345//! # let order_params = kiteconnect_async_wasm::models::orders::OrderParams {
346//! #     exchange: kiteconnect_async_wasm::models::common::Exchange::NSE,
347//! #     trading_symbol: "TEST".to_string(),
348//! #     transaction_type: kiteconnect_async_wasm::models::common::TransactionType::BUY,
349//! #     quantity: 1,
350//! #     order_type: kiteconnect_async_wasm::models::common::OrderType::MARKET,
351//! #     product: kiteconnect_async_wasm::models::common::Product::MIS,
352//! #     price: None, validity: None, disclosed_quantity: None, trigger_price: None,
353//! #     tag: None, squareoff: None, stoploss: None, trailing_stoploss: None,
354//! #     market_protection: None, iceberg_legs: None, iceberg_quantity: None,
355//! #     auction_number: None,
356//! # };
357//! match client.place_order_typed("regular", &order_params).await {
358//!     Ok(response) => {
359//!         println!("✅ Order placed: {}", response.order_id);
360//!     }
361//!     Err(KiteError::Authentication(msg)) => {
362//!         eprintln!("🔐 Authentication failed: {}", msg);
363//!         // Handle re-authentication
364//!     }
365//!     Err(KiteError::Api { status, message, .. }) => {
366//!         eprintln!("🚫 Order rejected: {} - {}", status, message);
367//!         if status == "429" {
368//!             eprintln!("⏱️ Rate limited - please wait before retrying");
369//!         }
370//!         // Handle order rejection (insufficient margin, invalid params, etc.)
371//!     }
372//!     Err(e) => eprintln!("❌ Other error: {}", e),
373//! }
374//! # }
375//! ```
376//!
377//! ## Order Validation
378//!
379//! The module provides built-in validation for order parameters:
380//!
381//! ```rust,no_run
382//! use kiteconnect_async_wasm::models::orders::OrderBuilder;
383//! use kiteconnect_async_wasm::models::common::{Exchange, TransactionType, OrderType, Product};
384//!
385//! # fn example() -> Result<(), String> {
386//! // This will fail validation - no price for LIMIT order
387//! let invalid_order = OrderBuilder::new()
388//!     .trading_symbol("RELIANCE")
389//!     .exchange(Exchange::NSE)
390//!     .transaction_type(TransactionType::BUY)
391//!     .quantity(10)
392//!     .order_type(OrderType::LIMIT)  // LIMIT order requires price
393//!     .product(Product::CNC)
394//!     .build(); // This returns Err("Price is required for LIMIT orders")
395//!
396//! match invalid_order {
397//!     Ok(_) => println!("Order validated successfully"),
398//!     Err(e) => println!("Validation error: {}", e),
399//! }
400//!
401//! // Correct version with price
402//! let valid_order = OrderBuilder::new()
403//!     .trading_symbol("RELIANCE")
404//!     .exchange(Exchange::NSE)
405//!     .transaction_type(TransactionType::BUY)
406//!     .quantity(10)
407//!     .order_type(OrderType::LIMIT)
408//!     .product(Product::CNC)
409//!     .price(2500.0)  // Price provided for LIMIT order
410//!     .build()?;
411//!
412//! println!("✅ Order validated and ready for placement");
413//! # Ok(())
414//! # }
415//! ```
416//!
417//! ## Performance Considerations
418//!
419//! ### Efficient Order Management
420//! - **Batch Operations**: Use `tokio::join!` for concurrent order operations
421//! - **Typed APIs**: Use `*_typed()` methods for better performance and type safety
422//! - **Builder Patterns**: Use builders for complex orders to avoid parameter errors
423//!
424//! ### Memory Usage
425//! - **Structured Data**: Typed APIs use less memory than JSON parsing
426//! - **Efficient Calculations**: Built-in helper methods reduce computation overhead
427//! - **Order Filtering**: Filter orders client-side to reduce data processing
428//!
429//! ## Rate Limiting
430//!
431//! The module automatically handles rate limiting according to KiteConnect API guidelines:
432//! - **Order APIs**: 10 requests per second for order placement and modification
433//! - **Query APIs**: 3 requests per second for order and trade queries
434//! - **Automatic Retry**: Built-in retry mechanism with exponential backoff
435//! - **Connection Pooling**: HTTP connections are reused for better performance
436//!
437//! ## Thread Safety
438//!
439//! All methods are thread-safe and can be called concurrently:
440//! ```rust,no_run
441//! # use kiteconnect_async_wasm::connect::KiteConnect;
442//! # #[tokio::main]
443//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
444//! # let client = KiteConnect::new("", "");
445//! // Concurrent order and trade data retrieval
446//! let (orders, trades) = tokio::try_join!(
447//!     client.orders_typed(),
448//!     client.trades_typed()
449//! )?;
450//!
451//! // Process both datasets concurrently
452//! println!("Orders: {}, Trades: {}", orders.len(), trades.len());
453//! # Ok(())
454//! # }
455//! ```
456//!
457//! ## Migration from v1.0.2
458//!
459//! All existing methods continue to work. New typed methods provide enhanced features:
460//! - Replace `place_order()` with `place_order_typed()` for structured parameters
461//! - Use `orders_typed()` and `trades_typed()` for type safety
462//! - Leverage `OrderBuilder` and `BracketOrderBuilder` for complex orders
463//! - Legacy methods remain available for backward compatibility
464
465use crate::connect::endpoints::KiteEndpoint;
466use anyhow::Result;
467use serde_json::Value as JsonValue;
468use std::collections::HashMap;
469
470// Import typed models for dual API support
471use crate::models::common::KiteResult;
472use crate::models::orders::{Order, OrderParams, OrderResponse, Trade};
473
474use crate::connect::KiteConnect;
475
476impl KiteConnect {
477    // === LEGACY API METHODS (JSON responses) ===
478
479    /// Place an order
480    #[allow(clippy::too_many_arguments)]
481    pub async fn place_order(
482        &self,
483        variety: &str,
484        exchange: &str,
485        tradingsymbol: &str,
486        transaction_type: &str,
487        quantity: &str,
488        product: Option<&str>,
489        order_type: Option<&str>,
490        price: Option<&str>,
491        validity: Option<&str>,
492        disclosed_quantity: Option<&str>,
493        trigger_price: Option<&str>,
494        squareoff: Option<&str>,
495        stoploss: Option<&str>,
496        trailing_stoploss: Option<&str>,
497        tag: Option<&str>,
498    ) -> Result<JsonValue> {
499        let mut params = HashMap::new();
500        params.insert("variety", variety);
501        params.insert("exchange", exchange);
502        params.insert("tradingsymbol", tradingsymbol);
503        params.insert("transaction_type", transaction_type);
504        params.insert("quantity", quantity);
505
506        if let Some(product) = product {
507            params.insert("product", product);
508        }
509        if let Some(order_type) = order_type {
510            params.insert("order_type", order_type);
511        }
512        if let Some(price) = price {
513            params.insert("price", price);
514        }
515        if let Some(validity) = validity {
516            params.insert("validity", validity);
517        }
518        if let Some(disclosed_quantity) = disclosed_quantity {
519            params.insert("disclosed_quantity", disclosed_quantity);
520        }
521        if let Some(trigger_price) = trigger_price {
522            params.insert("trigger_price", trigger_price);
523        }
524        if let Some(squareoff) = squareoff {
525            params.insert("squareoff", squareoff);
526        }
527        if let Some(stoploss) = stoploss {
528            params.insert("stoploss", stoploss);
529        }
530        if let Some(trailing_stoploss) = trailing_stoploss {
531            params.insert("trailing_stoploss", trailing_stoploss);
532        }
533        if let Some(tag) = tag {
534            params.insert("tag", tag);
535        }
536
537        let resp = self
538            .send_request_with_rate_limiting_and_retry(
539                KiteEndpoint::PlaceOrder,
540                &[variety],
541                None,
542                Some(params),
543            )
544            .await
545            .map_err(|e| anyhow::anyhow!("Place order failed: {:?}", e))?;
546        self.raise_or_return_json(resp).await
547    }
548
549    /// Modify an open order
550    #[allow(clippy::too_many_arguments)]
551    pub async fn modify_order(
552        &self,
553        order_id: &str,
554        variety: &str,
555        quantity: Option<&str>,
556        price: Option<&str>,
557        order_type: Option<&str>,
558        validity: Option<&str>,
559        disclosed_quantity: Option<&str>,
560        trigger_price: Option<&str>,
561        parent_order_id: Option<&str>,
562    ) -> Result<JsonValue> {
563        let mut params = HashMap::new();
564        params.insert("order_id", order_id);
565        params.insert("variety", variety);
566
567        if let Some(quantity) = quantity {
568            params.insert("quantity", quantity);
569        }
570        if let Some(price) = price {
571            params.insert("price", price);
572        }
573        if let Some(order_type) = order_type {
574            params.insert("order_type", order_type);
575        }
576        if let Some(validity) = validity {
577            params.insert("validity", validity);
578        }
579        if let Some(disclosed_quantity) = disclosed_quantity {
580            params.insert("disclosed_quantity", disclosed_quantity);
581        }
582        if let Some(trigger_price) = trigger_price {
583            params.insert("trigger_price", trigger_price);
584        }
585        if let Some(parent_order_id) = parent_order_id {
586            params.insert("parent_order_id", parent_order_id);
587        }
588
589        let resp = self
590            .send_request_with_rate_limiting_and_retry(
591                KiteEndpoint::ModifyOrder,
592                &[variety, order_id],
593                None,
594                Some(params),
595            )
596            .await
597            .map_err(|e| anyhow::anyhow!("Modify order failed: {:?}", e))?;
598        self.raise_or_return_json(resp).await
599    }
600
601    /// Cancel an order
602    pub async fn cancel_order(
603        &self,
604        order_id: &str,
605        variety: &str,
606        parent_order_id: Option<&str>,
607    ) -> Result<JsonValue> {
608        let mut params = HashMap::new();
609        params.insert("order_id", order_id);
610        params.insert("variety", variety);
611        if let Some(parent_order_id) = parent_order_id {
612            params.insert("parent_order_id", parent_order_id);
613        }
614
615        let resp = self
616            .send_request_with_rate_limiting_and_retry(
617                KiteEndpoint::CancelOrder,
618                &[variety, order_id],
619                None,
620                Some(params),
621            )
622            .await
623            .map_err(|e| anyhow::anyhow!("Cancel order failed: {:?}", e))?;
624        self.raise_or_return_json(resp).await
625    }
626
627    /// Exit a BO/CO order
628    pub async fn exit_order(
629        &self,
630        order_id: &str,
631        variety: &str,
632        parent_order_id: Option<&str>,
633    ) -> Result<JsonValue> {
634        self.cancel_order(order_id, variety, parent_order_id).await
635    }
636
637    /// Retrieves a list of all orders for the current trading day
638    ///
639    /// Returns all orders placed by the user for the current trading day,
640    /// including pending, completed, rejected, and cancelled orders.
641    ///
642    /// # Returns
643    ///
644    /// A `Result<JsonValue>` containing orders data with fields like:
645    /// - `order_id` - Unique order identifier
646    /// - `tradingsymbol` - Trading symbol
647    /// - `quantity` - Order quantity
648    /// - `price` - Order price
649    /// - `status` - Order status (OPEN, COMPLETE, CANCELLED, REJECTED)
650    /// - `order_type` - Order type (MARKET, LIMIT, SL, SL-M)
651    /// - `product` - Product type (MIS, CNC, NRML)
652    ///
653    /// # Errors
654    ///
655    /// Returns an error if the API request fails or the user is not authenticated.
656    ///
657    /// # Example
658    ///
659    /// ```rust,no_run
660    /// use kiteconnect_async_wasm::connect::KiteConnect;
661    ///
662    /// # #[tokio::main]
663    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
664    /// let client = KiteConnect::new("api_key", "access_token");
665    ///
666    /// let orders = client.orders().await?;
667    /// println!("Orders: {:?}", orders);
668    ///
669    /// // Check order statuses
670    /// if let Some(data) = orders["data"].as_array() {
671    ///     for order in data {
672    ///         println!("Order {}: {} - {}",
673    ///             order["order_id"],
674    ///             order["tradingsymbol"],
675    ///             order["status"]);
676    ///     }
677    /// }
678    /// # Ok(())
679    /// # }
680    /// ```
681    pub async fn orders(&self) -> Result<JsonValue> {
682        let resp = self
683            .send_request_with_rate_limiting_and_retry(KiteEndpoint::Orders, &[], None, None)
684            .await
685            .map_err(|e| anyhow::anyhow!("Get orders failed: {:?}", e))?;
686        self.raise_or_return_json(resp).await
687    }
688
689    /// Get the list of order history
690    pub async fn order_history(&self, order_id: &str) -> Result<JsonValue> {
691        // REST spec: GET /orders/{order_id}
692        let resp = self
693            .send_request_with_rate_limiting_and_retry(
694                KiteEndpoint::OrderHistory,
695                &[order_id],
696                None,
697                None,
698            )
699            .await
700            .map_err(|e| anyhow::anyhow!("Get order history failed: {:?}", e))?;
701        self.raise_or_return_json(resp).await
702    }
703
704    /// Get all trades
705    pub async fn trades(&self) -> Result<JsonValue> {
706        let resp = self
707            .send_request_with_rate_limiting_and_retry(KiteEndpoint::Trades, &[], None, None)
708            .await
709            .map_err(|e| anyhow::anyhow!("Get trades failed: {:?}", e))?;
710        self.raise_or_return_json(resp).await
711    }
712
713    /// Get all trades for a specific order
714    pub async fn order_trades(&self, order_id: &str) -> Result<JsonValue> {
715        // REST spec: GET /orders/{order_id}/trades
716        let resp = self
717            .send_request_with_rate_limiting_and_retry(
718                KiteEndpoint::OrderTrades,
719                &[order_id, "trades"],
720                None,
721                None,
722            )
723            .await
724            .map_err(|e| anyhow::anyhow!("Get order trades failed: {:?}", e))?;
725        self.raise_or_return_json(resp).await
726    }
727
728    /// Modify an open position product type
729    #[allow(clippy::too_many_arguments)]
730    pub async fn convert_position(
731        &self,
732        exchange: &str,
733        tradingsymbol: &str,
734        transaction_type: &str,
735        position_type: &str,
736        quantity: &str,
737        old_product: &str,
738        new_product: &str,
739    ) -> Result<JsonValue> {
740        let mut params = HashMap::new();
741        params.insert("exchange", exchange);
742        params.insert("tradingsymbol", tradingsymbol);
743        params.insert("transaction_type", transaction_type);
744        params.insert("position_type", position_type);
745        params.insert("quantity", quantity);
746        params.insert("old_product", old_product);
747        params.insert("new_product", new_product);
748
749        let resp = self
750            .send_request_with_rate_limiting_and_retry(
751                KiteEndpoint::ConvertPosition,
752                &[],
753                None,
754                Some(params),
755            )
756            .await
757            .map_err(|e| anyhow::anyhow!("Convert position failed: {:?}", e))?;
758        self.raise_or_return_json(resp).await
759    }
760
761    // === TYPED API METHODS (v1.0.0) ===
762
763    /// Place an order with typed response
764    ///
765    /// Returns strongly typed order response instead of JsonValue.
766    /// This is the preferred method for new applications.
767    ///
768    /// # Arguments
769    ///
770    /// * `variety` - Order variety ("regular", "bo", "co", etc.)
771    /// * `order_params` - Typed order parameters struct
772    ///
773    /// # Returns
774    ///
775    /// A `KiteResult<OrderResponse>` containing the order ID
776    ///
777    /// # Example
778    ///
779    /// ```rust,no_run
780    /// use kiteconnect_async_wasm::connect::KiteConnect;
781    /// use kiteconnect_async_wasm::models::orders::OrderParams;
782    /// use kiteconnect_async_wasm::models::common::{Exchange, Product, OrderType, TransactionType, Validity};
783    ///
784    /// # #[tokio::main]
785    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
786    /// let client = KiteConnect::new("api_key", "access_token");
787    ///
788    /// let params = OrderParams {
789    ///     trading_symbol: "INFY".to_string(),
790    ///     exchange: Exchange::NSE,
791    ///     transaction_type: TransactionType::BUY,
792    ///     quantity: 1,
793    ///     order_type: OrderType::LIMIT,
794    ///     product: Product::CNC,
795    ///     price: Some(1500.0),
796    ///     validity: Some(Validity::DAY),
797    ///     disclosed_quantity: None,
798    ///     trigger_price: None,
799    ///     squareoff: None,
800    ///     stoploss: None,
801    ///     trailing_stoploss: None,
802    ///     market_protection: None,
803    ///     iceberg_legs: None,
804    ///     iceberg_quantity: None,
805    ///     auction_number: None,
806    ///     tag: None,
807    /// };
808    ///
809    /// let order_response = client.place_order_typed("regular", &params).await?;
810    /// println!("Order ID: {}", order_response.order_id);
811    /// # Ok(())
812    /// # }
813    /// ```
814    pub async fn place_order_typed(
815        &self,
816        variety: &str,
817        order_params: &OrderParams,
818    ) -> KiteResult<OrderResponse> {
819        // Create all string conversions upfront to avoid lifetime issues
820        let exchange_str = order_params.exchange.to_string();
821        let transaction_type_str = order_params.transaction_type.to_string();
822        let quantity_str = order_params.quantity.to_string();
823        let product_str = order_params.product.to_string();
824        let order_type_str = order_params.order_type.to_string();
825
826        let price_str = order_params.price.map(|p| p.to_string());
827        let validity_str = order_params.validity.as_ref().map(|v| v.to_string());
828        let disclosed_str = order_params.disclosed_quantity.map(|d| d.to_string());
829        let trigger_str = order_params.trigger_price.map(|t| t.to_string());
830
831        let mut params = HashMap::new();
832        params.insert("variety", variety);
833        params.insert("exchange", exchange_str.as_str());
834        params.insert("tradingsymbol", order_params.trading_symbol.as_str());
835        params.insert("transaction_type", transaction_type_str.as_str());
836        params.insert("quantity", quantity_str.as_str());
837        params.insert("product", product_str.as_str());
838        params.insert("order_type", order_type_str.as_str());
839
840        if let Some(ref price) = price_str {
841            params.insert("price", price.as_str());
842        }
843        if let Some(ref validity) = validity_str {
844            params.insert("validity", validity.as_str());
845        }
846        if let Some(ref disclosed) = disclosed_str {
847            params.insert("disclosed_quantity", disclosed.as_str());
848        }
849        if let Some(ref trigger) = trigger_str {
850            params.insert("trigger_price", trigger.as_str());
851        }
852        if let Some(ref tag) = order_params.tag {
853            params.insert("tag", tag.as_str());
854        }
855
856        let resp = self
857            .send_request_with_rate_limiting_and_retry(
858                KiteEndpoint::PlaceOrder,
859                &[variety],
860                None,
861                Some(params),
862            )
863            .await?;
864        let json_response = self.raise_or_return_json_typed(resp).await?;
865
866        // Extract the data field from response
867        let data = json_response["data"].clone();
868        self.parse_response(data)
869    }
870
871    /// Get all orders with typed response
872    ///
873    /// Returns strongly typed list of orders instead of JsonValue.
874    ///
875    /// # Returns
876    ///
877    /// A `KiteResult<Vec<Order>>` containing typed order information
878    ///
879    /// # Example
880    ///
881    /// ```rust,no_run
882    /// use kiteconnect_async_wasm::connect::KiteConnect;
883    ///
884    /// # #[tokio::main]
885    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
886    /// let client = KiteConnect::new("api_key", "access_token");
887    ///
888    /// let orders = client.orders_typed().await?;
889    /// for order in orders {
890    ///     println!("Order {}: {} - {:?}",
891    ///         order.order_id,
892    ///         order.trading_symbol,
893    ///         order.status);
894    /// }
895    /// # Ok(())
896    /// # }
897    /// ```
898    pub async fn orders_typed(&self) -> KiteResult<Vec<Order>> {
899        let resp = self
900            .send_request_with_rate_limiting_and_retry(KiteEndpoint::Orders, &[], None, None)
901            .await?;
902        let json_response = self.raise_or_return_json_typed(resp).await?;
903
904        // Extract the data field from response
905        let data = json_response["data"].clone();
906        self.parse_response(data)
907    }
908
909    /// Get all trades with typed response
910    ///
911    /// Returns strongly typed list of trades instead of JsonValue.
912    ///
913    /// # Returns
914    ///
915    /// A `KiteResult<Vec<Trade>>` containing typed trade information
916    ///
917    /// # Example
918    ///
919    /// ```rust,no_run
920    /// use kiteconnect_async_wasm::connect::KiteConnect;
921    ///
922    /// # #[tokio::main]
923    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
924    /// let client = KiteConnect::new("api_key", "access_token");
925    ///
926    /// let trades = client.trades_typed().await?;
927    /// for trade in trades {
928    ///     println!("Trade {}: {} @ {}",
929    ///         trade.trade_id,
930    ///         trade.quantity,
931    ///         trade.average_price);
932    /// }
933    /// # Ok(())
934    /// # }
935    /// ```
936    pub async fn trades_typed(&self) -> KiteResult<Vec<Trade>> {
937        let resp = self
938            .send_request_with_rate_limiting_and_retry(KiteEndpoint::Trades, &[], None, None)
939            .await?;
940        let json_response = self.raise_or_return_json_typed(resp).await?;
941
942        // Extract the data field from response
943        let data = json_response["data"].clone();
944        self.parse_response(data)
945    }
946
947    /// Get trades for specific order with typed response
948    ///
949    /// Returns strongly typed list of trades for a specific order instead of JsonValue.
950    ///
951    /// # Arguments
952    ///
953    /// * `order_id` - The order ID to get trades for
954    ///
955    /// # Returns
956    ///
957    /// A `KiteResult<Vec<Trade>>` containing typed trade information
958    ///
959    /// # Example
960    ///
961    /// ```rust,no_run
962    /// use kiteconnect_async_wasm::connect::KiteConnect;
963    ///
964    /// # #[tokio::main]
965    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
966    /// let client = KiteConnect::new("api_key", "access_token");
967    ///
968    /// let trades = client.order_trades_typed("order_id").await?;
969    /// for trade in trades {
970    ///     println!("Trade executed: {} @ {}", trade.quantity, trade.average_price);
971    /// }
972    /// # Ok(())
973    /// # }
974    /// ```
975    pub async fn order_trades_typed(&self, order_id: &str) -> KiteResult<Vec<Trade>> {
976        let resp = self
977            .send_request_with_rate_limiting_and_retry(
978                KiteEndpoint::OrderTrades,
979                &[order_id, "trades"],
980                None,
981                None,
982            )
983            .await?;
984        let json_response = self.raise_or_return_json_typed(resp).await?;
985
986        // Extract the data field from response
987        let data = json_response["data"].clone();
988        self.parse_response(data)
989    }
990}