Curves
A series is a shape of assume — rate curves, price decks, escalation
paths — read at the reader's period as inputs.<name>, and at another
date with curve_value(inputs.<name>, date).
assume sofr = curve linear {
2026-01: 0.050
2027-01: 0.038
}
stream loan.interest on entity asset.loan inflow currency USD {
schedule every month from 2026-01 to 2026-12
amount = 1000000 * (inputs.sofr + 0.0275) / 12
}Interpolation
step— flat-forward: each value holds until the next point.linear— calendar-day interpolation between points.- Before the first point a series reads the first value. Past the last point
it holds the last value flat-forward, and a stream or field that reads it
there is warned once (
W5024). - A series may state the dates it is good for on its header,
curve from 2026-01 to 2029-05 { … }. A read outside them has no value, and the run is refused (E5040), naming the series, the date and the reader.
Duplicate point dates or malformed points fail compilation with
E5008_INVALID_CURVE; two assumptions of one name are E1005. The old
string spelling, curve_value("sofr", …), is refused with the new one.
Where a series shines
The credit pack's floating-rate loan reads its coupon index from a series
the index term names, with margin, floor, and cap. An interest-only loan
states amortization = "interest_only":
contract credit.loan.bridge on entity asset.buyer {
term 2026-01..2029-05
terms {
amortization = "interest_only"
principal = 15000000
index = inputs.sofr
margin = 0.0275
rate_floor = 0.07
rate_cap = 0.09
amortization_months = 36
}
}A series supplied by the run
A series the model states is its fallback. The run's inputs file can replace it by full name, with its own points, interpolation, effective dates and source, or fill a series the model declares with a type and no body:
assume sofr : rateThe run then must supply sofr, or it is refused before any period exists
(E5045). See Scenarios and run configurations.
A series as the discount rate
A run that names a series as annual_discount_curve, in place of
annual_discount_rate, discounts each period at that period's annual rate.
The results record run.annual_discount_curve in place of the scalar rate.
Quantiles: a spread instead of a path
A series is indexed by date. A quantile is indexed by cumulative share, for a quantity whose spread within a period drives the answer, such as the hours of a month's power prices:
assume prices = quantile linear {
0.00: 11.0
0.50: 28.0
0.98: 340.0
1.00: 512.0
}It is read with quantile_at(inputs.prices, share),
quantile_mean(inputs.prices, from, to) and
quantile_of(inputs.prices, value).
Uncertainty and a series
A series is deterministic, and it is not sampled. Uncertainty about its level
is an ordinary distributed assumption scaling the read,
inputs.price_factor * inputs.power_price. A rate path that moves
stochastically is computed, not stated: a field on a reference entity
whose rule reads a distributed assumption, or sample(inputs.<name>) for a
draw per entity and period.