Skip to content

Commit

Permalink
Merge pull request #451 from AurumnPegasus/master
Browse files Browse the repository at this point in the history
Set single candle color
  • Loading branch information
DanielGoldfarb authored Dec 14, 2021
2 parents d858138 + 28b05ca commit 1bf18a6
Show file tree
Hide file tree
Showing 10 changed files with 1,279 additions and 34 deletions.
831 changes: 831 additions & 0 deletions examples/marketcolor_overrides.ipynb

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions examples/scratch_pad/pr451_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import pandas as pd
import mplfinance as mpf
import ast

df = pd.read_csv('pr451data.csv',index_col=0,parse_dates=True)

print(df.head(3))

custom_colors = []
for i in range(len(df)):
if i % 3 == 0:
#custom_colors.append(mpf.make_marketcolors(up='#29c9ff', down='#f3b5ff', edge='#29c9ff', wick='#29c9ff', ohlc='#32a852', volume='#a89132'))
custom_colors.append(mpf.make_marketcolors(up='#29c9ff',down='#f3b5ff',edge='#29c9ff',wick='#29c9ff',
ohlc={'up':'lime','down':'blue'}, volume='#a89132'))
elif i%5 == 0:
custom_colors.append("#000000")
else:
custom_colors.append(None)

#STYLE = 'binance'
STYLE = 'yahoo'

#mpf.plot(df, type='candle',style=STYLE,volume=True,block=False,figscale=1.25,savefig='pr451t2no.jpg')
#mpf.plot(df, type='ohlc',style=STYLE,volume=True,block=False,figscale=1.25)
mpf.plot(df, type='candle',style=STYLE,volume=True,block=False,figscale=1.25)
#mpf.plot(df, type='hollow',style=STYLE,volume=True,block=False,figscale=1.25)

#mpf.plot(df, type='candle',style=STYLE,marketcolor_overrides=custom_colors,volume=True,figscale=1.25,savefig='pr451t2ye.jpg')
#mpf.plot(df, type='ohlc',style=STYLE,marketcolor_overrides=custom_colors,volume=True,figscale=1.25)
mpf.plot(df, type='candle',style=STYLE,marketcolor_overrides=custom_colors,volume=True,figscale=1.25)
#mpf.plot(df, type='hollow',style=STYLE,marketcolor_overrides=custom_colors,volume=True,figscale=1.25)
180 changes: 180 additions & 0 deletions examples/scratch_pad/pr451_testing.ipynb

Large diffs are not rendered by default.

124 changes: 124 additions & 0 deletions examples/scratch_pad/pr451data.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
Date,Open,Close,High,Low,Date,Volume
2019-09-01,29,20,29,20,2019-09-01,10787
2019-09-02,29,31,33,23,2019-09-02,17215
2019-09-03,29,20,29,20,2019-09-03,16697
2019-09-04,24,16,24,15,2019-09-04,12104
2019-09-05,23,20,25,15,2019-09-05,12159
2019-09-06,22,24,24,20,2019-09-06,13618
2019-09-07,19,15,22,14,2019-09-07,13645
2019-09-08,13,13,15,13,2019-09-08,13472
2019-09-09,20,16,20,14,2019-09-09,17861
2019-09-10,17,25,25,16,2019-09-10,18565
2019-09-11,30,24,30,23,2019-09-11,10283
2019-09-12,24,25,26,19,2019-09-12,10102
2019-09-13,22,22,26,21,2019-09-13,17100
2019-09-14,27,28,28,21,2019-09-14,13079
2019-09-15,26,29,29,26,2019-09-15,10800
2019-09-16,30,23,30,21,2019-09-16,17927
2019-09-17,30,27,30,26,2019-09-17,16355
2019-09-18,22,27,29,22,2019-09-18,12066
2019-09-19,19,23,23,18,2019-09-19,19733
2019-09-20,21,14,24,14,2019-09-20,14761
2019-09-21,24,23,24,19,2019-09-21,19410
2019-09-22,15,25,25,15,2019-09-22,17238
2019-09-23,23,20,26,18,2019-09-23,10840
2019-09-24,18,25,26,17,2019-09-24,17668
2019-09-25,23,28,29,23,2019-09-25,19267
2019-09-26,30,26,31,26,2019-09-26,18340
2019-09-27,33,28,37,27,2019-09-27,18905
2019-09-28,26,25,34,25,2019-09-28,16682
2019-09-29,31,27,32,24,2019-09-29,12605
2019-09-30,30,31,32,23,2019-09-30,12702
2019-10-01,37,31,38,29,2019-10-01,17485
2019-10-02,41,39,42,39,2019-10-02,12198
2019-10-03,39,45,46,37,2019-10-03,14923
2019-10-04,41,48,50,41,2019-10-04,10326
2019-10-05,41,44,47,40,2019-10-05,17738
2019-10-06,47,49,52,46,2019-10-06,13330
2019-10-07,47,45,48,38,2019-10-07,19102
2019-10-08,43,44,45,39,2019-10-08,16682
2019-10-09,40,32,41,32,2019-10-09,12813
2019-10-10,46,38,46,36,2019-10-10,12306
2019-10-11,44,42,45,38,2019-10-11,17205
2019-10-12,44,44,44,35,2019-10-12,14736
2019-10-13,39,41,42,34,2019-10-13,19296
2019-10-14,34,31,34,31,2019-10-14,12587
2019-10-15,32,31,33,31,2019-10-15,14709
2019-10-16,42,36,43,36,2019-10-16,18555
2019-10-17,43,40,43,40,2019-10-17,18850
2019-10-18,37,41,41,37,2019-10-18,14650
2019-10-19,31,37,38,31,2019-10-19,10405
2019-10-20,26,34,35,26,2019-10-20,12074
2019-10-21,34,30,34,26,2019-10-21,17407
2019-10-22,23,32,32,22,2019-10-22,18649
2019-10-23,20,23,27,18,2019-10-23,16161
2019-10-24,20,18,20,18,2019-10-24,14008
2019-10-25,20,21,25,19,2019-10-25,16251
2019-10-26,19,17,24,17,2019-10-26,14594
2019-10-27,29,20,29,19,2019-10-27,10994
2019-10-28,28,26,30,23,2019-10-28,16978
2019-10-29,30,22,30,22,2019-10-29,11373
2019-10-30,18,26,28,18,2019-10-30,11589
2019-10-31,26,21,31,21,2019-10-31,14787
2019-11-01,19,25,26,18,2019-11-01,15088
2019-11-02,25,26,27,22,2019-11-02,10827
2019-11-03,24,28,28,22,2019-11-03,12281
2019-11-04,24,15,24,15,2019-11-04,19768
2019-11-05,22,17,23,15,2019-11-05,11398
2019-11-06,20,23,25,18,2019-11-06,15819
2019-11-07,20,26,26,17,2019-11-07,14057
2019-11-08,15,14,24,14,2019-11-08,15366
2019-11-09,11,12,18,11,2019-11-09,10403
2019-11-10,16,13,20,13,2019-11-10,15611
2019-11-11,18,15,18,10,2019-11-11,14544
2019-11-12,18,11,19,11,2019-11-12,12009
2019-11-13,16,16,22,14,2019-11-13,18481
2019-11-14,14,11,20,11,2019-11-14,11876
2019-11-15,21,16,23,15,2019-11-15,16481
2019-11-16,23,23,23,15,2019-11-16,18562
2019-11-17,26,18,26,17,2019-11-17,16095
2019-11-18,24,24,26,21,2019-11-18,14052
2019-11-19,30,23,31,22,2019-11-19,12698
2019-11-20,27,25,32,22,2019-11-20,10097
2019-11-21,24,28,30,22,2019-11-21,12405
2019-11-22,18,22,23,18,2019-11-22,11883
2019-11-23,18,21,22,17,2019-11-23,15834
2019-11-24,21,18,24,18,2019-11-24,17172
2019-11-25,24,15,25,15,2019-11-25,11327
2019-11-26,27,25,27,17,2019-11-26,11876
2019-11-27,30,24,32,23,2019-11-27,17715
2019-11-28,28,22,28,19,2019-11-28,14520
2019-11-29,14,16,19,13,2019-11-29,18113
2019-11-30,22,19,23,19,2019-11-30,16670
2019-12-01,31,26,32,25,2019-12-01,15978
2019-12-02,29,26,30,26,2019-12-02,15367
2019-12-03,28,28,28,28,2019-12-03,18364
2019-12-04,27,27,28,27,2019-12-04,17550
2019-12-05,37,41,42,34,2019-12-05,16636
2019-12-06,31,28,36,28,2019-12-06,15326
2019-12-07,33,28,36,28,2019-12-07,15007
2019-12-08,37,38,38,35,2019-12-08,16018
2019-12-09,44,43,44,43,2019-12-09,17392
2019-12-10,36,40,40,33,2019-12-10,17550
2019-12-11,27,35,36,26,2019-12-11,13408
2019-12-12,32,24,32,23,2019-12-12,19170
2019-12-13,29,34,34,29,2019-12-13,12548
2019-12-14,34,31,36,28,2019-12-14,19605
2019-12-15,33,31,37,31,2019-12-15,14594
2019-12-16,43,43,43,39,2019-12-16,16895
2019-12-17,50,40,50,40,2019-12-17,18880
2019-12-18,42,48,48,39,2019-12-18,18207
2019-12-19,44,39,49,39,2019-12-19,17279
2019-12-20,53,46,53,45,2019-12-20,11028
2019-12-21,51,44,51,43,2019-12-21,19840
2019-12-22,44,49,49,41,2019-12-22,10863
2019-12-23,43,40,45,38,2019-12-23,13153
2019-12-24,50,42,50,40,2019-12-24,16929
2019-12-25,51,42,52,42,2019-12-25,17419
2019-12-26,49,56,56,49,2019-12-26,13232
2019-12-27,47,48,50,45,2019-12-27,19252
2019-12-28,54,53,54,53,2019-12-28,11631
2019-12-29,46,53,53,46,2019-12-29,14527
2019-12-30,46,46,55,46,2019-12-30,10600
2019-12-31,54,58,59,53,2019-12-31,17911
2020-01-01,55,48,56,47,2020-01-01,17827
21 changes: 20 additions & 1 deletion src/mplfinance/_arg_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import pandas as pd
import numpy as np
import datetime
from mplfinance._helpers import _list_of_dict
from mplfinance._helpers import _list_of_dict, _mpf_is_color_like
import matplotlib as mpl
import warnings

Expand Down Expand Up @@ -359,6 +359,25 @@ def _yscale_validator(value):
return True


def _is_marketcolor_object(obj):
if not isinstance(obj,dict): return False
market_colors_keys = ('candle','edge','wick','ohlc')
return all([k in obj for k in market_colors_keys])


def _mco_validator(value): # marketcolor overrides validator
if isinstance(value,dict): # not yet supported, but maybe we will have other
if 'colors' not in value: # kwargs related to mktcolor overrides (ex: `mco_faceonly`)
raise ValueError('`marketcolor_overrides` as dict must contain `colors` key.')
colors = value['colors']
else:
colors = value
if not isinstance(colors,(list,tuple,np.ndarray)):
return False
return all([(c is None or
_mpf_is_color_like(c) or
_is_marketcolor_object(c) ) for c in colors])

def _check_for_external_axes(config):
'''
Check that all `fig` and `ax` kwargs are either ALL None,
Expand Down
39 changes: 38 additions & 1 deletion src/mplfinance/_helpers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
"""
Some helper functions for mplfinance.
NOTE: This is the lowest level in mplfinance:
This file should have NO dependencies on
any other mplfinance files.
"""

import datetime
import matplotlib.dates as mdates
import matplotlib.dates as mdates
import matplotlib.colors as mcolors
import numpy as np

def _adjust_color_brightness(color,amount=0.5):
Expand Down Expand Up @@ -82,3 +86,36 @@ def roundTime(dt=None, roundTo=60):
seconds = (dt.replace(tzinfo=None) - dt.min).seconds
rounding = (seconds+roundTo/2) // roundTo * roundTo
return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond)


def _is_uint8_rgb_or_rgba(tup):
""" Deterine if rgb or rgba is in (0-255) format:
Matplotlib expects rgb (and rgba) tuples to contain
three (or four) floats between 0.0 and 1.0
Some people express rgb as tuples of three integers
between 0 and 255.
(In rgba, alpha is still a float from 0.0 to 1.0)
"""
if isinstance(tup,str): return False
if not np.iterable(tup): return False
L = len(tup)
if L < 3 or L > 4: return False
if L == 4 and (tup[3] < 0 or tup[3] > 1): return False
return not any([not isinstance(v,(int,np.unsignedinteger)) or v<0 or v>255 for v in tup[0:3]])

def _mpf_is_color_like(c):
"""Determine if an object is a color.
Identical to `matplotlib.colors.is_color_like()`
BUT ALSO considers int (0-255) rgb and rgba colors.
"""
if mcolors.is_color_like(c): return True
return _is_uint8_rgb_or_rgba(c)

def _mpf_to_rgba(c, alpha=None):
cnew = c
if _is_uint8_rgb_or_rgba(c) and any(e>1 for e in c[:3]):
cnew = tuple([e/255. for e in c[:3]])
if len(c) == 4: cnew += c[3:]
return mcolors.to_rgba(cnew, alpha)
22 changes: 11 additions & 11 deletions src/mplfinance/_styles.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import copy
import pprint
import os.path as path

from mplfinance._arg_validators import _process_kwargs, _validate_vkwargs_dict
from mplfinance._styledata import _styles
from mplfinance._helpers import _mpf_is_color_like


def _get_mpfstyle(style):
Expand Down Expand Up @@ -70,7 +70,7 @@ def _valid_make_mpf_style_kwargs():
'Validator' : lambda value: isinstance(value,dict) },

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

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

def _valid_mpf_color_spec(value):
'value must be a color, "inherit"-like, or dict of colors'
return ( mcolors.is_color_like(value) or
return ( _mpf_is_color_like(value) or
( isinstance(value,str) and value == 'inherit'[0:len(value)]) or
( isinstance(value,dict) and
all([mcolors.is_color_like(v) for v in value.values()])
all([_mpf_is_color_like(v) for v in value.values()])
)
)

Expand Down Expand Up @@ -190,13 +190,13 @@ def _valid_mpf_style(value):
def _valid_make_marketcolors_kwargs():
vkwargs = {
'up' : { 'Default' : None,
'Validator' : lambda value: mcolors.is_color_like(value) },
'Validator' : lambda value: _mpf_is_color_like(value) },

'down' : { 'Default' : None,
'Validator' : lambda value: mcolors.is_color_like(value) },
'Validator' : lambda value: _mpf_is_color_like(value) },

'hollow' : { 'Default' : None,
'Validator' : lambda value: mcolors.is_color_like(value) },
'Validator' : lambda value: _mpf_is_color_like(value) },

'alpha' : { 'Default' : None,
'Validator' : lambda value: ( isinstance(value,float) and
Expand All @@ -208,17 +208,17 @@ def _valid_make_marketcolors_kwargs():
'wick' : { 'Default' : None,
'Validator' : lambda value: isinstance(value,dict)
or isinstance(value,str)
or mcolors.is_color_like(value) },
or _mpf_is_color_like(value) },

'ohlc' : { 'Default' : None,
'Validator' : lambda value: isinstance(value,dict)
or isinstance(value,str)
or mcolors.is_color_like(value) },
or _mpf_is_color_like(value) },

'volume' : { 'Default' : None,
'Validator' : lambda value: isinstance(value,dict)
or isinstance(value,str)
or mcolors.is_color_like(value) },
or _mpf_is_color_like(value) },

'vcdopcod' : { 'Default' : False,
'Validator' : lambda value: isinstance(value,bool) },
Expand Down Expand Up @@ -282,7 +282,7 @@ def _check_and_set_mktcolor(candle,**kwarg):
else:
colors = dict(up=value, down=value)
for updown in ['up','down']:
if not mcolors.is_color_like(colors[updown]):
if not _mpf_is_color_like(colors[updown]):
err = f'NOT is_color_like() for {key}[\'{updown}\'] = {colors[updown]}'
raise ValueError(err)
return colors
Expand Down
Loading

0 comments on commit 1bf18a6

Please sign in to comment.