Skip to content

Commit 18ffa3f

Browse files
committed
plotting styles
1 parent 5cbd645 commit 18ffa3f

File tree

2 files changed

+137
-9
lines changed

2 files changed

+137
-9
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,6 @@ cython_debug/
157157
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158158
# and can be added to the global gitignore or merged into this file. For a more nuclear
159159
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
160-
#.idea/
160+
#.idea/
161+
162+
.DS_Store

plotting.py

Lines changed: 134 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from datetime import datetime, timezone
2-
from pytest import Instance
32
import pytz
43

54
import pandas as pd
5+
import numpy as np
66
import matplotlib.pyplot as plt
7+
import pyqtgraph as pg
78

89
import finplot_lib as fplt
910

@@ -24,23 +25,148 @@ def create_observation_matrix(mp_slice):
2425

2526
# slice_dt = pytz.timezone('Asia/Hong_Kong').localize(datetime(2022,3,17,17,23,0)) # input in HKT
2627
slice_start = pytz.timezone('Asia/Hong_Kong').localize(datetime(2021,12,10,0,0,0)) # input in HKT
27-
slice_end = pytz.timezone('Asia/Hong_Kong').localize(datetime(2021,12,12,0,0,0)) # input in HKT
28+
slice_end = pytz.timezone('Asia/Hong_Kong').localize(datetime(2021,12,10,16,0,0)) # input in HKT
2829

2930
# mp_slice = profile[slice_dt]
3031
mp_slice = profile[slice_start:slice_end]
3132

32-
ochl = pd.DataFrame(
33+
ohlcv = pd.DataFrame(
3334
{
3435
'o': [mp.open for mp in mp_slice],
35-
'c': [mp.close for mp in mp_slice],
3636
'h': [mp.high for mp in mp_slice],
3737
'l': [mp.low for mp in mp_slice],
38-
# 'v': [mp.volume_qty for mp in mp_slice]
38+
'c': [mp.close for mp in mp_slice],
39+
'v': [mp.volume_qty for mp in mp_slice],
40+
'd': [mp.delta_qty for mp in mp_slice]
3941
},
4042
index=[mp.timepoint for mp in mp_slice]
4143
)
4244

43-
# ohlcv.plot(y='o')
44-
# plt.show()
45-
fplt.candlestick_ochl(datasrc=ochl, candle_width=0.2)
45+
# plotting
46+
fplt.foreground = '#D6DBDF'
47+
fplt.background = '#151E26'
48+
ax, ax2 = fplt.create_plot(
49+
title='Orderflow',
50+
rows=2, # row1: candlestick, volume; row2: delta table; row2:
51+
)
52+
53+
# set font
54+
'''
55+
TODO: set font
56+
'''
57+
58+
# fplt.windows[0].ci.layout.setRowStretchFactor(0, 8) # make primary plot large, and implicitly table small
59+
60+
# add candlestick
61+
candlestick_plot = fplt.candlestick_ochl(datasrc=ohlcv[['o', 'c', 'h', 'l']], candle_width=0.6, ax=ax)
62+
63+
# add volume
64+
volume_plot = fplt.volume_ocv(ohlcv[['o', 'c', 'v']], ax=ax.overlay())
65+
66+
# add delta table
67+
'''
68+
Ref: examples/bubble-table.py
69+
'''
70+
# def skip_y_crosshair_info(x, y, xt, yt): # we don't want any Y crosshair info on the table
71+
# return xt, ''
72+
# ax2.set_visible(yaxis=False)
73+
# fplt.add_crosshair_info(skip_y_crosshair_info, ax=ax2)
74+
# fplt.set_y_range(0, 2, ax2)
75+
# # hmmm it is weird that finplot requires the column to be visualized to be named int 0,1,2,...
76+
# delta_df = ohlcv.copy()
77+
# delta_df[1] = delta_df['d']
78+
# delta_df[0] = delta_df['d'].cumsum()
79+
80+
# colmap = fplt.ColorMap([0.0, 0.5, 1.0], [[200, 80, 60], [200, 190, 100], [40, 170, 30]]) # traffic light colors
81+
# ts = [int(t.timestamp()) for t in ohlcv.index]
82+
# fplt.heatmap(delta_df[[1, 0]], colmap=colmap, colcurve=lambda x: x, ax=ax2)
83+
# fplt.labels(ts, [1.5] * len(ohlcv), [f'{d:2f}' for d in ohlcv['d']], ax=ax2, anchor=(0.5, 0.5))
84+
# fplt.labels(ts, [0.5] * len(ohlcv), [f'{d:2f}' for d in ohlcv['d'].cumsum()], ax=ax2, anchor=(0.5, 0.5))
85+
86+
'''
87+
Ref: examples/snp500.py
88+
'''
89+
# plot cvd
90+
line_color = '#3498DB'
91+
cvd_plot = fplt.plot(np.cumsum(ohlcv['d']), ax=ax2, legend='CVD', color=line_color, fillLevel=0, brush=line_color+'10')
92+
# and set background
93+
vb = cvd_plot.getViewBox()
94+
vb.setBackgroundColor('#00000000')
95+
96+
'''
97+
Ref: examples/complicated.py
98+
'''
99+
# set bull body to same color as bull frame; otherwise it is default background color (transparent)
100+
bull = '#1ABC9C'
101+
bear = '#E74C3C'
102+
fplt.candle_bull_color = bull
103+
fplt.candle_bull_body_color = bull
104+
fplt.candle_bear_color = bear
105+
candlestick_plot.colors.update({
106+
'bull_body': fplt.candle_bull_color
107+
})
108+
109+
transparency = '45'
110+
volume_plot.colors.update({
111+
'bull_frame': fplt.candle_bull_color + transparency,
112+
'bull_body': fplt.candle_bull_body_color + transparency,
113+
'bear_frame': fplt.candle_bear_color + transparency,
114+
'bear_body': fplt.candle_bear_color + transparency,
115+
})
116+
117+
# set gridlines
118+
ax.showGrid(x=True, y=True, alpha=0.2)
119+
ax2.showGrid(x=True, y=True, alpha=0.2)
120+
121+
# add legend of ohlcv data
122+
'''
123+
Ref: examples/snp500.py
124+
'''
125+
hover_label = fplt.add_legend('', ax=ax)
126+
def update_legend_text(x, y):
127+
dt = datetime.fromtimestamp(x // 1000000000)
128+
utcdt = dt.astimezone(pytz.utc)
129+
# dt = dt.replace(tzinfo=timezone.utc)
130+
row = ohlcv.loc[utcdt]
131+
# format html with the candle and set legend
132+
fmt = '<span style="color:%s; margin: 16px;">%%s</span>' % (bull if (row['o'] < row['c']).all() else bear)
133+
rawtxt = '<span style="font-size:14px">%%s %%s</span> &nbsp; O: %s H: %s L: %s C: %s Delta: %s' % (fmt, fmt, fmt, fmt, fmt)
134+
hover_label.setText(rawtxt % ('TOKEN', 'INTERVAL', row['o'], row['h'], row['l'], row['c'], row['d']))
135+
fplt.set_time_inspector(update_legend_text, ax=ax, when='hover')
136+
137+
# additional crosshair info
138+
def enrich_info(x, y, xtext, ytext):
139+
o = ohlcv.iloc[x]['o']
140+
h = ohlcv.iloc[x]['h']
141+
l = ohlcv.iloc[x]['l']
142+
c = ohlcv.iloc[x]['c']
143+
add_yt = f'\tOpen: {o}\n\tHigh: {h}\n\tLow: {l}\n\tClose: {c}'
144+
return xtext, add_yt
145+
146+
fplt.add_crosshair_info(enrich_info, ax=ax)
147+
148+
# set dark themes ====================
149+
pg.setConfigOptions(foreground=fplt.foreground, background=fplt.background)
150+
151+
# window background
152+
for win in fplt.windows:
153+
win.setBackground(fplt.background)
154+
155+
# axis, crosshair, candlesticks, volumes
156+
axs = [ax for win in fplt.windows for ax in win.axs]
157+
vbs = set([ax.vb for ax in axs])
158+
axs += fplt.overlay_axs
159+
axis_pen = fplt._makepen(color=fplt.foreground)
160+
for ax in axs:
161+
ax.axes['left']['item'].setPen(axis_pen)
162+
ax.axes['left']['item'].setTextPen(axis_pen)
163+
ax.axes['bottom']['item'].setPen(axis_pen)
164+
ax.axes['bottom']['item'].setTextPen(axis_pen)
165+
if ax.crosshair is not None:
166+
ax.crosshair.vline.pen.setColor(pg.mkColor(fplt.foreground))
167+
ax.crosshair.hline.pen.setColor(pg.mkColor(fplt.foreground))
168+
ax.crosshair.xtext.setColor(fplt.foreground)
169+
ax.crosshair.ytext.setColor(fplt.foreground)
170+
# ====================================
171+
46172
fplt.show()

0 commit comments

Comments
 (0)