trade -- Trading Action Tool

The unified trading action tool. Dispatches to one of 6 actions via the action parameter. Always visible at root post-onboarding -- no hub expansion needed.

All trade actions use a two-phase confirmation protocol: propose first, then confirm. Proposals expire after 60 seconds.


Actions

propose_entry

Create an entry proposal for an Iron Condor position.

Parameter Type Required Default Description
action string Yes -- "propose_entry"
ticker string Yes -- Underlying symbol
candidate dict Yes -- Candidate from find_iron_condors (must include strikes and credit)
qty int Yes -- Number of contracts (>= 1)
saved_strategy_id string No null UUID from save_strategy for audit trail

The candidate dict must include: expiry, short_put, long_put, short_call, long_call, net_credit. Pass a complete candidate object from find_iron_condors results.

When saved_strategy_id is provided, the proposal is linked to the optimizer run that produced the strategy, creating a full audit trail from optimization through execution.

Response: ProposalResponse with a proposal_id and 60-second TTL.

{
  "id": "p1q2r3s4-...",
  "type": "entry",
  "ticker": "SPY",
  "status": "pending",
  "payload": {
    "candidate": { "..." : "..." },
    "qty": 2,
    "saved_strategy_id": "e5f6g7h8-..."
  },
  "expires_at": "2026-05-12T14:31:00Z",
  "created_at": "2026-05-12T14:30:00Z"
}

propose_roll

Create a roll proposal for an existing Iron Condor position.

Parameter Type Required Default Description
action string Yes -- "propose_roll"
position_id string Yes -- UUID of the IC position to roll
intent string Yes -- "full_roll" (both spreads) or "spread_roll" (one side)
candidate_id string No null Specific roll candidate ID
roll_side string No null "put" or "call" (for spread_roll)
new_short_strike float No null Override short strike for the new spread
new_long_strike float No null Override long strike for the new spread
new_expiry string No null Override expiration date
liquidation_order_type string No "market" Order type for closing the old spread
liquidation_net_debit float No null Limit price for closing (if limit order)
open_order_type string No "market" Order type for opening the new spread
open_net_credit float No null Limit price for opening (if limit order)

Response: ProposalResponse with a proposal_id and 60-second TTL.


propose_exit

Create an exit proposal to close an existing position.

Parameter Type Required Default Description
action string Yes -- "propose_exit"
position_id string Yes -- UUID of the position to close
reason string No "" Why the exit is being requested

Response: ProposalResponse with a proposal_id and 60-second TTL.


confirm

Submit a pending proposal to the broker for execution.

Parameter Type Required Description
action string Yes "confirm"
proposal_id string Yes UUID from a propose action

Must be called within 60 seconds of the proposal creation. After confirmation, the order is submitted to the active broker account.

Response: PendingOrderSchema with order details.

Errors:

  • PROPOSAL_NOT_FOUND -- invalid or non-existent proposal ID
  • PROPOSAL_EXPIRED -- TTL exceeded (create a new proposal)
  • PROPOSAL_ALREADY_CONSUMED -- already confirmed

cancel

Cancel a pending proposal before it expires or is confirmed.

Parameter Type Required Description
action string Yes "cancel"
proposal_id string Yes UUID of the proposal to cancel

Response:

{
  "ok": true,
  "proposal_id": "p1q2r3s4-...",
  "status": "cancelled"
}

list

List proposals for the current user.

Parameter Type Required Default Description
action string Yes -- "list"
status string No null Filter: "pending", "confirmed", "expired", "cancelled"
limit int No 20 Max results (1-50)

Response: Array of proposal summaries, newest first.

[
  {
    "id": "p1q2r3s4-...",
    "type": "entry",
    "ticker": "SPY",
    "status": "pending",
    "qty": 2,
    "net_credit": 1.42,
    "expires_at": "2026-05-12T14:31:00Z",
    "created_at": "2026-05-12T14:30:00Z"
  }
]

Proposal Lifecycle

propose_entry / propose_roll / propose_exit
    |
    v
  PENDING  ---- 60 seconds ----> EXPIRED (automatic)
    |
    +---> confirm  ----> CONFIRMED (order submitted to broker)
    |
    +---> cancel   ----> CANCELLED (no order placed)
  • Proposals are immutable once created. The 60-second TTL ensures prices do not drift too far between proposal and execution.
  • A background worker (proposal_expirer) marks uncollected proposals as expired.
  • Each proposal stores the full trade details (candidate, qty, strategy reference) so the agent can review what was proposed.

Audit Trail via saved_strategy_id

When propose_entry includes a saved_strategy_id, the full provenance chain is recorded:

Optimizer run (run_id)
    -> Saved strategy (saved_strategy_id, rank)
        -> Chain scan (find_iron_condors with saved_strategy_id)
            -> Entry proposal (proposal_id, saved_strategy_id)
                -> Confirmed order (order_id)
                    -> Position (position_id)

This enables regulatory audit, performance attribution, and "what strategy produced this trade?" queries.


Cross-references