Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import yfinance as yf | |
| import pandas as pd | |
| import numpy as np | |
| import feedparser | |
| import requests | |
| import base64 | |
| from sklearn.preprocessing import MinMaxScaler | |
| from tensorflow.keras.models import Sequential | |
| from tensorflow.keras.layers import LSTM, Dense, Dropout | |
| # 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 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 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 OBV | |
| def calculate_obv(data): | |
| obv = (np.sign(data['Close'].diff()) * data['Volume']).cumsum() | |
| return obv | |
| # Function to calculate probabilities for the next 12 hours | |
| def calculate_probabilities(data): | |
| # Calculate indicators on the entire dataset | |
| data['RSI'] = calculate_rsi(data) | |
| data['Upper_Band'], data['Lower_Band'] = calculate_bollinger_bands(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['OBV'] = calculate_obv(data) | |
| # Use the most recent values for predictions | |
| probabilities = { | |
| "RSI": {"Value": data['RSI'].iloc[-1], "Pump": 0, "Dump": 0}, | |
| "Bollinger Bands": {"Value": data['Close'].iloc[-1], "Pump": 0, "Dump": 0}, | |
| "MACD": {"Value": data['MACD'].iloc[-1], "Pump": 0, "Dump": 0}, | |
| "EMA": {"Value": data['EMA_50'].iloc[-1], "Pump": 0, "Dump": 0}, | |
| "OBV": {"Value": data['OBV'].iloc[-1], "Pump": 0, "Dump": 0}, | |
| } | |
| # RSI | |
| rsi = data['RSI'].iloc[-1] | |
| 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 | |
| # Bollinger Bands | |
| close = data['Close'].iloc[-1] | |
| upper_band = data['Upper_Band'].iloc[-1] | |
| lower_band = data['Lower_Band'].iloc[-1] | |
| 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 | |
| # MACD | |
| macd = data['MACD'].iloc[-1] | |
| macd_signal = data['MACD_Signal'].iloc[-1] | |
| 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 = data['EMA_50'].iloc[-1] | |
| ema_long = data['EMA_200'].iloc[-1] | |
| 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 | |
| # OBV | |
| obv = data['OBV'].iloc[-1] | |
| 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 | |
| # Normalize Pump and Dump probabilities to sum to 100% | |
| for indicator in probabilities: | |
| pump_prob = probabilities[indicator]["Pump"] | |
| dump_prob = probabilities[indicator]["Dump"] | |
| # If pump probability is set, normalize dump | |
| if pump_prob > 0: | |
| probabilities[indicator]["Dump"] = 100 - pump_prob | |
| # If dump probability is set, normalize pump | |
| if dump_prob > 0: | |
| probabilities[indicator]["Pump"] = 100 - dump_prob | |
| return probabilities, data.iloc[-1] | |
| # Function to calculate weighted probabilities | |
| def calculate_weighted_probabilities(probabilities): | |
| weightages = { | |
| "RSI": 0.20, | |
| "Bollinger Bands": 0.20, | |
| "MACD": 0.25, | |
| "EMA": 0.15, | |
| "OBV": 0.20 | |
| } | |
| # Initialize final probabilities | |
| final_probabilities = {"Pump": 0, "Dump": 0} | |
| # Calculate weighted probabilities | |
| for indicator, values in probabilities.items(): | |
| pump_prob = values["Pump"] * weightages[indicator] | |
| dump_prob = values["Dump"] * weightages[indicator] | |
| final_probabilities["Pump"] += pump_prob | |
| final_probabilities["Dump"] += dump_prob | |
| # Normalize the final probabilities to ensure they sum to 100% | |
| total = final_probabilities["Pump"] + final_probabilities["Dump"] | |
| # Handle cases where the total sum of probabilities is zero | |
| if total == 0: | |
| final_probabilities["Pump"] = 50 | |
| final_probabilities["Dump"] = 50 | |
| else: | |
| final_probabilities["Pump"] = (final_probabilities["Pump"] / total) * 100 | |
| final_probabilities["Dump"] = (final_probabilities["Dump"] / total) * 100 | |
| # Debugging the final probabilities to ensure they sum up to 100% | |
| print(f"Final Pump Probability: {final_probabilities['Pump']}%") | |
| print(f"Final Dump Probability: {final_probabilities['Dump']}%") | |
| return final_probabilities | |
| # Function to fetch news data from Google News RSS feeds | |
| def fetch_news(coin_name): | |
| try: | |
| url = f"https://news.google.com/rss/search?q={coin_name}+cryptocurrency" | |
| feed = feedparser.parse(url) | |
| news_items = [] | |
| for entry in feed.entries[:5]: # Limit to 5 news items | |
| news_items.append({ | |
| "title": entry.title, | |
| "link": entry.link, | |
| "published": entry.published, | |
| }) | |
| return news_items | |
| except Exception as e: | |
| st.error(f"Error fetching news: {e}") | |
| return [] | |
| # Prepare data for LSTM Model | |
| def prepare_lstm_data(df, seq_len=60): | |
| data = df['Price'].values.reshape(-1, 1) | |
| scaler = MinMaxScaler(feature_range=(0, 1)) | |
| scaled_data = scaler.fit_transform(data) | |
| sequences, labels = [], [] | |
| for i in range(len(scaled_data) - seq_len): | |
| sequences.append(scaled_data[i:i + seq_len]) | |
| labels.append(scaled_data[i + seq_len]) | |
| return np.array(sequences), np.array(labels), scaler | |
| # Build and train LSTM model | |
| def build_lstm_model(input_shape): | |
| model = Sequential([ | |
| LSTM(units=50, return_sequences=True, input_shape=input_shape), | |
| Dropout(0.2), | |
| LSTM(units=50, return_sequences=False), | |
| Dropout(0.2), | |
| Dense(units=25), | |
| Dense(units=1) | |
| ]) | |
| model.compile(optimizer='adam', loss='mean_squared_error') | |
| return model | |
| # Calculate prediction based of LTSM model learning | |
| def calculate_prediction_with_ltsm(symbol="BTC", period="5d", interval="5m"): | |
| st.write("**Fetched Data...") | |
| data = get_crypto_data(symbol, period, interval) | |
| prices = [(pd.to_datetime(index, unit='m'), price) for index, price in data['Close'].items()] | |
| df = pd.DataFrame(prices, columns=['Date', 'Price']) | |
| st.write("**Preparing data for LTSM Model training......(processing)...") | |
| X, Y, scaler = prepare_lstm_data(df) | |
| st.write("**Build LTSM Model with X shape data.........(processing)...") | |
| model = build_lstm_model((X.shape[1], 1)) | |
| # Train the model | |
| st.write("**Train LTSM Model with X,Y shape data with batch_size(32), epochs(10)............(processing)...") | |
| model.fit(X, Y, batch_size=32, epochs=10) | |
| # Predict the next price point | |
| st.write("**Sequence LTSM Model with X,Y shape data with batch_size(32), epochs(10)...............(processing)...") | |
| last_sequence = X[-1].reshape(1, X.shape[1], 1) | |
| st.write("**Predict realtime price with LTSM Model trained with X,Y shape data with batch_size(32), epochs(10)..................(processing)...") | |
| scaled_prediction = model.predict(last_sequence) | |
| predicted_price = scaler.inverse_transform(scaled_prediction) | |
| return predicted_price | |
| # Streamlit App | |
| st.set_page_config(page_title="Crypto Insights ", layout="wide") | |
| # Add styled title with specific color | |
| st.markdown( | |
| """ | |
| <div style="text-align: center; margin-top: 5px; margin-left: 20px"> | |
| <h1 style="font-size: 2.5em; color: #FFD700;">Crypto Vision</h1> | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| # Add styled subtitle with lines on both sides and reduced gap | |
| st.markdown( | |
| """ | |
| <div style="display: flex; align-items: center; justify-content: center; margin-top: 0px;"> | |
| <hr style="width: 20%; border: 1px solid #ccc; margin: 0 5px; height: 1px;"> | |
| <span style="font-size: 1.2em; color: gray; margin: 0;">MARKET ANALYZER</span> | |
| <hr style="width: 20%; border: 1px solid #ccc; margin: 0 5px; height: 1px;"> | |
| </div> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| # Function to add a background image to the app | |
| def add_background_to_main(image_file): | |
| page_bg_img = f""" | |
| <style> | |
| /* Apply background image to the main container */ | |
| [data-testid="stAppViewContainer"] {{ | |
| background-image: url('data:image/jpeg;base64,{image_file}'); | |
| background-size: cover; | |
| background-position: center; | |
| background-repeat: no-repeat; | |
| background-attachment: fixed; | |
| min-height: 100vh; | |
| }} | |
| </style> | |
| """ | |
| st.markdown(page_bg_img, unsafe_allow_html=True) | |
| # Function to encode the image to Base64 | |
| def get_base64_of_image(image_path): | |
| with open(image_path, "rb") as img_file: | |
| return base64.b64encode(img_file.read()).decode() | |
| # Add the background image (ensure the image file is in the correct path) | |
| image_path = "black.jpeg" # Replace with your image file name | |
| try: | |
| encoded_image = get_base64_of_image(image_path) | |
| add_background_to_main(encoded_image) | |
| except FileNotFoundError: | |
| st.warning(f"Background image '{image_path}' not found. Please check the file path.") | |
| st.markdown(""" | |
| Welcome to the "Crypto Vision". This tool provides real-time predictions | |
| and insights on cryptocurrency price movements using advanced technical indicators like RSI, | |
| Bollinger Bands, MACD, and more. Simply enter the cryptocurrency symbol, and our tool will analyze the | |
| market data, calculate indicators, and provide you with the probabilities of price movements (pump or dump). | |
| Stay ahead in your crypto trading with this powerful tool! | |
| """) | |
| # Add CSS to make the sidebar fixed and apply hover effect on buttons | |
| st.markdown( | |
| """ | |
| <style> | |
| /* Make the sidebar always visible and fixed */ | |
| [data-testid="stSidebar"] { | |
| width: 300px; | |
| min-width: 300px; | |
| max-width: 300px; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| bottom: 0; | |
| background-color: #2d2d2d; | |
| padding-top: 20px; | |
| z-index: 9999; | |
| } | |
| [data-testid="collapsedControl"] { | |
| display: none; | |
| } | |
| /* Sidebar button hover effect */ | |
| .css-1emrehy.edgvbvh3 { | |
| background-color: #3e3e3e; | |
| color: #fff; | |
| transition: all 0.3s ease; | |
| } | |
| .css-1emrehy.edgvbvh3:hover { | |
| background-color: #FFD700; | |
| color: black; | |
| } | |
| /* Optional: Add padding for better spacing */ | |
| .css-1emrehy.edgvbvh3 { | |
| margin-bottom: 15px; | |
| border-radius: 5px; | |
| padding: 12px; | |
| font-size: 16px; | |
| font-weight: bold; | |
| } | |
| /* Customize the sidebar header */ | |
| .css-1r6slb0 { | |
| color: #FFD700; | |
| font-size: 20px; | |
| font-weight: bold; | |
| } | |
| /* Customizing the text input inside the sidebar */ | |
| .stTextInput input { | |
| background-color: #3e3e3e; | |
| color: #fff; | |
| border: 1px solid #FFD700; | |
| border-radius: 5px; | |
| padding: 10px; | |
| } | |
| /* Customize the buttons inside the sidebar */ | |
| .stButton button { | |
| background-color: #3e3e3e; | |
| color: #fff; | |
| border-radius: 5px; | |
| padding: 12px; | |
| font-size: 16px; | |
| font-weight: bold; | |
| } | |
| .stButton button:hover { | |
| background-color: #C0C0C0; | |
| color: black; | |
| } | |
| </style> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| # Sidebar for user input | |
| st.sidebar.header("Cryptocurrency Symbol") | |
| symbol = st.sidebar.text_input("Enter Cryptocurrency Symbol (e.g., BTC):", "BTC") | |
| # Add buttons for navigation | |
| show_news_button = st.sidebar.button("Show Latest News") | |
| show_data_button = st.sidebar.button("Show Data and Indicators") | |
| predict_lstm_button = st.sidebar.button("Predict by training LSTM Model") | |
| # Fetch data and news when the button is clicked | |
| if show_data_button: | |
| if symbol: | |
| # Fetch data | |
| data = get_crypto_data(symbol) | |
| if data.empty: | |
| st.error(f"No data found for {symbol}. Please check the symbol and try again.") | |
| else: | |
| # Display fetched data | |
| st.write("**Fetched Data:**") | |
| st.dataframe(data.tail()) | |
| # Ensure the DataFrame has enough rows | |
| if len(data) < 20: | |
| st.warning(f"Not enough data to calculate indicators. Only {len(data)} rows available. Please try a longer period.") | |
| else: | |
| # Calculate probabilities for the next 12 hours | |
| probabilities, recent_data = calculate_probabilities(data) | |
| # Create a DataFrame for the indicator values | |
| indicator_values = { | |
| "Indicator": ["RSI", "Bollinger Bands", "MACD", "EMA", "OBV"], | |
| "Value": [probabilities["RSI"]["Value"], probabilities["Bollinger Bands"]["Value"], probabilities["MACD"]["Value"], probabilities["EMA"]["Value"], probabilities["OBV"]["Value"]], | |
| } | |
| # Convert dictionary to a DataFrame | |
| df_indicators = pd.DataFrame(indicator_values) | |
| # Display indicator values in table format | |
| st.write("### **Indicators and Probabilities Table**:") | |
| st.dataframe(df_indicators) | |
| # Calculate weighted combined probabilities | |
| weighted_probabilities = calculate_weighted_probabilities(probabilities) | |
| # Display final combined probability predictions | |
| st.write("### **Final Predicted Probabilities for the Next 12 Hours:**") | |
| st.write(f"- **Pump Probability**: {weighted_probabilities['Pump']:.2f}%") | |
| st.write(f"- **Dump Probability**: {weighted_probabilities['Dump']:.2f}%") | |
| elif show_news_button: | |
| if symbol: | |
| # Fetch news | |
| news_items = fetch_news(symbol) | |
| if news_items: | |
| st.write("### Latest News:") | |
| for news_item in news_items: | |
| st.markdown(f"**{news_item['title']}**: [Read More]({news_item['link']})") | |
| st.write(f"Published on: {news_item['published']}") | |
| else: | |
| st.warning(f"No news found for {symbol}. Please try again later.") | |
| elif predict_lstm_button: | |
| if symbol: | |
| # Call the LSTM prediction function based on last 5 days with 5 interval of closing data | |
| st.markdown( | |
| """ | |
| <h3 style="color: #FFD700;">Final Predicted Value Learned by training a LSTM Model</h3> | |
| <p style="font-size: 1.5em; color: #32CD32;"> | |
| ***Based on the last 5 days with 5-minute intervals of closing data*** | |
| </p> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |
| period = "5d" | |
| interval = "5m" | |
| predicted_price = calculate_prediction_with_ltsm(symbol, period, interval) | |
| #st.write("### **Final Predicted value by learned LTSM model based on last 5 days with 5 interval of closing data** ###") | |
| #st.write(f"**Predicted next realtime price: ${predicted_price[0][0]:.10f}**") | |
| st.markdown( | |
| f""" | |
| <p style="font-size: 2em; font-weight: bold; color: #FF4500;"> | |
| Predicted Next Realtime Price: ${predicted_price[0][0]:.10f} | |
| </p> | |
| """, | |
| unsafe_allow_html=True | |
| ) | |