feat: connect portfolio loss to finalized accounting and daily risk clock
This commit is contained in:
@@ -453,8 +453,10 @@ mod tests {
|
||||
state.decide(date(2), Some(date(1)), time(2, 1), 0.9),
|
||||
Err(PortfolioLossError::SessionDiscontinuity)
|
||||
);
|
||||
let mut late = state.clone();
|
||||
late.last_session.as_mut().unwrap().available_at = time(2, 1);
|
||||
let mut late = PortfolioLossState::new(config(), date(0)).unwrap();
|
||||
let mut delayed = session(0, 1.0, 0.99, 1.0);
|
||||
delayed.available_at = time(2, 1);
|
||||
late.observe(delayed).unwrap();
|
||||
assert_eq!(
|
||||
late.decide(date(1), Some(date(0)), time(1, 1), 0.9),
|
||||
Err(PortfolioLossError::ObservationNotVisible)
|
||||
@@ -481,4 +483,35 @@ mod tests {
|
||||
assert_eq!(decision.target_exposure, 0.9);
|
||||
assert_eq!(state.last_session().unwrap().date, date(19));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn restored_state_rejects_changed_policy_and_forged_cooldown() {
|
||||
let state = PortfolioLossState::new(config(), date(0)).unwrap();
|
||||
let mut changed = config();
|
||||
changed.floor_exposure = 0.5;
|
||||
assert_eq!(
|
||||
state.validate(&changed),
|
||||
Err(PortfolioLossError::StateMismatch)
|
||||
);
|
||||
let mut forged = state.clone();
|
||||
forged.cooldown_remaining = 1;
|
||||
assert_eq!(
|
||||
forged.validate(&config()),
|
||||
Err(PortfolioLossError::StateMismatch)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nav_serialization_preserves_float_bits() {
|
||||
let mut seed = 0xabcddcba12345678_u64;
|
||||
for _ in 0..2000 {
|
||||
seed ^= seed << 13;
|
||||
seed ^= seed >> 7;
|
||||
seed ^= seed << 17;
|
||||
let value = 0.01 + (seed as f64 / u64::MAX as f64) * 9.99;
|
||||
let serialized = serde_json::to_string(&value).unwrap();
|
||||
let restored: f64 = serde_json::from_str(&serialized).unwrap();
|
||||
assert_eq!(value.to_bits(), restored.to_bits());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user