matplotlib.finance.candlestick_ohlc отображает внутридневные 1-минутные данные бара с временными перерывами и правильными xticklabels каждый час

Проблема в:

Я хочу построить внутридневные 1-минутные бары OHLC одной акции. Ежедневный торговый час состоит из нескольких сегментов торговых периодов. Который указан ниже:

Дата сделки: 2017/09/14

Включенный торговый час: 13.09.2017 21:00 - 23:00, 14.09.2017 9:00 - 10:15, 10:30 - 11:30, 13:30 - 15:00.

Как видите, если я просто использую candlestick_ohlc напрямую, будут пробелы.

Теперь, если я получу 1-минутные данные в виде кадра данных. Как построить свечной график без промежутков между любыми барами (например, без промежутков между 10:15 и 10:30 барами) и чтобы метки xticklabels отображали только основные тики каждый час, например, 22:00, 23: 00, 10:00 и небольшие тики каждые 15 минут, например, 21:15, 21:30, 21:45 и т. д.

Вот изображение того, как выглядит мой фрейм данных за 1 торговый день: введите здесь описание изображения

Вы можете сгенерировать некоторые псевдоданные с похожей формой здесь:

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

Я видел в модуле matplotlib.finance, там есть candlestic2_ohlc и candlestick_ohlc. Моим первым испытанием было использование candlestick2_ohlc, так как он не требует числового аргумента datetime, который мог бы испортить такты с большим количеством пробелов. У меня нет пробелов, но я не могу сделать xticklabels такими, какими хочу, потому что я не знаю, как теперь передать информацию о datetimeIndex в xticklabels.

Вот что я попробовал сначала: в основном узнал из этого поста: как построить свечу ohlc с датой и временем в matplotlib?

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()
figManager = plt.get_current_fig_manager()
figManager.window.showMaximized()

candlestick2_ohlc(ax, bar_df.open, bar_df.high, bar_df.low, bar_df.close,
                  width=0.6, colorup='r', colordown='c', alpha=1)
xdate = bar_df.index
def mydate(x, pos):
    try:
        return xdate[int(x)]
    except IndexError:
        return ''

ax.xaxis.set_major_formatter(ticker.FuncFormatter(mydate))
# Everything works fine up to now.
# However the xticklabels are not exactly at 22:00, 23:00, etc.
# And no minor tick labels set up at 21:15, 21:30, 21:45, etc.

# I tried either one of the command below, but both failed with no xticklabels
# showed up.

ax.xaxis.set_major_locator(mdates.HourLocator())
ax.xaxis.set_major_locator(mdates.MinuteLocator(byminute=[0, 15, 30, 45],
                                                interval=1))

# This one works because it only tells xticklabels to have at most
# 8 tick labels, but no info about where the xticklabels should be.
ax.xaxis.set_major_locator(ticker.MaxNLocator(8))

Результат подсвечника_ohlc

Пожалуйста помоги.


person StayFoolish    schedule 12.01.2018    source источник
comment
На самом деле вы не наносите даты на оси. Однако для того, чтобы использовать любой из локаторов и средств форматирования дат, вам потребуется отобразить объекты даты и времени или числа, соответствующие дате и времени, на осях.   -  person ImportanceOfBeingErnest    schedule 13.01.2018


Ответы (1)


В настоящее время вы строите данные по его индексу. Однако, если вы хотите использовать matplotlib.dates локаторы и средства форматирования, вам нужно будет нанести даты на оси. Это невозможно при использовании candlestick2_ohlc. Вместо этого вам нужно будет использовать функцию candlestick_ohlc. На самом деле это также сказано в этом ответе на вопрос, на который вы ссылаетесь. Однако использование фактических дат не позволяет объединять сегменты, за исключением возможного построения графиков в разных подграфиках, см. ☼пример сломанных топоров.

Таким образом, решение здесь может заключаться в том, чтобы остаться с построением индекса и установкой отметок в местах, которые соответствуют желаемым меткам отметок.

xdate = bar_df.index
def mydate(x, pos):
    try:
        return xdate[int(x)]
    except IndexError:
        return ''
# create date ranges of possible dates to show as major and minor ticklabels
major_dr = pd.date_range('2017-09-13 21:00:00','2017-09-14 15:00:00', freq='60min')
minor_dr = pd.date_range('2017-09-13 21:00:00','2017-09-14 15:00:00', freq='15min')
# calculate positions of the above dates inside the dataframe index
major_ticks = np.isin(xdate, major_dr).nonzero()[0] 
minor_ticks = np.isin(xdate, minor_dr).nonzero()[0]
# use those positions to put ticks at
ax.xaxis.set_major_locator(ticker.FixedLocator(major_ticks))
ax.xaxis.set_minor_locator(ticker.FixedLocator(minor_ticks))
ax.minorticks_on()
ax.xaxis.set_major_formatter(ticker.FuncFormatter(mydate))
fig.autofmt_xdate()

Результат будет выглядеть так

введите здесь описание изображения

Это читается очень запутанно, но, насколько я понимаю, это то, о чем просит вопрос.

person ImportanceOfBeingErnest    schedule 13.01.2018
comment
Спасибо, я немного изменил функцию mydate, чтобы она отображала только часы и минуты, например 22:00, и попытался применить функцию mydate к minor_formatter. Но будут перекрытия в основных тиках и второстепенных тиках. Поэтому я думаю, что мне нужно снова использовать функцию np.in1d(), чтобы удалить перекрытия, верно? - person StayFoolish; 14.01.2018
comment
Да, второстепенные локаторы не учитывают главные локаторы при определении местоположений — они на самом деле полностью независимы. Так что это общая проблема не только для FixedLocators. Здесь решение действительно состояло бы в том, чтобы проверить наличие индекса в списке major_ticks и удалить этот индекс из minor_ticks или наоборот. - person ImportanceOfBeingErnest; 14.01.2018