highfestiva / finplot

Performant and effortless finance plotting for Python
MIT License
935 stars 187 forks source link

One Subchart, two times Candlesticks: zoom out, zoom in: daily candlesticks have disappeared #85

Closed haimivan closed 3 years ago

haimivan commented 3 years ago

Hi,

based on example-overlay-correlate.py I multiplied the amount of data in the plot.

If I zoom out and zoom in again, the daily candles are gone.

Please find below the referring GIF and the code.

Thanks also here for looking at the topic! :-)

output

code

#!/usr/bin/env python3

from datetime import date, timedelta
import finplot as fplt
import pandas as pd
import scipy.optimize
import yfinance as yf

fplt.long_time = 200 * 365 * 24 * 60 * 60 * 1e9

now = date.today()
start_day = now - timedelta(days=58)
df = yf.download('GOOG', start_day.isoformat(), now.isoformat(), interval='90m')
dfms = yf.download('MSFT', start_day.isoformat(), now.isoformat(), interval='90m')

df.reset_index(drop=True,inplace=True)

# amountOfDfDuplication = 6
amountOfDfDuplication = 13

for runner in range(amountOfDfDuplication):
    df = df.append(df)
df.reset_index(inplace=True, drop=True)

periods = df.shape[0]
datelist = pd.date_range(pd.to_datetime('1970-01-01'), periods=periods, freq="90min").tolist()
datelist[-1]
df['date']=datelist
df.set_index('date',inplace=True)

dfd = df.Open.resample('D').first().to_frame()
dfd['Close'] = df.Close.resample('D').last()
dfd['High'] = df.High.resample('D').max()
dfd['Low'] = df.Low.resample('D').min()

ax = fplt.create_plot('Alphabet Inc.', rows=1, maximize=True)

# plot down-sampled daily candles first
daily_plot = fplt.candlestick_ochl(dfd.dropna(), candle_width=5)
daily_plot.colors.update(dict(bull_body='#bfb', bull_shadow='#ada', bear_body='#fbc', bear_shadow='#dab'))
daily_plot.x_offset = 3.1  # resample() gets us start of day, offset +1.1 (gap+off center wick)

# plot high resolution on top
fplt.candlestick_ochl(df[['Open', 'Close', 'High', 'Low']])

fplt.autoviewrestore(True)
fplt.show()

Alphabet Inc..ini (after executing the animation)

min_x = 167740200000000000
max_x = 168129000000000000
highfestiva commented 3 years ago

Fixed in https://github.com/highfestiva/finplot/commit/04dfeff634bebe94be98ea678529b070ca43fa95.

haimivan commented 3 years ago

Thanks a lot for the fast fix, that looks very good.

I have an additional question:

Can I somehow configure the point when the daily candles start to appear again?

For me personally, they could show up already earlier (so that I am able to see them already when the zoom level is very coarse).

Thanks in advance!

highfestiva commented 3 years ago

Good call, fixed it in https://github.com/highfestiva/finplot/commit/393bd2ada407490c2480a1d3c502e3e75e9ab795. If that's not enough you could set fplt.lod_candles to a high value. It defaults to ~3k.

haimivan commented 3 years ago

Very nice! Thanks!

I found a little bit of room for improvements, that I would like to share with you.

Somehow, if I introduce another daily candlestick (yellow and blue), for the second one your fix does not yet seem to work... :

code:

#!/usr/bin/env python3

from datetime import date, timedelta
import finplot2 as fplt
import pandas as pd
import scipy.optimize
import yfinance as yf

fplt.long_time = 200 * 365 * 24 * 60 * 60 * 1e9
# fplt.long_time = 1/200 * 365 * 24 * 60 * 60 * 1e9
fplt.max_zoom_points = 1

now = date.today()
start_day = now - timedelta(days=58)
df = yf.download('GOOG', start_day.isoformat(), now.isoformat(), interval='90m')
dfms = yf.download('MSFT', start_day.isoformat(), now.isoformat(), interval='90m')

df.reset_index(drop=True, inplace=True)

# amountOfDfDuplication = 6
amountOfDfDuplication = 13

for runner in range(amountOfDfDuplication):
    df = df.append(df)
df.reset_index(inplace=True, drop=True)

periods = df.shape[0]
datelist = pd.date_range(pd.to_datetime('1970-01-01'), periods=periods, freq="90min").tolist()
datelist[-1]
df['date'] = datelist
df.set_index('date', inplace=True)

dfd = df.Open.resample('D').first().to_frame()
dfd['Close'] = df.Close.resample('D').last()
dfd['High'] = df.High.resample('D').max()
dfd['Low'] = df.Low.resample('D').min()

ax = fplt.create_plot('Alphabet Inc.', rows=1, maximize=True)

# plot down-sampled daily candles first
daily_plot = fplt.candlestick_ochl(dfd.dropna(), candle_width=5)
daily_plot.colors.update(dict(bull_body='#bfb', bull_shadow='#ada', bear_body='#fbc', bear_shadow='#dab'))
daily_plot.x_offset = 3.1  # resample() gets us start of day, offset +1.1 (gap+off center wick)

daily_plot2 = fplt.candlestick_ochl(dfd.dropna(), candle_width=3)
daily_plot2.colors.update(dict(bull_body='#1f77b4', bull_shadow='#1f77b4', bear_body='#ffcc00', bear_shadow='#ffcc00'))
daily_plot2.x_offset = 2.1  # resample() gets us start of day, offset +1.1 (gap+off center wick)

# plot high resolution on top
fplt.candlestick_ochl(df[['Open', 'Close', 'High', 'Low']])

fplt.autoviewrestore(True)
fplt.show()
highfestiva commented 3 years ago

A temporary and ugly solution is to set daily_plot2.datasrc.is_sparse = True, I'll think about how I can improve the internals of my data sources.

haimivan commented 3 years ago

Thanks a lot. This helps for me already!

You can close the issue or leave it open. Just how it is better for you!

highfestiva commented 3 years ago

I've problems stemming from the same root cause once before. As long as the problem can be circumvented, I'll postpone rewriting the core internals, as rewriting takes a lot, but gains so little.