Revise plot_profit to use pandas functions where possible

This commit is contained in:
Matthias 2019-06-29 20:52:33 +02:00
parent 8aa327cb8a
commit c3db4ebbc3

View File

@ -4,64 +4,28 @@ Script to display profits
Use `python plot_profit.py --help` to display the command line arguments
"""
import json
import logging
import sys
from argparse import Namespace
from pathlib import Path
from typing import List, Optional
from typing import List
import numpy as np
import pandas as pd
import plotly.graph_objs as go
from plotly import tools
from plotly.offline import plot
from freqtrade.arguments import Arguments, ARGS_PLOT_PROFIT
from freqtrade.arguments import ARGS_PLOT_PROFIT, Arguments
from freqtrade.configuration import Configuration
from freqtrade.data import history
from freqtrade.exchange import timeframe_to_seconds
from freqtrade.misc import common_datearray
from freqtrade.data.btanalysis import create_cum_profit, load_trades
from freqtrade.plot.plotting import generate_plot_file
from freqtrade.resolvers import StrategyResolver
from freqtrade.state import RunMode
logger = logging.getLogger(__name__)
# data:: [ pair, profit-%, enter, exit, time, duration]
# data:: ["ETH/BTC", 0.0023975, "1515598200", "1515602100", "2018-01-10 07:30:00+00:00", 65]
def make_profit_array(data: List, px: int, min_date: int,
interval: str,
filter_pairs: Optional[List] = None) -> np.ndarray:
pg = np.zeros(px)
filter_pairs = filter_pairs or []
# Go through the trades
# and make an total profit
# array
for trade in data:
pair = trade[0]
if filter_pairs and pair not in filter_pairs:
continue
profit = trade[1]
trade_sell_time = int(trade[3])
ix = define_index(min_date, trade_sell_time, interval)
if ix < px:
logger.debug('[%s]: Add profit %s on %s', pair, profit, trade[4])
pg[ix] += profit
# rewrite the pg array to go from
# total profits at each timeframe
# to accumulated profits
pa = 0
for x in range(0, len(pg)):
p = pg[x] # Get current total percent
pa += p # Add to the accumulated percent
pg[x] = pa # write back to save memory
return pg
def plot_profit(args: Namespace) -> None:
"""
Plots the total profit for all pairs.
@ -70,34 +34,15 @@ def plot_profit(args: Namespace) -> None:
in helping out to find a good algorithm.
"""
# We need to use the same pairs, same ticker_interval
# and same timeperiod as used in backtesting
# to match the tickerdata against the profits-results
# We need to use the same pairs and the same ticker_interval
# as used in backtesting / trading
# to match the tickerdata against the results
timerange = Arguments.parse_timerange(args.timerange)
config = Configuration(args, RunMode.OTHER).get_config()
# Init strategy
try:
strategy = StrategyResolver({'strategy': config.get('strategy')}).strategy
except AttributeError:
logger.critical(
'Impossible to load the strategy. Please check the file "user_data/strategies/%s.py"',
config.get('strategy')
)
exit(1)
# Load the profits results
try:
filename = args.exportfilename
with open(filename) as file:
data = json.load(file)
except FileNotFoundError:
logger.critical(
'File "backtest-result.json" not found. This script require backtesting '
'results to run.\nPlease run a backtesting with the parameter --export.')
exit(1)
strategy = StrategyResolver(config).strategy
# Take pairs from the cli otherwise switch to the pair in the config file
if args.pairs:
@ -106,6 +51,11 @@ def plot_profit(args: Namespace) -> None:
else:
filter_pairs = config['exchange']['pair_whitelist']
# Load the profits results
trades = load_trades(config)
trades = trades[trades['pair'].isin(filter_pairs)]
ticker_interval = strategy.ticker_interval
pairs = config['exchange']['pair_whitelist']
@ -120,49 +70,28 @@ def plot_profit(args: Namespace) -> None:
refresh_pairs=False,
timerange=timerange
)
dataframes = strategy.tickerdata_to_dataframe(tickers)
# NOTE: the dataframes are of unequal length,
# 'dates' is an merged date array of them all.
dates = common_datearray(dataframes)
min_date = int(min(dates).timestamp())
max_date = int(max(dates).timestamp())
num_iterations = define_index(min_date, max_date, ticker_interval) + 1
# Make an average close price of all the pairs that was involved.
# Create an average close price of all the pairs that were involved.
# this could be useful to gauge the overall market trend
# We are essentially saying:
# array <- sum dataframes[*]['close'] / num_items dataframes
# FIX: there should be some onliner numpy/panda for this
avgclose = np.zeros(num_iterations)
num = 0
for pair, pair_data in dataframes.items():
close = pair_data['close']
maxprice = max(close) # Normalize price to [0,1]
logger.info('Pair %s has length %s' % (pair, len(close)))
for x in range(0, len(close)):
avgclose[x] += close[x] / maxprice
# avgclose += close
num += 1
avgclose /= num
# make an profits-growth array
pg = make_profit_array(data, num_iterations, min_date, ticker_interval, filter_pairs)
# Combine close-values for all pairs, rename columns to "pair"
df_comb = pd.concat([tickers[pair].set_index('date').rename(
{'close': pair}, axis=1)[pair] for pair in tickers], axis=1)
df_comb['mean'] = df_comb.mean(axis=1)
# Add combined cumulative profit
df_comb = create_cum_profit(df_comb, trades, 'cum_profit')
#
# Plot the pairs average close prices, and total profit growth
#
avgclose = go.Scattergl(
x=dates,
y=avgclose,
x=df_comb.index,
y=df_comb['mean'],
name='Avg close price',
)
profit = go.Scattergl(
x=dates,
y=pg,
x=df_comb.index,
y=df_comb['cum_profit'],
name='Profit',
)
@ -172,23 +101,19 @@ def plot_profit(args: Namespace) -> None:
fig.append_trace(profit, 2, 1)
for pair in pairs:
pg = make_profit_array(data, num_iterations, min_date, ticker_interval, [pair])
profit_col = f'cum_profit_{pair}'
df_comb = create_cum_profit(df_comb, trades[trades['pair'] == pair], profit_col)
pair_profit = go.Scattergl(
x=dates,
y=pg,
name=pair,
x=df_comb.index,
y=df_comb[profit_col],
name=f"Profit {pair}",
)
fig.append_trace(pair_profit, 3, 1)
plot(fig, filename=str(Path('user_data').joinpath('freqtrade-profit-plot.html')))
def define_index(min_date: int, max_date: int, ticker_interval: str) -> int:
"""
Return the index of a specific date
"""
interval_seconds = timeframe_to_seconds(ticker_interval)
return int((max_date - min_date) / interval_seconds)
generate_plot_file(fig,
filename='freqtrade-profit-plot.html',
auto_open=True)
def plot_parse_args(args: List[str]) -> Namespace: