notebook documentation
This commit is contained in:
parent
228b91da20
commit
8c87ba36f9
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*.ipynb filter=nbstripout
|
||||
|
||||
*.ipynb diff=ipynb
|
@ -16,6 +16,45 @@
|
||||
"## Setup"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Change directory\n",
|
||||
"Jupyter notebooks execute from the current directory. Change working directory to the project root so that relative paths work."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"# Modify this cell to insure that the output shows the correct path.\n",
|
||||
"project_root = \"somedir/freqtrade\"\n",
|
||||
"i=0\n",
|
||||
"try:\n",
|
||||
" os.chdirdir(project_root)\n",
|
||||
" assert Path('LICENSE').is_file()\n",
|
||||
"except:\n",
|
||||
" while i<4 and (not Path('LICENSE').is_file()):\n",
|
||||
" os.chdir(Path(Path.cwd(), '../'))\n",
|
||||
" i+=1\n",
|
||||
" project_root = Path.cwd()\n",
|
||||
"print(Path.cwd())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Fix asycronous execution\n",
|
||||
"Jupyter notebooks get confused with async operations. This fixes the problem."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@ -28,17 +67,62 @@
|
||||
"nest_asyncio.apply()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Generate configuration\n",
|
||||
"This combines all config files into a single dictionary. Individual options can be manipulated with dict indexing.\n",
|
||||
"Watch out for type conversion pitfalls. The config dict created here has string values. More work needs to be done to automatically coerce strings to the expected object types. You will need to perform type conversion when passing function arguments as demonstrated in the following sections."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from os import chdir\n",
|
||||
"from pathlib import Path\n",
|
||||
"from freqtrade.configuration import Configuration\n",
|
||||
"from freqtrade.configuration.timerange import TimeRange\n",
|
||||
"\n",
|
||||
"# Change directory to project root\n",
|
||||
"chdir(Path(Path.home(), 'Documents', 'Repos', 'freqtrade'))"
|
||||
"# Load configuration\n",
|
||||
"# Specify values for use in this script\n",
|
||||
"############### Customize to match your needs. ##################\n",
|
||||
"config_files = [\n",
|
||||
" Path('user_data', 'user_repo', 'config.json'),\n",
|
||||
" Path(Path.home(), '.freqtrade', 'exchange-config.json')\n",
|
||||
"]\n",
|
||||
"# Create config object\n",
|
||||
"config = Configuration.from_files(config_files)\n",
|
||||
"\n",
|
||||
"############### Customize to match your needs. ##################\n",
|
||||
"# Define some constants\n",
|
||||
"ticker_interval = \"5m\"\n",
|
||||
"# Path to user data\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",
|
||||
"strategy_name = 'NewStrategy'\n",
|
||||
"# Location of the strategy\n",
|
||||
"strategy_path = Path(user_data_dir, 'user_repo/strategies')\n",
|
||||
"# Specify backtest results to load\n",
|
||||
"trade_source = 'file'\n",
|
||||
"exportfilename = Path(user_data_dir, 'backtest_results/backtest-result.json')\n",
|
||||
"db_url = 'sqlite://'\n",
|
||||
"# Specify timerange to test\n",
|
||||
"\n",
|
||||
"timerange = '-1000'\n",
|
||||
"# Pair to analyze - Only use one pair here\n",
|
||||
"pair = \"ETH/BTC\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Generate config argument for CLI\n",
|
||||
"CLI commands can be executed from a notebook cell by including `!` before the command. This combines all config files into a variable that can be called in a cli command as `{conf}`"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -49,20 +133,20 @@
|
||||
"source": [
|
||||
"from itertools import chain\n",
|
||||
"\n",
|
||||
"from freqtrade.configuration import Configuration\n",
|
||||
"\n",
|
||||
"# Load configuration\n",
|
||||
"# Specify values for use in this script\n",
|
||||
"# Edit to match your needs\n",
|
||||
"config_files = [\n",
|
||||
" Path('user_data', 'user_repo', 'config.json'),\n",
|
||||
" Path(Path.home(), '.freqtrade', 'exchange-config.json')\n",
|
||||
"]\n",
|
||||
"# Create config object\n",
|
||||
"config = Configuration.from_files(config_files)\n",
|
||||
"# Create config string for use in cli commands\n",
|
||||
"conf = \" \".join(\n",
|
||||
" list(chain.from_iterable([['-c', str(file)] for file in config_files])))"
|
||||
" list(chain.from_iterable([['-c', str(file)] for file in config_files])))\n",
|
||||
"\n",
|
||||
"# Example cli command\n",
|
||||
"!freqtrade {conf} backtesting --help"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Configure logging\n",
|
||||
"This imports the freqtrade logger format and displays logging messages from the internal functions."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -80,52 +164,34 @@
|
||||
"setup_logging(config)\n",
|
||||
"logger.setLevel(logging.INFO)\n",
|
||||
"logger.info(f'conf: {conf}')\n",
|
||||
"# print(json.dumps(config, indent=1))"
|
||||
"\n",
|
||||
"# Show config in memory\n",
|
||||
"logger.info(json.dumps(config, indent=1))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Download data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Download data\n",
|
||||
"!freqtrade {conf} download-data --timeframes 1m 5m 1d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Backtest"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"scrolled": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Run backtest\n",
|
||||
"!freqtrade {conf} backtesting --timerange -200 --ticker-interval 15m --refresh-pairs-cached --export=trades"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Plot"
|
||||
"## Visualize buy/sell signals\n",
|
||||
"This uses the values set in the configuration section to:\n",
|
||||
"* Load the history of the specified pair\n",
|
||||
"* Load the specified strategy\n",
|
||||
"* Generate buy and sell signals produced by the specified strategy\n",
|
||||
"* Plot the results\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",
|
||||
"\n",
|
||||
"### Possible problems\n",
|
||||
"\n",
|
||||
"* Columns with NaN values at the end of the dataframe\n",
|
||||
"* Columns used in `crossed*()` functions with completely different units\n",
|
||||
"\n",
|
||||
"### Comparison with full backtest\n",
|
||||
"\n",
|
||||
"* having 200 buy signals as output for one pair from `analyze_ticker()` does not necessarily mean that 200 trades will be made during backtesting.\n",
|
||||
"* Assuming you use only one condition such as, `df['rsi'] < 30` as buy condition, this will generate multiple \"buy\" signals for each pair in sequence (until rsi returns > 29). The bot will only buy on the first of these signals (and also only if a trade-slot (\"max_open_trades\") is still available), or on one of the middle signals, as soon as a \"slot\" becomes available. "
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -136,46 +202,74 @@
|
||||
"source": [
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"import pandas as pd\n",
|
||||
"\n",
|
||||
"from freqtrade.data.btanalysis import load_trades\n",
|
||||
"from freqtrade.data.history import load_pair_history\n",
|
||||
"from freqtrade.plot.plotting import (extract_trades_of_period,\n",
|
||||
" generate_candlestick_graph)\n",
|
||||
"from freqtrade.resolvers import StrategyResolver\n",
|
||||
"\n",
|
||||
"# Specify pair to plot\n",
|
||||
"pair = \"ETH/BTC\"\n",
|
||||
"from freqtrade.plot.plotting import extract_trades_of_period, generate_candlestick_graph\n",
|
||||
"# Load ticker history\n",
|
||||
"tickers = load_pair_history(datadir=Path(config['datadir']),\n",
|
||||
" ticker_interval=config['ticker_interval'],\n",
|
||||
" pair=pair)\n",
|
||||
"tickers = load_pair_history(pair=pair,\n",
|
||||
" ticker_interval=ticker_interval,\n",
|
||||
" datadir=datadir,\n",
|
||||
" timerange=TimeRange.parse_timerange(timerange))\n",
|
||||
"\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",
|
||||
" 'user_data_dir': Path(config['user_data_dir']),\n",
|
||||
" 'strategy_path': Path(config['strategy_path'])\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\n",
|
||||
"trades = load_trades(\n",
|
||||
" config['trade_source'],\n",
|
||||
" db_url=config.get('db_url'),\n",
|
||||
" exportfilename=config.get('exportfilename'),\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",
|
||||
" )\n",
|
||||
"\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",
|
||||
"# Specigy 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(pair=pair,\n",
|
||||
" data=data,\n",
|
||||
" trades=trades,\n",
|
||||
" indicators1=config[\"indicators1\"],\n",
|
||||
" indicators2=config[\"indicators2\"])\n",
|
||||
" indicators1=['ema20', 'ema50', 'ema100', 'ha_open', 'ha_close'],\n",
|
||||
" indicators2=['macd', 'macdsignal','ao'])\n",
|
||||
"\n",
|
||||
"fig.show()"
|
||||
"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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Run backtest\n",
|
||||
"!freqtrade {conf} backtesting --timerange={timerange} --ticker-interval {ticker_interval} --export=trades --export-filename={exportfilename}"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -195,62 +289,17 @@
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
"name": "ipython"
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.7.4"
|
||||
"nbconvert_exporter": "python"
|
||||
},
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"npconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
"nav_menu": {},
|
||||
"number_sections": true,
|
||||
"sideBar": true,
|
||||
"skip_h1_title": false,
|
||||
"title_cell": "Table of Contents",
|
||||
"title_sidebar": "Contents",
|
||||
"toc_cell": false,
|
||||
"toc_position": {},
|
||||
"toc_section_display": true,
|
||||
"toc_window_display": false
|
||||
},
|
||||
"varInspector": {
|
||||
"cols": {
|
||||
"lenName": 16,
|
||||
"lenType": 16,
|
||||
"lenVar": 40
|
||||
},
|
||||
"kernels_config": {
|
||||
"python": {
|
||||
"delete_cmd_postfix": "",
|
||||
"delete_cmd_prefix": "del ",
|
||||
"library": "var_list.py",
|
||||
"varRefreshCmd": "print(var_dic_list())"
|
||||
},
|
||||
"r": {
|
||||
"delete_cmd_postfix": ") ",
|
||||
"delete_cmd_prefix": "rm(",
|
||||
"library": "var_list.r",
|
||||
"varRefreshCmd": "cat(var_dic_list()) "
|
||||
}
|
||||
},
|
||||
"types_to_exclude": [
|
||||
"module",
|
||||
"function",
|
||||
"builtin_function_or_method",
|
||||
"instance",
|
||||
"_Feature"
|
||||
],
|
||||
"window_display": false
|
||||
},
|
||||
"version": 3
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
Loading…
Reference in New Issue
Block a user