Files
obsidian-vault/05 投资交易/freqtrade是否支持自定义K线形态的识别监测?.md
2026-06-23 00:24:32 +08:00

346 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

#交易 #量化交易 #策略研究 #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种高概率形态。