Skip to content

Commit 1bf18a6

Browse files
Merge pull request #451 from AurumnPegasus/master
Set single candle color
2 parents d858138 + 28b05ca commit 1bf18a6

10 files changed

+1279
-34
lines changed

examples/marketcolor_overrides.ipynb

+831
Large diffs are not rendered by default.

examples/scratch_pad/pr451_test.py

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import pandas as pd
2+
import mplfinance as mpf
3+
import ast
4+
5+
df = pd.read_csv('pr451data.csv',index_col=0,parse_dates=True)
6+
7+
print(df.head(3))
8+
9+
custom_colors = []
10+
for i in range(len(df)):
11+
if i % 3 == 0:
12+
#custom_colors.append(mpf.make_marketcolors(up='#29c9ff', down='#f3b5ff', edge='#29c9ff', wick='#29c9ff', ohlc='#32a852', volume='#a89132'))
13+
custom_colors.append(mpf.make_marketcolors(up='#29c9ff',down='#f3b5ff',edge='#29c9ff',wick='#29c9ff',
14+
ohlc={'up':'lime','down':'blue'}, volume='#a89132'))
15+
elif i%5 == 0:
16+
custom_colors.append("#000000")
17+
else:
18+
custom_colors.append(None)
19+
20+
#STYLE = 'binance'
21+
STYLE = 'yahoo'
22+
23+
#mpf.plot(df, type='candle',style=STYLE,volume=True,block=False,figscale=1.25,savefig='pr451t2no.jpg')
24+
#mpf.plot(df, type='ohlc',style=STYLE,volume=True,block=False,figscale=1.25)
25+
mpf.plot(df, type='candle',style=STYLE,volume=True,block=False,figscale=1.25)
26+
#mpf.plot(df, type='hollow',style=STYLE,volume=True,block=False,figscale=1.25)
27+
28+
#mpf.plot(df, type='candle',style=STYLE,marketcolor_overrides=custom_colors,volume=True,figscale=1.25,savefig='pr451t2ye.jpg')
29+
#mpf.plot(df, type='ohlc',style=STYLE,marketcolor_overrides=custom_colors,volume=True,figscale=1.25)
30+
mpf.plot(df, type='candle',style=STYLE,marketcolor_overrides=custom_colors,volume=True,figscale=1.25)
31+
#mpf.plot(df, type='hollow',style=STYLE,marketcolor_overrides=custom_colors,volume=True,figscale=1.25)

examples/scratch_pad/pr451_testing.ipynb

+180
Large diffs are not rendered by default.

examples/scratch_pad/pr451data.csv

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
Date,Open,Close,High,Low,Date,Volume
2+
2019-09-01,29,20,29,20,2019-09-01,10787
3+
2019-09-02,29,31,33,23,2019-09-02,17215
4+
2019-09-03,29,20,29,20,2019-09-03,16697
5+
2019-09-04,24,16,24,15,2019-09-04,12104
6+
2019-09-05,23,20,25,15,2019-09-05,12159
7+
2019-09-06,22,24,24,20,2019-09-06,13618
8+
2019-09-07,19,15,22,14,2019-09-07,13645
9+
2019-09-08,13,13,15,13,2019-09-08,13472
10+
2019-09-09,20,16,20,14,2019-09-09,17861
11+
2019-09-10,17,25,25,16,2019-09-10,18565
12+
2019-09-11,30,24,30,23,2019-09-11,10283
13+
2019-09-12,24,25,26,19,2019-09-12,10102
14+
2019-09-13,22,22,26,21,2019-09-13,17100
15+
2019-09-14,27,28,28,21,2019-09-14,13079
16+
2019-09-15,26,29,29,26,2019-09-15,10800
17+
2019-09-16,30,23,30,21,2019-09-16,17927
18+
2019-09-17,30,27,30,26,2019-09-17,16355
19+
2019-09-18,22,27,29,22,2019-09-18,12066
20+
2019-09-19,19,23,23,18,2019-09-19,19733
21+
2019-09-20,21,14,24,14,2019-09-20,14761
22+
2019-09-21,24,23,24,19,2019-09-21,19410
23+
2019-09-22,15,25,25,15,2019-09-22,17238
24+
2019-09-23,23,20,26,18,2019-09-23,10840
25+
2019-09-24,18,25,26,17,2019-09-24,17668
26+
2019-09-25,23,28,29,23,2019-09-25,19267
27+
2019-09-26,30,26,31,26,2019-09-26,18340
28+
2019-09-27,33,28,37,27,2019-09-27,18905
29+
2019-09-28,26,25,34,25,2019-09-28,16682
30+
2019-09-29,31,27,32,24,2019-09-29,12605
31+
2019-09-30,30,31,32,23,2019-09-30,12702
32+
2019-10-01,37,31,38,29,2019-10-01,17485
33+
2019-10-02,41,39,42,39,2019-10-02,12198
34+
2019-10-03,39,45,46,37,2019-10-03,14923
35+
2019-10-04,41,48,50,41,2019-10-04,10326
36+
2019-10-05,41,44,47,40,2019-10-05,17738
37+
2019-10-06,47,49,52,46,2019-10-06,13330
38+
2019-10-07,47,45,48,38,2019-10-07,19102
39+
2019-10-08,43,44,45,39,2019-10-08,16682
40+
2019-10-09,40,32,41,32,2019-10-09,12813
41+
2019-10-10,46,38,46,36,2019-10-10,12306
42+
2019-10-11,44,42,45,38,2019-10-11,17205
43+
2019-10-12,44,44,44,35,2019-10-12,14736
44+
2019-10-13,39,41,42,34,2019-10-13,19296
45+
2019-10-14,34,31,34,31,2019-10-14,12587
46+
2019-10-15,32,31,33,31,2019-10-15,14709
47+
2019-10-16,42,36,43,36,2019-10-16,18555
48+
2019-10-17,43,40,43,40,2019-10-17,18850
49+
2019-10-18,37,41,41,37,2019-10-18,14650
50+
2019-10-19,31,37,38,31,2019-10-19,10405
51+
2019-10-20,26,34,35,26,2019-10-20,12074
52+
2019-10-21,34,30,34,26,2019-10-21,17407
53+
2019-10-22,23,32,32,22,2019-10-22,18649
54+
2019-10-23,20,23,27,18,2019-10-23,16161
55+
2019-10-24,20,18,20,18,2019-10-24,14008
56+
2019-10-25,20,21,25,19,2019-10-25,16251
57+
2019-10-26,19,17,24,17,2019-10-26,14594
58+
2019-10-27,29,20,29,19,2019-10-27,10994
59+
2019-10-28,28,26,30,23,2019-10-28,16978
60+
2019-10-29,30,22,30,22,2019-10-29,11373
61+
2019-10-30,18,26,28,18,2019-10-30,11589
62+
2019-10-31,26,21,31,21,2019-10-31,14787
63+
2019-11-01,19,25,26,18,2019-11-01,15088
64+
2019-11-02,25,26,27,22,2019-11-02,10827
65+
2019-11-03,24,28,28,22,2019-11-03,12281
66+
2019-11-04,24,15,24,15,2019-11-04,19768
67+
2019-11-05,22,17,23,15,2019-11-05,11398
68+
2019-11-06,20,23,25,18,2019-11-06,15819
69+
2019-11-07,20,26,26,17,2019-11-07,14057
70+
2019-11-08,15,14,24,14,2019-11-08,15366
71+
2019-11-09,11,12,18,11,2019-11-09,10403
72+
2019-11-10,16,13,20,13,2019-11-10,15611
73+
2019-11-11,18,15,18,10,2019-11-11,14544
74+
2019-11-12,18,11,19,11,2019-11-12,12009
75+
2019-11-13,16,16,22,14,2019-11-13,18481
76+
2019-11-14,14,11,20,11,2019-11-14,11876
77+
2019-11-15,21,16,23,15,2019-11-15,16481
78+
2019-11-16,23,23,23,15,2019-11-16,18562
79+
2019-11-17,26,18,26,17,2019-11-17,16095
80+
2019-11-18,24,24,26,21,2019-11-18,14052
81+
2019-11-19,30,23,31,22,2019-11-19,12698
82+
2019-11-20,27,25,32,22,2019-11-20,10097
83+
2019-11-21,24,28,30,22,2019-11-21,12405
84+
2019-11-22,18,22,23,18,2019-11-22,11883
85+
2019-11-23,18,21,22,17,2019-11-23,15834
86+
2019-11-24,21,18,24,18,2019-11-24,17172
87+
2019-11-25,24,15,25,15,2019-11-25,11327
88+
2019-11-26,27,25,27,17,2019-11-26,11876
89+
2019-11-27,30,24,32,23,2019-11-27,17715
90+
2019-11-28,28,22,28,19,2019-11-28,14520
91+
2019-11-29,14,16,19,13,2019-11-29,18113
92+
2019-11-30,22,19,23,19,2019-11-30,16670
93+
2019-12-01,31,26,32,25,2019-12-01,15978
94+
2019-12-02,29,26,30,26,2019-12-02,15367
95+
2019-12-03,28,28,28,28,2019-12-03,18364
96+
2019-12-04,27,27,28,27,2019-12-04,17550
97+
2019-12-05,37,41,42,34,2019-12-05,16636
98+
2019-12-06,31,28,36,28,2019-12-06,15326
99+
2019-12-07,33,28,36,28,2019-12-07,15007
100+
2019-12-08,37,38,38,35,2019-12-08,16018
101+
2019-12-09,44,43,44,43,2019-12-09,17392
102+
2019-12-10,36,40,40,33,2019-12-10,17550
103+
2019-12-11,27,35,36,26,2019-12-11,13408
104+
2019-12-12,32,24,32,23,2019-12-12,19170
105+
2019-12-13,29,34,34,29,2019-12-13,12548
106+
2019-12-14,34,31,36,28,2019-12-14,19605
107+
2019-12-15,33,31,37,31,2019-12-15,14594
108+
2019-12-16,43,43,43,39,2019-12-16,16895
109+
2019-12-17,50,40,50,40,2019-12-17,18880
110+
2019-12-18,42,48,48,39,2019-12-18,18207
111+
2019-12-19,44,39,49,39,2019-12-19,17279
112+
2019-12-20,53,46,53,45,2019-12-20,11028
113+
2019-12-21,51,44,51,43,2019-12-21,19840
114+
2019-12-22,44,49,49,41,2019-12-22,10863
115+
2019-12-23,43,40,45,38,2019-12-23,13153
116+
2019-12-24,50,42,50,40,2019-12-24,16929
117+
2019-12-25,51,42,52,42,2019-12-25,17419
118+
2019-12-26,49,56,56,49,2019-12-26,13232
119+
2019-12-27,47,48,50,45,2019-12-27,19252
120+
2019-12-28,54,53,54,53,2019-12-28,11631
121+
2019-12-29,46,53,53,46,2019-12-29,14527
122+
2019-12-30,46,46,55,46,2019-12-30,10600
123+
2019-12-31,54,58,59,53,2019-12-31,17911
124+
2020-01-01,55,48,56,47,2020-01-01,17827

src/mplfinance/_arg_validators.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import pandas as pd
33
import numpy as np
44
import datetime
5-
from mplfinance._helpers import _list_of_dict
5+
from mplfinance._helpers import _list_of_dict, _mpf_is_color_like
66
import matplotlib as mpl
77
import warnings
88

@@ -359,6 +359,25 @@ def _yscale_validator(value):
359359
return True
360360

361361

362+
def _is_marketcolor_object(obj):
363+
if not isinstance(obj,dict): return False
364+
market_colors_keys = ('candle','edge','wick','ohlc')
365+
return all([k in obj for k in market_colors_keys])
366+
367+
368+
def _mco_validator(value): # marketcolor overrides validator
369+
if isinstance(value,dict): # not yet supported, but maybe we will have other
370+
if 'colors' not in value: # kwargs related to mktcolor overrides (ex: `mco_faceonly`)
371+
raise ValueError('`marketcolor_overrides` as dict must contain `colors` key.')
372+
colors = value['colors']
373+
else:
374+
colors = value
375+
if not isinstance(colors,(list,tuple,np.ndarray)):
376+
return False
377+
return all([(c is None or
378+
_mpf_is_color_like(c) or
379+
_is_marketcolor_object(c) ) for c in colors])
380+
362381
def _check_for_external_axes(config):
363382
'''
364383
Check that all `fig` and `ax` kwargs are either ALL None,

src/mplfinance/_helpers.py

+38-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
"""
22
Some helper functions for mplfinance.
3+
NOTE: This is the lowest level in mplfinance:
4+
This file should have NO dependencies on
5+
any other mplfinance files.
36
"""
47

58
import datetime
6-
import matplotlib.dates as mdates
9+
import matplotlib.dates as mdates
10+
import matplotlib.colors as mcolors
711
import numpy as np
812

913
def _adjust_color_brightness(color,amount=0.5):
@@ -82,3 +86,36 @@ def roundTime(dt=None, roundTo=60):
8286
seconds = (dt.replace(tzinfo=None) - dt.min).seconds
8387
rounding = (seconds+roundTo/2) // roundTo * roundTo
8488
return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond)
89+
90+
91+
def _is_uint8_rgb_or_rgba(tup):
92+
""" Deterine if rgb or rgba is in (0-255) format:
93+
Matplotlib expects rgb (and rgba) tuples to contain
94+
three (or four) floats between 0.0 and 1.0
95+
96+
Some people express rgb as tuples of three integers
97+
between 0 and 255.
98+
(In rgba, alpha is still a float from 0.0 to 1.0)
99+
"""
100+
if isinstance(tup,str): return False
101+
if not np.iterable(tup): return False
102+
L = len(tup)
103+
if L < 3 or L > 4: return False
104+
if L == 4 and (tup[3] < 0 or tup[3] > 1): return False
105+
return not any([not isinstance(v,(int,np.unsignedinteger)) or v<0 or v>255 for v in tup[0:3]])
106+
107+
def _mpf_is_color_like(c):
108+
"""Determine if an object is a color.
109+
110+
Identical to `matplotlib.colors.is_color_like()`
111+
BUT ALSO considers int (0-255) rgb and rgba colors.
112+
"""
113+
if mcolors.is_color_like(c): return True
114+
return _is_uint8_rgb_or_rgba(c)
115+
116+
def _mpf_to_rgba(c, alpha=None):
117+
cnew = c
118+
if _is_uint8_rgb_or_rgba(c) and any(e>1 for e in c[:3]):
119+
cnew = tuple([e/255. for e in c[:3]])
120+
if len(c) == 4: cnew += c[3:]
121+
return mcolors.to_rgba(cnew, alpha)

src/mplfinance/_styles.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import matplotlib.pyplot as plt
2-
import matplotlib.colors as mcolors
32
import copy
43
import pprint
54
import os.path as path
65

76
from mplfinance._arg_validators import _process_kwargs, _validate_vkwargs_dict
87
from mplfinance._styledata import _styles
8+
from mplfinance._helpers import _mpf_is_color_like
99

1010

1111
def _get_mpfstyle(style):
@@ -70,7 +70,7 @@ def _valid_make_mpf_style_kwargs():
7070
'Validator' : lambda value: isinstance(value,dict) },
7171

7272
'mavcolors' : { 'Default' : None,
73-
'Validator' : lambda value: isinstance(value,list) }, # TODO: all([mcolors.is_color_like(v) for v in value.values()])
73+
'Validator' : lambda value: isinstance(value,list) }, # TODO: all([_mpf_is_color_like(v) for v in value.values()])
7474

7575
'facecolor' : { 'Default' : None,
7676
'Validator' : lambda value: isinstance(value,str) },
@@ -153,10 +153,10 @@ def make_mpf_style( **kwargs ):
153153

154154
def _valid_mpf_color_spec(value):
155155
'value must be a color, "inherit"-like, or dict of colors'
156-
return ( mcolors.is_color_like(value) or
156+
return ( _mpf_is_color_like(value) or
157157
( isinstance(value,str) and value == 'inherit'[0:len(value)]) or
158158
( isinstance(value,dict) and
159-
all([mcolors.is_color_like(v) for v in value.values()])
159+
all([_mpf_is_color_like(v) for v in value.values()])
160160
)
161161
)
162162

@@ -190,13 +190,13 @@ def _valid_mpf_style(value):
190190
def _valid_make_marketcolors_kwargs():
191191
vkwargs = {
192192
'up' : { 'Default' : None,
193-
'Validator' : lambda value: mcolors.is_color_like(value) },
193+
'Validator' : lambda value: _mpf_is_color_like(value) },
194194

195195
'down' : { 'Default' : None,
196-
'Validator' : lambda value: mcolors.is_color_like(value) },
196+
'Validator' : lambda value: _mpf_is_color_like(value) },
197197

198198
'hollow' : { 'Default' : None,
199-
'Validator' : lambda value: mcolors.is_color_like(value) },
199+
'Validator' : lambda value: _mpf_is_color_like(value) },
200200

201201
'alpha' : { 'Default' : None,
202202
'Validator' : lambda value: ( isinstance(value,float) and
@@ -208,17 +208,17 @@ def _valid_make_marketcolors_kwargs():
208208
'wick' : { 'Default' : None,
209209
'Validator' : lambda value: isinstance(value,dict)
210210
or isinstance(value,str)
211-
or mcolors.is_color_like(value) },
211+
or _mpf_is_color_like(value) },
212212

213213
'ohlc' : { 'Default' : None,
214214
'Validator' : lambda value: isinstance(value,dict)
215215
or isinstance(value,str)
216-
or mcolors.is_color_like(value) },
216+
or _mpf_is_color_like(value) },
217217

218218
'volume' : { 'Default' : None,
219219
'Validator' : lambda value: isinstance(value,dict)
220220
or isinstance(value,str)
221-
or mcolors.is_color_like(value) },
221+
or _mpf_is_color_like(value) },
222222

223223
'vcdopcod' : { 'Default' : False,
224224
'Validator' : lambda value: isinstance(value,bool) },
@@ -282,7 +282,7 @@ def _check_and_set_mktcolor(candle,**kwarg):
282282
else:
283283
colors = dict(up=value, down=value)
284284
for updown in ['up','down']:
285-
if not mcolors.is_color_like(colors[updown]):
285+
if not _mpf_is_color_like(colors[updown]):
286286
err = f'NOT is_color_like() for {key}[\'{updown}\'] = {colors[updown]}'
287287
raise ValueError(err)
288288
return colors

0 commit comments

Comments
 (0)