from jqdata import * import datetime as dt import numpy as np import pandas as pd import seaborn as sns import matplotlib.pyplot as plt import json, textwrap# 获取股票和价格数据 stocks = get_index_stocks("000985.XSHG") now = dt.datetime.now().strftime('%Y-%m-%d %H:%M:%S') yesterday = (dt.datetime.now() - dt.timedelta(days=1)).strftime("%Y-%m-%d")count = 90 #1年的交易日 price_hist = get_price(stocks,end_date=yesterday,frequency="1d",fields=["close"],count=count + 19,panel=False)# 获取行业信息 def getStockIndustry(stocks):industry = get_industry(stocks)dict = {stock: info["sw_l1"]["industry_name"]for stock, info in industry.items()if "sw_l1" in info}industry_2_stock = {}for stock, info in industry.items():if "sw_l1" in info:industry_name = info["sw_l1"]["industry_name"]ls = industry_2_stock.get(industry_name, [])ls.append(stock)industry_2_stock[industry_name] = lsreturn pd.Series(dict), industry_2_stockdef update_price():cur_price = get_price(stocks,end_date=now,frequency="1m",fields=["close"],count=1,panel=False)cur_price['time'] = pd.to_datetime(cur_price['time']).dt.floor('d')new_price = pd.concat([price_hist, cur_price], ignore_index=True)new_price= new_price.sort_values(['code', 'time']).reset_index(drop=True)return new_pricedef update_df():# 处理数据h = update_price()h["date"] = pd.DatetimeIndex(h.time).datedf_close = h.pivot(index="code", columns="date", values="close").dropna(axis=0)df_ma20 = df_close.rolling(window=20, axis=1).mean().iloc[:, -count:]df_bias = df_close.iloc[:, -count:] > df_ma20df_bias["industry_name"], industry_2_stock = getStockIndustry(stocks)df_ratio = ((df_bias.groupby("industry_name").sum() * 100.0)/ df_bias.groupby("industry_name").count()).round()df_ratio.loc['合计'] = df_ratio.sum().astype("int32")DF = df_ratio.Treturn DF#======================================================================def update_html(DF):industry_cols = DF.columns[:-1]df = DF.iloc[:, :-1].copy() # 创建数据框副本,避免修改原始数据df.insert(len(industry_cols), '市场平均', df[industry_cols].mean(axis=1).round().astype(int))df.index = pd.to_datetime(df.index)use_cols = [c for c in df.columns if c not in {'合计'}]# 1. 只保留 [x, y, value] 三元组给 EChartsdata_js = [[j, i, int(df.iloc[i, j])]for i in range(len(df))for j in range(len(df.columns))] # print("data_js:", data_js)# 2. 行业名、日期单独传两份数组,前端用索引去取cols = df.columns.tolist() # print("cols:", cols)dates = [str(d) for d in df.index.date] # print("dates:", dates) cell_w = 40 # 每列宽 80 pxcell_h = 40 # 每行高 26 px(足够看清文字)width = len(use_cols) * cell_w # 留边给 visualMapheight = len(df) * cell_h # 随行情自动增高# 写进单文件 HTML html = textwrap.dedent(f'''\<!doctype html><html><head><meta charset="utf-8"><title>行业热力图(可点击)</title><script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script><style>#wrapper{{width:100%;max-height:70vh;overflow:auto;border:1px solid #ddd}}#chart{{width:{width}px;height:{height}px;margin:auto}}</style></head><body><div id="chart" style="width:{{width}}px;height:{{height}}px;margin:auto"></div><script>const raw = {json.dumps(data_js)};const cols = {json.dumps(cols)};const dates = {json.dumps(dates)};const myChart = echarts.init(document.getElementById('chart'));const option = {{tooltip: {{position: 'top',formatter: p => {{const [x, y, val] = p.data;return `${{dates[y]}}<br/>${{cols[x]}}: <b>${{val}}</b>`;}}}},animation: true,grid: {{left: '10%', right: '5%', bottom: '5%', top: '2%'}},xAxis: {{type: 'category',data: cols,position: 'top', axisLabel: {{interval: 0,rotate: 45,fontSize: 11}},splitArea: {{show: true}}}},yAxis: {{type: 'category',data: dates,splitArea: {{show: true}}}},visualMap: {{min: 0, max: 100, calculable: true, type: 'continuous',orient: 'horizontal', left: 'center', bottom: '2%',inRange: {{color: ['#005824','#238b45','#5cb85c','#90ee90','#ffff99','#ffaa99','#ff7d66','#f54437','#b00000']}}}},series: [{{name: '热力图',type: 'heatmap',data: raw,label: {{show: true, fontSize: 11, color: '#000'}},itemStyle: {{borderWidth: 1, borderColor: '#fff'}},emphasis: {{itemStyle: {{shadowBlur: 12, shadowColor: 'rgba(0,0,0,.4'}}}}}}]}};myChart.setOption(option);// 点击事件myChart.on('click', params => {{const [,,val,ind,dt] = params.data;alert(`${{dt}}\\n${{ind}}: ${{val}}`);}});</script></body></html>''')open('行业宽度-定时刷新版.html','w',encoding='utf-8').write(html)print("可以打开-行业宽度-定时刷新版.html")# 定时刷新 10分钟一次 while True:DF = update_df()update_html(DF)time.sleep(60 * 10)