1use crate::types::{
7 CreditExposure, CreditFactors, CreditRiskResult, Portfolio, PortfolioRiskResult, Sensitivity,
8 StressScenario, StressTestResult, VaRParams, VaRResult,
9};
10use rustkernel_derive::KernelMessage;
11use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Clone, Serialize, Deserialize, KernelMessage)]
21#[message(type_id = 3000, domain = "RiskAnalytics")]
22pub struct CreditRiskScoringInput {
23 pub factors: CreditFactors,
25 pub ead: f64,
27 pub maturity: f64,
29}
30
31impl CreditRiskScoringInput {
32 pub fn new(factors: CreditFactors, ead: f64, maturity: f64) -> Self {
34 Self {
35 factors,
36 ead,
37 maturity,
38 }
39 }
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize, KernelMessage)]
46#[message(type_id = 3001, domain = "RiskAnalytics")]
47pub struct CreditRiskScoringOutput {
48 pub result: CreditRiskResult,
50 pub compute_time_us: u64,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct CreditRiskBatchInput {
57 pub exposures: Vec<CreditExposure>,
59}
60
61impl CreditRiskBatchInput {
62 pub fn new(exposures: Vec<CreditExposure>) -> Self {
64 Self { exposures }
65 }
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct CreditRiskBatchOutput {
71 pub results: Vec<CreditRiskResult>,
73 pub compute_time_us: u64,
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize, KernelMessage)]
85#[message(type_id = 3010, domain = "RiskAnalytics")]
86pub struct MonteCarloVaRInput {
87 pub portfolio: Portfolio,
89 pub params: VaRParams,
91}
92
93impl MonteCarloVaRInput {
94 pub fn new(portfolio: Portfolio, params: VaRParams) -> Self {
96 Self { portfolio, params }
97 }
98
99 pub fn with_defaults(portfolio: Portfolio) -> Self {
101 Self {
102 portfolio,
103 params: VaRParams::default(),
104 }
105 }
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize, KernelMessage)]
112#[message(type_id = 3011, domain = "RiskAnalytics")]
113pub struct MonteCarloVaROutput {
114 pub result: VaRResult,
116 pub compute_time_us: u64,
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize, KernelMessage)]
128#[message(type_id = 3020, domain = "RiskAnalytics")]
129pub struct PortfolioRiskAggregationInput {
130 pub portfolio: Portfolio,
132 pub confidence_level: f64,
134 pub holding_period: u32,
136}
137
138impl PortfolioRiskAggregationInput {
139 pub fn new(portfolio: Portfolio, confidence_level: f64, holding_period: u32) -> Self {
141 Self {
142 portfolio,
143 confidence_level,
144 holding_period,
145 }
146 }
147
148 pub fn standard(portfolio: Portfolio) -> Self {
150 Self {
151 portfolio,
152 confidence_level: 0.99,
153 holding_period: 10,
154 }
155 }
156}
157
158#[derive(Debug, Clone, Serialize, Deserialize, KernelMessage)]
162#[message(type_id = 3021, domain = "RiskAnalytics")]
163pub struct PortfolioRiskAggregationOutput {
164 pub result: PortfolioRiskResult,
166 pub compute_time_us: u64,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct StressTestingInput {
177 pub portfolio: Portfolio,
179 pub scenario: StressScenario,
181 pub sensitivities: Option<Vec<Sensitivity>>,
183}
184
185impl StressTestingInput {
186 pub fn new(portfolio: Portfolio, scenario: StressScenario) -> Self {
188 Self {
189 portfolio,
190 scenario,
191 sensitivities: None,
192 }
193 }
194
195 pub fn with_sensitivities(
197 portfolio: Portfolio,
198 scenario: StressScenario,
199 sensitivities: Vec<Sensitivity>,
200 ) -> Self {
201 Self {
202 portfolio,
203 scenario,
204 sensitivities: Some(sensitivities),
205 }
206 }
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize)]
211pub struct StressTestingOutput {
212 pub result: StressTestResult,
214 pub compute_time_us: u64,
216}
217
218#[derive(Debug, Clone, Serialize, Deserialize)]
220pub struct StressTestingBatchInput {
221 pub portfolio: Portfolio,
223 pub scenarios: Vec<StressScenario>,
225 pub sensitivities: Option<Vec<Sensitivity>>,
227}
228
229impl StressTestingBatchInput {
230 pub fn new(portfolio: Portfolio, scenarios: Vec<StressScenario>) -> Self {
232 Self {
233 portfolio,
234 scenarios,
235 sensitivities: None,
236 }
237 }
238
239 pub fn with_sensitivities(
241 portfolio: Portfolio,
242 scenarios: Vec<StressScenario>,
243 sensitivities: Vec<Sensitivity>,
244 ) -> Self {
245 Self {
246 portfolio,
247 scenarios,
248 sensitivities: Some(sensitivities),
249 }
250 }
251
252 pub fn standard_scenarios(portfolio: Portfolio) -> Self {
254 use crate::stress::StressTesting;
255 Self {
256 portfolio,
257 scenarios: StressTesting::standard_scenarios(),
258 sensitivities: None,
259 }
260 }
261}
262
263#[derive(Debug, Clone, Serialize, Deserialize)]
265pub struct StressTestingBatchOutput {
266 pub results: Vec<StressTestResult>,
268 pub worst_case: Option<StressTestResult>,
270 pub compute_time_us: u64,
272}
273
274#[cfg(test)]
275mod tests {
276 use super::*;
277
278 fn create_test_portfolio() -> Portfolio {
279 Portfolio::new(
280 vec![1, 2],
281 vec![100_000.0, 50_000.0],
282 vec![0.08, 0.10],
283 vec![0.15, 0.20],
284 vec![1.0, 0.5, 0.5, 1.0],
285 )
286 }
287
288 fn create_test_factors() -> CreditFactors {
289 CreditFactors {
290 obligor_id: 1,
291 debt_to_income: 0.30,
292 loan_to_value: 0.70,
293 credit_utilization: 0.25,
294 payment_history: 85.0,
295 employment_years: 5.0,
296 recent_inquiries: 2,
297 delinquencies: 0,
298 credit_history_years: 8.0,
299 }
300 }
301
302 #[test]
303 fn test_credit_risk_scoring_input() {
304 let factors = create_test_factors();
305 let input = CreditRiskScoringInput::new(factors, 100_000.0, 5.0);
306 assert_eq!(input.ead, 100_000.0);
307 assert_eq!(input.maturity, 5.0);
308 }
309
310 #[test]
311 fn test_monte_carlo_var_input() {
312 let portfolio = create_test_portfolio();
313 let input = MonteCarloVaRInput::with_defaults(portfolio);
314 assert_eq!(input.params.confidence_level, 0.99);
315 }
316
317 #[test]
318 fn test_portfolio_risk_aggregation_input() {
319 let portfolio = create_test_portfolio();
320 let input = PortfolioRiskAggregationInput::standard(portfolio);
321 assert_eq!(input.confidence_level, 0.99);
322 assert_eq!(input.holding_period, 10);
323 }
324
325 #[test]
326 fn test_stress_testing_input() {
327 let portfolio = create_test_portfolio();
328 let scenario = StressScenario::equity_crash(-0.20);
329 let input = StressTestingInput::new(portfolio, scenario);
330 assert!(input.sensitivities.is_none());
331 }
332}