Repository navigation
Support orders placed outside of the algorithm - #53
Merged
Merged
Conversation
Romazes
self-requested a review
August 7, 2026 09:55
Romazes
approved these changes
Sep 11, 2026
AlexCatarino
force-pushed
the
improve-unknown-order-error-message
branch
3 times, most recently
from
September 11, 2026 18:07
645b10e to
4220947
Compare
This was referenced Sep 11, 2026
AlexCatarino
force-pushed
the
improve-unknown-order-error-message
branch
4 times, most recently
from
September 11, 2026 22:49
65a0d79 to
72ced1a
Compare
Explain that unknown order ids are usually caused by manual orders placed directly on the brokerage account, why LEAN terminates the algorithm, and how to trade manually safely (QuantConnect IDE/LEAN CLI or stop-and-redeploy). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Orders placed directly in the Tradier account are now offered to the algorithm through the NewBrokerageOrderNotification event, like the other brokerages do. A custom IBrokerageMessageHandler whose HandleOrder returns true takes ownership of them: LEAN assigns the order id and we start tracking the order, emitting its submission, fills and final status. The default handler ignores them, so unknown order ids keep terminating the algorithm as before, with the message now pointing at the handler. Rejected orders are skipped altogether instead of only within a one minute window: they never reached the account, so there is nothing to track. An empty response from the intraday order fetch no longer fails the algorithm for ids it could not inspect. They are left unverified so the next poll rechecks them, which is also why the error path no longer adds the ids back to the pending set: doing so blocked the recheck task from ever firing again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
An order we couldn't fetch the details of, or couldn't convert into a Lean order, was reported with the same message as an order the algorithm was offered and declined. That message tells the user to set a brokerage message handler whose HandleOrder returns true, which doesn't help when the order never reached the handler in the first place. Both outcomes are now distinguished and get their own message. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The notAcceptedOrderIDs declaration was corrupted in the previous commit, leaving the project uncompilable. Restore it, and use hash sets for both collections so an order id can never be reported twice. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Restores the one minute window on the rejected order check: the fill polling runs every couple of seconds, so a rejection older than that is not one of ours whose brokerage id we failed to resolve, it was placed outside of the algorithm and should be offered to it like any other order. The orders are now kept in a dictionary rather than a set of ids, so the same lookup serves both this check and the brokerage side order handling. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Restores the original recentOrders lines on top of a single fetch, instead of testing the status and transaction date inside the loop, keeping the diff closer to what the method looked like. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Move the BrokerageSideOrderResult enum to its own file under Models/Enums - Clone the brokerage order and reset the execution fields instead of re-creating it field by field - Report the order as submitted with the message the other brokerages use - Cache the order only after it holds its real state: it was being cached with no execution progress before its fills were emitted, so a concurrent poll could see an already filled order as unfilled and emit them twice - Cover the unsupported multileg only order types with a test - Only trace the ids pending a recheck when they change, every poll retries them so an unreachable orders endpoint would flood the log - Add a test for the ids being left unverified after a failed verification, which is what lets the next poll fire a new task for them Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ion races - Declined orders are a one-time Warning and their ids are verified, so later polls don't re-offer them; unprocessable ones stay an Error - Clear the pending id set once the verification task ends, so a second task can't offer the same order twice; handle orders under the fill lock - Reject multileg/combo classes in ConvertOrder; GetOpenOrders skips orders it can't convert instead of failing the launch - Emit the partial fill of closed brokerage-side orders before the final status; cache the order before emitting so a failure is recoverable - TryGetIntradayAndPendingOrders tells a failed request from no orders - Shorter messages, private result enum, no Clone on the order model Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…were Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…supported orders An oto, oco or otoco order in the account failed the whole orders response to deserialize. Unsupported orders placed outside the algorithm now warn instead of stopping it, like IB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AlexCatarino
force-pushed
the
improve-unknown-order-error-message
branch
from
September 25, 2026 17:25
72ced1a to
e9e72fa
Compare
Romazes
approved these changes
Sep 25, 2026
An open multileg, combo, oto, oco or otoco order, or a stop whose price could not be fetched, made GetOpenOrders throw and failed the launch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e orders A timed out order POST can still reach Tradier, so retrying it could place the order twice and have the first one offered back as an outside order. Declined or unsupported outside orders are logged like the other brokerages do, a generic warning would belong in Lean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pported ones A slow placement reply left the order visible to the poll before its id was on the Lean order, so it was offered back as an outside order. The verification now waits for in-flight placements and rechecks the cache and order provider under the fill lock before offering. Each offered id is verified as it's handled, so a failure later in the batch doesn't re-offer the ones already declined. Unsupported outside orders warn again in both paths, as Alpaca does; only declined ones are log-only. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Martin-Molinero
approved these changes
Sep 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Supports orders placed in the Tradier account outside of the algorithm, like TradeStation, Alpaca and IB do. The fill polling converts an unknown order and offers it through
OnNewBrokerageOrderNotification; a brokerage message handler returningtruefromHandleOrdertakes ownership and the order is tracked from then on:Submitted, the fills it already had, and every later update through the regular polling path.credit/debit/eventypes, a stop whose price could not be fetched) raise a one-timeUnprocessableOrderIdWarning and are not tracked, as Alpaca does for its multi-leg orders; the algorithm keeps running. Adopting orders with legs on top of Lean's contingent orders (Add contingent orders: OCO, OTO, OUO and brackets Lean#9828) is left for a follow-up.OrderErrorwarning instead of stopping the algorithm.GetOpenOrdersskips the same unsupported orders with a warning instead of failing the launch.TradierOrderClassgainsoto,ocoandotoco: one such order in the account failed the whole orders response to deserialize, breaking the fill polling.Related Issue
N/A
Motivation and Context
Every unknown Tradier order id terminated the live algorithm, with no way to reconcile manual or broker-initiated activity.
Requires Documentation Change
No
How Has This Been Tested?
TradierBrokerageAditionalTestscover the accepted, declined, unsupported (polling and launch), partial-fill, order-class deserialization and verification-retry paths, the single-attempt order placement, and the own-order and mid-batch failure guards (59 tests pass).Running: a declined resting limit leaves the algorithm running; an accepted one emitsSubmittedand thenCanceledafter an API cancel. These runs predate dropping the decline warning and the order POST retries, which are covered by unit tests only.Types of changes
Checklist:
🤖 Generated with Claude Code