ExLedger.Parser.Price (ex_ledger v0.6.0)
Parser for price directives (P DATE COMMODITY PRICE).
Provides extraction, parsing, and lookup functionality for price data.
Summary
Functions
Returns all available commodity pairs in the price database.
Builds a price database from a list of price directives.
Returns all commodities that can be converted to the target currency.
Extracts all price directives from input.
Looks up the price for a commodity on a given date.
Parses a single price directive line.
Types
@type price_directive() :: ExLedger.Parser.Core.price_directive()
Functions
Returns all available commodity pairs in the price database.
Examples
iex> db = %{{"EUR", "CHF"} => [...], {"USD", "CHF"} => [...]}
iex> Price.available_pairs(db)
[{"EUR", "CHF"}, {"USD", "CHF"}]
@spec build_price_db([price_directive()]) :: price_db()
Builds a price database from a list of price directives.
The database is indexed by {source_commodity, target_commodity} tuples, with prices sorted by date descending for efficient lookup.
Examples
iex> prices = [
...> %{date: ~D[2026-01-15], commodity: "EUR", price: %{value: 0.9432, currency: "CHF"}},
...> %{date: ~D[2026-02-01], commodity: "EUR", price: %{value: 0.9455, currency: "CHF"}}
...> ]
iex> db = Price.build_price_db(prices)
iex> db[{"EUR", "CHF"}]
[{~D[2026-02-01], 0.9455}, {~D[2026-01-15], 0.9432}]
Returns all commodities that can be converted to the target currency.
Examples
iex> db = %{{"EUR", "CHF"} => [...], {"USD", "CHF"} => [...], {"GBP", "EUR"} => [...]}
iex> Price.commodities_convertible_to("CHF", db)
["EUR", "USD"]
@spec extract_price_directives(String.t()) :: [price_directive()]
Extracts all price directives from input.
Returns a list of price directive maps with date, commodity, and price.
Examples
iex> input = """
...> P 2026-01-15 EUR CHF 0.9432
...> P 2026-01-15 USD CHF 0.8821
...> """
iex> Price.extract_price_directives(input)
[
%{date: ~D[2026-01-15], commodity: "EUR", price: %{value: 0.9432, currency: "CHF", currency_position: :leading}},
%{date: ~D[2026-01-15], commodity: "USD", price: %{value: 0.8821, currency: "CHF", currency_position: :leading}}
]
@spec lookup_price(String.t(), String.t(), Date.t(), price_db()) :: {:ok, Decimal.t()} | {:error, :no_price_found}
Looks up the price for a commodity on a given date.
Returns the most recent price on or before the given date.
Examples
iex> db = %{{"EUR", "CHF"} => [{~D[2026-02-01], 0.9455}, {~D[2026-01-15], 0.9432}]}
iex> Price.lookup_price("EUR", "CHF", ~D[2026-01-20], db)
{:ok, 0.9432}
iex> Price.lookup_price("EUR", "CHF", ~D[2026-02-15], db)
{:ok, 0.9455}
iex> Price.lookup_price("EUR", "CHF", ~D[2026-01-01], db)
{:error, :no_price_found}
@spec parse_price_directive(String.t()) :: {:ok, price_directive()} | :skip
Parses a single price directive line.
Format: P DATE COMMODITY PRICE
- DATE: YYYY/MM/DD or YYYY-MM-DD
- COMMODITY: The source commodity symbol (e.g., EUR, USD, AAPL)
- PRICE: The price amount with target currency (e.g., CHF 0.9432 or $150.00)
Examples
iex> Price.parse_price_directive("P 2026-01-15 EUR CHF 0.9432")
{:ok, %{date: ~D[2026-01-15], commodity: "EUR", price: %{value: 0.9432, currency: "CHF", currency_position: :leading}}}
iex> Price.parse_price_directive("P 2026/01/15 AAPL $150.00")
{:ok, %{date: ~D[2026-01-15], commodity: "AAPL", price: %{value: 150.0, currency: "$", currency_position: :leading}}}