-
Notifications
You must be signed in to change notification settings - Fork 192
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
Order Management Overhaul #704
Conversation
… orders did not work in all contexts and brokers. There are also several confusing and deprecated features being utilized and all of these have been modified across all brokers so that the behavior is consistent going forward. Change highlights: - order.type has been replaced with order.order_type to match (most) broker's terminology and to prevent shadowing with Python's built-in 'type'. - order.order_type no longer accepts "oco", "oto", or "bracket". These have been consolidated into the order.order_class parameter for clarity. - order.child_orders is now populated automatically for all advanced order types at order creation time. Previously, each broker object was handling this themselves differently and it led to divergent and inconsistent behavior across brokers (including BackTestingBroker). - stop_limit and trailing_stop are now allowed within OCO/OTO/Bracket children. Previously these settings were ignored for any non-Simple order class. - Documentation changes to clarify how these options should be used going forward. - Backwards compatibility maintained with numerous checks and warnings are now issued to inform the user if their current methodology needs changing for the future. - Removed BackTestingBroker __get_attribute() silliness. Seriously silly ... seriously.
Important Required App Permission UpdateNoise Reduction ImprovementsThis update requests write permissions for Commit Statuses in order to send updates directly to your PRs without adding comments that spam notifications. Visit our changelog to learn more. Click here to accept the updated permissions To accept the updated permissions, sufficient privileges are required |
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.
Review by Korbit AI
Korbit automatically attempts to detect when you fix issues in new commits.
Category | Issue | Fix Detected |
---|---|---|
Incorrect Price Reference in Take Profit Orders ▹ view | ✅ | |
Incorrect Enum Reference for Order Classes ▹ view | ✅ | |
Invalid Portfolio Weight Distribution on Zero Total Value ▹ view |
Files scanned
File Path | Reviewed |
---|---|
lumibot/example_strategies/stock_bracket.py | ✅ |
lumibot/example_strategies/stock_oco.py | ✅ |
lumibot/entities/asset.py | ✅ |
lumibot/components/drift_rebalancer_logic.py | ✅ |
lumibot/brokers/alpaca.py | ✅ |
lumibot/brokers/ccxt.py | ✅ |
lumibot/brokers/interactive_brokers_rest.py | ✅ |
lumibot/brokers/broker.py | ✅ |
lumibot/backtesting/backtesting_broker.py | ✅ |
lumibot/brokers/tradier.py | ✅ |
lumibot/brokers/interactive_brokers.py | ✅ |
lumibot/entities/order.py | ✅ |
Explore our documentation to understand the languages and file types we support and the files we ignore.
Need a new review? Comment
/korbit-review
on this PR and I'll review your latest changes.Korbit Guide: Usage and Customization
Interacting with Korbit
- You can manually ask Korbit to review your PR using the
/korbit-review
command in a comment at the root of your PR.- You can ask Korbit to generate a new PR description using the
/korbit-generate-pr-description
command in any comment on your PR.- Too many Korbit comments? I can resolve all my comment threads if you use the
/korbit-resolve
command in any comment on your PR.- Chat with Korbit on issues we post by tagging @korbit-ai in your reply.
- Help train Korbit to improve your reviews by giving a 👍 or 👎 on the comments Korbit posts.
Customizing Korbit
- Check out our docs on how you can make Korbit work best for you and your team.
- Customize Korbit for your organization through the Korbit Console.
Feedback and Support
lumibot/brokers/alpaca.py
Outdated
if isinstance(order.limit_price, Decimal) | ||
else order.limit_price, |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
lumibot/brokers/alpaca.py
Outdated
elif order.order_class in [Order.OrderType.BRACKET, Order.OrderType.OTO]: | ||
alpaca_type = Order.OrderType.MARKET |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
total_value = self.df["current_value"].sum() | ||
self.df["current_weight"] = self.df["current_value"] / total_value | ||
self.df["current_weight"] = self.df["current_value"] / total_value if total_value > 0 else Decimal(0) |
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.
Invalid Portfolio Weight Distribution on Zero Total Value 
Tell me more
What is the issue?
The handling of zero total_value creates inconsistent portfolio weights. When total_value is zero, all current_weights are set to 0, which means the sum of portfolio weights will be 0 instead of 1.
Why this matters
This can lead to incorrect drift calculations and rebalancing decisions. In a valid portfolio, weights should always sum to 1 (or -1 for short positions), even when total_value is zero.
Suggested change ∙ Feature Preview
A better approach would be to use target weights when total_value is zero:
total_value = self.df["current_value"].sum()
self.df["current_weight"] = (
self.df["current_value"] / total_value if total_value > 0
else self.df["target_weight"]
)
💬 Chat with Korbit by mentioning @korbit-ai.
…pdate that turned off Cash position reporting because AI helpers were getting confused.
@@ -355,9 +360,15 @@ def _parse_broker_order(self, response, strategy_name, strategy_object=None): | |||
), | |||
Decimal(response.qty), | |||
response.side, | |||
limit_price=response.limit_price, | |||
limit_price=limit_price, # order.py always converts to 'float'. Crypto issue? |
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.
yeah i would have assumed this was an issue. maybe it is and we don't know cause yahoo is down. i can test with alpaca crypto
i dont know why the test doesnt work as before. previous method retured a value, but now its returning a series and i had to extract the value. maybe pandas changed
… parent orders that are not technically submitted as a separate order. This is primarily for BackTesting as Tradier and other brokers do return it as an actual order.
…oco_stop_limit_deconflict # Conflicts: # tests/test_get_historical_prices.py
… valid strike instead of using current_asset_price.
Advanced order handling of OCO/OTO/Bracket orders did not work in all contexts and brokers. There are also several confusing and deprecated features being utilized and all of these have been modified across all brokers so that the behavior is consistent going forward.
Change highlights:
order.type
has been replaced withorder.order_type
to match (most) broker's terminology and to prevent shadowing with Python's built-intype
.order.order_type
no longer accepts "oco", "oto", or "bracket". These have been consolidated into theorder.order_class
parameter for clarity.order.child_orders
is now populated automatically for all advanced order types at order creation time. Previously, each broker object was handling this themselves differently and it led to divergent and inconsistent behavior across brokers (including BackTestingBroker).stop_limit
andtrailing_stop
are now allowed within OCO/OTO/Bracket children. Previously these settings were ignored for any non-Simple order class.__get_attribute()
silliness. Seriously silly ... seriously.Why was this change made?
Tradier and BackTesting were not handling OCO orders in the same way. Each was making different assumptions that led to being unable for a single strategy to run using both. As part of trying to tease all of this out I kept coming upon more stumbling blocks and eventually had to just rip all of the order handling apart so I could put it back together in a way that will make sense for most brokers. The previous implementation was very much tied to IBKR specific ways of doing things that don't apply 1-to-1 with the more modern brokers.
How do make sense of all of this
strategy.create_order()
. The documenation has been updated here to explain what the expected behavior is supposed to be.Order.__init__()
. It will show how backwards compatibility is maintained.Order._set_order_class_children
. This should make intuitive sense based upon how OCO/OTO/Bracket orders work. Any assumptions that should be challenged will most likely come from looking at this code. This code will also lead you nicely down the rabbit hole of looking at the mess in all of the other Brokers.Testing
Description by Korbit AI
What change is being made?
Refactor and enhance order management system for improved handling of complex orders in the Lumibot backtesting framework and associated broker implementations.
Why are these changes being made?
These changes address the need for a more comprehensive and flexible order management system within Lumibot, allowing for better support of advanced order types like OCO, Bracket, and OTO orders. The refactoring simplifies code and resolves existing limitations around order submission, modification, and execution logic, aligning closely with broker-specific requirements and improving backtesting accuracy for strategies that utilize complex orders. Additionally, the update standardizes the handling of order types and classes across different components, which was previously inconsistent and led to potential errors. This provides a more reliable foundation for both testing and live trading environments.