Drop stale broker sizing helpers
This commit is contained in:
@@ -924,65 +924,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn estimate_value_buy_quantity(
|
||||
&self,
|
||||
date: NaiveDate,
|
||||
portfolio: &PortfolioState,
|
||||
data: &DataSet,
|
||||
symbol: &str,
|
||||
round_lot: u32,
|
||||
value_budget: f64,
|
||||
intraday_turnover: &BTreeMap<String, u32>,
|
||||
execution_cursors: &BTreeMap<String, NaiveDateTime>,
|
||||
global_execution_cursor: Option<NaiveDateTime>,
|
||||
) -> Option<u32> {
|
||||
if self.execution_price_field != PriceField::Last {
|
||||
return None;
|
||||
}
|
||||
let snapshot = data.market(date, symbol)?;
|
||||
let market_limited_qty = self
|
||||
.market_fillable_quantity(
|
||||
snapshot,
|
||||
OrderSide::Buy,
|
||||
u32::MAX,
|
||||
round_lot,
|
||||
*intraday_turnover.get(symbol).unwrap_or(&0),
|
||||
)
|
||||
.ok()?;
|
||||
let max_requested_qty = market_limited_qty;
|
||||
let start_cursor = self
|
||||
.intraday_execution_start_time
|
||||
.map(|start_time| date.and_time(start_time));
|
||||
let quotes = data.execution_quotes_on(date, symbol);
|
||||
if let Some(estimated) = self.select_buy_sizing_fill(
|
||||
date,
|
||||
snapshot,
|
||||
quotes,
|
||||
start_cursor,
|
||||
max_requested_qty,
|
||||
round_lot,
|
||||
Some(portfolio.cash()),
|
||||
Some(value_budget),
|
||||
) {
|
||||
return Some(estimated.quantity);
|
||||
}
|
||||
|
||||
let execution_price = self.snapshot_execution_price(snapshot, OrderSide::Buy);
|
||||
let fallback_qty = self.affordable_buy_quantity(
|
||||
date,
|
||||
portfolio.cash(),
|
||||
Some(value_budget),
|
||||
execution_price,
|
||||
max_requested_qty,
|
||||
round_lot,
|
||||
);
|
||||
if fallback_qty > 0 {
|
||||
Some(fallback_qty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_expand_periodic_value_buy_quantity(
|
||||
&self,
|
||||
_date: NaiveDate,
|
||||
@@ -999,105 +940,6 @@ where
|
||||
requested_qty
|
||||
}
|
||||
|
||||
fn select_buy_sizing_fill(
|
||||
&self,
|
||||
date: NaiveDate,
|
||||
snapshot: &crate::data::DailyMarketSnapshot,
|
||||
quotes: &[IntradayExecutionQuote],
|
||||
start_cursor: Option<NaiveDateTime>,
|
||||
requested_qty: u32,
|
||||
round_lot: u32,
|
||||
cash_limit: Option<f64>,
|
||||
gross_limit: Option<f64>,
|
||||
) -> Option<ExecutionFill> {
|
||||
if requested_qty == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let lot = round_lot.max(1);
|
||||
let mut filled_qty = 0_u32;
|
||||
let mut gross_amount = 0.0_f64;
|
||||
let mut last_timestamp = None;
|
||||
|
||||
for quote in quotes {
|
||||
if start_cursor.is_some_and(|cursor| quote.timestamp < cursor) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let fallback_quote_price = if quote.last_price.is_finite() && quote.last_price > 0.0 {
|
||||
Some(quote.last_price)
|
||||
} else {
|
||||
quote.buy_price()
|
||||
};
|
||||
|
||||
if quote.volume_delta == 0 {
|
||||
continue;
|
||||
}
|
||||
let Some(raw_quote_price) = fallback_quote_price else {
|
||||
continue;
|
||||
};
|
||||
let quote_price = self.quote_execution_price(snapshot, OrderSide::Buy, raw_quote_price);
|
||||
if !quote_price.is_finite() || quote_price <= 0.0 {
|
||||
continue;
|
||||
}
|
||||
let available_qty = quote
|
||||
.ask1_volume
|
||||
.saturating_mul(lot as u64)
|
||||
.min(u32::MAX as u64) as u32;
|
||||
if available_qty == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let remaining_qty = requested_qty.saturating_sub(filled_qty);
|
||||
if remaining_qty == 0 {
|
||||
break;
|
||||
}
|
||||
let mut take_qty = remaining_qty.min(available_qty);
|
||||
take_qty = self.round_buy_quantity(take_qty, lot);
|
||||
if take_qty == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(cash) = cash_limit {
|
||||
while take_qty > 0 {
|
||||
let candidate_gross = gross_amount + quote_price * take_qty as f64;
|
||||
if gross_limit.is_some_and(|limit| candidate_gross > limit + 1e-6) {
|
||||
take_qty = take_qty.saturating_sub(lot);
|
||||
continue;
|
||||
}
|
||||
let candidate_cost =
|
||||
self.cost_model
|
||||
.calculate(date, OrderSide::Buy, candidate_gross);
|
||||
if candidate_gross + candidate_cost.total() <= cash + 1e-6 {
|
||||
break;
|
||||
}
|
||||
take_qty = take_qty.saturating_sub(lot);
|
||||
}
|
||||
if take_qty == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gross_amount += quote_price * take_qty as f64;
|
||||
filled_qty += take_qty;
|
||||
last_timestamp = Some(quote.timestamp);
|
||||
|
||||
if filled_qty >= requested_qty {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if filled_qty == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(ExecutionFill {
|
||||
price: gross_amount / filled_qty as f64,
|
||||
quantity: filled_qty,
|
||||
next_cursor: last_timestamp.unwrap() + Duration::seconds(1),
|
||||
})
|
||||
}
|
||||
|
||||
fn process_buy(
|
||||
&self,
|
||||
date: NaiveDate,
|
||||
@@ -1383,8 +1225,8 @@ where
|
||||
data: &DataSet,
|
||||
requested_qty: u32,
|
||||
round_lot: u32,
|
||||
execution_cursors: &mut BTreeMap<String, NaiveDateTime>,
|
||||
global_execution_cursor: Option<NaiveDateTime>,
|
||||
_execution_cursors: &mut BTreeMap<String, NaiveDateTime>,
|
||||
_global_execution_cursor: Option<NaiveDateTime>,
|
||||
cash_limit: Option<f64>,
|
||||
gross_limit: Option<f64>,
|
||||
) -> Option<ExecutionFill> {
|
||||
|
||||
Reference in New Issue
Block a user