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
//! # KiteTicker Async Manager
//!
//! High-performance async WebSocket client for the [Kite Connect API](https://kite.trade/docs/connect/v3/websocket/#websocket-streaming)
//! with multi-connection support and dynamic subscription management.
//!
//! ## Features
//!
//! - **๐ Multi-Connection Support** - Utilize all 3 allowed WebSocket connections (9,000 symbol capacity)
//! - **โก High Performance** - Dedicated parser tasks, optimized buffers, sub-microsecond latency
//! - **๐ Dynamic Subscriptions** - Add/remove symbols at runtime without reconnection
//! - **๐ Load Balancing** - Automatic symbol distribution across connections
//! - **๐ช Production Ready** - Comprehensive error handling, health monitoring, reconnection
//! - **๐ง Async-First Design** - Built with Tokio, follows Rust async best practices
//!
//! ## Quick Start
//!
//! ### Multi-Connection Manager (Recommended)
//!
//! Using the builder:
//!
//! ```rust,no_run
//! use kiteticker_async_manager::{KiteTickerManagerBuilder, Mode};
//! #[tokio::main]
//! async fn main() -> Result<(), String> {
//! let api_key = std::env::var("KITE_API_KEY").unwrap();
//! let access_token = std::env::var("KITE_ACCESS_TOKEN").unwrap();
//! let mut manager = KiteTickerManagerBuilder::new(api_key, access_token)
//! .max_connections(3)
//! .max_symbols_per_connection(3000)
//! .raw_only(true) // receive only raw frames if desired
//! .default_mode(Mode::Quote)
//! .enable_dedicated_parsers(true)
//! .build();
//! manager.start().await?;
//! Ok(())
//! }
//! ```
//!
//! ```rust,no_run
//! use kiteticker_async_manager::{KiteTickerManager, KiteManagerConfig, Mode, TickerMessage};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), String> {
//! // Setup credentials
//! let api_key = std::env::var("KITE_API_KEY").unwrap();
//! let access_token = std::env::var("KITE_ACCESS_TOKEN").unwrap();
//!
//! // Create high-performance manager
//! let config = KiteManagerConfig {
//! max_connections: 3,
//! max_symbols_per_connection: 3000,
//! enable_dedicated_parsers: true,
//! default_mode: Mode::LTP,
//! ..Default::default()
//! };
//!
//! // Start manager
//! let mut manager = KiteTickerManager::new(api_key, access_token, config);
//! manager.start().await?;
//!
//! // Subscribe to symbols (automatically distributed)
//! let symbols = vec![256265, 408065, 738561]; // NIFTY 50, HDFC Bank, Reliance
//! manager.subscribe_symbols(&symbols, Some(Mode::Quote)).await?;
//!
//! // Process data from independent channels
//! let channels = manager.get_all_channels();
//! for (channel_id, mut receiver) in channels {
//! tokio::spawn(async move {
//! while let Ok(message) = receiver.recv().await {
//! if let TickerMessage::Ticks(ticks) = message {
//! for tick in ticks {
//! println!("Channel {:?}: {} @ โน{:.2}",
//! channel_id,
//! tick.instrument_token,
//! tick.content.last_price.unwrap_or(0.0));
//! }
//! }
//! }
//! });
//! }
//!
//! // Dynamic operations
//! manager.subscribe_symbols(&[5633, 884737], Some(Mode::Full)).await?; // Add
//! manager.unsubscribe_symbols(&[408065]).await?; // Remove
//! manager.change_mode(&[256265], Mode::Full).await?; // Change mode
//!
//! Ok(())
//! }
//! ```
//!
//! ### Single Connection Usage
//!
//! ```rust,no_run
//! use kiteticker_async_manager::{KiteTickerAsync, Mode, TickerMessage};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), String> {
//! let api_key = std::env::var("KITE_API_KEY").unwrap();
//! let access_token = std::env::var("KITE_ACCESS_TOKEN").unwrap();
//!
//! // Connect to WebSocket
//! let mut ticker = KiteTickerAsync::connect(&api_key, &access_token).await?;
//!
//! // Subscribe to symbols
//! let symbols = vec![256265, 408065]; // NIFTY 50, HDFC Bank
//! let mut subscriber = ticker.subscribe(&symbols, Some(Mode::LTP)).await?;
//!
//! // Receive data
//! while let Ok(Some(message)) = subscriber.next_message().await {
//! if let TickerMessage::Ticks(ticks) = message {
//! for tick in ticks {
//! println!("Symbol {}: โน{:.2}",
//! tick.instrument_token,
//! tick.content.last_price.unwrap_or(0.0));
//! }
//! }
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! ## Performance Comparison
//!
//! | Feature | Single Connection | Multi-Connection Manager | Improvement |
//! |---------|------------------|---------------------------|-------------|
//! | **Max Symbols** | 3,000 | 9,000 | **3x capacity** |
//! | **Throughput** | Limited by 1 connection | 3 parallel connections | **3x throughput** |
//! | **Latency** | ~5-10ยตs | ~1-2ยตs | **5x faster** |
//! | **Resilience** | Single point of failure | 3 independent connections | **High availability** |
//! | **Dynamic Ops** | Manual reconnection | Runtime add/remove | **Zero downtime** |
//!
//! ## Architecture
//!
//! The library provides two main components:
//!
//! ### 1. `KiteTickerAsync` - Single WebSocket Connection
//! - Direct WebSocket client for simple use cases
//! - Up to 3,000 symbols per connection
//! - Manual connection management
//!
//! ### 2. `KiteTickerManager` - Multi-Connection Manager (Recommended)
//! - Manages up to 3 WebSocket connections automatically
//! - Supports up to 9,000 symbols total
//! - Dynamic subscription management
//! - Load balancing and health monitoring
//! - High-performance optimizations
//!
//! ## Subscription Modes
//!
//! The library supports three subscription modes:
//!
//! - **`Mode::LTP`** - Last traded price only (minimal bandwidth)
//! - **`Mode::Quote`** - Price + volume + OHLC (standard data)
//! - **`Mode::Full`** - Complete market depth (maximum data)
//!
//! ## Zero-copy raw access (advanced)
//!
//! For maximum throughput and minimal allocations, you can work directly with the raw
//! WebSocket frame bytes and view individual packets using zero-copy, endian-safe types.
//! This is fully safe and avoids undefined behavior by using `zerocopy::Ref` and
//! big-endian field wrappers.
//!
//! Key points:
//! - Subscribe to raw frames via `KiteTickerAsync::subscribe_raw_frames()` or
//! `KiteTickerManager::get_raw_frame_channel(ChannelId)` / `get_all_raw_frame_channels()`,
//! which yield `bytes::Bytes` frames.
//! - Extract packet bodies (length-prefixed) from a frame and select the size you need.
//! - Use helpers like `as_tick_raw`, `as_index_quote_32`, and `as_inst_header_64` to obtain
//! `zerocopy::Ref<&[u8], T>` that dereferences to a typed view.
//! - The `Ref` is valid as long as the backing bytes live; examples store `Bytes` to keep it alive.
//!
//! Example (snippets):
//! ```rust,no_run
//! use kiteticker_async_manager::{KiteTickerAsync, Mode, as_tick_raw};
//! use bytes::Bytes;
//!
//! # #[tokio::main]
//! # async fn main() -> Result<(), String> {
//! let api_key = std::env::var("KITE_API_KEY").unwrap();
//! let access_token = std::env::var("KITE_ACCESS_TOKEN").unwrap();
//! let mut ticker = KiteTickerAsync::connect_with_options(&api_key, &access_token, true).await?;
//! let _sub = ticker.subscribe(&[256265], Some(Mode::Full)).await?;
//! let mut frames = ticker.subscribe_raw_frames();
//!
//! // Receive a frame and pull out a 184-byte Full packet body
//! let frame: Bytes = frames.recv().await.unwrap();
//! let num = u16::from_be_bytes([frame[0], frame[1]]) as usize;
//! let mut off = 2usize;
//! for _ in 0..num {
//! let len = u16::from_be_bytes([frame[off], frame[off+1]]) as usize;
//! let body = frame.slice(off+2..off+2+len);
//! if len == 184 {
//! if let Some(view_ref) = as_tick_raw(&body) {
//! let tick = &*view_ref; // &TickRaw
//! let token = tick.header.instrument_token.get();
//! let ltp_scaled = tick.header.last_price.get();
//! // ... use fields ...
//! }
//! }
//! off += 2 + len;
//! }
//! # Ok(()) }
//! ```
//!
//! Manager-level example (per-connection frames):
//! ```rust,no_run
//! use kiteticker_async_manager::{KiteTickerManagerBuilder, Mode, as_tick_raw};
//! # #[tokio::main]
//! # async fn main() -> Result<(), String> {
//! let api_key = std::env::var("KITE_API_KEY").unwrap();
//! let access_token = std::env::var("KITE_ACCESS_TOKEN").unwrap();
//! let mut mgr = KiteTickerManagerBuilder::new(api_key, access_token)
//! .raw_only(true)
//! .build();
//! mgr.start().await?;
//! mgr.subscribe_symbols(&[256265], Some(Mode::Full)).await?;
//! for (id, mut rx) in mgr.get_all_raw_frame_channels() {
//! tokio::spawn(async move {
//! while let Ok(frame) = rx.recv().await {
//! if frame.len() < 2 { continue; }
//! let mut off = 2usize;
//! let num = u16::from_be_bytes([frame[0], frame[1]]) as usize;
//! for _ in 0..num {
//! if off + 2 > frame.len() { break; }
//! let len = u16::from_be_bytes([frame[off], frame[off+1]]) as usize;
//! let body = frame.slice(off+2..off+2+len);
//! if len == 184 {
//! if let Some(view) = as_tick_raw(&body) {
//! let token = view.header.instrument_token.get();
//! let _ = (id, token);
//! }
//! }
//! off += 2 + len;
//! }
//! }
//! });
//! }
//! # Ok(()) }
//! ```
//!
//! Safety model: all raw structs derive `Unaligned` and use `big_endian` wrappers for integer fields.
//! `as_*` helpers return `Option<zerocopy::Ref<&[u8], T>>` which validates size and alignment. No `unsafe` is required.
//!
//! ## Examples
//!
//! See the [examples directory](https://github.com/SPRAGE/kiteticker-async-manager/tree/main/examples) for:
//!
//! - **Basic Examples** - Simple usage patterns
//! - **Advanced Examples** - Complex multi-connection scenarios
//! - **Performance Examples** - Optimization and benchmarking
//!
//! ## Documentation
//!
//! - [Getting Started Guide](https://github.com/SPRAGE/kiteticker-async-manager/blob/main/docs/guides/getting-started.md)
//! - [API Reference](https://github.com/SPRAGE/kiteticker-async-manager/tree/main/docs/api)
//! - [Dynamic Subscriptions](https://github.com/SPRAGE/kiteticker-async-manager/blob/main/docs/guides/DYNAMIC_SUBSCRIPTION_GUIDE.md)
//! - [Performance Guide](https://github.com/SPRAGE/kiteticker-async-manager/blob/main/docs/guides/PERFORMANCE_IMPROVEMENTS.md)
pub use ParseTickError;
pub use ;
pub use ;
pub use ;
pub use ;
// Expose the raw 184-byte subscriber helper
pub use KiteTickerRawSubscriber184;