Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9d553dcf1a |
@@ -6,6 +6,13 @@ All notable changes to this project are documented in this file.
|
||||
|
||||
No unreleased changes yet.
|
||||
|
||||
## 2026-07-29 v1.0.3
|
||||
|
||||
- Removed invalid fixed sizing mode from Panel Tabulator grids to avoid Bokeh
|
||||
layout warnings while preserving compact table layout.
|
||||
- Changed the Panel Calculate action to refresh the result-file list before
|
||||
loading data and removed the standalone Panel Refresh button.
|
||||
|
||||
## 2026-07-29 v1.0.2
|
||||
|
||||
- Added a Panel application for single-day SPBT result analysis with result-file
|
||||
|
||||
@@ -45,7 +45,6 @@ class SpbtDayPanelApp:
|
||||
value=str(self.repo_root / "data"),
|
||||
)
|
||||
self.show_all_files = pn.widgets.Checkbox(label="Show all files", value=False)
|
||||
self.refresh_button = pn.widgets.Button(label="Refresh")
|
||||
self.file_select = pn.widgets.Select(
|
||||
label="SQLite result file",
|
||||
options={},
|
||||
@@ -85,7 +84,6 @@ class SpbtDayPanelApp:
|
||||
sizing_mode="stretch_width",
|
||||
)
|
||||
|
||||
self.refresh_button.on_click(self.refresh_files)
|
||||
self.calculate_button.on_click(self.calculate)
|
||||
self.directory_input.param.watch(self.refresh_files, "value")
|
||||
self.show_all_files.param.watch(self.refresh_files, "value")
|
||||
@@ -111,7 +109,7 @@ class SpbtDayPanelApp:
|
||||
raise ValueError(f"Selected database path is not a file: {db_path}")
|
||||
return db_path
|
||||
|
||||
def refresh_files(self, *_events: Any) -> None:
|
||||
def refresh_files(self, *_events: Any) -> bool:
|
||||
"""Refresh selectable SQLite files from the configured directory."""
|
||||
try:
|
||||
directory = spbt_day.normalize_directory(
|
||||
@@ -126,7 +124,7 @@ class SpbtDayPanelApp:
|
||||
self.file_select.options = {}
|
||||
self.file_select.value = None
|
||||
self.set_status(str(exc), error=True)
|
||||
return
|
||||
return False
|
||||
|
||||
options = {path.name: str(path) for path in candidates}
|
||||
previous_value = self.file_select.value
|
||||
@@ -142,11 +140,14 @@ class SpbtDayPanelApp:
|
||||
self.set_status(f"Found {len(options):,} file(s) in {directory}.")
|
||||
else:
|
||||
self.set_status(f"No selectable files found in {directory}.")
|
||||
return True
|
||||
|
||||
def calculate(self, *_events: Any) -> None:
|
||||
"""Load selected data and calculate all-pair TheoRet."""
|
||||
self.calculate_button.loading = True
|
||||
try:
|
||||
if not self.refresh_files():
|
||||
return
|
||||
db_path = self.selected_database_path()
|
||||
self.min_pctg_change = float(self.min_pctg_change_input.value)
|
||||
|
||||
@@ -260,7 +261,7 @@ class SpbtDayPanelApp:
|
||||
"""Return the app layout."""
|
||||
controls = pn.Column(
|
||||
"## Inputs",
|
||||
pn.Row(self.directory_input, self.refresh_button),
|
||||
self.directory_input,
|
||||
self.show_all_files,
|
||||
self.file_select,
|
||||
self.min_pctg_change_input,
|
||||
|
||||
@@ -1137,7 +1137,6 @@ def create_pair_theo_ret_analyze_grid(
|
||||
pagination=None,
|
||||
layout="fit_data_table",
|
||||
height=height,
|
||||
sizing_mode="fixed",
|
||||
selectable=False,
|
||||
)
|
||||
|
||||
@@ -1161,7 +1160,6 @@ def create_selected_pair_executions_grid(
|
||||
pagination=None,
|
||||
layout="fit_data_table",
|
||||
height=height,
|
||||
sizing_mode="fixed",
|
||||
selectable=False,
|
||||
)
|
||||
|
||||
|
||||
@@ -1023,7 +1023,7 @@ def test_create_panel_grids_use_analyze_button_and_hidden_pair_column():
|
||||
assert pair_grid.disabled is False
|
||||
assert pair_grid.pagination is None
|
||||
assert pair_grid.layout == "fit_data_table"
|
||||
assert pair_grid.sizing_mode == "fixed"
|
||||
assert pair_grid.sizing_mode is None
|
||||
assert executions_grid.value.columns.tolist() == [
|
||||
"time",
|
||||
"asset",
|
||||
|
||||
@@ -166,6 +166,7 @@ def test_panel_app_uses_fast_list_template(tmp_path):
|
||||
app = module.SpbtDayPanelApp(repo_root=tmp_path)
|
||||
view = app.view
|
||||
|
||||
assert not hasattr(app, "refresh_button")
|
||||
assert isinstance(view, module.pn.template.FastListTemplate)
|
||||
assert view.title == module.APP_TITLE
|
||||
assert view.sidebar_width == 430
|
||||
@@ -216,3 +217,22 @@ def test_panel_app_calculates_pairs_and_selected_pair_outputs(tmp_path):
|
||||
"CLOSE",
|
||||
]
|
||||
assert app.selected_pair_market_plot.object is not None
|
||||
|
||||
|
||||
def test_calculate_refreshes_file_list_before_loading(tmp_path):
|
||||
module = load_panel_app_module()
|
||||
data_dir = tmp_path / "data"
|
||||
data_dir.mkdir()
|
||||
|
||||
app = module.SpbtDayPanelApp(repo_root=tmp_path)
|
||||
app.directory_input.value = str(data_dir)
|
||||
app.refresh_files()
|
||||
assert app.file_select.value is None
|
||||
|
||||
db_path = data_dir / "20260617.spbt_results.db"
|
||||
create_panel_fixture_db(db_path)
|
||||
|
||||
app.calculate()
|
||||
|
||||
assert app.file_select.value == str(db_path)
|
||||
assert app.pair_theo_ret_table.value["pair_name"].tolist() == ["AAA-BBB"]
|
||||
|
||||
Reference in New Issue
Block a user