通达信K线形态匹配实战:5步教你用Python代码找出相似股票走势
通达信K线形态匹配实战5步Python代码实现股票走势相似度分析当你在通达信软件上看到某只股票的K线走势时有没有想过历史上还有哪些股票出现过类似的形态这些股票后来都怎么样了作为量化交易开发者我们可以用Python代码实现这个功能而不仅仅是依赖软件自带的分析工具。本文将手把手教你如何从零开始构建一个K线形态匹配系统。1. 数据准备与预处理在开始匹配K线形态之前我们需要获取并准备好基础数据。通达信的日线数据通常以特定格式存储我们需要先将其转换为适合Python处理的格式。首先安装必要的Python库pip install pandas numpy sqlite3 tushare然后编写数据导入函数import pandas as pd import sqlite3 def import_tdx_data(tdx_path, db_pathstock_data.db): 导入通达信日线数据到SQLite数据库 :param tdx_path: 通达信安装目录 :param db_path: 数据库文件路径 conn sqlite3.connect(db_path) cursor conn.cursor() # 创建数据表 cursor.execute( CREATE TABLE IF NOT EXISTS tdx_stock_daily ( code TEXT, trade_date TEXT, open REAL, high REAL, low REAL, close REAL, volume INTEGER, PRIMARY KEY (code, trade_date) ) ) # 这里需要根据通达信实际数据格式编写解析代码 # 示例伪代码 for market in [SH, SZ]: for stock_file in os.listdir(f{tdx_path}/T0002/hq_cache/{market}): data parse_tdx_file(f{tdx_path}/T0002/hq_cache/{market}/{stock_file}) data.to_sql(tdx_stock_daily, conn, if_existsappend, indexFalse) conn.commit() conn.close()数据预处理的关键步骤标准化处理不同股票价格绝对值差异大需要归一化缺失值处理处理停牌等导致的缺失数据数据对齐确保所有股票交易日一致2. K线形态特征提取K线形态匹配的核心是将连续的K线走势转化为可计算的特征向量。我们主要关注以下几种特征特征类型计算方式说明价格变化(close-open)/open反映单日涨跌幅实体大小(close-open)/high-low反映K线实体占比上下影线(high-close)/high-low, (open-low)/high-low反映压力支撑波动率窗口内标准差反映价格波动程度def extract_features(window): 从K线窗口提取特征向量 :param window: DataFrame包含open,high,low,close列 :return: 特征向量 features [] # 价格变化特征 price_change (window[close] - window[open]) / window[open] features.extend(price_change.values) # 实体大小特征 entity_size (window[close] - window[open]) / (window[high] - window[low]) features.extend(entity_size.fillna(0).values) # 处理除零情况 # 其他特征... return np.array(features)3. 相似度算法实现有了特征向量后我们需要定义相似度计算方法。常用的时间序列相似度算法包括欧氏距离简单直接但对时间偏移敏感DTW动态时间规整能处理不同长度和相位差的序列皮尔逊相关系数衡量形态相似性忽略绝对值差异以下是DTW算法的Python实现from dtaidistance import dtw def calculate_similarity(seq1, seq2): 使用DTW算法计算两个序列的相似度 :param seq1: 序列1 :param seq2: 序列2 :return: 相似度得分(0-1) distance dtw.distance(seq1, seq2) max_distance max(np.max(seq1)-np.min(seq1), np.max(seq2)-np.min(seq2)) * len(seq1) return 1 - distance / max_distance if max_distance 0 else 0实际应用中我们可以组合多种相似度算法def combined_similarity(features1, features2): 组合多种相似度计算方法 # 特征相似度 feature_sim cosine_similarity(features1.reshape(1,-1), features2.reshape(1,-1))[0][0] # 价格序列相似度 price_sim calculate_similarity(features1[:5], features2[:5]) # 假设前5个是价格特征 # 加权综合 return 0.6 * price_sim 0.4 * feature_sim4. 滑动窗口匹配实现有了相似度计算方法后我们需要在全市场历史数据中搜索相似形态。这里采用滑动窗口方法def find_similar_patterns(db_path, query_pattern, threshold0.8, max_results50): 在全市场查找相似K线形态 :param db_path: 数据库路径 :param query_pattern: 查询形态特征 :param threshold: 相似度阈值 :param max_results: 最大返回结果数 :return: 匹配结果列表 conn sqlite3.connect(db_path) cursor conn.cursor() # 获取所有股票代码 cursor.execute(SELECT DISTINCT code FROM tdx_stock_daily) stock_codes [row[0] for row in cursor.fetchall()] results [] window_size len(query_pattern) for code in stock_codes: # 获取该股票全部收盘价 cursor.execute( SELECT trade_date, close FROM tdx_stock_daily WHERE code? ORDER BY trade_date, (code,) ) data cursor.fetchall() closes [row[1] for row in data] dates [row[0] for row in data] # 滑动窗口匹配 for i in range(len(closes) - window_size 1): window closes[i:iwindow_size] window_features extract_features_from_prices(window) similarity combined_similarity(query_pattern, window_features) if similarity threshold: results.append({ code: code, start_date: dates[i], end_date: dates[iwindow_size-1], similarity: similarity }) if len(results) max_results: break conn.close() # 按相似度排序 return sorted(results, keylambda x: x[similarity], reverseTrue)[:max_results]5. 结果可视化与分析找到相似形态后我们需要直观展示结果并分析统计特征。使用Matplotlib绘制对比图import matplotlib.pyplot as plt from matplotlib.dates import DateFormatter def plot_comparison(db_path, query_code, query_dates, match_code, match_dates): 绘制查询形态与匹配形态的对比图 fig, (ax1, ax2) plt.subplots(2, 1, figsize(12, 8)) # 查询形态 query_data get_stock_data(db_path, query_code, query_dates[0], query_dates[1]) plot_candlestick(ax1, query_data, titlef查询形态: {query_code}) # 匹配形态 match_data get_stock_data(db_path, match_code, match_dates[0], match_dates[1]) plot_candlestick(ax2, match_data, titlef匹配形态: {match_code}) plt.tight_layout() plt.show() def plot_candlestick(ax, data, title): 绘制K线图 dates pd.to_datetime(data[trade_date]) opens data[open] closes data[close] highs data[high] lows data[low] # 确定上涨下跌颜色 colors [red if close open else green for close, open in zip(closes, opens)] # 绘制K线实体 ax.bar(dates, closes-opens, bottomopens, width0.6, colorcolors) # 绘制上下影线 for date, high, low, open_, close in zip(dates, highs, lows, opens, closes): ax.plot([date, date], [low, min(open_, close)], colorcolors[0]) ax.plot([date, date], [max(open_, close), high], colorcolors[0]) ax.xaxis.set_major_formatter(DateFormatter(%Y-%m-%d)) plt.setp(ax.get_xticklabels(), rotation45) ax.set_title(title)统计分析方法可以包括后续走势分析统计匹配形态后N日的平均涨跌幅胜率分析统计匹配形态后上涨的概率风险收益比统计最大回撤与平均收益的关系def analyze_pattern_performance(db_path, pattern_results, days_after5): 分析匹配形态后的表现 :param pattern_results: find_similar_patterns返回的结果 :param days_after: 统计多少天后的表现 :return: 统计分析结果 conn sqlite3.connect(db_path) cursor conn.cursor() stats { total: len(pattern_results), positive: 0, avg_return: 0, max_return: 0, min_return: 0 } returns [] for result in pattern_results: # 获取匹配结束日期后days_after天的数据 cursor.execute( SELECT close FROM tdx_stock_daily WHERE code? AND trade_date? ORDER BY trade_date LIMIT ?, (result[code], result[end_date], days_after) ) future_data cursor.fetchall() if len(future_data) days_after: start_price get_price_at_date(db_path, result[code], result[end_date]) end_price future_data[-1][0] ret (end_price - start_price) / start_price * 100 returns.append(ret) if returns: stats.update({ positive: sum(1 for r in returns if r 0) / len(returns), avg_return: np.mean(returns), max_return: np.max(returns), min_return: np.min(returns), median_return: np.median(returns) }) conn.close() return stats6. 性能优化与生产部署当数据量较大时上述基础实现可能会遇到性能问题。以下是几种优化方案数据库索引优化CREATE INDEX idx_code_date ON tdx_stock_daily(code, trade_date);并行计算from concurrent.futures import ThreadPoolExecutor def parallel_search(query_pattern, stock_codes, db_path, threshold0.8): with ThreadPoolExecutor(max_workers8) as executor: futures [ executor.submit(search_single_stock, code, query_pattern, db_path, threshold) for code in stock_codes ] results [] for future in as_completed(futures): results.extend(future.result()) return sorted(results, keylambda x: x[similarity], reverseTrue)近似最近邻搜索(ANN)使用FAISS或Annoy等库构建向量索引将K线特征向量化后建立索引实现快速相似度搜索缓存机制对常见查询模式缓存结果使用Redis存储中间结果生产部署建议使用Flask或FastAPI构建Web服务添加任务队列(Celery)处理长时间任务使用Vue或React构建前端界面考虑使用Docker容器化部署from fastapi import FastAPI from celery import Celery app FastAPI() celery Celery(tasks, brokerredis://localhost:6379/0) app.post(/search) async def search_pattern(query: dict): task search_pattern_task.delay(query) return {task_id: task.id} celery.task def search_pattern_task(query): # 实际的搜索逻辑 return find_similar_patterns(...)7. 实际应用案例假设我们发现某只股票近期出现了早晨之星形态想找历史上出现类似形态的股票# 获取查询股票的K线数据 query_code 600519.SH # 贵州茅台 query_dates (2023-03-01, 2023-03-10) query_data get_stock_data(db_path, query_code, query_dates[0], query_dates[1]) # 提取特征 query_pattern extract_features(query_data) # 搜索相似形态 similar_patterns find_similar_patterns(db_path, query_pattern, threshold0.85) # 分析结果 analysis_result analyze_pattern_performance(db_path, similar_patterns) print(f找到{len(similar_patterns)}个相似形态) print(f后续5日平均涨幅: {analysis_result[avg_return]:.2f}%) print(f上涨概率: {analysis_result[positive]*100:.2f}%) # 可视化最佳匹配 best_match similar_patterns[0] plot_comparison( db_path, query_code, query_dates, best_match[code], (best_match[start_date], best_match[end_date]) )实际应用中我们可以将这套方法扩展到更多场景形态组合策略结合多种形态信号提高胜率参数优化通过历史数据回测确定最佳参数实时监控对接实时行情数据实现盘中预警