log info 封装

This commit is contained in:
zhangkun 2026-01-05 10:42:14 +08:00
parent 0818437caf
commit 42bbf4846d
8 changed files with 248 additions and 121 deletions

View File

@ -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
}
}

View File

@ -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,

View File

@ -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
}
}
}

View File

@ -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
}
}

View File

@ -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
# 检查3ML 审核官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':
# 情况AAI 预测强趋势(高波动),且当前不亏损 → 忽略本次 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
# 情况BAI 预测震荡市(低波动) → 强制接受 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

View File

@ -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

View File

@ -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

View File

@ -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 \