Dhanush-37's picture
Upload 4 files
cc82b9a verified
import streamlit as st
import pandas as pd
import plotly.express as px
from datetime import datetime, timedelta
import requests
from models.prophet_model import ProphetModel
from models.arima_model import ArimaModel
from models.lstm_model import LSTMModel
from utils.preprocessing import preprocess_data
from utils.visualization import plot_decomposition, plot_forecast
#
st.set_page_config(page_title="Crypto Forecasting Platform", layout="wide")
class CryptoForecastingApp:
def __init__(self):
self.available_coins = {
'Bitcoin': {'binance': 'BTCUSDT', 'yahoo': 'BTC-USD'},
'Ethereum': {'binance': 'ETHUSDT', 'yahoo': 'ETH-USD'},
'Dogecoin': {'binance': 'DOGEUSDT', 'yahoo': 'DOGE-USD'},
'Cardano': {'binance': 'ADAUSDT', 'yahoo': 'ADA-USD'},
'Solana': {'binance': 'SOLUSDT', 'yahoo': 'SOL-USD'}
}
self.available_models = ['Prophet', 'ARIMA', 'LSTM']
def get_binance_data(self, symbol, start_date, end_date):
try:
# Convert dates to timestamps (milliseconds)
start_ts = int(datetime.combine(start_date, datetime.min.time()).timestamp() * 1000)
end_ts = int(datetime.combine(end_date, datetime.max.time()).timestamp() * 1000)
# Binance API endpoint for klines (candlestick) data
url = "https://api.binance.com/api/v3/klines"
params = {
"symbol": symbol,
"interval": "1d", # Daily data
"startTime": start_ts,
"endTime": end_ts,
"limit": 1000
}
response = requests.get(url, params=params)
if response.status_code != 200:
return None
data = response.json()
if not data:
return None
# Convert to DataFrame
df = pd.DataFrame(data, columns=[
'timestamp', 'Open', 'High', 'Low', 'Close', 'Volume',
'close_time', 'quote_volume', 'trades', 'taker_base',
'taker_quote', 'ignored'
])
# Convert timestamp to datetime
df['Date'] = pd.to_datetime(df['timestamp'], unit='ms')
df.set_index('Date', inplace=True)
# Convert string values to float
for col in ['Open', 'High', 'Low', 'Close', 'Volume']:
df[col] = df[col].astype(float)
return df[['Open', 'High', 'Low', 'Close', 'Volume']]
except Exception as e:
st.error(f"Error fetching from Binance: {str(e)}")
return None
def get_yahoo_data(self, symbol, start_date, end_date):
try:
import yfinance as yf
data = yf.download(symbol, start=start_date, end=end_date)
return data if not data.empty else None
except Exception as e:
st.error(f"Error fetching from Yahoo: {str(e)}")
return None
def get_crypto_data(self, coin_info, start_date, end_date):
# Try Binance first
data = self.get_binance_data(coin_info['binance'], start_date, end_date)
# If Binance fails, try Yahoo Finance
if data is None:
st.warning("Binance data unavailable, trying Yahoo Finance...")
data = self.get_yahoo_data(coin_info['yahoo'], start_date, end_date)
if data is None:
st.error("Unable to fetch data from both Binance and Yahoo Finance")
return None
return data
def run(self):
st.title("Cryptocurrency Price Forecasting & Analysis Platform")
# Sidebar controls
st.sidebar.header("Controls")
selected_coin_name = st.sidebar.selectbox('Choose Cryptocurrency', list(self.available_coins.keys()))
selected_coin = self.available_coins[selected_coin_name]
# Date range selection
col1, col2 = st.sidebar.columns(2)
with col1:
start_date = st.date_input(
"Start Date",
datetime.now().date() - timedelta(days=365),
min_value=datetime(2015, 1, 1).date(),
max_value=datetime.now().date()
)
with col2:
end_date = st.date_input(
"End Date",
datetime.now().date(),
min_value=start_date,
max_value=datetime.now().date()
)
if start_date >= end_date:
st.error("Error: End date must be after start date.")
return
selected_model = st.sidebar.selectbox('Choose Model', self.available_models)
forecast_days = st.sidebar.slider('Forecast Days', 7, 90, 30)
if st.sidebar.button('Generate Forecast'):
with st.spinner('Loading historical data...'):
data = self.get_crypto_data(selected_coin, start_date, end_date)
if data is not None and not data.empty:
try:
with st.spinner('Processing data...'):
processed_data = preprocess_data(data)
# Display basic stats
st.subheader("Current Statistics")
metrics_col1, metrics_col2, metrics_col3 = st.columns(3)
with metrics_col1:
current_price = float(data['Close'].iloc[-1])
st.metric("Current Price", f"${current_price:.2f}")
with metrics_col2:
if len(data) > 1:
price_change = float(data['Close'].iloc[-1] - data['Close'].iloc[-2])
price_change_pct = (price_change / float(data['Close'].iloc[-2])) * 100
st.metric("24h Change",
f"${price_change:.2f}",
f"{price_change_pct:.2f}%")
else:
st.metric("24h Change", "N/A")
with metrics_col3:
current_volume = float(data['Volume'].iloc[-1])
st.metric("24h Volume", f"${current_volume:,.0f}")
# Show price history
st.subheader("Price History")
fig = px.line(data, y='Close', title=f'{selected_coin_name} Price History')
st.plotly_chart(fig)
# Show decomposition
st.subheader("Time Series Decomposition")
with st.spinner('Generating decomposition plot...'):
try:
decomp_fig = plot_decomposition(processed_data)
st.plotly_chart(decomp_fig)
except Exception as e:
st.error(f"Error in decomposition: {str(e)}")
# Generate and show forecast
st.subheader(f"Price Forecast ({forecast_days} days)")
with st.spinner(f'Training {selected_model} model and generating forecast...'):
try:
if selected_model == 'Prophet':
model = ProphetModel()
elif selected_model == 'ARIMA':
model = ArimaModel()
else:
model = LSTMModel()
forecast = model.train_and_predict(processed_data, forecast_days)
forecast_fig = plot_forecast(processed_data, forecast, selected_model)
st.plotly_chart(forecast_fig)
# Show model performance metrics
st.subheader("Model Performance Metrics")
metrics = model.get_metrics()
metrics_df = pd.DataFrame(metrics, index=[0])
st.table(metrics_df)
except Exception as e:
st.error(f"Error in forecasting: {str(e)}")
except Exception as e:
st.error(f"Error processing data: {str(e)}")
else:
st.warning("No data available for the selected date range. Please try a different range.")
# Add information about data source
st.sidebar.markdown("---")
st.sidebar.info("Data sources: Binance API (primary) and Yahoo Finance (backup)")
with st.expander("How to use this app"):
st.write("""
1. Select a cryptocurrency from the dropdown menu
2. Choose your desired date range (data available from 2015 onwards)
3. Select a forecasting model:
- Prophet: Good for general trends
- ARIMA: Good for short-term forecasts
- LSTM: Good for complex patterns
4. Choose the number of days to forecast
5. Click 'Generate Forecast' to see the results
Note: The app uses Binance API as the primary data source and falls back to Yahoo Finance if needed.
""")
if __name__ == "__main__":
app = CryptoForecastingApp()
app.run()