/order/liquidatePosition

@Alexander I have /order/liquidatePosition and orderstrategy/startorderstrategy working individually. But when I first liquidate followed by starting a new strategy, my strategy also gets closed out right away. I see the commands are sent out about 100ms apart, and I receive the a[{“s”:200,“i”:2,“d”:{}}]’ for each command about 100ms apart as well. But my StartOrderStrategy. gets cancelled right after getting placed. Any ideas on how long a /order/liquidatePosition stays in effect?

2024-01-24:14:20:32,097 DEBUG    [protocol.py:698] > TEXT 'order/liquidateposition\n2\n\n{"accountId":XXX...ull,"isAutomated":true}' [121 bytes]
2024-01-24:14:20:32,163 DEBUG    [protocol.py:548] < TEXT 'a[{"s":200,"i":2,"d":{}}]' [25 bytes]
2024-01-24:14:20:32,226 DEBUG    [protocol.py:698] > TEXT 'orderstrategy/startorderstrategy\n3\n\n{"symbol...ilingStop\\":false}]}"}' [362 bytes]
2024-01-24:14:20:32,293 DEBUG    [protocol.py:548] < TEXT 'a[{"s":200,"i":3,"d":{"orderStrategy":{"id":XXX...essionId":XXXX}}}]' [487 bytes]

@BWeis do you have any thoughts on this?

This is still a problem. I tried creating other work arounds, but I keep coming back to this.

If I place an order right after calling the liquidate command it enters and exits the new order right away.

For anyone still landing here: I probed this endpoint against the demo API today and the body schema that’s been guessed at across this and the
sibling threads is:

POST /order/liquidatePosition
{
“accountId”: ,
“contractId”: <numeric, > 0>,
“admin”: ,
“customTag50”: “”
}

Body Response
{} 400 missing required field “admin”
{“accountId”: N} 400 missing required field “admin”
{“accountId”: N, “isAutomated”: true} 400 missing required field “admin”
{“accountId”: N, “admin”: false} 400 contractId must be > 0
{“accountId”: N, “contractId”: 99999, “admin”: false} 404 (contract validated)
{“accountId”: N, “positions”: [id], “admin”: false} 400 contractId must be > 0
{“accountId”: N, “contractId”: <real, flat>, “admin”: false} 200 {}

Three takeaways:

  1. admin is mandatory. A lot of the example bodies floating around forget it because the debug-log dumps you see make it look optional. It isn’t
    — you’ll get a 400 every time.
  2. It’s per-(accountId, contractId), not by positionId. The positions: [id] body shape several threads suggest is silently ignored — Tradovate
    reads contractId and looks up the netPos server-side itself.
  3. It’s race-safe. If the position closed in the gap between your /position/list and your liquidatePosition POST, you get a clean 200 {} no-op.
    That’s the killer reason to prefer this over a synthesized opposite-side placeOrder, which would open a fresh reverse position in exactly that
    race.