{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Basic Stock Trading"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import yfinance as yf\n",
    "import matplotlib.pyplot as plt\n",
    "import pandas as pd\n",
    "from datetime import datetime, timedelta"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [],
   "source": [
    "#define the ticker symbol\n",
    "tickerSymbol = 'JBLU'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [],
   "source": [
    "#get data on this ticker\n",
    "tickerData = yf.Ticker(tickerSymbol)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [],
   "source": [
    "#get the historical prices for this ticker\n",
    "tickerDf = tickerData.history(interval='1d', start='2019-1-1', end='2020-4-10')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [],
   "source": [
    "priceData = tickerDf.Open"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [],
   "source": [
    "priceData = priceData.asfreq(pd.infer_freq(priceData.index))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Date\n",
       "2019-01-02    15.80\n",
       "2019-01-03    16.01\n",
       "2019-01-04    16.14\n",
       "2019-01-05      NaN\n",
       "2019-01-06      NaN\n",
       "              ...  \n",
       "2020-04-04      NaN\n",
       "2020-04-05      NaN\n",
       "2020-04-06     7.82\n",
       "2020-04-07     8.96\n",
       "2020-04-08     9.03\n",
       "Freq: D, Name: Open, Length: 463, dtype: float64"
      ]
     },
     "execution_count": 92,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "priceData"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'JBLU Price Data')"
      ]
     },
     "execution_count": 93,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 28184 characters]\n",
      "text/plain": [
       "<Figure size 720x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10,4))\n",
    "plt.plot(priceData)\n",
    "for year in range(priceData.index[0].year, priceData.index[-1].year+1):\n",
    "    plt.axvline(datetime(year,1,1), color='k', linestyle='--', alpha=0.2)\n",
    "plt.title(\"%s Price Data\"%tickerSymbol, fontsize=20)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Basic Buying Protocol:\n",
    "\n",
    "### - Buy if stock increasing for $b$ consecutive days"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Basic Selling Protocols:\n",
    "\n",
    "### - Sell if stock decreasing for $s$ consecutive days (and we've made a profit)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_buying_selling_days(price_data, b, s):\n",
    "    \n",
    "    #get the percent change day after day\n",
    "    pct_change = price_data.pct_change()[1:]\n",
    "    \n",
    "    #this function checks the buying condition\n",
    "    def buying_condition(sub_series):\n",
    "        return (sub_series > 0).all()\n",
    "    \n",
    "    #this function checks the selling condition\n",
    "    def selling_condition(sub_series):\n",
    "        return (sub_series < 0).all()\n",
    "    \n",
    "    #get all buying days in the data\n",
    "    buying_days = pct_change.rolling(b).apply(buying_condition)\n",
    "    \n",
    "    #get all potential selling days in the data\n",
    "    potential_selling_days = pct_change.rolling(s).apply(selling_condition)\n",
    "    \n",
    "    #return a dictionary\n",
    "    return {'buying_days': buying_days, 'potential_selling_days': potential_selling_days}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "metadata": {},
   "outputs": [],
   "source": [
    "info_dict = get_buying_selling_days(priceData, 4, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "metadata": {},
   "outputs": [],
   "source": [
    "buying_days = info_dict['buying_days']\n",
    "potential_selling_days = info_dict['potential_selling_days']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "metadata": {},
   "outputs": [],
   "source": [
    "#create dataframe to store information\n",
    "df_stocks = pd.DataFrame(index = buying_days.index)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "metadata": {},
   "outputs": [],
   "source": [
    "#populate df with buying days, possible selling days, and price\n",
    "df_stocks['buying_day'] = (buying_days == 1)\n",
    "df_stocks['potential_selling_day'] = (potential_selling_days == 1)\n",
    "df_stocks['price'] = priceData\n",
    "\n",
    "#only keep days that are buying or possible selling days\n",
    "df_stocks = df_stocks[(df_stocks.buying_day | df_stocks.potential_selling_day)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "metadata": {},
   "outputs": [
    {
     "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>buying_day</th>\n",
       "      <th>potential_selling_day</th>\n",
       "      <th>price</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2019-01-09</th>\n",
       "      <td>False</td>\n",
       "      <td>True</td>\n",
       "      <td>16.84</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-01-10</th>\n",
       "      <td>False</td>\n",
       "      <td>True</td>\n",
       "      <td>16.16</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-01-17</th>\n",
       "      <td>False</td>\n",
       "      <td>True</td>\n",
       "      <td>17.32</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-01-22</th>\n",
       "      <td>False</td>\n",
       "      <td>True</td>\n",
       "      <td>17.56</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2019-01-23</th>\n",
       "      <td>False</td>\n",
       "      <td>True</td>\n",
       "      <td>17.42</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "            buying_day  potential_selling_day  price\n",
       "Date                                                \n",
       "2019-01-09       False                   True  16.84\n",
       "2019-01-10       False                   True  16.16\n",
       "2019-01-17       False                   True  17.32\n",
       "2019-01-22       False                   True  17.56\n",
       "2019-01-23       False                   True  17.42"
      ]
     },
     "execution_count": 109,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_stocks.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 110,
   "metadata": {},
   "outputs": [],
   "source": [
    "def check_cumulative_percent_change(price_data, buy_date, potential_sell_date):\n",
    "    \"\"\"\n",
    "    This helper function will check if the cumulative percent change\n",
    "    between a buying and potential selling day yields overall growth\n",
    "    \"\"\"\n",
    "    \n",
    "    #get the percent change day after day\n",
    "    pct_change = price_data.pct_change()[1:]\n",
    "    \n",
    "    sub_series = 1 + pct_change[buy_date + timedelta(hours=1): potential_sell_date]\n",
    "\n",
    "    return sub_series.product() > 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_investing_result(df_stocks, starting_funds, verbose=False):\n",
    "    \n",
    "    #get a copy of price data\n",
    "    price_data = df_stocks.price\n",
    "    \n",
    "    #at start, not holding any shares\n",
    "    holding = False\n",
    "    \n",
    "    #init vars\n",
    "    current_funds = starting_funds\n",
    "    current_shares = 0\n",
    "    last_buy_date = None\n",
    "    \n",
    "    #init dict of buying and selling dates\n",
    "    events_list = []\n",
    "    \n",
    "    #for each buying day and potential selling day...\n",
    "    for date,data in df_stocks.iterrows():\n",
    "        \n",
    "        #if not currently holding shares, and this is a buying day...\n",
    "        if (not holding) and data.buying_day:\n",
    "            \n",
    "            #calculate the number of shares we can buy\n",
    "            num_shares_to_buy = int(current_funds / data.price)\n",
    "            \n",
    "            #update number of shares\n",
    "            current_shares += num_shares_to_buy\n",
    "            \n",
    "            #decrease current funds\n",
    "            current_funds -= num_shares_to_buy * data.price\n",
    "            \n",
    "            #set last buy date\n",
    "            last_buy_date = date\n",
    "            events_list.append(('b', date))\n",
    "            \n",
    "            #we are now holding shares\n",
    "            holding = True\n",
    "            \n",
    "            if verbose:\n",
    "                print('Bought %s shares at $%s on %s totaling $%s'%(num_shares_to_buy, data.price, date.date(), round(num_shares_to_buy*data.price,2)))\n",
    "        \n",
    "        #if you are holding shares, and this is a potential selling day...\n",
    "        elif holding and data.potential_selling_day:\n",
    "            \n",
    "            #check to make sure we're making a profit\n",
    "            if check_cumulative_percent_change(price_data, last_buy_date, date):\n",
    "                #add to our current funds\n",
    "                current_funds += current_shares * data.price\n",
    "                \n",
    "                if verbose:\n",
    "                    print('Sold %s shares at $%s on %s totaling $%s'%(current_shares, data.price, date.date(), round(num_shares_to_buy*data.price,2)))\n",
    "                    print('--------------------------------------')\n",
    "                    \n",
    "                #reset current shares\n",
    "                current_shares = 0\n",
    "                \n",
    "                #we are no longer holding shares\n",
    "                holding = False\n",
    "                \n",
    "                events_list.append(('s', date))\n",
    "                \n",
    "    #get the stock price at the end of the time span\n",
    "    final_stock_price = price_data[-1]\n",
    "        \n",
    "    #get the final total value of all assets (funds + stock value)\n",
    "    final_value = current_funds + final_stock_price * current_shares\n",
    "    \n",
    "    #return the percent change in value\n",
    "    return round((final_value - starting_funds) / starting_funds,2), events_list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 112,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Bought 535 shares at $18.66 on 2019-05-02 totaling $9983.1\n",
      "Sold 535 shares at $19.38 on 2019-06-17 totaling $10368.3\n",
      "--------------------------------------\n",
      "Bought 532 shares at $19.49 on 2019-07-26 totaling $10368.68\n",
      "Sold 532 shares at $19.56 on 2019-11-08 totaling $10405.92\n",
      "--------------------------------------\n",
      "Bought 493 shares at $21.1 on 2020-01-24 totaling $10402.3\n",
      "Sold 493 shares at $21.19 on 2020-02-18 totaling $10446.67\n",
      "--------------------------------------\n"
     ]
    }
   ],
   "source": [
    "percent_change, events_list = get_investing_result(df_stocks, 10000, True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 113,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.05\n"
     ]
    }
   ],
   "source": [
    "print(percent_change)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(7, 22)"
      ]
     },
     "execution_count": 114,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 31208 characters]\n",
      "text/plain": [
       "<Figure size 720x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10,4))\n",
    "plt.plot(priceData)\n",
    "\n",
    "y_lims = (int(priceData.min()*.95), int(priceData.max()*1.05))\n",
    "shaded_y_lims = int(priceData.min()*.5), int(priceData.max()*1.5)\n",
    "\n",
    "for idx, event in enumerate(events_list):\n",
    "    color = 'red' if event[0] == 'b' else 'blue'\n",
    "    plt.axvline(event[1], color=color, linestyle='--', alpha=0.4)\n",
    "    if event[0] == 's':\n",
    "        plt.fill_betweenx(range(*shaded_y_lims), \n",
    "                          event[1], events_list[idx-1][1], color='k', alpha=0.1)\n",
    "\n",
    "plt.title(\"%s Price Data\"%tickerSymbol, fontsize=20)\n",
    "plt.ylim(*y_lims)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
