严格校验回测撮合类型
This commit is contained in:
@@ -369,17 +369,18 @@ pub fn platform_expr_config_from_value(
|
||||
value: &Value,
|
||||
) -> Result<PlatformExprStrategyConfig, serde_json::Error> {
|
||||
if value.is_null() || value.as_object().is_some_and(|object| object.is_empty()) {
|
||||
return Ok(platform_expr_config_from_spec(
|
||||
strategy_id,
|
||||
signal_symbol,
|
||||
None,
|
||||
));
|
||||
return platform_expr_config_from_spec(strategy_id, signal_symbol, None)
|
||||
.map_err(platform_config_error);
|
||||
}
|
||||
let spec = serde_json::from_value::<StrategyRuntimeSpec>(value.clone())?;
|
||||
Ok(platform_expr_config_from_spec(
|
||||
strategy_id,
|
||||
signal_symbol,
|
||||
Some(&spec),
|
||||
platform_expr_config_from_spec(strategy_id, signal_symbol, Some(&spec))
|
||||
.map_err(platform_config_error)
|
||||
}
|
||||
|
||||
fn platform_config_error(message: String) -> serde_json::Error {
|
||||
serde_json::Error::io(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
message,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -418,12 +419,17 @@ fn normalize_model_name(value: &str) -> String {
|
||||
value.trim().to_ascii_lowercase().replace('-', "_")
|
||||
}
|
||||
|
||||
fn parse_matching_type(value: Option<&str>) -> Option<MatchingType> {
|
||||
match normalize_model_name(value?).as_str() {
|
||||
"current_bar_close" => Some(MatchingType::CurrentBarClose),
|
||||
"next_bar_open" => Some(MatchingType::NextBarOpen),
|
||||
"minute_last" => Some(MatchingType::MinuteLast),
|
||||
_ => None,
|
||||
fn parse_matching_type(value: Option<&str>) -> Result<Option<MatchingType>, String> {
|
||||
let Some(raw) = value.map(str::trim).filter(|item| !item.is_empty()) else {
|
||||
return Ok(None);
|
||||
};
|
||||
match normalize_model_name(raw).as_str() {
|
||||
"current_bar_close" => Ok(Some(MatchingType::CurrentBarClose)),
|
||||
"next_bar_open" => Ok(Some(MatchingType::NextBarOpen)),
|
||||
"minute_last" => Ok(Some(MatchingType::MinuteLast)),
|
||||
_ => Err(format!(
|
||||
"matchingType only supports current_bar_close, next_bar_open, minute_last: {raw}"
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,8 +480,8 @@ fn apply_execution_behavior_overrides(
|
||||
slippage_volatility_coefficient: Option<f64>,
|
||||
slippage_max_value: Option<f64>,
|
||||
strict_value_budget: Option<bool>,
|
||||
) {
|
||||
if let Some(matching_type) = parse_matching_type(matching_type) {
|
||||
) -> Result<(), String> {
|
||||
if let Some(matching_type) = parse_matching_type(matching_type)? {
|
||||
cfg.matching_type = matching_type;
|
||||
}
|
||||
if slippage_model.is_some()
|
||||
@@ -497,6 +503,7 @@ fn apply_execution_behavior_overrides(
|
||||
if let Some(enabled) = strict_value_budget {
|
||||
cfg.strict_value_budget = enabled;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_usize_after(text: &str, start: usize) -> Option<(usize, usize)> {
|
||||
@@ -626,7 +633,7 @@ pub fn platform_expr_config_from_spec(
|
||||
strategy_id: &str,
|
||||
signal_symbol: &str,
|
||||
strategy_spec: Option<&StrategyRuntimeSpec>,
|
||||
) -> PlatformExprStrategyConfig {
|
||||
) -> Result<PlatformExprStrategyConfig, String> {
|
||||
let mut cfg = PlatformExprStrategyConfig::microcap_rotation();
|
||||
cfg.strategy_name = strategy_id.to_string();
|
||||
if !signal_symbol.trim().is_empty() {
|
||||
@@ -634,7 +641,7 @@ pub fn platform_expr_config_from_spec(
|
||||
}
|
||||
|
||||
let Some(spec) = strategy_spec else {
|
||||
return cfg;
|
||||
return Ok(cfg);
|
||||
};
|
||||
let mut benchmark_short_explicit = false;
|
||||
let mut benchmark_long_explicit = false;
|
||||
@@ -751,7 +758,7 @@ pub fn platform_expr_config_from_spec(
|
||||
engine.slippage_volatility_coefficient,
|
||||
engine.slippage_max_value,
|
||||
engine.strict_value_budget,
|
||||
);
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(spec_signal_symbol) = spec
|
||||
@@ -1151,7 +1158,7 @@ pub fn platform_expr_config_from_spec(
|
||||
execution.slippage_volatility_coefficient,
|
||||
execution.slippage_max_value,
|
||||
execution.strict_value_budget,
|
||||
);
|
||||
)?;
|
||||
}
|
||||
if cfg.aiquant_transaction_cost
|
||||
&& cfg
|
||||
@@ -1161,7 +1168,7 @@ pub fn platform_expr_config_from_spec(
|
||||
cfg.minimum_commission = None;
|
||||
}
|
||||
|
||||
cfg
|
||||
Ok(cfg)
|
||||
}
|
||||
|
||||
fn parse_platform_rebalance_schedule(
|
||||
@@ -1706,9 +1713,15 @@ mod tests {
|
||||
}
|
||||
});
|
||||
|
||||
let cfg = platform_expr_config_from_value("", "", &spec).expect("config");
|
||||
let err =
|
||||
platform_expr_config_from_value("", "", &spec).expect_err("invalid matchingType");
|
||||
|
||||
assert_eq!(cfg.matching_type, MatchingType::CurrentBarClose);
|
||||
assert!(
|
||||
err.to_string().contains(
|
||||
"matchingType only supports current_bar_close, next_bar_open, minute_last"
|
||||
),
|
||||
"{err}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user