@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:
- 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.
- 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.
- 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.