diff --git a/routers/controllers.py b/routers/controllers.py index 65a66c53..a1a0c1eb 100644 --- a/routers/controllers.py +++ b/routers/controllers.py @@ -218,7 +218,7 @@ async def delete_controller(controller_type: ControllerType, controller_name: st ) -@router.get("/{controller_type}/{controller_name}/config/template", response_model=Dict) +@router.get("/{controller_type}/{controller_name}/config/template") async def get_controller_config_template(controller_type: ControllerType, controller_name: str): """ Get controller configuration template with default values. @@ -241,10 +241,40 @@ async def get_controller_config_template(controller_type: ControllerType, contro ) # Extract fields and default values - config_fields = {name: field.default for name, field in config_class.model_fields.items()} + config_fields = {name: {"default": field.default, + "type": field.annotation, + "required": field.required if hasattr(field, 'required') else False, + } for name, field in config_class.model_fields.items()} return json.loads(json.dumps(config_fields, default=str)) +@router.post("/{controller_type}/{controller_name}/config/validate") +async def validate_controller_config(controller_type: ControllerType, controller_name: str, config: Dict): + """ + Validate controller configuration against the controller's config class. + + Args: + controller_type: Type of the controller + controller_name: Name of the controller + config: Configuration dictionary to validate + + Returns: + Success message if configuration is valid + + Raises: + HTTPException: 400 if validation fails + """ + config_class = fs_util.load_controller_config_class(controller_type.value, controller_name) + if config_class is None: + raise HTTPException( + status_code=404, + detail=f"Controller configuration class for '{controller_name}' not found" + ) + try: + config_class(**config) # Validate by instantiating the model + return {"message": "Configuration is valid"} + except Exception as e: + raise HTTPException(status_code=400, detail=str(e)) # Bot-specific controller config endpoints diff --git a/services/accounts_service.py b/services/accounts_service.py index b847d442..71930ed1 100644 --- a/services/accounts_service.py +++ b/services/accounts_service.py @@ -252,13 +252,13 @@ async def update_account_state(self): self.accounts_state[account_name] = {} for connector_name, connector in connectors.items(): try: - tokens_info = await self._get_connector_tokens_info(connector, connector_name, self.market_data_feed_manager) + tokens_info = await self._get_connector_tokens_info(connector, connector_name) self.accounts_state[account_name][connector_name] = tokens_info except Exception as e: logger.error(f"Error updating balances for connector {connector_name} in account {account_name}: {e}") self.accounts_state[account_name][connector_name] = [] - async def _get_connector_tokens_info(self, connector, connector_name: str, market_data_manager: Optional[MarketDataFeedManager] = None) -> List[Dict]: + async def _get_connector_tokens_info(self, connector, connector_name: str) -> List[Dict]: """Get token info from a connector instance using cached prices when available.""" balances = [{"token": key, "units": value} for key, value in connector.get_all_balances().items() if value != Decimal("0") and key not in settings.banned_tokens] @@ -269,10 +269,10 @@ async def _get_connector_tokens_info(self, connector, connector_name: str, marke prices_from_cache = {} trading_pairs_need_update = [] - if market_data_manager: + if self.market_data_feed_manager: for trading_pair in trading_pairs: try: - cached_price = market_data_manager.market_data_provider.get_rate(trading_pair) + cached_price = self.market_data_feed_manager.market_data_provider.get_rate(trading_pair) if cached_price > 0: prices_from_cache[trading_pair] = cached_price else: