File size: 4,448 Bytes
afd8f1d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
import pandas as pd
import numpy as np
from datetime import datetime
import requests
import os
from functools import lru_cache
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# SingStat API configuration
SINGSTAT_API_KEY = os.getenv('SINGSTAT_API_KEY')
SINGSTAT_API_URL = "https://tablebuilder.singstat.gov.sg/api/table/tabledata"
# HDB Resale Price Index table ID
HDB_TABLE_ID = "M212881"
@lru_cache(maxsize=1) # Cache the HDB data for 1 day
def fetch_hdb_price_index():
"""
Fetch HDB Resale Price Index from SingStat TableBuilder API
"""
try:
if not SINGSTAT_API_KEY:
raise Exception("SINGSTAT_API_KEY not found in environment variables")
# API parameters
params = {
"key": SINGSTAT_API_KEY,
"resourceId": HDB_TABLE_ID,
"variable": "HDB Resale Price Index",
"timeFrom": "2000",
"timeTo": datetime.now().strftime("%Y")
}
# Make API request
response = requests.get(SINGSTAT_API_URL, params=params)
response.raise_for_status()
# Parse response
data = response.json()
if 'Data' not in data:
raise Exception("Invalid response format from SingStat API")
# Extract the data
records = data['Data']
if not records:
raise Exception("No records found in SingStat API response")
# Convert to DataFrame
df = pd.DataFrame(records)
# Process the data
# The exact column names might need adjustment based on the actual API response
df['year'] = pd.to_datetime(df['year'], format='%Y')
df['value'] = pd.to_numeric(df['value'])
# Create a dictionary of year to index
yearly_data = df.set_index('year')['value']
# Convert to dictionary with string keys
result = {str(year.year): float(value) for year, value in yearly_data.items()}
return result
except Exception as e:
print(f"Error fetching HDB data from SingStat: {e}")
# Fallback to hardcoded data if API fails
return {
'2000': 78.3,
'2001': 75.6,
'2002': 74.1,
'2003': 73.1,
'2004': 74.3,
'2005': 80.0,
'2006': 88.0,
'2007': 100.0,
'2008': 110.0,
'2009': 100.0, # Base year
'2010': 105.0,
'2011': 111.0,
'2012': 118.0,
'2013': 123.0,
'2014': 120.0,
'2015': 115.0,
'2016': 110.0,
'2017': 108.0,
'2018': 110.0,
'2019': 111.0,
'2020': 112.0,
'2021': 120.0,
'2022': 130.0,
'2023': 140.0,
'2024': 145.0
}
def calculate_hdb_returns(start_date, end_date, initial_investment):
"""
Calculate HDB price returns based on the HDB Resale Price Index
"""
try:
# Get the latest HDB price index data
hdb_index = fetch_hdb_price_index()
# Create a date range for the investment period
date_range = pd.date_range(start=start_date, end=end_date)
# Convert the yearly data to a Series with datetime index
yearly_dates = pd.to_datetime([f"{year}-01-01" for year in hdb_index.keys()])
yearly_values = list(hdb_index.values())
yearly_prices = pd.Series(yearly_values, index=yearly_dates)
# Sort by date to ensure proper interpolation
yearly_prices = yearly_prices.sort_index()
# Interpolate the price index for each day
daily_prices = yearly_prices.reindex(date_range, method='ffill')
# Calculate the return based on the price index
if not daily_prices.empty:
start_price = daily_prices.iloc[0]
daily_returns = daily_prices / start_price
investment_value = initial_investment * daily_returns
return investment_value
return None
except Exception as e:
print(f"Error calculating HDB returns: {e}")
return None
if __name__ == "__main__":
# Test the function
start = datetime(2000, 1, 1)
end = datetime(2024, 1, 1)
result = calculate_hdb_returns(start, end, 100000)
print(result) |