use std::collections::HashMap;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use crate::data::enums::{Exchange, NewsImageSize};
use crate::types::serde_util::string_or_list;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Bar {
#[serde(default, skip_deserializing)]
pub symbol: String,
#[serde(rename = "t", with = "crate::types::timestamp")]
pub timestamp: DateTime<Utc>,
#[serde(rename = "o")]
pub open: f64,
#[serde(rename = "h")]
pub high: f64,
#[serde(rename = "l")]
pub low: f64,
#[serde(rename = "c")]
pub close: f64,
#[serde(rename = "v")]
pub volume: f64,
#[serde(rename = "n", default)]
pub trade_count: Option<f64>,
#[serde(rename = "vw", default)]
pub vwap: Option<f64>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Quote {
#[serde(default, skip_deserializing)]
pub symbol: String,
#[serde(rename = "t", with = "crate::types::timestamp")]
pub timestamp: DateTime<Utc>,
#[serde(rename = "bp")]
pub bid_price: f64,
#[serde(rename = "bs")]
pub bid_size: f64,
#[serde(rename = "bx", default)]
pub bid_exchange: Option<Exchange>,
#[serde(rename = "ap")]
pub ask_price: f64,
#[serde(rename = "as")]
pub ask_size: f64,
#[serde(rename = "ax", default)]
pub ask_exchange: Option<Exchange>,
#[serde(rename = "c", default, deserialize_with = "string_or_list")]
pub conditions: Option<Vec<String>>,
#[serde(rename = "z", default)]
pub tape: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Trade {
#[serde(default, skip_deserializing)]
pub symbol: String,
#[serde(rename = "t", with = "crate::types::timestamp")]
pub timestamp: DateTime<Utc>,
#[serde(rename = "x", default)]
pub exchange: Option<Exchange>,
#[serde(rename = "p")]
pub price: f64,
#[serde(rename = "s")]
pub size: f64,
#[serde(rename = "i", default)]
pub id: Option<i64>,
#[serde(rename = "c", default, deserialize_with = "string_or_list")]
pub conditions: Option<Vec<String>>,
#[serde(rename = "z", default)]
pub tape: Option<String>,
#[serde(rename = "tks", default)]
pub taker_side: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct TradingStatus {
#[serde(default, skip_deserializing)]
pub symbol: String,
#[serde(rename = "t", with = "crate::types::timestamp")]
pub timestamp: DateTime<Utc>,
#[serde(rename = "sc")]
pub status_code: String,
#[serde(rename = "sm")]
pub status_message: String,
#[serde(rename = "rc")]
pub reason_code: String,
#[serde(rename = "rm")]
pub reason_message: String,
#[serde(rename = "z")]
pub tape: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct TradeCancel {
#[serde(default, skip_deserializing)]
pub symbol: String,
#[serde(rename = "t", with = "crate::types::timestamp")]
pub timestamp: DateTime<Utc>,
#[serde(rename = "x")]
pub exchange: Exchange,
#[serde(rename = "p")]
pub price: f64,
#[serde(rename = "s")]
pub size: f64,
#[serde(rename = "i", default)]
pub id: Option<i64>,
#[serde(rename = "a", default)]
pub action: Option<String>,
#[serde(rename = "z")]
pub tape: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct TradeCorrection {
#[serde(default, skip_deserializing)]
pub symbol: String,
#[serde(rename = "t", with = "crate::types::timestamp")]
pub timestamp: DateTime<Utc>,
#[serde(rename = "x")]
pub exchange: Exchange,
#[serde(rename = "oi", default)]
pub original_id: Option<i64>,
#[serde(rename = "op")]
pub original_price: f64,
#[serde(rename = "os")]
pub original_size: f64,
#[serde(rename = "oc", default)]
pub original_conditions: Vec<String>,
#[serde(rename = "ci", default)]
pub corrected_id: Option<i64>,
#[serde(rename = "cp")]
pub corrected_price: f64,
#[serde(rename = "cs")]
pub corrected_size: f64,
#[serde(rename = "cc", default)]
pub corrected_conditions: Vec<String>,
#[serde(rename = "z")]
pub tape: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Auction {
#[serde(rename = "t", with = "crate::types::timestamp")]
pub timestamp: DateTime<Utc>,
#[serde(rename = "x")]
pub exchange: Exchange,
#[serde(rename = "p")]
pub price: f64,
#[serde(rename = "s", default)]
pub size: Option<f64>,
#[serde(rename = "c")]
pub condition: String,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct DailyAuctions {
#[serde(default, skip_deserializing)]
pub symbol: String,
#[serde(rename = "d")]
pub date: chrono::NaiveDate,
#[serde(rename = "o", default)]
pub opening: Vec<Auction>,
#[serde(rename = "c", default)]
pub closing: Vec<Auction>,
}
pub type AuctionSet = HashMap<String, Vec<DailyAuctions>>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct ForexRate {
#[serde(default, skip_deserializing)]
pub currency_pair: String,
#[serde(rename = "t", with = "crate::types::timestamp")]
pub timestamp: DateTime<Utc>,
#[serde(rename = "bp")]
pub bid_price: f64,
#[serde(rename = "mp")]
pub mid_price: f64,
#[serde(rename = "ap")]
pub ask_price: f64,
}
fn epoch() -> DateTime<Utc> {
DateTime::from_timestamp(0, 0).unwrap_or_default()
}
impl Default for Bar {
fn default() -> Self {
Self {
symbol: String::new(),
timestamp: epoch(),
open: 0.0,
high: 0.0,
low: 0.0,
close: 0.0,
volume: 0.0,
trade_count: None,
vwap: None,
}
}
}
impl Default for Quote {
fn default() -> Self {
Self {
symbol: String::new(),
timestamp: epoch(),
bid_price: 0.0,
bid_size: 0.0,
bid_exchange: None,
ask_price: 0.0,
ask_size: 0.0,
ask_exchange: None,
conditions: None,
tape: None,
}
}
}
impl Default for Trade {
fn default() -> Self {
Self {
symbol: String::new(),
timestamp: epoch(),
exchange: None,
price: 0.0,
size: 0.0,
id: None,
conditions: None,
tape: None,
taker_side: None,
}
}
}
impl Default for Auction {
fn default() -> Self {
Self {
timestamp: epoch(),
exchange: Exchange::Unknown(String::new()),
price: 0.0,
size: None,
condition: String::new(),
}
}
}
impl Default for Orderbook {
fn default() -> Self {
Self {
symbol: String::new(),
timestamp: epoch(),
bids: Vec::new(),
asks: Vec::new(),
reset: false,
}
}
}
impl Default for ForexRate {
fn default() -> Self {
Self {
currency_pair: String::new(),
timestamp: epoch(),
bid_price: 0.0,
mid_price: 0.0,
ask_price: 0.0,
}
}
}
pub type ForexRateSet = HashMap<String, Vec<ForexRate>>;
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct OrderbookQuote {
#[serde(rename = "p")]
pub price: f64,
#[serde(rename = "s")]
pub size: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Orderbook {
#[serde(default, skip_deserializing)]
pub symbol: String,
#[serde(rename = "t", with = "crate::types::timestamp")]
pub timestamp: DateTime<Utc>,
#[serde(rename = "b", default)]
pub bids: Vec<OrderbookQuote>,
#[serde(rename = "a", default)]
pub asks: Vec<OrderbookQuote>,
#[serde(rename = "r", default)]
pub reset: bool,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Snapshot {
#[serde(default, skip_deserializing)]
pub symbol: String,
#[serde(rename = "latestTrade", default)]
pub latest_trade: Option<Trade>,
#[serde(rename = "latestQuote", default)]
pub latest_quote: Option<Quote>,
#[serde(rename = "minuteBar", default)]
pub minute_bar: Option<Bar>,
#[serde(rename = "dailyBar", default)]
pub daily_bar: Option<Bar>,
#[serde(rename = "prevDailyBar", default)]
pub previous_daily_bar: Option<Bar>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct OptionsGreeks {
pub delta: f64,
pub gamma: f64,
pub rho: f64,
pub theta: f64,
pub vega: f64,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct OptionsSnapshot {
#[serde(default, skip_deserializing)]
pub symbol: String,
#[serde(rename = "latestTrade", default)]
pub latest_trade: Option<Trade>,
#[serde(rename = "latestQuote", default)]
pub latest_quote: Option<Quote>,
#[serde(rename = "impliedVolatility", default)]
pub implied_volatility: Option<f64>,
#[serde(default)]
pub greeks: Option<OptionsGreeks>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct NewsImage {
pub size: NewsImageSize,
pub url: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct News {
pub id: i64,
pub headline: String,
pub source: String,
#[serde(default)]
pub url: Option<String>,
#[serde(default)]
pub summary: String,
#[serde(with = "crate::types::timestamp")]
pub created_at: DateTime<Utc>,
#[serde(with = "crate::types::timestamp")]
pub updated_at: DateTime<Utc>,
#[serde(
default,
deserialize_with = "crate::types::serde_util::null_as_default"
)]
pub symbols: Vec<String>,
#[serde(default)]
pub author: String,
#[serde(default)]
pub content: String,
#[serde(default)]
pub images: Option<Vec<NewsImage>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct NewsSet {
#[serde(
default,
deserialize_with = "crate::types::serde_util::null_as_default"
)]
pub news: Vec<News>,
#[serde(default)]
pub next_page_token: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct ActiveStock {
pub symbol: String,
pub volume: f64,
pub trade_count: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct MostActives {
pub most_actives: Vec<ActiveStock>,
pub last_updated: DateTime<Utc>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Mover {
pub symbol: String,
pub percent_change: f64,
pub change: f64,
pub price: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Movers {
pub gainers: Vec<Mover>,
pub losers: Vec<Mover>,
pub market_type: crate::data::enums::MarketType,
pub last_updated: DateTime<Utc>,
}
pub type BarSet = HashMap<String, Vec<Bar>>;
pub type QuoteSet = HashMap<String, Vec<Quote>>;
pub type TradeSet = HashMap<String, Vec<Trade>>;
pub(crate) trait WithSymbol {
fn set_symbol(&mut self, symbol: &str);
}
macro_rules! impl_with_symbol {
($($ty:ty),+ $(,)?) => {
$(
impl WithSymbol for $ty {
fn set_symbol(&mut self, symbol: &str) {
self.symbol = symbol.to_owned();
}
}
)+
};
}
impl_with_symbol!(
Bar,
Quote,
Trade,
TradingStatus,
TradeCancel,
TradeCorrection,
Orderbook,
DailyAuctions,
);
impl WithSymbol for ForexRate {
fn set_symbol(&mut self, symbol: &str) {
self.currency_pair = symbol.to_owned();
}
}
impl WithSymbol for Snapshot {
fn set_symbol(&mut self, symbol: &str) {
self.symbol = symbol.to_owned();
if let Some(trade) = &mut self.latest_trade {
trade.set_symbol(symbol);
}
if let Some(quote) = &mut self.latest_quote {
quote.set_symbol(symbol);
}
for bar in [
self.minute_bar.as_mut(),
self.daily_bar.as_mut(),
self.previous_daily_bar.as_mut(),
]
.into_iter()
.flatten()
{
bar.set_symbol(symbol);
}
}
}
impl WithSymbol for OptionsSnapshot {
fn set_symbol(&mut self, symbol: &str) {
self.symbol = symbol.to_owned();
if let Some(trade) = &mut self.latest_trade {
trade.set_symbol(symbol);
}
if let Some(quote) = &mut self.latest_quote {
quote.set_symbol(symbol);
}
}
}