11from enum import Enum
22from typing import Any , Dict , Optional , Union , List
33
4- from hummingbot .core .data_type .common import PositionMode
54from pydantic import BaseModel , Field
65from decimal import Decimal
76from hummingbot .strategy_v2 .controllers import MarketMakingControllerConfigBase , ControllerConfigBase , DirectionalTradingControllerConfigBase
2322
2423class StrategyParameter (BaseModel ):
2524 name : str
25+ group : str
26+ is_advanced : bool = False
2627 type : str
2728 prompt : str
2829 default : Optional [Any ]
@@ -35,24 +36,47 @@ class StrategyParameter(BaseModel):
3536 is_timespan : bool = False
3637 is_connector : bool = False
3738 is_trading_pair : bool = False
39+ is_integer : bool = False
3840 display_type : str = Field (default = "input" , description = "Can be 'input', 'slider', 'dropdown', 'toggle', or 'date'" )
3941
4042
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+
4164def convert_to_strategy_parameter (name : str , field : ModelField ) -> StrategyParameter :
4265 param = StrategyParameter (
4366 name = name ,
4467 type = str (field .type_ .__name__ ),
4568 prompt = field .description if hasattr (field , 'description' ) else "" ,
4669 default = field .default ,
4770 required = field .required or field .default is not None ,
71+ is_advanced = is_advanced_parameter (name ),
4872 )
4973
5074 # 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
5680 if not param .required :
5781 param .required = client_data .prompt_on_new if hasattr (client_data , 'prompt_on_new' ) else param .required
5882 param .display_type = "input"
@@ -69,6 +93,9 @@ def convert_to_strategy_parameter(name: str, field: ModelField) -> StrategyParam
6993 elif param .type == "bool" :
7094 param .display_type = "toggle"
7195
96+ # Determine the group for the parameter
97+ param .group = determine_parameter_group (name )
98+
7299 # Check for specific use cases
73100 if "connector" in name .lower ():
74101 param .is_connector = True
@@ -84,6 +111,12 @@ def convert_to_strategy_parameter(name: str, field: ModelField) -> StrategyParam
84111 param .min_value = Decimal (0 )
85112 if any (word in name .lower () for word in ["time" , "interval" , "duration" ]):
86113 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
87120 try :
88121 if issubclass (field .type_ , Enum ):
89122 param .valid_values = [item .value for item in field .type_ ]
@@ -92,6 +125,28 @@ def convert_to_strategy_parameter(name: str, field: ModelField) -> StrategyParam
92125 pass
93126 return param
94127
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+
95150
96151@functools .lru_cache (maxsize = 1 )
97152def get_all_strategy_maps () -> Dict [str , Dict [str , StrategyParameter ]]:
@@ -129,4 +184,4 @@ def get_all_strategy_maps() -> Dict[str, Dict[str, StrategyParameter]]:
129184 print (f"Unexpected error processing { module_path } : { e } " )
130185 import traceback
131186 traceback .print_exc ()
132- return strategy_maps
187+ return strategy_maps
0 commit comments