matplotlib / mplfinance

Financial Markets Data Visualization using Matplotlib
https://pypi.org/project/mplfinance/
Other
3.57k stars 618 forks source link

live update of the chart #264

Closed gchudublin closed 3 years ago

gchudublin commented 3 years ago

I have data streaming through API calls to Alpaca and it is real time stock market data, it is using the code below to get data, and "on_message" event triggers I parse the data to pandas dataframe object dfObj, then plot the candlestick chart. Now the issue is the chart will need to be closed manually in order for it to continue execute the next "on message event", anyway to update the chart? and continue without plotting a new one?


ws = websocket.WebSocketApp("wss://socket.polygon.io/stocks",
                          on_message = on_message,
                          on_error = on_error,
                          on_close = on_close)
ws.on_open = on_open
ws.run_forever()

import mplfinance as mpf 

def on_message(ws, message):
          # code to parse message and add data to dfObj .....
          mpf.plot(dfObj, type='candle')

the code above just fragments

DanielGoldfarb commented 3 years ago

There are a few things you can try:

Please let me know if that helps.

gchudublin commented 3 years ago

mpf.plot(dfObj,...,block=False) or mpf.plot(dfObj,...,closefig=True) just does not work

I recorded my screen and you can see I have to manually close the plotted window to let the app continue execution, YouTube video link below: https://youtu.be/sFva4TgsYQg

DanielGoldfarb commented 3 years ago

@gchudublin

Correct me if I'm wrong, but I think what you really want is not for the plot to close automatically, but for the plot to stay open but continually update. Something like this perhaps:

gc

Please let me know if that is the type of thing are looking for. If not, please explain exactly how you want your plot to appear and how you want your plot to behave. Thank you. --Daniel

gchudublin commented 3 years ago

Yes, but animation does not work, animation you have to decide an interval, this is based on event when "message received". so when new stock price come in, then update the chart, the new data is the trigger for update not the predefind interval.

it seems to me the solution is to use figure with axes, you plot the chart initially with a figure, then you let app to continue execute, then when data arrived, you clear the existing figure(or axes) and draw the new figure inside the plot. but it could not continue the app after it executed mpf.plot statement, it plotted the chart and I have to close the chart window use my mouse, then it continue.

Looks like need to have plot run in another thread, then update it when needed from the main thread.

gchudublin commented 3 years ago

after search more, found that below code can close the chart and continue app execution: mpf.plot(dfObj,type='candle',block=False) plt.pause(3) plt.close()

https://youtu.be/UqZ9UGNt1HU

this is not what I want, I need to use the same plot, and update what's in side. I think use figure, and clear figure and redraw figure might work.

DanielGoldfarb commented 3 years ago

Because I only have some snippets of your code, it's difficult for me to be very exact in what to do, however I would suggest doing something along these lines ...

First, and most important, you must be able to get the Axes object into you on_message() method. I don't know if you have the ability to pass it, or use a global (last resort), or perhaps define a class and make on_message() a method in that class, and when initializing an object for that class it stores the Axes. At any rate, you will have to find out how to do that ...

BEFORE you call ws.fun_forever() you will need to call:

fig = mpf.figure()
myaxes  = fig.add_subplot(1,1,1)

Then on_message() should look something like this:

def on_message(ws, message):
    # code to parse message and add data to dfObj .....
    myaxes.clear()
    mpf.plot(dfObj, ax=myaxes, type='candle')

NOTE: You must get the myaxes, that you created before, into on_message() somehow. That should work. Do not do closefig but ok to do block=False if that helps.

This is what I meant in the whole "Alternatively" section, the last section, of my original answer.

Let me know who that works. If you can't get it to work, then if you can provide access to the rest of your code I may be able to help figure this out.

gchudublin commented 3 years ago

After change to subplot and it started to work (see Youtube below), my guess the plt.pause(3) is the game changer step. Now, how do I add VWAP to the candlestick chart? The incoming data does have that number. (if you want to have the code, I can email to you or post here, but you need to go to https://alpaca.markets/ to get your key to run it, I am not sure if I give you my key will violate the contract, the account is free, but you need to put some money in to have the key code to access the data through ploygon)

initialize plot: fig = mpf.figure() ax1 = fig.add_subplot(2,1,1,style='yahoo') ax2 = fig.add_subplot(3,1,3)

after on_message event triggered: ax1.clear() ax2.clear() mpf.plot(dfObj,type='candle', ax=ax1,volume=ax2, block=False, mav=(9,21,50,200)) plt.pause(3)

https://youtu.be/s6lt7Vu8B_0

When ever the console windows post messages, my keyboard focus goes there, not sure how to stop that. Also how to add VWAP or other indicators to the chart is my next research. I will study more docs. My candle is missing head and tales, any idea?

DanielGoldfarb commented 3 years ago

Looks good! I'm glad you got it working. I will be offline for a few days. Will try to touch base next week. Good luck!

gchudublin commented 3 years ago

Greatly appreciated your help. When ever the console windows post messages, my keyboard focus goes there, not sure how to stop that, Also how to add VWAP or other indicators to the chart is my next research. I will study more docs. My candle is missing head and tales, any idea? (my guess is post market)

centi1 commented 3 years ago

The Mouse is repositioning to the most preferred next operation. This is a windows feature. You might have enabled the Snap To option in Mouse Pointer Options. To remove that, follow the below steps. Right Click on your desktop --> click "Personalize" --> click "Themes" from the left tab --> click "Mouse Cursor" --> click "Pointer Options" --> Un Check the "Snap To" option. Your mouse will not reposition to the most predicted next operation.

DanielGoldfarb commented 3 years ago

Greatly appreciated your help. When ever the console windows post messages, my keyboard focus goes there, not sure how to stop that, Also how to add VWAP or other indicators to the chart is my next research. I will study more docs. My candle is missing head and tales, any idea? (my guess is post market)

@gchudublin Definitely you should take the time to go though all of the docs listed here and in particular this one explains how to add your own indicators.

It may take a full hour, or two, to go carefully through all the documentation, but that will be time well spent to better understand the package. You may want to clone this repository and make sure you can actually run all the notebooks in the examples folder. After that, you may want to play around with tweaking the code in those notebooks to get a better sense of what you can do with this package.

Regarding the strange look of your candles. It probably has something to do with your data. I suggest that you carefully examine the dfObj dataframe. If you want me to take a look, the please call dfObj.to_csv('dfobj.csv') and then post the 'dfobj.csv' file here.

@centi1 Thank you for contributing a comment to this issue. Much appreciated!

nocciolate commented 3 years ago

Hi Daniel, I'm struggling with the same issue, but after "showing" the plot with mpf.show(), then nothing else helps not to get stuck with the plot. I am slowly starting to think this might be an IDE issue - I'm currently running my script within pycharm within a virtual conda env. Do you have any suggestion? My code might be different, but the approach and final goal is exactly the same as discussed so far here. Only difference - I need to do mpf.show(), otherwise I don't get any chart.

An alternative I was considering was placing the entire thing within a worker thread and not caring about it being stuck - but apparently it needs to be executed from within the main thread.

PS: Greatly appreciate the library! Already managed to create an amazing live chart with my own custom indicators. Now the only issue is how to integrate this into the rest of my bigger script, without blocking it..

DanielGoldfarb commented 3 years ago

@nocciolate What have you tried so far? Have you tried running it as an independent script outside of your IDE? Have you tried setting block=False? (Or both of the above). What exactly is the symptom you are seeing that you don't want to see? The plot comes up but does not update with new data? Or something else?

nocciolate commented 3 years ago

Hi Daniel, I haven't tried outside of pycharm because of a Windows issue that requires me to use pycharm in order to deal with it.

I used the MACD example you provided above and tweeked it a bit. But the overall logic is the same.

Adding block=False (or True) to the plot() function doesn't change anything for me.

Adding it to the show() function does. With block=True in the show() function the code gets stuck in the animation function until the plot is manually closed. With block=False - the animation function does not get executed even once. The plot also remains completely empty (does appear, but remains blank).

I also tried setting plt.ion() in the beginning of the script - same result as when block=False in the show(). I also tried putting everything in a different thread, but get an error message that the plot should be started from the main thread.

If you have any ideas, let me know. I should be able to identically apply any code-wise references to the MACD example since the logic is the same.

Perhaps multiprocessing might be a solution for me. Found this and wondering how to apply it in my case: https://matplotlib.org/3.1.0/gallery/misc/multiprocess_sgskip.html

Have a nice evening.

DanielGoldfarb commented 3 years ago

Adding block=False (or True) to the plot() function doesn't change anything for me. Adding it to the show() function does.

This makes sense. When plot() returns the figure, or is in external axes mode, then it does not call show() (that's why you have to call show() separately; and that is where block gets applied).


I also tried setting plt.ion() in the beginning of the script

Try also specifically calling plt.ioff() instead.


I used the MACD example you provided above and tweeked it a bit. But the overall logic is the same.

Are you able to get the MACD example to work with no changes? I suggest you try that first. If you can get that to work, then you can slowly, one at a time, apply your tweeks to see which tweek brings out the issue. If you can't get the MACD example to work as is, or any of the other animation examples, as they are, then let's focus on that alone first.

nocciolate commented 3 years ago

I believe I finally figured it out - it was a pycharm issue indeed. When running the script within the interactive python console within pycharm, then the plt.ion() works just fine.

When using a while loop after the plot() I had again the same issue, but managed to overcome this as well by including the plt.pause() within that while loop. It's not the prettiest solution and I'm not sure where and how ofter I will have to paste this plt.pause() in the rest of the code, but at least it seems to work. If you have any suggestions how to do this in a more pythonic way, please let me know :)

Thanks for your feedback!

Here's my final solution so far:

# DOING ALL THE IMPORTS HERE

plt.ion()

def animate(ival):
    # PREPARE DATAFRAME WITH OHLC AND "BUYS" AND "SELLS" HERE

        apds = [mpf.make_addplot(buys, color='tab:green', ax=ax_buys),
            mpf.make_addplot(sells, color='tab:red', ax=ax_sells)]
    for ax in axes:
        ax.clear()
    mpf.plot(df_ohlc, type='candle', addplot=apds, ax=ax_main)
    print('a')

if __name__ == "__main__":
    # START WEBSOCKET
    # WAIT TILL FIRST DATA LOADED FROM WEBSOCKET
    # PREPARE DATAFRAME WITH OHLC AND "BUYS" AND "SELLS"
    apds = [mpf.make_addplot(buys, panel=1, color='tab:green', secondary_y=False),
            mpf.make_addplot(sells, panel=1, color='tab:red', secondary_y=False)]

    fig, axes = mpf.plot(df_ohlc, type='candle', addplot=apds, figscale=1.5, figratio=(7, 5), title=symbol, volume=False, panel_ratios=(6, 3), returnfig=True)
    ax_main = axes[0]
    ax_buys = axes[2]
    ax_sells = ax_buys
    ani = animation.FuncAnimation(fig, animate, interval=100)
    mpf.show()

    i = 1
    while True:
        print(i)
        i += 1
        plt.pause(0.1)
DanielGoldfarb commented 3 years ago

@nocciolate Thanks for posting your solution to help others. All the best. --Daniel

nocciolate commented 3 years ago

Hi Daniel, thank you for taking care of the mplfinance :)

One last question - you wouldn't happen to have any recommendations for doing this in a better / more pythonic way, do you?

Cheers

DanielGoldfarb commented 3 years ago

One last question - you wouldn't happen to have any recommendations for doing this in a better / more pythonic way, do you?

I don't think I can recommend anything else. I am not familiar with the PyCharm environment. I also don't understand what the problem is or why the plt.pause(0.1) fixes the problem, so it's hard for me think of a better or more pythonic way to do something that I don't fully understand. That said, I would be interested to know more about the problem. If you ever figure out what's happening under the hood and why the pause fixes the issue, I would definitely like to know.

All the best. --Daniel

nocciolate commented 3 years ago

Hi Daniel,

so far the best explanation I have managed to find is the answer to this question: https://stackoverflow.com/questions/53758472/why-is-plt-pause-not-described-in-any-tutorials-if-it-is-so-essential-or-am-i

There are also some useful links in the comments to that answer.

From what I understand it's not an IDE issue, but rather a python/mpl issue.

A possible (and extremely ugly) solution is to have the code for the plot in a different script, which is to be launched by a thread as a subprocess. The thread will be blocked afterwards, but can be left as it is. I know this is probably the very opposite of good practice, but it's the only solution I have so far. I will try out themultiprocessing approach (link here) as a last resort.

I will update this commect, should I find something better.

Cheers

DanielGoldfarb commented 3 years ago

@nocciolate Thanks. That link explains a lot. At least now I have a concept how I might reproduce the issue in my environment (and can therefore investigate it further).

I wonder also if another way to handle the issue is, instead of making calculations between animation updates, perhaps place the calculations inside the animation function. That way the calculations are between each animation update, but they are also part of the animation loop itself. Just throwing it out there as an idea. I can't say whether I think it's a good idea or not, because I don't really know or understand enough about the issue to say. But it popped into my head because essentially that's what I am doing in the MACD animation example; that is, the MACD calculations are included in the animate() function.

Over the next few weeks, as my time permits, I think I will explore this further. As I mentioned, the link you provided at least gives my something concrete to play with to better understanding the issue. Along those lines, I have some questions that may influence the approach I take when I investigate this further: Aare you working on windows? If so, do you have same issue if you just run it as a python script under command prompt or power shell?

Whether threading as a subprocess (i.e. not true threading which is impossible in Python) will help, I can't say. It certainly seems a bit complicated but it may provide a lot of freedom to more cleanly do separate tasks during the animation, such as collecting new data, and processing new data, and then passing that to the animation subprocess. Still, I kind of wonder if maybe its simpler to put all that directly into the animation loop. Probably one of those things that you just have to try and see which approach works and keeps the code maintainable.

nocciolate commented 3 years ago

Great, thanks for the feedback. I have to think about it because it's a bit complicated. My problem is that I have a constellation where I am pulling live data directly from an exchange via two separate websockets. The first websocket pulls best bids in real time for over 300+ pairs and compares them to initially pre-recorded prices, while potentially executing orders if conditions are met (done similarly to the "on_message" logic in the conversation above). The second websocket pulls the exchange's responses from the persistence layer which are sent after an executed order of mine, while also potentially executing further orders. I have managed to tune it to run smoothly.

I don't know in advance which pair I will be interested in. The first websocket needs to catch this and enter the market. After entering the market, it is supposed to "however" open the plot and shut itself down. Opening the plot includes firing up a new websocket for last executed orders in real time (I basically want a chart showing in real time prices and volume of market buy vs market sell orders). The plot is supposed to run in parallel, while not interrupting the second websocket (listening for responses to orders of mine) which would still be running.

When I took it to "production" - basically tested in real life, I noticed that after the first websocket launches the plot (by calling the second script with the plotting functions, incl. the websocket for executed orders), it gets blocked afterwards.. which also blocks the second websocket... which makes the entire exercise pointless.

I'm just extremely surprised this is so difficult to achieve, but time and motivation to overcome this are present. Probably just lacking skills :)

PS: I might just create two identical copies of the script - one for trading, one for plotting, and pin them to two separate cores in order not to affect latency of the trading one.

Have a great weekend

DanielGoldfarb commented 3 years ago

PS: I might just create two identical copies of the script - one for trading, one for plotting, and pin them to two separate cores in order not to affect latency of the trading one.

That's almost exactly what I was thinking as I was reading your description before the "P.S."

My inclination, however, is not to make two copies of the script, but rather split it in two: running two separate processes that do not interfere with each other:

Trade execution is mission critical, and that process should be kept as simple as possible, focussing only on trade execution and nothing else. That way, if something goes wrong (with the trade execution process) it will be easier to debug (and being simpler it will be easier to test, and less likely to have a bug in the first place).

In other words, the trade excution part of the application should be kept as simple, independent, and decoupled from the rest of the application as possible. As an added benefit to this independence, it can be tested independently from the rest of the application too. You may want some kind of ipc between the executor and the analyzer, but only to tell the trade executor process to go ahead and execute a trade, and maybe have it send its info back to the analyzer/plotter (if needed), perhaps asynchronously so neither interferes with the other.

nocciolate commented 3 years ago

Hi Daniel, thanks a lot for the advice - that was roughly also what I had in mind!

I tested the combo yesterday on live market data and at least this part worked fine. There were some other issues with speed of processing and plotting, but it is outside of the scope of the topic here.

May I ask you one more thing related to plotting live market data?

DanielGoldfarb commented 3 years ago

@nocciolate of course. ask away.

nocciolate commented 3 years ago

My final goal is to have one live plot including 2 figures with 3 main components: a) OHLC chart in fig 1, b) volume split of market buy and sell orders in fig 2 and c) vizualization of the order book data as a heatmap behind the OHLC prices (again in fig 1). So far, with your help, I have managed to achieve a) and b) in python and they more or less work for periods of time, when there isn't much incoming volume to be processed. Sadly, I'm interested exactly in the opposite market conditions - but I will figure it out eventually.

For c) I was imagining something similar to the service that bookmap offers. There's also a javascript lib, which I found to be extremely well done (link).

From your experience - do you think python is the right way to go in order to achieve all three points, while the evnironment remains stable and suffiently fast? I am slowly starting to think javascript might be superior, when it comes to real time plotting of live market data.

DanielGoldfarb commented 3 years ago

@nocciolate From my experience working with Python and Javascript and other languages, the main difference is that

The decision, for me, often comes down to how fast the code needs to be. Let's say I need a half-dozen plots, and even if they need live updates once per second, or once every two seconds, the speed difference is negligable; you probably would not even notice it under most conditions on most machines. In such a case, for me, the ease and beauty of banging out the code in Python far outweighs speed difference which, at those rates, is not noticible. (But if I need many updates per second, and/or hundreds of plots in a short amount of time, then speed may become an issue).

Even where speed is an issue, depending on the application, it may be worthwhile to multi-process Python (again because of the ease of writing the code). I once wrote a market analysis program running some 20,000 different scenarios. I wrote the code in C++ and it took 2 to 3 minutes to run. It took me about a week to get the code fully functional.

I then re-wrote the code in Python in just a few hours. Admittedly some of that writing speed (a few hours vs a week) was because I already knew what I wanted the code to do, but for sure most of it was because I did not have to hand-craft and unit test a lot of different classes. In fact, I did not simply rewrite the code from C++ to Python (keeping the same structure and design) which I imagine would have taken me at least two to three days. Instead, I used existing python classes and methods from pandas, numpy, and the standard Python library modules. I finished coding in about 3 hours.

But the Python version took 55 minutes to run! The 20,000 scenarios were independent from each other, they could be run in any order and in parallel. So I used a python multi-processing module, running 8 parallel process on an 8 core pc, and got the time down to 6 minutes. For me, for that particular application, it was worth the extra time (6 minutes per run, vs 2.5 minutes per run) for the benefit of less code that was easier to maintain (because my goal was constantly tweaking the algorithm and re-running the 20,000 scenarios to see if I got better results).

It seems to me however, that for a market data visualization to plot 3 or more updates per second, if that rate of plotting speed is important to you, then Python may not be the way to go. There are definitely ways to optimize the Python to handle a faster rate of screen refresh (compared to what I am doing in mplfinance) however, imho, once you are putting that much effort into it, you may be better using a faster language. Of course, to keep the code easy to maintain you may have to take the time to hand-craft and organize the behavior of a number of classes.

So that's my take on it. Although matplotlib can plot heat maps (examples here and here), I have no intention to add heat maps to mplfinance in the near future; certainly not this year unless someone else volunteers to contribute the code. Now just to get a little philosophical about the market, i personally have never felt a need to see a visualization update more than once every two seconds or so. It seems to me that any decisions I am making based on the visualization are not going to be made that quickly. If I wanted to make decisions that quickly I would probably want the software to make the decision for me. I understand that other people find a lot of value in rapid updates to the data visualization. That's fine and good, and it appears to work well for many people. My own philosophy is that these differences (different people taking different approaches) are a significant part of what makes the free market work well. If everyone always did the same thing, and saw things the same way, imho, that would create friction and other problems in the marketplace. There is great value to diversity of thought and diversity of approach, in that they provide (among other things) opportunities for everyone.

HTH. All the best.

nocciolate commented 3 years ago

Hi Daniel,

I highly appreciate you taking the time to go into such details in your reply!

I agree with everything you said - in a normal case, which one already undestands well and can build a logic around, I would also always prefer a machine to be doing split second decisions instead of a human. On the other hand, I am still in a sort of "exploratory" mode and want to first understand what exactly happens within those 3-4 seconds I am interested in, before diving into automation.

From all the trade-by-trade analysis so far, I believe to have the full picture of what happens when it comes down to how market orders are coming in and managed to develop a logic (incl. location from which the script is running) that gives me a certain advantage for early entry.

In terms of speed of entry, I did manage to have a python script with a "loop" run-time of roughly 0.5 microseconds and an average of about 22-25 ms time between signal being "produced" within the previous auction block in the matching engine of the exchange (from the previous trades) and my entry order being successfully executed back in the matching engine. The exchange is running on aws and I'm sitting in the same server cluster, plus I have a certain logic for dealing with load balancers at the point of entry.

Because run-time is so negligible compared to latency, the additional benefit from a different language would be relatively small, plus I'm already a bit familiar with python but not js or C++, I was secretly hoping I'd be able to do the plotting part (separate script) also in python, without having to start from scratch again and learn a new language.

Once in the market - then the interesting part begins. Since the exchange does not provide historical data for limit orders (at least to retail traders), it's hard to analyse at a later point the action that occured in the order book post my market entry. I therefore wanted to plot the order book for a couple of times (for those 3-4 secs post entry) and come up with an additional exit logic for how certain conditions are to be handled - automatically as you also suggested.

Given all you said, I believe I have two options - either switch to a different language or perhaps try plotting the order book volume through matplotlib on top of the ohlc bar chart. I will probably start with the latter. Just need to figure out if that's even possible. So far I couldn't figure out how to combine two different plots on top of each other.

Best regards, Georgi

DanielGoldfarb commented 3 years ago

Georgi,

Regarding

Just need to figure out if that's even possible. So far I couldn't figure out how to combine two different plots on top of each other.

Take a look at this: Acessing mplfinance Figure and Axes objects and the links therein. In the returnfig=True "panels" approach, mplfinance will always create two Axes objects for each panel, even if only one axes has data. You can plot additional data on top of existing data by plotting on either of the two axes. Use the primary axes if the y-values are similar in magnitude to the existing ohlc data. Use the secondary axes if the different plot has a very different order of magnitude. This will overlay two data sets on top of each other, where one uses the left side for the y-axis, and the other uses the right side for its different y-axis.

Keep in mind that, at least for the panels approach, it is assume that all plots have same datetime x-axis data. That is, they are all time-series data sets over the same period of time.

A few other pages that may be of interest to you, in helping you decide how to accomplish what you want to do:

If you have not already seen the above, it may be well worth the time to allot about 25 minutes of your time to carefully read through the above examples.

All the best. --Daniel

nocciolate commented 3 years ago

Hi Daniel,

thanks a lot for the links! I took the time to study the examples and have a much better understanding now what's going on under the hood. Yet, I'm still not sure how to achieve what I set out to do. I came to the conclusion I might need external help :)

Thanks again for all your time and effort to help! I really do appreciate it. It has been a pleasure to talk to someone who understands you and you don't have to explain every little detail.

Have a great day and take care!

Best regards, Georgi

Olujideo commented 2 years ago

@gchudublin

Correct me if I'm wrong, but I think what you really want is not for the plot to close automatically, but for the plot to stay open but continually update. Something like this perhaps:

gc

Please let me know if that is the type of thing are looking for. If not, please explain exactly how you want your plot to appear and how you want your plot to behave. Thank you. --Daniel

I like to get around this too. How do I get live updates plotted on mplfinance, with reference to your diagram above? Thanks

DanielGoldfarb commented 2 years ago

@Olujideo I am not completely sure what you are asking. The code for the example shown in the plot that you referenced above can be found here: https://github.com/matplotlib/mplfinance/blob/master/examples/mpf_animation_growingcandle.py Let me know if that helps.

Olujideo commented 2 years ago

Hi Daniel, Thanks This is close to what I need.

On Sun, Nov 21, 2021, 02:39 Daniel Goldfarb @.***> wrote:

@Olujideo https://github.com/Olujideo I am not completely sure what you are asking. The code for the example shown in the plot that you referenced above can be found here: https://github.com/matplotlib/mplfinance/blob/master/examples/mpf_animation_growingcandle.py Let me know if that helps.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/matplotlib/mplfinance/issues/264#issuecomment-974739307, or unsubscribe https://github.com/notifications/unsubscribe-auth/APRS3R2K5VZZ3HYCVRPTN63UNBEWFANCNFSM4RPLRHNA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

KingOfHearts7865 commented 1 year ago

Binance live running candle stick chart of btcusdt Using mplfinance and matplotlib

import requests
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from mpl_finance import candlestick_ohlc
import matplotlib.dates as mpl_dates
from matplotlib.animation import FuncAnimation

url = 'https://api.binance.com/api/v3/klines?symbol=BTCUSDT&interval=1m'

headers = {
    'Content-Type': 'application/json'
}

fig, ax = plt.subplots()

def update_chart(i):
    response = requests.get(url, headers=headers)
    data = response.json()
    df = pd.DataFrame(data, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume', 'close_time',
                                     'quote_asset_volume', 'number_of_trades', 'taker_buy_base_asset_volume',
                                     'taker_buy_quote_asset_volume', 'ignore'])

    df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
    df['timestamp'] = df['timestamp'].apply(mpl_dates.date2num)
    df = df.astype(float)
    ax.clear()
    candlestick_ohlc(ax, df.values, width=0.0005, colorup='green', colordown='red')
    ax.xaxis_date()
    plt.xticks(rotation=45)
    plt.title('BTCUSDT Candlestick Chart')
    plt.xlabel('Date')
    plt.ylabel('Price')

ani = FuncAnimation(fig, update_chart, interval=10)

plt.show()
Ed-Yang commented 6 months ago

FYI, after mpf.plot, add the following work for me:

fig.canvas.draw_idle()