严格校验回测撮合类型
This commit is contained in:
@@ -369,17 +369,18 @@ pub fn platform_expr_config_from_value(
|
|||||||
value: &Value,
|
value: &Value,
|
||||||
) -> Result<PlatformExprStrategyConfig, serde_json::Error> {
|
) -> Result<PlatformExprStrategyConfig, serde_json::Error> {
|
||||||
if value.is_null() || value.as_object().is_some_and(|object| object.is_empty()) {
|
if value.is_null() || value.as_object().is_some_and(|object| object.is_empty()) {
|
||||||
return Ok(platform_expr_config_from_spec(
|
return platform_expr_config_from_spec(strategy_id, signal_symbol, None)
|
||||||
strategy_id,
|
.map_err(platform_config_error);
|
||||||
signal_symbol,
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
let spec = serde_json::from_value::<StrategyRuntimeSpec>(value.clone())?;
|
let spec = serde_json::from_value::<StrategyRuntimeSpec>(value.clone())?;
|
||||||
Ok(platform_expr_config_from_spec(
|
platform_expr_config_from_spec(strategy_id, signal_symbol, Some(&spec))
|
||||||
strategy_id,
|
.map_err(platform_config_error)
|
||||||
signal_symbol,
|
}
|
||||||
Some(&spec),
|
|
||||||
|
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('-', "_")
|
value.trim().to_ascii_lowercase().replace('-', "_")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_matching_type(value: Option<&str>) -> Option<MatchingType> {
|
fn parse_matching_type(value: Option<&str>) -> Result<Option<MatchingType>, String> {
|
||||||
match normalize_model_name(value?).as_str() {
|
let Some(raw) = value.map(str::trim).filter(|item| !item.is_empty()) else {
|
||||||
"current_bar_close" => Some(MatchingType::CurrentBarClose),
|
return Ok(None);
|
||||||
"next_bar_open" => Some(MatchingType::NextBarOpen),
|
};
|
||||||
"minute_last" => Some(MatchingType::MinuteLast),
|
match normalize_model_name(raw).as_str() {
|
||||||
_ => None,
|
"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_volatility_coefficient: Option<f64>,
|
||||||
slippage_max_value: Option<f64>,
|
slippage_max_value: Option<f64>,
|
||||||
strict_value_budget: Option<bool>,
|
strict_value_budget: Option<bool>,
|
||||||
) {
|
) -> Result<(), String> {
|
||||||
if let Some(matching_type) = parse_matching_type(matching_type) {
|
if let Some(matching_type) = parse_matching_type(matching_type)? {
|
||||||
cfg.matching_type = matching_type;
|
cfg.matching_type = matching_type;
|
||||||
}
|
}
|
||||||
if slippage_model.is_some()
|
if slippage_model.is_some()
|
||||||
@@ -497,6 +503,7 @@ fn apply_execution_behavior_overrides(
|
|||||||
if let Some(enabled) = strict_value_budget {
|
if let Some(enabled) = strict_value_budget {
|
||||||
cfg.strict_value_budget = enabled;
|
cfg.strict_value_budget = enabled;
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_usize_after(text: &str, start: usize) -> Option<(usize, usize)> {
|
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,
|
strategy_id: &str,
|
||||||
signal_symbol: &str,
|
signal_symbol: &str,
|
||||||
strategy_spec: Option<&StrategyRuntimeSpec>,
|
strategy_spec: Option<&StrategyRuntimeSpec>,
|
||||||
) -> PlatformExprStrategyConfig {
|
) -> Result<PlatformExprStrategyConfig, String> {
|
||||||
let mut cfg = PlatformExprStrategyConfig::microcap_rotation();
|
let mut cfg = PlatformExprStrategyConfig::microcap_rotation();
|
||||||
cfg.strategy_name = strategy_id.to_string();
|
cfg.strategy_name = strategy_id.to_string();
|
||||||
if !signal_symbol.trim().is_empty() {
|
if !signal_symbol.trim().is_empty() {
|
||||||
@@ -634,7 +641,7 @@ pub fn platform_expr_config_from_spec(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let Some(spec) = strategy_spec else {
|
let Some(spec) = strategy_spec else {
|
||||||
return cfg;
|
return Ok(cfg);
|
||||||
};
|
};
|
||||||
let mut benchmark_short_explicit = false;
|
let mut benchmark_short_explicit = false;
|
||||||
let mut benchmark_long_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_volatility_coefficient,
|
||||||
engine.slippage_max_value,
|
engine.slippage_max_value,
|
||||||
engine.strict_value_budget,
|
engine.strict_value_budget,
|
||||||
);
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(spec_signal_symbol) = spec
|
if let Some(spec_signal_symbol) = spec
|
||||||
@@ -1151,7 +1158,7 @@ pub fn platform_expr_config_from_spec(
|
|||||||
execution.slippage_volatility_coefficient,
|
execution.slippage_volatility_coefficient,
|
||||||
execution.slippage_max_value,
|
execution.slippage_max_value,
|
||||||
execution.strict_value_budget,
|
execution.strict_value_budget,
|
||||||
);
|
)?;
|
||||||
}
|
}
|
||||||
if cfg.aiquant_transaction_cost
|
if cfg.aiquant_transaction_cost
|
||||||
&& cfg
|
&& cfg
|
||||||
@@ -1161,7 +1168,7 @@ pub fn platform_expr_config_from_spec(
|
|||||||
cfg.minimum_commission = None;
|
cfg.minimum_commission = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg
|
Ok(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_platform_rebalance_schedule(
|
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