36 lines
1.2 KiB
Python
36 lines
1.2 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from dataclasses import replace
|
||
|
|
from decimal import Decimal
|
||
|
|
|
||
|
|
from broker_sync.fx import FxCache, convert_to_gbp
|
||
|
|
from broker_sync.models import Activity, ActivityType
|
||
|
|
|
||
|
|
_QTY_PRICE_TYPES = {ActivityType.BUY, ActivityType.SELL}
|
||
|
|
|
||
|
|
|
||
|
|
def normalise_to_gbp(activity: Activity, *, cache: FxCache) -> Activity:
|
||
|
|
"""Return a copy of `activity` with amount_gbp/fx_rate_gbp/fx_rate_source set.
|
||
|
|
|
||
|
|
Two cases:
|
||
|
|
- BUY/SELL: amount_gbp = quantity * unit_price * rate.
|
||
|
|
- Everything else (DIVIDEND/DEPOSIT/FEE/...): amount_gbp = amount * rate.
|
||
|
|
|
||
|
|
Source is always the cache's source tag (ECB_LIVE or HMRC_MONTHLY).
|
||
|
|
"""
|
||
|
|
on_date = activity.date.date()
|
||
|
|
if activity.activity_type in _QTY_PRICE_TYPES:
|
||
|
|
assert activity.quantity is not None and activity.unit_price is not None
|
||
|
|
native_total: Decimal = activity.quantity * activity.unit_price
|
||
|
|
else:
|
||
|
|
assert activity.amount is not None
|
||
|
|
native_total = activity.amount
|
||
|
|
|
||
|
|
amount_gbp, rate, source = convert_to_gbp(native_total, activity.currency, on_date, cache=cache)
|
||
|
|
return replace(
|
||
|
|
activity,
|
||
|
|
amount_gbp=amount_gbp,
|
||
|
|
fx_rate_gbp=rate,
|
||
|
|
fx_rate_source=source,
|
||
|
|
)
|