use crate::{
Client, Result,
endpoints::{
EndpointSpec, QueryEncoder, QueryParameters,
metadata::{EndpointBounds, EndpointMetadata, GeographicAvailability},
},
responses::{
chart::{StockChartFullBar, StockChartIntradayBar, StockChartLightBar},
indexes::{HistoricalIndexConstituent, IndexConstituent, IndexListing},
quote::{Quote, QuoteShort},
},
types::{Date, Ticker},
};
pub use super::quote::{QuoteQuery, QuoteShortQuery, ShortOnlyQuery};
const WORLDWIDE: EndpointMetadata =
EndpointMetadata::new().with_geography(GeographicAvailability::Worldwide);
const WORLDWIDE_EOD: EndpointMetadata =
WORLDWIDE.with_bounds(EndpointBounds::new().with_response_rows(5_000));
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum IndexKind {
Sp500,
Nasdaq,
DowJones,
}
impl IndexKind {
const fn constituent_path(self) -> &'static str {
match self {
Self::Sp500 => "sp500-constituent",
Self::Nasdaq => "nasdaq-constituent",
Self::DowJones => "dowjones-constituent",
}
}
const fn historical_constituent_path(self) -> &'static str {
match self {
Self::Sp500 => "historical-sp500-constituent",
Self::Nasdaq => "historical-nasdaq-constituent",
Self::DowJones => "historical-dowjones-constituent",
}
}
}
fn constituents(kind: IndexKind) -> EndpointSpec<(), Vec<IndexConstituent>> {
let path = kind.constituent_path();
EndpointSpec::get(path, path, ())
}
fn historical_constituents(kind: IndexKind) -> EndpointSpec<(), Vec<HistoricalIndexConstituent>> {
let path = kind.historical_constituent_path();
EndpointSpec::get(path, path, ())
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IndexChartQuery {
symbol: Ticker,
from: Option<Date>,
to: Option<Date>,
}
impl IndexChartQuery {
pub fn new(symbol: Ticker) -> Self {
Self {
symbol,
from: None,
to: None,
}
}
pub const fn with_from(mut self, from: Date) -> Self {
self.from = Some(from);
self
}
pub const fn with_to(mut self, to: Date) -> Self {
self.to = Some(to);
self
}
pub const fn symbol(&self) -> &Ticker {
&self.symbol
}
pub const fn from(&self) -> Option<Date> {
self.from
}
pub const fn to(&self) -> Option<Date> {
self.to
}
}
impl From<Ticker> for IndexChartQuery {
fn from(symbol: Ticker) -> Self {
Self::new(symbol)
}
}
impl From<&Ticker> for IndexChartQuery {
fn from(symbol: &Ticker) -> Self {
Self::new(symbol.clone())
}
}
impl QueryParameters for IndexChartQuery {
fn encode(&self, encoder: &mut QueryEncoder<'_>) {
encoder.required("symbol", &self.symbol);
encoder.optional("from", self.from);
encoder.optional("to", self.to);
}
}
pub fn index_list() -> EndpointSpec<(), Vec<IndexListing>> {
EndpointSpec::get("index-list", "index-list", ()).with_metadata(WORLDWIDE)
}
pub fn index_quote(query: QuoteQuery) -> EndpointSpec<QuoteQuery, Vec<Quote>> {
super::quote::quote(query)
}
pub fn index_quote_short(query: QuoteShortQuery) -> EndpointSpec<QuoteShortQuery, Vec<QuoteShort>> {
super::quote::quote_short(query)
}
pub fn index_quotes() -> EndpointSpec<ShortOnlyQuery, Vec<QuoteShort>> {
super::quote::index_quotes()
}
pub fn index_chart_light(
query: IndexChartQuery,
) -> EndpointSpec<IndexChartQuery, Vec<StockChartLightBar>> {
EndpointSpec::get(
"historical-price-eod/light",
"historical-price-eod/light",
query,
)
.with_metadata(WORLDWIDE_EOD)
}
pub fn index_chart_full(
query: IndexChartQuery,
) -> EndpointSpec<IndexChartQuery, Vec<StockChartFullBar>> {
EndpointSpec::get(
"historical-price-eod/full",
"historical-price-eod/full",
query,
)
.with_metadata(WORLDWIDE_EOD)
}
pub fn index_chart_one_minute(
query: IndexChartQuery,
) -> EndpointSpec<IndexChartQuery, Vec<StockChartIntradayBar>> {
EndpointSpec::get("historical-chart/1min", "historical-chart/1min", query)
.with_metadata(WORLDWIDE)
}
pub fn index_chart_five_minutes(
query: IndexChartQuery,
) -> EndpointSpec<IndexChartQuery, Vec<StockChartIntradayBar>> {
EndpointSpec::get("historical-chart/5min", "historical-chart/5min", query)
.with_metadata(WORLDWIDE)
}
pub fn index_chart_one_hour(
query: IndexChartQuery,
) -> EndpointSpec<IndexChartQuery, Vec<StockChartIntradayBar>> {
EndpointSpec::get("historical-chart/1hour", "historical-chart/1hour", query)
.with_metadata(WORLDWIDE)
}
pub fn sp500_constituents() -> EndpointSpec<(), Vec<IndexConstituent>> {
constituents(IndexKind::Sp500)
}
pub fn nasdaq_constituents() -> EndpointSpec<(), Vec<IndexConstituent>> {
constituents(IndexKind::Nasdaq)
}
pub fn dow_jones_constituents() -> EndpointSpec<(), Vec<IndexConstituent>> {
constituents(IndexKind::DowJones)
}
pub fn historical_sp500_constituents() -> EndpointSpec<(), Vec<HistoricalIndexConstituent>> {
historical_constituents(IndexKind::Sp500)
}
pub fn historical_nasdaq_constituents() -> EndpointSpec<(), Vec<HistoricalIndexConstituent>> {
historical_constituents(IndexKind::Nasdaq)
}
pub fn historical_dow_jones_constituents() -> EndpointSpec<(), Vec<HistoricalIndexConstituent>> {
historical_constituents(IndexKind::DowJones)
}
impl Client {
pub async fn index_list(&self) -> Result<Vec<IndexListing>> {
self.execute(&index_list()).await
}
pub async fn index_quote(&self, query: impl Into<QuoteQuery>) -> Result<Vec<Quote>> {
self.execute(&index_quote(query.into())).await
}
pub async fn index_quote_short(
&self,
query: impl Into<QuoteShortQuery>,
) -> Result<Vec<QuoteShort>> {
self.execute(&index_quote_short(query.into())).await
}
pub async fn index_chart_light(
&self,
query: impl Into<IndexChartQuery>,
) -> Result<Vec<StockChartLightBar>> {
self.execute(&index_chart_light(query.into())).await
}
pub async fn index_chart_full(
&self,
query: impl Into<IndexChartQuery>,
) -> Result<Vec<StockChartFullBar>> {
self.execute(&index_chart_full(query.into())).await
}
pub async fn index_chart_one_minute(
&self,
query: impl Into<IndexChartQuery>,
) -> Result<Vec<StockChartIntradayBar>> {
self.execute(&index_chart_one_minute(query.into())).await
}
pub async fn index_chart_five_minutes(
&self,
query: impl Into<IndexChartQuery>,
) -> Result<Vec<StockChartIntradayBar>> {
self.execute(&index_chart_five_minutes(query.into())).await
}
pub async fn index_chart_one_hour(
&self,
query: impl Into<IndexChartQuery>,
) -> Result<Vec<StockChartIntradayBar>> {
self.execute(&index_chart_one_hour(query.into())).await
}
pub async fn sp500_constituents(&self) -> Result<Vec<IndexConstituent>> {
self.execute(&sp500_constituents()).await
}
pub async fn nasdaq_constituents(&self) -> Result<Vec<IndexConstituent>> {
self.execute(&nasdaq_constituents()).await
}
pub async fn dow_jones_constituents(&self) -> Result<Vec<IndexConstituent>> {
self.execute(&dow_jones_constituents()).await
}
pub async fn historical_sp500_constituents(&self) -> Result<Vec<HistoricalIndexConstituent>> {
self.execute(&historical_sp500_constituents()).await
}
pub async fn historical_nasdaq_constituents(&self) -> Result<Vec<HistoricalIndexConstituent>> {
self.execute(&historical_nasdaq_constituents()).await
}
pub async fn historical_dow_jones_constituents(
&self,
) -> Result<Vec<HistoricalIndexConstituent>> {
self.execute(&historical_dow_jones_constituents()).await
}
}