From 0750190af12a5bfffe40b227f5e718479e51ddf5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Thu, 7 Aug 2025 21:05:15 +0200 Subject: [PATCH] fix(qav3): format number properly in log messages MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- .../freqaimodels/QuickAdapterRegressorV3.py | 9 ++++- .../user_data/strategies/QuickAdapterV3.py | 9 ++--- quickadapter/user_data/strategies/Utils.py | 33 +++++++++++++++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py b/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py index 4161065..fba0e28 100644 --- a/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py +++ b/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py @@ -21,6 +21,7 @@ from Utils import ( calculate_min_extrema, calculate_n_extrema, fit_regressor, + format_number, get_optuna_callbacks, get_optuna_study_model_parameters, largest_divisor, @@ -1009,8 +1010,14 @@ class QuickAdapterRegressorV3(BaseRegressionModel): f"Optuna {pair} {namespace} {objective_type} objective done{metric_log_msg} ({time_spent:.2f} secs)" ) for key, value in study_best_results.items(): + if isinstance(value, list): + formatted_value = ( + f"[{', '.join([format_number(item) for item in value])}]" + ) + elif isinstance(value, (int, float)): + formatted_value = format_number(value) logger.info( - f"Optuna {pair} {namespace} {objective_type} objective hyperopt | {key:>20s} : {value}" + f"Optuna {pair} {namespace} {objective_type} objective hyperopt | {key:>20s} : {formatted_value}" ) if not self.optuna_params_valid(pair, namespace, study): logger.warning( diff --git a/quickadapter/user_data/strategies/QuickAdapterV3.py b/quickadapter/user_data/strategies/QuickAdapterV3.py index 29b07aa..09d6b8c 100644 --- a/quickadapter/user_data/strategies/QuickAdapterV3.py +++ b/quickadapter/user_data/strategies/QuickAdapterV3.py @@ -23,6 +23,7 @@ from Utils import ( calculate_n_extrema, calculate_quantile, ewo, + format_number, get_distance, get_zl_ma_fn, non_zero_diff, @@ -63,7 +64,7 @@ class QuickAdapterV3(IStrategy): INTERFACE_VERSION = 3 def version(self) -> str: - return "3.3.142" + return "3.3.143" timeframe = "5m" @@ -932,7 +933,7 @@ class QuickAdapterV3(IStrategy): current_time=current_time, callback=lambda: logger.info( f"Trade {trade.trade_direction} {trade.pair} stage {trade_exit_stage} | " - f"Take Profit: {trade_take_profit_price:.4f}, Rate: {current_rate:.4f}" + f"Take Profit: {format_number(trade_take_profit_price)}, Rate: {format_number(current_rate)}" ), ) if trade_partial_exit: @@ -1177,7 +1178,7 @@ class QuickAdapterV3(IStrategy): current_time=current_time, callback=lambda: logger.info( f"Trade {trade.trade_direction} {trade.pair} stage {trade_exit_stage} | " - f"Take Profit: {trade_take_profit_price:.4f}, Rate: {current_rate:.4f} | " + f"Take Profit: {format_number(trade_take_profit_price)}, Rate: {format_number(current_rate)} | " f"Spiking: {trade_recent_pnl_spiking} " f"(V:{trade_recent_pnl_velocity:.5f} S:{trade_recent_pnl_velocity_std:.5f}, " f"A:{trade_recent_pnl_acceleration:.5f} S:{trade_recent_pnl_acceleration_std:.5f}) | " @@ -1223,7 +1224,7 @@ class QuickAdapterV3(IStrategy): ): return True logger.info( - f"User denied {side} entry for {pair}: rate {rate} did not break threshold {current_threshold}" + f"User denied {side} entry for {pair}: rate {format_number(rate)} did not break threshold {format_number(current_threshold)}" ) return False diff --git a/quickadapter/user_data/strategies/Utils.py b/quickadapter/user_data/strategies/Utils.py index 88d000e..7b8fc63 100644 --- a/quickadapter/user_data/strategies/Utils.py +++ b/quickadapter/user_data/strategies/Utils.py @@ -112,6 +112,39 @@ def smooth_extrema( ) +def format_number(value: int | float, significant_digits: int = 4) -> str: + if not isinstance(value, (int, float)): + return str(value) + + if np.isinf(value): + return "+∞" if value > 0 else "-∞" + if np.isnan(value): + return "NaN" + + if value == int(value): + return str(int(value)) + + abs_value = abs(value) + + if abs_value >= 1.0: + return f"{value:.{significant_digits}f}" + + value_str = f"{abs_value:.18f}" + first_digit_pos = -1 + for i, char in enumerate(value_str): + if char > "0" and char <= "9": + first_digit_pos = i + break + + if first_digit_pos == -1: + return f"{value:.{significant_digits}f}" + + leading_zeros = first_digit_pos - 2 + required_precision = leading_zeros + significant_digits + + return f"{value:.{required_precision}f}" + + @lru_cache(maxsize=128) def calculate_min_extrema( size: int, fit_live_predictions_candles: int, min_extrema: int = 4 -- 2.43.0