{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Robustness evaluation\n", "\n", "Input is backtest results in the format:\n", "- Parameter combination (multiindex)\n", "- Profitability metrics (columns)\n", "Lets explore various way to evaluate robustness.\n", "\n", "These are various areas to explore\n", "\n", "- [1](https://chatgpt.com/share/66fc06c0-edc4-8013-b228-16ee51dacff8)\n", "- [2](https://chatgpt.com/share/66fc0ab7-2004-8013-86ca-299af96feb57)\n", "- [3](https://chatgpt.com/share/66ffc5b3-6f10-8013-8ffa-38b09e778e0f)\n", "- [4](https://chatgpt.com/share/66ffc5c4-6a28-8013-92ad-ea5bef243b39)\n", "- [5](https://chatgpt.com/share/66ffc5d4-1100-8013-9cfb-3de2aa3cb136)\n", "- [6](https://chatgpt.com/share/66ffc5e7-0550-8013-9f88-f5069c78f7f7)" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "#!pip install git+https://github.com/drew2323/lightweight-charts-python.git\n", "#!pip install git+https://gitea.stratlab.dev/Stratlab/db.git\n", "from lightweight_charts import Panel, chart, PlotSRAccessor, PlotDFAccessor\n", "import pandas as pd\n", "import numpy as np\n", "import vectorbtpro as vbt\n", "# from itables import init_notebook_mode, show\n", "import datetime\n", "from itertools import product\n", "from IPython.display import display\n", "# init_notebook_mode(all_interactive=True)\n", "\n", "vbt.settings.set_theme(\"dark\")\n", "vbt.settings['plotting']['layout']['width'] = 1280\n", "vbt.settings.plotting.auto_rangebreaks = True\n", "# Set the option to display with pagination\n", "pd.set_option('display.notebook_repr_html', True)\n", "pd.set_option('display.max_rows', 10) # Number of rows per page" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "0aa468b6ecdb4dc283eae910cef9b72f", "version_major": 2, "version_minor": 0 }, "text/plain": [ "100%|##########| 1/1 [00:03<00:00, 3.21s/it, symbol=BAC]" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "#fetching US-STOCKS ohlcv_1s\n", "from lib.db import Connection\n", "SYMBOL = \"BAC\"\n", "SCHEMA = \"ohlcv_1s\" #time based 1s other options ohlcv_vol_200 (volume based ohlcv with resolution of 200), ohlcv_renko_20 (renko with 20 bricks size) ...\n", "DB = \"market_data\"\n", "\n", "con = Connection(db_name=DB, default_schema=SCHEMA, create_db=True)\n", "basic_data = con.pull(symbols=[SYMBOL], schema=SCHEMA,start=\"2024-08-01\", end=\"2024-08-05\", tz_convert='America/New_York')\n", "\n", "#basic_data.data[SYMBOL].info()\n", "\n", "#1month 1s data - 15s - 24MB\n" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Error fetching main session\n" ] }, { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "#basic_data.ohlcv.data[SYMBOL].lw.plot()\n", "basic_data.ohlcv.data[SYMBOL].lw.plot(size=\"xs\")" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "basic_data.data[SYMBOL].vwap.lw.plot()\n" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "basic_data.data[SYMBOL].vwap.lw.plot(histogram=(basic_data.data[SYMBOL].trades, \"trades\"))\n", "\n", " #xloc[\"2024-08-05\":\"2024-08-10\"]" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Define the market open and close times\n", "market_open = datetime.time(9, 30)\n", "market_close = datetime.time(16, 0)\n", "entry_window_opens = 1\n", "entry_window_closes = 370\n", "forced_exit_start = 380\n", "forced_exit_end = 390\n", "\n", "#NUMDAYS\n", "basic_data.wrapper.index.normalize().nunique()\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Add resample function to custom columns" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "from vectorbtpro.utils.config import merge_dicts, Config, HybridConfig\n", "from vectorbtpro import _typing as tp\n", "from vectorbtpro.generic import nb as generic_nb\n", "\n", "_feature_config: tp.ClassVar[Config] = HybridConfig(\n", " {\n", " \"buyvolume\": dict(\n", " resample_func=lambda self, obj, resampler: obj.vbt.resample_apply(\n", " resampler,\n", " generic_nb.sum_reduce_nb,\n", " )\n", " ),\n", " \"sellvolume\": dict(\n", " resample_func=lambda self, obj, resampler: obj.vbt.resample_apply(\n", " resampler,\n", " generic_nb.sum_reduce_nb,\n", " )\n", " ),\n", " \"trades\": dict(\n", " resample_func=lambda self, obj, resampler: obj.vbt.resample_apply(\n", " resampler,\n", " generic_nb.sum_reduce_nb,\n", " )\n", " )\n", " }\n", ")\n", "\n", "basic_data._feature_config = _feature_config" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "s1data = basic_data[['open', 'high', 'low', 'close', 'volume','vwap','buyvolume','trades','sellvolume']]\n", "\n", "# s5data = s1data.resample(\"12s\")\n", "# s5data = s5data.transform(lambda df: df.between_time('09:30', '16:00').dropna())\n", "\n", "t1data = basic_data[['open', 'high', 'low', 'close', 'volume','vwap','buyvolume','trades','sellvolume']].resample(\"1T\")\n", "t1data = t1data.transform(lambda df: df.between_time('09:30', '16:00').dropna())\n", "# t1data.data[\"BAC\"].info()\n", "\n", "# t30data = basic_data[['open', 'high', 'low', 'close', 'volume','vwap','buyvolume','trades','sellvolume']].resample(\"30T\")\n", "# t30data = t30data.transform(lambda df: df.between_time('09:30', '16:00').dropna())\n", "# # t30data.data[\"BAC\"].info()\n", "\n", "s1close = s1data.data[\"BAC\"].close\n", "t1close = t1data.data[\"BAC\"].close\n", "\n", "#realign t1data to s1data realign_closing\n", "\n", "\n", "\n", "#t1data.data[\"BAC\"].close.lw.plot()\n" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "time\n", "2024-08-01 09:30:00-04:00 40.3950\n", "2024-08-01 09:30:01-04:00 40.3600\n", "2024-08-01 09:30:02-04:00 40.3700\n", "2024-08-01 09:30:03-04:00 40.3700\n", "2024-08-01 09:30:04-04:00 40.3300\n", " ... \n", "2024-08-02 15:59:55-04:00 37.5799\n", "2024-08-02 15:59:56-04:00 37.5700\n", "2024-08-02 15:59:57-04:00 37.5800\n", "2024-08-02 15:59:58-04:00 37.5800\n", "2024-08-02 15:59:59-04:00 37.5800\n", "Name: close, Length: 29909, dtype: float64" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s1close" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "resampler_s = vbt.Resampler(t1data.index, s1data.index, source_freq=\"1T\", target_freq=\"1s\")\n", "t1close_realigned = t1close.vbt.realign_closing(resampler_s)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "\n", "#display 1s close with 1min close along with 1min realigned\n", "s1close.lw.plot(name=\"1s\", right=[(t1close, \"1min\"),(t1close_realigned, \"1min_realigned\")])\n" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "#display 1min ohlcv along with 1s close with 1min close realigned\n", "t1data.ohlcv.data[\"BAC\"].lw.plot(right=[(s1close, \"1ms\"),(t1close_realigned, \"1min_realigned\")])" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 't30data' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[13], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m#resample on specific index \u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m resampler \u001b[38;5;241m=\u001b[39m vbt\u001b[38;5;241m.\u001b[39mResampler(\u001b[43mt30data\u001b[49m\u001b[38;5;241m.\u001b[39mindex, s1data\u001b[38;5;241m.\u001b[39mindex, source_freq\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m30T\u001b[39m\u001b[38;5;124m\"\u001b[39m, target_freq\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m1s\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 3\u001b[0m t30close_realigned \u001b[38;5;241m=\u001b[39m t30close\u001b[38;5;241m.\u001b[39mvbt\u001b[38;5;241m.\u001b[39mrealign_closing(resampler)\n\u001b[1;32m 5\u001b[0m \u001b[38;5;66;03m#resample 1min to s\u001b[39;00m\n", "\u001b[0;31mNameError\u001b[0m: name 't30data' is not defined" ] } ], "source": [ "#resample on specific index \n", "resampler = vbt.Resampler(t30data.index, s1data.index, source_freq=\"30T\", target_freq=\"1s\")\n", "t30close_realigned = t30close.vbt.realign_closing(resampler)\n", "\n", "#resample 1min to s\n", "resampler_s = vbt.Resampler(t1data.index, s1data.index, source_freq=\"1T\", target_freq=\"1s\")\n", "t1close_realigned = t1close.vbt.realign_closing(resampler_s)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['talib:MOM']" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\n", "#vbt.IF.list_indicators(\"*vwap\")\n", "vbt.IF.list_indicators(\"*mom\")" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "MOM.run(\n", " close,\n", " timeperiod=Default(value=10),\n", " timeframe=Default(value=None),\n", " short_name='mom',\n", " hide_params=None,\n", " hide_default=True,\n", " **kwargs\n", "):\n", " Run `MOM` indicator.\n", " \n", " * Inputs: `close`\n", " * Parameters: `timeperiod`, `timeframe`\n", " * Outputs: `real`\n", " \n", " Pass a list of parameter names as `hide_params` to hide their column levels, or True to hide all.\n", " Set `hide_default` to False to show the column levels of the parameters with a default value.\n", " \n", " Other keyword arguments are passed to `MOM.run_pipeline`.\n" ] } ], "source": [ "vbt.phelp(vbt.indicator(\"talib:MOM\").run)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "t1mom_tt = vbt.indicator(\"talib:MOM\").run(t1data.data[\"BAC\"].close, timeperiod=20, timeframe=[\"1T\",\"5T\"])\n", "t1mom = vbt.indicator(\"talib:MOM\").run(t1data.data[\"BAC\"].close, timeperiod=20, timeframe=\"1T\")\n", "t1data.ohlcv.data[\"BAC\"].lw.plot(left=[(t1mom,\"mom\"),(t1mom_tt.mom.loc[:, (20,\"1T\")],),(t1mom_tt.mom.loc[:, (20,\"5T\")],)], size=\"m\") #right=[(s1close, \"1ms\"),(t1close_realigned, \"1min_realigned\")]\n", "\n", "#t1mom.mom[t1mom.mom.notna()]\n", "#t1mom_tt.mom.loc[:, (20,\"1T\")]\n", "\n", "\n", "#t1data.ohlcv.data[\"BAC\"].lw.plot(left=[(t1mom,\"mom\"),(t1mom_tt.mom,),(t1mom_tt.mom,)]) #right=[(s1close, \"1ms\"),(t1close_realigned, \"1min_realigned\")]\n", "\n" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
mom_timeperiod20
mom_timeframe1T5T
time
2024-08-01 09:30:00-04:00NaNNaN
2024-08-01 09:31:00-04:00NaNNaN
2024-08-01 09:32:00-04:00NaNNaN
2024-08-01 09:33:00-04:00NaNNaN
2024-08-01 09:34:00-04:00NaNNaN
.........
2024-08-02 15:55:00-04:000.12000.1749
2024-08-02 15:56:00-04:000.08500.1749
2024-08-02 15:57:00-04:000.13000.1749
2024-08-02 15:58:00-04:000.11510.1749
2024-08-02 15:59:00-04:000.20500.3250
\n", "

780 rows × 2 columns

\n", "
" ], "text/plain": [ "mom_timeperiod 20 \n", "mom_timeframe 1T 5T\n", "time \n", "2024-08-01 09:30:00-04:00 NaN NaN\n", "2024-08-01 09:31:00-04:00 NaN NaN\n", "2024-08-01 09:32:00-04:00 NaN NaN\n", "2024-08-01 09:33:00-04:00 NaN NaN\n", "2024-08-01 09:34:00-04:00 NaN NaN\n", "... ... ...\n", "2024-08-02 15:55:00-04:00 0.1200 0.1749\n", "2024-08-02 15:56:00-04:00 0.0850 0.1749\n", "2024-08-02 15:57:00-04:00 0.1300 0.1749\n", "2024-08-02 15:58:00-04:00 0.1151 0.1749\n", "2024-08-02 15:59:00-04:00 0.2050 0.3250\n", "\n", "[780 rows x 2 columns]" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t1mom_tt.mom" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "vbt.phelp(vbt.VWAP.run)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# VWAP" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "\n", "t1vwap_h = vbt.VWAP.run(t1data.high, t1data.low, t1data.close, t1data.volume, anchor=\"H\")\n", "t1vwap_d = vbt.VWAP.run(t1data.high, t1data.low, t1data.close, t1data.volume, anchor=\"D\")\n", "t1vwap_t = vbt.VWAP.run(t1data.high, t1data.low, t1data.close, t1data.volume, anchor=\"T\")\n", "\n", "t1vwap_h_real = t1vwap_h.vwap.vbt.realign_closing(resampler_s)\n", "t1vwap_d_real = t1vwap_d.vwap.vbt.realign_closing(resampler_s)\n", "t1vwap_t_real = t1vwap_t.vwap.vbt.realign_closing(resampler_s)\n", "\n", "#t1vwap_5t.xloc[\"2024-01-3 09:30:00\":\"2024-01-03 16:00:00\"].plot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "#m30data.close.lw.plot()\n", "#quick few liner\n", "pane1 = Panel(\n", " histogram=[\n", " #(s1data.volume, \"volume\",None, 0.8),\n", " #(m30volume, \"m30volume\",None, 1)\n", " ], # [(series, name, \"rgba(53, 94, 59, 0.6)\", opacity)]\n", " right=[\n", " (s1data.close, \"1s close\"),\n", " (t1data.close, \"1min close\"),\n", " (t1vwap_t, \"1mvwap_t\"),\n", " (t1vwap_h, \"1mvwap_h\"),\n", " (t1vwap_d, \"1mvwap_d\"),\n", " (t1vwap_t_real, \"1mvwap_t_real\"),\n", " (t1vwap_h_real, \"1mvwap_h_real\"),\n", " (t1vwap_d_real, \"1mvwap_d_real\")\n", " # (t1close_realigned, \"1min close realigned\"),\n", " # (m30data.close, \"30min-close\"),\n", " # (m30close_realigned, \"30min close realigned\"),\n", " ],\n", ")\n", "ch = chart([pane1], size=\"s\" ) #xloc=slice(\"2024-05-1 09:30:00\",\"2024-05-25 16:00:00\"))" ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.11" } }, "nbformat": 4, "nbformat_minor": 2 }