Align China A-share costs with rqalpha rules

This commit is contained in:
boris
2026-04-22 21:57:24 -07:00
parent 650e2e8319
commit aca8292c72
5 changed files with 111 additions and 43 deletions

View File

@@ -463,6 +463,7 @@ where
let provisional_target_qty = desired_qty.clamp(min_target_qty, max_target_qty);
if current_qty > provisional_target_qty {
projected_cash += self.estimated_sell_net_cash(
date,
price,
current_qty.saturating_sub(provisional_target_qty),
);
@@ -484,6 +485,7 @@ where
if target_qty > constraint.current_qty {
let desired_additional = target_qty - constraint.current_qty;
let affordable_additional = self.affordable_buy_quantity(
date,
projected_cash,
None,
constraint.price,
@@ -494,6 +496,7 @@ where
.clamp(constraint.min_target_qty, constraint.max_target_qty);
if target_qty > constraint.current_qty {
projected_cash -= self.estimated_buy_cash_out(
date,
constraint.price,
target_qty - constraint.current_qty,
);
@@ -582,21 +585,21 @@ where
current_qty.saturating_add(additional_limit)
}
fn estimated_sell_net_cash(&self, price: f64, quantity: u32) -> f64 {
fn estimated_sell_net_cash(&self, date: NaiveDate, price: f64, quantity: u32) -> f64 {
if quantity == 0 {
return 0.0;
}
let gross = price * quantity as f64;
let cost = self.cost_model.calculate(OrderSide::Sell, gross);
let cost = self.cost_model.calculate(date, OrderSide::Sell, gross);
gross - cost.total()
}
fn estimated_buy_cash_out(&self, price: f64, quantity: u32) -> f64 {
fn estimated_buy_cash_out(&self, date: NaiveDate, price: f64, quantity: u32) -> f64 {
if quantity == 0 {
return 0.0;
}
let gross = price * quantity as f64;
let cost = self.cost_model.calculate(OrderSide::Buy, gross);
let cost = self.cost_model.calculate(date, OrderSide::Buy, gross);
gross + cost.total()
}
@@ -705,7 +708,9 @@ where
(filled_qty, self.sell_price(snapshot))
};
let gross_amount = execution_price * filled_qty as f64;
let cost = self.cost_model.calculate(OrderSide::Sell, gross_amount);
let cost = self
.cost_model
.calculate(date, OrderSide::Sell, gross_amount);
let net_cash = gross_amount - cost.total();
let realized_pnl = portfolio
@@ -950,6 +955,7 @@ where
.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,
@@ -963,6 +969,7 @@ where
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,
@@ -994,6 +1001,7 @@ where
fn select_buy_sizing_fill(
&self,
date: NaiveDate,
snapshot: &crate::data::DailyMarketSnapshot,
quotes: &[IntradayExecutionQuote],
start_cursor: Option<NaiveDateTime>,
@@ -1057,7 +1065,9 @@ where
take_qty = take_qty.saturating_sub(lot);
continue;
}
let candidate_cost = self.cost_model.calculate(OrderSide::Buy, candidate_gross);
let candidate_cost =
self.cost_model
.calculate(date, OrderSide::Buy, candidate_gross);
if candidate_gross + candidate_cost.total() <= cash + 1e-6 {
break;
}
@@ -1166,6 +1176,7 @@ where
} else {
let execution_price = self.snapshot_execution_price(snapshot, OrderSide::Buy);
let filled_qty = self.affordable_buy_quantity(
date,
portfolio.cash(),
value_budget.map(|budget| budget + 400.0),
execution_price,
@@ -1189,7 +1200,9 @@ where
let cash_before = portfolio.cash();
let gross_amount = execution_price * filled_qty as f64;
let cost = self.cost_model.calculate(OrderSide::Buy, gross_amount);
let cost = self
.cost_model
.calculate(date, OrderSide::Buy, gross_amount);
let cash_out = gross_amount + cost.total();
portfolio.apply_cash_delta(-cash_out);
@@ -1290,6 +1303,7 @@ where
fn affordable_buy_quantity(
&self,
date: NaiveDate,
cash: f64,
gross_limit: Option<f64>,
price: f64,
@@ -1304,7 +1318,7 @@ where
quantity = quantity.saturating_sub(lot);
continue;
}
let cost = self.cost_model.calculate(OrderSide::Buy, gross);
let cost = self.cost_model.calculate(date, OrderSide::Buy, gross);
if gross + cost.total() <= cash + 1e-6 {
return quantity;
}
@@ -1382,6 +1396,7 @@ where
let execution_price = self.snapshot_execution_price(snapshot, side);
let quantity = match side {
OrderSide::Buy => self.affordable_buy_quantity(
date,
cash_limit.unwrap_or(f64::INFINITY),
gross_limit,
execution_price,