Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5027018fe0 | ||
|
|
5df9f23baf | ||
|
|
fdc1fa0374 | ||
|
|
0d914c2b76 | ||
|
|
cd5befd8c9 | ||
|
|
196c0093cc | ||
|
|
ed011ef498 | ||
|
|
4dcfc172f9 | ||
|
|
65b9e9c0fc | ||
|
|
cca246abfd | ||
|
|
37173ab636 | ||
|
|
8f4c374e6b | ||
|
|
ff7aff8ee7 | ||
|
|
e5cc226c01 | ||
|
|
63c1f07f06 | ||
|
|
b20684b5b1 | ||
|
|
96b76ffcc0 | ||
|
|
0fa0866370 | ||
|
|
887c4778b4 | ||
|
|
8777726441 | ||
|
|
b6b9a62c35 | ||
|
|
3fafbff8c3 | ||
|
|
619de5cede | ||
|
|
8535b10cea | ||
|
|
7da603fd08 | ||
|
|
144615b7a8 | ||
|
|
8448ab40f5 | ||
|
|
6916e49479 | ||
|
|
29fd0941a0 | ||
|
|
ec7d7c2842 | ||
|
|
ea707fe104 | ||
|
|
2f4a06d505 | ||
|
|
65116ab7b4 | ||
|
|
fbd72745cb | ||
|
|
8477bf07c7 | ||
|
|
03a54a5b0a | ||
|
|
e3ffdd92e0 | ||
|
|
c3e4a73eb3 | ||
|
|
21e4c2f2ea | ||
|
|
86e9a2ab61 | ||
|
|
05b65162a1 | ||
|
|
64e2edfa4e | ||
|
|
328769e0e1 | ||
|
|
82ed0e90e9 | ||
|
|
244b91ebd3 | ||
|
|
e0884d4349 | ||
|
|
456ae1fde0 | ||
|
|
b72587ed6a | ||
|
|
c145d5d452 | ||
|
|
872bfe4078 | ||
|
|
6e4e54b9c8 |
5
### **4. 测试优化后的策略**
Normal file
5
### **4. 测试优化后的策略**
Normal 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
4
.gitignore
vendored
@ -73,7 +73,9 @@ coverage.xml
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
#*.log
|
||||
!outout_filted.log
|
||||
|
||||
local_settings.py
|
||||
|
||||
# Flask stuff:
|
||||
|
||||
264
03a54a5b0ae8efd49daf13c408a37a2d3c7816bf.diff
Normal file
264
03a54a5b0ae8efd49daf13c408a37a2d3c7816bf.diff
Normal 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
5
4. **清理缓存**:
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
rm -rf /freqtrade/user_data/models/test62/
|
||||
>>>>>>> Snippet
|
||||
5
5. **重新训练**:
Normal file
5
5. **重新训练**:
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
freqtrade trade --config config_examples/config_freqai.okx.json --strategy FreqaiExampleStrategy
|
||||
>>>>>>> Snippet
|
||||
@ -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"
|
||||
}
|
||||
@ -5,6 +5,7 @@
|
||||
"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,
|
||||
@ -62,49 +63,45 @@
|
||||
"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,
|
||||
"train_period_days": 15,
|
||||
"identifier": "test62",
|
||||
"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
|
||||
},
|
||||
"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,
|
||||
"weight_factor": 0.9,
|
||||
"principal_component_analysis": false,
|
||||
"use_SVM_to_remove_outliers": false,
|
||||
"indicator_periods_candles": [
|
||||
10,
|
||||
20,
|
||||
50
|
||||
],
|
||||
"plot_feature_importances": 0
|
||||
"include_timeframes": ["3m", "5m", "1h"],
|
||||
"include_corr_pairlist": ["BTC/USDT", "ETH/USDT"],
|
||||
"label_period_candles": 12,
|
||||
"include_shifted_candles": 3,
|
||||
"indicator_periods_candles": [10, 20, 50],
|
||||
"plot_feature_importances": 1
|
||||
},
|
||||
"data_split_parameters": {
|
||||
"test_size": 0.2
|
||||
"test_size": 0.2,
|
||||
"shuffle": true,
|
||||
"random_state": 42
|
||||
},
|
||||
"model_training_parameters": {
|
||||
"n_estimators": 100,
|
||||
"n_estimators": 200,
|
||||
"learning_rate": 0.05,
|
||||
"max_depth": 5,
|
||||
"num_leaves": 31
|
||||
"subsample": 0.8,
|
||||
"colsample_bytree": 0.8,
|
||||
"objective": "reg:squarederror",
|
||||
"eval_metric": "rmse",
|
||||
"early_stopping_rounds": 50,
|
||||
"verbose": 0
|
||||
}
|
||||
},
|
||||
"api_server": {
|
||||
|
||||
122
config_examples/xgboostregression-ok1-kandipai.diff
Normal file
122
config_examples/xgboostregression-ok1-kandipai.diff
Normal 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"
|
||||
}
|
||||
@ -64,9 +64,10 @@ 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
|
||||
--strategy FreqaiExampleStrategy
|
||||
--timerange 20240920-20250420
|
||||
--timerange 20250401-20250420
|
||||
--cache none
|
||||
|
||||
7
filter.py
Normal file
7
filter.py
Normal 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
1162
freqai/data_kitchen.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,311 +0,0 @@
|
||||
import logging
|
||||
|
||||
import numpy as np # noqa
|
||||
import pandas as pd # noqa
|
||||
import talib.abstract as ta
|
||||
from pandas import DataFrame
|
||||
from technical import qtpylib
|
||||
|
||||
from freqtrade.strategy import IntParameter, IStrategy, merge_informative_pair
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FreqaiExampleHybridStrategy(IStrategy):
|
||||
"""
|
||||
Example of a hybrid FreqAI strat, designed to illustrate how a user may employ
|
||||
FreqAI to bolster a typical Freqtrade strategy.
|
||||
|
||||
Launching this strategy would be:
|
||||
|
||||
freqtrade trade --strategy FreqaiExampleHybridStrategy --strategy-path freqtrade/templates
|
||||
--freqaimodel CatboostClassifier --config config_examples/config_freqai.example.json
|
||||
|
||||
or the user simply adds this to their config:
|
||||
|
||||
"freqai": {
|
||||
"enabled": true,
|
||||
"purge_old_models": 2,
|
||||
"train_period_days": 15,
|
||||
"identifier": "unique-id",
|
||||
"feature_parameters": {
|
||||
"include_timeframes": [
|
||||
"3m",
|
||||
"15m",
|
||||
"1h"
|
||||
],
|
||||
"include_corr_pairlist": [
|
||||
"BTC/USDT",
|
||||
"ETH/USDT"
|
||||
],
|
||||
"label_period_candles": 20,
|
||||
"include_shifted_candles": 2,
|
||||
"DI_threshold": 0.9,
|
||||
"weight_factor": 0.9,
|
||||
"principal_component_analysis": false,
|
||||
"use_SVM_to_remove_outliers": true,
|
||||
"indicator_periods_candles": [10, 20]
|
||||
},
|
||||
"data_split_parameters": {
|
||||
"test_size": 0,
|
||||
"random_state": 1
|
||||
},
|
||||
"model_training_parameters": {
|
||||
"n_estimators": 800
|
||||
}
|
||||
},
|
||||
|
||||
Thanks to @smarmau and @johanvulgt for developing and sharing the strategy.
|
||||
"""
|
||||
|
||||
minimal_roi = {
|
||||
# "120": 0.0, # exit after 120 minutes at break even
|
||||
"60": 0.01,
|
||||
"30": 0.02,
|
||||
"0": 0.04,
|
||||
}
|
||||
|
||||
plot_config = {
|
||||
"main_plot": {
|
||||
"tema": {},
|
||||
},
|
||||
"subplots": {
|
||||
"MACD": {
|
||||
"macd": {"color": "blue"},
|
||||
"macdsignal": {"color": "orange"},
|
||||
},
|
||||
"RSI": {
|
||||
"rsi": {"color": "red"},
|
||||
},
|
||||
"Up_or_down": {
|
||||
"&s-up_or_down": {"color": "green"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
process_only_new_candles = True
|
||||
stoploss = -0.05
|
||||
use_exit_signal = True
|
||||
startup_candle_count: int = 30
|
||||
can_short = False
|
||||
|
||||
# Hyperoptable parameters
|
||||
buy_rsi = IntParameter(low=1, high=50, default=30, space="buy", optimize=True, load=True)
|
||||
sell_rsi = IntParameter(low=50, high=100, default=70, space="sell", optimize=True, load=True)
|
||||
|
||||
def feature_engineering_expand_all(
|
||||
self, dataframe: DataFrame, period: int, metadata: dict, **kwargs
|
||||
) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
This function will automatically expand the defined features on the config defined
|
||||
`indicator_periods_candles`, `include_timeframes`, `include_shifted_candles`, and
|
||||
`include_corr_pairs`. In other words, a single feature defined in this function
|
||||
will automatically expand to a total of
|
||||
`indicator_periods_candles` * `include_timeframes` * `include_shifted_candles` *
|
||||
`include_corr_pairs` numbers of features added to the model.
|
||||
|
||||
All features must be prepended with `%` to be recognized by FreqAI internals.
|
||||
|
||||
More details on how these config defined parameters accelerate feature engineering
|
||||
in the documentation at:
|
||||
|
||||
https://www.freqtrade.io/en/latest/freqai-parameter-table/#feature-parameters
|
||||
|
||||
https://www.freqtrade.io/en/latest/freqai-feature-engineering/#defining-the-features
|
||||
|
||||
:param dataframe: strategy dataframe which will receive the features
|
||||
:param period: period of the indicator - usage example:
|
||||
:param metadata: metadata of current pair
|
||||
dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period)
|
||||
"""
|
||||
|
||||
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
|
||||
)
|
||||
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()
|
||||
)
|
||||
|
||||
return dataframe
|
||||
|
||||
def feature_engineering_expand_basic(
|
||||
self, dataframe: DataFrame, metadata: dict, **kwargs
|
||||
) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
This function will automatically expand the defined features on the config defined
|
||||
`include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`.
|
||||
In other words, a single feature defined in this function
|
||||
will automatically expand to a total of
|
||||
`include_timeframes` * `include_shifted_candles` * `include_corr_pairs`
|
||||
numbers of features added to the model.
|
||||
|
||||
Features defined here will *not* be automatically duplicated on user defined
|
||||
`indicator_periods_candles`
|
||||
|
||||
All features must be prepended with `%` to be recognized by FreqAI internals.
|
||||
|
||||
More details on how these config defined parameters accelerate feature engineering
|
||||
in the documentation at:
|
||||
|
||||
https://www.freqtrade.io/en/latest/freqai-parameter-table/#feature-parameters
|
||||
|
||||
https://www.freqtrade.io/en/latest/freqai-feature-engineering/#defining-the-features
|
||||
|
||||
:param dataframe: strategy dataframe which will receive the features
|
||||
:param metadata: metadata of current pair
|
||||
dataframe["%-pct-change"] = dataframe["close"].pct_change()
|
||||
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(
|
||||
self, dataframe: DataFrame, metadata: dict, **kwargs
|
||||
) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
This optional function will be called once with the dataframe of the base timeframe.
|
||||
This is the final function to be called, which means that the dataframe entering this
|
||||
function will contain all the features and columns created by all other
|
||||
freqai_feature_engineering_* functions.
|
||||
|
||||
This function is a good place to do custom exotic feature extractions (e.g. tsfresh).
|
||||
This function is a good place for any feature that should not be auto-expanded upon
|
||||
(e.g. day of the week).
|
||||
|
||||
All features must be prepended with `%` to be recognized by FreqAI internals.
|
||||
|
||||
More details about feature engineering available:
|
||||
|
||||
https://www.freqtrade.io/en/latest/freqai-feature-engineering
|
||||
|
||||
:param dataframe: strategy dataframe which will receive the features
|
||||
:param metadata: metadata of current pair
|
||||
usage example: dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7
|
||||
"""
|
||||
dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek
|
||||
dataframe["%-hour_of_day"] = dataframe["date"].dt.hour
|
||||
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"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")
|
||||
raise ValueError("Required 'close' column missing in dataframe")
|
||||
|
||||
if len(dataframe) < 50:
|
||||
logger.error(f"Insufficient data: {len(dataframe)} rows, need at least 50 for shift(-50)")
|
||||
raise ValueError("Insufficient data for target calculation")
|
||||
|
||||
try:
|
||||
# 生成数值型标签:1 表示上涨,0 表示下跌
|
||||
dataframe["&-up_or_down"] = np.where(
|
||||
dataframe["close"].shift(-50) > dataframe["close"],
|
||||
1.0, # 数值型标签
|
||||
0.0
|
||||
)
|
||||
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
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
logger.info(f"Processing pair: {metadata['pair']}")
|
||||
logger.info(f"Input DataFrame shape: {dataframe.shape}")
|
||||
logger.info(f"Input DataFrame columns: {list(dataframe.columns)}")
|
||||
logger.info(f"Input DataFrame head:\n{dataframe[['date', 'close', 'volume']].head().to_string()}")
|
||||
|
||||
# Ensure FreqAI processing
|
||||
logger.info("Calling self.freqai.start")
|
||||
try:
|
||||
dataframe = self.freqai.start(dataframe, metadata, self)
|
||||
except Exception as e:
|
||||
logger.error(f"self.freqai.start failed: {str(e)}")
|
||||
raise
|
||||
logger.info("self.freqai.start completed")
|
||||
|
||||
logger.info(f"Output DataFrame shape: {dataframe.shape}")
|
||||
logger.info(f"Output DataFrame columns: {list(dataframe.columns)}")
|
||||
# Safely log columns that exist
|
||||
available_columns = [col for col in ['date', 'close', '&-up_or_down'] if col in dataframe.columns]
|
||||
logger.info(f"Output DataFrame head:\n{dataframe[available_columns].head().to_string()}")
|
||||
|
||||
if "&-up_or_down" not in dataframe.columns:
|
||||
logger.error("FreqAI did not generate the required &-up_or_down column")
|
||||
raise KeyError("FreqAI did not generate the required &-up_or_down column")
|
||||
|
||||
# RSI
|
||||
dataframe["rsi"] = ta.RSI(dataframe)
|
||||
|
||||
# Bollinger Bands
|
||||
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_percent"] = (dataframe["close"] - dataframe["bb_lowerband"]) / (
|
||||
dataframe["bb_upperband"] - dataframe["bb_lowerband"]
|
||||
)
|
||||
dataframe["bb_width"] = (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe[
|
||||
"bb_middleband"
|
||||
]
|
||||
|
||||
# TEMA
|
||||
dataframe["tema"] = ta.TEMA(dataframe, timeperiod=9)
|
||||
|
||||
return dataframe
|
||||
def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
|
||||
df.loc[
|
||||
(
|
||||
(qtpylib.crossed_above(df["rsi"], self.buy_rsi.value))
|
||||
& (df["tema"] <= df["bb_middleband"])
|
||||
& (df["tema"] > df["tema"].shift(1))
|
||||
& (df["volume"] > 0)
|
||||
),
|
||||
"enter_long",
|
||||
] = 1
|
||||
return df
|
||||
|
||||
def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
|
||||
df.loc[
|
||||
(
|
||||
(qtpylib.crossed_above(df["rsi"], self.sell_rsi.value))
|
||||
& (df["tema"] > df["bb_middleband"])
|
||||
& (df["tema"] < df["tema"].shift(1))
|
||||
& (df["volume"] > 0)
|
||||
),
|
||||
"exit_long",
|
||||
] = 1
|
||||
return df
|
||||
@ -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"
|
||||
}
|
||||
@ -30,23 +30,34 @@ class FreqaiExampleStrategy(IStrategy):
|
||||
|
||||
# FreqAI 配置
|
||||
freqai_info = {
|
||||
"model": "LightGBMRegressor",
|
||||
"model": "XGBoostRegressor", # 与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,
|
||||
"shuffle": False,
|
||||
"shuffle": True, # 启用shuffle
|
||||
},
|
||||
"model_training_parameters": {
|
||||
"n_estimators": 100,
|
||||
"learning_rate": 0.1,
|
||||
"num_leaves": 31,
|
||||
"verbose": -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,
|
||||
},
|
||||
"data_kitchen": {
|
||||
"feature_parameters": {
|
||||
"DI_threshold": 1.5, # 降低异常值过滤阈值
|
||||
"use_DBSCAN_to_remove_outliers": False # 禁用DBSCAN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plot_config = {
|
||||
@ -61,42 +72,77 @@ class FreqaiExampleStrategy(IStrategy):
|
||||
}
|
||||
|
||||
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()
|
||||
# 确保基础价格数据存在
|
||||
if "close" not in dataframe.columns:
|
||||
raise ValueError("Dataframe must contain 'close' column")
|
||||
|
||||
# 计算技术指标
|
||||
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
|
||||
dataframe["sma_short"] = ta.SMA(dataframe, timeperiod=12)
|
||||
dataframe["sma_long"] = ta.SMA(dataframe, timeperiod=26)
|
||||
dataframe["sma_cross"] = np.where(dataframe["sma_short"] > dataframe["sma_long"], 1, -1)
|
||||
|
||||
# 布林带
|
||||
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_pct"] = (dataframe["close"] - dataframe["bb_lowerband"]) / (
|
||||
dataframe["bb_upperband"] - dataframe["bb_lowerband"]
|
||||
)
|
||||
dataframe.replace([np.inf, -np.inf], 0, inplace=True)
|
||||
dataframe.ffill(inplace=True)
|
||||
dataframe.fillna(0, inplace=True)
|
||||
|
||||
# 成交量特征
|
||||
dataframe["volume_ma"] = dataframe["volume"].rolling(window=20).mean()
|
||||
dataframe["volume_pct"] = dataframe["volume"] / dataframe["volume_ma"]
|
||||
|
||||
# 价格变化特征
|
||||
dataframe["pct_change"] = dataframe["close"].pct_change()
|
||||
dataframe["pct_change_5"] = dataframe["close"].pct_change(5)
|
||||
dataframe["pct_change_10"] = dataframe["close"].pct_change(10)
|
||||
|
||||
# 动量指标
|
||||
dataframe["momentum"] = dataframe["close"] / dataframe["close"].shift(4) - 1
|
||||
dataframe["roc"] = ta.ROC(dataframe, timeperiod=10)
|
||||
|
||||
# 波动率
|
||||
dataframe["volatility"] = dataframe["close"].pct_change().rolling(window=20).std()
|
||||
|
||||
# 数据清理
|
||||
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)
|
||||
|
||||
# 确保至少有一个特征
|
||||
if len(dataframe.columns) == 0:
|
||||
raise ValueError("No features generated in feature engineering")
|
||||
|
||||
logger.info(f"特征工程完成,生成特征数量:{len(dataframe.columns)}")
|
||||
logger.debug(f"特征列表:{list(dataframe.columns)}")
|
||||
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)
|
||||
# 数据清理逻辑
|
||||
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:
|
||||
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.ffill(inplace=True)
|
||||
dataframe.fillna(0, inplace=True)
|
||||
return dataframe
|
||||
|
||||
@ -108,24 +154,48 @@ class FreqaiExampleStrategy(IStrategy):
|
||||
|
||||
try:
|
||||
label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
|
||||
# 生成 %-volatility 特征
|
||||
|
||||
# 定义目标变量为未来价格变化百分比(连续值)
|
||||
dataframe["target"] = (
|
||||
dataframe["close"].shift(-label_period) - dataframe["close"]
|
||||
) / dataframe["close"]
|
||||
|
||||
# 添加辅助目标变量
|
||||
dataframe["target_5"] = (
|
||||
dataframe["close"].shift(-5) - dataframe["close"]
|
||||
) / dataframe["close"]
|
||||
|
||||
dataframe["target_10"] = (
|
||||
dataframe["close"].shift(-10) - dataframe["close"]
|
||||
) / dataframe["close"]
|
||||
|
||||
# 数据清理:处理 NaN 和 Inf 值
|
||||
for col in ["target", "target_5", "target_10"]:
|
||||
dataframe[col] = dataframe[col].replace([np.inf, -np.inf], np.nan)
|
||||
dataframe[col] = dataframe[col].ffill().fillna(0)
|
||||
|
||||
# 确保目标变量是二维数组
|
||||
if dataframe["target"].ndim == 1:
|
||||
dataframe["target"] = dataframe["target"].values.reshape(-1, 1)
|
||||
|
||||
# 生成波动率特征
|
||||
dataframe["%-volatility"] = dataframe["close"].pct_change().rolling(20).std()
|
||||
|
||||
# 单一回归目标
|
||||
dataframe["&-buy_rsi"] = ta.RSI(dataframe, timeperiod=14).shift(-label_period)
|
||||
|
||||
# 数据清理
|
||||
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)
|
||||
for col in ["target", "target_5", "target_10", "%-volatility"]:
|
||||
dataframe[col] = dataframe[col].replace([np.inf, -np.inf], np.nan)
|
||||
dataframe[col] = dataframe[col].ffill()
|
||||
dataframe[col] = dataframe[col].fillna(dataframe[col].mean())
|
||||
if dataframe[col].isna().any():
|
||||
logger.warning(f"目标列 {col} 仍包含 NaN,检查数据生成逻辑")
|
||||
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['target'].shape}")
|
||||
logger.info(f"目标列预览:\n{dataframe[['target', 'target_5', 'target_10']].head().to_string()}")
|
||||
return dataframe
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
@ -142,6 +212,8 @@ class FreqaiExampleStrategy(IStrategy):
|
||||
|
||||
# 生成 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
|
||||
)
|
||||
@ -151,55 +223,64 @@ class FreqaiExampleStrategy(IStrategy):
|
||||
# 派生其他目标
|
||||
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"].shift(-label_period) / dataframe["close"] - 1).clip(0, 0.2)
|
||||
# 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)
|
||||
|
||||
# 限制预测值,添加平滑
|
||||
dataframe["buy_rsi_pred"] = dataframe["&-buy_rsi"].rolling(5).mean().clip(10, 50)
|
||||
dataframe["buy_rsi_pred"].fillna(dataframe["buy_rsi_pred"].mean(), inplace=True)
|
||||
if dataframe["buy_rsi_pred"].isna().any():
|
||||
logger.warning("buy_rsi_pred 列包含 NaN,已填充为默认值")
|
||||
dataframe["sell_rsi_pred"] = dataframe["&-sell_rsi"].rolling(5).mean().clip(50, 90)
|
||||
dataframe["sell_rsi_pred"].fillna(dataframe["sell_rsi_pred"].mean(), inplace=True)
|
||||
if dataframe["sell_rsi_pred"].isna().any():
|
||||
logger.warning("sell_rsi_pred 列包含 NaN,已填充为默认值")
|
||||
dataframe["stoploss_pred"] = dataframe["&-stoploss"].clip(-0.35, -0.1)
|
||||
dataframe["stoploss_pred"].fillna(dataframe["stoploss_pred"].mean(), inplace=True)
|
||||
if dataframe["stoploss_pred"].isna().any():
|
||||
logger.warning("stoploss_pred 列包含 NaN,已填充为默认值")
|
||||
# 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 的生成逻辑
|
||||
# 计算 buy_rsi_pred 并清理 NaN 值
|
||||
dataframe["buy_rsi_pred"] = dataframe["rsi"].rolling(window=10).mean().clip(30, 50)
|
||||
dataframe["buy_rsi_pred"] = dataframe["buy_rsi_pred"].fillna(dataframe["buy_rsi_pred"].median())
|
||||
|
||||
# 计算 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())
|
||||
|
||||
# 计算 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())
|
||||
|
||||
# 计算 roi_0_pred 并清理 NaN 值
|
||||
dataframe["roi_0_pred"] = dataframe["&-roi_0"].clip(0.01, 0.2)
|
||||
dataframe["roi_0_pred"].fillna(dataframe["roi_0_pred"].mean(), inplace=True)
|
||||
if dataframe["roi_0_pred"].isna().any():
|
||||
logger.warning("roi_0_pred 列包含 NaN,已填充为默认值")
|
||||
dataframe["roi_0_pred"] = dataframe["roi_0_pred"].fillna(dataframe["roi_0_pred"].mean())
|
||||
|
||||
# 检查预测值
|
||||
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[col] = dataframe[col].fillna(dataframe[col].mean())
|
||||
|
||||
# 动态追踪止盈
|
||||
dataframe["trailing_stop_positive"] = (dataframe["roi_0_pred"] * 0.5).clip(0.01, 0.3)
|
||||
dataframe["trailing_stop_positive_offset"] = (dataframe["roi_0_pred"] * 0.75).clip(0.02, 0.4)
|
||||
# 更保守的止损和止盈设置
|
||||
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.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 = float(dataframe["trailing_stop_positive"].iloc[-1])
|
||||
self.trailing_stop_positive_offset = float(dataframe["trailing_stop_positive_offset"].iloc[-1])
|
||||
# 更保守的追踪止损设置
|
||||
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.fillna(method='ffill', 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()}")
|
||||
@ -207,28 +288,13 @@ class FreqaiExampleStrategy(IStrategy):
|
||||
|
||||
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["tema"] > df["tema"].shift(1),
|
||||
df["volume"] > 0,
|
||||
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")
|
||||
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.97),
|
||||
df["volume"] > 0,
|
||||
df["do_predict"] == 1,
|
||||
df["up_or_down"] == 0
|
||||
(df["rsi"] > df["sell_rsi_pred"]), # RSI 高于卖出阈值
|
||||
(df["volume"] > df["volume"].rolling(window=10).mean()), # 成交量高于近期均值
|
||||
(df["close"] < df["bb_middleband"]), # 价格低于布林带中轨
|
||||
(df["sma_short"] < df["sma_long"]) # SMA 死叉(短期 SMA 下穿长期 SMA)
|
||||
]
|
||||
if exit_long_conditions:
|
||||
df.loc[
|
||||
@ -236,7 +302,29 @@ class FreqaiExampleStrategy(IStrategy):
|
||||
"exit_long"
|
||||
] = 1
|
||||
return df
|
||||
def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
|
||||
# 改进买入信号条件
|
||||
# 计算短期和长期 SMA
|
||||
df["sma_short"] = ta.SMA(df, timeperiod=12)
|
||||
df["sma_long"] = ta.SMA(df, timeperiod=26)
|
||||
|
||||
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"]) # 价格高于布林带中轨
|
||||
]
|
||||
|
||||
# 添加 SMA 金叉条件(短期 SMA 上穿长期 SMA)
|
||||
enter_long_conditions.append((df["sma_short"] > df["sma_long"]))
|
||||
|
||||
# 确保模型预测为买入
|
||||
enter_long_conditions.append((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")
|
||||
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
|
||||
|
||||
183
freqtrade/templates/aaa.md
Normal file
183
freqtrade/templates/aaa.md
Normal 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
|
||||
```
|
||||
```
|
||||
```
|
||||
```
|
||||
```
|
||||
```
|
||||
```
|
||||
```
|
||||
387
output_filted.log
Normal file
387
output_filted.log
Normal file
@ -0,0 +1,387 @@
|
||||
Creating freqtrade_freqtrade_run ...
|
||||
Creating freqtrade_freqtrade_run ... done
|
||||
2025-04-29 08:31:07,002 - freqtrade - INFO - freqtrade 2025.3
|
||||
2025-04-29 08:31:07,217 - numexpr.utils - INFO - NumExpr defaulting to 12 threads.
|
||||
2025-04-29 08:31:08,612 - freqtrade.configuration.load_config - INFO - Using config: /freqtrade/config_examples/config_freqai.okx.json ...
|
||||
2025-04-29 08:31:08,615 - freqtrade.loggers - INFO - Enabling colorized output.
|
||||
2025-04-29 08:31:08,615[90m - [0m[95mroot[0m[90m - [0m[34mINFO[0m[90m - [0mLogfile configured
|
||||
2025-04-29 08:31:08,615[90m - [0m[95mfreqtrade.loggers[0m[90m - [0m[34mINFO[0m[90m - [0mVerbosity set to 0
|
||||
2025-04-29 08:31:08,616[90m - [0m[95mfreqtrade.configuration.configuration[0m[90m - [0m[34mINFO[0m[90m - [0mUsing additional Strategy lookup path: /freqtrade/templates
|
||||
2025-04-29 08:31:08,616[90m - [0m[95mfreqtrade.configuration.configuration[0m[90m - [0m[34mINFO[0m[90m - [0mUsing max_open_trades: 4 ...
|
||||
2025-04-29 08:31:08,617[90m - [0m[95mfreqtrade.configuration.configuration[0m[90m - [0m[34mINFO[0m[90m - [0mParameter --timerange detected: 20250401-20250420 ...
|
||||
2025-04-29 08:31:08,640[90m - [0m[95mfreqtrade.configuration.configuration[0m[90m - [0m[34mINFO[0m[90m - [0mUsing user-data directory: /freqtrade/user_data ...
|
||||
2025-04-29 08:31:08,641[90m - [0m[95mfreqtrade.configuration.configuration[0m[90m - [0m[34mINFO[0m[90m - [0mUsing data directory: /freqtrade/user_data/data/okx ...
|
||||
2025-04-29 08:31:08,641[90m - [0m[95mfreqtrade.configuration.configuration[0m[90m - [0m[34mINFO[0m[90m - [0mParameter --cache=none detected ...
|
||||
2025-04-29 08:31:08,642[90m - [0m[95mfreqtrade.configuration.configuration[0m[90m - [0m[34mINFO[0m[90m - [0mFilter trades by timerange: 20250401-20250420
|
||||
2025-04-29 08:31:08,642[90m - [0m[95mfreqtrade.configuration.configuration[0m[90m - [0m[34mINFO[0m[90m - [0mUsing freqaimodel class name: XGBoostRegressor
|
||||
2025-04-29 08:31:08,643[90m - [0m[95mfreqtrade.exchange.check_exchange[0m[90m - [0m[34mINFO[0m[90m - [0mChecking exchange...
|
||||
2025-04-29 08:31:08,649[90m - [0m[95mfreqtrade.exchange.check_exchange[0m[90m - [0m[34mINFO[0m[90m - [0mExchange "okx" is officially supported by the Freqtrade development team.
|
||||
2025-04-29 08:31:08,649[90m - [0m[95mfreqtrade.configuration.configuration[0m[90m - [0m[34mINFO[0m[90m - [0mUsing pairlist from configuration.
|
||||
2025-04-29 08:31:08,650[90m - [0m[95mfreqtrade.configuration.config_validation[0m[90m - [0m[34mINFO[0m[90m - [0mValidating configuration ...
|
||||
2025-04-29 08:31:08,652[90m - [0m[95mfreqtrade.commands.optimize_commands[0m[90m - [0m[34mINFO[0m[90m - [0mStarting freqtrade in Backtesting mode
|
||||
2025-04-29 08:31:08,652[90m - [0m[95mfreqtrade.exchange.exchange[0m[90m - [0m[34mINFO[0m[90m - [0mInstance is running with dry_run enabled
|
||||
2025-04-29 08:31:08,653[90m - [0m[95mfreqtrade.exchange.exchange[0m[90m - [0m[34mINFO[0m[90m - [0mUsing CCXT 4.4.69
|
||||
2025-04-29 08:31:08,653[90m - [0m[95mfreqtrade.exchange.exchange[0m[90m - [0m[34mINFO[0m[90m - [0mApplying additional ccxt config: {'enableRateLimit': True, 'rateLimit': 500, 'options': {'defaultType': 'spot'}}
|
||||
2025-04-29 08:31:08,658[90m - [0m[95mfreqtrade.exchange.exchange[0m[90m - [0m[34mINFO[0m[90m - [0mApplying additional ccxt config: {'enableRateLimit': True, 'rateLimit': 500, 'options': {'defaultType': 'spot'}, 'timeout': 20000}
|
||||
2025-04-29 08:31:08,664[90m - [0m[95mfreqtrade.exchange.exchange[0m[90m - [0m[34mINFO[0m[90m - [0mUsing Exchange "OKX"
|
||||
2025-04-29 08:31:11,241[90m - [0m[95mfreqtrade.resolvers.exchange_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mUsing resolved exchange 'Okx'...
|
||||
2025-04-29 08:31:11,261[90m - [0m[95mfreqtrade.resolvers.iresolver[0m[90m - [0m[34mINFO[0m[90m - [0mUsing resolved strategy FreqaiExampleStrategy from '/freqtrade/templates/FreqaiExampleStrategy.py'...
|
||||
2025-04-29 08:31:11,262[90m - [0m[95mfreqtrade.strategy.hyper[0m[90m - [0m[34mINFO[0m[90m - [0mLoading parameters from file /freqtrade/templates/FreqaiExampleStrategy.json
|
||||
2025-04-29 08:31:11,263[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mOverride strategy 'timeframe' with value in config file: 3m.
|
||||
2025-04-29 08:31:11,263[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mOverride strategy 'stoploss' with value in config file: -0.05.
|
||||
2025-04-29 08:31:11,264[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mOverride strategy 'stake_currency' with value in config file: USDT.
|
||||
2025-04-29 08:31:11,264[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mOverride strategy 'stake_amount' with value in config file: 150.
|
||||
2025-04-29 08:31:11,264[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mOverride strategy 'startup_candle_count' with value in config file: 30.
|
||||
2025-04-29 08:31:11,265[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mOverride strategy 'unfilledtimeout' with value in config file: {'entry': 5, 'exit': 15, 'exit_timeout_count': 0, 'unit':
|
||||
'minutes'}.
|
||||
2025-04-29 08:31:11,265[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mOverride strategy 'max_open_trades' with value in config file: 4.
|
||||
2025-04-29 08:31:11,266[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using minimal_roi: {'0': 0.132, '8': 0.047, '14': 0.007, '60': 0}
|
||||
2025-04-29 08:31:11,266[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using timeframe: 3m
|
||||
2025-04-29 08:31:11,266[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using stoploss: -0.05
|
||||
2025-04-29 08:31:11,267[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using trailing_stop: True
|
||||
2025-04-29 08:31:11,267[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using trailing_stop_positive: 0.01
|
||||
2025-04-29 08:31:11,267[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using trailing_stop_positive_offset: 0.02
|
||||
2025-04-29 08:31:11,268[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using trailing_only_offset_is_reached: False
|
||||
2025-04-29 08:31:11,268[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using use_custom_stoploss: False
|
||||
2025-04-29 08:31:11,268[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using process_only_new_candles: True
|
||||
2025-04-29 08:31:11,269[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using order_types: {'entry': 'limit', 'exit': 'limit', 'stoploss': 'limit', 'stoploss_on_exchange': False,
|
||||
'stoploss_on_exchange_interval': 60}
|
||||
2025-04-29 08:31:11,269[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using order_time_in_force: {'entry': 'GTC', 'exit': 'GTC'}
|
||||
2025-04-29 08:31:11,269[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using stake_currency: USDT
|
||||
2025-04-29 08:31:11,270[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using stake_amount: 150
|
||||
2025-04-29 08:31:11,270[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using startup_candle_count: 30
|
||||
2025-04-29 08:31:11,270[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using unfilledtimeout: {'entry': 5, 'exit': 15, 'exit_timeout_count': 0, 'unit': 'minutes'}
|
||||
2025-04-29 08:31:11,271[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using use_exit_signal: True
|
||||
2025-04-29 08:31:11,271[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using exit_profit_only: False
|
||||
2025-04-29 08:31:11,272[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using ignore_roi_if_entry_signal: False
|
||||
2025-04-29 08:31:11,272[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using exit_profit_offset: 0.0
|
||||
2025-04-29 08:31:11,272[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using disable_dataframe_checks: False
|
||||
2025-04-29 08:31:11,272[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using ignore_buying_expired_candle_after: 0
|
||||
2025-04-29 08:31:11,273[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using position_adjustment_enable: False
|
||||
2025-04-29 08:31:11,273[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using max_entry_position_adjustment: -1
|
||||
2025-04-29 08:31:11,273[90m - [0m[95mfreqtrade.resolvers.strategy_resolver[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy using max_open_trades: 4
|
||||
2025-04-29 08:31:11,273[90m - [0m[95mfreqtrade.configuration.config_validation[0m[90m - [0m[34mINFO[0m[90m - [0mValidating configuration ...
|
||||
2025-04-29 08:31:11,277[90m - [0m[95mfreqtrade.resolvers.iresolver[0m[90m - [0m[34mINFO[0m[90m - [0mUsing resolved pairlist StaticPairList from '/freqtrade/freqtrade/plugins/pairlist/StaticPairList.py'...
|
||||
2025-04-29 08:31:11,283[90m - [0m[95mfreqtrade.optimize.backtesting[0m[90m - [0m[34mINFO[0m[90m - [0mUsing fee 0.1500% - worst case fee from exchange (lowest tier).
|
||||
2025-04-29 08:31:11,284[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mIncreasing startup_candle_count for freqai on 3m to 14450
|
||||
2025-04-29 08:31:11,284[90m - [0m[95mfreqtrade.data.history.history_utils[0m[90m - [0m[34mINFO[0m[90m - [0mUsing indicator startup period: 14450 ...
|
||||
2025-04-29 08:31:11,413[90m - [0m[95mfreqtrade.optimize.backtesting[0m[90m - [0m[34mINFO[0m[90m - [0mLoading data from 2025-03-01 21:30:00 up to 2025-04-20 00:00:00 (49 days).
|
||||
2025-04-29 08:31:11,414[90m - [0m[95mfreqtrade.optimize.backtesting[0m[90m - [0m[34mINFO[0m[90m - [0mDataload complete. Calculating indicators
|
||||
2025-04-29 08:31:11,415[90m - [0m[95mfreqtrade.optimize.backtesting[0m[90m - [0m[34mINFO[0m[90m - [0mRunning backtesting for Strategy FreqaiExampleStrategy
|
||||
2025-04-29 08:31:12,973[90m - [0m[95mmatplotlib.font_manager[0m[90m - [0m[34mINFO[0m[90m - [0mgenerated new fontManager
|
||||
2025-04-29 08:31:13,178[90m - [0m[95mfreqtrade.resolvers.iresolver[0m[90m - [0m[34mINFO[0m[90m - [0mUsing resolved freqaimodel XGBoostRegressor from '/freqtrade/freqtrade/freqai/prediction_models/XGBoostRegressor.py'...
|
||||
2025-04-29 08:31:13,178[90m - [0m[95mfreqtrade.freqai.data_drawer[0m[90m - [0m[34mINFO[0m[90m - [0mCould not find existing datadrawer, starting from scratch
|
||||
2025-04-29 08:31:13,178[90m - [0m[95mfreqtrade.freqai.data_drawer[0m[90m - [0m[34mINFO[0m[90m - [0mCould not find existing historic_predictions, starting from scratch
|
||||
2025-04-29 08:31:13,179[90m - [0m[95mfreqtrade.freqai.freqai_interface[0m[90m - [0m[34mINFO[0m[90m - [0mSet fresh train queue from whitelist. Queue: ['BTC/USDT', 'SOL/USDT']
|
||||
2025-04-29 08:31:13,179[90m - [0m[95mfreqtrade.strategy.hyper[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy Parameter: buy_rsi = 39.92672300850069
|
||||
2025-04-29 08:31:13,180[90m - [0m[95mfreqtrade.strategy.hyper[0m[90m - [0m[34mINFO[0m[90m - [0mStrategy Parameter: sell_rsi = 69.92672300850067
|
||||
2025-04-29 08:31:13,180[90m - [0m[95mfreqtrade.strategy.hyper[0m[90m - [0m[34mINFO[0m[90m - [0mNo params for protection found, using default values.
|
||||
2025-04-29 08:31:13,183[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m处理交易对:BTC/USDT
|
||||
2025-04-29 08:31:13,184[90m - [0m[95mfreqtrade.freqai.freqai_interface[0m[90m - [0m[34mINFO[0m[90m - [0mTraining 2 timeranges
|
||||
2025-04-29 08:31:13,186[90m - [0m[95mfreqtrade.freqai.freqai_interface[0m[90m - [0m[34mINFO[0m[90m - [0mTraining 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 08:31:13,186[90m - [0m[95mfreqtrade.freqai.data_kitchen[0m[90m - [0m[34mINFO[0m[90m - [0mCould not find backtesting prediction file at
|
||||
/freqtrade/user_data/models/test175/backtesting_predictions/cb_btc_1743465600_prediction.feather
|
||||
2025-04-29 08:31:13,221[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mIncreasing startup_candle_count for freqai on 5m to 8690
|
||||
2025-04-29 08:31:13,222[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mLoading data for BTC/USDT 5m from 2025-03-01 19:50:00 to 2025-04-20 00:00:00
|
||||
2025-04-29 08:31:13,294[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mIncreasing startup_candle_count for freqai on 1h to 770
|
||||
2025-04-29 08:31:13,295[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mLoading data for BTC/USDT 1h from 2025-02-27 22:00:00 to 2025-04-20 00:00:00
|
||||
2025-04-29 08:31:13,354[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mIncreasing startup_candle_count for freqai on 3m to 14450
|
||||
2025-04-29 08:31:13,355[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mLoading data for ETH/USDT 3m from 2025-03-01 21:30:00 to 2025-04-20 00:00:00
|
||||
2025-04-29 08:31:13,449[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mIncreasing startup_candle_count for freqai on 5m to 8690
|
||||
2025-04-29 08:31:13,449[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mLoading data for ETH/USDT 5m from 2025-03-01 19:50:00 to 2025-04-20 00:00:00
|
||||
2025-04-29 08:31:13,521[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mIncreasing startup_candle_count for freqai on 1h to 770
|
||||
2025-04-29 08:31:13,522[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mLoading data for ETH/USDT 1h from 2025-02-27 22:00:00 to 2025-04-20 00:00:00
|
||||
2025-04-29 08:31:13,571[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m设置 FreqAI 目标,交易对:BTC/USDT
|
||||
2025-04-29 08:31:13,576[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列形状:(14450,)
|
||||
2025-04-29 08:31:13,579[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列预览:
|
||||
up_or_down &-buy_rsi
|
||||
0 0.007116 50.010488
|
||||
1 0.005291 50.010488
|
||||
2 0.004416 50.010488
|
||||
3 0.002082 50.010488
|
||||
4 0.001904 50.010488
|
||||
2025-04-29 08:31:13,584[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m设置 FreqAI 目标,交易对:BTC/USDT
|
||||
2025-04-29 08:31:13,590[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列形状:(19250,)
|
||||
2025-04-29 08:31:13,592[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列预览:
|
||||
up_or_down &-buy_rsi
|
||||
0 0.007116 49.846666
|
||||
1 0.005291 49.846666
|
||||
2 0.004416 49.846666
|
||||
3 0.002082 49.846666
|
||||
4 0.001904 49.846666
|
||||
2025-04-29 08:31:13,600[90m - [0m[95mfreqtrade.freqai.freqai_interface[0m[90m - [0m[34mINFO[0m[90m - [0mCould not find model at /freqtrade/user_data/models/test175/sub-train-BTC_1743465600/cb_btc_1743465600
|
||||
2025-04-29 08:31:13,600[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0m-------------------- Starting training BTC/USDT --------------------
|
||||
2025-04-29 08:31:13,622[90m - [0m[95mfreqtrade.freqai.data_kitchen[0m[90m - [0m[34mINFO[0m[90m - [0mBTC/USDT: dropped 0 training points due to NaNs in populated dataset 14400.
|
||||
2025-04-29 08:31:13,623[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0m-------------------- Training on data from 2025-03-02 to 2025-03-31 --------------------
|
||||
2025-04-29 08:31:13,641[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0mTraining model on 75 features
|
||||
2025-04-29 08:31:13,642[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0mTraining model on 11520 data points
|
||||
/home/ftuser/.local/lib/python3.12/site-packages/xgboost/core.py:158: UserWarning: [08:31:13] WARNING: /workspace/src/learner.cc:740:
|
||||
Parameters: { "verbose" } are not used.
|
||||
|
||||
warnings.warn(smsg, UserWarning)
|
||||
[99] validation_0-rmse:0.13679 validation_1-rmse:0.11901
|
||||
2025-04-29 08:31:15,185[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0m-------------------- Done training BTC/USDT (1.58 secs) --------------------
|
||||
/home/ftuser/.local/lib/python3.12/site-packages/xgboost/core.py:158: UserWarning:
|
||||
|
||||
[08:31:15] WARNING: /workspace/src/learner.cc:740:
|
||||
Parameters: { "verbose" } are not used.
|
||||
|
||||
|
||||
2025-04-29 08:31:15,422[90m - [0m[95mfreqtrade.plot.plotting[0m[90m - [0m[34mINFO[0m[90m - [0mStored plot as /freqtrade/user_data/models/test175/sub-train-BTC_1743465600/cb_btc_1743465600--buy_rsi.html
|
||||
2025-04-29 08:31:15,423[90m - [0m[95mfreqtrade.freqai.freqai_interface[0m[90m - [0m[34mINFO[0m[90m - [0mSaving metadata to disk.
|
||||
2025-04-29 08:31:15,442[90m - [0m[95mdatasieve.pipeline[0m[90m - [0m[33mWARNING[0m[90m - [0mCould not find step di in pipeline, returning None
|
||||
2025-04-29 08:31:15,449[90m - [0m[95mfreqtrade.freqai.freqai_interface[0m[90m - [0m[34mINFO[0m[90m - [0mTraining 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 08:31:15,449[90m - [0m[95mfreqtrade.freqai.data_kitchen[0m[90m - [0m[34mINFO[0m[90m - [0mCould not find backtesting prediction file at
|
||||
/freqtrade/user_data/models/test175/backtesting_predictions/cb_btc_1744329600_prediction.feather
|
||||
2025-04-29 08:31:15,453[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m设置 FreqAI 目标,交易对:BTC/USDT
|
||||
2025-04-29 08:31:15,458[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列形状:(19250,)
|
||||
2025-04-29 08:31:15,459[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列预览:
|
||||
up_or_down &-buy_rsi
|
||||
0 0.007116 49.846666
|
||||
1 0.005291 49.846666
|
||||
2 0.004416 49.846666
|
||||
3 0.002082 49.846666
|
||||
4 0.001904 49.846666
|
||||
2025-04-29 08:31:15,464[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m设置 FreqAI 目标,交易对:BTC/USDT
|
||||
2025-04-29 08:31:15,469[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列形状:(23570,)
|
||||
2025-04-29 08:31:15,471[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列预览:
|
||||
up_or_down &-buy_rsi
|
||||
0 0.007116 50.074781
|
||||
1 0.005291 50.074781
|
||||
2 0.004416 50.074781
|
||||
3 0.002082 50.074781
|
||||
4 0.001904 50.074781
|
||||
2025-04-29 08:31:15,476[90m - [0m[95mfreqtrade.freqai.freqai_interface[0m[90m - [0m[34mINFO[0m[90m - [0mCould not find model at /freqtrade/user_data/models/test175/sub-train-BTC_1744329600/cb_btc_1744329600
|
||||
2025-04-29 08:31:15,476[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0m-------------------- Starting training BTC/USDT --------------------
|
||||
2025-04-29 08:31:15,494[90m - [0m[95mfreqtrade.freqai.data_kitchen[0m[90m - [0m[34mINFO[0m[90m - [0mBTC/USDT: dropped 0 training points due to NaNs in populated dataset 14400.
|
||||
2025-04-29 08:31:15,495[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0m-------------------- Training on data from 2025-03-12 to 2025-04-10 --------------------
|
||||
2025-04-29 08:31:15,509[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0mTraining model on 75 features
|
||||
2025-04-29 08:31:15,510[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0mTraining model on 11520 data points
|
||||
/home/ftuser/.local/lib/python3.12/site-packages/xgboost/core.py:158: UserWarning:
|
||||
|
||||
[08:31:15] WARNING: /workspace/src/learner.cc:740:
|
||||
Parameters: { "verbose" } are not used.
|
||||
|
||||
|
||||
[99] validation_0-rmse:0.13376 validation_1-rmse:0.11638
|
||||
2025-04-29 08:31:17,083[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0m-------------------- Done training BTC/USDT (1.61 secs) --------------------
|
||||
/home/ftuser/.local/lib/python3.12/site-packages/xgboost/core.py:158: UserWarning:
|
||||
|
||||
[08:31:17] WARNING: /workspace/src/learner.cc:740:
|
||||
Parameters: { "verbose" } are not used.
|
||||
|
||||
|
||||
2025-04-29 08:31:17,121[90m - [0m[95mfreqtrade.plot.plotting[0m[90m - [0m[34mINFO[0m[90m - [0mStored plot as /freqtrade/user_data/models/test175/sub-train-BTC_1744329600/cb_btc_1744329600--buy_rsi.html
|
||||
2025-04-29 08:31:17,122[90m - [0m[95mfreqtrade.freqai.freqai_interface[0m[90m - [0m[34mINFO[0m[90m - [0mSaving metadata to disk.
|
||||
2025-04-29 08:31:17,144[90m - [0m[95mdatasieve.pipeline[0m[90m - [0m[33mWARNING[0m[90m - [0mCould not find step di in pipeline, returning None
|
||||
2025-04-29 08:31:17,182[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m动态参数:buy_rsi=39.26145316407591, sell_rsi=59.26145316407591, stoploss=-0.15, trailing_stop_positive=0.05
|
||||
2025-04-29 08:31:17,189[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0mup_or_down 值统计:
|
||||
up_or_down
|
||||
1 11845
|
||||
0 11726
|
||||
2025-04-29 08:31:17,190[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0mdo_predict 值统计:
|
||||
do_predict
|
||||
0.0 14451
|
||||
1.0 9120
|
||||
2025-04-29 08:31:17,192[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m处理交易对:SOL/USDT
|
||||
2025-04-29 08:31:17,193[90m - [0m[95mfreqtrade.freqai.freqai_interface[0m[90m - [0m[34mINFO[0m[90m - [0mTraining 2 timeranges
|
||||
2025-04-29 08:31:17,194[90m - [0m[95mfreqtrade.freqai.freqai_interface[0m[90m - [0m[34mINFO[0m[90m - [0mTraining 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 08:31:17,195[90m - [0m[95mfreqtrade.freqai.data_kitchen[0m[90m - [0m[34mINFO[0m[90m - [0mCould not find backtesting prediction file at
|
||||
/freqtrade/user_data/models/test175/backtesting_predictions/cb_sol_1743465600_prediction.feather
|
||||
2025-04-29 08:31:17,217[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mIncreasing startup_candle_count for freqai on 5m to 8690
|
||||
2025-04-29 08:31:17,217[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mLoading data for SOL/USDT 5m from 2025-03-01 19:50:00 to 2025-04-20 00:00:00
|
||||
2025-04-29 08:31:17,281[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mIncreasing startup_candle_count for freqai on 1h to 770
|
||||
2025-04-29 08:31:17,282[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mLoading data for SOL/USDT 1h from 2025-02-27 22:00:00 to 2025-04-20 00:00:00
|
||||
2025-04-29 08:31:17,329[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mIncreasing startup_candle_count for freqai on 3m to 14450
|
||||
2025-04-29 08:31:17,329[90m - [0m[95mfreqtrade.data.dataprovider[0m[90m - [0m[34mINFO[0m[90m - [0mLoading data for BTC/USDT 3m from 2025-03-01 21:30:00 to 2025-04-20 00:00:00
|
||||
2025-04-29 08:31:17,591[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m设置 FreqAI 目标,交易对:SOL/USDT
|
||||
2025-04-29 08:31:17,596[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列形状:(14450,)
|
||||
2025-04-29 08:31:17,597[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列预览:
|
||||
up_or_down &-buy_rsi
|
||||
0 0.016595 49.72136
|
||||
1 0.012811 49.72136
|
||||
2 0.010135 49.72136
|
||||
3 0.008514 49.72136
|
||||
4 0.006242 49.72136
|
||||
2025-04-29 08:31:17,602[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m设置 FreqAI 目标,交易对:SOL/USDT
|
||||
2025-04-29 08:31:17,608[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列形状:(19250,)
|
||||
2025-04-29 08:31:17,609[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列预览:
|
||||
up_or_down &-buy_rsi
|
||||
0 0.016595 49.562407
|
||||
1 0.012811 49.562407
|
||||
2 0.010135 49.562407
|
||||
3 0.008514 49.562407
|
||||
4 0.006242 49.562407
|
||||
2025-04-29 08:31:17,615[90m - [0m[95mfreqtrade.freqai.freqai_interface[0m[90m - [0m[34mINFO[0m[90m - [0mCould not find model at /freqtrade/user_data/models/test175/sub-train-SOL_1743465600/cb_sol_1743465600
|
||||
2025-04-29 08:31:17,616[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0m-------------------- Starting training SOL/USDT --------------------
|
||||
2025-04-29 08:31:17,644[90m - [0m[95mfreqtrade.freqai.data_kitchen[0m[90m - [0m[34mINFO[0m[90m - [0mSOL/USDT: dropped 0 training points due to NaNs in populated dataset 14400.
|
||||
2025-04-29 08:31:17,645[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0m-------------------- Training on data from 2025-03-02 to 2025-03-31 --------------------
|
||||
2025-04-29 08:31:17,667[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0mTraining model on 111 features
|
||||
2025-04-29 08:31:17,668[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0mTraining model on 11520 data points
|
||||
/home/ftuser/.local/lib/python3.12/site-packages/xgboost/core.py:158: UserWarning:
|
||||
|
||||
[08:31:17] WARNING: /workspace/src/learner.cc:740:
|
||||
Parameters: { "verbose" } are not used.
|
||||
|
||||
|
||||
[99] validation_0-rmse:0.11848 validation_1-rmse:0.10165
|
||||
2025-04-29 08:31:20,071[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0m-------------------- Done training SOL/USDT (2.46 secs) --------------------
|
||||
/home/ftuser/.local/lib/python3.12/site-packages/xgboost/core.py:158: UserWarning:
|
||||
|
||||
[08:31:20] WARNING: /workspace/src/learner.cc:740:
|
||||
Parameters: { "verbose" } are not used.
|
||||
|
||||
|
||||
2025-04-29 08:31:20,104[90m - [0m[95mfreqtrade.plot.plotting[0m[90m - [0m[34mINFO[0m[90m - [0mStored plot as /freqtrade/user_data/models/test175/sub-train-SOL_1743465600/cb_sol_1743465600--buy_rsi.html
|
||||
2025-04-29 08:31:20,105[90m - [0m[95mfreqtrade.freqai.freqai_interface[0m[90m - [0m[34mINFO[0m[90m - [0mSaving metadata to disk.
|
||||
2025-04-29 08:31:20,136[90m - [0m[95mdatasieve.pipeline[0m[90m - [0m[33mWARNING[0m[90m - [0mCould not find step di in pipeline, returning None
|
||||
2025-04-29 08:31:20,143[90m - [0m[95mfreqtrade.freqai.freqai_interface[0m[90m - [0m[34mINFO[0m[90m - [0mTraining 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 08:31:20,144[90m - [0m[95mfreqtrade.freqai.data_kitchen[0m[90m - [0m[34mINFO[0m[90m - [0mCould not find backtesting prediction file at
|
||||
/freqtrade/user_data/models/test175/backtesting_predictions/cb_sol_1744329600_prediction.feather
|
||||
2025-04-29 08:31:20,148[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m设置 FreqAI 目标,交易对:SOL/USDT
|
||||
2025-04-29 08:31:20,154[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列形状:(19250,)
|
||||
2025-04-29 08:31:20,156[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列预览:
|
||||
up_or_down &-buy_rsi
|
||||
0 0.016595 49.562407
|
||||
1 0.012811 49.562407
|
||||
2 0.010135 49.562407
|
||||
3 0.008514 49.562407
|
||||
4 0.006242 49.562407
|
||||
2025-04-29 08:31:20,160[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m设置 FreqAI 目标,交易对:SOL/USDT
|
||||
2025-04-29 08:31:20,166[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列形状:(23570,)
|
||||
2025-04-29 08:31:20,167[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m目标列预览:
|
||||
up_or_down &-buy_rsi
|
||||
0 0.016595 49.934347
|
||||
1 0.012811 49.934347
|
||||
2 0.010135 49.934347
|
||||
3 0.008514 49.934347
|
||||
4 0.006242 49.934347
|
||||
2025-04-29 08:31:20,172[90m - [0m[95mfreqtrade.freqai.freqai_interface[0m[90m - [0m[34mINFO[0m[90m - [0mCould not find model at /freqtrade/user_data/models/test175/sub-train-SOL_1744329600/cb_sol_1744329600
|
||||
2025-04-29 08:31:20,173[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0m-------------------- Starting training SOL/USDT --------------------
|
||||
2025-04-29 08:31:20,197[90m - [0m[95mfreqtrade.freqai.data_kitchen[0m[90m - [0m[34mINFO[0m[90m - [0mSOL/USDT: dropped 0 training points due to NaNs in populated dataset 14400.
|
||||
2025-04-29 08:31:20,197[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0m-------------------- Training on data from 2025-03-12 to 2025-04-10 --------------------
|
||||
2025-04-29 08:31:20,219[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0mTraining model on 111 features
|
||||
2025-04-29 08:31:20,220[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0mTraining model on 11520 data points
|
||||
/home/ftuser/.local/lib/python3.12/site-packages/xgboost/core.py:158: UserWarning:
|
||||
|
||||
[08:31:20] WARNING: /workspace/src/learner.cc:740:
|
||||
Parameters: { "verbose" } are not used.
|
||||
|
||||
|
||||
[99] validation_0-rmse:0.12679 validation_1-rmse:0.11178
|
||||
2025-04-29 08:31:22,488[90m - [0m[95mfreqtrade.freqai.base_models.BaseRegressionModel[0m[90m - [0m[34mINFO[0m[90m - [0m-------------------- Done training SOL/USDT (2.31 secs) --------------------
|
||||
/home/ftuser/.local/lib/python3.12/site-packages/xgboost/core.py:158: UserWarning:
|
||||
|
||||
[08:31:22] WARNING: /workspace/src/learner.cc:740:
|
||||
Parameters: { "verbose" } are not used.
|
||||
|
||||
|
||||
2025-04-29 08:31:22,529[90m - [0m[95mfreqtrade.plot.plotting[0m[90m - [0m[34mINFO[0m[90m - [0mStored plot as /freqtrade/user_data/models/test175/sub-train-SOL_1744329600/cb_sol_1744329600--buy_rsi.html
|
||||
2025-04-29 08:31:22,530[90m - [0m[95mfreqtrade.freqai.freqai_interface[0m[90m - [0m[34mINFO[0m[90m - [0mSaving metadata to disk.
|
||||
2025-04-29 08:31:22,557[90m - [0m[95mdatasieve.pipeline[0m[90m - [0m[33mWARNING[0m[90m - [0mCould not find step di in pipeline, returning None
|
||||
2025-04-29 08:31:22,599[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0m动态参数:buy_rsi=50.0, sell_rsi=70.0, stoploss=-0.15, trailing_stop_positive=0.05
|
||||
2025-04-29 08:31:22,606[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0mup_or_down 值统计:
|
||||
up_or_down
|
||||
0 11865
|
||||
1 11706
|
||||
2025-04-29 08:31:22,607[90m - [0m[95mFreqaiExampleStrategy[0m[90m - [0m[34mINFO[0m[90m - [0mdo_predict 值统计:
|
||||
do_predict
|
||||
0.0 14451
|
||||
1.0 9120
|
||||
2025-04-29 08:31:22,610[90m - [0m[95mfreqtrade.optimize.backtesting[0m[90m - [0m[34mINFO[0m[90m - [0mBacktesting with data from 2025-04-01 00:00:00 up to 2025-04-20 00:00:00 (19 days).
|
||||
2025-04-29 08:31:23,193[90m - [0m[95mfreqtrade.misc[0m[90m - [0m[34mINFO[0m[90m - [0mdumping json to "/freqtrade/user_data/backtest_results/backtest-result-2025-04-29_08-31-23.meta.json"
|
||||
Result for strategy FreqaiExampleStrategy
|
||||
[3m BACKTESTING REPORT [0m
|
||||
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃[1m [0m[1m Pair[0m[1m [0m┃[1m [0m[1mTrades[0m[1m [0m┃[1m [0m[1mAvg Profit %[0m[1m [0m┃[1m [0m[1mTot Profit USDT[0m[1m [0m┃[1m [0m[1mTot Profit %[0m[1m [0m┃[1m [0m[1mAvg Duration[0m[1m [0m┃[1m [0m[1m Win Draw Loss Win%[0m[1m [0m┃
|
||||
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ BTC/USDT │ 15 │ 0.04 │ 0.801 │ 0.08 │ 12:58:00 │ 2 13 0 100 │
|
||||
│ SOL/USDT │ 13 │ -0.9 │ -17.573 │ -1.76 │ 8:54:00 │ 5 7 1 38.5 │
|
||||
│ TOTAL │ 28 │ -0.4 │ -16.773 │ -1.68 │ 11:05:00 │ 7 20 1 25.0 │
|
||||
└──────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┘
|
||||
[3m LEFT OPEN TRADES REPORT [0m
|
||||
┏━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃[1m [0m[1m Pair[0m[1m [0m┃[1m [0m[1mTrades[0m[1m [0m┃[1m [0m[1mAvg Profit %[0m[1m [0m┃[1m [0m[1mTot Profit USDT[0m[1m [0m┃[1m [0m[1mTot Profit %[0m[1m [0m┃[1m [0m[1mAvg Duration[0m[1m [0m┃[1m [0m[1m Win Draw Loss Win%[0m[1m [0m┃
|
||||
┡━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ TOTAL │ 0 │ 0.0 │ 0.000 │ 0.0 │ 0:00 │ 0 0 0 0 │
|
||||
└───────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┘
|
||||
[3m ENTER TAG STATS [0m
|
||||
┏━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃[1m [0m[1mEnter Tag[0m[1m [0m┃[1m [0m[1mEntries[0m[1m [0m┃[1m [0m[1mAvg Profit %[0m[1m [0m┃[1m [0m[1mTot Profit USDT[0m[1m [0m┃[1m [0m[1mTot Profit %[0m[1m [0m┃[1m [0m[1mAvg Duration[0m[1m [0m┃[1m [0m[1m Win Draw Loss Win%[0m[1m [0m┃
|
||||
┡━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ long │ 28 │ -0.4 │ -16.773 │ -1.68 │ 11:05:00 │ 7 20 1 25.0 │
|
||||
│ TOTAL │ 28 │ -0.4 │ -16.773 │ -1.68 │ 11:05:00 │ 7 20 1 25.0 │
|
||||
└───────────┴─────────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┘
|
||||
[3m EXIT REASON STATS [0m
|
||||
┏━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃[1m [0m[1m Exit Reason[0m[1m [0m┃[1m [0m[1mExits[0m[1m [0m┃[1m [0m[1mAvg Profit %[0m[1m [0m┃[1m [0m[1mTot Profit USDT[0m[1m [0m┃[1m [0m[1mTot Profit %[0m[1m [0m┃[1m [0m[1m Avg Duration[0m[1m [0m┃[1m [0m[1m Win Draw Loss Win%[0m[1m [0m┃
|
||||
┡━━━━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ roi │ 27 │ 0.14 │ 5.757 │ 0.58 │ 9:48:00 │ 7 20 0 100 │
|
||||
│ trailing_stop_loss │ 1 │ -15.0 │ -22.529 │ -2.25 │ 1 day, 21:45:00 │ 0 0 1 0 │
|
||||
│ TOTAL │ 28 │ -0.4 │ -16.773 │ -1.68 │ 11:05:00 │ 7 20 1 25.0 │
|
||||
└────────────────────┴───────┴──────────────┴─────────────────┴──────────────┴─────────────────┴────────────────────────┘
|
||||
[3m MIXED TAG STATS [0m
|
||||
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃[1m [0m[1m Enter Tag[0m[1m [0m┃[1m [0m[1mExit Reason[0m[1m [0m┃[1m [0m[1mTrades[0m[1m [0m┃[1m [0m[1mAvg Profit %[0m[1m [0m┃[1m [0m[1mTot Profit USDT[0m[1m [0m┃[1m [0m[1mTot Profit %[0m[1m [0m┃[1m [0m[1m Avg Duration[0m[1m [0m┃[1m [0m[1m Win Draw Loss Win%[0m[1m [0m┃
|
||||
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ ('long', 'roi') │ │ 27 │ 0.14 │ 5.757 │ 0.58 │ 9:48:00 │ 7 20 0 100 │
|
||||
│ ('long', 'trailing_stop_loss') │ │ 1 │ -15.0 │ -22.529 │ -2.25 │ 1 day, 21:45:00 │ 0 0 1 0 │
|
||||
│ TOTAL │ │ 28 │ -0.4 │ -16.773 │ -1.68 │ 11:05:00 │ 7 20 1 25.0 │
|
||||
└────────────────────────────────┴─────────────┴────────┴──────────────┴─────────────────┴──────────────┴─────────────────┴────────────────────────┘
|
||||
[3m SUMMARY METRICS [0m
|
||||
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃[1m [0m[1mMetric [0m[1m [0m┃[1m [0m[1mValue [0m[1m [0m┃
|
||||
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ Backtesting from │ 2025-04-01 00:00:00 │
|
||||
│ Backtesting to │ 2025-04-20 00:00:00 │
|
||||
│ Trading Mode │ Spot │
|
||||
│ Max open trades │ 2 │
|
||||
│ │ │
|
||||
│ Total/Daily Avg Trades │ 28 / 1.47 │
|
||||
│ Starting balance │ 1000 USDT │
|
||||
│ Final balance │ 983.227 USDT │
|
||||
│ Absolute profit │ -16.773 USDT │
|
||||
│ Total profit % │ -1.68% │
|
||||
│ CAGR % │ -27.74% │
|
||||
│ Sortino │ -100.00 │
|
||||
│ Sharpe │ -3.97 │
|
||||
│ Calmar │ -74.86 │
|
||||
│ SQN │ -0.73 │
|
||||
│ Profit factor │ 0.26 │
|
||||
│ Expectancy (Ratio) │ -0.60 (-0.74) │
|
||||
│ Avg. daily profit % │ -0.09% │
|
||||
│ Avg. stake amount │ 150 USDT │
|
||||
│ Total trade volume │ 8408.398 USDT │
|
||||
│ │ │
|
||||
│ Best Pair │ BTC/USDT 0.08% │
|
||||
│ Worst Pair │ SOL/USDT -1.76% │
|
||||
│ Best trade │ SOL/USDT 1.41% │
|
||||
│ Worst trade │ SOL/USDT -15.00% │
|
||||
│ Best day │ 2.151 USDT │
|
||||
│ Worst day │ -22.529 USDT │
|
||||
│ Days win/draw/lose │ 4 / 13 / 1 │
|
||||
│ Avg. Duration Winners │ 0:51:00 │
|
||||
│ Avg. Duration Loser │ 1 day, 21:45:00 │
|
||||
│ Max Consecutive Wins / Loss │ 3 / 10 │
|
||||
│ Rejected Entry signals │ 0 │
|
||||
│ Entry/Exit Timeouts │ 0 / 0 │
|
||||
│ │ │
|
||||
│ Min balance │ 977.471 USDT │
|
||||
│ Max balance │ 1000 USDT │
|
||||
│ Max % of account underwater │ 2.25% │
|
||||
│ Absolute Drawdown (Account) │ 2.25% │
|
||||
│ Absolute Drawdown │ 22.529 USDT │
|
||||
│ Drawdown high │ 0 USDT │
|
||||
│ Drawdown low │ -22.529 USDT │
|
||||
│ Drawdown Start │ 2025-04-02 08:24:00 │
|
||||
│ Drawdown End │ 2025-04-06 23:15:00 │
|
||||
│ Market change │ -0.80% │
|
||||
└─────────────────────────────┴─────────────────────┘
|
||||
|
||||
Backtested 2025-04-01 00:00:00 -> 2025-04-20 00:00:00 | Max open trades : 2
|
||||
[3m STRATEGY SUMMARY [0m
|
||||
┏━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃[1m [0m[1m Strategy[0m[1m [0m┃[1m [0m[1mTrades[0m[1m [0m┃[1m [0m[1mAvg Profit %[0m[1m [0m┃[1m [0m[1mTot Profit USDT[0m[1m [0m┃[1m [0m[1mTot Profit %[0m[1m [0m┃[1m [0m[1mAvg Duration[0m[1m [0m┃[1m [0m[1m Win Draw Loss Win%[0m[1m [0m┃[1m [0m[1m Drawdown[0m[1m [0m┃
|
||||
┡━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ FreqaiExampleStrategy │ 28 │ -0.40 │ -16.773 │ -1.68 │ 11:05:00 │ 7 20 1 25.0 │ 22.529 USDT 2.25% │
|
||||
└───────────────────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┴────────────────────┘
|
||||
18
utf8.py
Normal file
18
utf8.py
Normal 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
233
请啊!
Normal 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
|
||||
Loading…
x
Reference in New Issue
Block a user