Skip to content

Commit 8c0786c

Browse files
committed
[TradingMode] support dsl calls
1 parent 44de8fe commit 8c0786c

31 files changed

Lines changed: 1652 additions & 152 deletions

File tree

packages/commons/octobot_commons/configuration/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
get_password_hash,
4747
)
4848
from octobot_commons.configuration.user_inputs import (
49+
USER_INPUT_TYPE_TO_PYTHON_TYPE,
50+
MAX_USER_INPUT_ORDER,
4951
UserInput,
5052
UserInputFactory,
5153
sanitize_user_input_name,
@@ -85,6 +87,8 @@
8587
"decrypt",
8688
"decrypt_element_if_possible",
8789
"get_password_hash",
90+
"USER_INPUT_TYPE_TO_PYTHON_TYPE",
91+
"MAX_USER_INPUT_ORDER",
8892
"UserInput",
8993
"UserInputFactory",
9094
"sanitize_user_input_name",

packages/commons/octobot_commons/configuration/user_inputs.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,23 @@
2020
import octobot_commons.dict_util as dict_util
2121

2222

23+
USER_INPUT_TYPE_TO_PYTHON_TYPE = {
24+
enums.UserInputTypes.INT.value: int,
25+
enums.UserInputTypes.FLOAT.value: float,
26+
enums.UserInputTypes.BOOLEAN.value: bool,
27+
enums.UserInputTypes.TEXT.value: str,
28+
enums.UserInputTypes.OBJECT.value: dict,
29+
enums.UserInputTypes.OBJECT_ARRAY.value: list,
30+
enums.UserInputTypes.STRING_ARRAY.value: list,
31+
enums.UserInputTypes.OPTIONS.value: str,
32+
enums.UserInputTypes.MULTIPLE_OPTIONS.value: list,
33+
}
34+
35+
36+
MAX_USER_INPUT_ORDER = 9999
37+
38+
2339
class UserInput:
24-
MAX_ORDER = 9999
2540

2641
def __init__(
2742
self,

packages/commons/octobot_commons/dsl_interpreter/interpreter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ def _visit_node(self, node: typing.Optional[ast.AST]) -> typing.Union[
361361
)
362362

363363
raise octobot_commons.errors.UnsupportedOperatorError(
364-
f"Unsupported AST node type: {type(node).__name__}"
364+
f"Unsupported AST node type: {type(node).__name__}. Expression: {self._parsed_expression}"
365365
)
366366

367367
def _get_name_from_node(self, node: ast.AST) -> str:

packages/commons/octobot_commons/dsl_interpreter/operators/re_callable_operator_mixin.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,26 @@ def get_last_execution_result(
9393
]).last_execution_result
9494
return None
9595

96-
def build_re_callable_result(
96+
def create_re_callable_result(
97+
self,
98+
reset_to_id: typing.Optional[str] = None,
99+
waiting_time: typing.Optional[float] = None,
100+
last_execution_time: typing.Optional[float] = None,
101+
**kwargs: typing.Any,
102+
) -> ReCallingOperatorResult:
103+
"""
104+
Builds a re-callable result from the given parameters.
105+
"""
106+
return ReCallingOperatorResult(
107+
reset_to_id=reset_to_id,
108+
last_execution_result={
109+
ReCallingOperatorResultKeys.WAITING_TIME.value: waiting_time,
110+
ReCallingOperatorResultKeys.LAST_EXECUTION_TIME.value: last_execution_time,
111+
**kwargs,
112+
},
113+
)
114+
115+
def create_re_callable_result_dict(
97116
self,
98117
reset_to_id: typing.Optional[str] = None,
99118
waiting_time: typing.Optional[float] = None,
@@ -104,12 +123,10 @@ def build_re_callable_result(
104123
Builds a dict formatted re-callable result from the given parameters.
105124
"""
106125
return {
107-
ReCallingOperatorResult.__name__: ReCallingOperatorResult(
126+
ReCallingOperatorResult.__name__: self.create_re_callable_result(
108127
reset_to_id=reset_to_id,
109-
last_execution_result={
110-
ReCallingOperatorResultKeys.WAITING_TIME.value: waiting_time,
111-
ReCallingOperatorResultKeys.LAST_EXECUTION_TIME.value: last_execution_time,
112-
**kwargs,
113-
},
128+
waiting_time=waiting_time,
129+
last_execution_time=last_execution_time,
130+
**kwargs,
114131
).to_dict(include_default_values=False)
115132
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Drakkar-Software OctoBot-Commons
2+
# Copyright (c) Drakkar-Software, All rights reserved.
3+
#
4+
# This library is free software; you can redistribute it and/or
5+
# modify it under the terms of the GNU Lesser General Public
6+
# License as published by the Free Software Foundation; either
7+
# version 3.0 of the License, or (at your option) any later version.
8+
#
9+
# This library is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
# Lesser General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU Lesser General Public
15+
# License along with this library.
16+
import re
17+
18+
19+
def camel_to_snake(name: str) -> str:
20+
"""Convert CamelCase to snake_case (e.g. for DSL operator names)."""
21+
return re.sub(r"(?<!^)(?=[A-Z])", "_", name).lower()

packages/commons/tests/dsl_interpreter/operators/test_re_callable_operator_mixin.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,9 @@ def test_get_last_execution_result_with_reset_to_id_format(self):
148148
})
149149
assert result == inner
150150

151-
def test_build_re_callable_result(self):
151+
def test_create_re_callable_result_dict(self):
152152
operator = _TestReCallableOperator()
153-
result = operator.build_re_callable_result(
153+
result = operator.create_re_callable_result_dict(
154154
last_execution_time=1000.0,
155155
waiting_time=5.0,
156156
)
@@ -163,9 +163,9 @@ def test_build_re_callable_result(self):
163163
re_callable_operator_mixin.ReCallingOperatorResultKeys.WAITING_TIME.value
164164
] == 5.0
165165

166-
def test_build_re_callable_result_with_reset_to_id(self):
166+
def test_create_re_callable_result_dict_with_reset_to_id(self):
167167
operator = _TestReCallableOperator()
168-
result = operator.build_re_callable_result(
168+
result = operator.create_re_callable_result_dict(
169169
reset_to_id="target_123",
170170
last_execution_time=1000.0,
171171
waiting_time=5.0,
@@ -174,9 +174,9 @@ def test_build_re_callable_result_with_reset_to_id(self):
174174
assert inner["reset_to_id"] == "target_123"
175175
assert "last_execution_result" in inner
176176

177-
def test_build_re_callable_result_with_extra_kwargs(self):
177+
def test_create_re_callable_result_dict_with_extra_kwargs(self):
178178
operator = _TestReCallableOperator()
179-
result = operator.build_re_callable_result(
179+
result = operator.create_re_callable_result_dict(
180180
last_execution_time=1000.0,
181181
waiting_time=5.0,
182182
extra_field=42,
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Drakkar-Software OctoBot-Commons
2+
# Copyright (c) Drakkar-Software, All rights reserved.
3+
#
4+
# This library is free software; you can redistribute it and/or
5+
# modify it under the terms of the GNU Lesser General Public
6+
# License as published by the Free Software Foundation; either
7+
# version 3.0 of the License, or (at your option) any later version.
8+
#
9+
# This library is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
# Lesser General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU Lesser General Public
15+
# License along with this library.
16+
import octobot_commons.str_util as str_util
17+
18+
19+
def test_camel_to_snake_empty():
20+
assert str_util.camel_to_snake("") == ""
21+
22+
23+
def test_camel_to_snake_single_letter():
24+
assert str_util.camel_to_snake("A") == "a"
25+
26+
27+
def test_camel_to_snake_trading_mode_style():
28+
assert str_util.camel_to_snake("GridTradingMode") == "grid_trading_mode"
29+
assert str_util.camel_to_snake("IndexTradingMode") == "index_trading_mode"
30+
assert str_util.camel_to_snake("AbstractTradingMode") == "abstract_trading_mode"
31+
32+
33+
def test_camel_to_snake_already_lowercase():
34+
assert str_util.camel_to_snake("already_snake") == "already_snake"
35+
36+
37+
def test_camel_to_snake_single_word_upper():
38+
assert str_util.camel_to_snake("Trading") == "trading"

packages/flow/octobot_flow/entities/automations/additional_actions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
@dataclasses.dataclass
6-
class AdditionalActions(octobot_commons.dataclasses.FlexibleDataclass):
6+
class AdditionalActions(octobot_commons.dataclasses.MinimizableDataclass):
77
# todo implement this when necessary
88
check_min_portfolio: bool = False
99
optimize_portfolio: bool = False

packages/flow/octobot_flow/jobs/automation_job.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -207,15 +207,22 @@ async def _init_all_required_exchange_data(
207207
exchange_account_job = exchange_account_job_import.ExchangeAccountJob(
208208
self.automation_state, self.fetched_actions
209209
)
210-
symbol = set(
211-
exchange_account_job.get_all_actions_symbols()
212-
+ octobot_flow.logic.dsl.get_actions_symbol_dependencies(to_execute_actions)
210+
minimal_profile_data = octobot_flow.logic.configuration.create_profile_data(
211+
self.automation_state.exchange_account_details,
212+
self.automation_state.automation.metadata.automation_id,
213+
set()
214+
)
215+
symbols = set(
216+
exchange_account_job.get_all_actions_symbols(minimal_profile_data)
217+
+ octobot_flow.logic.dsl.get_actions_symbol_dependencies(
218+
to_execute_actions, minimal_profile_data
219+
)
213220
)
214221
async with exchange_account_job.account_exchange_context(
215222
octobot_flow.logic.configuration.create_profile_data(
216223
self.automation_state.exchange_account_details,
217224
self.automation_state.automation.metadata.automation_id,
218-
symbol
225+
symbols
219226
)
220227
):
221228
await exchange_account_job.update_public_data()

packages/flow/octobot_flow/jobs/automation_runner_job.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,9 @@ async def run(self):
6969
async def _execute_actions(self) -> tuple[list[octobot_flow.enums.ChangedElements], float]:
7070
actions_executor = octobot_flow.logic.actions.ActionsExecutor(
7171
self._maybe_community_repository, self._exchange_manager,
72+
self.profile_data_provider.get_profile_data(),
7273
self.automation_state.automation, self._to_execute_actions,
73-
self._as_reference_account
74+
self._as_reference_account,
7475
)
7576
await actions_executor.execute()
7677
return actions_executor.changed_elements, (
@@ -113,11 +114,16 @@ def init_strategy_exchange_data(self, exchange_data: exchange_data_import.Exchan
113114
exchange_data.orders_details.open_orders = exchange_account_elements.orders.open_orders
114115

115116
def _get_profile_data(self) -> commons_profiles.ProfileData:
117+
minimal_profile_data = octobot_flow.logic.configuration.create_profile_data(
118+
self.automation_state.exchange_account_details,
119+
self.automation_state.automation.metadata.automation_id,
120+
set()
121+
)
116122
return octobot_flow.logic.configuration.create_profile_data(
117123
self.automation_state.exchange_account_details,
118124
self.automation_state.automation.metadata.automation_id,
119125
set(octobot_flow.logic.dsl.get_actions_symbol_dependencies(
120-
self._to_execute_actions
126+
self._to_execute_actions, minimal_profile_data
121127
))
122128
)
123129

0 commit comments

Comments
 (0)