use std::fmt;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StockQuote {
pub ask_price: Option<String>,
pub ask_size: Option<i64>,
pub venue_ask_time: Option<String>,
pub bid_price: Option<String>,
pub bid_size: Option<i64>,
pub venue_bid_time: Option<String>,
pub last_trade_price: Option<String>,
pub venue_last_trade_time: Option<String>,
pub last_extended_hours_trade_price: Option<String>,
pub last_non_reg_trade_price: Option<String>,
pub venue_last_non_reg_trade_time: Option<String>,
pub previous_close: Option<String>,
pub adjusted_previous_close: Option<String>,
pub previous_close_date: Option<String>,
pub symbol: Option<String>,
pub trading_halted: Option<bool>,
pub has_traded: Option<bool>,
pub last_trade_price_source: Option<String>,
pub last_non_reg_trade_price_source: Option<String>,
pub updated_at: Option<String>,
pub instrument: Option<String>,
pub instrument_id: Option<String>,
pub state: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Fundamentals {
pub open: Option<String>,
pub high: Option<String>,
pub low: Option<String>,
pub volume: Option<String>,
pub overnight_volume: Option<String>,
pub bounds: Option<String>,
pub market_date: Option<String>,
pub average_volume_2_weeks: Option<String>,
pub average_volume: Option<String>,
pub average_volume_30_days: Option<String>,
pub high_52_weeks: Option<String>,
pub high_52_weeks_date: Option<String>,
pub dividend_yield: Option<String>,
pub float: Option<String>,
pub low_52_weeks: Option<String>,
pub low_52_weeks_date: Option<String>,
pub market_cap: Option<String>,
pub pb_ratio: Option<String>,
pub pe_ratio: Option<String>,
pub shares_outstanding: Option<String>,
pub description: Option<String>,
pub instrument: Option<String>,
pub ceo: Option<String>,
pub headquarters_city: Option<String>,
pub headquarters_state: Option<String>,
pub sector: Option<String>,
pub industry: Option<String>,
pub num_employees: Option<i64>,
pub year_founded: Option<i64>,
pub payable_date: Option<String>,
pub ex_dividend_date: Option<String>,
pub financial_status_indicator: Option<String>,
pub financial_status_description: Option<String>,
pub symbol: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Candle {
pub begins_at: Option<String>,
pub open_price: Option<String>,
pub close_price: Option<String>,
pub high_price: Option<String>,
pub low_price: Option<String>,
pub volume: Option<i64>,
pub session: Option<String>,
pub interpolated: Option<bool>,
pub symbol: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccountTypeTradability {
pub account_type: Option<String>,
pub account_type_tradability: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Instrument {
pub id: Option<String>,
pub url: Option<String>,
pub quote: Option<String>,
pub fundamentals: Option<String>,
pub splits: Option<String>,
pub symbol: Option<String>,
pub simple_name: Option<String>,
pub name: Option<String>,
pub tradeable: Option<bool>,
pub tradability: Option<String>,
pub market: Option<String>,
pub country: Option<String>,
#[serde(rename = "type")]
pub instrument_type: Option<String>,
pub tradable_chain_id: Option<String>,
pub fractional_tradability: Option<String>,
pub state: Option<String>,
pub bloomberg_unique: Option<String>,
pub margin_initial_ratio: Option<String>,
pub maintenance_ratio: Option<String>,
pub day_trade_ratio: Option<String>,
pub list_date: Option<String>,
pub min_tick_size: Option<String>,
pub rhs_tradability: Option<String>,
pub affiliate_tradability: Option<String>,
pub short_selling_tradability: Option<String>,
pub default_collar_fraction: Option<String>,
pub ipo_access_status: Option<String>,
pub ipo_access_cob_deadline: Option<String>,
pub ipo_s1_url: Option<String>,
pub ipo_roadshow_url: Option<String>,
pub is_spac: Option<bool>,
pub is_test: Option<bool>,
pub ipo_access_supports_dsp: Option<bool>,
pub ipoa_start_date: Option<String>,
pub extended_hours_fractional_tradability: Option<bool>,
pub internal_halt_reason: Option<String>,
pub internal_halt_details: Option<String>,
pub internal_halt_sessions: Option<String>,
pub internal_halt_start_time: Option<String>,
pub internal_halt_end_time: Option<String>,
pub internal_halt_source: Option<String>,
pub all_day_tradability: Option<String>,
pub notional_estimated_quantity_decimals: Option<i64>,
pub tax_security_type: Option<String>,
pub reserved_buying_power_percent_queued: Option<String>,
pub reserved_buying_power_percent_immediate: Option<String>,
pub otc_market_tier: Option<String>,
pub car_required: Option<bool>,
pub high_risk_maintenance_ratio: Option<String>,
pub low_risk_maintenance_ratio: Option<String>,
pub default_preset_percent_limit: Option<String>,
pub affiliate: Option<String>,
pub account_type_tradabilities: Option<Vec<AccountTypeTradability>>,
pub issuer_type: Option<String>,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(rename_all = "lowercase")]
pub enum HistoricalInterval {
#[cfg_attr(feature = "clap", value(name = "5minute"))]
#[serde(rename = "5minute")]
FiveMinute,
#[cfg_attr(feature = "clap", value(name = "10minute"))]
#[serde(rename = "10minute")]
TenMinute,
Hour,
Day,
Week,
}
impl HistoricalInterval {
pub fn as_str(&self) -> &'static str {
match self {
Self::FiveMinute => "5minute",
Self::TenMinute => "10minute",
Self::Hour => "hour",
Self::Day => "day",
Self::Week => "week",
}
}
}
impl fmt::Display for HistoricalInterval {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(rename_all = "lowercase")]
pub enum HistoricalSpan {
Day,
Week,
Month,
#[cfg_attr(feature = "clap", value(name = "3month"))]
#[serde(rename = "3month")]
ThreeMonth,
Year,
#[cfg_attr(feature = "clap", value(name = "5year"))]
#[serde(rename = "5year")]
FiveYear,
}
impl HistoricalSpan {
pub fn as_str(&self) -> &'static str {
match self {
Self::Day => "day",
Self::Week => "week",
Self::Month => "month",
Self::ThreeMonth => "3month",
Self::Year => "year",
Self::FiveYear => "5year",
}
}
}
impl fmt::Display for HistoricalSpan {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(rename_all = "lowercase")]
pub enum HistoricalBounds {
Regular,
Extended,
Trading,
}
impl HistoricalBounds {
pub fn as_str(&self) -> &'static str {
match self {
Self::Regular => "regular",
Self::Extended => "extended",
Self::Trading => "trading",
}
}
}
impl fmt::Display for HistoricalBounds {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone)]
pub struct HistoricalOpts {
pub interval: HistoricalInterval,
pub span: HistoricalSpan,
pub bounds: HistoricalBounds,
}
#[derive(Deserialize)]
pub struct HistoricalDataPoints {
pub symbol: Option<String>,
pub data_points: Vec<Candle>,
}
#[derive(serde::Deserialize)]
pub struct HistoricalsResult {
pub symbol: Option<String>,
pub historicals: Vec<Candle>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IndexQuoteWrapper {
pub status: Option<String>,
pub data: IndexQuoteInner,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IndexQuoteInner {
pub status: Option<String>,
pub data: IndexQuote,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IndexQuote {
pub symbol: Option<String>,
pub value: Option<String>,
pub venue_timestamp: Option<String>,
pub instrument_id: Option<String>,
pub state: Option<String>,
pub updated_at: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IndexInstrument {
pub id: Option<String>,
pub symbol: Option<String>,
pub tradable_chain_ids: Option<Vec<String>>,
}
#[cfg(test)]
mod historical_serde_tests {
use super::{HistoricalBounds, HistoricalInterval, HistoricalSpan};
#[test]
fn interval_serde_matches_as_str() {
for v in [
HistoricalInterval::FiveMinute,
HistoricalInterval::TenMinute,
HistoricalInterval::Hour,
HistoricalInterval::Day,
HistoricalInterval::Week,
] {
let json = serde_json::to_string(&v).unwrap();
assert_eq!(json, format!("\"{}\"", v.as_str()));
let back: HistoricalInterval = serde_json::from_str(&json).unwrap();
assert_eq!(back.as_str(), v.as_str());
}
}
#[test]
fn span_serde_matches_as_str() {
for v in [
HistoricalSpan::Day,
HistoricalSpan::Week,
HistoricalSpan::Month,
HistoricalSpan::ThreeMonth,
HistoricalSpan::Year,
HistoricalSpan::FiveYear,
] {
let json = serde_json::to_string(&v).unwrap();
assert_eq!(json, format!("\"{}\"", v.as_str()));
}
}
#[test]
fn bounds_serde_matches_as_str() {
for v in [
HistoricalBounds::Regular,
HistoricalBounds::Extended,
HistoricalBounds::Trading,
] {
let json = serde_json::to_string(&v).unwrap();
assert_eq!(json, format!("\"{}\"", v.as_str()));
}
}
}