Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Event Handling with mplfinance #83

Open
croganm opened this issue Apr 8, 2020 · 12 comments
Open

Event Handling with mplfinance #83

croganm opened this issue Apr 8, 2020 · 12 comments
Labels
question Further information is requested

Comments

@croganm
Copy link

croganm commented Apr 8, 2020

Hey Daniel, love what you're doing with this package, it's absolutely fantastic.

I'm a pretty novice coder so excuse any code that might be unpreferred but I recently had an idea for a "point and click" technical indicator and wanted to try it out. The only issue is that I have absolutely no idea how to use event handling with the new mplfinance package.

I made a makeshift version using the old mpl_finance package. Attached is it (I'm using Alphavantage for intraday data, not sure I want to post my apikey here so I'll post everything but that):

import requests_html
import yahoo_fin.stock_info as yf
import pandas as pd
import numpy as np
import mpl_finance as mpf
import json
import requests
import datetime
import matplotlib as mpl
from mplfinance.original_flavor import candlestick_ohlc


ticker='SPY'
interval='60min'
apikey=''

r = requests.get("https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol={}&interval={}&outputsize=full&apikey={}".format(ticker,interval, apikey))
df = pd.DataFrame.from_dict(r.json()['Time Series ({})'.format(interval)]).T
df.columns=['Open','High','Low','Close','Volume']
df.index = pd.to_datetime(df.index)
df.sort_index(ascending=True, inplace=True)
df = df.apply(pd.to_numeric)

inital_data = df
inital_data.columns = map(str.title, inital_data.columns)


fig, ax = plt.subplots(figsize=(15,15))


candlestick_ohlc(ax, zip(mpl.dates.date2num(inital_data.index), inital_data['Open'], inital_data['High'], inital_data['Low'], inital_data['Close']))  


def onclick(event):
    date = mpl.dates.num2date(event.xdata)
    # print(datetime.datetime.strftime(date,"%Y-%m-%d %H:%M"))
    data = inital_data.loc[date:,:]
    vwap = []


    for x in range(len(data['Close'])):
        vwap.append(np.sum((data['Close'][0:(x+1)]*data['Volume'][0:(x+1)]))/np.sum(data['Volume'][0:(x+1)]))

    data[date] = vwap
    inital_data[date]=data[date]

    ax.plot(inital_data.index,inital_data[date])

    inital_data.drop(date, axis=1, inplace=True)
    event.canvas.draw()
    print(data.index[0])

cid = fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()

The point and click functionality works incredible, exactly what I wanted, but it is so ugly. I made a non-point and click version using the new mplfinance and it looks beautiful but I want the point and click functionality for that.

Here's the ugly looking one:
https://imgur.com/a/VPa0SlH

Here's the beautiful looking one:
https://imgur.com/a/6s5gQSu

Any help in getting the event handling for the new package would be much appreciated.

@croganm croganm added the question Further information is requested label Apr 8, 2020
@croganm
Copy link
Author

croganm commented Apr 8, 2020

For some reason, I updated Anaconda and the script above stopped working. I updated the script to work again, feel free to use whichever one works on your end:

import requests_html
import yahoo_fin.stock_info as yf
import pandas as pd
import numpy as np
import json
import requests
import datetime
import matplotlib as mpl
import matplotlib.pyplot as plt
from mplfinance.original_flavor import candlestick_ohlc


ticker='SPY'
interval='60min'
apikey=''

r = requests.get("https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol={}&interval={}&outputsize=full&apikey={}".format(ticker,interval, apikey))
df = pd.DataFrame.from_dict(r.json()['Time Series ({})'.format(interval)]).T
df.columns=['Open','High','Low','Close','Volume']
df.index = pd.to_datetime(df.index)
df.sort_index(ascending=True, inplace=True)
df = df.apply(pd.to_numeric)

df.columns = map(str.title, df.columns)



fig, ax = plt.subplots(figsize=(15,15))


candlestick_ohlc(ax, zip(mpl.dates.date2num(df.index), df['Open'], df['High'], df['Low'], df['Close']))  

def onclick(event):
    if event.dblclick:
        date = mpl.dates.num2date(event.xdata)
        date = datetime.datetime.strftime(date,"%Y-%m-%d %H:%M")
        data = df.loc[date:,:]
        vwap = []

        
        for x in range(len(data['Close'])):
            vwap.append(np.sum((data['Close'][0:(x+1)]*data['Volume'][0:(x+1)]))/np.sum(data['Volume'][0:(x+1)]))

        data[date] = vwap
        new_df = pd.concat([df, data[date]], axis=1, sort=False)

        ax.plot(new_df[date])
        
        event.canvas.draw()
        print(data.index[0])

cid = fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()

@DanielGoldfarb
Copy link
Collaborator

Thanks. It will probably be a week or two before i have time to look into this, but i am definitely interested. Thank you for getting involved.

@croganm
Copy link
Author

croganm commented Apr 9, 2020

Thank you, Daniel!

I figure some sort of reload function or write function could handle this, I'm just not there skill-wise yet.

@brbatv
Copy link

brbatv commented Apr 28, 2020

Hello

i'm also struggling to use this package with event handling
which figure can I use to do these types of command :
fig.canvas.mpl_connect("scroll_event", zoom_fun) ?
Is there any workaround to adapt previous work from more general matplotlib event handling ?
OP, as i've understand, you had to use the previous API to do it right ?

I would like to add this scroll event handler to have a Tradingview feeling of the charts :

base_scale=1.5
def zoom_fun(event):
    """ ref : https://stackoverflow.com/questions/11551049/matplotlib-plot-zooming-with-scroll-wheel"""
    cur_xlim = ax.get_xlim()
    cur_ylim = ax.get_ylim()
    xdata = event.xdata
    ydata = event.ydata 
    if event.button == 'down':
        scale_factor = 1 / base_scale
    elif event.button == 'up':
        scale_factor = base_scale
    else:
        scale_factor = 1
        print(event.button)
    ax.set_xlim([xdata - (xdata - cur_xlim[0]) / scale_factor, xdata + (cur_xlim[1] - xdata) / scale_factor])
    ax.set_ylim([ydata - (ydata - cur_ylim[0]) / scale_factor, ydata + (cur_ylim[1] - ydata) / scale_factor])
    plt.draw()  

as well as other handlers
thank you for your help:)

@croganm
Copy link
Author

croganm commented Apr 28, 2020

Hello

i'm also struggling to use this package with event handling
which figure can I use to do these types of command :
fig.canvas.mpl_connect("scroll_event", my_scroll_function) ?
Is there any workaround to adapt previous work from more general matplotlib event handling ?
OP, as i've understand, you had to use the previous API to do it right ?
thank you :)

That is correct, the old matplotlib finance API worked well for this. I went into the new mplfinance.plotting file and it was easy enough to set up event handling, but I am having a difficult time setting up canvas redrawing

@DanielGoldfarb
Copy link
Collaborator

I expect next week to begin work on the enhancement to allow you to pass in your own Figure and Axes, which should make implementation of event handling much easier. I estimate 3 to 6 weeks to complete that enhancement (depending what other distractions or issues come up in the meantime).

@tacaswell
Copy link
Member

Please ping me if you need any help with the event system.

@brbatv
Copy link

brbatv commented Jun 18, 2020

any news ? thanks

@DanielGoldfarb
Copy link
Collaborator

Regarding direct support for event handling through mplfinance, I do not expect to code for this anytime in the next several months; it's hard to say if and when it will become a priority for me given a number of other projects on my plate at this time.

That said, the enhancement mentioned here to allow a caller to pass in their own Figure and Axes, while delayed, I do expect to do, and I am hoping to get it done approximately near the end of July (as noted here) .

Please correct me if I'm wrong but, based on my limited understanding, the ability to pass in your own Figure and Axes (and have mplfinance draw on them) will at least give those people who are familiar with matplotlib and its event handling the ability to do event hanlding with mplfinance plots.

@lyl1836
Copy link

lyl1836 commented Mar 20, 2021

Hi, @croganm :
p1

I also want to use the mouse event of mplfinance. I wrote an example to get fig and convert it into Matplotlib object. After setting the mouse event, I failed.

How did you solve your problem?

Please give me some guidance!

Thank you very much.

@DanielGoldfarb
Copy link
Collaborator

DanielGoldfarb commented Mar 21, 2021

@lyl1836
mpf.plot() will not return Figure and Axes list unless you set kwarg returnfig=True:

fig, axlist = mpf.plot(df,returnfig=True)

See also https://github.com/matplotlib/mplfinance/wiki/Acessing-mplfinance-Figure-and-Axes-objects

@lyl1836
Copy link

lyl1836 commented Mar 21, 2021

I want to use pick_event, but plot doesn't support picker.
Is there a way?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

5 participants