From 42bbf4846df38a96104545c87063f2baff33a792 Mon Sep 17 00:00:00 2001 From: zhangkun Date: Mon, 5 Jan 2026 10:42:14 +0800 Subject: [PATCH] =?UTF-8?q?log=20info=20=E5=B0=81=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config_examples/dryrun.json | 89 ++++++++++++++++++ config_examples/freqaiprimer.json | 1 + config_examples/hyperopt.json | 23 +++++ config_examples/live.json | 136 ++++++++++++++-------------- freqtrade/templates/freqaiprimer.py | 100 +++++++++++--------- tools/backtest.sh | 2 +- tools/dryrun.sh | 15 +-- tools/hyperopt_org.sh | 3 +- 8 files changed, 248 insertions(+), 121 deletions(-) create mode 100644 config_examples/dryrun.json create mode 100644 config_examples/hyperopt.json diff --git a/config_examples/dryrun.json b/config_examples/dryrun.json new file mode 100644 index 00000000..2ff3d056 --- /dev/null +++ b/config_examples/dryrun.json @@ -0,0 +1,89 @@ +{ + "exchange": { + "name": "okx", + "key": "cbda9fde-b9e3-4a2d-94f9-e5c3705dfb5c", + "secret": "CD3B7DB459CBBD540E0926E5C48150E1", + "password": "c^-d:g;P2S9?Q#^", + "enable_strategy_log": true, + "enable_ws": false, + "ccxt_config": { + "enableRateLimit": true, + "rateLimit": 500, + "options": { + "defaultType": "spot" + } + }, + "ccxt_async_config": { + "enableRateLimit": true, + "rateLimit": 3000, + "timeout": 20000 + }, + "pair_whitelist": [ + "AAVE/USDT", + "ADA/USDT", + "AVAX/USDT", + "BCH/USDT", + "BNB/USDT", + "BTC/USDT", + "CHZ/USDT", + "DOGE/USDT", + "ETC/USDT", + "ETH/USDT", + "FIL/USDT", + "ICP/USDT", + "LINK/USDT", + "LTC/USDT", + "PENGU/USDT", + "PEPE/USDT", + "PUMP/USDT", + "SHIB/USDT", + "SNX/USDT", + "SOL/USDT", + "SUI/USDT", + "TON/USDT", + "TRUMP/USDT", + "TRX/USDT", + "UNI/USDT", + "WIF/USDT", + "WLD/USDT", + "XAUT/USDT", + "XLM/USDT", + "XRP/USDT" + ], + "pair_blacklist": [ + "OKB/USDT" + ] + }, + "pairlists": [ + { + "method": "StaticPairList" + } + ], + "order_types": { + "entry": "market", + "exit": "market", + "stoploss": "limit", + "stoploss_on_exchange": false + }, + "order_time_in_force": { + "entry": "gtc", + "exit": "gtc" + }, + "entry_pricing": { + "price_side": "other", + "use_order_book": false, + "price_last_balance": 0 + }, + "exit_pricing": { + "price_side": "other", + "use_order_book": false + }, + + "fee": 0.0008, + "api_server": { + "enabled": true, + "listen_ip_address": "0.0.0.0", + "listen_port": 8080 + } +} + diff --git a/config_examples/freqaiprimer.json b/config_examples/freqaiprimer.json index ddff43c0..2aec6841 100644 --- a/config_examples/freqaiprimer.json +++ b/config_examples/freqaiprimer.json @@ -12,6 +12,7 @@ "process_only_new_candles": true, "fiat_display_currency": "USD", "dry_run": true, + "enable_strategy_log": true, "timeframe": "3m", "additional_timeframes": ["4h"], "dry_run_wallet": 2000, diff --git a/config_examples/hyperopt.json b/config_examples/hyperopt.json new file mode 100644 index 00000000..89561983 --- /dev/null +++ b/config_examples/hyperopt.json @@ -0,0 +1,23 @@ +{ + "exchange": { + "name": "okx", + "key": "cbda9fde-b9e3-4a2d-94f9-e5c3705dfb5c", + "secret": "CD3B7DB459CBBD540E0926E5C48150E1", + "password": "c^-d:g;P2S9?Q#^", + "enable_strategy_log": false, + "enable_ws": false, + "ccxt_config": { + "enableRateLimit": true, + "rateLimit": 500, + "options": { + "defaultType": "spot" + } + }, + "ccxt_async_config": { + "enableRateLimit": true, + "rateLimit": 3000, + "timeout": 20000 + } + } +} + diff --git a/config_examples/live.json b/config_examples/live.json index 93b34032..41548347 100644 --- a/config_examples/live.json +++ b/config_examples/live.json @@ -4,6 +4,7 @@ "key": "cbda9fde-b9e3-4a2d-94f9-e5c3705dfb5c", "secret": "CD3B7DB459CBBD540E0926E5C48150E1", "password": "c^-d:g;P2S9?Q#^", + "enable_strategy_log": true, "enable_ws": false, "ccxt_config": { "enableRateLimit": true, @@ -18,41 +19,35 @@ "timeout": 20000 }, "pair_whitelist": [ - "ACT/USDT", + "AAVE/USDT", "ADA/USDT", "AVAX/USDT", "BCH/USDT", "BNB/USDT", "BTC/USDT", + "CHZ/USDT", "DOGE/USDT", - "DOT/USDT", + "ETC/USDT", "ETH/USDT", "FIL/USDT", - "KAITO/USDT", + "ICP/USDT", "LINK/USDT", "LTC/USDT", - "MASK/USDT", - "MOODENG/USDT", - "OKB/USDT", "PENGU/USDT", "PEPE/USDT", - "PI/USDT", - "PNUT/USDT", - "RENDER/USDT", + "PUMP/USDT", "SHIB/USDT", "SNX/USDT", "SOL/USDT", "SUI/USDT", "TON/USDT", - "TRB/USDT", "TRUMP/USDT", "TRX/USDT", "UNI/USDT", "WIF/USDT", "WLD/USDT", - "WLFI/USDT", "XAUT/USDT", - "XPL/USDT", + "XLM/USDT", "XRP/USDT" ], "pair_blacklist": [ @@ -84,64 +79,64 @@ "use_order_book": false }, "freqai": { - "enabled": true, - "data_kitchen": { - "fillna": "ffill" - }, - "freqaimodel": "LightGBMMultiTargetRegressor", - "purge_old_models": 2, - "identifier": "test58", - "train_period_days": 18, - "backtest_period_days": 2, - "live_retrain_hours": 2, - "outlier_detection": { - "method": "IsolationForest", - "contamination": 0.1 - }, - "feature_selection": { - "method": "recursive_elimination" - }, - "feature_parameters": { - "include_timeframes": [ - "3m", - "15m", - "30m", - "1h" - ], - "include_corr_pairlist": [ - "ETH/USDT", - "SOL/USDT" - ], - "outlier_protection_percentage": 0.1, - "label_period_candles": 100, - "include_shifted_candles": 6, - "DI_threshold": 0.5, - "weight_factor": 0.9, - "principal_component_analysis": false, - "use_SVM_to_remove_outliers": true, - "indicator_periods_candles": [ - 10, - 20, - 50, - 100 - ], - "plot_feature_importances": 10 - }, - "data_split_parameters": { - "test_size": 0.15, - "shuffle": false - }, - "model_training_parameters": { - "n_estimators": 800, - "learning_rate": 0.02, - "num_leaves": 80, - "max_depth": 15, - "min_data_in_leaf": 12, - "feature_fraction": 0.7, - "bagging_fraction": 0.7, - "bagging_freq": 5, - "verbose": -1 - } + "enabled": true, + "data_kitchen": { + "fillna": "ffill" + }, + "freqaimodel": "LightGBMMultiTargetRegressor", + "purge_old_models": 2, + "identifier": "test58", + "train_period_days": 18, + "backtest_period_days": 2, + "live_retrain_hours": 2, + "outlier_detection": { + "method": "IsolationForest", + "contamination": 0.1 + }, + "feature_selection": { + "method": "recursive_elimination" + }, + "feature_parameters": { + "include_timeframes": [ + "3m", + "15m", + "30m", + "1h" + ], + "include_corr_pairlist": [ + "ETH/USDT", + "SOL/USDT" + ], + "outlier_protection_percentage": 0.1, + "label_period_candles": 100, + "include_shifted_candles": 6, + "DI_threshold": 0.5, + "weight_factor": 0.9, + "principal_component_analysis": false, + "use_SVM_to_remove_outliers": true, + "indicator_periods_candles": [ + 10, + 20, + 50, + 100 + ], + "plot_feature_importances": 10 + }, + "data_split_parameters": { + "test_size": 0.15, + "shuffle": false + }, + "model_training_parameters": { + "n_estimators": 800, + "learning_rate": 0.02, + "num_leaves": 80, + "max_depth": 15, + "min_data_in_leaf": 12, + "feature_fraction": 0.7, + "bagging_fraction": 0.7, + "bagging_freq": 5, + "verbose": -1 + } }, "fee": 0.0008, "api_server": { @@ -150,3 +145,4 @@ "listen_port": 8080 } } + diff --git a/freqtrade/templates/freqaiprimer.py b/freqtrade/templates/freqaiprimer.py index 67fc1e29..0983dc75 100644 --- a/freqtrade/templates/freqaiprimer.py +++ b/freqtrade/templates/freqaiprimer.py @@ -45,6 +45,22 @@ class FreqaiPrimer(IStrategy): # 入场间隔控制:记录每个交易对最近一次入场的时间 # 格式: {pair: datetime} self._last_entry_time = {} + + + def strategy_log(self, message: str, level: str = "info") -> None: + """根据 config 的 enable_strategy_log 决定是否输出日志""" + enable_log = self.config.get('enable_strategy_log', False) + if not enable_log: + return + if level.lower() == "debug": + logger.debug(message) + elif level.lower() == "warning": + logger.warning(message) + elif level.lower() == "error": + logger.error(message) + else: + logger.info(message) + # 只用于adjust_trade_position方法的波动系数获取 def get_volatility_coefficient(self, pair: str) -> float: @@ -85,7 +101,7 @@ class FreqaiPrimer(IStrategy): self._volatility_cache[pair] = current_volatility_coef self._volatility_timestamp[pair] = current_time - logger.info(f"波动系数计算完成 {pair}: 系数={current_volatility_coef:.4f} (基于最近200根1h K线)") + self.strategy_log(f"波动系数计算完成 {pair}: 系数={current_volatility_coef:.4f} (基于最近200根1h K线)") return current_volatility_coef @@ -448,7 +464,7 @@ class FreqaiPrimer(IStrategy): df_1h['macd_hist_1h'] = macd_1h['MACDh_12_26_9'] # 验证 MACD 列是否正确生成 - #logger.info(f"[{metadata['pair']}] 1小时 MACD 列: {list(macd_1h.columns)}") + #self.strategy_log(f"[{metadata['pair']}] 1小时 MACD 列: {list(macd_1h.columns)}") # 确保 StochRSI 指标已正确计算 # 将 1h 数据重新索引到主时间框架 (3m),并填充缺失值 @@ -483,7 +499,7 @@ class FreqaiPrimer(IStrategy): dataframe = dataframe.merge(df_1h, how='left', on='date').ffill() # 验证合并后的列 - #logger.info(f"[{metadata['pair']}] 合并后的数据框列名: {list(dataframe.columns)}") + #self.strategy_log(f"[{metadata['pair']}] 合并后的数据框列名: {list(dataframe.columns)}") # K线形态:看涨吞没 dataframe['bullish_engulfing'] = ( @@ -532,8 +548,8 @@ class FreqaiPrimer(IStrategy): if len(dataframe) > 0: current_score = dataframe['market_score'].iloc[-1] current_state = dataframe['market_state'].iloc[-1] - #logger.info(f"[{metadata['pair']}] 熊牛得分: {current_score:.1f}, 市场状态: {current_state}") - #logger.info(f"[{metadata['pair']}] 各时间框架趋势: 3m={'牛' if dataframe['trend_3m'].iloc[-1] == 1 else '熊'}, \ + #self.strategy_log(f"[{metadata['pair']}] 熊牛得分: {current_score:.1f}, 市场状态: {current_state}") + #self.strategy_log(f"[{metadata['pair']}] 各时间框架趋势: 3m={'牛' if dataframe['trend_3m'].iloc[-1] == 1 else '熊'}, \ # 15m={'牛' if dataframe['trend_15m'].iloc[-1] == 1 else '熊'}, \ # 1h={'牛' if dataframe['trend_1h_ema'].iloc[-1] == 1 else '熊'}") @@ -544,7 +560,7 @@ class FreqaiPrimer(IStrategy): # 'bullish_engulfing', 'volume', 'volume_ma']].tail(5)) # 打印最终数据框的列名以验证 - #logger.info(f"[{metadata['pair']}] 最终数据框列名: {list(dataframe.columns)}") + #self.strategy_log(f"[{metadata['pair']}] 最终数据框列名: {list(dataframe.columns)}") # 启用 FreqAI:在所有指标计算完成后调用 dataframe = self.freqai.start(dataframe, metadata, self) @@ -577,17 +593,17 @@ class FreqaiPrimer(IStrategy): dataframe.loc[final_exit_condition, 'exit_price'] = dataframe.loc[final_exit_condition, 'close'] * 1.0125 # 增强调试信息 - #logger.info(f"[{metadata['pair']}] 出场条件检查:") - #logger.info(f" - 价格突破布林带上轨: {breakout_condition.sum()} 次") - #logger.info(f" - 成交量显著放大: {volume_spike.sum()} 次") - #logger.info(f" - MACD 下降趋势: {macd_downward.sum()} 次") - #logger.info(f" - RSI 超买: {rsi_overbought.sum()} 次") - #logger.info(f" - 最终条件: {final_condition.sum()} 次") - #logger.info(f" - 使用参数: exit_bb_upper_deviation={self.exit_bb_upper_deviation.value}, exit_volume_multiplier={self.exit_volume_multiplier.value}, rsi_overbought={self.rsi_overbought.value}") + #self.strategy_log(f"[{metadata['pair']}] 出场条件检查:") + #self.strategy_log(f" - 价格突破布林带上轨: {breakout_condition.sum()} 次") + #self.strategy_log(f" - 成交量显著放大: {volume_spike.sum()} 次") + #self.strategy_log(f" - MACD 下降趋势: {macd_downward.sum()} 次") + #self.strategy_log(f" - RSI 超买: {rsi_overbought.sum()} 次") + #self.strategy_log(f" - 最终条件: {final_condition.sum()} 次") + #self.strategy_log(f" - 使用参数: exit_bb_upper_deviation={self.exit_bb_upper_deviation.value}, exit_volume_multiplier={self.exit_volume_multiplier.value}, rsi_overbought={self.rsi_overbought.value}") # 日志记录 #if dataframe['exit_long'].sum() > 0: - # logger.info(f"[{metadata['pair']}] 触发出场信号数量: {dataframe['exit_long'].sum()}") + # self.strategy_log(f"[{metadata['pair']}] 触发出场信号数量: {dataframe['exit_long'].sum()}") return dataframe @@ -644,14 +660,14 @@ class FreqaiPrimer(IStrategy): dataframe.loc[final_condition_updated, 'enter_price'] = dataframe.loc[final_condition_updated, 'close'] * 0.9833 # 增强调试信息 - #logger.info(f"[{metadata['pair']}] 入场条件检查:") - #logger.info(f" - 价格接近布林带下轨: {close_to_bb_lower_1h.sum()} 次") - #logger.info(f" - RSI 超卖: {rsi_condition_1h.sum()} 次") - #logger.info(f" - StochRSI 超卖: {stochrsi_condition_1h.sum()} 次") - #logger.info(f" - MACD 上升趋势: {macd_condition_1h.sum()} 次") - #logger.info(f" - 成交量或布林带宽度: {(volume_spike | bb_width_condition).sum()} 次") - #logger.info(f" - 趋势确认: {trend_confirmation.sum()} 次") - #logger.info(f" - 最终条件: {final_condition.sum()} 次") + #self.strategy_log(f"[{metadata['pair']}] 入场条件检查:") + #self.strategy_log(f" - 价格接近布林带下轨: {close_to_bb_lower_1h.sum()} 次") + #self.strategy_log(f" - RSI 超卖: {rsi_condition_1h.sum()} 次") + #self.strategy_log(f" - StochRSI 超卖: {stochrsi_condition_1h.sum()} 次") + #self.strategy_log(f" - MACD 上升趋势: {macd_condition_1h.sum()} 次") + #self.strategy_log(f" - 成交量或布林带宽度: {(volume_spike | bb_width_condition).sum()} 次") + #self.strategy_log(f" - 趋势确认: {trend_confirmation.sum()} 次") + #self.strategy_log(f" - 最终条件: {final_condition.sum()} 次") # 在populate_entry_trend方法末尾添加 # 计算条件间的相关性 conditions = DataFrame({ @@ -663,10 +679,10 @@ class FreqaiPrimer(IStrategy): 'trend': trend_confirmation }) correlation = conditions.corr().mean().mean() - #logger.info(f"[{metadata['pair']}] 条件平均相关性: {correlation:.2f}") + #self.strategy_log(f"[{metadata['pair']}] 条件平均相关性: {correlation:.2f}") # 日志记录 #if dataframe['enter_long'].sum() > 0: - # logger.info(f"[{metadata['pair']}] 发现入场信号数量: {dataframe['enter_long'].sum()}") + # self.strategy_log(f"[{metadata['pair']}] 发现入场信号数量: {dataframe['enter_long'].sum()}") return dataframe @@ -713,12 +729,12 @@ class FreqaiPrimer(IStrategy): # 检查是否超过阈值 if rise_percentage >= rapid_rise_threshold: rapid_rise_detected = True - #logger.info(f"[{pair}] 检测到剧烈拉升: 从 {window_low:.2f} 到 {window_high:.2f} ({rise_percentage:.2%}) 在 {max_consecutive_candles} 根K线内") + #self.strategy_log(f"[{pair}] 检测到剧烈拉升: 从 {window_low:.2f} 到 {window_high:.2f} ({rise_percentage:.2%}) 在 {max_consecutive_candles} 根K线内") break current_price = recent_data['close'].iloc[-1] - #logger.info(f"[{pair}] 剧烈拉升检测结果: {'不稳固' if rapid_rise_detected else '稳固'}") - #logger.info(f"[{pair}] 最近最大涨幅: {max_rise:.2%}") + #self.strategy_log(f"[{pair}] 剧烈拉升检测结果: {'不稳固' if rapid_rise_detected else '稳固'}") + #self.strategy_log(f"[{pair}] 最近最大涨幅: {max_rise:.2%}") return rapid_rise_detected @@ -742,7 +758,7 @@ class FreqaiPrimer(IStrategy): 交易买入前的确认函数,用于最终决定是否执行交易 此处实现剧烈拉升检查和入场间隔控制逻辑 """ - logger.info(f"[{pair}] confirm_trade_entry 被调用 - 价格: {rate:.8f}, 时间: {current_time}") + self.strategy_log(f"[{pair}] confirm_trade_entry 被调用 - 价格: {rate:.8f}, 时间: {current_time}") # 默认允许交易 allow_trade = True @@ -753,14 +769,14 @@ class FreqaiPrimer(IStrategy): last_entry = self._last_entry_time[pair] time_diff = (current_time - last_entry).total_seconds() * 0.0166666667 # 转换为分钟(使用乘法避免除法) if time_diff < self.entry_interval_minutes.value: - logger.info(f"[{pair}] 入场间隔不足: 距离上次入场 {time_diff:.1f}分钟 < {self.entry_interval_minutes.value}分钟,取消本次入场") + self.strategy_log(f"[{pair}] 入场间隔不足: 距离上次入场 {time_diff:.1f}分钟 < {self.entry_interval_minutes.value}分钟,取消本次入场") allow_trade = False # 检查2:检查是否处于剧烈拉升的不稳固区域 if allow_trade: is_unstable_region = self.detect_h1_rapid_rise(pair) if is_unstable_region: - #logger.info(f"[{pair}] 由于检测到剧烈拉升,取消入场交易") + #self.strategy_log(f"[{pair}] 由于检测到剧烈拉升,取消入场交易") allow_trade = False # 检查3:ML 审核官(FreqAI 过滤低质量入场) @@ -792,10 +808,10 @@ class FreqaiPrimer(IStrategy): entry_prob = max(0.0, min(1.0, entry_prob)) entry_threshold = self.ml_entry_signal_threshold.value if entry_prob < entry_threshold: - logger.info(f"[{pair}] ML 审核官拒绝入场: entry_signal 概率 {entry_prob:.2f} < 阈值 {entry_threshold:.2f}(上涨概率低,不宜入场)") + self.strategy_log(f"[{pair}] ML 审核官拒绝入场: entry_signal 概率 {entry_prob:.2f} < 阈值 {entry_threshold:.2f}(上涨概率低,不宜入场)") allow_trade = False else: - logger.info(f"[{pair}] ML 审核官允许入场: entry_signal 概率 {entry_prob:.2f} >= 阈值 {entry_threshold:.2f}") + self.strategy_log(f"[{pair}] ML 审核官允许入场: entry_signal 概率 {entry_prob:.2f} >= 阈值 {entry_threshold:.2f}") except Exception as e: logger.warning(f"[{pair}] ML 审核官检查失败,忽略 ML 过滤: {e}") return allow_trade @@ -803,7 +819,7 @@ class FreqaiPrimer(IStrategy): def custom_entry_price(self, pair: str, trade: Trade | None, current_time: datetime, proposed_rate: float, entry_tag: str | None, side: str, **kwargs) -> float: adjusted_rate = proposed_rate * (1 - 0.001) - logger.info(f"[{pair}] 自定义买入价:{adjusted_rate:.6f}(原价:{proposed_rate:.6f})") + self.strategy_log(f"[{pair}] 自定义买入价:{adjusted_rate:.6f}(原价:{proposed_rate:.6f})") return adjusted_rate def confirm_trade_exit( @@ -822,10 +838,10 @@ class FreqaiPrimer(IStrategy): 交易卖出前的确认函数,用于最终决定是否执行出场 此处使用 ML 审核官(exit_signal 置信度)过滤出场 """ - logger.info(f"[{pair}] confirm_trade_exit 被调用 - 价格: {rate:.8f}, 出场原因: {exit_reason}, 时间: {current_time}") + self.strategy_log(f"[{pair}] confirm_trade_exit 被调用 - 价格: {rate:.8f}, 出场原因: {exit_reason}, 时间: {current_time}") # 风险控制类退出原因:不经过 ML 审核官,直接允许出场 if exit_reason in ['stop_loss', 'trailing_stop_loss', 'emergency_exit', 'force_exit']: - logger.info(f"[{pair}] 风险控制退出,不走 ML 审核官: exit_reason={exit_reason}") + self.strategy_log(f"[{pair}] 风险控制退出,不走 ML 审核官: exit_reason={exit_reason}") return True # 默认允许出场 allow_exit = True @@ -886,7 +902,7 @@ class FreqaiPrimer(IStrategy): if future_vol_signal is not None and exit_reason == 'exit_signal': # 情况A:AI 预测强趋势(高波动),且当前不亏损 → 忽略本次 exit_signal,继续持有 if future_vol_signal > 0.65 and current_profit >= 0: - logger.info( + self.strategy_log( f"[波动率 AI] [{pair}] AI 预测强趋势(高波动 {future_vol_signal:.2f}),忽略本次 exit_signal,继续持有 | " f"持仓: {trade_age_minutes:.1f}min, 利润: {current_profit:.4f}" ) @@ -894,7 +910,7 @@ class FreqaiPrimer(IStrategy): return allow_exit # 情况B:AI 预测震荡市(低波动) → 强制接受 exit_signal,立即出场 elif future_vol_signal < 0.35: - logger.info( + self.strategy_log( f"[波动率 AI] [{pair}] AI 预测震荡市(低波动 {future_vol_signal:.2f}),强制接受 exit_signal 出场 | " f"持仓: {trade_age_minutes:.1f}min, 利润: {current_profit:.4f}" ) @@ -905,14 +921,14 @@ class FreqaiPrimer(IStrategy): dynamic_threshold = max(0.05, dynamic_threshold) if exit_prob < dynamic_threshold: - logger.info( + self.strategy_log( f"[{pair}] ML 审核官拒绝出场: exit_signal 概率 {exit_prob:.2f} < 动态阈值 {dynamic_threshold:.2f}" f" | 原应出场原因: {exit_reason} | 持仓: {trade_age_minutes:.1f}min, 利润: {current_profit:.4f}" f" | 波动率AI: {future_vol_signal if future_vol_signal is not None else 'N/A'}" ) allow_exit = False else: - logger.info( + self.strategy_log( f"[{pair}] ML 审核官允许出场: exit_signal 概率 {exit_prob:.2f} >= 动态阈值 {dynamic_threshold:.2f}" f" | 出场原因: {exit_reason} | 持仓: {trade_age_minutes:.1f}min, 利润: {current_profit:.4f}" f" | 波动率AI: {future_vol_signal if future_vol_signal is not None else 'N/A'}" @@ -988,7 +1004,7 @@ class FreqaiPrimer(IStrategy): if dynamic_roi_threshold < 0: exit_ratio = 1.0 - #logger.info(f"[{pair}] 动态止盈: 持仓时间={trade_age_minutes:.1f}分钟, 当前利润={current_profit:.2%}, " + #self.strategy_log(f"[{pair}] 动态止盈: 持仓时间={trade_age_minutes:.1f}分钟, 当前利润={current_profit:.2%}, " # f"动态ROI阈值={dynamic_roi_threshold:.4f}, 利润比值={profit_ratio:.2f}, " # f"市场状态={current_state}, entry_tag={entry_tag}, 退出比例={exit_ratio:.0%}") @@ -997,7 +1013,7 @@ class FreqaiPrimer(IStrategy): # 计算出场价格上浮比例(1.25%) price_markup_percent = 1.25 adjusted_exit_price = current_rate * 1.0125 - logger.info(f"[{pair}] 准备出场 - 市场价: {current_rate:.8f}, 调整后出场价: {adjusted_exit_price:.8f}, 上浮: {price_markup_percent}%, 退出比例: {exit_ratio:.0%}") + self.strategy_log(f"[{pair}] 准备出场 - 市场价: {current_rate:.8f}, 调整后出场价: {adjusted_exit_price:.8f}, 上浮: {price_markup_percent}%, 退出比例: {exit_ratio:.0%}") return exit_ratio @@ -1048,7 +1064,7 @@ class FreqaiPrimer(IStrategy): # 确保加仓金额在允许的范围内 additional_stake = max(min_stake, min(additional_stake, max_stake - trade.stake_amount)) - #logger.info(f"[{pair}] 触发加仓: 第{adjustment_count + 1}次加仓, 初始金额{initial_stake:.2f}, \ + #self.strategy_log(f"[{pair}] 触发加仓: 第{adjustment_count + 1}次加仓, 初始金额{initial_stake:.2f}, \ # 加仓金额{additional_stake:.2f}, 价格差{price_diff_pct:.2%}, 当前利润{current_profit:.2%}") return additional_stake diff --git a/tools/backtest.sh b/tools/backtest.sh index aa086035..912ca902 100755 --- a/tools/backtest.sh +++ b/tools/backtest.sh @@ -171,7 +171,7 @@ elif [ -n "$PAIRS_ARG" ]; then echo "Using pairs from --pairs parameter: $PAIRS_ARG" else # 没有提供任何交易对参数,使用默认值 - DEFAULT_PAIRS="BTC/USDT TON/USDT DOT/USDT XRP/USDT OKB/USDT SOL/USDT DOGE/USDT WCT/USDT TRUMP/USDT SUI/USDT PEPE/USDT TRB/USDT MASK/USDT UNI/USDT KAITO/USDT" + DEFAULT_PAIRS="BTC/USDT TON/USDT XRP/USDT SOL/USDT DOGE/USDT WCT/USDT TRUMP/USDT SUI/USDT PEPE/USDT TRB/USDT MASK/USDT" PAIRS_FLAG="--pairs $DEFAULT_PAIRS" echo "No pairs parameter provided, using default pairs: $DEFAULT_PAIRS" fi diff --git a/tools/dryrun.sh b/tools/dryrun.sh index 09cc5c59..631004e8 100755 --- a/tools/dryrun.sh +++ b/tools/dryrun.sh @@ -113,13 +113,13 @@ update_live_json_pair_whitelist() { # 6. 停止并移除指定名称的容器 remove_existing_container() { - local mode="$1" # dryrun 或 live - + local mode="$1" # dryrun 或 live + echo "正在查找并移除所有 'freqtrade-${mode}-*' 的容器..." >&2 # 查找所有名称以 freqtrade-${mode}- 开头的容器 CONTAINERS=$(docker ps -aq --filter "name=freqtrade-${mode}-") - + if [ -z "$CONTAINERS" ]; then echo "✅ 未找到任何 'freqtrade-${mode}-*' 的容器" >&2 return @@ -135,7 +135,7 @@ remove_existing_container() { CONTAINER_NAME=$(docker ps -a --filter "id=$CONTAINER" --format "{{.Names}}") echo "正在停止容器 $CONTAINER_NAME..." >&2 docker stop "$CONTAINER" >/dev/null 2>&1 - + echo "正在移除容器 $CONTAINER_NAME..." >&2 if docker rm "$CONTAINER" >/dev/null 2>&1; then echo "✅ 已成功移除容器 $CONTAINER_NAME" >&2 @@ -143,7 +143,7 @@ remove_existing_container() { echo "⚠️ 移除容器 $CONTAINER_NAME 失败" >&2 fi done - + echo "✅ 容器清理完成" >&2 } @@ -252,7 +252,7 @@ echo "正在启动新容器..." >&2 # 临时禁用 set -e,以便捕获 docker run 的错误 set +e -docker run -d --rm \ +docker run -d --restart always \ --name "${CONTAINER_NAME}" \ -p 8080:8080 \ --add-host "www.okx.com:104.18.43.174" \ @@ -273,11 +273,12 @@ docker run -d --rm \ --dry-run \ --freqaimodel LightGBMRegressorMultiTarget \ --config /freqtrade/config_examples/$CONFIG_FILE \ + --config /freqtrade/config_examples/dryrun.json \ --strategy $STRATEGY_NAME \ --fee 0.0008 \ --strategy-path /freqtrade/templates RUN_RESULT=$? -set -e # 恢复 set -e +set -e # 恢复 set -e if [ $RUN_RESULT -eq 0 ]; then echo "✅ 容器 $CONTAINER_NAME 启动成功" >&2 diff --git a/tools/hyperopt_org.sh b/tools/hyperopt_org.sh index 6c1f5a23..28e4eb4c 100755 --- a/tools/hyperopt_org.sh +++ b/tools/hyperopt_org.sh @@ -494,7 +494,8 @@ docker-compose run --rm freqtrade hyperopt $PAIRS_FLAG \ --strategy $STRATEGY_CLASS_NAME \ --config /freqtrade/config_examples/$CONFIG_FILE \ --config /freqtrade/templates/${PARAMS_NAME}.json \ - --enable-protections \ + --config /freqtrade/config_examples/hyperopt.json \ +--enable-protections \ --strategy-path /freqtrade/templates \ --timerange ${START_DATE}-${END_DATE} \ --random-state $RANDOM_STATE \