Table of Contents

RateSeries Class

Definition

Namespace
Bodu.Financial.ExchangeRates
Assembly
Bodu.Financial.dll
Package
Bodu.Financial 1.0.0
Source
RateSeries.cs

Stores the ordered set of dated exchange-rate observations for a single provider and currency pair, optimised for read-heavy lookup with allocation-free O(log n) resolution under any RateDateResolution policy.

public sealed class RateSeries
Inheritance
RateSeries
Inherited Members
Extension Methods

Remarks

The collection is immutable after construction. Internally it stores observations in a shared Bodu.Financial.ExchangeRates.RateSeriesStorage backed by two parallel sorted arrays - an int array of day numbers (DayNumber) and a decimal array of rates - so that the binary search at lookup time touches only the compact date array. Compared with SortedDictionary<TKey, TValue> this gives substantially better cache locality, no per-node allocation, and predictable hot-path performance for the multi-year daily series typical of FX data.

Instances are safe to share across threads after construction because all read paths only touch read-only arrays. Use RateSeriesBuilder to construct or edit observations imperatively before producing a snapshot via ToSeries().

using Bodu.Financial;

var series = new RateSeries(
    new CurrencyPair(CurrencyCode.USD, CurrencyCode.EUR),
    "ECB",
    new[] { (new DateOnly(2024, 3, 1), 0.92m), (new DateOnly(2024, 3, 4), 0.93m) });

// Resolve a date that has no exact observation, falling back to the previous one.
bool ok = series.TryGetRate(
    new DateOnly(2024, 3, 3),
    RateLookupOptions.PreviousWithin(5),
    out DateOnly resolvedDate,   // 2024-03-01
    out decimal rate);           // 0.92

Constructors

RateSeries(CurrencyPair, string, IEnumerable<RateObservation>, DateTimeOffset?)

Initializes a new instance of the RateSeries class from a sequence of RateObservation records.

public RateSeries(CurrencyPair pair, string provider, IEnumerable<RateObservation> observations, DateTimeOffset? fetchedAtUtc = null)

Parameters

pair CurrencyPair

The currency pair this series describes.

provider string

The non-empty identifier of the publishing source.

observations IEnumerable<RateObservation>

The observations to include. Must contain at least one entry and must not contain duplicate dates.

fetchedAtUtc DateTimeOffset?

The UTC instant at which the load that produced this series downloaded its source data, or null when not tracked.

Exceptions

ArgumentNullException

Thrown if provider or observations is null.

ArgumentException

Thrown if provider is empty or white-space, if observations is empty, or if it contains duplicate dates.

ArgumentOutOfRangeException

Thrown if any rate in observations is zero or negative.

RateSeries(CurrencyPair, string, IEnumerable<(DateOnly Date, decimal Rate)>, DateTimeOffset?)

Initializes a new instance of the RateSeries class from a sequence of date/rate tuples.

public RateSeries(CurrencyPair pair, string provider, IEnumerable<(DateOnly Date, decimal Rate)> rates, DateTimeOffset? fetchedAtUtc = null)

Parameters

pair CurrencyPair

The currency pair this series describes.

provider string

The non-empty identifier of the publishing source.

rates IEnumerable<(DateOnly Date, decimal Rate)>

The observations to include. Must contain at least one entry and must not contain duplicate dates.

fetchedAtUtc DateTimeOffset?

The UTC instant at which the load that produced this series downloaded its source data, or null when not tracked.

Exceptions

ArgumentNullException

Thrown if provider or rates is null.

ArgumentException

Thrown if provider is empty or white-space, if rates is empty, or if it contains duplicate dates.

ArgumentOutOfRangeException

Thrown if any rate in rates is zero or negative.

Properties

Count

Gets the number of observations stored in this series.

public int Count { get; }

Property Value

int

A non-negative count equal to the number of rate entries supplied at construction.

FetchedAtUtc

Gets the UTC instant at which the load that produced this series downloaded its source data, or null when not tracked.

public DateTimeOffset? FetchedAtUtc { get; }

Property Value

DateTimeOffset?

The fetch instant when known; otherwise null.

Remarks

The fetch instant is recorded at the series grain and stamped onto every ExchangeRate the series materializes, so downstream audit consumers can attribute a served rate to the moment its backing data was fetched. It is provenance metadata only and does not affect resolution.

Pair

Gets the currency pair this series describes.

public CurrencyPair Pair { get; }

Property Value

CurrencyPair

The series pair.

Provider

Gets the identifier of the source that published the rates in this series.

public string Provider { get; }

Property Value

string

A non-empty provider identifier.

Methods

GetObservations()

Enumerates the observations in strictly ascending date order.

public IEnumerable<RateObservation> GetObservations()

Returns

IEnumerable<RateObservation>

A lazy sequence of RateObservation values.

ToBuilder()

Creates a mutable builder pre-populated from this series.

public RateSeriesBuilder ToBuilder()

Returns

RateSeriesBuilder

A new RateSeriesBuilder seeded with the current observations.

TryGetRate(DateOnly, RateLookupOptions?, out DateOnly, out decimal)

Attempts to resolve a rate for requestedDate under options.

public bool TryGetRate(DateOnly requestedDate, RateLookupOptions? options, out DateOnly resolvedDate, out decimal rate)

Parameters

requestedDate DateOnly

The calendar date the caller is asking about.

options RateLookupOptions

The lookup rules to apply.

resolvedDate DateOnly

When this method returns true, the observation date selected as the answer; otherwise default.

rate decimal

When this method returns true, the rate observed on resolvedDate; otherwise default.

Returns

bool

true if a rate was resolved within tolerance; otherwise false.

Remarks

The resolution algorithm performs a single BinarySearch<T>(T[], T) over the day-number array. On an exact hit the corresponding rate is returned immediately. On a miss the previous and next candidate indices are derived from the bitwise complement of the returned index, then selected per options. For Nearest with a tie (the requested date lies exactly midway between two observations), this method returns false so callers receive a deterministic failure rather than an arbitrary pick.

WithRate(DateOnly, decimal)

Returns a new series with the observation for date upserted to rate.

public RateSeries WithRate(DateOnly date, decimal rate)

Parameters

date DateOnly

The observation date to insert or update.

rate decimal

The rate to record on date.

Returns

RateSeries

A new RateSeries reflecting the updated observation.

Remarks

Each call materialises a complete new immutable series, so this method is intended for occasional, functional-style single updates. For bulk import or repeated mutation, accumulate observations in an RateSeriesBuilder and build the series once rather than calling WithRate(DateOnly, decimal) in a loop.

Exceptions

ArgumentOutOfRangeException

Thrown if rate is zero or negative.

WithoutRate(DateOnly)

Returns a new series with the observation for date removed if present.

public RateSeries WithoutRate(DateOnly date)

Parameters

date DateOnly

The observation date to remove.

Returns

RateSeries

A new RateSeries reflecting the removal.

Exceptions

InvalidOperationException

Thrown if removing the observation would leave the series empty.

Applies to

ProductVersions
.NET8, 10