refactor(price): enhance currency handling with FX conversion and cache support
- Add `get_fx_rate()` function with caching to fetch foreign exchange rates from open.er-api.com - Introduce `get_currency()` helper to map market codes to currency identifiers - Update price parsing regex to support multiple currency symbols (£, $, €) - Convert shares to float to accommodate fractional holdings - Add currency, fx_rate, and total_value_gbp fields to output JSON - Support fractional share counts (e.g., 3.6185 AAPL shares)
This commit is contained in:
parent
38ecbd57e0
commit
f971708c5e
@ -1,3 +1,4 @@
|
||||
GGP,GB,100
|
||||
PAF,GB,200
|
||||
SVM,US,50
|
||||
AAPL,US,3.6185
|
||||
|
38
price.py
38
price.py
@ -5,31 +5,63 @@ import sys
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
FX_CACHE = {}
|
||||
|
||||
def get_fx_rate(currency):
|
||||
if currency in FX_CACHE:
|
||||
return FX_CACHE[currency]
|
||||
if currency == "GBP":
|
||||
return 1.0
|
||||
url = f"https://open.er-api.com/v6/latest/{currency}"
|
||||
r = requests.get(url, timeout=20)
|
||||
rate = r.json()["rates"]["GBP"]
|
||||
FX_CACHE[currency] = rate
|
||||
return rate
|
||||
|
||||
def get_price(market, ticker):
|
||||
url = f"https://web.freetrade.io/universe/{market}/{ticker}"
|
||||
response = requests.get(url, headers={
|
||||
"User-Agent": "Mozilla/5.0"
|
||||
}, timeout=20)
|
||||
text = BeautifulSoup(response.text, "html.parser").get_text(" ", strip=True)
|
||||
m = re.search(r"Latest price\s*:\s*[£$]([0-9,.]+)", text)
|
||||
m = re.search(r"Latest price\s*:\s*[£$€]([0-9,.]+)", text)
|
||||
if m:
|
||||
return float(m.group(1).replace(",", ""))
|
||||
return None
|
||||
|
||||
def get_currency(market):
|
||||
return {"GB": "GBP", "US": "USD"}.get(market, "GBP")
|
||||
|
||||
holdings_file = sys.argv[1] if len(sys.argv) > 1 else "holdings.csv"
|
||||
|
||||
results = []
|
||||
with open(holdings_file) as f:
|
||||
reader = csv.reader(f)
|
||||
for row in reader:
|
||||
ticker, market, shares = row[0].strip(), row[1].strip(), int(row[2].strip())
|
||||
ticker, market, shares = row[0].strip(), row[1].strip(), float(row[2].strip())
|
||||
currency = get_currency(market)
|
||||
price = get_price(market, ticker)
|
||||
if price is None:
|
||||
results.append({
|
||||
"ticker": ticker,
|
||||
"market": market,
|
||||
"currency": currency,
|
||||
"shares": shares,
|
||||
"price": None,
|
||||
"fx_rate": None,
|
||||
"total_value_gbp": None
|
||||
})
|
||||
continue
|
||||
fx = get_fx_rate(currency)
|
||||
total_gbp = round(price * shares * fx, 2)
|
||||
results.append({
|
||||
"ticker": ticker,
|
||||
"market": market,
|
||||
"currency": currency,
|
||||
"shares": shares,
|
||||
"price": price,
|
||||
"total_value": round(price * shares, 2) if price is not None else None
|
||||
"fx_rate": fx,
|
||||
"total_value_gbp": total_gbp
|
||||
})
|
||||
|
||||
print(json.dumps(results, indent=2))
|
||||
Loading…
x
Reference in New Issue
Block a user