Spaces:
Sleeping
Sleeping
| import pytest | |
| from kag.dashboard.data import ( | |
| build_investment_simulation, | |
| load_local_price_ohlcv, | |
| load_model_metrics, | |
| load_stock_options, | |
| normalize_prediction_rows, | |
| prediction_label, | |
| ) | |
| def test_normalize_prediction_rows_casts_values(): | |
| rows = normalize_prediction_rows( | |
| [ | |
| { | |
| "ticker": "BBCA", | |
| "date": "2026-05-22", | |
| "sector": "Financials", | |
| "close": "5875.0", | |
| "probability_up": "0.554636", | |
| "predicted_direction": "1", | |
| "model_type": "lightgbm", | |
| } | |
| ] | |
| ) | |
| assert rows == [ | |
| { | |
| "ticker": "BBCA", | |
| "date": "2026-05-22", | |
| "sector": "Financials", | |
| "close": 5875.0, | |
| "probability_up": 0.554636, | |
| "predicted_direction": 1, | |
| "model_type": "lightgbm", | |
| } | |
| ] | |
| def test_prediction_label_maps_known_values(): | |
| assert prediction_label(1) == "Up" | |
| assert prediction_label(0) == "Down" | |
| assert prediction_label(None) == "Unknown" | |
| def test_load_model_metrics_returns_empty_for_missing_file(tmp_path): | |
| assert load_model_metrics(tmp_path / "missing.json") == {} | |
| def test_load_local_price_ohlcv_filters_period_and_symbol(tmp_path): | |
| pd = pytest.importorskip("pandas") | |
| pytest.importorskip("pyarrow") | |
| path = tmp_path / "prices.parquet" | |
| frame = pd.DataFrame( | |
| [ | |
| { | |
| "ticker": "BBCA", | |
| "yfinance_symbol": "BBCA.JK", | |
| "date": "2026-01-01", | |
| "open": 100, | |
| "high": 110, | |
| "low": 90, | |
| "close": 105, | |
| "volume": 1000, | |
| }, | |
| { | |
| "ticker": "BBCA", | |
| "yfinance_symbol": "BBCA.JK", | |
| "date": "2026-05-23", | |
| "open": 120, | |
| "high": 130, | |
| "low": 118, | |
| "close": 128, | |
| "volume": 2000, | |
| }, | |
| { | |
| "ticker": "BBRI", | |
| "yfinance_symbol": "BBRI.JK", | |
| "date": "2026-05-23", | |
| "open": 90, | |
| "high": 95, | |
| "low": 88, | |
| "close": 94, | |
| "volume": 900, | |
| }, | |
| ] | |
| ) | |
| frame.to_parquet(path, index=False) | |
| rows = load_local_price_ohlcv("BBCA.JK", period="1mo", interval="1d", path=path) | |
| assert len(rows) == 1 | |
| assert rows[0]["date"] == "2026-05-23" | |
| assert rows[0]["close"] == 128 | |
| assert rows[0]["source"] == str(path) | |
| def test_load_stock_options_orders_priced_stocks_first(): | |
| class RecordingClient: | |
| def execute_read(self, query, parameters=None): | |
| assert "count(price) > 0 AS has_price" in query | |
| assert "coalesce(stock.universe_rank, 1000000) AS universe_rank" in query | |
| assert "ORDER BY has_price DESC, universe_rank, ticker" in query | |
| return [ | |
| {"ticker": "BBCA", "has_price": True, "price_points": 20}, | |
| {"ticker": "AADI", "has_price": False, "price_points": 0}, | |
| ] | |
| assert load_stock_options(RecordingClient())[0]["ticker"] == "BBCA" | |
| def test_build_investment_simulation_uses_historical_values(): | |
| simulation = build_investment_simulation( | |
| [ | |
| {"date": "2026-01-01", "close": 100.0}, | |
| {"date": "2026-01-02", "close": 110.0}, | |
| {"date": "2026-01-05", "close": 121.0}, | |
| ], | |
| amount=1_000_000, | |
| entry_date="2026-01-01", | |
| exit_date="2026-01-05", | |
| ) | |
| assert simulation["mode"] == "historical" | |
| assert simulation["entry_close"] == 100.0 | |
| assert simulation["exit_value"] == 1_210_000 | |
| assert len(simulation["rows"]) == 3 | |
| def test_build_investment_simulation_projects_future_weekdays(): | |
| simulation = build_investment_simulation( | |
| [ | |
| {"date": "2026-01-01", "close": 100.0}, | |
| {"date": "2026-01-02", "close": 101.0}, | |
| {"date": "2026-01-05", "close": 102.0}, | |
| {"date": "2026-01-06", "close": 103.0}, | |
| ], | |
| amount=1_000_000, | |
| entry_date="2026-01-02", | |
| exit_date="2026-01-09", | |
| probability_up=0.6, | |
| ) | |
| assert simulation["mode"] == "projected" | |
| assert simulation["rows"][-1]["kind"] == "projected" | |
| assert simulation["rows"][-1]["date"] == "2026-01-09" | |
| def test_build_investment_simulation_validates_inputs(): | |
| with pytest.raises(ValueError, match="amount"): | |
| build_investment_simulation([], amount=0, entry_date="2026-01-01", exit_date="2026-01-02") | |