复用策略表达式解析计划
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use chrono::{Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime};
|
use chrono::{Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime};
|
||||||
use rhai::{AST, Dynamic, Engine, Map, Scope};
|
use rhai::{AST, Dynamic, Engine, Map, Scope};
|
||||||
@@ -835,6 +836,11 @@ impl<'a> SelectiveExpressionScope<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ExpressionEvalPlan {
|
||||||
|
normalized: String,
|
||||||
|
identifiers: BTreeSet<String>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PlatformExprStrategy {
|
pub struct PlatformExprStrategy {
|
||||||
config: PlatformExprStrategyConfig,
|
config: PlatformExprStrategyConfig,
|
||||||
engine: Engine,
|
engine: Engine,
|
||||||
@@ -857,6 +863,7 @@ pub struct PlatformExprStrategy {
|
|||||||
/// 命中计数与未命中计数,便于在 unit test 中验证缓存生效;非生产指标。
|
/// 命中计数与未命中计数,便于在 unit test 中验证缓存生效;非生产指标。
|
||||||
cache_hits: RefCell<u64>,
|
cache_hits: RefCell<u64>,
|
||||||
cache_misses: RefCell<u64>,
|
cache_misses: RefCell<u64>,
|
||||||
|
expression_plan_cache: RefCell<HashMap<String, Arc<ExpressionEvalPlan>>>,
|
||||||
normalized_prelude: String,
|
normalized_prelude: String,
|
||||||
prelude_identifier_candidates: BTreeSet<String>,
|
prelude_identifier_candidates: BTreeSet<String>,
|
||||||
prelude_declared_identifiers: BTreeSet<String>,
|
prelude_declared_identifiers: BTreeSet<String>,
|
||||||
@@ -1177,6 +1184,7 @@ impl PlatformExprStrategy {
|
|||||||
compiled_cache: RefCell::new(HashMap::new()),
|
compiled_cache: RefCell::new(HashMap::new()),
|
||||||
cache_hits: RefCell::new(0),
|
cache_hits: RefCell::new(0),
|
||||||
cache_misses: RefCell::new(0),
|
cache_misses: RefCell::new(0),
|
||||||
|
expression_plan_cache: RefCell::new(HashMap::new()),
|
||||||
normalized_prelude,
|
normalized_prelude,
|
||||||
prelude_identifier_candidates,
|
prelude_identifier_candidates,
|
||||||
prelude_declared_identifiers,
|
prelude_declared_identifiers,
|
||||||
@@ -4453,8 +4461,9 @@ impl PlatformExprStrategy {
|
|||||||
stock: Option<&StockExpressionState>,
|
stock: Option<&StockExpressionState>,
|
||||||
position: Option<&PositionExpressionState>,
|
position: Option<&PositionExpressionState>,
|
||||||
) -> Result<Dynamic, BacktestError> {
|
) -> Result<Dynamic, BacktestError> {
|
||||||
let normalized_expr = Self::normalize_expr(expr);
|
let expression_plan = self.expression_eval_plan(expr);
|
||||||
let normalized_identifiers = Self::extract_identifier_candidates(&normalized_expr);
|
let normalized_expr = expression_plan.normalized.as_str();
|
||||||
|
let normalized_identifiers = &expression_plan.identifiers;
|
||||||
let prelude_identifiers = &self.prelude_identifier_candidates;
|
let prelude_identifiers = &self.prelude_identifier_candidates;
|
||||||
let include_day_factors = normalized_identifiers.contains("day_factors")
|
let include_day_factors = normalized_identifiers.contains("day_factors")
|
||||||
|| normalized_identifiers.contains("day_factor")
|
|| normalized_identifiers.contains("day_factor")
|
||||||
@@ -4481,27 +4490,30 @@ impl PlatformExprStrategy {
|
|||||||
let expanded_expr =
|
let expanded_expr =
|
||||||
self.expand_runtime_helpers(ctx, day, stock, &normalized_expr, &mut scope)?;
|
self.expand_runtime_helpers(ctx, day, stock, &normalized_expr, &mut scope)?;
|
||||||
if let Some(item) = stock {
|
if let Some(item) = stock {
|
||||||
let mut expanded_identifiers = Self::extract_identifier_candidates(&expanded_prelude);
|
let factor_identifiers = normalized_identifiers.iter().chain(
|
||||||
expanded_identifiers.extend(Self::extract_identifier_candidates(&expanded_expr));
|
prelude_identifiers
|
||||||
for identifier in expanded_identifiers {
|
.iter()
|
||||||
|
.filter(|identifier| !normalized_identifiers.contains(*identifier)),
|
||||||
|
);
|
||||||
|
for identifier in factor_identifiers {
|
||||||
if Self::is_reserved_scope_name(identifier.as_str())
|
if Self::is_reserved_scope_name(identifier.as_str())
|
||||||
|| self.prelude_declared_identifiers.contains(&identifier)
|
|| self.prelude_declared_identifiers.contains(identifier)
|
||||||
|| (!self.stock_extra_factor_identifiers.contains(&identifier)
|
|| (!self.stock_extra_factor_identifiers.contains(identifier)
|
||||||
&& !item.extra_factors.contains_key(&identifier)
|
&& !item.extra_factors.contains_key(identifier)
|
||||||
&& !day.available_factor_names.contains(&identifier)
|
&& !day.available_factor_names.contains(identifier)
|
||||||
&& !day.available_text_factor_names.contains(&identifier))
|
&& !day.available_text_factor_names.contains(identifier))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Some(value) = item.extra_text_factors.get(&identifier) {
|
if let Some(value) = item.extra_text_factors.get(identifier) {
|
||||||
scope.push_dynamic(identifier, Dynamic::from(value.clone()));
|
scope.push_dynamic(identifier.clone(), Dynamic::from(value.clone()));
|
||||||
} else {
|
} else {
|
||||||
let value = item
|
let value = item
|
||||||
.extra_factors
|
.extra_factors
|
||||||
.get(&identifier)
|
.get(identifier)
|
||||||
.copied()
|
.copied()
|
||||||
.unwrap_or(f64::NAN);
|
.unwrap_or(f64::NAN);
|
||||||
scope.push_dynamic(identifier, Dynamic::from(value));
|
scope.push_dynamic(identifier.clone(), Dynamic::from(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4514,6 +4526,21 @@ impl PlatformExprStrategy {
|
|||||||
self.eval_with_cache(&mut scope, &script)
|
self.eval_with_cache(&mut scope, &script)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expression_eval_plan(&self, expr: &str) -> Arc<ExpressionEvalPlan> {
|
||||||
|
if let Some(plan) = self.expression_plan_cache.borrow().get(expr).cloned() {
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
let normalized = Self::normalize_expr(expr);
|
||||||
|
let plan = Arc::new(ExpressionEvalPlan {
|
||||||
|
identifiers: Self::extract_identifier_candidates(&normalized),
|
||||||
|
normalized,
|
||||||
|
});
|
||||||
|
self.expression_plan_cache
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(expr.to_string(), Arc::clone(&plan));
|
||||||
|
plan
|
||||||
|
}
|
||||||
|
|
||||||
fn normalize_expr(expr: &str) -> String {
|
fn normalize_expr(expr: &str) -> String {
|
||||||
let expr = Self::normalize_runtime_field_aliases(expr.trim());
|
let expr = Self::normalize_runtime_field_aliases(expr.trim());
|
||||||
let expr = Self::normalize_python_numeric_division(&expr);
|
let expr = Self::normalize_python_numeric_division(&expr);
|
||||||
|
|||||||
Reference in New Issue
Block a user