{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import vectorbtpro as vbt\n", "import numpy as np\n", "import pandas as pd\n", "from itertools import product" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "vbt.settings.set_theme('dark')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Task / Learning ##" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this exercise, we want to create and understand a 3-dim-array to make a Volume Plot in VBT.\n", "\n", "Cf. https://stackoverflow.com/a/63748235\n", "Cf. https://vectorbt.pro/api/generic/plotting/" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "x = np.zeros((2,3,4)) \n", "Simply Means:\n", "\n", "2 Sets, 3 Rows per Set, 4 Columns\n", "Example:\n", "\n", "Input\n", "\n", "x = np.zeros((2,3,4))\n", "Output\n", "\n", "Set # 1 ---- [[[ 0., 0., 0., 0.], ---- Row 1\n", " [ 0., 0., 0., 0.], ---- Row 2\n", " [ 0., 0., 0., 0.]], ---- Row 3 \n", " \n", "Set # 2 ---- [[ 0., 0., 0., 0.], ---- Row 1\n", " [ 0., 0., 0., 0.], ---- Row 2\n", " [ 0., 0., 0., 0.]]] ---- Row 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Execution ##" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Prepare sample backtest ###" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Import Some real data " ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "3044c306f4984c36b256a30e16ff861b", "version_major": 2, "version_minor": 0 }, "text/plain": [ "0it [00:00, ?it/s]" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "start = '2021-01-01 UTC' # crypto is in UTC\n", "end = '2021-12-31 UTC'\n", "timeframe = '1h'\n", "cols = ['Open', 'High', 'Low', 'Close', 'Volume']\n", "\n", "ohlcv = vbt.BinanceData.fetch('BTCUSDT', start=start, end=end, timeframe=timeframe, limit=100000).get(cols)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Basic Function to test our parameters" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def test_entry(close=ohlcv['Close'], exit_shift=1, fast_window=9, slow_window=50, wait=0):\n", " fast_ma = vbt.MA.run(close=ohlcv['Close'], window=fast_window)\n", " slow_ma = vbt.MA.run(close=ohlcv['Close'], window=slow_window)\n", " entries = fast_ma.ma_crossed_above(slow_ma, wait=wait)\n", " exits = entries.shift(exit_shift).astype(bool)\n", " pf = vbt.Portfolio.from_signals(\n", " close=close, \n", " entries=entries, \n", " exits=exits,\n", " size=100,\n", " size_type='value',\n", " init_cash='auto')\n", " return pf.stats([\n", " 'total_return', \n", " 'win_rate', \n", " 'profit_factor',\n", " 'max_dd',\n", " 'total_trades'\n", " ])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Define the ranges of our three variables (shift, slow ma, fast ma)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "exit_shift = range(5,20) # in our 3d plot, this will equal the x axis (15 values)\n", "slow_ma = range(40,60) # in our 3d plot, this will equal the y axis (20 values)\n", "fast_ma = range(7,27) # in our 3d plot, this will equal the z axis (20 values)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ".. BTW: see above, cell 5 reg. the exit_shift variable. \n", "\n", "- All it does, is \"shifting\" the entry signals x timestamps forward to generate the signal for exiting the trade. \n", "\n", "Such technique is especially helpful to inspect the reliability and robustness of your entry logic __without__ confusing it with exit indicators (want to know whether your profit comes from the entry or the exit?). That is to say, it gives you an idea, if and how frequently a move in the anticipated direction occurs after the entry signal has happened." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lets run our backtest now!" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "th_combs = list(product(exit_shift, slow_ma, fast_ma))\n", "\n", "comb_stats = [\n", " test_entry(exit_shift=exit_shift, slow_window=slow_ma, fast_window=fast_ma)\n", " for exit_shift, slow_ma, fast_ma in th_combs\n", " ] " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create a Dataframe from our results and label it accordingly" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "comb_stats_df = pd.DataFrame(comb_stats)\n", "\n", "comb_stats_df.index = pd.MultiIndex.from_tuples(\n", " th_combs, \n", " names=['exit_shift', 'slow_ma', 'fast_ma'])" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
| \n", " | \n", " | \n", " | Total Return [%] | \n", "Win Rate [%] | \n", "Profit Factor | \n", "Max Drawdown [%] | \n", "Total Trades | \n", "
|---|---|---|---|---|---|---|---|
| exit_shift | \n", "slow_ma | \n", "fast_ma | \n", "\n", " | \n", " | \n", " | \n", " | \n", " |
| 5 | \n", "40 | \n", "7 | \n", "28.620706 | \n", "52.727273 | \n", "1.289403 | \n", "12.039517 | \n", "165 | \n", "
| 8 | \n", "12.865810 | \n", "51.592357 | \n", "1.128907 | \n", "14.661135 | \n", "157 | \n", "||
| 9 | \n", "8.272885 | \n", "51.333333 | \n", "1.082172 | \n", "15.812769 | \n", "150 | \n", "||
| 10 | \n", "13.276195 | \n", "48.591549 | \n", "1.124026 | \n", "17.905736 | \n", "142 | \n", "||
| 11 | \n", "9.227458 | \n", "48.905109 | \n", "1.099671 | \n", "22.467860 | \n", "138 | \n", "||
| ... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
| 19 | \n", "59 | \n", "22 | \n", "17.943975 | \n", "59.740260 | \n", "1.195631 | \n", "35.704668 | \n", "77 | \n", "
| 23 | \n", "-2.045321 | \n", "54.545455 | \n", "0.977928 | \n", "41.559362 | \n", "77 | \n", "||
| 24 | \n", "16.698445 | \n", "54.545455 | \n", "1.177064 | \n", "32.215622 | \n", "77 | \n", "||
| 25 | \n", "26.545968 | \n", "57.142857 | \n", "1.280304 | \n", "31.915274 | \n", "77 | \n", "||
| 26 | \n", "41.837836 | \n", "57.894737 | \n", "1.456534 | \n", "29.457537 | \n", "76 | \n", "
6000 rows × 5 columns
\n", "| \n", " | \n", " | \n", " | Total Return [%] | \n", "Win Rate [%] | \n", "Profit Factor | \n", "Max Drawdown [%] | \n", "Total Trades | \n", "
|---|---|---|---|---|---|---|---|
| exit_shift | \n", "slow_ma | \n", "fast_ma | \n", "\n", " | \n", " | \n", " | \n", " | \n", " |
| 11 | \n", "53 | \n", "11 | \n", "63.973228 | \n", "55.000000 | \n", "1.973216 | \n", "9.656734 | \n", "101 | \n", "
| 8 | \n", "59 | \n", "9 | \n", "55.996476 | \n", "60.396040 | \n", "1.956220 | \n", "10.207960 | \n", "101 | \n", "
| 53 | \n", "11 | \n", "51.522183 | \n", "59.000000 | \n", "1.949297 | \n", "10.397894 | \n", "101 | \n", "|
| 9 | \n", "54 | \n", "11 | \n", "55.580395 | \n", "53.061224 | \n", "1.943820 | \n", "9.979441 | \n", "99 | \n", "
| 8 | \n", "58 | \n", "10 | \n", "54.401509 | \n", "59.405941 | \n", "1.938970 | \n", "7.701408 | \n", "101 | \n", "
| ... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
| 5 | \n", "51 | \n", "13 | \n", "-3.241266 | \n", "44.444444 | \n", "0.944172 | \n", "13.009315 | \n", "100 | \n", "
| 50 | \n", "23 | \n", "-3.665415 | \n", "46.938776 | \n", "0.926288 | \n", "14.002172 | \n", "98 | \n", "|
| 13 | \n", "-5.637548 | \n", "47.000000 | \n", "0.903764 | \n", "13.811262 | \n", "101 | \n", "||
| 51 | \n", "22 | \n", "-6.530703 | \n", "48.979592 | \n", "0.868143 | \n", "11.870502 | \n", "98 | \n", "|
| 6 | \n", "51 | \n", "22 | \n", "-6.985558 | \n", "46.938776 | \n", "0.866175 | \n", "14.173559 | \n", "98 | \n", "
909 rows × 5 columns
\n", "| \n", " | \n", " | \n", " | Total Return [%] | \n", "Win Rate [%] | \n", "Profit Factor | \n", "Max Drawdown [%] | \n", "Total Trades | \n", "
|---|---|---|---|---|---|---|---|
| exit_shift | \n", "slow_ma | \n", "fast_ma | \n", "\n", " | \n", " | \n", " | \n", " | \n", " |
| 12 | \n", "51 | \n", "7 | \n", "75.931181 | \n", "57.627119 | \n", "1.817858 | \n", "12.950735 | \n", "119 | \n", "
| 11 | \n", "57 | \n", "8 | \n", "69.868964 | \n", "56.310680 | \n", "1.917144 | \n", "9.424025 | \n", "103 | \n", "
| 51 | \n", "7 | \n", "69.634861 | \n", "53.781513 | \n", "1.769494 | \n", "11.517904 | \n", "120 | \n", "|
| 57 | \n", "7 | \n", "67.116657 | \n", "56.190476 | \n", "1.860671 | \n", "9.742177 | \n", "105 | \n", "|
| 59 | \n", "7 | \n", "66.624758 | \n", "55.339806 | \n", "1.861782 | \n", "7.539600 | \n", "103 | \n", "|
| ... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
| 5 | \n", "51 | \n", "13 | \n", "-3.241266 | \n", "44.444444 | \n", "0.944172 | \n", "13.009315 | \n", "100 | \n", "
| 50 | \n", "23 | \n", "-3.665415 | \n", "46.938776 | \n", "0.926288 | \n", "14.002172 | \n", "98 | \n", "|
| 13 | \n", "-5.637548 | \n", "47.000000 | \n", "0.903764 | \n", "13.811262 | \n", "101 | \n", "||
| 51 | \n", "22 | \n", "-6.530703 | \n", "48.979592 | \n", "0.868143 | \n", "11.870502 | \n", "98 | \n", "|
| 6 | \n", "51 | \n", "22 | \n", "-6.985558 | \n", "46.938776 | \n", "0.866175 | \n", "14.173559 | \n", "98 | \n", "
909 rows × 5 columns
\n", "