Async client for the Kite Connect WebSocket API
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add ticker unit tests

+165 -5
+2
Cargo.toml
··· 25 25 26 26 [dev-dependencies] 27 27 tokio = { version = "1", features = ["test-util"] } 28 + chrono = { version = "0.4.31", features = ["serde"] } 29 + base64 = "0.21.5"
+2 -2
src/models/depth.rs
··· 2 2 3 3 use super::{value, price, value_short}; 4 4 5 - #[derive(Debug, Clone, Default)] 5 + #[derive(Debug, Clone, Default, PartialEq)] 6 6 /// 7 7 /// Market depth packet structure 8 8 /// ··· 36 36 } 37 37 } 38 38 39 - #[derive(Debug, Clone, Default)] 39 + #[derive(Debug, Clone, Default, PartialEq)] 40 40 /// 41 41 /// Structure for each market depth entry 42 42 ///
+1 -1
src/models/exchange.rs
··· 1 - #[derive(Debug, Clone, Default)] 1 + #[derive(Debug, Clone, Default, PartialEq)] 2 2 /// 3 3 /// Exchange options 4 4 ///
+1 -1
src/models/ohlc.rs
··· 2 2 3 3 use super::price; 4 4 5 - #[derive(Debug, Clone, Default)] 5 + #[derive(Debug, Clone, Default, PartialEq)] 6 6 /// 7 7 /// OHLC packet structure 8 8 ///
+1 -1
src/models/tick.rs
··· 4 4 5 5 use super::{price, value}; 6 6 7 - #[derive(Debug, Clone, Default)] 7 + #[derive(Debug, Clone, Default, PartialEq)] 8 8 /// 9 9 /// Quote packet structure 10 10 ///
+158
src/ticker.rs
··· 270 270 self.ticker.close().await 271 271 } 272 272 } 273 + 274 + #[cfg(test)] 275 + mod tests { 276 + use std::time::Duration; 277 + 278 + use base64::{engine::general_purpose, Engine}; 279 + 280 + use crate::{DepthItem, Mode, Tick, OHLC}; 281 + 282 + fn load_packet(name: &str) -> Vec<u8> { 283 + let str = 284 + std::fs::read_to_string(format!("kiteconnect-mocks/{}.packet", name)) 285 + .map(|s| s.trim().to_string()) 286 + .expect("could not read file"); 287 + let ret = general_purpose::STANDARD 288 + .decode(str) 289 + .expect("could not decode"); 290 + ret 291 + } 292 + 293 + fn setup() -> Vec<(&'static str, Vec<u8>, Tick)> { 294 + vec![ 295 + ( 296 + "quote packet", 297 + load_packet("ticker_quote"), 298 + Tick { 299 + mode: Mode::Quote, 300 + exchange: crate::Exchange::NSE, 301 + instrument_token: 408065, 302 + is_tradable: true, 303 + is_index: false, 304 + last_traded_timestamp: None, 305 + exchange_timestamp: None, 306 + last_price: Some(1573.15), 307 + avg_traded_price: Some(1570.33), 308 + last_traded_qty: Some(1), 309 + total_buy_qty: Some(256511), 310 + total_sell_qty: Some(360503), 311 + volume_traded: Some(1175986), 312 + ohlc: Some(OHLC { 313 + open: 1569.15, 314 + high: 1575.0, 315 + low: 1561.05, 316 + close: 1567.8, 317 + }), 318 + oi_day_high: None, 319 + oi_day_low: None, 320 + oi: None, 321 + net_change: None, 322 + depth: None, 323 + }, 324 + ), 325 + ( 326 + "full packet", 327 + load_packet("ticker_full"), 328 + Tick { 329 + mode: Mode::Full, 330 + exchange: crate::Exchange::NSE, 331 + instrument_token: 408065, 332 + is_tradable: true, 333 + is_index: false, 334 + last_traded_timestamp: Some(Duration::from_secs( 335 + chrono::DateTime::parse_from_rfc3339("2021-07-05T10:41:27+05:30") 336 + .unwrap() 337 + .timestamp() as u64, 338 + )), 339 + exchange_timestamp: Some(Duration::from_secs( 340 + chrono::DateTime::parse_from_rfc3339("2021-07-05T10:41:27+05:30") 341 + .unwrap() 342 + .timestamp() as u64, 343 + )), 344 + last_price: Some(1573.7), 345 + avg_traded_price: Some(1570.37), 346 + last_traded_qty: Some(7), 347 + total_buy_qty: Some(256443), 348 + total_sell_qty: Some(363009), 349 + volume_traded: Some(1192471), 350 + ohlc: Some(OHLC { 351 + open: 1569.15, 352 + high: 1575.0, 353 + low: 1561.05, 354 + close: 1567.8, 355 + }), 356 + oi_day_high: Some(0), 357 + oi_day_low: Some(0), 358 + oi: Some(0), 359 + net_change: Some(5.900000000000091), 360 + depth: Some(crate::Depth { 361 + buy: [ 362 + DepthItem { 363 + qty: 5, 364 + price: 1573.4, 365 + orders: 1, 366 + }, 367 + DepthItem { 368 + qty: 140, 369 + price: 1573.0, 370 + orders: 2, 371 + }, 372 + DepthItem { 373 + qty: 2, 374 + price: 1572.95, 375 + orders: 1, 376 + }, 377 + DepthItem { 378 + qty: 219, 379 + price: 1572.9, 380 + orders: 7, 381 + }, 382 + DepthItem { 383 + qty: 50, 384 + price: 1572.85, 385 + orders: 1, 386 + }, 387 + ], 388 + sell: [ 389 + DepthItem { 390 + qty: 172, 391 + price: 1573.7, 392 + orders: 3, 393 + }, 394 + DepthItem { 395 + qty: 44, 396 + price: 1573.75, 397 + orders: 3, 398 + }, 399 + DepthItem { 400 + qty: 302, 401 + price: 1573.85, 402 + orders: 3, 403 + }, 404 + DepthItem { 405 + qty: 141, 406 + price: 1573.9, 407 + orders: 2, 408 + }, 409 + DepthItem { 410 + qty: 724, 411 + price: 1573.95, 412 + orders: 5, 413 + }, 414 + ], 415 + }), 416 + }, 417 + ), 418 + ] 419 + } 420 + 421 + #[test] 422 + fn test_quotes() { 423 + let data = setup(); 424 + for (name, packet, expected) in data { 425 + let tick = Tick::try_from(packet.as_slice()); 426 + assert_eq!(tick.is_err(), false); 427 + assert_eq!(tick.unwrap(), expected, "Testing {}", name); 428 + } 429 + } 430 + }