VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > python数据分析 >
  • 实战:绘制某只股票的完整技术分析面板

第10章 股票技术分析实战
10.1 实战:绘制某只股票的完整技术分析面板
10.1.1 先讲个真实需求:老板要我做一个专业的股票分析面板
上个月老板让我做一个专业的股票分析面板,要求包含K线图、成交量、MACD、KDJ、RSI、BOLL这些技术指标,还要能实时更新数据。我用Matplotlib花了三天时间才做出来,后来发现用mplfinance和plotly可以更快地实现。今天我就把这个完vb.net教程C#教程python教程SQL教程access 2010教程整的技术分析面板的实现方法讲清楚,帮你快速做出专业的股票分析工具。

10.1.2 核心技术:多子图布局与技术指标整合
要绘制完整的技术分析面板,需要使用多子图布局,把K线图、成交量、MACD、KDJ、RSI、BOLL这些技术指标整合到一个画布中,同时添加交互式功能,方便用户操作。

10.1.3 实战1:用Matplotlib绘制完整技术分析面板

  1. 实战代码:Matplotlib完整技术分析面板
    python
	# 1. 导入需要的库
	import tushare as ts
	import pandas as pd
	import numpy as np
	import matplotlib.pyplot as plt
	from matplotlib.pylab import date2num
	from matplotlib.widgets import Cursor
	
	# 2. 获取贵州茅台的日线数据
	pro = ts.pro_api()
	df = pro.daily(ts_code='600519.SH', start_date='20250101', end_date='20250710')
	
	# 3. 数据预处理
	# 转换日期格式
	df['trade_date'] = pd.to_datetime(df['trade_date'], format='%Y%m%d')
	# 按时间从早到晚排序
	df.sort_values('trade_date', inplace=True)
	# 设置日期为索引
	df.set_index('trade_date', inplace=True)
	# 把日期转成Matplotlib需要的数字格式
	df['date_num'] = df.index.to_series().apply(date2num)
	# 计算涨跌颜色
	df['color'] = np.where(df['close'] >= df['open'], 'red', 'green')
	
	# 4. 计算技术指标
	# 计算均线
	df['ma5'] = df['close'].rolling(window=5).mean()
	df['ma20'] = df['close'].rolling(window=20).mean()
	df['ma60'] = df['close'].rolling(window=60).mean()
	
	# 计算MACD
	ema12 = df['close'].ewm(span=12, adjust=False).mean()
	ema26 = df['close'].ewm(span=26, adjust=False).mean()
	df['dif'] = ema12 - ema26
	df['dea'] = df['dif'].ewm(span=9, adjust=False).mean()
	df['macd'] = 2 * (df['dif'] - df['dea'])
	
	# 计算KDJ
	low9 = df['low'].rolling(window=9).min()
	high9 = df['high'].rolling(window=9).max()
	df['rsv'] = (df['close'] - low9) / (high9 - low9) * 100
	df['k'] = np.nan
	df['d'] = np.nan
	df.loc[df.index[8], 'k'] = df.loc[df.index[8], 'rsv']
	df.loc[df.index[8], 'd'] = df.loc[df.index[8], 'rsv']
	for i in range(9, len(df)):
	df.loc[df.index[i], 'k'] = (2/3) * df.loc[df.index[i-1], 'k'] + (1/3) * df.loc[df.index[i], 'rsv']
	df.loc[df.index[i], 'd'] = (2/3) * df.loc[df.index[i-1], 'd'] + (1/3) * df.loc[df.index[i], 'k']
	df['j'] = 3 * df['k'] - 2 * df['d']
	
	# 计算RSI
	df['change'] = df['close'].diff()
	df['up'] = np.where(df['change'] > 0, df['change'], 0)
	df['down'] = np.where(df['change'] < 0, -df['change'], 0)
	up6 = df['up'].rolling(window=6).mean()
	down6 = df['down'].rolling(window=6).mean()
	df['rsi6'] = up6 / (up6 + down6) * 100
	
	# 计算BOLL
	df['mid'] = df['close'].rolling(window=20).mean()
	df['std'] = df['close'].rolling(window=20).std()
	df['upper'] = df['mid'] + 2 * df['std']
	df['lower'] = df['mid'] - 2 * df['std']
	
	# 5. 创建画布和坐标轴
	fig, ((ax1, ax2), (ax3, ax4), (ax5, ax6)) = plt.subplots(
	3, 2, # 3行2列的坐标轴
	figsize=(16, 18), # 画布大小
	dpi=100, # 分辨率
	gridspec_kw={'height_ratios': [3, 1, 1]} # 三个行的高度比例,3:1:1
	)
	
	# 6. 绘制K线图和BOLL指标
	# 绘制BOLL上轨和下轨
	ax1.plot(
	df['date_num'], df['upper'],
	label='BOLL上轨', color='#ff7f0e', linewidth=1, linestyle='--'
	)
	ax1.plot(
	df['date_num'], df['mid'],
	label='BOLL中轨', color='#2ca02c', linewidth=1, linestyle='--'
	)
	ax1.plot(
	df['date_num'], df['lower'],
	label='BOLL下轨', color='#d62728', linewidth=1, linestyle='--'
	)
	# 填充BOLL上轨和下轨之间的区域
	ax1.fill_between(
	df['date_num'], df['upper'], df['lower'],
	color='#f0f0f0', alpha=0.3
	)
	# 绘制K线影线
	ax1.vlines(
	x=df['date_num'],
	ymin=df['low'],
	ymax=df['high'],
	color=df['color'],
	linewidth=1
	)
	# 绘制K线实体
	ax1.bar(
	x=df['date_num'],
	height=abs(df['close'] - df['open']),
	bottom=np.minimum(df['open'], df['close']),
	width=0.6,
	color=df['color'],
	edgecolor='#333333',
	linewidth=1
	)
	# 绘制均线
	ax1.plot(
	df['date_num'], df['ma5'],
	label='5日均线', color='#1f77b4', linewidth=2
	)
	ax1.plot(
	df['date_num'], df['ma20'],
	label='20日均线', color='#ff7f0e', linewidth=2
	)
	ax1.plot(
	df['date_num'], df['ma60'],
	label='60日均线', color='#2ca02c', linewidth=2
	)
	# 设置K线图属性
	ax1.set_title('贵州茅台2025年K线图与BOLL指标', fontsize=16, fontweight='bold', pad=20)
	ax1.set_ylabel('价格(元)', fontsize=14, labelpad=15)
	ax1.legend(fontsize=10, loc='upper right')
	ax1.grid(True, linestyle='--', alpha=0.7, color='#cccccc')
	# 设置日期显示格式
	ax1.xaxis_date()
	ax1.xaxis.set_major_formatter(plt.FixedFormatter(df.index.strftime('%Y-%m-%d')))
	plt.setp(ax1.get_xticklabels(), rotation=45, ha='right', fontsize=8)
	
	# 7. 绘制成交量柱形图
	ax2.bar(
	x=df['date_num'],
	height=df['vol'],
	width=0.6,
	color=df['color'],
	edgecolor='#333333',
	linewidth=1
	)
	# 绘制成交量均线
	ax2.plot(
	df['date_num'], df['vol'].rolling(window=5).mean(),
	label='5日成交量均线', color='#1f77b4', linewidth=2
	)
	ax2.plot(
	df['date_num'], df['vol'].rolling(window=20).mean(),
	label='20日成交量均线', color='#ff7f0e', linewidth=2
	)
	# 设置成交量属性
	ax2.set_title('成交量柱形图', fontsize=16, fontweight='bold', pad=20)
	ax2.set_ylabel('成交量(手)', fontsize=14, labelpad=15)
	ax2.legend(fontsize=10, loc='upper right')
	ax2.grid(True, linestyle='--', alpha=0.7, color='#cccccc')
	# 设置日期显示格式
	ax2.xaxis_date()
	ax2.xaxis.set_major_formatter(plt.FixedFormatter(df.index.strftime('%Y-%m-%d')))
	plt.setp(ax2.get_xticklabels(), rotation=45, ha='right', fontsize=8)
	
	# 8. 绘制MACD指标
	ax3.plot(
	df['date_num'], df['dif'],
	label='DIF(快线)', color='#1f77b4', linewidth=2
	)
	ax3.plot(
	df['date_num'], df['dea'],
	label='DEA(慢线)', color='#ff7f0e', linewidth=2
	)
	# 绘制MACD柱状图
	ax3.bar(
	x=df['date_num'],
	height=df['macd'],
	width=0.6,
	color=np.where(df['macd'] > 0, '#1f77b4', '#d62728'),
	alpha=0.5
	)
	# 设置MACD属性
	ax3.set_title('MACD指标', fontsize=16, fontweight='bold', pad=20)
	ax3.set_ylabel('MACD', fontsize=14, labelpad=15)
	ax3.legend(fontsize=10, loc='upper right')
	ax3.grid(True, linestyle='--', alpha=0.7, color='#cccccc')
	# 设置日期显示格式
	ax3.xaxis_date()
	ax3.xaxis.set_major_formatter(plt.FixedFormatter(df.index.strftime('%Y-%m-%d')))
	plt.setp(ax3.get_xticklabels(), rotation=45, ha='right', fontsize=8)
	
	# 9. 绘制KDJ指标
	ax4.plot(
	df['date_num'], df['k'],
	label='K线', color='#1f77b4', linewidth=2
	)
	ax4.plot(
	df['date_num'], df['d'],
	label='D线', color='#ff7f0e', linewidth=2
	)
	ax4.plot(
	df['date_num'], df['j'],
	label='J线', color='#2ca02c', linewidth=2
	)
	# 添加超买超卖线
	ax4.axhline(y=80, color='#d62728', linestyle='--', linewidth=1)
	ax4.axhline(y=20, color='#2ca02c', linestyle='--', linewidth=1)
	# 设置KDJ属性
	ax4.set_title('KDJ指标', fontsize=16, fontweight='bold', pad=20)
	ax4.set_ylabel('KDJ', fontsize=14, labelpad=15)
	ax4.legend(fontsize=10, loc='upper right')
	ax4.grid(True, linestyle='--', alpha=0.7, color='#cccccc')
	# 设置日期显示格式
	ax4.xaxis_date()
	ax4.xaxis.set_major_formatter(plt.FixedFormatter(df.index.strftime('%Y-%m-%d')))
	plt.setp(ax4.get_xticklabels(), rotation=45, ha='right', fontsize=8)
	
	# 10. 绘制RSI指标
	ax5.plot(
	df['date_num'], df['rsi6'],
	label='6日RSI', color='#1f77b4', linewidth=2
	)
	# 添加超买超卖线
	ax5.axhline(y=70, color='#d62728', linestyle='--', linewidth=1)
	ax5.axhline(y=30, color='#2ca02c', linestyle='--', linewidth=1)
	# 设置RSI属性
	ax5.set_title('RSI指标', fontsize=16, fontweight='bold', pad=20)
	ax5.set_xlabel('日期', fontsize=14, labelpad=15)
	ax5.set_ylabel('RSI', fontsize=14, labelpad=15)
	ax5.legend(fontsize=10, loc='upper right')
	ax5.grid(True, linestyle='--', alpha=0.7, color='#cccccc')
	# 设置日期显示格式
	ax5.xaxis_date()
	ax5.xaxis.set_major_formatter(plt.FixedFormatter(df.index.strftime('%Y-%m-%d')))
	plt.setp(ax5.get_xticklabels(), rotation=45, ha='right', fontsize=8)
	
	# 11. 绘制数据统计指标
	# 计算统计指标
	stats = pd.DataFrame({
	'指标': ['最新价', '开盘价', '最高价', '最低价', '成交量', '5日均线', '20日均线', '60日均线', 'DIF', 'DEA', 'MACD', 'K', 'D', 'J', 'RSI6'],
	'数值': [
	df['close'].iloc[-1], df['open'].iloc[-1], df['high'].iloc[-1], df['low'].iloc[-1], df['vol'].iloc[-1],
	df['ma5'].iloc[-1], df['ma20'].iloc[-1], df['ma60'].iloc[-1],
	df['dif'].iloc[-1], df['dea'].iloc[-1], df['macd'].iloc[-1],
	df['k'].iloc[-1], df['d'].iloc[-1], df['j'].iloc[-1], df['rsi6'].iloc[-1]
	]
	})
	# 绘制表格
	table = ax6.table(
	cellText=stats.values, # 表格内容
	colLabels=stats.columns, # 列标签
	cellLoc='center', # 单元格内容居中
	loc='center' # 表格位置居中
	)
	# 设置表格样式
	table.auto_set_font_size(False)
	table.set_fontsize(10)
	table.scale(1, 1.5) # 缩放表格,行高1.5倍
	# 隐藏坐标轴
	ax6.axis('off')
	# 设置标题
	ax6.set_title('数据统计指标', fontsize=16, fontweight='bold', pad=20)
	
	# 12. 添加十字光标
	cursor = Cursor(
	ax1, # 只在K线图上添加十字光标
	useblit=True,
	color='#333333',
	linewidth=1,
	linestyle='--'
	)
	
	# 13. 添加数据提示框
	text = ax1.text(
	0.02, 0.98,
	'',
	transform=ax1.transAxes,
	va='top',
	ha='left',
	fontsize=10,
	bbox=dict(
	boxstyle='round',
	facecolor='#ffffff',
	edgecolor='#333333',
	alpha=0.8
	)
	)
	
	def on_mouse_move(event):
	if not event.inaxes:
	return
	x = event.xdata
	idx = np.argmin(np.abs(df['date_num'] - x))
	data = df.iloc[idx]
	text_str = f'日期: {data.name.strftime("%Y-%m-%d")}
' 
	f'开盘价: {data["open"]:.2f}元
' 
	f'收盘价: {data["close"]:.2f}元
' 
	f'最高价: {data["high"]:.2f}元
' 
	f'最低价: {data["low"]:.2f}元
' 
	f'成交量: {data["vol"]:.0f}手'
	text.set_text(text_str)
	fig.canvas.draw_idle()
	
	fig.canvas.mpl_connect('motion_notify_event', on_mouse_move)
	
	# 14. 调整布局
	plt.tight_layout()
	
	# 15. 保存图片
	plt.savefig('贵州茅台2025年技术分析面板.png', dpi=300, bbox_inches='tight')
	
	# 16. 显示画布
	plt.show()

逐行讲解:
gridspec_kw={'height_ratios': [3, 1, 1]}:设置3行2列的坐标轴高度比例,第一行(K线图)占3份,第二行和第三行各占1份
ax1.fill_between(...):填充BOLL上轨和下轨之间的区域,使BOLL指标更直观
ax2.plot(...):绘制成交量的5日和20日均线,帮助判断成交量的趋势
ax6.table(...):绘制数据统计表格,显示最新的技术指标数值
ax6.axis('off'):隐藏表格所在的坐标轴,只显示表格
运行结果:
会弹出一个窗口,显示贵州茅台2025年的完整技术分析面板,包括:
1.K线图和BOLL指标
2.成交量柱形图和成交量均线
3.MACD指标
4.KDJ指标
5.RSI指标
6.数据统计表格
同时支持十字光标和数据提示功能,鼠标悬停在K线上时会显示详细数据。

10.1.4 实战2:用mplfinance绘制专业技术分析面板

  1. 实战代码:mplfinance专业技术分析面板
    python
	# 1. 导入需要的库
	import tushare as ts
	import mplfinance as mpf
	import pandas as pd
	import numpy as np
	
	# 2. 获取贵州茅台的日线数据
	pro = ts.pro_api()
	df = pro.daily(ts_code='600519.SH', start_date='20250101', end_date='20250710')
	
	# 3. 数据预处理
	df['trade_date'] = pd.to_datetime(df['trade_date'], format='%Y%m%d')
	df.set_index('trade_date', inplace=True)
	df.sort_index(ascending=True, inplace=True)
	df_rename = df.rename(columns={
	'open': 'Open',
	'high': 'High',
	'low': 'Low',
	'close': 'Close',
	'vol': 'Volume'
	})
	
	# 4. 计算技术指标
	# 计算MACD
	ema12 = df_rename['Close'].ewm(span=12, adjust=False).mean()
	ema26 = df_rename['Close'].ewm(span=26, adjust=False).mean()
	df_rename['MACD'] = ema12 - ema26
	df_rename['Signal'] = df_rename['MACD'].ewm(span=9, adjust=False).mean()
	df_rename['Histogram'] = 2 * (df_rename['MACD'] - df_rename['Signal'])
	
	# 计算KDJ
	low9 = df_rename['Low'].rolling(window=9).min()
	high9 = df_rename['High'].rolling(window=9).max()
	df_rename['RSV'] = (df_rename['Close'] - low9) / (high9 - low9) * 100
	df_rename['K'] = np.nan
	df_rename['D'] = np.nan
	df_rename.loc[df_rename.index[8], 'K'] = df_rename.loc[df_rename.index[8], 'RSV']
	df_rename.loc[df_rename.index[8], 'D'] = df_rename.loc[df_rename.index[8], 'RSV']
	for i in range(9, len(df_rename)):
	df_rename.loc[df_rename.index[i], 'K'] = (2/3) * df_rename.loc[df_rename.index[i-1], 'K'] + (1/3) * df_rename.loc[df_rename.index[i], 'RSV']
	df_rename.loc[df_rename.index[i], 'D'] = (2/3) * df_rename.loc[df_rename.index[i-1], 'D'] + (1/3) * df_rename.loc[df_rename.index[i], 'K']
	df_rename['J'] = 3 * df_rename['K'] - 2 * df_rename['D']
	
	# 计算RSI
	df_rename['Change'] = df_rename['Close'].diff()
	df_rename['Up'] = np.where(df_rename['Change'] > 0, df_rename['Change'], 0)
	df_rename['Down'] = np.where(df_rename['Change'] < 0, -df_rename['Change'], 0)
	up6 = df_rename['Up'].rolling(window=6).mean()
	down6 = df_rename['Down'].rolling(window=6).mean()
	df_rename['RSI6'] = up6 / (up6 + down6) * 100
	
	# 计算BOLL
	df_rename['Mid'] = df_rename['Close'].rolling(window=20).mean()
	df_rename['Std'] = df_rename['Close'].rolling(window=20).std()
	df_rename['Upper'] = df_rename['Mid'] + 2 * df_rename['Std']
	df_rename['Lower'] = df_rename['Mid'] - 2 * df_rename['Std']
	
	# 5. 自定义样式
	my_style = mpf.make_mpf_style(
	base_mpf_style='yahoo',
	marketcolors=mpf.make_marketcolors(
	up='red',
	down='green',
	edge='inherit',
	wick='inherit',
	volume='inherit'
	),
	gridstyle='--',
	y_on_right=False,
	facecolor='#f0f0f0',
	edgecolor='#333333',
	figcolor='#f0f0f0',
	gridcolor='#cccccc'
	)
	
	# 6. 创建附加指标面板
	apds = [
	# 绘制BOLL指标
	mpf.make_addplot(df_rename['Upper'], color='#ff7f0e', linestyle='--', width=1),
	mpf.make_addplot(df_rename['Mid'], color='#2ca02c', linestyle='--', width=1),
	mpf.make_addplot(df_rename['Lower'], color='#d62728', linestyle='--', width=1),
	# 绘制MACD指标
	mpf.make_addplot(df_rename['Histogram'], type='bar', color='#1f77b4', alpha=0.5, panel=1),
	mpf.make_addplot(df_rename['MACD'], color='#1f77b4', width=2, panel=1),
	mpf.make_addplot(df_rename['Signal'], color='#ff7f0e', width=2, panel=1),
	# 绘制KDJ指标
	mpf.make_addplot(df_rename['K'], color='#1f77b4', width=2, panel=2),
	mpf.make_addplot(df_rename['D'], color='#ff7f0e', width=2, panel=2),
	mpf.make_addplot(df_rename['J'], color='#2ca02c', width=2, panel=2),
	# 绘制RSI指标
	mpf.make_addplot(df_rename['RSI6'], color='#1f77b4', width=2, panel=3)
	]
	
	# 7. 绘制技术分析面板
	mpf.plot(
	df_rename,
	type='candle',
	style=my_style,
	title='贵州茅台2025年技术分析面板',
	ylabel='价格(元)',
	ylabel_lower='成交量(手)',
	volume=True,
	mav=(5, 20, 60),
	figratio=(16, 12),
	figscale=1.2,
	tight_layout=True,
	warn_too_much_data=1000,
	interactive=True,
	addplot=apds,
	panels=[
	{'name': 'Volume', 'height': 1},
	{'name': 'MACD', 'height': 1},
	{'name': 'KDJ', 'height': 1},
	{'name': 'RSI', 'height': 1}
	]
	)

逐行讲解:
mpf.make_addplot(...):创建附加指标面板,每个addplot对应一个技术指标
panel=1:指定指标显示在第2个面板(从0开始计数)
panels=[...]:定义各个面板的名称和高度比例
运行结果:
会弹出一个窗口,显示贵州茅台2025年的专业技术分析面板,支持交互式操作,包括缩放、平移、悬停提示等功能。

10.1.5 基础知识拓展:技术指标的综合应用

趋势判断:
使用BOLL指标判断趋势,当股价在BOLL上轨上方时,是上升趋势;当股价在BOLL下轨下方时,是下降趋势
使用均线判断趋势,当短期均线上穿长期均线时,是上升趋势;当短期均线下穿长期均线时,是下降趋势

买卖信号:

MACD金叉(DIF上穿DEA)时买入,死叉(DIF下穿DEA)时卖出
KDJ金叉(K线上穿D线)时买入,死叉(K线下穿D线)时卖出
RSI低于30时买入,高于70时卖出

成交量配合:

股价上涨时成交量放大,下跌时成交量缩小,是健康的上涨趋势
股价上涨时成交量缩小,下跌时成交量放大,是不健康的上涨趋势,可能反转

10.1.6 总结:技术分析面板的应用场景
1.股票分析:分析师可以通过技术分析面板快速查看股票的走势、成交量和各种技术指标,提高分析效率
2.量化交易:量化交易员可以通过技术分析面板监控股票的技术指标,当指标达到预设条件时自动执行交易
3.投资决策:投资者可以通过技术分析面板判断股票的买卖时机,提高投资收益
通过这个实战,你应该已经掌握了绘制完整技术分析面板的方法,接下来可以尝试用这些方法制作更专业的股票分析工具,或者结合量化策略实现自动交易。
下一节咱们就讲如何用Python做量化策略回测,帮你验证策略的有效性。
 

 
 本站原创,转载请注明出处:https://www.xin3721.com/ArticlePrograme/csharp49706.html

相关教程