carlospalol / money

Python money class with optional CLDR-backed locale-aware formatting and an extensible currency exchange solution.
MIT License
230 stars 34 forks source link

Currency pair classes #25

Open jeroenmeulenaar opened 7 years ago

jeroenmeulenaar commented 7 years ago

I have an use-case where I'm comparing different exchange rates. From Wikipedia: A currency pair is EUR/USD. Here, EUR is the base currency and USD is the quote currency. The quotation EUR/USD 1.2500 means that one euro is exchanged for 1.2500 US dollars.

I'd like to write something like

# Convert here 1 EUR for 1 USD
exchange1 = CurrencyPair(base = 'EUR', quote = 'USD', rate = '1.25')

# Convert here 1 EUR for 2 USD
exchange2 = CurrencyPair(base = 'EUR', quote = 'USD', rate = '2.50')

euro = Money(amount='1.00', currency='EUR')
dollar1 = exchange1 * euro   # dollar1 is now equal to Money(amount='1.25', currency='USD')
dollar2 = exchange2 * euro   # dollar2 is now equal to Money(amount='2.50', currency='USD')

I made this quickly by duplicating the Money class and changing some of it's multiplication operations.

Is this something you'd like to support? If so, I can make a proper pull request.

carlospalol commented 7 years ago

Hi Jeroen, it sounds like a good alternative to the exchange backend in your scenario (multiple rates simultaneously, better visibility of what is going on).

Such an exchange rate object could potentially be instantiated as one-way only (sell/buy rates) or both-ways (e.g. exchange1 * dollars -> euros) and it could also be used internally by the exchange backend.

Please let's keep this on hold for now, I would like to review a few things first in the codebase.

jeroenmeulenaar commented 7 years ago

Okay, I'll wait :). I also need to figure out how to make the code nicer. My current CurrencyPair has 90% overlap with the Money class, so I guess I need to pull out the commonality to a superclass.

jeroenmeulenaar commented 7 years ago

As for the both-way support: yes, I think this is good, but your example would need division (dollar / exchange1 -> euros). Otherwise you get into troubles with associativity, e.g.

three = Decimal('3.0')
(exchange1 * three) * dollar != exchange1 * (three * dollar)
carlospalol commented 7 years ago

You are correct, that would be weird.

jeroenmeulenaar commented 6 years ago

Please let's keep this on hold for now, I would like to review a few things first in the codebase.

Any update on this?