use crate::internal::domain::{
AccountCapabilityProfile, AccountId, BrokerAccount, BrokerSessionStatus, ContractCandidate,
ContractId, ErrorCode, GatewayError, HistoricalBar, HistoricalBarsRequest, MarketSnapshot,
OrdersHistory, OrdersHistoryRequest, PnlRealtime, PnlSnapshot, ReadOnlyOrderRecord,
};
use crate::internal::domain::{
CurrencyRate, FundamentalsReport, MarketHolidays, MarketSession, NewsArticle, NewsList,
TransferHistory,
};
use crate::internal::domain::{MarketDepth, OptionChain, OptionGreeks, ScannerRun};
use async_trait::async_trait;
pub type BackendResult<T> = Result<T, GatewayError>;
#[async_trait]
pub trait IbkrBackend: Send + Sync {
async fn session_status(&self) -> BackendResult<BrokerSessionStatus>;
async fn keepalive(&self) -> BackendResult<BrokerSessionStatus>;
async fn list_accounts(&self) -> BackendResult<Vec<BrokerAccount>>;
async fn account_summary(&self, account_id: &AccountId) -> BackendResult<serde_json::Value>;
async fn portfolio_snapshot(&self, account_id: &AccountId) -> BackendResult<serde_json::Value>;
async fn positions(&self, account_id: &AccountId) -> BackendResult<Vec<serde_json::Value>>;
async fn search_contracts(&self, query: &str) -> BackendResult<Vec<ContractCandidate>>;
async fn resolve_contract(&self, query: &str) -> BackendResult<ContractCandidate>;
async fn market_snapshot(&self, contract_id: &ContractId) -> BackendResult<MarketSnapshot>;
async fn historical_bars(
&self,
request: &HistoricalBarsRequest,
) -> BackendResult<Vec<HistoricalBar>>;
async fn orders(&self, account_id: &AccountId) -> BackendResult<Vec<ReadOnlyOrderRecord>>;
async fn order_status(
&self,
account_id: &AccountId,
order_lookup_id: &str,
) -> BackendResult<ReadOnlyOrderRecord>;
async fn executions(&self, account_id: &AccountId) -> BackendResult<Vec<serde_json::Value>>;
async fn pnl_daily(&self, account_id: &AccountId) -> BackendResult<PnlSnapshot>;
async fn pnl_realtime(&self, account_id: &AccountId) -> BackendResult<PnlRealtime>;
async fn orders_history(&self, request: &OrdersHistoryRequest) -> BackendResult<OrdersHistory>;
async fn account_metadata(
&self,
account_id: &AccountId,
) -> BackendResult<AccountCapabilityProfile>;
async fn options_chain(&self, _symbol: &str) -> BackendResult<OptionChain> {
Err(advanced_market_unavailable("options chain"))
}
async fn option_greeks(&self, _contract_id: &ContractId) -> BackendResult<OptionGreeks> {
Err(advanced_market_unavailable("option greeks"))
}
async fn market_depth(&self, _contract_id: &ContractId) -> BackendResult<MarketDepth> {
Err(advanced_market_unavailable("market depth"))
}
async fn scanner_run(&self, _scanner_code: &str) -> BackendResult<ScannerRun> {
Err(advanced_market_unavailable("scanner"))
}
async fn news_list(&self, _symbol: &str) -> BackendResult<NewsList> {
Err(advanced_market_unavailable("news list"))
}
async fn news_article(&self, _article_id: &str) -> BackendResult<NewsArticle> {
Err(advanced_market_unavailable("news article"))
}
async fn fundamentals_get(&self, _symbol: &str) -> BackendResult<FundamentalsReport> {
Err(advanced_market_unavailable("fundamentals"))
}
async fn market_session(&self, _exchange: &str) -> BackendResult<MarketSession> {
Err(advanced_market_unavailable("market session"))
}
async fn market_holidays(&self, _exchange: &str) -> BackendResult<MarketHolidays> {
Err(advanced_market_unavailable("market holidays"))
}
async fn currency_rate(&self, _base: &str, _quote: &str) -> BackendResult<CurrencyRate> {
Err(advanced_market_unavailable("currency rate"))
}
async fn transfer_history(&self, _account_id: &AccountId) -> BackendResult<TransferHistory> {
Err(advanced_market_unavailable("transfer history"))
}
}
fn advanced_market_unavailable(capability: &str) -> GatewayError {
GatewayError::new(
ErrorCode::BrokerCapabilityUnavailable,
format!("Broker backend does not support {capability}"),
false,
Some("Use a backend with the requested market research capability".to_string()),
)
}