Update scripts/app.py
Browse files- scripts/app.py +113 -37
scripts/app.py
CHANGED
|
@@ -528,59 +528,135 @@ def get_recent_transactions():
|
|
| 528 |
|
| 529 |
custom_css = """
|
| 530 |
.metric-box { background-color: #1f2937; padding: 20px; border-radius: 12px; border: 1px solid #374151; text-align: center; }
|
| 531 |
-
.metric-label { font-size: 1.1em; color: #9ca3af; }
|
| 532 |
.metric-value { font-size: 2.2em; font-weight: 700; color: #e5e7eb; }
|
|
|
|
| 533 |
"""
|
| 534 |
|
| 535 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 536 |
gr.HTML("""<script>function forceDark(){document.body.classList.add('dark');} forceDark(); setTimeout(forceDark, 500);</script>""")
|
|
|
|
| 537 |
gr.Markdown("# ๐ง Deep RL & LLM Portfolio Manager")
|
| 538 |
|
| 539 |
with gr.Tabs():
|
| 540 |
-
|
| 541 |
-
|
| 542 |
-
|
| 543 |
-
gr.HTML(f"<div class='metric-box'><div class='metric-label'>Simulated Net Worth</div><div class='metric-value'>{nw}</div></div>")
|
| 544 |
-
gr.HTML(f"<div class='metric-box'><div class='metric-label'>24h Change</div><div class='metric-value'>{chg}</div></div>")
|
| 545 |
with gr.Row():
|
| 546 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 547 |
with gr.Row():
|
| 548 |
-
with gr.Column(scale=
|
| 549 |
-
|
| 550 |
|
| 551 |
-
|
| 552 |
-
run_btn = gr.Button("๐ Run Analysis", variant="primary")
|
| 553 |
-
stat = gr.Textbox(label="Status", lines=1)
|
| 554 |
with gr.Row():
|
|
|
|
|
|
|
| 555 |
with gr.Column(scale=2):
|
| 556 |
-
|
| 557 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 558 |
with gr.Column(scale=3):
|
| 559 |
-
|
| 560 |
-
|
| 561 |
-
|
| 562 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 563 |
with gr.Row():
|
| 564 |
with gr.Column(scale=1):
|
| 565 |
-
|
| 566 |
-
|
| 567 |
-
|
| 568 |
-
|
| 569 |
-
|
| 570 |
-
|
| 571 |
-
|
| 572 |
-
|
| 573 |
-
|
| 574 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 575 |
with gr.Row():
|
| 576 |
-
|
| 577 |
-
|
| 578 |
-
|
| 579 |
-
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 584 |
|
| 585 |
if __name__ == "__main__":
|
| 586 |
demo.queue().launch(server_name="0.0.0.0", server_port=7860, debug=True, share=True)
|
|
|
|
| 528 |
|
| 529 |
custom_css = """
|
| 530 |
.metric-box { background-color: #1f2937; padding: 20px; border-radius: 12px; border: 1px solid #374151; text-align: center; }
|
| 531 |
+
.metric-label { font-size: 1.1em; color: #9ca3af; margin-bottom: 5px; }
|
| 532 |
.metric-value { font-size: 2.2em; font-weight: 700; color: #e5e7eb; }
|
| 533 |
+
.disclaimer-box { background-color: #374151; padding: 15px; border-radius: 8px; border-left: 4px solid #f59e0b; color: #d1d5db; font-size: 0.9em; margin-bottom: 20px; }
|
| 534 |
"""
|
| 535 |
|
| 536 |
+
theme = gr.themes.Soft(primary_hue="emerald", secondary_hue="slate", neutral_hue="zinc").set(
|
| 537 |
+
body_background_fill="#111827", block_background_fill="#1f2937", block_border_width="1px", block_border_color="#374151"
|
| 538 |
+
)
|
| 539 |
+
|
| 540 |
+
with gr.Blocks(theme=theme, css=custom_css, title="Deep RL Portfolio Manager") as demo:
|
| 541 |
gr.HTML("""<script>function forceDark(){document.body.classList.add('dark');} forceDark(); setTimeout(forceDark, 500);</script>""")
|
| 542 |
+
|
| 543 |
gr.Markdown("# ๐ง Deep RL & LLM Portfolio Manager")
|
| 544 |
|
| 545 |
with gr.Tabs():
|
| 546 |
+
# ================= TAB 1: DASHBOARD (RESTORED) =================
|
| 547 |
+
with gr.TabItem("๐ Live Dashboard"):
|
| 548 |
+
# Metrics Row
|
|
|
|
|
|
|
| 549 |
with gr.Row():
|
| 550 |
+
# MOVED THIS LINE INSIDE THE TAB
|
| 551 |
+
nw_val, dc_val = get_dashboard_metrics()
|
| 552 |
+
with gr.Column(elem_classes=["metric-box"]):
|
| 553 |
+
gr.HTML(f"<div class='metric-label'>Current Net Worth</div><div class='metric-value'>{nw_val}</div>")
|
| 554 |
+
with gr.Column(elem_classes=["metric-box"]):
|
| 555 |
+
gr.HTML(f"<div class='metric-label'>24h Change</div><div class='metric-value' style='color: #10b981;'>{daily_change}</div>")
|
| 556 |
+
|
| 557 |
+
# Main Chart row
|
| 558 |
with gr.Row():
|
| 559 |
+
with gr.Column(scale=3):
|
| 560 |
+
history_chart = gr.Plot(value=get_portfolio_history_plot(), label="Net Worth History")
|
| 561 |
|
| 562 |
+
# Bottom Row: Allocations and Transactions
|
|
|
|
|
|
|
| 563 |
with gr.Row():
|
| 564 |
+
with gr.Column(scale=1):
|
| 565 |
+
allocation_chart = gr.Plot(value=get_current_allocation_plot(), label="Current Allocation")
|
| 566 |
with gr.Column(scale=2):
|
| 567 |
+
gr.Markdown("### Recent Transactions")
|
| 568 |
+
transactions_table = gr.Dataframe(value=get_recent_transactions(), interactive=False, wrap=True)
|
| 569 |
+
|
| 570 |
+
# ================= TAB 2: FORECAST (UPDATED with XAI) =================
|
| 571 |
+
with gr.TabItem("๐ฎ Forecast & AI Analysis"):
|
| 572 |
+
gr.Markdown("### Generate Tomorrow's Portfolio Strategy")
|
| 573 |
+
run_btn = gr.Button("๐ Run Overnight Analysis", variant="primary", size="lg")
|
| 574 |
+
status_output = gr.Textbox(label="System Status", placeholder="Ready...", interactive=False, lines=1)
|
| 575 |
+
gr.Markdown("---")
|
| 576 |
+
|
| 577 |
+
with gr.Row():
|
| 578 |
+
# Left Column: Allocations & XAI Plot
|
| 579 |
+
with gr.Column(scale=2):
|
| 580 |
+
gr.Markdown("### ๐ Suggested Position")
|
| 581 |
+
allocation_output = gr.Dataframe(headers=["Asset", "Allocation"], datatype=["str", "str"], interactive=False)
|
| 582 |
+
|
| 583 |
+
# NEW: XAI Feature Importance Plot
|
| 584 |
+
gr.Markdown("### ๐ง Why did the agent choose this?")
|
| 585 |
+
xai_output_plot = gr.Plot(label="Top Influential Factors (XAI)", show_label=False)
|
| 586 |
+
|
| 587 |
+
# Right Column: AI Analysis Report
|
| 588 |
with gr.Column(scale=3):
|
| 589 |
+
analysis_report_html = gr.HTML(label="AI Risk Analysis Report")
|
| 590 |
+
|
| 591 |
+
# Updated click event with new XAI output
|
| 592 |
+
run_btn.click(
|
| 593 |
+
fn=predict_and_analyze,
|
| 594 |
+
inputs=None,
|
| 595 |
+
outputs=[status_output, allocation_output, xai_output_plot, analysis_report_html]
|
| 596 |
+
)
|
| 597 |
+
|
| 598 |
+
# ================= TAB 3: HISTORICAL DATA ANALYST =================
|
| 599 |
+
with gr.TabItem("๐
Historical Data Analyst"):
|
| 600 |
+
gr.Markdown("### Analyze Past Market Performance with AI")
|
| 601 |
+
|
| 602 |
with gr.Row():
|
| 603 |
with gr.Column(scale=1):
|
| 604 |
+
all_tickers_hist = ASSETS + list(FRED_IDS.values())
|
| 605 |
+
if DASHBOARD_DATA_DF is not None:
|
| 606 |
+
available_tickers_hist = [t for t in all_tickers_hist if t in DASHBOARD_DATA_DF.columns]
|
| 607 |
+
else:
|
| 608 |
+
available_tickers_hist = []
|
| 609 |
+
default_tickers_hist = available_tickers_hist[:3] if available_tickers_hist else []
|
| 610 |
+
|
| 611 |
+
asset_selector = gr.Dropdown(choices=available_tickers_hist, value=default_tickers_hist, multiselect=True, label="1. Select Assets")
|
| 612 |
+
period_selector = gr.Dropdown(choices=list(TIME_PERIODS.keys()), value="1 Year", label="2. Select Period")
|
| 613 |
+
analyze_btn = gr.Button("๐ Run Analysis", variant="primary")
|
| 614 |
+
|
| 615 |
+
with gr.Column(scale=3):
|
| 616 |
+
historical_plot = gr.Plot(label="Performance Plot")
|
| 617 |
+
|
| 618 |
+
gr.Markdown("---")
|
| 619 |
+
historical_analysis_md = gr.Markdown("### ๐ค AI Analyst Report\n\n*Click 'Run Analysis' to generate.*")
|
| 620 |
+
|
| 621 |
+
analyze_btn.click(
|
| 622 |
+
fn=run_historical_analysis,
|
| 623 |
+
inputs=[asset_selector, period_selector],
|
| 624 |
+
outputs=[historical_plot, historical_analysis_md]
|
| 625 |
+
)
|
| 626 |
+
|
| 627 |
+
# ================= TAB 4: HISTORICAL SIMULATION (UPDATED with Pro Metrics) =================
|
| 628 |
+
with gr.TabItem("๐ Historical Simulation"):
|
| 629 |
+
gr.Markdown("### Backtest the RL Agent against Baselines")
|
| 630 |
+
|
| 631 |
+
# Disclaimer Box
|
| 632 |
+
gr.HTML(f"""
|
| 633 |
+
<div class='disclaimer-box'>
|
| 634 |
+
<strong>โ ๏ธ IMPORTANT DISCLAIMER:</strong> The RL model was trained on data from approximately
|
| 635 |
+
<strong>{TRAIN_START_DATE} to {TRAIN_END_DATE}</strong>. Running simulations outside or overlapping significantly
|
| 636 |
+
with this period may not accurately reflect real-world performance (lookahead bias or out-of-distribution data).
|
| 637 |
+
Use for educational purposes only.
|
| 638 |
+
</div>
|
| 639 |
+
""")
|
| 640 |
+
|
| 641 |
with gr.Row():
|
| 642 |
+
with gr.Column(scale=1):
|
| 643 |
+
start_date_input = gr.Textbox(label="Start Date (YYYY-MM-DD)", value=(datetime.now() - timedelta(days=365)).strftime('%Y-%m-%d'))
|
| 644 |
+
end_date_input = gr.Textbox(label="End Date (YYYY-MM-DD)", value=(datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d'))
|
| 645 |
+
sim_btn = gr.Button("โถ๏ธ Run Simulation", variant="primary")
|
| 646 |
+
sim_status = gr.Textbox(label="Status", interactive=False, lines=1)
|
| 647 |
+
|
| 648 |
+
with gr.Column(scale=3):
|
| 649 |
+
sim_plot = gr.Plot(label="Simulation Performance")
|
| 650 |
+
|
| 651 |
+
gr.Markdown("---")
|
| 652 |
+
# Updated to Markdown component for better table formatting
|
| 653 |
+
sim_metrics_md = gr.Markdown("### ๐ Professional Performance Metrics\n\n*Run simulation to see metrics.*")
|
| 654 |
+
|
| 655 |
+
sim_btn.click(
|
| 656 |
+
fn=run_historical_simulation,
|
| 657 |
+
inputs=[start_date_input, end_date_input],
|
| 658 |
+
outputs=[sim_plot, sim_status, sim_metrics_md]
|
| 659 |
+
)
|
| 660 |
|
| 661 |
if __name__ == "__main__":
|
| 662 |
demo.queue().launch(server_name="0.0.0.0", server_port=7860, debug=True, share=True)
|