如何用Python制作基于网页爬取黄金价格的实时15分钟K线图?
实时15分钟黄金K线图实现方案(基于matplotlib/mplfinance)
一、核心问题解答:matplotlib可以实现吗?
完全可以。你用到的mplfinance是基于matplotlib开发的专业金融绘图库,原生支持动态更新K线图,能够实现每15分钟闭合旧K线、生成新K线的需求,达到类似TradingView的实时效果。
二、具体实现建议
1. 实时数据爬取与K线维护
- 定时触发爬取:用
time.sleep()配合循环,或更可靠的APScheduler实现定时爬取,注意对齐15分钟时间节点(如整点、15分、30分、45分触发),避免K线时间错位。 - K线数据管理:维护一个
pandas.DataFrame存储历史闭合K线,同时单独维护当前未闭合的K线:- 未到15分钟节点时,用最新爬取的价格更新当前K线的
High/Low/Close; - 到达时间节点时,将当前K线并入历史数据,然后用最新价格初始化新的K线(
Open/High/Low/Close均设为当前价格)。
- 未到15分钟节点时,用最新爬取的价格更新当前K线的
- 异常处理:爬取逻辑要加异常捕获(如请求失败、数据解析错误),避免程序直接崩溃。
2. 动态更新K线图
- 复用画布对象:不要每次绘图都重新创建
fig和ax,复用已有的对象,每次更新数据后调用ax.clear()清除旧图,再重新绘制。 - 实时刷新机制:每次绘制完成后调用
plt.pause(0.1)触发画布更新,同时避免程序阻塞。 - 性能优化:只保留最近的N根K线(比如你代码里的150根),避免数据量过大导致绘图卡顿。
3. 基于现有代码的改造示例
import pandas as pd import mplfinance as mpf import matplotlib.pyplot as plt import time import numpy as np from datetime import datetime, timedelta # 加载初始历史K线数据 df = pd.read_csv("XAUUSD15.csv", delimiter='\t', header=None) df.columns = ["Date", "Open", "High", "Low", "Close", "Volume"] df["Date"] = pd.to_datetime(df['Date'], format='%Y-%m-%d %H:%M') df.set_index('Date', inplace=True) last_candles = df.iloc[-150:].copy() # 初始化当前未闭合K线与下一个闭合时间 current_candle = None now = datetime.now() next_close_time = now.replace(minute=(now.minute // 15)*15 +15, second=0, microsecond=0) if next_close_time <= now: next_close_time += timedelta(minutes=15) # 初始化绘图样式与画布 style = "yahoo" fig, ax = plt.subplots(figsize=(8, 3.9)) ax.set_facecolor('#101010') fig.patch.set_facecolor('xkcd:black') ax.grid(True, color='black', linestyle='--', linewidth=0.5) ax.xaxis.set_visible(False) ax.tick_params(axis='y', colors='white') def fetch_gold_price(): # 替换为你的实际爬取逻辑,返回当前黄金价格(浮点数) # 以下为模拟价格波动示例 return round(last_candles['Close'].iloc[-1] + (np.random.rand()-0.5)*2, 2) while True: now = datetime.now() current_price = fetch_gold_price() # 初始化当前未闭合K线 if current_candle is None: current_candle = pd.DataFrame({ 'Open': [current_price], 'High': [current_price], 'Low': [current_price], 'Close': [current_price], 'Volume': [0] }, index=[last_candles.index[-1] + timedelta(minutes=15)]) # 更新当前K线的高低价与收盘价 current_candle['High'] = max(current_candle['High'].iloc[0], current_price) current_candle['Low'] = min(current_candle['Low'].iloc[0], current_price) current_candle['Close'] = current_price # 合并历史K线与当前K线用于显示 display_df = pd.concat([last_candles, current_candle]) # 清除旧图并重新绘制 ax.clear() mpf.plot(display_df, type='candle', style=style, volume=False, ax=ax, ylabel='', xrotation=0, datetime_format='%Y-%m-%d %H:%M') # 重置画布样式(clear会清除原有设置) ax.set_facecolor('#101010') ax.grid(True, color='black', linestyle='--', linewidth=0.5) ax.xaxis.set_visible(False) ax.tick_params(axis='y', colors='white') plt.tight_layout() plt.pause(0.1) # 到达时间节点时闭合当前K线 if now >= next_close_time: last_candles = pd.concat([last_candles, current_candle]) last_candles = last_candles.iloc[-150:] # 保留最近150根 current_candle = None # 计算下一个闭合时间 next_close_time = now.replace(minute=(now.minute //15)*15 +15, second=0, microsecond=0) if next_close_time <= now: next_close_time += timedelta(minutes=15) time.sleep(1) # 每秒刷新一次价格
4. 关键注意事项
- 反爬规避:免费爬取实时数据易触发网站反爬,建议添加浏览器请求头、设置合理请求间隔,避免IP被封禁。
- 时间同步:确保本地时间与数据来源时间一致,否则会导致K线闭合节点错误。
- 资源占用:长时间运行时定期清理冗余数据,若需后台运行可切换matplotlib的非交互式后端(如
Agg),但实时交互场景建议用默认后端。
内容的提问来源于stack exchange,提问作者Martin Ryan Lacis
相关产品推荐
相关产品推荐

