"""BBCA forecast desk. Every button press pulls fresh prices and refits. python app.py # real data from Yahoo Finance python app.py --demo # synthetic prices, works offline """ from __future__ import annotations import argparse import logging import os from pathlib import Path import gradio as gr from bbca import predict from bbca.data import DataError from bbca.model import MAX_HORIZON from ui import chart, render from ui.theme import FONTS_HEAD, build_theme log = logging.getLogger("bbca") HERE = Path(__file__).parent DEMO = os.environ.get("BBCA_DEMO") == "1" HEADER = """

BBCA.JK ยท SARIMA(0,1,0)(2,1,0)[5]

Where does BBCA close next?

Each press pulls the latest prices, refits the model and forecasts the next sessions. While the market is open it can start from the running price, so the forecast moves with the day.

""" def run(horizon: float, use_live: bool, run_no: int): run_no = int(run_no) + 1 try: horizon = int(min(max(int(horizon), 1), MAX_HORIZON)) pred = predict(horizon, use_live=bool(use_live), demo=DEMO) except DataError as exc: return render.error(str(exc)), chart.empty(), "", "", "", run_no except Exception: log.exception("forecast failed") return (render.error("Something went wrong while fitting the model. Try again."), chart.empty(), "", "", "", run_no) return ( render.board(pred, run_no), chart.build(pred), render.table(pred.forecast), render.backtest(pred.backtest), render.status(pred), run_no, ) def build_ui() -> gr.Blocks: with gr.Blocks(title="BBCA forecast desk") as ui: runs = gr.State(0) gr.HTML(HEADER) with gr.Row(elem_id="bb-controls"): horizon = gr.Slider(1, MAX_HORIZON, value=1, step=1, label="Sessions ahead", scale=3) use_live = gr.Checkbox(value=True, label="Use today's running price while the market is open", scale=3) go = gr.Button("Get fresh forecast", elem_id="bb-go", scale=2) board = gr.HTML(render.placeholder()) plot = gr.Plot(chart.empty(), elem_id="bb-chart", show_label=False) with gr.Row(equal_height=True, elem_id="bb-bottom"): table = gr.HTML() check = gr.HTML() status = gr.HTML() go.click(run, [horizon, use_live, runs], [board, plot, table, check, status, runs], concurrency_limit=2) return ui def main() -> None: global DEMO parser = argparse.ArgumentParser(description="BBCA forecast desk") parser.add_argument("--demo", action="store_true", help="use synthetic prices (offline)") parser.add_argument("--port", type=int, default=int(os.environ.get("GRADIO_SERVER_PORT", 7860))) # Local runs stay on 127.0.0.1. Hosting (the HF Space) sets GRADIO_SERVER_NAME=0.0.0.0. parser.add_argument("--host", default=os.environ.get("GRADIO_SERVER_NAME", "127.0.0.1")) args = parser.parse_args() DEMO = DEMO or args.demo logging.basicConfig(level=logging.INFO) build_ui().queue(max_size=16).launch( server_name=args.host, server_port=args.port, theme=build_theme(), css_paths=[HERE / "ui" / "style.css"], head=FONTS_HEAD, show_error=False, ) if __name__ == "__main__": main()