-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
[TradingMode] support dsl calls #3323
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
Merged
Merged
Changes from all commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
e4df10f
[TradingMode] support dsl calls
GuillaumeDSM 5596e36
[Exchanges] add minimal dynamic symbol env producers
GuillaumeDSM bf773b1
[TradingModes] use async chan for sync execution
GuillaumeDSM 8cdc822
[Copy] init octobot_copy
GuillaumeDSM 511f7a2
[Copy] add rebalancing module
GuillaumeDSM 4edccd0
[Copy] init copiers
GuillaumeDSM a083995
[Copy] copy portfolio
GuillaumeDSM 557e834
[Copy] add copy only mode
GuillaumeDSM 9e7006a
[Copy] add orders copy
GuillaumeDSM 0265e91
[Copy] add HistoricalConfigurationRebalanceActionsPlanner
GuillaumeDSM a81a969
[Copy] refactor exchange interface
GuillaumeDSM 62f0dcf
[Copy] handle index content change
GuillaumeDSM b23e473
[CI] bump pants
GuillaumeDSM aa1affb
[Flow] init simulated trading
GuillaumeDSM 2617909
[Flow] add ohlcv TTL cache
GuillaumeDSM d9bcb68
[Flow] handle simulated trading
GuillaumeDSM 6a2a71c
[Node] fix unstable test
GuillaumeDSM dd55e32
Typing comments fixes
GuillaumeDSM 787b675
[Flow] Support real trading on copied account
GuillaumeDSM 7de1a20
[Flow] factorize grid test mocks
GuillaumeDSM 0083f87
[Flow] fix results and trades
GuillaumeDSM 1e7e479
[DSL] add loop_until
GuillaumeDSM 8200101
[AIEvaluator] use LLM service
GuillaumeDSM c482162
[BlockchainWallets] add proxy config
GuillaumeDSM 6217c09
[Flow] Skip condition reevaluation for wait keyword
GuillaumeDSM e6e6417
[Flow] use updaters
GuillaumeDSM 4dd07c9
[Copy] add orders sync grace period
GuillaumeDSM 481b346
[Flow] return error in workflow output
GuillaumeDSM 0d7acd0
[CI] include octobot_copy tests
GuillaumeDSM 83e6021
[Flow] handle iteration exceptions in task error
GuillaumeDSM f698f42
[BlockchainWallet] add generic blockchain proxy config fallback
GuillaumeDSM c5aa1de
[Trading] fix ohlcv updater cache
GuillaumeDSM cdcb7fc
[Copy] clarify swap log
GuillaumeDSM File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
37 changes: 37 additions & 0 deletions
37
packages/async_channel/async_channel/util/synchronization_util.py
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| # Drakkar-Software Async-Channel | ||
| # Copyright (c) Drakkar-Software, All rights reserved. | ||
| # | ||
| # This library is free software; you can redistribute it and/or | ||
| # modify it under the terms of the GNU Lesser General Public | ||
| # License as published by the Free Software Foundation; either | ||
| # version 3.0 of the License, or (at your option) any later version. | ||
| # | ||
| # This library is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| # Lesser General Public License for more details. | ||
| # | ||
| # You should have received a copy of the GNU Lesser General Public | ||
| # License along with this library. | ||
| """ | ||
| Define async_channel synchronization utilities | ||
| """ | ||
| import asyncio | ||
| import typing | ||
|
|
||
| if typing.TYPE_CHECKING: | ||
| import async_channel.consumer | ||
|
|
||
|
|
||
| async def trigger_and_bypass_consumers_queue( | ||
| consumers: list["async_channel.consumer.Consumer"], kwargs: dict | ||
| ): | ||
| """ | ||
| Triggers the consumers queue and bypasses the consumers callback. | ||
| Warning: this can cause concurrent async executions of the consumer callback | ||
| as the queue is bypassed. | ||
| """ | ||
| await asyncio.gather(*[ | ||
| consumer.callback(**kwargs) | ||
| for consumer in consumers | ||
| ]) |
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
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
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
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,15 +20,18 @@ | |
|
|
||
| import octobot_commons.dataclasses | ||
| import octobot_commons.dsl_interpreter.operator_parameter as operator_parameter | ||
| import octobot_commons.dsl_interpreter.parameters_util as parameters_util | ||
|
|
||
|
|
||
| class ReCallingOperatorResultKeys(str, enum.Enum): | ||
| WAITING_TIME = "waiting_time" | ||
| LAST_EXECUTION_TIME = "last_execution_time" | ||
| SCRIPT_OVERRIDE = "script_override" | ||
|
|
||
|
|
||
| @dataclasses.dataclass | ||
| class ReCallingOperatorResult(octobot_commons.dataclasses.MinimizableDataclass): | ||
| keyword: typing.Optional[str] = None | ||
| reset_to_id: typing.Optional[str] = None | ||
| last_execution_result: typing.Optional[dict] = None | ||
|
|
||
|
|
@@ -56,6 +59,24 @@ def get_next_call_time(self) -> typing.Optional[float]: | |
| return last_execution_time + waiting_time | ||
| return None | ||
|
|
||
| @staticmethod | ||
| def get_script_override(result: typing.Any) -> typing.Optional[str]: | ||
|
Contributor
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. 👍 |
||
| """ | ||
| Returns the script override from the last execution result. | ||
| """ | ||
| if not ReCallingOperatorResult.is_re_calling_operator_result(result): | ||
| return None | ||
| return result[ReCallingOperatorResult.__name__].get("last_execution_result", {}).get( | ||
| ReCallingOperatorResultKeys.SCRIPT_OVERRIDE.value | ||
| ) | ||
|
|
||
| @staticmethod | ||
| def get_keyword(result: typing.Any) -> typing.Optional[str]: | ||
| """ | ||
| Returns the keyword from the re-calling operator result. | ||
| """ | ||
| return result[ReCallingOperatorResult.__name__]["keyword"] | ||
|
|
||
|
|
||
| class ReCallableOperatorMixin: | ||
| """ | ||
|
|
@@ -93,23 +114,58 @@ def get_last_execution_result( | |
| ]).last_execution_result | ||
| return None | ||
|
|
||
| def build_re_callable_result( | ||
| def create_re_callable_result( # pylint: disable=too-many-arguments | ||
| self, | ||
| keyword: str, | ||
| reset_to_id: typing.Optional[str] = None, | ||
| waiting_time: typing.Optional[float] = None, | ||
| last_execution_time: typing.Optional[float] = None, | ||
| script_override: typing.Optional[str] = None, | ||
| **kwargs: typing.Any, | ||
| ) -> ReCallingOperatorResult: | ||
| """ | ||
| Builds a re-callable result from the given parameters. | ||
| """ | ||
| return ReCallingOperatorResult( | ||
| keyword=keyword, | ||
| reset_to_id=reset_to_id, | ||
| last_execution_result={ | ||
| ReCallingOperatorResultKeys.WAITING_TIME.value: waiting_time, | ||
| ReCallingOperatorResultKeys.LAST_EXECUTION_TIME.value: last_execution_time, | ||
| ReCallingOperatorResultKeys.SCRIPT_OVERRIDE.value: script_override, | ||
| **kwargs, | ||
| }, | ||
| ) | ||
|
|
||
| def create_re_callable_result_dict( # pylint: disable=too-many-arguments | ||
| self, | ||
| keyword: str, | ||
| reset_to_id: typing.Optional[str] = None, | ||
| waiting_time: typing.Optional[float] = None, | ||
| last_execution_time: typing.Optional[float] = None, | ||
| script_override: typing.Optional[str] = None, | ||
| **kwargs: typing.Any, | ||
| ) -> dict: | ||
| """ | ||
| Builds a dict formatted re-callable result from the given parameters. | ||
| """ | ||
| return { | ||
| ReCallingOperatorResult.__name__: ReCallingOperatorResult( | ||
| ReCallingOperatorResult.__name__: self.create_re_callable_result( | ||
| keyword=keyword, | ||
| reset_to_id=reset_to_id, | ||
| last_execution_result={ | ||
| ReCallingOperatorResultKeys.WAITING_TIME.value: waiting_time, | ||
| ReCallingOperatorResultKeys.LAST_EXECUTION_TIME.value: last_execution_time, | ||
| **kwargs, | ||
| }, | ||
| waiting_time=waiting_time, | ||
| last_execution_time=last_execution_time, | ||
| script_override=script_override, | ||
| **kwargs, | ||
| ).to_dict(include_default_values=False) | ||
| } | ||
|
|
||
| def re_create_script(self, param_by_name: dict[str, typing.Any]): | ||
| """ | ||
| Returns the re-created script from the given parameters. | ||
| """ | ||
| param_without_re_callable_operator_params = { | ||
| k: v for k, v in param_by_name.items() if k != self.LAST_EXECUTION_RESULT_KEY | ||
| } | ||
| params = parameters_util.resove_operator_params(self, param_without_re_callable_operator_params) | ||
| return f"{self.get_name()}({', '.join(params)})" # type: ignore | ||
Oops, something went wrong.
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.
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.
Why
while True?is it an asyncio task to be canceled?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.
it is, we want this task to log every 30s to inform that it's still in progress. it will be cancelled as soon as the wrapped task is done (it's a waiter)
Uh oh!
There was an error while loading. Please reload this page.
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.
Are we sure all the previous usage (if they exists) of this function will have the same behavior with this loop?
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.
I don't understand what you mean, this is just a local task defined in the
async def _waiter()function, there is no "previous usage" and nothing changes compared to before, the only thing is that the previous impl was missing a loop so the waiter would only log once, which was a mistake. The task is always cancelled when the context managerlogged_waiterexits, this didn't change