Skip to content

feat(exchange): add bulk_order_with_grouping for normalTpsl atomic submits#191

Open
HathorNodes wants to merge 3 commits into
hyperliquid-dex:masterfrom
Hathor-Nodes:feat/grouping-param
Open

feat(exchange): add bulk_order_with_grouping for normalTpsl atomic submits#191
HathorNodes wants to merge 3 commits into
hyperliquid-dex:masterfrom
Hathor-Nodes:feat/grouping-param

Conversation

@HathorNodes
Copy link
Copy Markdown

Summary

The current `bulk_order` and `bulk_order_with_builder` hardcode `grouping: "na"` with no caller-facing override, which makes it impossible to submit atomic IOC entry + paired SL trigger via `grouping="normalTpsl"` — the canonical HL TPSL pattern that the Python SDK exposes as `exchange.bulk_orders(orders, grouping=...)`.

This PR adds two new methods to expose the existing `BulkOrder { grouping }` field through the public API:

  • `bulk_order_with_grouping(orders, wallet, grouping: &str)` — same payload shape as `bulk_order`, with `grouping` threaded through.
  • `bulk_order_with_builder_and_grouping(orders, wallet, builder, grouping: &str)` — equivalent with builder fees.

Existing `bulk_order` / `bulk_order_with_builder` are preserved as thin shims delegating to the new methods with `grouping = "na"`, so this change is fully backward-compatible — zero call-site updates needed for current users.

Valid grouping values, per the L1 action schema: `"na"`, `"normalTpsl"`, `"positionTpsl"`.

Use case

Submitting a bracket order (entry IOC + paired stop-loss trigger) as a single signed L1 action so they're processed atomically by the matching engine — eliminates the race where an entry could fill into an unprotected position momentarily if the SL trigger were posted separately. The Python SDK has supported this since 2023; this brings the Rust SDK to parity.

Test plan

  • `cargo build` green
  • `cargo test --lib` green (8 tests pass; the patch only adds methods, no behaviour changes for existing tests)
  • Integrated into the Hathor Hyperliquid trading bot's Rust port via `[patch.crates-io]` — 101 workspace tests + cross-language parity tests against the Python SDK all green using the new method to post `normalTpsl` brackets.

Happy to add unit tests for the grouping field if the maintainers prefer — the existing test suite doesn't cover `bulk_order` shape directly so wanted to confirm convention before adding.

…bmits

The existing `bulk_order` and `bulk_order_with_builder` hardcode
`grouping: "na"` with no caller-facing override, which makes it
impossible to submit atomic IOC entry + paired SL trigger via
`grouping="normalTpsl"` (the canonical HL pattern, exposed by the
Python SDK as `exchange.bulk_orders(orders, grouping=...)`).

Adds two new methods:

- `bulk_order_with_grouping(orders, wallet, grouping: &str)` — same
  payload shape as `bulk_order`, with `grouping` threaded through to
  `BulkOrder { grouping }`.
- `bulk_order_with_builder_and_grouping(orders, wallet, builder,
  grouping: &str)` — equivalent with builder fees.

Existing `bulk_order` / `bulk_order_with_builder` are preserved as
thin shims delegating to the new methods with `grouping = "na"`, so
this change is fully backward-compatible — zero call-site updates
needed for current users.

Valid grouping values include `"na"`, `"normalTpsl"`, `"positionTpsl"`.

`cargo build` + `cargo test --lib` green.
@HathorNodes HathorNodes force-pushed the feat/grouping-param branch from e607d8c to ca35192 Compare May 14, 2026 05:22
HathorNodes and others added 2 commits May 15, 2026 05:45
…214)

Adds the spot clearinghouse equivalent of user_state(): POST /info with
{"type": "spotClearinghouseState", "user": "<addr>"} returning a
per-coin balance list. The downstream Hathor Rust LiveExecutor needs both
perps (user_state) + spot (this method) to compute total account equity,
matching Python SDK semantics.

Wire-identical to the existing user_token_balances method (reuses the
InfoRequest::UserTokenBalances variant); SpotUserStateResponse differs
from UserTokenBalanceResponse only in dropping the entryNtl field for
parity with hyperliquid.info.Info.spot_user_state in the Python SDK.

Refs: Hathor-Nodes/hathor-nodes-bot#214, Hathor-Nodes/hathor-nodes-bot#171

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…hor #215)

The Hathor Rust LiveExecutor's info_bridge::msg_to_value translates
SDK WSS Message variants to serde_json::Value envelopes that downstream
callbacks consume. UserData (fills) and UserFundings need to round-trip
through serde_json so the trailing-stop + partial-TP logic in
Tick 3 of hyperliquid-dex#171 can read fill data from the bridge envelope.

Refs: Hathor-Nodes/hathor-nodes-bot#215, Hathor-Nodes/hathor-nodes-bot#171

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant