Skip to content

Commit 7b1b722

Browse files
Create mpf_animation_growingcandle.py
For [**Issue #256**](#256)
1 parent 3af71a8 commit 7b1b722

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
'''
2+
This file contains a animation demo using mplfinance demonstating resampling
3+
of the data and re-displaying the most recent, partially resampled, candle.
4+
5+
The idea for this example came from Issue #256
6+
(https://github.com/matplotlib/mplfinance/issues/256)
7+
8+
The typical use-case is where the user has real-time data from an API,
9+
perhaps to the second, or minute, but wants to aggregate that data to
10+
15 minutes per canlde, or maybe 30 minutes per candle. At the same time,
11+
during those 15 or 30 minutes, the user wants to see the most recent
12+
candle changing and developing as real-time data continues to come in.
13+
14+
In the example presented in this file, the data is once per minute,
15+
with an aggregation of 15 minutes per candle. But, for this *simulation*
16+
we set the animation rate to 250ms, which means we are getting 1 minute's
17+
worth of data from the API every 1/4 second. Thus, this simulation is
18+
running 240 times faster than real-time.
19+
20+
In a real-life case, if we have data once per second, and want to aggregate
21+
15 minutes per candle, we would set the animation interval to something
22+
like 5000ms (once every 5 seconds) because a more frequent visualization
23+
might be impractical to watch or to use for decision making.
24+
25+
PLEASE NOTE: In this example, we resample the *entire* data set with each
26+
animation cycle. This is inefficient, but works fine for less than 5000
27+
data points or so. For larger data sets it may be practical to cache
28+
the resampled data up to the last "full" candle, and only resample the
29+
data that contributes to the final candle (and append it to the cached
30+
resampled data). If I have time, I will work up and example doing that.
31+
32+
NOTE: Presently mplfinance does not support "blitting" (blitting makes animation
33+
more efficient). Nonetheless, the animation is efficient enough to update at least
34+
once per second, and typically more frequently depending on the size of the plot.
35+
'''
36+
import pandas as pd
37+
import mplfinance as mpf
38+
import matplotlib.animation as animation
39+
40+
## Class to simulate getting more data from API:
41+
42+
class RealTimeAPI():
43+
def __init__(self):
44+
self.data_pointer = 0
45+
self.data_frame = pd.read_csv('data/SP500_NOV2019_IDay.csv',index_col=0,parse_dates=True)
46+
#self.data_frame = self.data_frame.iloc[0:120,:]
47+
self.df_len = len(self.data_frame)
48+
49+
def fetch_next(self):
50+
r1 = self.data_pointer
51+
self.data_pointer += 1
52+
if self.data_pointer >= self.df_len:
53+
return None
54+
return self.data_frame.iloc[r1:self.data_pointer,:]
55+
56+
def initial_fetch(self):
57+
if self.data_pointer > 0:
58+
return
59+
r1 = self.data_pointer
60+
self.data_pointer += int(0.2*self.df_len)
61+
return self.data_frame.iloc[r1:self.data_pointer,:]
62+
63+
rtapi = RealTimeAPI()
64+
65+
resample_map ={'Open' :'first',
66+
'High' :'max' ,
67+
'Low' :'min' ,
68+
'Close':'last' }
69+
resample_period = '15T'
70+
71+
df = rtapi.initial_fetch()
72+
rs = df.resample(resample_period).agg(resample_map).dropna()
73+
74+
fig, axes = mpf.plot(rs,returnfig=True,figsize=(11,8),type='candle',title='\n\nGrowing Candle')
75+
ax = axes[0]
76+
77+
def animate(ival):
78+
global df
79+
global rs
80+
nxt = rtapi.fetch_next()
81+
if nxt is None:
82+
print('no more data to plot')
83+
ani.event_source.interval *= 3
84+
if ani.event_source.interval > 12000:
85+
exit()
86+
return
87+
df = df.append(nxt)
88+
rs = df.resample(resample_period).agg(resample_map).dropna()
89+
ax.clear()
90+
mpf.plot(rs,ax=ax,type='candle')
91+
92+
ani = animation.FuncAnimation(fig, animate, interval=250)
93+
94+
mpf.show()

0 commit comments

Comments
 (0)