feat: show max-hold session countdown

This commit is contained in:
2026-08-03 23:55:30 +02:00
parent 3a6900d45a
commit d431ee283d
5 changed files with 142 additions and 4 deletions
+4
View File
@@ -53,3 +53,7 @@ class PaperTradeResponse(BaseModel):
# when the trailing exit policy is active.
trailing_stop: float | None = None
trailing_distance_pct: float | None = None
# Trading sessions represented by post-entry OHLCV bars. These are populated
# only while the active exit policy has a max-hold rule.
sessions_held: int | None = None
sessions_remaining: int | None = None
+31 -1
View File
@@ -352,6 +352,7 @@ def _to_dict(
current_price: float | None,
benchmark_closes: dict[date, float] | None = None,
trailing: tuple[float, float | None] | None = None,
holding_sessions: tuple[int, int] | None = None,
) -> dict:
# For open trades, mark to market; for closed, the realized exit price.
ref = current_price if trade.status == "open" else trade.close_price
@@ -395,6 +396,8 @@ def _to_dict(
"fill_mode": trade.fill_mode,
"trailing_stop": trailing[0] if trailing else None,
"trailing_distance_pct": trailing[1] if trailing else None,
"sessions_held": holding_sessions[0] if holding_sessions else None,
"sessions_remaining": holding_sessions[1] if holding_sessions else None,
}
@@ -435,6 +438,26 @@ async def list_trades(
# Current trailing-stop level + distance for open trades (when a trailing
# policy is active).
policy = await get_exit_policy(db)
holding_sessions: dict[int, tuple[int, int]] = {}
if policy["mode"] in ("time", "atr_trailing"):
hold_days = int(policy["hold_days"])
for t, _ in rows:
if t.status != "open":
continue
held = int(
(
await db.execute(
select(func.count())
.select_from(OHLCVRecord)
.where(
OHLCVRecord.ticker_id == t.ticker_id,
OHLCVRecord.date > t.opened_at.date(),
)
)
).scalar_one()
)
holding_sessions[t.id] = (held, max(0, hold_days - held))
trailing_info: dict[int, tuple[float, float | None]] = {}
if policy["mode"] == "trailing":
trail_frac = policy["trailing_pct"] / 100.0
@@ -483,7 +506,14 @@ async def list_trades(
trailing_info[t.id] = (level, dist)
return [
_to_dict(t, sym, prices.get(t.ticker_id), benchmark_closes, trailing_info.get(t.id))
_to_dict(
t,
sym,
prices.get(t.ticker_id),
benchmark_closes,
trailing_info.get(t.id),
holding_sessions.get(t.id),
)
for t, sym in rows
]