From 3c50e5ebe6129e9d719c7acc3960a1a5fecaaf55 Mon Sep 17 00:00:00 2001 From: Yusuf Taiwo Hassan Date: Tue, 12 Nov 2024 07:19:25 +0100 Subject: [PATCH 1/4] Added pretty names --- routers/strategies_models.py | 91 +++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 21 deletions(-) diff --git a/routers/strategies_models.py b/routers/strategies_models.py index eafac0e..ecf31b6 100644 --- a/routers/strategies_models.py +++ b/routers/strategies_models.py @@ -1,6 +1,7 @@ from enum import Enum from typing import Any, Dict, Optional, Union, List +from hummingbot.core.data_type.common import PositionMode from pydantic import BaseModel, Field from decimal import Decimal from hummingbot.strategy_v2.controllers import MarketMakingControllerConfigBase, ControllerConfigBase, DirectionalTradingControllerConfigBase @@ -24,6 +25,8 @@ class StrategyParameter(BaseModel): name: str group: str is_advanced: bool = False + pretty_name: str + description: str type: str prompt: str default: Optional[Any] @@ -36,7 +39,6 @@ class StrategyParameter(BaseModel): is_timespan: bool = False is_connector: bool = False is_trading_pair: bool = False - is_integer: bool = False display_type: str = Field(default="input", description="Can be 'input', 'slider', 'dropdown', 'toggle', or 'date'") @@ -61,23 +63,81 @@ def is_advanced_parameter(name: str) -> bool: return True +def get_strategy_display_info() -> Dict[str, Dict[str, str]]: + """ + Returns user-friendly names and descriptions for each strategy + """ + return { + # Directional Trading Strategies + "bollinger_v1": { + "pretty_name": "Bollinger Bands Strategy", + "description": "Buys when price is low and sells when price is high based on Bollinger Bands." + }, + "dman_v3": { + "pretty_name": "Smart DCA Strategy", + "description": "Automatically adjusts buy/sell levels based on market conditions with multiple take-profit targets." + }, + "macd_bb_v1": { + "pretty_name": "MACD + Bollinger Strategy", + "description": "Uses two popular indicators to find better entry and exit points for trades." + }, + "supertrend_v1": { + "pretty_name": "SuperTrend Strategy", + "description": "Follows market trends to find good times to buy and sell." + }, + + # Market Making Strategies + "dman_maker_v2": { + "pretty_name": "Smart Market Maker", + "description": "Places buy and sell orders that automatically adjust to market conditions." + }, + "pmm_dynamic": { + "pretty_name": "Dynamic Market Maker", + "description": "Places orders with spreads that adapt to market volatility." + }, + "pmm_simple": { + "pretty_name": "Simple Market Maker", + "description": "Places basic buy and sell orders with fixed spreads." + }, + + # Generic Strategies + "spot_perp_arbitrage": { + "pretty_name": "Spot-Futures Arbitrage", + "description": "Profits from price differences between spot and futures markets." + }, + "xemm_multiple_levels": { + "pretty_name": "Multi-Exchange Market Maker", + "description": "Places orders across different exchanges to capture price differences." + } + } + def convert_to_strategy_parameter(name: str, field: ModelField) -> StrategyParameter: param = StrategyParameter( - name=snake_case_to_real_name(name), - group=determine_parameter_group(name), + name=name, type=str(field.type_.__name__), prompt=field.description if hasattr(field, 'description') else "", default=field.default, required=field.required or field.default is not None, is_advanced=is_advanced_parameter(name), + group=determine_parameter_group(name), + pretty_name=name.replace('_', ' ').title(), + description="", ) - # structure of field - client_data = field.field_info.extra.get('client_data') - if client_data is not None and param.prompt == "": - desc = client_data.prompt(None) if callable(client_data.prompt) else client_data.prompt - if desc is not None: - param.prompt = desc + # Get strategy display info + strategy_info = get_strategy_display_info() + + # Try to find matching strategy info + for strategy_name, info in strategy_info.items(): + if strategy_name in name.lower(): + param.pretty_name = info["pretty_name"] + param.description = info["description"] + break + + if hasattr(field, 'client_data'): + client_data = field.client_data + if param.prompt == "": + param.prompt = client_data.prompt() if callable(client_data.prompt) else client_data.prompt if not param.required: param.required = client_data.prompt_on_new if hasattr(client_data, 'prompt_on_new') else param.required param.display_type = "input" @@ -93,8 +153,7 @@ def convert_to_strategy_parameter(name: str, field: ModelField) -> StrategyParam param.display_type = "slider" elif param.type == "bool": param.display_type = "toggle" - - # Check for specific use cases + if "connector" in name.lower(): param.is_connector = True if "trading_pair" in name.lower(): @@ -109,12 +168,6 @@ def convert_to_strategy_parameter(name: str, field: ModelField) -> StrategyParam param.min_value = Decimal(0) if any(word in name.lower() for word in ["time", "interval", "duration"]): param.is_timespan = True - param.min_value = 0 - if param.type == "int": - param.is_integer = True - if any(word in name.lower() for word in ["executors", "workers"]): - param.display_type = "slider" - param.min_value = 1 try: if issubclass(field.type_, Enum): param.valid_values = [item.value for item in field.type_] @@ -146,10 +199,6 @@ def determine_parameter_group(name: str) -> str: return "Other" -def snake_case_to_real_name(snake_case: str) -> str: - return " ".join([word.capitalize() for word in snake_case.split("_")]) - - @functools.lru_cache(maxsize=1) def get_all_strategy_maps() -> Dict[str, Dict[str, StrategyParameter]]: strategy_maps = {} From 1ffb60bb7c2e185bd80ce10f9fb9df7a7fcf5227 Mon Sep 17 00:00:00 2001 From: Yusuf Taiwo Hassan Date: Tue, 12 Nov 2024 07:24:26 +0100 Subject: [PATCH 2/4] Fix --- routers/strategies_models.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/routers/strategies_models.py b/routers/strategies_models.py index ecf31b6..e454552 100644 --- a/routers/strategies_models.py +++ b/routers/strategies_models.py @@ -1,7 +1,6 @@ from enum import Enum from typing import Any, Dict, Optional, Union, List -from hummingbot.core.data_type.common import PositionMode from pydantic import BaseModel, Field from decimal import Decimal from hummingbot.strategy_v2.controllers import MarketMakingControllerConfigBase, ControllerConfigBase, DirectionalTradingControllerConfigBase @@ -134,10 +133,12 @@ def convert_to_strategy_parameter(name: str, field: ModelField) -> StrategyParam param.description = info["description"] break - if hasattr(field, 'client_data'): - client_data = field.client_data - if param.prompt == "": - param.prompt = client_data.prompt() if callable(client_data.prompt) else client_data.prompt + # structure of field + client_data = field.field_info.extra.get('client_data') + if client_data is not None and param.prompt == "": + desc = client_data.prompt(None) if callable(client_data.prompt) else client_data.prompt + if desc is not None: + param.prompt = desc if not param.required: param.required = client_data.prompt_on_new if hasattr(client_data, 'prompt_on_new') else param.required param.display_type = "input" From 4f17f2004796a03106d448fb31ae1298579d33d1 Mon Sep 17 00:00:00 2001 From: Yusuf Taiwo Hassan Date: Tue, 12 Nov 2024 07:26:42 +0100 Subject: [PATCH 3/4] fix --- routers/strategies_models.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/routers/strategies_models.py b/routers/strategies_models.py index e454552..172ad87 100644 --- a/routers/strategies_models.py +++ b/routers/strategies_models.py @@ -169,6 +169,12 @@ def convert_to_strategy_parameter(name: str, field: ModelField) -> StrategyParam param.min_value = Decimal(0) if any(word in name.lower() for word in ["time", "interval", "duration"]): param.is_timespan = True + param.min_value = 0 + if param.type == "int": + param.is_integer = True + if any(word in name.lower() for word in ["executors", "workers"]): + param.display_type = "slider" + param.min_value = 1 try: if issubclass(field.type_, Enum): param.valid_values = [item.value for item in field.type_] From d733b2c763f9d13590d187c8f1b769ee145ddaee Mon Sep 17 00:00:00 2001 From: Yusuf Taiwo Hassan Date: Mon, 16 Dec 2024 16:26:30 +0100 Subject: [PATCH 4/4] Reverted unnecessary change --- routers/strategies_models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/routers/strategies_models.py b/routers/strategies_models.py index 172ad87..033b7b5 100644 --- a/routers/strategies_models.py +++ b/routers/strategies_models.py @@ -38,6 +38,7 @@ class StrategyParameter(BaseModel): is_timespan: bool = False is_connector: bool = False is_trading_pair: bool = False + is_integer: bool = False display_type: str = Field(default="input", description="Can be 'input', 'slider', 'dropdown', 'toggle', or 'date'")