补充目标组合执行日展开测试
This commit is contained in:
@@ -4286,6 +4286,43 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct ScheduledTargetPortfolioSmartStrategy {
|
||||||
|
rule: ScheduleRule,
|
||||||
|
decision_date: NaiveDate,
|
||||||
|
target_weights: BTreeMap<String, f64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Strategy for ScheduledTargetPortfolioSmartStrategy {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"scheduled_target_portfolio_smart"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schedule_rules(&self) -> Vec<ScheduleRule> {
|
||||||
|
vec![self.rule.clone()]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_scheduled(
|
||||||
|
&mut self,
|
||||||
|
ctx: &StrategyContext<'_>,
|
||||||
|
rule: &ScheduleRule,
|
||||||
|
) -> Result<StrategyDecision, super::BacktestError> {
|
||||||
|
assert_eq!(rule.name, self.rule.name);
|
||||||
|
if ctx.decision_date != self.decision_date {
|
||||||
|
return Ok(StrategyDecision::default());
|
||||||
|
}
|
||||||
|
Ok(StrategyDecision {
|
||||||
|
order_intents: vec![OrderIntent::TargetPortfolioSmart {
|
||||||
|
target_weights: self.target_weights.clone(),
|
||||||
|
order_prices: None,
|
||||||
|
valuation_prices: None,
|
||||||
|
reason: "scheduled_target_portfolio_smart".to_string(),
|
||||||
|
}],
|
||||||
|
..StrategyDecision::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ScheduledEligibleUniverseBuyStrategy {
|
struct ScheduledEligibleUniverseBuyStrategy {
|
||||||
rule: ScheduleRule,
|
rule: ScheduleRule,
|
||||||
@@ -4921,6 +4958,51 @@ mod tests {
|
|||||||
assert_eq!(result.fills[0].price, 12.0);
|
assert_eq!(result.fills[0].price, 12.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn next_bar_open_target_portfolio_smart_sizes_with_execution_day_open() {
|
||||||
|
let first = d(2025, 1, 2);
|
||||||
|
let second = d(2025, 1, 3);
|
||||||
|
let dataset = DataSet::from_components(
|
||||||
|
vec![default_instrument()],
|
||||||
|
vec![market(first, 10.0, 10.0), market(second, 12.0, 12.0)],
|
||||||
|
vec![factor(first), factor(second)],
|
||||||
|
vec![candidate(first), candidate(second)],
|
||||||
|
vec![benchmark(first), benchmark(second)],
|
||||||
|
)
|
||||||
|
.expect("dataset");
|
||||||
|
let broker = scheduled_next_open_broker(FidcRiskControlConfig::default());
|
||||||
|
let config = BacktestConfig {
|
||||||
|
initial_cash: 100_000.0,
|
||||||
|
benchmark_code: "000852.SH".to_string(),
|
||||||
|
start_date: Some(first),
|
||||||
|
end_date: Some(second),
|
||||||
|
decision_lag_trading_days: 1,
|
||||||
|
execution_price_field: PriceField::Open,
|
||||||
|
};
|
||||||
|
let mut target_weights = BTreeMap::new();
|
||||||
|
target_weights.insert(SYMBOL.to_string(), 1.0);
|
||||||
|
|
||||||
|
let result = BacktestEngine::new(
|
||||||
|
dataset,
|
||||||
|
ScheduledTargetPortfolioSmartStrategy {
|
||||||
|
rule: ScheduleRule::daily("daily_target_portfolio", ScheduleStage::OnDay),
|
||||||
|
decision_date: first,
|
||||||
|
target_weights,
|
||||||
|
},
|
||||||
|
broker,
|
||||||
|
config,
|
||||||
|
)
|
||||||
|
.run()
|
||||||
|
.expect("backtest run");
|
||||||
|
|
||||||
|
assert_eq!(result.fills.len(), 1);
|
||||||
|
assert_eq!(result.fills[0].date, second);
|
||||||
|
assert_eq!(result.fills[0].decision_date, Some(first));
|
||||||
|
assert_eq!(result.fills[0].execution_date, Some(second));
|
||||||
|
assert_eq!(result.fills[0].price, 12.0);
|
||||||
|
assert_eq!(result.fills[0].quantity, 8_300);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn next_bar_open_executes_last_decision_without_execution_day_factor_snapshot() {
|
fn next_bar_open_executes_last_decision_without_execution_day_factor_snapshot() {
|
||||||
let first = d(2025, 1, 2);
|
let first = d(2025, 1, 2);
|
||||||
|
|||||||
Reference in New Issue
Block a user