use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct IndexQuote {
pub symbol: String,
pub name: Option<String>,
pub price: Option<f64>,
pub change: Option<f64>,
pub change_percent: Option<f64>,
pub timestamp: Option<i64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum MajorIndex {
Sp500,
Nasdaq100,
DowJones,
}
impl MajorIndex {
pub fn as_str(self) -> &'static str {
match self {
Self::Sp500 => "sp500",
Self::Nasdaq100 => "nasdaq100",
Self::DowJones => "dowjones",
}
}
pub fn from_symbol(symbol: &str) -> Option<Self> {
let s: String = symbol
.trim()
.trim_start_matches('^')
.chars()
.filter(|c| !c.is_whitespace() && *c != '&' && *c != '-')
.collect::<String>()
.to_ascii_lowercase();
match s.as_str() {
"gspc" | "spx" | "sp500" => Some(Self::Sp500),
"ndx" | "nasdaq100" => Some(Self::Nasdaq100),
"dji" | "djia" | "dowjones" | "dow" | "dowjones30" => Some(Self::DowJones),
_ => None,
}
}
}
impl std::fmt::Display for MajorIndex {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct IndexConstituent {
pub symbol: String,
pub name: Option<String>,
pub sector: Option<String>,
pub sub_sector: Option<String>,
pub headquarters: Option<String>,
pub date_first_added: Option<String>,
pub cik: Option<String>,
pub founded: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct IndexConstituentChange {
pub date: Option<String>,
pub symbol: Option<String>,
pub added_security: Option<String>,
pub removed_ticker: Option<String>,
pub removed_security: Option<String>,
pub reason: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn major_index_maps_common_symbols() {
for s in ["^GSPC", "GSPC", "SPX", "sp500", "S&P 500"] {
assert_eq!(MajorIndex::from_symbol(s), Some(MajorIndex::Sp500), "{s}");
}
for s in ["^NDX", "ndx", "NASDAQ 100", "nasdaq100"] {
assert_eq!(
MajorIndex::from_symbol(s),
Some(MajorIndex::Nasdaq100),
"{s}"
);
}
for s in ["^DJI", "DJIA", "dow", "Dow Jones"] {
assert_eq!(
MajorIndex::from_symbol(s),
Some(MajorIndex::DowJones),
"{s}"
);
}
assert_eq!(MajorIndex::from_symbol("AAPL"), None);
assert_eq!(MajorIndex::from_symbol("^IXIC"), None);
}
}