diff --git a/.gitignore b/.gitignore index d84d5b9d..f9b2210e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ __pycache__ .tox/ .cache/ *.code-workspace +examples/.ipynb_checkpoints/ +examples/scratch_pad/.ipynb_checkpoints/ diff --git a/TODO.md b/TODO.md index 80db8a95..0d0b5bb2 100644 --- a/TODO.md +++ b/TODO.md @@ -9,5 +9,6 @@ - documentation (replace old `https://matplotlib.org/api/finance_api.html`) - make code more efficient (ex: tlines reconstructing data frame). - **daily plot slower than intraday ???** -- add 'description' to valid kwargs table, and kwarg to print all kwargs information (kwarg and short description). +- add kwarg to print all kwargs information (kwarg and short description). +- fill the 'Description' fields in the kwarg dicts of these functions: `egrep -i 'def .*valid.*kwarg' *.py` diff --git a/examples/scratch_pad/fmtr.py b/examples/scratch_pad/fmtr.py new file mode 100644 index 00000000..a6bfd763 --- /dev/null +++ b/examples/scratch_pad/fmtr.py @@ -0,0 +1,116 @@ +#################################################################### +# +# https://stackoverflow.com/questions/25777037/how-can-i-left-justify-text-in-a-pandas-dataframe-column-in-an-ipython-notebook +# +#################################################################### + +import mplfinance as mpf +import pandas as pd +import textwrap + +vk = mpf.plotting._valid_plot_kwargs() + +df = (pd.DataFrame(vk).T.head(18)).drop('Validator',axis=1) + +df['Kwarg'] = df.index.values +df['Default'] = ["'"+d+"'" if isinstance(d,str) else str(d) for d in df['Default']] + +df = df[['Kwarg','Default','Description']] +df = df.head(5).append(df.tail(7)) + +# df.sort_index(inplace=True) + +df + +print('===========================') + +print(df) + +print('===========================') + +def make_left_formatter(maxwidth): + wm3 = maxwidth-3 + w = maxwidth + def left_formatter(value): + if not isinstance(value,str): + return f'{value:<}' + elif value[0:maxwidth] == '-'*maxwidth: + return f'{value:<{w}.{w}s}' + #elif len(value) > maxwidth and value[0:maxwidth] != '-'*maxwidth: + elif len(value) > maxwidth: + return f'{value:<{wm3}.{wm3}s}...' + else: + return f'{value:<{w}.{w}s}' + return left_formatter + +def df_wrapcols(df,wrap_columns=None): + + if wrap_columns is None: return df + if not isinstance(wrap_columns,dict): + raise TypeError('wrap_columns must be a dict of column_names and wrap_lengths') + + for col in wrap_columns: + if col not in df.columns: + raise ValueError('column "'+str(col)+'" not found in df.columns') + + index = [] + column_data = {} + for col in df.columns: + column_data[col] = [] + + for ix in df.index: + row = df.loc[ix,] + + row_data = {} + for col in row.index: + cstr = str(row[col]) + if col in wrap_columns: + wlen = wrap_columns[col] + tw = textwrap.wrap(cstr,wlen) if not cstr.isspace() else [' '] + else: + tw = [cstr] + row_data[col] = tw + + cmax = max(row_data,key=lambda k: len(row_data[k])) + rlen = len(row_data[cmax]) + for r in range(rlen): + for col in row.index: + extension = [' ']*(rlen - len(row_data[col])) + row_data[col].extend(extension) + column_data[col].append(row_data[col][r]) + ixstr = str(ix)+'.'+str(r) if r > 0 else str(ix) + index.append(ixstr) + + return pd.DataFrame(column_data,index=index) + +WRAPLEN = 55 + +df = df_wrapcols(df,wrap_columns={'Description':WRAPLEN}) +print('===========================') +print('dfnew1=',df) + + +# print('===========================') +# df.columns = [ ' '+col for col in df.columns ] + +dividers = [] +for col in df.columns: + dividers.append('-'*int(df[col].str.len().max())) +dfd = pd.DataFrame(dividers).T +dfd.columns = df.columns +dfd.index = pd.Index(['---']) + +print('===========================') + +df = dfd.append(df) + +fmts = {'Kwarg': make_left_formatter(df['Kwarg'].str.len().max()+1), + 'Description': make_left_formatter(WRAPLEN), + 'Default': make_left_formatter(8), + } +s = df.to_string(formatters=fmts,index=False,justify='left') + +print('\n ',s.replace('\n','\n ')) + +print('===========================') + diff --git a/src/mplfinance/__init__.py b/src/mplfinance/__init__.py index 17d5b739..f1e1865c 100644 --- a/src/mplfinance/__init__.py +++ b/src/mplfinance/__init__.py @@ -1,6 +1,7 @@ import mplfinance._mpf_warnings -from mplfinance.plotting import plot, make_addplot -from mplfinance._styles import make_mpf_style, make_marketcolors -from mplfinance._styles import available_styles, write_style_file -from mplfinance._version import __version__ -from mplfinance._mplwraps import figure, show +from mplfinance.plotting import plot, make_addplot +from mplfinance._styles import make_mpf_style, make_marketcolors +from mplfinance._styles import available_styles, write_style_file +from mplfinance._version import __version__ +from mplfinance._mplwraps import figure, show +from mplfinance._kwarg_help import kwarg_help diff --git a/src/mplfinance/_arg_validators.py b/src/mplfinance/_arg_validators.py index e38bbeac..268fe855 100644 --- a/src/mplfinance/_arg_validators.py +++ b/src/mplfinance/_arg_validators.py @@ -274,13 +274,20 @@ def _kwarg_not_implemented(value): raise NotImplementedError('kwarg NOT implemented.') def _validate_vkwargs_dict(vkwargs): - # Check that we didn't make a typo in any of the things - # that should be the same for all vkwargs dict items: + """ + Check that we didn't make a typo in any of the things + that should be the same for all vkwargs dict items: + + {kwarg : {'Default': ... , 'Description': ... , 'Validator': ...} } + """ for key, value in vkwargs.items(): - if len(value) != 2: - raise ValueError('Items != 2 in valid kwarg table, for kwarg "'+key+'"') + # has been changed to 3 to support descriptions + if len(value) != 3: + raise ValueError('Items != 3 in valid kwarg table, for kwarg "'+key+'"') if 'Default' not in value: raise ValueError('Missing "Default" value for kwarg "'+key+'"') + if 'Description' not in value: + raise ValueError('Missing "Description" value for kwarg "'+key+'"') if 'Validator' not in value: raise ValueError('Missing "Validator" function for kwarg "'+key+'"') diff --git a/src/mplfinance/_kwarg_help.py b/src/mplfinance/_kwarg_help.py new file mode 100644 index 00000000..ee5e70ca --- /dev/null +++ b/src/mplfinance/_kwarg_help.py @@ -0,0 +1,153 @@ +import mplfinance as mpf +import pandas as pd +import textwrap + +def df_wrapcols(df,wrap_columns=None): + + if wrap_columns is None: return df + if not isinstance(wrap_columns,dict): + raise TypeError('wrap_columns must be a dict of column_names and wrap_lengths') + + for col in wrap_columns: + if col not in df.columns: + raise ValueError('column "'+str(col)+'" not found in df.columns') + + index = [] + column_data = {} + for col in df.columns: + column_data[col] = [] + + for ix in df.index: + row = df.loc[ix,] + + row_data = {} + for col in row.index: + cstr = str(row[col]) + if col in wrap_columns: + wlen = wrap_columns[col] + tw = textwrap.wrap(cstr,wlen) if not cstr.isspace() else [' '] + else: + tw = [cstr] + row_data[col] = tw + + cmax = max(row_data,key=lambda k: len(row_data[k])) + rlen = len(row_data[cmax]) + for r in range(rlen): + for col in row.index: + extension = [' ']*(rlen - len(row_data[col])) + row_data[col].extend(extension) + column_data[col].append(row_data[col][r]) + ixstr = str(ix)+'.'+str(r) if r > 0 else str(ix) + index.append(ixstr) + + return pd.DataFrame(column_data,index=index) + +def make_left_formatter(maxwidth): + wm3 = maxwidth-3 + w = maxwidth + def left_formatter(value): + if not isinstance(value,str): + return f'{value:<}' + elif value[0:maxwidth] == '-'*maxwidth: + return f'{value:<{w}.{w}s}' + elif len(value) > maxwidth: + return f'{value:<{wm3}.{wm3}s}...' + else: + return f'{value:<{w}.{w}s}' + return left_formatter + + +def kwarg_help( func_name=None, kwarg_names=None ): + + func_kwarg_map = { + 'plot' : mpf.plotting._valid_plot_kwargs, + 'make_addplot' : mpf.plotting._valid_addplot_kwargs, + 'make_marketcolors' : mpf._styles._valid_make_marketcolors_kwargs, + 'make_mpf_style' : mpf._styles._valid_make_mpf_style_kwargs, + 'renko_params' : mpf._utils._valid_renko_kwargs, + 'pnf_params' : mpf._utils._valid_pnf_kwargs, + 'lines' : mpf._utils._valid_lines_kwargs, + 'scale_width_adjustment': mpf._widths._valid_scale_width_kwargs, + 'update_width_config': mpf._widths._valid_update_width_kwargs, + } + + func_kwarg_aliases = { + 'addplot' : mpf.plotting._valid_addplot_kwargs, + 'marketcolors' : mpf._styles._valid_make_marketcolors_kwargs, + 'mpf_style' : mpf._styles._valid_make_mpf_style_kwargs, + 'style' : mpf._styles._valid_make_mpf_style_kwargs, + 'renko' : mpf._utils._valid_renko_kwargs, + 'pnf' : mpf._utils._valid_pnf_kwargs, + 'hlines' : mpf._utils._valid_lines_kwargs, + 'alines' : mpf._utils._valid_lines_kwargs, + 'tlines' : mpf._utils._valid_lines_kwargs, + 'vlines' : mpf._utils._valid_lines_kwargs, + } + + if func_name is None: + print('\nUsage: `kwarg_help(func_name)` or `kwarg_help(func_name,kwarg_names)`') + print(' kwarg_help is available for the following func_names:') + s = str(list(func_kwarg_map.keys())) + text = textwrap.wrap(s,68) + for t in text: + print(' ',t) + print() + return + + fkmap = {**func_kwarg_map, **func_kwarg_aliases} + + if func_name not in fkmap: + raise ValueError('Function name "'+func_name+'" NOT a valid function name') + + if kwarg_names is not None and isinstance(kwarg_names,str): + kwarg_names = [ kwarg_names, ] + + if ( kwarg_names is not None + and (not isinstance(kwarg_names,(list,tuple)) + or not all([isinstance(k,str) for k in kwarg_names]) + ) + ): + raise ValueError('kwarg_names must be a sequence (list,tuple) of strings') + + vks = fkmap[func_name]() + + df = (pd.DataFrame(vks).T).drop('Validator',axis=1) + df.index.name = 'Kwarg' + df.reset_index(inplace=True) + + if kwarg_names is not None: + for k in kwarg_names: + if k not in df['Kwarg'].values: + print(' Warning: "'+k+'" is not a valid `kwarg_name` for `func_name` "'+func_name,'"') + df = df[ df['Kwarg'].isin(kwarg_names) ] + if len(df) < 1: + raise ValueError(' None of specified `kwarg_names` are valid for `func_name` "'+func_name,'"') + + df['Default'] = ["'"+d+"'" if isinstance(d,str) else str(d) for d in df['Default']] + + klen = df['Kwarg'].str.len().max()+1 + dlen = df['Default'].str.len().max()+1 + + wraplen = max( 40, 80-(klen+dlen) ) + df = df_wrapcols(df,wrap_columns={'Description':wraplen}) + + dividers = [] + for col in df.columns: + dividers.append('-'*int(df[col].str.len().max())) + dfd = pd.DataFrame(dividers).T + dfd.columns = df.columns + dfd.index = pd.Index(['---']) + + df = dfd.append(df) + + formatters = { 'Kwarg' : make_left_formatter( klen ), + 'Default' : make_left_formatter( dlen ), + 'Description' : make_left_formatter( wraplen ), + } + + print('\n ','-'*78) + print(' Kwargs for func_name "'+func_name+'":') + + s = df.to_string(formatters=formatters,index=False,justify='left') + + print('\n ',s.replace('\n','\n ')) diff --git a/src/mplfinance/_styles.py b/src/mplfinance/_styles.py index a8cb08dc..62ce2eca 100644 --- a/src/mplfinance/_styles.py +++ b/src/mplfinance/_styles.py @@ -61,54 +61,71 @@ def _apply_mpfstyle(style): def _valid_make_mpf_style_kwargs(): vkwargs = { 'base_mpf_style': { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: value in _styles.keys() }, 'base_mpl_style': { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, # and is in plt.style.available - 'marketcolors' : { 'Default' : None, # + 'marketcolors' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) }, 'mavcolors' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,list) }, # TODO: all([_mpf_is_color_like(v) for v in value.values()]) + 'facecolor' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, 'edgecolor' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, 'figcolor' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, 'gridcolor' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, 'gridstyle' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, 'gridaxis' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: value in [ 'vertical'[0:len(value)], 'horizontal'[0:len(value)], 'both'[0:len(value)] ] }, 'y_on_right' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, 'rc' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) }, 'legacy_rc' : { 'Default' : None, # Just in case someone depended upon old behavior + 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) }, 'style_name' : { 'Default' : None, 'Validator' : lambda value: isinstance(value,str) }, } + _validate_vkwargs_dict(vkwargs) + return vkwargs + def available_styles(): return list(_styles.keys()) - + def make_mpf_style( **kwargs ): config = _process_kwargs(kwargs, _valid_make_mpf_style_kwargs()) if config['rc'] is not None and config['legacy_rc'] is not None: @@ -187,51 +204,67 @@ def _valid_mpf_style(value): return False return True + def _valid_make_marketcolors_kwargs(): vkwargs = { - 'up' : { 'Default' : None, - 'Validator' : lambda value: _mpf_is_color_like(value) }, - - 'down' : { 'Default' : None, - 'Validator' : lambda value: _mpf_is_color_like(value) }, - - 'hollow' : { 'Default' : None, - 'Validator' : lambda value: _mpf_is_color_like(value) }, - - 'alpha' : { 'Default' : None, - 'Validator' : lambda value: ( isinstance(value,float) and - 0.0 <= value and 1.0 >= value ) }, - - 'edge' : { 'Default' : None, - 'Validator' : lambda value: _valid_mpf_color_spec(value) }, - - 'wick' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,dict) - or isinstance(value,str) - or _mpf_is_color_like(value) }, - - 'ohlc' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,dict) - or isinstance(value,str) - or _mpf_is_color_like(value) }, - - 'volume' : { 'Default' : None, - 'Validator' : lambda value: isinstance(value,dict) - or isinstance(value,str) - or _mpf_is_color_like(value) }, + 'up' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _mpf_is_color_like(value) }, + + 'down' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _mpf_is_color_like(value) }, + + 'hollow' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _mpf_is_color_like(value) }, + + 'alpha' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: (isinstance(value,float) + and 0.0 <= value and 1.0 >= value ) }, + + 'edge' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _valid_mpf_color_spec(value) }, + + 'wick' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,dict) + or isinstance(value,str) + or _mpf_is_color_like(value) }, + + 'ohlc' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,dict) + or isinstance(value,str) + or _mpf_is_color_like(value) }, + + 'volume' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,dict) + or isinstance(value,str) + or _mpf_is_color_like(value) }, + + 'vcdopcod' : { 'Default' : False, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,bool) }, - 'vcdopcod' : { 'Default' : False, - 'Validator' : lambda value: isinstance(value,bool) }, - 'inherit' : { 'Default' : False, - 'Validator' : lambda value: isinstance(value,bool) }, + 'inherit' : { 'Default' : False, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,bool) }, 'base_mpf_style': { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, } + _validate_vkwargs_dict(vkwargs) + return vkwargs + def make_marketcolors(**kwargs): ''' Create a 'marketcolors' dict that is structured as expected diff --git a/src/mplfinance/_utils.py b/src/mplfinance/_utils.py index 8c5803cd..4c169b10 100644 --- a/src/mplfinance/_utils.py +++ b/src/mplfinance/_utils.py @@ -64,6 +64,7 @@ def _check_input(opens, closes, highs, lows): if not same_missing: raise ValueError('O,H,L,C must have the same missing data!') + def _check_and_convert_xlim_configuration(data, config): ''' Check, if user entered `xlim` kwarg, if user entered dates @@ -375,9 +376,10 @@ def _valid_renko_kwargs(): ''' Construct and return the "valid renko kwargs table" for the mplfinance.plot(type='renko') function. A valid kwargs table is a `dict` of `dict`s. The keys of the outer dict are - the valid key-words for the function. The value for each key is a dict containing 2 - specific keys: "Default", and "Validator" with the following values: + the valid key-words for the function. The value for each key is a dict containing 3 + specific keys: "Default", "Description" and "Validator" with the following values: "Default" - The default value for the kwarg if none is specified. + "Description" - The description for the kwarg. "Validator" - A function that takes the caller specified value for the kwarg, and validates that it is the correct type, and (for kwargs with a limited set of allowed values) may also validate that the @@ -385,22 +387,28 @@ def _valid_renko_kwargs(): ''' vkwargs = { 'brick_size' : { 'Default' : 'atr', - 'Validator' : lambda value: isinstance(value,(float,int)) or value == 'atr' }, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,(float,int)) + or value == 'atr' }, 'atr_length' : { 'Default' : 14, - 'Validator' : lambda value: isinstance(value,int) or value == 'total' }, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,int) + or value == 'total' }, } _validate_vkwargs_dict(vkwargs) return vkwargs + def _valid_pnf_kwargs(): ''' Construct and return the "valid pnf kwargs table" for the mplfinance.plot(type='pnf') function. A valid kwargs table is a `dict` of `dict`s. The keys of the outer dict are - the valid key-words for the function. The value for each key is a dict containing 2 - specific keys: "Default", and "Validator" with the following values: + the valid key-words for the function. The value for each key is a dict containing 3 + specific keys: "Default", "Description" and "Validator" with the following values: "Default" - The default value for the kwarg if none is specified. + "Description" - The description for the kwarg. "Validator" - A function that takes the caller specified value for the kwarg, and validates that it is the correct type, and (for kwargs with a limited set of allowed values) may also validate that the @@ -408,25 +416,33 @@ def _valid_pnf_kwargs(): ''' vkwargs = { 'box_size' : { 'Default' : 'atr', - 'Validator' : lambda value: isinstance(value,(float,int)) or value == 'atr' }, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,(float,int)) + or value == 'atr' }, 'atr_length' : { 'Default' : 14, - 'Validator' : lambda value: isinstance(value,int) or value == 'total' }, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,int) + or value == 'total' }, + 'reversal' : { 'Default' : 1, - 'Validator' : lambda value: isinstance(value,int) } + 'Description' : '', + 'Validator' : lambda value: isinstance(value,int) }, } _validate_vkwargs_dict(vkwargs) return vkwargs + def _valid_lines_kwargs(): ''' Construct and return the "valid lines (hlines,vlines,alines,tlines) kwargs table" for the mplfinance.plot() `[h|v|a|t]lines=` kwarg functions. A valid kwargs table is a `dict` of `dict`s. The keys of the outer dict are - the valid key-words for the function. The value for each key is a dict containing 2 - specific keys: "Default", and "Validator" with the following values: + the valid key-words for the function. The value for each key is a dict containing 3 + specific keys: "Default", "Description" and "Validator" with the following values: "Default" - The default value for the kwarg if none is specified. + "Description" - The description for the kwarg. "Validator" - A function that takes the caller specified value for the kwarg, and validates that it is the correct type, and (for kwargs with a limited set of allowed values) may also validate that the @@ -435,33 +451,53 @@ def _valid_lines_kwargs(): valid_linestyles = ['-','solid','--','dashed','-.','dashdot',':','dotted',None,' ',''] vkwargs = { 'hlines' : { 'Default' : None, + 'Description' : '', 'Validator' : _bypass_kwarg_validation }, + 'vlines' : { 'Default' : None, + 'Description' : '', 'Validator' : _bypass_kwarg_validation }, + 'alines' : { 'Default' : None, + 'Description' : '', 'Validator' : _bypass_kwarg_validation }, + 'tlines' : { 'Default' : None, + 'Description' : '', 'Validator' : _bypass_kwarg_validation }, + 'colors' : { 'Default' : None, - 'Validator' : lambda value: value is None or - mcolors.is_color_like(value) or - ( isinstance(value,(list,tuple)) and - all([mcolors.is_color_like(v) for v in value]) ) }, + 'Description' : '', + 'Validator' : lambda value: value is None + or mcolors.is_color_like(value) + or (isinstance(value,(list,tuple)) + and all([mcolors.is_color_like(v) for v in value]) ) }, + 'linestyle' : { 'Default' : '-', + 'Description' : '', 'Validator' : lambda value: value is None or value in valid_linestyles or all([v in valid_linestyles for v in value]) }, + 'linewidths': { 'Default' : None, - 'Validator' : lambda value: value is None or - isinstance(value,(float,int)) or - all([isinstance(v,(float,int)) for v in value]) }, + 'Description' : '', + 'Validator' : lambda value: value is None + or isinstance(value,(float,int)) + or all([isinstance(v,(float,int)) for v in value]) }, + 'alpha' : { 'Default' : 1.0, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, - 'tline_use' : { 'Default' : 'close', - 'Validator' : lambda value: isinstance(value,str) or (isinstance(value,(list,tuple)) and - all([isinstance(v,str) for v in value]) ) }, - 'tline_method': { 'Default' : 'point-to-point', - 'Validator' : lambda value: value in ['point-to-point','least-squares'] } + + 'tline_use' : { 'Default' : 'close', + 'Description' : '', + 'Validator' : lambda value: isinstance(value,str) + or (isinstance(value,(list,tuple)) + and all([isinstance(v,str) for v in value]) ) }, + + 'tline_method': { 'Default' : 'point-to-point', + 'Description' : '', + 'Validator' : lambda value: value in ['point-to-point','least-squares'] } } _validate_vkwargs_dict(vkwargs) diff --git a/src/mplfinance/_version.py b/src/mplfinance/_version.py index 4b58f268..9af54986 100644 --- a/src/mplfinance/_version.py +++ b/src/mplfinance/_version.py @@ -1,5 +1,5 @@ -version_info = (0, 12, 8, 'beta', 6) +version_info = (0, 12, 8, 'beta', 7) _specifier_ = {'alpha': 'a','beta': 'b','candidate': 'rc','final': ''} diff --git a/src/mplfinance/_widths.py b/src/mplfinance/_widths.py index 1cc4aefe..a608fbba 100644 --- a/src/mplfinance/_widths.py +++ b/src/mplfinance/_widths.py @@ -29,57 +29,77 @@ def _get_widths_df(): _widths = _get_widths_df() + def _valid_scale_width_kwargs(): vkwargs = { 'ohlc' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'volume' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'candle' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'lines' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'volume_linewidth' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'ohlc_linewidth' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'candle_linewidth' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, } + _validate_vkwargs_dict(vkwargs) + return vkwargs + def _valid_update_width_kwargs(): vkwargs = { 'ohlc_ticksize' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'ohlc_linewidth' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'volume_width' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'volume_linewidth' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'candle_width' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'candle_linewidth' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, 'line_width' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(float,int)) }, } + _validate_vkwargs_dict(vkwargs) + return vkwargs diff --git a/src/mplfinance/plotting.py b/src/mplfinance/plotting.py index de29ec73..d5558c7a 100644 --- a/src/mplfinance/plotting.py +++ b/src/mplfinance/plotting.py @@ -99,182 +99,241 @@ def _valid_plot_kwargs(): vkwargs = { 'columns' : { 'Default' : None, # use default names: ('Open', 'High', 'Low', 'Close', 'Volume') + 'Description' : ('Column names to be used when plotting the data.'+ + ' Default: ("Open", "High", "Low", "Close", "Volume")'), 'Validator' : lambda value: isinstance(value, (tuple, list)) and len(value) == 5 and all(isinstance(c, str) for c in value) }, 'type' : { 'Default' : 'ohlc', + 'Description' : 'Plot type: '+str(_get_valid_plot_types()), 'Validator' : lambda value: value in _get_valid_plot_types() }, 'style' : { 'Default' : None, + 'Description' : 'plot style; see `mpf.available_styles()`', 'Validator' : _styles._valid_mpf_style }, 'volume' : { 'Default' : False, + 'Description' : 'Plot volume: True, False, or set to Axes object on which to plot.', 'Validator' : lambda value: isinstance(value,bool) or isinstance(value,mpl_axes.Axes) }, 'mav' : { 'Default' : None, + 'Description' : 'Moving Average window size(s); (int or tuple of ints)', 'Validator' : _mav_validator }, 'renko_params' : { 'Default' : dict(), + 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) }, 'pnf_params' : { 'Default' : dict(), + 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) }, 'study' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: _kwarg_not_implemented(value) }, 'marketcolor_overrides' : { 'Default' : None, + 'Description' : '', 'Validator' : _mco_validator }, 'mco_faceonly' : { 'Default' : False, # If True: Override only the face of the candle + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, 'no_xgaps' : { 'Default' : True, # None means follow default logic below: + 'Description' : '', 'Validator' : lambda value: _warn_no_xgaps_deprecated(value) }, 'show_nontrading' : { 'Default' : False, + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, 'figscale' : { 'Default' : None, # scale base figure size up or down. + 'Description' : 'Scale figure size up (if > 1) or down (if < 1)', 'Validator' : lambda value: isinstance(value,float) or isinstance(value,int) }, 'figratio' : { 'Default' : None, # aspect ratio; scaled to 8.0 height + 'Description' : 'Aspect ratio of the figure. Default: (8.00,5.75)', 'Validator' : lambda value: isinstance(value,(tuple,list)) and len(value) == 2 and isinstance(value[0],(float,int)) and isinstance(value[1],(float,int)) }, 'figsize' : { 'Default' : None, # figure size; overrides figratio and figscale + 'Description' : ('Figure size: overrides both figscale and figratio,'+ + ' else defaults to figratio*figscale'), 'Validator' : lambda value: isinstance(value,(tuple,list)) and len(value) == 2 and isinstance(value[0],(float,int)) and isinstance(value[1],(float,int)) }, 'fontscale' : { 'Default' : None, # scale all fonts up or down + 'Description' : 'Scale font sizes up (if > 1) or down (if < 1)', 'Validator' : lambda value: isinstance(value,float) or isinstance(value,int) }, 'linecolor' : { 'Default' : None, # line color in line plot + 'Description' : 'Line color for `type=line`', 'Validator' : lambda value: mcolors.is_color_like(value) }, 'title' : { 'Default' : None, # Figure Title + 'Description' : 'Figure Title (see also `axtitle`)', 'Validator' : lambda value: isinstance(value,(str,dict)) }, 'axtitle' : { 'Default' : None, # Axes Title (subplot title) + 'Description' : 'Axes Title (subplot title)', 'Validator' : lambda value: isinstance(value,(str,dict)) }, 'ylabel' : { 'Default' : 'Price', # y-axis label + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, 'ylabel_lower' : { 'Default' : None, # y-axis label default logic below + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, 'addplot' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) or (isinstance(value,list) and all([isinstance(d,dict) for d in value])) }, 'savefig' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) or isinstance(value,str) or isinstance(value, io.BytesIO) or isinstance(value, os.PathLike) }, 'block' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, 'returnfig' : { 'Default' : False, + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, - 'return_calculated_values' : {'Default' : None, - 'Validator' : lambda value: isinstance(value, dict) and len(value) == 0}, + 'return_calculated_values' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value, dict) and len(value) == 0}, - 'set_ylim' : {'Default' : None, - 'Validator' : lambda value: _warn_set_ylim_deprecated(value) }, + 'set_ylim' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _warn_set_ylim_deprecated(value) }, - 'ylim' : {'Default' : None, - 'Validator' : lambda value: isinstance(value, (list,tuple)) and len(value) == 2 + 'ylim' : { 'Default' : None, + 'Description' : 'Limits for y-axis as tuple (min,max), i.e. (bottom,top)', + 'Validator' : lambda value: isinstance(value, (list,tuple)) and len(value) == 2 and all([isinstance(v,(int,float)) for v in value])}, - 'xlim' : {'Default' : None, - 'Validator' : lambda value: _xlim_validator(value) }, + 'xlim' : { 'Default' : None, + 'Description' : 'Limits for x-axis as tuple (min, max), i.e. (left,right)', + 'Validator' : lambda value: _xlim_validator(value) }, - 'set_ylim_panelB' : {'Default' : None, - 'Validator' : lambda value: _warn_set_ylim_deprecated(value) }, + 'set_ylim_panelB' : { 'Default' : None, + 'Description' : '', + 'Validator' : lambda value: _warn_set_ylim_deprecated(value) }, 'hlines' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: _hlines_validator(value) }, 'vlines' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: _vlines_validator(value) }, 'alines' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: _alines_validator(value) }, 'tlines' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: _tlines_validator(value) }, 'panel_ratios' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,(tuple,list)) and len(value) <= 10 and all([isinstance(v,(int,float)) for v in value]) }, 'main_panel' : { 'Default' : 0, + 'Description' : '', 'Validator' : lambda value: _valid_panel_id(value) }, 'volume_panel' : { 'Default' : 1, + 'Description' : '', 'Validator' : lambda value: _valid_panel_id(value) }, 'num_panels' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,int) and value in range(1,10+1) }, 'datetime_format' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, 'xrotation' : { 'Default' : 45, + 'Description' : 'Angle (degrees) for x-axis tick labels; 90=vertical', 'Validator' : lambda value: isinstance(value,(int,float)) }, 'axisoff' : { 'Default' : False, + 'Description' : '`axisoff=True` means do NOT display any axis.', 'Validator' : lambda value: isinstance(value,bool) }, 'closefig' : { 'Default' : 'auto', + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, 'fill_between' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: _num_or_seq_of_num(value) or (isinstance(value,dict) and 'y1' in value and _num_or_seq_of_num(value['y1'])) }, 'tight_layout' : { 'Default' : False, + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, 'width_adjuster_version' : { 'Default' : 'v1', + 'Description' : '', 'Validator' : lambda value: value in ('v0', 'v1') }, 'scale_width_adjustment' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) and len(value) > 0 }, 'update_width_config' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) and len(value) > 0 }, 'return_width_config' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,dict) and len(value)==0 }, 'saxbelow' : { 'Default' : True, # Issue#115 Comment#639446764 + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, 'scale_padding' : { 'Default' : 1.0, # Issue#193 + 'Description' : '', 'Validator' : lambda value: _scale_padding_validator(value) }, 'ax' : { 'Default' : None, + 'Description' : 'Matplotlib Axes object on which to plot', 'Validator' : lambda value: isinstance(value,mpl_axes.Axes) }, 'volume_exponent' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,int) or value == 'legacy'}, 'tz_localize' : { 'Default' : True, + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, 'yscale' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: _yscale_validator(value) }, 'volume_yscale' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: _yscale_validator(value) }, 'warn_too_much_data' : { 'Default' : 599, + 'Description' : ('Tolerance for data amount in plot. Default=599 rows.'+ + ' Values greater than \'warn_too_much_data\' will trigger a warning.'), 'Validator' : lambda value: isinstance(value,int) }, } @@ -1048,73 +1107,95 @@ def _valid_addplot_kwargs(): vkwargs = { 'scatter' : { 'Default' : False, + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, 'type' : { 'Default' : 'line', + 'Description' : '', 'Validator' : lambda value: value in valid_types }, 'mav' : { 'Default' : None, + 'Description' : '', 'Validator' : _mav_validator }, 'panel' : { 'Default' : 0, + 'Description' : '', 'Validator' : lambda value: _valid_panel_id(value) }, 'marker' : { 'Default' : 'o', + 'Description' : '', 'Validator' : lambda value: _bypass_kwarg_validation(value) }, 'markersize' : { 'Default' : 18, + 'Description' : 'size of marker for `type=scatter`; default=18', 'Validator' : lambda value: isinstance(value,(int,float)) }, 'color' : { 'Default' : None, + 'Description' : 'color of line, scatter marker, or bar', 'Validator' : lambda value: mcolors.is_color_like(value) or (isinstance(value,(list,tuple,np.ndarray)) and all([mcolors.is_color_like(v) for v in value])) }, 'linestyle' : { 'Default' : None, + 'Description' : 'line style for `type=line` ('+str(valid_linestyles)+')', 'Validator' : lambda value: value in valid_linestyles }, - 'linewidths': {'Default': None, - 'Validator' : lambda value: isinstance(value,(int,float)) }, + 'linewidths' : { 'Default': None, + 'Description' : '', + 'Validator' : lambda value: isinstance(value,(int,float)) }, - 'edgecolors': {'Default': None, - 'Validator': lambda value: mcolors.is_color_like(value) or value in valid_edgecolors}, + 'edgecolors' : { 'Default': None, + 'Description' : '', + 'Validator': lambda value: mcolors.is_color_like(value) or value in valid_edgecolors}, 'width' : { 'Default' : None, # width of `bar` or `line` + 'Description' : '', 'Validator' : lambda value: isinstance(value,(int,float)) or all([isinstance(v,(int,float)) for v in value]) }, 'bottom' : { 'Default' : 0, # bottom for `type=bar` plots + 'Description' : 'bottom value for `type=bar` bars. Default=0', 'Validator' : lambda value: isinstance(value,(int,float)) or all([isinstance(v,(int,float)) for v in value]) }, 'alpha' : { 'Default' : 1, # alpha of `bar`, `line`, or `scatter` + 'Description' : 'opacity for 0.0 (transparent) to 1.0 (opaque)', 'Validator' : lambda value: isinstance(value,(int,float)) or all([isinstance(v,(int,float)) for v in value]) }, 'secondary_y' : { 'Default' : 'auto', + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) or value == 'auto' }, 'y_on_right' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,bool) }, 'ylabel' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, 'ylim' : {'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value, (list,tuple)) and len(value) == 2 and all([isinstance(v,(int,float)) for v in value])}, 'title' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,str) }, 'ax' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: isinstance(value,mpl_axes.Axes) }, 'yscale' : { 'Default' : None, + 'Description' : '', 'Validator' : lambda value: _yscale_validator(value) }, - 'stepwhere' : { 'Default' : 'pre', - 'Validator' : lambda value : value in valid_stepwheres }, + 'stepwhere' : { 'Default' : 'pre', + 'Description' : '', + 'Validator' : lambda value : value in valid_stepwheres }, - 'marketcolors' : { 'Default' : None, # use 'style' for default, instead. + 'marketcolors': { 'Default' : None, # use 'style' for default, instead. + 'Description' : '', 'Validator' : lambda value: _is_marketcolor_object(value) }, }