Merge branch 'improvedGraphing' into ObjectivyGraphImprovements

# Conflicts:
#	freqtrade/arguments.py
This commit is contained in:
Gert Wohlgemuth 2018-05-09 05:08:30 -07:00
commit 478b0803d6
5 changed files with 358 additions and 33 deletions

View File

@ -260,6 +260,77 @@ class Arguments(object):
default=None default=None
) )
self.parser.add_argument(
'--stop-loss',
help='Renders stop/loss information in the main chart',
dest='stoplossdisplay',
action='store_true',
default=False
)
self.parser.add_argument(
'--plot-rsi',
help='Renders a rsi chart of the given RSI dataframe name, for example --plot-rsi rsi',
dest='plotrsi',
nargs='+',
default=None
)
self.parser.add_argument(
'--plot-cci',
help='Renders a cci chart of the given CCI dataframe name, for example --plot-cci cci',
dest='plotcci',
nargs='+',
default=None
)
self.parser.add_argument(
'--plot-macd',
help='Renders a macd chart of the given '
'dataframe name, for example --plot-macd macd',
dest='plotmacd',
default=None
)
self.parser.add_argument(
'--plot-dataframe',
help='Renders the specified dataframes',
dest='plotdataframe',
default=None,
nargs='+',
type=str
)
self.parser.add_argument(
'--plot-dataframe-marker',
help='Renders the specified dataframes as markers. '
'Accepted values for a marker are either 100 or -100',
dest='plotdataframemarker',
default=None,
nargs='+',
type=str
)
self.parser.add_argument(
'--plot-volume',
help='plots the volume as a sub plot',
dest='plotvolume',
action='store_true'
)
self.parser.add_argument(
'--plot-max-ticks',
help='specify an upper limit of how many ticks we can display',
dest='plotticks',
default=750,
type=int
)
def testdata_dl_options(self) -> None: def testdata_dl_options(self) -> None:
""" """
Parses given arguments for testdata download Parses given arguments for testdata download

View File

@ -357,8 +357,9 @@ class Telegram(RPC):
message = tabulate({ message = tabulate({
'current': [len(trades)], 'current': [len(trades)],
'max': [self._config['max_open_trades']] 'max': [self._config['max_open_trades']],
}, headers=['current', 'max'], tablefmt='simple') 'total stake': [sum((trade.open_rate * trade.amount) for trade in trades)]
}, headers=['current', 'max', 'total stake'], tablefmt='simple')
message = "<pre>{}</pre>".format(message) message = "<pre>{}</pre>".format(message)
logger.debug(message) logger.debug(message)
self.send_msg(message, parse_mode=ParseMode.HTML) self.send_msg(message, parse_mode=ParseMode.HTML)

View File

@ -1013,8 +1013,11 @@ def test_count_handle(default_conf, update, ticker, fee, mocker) -> None:
msg_mock.reset_mock() msg_mock.reset_mock()
telegram._count(bot=MagicMock(), update=update) telegram._count(bot=MagicMock(), update=update)
msg = '<pre> current max\n--------- -----\n 1 {}</pre>'.format( msg = '<pre> current max total stake\n--------- ----- -------------\n' \
default_conf['max_open_trades'] ' 1 {} {}</pre>'\
.format(
default_conf['max_open_trades'],
default_conf['stake_amount']
) )
assert msg in msg_mock.call_args_list[0][0][0] assert msg in msg_mock.call_args_list[0][0][0]

View File

@ -1,6 +1,6 @@
ccxt==1.11.149 ccxt==1.11.149
SQLAlchemy==1.2.7 SQLAlchemy==1.2.7
python-telegram-bot==10.0.2 python-telegram-bot==10.1.0
arrow==0.12.1 arrow==0.12.1
cachetools==2.0.1 cachetools==2.0.1
requests==2.18.4 requests==2.18.4

View File

@ -11,21 +11,21 @@ Optional Cli parameters
--timerange: specify what timerange of data to use. --timerange: specify what timerange of data to use.
-l / --live: Live, to download the latest ticker for the pair -l / --live: Live, to download the latest ticker for the pair
""" """
import datetime
import logging import logging
import sys import sys
from argparse import Namespace from argparse import Namespace
from typing import List from typing import List
import plotly.graph_objs as go
from plotly import tools from plotly import tools
from plotly.offline import plot from plotly.offline import plot
import plotly.graph_objs as go
from freqtrade.arguments import Arguments
from freqtrade.analyze import Analyze
from freqtrade import exchange
import freqtrade.optimize as optimize import freqtrade.optimize as optimize
from freqtrade import exchange
from freqtrade.analyze import Analyze
from freqtrade.arguments import Arguments
from freqtrade.configuration import Configuration
<<<<<<< HEAD <<<<<<< HEAD
logger = logging.getLogger('freqtrade') logger = logging.getLogger('freqtrade')
@ -33,6 +33,203 @@ logger = logging.getLogger('freqtrade')
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
>>>>>>> bddf009a2b6d0e1a19cca558887ce972e99a6238 >>>>>>> bddf009a2b6d0e1a19cca558887ce972e99a6238
def plot_dataframes_markers(data, fig, args):
"""
plots additional dataframe markers in the main plot
:param data:
:param fig:
:param args:
:return:
"""
if args.plotdataframemarker:
for x in args.plotdataframemarker:
filter = data[(data[x] == 100 ) | (data[x] == -100) ]
marker = go.Scatter(
x=filter.date,
y=filter.low * 0.99,
mode='markers',
name=x,
marker=dict(
symbol='diamond-tall-open',
size=10,
line=dict(width=1)
)
)
fig.append_trace(marker, 1, 1)
def plot_dataframes(data, fig, args):
"""
plots additional dataframes in the main plot
:param data:
:param fig:
:param args:
:return:
"""
if args.plotdataframe:
for x in args.plotdataframe:
chart = go.Scattergl(x=data['date'], y=data[x], name=x)
fig.append_trace(chart, 1, 1)
def plot_volume_dataframe(data, fig, args, plotnumber):
"""
adds the plotting of the volume
:param data:
:param fig:
:param args:
:return:
"""
volume = go.Bar(x=data['date'], y=data['volume'], name='Volume')
fig.append_trace(volume, plotnumber, 1)
def plot_macd_dataframe(data, fig, args, plotnumber):
"""
adds the plotting of the MACD if specified
:param data:
:param fig:
:param args:
:return:
"""
macd = go.Scattergl(x=data['date'], y=data[args.plotmacd], name='MACD')
macdsignal = go.Scattergl(x=data['date'], y=data[args.plotmacd + 'signal'], name='MACD signal')
fig.append_trace(macd, plotnumber, 1)
fig.append_trace(macdsignal, plotnumber, 1)
def plot_rsi_dataframe(data, fig, args, plotnumber):
"""
this function plots an additional RSI chart under the exiting charts
:param data:
:param fig:
:param args:
:return:
"""
if args.plotrsi:
for x in args.plotrsi:
rsi = go.Scattergl(x=data['date'], y=data[x], name=x)
fig.append_trace(rsi, plotnumber, 1)
def plot_cci_dataframe(data, fig, args, plotnumber):
"""
this function plots an additional cci chart under the exiting charts
:param data:
:param fig:
:param args:
:return:
"""
if args.plotcci:
for x in args.plotcci:
chart = go.Scattergl(x=data['date'], y=data[x], name=x)
fig.append_trace(chart, plotnumber, 1)
def plot_stop_loss_trade(df_sell, fig, analyze, args):
"""
plots the stop loss for the associated trades and buys
as well as the estimated profit ranges.
will be enabled if --stop-loss is provided
as argument
:param data:
:param trades:
:return:
"""
if args.stoplossdisplay is False:
return
if 'associated_buy_price' not in df_sell:
return
stoploss = analyze.strategy.stoploss
for index, x in df_sell.iterrows():
if x['associated_buy_price'] > 0:
# draw stop loss
fig['layout']['shapes'].append(
{
'fillcolor': 'red',
'opacity': 0.1,
'type': 'rect',
'x0': x['associated_buy_date'],
'x1': x['date'],
'y0': x['associated_buy_price'],
'y1': (x['associated_buy_price'] - abs(stoploss) * x['associated_buy_price']),
'line': {'color': 'red'}
}
)
totalTime = 0
for time in analyze.strategy.minimal_roi:
t = int(time)
totalTime = t + totalTime
enddate = x['date']
date = x['associated_buy_date'] + datetime.timedelta(minutes=totalTime)
# draw profit range
fig['layout']['shapes'].append(
{
'fillcolor': 'green',
'opacity': 0.1,
'type': 'rect',
'x0': date,
'x1': enddate,
'y0': x['associated_buy_price'],
'y1': x['associated_buy_price'] + x['associated_buy_price'] * analyze.strategy.minimal_roi[
time],
'line': {'color': 'green'}
}
)
def find_profits(data):
"""
finds the profits between sells and the associated buys. This does not take in account
ROI!
:param data:
:return:
"""
# go over all the sells
# find all previous buys
df_sell = data[data['sell'] == 1]
df_sell['profit'] = 0
df_buys = data[data['buy'] == 1]
lastDate = data['date'].iloc[0]
for index, row in df_sell.iterrows():
buys = df_buys[(df_buys['date'] < row['date']) & (df_buys['date'] > lastDate)]
profit = None
if buys['date'].count() > 0:
buys = buys.tail()
profit = round(row['close'] / buys['close'].values[0] * 100 - 100, 2)
lastDate = row['date']
df_sell.loc[index, 'associated_buy_date'] = buys['date'].values[0]
df_sell.loc[index, 'associated_buy_price'] = buys['close'].values[0]
df_sell.loc[index, 'profit'] = profit
return df_sell
def plot_analyzed_dataframe(args: Namespace) -> None: def plot_analyzed_dataframe(args: Namespace) -> None:
""" """
@ -44,7 +241,9 @@ def plot_analyzed_dataframe(args: Namespace) -> None:
# Init strategy # Init strategy
try: try:
analyze = Analyze({'strategy': args.strategy}) config = Configuration(args)
analyze = Analyze(config.get_config())
except AttributeError: except AttributeError:
logger.critical( logger.critical(
'Impossible to load the strategy. Please check the file "user_data/strategies/%s.py"', 'Impossible to load the strategy. Please check the file "user_data/strategies/%s.py"',
@ -73,9 +272,9 @@ def plot_analyzed_dataframe(args: Namespace) -> None:
dataframe = analyze.populate_buy_trend(dataframe) dataframe = analyze.populate_buy_trend(dataframe)
dataframe = analyze.populate_sell_trend(dataframe) dataframe = analyze.populate_sell_trend(dataframe)
if len(dataframe.index) > 750: if len(dataframe.index) > args.plotticks:
logger.warning('Ticker contained more than 750 candles, clipping.') logger.warning('Ticker contained more than {} candles, clipping.'.format(args.plotticks))
data = dataframe.tail(750) data = dataframe.tail(args.plotticks)
candles = go.Candlestick( candles = go.Candlestick(
x=data.date, x=data.date,
@ -87,30 +286,35 @@ def plot_analyzed_dataframe(args: Namespace) -> None:
) )
df_buy = data[data['buy'] == 1] df_buy = data[data['buy'] == 1]
buys = go.Scattergl( buys = go.Scattergl(
x=df_buy.date, x=df_buy.date,
y=df_buy.close, y=df_buy.close * 0.995,
mode='markers', mode='markers',
name='buy', name='buy',
marker=dict( marker=dict(
symbol='triangle-up-dot', symbol='triangle-up-dot',
size=9, size=15,
line=dict(width=1), line=dict(width=1),
color='green', color='green',
) )
) )
df_sell = data[data['sell'] == 1] df_sell = find_profits(data)
sells = go.Scattergl(
sells = go.Scatter(
x=df_sell.date, x=df_sell.date,
y=df_sell.close, y=df_sell.close * 1.01,
mode='markers', mode='markers+text',
name='sell', name='sell',
text=df_sell.profit,
textposition='top right',
marker=dict( marker=dict(
symbol='triangle-down-dot', symbol='triangle-down-dot',
size=9, size=15,
line=dict(width=1), line=dict(width=1),
color='red', color='red',
) )
) )
bb_lower = go.Scatter( bb_lower = go.Scatter(
@ -127,31 +331,77 @@ def plot_analyzed_dataframe(args: Namespace) -> None:
fillcolor="rgba(0,176,246,0.2)", fillcolor="rgba(0,176,246,0.2)",
line={'color': "transparent"}, line={'color': "transparent"},
) )
macd = go.Scattergl(x=data['date'], y=data['macd'], name='MACD') bb_middle = go.Scatter(
macdsignal = go.Scattergl(x=data['date'], y=data['macdsignal'], name='MACD signal') x=data.date,
volume = go.Bar(x=data['date'], y=data['volume'], name='Volume') y=data.bb_middleband,
name='BB middle',
fill="tonexty",
fillcolor="rgba(0,176,246,0.2)",
line={'color': "red"},
)
# ugly hack for now
rowWidth = [1]
if args.plotvolume:
rowWidth.append(1)
if args.plotmacd:
rowWidth.append(1)
if args.plotrsi:
rowWidth.append(1)
if args.plotcci:
rowWidth.append(1)
# standard layout signal + volume
fig = tools.make_subplots( fig = tools.make_subplots(
rows=3, rows=len(rowWidth),
cols=1, cols=1,
shared_xaxes=True, shared_xaxes=True,
row_width=[1, 1, 4], row_width=rowWidth,
vertical_spacing=0.0001, vertical_spacing=0.0001,
) )
# todo should be optional
fig.append_trace(candles, 1, 1) fig.append_trace(candles, 1, 1)
fig.append_trace(bb_lower, 1, 1) fig.append_trace(bb_lower, 1, 1)
fig.append_trace(bb_middle, 1, 1)
fig.append_trace(bb_upper, 1, 1) fig.append_trace(bb_upper, 1, 1)
fig.append_trace(buys, 1, 1) fig.append_trace(buys, 1, 1)
fig.append_trace(sells, 1, 1) fig.append_trace(sells, 1, 1)
fig.append_trace(volume, 2, 1)
fig.append_trace(macd, 3, 1) # append stop loss/profit
fig.append_trace(macdsignal, 3, 1) plot_stop_loss_trade(df_sell, fig, analyze, args)
# plot other dataframes
plot_dataframes(data, fig, args)
plot_dataframes_markers(data, fig, args)
fig['layout'].update(title=args.pair) fig['layout'].update(title=args.pair)
fig['layout']['yaxis1'].update(title='Price') fig['layout']['yaxis1'].update(title='Price')
fig['layout']['yaxis2'].update(title='Volume')
fig['layout']['yaxis3'].update(title='MACD') subplots = 1
if args.plotvolume:
subplots = subplots + 1
plot_volume_dataframe(data, fig, args, subplots)
fig['layout']['yaxis' + str(subplots)].update(title='Volume')
if args.plotmacd:
subplots = subplots + 1
plot_macd_dataframe(data, fig, args, subplots)
fig['layout']['yaxis' + str(subplots)].update(title='MACD')
if args.plotrsi:
subplots = subplots + 1
plot_rsi_dataframe(data, fig, args, subplots)
fig['layout']['yaxis' + str(subplots)].update(title='RSI', range=[0, 100])
if args.plotcci:
subplots = subplots + 1
plot_cci_dataframe(data, fig, args, subplots)
fig['layout']['yaxis' + str(subplots)].update(title='CCI')
# updated all the
plot(fig, filename='freqtrade-plot.html') plot(fig, filename='freqtrade-plot.html')