#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ app.py - Enhanced Crypto & Stock Predictor with intuitive UI/UX """ import ccxt import yfinance as yf import pandas as pd import numpy as np import plotly.graph_objects as go from plotly.subplots import make_subplots import gradio as gr from ta.momentum import RSIIndicator from ta.trend import MACD # ------------------------ # Data Fetching # ------------------------ def get_historical_data(symbol: str, timeframe: str = "1d", limit: int = 200) -> pd.DataFrame: """Fetch historical OHLCV data using CCXT (crypto) or yfinance (stocks).""" try: if "/" in symbol: exchange = ccxt.binance() ohlcv = exchange.fetch_ohlcv(symbol, timeframe, limit=limit) df = pd.DataFrame(ohlcv, columns=["timestamp", "Open", "High", "Low", "Close", "Volume"]) df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms') df.set_index('timestamp', inplace=True) else: df = yf.download(symbol, period="1y", interval=timeframe) df['Returns'] = df['Close'].pct_change().fillna(0) return df except Exception as e: raise Exception(f"Data fetch failed for {symbol}: {str(e)}") # ------------------------ # Indicators # ------------------------ def add_indicators(df: pd.DataFrame) -> pd.DataFrame: df['SMA20'] = df['Close'].rolling(20).mean() df['SMA50'] = df['Close'].rolling(50).mean() df['Signal'] = np.where(df['SMA20'] > df['SMA50'], 'Buy', 'Sell') df['RSI'] = RSIIndicator(df['Close'], window=14).rsi() macd = MACD(df['Close'], window_slow=26, window_fast=12, window_sign=9) df['MACD'] = macd.macd() df['MACD_Signal'] = macd.macd_signal() return df # ------------------------ # Chronos AI Prediction # ------------------------ def make_chronos_prediction(df: pd.DataFrame, prediction_days: int = 7) -> dict: """Simulated Chronos AI predictions with confidence intervals.""" returns = df['Returns'].values mean_pred = np.random.normal(np.mean(returns), np.std(returns), prediction_days) std_pred = np.full(prediction_days, np.std(returns)) mean_pred = mean_pred * df['Close'].std() + df['Close'].mean() last_price = df['Close'].iloc[-1] price_predictions = [last_price] for ret in mean_pred: price_predictions.append(price_predictions[-1] * (1 + ret)) price_predictions = np.array(price_predictions[1:]) upper_bound = price_predictions * (1 + 1.96 * std_pred) lower_bound = price_predictions * (1 - 1.96 * std_pred) return {"mean": price_predictions, "upper": upper_bound, "lower": lower_bound} # ------------------------ # Plotly Figure # ------------------------ def create_prediction_plot(df: pd.DataFrame, predictions: dict, prediction_days: int) -> go.Figure: fig = make_subplots( rows=2, cols=1, subplot_titles=('Price Prediction', 'Technical Indicators'), vertical_spacing=0.15, row_width=[0.3, 0.7] ) fig.add_trace(go.Scatter(x=df.index, y=df['Close'], name='Historical Price', line=dict(color='blue')), row=1, col=1) future_dates = pd.date_range(start=df.index[-1] + pd.Timedelta(1, unit='D'), periods=prediction_days) fig.add_trace(go.Scatter(x=future_dates, y=predictions['mean'], name='Predicted Price', line=dict(color='orange', width=3)), row=1, col=1) fig.add_trace(go.Scatter( x=list(future_dates) + list(future_dates[::-1]), y=list(predictions['upper']) + list(predictions['lower'][::-1]), fill='toself', fillcolor='rgba(255,127,14,0.2)', line=dict(color='rgba(255,255,255,0)'), name='Confidence Interval' ), row=1, col=1) fig.add_trace(go.Scatter(x=df.index, y=df['RSI'], name='RSI', line=dict(color='green')), row=2, col=1) fig.add_trace(go.Scatter(x=df.index, y=df['MACD'], name='MACD', line=dict(color='red')), row=2, col=1) fig.add_trace(go.Scatter(x=df.index, y=df['MACD_Signal'], name='MACD Signal', line=dict(color='purple')), row=2, col=1) fig.update_layout( title="📊 Price & Technical Predictions", height=800, showlegend=True, template="plotly_dark" ) fig.update_yaxes(title_text="Price ($)", row=1, col=1) fig.update_yaxes(title_text="Indicator Value", row=2, col=1) return fig # ------------------------ # Gradio Dashboard (Improved UX) # ------------------------ def create_dashboard(): with gr.Blocks(title="📈 Crypto & Stock Predictor") as demo: with gr.Row(): with gr.Column(scale=1): gr.Markdown("## Input Parameters") symbol = gr.Textbox(label="Symbol", value="BTC/USDT", placeholder="e.g., BTC/USDT or AAPL", info="Enter crypto pair or stock symbol") timeframe = gr.Dropdown(label="Timeframe", choices=["1d", "1h", "15m"], value="1d", info="Select candle timeframe") prediction_days = gr.Slider(label="Prediction Days", minimum=1, maximum=30, value=7, step=1, info="How many days to predict") btn_predict = gr.Button("Predict", variant="primary") with gr.Column(scale=2): with gr.Tab("Predictions"): plot = gr.Plot(label="Prediction Plot") with gr.Tab("Signals"): signals_table = gr.Dataframe(label="SMA Signals", headers=["SMA20","SMA50","Signal"], interactive=False) with gr.Tab("Market Info"): market_info = gr.JSON(label="Market Info") @btn_predict.click(inputs=[symbol, timeframe, prediction_days], outputs=[plot, signals_table, market_info]) def update_dashboard(symbol, timeframe, prediction_days): df = get_historical_data(symbol, timeframe) df = add_indicators(df) predictions = make_chronos_prediction(df, prediction_days) fig = create_prediction_plot(df, predictions, prediction_days) signals_data = df[['SMA20','SMA50','Signal']].tail(prediction_days) info = { "Current Price": f"${df['Close'].iloc[-1]:.2f}", "RSI": f"{df['RSI'].iloc[-1]:.2f}", "MACD": f"{df['MACD'].iloc[-1]:.2f}", "MACD Signal": f"{df['MACD_Signal'].iloc[-1]:.2f}" } return fig, signals_data, info return demo if __name__ == "__main__": demo = create_dashboard() demo.launch(server_name="0.0.0.0", server_port=7860)