{
 "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.3.63b0\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 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.3.63b0\n",
      "\n",
      "Indicators and Utilities [148]:\n",
      "    aberration, accbands, ad, adosc, adx, alligator, alma, amat, ao, aobv, apo, aroon, atr, atrts, bbands, bias, bop, brar, cci, cdl_pattern, cdl_z, cfo, cg, chop, cksp, cmf, cmo, coppock, cti, cube, decay, decreasing, dema, dm, donchian, dpo, ebsw, efi, ema, entropy, eom, er, eri, fisher, fwma, ha, hilo, hl2, hlc3, hma, hwc, hwma, ichimoku, ifisher, increasing, inertia, jma, kama, kc, kdj, kst, kurtosis, kvo, linreg, log_return, long_run, macd, mad, mama, 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, reflex, remap, rma, roc, rsi, rsx, rvgi, rvi, short_run, sinwma, skew, slope, sma, smi, smma, squeeze, squeeze_pro, ssf, ssf3, stc, stdev, stoch, stochf, stochrsi, supertrend, swma, t3, td_seq, tema, thermo, tos_stdevall, trendflex, trima, trix, true_range, tsi, tsignals, ttm_trend, ui, uo, variance, vhf, vidya, vortex, vwap, vwma, wb_tsv, wcp, willr, wma, xsignals, zlma, zscore\n",
      "\n",
      "Candle Patterns [62]:\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",
      "\n",
      "Total Candles, Indicators and Utilities: 210\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: pandas.core.series.Series, length: Union[int, numpy.integer] = None, talib: bool = None, presma: bool = None, offset: Union[int, numpy.integer] = None, **kwargs: Optional[dict]) -> pandas.core.series.Series\n",
      "    Exponential Moving Average (EMA)\n",
      "    \n",
      "    The Exponential Moving Average is a more responsive moving average\n",
      "    compared to the Simple Moving Average (SMA). The weights are determined\n",
      "    by alpha which is proportional to it's length.  There are several\n",
      "    different methods of calculating EMA. One method uses just the standard\n",
      "    definition of EMA and another uses the SMA to generate the initial value\n",
      "    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",
      "    Args:\n",
      "        close (pd.Series): Series of 'close's\n",
      "        length (int): It's period. Default: 10\n",
      "        talib (bool): If TA Lib is installed and talib is True, Returns\n",
      "            the TA Lib version. Default: True\n",
      "        presma (bool, optional): If True, uses SMA for initial value like\n",
      "            TA Lib. Default: True\n",
      "        offset (int): How many periods to offset the result. Default: 0\n",
      "    \n",
      "    Kwargs:\n",
      "        adjust (bool, optional): Default: False\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": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "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": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# help(e.ta.ticker)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "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                                                     412.07 | 1.3000%\n",
      "\n",
      "\n",
      "\n",
      "====  Price Information    =====================================================\n",
      "Open High Low | Close                    423.5900  423.5900  411.2100 | 412.0000\n",
      "HL2 | HLC3 | OHLC4 | C - OHLC4             418.5400, 416.3600, 418.1675, -6.1675\n",
      "Change (%)                                                   -15.8100 (-3.6956%)\n",
      "Bid | Ask | Spread                        413.35 x 1400 | 413.45 x 4000 | 0.1000\n",
      "Volume | Market | Avg Vol (10Day)       \n",
      "                           145,491,088 | 145,491,088 | 105,112,352 (102,313,060)\n",
      "\n",
      "52Wk Range (% from 52Wk Low)                    404 - 479.98 : 75.9800 (1.9802%)\n",
      "SMA 50 | SMA 200                                             437.1890 | 448.1483\n",
      "Avg. Return 3Yr | 5Yr                                        15.2500% | 14.4100%\n",
      "\n",
      "====  Dividends / Splits   =====================================================\n",
      "Trailing Annual Dividend Rate | Yield                            5.662 | 1.3235%\n",
      "\n",
      "\n",
      "Stock Splits (Last 5 of 118):\n",
      "Date   2022-03-18  2021-12-17  2021-09-17  2021-06-18  2021-03-19\n",
      "Ratio       1.366       1.633       1.428       1.376       1.278\n",
      "[+] yf | SPY(7367, 7): 3189.1786 ms (3.1892 s)\n"
     ]
    }
   ],
   "source": [
    "# Recent Data\n",
    "ticker = \"BTC-USD\"\n",
    "ticker = \"SPY\"\n",
    "df = e.ta.ticker(ticker, kind=\"info\", timed=True)\n",
    "recent_startdate = df.tail(recent_bars(df)).index[0]\n",
    "recent_enddate = df.tail(recent_bars(df)).index[-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "From 2021-05-03 00:00:00 to 2022-04-29 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>2021-05-03</th>\n",
       "      <td>413.982163</td>\n",
       "      <td>414.386841</td>\n",
       "      <td>412.245043</td>\n",
       "      <td>412.768158</td>\n",
       "      <td>68128300</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-05-04</th>\n",
       "      <td>410.665847</td>\n",
       "      <td>411.188962</td>\n",
       "      <td>406.323003</td>\n",
       "      <td>410.221680</td>\n",
       "      <td>101591200</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-05-05</th>\n",
       "      <td>411.958809</td>\n",
       "      <td>412.205562</td>\n",
       "      <td>409.757763</td>\n",
       "      <td>410.349976</td>\n",
       "      <td>60162200</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-05-06</th>\n",
       "      <td>410.428955</td>\n",
       "      <td>413.765058</td>\n",
       "      <td>408.306886</td>\n",
       "      <td>413.626892</td>\n",
       "      <td>74321400</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2021-05-07</th>\n",
       "      <td>414.436221</td>\n",
       "      <td>417.328158</td>\n",
       "      <td>413.715692</td>\n",
       "      <td>416.637238</td>\n",
       "      <td>67733800</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                  Open        High         Low       Close     Volume  \\\n",
       "Date                                                                    \n",
       "2021-05-03  413.982163  414.386841  412.245043  412.768158   68128300   \n",
       "2021-05-04  410.665847  411.188962  406.323003  410.221680  101591200   \n",
       "2021-05-05  411.958809  412.205562  409.757763  410.349976   60162200   \n",
       "2021-05-06  410.428955  413.765058  408.306886  413.626892   74321400   \n",
       "2021-05-07  414.436221  417.328158  413.715692  416.637238   67733800   \n",
       "\n",
       "            Dividends  Stock Splits  \n",
       "Date                                 \n",
       "2021-05-03        0.0             0  \n",
       "2021-05-04        0.0             0  \n",
       "2021-05-05        0.0             0  \n",
       "2021-05-06        0.0             0  \n",
       "2021-05-07        0.0             0  "
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# print(f\"{df.name}{df.tail(recent_bars(df)).shape} from {recent_startdate} to {recent_enddate}\")\n",
    "\n",
    "print(f\"\\nFrom {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, study: ta.Study = ta.CommonStudy, *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_study(study)\n",
    "\n",
    "        # Build TA and Plot\n",
    "        self.df.ta.study(self.study, verbose=self.verbose)\n",
    "        self._plot(**kwargs)\n",
    "\n",
    "    def _validate_ta_study(self, study):\n",
    "        if study is not None or isinstance(study, ta.study):\n",
    "            self.study = study\n",
    "        elif len(self.study_ta) > 0:\n",
    "            print(f\"[+] Study: {self.study_name}\")\n",
    "        else:\n",
    "            self.study = ta.CommonStudy\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.study.name == ta.CommonStudy.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.study.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",
    "        dfmt=\"%-m/%-d/%Y\"\n",
    "        try:\n",
    "            datetime.now().strftime(dfmt)\n",
    "        except:\n",
    "            dfmt=\"%m/%d/%Y\"\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=dfmt,\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(7367, 34)\n",
      "[+] Study: Common Price and Volume SMAs\n",
      "[i] Indicator arguments: {'append': True}\n",
      "[i] No multiprocessing (cores = 0).\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[i] Progress: 100%|███████████████████████████| 5/5 [00:00<00:00, 774.71it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[i] Total indicators: 5\n",
      "[i] Columns added: 5\n",
      "[i] Last Run: Sunday May 1, 2022, NYSE: 14:14:53, Local: 18:14:53 PDT, Day 121/365 (33.00%)\n",
      "tsignals\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 292688 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.3.0 [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.3.63b0 [pip install pandas_ta] https://github.com/twopirllc/pandas-ta\n",
      "Charts by Matplotlib Finance v: 0.12.7a17 [pip install mplfinance] https://github.com/matplotlib/mplfinance\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<__main__.Chart at 0x131e9c0a0>"
      ]
     },
     "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 2021-05-03 00:00:00 to 2022-04-29 00:00:00 (252)'}, xlabel='Date'>"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 96280 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 0x13420fa00>"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 112792 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 0x1342ae1c0>"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 78064 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 0x1342935b0>"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 86164 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": [
    "## 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, 206408 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.3.0 [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.3.63b0 [pip install pandas_ta] https://github.com/twopirllc/pandas-ta\n",
      "Charts by Matplotlib Finance v: 0.12.7a17 [pip install mplfinance] https://github.com/matplotlib/mplfinance\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<__main__.Chart at 0x1341d29a0>"
      ]
     },
     "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, 206976 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.3.0 [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.3.63b0 [pip install pandas_ta] https://github.com/twopirllc/pandas-ta\n",
      "Charts by Matplotlib Finance v: 0.12.7a17 [pip install mplfinance] https://github.com/matplotlib/mplfinance\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<__main__.Chart at 0x1340473d0>"
      ]
     },
     "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": [
    "# 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 (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.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
