You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用matplotlib.finance绘制无间隙日内1分钟OHLC K线并设置自定义刻度

解决跨时段股票K线无间隙+自定义X轴刻度的问题

我刚碰到过类似的期货跨交易日K线绘制需求,你的核心痛点在于candlestick2_ohlc是基于序列索引(0,1,2...)来绘制K线的,不是真实的时间轴,所以直接用mdates的定位器完全不生效——它只认matplotlib的日期数值,不认我们的序列位置。

下面是完整的解决方案,既能保留无间隙的K线,又能实现你要的整点主刻度、15分钟次刻度:

def generate_pseudo_data():
    # datetime index data
    idx = pd.date_range('2017-09-13 21:01:00', '2017-09-13 23:00:00', freq='1min')
    idx = idx.append(pd.date_range('2017-09-14 09:01:00', '2017-09-14 10:15:00', freq='1min'))
    idx = idx.append(pd.date_range('2017-09-14 10:31:00', '2017-09-14 11:30:00', freq='1min'))
    idx = idx.append(pd.date_range('2017-09-14 13:31:00', '2017-09-14 15:00:00', freq='1min'))
    # OHLC
    inc = np.random.randint(-2, 3, size=idx.shape).cumsum()
    opens = 3500 + inc
    closes = opens + np.random.randint(-3, 3, idx.shape)
    range_max = np.max(np.concatenate([opens.reshape(-1, 1), closes.reshape(-1, 1)], axis=1), axis=1)
    highs = range_max + np.random.randint(0, 5, size=idx.shape)
    range_min = np.min(np.concatenate([opens.reshape(-1, 1), closes.reshape(-1, 1)], axis=1), axis=1)
    lows = range_min - np.random.randint(0, 5, size=idx.shape)
    bar_df = pd.DataFrame({'open': opens, 'high': highs, 'low': lows, 'close': closes}, index=idx)
    return bar_df

from datetime import datetime, time
import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.finance import candlestick2_ohlc, candlestick_ohlc
import matplotlib.dates as mdates
from matplotlib import ticker

bar_df = generate_pseudo_data()
fig, ax = plt.subplots(figsize=(12,6))
figManager = plt.get_current_fig_manager()
figManager.window.showMaximized()

# 绘制无间隙K线
candlestick2_ohlc(ax, bar_df.open, bar_df.high, bar_df.low, bar_df.close, 
                  width=0.6, colorup='r', colordown='c', alpha=1)

# -------------------------- 核心:自定义刻度配置 --------------------------
# 1. 准备所有K线的时间序列和对应的序列索引
x_dates = bar_df.index
x_indices = np.arange(len(x_dates))

# 2. 筛选主刻度位置:整点的K线对应的索引
major_positions = x_indices[x_dates.minute == 0]
# 3. 筛选次刻度位置:每15分钟的K线对应的索引(0/15/30/45分)
minor_positions = x_indices[x_dates.minute.isin([0,15,30,45])]

# 4. 定义主刻度定位器:返回整点的索引位置
def major_locator_func(value, pos):
    # 只返回在major_positions里的位置
    if value in major_positions:
        return value
    return None
ax.xaxis.set_major_locator(ticker.FuncLocator(major_locator_func))

# 5. 定义次刻度定位器:返回15分钟间隔的索引位置
def minor_locator_func(value, pos):
    if value in minor_positions:
        return value
    return None
ax.xaxis.set_minor_locator(ticker.FuncLocator(minor_locator_func))

# 6. 定义刻度格式化器:把索引转成时间字符串(比如22:00、09:15)
def date_formatter(value, pos):
    try:
        return x_dates[int(value)].strftime('%H:%M')
    except IndexError:
        return ''
ax.xaxis.set_major_formatter(ticker.FuncFormatter(date_formatter))
ax.xaxis.set_minor_formatter(ticker.FuncFormatter(date_formatter))

# 7. 美化:旋转主刻度标签,避免重叠,调整次刻度字体大小
plt.xticks(rotation=45)
ax.tick_params(axis='x', which='minor', labelsize=8, color='#999999')

# 调整布局,防止标签被截断
plt.tight_layout()
plt.show()

关键部分解释:

  • 因为candlestick2_ohlc的X轴是序列索引(0到N-1),所以我们必须基于这些索引来定位刻度,而不是真实的时间戳
  • 先筛选出符合条件的时间点对应的索引位置,再用FuncLocator告诉matplotlib这些位置要显示刻度
  • 次刻度用更小的字体和灰色区分,让图表层次更清晰
  • 最后用tight_layout()防止X轴标签被截断

这样就能完美实现你要的效果:K线完全无间隙,X轴主刻度显示整点,次刻度显示每15分钟的时间点。

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

火山引擎 最新活动