VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > python数据分析 >
  • 实战:开发包含资金流向与舆情分析的综合看盘工具

第19章 综合看盘工具实战
19.1 实战:开发包含资金流向与舆情分析的综合看盘工具
19.1.1 先讲个真实需求:老板要我做一个综合看盘工具
上个月老板让我做一个综合看盘工具,要求能实时展示股票的行情、资金流向和舆情分析结果,还要能在公司内部服务器上部署。我之前只会用Plotly生成静态图表,完全不知道怎么实现实时更新和多模块集成。后来发现Dash可以快速实现这些功能,而且不需要vb.net教程C#教程python教程SQL教程access 2010教程前端知识。今天我就把开发包含资金流向与舆情分析的综合看盘工具的方法讲清楚,帮你快速做出专业的综合看盘工具。

19.1.2 核心技术:多模块集成与实时更新

  1. 多模块集成
    Dash可以将多个模块(行情展示、资金流向分析、舆情分析)集成到一个网页应用中,通过回调机制实现模块之间的交互。
  2. 实时更新
    Dash的dcc.Interval组件可以实现数据的实时更新,每隔一定时间自动刷新数据并更新图表。

19.1.3 实战:开发包含资金流向与舆情分析的综合看盘工具

  1. 实战代码:综合看盘工具
    python
	# 1. 导入需要的库
	import dash
	from dash import dcc, html, Input, Output, State
	import plotly.graph_objects as go
	import plotly.express as px
	import pandas as pd
	import tushare as ts
	import jieba
	import jieba.analyse
	from wordcloud import WordCloud
	import matplotlib.pyplot as plt
	import requests
	import re
	from datetime import datetime, timedelta
	import base64
	from io import BytesIO
	
	# 2. 初始化Dash应用
	app = dash.Dash(__name__, title='专业综合看盘工具')
	server = app.server
	
	# 3. 获取股票列表
	pro = ts.pro_api()
	stock_list = pro.stock_basic(exchange='', list_status='L', fields='ts_code,symbol,name,industry,list_date')
	stock_options = [{'label': f'{row["name"]} ({row["ts_code"]})', 'value': row['ts_code']} for _, row in stock_list.iterrows()]
	
	# 4. 定义辅助函数
	# 4.1 获取股票行情数据
	def get_stock_data(ts_code, days=30):
	start_date = (datetime.now() - timedelta(days=days)).strftime('%Y%m%d')
	end_date = datetime.now().strftime('%Y%m%d')
	df = pro.daily(ts_code=ts_code, start_date=start_date, end_date=end_date)
	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)
	# 计算均线
	df['ma5'] = df['close'].rolling(window=5).mean()
	df['ma20'] = df['close'].rolling(window=20).mean()
	df['ma60'] = df['close'].rolling(window=60).mean()
	return df
	
	# 4.2 获取资金流向数据
	def get_money_flow_data(ts_code, days=30):
	start_date = (datetime.now() - timedelta(days=days)).strftime('%Y%m%d')
	end_date = datetime.now().strftime('%Y%m%d')
	df = pro.moneyflow(ts_code=ts_code, start_date=start_date, end_date=end_date)
	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)
	# 计算主力资金净流入
	df['main_net_inflow'] = df['large_net_inflow'] + df['xlarge_net_inflow']
	return df
	
	# 4.3 获取股吧评论数据
	def get_guba_comments(ts_code, page_count=5):
	symbol = ts_code.split('.')[0]
	comments = []
	for page in range(1, page_count + 1):
	api_url = f' https://guba.eastmoney.com/list ,{symbol},f_{page}.html'
	try:
	response = requests.get(api_url, headers={
	'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
	})
	response.encoding = 'utf-8'
	html = response.text
	
	title_pattern = re.compile(r'<span class="l3 a3"><a href=".*?" target="_blank">(.*?)</a></span>')
	content_pattern = re.compile(r'<div class="articleh normal_post">(.*?)</div>', re.S)
	author_pattern = re.compile(r'<span class="l4 a4"><a href=".*?" target="_blank">(.*?)</a></span>')
	time_pattern = re.compile(r'<span class="l5 a5">(.*?)</span>')
	
	titles = title_pattern.findall(html)
	contents = content_pattern.findall(html)
	authors = author_pattern.findall(html)
	times = time_pattern.findall(html)
	
	for i in range(len(titles)):
	title = titles[i].strip()
	content = re.sub(r'<.*?>', '', contents[i]).strip()
	author = authors[i].strip()
	time = times[i].strip()
	comments.append({
	'title': title,
	'content': content,
	'author': author,
	'time': time
	})
	except Exception as e:
	print(f'抓取股吧评论失败: {e}')
	return comments
	
	# 4.4 生成词云图
	def generate_wordcloud(comments):
	text = ' '.join([comment['title'] + ' ' + comment['content'] for comment in comments])
	# 中文分词
	words = jieba.cut(text)
	# 过滤停用词
	with open('stopwords.txt', 'r', encoding='utf-8') as f:
	stopwords = set(f.read().splitlines())
	filtered_words = [word for word in words if word not in stopwords and len(word) > 1]
	# 词频统计
	word_counts = pd.Series(filtered_words).value_counts()
	# 生成词云图
	wc = WordCloud(
	font_path='simhei.ttf',
	background_color='white',
	max_words=200,
	max_font_size=100,
	width=800,
	height=600
	)
	wc.generate_from_frequencies(word_counts)
	# 保存词云图到内存
	img_buf = BytesIO()
	wc.to_image().save(img_buf, format='PNG')
	img_buf.seek(0)
	img_base64 = base64.b64encode(img_buf.getvalue()).decode('utf-8')
	return img_base64
	
	# 5. 创建应用布局
	app.layout = html.Div([
	# 顶部导航栏
	html.Div([
	html.H1('专业综合看盘工具', style={'textAlign': 'center', 'color': '#333333', 'margin': '20px 0'}),
	html.Div([
	# 股票选择下拉菜单
	html.Div([
	html.Label('选择股票:', style={'fontSize': '16px', 'marginRight': '10px'}),
	dcc.Dropdown(
	id='stock-selector',
	options=stock_options,
	value='600519.SH', # 默认选择贵州茅台
	style={'width': '300px', 'marginRight': '20px'}
	)
	], style={'display': 'inline-block', 'verticalAlign': 'middle'}),
	# 时间范围选择下拉菜单
	html.Div([
	html.Label('选择时间范围:', style={'fontSize': '16px', 'marginRight': '10px'}),
	dcc.Dropdown(
	id='time-range-selector',
	options=[
	{'label': '最近30天', 'value': '30'},
	{'label': '最近60天', 'value': '60'},
	{'label': '最近90天', 'value': '90'},
	{'label': '最近180天', 'value': '180'}
	],
	value='30', # 默认选择最近30天
	style={'width': '200px', 'marginRight': '20px'}
	)
	], style={'display': 'inline-block', 'verticalAlign': 'middle'}),
	# 刷新按钮
	html.Div([
	html.Button('刷新数据', id='refresh-button', n_clicks=0, style={'fontSize': '16px', 'padding': '8px 16px', 'backgroundColor': '#1f77b4', 'color': 'white', 'border': 'none', 'borderRadius': '4px'})
	], style={'display': 'inline-block', 'verticalAlign': 'middle'})
	], style={'textAlign': 'center', 'marginBottom': '20px'})
	], style={'backgroundColor': '#f0f0f0', 'padding': '20px', 'boxShadow': '0 2px 4px rgba(0,0,0,0.1)'}),
	
	# 主要内容区域
	html.Div([
	# 行情展示区域
	html.Div([
	html.H2('行情展示', style={'color': '#333333', 'margin': '20px 0'}),
	dcc.Graph(id='k线图', style={'height': '600px'})
	], style={'width': '70%', 'display': 'inline-block', 'verticalAlign': 'top', 'padding': '0 20px'}),
	
	# 股票信息区域
	html.Div([
	html.H2('股票信息', style={'color': '#333333', 'margin': '20px 0'}),
	html.Div(id='stock-info', style={'fontSize': '16px', 'lineHeight': '1.8'})
	], style={'width': '25%', 'display': 'inline-block', 'verticalAlign': 'top', 'padding': '0 20px', 'backgroundColor': '#f0f0f0', 'padding': '20px', 'borderRadius': '8px', 'boxShadow': '0 2px 4px rgba(0,0,0,0.1)'})
	], style={'width': '100%', 'maxWidth': '1600px', 'margin': '0 auto', 'padding': '20px 0'}),
	
	# 资金流向分析区域
	html.Div([
	html.H2('资金流向分析', style={'textAlign': 'center', 'color': '#333333', 'margin': '20px 0'}),
	html.Div([
	dcc.Graph(id='主力资金流向图', style={'height': '400px', 'width': '50%', 'display': 'inline-block', 'verticalAlign': 'top'}),
	dcc.Graph(id='资金流向占比图', style={'height': '400px', 'width': '50%', 'display': 'inline-block', 'verticalAlign': 'top'})
	])
	], style={'width': '100%', 'maxWidth': '1600px', 'margin': '0 auto', 'padding': '20px 0'}),
	
	# 舆情分析区域
	html.Div([
	html.H2('舆情分析', style={'textAlign': 'center', 'color': '#333333', 'margin': '20px 0'}),
	html.Div([
	html.Div([
	html.H3('股吧评论词云图', style={'color': '#333333', 'margin': '20px 0'}),
	html.Img(id='词云图', style={'width': '100%', 'height': 'auto'})
	], style={'width': '50%', 'display': 'inline-block', 'verticalAlign': 'top', 'padding': '0 20px'}),
	html.Div([
	html.H3('最新股吧评论', style={'color': '#333333', 'margin': '20px 0'}),
	html.Div(id='最新评论', style={'maxHeight': '600px', 'overflowY': 'scroll', 'fontSize': '14px', 'lineHeight': '1.6'})
	], style={'width': '50%', 'display': 'inline-block', 'verticalAlign': 'top', 'padding': '0 20px'})
	])
	], style={'width': '100%', 'maxWidth': '1600px', 'margin': '0 auto', 'padding': '20px 0'}),
	
	# 隐藏的Interval组件,用于自动刷新数据
	dcc.Interval(
	id='interval-component',
	interval=5*60*1000, # 每隔5分钟自动刷新一次
	n_intervals=0
	)
	])
	
	# 6. 定义回调函数:更新行情展示和股票信息
	@app.callback( 
	[Output('k线图', 'figure'),
	Output('stock-info', 'children')],
	[Input('stock-selector', 'value'),
	Input('time-range-selector', 'value'),
	Input('refresh-button', 'n_clicks'),
	Input('interval-component', 'n_intervals')],
	[State('stock-selector', 'value'),
	State('time-range-selector', 'value')]
	)
	def update_stock_data(selected_stock, time_range, n_clicks, n_intervals, current_stock, current_time_range):
	stock_code = selected_stock if selected_stock is not None else current_stock
	days = int(time_range) if time_range is not None else int(current_time_range)
	
	# 获取股票行情数据
	df = get_stock_data(stock_code, days)
	# 获取股票基本信息
	stock_info = stock_list[stock_list['ts_code'] == stock_code].iloc[0]
	
	# 绘制K线图
	fig = go.Figure()
	fig.add_trace(go.Candlestick(
	x=df.index,
	open=df['open'],
	high=df['high'],
	low=df['low'],
	close=df['close'],
	name='K线图',
	increasing_line_color='red',
	decreasing_line_color='green'
	))
	fig.add_trace(go.Scatter(
	x=df.index,
	y=df['ma5'],
	name='5日均线',
	line=dict(color='#1f77b4', width=2),
	opacity=0.8
	))
	fig.add_trace(go.Scatter(
	x=df.index,
	y=df['ma20'],
	name='20日均线',
	line=dict(color='#ff7f0e', width=2),
	opacity=0.8
	))
	fig.add_trace(go.Scatter(
	x=df.index,
	y=df['ma60'],
	name='60日均线',
	line=dict(color='#2ca02c', width=2),
	opacity=0.8
	))
	fig.update_layout(
	title=f'{stock_info["name"]}({stock_code}) K线图',
	yaxis_title='价格(元)',
	xaxis_title='日期',
	template='plotly_white',
	hovermode='x unified',
	legend={'x': 0.02, 'y': 0.98}
	)
	fig.update_xaxes(rangeslider_visible=False)
	
	# 生成股票信息
	stock_info_children = [
	html.P(f'股票名称: {stock_info["name"]}'),
	html.P(f'股票代码: {stock_info["symbol"]}'),
	html.P(f'行业: {stock_info["industry"]}'),
	html.P(f'上市日期: {stock_info["list_date"]}'),
	html.P(f'最新价: {df.iloc[-1]["close"]:.2f}元'),
	html.P(f'涨跌幅: {(df.iloc[-1]["close"] - df.iloc[-1]["open"])/df.iloc[-1]["open"]*100:.2f}%'),
	html.P(f'最高价: {df.iloc[-1]["high"]:.2f}元'),
	html.P(f'最低价: {df.iloc[-1]["low"]:.2f}元'),
	html.P(f'成交量: {df.iloc[-1]["vol"]/10000:.2f}万手'),
	html.P(f'成交额: {df.iloc[-1]["amount"]/100000000:.2f}亿元')
	]
	
	return fig, stock_info_children
	
	# 7. 定义回调函数:更新资金流向分析
	@app.callback( 
	[Output('主力资金流向图', 'figure'),
	Output('资金流向占比图', 'figure')],
	[Input('stock-selector', 'value'),
	Input('time-range-selector', 'value'),
	Input('refresh-button', 'n_clicks'),
	Input('interval-component', 'n_intervals')],
	[State('stock-selector', 'value'),
	State('time-range-selector', 'value')]
	)
	def update_money_flow(selected_stock, time_range, n_clicks, n_intervals, current_stock, current_time_range):
	stock_code = selected_stock if selected_stock is not None else current_stock
	days = int(time_range) if time_range is not None else int(current_time_range)
	
	# 获取资金流向数据
	df = get_money_flow_data(stock_code, days)
	
	# 绘制主力资金流向图
	fig_main = go.Figure()
	fig_main.add_trace(go.Bar(
	x=df.index,
	y=df['main_net_inflow'],
	name='主力资金净流入(万元)',
	marker_color=np.where(df['main_net_inflow'] > 0, '#1f77b4', '#d62728'),
	opacity=0.7
	))
	fig_main.update_layout(
	title='主力资金净流入趋势',
	yaxis_title='主力资金净流入(万元)',
	xaxis_title='日期',
	template='plotly_white',
	hovermode='x unified'
	)
	
	# 绘制资金流向占比图
	latest_data = df.iloc[-1]
	flow_data = pd.DataFrame({
	'资金类型': ['超大单净流入', '大单净流入', '中单净流入', '小单净流入'],
	'金额(万元)': [latest_data['xlarge_net_inflow'], latest_data['large_net_inflow'], latest_data['mid_net_inflow'], latest_data['small_net_inflow']]
	})
	fig_pie = px.pie(
	flow_data,
	values='金额(万元)',
	names='资金类型',
	title='最新资金流向占比',
	color_discrete_sequence=px.colors.qualitative.Set3
	)
	fig_pie.update_traces(textposition='inside', textinfo='percent+label')
	
	return fig_main, fig_pie
	
	# 8. 定义回调函数:更新舆情分析
	@app.callback( 
	[Output('词云图', 'src'),
	Output('最新评论', 'children')],
	[Input('stock-selector', 'value'),
	Input('refresh-button', 'n_clicks'),
	Input('interval-component', 'n_intervals')],
	[State('stock-selector', 'value')]
	)
	def update_sentiment_analysis(selected_stock, n_clicks, n_intervals, current_stock):
	stock_code = selected_stock if selected_stock is not None else current_stock
	
	# 获取股吧评论数据
	comments = get_guba_comments(stock_code)
	# 生成词云图
	img_base64 = generate_wordcloud(comments)
	# 生成最新评论
	latest_comments = comments[:10] # 只显示最新的10条评论
	comments_children = []
	for comment in latest_comments:
	comments_children.append(
	html.Div([
	html.P(f'<b>标题:</b> {comment["title"]}', style={'marginBottom': '5px'}),
	html.P(f'<b>内容:</b> {comment["content"]}', style={'marginBottom': '5px'}),
	html.P(f'<b>作者:</b> {comment["author"]}', style={'marginBottom': '5px'}),
	html.P(f'<b>时间:</b> {comment["time"]}', style={'marginBottom': '20px', 'borderBottom': '1px solid #ccc', 'paddingBottom': '10px'})
	])
	)
	
	return f'data:image/png;base64,{img_base64}', comments_children
	
	# 9. 运行应用
	if __name__ == '__main__':
	app.run_server(debug=True, host='0.0.0.0', port=8053)

逐行讲解:
get_stock_data(ts_code, days=30):获取股票行情数据,包括K线数据和均线数据
get_money_flow_data(ts_code, days=30):获取资金流向数据,包括超大单、大单、中单、小单的资金流入流出情况
get_guba_comments(ts_code, page_count=5):抓取东方财富股吧的评论数据
generate_wordcloud(comments):根据股吧评论生成词云图,并保存到内存中
dcc.Interval(...):每隔5分钟自动刷新一次数据
@app.callback(...):定义回调函数,当用户选择不同的股票或时间范围时,自动更新对应的图表和数据
运行结果:
在命令行中运行代码,在浏览器中访问 http://localhost:8053 ,就可以看到专业的综合看盘工具,包含行情展示、资金流向分析、舆情分析三个模块,支持选择不同的股票和时间范围,手动或自动刷新数据。

19.1.4 基础知识拓展:综合看盘工具的应用场景

  1. 专业投资者
    专业投资者可以通过综合看盘工具实时监控股票的行情、资金流向和舆情,更准确地判断买卖时机。
  2. 量化交易员
    量化交易员可以通过综合看盘工具监控市场的热点板块和龙头股票,辅助构建量化交易策略。
  3. 公司内部使用
    公司内部的投资团队可以通过综合看盘工具实时监控股票行情,辅助投资决策。
  4. 教学演示
    在教学中使用综合看盘工具,更直观地展示股票分析的方法和应用场景。

19.1.5 实战优化:添加多股票对比功能

  1. 实战代码:添加多股票对比功能
    python
	# 在应用布局中添加多股票对比区域
	html.Div([
	html.H2('多股票对比', style={'textAlign': 'center', 'color': '#333333', 'margin': '20px 0'}),
	html.Div([
	html.Div([
	html.Label('选择对比股票:', style={'fontSize': '16px', 'marginRight': '10px'}),
	dcc.Dropdown(
	id='compare-stock-selector',
	options=stock_options,
	value=['600519.SH', '000858.SZ'], # 默认选择贵州茅台和五粮液
	multi=True,
	style={'width': '800px', 'marginRight': '20px'}
	)
	], style={'textAlign': 'center', 'marginBottom': '20px'}),
	dcc.Graph(id='多股票对比图', style={'height': '600px'})
	])
	], style={'width': '100%', 'maxWidth': '1600px', 'margin': '0 auto', 'padding': '20px 0'})
	
	# 定义回调函数:更新多股票对比图
	@app.callback( 
	Output('多股票对比图', 'figure'),
	[Input('compare-stock-selector', 'value'),
	Input('time-range-selector', 'value'),
	Input('refresh-button', 'n_clicks'),
	Input('interval-component', 'n_intervals')],
	[State('compare-stock-selector', 'value'),
	State('time-range-selector', 'value')]
	)
	def update_compare_stocks(selected_stocks, time_range, n_clicks, n_intervals, current_stocks, current_time_range):
	stock_codes = selected_stocks if selected_stocks is not None else current_stocks
	days = int(time_range) if time_range is not None else int(current_time_range)
	
	fig = go.Figure()
	for stock_code in stock_codes:
	df = get_stock_data(stock_code, days)
	stock_name = stock_list[stock_list['ts_code'] == stock_code].iloc[0]['name']
	fig.add_trace(go.Scatter(
	x=df.index,
	y=df['close'],
	name=f'{stock_name}({stock_code})',
	line=dict(width=2),
	opacity=0.8
	))
	
	fig.update_layout(
	title='多股票收盘价对比',
	yaxis_title='价格(元)',
	xaxis_title='日期',
	template='plotly_white',
	hovermode='x unified',
	legend={'x': 0.02, 'y': 0.98}
	)
	
	return fig

运行结果:
在浏览器中可以看到多股票对比区域,支持选择多个股票进行对比,展示它们的收盘价走势。

19.1.6 总结:综合看盘工具的应用场景
1.专业投资者:专业投资者可以通过综合看盘工具实时监控股票的行情、资金流向和舆情,更准确地判断买卖时机。
2.量化交易员:量化交易员可以通过综合看盘工具监控市场的热点板块和龙头股票,辅助构建量化交易策略。
3.公司内部使用:公司内部的投资团队可以通过综合看盘工具实时监控股票行情,辅助投资决策。
4.教学演示:在教学中使用综合看盘工具,更直观地展示股票分析的方法和应用场景。
通过这个实战,你应该已经掌握了开发包含资金流向与舆情分析的综合看盘工具的方法,包括行情展示、资金流向分析、舆情分析、多股票对比等功能。接下来可以尝试用这些方法制作更专业的股票分析工具和量化交易系统。
下一节咱们就讲如何用Python做量化策略回测,帮你验证策略的有效性。

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


相关教程