- Add scheduler and ingestion unit tests (test_scheduler_unit.py, test_ingestion_unit.py) - Add all 13 app services + dashboard to docker-compose.yml - Add full documentation suite: API reference, Helm reference, Docker deployment guide, 3 architecture diagrams (K8s, Docker Compose, data pipeline), AI agent guide, backup/restore guide, observability/metrics reference, per-service docs - Add intelligence pipeline deep-dive docs with Mermaid diagrams - Update README with documentation index and links - Add specs for comprehensive-quality-docs, intelligence-pipeline-deep-dive, sanitized-pipeline-docs
42 KiB
Stonks Oracle — API Reference
This document covers every HTTP endpoint exposed by the four FastAPI services in the Stonks Oracle platform. For each endpoint: HTTP method, path, query parameters (with type, default, and constraints), request body schema, response schema, and error codes.
Live endpoints:
| Service | Base URL | Source |
|---|---|---|
| Query API | https://stonks-api.celestium.life |
services/api/app.py |
| Symbol Registry | https://stonks-registry.celestium.life |
services/symbol_registry/app.py |
| Trading Engine | https://stonks-trading.celestium.life |
services/trading/app.py |
| Risk Engine | (cluster-internal) | services/risk/app.py |
Common error format: All services return errors as {"detail": "error message"} with the appropriate HTTP status code.
Table of Contents
1. Query API
Source: services/api/app.py
Base path: / (most endpoints prefixed with /api/)
1.1 Health and Metrics
GET /health
Liveness probe. Verifies database connectivity.
- Response:
{"status": "ok"} - Errors:
503— Database unavailable
GET /metrics
Prometheus metrics endpoint for scraping.
- Response: Prometheus text format (
text/plain)
1.2 Companies
GET /api/companies
List tracked companies with optional filters.
| Parameter | Type | Default | Description |
|---|---|---|---|
active |
bool | true |
Filter by active status |
sector |
string | — | Filter by sector |
ticker |
string | — | Filter by ticker (auto-uppercased) |
- Response: Array of company objects with
id,ticker,legal_name,exchange,sector,industry,market_cap_bucket,active,created_at,updated_at
GET /api/companies/{company_id}
Get a single company with aliases and active source count.
- Path params:
company_id(UUID string) - Response: Company object +
aliases[]+active_source_count - Errors:
404— Company not found
GET /api/companies/{company_id}/sources
List sources configured for a company.
- Path params:
company_id(UUID string) - Response: Array of source objects with
id,source_type,source_name,config,credibility_score,retention_days,access_policy,active
1.3 Documents
GET /api/documents
List documents with optional filters, ordered by published_at descending.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
ticker |
string | — | — | Filter by ticker |
company_id |
string | — | — | Filter by company UUID |
document_type |
string | — | — | Filter by type |
status |
string | — | — | Filter by processing status |
since |
string | — | ISO 8601 timestamp | Documents published after this time |
limit |
int | 50 |
max 200 |
Page size |
offset |
int | 0 |
— | Pagination offset |
- Response: Array of document objects
GET /api/documents/{document_id}
Get a single document with intelligence extraction and company mentions.
- Path params:
document_id(UUID string) - Response: Document object +
company_mentions[]+intelligence(withcompany_impacts[]) - Errors:
404— Document not found
1.4 Trends
GET /api/trends
List trend summaries with optional filters.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
ticker |
string | — | — | Filter by entity_id (ticker) |
entity_type |
string | "company" |
— | Entity type filter |
window |
string | — | — | Time window filter |
limit |
int | 50 |
max 200 |
Page size |
offset |
int | 0 |
— | Pagination offset |
- Response: Array of trend objects with JSONB fields parsed, plus
projectionsub-object fromtrend_projections
GET /api/trends/history
Historical trend snapshots for charting (time series from trend_history table).
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
ticker |
string | — | — | Filter by entity_id |
window |
string | — | — | Time window filter |
limit |
int | 200 |
max 1000 |
Max rows |
- Response: Array of trend history objects ordered by
generated_atascending
GET /api/trends/{trend_id}
Get a single trend summary by ID.
- Path params:
trend_id(UUID string) - Response: Trend object with parsed JSONB fields
- Errors:
404— Trend not found
GET /api/trends/{trend_id}/evidence
Drill down from a trend window to contributing documents and raw artifacts. Full provenance chain.
- Path params:
trend_id(UUID string) - Response:
{ trend, evidence[] }— each evidence item includesintelligenceandcompany_impacts[] - Errors:
404— Trend not found
GET /api/trends/{trend_id}/projection
Trend projection for a specific trend window.
- Path params:
trend_id(UUID string) - Response: Projection object with
projected_direction,projected_strength,projected_confidence,projection_horizon,driving_factors,macro_contribution_pct,diverges_from_current - Errors:
404— Trend not found
1.5 Market Prices
GET /api/market/prices/{ticker}
Historical close prices from market_snapshots.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
limit |
int | 30 |
max 200 |
Max bars returned |
- Path params:
ticker(auto-uppercased) - Response: Array of OHLCV objects ordered oldest-first
1.6 Recommendations
GET /api/recommendations
List recommendations with optional filters.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
ticker |
string | — | — | Filter by ticker |
action |
string | — | — | Filter by action (buy/sell/hold) |
mode |
string | — | — | Filter by mode |
since |
string | — | ISO 8601 | Generated after this time |
min_confidence |
float | — | 0.0–1.0 | Minimum confidence threshold |
limit |
int | 50 |
max 200 |
Page size |
offset |
int | 0 |
— | Pagination offset |
latest |
bool | true |
— | Return only latest per ticker |
- Response: Array of recommendation objects
GET /api/recommendations/{recommendation_id}
Get a single recommendation with evidence and risk evaluation.
- Path params:
recommendation_id(UUID string) - Response: Recommendation +
evidence[]+risk_evaluation - Errors:
404— Recommendation not found
GET /api/recommendations/{recommendation_id}/evidence
Full evidence drill-down: provenance chain from recommendation to source documents and raw artifacts.
- Path params:
recommendation_id(UUID string) - Response:
{ recommendation, evidence[], trend_window }— each evidence item includesintelligenceandcompany_impacts[] - Errors:
404— Recommendation not found
1.7 Orders
GET /api/orders
List orders with optional filters.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
ticker |
string | — | — | Filter by ticker |
status |
string | — | — | Filter by order status |
side |
string | — | — | Filter by side (buy/sell) |
since |
string | — | ISO 8601 | Created after this time |
limit |
int | 50 |
max 200 |
Page size |
offset |
int | 0 |
— | Pagination offset |
- Response: Array of order objects
GET /api/orders/{order_id}
Get a single order with events, decision trace, and full audit trail.
- Path params:
order_id(UUID string) - Response: Order object +
events[]+audit_trail - Errors:
404— Order not found
1.8 Positions
GET /api/positions
List current positions.
| Parameter | Type | Default | Description |
|---|---|---|---|
ticker |
string | — | Filter by ticker |
- Response: Array of position objects with
id,broker_account_id,ticker,quantity,avg_entry_price,current_price,unrealized_pnl,realized_pnl,updated_at
1.9 Audit Trail
GET /api/audit/{entity_type}/{entity_id}
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
GET /api/admin/sources/health
Source health overview with latest ingestion status and failure counts.
| Parameter | Type | Default | Description |
|---|---|---|---|
source_type |
string | — | Filter by source type |
company_id |
string | — | Filter by company UUID |
active_only |
bool | true |
Only show active sources |
- Response: Array of source health objects with
source_id,source_type,source_name,credibility_score,ticker,legal_name,last_run_status,last_run_at,last_error,last_items_fetched,last_items_new,total_runs_24h,failed_runs_24h,total_items_24h
GET /api/admin/sources/{source_id}/runs
Recent ingestion runs for a specific source.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
limit |
int | 20 |
max 100 |
Page size |
offset |
int | 0 |
— | Pagination offset |
PUT /api/admin/sources/{source_id}/toggle
Enable or disable a source.
| Parameter | Type | Default | Description |
|---|---|---|---|
active |
bool | true |
New active state |
- Errors:
404— Source not found
PUT /api/admin/sources/{source_id}/credibility
Update a source's credibility score.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
credibility_score |
float | — | 0.0–1.0 | New credibility score |
- Errors:
404— Source not found
1.11 Admin: Company Management
PUT /api/admin/companies/{company_id}/toggle
Enable or disable a tracked company.
| Parameter | Type | Default | Description |
|---|---|---|---|
active |
bool | true |
New active state |
- Errors:
404— Company not found
PUT /api/admin/companies/{company_id}/sector
Update a company's sector and industry classification.
| Parameter | Type | Default | Description |
|---|---|---|---|
sector |
string | — | Required. New sector |
industry |
string | — | Optional new industry |
- Errors:
404— Company not found
GET /api/admin/companies/coverage
Source coverage overview per active company. Shows active source counts by type.
- Response: Array of objects with
company_id,ticker,legal_name,sector,active_sources,market_sources,news_sources,filings_sources,web_scrape_sources,broker_sources
1.12 Admin: Trading Configuration
GET /api/admin/trading/config
Get the current active risk/trading configuration.
- Response: Risk config object with
id,name,trading_mode,config(JSONB),active, timestamps
PUT /api/admin/trading/mode
Switch the active trading mode.
| Parameter | Type | Constraints | Description |
|---|---|---|---|
mode |
string | paper, live, or disabled |
Required. New trading mode |
PUT /api/admin/trading/config
Update the active risk configuration JSON.
- Body:
dict[str, Any]— partial or full risk config object - Response: Updated config object
GET /api/admin/trading/approvals
List pending operator approval requests for live trading orders.
- Response: Array of approval objects with
order_job(JSONB),recommendation_id,ticker,side,quantity,estimated_value,status,expires_at, etc.
PUT /api/admin/trading/approvals/{approval_id}
Approve or reject a pending operator approval request.
| Parameter | Type | Default | Description |
|---|---|---|---|
approved |
bool | — | Required. Approve or reject |
reviewed_by |
string | "operator" |
Reviewer identity |
review_note |
string | "" |
Optional note |
- Errors:
404— Approval not found or no longer pending
GET /api/admin/trading/lockouts
List active symbol lockouts (news-shock, cooldown, manual).
POST /api/admin/trading/lockouts
Create a manual symbol lockout.
- Body:
{ ticker: string, reason: string, duration_minutes: int, lockout_type?: string } - Errors:
400— Missing or invalid fields
DELETE /api/admin/trading/lockouts/{lockout_id}
Delete a symbol lockout (early removal).
- Errors:
404— Lockout not found
GET /api/admin/trading/approval-config
Get operator approval settings from the active risk config.
- Response:
{ auto_approve_paper, require_approval_for_live, approval_timeout_minutes }
PUT /api/admin/trading/approval-config
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
Ingestion throughput over time, bucketed by interval.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
hours |
int | 24 |
1–168 | Time window |
bucket |
string | "1h" |
15m, 1h, 6h, 1d |
Bucket interval |
- Response: Array of bucketed throughput objects by source type
GET /api/ops/ingestion/summary
High-level ingestion summary for the operational dashboard.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
hours |
int | 24 |
1–168 | Time window |
- Response:
{ total_runs, completed, failed, pending, running, total_items_fetched, total_items_new, active_sources, active_companies, by_source_type[], hours }
GET /api/ops/model/failures
Recent model extraction failures with error details.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
hours |
int | 24 |
1–168 | Time window |
limit |
int | 50 |
max 200 |
Max results |
GET /api/ops/model/performance
Aggregated model performance metrics.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
hours |
int | 24 |
1–168 | Time window |
model_name |
string | — | — | Filter by model |
GET /api/ops/pipeline/health
Pipeline stage health summary across ingestion, parsing, extraction, and aggregation.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
hours |
int | 24 |
1–168 | Time window |
- Response:
{ hours, pipeline_enabled, document_stages[], parsing, extraction, aggregation, queue_depths }
GET /api/ops/pipeline/stream
Server-Sent Events stream of live pipeline status. Pushes queue depths and document stage counts every 3 seconds.
- Response:
text/event-streamwith JSON data payloads
POST /api/ops/pipeline/retry-failed
Re-enqueue documents stuck in extraction_failed for another attempt (up to 200).
- Response:
{ retried: int, message: string }
GET /api/ops/pipeline/toggle
Get the current pipeline enabled/disabled state.
- Response:
{ pipeline_enabled: bool }
POST /api/ops/pipeline/toggle
Toggle the pipeline on or off.
- Body:
{ enabled: bool } - Response:
{ pipeline_enabled: bool, message: string }
GET /api/ops/sources/coverage-gaps
Identify symbols with missing or insufficient source coverage.
- Response:
{ missing_source_types[], stale_sources[] }
1.14 System
GET /api/system/rate-limits
Current rate limit configuration and usage.
- Response:
{ polygon_global_limit, polygon_source_types, per_type_limits, cadences_seconds, market_api: { rate_per_minute, cadence_seconds, max_tickers_per_cycle, active_sources }, news_api: {...} }
1.15 Analytics
POST /api/analytics/query
Proxy SQL to Trino with row limits.
- Body:
{ sql: string, limit?: int (default 1000, max 10000) } - Response:
{ columns[], rows[][], row_count, elapsed_ms } - Errors:
400— Empty SQL;502— Trino connection error;504— Trino timeout
GET /api/analytics/schema
Trino catalog/schema/table/column metadata for the schema browser.
- Response:
{ catalog, schema, tables[{ name, columns[{ name, type }] }] }
GET /api/analytics/pg-schema
PostgreSQL table/column metadata with primary keys, foreign keys, and row estimates.
- Response:
{ catalog: "postgresql", schema: "public", tables[] }
POST /api/analytics/pg-query
Run read-only SQL against PostgreSQL directly. Only SELECT statements allowed.
- Body:
{ sql: string, limit?: int (default 1000, max 10000) } - Response:
{ columns[], rows[][], row_count, elapsed_ms } - Errors:
400— Non-SELECT query, syntax error, table not found, or query error
GET /api/analytics/saved-queries
List all saved queries.
POST /api/analytics/saved-queries (201)
Save a new query.
- Body:
{ name: string, description?: string, sql_text: string }
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
Return the current macro signal layer enabled/disabled state.
- Response:
{ macro_enabled: bool, source: "default" | "risk_configs" }
PUT /api/admin/macro/toggle
Toggle the macro signal layer on or off. Records an audit event.
- Body:
{ enabled: bool, operator?: string (default "operator") } - Response:
{ macro_enabled, previous_enabled, toggled_by }
1.17 Macro Events and Impacts
GET /api/macro/events
List recent global events with filtering.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
severity |
string | — | — | Filter by severity |
region |
string | — | — | Filter by affected region |
sector |
string | — | — | Filter by affected sector |
since |
string | — | ISO 8601 | Events after this time |
until |
string | — | ISO 8601 | Events before this time |
limit |
int | 50 |
max 200 |
Page size |
offset |
int | 0 |
— | Pagination offset |
GET /api/macro/events/{event_id}
Event detail with affected companies and macro impact scores.
- Errors:
404— Global event not found
GET /api/macro/impacts/{ticker}
Macro impacts and exposure profile for a specific company.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
since |
string | — | ISO 8601 | Impacts after this time |
limit |
int | 50 |
max 200 |
Page size |
offset |
int | 0 |
— | Pagination offset |
- Response:
{ exposure_profile, impacts[] }
1.18 Competitive Signal Layer
GET /api/admin/competitive/status
Return the current competitive signal layer enabled/disabled state.
- Response:
{ competitive_enabled: bool, source: "default" | "risk_configs" }
PUT /api/admin/competitive/toggle
Toggle the competitive signal layer on or off. Records an audit event.
- Body:
{ enabled: bool, operator?: string (default "operator") } - Response:
{ competitive_enabled, previous_enabled, toggled_by }
1.19 Patterns and Competitive Signals
GET /api/patterns/{ticker}
Historical patterns for a company.
| Parameter | Type | Default | Description |
|---|---|---|---|
catalyst_type |
string | — | Filter by catalyst type |
time_horizon |
string | — | Filter by time horizon |
- Response:
{ ticker, patterns[], count }
GET /api/patterns/{ticker}/competitors
Cross-company patterns showing how this company's catalysts affected competitors.
| Parameter | Type | Default | Description |
|---|---|---|---|
catalyst_type |
string | — | Filter by catalyst type |
time_horizon |
string | — | Filter by time horizon |
- Response:
{ ticker, cross_company_patterns[], count }
GET /api/patterns/{ticker}/competitive-signals
Recent competitive signals targeting this company (limit 100).
- Response:
{ ticker, competitive_signals[], count }
GET /api/patterns/{ticker}/decisions
Major corporate decision history with trend outcomes and pattern statistics.
| Parameter | Type | Default | Description |
|---|---|---|---|
time_horizon |
string | — | Filter by time horizon |
- Response:
{ ticker, decisions[], count }— each decision includespattern_statistics[]
1.20 AI Agents
GET /api/agents
List all AI agent configurations.
| Parameter | Type | Default | Description |
|---|---|---|---|
active_only |
bool | false |
Only show active agents |
GET /api/agents/{agent_id}
Get a single agent configuration.
- Errors:
404— Agent not found
POST /api/agents (201)
Create a new user-defined agent.
- Body:
AgentCreateBody
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | — | Required |
slug |
string | auto-generated | URL-safe identifier |
purpose |
string | "" |
Agent purpose |
model_provider |
string | "ollama" |
LLM provider |
model_name |
string | "llama3.1:8b" |
Model identifier |
system_prompt |
string | "" |
System prompt |
user_prompt_template |
string | "" |
User prompt template |
prompt_version |
string | "" |
Prompt version tag |
schema_version |
string | "1.0.0" |
Output schema version |
temperature |
float | 0.0 |
Sampling temperature |
max_tokens |
int | 32768 |
Max output tokens |
timeout_seconds |
int | 120 |
Request timeout |
max_retries |
int | 2 |
Max retry attempts |
PUT /api/agents/{agent_id}
Update an agent configuration. Partial updates supported.
- Body:
AgentUpdateBody— all fields optional (same fields as create) - Errors:
400— No fields to update;404— Agent not found
DELETE /api/agents/{agent_id}
Delete a user-created agent. System agents cannot be deleted.
- Errors:
403— Cannot delete system agents;404— Agent not found
GET /api/agents/{agent_id}/performance
Aggregated performance metrics for an agent.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
hours |
int | 24 |
max 720 |
Time window |
- Response:
{ total_invocations, successes, failures, avg_duration_ms, p95_duration_ms, avg_confidence, avg_retries, total_input_tokens, total_output_tokens, success_rate }
GET /api/agents/{agent_id}/performance/history
Hourly performance time-series for an agent.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
hours |
int | 24 |
max 720 |
Time window |
- Response: Array of
{ hour, invocations, successes, avg_duration_ms, avg_confidence }
1.21 Agent Variants
GET /api/agents/{agent_id}/variants
List all variants for an agent, ordered by created_at ascending.
GET /api/agents/{agent_id}/variants/{variant_id}
Get a single variant.
- Errors:
404— Variant not found
POST /api/agents/{agent_id}/variants (201)
Create a new variant for an agent.
- Body:
VariantCreateBody
| Field | Type | Default | Description |
|---|---|---|---|
variant_name |
string | — | Required |
variant_slug |
string | auto-generated | URL-safe identifier |
description |
string | "" |
Variant description |
model_provider |
string | "ollama" |
LLM provider |
model_name |
string | — | Required. Model identifier |
system_prompt |
string | "" |
System prompt |
user_prompt_template |
string | "" |
User prompt template |
prompt_version |
string | "" |
Prompt version tag |
temperature |
float | 0.0 |
Sampling temperature |
max_tokens |
int | 32768 |
Max output tokens |
context_window |
int | 0 |
Context window size |
input_token_limit |
int | 0 |
Input token limit |
token_budget |
int | 0 |
Token budget |
timeout_seconds |
int | 120 |
Request timeout |
max_retries |
int | 2 |
Max retry attempts |
- Errors:
409— Duplicate variant slug
PUT /api/agents/{agent_id}/variants/{variant_id}
Partial update a variant.
- Body:
VariantUpdateBody— all fields optional - Errors:
400— No fields to update;404— Variant not found
DELETE /api/agents/{agent_id}/variants/{variant_id}
Delete a variant. Cannot delete active variants.
- Errors:
400— Cannot delete active variant;404— Variant not found
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 } - 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 - Errors:
404— Source variant not found;409— Duplicate slug
POST /api/agents/{agent_id}/variants/{variant_id}/activate
Set a variant as the active variant for its agent. Deactivates any currently active variant in a transaction.
- Errors:
404— Variant not found
POST /api/agents/{agent_id}/variants/deactivate
Deactivate the currently active variant. Agent falls back to base configuration.
GET /api/agents/{agent_id}/variants/{variant_id}/performance
Aggregated performance metrics for a specific variant.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
hours |
int | 24 |
max 720 |
Time window |
GET /api/agents/{agent_id}/variants/{variant_id}/performance/history
Hourly performance time-series for a specific variant.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
hours |
int | 24 |
max 720 |
Time window |
2. Symbol Registry API
Source: services/symbol_registry/app.py with routers from exposure.py, competitors.py, competitor_inference.py
2.1 Health
GET /health
Liveness probe. Verifies database connectivity.
- Response:
{"status": "ok"} - Errors:
503— Database unavailable
2.2 Companies
POST /companies (201)
Create a new tracked company.
- Body:
CompanyCreate
| Field | Type | Default | Constraints | Description |
|---|---|---|---|---|
ticker |
string | — | 1–10 uppercase letters | Required. Stock ticker |
legal_name |
string | — | — | Required. Company name |
exchange |
string | null |
— | Stock exchange |
sector |
string | null |
— | Sector classification |
industry |
string | null |
— | Industry classification |
market_cap_bucket |
string | null |
— | Market cap bucket |
- Response:
CompanyResponse { id, ticker, legal_name, exchange, sector, industry, market_cap_bucket, active } - Errors:
409— Company already exists;422— Invalid ticker format
GET /companies
List tracked companies.
| Parameter | Type | Default | Description |
|---|---|---|---|
active |
bool | true |
Filter by active status |
- Response: Array of
CompanyResponse
GET /companies/{company_id}
Get a single company.
- Errors:
404— Company not found
PUT /companies/{company_id}
Update a company.
- Body:
CompanyCreate(same as create) - Errors:
404— Company not found
2.3 Aliases
POST /companies/{company_id}/aliases (201)
Add an alias for a company.
- Body:
{ alias: string, alias_type?: string (default "brand") } - Response:
{ id, alias, alias_type }
GET /companies/{company_id}/aliases
List aliases for a company.
- Response: Array of
{ id, alias, alias_type }
2.4 Watchlists
POST /watchlists (201)
Create a new watchlist.
- Body:
{ name: string, description?: string } - Errors:
409— Watchlist name already exists
GET /watchlists
List all watchlists.
POST /watchlists/{watchlist_id}/members/{company_id} (201)
Add a company to a watchlist.
- Errors:
409— Already a member;404— Watchlist or company not found
GET /watchlists/{watchlist_id}/members
List companies in a watchlist.
- Response: Array of
CompanyResponse
2.5 Sources
POST /companies/{company_id}/sources (201)
Add a data source for a company.
- Body:
SourceCreate
| Field | Type | Default | Constraints | Description |
|---|---|---|---|---|
source_type |
string | — | market_api, news_api, filings_api, web_scrape, broker |
Required |
source_name |
string | — | — | Required |
config |
dict | {} |
URLs validated for base_url |
Source configuration |
credibility_score |
float | 0.5 |
— | Source credibility |
retention_days |
int | 365 |
— | Data retention period |
access_policy |
string | "internal" |
internal, public, restricted |
Access policy |
- Errors:
404— Company not found;422— Invalid source_type or access_policy
GET /companies/{company_id}/sources
List sources for a company.
2.6 Exposure Profiles
GET /companies/{company_id}/exposure
Get the current active exposure profile for a company.
- Response:
ExposureProfileResponse { id, company_id, geographic_revenue_mix, supply_chain_regions, key_input_commodities, regulatory_jurisdictions, market_position_tier, export_dependency_pct, source, confidence, version, active, created_at, updated_at } - Errors:
404— No active exposure profile found
PUT /companies/{company_id}/exposure
Create or update an exposure profile. Archives the previous active version.
- Body:
ExposureProfileCreate
| Field | Type | Default | Constraints | Description |
|---|---|---|---|---|
geographic_revenue_mix |
dict[str, float] | {} |
— | Region to revenue percentage |
supply_chain_regions |
list[str] | [] |
— | Supply chain regions |
key_input_commodities |
list[str] | [] |
— | Key input commodities |
regulatory_jurisdictions |
list[str] | [] |
— | Regulatory jurisdictions |
market_position_tier |
string | "regional" |
global_leader, multinational, regional, domestic |
Market position |
export_dependency_pct |
float | 0.0 |
0.0–1.0 | Export dependency |
source |
string | "manual" |
manual, inferred |
Data source |
confidence |
float | 1.0 |
0.0–1.0 | Confidence score |
- Errors:
404— Company not found
GET /companies/{company_id}/exposure/history
Get all exposure profile versions for a company, ordered by version descending.
2.7 Competitor Relationships
POST /companies/{company_id}/competitors (201)
Create a competitor relationship. Records an audit event.
- Body:
CompetitorRelationshipCreate
| Field | Type | Default | Constraints | Description |
|---|---|---|---|---|
company_b_id |
string | — | UUID | Required. Other company |
relationship_type |
string | — | direct_rival, same_sector, overlapping_products, supply_chain_adjacent |
Required |
strength |
float | 0.5 |
0–1 | Relationship strength |
bidirectional |
bool | true |
— | Bidirectional relationship |
source |
string | "manual" |
manual, inferred |
Data source |
- 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.
- Errors:
404— Company not found
PUT /companies/{company_id}/competitors/{relationship_id}
Update a competitor relationship. Records an audit event with previous state.
- Body:
CompetitorRelationshipCreate - Errors:
404— Relationship not found
DELETE /companies/{company_id}/competitors/{relationship_id}
Soft-delete a competitor relationship (sets active=false). Records an audit event.
- Errors:
404— Active relationship not found
2.8 Competitor Inference
POST /companies/{company_id}/competitors/infer
Auto-infer competitor relationships based on sector/industry match and document co-mention frequency.
Strength formula: 0.3 * sector_match + 0.7 * normalized_co_mention_count
Upserts relationships with source='inferred' and relationship_type='same_sector'.
- Response: Array of
CompetitorRelationshipobjects sorted by strength descending - Errors:
400— Company missing sector or industry;404— Company not found
3. Trading Engine API
Source: services/trading/app.py
3.1 Health and Readiness
GET /health
Liveness probe.
- Response:
{"status": "ok"}
GET /ready
Readiness probe — reports whether the engine is running.
- Response:
{"ready": bool}
3.2 Debug
GET /api/trading/debug
Diagnostic endpoint showing engine internals for troubleshooting.
- Response:
{ running, has_pool, has_redis, config_enabled, polling_interval, last_poll, portfolio_state: { active_pool, reserve_pool, total_value, open_positions }, risk_tier, tasks, processed_rec_count }
3.3 Engine Status and Control
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 } - Errors:
503— Engine not initialised
PUT /api/trading/config
Update trading engine configuration. Returns previous and new values for audit trail.
- Body:
ConfigUpdateRequest
| Field | Type | Description |
|---|---|---|
enabled |
bool | Enable/disable engine |
risk_tier |
string | Risk tier level |
reserve_siphon_pct |
float | Reserve pool siphon percentage |
polling_interval_seconds |
int | Polling interval |
absolute_position_cap |
float | Max position value |
active_pool_minimum |
float | Minimum active pool |
micro_trading_enabled |
bool | Enable micro trades |
max_open_positions |
int | Max concurrent positions |
All fields optional. Only provided fields are updated.
- Response:
{ previous, updated, change_source: "api", changed_at } - Errors:
503— Engine not initialised
POST /api/trading/pause
Pause the trading engine.
- Response:
{"paused": true}
POST /api/trading/resume
Resume the trading engine.
- Response:
{"paused": false}
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 - 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
3.4 Decision Audit Trail
GET /api/trading/decisions
Return recent trading decisions from the database.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
ticker |
string | — | — | Filter by ticker |
decision |
string | — | — | Filter by decision type |
is_micro_trade |
bool | — | — | Filter micro trades |
limit |
int | 50 |
max 200 |
Page size |
offset |
int | 0 |
— | Pagination offset |
3.5 Performance Metrics
GET /api/trading/metrics
Return current performance metrics.
- Response:
{ total_portfolio_value, active_pool, reserve_pool, unrealized_pnl, realized_pnl, daily_pnl, win_rate, profit_factor, sharpe_ratio, max_drawdown, portfolio_heat } - Errors:
503— Engine not initialised
GET /api/trading/metrics/history
Return historical daily portfolio snapshots.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
limit |
int | 30 |
max 365 |
Max snapshots |
3.6 Backtesting
POST /api/trading/backtest
Launch a backtest run asynchronously.
- Body:
BacktestRequest
| Field | Type | Default | Description |
|---|---|---|---|
start_date |
string | — | Required. ISO date (YYYY-MM-DD) |
end_date |
string | — | Required. ISO date (YYYY-MM-DD) |
initial_capital |
float | 500.0 |
Starting capital |
risk_tier |
string | "moderate" |
Risk tier for backtest |
- Response:
{ id: string, status: "running" } - Errors:
503— Engine not initialised
GET /api/trading/backtest/{backtest_id}
Retrieve backtest results.
- 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
3.7 Notifications
GET /api/trading/notifications/config
Return current notification configuration.
- Response:
{ sms_enabled, email_enabled, phone_number, email_recipient } - Errors:
503— Engine not initialised
PUT /api/trading/notifications/config
Update notification preferences.
- Body:
NotificationConfigRequest
| Field | Type | Description |
|---|---|---|
sms_enabled |
bool | Enable SMS notifications |
email_enabled |
bool | Enable email notifications |
phone_number |
string | SMS phone number |
email_recipient |
string | Email recipient address |
All fields optional.
- Errors:
503— Engine not initialised
GET /api/trading/notifications/history
Return recent notifications.
| Parameter | Type | Default | Constraints | Description |
|---|---|---|---|---|
limit |
int | 50 |
max 200 |
Max results |
3.8 Override Orders
POST /api/trading/override/order (202)
Submit a manual override order to the broker queue. Auto-registers untracked tickers in the Symbol Registry.
- Body:
OverrideOrderRequest
| Field | Type | Default | Constraints | Description |
|---|---|---|---|---|
ticker |
string | — | 1–10 alphabetic chars | Required. Stock ticker |
side |
string | — | buy or sell |
Required. Order side |
quantity |
float | — | Must be positive | Required. Share quantity |
order_type |
string | "market" |
market, limit, stop, stop_limit |
Order type |
limit_price |
float | null |
Required for limit/stop_limit |
Limit price |
stop_price |
float | null |
Required for stop/stop_limit |
Stop price |
- Response:
OverrideOrderResponse { job_id, status: "queued", ticker, side, quantity, auto_registered } - Errors:
503— Engine not initialised or broker queue unavailable;422— Validation errors
4. Risk Engine API
Source: services/risk/app.py
4.1 Health
GET /health
Liveness probe.
- Response:
{"status": "ok"}
4.2 Order Evaluation
POST /evaluate
Evaluate a proposed order against risk rules.
- Body:
EvaluateRequest
| Field | Type | Description |
|---|---|---|
order |
ProposedOrder | Required. The order to evaluate |
config |
PortfolioRiskConfig | Optional. Risk config (uses defaults if null) |
state |
AccountRiskState | Optional. Current account state |
ProposedOrder schema:
| Field | Type | Default | Description |
|---|---|---|---|
recommendation_id |
string | null |
Source recommendation |
ticker |
string | — | Required. Stock ticker |
sector |
string | "" |
Company sector |
action |
string | "buy" |
buy or sell |
quantity |
float | 0.0 |
Share quantity |
estimated_value |
float | 0.0 |
Estimated order value |
confidence |
float | 0.0 |
Recommendation confidence |
- Response:
RiskEvaluation { evaluation_id, recommendation_id, ticker, eligible, allowed_mode, checks[], rejection_reasons[], config_snapshot, state_snapshot, evaluated_at }
4.3 Approvals
GET /approvals/pending
List pending approval requests.
- Response: Array of approval request objects (serialized via
to_dict()) - Errors:
503— Database not ready
GET /approvals/{approval_id}
Get a single approval request.
- Errors:
404— Approval not found;503— Database not ready
POST /approvals/{approval_id}/review
Approve or reject a pending approval request.
- Body:
ReviewRequest
| Field | Type | Default | Description |
|---|---|---|---|
approved |
bool | — | Required. Approve or reject |
reviewed_by |
string | "operator" |
Reviewer identity |
review_note |
string | "" |
Optional review note |
- Response:
{ approval_id, status } - Errors:
404— Approval not found or no longer pending;503— Database not ready
4.4 Approval Expiration
POST /approvals/expire
Expire stale approvals that have passed their expiration time.
- Response:
{ expired: int, items: [] } - Errors:
503— Database not ready