1"""Balance-sheet invariants of the Model C ledger under random sequences of operations (Hypothesis)."""2import numpy as np3from hypothesis import given, settings, strategies as st45from age.banking.ledger import Ledger678def make(n=6, margin=0.5, rf=0.01, fee=0.001):9 return Ledger(n, np.full(n, 1.0), np.full(n, 1.0), 2.0, margin, fee, price0=5.0, rf=rf, bank_capital_ratio=0.05)101112@settings(max_examples=100, deadline=None)13@given(ops=st.lists(st.tuples(st.sampled_from(['div', 'int', 'borrow', 'repay', 'trade', 'mtm']),14 st.integers(0, 5), st.integers(0, 5), st.floats(0.0, 2.0), st.floats(0.5, 8.0)),15 min_size=1, max_size=40))16def test_invariants_hold_under_random_operations(ops):17 led = make()18 for op, i, j, q, px in ops:19 if op == 'div':20 led.pay_dividend(q * 0.05)21 elif op == 'int':22 led.accrue_interest()23 elif op == 'borrow':24 led.borrow(i, q)25 elif op == 'repay':26 led.repay(i, q)27 elif op == 'trade':28 led.settle_trade(i, j, q * 0.3, px)29 else:30 led.mark_to_market(px, liquidation_impact=0.5)31 led.check() # raises on any violated identity32 # margin rule holds after mark-to-market33 led.mark_to_market(led.price)34 assert np.all(led.loan <= (1 - led.margin) * led.price * led.holdings + 1e-6)353637def test_every_flow_has_a_counterparty():38 led = make()39 before = led.cash.sum() + led.F + led.bank_equity - led.loan.sum()40 assert led.settle_trade(0, 1, 0.1, 5.0)41 after = led.cash.sum() + led.F + led.bank_equity - led.loan.sum()42 assert np.isclose(before, after) # trades and fees are transfers, reserves unchanged43 led.pay_dividend(0.1)44 assert np.isclose(led.reserves - led._reserves0, led.injections)454647def test_default_and_bail_in_are_explicit():48 led = Ledger(3, np.array([0.0, 5.0, 5.0]), np.array([3.0, 0.0, 0.0]), 0.2, 0.5, 0.0, price0=2.0, rf=0.0)49 granted = led.borrow(0, 3.0) # capacity (1-m) p h = 3.050 assert np.isclose(granted, 3.0)51 led.cash[0] = 0.0 # borrower spends the loan outside the system? no: keep in system52 led.settle_trade(1, 0, 0.0, 2.0)53 # price collapses -> margin breach, forced sale, default, bank equity 0.2 cannot absorb -> bail-in54 led.cash[0] = 0.0; led.reserves -= 3.0; led.injections -= 3.0 # simulate consumption of the loan (explicit outflow)55 led.check()56 res = led.mark_to_market(0.4, liquidation_impact=0.0)57 assert res['defaults'] == 158 assert led.bank_equity >= -1e-959 assert led.deposit_haircuts > 0 or led.loan_losses > 060