Support algo order pricing in smart portfolio rebalances

This commit is contained in:
boris
2026-04-23 18:48:14 -07:00
parent ac308c8d68
commit 58836a1c37
7 changed files with 427 additions and 28 deletions

View File

@@ -12,7 +12,9 @@ use crate::events::{
};
use crate::portfolio::PortfolioState;
use crate::rules::EquityRuleHooks;
use crate::strategy::{AlgoOrderStyle, OpenOrderView, OrderIntent, StrategyDecision};
use crate::strategy::{
AlgoOrderStyle, OpenOrderView, OrderIntent, StrategyDecision, TargetPortfolioOrderPricing,
};
#[derive(Debug, Default)]
pub struct BrokerExecutionReport {
@@ -547,6 +549,7 @@ where
execution_cursors,
global_execution_cursor,
commission_state,
None,
report,
),
OrderIntent::LimitShares {
@@ -1567,7 +1570,7 @@ where
portfolio: &mut PortfolioState,
data: &DataSet,
target_weights: &BTreeMap<String, f64>,
order_prices: Option<&BTreeMap<String, f64>>,
order_prices: Option<&TargetPortfolioOrderPricing>,
valuation_prices: Option<&BTreeMap<String, f64>>,
reason: &str,
intraday_turnover: &mut BTreeMap<String, u32>,
@@ -1584,6 +1587,25 @@ where
valuation_prices,
)?;
report.diagnostics.extend(diagnostics);
let limit_prices = match order_prices {
Some(TargetPortfolioOrderPricing::LimitPrices(prices)) => Some(prices),
_ => None,
};
let algo_request = match order_prices {
Some(TargetPortfolioOrderPricing::AlgoOrder {
style,
start_time,
end_time,
}) => Some(AlgoExecutionRequest {
style: match style {
AlgoOrderStyle::Vwap => AlgoExecutionStyle::Vwap,
AlgoOrderStyle::Twap => AlgoExecutionStyle::Twap,
},
start_time: *start_time,
end_time: *end_time,
}),
_ => None,
};
let mut symbols = BTreeSet::new();
symbols.extend(portfolio.positions().keys().cloned());
@@ -1601,7 +1623,7 @@ where
let sell_qty = current_qty - target_qty;
let mut local_report = BrokerExecutionReport::default();
if let Some(limit_price) =
self.required_custom_order_price(date, symbol, order_prices)?
self.required_custom_order_price(date, symbol, limit_prices)?
{
self.process_limit_shares(
date,
@@ -1629,6 +1651,7 @@ where
execution_cursors,
global_execution_cursor,
commission_state,
algo_request.as_ref(),
&mut local_report,
)?;
}
@@ -1647,7 +1670,7 @@ where
let buy_qty = target_qty - current_qty;
let mut local_report = BrokerExecutionReport::default();
if let Some(limit_price) =
self.required_custom_order_price(date, symbol, order_prices)?
self.required_custom_order_price(date, symbol, limit_prices)?
{
self.process_limit_shares(
date,
@@ -1675,6 +1698,7 @@ where
execution_cursors,
global_execution_cursor,
commission_state,
algo_request.as_ref(),
&mut local_report,
)?;
}
@@ -3189,6 +3213,7 @@ where
execution_cursors: &mut BTreeMap<String, NaiveDateTime>,
global_execution_cursor: &mut Option<NaiveDateTime>,
commission_state: &mut BTreeMap<u64, f64>,
algo_request: Option<&AlgoExecutionRequest>,
report: &mut BrokerExecutionReport,
) -> Result<(), BacktestError> {
if quantity == 0 {
@@ -3216,7 +3241,7 @@ where
None,
false,
true,
None,
algo_request,
report,
)
} else {
@@ -3235,7 +3260,7 @@ where
None,
false,
true,
None,
algo_request,
report,
)
}
@@ -3273,6 +3298,7 @@ where
execution_cursors,
global_execution_cursor,
commission_state,
None,
report,
)
}