{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "aa29771a",
   "metadata": {},
   "source": [
    "<div style=\"background-color:#000;\"><img src=\"pqn.png\"></img></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1ed22fa1",
   "metadata": {},
   "source": [
    "This code implements a trading algorithm using Zipline, simulating trades on Apple Inc. (AAPL) stock based on moving average crossovers. It initializes the trading environment, defines trading logic, and records relevant data. The algorithm is backtested over a specified time period, and performance metrics are analyzed and visualized using Pyfolio. This is useful for developing and evaluating trading strategies in a systematic manner."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5155ca1e",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import pandas_datareader.data as web"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d1b4290f",
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aef80e58",
   "metadata": {},
   "outputs": [],
   "source": [
    "from zipline import run_algorithm\n",
    "from zipline.api import order_target, record, symbol\n",
    "from zipline.finance import commission, slippage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eec4cef3",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pyfolio as pf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e1fa431a",
   "metadata": {
    "lines_to_next_cell": 1
   },
   "outputs": [],
   "source": [
    "import warnings\n",
    "warnings.filterwarnings('ignore')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "19f0166c",
   "metadata": {},
   "source": [
    "Load the Zipline extension for Jupyter notebooks"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5d952e31",
   "metadata": {},
   "outputs": [],
   "source": [
    "%load_ext zipline"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "86ddb827",
   "metadata": {},
   "source": [
    "Ingest historical data from Quandl for Zipline to use"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6416593a",
   "metadata": {},
   "outputs": [],
   "source": [
    "! zipline ingest -b quandl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c578c2fc",
   "metadata": {
    "lines_to_next_cell": 1
   },
   "outputs": [],
   "source": [
    "def initialize(context):\n",
    "    \"\"\"Initialize the trading algorithm\n",
    "\n",
    "    Sets up initial parameters and trading environment.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    context : zipline.assets.context\n",
    "        The algorithm's context, including variables and state.\n",
    "    \"\"\"\n",
    "\n",
    "    context.i = 0\n",
    "    context.asset = symbol(\"AAPL\")\n",
    "\n",
    "    context.set_commission(commission.PerShare(cost=0.01))\n",
    "    context.set_slippage(slippage.FixedSlippage(spread=0.01))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ad255427",
   "metadata": {
    "lines_to_next_cell": 1
   },
   "outputs": [],
   "source": [
    "def handle_data(context, data):\n",
    "    \"\"\"Handle the trading logic\n",
    "\n",
    "    Executes trading logic based on moving averages.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    context : zipline.assets.context\n",
    "        The algorithm's context, including variables and state.\n",
    "    data : zipline.protocol.BarData\n",
    "        Contains current and historical market data.\n",
    "    \"\"\"\n",
    "\n",
    "    context.i += 1\n",
    "    if context.i < 50:\n",
    "        return\n",
    "\n",
    "    short_mavg = data.history(\n",
    "        context.asset, \n",
    "        \"price\", \n",
    "        bar_count=14,\n",
    "        frequency=\"1d\"\n",
    "    ).mean()\n",
    "    \n",
    "    long_mavg = data.history(\n",
    "        context.asset,\n",
    "        \"price\",\n",
    "        bar_count=50,\n",
    "        frequency=\"1d\"\n",
    "    ).mean()\n",
    "\n",
    "    if short_mavg > long_mavg:\n",
    "        order_target(context.asset, 100)\n",
    "    elif short_mavg < long_mavg:\n",
    "        order_target(context.asset, 0)\n",
    "\n",
    "    record(\n",
    "        AAPL=data.current(context.asset, \"price\"),\n",
    "        short_mavg=short_mavg,\n",
    "        long_mavg=long_mavg,\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c995758d",
   "metadata": {
    "lines_to_next_cell": 1
   },
   "outputs": [],
   "source": [
    "def analyze(context, perf):\n",
    "    \"\"\"Analyze the performance of the algorithm\n",
    "\n",
    "    Visualizes the portfolio and stock performance.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    context : zipline.assets.context\n",
    "        The algorithm's context, including variables and state.\n",
    "    perf : pandas.DataFrame\n",
    "        A dataframe containing the performance metrics.\n",
    "    \"\"\"\n",
    "\n",
    "    fig = plt.figure()\n",
    "    ax1 = fig.add_subplot(211)\n",
    "    perf.portfolio_value.plot(ax=ax1)\n",
    "    ax1.set_ylabel(\"portfolio value in $\")\n",
    "\n",
    "    ax2 = fig.add_subplot(212)\n",
    "    perf[\"AAPL\"].plot(ax=ax2)\n",
    "    perf[[\"short_mavg\", \"long_mavg\"]].plot(ax=ax2)\n",
    "\n",
    "    perf_trans = perf.loc[\n",
    "        [t != [] for t in perf.transactions]\n",
    "    ]\n",
    "    buys = perf_trans.loc[\n",
    "        [t[0][\"amount\"] > 0 for t in perf_trans.transactions]\n",
    "    ]\n",
    "    sells = perf_trans.loc[\n",
    "        [t[0][\"amount\"] < 0 for t in perf_trans.transactions]\n",
    "    ]\n",
    "    ax2.plot(\n",
    "        buys.index,\n",
    "        perf.short_mavg.loc[buys.index],\n",
    "        \"^\",\n",
    "        markersize=10,\n",
    "        color=\"m\"\n",
    "    )\n",
    "    ax2.plot(\n",
    "        sells.index,\n",
    "        perf.short_mavg.loc[sells.index],\n",
    "        \"v\",\n",
    "        markersize=10,\n",
    "        color=\"k\"\n",
    "    )\n",
    "    ax2.set_ylabel(\"price in $\")\n",
    "    plt.legend(loc=0)\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e4bce6eb",
   "metadata": {},
   "source": [
    "Define the start and end dates for the backtesting period"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "606aa860",
   "metadata": {},
   "outputs": [],
   "source": [
    "start = pd.Timestamp('2000')\n",
    "end = pd.Timestamp('2018')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "87ff84e5",
   "metadata": {},
   "source": [
    "Fetch the benchmark returns for the S&P 500 index from the Federal Reserve Economic Data (FRED)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fc68568d",
   "metadata": {},
   "outputs": [],
   "source": [
    "sp500 = web.DataReader('SP500', 'fred', start, end).SP500\n",
    "benchmark_returns = sp500.pct_change()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3340b872",
   "metadata": {},
   "source": [
    "Run the algorithm with the specified parameters and historical data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f81482a1",
   "metadata": {},
   "outputs": [],
   "source": [
    "perf = run_algorithm(\n",
    "    start=start,\n",
    "    end=end,\n",
    "    initialize=initialize,\n",
    "    handle_data=handle_data,\n",
    "    analyze=analyze,\n",
    "    capital_base=100000,\n",
    "    benchmark_returns=benchmark_returns,\n",
    "    bundle=\"quandl\",\n",
    "    data_frequency=\"daily\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f8420c1",
   "metadata": {},
   "source": [
    "Display the performance metrics of the algorithm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2c8fdd55",
   "metadata": {},
   "outputs": [],
   "source": [
    "perf.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "01c3ebb3",
   "metadata": {},
   "source": [
    "Extract returns, positions, and transactions from the performance DataFrame for analysis"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2f2c6986",
   "metadata": {},
   "outputs": [],
   "source": [
    "returns, positions, transactions = \\\n",
    "    pf.utils.extract_rets_pos_txn_from_zipline(perf)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c658ddfc",
   "metadata": {},
   "source": [
    "Create a full tear sheet using Pyfolio to analyze the trading strategy's performance"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4a92b98b",
   "metadata": {},
   "outputs": [],
   "source": [
    "pf.create_full_tear_sheet(\n",
    "    returns,\n",
    "    positions=positions,\n",
    "    transactions=transactions,\n",
    "    live_start_date=\"2016-01-01\",\n",
    "    round_trips=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5ad9c36f",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "633aa53b",
   "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
}
