Class AdjustmentFactor
- Namespace
- DatabentoDotNet.Reference
- Assembly
- DatabentoDotNet.Reference.dll
One row of an adjustment_factors.get_range response: an event that changes how a
security's historical prices must be scaled, and the multiplier that does it.
public sealed record AdjustmentFactor : IEquatable<AdjustmentFactor>
- Inheritance
-
AdjustmentFactor
- Implements
- Inherited Members
Remarks
Port of upstream's AdjustmentFactor (adjustment.rs:92-169), field for field and in
its order. Twenty-eight properties, fourteen of them optional — upstream's Option in every
case, never a judgement made here.
The four rate fields are decimal where upstream has f64, and this is
the type that owns that decision for all three reference models. See Factor,
which carries the measurement.
Two spellings of "absent" appear below, and the difference is upstream's rather than a
choice. A missing string is null; a missing reference code —
DividendCurrency, Frequency — is that type's
default, whose HasValue is false. A nullable code
struct would give the same field two ways to say nothing, and
IReferenceCode<TSelf> already defines one.
Currency is a string while DividendCurrency is a
Currency, and that asymmetry is reproduced rather than
tidied. Upstream types the two fields differently in adjacent lines
(adjustment.rs:147 against :157). Making them agree would be a behavioural change
to a field neither library has probed: the closing-price currency would start rejecting nothing
and start reporting IsKnown, which reads as new information when it would only be a new
guess. #57 is where a real row says which spelling the server actually uses for each.
The rows arrive in the server's order and this library does not sort them. Upstream sorts
its Vec by ExDate after buffering the whole response
(adjustment.rs:51); GetRangeAsync(AdjustmentFactorsGetRangeParams, CancellationToken) streams, and a
stream cannot be sorted. See that method, and ROADMAP.md §6.
Properties
Close
public decimal? Close { get; init; }
Property Value
Remarks
Currency
public string? Currency { get; init; }
Property Value
Remarks
A bare string, unlike DividendCurrency. Upstream's asymmetry, reproduced deliberately — see this type's remarks.
Detail
A human-readable description of the event.
public required string Detail { get; init; }
Property Value
DividendCurrency
The currency the dividend is paid in, or default when the row carries none.
public Currency DividendCurrency { get; init; }
Property Value
Remarks
Event
The event type.
public required Event Event { get; init; }
Property Value
Remarks
An open carrier rather than an enum: a code Databento adds to the EVENT dictionary is
kept rather than rejected. See Event.
EventId
Event identifier, unique at the event level. Links to a corporate action's event_id.
public required string EventId { get; init; }
Property Value
ExDate
The date from which the event is effective.
public required LocalDate ExDate { get; init; }
Property Value
Remarks
A LocalDate, not a DateOnly — CLAUDE.md, "Dates and times". It carries
no zone because the wire does not: the field is yyyy-MM-dd, and attaching a zone here
would invent one. This is the key upstream sorts its buffered response by.
Exchange
Exchange code for the listing, or null.
public string? Exchange { get; init; }
Property Value
Remarks
Equivalent to the MIC but more stable: a MIC may not be published in a timely fashion, and a MIC can change while the exchange stays the same.
Factor
The adjustment factor to apply.
public required decimal Factor { get; init; }
Property Value
Remarks
decimal rather than upstream's f64, and this property is where
that decision was made for all four rate fields here and for the eight in #54 and #55.
This is the multiplier applied to historical prices, so it is the field where the choice
bites hardest; GetCostAsync(MetadataQueryParams, CancellationToken) and
CostUsd already made the same call for money on the historical side.
What was measured, on .NET 10, because the obvious argument for it is wrong. The
claim this decision was originally written around — that a rate round-trips through
decimal and not through double — does not survive a
probe. System.Text.Json writes a double in shortest-round-trip form,
so any wire value of seventeen significant digits or fewer comes back out spelled exactly as
it arrived; upstream's own fixture value 0.995833170541121 does, and so does
0.3333333333333333. What double actually loses is not the text but
the value: 0.995833170541121 * 51.19 is 50.97669999999998399 exactly
and 50.97669999999998 in binary floating point. A factor exists to be multiplied by a
price, so that is the number that matters, and it is the reason the answer here is still
decimal.
The cost, also measured rather than assumed, and it is two-sided. Above
MaxValue (~7.9 × 10^28) System.Text.Json throws a
JsonException naming the property path — loud, diagnosable,
and confined to the row. Below ~10^-28 it does not throw: the value silently reads
as zero, which is the worse of the two failures and the one to know about. Neither bound is
reachable by a price, a dividend, a ratio near one, or a split factor, so the risk is remote
rather than absent.
The magnitudes actually present in a live response are still unprobed, and #57 turned
that from an unopened question into a measured obstacle.
RealReferenceRequestTests.TheRateFields_CarryMagnitudesDecimalHoldsComfortably reads
every factor, close, gross_dividend and sentiment a real response
carries, plus the values of CorporateAction.RateInfo, and reports any magnitude
outside a band far inside the two bounds above. Reaching its assertions at all is most of the
answer — a value beyond MaxValue throws in the converter, before any
assertion runs. On 2026-08-29 the account it ran under was answered
403 license_reference_dataset_no_subscription: reference data is a separate Databento
product, and three separate subscriptions at that. So this remains the disclosure #53 asked
for in place of a probe, and the probe now exists and is gated on
DATABENTO_REFERENCE_REQUEST rather than on anyone remembering to write it.
Frequency
How often the dividend is paid, or default when the row carries none.
public Frequency Frequency { get; init; }
Property Value
GrossDividend
The dividend before taxes or fees — the total declared by the company — or null.
public decimal? GrossDividend { get; init; }
Property Value
Remarks
Isin
The ISIN global identifier, as an ISO 6166 string, or null.
public string? Isin { get; init; }
Property Value
IsinResulting
The resulting ISIN where applicable and known, or null.
public string? IsinResulting { get; init; }
Property Value
IssuerName
The issuer name.
public required string IssuerName { get; init; }
Property Value
LocalCode
The local code, or null.
public string? LocalCode { get; init; }
Property Value
Remarks
Usually unique at market level, with exceptions. Either an alphabetic string or a number, so it stays a string either way.
LocalCodeResulting
The resulting local code where applicable and known, or null.
public string? LocalCodeResulting { get; init; }
Property Value
NasdaqSymbol
The Nasdaq Integrated Platform suffix-convention symbol, or null.
public string? NasdaqSymbol { get; init; }
Property Value
OperatingMic
Market Identifier Code (MIC), as an ISO 10383 string.
public required string OperatingMic { get; init; }
Property Value
Option
The choice or option number, where shareholders were given several ways to take the benefit — cash or scrip, for instance.
public required uint Option { get; init; }
Property Value
Remarks
A bare uint, for the reason Reason records: the vendored
dictionary describes no vocabulary for it either. Named Option on the wire; the C#
property keeps that name because it is what the field is called, and nothing in this
language reserves it.
PrimaryExchange
Exchange code for the primary security, or null.
public string? PrimaryExchange { get; init; }
Property Value
Reason
The reason code, distinguishing event types within Event.
public required uint Reason { get; init; }
Property Value
Remarks
A bare uint, and that was checked rather than assumed. #53's porting
notes asked whether this is really a closed set before shipping one. The vendored
corporate_actions.list_enums response — the oracle the ten open carriers and the nine
closed enums were both transcribed from — has 235 groups and describes this field in none of
them. Its REASON group is a different vocabulary entirely (C, H, blank);
the four groups whose codes are numeric are CLASSCODE, INDUS, MKTSG and
REPAYSRC, none of which is an adjustment reason. That is consistent with
AdjustmentStatus: the dictionary documents corporate actions, and
this is an adjustment_factors field.
So there is no table to model against and an enum here would be invented rather than ported. #57 is where real rows can say what values occur.
SecurityId
Security-level numerical ID, linking every listing of the same security together.
public required string SecurityId { get; init; }
Property Value
SecurityType
The security type.
public required SecurityType SecurityType { get; init; }
Property Value
Remarks
The field that makes SecurityType's open-carrier
shape load-bearing rather than tidy. Upstream types this as a bare
SecurityType — not an Option — over an enum modelling 30 of the 64 codes the
live dictionary reports, so one of the 34 it does not know fails the whole row rather than
one field. Here an unmodelled code arrives in Code with IsKnown false.
Sentiment
Market sentiment: the previous close divided by today's open — the market's reaction to the event.
public required decimal Sentiment { get; init; }
Property Value
Remarks
Only meaningful when the factor calculation required the previous close. Upstream carries the same caveat and the same non-optional type, so a row without one still reports a number. decimal for the reason Factor gives.
Status
The adjustment status.
public required AdjustmentStatus Status { get; init; }
Property Value
Remarks
One of the nine closed enums: three single-character codes, and an unrecognised one is an error rather than an opaque value. See AdjustmentStatus, which records that it is also the one of the nine with no independent check yet.
Symbol
The query input symbol this row matched, or null.
public string? Symbol { get; init; }
Property Value
TsCreated
When Databento added the record, in UTC.
public required Instant TsCreated { get; init; }
Property Value
Remarks
An Instant, not a DateTimeOffset. Upstream reads this through its own
deserialize_date_time rather than serde's default, which is exactly the set of
spellings InstantJsonConverter reads.
UsCode
The US domestic CUSIP, or null.
public string? UsCode { get; init; }