{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "3d7e090f",
   "metadata": {},
   "source": [
    "<div style=\"background-color:#000;\"><img src=\"pqn.png\"></img></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "71212d49",
   "metadata": {},
   "source": [
    "This code analyzes the SPY ticker data from Yahoo Finance to identify and study 3-day losing streaks. It calculates daily returns, identifies losing streaks, and tracks the days since the last streak. The code further computes future returns following these streaks to evaluate market behavior. This is useful for understanding market patterns and predicting future performance based on historical data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3e33fd4d",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import yfinance as yf"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "207fb52c",
   "metadata": {},
   "source": [
    "Define the ticker symbol and download historical data from Yahoo Finance"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f6c02468",
   "metadata": {},
   "outputs": [],
   "source": [
    "ticker = \"SPY\"\n",
    "data = yf.download(ticker)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2564ee80",
   "metadata": {},
   "source": [
    "Calculate daily returns by finding the difference between consecutive closing prices"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bab6fda1",
   "metadata": {},
   "outputs": [],
   "source": [
    "data[\"return\"] = data[\"Close\"].diff()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b9b2fb9f",
   "metadata": {},
   "source": [
    "Identify days with negative returns to find losing days in the dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fe5059b6",
   "metadata": {},
   "outputs": [],
   "source": [
    "data[\"down\"] = data[\"return\"] < 0"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0dcd7b43",
   "metadata": {},
   "source": [
    "Identify 3-day losing streaks by checking for three consecutive losing days"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e0dc811b",
   "metadata": {},
   "outputs": [],
   "source": [
    "data[\"3_day_losing_streak\"] = (\n",
    "    data[\"down\"] & data[\"down\"].shift(1) & data[\"down\"].shift(2)\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f20e4853",
   "metadata": {},
   "source": [
    "Initialize a column to track the number of days since the last 3-day losing streak"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "766171ef",
   "metadata": {},
   "outputs": [],
   "source": [
    "data[\"days_since_last_streak\"] = np.nan"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3c417464",
   "metadata": {},
   "source": [
    "Iterate over the data to calculate the days since the last 3-day losing streak"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "49416f01",
   "metadata": {},
   "outputs": [],
   "source": [
    "last_streak_day = -np.inf  # Initialize with a very large negative value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2f6d58c2",
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in range(len(data)):\n",
    "    if data[\"3_day_losing_streak\"].iloc[i]:\n",
    "        if i - last_streak_day >= 42:  # Check if it's been at least 42 trading days\n",
    "            data.loc[data.index[i], \"days_since_last_streak\"] = i - last_streak_day\n",
    "        last_streak_day = i"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b11167c0",
   "metadata": {},
   "source": [
    "Filter the data to show only the occurrences that meet the criteria"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8910af75",
   "metadata": {},
   "outputs": [],
   "source": [
    "result = data.dropna(subset=[\"days_since_last_streak\"]).copy()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "870198e1",
   "metadata": {},
   "source": [
    "Calculate future returns following the identified streaks"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0fcde2dc",
   "metadata": {},
   "outputs": [],
   "source": [
    "result[\"next_1_day_return\"] = data[\"Close\"].shift(-1) / data[\"Close\"] - 1\n",
    "result[\"next_5_day_return\"] = data[\"Close\"].shift(-5) / data[\"Close\"] - 1\n",
    "result[\"next_10_day_return\"] = data[\"Close\"].shift(-10) / data[\"Close\"] - 1\n",
    "result[\"next_21_day_return\"] = data[\"Close\"].shift(-21) / data[\"Close\"] - 1"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "10250edf",
   "metadata": {},
   "source": [
    "Print the mean future returns for different time horizons"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "62d635bc",
   "metadata": {},
   "outputs": [],
   "source": [
    "cols = [\n",
    "    \"next_1_day_return\",\n",
    "    \"next_5_day_return\",\n",
    "    \"next_10_day_return\",\n",
    "    \"next_21_day_return\"\n",
    "]\n",
    "print(result[cols].mean())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "374238ed",
   "metadata": {},
   "source": [
    "Plot the proportion of positive returns for the different time horizons"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9cc1f42b",
   "metadata": {},
   "outputs": [],
   "source": [
    "result[cols].gt(0).mean().plot.bar()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7b4b3cbe",
   "metadata": {},
   "source": [
    "Display the proportion of positive returns for the different time horizons"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5538d15f",
   "metadata": {},
   "outputs": [],
   "source": [
    "result[cols].gt(0).mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b190dc9f",
   "metadata": {},
   "source": [
    "<a href=\"https://pyquantnews.com/\">PyQuant News</a> is where finance practitioners level up with Python for quant finance, algorithmic trading, and market data analysis. Looking to get started? Check out the fastest growing, top-selling course to <a href=\"https://gettingstartedwithpythonforquantfinance.com/\">get started with Python for quant finance</a>. For educational purposes. Not investment advise. Use at your own risk."
   ]
  }
 ],
 "metadata": {
  "jupytext": {
   "cell_metadata_filter": "-all",
   "main_language": "python",
   "notebook_metadata_filter": "-all"
  },
  "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.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
