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

5.7 KiB

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

["pending", "running", "completed", "failed", "cancelled"]

3.2 Stage name

["analysts", "research", "trading", "risk", "portfolio"]

3.3 Decision rating

["BUY", "OVERWEIGHT", "HOLD", "UNDERWEIGHT", "SELL"]

4. Canonical envelope

All application-facing payloads should include:

{
  "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

{
  "contract_version": "v1alpha1",
  "task_id": "600519.SS_20260413_120000_ab12cd",
  "ticker": "600519.SS",
  "date": "2026-04-13",
  "status": "running"
}

5.2 Status / progress document

{
  "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

{
  "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

{
  "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.

{
  "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

{
  "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?