How I Created a Currency Prediction App Using Streamlit

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: πŸ‘‡