The currency exchange market has been around since coins were first used. At the end of the 1800s the development of the gold standard fixed currency values to a certain amount of gold, allowing for an internationally stable monetary system (1). Eventually the amount of gold was not enough to keep up with the demand for currency. After World War II the Bretton Woods Accord set the US Dollar as the global fixed currency. This was an adjustable rate, but still determined by central banks and state actors (2). The US dollar was pegged to gold at the time, but during the 1970s the same problem occurred with the dollar. In August of 1971 President Richard Nixon unilaterally canceled direct international convertability of the US dollar to gold, inadvertently beginning a regime of free-floating currencies (3).
The modern foreign exchange market (also called Forex, FX, or currency market) is a direct broker to dealer global marketplace that determines the market value and exchange rate of currencies all over the world. It is open 24 hours a day, 5 days a week. Currencies are always traded in pairs, and the value expressed is of one currency relative to another. For example, at the end of the day on 11/19/21 the Euro to US dollar rate was 1.13, or $1.13 equals €1. All of the twenty most traded currencies are free-floating, their value is determined by political conditions, economic factors and market psychology.
Forex is by far the largest financial market in the world, in 2019 having a daily volume of over $6.6 trillion (4). The Euro to US dollar (EURUSD) is the most traded currency pair, taking about 30% of the multi-billion dollar Forex turnover (5).
This study examines the volatility of the value of the Euro to eight other currencies. It uses the 2019 Triennial Central Bank Survey by the Bank for International Settlements to determine four currencies that represent large portions of the market and four currencies that represent small portions of the market. The highly traded currencies are the US dollar, Japanese yen, UK pound, and Australian dollar. The Israeli shekel, Phillipine peso, Malaysian ringgit, and Romanian leu comprise the group of least traded currencies.
The data set used is based on daily closing values provided by the European Central Bank and compiled by Daria Chemkaeva. It is updated weekly, the version used for this study was downloaded from Kaggle in November 2021.
Text with conclusion.
The first steps are to import the basic libraries, open the file, and take an initial look at the dataset.
# import libraries and set display options
import pandas as pd
import pprint
pd.options.display.float_format = '{:20,.4f}'.format
pd.set_option('display.max_rows', None)
pd.set_option('display.max_columns', None)
pd.set_option('display.width', 1000)
pd.set_option('display.colheader_justify', 'center')
pd.set_option('display.precision', 3)
# open file
x_rates = pd.read_csv("euro-daily-hist_1999_2020.csv")
# head, tail, and basic info
display(x_rates.head())
display(x_rates.tail())
display(x_rates.info())
Period\Unit: | [Australian dollar ] | [Bulgarian lev ] | [Brazilian real ] | [Canadian dollar ] | [Swiss franc ] | [Chinese yuan renminbi ] | [Cypriot pound ] | [Czech koruna ] | [Danish krone ] | [Estonian kroon ] | [UK pound sterling ] | [Greek drachma ] | [Hong Kong dollar ] | [Croatian kuna ] | [Hungarian forint ] | [Indonesian rupiah ] | [Israeli shekel ] | [Indian rupee ] | [Iceland krona ] | [Japanese yen ] | [Korean won ] | [Lithuanian litas ] | [Latvian lats ] | [Maltese lira ] | [Mexican peso ] | [Malaysian ringgit ] | [Norwegian krone ] | [New Zealand dollar ] | [Philippine peso ] | [Polish zloty ] | [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 | NaN | 0.90128 | NaN | 9.4982 | 7.5690 | 359.62 | 17247.33 | 3.8981 | 89.7975 | 155.5000 | 127.26 | 1337.90 | NaN | NaN | NaN | 24.4718 | 4.9359 | 10.2863 | 1.6883 | 58.947 | 4.5113 | 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 | NaN | 0.90190 | NaN | 9.5176 | 7.5660 | 357.79 | 17259.99 | 3.9027 | 90.0455 | 155.3000 | 127.13 | 1342.29 | NaN | NaN | NaN | 24.2552 | 4.9570 | 10.3435 | 1.6907 | 59.043 | 4.4998 | 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 | NaN | 0.90635 | NaN | 9.5659 | 7.5595 | 357.86 | 17168.20 | 3.9289 | 90.2040 | 156.3000 | 127.03 | 1339.30 | NaN | NaN | NaN | 24.3543 | 4.9482 | 10.3810 | 1.6916 | 59.296 | 4.5160 | 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 | NaN | 0.90333 | NaN | 9.5136 | 7.5588 | 360.27 | 17075.10 | 3.9277 | 89.8670 | 156.1000 | 126.25 | 1335.85 | NaN | NaN | NaN | 24.5860 | 4.9293 | 10.4713 | 1.7036 | 59.020 | 4.5473 | 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 | NaN | 0.90160 | NaN | 9.5330 | 7.5565 | 361.32 | 17062.67 | 3.9430 | 89.7890 | 156.1000 | 126.62 | 1332.03 | NaN | NaN | NaN | 24.3031 | 4.9264 | 10.4440 | 1.7065 | 59.058 | 4.5475 | 4.8713 | 90.3420 | 10.0895 | 1.6198 | NaN | NaN | 36.7280 | 9.0579 | 1.2296 | 17.9214 |
Period\Unit: | [Australian dollar ] | [Bulgarian lev ] | [Brazilian real ] | [Canadian dollar ] | [Swiss franc ] | [Chinese yuan renminbi ] | [Cypriot pound ] | [Czech koruna ] | [Danish krone ] | [Estonian kroon ] | [UK pound sterling ] | [Greek drachma ] | [Hong Kong dollar ] | [Croatian kuna ] | [Hungarian forint ] | [Indonesian rupiah ] | [Israeli shekel ] | [Indian rupee ] | [Iceland krona ] | [Japanese yen ] | [Korean won ] | [Lithuanian litas ] | [Latvian lats ] | [Maltese lira ] | [Mexican peso ] | [Malaysian ringgit ] | [Norwegian krone ] | [New Zealand dollar ] | [Philippine peso ] | [Polish zloty ] | [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 | 15.6466 | 0.70940 | 324.00 | 9.0302 | NaN | 250.15 | 9321.63 | NaN | NaN | 80.9900 | 130.09 | 1366.73 | 4.66430 | 0.6654 | 0.4419 | 11.4414 | 4.4295 | 8.5900 | 2.1557 | 44.295 | 4.0363 | 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 | 15.6466 | 0.70585 | 324.40 | 9.0131 | NaN | 250.09 | 9218.77 | NaN | NaN | 81.0600 | 129.43 | 1337.16 | 4.65480 | 0.6627 | 0.4413 | 11.5511 | 4.4203 | 8.6295 | 2.1531 | 44.436 | 4.0165 | 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 | 15.6466 | 0.70760 | 324.72 | 9.1010 | NaN | 250.67 | 9337.68 | NaN | NaN | 81.5400 | 131.42 | 1359.54 | 4.69940 | 0.6649 | 0.4420 | 11.4705 | 4.4637 | 8.7335 | 2.1890 | 44.872 | 4.0065 | 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 | 15.6466 | 0.71220 | 324.70 | 9.1341 | NaN | 250.80 | 9314.51 | NaN | NaN | 81.5300 | 130.96 | 1373.01 | 4.71740 | 0.6657 | 0.4432 | 11.5960 | 4.4805 | 8.7745 | 2.2011 | 44.745 | 4.0245 | 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 | 15.6466 | 0.71110 | 327.15 | 9.1332 | NaN | 251.48 | 9433.61 | NaN | NaN | 81.4800 | 133.73 | 1398.59 | 4.71700 | 0.6668 | 0.4432 | 11.6446 | 4.4798 | 8.8550 | 2.2229 | 45.510 | 4.0712 | 1.3111 | 25.2875 | 9.4696 | 1.9554 | 189.0450 | 42.991 | 42.6799 | 0.3723 | 1.1789 | 6.9358 |
<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
None
The dataset covers the time period from January 1999 to January 2021. It has 5699 rows and 41 columns. Some of these columns have less than half the number of entries as other columns. In the original data set, cells with missing entries have a hyphen (-). This causes problems with a lot of the functions that will be used. For the time being the hyphens will be converted to the value NaN
, which preserves the row of information.
The first steps will be:
datetime
data type# strip brackets and trailing space from country names
# replace remaining space with underscore
x_rates.columns = x_rates.columns.str.replace("[","").str.replace("]","")
x_rates.columns = x_rates.columns.str.rstrip()
x_rates.columns = x_rates.columns.str.replace(" ","_")
# rename columns
x_rates.rename(columns={"Period\\Unit:":"Date",
"Chinese_yuan_renminbi":"Chinese_yuan",
"UK_pound_sterling":"UK_pound"}, inplace=True)
# convert datetime
x_rates["Date"] = pd.to_datetime(x_rates["Date"])
# resort and reindex
x_rates.sort_values("Date", inplace=True)
x_rates.reset_index(drop=True, inplace=True)
# convert hyphens in currency columns to NaN
import numpy as np
x_rates = x_rates.replace("-", np.nan)
# convert exchange rate values to float
x_rates.iloc[:,1:] = x_rates.iloc[:,1:].astype(float)
/var/folders/bz/5cj1tzbj5xn319rpqrw6gpmh0000gn/T/ipykernel_18137/3201399205.py:3: FutureWarning: The default value of regex will change from True to False in a future version. In addition, single character regular expressions will *not* be treated as literal strings when regex=True. x_rates.columns = x_rates.columns.str.replace("[","").str.replace("]","")
The change in the Euro exchange rate over time can be visualized in a line graph. The US dollar is the first currency to be examined.
# create a euro to dollar dataframe and add 30 day rolling mean column
us_dollar = x_rates[["Date","US_dollar"]].copy()
us_dollar["rolling_mean_30"] = us_dollar["US_dollar"].rolling(30).mean()
# line graph for euro to dollar exchange rate
import matplotlib.pyplot as plt
%matplotlib inline
plt.plot(us_dollar["Date"], us_dollar["rolling_mean_30"])
plt.show()
# create nan group and get dates
nan_dollar_group = us_dollar[us_dollar["US_dollar"].isnull()]
nan_days = nan_dollar_group["Date"]
# line graph showing 30 day rolling mean with and without vertical bars representing null days
plt.figure(figsize=(10,3.75))
plt.subplot(1,2,1)
plt.plot(us_dollar["Date"], us_dollar["rolling_mean_30"])
plt.yticks([])
plt.subplot(1,2,2)
plt.plot(us_dollar["Date"], us_dollar["rolling_mean_30"])
plt.yticks([])
for xc in nan_days:
plt.axvline(x=xc, color="lightcyan")
plt.suptitle("Euro to US dollar exchange rates, dataset w/ NaN values and corresponding dates in light blue")
plt.show()
# create a dollar to euro dataframe with NaN dates removed
US_dollar_nonull = x_rates[x_rates["US_dollar"].notna()].copy()
US_dollar_nonull["rolling_mean_30"] = US_dollar_nonull["US_dollar"].rolling(30).mean()
# line graph showing 30 day rolling mean with and without NaN dates
plt.figure(figsize=(10,3.75))
plt.subplot(1,2,1)
plt.plot(us_dollar["Date"], us_dollar["rolling_mean_30"])
plt.yticks([])
plt.subplot(1,2,2)
plt.plot(US_dollar_nonull["Date"], US_dollar_nonull["rolling_mean_30"])
plt.yticks([])
plt.suptitle("Euro to US dollar exchange rates, with NaN dates and corresponding dates removed")
plt.show()
The line graph shows that the exchange rate between the Euro and US dollar is highly variable. There are also a lot of gaps in the graph. These represent points in the data frame where information for a particular day is missing. The third chart shows vertical blue stripes for all dates with missing information. These correspond perfectly with the gaps in the original chart. One option is to remove all the missing rows. The final chart, with these rows removed, appears to be good match and is easier to look at. All further currency data frames will be handled the same.
The line graphs represent the exchange rates for the Euro to the US dollar, Japanese yen, UK pound, and Australian dollar. These four currencies, in addition to the Euro, are the top five currenceis in the Forex market. All five together comprise over 75% of daily trades (4).
column_names = list(x_rates)
column_names = column_names[1:]
# us_dollar = x_rates[["Date","US_dollar"]].copy()
# us_dollar["rolling_mean_30"] = us_dollar["US_dollar"].rolling(30).mean()
# def rounder(element):
# element = element
# rf = x_rates
# rf.tail()
# function to build data frame for Euro to other half of trading pair
xchange_list = []
def xchange(column):
xchange_list.append(column)
dataset = x_rates[["Date",column]].copy()
dataset = dataset[dataset[column].notna()]
dataset["rolling_mean_30"] = dataset[column].rolling(30).mean()
return dataset
# is there a way to apply this function to all the columns in x_rates?
# one drawback would be having 42 data frames
# but I don't know how else to deal with NaN cells being different for each currency
# i should see if there's a way to add the rolling mean column for each currency
# calling xchange function on four highly traded currencies
us_dollar = xchange("US_dollar")
japanese_yen = xchange("Japanese_yen")
uk_pound = xchange("UK_pound")
australian_dollar = xchange("Australian_dollar")
# line graph showing Euro to each trading pair
plt.figure(figsize=(10,7.5))
plt.subplot(2,2,1)
plt.plot(us_dollar["Date"], us_dollar["rolling_mean_30"])
plt.title("Euro to US dollar")
plt.yticks([])
plt.subplot(2,2,2)
plt.plot(japanese_yen["Date"], japanese_yen["rolling_mean_30"])
plt.title("Euro to Japanese yen")
plt.yticks([])
plt.subplot(2,2,3)
plt.plot(uk_pound["Date"], uk_pound["rolling_mean_30"])
plt.title("Euro to UK pound")
plt.yticks([])
plt.subplot(2,2,4)
plt.plot(australian_dollar["Date"], australian_dollar["rolling_mean_30"])
plt.title("Euro to Australian dollar")
plt.yticks([])
plt.subplots_adjust(hspace=0.3)
plt.show()
# with less code?
# plt.figure(figsize=(10,7.5))
# for i in range(1, 5):
# plt.subplot(2,2,i)
# plt.show()
stuff stuff
The line graphs represent the exchange rates for the Euro to the Israeli shekel, Philippine peso, Malaysian ringgit, and Romanian leu. These four currencies have low trade volumes, all five together comprise less than 0.4% of daily trades (4).
# calling xchange function on four least traded currencies
israeli_shekel = xchange("Israeli_shekel")
philippine_peso = xchange("Philippine_peso")
malaysian_ringgit = xchange("Malaysian_ringgit")
romanian_leu = xchange("Romanian_leu")
# line graph showing Euro to each trading pair
plt.figure(figsize=(10,7.5))
plt.subplot(2,2,1)
plt.plot(israeli_shekel["Date"], israeli_shekel["rolling_mean_30"])
plt.title("Euro to Israeli shekel")
plt.yticks([])
plt.subplot(2,2,2)
plt.plot(philippine_peso["Date"], philippine_peso["rolling_mean_30"])
plt.title("Euro to Philippine peso")
plt.yticks([])
plt.subplot(2,2,3)
plt.plot(malaysian_ringgit["Date"], malaysian_ringgit["rolling_mean_30"])
plt.title("Euro to Malaysian ringgit")
plt.yticks([])
plt.subplot(2,2,4)
plt.plot(romanian_leu["Date"], romanian_leu["rolling_mean_30"])
plt.title("Euro to Romanian leu")
plt.yticks([])
plt.subplots_adjust(hspace=0.3)
plt.show()
Israeli shekel and Philppine peso both appear to be increasing in value and the Romanian leu is definitely loosing value. The shekel and leu also appear to be fairly stable, or have low volatility. Determining volatility of the eight currencies for the past two decades illustrates part of the story of the twenty-first century.
stuff
# function to get log of daily rate
def logarizer(dataset):
dataset["log_rate"] = np.log(dataset.iloc[:,1]/dataset.iloc[:,1].shift()) # getting the log of the exchange rate
return dataset["log_rate"]
# function to get overall volatility
volatility_dict = {}
def volatizer(dataset):
column_headers = list(dataset.columns.values)
currency_name = column_headers[1]
volatility = dataset["log_rate"].std()*253**.5 # volatility measured by standard deviation * 253 trading days per year
volatility = round(volatility, 4)*100
volatility_dict[currency_name] = volatility
# it would be cool to convert or use xchange_list
# i didn't really think .replace would work
# currency_list = []
# for currency in xchange_list:
# currency = currency.replace("'","").lower()
# currency_list.append(currency)
# currency_list
# ['us_dollar',
# 'japanese_yen',
# 'uk_pound',
# 'australian_dollar',
# 'israeli_shekel',
# 'philippine_peso',
# 'malaysian_ringgit',
# 'romanian_leu']
# calling logarizer on all eight currencies
c_list = [us_dollar, japanese_yen, uk_pound, australian_dollar,
israeli_shekel, philippine_peso, malaysian_ringgit, romanian_leu]
for currency in c_list:
logarizer(currency)
# calling volatizer on all eight currencies
for currency in c_list:
volatizer(currency)
# line graph showing log exchange rates of each currency
plt.figure(figsize=(10,14))
for i, currency in zip(range(1,9), c_list):
plt.subplot(4,2,i)
currency["log_rate"].plot.hist(bins=50)
# plt.title(currency) # will get ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
plt.show()
# plt.title("Romanian volatility: " + str(romanian_leu["volatility"]) + "%")
volatility_dict
{'US_dollar': 9.66, 'Japanese_yen': 11.74, 'UK_pound': 8.110000000000001, 'Australian_dollar': 10.56, 'Israeli_shekel': 9.83, 'Philippine_peso': 10.57, 'Malaysian_ringgit': 9.47, 'Romanian_leu': 8.16}
# import geopandas and other libraries
import geopandas as gpd
import seaborn as sns
import os
map_data = gpd.read_file("World_Countries__Generalized_.shp")
map_data["Volatility"] = None
map_data.head()
map_data.shape
# map_data.plot(figsize=(15,13))
# map_data[map_data["COUNTRY"] == "United States"].plot(color = "green")
(249, 9)