|
| 1 | +import streamlit as st |
| 2 | +from PIL import Image |
| 3 | +import pandas as pd |
| 4 | +import base64 |
| 5 | +import matplotlib.pyplot as plt |
| 6 | +from bs4 import BeautifulSoup |
| 7 | +import requests |
| 8 | +import json |
| 9 | +import time |
| 10 | +#---------------------------------# |
| 11 | +# New feature (make sure to upgrade your streamlit library) |
| 12 | +# pip install --upgrade streamlit |
| 13 | + |
| 14 | +#---------------------------------# |
| 15 | +# Page layout |
| 16 | +## Page expands to full width |
| 17 | +st.beta_set_page_config(layout="wide") |
| 18 | +#---------------------------------# |
| 19 | +# Title |
| 20 | + |
| 21 | +image = Image.open('logo.jpg') |
| 22 | + |
| 23 | +st.image(image, width = 500) |
| 24 | + |
| 25 | +st.title('Crypto Price App') |
| 26 | +st.markdown(""" |
| 27 | +This app retrieves cryptocurrency prices for the top 100 cryptocurrency from the **CoinMarketCap**! |
| 28 | +
|
| 29 | +""") |
| 30 | +#---------------------------------# |
| 31 | +# About |
| 32 | +expander_bar = st.beta_expander("About") |
| 33 | +expander_bar.markdown(""" |
| 34 | +* **Python libraries:** base64, pandas, streamlit, numpy, matplotlib, seaborn, BeautifulSoup, requests, json, time |
| 35 | +* **Data source:** [CoinMarketCap](http://coinmarketcap.com). |
| 36 | +* **Credit:** Web scraper adapted from the Medium article *[Web Scraping Crypto Prices With Python](https://towardsdatascience.com/web-scraping-crypto-prices-with-python-41072ea5b5bf)* written by [Bryan Feng](https://medium.com/@bryanf). |
| 37 | +""") |
| 38 | + |
| 39 | + |
| 40 | +#---------------------------------# |
| 41 | +# Page layout (continued) |
| 42 | +## Divide page to 3 columns (col1 = sidebar, col2 and col3 = page contents) |
| 43 | +col1 = st.sidebar |
| 44 | +col2, col3 = st.beta_columns((2,1)) |
| 45 | + |
| 46 | +#---------------------------------# |
| 47 | +# Sidebar + Main panel |
| 48 | +col1.header('Input Options') |
| 49 | + |
| 50 | +## Sidebar - Currency price unit |
| 51 | +currency_price_unit = col1.selectbox('Select currency for price', ('USD', 'BTC', 'ETH')) |
| 52 | + |
| 53 | +# Web scraping of CoinMarketCap data |
| 54 | +@st.cache |
| 55 | +def load_data(): |
| 56 | + cmc = requests.get('https://coinmarketcap.com') |
| 57 | + soup = BeautifulSoup(cmc.content, 'html.parser') |
| 58 | + |
| 59 | + data = soup.find('script', id='__NEXT_DATA__', type='application/json') |
| 60 | + coins = {} |
| 61 | + coin_data = json.loads(data.contents[0]) |
| 62 | + listings = coin_data['props']['initialState']['cryptocurrency']['listingLatest']['data'] |
| 63 | + for i in listings: |
| 64 | + coins[str(i['id'])] = i['slug'] |
| 65 | + |
| 66 | + coin_name = [] |
| 67 | + coin_symbol = [] |
| 68 | + market_cap = [] |
| 69 | + percent_change_1h = [] |
| 70 | + percent_change_24h = [] |
| 71 | + percent_change_7d = [] |
| 72 | + price = [] |
| 73 | + volume_24h = [] |
| 74 | + |
| 75 | + for i in listings: |
| 76 | + coin_name.append(i['slug']) |
| 77 | + coin_symbol.append(i['symbol']) |
| 78 | + price.append(i['quote'][currency_price_unit]['price']) |
| 79 | + percent_change_1h.append(i['quote'][currency_price_unit]['percent_change_1h']) |
| 80 | + percent_change_24h.append(i['quote'][currency_price_unit]['percent_change_24h']) |
| 81 | + percent_change_7d.append(i['quote'][currency_price_unit]['percent_change_7d']) |
| 82 | + market_cap.append(i['quote'][currency_price_unit]['market_cap']) |
| 83 | + volume_24h.append(i['quote'][currency_price_unit]['volume_24h']) |
| 84 | + |
| 85 | + df = pd.DataFrame(columns=['coin_name', 'coin_symbol', 'market_cap', 'percent_change_1h', 'percent_change_24h', 'percent_change_7d', 'price', 'volume_24h']) |
| 86 | + df['coin_name'] = coin_name |
| 87 | + df['coin_symbol'] = coin_symbol |
| 88 | + df['price'] = price |
| 89 | + df['percent_change_1h'] = percent_change_1h |
| 90 | + df['percent_change_24h'] = percent_change_24h |
| 91 | + df['percent_change_7d'] = percent_change_7d |
| 92 | + df['market_cap'] = market_cap |
| 93 | + df['volume_24h'] = volume_24h |
| 94 | + return df |
| 95 | + |
| 96 | +df = load_data() |
| 97 | + |
| 98 | +## Sidebar - Cryptocurrency selections |
| 99 | +sorted_coin = sorted( df['coin_symbol'] ) |
| 100 | +selected_coin = col1.multiselect('Cryptocurrency', sorted_coin, sorted_coin) |
| 101 | + |
| 102 | +df_selected_coin = df[ (df['coin_symbol'].isin(selected_coin)) ] # Filtering data |
| 103 | + |
| 104 | +## Sidebar - Number of coins to display |
| 105 | +num_coin = col1.slider('Display Top N Coins', 1, 100, 100) |
| 106 | +df_coins = df_selected_coin[:num_coin] |
| 107 | + |
| 108 | +## Sidebar - Percent change timeframe |
| 109 | +percent_timeframe = col1.selectbox('Percent change time frame', |
| 110 | + ['7d','24h', '1h']) |
| 111 | +percent_dict = {"7d":'percent_change_7d',"24h":'percent_change_24h',"1h":'percent_change_1h'} |
| 112 | +selected_percent_timeframe = percent_dict[percent_timeframe] |
| 113 | + |
| 114 | +## Sidebar - Sorting values |
| 115 | +sort_values = col1.selectbox('Sort values?', ['Yes', 'No']) |
| 116 | + |
| 117 | +col2.subheader('Price Data of Selected Cryptocurrency') |
| 118 | +col2.write('Data Dimension: ' + str(df_selected_coin.shape[0]) + ' rows and ' + str(df_selected_coin.shape[1]) + ' columns.') |
| 119 | + |
| 120 | +col2.dataframe(df_coins) |
| 121 | + |
| 122 | +# Download CSV data |
| 123 | +# https://discuss.streamlit.io/t/how-to-download-file-in-streamlit/1806 |
| 124 | +def filedownload(df): |
| 125 | + csv = df.to_csv(index=False) |
| 126 | + b64 = base64.b64encode(csv.encode()).decode() # strings <-> bytes conversions |
| 127 | + href = f'<a href="data:file/csv;base64,{b64}" download="crypto.csv">Download CSV File</a>' |
| 128 | + return href |
| 129 | + |
| 130 | +col2.markdown(filedownload(df_selected_coin), unsafe_allow_html=True) |
| 131 | + |
| 132 | +#---------------------------------# |
| 133 | +# Preparing data for Bar plot of % Price change |
| 134 | +col2.subheader('Table of % Price Change') |
| 135 | +df_change = pd.concat([df_coins.coin_symbol, df_coins.percent_change_1h, df_coins.percent_change_24h, df_coins.percent_change_7d], axis=1) |
| 136 | +df_change = df_change.set_index('coin_symbol') |
| 137 | +df_change['positive_percent_change_1h'] = df_change['percent_change_1h'] > 0 |
| 138 | +df_change['positive_percent_change_24h'] = df_change['percent_change_24h'] > 0 |
| 139 | +df_change['positive_percent_change_7d'] = df_change['percent_change_7d'] > 0 |
| 140 | +col2.dataframe(df_change) |
| 141 | + |
| 142 | +# Conditional creation of Bar plot (time frame) |
| 143 | +col3.subheader('Bar plot of % Price Change') |
| 144 | + |
| 145 | +if percent_timeframe == '7d': |
| 146 | + if sort_values == 'Yes': |
| 147 | + df_change = df_change.sort_values(by=['percent_change_7d']) |
| 148 | + col3.write('*7 days period*') |
| 149 | + plt.figure(figsize=(5,25)) |
| 150 | + plt.subplots_adjust(top = 1, bottom = 0) |
| 151 | + df_change['percent_change_7d'].plot(kind='barh', color=df_change.positive_percent_change_7d.map({True: 'g', False: 'r'})) |
| 152 | + col3.pyplot(plt) |
| 153 | +elif percent_timeframe == '24h': |
| 154 | + if sort_values == 'Yes': |
| 155 | + df_change = df_change.sort_values(by=['percent_change_24h']) |
| 156 | + col3.write('*24 hour period*') |
| 157 | + plt.figure(figsize=(5,25)) |
| 158 | + plt.subplots_adjust(top = 1, bottom = 0) |
| 159 | + df_change['percent_change_24h'].plot(kind='barh', color=df_change.positive_percent_change_24h.map({True: 'g', False: 'r'})) |
| 160 | + col3.pyplot(plt) |
| 161 | +else: |
| 162 | + if sort_values == 'Yes': |
| 163 | + df_change = df_change.sort_values(by=['percent_change_1h']) |
| 164 | + col3.write('*1 hour period*') |
| 165 | + plt.figure(figsize=(5,25)) |
| 166 | + plt.subplots_adjust(top = 1, bottom = 0) |
| 167 | + df_change['percent_change_1h'].plot(kind='barh', color=df_change.positive_percent_change_1h.map({True: 'g', False: 'r'})) |
| 168 | + col3.pyplot(plt) |
0 commit comments