Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added vlines feature to plotting.py #570

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions build/lib/mplfinance/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +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._kwarg_help import kwarg_help
462 changes: 462 additions & 0 deletions build/lib/mplfinance/_arg_validators.py

Large diffs are not rendered by default.

121 changes: 121 additions & 0 deletions build/lib/mplfinance/_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
"""
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.colors as mcolors
import numpy as np

def _adjust_color_brightness(color,amount=0.5):

def _adjcb(c1, amount):
import matplotlib.colors as mc
import colorsys
# mc.is_color_like(value)
try:
c = mc.cnames[c1]
except:
c = c1
c = colorsys.rgb_to_hls(*mc.to_rgb(c))
return colorsys.hls_to_rgb(c[0], max(0, min(1, amount * c[1])), c[2])

if not isinstance(color,(list,tuple)):
return _adjcb(color,amount)

cout = []
cadj = {}
for c1 in color:
if c1 in cadj:
cout.append(cadj[c1])
else:
newc = _adjcb(c1,amount)
cadj[c1] = newc
cout.append(cadj[c1])
return cout


def _determine_format_string( dates, datetime_format=None ):
"""
Determine the datetime format string based on the averge number
of days between data points, or if the user passed in kwarg
datetime_format, use that as an override.
"""
avg_days_between_points = (dates[-1] - dates[0]) / float(len(dates))

if datetime_format is not None:
return datetime_format

# avgerage of 3 or more data points per day we will call intraday data:
if avg_days_between_points < 0.33: # intraday
if mdates.num2date(dates[-1]).date() != mdates.num2date(dates[0]).date():
# intraday data for more than one day:
fmtstring = '%b %d, %H:%M'
else: # intraday data for a single day
fmtstring = '%H:%M'
else: # 'daily' data (or could be weekly, etc.)
if mdates.num2date(dates[-1]).date().year != mdates.num2date(dates[0]).date().year:
fmtstring = '%Y-%b-%d'
else:
fmtstring = '%b %d'
return fmtstring


def _list_of_dict(x):
'''
Return True if x is a list of dict's
'''
return isinstance(x,list) and all([isinstance(item,dict) for item in x])

def _num_or_seq_of_num(value):
return ( isinstance(value,(int,float,np.integer,np.floating)) or
(isinstance(value,(list,tuple,np.ndarray)) and
all([isinstance(v,(int,float,np.integer,np.floating)) for v in value]))
)

def roundTime(dt=None, roundTo=60):
"""Round a datetime object to any time lapse in seconds
dt : datetime.datetime object, default now.
roundTo : Closest number of seconds to round to, default 1 minute.
Author: Thierry Husson 2012 - Use it as you want but don't blame me.
"""
if dt is None : dt = datetime.datetime.now()
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)
154 changes: 154 additions & 0 deletions build/lib/mplfinance/_kwarg_help.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
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, sort=False ):

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'
if sort: df.sort_index(inplace=True)
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 '))
16 changes: 16 additions & 0 deletions build/lib/mplfinance/_mpf_warnings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import sys as __sys
if not __sys.warnoptions:
import os as __os
import warnings as __warnings
__warnings.filterwarnings("default",category=DeprecationWarning,module='mplfinance') # Change the filter in this process
__os.environ["PYTHONWARNINGS"] = "default::DeprecationWarning:mplfinance" # Also affect subprocesses

if __sys.version_info <= (3, 6):
__warnings.filterwarnings("default",category=ImportWarning,module='mplfinance') # Change the filter in this process
__os.environ["PYTHONWARNINGS"] = "default::ImportWarning:mplfinance" # Also affect subprocesses
__warnings.warn('\n\n ================================================================= '+
'\n\n WARNING: `mplfinance` is NOT supported for Python versions '+
'\n less than 3.6'
'\n\n ================================================================= ',
category=ImportWarning)

87 changes: 87 additions & 0 deletions build/lib/mplfinance/_mplrcputils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env python
"""
rcparams utilities
"""

import pandas as pd
import matplotlib.pyplot as plt
import sys

__author__ = "Daniel Goldfarb"
__version__ = "0.1.0"
__license__ = "MIT"

def rcParams_to_df(rcp,name=None):
keys = []
vals = []
for item in rcp:
keys.append(item)
vals.append(rcp[item])
df = pd.DataFrame(vals,index=pd.Index(keys,name='rcParamsKey'))
if name is not None:
df.columns = [name]
else:
df.columns = ['Value']
return df

def compare_styles(s1,s2):
with plt.rc_context():
plt.style.use('default')
plt.style.use(s1)
df1 = rcParams_to_df(plt.rcParams,name=s1)

with plt.rc_context():
plt.style.use('default')
plt.style.use(s2)
df2 = rcParams_to_df(plt.rcParams,name=s2)

df = pd.concat([df1,df2],axis=1)
dif = df[df[s1] != df[s2]].dropna(how='all')
return (dif,df,df1,df2)

def main():
""" Main entry point of the app """
def usage():
print('\n Usage: rcparams <command> <arguments> \n')
print(' Available commands: ')
print(' rcparams find <findstring>')
print(' rcparams compare <style1> <style2>')
print('')
exit(1)
commands = ('find','compare')

if len(sys.argv) < 3 :
print('\n Too few arguments!')
usage()

command = sys.argv[1]
if command not in commands:
print('\n Unrecognized command \"'+command+'\"')
usage()

if command == 'find':
findstr = sys.argv[2]
df = rcParams_to_df(plt.rcParams)
if findstr == '--all':
for key in df.index:
print(key+':',df.loc[key,'Value'])
else:
print(df[df.index.str.contains(findstr)])

elif command == 'compare':
if len(sys.argv) < 4 :
print('\n Need two styles to compare!')
usage()
style1 = sys.argv[2]
style2 = sys.argv[3]
dif,df,df1,df2 = compare_styles(style1,style2)
print('\n==== dif ====\n',dif)

else:
print('\n Unrecognized command \"'+command+'\"')
usage()


if __name__ == "__main__":
""" This is executed when run from the command line """
main()
Loading