added returns for easier notebook plotting
This commit is contained in:
parent
0477e7938d
commit
85a0d2f6cb
@ -332,13 +332,14 @@ def load_and_plot_trades(config: Dict[str, Any]):
|
|||||||
- Load trades excecuted during the selected period
|
- Load trades excecuted during the selected period
|
||||||
- Generate Plotly plot objects
|
- Generate Plotly plot objects
|
||||||
- Generate plot files
|
- Generate plot files
|
||||||
:return: None
|
:return: Dict of fig, data, trades for each pair and interval
|
||||||
"""
|
"""
|
||||||
strategy = StrategyResolver(config).strategy
|
strategy = StrategyResolver(config).strategy
|
||||||
|
|
||||||
plot_elements = init_plotscript(config)
|
plot_elements = init_plotscript(config)
|
||||||
trades = plot_elements['trades']
|
trades = plot_elements['trades']
|
||||||
pair_counter = 0
|
pair_counter = 0
|
||||||
|
plot_data = {}
|
||||||
for pair, data in plot_elements["tickers"].items():
|
for pair, data in plot_elements["tickers"].items():
|
||||||
pair_counter += 1
|
pair_counter += 1
|
||||||
logger.info("analyse pair %s", pair)
|
logger.info("analyse pair %s", pair)
|
||||||
@ -359,16 +360,23 @@ def load_and_plot_trades(config: Dict[str, Any]):
|
|||||||
|
|
||||||
store_plot_file(fig, filename=generate_plot_filename(pair, config['ticker_interval']),
|
store_plot_file(fig, filename=generate_plot_filename(pair, config['ticker_interval']),
|
||||||
directory=config['user_data_dir'] / "plot")
|
directory=config['user_data_dir'] / "plot")
|
||||||
|
plot_data[generate_plot_filename(pair,
|
||||||
|
config['ticker_interval'])] = {"fig": fig,
|
||||||
|
"data": dataframe,
|
||||||
|
"trades": trades}
|
||||||
|
|
||||||
logger.info('End of plotting process. %s plots generated', pair_counter)
|
logger.info('End of plotting process. %s plots generated', pair_counter)
|
||||||
|
logger.info(f'fig, data, trades are available with the keys {list(plot_data)}')
|
||||||
|
return plot_data
|
||||||
|
|
||||||
|
|
||||||
def plot_profit(config: Dict[str, Any]) -> None:
|
def plot_profit(config: Dict[str, Any], auto_open: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
Plots the total profit for all pairs.
|
Plots the total profit for all pairs.
|
||||||
Note, the profit calculation isn't realistic.
|
Note, the profit calculation isn't realistic.
|
||||||
But should be somewhat proportional, and therefor useful
|
But should be somewhat proportional, and therefor useful
|
||||||
in helping out to find a good algorithm.
|
in helping out to find a good algorithm.
|
||||||
|
:return: profit plot
|
||||||
"""
|
"""
|
||||||
plot_elements = init_plotscript(config)
|
plot_elements = init_plotscript(config)
|
||||||
trades = load_trades(config['trade_source'],
|
trades = load_trades(config['trade_source'],
|
||||||
@ -382,4 +390,5 @@ def plot_profit(config: Dict[str, Any]) -> None:
|
|||||||
# this could be useful to gauge the overall market trend
|
# this could be useful to gauge the overall market trend
|
||||||
fig = generate_profit_graph(plot_elements["pairs"], plot_elements["tickers"], trades)
|
fig = generate_profit_graph(plot_elements["pairs"], plot_elements["tickers"], trades)
|
||||||
store_plot_file(fig, filename='freqtrade-profit-plot.html',
|
store_plot_file(fig, filename='freqtrade-profit-plot.html',
|
||||||
directory=config['user_data_dir'] / "plot", auto_open=True)
|
directory=config['user_data_dir'] / "plot", auto_open=auto_open)
|
||||||
|
return fig
|
||||||
|
@ -89,31 +89,38 @@
|
|||||||
"# Specify values for use in this script\n",
|
"# Specify values for use in this script\n",
|
||||||
"############### Customize to match your needs. ##################\n",
|
"############### Customize to match your needs. ##################\n",
|
||||||
"config_files = [\n",
|
"config_files = [\n",
|
||||||
" Path('user_data', 'config.json'),\n",
|
" Path('user_data', 'user_repo', 'config.json'),\n",
|
||||||
" Path(Path.home(), '.freqtrade', 'config.json')\n",
|
" Path(Path.home(), '.freqtrade', 'exchange-config.json')\n",
|
||||||
"]\n",
|
"]\n",
|
||||||
"# Create config object\n",
|
"# Create config object\n",
|
||||||
"config = Configuration.from_files(config_files)\n",
|
"config = Configuration.from_files(config_files)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"############### Customize to match your needs. ##################\n",
|
"############### Customize to match your needs. ##################\n",
|
||||||
"# Define some constants\n",
|
"# Define some constants\n",
|
||||||
"ticker_interval = \"5m\"\n",
|
"\n",
|
||||||
"# Path to user data\n",
|
"# These values must be included in config.json or set here\n",
|
||||||
"user_data_dir = Path('user_data')\n",
|
|
||||||
"# Location of the ticker data\n",
|
|
||||||
"datadir = Path(user_data_dir, 'data/binance')\n",
|
|
||||||
"# Name of the strategy class\n",
|
"# Name of the strategy class\n",
|
||||||
"strategy_name = 'DefaultStrategy'\n",
|
"config['strategy'] = 'DefaultStrategy'\n",
|
||||||
|
"# Path to user data\n",
|
||||||
|
"config['user_data_dir'] = Path('user_data')\n",
|
||||||
|
"# Location of the ticker data\n",
|
||||||
|
"config['datadir'] = Path('user_data', 'data/binance')\n",
|
||||||
"# Location of the strategy\n",
|
"# Location of the strategy\n",
|
||||||
"strategy_path = Path(user_data_dir, 'strategies')\n",
|
"config['strategy_path'] = Path('user_data', 'strategies')\n",
|
||||||
"# Specify backtest results to load\n",
|
"# Specify backtest results to load\n",
|
||||||
"trade_source = 'file'\n",
|
"config['trade_source'] = 'file'\n",
|
||||||
"exportfilename = Path(user_data_dir, 'backtest_results/backtest-result.json')\n",
|
"config['exportfilename'] = Path('user_data', 'backtest_results/backtest-result.json')\n",
|
||||||
"db_url = 'sqlite://'\n",
|
"config['db_url'] = 'sqlite://'\n",
|
||||||
|
"\n",
|
||||||
|
"# Specify interval to analyze\n",
|
||||||
|
"ticker_interval = \"5m\"\n",
|
||||||
"# Specify timerange to test\n",
|
"# Specify timerange to test\n",
|
||||||
"timerange = '-100'\n",
|
"timerange = '-100'\n",
|
||||||
"# Pair to analyze - Only use one pair here\n",
|
"# Pair to analyze - Only use one pair here\n",
|
||||||
"pair = \"ETH/BTC\""
|
"pair = \"ETH/BTC\"\n",
|
||||||
|
"# Indicators from strategy to plot\n",
|
||||||
|
"overlay_indicators = ['ema50', 'ema100']\n",
|
||||||
|
"bottom_indicators = ['macd']"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -155,17 +162,14 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"import logging\n",
|
"import logging\n",
|
||||||
"\n",
|
"import json\n",
|
||||||
"from freqtrade.loggers import setup_logging\n",
|
"from freqtrade.loggers import setup_logging\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Configure logging\n",
|
"# Configure logging\n",
|
||||||
"logger = logging.getLogger()\n",
|
"logger = logging.getLogger()\n",
|
||||||
"setup_logging(config)\n",
|
"setup_logging(config)\n",
|
||||||
"logger.setLevel(logging.INFO)\n",
|
"logger.setLevel(logging.INFO)\n",
|
||||||
"logger.info(f'conf: {conf}')\n",
|
"logger.info(f'conf: {conf}')"
|
||||||
"\n",
|
|
||||||
"# Show config in memory\n",
|
|
||||||
"logger.info(json.dumps(config, indent=1))"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -177,8 +181,10 @@
|
|||||||
"* Load the history of the specified pair\n",
|
"* Load the history of the specified pair\n",
|
||||||
"* Load the specified strategy\n",
|
"* Load the specified strategy\n",
|
||||||
"* Generate buy and sell signals produced by the specified strategy\n",
|
"* Generate buy and sell signals produced by the specified strategy\n",
|
||||||
"* Plot the results\n",
|
"* Return a dictionary with the figure, figure dataframe and trades dataframe\n",
|
||||||
"\n",
|
" * Key is the same as the figure filename. EG: 'freqtrade-plot-ETH_BTC-15m.html'\n",
|
||||||
|
" * Display elements with dict indexing as demonstrated below\n",
|
||||||
|
" * `fig.show()` displays the chart inline `fig.show(renderer=\"browser\")` displays the chart in a tab.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"*Note: `data.head()` may include empty values for indicators that require a startup period. This is expected behavior. For example `ma5` requires 5 candles before computing the first average*\n",
|
"*Note: `data.head()` may include empty values for indicators that require a startup period. This is expected behavior. For example `ma5` requires 5 candles before computing the first average*\n",
|
||||||
"\n",
|
"\n",
|
||||||
@ -199,66 +205,21 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"from pathlib import Path\n",
|
"from freqtrade.plot.plotting import load_and_plot_trades\n",
|
||||||
"\n",
|
"\n",
|
||||||
"import pandas as pd\n",
|
"plot_data = load_and_plot_trades({'strategy': config['strategy'],\n",
|
||||||
"\n",
|
" 'strategy_path': Path(config['strategy_path']),\n",
|
||||||
"from freqtrade.data.btanalysis import load_trades\n",
|
" 'timerange': timerange,\n",
|
||||||
"from freqtrade.data.history import load_pair_history\n",
|
" 'ticker_interval': ticker_interval,\n",
|
||||||
"from freqtrade.resolvers import StrategyResolver\n",
|
" 'strategy_path': Path(config['strategy_path']),\n",
|
||||||
"from freqtrade.plot.plotting import extract_trades_of_period, generate_candlestick_graph\n",
|
" 'datadir': Path(config['datadir']),\n",
|
||||||
"# Load ticker history\n",
|
" 'user_data_dir': Path(config['user_data_dir']),\n",
|
||||||
"tickers = load_pair_history(pair=pair,\n",
|
" 'exchange': config['exchange'],\n",
|
||||||
" ticker_interval=ticker_interval,\n",
|
" 'trade_source': config['trade_source'],\n",
|
||||||
" datadir=datadir,\n",
|
" 'exportfilename': config['exportfilename'],\n",
|
||||||
" timerange=TimeRange.parse_timerange(timerange))\n",
|
" 'indicators1': overlay_indicators,\n",
|
||||||
"\n",
|
" 'indicators2': bottom_indicators\n",
|
||||||
"# Confirm success\n",
|
" })"
|
||||||
"print(\"Loaded \" + str(len(tickers)) +\n",
|
|
||||||
" f\" rows of data for {pair} from {datadir}\")\n",
|
|
||||||
"\n",
|
|
||||||
"# Load strategy\n",
|
|
||||||
"strategy = StrategyResolver({\n",
|
|
||||||
" 'strategy': strategy_name,\n",
|
|
||||||
" 'user_data_dir': user_data_dir,\n",
|
|
||||||
" 'strategy_path': strategy_path\n",
|
|
||||||
"}).strategy\n",
|
|
||||||
"\n",
|
|
||||||
"# Generate buy/sell signals using strategy\n",
|
|
||||||
"data = strategy.analyze_ticker(tickers, {'pair': pair})\n",
|
|
||||||
"logger.info(f'Indicators: {list(data)[6:-2]}')\n",
|
|
||||||
"\n",
|
|
||||||
"# Collect trades if a backtest has been completed\n",
|
|
||||||
"try:\n",
|
|
||||||
" trades = load_trades(source=trade_source,\n",
|
|
||||||
" db_url=db_url,\n",
|
|
||||||
" exportfilename=exportfilename)\n",
|
|
||||||
" trades = trades.loc[trades['pair'] == pair]\n",
|
|
||||||
" trades = extract_trades_of_period(data, trades)\n",
|
|
||||||
"except:\n",
|
|
||||||
" trades = pd.DataFrame()\n",
|
|
||||||
"\n",
|
|
||||||
"# Build and display plot\n",
|
|
||||||
"# Specify the indicators to plot as lists\n",
|
|
||||||
"# indicators1 is a list of indicators to overlay on the price chart\n",
|
|
||||||
"# indicators2 is a list of indicators to plot below the price chart\n",
|
|
||||||
"fig = generate_candlestick_graph(\n",
|
|
||||||
" pair=pair,\n",
|
|
||||||
" data=data,\n",
|
|
||||||
" trades=trades,\n",
|
|
||||||
" indicators1=['ema20', 'ema50', 'ema100'],\n",
|
|
||||||
" indicators2=['macd', 'macdsignal'])\n",
|
|
||||||
"\n",
|
|
||||||
"fig.show()\n",
|
|
||||||
"display(data.tail())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Run Backtest\n",
|
|
||||||
"Once you are happy with your strategy signals, run a backtest then plot again."
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -267,8 +228,51 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"# Run backtest\n",
|
"# Display charts and data inline\n",
|
||||||
"!freqtrade {conf} backtesting --timerange={timerange} --ticker-interval {ticker_interval} --export=trades --export-filename={exportfilename}"
|
"for idx in list(plot_data.keys()):\n",
|
||||||
|
" print(idx)\n",
|
||||||
|
" plot_data[idx]['fig'].show()\n",
|
||||||
|
" display(plot_data[idx]['data'].tail())\n",
|
||||||
|
" display(plot_data[idx]['trades'].head())"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Detailed analysis\n",
|
||||||
|
"Slice and dice your data to generate insights"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"def show_indicator_extremes(df, indicator):\n",
|
||||||
|
" '''\n",
|
||||||
|
" Sorts simulation dataframe by specified indicator\n",
|
||||||
|
" '''\n",
|
||||||
|
" df = df[df[indicator].notna()].sort_values(by=indicator, ascending=False)\n",
|
||||||
|
" return df\n",
|
||||||
|
"\n",
|
||||||
|
"# Demonstrate with first item\n",
|
||||||
|
"idx = list(plot_data.keys())[0]\n",
|
||||||
|
"indicator = overlay_indicators[0]\n",
|
||||||
|
"print(idx)\n",
|
||||||
|
"data = plot_data[idx]['data']\n",
|
||||||
|
"extremes = show_indicator_extremes(data, indicator)\n",
|
||||||
|
"display(extremes.head(10))\n",
|
||||||
|
"display(extremes.tail(10))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Run Backtest\n",
|
||||||
|
"Once you are happy with your strategy signals, run a backtest then plot again."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user