{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "16f4ed9b-5a03-4225-b54c-9a8be3f32cfa",
   "metadata": {},
   "source": [
    "# Patterns and projections"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "09993824-ddc7-4e30-8bb6-a1e86f6bf78c",
   "metadata": {},
   "source": [
    "## Patterns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f28adb62-732c-4fdb-90eb-553650314736",
   "metadata": {},
   "outputs": [],
   "source": [
    "from vectorbtpro import *\n",
    "# whats_imported()\n",
    "\n",
    "vbt.settings.set_theme(\"dark\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b2745757-3cce-42f9-ac4c-2efe41ec4d20",
   "metadata": {},
   "outputs": [],
   "source": [
    "data = vbt.BinanceData.pull(\n",
    "    \"BTCUSDT\", \n",
    "    start=\"2020-06-01 UTC\", \n",
    "    end=\"2022-06-01 UTC\"\n",
    ")\n",
    "data.plot().show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8d28352b-b24d-4d9e-b2ff-8b893dc09da7",
   "metadata": {},
   "outputs": [],
   "source": [
    "data_window = data.loc[\"2021-09-25\":\"2021-11-25\"]\n",
    "data_window.plot(plot_volume=False).show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7dfcdf27-18b3-4fe1-bcc1-8ebf681827e7",
   "metadata": {},
   "outputs": [],
   "source": [
    "price_window = data_window.hlc3\n",
    "price_window.vbt.plot().show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a65950da-0df5-4371-8b50-54ded8fbfa7f",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern = np.array([1, 2, 3, 2, 3, 2])\n",
    "pd.Series(pattern).vbt.plot().show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ec71f516-e9ca-4238-befd-c2a30b9018ce",
   "metadata": {},
   "source": [
    "### Interpolation"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9b36945d-dc5b-4cc1-a53b-683ac294a657",
   "metadata": {},
   "source": [
    "#### Linear"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3b2eceec-da77-4cf5-bb5b-2355fdff5db2",
   "metadata": {},
   "outputs": [],
   "source": [
    "resized_pattern = vbt.nb.interp_resize_1d_nb(\n",
    "    pattern, 10, vbt.enums.InterpMode.Linear\n",
    ")\n",
    "resized_pattern"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "56ed8dd0-0192-4242-9a86-906c1cdf9982",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_linear(n):\n",
    "    resized_pattern = vbt.nb.interp_resize_1d_nb(\n",
    "        pattern, n, vbt.enums.InterpMode.Linear\n",
    "    )\n",
    "    return pd.Series(resized_pattern).vbt.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2e4d8724-6fc6-436e-b9aa-abdf9d97b12b",
   "metadata": {},
   "outputs": [],
   "source": [
    "plot_linear(7).show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f377c765-e433-4059-a757-50ba4da8a9c0",
   "metadata": {},
   "outputs": [],
   "source": [
    "resized_pattern = vbt.nb.interp_resize_1d_nb(\n",
    "    pattern, 7, vbt.enums.InterpMode.Linear\n",
    ")\n",
    "ratio = (len(pattern) - 1) / (len(resized_pattern) - 1)\n",
    "new_points = np.arange(len(resized_pattern)) * ratio\n",
    "fig = pd.Series(pattern).vbt.plot()\n",
    "pd.Series(resized_pattern, index=new_points).vbt.scatterplot(fig=fig).show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f0090d25-94e2-4be3-a4ae-e86f6f766228",
   "metadata": {},
   "source": [
    "#### Nearest"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7727b0c3-2d09-43c1-be29-f4c0b40a6e36",
   "metadata": {},
   "outputs": [],
   "source": [
    "resized_pattern = vbt.nb.interp_resize_1d_nb(\n",
    "    pattern, 10, vbt.enums.InterpMode.Nearest\n",
    ")\n",
    "resized_pattern"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "13433f4a-b921-4be1-9f5f-8d3cc8b07eb4",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_nearest(n):\n",
    "    resized_pattern = vbt.nb.interp_resize_1d_nb(\n",
    "        pattern, n, vbt.enums.InterpMode.Nearest\n",
    "    )\n",
    "    return pd.Series(resized_pattern).vbt.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c6a581f9-446f-4424-b6a1-535aa9bd6248",
   "metadata": {},
   "outputs": [],
   "source": [
    "plot_nearest(7).show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "07bcf923-36ac-41c3-b660-a70d78917584",
   "metadata": {},
   "source": [
    "#### Discrete"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "40e606f5-9bf1-41ef-acf2-86e595e73407",
   "metadata": {},
   "outputs": [],
   "source": [
    "resized_pattern = vbt.nb.interp_resize_1d_nb(\n",
    "    pattern, 10, vbt.enums.InterpMode.Discrete\n",
    ")\n",
    "resized_pattern"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "be23bbd3-9ab7-458b-bfcd-a8b0d8625420",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_discrete(n):\n",
    "    resized_pattern = vbt.nb.interp_resize_1d_nb(\n",
    "        pattern, n, vbt.enums.InterpMode.Discrete\n",
    "    )\n",
    "    return pd.Series(resized_pattern).vbt.plot(\n",
    "        trace_kwargs=dict(\n",
    "            line=dict(dash=\"dot\"), \n",
    "            connectgaps=True\n",
    "        )\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1091a1ec-3be9-49a3-a600-d47a45536131",
   "metadata": {},
   "outputs": [],
   "source": [
    "plot_discrete(7).show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8d730164-6099-42cf-8bd0-f4b8b531a221",
   "metadata": {},
   "source": [
    "#### Mixed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d9f7a8c5-0361-43b3-bcdd-d68173155404",
   "metadata": {},
   "outputs": [],
   "source": [
    "resized_pattern = vbt.nb.interp_resize_1d_nb(\n",
    "    pattern, 10, vbt.enums.InterpMode.Mixed\n",
    ")\n",
    "resized_pattern"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0c7bc0c0-8f09-4191-a4e4-644fd067b8e1",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_mixed(n):\n",
    "    lin_resized_pattern = vbt.nb.interp_resize_1d_nb(\n",
    "        pattern, n, vbt.enums.InterpMode.Linear\n",
    "    )\n",
    "    mix_resized_pattern = vbt.nb.interp_resize_1d_nb(\n",
    "        pattern, n, vbt.enums.InterpMode.Mixed\n",
    "    )\n",
    "    fig = pd.Series(lin_resized_pattern, name=\"Linear\").vbt.plot()\n",
    "    return pd.Series(mix_resized_pattern, name=\"Mixed\").vbt.plot(fig=fig)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7f44cc40-77ee-4e1d-9c4c-acb926793cf0",
   "metadata": {},
   "outputs": [],
   "source": [
    "plot_mixed(7).show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1a3ce6d1-8a17-4320-9421-91b6baf63672",
   "metadata": {},
   "outputs": [],
   "source": [
    "resized_pattern = vbt.nb.interp_resize_1d_nb(\n",
    "    pattern, len(price_window), vbt.enums.InterpMode.Mixed\n",
    ")\n",
    "resized_pattern.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dd584ad8-1021-440f-8560-05e5bb00773f",
   "metadata": {},
   "source": [
    "### Rescaling"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "71c86abd-dfa5-474c-bad9-d8027dc6f7f1",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_scale = (resized_pattern.min(), resized_pattern.max())\n",
    "price_window_scale = (price_window.min(), price_window.max())\n",
    "rescaled_pattern = vbt.utils.array_.rescale_nb(\n",
    "    resized_pattern, pattern_scale, price_window_scale\n",
    ")\n",
    "rescaled_pattern = pd.Series(rescaled_pattern, index=price_window.index)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "118dc7e7-a701-4ca9-986a-f3d0ba840a0d",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = price_window.vbt.plot()\n",
    "rescaled_pattern.vbt.plot(\n",
    "    trace_kwargs=dict(\n",
    "        fill=\"tonexty\", \n",
    "        fillcolor=\"rgba(255, 100, 0, 0.25)\"\n",
    "    ), \n",
    "    fig=fig\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3f2b7762-2194-48c3-9c01-6b545edfa00f",
   "metadata": {},
   "source": [
    "#### Rebasing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3cd899eb-3a74-4a7d-ac80-f84f70d2c582",
   "metadata": {},
   "outputs": [],
   "source": [
    "pct_pattern = np.array([1, 1.3, 1.6, 1.3, 1.6, 1.3])\n",
    "resized_pct_pattern = vbt.nb.interp_resize_1d_nb(\n",
    "    pct_pattern, len(price_window), vbt.enums.InterpMode.Mixed\n",
    ")\n",
    "rebased_pattern = resized_pct_pattern / resized_pct_pattern[0]\n",
    "rebased_pattern *= price_window.values[0]\n",
    "rebased_pattern = pd.Series(rebased_pattern, index=price_window.index)\n",
    "fig = price_window.vbt.plot()\n",
    "rebased_pattern.vbt.plot(\n",
    "    trace_kwargs=dict(\n",
    "        fill=\"tonexty\", \n",
    "        fillcolor=\"rgba(255, 100, 0, 0.25)\"\n",
    "    ), \n",
    "    fig=fig\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "04a1cec7-cbd2-4653-8908-04e8439f3079",
   "metadata": {},
   "source": [
    "### Similarity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5a91fb91-2c80-49ec-a3ba-fd548952b2b2",
   "metadata": {},
   "outputs": [],
   "source": [
    "abs_distances = np.abs(rescaled_pattern - price_window.values)\n",
    "mae = abs_distances.sum()\n",
    "max_abs_distances = np.column_stack((\n",
    "    (price_window.max() - rescaled_pattern), \n",
    "    (rescaled_pattern - price_window.min())\n",
    ")).max(axis=1)\n",
    "max_mae = max_abs_distances.sum()\n",
    "similarity = 1 - mae / max_mae\n",
    "similarity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "71c95949-c983-46b5-9393-e8d842d9652b",
   "metadata": {},
   "outputs": [],
   "source": [
    "quad_distances = (rescaled_pattern - price_window.values) ** 2\n",
    "rmse = np.sqrt(quad_distances.sum())\n",
    "max_quad_distances = np.column_stack((\n",
    "    (price_window.max() - rescaled_pattern), \n",
    "    (rescaled_pattern - price_window.min())\n",
    ")).max(axis=1) ** 2\n",
    "max_rmse = np.sqrt(max_quad_distances.sum())\n",
    "similarity = 1 - rmse / max_rmse\n",
    "similarity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1a6017cf-5a86-4b3d-9aa9-18d5729817cf",
   "metadata": {},
   "outputs": [],
   "source": [
    "quad_distances = (rescaled_pattern - price_window.values) ** 2\n",
    "mse = quad_distances.sum()\n",
    "max_quad_distances = np.column_stack((\n",
    "    (price_window.max() - rescaled_pattern), \n",
    "    (rescaled_pattern - price_window.min())\n",
    ")).max(axis=1) ** 2\n",
    "max_mse = max_quad_distances.sum()\n",
    "similarity = 1 - mse / max_mse\n",
    "similarity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d8eb54f6-9562-4a95-b793-c9f661835d01",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(price_window.values, pattern)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8ff3ef28-c13d-4eb2-804f-bb4a008c60a0",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(\n",
    "    price_window.values, \n",
    "    pct_pattern, \n",
    "    rescale_mode=vbt.enums.RescaleMode.Rebase\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bbba899c-eb0a-4c10-ba0a-da3d92db43ac",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(\n",
    "    price_window.values, \n",
    "    pct_pattern, \n",
    "    interp_mode=vbt.enums.InterpMode.Nearest,\n",
    "    rescale_mode=vbt.enums.RescaleMode.Rebase,\n",
    "    distance_measure=vbt.enums.DistanceMeasure.RMSE\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "58aca67c-c274-4d11-a6b8-c8d68d45dc44",
   "metadata": {},
   "outputs": [],
   "source": [
    "price_window.vbt.plot_pattern(\n",
    "    pct_pattern, \n",
    "    interp_mode=\"nearest\",\n",
    "    rescale_mode=\"rebase\",\n",
    "    fill_distance=True\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9dc007d9-1cdf-4783-9217-4f032fee6284",
   "metadata": {},
   "outputs": [],
   "source": [
    "adj_pct_pattern = np.array([1, 1.3, 1.6, 1.45, 1.6, 1.3])\n",
    "vbt.nb.pattern_similarity_nb(\n",
    "    price_window.values, \n",
    "    adj_pct_pattern, \n",
    "    interp_mode=vbt.enums.InterpMode.Nearest,\n",
    "    rescale_mode=vbt.enums.RescaleMode.Rebase,\n",
    "    distance_measure=vbt.enums.DistanceMeasure.RMSE\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "21f3b1f9-d97e-4c34-8f36-a316a8a26221",
   "metadata": {},
   "outputs": [],
   "source": [
    "price_window.vbt.plot_pattern(\n",
    "    adj_pct_pattern, \n",
    "    interp_mode=\"discrete\",\n",
    "    rescale_mode=\"rebase\",\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "deb354ad-8971-4d44-bbc5-fabccb5afc2e",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(\n",
    "    price_window.values, \n",
    "    adj_pct_pattern, \n",
    "    interp_mode=vbt.enums.InterpMode.Discrete,\n",
    "    rescale_mode=vbt.enums.RescaleMode.Rebase,\n",
    "    distance_measure=vbt.enums.DistanceMeasure.RMSE\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "71532171-5624-4c6b-9dd0-1853590b31f2",
   "metadata": {},
   "source": [
    "#### Relative"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f72cd3c8-a561-485e-9ab6-30edefc53143",
   "metadata": {},
   "outputs": [],
   "source": [
    "abs_pct_distances = abs_distances / rescaled_pattern\n",
    "pct_mae = abs_pct_distances.sum()\n",
    "max_abs_pct_distances = max_abs_distances / rescaled_pattern\n",
    "max_pct_mae = max_abs_pct_distances.sum()\n",
    "similarity = 1 - pct_mae / max_pct_mae\n",
    "similarity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d4b8a531-000f-4837-a069-388897e709e1",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(\n",
    "    price_window.values, \n",
    "    pct_pattern, \n",
    "    error_type=vbt.enums.ErrorType.Relative\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7784e836-786a-4e92-a605-431beb635e12",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(\n",
    "    np.array([10, 30, 100]),\n",
    "    np.array([1, 2, 3]),\n",
    "    error_type=vbt.enums.ErrorType.Absolute\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bfcec566-fb2e-42b6-b8f1-03dc347f2986",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(\n",
    "    np.array([10, 30, 100]),\n",
    "    np.array([1, 2, 3]),\n",
    "    error_type=vbt.enums.ErrorType.Relative\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e2a99c01-cafb-443e-9851-a54cd04114c7",
   "metadata": {},
   "source": [
    "#### Inverse"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fc894117-9148-4e6f-a812-c01f15aa8d66",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(price_window.values, pattern, invert=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f932cc4d-885f-46b0-b306-e05eb3329d6b",
   "metadata": {},
   "outputs": [],
   "source": [
    "price_window.vbt.plot_pattern(pattern, invert=True).show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a5faa78d-c7c7-47f3-8847-bf19c4b4ee04",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern.max() + pattern.min() - pattern"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e8bd3c8-4112-4c57-9b37-05b79a0f483c",
   "metadata": {},
   "source": [
    "#### Max error"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2f2e0182-3e5e-4809-bde4-ff4aeaf33ce2",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(\n",
    "    price_window.values, \n",
    "    pattern,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cbd19ab7-16d6-4c94-9ca1-bbba7ea8f88d",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(\n",
    "    price_window.values, \n",
    "    pattern, \n",
    "    max_error=np.array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5]),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bf4b4ec8-9665-4400-9fa5-bebf204eeb4a",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(\n",
    "    price_window.values, \n",
    "    pattern, \n",
    "    max_error=np.array([0.5]),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e562481d-6e22-4d6f-99af-4a6e763fdbcd",
   "metadata": {},
   "outputs": [],
   "source": [
    "price_window.vbt.plot_pattern(\n",
    "    pattern, \n",
    "    max_error=0.5\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2b697b1e-6806-4813-84c0-59fc58b7c1ab",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(\n",
    "    price_window.values, \n",
    "    pattern, \n",
    "    max_error=np.array([0.5]),\n",
    "    max_error_strict=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9a20ef9a-11fe-418b-a6c5-1334826176bd",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(\n",
    "    price_window.values, \n",
    "    adj_pct_pattern, \n",
    "    rescale_mode=vbt.enums.RescaleMode.Rebase,\n",
    "    max_error=np.array([0.2, 0.1, 0.05, 0.1, 0.05, 0.1]),\n",
    "    max_error_strict=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ab8bbd05-b4f0-421f-8180-05ad7c84087e",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(\n",
    "    price_window.values, \n",
    "    pattern, \n",
    "    max_error=np.array([0.1]),\n",
    "    error_type=vbt.enums.ErrorType.Relative\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b6ff62e3-ccee-40bb-9e03-ab1e78f12547",
   "metadata": {},
   "outputs": [],
   "source": [
    "price_window.vbt.plot_pattern(\n",
    "    pattern, \n",
    "    max_error=0.1,\n",
    "    error_type=\"relative\"\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a741780d-857d-4111-9731-00ac63e8bdcb",
   "metadata": {},
   "outputs": [],
   "source": [
    "price_window.vbt.plot_pattern(\n",
    "    adj_pct_pattern, \n",
    "    rescale_mode=\"rebase\",\n",
    "    max_error=np.array([0.2, 0.1, 0.05, 0.1, 0.05, 0.1])\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "71b9ca1e-8074-45f2-b62a-9e8fddb560a5",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(\n",
    "    price_window.values, \n",
    "    adj_pct_pattern, \n",
    "    rescale_mode=vbt.enums.RescaleMode.Rebase,\n",
    "    max_error=np.array([0.2, 0.1, 0.05, 0.1, 0.05, 0.1]) + 0.05,\n",
    "    max_error_strict=True\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bacece86-cc55-4499-959b-49eb7c99a8c8",
   "metadata": {},
   "source": [
    "##### Interpolation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f92c333c-fe6e-41bc-9f17-fcd9d8846b24",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(\n",
    "    price_window.values, \n",
    "    adj_pct_pattern, \n",
    "    rescale_mode=vbt.enums.RescaleMode.Rebase,\n",
    "    max_error=np.array([np.nan, np.nan, 0.1, np.nan, 0.1, np.nan]),\n",
    "    max_error_interp_mode=vbt.enums.InterpMode.Discrete,\n",
    "    max_error_strict=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0b4ea56d-a9fd-4b5e-b8be-4212ae0a2815",
   "metadata": {},
   "outputs": [],
   "source": [
    "price_window.vbt.plot_pattern(\n",
    "    adj_pct_pattern, \n",
    "    rescale_mode=\"rebase\",\n",
    "    max_error=np.array([np.nan, np.nan, 0.1, np.nan, 0.1, np.nan]),\n",
    "    max_error_interp_mode=\"discrete\"\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f42d2d89-09a2-469c-9490-84267a973202",
   "metadata": {},
   "source": [
    "##### Max distance"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dc55ea4c-35b3-4fef-952a-ece601444a72",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(price_window.values, pattern)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "29587bc3-998e-4096-be6b-e4e91902e4ae",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(\n",
    "    price_window.values, \n",
    "    pattern, \n",
    "    max_error=np.array([0.5]),\n",
    "    max_error_as_maxdist=True\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "481524c4-d6c6-4f2e-a862-f60f65149a84",
   "metadata": {},
   "source": [
    "#### Further filters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "112660d1-e7be-4f51-9db4-93b79a22fca9",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(price_window.values, pattern, max_pct_change=0.3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a3fe67b2-0532-45d3-a757-e03a8f05f7f5",
   "metadata": {},
   "outputs": [],
   "source": [
    "vbt.nb.pattern_similarity_nb(price_window.values, pattern, min_similarity=0.9)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "df50b2a9-7bf7-47c8-8292-91043252f9cc",
   "metadata": {},
   "source": [
    "### Rolling similarity"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "97dc4e9d-9285-4909-9499-6792d44379d9",
   "metadata": {},
   "outputs": [],
   "source": [
    "price = data.hlc3\n",
    "\n",
    "similarity = price.vbt.rolling_pattern_similarity(\n",
    "    pattern, \n",
    "    window=30,\n",
    "    error_type=\"relative\",\n",
    "    max_error=0.05,\n",
    "    max_error_interp_mode=\"discrete\"\n",
    ")\n",
    "similarity.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "27d7ae88-d60d-4be7-be44-d148d3dcef1b",
   "metadata": {},
   "outputs": [],
   "source": [
    "end_row = similarity.argmax() + 1\n",
    "start_row = end_row - 30\n",
    "fig = data.iloc[start_row:end_row].plot(plot_volume=False)\n",
    "price.iloc[start_row:end_row].vbt.plot_pattern(\n",
    "    pattern, \n",
    "    error_type=\"relative\",\n",
    "    max_error=0.05,\n",
    "    max_error_interp_mode=\"discrete\",\n",
    "    plot_obj=False, \n",
    "    fig=fig\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0a018943-adff-4249-a2b4-d6a7cb34e62f",
   "metadata": {},
   "outputs": [],
   "source": [
    "end_row = similarity.argmin() + 1\n",
    "start_row = end_row - 30\n",
    "fig = data.iloc[start_row:end_row].plot(plot_volume=False)\n",
    "price.iloc[start_row:end_row].vbt.plot_pattern(\n",
    "    pattern, \n",
    "    invert=True,\n",
    "    error_type=\"relative\",\n",
    "    max_error=0.05,\n",
    "    max_error_interp_mode=\"discrete\",\n",
    "    plot_obj=False, \n",
    "    fig=fig\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c98cfea9-5b10-4c9a-a0de-c526ba4cb7ab",
   "metadata": {},
   "outputs": [],
   "source": [
    "inv_similarity = price.vbt.rolling_pattern_similarity(\n",
    "    pattern, \n",
    "    window=30,\n",
    "    invert=True,\n",
    "    error_type=\"relative\",\n",
    "    max_error=0.05,\n",
    "    max_error_interp_mode=\"discrete\"\n",
    ")\n",
    "inv_similarity.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1c76c75f-1eb8-44dd-a633-ec4574c02ce7",
   "metadata": {},
   "outputs": [],
   "source": [
    "end_row = inv_similarity.argmax() + 1\n",
    "start_row = end_row - 30\n",
    "fig = data.iloc[start_row:end_row].plot(plot_volume=False)\n",
    "price.iloc[start_row:end_row].vbt.plot_pattern(\n",
    "    pattern, \n",
    "    invert=True,\n",
    "    error_type=\"relative\",\n",
    "    max_error=0.05,\n",
    "    max_error_interp_mode=\"discrete\",\n",
    "    plot_obj=False, \n",
    "    fig=fig\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b0f936be-2cb1-483a-8388-36bcd2292c95",
   "metadata": {},
   "source": [
    "#### Indicator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2c66d09c-3d29-4656-bb90-6d3e60010e85",
   "metadata": {},
   "outputs": [],
   "source": [
    "patsim = vbt.PATSIM.run(\n",
    "    price, \n",
    "    vbt.Default(pattern),\n",
    "    error_type=vbt.Default(\"relative\"),\n",
    "    max_error=vbt.Default(0.05),\n",
    "    max_error_interp_mode=vbt.Default(\"discrete\"),\n",
    "    window=[30, 45, 60, 75, 90]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "789f1c55-f448-4d74-9619-2e45c5d25ae7",
   "metadata": {},
   "outputs": [],
   "source": [
    "patsim.wrapper.columns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e4f9c2a7-f251-49ea-90e2-1b8d3be2fdc2",
   "metadata": {},
   "outputs": [],
   "source": [
    "patsim.plot(column=60).show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d2341e8a-539c-4426-ba18-abda070b0c0f",
   "metadata": {},
   "outputs": [],
   "source": [
    "patsim.overlay_with_heatmap(column=60).show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "18d865d5-3942-47fd-b01c-0837d2bad35e",
   "metadata": {},
   "outputs": [],
   "source": [
    "exits = patsim.similarity >= 0.8\n",
    "exits.sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "08cc861a-5d5a-4b43-80ce-00b18e7fd3e3",
   "metadata": {},
   "outputs": [],
   "source": [
    "patsim = vbt.PATSIM.run(\n",
    "    price, \n",
    "    vbt.Default(pattern),\n",
    "    error_type=vbt.Default(\"relative\"),\n",
    "    max_error=vbt.Default(0.05),\n",
    "    max_error_interp_mode=vbt.Default(\"discrete\"),\n",
    "    window=[30, 45, 60, 75, 90],\n",
    "    invert=[False, True],\n",
    "    min_similarity=[0.7, 0.8],\n",
    "    param_product=True\n",
    ")\n",
    "exits = ~patsim.similarity.isnull()\n",
    "exits.sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5911f6c0-29dc-466e-be6d-367e69d4c507",
   "metadata": {},
   "outputs": [],
   "source": [
    "groupby = [\n",
    "    name for name in patsim.wrapper.columns.names \n",
    "    if name != \"patsim_window\"\n",
    "]\n",
    "max_sim = patsim.similarity.groupby(groupby, axis=1).max()\n",
    "entries = ~max_sim.xs(True, level=\"patsim_invert\", axis=1).isnull()\n",
    "exits = ~max_sim.xs(False, level=\"patsim_invert\", axis=1).isnull()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d4155041-905e-42d1-87d4-bcc09e06e266",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = data.plot(ohlc_trace_kwargs=dict(opacity=0.5))\n",
    "entries[0.8].vbt.signals.plot_as_entries(price, fig=fig)\n",
    "exits[0.8].vbt.signals.plot_as_exits(price, fig=fig).show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f4cab670-88b0-4c00-9170-ca310b7624ab",
   "metadata": {},
   "source": [
    "### Search"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3c039275-8a26-435f-ac58-ba3f418931cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_range_records = vbt.nb.find_pattern_1d_nb(\n",
    "    price.values,\n",
    "    pattern,\n",
    "    window=30,\n",
    "    max_window=90,\n",
    "    error_type=vbt.enums.ErrorType.Relative,\n",
    "    max_error=np.array([0.05]),\n",
    "    max_error_interp_mode=vbt.enums.InterpMode.Discrete,\n",
    "    min_similarity=0.85\n",
    ")\n",
    "pattern_range_records"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9dbed8af-829e-4ee3-ab21-416ce30b5356",
   "metadata": {},
   "outputs": [],
   "source": [
    "start_row = pattern_range_records[1][\"start_idx\"]\n",
    "end_row = pattern_range_records[1][\"end_idx\"]\n",
    "fig = data.iloc[start_row:end_row + 30].plot(plot_volume=False)\n",
    "price.iloc[start_row:end_row].vbt.plot_pattern(\n",
    "    pattern, \n",
    "    error_type=\"relative\",\n",
    "    max_error=0.05,\n",
    "    max_error_interp_mode=\"discrete\",\n",
    "    plot_obj=False, \n",
    "    fig=fig\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d9b75568-2605-40cf-a303-203d0d4a99d0",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges = vbt.PatternRanges.from_pattern_search(\n",
    "    price,\n",
    "    pattern,\n",
    "    window=30,\n",
    "    max_window=120,\n",
    "    error_type=\"relative\",\n",
    "    max_error=0.05,\n",
    "    max_error_interp_mode=\"discrete\",\n",
    "    min_similarity=0.85\n",
    ")\n",
    "pattern_ranges"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4173fd82-22f4-4f7f-afac-64d17836a608",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges = price.vbt.find_pattern(\n",
    "    pattern,\n",
    "    window=30,\n",
    "    max_window=90,\n",
    "    error_type=\"relative\",\n",
    "    max_error=0.05,\n",
    "    max_error_interp_mode=\"discrete\",\n",
    "    min_similarity=0.85\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f58a06d1-9df6-4e26-9541-fa5c45e52368",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(pattern_ranges.records_readable)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d83797be-ea9a-4f66-b27b-13a70e121735",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges.wrapper.columns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b2d620cb-8deb-4fda-a62c-ccf8e0b126d1",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges.search_configs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "db1df1d9-69ae-4a84-8a45-57df9f16d9bb",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges.plot().show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1e006d13-e92d-4e72-999d-442ec8cd867a",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges.loc[\"2021-09-01\":\"2022-01-01\"].plot().show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "31895f9e-9dab-44b4-b810-02549c01a3b6",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges.stats()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "099ecd8c-d9dd-40fc-b766-53c619240991",
   "metadata": {},
   "source": [
    "#### Overlapping"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5b33eb7c-2e4c-4a66-8ebf-6ff6fe82639c",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges = price.vbt.find_pattern(\n",
    "    pattern,\n",
    "    window=30,\n",
    "    max_window=120,\n",
    "    error_type=\"relative\",\n",
    "    max_error=0.05,\n",
    "    max_error_interp_mode=\"discrete\",\n",
    "    min_similarity=0.85,\n",
    "    overlap_mode=\"allow\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0c924f37-e0c3-4588-8515-3684ef4eb46c",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges.count()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "37de96f6-27f2-4538-88a5-2758c5442ea4",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges.overlap_coverage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b9a5bc35-4f8d-4add-af11-c2ac583fe70a",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges.plot(plot_zones=False, plot_patterns=False).show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "532a3db0-a81e-46f5-945c-37a0774a17a7",
   "metadata": {},
   "source": [
    "#### Random selection"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8c163259-3d64-4d06-a824-834d21043434",
   "metadata": {},
   "outputs": [],
   "source": [
    "def run_prob_search(row_select_prob, window_select_prob):\n",
    "    return price.vbt.find_pattern(\n",
    "        pattern,\n",
    "        window=30,\n",
    "        max_window=120,\n",
    "        row_select_prob=row_select_prob,\n",
    "        window_select_prob=window_select_prob,\n",
    "        error_type=\"relative\",\n",
    "        max_error=0.05,\n",
    "        max_error_interp_mode=\"discrete\",\n",
    "        min_similarity=0.8,\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5f08fb98-3b7c-41b2-a8b9-ba9ba7f4d475",
   "metadata": {},
   "outputs": [],
   "source": [
    "%timeit run_prob_search(1.0, 1.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3cefffe3-5d70-4a3d-822a-d39ea0f3b30a",
   "metadata": {},
   "outputs": [],
   "source": [
    "%timeit run_prob_search(0.5, 0.25)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d3a04c29-284e-4840-a77d-f23638962cd9",
   "metadata": {},
   "outputs": [],
   "source": [
    "run_prob_search(1.0, 1.0).count()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d1ff96a9-7c06-4f27-9e88-90e8902aae8a",
   "metadata": {},
   "outputs": [],
   "source": [
    "pd.Series([\n",
    "    run_prob_search(0.5, 0.25).count() \n",
    "    for i in range(100)\n",
    "]).vbt.plot().show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "292d8003-d997-4826-b2cf-827786c66d55",
   "metadata": {},
   "source": [
    "#### Params"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9f47a2b9-3d72-4b4a-a544-17bb08600836",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges = price.vbt.find_pattern(\n",
    "    vbt.Param([\n",
    "        [1, 2, 1],\n",
    "        [2, 1, 2],\n",
    "        [1, 2, 3],\n",
    "        [3, 2, 1]\n",
    "    ]),\n",
    "    window=30,\n",
    "    max_window=120,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e2dffbc9-e64b-4629-83ce-af6bc96c701b",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges.count()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "294ee0c1-74f1-4d08-9627-9d7f78bb7c1d",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges = price.vbt.find_pattern(\n",
    "    vbt.Param([\n",
    "        [1, 2, 1],\n",
    "        [2, 1, 2],\n",
    "        [1, 2, 3],\n",
    "        [3, 2, 1]\n",
    "    ], keys=[\"v-top\", \"v-bottom\", \"rising\", \"falling\"]),\n",
    "    window=30,\n",
    "    max_window=120,\n",
    ")\n",
    "pattern_ranges.count()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "596fe13e-d557-4115-871f-393d993e1922",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges.plot(column=\"falling\").show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e484ac50-c92c-4287-bd7a-f7ecdd3ca523",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges = price.vbt.find_pattern(\n",
    "    vbt.Param([\n",
    "        [1, 2, 1],\n",
    "        [2, 1, 2],\n",
    "        [1, 2, 3],\n",
    "        [3, 2, 1]\n",
    "    ], keys=[\"v-top\", \"v-bottom\", \"rising\", \"falling\"]),\n",
    "    window=30,\n",
    "    max_window=120,\n",
    "    min_similarity=vbt.Param([0.8, 0.85])\n",
    ")\n",
    "pattern_ranges.count()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bcf16c45-3021-49d6-9033-82ddd96a0f30",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges.plot(column=(\"v-bottom\", 0.8)).show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7da6b0a3-899b-41a7-a514-68ccedea422f",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges = price.vbt.find_pattern(\n",
    "    vbt.Param([\n",
    "        [1, 2, 1],\n",
    "        [2, 1, 2],\n",
    "        [1, 2, 3],\n",
    "        [3, 2, 1]\n",
    "    ], keys=[\"v-top\", \"v-bottom\", \"rising\", \"falling\"], level=0),\n",
    "    window=vbt.Param([30, 30, 7, 7], level=0),\n",
    "    max_window=vbt.Param([120, 120, 30, 30], level=0),\n",
    "    min_similarity=vbt.Param([0.8, 0.85], level=1)\n",
    ")\n",
    "pattern_ranges.count()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c289b606-0c93-48d2-9eb4-4ee571bc4636",
   "metadata": {},
   "source": [
    "#### Configs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0c3bbcfc-6336-4241-a259-4cbf45a37d72",
   "metadata": {},
   "outputs": [],
   "source": [
    "mult_data = vbt.BinanceData.pull(\n",
    "    [\"BTCUSDT\", \"ETHUSDT\"], \n",
    "    start=\"2020-06-01 UTC\", \n",
    "    end=\"2022-06-01 UTC\"\n",
    ")\n",
    "mult_price = mult_data.hlc3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0c15e655-b3be-4223-992d-a4b27d82a5eb",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges = mult_price.vbt.find_pattern(\n",
    "    search_configs=[\n",
    "        vbt.PSC(pattern=[1, 2, 3, 2, 3, 2], window=30),\n",
    "        [\n",
    "            vbt.PSC(pattern=mult_price.iloc[-30:, 0]),\n",
    "            vbt.PSC(pattern=mult_price.iloc[-30:, 1]),\n",
    "        ]\n",
    "    ],\n",
    "    min_similarity=0.8\n",
    ")\n",
    "pattern_ranges.count()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3c19e67e-70ab-4a0e-ad63-46e24b9121ed",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges = mult_price.vbt.find_pattern(\n",
    "    search_configs=[\n",
    "        vbt.PSC(pattern=[1, 2, 3, 2, 3, 2], window=30, name=\"double_top\"),\n",
    "        [\n",
    "            vbt.PSC(pattern=mult_price.iloc[-30:, 0], name=\"last\"),\n",
    "            vbt.PSC(pattern=mult_price.iloc[-30:, 1], name=\"last\"),\n",
    "        ]\n",
    "    ],\n",
    "    min_similarity=0.8\n",
    ")\n",
    "pattern_ranges.count()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "97bdb94f-ea9b-4321-b858-3b49e29dd04b",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges = mult_price.vbt.find_pattern(\n",
    "    search_configs=[\n",
    "        vbt.PSC(pattern=[1, 2, 3, 2, 3, 2], window=30, name=\"double_top\"),\n",
    "        [\n",
    "            vbt.PSC(pattern=mult_price.iloc[-30:, 0], name=\"last\"),\n",
    "            vbt.PSC(pattern=mult_price.iloc[-30:, 1], name=\"last\"),\n",
    "        ]\n",
    "    ],\n",
    "    rescale_mode=vbt.Param([\"minmax\", \"rebase\"]),\n",
    "    min_similarity=0.8,\n",
    "    open=mult_data.open,\n",
    "    high=mult_data.high,\n",
    "    low=mult_data.low,\n",
    "    close=mult_data.close,\n",
    ")\n",
    "pattern_ranges.count()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c5f0ee35-b0be-48f8-9087-1b81cc3867ce",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges.plot(column=(\"rebase\", \"last\", \"ETHUSDT\")).show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c75c253d-e60f-4cd5-8cab-6a610f82bc9c",
   "metadata": {},
   "source": [
    "#### Mask"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3fbd7240-7dee-4ee4-b371-445abe564fd8",
   "metadata": {},
   "outputs": [],
   "source": [
    "mask = pattern_ranges.last_pd_mask\n",
    "mask.sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9451fb73-03e4-4287-acce-df905eec8fa4",
   "metadata": {},
   "source": [
    "#### Indicator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "add9ccd5-966a-4262-bb18-ace8abbf9cba",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges = price.vbt.find_pattern(\n",
    "    pattern,\n",
    "    window=30,\n",
    "    max_window=120,\n",
    "    row_select_prob=0.5,\n",
    "    window_select_prob=0.5,\n",
    "    overlap_mode=\"allow\",\n",
    "    seed=42\n",
    ")\n",
    "pr_mask = pattern_ranges.map_field(\n",
    "    \"similarity\", \n",
    "    idx_arr=pattern_ranges.last_idx.values\n",
    ").to_pd()\n",
    "pr_mask[~pr_mask.isnull()]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "86147e26-3814-4f0c-915f-cff77c5d4c28",
   "metadata": {},
   "outputs": [],
   "source": [
    "patsim = vbt.PATSIM.run(\n",
    "    price,\n",
    "    vbt.Default(pattern),\n",
    "    window=vbt.Default(30),\n",
    "    max_window=vbt.Default(120),\n",
    "    row_select_prob=vbt.Default(0.5),\n",
    "    window_select_prob=vbt.Default(0.5),\n",
    "    min_similarity=vbt.Default(0.85),\n",
    "    seed=42\n",
    ")\n",
    "ind_mask = patsim.similarity\n",
    "ind_mask[~ind_mask.isnull()]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f89ddd9d-d8a4-4bd8-800e-3dd2e962c229",
   "metadata": {},
   "source": [
    "### Combination"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "27387a58-44cc-4885-abfc-bb93e40931e0",
   "metadata": {},
   "outputs": [],
   "source": [
    "price_highs = vbt.PATSIM.run(\n",
    "    data.high, \n",
    "    pattern=np.array([1, 3, 2, 4]), \n",
    "    window=40,\n",
    "    max_window=50\n",
    ")\n",
    "macd = data.run(\"talib_macd\").macd\n",
    "macd_lows = vbt.PATSIM.run(\n",
    "    macd, \n",
    "    pattern=np.array([4, 2, 3, 1]), \n",
    "    window=40,\n",
    "    max_window=50\n",
    ")\n",
    "\n",
    "fig = vbt.make_subplots(\n",
    "    rows=3, cols=1, shared_xaxes=True, vertical_spacing=0.02\n",
    ")\n",
    "fig.update_layout(height=500)\n",
    "data.high.rename(\"Price\").vbt.plot(\n",
    "    add_trace_kwargs=dict(row=1, col=1), fig=fig\n",
    ")\n",
    "macd.rename(\"MACD\").vbt.plot(\n",
    "    add_trace_kwargs=dict(row=2, col=1), fig=fig\n",
    ")\n",
    "price_highs.similarity.rename(\"Price Sim\").vbt.plot(\n",
    "    add_trace_kwargs=dict(row=3, col=1), fig=fig\n",
    ")\n",
    "macd_lows.similarity.rename(\"MACD Sim\").vbt.plot(\n",
    "    add_trace_kwargs=dict(row=3, col=1), fig=fig\n",
    ")\n",
    "fig.show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4aa7cb3d-4000-443c-830c-2f5034a46c2d",
   "metadata": {},
   "outputs": [],
   "source": [
    "cond1 = (price_highs.similarity >= 0.8).vbt.rolling_any(10)\n",
    "cond2 = (macd_lows.similarity >= 0.8).vbt.rolling_any(10)\n",
    "exits = cond1 & cond2\n",
    "fig = data.plot(ohlc_trace_kwargs=dict(opacity=0.5))\n",
    "exits.vbt.signals.plot_as_exits(data.close, fig=fig).show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ea6d38dd-f8a7-4cfd-a0cd-0372ba13781f",
   "metadata": {},
   "source": [
    "## Projections"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2454a1d5-d966-4511-a0d6-942eb479414b",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges = price.vbt.find_pattern(\n",
    "    [1, 1.2], \n",
    "    window=7, \n",
    "    rescale_mode=\"rebase\", \n",
    "    max_error=0.01,\n",
    "    max_error_interp_mode=\"discrete\",\n",
    "    max_error_strict=True\n",
    ")\n",
    "pattern_ranges.count()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a5e28f0-13c5-429e-a2c8-a6d249b5fbf5",
   "metadata": {},
   "source": [
    "### Pattern projections"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "db8fb47e-92a1-4476-becb-6677d6bac612",
   "metadata": {},
   "outputs": [],
   "source": [
    "range_idxs, raw_projections = vbt.nb.map_ranges_to_projections_nb(\n",
    "    vbt.to_2d_array(price),\n",
    "    pattern_ranges.get_field_arr(\"col\"),\n",
    "    pattern_ranges.get_field_arr(\"start_idx\"),\n",
    "    pattern_ranges.get_field_arr(\"end_idx\"),\n",
    "    pattern_ranges.get_field_arr(\"status\")\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "42bc6ef9-55b8-4331-9b4e-acd42d6fa28d",
   "metadata": {},
   "outputs": [],
   "source": [
    "range_idxs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3ef238f3-59b3-44c9-9164-8770077516ff",
   "metadata": {},
   "outputs": [],
   "source": [
    "raw_projections"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cf6ec440-517b-4ec3-b5f2-88637429f270",
   "metadata": {},
   "outputs": [],
   "source": [
    "projections = pattern_ranges.get_projections()\n",
    "print(projections)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e2ecac89-f4b1-4d11-af3e-cceebf01770c",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges.duration.values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "350fc784-81ac-4d40-9a8e-81eb4d7e3f4d",
   "metadata": {},
   "outputs": [],
   "source": [
    "projections = pattern_ranges.get_projections(incl_end_idx=False)\n",
    "print(projections)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3d68f485-f5db-4af2-be32-b547446aaade",
   "metadata": {},
   "outputs": [],
   "source": [
    "projections.iloc[-1] / projections.iloc[0] - 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "37ff3101-9abb-44e9-81f8-7bba26fc7890",
   "metadata": {},
   "outputs": [],
   "source": [
    "projections.vbt.plot().show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8107b799-c0cc-403f-9036-3fb69ce9d107",
   "metadata": {},
   "source": [
    "### Delta projections"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5049cc27-b914-4a1d-b302-0bb1fd69ed21",
   "metadata": {},
   "outputs": [],
   "source": [
    "delta_ranges = pattern_ranges.with_delta(4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "be87a7da-4d2d-4522-bb00-68c9a5bd2d8b",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = pattern_ranges.loc[\"2021-01\":\"2021-03\"].plot()\n",
    "delta_ranges.loc[\"2021-01\":\"2021-03\"].plot(\n",
    "    plot_ohlc=False,\n",
    "    plot_close=False,\n",
    "    plot_markers=False,\n",
    "    closed_shape_kwargs=dict(fillcolor=\"DeepSkyBlue\"),\n",
    "    fig=fig\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eafc7432-212f-4029-9863-ce77680876a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "projections = delta_ranges.get_projections()\n",
    "print(projections)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "71564e43-47b6-41fa-a00b-d5dfbbc597c9",
   "metadata": {},
   "outputs": [],
   "source": [
    "np.mean(projections.iloc[-1] / projections.iloc[0] - 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "458e3eb1-d963-4b63-b143-8e83a311b7e8",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges = mult_price.vbt.find_pattern(\n",
    "    [1, 1.2], \n",
    "    window=7, \n",
    "    max_window=30,\n",
    "    rescale_mode=\"rebase\",\n",
    "    max_error=0.01,\n",
    "    max_error_interp_mode=\"discrete\",\n",
    "    max_error_strict=True,\n",
    "    overlap_mode=\"allow\"\n",
    ")\n",
    "pattern_ranges.count()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "962f00c1-d8d2-4f36-b9d0-b3f22d0e9b85",
   "metadata": {},
   "outputs": [],
   "source": [
    "delta_ranges = pattern_ranges.with_delta(4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6342f033-5867-4c10-aa52-572cc6fa4b1c",
   "metadata": {},
   "outputs": [],
   "source": [
    "projections = delta_ranges.get_projections()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5d852b78-9631-471a-936b-e4ecde58306d",
   "metadata": {},
   "outputs": [],
   "source": [
    "(projections.iloc[-1] / projections.iloc[0] - 1).describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "83317097-d330-42bc-9914-e1771223d87d",
   "metadata": {},
   "outputs": [],
   "source": [
    "projections = delta_ranges.get_projections(id_level=\"end_idx\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b2826f67-9bca-4fb0-869e-a82cdfd2241d",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(projections.columns)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "81af5933-1c93-4d78-9fc1-caf11fbcebfa",
   "metadata": {},
   "outputs": [],
   "source": [
    "btc_projections = projections.xs(\"BTCUSDT\", level=\"symbol\", axis=1)\n",
    "total_proj_return = btc_projections.iloc[-1] / btc_projections.iloc[0] - 1\n",
    "total_proj_return.vbt.scatterplot(\n",
    "    trace_kwargs=dict(\n",
    "        marker=dict(\n",
    "            color=total_proj_return.values,\n",
    "            colorscale=\"Temps_r\",\n",
    "            cmid=0\n",
    "        )\n",
    "    )\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3052612d-739e-4850-98c0-c95339abab89",
   "metadata": {},
   "source": [
    "### Plotting"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "80393e11-1f0b-4677-8449-704c608fc663",
   "metadata": {},
   "outputs": [],
   "source": [
    "btc_projections.vbt.plot_projections(plot_bands=False).show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "36245487-378f-485c-a8b5-943882c67d4a",
   "metadata": {},
   "source": [
    "#### Colorization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7899b684-bb9f-466b-ab32-c8a458dcaaf3",
   "metadata": {},
   "outputs": [],
   "source": [
    "btc_projections[\"2020-08-03\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bbae99b6-bd79-4761-a841-2c4332b40e89",
   "metadata": {},
   "outputs": [],
   "source": [
    "btc_projections[\"2020-08-03\"].median()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3dc3ff43-6652-43e6-8846-4395f4961778",
   "metadata": {},
   "outputs": [],
   "source": [
    "btc_projections.vbt.plot_projections(\n",
    "    plot_bands=False, colorize=np.std\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cd341c89-03e5-49c0-bf5f-54e400e1006e",
   "metadata": {},
   "source": [
    "#### Bands"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8289d408-7647-42e3-b031-4fca40126501",
   "metadata": {},
   "outputs": [],
   "source": [
    "projections.xs(\"ETHUSDT\", level=\"symbol\", axis=1).median(axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "43533726-0d4a-4ff1-8b6d-dcfd1cc47e6b",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(projections.groupby(\"symbol\", axis=1).median())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f4059411-7aec-4ca6-ba4e-16fec33303f3",
   "metadata": {},
   "outputs": [],
   "source": [
    "projections.median(axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "57d904bb-d80a-48b9-a518-c1302b16ea51",
   "metadata": {},
   "outputs": [],
   "source": [
    "btc_projections.vbt.plot_projections().show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3ac38bd4-62a9-4f47-ab1b-9387b5aef98d",
   "metadata": {},
   "outputs": [],
   "source": [
    "btc_projections.iloc[-1].quantile(0.8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e66e93d8-8ff7-4f34-ae0d-ccadd66cebcc",
   "metadata": {},
   "outputs": [],
   "source": [
    "btc_projections.vbt.plot_projections(\n",
    "    plot_lower=False,\n",
    "    plot_middle=\"30%\", \n",
    "    plot_upper=False, \n",
    "    plot_aux_middle=False, \n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f949a129-4ec8-4ea8-923f-34ab2c3a1927",
   "metadata": {},
   "outputs": [],
   "source": [
    "btc_projections.iloc[-1].vbt.qqplot().show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4d0e1932-7d85-4b5f-8b07-a720b50033cb",
   "metadata": {},
   "outputs": [],
   "source": [
    "btc_projections.vbt.plot_projections(\n",
    "    plot_lower=\"P=20%\",\n",
    "    plot_middle=\"mean\", \n",
    "    plot_upper=\"P=80%\", \n",
    "    plot_aux_middle=False, \n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c6759119-3477-4a13-9127-3fca78fbf827",
   "metadata": {},
   "outputs": [],
   "source": [
    "def finishes_at_quantile(df, q):\n",
    "    nth_element = int(np.ceil(q * (df.shape[1] - 1)))\n",
    "    nth_index = np.argsort(df.iloc[-1])[nth_element]\n",
    "    return df.iloc[:, nth_index]\n",
    "\n",
    "btc_projections.vbt.plot_projections(\n",
    "    plot_lower=partial(finishes_at_quantile, q=0.2),\n",
    "    plot_middle=False, \n",
    "    plot_upper=partial(finishes_at_quantile, q=0.8), \n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "94e7b8cb-9143-4fce-bd98-5a7f4cf45a88",
   "metadata": {},
   "source": [
    "### Filtering"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "de11af10-ca2e-43e9-a4ac-5264b7ef0bb0",
   "metadata": {},
   "outputs": [],
   "source": [
    "crossed_mask = projections.expanding().max().iloc[1] >= 1.05\n",
    "filt_projections = projections.loc[:, crossed_mask]\n",
    "filt_projections.iloc[-1].describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "09a8a128-dbbc-441a-b0b9-4c38728e4b66",
   "metadata": {},
   "outputs": [],
   "source": [
    "filt_projections.vbt.plot_projections().show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2baaec17-f214-45e1-9056-24efc36e8eb2",
   "metadata": {},
   "source": [
    "### Latest projections"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "30883240-2b3f-40bb-bfd0-3ec6a76cf638",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges = price.vbt.find_pattern(\n",
    "    pattern=data.close.iloc[-7:],\n",
    "    rescale_mode=\"rebase\",\n",
    "    overlap_mode=\"allow\"\n",
    ")\n",
    "pattern_ranges.count()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a82ef541-7b12-4f5b-af56-39ca78ea6c69",
   "metadata": {},
   "outputs": [],
   "source": [
    "pattern_ranges = pattern_ranges.status_closed\n",
    "pattern_ranges.count()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "284df49d-5235-4450-af49-f31475eedab2",
   "metadata": {},
   "outputs": [],
   "source": [
    "projections = pattern_ranges.get_projections()\n",
    "projections.vbt.plot_projections(plot_bands=False).show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "463036d2-3b03-4aaf-ba51-17bbe30902db",
   "metadata": {},
   "outputs": [],
   "source": [
    "delta_ranges = pattern_ranges.with_delta(7)\n",
    "projections = delta_ranges.get_projections(start_value=-1)\n",
    "fig = data.iloc[-7:].plot(plot_volume=False)\n",
    "projections.vbt.plot_projections(fig=fig).show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "40cd39a7-eee3-468f-953e-2e3e248a0a57",
   "metadata": {},
   "outputs": [],
   "source": [
    "projections.mean(axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ea7b7996-6040-4e22-a8a7-1b3158f3d3ae",
   "metadata": {},
   "outputs": [],
   "source": [
    "next_data = vbt.BinanceData.pull(\n",
    "    \"BTCUSDT\", \n",
    "    start=\"2022-05-31\", \n",
    "    end=\"2022-06-08\"\n",
    ")\n",
    "next_data.close"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "17e50e87-4c45-4226-9c6e-d6f8c4fcc1ad",
   "metadata": {},
   "source": [
    "#### Quick plotting"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ab44b469-25f6-4521-8597-508b0e90dcd0",
   "metadata": {},
   "outputs": [],
   "source": [
    "delta_ranges.plot_projections().show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0998e94d-1235-492f-8a43-7d5447c62ad0",
   "metadata": {},
   "source": [
    "### Non-uniform projections"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d89bff85-7fb4-4199-acff-d3933e7a5bc1",
   "metadata": {},
   "outputs": [],
   "source": [
    "windows = np.arange(10, 31)\n",
    "window_tuples = combinations(windows, 2)\n",
    "window_tuples = filter(lambda x: abs(x[0] - x[1]) >= 5, window_tuples)\n",
    "fast_windows, slow_windows = zip(*window_tuples)\n",
    "fast_sma = data.run(\"sma\", fast_windows, short_name=\"fast_sma\")\n",
    "slow_sma = data.run(\"sma\", slow_windows, short_name=\"slow_sma\")\n",
    "entries = fast_sma.real_crossed_above(slow_sma.real)\n",
    "exits = fast_sma.real_crossed_below(slow_sma.real)\n",
    "\n",
    "entries.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5b467365-1c39-4df8-82f9-e187695d66e8",
   "metadata": {},
   "outputs": [],
   "source": [
    "entry_ranges = entries.vbt.signals.delta_ranges(30, close=data.close)\n",
    "entry_ranges = entry_ranges.status_closed\n",
    "entry_ranges.count().sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9dbd119c-1ca9-4baf-9464-247c375da1bd",
   "metadata": {},
   "outputs": [],
   "source": [
    "exit_ranges = exits.vbt.signals.delta_ranges(30, close=data.close)\n",
    "exit_ranges = exit_ranges.status_closed\n",
    "exit_ranges.count().sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "20a19b6e-3c65-4fba-8cbb-58fd37422420",
   "metadata": {},
   "outputs": [],
   "source": [
    "entry_projections = entry_ranges.get_projections()\n",
    "entry_projections.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d0ed13b1-f9b0-4b8d-a1a1-1f45e9384387",
   "metadata": {},
   "outputs": [],
   "source": [
    "exit_projections = exit_ranges.get_projections()\n",
    "exit_projections.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d390a0d6-8371-4b45-a859-7c2d75cc3e1f",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig = entry_projections.vbt.plot_projections(\n",
    "    plot_projections=False,\n",
    "    lower_trace_kwargs=dict(name=\"Lower (entry)\", line_color=\"green\"),\n",
    "    middle_trace_kwargs=dict(name=\"Middle (entry)\", line_color=\"green\"),\n",
    "    upper_trace_kwargs=dict(name=\"Upper (entry)\", line_color=\"green\"),\n",
    "    plot_aux_middle=False,\n",
    "    plot_fill=False\n",
    ")\n",
    "fig = exit_projections.vbt.plot_projections(\n",
    "    plot_projections=False,\n",
    "    lower_trace_kwargs=dict(name=\"Lower (exit)\", line_color=\"orangered\"),\n",
    "    middle_trace_kwargs=dict(name=\"Middle (exit)\", line_color=\"orangered\"),\n",
    "    upper_trace_kwargs=dict(name=\"Upper (exit)\", line_color=\"orangered\"),\n",
    "    plot_aux_middle=False,\n",
    "    plot_fill=False,\n",
    "    fig=fig\n",
    ")\n",
    "fig.show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b9e3ff1d-8278-4715-9daf-c1bd779796fe",
   "metadata": {},
   "outputs": [],
   "source": [
    "entry_ranges = entries.vbt.signals.between_ranges(exits, close=data.close)\n",
    "entry_ranges = entry_ranges.status_closed\n",
    "entry_ranges.count().sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cd4ff156-429b-4815-a15d-2582ea0ce8c3",
   "metadata": {},
   "outputs": [],
   "source": [
    "exit_ranges = exits.vbt.signals.between_ranges(entries, close=data.close)\n",
    "exit_ranges = exit_ranges.status_closed\n",
    "exit_ranges.count().sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "19678630-7b6c-41df-8ff5-10987936cdbe",
   "metadata": {},
   "outputs": [],
   "source": [
    "entry_projections = entry_ranges.get_projections()\n",
    "entry_projections.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f1edfedd-8899-482d-8eae-fd452ea039b3",
   "metadata": {},
   "outputs": [],
   "source": [
    "exit_projections = exit_ranges.get_projections()\n",
    "exit_projections.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "efe053ae-3fc2-4011-b6dd-073f1898b261",
   "metadata": {},
   "outputs": [],
   "source": [
    "rand_cols = np.random.choice(entry_projections.shape[1], 100)\n",
    "entry_projections.iloc[:, rand_cols].vbt.plot_projections(plot_bands=False).show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0307a36b-6cea-41b5-97fc-9d580c6e16fc",
   "metadata": {},
   "outputs": [],
   "source": [
    "rand_cols = np.random.choice(exit_projections.shape[1], 100)\n",
    "exit_projections.iloc[:, rand_cols].vbt.plot_projections(plot_bands=False).show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "efb5dbd7-92dc-4b11-9e17-53149dc69094",
   "metadata": {},
   "source": [
    "#### Shrinking"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4e8bc5c4-6468-4d22-83ad-5eba09672b54",
   "metadata": {},
   "outputs": [],
   "source": [
    "entry_projections = entry_ranges.get_projections(proj_period=\"30d\")\n",
    "entry_projections.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "255f0a7f-b55c-4c66-bf7c-45cc0285fe84",
   "metadata": {},
   "outputs": [],
   "source": [
    "exit_projections = exit_ranges.get_projections(proj_period=\"30d\")\n",
    "exit_projections.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "31b7b35d-a419-4077-99a7-7138b0fdbfe2",
   "metadata": {},
   "outputs": [],
   "source": [
    "rand_cols = np.random.choice(entry_projections.shape[1], 100)\n",
    "entry_projections.iloc[:, rand_cols].vbt.plot_projections().show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b6de42c1-2359-44d9-b7b4-f301dcb82877",
   "metadata": {},
   "outputs": [],
   "source": [
    "rand_cols = np.random.choice(exit_projections.shape[1], 100)\n",
    "exit_projections.iloc[:, rand_cols].vbt.plot_projections().show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bc947af3-c7fe-4c91-925b-2cb5c8062217",
   "metadata": {},
   "source": [
    "#### Stretching"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9cd9fc97-d3be-44b8-a907-99b9db01faa4",
   "metadata": {},
   "outputs": [],
   "source": [
    "entry_projections = entry_ranges.get_projections(\n",
    "    proj_period=\"30d\", extend=True\n",
    ")\n",
    "entry_projections.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0584041b-86cc-4ce5-a127-e0cfd80e9c4a",
   "metadata": {},
   "outputs": [],
   "source": [
    "exit_projections = exit_ranges.get_projections(\n",
    "    proj_period=\"30d\", extend=True\n",
    ")\n",
    "exit_projections.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "307b1297-555e-4db5-a739-ca5ddf4a7157",
   "metadata": {},
   "outputs": [],
   "source": [
    "rand_cols = np.random.choice(entry_projections.shape[1], 100)\n",
    "entry_projections.iloc[:, rand_cols].vbt.plot_projections().show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "14a8234f-11e1-4841-b55e-a63483a3fce3",
   "metadata": {},
   "outputs": [],
   "source": [
    "rand_cols = np.random.choice(exit_projections.shape[1], 100)\n",
    "exit_projections.iloc[:, rand_cols].vbt.plot_projections().show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ceac936f-10c8-41c3-8b42-fcac372e8b0b",
   "metadata": {},
   "source": [
    "#### Quick plotting"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f53ea678-3707-41af-807d-4690abde298e",
   "metadata": {},
   "outputs": [],
   "source": [
    "entry_ranges.wrapper.columns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8c128064-5e25-4949-9ab6-d01867d7523d",
   "metadata": {},
   "outputs": [],
   "source": [
    "entry_ranges.plot_projections(\n",
    "    column=(25, 30),\n",
    "    last_n=10,\n",
    "    proj_period=\"30d\", \n",
    "    extend=True,\n",
    "    plot_lower=False,\n",
    "    plot_upper=False,\n",
    "    plot_aux_middle=False,\n",
    "    projection_trace_kwargs=dict(opacity=0.3)\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "86fa4fc5-010e-4102-979a-f5a0f39af5c7",
   "metadata": {},
   "source": [
    "### Open projections"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "55fd0811-5970-4fe4-88d4-852cb352430e",
   "metadata": {},
   "outputs": [],
   "source": [
    "exit_ranges = exits.vbt.signals.between_ranges(\n",
    "    entries, \n",
    "    incl_open=True, \n",
    "    close=data.close\n",
    ")\n",
    "exit_ranges.count().sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a6ee4056-46c3-48c3-a0c8-dd6c7fd96331",
   "metadata": {},
   "outputs": [],
   "source": [
    "exit_ranges.wrapper.columns[exit_ranges.status_open.col_arr]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6012e861-9761-4244-a94c-1c19726cad31",
   "metadata": {},
   "outputs": [],
   "source": [
    "exit_ranges.status_closed.plot_projections(\n",
    "    column=(20, 30), plot_bands=False\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d98c6dfb-80d6-4bab-89e6-9526397b9a39",
   "metadata": {},
   "outputs": [],
   "source": [
    "exit_ranges.plot_projections(\n",
    "    column=(20, 30), plot_bands=False\n",
    ").show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "93a55365-7167-408e-b5eb-b3260ce186e4",
   "metadata": {},
   "outputs": [],
   "source": [
    "column = (20, 30)\n",
    "signal_index = data.wrapper.index[np.flatnonzero(exits[column])[-1]]\n",
    "plot_start_index = signal_index - pd.Timedelta(days=10)\n",
    "sub_close = data.close[plot_start_index:]\n",
    "sub_exits = exits.loc[plot_start_index:, column]\n",
    "\n",
    "fig = sub_close.vbt.plot()\n",
    "sub_exits.vbt.signals.plot_as_exits(sub_close, fig=fig)\n",
    "projections = exit_ranges[column].status_closed.get_projections(\n",
    "    start_value=sub_close.loc[signal_index],\n",
    "    start_index=signal_index\n",
    ")\n",
    "projections.vbt.plot_projections(plot_bands=False, fig=fig).show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "06010e28-2a21-46df-a921-0b0533137762",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.9.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
