93 lines
2.5 KiB
Python
93 lines
2.5 KiB
Python
"""Tests for Part VII, VIII, IX (shadow banking, CCP, CBDC)."""
|
|
|
|
import pytest
|
|
from fqbm.sheets.shadow_banking import (
|
|
leverage_ratio,
|
|
margin_spiral_risk,
|
|
repo_multiplier,
|
|
margin_spiral_simulation,
|
|
)
|
|
from fqbm.sheets.ccp import (
|
|
ccp_identity,
|
|
default_waterfall_triggered,
|
|
variation_margin_flow,
|
|
ccp_clearing_simulation,
|
|
)
|
|
from fqbm.sheets.cbdc import deposit_to_cbdc_shift, funding_gap
|
|
|
|
|
|
def test_leverage_ratio():
|
|
assert leverage_ratio(1000, 100) == 10.0
|
|
assert leverage_ratio(500, 0) == 0.0
|
|
|
|
|
|
def test_margin_spiral_risk():
|
|
r = margin_spiral_risk(100, 80, 0.1)
|
|
assert "margin_call_triggered" in r
|
|
assert "shortfall" in r
|
|
assert r["shortfall"] >= 0
|
|
|
|
|
|
def test_ccp_identity():
|
|
assert ccp_identity(100, 100) is True
|
|
assert ccp_identity(100, 99) is False
|
|
|
|
|
|
def test_default_waterfall_triggered():
|
|
assert default_waterfall_triggered(150, 100) is True
|
|
assert default_waterfall_triggered(50, 100) is False
|
|
|
|
|
|
def test_deposit_to_cbdc_shift():
|
|
d = deposit_to_cbdc_shift(50)
|
|
assert d["d_deposits"] == -50
|
|
assert d["d_reserves"] == -50
|
|
assert d["d_cbdc_liability"] == 50
|
|
|
|
|
|
def test_funding_gap():
|
|
assert funding_gap(100, 60) == 40
|
|
assert funding_gap(50, 80) == -30
|
|
|
|
|
|
def test_repo_multiplier():
|
|
r = repo_multiplier(100.0, haircut=0.02, rounds=3)
|
|
assert r["total_effective_collateral"] > 100
|
|
assert r["multiplier_implied"] > 1
|
|
assert r["rounds_used"] == 3
|
|
r0 = repo_multiplier(0, rounds=2)
|
|
assert r0["total_effective_collateral"] == 0
|
|
|
|
|
|
def test_margin_spiral_simulation():
|
|
r = margin_spiral_simulation(
|
|
initial_collateral=100,
|
|
margin_requirement=90,
|
|
haircut=0.1,
|
|
liquidity_buffer=5,
|
|
fire_sale_impact=0.2,
|
|
max_rounds=10,
|
|
)
|
|
assert "path_collateral" in r
|
|
assert "path_margin_calls" in r
|
|
assert "cumulative_forced_sales" in r
|
|
assert "waterfall_triggered" in r
|
|
assert len(r["path_collateral"]) >= 1
|
|
|
|
|
|
def test_variation_margin_flow():
|
|
vm = variation_margin_flow(-10.0, member_pays_when_positive=True)
|
|
assert vm == pytest.approx(10.0)
|
|
vm2 = variation_margin_flow(5.0, member_pays_when_positive=True)
|
|
assert vm2 == pytest.approx(-5.0)
|
|
|
|
|
|
def test_ccp_clearing_simulation():
|
|
results = ccp_clearing_simulation(
|
|
vm_calls_per_period=[5, 10, 15],
|
|
liquidity_buffer_start=20,
|
|
)
|
|
assert len(results) == 3
|
|
assert results[0]["buffer_end"] == 15
|
|
assert results[1]["buffer_end"] == 5
|
|
assert results[2]["waterfall_triggered"] is True |