import importlib.util import sqlite3 from pathlib import Path import pandas as pd def load_panel_app_module(): module_path = Path("panel/spbt_day_panel.py").resolve() spec = importlib.util.spec_from_file_location("spbt_day_panel_app", module_path) module = importlib.util.module_from_spec(spec) assert spec.loader is not None spec.loader.exec_module(module) return module def create_panel_fixture_db(db_path: Path) -> None: trading_day_start_ns = pd.Timestamp("2026-06-17T00:00:00Z").value conn = sqlite3.connect(db_path) try: conn.execute( """ CREATE TABLE selector_pairs ( time_ns INTEGER, tstamp TEXT, pair_name TEXT, instrument_a TEXT, instrument_b TEXT, mr_score TEXT ) """ ) conn.execute( """ CREATE TABLE trading_instructions ( time_ns INTEGER, tstamp TEXT, book_id TEXT, strategy_id TEXT, type TEXT, data TEXT ) """ ) conn.execute( """ CREATE TABLE ohlcv_1min ( tstamp TEXT, tstamp_ns INTEGER, exch_acct TEXT, exchange_id TEXT, instrument_id TEXT, interval_sec INTEGER, open REAL, high REAL, low REAL, close REAL, volume REAL, vwap REAL, num_trades INTEGER ) """ ) conn.execute( "INSERT INTO selector_pairs VALUES (?, ?, ?, ?, ?, ?)", ( 10, "2026-06-17T00:00:00Z", "AAA:USD-BBB:USD", "EXCH:PAIR-AAA-USD", "EXCH:PAIR-BBB-USD", '{"final":"0.5"}', ), ) conn.executemany( "INSERT INTO trading_instructions VALUES (?, ?, ?, ?, ?, ?)", [ ( trading_day_start_ns, "2026-06-17T00:00:00Z", "book", "strategy-AAA:USD-BBB:USD", "TARGET_POSITION", ( '{"action":"TARGET","quote_asset":"USD","assets":' '{"AAA":{"reference_price":"100","strength":"0.5"},' '"BBB":{"reference_price":"50","strength":"-0.5"}}}' ), ), ( trading_day_start_ns + 60_000_000_000, "2026-06-17T00:01:00Z", "book", "strategy-AAA:USD-BBB:USD", "CLOSE_POSITION", ( '{"action":"CLOSE","quote_asset":"USD","assets":' '{"AAA":{"reference_price":"110"},' '"BBB":{"reference_price":"45"}}}' ), ), ], ) conn.executemany( "INSERT INTO ohlcv_1min VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [ ( "2026-06-17T00:00:00Z", trading_day_start_ns, "EXCH", "EXCH", "PAIR-AAA-USD", 60, 100.0, 100.0, 100.0, 100.0, 1.0, 100.0, 1, ), ( "2026-06-17T00:00:00Z", trading_day_start_ns, "EXCH", "EXCH", "PAIR-BBB-USD", 60, 50.0, 50.0, 50.0, 50.0, 1.0, 50.0, 1, ), ], ) conn.commit() finally: conn.close() def test_pair_analyze_grid_keeps_clean_labels_and_full_pair_values(): module = load_panel_app_module() pair_theo_ret = pd.DataFrame( { "pair_name": ["BTC:USD-ETH:USD", "ADA:USD-BTC:USD"], "mr_ranking": [2, 1], "realized_pnl": [0.0, 0.0], "unrealized_pnl": [0.0, 0.0], } ) formatted = module.spbt_day.format_pair_theo_ret_for_analyze_grid(pair_theo_ret) assert formatted["pair_name"].tolist() == ["BTC-ETH", "ADA-BTC"] assert formatted[module.spbt_day.PAIR_NAME_VALUE_COLUMN].tolist() == [ "BTC:USD-ETH:USD", "ADA:USD-BTC:USD", ] def test_panel_app_uses_fast_list_template(tmp_path): module = load_panel_app_module() app = module.SpbtDayPanelApp(repo_root=tmp_path) view = app.view assert isinstance(view, module.pn.template.FastListTemplate) assert view.title == module.APP_TITLE assert view.sidebar_width == 430 assert view.accent_base_color == module.APP_ACCENT_COLOR assert view.header_background == module.APP_HEADER_COLOR assert len(view.sidebar) == 1 assert len(view.main) == 1 def test_panel_app_calculates_pairs_and_selected_pair_outputs(tmp_path): module = load_panel_app_module() data_dir = tmp_path / "data" data_dir.mkdir() db_path = data_dir / "20260617.spbt_results.db" create_panel_fixture_db(db_path) app = module.SpbtDayPanelApp(repo_root=tmp_path) app.directory_input.value = str(data_dir) app.refresh_files() app.min_pctg_change_input.value = 0.0 app.calculate() assert app.file_select.value == str(db_path) assert app.file_select.width == 360 assert app.min_pctg_change_input.width == 220 assert app.calculate_button.width == 110 assert app.total_pnl_histogram.sizing_mode == "stretch_width" assert app.selected_pair_market_plot.sizing_mode == "stretch_width" assert app.pair_theo_ret_table.pagination is None assert app.pair_theo_ret_table.layout == "fit_data_table" assert app.pair_theo_ret_table.value["pair_name"].tolist() == ["AAA-BBB"] assert ( app.pair_theo_ret_table.value[module.spbt_day.PAIR_NAME_VALUE_COLUMN].tolist() == ["AAA:USD-BBB:USD"] ) assert app.selected_pair_name is None assert app.selected_pair_executions_table.value.empty assert app.selected_pair_market_plot.object is None app.analyze_pair_row(0) assert app.selected_pair_name == "AAA:USD-BBB:USD" assert app.selected_pair_executions_table.value["action"].tolist() == [ "TARGET", "TARGET", "CLOSE", "CLOSE", ] assert app.selected_pair_market_plot.object is not None