From 25f1ba80c5ff57eaa3c1b390df580a342fc80e29 Mon Sep 17 00:00:00 2001 From: Peter Dekkers Date: Thu, 22 Aug 2024 07:13:48 +0200 Subject: [PATCH] Changed the return type for matmul operator on monetary objects --- roboquant/__init__.py | 2 +- roboquant/account.py | 4 ++-- roboquant/monetary.py | 20 +++++++++++--------- tests/unit/test_account.py | 8 ++++---- tests/unit/test_monetary.py | 13 ++++++++----- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/roboquant/__init__.py b/roboquant/__init__.py index 6a305fd..0aab022 100644 --- a/roboquant/__init__.py +++ b/roboquant/__init__.py @@ -3,7 +3,7 @@ `Account`, `Asset` and `Event`. """ -__version__ = "0.9.1" +__version__ = "0.9.2" import logging diff --git a/roboquant/account.py b/roboquant/account.py index 3090c26..80ff63c 100644 --- a/roboquant/account.py +++ b/roboquant/account.py @@ -67,7 +67,7 @@ def mkt_value(self) -> Wallet: def convert(self, x: Wallet | Amount) -> float: """convert a wallet or amount into the base currency of the account""" - return x.convert(self.base_currency, self.last_update) + return x.convert_to(self.base_currency, self.last_update) def position_value(self, asset: Asset) -> float: """Return position value denoted in the base currency of the account.""" @@ -84,7 +84,7 @@ def long_positions(self) -> dict[Asset, Position]: def contract_value(self, asset: Asset, size: Decimal, price: float) -> float: """Contract value denoted in the base currency of hte account""" - return asset.contract_amount(size, price).convert(self.base_currency, self.last_update) + return asset.contract_amount(size, price).convert_to(self.base_currency, self.last_update) def equity(self) -> Wallet: """Return the equity of the account. diff --git a/roboquant/monetary.py b/roboquant/monetary.py index 84981f4..e2e0e48 100644 --- a/roboquant/monetary.py +++ b/roboquant/monetary.py @@ -165,12 +165,13 @@ def __add__(self, other: "Amount") -> "Wallet": """ return Wallet(self, other) - def __matmul__(self, other: Currency) -> float: - return self.convert(other, datetime.now(tz=timezone.utc)) + def __matmul__(self, other: Currency) -> "Amount": + time = datetime.now(tz=timezone.utc) + return Amount(other, self.convert_to(other, time)) - def convert(self, currency: Currency, time: datetime) -> float: - """Convert this amount to another currency and return that value. - If a conversion is required, it will invoke the registered `Amount.converter`. + def convert_to(self, currency: Currency, time: datetime) -> float: + """Convert this amount to another currency and return the monetary value. + If an exchange rate is required, it will invoke the registered `Amount.converter` under the hood. """ if currency == self.currency: return self.value @@ -217,17 +218,18 @@ def __sub__(self, other: "Amount | Wallet"): result[k] -= v return result - def __matmul__(self, other: Currency) -> float: - return self.convert(other, datetime.now(tz=timezone.utc)) + def __matmul__(self, other: Currency) -> Amount: + time = datetime.now(tz=timezone.utc) + return Amount(other, self.convert_to(other, time)) def deepcopy(self) -> "Wallet": result = Wallet() result.update(self) return result - def convert(self, currency: Currency, time: datetime) -> float: + def convert_to(self, currency: Currency, time: datetime) -> float: """convert all the amounts hold in this wallet to a single currency and return the value""" - return sum(amount.convert(currency, time) for amount in self.amounts()) + return sum(amount.convert_to(currency, time) for amount in self.amounts()) def __repr__(self) -> str: return " + ".join([f"{a}" for a in self.amounts()]) diff --git a/tests/unit/test_account.py b/tests/unit/test_account.py index a782891..77b27a0 100644 --- a/tests/unit/test_account.py +++ b/tests/unit/test_account.py @@ -16,8 +16,8 @@ def test_account_init(self): self.assertEqual(acc.buying_power.value, 0.0) self.assertEqual(acc.buying_power.currency, USD) self.assertEqual(acc.base_currency, USD) - self.assertEqual(acc.unrealized_pnl().convert(USD, now), 0.0) - self.assertEqual(acc.mkt_value().convert(USD, now), 0.0) + self.assertEqual(acc.unrealized_pnl().convert_to(USD, now), 0.0) + self.assertEqual(acc.mkt_value().convert_to(USD, now), 0.0) self.assertEqual(acc.equity_value(), 1_000.0) def test_account_positions(self): @@ -31,9 +31,9 @@ def test_account_positions(self): acc.positions[symbol] = Position(Decimal(10), price, price) prices[symbol] = price - self.assertAlmostEqual(acc.mkt_value().convert(USD, now), 1450.0) + self.assertAlmostEqual(acc.mkt_value().convert_to(USD, now), 1450.0) self.assertAlmostEqual(acc.equity_value(), 2450.0) - self.assertAlmostEqual(acc.unrealized_pnl().convert(USD, now), 0.0) + self.assertAlmostEqual(acc.unrealized_pnl().convert_to(USD, now), 0.0) if __name__ == "__main__": diff --git a/tests/unit/test_monetary.py b/tests/unit/test_monetary.py index c6ac81f..1425b1c 100644 --- a/tests/unit/test_monetary.py +++ b/tests/unit/test_monetary.py @@ -40,17 +40,20 @@ def test_conversion(self): now = datetime.now() Amount.register_converter(One2OneConversion()) one_dollar = Amount(USD, 1.0) - self.assertEqual(1.0, one_dollar.convert(EUR, now)) + self.assertEqual(1.0, one_dollar.convert_to(EUR, now)) Amount.register_converter(NoConversion()) - self.assertRaises(NotImplementedError, lambda: one_dollar.convert(EUR, now)) + self.assertRaises(NotImplementedError, lambda: one_dollar.convert_to(EUR, now)) def test_static_conversion(self): now = datetime.now() converter = StaticConversion(USD, {EUR: 0.9, GBP: 0.8, JPY: 150}) Amount.register_converter(converter) amt1 = Amount(GBP, 100.0) - self.assertAlmostEqual(112.5, amt1.convert(EUR, now)) + self.assertAlmostEqual(112.5, amt1.convert_to(EUR, now)) + + start = 100@EUR + self.assertAlmostEqual(start, 100@EUR@USD@EUR) Amount.register_converter(NoConversion()) @@ -59,10 +62,10 @@ def test_ecb_conversion(self): converter = ECBConversion() Amount.register_converter(converter) amt1 = Amount(GBP, 100.0) - self.assertAlmostEqual(117.8856, amt1.convert(EUR, now), 4) + self.assertAlmostEqual(117.8856, amt1.convert_to(EUR, now), 4) # convert an amount to its own currency - self.assertEqual(amt1.value, amt1@amt1.currency) + self.assertEqual(amt1.value, (amt1@amt1.currency).value) Amount.register_converter(NoConversion())