修复分钟事件轮动仅执行最后时点的问题
This commit is contained in:
@@ -672,6 +672,7 @@ pub struct PlatformExprStrategyConfig {
|
|||||||
pub completed_session_factor_fields: BTreeSet<String>,
|
pub completed_session_factor_fields: BTreeSet<String>,
|
||||||
pub candidate_symbols_by_date: BTreeMap<NaiveDate, BTreeSet<String>>,
|
pub candidate_symbols_by_date: BTreeMap<NaiveDate, BTreeSet<String>>,
|
||||||
pub intraday_execution_time: Option<NaiveTime>,
|
pub intraday_execution_time: Option<NaiveTime>,
|
||||||
|
pub session_event_times: Vec<NaiveTime>,
|
||||||
pub explicit_action_times: Vec<NaiveTime>,
|
pub explicit_action_times: Vec<NaiveTime>,
|
||||||
pub delayed_limit_open_exit_enabled: bool,
|
pub delayed_limit_open_exit_enabled: bool,
|
||||||
pub delayed_limit_open_exit_time: Option<NaiveTime>,
|
pub delayed_limit_open_exit_time: Option<NaiveTime>,
|
||||||
@@ -753,6 +754,7 @@ impl PlatformExprStrategyConfig {
|
|||||||
completed_session_factor_fields: BTreeSet::new(),
|
completed_session_factor_fields: BTreeSet::new(),
|
||||||
candidate_symbols_by_date: BTreeMap::new(),
|
candidate_symbols_by_date: BTreeMap::new(),
|
||||||
intraday_execution_time: None,
|
intraday_execution_time: None,
|
||||||
|
session_event_times: Vec::new(),
|
||||||
explicit_action_times: Vec::new(),
|
explicit_action_times: Vec::new(),
|
||||||
delayed_limit_open_exit_enabled: false,
|
delayed_limit_open_exit_enabled: false,
|
||||||
delayed_limit_open_exit_time: None,
|
delayed_limit_open_exit_time: None,
|
||||||
@@ -12294,13 +12296,15 @@ impl Strategy for PlatformExprStrategy {
|
|||||||
.is_some()
|
.is_some()
|
||||||
&& self.config.rotation_enabled
|
&& self.config.rotation_enabled
|
||||||
{
|
{
|
||||||
rules.push(
|
let schedule=self.config.rebalance_schedule.as_ref().expect("checked timed rebalance schedule");
|
||||||
self.config
|
if self.config.session_event_times.is_empty() {
|
||||||
.rebalance_schedule
|
rules.push(schedule.as_schedule_rule(ScheduleStage::OnDay));
|
||||||
.as_ref()
|
} else {
|
||||||
.expect("checked timed rebalance schedule")
|
for time in &self.config.session_event_times {
|
||||||
.as_schedule_rule(ScheduleStage::OnDay),
|
let mut timed=schedule.clone();timed.time_rule=Some(ScheduleTimeRule::physical_time(time.hour(),time.minute()));
|
||||||
);
|
rules.push(timed.as_schedule_rule(ScheduleStage::OnDay));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if self.config.explicit_actions.is_empty() {
|
if self.config.explicit_actions.is_empty() {
|
||||||
return rules;
|
return rules;
|
||||||
@@ -12363,6 +12367,7 @@ impl Strategy for PlatformExprStrategy {
|
|||||||
|
|
||||||
fn decision_quote_times(&self) -> Vec<NaiveTime> {
|
fn decision_quote_times(&self) -> Vec<NaiveTime> {
|
||||||
let mut times = BTreeSet::new();
|
let mut times = BTreeSet::new();
|
||||||
|
times.extend(self.config.session_event_times.iter().copied());
|
||||||
if self.uses_intraday_execution_quotes() {
|
if self.uses_intraday_execution_quotes() {
|
||||||
if self.config.explicit_action_times.is_empty() {
|
if self.config.explicit_action_times.is_empty() {
|
||||||
times.insert(self.intraday_execution_start_time());
|
times.insert(self.intraday_execution_start_time());
|
||||||
|
|||||||
@@ -2538,6 +2538,10 @@ pub fn platform_expr_config_from_spec(
|
|||||||
cfg.benchmark_symbol = normalize_symbol(&cfg.benchmark_symbol, None);
|
cfg.benchmark_symbol = normalize_symbol(&cfg.benchmark_symbol, None);
|
||||||
}
|
}
|
||||||
let trade_times = spec_trade_times(spec);
|
let trade_times = spec_trade_times(spec);
|
||||||
|
if crate::pattern_context::specs_in_value(&serde_json::to_value(spec).map_err(|e|e.to_string())?)?.iter().any(|p|p.template=="session_event") {
|
||||||
|
if trade_times.is_empty() {return Err("session_event_requires_explicit_trade_times".into());}
|
||||||
|
cfg.session_event_times=trade_times.clone();
|
||||||
|
}
|
||||||
let explicit_trading_schedule = spec
|
let explicit_trading_schedule = spec
|
||||||
.runtime_expressions
|
.runtime_expressions
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -4458,6 +4462,20 @@ mod tests {
|
|||||||
assert_eq!(cfg.delayed_limit_open_exit_time, None);
|
assert_eq!(cfg.delayed_limit_open_exit_time, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn session_rotation_keeps_every_declared_clock_not_only_the_last_one() {
|
||||||
|
use crate::Strategy;
|
||||||
|
let literal=serde_json::to_string(&serde_json::json!({"template":"session_event","session_event":"INTRADAY_VOLUME_SPIKE","parameters":{}}).to_string()).unwrap();
|
||||||
|
let mut spec=serde_json::json!({"rebalance":{"tradeTimes":["09:35","10:40","14:59"]},"runtimeExpressions":{"schedule":{"frequency":"daily","time":"14:59"},"trading":{"rotationEnabled":true,"buyFilterExpr":format!("pattern_signal({literal})")}},"execution":{"matchingType":"minute_last"}});
|
||||||
|
let config=platform_expr_config_from_value("session","000300.SH",&spec).unwrap();
|
||||||
|
assert_eq!(config.session_event_times.len(),3);
|
||||||
|
let strategy=crate::PlatformExprStrategy::new(config);
|
||||||
|
assert_eq!(strategy.schedule_rules().len(),3);
|
||||||
|
assert_eq!(strategy.decision_quote_times().len(),3);
|
||||||
|
spec["rebalance"]["tradeTimes"]=serde_json::json!([]);
|
||||||
|
assert!(platform_expr_config_from_value("session","000300.SH",&spec).unwrap_err().to_string().contains("explicit_trade_times"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn explicit_trading_schedule_overrides_rebalance_trade_times() {
|
fn explicit_trading_schedule_overrides_rebalance_trade_times() {
|
||||||
let spec = serde_json::json!({
|
let spec = serde_json::json!({
|
||||||
|
|||||||
Reference in New Issue
Block a user