units icon indicating copy to clipboard operation
units copied to clipboard

Conversion of monetary units

Open danielhuppmann opened this issue 4 years ago • 7 comments

As discussed in other contexts, it would be highly useful to add a module to convert between different currencies taking into account deflation and the year (or more granular?) of conversion.

I.e., converting from 2010-USD to 2020-EUR would yield different results depending on whether you first deflate from 2010 to 2020 and then convert, or vice versa.

danielhuppmann avatar Feb 27 '21 14:02 danielhuppmann

Good suggestion!

Some thoughts:

  • There are ≥2 kinds of data involved:
    • Deflators/inflators.
    • Exchange rates.
      • Market.
      • PPP.
  • Following the pattern of iam_units.emissions, this should include code to update the definitions files which are stored in the repo/installed with the package, so the definitions can simply be read at runtime.
    • This code can query the World Bank web service or other data source(s) for the data.
    • Are there multiple sources for each kind of data? What are the best initial/default choices?
  • As suggested, a function like convert_currency() would need to take an argument to describe the "order" for a conversion between two (currency, period) pairs.
  • Per "or more granular?".
    • It's true that a conversion between 2 currencies on, e.g. 2021-02-27 is different than one on 2021-02-26; there are even intra-day rates.
    • Deflator data is probably more coarse in resolution than exchange rate data. Are there sources for sub-annual deflators?
    • For a first cut, it seems simplest to stick with a single resolution, the coarsest.
    • Perhaps could implement a matching algorithm, e.g. if the package ships with annual data, and the user requests "2021-02-27", they get the average rate for 2021.
    • We currently define units like EUR_2010, EUR_2020, etc.. We should use the ISO 8601 "basic" format rather than "extended" for sub-annual, because e.g. EUR_20210226, because EUR_2021-02-26 contains hyphens that would probably offend pint (interpreted as separators).
      • Maybe sub-annual dates could only be passed through that optional argument?
  • Keywan Riahi mentioned there was earlier research on methods for market and PPP exchange rates; we should dig it up and see if it suggests anything, or at least reference it.

khaeru avatar Feb 27 '21 15:02 khaeru

Hi all, luckily enough, I ran into this use case a few years ago (oh jesus, just saw it was 4 years ago in the commit log..) and wrote a small tool to help deal with it.

Salamanca treats inflation/deflation for both MER/PPP exchange calculations. It offers both an API and CLI for currency conversions specifically. Because it is based on WB data, only year-granularity is supported. An interface into the WB rest API is also provided (@coroa just helped updating it to v2) as both API and CLI.

I've been meaning to at least get the module back on its feet in terms of CI/setuptools-scm, etc. If this would help here, happy to put some time into it.

Note in addition to users at CA, I believe Ed and Miguel both use some of salamanca in other use cases. But best to check with them on that.

gidden avatar Feb 27 '21 16:02 gidden

To note, I developed this module during the course of working on downscaling and inequality, so there's also some handy tools/conversions there as well (e.g., between Ginis and Theils).

gidden avatar Feb 27 '21 16:02 gidden

@gidden thanks for mentioning that!

The two packages seem to have slightly different aims, e.g. this one is narrowly aimed at making it possible to do some things via pint-parseable units, with those other (useful) tasks out of scope. So perhaps it would be most straightforward to copy/use part of the Salamanca code as reference (with appropriate credit) when addressing this issue.

Whoever tackles this enhancement can decide the best course.

khaeru avatar Feb 28 '21 11:02 khaeru

One use case encountered in openENTRANCE and several IAM projects is to convert combined units, like 2010-USD/kW (for investment cost) to 2020-EUR/kW or EJ/2010-USD (for energy per GDP) to GWh/2020-EUR. It would be super-nice to combine the generality of pint & iam-units with the currency-specific features of salamanca...

danielhuppmann avatar Feb 28 '21 16:02 danielhuppmann

Hi all, fresh new rtd, pypi tag, fully tested on all 3 oses with py 3.7/3.8. To note, currency conversion and wb rest api querying is about 2/3 of total code size (or more) as it was one of the primary purposes of the library at the time.

On Sun, Feb 28, 2021, 17:42 Daniel Huppmann [email protected] wrote:

One use case encountered in openENTRANCE and several IAM projects is to convert combined units, like 2010-USD/kW (for investment cost) to 2020-EUR/kW or EJ/2010-USD (for energy per GDP) to GWh/2020-EUR. It would be super-nice to combine the generality of pint & iam-units with the currency-specific features of salamanca...

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/IAMconsortium/units/issues/25#issuecomment-787480985, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAKUAEJZI6MY5XCW645ABOTTBJW6ZANCNFSM4YKAAIAQ .

gidden avatar Feb 28 '21 18:02 gidden

In #43:

  • @danielhuppmann removes the hard-coded conversion between USD and EUR and comments (consistent with the discussion above):

    Instead, I think we should add an explicit way to set the conversion year using a pint-context or similar.

    In my view, this follows the principle of explicit rather than implicit configuration.

  • @gidden also adds further detail at https://github.com/IAMconsortium/units/pull/43#issuecomment-1631081722

I see that above I already shared some thoughts. At this point I think I see one of two options:

  1. User calls a specific method (like convert_currency()) to perform currency conversions and iam-units selects a particular context in which to do so; or
  2. User calls a specific method (like setup_currency()) to configure currency conversions, and the package inserts/updates the appropriate definitions in iam_units.registry, to then be used through ordinary pint behaviour.

In the case of (2), the method could be called by default, with a deprecation warning; and then in future releases that default call would disappear. This would avoid downstream code breakage from #43.

I'd be able to take this on, but not until middle of next week.

khaeru avatar Jul 19 '23 10:07 khaeru