Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import yfinance as yf | |
| import pandas as pd | |
| import numpy as np | |
| from datetime import datetime, timedelta | |
| import feedparser | |
| from textblob import TextBlob | |
| from statsmodels.tsa.holtwinters import ExponentialSmoothing | |
| # Function to fetch cryptocurrency data | |
| def get_crypto_data(symbol, period="30d", interval="1h"): | |
| crypto = yf.Ticker(f"{symbol}-USD") | |
| data = crypto.history(period=period, interval=interval) | |
| return data | |
| # Function to calculate RSI | |
| def calculate_rsi(data, period=14): | |
| delta = data['Close'].diff() | |
| gain = (delta.where(delta > 0, 0)).rolling(window=period).mean() | |
| loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean() | |
| rs = gain / loss | |
| rsi = 100 - (100 / (1 + rs)) | |
| return rsi | |
| # Function to calculate MACD | |
| def calculate_macd(data, short_window=12, long_window=26, signal_window=9): | |
| short_ema = data['Close'].ewm(span=short_window, adjust=False).mean() | |
| long_ema = data['Close'].ewm(span=long_window, adjust=False).mean() | |
| macd = short_ema - long_ema | |
| signal = macd.ewm(span=signal_window, adjust=False).mean() | |
| return macd, signal | |
| # Function to calculate EMA | |
| def calculate_ema(data, period=20): | |
| return data['Close'].ewm(span=period, adjust=False).mean() | |
| # Function to calculate ATR | |
| def calculate_atr(data, period=14): | |
| high_low = data['High'] - data['Low'] | |
| high_close = np.abs(data['High'] - data['Close'].shift()) | |
| low_close = np.abs(data['Low'] - data['Close'].shift()) | |
| true_range = pd.concat([high_low, high_close, low_close], axis=1).max(axis=1) | |
| atr = true_range.rolling(window=period).mean() | |
| return atr | |
| # Function to calculate Stochastic Oscillator | |
| def calculate_stochastic(data, period=14): | |
| high = data['High'].rolling(window=period).max() | |
| low = data['Low'].rolling(window=period).min() | |
| stoch_k = 100 * ((data['Close'] - low) / (high - low)) | |
| stoch_d = stoch_k.rolling(window=3).mean() | |
| return stoch_k, stoch_d | |
| # Function to calculate Bollinger Bands | |
| def calculate_bollinger_bands(data, period=20, std_dev=2): | |
| sma = data['Close'].rolling(window=period).mean() | |
| std = data['Close'].rolling(window=period).std() | |
| upper_band = sma + (std * std_dev) | |
| lower_band = sma - (std * std_dev) | |
| return upper_band, lower_band | |
| # Function to calculate On-Balance Volume (OBV) | |
| def calculate_obv(data): | |
| obv = (np.sign(data['Close'].diff()) * data['Volume']).cumsum() | |
| return obv | |
| # Function to calculate Average Directional Index (ADX) | |
| def calculate_adx(data, period=14): | |
| high = data['High'] | |
| low = data['Low'] | |
| close = data['Close'] | |
| # Calculate +DM and -DM | |
| plus_dm = high.diff() | |
| minus_dm = -low.diff() | |
| plus_dm[plus_dm < 0] = 0 | |
| minus_dm[minus_dm < 0] = 0 | |
| # Calculate True Range (TR) | |
| tr = pd.concat([high - low, abs(high - close.shift()), abs(low - close.shift())], axis=1).max(axis=1) | |
| # Calculate +DI and -DI | |
| plus_di = 100 * (plus_dm.ewm(alpha=1/period).mean() / tr.ewm(alpha=1/period).mean()) | |
| minus_di = 100 * (minus_dm.ewm(alpha=1/period).mean() / tr.ewm(alpha=1/period).mean()) | |
| # Calculate ADX | |
| dx = 100 * abs(plus_di - minus_di) / (plus_di + minus_di) | |
| adx = dx.ewm(alpha=1/period).mean() | |
| return adx | |
| # Function to calculate Fibonacci Retracement levels | |
| def calculate_fibonacci_levels(data): | |
| high = data['High'].max() | |
| low = data['Low'].min() | |
| diff = high - low | |
| return { | |
| "23.6%": high - diff * 0.236, | |
| "38.2%": high - diff * 0.382, | |
| "50%": high - diff * 0.5, | |
| "61.8%": high - diff * 0.618, | |
| "78.6%": high - diff * 0.786, | |
| } | |
| # Function to calculate probabilities | |
| def calculate_probabilities(data): | |
| # Calculate indicators | |
| data['RSI'] = calculate_rsi(data) | |
| data['MACD'], data['MACD_Signal'] = calculate_macd(data) | |
| data['EMA_50'] = calculate_ema(data, period=50) | |
| data['EMA_200'] = calculate_ema(data, period=200) | |
| data['ATR'] = calculate_atr(data) | |
| data['Stoch_K'], data['Stoch_D'] = calculate_stochastic(data) | |
| data['Upper_Band'], data['Lower_Band'] = calculate_bollinger_bands(data) | |
| data['OBV'] = calculate_obv(data) | |
| data['ADX'] = calculate_adx(data) | |
| # Use the most recent values for predictions | |
| recent_data = data.iloc[-1] | |
| # Calculate probabilities | |
| probabilities = { | |
| "RSI": {"Pump": 0, "Dump": 0}, | |
| "MACD": {"Pump": 0, "Dump": 0}, | |
| "EMA": {"Pump": 0, "Dump": 0}, | |
| "ATR": {"Pump": 0, "Dump": 0}, | |
| "Stochastic": {"Pump": 0, "Dump": 0}, | |
| "Bollinger Bands": {"Pump": 0, "Dump": 0}, | |
| "OBV": {"Pump": 0, "Dump": 0}, | |
| "ADX": {"Pump": 0, "Dump": 0}, | |
| } | |
| # RSI | |
| rsi = recent_data['RSI'] | |
| if rsi < 25: | |
| probabilities["RSI"]["Pump"] = 90 # Strong Pump | |
| elif 25 <= rsi < 30: | |
| probabilities["RSI"]["Pump"] = 60 # Moderate Pump | |
| elif 70 < rsi <= 75: | |
| probabilities["RSI"]["Dump"] = 60 # Moderate Dump | |
| elif rsi > 75: | |
| probabilities["RSI"]["Dump"] = 90 # Strong Dump | |
| # MACD | |
| macd = recent_data['MACD'] | |
| macd_signal = recent_data['MACD_Signal'] | |
| if macd > macd_signal and macd > 0: | |
| probabilities["MACD"]["Pump"] = 90 # Strong Pump | |
| elif macd > macd_signal and macd <= 0: | |
| probabilities["MACD"]["Pump"] = 60 # Moderate Pump | |
| elif macd < macd_signal and macd >= 0: | |
| probabilities["MACD"]["Dump"] = 60 # Moderate Dump | |
| elif macd < macd_signal and macd < 0: | |
| probabilities["MACD"]["Dump"] = 90 # Strong Dump | |
| # EMA | |
| ema_short = recent_data['EMA_50'] | |
| ema_long = recent_data['EMA_200'] | |
| close = recent_data['Close'] | |
| if ema_short > ema_long and close > ema_short: | |
| probabilities["EMA"]["Pump"] = 90 # Strong Pump | |
| elif ema_short > ema_long and close <= ema_short: | |
| probabilities["EMA"]["Pump"] = 60 # Moderate Pump | |
| elif ema_short < ema_long and close >= ema_short: | |
| probabilities["EMA"]["Dump"] = 60 # Moderate Dump | |
| elif ema_short < ema_long and close < ema_short: | |
| probabilities["EMA"]["Dump"] = 90 # Strong Dump | |
| # ATR | |
| atr = recent_data['ATR'] | |
| if atr > 100: | |
| probabilities["ATR"]["Pump"] = 90 # Strong Pump | |
| elif 50 < atr <= 100: | |
| probabilities["ATR"]["Pump"] = 60 # Moderate Pump | |
| elif -100 <= atr < -50: | |
| probabilities["ATR"]["Dump"] = 60 # Moderate Dump | |
| elif atr < -100: | |
| probabilities["ATR"]["Dump"] = 90 # Strong Dump | |
| # Stochastic Oscillator | |
| stoch_k = recent_data['Stoch_K'] | |
| stoch_d = recent_data['Stoch_D'] | |
| if stoch_k < 20 and stoch_d < 20: | |
| probabilities["Stochastic"]["Pump"] = 90 # Strong Pump | |
| elif 20 <= stoch_k < 30 and 20 <= stoch_d < 30: | |
| probabilities["Stochastic"]["Pump"] = 60 # Moderate Pump | |
| elif 70 < stoch_k <= 80 and 70 < stoch_d <= 80: | |
| probabilities["Stochastic"]["Dump"] = 60 # Moderate Dump | |
| elif stoch_k > 80 and stoch_d > 80: | |
| probabilities["Stochastic"]["Dump"] = 90 # Strong Dump | |
| # Bollinger Bands | |
| close = recent_data['Close'] | |
| upper_band = recent_data['Upper_Band'] | |
| lower_band = recent_data['Lower_Band'] | |
| if close <= lower_band: | |
| probabilities["Bollinger Bands"]["Pump"] = 90 # Strong Pump | |
| elif lower_band < close <= lower_band * 1.05: | |
| probabilities["Bollinger Bands"]["Pump"] = 60 # Moderate Pump | |
| elif upper_band * 0.95 <= close < upper_band: | |
| probabilities["Bollinger Bands"]["Dump"] = 60 # Moderate Dump | |
| elif close >= upper_band: | |
| probabilities["Bollinger Bands"]["Dump"] = 90 # Strong Dump | |
| # OBV | |
| obv = recent_data['OBV'] | |
| if obv > 100000: | |
| probabilities["OBV"]["Pump"] = 90 # Strong Pump | |
| elif 50000 < obv <= 100000: | |
| probabilities["OBV"]["Pump"] = 60 # Moderate Pump | |
| elif -100000 <= obv < -50000: | |
| probabilities["OBV"]["Dump"] = 60 # Moderate Dump | |
| elif obv < -100000: | |
| probabilities["OBV"]["Dump"] = 90 # Strong Dump | |
| # ADX | |
| adx = recent_data['ADX'] | |
| if adx > 25: | |
| probabilities["ADX"]["Pump"] = 90 # Strong Pump | |
| elif 20 < adx <= 25: | |
| probabilities["ADX"]["Pump"] = 60 # Moderate Pump | |
| elif 15 < adx <= 20: | |
| probabilities["ADX"]["Dump"] = 60 # Moderate Dump | |
| elif adx <= 15: | |
| probabilities["ADX"]["Dump"] = 90 # Strong Dump | |
| return probabilities, recent_data | |
| # Function to predict future prices using Exponential Smoothing | |
| def predict_price(data, days=7): | |
| try: | |
| # Prepare data for Exponential Smoothing | |
| df = data[['Close']] | |
| # Train the model | |
| model = ExponentialSmoothing(df, trend="add", seasonal="add", seasonal_periods=7) | |
| fit = model.fit() | |
| # Make future predictions | |
| forecast = fit.forecast(steps=days) | |
| # Format predictions with dates | |
| last_date = data.index[-1] | |
| dates = pd.date_range(start=last_date + timedelta(days=1), periods=days) | |
| forecast_df = pd.DataFrame({"Date": dates, "Price": forecast}) | |
| forecast_df["Date"] = forecast_df["Date"].dt.strftime("%B %d") # Format as "Month Day" | |
| forecast_df["Price"] = forecast_df["Price"].round(2) | |
| return forecast_df | |
| except Exception as e: | |
| return f"Error predicting prices: {e}" | |
| # Function to fetch news from top 5 crypto news sites and perform sentiment analysis | |
| def fetch_crypto_news(symbol): | |
| try: | |
| # List of RSS feeds for top 5 crypto news sites | |
| rss_feeds = [ | |
| "https://coindesk.com/feed/", | |
| "https://cointelegraph.com/rss", | |
| "https://cryptoslate.com/feed/", | |
| "https://www.newsbtc.com/feed/", | |
| "https://news.bitcoin.com/feed/" | |
| ] | |
| news_items = [] | |
| for feed_url in rss_feeds: | |
| feed = feedparser.parse(feed_url) | |
| for entry in feed.entries[:5]: # Limit to 5 articles per site | |
| if symbol.lower() in entry.title.lower() or symbol.lower() in entry.summary.lower(): | |
| # Perform sentiment analysis on the article title | |
| analysis = TextBlob(entry.title) | |
| sentiment = "Bullish" if analysis.sentiment.polarity > 0 else "Bearish" if analysis.sentiment.polarity < 0 else "Neutral" | |
| # Format the date as "Month Day" | |
| published_date = datetime.strptime(entry.published, "%a, %d %b %Y %H:%M:%S %z").strftime("%B %d") | |
| # Extract website name from the link | |
| website = entry.link.split("//")[1].split("/")[0] | |
| news_items.append({ | |
| "title": entry.title, | |
| "website": website, | |
| "sentiment": sentiment, | |
| "published": published_date, | |
| }) | |
| return news_items[:5] # Return top 5 articles | |
| except Exception as e: | |
| return f"Error fetching crypto news: {e}" | |
| # Gradio Interface | |
| def crypto_app(symbol): | |
| if symbol: | |
| # Fetch data | |
| data = get_crypto_data(symbol) | |
| if data.empty: | |
| return f"No data found for {symbol}. Please check the symbol and try again." | |
| else: | |
| # Ensure the DataFrame has enough rows | |
| if len(data) < 20: | |
| return f"Not enough data to calculate indicators. Only {len(data)} rows available. Please try a longer period." | |
| else: | |
| # Calculate probabilities | |
| probabilities, recent_data = calculate_probabilities(data) | |
| # Predict future prices | |
| price_predictions = predict_price(data) | |
| # Fetch crypto news and sentiment | |
| news_items = fetch_crypto_news(symbol) | |
| # Calculate Fibonacci Retracement levels | |
| fib_levels = calculate_fibonacci_levels(data) | |
| # Prepare output | |
| output = f"**{symbol} Pump/Dump Probabilities:**\n" | |
| for indicator, values in probabilities.items(): | |
| output += f"- **{indicator}**: Pump: {values['Pump']:.2f}%, Dump: {values['Dump']:.2f}%\n" | |
| output += "\n**Price Predictions (Next 7 Days):**\n" | |
| if isinstance(price_predictions, pd.DataFrame): | |
| output += price_predictions.to_string(index=False) | |
| else: | |
| output += price_predictions | |
| output += "\n\n**Fibonacci Retracement Levels:**\n" | |
| for level, price in fib_levels.items(): | |
| output += f"- **{level}**: ${price:.2f}\n" | |
| output += "\n**Latest Crypto News Sentiment:**\n" | |
| if isinstance(news_items, list): | |
| for news in news_items: | |
| output += f"- **{news['title']}** ({news['sentiment']}) - {news['website']}\n" | |
| else: | |
| output += news_items | |
| return output | |
| else: | |
| return "Please enter a cryptocurrency symbol." | |
| # Gradio Interface with Background Image | |
| iface = gr.Interface( | |
| fn=crypto_app, | |
| inputs=gr.Textbox(placeholder="Enter cryptocurrency symbol (e.g., ETH, BTC)"), | |
| outputs="text", | |
| title="Crypto AI Agent ππ", | |
| description="This app provides technical indicator-based predictions, price forecasts, and sentiment analysis for any cryptocurrency.", | |
| theme="default", # Use a theme that supports custom backgrounds | |
| css=".gradio-container { background-image: url('https://example.com/crypto-background.jpg'); background-size: cover; }", | |
| ) | |
| iface.launch() |