--- name: desk-trade-lifecycle description: The end-to-end procedure for one trade on the HyperGrok desk - from an idea to a reviewed, journaled result - with the ticket format, the JSON ticket and policy gate that replace human approval, who owns each stage, and what "done" looks like. Use whenever the user or the cycle wants to open, adjust or close a position, or whenever any role is about to touch the exchange write path. license: MIT metadata: version: "1.2.0" author: Galleon Labs category: desk --- # Trade lifecycle Every position change on the desk goes through the same seven stages, in order. Skipping one is a defect, not a shortcut. The Desk Lead keeps the lifecycle moving; the owner of each stage does the work. In the autonomous cycle (`desk-autonomous-loop`) the same stages run in the same order with nobody watching. ``` idea -> evidence -> risk sign-off -> policy gate -> execution -> reconciliation -> review DL MA/RA RM gate script ET ET TR ``` ## 0. Open a proposal **Owner: Desk Lead.** As soon as a trade idea appears (from the user, a live strategy, the Strategist's discretionary judgement, or a watch alert), assign an id `HG-YYYYMMDD-NN` (NN increments per day) and create `/workspace/trading-desk/proposals/.md`: ```markdown # HG-20260907-01 - opened: 2026-09-07 14:02 UTC by user - origin: user - market: ETH-PERP network: testnet account: 0xabc...def - idea: long ETH on a retest of 3,000 with invalidation below 2,900 (user's idea) - status: evidence ## evidence ## risk ## approval ## execution ## reconciliation ## review ``` `origin` is `user`, `user:`, `strategist:` or `desk:discretionary`; it is copied into the JSON ticket and checked by the gate. Every later stage appends under its heading. The file is the single record of the trade; chat is context. ## 1. Evidence **Owner: Market Analyst, and Research Analyst when the idea depends on anything beyond exchange data.** The Desk Lead asks for exactly what sizing and execution will need: current mid, mark and oracle; funding now and predicted; open interest and 24h volume; depth within 5/10/25 bps for the intended size; the market's constraints (max leverage, margin tiers, size decimals, minimum order value); recent range and volatility. Research adds anything scheduled or breaking that touches the market. Both write their blocks under `## evidence` with sources and UTC times. Done when: the Risk Manager has every input it needs and nothing is older than a few minutes. ## 2. Risk sign-off **Owner: Risk Manager.** Reads `risk-limits.md`, reads live account state, computes size from the stop and risk budget, checks every gate, and writes PASS or REJECT with exact ticket fields under `## risk` (procedure and arithmetic in `desk-risk-limits`). A PASS produces the **ticket**, in two forms from the same numbers: the block below under `## risk`, and `proposals/.ticket.json` with the fields in `desk-autonomy-policy` section 2. ``` TICKET HG-20260907-01 | testnet | account 0xabc...def market: ETH-PERP (asset 1) side: buy size: 0.4827 ETH (~$1,448) entry: limit 3,000.0 Gtc reduce-only: no stop: sell 0.4827 trigger 2,900 market (worst 2,755, 5% bound), normalTpsl with the entry take-profit: none leverage: 3x cross (set before entry if different) slippage tolerance: 10 bps from ticket price at send time risk: $51.00 = 0.5% of equity $10,200.00 (clearinghouseState 14:11 UTC), R = 100 USD/ETH sizing: stressed distance 105.65 USD/ETH (stop 100 + slippage 3.00 + fees 2.65) origin: user risk sign-off: PASS 14:12 UTC, risk-limits.md v3 expires: 14:42 UTC gate: python3 /workspace/hypergrok/scripts/policy_gate.py check --desk-root /workspace/trading-desk --ticket proposals/HG-20260907-01.ticket.json ``` A REJECT names one failed gate and what would have to change. A REJECT ends the lifecycle for that proposal unless the idea changes (new evidence, new stop, new size) - then it goes back to stage 1 under the same id with a note. ## 3. Policy gate **Owner: `scripts/policy_gate.py`, run by the Execution Trader or the cycle.** The gate reads the JSON ticket, `autonomy.json`, the halt file, the send ledger and live account state, prints every check with its numbers, and exits 0 (PASS, `proposals/.approval.json` written), 1 (FAIL, failed gate names on the last line) or 2 (an input was unavailable; not a PASS). The full output is pasted under `## approval` with the UTC time. What it checks is listed in `desk-autonomy-policy` section 3. A FAIL ends the lifecycle for that ticket. Nobody edits the ticket to make it pass; a changed idea is a new ticket with a fresh Risk sign-off. A PASS is good for ten minutes and for the exact ticket bytes; if the send has not happened by then, run the gate again (the ticket itself is still valid until its 30-minute expiry). In a supervised session the user may also type "approve HG-20260907-01" after seeing the ticket. The Desk Lead records that line and its timestamp under `## approval` as `origin: user` evidence. It is welcome; it is not the gate. A ticket with a typed approval and a gate FAIL is not approved. If the ticket expires before the gate passes, it is void; a fresh Risk sign-off is needed because prices and the book have moved. ## 4. Execution **Owner: Execution Trader.** Runs the pre-send checklist in `desk-execution-protocol`, calls `scripts/desk_send.py` once for the ticket, and records the printed intent, `cloid`, `expiresAfter` deadline, response and timestamps under `## execution`. Anything other than exit 0 is handled per `desk-incident-response`. ## 5. Reconciliation **Owner: Execution Trader.** Confirms from the exchange record - `orderStatus` by cloid, `openOrders`, `userFills`, `clearinghouseState` - and from `proposals/.execution.json` what happened, and writes it under `## reconciliation`. Posts the execution report on the floor (or in the cycle log) and DMs the Trade Reviewer. Reconciliation continues while the order rests: fill notifications go into the same section as they arrive. ## 6. Review **Owner: Trade Reviewer.** Journals the trade on the day it happened; writes the review when the trade closes (or on request), per `desk-post-trade-review`. Sets `status: closed` in the proposal file. ## Adjustments and exits are trades too Moving a stop, adding to a position, reducing, closing, changing leverage: each is a new ticket under the same proposal id with a suffix (`HG-20260907-01-B`), with its own `proposals/-B.ticket.json` (`kind` set to `entry`, `close` or `protect`), its own Risk PASS and its own gate run. Closing a position at market needs a ticket stating the reduce-only size read live from the account and the slippage bound. Protective tickets (`kind: protect`, reduce-only with a stop) and closes always pass the gate, halted or not, so an unprotected position never waits on anyone. They are still tickets, and they are still journaled. ## Paper trading and testnet The lifecycle is identical on testnet. That is the point: the user sees the tickets, gate output, reports and reviews with play money before any real key exists. Strategy signals enter at stage 0 as proposals like any other idea; only strategies with `status: live` in their `RULES.md` are traded by the cycle (`desk-strategy-lab`). ## Definitions of done - A proposal is **live** once stage 5 shows a resting or filled order. - A proposal is **closed** once the position is flat, orphaned orders are cancelled, and stage 6 is written. - A proposal is **void** if it expired or was rejected without a retry. ## Common failure modes and the fix | Symptom | Fix | | --- | --- | | The user asks the Execution Trader directly to "just buy some" | Execution Trader routes to the Desk Lead; a proposal is opened; the lifecycle runs. It can be quick, but it runs. | | Risk PASS was computed from a brief older than the ticket | Risk re-reads live state; PASS is re-issued with a new expiry and a new JSON ticket. | | Gate FAIL | The failed gate is named under `## approval`; the proposal ends for this cycle. A changed idea is a new ticket, never an edited one. | | Approval expired (10 min) before the send | Run the gate again on the unchanged ticket; if the ticket itself has expired, back to Risk. | | Two roles each think they own the next step | The proposal file's `status` line names the stage; the stage owner acts. | | Ticket on testnet, desk configured for mainnet (or vice versa) | The gate fails `network`; `desk_send.py` would refuse anyway. Fix the environment or the policy, never the ticket. |