修正调仓后剩余买入预算
This commit is contained in:
@@ -2540,28 +2540,31 @@ impl PlatformExprStrategy {
|
|||||||
self.projected_position_value_at_execution_price(ctx, projected, date, symbol)
|
self.projected_position_value_at_execution_price(ctx, projected, date, symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn context_position_value_for_remaining_buy_cash(
|
fn projected_strategy_visible_position_value_for_remaining_buy_cash(
|
||||||
&self,
|
&self,
|
||||||
ctx: &StrategyContext<'_>,
|
ctx: &StrategyContext<'_>,
|
||||||
|
projected: &PortfolioState,
|
||||||
date: NaiveDate,
|
date: NaiveDate,
|
||||||
symbol: &str,
|
symbol: &str,
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
let Some(position) = ctx.portfolio.position(symbol) else {
|
let Some(projected_position) = projected.position(symbol) else {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
};
|
};
|
||||||
if position.quantity == 0 {
|
if projected_position.quantity == 0 {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
let context_position = ctx.portfolio.position(symbol);
|
||||||
let mark_price = self
|
let mark_price = self
|
||||||
.aiquant_scheduled_last_price(ctx, date, symbol)
|
.aiquant_scheduled_last_price(ctx, date, symbol)
|
||||||
.or_else(|| ctx.data.price(date, symbol, PriceField::Last))
|
.or_else(|| ctx.data.price(date, symbol, PriceField::Last))
|
||||||
.or_else(|| ctx.data.price_on_or_before(date, symbol, PriceField::Last))
|
.or_else(|| ctx.data.price_on_or_before(date, symbol, PriceField::Last))
|
||||||
|
.or_else(|| context_position.map(|position| position.last_price))
|
||||||
.filter(|price| price.is_finite() && *price > 0.0)
|
.filter(|price| price.is_finite() && *price > 0.0)
|
||||||
.unwrap_or(position.last_price);
|
.unwrap_or(projected_position.last_price);
|
||||||
if mark_price.is_finite() && mark_price > 0.0 {
|
if mark_price.is_finite() && mark_price > 0.0 {
|
||||||
mark_price * position.quantity as f64
|
mark_price * projected_position.quantity as f64
|
||||||
} else {
|
} else {
|
||||||
position.market_value()
|
projected_position.market_value()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2775,7 +2778,9 @@ impl PlatformExprStrategy {
|
|||||||
*aiquant_available_cash = (*aiquant_available_cash - spent).max(0.0);
|
*aiquant_available_cash = (*aiquant_available_cash - spent).max(0.0);
|
||||||
slot_working_symbols.insert(symbol.clone());
|
slot_working_symbols.insert(symbol.clone());
|
||||||
same_bar_buy_symbols.insert(symbol.clone());
|
same_bar_buy_symbols.insert(symbol.clone());
|
||||||
*pending_buy_value += available_buy_cash;
|
if order_result.filled_quantity == 0 {
|
||||||
|
*pending_buy_value += available_buy_cash;
|
||||||
|
}
|
||||||
if debug_daily_top_up {
|
if debug_daily_top_up {
|
||||||
daily_top_up_debug_notes.push(format!(
|
daily_top_up_debug_notes.push(format!(
|
||||||
"daily_top_up_fill date={} symbol={} requested_cash={:.4} filled_qty={} spent={:.4} remaining_cash={:.4}",
|
"daily_top_up_fill date={} symbol={} requested_cash={:.4} filled_qty={} spent={:.4} remaining_cash={:.4}",
|
||||||
@@ -2833,7 +2838,9 @@ impl PlatformExprStrategy {
|
|||||||
.filter(|symbol| value_symbols.contains(*symbol))
|
.filter(|symbol| value_symbols.contains(*symbol))
|
||||||
.map(|symbol| {
|
.map(|symbol| {
|
||||||
if self.config.aiquant_transaction_cost {
|
if self.config.aiquant_transaction_cost {
|
||||||
self.context_position_value_for_remaining_buy_cash(ctx, date, symbol)
|
self.projected_strategy_visible_position_value_for_remaining_buy_cash(
|
||||||
|
ctx, projected, date, symbol,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
self.projected_position_value_at_execution_price(ctx, projected, date, symbol)
|
self.projected_position_value_at_execution_price(ctx, projected, date, symbol)
|
||||||
}
|
}
|
||||||
@@ -17610,7 +17617,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn platform_aiquant_weak_market_threshold_top_up_uses_remaining_budget() {
|
fn platform_aiquant_weak_market_threshold_top_up_uses_projected_remaining_budget() {
|
||||||
let prev_date = d(2023, 5, 4);
|
let prev_date = d(2023, 5, 4);
|
||||||
let date = d(2023, 5, 5);
|
let date = d(2023, 5, 5);
|
||||||
let symbols = ["000001.SZ", "000002.SZ", "000003.SZ"];
|
let symbols = ["000001.SZ", "000002.SZ", "000003.SZ"];
|
||||||
@@ -17766,10 +17773,15 @@ mod tests {
|
|||||||
"{:?}",
|
"{:?}",
|
||||||
decision.order_intents
|
decision.order_intents
|
||||||
);
|
);
|
||||||
assert!(!decision.order_intents.iter().any(|intent| matches!(
|
assert!(
|
||||||
intent,
|
decision.order_intents.iter().any(|intent| matches!(
|
||||||
OrderIntent::Value { reason, .. } if reason == "daily_top_up_buy"
|
intent,
|
||||||
)));
|
OrderIntent::Value { value, reason, .. }
|
||||||
|
if reason == "daily_top_up_buy" && (*value - 13_000.0).abs() < 1e-6
|
||||||
|
)),
|
||||||
|
"{:?}",
|
||||||
|
decision.order_intents
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -21713,7 +21725,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn platform_aiquant_remaining_buy_cash_uses_strategy_visible_positions() {
|
fn platform_aiquant_remaining_buy_cash_uses_strategy_visible_price_and_projected_quantity() {
|
||||||
let prev_date = d(2025, 2, 2);
|
let prev_date = d(2025, 2, 2);
|
||||||
let date = d(2025, 2, 3);
|
let date = d(2025, 2, 3);
|
||||||
let symbols = ["000001.SZ", "000002.SZ"];
|
let symbols = ["000001.SZ", "000002.SZ"];
|
||||||
@@ -21842,8 +21854,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
(cash - 1_000.0).abs() < 1e-6,
|
(cash - 5_000.0).abs() < 1e-6,
|
||||||
"remaining cash should use strategy-visible 900-share position, got {cash}"
|
"remaining cash should use strategy-visible price and projected 500-share quantity, got {cash}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22000,7 +22012,7 @@ mod tests {
|
|||||||
reason,
|
reason,
|
||||||
} if symbol == "000002.SZ"
|
} if symbol == "000002.SZ"
|
||||||
&& reason == "daily_top_up_buy"
|
&& reason == "daily_top_up_buy"
|
||||||
&& (*value - 1_500.0).abs() < 1e-6
|
&& (*value - 4_500.0).abs() < 1e-6
|
||||||
)),
|
)),
|
||||||
"{:?}",
|
"{:?}",
|
||||||
decision.order_intents
|
decision.order_intents
|
||||||
|
|||||||
Reference in New Issue
Block a user