delete: dead DDL (10 tables), dead projections, pinned dead code; README/pyproject prune
pg_schema.sql: drop CREATE TABLE for 10 zero-reference tables (operator DROP list in plans/002-deletions.log — production tables untouched until run). projections.py: remove 4 zero-consumer query functions. Clear all 'plan 002' ruff pins from the CI gate (files now F-clean); api/main.py:F821 pin remains for plan 007. README repo-map/test-count fixed; pydantic-settings removed (zero imports). Full receipts: plans/002-deletions.log Suite: 351 passed (16 schwab/dead-module tests removed), 15 failures = the known WSL-loopback dashboard set only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cf431c6c2b
commit
af8137dfd7
11 files changed
+53
-234
No files matched your search
@@ -39,20 +39,11 @@ jobs:
|
||||
# F errors anywhere in scope still fail; remove each pin when its owning
|
||||
# plan lands:
|
||||
# api/main.py F821 (missing os/hmac imports) -> plan 007
|
||||
# research/gapper_history.py F401, research/labeler.py F541/F841,
|
||||
# storage/event_store.py F401,
|
||||
# strategy/evaluation/structure.py F401/F841 (dead code) -> plan 002
|
||||
- run: >-
|
||||
ruff check --select F
|
||||
run_live_paper.py trading_execution.py telegram_bot.py
|
||||
api/ alpaca_paper/ runtime/ storage/ strategy/ research/
|
||||
--per-file-ignores "api/main.py:F821"
|
||||
--per-file-ignores "research/gapper_history.py:F401"
|
||||
--per-file-ignores "research/labeler.py:F541"
|
||||
--per-file-ignores "research/labeler.py:F841"
|
||||
--per-file-ignores "storage/event_store.py:F401"
|
||||
--per-file-ignores "strategy/evaluation/structure.py:F401"
|
||||
--per-file-ignores "strategy/evaluation/structure.py:F841"
|
||||
- run: python -m pytest -q
|
||||
env:
|
||||
DATABASE_URL: postgresql://momentum:momentum@localhost:5432/momentum
|
||||
|
||||
@@ -110,8 +110,8 @@ The `.sh` wrappers set the venv + cwd so cron can call them directly:
|
||||
|
||||
```bash
|
||||
DATABASE_URL=postgresql://user:pass@host:5432/momentum python -m pytest
|
||||
# ~130 tests: strategy, storage, triggers, execution (cooldown/re-entry/EOD
|
||||
# flatten/naked-stop guards), exits, journal P&L, schwab, api, research.
|
||||
# ~365 tests: strategy, storage, triggers, execution (cooldown/re-entry/EOD
|
||||
# flatten/naked-stop guards), exits, journal P&L, api, research.
|
||||
```
|
||||
|
||||
Tests isolate via throwaway `mem_*` Postgres schemas; `tests/conftest.py` sweeps
|
||||
@@ -180,7 +180,6 @@ strategy/ pure strategy engine: evaluation, structure, exits, backte
|
||||
storage/ event schema + store (PostgreSQL), projections
|
||||
research/ research DBs, ingestion (bars, RSS, gappers), screeners
|
||||
alpaca_paper/ Alpaca paper client, executor, account/order sync
|
||||
schwab/ Schwab OAuth, market data, positions/orders, health
|
||||
api/ + dashboard_api.py dashboard JSON API + static UI (:8765)
|
||||
admin_api.py admin panel (:8767): health, config overrides, profiles, restarts
|
||||
youtube_claims/ trader-video transcript -> claim extraction pipeline
|
||||
@@ -193,7 +192,7 @@ tests/ pytest suite (unit + integration)
|
||||
|
||||
## Security
|
||||
|
||||
`.env` and all of `data/` (DBs, `data/schwab_tokens.json`) are git-ignored and
|
||||
`.env` and all of `data/` are git-ignored and
|
||||
never committed; token files are written `0600`. The `.env` holds **live broker /
|
||||
database / webhook credentials** — keep it local. If any secret was ever
|
||||
committed to a repo's history, **rotate it** (re-issue Alpaca keys / re-run the
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# Plan 002 deletions log — 2026-07-13, branch milestone-2026-07
|
||||
|
||||
Every deletion was grep-gated: `grep -rn "<name>" --include="*.py" --include="*.yml" --include="*.sh"` excluding the target itself, plans/, docs/. "clear" = zero live references.
|
||||
|
||||
## Deleted (grep receipts)
|
||||
- schwab/ (23 tracked files) — clear (README prose + .env.example keys only; both cleaned). Commit message of d54a2a9 claimed this deletion; it never happened.
|
||||
- tests/unit/schwab/ — tests of the deleted module.
|
||||
- milestone3_verify.py — schwab-only walk-through; clear.
|
||||
- comprehensive_backtest.py — crashes on import (research/connection.py absent); clear.
|
||||
- strategy/universe.py + UniverseConfig — clear.
|
||||
- strategy/backtest/outcomes.py (+ its exports in strategy/backtest/__init__.py) — clear.
|
||||
- detect_momentum_ignition in strategy/evaluation/ignition.py — clear; **kept `_last_higher_low`** (imported by runner.py:33, premarket_setup.py:32, liquid_breakout.py:44). tests/unit/test_ignition.py trimmed to the kept helper.
|
||||
- grafana/ (standalone stack) — pointed at decommissioned pre-migration DB. **Provisioning dashboards MOVED** to deploy/compose/grafana/dashboards/ and docker-compose.yml bind-mount re-pointed (the in-compose grafana service keeps working). SECURITY NOTE: the deleted datasource YAML carried committed dev Postgres credentials (values not reproduced here); they remain in git history — rotate that DB user's password if the old 5432 instance still runs.
|
||||
- telemetry/ — contained only stale __pycache__ (untracked); removed from disk.
|
||||
- .github/workflows/docker-publish.yml — fired on nonexistent `main` + stale artifact branch; pushed wrong image name (momentum-system).
|
||||
- uv.lock — DuckDB-era lockfile; requirements.txt is the real manifest.
|
||||
- SCHWAB_* keys from .env.example.
|
||||
- pydantic-settings from pyproject.toml — zero imports repo-wide.
|
||||
- Dead intra-file code (the CI ruff pins annotated "plan 002", all removed and pins dropped from docker.yml): unused imports in research/gapper_history.py, storage/event_store.py, strategy/evaluation/structure.py; empty f-string + dead `orb` query in research/labeler.py; dead `closes` assignment in structure.py.
|
||||
|
||||
## Dead DDL removed from storage/pg_schema.sql (10 tables, zero code references)
|
||||
backtest_runs, halt_events, market_context, paper_missed_trades, paper_sessions,
|
||||
short_interest, simulated_fills, simulated_orders, strategy_runs, telemetry_events
|
||||
|
||||
## Dead projections removed from storage/projections.py (zero consumers)
|
||||
query_event_timeline, query_positions_view, query_settings_snapshot, query_symbol_status
|
||||
(private helpers _evt_window/_hist_window/_latest_event_payload/_state_until/_sum_position_unrealized all have internal callers — kept)
|
||||
|
||||
## Kept (grep hit live code, or disposition elsewhere)
|
||||
- strategy/evaluation/ignition.py `_last_higher_low` — live (3 importers).
|
||||
- quote_snapshots, float_cache — created by CODE (run_live_paper.py, research/ingestion/float_cache.py), no pg_schema DDL to remove; write-only today; disposition in plan 006.
|
||||
- dilution_events — pg_schema DDL kept; disposition in plan 006.
|
||||
|
||||
## FOR THE OPERATOR — run only after plan 001's backup exists + one session soak
|
||||
```sql
|
||||
DROP TABLE IF EXISTS backtest_runs;
|
||||
DROP TABLE IF EXISTS halt_events;
|
||||
DROP TABLE IF EXISTS market_context;
|
||||
DROP TABLE IF EXISTS paper_missed_trades;
|
||||
DROP TABLE IF EXISTS paper_sessions;
|
||||
DROP TABLE IF EXISTS short_interest;
|
||||
DROP TABLE IF EXISTS simulated_fills;
|
||||
DROP TABLE IF EXISTS simulated_orders;
|
||||
DROP TABLE IF EXISTS strategy_runs;
|
||||
DROP TABLE IF EXISTS telemetry_events;
|
||||
```
|
||||
These were removed from pg_schema.sql only; the production database still holds the (empty/stale) tables until you run the DROPs.
|
||||
+1
-1
@@ -17,7 +17,7 @@ your row when done.
|
||||
| Plan | Title | Priority | Effort | Depends on | Status |
|
||||
|------|-------|----------|--------|------------|--------|
|
||||
| 001 | Production safety rails — CI test gate, dead-man's switch, pg_dump backup | P1 | S | — | DONE |
|
||||
| 002 | Dead-weight deletion — schwab/, grafana/, dead modules/tables/projections | P2 | S | 001 | TODO |
|
||||
| 002 | Dead-weight deletion — schwab/, grafana/, dead modules/tables/projections | P2 | S | 001 | DONE |
|
||||
| 003 | Money-path hardening — daily self-restart, positive-evidence contract, reconcile, cage count | P1 | M | 001 | TODO |
|
||||
| 004 | Learning flywheel — one population module, scheduled eod_replay + nightly_tune, atomic writes | P1 | M | 001 (002 rec.) | TODO |
|
||||
| 005 | Entry-path unification + decision receipts | P2 | M | 001, 003, 004 | TODO |
|
||||
|
||||
@@ -11,7 +11,6 @@ dependencies = [
|
||||
"psycopg2-binary>=2.9.0",
|
||||
"pandas>=2.0.0",
|
||||
"pydantic>=2.0.0",
|
||||
"pydantic-settings>=2.0.0",
|
||||
"pyyaml>=6.0",
|
||||
"typer>=0.9.0",
|
||||
"rich>=13.0.0",
|
||||
|
||||
@@ -24,7 +24,7 @@ market at minute resolution:
|
||||
import argparse
|
||||
import time
|
||||
from collections import defaultdict
|
||||
from datetime import date, datetime, timedelta
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import os
|
||||
import pandas as pd
|
||||
|
||||
+1
-7
@@ -774,12 +774,6 @@ def validate_runner(con):
|
||||
lb_1r = _wilson_lower(sum(r1), len(r1))
|
||||
fresh = [r[2] for r in rows if r[3] is None or r[3] <= RUNNER_PM_EXHAUSTION_FRAC]
|
||||
rate_fresh = (sum(fresh) / len(fresh)) if fresh else 0.0
|
||||
orb = con.execute(
|
||||
"WITH rn AS (SELECT DISTINCT symbol, session_date FROM setup_events WHERE setup_version=?) "
|
||||
"SELECT avg(CASE WHEN l.reached_1r_before_minus_1r THEN 1.0 ELSE 0 END), count(*) "
|
||||
"FROM setup_events se JOIN outcome_labels l ON l.setup_id = se.setup_id "
|
||||
"JOIN rn ON rn.symbol = se.symbol AND rn.session_date = se.session_date "
|
||||
"WHERE se.setup_version=?", [RUNNER_SETUP_VERSION, SETUP_VERSION]).fetchone()
|
||||
vr = con.execute(
|
||||
"WITH rn AS (SELECT DISTINCT symbol, session_date FROM setup_events WHERE setup_version=?) "
|
||||
"SELECT avg(CASE WHEN l.reached_1r_before_minus_1r THEN 1.0 ELSE 0 END), count(*) "
|
||||
@@ -1391,7 +1385,7 @@ def lift(con):
|
||||
ct = df[df["cat_type"].notna()].groupby("cat_type", observed=True)[label].agg(["mean", "count"])
|
||||
ct = ct[ct["count"] >= 15].sort_values("mean", ascending=False)
|
||||
if len(ct):
|
||||
print(f" catalyst_type (n>=15): " + " | ".join(
|
||||
print(" catalyst_type (n>=15): " + " | ".join(
|
||||
f"{t}:{r['mean']*100:.0f}%/{int(r['count'])}({r['mean']/base:.1f}x)" for t, r in ct.iterrows()))
|
||||
print("\nCAVEAT: ~17-19 autocorrelated days, +20% runners are sparse — a lift is a HYPOTHESIS to")
|
||||
print("shadow-confirm forward, not a validated win-rate. Anything 'thin n' is noise until more data.")
|
||||
|
||||
@@ -6,7 +6,6 @@ Append-only event storage with canonical event types.
|
||||
from .event_schema import (
|
||||
BaseEvent,
|
||||
EventType,
|
||||
EventMode,
|
||||
)
|
||||
from .db import get_connection
|
||||
from uuid import uuid4
|
||||
|
||||
@@ -126,36 +126,7 @@ CREATE TABLE IF NOT EXISTS news_events (
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS halt_events (
|
||||
id VARCHAR,
|
||||
symbol VARCHAR,
|
||||
halt_start TIMESTAMP,
|
||||
halt_end TIMESTAMP,
|
||||
halt_type VARCHAR,
|
||||
price_at_halt DOUBLE PRECISION,
|
||||
resumed_price DOUBLE PRECISION,
|
||||
gap_on_resume_pct DOUBLE PRECISION,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS market_context (
|
||||
timestamp TIMESTAMP,
|
||||
trade_date DATE,
|
||||
spy_open DOUBLE PRECISION,
|
||||
spy_high DOUBLE PRECISION,
|
||||
spy_low DOUBLE PRECISION,
|
||||
spy_close DOUBLE PRECISION,
|
||||
spy_volume BIGINT,
|
||||
qqq_open DOUBLE PRECISION,
|
||||
qqq_close DOUBLE PRECISION,
|
||||
spy_intraday_return_pct DOUBLE PRECISION,
|
||||
vix_open DOUBLE PRECISION,
|
||||
vix_level DOUBLE PRECISION,
|
||||
advance_decline_ratio DOUBLE PRECISION,
|
||||
up_volume_down_volume_ratio DOUBLE PRECISION,
|
||||
tape_regime_flag VARCHAR,
|
||||
PRIMARY KEY (timestamp)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS dilution_events (
|
||||
id VARCHAR PRIMARY KEY,
|
||||
@@ -168,14 +139,6 @@ CREATE TABLE IF NOT EXISTS dilution_events (
|
||||
gross_proceeds DOUBLE PRECISION
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS short_interest (
|
||||
symbol VARCHAR,
|
||||
report_date DATE,
|
||||
short_interest_shares BIGINT,
|
||||
short_interest_pct_float DOUBLE PRECISION,
|
||||
days_to_cover DOUBLE PRECISION,
|
||||
PRIMARY KEY (symbol, report_date)
|
||||
);
|
||||
|
||||
-- =====================================================================
|
||||
-- Features / setups / outcomes / backtests
|
||||
@@ -252,102 +215,14 @@ CREATE TABLE IF NOT EXISTS outcome_labels (
|
||||
time_to_max_drawdown_minutes DOUBLE PRECISION
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS backtest_runs (
|
||||
run_id VARCHAR PRIMARY KEY,
|
||||
run_timestamp TIMESTAMP,
|
||||
strategy_name VARCHAR,
|
||||
strategy_version VARCHAR,
|
||||
feature_version VARCHAR,
|
||||
date_range_start DATE,
|
||||
date_range_end DATE,
|
||||
parameter_config_json VARCHAR,
|
||||
summary_metrics_json VARCHAR,
|
||||
total_trades INTEGER,
|
||||
win_rate DOUBLE PRECISION,
|
||||
expectancy DOUBLE PRECISION,
|
||||
max_drawdown DOUBLE PRECISION,
|
||||
profit_factor DOUBLE PRECISION
|
||||
);
|
||||
|
||||
-- =====================================================================
|
||||
-- Paper trading
|
||||
-- =====================================================================
|
||||
CREATE TABLE IF NOT EXISTS simulated_orders (
|
||||
order_id VARCHAR PRIMARY KEY,
|
||||
session_id VARCHAR,
|
||||
symbol VARCHAR,
|
||||
created_at TIMESTAMP,
|
||||
side VARCHAR,
|
||||
order_type VARCHAR,
|
||||
qty INTEGER,
|
||||
intended_entry DOUBLE PRECISION,
|
||||
stop_price DOUBLE PRECISION,
|
||||
target_price DOUBLE PRECISION,
|
||||
status VARCHAR,
|
||||
strategy_name VARCHAR,
|
||||
setup_id VARCHAR
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS simulated_fills (
|
||||
fill_id VARCHAR PRIMARY KEY,
|
||||
order_id VARCHAR,
|
||||
symbol VARCHAR,
|
||||
fill_time TIMESTAMP,
|
||||
fill_price DOUBLE PRECISION,
|
||||
qty INTEGER,
|
||||
slippage DOUBLE PRECISION,
|
||||
commission DOUBLE PRECISION,
|
||||
venue VARCHAR
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS strategy_runs (
|
||||
run_id VARCHAR PRIMARY KEY,
|
||||
started_at TIMESTAMP,
|
||||
ended_at TIMESTAMP,
|
||||
mode VARCHAR,
|
||||
strategy_name VARCHAR,
|
||||
strategy_version VARCHAR,
|
||||
config_json VARCHAR,
|
||||
summary_json VARCHAR
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS paper_sessions (
|
||||
session_id VARCHAR PRIMARY KEY,
|
||||
trade_date DATE,
|
||||
started_at TIMESTAMP,
|
||||
ended_at TIMESTAMP,
|
||||
starting_equity DOUBLE PRECISION,
|
||||
ending_equity DOUBLE PRECISION,
|
||||
realized_pnl DOUBLE PRECISION,
|
||||
unrealized_pnl DOUBLE PRECISION,
|
||||
total_orders INTEGER,
|
||||
total_fills INTEGER,
|
||||
total_setups INTEGER,
|
||||
notes VARCHAR
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS paper_missed_trades (
|
||||
audit_id VARCHAR PRIMARY KEY,
|
||||
session_id VARCHAR,
|
||||
symbol VARCHAR,
|
||||
setup_id VARCHAR,
|
||||
reason VARCHAR,
|
||||
setup_time TIMESTAMP,
|
||||
evaluated_at TIMESTAMP,
|
||||
attempted_entry_time TIMESTAMP,
|
||||
entry_cutoff VARCHAR,
|
||||
minutes_past_cutoff DOUBLE PRECISION,
|
||||
success_score_pct DOUBLE PRECISION,
|
||||
criteria_passed INTEGER,
|
||||
criteria_total INTEGER,
|
||||
provider_status VARCHAR,
|
||||
provider_degraded_count INTEGER,
|
||||
source_status VARCHAR,
|
||||
source_degraded_count INTEGER,
|
||||
source_backoff_count INTEGER,
|
||||
created_at TIMESTAMP,
|
||||
details_json VARCHAR
|
||||
);
|
||||
|
||||
-- =====================================================================
|
||||
-- Raw landing (append-only) + telemetry + scanner snapshots
|
||||
@@ -412,18 +287,6 @@ CREATE INDEX IF NOT EXISTS idx_news_catalyst_cache_symbol
|
||||
CREATE INDEX IF NOT EXISTS idx_news_catalyst_cache_enriched
|
||||
ON news_catalyst_cache (enriched_at);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS telemetry_events (
|
||||
id VARCHAR PRIMARY KEY,
|
||||
event_type VARCHAR,
|
||||
session_id VARCHAR,
|
||||
symbol VARCHAR,
|
||||
source VARCHAR,
|
||||
from_state VARCHAR,
|
||||
to_state VARCHAR,
|
||||
reason VARCHAR,
|
||||
metadata_json VARCHAR,
|
||||
created_at TIMESTAMP DEFAULT current_timestamp
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS scanner_snapshots (
|
||||
id VARCHAR PRIMARY KEY,
|
||||
|
||||
@@ -103,27 +103,6 @@ def query_session_summary(store) -> list[dict]:
|
||||
return summaries
|
||||
|
||||
|
||||
def query_symbol_status(store, symbol: str | None = None) -> list[dict]:
|
||||
"""Query current status for symbols."""
|
||||
events = store.query_events(
|
||||
event_type="symbol_state_changed",
|
||||
symbol=symbol,
|
||||
)
|
||||
|
||||
return [
|
||||
{
|
||||
"event_id": event["id"],
|
||||
"symbol": json.loads(event.get("payload_json", "{}")).get("symbol"),
|
||||
"previous_state": json.loads(event.get("payload_json", "{}")).get(
|
||||
"previous_state"
|
||||
),
|
||||
"new_state": json.loads(event.get("payload_json", "{}")).get("new_state"),
|
||||
"timestamp": event["timestamp"],
|
||||
}
|
||||
for event in events
|
||||
]
|
||||
|
||||
|
||||
def query_approval_queue(store) -> list[dict]:
|
||||
requested = store.query_events(event_type="order_approval_requested", limit=None)
|
||||
approved = store.query_events(event_type="order_approved", limit=None)
|
||||
@@ -158,56 +137,6 @@ def query_approval_queue(store) -> list[dict]:
|
||||
return queue
|
||||
|
||||
|
||||
def query_positions_view(store) -> list[dict]:
|
||||
"""Query all positions (opened/closed events)."""
|
||||
opened = store.query_events(event_type="position_opened")
|
||||
closed = store.query_events(event_type="position_closed")
|
||||
position_events = opened + closed
|
||||
|
||||
positions = []
|
||||
for event in position_events:
|
||||
payload = json.loads(event.get("payload_json", "{}"))
|
||||
positions.append(
|
||||
{
|
||||
"event_id": event["id"],
|
||||
"position_id": payload.get("position_id"),
|
||||
"symbol": payload.get("symbol"),
|
||||
"event_type": event["event_type"],
|
||||
"entry_price": payload.get("entry_price"),
|
||||
"quantity": payload.get("quantity"),
|
||||
"stop_loss_price": payload.get("stop_loss_price"),
|
||||
"exit_price": payload.get("exit_price")
|
||||
if event["event_type"] == "position_closed"
|
||||
else None,
|
||||
"exit_reason": payload.get("exit_reason")
|
||||
if event["event_type"] == "position_closed"
|
||||
else None,
|
||||
"realized_pnl": payload.get("realized_pnl")
|
||||
if event["event_type"] == "position_closed"
|
||||
else None,
|
||||
"timestamp": event["timestamp"],
|
||||
}
|
||||
)
|
||||
|
||||
return positions
|
||||
|
||||
|
||||
def query_event_timeline(store, session_id: str | None = None) -> list[dict]:
|
||||
"""Query full event timeline for a session."""
|
||||
return store.query_events(session_id=session_id, limit=None)
|
||||
|
||||
|
||||
def query_settings_snapshot(store) -> dict:
|
||||
"""Query current settings snapshot."""
|
||||
events = store.query_events(event_type="settings_snapshot")
|
||||
|
||||
if not events:
|
||||
return {}
|
||||
|
||||
latest_event = events[-1]
|
||||
return json.loads(latest_event.get("payload_json", "{}"))
|
||||
|
||||
|
||||
def query_ready_signals_snapshot(store, session_id: str | None = None) -> list[dict]:
|
||||
"""Latest signal_ready per symbol, newest first. Feeds the dashboard."""
|
||||
events = store.query_events(
|
||||
|
||||
@@ -7,7 +7,6 @@ based on Ross Cameron momentum strategy specifications.
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from typing import Literal
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
@@ -192,7 +191,6 @@ def detect_first_pullback(
|
||||
|
||||
highs = bars["high"].values
|
||||
lows = bars["low"].values
|
||||
closes = bars["close"].values
|
||||
|
||||
# Find impulse high in early session window (avoid late-day highs)
|
||||
search_end = min(len(highs), impulse_search_bars)
|
||||
|
||||
Reference in new issue
Block a user