Spaces:
Running
Running
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() |