Attach a take-profit and stop-loss
A take-profit and a stop-loss have to behave as one unit — if the survivor outlives the leg that fired, it re-opens the exposure it was supposed to close. This attaches both to an already-open position as reduce-only legs sharing a single OCO group.
-
Find the position
Section titled “Find the position”The server resolves the position from your account plus the
symbolyou send, so that is the only thing you need off this read. No open position on that symbol gives404 no_position_for_symbol.Terminal window curl -s https://api.troncharts.xyz/api/v1/accounts/$ACCOUNT_ID/positions \-H "authorization: Bearer $TOKEN" \-H "x-tenant-slug: $TC_TENANT_SLUG"# → { accountId, accountNumber, positions: [ { symbol, venue, side, qty, entryPrice, … } ] }const { positions } = await sdk.accounts.positions(accountId)const pos = positions.find((p) => p.symbol === 'BTC.HL') -
Attach both legs
Section titled “Attach both legs”At least one of
tpPrice/slPricemust be present, or you get400 no_legs_requested. Send them as JSON numbers — unlike the compose schema, this one does not coerce decimal strings.Terminal window curl -s https://api.troncharts.xyz/api/v1/oms/brackets/attach-to-position \-H "authorization: Bearer $TOKEN" \-H "x-tenant-slug: $TC_TENANT_SLUG" \-H 'content-type: application/json' \-H "idempotency-key: $(uuidgen)" \-d '{"symbol":"BTC.HL","tpPrice":72000,"slPrice":58500}'const bracket = await sdk.oms.attachBracketsToPosition({ symbol: 'BTC.HL', tpPrice: 72000, slPrice: 58500 },crypto.randomUUID(),) -
Read the OCO group off the response
Section titled “Read the OCO group off the response”Both legs carry
ocoGroupIdas theirparentIntentId; that linkage is what makes them one unit.sideis the closing side (a long position givessell), andqtyis the full position size — each leg covers all of it.{ "ok": true, "ocoGroupId": "9c41…", "tpIntentId": "1a2b…","tpIntentIds": ["1a2b…"], "slIntentId": "7d8e…","side": "sell", "qty": "0.01" }The legs dispatch immediately — a position already exists to reduce, so there is nothing to wait for. From here the server owns the lifecycle: when one leg fills it cancels the survivor, and when the position closes by any route it cancels both.
Next: Split a take-profit across several targets · Cancel an order or close a position · Order lifecycle & signing