feat: implement dual-pipeline signal engine service
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/push/build-2 Pipeline was successful
ci/woodpecker/push/build-1 Pipeline was successful
ci/woodpecker/push/build-3 Pipeline was successful
ci/woodpecker/push/finalize Pipeline was successful
Build and Push / lint-and-test (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.adapters.broker_adapter name:broker-adapter]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.aggregation.worker name:aggregation]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.extractor.worker name:extractor]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.ingestion.worker name:ingestion]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.lake_publisher.worker name:lake-publisher]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.parser.worker name:parser]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.recommendation.worker name:recommendation]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.scheduler.app name:scheduler]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.api.app:app --host 0.0.0.0 --port 8000 name:query-api]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.risk.app:app --host 0.0.0.0 --port 8000 name:risk]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.symbol_registry.app:app --host 0.0.0.0 --port 8000 name:symbol-registry]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.trading.app:app --host 0.0.0.0 --port 8000 name:trading-engine]) (push) Has been cancelled
Build and Push / build-dashboard (push) Has been cancelled
Build and Push / build-superset (push) Has been cancelled
Build and Push / integration-test (push) Has been cancelled
Build and Push / beta-gate (push) Has been cancelled
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/push/build-2 Pipeline was successful
ci/woodpecker/push/build-1 Pipeline was successful
ci/woodpecker/push/build-3 Pipeline was successful
ci/woodpecker/push/finalize Pipeline was successful
Build and Push / lint-and-test (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.adapters.broker_adapter name:broker-adapter]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.aggregation.worker name:aggregation]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.extractor.worker name:extractor]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.ingestion.worker name:ingestion]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.lake_publisher.worker name:lake-publisher]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.parser.worker name:parser]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.recommendation.worker name:recommendation]) (push) Has been cancelled
Build and Push / build-services (map[cmd:python -m services.scheduler.app name:scheduler]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.api.app:app --host 0.0.0.0 --port 8000 name:query-api]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.risk.app:app --host 0.0.0.0 --port 8000 name:risk]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.symbol_registry.app:app --host 0.0.0.0 --port 8000 name:symbol-registry]) (push) Has been cancelled
Build and Push / build-services (map[cmd:uvicorn services.trading.app:app --host 0.0.0.0 --port 8000 name:trading-engine]) (push) Has been cancelled
Build and Push / build-dashboard (push) Has been cancelled
Build and Push / build-superset (push) Has been cancelled
Build and Push / integration-test (push) Has been cancelled
Build and Push / beta-gate (push) Has been cancelled
New service at services/signal_engine/ implementing concurrent heuristic (deterministic scoring) and probabilistic (Bayesian inference) pipelines that evaluate technical signals across 6 timeframes (M30-M) and produce independent BUY/WATCH/SKIP verdicts per ticker per evaluation tick. Components: - Input Normalizer: multi-source data assembly with sentinel fallbacks - Signal Library: Fibonacci, MA Stack, RSI, Cup & Handle, Elliott Wave - Multi-Timeframe Confluence Engine: weighted scoring with D/W/M anchors - Hard Filter Engine: macro_bias, valuation, earnings proximity gating - Heuristic Pipeline: S_total scoring with confidence-gated verdicts - Probabilistic Pipeline: Bayesian log-odds with regime priors, entropy gating, EV_R calculation, and signal correlation penalty - Exit Engine: stop-loss, targets, trailing ATR-based stops - Delta Analyzer: pipeline agreement tracking with rolling Redis metrics - Output Formatter: SignalOutput contract + Recommendation schema mapping - Worker orchestrator: concurrent pipelines with failure isolation - Main entry point: queue polling with fail-safe config loading Infrastructure: - Migration 039: signal_engine_outputs table with 3 indexes - Helm chart: signalEngine service entry (processing tier) - Redis key: QUEUE_SIGNAL_ENGINE constant Tests: 390 tests (unit + property-based) covering all components Config: dual_pipeline_enabled=false by default (safe rollout)
This commit is contained in:
+185
-19
@@ -142,14 +142,35 @@ Trend projection for a specific trend window.
|
||||
### 1.5 Market Prices
|
||||
|
||||
#### `GET /api/market/prices/{ticker}`
|
||||
Historical close prices from `market_snapshots`.
|
||||
Historical OHLCV bars from `market_snapshots`, deduplicated by bar timestamp and ordered oldest-first. Also returns 90-day high/low range.
|
||||
|
||||
| Parameter | Type | Default | Constraints | Description |
|
||||
|-----------|------|---------|-------------|-------------|
|
||||
| `limit` | int | `30` | max `200` | Max bars returned |
|
||||
| `limit` | int | `200` | max `500` | Max bars returned |
|
||||
|
||||
- **Path params:** `ticker` (auto-uppercased)
|
||||
- **Response:** Array of OHLCV objects ordered oldest-first
|
||||
- **Response:** `{ bars: [{ ticker, close, open, high, low, volume, bar_timestamp, captured_at }], range_90d: { low, high } }`
|
||||
|
||||
#### `POST /api/market/backfill/{ticker}`
|
||||
Backfill daily OHLCV bars from Polygon for the last N days. Deduplicates by bar timestamp.
|
||||
|
||||
| Parameter | Type | Default | Constraints | Description |
|
||||
|-----------|------|---------|-------------|-------------|
|
||||
| `days` | int | `90` | max `365` | Number of days to backfill |
|
||||
|
||||
- **Path params:** `ticker` (auto-uppercased)
|
||||
- **Response:** `{ ticker, inserted, total_bars, days }`
|
||||
- **Errors:** `503` — No market data API key configured
|
||||
|
||||
#### `POST /api/market/backfill-all`
|
||||
Backfill daily bars for all active companies from Polygon.
|
||||
|
||||
| Parameter | Type | Default | Constraints | Description |
|
||||
|-----------|------|---------|-------------|-------------|
|
||||
| `days` | int | `90` | max `365` | Number of days to backfill |
|
||||
|
||||
- **Response:** `{ total_inserted, tickers, details[] }` — each detail has `{ ticker, inserted }` or `{ ticker, inserted: 0, error }`
|
||||
- **Errors:** `503` — No market data API key configured
|
||||
|
||||
### 1.6 Recommendations
|
||||
|
||||
@@ -224,8 +245,6 @@ Get audit events for any entity type and ID.
|
||||
|
||||
- **Path params:** `entity_type` (string), `entity_id` (string)
|
||||
- **Response:** Array of audit event objects
|
||||
- **Errors:** `404` — No audit events found
|
||||
|
||||
|
||||
### 1.10 Admin: Source Health
|
||||
|
||||
@@ -331,6 +350,8 @@ Approve or reject a pending operator approval request.
|
||||
#### `GET /api/admin/trading/lockouts`
|
||||
List active symbol lockouts (news-shock, cooldown, manual).
|
||||
|
||||
- **Response:** Array of lockout objects
|
||||
|
||||
#### `POST /api/admin/trading/lockouts`
|
||||
Create a manual symbol lockout.
|
||||
|
||||
@@ -353,7 +374,6 @@ Update operator approval settings.
|
||||
- **Body:** `{ auto_approve_paper?: bool, require_approval_for_live?: bool, approval_timeout_minutes?: int }`
|
||||
- **Response:** Updated approval settings
|
||||
|
||||
|
||||
### 1.13 Operational Dashboard
|
||||
|
||||
#### `GET /api/ops/ingestion/throughput`
|
||||
@@ -450,7 +470,7 @@ Trino catalog/schema/table/column metadata for the schema browser.
|
||||
#### `GET /api/analytics/pg-schema`
|
||||
PostgreSQL table/column metadata with primary keys, foreign keys, and row estimates.
|
||||
|
||||
- **Response:** `{ catalog: "postgresql", schema: "public", tables[] }`
|
||||
- **Response:** `{ catalog: "postgresql", schema: "public", tables[{ name, row_estimate, columns[{ name, type, nullable, primary_key?, references?, has_default? }] }] }`
|
||||
|
||||
#### `POST /api/analytics/pg-query`
|
||||
Run read-only SQL against PostgreSQL directly. Only SELECT statements allowed.
|
||||
@@ -462,17 +482,19 @@ Run read-only SQL against PostgreSQL directly. Only SELECT statements allowed.
|
||||
#### `GET /api/analytics/saved-queries`
|
||||
List all saved queries.
|
||||
|
||||
- **Response:** Array of `{ id, name, description, sql_text, created_by, created_at, updated_at }`
|
||||
|
||||
#### `POST /api/analytics/saved-queries` (201)
|
||||
Save a new query.
|
||||
|
||||
- **Body:** `{ name: string, description?: string, sql_text: string }`
|
||||
- **Response:** `{ id, name, description, sql_text, created_by, created_at }`
|
||||
|
||||
#### `DELETE /api/analytics/saved-queries/{query_id}`
|
||||
Delete a saved query.
|
||||
|
||||
- **Errors:** `404` — Query not found
|
||||
|
||||
|
||||
### 1.16 Macro Signal Layer
|
||||
|
||||
#### `GET /api/admin/macro/status`
|
||||
@@ -501,9 +523,13 @@ List recent global events with filtering.
|
||||
| `limit` | int | `50` | max `200` | Page size |
|
||||
| `offset` | int | `0` | — | Pagination offset |
|
||||
|
||||
- **Response:** Array of global event objects with `id`, `event_types`, `severity`, `affected_regions`, `affected_sectors`, `affected_commodities`, `summary`, `key_facts`, `estimated_duration`, `confidence`, `source_document_id`, `created_at`
|
||||
|
||||
#### `GET /api/macro/events/{event_id}`
|
||||
Event detail with affected companies and macro impact scores.
|
||||
|
||||
- **Path params:** `event_id` (UUID string)
|
||||
- **Response:** Global event object + `impacts[]` (each with `company_id`, `ticker`, `macro_impact_score`, `impact_direction`, `contributing_factors`, `confidence`, `legal_name`, `sector`)
|
||||
- **Errors:** `404` — Global event not found
|
||||
|
||||
#### `GET /api/macro/impacts/{ticker}`
|
||||
@@ -515,7 +541,8 @@ Macro impacts and exposure profile for a specific company.
|
||||
| `limit` | int | `50` | max `200` | Page size |
|
||||
| `offset` | int | `0` | — | Pagination offset |
|
||||
|
||||
- **Response:** `{ exposure_profile, impacts[] }`
|
||||
- **Path params:** `ticker` (auto-uppercased)
|
||||
- **Response:** `{ exposure_profile, impacts[] }` — each impact includes `event_summary`, `event_severity`, `event_types`, `affected_regions`
|
||||
|
||||
### 1.18 Competitive Signal Layer
|
||||
|
||||
@@ -540,6 +567,7 @@ Historical patterns for a company.
|
||||
| `catalyst_type` | string | — | Filter by catalyst type |
|
||||
| `time_horizon` | string | — | Filter by time horizon |
|
||||
|
||||
- **Path params:** `ticker` (string)
|
||||
- **Response:** `{ ticker, patterns[], count }`
|
||||
|
||||
#### `GET /api/patterns/{ticker}/competitors`
|
||||
@@ -555,6 +583,7 @@ Cross-company patterns showing how this company's catalysts affected competitors
|
||||
#### `GET /api/patterns/{ticker}/competitive-signals`
|
||||
Recent competitive signals targeting this company (limit 100).
|
||||
|
||||
- **Path params:** `ticker` (string)
|
||||
- **Response:** `{ ticker, competitive_signals[], count }`
|
||||
|
||||
#### `GET /api/patterns/{ticker}/decisions`
|
||||
@@ -564,9 +593,9 @@ Major corporate decision history with trend outcomes and pattern statistics.
|
||||
|-----------|------|---------|-------------|
|
||||
| `time_horizon` | string | — | Filter by time horizon |
|
||||
|
||||
- **Path params:** `ticker` (string)
|
||||
- **Response:** `{ ticker, decisions[], count }` — each decision includes `pattern_statistics[]`
|
||||
|
||||
|
||||
### 1.20 AI Agents
|
||||
|
||||
#### `GET /api/agents`
|
||||
@@ -576,9 +605,12 @@ List all AI agent configurations.
|
||||
|-----------|------|---------|-------------|
|
||||
| `active_only` | bool | `false` | Only show active agents |
|
||||
|
||||
- **Response:** Array of agent objects with `id`, `name`, `slug`, `purpose`, `model_provider`, `model_name`, `system_prompt`, `user_prompt_template`, `prompt_version`, `schema_version`, `temperature`, `max_tokens`, `timeout_seconds`, `max_retries`, `active`, `source`, `created_at`, `updated_at`
|
||||
|
||||
#### `GET /api/agents/{agent_id}`
|
||||
Get a single agent configuration.
|
||||
|
||||
- **Path params:** `agent_id` (UUID string)
|
||||
- **Errors:** `404` — Agent not found
|
||||
|
||||
#### `POST /api/agents` (201)
|
||||
@@ -603,9 +635,9 @@ Create a new user-defined agent.
|
||||
| `max_retries` | int | `2` | Max retry attempts |
|
||||
|
||||
#### `PUT /api/agents/{agent_id}`
|
||||
Update an agent configuration. Partial updates supported.
|
||||
Update an agent configuration. Partial updates supported — only provided fields are changed.
|
||||
|
||||
- **Body:** `AgentUpdateBody` — all fields optional (same fields as create)
|
||||
- **Body:** `AgentUpdateBody` — all fields optional (same fields as create plus `active`)
|
||||
- **Errors:** `400` — No fields to update; `404` — Agent not found
|
||||
|
||||
#### `DELETE /api/agents/{agent_id}`
|
||||
@@ -636,6 +668,8 @@ Hourly performance time-series for an agent.
|
||||
#### `GET /api/agents/{agent_id}/variants`
|
||||
List all variants for an agent, ordered by `created_at` ascending.
|
||||
|
||||
- **Response:** Array of variant objects with `id`, `agent_id`, `variant_name`, `variant_slug`, `description`, `model_provider`, `model_name`, `system_prompt`, `user_prompt_template`, `prompt_version`, `temperature`, `max_tokens`, `context_window`, `input_token_limit`, `token_budget`, `timeout_seconds`, `max_retries`, `is_active`, `created_at`, `updated_at`
|
||||
|
||||
#### `GET /api/agents/{agent_id}/variants/{variant_id}`
|
||||
Get a single variant.
|
||||
|
||||
@@ -680,13 +714,13 @@ Delete a variant. Cannot delete active variants.
|
||||
#### `POST /api/agents/{agent_id}/clone` (201)
|
||||
Clone an agent's configuration as a new variant with optional overrides.
|
||||
|
||||
- **Body:** `VariantCloneBody { variant_name, variant_slug?, ...optional overrides }`
|
||||
- **Body:** `VariantCloneBody { variant_name, variant_slug?, description?, model_provider?, model_name?, system_prompt?, user_prompt_template?, prompt_version?, temperature?, max_tokens?, context_window?, input_token_limit?, token_budget?, timeout_seconds?, max_retries? }`
|
||||
- **Errors:** `404` — Agent not found; `409` — Duplicate slug
|
||||
|
||||
#### `POST /api/agents/{agent_id}/variants/{variant_id}/clone` (201)
|
||||
Clone an existing variant as a new variant with optional overrides.
|
||||
|
||||
- **Body:** `VariantCloneBody`
|
||||
- **Body:** `VariantCloneBody` (same as above)
|
||||
- **Errors:** `404` — Source variant not found; `409` — Duplicate slug
|
||||
|
||||
#### `POST /api/agents/{agent_id}/variants/{variant_id}/activate`
|
||||
@@ -697,6 +731,8 @@ Set a variant as the active variant for its agent. Deactivates any currently act
|
||||
#### `POST /api/agents/{agent_id}/variants/deactivate`
|
||||
Deactivate the currently active variant. Agent falls back to base configuration.
|
||||
|
||||
- **Response:** `{ deactivated: true }`
|
||||
|
||||
#### `GET /api/agents/{agent_id}/variants/{variant_id}/performance`
|
||||
Aggregated performance metrics for a specific variant.
|
||||
|
||||
@@ -704,6 +740,8 @@ Aggregated performance metrics for a specific variant.
|
||||
|-----------|------|---------|-------------|-------------|
|
||||
| `hours` | int | `24` | max `720` | Time window |
|
||||
|
||||
- **Response:** Same shape as agent performance (invocations, successes, failures, durations, confidence, tokens, success_rate)
|
||||
|
||||
#### `GET /api/agents/{agent_id}/variants/{variant_id}/performance/history`
|
||||
Hourly performance time-series for a specific variant.
|
||||
|
||||
@@ -711,6 +749,108 @@ Hourly performance time-series for a specific variant.
|
||||
|-----------|------|---------|-------------|-------------|
|
||||
| `hours` | int | `24` | max `720` | Time window |
|
||||
|
||||
- **Response:** Array of `{ hour, invocations, successes, avg_duration_ms, avg_confidence }`
|
||||
|
||||
### 1.22 Model Validation
|
||||
|
||||
#### `GET /api/validation/summary`
|
||||
Latest model metric snapshot plus quality gate status.
|
||||
|
||||
| Parameter | Type | Default | Constraints | Description |
|
||||
|-----------|------|---------|-------------|-------------|
|
||||
| `lookback` | string | `"30d"` | `7d`, `30d`, `90d`, `all` | Lookback window |
|
||||
| `horizon` | string | `"7d"` | `1h`, `6h`, `1d`, `7d`, `30d` | Prediction horizon |
|
||||
|
||||
- **Response:** `{ snapshot: { id, generated_at, lookback_window, horizon, prediction_count, win_rate, directional_accuracy, information_coefficient, rank_information_coefficient, avg_return, avg_excess_return_vs_spy, avg_excess_return_vs_sector, calibration_error, brier_score, buy_win_rate, sell_win_rate, hold_win_rate, metadata }, gate_status }`
|
||||
- **Errors:** `400` — Invalid lookback or horizon value
|
||||
|
||||
#### `GET /api/validation/calibration`
|
||||
Calibration table with confidence buckets showing predicted vs observed win rates.
|
||||
|
||||
| Parameter | Type | Default | Constraints | Description |
|
||||
|-----------|------|---------|-------------|-------------|
|
||||
| `lookback` | string | `"30d"` | `7d`, `30d`, `90d`, `all` | Lookback window |
|
||||
| `horizon` | string | `"7d"` | `1h`, `6h`, `1d`, `7d`, `30d` | Prediction horizon |
|
||||
|
||||
- **Response:** `{ buckets: [{ bucket_low, bucket_high, avg_confidence, observed_win_rate, prediction_count, miscalibrated }], lookback, horizon }`
|
||||
- Buckets: 0.50–0.60, 0.60–0.70, 0.70–0.80, 0.80–0.90, 0.90–1.00
|
||||
- `miscalibrated` is `true` when `|avg_confidence - observed_win_rate| > 0.15`
|
||||
- **Errors:** `400` — Invalid lookback or horizon value
|
||||
|
||||
#### `GET /api/validation/ic-by-horizon`
|
||||
Information Coefficient and Rank IC per prediction horizon.
|
||||
|
||||
| Parameter | Type | Default | Constraints | Description |
|
||||
|-----------|------|---------|-------------|-------------|
|
||||
| `lookback` | string | `"30d"` | `7d`, `30d`, `90d`, `all` | Lookback window |
|
||||
|
||||
- **Response:** `{ horizons: [{ horizon, information_coefficient, rank_information_coefficient, prediction_count, generated_at }], lookback }`
|
||||
- Horizons ordered: `1h`, `6h`, `1d`, `7d`, `30d`
|
||||
- **Errors:** `400` — Invalid lookback value
|
||||
|
||||
#### `GET /api/validation/gate-status`
|
||||
Quality gate evaluation detail from `risk_configs` where `name = 'model_quality_gate'`.
|
||||
|
||||
- **Response:** `{ gate_status, updated_at }` or `{ gate_status: null, message: "No gate evaluation found..." }`
|
||||
|
||||
### 1.23 Attribution
|
||||
|
||||
#### `GET /api/validation/attribution/sources`
|
||||
Per-source performance metrics: win rate, IC, average return, duplicate rate.
|
||||
|
||||
| Parameter | Type | Default | Constraints | Description |
|
||||
|-----------|------|---------|-------------|-------------|
|
||||
| `lookback` | string | `"30d"` | `7d`, `30d`, `90d`, `all` | Lookback window |
|
||||
| `horizon` | string | `"7d"` | `1h`, `6h`, `1d`, `7d`, `30d` | Prediction horizon |
|
||||
|
||||
- **Response:** `{ sources[], lookback, horizon }`
|
||||
- **Errors:** `400` — Invalid lookback or horizon; `500` — Computation failed
|
||||
|
||||
#### `GET /api/validation/attribution/catalysts`
|
||||
Per-catalyst-type performance metrics: win rate, IC, average return.
|
||||
|
||||
| Parameter | Type | Default | Constraints | Description |
|
||||
|-----------|------|---------|-------------|-------------|
|
||||
| `lookback` | string | `"30d"` | `7d`, `30d`, `90d`, `all` | Lookback window |
|
||||
| `horizon` | string | `"7d"` | `1h`, `6h`, `1d`, `7d`, `30d` | Prediction horizon |
|
||||
|
||||
- **Response:** `{ catalysts[], lookback, horizon }`
|
||||
- **Errors:** `400` — Invalid lookback or horizon; `500` — Computation failed
|
||||
|
||||
#### `GET /api/validation/attribution/layers`
|
||||
Per-signal-layer (company, macro, competitive) performance metrics.
|
||||
|
||||
| Parameter | Type | Default | Constraints | Description |
|
||||
|-----------|------|---------|-------------|-------------|
|
||||
| `lookback` | string | `"30d"` | `7d`, `30d`, `90d`, `all` | Lookback window |
|
||||
| `horizon` | string | `"7d"` | `1h`, `6h`, `1d`, `7d`, `30d` | Prediction horizon |
|
||||
|
||||
- **Response:** `{ layers[], lookback, horizon }` — each layer has `avg_contribution_pct`, `dominant_win_rate`, `dominant_ic`
|
||||
- **Errors:** `400` — Invalid lookback or horizon; `500` — Computation failed
|
||||
|
||||
### 1.24 Trading Reports
|
||||
|
||||
#### `GET /api/reports`
|
||||
Paginated list of trading reports with optional filtering.
|
||||
|
||||
| Parameter | Type | Default | Constraints | Description |
|
||||
|-----------|------|---------|-------------|-------------|
|
||||
| `report_type` | string | — | `daily` or `weekly` | Filter by report type |
|
||||
| `start_date` | string | — | ISO date (YYYY-MM-DD) | Filter `period_start >= this` |
|
||||
| `end_date` | string | — | ISO date (YYYY-MM-DD) | Filter `period_end <= this` |
|
||||
| `limit` | int | `20` | max `100` | Page size |
|
||||
| `offset` | int | `0` | min `0` | Pagination offset |
|
||||
|
||||
- **Response:** Array of `{ id, report_type, period_start, period_end, validation_status, generated_at }`
|
||||
- **Errors:** `400` — Invalid `report_type` or date format
|
||||
|
||||
#### `GET /api/reports/{report_id}`
|
||||
Fetch a single report including full `report_data` JSONB.
|
||||
|
||||
- **Path params:** `report_id` (UUID string)
|
||||
- **Response:** `{ id, report_type, period_start, period_end, report_data, validation_status, generated_at, created_at }`
|
||||
- **Errors:** `404` — Report not found
|
||||
|
||||
---
|
||||
|
||||
## 2. Symbol Registry API
|
||||
@@ -756,6 +896,7 @@ List tracked companies.
|
||||
#### `GET /companies/{company_id}`
|
||||
Get a single company.
|
||||
|
||||
- **Path params:** `company_id` (UUID string)
|
||||
- **Errors:** `404` — Company not found
|
||||
|
||||
#### `PUT /companies/{company_id}`
|
||||
@@ -783,14 +924,18 @@ List aliases for a company.
|
||||
Create a new watchlist.
|
||||
|
||||
- **Body:** `{ name: string, description?: string }`
|
||||
- **Response:** `{ id, name, description, active }`
|
||||
- **Errors:** `409` — Watchlist name already exists
|
||||
|
||||
#### `GET /watchlists`
|
||||
List all watchlists.
|
||||
|
||||
- **Response:** Array of `{ id, name, description, active }`
|
||||
|
||||
#### `POST /watchlists/{watchlist_id}/members/{company_id}` (201)
|
||||
Add a company to a watchlist.
|
||||
|
||||
- **Response:** `{ status: "added" }`
|
||||
- **Errors:** `409` — Already a member; `404` — Watchlist or company not found
|
||||
|
||||
#### `GET /watchlists/{watchlist_id}/members`
|
||||
@@ -814,11 +959,14 @@ Add a data source for a company.
|
||||
| `retention_days` | int | `365` | — | Data retention period |
|
||||
| `access_policy` | string | `"internal"` | `internal`, `public`, `restricted` | Access policy |
|
||||
|
||||
- **Response:** `{ id, source_type, source_name, credibility_score, active }`
|
||||
- **Errors:** `404` — Company not found; `422` — Invalid source_type or access_policy
|
||||
|
||||
#### `GET /companies/{company_id}/sources`
|
||||
List sources for a company.
|
||||
|
||||
- **Response:** Array of `{ id, source_type, source_name, config, credibility_score, retention_days, access_policy, active }`
|
||||
|
||||
### 2.6 Exposure Profiles
|
||||
|
||||
#### `GET /companies/{company_id}/exposure`
|
||||
@@ -848,6 +996,8 @@ Create or update an exposure profile. Archives the previous active version.
|
||||
#### `GET /companies/{company_id}/exposure/history`
|
||||
Get all exposure profile versions for a company, ordered by version descending.
|
||||
|
||||
- **Response:** Array of `ExposureProfileResponse`
|
||||
|
||||
### 2.7 Competitor Relationships
|
||||
|
||||
#### `POST /companies/{company_id}/competitors` (201)
|
||||
@@ -863,10 +1013,11 @@ Create a competitor relationship. Records an audit event.
|
||||
| `bidirectional` | bool | `true` | — | Bidirectional relationship |
|
||||
| `source` | string | `"manual"` | `manual`, `inferred` | Data source |
|
||||
|
||||
- **Response:** `CompetitorRelationship { id, company_a_id, company_b_id, relationship_type, strength, bidirectional, source, active, created_at, updated_at }`
|
||||
- **Errors:** `400` — Self-reference; `404` — Company not found; `409` — Relationship already exists
|
||||
|
||||
#### `GET /companies/{company_id}/competitors`
|
||||
List active competitor relationships, enriched with ticker and legal_name of the other company.
|
||||
List active competitor relationships, enriched with `ticker` and `legal_name` of the other company. Ordered by strength descending.
|
||||
|
||||
- **Errors:** `404` — Company not found
|
||||
|
||||
@@ -879,6 +1030,7 @@ Update a competitor relationship. Records an audit event with previous state.
|
||||
#### `DELETE /companies/{company_id}/competitors/{relationship_id}`
|
||||
Soft-delete a competitor relationship (sets `active=false`). Records an audit event.
|
||||
|
||||
- **Response:** `{ status: "deleted", id }`
|
||||
- **Errors:** `404` — Active relationship not found
|
||||
|
||||
### 2.8 Competitor Inference
|
||||
@@ -923,7 +1075,7 @@ Diagnostic endpoint showing engine internals for troubleshooting.
|
||||
#### `GET /api/trading/status`
|
||||
Return current engine state.
|
||||
|
||||
- **Response:** `{ enabled, paused, risk_tier, circuit_breaker_status, active_pool, reserve_pool, portfolio_heat, open_positions, last_decision_at }`
|
||||
- **Response:** `{ enabled, paused, risk_tier, circuit_breaker_status, active_pool, reserve_pool, portfolio_heat, open_positions, open_position_count, max_open_positions, absolute_position_cap, last_decision_at }`
|
||||
- **Errors:** `503` — Engine not initialised
|
||||
|
||||
#### `PUT /api/trading/config`
|
||||
@@ -960,7 +1112,13 @@ Resume the trading engine.
|
||||
#### `POST /api/trading/reset`
|
||||
Full paper trading reset: liquidate broker positions, cancel orders, clear trading state, reset capital.
|
||||
|
||||
- **Body:** `{ initial_capital?: float (default 0.0) }` — if 0, uses broker balance or defaults to 100,000
|
||||
- **Body:** `CapitalRequest`
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `initial_capital` | float | `0.0` | If 0, uses broker balance or defaults to 100,000 |
|
||||
| `reserve_pct` | float | `null` | Reserve pool percentage (0–1). If null, uses engine config `reserve_siphon_pct` |
|
||||
|
||||
- **Response:** `{ reset: true, initial_capital, active_pool, reserve_pool, broker: { orders_cancelled, positions_closed, portfolio_value, cash, buying_power } }`
|
||||
- **Errors:** `503` — Engine not initialised; `500` — Database reset failed
|
||||
|
||||
@@ -977,6 +1135,8 @@ Return recent trading decisions from the database.
|
||||
| `limit` | int | `50` | max `200` | Page size |
|
||||
| `offset` | int | `0` | — | Pagination offset |
|
||||
|
||||
- **Response:** Array of `{ id, recommendation_id, decision, skip_reason, ticker, computed_position_size, computed_share_quantity, risk_tier_at_decision, portfolio_heat_at_decision, active_pool_at_decision, reserve_pool_at_decision, circuit_breaker_status, is_micro_trade, created_at }`
|
||||
|
||||
### 3.5 Performance Metrics
|
||||
|
||||
#### `GET /api/trading/metrics`
|
||||
@@ -992,6 +1152,8 @@ Return historical daily portfolio snapshots.
|
||||
|-----------|------|---------|-------------|-------------|
|
||||
| `limit` | int | `30` | max `365` | Max snapshots |
|
||||
|
||||
- **Response:** Array of `{ id, snapshot_date, portfolio_value, active_pool, reserve_pool, daily_return, cumulative_return, unrealized_pnl, realized_pnl, win_count, loss_count, win_rate, sharpe_ratio, max_drawdown, current_drawdown_pct, portfolio_heat, risk_tier, created_at }`
|
||||
|
||||
### 3.6 Backtesting
|
||||
|
||||
#### `POST /api/trading/backtest`
|
||||
@@ -1012,6 +1174,7 @@ Launch a backtest run asynchronously.
|
||||
#### `GET /api/trading/backtest/{backtest_id}`
|
||||
Retrieve backtest results.
|
||||
|
||||
- **Path params:** `backtest_id` (UUID string)
|
||||
- **Response:** `{ id, start_date, end_date, initial_capital, risk_tier, config, total_return, sharpe_ratio, max_drawdown, win_rate, profit_factor, trade_count, equity_curve[], trades[], status, completed_at, created_at }`
|
||||
- Status values: `running`, `completed`, `not_found`, `pending`
|
||||
|
||||
@@ -1037,10 +1200,11 @@ Update notification preferences.
|
||||
|
||||
All fields optional.
|
||||
|
||||
- **Response:** `{ updated: { ...changed fields } }`
|
||||
- **Errors:** `503` — Engine not initialised
|
||||
|
||||
#### `GET /api/trading/notifications/history`
|
||||
Return recent notifications.
|
||||
Return recent notifications (placeholder — currently returns empty array).
|
||||
|
||||
| Parameter | Type | Default | Constraints | Description |
|
||||
|-----------|------|---------|-------------|-------------|
|
||||
@@ -1116,6 +1280,8 @@ List pending approval requests.
|
||||
#### `GET /approvals/{approval_id}`
|
||||
Get a single approval request.
|
||||
|
||||
- **Path params:** `approval_id` (UUID string)
|
||||
- **Response:** Approval request object
|
||||
- **Errors:** `404` — Approval not found; `503` — Database not ready
|
||||
|
||||
#### `POST /approvals/{approval_id}/review`
|
||||
@@ -1138,4 +1304,4 @@ Approve or reject a pending approval request.
|
||||
Expire stale approvals that have passed their expiration time.
|
||||
|
||||
- **Response:** `{ expired: int, items: [] }`
|
||||
- **Errors:** `503` — Database not ready
|
||||
- **Errors:** `503` — Database not ready
|
||||
|
||||
Reference in New Issue
Block a user