comprehensive_example/
comprehensive_example.rs

1//! # Comprehensive KiteConnect API Example
2//! 
3//! This example demonstrates various KiteConnect API operations including
4//! authentication, portfolio management, and market data access.
5
6use kiteconnect_async_wasm::connect::KiteConnect;
7use std::error::Error;
8
9#[tokio::main]
10async fn main() -> Result<(), Box<dyn Error>> {
11    // Initialize the KiteConnect client
12    let mut client = KiteConnect::new("your_api_key", "");
13    
14    // Step 1: Authentication Flow
15    println!("=== Authentication ===");
16    
17    // Generate login URL for user authentication
18    let login_url = client.login_url();
19    println!("1. Visit this URL to login: {}", login_url);
20    println!("2. After login, copy the request_token from the redirect URL");
21    
22    // In a real application, you would:
23    // - Open the login URL in a browser
24    // - User completes login
25    // - Extract request_token from callback URL
26    // - Use it here:
27    
28    // Uncomment and use real tokens:
29    // let session = client.generate_session("your_request_token", "your_api_secret").await?;
30    // println!("Session created: {:?}", session);
31    
32    // For demo purposes, set access token directly
33    client.set_access_token("your_access_token");
34    
35    // Step 2: Portfolio Information
36    println!("\n=== Portfolio Information ===");
37    
38    // Get holdings
39    match client.holdings().await {
40        Ok(holdings) => {
41            println!("Holdings retrieved successfully");
42            if let Some(data) = holdings["data"].as_array() {
43                println!("Number of holdings: {}", data.len());
44                for holding in data.iter().take(3) { // Show first 3
45                    println!("  - {} qty: {}", 
46                        holding["tradingsymbol"].as_str().unwrap_or("N/A"),
47                        holding["quantity"]);
48                }
49            }
50        }
51        Err(e) => println!("Failed to get holdings: {}", e),
52    }
53    
54    // Get positions
55    match client.positions().await {
56        Ok(positions) => {
57            println!("Positions retrieved successfully");
58            if let Some(day_positions) = positions["data"]["day"].as_array() {
59                let open_positions: Vec<_> = day_positions
60                    .iter()
61                    .filter(|p| p["quantity"].as_i64().unwrap_or(0) != 0)
62                    .collect();
63                    
64                println!("Open positions: {}", open_positions.len());
65                for position in open_positions.iter().take(3) {
66                    println!("  - {} qty: {}", 
67                        position["tradingsymbol"].as_str().unwrap_or("N/A"),
68                        position["quantity"]);
69                }
70            }
71        }
72        Err(e) => println!("Failed to get positions: {}", e),
73    }
74    
75    // Get margins
76    match client.margins(None).await {
77        Ok(margins) => {
78            println!("Margins retrieved successfully");
79            if let Some(equity) = margins["data"]["equity"].as_object() {
80                println!("Equity available balance: {}", 
81                    equity["available"]["live_balance"].as_f64().unwrap_or(0.0));
82            }
83        }
84        Err(e) => println!("Failed to get margins: {}", e),
85    }
86    
87    // Step 3: Orders and Trades
88    println!("\n=== Orders and Trades ===");
89    
90    // Get today's orders
91    match client.orders().await {
92        Ok(orders) => {
93            println!("Orders retrieved successfully");
94            if let Some(data) = orders["data"].as_array() {
95                println!("Total orders today: {}", data.len());
96                
97                // Group by status
98                let mut status_count = std::collections::HashMap::new();
99                for order in data {
100                    let status = order["status"].as_str().unwrap_or("UNKNOWN");
101                    *status_count.entry(status).or_insert(0) += 1;
102                }
103                
104                for (status, count) in status_count {
105                    println!("  - {}: {}", status, count);
106                }
107            }
108        }
109        Err(e) => println!("Failed to get orders: {}", e),
110    }
111    
112    // Get trades
113    match client.trades().await {
114        Ok(trades) => {
115            println!("Trades retrieved successfully");
116            if let Some(data) = trades["data"].as_array() {
117                println!("Total trades today: {}", data.len());
118                
119                let total_turnover: f64 = data
120                    .iter()
121                    .filter_map(|trade| {
122                        let price = trade["price"].as_f64()?;
123                        let quantity = trade["quantity"].as_f64()?;
124                        Some(price * quantity)
125                    })
126                    .sum();
127                    
128                println!("Total turnover: ₹{:.2}", total_turnover);
129            }
130        }
131        Err(e) => println!("Failed to get trades: {}", e),
132    }
133    
134    // Step 4: Market Data
135    println!("\n=== Market Data ===");
136    
137    // Get instruments (this can be large, so we'll just count)
138    match client.instruments(None).await {
139        Ok(instruments) => {
140            println!("Instruments data retrieved successfully");
141            // Note: instruments() returns CSV data, not JSON
142            println!("Instruments data type: {}", 
143                if instruments.is_string() { "CSV String" } else { "JSON" });
144        }
145        Err(e) => println!("Failed to get instruments: {}", e),
146    }
147    
148    // Step 5: Mutual Funds
149    println!("\n=== Mutual Funds ===");
150    
151    // Get MF orders
152    match client.mf_orders(None).await {
153        Ok(mf_orders) => {
154            println!("MF orders retrieved successfully");
155            if let Some(data) = mf_orders["data"].as_array() {
156                println!("MF orders count: {}", data.len());
157            }
158        }
159        Err(e) => println!("Failed to get MF orders: {}", e),
160    }
161    
162    // Step 6: Concurrent API Calls
163    println!("\n=== Concurrent Operations ===");
164    
165    // Demonstrate concurrent API calls
166    let client1 = client.clone();
167    let client2 = client.clone();
168    let client3 = client.clone();
169    
170    let start = std::time::Instant::now();
171    
172    // Fetch multiple endpoints concurrently
173    let results = tokio::try_join!(
174        client1.holdings(),
175        client2.positions(), 
176        client3.margins(None)
177    );
178    
179    let duration = start.elapsed();
180    
181    match results {
182        Ok((holdings, positions, margins)) => {
183            println!("✅ All concurrent requests completed in {:?}", duration);
184            println!("   - Holdings: {} items", 
185                holdings["data"].as_array().map_or(0, |a| a.len()));
186            println!("   - Positions: {} day positions", 
187                positions["data"]["day"].as_array().map_or(0, |a| a.len()));
188            println!("   - Margins: {} segments", 
189                margins["data"].as_object().map_or(0, |o| o.len()));
190        }
191        Err(e) => println!("❌ Concurrent requests failed: {}", e),
192    }
193    
194    println!("\n=== Example completed ===");
195    println!("This example demonstrates the main KiteConnect API features.");
196    println!("Replace placeholder values with real API credentials to test.");
197    
198    Ok(())
199}