File size: 9,747 Bytes
cc82b9a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
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()