Bodu.Financial.Extensions Namespace
- Package
-
Bodu.Financial 1.0.0
Bodu.Financial.Extensions
Purpose
Bodu.Financial.Extensions is the extension-member namespace of the core Bodu.Financial package. It carries the derived helpers that are deliberately kept off the value types themselves - sign and magnitude tests, clamping and comparison, compact "$1.2K" formatting, dated-provider conversion, audit conveniences on a lookup result, and the materializers that turn observations into an immutable book or a fixed provider - so that Money, Money<TCurrency>, and RateLookupResult stay focused on construction, arithmetic, equality, and formatting.
Every member is a thin projection over the public surface of the type it extends and carries no state of its own. Add using Bodu.Financial.Extensions; to bring them into scope.
When the library is compiled with a tool-chain that supports C# 14 extension members (the .NET 10 SDK the repository pins), the instance helpers are exposed as extension properties - money.IsZero, result.IsExactDate - and otherwise as classic extension methods - money.IsZero(), result.IsExactDate(). Both spellings appear in the guides; the property form is the one the shipped packages expose. The comparison helpers Min, Max, and Clamp take two or more operands and are therefore ordinary static methods (MoneyOfTCurrencyExtensions.Clamp(value, min, max)) under either tool-chain.
Static documentation
- Working with
Money<TCurrency>- the value types these helpers extend, including compact formatting. - Working with exchange rates - dated lookups, provenance, and the audit-grade conversion these extensions provide.
- Exchange-rate lookups on a known dataset - reading the resolution metadata the
RateLookupResulthelpers summarize. - Built-in exchange-rate providers - snapshotting a provider's book with
ToBook/ToFixedProvider/ToFixedProviderAsync.
Key types
Sign and magnitude
- MoneyExtensions - for the runtime-tagged Money:
Abs,Sign(-1/0/1),IsZero,IsPositive,IsNegative. - MoneyOfTCurrencyExtensions - the same five members for Money<TCurrency>, plus the static comparison helpers
Min(left, right),Max(left, right), andClamp(value, min, max)(throwsArgumentExceptionwhenmin > max). Being generic overTCurrency, they only ever compare amounts in the same currency.
Formatting
- MoneyCompactFormattingExtensions -
ToCompactString(format = "C", provider = null, precision = 1)for both money types: scales by thousands, millions, billions, or trillions and appendsK/M/B/Tto the numeric portion, honoring the format specifier's currency placement per culture ("$1.2K","1,2K €"). The round-tripRspecifier is rejected withFormatExceptionbecause compact output cannot round-trip.
Conversion through a dated provider
- MoneyOfTCurrencyExchangeRateExtensions -
ConvertTo<TSource, TTarget>(provider, date, options, rounding)returns the converted Money<TCurrency>;ConvertToWithRate<TSource, TTarget>(…)returns a MoneyConversionResult<TSource, TTarget> carryingSourceAmount,TargetAmount, and the fullExchangeRatelookup result for the audit trail. - MoneyExchangeRateExtensions - the runtime-tagged counterparts on Money:
ConvertTo(provider, targetIsoCode, date, …)andConvertTo<TTarget>(provider, date, …)return the converted amount;ConvertToWithRate(provider, targetIsoCode, date, …)returns a(Money Target, RateLookupResult Rate)tuple.
All four resolve the rate with IDatedRateProvider.GetRate(from, to, date, options), so a miss surfaces as KeyNotFoundException, and round the product at the destination currency's precision with the supplied MidpointRounding (banker's rounding by default).
Lookup-result audit
- RateLookupResultExtensions - derived views over RateLookupResult:
ResolvedDate(the observed date,Rate.Date),SignedOffsetDays(negative when the observation predates the request, positive when it post-dates it, zero on an exact match),IsExactDate,IsPreviousDate, andIsFutureDate.
Materializing books and providers
- ExchangeRateEnumerableExtensions -
ToBook()on anyIEnumerable<ExchangeRate>: one series per(pair, provider), upsert semantics for duplicate dates, inverse-resolved rows stored under their natively quoted direction, and each series'FetchedAtUtcset to the latest instant seen - so aggregated or multi-source range results round-trip without error. - RateBookExtensions -
ToFixedProvider()wraps a RateBook in a FixedDatedRateProvider (throws when a pair has two providers);ToFixedProvider(providerPriority)resolves that ambiguity with an ordered provider list. - DatedRateProviderExtensions -
ToFixedProviderAsync(pairs, startDate, endDate, cancellationToken)fetches each distinct pair's window throughGetRatesAsync(sequentially - the web providers already coalesce) and materializes an immutable, source-independent FixedDatedRateProvider.
Example
using Bodu.Financial;
using Bodu.Financial.Currencies;
using Bodu.Financial.ExchangeRates;
using Bodu.Financial.Extensions;
Money<USD> balance = new Money<USD>(-1_250_000m);
bool overdrawn = balance.IsNegative; // true (IsNegative() under the method form)
Money<USD> magnitude = balance.Abs; // USD 1,250,000.00
string compact = magnitude.ToCompactString(); // "$1.3M" in en-US
Money<USD> fee = MoneyOfTCurrencyExtensions.Clamp(
new Money<USD>(3.25m),
new Money<USD>(1m),
new Money<USD>(2.50m)); // USD 2.50 - clamped to the upper bound
// Audit-grade conversion through a dated provider.
IDatedRateProvider provider = new FixedDatedRateProvider(new[]
{
new ExchangeRate(CurrencyCode.USD, CurrencyCode.EUR, new DateOnly(2024, 6, 14), 0.93m, "Test"),
});
MoneyConversionResult<USD, EUR> converted = new Money<USD>(100m).ConvertToWithRate<USD, EUR>(
provider,
new DateOnly(2024, 6, 16),
RateLookupOptions.PreviousWithin(7));
Console.WriteLine(converted.TargetAmount); // EUR 93.00
Console.WriteLine(converted.ExchangeRate.SignedOffsetDays); // -2 - the Friday observation served a Sunday request
Console.WriteLine(converted.ExchangeRate.IsExactDate); // False
// Freeze a range of observations into an offline provider.
RateRangeResult window = provider.GetRates("USD", "EUR", new DateOnly(2024, 6, 1), new DateOnly(2024, 6, 30));
FixedDatedRateProvider offline = window.ToBook().ToFixedProvider();
Notes
- Extension properties vs methods. Under the C# 14 tool-chain the instance helpers are properties (
money.IsZero); under an older tool-chain they are methods (money.IsZero()). The staticMin/Max/Clamphelpers are called through the class name in both cases. - Same-currency only.
Min,Max, andClampare generic over oneTCurrency, so mixing currencies is a compile error, not a runtime check; the runtime-tagged Money has no comparison helpers because a cross-currency comparison has no meaningful answer. - Conversion rounds once. Each
ConvertTomultiplies the source amount by the resolved rate and rounds once at the destination precision; the unrounded rate is available on the returned lookup result when an audit needs it. ToBookkeeps multiple providers apart. Unlike theFixedDatedRateProvider(IEnumerable<ExchangeRate>)constructor, which requires one provider per pair,ToBook()accepts rates for the same pair from several providers and keeps them as separate series; choose which wins withToFixedProvider(providerPriority).- See also: the
Bodu.Financialreference and theBodu.Financial.ExchangeRatesreference.
Classes
- DatedRateProviderExtensions
Provides extension methods that materialize the historical rates any IDatedRateProvider serves into immutable, offline-queryable snapshots.
- ExchangeRateEnumerableExtensions
Provides extension methods that materialize sequences of ExchangeRate observations into the immutable RateBook store.
- MoneyCompactFormattingExtensions
Provides compact-notation formatting (
"$1.2K","€1.5M","USD 2.3B") for Money<TCurrency> and Money values, on top of the standard format-specifier vocabulary.
- MoneyExchangeRateExtensions
Provides extension methods that resolve a dated exchange rate from an IDatedRateProvider and apply it to a Money - the runtime-tagged counterpart of MoneyOfTCurrencyExchangeRateExtensions.
- MoneyExtensions
Provides sign, magnitude, and related convenience members for the runtime-tagged Money type, keeping those derived helpers off the core value type while preserving familiar property-style access.
- MoneyOfTCurrencyExchangeRateExtensions
Provides extension methods that resolve a dated exchange rate from an IDatedRateProvider and apply it to a Money<TCurrency> value.
- MoneyOfTCurrencyExtensions
Provides sign, magnitude, and comparison convenience members for the strongly-typed Money<TCurrency> type, keeping those derived helpers off the core value type while preserving familiar property-style access.
- RateBookExtensions
Provides extension methods that wrap an immutable RateBook in ready-to-query provider facades.
- RateLookupResultExtensions
Provides audit-convenience members for RateLookupResult that describe how the resolved rate relates to the requested date, keeping those derived helpers off the core result type.