use serde::{Deserialize, Serialize};
use super::account::AccountPositions;
use super::common::{PingMessage, Response};
use super::order::Order;
use super::{
Balance, BarType, Depth, OrderFill, Position, QuoteFull, RiskInfo, Symbol, TickBar, TimeBar,
TradeBar, TradeOpt, VolumeBar,
};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StreamResponse {
#[serde(rename = "p", default)]
pub ping: Option<PingMessage>,
#[serde(rename = "q", default)]
pub quotes: Option<Vec<QuoteFull>>,
#[serde(rename = "d", default)]
pub depths: Option<Vec<Depth>>,
#[serde(rename = "tr", default)]
pub trades: Option<Vec<TradeOpt>>,
#[serde(rename = "o", default)]
pub orders: Option<Vec<Order>>,
#[serde(rename = "f", default)]
pub fills: Option<Vec<OrderFill>>,
#[serde(rename = "ps", default)]
pub positions: Option<Vec<Position>>,
#[serde(rename = "psa", default)]
pub all_positions: Option<Vec<AccountPositions>>,
#[serde(rename = "b", default)]
pub balance: Option<Balance>,
#[serde(rename = "ba", default)]
pub all_balances: Option<Vec<Balance>>,
#[serde(rename = "ri", default)]
pub risk: Option<RiskInfo>,
#[serde(rename = "ria", default)]
pub all_risk: Option<Vec<RiskInfo>>,
#[serde(rename = "tb", default)]
pub trade_bars: Option<Vec<TradeBar>>,
#[serde(rename = "tc", default)]
pub tick_bars: Option<Vec<TickBar>>,
#[serde(rename = "ti", default)]
pub time_bars: Option<Vec<TimeBar>>,
#[serde(rename = "vb", default)]
pub volume_bars: Option<Vec<VolumeBar>>,
#[serde(rename = "i", default)]
pub indicators: Option<Vec<IndicatorValues>>,
#[serde(rename = "r", default)]
pub notification: Option<Response>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct IndicatorValues {
#[serde(rename = "n")]
pub name: String,
#[serde(rename = "fi", default)]
pub from_index: Option<i64>,
#[serde(rename = "v", default)]
pub values: Vec<Vec<String>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct IndicatorSubscribeResponse {
#[serde(rename = "indicatorId")]
pub indicator_id: String,
#[serde(rename = "valueNames", default)]
pub value_names: Vec<String>,
#[serde(rename = "valueTypes", default)]
pub value_types: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SubscribeBarsRequest {
pub symbol: Symbol,
pub period: i32,
#[serde(rename = "barType")]
pub bar_type: BarType,
#[serde(rename = "loadSize")]
pub load_size: i32,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct StreamIdResponse {
#[serde(rename = "streamId")]
pub stream_id: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn stream_response_ping() {
let json = r#"{"p":{"ping":"keepalive"}}"#;
let sr: StreamResponse = serde_json::from_str(json).unwrap();
assert!(sr.ping.is_some());
assert!(sr.quotes.is_none());
}
#[test]
fn stream_response_quotes() {
let json = r#"{"q":[{"s":"XCME:ES.U16","l":4500.0}]}"#;
let sr: StreamResponse = serde_json::from_str(json).unwrap();
assert_eq!(sr.quotes.as_ref().unwrap().len(), 1);
assert_eq!(sr.quotes.as_ref().unwrap()[0].symbol, "XCME:ES.U16");
}
#[test]
fn stream_response_order_with_aliases() {
let json = r#"{"o":[{
"oid":"ORD001",
"a":"ACC001",
"s":"XCME:ES.U16",
"st":"NEW",
"sd":"BUY",
"q":5.0,
"ot":"2",
"dr":"0"
}]}"#;
let sr: StreamResponse = serde_json::from_str(json).unwrap();
let orders = sr.orders.unwrap();
assert_eq!(orders[0].order_id, "ORD001");
}
#[test]
fn stream_id_response() {
let json = r#"{"streamId":"550e8400-e29b-41d4-a716-446655440000"}"#;
let r: StreamIdResponse = serde_json::from_str(json).unwrap();
assert_eq!(r.stream_id, "550e8400-e29b-41d4-a716-446655440000");
}
#[test]
fn indicator_subscribe_response() {
let json = r#"{
"indicatorId":"IND001",
"valueNames":["date","open","close"],
"valueTypes":["date","number","number"]
}"#;
let r: IndicatorSubscribeResponse = serde_json::from_str(json).unwrap();
assert_eq!(r.indicator_id, "IND001");
assert_eq!(r.value_names.len(), 3);
}
}