Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
This commit is contained in:
@@ -0,0 +1,639 @@
|
||||
//! # Application 6: Anti-Cascade Financial Systems
|
||||
//!
|
||||
//! Transactions, leverage, or derivatives that increase systemic incoherence
|
||||
//! are throttled or blocked automatically.
|
||||
//!
|
||||
//! ## Problem
|
||||
//! Financial cascades (2008, flash crashes) happen when local actions
|
||||
//! destroy global coherence faster than the system can respond.
|
||||
//!
|
||||
//! ## Δ-Behavior Solution
|
||||
//! Every transaction must preserve or improve systemic coherence.
|
||||
//! High-risk operations face exponential energy costs.
|
||||
//!
|
||||
//! ## Exotic Result
|
||||
//! A financial system that cannot cascade into collapse by construction.
|
||||
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
/// A financial system with coherence-enforced stability
|
||||
pub struct AntiCascadeFinancialSystem {
|
||||
/// Market participants
|
||||
participants: HashMap<String, Participant>,
|
||||
|
||||
/// Open positions
|
||||
positions: Vec<Position>,
|
||||
|
||||
/// Systemic coherence (1.0 = stable, 0.0 = collapse)
|
||||
coherence: f64,
|
||||
|
||||
/// Coherence thresholds
|
||||
warning_threshold: f64,
|
||||
critical_threshold: f64,
|
||||
lockdown_threshold: f64,
|
||||
|
||||
/// Maximum allowed leverage system-wide
|
||||
max_system_leverage: f64,
|
||||
|
||||
/// Current aggregate leverage
|
||||
current_leverage: f64,
|
||||
|
||||
/// Transaction queue (pending during high stress)
|
||||
pending_transactions: Vec<Transaction>,
|
||||
|
||||
/// Circuit breaker state
|
||||
circuit_breaker: CircuitBreakerState,
|
||||
|
||||
/// Historical coherence for trend analysis
|
||||
coherence_history: VecDeque<f64>,
|
||||
|
||||
/// Cached coherence factors (updated when underlying data changes)
|
||||
cached_leverage_factor: f64,
|
||||
cached_depth_factor: f64,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Participant {
|
||||
pub id: String,
|
||||
pub capital: f64,
|
||||
pub exposure: f64,
|
||||
pub risk_rating: f64, // 0.0 = safe, 1.0 = risky
|
||||
pub interconnectedness: f64, // How many counterparties
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Position {
|
||||
pub holder: String,
|
||||
pub counterparty: String,
|
||||
pub notional: f64,
|
||||
pub leverage: f64,
|
||||
pub derivative_depth: u8, // 0 = spot, 1 = derivative, 2 = derivative of derivative, etc.
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Transaction {
|
||||
pub id: u64,
|
||||
pub from: String,
|
||||
pub to: String,
|
||||
pub amount: f64,
|
||||
pub transaction_type: TransactionType,
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum TransactionType {
|
||||
/// Simple transfer
|
||||
Transfer,
|
||||
/// Open leveraged position
|
||||
OpenLeverage { leverage: f64 },
|
||||
/// Close position
|
||||
ClosePosition { position_id: usize },
|
||||
/// Create derivative
|
||||
CreateDerivative { underlying_position: usize },
|
||||
/// Margin call
|
||||
MarginCall { participant: String },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum CircuitBreakerState {
|
||||
/// Normal operation
|
||||
Open,
|
||||
/// Elevated monitoring
|
||||
Cautious,
|
||||
/// Only risk-reducing transactions allowed
|
||||
Restricted,
|
||||
/// All transactions halted
|
||||
Halted,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TransactionResult {
|
||||
/// Transaction executed
|
||||
Executed {
|
||||
coherence_impact: f64,
|
||||
fee_multiplier: f64,
|
||||
},
|
||||
/// Transaction queued for later
|
||||
Queued { reason: String },
|
||||
/// Transaction rejected
|
||||
Rejected { reason: String },
|
||||
/// System halted
|
||||
SystemHalted,
|
||||
}
|
||||
|
||||
impl AntiCascadeFinancialSystem {
|
||||
pub fn new() -> Self {
|
||||
let mut history = VecDeque::with_capacity(100);
|
||||
history.push_back(1.0);
|
||||
Self {
|
||||
participants: HashMap::new(),
|
||||
positions: Vec::new(),
|
||||
coherence: 1.0,
|
||||
warning_threshold: 0.7,
|
||||
critical_threshold: 0.5,
|
||||
lockdown_threshold: 0.3,
|
||||
max_system_leverage: 10.0,
|
||||
current_leverage: 1.0,
|
||||
pending_transactions: Vec::new(),
|
||||
circuit_breaker: CircuitBreakerState::Open,
|
||||
coherence_history: history,
|
||||
cached_leverage_factor: 0.9, // 1.0 - (1.0 / 10.0) for initial leverage
|
||||
cached_depth_factor: 1.0, // No positions initially
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_participant(&mut self, id: &str, capital: f64) {
|
||||
self.participants.insert(id.to_string(), Participant {
|
||||
id: id.to_string(),
|
||||
capital,
|
||||
exposure: 0.0,
|
||||
risk_rating: 0.0,
|
||||
interconnectedness: 0.0,
|
||||
});
|
||||
}
|
||||
|
||||
/// Calculate systemic coherence based on multiple risk factors
|
||||
/// Optimized: Single-pass calculation for participant metrics
|
||||
fn calculate_coherence(&self) -> f64 {
|
||||
if self.participants.is_empty() {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
// Use pre-computed cached factors for leverage and depth
|
||||
let leverage_factor = self.cached_leverage_factor;
|
||||
let depth_factor = self.cached_depth_factor;
|
||||
|
||||
// Single-pass calculation for interconnectedness, exposure, and capital
|
||||
let (sum_interconnect, total_exposure, total_capital) = self.participants.values()
|
||||
.fold((0.0, 0.0, 0.0), |(ic, exp, cap), p| {
|
||||
(ic + p.interconnectedness, exp + p.exposure, cap + p.capital)
|
||||
});
|
||||
|
||||
// Factor 3: Interconnectedness risk (contagion potential)
|
||||
let avg_interconnectedness = sum_interconnect / self.participants.len() as f64;
|
||||
let interconnect_factor = 1.0 / (1.0 + avg_interconnectedness * 0.1);
|
||||
|
||||
// Factor 4: Capital adequacy
|
||||
let capital_factor = if total_exposure > 0.0 {
|
||||
(total_capital / total_exposure).min(1.0)
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
|
||||
// Factor 5: Coherence trend (declining coherence is worse)
|
||||
let trend_factor = if self.coherence_history.len() >= 5 {
|
||||
// VecDeque allows efficient back access
|
||||
let len = self.coherence_history.len();
|
||||
let newest = self.coherence_history[len - 1];
|
||||
let oldest_of_five = self.coherence_history[len - 5];
|
||||
let trend = newest - oldest_of_five;
|
||||
if trend < 0.0 {
|
||||
1.0 + trend // Penalize declining trend
|
||||
} else {
|
||||
1.0
|
||||
}
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
|
||||
// Geometric mean of factors (more sensitive to low values)
|
||||
let product = leverage_factor * depth_factor * interconnect_factor
|
||||
* capital_factor * trend_factor;
|
||||
product.powf(0.2).clamp(0.0, 1.0)
|
||||
}
|
||||
|
||||
/// Update cached coherence factors when positions or leverage change
|
||||
fn update_cached_factors(&mut self) {
|
||||
// Factor 1: Leverage concentration
|
||||
self.cached_leverage_factor = 1.0 - (self.current_leverage / self.max_system_leverage).min(1.0);
|
||||
|
||||
// Factor 2: Derivative depth (single pass over positions)
|
||||
let max_depth = self.positions.iter()
|
||||
.map(|p| p.derivative_depth)
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
self.cached_depth_factor = 1.0 / (1.0 + max_depth as f64 * 0.2);
|
||||
}
|
||||
|
||||
/// Calculate the energy cost for a transaction (higher for risky transactions)
|
||||
fn transaction_energy_cost(&self, tx: &Transaction) -> f64 {
|
||||
let base_cost = match &tx.transaction_type {
|
||||
TransactionType::Transfer => 1.0,
|
||||
TransactionType::OpenLeverage { leverage } => {
|
||||
// Exponential cost for leverage
|
||||
(1.0 + leverage).powf(2.0)
|
||||
}
|
||||
TransactionType::ClosePosition { .. } => 0.5, // Closing is cheap (reduces risk)
|
||||
TransactionType::CreateDerivative { underlying_position } => {
|
||||
// Cost increases with derivative depth
|
||||
let depth = self.positions.get(*underlying_position)
|
||||
.map(|p| p.derivative_depth)
|
||||
.unwrap_or(0);
|
||||
(2.0_f64).powf(depth as f64 + 1.0)
|
||||
}
|
||||
TransactionType::MarginCall { .. } => 0.1, // Emergency actions are cheap
|
||||
};
|
||||
|
||||
// Multiply by inverse coherence (lower coherence = higher costs)
|
||||
let coherence_multiplier = 1.0 / self.coherence.max(0.1);
|
||||
|
||||
// Circuit breaker multiplier
|
||||
let circuit_multiplier = match self.circuit_breaker {
|
||||
CircuitBreakerState::Open => 1.0,
|
||||
CircuitBreakerState::Cautious => 2.0,
|
||||
CircuitBreakerState::Restricted => 10.0,
|
||||
CircuitBreakerState::Halted => f64::INFINITY,
|
||||
};
|
||||
|
||||
base_cost * coherence_multiplier * circuit_multiplier
|
||||
}
|
||||
|
||||
/// Predict coherence impact of a transaction
|
||||
fn predict_coherence_impact(&self, tx: &Transaction) -> f64 {
|
||||
match &tx.transaction_type {
|
||||
TransactionType::Transfer => 0.0, // Neutral
|
||||
TransactionType::OpenLeverage { leverage } => {
|
||||
-0.01 * leverage // Leverage reduces coherence
|
||||
}
|
||||
TransactionType::ClosePosition { .. } => 0.02, // Closing improves coherence
|
||||
TransactionType::CreateDerivative { .. } => -0.05, // Derivatives hurt coherence
|
||||
TransactionType::MarginCall { .. } => 0.03, // Margin calls improve coherence
|
||||
}
|
||||
}
|
||||
|
||||
/// Process a transaction through the Δ-behavior filter
|
||||
pub fn process_transaction(&mut self, tx: Transaction) -> TransactionResult {
|
||||
// Update circuit breaker state
|
||||
self.update_circuit_breaker();
|
||||
|
||||
// Check if system is halted
|
||||
if self.circuit_breaker == CircuitBreakerState::Halted {
|
||||
return TransactionResult::SystemHalted;
|
||||
}
|
||||
|
||||
// Calculate energy cost
|
||||
let energy_cost = self.transaction_energy_cost(&tx);
|
||||
|
||||
// Predict coherence impact
|
||||
let predicted_impact = self.predict_coherence_impact(&tx);
|
||||
let predicted_coherence = self.coherence + predicted_impact;
|
||||
|
||||
// CORE Δ-BEHAVIOR: Reject if would cross lockdown threshold
|
||||
if predicted_coherence < self.lockdown_threshold {
|
||||
return TransactionResult::Rejected {
|
||||
reason: format!(
|
||||
"Transaction would reduce coherence to {:.3} (threshold: {:.3})",
|
||||
predicted_coherence, self.lockdown_threshold
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
// In restricted mode, only allow risk-reducing transactions
|
||||
if self.circuit_breaker == CircuitBreakerState::Restricted {
|
||||
match &tx.transaction_type {
|
||||
TransactionType::ClosePosition { .. } | TransactionType::MarginCall { .. } => {}
|
||||
_ => {
|
||||
return TransactionResult::Queued {
|
||||
reason: "System in restricted mode - only risk-reducing transactions allowed".to_string(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the transaction
|
||||
self.execute_transaction(&tx);
|
||||
|
||||
// Update coherence
|
||||
self.coherence = self.calculate_coherence();
|
||||
self.coherence_history.push_back(self.coherence);
|
||||
|
||||
// Keep history bounded - O(1) with VecDeque instead of O(n) with Vec
|
||||
if self.coherence_history.len() > 100 {
|
||||
self.coherence_history.pop_front();
|
||||
}
|
||||
|
||||
TransactionResult::Executed {
|
||||
coherence_impact: predicted_impact,
|
||||
fee_multiplier: energy_cost,
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_transaction(&mut self, tx: &Transaction) {
|
||||
match &tx.transaction_type {
|
||||
TransactionType::Transfer => {
|
||||
// Simple transfer logic
|
||||
if let Some(from) = self.participants.get_mut(&tx.from) {
|
||||
from.capital -= tx.amount;
|
||||
}
|
||||
if let Some(to) = self.participants.get_mut(&tx.to) {
|
||||
to.capital += tx.amount;
|
||||
}
|
||||
}
|
||||
TransactionType::OpenLeverage { leverage } => {
|
||||
// Create leveraged position
|
||||
self.positions.push(Position {
|
||||
holder: tx.from.clone(),
|
||||
counterparty: tx.to.clone(),
|
||||
notional: tx.amount * leverage,
|
||||
leverage: *leverage,
|
||||
derivative_depth: 0,
|
||||
});
|
||||
|
||||
// Update metrics
|
||||
self.current_leverage = (self.current_leverage + leverage) / 2.0;
|
||||
|
||||
// Update participant exposure
|
||||
if let Some(holder) = self.participants.get_mut(&tx.from) {
|
||||
holder.exposure += tx.amount * leverage;
|
||||
holder.interconnectedness += 1.0;
|
||||
}
|
||||
if let Some(counterparty) = self.participants.get_mut(&tx.to) {
|
||||
counterparty.interconnectedness += 1.0;
|
||||
}
|
||||
|
||||
// Update cached factors since leverage/positions changed
|
||||
self.update_cached_factors();
|
||||
}
|
||||
TransactionType::ClosePosition { position_id } => {
|
||||
if *position_id < self.positions.len() {
|
||||
let pos = self.positions.remove(*position_id);
|
||||
|
||||
// Reduce leverage
|
||||
self.current_leverage = (self.current_leverage - pos.leverage * 0.1).max(1.0);
|
||||
|
||||
// Update participant exposure
|
||||
if let Some(holder) = self.participants.get_mut(&pos.holder) {
|
||||
holder.exposure = (holder.exposure - pos.notional).max(0.0);
|
||||
}
|
||||
|
||||
// Update cached factors since leverage/positions changed
|
||||
self.update_cached_factors();
|
||||
}
|
||||
}
|
||||
TransactionType::CreateDerivative { underlying_position } => {
|
||||
if let Some(underlying) = self.positions.get(*underlying_position) {
|
||||
self.positions.push(Position {
|
||||
holder: tx.from.clone(),
|
||||
counterparty: tx.to.clone(),
|
||||
notional: underlying.notional * 0.5,
|
||||
leverage: underlying.leverage * 1.5,
|
||||
derivative_depth: underlying.derivative_depth + 1,
|
||||
});
|
||||
|
||||
// Update cached factors since positions changed (derivative depth may increase)
|
||||
self.update_cached_factors();
|
||||
}
|
||||
}
|
||||
TransactionType::MarginCall { participant } => {
|
||||
// Force close risky positions for participant using retain() - O(n) instead of O(n^2)
|
||||
let initial_len = self.positions.len();
|
||||
self.positions.retain(|p| !(&p.holder == participant && p.leverage > 5.0));
|
||||
|
||||
// Update cached factors if positions were removed
|
||||
if self.positions.len() != initial_len {
|
||||
self.update_cached_factors();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_circuit_breaker(&mut self) {
|
||||
self.circuit_breaker = match self.coherence {
|
||||
c if c >= self.warning_threshold => CircuitBreakerState::Open,
|
||||
c if c >= self.critical_threshold => CircuitBreakerState::Cautious,
|
||||
c if c >= self.lockdown_threshold => CircuitBreakerState::Restricted,
|
||||
_ => CircuitBreakerState::Halted,
|
||||
};
|
||||
}
|
||||
|
||||
/// Process pending transactions (called when coherence improves)
|
||||
pub fn process_pending(&mut self) -> Vec<TransactionResult> {
|
||||
if self.circuit_breaker == CircuitBreakerState::Halted
|
||||
|| self.circuit_breaker == CircuitBreakerState::Restricted {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let pending = std::mem::take(&mut self.pending_transactions);
|
||||
pending.into_iter()
|
||||
.map(|tx| self.process_transaction(tx))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn coherence(&self) -> f64 {
|
||||
self.coherence
|
||||
}
|
||||
|
||||
pub fn circuit_breaker_state(&self) -> &CircuitBreakerState {
|
||||
&self.circuit_breaker
|
||||
}
|
||||
|
||||
pub fn status(&self) -> String {
|
||||
format!(
|
||||
"Coherence: {:.3} | Circuit Breaker: {:?} | Leverage: {:.2}x | Positions: {} | Pending: {}",
|
||||
self.coherence,
|
||||
self.circuit_breaker,
|
||||
self.current_leverage,
|
||||
self.positions.len(),
|
||||
self.pending_transactions.len()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_anti_cascade_basic() {
|
||||
let mut system = AntiCascadeFinancialSystem::new();
|
||||
|
||||
system.add_participant("bank_a", 1000.0);
|
||||
system.add_participant("bank_b", 1000.0);
|
||||
system.add_participant("hedge_fund", 500.0);
|
||||
|
||||
// Normal transaction should succeed
|
||||
let tx = Transaction {
|
||||
id: 1,
|
||||
from: "bank_a".to_string(),
|
||||
to: "bank_b".to_string(),
|
||||
amount: 100.0,
|
||||
transaction_type: TransactionType::Transfer,
|
||||
timestamp: 0,
|
||||
};
|
||||
|
||||
let result = system.process_transaction(tx);
|
||||
assert!(matches!(result, TransactionResult::Executed { .. }));
|
||||
println!("After transfer: {}", system.status());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_leverage_throttling() {
|
||||
let mut system = AntiCascadeFinancialSystem::new();
|
||||
|
||||
system.add_participant("bank_a", 1000.0);
|
||||
system.add_participant("bank_b", 1000.0);
|
||||
|
||||
// Open multiple leveraged positions - costs should increase
|
||||
let mut costs = Vec::new();
|
||||
|
||||
for i in 0..5 {
|
||||
let tx = Transaction {
|
||||
id: i,
|
||||
from: "bank_a".to_string(),
|
||||
to: "bank_b".to_string(),
|
||||
amount: 100.0,
|
||||
transaction_type: TransactionType::OpenLeverage { leverage: 5.0 },
|
||||
timestamp: i,
|
||||
};
|
||||
|
||||
if let TransactionResult::Executed { fee_multiplier, .. } = system.process_transaction(tx) {
|
||||
costs.push(fee_multiplier);
|
||||
println!("Position {}: cost multiplier = {:.2}", i, fee_multiplier);
|
||||
}
|
||||
|
||||
println!(" Status: {}", system.status());
|
||||
}
|
||||
|
||||
// Costs should generally increase as coherence drops
|
||||
// (though relationship isn't strictly monotonic due to multiple factors)
|
||||
println!("Cost progression: {:?}", costs);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_derivative_depth_limit() {
|
||||
let mut system = AntiCascadeFinancialSystem::new();
|
||||
|
||||
system.add_participant("bank_a", 10000.0);
|
||||
system.add_participant("bank_b", 10000.0);
|
||||
|
||||
// Create base position
|
||||
let tx = Transaction {
|
||||
id: 0,
|
||||
from: "bank_a".to_string(),
|
||||
to: "bank_b".to_string(),
|
||||
amount: 100.0,
|
||||
transaction_type: TransactionType::OpenLeverage { leverage: 2.0 },
|
||||
timestamp: 0,
|
||||
};
|
||||
system.process_transaction(tx);
|
||||
|
||||
// Try to create derivatives of derivatives
|
||||
for i in 0..5 {
|
||||
let tx = Transaction {
|
||||
id: i + 1,
|
||||
from: "bank_a".to_string(),
|
||||
to: "bank_b".to_string(),
|
||||
amount: 50.0,
|
||||
transaction_type: TransactionType::CreateDerivative { underlying_position: i as usize },
|
||||
timestamp: i + 1,
|
||||
};
|
||||
|
||||
let result = system.process_transaction(tx);
|
||||
println!("Derivative layer {}: {:?}", i, result);
|
||||
println!(" Status: {}", system.status());
|
||||
|
||||
// Eventually should be rejected or system should halt
|
||||
if matches!(result, TransactionResult::Rejected { .. } | TransactionResult::SystemHalted) {
|
||||
println!("System prevented excessive derivative depth at layer {}", i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cascade_prevention() {
|
||||
let mut system = AntiCascadeFinancialSystem::new();
|
||||
|
||||
// Create interconnected network
|
||||
for i in 0..10 {
|
||||
system.add_participant(&format!("bank_{}", i), 1000.0);
|
||||
}
|
||||
|
||||
// Try to create a cascade scenario
|
||||
let mut rejected_count = 0;
|
||||
let mut queued_count = 0;
|
||||
let mut halted = false;
|
||||
|
||||
for i in 0..50 {
|
||||
let from = format!("bank_{}", i % 10);
|
||||
let to = format!("bank_{}", (i + 1) % 10);
|
||||
|
||||
let tx = Transaction {
|
||||
id: i,
|
||||
from,
|
||||
to,
|
||||
amount: 200.0,
|
||||
transaction_type: TransactionType::OpenLeverage { leverage: 8.0 },
|
||||
timestamp: i,
|
||||
};
|
||||
|
||||
match system.process_transaction(tx) {
|
||||
TransactionResult::Rejected { reason } => {
|
||||
rejected_count += 1;
|
||||
println!("Transaction {} rejected: {}", i, reason);
|
||||
}
|
||||
TransactionResult::SystemHalted => {
|
||||
halted = true;
|
||||
println!("System halted at transaction {}", i);
|
||||
break;
|
||||
}
|
||||
TransactionResult::Queued { reason } => {
|
||||
queued_count += 1;
|
||||
println!("Transaction {} queued: {}", i, reason);
|
||||
}
|
||||
TransactionResult::Executed { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
println!("\n=== Final Status ===");
|
||||
println!("{}", system.status());
|
||||
println!("Rejected: {}, Queued: {}, Halted: {}", rejected_count, queued_count, halted);
|
||||
|
||||
// System should have prevented the cascade (via rejection, queueing, or halt)
|
||||
assert!(rejected_count > 0 || queued_count > 0 || halted, "System should prevent cascade");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_margin_call_improves_coherence() {
|
||||
let mut system = AntiCascadeFinancialSystem::new();
|
||||
|
||||
system.add_participant("risky_fund", 500.0);
|
||||
system.add_participant("counterparty", 5000.0);
|
||||
|
||||
// Open risky positions
|
||||
for i in 0..3 {
|
||||
let tx = Transaction {
|
||||
id: i,
|
||||
from: "risky_fund".to_string(),
|
||||
to: "counterparty".to_string(),
|
||||
amount: 100.0,
|
||||
transaction_type: TransactionType::OpenLeverage { leverage: 7.0 },
|
||||
timestamp: i,
|
||||
};
|
||||
system.process_transaction(tx);
|
||||
}
|
||||
|
||||
let coherence_before = system.coherence();
|
||||
println!("Before margin call: {}", system.status());
|
||||
|
||||
// Issue margin call
|
||||
let margin_tx = Transaction {
|
||||
id: 100,
|
||||
from: "system".to_string(),
|
||||
to: "risky_fund".to_string(),
|
||||
amount: 0.0,
|
||||
transaction_type: TransactionType::MarginCall { participant: "risky_fund".to_string() },
|
||||
timestamp: 100,
|
||||
};
|
||||
|
||||
system.process_transaction(margin_tx);
|
||||
let coherence_after = system.coherence();
|
||||
println!("After margin call: {}", system.status());
|
||||
|
||||
// Coherence should improve after margin call
|
||||
assert!(
|
||||
coherence_after >= coherence_before,
|
||||
"Margin call should improve or maintain coherence"
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user