feat: order amendments, decrease, and queue positions (v0.5.0)#27
Conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ersResource Add four new sync methods to OrdersResource: - amend() - amend a resting order's price/count - decrease() - reduce order quantity by amount or to target - queue_positions() - list queue positions with optional filters - queue_position() - get single order's queue position as Decimal Includes 13 new tests covering happy paths, serialization verification, error handling (404/400), empty responses, and filter parameter passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…osition() Review fixes from /review adversarial pass: - Add OrderQueuePosition to _contract_map.py for spec drift coverage - Wrap bare KeyError in queue_position() with KalshiError for clean error hierarchy Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Code Review: feat: order amendments, decrease, and queue positions (v0.5.0)OverviewSolid addition of 4 new order management endpoints with full sync/async parity, good test coverage, and proper model design. The implementation follows existing SDK conventions well. A few issues worth addressing before landing. IssuesMedium: def queue_positions(self, *, market_tickers: str | None = None, ...The parameter is named Medium: Calling if reduce_by is None and reduce_to is None:
raise ValueError("decrease() requires either reduce_by or reduce_to")
if reduce_by is not None and reduce_to is not None:
raise ValueError("decrease() accepts reduce_by or reduce_to, not both")Add two regression tests for these cases. Low:
Low:
Observations (non-blocking)
What's done well
Summary: Two medium issues ( |
…rt, queue_position fallback - Add ValueError guards on decrease() for missing/conflicting reduce_by/reduce_to - Accept list[str] | str for market_tickers on queue_positions() (auto-joins with comma) - Add .get() fallback for queue_position_fp/queue_position key in queue_position() - Fix async test that called decrease() with no args (now raises ValueError) - Add 4 regression tests for the new guards (sync + async) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Code Review: feat: order amendments, decrease, and queue positions (v0.5.0)OverviewSolid addition of 4 new order management endpoints. The code follows existing SDK conventions, test coverage is thorough, and sync/async parity is maintained. A few issues worth addressing before landing. Bug: Falsy short-circuit in
|
| Severity | Issue |
|---|---|
| Bug | or falsy short-circuit in queue_position() — use is not None |
| Improvement | Client-side guard: amend() with no price or count raises ValueError |
| Test gap | market_tickers list comma-join is never asserted |
| Test gap | queue_position() fallback key ('queue_position') is never exercised |
| Nit | import json and model imports inside test function bodies |
The core logic, model design, auth guards, and error mapping all look correct and follow project conventions. The or short-circuit in queue_position() is the one thing worth fixing before landing — everything else is low-risk.
- Add ValueError guard on amend() when no price or count provided - Fix falsy short-circuit in queue_position() (or → is not None) - Fix line-too-long lint errors in queue_positions() tickers_str - Add test for market_tickers list comma-join - Add test for queue_position() fallback key path - Add test for amend() no-price-or-count guard - Fix existing tests that called amend() without price args Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Code Review: feat: order amendments, decrease, and queue positions (v0.5.0)OverviewThis PR adds 4 new order management endpoints to Issues1. Missing test:
|
Covers the third code path in queue_position() where neither queue_position_fp nor queue_position key is present in the response. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Code Review — PR #27: Order amendments, decrease, and queue positions (v0.5.0)OverviewAdds 4 new order management endpoints ( IssuesMinor:
|
Brings async amend coverage to parity with sync: - test_amend_serializes_dollars_and_count (wire format verification) - test_amend_validation_error (400 → KalshiValidationError) - test_amend_requires_price_or_count (ValueError guard) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Code Review — PR #27: Order amendments, decrease, and queue positions (v0.5.0)Overall: Solid, well-structured addition. The implementation follows existing SDK conventions closely and the test coverage is thorough. A few gaps in the async test suite and one serialization question to clarify before merge. What this PR doesAdds 4 new order management methods ( Issues to fix before merge1. Async test suite has gaps vs. sync The sync tests in
These gaps mean async regressions on those paths won't be caught. Each sync test that covers a distinct code path should have an async mirror. 2. In body["count_fp"] = str(to_decimal(count))
Minor issues3. Inline imports in test methods Several tests use mid-function imports, which is inconsistent with the rest of the test files: # tests/test_orders.py — test_amend_serializes_dollars_and_count
import json # ← inside the test body
# tests/test_async_orders.py — auth guard tests
from kalshi.errors import AuthRequiredError # ← inside every guard test
4. raise KalshiError(
f"Unexpected response for queue_position: missing 'queue_position_fp' in {data!r}"
)The code actually falls through if either raise KalshiError(
f"Unexpected response for queue_position: missing 'queue_position_fp' and 'queue_position' in {data!r}"
)5. The Kalshi API accepts only specific string values for What looks good
SummaryFix the 6 missing async tests and verify the |
- Add async test_decrease_to and test_decrease_not_found - Add async test_queue_positions_with_list_tickers - Add async test_queue_position_fallback_key and test_queue_position_not_found - Fix queue_position() error message to mention both fallback keys Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Code Review: feat: order amendments, decrease, and queue positions (v0.5.0)Overall: Well-structured, clean PR with solid test coverage. Follows existing SDK conventions consistently. A few minor items to address. OverviewAdds four new order management endpoints ( IssuesModerateInline imports in test methods ( # Inside test body:
import json
from kalshi.errors import KalshiError
from kalshi.models.orders import OrderQueuePositionThese should be at module level. Mid-function imports signal the module's Minor
yes_price: float | str | int | None = None
Missing test:
order_data = data.get("order", data)There's no test for the case where the API returns a bare Missing test: All amend serialization tests use InformationalSync/async duplication The
Auth guard ordering The auth guard tests for unauth_orders.amend("ord-123", ticker="T", side="yes", action="buy")This works because What's working well
🤖 Generated with Claude Code |
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Code Review: feat: order amendments, decrease, and queue positions (v0.5.0)OverviewThis PR adds 4 new order management methods to Issues1. Potential API field name mismatch in
|
…ath (#28) (#142) * fix(ws): wire SequenceTracker into MessageDispatcher PR #137 added an optional seq_tracker kwarg on MessageDispatcher.__init__ so server-initiated unsubscribe (#81) can clear stale seq state alongside the sid mapping. The wiring at the construction site in KalshiWebSocket was never landed — the dispatcher always saw seq_tracker=None and could only clear half the state. Closes #27 (post-Wave-3 integration tracker). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(ws): close #84 F-O-05 + #86 — drop exc_info leak, single parse path F-O-05 / Closes #84 (final half): The validation-failure log in MessageDispatcher.dispatch used `logger.warning("Failed to parse %s message", msg_type, exc_info=True)`. Pydantic's ValidationError stringification echoes the full input — for trade/fill/order_group channels that includes price, count, and sometimes user identifiers, dumped straight into stdout/Sentry/log infrastructure. Dropped exc_info; surface type + exception class name only. The underlying exception is still available via __cause__ for local debug. #86 dispatcher side: - Signature change: dispatch(raw: str) -> dispatch(data: dict, *, pre_validated: BaseModel | None = None). The recv loop now owns the json.loads (it already had one); the dispatcher's redundant second parse is gone. - pre_validated lets the recv loop hand off an orderbook message it already validated for the local OrderbookManager, so the dispatcher routes the same instance to the subscription queue without re-running Pydantic. Eliminates the double-validate the issue called out (~3 µs/msg). - json import dropped from dispatch.py (now unused). Recv loop client.py side (in the previous commit alongside the seq_tracker wiring): _process_frame captures the typed orderbook message and passes pre_validated to dispatch. Test fallout: - 21 tests in test_dispatch.py updated from `dispatcher.dispatch(raw)` to `dispatcher.dispatch(json.loads(raw))` via sed. - Dropped test_dispatch_invalid_json — that path now lives in the recv loop's exception ladder (covered by test_malformed_frame_logged_with_traceback_and_continues). - 2 tests in test_recv_loop_hardening.py monkey-patched dispatch with the old (raw: str) signature; updated to (data: dict[str, Any], **kw). - New regression: test_dispatch_pre_validated_skips_revalidation — asserts dispatch routes the same instance when pre_validated matches the expected model_cls. Closes #84 Closes #86 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * review(#142): drop false __cause__ claim in dispatch parse-fail log Per bot review on PR #142: the comment said "the underlying exception is preserved on __cause__ for debug" — but the except block catches, logs the type name, and returns. Nothing is re-raised, so no __cause__ chain is established. Dropped the misleading sentence; kept the security rationale (Pydantic input echo). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Adds 4 new order management endpoints to the SDK, bringing coverage from 24 to 28 of 77 Kalshi API endpoints.
New methods on OrdersResource + AsyncOrdersResource:
amend(order_id, *, ticker, side, action, yes_price, no_price, count, ...)— amend order price and/or quantity. ReturnsAmendOrderResponsewith both pre and post-amendment state.decrease(order_id, *, reduce_by, reduce_to, subaccount)— reduce order quantity by amount or to amountqueue_positions(*, market_tickers, event_ticker, subaccount)— bulk queue position lookup for all resting ordersqueue_position(order_id)— single order queue position, returnsDecimalNew models:
AmendOrderResponse(old_order: Order, order: Order)— preserves both pre/post amendment stateOrderQueuePosition(order_id, market_ticker, queue_position)— queue position dataTesting: 29 new tests (557 total). Sync/async happy paths, error paths (404, 400), serialization verification, and auth guards for all 4 methods.
Spec drift: Contract map entries added for both new models. Integration coverage harness updated.
Review fix:
queue_position()now wrapsKeyErrorinKalshiErrorinstead of leaking raw exceptions.Test Coverage
557 tests passing. mypy clean. ruff clean.
Tests: 528 → 557 (+29 new)
All new code paths covered: happy path, error path, serialization, auth guards, sync + async mirrors.
Pre-Landing Review
Pre-Landing Review: 3 issues (0 critical, 3 informational)
Adversarial review ran with both Claude + Codex. PR Quality Score: 9/10.
TODOS
Test plan
🤖 Generated with Claude Code