TradingAgents/docs/contracts/result-contract-v1alpha1.md

245 lines
5.7 KiB
Markdown

# TradingAgents result contract v1alpha1 draft
Status: draft
Audience: backend, desktop, frontend, verification
Format: JSON-oriented contract notes with examples
## 1. Goals
`result-contract-v1alpha1` defines the stable shapes exchanged across:
- analysis start/status APIs
- websocket progress events
- live orchestrator streaming
- persisted task state
- historical report projection
The contract should be application-facing, not raw domain dataclasses.
## 2. Design principles
- version every externally consumed payload
- keep transport-neutral field meanings
- allow partial/degraded results when quant or LLM lane fails
- distinguish task lifecycle from signal outcome
- keep raw domain metadata nested, not smeared across top-level fields
## 3. Core enums
## 3.1 Task status
```json
["pending", "running", "completed", "failed", "cancelled"]
```
## 3.2 Stage name
```json
["analysts", "research", "trading", "risk", "portfolio"]
```
## 3.3 Decision rating
```json
["BUY", "OVERWEIGHT", "HOLD", "UNDERWEIGHT", "SELL"]
```
## 4. Canonical envelope
All application-facing payloads should include:
```json
{
"contract_version": "v1alpha1"
}
```
Optional transport-specific wrapper fields such as WebSocket `type` may sit outside the contract body.
## 5. Analysis task contract
## 5.1 Accepted response
```json
{
"contract_version": "v1alpha1",
"task_id": "600519.SS_20260413_120000_ab12cd",
"ticker": "600519.SS",
"date": "2026-04-13",
"status": "running"
}
```
## 5.2 Status / progress document
```json
{
"contract_version": "v1alpha1",
"task_id": "600519.SS_20260413_120000_ab12cd",
"ticker": "600519.SS",
"date": "2026-04-13",
"status": "running",
"progress": 40,
"current_stage": "research",
"created_at": "2026-04-13T12:00:00Z",
"elapsed_seconds": 18,
"stages": [
{"name": "analysts", "status": "completed", "completed_at": "12:00:05"},
{"name": "research", "status": "running", "completed_at": null},
{"name": "trading", "status": "pending", "completed_at": null},
{"name": "risk", "status": "pending", "completed_at": null},
{"name": "portfolio", "status": "pending", "completed_at": null}
],
"result": null,
"error": null
}
```
Notes:
- `elapsed_seconds` is preferred over the current loosely typed `elapsed`.
- stage entries should carry explicit `name`; current positional arrays are fragile.
- `result` remains nullable until completion.
## 5.3 Completed result payload
```json
{
"contract_version": "v1alpha1",
"task_id": "600519.SS_20260413_120000_ab12cd",
"ticker": "600519.SS",
"date": "2026-04-13",
"status": "completed",
"progress": 100,
"current_stage": "portfolio",
"result": {
"decision": "OVERWEIGHT",
"confidence": 0.64,
"signals": {
"merged": {"direction": 1, "rating": "OVERWEIGHT"},
"quant": {"direction": 1, "rating": "OVERWEIGHT", "available": true},
"llm": {"direction": 1, "rating": "BUY", "available": true}
},
"degraded": false,
"report": {
"path": "results/600519.SS/2026-04-13/complete_report.md",
"available": true
}
},
"error": null
}
```
## 5.4 Failed result payload
```json
{
"contract_version": "v1alpha1",
"task_id": "600519.SS_20260413_120000_ab12cd",
"ticker": "600519.SS",
"date": "2026-04-13",
"status": "failed",
"progress": 60,
"current_stage": "trading",
"result": null,
"error": {
"code": "analysis_failed",
"message": "both quant and llm signals are None",
"retryable": false
}
}
```
## 6. Live signal batch contract
This covers `/ws/orchestrator` style responses currently produced by `LiveMode`.
```json
{
"contract_version": "v1alpha1",
"signals": [
{
"ticker": "600519.SS",
"date": "2026-04-13",
"status": "completed",
"result": {
"direction": 1,
"confidence": 0.64,
"quant_direction": 1,
"llm_direction": 1,
"timestamp": "2026-04-13T12:00:11Z"
},
"error": null
},
{
"ticker": "300750.SZ",
"date": "2026-04-13",
"status": "failed",
"result": null,
"error": {
"code": "live_signal_failed",
"message": "both quant and llm signals are None",
"retryable": false
}
}
]
}
```
## 7. Historical report contract
```json
{
"contract_version": "v1alpha1",
"ticker": "600519.SS",
"date": "2026-04-13",
"decision": "OVERWEIGHT",
"report": "# TradingAgents ...",
"artifacts": {
"complete_report": true,
"stage_reports": {
"analysts": true,
"research": true,
"trading": true,
"risk": true,
"portfolio": false
}
}
}
```
## 8. Mapping from current implementation
Current backend fields in `web_dashboard/backend/main.py` map roughly as follows:
- `decision` -> `result.decision`
- `quant_signal` -> `result.signals.quant.rating`
- `llm_signal` -> `result.signals.llm.rating`
- `confidence` -> `result.confidence`
- top-level `error` string -> structured `error`
- positional `stages[]` -> named `stages[]`
## 9. Compatibility notes
### v1alpha1 tolerances
Consumers should tolerate:
- absent `result.signals.quant` when quant path is unavailable
- absent `result.signals.llm` when LLM path is unavailable
- `result.degraded = true` when only one lane produced a usable signal
### fields to avoid freezing yet
Do not freeze these until config-schema work lands:
- provider-specific configuration echo fields
- raw metadata blobs from quant/LLM internals
- report summary extraction fields
## 10. Open review questions
- Should `rating` remain duplicated with `direction`, or should one be derived client-side?
- Should task progress timestamps standardize on RFC 3339 instead of mixed clock-only strings?
- Should historical report APIs return extracted summary separately from full markdown?