Commit Graph
100 Commits
Author SHA1 Message Date
Celes Renata 3b7ded37cc fix: global event detail returns 'impacts' field to match frontend type
API was returning 'affected_companies' but frontend GlobalEventDetail
type expects 'impacts'. Renamed the response field.
2026-04-17 05:30:36 +00:00
Celes Renata bb3060c3b7 fix: render trend evidence as readable labels instead of raw UUIDs
- Pattern IDs (pattern:META:other:1d) shown as 'pattern META other (1d)'
- Document UUIDs shown as clickable 'doc:43156423…' links to document detail
- Unknown formats shown truncated as fallback
2026-04-17 05:29:00 +00:00
Celes Renata 62769c9b7e fix: macro impacts API returns {exposure_profile, impacts} to match frontend type
API was returning a flat array but frontend expects CompanyMacroImpacts
wrapper with exposure_profile and impacts fields. Also queries the
exposure_profiles table for the company's active profile.
2026-04-17 05:26:08 +00:00
Celes Renata d712d6b118 chore: gitignore .hypothesis/ cache directory 2026-04-17 05:16:47 +00:00
Celes Renata 7c23c044d7 feat: agent variants — migration, API, service integration, frontend, tests
- Migration 027: agent_variants table with single-active enforcement,
  variant_id column on agent_performance_log
- API: full CRUD, clone from agent/variant, activate/deactivate,
  per-variant performance metrics and history endpoints
- Services: extractor, event classifier, thesis rewriter all wired
  to AgentConfigResolver with variant override support
- Frontend: variant list, comparison view, create/edit/clone forms,
  activate/delete actions on Agents page
- Tests: API tests + 5 property-based tests (single-active invariant,
  clone preservation, config resolution, slug determinism, update idempotence)
- Spec files for agent-variants feature
2026-04-17 05:15:42 +00:00
Celes Renata 734bf001a7 feat: risk tier selector on Trading page + confidence filter on Recommendations
- Trading page: added conservative/moderate/aggressive selector that
  updates the trading engine config via PUT /api/trading/config
- Recommendations page: added risk tier dropdown that defaults to the
  engine's current tier and filters recs by the tier's min_confidence
- Backend: added min_confidence query param to GET /api/recommendations
- Risk tier thresholds: conservative ≥0.75, moderate ≥0.55, aggressive ≥0.40
2026-04-17 05:08:54 +00:00
Celes Renata 49e3955fab fix: add missing agent_config.py — was untracked, causing extractor crash in cluster 2026-04-17 04:41:58 +00:00
Celes Renata 0f06cf8971 docs: update README, runbook, and steering files for today's changes
- README: added AI agent management section, updated paper trading
  description (no manual capital controls, broker-synced reset)
- Steering: migration numbers updated to 027 (next: 028), added
  trading engine endpoint, ruff pinning and isort config notes
- Runbook: already had reset/Alpaca sections from earlier commits
2026-04-17 04:37:44 +00:00
Celes Renata fde819ec09 docs: update README and runbook for broker-synced reset, confidence dampener, paper account workflow 2026-04-17 04:32:49 +00:00
Celes Renata fd862da29e fix: remove broken capital controls, reset now queries broker for real balance
- Removed PUT /api/trading/capital (set capital) — only touched in-memory state
- Removed POST /api/trading/capital/adjust (add/withdraw) — same problem
- Reset endpoint now: liquidates Alpaca positions, cancels orders, clears DB,
  then queries Alpaca for real portfolio_value to set engine capital
- Frontend: replaced CapitalCard with simple ResetCard (one button)
- Removed useSetTradingCapital and useAdjustCapital hooks
2026-04-17 04:24:10 +00:00
Celes Renata 5fb59b379c feat: reset endpoint now liquidates Alpaca positions and cancels orders
- Added cancel_all_orders() and close_all_positions() to AlpacaBrokerAdapter
- Reset endpoint creates a temporary adapter to call Alpaca DELETE /v2/orders
  and DELETE /v2/positions before clearing DB and engine state
- Also clears positions table and processed_recommendation_ids on reset
- Broker reset is best-effort — DB/engine reset proceeds even if Alpaca fails
2026-04-17 04:03:31 +00:00
Celes Renata 5fc78bd9b4 feat: add 7 tests for confidence agreement dampener — sample-size boundary coverage 2026-04-17 03:48:08 +00:00
Celes Renata e21f162e48 fix: dampen agreement factor by sample size in trend confidence to prevent low-evidence inflation
Agreement of 1-2 signals was inflating confidence to paper-eligible
levels (0.575) even with low credibility sources. Added log2-based
dampener that scales agreement contribution by unique source count,
saturating at n=7. Single signals now cap at 0.39 confidence,
2 signals at 0.49 — both correctly below paper threshold (0.50).
2026-04-17 03:41:39 +00:00
Celes Renata d80d44e2fc fix: update stale tests — 50 companies, normalization defaults, low-confidence thresholds 2026-04-17 03:28:22 +00:00
Celes Renata 8ac2c1ea7a fix: declare services as known-first-party in ruff isort config for CI parity 2026-04-17 03:18:26 +00:00
Celes Renata 3084463c78 fix: pin ruff==0.15.10 to match local version and fix CI I001 failures 2026-04-17 03:16:28 +00:00
Celes Renata 376d961a08 ci: add ruff version + diff output to lint step for debugging 2026-04-17 03:11:21 +00:00
Celes Renata 6179382d1e feat: wire all 3 agents to DB config resolver
- Recommendation worker now resolves thesis-rewriter config from DB
  and passes ollama_config to generate_recommendation. Thesis rewriting
  is now active when the thesis-rewriter agent exists in ai_agents.
  Refreshes config every 50 jobs.

- Event classifier now resolves its own config separately from the
  document extractor via 'event-classifier' slug. Uses a separate
  OllamaClient when the model differs from the extractor. Refreshes
  alongside the extractor every 100 jobs.

- Document extractor was already wired (existing code).

- Added 8 unit tests for AgentConfigResolver covering: DB resolution,
  variant override, not-found, DB errors, TTL caching, cache refresh,
  and invalidation.
2026-04-17 02:59:40 +00:00
Celes Renata c501ccea40 fix: default model to qwen3.5:9b + improve event classifier prompt
- Migration 026 and OllamaConfig now default to qwen3.5:9b instead of
  llama3.1:8b. Existing deployments keep their current model (qwen3.5:9b-fast)
  since the migration uses WHERE NOT EXISTS on slug.

- Event classifier system prompt expanded with macro-vs-company filtering:
  explicitly instructs the model to NOT classify single-company news
  (lawsuits, earnings, management changes, debt crises) as macro events.
  Sets severity=low and confidence<0.3 for company-specific articles.
  Reserves 'critical' severity for multi-country/global market events.
  Prevents over-tagging event_types by requiring direct description.

- Updated test_system_prompt_is_concise threshold to accommodate the
  expanded prompt (300 → 1000 chars).
2026-04-17 02:53:38 +00:00
Celes Renata 90614dd7bb feat: paper trading capital controls — add, withdraw, and full reset
Three distinct capital operations on the Trading Controls page:

- Set Capital: overwrites pool balances to a new amount (existing)
- Add/Withdraw: adjusts active pool by a delta without touching
  positions, orders, or history. Validates sufficient balance for
  withdrawals. Logged to reserve_pool_ledger as manual_adjustment.
- Reset Everything: nuclear option — deletes all positions, orders,
  trading decisions, stop levels, snapshots, backtests, notifications,
  and circuit breaker events, then resets capital fresh. Red button
  with double-confirmation dialog.

Backend: POST /api/trading/capital/adjust and POST /api/trading/reset
Frontend: CapitalCard rebuilt with three sections and confirmation UIs
2026-04-17 02:23:26 +00:00
Celes Renata 45752b9a29 feat: AI Agents management page with per-agent performance tracking
New Agents tab in the sidebar (Ops group) for viewing, editing, and
creating AI agent configurations:

Database (migration 026):
- ai_agents table: editable configs for each LLM agent (model, prompts,
  temperature, tokens, retries). source='system' for built-in,
  source='user' for custom. Seeds 3 system agents (Document Extractor,
  Event Classifier, Thesis Rewriter) using WHERE NOT EXISTS to never
  overwrite user edits across reinstalls.
- agent_performance_log table: per-invocation metrics (duration,
  confidence, retries, tokens, errors) linked to agent config.

API endpoints:
- GET/POST /api/agents — list and create agents
- GET/PUT/DELETE /api/agents/{id} — view, edit, delete (system agents
  can be edited but not deleted)
- GET /api/agents/{id}/performance — aggregated metrics (success rate,
  avg/p95 latency, confidence, token usage)
- GET /api/agents/{id}/performance/history — hourly time series

Frontend:
- AgentsPage with sidebar list + detail panel
- Agent detail: config display, system prompt viewer, performance
  dashboard with metrics cards and time-series chart
- Edit form: all config fields editable including system prompt,
  model, temperature, tokens, retries
- Create form: new user-defined agents with auto-slug generation
- System agents show blue badge, user agents show green badge
2026-04-17 01:24:35 +00:00
Celes Renata 86b549e5e1 fix: migrations preserve trend history across reinstalls
Migration 023 was deleting all but the latest trend_windows row per
entity before 024 could save them to trend_history. On reinstall,
this wiped the entire history every time.

Fixed by restructuring:
- 023 now creates trend_history FIRST and copies all trend_windows
  rows into it before deduplicating trend_windows down to latest-only.
  Uses NOT EXISTS to avoid duplicating rows on re-runs.
- 024 is now idempotent: ensures table/indexes exist and backfills
  from recommendations (last 7 days, 1 point per ticker/window/hour)
  to reconstruct approximate history even if trend_windows was sparse.

Both migrations are safe to re-run on existing databases.
2026-04-17 01:15:28 +00:00
Celes Renata 2360c501e4 feat: intraday hourly price bars via Polygon range endpoint
- New 'intraday_bars' endpoint in PolygonMarketAdapter: fetches hourly
  bars for today using range_bars URL with timespan=hour, sort=asc
- Scheduler expands intraday_bars global source into per-ticker jobs
  for all active companies (every 15 minutes via polling_interval)
- Migration 025 inserts the intraday source with 900s cadence
- Frontend price matching uses closest-timestamp instead of date-string
  matching, with 2h tolerance for intraday and 36h for daily windows
- Bumped market price fetch limit to 200 for intraday granularity
2026-04-17 01:13:24 +00:00
Celes Renata c4206b3f4c feat: overlay stock price on trend charts with right Y axis
- New GET /api/market/prices/{ticker} endpoint serving OHLCV data from
  market_snapshots, deduped by bar_timestamp
- New useMarketPrices hook in frontend
- Trend chart now shows price (purple line) on a right Y axis ($)
  alongside trend metrics (%) on the left Y axis
- Custom tooltip formats price as dollars, metrics as percentages
- Price line uses connectNulls for days with missing bar data
2026-04-17 01:09:36 +00:00
Celes Renata ebe0ccca4c fix: trend chart tooltip shows no data on hover
Replaced Recharts default Tooltip with formatter prop (broken in
Recharts v3 with explicit type annotations) with a custom
TrendTooltip component matching the SQL Explorer pattern. Shows
each series name, value, and color on hover.
2026-04-17 01:01:02 +00:00
Celes Renata 5593ee6d92 fix: company detail crash — patterns API returns object not array
/api/patterns/{ticker} returns {ticker, patterns, count} but
useHistoricalPatterns typed its response as HistoricalPattern[].
The .map() call on the object caused 'e.map is not a function'.
Fixed by unwrapping resp.patterns in the hook's queryFn.
2026-04-17 00:50:51 +00:00
Celes Renata 7c589353f8 fix: blank company charts + competitor GUIDs instead of tickers
Trend charts blank:
- trend_windows uses upsert (1 row per ticker/window), so charts had
  at most 1 data point. Added trend_history table (migration 024) that
  appends every snapshot. New /api/trends/history endpoint serves the
  time series. Frontend now uses useTrendHistory for charts and
  useTrends for the latest summary card.

Competitor GUIDs:
- list_competitors query returned raw company_b_id UUIDs without
  joining companies table. Added LEFT JOIN with CASE to resolve the
  other company's ticker and legal_name. Updated Pydantic model to
  include enriched fields. Frontend fallback changed from truncated
  UUID to ticker/legal_name/Unknown.
2026-04-17 00:42:55 +00:00
Celes Renata f2d8744a4f fix: backtest submission shows no results — 4 bugs fixed
- ID mismatch: API generated a throwaway UUID while BacktestReplay
  generated its own internally. Frontend polled with wrong ID and
  never found the DB row. Now pre-generate ID in endpoint and pass
  it to BacktestReplay.
- Field name: API returned 'backtest_id' but frontend read 'data.id'.
  Unified to 'id' everywhere.
- No polling: useBacktestResult fired once and never refreshed.
  Added refetchInterval that polls every 2s while status is running.
- Response shape: GET endpoint nested results under 'result' object
  but frontend expected flat fields. Flattened response to match
  BacktestResult type.
- Added running/failed/completed status indicators in BacktestPanel.
2026-04-17 00:31:17 +00:00
Celes Renata f11aa0a1ee fix: deduplicate recommendations and widen position sizing range
- Add dedup check in recommendation worker: skip generation when latest
  rec for same ticker+window has identical action/mode/confidence
- Widen position sizing range (1-10% portfolio, 0.3-2% max loss) and
  factor in trend strength + evidence count for differentiated sizing
- API returns only latest recommendation per ticker by default (DISTINCT ON)
  to eliminate duplicate rows in the frontend list view
2026-04-17 00:15:32 +00:00
Celes Renata 29f46d387c fix: 6 buy/sell logic bugs — sells check trading window, persist audit trail, dedup after position check, no duplicate buys, fix stop-level insert, profit-taking respects market hours 2026-04-17 00:07:50 +00:00
Celes Renata 1246b3868b fix: use current_price not avg_entry_price for invested calc — prevents margin-inflated numbers showing $0 available 2026-04-17 00:04:12 +00:00
Celes Renata f57167ce4d fix: only poll recommendations from last 2 hours (not 24h), persist snapshots during market hours for performance tab 2026-04-16 23:53:54 +00:00
Celes Renata 18eb150c75 fix: confidence formula now uses unique doc count + signal agreement instead of raw signal count — prevents 99.9% inflation 2026-04-16 23:48:05 +00:00
Celes Renata 1a5fb2e36a fix: recovery sweep touches updated_at after re-enqueue to prevent duplicate flooding every 5 min 2026-04-16 19:13:10 +00:00
Celes Renata 693d9e0d60 fix: reduce LLM timeouts — truncate docs to 8k/6k chars, cut num_predict 16k→4k, tighten prompts, trim anti-hallucination rules 2026-04-16 18:56:11 +00:00
Celes Renata 3a856cf6ff fix: reduce Ollama timeout from 300s to 240s (4 min) 2026-04-16 18:43:50 +00:00
Celes Renata 60cfb7618e fix: recovery sweep skips docs that already have global_events — prevents re-enqueue loop 2026-04-16 18:27:21 +00:00
Celes Renata 1043710b6d fix: track last_published_at per source to avoid re-fetching same articles — applies to both news_api and macro_news 2026-04-16 18:12:12 +00:00
Celes Renata 513310abba fix: stop tagging all macro_news articles as macro_event — default to article, let extractor reclassify. Also reduced fetch limit to 20 and cadence to 30min 2026-04-16 18:09:50 +00:00
Celes Renata f83577480f fix: alternate extractor between macro and extraction queues (1:2 ratio) to prevent starvation 2026-04-16 17:45:25 +00:00
Celes Renata 2440cddd37 feat: add comprehensive table retention cleanup to scheduler — 10 tables with per-table retention windows 2026-04-16 15:56:50 +00:00
Celes Renata 63287903d0 feat: wire up stop levels, circuit breaker daily loss, profit-taking, real portfolio/decisions/history endpoints 2026-04-16 15:52:46 +00:00
Celes Renata 1329df0bbf feat: sell execution, correlation matrix from market data, US market holiday awareness
- Sell path: looks up existing position, sells full quantity, returns proceeds to pool
- Correlation matrix: computed from 30-day market_snapshots on startup + every 5min
- Holidays: 10 major US market holidays for 2026 checked in trading window functions
2026-04-16 15:36:49 +00:00
Celes Renata 2e77cf32fd fix: critical — track capital properly: load invested positions on startup, deduct on act, sync every 5min 2026-04-16 15:29:28 +00:00
Celes Renata 9a8d36068a fix: convert Decimal to float in API responses instead of string — fixes positions page crash 2026-04-16 15:25:40 +00:00
Celes Renata 354c3d484a fix: fetch current prices from market_snapshots before evaluating recommendations — fixes 'Invalid current price' skip 2026-04-16 15:17:49 +00:00
Celes Renata 2a6aac47a6 fix: add decision logging to trading engine, flushed 103k stale dedup keys 2026-04-16 15:12:58 +00:00
Celes Renata c114e77b1c fix: limit recommendation poll to 50 per cycle to prevent 85k-rec processing stall, add poll logging 2026-04-16 15:05:26 +00:00
Celes Renata 136b149000 fix: add logging config to trading engine, add /api/trading/debug diagnostic endpoint 2026-04-16 14:55:42 +00:00
Celes Renata 6bab199159 fix: trend_windows now upserts instead of accumulating (7.5GB→4MB), add competitive signal retention cleanup 2026-04-16 14:32:24 +00:00
Celes Renata 58a8726306 feat: add paper trading capital controls — API endpoint + UI with presets, fix status/metrics to read real state, fix migration duplicates 2026-04-16 14:06:30 +00:00
Celes Renata 14e411daf9 fix: trading status and metrics endpoints now read real portfolio state instead of hardcoded zeros 2026-04-16 14:02:38 +00:00
Celes Renata 5cc64498c0 fix: skip already-propagated docs in aggregation, limit to last hour + 10 docs instead of 50 2026-04-16 09:35:11 +00:00
Celes Renata 540d54c3f7 feat: scale aggregation to 4 replicas across cluster nodes 2026-04-16 09:26:22 +00:00
Celes Renata f0887afd9b fix: cap competitive signals to 500 most recent per window to prevent 67k row aggregation bottleneck 2026-04-16 09:24:31 +00:00
Celes Renata c5e9644f6f fix: guard EventSource for jsdom test env, add rate-limits MSW handler 2026-04-16 08:19:53 +00:00
Celes Renata 58a05ca322 feat: add SSE stream for live pipeline status, add all 10 queues + DLQs, configure nginx for SSE 2026-04-16 08:15:44 +00:00
Celes Renata 0b1640abb9 feat: add status colors for document pipeline stages, add status filter to documents page 2026-04-16 08:06:12 +00:00
Celes Renata 87579d68da fix: add stale document recovery sweep to scheduler, re-enqueues orphaned parsed docs every 5 min 2026-04-16 07:59:30 +00:00
Celes Renata cdc825619e feat: add live queue depths to pipeline health API and dashboard 2026-04-16 07:49:07 +00:00
Celes Renata 8050f4a03b chore: mark all Phase 2 tasks (27-37) as complete
All 152 tasks across both phases are now marked complete:
- Phase 1 (1-26): pure computation modules, property tests, API, frontend, infra
- Phase 2 (27-37): live decision loop, stop-loss monitor, performance metrics,
  risk tier scheduler, rebalancer, notification dispatch, backtest replay,
  real DB connections, paper trading config, integration tests
2026-04-16 07:27:35 +00:00
Celes Renata 0ee7f26633 feat: raise market_api rate to 20/min, add global Polygon cap at 45/min, add rate-limit API + watchlist warning 2026-04-16 07:26:10 +00:00
Celes Renata 0b3ab4ed90 feat: add 11 new saved queries, fix window quoting and cross-table join in samples 2026-04-16 07:14:44 +00:00
Celes Renata f1e32e9186 fix: add round(double precision, integer) overload so ad-hoc queries work without ::numeric casts 2026-04-16 07:10:23 +00:00
Celes Renata 981e16a27f fix: quote reserved keyword 'window' in trend query, add Top Movers sample, make seed upsert 2026-04-16 06:25:38 +00:00
Celes Renata 1ccea17600 fix: tooltip type inference for Recharts strict mode 2026-04-16 06:01:29 +00:00
Celes Renata 79a85723b6 feat: rich tooltips in SQL Explorer charts show all row values
Hover over any bar, line point, or scatter dot to see every column
value for that data point. The Y-axis column is highlighted in
brand color, X-axis in white, and other columns in gray. Works
for all chart types (bar, line, scatter, auto).
2026-04-16 05:57:06 +00:00
Celes Renata b43ad88f5d feat: auto-chart detection in SQL Explorer
Adds an ' Auto' button that analyzes query results and picks the
best chart type and column mapping:

- Date/time column + numeric → line chart (time series)
- Categorical + numeric → bar chart (categories)
- Two numeric columns → scatter plot
- Shows detected type and column names as a label

Click Auto, run any query, and it figures out the rest.
2026-04-16 05:52:41 +00:00
Celes Renata 7fefc65692 chore: remove runmefirst.sh from repo, add to gitignore
Deploy scripts live on gremlin-1 at ~/sources/kube/stonks-oracle/,
not in the git repo. They reference local secret files and should
not be version controlled.
2026-04-16 05:39:56 +00:00
Celes Renata 328cb0de28 fix: SQL Explorer chart parses string values as floats
The pg-query API returns all values as strings. The chart builder
was using Number() which returns NaN for non-numeric strings.
Now uses parseFloat with NaN fallback to 0.
2026-04-16 05:33:53 +00:00
Celes Renata 1107d34027 fix: SQL Explorer handles comments and shows descriptive errors
- Strip SQL comments (-- and /* */) before checking for SELECT,
  so queries with leading comments don't get rejected
- Show the actual error detail from the API response instead of
  generic 'API error 400' in the SQL Explorer UI
2026-04-16 05:25:45 +00:00
Celes Renata d28787a8ee fix: add unique constraint on saved_queries.name to prevent duplicates
The migration ran on every deploy, inserting duplicate queries each
time (96 instead of 12). Added UNIQUE constraint on name and changed
ON CONFLICT to reference it. Cleaned up 84 duplicates in DB.
2026-04-16 05:16:18 +00:00
Celes Renata a3b2e97c2c fix: allow SMTP port 587 egress for Gmail notifications
The trading engine network policy only allowed egress on ports 443
(HTTPS) and 53 (DNS). Gmail SMTP uses port 587 (STARTTLS), causing
'Network is unreachable' when sending notifications.
2026-04-16 05:04:08 +00:00
Celes Renata c4666c071b feat: wire Gmail SMTP notifications with app password
Replaced the Gmail API (OAuth2) notification delivery with plain
SMTP using a Gmail app password. Much simpler setup — no Google
Cloud project, no OAuth2 flow, no extra dependencies.

- Rewrote _send_gmail() to use smtplib with smtp.gmail.com:587 TLS
- Added stonks-gmail-secrets to Helm chart (GMAIL_SENDER,
  GMAIL_RECIPIENT, GMAIL_APP_PASSWORD)
- Added gmail secret to trading-engine deployment
- Updated runmefirst.sh to read gmail.app from kube dir
- Sender/recipient: celes@celestium.life
2026-04-16 02:37:40 +00:00
Celes Renata 9aae57f3e1 docs: rewrite README and runbook for current platform state
README: updated architecture diagram, three signal layers, tracked
universe, autonomous trading engine, global news interpolation,
competitive intelligence, paper trading, notification service,
updated services table, project structure, deployment, endpoints.

Runbook: updated service overview, deployment via runmefirst.sh,
secrets management (keys in kube dir not repo), backup/restore
scripts, trading engine operations, signal layer toggles, database
nuke & rebuild, monitoring, CI/CD, removed hardcoded secrets.
2026-04-16 02:06:18 +00:00
Celes Renata e652a62dbc fix: Trading Controls page field mapping for macro/competitive status
The API returns macro_enabled/competitive_enabled but the TypeScript
interfaces expected 'enabled'. The toggles always showed disabled.
Now handles both field names with fallback.
2026-04-16 01:46:13 +00:00
Celes Renata 88c9f50371 fix: treat 404 on Alpaca positions endpoint as empty result
Alpaca returns 404 when you don't hold a position in a ticker.
The ingestion worker was logging this as an error and incrementing
the failure count. Now returns an empty items list instead, since
'no position' is a valid state, not an error.
2026-04-16 01:33:35 +00:00
Celes Renata 00ea917fc0 fix: add broker secrets to ingestion worker deployment
The ingestion worker creates an AlpacaBrokerAdapter but the pod
didn't have BROKER_API_KEY/BROKER_API_SECRET env vars, causing
401 Unauthorized on every broker source fetch. Added
stonks-broker-secrets to the ingestion service's secrets list.
2026-04-16 01:25:54 +00:00
Celes Renata 36c92196d2 fix: remove unused Legend import from Dashboards (TS strict) 2026-04-16 01:11:23 +00:00
Celes Renata 949324dc89 feat: SQL Explorer with PostgreSQL schema browser and pre-built queries
The SQL Explorer was querying Trino which has zero tables. Rewrote to
use PostgreSQL directly:

Backend:
- GET /api/analytics/pg-schema: returns all public tables with column
  names, types, and nullability from information_schema
- POST /api/analytics/pg-query: read-only SQL execution against
  PostgreSQL with SELECT-only enforcement, auto LIMIT, and descriptive
  error messages for syntax/table/query errors

Frontend:
- Schema browser shows all PostgreSQL tables with columns and types
- Click a table name → generates SELECT * FROM table LIMIT 100
- Pre-built Queries section with 12 seeded queries covering companies,
  recommendations, trends, market prices, documents, global events,
  trading decisions, ingestion health, reserve pool, sector exposure
- User-saved queries shown separately with delete buttons
- Chart builder, Monaco editor, and save functionality preserved

Migration 021: seeds 12 pre-built saved queries
2026-04-16 01:06:49 +00:00
Celes Renata 55512ca5a8 fix: rewrite dashboards to use PostgreSQL API instead of empty Trino lakehouse
The Trino/Iceberg lakehouse has zero tables, so all Trino-backed
dashboards showed 'No data available'. Rewrote all four to use
existing PostgreSQL-backed API endpoints:

- Sentiment Heatmap: useTrends + useCompanies → sector and ticker
  trend strength bar charts (30k trend_windows in DB)
- Prediction Accuracy: useRecommendations → confidence distribution
  and action distribution charts (30k recommendations in DB)
- Paper PnL: useTradingMetrics + useTradingMetricsHistory → equity
  curve, daily returns, win/loss stats from trading engine
- Model Quality: useModelPerformance + useModelFailures → success
  rate, latency, retries, and failure table from ops API

Removed unused Trino query function and ScatterChart imports.
2026-04-16 00:58:18 +00:00
Celes Renata b5c0c6d7c9 fix: aggregate ingestion throughput chart by time bucket
The throughput API returns one row per source_type per time bucket,
but the chart was mapping each row as a separate bar. With 5 source
types × 24 hours, the bars were tiny and overlapping. Now aggregates
completed/failed/items across source types per time bucket so the
chart shows meaningful totals.
2026-04-16 00:52:29 +00:00
Celes Renata 6eda988e3b fix: strip /v2 suffix from broker base URL to prevent doubled path
The alpaca.url config file contains https://paper-api.alpaca.markets/v2
but the adapter code also prepends /v2/ to all paths, resulting in
/v2/v2/positions which returns 404. Now strips trailing /v2 or /v1
from the configured base URL since the adapter manages API versioning.

This was causing 1,017 consecutive broker sync failures.
2026-04-16 00:45:19 +00:00
Celes Renata 88c2bc84a1 feat: upgrade paper trading to $100k moderate tier
Paper money has no downside — bigger capital exposes more model
behavior: position sizing, diversification, sector exposure,
correlation checks, circuit breakers, reserve pool siphoning,
and risk tier auto-adjustment all become meaningful.

- risk_tier: conservative → moderate (min_confidence 0.55)
- absolute_position_cap: $25 → $10,000
- max_open_positions: 5 → 10
- initial portfolio value: $500 → $100,000
- Updated migration 019, Helm values, and engine default
2026-04-16 00:37:35 +00:00
Celes Renata d21110b3d2 fix: backtest skips duplicate ticker positions to prevent overwrite
When multiple recommendations for the same ticker produce 'act'
decisions, the second one would overwrite the first in
simulated_positions, losing the first position's value and causing
incorrect portfolio value calculations. Now skips if already holding.
2026-04-16 00:28:59 +00:00
Celes Renata 2eaf6dc025 fix: upgrade backtest day summary to WARNING level for visibility 2026-04-16 00:21:46 +00:00
Celes Renata bad7e02e53 fix: add first-skip-reason logging to backtest replay for debugging 2026-04-16 00:16:32 +00:00
Celes Renata 357e68a764 feat: add database and Redis backup/restore scripts
- scripts/backup-db.sh: pg_dump compressed backup with table count
  verification, optional MinIO upload, auto-prune keeping last 7
- scripts/restore-db.sh: restore from backup with safety confirmation,
  scales down services during restore, re-grants permissions, scales
  back up with correct replica counts
- scripts/backup-redis.sh: triggers BGSAVE, copies RDB dump locally,
  shows key stats
2026-04-16 00:10:27 +00:00
Celes Renata 4634f1f3fc fix: remove unused skip_count variable (lint) 2026-04-16 00:07:29 +00:00
Celes Renata ff5055ee4e fix: backtest replay field mapping and logging
- Map DB 'id' field to 'recommendation_id' for evaluate_recommendation()
- Ensure confidence is cast to float (asyncpg may return Decimal)
- Add per-day logging showing rec count, act/skip, positions, pool balance
- Helps diagnose why backtests produce 0 trades
2026-04-15 22:55:26 +00:00
Celes Renata 4501bbebd4 feat: add Polygon grouped daily endpoint for broad market data
Two tiers of market data:
1. Per-ticker prev bars (existing 50 sources, 15-min cadence) for
   watchlist detail — trading decisions, stop-loss, position sizing
2. Grouped daily (new single source, once per day) for broad market
   context — correlation analysis, sector rotation, competitive intel

Changes:
- Add grouped_daily endpoint to PolygonMarketAdapter with auto date
  calculation (previous trading day, skip weekends)
- Add fetch_global_market_sources() to scheduler for sources without
  company_id, scheduled once daily (86400s cadence)
- Update _persist_market_items to use item-level ticker from T field
  and look up company_id dynamically for grouped daily bars
- Migration 020: make company_id nullable on sources and
  market_snapshots tables, add grouped daily source row
- Fix backtest replay to query market_snapshots data->>'c' for prices
2026-04-15 22:38:18 +00:00
Celes Renata ea6c2b3f54 fix: market data rate limiting and backtest price lookup
- Increase market_api polling cadence from 60s to 900s (15 min).
  The prev-day bar endpoint returns the same data all day, so polling
  every minute wastes API quota. 50 tickers at 15-min cadence = ~3.3
  req/min, well within the 5/min rate limit.
- Reduce market_api rate limit from 30/min to 5/min to match.
- Fix backtest replay to query market_snapshots with data->>'c' for
  close prices instead of nonexistent market_data.close_price column.
- Enrich backtest recommendations with prices from market_snapshots
  and sectors from companies table.
2026-04-15 22:19:44 +00:00
Celes Renata 69eb366bf9 fix: backtest simulation uses ET timezone for trading window
The simulated timestamp was 10:00 UTC (6:00 AM ET) which is outside
the trading window. Changed to 11:00 AM ET so backtested decisions
actually pass the trading window check.
2026-04-15 21:48:32 +00:00
Celes Renata 70bad7709a feat: wire live decision loop and enable paper trading
Phase 2 of the autonomous trading engine:

- Replace start()/stop() stubs with real async implementations
- Decision loop: polls recommendations from PostgreSQL, deduplicates
  via Redis, evaluates through the full pipeline, submits orders to
  stonks:queue:broker_orders
- Stop-loss monitor: fetches prices from Polygon API, checks crossings,
  submits immediate sell orders, safety sell after 15 min without data
- Performance loop: computes metrics every 5 min during market hours,
  persists daily snapshots at market close
- Risk tier scheduler: evaluates daily at 16:00 ET, persists tier changes
- Rebalance scheduler: evaluates Monday 09:45 ET, respects circuit breaker
- Notification dispatch: SNS + Gmail with rate limiting and retry
- Backtest replay: fetches historical data, simulates decisions, persists
- Real asyncpg/redis connections in FastAPI lifespan (graceful degradation)
- Migration 019: enable paper trading with conservative tier, 5 cap
- Added max_open_positions to TradingConfig with env var loading
- Phase 2 tasks added to autonomous-trading-engine spec
2026-04-15 20:52:28 +00:00
Celes Renata c4b90a5224 fix: sidebar nav highlights both Trading Controls and Trading Engine
When on /trading/engine, the /trading nav item also matched via
startsWith. Now checks if a more specific child route matches
first and uses exact match in that case.
2026-04-15 20:07:31 +00:00
Celes Renata 78aee4c9e6 fix: add trading-engine to CI build matrix
The service was added to the Helm chart but not to the GitHub Actions
build matrix, causing ImagePullBackOff on deploy.
2026-04-15 19:55:34 +00:00
Celes Renata 3ff910433f fix: reject empty LLM classifications for global events
When the LLM returns empty summary and no key facts, raise ValueError
so the retry logic kicks in instead of persisting an empty event.
Also strip whitespace from summary and filter empty key_facts entries.

Cleaned up 17 empty events from the database.
2026-04-15 19:46:31 +00:00
Celes Renata 326c409d63 fix: use _global fallback for empty ticker in MinIO storage paths
Macro news documents have no ticker, causing upload_normalized_text
and upload_parser_output to produce paths like parsed//2026/...
which MinIO rejects as XMinioInvalidObjectName. Use '_global' as
the path segment when ticker is empty, matching the existing
macro prefix pattern in upload_raw_document.
2026-04-15 19:25:23 +00:00
Celes Renata cdf1cd06bc fix: bump GitHub Actions to Node 24 versions
- actions/checkout v4 → v5
- actions/setup-python v5 → v6
- actions/setup-node v4 → v5
- docker/login-action v3 → v4
- docker/setup-buildx-action v3 → v4
- docker/build-push-action v6 → v7

Silences Node.js 20 deprecation warnings ahead of the
June 2026 forced migration deadline.
2026-04-15 16:24:50 +00:00
Celes Renata 516731e69a fix: remove explicit type annotations on Recharts formatter callbacks
TypeScript strict mode in CI rejects explicit parameter types on
Recharts formatter/tickFormatter callbacks. Use inference with
'as number' casts on the value instead. Also fix unsafe cast in
PortfolioComposition and handle possibly-undefined percent.
2026-04-15 16:17:00 +00:00