initial vault sync
This commit is contained in:
346
05 投资交易/freqtrade是否支持自定义K线形态的识别监测?.md
Normal file
346
05 投资交易/freqtrade是否支持自定义K线形态的识别监测?.md
Normal file
@ -0,0 +1,346 @@
|
||||
#交易 #量化交易 #策略研究 #freqtrade #DeepSeek
|
||||
|
||||
## 复杂形态识别在 Freqtrade 中的实现
|
||||
|
||||
是的,Freqtrade 完全支持自定义复杂形态识别,即使是分析 10-50 根K线的形态组合。下面是一个完整的实现方案,展示如何识别"上升通道"、"头肩顶"等复杂形态:
|
||||
|
||||
### 核心实现方案
|
||||
|
||||
```
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from scipy.stats import linregress
|
||||
from freqtrade.strategy import IStrategy, DecimalParameter, IntParameter
|
||||
|
||||
class ComplexPatternStrategy(IStrategy):
|
||||
timeframe = '4h' # 推荐4小时以上时间框架
|
||||
minimal_roi = {"0": 0.15, "240": 0.05, "480": 0}
|
||||
stoploss = -0.1
|
||||
|
||||
# 形态检测参数
|
||||
pattern_window = IntParameter(10, 50, default=30, space='buy', optimize=True)
|
||||
channel_deviation = DecimalParameter(0.01, 0.1, default=0.03, space='buy', optimize=True)
|
||||
|
||||
def detect_market_background(self, dataframe: pd.DataFrame, window: int) -> dict:
|
||||
"""
|
||||
分析市场背景:识别趋势、通道、反转形态等
|
||||
返回包含市场状态和形态特征的字典
|
||||
"""
|
||||
df = dataframe.copy().tail(window)
|
||||
results = {
|
||||
'market_state': 'neutral',
|
||||
'pattern': None,
|
||||
'trend_strength': 0,
|
||||
'volatility': df['close'].pct_change().std(),
|
||||
'key_levels': []
|
||||
}
|
||||
|
||||
# 1. 趋势强度分析
|
||||
slope, intercept, _, _, _ = linregress(np.arange(len(df)), df['close'])
|
||||
results['trend_strength'] = slope * len(df) / df['close'].mean()
|
||||
|
||||
# 2. 通道识别
|
||||
upper_channel = self.detect_price_channel(df, 'high', deviation=self.channel_deviation.value)
|
||||
lower_channel = self.detect_price_channel(df, 'low', deviation=self.channel_deviation.value)
|
||||
|
||||
if upper_channel and lower_channel:
|
||||
results['market_state'] = 'channel'
|
||||
results['pattern'] = 'price_channel'
|
||||
results['key_levels'] = [upper_channel[-1], lower_channel[-1]]
|
||||
|
||||
# 3. 头肩形态识别
|
||||
elif head_shoulder := self.detect_head_shoulder(df):
|
||||
results['market_state'] = 'reversal'
|
||||
results['pattern'] = 'head_shoulder' if head_shoulder['type'] == 'top' else 'inverse_head_shoulder'
|
||||
results['key_levels'] = [head_shoulder['neckline']]
|
||||
|
||||
# 4. 三角形形态识别
|
||||
elif triangle := self.detect_triangle(df):
|
||||
results['market_state'] = 'consolidation'
|
||||
results['pattern'] = triangle['type']
|
||||
results['key_levels'] = [triangle['upper'], triangle['lower']]
|
||||
|
||||
# 5. 趋势状态判断
|
||||
elif abs(results['trend_strength']) > 0.05:
|
||||
results['market_state'] = 'uptrend' if slope > 0 else 'downtrend'
|
||||
|
||||
return results
|
||||
|
||||
def detect_price_channel(self, df: pd.DataFrame, price_col: str, deviation=0.03) -> list:
|
||||
"""
|
||||
检测价格通道
|
||||
deviation: 允许的偏离度
|
||||
"""
|
||||
prices = df[price_col].values
|
||||
|
||||
# 线性回归通道
|
||||
x = np.arange(len(prices))
|
||||
slope, intercept, _, _, _ = linregress(x, prices)
|
||||
regression_line = intercept + slope * x
|
||||
|
||||
# 检查价格是否在通道内
|
||||
deviations = np.abs(prices - regression_line)
|
||||
if np.max(deviations) / np.mean(prices) < deviation:
|
||||
return regression_line.tolist()
|
||||
return None
|
||||
|
||||
def detect_head_shoulder(self, df: pd.DataFrame) -> dict:
|
||||
"""
|
||||
检测头肩顶/底形态
|
||||
返回形态特征字典
|
||||
"""
|
||||
# 寻找关键转折点 (使用最高价/最低价)
|
||||
highs = df['high'].values
|
||||
lows = df['low'].values
|
||||
|
||||
# 寻找局部极值点
|
||||
max_idx = np.argsort(highs)[-5:] # 前5个高点
|
||||
min_idx = np.argsort(lows)[:5] # 前5个低点
|
||||
|
||||
# 排序索引以确保时间顺序
|
||||
max_idx.sort()
|
||||
min_idx.sort()
|
||||
|
||||
# 头肩顶模式检查
|
||||
if len(max_idx) >= 5:
|
||||
# 典型头肩顶: 左肩-头-右肩 形态
|
||||
if (max_idx[1] > max_idx[0] and max_idx[2] > max_idx[1] and
|
||||
max_idx[3] < max_idx[2] and max_idx[4] < max_idx[3]):
|
||||
neckline = np.mean([lows[max_idx[1]], lows[max_idx[3]]])
|
||||
return {
|
||||
'type': 'top',
|
||||
'left_shoulder': max_idx[0],
|
||||
'head': max_idx[2],
|
||||
'right_shoulder': max_idx[4],
|
||||
'neckline': neckline
|
||||
}
|
||||
|
||||
# 头肩底模式检查
|
||||
if len(min_idx) >= 5:
|
||||
# 典型头肩底: 左肩-头-右肩 形态
|
||||
if (min_idx[1] < min_idx[0] and min_idx[2] < min_idx[1] and
|
||||
min_idx[3] > min_idx[2] and min_idx[4] > min_idx[3]):
|
||||
neckline = np.mean([highs[min_idx[1]], highs[min_idx[3]]])
|
||||
return {
|
||||
'type': 'bottom',
|
||||
'left_shoulder': min_idx[0],
|
||||
'head': min_idx[2],
|
||||
'right_shoulder': min_idx[4],
|
||||
'neckline': neckline
|
||||
}
|
||||
return None
|
||||
|
||||
def detect_triangle(self, df: pd.DataFrame) -> dict:
|
||||
"""
|
||||
检测三角形整理形态
|
||||
"""
|
||||
# 计算收敛趋势线
|
||||
highs = df['high'].values
|
||||
lows = df['low'].values
|
||||
|
||||
# 高点下降趋势线
|
||||
high_slope, high_intercept, _, _, _ = linregress(np.arange(len(highs)), highs)
|
||||
high_line = high_intercept + high_slope * np.arange(len(highs))
|
||||
|
||||
# 低点上升趋势线
|
||||
low_slope, low_intercept, _, _, _ = linregress(np.arange(len(lows)), lows)
|
||||
low_line = low_intercept + low_slope * np.arange(len(lows))
|
||||
|
||||
# 确定三角形类型
|
||||
triangle_type = None
|
||||
if high_slope < 0 and low_slope > 0:
|
||||
triangle_type = 'symmetrical'
|
||||
elif high_slope < 0 and abs(low_slope) < 0.001:
|
||||
triangle_type = 'descending'
|
||||
elif low_slope > 0 and abs(high_slope) < 0.001:
|
||||
triangle_type = 'ascending'
|
||||
|
||||
# 验证价格在趋势线范围内
|
||||
if triangle_type and np.all(highs <= high_line * 1.02) and np.all(lows >= low_line * 0.98):
|
||||
return {
|
||||
'type': triangle_type,
|
||||
'upper': high_line[-1],
|
||||
'lower': low_line[-1],
|
||||
'apex_index': int(-high_intercept / high_slope) # 计算交汇点
|
||||
}
|
||||
return None
|
||||
|
||||
def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
|
||||
# 每根K线分析前N根K线形成的市场背景
|
||||
window = self.pattern_window.value
|
||||
|
||||
# 初始化新列
|
||||
dataframe['market_state'] = 'neutral'
|
||||
dataframe['pattern_type'] = ''
|
||||
dataframe['trend_strength'] = 0.0
|
||||
|
||||
# 使用rolling窗口分析形态 (避免未来函数)
|
||||
for i in range(window, len(dataframe)):
|
||||
window_data = dataframe.iloc[i-window:i]
|
||||
analysis = self.detect_market_background(window_data, window)
|
||||
|
||||
# 将分析结果存入当前K线
|
||||
dataframe.at[dataframe.index[i], 'market_state'] = analysis['market_state']
|
||||
dataframe.at[dataframe.index[i], 'pattern_type'] = analysis.get('pattern', '')
|
||||
dataframe.at[dataframe.index[i], 'trend_strength'] = analysis['trend_strength']
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
|
||||
# 通道下沿买入策略
|
||||
dataframe.loc[
|
||||
(dataframe['market_state'] == 'channel') &
|
||||
(dataframe['close'] < dataframe['close'].rolling(5).mean() * 1.01) & # 接近通道底部
|
||||
(dataframe['volume'] > dataframe['volume'].rolling(20).mean()),
|
||||
'enter_long'] = 1
|
||||
|
||||
# 头肩底突破策略
|
||||
dataframe.loc[
|
||||
(dataframe['pattern_type'] == 'inverse_head_shoulder') &
|
||||
(dataframe['close'] > dataframe['close'].shift(1) * 1.02), # 突破颈线
|
||||
'enter_long'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
|
||||
# 通道上沿卖出
|
||||
dataframe.loc[
|
||||
(dataframe['market_state'] == 'channel') &
|
||||
(dataframe['close'] > dataframe['close'].rolling(5).mean() * 0.99), # 接近通道顶部
|
||||
'exit_long'] = 1
|
||||
|
||||
# 趋势逆转退出
|
||||
dataframe.loc[
|
||||
(dataframe['trend_strength'] < -0.03) & # 趋势转弱
|
||||
(dataframe['market_state'].shift(1) == 'uptrend'), # 前一状态是上涨
|
||||
'exit_long'] = 1
|
||||
|
||||
return dataframe
|
||||
```
|
||||
|
||||
### 关键实现技术
|
||||
|
||||
1. **滚动窗口分析**
|
||||
|
||||
```
|
||||
for i in range(window, len(dataframe)):
|
||||
window_data = dataframe.iloc[i-window:i]
|
||||
analysis = detect_market_background(window_data)
|
||||
# 将结果存入当前K线 (无未来函数)
|
||||
```
|
||||
|
||||
2. **多形态检测系统**
|
||||
|
||||
- 价格通道检测:使用线性回归和偏差分析
|
||||
- 头肩形态:通过极值点定位和时间顺序验证
|
||||
- 三角形识别:分析高低点趋势线收敛角度
|
||||
3. **市场状态分类**
|
||||
|
||||
|
||||
```
|
||||
market_state = {
|
||||
'neutral': 无明确方向,
|
||||
'uptrend/downtrend': 单边趋势,
|
||||
'channel': 价格通道,
|
||||
'reversal': 反转形态,
|
||||
'consolidation': 整理形态
|
||||
}
|
||||
```
|
||||
|
||||
4. **几何特征量化**
|
||||
- 趋势强度: `slope * len(df) / mean_price`
|
||||
- 波动率: `df['close'].pct_change().std()`
|
||||
- 关键水平: 颈线、通道边界、三角形顶点
|
||||
|
||||
### 高级技巧:动态形态检测
|
||||
|
||||
对于更复杂的形态,可以结合机器学习:
|
||||
|
||||
```
|
||||
from sklearn.ensemble import IsolationForest
|
||||
|
||||
def detect_anomaly_patterns(df):
|
||||
"""使用异常检测识别非常规形态"""
|
||||
features = df[['close', 'volume', 'range']].pct_change().dropna()
|
||||
|
||||
model = IsolationForest(contamination=0.05)
|
||||
anomalies = model.fit_predict(features)
|
||||
|
||||
if np.sum(anomalies == -1) > 3: # 至少3个异常点
|
||||
# 分析异常点的几何分布
|
||||
anomaly_idx = np.where(anomalies == -1)[0]
|
||||
if is_cluster(anomaly_idx): # 检查是否形成集群
|
||||
return 'cluster_anomaly'
|
||||
return None
|
||||
|
||||
def is_cluster(indices, max_gap=3):
|
||||
"""检查异常点是否形成集群"""
|
||||
gaps = np.diff(indices)
|
||||
return np.all(gaps <= max_gap)
|
||||
```
|
||||
|
||||
### 性能优化方案
|
||||
|
||||
处理长窗口时需考虑效率:
|
||||
|
||||
```
|
||||
def populate_indicators(self, dataframe):
|
||||
# 仅对最近6个月数据做全量分析
|
||||
if len(dataframe) > 4320: # 6个月(4h)
|
||||
dataframe = dataframe.tail(4320)
|
||||
|
||||
# 每10根K线分析一次
|
||||
for i in range(window, len(dataframe), 10):
|
||||
# 分析逻辑...
|
||||
|
||||
# 填充空白
|
||||
dataframe['market_state'].fillna(method='ffill', inplace=True)
|
||||
```
|
||||
|
||||
### 实际应用建议
|
||||
|
||||
1. **参数优化组合**
|
||||
|
||||
```
|
||||
self.pattern_window.optimize = True
|
||||
self.channel_deviation.optimize = True
|
||||
|
||||
# Hyperopt命令
|
||||
# freqtrade hyperopt --strategy ComplexPatternStrategy -e 500 --timerange 20220101-20230101
|
||||
```
|
||||
|
||||
2. **多时间框架验证**
|
||||
|
||||
```
|
||||
@informative('1d', name='daily')
|
||||
def populate_daily(self, df, metadata):
|
||||
df['daily_state'] = ... # 日线形态分析
|
||||
return df
|
||||
|
||||
# 在4小时策略中:
|
||||
def populate_entry_trend(self, df):
|
||||
df.loc[
|
||||
(df['market_state'] == 'uptrend') &
|
||||
(df['daily_state'] == 'channel') & # 日线在通道中
|
||||
...,
|
||||
'enter_long'] = 1
|
||||
```
|
||||
|
||||
3. **可视化调试**
|
||||
|
||||
```
|
||||
# 策略中增加调试输出
|
||||
if self.dp and self.dp.runmode.value in ('plot'):
|
||||
from freqtrade.plot.plotting import store_plot_file
|
||||
# 生成形态识别图表
|
||||
self.plot_patterns(dataframe, metadata)
|
||||
```
|
||||
|
||||
这种基于几何形态的市场背景分析特别适用于:
|
||||
|
||||
1. 中长线趋势跟踪(通道策略)
|
||||
2. 重大反转点捕捉(头肩形态)
|
||||
3. 突破交易(三角形末端)
|
||||
4. 市场状态自适应策略(根据背景调整参数)
|
||||
|
||||
关键是要平衡形态识别的复杂度和计算效率,建议从20-30根K线的窗口开始,重点识别2-3种高概率形态。
|
||||
Reference in New Issue
Block a user