use crate::types::alpaca::Source; use governor::{DefaultDirectRateLimiter, Quota, RateLimiter}; use reqwest::{ header::{HeaderMap, HeaderName, HeaderValue}, Client, }; use std::{env, num::NonZeroU32, sync::Arc}; pub const ALPACA_ASSET_API_URL: &str = "https://api.alpaca.markets/v2/assets"; pub const ALPACA_CLOCK_API_URL: &str = "https://api.alpaca.markets/v2/clock"; pub const ALPACA_STOCK_DATA_URL: &str = "https://data.alpaca.markets/v2/stocks/bars"; pub const ALPACA_CRYPTO_DATA_URL: &str = "https://data.alpaca.markets/v1beta3/crypto/us/bars"; pub const ALPACA_NEWS_DATA_URL: &str = "https://data.alpaca.markets/v1beta1/news"; pub const ALPACA_STOCK_WEBSOCKET_URL: &str = "wss://stream.data.alpaca.markets/v2"; pub const ALPACA_CRYPTO_WEBSOCKET_URL: &str = "wss://stream.data.alpaca.markets/v1beta3/crypto/us"; pub const ALPACA_NEWS_WEBSOCKET_URL: &str = "wss://stream.data.alpaca.markets/v1beta1/news"; pub struct Config { pub alpaca_api_key: String, pub alpaca_api_secret: String, pub alpaca_client: Client, pub alpaca_rate_limit: DefaultDirectRateLimiter, pub alpaca_source: Source, pub clickhouse_client: clickhouse::Client, } impl Config { pub fn from_env() -> Self { let alpaca_api_key = env::var("ALPACA_API_KEY").expect("ALPACA_API_KEY must be set."); let alpaca_api_secret = env::var("ALPACA_API_SECRET").expect("ALPACA_API_SECRET must be set."); let alpaca_source: Source = env::var("ALPACA_SOURCE") .expect("ALPACA_SOURCE must be set.") .parse() .expect("ALPACA_SOURCE must be a either 'iex' or 'sip'."); let clickhouse_url = env::var("CLICKHOUSE_URL").expect("CLICKHOUSE_URL must be set."); let clickhouse_user = env::var("CLICKHOUSE_USER").expect("CLICKHOUSE_USER must be set."); let clickhouse_password = env::var("CLICKHOUSE_PASSWORD").expect("CLICKHOUSE_PASSWORD must be set."); let clickhouse_db = env::var("CLICKHOUSE_DB").expect("CLICKHOUSE_DB must be set."); Self { alpaca_client: Client::builder() .default_headers(HeaderMap::from_iter([ ( HeaderName::from_static("apca-api-key-id"), HeaderValue::from_str(&alpaca_api_key) .expect("Alpaca API key must not contain invalid characters."), ), ( HeaderName::from_static("apca-api-secret-key"), HeaderValue::from_str(&alpaca_api_secret) .expect("Alpaca API secret must not contain invalid characters."), ), ])) .build() .unwrap(), alpaca_rate_limit: RateLimiter::direct(Quota::per_minute(match alpaca_source { Source::Iex => unsafe { NonZeroU32::new_unchecked(200) }, Source::Sip => unsafe { NonZeroU32::new_unchecked(10000) }, })), alpaca_source, clickhouse_client: clickhouse::Client::default() .with_url(clickhouse_url) .with_user(clickhouse_user) .with_password(clickhouse_password) .with_database(clickhouse_db), alpaca_api_key, alpaca_api_secret, } } pub fn arc_from_env() -> Arc { Arc::new(Self::from_env()) } }