Spaces:
Sleeping
Sleeping
File size: 5,542 Bytes
a47157b 87caa42 fb158f8 9a043ee a47157b fb158f8 d45247a fb158f8 01fa4a1 fb158f8 01fa4a1 fb158f8 01fa4a1 fb158f8 01fa4a1 1eede32 fb158f8 77f52f4 fb158f8 5e546fa 01fa4a1 fb158f8 01fa4a1 fb158f8 9a043ee 01fa4a1 fb158f8 01fa4a1 9a043ee fb158f8 d45247a 01fa4a1 d45247a 01fa4a1 0a114f9 fb158f8 01fa4a1 1eede32 fb158f8 01fa4a1 d45247a fb158f8 9a043ee 01fa4a1 dce0ea3 fb158f8 01fa4a1 a47157b 87caa42 01fa4a1 fb158f8 01fa4a1 fb158f8 431a4a5 fb158f8 a47157b 01fa4a1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
import gradio as gr
import pandas as pd
import yfinance as yf
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from statsforecast import StatsForecast
from statsforecast.models import AutoARIMA
def calculate_indicators(df):
# RSI Calculation
delta = df['Close'].diff()
gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
rs = gain / loss
df['RSI'] = 100 - (100 / (1 + rs))
# MACD Calculation
df['EMA12'] = df['Close'].ewm(span=12, adjust=False).mean()
df['EMA26'] = df['Close'].ewm(span=26, adjust=False).mean()
df['MACD'] = df['EMA12'] - df['EMA26']
df['Signal'] = df['MACD'].ewm(span=9, adjust=False).mean()
return df
def get_pro_chart(df, forecast_df, ticker):
# Professional Subplots: Price + Indicators
fig = make_subplots(rows=3, cols=1, shared_xaxes=True,
vertical_spacing=0.05, row_heights=[0.5, 0.25, 0.25],
subplot_titles=(f"{ticker} Forecast & Confidence Zone", "RSI Momentum", "MACD Trend"))
# --- 1. Price + Forecast + CONFIDENCE ZONE ---
# Shaded Confidence Area (AutoARIMA-hi-80 and AutoARIMA-lo-80)
fig.add_trace(go.Scatter(
x=forecast_df['ds'].tolist() + forecast_df['ds'].tolist()[::-1],
y=forecast_df['AutoARIMA-hi-80'].tolist() + forecast_df['AutoARIMA-lo-80'].tolist()[::-1],
fill='toself',
fillcolor='rgba(0, 210, 255, 0.2)',
line=dict(color='rgba(255,255,255,0)'),
hoverinfo="skip",
showlegend=True,
name='80% Confidence'
), row=1, col=1)
# Historical Price
fig.add_trace(go.Scatter(x=df.index, y=df['Close'], name='Historical Price', line=dict(color='#00d2ff', width=2)), row=1, col=1)
# AI Mean Forecast Line
fig.add_trace(go.Scatter(x=forecast_df['ds'], y=forecast_df['AutoARIMA'], name='AI Target', line=dict(color='#F23645', dash='dot')), row=1, col=1)
# --- 2. RSI ---
fig.add_trace(go.Scatter(x=df.index, y=df['RSI'], name='RSI', line=dict(color='#FF9800')), row=2, col=1)
fig.add_hline(y=70, line_dash="dot", line_color="red", row=2, col=1)
fig.add_hline(y=30, line_dash="dot", line_color="green", row=2, col=1)
# --- 3. MACD ---
fig.add_trace(go.Bar(x=df.index, y=df['MACD'] - df['Signal'], name='Momentum', marker_color='#9d50bb'), row=3, col=1)
# Styling to match your Aether UI
fig.update_layout(
template='plotly_dark',
height=800,
showlegend=True,
paper_bgcolor='rgba(0,0,0,0)', # Transparent to show your terminal background
plot_bgcolor='rgba(0,0,0,0)',
font=dict(family="Lato", size=12)
)
fig.update_xaxes(showgrid=False, zeroline=False)
fig.update_yaxes(showgrid=False, zeroline=False)
return fig
def analyze(ticker, horizon):
try:
# Step 1: Data
stock = yf.Ticker(ticker)
df = stock.history(period="1y")
if df.empty: return None, "Symbol Error"
info = stock.info
target_high = info.get('targetHighPrice', 'N/A')
current_price = df['Close'].iloc[-1]
# Step 2: Indicators
df = calculate_indicators(df)
# Step 3: StatsForecast with Levels
data = df.reset_index()[['Date', 'Close']]
data.columns = ['ds', 'y']
data['unique_id'] = ticker
sf = StatsForecast(models=[AutoARIMA(season_length=5)], freq='B')
sf.fit(data)
# We request 80% level to get the 'lo-80' and 'hi-80' columns
forecast = sf.predict(h=horizon, level=[80])
forecast = forecast.reset_index()
# Step 4: Signal Analysis
rsi_val = df['RSI'].iloc[-1]
rsi_stat = "OVERSOLD" if rsi_val < 30 else "OVERBOUGHT" if rsi_val > 70 else "NEUTRAL"
signal_html = f"""
<div style='background: rgba(255,255,255,0.05); padding: 20px; border-radius: 15px; border: 1px solid rgba(255,255,255,0.1); font-family: "Lato", sans-serif;'>
<p style='margin:0; color:#888; font-size:12px;'>CURRENT VALUE</p>
<h2 style='margin:0; color:#00d2ff;'>${current_price:.2f}</h2>
<hr style='border:0; border-top:1px solid #333; margin:15px 0;'>
<p>RSI Analysis: <b style='color:#FF9800;'>{rsi_stat} ({rsi_val:.1f})</b></p>
<p>AI Forecast ({horizon}d): <b style='color:#F23645;'>${forecast['AutoARIMA'].iloc[-1]:.2f}</b></p>
<p style='font-size:11px; color:#555;'>Confidence Zone: ${forecast['AutoARIMA-lo-80'].iloc[-1]:.2f} - ${forecast['AutoARIMA-hi-80'].iloc[-1]:.2f}</p>
</div>
"""
return get_pro_chart(df, forecast, ticker), signal_html
except Exception as e:
return None, f"<p style='color:red;'>Error: {str(e)}</p>"
# --- UI Layout ---
with gr.Blocks(theme=gr.themes.Default(primary_hue="blue", secondary_hue="slate")) as demo:
gr.Markdown("<h1 style='text-align: center; letter-spacing: 5px;'>AETHER BACKEND ENGINE</h1>")
with gr.Row():
with gr.Column(scale=1):
t_in = gr.Textbox(label="Ticker", value="NVDA")
h_in = gr.Slider(7, 90, value=30, label="Forecast Days")
btn = gr.Button("UPDATE ENGINE", variant="primary")
info_out = gr.HTML()
with gr.Column(scale=4):
plot_out = gr.Plot()
btn.click(analyze, [t_in, h_in], [plot_out, info_out])
if __name__ == "__main__":
demo.launch() |