From 4a3890841c12cf1f8082e51b06e4653756ef5ae8 Mon Sep 17 00:00:00 2001 From: paisley <8197966+su8su@users.noreply.github.com> Date: Wed, 10 Dec 2025 16:54:07 +0800 Subject: [PATCH] fix:fix total equity zero --- .../common/trading/execution/ccxt_trading.py | 6 ++++-- python/valuecell/agents/common/trading/utils.py | 14 +++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/python/valuecell/agents/common/trading/execution/ccxt_trading.py b/python/valuecell/agents/common/trading/execution/ccxt_trading.py index c771ee84d..2f79c8814 100644 --- a/python/valuecell/agents/common/trading/execution/ccxt_trading.py +++ b/python/valuecell/agents/common/trading/execution/ccxt_trading.py @@ -1329,8 +1329,10 @@ async def fetch_positions(self, symbols: Optional[List[str]] = None) -> List[Dic positions = await exchange.fetch_positions(normalized_symbols) return positions except Exception as e: - print(f"Warning: Could not fetch positions: {e}") - return [] + # Do NOT return an empty list on network/exchange errors; propagate + # so upstream retry/backoff logic can kick in and avoid wiping holdings. + logger.warning(f"⚠️ Could not fetch positions: {e}") + raise async def cancel_order(self, order_id: str, symbol: str) -> Dict: """Cancel an open order. diff --git a/python/valuecell/agents/common/trading/utils.py b/python/valuecell/agents/common/trading/utils.py index ec05c83a0..c7076096e 100644 --- a/python/valuecell/agents/common/trading/utils.py +++ b/python/valuecell/agents/common/trading/utils.py @@ -31,7 +31,10 @@ async def fetch_free_cash_from_gateway( logger.info("Fetching exchange balance for LIVE trading mode") try: if not hasattr(execution_gateway, "fetch_balance"): - return 0.0, 0.0 + raise AttributeError( + f"Execution gateway {execution_gateway.__class__.__name__} " + "does not implement the required 'fetch_balance' method." + ) balance = await execution_gateway.fetch_balance() except Exception as e: if retry_cnt < max_retries: @@ -44,11 +47,12 @@ async def fetch_free_cash_from_gateway( return await fetch_free_cash_from_gateway( execution_gateway, symbols, retry_cnt + 1, max_retries ) + # Propagate after exhausting retries so upstream can keep cached portfolio logger.error( - f"Failed to fetch free cash from exchange after {max_retries} retries, returning 0.0", + f"Failed to fetch free cash from exchange after {max_retries} retries.", exception=e, ) - return 0.0, 0.0 + raise logger.info(f"Raw balance response: {balance}") free_map: dict[str, float] = {} @@ -70,6 +74,10 @@ async def fetch_free_cash_from_gateway( except Exception: continue + # If balance structure is unrecognized, avoid returning zeros silently + if not isinstance(balance, dict) or (not free_map and free_section is None): + raise ValueError("Unrecognized balance response shape from exchange") + logger.info(f"Parsed free balance map: {free_map}") # Derive quote currencies from symbols, fallback to common USD-stable quotes quotes: list[str] = []