-
Notifications
You must be signed in to change notification settings - Fork 0
feat(orderscaler): introduce order scaling with config, API & audits; integrate engine/emitter #42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@codex review and check if it matches specs/order_scaler.adoc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| func (s *Storage) UpsertOrderScaler(ctx context.Context, multiplier float64, updatedBy string, notes *string) (OrderScalerState, error) { | ||
| s.mu.Lock() | ||
| defer s.mu.Unlock() | ||
|
|
||
| params := sqlcgen.UpsertOrderScalerParams{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Publish SSE events when order scaler settings change
The spec requires multiplier configuration to be “hot‑reloadable” and broadcast via the storage stream, but UpsertOrderScaler (and similarly UpsertBotOrderScaler/DeleteBotOrderScaler) only persist to SQLite and immediately return without calling publishStreamEventLocked. Components that cache the effective multiplier will never see updates unless they poll or restart, so UI/API consumers cannot react to configuration changes as described in specs/order_scaler.adoc.
Useful? React with 👍 / 👎.
…ion-in-operations docs: document order scaler operations and architecture
…port feat: add order scaler configuration endpoints
…vice feat: add Hyperliquid order scaling service
…d-recordscaledorder feat(storage): add order scaler read models and events
|
@codex review and confirm if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| func (e *Engine) applyScaling( | ||
| ctx context.Context, | ||
| md metadata.Metadata, | ||
| latest *recomma.BotEvent, | ||
| action recomma.Action, | ||
| logger *slog.Logger, | ||
| ) (recomma.Action, *orderscaler.Result, bool, error) { | ||
| if e.scaler == nil || latest == nil { | ||
| return action, nil, true, nil | ||
| } | ||
|
|
||
| switch action.Type { | ||
| case recomma.ActionCreate: | ||
| if action.Create == nil { | ||
| return action, nil, true, nil | ||
| } | ||
| req := orderscaler.BuildRequest(md, latest.BotEvent, *action.Create) | ||
| result, err := e.scaler.Scale(ctx, req, action.Create) | ||
| if err != nil { | ||
| if errors.Is(err, orderscaler.ErrBelowMinimum) { | ||
| logger.Warn("skipping scaled order below venue minimum", slog.Float64("price", req.Price), slog.Float64("size", req.OriginalSize)) | ||
| return recomma.Action{Type: recomma.ActionNone, Reason: "scaled order below minimum"}, nil, false, nil | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Emit an audit when a scaled order is skipped
The spec requires deals that fall below Hyperliquid minimums to be “flag[ged] for operator review and skip submission rather than silently discarding legs”. In applyScaling a below‑minimum leg is handled by logging and returning ActionNone, but no storage audit or SSE event is emitted. As a result operators who rely on the order scaler records or the streamed logs have no visibility that an order was skipped, so the requirement to flag the deal is not met.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codex plan a task how we resolve this properly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation in Engine.applyScaling turns a below-minimum leg into ActionNone without recording anything in storage or the SSE stream, so operators never see that the scaled order was skipped. This violates the spec’s requirement to flag sub-minimum deals for review instead of silently discarding them. engine/engine.goL500-L536 specs/order_scaler.adocL14-L18
:::task-stub{title="Record and broadcast skipped scaled orders"}
Step 1. Extend the scaler audit model to represent skipped submissions (e.g., add a skipped flag or reason) by updating storage/sqlc/schema.sql, corresponding queries, and regenerating storage/sqlcgen. Update storage/order_scalers.go conversions and publishStreamEventLocked to include the new metadata, and reflect the shape change in openapi.yaml/generated API types so SSE consumers can detect skipped legs.
Step 2. Teach engine/orderscaler.Service to invoke the new storage hook when constraints.NotionalBelowMinimum triggers, ensuring the audit row and SSE event are created before returning ErrBelowMinimum. Add focused coverage in engine/orderscaler/service_test.go for the skip path.
Step 3. Update Engine.applyScaling so that when Scale reports a skipped order it forwards the scaler’s audit metadata (if any) and logs, ensuring the engine records the skip without re-entering storage. Extend existing engine tests (or add new ones) to verify the audit emission when an order is skipped.
:::
…or-skips feat: audit skipped scaled orders
|
@codex review and confirm if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| scaledSize := req.OriginalSize * multiplier | ||
|
|
||
| constraints, err := s.constraints.Resolve(ctx, req.Coin) | ||
| if err != nil { | ||
| return Result{}, fmt.Errorf("resolve constraints: %w", err) | ||
| } | ||
|
|
||
| roundedPrice := order.Price | ||
| if req.Price > 0 { | ||
| roundedPrice = req.Price | ||
| } | ||
| roundedPrice = constraints.RoundPrice(roundedPrice) | ||
|
|
||
| roundedSize := constraints.RoundSize(scaledSize) | ||
| roundedSize = clampToNonNegative(roundedSize) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep take‑profit ratios intact when rounding scaled legs
The order scaler currently multiplies and rounds each order independently (scaledSize := req.OriginalSize * multiplier followed by constraints.RoundSize), which can change the proportional sizes of stacked take‑profit orders when lot rounding kicks in. The spec in specs/order_scaler.adoc requires that “scaled legs preserve ratio orderings” after applying venue tick/lot rules. With the existing implementation two legs sized 1.0 and 1.05 with a 0.5× multiplier and 0.1 size step become 0.5 and 0.5 after rounding, altering the leg ratios and changing exposure. Consider adjusting the algorithm to scale the entire stack and redistribute rounding deltas so the relative sizes remain consistent while still respecting the venue’s increments.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codex propose a better implementation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary
- Extended the order scaler request metadata and scaling routine to resolve take-profit stack sizes from storage and apply ratio-aware rounding across each stack while preserving lot constraints. engine/orderscaler/service.goL66-L190 engine/orderscaler/service.goL204-L320
- Added a storage helper that queries the latest threecommas take-profit legs for a deal to supply stack sizing data, alongside the supporting SQL definition. storage/order_scalers.goL158-L210 storage/sqlc/queries.sqlL402-L424
- Introduced a unit test covering stacked take-profit legs to ensure scaled outputs maintain the expected ordering after rounding. engine/orderscaler/service_test.goL107-L166
Testing
⚠️ go test ./...(hung waiting on external module downloads; aborted)
|
@codex review |
|
Codex Review: Didn't find any major issues. Breezy! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
…or-orders
feat(orderscaler): introduce order scaling with config, API & audits; integrate engine/emitter
Add an order-scaler subsystem that applies configurable multipliers to mirrored orders, preserves take-profit stack ratios under venue constraints, and records auditable changes. Integrates across engine, storage, API, docs, and tests.
| Area | Key changes |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Config | Add `OrderScalerMaxMultiplier` (flag `--order-scaler-max-multiplier`, env `RECOMMA_ORDER_SCALER_MAX_MULTIPLIER`). Validate >0. Wire into API handler and engine. |
| Engine | Insert scaling step before submission; skip orders that fall below venue minimums (with audit); preserve TP stack ratios; feed scaled size/price into fill tracker. |
| Emitter | Return/propagate Hyperliquid order status; log `requested_size`, `executed_size`, and IOC retry metadata. |
| HL constraints | Add metadata cache for coin rounding (`SizeStep`, significant figs, min notional helper). |
| Storage | Persist default + per-bot scaler configs; compute effective scaler; store `scaled_orders` audit with rounding delta, actor, skip reason; expose list/query helpers. |
| API (OpenAPI) | New endpoints: `GET/PUT /api/v1/order-scaler`, `GET/PUT/DELETE /api/v1/bots/{botId}/order-scaler`, `GET /api/orders/scalers`. Enforce multiplier bounds and vault session. |
| Streaming | Emit `order_scaler_config` and `scaled_order_audit` entries on `/sse/orders` with actor and effective config. |
| Docs | Architecture + operations runbook for the scaler; navigation updates; README pointer. |
| Tests | Unit tests for scaler service, engine integration, emitter logging, fill tracker updates, and API handler. |
Notes:
* Multiplier clamped by configured max; below-minimum-notional legs are **skipped** and audited with reason.
* Effective config resolves per-bot overrides against the global default and is included in stream/audit payloads.
feat(orderscaler): introduce order scaling with config, API & audits; integrate engine/emitter
Add an order-scaler subsystem that applies configurable multipliers to mirrored orders, preserves take-profit stack ratios under venue constraints, and records auditable changes. Integrates across engine, storage, API, docs, and tests.
OrderScalerMaxMultiplier(flag--order-scaler-max-multiplier, envRECOMMA_ORDER_SCALER_MAX_MULTIPLIER). Validate >0. Wire into API handler and engine.requested_size,executed_size, and IOC retry metadata.SizeStep, significant figs, min notional helper).scaled_ordersaudit with rounding delta, actor, skip reason; expose list/query helpers.GET/PUT /api/v1/order-scaler,GET/PUT/DELETE /api/v1/bots/{botId}/order-scaler,GET /api/orders/scalers. Enforce multiplier bounds and vault session.order_scaler_configandscaled_order_auditentries on/sse/orderswith actor and effective config.Notes:
Refs: #43, #44, #45, #46, #47
https://chatgpt.com/codex/tasks/task_e_690493b50a808326a027433a459e035a