chore: cleanup duplicate trade save, misleading cycle counters, and /api/summary inconsistencies
CI/CD / build-and-push (push) Successful in 7s
CI/CD / build-and-push (push) Successful in 7s
Bug #5: metrics.record_trade() only delegated to save_trade(), which executor.execute() already calls — every trade was written twice (deduped only by ON CONFLICT DO NOTHING). Remove the redundant call and the now-dead method. RealExecutor.execute() raises NotImplementedError, so real mode is unaffected. Bug #6 (CYCLE SUMMARY): manifold accepted/rejected counters only increment on the active-signal path, so with MANIFOLD_SIGNAL_ENABLED=false they always printed 0/0 — print 'manifold_signal: disabled' instead. family_conflicts_prevented duplicated blocked_by_family (same counter printed twice); removed. gnews_cap was a dead variable with a misleading comment; removed. Bug #7 (/api/summary): total_trades was len() over a LIMIT-500 query — capped once history grows; counts now come from COUNT(*) via compute_metrics_from_db. cash_available was reimplemented in the API; extract cash_available() in paper.py (same formula, unchanged) and feed it from get_open_position_data() — the exact source/helper PaperExecutor.initialize() uses. Test asserts API and executor report identical cash for the same DB state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
02cbfc0b94
commit
7ebb87aede
+14
-9
@@ -11,6 +11,7 @@ from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
from bot.data.db import Database
|
||||
from bot.executor.paper import cash_available
|
||||
|
||||
# Phase 6 format (Phase 6+): values already in log-odds space.
|
||||
# "fg_lo=+0.1200 mom_lo=+0.0000 news_lo=+0.0000 mfld_lo=-0.7483 btc_dom_lo=+0.0000"
|
||||
@@ -280,27 +281,31 @@ async def get_summary():
|
||||
which is written by the bot every cycle via MetricsTracker.update_daily_summary().
|
||||
After Fix 3, that snapshot is also DB-computed — not dependent on pod restarts.
|
||||
"""
|
||||
latest_metrics, open_trades, all_trades, inverted, legacy_count = await asyncio.gather(
|
||||
latest_metrics, counts, position_data, inverted, legacy_count = await asyncio.gather(
|
||||
db.get_metrics_history(days=1),
|
||||
db.get_recent_trades(limit=500, status="open"),
|
||||
db.get_recent_trades(limit=500),
|
||||
db.compute_metrics_from_db(),
|
||||
db.get_open_position_data(),
|
||||
db.get_recently_closed_inverted(hours=24),
|
||||
db.get_legacy_incomplete_count(),
|
||||
)
|
||||
|
||||
latest = latest_metrics[0] if latest_metrics else {}
|
||||
paper_bankroll = float(os.getenv("PAPER_BANKROLL", "10000"))
|
||||
total_deployed = sum(t.get("net_cost", 0) for t in open_trades)
|
||||
total_trades = int(counts["total_trades"] or 0)
|
||||
# Same source PaperExecutor.initialize() uses to reconstruct cash:
|
||||
# total_net_cost_open = SUM(net_cost) over open trades, uncapped.
|
||||
_, total_net_cost_open = position_data
|
||||
total_deployed = total_net_cost_open
|
||||
|
||||
return {
|
||||
# ── Portfolio state (live from DB) ──────────────────────────────────
|
||||
"paper_mode": os.getenv("PAPER_MODE", "true") == "true",
|
||||
"paper_bankroll": paper_bankroll,
|
||||
"total_trades": len(all_trades), # exact, from DB
|
||||
"open_trades_count": len(open_trades), # exact, from DB
|
||||
"closed_trades_count": len(all_trades) - len(open_trades), # exact
|
||||
"total_trades": total_trades, # COUNT(*), uncapped
|
||||
"open_trades_count": int(counts["open_count"] or 0), # COUNT(*), uncapped
|
||||
"closed_trades_count": int(counts["closed_count"] or 0), # COUNT(*), uncapped
|
||||
"total_deployed": total_deployed, # exact, from DB
|
||||
"cash_available": max(0.0, paper_bankroll - total_deployed), # exact
|
||||
"cash_available": cash_available(paper_bankroll, total_net_cost_open),
|
||||
"legacy_incomplete_count": legacy_count, # exact, from DB
|
||||
"reentry_guard_blocks_24h": len(inverted), # exact, from DB
|
||||
|
||||
@@ -333,6 +338,6 @@ async def get_summary():
|
||||
(latest.get("sharpe_ratio") or 0) >= 0.5
|
||||
and (latest.get("win_rate") or 0) >= 0.52
|
||||
and (latest.get("calibration_score") or 0) >= 0.7
|
||||
and len(all_trades) >= 50
|
||||
and total_trades >= 50
|
||||
),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user