# Deterministic Deal YAML Reference The deterministic simulator consumes a focused YAML file that maps directly to `DeterministicDealConfig`. The loader (`load_deterministic_deal_config`) lives in `simulator.io.loader` and reuses the same deal schema and helpers as the stochastic scenario loader. ## Top-Level Keys | Key | Type | Notes | | --- | --- | --- | | `version` | string / number (optional) | Free-form configuration or schema revision. | | `metadata` | object (optional) | Opaque provenance carried through untouched. | | `deal` | object (required) | Single-deal definition; identical to the scenario schema’s `deal`. | | `discounting` | object (optional) | Discount-rate overrides for deterministic valuation. | > **Schema validation** – `load_deterministic_deal_config` validates inputs with > `simulator/io/deterministic_schema.json`, which internally references the > scenario schema for the `deal` definition. IDE integrations can point at the > JSON Schema to lint deterministic configs as they do full scenarios. ## Deal Block The `deal` object accepts the same fields described in [`Scenario YAML Reference`](./scenario_yaml.md). Only a subset is consumed by `DeterministicDealConfig`: | Field | Required | Purpose | | ----- | -------- | ------- | | `id` | yes | Used for logging and error messages. | | `start_date` | yes | Calendar anchor for amortisation schedules and dated overrides. | | `frequency` | no (defaults to `M`) | Payment cadence (`M`, `Q`, or `A`). | | `parameters` | yes | Provides the stochastic specs so we can build matching operating-income and residual models. Scalars are accepted for `principal`, `rate`, and `term_months`; they are auto-wrapped into constant distributions. | | `collateral` | no | Translated into collateral upfront ratio, contribution policy, and yield spec. | | `liquidation` | no | `schedule` entries become a liquidation value series. | | `downpayment_percent` | no | Borrower equity fraction (e.g. `0.2` for 80% LTV). | | `revenue_offsets.fees` | no | Generates a `revenue_fee_schedule`. | | `revenue_offsets.origination_fee_pct` | no | Upfront fee as a fraction of principal. | | `revenue_offsets.servicing_fee_pct` | no | Annual servicing fee applied to the outstanding balance. | | `revenue_offsets.aum_fee_pct` | no | Annual fee applied to collateral balances. | | Legacy `*_percent` / `*_apr` keys | no | Still accepted for backwards compatibility but will be removed in a future release. | | `operating_income` | no | Converted into an `OperatingIncomeModel` (constant, probabilistic, or driver-based). | | `residual_model` | no | Reuses the depreciation schema to supply a `DepreciationModel`. | Other scenario-only fields (`insurance_policy`, non-fee revenue offsets, etc.) are ignored for deterministic runs. ### Collateral ```yaml collateral: upfront_ratio: 0.05 contribution: fixed: 150.0 percent_of_payment: 0.08 yield: mode: fixed rate: 0.02 ``` ### Liquidation Schedule ```yaml liquidation: schedule: - { month: 6, amount: 12500.0 } - { month: 12, amount: 8000.0 } ``` ### Fees ```yaml revenue_offsets: origination_fee_pct: 0.025 servicing_fee_pct: 0.012 aum_fee_pct: 0.01 fees: - { month: 3, amount: 250.0 } - { month: 9, amount: 250.0 } ``` ### Down Payment / LTV ```yaml downpayment_percent: 0.2 # 80% initial loan-to-value ``` ### Operating Income All scenario modes are supported: - `constant`: `{ model: constant, value: 1200.0 }` - `probabilistic`: requires a `spec` block and optional `deterministic_override` - `driver`: drivers keep the same structure (baseline curve, uncertainty, initial value) ### Residual Model Straight-line curves with optional macro/idiosyncratic multipliers and obsolescence shocks follow the existing scenario schema. They are converted into `DepreciationModel` instances, enabling deterministic simulations to request residual samples when you provide `residual_macro` / `residual_idio` overrides. Example with staged obsolescence shocks: ```yaml residual_model: curve: type: straight_line macro_multiplier: value: 1.0 obsolescence_shocks: - note: Mid-life retrofit probability: 0.8 time_fraction: spec: mode: params family: beta params: { a: 6.0, b: 4.0 } drop_fraction: spec: mode: params family: beta params: { a: 2.0, b: 2.0, loc: 0.25, scale: 0.20 } - note: Late-life displacement probability: 0.99 time_fraction: spec: mode: params family: beta params: { a: 8.0, b: 1.8 } drop_fraction: spec: mode: params family: beta params: { a: 2.5, b: 2.0, loc: 0.50, scale: 0.20 } ``` See `examples/deterministic_single_case_with_shocks.yaml` for the full dual-shock configuration, and `examples/deterministic_single_case.yaml` for a simpler single-shock baseline. ## Discounting Block The optional `discounting` block mirrors the scenario `simulation` fields that influence deterministic valuation: | Field | Type | Notes | | ----- | ---- | ----- | | `discount_rate` | number | Baseline discount rate (defaults to `0.0`). | | `scenario_discount_rule` | object | Same piecewise rules as the scenario schema; transformed into a callable hook. | Example: ```yaml discounting: discount_rate: 0.055 scenario_discount_rule: type: piecewise_rate rules: - max_rate: 0.08 discount_rate: 0.05 - discount_rate: 0.06 ``` If omitted, the loader falls back to the defaults on `DeterministicDealConfig`. ## End-to-End Example See `examples/deterministic_single_case.yaml` (baseline) or `examples/deterministic_single_case_with_shocks.yaml` (dual-shock variant) for complete configurations that pass schema validation and feed directly into `load_deterministic_deal_config`: ```python from pathlib import Path from simulator.engine import DeterministicDealSimulator from simulator.io.loader import load_deterministic_deal_config config = load_deterministic_deal_config(Path("examples/deterministic_single_case.yaml")) simulator = DeterministicDealSimulator(config) result = simulator.simulate(principal=300_000.0, rate=0.12, term_months=48) ``` The helper reuses the same collateral, operating-income, and residual wiring as the Monte Carlo path, ensuring deterministic and stochastic runs stay behaviourally aligned.