4个月回测需要4分钟,结果还是跑输15%
This commit is contained in:
parent
8f4c374e6b
commit
37173ab636
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[
|
||||
@ -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,
|
||||
@ -65,27 +66,36 @@
|
||||
"fillna": "ffill"
|
||||
},
|
||||
"freqaimodel": "XGBoostRegressor",
|
||||
"model_training_parameters": {
|
||||
"n_estimators": 100,
|
||||
"learning_rate": 0.05,
|
||||
"max_depth": 5
|
||||
},
|
||||
"train_period_days": 180,
|
||||
"backtest_period_days": 60,
|
||||
"purge_old_models": 2,
|
||||
"identifier": "test175",
|
||||
"train_period_days": 30,
|
||||
"backtest_period_days": 10,
|
||||
"live_retrain_hours": 0,
|
||||
"feature_selection": {
|
||||
"method": "recursive_elimination"
|
||||
},
|
||||
"feature_parameters": {
|
||||
"include_timeframes": ["15m"],
|
||||
"include_corr_pairlist": ["BTC/USDT"],
|
||||
"label_period_candles": 10,
|
||||
"include_shifted_candles": 1,
|
||||
"include_timeframes": [
|
||||
"5m",
|
||||
"1h"
|
||||
],
|
||||
"include_corr_pairlist": [
|
||||
"BTC/USDT",
|
||||
"ETH/USDT"
|
||||
],
|
||||
"label_period_candles": 12,
|
||||
"include_shifted_candles": 3,
|
||||
"DI_threshold": 0.9,
|
||||
|
||||
"weight_factor": 0.9,
|
||||
"principal_component_analysis": false,
|
||||
"use_SVM_to_remove_outliers": false,
|
||||
"indicator_periods_candles": [14],
|
||||
"indicator_periods_candles": [
|
||||
10,
|
||||
20,
|
||||
50
|
||||
],
|
||||
"plot_feature_importances": 0
|
||||
},
|
||||
"data_split_parameters": {
|
||||
"test_size": 0.2
|
||||
|
||||
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"
|
||||
}
|
||||
@ -69,5 +69,5 @@ services:
|
||||
--config /freqtrade/templates/FreqaiExampleStrategy.json
|
||||
--strategy-path /freqtrade/templates
|
||||
--strategy FreqaiExampleStrategy
|
||||
--timerange 20250320-20250420
|
||||
--timerange 20250101-20250420
|
||||
--cache none
|
||||
|
||||
1162
freqai/data_kitchen.py
Normal file
1162
freqai/data_kitchen.py
Normal file
File diff suppressed because it is too large
Load Diff
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
|
||||
```
|
||||
```
|
||||
```
|
||||
```
|
||||
```
|
||||
```
|
||||
```
|
||||
```
|
||||
Loading…
x
Reference in New Issue
Block a user