Compare commits

..

60 Commits
main ... test3

Author SHA1 Message Date
zhangkun9038@dingtalk.com
1f5efe2d4f Merge branch 'test3' of ssh://gitea.zjmud.xyz:2222/phyer/myTestFreqAI into test3 2025-04-29 14:32:31 +08:00
zhangkun9038@dingtalk.com
de31f38a41 with v3 2025-04-29 14:31:05 +08:00
zhangkun9038@dingtalk.com
6d764b8cd2 log 2025-04-29 14:23:15 +08:00
zhangkun9038@dingtalk.com
8912ebbb69 log 2025-04-29 14:22:10 +08:00
zhangkun9038@dingtalk.com
3a721996a0 with v3 2025-04-29 14:20:23 +08:00
zhangkun9038@dingtalk.com
1eedae044a with v3 2025-04-29 14:17:56 +08:00
zhangkun9038@dingtalk.com
85736d17c9 with v3 2025-04-29 14:17:09 +08:00
zhangkun9038@dingtalk.com
b5f733c2f2 with v3 2025-04-29 14:05:46 +08:00
zhangkun9038@dingtalk.com
4cdd0c9d1e with v3 2025-04-29 14:02:40 +08:00
zhangkun9038@dingtalk.com
339f97044d with v3 2025-04-29 14:00:06 +08:00
zhangkun9038@dingtalk.com
9490a8e12e with v3 2025-04-29 13:57:33 +08:00
zhangkun9038@dingtalk.com
02a5cc410f with v3 2025-04-29 13:55:49 +08:00
zhangkun9038@dingtalk.com
c54f83d64f with v3 2025-04-29 13:53:54 +08:00
zhangkun9038@dingtalk.com
80394be9d4 with v3 2025-04-29 12:08:45 +08:00
zhangkun9038@dingtalk.com
e27cde2e19 with v3 2025-04-29 12:00:36 +08:00
zhangkun9038@dingtalk.com
ed011ef498 run result 2025-04-29 11:47:05 +08:00
zhangkun9038@dingtalk.com
4dcfc172f9 听v3的 2025-04-29 11:45:15 +08:00
zhangkun9038@dingtalk.com
65b9e9c0fc allow kog 2025-04-29 10:42:56 +08:00
zhangkun9038@dingtalk.com
cca246abfd log ok 2025-04-29 10:22:02 +08:00
zhangkun9038@dingtalk.com
37173ab636 4个月回测需要4分钟,结果还是跑输15% 2025-04-29 08:47:03 +08:00
zhangkun9038@dingtalk.com
8f4c374e6b 检查 MACD 列是否存在
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 17:01:30 +08:00
zhangkun9038@dingtalk.com
ff7aff8ee7 检查 MACD 列是否存在
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 16:51:18 +08:00
zhangkun9038@dingtalk.com
e5cc226c01 检查 MACD 列是否存在
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 16:48:53 +08:00
zhangkun9038@dingtalk.com
63c1f07f06 确保是二维数组
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 16:46:26 +08:00
zhangkun9038@dingtalk.com
b20684b5b1 up3
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 16:12:02 +08:00
zhangkun9038@dingtalk.com
96b76ffcc0 up3
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 16:09:50 +08:00
zhangkun9038@dingtalk.com
0fa0866370 up3
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 16:09:02 +08:00
zhangkun9038@dingtalk.com
887c4778b4 up3
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 16:07:03 +08:00
zhangkun9038@dingtalk.com
8777726441 up
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 15:49:02 +08:00
zhangkun9038@dingtalk.com
b6b9a62c35 up
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 15:47:10 +08:00
zhangkun9038@dingtalk.com
3fafbff8c3 up
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 15:44:22 +08:00
zhangkun9038@dingtalk.com
619de5cede 跟特征数量没关系
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 15:32:01 +08:00
zhangkun9038@dingtalk.com
8535b10cea 跟特征数量没关系
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 15:15:37 +08:00
zhangkun9038@dingtalk.com
7da603fd08 跟特征数量没关系
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 15:14:09 +08:00
zhangkun9038@dingtalk.com
144615b7a8 跟特征数量没关系
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 14:13:16 +08:00
zhangkun9038@dingtalk.com
8448ab40f5 跟特征数量没关系
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 14:11:36 +08:00
zhangkun9038@dingtalk.com
6916e49479 跟特征数量没关系
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 14:10:54 +08:00
zhangkun9038@dingtalk.com
29fd0941a0 跟特征数量没关系
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 14:08:34 +08:00
zhangkun9038@dingtalk.com
ec7d7c2842 跟特征数量没关系
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 14:07:32 +08:00
zhangkun9038@dingtalk.com
ea707fe104 跟特征数量没关系
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 14:06:49 +08:00
zhangkun9038@dingtalk.com
2f4a06d505 跟特征数量没关系
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 13:59:16 +08:00
zhangkun9038@dingtalk.com
65116ab7b4 跟特征数量没关系
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 13:49:35 +08:00
zhangkun9038@dingtalk.com
fbd72745cb 跟特征数量没关系
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 13:34:56 +08:00
zhangkun9038@dingtalk.com
8477bf07c7 增加特征
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 13:23:49 +08:00
zhangkun9038@dingtalk.com
03a54a5b0a 添加更多技术指标
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 13:13:19 +08:00
zhangkun9038@dingtalk.com
e3ffdd92e0 :生成的特征可能不够稳定,导致新数据与训练数据差异过大
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 13:01:27 +08:00
zhangkun9038@dingtalk.com
c3e4a73eb3 缩进乱了
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 12:49:02 +08:00
zhangkun9038@dingtalk.com
21e4c2f2ea 数据清理
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 12:45:19 +08:00
zhangkun9038@dingtalk.com
86e9a2ab61 确保 &-buy_rsi 列的值计算正确
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 12:42:12 +08:00
zhangkun9038@dingtalk.com
05b65162a1 Additional check to ensure no NaN values remain
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 12:34:47 +08:00
zhangkun9038@dingtalk.com
64e2edfa4e 计算 buy_rsi_pred 并清理 NaN 值
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 12:31:10 +08:00
zhangkun9038@dingtalk.com
328769e0e1 up
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 12:25:20 +08:00
zhangkun9038@dingtalk.com
82ed0e90e9 up
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 12:21:53 +08:00
zhangkun9038@dingtalk.com
244b91ebd3 up
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 12:20:59 +08:00
zhangkun9038@dingtalk.com
e0884d4349 up
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 12:16:22 +08:00
zhangkun9038@dingtalk.com
456ae1fde0 up
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 12:10:17 +08:00
zhangkun9038@dingtalk.com
b72587ed6a up 2025-04-28 11:54:42 +08:00
zhangkun9038@dingtalk.com
c145d5d452 up
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 11:52:45 +08:00
zhangkun9038@dingtalk.com
872bfe4078 up
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 11:38:27 +08:00
zhangkun9038@dingtalk.com
6e4e54b9c8 去掉看底牌代码
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run
2025-04-28 11:34:17 +08:00
25 changed files with 2915 additions and 9115 deletions

View File

@ -0,0 +1,5 @@
<<<<<<< HEAD
=======
freqtrade backtesting --strategy FreqaiExampleStrategy --strategy-path freqtrade/templates --config config_examples/config_freqai.example.json --timerange 20230101-20230401
>>>>>>> Snippet

4
.gitignore vendored
View File

@ -73,7 +73,9 @@ coverage.xml
*.pot
# Django stuff:
*.log
#*.log
!outout_filted.log
local_settings.py
# Flask stuff:

View File

@ -0,0 +1,264 @@
diff --git "a/4. **\346\270\205\347\220\206\347\274\223\345\255\230**\357\274\232" "b/4. **\346\270\205\347\220\206\347\274\223\345\255\230**\357\274\232"
new file mode 100644
index 0000000..3bb7671
--- /dev/null
+++ "b/4. **\346\270\205\347\220\206\347\274\223\345\255\230**\357\274\232"
@@ -0,0 +1,5 @@
+
+<<<<<<< HEAD
+=======
+ rm -rf /freqtrade/user_data/models/test62/
+>>>>>>> Snippet
diff --git "a/5. **\351\207\215\346\226\260\350\256\255\347\273\203**\357\274\232" "b/5. **\351\207\215\346\226\260\350\256\255\347\273\203**\357\274\232"
new file mode 100644
index 0000000..8a18d3d
--- /dev/null
+++ "b/5. **\351\207\215\346\226\260\350\256\255\347\273\203**\357\274\232"
@@ -0,0 +1,5 @@
+
+<<<<<<< HEAD
+=======
+ freqtrade trade --config config_examples/config_freqai.okx.json --strategy FreqaiExampleStrategy
+>>>>>>> Snippet
diff --git a/config_examples/config_freqai.okx.json b/config_examples/config_freqai.okx.json
index 1816983..4535010 100644
--- a/config_examples/config_freqai.okx.json
+++ b/config_examples/config_freqai.okx.json
@@ -67,45 +67,31 @@
"freqaimodel": "CatboostClassifier",
"purge_old_models": 2,
"train_period_days": 15,
- "identifier": "test62",
- "train_period_days": 30,
- "backtest_period_days": 10,
+ "train_period_days": 180,
+ "backtest_period_days": 60,
"live_retrain_hours": 0,
"feature_selection": {
"method": "recursive_elimination"
},
"feature_parameters": {
- "include_timeframes": [
- "3m",
- "15m",
- "1h"
- ],
- "include_corr_pairlist": [
- "BTC/USDT",
- "SOL/USDT"
- ],
- "label_period_candles": 20,
- "include_shifted_candles": 2,
- "DI_threshold": 0.9,
+ "include_timeframes": ["15m"],
+ "include_corr_pairlist": ["BTC/USDT"],
+ "label_period_candles": 10,
+ "include_shifted_candles": 1,
+ "DI_threshold": 0.7,
"weight_factor": 0.9,
"principal_component_analysis": false,
"use_SVM_to_remove_outliers": false,
- "indicator_periods_candles": [
- 10,
- 20,
- 50
- ],
- "plot_feature_importances": 0
+ "indicator_periods_candles": [14],
},
"data_split_parameters": {
"test_size": 0.2
},
- "model_training_parameters": {
- "n_estimators": 100,
- "learning_rate": 0.05,
- "max_depth": 5,
- "num_leaves": 31
- }
+ "model_training_parameters": {
+ "n_estimators": 100,
+ "learning_rate": 0.05,
+ "max_depth": 5
+ }
},
"api_server": {
"enabled": true,
diff --git a/docker-compose.yml b/docker-compose.yml
index defe81e..aeb31e6 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -64,7 +64,7 @@ services:
command: >
backtesting
--logfile /freqtrade/user_data/logs/freqtrade.log
- --freqaimodel LightGBMRegressor
+ --freqaimodel XGBoostRegressor
--config /freqtrade/config_examples/config_freqai.okx.json
--config /freqtrade/templates/FreqaiExampleStrategy.json
--strategy-path /freqtrade/templates
diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py
index 688e644..e27e17b 100644
--- a/freqtrade/templates/FreqaiExampleStrategy.py
+++ b/freqtrade/templates/FreqaiExampleStrategy.py
@@ -30,12 +30,12 @@ class FreqaiExampleStrategy(IStrategy):
# FreqAI 配置
freqai_info = {
- "model": "XGBoostRegressor", # 改用XGBoost
+ "model": "CatboostClassifier", # 与config保持一致
"feature_parameters": {
- "include_timeframes": ["5m", "15m", "1h"],
- "include_corr_pairlist": [],
- "label_period_candles": 12,
- "include_shifted_candles": 3,
+ "include_timeframes": ["3m", "15m", "1h"], # 与config一致
+ "include_corr_pairlist": ["BTC/USDT", "SOL/USDT"], # 添加相关交易对
+ "label_period_candles": 20, # 与config一致
+ "include_shifted_candles": 2, # 与config一致
},
"data_split_parameters": {
"test_size": 0.2,
@@ -72,54 +72,26 @@ class FreqaiExampleStrategy(IStrategy):
}
def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, metadata: dict, **kwargs) -> DataFrame:
- # 添加更多技术指标
+ # 保留关键的技术指标
dataframe["%-rsi"] = ta.RSI(dataframe, timeperiod=14)
- dataframe["%-mfi"] = ta.MFI(dataframe, timeperiod=14)
- dataframe["%-sma"] = ta.SMA(dataframe, timeperiod=20)
- dataframe["%-ema"] = ta.EMA(dataframe, timeperiod=20)
- dataframe["%-adx"] = ta.ADX(dataframe, timeperiod=14)
- dataframe["%-atr"] = ta.ATR(dataframe, timeperiod=14)
- dataframe["%-obv"] = ta.OBV(dataframe)
- dataframe["%-cci"] = ta.CCI(dataframe, timeperiod=20)
- dataframe["%-stoch"] = ta.STOCH(dataframe)['slowk']
- dataframe["%-macd"] = ta.MACD(dataframe)['macd']
- dataframe["%-macdsignal"] = ta.MACD(dataframe)['macdsignal']
- dataframe["%-macdhist"] = ta.MACD(dataframe)['macdhist']
- dataframe["%-willr"] = ta.WILLR(dataframe, timeperiod=14)
- dataframe["%-ultosc"] = ta.ULTOSC(dataframe)
- dataframe["%-trix"] = ta.TRIX(dataframe, timeperiod=14)
- dataframe["%-ad"] = ta.ADOSC(dataframe)
- dataframe["%-mom"] = ta.MOM(dataframe, timeperiod=10)
- dataframe["%-roc"] = ta.ROC(dataframe, timeperiod=10)
-
- # 添加布林带相关特征
+ macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
+ dataframe["%-macd"] = macd["macd"]
+ dataframe["%-macdsignal"] = macd["macdsignal"]
+
+ # 保留布林带相关特征
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
dataframe["bb_lowerband"] = bollinger["lower"]
dataframe["bb_middleband"] = bollinger["mid"]
dataframe["bb_upperband"] = bollinger["upper"]
dataframe["bb_width"] = (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"]
dataframe["bb_pct"] = (dataframe["close"] - dataframe["bb_lowerband"]) / (dataframe["bb_upperband"] - dataframe["bb_lowerband"])
-
- # 添加成交量相关特征
+
+ # 保留成交量相关特征
dataframe["volume_ma"] = dataframe["volume"].rolling(window=20).mean()
dataframe["volume_roc"] = dataframe["volume"].pct_change(periods=10)
- dataframe["volume_obv"] = ta.OBV(dataframe)
-
- # 添加价格相关特征
- dataframe["close_ma"] = dataframe["close"].rolling(window=20).mean()
+
+ # 保留价格变化率
dataframe["close_roc"] = dataframe["close"].pct_change(periods=10)
- dataframe["close_log_ret"] = np.log(dataframe["close"]).diff()
- dataframe["close_zscore"] = (dataframe["close"] - dataframe["close"].rolling(window=20).mean()) / dataframe["close"].rolling(window=20).std()
-
- # 添加时间相关特征
- dataframe["hour"] = dataframe["date"].dt.hour
- dataframe["day_of_week"] = dataframe["date"].dt.dayofweek
- dataframe["is_weekend"] = dataframe["day_of_week"].isin([5, 6]).astype(int)
-
- # 添加波动率相关特征
- dataframe["volatility"] = dataframe["close"].pct_change().rolling(window=20).std()
- dataframe["volatility_ma"] = dataframe["volatility"].rolling(window=20).mean()
- dataframe["volatility_roc"] = dataframe["volatility"].pct_change(periods=10)
# 改进数据清理
for col in dataframe.columns:
@@ -170,16 +142,23 @@ class FreqaiExampleStrategy(IStrategy):
try:
label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
+
+ # 生成更复杂的目标变量 up_or_down
+ dataframe["up_or_down"] = np.where(
+ dataframe["close"].shift(-label_period) > dataframe["close"], 1, 0
+ )
+ # 确保目标变量是二维数组
+ if dataframe["up_or_down"].ndim == 1:
+ dataframe["up_or_down"] = dataframe["up_or_down"].values.reshape(-1, 1)
+
# 生成 %-volatility 特征
dataframe["%-volatility"] = dataframe["close"].pct_change().rolling(20).std()
- # 单一回归目标
- # 移除对未来的数据依赖
# 确保 &-buy_rsi 列的值计算正确
dataframe["&-buy_rsi"] = ta.RSI(dataframe, timeperiod=14)
# 数据清理
- for col in ["&-buy_rsi"]:
+ for col in ["&-buy_rsi", "up_or_down", "%-volatility"]:
# 使用直接操作避免链式赋值
dataframe[col] = dataframe[col].replace([np.inf, -np.inf], np.nan)
dataframe[col] = dataframe[col].ffill() # 替代 fillna(method='ffill')
@@ -187,19 +166,13 @@ class FreqaiExampleStrategy(IStrategy):
if dataframe[col].isna().any():
logger.warning(f"目标列 {col} 仍包含 NaN填充为默认值")
- # 数据清理
- for col in ["&-buy_rsi", "%-volatility"]:
- # 使用直接操作避免链式赋值
- dataframe[col] = dataframe[col].replace([np.inf, -np.inf], 0)
- dataframe[col] = dataframe[col].ffill() # 替代 fillna(method='ffill')
- dataframe[col] = dataframe[col].fillna(0)
- if dataframe[col].isna().any():
- logger.warning(f"目标列 {col} 仍包含 NaN检查数据生成逻辑")
except Exception as e:
logger.error(f"创建 FreqAI 目标失败:{str(e)}")
raise
- logger.info(f"目标列预览:\n{dataframe[['&-buy_rsi']].head().to_string()}")
+ # Log the shape of the target variable for debugging
+ logger.info(f"目标列形状:{dataframe['up_or_down'].shape}")
+ logger.info(f"目标列预览:\n{dataframe[['up_or_down', '&-buy_rsi']].head().to_string()}")
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
@@ -237,13 +210,13 @@ class FreqaiExampleStrategy(IStrategy):
dataframe[col] = dataframe[col].fillna(-0.1 if col == "&-stoploss" else 0)
# 简化动态参数生成逻辑
-# 简化 buy_rsi 和 sell_rsi 的生成逻辑
+ # 放松 buy_rsi 和 sell_rsi 的生成逻辑
# 计算 buy_rsi_pred 并清理 NaN 值
- dataframe["buy_rsi_pred"] = dataframe["&-buy_rsi"].rolling(window=10).mean().clip(20, 40)
+ dataframe["buy_rsi_pred"] = dataframe["&-buy_rsi"].rolling(window=10).mean().clip(30, 50)
dataframe["buy_rsi_pred"] = dataframe["buy_rsi_pred"].fillna(dataframe["buy_rsi_pred"].mean())
# 计算 sell_rsi_pred 并清理 NaN 值
- dataframe["sell_rsi_pred"] = dataframe["buy_rsi_pred"] + 20
+ dataframe["sell_rsi_pred"] = dataframe["buy_rsi_pred"] + 40
dataframe["sell_rsi_pred"] = dataframe["sell_rsi_pred"].fillna(dataframe["sell_rsi_pred"].mean())
# 计算 stoploss_pred 并清理 NaN 值
@@ -308,8 +281,9 @@ class FreqaiExampleStrategy(IStrategy):
# 改进买入信号条件
enter_long_conditions = [
(df["rsi"] < df["buy_rsi_pred"]), # RSI 低于买入阈值
- (df["volume"] > df["volume"].rolling(window=10).mean()), # 成交量高于近期均值
- (df["close"] > df["bb_middleband"]) # 价格高于布林带中轨
+ (df["volume"] > df["volume"].rolling(window=10).mean() * 1.2), # 成交量高于近期均值20%
+ (df["close"] > df["bb_middleband"]), # 价格高于布林带中轨
+ (df["do_predict"] == 1) # 确保模型预测为买入
]
if enter_long_conditions:
df.loc[

5
4. **清理缓存**: Normal file
View File

@ -0,0 +1,5 @@
<<<<<<< HEAD
=======
rm -rf /freqtrade/user_data/models/test62/
>>>>>>> Snippet

5
5. **重新训练**: Normal file
View File

@ -0,0 +1,5 @@
<<<<<<< HEAD
=======
freqtrade trade --config config_examples/config_freqai.okx.json --strategy FreqaiExampleStrategy
>>>>>>> Snippet

View File

@ -1,48 +0,0 @@
#!/bin/bash
# 脚本名称: filter_freqtrade_logs.sh
# 功能: 实时过滤 Freqtrade 容器日志,捕获包含 "but got Index" 的日志及上下文,输出到文件和终端
# 配置
CONTAINER_NAME="freqtrade_freqtrade_run_ef258891294d" # 容器名称或 ID
OUTPUT_FILE="freqtrade_error_logs.txt" # 输出日志文件
SEARCH_PATTERN="but got Index" # 过滤的关键字
CONTEXT_LINES=5 # 匹配行后的上下文行数
# 检查容器是否存在
if ! docker ps -a --format '{{.Names}}' | grep -q "$CONTAINER_NAME"; then
echo "错误: 容器 $CONTAINER_NAME 不存在。请检查容器名称或 ID。"
exit 1
fi
# 检查容器是否正在运行
if ! docker ps --format '{{.Names}}' | grep -q "$CONTAINER_NAME"; then
echo "警告: 容器 $CONTAINER_NAME 未运行,将获取历史日志。"
RUNNING=false
else
RUNNING=true
fi
# 初始化输出文件
echo "开始过滤日志,输出到 $OUTPUT_FILE ..."
>"$OUTPUT_FILE" # 清空或创建输出文件
# 实时过滤日志
if [ "$RUNNING" = true ]; then
echo "实时监控 $CONTAINER_NAME 的日志,过滤 '$SEARCH_PATTERN'..."
docker logs -f "$CONTAINER_NAME" 2>/dev/null |
stdbuf -oL grep --line-buffered -i -A "$CONTEXT_LINES" "$SEARCH_PATTERN" |
tee -a "$OUTPUT_FILE"
else
echo "获取 $CONTAINER_NAME 的历史日志,过滤 '$SEARCH_PATTERN'..."
docker logs "$CONTAINER_NAME" 2>/dev/null |
grep -i -A "$CONTEXT_LINES" "$SEARCH_PATTERN" |
tee -a "$OUTPUT_FILE"
fi
# 检查是否捕获到日志
if [ -s "$OUTPUT_FILE" ]; then
echo "已捕获日志,保存在 $OUTPUT_FILE"
else
echo "未捕获到包含 '$SEARCH_PATTERN' 的日志,文件 $OUTPUT_FILE 为空"
fi

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,121 @@
diff --git a/config_examples/config_freqai.okx.json b/config_examples/config_freqai.okx.json
index 259459e..c2693fc 100644
--- a/config_examples/config_freqai.okx.json
+++ b/config_examples/config_freqai.okx.json
@@ -5,11 +5,10 @@
"max_open_trades": 4,
"stake_currency": "USDT",
"stake_amount": 150,
- "startup_candle_count": 30,
"tradable_balance_ratio": 1,
"fiat_display_currency": "USD",
"dry_run": true,
- "timeframe": "5m",
+ "timeframe": "3m",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"stoploss": -0.05,
@@ -24,21 +23,21 @@
"enable_ws": false,
"ccxt_config": {
"enableRateLimit": true,
- "rateLimit": 800,
+ "rateLimit": 500,
"options": {
"defaultType": "spot"
}
},
"ccxt_async_config": {
"enableRateLimit": true,
- "rateLimit": 800,
+ "rateLimit": 500,
"timeout": 20000
},
"pair_whitelist": [
- "OKB/USDT",
- "DOT/USDT",
+ "BTC/USDT",
"SOL/USDT"
- ]
+ ],
+ "pair_blacklist": []
},
"entry_pricing": {
"price_side": "same",
@@ -65,47 +64,37 @@
"data_kitchen": {
"fillna": "ffill"
},
- "freqaimodel": "CatboostClassifier",
- "purge_old_models": 2,
- "identifier": "test175",
- "train_period_days": 30,
- "backtest_period_days": 10,
+ "freqaimodel": "XGBoostRegressor",
+ "model_training_parameters": {
+ "n_estimators": 100,
+ "learning_rate": 0.05,
+ "max_depth": 5
+ },
+ "train_period_days": 180,
+ "backtest_period_days": 60,
"live_retrain_hours": 0,
"feature_selection": {
"method": "recursive_elimination"
},
"feature_parameters": {
- "include_timeframes": [
- "5m",
- "1h"
- ],
- "include_corr_pairlist": [
- "BTC/USDT",
- "ETH/USDT"
- ],
- "label_period_candles": 12,
- "include_shifted_candles": 3,
- "DI_threshold": 0.9,
+ "include_timeframes": ["15m"],
+ "include_corr_pairlist": ["BTC/USDT"],
+ "label_period_candles": 10,
+ "include_shifted_candles": 1,
+
"weight_factor": 0.9,
"principal_component_analysis": false,
"use_SVM_to_remove_outliers": false,
- "indicator_periods_candles": [
- 10,
- 20,
- 50
- ],
- "plot_feature_importances": 0
+ "indicator_periods_candles": [14],
},
"data_split_parameters": {
- "test_size": 0.2,
- "shuffle": false,
+ "test_size": 0.2
},
- "model_training_parameters": {
- "n_estimators": 100,
- "learning_rate": 0.1,
- "num_leaves": 15,
- "verbose": -1
- }
+ "model_training_parameters": {
+ "n_estimators": 100,
+ "learning_rate": 0.05,
+ "max_depth": 5
+ }
},
"api_server": {
"enabled": true,
@@ -123,7 +112,7 @@
"initial_state": "running",
"force_entry_enable": false,
"internals": {
- "process_throttle_secs": 10,
+ "process_throttle_secs": 5,
"heartbeat_interval": 20,
"loglevel": "DEBUG"
}

View File

@ -9,7 +9,7 @@
"tradable_balance_ratio": 1,
"fiat_display_currency": "USD",
"dry_run": true,
"timeframe": "5m",
"timeframe": "3m",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"stoploss": -0.05,
@ -24,20 +24,21 @@
"enable_ws": false,
"ccxt_config": {
"enableRateLimit": true,
"rateLimit": 800,
"rateLimit": 500,
"options": {
"defaultType": "spot"
}
},
"ccxt_async_config": {
"enableRateLimit": true,
"rateLimit": 800,
"rateLimit": 500,
"timeout": 20000
},
"pair_whitelist": [
"BTC/USDT",
"SOL/USDT"
]
],
"pair_blacklist": []
},
"entry_pricing": {
"price_side": "same",
@ -62,48 +63,48 @@
"freqai": {
"enabled": true,
"data_kitchen": {
"fillna": "ffill"
"fillna": "ffill",
"feature_parameters": {
"DI_threshold": 0.9,
"weight_factor": 0.9
}
},
"freqaimodel": "CatboostClassifier",
"freqaimodel": "XGBoostRegressor",
"purge_old_models": 2,
"identifier": "test178",
"identifier": "test175",
"train_period_days": 30,
"backtest_period_days": 10,
"live_retrain_hours": 0,
"feature_selection": {
"method": "recursive_elimination"
"method": "recursive_elimination",
"threshold": 0.01,
"steps": 1,
"cv": 5,
"n_features_to_select": null
},
"feature_parameters": {
"include_timeframes": [
"5m",
"1h"
],
"include_corr_pairlist": [
"BTC/USDT",
"SOL/USDT"
],
"include_timeframes": ["3m", "5m", "1h"],
"include_corr_pairlist": ["BTC/USDT", "ETH/USDT"],
"label_period_candles": 12,
"include_shifted_candles": 3,
"DI_threshold": 0.9,
"weight_factor": 0.9,
"principal_component_analysis": false,
"use_SVM_to_remove_outliers": false,
"indicator_periods_candles": [
10,
20,
50
],
"plot_feature_importances": 0
"indicator_periods_candles": [10, 20, 50],
"plot_feature_importances": 1
},
"data_split_parameters": {
"test_size": 0.2,
"shuffle": false,
"shuffle": true,
"random_state": 42
},
"model_training_parameters": {
"n_estimators": 100,
"learning_rate": 0.1,
"num_leaves": 15,
"verbose": -1
"max_depth": 5,
"subsample": 0.8,
"colsample_bytree": 0.8,
"objective": "reg:squarederror",
"eval_metric": "rmse",
"early_stopping_rounds": 50,
"verbose": 0
}
},
"api_server": {
@ -122,7 +123,7 @@
"initial_state": "running",
"force_entry_enable": false,
"internals": {
"process_throttle_secs": 10,
"process_throttle_secs": 5,
"heartbeat_interval": 20,
"loglevel": "DEBUG"
}

View File

@ -0,0 +1,122 @@
diff --git a/config_examples/config_freqai.okx.json b/config_examples/config_freqai.okx.json
index 259459e..c8f04af 100644
--- a/config_examples/config_freqai.okx.json
+++ b/config_examples/config_freqai.okx.json
@@ -5,11 +5,10 @@
"max_open_trades": 4,
"stake_currency": "USDT",
"stake_amount": 150,
- "startup_candle_count": 30,
"tradable_balance_ratio": 1,
"fiat_display_currency": "USD",
"dry_run": true,
- "timeframe": "5m",
+ "timeframe": "3m",
"dry_run_wallet": 1000,
"cancel_open_orders_on_exit": true,
"stoploss": -0.05,
@@ -24,21 +23,21 @@
"enable_ws": false,
"ccxt_config": {
"enableRateLimit": true,
- "rateLimit": 800,
+ "rateLimit": 500,
"options": {
"defaultType": "spot"
}
},
"ccxt_async_config": {
"enableRateLimit": true,
- "rateLimit": 800,
+ "rateLimit": 500,
"timeout": 20000
},
"pair_whitelist": [
- "OKB/USDT",
- "DOT/USDT",
+ "BTC/USDT",
"SOL/USDT"
- ]
+ ],
+ "pair_blacklist": []
},
"entry_pricing": {
"price_side": "same",
@@ -65,47 +64,38 @@
"data_kitchen": {
"fillna": "ffill"
},
- "freqaimodel": "CatboostClassifier",
- "purge_old_models": 2,
- "identifier": "test175",
- "train_period_days": 30,
- "backtest_period_days": 10,
+ "freqaimodel": "XGBoostRegressor",
+ "model_training_parameters": {
+ "n_estimators": 100,
+ "learning_rate": 0.05,
+ "max_depth": 5
+ },
+ "train_period_days": 15,
+ "train_period_days": 180,
+ "backtest_period_days": 60,
"live_retrain_hours": 0,
"feature_selection": {
"method": "recursive_elimination"
},
"feature_parameters": {
- "include_timeframes": [
- "5m",
- "1h"
- ],
- "include_corr_pairlist": [
- "BTC/USDT",
- "ETH/USDT"
- ],
- "label_period_candles": 12,
- "include_shifted_candles": 3,
- "DI_threshold": 0.9,
+ "include_timeframes": ["15m"],
+ "include_corr_pairlist": ["BTC/USDT"],
+ "label_period_candles": 10,
+ "include_shifted_candles": 1,
+
"weight_factor": 0.9,
"principal_component_analysis": false,
"use_SVM_to_remove_outliers": false,
- "indicator_periods_candles": [
- 10,
- 20,
- 50
- ],
- "plot_feature_importances": 0
+ "indicator_periods_candles": [14],
},
"data_split_parameters": {
- "test_size": 0.2,
- "shuffle": false,
+ "test_size": 0.2
},
- "model_training_parameters": {
- "n_estimators": 100,
- "learning_rate": 0.1,
- "num_leaves": 15,
- "verbose": -1
- }
+ "model_training_parameters": {
+ "n_estimators": 100,
+ "learning_rate": 0.05,
+ "max_depth": 5
+ }
},
"api_server": {
"enabled": true,
@@ -123,7 +113,7 @@
"initial_state": "running",
"force_entry_enable": false,
"internals": {
- "process_throttle_secs": 10,
+ "process_throttle_secs": 5,
"heartbeat_interval": 20,
"loglevel": "DEBUG"
}

View File

@ -23,7 +23,6 @@ services:
- "./config_examples:/freqtrade/config_examples"
- "./freqtrade/templates:/freqtrade/templates"
- "./freqtrade/exchange/:/freqtrade/exchange"
- "./ccxt/async_support/okx.py:/home/ftuser/.local/lib/python3.12/site-packages/ccxt/async_support/okx.py"
# Expose api on port 8080 (localhost only)
# Please read the https://www.freqtrade.io/en/stable/rest-api/ documentation
# for more information.
@ -32,15 +31,15 @@ services:
# Default command used when running `docker compose up`
# --freqaimodel XGBoostRegressor
command: >
trade
--logfile /freqtrade/user_data/logs/freqtrade.log
--db-url sqlite:////freqtrade/user_data/tradesv3.sqlite
--freqaimodel XGBoostRegressor
--config /freqtrade/config_examples/config_freqai.okx.json
--strategy FreqaiExampleStrategy
--strategy-path /freqtrade/templates
--fee 0.0008
# commangd: >
# # trade
# --logfile /freqtrade/user_data/logs/freqtrade.log
# --db-url sqlite:////freqtrade/user_data/tradesv3.sqlite
# --freqaimodel LightGBMRegressor
# --config /freqtrade/config_examples/config_freqai.okx.json
# --strategy FreqaiExampleStrategy
# --strategy FreqaiExampleHybridStrategy
# --strategy-path /freqtrade/templates
# command: >
# backtesting
# --logfile /freqtrade/user_data/logs/freqtrade.log
@ -61,34 +60,14 @@ services:
# --hyperopt-loss SharpeHyperOptLoss
# --spaces roi stoploss
# -e 200
# --config /freqtrade/templates/FreqaiExampleStrategy.json
# command: >
# backtesting
# --logfile /freqtrade/user_data/logs/freqtrade.log
# --freqaimodel XGBoostRegressor
# --config /freqtrade/config_examples/config_freqai.okx.json
# --strategy-path /freqtrade/templates
# --strategy FreqaiExampleStrategy
# --timerange 20250101-20250420
# --fee 0.0008
# command: >
# download-data
# --config /freqtrade/config_examples/config_freqai.okx.json
# --exchange okx
# --pairs DOT/USDT
# --timeframe 1h 5m
# --timerange 20240101-20250420
#
# command: >
# hyperopt
# --logfile /freqtrade/user_data/logs/freqtrade.log
# --freqaimodel LightGBMRegressor
# --config /freqtrade/config_examples/config_freqai.okx.json
# --strategy-path /freqtrade/templates
# --strategy FreqaiExampleStrategy
# --timerange 20250301-20250420
# --hyperopt-loss SharpeHyperOptLoss
# --spaces buy sell roi stoploss trailing
# --fee 0.001
# -e 200
command: >
backtesting
--logfile /freqtrade/user_data/logs/freqtrade.log
--freqaimodel XGBoostRegressor
--config /freqtrade/config_examples/config_freqai.okx.json
--config /freqtrade/templates/FreqaiExampleStrategy.json
--strategy-path /freqtrade/templates
--strategy FreqaiExampleStrategy
--timerange 20250401-20250420
--cache none

7
filter.py Normal file
View File

@ -0,0 +1,7 @@
with open('output.log', 'r') as input_file, open('output_filted.log', 'w') as output_file:
for line in input_file:
if "validation_0" in line:
if "[99]" in line:
output_file.write(line)
else:
output_file.write(line)

1162
freqai/data_kitchen.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -52,7 +52,9 @@ class FreqaiExampleHybridStrategy(IStrategy):
"random_state": 1
},
"model_training_parameters": {
"n_estimators": 800
"n_estimators": 200,
"max_depth": 5,
"learning_rate": 0.05
}
},
@ -122,13 +124,11 @@ class FreqaiExampleHybridStrategy(IStrategy):
"""
dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period)
dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period)
dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period)
dataframe["%-sma-period"] = ta.SMA(dataframe, timeperiod=period)
dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period)
bollinger = qtpylib.bollinger_bands(
qtpylib.typical_price(dataframe), window=period, stds=2.2
qtpylib.typical_price(dataframe), window=period, stds=2
)
dataframe["bb_lowerband-period"] = bollinger["lower"]
dataframe["bb_middleband-period"] = bollinger["mid"]
@ -137,13 +137,6 @@ class FreqaiExampleHybridStrategy(IStrategy):
dataframe["%-bb_width-period"] = (
dataframe["bb_upperband-period"] - dataframe["bb_lowerband-period"]
) / dataframe["bb_middleband-period"]
dataframe["%-close-bb_lower-period"] = dataframe["close"] / dataframe["bb_lowerband-period"]
dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period)
dataframe["%-relative_volume-period"] = (
dataframe["volume"] / dataframe["volume"].rolling(period).mean()
)
return dataframe
@ -177,8 +170,7 @@ class FreqaiExampleHybridStrategy(IStrategy):
dataframe["%-ema-200"] = ta.EMA(dataframe, timeperiod=200)
"""
dataframe["%-pct-change"] = dataframe["close"].pct_change()
dataframe["%-raw_volume"] = dataframe["volume"]
dataframe["%-raw_price"] = dataframe["close"]
return dataframe
def feature_engineering_standard(
@ -209,10 +201,10 @@ class FreqaiExampleHybridStrategy(IStrategy):
dataframe["%-hour_of_day"] = dataframe["date"].dt.hour
return dataframe
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
"""
Redefined target variable to predict whether the price will increase or decrease in the future.
"""
logger.info(f"Setting FreqAI targets for pair: {metadata['pair']}")
logger.info(f"DataFrame shape: {dataframe.shape}")
logger.info(f"Available columns: {list(dataframe.columns)}")
logger.info(f"First few rows:\n{dataframe[['date', 'close']].head().to_string()}")
if "close" not in dataframe.columns:
logger.error("Required 'close' column missing in dataframe")
@ -223,22 +215,16 @@ class FreqaiExampleHybridStrategy(IStrategy):
raise ValueError("Insufficient data for target calculation")
try:
# 生成数值型标签1 表示上涨0 表示下跌
# Define target variable: 1 for price increase, 0 for price decrease
dataframe["&-up_or_down"] = np.where(
dataframe["close"].shift(-50) > dataframe["close"],
1.0, # 数值型标签
0.0
dataframe["close"].shift(-50) > dataframe["close"], 1, 0
)
# Ensure target variable is a 2D array
dataframe["&-up_or_down"] = dataframe["&-up_or_down"].values.reshape(-1, 1)
except Exception as e:
logger.error(f"Failed to create &-up_or_down column: {str(e)}")
raise
logger.info(f"Target column head:\n{dataframe[['&-up_or_down']].head().to_string()}")
if "&-up_or_down" not in dataframe.columns:
logger.error("FreqAI failed to generate the &-up_or_down column")
raise KeyError("FreqAI failed to generate the &-up_or_down column")
logger.info("FreqAI targets set successfully")
return dataframe

View File

@ -1,262 +0,0 @@
diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py
index 343c073..1d7ed33 100644
--- a/freqtrade/templates/FreqaiExampleStrategy.py
+++ b/freqtrade/templates/FreqaiExampleStrategy.py
@@ -11,9 +11,9 @@ logger = logging.getLogger(__name__)
class FreqaiExampleStrategy(IStrategy):
minimal_roi = {
- "0": 0.076,
- "7": 0.034,
- "13": 0.007,
+ "0": 0.02,
+ "7": 0.01,
+ "13": 0.005,
"60": 0
}
@@ -24,29 +24,25 @@ class FreqaiExampleStrategy(IStrategy):
startup_candle_count: int = 40
can_short = False
- # Hyperopt 参数
buy_rsi = IntParameter(low=10, high=50, default=27, space="buy", optimize=True, load=True)
sell_rsi = IntParameter(low=50, high=90, default=59, space="sell", optimize=True, load=True)
roi_0 = DecimalParameter(low=0.01, high=0.2, default=0.038, space="roi", optimize=True, load=True)
roi_15 = DecimalParameter(low=0.005, high=0.1, default=0.027, space="roi", optimize=True, load=True)
roi_30 = DecimalParameter(low=0.001, high=0.05, default=0.009, space="roi", optimize=True, load=True)
stoploss_param = DecimalParameter(low=-0.25, high=-0.05, default=-0.1, space="stoploss", optimize=True, load=True)
- trailing_stop_positive_offset = DecimalParameter(low=0.01, high=0.5, default=0.02, space="trailing", optimize=True, load=True)
+ trailing_stop_positive_offset = DecimalParameter(low=0.005, high=0.5, default=0.01, space="trailing", optimize=True, load=True)
- protections = [
- {"method": "StoplossGuard", "stop_duration": 60, "lookback_period": 120},
- {"method": "MaxDrawdown", "lookback_period": 120, "max_allowed_drawdown": 0.05}
- ]
+ protections = []
freqai_info = {
"model": "LightGBMRegressor",
"feature_parameters": {
"include_timeframes": ["5m"],
- "include_corr_pairlist": ["SOL/USDT", "BTC/USDT"],
+ "include_corr_pairlist": ["SOL/USDT"],
"label_period_candles": 12,
"include_shifted_candles": 0,
- "include_periods": [10, 20],
- "DI_threshold": 3.0
+ "include_periods": [20],
+ "DI_threshold": 5.0
},
"data_split_parameters": {
"test_size": 0.2,
@@ -62,14 +58,20 @@ class FreqaiExampleStrategy(IStrategy):
}
plot_config = {
- "main_plot": {},
+ "main_plot": {
+ "close": {"color": "blue"},
+ "bb_lowerband": {"color": "purple"}
+ },
"subplots": {
"&-buy_rsi": {"&-buy_rsi": {"color": "green"}},
"&-sell_rsi": {"&-sell_rsi": {"color": "red"}},
- "&-stoploss": {"&-stoploss": {"color": "purple"}},
- "&-roi_0": {"&-roi_0": {"color": "orange"}},
+ "rsi": {"rsi": {"color": "black"}},
"do_predict": {"do_predict": {"color": "brown"}},
- },
+ "trade_signals": {
+ "enter_long": {"color": "green", "type": "scatter"},
+ "exit_long": {"color": "red", "type": "scatter"}
+ }
+ }
}
def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, metadata: dict, **kwargs) -> DataFrame:
@@ -130,12 +132,10 @@ class FreqaiExampleStrategy(IStrategy):
logger.info(f"DataFrame rows: {len(dataframe)}")
logger.info(f"Columns before freqai.start: {list(dataframe.columns)}")
- # 验证输入数据
if "close" not in dataframe.columns or dataframe["close"].isna().all():
logger.error(f"DataFrame missing 'close' column or all NaN for pair: {metadata['pair']}")
raise ValueError("DataFrame missing valid 'close' column")
- # 生成 RSI
if len(dataframe) < 14:
logger.warning(f"DataFrame too short ({len(dataframe)} rows), cannot compute rsi")
dataframe["rsi"] = 50
@@ -143,7 +143,6 @@ class FreqaiExampleStrategy(IStrategy):
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
logger.info(f"rsi stats: {dataframe['rsi'].describe().to_string()}")
- # 生成 %-volatility
if len(dataframe) < 20 or dataframe["close"].isna().any():
logger.warning(f"DataFrame too short ({len(dataframe)} rows) or contains NaN in close, cannot compute %-volatility")
dataframe["%-volatility"] = 0
@@ -154,7 +153,6 @@ class FreqaiExampleStrategy(IStrategy):
dataframe["%-volatility"] = (dataframe["%-volatility"] - dataframe["%-volatility"].mean()) / dataframe["%-volatility"].std()
logger.info(f"%-volatility stats: {dataframe['%-volatility'].describe().to_string()}")
- # 生成 TEMA
if len(dataframe) < 9:
logger.warning(f"DataFrame too short ({len(dataframe)} rows), cannot compute tema")
dataframe["tema"] = dataframe["close"]
@@ -165,7 +163,6 @@ class FreqaiExampleStrategy(IStrategy):
dataframe["tema"] = dataframe["tema"].fillna(dataframe["close"])
logger.info(f"tema stats: {dataframe['tema'].describe().to_string()}")
- # 生成 Bollinger Bands
if len(dataframe) < 20:
logger.warning(f"DataFrame too short ({len(dataframe)} rows), cannot compute bb_lowerband")
dataframe["bb_lowerband"] = dataframe["close"]
@@ -177,21 +174,6 @@ class FreqaiExampleStrategy(IStrategy):
dataframe["bb_lowerband"] = dataframe["bb_lowerband"].fillna(dataframe["close"])
logger.info(f"bb_lowerband stats: {dataframe['bb_lowerband'].describe().to_string()}")
- # 生成 up_or_down
- label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
- if len(dataframe) < label_period + 1:
- logger.warning(f"DataFrame too short ({len(dataframe)} rows), cannot compute up_or_down")
- dataframe["up_or_down"] = 0
- else:
- dataframe["up_or_down"] = np.where(
- dataframe["close"].shift(-label_period) > dataframe["close"], 1, 0
- )
- if dataframe["up_or_down"].isna().any():
- logger.warning("up_or_down contains NaN, filling with 0")
- dataframe["up_or_down"] = dataframe["up_or_down"].fillna(0)
- logger.info(f"up_or_down stats: {dataframe['up_or_down'].describe().to_string()}")
-
- # 生成其他特征
if "date" in dataframe.columns:
dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek
dataframe["%-hour_of_day"] = dataframe["date"].dt.hour
@@ -200,7 +182,6 @@ class FreqaiExampleStrategy(IStrategy):
dataframe["%-day_of_week"] = 0
dataframe["%-hour_of_day"] = 0
- # 调用 FreqAI
try:
dataframe = self.freqai.start(dataframe, metadata, self)
logger.info(f"Columns after freqai.start: {list(dataframe.columns)}")
@@ -210,26 +191,23 @@ class FreqaiExampleStrategy(IStrategy):
dataframe["sell_rsi_pred"] = 80
dataframe["do_predict"] = 1
- # 检查预测列
for col in ["buy_rsi_pred", "sell_rsi_pred"]:
if col not in dataframe.columns:
logger.error(f"Error: {col} column not generated for pair: {metadata['pair']}")
dataframe[col] = 50 if col == "buy_rsi_pred" else 80
logger.info(f"{col} stats: {dataframe[col].describe().to_string()}")
- # 调试特征分布
- if "%-bb_width-period_10_SOL/USDT_5m" in dataframe.columns:
- if dataframe["%-bb_width-period_10_SOL/USDT_5m"].std() > 0:
- dataframe["%-bb_width-period_10_SOL/USDT_5m"] = (
- dataframe["%-bb_width-period_10_SOL/USDT_5m"] - dataframe["%-bb_width-period_10_SOL/USDT_5m"].mean()
- ) / dataframe["%-bb_width-period_10_SOL/USDT_5m"].std()
- logger.info(f"%-bb_width-period_10 stats: {dataframe['%-bb_width-period_10_SOL/USDT_5m'].describe().to_string()}")
+ if "%-bb_width-period_20_SOL/USDT_5m" in dataframe.columns:
+ if dataframe["%-bb_width-period_20_SOL/USDT_5m"].std() > 0:
+ dataframe["%-bb_width-period_20_SOL/USDT_5m"] = (
+ dataframe["%-bb_width-period_20_SOL/USDT_5m"] - dataframe["%-bb_width-period_20_SOL/USDT_5m"].mean()
+ ) / dataframe["%-bb_width-period_20_SOL/USDT_5m"].std()
+ logger.info(f"%-bb_width-period_20 stats: {dataframe['%-bb_width-period_20_SOL/USDT_5m'].describe().to_string()}")
- # 动态生成期望的特征列
def get_expected_columns(freqai_config: dict) -> list:
indicators = ["rsi", "bb_width", "pct-change"]
- periods = freqai_config.get("feature_parameters", {}).get("include_periods", [10, 20])
- pairs = freqai_config.get("include_corr_pairlist", ["SOL/USDT", "BTC/USDT"])
+ periods = freqai_config.get("feature_parameters", {}).get("include_periods", [20])
+ pairs = freqai_config.get("include_corr_pairlist", ["SOL/USDT"])
timeframes = freqai_config.get("include_timeframes", ["5m"])
shifts = [0]
expected_columns = ["%-volatility", "%-day_of_week", "%-hour_of_day"]
@@ -248,50 +226,47 @@ class FreqaiExampleStrategy(IStrategy):
expected_columns = get_expected_columns(self.freqai_info)
logger.info(f"Expected feature columns ({len(expected_columns)}): {expected_columns[:10]}...")
- # 比较特征集
actual_columns = list(dataframe.columns)
missing_columns = [col for col in expected_columns if col not in actual_columns]
extra_columns = [col for col in actual_columns if col not in expected_columns and col.startswith("%-")]
logger.info(f"Missing columns ({len(missing_columns)}): {missing_columns}")
logger.info(f"Extra columns ({len(extra_columns)}): {extra_columns}")
- # 调试 DI 丢弃预测
if "DI_values" in dataframe.columns:
logger.info(f"DI_values stats: {dataframe['DI_values'].describe().to_string()}")
logger.info(f"DI discarded predictions: {len(dataframe[dataframe['do_predict'] == 0])}")
- # 清理数据
dataframe = dataframe.replace([np.inf, -np.inf], 0).ffill().fillna(0)
logger.info(f"Final columns in populate_indicators: {list(dataframe.columns)}")
return dataframe
def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
enter_long_conditions = [
- qtpylib.crossed_above(df["rsi"], df["buy_rsi_pred"] + (5 if metadata["pair"] == "BTC/USDT" else 0)),
+ qtpylib.crossed_above(df["rsi"], df["buy_rsi_pred"]),
df["tema"] > df["tema"].shift(1),
df["volume"] > 0,
- df["do_predict"] == 1,
- df["up_or_down"] == 1
+ df["do_predict"] == 1
]
- if enter_long_conditions:
- df.loc[
- reduce(lambda x, y: x & y, enter_long_conditions),
- ["enter_long", "enter_tag"]
- ] = (1, "long")
+ df["entry_signal"] = reduce(lambda x, y: x & y, enter_long_conditions)
+ df["entry_signal"] = df["entry_signal"].rolling(window=2, min_periods=1).max().astype(bool)
+ df.loc[
+ df["entry_signal"],
+ ["enter_long", "enter_tag"]
+ ] = (1, "long")
+ if df["entry_signal"].iloc[-1]:
+ logger.info(f"Entry signal triggered for {metadata['pair']}: rsi={df['rsi'].iloc[-1]}, buy_rsi_pred={df['buy_rsi_pred'].iloc[-1]}, do_predict={df['do_predict'].iloc[-1]}")
return df
def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
exit_long_conditions = [
- (qtpylib.crossed_above(df["rsi"], df["sell_rsi_pred"])) |
+ (qtpylib.crossed_above(df["rsi"], df["sell_rsi_pred"] - 5)) |
(df["close"] < df["close"].shift(1) * 0.98) |
(df["close"] < df["bb_lowerband"]),
df["volume"] > 0,
- df["do_predict"] == 1,
- df["up_or_down"] == 0
+ df["do_predict"] == 1
]
- time_exit = (df["date"] >= df["date"].shift(1) + pd.Timedelta(days=1))
df.loc[
- (reduce(lambda x, y: x & y, exit_long_conditions)) | time_exit,
+ reduce(lambda x, y: x & y, exit_long_conditions),
"exit_long"
] = 1
return df
@@ -300,9 +275,16 @@ class FreqaiExampleStrategy(IStrategy):
self, pair: str, order_type: str, amount: float, rate: float,
time_in_force: str, current_time, entry_tag, side: str, **kwargs
) -> bool:
+ logger.info(f"Confirming trade entry for {pair}, order_type: {order_type}, rate: {rate}, current_time: {current_time}")
df, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = df.iloc[-1].squeeze()
if side == "long":
- if rate > (last_candle["close"] * (1 + 0.001)):
- return False
+ if order_type == "market":
+ logger.info(f"Order confirmed for {pair}, rate: {rate} (market order)")
+ return True
+ if rate <= (last_candle["close"] * (1 + 0.01)):
+ logger.info(f"Order confirmed for {pair}, rate: {rate}")
+ return True
+ logger.info(f"Order rejected: rate {rate} exceeds threshold {last_candle['close'] * 1.01}")
+ return False
return True

View File

@ -1,32 +1,32 @@
{
"strategy_name": "FreqaiExampleStrategy",
"params": {
"trailing": {
"trailing_stop": true,
"trailing_stop_positive": 0.01,
"trailing_stop_positive_offset": 0.02,
"trailing_only_offset_is_reached": false
},
"max_open_trades": {
"max_open_trades": 4
},
"buy": {
"buy_rsi": 37
"buy_rsi": 39.92672300850069
},
"sell": {
"sell_rsi": 80
"sell_rsi": 69.92672300850067
},
"protection": {},
"roi": {
"0": 0.124,
"14": 0.023,
"37": 0.011,
"50": 0
"0": 0.132,
"8": 0.047,
"14": 0.007,
"60": 0
},
"stoploss": {
"stoploss": -0.168
},
"trailing": {
"trailing_stop": true,
"trailing_stop_positive": 0.047,
"trailing_stop_positive_offset": 0.051000000000000004,
"trailing_only_offset_is_reached": true
"stoploss": -0.322
}
},
"ft_stratparam_v": 1,
"export_time": "2025-04-24 11:42:35.037486+00:00"
"export_time": "2025-04-23 12:30:05.550433+00:00"
}

View File

@ -1,32 +0,0 @@
{
"strategy_name": "FreqaiExampleStrategy",
"params": {
"trailing": {
"trailing_stop": true,
"trailing_stop_positive": 0.01,
"trailing_stop_positive_offset": 0.02,
"trailing_only_offset_is_reached": false
},
"max_open_trades": {
"max_open_trades": 4
},
"buy": {
"buy_rsi": 39.92672300850069
},
"sell": {
"sell_rsi": 69.92672300850067
},
"protection": {},
"roi": {
"0": 0.132,
"8": 0.047,
"14": 0.007,
"60": 0
},
"stoploss": {
"stoploss": -0.322
}
},
"ft_stratparam_v": 1,
"export_time": "2025-04-23 12:30:05.550433+00:00"
}

View File

@ -1,6 +1,5 @@
import logging
import numpy as np
import pandas as pd
from functools import reduce
import talib.abstract as ta
from pandas import DataFrame
@ -10,296 +9,433 @@ from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter
logger = logging.getLogger(__name__)
class FreqaiExampleStrategy(IStrategy):
minimal_roi = {
"0": 0.02,
"7": 0.01,
"13": 0.005,
"60": 0
}
stoploss = 0.0
# 移除硬编码的 minimal_roi 和 stoploss改为动态适配
minimal_roi = {} # 将在 populate_indicators 中动态生成
stoploss = 0.0 # 将在 populate_indicators 中动态设置
trailing_stop = True
process_only_new_candles = True
use_exit_signal = True
startup_candle_count: int = 40
can_short = False
buy_rsi = IntParameter(low=10, high=40, default=20, space="buy", optimize=True, load=True)
sell_rsi = IntParameter(low=50, high=90, default=59, space="sell", optimize=True, load=True)
# 参数定义FreqAI 动态适配 buy_rsi 和 sell_rsi禁用 Hyperopt 优化
buy_rsi = IntParameter(low=10, high=50, default=27, space="buy", optimize=False, load=True)
sell_rsi = IntParameter(low=50, high=90, default=59, space="sell", optimize=False, load=True)
# 为 Hyperopt 优化添加 ROI 和 stoploss 参数
roi_0 = DecimalParameter(low=0.01, high=0.2, default=0.038, space="roi", optimize=True, load=True)
roi_15 = DecimalParameter(low=0.005, high=0.1, default=0.027, space="roi", optimize=True, load=True)
roi_30 = DecimalParameter(low=0.001, high=0.05, default=0.009, space="roi", optimize=True, load=True)
stoploss_param = DecimalParameter(low=-0.25, high=-0.05, default=-0.1, space="stoploss", optimize=True, load=True)
trailing_stop_positive_offset = DecimalParameter(low=0.005, high=0.5, default=0.01, space="trailing", optimize=True, load=True)
protections = []
stoploss_param = DecimalParameter(low=-0.35, high=-0.1, default=-0.182, space="stoploss", optimize=True, load=True)
# FreqAI 配置
freqai_info = {
"model": "LightGBMRegressor",
"model": "CatboostClassifier", # 与config保持一致
"feature_parameters": {
"include_timeframes": ["5m"],
"include_corr_pairlist": ["OKB/USDT", "SOL/USDT"], # 与白名单一致
"label_period_candles": 12,
"include_shifted_candles": 0,
"include_periods": [20],
"DI_threshold": 1.5 # 提高以减少丢弃预测
"include_timeframes": ["3m", "15m", "1h"], # 与config一致
"include_corr_pairlist": ["BTC/USDT", "SOL/USDT"], # 添加相关交易对
"label_period_candles": 20, # 与config一致
"include_shifted_candles": 2, # 与config一致
},
"data_split_parameters": {
"test_size": 0.2,
"shuffle": False,
"shuffle": True, # 启用shuffle
},
"model_training_parameters": {
"n_estimators": 100,
"learning_rate": 0.1,
"num_leaves": 15,
"n_jobs": 4,
"verbosity": -1
"n_estimators": 100, # 减少树的数量
"learning_rate": 0.1, # 提高学习率
"max_depth": 6, # 限制树深度
"subsample": 0.8, # 添加子采样
"colsample_bytree": 0.8, # 添加特征采样
"objective": "reg:squarederror",
"eval_metric": "rmse",
"early_stopping_rounds": 20,
"verbose": 0,
},
}
plot_config = {
"main_plot": {
"close": {"color": "blue"},
"bb_lowerband": {"color": "purple"}
},
"subplots": {
"&-buy_rsi": {"&-buy_rsi": {"color": "green"}},
"&-sell_rsi": {"&-sell_rsi": {"color": "red"}},
"rsi": {"rsi": {"color": "black"}},
"do_predict": {"do_predict": {"color": "brown"}},
"trade_signals": {
"enter_long": {"color": "green", "type": "scatter"},
"exit_long": {"color": "red", "type": "scatter"}
"data_kitchen": {
"feature_parameters": {
"DI_threshold": 1.5, # 降低异常值过滤阈值
"use_DBSCAN_to_remove_outliers": False # 禁用DBSCAN
}
}
}
def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, metadata: dict, **kwargs) -> DataFrame:
dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period)
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=period, stds=2.2)
dataframe["%-bb_width-period"] = (bollinger["upper"] - bollinger["lower"]) / bollinger["mid"]
dataframe = dataframe.replace([np.inf, -np.inf], 0).ffill().fillna(0)
plot_config = {
"main_plot": {},
"subplots": {
"&-buy_rsi": {"&-buy_rsi": {"color": "green"}},
"&-sell_rsi": {"&-sell_rsi": {"color": "red"}},
"&-stoploss": {"&-stoploss": {"color": "purple"}},
"&-roi_0": {"&-roi_0": {"color": "orange"}},
"do_predict": {"do_predict": {"color": "brown"}},
},
}
def featcaure_engineering_expand_all(self, dataframe: DataFrame, period: int, metadata: dict, **kwargs) -> DataFrame:
# 只计算必要的技术指标
if len(dataframe) > 14:
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
dataframe["ema_12"] = ta.EMA(dataframe, timeperiod=12)
dataframe["ema_26"] = ta.EMA(dataframe, timeperiod=26)
else:
dataframe["rsi"] = 50
dataframe["ema_12"] = dataframe["close"]
dataframe["ema_26"] = dataframe["close"]
# 确保 MACD 列被正确计算并保留
# 确保有足够的数据计算 MACD
if len(dataframe) >= 50:
macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
dataframe["macd"] = macd["macd"]
dataframe["macdsignal"] = macd["macdsignal"]
dataframe["macdhist"] = macd["macdhist"]
else:
dataframe["macd"] = 0
dataframe["macdsignal"] = 0
dataframe["macdhist"] = 0
# 检查 MACD 列是否存在
if "macd" not in dataframe.columns or "macdsignal" not in dataframe.columns:
logger.error("MACD 或 MACD 信号列缺失,无法生成买入信号")
raise ValueError("DataFrame 缺少必要的 MACD 列")
# 确保 MACD 列存在
if "macd" not in dataframe.columns or "macdsignal" not in dataframe.columns:
logger.error("MACD 或 MACD 信号列缺失,无法生成买入信号")
raise ValueError("DataFrame 缺少必要的 MACD 列")
# 保留布林带相关特征
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
dataframe["bb_lowerband"] = bollinger["lower"]
dataframe["bb_middleband"] = bollinger["mid"]
dataframe["bb_upperband"] = bollinger["upper"]
# 保留成交量相关特征
dataframe["volume_ma"] = dataframe["volume"].rolling(window=20).mean()
# 数据清理
for col in dataframe.columns:
if dataframe[col].dtype in ["float64", "int64"]:
dataframe[col] = dataframe[col].replace([np.inf, -np.inf], np.nan)
dataframe[col] = dataframe[col].ffill().fillna(0)
logger.info(f"特征工程完成,特征数量:{len(dataframe.columns)}")
return dataframe
def feature_engineering_expand_basic(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
dataframe["%-pct-change"] = dataframe["close"].pct_change()
dataframe = dataframe.replace([np.inf, -np.inf], 0).ffill().fillna(0)
dataframe["%-raw_volume"] = dataframe["volume"]
dataframe["%-raw_price"] = dataframe["close"]
# 数据清理逻辑
for col in dataframe.columns:
if dataframe[col].dtype in ["float64", "int64"]:
dataframe[col] = dataframe[col].replace([np.inf, -np.inf], 0)
dataframe[col] = dataframe[col].ffill()
dataframe[col] = dataframe[col].fillna(0)
# 检查是否仍有无效值
if dataframe[col].isna().any() or np.isinf(dataframe[col]).any():
logger.warning(f"{col} 仍包含无效值,已填充为默认值")
dataframe[col] = dataframe[col].fillna(0)
return dataframe
def feature_engineering_standard(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
if len(dataframe) < 20 or dataframe["close"].isna().any():
logger.warning(f"DataFrame too short ({len(dataframe)} rows) or contains NaN in close, cannot compute %-volatility")
dataframe["%-volatility"] = 0
else:
dataframe["%-volatility"] = dataframe["close"].pct_change().rolling(20).std()
dataframe["%-volatility"] = dataframe["%-volatility"].fillna(0)
if dataframe["%-volatility"].std() > 0:
dataframe["%-volatility"] = (dataframe["%-volatility"] - dataframe["%-volatility"].mean()) / dataframe["%-volatility"].std()
dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek
dataframe["%-hour_of_day"] = dataframe["date"].dt.hour
dataframe = dataframe.replace([np.inf, -np.inf], 0).ffill().fillna(0)
dataframe.replace([np.inf, -np.inf], 0, inplace=True)
dataframe.ffill(inplace=True)
dataframe.fillna(0, inplace=True)
return dataframe
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
logger.info(f"Setting FreqAI targets for pair: {metadata['pair']}")
logger.info(f"设置 FreqAI 目标,交易对:{metadata['pair']}")
if "close" not in dataframe.columns:
logger.error("DataFrame missing required 'close' column")
raise ValueError("DataFrame missing required 'close' column")
logger.error("数据框缺少必要的 'close'")
raise ValueError("数据框缺少必要的 'close'")
try:
label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
if len(dataframe) < 20 or dataframe["close"].isna().any():
logger.warning(f"DataFrame too short ({len(dataframe)} rows) or contains NaN in close, cannot compute %-volatility")
dataframe["%-volatility"] = 0
else:
dataframe["%-volatility"] = dataframe["close"].pct_change().rolling(20).std()
dataframe["%-volatility"] = dataframe["%-volatility"].fillna(0)
if dataframe["%-volatility"].std() > 0:
dataframe["%-volatility"] = (dataframe["%-volatility"] - dataframe["%-volatility"].mean()) / dataframe["%-volatility"].std()
dataframe["&-buy_rsi"] = ta.RSI(dataframe, timeperiod=14).shift(-label_period)
for col in ["&-buy_rsi", "%-volatility"]:
dataframe[col] = dataframe[col].replace([np.inf, -np.inf], 0)
dataframe[col] = dataframe[col].ffill().fillna(0)
# 定义目标变量为未来价格变化百分比(连续值)
# 使用对数收益率作为目标变量
dataframe["target"] = np.log(
dataframe["close"].shift(-label_period) / dataframe["close"]
)
# 处理异常值
dataframe["target"] = dataframe["target"].clip(-0.1, 0.1)
# 创建 up_or_down 列
dataframe["up_or_down"] = np.where(
dataframe["close"].shift(-label_period) > dataframe["close"], 1, 0
)
# 数据清理:处理 NaN 和 Inf 值
dataframe["up_or_down"] = dataframe["up_or_down"].replace([np.inf, -np.inf], np.nan)
dataframe["up_or_down"] = dataframe["up_or_down"].ffill().fillna(0)
# 确保目标变量是二维数组
if dataframe["up_or_down"].ndim == 1:
dataframe["up_or_down"] = dataframe["up_or_down"].values.reshape(-1, 1)
# 检查并处理 NaN 或无限值
dataframe["up_or_down"] = dataframe["up_or_down"].replace([np.inf, -np.inf], np.nan)
dataframe["up_or_down"] = dataframe["up_or_down"].ffill().fillna(0)
# 生成 %-volatility 特征
dataframe["%-volatility"] = dataframe["close"].pct_change().rolling(20).std()
# 确保 &-buy_rsi 列的值计算正确
dataframe["&-buy_rsi"] = ta.RSI(dataframe, timeperiod=14)
# 数据清理
for col in ["&-buy_rsi", "up_or_down", "%-volatility"]:
# 使用直接操作避免链式赋值
dataframe[col] = dataframe[col].replace([np.inf, -np.inf], np.nan)
dataframe[col] = dataframe[col].ffill() # 替代 fillna(method='ffill')
dataframe[col] = dataframe[col].fillna(dataframe[col].mean()) # 使用均值填充 NaN 值
if dataframe[col].isna().any():
logger.warning(f"Target column {col} still contains NaN, check data generation logic")
logger.warning(f"目标列 {col} 仍包含 NaN填充为默认值")
except Exception as e:
logger.error(f"Failed to create FreqAI targets: {str(e)}")
logger.error(f"创建 FreqAI 目标失败:{str(e)}")
raise
logger.info(f"Target columns preview: {dataframe[['&-buy_rsi']].head().to_string()}")
# Log the shape of the target variable for debugging
logger.info(f"目标列形状:{dataframe['up_or_down'].shape}")
logger.info(f"目标列预览:\n{dataframe[['up_or_down', '&-buy_rsi']].head().to_string()}")
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
logger.info(f"populate_indicators Processing pair: {metadata['pair']}")
logger.info(f"populate_indicators DataFrame rows: {len(dataframe)}")
logger.info(f"populate_indicators Columns before freqai.start: {list(dataframe.columns)}")
if "close" not in dataframe.columns or dataframe["close"].isna().all():
logger.error(f"DataFrame missing 'close' column or all NaN for pair: {metadata['pair']}")
raise ValueError("DataFrame missing valid 'close' column")
if len(dataframe) < 14:
logger.warning(f"DataFrame too short ({len(dataframe)} rows), cannot compute rsi")
dataframe["rsi"] = 50
else:
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
logger.info(f"rsi stats: {dataframe['rsi'].describe().to_string()}")
if len(dataframe) < 20 or dataframe["close"].isna().any():
logger.warning(f"DataFrame too short ({len(dataframe)} rows) or contains NaN in close, cannot compute %-volatility")
dataframe["%-volatility"] = 0
else:
logger.info(f"处理交易对:{metadata['pair']}")
dataframe = self.freqai.start(dataframe, metadata, self)
# 确保 MACD 列在数据开始时就计算
macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
dataframe["macd"] = macd["macd"]
dataframe["macdsignal"] = macd["macdsignal"]
dataframe["macdhist"] = macd["macdhist"]
# 计算传统指标
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
dataframe["bb_lowerband"] = bollinger["lower"]
dataframe["bb_middleband"] = bollinger["mid"]
dataframe["bb_upperband"] = bollinger["upper"]
dataframe["tema"] = ta.TEMA(dataframe, timeperiod=9)
# 生成 up_or_down 信号(非 FreqAI 目标)
label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
# 使用未来价格变化方向生成 up_or_down 信号
label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
dataframe["up_or_down"] = np.where(
dataframe["close"].shift(-label_period) > dataframe["close"], 1, 0
)
# 动态设置参数
if "&-buy_rsi" in dataframe.columns:
# 派生其他目标
dataframe["&-sell_rsi"] = dataframe["&-buy_rsi"] + 30
dataframe["%-volatility"] = dataframe["close"].pct_change().rolling(20).std()
dataframe["%-volatility"] = dataframe["%-volatility"].fillna(0)
if dataframe["%-volatility"].std() > 0:
dataframe["%-volatility"] = (dataframe["%-volatility"] - dataframe["%-volatility"].mean()) / dataframe["%-volatility"].std()
logger.info(f"%-volatility stats: {dataframe['%-volatility'].describe().to_string()}")
# Ensure proper calculation and handle potential NaN values
dataframe["&-stoploss"] = (-0.1 - (dataframe["%-volatility"] * 10).clip(0, 0.25)).fillna(-0.1)
dataframe["&-roi_0"] = ((dataframe["close"] / dataframe["close"].shift(label_period) - 1).clip(0, 0.2)).fillna(0)
if len(dataframe) < 9:
logger.warning(f"DataFrame too short ({len(dataframe)} rows), cannot compute tema")
dataframe["tema"] = dataframe["close"]
else:
dataframe["tema"] = ta.TEMA(dataframe, timeperiod=9)
if dataframe["tema"].isna().any():
logger.warning("tema contains NaN, filling with close")
dataframe["tema"] = dataframe["tema"].fillna(dataframe["close"])
logger.info(f"tema stats: {dataframe['tema'].describe().to_string()}")
# Additional check to ensure no NaN values remain
for col in ["&-stoploss", "&-roi_0"]:
if dataframe[col].isna().any():
logger.warning(f"{col} 仍包含 NaN填充为默认值")
dataframe[col] = dataframe[col].fillna(-0.1 if col == "&-stoploss" else 0)
# 简化动态参数生成逻辑
# 放松 buy_rsi 和 sell_rsi 的生成逻辑
# 使用固定 RSI 阈值
self.buy_rsi.value = 30
self.sell_rsi.value = 70
if len(dataframe) < 20:
logger.warning(f"DataFrame too short ({len(dataframe)} rows), cannot compute bb_lowerband")
dataframe["bb_lowerband"] = dataframe["close"]
else:
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2.2)
dataframe["bb_lowerband"] = bollinger["lower"]
if dataframe["bb_lowerband"].isna().any():
logger.warning("bb_lowerband contains NaN, filling with close")
dataframe["bb_lowerband"] = dataframe["bb_lowerband"].fillna(dataframe["close"])
logger.info(f"bb_lowerband stats: {dataframe['bb_lowerband'].describe().to_string()}")
# 确保 buy_rsi_pred 列存在并合理初始化
if "buy_rsi_pred" not in dataframe.columns:
logger.warning("buy_rsi_pred 列缺失,使用 RSI 值进行初始化")
dataframe["buy_rsi_pred"] = ta.RSI(dataframe, timeperiod=14)
dataframe["buy_rsi_pred"] = dataframe["buy_rsi_pred"].fillna(30).clip(10, 90)
# 计算 sell_rsi_pred 并清理 NaN 值
dataframe["sell_rsi_pred"] = dataframe["buy_rsi_pred"] + 20
dataframe["sell_rsi_pred"] = dataframe["sell_rsi_pred"].fillna(dataframe["sell_rsi_pred"].median())
if "date" in dataframe.columns:
dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek
dataframe["%-hour_of_day"] = dataframe["date"].dt.hour
else:
logger.warning("Missing 'date' column, skipping %-day_of_week and %-hour_of_day")
dataframe["%-day_of_week"] = 0
dataframe["%-hour_of_day"] = 0
# 计算 stoploss_pred 并清理 NaN 值
dataframe["stoploss_pred"] = -0.1 - (dataframe["%-volatility"] * 10).clip(0, 0.25)
dataframe["stoploss_pred"] = dataframe["stoploss_pred"].fillna(dataframe["stoploss_pred"].mean())
try:
dataframe = self.freqai.start(dataframe, metadata, self)
logger.info(f"Columns after freqai.start: {list(dataframe.columns)}")
except Exception as e:
logger.error(f"freqai.start failed: {str(e)}")
dataframe["buy_rsi_pred"] = 50
dataframe["sell_rsi_pred"] = 80
dataframe["do_predict"] = 1
for col in ["buy_rsi_pred", "sell_rsi_pred"]:
# 计算 roi_0_pred 并清理 NaN 值
dataframe["roi_0_pred"] = dataframe["&-roi_0"].clip(0.01, 0.2)
dataframe["roi_0_pred"] = dataframe["roi_0_pred"].fillna(dataframe["roi_0_pred"].mean())
# Initialize all required prediction columns with proper default values
pred_columns = {
"buy_rsi_pred": 30, # Default RSI buy threshold
"sell_rsi_pred": 70, # Default RSI sell threshold
"stoploss_pred": -0.1, # Default stoploss
"roi_0_pred": 0.038, # Default ROI
"do_predict": 0 # Default prediction flag
}
# Create and initialize columns before any calculations
for col, default_value in pred_columns.items():
# Create column if it doesn't exist
if col not in dataframe.columns:
logger.error(f"Error: {col} column not generated for pair: {metadata['pair']}")
dataframe[col] = 50 if col == "buy_rsi_pred" else 80
logger.info(f"{col} stats: {dataframe[col].describe().to_string()}")
logger.warning(f"Column {col} missing, initializing with default value {default_value}")
dataframe[col] = default_value
# Ensure proper data type
if dataframe[col].dtype not in [np.float64, np.int64]:
logger.warning(f"Column {col} has incorrect dtype {dataframe[col].dtype}, converting to float")
dataframe[col] = dataframe[col].astype(float)
# Handle NaN values
if dataframe[col].isna().any():
logger.warning(f"Column {col} contains NaN values, filling with default value {default_value}")
dataframe[col] = dataframe[col].fillna(default_value)
# Add additional validation for RSI predictions
if col in ["buy_rsi_pred", "sell_rsi_pred"]:
dataframe[col] = dataframe[col].clip(lower=10, upper=90) # Keep RSI values within valid range
# Final validation of buy_rsi_pred
if "buy_rsi_pred" not in dataframe.columns:
logger.error("buy_rsi_pred column still missing after initialization, aborting")
raise ValueError("Failed to initialize required buy_rsi_pred column")
# Ensure buy_rsi_pred has valid values
dataframe["buy_rsi_pred"] = dataframe["buy_rsi_pred"].clip(lower=10, upper=90)
dataframe["buy_rsi_pred"] = dataframe["buy_rsi_pred"].fillna(30)
# Initialize columns before any calculations
for col, default_value in pred_columns.items():
# Create column if it doesn't exist
if col not in dataframe.columns:
logger.warning(f"Column {col} missing, initializing with default value {default_value}")
dataframe[col] = default_value
# Ensure proper data type
if dataframe[col].dtype not in [np.float64, np.int64]:
logger.warning(f"Column {col} has incorrect dtype {dataframe[col].dtype}, converting to float")
dataframe[col] = dataframe[col].astype(float)
# Handle NaN values
if dataframe[col].isna().any():
logger.warning(f"Column {col} contains NaN values, filling with default value {default_value}")
dataframe[col] = dataframe[col].fillna(default_value)
# Add additional validation for RSI predictions
if col in ["buy_rsi_pred", "sell_rsi_pred"]:
dataframe[col] = dataframe[col].clip(lower=10, upper=90) # Keep RSI values within valid range
# Ensure buy_rsi_pred exists before using it
if "buy_rsi_pred" not in dataframe.columns:
logger.error("buy_rsi_pred column still missing after initialization, aborting")
raise ValueError("Failed to initialize required buy_rsi_pred column")
# Ensure buy_rsi_pred exists with proper initialization
if "buy_rsi_pred" not in dataframe.columns:
logger.warning("buy_rsi_pred column missing, initializing with default value 30")
dataframe["buy_rsi_pred"] = 30
# Now perform calculations that depend on these columns
dataframe["sell_rsi_pred"] = dataframe["buy_rsi_pred"] + 20
dataframe["sell_rsi_pred"] = dataframe["sell_rsi_pred"].fillna(dataframe["sell_rsi_pred"].median())
# 调试特征分布
if "%-bb_width-period_10_OKB/USDT_5m" in dataframe.columns:
if dataframe["%-bb_width-period_10_OKB/USDT_5m"].std() > 0:
dataframe["%-bb_width-period_10_OKB/USDT_5m"] = (
dataframe["%-bb_width-period_10_OKB/USDT_5m"] - dataframe["%-bb_width-period_10_OKB/USDT_5m"].mean()
) / dataframe["%-bb_width-period_10_OKB/USDT_5m"].std()
logger.info(f"%-bb_width-period_10_OKB stats: {dataframe['%-bb_width-period_10_OKB/USDT_5m'].describe().to_string()}")
if "%-bb_width-period_10_SOL/USDT_5m" in dataframe.columns:
if dataframe["%-bb_width-period_10_SOL/USDT_5m"].std() > 0:
dataframe["%-bb_width-period_10_SOL/USDT_5m"] = (
dataframe["%-bb_width-period_10_SOL/USDT_5m"] - dataframe["%-bb_width-period_10_SOL/USDT_5m"].mean()
) / dataframe["%-bb_width-period_10_SOL/USDT_5m"].std()
logger.info(f"%-bb_width-period_10_SOL stats: {dataframe['%-bb_width-period_10_SOL/USDT_5m'].describe().to_string()}")
def get_expected_columns(freqai_config: dict) -> list:
indicators = ["rsi", "bb_width", "pct-change"]
periods = freqai_config.get("feature_parameters", {}).get("include_periods", [10, 20])
pairs = freqai_config.get("include_corr_pairlist", ["OKB/USDT", "SOL/USDT"])
timeframes = freqai_config.get("include_timeframes", ["5m"])
shifts = [0]
expected_columns = ["%-volatility", "%-day_of_week", "%-hour_of_day"]
for indicator in indicators:
for period in periods:
for pair in pairs:
for timeframe in timeframes:
for shift in shifts:
col_name = f"%-{indicator}-period_{period}" if indicator != "pct-change" else f"%-{indicator}"
if shift > 0:
col_name += f"_shift-{shift}"
col_name += f"_{pair}_{timeframe}"
expected_columns.append(col_name)
return expected_columns
expected_columns = get_expected_columns(self.freqai_info)
logger.info(f"Expected feature columns ({len(expected_columns)}): {expected_columns[:10]}...")
actual_columns = list(dataframe.columns)
missing_columns = [col for col in expected_columns if col not in actual_columns]
extra_columns = [col for col in actual_columns if col not in expected_columns and col.startswith("%-")]
logger.info(f"Missing columns ({len(missing_columns)}): {missing_columns}")
logger.info(f"Extra columns ({len(extra_columns)}): {extra_columns}")
if "DI_values" in dataframe.columns:
logger.info(f"DI_values stats: {dataframe['DI_values'].describe().to_string()}")
logger.info(f"DI discarded predictions: {len(dataframe[dataframe['do_predict'] == 0])}")
dataframe = dataframe.replace([np.inf, -np.inf], 0).ffill().fillna(0)
logger.info(f"Final columns in populate_indicators: {list(dataframe.columns)}")
# 检查并处理 NaN 值
all_columns = list(pred_columns.keys()) + ["&-sell_rsi", "&-stoploss", "&-roi_0", "buy_rsi_pred", "sell_rsi_pred"]
for col in all_columns:
if col in dataframe.columns:
if dataframe[col].isna().any():
logger.warning(f"{col} 包含 NaN填充为默认值")
dataframe[col] = dataframe[col].fillna(dataframe[col].mean())
# 更保守的止损和止盈设置
dataframe["trailing_stop_positive"] = (dataframe["roi_0_pred"] * 0.3).clip(0.01, 0.2)
dataframe["trailing_stop_positive_offset"] = (dataframe["roi_0_pred"] * 0.5).clip(0.01, 0.3)
# 设置策略级参数
self.buy_rsi.value = float(dataframe["buy_rsi_pred"].iloc[-1])
self.sell_rsi.value = float(dataframe["sell_rsi_pred"].iloc[-1])
# 更保守的止损设置
self.stoploss = -0.15 # 固定止损 15%
self.minimal_roi = {
0: float(self.roi_0.value),
15: float(self.roi_15.value),
30: float(self.roi_30.value),
60: 0
}
# 更保守的追踪止损设置
self.trailing_stop_positive = 0.05 # 追踪止损触发点
self.trailing_stop_positive_offset = 0.1 # 追踪止损偏移量
logger.info(f"动态参数buy_rsi={self.buy_rsi.value}, sell_rsi={self.sell_rsi.value}, "
f"stoploss={self.stoploss}, trailing_stop_positive={self.trailing_stop_positive}")
dataframe.replace([np.inf, -np.inf], 0, inplace=True)
dataframe.ffill(inplace=True)
dataframe.fillna(0, inplace=True)
logger.info(f"up_or_down 值统计:\n{dataframe['up_or_down'].value_counts().to_string()}")
logger.info(f"do_predict 值统计:\n{dataframe['do_predict'].value_counts().to_string()}")
return dataframe
def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
enter_long_conditions = [
qtpylib.crossed_above(df["rsi"], df["buy_rsi_pred"]),
df["close"] > df["tema"],
df["volume"] > 0,
df["do_predict"] == 1
def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
# 改进卖出信号条件
exit_long_conditions = [
(df["rsi"] > df["sell_rsi_pred"]), # RSI 高于卖出阈值
(df["volume"] > df["volume"].rolling(window=10).mean()), # 成交量高于近期均值
(df["close"] < df["bb_middleband"]) # 价格低于布林带中轨
]
if exit_long_conditions:
df.loc[
reduce(lambda x, y: x & y, exit_long_conditions),
"exit_long"
] = 1
return df
def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
# 改进买入信号条件
# 检查 MACD 列是否存在
if "macd" not in df.columns or "macdsignal" not in df.columns:
logger.error("MACD 或 MACD 信号列缺失,无法生成买入信号。尝试重新计算 MACD 列。")
try:
macd = ta.MACD(df, fastperiod=12, slowperiod=26, signalperiod=9)
df["macd"] = macd["macd"]
df["macdsignal"] = macd["macdsignal"]
logger.info("MACD 列已成功重新计算。")
except Exception as e:
logger.error(f"重新计算 MACD 列时出错:{str(e)}")
raise ValueError("DataFrame 缺少必要的 MACD 列且无法重新计算。")
enter_long_conditions = [
(df["rsi"] < df["buy_rsi_pred"]), # RSI 低于买入阈值
(df["volume"] > df["volume"].rolling(window=10).mean() * 1.2), # 成交量高于近期均值20%
(df["close"] > df["bb_middleband"]) # 价格高于布林带中轨
]
# 如果 MACD 列存在,则添加 MACD 金叉条件
if "macd" in df.columns and "macdsignal" in df.columns:
enter_long_conditions.append((df["macd"] > df["macdsignal"]))
# 放宽模型预测条件
enter_long_conditions.append((df["do_predict"] >= 0.5)) # 将预测阈值从1降低到0.5
if enter_long_conditions:
df.loc[
reduce(lambda x, y: x & y, enter_long_conditions),
["enter_long", "enter_tag"]
] = (1, "long")
df["entry_signal"] = reduce(lambda x, y: x & y, enter_long_conditions)
df["entry_signal"] = df["entry_signal"].rolling(window=2, min_periods=1).max().astype(bool)
df.loc[
df["entry_signal"],
["enter_long", "enter_tag"]
] = (1, "long")
if df["entry_signal"].iloc[-1]:
logger.info(f"Entry signal triggered for {metadata['pair']}: rsi={df['rsi'].iloc[-1]}, buy_rsi_pred={df['buy_rsi_pred'].iloc[-1]}, do_predict={df['do_predict'].iloc[-1]}, close={df['close'].iloc[-1]}, tema={df['tema'].iloc[-1]}")
logger.info(f"Entry conditions: RSI_cross={qtpylib.crossed_above(df['rsi'], df['buy_rsi_pred']).iloc[-1]}, Close_above_tema={df['close'].iloc[-1] > df['tema'].iloc[-1]}, Volume={df['volume'].iloc[-1] > 0}, Do_predict={df['do_predict'].iloc[-1] == 1}")
logger.info(f"Last candle: rsi={df['rsi'].iloc[-1]}, buy_rsi_pred={df['buy_rsi_pred'].iloc[-1]}, close={df['close'].iloc[-1]}, tema={df['tema'].iloc[-1]}, do_predict={df['do_predict'].iloc[-1]}")
return df
def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
exit_long_conditions = [
(qtpylib.crossed_above(df["rsi"], df["sell_rsi_pred"])) |
(df["close"] < df["close"].shift(1) * 0.98) |
(df["close"] < df["bb_lowerband"]),
df["volume"] > 0,
df["do_predict"] == 1
]
time_exit = (df["date"] >= df["date"].shift(1) + pd.Timedelta(days=1))
df.loc[
(reduce(lambda x, y: x & y, exit_long_conditions)) | time_exit,
"exit_long"
] = 1
return df
def confirm_trade_entry(
self, pair: str, order_type: str, amount: float, rate: float,
time_in_force: str, current_time, entry_tag, side: str, **kwargs
) -> bool:
logger.info(f"Confirming trade entry for {pair}, order_type: {order_type}, rate: {rate}, current_time: {current_time}")
df, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = df.iloc[-1].squeeze()
if side == "long":
if order_type == "market":
logger.info(f"Order confirmed for {pair}, rate: {rate} (market order)")
return True
if rate <= (last_candle["close"] * (1 + 0.01)):
logger.info(f"Order confirmed for {pair}, rate: {rate}")
return True
logger.info(f"Order rejected: rate {rate} exceeds threshold {last_candle['close'] * 1.01}")
return False
if rate > (last_candle["close"] * (1 + 0.0025)):
return False
return True

183
freqtrade/templates/aaa.md Normal file
View File

@ -0,0 +1,183 @@
```python
class FreqaiExampleStrategy(IStrategy):
minimal_roi = {}
stoploss = -0.1
trailing_stop = True
process_only_new_candles = True
use_exit_signal = True
startup_candle_count: int = 100 # 增加数据需求
can_short = False
# Hyperopt 参数
buy_rsi = IntParameter(low=10, high=50, default=27, space="buy", optimize=False, load=True)
sell_rsi = IntParameter(low=50, high=90, default=59, space="sell", optimize=False, load=True)
roi_0 = DecimalParameter(low=0.01, high=0.2, default=0.038, space="roi", optimize=True, load=True)
roi_15 = DecimalParameter(low=0.005, high=0.1, default=0.027, space="roi", optimize=True, load=True)
roi_30 = DecimalParameter(low=0.001, high=0.05, default=0.009, space="roi", optimize=True, load=True)
stoploss_param = DecimalParameter(low=-0.25, high=-0.05, default=-0.1, space="stoploss", optimize=True, load=True)
# 保护机制
protections = [
{"method": "StoplossGuard", "stop_duration": 60, "lookback_period": 120},
{"method": "MaxDrawdown", "lookback_period": 120, "max_allowed_drawdown": 0.05}
]
# FreqAI 配置
freqai_info = {
"model": "LightGBMRegressor",
"feature_parameters": {
"include_timeframes": ["5m", "15m", "1h"],
"include_corr_pairlist": [],
"label_period_candles": 12,
"include_shifted_candles": 3,
},
"data_split_parameters": {
"test_size": 0.2,
"shuffle": False,
"n_splits": 5 # 添加交叉验证
},
"model_training_parameters": {
"n_estimators": 200,
"learning_rate": 0.05,
"num_leaves": 10,
"min_child_weight": 1,
"verbose": -1,
},
}
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
logger.info(f"设置 FreqAI 目标,交易对:{metadata['pair']}")
if "close" not in dataframe.columns:
logger.error("数据框缺少必要的 'close' 列")
raise ValueError("数据框缺少必要的 'close' 列")
try:
label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
dataframe["%-volatility"] = dataframe["close"].pct_change().rolling(20).std()
dataframe["&-buy_rsi"] = (dataframe["close"].shift(-label_period) / dataframe["close"] - 1) * 100 # 修改目标为收益率
for col in ["&-buy_rsi", "%-volatility"]:
dataframe[col] = dataframe[col].replace([np.inf, -np.inf], 0)
dataframe[col] = dataframe[col].ffill()
if dataframe[col].isna().any():
logger.warning(f"目标列 {col} 包含 NaN填充为 0")
dataframe[col] = dataframe[col].fillna(0)
logger.info(f"目标列 {col} 统计:\n{dataframe[col].describe().to_string()}")
except Exception as e:
logger.error(f"创建 FreqAI 目标失败:{str(e)}")
raise
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
logger.info(f"处理交易对:{metadata['pair']}, 数据形状:{dataframe.shape}")
dataframe = self.freqai.start(dataframe, metadata, self)
# 计算传统指标
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
dataframe["bb_lowerband"] = bollinger["lower"]
dataframe["bb_middleband"] = bollinger["mid"]
dataframe["bb_upperband"] = bollinger["upper"]
dataframe["tema"] = ta.TEMA(dataframe, timeperiod=9)
# 检查FreqAI预测列
if "&-buy_rsi_pred" in dataframe.columns:
logger.info(f"&-buy_rsi_pred 统计:均值={dataframe['&-buy_rsi_pred'].mean():.2f}, 标准差={dataframe['&-buy_rsi_pred'].std():.2f}")
dataframe["buy_rsi_trend"] = np.where(
dataframe["&-buy_rsi_pred"] > dataframe["&-buy_rsi_pred"].shift(1), 1, 0
)
dataframe["&-sell_rsi_pred"] = dataframe["&-buy_rsi_pred"] + 30
dataframe["%-volatility"] = dataframe["close"].pct_change().rolling(20).std()
dataframe["&-stoploss_pred"] = -0.1 - (dataframe["%-volatility"] * 10).clip(0, 0.25)
dataframe["&-roi_0_pred"] = (dataframe["&-buy_rsi_pred"] / 1000).clip(0.01, 0.2)
for col in ["&-buy_rsi_pred", "&-sell_rsi_pred", "&-stoploss_pred", "&-roi_0_pred"]:
if dataframe[col].isna().any():
logger.warning(f"列 {col} 包含 NaN填充为默认值")
mean_value = dataframe[col].mean()
if pd.isna(mean_value):
mean_value = {
"&-buy_rsi_pred": 30,
"&-sell_rsi_pred": 70,
"&-stoploss_pred": -0.1,
"&-roi_0_pred": 0.05
}.get(col, 0)
dataframe[col] = dataframe[col].fillna(mean_value)
else:
logger.warning(f"&-buy_rsi_pred 列缺失,使用默认值初始化")
dataframe["buy_rsi_trend"] = 0
dataframe["&-buy_rsi_pred"] = 30
dataframe["&-sell_rsi_pred"] = 70
dataframe["&-stoploss_pred"] = -0.1
dataframe["&-roi_0_pred"] = 0.05
# 动态参数设置
try:
last_valid_idx = dataframe["&-stoploss_pred"].last_valid_index()
if last_valid_idx is None:
raise ValueError("没有有效的预测数据")
self.stoploss = float(np.clip(dataframe["&-stoploss_pred"].iloc[last_valid_idx], -0.25, -0.05))
self.buy_rsi.value = int(np.clip(dataframe["&-buy_rsi_pred"].iloc[last_valid_idx], 10, 50))
self.sell_rsi.value = int(np.clip(dataframe["&-sell_rsi_pred"].iloc[last_valid_idx], 50, 90))
self.roi_0.value = float(np.clip(dataframe["&-roi_0_pred"].iloc[last_valid_idx], 0.01, 0.2))
self.minimal_roi = {
0: self.roi_0.value,
15: self.roi_15.value,
30: self.roi_30.value,
60: 0.0
}
logger.info(f"动态参数设置: buy_rsi={self.buy_rsi.value}, sell_rsi={self.sell_rsi.value}, stoploss={self.stoploss:.2%}")
except Exception as e:
logger.error(f"动态参数设置失败,使用默认值: {str(e)}")
self.stoploss = -0.1
self.buy_rsi.value = 27
self.sell_rsi.value = 59
self.minimal_roi = {0: 0.038, 15: 0.027, 30: 0.009, 60: 0.0}
dataframe = dataframe.replace([np.inf, -np.inf], 0)
dataframe = dataframe.ffill()
dataframe = dataframe.fillna(0)
logger.info(f"do_predict 分布:\n{dataframe['do_predict'].value_counts().to_string()}")
return dataframe
def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
enter_long_conditions = [
qtpylib.crossed_above(df["rsi"], df["&-buy_rsi_pred"] - 5), # 放宽RSI条件
df["tema"] > df["tema"].shift(1),
df["volume"] > 0,
df["do_predict"] == 1
]
if enter_long_conditions:
condition_met = reduce(lambda x, y: x & y, enter_long_conditions)
df.loc[condition_met, ["enter_long", "enter_tag"]] = (1, "long")
if condition_met.any():
logger.info(f"买入信号触发:{metadata['pair']},时间={df.index[condition_met][-1]}")
else:
logger.debug(f"买入条件未满足:{metadata['pair']}do_predict={df['do_predict'].iloc[-1]}, rsi={df['rsi'].iloc[-1]:.2f}, buy_rsi_pred={df['&-buy_rsi_pred'].iloc[-1]:.2f}")
return df
def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
exit_long_conditions = [
qtpylib.crossed_above(df["rsi"], df["&-sell_rsi_pred"]),
df["close"] < df["bb_lowerband"],
df["volume"] > 0,
df["do_predict"] == 1
]
time_exit = (df["date"] >= df["date"].shift(1) + pd.Timedelta(days=2))
df.loc[
(reduce(lambda x, y: x & y, exit_long_conditions)) | time_exit,
"exit_long"
] = 1
return df
```
```
```
```
```
```
```
```

View File

@ -1,104 +0,0 @@
diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py
index 1d7ed33..245f771 100644
--- a/freqtrade/templates/FreqaiExampleStrategy.py
+++ b/freqtrade/templates/FreqaiExampleStrategy.py
@@ -128,9 +128,9 @@ class FreqaiExampleStrategy(IStrategy):
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
- logger.info(f"Processing pair: {metadata['pair']}")
- logger.info(f"DataFrame rows: {len(dataframe)}")
- logger.info(f"Columns before freqai.start: {list(dataframe.columns)}")
+ logger.info(f"populate_indicators Processing pair: {metadata['pair']}")
+ logger.info(f"populate_indicators DataFrame rows: {len(dataframe)}")
+ logger.info(f"populate_indicators Columns before freqai.start: {list(dataframe.columns)}")
if "close" not in dataframe.columns or dataframe["close"].isna().all():
logger.error(f"DataFrame missing 'close' column or all NaN for pair: {metadata['pair']}")
@@ -173,6 +173,19 @@ class FreqaiExampleStrategy(IStrategy):
logger.warning("bb_lowerband contains NaN, filling with close")
dataframe["bb_lowerband"] = dataframe["bb_lowerband"].fillna(dataframe["close"])
logger.info(f"bb_lowerband stats: {dataframe['bb_lowerband'].describe().to_string()}")
+ # 生成 up_or_down
+ label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
+ if len(dataframe) < label_period + 1:
+ logger.warning(f"DataFrame too short ({len(dataframe)} rows), cannot compute up_or_down")
+ dataframe["up_or_down"] = 0
+ else:
+ dataframe["up_or_down"] = np.where(
+ dataframe["close"].shift(-label_period) > dataframe["close"], 1, 0
+ )
+ if dataframe["up_or_down"].isna().any():
+ logger.warning("up_or_down contains NaN, filling with 0")
+ dataframe["up_or_down"] = dataframe["up_or_down"].fillna(0)
+ logger.info(f"up_or_down stats: {dataframe['up_or_down'].describe().to_string()}")
if "date" in dataframe.columns:
dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek
@@ -197,17 +210,18 @@ class FreqaiExampleStrategy(IStrategy):
dataframe[col] = 50 if col == "buy_rsi_pred" else 80
logger.info(f"{col} stats: {dataframe[col].describe().to_string()}")
- if "%-bb_width-period_20_SOL/USDT_5m" in dataframe.columns:
- if dataframe["%-bb_width-period_20_SOL/USDT_5m"].std() > 0:
- dataframe["%-bb_width-period_20_SOL/USDT_5m"] = (
- dataframe["%-bb_width-period_20_SOL/USDT_5m"] - dataframe["%-bb_width-period_20_SOL/USDT_5m"].mean()
- ) / dataframe["%-bb_width-period_20_SOL/USDT_5m"].std()
- logger.info(f"%-bb_width-period_20 stats: {dataframe['%-bb_width-period_20_SOL/USDT_5m'].describe().to_string()}")
+ # 调试特征分布
+ if "%-bb_width-period_10_SOL/USDT_5m" in dataframe.columns:
+ if dataframe["%-bb_width-period_10_SOL/USDT_5m"].std() > 0:
+ dataframe["%-bb_width-period_10_SOL/USDT_5m"] = (
+ dataframe["%-bb_width-period_10_SOL/USDT_5m"] - dataframe["%-bb_width-period_10_SOL/USDT_5m"].mean()
+ ) / dataframe["%-bb_width-period_10_SOL/USDT_5m"].std()
+ logger.info(f"%-bb_width-period_10 stats: {dataframe['%-bb_width-period_10_SOL/USDT_5m'].describe().to_string()}")
def get_expected_columns(freqai_config: dict) -> list:
indicators = ["rsi", "bb_width", "pct-change"]
- periods = freqai_config.get("feature_parameters", {}).get("include_periods", [20])
- pairs = freqai_config.get("include_corr_pairlist", ["SOL/USDT"])
+ periods = freqai_config.get("feature_parameters", {}).get("include_periods", [10, 20])
+ pairs = freqai_config.get("include_corr_pairlist", ["SOL/USDT", "BTC/USDT"])
timeframes = freqai_config.get("include_timeframes", ["5m"])
shifts = [0]
expected_columns = ["%-volatility", "%-day_of_week", "%-hour_of_day"]
@@ -242,11 +256,17 @@ class FreqaiExampleStrategy(IStrategy):
def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
enter_long_conditions = [
- qtpylib.crossed_above(df["rsi"], df["buy_rsi_pred"]),
+ qtpylib.crossed_above(df["rsi"], df["buy_rsi_pred"] + (5 if metadata["pair"] == "BTC/USDT" else 0)),
df["tema"] > df["tema"].shift(1),
df["volume"] > 0,
- df["do_predict"] == 1
+ df["do_predict"] == 1,
+ df["up_or_down"] == 1
]
+ if enter_long_conditions:
+ df.loc[
+ reduce(lambda x, y: x & y, enter_long_conditions),
+ ["enter_long", "enter_tag"]
+ ] = (1, "long")
df["entry_signal"] = reduce(lambda x, y: x & y, enter_long_conditions)
df["entry_signal"] = df["entry_signal"].rolling(window=2, min_periods=1).max().astype(bool)
df.loc[
@@ -259,14 +279,16 @@ class FreqaiExampleStrategy(IStrategy):
def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
exit_long_conditions = [
- (qtpylib.crossed_above(df["rsi"], df["sell_rsi_pred"] - 5)) |
+ (qtpylib.crossed_above(df["rsi"], df["sell_rsi_pred"])) |
(df["close"] < df["close"].shift(1) * 0.98) |
(df["close"] < df["bb_lowerband"]),
df["volume"] > 0,
- df["do_predict"] == 1
+ df["do_predict"] == 1,
+ df["up_or_down"] == 0
]
+ time_exit = (df["date"] >= df["date"].shift(1) + pd.Timedelta(days=1))
df.loc[
- reduce(lambda x, y: x & y, exit_long_conditions),
+ (reduce(lambda x, y: x & y, exit_long_conditions)) | time_exit,
"exit_long"
] = 1
return df

View File

@ -1,5 +0,0 @@
开始过滤日志,输出到 freqtrade_error_logs.txt ...
实时监控 freqtrade_freqtrade_run_ef258891294d 的日志,过滤 'but got Index'...
开始过滤日志,输出到 freqtrade_error_logs.txt ...
实时监控 freqtrade_freqtrade_run_ef258891294d 的日志,过滤 'but got Index'...
未捕获到包含 'but got Index' 的日志,文件 freqtrade_error_logs.txt 为空

347
output_filted.log Normal file
View File

@ -0,0 +1,347 @@
Creating freqtrade_freqtrade_run ...
Creating freqtrade_freqtrade_run ... done
2025-04-29 06:20:29,163 - freqtrade - INFO - freqtrade 2025.3
2025-04-29 06:20:29,374 - numexpr.utils - INFO - NumExpr defaulting to 12 threads.
2025-04-29 06:20:30,758 - freqtrade.configuration.load_config - INFO - Using config: /freqtrade/config_examples/config_freqai.okx.json ...
2025-04-29 06:20:30,759 - freqtrade.configuration.load_config - INFO - Using config: /freqtrade/templates/FreqaiExampleStrategy.json ...
2025-04-29 06:20:30,761 - freqtrade.loggers - INFO - Enabling colorized output.
2025-04-29 06:20:30,761 - root - INFO - Logfile configured
2025-04-29 06:20:30,762 - freqtrade.loggers - INFO - Verbosity set to 0
2025-04-29 06:20:30,762 - freqtrade.configuration.configuration - INFO - Using additional Strategy lookup path: /freqtrade/templates
2025-04-29 06:20:30,763 - freqtrade.configuration.configuration - INFO - Using max_open_trades: 4 ...
2025-04-29 06:20:30,763 - freqtrade.configuration.configuration - INFO - Parameter --timerange detected: 20250401-20250420 ...
2025-04-29 06:20:30,787 - freqtrade.configuration.configuration - INFO - Using user-data directory: /freqtrade/user_data ...
2025-04-29 06:20:30,788 - freqtrade.configuration.configuration - INFO - Using data directory: /freqtrade/user_data/data/okx ...
2025-04-29 06:20:30,788 - freqtrade.configuration.configuration - INFO - Parameter --cache=none detected ...
2025-04-29 06:20:30,788 - freqtrade.configuration.configuration - INFO - Filter trades by timerange: 20250401-20250420
2025-04-29 06:20:30,788 - freqtrade.configuration.configuration - INFO - Using freqaimodel class name: XGBoostRegressor
2025-04-29 06:20:30,789 - freqtrade.exchange.check_exchange - INFO - Checking exchange...
2025-04-29 06:20:30,795 - freqtrade.exchange.check_exchange - INFO - Exchange "okx" is officially supported by the Freqtrade development team.
2025-04-29 06:20:30,795 - freqtrade.configuration.configuration - INFO - Using pairlist from configuration.
2025-04-29 06:20:30,796 - freqtrade.configuration.config_validation - INFO - Validating configuration ...
2025-04-29 06:20:30,798 - freqtrade.commands.optimize_commands - INFO - Starting freqtrade in Backtesting mode
2025-04-29 06:20:30,798 - freqtrade.exchange.exchange - INFO - Instance is running with dry_run enabled
2025-04-29 06:20:30,799 - freqtrade.exchange.exchange - INFO - Using CCXT 4.4.69
2025-04-29 06:20:30,799 - freqtrade.exchange.exchange - INFO - Applying additional ccxt config: {'enableRateLimit': True, 'rateLimit': 500, 'options': {'defaultType': 'spot'}}
2025-04-29 06:20:30,804 - freqtrade.exchange.exchange - INFO - Applying additional ccxt config: {'enableRateLimit': True, 'rateLimit': 500, 'options': {'defaultType': 'spot'}, 'timeout': 20000}
2025-04-29 06:20:30,809 - freqtrade.exchange.exchange - INFO - Using Exchange "OKX"
2025-04-29 06:20:33,353 - freqtrade.resolvers.exchange_resolver - INFO - Using resolved exchange 'Okx'...
2025-04-29 06:20:33,373 - freqtrade.resolvers.iresolver - INFO - Using resolved strategy FreqaiExampleStrategy from '/freqtrade/templates/FreqaiExampleStrategy.py'...
2025-04-29 06:20:33,373 - freqtrade.strategy.hyper - INFO - Loading parameters from file /freqtrade/templates/FreqaiExampleStrategy.json
2025-04-29 06:20:33,374 - freqtrade.resolvers.strategy_resolver - INFO - Override strategy 'timeframe' with value in config file: 3m.
2025-04-29 06:20:33,374 - freqtrade.resolvers.strategy_resolver - INFO - Override strategy 'stoploss' with value in config file: -0.05.
2025-04-29 06:20:33,375 - freqtrade.resolvers.strategy_resolver - INFO - Override strategy 'stake_currency' with value in config file: USDT.
2025-04-29 06:20:33,375 - freqtrade.resolvers.strategy_resolver - INFO - Override strategy 'stake_amount' with value in config file: 150.
2025-04-29 06:20:33,376 - freqtrade.resolvers.strategy_resolver - INFO - Override strategy 'startup_candle_count' with value in config file: 30.
2025-04-29 06:20:33,376 - freqtrade.resolvers.strategy_resolver - INFO - Override strategy 'unfilledtimeout' with value in config file: {'entry': 5, 'exit': 15, 'exit_timeout_count': 0, 'unit':
'minutes'}.
2025-04-29 06:20:33,376 - freqtrade.resolvers.strategy_resolver - INFO - Override strategy 'max_open_trades' with value in config file: 4.
2025-04-29 06:20:33,377 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using minimal_roi: {'0': 0.132, '8': 0.047, '14': 0.007, '60': 0}
2025-04-29 06:20:33,377 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using timeframe: 3m
2025-04-29 06:20:33,377 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using stoploss: -0.05
2025-04-29 06:20:33,378 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using trailing_stop: True
2025-04-29 06:20:33,378 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using trailing_stop_positive: 0.01
2025-04-29 06:20:33,378 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using trailing_stop_positive_offset: 0.02
2025-04-29 06:20:33,379 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using trailing_only_offset_is_reached: False
2025-04-29 06:20:33,379 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using use_custom_stoploss: False
2025-04-29 06:20:33,379 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using process_only_new_candles: True
2025-04-29 06:20:33,380 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using order_types: {'entry': 'limit', 'exit': 'limit', 'stoploss': 'limit', 'stoploss_on_exchange': False,
'stoploss_on_exchange_interval': 60}
2025-04-29 06:20:33,380 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using order_time_in_force: {'entry': 'GTC', 'exit': 'GTC'}
2025-04-29 06:20:33,380 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using stake_currency: USDT
2025-04-29 06:20:33,380 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using stake_amount: 150
2025-04-29 06:20:33,381 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using startup_candle_count: 30
2025-04-29 06:20:33,381 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using unfilledtimeout: {'entry': 5, 'exit': 15, 'exit_timeout_count': 0, 'unit': 'minutes'}
2025-04-29 06:20:33,381 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using use_exit_signal: True
2025-04-29 06:20:33,382 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using exit_profit_only: False
2025-04-29 06:20:33,382 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using ignore_roi_if_entry_signal: False
2025-04-29 06:20:33,382 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using exit_profit_offset: 0.0
2025-04-29 06:20:33,383 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using disable_dataframe_checks: False
2025-04-29 06:20:33,383 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using ignore_buying_expired_candle_after: 0
2025-04-29 06:20:33,383 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using position_adjustment_enable: False
2025-04-29 06:20:33,384 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using max_entry_position_adjustment: -1
2025-04-29 06:20:33,384 - freqtrade.resolvers.strategy_resolver - INFO - Strategy using max_open_trades: 4
2025-04-29 06:20:33,384 - freqtrade.configuration.config_validation - INFO - Validating configuration ...
2025-04-29 06:20:33,388 - freqtrade.resolvers.iresolver - INFO - Using resolved pairlist StaticPairList from '/freqtrade/freqtrade/plugins/pairlist/StaticPairList.py'...
2025-04-29 06:20:33,394 - freqtrade.optimize.backtesting - INFO - Using fee 0.1500% - worst case fee from exchange (lowest tier).
2025-04-29 06:20:33,395 - freqtrade.data.dataprovider - INFO - Increasing startup_candle_count for freqai on 3m to 14450
2025-04-29 06:20:33,396 - freqtrade.data.history.history_utils - INFO - Using indicator startup period: 14450 ...
2025-04-29 06:20:33,524 - freqtrade.optimize.backtesting - INFO - Loading data from 2025-03-01 21:30:00 up to 2025-04-20 00:00:00 (49 days).
2025-04-29 06:20:33,525 - freqtrade.optimize.backtesting - INFO - Dataload complete. Calculating indicators
2025-04-29 06:20:33,526 - freqtrade.optimize.backtesting - INFO - Running backtesting for Strategy FreqaiExampleStrategy
2025-04-29 06:20:35,089 - matplotlib.font_manager - INFO - generated new fontManager
2025-04-29 06:20:35,292 - freqtrade.resolvers.iresolver - INFO - Using resolved freqaimodel XGBoostRegressor from '/freqtrade/freqtrade/freqai/prediction_models/XGBoostRegressor.py'...
2025-04-29 06:20:35,292 - freqtrade.freqai.data_drawer - INFO - Could not find existing datadrawer, starting from scratch
2025-04-29 06:20:35,293 - freqtrade.freqai.data_drawer - INFO - Could not find existing historic_predictions, starting from scratch
2025-04-29 06:20:35,293 - freqtrade.freqai.freqai_interface - INFO - Set fresh train queue from whitelist. Queue: ['BTC/USDT', 'SOL/USDT']
2025-04-29 06:20:35,294 - freqtrade.strategy.hyper - INFO - Strategy Parameter: buy_rsi = 39.92672300850069
2025-04-29 06:20:35,294 - freqtrade.strategy.hyper - INFO - Strategy Parameter: sell_rsi = 69.92672300850067
2025-04-29 06:20:35,295 - freqtrade.strategy.hyper - INFO - No params for protection found, using default values.
2025-04-29 06:20:35,297 - FreqaiExampleStrategy - INFO - 处理交易对BTC/USDT
2025-04-29 06:20:35,299 - freqtrade.freqai.freqai_interface - INFO - Training 2 timeranges
2025-04-29 06:20:35,300 - freqtrade.freqai.freqai_interface - INFO - Training BTC/USDT, 1/2 pairs from 2025-03-02 00:00:00 to 2025-04-01 00:00:00, 1/2 trains
2025-04-29 06:20:35,300 - freqtrade.freqai.data_kitchen - INFO - Could not find backtesting prediction file at
/freqtrade/user_data/models/test175/backtesting_predictions/cb_btc_1743465600_prediction.feather
2025-04-29 06:20:35,336 - freqtrade.data.dataprovider - INFO - Increasing startup_candle_count for freqai on 5m to 8690
2025-04-29 06:20:35,337 - freqtrade.data.dataprovider - INFO - Loading data for BTC/USDT 5m from 2025-03-01 19:50:00 to 2025-04-20 00:00:00
2025-04-29 06:20:35,407 - freqtrade.data.dataprovider - INFO - Increasing startup_candle_count for freqai on 1h to 770
2025-04-29 06:20:35,408 - freqtrade.data.dataprovider - INFO - Loading data for BTC/USDT 1h from 2025-02-27 22:00:00 to 2025-04-20 00:00:00
2025-04-29 06:20:35,462 - freqtrade.data.dataprovider - INFO - Increasing startup_candle_count for freqai on 3m to 14450
2025-04-29 06:20:35,463 - freqtrade.data.dataprovider - INFO - Loading data for ETH/USDT 3m from 2025-03-01 21:30:00 to 2025-04-20 00:00:00
2025-04-29 06:20:35,556 - freqtrade.data.dataprovider - INFO - Increasing startup_candle_count for freqai on 5m to 8690
2025-04-29 06:20:35,556 - freqtrade.data.dataprovider - INFO - Loading data for ETH/USDT 5m from 2025-03-01 19:50:00 to 2025-04-20 00:00:00
2025-04-29 06:20:35,629 - freqtrade.data.dataprovider - INFO - Increasing startup_candle_count for freqai on 1h to 770
2025-04-29 06:20:35,630 - freqtrade.data.dataprovider - INFO - Loading data for ETH/USDT 1h from 2025-02-27 22:00:00 to 2025-04-20 00:00:00
2025-04-29 06:20:35,679 - FreqaiExampleStrategy - INFO - 设置 FreqAI 目标交易对BTC/USDT
2025-04-29 06:20:35,685 - FreqaiExampleStrategy - INFO - 目标列形状(14450,)
2025-04-29 06:20:35,687 - FreqaiExampleStrategy - INFO - 目标列预览
up_or_down &-buy_rsi
0 1 50.010488
1 1 50.010488
2 1 50.010488
3 1 50.010488
4 1 50.010488
2025-04-29 06:20:35,691 - FreqaiExampleStrategy - INFO - 设置 FreqAI 目标交易对BTC/USDT
2025-04-29 06:20:35,697 - FreqaiExampleStrategy - INFO - 目标列形状(19250,)
2025-04-29 06:20:35,698 - FreqaiExampleStrategy - INFO - 目标列预览
up_or_down &-buy_rsi
0 1 49.846666
1 1 49.846666
2 1 49.846666
3 1 49.846666
4 1 49.846666
2025-04-29 06:20:35,705 - freqtrade.freqai.freqai_interface - INFO - Could not find model at /freqtrade/user_data/models/test175/sub-train-BTC_1743465600/cb_btc_1743465600
2025-04-29 06:20:35,705 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - -------------------- Starting training BTC/USDT --------------------
2025-04-29 06:20:35,726 - freqtrade.freqai.data_kitchen - INFO - BTC/USDT: dropped 0 training points due to NaNs in populated dataset 14400.
2025-04-29 06:20:35,727 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - -------------------- Training on data from 2025-03-02 to 2025-03-31 --------------------
2025-04-29 06:20:35,742 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - Training model on 75 features
2025-04-29 06:20:35,743 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - Training model on 11520 data points
/home/ftuser/.local/lib/python3.12/site-packages/xgboost/core.py:158: UserWarning: [06:20:35] WARNING: /workspace/src/learner.cc:740:
Parameters: { "verbose" } are not used.
warnings.warn(smsg, UserWarning)
[99] validation_0-rmse:0.10879 validation_1-rmse:0.08763
2025-04-29 06:20:36,227 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - -------------------- Done training BTC/USDT (0.52 secs) --------------------
/home/ftuser/.local/lib/python3.12/site-packages/xgboost/core.py:158: UserWarning:
[06:20:36] WARNING: /workspace/src/learner.cc:740:
Parameters: { "verbose" } are not used.
2025-04-29 06:20:36,452 - freqtrade.plot.plotting - INFO - Stored plot as /freqtrade/user_data/models/test175/sub-train-BTC_1743465600/cb_btc_1743465600--buy_rsi.html
2025-04-29 06:20:36,452 - freqtrade.freqai.freqai_interface - INFO - Saving metadata to disk.
2025-04-29 06:20:36,475 - datasieve.pipeline - WARNING - Could not find step di in pipeline, returning None
2025-04-29 06:20:36,482 - freqtrade.freqai.freqai_interface - INFO - Training BTC/USDT, 1/2 pairs from 2025-03-12 00:00:00 to 2025-04-11 00:00:00, 2/2 trains
2025-04-29 06:20:36,483 - freqtrade.freqai.data_kitchen - INFO - Could not find backtesting prediction file at
/freqtrade/user_data/models/test175/backtesting_predictions/cb_btc_1744329600_prediction.feather
2025-04-29 06:20:36,486 - FreqaiExampleStrategy - INFO - 设置 FreqAI 目标交易对BTC/USDT
2025-04-29 06:20:36,492 - FreqaiExampleStrategy - INFO - 目标列形状(19250,)
2025-04-29 06:20:36,494 - FreqaiExampleStrategy - INFO - 目标列预览
up_or_down &-buy_rsi
0 1 49.846666
1 1 49.846666
2 1 49.846666
3 1 49.846666
4 1 49.846666
2025-04-29 06:20:36,499 - FreqaiExampleStrategy - INFO - 设置 FreqAI 目标交易对BTC/USDT
2025-04-29 06:20:36,505 - FreqaiExampleStrategy - INFO - 目标列形状(23570,)
2025-04-29 06:20:36,506 - FreqaiExampleStrategy - INFO - 目标列预览
up_or_down &-buy_rsi
0 1 50.074781
1 1 50.074781
2 1 50.074781
3 1 50.074781
4 1 50.074781
2025-04-29 06:20:36,511 - freqtrade.freqai.freqai_interface - INFO - Could not find model at /freqtrade/user_data/models/test175/sub-train-BTC_1744329600/cb_btc_1744329600
2025-04-29 06:20:36,511 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - -------------------- Starting training BTC/USDT --------------------
2025-04-29 06:20:36,529 - freqtrade.freqai.data_kitchen - INFO - BTC/USDT: dropped 0 training points due to NaNs in populated dataset 14400.
2025-04-29 06:20:36,530 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - -------------------- Training on data from 2025-03-12 to 2025-04-10 --------------------
2025-04-29 06:20:36,546 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - Training model on 75 features
2025-04-29 06:20:36,547 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - Training model on 11520 data points
/home/ftuser/.local/lib/python3.12/site-packages/xgboost/core.py:158: UserWarning:
[06:20:36] WARNING: /workspace/src/learner.cc:740:
Parameters: { "verbose" } are not used.
[99] validation_0-rmse:0.10835 validation_1-rmse:0.08627
2025-04-29 06:20:36,951 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - -------------------- Done training BTC/USDT (0.44 secs) --------------------
2025-04-29 06:20:36,996 - freqtrade.plot.plotting - INFO - Stored plot as /freqtrade/user_data/models/test175/sub-train-BTC_1744329600/cb_btc_1744329600--buy_rsi.html
2025-04-29 06:20:36,997 - freqtrade.freqai.freqai_interface - INFO - Saving metadata to disk.
2025-04-29 06:20:37,014 - datasieve.pipeline - WARNING - Could not find step di in pipeline, returning None
2025-04-29 06:20:37,045 - FreqaiExampleStrategy - WARNING - buy_rsi_pred 列缺失,使用默认值 30 进行初始化
2025-04-29 06:20:37,053 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:37,055 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:37,057 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:37,059 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:37,061 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:37,063 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:37,064 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:37,066 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:37,068 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:37,070 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:37,076 - FreqaiExampleStrategy - INFO - up_or_down 值统计:
up_or_down
1 11845
0 11726
2025-04-29 06:20:37,077 - FreqaiExampleStrategy - INFO - do_predict 值统计:
do_predict
0.0 14451
1.0 9120
2025-04-29 06:20:37,079 - FreqaiExampleStrategy - INFO - 处理交易对SOL/USDT
2025-04-29 06:20:37,080 - freqtrade.freqai.freqai_interface - INFO - Training 2 timeranges
2025-04-29 06:20:37,081 - freqtrade.freqai.freqai_interface - INFO - Training SOL/USDT, 2/2 pairs from 2025-03-02 00:00:00 to 2025-04-01 00:00:00, 1/2 trains
2025-04-29 06:20:37,081 - freqtrade.freqai.data_kitchen - INFO - Could not find backtesting prediction file at
/freqtrade/user_data/models/test175/backtesting_predictions/cb_sol_1743465600_prediction.feather
2025-04-29 06:20:37,104 - freqtrade.data.dataprovider - INFO - Increasing startup_candle_count for freqai on 5m to 8690
2025-04-29 06:20:37,104 - freqtrade.data.dataprovider - INFO - Loading data for SOL/USDT 5m from 2025-03-01 19:50:00 to 2025-04-20 00:00:00
2025-04-29 06:20:37,167 - freqtrade.data.dataprovider - INFO - Increasing startup_candle_count for freqai on 1h to 770
2025-04-29 06:20:37,168 - freqtrade.data.dataprovider - INFO - Loading data for SOL/USDT 1h from 2025-02-27 22:00:00 to 2025-04-20 00:00:00
2025-04-29 06:20:37,216 - freqtrade.data.dataprovider - INFO - Increasing startup_candle_count for freqai on 3m to 14450
2025-04-29 06:20:37,216 - freqtrade.data.dataprovider - INFO - Loading data for BTC/USDT 3m from 2025-03-01 21:30:00 to 2025-04-20 00:00:00
2025-04-29 06:20:37,467 - FreqaiExampleStrategy - INFO - 设置 FreqAI 目标交易对SOL/USDT
2025-04-29 06:20:37,473 - FreqaiExampleStrategy - INFO - 目标列形状(14450,)
2025-04-29 06:20:37,474 - FreqaiExampleStrategy - INFO - 目标列预览
up_or_down &-buy_rsi
0 1 49.72136
1 1 49.72136
2 1 49.72136
3 1 49.72136
4 1 49.72136
2025-04-29 06:20:37,477 - FreqaiExampleStrategy - INFO - 设置 FreqAI 目标交易对SOL/USDT
2025-04-29 06:20:37,483 - FreqaiExampleStrategy - INFO - 目标列形状(19250,)
2025-04-29 06:20:37,484 - FreqaiExampleStrategy - INFO - 目标列预览
up_or_down &-buy_rsi
0 1 49.562407
1 1 49.562407
2 1 49.562407
3 1 49.562407
4 1 49.562407
2025-04-29 06:20:37,490 - freqtrade.freqai.freqai_interface - INFO - Could not find model at /freqtrade/user_data/models/test175/sub-train-SOL_1743465600/cb_sol_1743465600
2025-04-29 06:20:37,490 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - -------------------- Starting training SOL/USDT --------------------
2025-04-29 06:20:37,516 - freqtrade.freqai.data_kitchen - INFO - SOL/USDT: dropped 0 training points due to NaNs in populated dataset 14400.
2025-04-29 06:20:37,516 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - -------------------- Training on data from 2025-03-02 to 2025-03-31 --------------------
2025-04-29 06:20:37,539 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - Training model on 111 features
2025-04-29 06:20:37,540 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - Training model on 11520 data points
/home/ftuser/.local/lib/python3.12/site-packages/xgboost/core.py:158: UserWarning:
[06:20:37] WARNING: /workspace/src/learner.cc:740:
Parameters: { "verbose" } are not used.
[99] validation_0-rmse:0.09426 validation_1-rmse:0.07484
2025-04-29 06:20:38,169 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - -------------------- Done training SOL/USDT (0.68 secs) --------------------
/home/ftuser/.local/lib/python3.12/site-packages/xgboost/core.py:158: UserWarning:
[06:20:38] WARNING: /workspace/src/learner.cc:740:
Parameters: { "verbose" } are not used.
2025-04-29 06:20:38,205 - freqtrade.plot.plotting - INFO - Stored plot as /freqtrade/user_data/models/test175/sub-train-SOL_1743465600/cb_sol_1743465600--buy_rsi.html
2025-04-29 06:20:38,206 - freqtrade.freqai.freqai_interface - INFO - Saving metadata to disk.
2025-04-29 06:20:38,231 - datasieve.pipeline - WARNING - Could not find step di in pipeline, returning None
2025-04-29 06:20:38,237 - freqtrade.freqai.freqai_interface - INFO - Training SOL/USDT, 2/2 pairs from 2025-03-12 00:00:00 to 2025-04-11 00:00:00, 2/2 trains
2025-04-29 06:20:38,238 - freqtrade.freqai.data_kitchen - INFO - Could not find backtesting prediction file at
/freqtrade/user_data/models/test175/backtesting_predictions/cb_sol_1744329600_prediction.feather
2025-04-29 06:20:38,241 - FreqaiExampleStrategy - INFO - 设置 FreqAI 目标交易对SOL/USDT
2025-04-29 06:20:38,247 - FreqaiExampleStrategy - INFO - 目标列形状(19250,)
2025-04-29 06:20:38,248 - FreqaiExampleStrategy - INFO - 目标列预览
up_or_down &-buy_rsi
0 1 49.562407
1 1 49.562407
2 1 49.562407
3 1 49.562407
4 1 49.562407
2025-04-29 06:20:38,255 - FreqaiExampleStrategy - INFO - 设置 FreqAI 目标交易对SOL/USDT
2025-04-29 06:20:38,261 - FreqaiExampleStrategy - INFO - 目标列形状(23570,)
2025-04-29 06:20:38,262 - FreqaiExampleStrategy - INFO - 目标列预览
up_or_down &-buy_rsi
0 1 49.934347
1 1 49.934347
2 1 49.934347
3 1 49.934347
4 1 49.934347
2025-04-29 06:20:38,268 - freqtrade.freqai.freqai_interface - INFO - Could not find model at /freqtrade/user_data/models/test175/sub-train-SOL_1744329600/cb_sol_1744329600
2025-04-29 06:20:38,268 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - -------------------- Starting training SOL/USDT --------------------
2025-04-29 06:20:38,290 - freqtrade.freqai.data_kitchen - INFO - SOL/USDT: dropped 0 training points due to NaNs in populated dataset 14400.
2025-04-29 06:20:38,291 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - -------------------- Training on data from 2025-03-12 to 2025-04-10 --------------------
2025-04-29 06:20:38,314 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - Training model on 111 features
2025-04-29 06:20:38,315 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - Training model on 11520 data points
/home/ftuser/.local/lib/python3.12/site-packages/xgboost/core.py:158: UserWarning:
[06:20:38] WARNING: /workspace/src/learner.cc:740:
Parameters: { "verbose" } are not used.
[99] validation_0-rmse:0.10563 validation_1-rmse:0.08482
2025-04-29 06:20:38,937 - freqtrade.freqai.base_models.BaseRegressionModel - INFO - -------------------- Done training SOL/USDT (0.67 secs) --------------------
2025-04-29 06:20:38,969 - freqtrade.plot.plotting - INFO - Stored plot as /freqtrade/user_data/models/test175/sub-train-SOL_1744329600/cb_sol_1744329600--buy_rsi.html
2025-04-29 06:20:38,969 - freqtrade.freqai.freqai_interface - INFO - Saving metadata to disk.
2025-04-29 06:20:38,994 - datasieve.pipeline - WARNING - Could not find step di in pipeline, returning None
2025-04-29 06:20:39,030 - FreqaiExampleStrategy - WARNING - buy_rsi_pred 列缺失,使用默认值 30 进行初始化
2025-04-29 06:20:39,038 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:39,040 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:39,041 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:39,043 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:39,045 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:39,047 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:39,049 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:39,050 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:39,052 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:39,054 - FreqaiExampleStrategy - INFO - 动态参数buy_rsi=30.0, sell_rsi=50.0, stoploss=-0.15, trailing_stop_positive=0.05
2025-04-29 06:20:39,060 - FreqaiExampleStrategy - INFO - up_or_down 值统计:
up_or_down
0 11865
1 11706
2025-04-29 06:20:39,061 - FreqaiExampleStrategy - INFO - do_predict 值统计:
do_predict
0.0 14451
1.0 9120
2025-04-29 06:20:39,064 - freqtrade.optimize.backtesting - INFO - Backtesting with data from 2025-04-01 00:00:00 up to 2025-04-20 00:00:00 (19 days).
2025-04-29 06:20:39,066 - FreqaiExampleStrategy - ERROR - MACD 或 MACD 信号列缺失,无法生成买入信号。尝试重新计算 MACD 列。
2025-04-29 06:20:39,067 - FreqaiExampleStrategy - INFO - MACD 列已成功重新计算。
2025-04-29 06:20:39,084 - FreqaiExampleStrategy - ERROR - MACD 或 MACD 信号列缺失,无法生成买入信号。尝试重新计算 MACD 列。
2025-04-29 06:20:39,086 - FreqaiExampleStrategy - INFO - MACD 列已成功重新计算。
2025-04-29 06:20:39,186 - freqtrade.misc - INFO - dumping json to "/freqtrade/user_data/backtest_results/backtest-result-2025-04-29_06-20-39.meta.json"
Result for strategy FreqaiExampleStrategy
 BACKTESTING REPORT 
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
  Pair ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃  Win Draw Loss Win% ┃
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
│ BTC/USDT │ 0 │ 0.0 │ 0.000 │ 0.0 │ 0:00 │ 0 0 0 0 │
│ SOL/USDT │ 0 │ 0.0 │ 0.000 │ 0.0 │ 0:00 │ 0 0 0 0 │
│ TOTAL │ 0 │ 0.0 │ 0.000 │ 0.0 │ 0:00 │ 0 0 0 0 │
└──────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┘
 LEFT OPEN TRADES REPORT 
┏━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
  Pair ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃  Win Draw Loss Win% ┃
┡━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
│ TOTAL │ 0 │ 0.0 │ 0.000 │ 0.0 │ 0:00 │ 0 0 0 0 │
└───────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┘
 ENTER TAG STATS 
┏━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
 Enter Tag ┃ Entries ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃  Win Draw Loss Win% ┃
┡━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
│ TOTAL │ 0 │ 0.0 │ 0.000 │ 0.0 │ 0:00 │ 0 0 0 0 │
└───────────┴─────────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┘
 EXIT REASON STATS 
┏━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
 Exit Reason ┃ Exits ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃  Win Draw Loss Win% ┃
┡━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
│ TOTAL │ 0 │ 0.0 │ 0.000 │ 0.0 │ 0:00 │ 0 0 0 0 │
└─────────────┴───────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┘
 MIXED TAG STATS 
┏━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
 Enter Tag ┃ Exit Reason ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃  Win Draw Loss Win% ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
│ TOTAL │ │ 0 │ 0.0 │ 0.000 │ 0.0 │ 0:00 │ 0 0 0 0 │
└───────────┴─────────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┘
No trades made. Your starting balance was 1000 USDT, and your stake was 150 USDT.
Backtested 2025-04-01 00:00:00 -> 2025-04-20 00:00:00 | Max open trades : 2
 STRATEGY SUMMARY 
┏━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
  Strategy ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃  Win Draw Loss Win% ┃  Drawdown ┃
┡━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ FreqaiExampleStrategy │ 0 │ 0.00 │ 0.000 │ 0.0 │ 0:00 │ 0 0 0 0 │ 0 USDT 0.00% │
└───────────────────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┴───────────────┘

18
utf8.py Normal file
View File

@ -0,0 +1,18 @@
import chardet
import codecs
def convert_encoding(input_file, output_file):
# 检测文件编码
with open(input_file, 'rb') as f:
result = chardet.detect(f.read())
encoding = result['encoding']
# 以检测到的编码读取文件内容并以UTF-8编码写入新文件
with codecs.open(input_file, 'r', encoding=encoding) as infile, \
codecs.open(output_file, 'w', encoding='utf-8') as outfile:
outfile.write(infile.read())
if __name__ == "__main__":
input_file = 'freqtrade.log' # 替换为实际的输入文件名
output_file = 'freqtrade_utf8.log' # 替换为你想要的输出文件名
convert_encoding(input_file, output_file)

233
请啊! Normal file
View File

@ -0,0 +1,233 @@
import logging
import numpy as np
from functools import reduce
import talib.abstract as ta
from pandas import DataFrame
from technical import qtpylib
from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter
logger = logging.getLogger(__name__)
class FreqaiExampleStrategy(IStrategy):
# 移除硬编码的 minimal_roi 和 stoploss改为动态适配
minimal_roi = {} # 将在 populate_indicators 中动态生成
stoploss = 0.0 # 将在 populate_indicators 中动态设置
trailing_stop = True
process_only_new_candles = True
use_exit_signal = True
startup_candle_count: int = 40
can_short = False
# 参数定义FreqAI 动态适配 buy_rsi 和 sell_rsi禁用 Hyperopt 优化
buy_rsi = IntParameter(low=10, high=50, default=27, space="buy", optimize=False, load=True)
sell_rsi = IntParameter(low=50, high=90, default=59, space="sell", optimize=False, load=True)
# 为 Hyperopt 优化添加 ROI 和 stoploss 参数
roi_0 = DecimalParameter(low=0.01, high=0.2, default=0.038, space="roi", optimize=True, load=True)
roi_15 = DecimalParameter(low=0.005, high=0.1, default=0.027, space="roi", optimize=True, load=True)
roi_30 = DecimalParameter(low=0.001, high=0.05, default=0.009, space="roi", optimize=True, load=True)
stoploss_param = DecimalParameter(low=-0.35, high=-0.1, default=-0.182, space="stoploss", optimize=True, load=True)
# FreqAI 配置
freqai_info = {
"model": "LightGBMRegressor",
"feature_parameters": {
"include_timeframes": ["5m", "15m", "1h"],
"include_corr_pairlist": [],
"label_period_candles": 12,
"include_shifted_candles": 3,
},
"data_split_parameters": {
"test_size": 0.2,
"shuffle": False,
},
"model_training_parameters": {
"n_estimators": 100,
"learning_rate": 0.1,
"num_leaves": 31,
"verbose": -1,
},
}
plot_config = {
"main_plot": {},
"subplots": {
"&-buy_rsi": {"&-buy_rsi": {"color": "green"}},
"&-sell_rsi": {"&-sell_rsi": {"color": "red"}},
"&-stoploss": {"&-stoploss": {"color": "purple"}},
"&-roi_0": {"&-roi_0": {"color": "orange"}},
"do_predict": {"do_predict": {"color": "brown"}},
},
}
def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, metadata: dict, **kwargs) -> DataFrame:
dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period)
dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period)
dataframe["%-sma-period"] = ta.SMA(dataframe, timeperiod=period)
dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period)
dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period)
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=period, stds=2.2)
dataframe["bb_lowerband-period"] = bollinger["lower"]
dataframe["bb_middleband-period"] = bollinger["mid"]
dataframe["bb_upperband-period"] = bollinger["upper"]
dataframe["%-bb_width-period"] = (
dataframe["bb_upperband-period"] - dataframe["bb_lowerband-period"]
) / dataframe["bb_middleband-period"]
dataframe["%-close-bb_lower-period"] = dataframe["close"] / dataframe["bb_lowerband-period"]
dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period)
dataframe["%-relative_volume-period"] = (
dataframe["volume"] / dataframe["volume"].rolling(period).mean()
)
dataframe.replace([np.inf, -np.inf], 0, inplace=True)
dataframe.ffill(inplace=True)
dataframe.fillna(0, inplace=True)
return dataframe
def feature_engineering_expand_basic(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
dataframe["%-pct-change"] = dataframe["close"].pct_change()
dataframe["%-raw_volume"] = dataframe["volume"]
dataframe["%-raw_price"] = dataframe["close"]
dataframe.replace([np.inf, -np.inf], 0, inplace=True)
dataframe.fillna(method='ffill', inplace=True)
dataframe.fillna(0, inplace=True)
return dataframe
def feature_engineering_standard(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek
dataframe["%-hour_of_day"] = dataframe["date"].dt.hour
dataframe.replace([np.inf, -np.inf], 0, inplace=True)
dataframe.fillna(method='ffill', inplace=True)
dataframe.fillna(0, inplace=True)
return dataframe
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
logger.info(f"设置 FreqAI 目标,交易对:{metadata['pair']}")
if "close" not in dataframe.columns:
logger.error("数据框缺少必要的 'close' 列")
raise ValueError("数据框缺少必要的 'close' 列")
try:
label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
# 生成 %-volatility 特征
dataframe["%-volatility"] = dataframe["close"].pct_change().rolling(20).std()
# 单一回归目标
# 移除对未来的数据依赖
dataframe["&-buy_rsi"] = ta.RSI(dataframe, timeperiod=14)
# 数据清理
for col in ["&-buy_rsi", "%-volatility"]:
dataframe[col].replace([np.inf, -np.inf], 0, inplace=True)
dataframe[col].fillna(method='ffill', inplace=True)
dataframe[col].fillna(0, inplace=True)
if dataframe[col].isna().any():
logger.warning(f"目标列 {col} 仍包含 NaN检查数据生成逻辑")
except Exception as e:
logger.error(f"创建 FreqAI 目标失败:{str(e)}")
raise
logger.info(f"目标列预览:\n{dataframe[['&-buy_rsi']].head().to_string()}")
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
logger.info(f"处理交易对:{metadata['pair']}")
dataframe = self.freqai.start(dataframe, metadata, self)
# 计算传统指标
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
dataframe["bb_lowerband"] = bollinger["lower"]
dataframe["bb_middleband"] = bollinger["mid"]
dataframe["bb_upperband"] = bollinger["upper"]
dataframe["tema"] = ta.TEMA(dataframe, timeperiod=9)
# 生成 up_or_down 信号(非 FreqAI 目标)
label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
# 使用历史数据生成 up_or_down 信号
dataframe["up_or_down"] = np.where(
dataframe["close"] > dataframe["close"].shift(1), 1, 0
)
# 动态设置参数
if "&-buy_rsi" in dataframe.columns:
# 派生其他目标
dataframe["&-sell_rsi"] = dataframe["&-buy_rsi"] + 30
dataframe["%-volatility"] = dataframe["close"].pct_change().rolling(20).std()
dataframe["&-stoploss"] = -0.1 - (dataframe["%-volatility"] * 10).clip(0, 0.25)
dataframe["&-roi_0"] = (dataframe["close"] / dataframe["close"].shift(label_period) - 1).clip(0, 0.2)
# 简化动态参数生成逻辑
dataframe["buy_rsi_pred"] = dataframe["&-buy_rsi"].clip(10, 50)
dataframe["sell_rsi_pred"] = dataframe["&-buy_rsi"] + 30
dataframe["stoploss_pred"] = -0.1 - (dataframe["%-volatility"] * 10).clip(0, 0.25)
dataframe["roi_0_pred"] = dataframe["&-roi_0"].clip(0.01, 0.2)
# 检查预测值
for col in ["buy_rsi_pred", "sell_rsi_pred", "stoploss_pred", "roi_0_pred", "&-sell_rsi", "&-stoploss", "&-roi_0"]:
if dataframe[col].isna().any():
logger.warning(f"列 {col} 包含 NaN填充为默认值")
dataframe[col].fillna(dataframe[col].mean(), inplace=True)
# 更保守的止损和止盈设置
dataframe["trailing_stop_positive"] = (dataframe["roi_0_pred"] * 0.3).clip(0.01, 0.2)
dataframe["trailing_stop_positive_offset"] = (dataframe["roi_0_pred"] * 0.5).clip(0.01, 0.3)
# 设置策略级参数
self.buy_rsi.value = float(dataframe["buy_rsi_pred"].iloc[-1])
self.sell_rsi.value = float(dataframe["sell_rsi_pred"].iloc[-1])
self.stoploss = float(self.stoploss_param.value)
self.minimal_roi = {
0: float(self.roi_0.value),
15: float(self.roi_15.value),
30: float(self.roi_30.value),
60: 0
}
self.trailing_stop_positive = float(dataframe["trailing_stop_positive"].iloc[-1])
self.trailing_stop_positive_offset = float(dataframe["trailing_stop_positive_offset"].iloc[-1])
logger.info(f"动态参数buy_rsi={self.buy_rsi.value}, sell_rsi={self.sell_rsi.value}, "
f"stoploss={self.stoploss}, trailing_stop_positive={self.trailing_stop_positive}")
dataframe.replace([np.inf, -np.inf], 0, inplace=True)
dataframe.fillna(method='ffill', inplace=True)
dataframe.fillna(0, inplace=True)
logger.info(f"up_or_down 值统计:\n{dataframe['up_or_down'].value_counts().to_string()}")
logger.info(f"do_predict 值统计:\n{dataframe['do_predict'].value_counts().to_string()}")
return dataframe
def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
enter_long_conditions = [
qtpylib.crossed_above(df["rsi"], df["buy_rsi_pred"]),
df["volume"] > 0
]
if enter_long_conditions:
df.loc[
reduce(lambda x, y: x & y, enter_long_conditions),
["enter_long", "enter_tag"]
] = (1, "long")
return df
def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
exit_long_conditions = [
qtpylib.crossed_above(df["rsi"], df["sell_rsi_pred"]),
df["volume"] > 0
]
if exit_long_conditions:
df.loc[
reduce(lambda x, y: x & y, exit_long_conditions),
"exit_long"
] = 1
return df
def confirm_trade_entry(
self, pair: str, order_type: str, amount: float, rate: float,
time_in_force: str, current_time, entry_tag, side: str, **kwargs
) -> bool:
df, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = df.iloc[-1].squeeze()
if side == "long":
if rate > (last_candle["close"] * (1 + 0.0025)):
return False
return True