{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "9d9b5c91-f3a3-4709-a36f-40ecc86595d6",
   "metadata": {},
   "source": [
    "# Forecasting future price trends by projecting historical price patterns"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2cffb873-e431-44f3-b243-e35969bbd2c1",
   "metadata": {},
   "source": [
    "In our previous newsletter focusing on VectorBT PRO (VBT), we dived into the pattern detection capabilities of this powerful library. An additional key functionality is VBT's capacity to extrapolate identified price segments into the future and aggregate them for statistical analysis. This feature can be an invaluable tool for real-time decision-making in market analysis."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c472968b-1863-4d79-a299-ec67c1757455",
   "metadata": {},
   "source": [
    "## Imports and set up"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ddf68612-622b-4803-87fc-a1ad80341536",
   "metadata": {},
   "source": [
    "Given the self-contained design of VBT, a single import suffices."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a42ccb91-bc73-4ad5-9327-18c7c22af598",
   "metadata": {},
   "outputs": [],
   "source": [
    "from vectorbtpro import *\n",
    "# whats_imported()\n",
    "\n",
    "vbt.settings.set_theme(\"dark\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15412fda-c27f-4820-9273-17366164b2b3",
   "metadata": {},
   "source": [
    "Let's define a set of variables for our analysis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fc016fe0-5ae6-416f-bb4d-84a33a91fce8",
   "metadata": {},
   "outputs": [],
   "source": [
    "SYMBOL = \"BTCUSDT\"\n",
    "TIMEFRAME = \"1 hour\"\n",
    "START = \"one year ago\"\n",
    "\n",
    "LAST_N_BARS = 24\n",
    "PRED_N_BARS = 12\n",
    "\n",
    "GIF_FNAME = \"projections.gif\"\n",
    "GIF_N_BARS = 72\n",
    "GIF_FPS = 4\n",
    "GIF_PAD = 0.01"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e4667d70-f1d9-4f34-81ff-fdf8320477ae",
   "metadata": {},
   "source": [
    "We will execute the analysis using price data retrieved from BinanceData, based on the parameters we previously defined."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b797e0ff-320d-456b-91df-1e0e369d83a9",
   "metadata": {},
   "outputs": [],
   "source": [
    "data = vbt.BinanceData.pull(SYMBOL, timeframe=TIMEFRAME, start=START)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "43fade8d-2d1f-492b-88bb-95facd21ceda",
   "metadata": {},
   "source": [
    "## Find and plot projections"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0013fab2-d1fa-4777-99e9-2081a90444e3",
   "metadata": {},
   "source": [
    "Let's write a function that analyzes the most recent price trend and employs it as a pattern to identify similar price movements in historical data. This pattern recognition function will focus exclusively on segments of price history having a comparable percentage change from their respective starting points."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f7f4ead3-c4db-47d5-8a30-3f7dbe4347dc",
   "metadata": {},
   "outputs": [],
   "source": [
    "def find_patterns(data):\n",
    "    price = data.hlc3\n",
    "    pattern = price.values[-LAST_N_BARS:]\n",
    "    pattern_ranges = price.vbt.find_pattern(\n",
    "        pattern=pattern,\n",
    "        rescale_mode=\"rebase\",\n",
    "        overlap_mode=\"allow\",\n",
    "        wrapper_kwargs=dict(freq=TIMEFRAME)\n",
    "    )\n",
    "    pattern_ranges = pattern_ranges.status_closed\n",
    "    return pattern_ranges\n",
    "\n",
    "pattern_ranges = find_patterns(data)\n",
    "print(pattern_ranges.count())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6dc1f00c-f0a2-4b74-831f-3043c14f1195",
   "metadata": {},
   "source": [
    "We have identified a number of price segments that closely resemble the latest price trend. Now, we'll write a function that extracts the price data immediately succeeding each identified segment and plots these as extensions of the price trend. These subsequent segments are known as \"projections.\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9fb7b02c-190a-488e-bfa6-843db23c324e",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_projections(data, pattern_ranges, **kwargs):\n",
    "    projection_ranges = pattern_ranges.with_delta(\n",
    "        PRED_N_BARS,\n",
    "        open=data.open,\n",
    "        high=data.high,\n",
    "        low=data.low,\n",
    "        close=data.close,\n",
    "    )\n",
    "    projection_ranges = projection_ranges.status_closed\n",
    "    return projection_ranges.plot_projections(\n",
    "        plot_past_period=LAST_N_BARS, \n",
    "        **kwargs,\n",
    "    )\n",
    "\n",
    "plot_projections(data, pattern_ranges, plot_bands=False).show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8df73436-c6ae-411b-8c44-e5764f9c1812",
   "metadata": {},
   "source": [
    "As we can see, similar price movements have historically branched into a diverse set of trajectories. For a visually compelling and statistically robust forecast, we will display the confidence bands encompassing all the projections, with 60% of these projections falling between the upper and lower bands."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b97458a5-7428-4877-80c6-a522aef4b5ce",
   "metadata": {},
   "outputs": [],
   "source": [
    "plot_projections(data, pattern_ranges, plot_bands=True).show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9011e2c5-1745-480c-b9da-c031f6ba9ae2",
   "metadata": {},
   "source": [
    "## Generate animation"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ac05a0ea-6883-4736-a815-619f76607966",
   "metadata": {},
   "source": [
    "Lastly, we will compile a GIF animation that iterates through a specified range of bars, applying the aforementioned procedure to each bar within that range."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6238530e-9d06-4da4-a71d-3ae7489c2c9a",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_frame(frame_index, **kwargs):\n",
    "    sub_data = data.loc[:frame_index[-1]]\n",
    "    pattern_ranges = find_patterns(sub_data)\n",
    "    if pattern_ranges.count() < 3:\n",
    "        return None\n",
    "    return plot_projections(sub_data, pattern_ranges, **kwargs)\n",
    "\n",
    "vbt.save_animation(\n",
    "    GIF_FNAME,\n",
    "    data.index[-GIF_N_BARS:],\n",
    "    plot_frame,\n",
    "    plot_projections=False,\n",
    "    delta=1,\n",
    "    fps=GIF_FPS,\n",
    "    writer_kwargs=dict(loop=0),\n",
    "    yaxis_range=[\n",
    "        data.low.iloc[-GIF_N_BARS:].min() * (1 - GIF_PAD), \n",
    "        data.high.iloc[-GIF_N_BARS:].max() * (1 + GIF_PAD)\n",
    "    ],\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "91b825fb-7e4c-4d48-ae73-bffe633a6f52",
   "metadata": {},
   "source": [
    "Bear in mind that while the confidence bands describe past performance, they should not be used as guarantees of future results."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "319a24bb-e210-4d02-ab2c-0ce58b3dc82c",
   "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
}
