sandbox_quant/app/
bootstrap.rs1use std::env;
2use std::sync::Arc;
3
4use crate::error::exchange_error::ExchangeError;
5use crate::exchange::binance::auth::BinanceAuth;
6use crate::exchange::binance::client::{BinanceExchange, BinanceHttpTransport, BinanceTransport};
7use crate::exchange::binance::demo::BinanceDemoHttpTransport;
8use crate::exchange::facade::ExchangeFacade;
9use crate::execution::service::ExecutionService;
10use crate::market_data::price_store::PriceStore;
11use crate::market_data::service::MarketDataService;
12use crate::portfolio::store::PortfolioStateStore;
13use crate::portfolio::sync::PortfolioSyncService;
14use crate::storage::event_log::EventLog;
15
16#[derive(Debug)]
17pub struct AppBootstrap<E: ExchangeFacade> {
18 pub exchange: E,
19 pub portfolio_store: PortfolioStateStore,
20 pub price_store: PriceStore,
21 pub event_log: EventLog,
22 pub execution: ExecutionService,
23 pub portfolio_sync: PortfolioSyncService,
24 pub market_data: MarketDataService,
25}
26
27impl<E: ExchangeFacade> AppBootstrap<E> {
28 pub fn new(exchange: E, portfolio_store: PortfolioStateStore) -> Self {
29 Self {
30 exchange,
31 portfolio_store,
32 price_store: PriceStore::default(),
33 event_log: EventLog::default(),
34 execution: ExecutionService::default(),
35 portfolio_sync: PortfolioSyncService,
36 market_data: MarketDataService,
37 }
38 }
39}
40
41impl AppBootstrap<BinanceExchange> {
42 pub fn from_env(portfolio_store: PortfolioStateStore) -> Result<Self, ExchangeError> {
53 let config = BinanceEnvConfig::from_env()?;
54 Ok(Self::new(BinanceExchange::new(config.build_transport()), portfolio_store))
55 }
56
57 pub fn switch_mode(&mut self, mode: BinanceMode) -> Result<(), ExchangeError> {
58 let mut config = BinanceEnvConfig::from_env()?;
59 config.mode = mode;
60 config.spot_base_url = None;
61 config.futures_base_url = None;
62 self.exchange = BinanceExchange::new(config.build_transport());
63 Ok(())
64 }
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum BinanceMode {
69 Real,
70 Demo,
71}
72
73#[derive(Debug, Clone, PartialEq, Eq)]
74pub struct BinanceEnvConfig {
75 pub api_key: String,
76 pub secret_key: String,
77 pub mode: BinanceMode,
78 pub spot_base_url: Option<String>,
79 pub futures_base_url: Option<String>,
80}
81
82impl BinanceEnvConfig {
83 pub fn from_env() -> Result<Self, ExchangeError> {
84 let api_key = env::var("BINANCE_API_KEY")
85 .map_err(|_| ExchangeError::MissingConfiguration("BINANCE_API_KEY"))?;
86 let secret_key = env::var("BINANCE_SECRET_KEY")
87 .map_err(|_| ExchangeError::MissingConfiguration("BINANCE_SECRET_KEY"))?;
88 let mode = match env::var("BINANCE_MODE")
89 .unwrap_or_else(|_| "demo".to_string())
90 .to_ascii_lowercase()
91 .as_str()
92 {
93 "demo" => BinanceMode::Demo,
94 _ => BinanceMode::Real,
95 };
96 Ok(Self {
97 api_key,
98 secret_key,
99 mode,
100 spot_base_url: env::var("BINANCE_SPOT_BASE_URL").ok(),
101 futures_base_url: env::var("BINANCE_FUTURES_BASE_URL").ok(),
102 })
103 }
104
105 pub fn build_transport(&self) -> Arc<dyn BinanceTransport> {
106 let auth = BinanceAuth::new(self.api_key.clone(), self.secret_key.clone());
107 match (&self.spot_base_url, &self.futures_base_url) {
108 (Some(spot), Some(futures)) => {
109 Arc::new(BinanceHttpTransport::with_base_urls(auth, spot.clone(), futures.clone()))
110 }
111 _ => match self.mode {
112 BinanceMode::Real => Arc::new(BinanceHttpTransport::new(auth)),
113 BinanceMode::Demo => Arc::new(BinanceDemoHttpTransport::new(auth)),
114 },
115 }
116 }
117}