log info 封装
This commit is contained in:
parent
0818437caf
commit
42bbf4846d
89
config_examples/dryrun.json
Normal file
89
config_examples/dryrun.json
Normal 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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
23
config_examples/hyperopt.json
Normal file
23
config_examples/hyperopt.json
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 \
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user