Module: Timeprice

Defined in:
lib/timeprice.rb,
lib/timeprice/cli.rb,
lib/timeprice/date.rb,
lib/timeprice/point.rb,
lib/timeprice/errors.rb,
lib/timeprice/schema.rb,
lib/timeprice/compare.rb,
lib/timeprice/sources.rb,
lib/timeprice/version.rb,
lib/timeprice/exchange.rb,
lib/timeprice/forecast.rb,
lib/timeprice/metadata.rb,
lib/timeprice/inflation.rb,
lib/timeprice/supported.rb,
lib/timeprice/cpi_lookup.rb,
lib/timeprice/data_loader.rb,
lib/timeprice/granularity.rb,
lib/timeprice/forecast/cagr.rb,
lib/timeprice/cli/formatting.rb,
lib/timeprice/compare/series.rb,
lib/timeprice/sources/coverage.rb,
lib/timeprice/metadata_snapshot.rb,
lib/timeprice/cli/presenters/compare.rb,
lib/timeprice/cli/presenters/sources.rb,
lib/timeprice/forecast/fx_forecaster.rb,
lib/timeprice/cli/presenters/exchange.rb,
lib/timeprice/forecast/cpi_forecaster.rb,
lib/timeprice/cli/presenters/inflation.rb

Overview

Offline historical inflation & FX for Ruby.

Top-level module functions wrap the three core operations: inflation adjustment, currency exchange, and a combined “compare” that does both in the right order. Each returns an immutable ‘Data.define` value object.

Examples:

Inflation

Timeprice.inflation(amount: 100, from: "1990-01", to: "2024-01", country: "US")

FX

Timeprice.exchange(amount: 100, from: "USD", to: "JPY", date: "2010-06-15")

Compare

Timeprice.compare(amount: 100, from: ["USD", "2010"], to: ["VND", "2024"])

Defined Under Namespace

Modules: Compare, DataLoader, Exchange, Forecast, Granularity, Inflation, Metadata, Schema, Sources, Supported Classes: CLI, CompareResult, CpiLookup, CpiPoint, DataNotFound, Date, DateOutOfRange, Error, ExchangeResult, InflationResult, InvalidDate, MetadataSnapshot, Point, UnsupportedCountry, UnsupportedCurrency, UnsupportedSchemaVersion

Constant Summary collapse

VERSION =
"0.8.0"

Class Method Summary collapse

Class Method Details

.compare(amount:, from:, to:, forecast: false) ⇒ CompareResult

Compare an amount across two (currency, date) points: convert at the source date, then inflate in the destination currency. See README.md “Compare semantics” for why this order is correct.

Parameters:

  • amount (Numeric)
  • from (Point, Array(String, String))

    source point

  • to (Point, Array(String, String))

    destination point

Returns:



97
98
99
# File 'lib/timeprice.rb', line 97

def compare(amount:, from:, to:, forecast: false)
  Compare.run(amount: amount, from: from, to: to, forecast: forecast)
end

.exchange(amount:, from:, to:, date:) ⇒ ExchangeResult

Convert an amount between currencies on a specific date.

Parameters:

  • amount (Numeric)

    the original amount

  • from (String)

    source currency (ISO 4217)

  • to (String)

    destination currency (ISO 4217)

  • date (String)

    date as “YYYY-MM-DD”

Returns:

Raises:



57
58
59
# File 'lib/timeprice.rb', line 57

def exchange(amount:, from:, to:, date:)
  Exchange.convert(amount: amount, from: from, to: to, date: date)
end

.forecast(kind:, target:, country: nil, from: nil, to: nil, window_years: nil) ⇒ Forecast::Result

Project a CPI index or FX rate forward past the last bundled data point.

Parameters:

  • kind (Symbol)

    :cpi or :fx

  • target (String)

    target date as “YYYY” or “YYYY-MM”

  • country (String) (defaults to: nil)

    (only when kind: :cpi)

  • from (String) (defaults to: nil)

    (only when kind: :fx) source currency

  • to (String) (defaults to: nil)

    (only when kind: :fx) destination currency

  • window_years (Integer, nil) (defaults to: nil)

    override default trailing window

Returns:



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/timeprice.rb', line 70

def forecast(kind:, target:, country: nil, from: nil, to: nil, window_years: nil)
  case kind
  when :cpi
    fail ArgumentError, "country: required for kind: :cpi" unless country

    opts = { country: country, target: target }
    opts[:window_years] = window_years if window_years
    Forecast::CpiForecaster.project(**opts)
  when :fx
    fail ArgumentError, "from:/to: required for kind: :fx" unless from && to

    opts = { from: from, to: to, target: target }
    opts[:window_years] = window_years if window_years
    Forecast::FxForecaster.project(**opts)
  else
    fail ArgumentError, "unknown forecast kind: #{kind.inspect} (expected :cpi or :fx)"
  end
end

.inflation(amount:, from:, to:, country:) ⇒ InflationResult

Inflation-adjust an amount between two dates using a country’s CPI.

Parameters:

  • amount (Numeric)

    the original amount

  • from (String)

    source date as “YYYY” or “YYYY-MM”

  • to (String)

    target date as “YYYY” or “YYYY-MM”

  • country (String)

    country code from Timeprice::Supported.countries

Returns:

Raises:



44
45
46
# File 'lib/timeprice.rb', line 44

def inflation(amount:, from:, to:, country:)
  Inflation.adjust(amount: amount, from: from, to: to, country: country)
end

.metadataHash

Snapshot describing the bundled dataset: version, refresh date, country list with CPI ranges, currency list with display names, and FX coverage. Intended as the single source of truth for downstream UIs (the website in particular) so dropdowns and date pickers never drift from the data.

Returns:

  • (Hash)

    frozen, JSON-serialisable



107
108
109
# File 'lib/timeprice.rb', line 107

def 
  Metadata.build
end