The duckdb library is already gone (not a dependency, not importable, no
`import duckdb` anywhere) — these were leftover text references that misled.
- Delete storage/schema.py: 418 lines of DuckDB DDL with zero importers. The
Postgres schema is created by db_pg._apply_schema + event_store._ensure_schema.
- Neutralise stale default db_path strings (./data/momentum*.duckdb) in
event_store, config, run_live_paper, dashboard_api — the connection layer
ignores the path (DATABASE_URL is the datastore), so these phantom file paths
only created confusion. Dropped the now-pointless os.makedirs for them.
- research/multi_schema: the "three DuckDB files" are one Postgres DB now (all
resolve to the same connection); doc + constants updated to match reality.
- Fix stale "DuckDB handle" comments in api/main.
Kept the DuckDB mentions in storage/db_pg.py + storage/db.py — they document
why the Postgres facade mimics DuckDB's ? placeholders and :memory: semantics.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DB latency: every projection runs `WHERE event_type=? ORDER BY timestamp DESC
LIMIT n`. With only a plain timestamp index, the latest of a STALE type
backward-scans the whole events table — measured 373ms / ~52k buffers on 235k
rows. Add a composite index in event_store._ensure_schema:
CREATE INDEX idx_events_type_ts ON events(event_type, timestamp DESC)
-> same query is now a 0.018ms index seek (3 buffers). Applied to the live DB
CONCURRENTLY; also dropped two redundant legacy indexes (idx_events_type, now
covered by the composite prefix; idx_events_correlation, a dup of
idx_events_session_id) to cut write overhead.
tests/conftest.py: sweep the throwaway `mem_*` schemas EventStore(":memory:")
creates — 170 had leaked into the shared Postgres, bloating the catalog.
README: rewritten around the current system — PostgreSQL event store, a full
command reference (run_live_paper / momentum CLI / eod_replay / sweeps / tuning /
cron), config knobs, and a database & performance section (the index above,
extension guidance, retention).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three fixes from the first live session:
1) Naked-stop bug (critical): the entry-timeout guard cancelled an entry it
thought was unfilled AFTER it had really filled (our order_filled events lag
the 60s sync). Cancelling a bracket parent cancels its stop/TP legs, so the
position went NAKED and bled 22% with no floor. Guard now checks the broker's
LIVE positions (get_positions) before cancelling and never cancels a filled
name. Regression test added.
2) Speed: ingest re-fetched a 240-min window for ~80 symbols every minute (~46s
measured), and the single-threaded loop froze the 4s trigger that whole time
-> breakouts caught once a minute, not in real time. Ingest is now
incremental (heavy first pass covers the session so the opening range is
present; then ~20-min refreshes, closed bars never change). Loop passes
dropped from ~70s to ~2-5s.
3) Threaded trigger: the fast breakout detector/fire loop now runs on its own
thread, fully decoupled from the slow scheduler. EventStore, the execution
service, and the trigger book are made thread-safe (locks) so the thread and
main loop can't race the shared psycopg2 connection or in-memory state.
Verified live: fired EZGO/NEOV, all positions retain active stops.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- storage/db_pg.py: thin psycopg2 connection shim (?->%s translation,
autocommit, .df(), and per-test isolated schema for ':memory:').
- storage/db.py: delegate get_connection/get_memory_connection to db_pg.
- storage/pg_schema.sql: Postgres schema, applied on connect.
- research/query.py runs UNMODIFIED on Postgres via the shim.
- ingestion upserts: INSERT OR REPLACE -> INSERT ... ON CONFLICT DO UPDATE.
- event_store: drop invalid btree-on-JSON-text index.
Full logic suite: 67/67 green against Postgres (was DuckDB).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Snapshot before the DuckDB->PostgreSQL migration. data/, archive/, the 232MB
rebuild zip, the Windows .venv, and .env are excluded via .gitignore.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>