fix: preserve missing numeric factors and reject nonfinite truthiness

This commit is contained in:
boris
2026-09-09 02:51:26 +08:00
parent 078839b0f3
commit dd6b37be16
+19 -9
View File
@@ -4687,7 +4687,7 @@ impl PlatformExprStrategy {
} else if intraday_same_day_factor {
f64::NAN
} else {
factor.extra_factors.get("amount").copied().unwrap_or(0.0)
factor.extra_factors.get("amount").copied().unwrap_or(f64::NAN)
};
let market_cap_bn = decision_market_cap_bn(factor);
let free_float_cap_bn = decision_free_float_cap_bn(factor);
@@ -4769,8 +4769,8 @@ impl PlatformExprStrategy {
minute_volume: market.minute_volume as i64,
bid1_volume: market.bid1_volume as i64,
ask1_volume: market.ask1_volume as i64,
turnover_ratio: factor.turnover_ratio.unwrap_or(0.0),
effective_turnover_ratio: factor.effective_turnover_ratio.unwrap_or(0.0),
turnover_ratio: factor.turnover_ratio.unwrap_or(f64::NAN),
effective_turnover_ratio: factor.effective_turnover_ratio.unwrap_or(f64::NAN),
open: feature_market.day_open,
high: expression_high,
low: expression_low,
@@ -8359,7 +8359,7 @@ impl PlatformExprStrategy {
if let Some(value) = self.eval_numeric_vm(ctx, expr, day, stock, position)? {
return match value {
NumericVmValue::Boolean(boolean) => Ok(boolean),
NumericVmValue::Number(number) => Ok(number != 0.0),
NumericVmValue::Number(number) => Ok(number.is_finite() && number != 0.0),
};
}
let value = self.eval_dynamic(ctx, expr, day, stock, position)?;
@@ -8367,7 +8367,7 @@ impl PlatformExprStrategy {
return Ok(boolean);
}
if let Some(number) = value.clone().try_cast::<f64>() {
return Ok(number != 0.0);
return Ok(number.is_finite() && number != 0.0);
}
if let Some(number) = value.try_cast::<i64>() {
return Ok(number != 0);
@@ -16524,8 +16524,8 @@ mod tests {
market_cap_bn: 12.0,
free_float_cap_bn: 10.0,
pe_ttm: 8.0,
turnover_ratio: Some(1.0),
effective_turnover_ratio: Some(1.0),
turnover_ratio: None,
effective_turnover_ratio: None,
adjustment_factor_backward1: None,
extra_factors: BTreeMap::new(),
},
@@ -16535,8 +16535,8 @@ mod tests {
market_cap_bn: 12.0,
free_float_cap_bn: 10.0,
pe_ttm: 8.0,
turnover_ratio: Some(1.0),
effective_turnover_ratio: Some(1.0),
turnover_ratio: Some(0.0),
effective_turnover_ratio: Some(0.0),
adjustment_factor_backward1: None,
extra_factors: BTreeMap::from([
("model_score".into(), 2.0),
@@ -16601,6 +16601,16 @@ mod tests {
.expect("present stock state");
assert!(day.available_factor_names.contains("model_score"));
assert!(missing_stock.turnover_ratio.is_nan());
assert!(missing_stock.effective_turnover_ratio.is_nan());
assert_eq!(present_stock.turnover_ratio, 0.0);
assert!(!strategy.eval_bool(&ctx, "model_score", &day, Some(&missing_stock), None).unwrap());
assert!(strategy.eval_bool(&ctx, "model_score", &day, Some(&present_stock), None).unwrap());
for field in ["turnover_ratio", "effective_turnover_ratio"] {
let predicate = format!("{field} < 1.0");
assert!(!strategy.eval_bool(&ctx, &predicate, &day, Some(&missing_stock), None).unwrap());
assert!(strategy.eval_bool(&ctx, &predicate, &day, Some(&present_stock), None).unwrap());
}
assert!(
!strategy
.stock_passes_expr(&ctx, &day, &missing_stock)