Expose account runtime metrics

This commit is contained in:
boris
2026-04-23 20:03:49 -07:00
parent 9f10afddec
commit e0a5d0c945
7 changed files with 367 additions and 19 deletions

View File

@@ -95,6 +95,28 @@ pub struct OrderRuntimeView {
pub reason: String,
}
#[derive(Debug, Clone)]
pub struct PortfolioRuntimeView {
pub starting_cash: f64,
pub units: f64,
pub cash: f64,
pub available_cash: f64,
pub frozen_cash: f64,
pub market_value: f64,
pub total_value: f64,
pub portfolio_value: f64,
pub total_equity: f64,
pub unit_net_value: f64,
pub static_unit_net_value: f64,
pub daily_pnl: f64,
pub daily_returns: f64,
pub total_returns: f64,
pub transaction_cost: f64,
pub trading_pnl: f64,
pub position_pnl: f64,
pub cash_liabilities: f64,
}
pub struct StrategyContext<'a> {
pub execution_date: NaiveDate,
pub decision_date: NaiveDate,
@@ -323,6 +345,55 @@ impl StrategyContext<'_> {
.unwrap_or(0.0)
}
pub fn portfolio_view(&self) -> PortfolioRuntimeView {
let frozen_cash = self.frozen_cash();
let cash = self.portfolio.cash();
let total_equity = self.portfolio.total_equity();
PortfolioRuntimeView {
starting_cash: self.portfolio.starting_cash(),
units: self.portfolio.units(),
cash,
available_cash: (cash - frozen_cash).max(0.0),
frozen_cash,
market_value: self.portfolio.market_value(),
total_value: self.portfolio.total_value(),
portfolio_value: self.portfolio.portfolio_value(),
total_equity,
unit_net_value: self.portfolio.unit_net_value(),
static_unit_net_value: self.portfolio.static_unit_net_value(),
daily_pnl: self.portfolio.daily_pnl(),
daily_returns: self.portfolio.daily_returns(),
total_returns: self.portfolio.total_returns(),
transaction_cost: self.portfolio.transaction_cost(),
trading_pnl: self.portfolio.trading_pnl(),
position_pnl: self.portfolio.position_pnl(),
cash_liabilities: 0.0,
}
}
pub fn account(&self) -> PortfolioRuntimeView {
self.portfolio_view()
}
pub fn frozen_cash(&self) -> f64 {
self.open_orders
.iter()
.filter(|order| order.side == OrderSide::Buy)
.map(|order| {
let price = if order.limit_price.is_finite() {
order.limit_price.max(0.0)
} else {
0.0
};
order.remaining_quantity as f64 * price
})
.sum()
}
pub fn available_cash(&self) -> f64 {
(self.portfolio.cash() - self.frozen_cash()).max(0.0)
}
pub fn available_sellable_qty(&self, symbol: &str, raw_sellable_qty: u32) -> u32 {
raw_sellable_qty.saturating_sub(self.symbol_open_sell_quantity(symbol))
}