严格校验换股证据并原子提交公司行为批次
This commit is contained in:
@@ -459,19 +459,29 @@ impl CorporateAction {
|
||||
self.successor_symbol
|
||||
.as_ref()
|
||||
.is_some_and(|symbol| !symbol.trim().is_empty())
|
||||
&& self.successor_ratio_value() > 0.0
|
||||
}
|
||||
|
||||
pub fn successor_ratio_value(&self) -> f64 {
|
||||
self.successor_ratio
|
||||
.filter(|ratio| ratio.is_finite() && *ratio > 0.0)
|
||||
.unwrap_or(1.0)
|
||||
}
|
||||
|
||||
pub fn successor_cash_value(&self) -> f64 {
|
||||
self.successor_cash
|
||||
.filter(|cash| cash.is_finite())
|
||||
.unwrap_or(0.0)
|
||||
/// A code mapping alone is not evidence for a 1:1 financial conversion.
|
||||
/// An absent cash component means no declared cash leg; an invalid one
|
||||
/// must never be replaced with zero.
|
||||
pub(crate) fn validated_successor_terms(&self) -> Result<Option<(&str, f64, f64)>, String> {
|
||||
let fail = |reason: &str| format!(
|
||||
"corporate_action_{reason}: symbol={} action_date={}", self.symbol, self.date);
|
||||
let Some(symbol) = self.successor_symbol.as_deref() else {
|
||||
if self.successor_ratio.is_some() || self.successor_cash.is_some() {
|
||||
return Err(fail("successor_symbol_missing"));
|
||||
}
|
||||
return Ok(None);
|
||||
};
|
||||
if symbol.is_empty() || symbol.trim() != symbol || symbol == self.symbol
|
||||
|| self.symbol.is_empty() || self.symbol.trim() != self.symbol {
|
||||
return Err(fail("successor_symbol_invalid"));
|
||||
}
|
||||
let ratio = self.successor_ratio.filter(|ratio| ratio.is_finite() && *ratio > 0.)
|
||||
.ok_or_else(|| fail("successor_ratio_missing_or_invalid"))?;
|
||||
let cash = self.successor_cash.unwrap_or(0.);
|
||||
if !cash.is_finite() { return Err(fail("successor_cash_invalid")); }
|
||||
Ok(Some((symbol, ratio, cash)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user