减少运行时辅助函数参数分配
This commit is contained in:
@@ -6158,7 +6158,7 @@ impl PlatformExprStrategy {
|
|||||||
) -> Result<RuntimeHelperResolution, BacktestError> {
|
) -> Result<RuntimeHelperResolution, BacktestError> {
|
||||||
match helper {
|
match helper {
|
||||||
"factor" => {
|
"factor" => {
|
||||||
let key = Self::normalize_runtime_factor_key(&Self::parse_string_or_identifier(
|
let key = Self::normalize_runtime_factor_key(Self::parse_string_or_identifier_ref(
|
||||||
args.first().map(String::as_str).unwrap_or_default(),
|
args.first().map(String::as_str).unwrap_or_default(),
|
||||||
)?);
|
)?);
|
||||||
if let Some((field, lookback)) = framework_stock_rolling_factor_requirement(&key) {
|
if let Some((field, lookback)) = framework_stock_rolling_factor_requirement(&key) {
|
||||||
@@ -6190,7 +6190,7 @@ impl PlatformExprStrategy {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
"day_factor" => {
|
"day_factor" => {
|
||||||
let key = Self::normalize_runtime_factor_key(&Self::parse_string_or_identifier(
|
let key = Self::normalize_runtime_factor_key(Self::parse_string_or_identifier_ref(
|
||||||
args.first().map(String::as_str).unwrap_or_default(),
|
args.first().map(String::as_str).unwrap_or_default(),
|
||||||
)?);
|
)?);
|
||||||
Ok(RuntimeHelperResolution::Expression(format!(
|
Ok(RuntimeHelperResolution::Expression(format!(
|
||||||
@@ -6204,7 +6204,7 @@ impl PlatformExprStrategy {
|
|||||||
"{helper} expects 2 arguments"
|
"{helper} expects 2 arguments"
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
let field = Self::parse_string_or_identifier(&args[0])?;
|
let field = Self::parse_string_or_identifier_ref(&args[0])?;
|
||||||
let lookback = Self::parse_positive_usize(&args[1])?;
|
let lookback = Self::parse_positive_usize(&args[1])?;
|
||||||
let value = self.resolve_rolling_mean(ctx, day, stock, &field, lookback)?;
|
let value = self.resolve_rolling_mean(ctx, day, stock, &field, lookback)?;
|
||||||
Ok(RuntimeHelperResolution::Number(value))
|
Ok(RuntimeHelperResolution::Number(value))
|
||||||
@@ -6215,7 +6215,7 @@ impl PlatformExprStrategy {
|
|||||||
"rolling_mean_current expects 2 arguments".to_string(),
|
"rolling_mean_current expects 2 arguments".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let field = Self::parse_string_or_identifier(&args[0])?;
|
let field = Self::parse_string_or_identifier_ref(&args[0])?;
|
||||||
let lookback = Self::parse_positive_usize(&args[1])?;
|
let lookback = Self::parse_positive_usize(&args[1])?;
|
||||||
let value = self.resolve_current_rolling_mean(ctx, day, stock, &field, lookback)?;
|
let value = self.resolve_current_rolling_mean(ctx, day, stock, &field, lookback)?;
|
||||||
Ok(RuntimeHelperResolution::Number(value))
|
Ok(RuntimeHelperResolution::Number(value))
|
||||||
@@ -6226,7 +6226,7 @@ impl PlatformExprStrategy {
|
|||||||
"rolling_max_current expects field and lookback".to_string(),
|
"rolling_max_current expects field and lookback".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let field = Self::parse_string_or_identifier(&args[0])?;
|
let field = Self::parse_string_or_identifier_ref(&args[0])?;
|
||||||
let lookback = Self::parse_positive_usize(&args[1])?;
|
let lookback = Self::parse_positive_usize(&args[1])?;
|
||||||
let values =
|
let values =
|
||||||
self.resolve_current_rolling_values(ctx, day, stock, &field, lookback)?;
|
self.resolve_current_rolling_values(ctx, day, stock, &field, lookback)?;
|
||||||
@@ -6239,7 +6239,7 @@ impl PlatformExprStrategy {
|
|||||||
"rolling_return_stddev_current expects field and return count".to_string(),
|
"rolling_return_stddev_current expects field and return count".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let field = Self::parse_string_or_identifier(&args[0])?;
|
let field = Self::parse_string_or_identifier_ref(&args[0])?;
|
||||||
let return_count = Self::parse_positive_usize(&args[1])?;
|
let return_count = Self::parse_positive_usize(&args[1])?;
|
||||||
let values = self.resolve_current_rolling_values(
|
let values = self.resolve_current_rolling_values(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -6278,7 +6278,7 @@ impl PlatformExprStrategy {
|
|||||||
"{helper} expects field and lookback"
|
"{helper} expects field and lookback"
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
let field = Self::parse_string_or_identifier(&args[0])?;
|
let field = Self::parse_string_or_identifier_ref(&args[0])?;
|
||||||
let lookback = Self::parse_positive_usize(&args[1])?;
|
let lookback = Self::parse_positive_usize(&args[1])?;
|
||||||
let values = self.resolve_rolling_values(ctx, day, stock, &field, lookback)?;
|
let values = self.resolve_rolling_values(ctx, day, stock, &field, lookback)?;
|
||||||
let value = match helper {
|
let value = match helper {
|
||||||
@@ -6297,7 +6297,7 @@ impl PlatformExprStrategy {
|
|||||||
"pct_change expects field and lookback".to_string(),
|
"pct_change expects field and lookback".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let field = Self::parse_string_or_identifier(&args[0])?;
|
let field = Self::parse_string_or_identifier_ref(&args[0])?;
|
||||||
let lookback = Self::parse_positive_usize(&args[1])?;
|
let lookback = Self::parse_positive_usize(&args[1])?;
|
||||||
let values = self.resolve_rolling_values(
|
let values = self.resolve_rolling_values(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -7083,6 +7083,35 @@ impl PlatformExprStrategy {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse the literal/identifier forms used by runtime helpers without
|
||||||
|
/// allocating a new String on every stock evaluation. The owned parser
|
||||||
|
/// above remains the boundary for helpers that must retain the value.
|
||||||
|
fn parse_string_or_identifier_ref(raw: &str) -> Result<&str, BacktestError> {
|
||||||
|
let trimmed = raw.trim();
|
||||||
|
if trimmed.is_empty() {
|
||||||
|
return Err(BacktestError::Execution(
|
||||||
|
"platform helper argument cannot be empty".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if let Some(value) = trimmed
|
||||||
|
.strip_prefix('"')
|
||||||
|
.and_then(|value| value.strip_suffix('"'))
|
||||||
|
.or_else(|| {
|
||||||
|
trimmed
|
||||||
|
.strip_prefix('\'')
|
||||||
|
.and_then(|value| value.strip_suffix('\''))
|
||||||
|
})
|
||||||
|
{
|
||||||
|
return Ok(value);
|
||||||
|
}
|
||||||
|
if Self::is_expression_identifier(trimmed) {
|
||||||
|
return Ok(trimmed);
|
||||||
|
}
|
||||||
|
Err(BacktestError::Execution(format!(
|
||||||
|
"platform helper expects a factor name or string literal, got {trimmed}"
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
fn normalize_runtime_factor_key(key: &str) -> String {
|
fn normalize_runtime_factor_key(key: &str) -> String {
|
||||||
key.trim()
|
key.trim()
|
||||||
.trim_matches('"')
|
.trim_matches('"')
|
||||||
|
|||||||
Reference in New Issue
Block a user