From 43c7aa4a4bf89e22b6f735b66ec37c1779f519ad Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Sun, 1 Mar 2026 21:56:50 +0100 Subject: [PATCH] feat(risk-data): wire get_portfolio_positions to broker_positions DB table Replace empty Vec stub with a real sqlx::query_as query against the broker_positions table, filtering by account_id and non-zero quantity. Uses runtime query_as (not macro) so SQLX_OFFLINE=true works without offline metadata. Co-Authored-By: Claude Opus 4.6 --- crates/risk-data/src/var.rs | 42 ++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/crates/risk-data/src/var.rs b/crates/risk-data/src/var.rs index da230494f..492f84148 100644 --- a/crates/risk-data/src/var.rs +++ b/crates/risk-data/src/var.rs @@ -128,6 +128,14 @@ pub struct PortfolioPosition { pub asset_class: String, } +/// Internal row type for SQLX query mapping from `broker_positions` table +#[derive(Debug, sqlx::FromRow)] +struct PortfolioPositionRow { + symbol: String, + quantity: Decimal, + market_value: Option, +} + /// Historical price data #[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)] pub struct PriceData { @@ -642,10 +650,38 @@ impl VarRepository for VarRepositoryImpl { &self, portfolio_id: &str, ) -> RiskDataResult> { - // STUB: requires broker or database integration info!("Getting portfolio positions for {}", portfolio_id); - warn!("STUB: get_portfolio_positions returns empty -- wire to broker/DB for real positions"); - Ok(vec![]) + + // Query broker_positions table (populated by fill events from trading engine) + let rows: Vec = sqlx::query_as( + "SELECT symbol, quantity, market_value \ + FROM broker_positions \ + WHERE account_id = $1 AND quantity != 0 \ + ORDER BY symbol", + ) + .bind(portfolio_id) + .fetch_all(&self.db_pool) + .await?; + + if rows.is_empty() { + warn!( + portfolio_id = %portfolio_id, + "no positions found in broker_positions table" + ); + } + + let positions = rows + .into_iter() + .map(|row| PortfolioPosition { + symbol: row.symbol, + quantity: row.quantity, + market_value: row.market_value.unwrap_or_default(), + currency: "USD".to_string(), + asset_class: "futures".to_string(), + }) + .collect(); + + Ok(positions) } async fn calculate_volatility_matrix(