# Authors: Sarah Abdelazim, Markus Nam, Crystal Geng, Lennon Au-Yeung
# Date: January, 2023
# import pandas_datareader as pdr
import yfinance as yf
import altair as alt
from yfinance import shared
import datetime
alt.renderers.enable('mimetype')
[docs]def fx_rate_lookup(curr, target_px):
"""
Return the most recent date on which
the target price happend.
i.e. the target price was between day high
and day low of the day.
Parameters
----------
curr : string
Ticker of the currency pair such as 'EURUSD'.
target_px : float
Target price for the lookup.
Returns
--------
date: string
The most recent date in YYYY-MM-DD on which the target
price happened. i.e. the target price was between day high
and day low of that day.
Examples
--------
>>> fx_rate_lookup('EURUSD', 1.072)
'2023-01-10'
"""
# check input type of curr
if not isinstance(curr, str):
raise TypeError("curr needs to be of str type.")
# Check input type of target_px
if not isinstance(target_px, (int, float)):
raise TypeError("target_px needs to be a number.")
df = yf.download(curr + '=X', progress=False, show_errors=False)
if len(df) == 0:
raise Exception('No data found from data source. Check your ticker.')
# To check if the input price is within the High and Low of any previous
# days.
myquery = 'High >= ' + str(target_px) + 'and Low <= ' + str(target_px)
mydates = df.query(myquery).index.format(
formatter=lambda x: x.strftime('%Y-%m-%d'))
# Found, return the latest one (closest to the query date)
if len(mydates) > 0:
return mydates[-1]
else:
raise Exception('Target price not found. Adjust your target price.')
[docs]def pl_trend_viz(curr, start_date, end_date, chart_type):
"""
Visualizes trend of the profit and loss of a
currency pair between the selected start date and end date.
Parameters
----------
curr : string
Ticker of the currency pair such as 'EURUSD'
start_date : string
Start date of the selected period of time
end_date : string
End date of the selected period of time
chart_type: string
Type of visulization
Returns
--------
Line plot that shows the trend of the profit and
loss of a currency pair over the selected period of time
Examples
--------
>>> pl_trend_viz('EURUSD', '2018-12-31', '2022-12-31','line')
"""
shared._ERRORS = {}
# check input type of curr
if not isinstance(curr, str):
raise TypeError("curr needs to be of str type.")
curr_X = curr + '=X'
# Check input type of start_date
if not isinstance(start_date, str):
raise TypeError("start_date needs to be of str type.")
# Check input type of end_date
if not isinstance(end_date, str):
raise TypeError("end_date needs to be of str type.")
# Check type of visulization
if chart_type not in ['line', 'area']:
raise ValueError(
"Your option of plotting should be from 'line' or 'area'")
# Assert end date is later than start date
format = "%Y-%m-%d"
if (datetime.datetime.strptime(end_date, format)
< datetime.datetime.strptime(start_date, format)):
raise ValueError(
"The end date is earlier than the start date! Try again.")
data = yf.download(curr_X, start_date, end_date)
if (curr_X in shared._ERRORS and
'symbol may be delisted' in shared._ERRORS[curr_X]):
raise NameError(
"You have entered an invalid foreign ticker! Try again.")
drop = {'Open', 'High', 'Low', 'Adj Close', 'Volume'}
data = data.drop(columns=drop)
for i in range(1, len(data)):
data.iloc[i, :] = round(
(data.iloc[i, :] - data.iloc[0, :]) / data.iloc[0, :], 3)
data.iloc[0, :] = round(
(data.iloc[0, :] - data.iloc[0, :]) / data.iloc[0, :], 3)
data = data.rename(columns={"Close": "Percentage Change"})
title = 'Profit and loss trend over time for currency ' + curr
if chart_type == 'line':
chart = alt.Chart(data.reset_index(), title=title).mark_line().encode(
x=alt.X('Date'),
y=alt.Y('Percentage Change', axis=alt.Axis(format='%')),
tooltip=alt.Tooltip('Percentage Change', format='.2%')
)
else:
chart = alt.Chart(data.reset_index(), title=title).mark_area().encode(
x=alt.X('Date'),
y=alt.Y('Percentage Change', axis=alt.Axis(format='%')),
tooltip=alt.Tooltip('Percentage Change', format='.2%')
)
# chart.show()
return chart
[docs]def price_trend_viz(curr, start_date, end_date, option):
"""
Visualizes trend of the exchange rate of a
currency pair between the selected start date and end date.
Parameters
----------
curr : string
Ticker of the currency pair such as 'EURUSD'
start_date : string
Start date of the selected period of time
end_date : string
End date of the selected period of time
option: string
A choice of option from ['Open', 'High', 'Low', 'Close']
Returns
--------
Line plot that shows the trend of the exchange rate of
a currency pair over the selected period of time
Examples
--------
>>> price_trend_viz('EURUSD', '2018-12-31', '2022-12-31')
"""
# Check input type of curr
if not isinstance(curr, str):
raise TypeError("curr needs to be of str type.")
# Check input type of start_date
if not isinstance(start_date, str):
raise TypeError("start_date needs to be of str type.")
# Check input type of end_date
if not isinstance(end_date, str):
raise TypeError("end_date needs to be of str type.")
if option not in ['Open', 'High', 'Low', 'Close']:
raise Exception(
"Your option of plotting should be "
"from 'Open', 'High', 'Low' or 'Close'")
# Check if the end date entered is later than 2003-12-01
if (datetime.datetime.strptime(end_date, "%Y-%m-%d")
< datetime.datetime.strptime('2003-12-01', "%Y-%m-%d")):
raise Exception("No data exists before 2003-12-01, please try again.")
# Check if the start date entered is earlier than or equal to today
if (datetime.datetime.strptime(start_date, "%Y-%m-%d")
> datetime.datetime.today()):
raise Exception(
"You entered a start date later than today, please try again.")
curr_X = curr + '=X'
data = yf.download(curr_X, start_date, end_date, progress=False)
# Raise an exception if the data downloaded has emtpy content
if len(data) == 0:
raise Exception(
'No data found from data source. Check your ticker and date.')
line_1 = f"Trend of Exchange Rate (Daily {option})"
line_2 = f" of {curr} from {start_date} to {end_date}"
trend_plot = alt.Chart(
data.reset_index(),
title=line_1+line_2
).mark_line(
).encode(
x=alt.X('Date', axis=alt.Axis(format=("%Y-%m-%d"))),
y=alt.Y(option, title='Exchange Rate', scale=alt.Scale(zero=False)),
tooltip=alt.Tooltip(option, format='.2%')
).properties(height=400, width=600
).configure_axis(
labelFontSize=14,
titleFontSize=15
).configure_title(
fontSize=16)
# trend_plot.show()
return trend_plot
[docs]def fx_conversion(curr1, curr2, amt):
"""
Converts a specific amount of money from current
currency (curr1) to desired currency (curr2)
Parameters
----------
curr1 : string
Ticker of the current currency such as 'EUR'
curr2 : string
Ticker of the desired currency to convert to such as 'USD'
amt : int or float
amount of money to be converted
Returns
--------
Amount of value converted from currency 1 to currency 2
Examples
--------
>>> fx_conversion('EUR', 'USD', 150.75)
"""
shared._ERRORS = {}
# Tests
# Check input type of curr1
if not isinstance(curr1, str):
raise TypeError(
"Ticker of the current currency needs to be of str type.")
# Check input type of curr1
if not isinstance(curr2, str):
raise TypeError(
"Ticker of the desired currency needs to be of str type.")
# Check input type of amt
if not isinstance(amt, (int, float)):
raise TypeError(
"Amount of money to be converted needs to be a number.")
curr_pair = curr1 + curr2 + '=X'
data = yf.download(
curr_pair,
interval='1m',
progress=False,
show_errors=False)
# Check for invalid ticker name
if (curr_pair in shared._ERRORS and
'symbol may be delisted' in shared._ERRORS[curr_pair]):
raise NameError(
"You have entered an invalid foreign ticker! Try again.")
conversion_rate = data['Close'].iloc[-1]
converted_value = amt * conversion_rate
return converted_value