【问题标题】:how to plot ohlc candlestick with datetime in matplotlib?如何在 matplotlib 中绘制带有日期时间的 ohlc 烛台?
【发布时间】:2016-07-19 23:33:19
【问题描述】:

我需要每 5 分钟绘制一次交易数据(一根蜡烛)

这是我目前所拥有的:

from matplotlib.finance import candlestick2_ohlc
fig, ax = plt.subplots()
candlestick2_ohlc(ax,quotes['open'],quotes['high'],quotes['low'],quotes['close'],width=0.6)

它看起来像这样:

我需要改进它:

  1. 蓝色标记表示xticks 显示为int,我希望它们为datetime 格式。

  2. 红色标记显示状态栏中的 x 值。我也希望它是datetime 格式。

这是quotes的演示数据:

array([ (1459388100, 29.799999237060547, 29.799999237060547, 29.799999237060547, 29.799999237060547, 148929.0, 450030016.0),
   (1459388400, 29.799999237060547, 29.979999542236328, 29.709999084472656, 29.920000076293945, 10395.0, 31069984.0),
   (1459388700, 29.959999084472656, 30.18000030517578, 29.719999313354492, 30.149999618530273, 38522.0, 114999968.0),
   (1459389000, 30.170000076293945, 30.479999542236328, 30.0, 30.149999618530273, 29823.0, 90220032.0),
   (1459389300, 30.149999618530273, 30.75, 30.1299991607666, 30.549999237060547, 38903.0, 118620032.0),
   (1459389600, 30.59000015258789, 30.93000030517578, 30.559999465942383, 30.65999984741211, 42308.0, 130000000.0),
   (1459389900, 30.6200008392334, 30.690000534057617, 30.3799991607666, 30.3799991607666, 20209.0, 61689984.0),
   (1459390200, 30.3700008392334, 30.489999771118164, 30.18000030517578, 30.18000030517578, 18491.0, 56169984.0),
   (1459390500, 30.190000534057617, 30.329999923706055, 30.010000228881836, 30.010000228881836, 17641.0, 53200000.0),
   (1459390800, 30.030000686645508, 30.399999618530273, 30.030000686645508, 30.280000686645508, 9526.0, 28899968.0),
   (1459391100, 30.299999237060547, 30.31999969482422, 30.200000762939453, 30.209999084472656, 9282.0, 28100096.0),
   (1459391400, 30.190000534057617, 30.280000686645508, 30.049999237060547, 30.1200008392334, 8663.0, 26099968.0),
   (1459391700, 30.110000610351562, 30.110000610351562, 29.959999084472656, 30.100000381469727, 15677.0, 47099904.0),
   (1459392000, 30.1200008392334, 30.260000228881836, 30.0, 30.059999465942383, 5649.0, 17000064.0),
   (1459392300, 30.079999923706055, 30.299999237060547, 30.0, 30.280000686645508, 6057.0, 18199936.0),
   (1459392600, 30.290000915527344, 30.34000015258789, 30.1200008392334, 30.1200008392334, 7914.0, 24000000.0),
   (1459392900, 30.1299991607666, 30.15999984741211, 30.079999923706055, 30.139999389648438, 4521.0, 13600000.0),
   (1459393200, 30.139999389648438, 30.139999389648438, 29.829999923706055, 29.899999618530273, 16255.0, 48600064.0),
   (1459393500, 29.93000030517578, 30.1200008392334, 29.889999389648438, 30.1200008392334, 6877.0, 20600064.0),
   (1459393800, 30.1299991607666, 30.15999984741211, 29.979999542236328, 30.030000686645508, 3803.0, 11499904.0),
   (1459394100, 30.040000915527344, 30.1299991607666, 30.0, 30.030000686645508, 4421.0, 13300096.0),
   (1459394400, 29.989999771118164, 30.389999389648438, 29.989999771118164, 30.389999389648438, 7011.0, 21099904.0),
   (1459394700, 30.399999618530273, 30.450000762939453, 30.270000457763672, 30.299999237060547, 12095.0, 36800000.0),
   (1459395000, 30.34000015258789, 30.450000762939453, 30.280000686645508, 30.43000030517578, 9284.0, 28099968.0),
   (1459400700, 30.510000228881836, 30.729999542236328, 30.5, 30.600000381469727, 17139.0, 52500096.0),
   (1459401000, 30.600000381469727, 30.799999237060547, 30.530000686645508, 30.790000915527344, 11888.0, 36400000.0),
   (1459401300, 30.809999465942383, 31.100000381469727, 30.809999465942383, 31.049999237060547, 30692.0, 95099904.0),
   (1459401600, 31.06999969482422, 31.559999465942383, 30.93000030517578, 31.559999465942383, 24473.0, 76200064.0),
   (1459401900, 31.600000381469727, 31.860000610351562, 31.299999237060547, 31.450000762939453, 34497.0, 109200000.0),
   (1459402200, 31.43000030517578, 31.600000381469727, 31.18000030517578, 31.18000030517578, 18525.0, 58200064.0),
   (1459402500, 31.18000030517578, 31.350000381469727, 31.040000915527344, 31.18000030517578, 10153.0, 31599872.0),
   (1459402800, 31.200000762939453, 31.399999618530273, 31.010000228881836, 31.389999389648438, 9668.0, 30100096.0),
   (1459403100, 31.399999618530273, 31.399999618530273, 31.110000610351562, 31.360000610351562, 8445.0, 26499968.0),
   (1459403400, 31.360000610351562, 31.399999618530273, 31.040000915527344, 31.100000381469727, 9538.0, 29799936.0),
   (1459403700, 31.1200008392334, 31.399999618530273, 31.100000381469727, 31.270000457763672, 7996.0, 25000064.0),
   (1459404000, 31.270000457763672, 31.399999618530273, 31.15999984741211, 31.399999618530273, 6760.0, 21100032.0),
   (1459404300, 31.389999389648438, 32.400001525878906, 31.389999389648438, 32.189998626708984, 26108.0, 83700096.0),
   (1459404600, 32.209999084472656, 32.400001525878906, 31.860000610351562, 32.29999923706055, 15736.0, 50599936.0),
   (1459404900, 32.29999923706055, 32.310001373291016, 31.489999771118164, 31.489999771118164, 12945.0, 41399808.0),
   (1459405200, 31.5, 32.0, 31.40999984741211, 31.81999969482422, 11901.0, 37700096.0),
   (1459405500, 31.809999465942383, 31.940000534057617, 31.719999313354492, 31.770000457763672, 6503.0, 20700160.0),
   (1459405800, 31.760000228881836, 31.790000915527344, 31.399999618530273, 31.790000915527344, 10103.0, 31899904.0),
   (1459406100, 31.780000686645508, 32.029998779296875, 31.780000686645508, 31.850000381469727, 12033.0, 38500096.0),
   (1459406400, 31.809999465942383, 33.310001373291016, 31.809999465942383, 33.029998779296875, 58238.0, 192199936.0),
   (1459406700, 33.029998779296875, 33.310001373291016, 32.79999923706055, 32.79999923706055, 36689.0, 121900032.0),
   (1459407000, 32.79999923706055, 32.869998931884766, 32.61000061035156, 32.70000076293945, 15245.0, 49799936.0),
   (1459407300, 32.68000030517578, 32.689998626708984, 31.799999237060547, 32.0099983215332, 20507.0, 65999872.0),
   (1459407600, 32.02000045776367, 32.02000045776367, 31.760000228881836, 31.799999237060547, 29610.0, 94300160.0)], 
  dtype=[('time', '<i4'), ('open', '<f4'), ('high', '<f4'), ('low', '<f4'), ('close', '<f4'), ('volume', '<f4'), ('amount', '<f4')])

【问题讨论】:

    标签: python numpy matplotlib


    【解决方案1】:

    您应该先将数组中的日期戳转换为日期时间对象,然后使用date2num 进行转换。

    http://matplotlib.org/api/finance_api.html中指定

    matplotlib.finance.candlestick_ochl(ax, **quotes**, width=0.2, colorup='k', colordown='r', alpha=1.0)
    

    quotes:(时间、开盘、收盘、最高价、最低价……)序列的序列

    只要前 5 个元素是这些值,记录可以任意长(例如,它可以存储体积)。

    时间必须采用浮点天数格式 - 请参阅 date2num

    import datetime
    from matplotlib.dates import date2num
    
    a = your_array
    d = [date2num(datetime.datetime.fromtimestamp(x[0])) for x in a]
    

    【讨论】:

    • OP 使用的是candelstick_ohlc,而不是candlestick_ochl,它采用不同的选项(只是opens, highs, lows, closes
    • 你是对的,我看错了。但是他应该只使用烛台_ochl 并转换数组中的时间戳。
    • 我在问之前尝试了 candelstick_ohlc,它在 xaxis 上没有显示任何内容,我不知道为什么。无论如何,谢谢!
    • 你介意看看这篇相关的帖子吗?我不知道该怎么做。谢谢。 stackoverflow.com/q/48225888/2525479
    【解决方案2】:

    这是一些有效的代码。

    首先,我们使用datetime.datetime.fromtimestamp 将时间戳转换为日期时间对象。

    然后,我们使用ticker.MaxNLocator 设置刻度位置。

    然后我创建了一个函数来提供给ticker.FuncFormatter 以使用datetime 对象作为刻度标签,并使用刻度的整数值来索引我们之前创建的xdate 列表。

    try... except 子句在其中,以防您的 quotes 数组中的最终时间戳超出一个刻度,在这种情况下函数将失败。

    我还添加了autofmt_xdate() 来旋转刻度,并添加了tight_layout() 来为它们腾出空间

    from matplotlib.finance import candlestick2_ohlc
    import matplotlib.pyplot as plt
    import matplotlib.ticker as ticker
    import datetime as datetime
    import numpy as np
    
    quotes = np.array(...)
    
    fig, ax = plt.subplots()
    candlestick2_ohlc(ax,quotes['open'],quotes['high'],quotes['low'],quotes['close'],width=0.6)
    
    xdate = [datetime.datetime.fromtimestamp(i) for i in quotes['time']]
    
    ax.xaxis.set_major_locator(ticker.MaxNLocator(6))
    
    def mydate(x,pos):
        try:
            return xdate[int(x)]
        except IndexError:
            return ''
    
    ax.xaxis.set_major_formatter(ticker.FuncFormatter(mydate))
    
    fig.autofmt_xdate()
    fig.tight_layout()
    
    plt.show()
    

    【讨论】:

    • 我还是不明白。如果quotes只是一个数组,你怎么能做quotes['open']这个操作呢?我认为quotes 是一个数据框?
    • @StayFoolish 这是一个 numpy 结构化数组:docs.scipy.org/doc/numpy-1.13.0/user/basics.rec.html 请参阅粘贴在设置 dtype 的问题中的示例数组的最后一行。
    • 谢谢。现在我有另一个问题,如你所知,在股市中,如果我有以频率 = 1 分钟采样的烛台数据(OHLC)。交易时间例如 9:00 -15:00。关键是它不是 24 小时交易。如果我使用烛台_ohlc() 并传入一个 1 分钟柱形数据的数据框 2 天。这个函数假设时间之间的距离相等,所以它搞砸了。因此,我尝试使用烛台2_ohlc() 来解决。但是使用您的方法,我怎样才能在每 1 小时准确地添加一次主要标签,并且可能在每小时每小时准确地添加次要标签?
    • @StayFoolish 如果您要问一个新问题,最好在本网站上将其作为一个问题提出,因为这样您更有可能获得高质量的答案
    • @tmdavison,我认为值得一提的是 matplotlib.finance 已被弃用,其代码已提取到 mpl_finance 模块。
    【解决方案3】:

    在没有 matplotlib.finance 的情况下绘制 ohlc 蜡烛

    假设 prices 是一个数据框

    import pandas as pd
    import matplotlib.pyplot as plt
    
    plt.figure()
    width=1
    width2=0.1
    pricesup=prices[prices.close>=prices.open]
    pricesdown=prices[prices.close<prices.open]
    
    plt.bar(pricesup.index,pricesup.close-pricesup.open,width,bottom=pricesup.open,color='g')
    plt.bar(pricesup.index,pricesup.high-pricesup.close,width2,bottom=pricesup.close,color='g')
    plt.bar(pricesup.index,pricesup.low-pricesup.open,width2,bottom=pricesup.open,color='g')
    
    plt.bar(pricesdown.index,pricesdown.close-pricesdown.open,width,bottom=pricesdown.open,color='r')
    plt.bar(pricesdown.index,pricesdown.high-pricesdown.open,width2,bottom=pricesdown.open,color='r')
    plt.bar(pricesdown.index,pricesdown.low-pricesdown.close,width2, bottom=pricesdown.close,color='r')
    plt.grid()
    

    应根据不同的时间范围调整宽度

    【讨论】:

    • 预览会很好。
    • 当我们需要将烛台集成到现有的斧头时,这会更好。谢谢
    • 你能用从 stooq 收到的 DataFrame 对象编写这段代码吗?我已经尝试过,但它失败了`pricesup=self.dataSubset[self.dataSubset['Close']>=self.dataSubset['Open']]`,错误为TypeError: 'Series' objects are mutable, thus they cannot be hashed
    • 恕我直言,这个答案应该是 2021 年 1 月被接受的答案——有两个原因。首先,它使用简单的 matplotlib 方法来完全按照 OP 的要求进行操作。其次,它使用不被弃用的代码(与matplotlib.finance相反)并且它不使用其他库的自定义实现,即使它们可能很花哨,它们也需要时间来学习他们的API并且不容易与@987654325集成@ 这是不可避免的标准,无论其瓶颈如何。对不起,如果咸了,但我花了 2 小时的时间尝试得到一个与我的 plt.subplots 集成的简单 OHLC 图。
    • 现在我明白为什么不推荐使用 mpl_finance 了。这在 matplotlib 中并不难做到。我同意这应该是公认的答案。
    【解决方案4】:

    在这里,我想扩展 Daniele 在此页面上的代码,因为有些人想看看 DataFrame(价格)的样子。这是我的看法(顺便感谢 Daniele 的这个好主意)。

    listTimestamp = list(<timestamp data>)
    listOpen = list(<Open data>)
    listHigh = list(<High data>)
    listLow = list(<Low data>)
    listClose = list(<Close data>)
    
    dictdata = {'Timestamp':listTimestamp,'Open':listOpen,
              'High':listHigh,'Low':listLow,'Close':listClose}
    prices = pd.DataFrame(dictdata,columns=['Timestamp','Open','High','Low','Close'])
    
    width=0.9
    width2=0.1
    pricesup=prices[prices.Close>=prices.Open]
    pricesdown=prices[prices.Close<prices.Open]
    plt.bar(pricesup.index,pricesup.Close-pricesup.Open,width,bottom=pricesup.Open,color='g')
    plt.bar(pricesup.index,pricesup.High-pricesup.Close,width2,bottom=pricesup.Close,color='g')
    plt.bar(pricesup.index,pricesup.Low-pricesup.Open,width2,bottom=pricesup.Open,color='g')
    plt.bar(pricesdown.index,pricesdown.Close-pricesdown.Open,width,bottom=pricesdown.Open,color='r')
    plt.bar(pricesdown.index,pricesdown.High-pricesdown.Open,width2,bottom=pricesdown.Open,color='r')
    plt.bar(pricesdown.index,pricesdown.Low-pricesdown.Close,width2, bottom=pricesdown.Close,color='r')
    plt.grid()
    plt.show()
    

    【讨论】:

      【解决方案5】:

      我推荐使用finplot,它会自动处理日期。

      import finplot as fplt
      import pandas as pd
      
      a = [[1459388100, 29.799999237060547, 29.799999237060547, 29.799999237060547, 29.799999237060547, 148929.0, 450030016.0],
           [1459388400, 29.799999237060547, 29.979999542236328, 29.709999084472656, 29.920000076293945, 10395.0, 31069984.0],
           [1459388700, 29.959999084472656, 30.18000030517578, 29.719999313354492, 30.149999618530273, 38522.0, 114999968.0],
           [1459389000, 30.170000076293945, 30.479999542236328, 30.0, 30.149999618530273, 29823.0, 90220032.0]]
           # add some more data...
      df = pd.DataFrame(a, columns='time open high low close volume amount'.split())
      fplt.candlestick_ochl(df[['time','open','close','high','low']])
      fplt.show()
      

      免责声明:我写 finplot 是因为我不喜欢 matplotlib 和 plotly 的 API、性能和缺乏功能。

      【讨论】:

      • 这太酷了。我只是尝试了一个示例代码,从它的外观来看,我可以说它比 plotly 和 matplotlib 好得多。
      • @Rahib 谢谢伙计,我也喜欢!如果您在致富过程中发现任何错误,请在 github 上告诉我。 :D
      • 我在处理微小的数据时遇到了困难 - 事实证明,使用 df.reset_index(drop=True) 让它工作。希望这可以帮助某人。
      • 如果您只有 OHLC,每个人都会遇到索引错误 - 添加第五列 - 时间(可能只是索引)
      • 如果我的时间戳格式是'timestamp': '2021-10-03T23:59:59.999Z'呢?如果 lib 检测到这一点并进行转换,那就太好了。 arrow 非常适合时间操作。
      【解决方案6】:

      我不想使用任何外部库,并且发现这里的其他答案非常复杂。这是我的代码:

      def candlestick(t, o, h, l, c):
          plt.figure(figsize=(12,4))
          color = ["green" if close_price > open_price else "red" for close_price, open_price in zip(c, o)]
          plt.bar(x=t, height=np.abs(o-c), bottom=np.min((o,c), axis=0), width=0.6, color=color)
          plt.bar(x=t, height=h-l, bottom=l, width=0.1, color=color)
      
      candlestick(
          df["2020-02":"2020-04"].index,
          df["2020-02":"2020-04"]["Open"],
          df["2020-02":"2020-04"]["High"],
          df["2020-02":"2020-04"]["Low"],
          df["2020-02":"2020-04"]["Close"]
      )
      
      plt.grid(alpha=0.2)
      plt.show()
      

      我将它与如下所示的 pandas 数据框一起使用:

                       Open       High        Low      Close
      Date                                                  
      2020-02-03  76.074997  78.372498  75.555000  77.165001
      2020-02-04  78.827499  79.910004  78.407501  79.712502
      2020-02-05  80.879997  81.190002  79.737503  80.362503
      2020-02-06  80.642502  81.305000  80.065002  81.302498
      2020-02-07  80.592499  80.849998  79.500000  80.007243
      

      结果如下所示:

      注意有时条形的宽度会很奇怪,因此细条形可能不可见。这是通过改变图形的dpi来解决的:https://stackoverflow.com/a/62856898/9439097

      作为确认,这里是https://www.tradingview.com 显示同一时期的方式。

      【讨论】:

      • 您知道我们如何将它与日期/时间一起使用,而不是仅使用日期吗?
      • 如果您的时间间隔是datetime 类型的常规空间时间步长,它不会按原样工作吗?如果不是,您遇到的问题是什么?
      • 我设法解决了这个问题,至少可以满足我的需要。我的解决方案涉及对 x 轴使用索引整数数组 (df.index.get_loc(idx))。无论如何,谢谢。
      【解决方案7】:

      新的matplotlib财务模块非常好用(link) 它也可以处理没有谈判的日子

      您只需要一个带有 [high,low,open,close,volume] 列的 pandas 数据框,其中包含刻度时间戳作为索引和 2 行代码:

      import mplfinance as mpf
      mpf.plot(daily,type='candle',mav=(3,6,9),volume=True)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-02
        • 2021-12-29
        • 2020-10-04
        • 1970-01-01
        • 2019-08-14
        • 2019-05-14
        相关资源
        最近更新 更多