1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//! `QuantSupport` is a Rust library for financial calculations and analysis.
//!
//! This library provides tools for computing prices, sensitivities and other
//! metrics of financial products.
//!
//! # Quick-start example
//!
//! The snippet below prices a 5-year receive-fixed / pay-floating USD IRS,
//! retrieves its NPV, cashflow schedule and curve sensitivities.
//! A complete, runnable version lives in `examples/valuation/`.
//!
//! ## 1 — Imports
//!
//! Everything needed is re-exported through the [`prelude`] module.
//!
//! ```rust
//! use std::{cell::RefCell, rc::Rc};
//! use quantsupport::prelude::*;
//! ```
//!
//! ## 2 — Build the swap trade
//!
//! Use [`MakeSwap`](crate::instruments::rates::makeswap::MakeSwap) to
//! configure the instrument, then wrap it in a
//! [`SwapTrade`](crate::instruments::rates::swap::SwapTrade) that carries
//! trade-level metadata (trade date, notional, side).
//!
//! ```rust
//! let start_date = Date::new(2024, 1, 15);
//! let maturity_date = Date::new(2029, 1, 15);
//! let notional = 10_000_000.0;
//! let fixed_rate = 0.030; // 3.0%
//!
//! // Day-count / compounding convention for the fixed leg coupon rate.
//! let rate_definition = RateDefinition::new(
//! DayCounter::Actual360,
//! Compounding::Simple,
//! Frequency::Semiannual,
//! );
//!
//! let swap = MakeSwap::default()
//! .with_identifier("USD_IRS_5Y".to_string())
//! .with_start_date(start_date)
//! .with_maturity_date(maturity_date)
//! .with_fixed_rate(fixed_rate)
//! .with_notional(notional)
//! .with_rate_definition(rate_definition)
//! .with_currency(Currency::USD)
//! .with_market_index(MarketIndex::SOFR)
//! .with_side(Side::LongRecieve) // receive fixed, pay floating
//! .with_fixed_leg_frequency(Frequency::Semiannual)
//! .with_floating_leg_frequency(Frequency::Semiannual)
//! .build()
//! .expect("Failed to build swap");
//!
//! let trade = SwapTrade::new(swap, start_date, notional, Side::LongRecieve);
//! ```
//!
//! ## 3 — Set up the pricing context
//!
//! A [`ContextManager`](crate::core::contextmanager::ContextManager) holds
//! market data (discount curves, quote / fixing stores) that pricers consult
//! during evaluation. Here we create a flat SOFR discount curve at 3.0%.
//!
//! ```rust
//! let evaluation_date = Date::new(2024, 1, 15);
//! let discount_rate = 0.03; // 3.0% flat curve
//!
//! // Curve rate convention: continuous compounding, ACT/360.
//! let curve_definition = RateDefinition::new(
//! DayCounter::Actual360,
//! Compounding::Continuous,
//! Frequency::Annual,
//! );
//!
//! // Build the flat-forward term structure.
//! let discount_curve = FlatForwardTermStructure::new(
//! evaluation_date,
//! ADReal::from(discount_rate),
//! curve_definition,
//! )
//! .with_pillar_label("SOFR_flat".to_string());
//!
//! // Register the curve as the SOFR discount curve.
//! let mut constructed_elements = ConstructedElementStore::default();
//! constructed_elements.discount_curves_mut().insert(
//! MarketIndex::SOFR,
//! DiscountCurveElement::new(
//! MarketIndex::SOFR,
//! Currency::USD,
//! Rc::new(RefCell::new(discount_curve)),
//! ),
//! );
//!
//! // Empty stores — no live quotes or historical fixings in this example.
//! let quote_store = QuoteStore::new(evaluation_date);
//! let fixing_store = FixingStore::default();
//!
//! let context = ContextManager::new(quote_store, fixing_store)
//! .with_base_currency(Currency::USD)
//! .with_constructed_elements(constructed_elements);
//! ```
//!
//! ## 4 — Price the swap and read results
//!
//! Create a [`CashflowDiscountPricer`](crate::pricers::cashflows::discountingcashflowpricer::CashflowDiscountPricer),
//! choose which outputs you need via [`Request`](crate::core::request::Request),
//! and call `evaluate`.
//!
//! ```rust
//! let pricer = CashflowDiscountPricer::<Swap, SwapTrade>::new();
//! let requests = vec![Request::Value, Request::Cashflows, Request::Sensitivities];
//! let results = pricer.evaluate(&trade, &requests, &context)?;
//!
//! // --- NPV ---
//! if let Some(price) = results.price() {
//! println!("Swap NPV = {price:.2}");
//! }
//!
//! // --- Sensitivities (dV/dQuote per curve pillar) ---
//! if let Some(sensitivities) = results.sensitivities() {
//! println!("\nSensitivities:");
//! for (key, exposure) in sensitivities.instrument_keys()
//! .iter()
//! .zip(sensitivities.exposure().iter())
//! {
//! println!(" {key}: {exposure:.4}");
//! }
//! }
//!
//! // --- Cashflow schedule ---
//! if let Some(cashflows) = results.cashflows() {
//! let dates = cashflows.payment_dates();
//! let types = cashflows.cashflow_types();
//! let amounts = cashflows.amounts();
//! let currencies = cashflows.currencies();
//!
//! println!("\nCashflows ({} rows):", dates.len());
//! for i in 0..dates.len() {
//! println!(
//! " {} | {:<20} | {:>14.2} {}",
//! dates[i], types[i], amounts[i], currencies[i]
//! );
//! }
//! }
//! ```