Streamlit + NeuralProphet

Ferdinando de Melo
7 min readJul 4, 2021

Using Streamlit to show a dynamic page and NeuralProphet to go beyond.

This is my first article and I’d like to show you a personal project in Python using Streamlit to show a dynamic currency conversion and NeuralProphet to predict the value of a currency.

Where and how to get values of currencies

In this project, I create a file, called requests_functions.py, just to get all request from api sourced by Exchangerate, they provides values about thousands of currencies around the world (including cripto currencies) for free. In this file we have just 2 functions: One to get the latest conversions between the currencies that we set in our environment and other function the get all the values about these currencies during some period of time.

On request_conversions function we get the latest conversion from a base currency to other currencies in a dictionary form. And on request_time_series_conversion, we can get a DataFrame with the conversion of this same base currency during a period.

#requests_funcions.pyimport datetime
from functools import lru_cache
import requests
import pandas as pd
from pandas import DataFrame

from utils import cleaner_function, bases_verification_str

# Definitions of requests
DECIMALS = str(2)
@lru_cache(1000)
def request_conversions(base: str, amount: float) -> dict:
"""
Function to request the latest conversion from a currency
:param base: currency base to make a conversion
:param amount: amount to verify the conversion
:return:
>>> request_conversions("BRL", 1200)
{'base': 'BRL', 'date': '2021-04-17', 'rates': {'EUR': 179.22, 'USD': 214.74}}
"""
symbols = bases_verification_str(base)
url = f'https://api.exchangerate.host/latest?base={base}&symbols={symbols}&places={DECIMALS}&amount={amount}'
response = requests.get(url)
return cleaner_function(response.json(), ['base', 'date', 'rates'])


@lru_cache(500)
def request_time_series_conversion(base: str, amount: float, start_date: str, end_date: str) -> DataFrame:
"""
Function to request a time series of conversions from a currency
:param base: currency base to make a conversion
:param amount: amount to verify the conversion
:param start_date: start date to search a conversion
:param end_date: end date to search a conversion
:return:
>>> request_time_series_conversion('BRL', 1200.00, str(datetime.date(2021, 3, 1)), str(datetime.date(2021, 3, 3)))
EUR USD
2021-03-01 176.50 212.68
2021-03-02 174.95 211.41
2021-03-03 177.01 213.53
"""
symbols = bases_verification_str(base)
url = f'https://api.exchangerate.host/timeseries?start_date={start_date}&end_date={end_date}' \
f'&base={base}&amount={amount}&places={DECIMALS}&symbols={symbols}'
response = requests.get(url)
time_series_conversion_dict = cleaner_function(response.json(), ['base', 'rates'])
# this function returns the transposal of dataFrame to get timeseries in lines and not in columns
df = pd.DataFrame(time_series_conversion_dict['rates']).T
df = df.round(2)
return df

So, then? What can I do with this data?

Now that we have some data, we can show them in a html page. But how can we can show this data on a html page?

The easiest way that I know in the moment that I’m writing this article is using the Streamlit library. It is a library made to provides you the capability to show the world your data in a interactive form. You don’t need to concern about CSS or HTML code, just need to use its functions to get an object to write text, sample of code or YOUR DATA (that’s what I was looking for).

Using Streamlit library

To use the Streamlit library, you need to install it in your environment and it’s possible using pip:

>pip install streamlit

You can test if the package was correctly installed using the command below on your terminal:

>streamlit hello

It’ll provides a page hosted on your localhost using port 8501 and it looks like:

Hello page from Streamlit

Now that we have Streamlit working well, we can put our data retrived from Exchangerate API.

Showing our data in a fancy way

With data that we got from requests_functions.py, we can put them on our page. To this, in main file of our project (main.py) we need to create how all this data will be shown.

I’ve created some functions to help me to deal with theses currencies and DataFrames. These functions is on utils.py and they ensure that all data is able to be shown. Besides theses functions, all my static values is there as well like bases and their descriptions.

#utils.pyimport copy
import json

import pandas as pd
from pandas import DataFrame

"""General definitions"""
BASES = sorted(['USD', 'EUR', 'BRL', 'CHF', 'GBP', 'ARS', 'CAD', 'CNY', 'JPY'])
BASES_DESCRIPTIONS = {'USD': "United States Dollar", 'EUR': "Euro", 'BRL': "Brazilian Real", 'CHF': "Swiss Franc",
'GBP': "British Pound Sterling", 'ARS': "Argentine Peso", 'CAD': "Canadian Dollar",
'CNY': "Chinese Yuan", 'JPY': "Japanese Yen"}
DAYS_OF_PREDICTION = 15


def cleaner_function(json_data: json, returned_keys_list: list) -> dict:
"""
Function to clean json returned from any request
:param json_data: json data returned inserted to clean
:param returned_keys_list:
:return:
>>> cleaner_function({'base':'Real','success':'true', 'date':'2021-04-17'}, ['base', 'date'])
{'base': 'Real', 'date': '2021-04-17'}
"""
test = {key: value for key, value in dict(json_data).items()
if key in returned_keys_list}
return test


def bases_verification_str(base: str) -> str:
"""
Verify which base need to be excluded from list of converted currencies
:param base: Base currency that will be used in convertion
:return:
>>> bases_verification_str('BRL')
'USD,EUR,CHF,BTC'
"""
symbols = copy.copy(BASES)
symbols.remove(base)

return ','.join(symbols)


def bases_verification_lst(base: str) -> list:
"""
Verify which base need to be excluded from list of converted currencies
:param base: Base currency that will be used in convertion
:return:
>>> bases_verification_lst('BRL')
['USD', 'EUR', 'CHF', 'BTC']
"""
symbols = copy.copy(BASES)
symbols.remove(base)
return symbols


def divide_currencies(df: DataFrame, base: str) -> dict:
"""
Divide all currencies into individuals dataframes to make predictions
:param df: DataFrame with all currencies
:param base: Used base to make conversion
:return:
"""
bases = bases_verification_lst(base)
df.reset_index(level=0, inplace=True)
dataframes_dict = dict()
for currency in bases:
df_aux = pd.DataFrame()
df_aux['ds'] = df['index']
df_aux['y'] = df[currency]
dataframes_dict[currency] = df_aux
return dataframes_dict

With these “useful functions and parameters”, we can build our page in main file using Streamlit lib:

#main.pyimport datetime
from datetime import date

import pandas as pd
import streamlit as st

import requests_functions
from utils import BASES, divide_currencies, DAYS_OF_PREDICTION, BASES_DESCRIPTIONS

TODAY = date.today()
FIFTEEN_DAYS_BEFORE = TODAY - datetime.timedelta(15)
SIXTY_DAYS_BEFORE = TODAY - datetime.timedelta(60)

st.set_page_config(page_title="Currency conversion using Exchangerate API",
layout="centered",
initial_sidebar_state="expanded")

st.title("Currency conversion using Exchangerate API")
st.write("""""")
st.write("""""")
st.write("""""")

BASE = st.radio("Pick a base currency", BASES)
st.write("""""")
AMOUNT = st.number_input("Amount to be converted:", step=100.0, min_value=100.0)
st.subheader("Latest Conversion")
"""Get the latest conversion of currency available"""
latest_conversion_df = pd.DataFrame(requests_functions.request_conversions(BASE, AMOUNT))
latest_conversion_df

st.write("""""")
START_DATE = st.date_input("Pick a START date", min_value=SIXTY_DAYS_BEFORE, max_value=FIFTEEN_DAYS_BEFORE)
END_DATE = st.date_input("Pick a END date", max_value=TODAY)

st.write("""""")
st.subheader(f"Values since {START_DATE}")
"""Show the last few days of conversion of currency"""

time_series_conversion_df = requests_functions.request_time_series_conversion(BASE,
AMOUNT, str(START_DATE), str(END_DATE))
"""Presenting the return time series"""
time_series_conversion_df
st.subheader(f"Timeline since {START_DATE}")
st.line_chart(time_series_conversion_df)

With this code above, we have a page with good looking and all the information that we gathered about the currencies that we choose.

To run this code, go to terminal and type this:

>streamlit run main.py

Where is NeuralProphet? I came here for it!

Calm down, young Padawan… Use NeuralProphet library is our next step.

NeuralProphet is a Neural Network based Time-Series model, inspired by Facebook Prophet and AR-Net, built on PyTorch. And with this library you just need inform date series (DS) and the value to train your neural network (y).

I’ve created a file just to use NeuralProphet and I called it as predictions.py. I’m using the same 15 days ahead to predict declared on utils.py.

#predictions.pyimport pandas as pd
from neuralprophet import NeuralProphet, set_random_seed
from pandas import DataFrame

from utils import DAYS_OF_PREDICTION

set_random_seed(0)


def predictions(df: DataFrame) -> DataFrame:
"""
Make predictions about
:param df: Dataframe to make the predictions
:return:
"""
m = NeuralProphet()
m.fit(df, freq='D')
future = m.make_future_dataframe(df, periods=DAYS_OF_PREDICTION)
forecast = m.predict(future)
forecast['ds'] = pd.to_datetime(forecast['ds']).dt.strftime('%Y-%m-%d')
forecast = forecast.set_index('ds')
forecast.rename(columns={'yhat1': 'currency'}, inplace=True)
forecast = forecast.round(2)
return forecast

Now we can call it direct from our page file with data collected. We just need add some more code in our main.py file to show our predictions:

#main.py"""Presenting the return time series"""
time_series_conversion_df
st.subheader(f"Timeline since {START_DATE}")
st.line_chart(time_series_conversion_df)

st.write("""""")
st.subheader(f"Predictions")
"""Make some predictions to these conversions"""
time_series_dict_to_forecast = divide_currencies(time_series_conversion_df, BASE)
try:
for k in time_series_dict_to_forecast.keys():
forecast = predictions(time_series_dict_to_forecast[k])
st.subheader(
f"Value of {AMOUNT} {BASE}'s prediction for next {DAYS_OF_PREDICTION} days in {BASES_DESCRIPTIONS[k]} "
f"currency")
st.line_chart(forecast['currency'])

except ValueError as e:
st.write(
f"Change the date to do the simulations or one of the currencies doesn't have any value to calculate a "
f"prediction")

After it get data from Exchangerate, it will make the forecast using your base currency to predict how much 100 units of this currency will worth in 15 days on others currencies.

You’ll get some charts like these on your page:

Conclusions

The same way that we could show the latest and predict future values of these currencies, we can use the same mechanism to study about financial market and releated.

I hope that this article helps you to understand how can you use Streamlit to show your data and NeuralProphet to predict your timeseries values in a easy way.

You can revisit all this code in my project on github or if you have some doubt about it, you can reach me on LinkedIn.

Thank You :)

--

--