In the first part of this project article, we created a currency converter app. We designed it in such a way that the user will enter his or her API key, base and target currency, plus the amount. Once the convert button is clicked, the conversion amount is displayed.
If you can recall, in the concluding part of the article, I told you guys that I will add a Machine Learning prediction feature to predict the next day currency rates. It will be a nice addition to our currency converter app. That is exactly what we are going to learn in this tutorial.

For this second part, we will use the Yahoo Finance API to fetch data of a currency pair for a given period. We will do something that is somehow similar to what we did while building a Gold price prediction app.
I recommend you go through the first part before attempting this project so you can understand how we arrived at where we are in this project.
Downloading the data

We will use Euro and US Dollar currency pair as an example. Then, we fetch data from 2008 to date.
import datetime import yfinance as yf import pandas as pd df = yf.download('EURUSD=X', start='2008-01-01', end=datetime.date.today(), progress=False) df.head()
Open High Low Close Adj Close Volume Date 2008-01-01 1.460110 1.462994 1.458194 1.462010 1.462010 0 2008-01-02 1.462309 1.474296 1.460110 1.471692 1.471692 0 2008-01-03 1.471692 1.477891 1.469400 1.474491 1.474491 0 2008-01-04 1.474709 1.481811 1.469896 1.475492 1.475492 0 2008-01-07 1.475209 1.475209 1.466706 1.468299 1.468299 0
The data has six columns. We are only interested in the Close
column which is the closing price at the end of each trading day.
data = df[['Close']]
Feature Engineering

Letβs add some features that will help improve the modelβs performance. First is the rolling means. This helps the model evaluate the current prices against weekly, monthly, quarterly, or annual average prices.
import warnings warnings.filterwarnings('ignore') weekly_mean = data.Close.rolling(7).mean() monthly_mean = data.Close.rolling(30).mean() quarterly_mean = data.Close.rolling(90).mean() yearly_mean = data.Close.rolling(365).mean()
We then find the ratios of these variables to the Close price and add them to the DataFrame.
data['weekly_mean'] = weekly_mean / data.Close data['monthly_mean'] = monthly_mean / data.Close data['quarterly_mean'] = quarterly_mean / data.Close data['yearly_mean'] = yearly_mean / data.Close
Next, we add more features to help the model understand what the weekly, quarterly and monthly trends are in relation to the yearly trend.
data['yearly_weekly_mean'] = data.yearly_mean / data.weekly_mean data['yearly_monthly_mean'] = data.yearly_mean / data.monthly_mean data['yearly_quarterly_mean'] = data.yearly_mean / data.quarterly_mean
Setting Up the Target
We set up our target by using the shift
method to move all rows forward one day to avoid using the same day to make predictions. Finally, we drop all null values.
data['next_day_price'] = data.Close.shift(-1) data = data.dropna()
Creating a Machine Learning Model

We will use different Machine Learning algorithms to see how accurately the models can predict the currency rate. Let’s first normalize our data.
from sklearn.preprocessing import StandardScaler scaler = StandardScaler() features = data.drop(['Close', 'next_day_price'], axis=True) target = data['next_day_price'] features = scaler.fit_transform(features)
We also split the data setting aside 20% for testing, and the rest for training.
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(features, target, test_size=.2, random_state=0)
We now select only 4 different models. Then, we use r2_score
to get the accuracy score.
from sklearn.linear_model import LinearRegression from sklearn.ensemble import RandomForestRegressor from sklearn.neighbors import KNeighborsRegressor from sklearn.tree import DecisionTreeRegressor from sklearn.metrics import r2_score models = [LinearRegression(), RandomForestRegressor(), KNeighborsRegressor(), DecisionTreeRegressor()] from sklearn.metrics import mean_absolute_error for i in range(4): models[i].fit(X_train, y_train) preds = models[i].predict(X_test) print(r2_score(y_test, preds)*100)
Output:
24.072988955766974 79.61913508661986 58.69174330472067 53.94591537461206
It’s quite obvious that the Random Forest model performs outstandingly far above the other models. If you try other metrics, for example, the Mean Absolute Error metric, it will still point to Random Forest as the one with the lowest error score. Hence, we select the model.
The Random Forest model is approximately 80% accurate. Not bad indeed!
We then create a model.py
file for the script. Check my GitHub page for the full code.
import streamlit as st import numpy as np import datetime import yfinance as yf from sklearn.metrics import r2_score from sklearn.ensemble import RandomForestRegressor from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split from currency import get_prediction import warnings warnings.filterwarnings('ignore') def predict(): base = st.sidebar.selectbox('Choose currency pair', ['USD', 'GBP', 'EUR']) target = st.sidebar.selectbox('Choose another currency pair', ['EUR', 'GBP', 'USD']) if base == target: st.error('Application Error!') return None symbol= f'{base}{target}=X' if st.sidebar.button('Accept'): data = download_data(symbol) st.sidebar.success('Data Downloaded!') model_engine(data, symbol) @st.cache_resource def download_data(symbol): df = yf.download(symbol, start='2008-01-01', end=datetime.date.today(), progress=False) return df
We added several currency pairs. You can add more provided the data are included in Yahoo Finance.

def model_engine(df, symbol): data = df[['Close']] weekly_mean = data.Close.rolling(7).mean() monthly_mean = data.Close.rolling(30).mean() quarterly_mean = data.Close.rolling(90).mean() yearly_mean = data.Close.rolling(365).mean() data['weekly_mean'] = weekly_mean / data.Close data['monthly_mean'] = monthly_mean / data.Close data['quarterly_mean'] = quarterly_mean / data.Close data['yearly_mean'] = yearly_mean / data.Close data['yearly_weekly_mean'] = data.yearly_mean / data.weekly_mean data['yearly_monthly_mean'] = data.yearly_mean / data.monthly_mean data['yearly_quarterly_mean'] = data.yearly_mean / data.quarterly_mean data['next_day_price'] = data.Close.shift(-1) data = data.dropna() scaler = StandardScaler() features = data.drop(['Close', 'next_day_price'], axis=True) target = data['next_day_price'] features = scaler.fit_transform(features) X_train, X_test, y_train, y_test = train_test_split(features, target, test_size=.2, random_state=0) model = RandomForestRegressor() model.fit(X_train, y_train) preds = model.predict(X_test) score = r2_score(y_test, preds) * 100 st.header('Currency Rate Prediction') st.write(f'Model Accuracy: {round(score)}%') get_prediction(model, df)
We have already explained this. The function will be automatically called as soon as the data have been downloaded. Then we display the r2_score
result.
Notice another callback function. This function will use the data downloaded and predict the next day currency rate.
Create another file called currency.py
and add the following script.
def get_prediction(model, df): data = df[['Close']] weekly_mean = data.Close.rolling(7).mean() monthly_mean = data.Close.rolling(30).mean() quarterly_mean = data.Close.rolling(90).mean() yearly_mean = data.Close.rolling(365).mean() data['weekly_mean'] = weekly_mean / data.Close data['monthly_mean'] = monthly_mean / data.Close data['quarterly_mean'] = quarterly_mean / data.Close data['yearly_mean'] = yearly_mean / data.Close data['yearly_weekly_mean'] = data.yearly_mean / data.weekly_mean data['yearly_monthly_mean'] = data.yearly_mean / data.monthly_mean data['yearly_quarterly_mean'] = data.yearly_mean / data.quarterly_mean data = data.dropna() scaler = StandardScaler() features = data.drop(['Close'], axis=True) features = scaler.fit_transform(features) data['predicted_rate'] = model.predict(features) data['signal'] = np.where(data.predicted_rate.shift(1) < data.predicted_rate,"Buy","No Position") prediction = data.tail(1)[['signal','predicted_rate']].T st.write('Current Rate') st.dataframe(data.Close.tail(1)) st.write('Next Day Predicted Rate') st.dataframe(prediction)
Make sure you import the corresponding modules. Again, my GitHub page is at your disposal here.
Notice that the same data used for training the model was also used to predict the next-day currency rate. But we are careful not to let the model know of that.
Instead of passing the data
variable to the get_prediction()
function, we passed the DataFrame df
, the variable holding the data downloaded from Yahoo Finance.
We assume a user is a Forex trader. So, we added a signal to predict whether he should buy or not given the predicted currency rate. Remember, this should not be taken as financial advice.
Finally, we update our main file, the app.py
file. Inside the file, we just have to import the file containing the predict()
function. This is now the updated app.py
file.
import streamlit as st from currencyConverter import currency_converter from model import predict def main(): st.sidebar.header('Currency Converter and Predictor App') op = st.sidebar.selectbox('Select an option', ['convert', 'predict']) if op == 'convert': currency_converter() else: predict() if __name__ == '__main__': main()
Start the local server and have fun trying all the features.

Conclusion
We have finally come to the end of this two-part series of project articles in which we built a currency converter app and a currency prediction app, all two in one application.
Of course, this is not the first time we are including several features in a Streamlit application. In the calculator app, we added 5 features.
By creating such an application and deploying it on Streamlit Cloud, here, you are improving your Python and web development skills.
For ongoing tutorials and free training, download our cheat sheets here: π