myTestFreqAI/freqtrade/templates/freqaiprimer.py

143 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
logger = logging.getLogger(__name__)
class FreqaiPrimer(IStrategy):
"""
策略说明:
- 所有交易信号由 FreqAI 动态预测
- 不使用 Hyperopt 优化任何参数
- 使用 FreqAI 提供的趋势和波动率信号进行交易决策
"""
plot_config = {
"main_plot": {},
"subplots": {
"Signals": {
"enter_long": {"color": "green"},
"exit_long": {"color": "red"}
},
"FreqAI Predictions": {
"&-buy_signal": {"color": "blue"},
"&-sell_signal": {"color": "orange"},
"&-volatility_forecast": {"color": "purple"}
}
}
}
freqai_info = {
"model": "LightGBMClassifier",
"feature_parameters": {
"include_timeframes": ["5m", "15m", "1h"],
"label_period_candles": 24,
"include_shifted_candles": 3,
},
"data_split_parameters": {
"test_size": 0.2,
"shuffle": False,
},
"model_training_parameters": {
"n_estimators": 200,
"learning_rate": 0.05,
"num_leaves": 31,
"verbose": -1,
},
}
def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, metadata: dict, **kwargs) -> DataFrame:
dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period)
dataframe["%-sma-period"] = ta.SMA(dataframe, timeperiod=period)
dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period)
real = ta.TYPPRICE(dataframe)
upperband, middleband, lowerband = ta.BBANDS(real, timeperiod=period, nbdevup=2.0, nbdevdn=2.0)
dataframe["bb_lowerband-period"] = lowerband
dataframe["bb_upperband-period"] = upperband
dataframe["bb_middleband-period"] = middleband
dataframe["%-bb_width-period"] = (dataframe["bb_upperband-period"] - dataframe["bb_lowerband-period"]) / dataframe["bb_middleband-period"]
dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period)
return dataframe
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
"""
使用历史窗口预测未来趋势和波动率作为辅助信号,
避免使用任何未来数据(如 shift(-N)
"""
label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
# 1. 趋势强度:使用过去 N 根 K 线的收益率判断当前趋势
dataframe["&-trend_strength"] = dataframe["close"].pct_change(label_period)
# 2. 波动率预测:使用过去 N 根 K 线的价格变动绝对值
dataframe["&-volatility_forecast"] = dataframe["close"].pct_change(label_period).abs()
# 3. 动态 ROI 目标:基于趋势强度缩放
dataframe["&-roi_target"] = np.where(
dataframe["&-trend_strength"] > 0,
dataframe["&-trend_strength"] * 1.5,
0.01 # 最小 ROI
)
# 4. 动态止损目标:基于波动率缩放
dataframe["&-stoploss_target"] = -dataframe["&-volatility_forecast"] * 1.2
# 5. 市场状态识别:判断当前是震荡、趋势、超买还是超卖
if "bb_upperband-period" in dataframe.columns and "bb_lowerband-period" in dataframe.columns:
dataframe["&-market_condition"] = np.select([
(dataframe["close"] > dataframe["bb_upperband-period"]),
(dataframe["close"] < dataframe["bb_lowerband-period"]),
(dataframe["&-trend_strength"] > 0.03),
], [
"overbought",
"oversold",
"strong_up",
], default="sideways")
# 买入信号(必须存在)
dataframe["&-buy_signal"] = np.where(dataframe["&-trend_strength"] > 0.01, 1, 0)
# 卖出信号(必须存在)
dataframe["&-sell_signal"] = np.where(dataframe["&-trend_strength"] < -0.01, 1, 0)
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
logger.info(f"[{metadata['pair']}] 当前可用列: {list(dataframe.columns)}")
dataframe = self.freqai.start(dataframe, metadata, self)
# FreqAI 提供的预测列
if "&-trend" in dataframe.columns:
dataframe["in_uptrend"] = dataframe["&-trend"] > 0.5
return dataframe
def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
conditions = []
if "&-buy_signal" in df.columns:
conditions.append(df["&-buy_signal"] > 0.5)
else:
logger.warning("⚠️ &-buy_signal 列缺失,跳过该条件")
if len(conditions) == 0:
return df
df.loc[reduce(lambda x, y: x & y, conditions), 'enter_long'] = 1
return df
def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
conditions = [
df["&-sell_signal"] > 0.5,
]
df.loc[reduce(lambda x, y: x & y, conditions), 'exit_long'] = 1
return df