You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带布林带的K线图无法渲染:MWE运行报错求助

带布林带的K线图绘制报错:过多刻度问题

我写了一个最小可复现示例(MWE)用来绘制带布林带的SPY标的K线图,但无法正常运行,控制台只提示“过多刻度(too many ticks)”。我用的是2017年4月23日至7月1日共3个月的数据,实在搞不懂问题出在哪。以下是我的代码:

import yfinance as yf
from stockstats import StockDataFrame

# Convert to StockDataFrame
# Need to pass a copy of candlestick_data to StockDataFrame.retype
# Otherwise the original candlestick_data will be modified

df = yf.download('SPY',start='2017-04-23', end = '2017-07-01')
stockstats = StockDataFrame.retype(df)

# 5-day exponential moving average on closing price
ema_5 = stockstats["close_5_ema"]
# 20-day exponential moving average on closing price
ema_20 = stockstats["close_20_ema"]
# 50-day exponential moving average on closing price
ema_50 = stockstats["close_50_ema"]

# Upper Bollinger band
boll_ub = stockstats["boll_ub"]
# Lower Bollinger band
boll_lb = stockstats["boll_lb"]

# 7-day Relative Strength Index
rsi_7 = stockstats['rsi_7']
# 14-day Relative Strength Index
rsi_14 = stockstats['rsi_14']


import datetime
import matplotlib.pyplot as plt
from matplotlib.dates import date2num, WeekdayLocator, DayLocator, DateFormatter, MONDAY
from mplfinance.original_flavor import candlestick_ohlc

# Create a new Matplotlib figure
fig, ax = plt.subplots()

# Prepare a candlestick plot
candlestick_ohlc(ax, df.values, width=0.6)

# Plot stock indicators in the same plot
ax.plot(df.index, ema_5, lw=1, label='EMA (5)')
ax.plot(df.index, ema_20, lw=1, label='EMA (20)')
ax.plot(df.index, ema_50, lw=1, label='EMA (50)')
ax.plot(df.index, boll_ub, lw=2, linestyle="--", label='Bollinger upper')
ax.plot(df.index, boll_lb, lw=2, linestyle="--", label='Bollinger lower')
ax.xaxis.set_major_locator(WeekdayLocator(MONDAY)) # major ticks on

# the mondays
ax.xaxis.set_minor_locator(DayLocator()) # minor ticks on the days
ax.xaxis.set_major_formatter(DateFormatter('%Y-%m-%d'))
ax.xaxis_date() # treat the x data as dates

# rotate all ticks to vertical
plt.setp(ax.get_xticklabels(), rotation=90, horizontalalignment='right')
ax.set_ylabel('Price (US $)') # Set y-axis label

# Limit the x-axis range from 2017-4-23 to 2017-7-1
datemin = datetime.date(2017, 4, 23)
datemax = datetime.date(2017, 7, 1)
ax.set_xlim(datemin, datemax)

plt.legend() # Show figure legend
plt.tight_layout()
plt.show()

问题根源与修复方案

核心问题

  1. candlestick_ohlc的格式要求:该函数需要输入的OHLC数据第一列是数值型日期(经date2num转换),但你直接传入df.values,其中日期是datetime格式,导致matplotlib无法正确解析x轴刻度,引发“过多刻度”警告。
  2. 冗余刻度设置:同时启用WeekdayLocator和DayLocator会生成大量重叠刻度,加剧了刻度拥挤问题。

修改后的代码

import yfinance as yf
from stockstats import StockDataFrame
import datetime
import matplotlib.pyplot as plt
from matplotlib.dates import date2num, WeekdayLocator, DateFormatter, MONDAY
from mplfinance.original_flavor import candlestick_ohlc

# 下载数据并转换为StockDataFrame(传入副本避免修改原数据)
df = yf.download('SPY', start='2017-04-23', end='2017-07-01')
stockstats = StockDataFrame.retype(df.copy())

# 计算指标
ema_5 = stockstats["close_5_ema"]
ema_20 = stockstats["close_20_ema"]
ema_50 = stockstats["close_50_ema"]
boll_ub = stockstats["boll_ub"]
boll_lb = stockstats["boll_lb"]

# 转换K线数据格式:将日期转为matplotlib兼容的数值型
ohlc_data = df.reset_index()[['Date', 'Open', 'High', 'Low', 'Close']].values
ohlc_data[:, 0] = date2num(ohlc_data[:, 0])

# 创建画布
fig, ax = plt.subplots(figsize=(12, 6))

# 绘制K线图
candlestick_ohlc(ax, ohlc_data, width=0.6, colorup='g', colordown='r')

# 绘制指标
ax.plot(df.index, ema_5, lw=1, label='EMA (5)')
ax.plot(df.index, ema_20, lw=1, label='EMA (20)')
ax.plot(df.index, ema_50, lw=1, label='EMA (50)')
ax.plot(df.index, boll_ub, lw=2, linestyle="--", label='布林带上轨')
ax.plot(df.index, boll_lb, lw=2, linestyle="--", label='布林带下轨')

# 设置x轴刻度:仅保留周一主刻度,避免拥挤
ax.xaxis.set_major_locator(WeekdayLocator(MONDAY))
ax.xaxis.set_major_formatter(DateFormatter('%Y-%m-%d'))
ax.xaxis_date()

# 调整刻度标签角度,减少重叠
plt.setp(ax.get_xticklabels(), rotation=45, horizontalalignment='right')
ax.set_ylabel('价格(美元)')

# 设置x轴范围
datemin = datetime.date(2017, 4, 23)
datemax = datetime.date(2017, 7, 1)
ax.set_xlim(datemin, datemax)

plt.legend()
plt.tight_layout()
plt.show()

关键修改点

  • 用date2num将日期转换为数值型,满足candlestick_ohlc的格式要求
  • 移除DayLocator()小刻度,避免x轴刻度过多重叠
  • 传入df.copy()给StockDataFrame.retype,符合你注释中“不修改原数据”的要求
  • 将刻度标签旋转角度改为45度,比90度更美观且可读性更强

内容的提问来源于stack exchange,提问作者Vincent ISOZ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 14:39:14