Release v1.0.2
This commit is contained in:
@@ -20,6 +20,22 @@ OHLCV_1MIN_COLUMNS = ("tstamp", "tstamp_ns", "exch_acct", "instrument_id", "clos
|
||||
INITIAL_THEO_CAPITAL_USD = 10_000.0
|
||||
SQLITE_EXTENSIONS = {".db", ".sqlite", ".sqlite3"}
|
||||
PAIR_NAME_DISPLAY_SUFFIX = ":USD"
|
||||
PAIR_NAME_VALUE_COLUMN = "_pair_name_value"
|
||||
ANALYZE_BUTTON_COLUMN = "analyze"
|
||||
ANALYZE_BUTTON_HTML = (
|
||||
'<button type="button" title="Analyze pair" aria-label="Analyze pair" '
|
||||
'style="padding: 1px 6px; line-height: 1.2;">▶</button>'
|
||||
)
|
||||
SELECTED_PAIR_EXECUTION_DISPLAY_COLUMNS = [
|
||||
"time",
|
||||
"asset",
|
||||
"action",
|
||||
"side",
|
||||
"strength",
|
||||
"size",
|
||||
"price",
|
||||
"usd_value",
|
||||
]
|
||||
INTERACTIVE_TABLE_CSS = """
|
||||
table.dataTable,
|
||||
table.dataTable th,
|
||||
@@ -1081,6 +1097,75 @@ def format_pair_names_for_display(
|
||||
return formatted
|
||||
|
||||
|
||||
def format_pair_theo_ret_for_analyze_grid(pair_theo_ret: pd.DataFrame) -> pd.DataFrame:
|
||||
"""Format pair TheoRet rows for an Analyze-button grid.
|
||||
|
||||
The visible pair name is display-cleaned, while the original pair name is
|
||||
retained in a hidden column for callbacks that need the calculation key.
|
||||
"""
|
||||
if "pair_name" not in pair_theo_ret.columns:
|
||||
raise ValueError("pair TheoRet dataframe missing column: pair_name")
|
||||
|
||||
formatted = format_pair_names_for_display(pair_theo_ret)
|
||||
formatted[PAIR_NAME_VALUE_COLUMN] = pair_theo_ret["pair_name"].to_numpy()
|
||||
return formatted
|
||||
|
||||
|
||||
def pair_name_from_analyze_event(table: Any, event: Any) -> str:
|
||||
"""Resolve the full pair name from a Panel Tabulator click event."""
|
||||
if PAIR_NAME_VALUE_COLUMN not in table.value.columns:
|
||||
raise ValueError(f"Analyze table missing column: {PAIR_NAME_VALUE_COLUMN}")
|
||||
pair_name = table.value[PAIR_NAME_VALUE_COLUMN].iloc[event.row]
|
||||
if pd.isna(pair_name) or not str(pair_name):
|
||||
raise ValueError(f"Analyze row {event.row} does not contain a pair name")
|
||||
return str(pair_name)
|
||||
|
||||
|
||||
def create_pair_theo_ret_analyze_grid(
|
||||
pair_theo_ret_display: pd.DataFrame,
|
||||
*,
|
||||
height: int = 420,
|
||||
) -> Any:
|
||||
"""Create a sortable Panel grid with a compact Analyze button column."""
|
||||
import panel as pn
|
||||
|
||||
return pn.widgets.Tabulator(
|
||||
pair_theo_ret_display,
|
||||
buttons={ANALYZE_BUTTON_COLUMN: ANALYZE_BUTTON_HTML},
|
||||
hidden_columns=[PAIR_NAME_VALUE_COLUMN],
|
||||
show_index=False,
|
||||
pagination=None,
|
||||
layout="fit_data_table",
|
||||
height=height,
|
||||
sizing_mode="fixed",
|
||||
selectable=False,
|
||||
)
|
||||
|
||||
|
||||
def create_selected_pair_executions_grid(
|
||||
dataframe: pd.DataFrame | None = None,
|
||||
*,
|
||||
height: int = 320,
|
||||
) -> Any:
|
||||
"""Create a sortable Panel grid for selected-pair theoretical executions."""
|
||||
import panel as pn
|
||||
|
||||
source = (
|
||||
dataframe
|
||||
if dataframe is not None
|
||||
else pd.DataFrame(columns=SELECTED_PAIR_EXECUTION_DISPLAY_COLUMNS)
|
||||
)
|
||||
return pn.widgets.Tabulator(
|
||||
source.reindex(columns=SELECTED_PAIR_EXECUTION_DISPLAY_COLUMNS),
|
||||
show_index=False,
|
||||
pagination=None,
|
||||
layout="fit_data_table",
|
||||
height=height,
|
||||
sizing_mode="fixed",
|
||||
selectable=False,
|
||||
)
|
||||
|
||||
|
||||
def add_total_pnl(pair_theo_ret: pd.DataFrame) -> pd.DataFrame:
|
||||
"""Return a copy of pair TheoRet rows with total realized plus unrealized PnL."""
|
||||
required_columns = {"realized_pnl", "unrealized_pnl"}
|
||||
|
||||
Reference in New Issue
Block a user