Skip to content

Commit a572ead

Browse files
committed
added ability to plot hollow candles
1 parent 51e66ce commit a572ead

File tree

5 files changed

+118
-3
lines changed

5 files changed

+118
-3
lines changed

examples/scratch_pad/stash_plotting.yscale.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def _valid_plot_kwargs():
8686
and all(isinstance(c, str) for c in value) },
8787
'type' : { 'Default' : 'ohlc',
8888
'Validator' : lambda value: value in ('candle','candlestick','ohlc','ohlc_bars',
89-
'line','renko','pnf') },
89+
'line','renko','pnf','hollow_candle') },
9090

9191
'style' : { 'Default' : 'default',
9292
'Validator' : lambda value: value in _styles.available_styles() or isinstance(value,dict) },

src/mplfinance/_styledata/default.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
style = dict(style_name = 'default',
22
base_mpl_style= 'seaborn-darkgrid',
3-
marketcolors = {'candle' : {'up':'w', 'down':'k'},
3+
marketcolors = {'candle' : {'up':'w', 'down':'k', 'up':'w', 'down':'k'},
44
'edge' : {'up':'k', 'down':'k'},
55
'wick' : {'up':'k', 'down':'k'},
66
'ohlc' : {'up':'k', 'down':'k'},

src/mplfinance/_styles.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,12 @@ def _valid_make_marketcolors_kwargs():
159159

160160
'down' : { 'Default' : None,
161161
'Validator' : lambda value: mcolors.is_color_like(value) },
162+
163+
'up_hollow' : { 'Default' : None,
164+
'Validator' : lambda value: mcolors.is_color_like(value) },
165+
166+
'down_hollow' : { 'Default' : None,
167+
'Validator' : lambda value: mcolors.is_color_like(value) },
162168

163169
'alpha' : { 'Default' : None,
164170
'Validator' : lambda value: ( isinstance(value,float) and
@@ -219,6 +225,7 @@ def make_marketcolors(**kwargs):
219225

220226
up = config['up']
221227
down = config['down']
228+
hollow = config['down']
222229
if up is not None and down is not None:
223230
marketcolors.update(candle=dict(up=up,down=down))
224231
elif up is not None:
@@ -229,6 +236,10 @@ def make_marketcolors(**kwargs):
229236
candle = marketcolors['candle']
230237
candle.update(down=down)
231238
marketcolors.update(down=down)
239+
elif hollow is not None:
240+
candle = marketcolors['candle']
241+
candle.update(hollow=hollow)
242+
marketcolors.update(hollow=hollow)
232243

233244
def _check_and_set_mktcolor(candle,**kwarg):
234245
if len(kwarg) != 1:

src/mplfinance/_utils.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ def _construct_mpf_collections(ptype,dates,xdates,opens,highs,lows,closes,volume
6767
if ptype == 'candle' or ptype == 'candlestick':
6868
collections = _construct_candlestick_collections(xdates, opens, highs, lows, closes,
6969
marketcolors=style['marketcolors'],config=config )
70+
71+
elif ptype =='hollow_candle':
72+
collections = _construct_hollow_candlestick_collections(xdates, opens, highs, lows, closes,
73+
marketcolors=style['marketcolors'],config=config )
74+
7075
elif ptype == 'ohlc' or ptype == 'bars' or ptype == 'ohlc_bars':
7176
collections = _construct_ohlc_collections(xdates, opens, highs, lows, closes,
7277
marketcolors=style['marketcolors'],config=config )
@@ -159,6 +164,18 @@ def _updown_colors(upcolor,downcolor,opens,closes,use_prev_close=False):
159164
_list = [ cmap[pre < cls] for cls,pre in zip(closes[1:], closes) ]
160165
return [first] + _list
161166

167+
168+
def _updownhollow_colors(upcolor,downcolor,uphollow,downhollow,opens,closes):
169+
if upcolor == downcolor == downhollow== uphollow:
170+
return upcolor
171+
cmap = {True : upcolor, False : downcolor}
172+
first = cmap[opens[0] < closes[0]]
173+
umap = {True : upcolor, False : uphollow}
174+
dmap = {True : downcolor, False : downhollow}
175+
_list = [ umap[cls > opn] if cls > cls0 else dmap[cls < opn] for opn0,cls0,opn,cls in zip(opens[0:-1],closes[0:-1],opens[1:],closes[1:]) ]
176+
return [first] + _list
177+
178+
162179
def _date_to_iloc(dtseries,date):
163180
d1s = dtseries.loc[date:]
164181
if len(d1s) < 1:
@@ -471,6 +488,93 @@ def _construct_candlestick_collections(dates, opens, highs, lows, closes, market
471488

472489
return [rangeCollection, barCollection]
473490

491+
492+
def _construct_hollow_candlestick_collections(dates, opens, highs, lows, closes, marketcolors=None, config=None):
493+
"""Represent the open, close as a bar line and high low range as a
494+
vertical line. Same as basic candlestick, but utilizes solid and hollow candlesticks
495+
496+
NOTE: this code assumes if any value open, low, high, close is
497+
missing they all are missing
498+
499+
500+
Parameters
501+
----------
502+
opens : sequence
503+
sequence of opening values
504+
highs : sequence
505+
sequence of high values
506+
lows : sequence
507+
sequence of low values
508+
closes : sequence
509+
sequence of closing values
510+
marketcolors : dict of colors: up, down, edge, wick, alpha
511+
alpha : float
512+
bar transparency
513+
514+
Returns
515+
-------
516+
ret : list
517+
(lineCollection, barCollection)
518+
"""
519+
520+
_check_input(opens, highs, lows, closes)
521+
522+
if marketcolors is None:
523+
marketcolors = _get_mpfstyle('classic')['marketcolors']
524+
#print('default market colors:',marketcolors)
525+
526+
datalen = len(dates)
527+
528+
avg_dist_between_points = (dates[-1] - dates[0]) / float(datalen)
529+
530+
delta = config['_width_config']['candle_width'] / 2.0
531+
532+
barVerts = [((date - delta, open),
533+
(date - delta, close),
534+
(date + delta, close),
535+
(date + delta, open))
536+
for date, open, close in zip(dates, opens, closes)]
537+
538+
rangeSegLow = [((date, low), (date, min(open,close)))
539+
for date, low, open, close in zip(dates, lows, opens, closes)]
540+
541+
rangeSegHigh = [((date, high), (date, max(open,close)))
542+
for date, high, open, close in zip(dates, highs, opens, closes)]
543+
544+
rangeSegments = rangeSegLow + rangeSegHigh
545+
546+
alpha = marketcolors['alpha']
547+
548+
uc = mcolors.to_rgba(marketcolors['candle'][ 'up' ], alpha)
549+
dc = mcolors.to_rgba(marketcolors['candle']['down'], alpha)
550+
uh = mcolors.to_rgba(marketcolors['candle']['up_hollow'], alpha)
551+
dh = mcolors.to_rgba(marketcolors['candle']['down_hollow'], alpha)
552+
colors = _updownhollow_colors(uc, dc, uh, dh, opens, closes)
553+
554+
uc = mcolors.to_rgba(marketcolors['edge'][ 'up' ], 1.0)
555+
dc = mcolors.to_rgba(marketcolors['edge']['down'], 1.0)
556+
edgecolor = _updownhollow_colors(uc, dc, uc, dc, opens, closes)
557+
558+
uc = mcolors.to_rgba(marketcolors['wick'][ 'up' ], 1.0)
559+
dc = mcolors.to_rgba(marketcolors['wick']['down'], 1.0)
560+
wickcolor = _updownhollow_colors(uc, dc, uc, dc, opens, closes)
561+
562+
lw = config['_width_config']['candle_linewidth']
563+
564+
rangeCollection = LineCollection(rangeSegments,
565+
colors=wickcolor,
566+
linewidths=lw,
567+
)
568+
569+
barCollection = PolyCollection(barVerts,
570+
facecolors=colors,
571+
edgecolors=edgecolor,
572+
linewidths=lw
573+
)
574+
575+
return [rangeCollection, barCollection]
576+
577+
474578
def _construct_renko_collections(dates, highs, lows, volumes, config_renko_params, closes, marketcolors=None):
475579
"""Represent the price change with bricks
476580

src/mplfinance/plotting.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def _valid_plot_kwargs():
100100
and all(isinstance(c, str) for c in value) },
101101
'type' : { 'Default' : 'ohlc',
102102
'Validator' : lambda value: value in ('candle','candlestick','ohlc','ohlc_bars',
103-
'line','renko','pnf') },
103+
'line','renko','pnf','hollow_candle') },
104104

105105
'style' : { 'Default' : None,
106106
'Validator' : _styles._valid_mpf_style },

0 commit comments

Comments
 (0)