The dataset we'll use describes Euro daily exchange rates between 1999 and 2021. The euro (symbolized with €) is the official currency in most of the countries of the European Union.
Daria Chemkaeva put together the data set and made it available on Kaggle — the data source is the European Central Bank. Note that the dataset gets regular updates — we downloaded it on January 2021.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.style as style
import seaborn as sns
import re
import datetime
#magic command
%matplotlib inline
exchange_rates = pd.read_csv("euro-daily-hist_1999_2020.csv")
exchange_rates.shape
(5699, 41)
#first 5 rows
exchange_rates.head()
Period\Unit: | [Australian dollar ] | [Bulgarian lev ] | [Brazilian real ] | [Canadian dollar ] | [Swiss franc ] | [Chinese yuan renminbi ] | [Cypriot pound ] | [Czech koruna ] | [Danish krone ] | ... | [Romanian leu ] | [Russian rouble ] | [Swedish krona ] | [Singapore dollar ] | [Slovenian tolar ] | [Slovak koruna ] | [Thai baht ] | [Turkish lira ] | [US dollar ] | [South African rand ] | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2021-01-08 | 1.5758 | 1.9558 | 6.5748 | 1.5543 | 1.0827 | 7.9184 | NaN | 26.163 | 7.4369 | ... | 4.8708 | 90.8000 | 10.0510 | 1.6228 | NaN | NaN | 36.8480 | 9.0146 | 1.2250 | 18.7212 |
1 | 2021-01-07 | 1.5836 | 1.9558 | 6.5172 | 1.5601 | 1.0833 | 7.9392 | NaN | 26.147 | 7.4392 | ... | 4.8712 | 91.2000 | 10.0575 | 1.6253 | NaN | NaN | 36.8590 | 8.9987 | 1.2276 | 18.7919 |
2 | 2021-01-06 | 1.5824 | 1.9558 | 6.5119 | 1.5640 | 1.0821 | 7.9653 | NaN | 26.145 | 7.4393 | ... | 4.8720 | 90.8175 | 10.0653 | 1.6246 | NaN | NaN | 36.9210 | 9.0554 | 1.2338 | 18.5123 |
3 | 2021-01-05 | 1.5927 | 1.9558 | 6.5517 | 1.5651 | 1.0803 | 7.9315 | NaN | 26.227 | 7.4387 | ... | 4.8721 | 91.6715 | 10.0570 | 1.6180 | NaN | NaN | 36.7760 | 9.0694 | 1.2271 | 18.4194 |
4 | 2021-01-04 | 1.5928 | 1.9558 | 6.3241 | 1.5621 | 1.0811 | 7.9484 | NaN | 26.141 | 7.4379 | ... | 4.8713 | 90.3420 | 10.0895 | 1.6198 | NaN | NaN | 36.7280 | 9.0579 | 1.2296 | 17.9214 |
5 rows × 41 columns
#last 5 rows
exchange_rates.tail()
Period\Unit: | [Australian dollar ] | [Bulgarian lev ] | [Brazilian real ] | [Canadian dollar ] | [Swiss franc ] | [Chinese yuan renminbi ] | [Cypriot pound ] | [Czech koruna ] | [Danish krone ] | ... | [Romanian leu ] | [Russian rouble ] | [Swedish krona ] | [Singapore dollar ] | [Slovenian tolar ] | [Slovak koruna ] | [Thai baht ] | [Turkish lira ] | [US dollar ] | [South African rand ] | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
5694 | 1999-01-08 | 1.8406 | NaN | NaN | 1.7643 | 1.6138 | NaN | 0.58187 | 34.938 | 7.4433 | ... | 1.3143 | 27.2075 | 9.1650 | 1.9537 | 188.8400 | 42.560 | 42.5590 | 0.3718 | 1.1659 | 6.7855 |
5695 | 1999-01-07 | 1.8474 | NaN | NaN | 1.7602 | 1.6165 | NaN | 0.58187 | 34.886 | 7.4431 | ... | 1.3092 | 26.9876 | 9.1800 | 1.9436 | 188.8000 | 42.765 | 42.1678 | 0.3701 | 1.1632 | 6.8283 |
5696 | 1999-01-06 | 1.8820 | NaN | NaN | 1.7711 | 1.6116 | NaN | 0.58200 | 34.850 | 7.4452 | ... | 1.3168 | 27.4315 | 9.3050 | 1.9699 | 188.7000 | 42.778 | 42.6949 | 0.3722 | 1.1743 | 6.7307 |
5697 | 1999-01-05 | 1.8944 | NaN | NaN | 1.7965 | 1.6123 | NaN | 0.58230 | 34.917 | 7.4495 | ... | 1.3168 | 26.5876 | 9.4025 | 1.9655 | 188.7750 | 42.848 | 42.5048 | 0.3728 | 1.1790 | 6.7975 |
5698 | 1999-01-04 | 1.9100 | NaN | NaN | 1.8004 | 1.6168 | NaN | 0.58231 | 35.107 | 7.4501 | ... | 1.3111 | 25.2875 | 9.4696 | 1.9554 | 189.0450 | 42.991 | 42.6799 | 0.3723 | 1.1789 | 6.9358 |
5 rows × 41 columns
exchange_rates.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 5699 entries, 0 to 5698 Data columns (total 41 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Period\Unit: 5699 non-null object 1 [Australian dollar ] 5699 non-null object 2 [Bulgarian lev ] 5297 non-null object 3 [Brazilian real ] 5431 non-null object 4 [Canadian dollar ] 5699 non-null object 5 [Swiss franc ] 5699 non-null object 6 [Chinese yuan renminbi ] 5431 non-null object 7 [Cypriot pound ] 2346 non-null object 8 [Czech koruna ] 5699 non-null object 9 [Danish krone ] 5699 non-null object 10 [Estonian kroon ] 3130 non-null object 11 [UK pound sterling ] 5699 non-null object 12 [Greek drachma ] 520 non-null object 13 [Hong Kong dollar ] 5699 non-null object 14 [Croatian kuna ] 5431 non-null object 15 [Hungarian forint ] 5699 non-null object 16 [Indonesian rupiah ] 5699 non-null object 17 [Israeli shekel ] 5431 non-null object 18 [Indian rupee ] 5431 non-null object 19 [Iceland krona ] 3292 non-null float64 20 [Japanese yen ] 5699 non-null object 21 [Korean won ] 5699 non-null object 22 [Lithuanian litas ] 4159 non-null object 23 [Latvian lats ] 3904 non-null object 24 [Maltese lira ] 2346 non-null object 25 [Mexican peso ] 5699 non-null object 26 [Malaysian ringgit ] 5699 non-null object 27 [Norwegian krone ] 5699 non-null object 28 [New Zealand dollar ] 5699 non-null object 29 [Philippine peso ] 5699 non-null object 30 [Polish zloty ] 5699 non-null object 31 [Romanian leu ] 5637 non-null float64 32 [Russian rouble ] 5699 non-null object 33 [Swedish krona ] 5699 non-null object 34 [Singapore dollar ] 5699 non-null object 35 [Slovenian tolar ] 2085 non-null object 36 [Slovak koruna ] 2608 non-null object 37 [Thai baht ] 5699 non-null object 38 [Turkish lira ] 5637 non-null float64 39 [US dollar ] 5699 non-null object 40 [South African rand ] 5699 non-null object dtypes: float64(3), object(38) memory usage: 1.8+ MB
exchange_rates.isnull().sum().sort_values(ascending= False)
[Greek drachma ] 5179 [Slovenian tolar ] 3614 [Cypriot pound ] 3353 [Maltese lira ] 3353 [Slovak koruna ] 3091 [Estonian kroon ] 2569 [Iceland krona ] 2407 [Latvian lats ] 1795 [Lithuanian litas ] 1540 [Bulgarian lev ] 402 [Indian rupee ] 268 [Brazilian real ] 268 [Chinese yuan renminbi ] 268 [Croatian kuna ] 268 [Israeli shekel ] 268 [Turkish lira ] 62 [Romanian leu ] 62 [UK pound sterling ] 0 [South African rand ] 0 [Danish krone ] 0 [Czech koruna ] 0 [Swiss franc ] 0 [Canadian dollar ] 0 [Australian dollar ] 0 [Hong Kong dollar ] 0 [Japanese yen ] 0 [Hungarian forint ] 0 [Indonesian rupiah ] 0 [US dollar ] 0 [Korean won ] 0 [Mexican peso ] 0 [Malaysian ringgit ] 0 [Norwegian krone ] 0 [New Zealand dollar ] 0 [Philippine peso ] 0 [Polish zloty ] 0 [Russian rouble ] 0 [Swedish krona ] 0 [Singapore dollar ] 0 [Thai baht ] 0 Period\Unit: 0 dtype: int64
Doing a quick review of the dataset, we can see have 40 different currency conversion from the euro. Furthermore, we are given the date when the data was recorded since 1999, but the dtype is currently in a string format so will need to convert it to datetime format. Also, several of the currency currently are a string and will need to make sure all currency are float.
Lastly, we have several columns where we are missing the currency conversion especially the european countries like Greece. The reason for this they joined the EU back in 2001 and adopted the Euro currency so the Greek drachma was given up hence it having the highest missing values. I am not sure why for some like Renminbi and Rupee are missing as these countries are in Asia.
I will be cleaning the data to have it in the correct style before we do any visual.
Currency column names have these brackest "[" and "]", I will remove them and also replace spaces with under_scores.
exchange_rates_columns = exchange_rates.columns
exchange_rates_new_columns = {}
for c in exchange_rates_columns[1:]:
clean = c.strip().replace('[','').replace(']','').replace(' ','_').lower()[:-1]
exchange_rates_new_columns[c] = clean
exchange_rates_new_columns['Period\\Unit:'] = 'time'
# set inplace true to return new dataframe copy
exchange_rates.rename(columns = exchange_rates_new_columns, inplace = True)
exchange_rates.head()
time | australian_dollar | bulgarian_lev | brazilian_real | canadian_dollar | swiss_franc | chinese_yuan_renminbi | cypriot_pound | czech_koruna | danish_krone | ... | romanian_leu | russian_rouble | swedish_krona | singapore_dollar | slovenian_tolar | slovak_koruna | thai_baht | turkish_lira | us_dollar | south_african_rand | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2021-01-08 | 1.5758 | 1.9558 | 6.5748 | 1.5543 | 1.0827 | 7.9184 | NaN | 26.163 | 7.4369 | ... | 4.8708 | 90.8000 | 10.0510 | 1.6228 | NaN | NaN | 36.8480 | 9.0146 | 1.2250 | 18.7212 |
1 | 2021-01-07 | 1.5836 | 1.9558 | 6.5172 | 1.5601 | 1.0833 | 7.9392 | NaN | 26.147 | 7.4392 | ... | 4.8712 | 91.2000 | 10.0575 | 1.6253 | NaN | NaN | 36.8590 | 8.9987 | 1.2276 | 18.7919 |
2 | 2021-01-06 | 1.5824 | 1.9558 | 6.5119 | 1.5640 | 1.0821 | 7.9653 | NaN | 26.145 | 7.4393 | ... | 4.8720 | 90.8175 | 10.0653 | 1.6246 | NaN | NaN | 36.9210 | 9.0554 | 1.2338 | 18.5123 |
3 | 2021-01-05 | 1.5927 | 1.9558 | 6.5517 | 1.5651 | 1.0803 | 7.9315 | NaN | 26.227 | 7.4387 | ... | 4.8721 | 91.6715 | 10.0570 | 1.6180 | NaN | NaN | 36.7760 | 9.0694 | 1.2271 | 18.4194 |
4 | 2021-01-04 | 1.5928 | 1.9558 | 6.3241 | 1.5621 | 1.0811 | 7.9484 | NaN | 26.141 | 7.4379 | ... | 4.8713 | 90.3420 | 10.0895 | 1.6198 | NaN | NaN | 36.7280 | 9.0579 | 1.2296 | 17.9214 |
5 rows × 41 columns
#convert time column to datetime data type
exchange_rates['time'] = pd.to_datetime(exchange_rates['time'])
exchange_rates.sort_values('time', inplace=True)
exchange_rates.reset_index(drop=True, inplace=True)
exchange_rates.replace('-',np.nan, inplace= True)
# convert all column except time to float datatype
for c in list(exchange_rates.columns):
if c != 'time':
exchange_rates = exchange_rates.astype({c:'float'})
exchange_rates.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 5699 entries, 0 to 5698 Data columns (total 41 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 time 5699 non-null datetime64[ns] 1 australian_dollar 5637 non-null float64 2 bulgarian_lev 5239 non-null float64 3 brazilian_real 5370 non-null float64 4 canadian_dollar 5637 non-null float64 5 swiss_franc 5637 non-null float64 6 chinese_yuan_renminbi 5370 non-null float64 7 cypriot_pound 2304 non-null float64 8 czech_koruna 5637 non-null float64 9 danish_krone 5637 non-null float64 10 estonian_kroon 3074 non-null float64 11 uk_pound_sterling 5637 non-null float64 12 greek_drachma 514 non-null float64 13 hong_kong_dollar 5637 non-null float64 14 croatian_kuna 5370 non-null float64 15 hungarian_forint 5637 non-null float64 16 indonesian_rupiah 5637 non-null float64 17 israeli_shekel 5369 non-null float64 18 indian_rupee 5370 non-null float64 19 iceland_krona 3292 non-null float64 20 japanese_yen 5637 non-null float64 21 korean_won 5637 non-null float64 22 lithuanian_litas 4097 non-null float64 23 latvian_lats 3842 non-null float64 24 maltese_lira 2304 non-null float64 25 mexican_peso 5637 non-null float64 26 malaysian_ringgit 5637 non-null float64 27 norwegian_krone 5637 non-null float64 28 new_zealand_dollar 5637 non-null float64 29 philippine_peso 5637 non-null float64 30 polish_zloty 5637 non-null float64 31 romanian_leu 5637 non-null float64 32 russian_rouble 5637 non-null float64 33 swedish_krona 5637 non-null float64 34 singapore_dollar 5637 non-null float64 35 slovenian_tolar 2049 non-null float64 36 slovak_koruna 2560 non-null float64 37 thai_baht 5637 non-null float64 38 turkish_lira 5637 non-null float64 39 us_dollar 5637 non-null float64 40 south_african_rand 5637 non-null float64 dtypes: datetime64[ns](1), float64(40) memory usage: 1.8 MB
exchange_rates.isnull().sum().sort_values(ascending= False)
greek_drachma 5185 slovenian_tolar 3650 maltese_lira 3395 cypriot_pound 3395 slovak_koruna 3139 estonian_kroon 2625 iceland_krona 2407 latvian_lats 1857 lithuanian_litas 1602 bulgarian_lev 460 israeli_shekel 330 indian_rupee 329 brazilian_real 329 croatian_kuna 329 chinese_yuan_renminbi 329 hong_kong_dollar 62 south_african_rand 62 uk_pound_sterling 62 hungarian_forint 62 czech_koruna 62 swiss_franc 62 canadian_dollar 62 australian_dollar 62 danish_krone 62 japanese_yen 62 indonesian_rupiah 62 us_dollar 62 korean_won 62 mexican_peso 62 malaysian_ringgit 62 norwegian_krone 62 new_zealand_dollar 62 philippine_peso 62 polish_zloty 62 romanian_leu 62 russian_rouble 62 swedish_krona 62 singapore_dollar 62 thai_baht 62 turkish_lira 62 time 0 dtype: int64
Throughout the project I will be only looking at usa dollar, however I may come back to the other conversion. So for now I will isoloate the time and the us_dollar column.
Then will remove all the rows that have null value as they may mess our visual work.
euro_to_dollar = exchange_rates[['time','us_dollar']].copy()
before = euro_to_dollar.shape
euro_to_dollar.dropna(inplace = True)
after = euro_to_dollar.shape
error = (before[0] - after[0])/before[0]
print("error rate: ", error *100)
error rate: 1.0879101596771363
plt.plot(euro_to_dollar['time'],
euro_to_dollar['us_dollar'])
plt.show()
Looking at this chart, currently we can see there is alot of noise hence huge amount of wiggles instead of the usual smooth line. To get a much smoother line that provides us with better view of the long term trend, we can use the rolling mean method that is built in pandas.
The rolling window can take various values — some common values include:
To learn more about rolling mean read this article.
I will take several rolling mean to see comparison as we increase the number of days.
euro_to_dollar['7_days'] = euro_to_dollar['us_dollar'].rolling(7).mean()
euro_to_dollar['30_days'] = euro_to_dollar['us_dollar'].rolling(30).mean()
euro_to_dollar['60_days'] = euro_to_dollar['us_dollar'].rolling(60).mean()
euro_to_dollar['120_days'] = euro_to_dollar['us_dollar'].rolling(120).mean()
euro_to_dollar['365_days'] = euro_to_dollar['us_dollar'].rolling(365).mean()
euro_to_dollar.head(7)
time | us_dollar | 7_days | 30_days | 60_days | 120_days | 365_days | |
---|---|---|---|---|---|---|---|
0 | 1999-01-04 | 1.1789 | NaN | NaN | NaN | NaN | NaN |
1 | 1999-01-05 | 1.1790 | NaN | NaN | NaN | NaN | NaN |
2 | 1999-01-06 | 1.1743 | NaN | NaN | NaN | NaN | NaN |
3 | 1999-01-07 | 1.1632 | NaN | NaN | NaN | NaN | NaN |
4 | 1999-01-08 | 1.1659 | NaN | NaN | NaN | NaN | NaN |
5 | 1999-01-11 | 1.1569 | NaN | NaN | NaN | NaN | NaN |
6 | 1999-01-12 | 1.1520 | 1.167171 | NaN | NaN | NaN | NaN |
euro_to_dollar.tail()
time | us_dollar | 7_days | 30_days | 60_days | 120_days | 365_days | |
---|---|---|---|---|---|---|---|
5694 | 2021-01-04 | 1.2296 | 1.224071 | 1.211170 | 1.195167 | 1.186142 | 1.132095 |
5695 | 2021-01-05 | 1.2271 | 1.225571 | 1.212530 | 1.195960 | 1.186844 | 1.132433 |
5696 | 2021-01-06 | 1.2338 | 1.227643 | 1.213987 | 1.196858 | 1.187586 | 1.132771 |
5697 | 2021-01-07 | 1.2276 | 1.228457 | 1.215357 | 1.197673 | 1.188280 | 1.133070 |
5698 | 2021-01-08 | 1.2250 | 1.228329 | 1.216557 | 1.198507 | 1.188840 | 1.133362 |
# create the fig and ax
style.use('ggplot')
fig, ax = plt.subplots(2,3,figsize=(22, 12))
# set x as the time period is the same
x = euro_to_dollar['time']
i = 1
for c in list(euro_to_dollar.columns)[1:]:
plt.subplot(2,3,i)
plt.plot(x,euro_to_dollar[c])
# use the column name as title
if c == 'us_dollar':
plt.title('Original Values')
# add one to i for the next subplot
i += 1
else:
plt.title(c.lower().replace('_',' ')+' Rolling Mean')
i += 1
Now looking at each chart one by one we can see the lines get smoother as we increase the number of days, this creates less noise and much smoother chart.
Lets look deeper at the charts and explore the currency when different presental changes happen. How the euro-dollar rate changed under the last 4 US presidents:
Although the data only goes back to 1999, I am still curious to see the end period of Bill Clinton for euro and usa conversion rate.
In addition, I will add 4 major events label from 1999 to 2021 that could influence the exchange rates.
Lastly, I will use the 120 rolling average as I am interested to see the conversion for every quarter. This can give us good enough indication of the trend reduce alot noise.
euro_to_dollar_120_days = euro_to_dollar[['time','120_days']].copy()
Based on the year we need to add the president column that has the current president in that period
Will import datetime library and create several datetime object based on the president final year.
import datetime
clinton_end = datetime.datetime(2001,1,1).year
bush_end = datetime.datetime(2009,1,1).year
obama_end = datetime.datetime(2017,1,1).year
#create empty column
euro_to_dollar_120_days['president'] = np.nan
euro_to_dollar_120_days.head()
time | 120_days | president | |
---|---|---|---|
0 | 1999-01-04 | NaN | NaN |
1 | 1999-01-05 | NaN | NaN |
2 | 1999-01-06 | NaN | NaN |
3 | 1999-01-07 | NaN | NaN |
4 | 1999-01-08 | NaN | NaN |
WIll add the president name based on the year.
This will be done by creating different subsets of the dataframe and then finally concatenating them together. The end result should have the exact shape as before.
#clinton
clinton_condition = (euro_to_dollar_120_days.time.dt.year < clinton_end)
clinton_df = euro_to_dollar_120_days[clinton_condition].copy()
clinton_df['president'] = clinton_df['president'].fillna('clinton')
#bush
bush_condition_1 = (euro_to_dollar_120_days.time.dt.year < bush_end)
bush_condition_2 = (euro_to_dollar_120_days.time.dt.year >= clinton_end)
#filter the data based on multiple conditions
bush_df = euro_to_dollar_120_days[(bush_condition_1) & (bush_condition_2)].copy()
bush_df['president'] = bush_df['president'].fillna('bush')
#obama
obama_condition_1 = (euro_to_dollar_120_days.time.dt.year < obama_end)
obama_condition_2 = (euro_to_dollar_120_days.time.dt.year >= bush_end)
#filter the data based on multiple conditions
obama_df = euro_to_dollar_120_days[(obama_condition_1) & (obama_condition_2)].copy()
obama_df['president'] = obama_df['president'].fillna('obama')
#obama
trump_condition = (euro_to_dollar_120_days.time.dt.year >= obama_end)
trump_df = euro_to_dollar_120_days[trump_condition].copy()
trump_df['president'] = trump_df['president'].fillna('trump')
We will concatanate all 4 df into one, the shape should be the same as the original.
So we will do a quick check to make sure everything went correctly
final = pd.concat([clinton_df,bush_df,obama_df,trump_df], axis = 0)
#check nothing missing
if final.shape == euro_to_dollar_120_days.shape:
print("no error")
else:
print("error")
no error
final.head()
time | 120_days | president | |
---|---|---|---|
0 | 1999-01-04 | NaN | clinton |
1 | 1999-01-05 | NaN | clinton |
2 | 1999-01-06 | NaN | clinton |
3 | 1999-01-07 | NaN | clinton |
4 | 1999-01-08 | NaN | clinton |
Here we can see each colour represent the different terms of the president. However, we don't know which color represent which presidents and the color scheme isn't great. Furthermore, we want to add titles and few styles to the plot.
For presidents that was Democrats will keep them close to red color, while the Repbulic will be close to blue color.
# map each president by a specific color
presidents = ['clinton','bush','obama','trump',]
color_map = {'clinton': 'firebrick', 'bush':'navy', 'obama': 'red' , 'trump':'blue'}
I will create the final chart as a mentioned above will have different color indicating the different presidents who was running the USA. In addition I will add 4 key events that is worth pointing out that could infer any changes, you will see it thanks to the plt.arrow(). This function allows us to create black vertical line so you can see where the event happen within the chart.
Within the chart I will remove grid lines (ticks) and limit the x and y co-ordinate so there is less unnecessary wasted space. Then I will use ax.text to create a title and a subtitle about the chart.
# select the style you want
style.use('ggplot')
# create the fig and ax
fig, ax = plt.subplots(figsize=(12, 8))
#plot each president term seperately
# same figure
for p in presidents:
plot_df = final[final['president'] == p]
ax.plot(plot_df['time'], plot_df['120_days'],color = color_map[p])
#get the first x coordiante
x_one = final.time[0:1]
x_one
'''Get the x coordinate from the first row of dataframe.
So we can position the chart far left and remove any unnecessary space.'''
#set limit
ax.set_xlim(xmin = x_one)
ax.set_ylim(ymin = 0.83 , ymax = 1.7)
#position of x-cordinate for text
#offset to move the x corrdinate 60 days to left
txt_x = x_one + pd.DateOffset(days=60)
#add title & subtitle
# use weight to create style on the word
ax.text(txt_x, 1.673,
'Euro To USD Conversion Since January 1999 to January 2021',
size=17, weight='bold', backgroundcolor = '#F8F8FF')
ax.text(txt_x, 1.64,
'120 Day Moving Avg exchange rate under Bill Clinton (1993-2001), George.W Bush (2001-2009),',
backgroundcolor = '#F8F8FF')
ax.text(txt_x, 1.605,
'Barack Obama (2009-2017) and Donald Trump (2017-2021).', backgroundcolor = '#F8F8FF')
#remove ticks
ax.grid(b=False)
'''Adding events'''
#event 1
#get x-corrdinate of arrow
event_a = datetime.datetime(2001,9,11)
#get y-corrdinate of arrow
# iat access single value
event_a_y = final.loc[final.time == event_a,'120_days'].iat[0]
#0.3 thinkness of the arrow
plt.arrow(event_a, event_a_y,
0.3, 0.15, color = 'black')
ax.text(event_a- pd.DateOffset(months=15),
event_a_y+0.16,'9/11 Bombing',
weight = 'bold',
size = 8,
backgroundcolor = '#eaeaea')
#event 2
event_b = datetime.datetime(2007,1,2)
event_b_y = final.loc[final.time == event_b,'120_days'].iat[0]
plt.arrow(event_b, event_b_y,
0.3, 0.2, color = 'black')
event_c = datetime.datetime(2009,1,2)
event_c_y = final.loc[final.time == event_c,'120_days'].iat[0]
plt.arrow(event_c, event_c_y,
0.3, 0.08, color = 'black')
ax.text(event_c- pd.DateOffset(months=25),
event_c_y+0.08,'Financial Crisis',
weight = 'bold',
size = 8,
backgroundcolor = '#eaeaea')
#event 3
#get x-corrdinate of arrow
event_d = datetime.datetime(2016,6,23)
#get y-corrdinate of arrow
event_d_y = final.loc[final.time == event_d,'120_days'].iat[0]
plt.arrow(event_d, event_d_y,
0.3, 0.15, color = 'black')
ax.text(event_d- pd.DateOffset(months=13),
event_d_y+0.16,'Brexit Annouced',
weight = 'bold',
size = 8,
backgroundcolor = '#eaeaea')
#event 4
event_e = datetime.datetime(2020,3,19)
#get y-corrdinate of arrow
event_e_y = final.loc[final.time == event_e,'120_days'].iat[0]
plt.arrow(event_e, event_e_y,
0.3, 0.15, color = 'black')
ax.text(event_e- pd.DateOffset(months=20),
event_e_y+0.16,'Covid First Lockdown',
weight = 'bold',
size = 8,
backgroundcolor = '#eaeaea')
# add legends
x_legend = datetime.datetime(2020,5,30)
legend_position = {'clinton': 1.6, 'bush':1.56, 'obama': 1.58 , 'trump':1.54}
for p in presidents:
ax.text(x_legend, legend_position[p],p, size = 10.5)
ax.axhline(legend_position[p]+0.01, c=color_map[p], linewidth=1 ,xmin = 0.86, xmax = 0.92)
#finally save your image
plt.savefig("Euro To Dollar 120 MA Annotated.png",bbox_inches='tight')
plt.show()
Now our chart looks complete with a clear breakdown which president was running the correct during specific period. Furthermore, we can see the 4 key worldwide events between 1999-2021 that I think could of effect the euro to dollar conversion.
I could add more but this will make the chart very clutter and would provide an overload on information.
Several things we can see: