1
1
from enum import Enum
2
2
from typing import Any , Dict , Optional , Union , List
3
3
4
- from hummingbot .core .data_type .common import PositionMode
5
4
from pydantic import BaseModel , Field
6
5
from decimal import Decimal
7
6
from hummingbot .strategy_v2 .controllers import MarketMakingControllerConfigBase , ControllerConfigBase , DirectionalTradingControllerConfigBase
23
22
24
23
class StrategyParameter (BaseModel ):
25
24
name : str
25
+ group : str
26
+ is_advanced : bool = False
26
27
type : str
27
28
prompt : str
28
29
default : Optional [Any ]
@@ -35,24 +36,47 @@ class StrategyParameter(BaseModel):
35
36
is_timespan : bool = False
36
37
is_connector : bool = False
37
38
is_trading_pair : bool = False
39
+ is_integer : bool = False
38
40
display_type : str = Field (default = "input" , description = "Can be 'input', 'slider', 'dropdown', 'toggle', or 'date'" )
39
41
40
42
43
+ def is_advanced_parameter (name : str ) -> bool :
44
+ advanced_keywords = [
45
+ "activation_bounds" , "triple_barrier" , "leverage" , "dca" , "macd" , "natr" ,
46
+ "multiplier" , "imbalance" , "executor" , "perp" , "arbitrage"
47
+ ]
48
+
49
+ simple_keywords = [
50
+ "controller_name" , "candles" , "interval" , "stop_loss" , "take_profit" ,
51
+ "buy" , "sell" , "position_size" , "time_limit" , "spot"
52
+ ]
53
+
54
+ name_lower = name .lower ()
55
+
56
+ if any (keyword in name_lower for keyword in advanced_keywords ):
57
+ return True
58
+
59
+ if any (keyword in name_lower for keyword in simple_keywords ):
60
+ return False
61
+
62
+ return True
63
+
41
64
def convert_to_strategy_parameter (name : str , field : ModelField ) -> StrategyParameter :
42
65
param = StrategyParameter (
43
66
name = name ,
44
67
type = str (field .type_ .__name__ ),
45
68
prompt = field .description if hasattr (field , 'description' ) else "" ,
46
69
default = field .default ,
47
70
required = field .required or field .default is not None ,
71
+ is_advanced = is_advanced_parameter (name ),
48
72
)
49
73
50
74
# structure of field
51
- print ( field )
52
- if hasattr ( field , ' client_data' ) :
53
- client_data = field . client_data
54
- if param . prompt == "" :
55
- param .prompt = client_data . prompt () if callable ( client_data . prompt ) else client_data . prompt
75
+ client_data = field . field_info . extra . get ( 'client_data' )
76
+ if client_data is not None and param . prompt == "" :
77
+ desc = client_data . prompt ( None ) if callable ( client_data . prompt ) else client_data . prompt
78
+ if desc is not None :
79
+ param .prompt = desc
56
80
if not param .required :
57
81
param .required = client_data .prompt_on_new if hasattr (client_data , 'prompt_on_new' ) else param .required
58
82
param .display_type = "input"
@@ -69,6 +93,9 @@ def convert_to_strategy_parameter(name: str, field: ModelField) -> StrategyParam
69
93
elif param .type == "bool" :
70
94
param .display_type = "toggle"
71
95
96
+ # Determine the group for the parameter
97
+ param .group = determine_parameter_group (name )
98
+
72
99
# Check for specific use cases
73
100
if "connector" in name .lower ():
74
101
param .is_connector = True
@@ -84,6 +111,12 @@ def convert_to_strategy_parameter(name: str, field: ModelField) -> StrategyParam
84
111
param .min_value = Decimal (0 )
85
112
if any (word in name .lower () for word in ["time" , "interval" , "duration" ]):
86
113
param .is_timespan = True
114
+ param .min_value = 0
115
+ if param .type == "int" :
116
+ param .is_integer = True
117
+ if any (word in name .lower () for word in ["executors" , "workers" ]):
118
+ param .display_type = "slider"
119
+ param .min_value = 1
87
120
try :
88
121
if issubclass (field .type_ , Enum ):
89
122
param .valid_values = [item .value for item in field .type_ ]
@@ -92,6 +125,28 @@ def convert_to_strategy_parameter(name: str, field: ModelField) -> StrategyParam
92
125
pass
93
126
return param
94
127
128
+ def determine_parameter_group (name : str ) -> str :
129
+ if any (word in name .lower () for word in ["controller_name" , "candles" , "interval" ]):
130
+ return "General Settings"
131
+ elif any (word in name .lower () for word in ["stop_loss" , "trailing_stop" , "take_profit" , "activation_bounds" , "leverage" , "triple_barrier" ]):
132
+ return "Risk Management"
133
+ elif "buy" in name .lower ():
134
+ return "Buy Order Settings"
135
+ elif "sell" in name .lower ():
136
+ return "Sell Order Settings"
137
+ elif "dca" in name .lower ():
138
+ return "DCA Settings"
139
+ elif any (word in name .lower () for word in ["bb" , "macd" , "natr" , "length" , "multiplier" ]):
140
+ return "Indicator Settings"
141
+ elif any (word in name .lower () for word in ["profitability" , "position_size" ]):
142
+ return "Profitability Settings"
143
+ elif any (word in name .lower () for word in ["time_limit" , "executor" , "imbalance" ]):
144
+ return "Execution Settings"
145
+ elif any (word in name .lower () for word in ["spot" , "perp" ]):
146
+ return "Arbitrage Settings"
147
+ else :
148
+ return "Other"
149
+
95
150
96
151
@functools .lru_cache (maxsize = 1 )
97
152
def get_all_strategy_maps () -> Dict [str , Dict [str , StrategyParameter ]]:
@@ -129,4 +184,4 @@ def get_all_strategy_maps() -> Dict[str, Dict[str, StrategyParameter]]:
129
184
print (f"Unexpected error processing { module_path } : { e } " )
130
185
import traceback
131
186
traceback .print_exc ()
132
- return strategy_maps
187
+ return strategy_maps
0 commit comments