{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Technical Analysis with Pandas ([pandas_ta](https://github.com/twopirllc/pandas-ta))\n",
    "* Below contains examples of simple charts that can be made from pandas_ta indicators\n",
    "* Examples below are for **educational purposes only**\n",
    "* **NOTE:** The **watchlist** module is independent of Pandas TA. To easily use it, copy it from your local pandas_ta installation directory into your project directory."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Pandas TA v0.2.89b0\n",
      "To install the Latest Version:\n",
      "$ pip install -U git+https://github.com/twopirllc/pandas-ta\n",
      "\n",
      "Populating the interactive namespace from numpy and matplotlib\n"
     ]
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "import datetime as dt\n",
    "import random as rnd\n",
    "\n",
    "from tqdm import tqdm\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.ticker as ticker\n",
    "import mplfinance as mpf\n",
    "\n",
    "from alphaVantageAPI.alphavantage import AlphaVantage\n",
    "import pandas_ta as ta\n",
    "\n",
    "from watchlist import colors # Is this failing? If so, copy it locally. See above.\n",
    "\n",
    "print(f\"\\nPandas TA v{ta.version}\\nTo install the Latest Version:\\n$ pip install -U git+https://github.com/twopirllc/pandas-ta\\n\")\n",
    "\n",
    "%pylab inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### List of Indicators (post an [issue](https://github.com/twopirllc/pandas-ta/issues) if the indicator doc needs updating)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Pandas TA - Technical Analysis Indicators - v0.2.89b0\n",
      "Total Indicators & Utilities: 202\n",
      "Abbreviations:\n",
      "    aberration, above, above_value, accbands, ad, adosc, adx, alma, amat, ao, aobv, apo, aroon, atr, bbands, below, below_value, bias, bop, brar, cci, cdl_pattern, cdl_z, cfo, cg, chop, cksp, cmf, cmo, coppock, cross, cross_value, cti, decay, decreasing, dema, dm, donchian, dpo, ebsw, efi, ema, entropy, eom, er, eri, fisher, fwma, ha, hilo, hl2, hlc3, hma, hwc, hwma, ichimoku, increasing, inertia, kama, kc, kdj, kst, kurtosis, kvo, linreg, log_return, long_run, macd, mad, massi, mcgd, median, mfi, midpoint, midprice, mom, natr, nvi, obv, ohlc4, pdist, percent_return, pgo, ppo, psar, psl, pvi, pvo, pvol, pvr, pvt, pwma, qqe, qstick, quantile, rma, roc, rsi, rsx, rvgi, rvi, short_run, sinwma, skew, slope, sma, smi, squeeze, ssf, stc, stdev, stoch, stochrsi, supertrend, swma, t3, td_seq, tema, thermo, trima, trix, true_range, tsi, tsignals, ttm_trend, ui, uo, variance, vhf, vidya, vortex, vp, vwap, vwma, wcp, willr, wma, xsignals, zlma, zscore\n",
      "\n",
      "Candle Patterns:\n",
      "    2crows, 3blackcrows, 3inside, 3linestrike, 3outside, 3starsinsouth, 3whitesoldiers, abandonedbaby, advanceblock, belthold, breakaway, closingmarubozu, concealbabyswall, counterattack, darkcloudcover, doji, dojistar, dragonflydoji, engulfing, eveningdojistar, eveningstar, gapsidesidewhite, gravestonedoji, hammer, hangingman, harami, haramicross, highwave, hikkake, hikkakemod, homingpigeon, identical3crows, inneck, inside, invertedhammer, kicking, kickingbylength, ladderbottom, longleggeddoji, longline, marubozu, matchinglow, mathold, morningdojistar, morningstar, onneck, piercing, rickshawman, risefall3methods, separatinglines, shootingstar, shortline, spinningtop, stalledpattern, sticksandwich, takuri, tasukigap, thrusting, tristar, unique3river, upsidegap2crows, xsidegap3methods\n"
     ]
    }
   ],
   "source": [
    "e = pd.DataFrame()\n",
    "e.ta.indicators()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Individual Indicator help"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on function ema in module pandas_ta.overlap.ema:\n",
      "\n",
      "ema(close, length=None, offset=None, **kwargs)\n",
      "    Exponential Moving Average (EMA)\n",
      "    \n",
      "    The Exponential Moving Average is more responsive moving average compared to the\n",
      "    Simple Moving Average (SMA).  The weights are determined by alpha which is\n",
      "    proportional to it's length.  There are several different methods of calculating\n",
      "    EMA.  One method uses just the standard definition of EMA and another uses the\n",
      "    SMA to generate the initial value for the rest of the calculation.\n",
      "    \n",
      "    Sources:\n",
      "        https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_averages\n",
      "        https://www.investopedia.com/ask/answers/122314/what-exponential-moving-average-ema-formula-and-how-ema-calculated.asp\n",
      "    \n",
      "    Calculation:\n",
      "        Default Inputs:\n",
      "            length=10, adjust=False, sma=True\n",
      "        if sma:\n",
      "            sma_nth = close[0:length].sum() / length\n",
      "            close[:length - 1] = np.NaN\n",
      "            close.iloc[length - 1] = sma_nth\n",
      "        EMA = close.ewm(span=length, adjust=adjust).mean()\n",
      "    \n",
      "    Args:\n",
      "        close (pd.Series): Series of 'close's\n",
      "        length (int): It's period. Default: 10\n",
      "        offset (int): How many periods to offset the result. Default: 0\n",
      "    \n",
      "    Kwargs:\n",
      "        adjust (bool, optional): Default: False\n",
      "        sma (bool, optional): If True, uses SMA for initial value. Default: True\n",
      "        fillna (value, optional): pd.DataFrame.fillna(value)\n",
      "        fill_method (value, optional): Type of fill method\n",
      "    \n",
      "    Returns:\n",
      "        pd.Series: New feature generated.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(ta.ema)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Function to format Millions\n",
    "def format_millions(x, pos):\n",
    "    \"The two args are the value and tick position\"\n",
    "    return \"%1.1fM\" % (x * 1e-6)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def ctitle(indicator_name, ticker=\"SPY\", length=100):\n",
    "    return f\"{ticker}: {indicator_name} from {recent_startdate} to {recent_enddate} ({length})\"\n",
    "\n",
    "# # All Data: 0, Last Four Years: 0.25, Last Two Years: 0.5, This Year: 1, Last Half Year: 2, Last Quarter: 3\n",
    "# yearly_divisor = 1\n",
    "# recent = int(ta.RATE[\"TRADING_DAYS_PER_YEAR\"] / yearly_divisor) if yearly_divisor > 0 else df.shape[0]\n",
    "# print(recent)\n",
    "def recent_bars(df, tf: str = \"1y\"):\n",
    "    # All Data: 0, Last Four Years: 0.25, Last Two Years: 0.5, This Year: 1, Last Half Year: 2, Last Quarter: 4\n",
    "    yearly_divisor = {\"all\": 0, \"10y\": 0.1, \"5y\": 0.2, \"4y\": 0.25, \"3y\": 1./3, \"2y\": 0.5, \"1y\": 1, \"6mo\": 2, \"3mo\": 4}\n",
    "    yd = yearly_divisor[tf] if tf in yearly_divisor.keys() else 0\n",
    "    return int(ta.RATE[\"TRADING_DAYS_PER_YEAR\"] / yd) if yd > 0 else df.shape[0]\n",
    "\n",
    "def ta_ylim(series: pd.Series, percent: float = 0.1):\n",
    "    smin, smax = series.min(), series.max()\n",
    "    if isinstance(percent, float) and 0 <= float(percent) <= 1:\n",
    "        y_min = (1 + percent) * smin if smin < 0 else (1 - percent) * smin\n",
    "        y_max = (1 - percent) * smax if smax < 0 else (1 + percent) * smax\n",
    "        return (y_min, y_max)\n",
    "    return (smin, smax)\n",
    "\n",
    "price_size = (16, 8)\n",
    "ind_size = (16, 3.25)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load Daily Ticker Data using yfinance and clean it"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# help(e.ta.ticker)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "====  Company Information  =====================================================\n",
      "SPDR S&P 500 ETF Trust(SPDR S&P 500) [SPY]\n",
      "\n",
      "====  Market Information   =====================================================\n",
      "Market | Exchange | Symbol | Category               US | PCX | SPY | Large Blend\n",
      "\n",
      "NAV | Yield                                                     415.05 | 1.3300%\n",
      "\n",
      "\n",
      "\n",
      "====  Price Information    =====================================================\n",
      "Open High Low | Close                    417.0900  417.0900  414.7000 | 414.9200\n",
      "HL2 | HLC3 | OHLC4 | C - OHLC4             416.2640, 415.8160, 416.1345, -1.2145\n",
      "Change (%)                                                    -5.6741 (-1.3491%)\n",
      "Bid | Ask | Spread                          413.56 x 900 | 413.68 x 900 | 0.1200\n",
      "Volume | Market | Avg Vol (10Day)       \n",
      "                             118,676,302 | 118,676,302 | 74,021,017 (66,100,437)\n",
      "\n",
      "52Wk Range (% from 52Wk Low)               298.93 - 425.46 : 126.5300 (38.8017%)\n",
      "SMA 50 | SMA 200                                             418.3137 | 395.1771\n",
      "Avg. Return 3Yr | 5Yr                                        16.9700% | 17.4100%\n",
      "\n",
      "====  Dividends / Splits   =====================================================\n",
      "\n",
      "Stock Splits (Last 5 of 114):\n",
      "Date   2021-03-19  2020-12-18  2020-09-18  2020-06-19  2020-03-20\n",
      "Ratio       1.278        1.58       1.339       1.366       1.406\n",
      "SPY(252, 7) from 2020-06-19 00:00:00 to 2021-06-18 00:00:00\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>open</th>\n",
       "      <th>high</th>\n",
       "      <th>low</th>\n",
       "      <th>close</th>\n",
       "      <th>volume</th>\n",
       "      <th>dividends</th>\n",
       "      <th>stock splits</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2020-06-19</th>\n",
       "      <td>310.572014</td>\n",
       "      <td>310.779600</td>\n",
       "      <td>303.019496</td>\n",
       "      <td>305.105347</td>\n",
       "      <td>135549600</td>\n",
       "      <td>1.366</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2020-06-22</th>\n",
       "      <td>304.462768</td>\n",
       "      <td>307.487721</td>\n",
       "      <td>303.236978</td>\n",
       "      <td>307.062653</td>\n",
       "      <td>74649400</td>\n",
       "      <td>0.000</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2020-06-23</th>\n",
       "      <td>309.899768</td>\n",
       "      <td>310.898211</td>\n",
       "      <td>308.041294</td>\n",
       "      <td>308.476257</td>\n",
       "      <td>68471200</td>\n",
       "      <td>0.000</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2020-06-24</th>\n",
       "      <td>306.291601</td>\n",
       "      <td>306.953942</td>\n",
       "      <td>298.640252</td>\n",
       "      <td>300.607452</td>\n",
       "      <td>132813500</td>\n",
       "      <td>0.000</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2020-06-25</th>\n",
       "      <td>299.994539</td>\n",
       "      <td>304.116796</td>\n",
       "      <td>297.829618</td>\n",
       "      <td>303.830109</td>\n",
       "      <td>89468000</td>\n",
       "      <td>0.000</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                  open        high         low       close     volume  \\\n",
       "date                                                                    \n",
       "2020-06-19  310.572014  310.779600  303.019496  305.105347  135549600   \n",
       "2020-06-22  304.462768  307.487721  303.236978  307.062653   74649400   \n",
       "2020-06-23  309.899768  310.898211  308.041294  308.476257   68471200   \n",
       "2020-06-24  306.291601  306.953942  298.640252  300.607452  132813500   \n",
       "2020-06-25  299.994539  304.116796  297.829618  303.830109   89468000   \n",
       "\n",
       "            dividends  stock splits  \n",
       "date                                 \n",
       "2020-06-19      1.366             0  \n",
       "2020-06-22      0.000             0  \n",
       "2020-06-23      0.000             0  \n",
       "2020-06-24      0.000             0  \n",
       "2020-06-25      0.000             0  "
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Recent Data\n",
    "ticker = \"BTC-USD\"\n",
    "ticker = \"SPY\"\n",
    "df = e.ta.ticker(ticker, kind=\"info\", lc_cols=True)\n",
    "recent_startdate = df.tail(recent_bars(df)).index[0]\n",
    "recent_enddate = df.tail(recent_bars(df)).index[-1]\n",
    "print(f\"{df.name}{df.tail(recent_bars(df)).shape} from {recent_startdate} to {recent_enddate}\")\n",
    "df.tail(recent_bars(df)).head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Aliases"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "opendf = df[\"open\"]\n",
    "highdf = df[\"high\"]\n",
    "lowdf = df[\"low\"]\n",
    "closedf = df[\"close\"]\n",
    "volumedf = df[\"volume\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## DataFrame **constants**: When you need some simple lines for charting"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Columns: open, high, low, close, volume, dividends, stock splits, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, -100, -90, -80, -70, -50, -30, -20, -10, 10, 20, 30, 50, 70, 80, 90, 100\n"
     ]
    }
   ],
   "source": [
    "# help(df.ta.constants) # for more info\n",
    "chart_lines = np.append(np.arange(-5, 6, 1), np.arange(-100, 110, 10))\n",
    "df.ta.constants(True, chart_lines) # Adding the constants for the charts\n",
    "df.ta.constants(False, np.array([-60, -40, 40, 60])) # Removing some constants from the DataFrame\n",
    "print(f\"Columns: {', '.join(list(df.columns))}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example Charting Class utilizing **mplfinance** panels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Chart(object):\n",
    "    def __init__(self, df: pd.DataFrame = None, strategy: ta.Strategy = ta.CommonStrategy, *args, **kwargs):\n",
    "        self.verbose = kwargs.pop(\"verbose\", False)\n",
    "\n",
    "        if isinstance(df, pd.DataFrame) and df.ta.datetime_ordered:\n",
    "            self.df = df\n",
    "            if self.df.name is not None and self.df.name != \"\":\n",
    "                df_name = str(self.df.name)\n",
    "            else:\n",
    "                df_name = \"DataFrame\"\n",
    "            if self.verbose: print(f\"[i] Loaded {df_name}{self.df.shape}\")\n",
    "        else:\n",
    "            print(f\"[X] Oops! Missing 'ohlcv' data or index is not datetime ordered.\\n\")\n",
    "            return None\n",
    "\n",
    "        self._validate_mpf_kwargs(**kwargs)\n",
    "        self._validate_chart_kwargs(**kwargs)\n",
    "        self._validate_ta_strategy(strategy)\n",
    "\n",
    "        # Build TA and Plot\n",
    "        self.df.ta.strategy(self.strategy, verbose=self.verbose)\n",
    "        self._plot(**kwargs)\n",
    "\n",
    "    def _validate_ta_strategy(self, strategy):\n",
    "        if strategy is not None or isinstance(strategy, ta.Strategy):\n",
    "            self.strategy = strategy\n",
    "        elif len(self.strategy_ta) > 0:\n",
    "            print(f\"[+] Strategy: {self.strategy_name}\")\n",
    "        else:\n",
    "            self.strategy = ta.CommonStrategy        \n",
    "\n",
    "    def _validate_chart_kwargs(self, **kwargs):\n",
    "        \"\"\"Chart Settings\"\"\"\n",
    "        self.config = {}\n",
    "        self.config[\"last\"] = kwargs.pop(\"last\", recent_bars(self.df))\n",
    "        self.config[\"rpad\"] = kwargs.pop(\"rpad\", 10)\n",
    "        self.config[\"title\"] = kwargs.pop(\"title\", \"Asset\")\n",
    "        self.config[\"volume\"] = kwargs.pop(\"volume\", True)\n",
    "\n",
    "    def _validate_mpf_kwargs(self, **kwargs):\n",
    "        # mpf global chart settings\n",
    "        default_chart = mpf.available_styles()[-1]\n",
    "        default_mpf_width = {\n",
    "            'candle_linewidth': 0.6,\n",
    "            'candle_width': 0.525,\n",
    "            'volume_width': 0.525\n",
    "        }\n",
    "        mpfchart = {}\n",
    "\n",
    "        mpf_style = kwargs.pop(\"style\", \"\")\n",
    "        if mpf_style == \"\" or mpf_style.lower() == \"random\":\n",
    "            mpf_styles = mpf.available_styles()\n",
    "            mpfchart[\"style\"] = mpf_styles[rnd.randrange(len(mpf_styles))]\n",
    "        elif mpf_style.lower() in mpf.available_styles():\n",
    "            mpfchart[\"style\"] = mpf_style\n",
    "\n",
    "        mpfchart[\"figsize\"] = kwargs.pop(\"figsize\", (12, 10))\n",
    "        mpfchart[\"non_trading\"] = kwargs.pop(\"nontrading\", False)\n",
    "        mpfchart[\"rc\"] = kwargs.pop(\"rc\", {'figure.facecolor': '#EDEDED'})\n",
    "        mpfchart[\"plot_ratios\"] = kwargs.pop(\"plot_ratios\", (12, 1.7))\n",
    "        mpfchart[\"scale_padding\"] = kwargs.pop(\"scale_padding\", {'left': 1, 'top': 4, 'right': 1, 'bottom': 1})\n",
    "        mpfchart[\"tight_layout\"] = kwargs.pop(\"tight_layout\", True)\n",
    "        mpfchart[\"type\"] = kwargs.pop(\"type\", \"candle\")\n",
    "        mpfchart[\"width_config\"] = kwargs.pop(\"width_config\", default_mpf_width)\n",
    "        mpfchart[\"xrotation\"] = kwargs.pop(\"xrotation\", 15)\n",
    "        \n",
    "        self.mpfchart = mpfchart\n",
    "\n",
    "    def _attribution(self):\n",
    "        print(f\"\\nPandas v: {pd.__version__} [pip install pandas] https://github.com/pandas-dev/pandas\")\n",
    "        print(f\"Data from AlphaVantage v: 1.0.19 [pip install alphaVantage-api] http://www.alphavantage.co https://github.com/twopirllc/AlphaVantageAPI\")\n",
    "        print(f\"Technical Analysis with Pandas TA v: {ta.version} [pip install pandas_ta] https://github.com/twopirllc/pandas-ta\")\n",
    "        print(f\"Charts by Matplotlib Finance v: {mpf.__version__} [pip install mplfinance] https://github.com/matplotlib/mplfinance\\n\")\n",
    "\n",
    "    def _right_pad_df(self, rpad: int, delta_unit: str = \"D\", range_freq: str = \"B\"):\n",
    "        if rpad > 0:\n",
    "            dfpad = self.df[-rpad:].copy()\n",
    "            dfpad.iloc[:,:] = np.NaN\n",
    "\n",
    "            df_frequency = self.df.index.value_counts().mode()[0] # Most common frequency\n",
    "            freq_delta = pd.Timedelta(df_frequency, unit=delta_unit)\n",
    "            new_dr = pd.date_range(start=self.df.index[-1] + freq_delta, periods=rpad, freq=range_freq)\n",
    "            dfpad.index = new_dr # Update the padded index with new dates\n",
    "            self.df = self.df.append(dfpad)\n",
    "        \n",
    "            \n",
    "    def _plot(self, **kwargs):\n",
    "        if not isinstance(self.mpfchart[\"plot_ratios\"], tuple):\n",
    "            print(f\"[X] plot_ratios must be a tuple\")\n",
    "            return\n",
    "\n",
    "        # Override Chart Title Option\n",
    "        chart_title = self.config[\"title\"]\n",
    "        if \"title\" in kwargs and isinstance(kwargs[\"title\"], str):\n",
    "            chart_title = kwargs.pop(\"title\")\n",
    "\n",
    "        # Override Right Bar Padding Option\n",
    "        rpad = self.config[\"rpad\"]\n",
    "        if \"rpad\" in kwargs and kwargs[\"rpad\"] > 0:\n",
    "            rpad = int(kwargs[\"rpad\"])\n",
    "\n",
    "        def cpanel():\n",
    "            return len(self.mpfchart[\"plot_ratios\"])\n",
    "\n",
    "        # Last Second Default TA Indicators\n",
    "        linreg = kwargs.pop(\"linreg\", False)\n",
    "        linreg_name = self.df.ta.linreg(append=True).name if linreg else \"\"\n",
    "\n",
    "        midpoint = kwargs.pop(\"midpoint\", False)\n",
    "        midpoint_name = self.df.ta.midpoint(append=True).name if midpoint else \"\"\n",
    "\n",
    "        ohlc4 = kwargs.pop(\"ohlc4\", False)\n",
    "        ohlc4_name = self.df.ta.ohlc4(append=True).name if ohlc4 else \"\"\n",
    "\n",
    "        clr = kwargs.pop(\"clr\", False)\n",
    "        clr_name = self.df.ta.log_return(cumulative=True, append=True).name if clr else \"\"\n",
    "\n",
    "        rsi = kwargs.pop(\"rsi\", False)\n",
    "        rsi_length = kwargs.pop(\"rsi_length\", None)\n",
    "        if isinstance(rsi_length, int) and rsi_length > 1:\n",
    "            rsi_name = self.df.ta.rsi(length=rsi_length, append=True).name\n",
    "        elif rsi:\n",
    "            rsi_name = self.df.ta.rsi(append=True).name\n",
    "        else: rsi_name = \"\"\n",
    "            \n",
    "        zscore = kwargs.pop(\"zscore\", False)\n",
    "        zscore_length = kwargs.pop(\"zscore_length\", None)\n",
    "        if isinstance(zscore_length, int) and zscore_length > 1:\n",
    "            zs_name = self.df.ta.zscore(length=zscore_length, append=True).name\n",
    "        elif zscore:\n",
    "            zs_name = self.df.ta.zscore(append=True).name\n",
    "        else: zs_name = \"\"\n",
    "\n",
    "        macd = kwargs.pop(\"macd\", False)\n",
    "        macd_name = \"\"\n",
    "        if macd:\n",
    "            macds = self.df.ta.macd(append=True)\n",
    "            macd_name = macds.name\n",
    "\n",
    "        squeeze = kwargs.pop(\"squeeze\", False)\n",
    "        lazybear = kwargs.pop(\"lazybear\", False)\n",
    "        squeeze_name = \"\"\n",
    "        if squeeze:\n",
    "            squeezes = self.df.ta.squeeze(lazybear=lazybear, detailed=True, append=True)\n",
    "            squeeze_name = squeezes.name\n",
    "\n",
    "        ama = kwargs.pop(\"archermas\", False)\n",
    "        ama_name = \"\"\n",
    "        if ama:\n",
    "            amas = self.df.ta.amat(append=True)\n",
    "            ama_name = amas.name\n",
    "\n",
    "        aobv = kwargs.pop(\"archerobv\", False)\n",
    "        aobv_name = \"\"\n",
    "        if aobv:\n",
    "            aobvs = self.df.ta.aobv(append=True)\n",
    "            aobv_name = aobvs.name\n",
    "\n",
    "        # Pad and trim Chart\n",
    "        self._right_pad_df(rpad)\n",
    "        mpfdf = self.df.tail(self.config[\"last\"]).copy()\n",
    "        mpfdf_columns = list(self.df.columns)\n",
    "        \n",
    "        tsig = kwargs.pop(\"tsignals\", False)\n",
    "        if tsig:\n",
    "            # Long Trend requires Series Comparison (<=. <, = >, >=)\n",
    "            # or Trade Logic that yields trends in binary.\n",
    "            default_long = mpfdf[\"SMA_10\"] > mpfdf[\"SMA_20\"]\n",
    "            long_trend = kwargs.pop(\"long_trend\", default_long)\n",
    "            if not isinstance(long_trend, pd.Series):\n",
    "                raise(f\"[X] Must be a Series that has boolean values or values of 0s and 1s\")\n",
    "            mpfdf.ta.percent_return(append=True)\n",
    "            mpfdf.ta.tsignals(long_trend, append=True)\n",
    "            buys = np.where(mpfdf.TS_Entries > 0, 1, np.nan)\n",
    "            sells = np.where(mpfdf.TS_Exits > 0, 1, np.nan)\n",
    "            mpfdf[\"ACTRET_1\"] = mpfdf.TS_Trends * mpfdf.PCTRET_1\n",
    "\n",
    "        # BEGIN: Custom TA Plots and Panels\n",
    "        # Modify the area below \n",
    "        taplots = [] # Holds all the additional plots\n",
    "\n",
    "        # Panel 0: Price Overlay\n",
    "        if linreg_name in mpfdf_columns:\n",
    "            taplots += [mpf.make_addplot(mpfdf[linreg_name], type=kwargs.pop(\"linreg_type\", \"line\"), color=kwargs.pop(\"linreg_color\", \"black\"), linestyle=\"-.\", width=1.2, panel=0)]\n",
    "\n",
    "        if midpoint_name in mpfdf_columns:\n",
    "            taplots += [mpf.make_addplot(mpfdf[midpoint_name], type=kwargs.pop(\"midpoint_type\", \"scatter\"), color=kwargs.pop(\"midpoint_color\", \"fuchsia\"), width=0.4, panel=0)]\n",
    "\n",
    "        if ohlc4_name in mpfdf_columns:\n",
    "            taplots += [mpf.make_addplot(mpfdf[ohlc4_name], ylabel=ohlc4_name, type=kwargs.pop(\"ohlc4_type\", \"scatter\"), color=kwargs.pop(\"ohlc4_color\", \"blue\"), alpha=0.85, width=0.4, panel=0)]\n",
    "    \n",
    "        if self.strategy.name == ta.CommonStrategy.name:\n",
    "            total_sma = 0 # Check if all the overlap indicators exists before adding plots\n",
    "            for c in [\"SMA_10\", \"SMA_20\", \"SMA_50\", \"SMA_200\"]:\n",
    "                if c in mpfdf_columns: total_sma += 1\n",
    "                else: print(f\"[X] Indicator: {c} missing!\")\n",
    "            if total_sma == 4:\n",
    "                ta_smas = [\n",
    "                    mpf.make_addplot(mpfdf[\"SMA_10\"], color=\"green\", width=1.5, panel=0),\n",
    "                    mpf.make_addplot(mpfdf[\"SMA_20\"], color=\"orange\", width=2, panel=0),\n",
    "                    mpf.make_addplot(mpfdf[\"SMA_50\"], color=\"red\", width=2, panel=0),\n",
    "                    mpf.make_addplot(mpfdf[\"SMA_200\"], color=\"maroon\", width=3, panel=0),\n",
    "                ]\n",
    "                taplots += ta_smas\n",
    "\n",
    "        if tsig:\n",
    "            taplots += [\n",
    "                mpf.make_addplot(0.985 * mpfdf.close * buys, type=\"scatter\", marker=\"^\", markersize=26, color=\"blue\", panel=0),\n",
    "                mpf.make_addplot(1.015 * mpfdf.close * sells, type=\"scatter\", marker=\"v\", markersize=26, color=\"fuchsia\", panel=0),\n",
    "            ]\n",
    "                \n",
    "        if len(ama_name):\n",
    "            amat_sr_ = mpfdf[amas.columns[-1]][mpfdf[amas.columns[-1]] > 0]\n",
    "            amat_sr = amat_sr_.index.to_list()\n",
    "        else:\n",
    "            amat_sr = None\n",
    "\n",
    "        # Panel 1: If volume=True, the add the VOL MA. Since we know there is only one, we immediately pop it.\n",
    "        if self.config[\"volume\"]:\n",
    "            volma = [x for x in list(self.df.columns) if x.startswith(\"VOL_\")].pop()\n",
    "            max_vol = mpfdf[\"volume\"].max()\n",
    "             # Volume axis\n",
    "            ta_volume = [mpf.make_addplot(mpfdf[volma], color=\"black\", width=1.2, panel=1, ylim=(-.2 * max_vol, 1.5 * max_vol))]\n",
    "            taplots += ta_volume\n",
    "\n",
    "        # Panels 2 - 9\n",
    "        common_plot_ratio = (3,)\n",
    "\n",
    "        if len(aobv_name):\n",
    "            _p = kwargs.pop(\"aobv_percenty\", 0.2)\n",
    "            aobv_ylim = ta_ylim(mpfdf[aobvs.columns[0]], _p)\n",
    "            taplots += [\n",
    "                mpf.make_addplot(mpfdf[aobvs.columns[0]], ylabel=aobv_name, color=\"black\", width=1.5, panel=cpanel(), ylim=aobv_ylim),\n",
    "                mpf.make_addplot(mpfdf[aobvs.columns[2]], color=\"silver\", width=1, panel=cpanel(), ylim=aobv_ylim),\n",
    "                mpf.make_addplot(mpfdf[aobvs.columns[3]], color=\"green\", width=1, panel=cpanel(), ylim=aobv_ylim),\n",
    "                mpf.make_addplot(mpfdf[aobvs.columns[4]], color=\"red\", width=1.2, panel=cpanel(), ylim=aobv_ylim),\n",
    "            ]\n",
    "            self.mpfchart[\"plot_ratios\"] += common_plot_ratio # Required to add a new Panel\n",
    "\n",
    "        if clr_name in mpfdf_columns:\n",
    "            _p = kwargs.pop(\"clr_percenty\", 0.1)\n",
    "            clr_ylim = ta_ylim(mpfdf[clr_name], _p)\n",
    "\n",
    "            taplots += [mpf.make_addplot(mpfdf[clr_name], ylabel=clr_name, color=\"black\", width=1.5, panel=cpanel(), ylim=clr_ylim)]\n",
    "            if (1 - _p) * mpfdf[clr_name].min() < 0 and (1 + _p) * mpfdf[clr_name].max() > 0:\n",
    "                taplots += [mpf.make_addplot(mpfdf[\"0\"], color=\"gray\", width=1.2, panel=cpanel(), ylim=clr_ylim)]\n",
    "            self.mpfchart[\"plot_ratios\"] += common_plot_ratio # Required to add a new Panel\n",
    "\n",
    "        if rsi_name in mpfdf_columns:\n",
    "            rsi_ylim = (0, 100)\n",
    "            taplots += [\n",
    "                mpf.make_addplot(mpfdf[rsi_name], ylabel=rsi_name, color=kwargs.pop(\"rsi_color\", \"black\"), width=1.5, panel=cpanel(), ylim=rsi_ylim),\n",
    "                mpf.make_addplot(mpfdf[\"20\"], color=\"green\", width=1, panel=cpanel(), ylim=rsi_ylim),\n",
    "                mpf.make_addplot(mpfdf[\"50\"], color=\"gray\", width=0.8, panel=cpanel(), ylim=rsi_ylim),\n",
    "                mpf.make_addplot(mpfdf[\"80\"], color=\"red\", width=1, panel=cpanel(), ylim=rsi_ylim),\n",
    "            ]\n",
    "            self.mpfchart[\"plot_ratios\"] += common_plot_ratio # Required to add a new Panel\n",
    "        \n",
    "        if macd_name in mpfdf_columns:\n",
    "            _p = kwargs.pop(\"macd_percenty\", 0.15)\n",
    "            macd_ylim = ta_ylim(mpfdf[macd_name], _p)\n",
    "            taplots += [\n",
    "                mpf.make_addplot(mpfdf[macd_name], ylabel=macd_name, color=\"black\", width=1.5, panel=cpanel()),#, ylim=macd_ylim),\n",
    "                mpf.make_addplot(mpfdf[macds.columns[-1]], color=\"blue\", width=1.1, panel=cpanel()),#, ylim=macd_ylim),\n",
    "                mpf.make_addplot(mpfdf[macds.columns[1]], type=\"bar\", alpha=0.8, color=\"dimgray\", width=0.8, panel=cpanel()),#, ylim=macd_ylim),\n",
    "                mpf.make_addplot(mpfdf[\"0\"], color=\"black\", width=1.2, panel=cpanel()),#, ylim=macd_ylim),\n",
    "            ]\n",
    "            self.mpfchart[\"plot_ratios\"] += common_plot_ratio # Required to add a new Panel            \n",
    "\n",
    "        if zs_name in mpfdf_columns:\n",
    "            _p = kwargs.pop(\"zascore_percenty\", 0.2)\n",
    "            zs_ylim = ta_ylim(mpfdf[zs_name], _p)\n",
    "            taplots += [\n",
    "                mpf.make_addplot(mpfdf[zs_name], ylabel=zs_name, color=\"black\", width=1.5, panel=cpanel(), ylim=zs_ylim),\n",
    "                mpf.make_addplot(mpfdf[\"-3\"], color=\"red\", width=1.2, panel=cpanel(), ylim=zs_ylim),\n",
    "                mpf.make_addplot(mpfdf[\"-2\"], color=\"orange\", width=1, panel=cpanel(), ylim=zs_ylim),\n",
    "                mpf.make_addplot(mpfdf[\"-1\"], color=\"silver\", width=1, panel=cpanel(), ylim=zs_ylim),\n",
    "                mpf.make_addplot(mpfdf[\"0\"], color=\"black\", width=1.2, panel=cpanel(), ylim=zs_ylim),\n",
    "                mpf.make_addplot(mpfdf[\"1\"], color=\"silver\", width=1, panel=cpanel(), ylim=zs_ylim),\n",
    "                mpf.make_addplot(mpfdf[\"2\"], color=\"orange\", width=1, panel=cpanel(), ylim=zs_ylim),\n",
    "                mpf.make_addplot(mpfdf[\"3\"], color=\"red\", width=1.2, panel=cpanel(), ylim=zs_ylim)\n",
    "            ]\n",
    "            self.mpfchart[\"plot_ratios\"] += common_plot_ratio # Required to add a new Panel\n",
    "\n",
    "        if squeeze_name in mpfdf_columns:\n",
    "            _p = kwargs.pop(\"squeeze_percenty\", 0.6)\n",
    "            sqz_ylim = ta_ylim(mpfdf[squeeze_name], _p)\n",
    "            taplots += [\n",
    "                mpf.make_addplot(mpfdf[squeezes.columns[-4]], type=\"bar\", color=\"lime\", alpha=0.65, width=0.8, panel=cpanel(), ylim=sqz_ylim),\n",
    "                mpf.make_addplot(mpfdf[squeezes.columns[-3]], type=\"bar\", color=\"green\", alpha=0.65, width=0.8, panel=cpanel(), ylim=sqz_ylim),\n",
    "                mpf.make_addplot(mpfdf[squeezes.columns[-2]], type=\"bar\", color=\"maroon\", alpha=0.65, width=0.8, panel=cpanel(), ylim=sqz_ylim),\n",
    "                mpf.make_addplot(mpfdf[squeezes.columns[-1]], type=\"bar\", color=\"red\", alpha=0.65, width=0.8, panel=cpanel(), ylim=sqz_ylim),\n",
    "                mpf.make_addplot(mpfdf[\"0\"], color=\"black\", width=1.2, panel=cpanel(), ylim=sqz_ylim),\n",
    "                mpf.make_addplot(mpfdf[squeezes.columns[4]], ylabel=squeeze_name, color=\"green\", width=2, panel=cpanel(), ylim=sqz_ylim),\n",
    "                mpf.make_addplot(mpfdf[squeezes.columns[5]], color=\"red\", width=1.8, panel=cpanel(), ylim=sqz_ylim),\n",
    "            ]\n",
    "            self.mpfchart[\"plot_ratios\"] += common_plot_ratio # Required to add a new Panel\n",
    "\n",
    "        if tsig:\n",
    "            _p = kwargs.pop(\"tsig_percenty\", 0.23)\n",
    "            treturn_ylim = ta_ylim(mpfdf[\"ACTRET_1\"], _p)\n",
    "            taplots += [\n",
    "                mpf.make_addplot(mpfdf[\"ACTRET_1\"], ylabel=\"Active % Return\", type=\"bar\", color=\"green\", alpha=0.45, width=0.8, panel=cpanel(), ylim=treturn_ylim),\n",
    "                mpf.make_addplot(pd.Series(mpfdf[\"ACTRET_1\"].mean(), index=mpfdf[\"ACTRET_1\"].index), color=\"blue\", width=1, panel=cpanel(), ylim=treturn_ylim),\n",
    "                mpf.make_addplot(mpfdf[\"0\"], color=\"black\", width=1, panel=cpanel(), ylim=treturn_ylim),\n",
    "            ]\n",
    "            self.mpfchart[\"plot_ratios\"] += common_plot_ratio # Required to add a new Panel\n",
    "\n",
    "            _p = kwargs.pop(\"cstreturn_percenty\", 0.58)\n",
    "            mpfdf[\"CUMACTRET_1\"] = mpfdf[\"ACTRET_1\"].cumsum()\n",
    "            cumactret_ylim = ta_ylim(mpfdf[\"CUMACTRET_1\"], _p)\n",
    "            taplots += [\n",
    "                mpf.make_addplot(mpfdf[\"CUMACTRET_1\"], ylabel=\"Cum Trend Return\", type=\"bar\", color=\"silver\", alpha=0.45, width=1, panel=cpanel(), ylim=cumactret_ylim),\n",
    "                mpf.make_addplot(0.9 * buys * mpfdf[\"CUMACTRET_1\"], type=\"scatter\", marker=\"^\", markersize=14, color=\"green\", panel=cpanel(), ylim=cumactret_ylim),\n",
    "                mpf.make_addplot(1.1 * sells * mpfdf[\"CUMACTRET_1\"], type=\"scatter\", marker=\"v\", markersize=14, color=\"red\", panel=cpanel(), ylim=cumactret_ylim),\n",
    "                mpf.make_addplot(mpfdf[\"0\"], color=\"black\", width=1, panel=cpanel(), ylim=cumactret_ylim),\n",
    "            ]            \n",
    "            self.mpfchart[\"plot_ratios\"] += common_plot_ratio # Required to add a new Panel\n",
    "\n",
    "        # END: Custom TA Plots and Panels\n",
    "        \n",
    "        if self.verbose:\n",
    "            additional_ta = []\n",
    "            chart_title  = f\"{chart_title} [{self.strategy.name}] (last {self.config['last']} bars)\"\n",
    "            chart_title += f\"\\nSince {mpfdf.index[0]} till {mpfdf.index[-1]}\"\n",
    "            if len(linreg_name) > 0: additional_ta.append(linreg_name)\n",
    "            if len(midpoint_name) > 0: additional_ta.append(midpoint_name)\n",
    "            if len(ohlc4_name) > 0: additional_ta.append(ohlc4_name)\n",
    "            if len(additional_ta) > 0:\n",
    "                chart_title += f\"\\nIncluding: {', '.join(additional_ta)}\"\n",
    "\n",
    "        if amat_sr:\n",
    "            vlines_ = dict(vlines=amat_sr, alpha=0.1, colors=\"red\")\n",
    "        else:\n",
    "            # Hidden because vlines needs valid arguments even if None \n",
    "            vlines_ = dict(vlines=mpfdf.index[0], alpha=0, colors=\"white\")\n",
    "\n",
    "        # Create Final Plot\n",
    "        mpf.plot(mpfdf,\n",
    "            title=chart_title,\n",
    "            type=self.mpfchart[\"type\"],\n",
    "            style=self.mpfchart[\"style\"],\n",
    "            datetime_format=\"%-m/%-d/%Y\",\n",
    "            volume=self.config[\"volume\"],\n",
    "            figsize=self.mpfchart[\"figsize\"],\n",
    "            tight_layout=self.mpfchart[\"tight_layout\"],\n",
    "            scale_padding=self.mpfchart[\"scale_padding\"],\n",
    "            panel_ratios=self.mpfchart[\"plot_ratios\"], # This key needs to be update above if adding more panels\n",
    "            xrotation=self.mpfchart[\"xrotation\"],\n",
    "            update_width_config=self.mpfchart[\"width_config\"],\n",
    "            show_nontrading=self.mpfchart[\"non_trading\"],\n",
    "            vlines=vlines_,\n",
    "            addplot=taplots\n",
    "        )\n",
    "        \n",
    "        self._attribution()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Charting Example\n",
    "#### Play with the parameters to see different charts and results\n",
    "* This is an example chart so it's not perfect. Enough to get started with common and uncommon plots.\n",
    "* There is a maximum of 10 Panels. In this example, panels 0 and 1 are reserved for Price and Volume respectively.\n",
    "    * "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[i] Loaded SPY(7149, 34)\n",
      "[+] Strategy: Common Price and Volume SMAs\n",
      "[i] Indicator arguments: {'append': True}\n",
      "[i] Multiprocessing 5 indicators with 7 chunks and 8/8 cpus.\n",
      "[i] Total indicators: 5\n",
      "[i] Columns added: 5\n",
      "[i] Last Run: Saturday June 19, 2021, NYSE: 8:05:53, Local: 12:05:53 PDT, Day 170/365 (47.00%)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 256884 characters]\n",
      "text/plain": [
       "<Figure size 1200x1000 with 12 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Pandas v: 1.2.4 [pip install pandas] https://github.com/pandas-dev/pandas\n",
      "Data from AlphaVantage v: 1.0.19 [pip install alphaVantage-api] http://www.alphavantage.co https://github.com/twopirllc/AlphaVantageAPI\n",
      "Technical Analysis with Pandas TA v: 0.2.89b0 [pip install pandas_ta] https://github.com/twopirllc/pandas-ta\n",
      "Charts by Matplotlib Finance v: 0.12.7a12 [pip install mplfinance] https://github.com/matplotlib/mplfinance\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<__main__.Chart at 0x130ba8790>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Used for example Trend Return Long Trend Below\n",
    "macd_ = ta.macd(closedf)\n",
    "macdh = macd_[macd_.columns[1]]\n",
    "\n",
    "Chart(df,\n",
    "    # style: which mplfinance chart style to use. Added \"random\" as an option.\n",
    "    # rpad: how many bars to leave empty on the right of the chart\n",
    "    style=\"yahoo\", title=ticker, last=recent_bars(df), rpad=10,\n",
    "    \n",
    "    # Overlap Indicators\n",
    "    linreg=True, midpoint=False, ohlc4=False, archermas=True,\n",
    "    \n",
    "    # Example Indicators with default parameters\n",
    "    volume=True, rsi=True, clr=False, macd=True, zscore=False, squeeze=False, lazybear=False,\n",
    "\n",
    "    # Archer OBV and OBV MAs (https://www.tradingview.com/script/Co1ksara-Trade-Archer-On-balance-Volume-Moving-Averages-v1/)\n",
    "    archerobv=False,\n",
    "\n",
    "    # Create trends and see their returns\n",
    "    tsignals=True,\n",
    "    # Example Trends or create your own. Trend must yield Booleans\n",
    "    long_trend=ta.sma(closedf,10) > ta.sma(closedf,20), # trend: sma(close,10) > sma(close,20) [Default Example]\n",
    "#     long_trend=closedf > ta.ema(closedf,5), # trend: close > ema(close,5)\n",
    "#     long_trend=ta.sma(closedf,10) > ta.ema(closedf,50), # trend: sma(close,10) > ema(close,50)\n",
    "#     long_trend=ta.increasing(ta.ema(closedf), 10), # trend: increasing(ema, 10)\n",
    "#     long_trend=macdh > 0, # trend: macd hist > 0\n",
    "#     long_trend=macd_[macd_.columns[0]] > macd_[macd_.columns[-1]], # trend: macd > macd signal\n",
    "#     long_trend=ta.increasing(ta.sma(ta.rsi(closedf), 10), 5, asint=False), # trend: rising sma(rsi, 10) for the previous 5 periods\n",
    "#     long_trend=ta.squeeze(highdf, lowdf, closedf, lazybear=True, detailed=True).SQZ_PINC > 0,\n",
    "#     long_trend=ta.amat(closedf, 50, 200, mamode=\"sma\").iloc[:,0], # trend: amat(50, 200) long signal using sma\n",
    "    show_nontrading=False, # Intraday use if needed\n",
    "    verbose=True, # More detail\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Indicator Examples\n",
    "* Examples of simple and complex indicators.  Most indicators return a Series, while a few return DataFrames.\n",
    "* All indicators can be called one of three ways. Either way, they return the result.\n",
    "\n",
    "### Three ways to use pandas_ta\n",
    "1. Stand Alone like TA-Lib  ta.**indicator**(*kwargs*).\n",
    "2. As a DataFrame Extension like df.ta.**indicator**(*kwargs*).  Where df is a DataFrame with columns named \"open\", \"high\", \"low\", \"close, \"volume\" for simplicity.\n",
    "3. Similar to #2, but by calling: df.ta(kind=\"**indicator**\", *kwargs*)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Cumulative Log Return"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<AxesSubplot:title={'center':'SPY: CUMLOGRET_1 from 2020-06-19 00:00:00 to 2021-06-18 00:00:00 (252)'}, xlabel='date'>"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 74848 characters]\n",
      "text/plain": [
       "<Figure size 1600x325 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "clr_ma_length = 8\n",
    "clrdf = df.ta.log_return(cumulative=True, append=True)\n",
    "clrmadf = ta.ema(clrdf, length=clr_ma_length)\n",
    "clrxdf = pd.DataFrame({f\"{clrdf.name}\": clrdf, f\"{clrmadf.name}({clrdf.name})\": clrmadf})\n",
    "clrxdf.tail(recent_bars(df)).plot(figsize=ind_size, color=colors(\"BkBl\"), linewidth=1, title=ctitle(clrdf.name, ticker=ticker, length=recent_bars(df)), grid=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### MACD"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.lines.Line2D at 0x132f609d0>"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 123120 characters]\n",
      "text/plain": [
       "<Figure size 1600x325 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "macddf = df.ta.macd(fast=8, slow=21, signal=9, min_periods=None, append=True)\n",
    "macddf[[macddf.columns[0], macddf.columns[2]]].tail(recent_bars(df)).plot(figsize=(16, 2), color=colors(\"BkBl\"), linewidth=1.3)\n",
    "macddf[macddf.columns[1]].tail(recent_bars(df)).plot.area(figsize=ind_size, stacked=False, color=[\"silver\"], linewidth=1, title=ctitle(macddf.name, ticker=ticker, length=recent_bars(df)), grid=True).axhline(y=0, color=\"black\", lw=1.1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ZScore"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.lines.Line2D at 0x132ec7820>"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 73904 characters]\n",
      "text/plain": [
       "<Figure size 1600x325 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "zscoredf = df.ta.zscore(length=30, append=True)\n",
    "zcolors = [\"darkgreen\", \"green\", \"silver\", \"silver\", \"red\", \"maroon\", \"black\"]\n",
    "zcols = df[[\"-4\", \"-3\", \"-2\", \"2\", \"3\", \"4\", zscoredf.name]].tail(recent_bars(df))\n",
    "zcols.plot(figsize=ind_size, color=zcolors, linewidth=1.2, title=ctitle(zscoredf.name, ticker=ticker, length=recent_bars(df)), grid=True).axhline(y=0, color=\"black\", lw=1.1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.lines.Line2D at 0x13241e280>"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 86928 characters]\n",
      "text/plain": [
       "<Figure size 1600x325 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Now Volume Z Score\n",
    "zvscoredf = df.ta.zscore(close=\"volume\", length=30, prefix=\"VOL\", append=True)\n",
    "zcolors = [\"darkgreen\", \"green\", \"silver\", \"silver\", \"red\", \"maroon\", \"black\"]\n",
    "zvcols = df[[\"-4\", \"-3\", \"-2\", \"2\", \"3\", \"4\", zvscoredf.name]].tail(recent_bars(df))\n",
    "zvcols.plot(figsize=ind_size, color=zcolors, linewidth=1.2, title=ctitle(zvscoredf.name, ticker=ticker, length=recent_bars(df)), grid=True).axhline(y=0, color=\"black\", lw=1.1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# New Features"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Squeeze Indicator (John Carter and Lazybear Versions)\n",
    "Squeeze Indicator (__squeeze__)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "# help(ta.squeeze)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 187572 characters]\n",
      "text/plain": [
       "<Figure size 1200x1000 with 8 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Pandas v: 1.2.4 [pip install pandas] https://github.com/pandas-dev/pandas\n",
      "Data from AlphaVantage v: 1.0.19 [pip install alphaVantage-api] http://www.alphavantage.co https://github.com/twopirllc/AlphaVantageAPI\n",
      "Technical Analysis with Pandas TA v: 0.2.89b0 [pip install pandas_ta] https://github.com/twopirllc/pandas-ta\n",
      "Charts by Matplotlib Finance v: 0.12.7a12 [pip install mplfinance] https://github.com/matplotlib/mplfinance\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<__main__.Chart at 0x131b6a2e0>"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Chart(df, style=\"yahoo\", title=ticker, verbose=False,\n",
    "    last=recent_bars(df), rpad=10, clr=True, squeeze=True,\n",
    "    show_nontrading=False, # Intraday use if needed\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Lazybear's TradingView Squeeze"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 185112 characters]\n",
      "text/plain": [
       "<Figure size 1200x1000 with 8 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Pandas v: 1.2.4 [pip install pandas] https://github.com/pandas-dev/pandas\n",
      "Data from AlphaVantage v: 1.0.19 [pip install alphaVantage-api] http://www.alphavantage.co https://github.com/twopirllc/AlphaVantageAPI\n",
      "Technical Analysis with Pandas TA v: 0.2.89b0 [pip install pandas_ta] https://github.com/twopirllc/pandas-ta\n",
      "Charts by Matplotlib Finance v: 0.12.7a12 [pip install mplfinance] https://github.com/matplotlib/mplfinance\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<__main__.Chart at 0x1326be430>"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Chart(df, style=\"yahoo\", title=ticker, verbose=False,\n",
    "    last=recent_bars(df), rpad=10, clr=True, squeeze=True, lazybear=True,\n",
    "    show_nontrading=False, # Intraday use if needed\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Archer Moving Averages Trends\n",
    "Archer Moving Average Trends (__amat__) returns the long and short run trends of fast and slow moving averages.\n",
    "* The _pink_ background, on the Price chart, is when Archer MAs are bearish. Conversely, a _white_ background is bullish"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 169028 characters]\n",
      "text/plain": [
       "<Figure size 1200x1000 with 6 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Pandas v: 1.2.4 [pip install pandas] https://github.com/pandas-dev/pandas\n",
      "Data from AlphaVantage v: 1.0.19 [pip install alphaVantage-api] http://www.alphavantage.co https://github.com/twopirllc/AlphaVantageAPI\n",
      "Technical Analysis with Pandas TA v: 0.2.89b0 [pip install pandas_ta] https://github.com/twopirllc/pandas-ta\n",
      "Charts by Matplotlib Finance v: 0.12.7a12 [pip install mplfinance] https://github.com/matplotlib/mplfinance\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<__main__.Chart at 0x132ccd460>"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Chart(df, style=\"yahoo\", title=ticker, verbose=False,\n",
    "    last=recent_bars(df), rpad=10,\n",
    "    volume=True, midpoint=False, ohlc4=False,\n",
    "    rsi=False, clr=True, macd=False, zscore=False, squeeze=False, lazybear=False,\n",
    "    archermas=True, archerobv=False,\n",
    "    show_nontrading=False, # Intraday use if needed\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Archer On Balance Volume\n",
    "Archer On Balance Volume (__aobv__) returns a DataFrame of OBV, OBV min and max, fast and slow MAs of OBV, and the long and short run trends of the two OBV MAs.\n",
    "* On the chart below, only **OBV**, **OBV min**, _fast_ and _slow_ **OBV MAs**.\n",
    "* Not on the chart are: **OBV LR** and **OBV SR** trends."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 180200 characters]\n",
      "text/plain": [
       "<Figure size 1200x1000 with 8 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Pandas v: 1.2.4 [pip install pandas] https://github.com/pandas-dev/pandas\n",
      "Data from AlphaVantage v: 1.0.19 [pip install alphaVantage-api] http://www.alphavantage.co https://github.com/twopirllc/AlphaVantageAPI\n",
      "Technical Analysis with Pandas TA v: 0.2.89b0 [pip install pandas_ta] https://github.com/twopirllc/pandas-ta\n",
      "Charts by Matplotlib Finance v: 0.12.7a12 [pip install mplfinance] https://github.com/matplotlib/mplfinance\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<__main__.Chart at 0x131c38a60>"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Chart(df, style=\"yahoo\", title=ticker, verbose=False,\n",
    "    last=recent_bars(df), rpad=10,\n",
    "    volume=True, midpoint=False, ohlc4=False,\n",
    "    rsi=False, clr=True, macd=False, zscore=False, squeeze=False, lazybear=False,\n",
    "    archermas=False, archerobv=True,\n",
    "    show_nontrading=False, # Intraday use if needed\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Disclaimer\n",
    "* All investments involve risk, and the past performance of a security, industry, sector, market, financial product, trading strategy, or individual’s trading does not guarantee future results or returns. Investors are fully responsible for any investment decisions they make. Such decisions should be based solely on an evaluation of their financial circumstances, investment objectives, risk tolerance, and liquidity needs.\n",
    "\n",
    "* Any opinions, news, research, analyses, prices, or other information offered is provided as general market commentary, and does not constitute investment advice. I will not accept liability for any loss or damage, including without limitation any loss of profit, which may arise directly or indirectly from use of or reliance on such information."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
