拒绝废弃的引擎配置档案字段
This commit is contained in:
@@ -117,8 +117,6 @@ pub struct StrategyExecutionSpec {
|
|||||||
pub struct StrategyEngineConfig {
|
pub struct StrategyEngineConfig {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub template_id: Option<String>,
|
pub template_id: Option<String>,
|
||||||
#[serde(default, alias = "profile_name")]
|
|
||||||
pub profile_name: Option<String>,
|
|
||||||
#[serde(default, alias = "benchmark_symbol")]
|
#[serde(default, alias = "benchmark_symbol")]
|
||||||
pub benchmark_symbol: Option<String>,
|
pub benchmark_symbol: Option<String>,
|
||||||
#[serde(default, alias = "signal_symbol")]
|
#[serde(default, alias = "signal_symbol")]
|
||||||
@@ -837,6 +835,16 @@ fn reject_removed_compatibility_fields(value: &Value) -> Result<(), String> {
|
|||||||
"{section_name}.{field_name} has been removed; configure matching, risk, fees and scheduling explicitly"
|
"{section_name}.{field_name} has been removed; configure matching, risk, fees and scheduling explicitly"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if section_name != "execution" {
|
||||||
|
if let Some(field_name) = ["profileName", "profile_name"]
|
||||||
|
.iter()
|
||||||
|
.find(|field_name| section.contains_key(**field_name))
|
||||||
|
{
|
||||||
|
return Err(format!(
|
||||||
|
"{section_name}.{field_name} has been removed; configure matching, risk, fees and scheduling explicitly"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -2419,7 +2427,6 @@ mod tests {
|
|||||||
"signalSymbol": "000852.SH",
|
"signalSymbol": "000852.SH",
|
||||||
"benchmark": { "instrumentId": "000852.SH" },
|
"benchmark": { "instrumentId": "000852.SH" },
|
||||||
"universe": { "exclude": ["paused", "st", "kcb", "one_yuan"] },
|
"universe": { "exclude": ["paused", "st", "kcb", "one_yuan"] },
|
||||||
"engineConfig": { "profileName": "aiquant" },
|
|
||||||
"runtimeExpressions": {
|
"runtimeExpressions": {
|
||||||
"prelude": "let stocknum = 8;",
|
"prelude": "let stocknum = 8;",
|
||||||
"selection": {
|
"selection": {
|
||||||
@@ -2579,7 +2586,6 @@ mod tests {
|
|||||||
"stampTaxChangeDate": "2024-01-02"
|
"stampTaxChangeDate": "2024-01-02"
|
||||||
},
|
},
|
||||||
"engineConfig": {
|
"engineConfig": {
|
||||||
"profileName": "aiquant",
|
|
||||||
"commissionRate": 0.0008
|
"commissionRate": 0.0008
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -2868,7 +2874,6 @@ mod tests {
|
|||||||
"strictValueBudget": true
|
"strictValueBudget": true
|
||||||
},
|
},
|
||||||
"engineConfig": {
|
"engineConfig": {
|
||||||
"profileName": "aiquant",
|
|
||||||
"matchingType": "current_bar_close",
|
"matchingType": "current_bar_close",
|
||||||
"slippageModel": "none",
|
"slippageModel": "none",
|
||||||
"slippageValue": 0.0,
|
"slippageValue": 0.0,
|
||||||
@@ -3046,80 +3051,9 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn profile_name_does_not_inject_trading_behaviors() {
|
|
||||||
let spec = serde_json::json!({
|
|
||||||
"engineConfig": {
|
|
||||||
"profileName": "aiquant"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let cfg = platform_expr_config_from_value("", "", &spec).expect("config");
|
|
||||||
|
|
||||||
assert!(!cfg.daily_top_up_enabled);
|
|
||||||
assert!(!cfg.retry_empty_rebalance);
|
|
||||||
assert!(cfg.strict_value_budget);
|
|
||||||
|
|
||||||
let explicit_off = serde_json::json!({
|
|
||||||
"engineConfig": {
|
|
||||||
"profileName": "aiquant"
|
|
||||||
},
|
|
||||||
"runtimeExpressions": {
|
|
||||||
"trading": {
|
|
||||||
"dailyTopUp": false,
|
|
||||||
"dailyPositionTargetAdjust": false,
|
|
||||||
"rebalanceExistingPositions": true,
|
|
||||||
"selectionBufferMultiple": 1.5,
|
|
||||||
"dailyReplacementLimit": 2,
|
|
||||||
"retryEmptyRebalance": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let cfg = platform_expr_config_from_value("", "", &explicit_off).expect("config");
|
|
||||||
|
|
||||||
assert!(!cfg.daily_top_up_enabled);
|
|
||||||
assert!(!cfg.daily_position_target_adjust_enabled);
|
|
||||||
assert!(cfg.rebalance_existing_positions);
|
|
||||||
assert_eq!(cfg.selection_buffer_multiple, 1.5);
|
|
||||||
assert_eq!(cfg.daily_replacement_limit, 2);
|
|
||||||
assert!(!cfg.retry_empty_rebalance);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn engine_config_profile_name_is_metadata_only() {
|
|
||||||
let spec = serde_json::json!({
|
|
||||||
"engineConfig": {
|
|
||||||
"profileName": "aiquant"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let cfg = platform_expr_config_from_value("", "", &spec).expect("config");
|
|
||||||
assert!(!cfg.daily_top_up_enabled);
|
|
||||||
assert!(!cfg.retry_empty_rebalance);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn legacy_profile_name_does_not_inject_hidden_defaults() {
|
|
||||||
let spec = serde_json::json!({
|
|
||||||
"engineConfig": {
|
|
||||||
"profileName": "aiquant_rqalpha"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let cfg = platform_expr_config_from_value("", "", &spec).expect("config");
|
|
||||||
|
|
||||||
assert!(!cfg.daily_top_up_enabled);
|
|
||||||
assert!(!cfg.retry_empty_rebalance);
|
|
||||||
assert!(cfg.strict_value_budget);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn runtime_expressions_infer_ma_windows_from_literal_strategy_logic() {
|
fn runtime_expressions_infer_ma_windows_from_literal_strategy_logic() {
|
||||||
let spec = serde_json::json!({
|
let spec = serde_json::json!({
|
||||||
"engineConfig": {
|
|
||||||
"profileName": "aiquant"
|
|
||||||
},
|
|
||||||
"runtimeExpressions": {
|
"runtimeExpressions": {
|
||||||
"selection": {
|
"selection": {
|
||||||
"stockFilterExpr": "rolling_mean(\"close\", 5) > rolling_mean(\"close\", 10) && rolling_mean(\"close\", 10) > rolling_mean(\"close\", 30)"
|
"stockFilterExpr": "rolling_mean(\"close\", 5) > rolling_mean(\"close\", 10) && rolling_mean(\"close\", 10) > rolling_mean(\"close\", 30)"
|
||||||
@@ -3177,7 +3111,6 @@ mod tests {
|
|||||||
"instrumentId": "932000.CSI"
|
"instrumentId": "932000.CSI"
|
||||||
},
|
},
|
||||||
"engineConfig": {
|
"engineConfig": {
|
||||||
"profileName": "aiquant",
|
|
||||||
"indexThrottle": {
|
"indexThrottle": {
|
||||||
"shortDays": 10,
|
"shortDays": 10,
|
||||||
"longDays": 30,
|
"longDays": 30,
|
||||||
@@ -3206,7 +3139,6 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn parses_daily_schedule_time_for_execution_quotes() {
|
fn parses_daily_schedule_time_for_execution_quotes() {
|
||||||
let spec = serde_json::json!({
|
let spec = serde_json::json!({
|
||||||
"engineConfig": { "profileName": "aiquant" },
|
|
||||||
"runtimeExpressions": {
|
"runtimeExpressions": {
|
||||||
"schedule": { "frequency": "daily", "time": "09:33" }
|
"schedule": { "frequency": "daily", "time": "09:33" }
|
||||||
}
|
}
|
||||||
@@ -3225,7 +3157,6 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn multiple_trade_times_do_not_imply_delayed_limit_exit() {
|
fn multiple_trade_times_do_not_imply_delayed_limit_exit() {
|
||||||
let spec = serde_json::json!({
|
let spec = serde_json::json!({
|
||||||
"engineConfig": { "profileName": "aiquant" },
|
|
||||||
"rebalance": { "tradeTimes": ["10:31", "10:40"] },
|
"rebalance": { "tradeTimes": ["10:31", "10:40"] },
|
||||||
"runtimeExpressions": {
|
"runtimeExpressions": {
|
||||||
"schedule": { "frequency": "daily", "time": "10:40" }
|
"schedule": { "frequency": "daily", "time": "10:40" }
|
||||||
@@ -3246,7 +3177,6 @@ mod tests {
|
|||||||
fn rejects_removed_compatibility_profile() {
|
fn rejects_removed_compatibility_profile() {
|
||||||
let spec = serde_json::json!({
|
let spec = serde_json::json!({
|
||||||
"engineConfig": {
|
"engineConfig": {
|
||||||
"profileName": "cn_a_microcap_v1",
|
|
||||||
"compatibilityProfile": "aiquant_rqalpha"
|
"compatibilityProfile": "aiquant_rqalpha"
|
||||||
},
|
},
|
||||||
"rebalance": { "tradeTimes": ["09:31", "10:15"] },
|
"rebalance": { "tradeTimes": ["09:31", "10:15"] },
|
||||||
@@ -3263,10 +3193,21 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rejects_removed_engine_profile_name() {
|
||||||
|
let spec = serde_json::json!({
|
||||||
|
"engineConfig": {
|
||||||
|
"profileName": "aiquant"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let error = platform_expr_config_from_value("", "", &spec).expect_err("removed field");
|
||||||
|
assert!(error.to_string().contains("profileName has been removed"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_explicit_delayed_limit_open_exit() {
|
fn parses_explicit_delayed_limit_open_exit() {
|
||||||
let spec = serde_json::json!({
|
let spec = serde_json::json!({
|
||||||
"engineConfig": { "profileName": "aiquant" },
|
|
||||||
"runtimeExpressions": {
|
"runtimeExpressions": {
|
||||||
"schedule": { "frequency": "daily", "time": "10:40" },
|
"schedule": { "frequency": "daily", "time": "10:40" },
|
||||||
"trading": {
|
"trading": {
|
||||||
@@ -3290,9 +3231,8 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn explicit_delayed_limit_open_exit_false_overrides_aiquant_trade_times() {
|
fn explicit_delayed_limit_open_exit_false_overrides_trade_times() {
|
||||||
let spec = serde_json::json!({
|
let spec = serde_json::json!({
|
||||||
"engineConfig": { "profileName": "aiquant" },
|
|
||||||
"rebalance": { "tradeTimes": ["10:31", "10:40"] },
|
"rebalance": { "tradeTimes": ["10:31", "10:40"] },
|
||||||
"runtimeExpressions": {
|
"runtimeExpressions": {
|
||||||
"schedule": { "frequency": "daily", "time": "10:40" },
|
"schedule": { "frequency": "daily", "time": "10:40" },
|
||||||
|
|||||||
Reference in New Issue
Block a user