|
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 |
|
|
|
|
|
def get_crypto_data(symbol, period="30d", interval="1h"): |
|
crypto = yf.Ticker(f"{symbol}-USD") |
|
data = crypto.history(period=period, interval=interval) |
|
return data |
|
|
|
|
|
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 |
|
|
|
|
|
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 |
|
|
|
|
|
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 |
|
|
|
|
|
def calculate_ema(data, period=20): |
|
return data['Close'].ewm(span=period, adjust=False).mean() |
|
|
|
|
|
def calculate_obv(data): |
|
obv = (np.sign(data['Close'].diff()) * data['Volume']).cumsum() |
|
return obv |
|
|
|
|
|
def calculate_probabilities(data): |
|
|
|
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) |
|
|
|
|
|
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 = data['RSI'].iloc[-1] |
|
if rsi < 25: |
|
probabilities["RSI"]["Pump"] = 90 |
|
elif 25 <= rsi < 30: |
|
probabilities["RSI"]["Pump"] = 60 |
|
elif 70 < rsi <= 75: |
|
probabilities["RSI"]["Dump"] = 60 |
|
elif rsi > 75: |
|
probabilities["RSI"]["Dump"] = 90 |
|
|
|
|
|
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 |
|
elif lower_band < close <= lower_band * 1.05: |
|
probabilities["Bollinger Bands"]["Pump"] = 60 |
|
elif upper_band * 0.95 <= close < upper_band: |
|
probabilities["Bollinger Bands"]["Dump"] = 60 |
|
elif close >= upper_band: |
|
probabilities["Bollinger Bands"]["Dump"] = 90 |
|
|
|
|
|
macd = data['MACD'].iloc[-1] |
|
macd_signal = data['MACD_Signal'].iloc[-1] |
|
if macd > macd_signal and macd > 0: |
|
probabilities["MACD"]["Pump"] = 90 |
|
elif macd > macd_signal and macd <= 0: |
|
probabilities["MACD"]["Pump"] = 60 |
|
elif macd < macd_signal and macd >= 0: |
|
probabilities["MACD"]["Dump"] = 60 |
|
elif macd < macd_signal and macd < 0: |
|
probabilities["MACD"]["Dump"] = 90 |
|
|
|
|
|
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 |
|
elif ema_short > ema_long and close <= ema_short: |
|
probabilities["EMA"]["Pump"] = 60 |
|
elif ema_short < ema_long and close >= ema_short: |
|
probabilities["EMA"]["Dump"] = 60 |
|
elif ema_short < ema_long and close < ema_short: |
|
probabilities["EMA"]["Dump"] = 90 |
|
|
|
|
|
obv = data['OBV'].iloc[-1] |
|
if obv > 100000: |
|
probabilities["OBV"]["Pump"] = 90 |
|
elif 50000 < obv <= 100000: |
|
probabilities["OBV"]["Pump"] = 60 |
|
elif -100000 <= obv < -50000: |
|
probabilities["OBV"]["Dump"] = 60 |
|
elif obv < -100000: |
|
probabilities["OBV"]["Dump"] = 90 |
|
|
|
|
|
for indicator in probabilities: |
|
pump_prob = probabilities[indicator]["Pump"] |
|
dump_prob = probabilities[indicator]["Dump"] |
|
|
|
|
|
if pump_prob > 0: |
|
probabilities[indicator]["Dump"] = 100 - pump_prob |
|
|
|
|
|
if dump_prob > 0: |
|
probabilities[indicator]["Pump"] = 100 - dump_prob |
|
|
|
return probabilities, data.iloc[-1] |
|
|
|
|
|
|
|
def calculate_weighted_probabilities(probabilities): |
|
weightages = { |
|
"RSI": 0.20, |
|
"Bollinger Bands": 0.20, |
|
"MACD": 0.25, |
|
"EMA": 0.15, |
|
"OBV": 0.20 |
|
} |
|
|
|
|
|
final_probabilities = {"Pump": 0, "Dump": 0} |
|
|
|
|
|
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 |
|
|
|
|
|
total = final_probabilities["Pump"] + final_probabilities["Dump"] |
|
|
|
|
|
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 |
|
|
|
|
|
print(f"Final Pump Probability: {final_probabilities['Pump']}%") |
|
print(f"Final Dump Probability: {final_probabilities['Dump']}%") |
|
|
|
return final_probabilities |
|
|
|
|
|
|
|
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]: |
|
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 [] |
|
|
|
|
|
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 |
|
|
|
|
|
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 |
|
|
|
|
|
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)) |
|
|
|
|
|
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) |
|
|
|
|
|
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 |
|
|
|
|
|
st.set_page_config(page_title="Crypto Insights ", layout="wide") |
|
|
|
|
|
|
|
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 |
|
) |
|
|
|
|
|
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 |
|
) |
|
|
|
|
|
|
|
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) |
|
|
|
|
|
def get_base64_of_image(image_path): |
|
with open(image_path, "rb") as img_file: |
|
return base64.b64encode(img_file.read()).decode() |
|
|
|
|
|
image_path = "black.jpeg" |
|
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! |
|
""") |
|
|
|
|
|
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 |
|
) |
|
|
|
|
|
|
|
st.sidebar.header("Cryptocurrency Symbol") |
|
symbol = st.sidebar.text_input("Enter Cryptocurrency Symbol (e.g., BTC):", "BTC") |
|
|
|
|
|
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") |
|
|
|
|
|
|
|
if show_data_button: |
|
if symbol: |
|
|
|
data = get_crypto_data(symbol) |
|
if data.empty: |
|
st.error(f"No data found for {symbol}. Please check the symbol and try again.") |
|
else: |
|
|
|
st.write("**Fetched Data:**") |
|
st.dataframe(data.tail()) |
|
|
|
|
|
if len(data) < 20: |
|
st.warning(f"Not enough data to calculate indicators. Only {len(data)} rows available. Please try a longer period.") |
|
else: |
|
|
|
probabilities, recent_data = calculate_probabilities(data) |
|
|
|
|
|
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"]], |
|
} |
|
|
|
|
|
df_indicators = pd.DataFrame(indicator_values) |
|
|
|
|
|
st.write("### **Indicators and Probabilities Table**:") |
|
st.dataframe(df_indicators) |
|
|
|
|
|
weighted_probabilities = calculate_weighted_probabilities(probabilities) |
|
|
|
|
|
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: |
|
|
|
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: |
|
|
|
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.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 |
|
) |
|
|