# KiteConnect Async WASM - API Documentation Guide
This guide provides comprehensive documentation for using the KiteConnect Async WASM library v1.0.3 with real-world examples and best practices.
## Table of Contents
1. [Getting Started](#getting-started)
2. [Authentication Flow](#authentication-flow)
3. [Portfolio Management](#portfolio-management)
4. [Order Management](#order-management)
5. [Market Data](#market-data)
6. [Historical Data (Enhanced v1.0.3)](#historical-data-enhanced-v103)
7. [Mutual Funds](#mutual-funds)
8. [Error Handling](#error-handling)
9. [Rate Limiting](#rate-limiting)
10. [Best Practices](#best-practices)
## Getting Started
### Installation
Add to your `Cargo.toml`:
```toml
[dependencies]
kiteconnect-async-wasm = "1.0.3"
chrono = { version = "0.4", features = ["serde"] }
tokio = { version = "1.0", features = ["full"] }
anyhow = "1.0"
```
### Basic Setup
```rust
use kiteconnect_async_wasm::connect::KiteConnect;
use kiteconnect_async_wasm::models::prelude::*;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = KiteConnect::new("your_api_key", "your_access_token");
// Your trading logic here
Ok(())
}
```
## Authentication Flow
### Complete Authentication Example
```rust
use kiteconnect_async_wasm::connect::KiteConnect;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Step 1: Initialize client with API key
let mut client = KiteConnect::new("your_api_key", "");
// Step 2: Get login URL
let login_url = client.login_url();
println!("Please visit: {}", login_url);
println!("After login, copy the request_token from the callback URL");
// Step 3: Get request token from user input
let request_token = "your_request_token_from_callback";
// Step 4: Generate session
let session = client.generate_session(request_token, "your_api_secret").await?;
println!("Access token: {}", session.access_token);
// The client now has the access token and is ready for trading
Ok(())
}
```
### User Profile Information
```rust
// Get user profile (typed API)
let profile = client.profile_typed().await?;
println!("User: {} ({})", profile.user_name, profile.user_id);
println!("Broker: {}", profile.broker);
println!("Email: {}", profile.email);
// Get margin information
let margins = client.margins_typed(None).await?;
println!("Available margin: ₹{:.2}", margins.equity.available.live_balance);
```
## Portfolio Management
### Holdings Management
```rust
use kiteconnect_async_wasm::models::portfolio::Holding;
// Get all holdings (typed API)
let holdings: Vec<Holding> = client.holdings_typed().await?;
println!("Holdings Summary:");
println!("================");
let mut total_investment = 0.0;
let mut total_current_value = 0.0;
let mut total_pnl = 0.0;
for holding in &holdings {
let investment = holding.average_price * holding.quantity as f64;
let current_value = holding.last_price * holding.quantity as f64;
let pnl = current_value - investment;
total_investment += investment;
total_current_value += current_value;
total_pnl += pnl;
println!(" {}: {} shares", holding.trading_symbol, holding.quantity);
println!(" Avg: ₹{:.2}, LTP: ₹{:.2}", holding.average_price, holding.last_price);
println!(" Investment: ₹{:.2}, Current: ₹{:.2}", investment, current_value);
println!(" P&L: ₹{:.2} ({:.2}%)", pnl, (pnl / investment) * 100.0);
println!();
}
println!("Total Investment: ₹{:.2}", total_investment);
println!("Total Current Value: ₹{:.2}", total_current_value);
println!("Total P&L: ₹{:.2} ({:.2}%)", total_pnl, (total_pnl / total_investment) * 100.0);
```
### Positions Monitoring
```rust
use kiteconnect_async_wasm::models::portfolio::Position;
// Get all positions
let positions: Vec<Position> = client.positions_typed().await?;
println!("Active Positions:");
println!("=================");
for position in &positions {
if position.quantity != 0 {
let pnl = position.pnl + position.unrealised;
println!(" {}: {} {} shares",
position.trading_symbol,
position.quantity.abs(),
if position.quantity > 0 { "LONG" } else { "SHORT" }
);
println!(" Avg: ₹{:.2}, LTP: ₹{:.2}", position.average_price, position.last_price);
println!(" P&L: ₹{:.2}", pnl);
println!();
}
}
```
## Order Management
### Placing Orders
```rust
use kiteconnect_async_wasm::models::orders::{OrderParams, OrderBuilder};
use kiteconnect_async_wasm::models::common::{Exchange, TransactionType, OrderType, Product, Validity};
// Method 1: Using OrderParams directly
let order_params = OrderParams {
exchange: Exchange::NSE,
tradingsymbol: "RELIANCE".to_string(),
transaction_type: TransactionType::BUY,
quantity: 10,
order_type: OrderType::LIMIT,
product: Product::CNC,
price: Some(2500.0),
validity: Validity::DAY,
..Default::default()
};
let order_response = client.place_order_typed(&order_params).await?;
println!("Order placed: {}", order_response.order_id);
// Method 2: Using OrderBuilder (more ergonomic)
let order = OrderBuilder::new()
.exchange(Exchange::NSE)
.symbol("TCS")
.transaction_type(TransactionType::BUY)
.quantity(5)
.order_type(OrderType::MARKET)
.product(Product::CNC)
.validity(Validity::DAY)
.build();
let response = client.place_order_typed(&order).await?;
println!("Market order placed: {}", response.order_id);
```
### Order Status and History
```rust
// Get all orders
let orders = client.orders_typed().await?;
println!("Recent Orders:");
println!("==============");
for order in &orders {
println!(" {} ({}): {} {} {}",
order.order_id,
order.status,
order.transaction_type,
order.quantity,
order.trading_symbol
);
if let Some(price) = order.price {
println!(" Price: ₹{:.2}", price);
}
if order.filled_quantity > 0 {
println!(" Filled: {} @ ₹{:.2}",
order.filled_quantity,
order.average_price.unwrap_or(0.0)
);
}
println!();
}
```
### Modifying and Cancelling Orders
```rust
use kiteconnect_async_wasm::models::orders::OrderModifyParams;
// Modify an order
let modify_params = OrderModifyParams {
order_id: "order_id_here".to_string(),
price: Some(2450.0), // New price
quantity: Some(15), // New quantity
order_type: Some(OrderType::LIMIT),
validity: Some(Validity::DAY),
..Default::default()
};
let modify_response = client.modify_order_typed(&modify_params).await?;
println!("Order modified: {}", modify_response.order_id);
// Cancel an order
let cancel_response = client.cancel_order("order_id_here").await?;
println!("Order cancelled: {}", cancel_response.order_id);
```
## Market Data
### Real-time Quotes
```rust
// Get quotes for multiple instruments
let instruments = vec!["NSE:RELIANCE", "NSE:TCS", "NSE:INFY"];
let quotes = client.quote_typed(instruments).await?;
println!("Live Quotes:");
println!("============");
for quote in "es {
println!(" {}: ₹{:.2}", quote.trading_symbol, quote.last_price);
println!(" OHLC: {:.2}/{:.2}/{:.2}/{:.2}",
quote.ohlc.open, quote.ohlc.high, quote.ohlc.low, quote.ohlc.close);
println!(" Volume: {}", quote.volume_traded);
println!(" Change: {:.2} ({:.2}%)", quote.net_change, quote.oi_day_change);
println!();
}
```
### OHLC and LTP Data
```rust
// Get OHLC data
let instruments = vec!["NSE:NIFTY50", "NSE:BANKNIFTY"];
let ohlc_data = client.ohlc_typed(instruments.clone()).await?;
for ohlc in &ohlc_data {
println!("{}: O:{:.2} H:{:.2} L:{:.2} C:{:.2}",
ohlc.instrument_token, ohlc.open, ohlc.high, ohlc.low, ohlc.close);
}
// Get just the last traded prices
let ltp_data = client.ltp_typed(instruments).await?;
for ltp in <p_data {
println!("LTP for {}: ₹{:.2}", ltp.instrument_token, ltp.last_price);
}
```
## Historical Data (Enhanced v1.0.3)
### Basic Historical Data Request
```rust
use kiteconnect_async_wasm::models::market_data::HistoricalDataRequest;
use kiteconnect_async_wasm::models::common::Interval;
use chrono::NaiveDateTime;
// Enhanced v1.0.3 approach with structured request
let request = HistoricalDataRequest::new(
738561, // RELIANCE instrument token
NaiveDateTime::parse_from_str("2023-11-01 09:15:00", "%Y-%m-%d %H:%M:%S")?,
NaiveDateTime::parse_from_str("2023-11-30 15:30:00", "%Y-%m-%d %H:%M:%S")?,
Interval::Day,
);
let historical_data = client.historical_data_typed(request).await?;
println!("Historical Data for RELIANCE:");
println!("=============================");
for candle in &historical_data.candles {
println!(" {}: O:{:.2} H:{:.2} L:{:.2} C:{:.2} V:{}",
candle.date.format("%Y-%m-%d"),
candle.open,
candle.high,
candle.low,
candle.close,
candle.volume
);
}
```
### Advanced Historical Data with Options
```rust
// Intraday data with continuous flag and OI
let intraday_request = HistoricalDataRequest::new(
738561,
NaiveDateTime::parse_from_str("2023-11-20 09:00:00", "%Y-%m-%d %H:%M:%S")?,
NaiveDateTime::parse_from_str("2023-11-20 16:00:00", "%Y-%m-%d %H:%M:%S")?,
Interval::FiveMinute,
).continuous(true) // Include pre/post market
.with_oi(false); // No OI for equity
let data = client.historical_data_typed(intraday_request).await?;
// Calculate statistics
let low = prices.iter().cloned().fold(f64::INFINITY, f64::min);
let avg = prices.iter().sum::<f64>() / prices.len() as f64;
println!("Intraday Statistics:");
println!(" High: ₹{:.2}", high);
println!(" Low: ₹{:.2}", low);
println!(" Average: ₹{:.2}", avg);
println!(" Range: ₹{:.2} ({:.2}%)", high - low, ((high - low) / low) * 100.0);
```
## Mutual Funds
### MF Orders and Holdings
```rust
// Get MF orders
let mf_orders = client.mf_orders_typed().await?;
println!("Mutual Fund Orders:");
println!("===================");
for order in &mf_orders {
println!(" {}: {} units of {}",
order.order_id,
order.quantity,
order.trading_symbol
);
println!(" Status: {}, Amount: ₹{:.2}",
order.status,
order.amount.unwrap_or(0.0)
);
}
// Get MF holdings
let mf_holdings = client.mf_holdings_typed().await?;
let mut total_value = 0.0;
for holding in &mf_holdings {
let value = holding.last_price * holding.quantity;
total_value += value;
println!(" {}: {} units @ ₹{:.4}",
holding.trading_symbol,
holding.quantity,
holding.last_price
);
println!(" Value: ₹{:.2}, P&L: ₹{:.2}",
value,
holding.pnl
);
}
println!("Total MF Portfolio Value: ₹{:.2}", total_value);
```
## Error Handling
### Comprehensive Error Handling
```rust
use kiteconnect_async_wasm::models::common::KiteError;
async fn robust_trading_operation(client: &KiteConnect) -> Result<(), Box<dyn std::error::Error>> {
match client.holdings_typed().await {
Ok(holdings) => {
println!("Successfully retrieved {} holdings", holdings.len());
// Process holdings...
}
Err(KiteError::Authentication(msg)) => {
eprintln!("Authentication failed: {}", msg);
// Redirect to login or refresh token
return Err("Please re-authenticate".into());
}
Err(KiteError::Api { status, message, error_type }) => {
eprintln!("API error {}: {}", status, message);
match status.as_str() {
"429" => {
eprintln!("Rate limited - waiting before retry");
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
// Retry logic here
}
"500" | "502" | "503" => {
eprintln!("Server error - will retry");
// Implement exponential backoff
}
_ => {
eprintln!("Unhandled API error: {}", error_type.unwrap_or_default());
}
}
}
Err(KiteError::RateLimit { retry_after, .. }) => {
eprintln!("Rate limited. Retry after: {:?}", retry_after);
if let Some(delay) = retry_after {
tokio::time::sleep(delay).await;
// Retry the operation
}
}
Err(KiteError::Json(json_err)) => {
eprintln!("JSON parsing error: {}", json_err);
// This usually indicates an API change or network corruption
}
Err(KiteError::Http(http_err)) => {
eprintln!("Network error: {}", http_err);
// Check internet connection, DNS, etc.
}
Err(e) => {
eprintln!("Unexpected error: {}", e);
}
}
Ok(())
}
```
## Rate Limiting
### Understanding Rate Limits
The library automatically handles rate limiting, but understanding the limits helps optimize your application:
```rust
// Quote data: 1 request/second (most restrictive)
async fn get_multiple_quotes_safely(client: &KiteConnect) -> Result<(), Box<dyn std::error::Error>> {
let symbols = vec!["NSE:RELIANCE", "NSE:TCS", "NSE:INFY", "NSE:HDFC"];
// Option 1: Single request for multiple symbols (recommended)
let quotes = client.quote_typed(symbols).await?;
// Option 2: Multiple requests (automatically rate-limited)
// for symbol in &symbols {
// let quote = client.quote_typed(vec![symbol]).await?;
// // Library automatically waits 1 second between requests
// }
Ok(())
}
// Historical data: 3 requests/second
async fn get_historical_data_batch(client: &KiteConnect) -> Result<(), Box<dyn std::error::Error>> {
let instruments = vec![738561, 492033, 408065]; // RELIANCE, TCS, INFY
for instrument in instruments {
let request = HistoricalDataRequest::new(
instrument,
NaiveDateTime::parse_from_str("2023-11-01 09:15:00", "%Y-%m-%d %H:%M:%S")?,
NaiveDateTime::parse_from_str("2023-11-30 15:30:00", "%Y-%m-%d %H:%M:%S")?,
Interval::Day,
);
let data = client.historical_data_typed(request).await?;
// Library automatically enforces 3 req/sec limit
println!("Got {} candles for instrument {}", data.candles.len(), instrument);
}
Ok(())
}
```
## Best Practices
### 1. Connection Management
```rust
// Reuse client instances
lazy_static::lazy_static! {
static ref KITE_CLIENT: KiteConnect = {
KiteConnect::new(
std::env::var("KITE_API_KEY").expect("KITE_API_KEY not set"),
std::env::var("KITE_ACCESS_TOKEN").expect("KITE_ACCESS_TOKEN not set")
)
};
}
async fn efficient_data_access() -> Result<(), Box<dyn std::error::Error>> {
// Fetch multiple data types concurrently
let (holdings, positions, orders) = tokio::try_join!(
KITE_CLIENT.holdings_typed(),
KITE_CLIENT.positions_typed(),
KITE_CLIENT.orders_typed()
)?;
// Process results...
Ok(())
}
```
### 2. Error Recovery with Exponential Backoff
```rust
async fn retry_with_backoff<F, T>(mut operation: F, max_retries: u32) -> Result<T, Box<dyn std::error::Error>>
where
F: FnMut() -> Result<T, KiteError>,
{
let mut delay = std::time::Duration::from_millis(100);
for attempt in 0..max_retries {
match operation() {
Ok(result) => return Ok(result),
Err(KiteError::RateLimit { retry_after, .. }) => {
if let Some(delay) = retry_after {
tokio::time::sleep(delay).await;
} else {
tokio::time::sleep(delay).await;
delay *= 2; // Exponential backoff
}
}
Err(KiteError::Api { status, .. }) if status == "500" || status == "502" => {
if attempt == max_retries - 1 {
return Err("Max retries exceeded".into());
}
tokio::time::sleep(delay).await;
delay *= 2;
}
Err(e) => return Err(e.into()),
}
}
Err("Max retries exceeded".into())
}
```
### 3. Portfolio Monitoring Example
```rust
use std::collections::HashMap;
async fn monitor_portfolio(client: &KiteConnect) -> Result<(), Box<dyn std::error::Error>> {
loop {
// Get current portfolio state
let holdings = client.holdings_typed().await?;
let positions = client.positions_typed().await?;
// Build symbol list for quotes
let mut symbols = Vec::new();
for holding in &holdings {
symbols.push(format!("{}:{}", holding.exchange, holding.trading_symbol));
}
// Get live quotes
let quotes = client.quote_typed(symbols.iter().map(|s| s.as_str()).collect()).await?;
let quote_map: HashMap<_, _> = quotes.iter()
.map(|q| (q.trading_symbol.clone(), q))
.collect();
// Calculate portfolio metrics
let mut total_investment = 0.0;
let mut total_value = 0.0;
for holding in &holdings {
if let Some(quote) = quote_map.get(&holding.trading_symbol) {
let investment = holding.average_price * holding.quantity as f64;
let current_value = quote.last_price * holding.quantity as f64;
total_investment += investment;
total_value += current_value;
let pnl = current_value - investment;
let pnl_pct = (pnl / investment) * 100.0;
if pnl_pct.abs() > 5.0 {
println!("ALERT: {} moved {:.2}% (₹{:.2})",
holding.trading_symbol, pnl_pct, pnl);
}
}
}
let total_pnl = total_value - total_investment;
let total_pnl_pct = (total_pnl / total_investment) * 100.0;
println!("Portfolio: ₹{:.2} ({:.2}%) | Last update: {}",
total_pnl, total_pnl_pct, chrono::Utc::now().format("%H:%M:%S"));
// Wait before next update (respect rate limits)
tokio::time::sleep(std::time::Duration::from_secs(60)).await;
}
}
```
## Margins and Charges
- Calculate margins for orders: `calculate_order_margins` / `calculate_order_margins_typed`
- Calculate basket margins: `calculate_basket_margins` / `calculate_basket_margins_typed`
- Virtual contract note (charges): `calculate_order_charges` / `calculate_order_charges_typed`
Models: `OrderMarginRequest`, `OrderMarginResult`, `BasketMarginsData`, `OrderChargesRequest`, `OrderChargesResult`, `ChargesBreakdown`.
### Example: Order Margin Calculation
```rust
use kiteconnect_async_wasm::models::orders::OrderMarginRequest;
// Single order margin calculation
let margin_request = OrderMarginRequest {
exchange: Exchange::NSE,
tradingsymbol: "RELIANCE".to_string(),
transaction_type: TransactionType::BUY,
quantity: 10,
order_type: OrderType::LIMIT,
price: Some(2500.0),
product: Product::CNC,
validity: Validity::DAY,
};
let margin_result = client.calculate_order_margins_typed(&margin_request).await?;
println!("Margin required: ₹{:.2}", margin_result.margin_required);
// Basket margin calculation
let basket_request = vec![
OrderMarginRequest {
exchange: Exchange::NSE,
tradingsymbol: "RELIANCE".to_string(),
transaction_type: TransactionType::BUY,
quantity: 10,
order_type: OrderType::LIMIT,
price: Some(2500.0),
product: Product::CNC,
validity: Validity::DAY,
},
OrderMarginRequest {
exchange: Exchange::NSE,
tradingsymbol: "TCS".to_string(),
transaction_type: TransactionType::SELL,
quantity: 5,
order_type: OrderType::LIMIT,
price: Some(3500.0),
product: Product::CNC,
validity: Validity::DAY,
},
];
let basket_margin_result = client.calculate_basket_margins_typed(&basket_request).await?;
println!("Total basket margin required: ₹{:.2}", basket_margin_result.total_margin);
```
### Example: Order Charges Calculation
```rust
use kiteconnect_async_wasm::models::orders::OrderChargesRequest;
// Calculate charges for an order
let charges_request = OrderChargesRequest {
exchange: Exchange::NSE,
tradingsymbol: "RELIANCE".to_string(),
transaction_type: TransactionType::BUY,
quantity: 10,
order_type: OrderType::LIMIT,
price: Some(2500.0),
product: Product::CNC,
validity: Validity::DAY,
};
let charges_result = client.calculate_order_charges_typed(&charges_request).await?;
println!("Order charges: {:?}", charges_result.breakdown);
```