IDX-Chronos-API / app.py
omniverse1's picture
Update app.py
c67acf2 verified
raw
history blame
7.7 kB
import gradio as gr
import pandas as pd
import yfinance as yf
from utils import (
calculate_technical_indicators,
generate_trading_signals,
get_fundamental_data,
predict_prices,
create_price_chart,
create_technical_chart,
create_prediction_chart,
)
import warnings
warnings.filterwarnings("ignore")
def analyze_stock(symbol, prediction_days=30):
try:
if not symbol.strip():
raise ValueError("Please enter a valid stock symbol.")
if not symbol.endswith(".JK"):
symbol = symbol.upper() + ".JK"
stock = yf.Ticker(symbol)
data = stock.history(period="6mo", interval="1d")
if data.empty:
raise ValueError("No price data available for this stock.")
indicators = calculate_technical_indicators(data)
signals = generate_trading_signals(data, indicators)
fundamental_info = get_fundamental_data(stock)
predictions = predict_prices(data, prediction_days=prediction_days)
fig_price = create_price_chart(data, indicators)
fig_technical = create_technical_chart(data, indicators)
fig_prediction = create_prediction_chart(data, predictions)
return fundamental_info, indicators, signals, fig_price, fig_technical, fig_prediction, predictions
except Exception as e:
print(f"Error analyzing {symbol}: {e}")
empty_fig = gr.Plot.update(value=None)
empty_predictions = {
"high_30d": 0,
"low_30d": 0,
"change_pct": 0,
"summary": "Prediction unavailable.",
}
return {}, {}, {}, empty_fig, empty_fig, empty_fig, empty_predictions
def update_analysis(symbol, prediction_days):
(
fundamental_info,
indicators,
signals,
fig_price,
fig_technical,
fig_prediction,
predictions,
) = analyze_stock(symbol, prediction_days)
if not fundamental_info:
return (
"Unable to fetch stock data.",
"No technical signals available.",
gr.Plot.update(value=None),
gr.Plot.update(value=None),
gr.Plot.update(value=None),
"0",
"0",
"0",
"No prediction data available.",
)
fundamentals = f"""
<h4>COMPANY FUNDAMENTALS</h4>
<b>Name:</b> {fundamental_info.get('name', 'N/A')} ({symbol.upper()})<br>
<b>Current Price:</b> Rp{fundamental_info.get('current_price', 0):,.2f}<br>
<b>Market Cap:</b> {fundamental_info.get('market_cap', 0):,}<br>
<b>P/E Ratio:</b> {fundamental_info.get('pe_ratio', 0):.2f}<br>
<b>Dividend Yield:</b> {fundamental_info.get('dividend_yield', 0):.2f}%<br>
<b>Volume:</b> {fundamental_info.get('volume', 0):,}<br>
"""
details_list = "".join(
[f"<li>{line.strip()}</li>" for line in signals.get("details", "").split("\n") if line.strip()]
)
trading_signal = f"""
<h4>TECHNICAL SIGNAL SUMMARY</h4>
<b>Overall Trend:</b> {signals.get('overall', 'N/A')}<br>
<b>Signal Strength:</b> {signals.get('strength', 0):.2f}%<br>
<b>Support:</b> Rp{signals.get('support', 0):,.2f}<br>
<b>Resistance:</b> Rp{signals.get('resistance', 0):,.2f}<br>
<b>Stop Loss:</b> Rp{signals.get('stop_loss', 0):,.2f}<br><br>
<b>Detailed Signals:</b>
<ul style="margin-top: 8px; padding-left: 20px; line-height: 1.6;">
{details_list}
</ul>
"""
prediction = f"""
<h4>30-DAY AI FORECAST (CHRONOS-BOLT)</h4>
<b>Predicted High:</b> Rp{predictions.get('high_30d', 0):,.2f}<br>
<b>Predicted Low:</b> Rp{predictions.get('low_30d', 0):,.2f}<br>
<b>Expected Change:</b> {predictions.get('change_pct', 0):.2f}%<br><br>
<b>Model Insight:</b><br>{predictions.get('summary', 'No analysis available')}
"""
return (
fundamentals,
trading_signal,
fig_price,
fig_technical,
fig_prediction,
f"{predictions.get('high_30d', 0):,.2f}",
f"{predictions.get('low_30d', 0):,.2f}",
f"{predictions.get('change_pct', 0):.2f}%",
prediction,
)
with gr.Blocks(
title="REXPRO FINANCIAL AI DASHBOARD",
theme=gr.themes.Soft(primary_hue="blue", secondary_hue="gray"),
css="""
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
body {
background-color: #f9fafb;
color: #1e293b;
font-family: 'Inter', 'Segoe UI', Arial, sans-serif;
}
h1 {
color: #1e40af;
text-align: center;
font-weight: 700;
letter-spacing: 0.5px;
}
h2, h3, h4 {
color: #1e3a8a;
font-weight: 600;
margin-bottom: 6px;
}
.gr-markdown {
background-color: #ffffff;
border-radius: 10px;
border: 1px solid #e2e8f0;
padding: 16px;
}
.gr-button {
background-color: #2563eb !important;
color: white !important;
font-weight: 600;
border-radius: 8px;
padding: 10px 18px;
}
.gr-textbox input {
background-color: #ffffff !important;
color: #1e293b !important;
border: 1px solid #d1d5db !important;
}
.gr-slider {
background-color: #ffffff !important;
}
.gr-plot {
background-color: #ffffff;
border: 1px solid #e2e8f0;
border-radius: 10px;
}
ul {
margin: 0;
padding: 0 0 0 18px;
}
li {
margin-bottom: 4px;
}
""",
) as app:
gr.Markdown("# REXPRO FINANCIAL AI DASHBOARD")
gr.Markdown(
"A modern financial intelligence dashboard powered by **AI forecasting and technical analytics.**"
)
with gr.Row():
symbol = gr.Textbox(
label="STOCK SYMBOL (IDX)",
value="BBCA",
placeholder="Example: BBCA, TLKM, ADRO, BMRI",
interactive=True,
)
prediction_days = gr.Slider(
label="FORECAST PERIOD (DAYS)",
minimum=5,
maximum=60,
step=5,
value=30,
interactive=True,
)
analyze_button = gr.Button("RUN ANALYSIS")
gr.Markdown("---")
with gr.Row():
with gr.Column(scale=1):
fundamentals_output = gr.HTML()
with gr.Column(scale=1):
signal_output = gr.HTML()
gr.Markdown("---")
with gr.Tab("MARKET CHARTS"):
with gr.Row():
price_chart = gr.Plot(label="PRICE & MOVING AVERAGES")
technical_chart = gr.Plot(label="TECHNICAL INDICATORS OVERVIEW")
gr.Markdown("---")
prediction_chart = gr.Plot(label="AI FORECAST PROJECTION")
with gr.Tab("AI FORECAST SUMMARY"):
with gr.Row():
predicted_high = gr.Textbox(label="PREDICTED HIGH (30D)", interactive=False)
predicted_low = gr.Textbox(label="PREDICTED LOW (30D)", interactive=False)
predicted_change = gr.Textbox(label="EXPECTED CHANGE (%)", interactive=False)
gr.Markdown("---")
prediction_summary = gr.HTML()
analyze_button.click(
fn=update_analysis,
inputs=[symbol, prediction_days],
outputs=[
fundamentals_output,
signal_output,
price_chart,
technical_chart,
prediction_chart,
predicted_high,
predicted_low,
predicted_change,
prediction_summary,
],
)
if __name__ == "__main__":
app.launch(server_name="0.0.0.0", server_port=7860, ssr_mode=True)