-
Notifications
You must be signed in to change notification settings - Fork 390
v4.5.91 - Fix live bar pagination + crypto-futures close_position #1164
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
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2644,6 +2644,8 @@ def modify_order(self, order, stop_price: Union[float, None] = None, limit_price | |
|
|
||
| def submit_order(self, order) -> Order: | ||
| """Conform an order for an asset to broker constraints and submit it.""" | ||
| if order is None: | ||
| raise ValueError("Cannot submit a null order") | ||
| self.resolve_option_order_intent(order) | ||
| self._conform_order(order) | ||
| return self._submit_order(order) | ||
|
|
@@ -2878,16 +2880,33 @@ def sell_all(self, strategy_name, cancel_open_orders=True, strategy=None, is_mul | |
| if position.quantity == 0: | ||
| continue | ||
|
|
||
| order = None | ||
| if strategy is not None: | ||
| if strategy.quote_asset != position.asset: | ||
| order = position.get_selling_order(quote_asset=strategy.quote_asset) | ||
| orders.append(order) | ||
| order = self._create_position_closing_order(position, quote_asset=strategy.quote_asset) | ||
| else: | ||
| order = position.get_selling_order() | ||
| order = self._create_position_closing_order(position) | ||
| if order is not None: | ||
| orders.append(order) | ||
|
|
||
| self.submit_orders(orders, is_multileg=is_multileg) | ||
|
|
||
| def _create_position_closing_order(self, position, quote_asset=None): | ||
| """Build a close order, including reduce-only crypto-futures fallback.""" | ||
| order = position.get_selling_order(quote_asset=quote_asset) | ||
| if order is not None or position.quantity == 0: | ||
| return order | ||
|
|
||
| order = Order( | ||
| position.strategy, | ||
| position.asset, | ||
| abs(position.quantity), | ||
| side=Order.OrderSide.SELL if position.quantity > 0 else Order.OrderSide.BUY, | ||
| quote=quote_asset, | ||
| ) | ||
| order.reduce_only = True | ||
| return order | ||
|
|
||
| def close_position(self, strategy_name: str, asset: Asset, fraction: float = 1.00): | ||
| """ | ||
| Close a position for a given strategy and asset by submitting a sell order. | ||
|
|
@@ -2907,6 +2926,10 @@ def close_position(self, strategy_name: str, asset: Asset, fraction: float = 1.0 | |
| The sell order submitted to close the position, or None if no open position exists | ||
| or the position quantity is zero. | ||
| """ | ||
| fraction_value = float(fraction) | ||
| if not 0 < fraction_value <= 1: | ||
| raise ValueError("fraction must be greater than 0 and no more than 1") | ||
|
|
||
| pos = self.get_tracked_position(strategy_name, asset) | ||
| if pos and pos.quantity != 0: | ||
| self.logger.info( | ||
|
|
@@ -2916,9 +2939,17 @@ def close_position(self, strategy_name: str, asset: Asset, fraction: float = 1.0 | |
| fraction, | ||
| pos.quantity, | ||
| ) | ||
| order = pos.get_selling_order(quote_asset=self.quote_assets and next(iter(self.quote_assets))) | ||
| quote_asset = next(iter(self.quote_assets), None) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🤖 get_repo_knowledge executed:
Length of output: 47820 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- changed hunk context ---'
sed -n '2615,2675p' lumibot/brokers/broker.py
sed -n '2860,2965p' lumibot/brokers/broker.py
printf '%s\n' '--- strategy quote asset registration ---'
sed -n '190,240p' lumibot/strategies/strategy.py
printf '%s\n' '--- quote_assets and close_position references ---'
rg -n -C 3 'quote_assets|close_position\(' lumibot/brokers lumibot/strategies | head -240
printf '%s\n' '--- broker subclasses and close-order consumers ---'
rg -n -C 4 'def _submit_order|def submit_order|quote_asset|is_crypto|crypto.?futures|reduce_only' lumibot/brokers | head -320Repository: Lumiwealth/lumibot Length of output: 43986 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- broker.py close_position exact region ---'
cat -n lumibot/brokers/broker.py | sed -n '2868,2960p'
printf '%s\n' '--- strategy.py exact quote registration ---'
cat -n lumibot/strategies/strategy.py | sed -n '205,230p'
printf '%s\n' '--- all quote_assets definitions and direct uses ---'
rg -n -C 5 'quote_assets' lumibot tests 2>/dev/null | head -300Repository: Lumiwealth/lumibot Length of output: 22425 🏁 Script executed: #!/bin/bash
set -eu
git status --short
git diff -- lumibot/brokers/broker.py lumibot/strategies/strategy.py | sed -n '1,240p'Repository: Lumiwealth/lumibot Length of output: 156 🌐 Web query:
💡 Result: In the context of the Lumibot trading framework, quote_assets and close_position are related components used for managing trading operations and portfolio valuation [1][2]. quote_assets: This refers to a collection of assets (typically a set) defined within a broker instance that represent the base currencies or cash equivalents used to value positions and measure portfolio performance (e.g., USDT, USD, USDC) [1][2][3]. The quote asset is the currency in which a strategy's portfolio value is denominated [1]. When a position is closed, the framework may use these defined quote assets to determine the currency in which the trade proceeds are settled [2]. close_position: This is a method available in both the strategy and broker classes used to exit an open trading position [1][2]. - Strategy Level: When calling self.close_position(asset) within a strategy, it triggers the corresponding broker's close_position method for that specific asset [1]. It supports closing a fraction of the position (default is 1.0, or 100%) [1][2]. - Broker Level: The broker implementation executes the logic to close the position [2]. For standard assets, this is typically achieved by submitting a market sell order [1][2]. For specific crypto futures brokers (such as Bitunix), the implementation may utilize specialized, high-performance API endpoints, such as a flash-close or reduce-only order, to exit the position immediately [1][4]. If no open position exists for the specified asset, the close_position method generally does not take any action [1][2]. Citations:
🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- position closing order implementation ---'
rg -n -C 8 'def get_selling_order|class Position' lumibot/entities/position.py lumibot/entities
printf '%s\n' '--- crypto-futures quote consumption ---'
rg -n -C 6 'order\.quote|quote\.symbol|quote_asset|CRYPTO_FUTURE|reduce_only' lumibot/brokers lumibot/entities/order.py | head -360
printf '%s\n' '--- close-position tests ---'
cat -n tests/test_strategy_close_position.py | sed -n '1,180p'Repository: Lumiwealth/lumibot Length of output: 39482 🏁 Script executed: #!/bin/bash
set -eu
cat -n lumibot/entities/position.py | sed -n '300,390p'
rg -n -C 5 'get_selling_order' lumibot testsRepository: Lumiwealth/lumibot Length of output: 7868 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- Position.get_selling_order body ---'
cat -n lumibot/entities/position.py | sed -n '182,235p'
printf '%s\n' '--- Order quote initialization ---'
cat -n lumibot/entities/order.py | sed -n '430,530p'
printf '%s\n' '--- base broker conformance and quote consumers ---'
rg -n -C 8 'def _conform_order|order\.quote|quote=order\.quote|quote_asset' lumibot/brokers/broker.py lumibot/brokers/bitunix.py lumibot/entities/order.pyRepository: Lumiwealth/lumibot Length of output: 23087 🏁 Script executed: #!/bin/bash
set -eu
cat -n lumibot/brokers/broker.py | sed -n '2045,2125p'
printf '%s\n' '--- crypto-future broker implementations ---'
rg -n -l 'CRYPTO_FUTURE|crypto_future' lumibot/brokersRepository: Lumiwealth/lumibot Length of output: 4145 Scope the close-order quote to
🤖 Prompt for AI Agents |
||
| order = self._create_position_closing_order(pos, quote_asset=quote_asset) | ||
| if order is None: | ||
| self.logger.warning( | ||
| "close_position(strategy=%s, asset=%s) could not build a close order", | ||
| strategy_name, | ||
| getattr(asset, "symbol", asset), | ||
| ) | ||
| return None | ||
| if fraction != 1.00: | ||
| order.quantity = order.quantity * fraction | ||
| order.quantity = order.quantity * fraction_value | ||
| order_id = getattr(order, "identifier", None) or getattr(order, "id", None) or getattr(order, "order_id", None) | ||
| self.logger.info( | ||
| "close_position(strategy=%s) submitting order %s qty=%s side=%s type=%s", | ||
|
|
||
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.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Reject null entries in
submit_orders.submit_orders([None])bypassessubmit_order()and reachesProjectX._submit_order(None)through the generic fallback. That method dereferencesorder.asset, causing a null-order failure. Add the guard beforeresolve_option_order_intent().Proposed fix
def submit_orders(self, orders, **kwargs) -> Union[Order, list[Order]]: """Submit orders""" resolved_orders = [] for order in orders: + if order is None: + raise ValueError("Cannot submit a null order") self.resolve_option_order_intent(order, additional_active_orders=resolved_orders) resolved_orders.append(order)📝 Committable suggestion
🤖 Prompt for AI Agents