Annabella Stoll-Dansereau
Exchange rates are notoriously difficult to predict. Even extrapolating from transaction costs it's hard to find a model that proves more accurate than a random walk (mean zero). Many of the models learned in my Microfinance class, 456, taught us models that rely on inaccessible data such as the natural interest rate and the output gap. Sometimes these indicators are provided though they are highly speculative and not widely available across countries.
While any complex model was out of the question there was the simple real exchange rate equation defined as
$$RER = \frac{P_{US}}{P_{i}} * S $$Where the RER is the real exchange rate, S is the nominal exchange rate and P are the price levels in the respective counties. To clarify this is always in the US perspective i.e. for Canada and US an RER = 1.3 would mean for every 1 USD you get 1.3 CAD.
One theory is that long-run RER stays constant between counties so if the RER is above the mean in one year in the long run it should come back down and meaning the home currency will depreciate. Since the US is our benchmark RER that is above the long run RER would mean the exchange rate should adjust down. In this example, the USD feels a depreciation compared to the other country in question.
My main question was whether I could build a framework that made money on average following some investing rule based on this model. To test this I created a short and long-betting strategy in the currency depending on what my model said. If my model predicted a depreciation in the the non-US currency I would take out a loan in that currency using it to buy US dollars and hold those. Then after some period I would convert the currency back into the non-US currency and make a profit! (or more likely a loss). The opposite trading strategy occurred when I predicted the non-US currency would appreciate.
There are some obvious assumptions that need to be addressed. First I assumed the present value of my investment stayed the same over the years. This is highly unlikely because the US interest rate is much lower than more risky currencies and loan rates will differ depending on the nation. With more time, and access to more data it would be interesting to relax this assumption and account for various lending rates between countries to take into consideration the accumulation/depreciation of wealth over the holding period. Also, note that the stated returns are over the time period and not yearly.
Another assumption was no trading costs and unlimited access to capital and credit. The data is also stated on a yearly basis so I could compare the exchange rate to the OECD indexes. There are probably some timing issues as exchange rates are very volatile locally.
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings('ignore')
def data_comp(variables):
'''
cleaning OECD data pass in the name of csv files you are using
'''
for n, var in enumerate(variables):
#read in file OECD data
df = pd.read_csv(f"{var}.csv")
#drop redundent columns and transform it into Year, Country, Variable
df.columns = df.iloc[2]
df.drop([0,1,2], inplace=True)
df.drop(df.columns[1:44], axis=1, inplace=True)
df.set_index('Country Name', inplace = True, drop = True)
df = df.T
df.index = [round(idx) for idx in df.index]
df.index = pd.to_datetime(df.index, format='%Y')
df = df.reset_index()
df = pd.melt(df, id_vars=['index'], value_vars=df.columns[1:], var_name='Country Name', value_name='Value')
df.set_index(['index', 'Country Name'], inplace=True)
df.index.names = ["Year", "Country Name"]
df.rename(columns={'Value': var}, inplace=True)
#making the dataframe and combining over all variables
if n == 0:
full_df = df
else:
full_df = pd.concat([full_df, df], axis =1)
return(full_df)
df_PPP_model= data_comp(['RER', 'Forex rate', 'PPP'])
df_PPP = pd.read_csv(f"PPP_US.csv")
df_PPP_model = df_PPP_model[df_PPP_model.notna().all(axis=1)]
df_PPP_model['con_RER'] = (df_PPP_model['Forex rate'] * df_PPP_model['PPP'])
df =df_PPP_model.reset_index()
df= pd.read_csv(f"PPP_US.csv")
country_mapping = {
'ARM': 'Armenia', 'ATG': 'Antigua and Barbuda', 'AUS': 'Australia', 'BDI': 'Burundi', 'BGR': 'Bulgaria',
'BHR': 'Bahrain', 'BHS': 'Bahamas, The', 'BLZ': 'Belize', 'BOL': 'Bolivia', 'BRA': 'Brazil',
'CAF': 'Central African Republic', 'CAN': 'Canada', 'CHE': 'Switzerland', 'CHL': 'Chile', 'CHN': 'China',
'CIV': "Cote d'Ivoire", 'CMR': 'Cameroon', 'COD': 'Congo, Dem. Rep.', 'COL': 'Colombia', 'CRI': 'Costa Rica',
'CYP': 'Cyprus', 'CZE': 'Czechia', 'DMA': 'Dominica', 'DNK': 'Denmark', 'DOM': 'Dominican Republic',
'DZA': 'Algeria', 'FJI': 'Fiji', 'GAB': 'Gabon', 'GBR': 'United Kingdom', 'GEO': 'Georgia', 'GHA': 'Ghana',
'GMB': 'Gambia, The', 'GNQ': 'Equatorial Guinea', 'GRC': 'Greece', 'GRD': 'Grenada', 'GUY': 'Guyana',
'HKG': 'Hong Kong SAR, China', 'HRV': 'Croatia', 'HUN': 'Hungary', 'IRN': 'Iran, Islamic Rep.', 'ISL': 'Iceland',
'ISR': 'Israel', 'JPN': 'Japan', 'KNA': 'St. Kitts and Nevis', 'KOR': 'Korea, Rep.', 'LCA': 'St. Lucia',
'LSO': 'Lesotho', 'LVA': 'Latvia', 'MAR': 'Morocco', 'MDA': 'Moldova', 'MEX': 'Mexico', 'MKD': 'North Macedonia',
'MLT': 'Malta', 'MWI': 'Malawi', 'MYS': 'Malaysia', 'NGA': 'Nigeria', 'NIC': 'Nicaragua', 'NOR': 'Norway',
'NZL': 'New Zealand', 'PAK': 'Pakistan', 'PHL': 'Philippines', 'PNG': 'Papua New Guinea', 'POL': 'Poland',
'PRY': 'Paraguay', 'ROU': 'Romania', 'RUS': 'Russian Federation', 'SAU': 'Saudi Arabia', 'SGP': 'Singapore',
'SLB': 'Solomon Islands', 'SLE': 'Sierra Leone', 'SVK': 'Slovak Republic', 'SWE': 'Sweden', 'TGO': 'Togo',
'TTO': 'Trinidad and Tobago', 'TUN': 'Tunisia', 'UGA': 'Uganda', 'UKR': 'Ukraine', 'URY': 'Uruguay', 'USA': 'United States',
'VCT': 'St. Vincent and the Grenadines', 'VEN': 'Venezuela, RB', 'WSM': 'Samoa', 'ZAF': 'South Africa',
'ZMB': 'Zambia'}
def apply_country_mapping(location):
if location in country_mapping:
return country_mapping[location]
else:
return None
df['LOCATION'] = df['LOCATION'].apply(apply_country_mapping)
# Extract only the necessary columns
df = df[['LOCATION', 'TIME', 'Value']]
df['TIME'] = pd.to_datetime(df['TIME'], format='%Y')
df = df.rename(columns={'Value': 'PPP_for_ER'})
df = df.dropna()
df.set_index(['TIME', 'LOCATION'], inplace=True)
df.index.set_names(['Year', 'Country Name'], inplace=True)
df
df_merged = df.merge(df_PPP_model, left_index=True, right_index=True, how='inner')
df_merged['Final_diff'] = df_merged['con_RER'] - df_merged['PPP_for_ER']
#filtering out unstable ones, increases returns by only 2% in higher return one so not super important
df_merged = df_merged[df_merged['Final_diff']>-0.1]
df_merged = df_merged[df_merged['Final_diff']<0.1]
df_merged.sort_index(inplace=True)
# Select all rows with years before 2015 and including 2015
df_year_before_2015 = df_merged.loc[(slice(None, '2015-01-01'), slice(None)), :]
df_merged['diff_in_ave_RER'] = df_merged['RER'].div(df_year_before_2015.groupby('Country Name').mean()['RER'])
df_years={}
for yr in range(2000, 2022):
name = f'df_{yr}'
dt_year= pd.to_datetime(f'{yr}-01-01')
df_year = df_merged.loc[(dt_year, slice(None))]
df_years[yr] = df_year
For mean reversion I am taking the average of the historical $RER$ up until 2015 and then predicting on this 2015-2018 using a collection of 1-4 year holding periods. I calculed the difference in the average $RER$ as $$\frac{RER_{n}}{ \Sigma_{i=2000}^ {2014} \frac{1}{15}RER_i}$$ where n is between 2015-2018.
If this value was greater less than one that means the USD is overvalued or other currency is undervalued as such we expect the USD to depreciate and should take out a loan in USD and buy the other currency then after the holding period pay back the loan and make a profit (...hopfully).
# Function that determines if the currency is overvalued i.e. <1 and we should should bet the currency will go up
def holdings(row):
if row['diff_in_ave_RER'] < 1:
loan_amount = row['loan_amount'] * row['Forex rate']
row['usd_amount'] = loan_amount/row['Forex rate']
row['home_currency_amount'] = -loan_amount
else:
loan_amount = row['loan_amount']
row['usd_amount'] = -loan_amount
row['home_currency_amount'] = loan_amount * row['Forex rate']
return row
yr_past = 2015
returns = {}
for yr_past in range(2015,2018):
list = []
for yr in range(1,5):
yr_future = yr_past+yr
df = df_years[yr_past]
df['loan_amount'] = 1000
df_mean_RER_investment = df_years[yr_past].apply(holdings,axis=1)
df_mean_RER_investment[f'{yr_future}_ER'] = df_years[yr_future]['Forex rate']
df_mean_RER_investment['new_usd_amount'] = (1/df_mean_RER_investment[f'{yr_future}_ER'])*df_mean_RER_investment['home_currency_amount']
df_mean_RER_investment['return_USD'] = df_mean_RER_investment['new_usd_amount'] + df_mean_RER_investment['usd_amount']
total_investment = df_mean_RER_investment['return_USD'].count() *1000
gains = df_mean_RER_investment['return_USD'].sum()
return_to = (((gains+total_investment)/total_investment-1)*100).round(3)
list.append(return_to)
returns[yr_past] = list
returns_mean_reverting = []
for i in range(0,4):
elements = [v[i] for v in returns.values()]
average = sum(elements) / len(elements)
returns_mean_reverting.append(average)
print(f"Average Returns for {i+1} year holding period:", average.round(2), "%")
Average Returns for 1 year holding period: -0.06 % Average Returns for 2 year holding period: -0.49 % Average Returns for 3 year holding period: 0.49 % Average Returns for 4 year holding period: 2.15 %
Here we see evidence for mean reversion although the percentages are very small, so you wont be making much money.
This is where the theory becomes a bit looser and instead is experimenting. There was OECD data on the estimated real exchange rates, while there wasn't any information on how exactly they reported this is wasn't by our definition above so that cued me to use this differential in a model. There are a lot of timing issues as I have no idea when these various data sources reported their values but assuming everything was reported for the same time (end/beginning of the year).
In one version I decided that the market knows best and the nominal exchange rate is the most reflective of current information and true expectations of $RER$ and maybe $RER_{OECD}$ was a more accurate true real exchange rate taking into consideration more than just the price levels. Whatever the mechanism I guessed that the $RER_{OECD}$ would adjust towards the market information and used this value to benchmark whether the currency should appreciate or depreciate.
$$\Delta = RER_{con} - RER_{OECD}$$Where as before $ RER_{con} = PPP*S $. I hypothesized that if this value was positive then that would mean nominal rates would adjust. If we held moved the OECD to close this gap a positive value would mean the price $RER_{OECD}$ would have to increase and thus cause an appreciation of the dollar compared to the other currency. As such we would want to invest in USD and take out a loan in the other currency.
In another strategy, I used the absolute value of this differential to automatically get a loan in the other currency and invest in USD. The rationale was this indicates an unstable currency potentially (unstable in terms of expectation not actual trading volatility). However, this signalled that it would be better to divest in that currency. This return that we see could be interpreted as compensation for risk, while we are personally safe from this risk because our holdings are in USD the loan we took out in the other currency may have a higher loan payment rate because of currency instability causing us to make a much lower real return.
I first model this with equal investments in all countries based on a holdings rule (i.e. either a loan or hold $1000 USD for all countries regardless of the size of the differential).
def holdings(row):
if row['Final_diff'] > 0:
loan_amount = 1000 * row['Forex rate']
row['usd_amount'] = loan_amount/row['Forex rate']
row['home_currency_amount'] = -loan_amount
else:
loan_amount = 1000
row['usd_amount'] = -loan_amount
row['home_currency_amount'] = loan_amount * row['Forex rate']
return row
returns = {}
for yr_past in range(2009,2018):
list = []
for yr in range(1,5):
yr_future = yr_past+yr
df_mean_PPP_diff_investment = df_years[yr_past].apply(holdings, axis=1)
df_mean_PPP_diff_investment[f'{yr_future}_ER'] = df_years[yr_future]['Forex rate']
df_mean_PPP_diff_investment['new_usd_amount'] = (1/df_mean_PPP_diff_investment[f'{yr_future}_ER'])*df_mean_PPP_diff_investment['home_currency_amount']
df_mean_PPP_diff_investment['return_USD'] = df_mean_PPP_diff_investment['new_usd_amount'] + df_mean_PPP_diff_investment['usd_amount']
total_investment = df_mean_PPP_diff_investment['return_USD'].count() *1000
gains = df_mean_PPP_diff_investment['return_USD'].sum()
return_to = (((gains+total_investment)/total_investment-1)*100).round(3)
list.append(return_to)
returns[yr_past] = list
returns_uniform = []
for i in range(0,4):
elements = [v[i] for v in returns.values()]
average = sum(elements) / len(elements)
returns_uniform.append(average)
print(f"Average Returns for {i+1} year holding period:", average.round(2),"%")
Average Returns for 1 year holding period: 0.22 % Average Returns for 2 year holding period: 0.52 % Average Returns for 3 year holding period: 1.18 % Average Returns for 4 year holding period: 1.83 %
We see a small return although nothing to be too happy about.
To try and break my model and see whether we just got lucky over the ten years I am describing a new holding rule. Now you will invest in a currency proportional to your holdings so this will amplify our prediction rule effect. I capped investments at a threshold given some countries had abnormally high differentials as a non risk adverse invester I decided this was an okay assumption as having these outliers really skewed the returns (i.e. if we invested 10000 dollars in Australia and under 100 dollars in all other countries we would just be modeling the predictive power for Austria).
def holdings(row):
if row['Final_diff'] > 0:
loan_amount = row['loan_amount']* row['Forex rate']
row['usd_amount'] = loan_amount/row['Forex rate']
row['home_currency_amount'] = -loan_amount
else:
loan_amount = row['loan_amount']
row['usd_amount'] = -loan_amount
row['home_currency_amount'] = loan_amount * row['Forex rate']
return row
returns = {}
for yr_past in range(2008,2018):
list = []
for yr in range(1,5):
yr_future = yr_past+yr
x = 10000000 * df_years[yr_past]['Final_diff'].abs()
df_years[yr_past]['loan_amount'] = x.clip(upper=1000)
df_mean_PPP_diff_investment = df_years[yr_past].apply(holdings, axis=1)
df_mean_PPP_diff_investment[f'{yr_future}_ER'] = df_years[yr_future]['Forex rate']
df_mean_PPP_diff_investment['new_usd_amount'] = (1/df_mean_PPP_diff_investment[f'{yr_future}_ER'])*df_mean_PPP_diff_investment['home_currency_amount']
df_mean_PPP_diff_investment['return_USD'] = df_mean_PPP_diff_investment['new_usd_amount'] + df_mean_PPP_diff_investment['usd_amount']
df_years[yr_past]['home_currency_amount'] = df_mean_PPP_diff_investment['home_currency_amount']
df_years[yr_past]['usd_amount'] = df_mean_PPP_diff_investment['usd_amount']
total_investment = np.abs(df_mean_PPP_diff_investment['usd_amount']).sum()
gains = df_mean_PPP_diff_investment['return_USD'].sum()/total_investment *100
list.append(gains)
returns[yr_past] = list
returns_prop = []
for i in range(0,4):
elements = [v[i] for v in returns.values()]
average = sum(elements) / len(elements)
returns_prop.append(average)
print(f"Average Returns for {i+1} year holding period:", average.round(2), "%")
Average Returns for 1 year holding period: 1.15 % Average Returns for 2 year holding period: 0.57 % Average Returns for 3 year holding period: 1.99 % Average Returns for 4 year holding period: 2.92 %
We see stronger returns overall holding periods which is a positive sign that we are measuring an actual effect rather than purely getting lucky (although we can't rule luck out).
Next we will investigate our final question of whether the size rather than actual sign of this differential has an effect. Note that we will be shorting every currency to different extents (i.e. we rarely take a position in Canada becuase our differential stated that this is a stable currency).
returns2 = {}
for yr_past in range(2008,2018):
list = []
for yr in range(1,5):
yr_future = yr_past+yr
x = 10000000 * df_years[yr_past]['Final_diff']
df_years[yr_past]['loan_amount'] = x.clip(upper=1000)
df_mean_PPP_diff_investment = df_years[yr_past].apply(holdings, axis=1)
df_mean_PPP_diff_investment[f'{yr_future}_ER'] = df_years[yr_future]['Forex rate']
df_mean_PPP_diff_investment['new_usd_amount'] = (1/df_mean_PPP_diff_investment[f'{yr_future}_ER'])*df_mean_PPP_diff_investment['home_currency_amount']
df_mean_PPP_diff_investment['return_USD'] = df_mean_PPP_diff_investment['new_usd_amount'] + df_mean_PPP_diff_investment['usd_amount']
#df_years[yr_past]['home_currency_amount'] = df_mean_PPP_diff_investment['home_currency_amount']
#df_years[yr_past]['usd_amount'] = df_mean_PPP_diff_investment['usd_amount']
total_investment = np.abs(df_mean_PPP_diff_investment['usd_amount']).sum()
gains = df_mean_PPP_diff_investment['return_USD'].sum()/total_investment *100
list.append(gains)
returns2[yr_past] = list
returns_prop2 = []
for i in range(0,4):
elements2 = [v[i] for v in returns2.values()]
average2 = sum(elements2) / len(elements2)
returns_prop2.append(average2)
print(f"Average Returns for {i+1} year holding period:", average2.round(2), "%")
Average Returns for 1 year holding period: 3.24 % Average Returns for 2 year holding period: 5.82 % Average Returns for 3 year holding period: 7.06 % Average Returns for 4 year holding period: 10.75 %
Here our the returns for the different strategies graphed together, taking the average across all the years I modeled it for (2008-2018) across discrete time periods (1,2,3,4 years).
import plotly.graph_objs as go
# Create some data for the chart
x_values = [1, 2, 3, 4]
y_1 = returns_mean_reverting
y_2 = returns_uniform
y_3 = returns_prop
y_4 = returns_prop2
# Create two traces, one for each line
trace1 = go.Scatter(x=x_values, y=y_1, mode='lines', name='Average Returns to Mean Reverting Investing')
trace2 = go.Scatter(x=x_values, y=y_2, mode='lines', name='Average Returns Uniform PPP Investing')
trace3 = go.Scatter(x=x_values, y=y_3, mode='lines', name='Average Returns Proportional PPP Investing')
trace4 = go.Scatter(x=x_values, y=y_4, mode='lines', name='Average Absolute Deviation PPP Investing')
# Add the traces to a data object
data = [trace1, trace2, trace3, trace4]
# Define the layout for the chart
layout = go.Layout(title={'text': 'Returns to Different Investment Strategies','y': 0.95, 'x': 0.35, 'xanchor': 'center',
'yanchor': 'top'},
xaxis_title='Holding Period', yaxis_title='Percentage Return (%)')
# Create the figure
fig = go.Figure(data=data, layout=layout)
# Show the figure
fig.show()
To better understand what is happending here is a snapshot showing the different holding periods and the returns depending on which year you started investing. It appears to be more reliable over longer time horizons and we see a large dip after the 2008 crisis. Although this isn't the most enlightening picture it shows how we are getting pretty consistent positive returns and not just having one year with incredibly high returns making up for negatives across other years.
import plotly.graph_objs as go
from plotly.subplots import make_subplots
# Define the years and values for each holding period
years = [k for k in returns2.keys()]
values = [[v[i] for v in returns2.values()] for i in range(4)]
# Define the colors for each holding period
colors = ['red', 'green', 'blue', 'purple']
# Define the subplot layout
fig = make_subplots(rows=2, cols=2, subplot_titles=["1 Year Holding Period", "2 Year Holding Period",
"3 Year Holding Period", "4 Year Holding Period"])
# Loop through the data and create a bar chart in each subplot
for i in range(4):
row = (i // 2) + 1
col = (i % 2) + 1
fig.add_trace(go.Bar(x=years, y=values[i], marker_color=colors[i], name=f'{i+1} Year Holding Period'),
row=row, col=col)
# Update the subplot layout and style
fig.update_layout(height=600, width=800,
title={
'text': 'Return in the PPP Strategy over Holding Periods by Start Year',
'y': 0.98,
'x': 0.5,
'xanchor': 'center',
'yanchor': 'top'},
showlegend=False,
margin=dict(l=20, r=20, t=80, b=20),
paper_bgcolor='rgb(255, 255, 255)',
plot_bgcolor='rgb(243, 243, 243)',
yaxis=dict(automargin=True),
xaxis=dict(automargin=True),
)
for i in range(2):
for j in range(2):
fig.update_xaxes(title_text="Year", row=i+1, col=j+1)
fig.update_yaxes(title_text="Returns (%)", row=i+1, col=j+1)
# Show the plot
fig.show()
Finally, let's look at what is happening on a country level, what currencies we are betting will go up and which we are betting to go down. The red indicates we are expecting the home currency to depreciate and we took out an associated loan in that currency. Green indicates an appreciation in the currency so you want to loan in USD and hold in the other currency. The closer to white the hue is the less significant our differential is thus we took a smaller position. For the deviation investing you can interpret the darker-coloured countries as countries we bet more strongly against.
This map shows how your holdings change over the years (press replay if you want to see it go again) also notice that white moves with zero even if the ranges change because that was an annoying detail to code.
import pandas as pd
import plotly.graph_objs as go
import plotly.offline as offline
import plotly.io as pio
pio.renderers.default = 'iframe'
df_full = []
colors = []
for year in range(2008, 2018):
df = df_years[year].reset_index()
df = df[df['Country Name'] != 'United States']
df_full.append(df)
max = df['usd_amount'].max()
min = df['usd_amount'].min()
middle = (max)/(max-min)
colors.append([[0, 'red'], [middle, 'white'], [1, 'green']])
frames = []
for i, year in enumerate(range(2008, 2018)):
# Create choropleth trace for each year
choropleth_trace = go.Choropleth(
locations=df_full[i]['Country Name'].astype(str),
z=-(df_full[i]['usd_amount'].astype(float)),
locationmode='country names',
colorscale=colors[i],
colorbar_title=f"Home Currency t=0 ($) {year}"
)
frames.append(go.Frame(data=[choropleth_trace]))
layout = go.Layout(
title={
'text': 'Betting: Shorting or Going Long 2008-2017',
'y': 0.9,
'x': 0.45,
'xanchor': 'center',
'yanchor': 'top'},
geo_scope='world',
updatemenus=[{
'type': 'buttons',
'buttons': [{
'label': 'Replay',
'method': 'animate',
'args': [None, {'frame': {'duration': 1000, 'redraw': True}, 'fromcurrent': True, 'transition': {'duration': 0, 'easing': 'linear'}}]
}]
}]
)
fig = go.Figure(data=[choropleth_trace], frames=frames)
fig.update_layout(layout)
offline.iplot(fig)
offline.plot(fig, filename='animation.html')
'animation.html'
Clearly a within-sample question but I was curious if there were any countries that we always took a long or short position on. Remember that we took a series of 10 years so countries with lower numbers like -2 or 2 which implies that 6:4 of the times we took one position over the other and would imply a more stable currency that is potentially stronger. This map doesn't glean much information however shows that positions change and we have a split between shorting and going long depending on the year. So it's not that we are measuring consistent effects of the USD strengthening and every other currency weakening.
values={}
yr = 2015
for country in df_years[yr].index:
value = 0
for yr in range(2008, 2018):
x = df_years[yr].groupby('Country Name')['Final_diff'].mean()
try:
if x[country]>=0:
value +=1
elif x[country]<0:
value -=1
except:
print()
values[country] = value
df = pd.Series(values)
df = df.reset_index()
colors = [[0, 'darkblue'], [0.37, 'white'], [1, 'green']]
# Choropleth map!
fig = go.Figure(data=go.Choropleth(
locations = df['index'].astype(str),
z = df[0].astype(float),
locationmode = 'country names',
colorscale = colors,
colorbar_title = "Home Currency t=0 ($)"
))
fig.update_layout(
#manually centering, not great but not sure how to automate
title={
'text': 'Performance of Different Currencies',
'y': 0.9,
'x': 0.45,
'xanchor': 'center',
'yanchor': 'top'},
geo_scope = 'world'
)
fig.show()
offline.plot(fig, filename='static_map.html')
'static_map.html'
I thought this was pretty cool that we got non-zero returns on all the investment strategies. To be honest this brought forth more questions than answers, especially regarding the feasibility strategies of the absolute deviation strategy (how would it work with different interest and lending rates). Is it even possible to get safe assets in some of these countries that I modelled in or are part of these effects just coming from risk?
There are a lot of weaknesses in this modelling for example I have no idea why proportionally betting on the USD wins maybe it's because the higher differential signals an unstable currency and you can earn through USD. But it was interesting to see that the strength of my effect increased when we changed from uniform to proportional investing. The takeaway isn’t clear and would require a lot more analysis. All in all, I wouldn't start taking out large loans from currencies that deviated from the real exchange rate measure defined above.
All the files used came from OECD data (https://data.oecd.org/) and special thanks to ChatGPT for helping with some mind-numbing tasks like writing down my country mapping part in the data cleaning section.