The dal package wraps the C++ public facade with Python objects and
keyword-only settings. See installation
for supported interpreters and wheel platforms; the examples below are Python
specific. The numerical methods themselves are documented with C++ examples
in yield curves, CCY curves,
Monte Carlo, and PDE.
Import the installed package with:
import dal| Workflow | Python entry points |
|---|---|
| Dates/global state | Date_, Year, Month, Day, EvaluationDate_Set, EvaluationDate_Get |
| Script products | Product_New, Product_Describe, Product_Debug, Product_DebugJson, Product_DebugTree |
| Models | BSModelData_New, LocalVolSurfaceData_New, BSLocalVolModelData_New, HybridModelData_New |
| Valuation | MonteCarlo_Value, MonteCarlo_ValueWithSettings, ScriptValuation_Explain, ScriptSimulation_Explain |
| Script settings | ScriptProductSettings_, ScriptValuationSettings_, MonteCarloSettings_, TodayFixingPolicy_ |
| Random generation | PseudoRSG_New, SobolRSG_New, *_Get_Uniform, *_Get_Normal |
| Calendar operations | Holidays_, Is_BizDay, NextBizDay, PrevBizDay, Adjust |
| Curves | DiscountZeroRate_New, convention/instrument builders, CurveCalibrationSpecBuilder_, CalibrateSingleCurve, CalibrateMultiCurveBundle, CalibrateXccyMarket, CalibrateJointXccyMarket |
| XCCY reset data | FixingIdentity_, FxResetConvention_, MarketFixingSnapshot_New, CrossCurrencySwapConfigBuilder_, XccyNotionalMode |
| Rate cashflow pricing | RateTradeDefinition_, typed terms, RatePricingMarket_, PriceRateTrades, RateTradeNodeSensitivities, RateTradeNodeSensitivitiesBatch, AggregateRatePortfolioNodeRisk, quote-risk provenance builders, AggregateRatePortfolioQuoteRisk |
| Convenience calibration | calibrate_curve from dal/api.py |
The basic valuation shape is:
import dal
dal.EvaluationDate_Set(dal.Date_(2022, 9, 25))
product = dal.Product_New(
["STRIKE", dal.Date_(2023, 9, 25)],
["100.0", "call pays MAX(spot() - STRIKE, 0.0)"],
)
model = dal.BSModelData_New(100.0, 0.2, 0.05, 0.02)
result = dal.MonteCarlo_Value(product, model, 2**16, enable_aad=True)Both Python Value entries require an integer or valid __index__ path count
in 1..2147483647, excluding bool and enums; floats such as 1.0 are rejected.
The bindings copy settings and native handles before releasing the GIL for
valuation. EvaluationDate_Get / EvaluationDate_Set also release it before
native synchronization. A setter waits for an in-progress valuation; a getter
can read the stable current date while valuation runs.
For precise-CDF-polished Sobol normal draws, pass both flags explicitly:
rsg = dal.SobolRSG_New(i_path=0, ndim=3, precise=True, polish=True)
normals = dal.SobolRSG_Get_Normal(rsg, 1024)The settings entry points are:
Product_New(events_dates, events, *, settings=None)
MonteCarlo_ValueWithSettings(product, modelData, num_path, *, valuation=None, simulation=None)
Product_Describe(product)
ScriptValuation_Explain(product, modelData, *, valuation=None)
ScriptSimulation_Explain(product, modelData, num_path, *, valuation=None, simulation=None)
settings, valuation, and simulation take ScriptProductSettings_,
ScriptValuationSettings_, and MonteCarloSettings_ respectively, or None
for fresh defaults. Their constructors use keyword-only fields. Product settings
provide default_index and regression_features; valuation settings provide evaluation_date,
today_fixing and fixings; simulation settings provide
method, use_bb, enable_aad, smooth, compiled, lsmc_basis_degree,
lsmc_training_paths, lsmc_validation_paths, lsmc_rqmc_replicates,
lsmc_training_seed, lsmc_pricing_seed, lsmc_policy_risk_mode,
lsmc_policy_bump_relative, lsmc_checkpoint_block_events,
lsmc_training_memory_mb, and normal_precision. The latter accepts exact
Default, Fast, or Precise strings. Default uses fast conversion for all
three generators; use MonteCarloSettings_(method="mrg32", normal_precision="Precise")
to use CDF-polished MRG32 normals. See normal precision
for the numerical tradeoff. Frozen is the default AAD sensitivity mode;
RetrainedBump adds a common-path policy-retraining secant to model-parameter
and script-constant risks. RQMC pricing uses one fitted
policy and reports conditional replicate-mean uncertainty through
ScriptSimulation_Explain.
Checkpoint settings default to None; see the supported domain, MiB budget
and fallback contract under training checkpoints.
For multi-asset EXERCISE, pass a list of at most three state names, such as
ScriptProductSettings_(regression_features=["EQ[A]", "VAR[runningAverage]"]).
EQ[...] samples a model equity at each exercise date; VAR[...] reads a
scalar script variable at that event. The list is stored with the product and
is available in Product_Describe. With no list, default_index remains the
single regression state for a multi-asset exercise product.
Model-supported IR discount-factor, Libor, and swap names can also be selected.
Rate-only GSR exercise requires an explicit list, such as
ScriptProductSettings_(regression_features=["IR[USD,SWAP,5Y]"]); see
GSR Bermudan products.
today_fixing accepts TodayFixingPolicy_.MODEL / .REQUIREHISTORICAL or exact,
case-sensitive Model / RequireHistorical strings. The three settings fields default_index,
method, and today_fixing reject foreign enums, including string-derived enum
members, with TypeError on construction or assignment. Ordinary string
subclasses, DAL String_, and the native today-policy members remain supported.
Event text accepts string-derived enum members. Dates require a valid DAL
Date_; snapshot keys require DateTime_(date, 0) for exact midnight.
fixings=None captures current global history; an explicit empty snapshot
never falls back to it. Global capture is sequential, not atomic across
sequences, and requires callers to exclude concurrent fixing writes.
The FIX source rules
and script model index
apply unchanged: past history, today's selected policy, future model, and no
fixing after its event. The complete
Python example supplies a legal
BS model and checks PV=260 / d_SCALE=80 for historical SCALE state plus a
retained future fixing. See the
Python settings reference
for defaults, strict field types, setters, detached property copies and
copy/deepcopy semantics. Snapshot handles share immutable data; workers use
native copies without Python callbacks or mutable dictionaries.
High-level Describe returns a dal.script-product/2 dictionary without market
I/O, global-date access or valuation phase. High-level Explain returns a
dal.script-valuation/1 dictionary from one independent default exact/tree
price preparation. It may read history and initialize a model, but generates
no paths or workers and accepts no simulation settings. It neither describes
a preceding compiled/AAD call nor caches the next Value. High-level
ScriptSimulation_Explain runs the full double valuation with the given
num_path on exercise products (plain products skip the run, since their
exercise events array is empty either way) and returns the
dal.script-simulation/1 exercise diagnostics dictionary. Low-level dal._dal
and dal.dal diagnostics return raw JSON strings with the same schemas.
Diagnostics are not loadable archives; Python has no public script-product
serializer. Value results contain only already-normalized PV and optional
d_ parameter risks, with no fixing-risk or diagnostic keys.
Existing three-to-eight-argument MonteCarlo_Value retains its original
keywords/defaults and valid flag/float conversions. It cannot take the new
settings, and the settings entry cannot take flat simulation options. The
high-level product date keyword is events_dates; low-level Product_New
uses dates and requires Cell_ elements. High-level conversion leaves existing
cells intact. Unknown keywords, wrong types or extra positional settings raise
TypeError; unknown attributes raise AttributeError; invalid values and native
failures raise RuntimeError with field/constraint and source context.
Product_DebugJson remains a JSON string with schema /1 and rejects FIX or
nonempty defaults with DebugSchemaUnsupported.
MonteCarlo_ValueWithRisk(product, modelData, num_path, *, request=None, valuation=None, simulation=None) returns a read-only RiskResult_.
The omitted simulation enables native AAD; an explicit
MonteCarloSettings_(enable_aad=False) requests price only.
request = dal.RiskRequest_(
inputs=["constant:0", "model:1"], report_factors=[0.5, 0.01],
)
risk = dal.MonteCarlo_ValueWithRisk(product, model, 2**16, request=request)
raw = risk.jacobian.to_rows() # [[strike derivative, volatility derivative]]
reported = risk.reported_jacobian.to_rows()
method = risk.provenance.methodRequest fields are keyword-only inputs, outputs, report_factors and
numeric_payload_budget_bytes. IDs/factors accept lists or tuples, with None
meaning omission. Empty native inputs preserve the (1, 0) matrix and smoothed
price; price-only cannot select nonempty inputs. Budget is a nonnegative integer
excluding bool. It covers returned numeric values/Jacobian, excluding metadata,
worker/tape storage and getter copies.
output_ids, values, input_axis, complete_input_axis, jacobian,
reported_jacobian, provenance and legacy_values expose detached data.
Changing a returned matrix or copied simulation settings cannot change the result.
Coordinate IDs identify model/script ordinals within the retained snapshot;
physical units can be unknown. The raw legacy view rejects display collisions.
The AAD methodology
describes the retained product/model/history settings and mixed LSM policy risk.
Product_Get_RiskOutputs(product) returns detached read-only scalar coordinates
with id, label and slot. The payoff receiver has ID payoff; other scalar
slots use output:<ordinal>. Labels are display text. Vector storage is excluded.
request = dal.WeightedRiskRequest_(
outputs=["output:0", "payoff"], weights=[2.0, -0.5],
inputs=["model:0", "model:1"], report_factors=[1.0, 0.01],
)
risk = dal.MonteCarlo_ValueWithWeightedRisk(
product, model, 2**16, request=request,
)
objective = risk.weighted_value
components = risk.component_means
gradient = risk.jacobian.to_rows() # one row in requested input orderWeightedRiskRequest_ fields are keyword-only: inputs, outputs, weights,
report_factors and numeric_payload_budget_bytes. None selects the default
payoff, unit weights and native input set. ID/numeric sequences accept lists or
tuples; numeric entries require int/float and exclude bool, enum and text.
Native preflight rejects nonfinite/mismatched weights, empty/repeated/unknown
outputs, unsupported exercise and fully expired products before history/workers.
Signed/zero weights are valid; every selected component must remain finite.
The valuation has the scalar entry's keyword-only request, valuation and
simulation settings and defaults to native AAD. Explicit price-only execution
uses MonteCarloSettings_(enable_aad=False). Empty native inputs preserve AAD
smoothing and a (1, 0) matrix. Requests/settings are copied before the GIL is
released for native work.
weighted_value, component_means, weights, output_axis, jacobian,
reported_jacobian, input_axis, complete_input_axis and provenance are
read-only owning result properties. Container/matrix getters return independent
copies, and copy/deepcopy retain the passive result after caller objects die.
The numeric budget covers 8 * (1 + inputs + 2 * outputs) bytes: objective,
raw gradient, component means and weights. Metadata, worker/tape storage,
source snapshots and detached getter copies are excluded. See the
weighted AAD methodology.
MonteCarlo_ValueWithJacobianRisk returns owning output means and a complete
selected-output by selected-input matrix. Choices after product, model and
path count are keyword-only:
request = dal.JacobianRiskRequest_(
outputs=["output:0", "payoff"], inputs=["model:0", "model:1"],
max_block_width=2, scratch_capacity_budget_bytes=8 * 1024 * 1024,
)
risk = dal.MonteCarlo_ValueWithJacobianRisk(
product, model, 1024, request=request, valuation=valuation,
)
means = risk.values
raw = risk.jacobian.to_numpy() # shape (2, 2)
reported = risk.reported_jacobian.to_numpy()
work = risk.execution.executed_pathsRequest fields are read-only: inputs, outputs, report_factors,
max_block_width, numeric_payload_budget_bytes,
recording_capacity_budget_bytes and scratch_capacity_budget_bytes.
Width defaults to one and must fit the native channel limit. Budgets accept
nonnegative size_t integers or None; booleans, enums, fractions and strings
are rejected. ID/factor containers accept lists or tuples. Omitted output
selection means payoff; an empty output list is invalid.
Result properties are values, jacobian, reported_jacobian, selected and
complete output_axis/input_axis, provenance and execution. Getters return
detached containers/matrices. Single rows remain two-dimensional and empty
inputs retain (m, 0). Execution properties are actual_widths,
replay_attempts, executed_paths, peak_recording_bytes and
peak_scratch_bytes. Native work releases the GIL after copying typed request
and settings inputs. Each native output block replays all requested paths;
explicit passive mode performs one replay with no risk columns. The
AAD methodology defines
capacity scopes, exclusions and failure behavior.
ScriptPortfolio_New(trade_ids, products, modelData) seals equal-length nonempty
lists or tuples. Repeating the same original model object establishes one owner;
distinct model objects remain separate even if their values agree. Matching
original sampling contracts determine which trades share scenarios. Trade IDs
must be unique, and all product/model elements must be typed handles.
import dal
date = dal.Date_(2027, 1, 1)
trade_a = dal.Product_New(["X", date], ["5", "pay PAYS 2 * SPOT() + X"])
trade_b = dal.Product_New(["X", date], ["7", "pay PAYS 3 * SPOT() + X"])
model = dal.BSModelData_New(1, 0, 0, 0)
portfolio = dal.ScriptPortfolio_New(["A", "B"], [trade_a, trade_b], [model, model])
valuation = dal.ScriptValuationSettings_(evaluation_date=dal.Date_(2026, 1, 1))
inputs = ["model:0:parameter:0", "trade:0:constant:0", "trade:1:constant:0"]
weighted = dal.PortfolioMonteCarlo_ValueWithWeightedRisk(
portfolio, 17, valuation=valuation,
request=dal.PortfolioWeightedRiskRequest_(inputs=inputs, weights=[2, -1]),
)
assert weighted.component_means == [7, 10]
assert weighted.weighted_value == 4
assert weighted.jacobian.to_rows() == [[1, 2, -1]]
rows = dal.PortfolioMonteCarlo_ValueWithJacobianRisk(
portfolio, 17, valuation=valuation,
request=dal.PortfolioJacobianRiskRequest_(
inputs=inputs, outputs=["trade:1:payoff", "trade:0:payoff"], max_block_width=2,
),
)
assert rows.values == [10, 7]
assert rows.jacobian.to_rows() == [[3, 0, 1], [2, 1, 0]]
assert rows.execution.groups[0].generated_scenarios == 17Both value functions take portfolio and num_path first; request, valuation
and simulation are keyword-only. Their default simulation enables native AAD.
An explicit MonteCarloSettings_(enable_aad=False) retains sharp price-only rows
and zero risk columns; recording limits have no effect in that mode. Native
explicit empty inputs=[] retains native fuzzy prices and zero-column shapes.
Omitted inputs select all native columns; omitted outputs select each trade's
payoff in original order. Global IDs and reporting factors follow the
C++ portfolio rules.
The immutable request types share inputs, outputs, report_factors and the
three optional byte budgets: numeric_payload_budget_bytes,
recording_capacity_budget_bytes, scratch_capacity_budget_bytes. Weighted
requests add weights; Jacobian requests add positive bounded max_block_width,
default one. Numeric payloads are respectively 8*(1+n+2*m) and 8*m*(1+n);
runtime capacities include all admitted workers and native replacement headroom.
Capacity narrowing preserves requested maximum and estimator.
Owning results expose detached raw/reported matrices, selected/complete axes,
trade provenance and original group contracts. provenance.trade_ids,
provenance.model_owners and provenance.trades retain the sealed source mapping.
execution.groups reports actual widths, replay attempts and
scenario/evaluator/reversal counts; execution also reports actual peak
recording/scratch bytes. Sampling definitions, settings, lists and matrices are
copied by getters. Results survive destruction of portfolios or source handles;
getters perform no valuation or history reads. Path counts exclude bool, enums,
fractions and values beyond INT_MAX. Malformed requests fail with field and
trade/group/coordinate context, leaving prior completed results intact.
DupireCalibration_New(base, inputs, *, name="") creates a frozen calibration
from an existing BS model, MertonIVS_, or a Python subclass of IVS_.
Configuration is keyword-only; quote rows are strikes and columns are maturities.
inputs = dal.DupireRiskInputs_(
quote_strikes=[75.0, 105.0, 135.0], quote_maturities=[0.4, 1.2],
quote_spreads=dal.DoubleMatrix_(3, 2),
inclusion_spots=[60.0, 100.0, 140.0], max_spot_spacing=10.0,
inclusion_times=[0.5, 1.0], max_time_spacing=0.5,
)
base = dal.BSModelData_New(100.0, 0.2, 0.05, 0.02)
calibration = dal.DupireCalibration_New(base, inputs, name="local_vol")
seeds = dal.DupireParameterAdjoints_(
calibration, dal.DoubleMatrix_(len(calibration.spots), len(calibration.times), 1.0),
)
quotes = dal.DupireQuoteRisk_New(calibration, seeds)
raw = quotes.total_adjoints.to_rows()This example differentiates the sum of calibrated surface nodes. For trade risk,
create DupireModelData_New(calibration, index, currency, factor, *, name="", max_step=1/12) or use calibration.surface in a Hybrid local-vol component, then obtain a
MonteCarlo_ValueWithRisk result with every surface input selected. Then call
DupireScriptQuoteRisk_New(valuation, calibration, component, *, direct=None).
Its valuation, quote_risk, component and method retain the source and
quote results. DupireParameterAdjoints_FromRisk extracts the surface seed
separately for compatible portfolio accumulation.
The convenience model copies the surface, preserves frozen spot/rate/dividend,
and names its local-vol component equity and deterministic-rate component rate.
DupireDirectQuoteAdjoints_(calibration, matrix) supplies an optional raw PV
quote contribution. Results separate calibration_adjoints, direct_adjoints
and total_adjoints; their unit is decimal-vol. Reporting factors and path
averaging are not applied again. Snapshot getters expose copied inputs,
spots, times, vols and a detached surface, plus spot, rate,
dividend_yield, algorithm and full-content matches(other).
Numeric properties and copy/deepcopy cannot change retained calibration data.
Custom IVS subclasses call super().__init__(spot=..., rate=..., dividend_yield=...) and implement implied_vol(strike, maturity) returning a
finite numeric volatility. MertonIVS_ takes keyword-only spot, vol,
intensity, average_jump, jump_std and retains zero carry. Sampling holds
the GIL; the snapshot retains no Python callback, and native pullbacks release
the GIL. Later changes or destruction of the IVS do not affect prior results.
Numeric configuration excludes bool and enums; invalid domains, missing surface
columns and incompatible identities fail explicitly. See the
discrete derivative and estimator boundaries.
CalibrationRiskPlan_New(calibration, *, request=None) plans an immutable
quote selection over an owning CalibrationPullback_. It accepts frozen Dupire
or any supported curve provenance captured with retain_calibration_record=True.
CalibrationRiskResult_New(plan, parameter_adjoints, *, direct=None) performs
the native pullback using the existing typed parameter/direct seeds.
boundary = dal.CalibrationPullback_New(calibration)
parameters = dal.CalibrationParameterAdjoints_New(
boundary, dal.DoubleMatrix_(boundary.parameter_rows, boundary.parameter_cols, 1.0),
)
request = dal.CalibrationRiskRequest_(
inputs=["quote:3", "quote:0"], report_factors=[0.01, 0.01],
numeric_payload_budget_bytes=144,
)
plan = dal.CalibrationRiskPlan_New(boundary, request=request)
result = dal.CalibrationRiskResult_New(plan, parameters)
raw = result.jacobian.to_rows()
per_vol_point = result.reported_jacobian.to_rows()Request fields are keyword-only and read-only. Lists/tuples are copied; inputs=None
selects every source quote, while inputs=[] retains an empty (1, 0) projection
and still performs the native pullback. Unknown/repeated IDs and nonpositive or
nonfinite factors fail during planning. IDs identify source ordinals; labels
cannot establish source compatibility. Factors apply once to reported copies:
use 0.01 for a decimal-vol point or 1e-4 for a decimal-rate basis point.
The plan exposes calibration, complete_input_axis, input_axis,
selected_ordinals and numeric_payload_bytes. Coordinates retain native
row/column, units and quote metadata: curve value/strike/maturity are None,
and Dupire block fields are None. The budget counts all three complete native
quote matrices even for subset/empty selections. It excludes source/metadata,
input seeds, getter copies and temporary recording storage.
Results expose plan, quote_risk, jacobian, calibration_jacobian,
direct_jacobian and reported_jacobian. All matrices, lists and nested values
are detached copies. The common result retains native method/unit/boundary
metadata without deriving a generic PV or currency from external seeds.
Constructors exclude bool/enums and implicit dictionary/container coercions.
Plans/results support copy/deepcopy; native planning and pullback release the
GIL after owning all Python inputs. See the
native request contract
for retained payload and source-identity rules.
DupireScriptRiskPlan_New(product, modelData, calibration, component, request)
plans the complete surface inputs needed by the native Dupire pullback over a
flat-rate Hybrid. DupireScriptRiskResult_New(plan) runs the sealed valuation
and quote pullback. No manual node-risk extraction is needed.
request = dal.DupireScriptRiskRequest_(
num_paths=257,
quotes=dal.CalibrationRiskRequest_(
inputs=["quote:3", "quote:0"], report_factors=[0.01, 0.5],
),
valuation=dal.ScriptValuationSettings_(evaluation_date=dal.Date_(2026, 9, 12)),
)
plan = dal.DupireScriptRiskPlan_New(product, hybrid, calibration, "Z_LOCAL", request)
result = dal.DupireScriptRiskResult_New(plan)
price = result.valuation.values[0]
spread_risk = result.quote_risk.reported_jacobian.to_rows()Request fields are keyword-only. num_paths is required and accepts integers in
1..INT_MAX, excluding bool and enums. Optional quotes, valuation and
simulation accept their native bound types or None; omitted simulation
enables AAD. Explicit price-only settings reject during planning.
Use direct_bindings=[dal.DupireQuoteBinding_(constant_ordinal=0, quote_id="quote:3")] for an explicit script constant dependency. The ordinal
identifies the prepared script constant, and its value must equal the selected
source quote. Bindings require a copied list/tuple of typed values. Alternatively,
direct accepts a common CalibrationDirectQuoteAdjoints_ containing raw PV
partials with the local-vol surface fixed. These two forms are mutually exclusive;
the native planner validates source identity and adds direct risk once.
Plans expose component, quote_plan, complete_input_axis,
required_input_axis, direct_bindings, num_paths, valuation_settings,
simulation_settings and numeric_payload_bytes. They seal native product/model
content and capture the evaluation date. Explicit fixing snapshots remain owned;
global history is resolved at execution. Quote subset/empty selection retains all
mandatory surface/direct gradients and the native smoothed estimator.
The common quote request's budget now covers the retained valuation value and
required gradients plus all three complete quote contribution matrices. It
excludes source/metadata, getter copies and temporary worker/tape storage.
Results expose valuation, quote_risk, component, method and
numeric_payload_bytes; quote_risk is a CalibrationRiskResult_. All properties
are read-only and detached. Copy/deepcopy retain owning passive values. Planning
and execution release the GIL after copying typed inputs. See the
native automatic request boundaries.
DupireScriptCurvaturePlan_New plans finite-step differences of complete native
quote gradients, recalibrating the surface at every perturbed quote point.
DupireScriptCurvatureResult_New(plan) executes the sealed plan on common paths.
Use an existing DupireScriptRiskRequest_ to specify paths, valuation, simulation
and any direct script-constant quote bindings:
directions = dal.DoubleMatrix_(1, 6, 0.0)
directions[0, 3] = 1.0
bumps = dal.BumpOverAADRequest_(directions=directions, steps=[0.0002])
request = dal.DupireScriptCurvatureRequest_(risk=risk_request, bumps=bumps)
plan = dal.DupireScriptCurvaturePlan_New(
product, hybrid, calibration, "Z_LOCAL", request,
)
result = dal.DupireScriptCurvatureResult_New(plan)
gamma = result.hessian_products[0, 3]
gradient = result.gradientDirection columns follow the complete raw strike-major decimal-vol spread axis,
available as result.input_axis. Unit rows select Gamma/cross-Gamma; signed rows
select Hessian-vector products. First-order input subsets and report factors
affect result.base.quote_risk only; gradient and hessian_products retain
the complete raw axis. Steps are finite, positive and explicit, one per direction
row. All-zero direction rows reject. A DoubleMatrix_(0, quote_count) with
steps=[] requests the base gradient without curvature rows.
The bump constructor is keyword-only and copies a native DoubleMatrix_ and a
list/tuple of real steps. It excludes bool/enums and implicit matrix conversion.
Optional numeric_payload_budget_bytes and recording_capacity_budget_bytes
accept nonnegative size_t integers or None; zero remains an explicit cap.
The Dupire planner rejects recording-cap requests because a caller-thread tape
cap cannot constrain parallel worker tapes. The numeric cap covers the combined
bump/base result payload described in the
native financial contract.
External first-order direct seeds and exercise policies also reject.
Requests, plans and results support copy/deepcopy. All container, matrix and
nested getters return detached values. Plans expose base_plan, point,
directions, steps and numeric_payload_bytes; results add base, gradient,
input_axis, hessian_products and execution. Execution reports method,
quote_gradient_evaluations (1+2*direction_count), paths_per_evaluation and
numeric_payload_bytes. Planning freezes the evaluation date and fixing snapshot;
native planning/execution release the GIL after owning typed Python inputs.
The method is a finite-step estimator, with the native first-order smoothing and
calibration stencil constraints. This entry does not select the smooth C++
forward-over-reverse prototype.
RateCalibration_New(spec) captures an owning immutable calibration snapshot.
It accepts native single-curve, joint multi-curve, staged XCCY and joint XCCY
specifications, restricted to supported exact square systems. point contains
raw decimal quotes in provenance.axis.quotes order; parameters contains the
solved free coordinates. Staged XCCY exposes basis quotes only; its other curves
remain fixed. RateCalibration_Recalibrate(calibration, quotes) returns a new
snapshot from a copied list/tuple of finite real quotes with the same axis.
Use existing RateTradeDefinition_ values and the shared bump request:
calibration = dal.RateCalibration_New(spec)
directions = dal.DoubleMatrix_(1, len(calibration.point), 0.0)
directions[0, 0] = 1.0
bumps = dal.BumpOverAADRequest_(directions=directions, steps=[0.0002])
settings = dal.RateTradeQuoteCurvatureSettings_(weights=[1.0, -0.5])
result = dal.RateTradeQuoteCurvature([trade_a, trade_b], calibration, bumps, settings=settings)
value = result.curvature.value
gradient = result.curvature.gradient
gamma = result.curvature.hessian_products[0, 0]Trades support the native deposit, FRA, future, IRS, basis-swap, OIS and XCCY
families. Use curve component keys from calibration provenance for free curves;
joint declarations retain distinct keys even when display names repeat. All
trades must have the same actual PV currency, returned as result.currency.
This entry performs no currency conversion. Missing or empty weights mean unit
weights; supplied finite weights must match the trade count. Negative and zero
weights are allowed, and every trade is validated even at zero weight.
RateTradeQuoteCurvatureSettings_(*, weights=None, fixings=None) optionally
retains an immutable MarketFixingSnapshot_ for additional trade history.
It must agree with saved calibration observations. Without an explicit snapshot,
missing required history is captured once from global fixings. Calibration
sources, valuation inputs and historical observations stay fixed during bumps.
The finite-step method BumpOverRecalibratedNativeRateAAD recalibrates and
recomputes the full quote gradient at every point. With M directions, execution
reports 1+2*M calibrations, quote gradients and objective reverse sweeps.
DoubleMatrix_(0, quote_count) and steps=[] request the base gradient only.
Products retain raw quote units and signs; choose explicit positive steps using
convergence checks. These estimates do not enable general native higher order.
The numeric budget covers 8*(1+2*N+2*N*M+M) bytes for N quotes and M directions,
excluding solver/source storage, getter copies and allocator overhead. The
separate recording cap constrains caller-thread recalibration and objective
tapes, including cleanup reserve. Both optional caps preserve zero. Execution
also reports numeric_payload_bytes, peak_tape_bytes and cleanup_reserve_bytes.
Vectors, matrices, nested results and provenance getters are detached; snapshots,
settings and results support copy/deepcopy. Factories release the GIL after
copying typed inputs. See the
native financial contract.
Prepare a closed native Black–Scholes script once, then reuse its frozen contract and historical observations for explicit parameter points:
valuation = dal.ScriptValuationSettings_(evaluation_date=dal.Date_(2026, 1, 2))
product = dal.Product_New(
["SCALE", dal.Date_(2027, 1, 2)],
["2", "pay PAYS SCALE * FIX(EQ[UNDERLYING]) ^ 2"],
)
plan = dal.BlackScholesMonteCarloPlan_New(product, valuation=valuation)
point = [100.0, 0.2, 0.03, 0.01, *plan.script_constants]
settings = dal.SegmentedMonteCarloSettings_(first_path=7, segment_steps=64)
mean = dal.BlackScholesMonteCarlo_Get_Risk(plan, point, 129, settings=settings)
bumps = dal.BumpOverAADRequest_(
directions=dal.DoubleMatrix_([[1.0, 0.0, 0.0, 0.0, 0.0]]), steps=[0.25]
)
risk = dal.BlackScholesMonteCarlo_Get_Curvature(
plan, point, 129, bumps, settings=settings
)
spot_gamma = risk.hessian_products[0, 0]Columns follow plan.parameter_labels: spot, volatility, continuously compounded
rate, dividend yield, then script constants. Points must be lists or tuples of
finite real numbers; no coordinate scaling is applied. The path count follows
the positive integer contract above. Plan creation resolves history; subsequent
evaluations replay the sealed observations and do not read global history again.
valuation, smoothing, contract_dates, contract_events, contract_settings
and observations identify the preparation. An optional smoothing factory
argument selects the compiled native first-order smoothing width. EXERCISE
requires the separate policy estimator and is rejected by this preparation.
Keyword-only settings expose rsg (sobol/mrg32/irn), use_bb, absolute
first_path, optional Sobol-only uint64 scramble_key, normal_precision
(Default/Fast/Precise), positive segment_steps and optional
checkpoint_capacity_budget_bytes / recording_capacity_budget_bytes.
Explicit zero caps remain zero. Fixed 32-path batches preserve native reduction
order. Defaults select Sobol, offset zero, no bridge and 64-step segments.
Mean results expose value, gradient, point, parameter_labels, settings,
execution and the owning plan. Curvature exposes base with the mean and
gradient, plus point, directions, actual steps, products, settings, execution
and plan. Containers/settings are detached copies; copy/deepcopy may safely
share immutable native preparation. Numerical calls release the Python GIL.
The curvature method is BumpOverSegmentedNativeAAD: each row differences
complete native mean gradients on the same absolute paths. Its 1+2M
gradient_evaluations count is distinct from segment reverse sweeps. Empty
directions retain the base gradient and a 0 x N product. Numeric payload uses
the shared bump request's owning-double formula and excludes preparation,
tasks and random buffers. The smaller path/bump recording limit applies;
execution reports that effective limit and per-path tape/checkpoint/cleanup
maxima, excluding aggregate memory and RSS. These are finite-step secants;
nonsmooth payoffs have separate step and sampling errors. See the
native methodology.
Prepare a closed Black–Scholes EXERCISE contract and seal its valuation, historical observations and simulation settings before requesting curvature:
product = dal.Product_New(
["K", dal.Date_(2027, 4, 10), dal.Date_(2027, 10, 10)],
["50", "EXERCISE 2 * K - spot()", "EXERCISE 2 * K - spot()"],
)
simulation = dal.MonteCarloSettings_(
enable_aad=True, compiled=True, smooth=2.0,
lsmc_training_paths=256, lsmc_policy_risk_mode="Frozen",
)
plan = dal.BlackScholesLsmcPlan_New(
product, simulation=simulation,
valuation=dal.ScriptValuationSettings_(evaluation_date=dal.Date_(2026, 10, 10)),
)
point = [100.0, 0.2, 0.05, 0.0, *plan.script_constants]
bumps = dal.BumpOverAADRequest_(
directions=dal.DoubleMatrix_([[1.0, 0.0, 0.0, 0.0, 0.0]]), steps=[0.1],
)
risk = dal.BlackScholesLsmc_Get_Curvature(plan, point, 129, bumps)
spot_gamma = risk.hessian_products[0, 0]
base_policy = risk.base_policyThe point uses raw spot, volatility, rate, dividend yield, then script constants
in plan.parameter_labels order. Planning copies the contract and resolves
history once; evaluation replays those sealed observations with the supplied
constant values. simulation=None uses native-risk defaults with AAD enabled.
An explicitly disabled AAD setting, expired exercise or a contract without live
EXERCISE is rejected. Settings and numeric arguments are copied before GIL
release; no active Python scalar, objective or model callback is accepted.
Frozen fits one base policy and uses that same policy for all outer points;
its method is BumpOverFrozenNativeLsmcAAD. Repeating ordinary Frozen pricing
at bumped points fits different policies and estimates a different quantity.
RetrainedBump fits a policy at every outer point and differences the existing
complete gradient estimator, including its inner policy-only price secant.
It reports BumpOverRetrainedNativeLsmcPolicySecant. The retained
simulation.lsmc_policy_bump_relative controls the inner step independently
from risk.steps; training, validation and pricing streams remain common.
Results own plan, value, gradient, parameter_labels, point,
directions, steps, hessian_products, base_policy, simulation and
execution. Passive LsmcExercisePolicy_ elements retain coefficients, scalar
and multivariate normalization, basis powers/degree, degeneracy, effective rank,
solver/fallback and validation error in live EXERCISE order. Plan getters include
valuation, simulation, original contract dates/events/settings, live event dates,
time line and observation snapshots. Nested containers/settings are detached;
copy/deepcopy may share immutable preparation.
Execution records 1+2M gradient requests, paths per replicate,
training/validation/replicate counts, numeric payload, recording cap and maximum
batch tape/cleanup reserve. Empty directions retain the full base gradient.
Numeric payload excludes policy, preparation and temporary work. Recording caps
apply to individual fuzzy replay batches and can fail after policy training;
resource maxima exclude aggregate process memory. Explicit zero limits remain
zero. These finite-path, finite-step estimators do not imply an analytic,
symmetric Hessian or unbiased optimal-stopping Gamma. See
the estimator contract.
DoubleMatrix_ supports all of the following:
surface = dal.DoubleMatrix_(3, 2, 0.20)
surface[1, 0] = 0.21
surface = dal.DoubleMatrix_([
[0.24, 0.23],
[0.21, 0.20],
[0.22, 0.21],
])Rows must be rectangular numeric sequences. LocalVolSurfaceData_New expects a
spots-by-times matrix, so its shape must be
len(spots) × len(times).
dal.calibrate_curve(...) covers the common single discount-curve path. Use
CurveCalibrationSpecBuilder_ directly for projection-curve inputs, staged
multi-curve calibration, or lower-level solver settings. Python enum names are:
CurveParameterization:PIECEWISE_LINEAR_FWD,PIECEWISE_CONSTANT_FWD,ZERO_RATE,LOG_DISCOUNT;CurveSolveMode:EXACT,APPROXIMATE;CurveJacobianMode:ANALYTIC,BUMPED; andLogDfScheme:LOG_LINEAR,LOG_CUBIC_NATURAL,MIXED.
ZERO_RATE is supported by CalibrateSingleCurve and dal.calibrate_curve. Supply only
strictly-future knots; the anchor is internal and contributes no solver or Jacobian
column. The scalar initialGuess_ is a decimal continuously compounded zero rate.
dal.calibrate_curve(..., base_curve=...) treats the calibrated zero rates as spreads
over that base.
Direct construction uses:
curve = dal.DiscountZeroRate_New(
"usd_zero", "USD", today, node_dates, zero_rates,
day_count=dal.DayBasis_("ACT_365F"),
log_df_scheme=dal.LogDfScheme.LOG_LINEAR,
base=None,
)The returned DiscountZeroRate_ exposes read-only anchor_date, node_dates,
zero_rates, day_count, and log_df_scheme properties.
Python staged XCCY exposes both CalibrateXccyMarket(spec) and
CalibrateXccyMarket(spec, options). CrossCurrencyCalibrationOptions_
provides trailing-underscore and snake-case properties for the Jacobian mode
and the two independent compute flags; its defaults are ANALYTIC, True, and
True. The result keeps matrices under result.diagnostics, not at the result
top level. That diagnostics object exposes the forward jacobian, the
eff_jacobian_inverse, instrument-name and parameter-knot axes, residual
tolerance, scaling labels, and availability states, with matching
trailing-underscore aliases.
Python joint XCCY exposes the declarations, builder,
JointXccyCalibrationOptions_, calibration entry point, and result surface
with both trailing-underscore and snake-case aliases.
JointXccyCalibrationResult_ provides domestic_curve_block,
foreign_curve_block, basis_curve, fx_forward_curve, fixings, group
diagnostics, market_rates, model_rates, residuals,
jacobian_at_solution, eff_jacobian_inverse, parameter_ranges, and
residual_ranges. CalibrateJointXccyMarket(spec, options) selects analytic or
bumped Jacobians and optional matrix construction. The effective inverse has
shape totalParameters x totalResiduals; applying it to a raw decimal quote
bump requires division by the spec's tolerance_, as described in the
Jacobian methodology.
Python exports the seven-family enum, all family-specific terms classes,
RateTradeDefinition_, RatePricingMarket_, PriceRateTrades,
RateTradeNodeSensitivities, RateTradeNodeSensitivitiesBatch, and
AggregateRatePortfolioNodeRisk. The pricing and sensitivity functions use
keyword-only arguments and release the GIL around native work.
Repeated pricing also exposes PreparedRateTrades_New,
PreparedRateTrades_Get_Prices and PreparedRateTrades_Get_NodeSensitivities
with keyword-only inputs and a read-only prepared size property.
component_keys must be a Python list — a tuple is rejected with TypeError
before any native work starts. The minimal single-trade call:
r = dal.RateTradeNodeSensitivities(trade=trade, market=market, component_key="discount")
# r.eligible, r.pv, list(r.gradient), r.reasonResults are read-only projections of the C++ shapes. A complete runnable deposit example covering the batch and aggregation calls is in the dal-python README.
Python exposes RateQuoteRiskProvenanceConfig_, all four supported provenance
builders, and AggregateRatePortfolioQuoteRisk as keyword-only calls. They
release the GIL around native construction or aggregation and return read-only
objects. The axis/state fingerprint schemes, stable availability reasons,
price-per-decimal and DV01 units, and UnconvertedByActualPvCcy policy are
identical to C++.
The runnable single-curve quote-risk example
prints both fingerprints, the policy, and every bucket. The
joint XCCY example also
constructs joint provenance. The generic joint example
uses constructible spec/options, CalibrateJointMultiCurveBundle, owning result
curves, and BuildJointMultiCurveQuoteRiskProvenance. Ordinary staged
multi-curve chain rules remain outside the supported Python surface.
Storable_ exposes read-only name and type properties, and the native
YieldCurve_ / CurveBlock_ / Bag_ hierarchy is bound for archive
compatibility with the standalone web application. _StorableToJson,
_StorableFromJson, _BagNew, and _BagContents are private integration
helpers rather than supported general serialization functions.
settings = dal.EuropeanPdeSettings_(grid_points=61, ordinary_steps=120)
risk = dal.EuropeanPdeRiskResult_New(0.05, 0.20, 110.0, settings=settings)
call_price, put_price = risk.prices
call_rho_per_bp = 1e-4 * risk.jacobian[0, 0]
call_vega_per_point = 0.01 * risk.jacobian[0, 1]The three required parameters are absolute decimal rate, volatility and strike.
Optional settings and numeric_payload_budget_bytes /
recording_capacity_budget_bytes are keyword-only. Settings are immutable:
node/ordinary-interval defaults are 61/120, upper boundary 400, expiry 1,
dividend yield 0.02 and both solve-error limits 1e-12.
Both error limits must be finite and in [0,1].
spot_index=None resolves the quarter-grid node; otherwise supply an interior
node index. Strike must be positive, below the upper boundary and away from
grid nodes. Volatility and expiry must be positive. Bool, enums and implicit
numeric coercions are rejected.
The owning result exposes copied point, settings, grid, prices,
jacobian, axes/units, spot, method, actual chronological forward/
transpose error matrices and execution resource observations. Its arrays and
matrices remain valid after GC or subsequent calls. Native work releases the
GIL. The mesh, spot node, dividend and expiry are passive; the Jacobian contains
rate/volatility/strike first derivatives only.
The numeric budget covers 8*(17+nodes+6*(ordinary_steps+2)) retained doubles,
excluding labels, containers and temporary copies. The recording limit uses
actual retained tape/event capacity with a cleanup reservation; it is not a
process heap quota. Zero limits reject nonempty requests. See
the financial program and budget details.
See dal-python/README.md for package-focused examples.