{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Bar data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<IB connected to 127.0.0.1:7497 clientId=14>"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from ib_insync import *\n",
    "util.startLoop()\n",
    "\n",
    "ib = IB()\n",
    "ib.connect('127.0.0.1', 7497, clientId=14)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Historical data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To get the earliest date of available bar data the \"head timestamp\" can be requested:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "datetime.datetime(2010, 6, 29, 8, 0)"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "contract = Stock('TSLA', 'SMART', 'USD')\n",
    "\n",
    "ib.reqHeadTimeStamp(contract, whatToShow='TRADES', useRTH=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To request hourly data of the last 60 trading days:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "bars = ib.reqHistoricalData(\n",
    "        contract,\n",
    "        endDateTime='',\n",
    "        durationStr='60 D',\n",
    "        barSizeSetting='1 hour',\n",
    "        whatToShow='TRADES',\n",
    "        useRTH=True,\n",
    "        formatDate=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "BarData(date=datetime.datetime(2019, 10, 4, 15, 30), open=231.82, high=234.78, low=230.29, close=233.06, volume=12066, average=232.914, barCount=5981)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bars[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Convert the list of bars to a data frame and print the first and last rows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "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>date</th>\n",
       "      <th>open</th>\n",
       "      <th>high</th>\n",
       "      <th>low</th>\n",
       "      <th>close</th>\n",
       "      <th>volume</th>\n",
       "      <th>average</th>\n",
       "      <th>barCount</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>2019-10-04 15:30:00</td>\n",
       "      <td>231.82</td>\n",
       "      <td>234.78</td>\n",
       "      <td>230.29</td>\n",
       "      <td>233.06</td>\n",
       "      <td>12066</td>\n",
       "      <td>232.914</td>\n",
       "      <td>5981</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2019-10-04 16:00:00</td>\n",
       "      <td>233.02</td>\n",
       "      <td>233.19</td>\n",
       "      <td>228.07</td>\n",
       "      <td>228.69</td>\n",
       "      <td>15847</td>\n",
       "      <td>229.846</td>\n",
       "      <td>7664</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>2019-10-04 17:00:00</td>\n",
       "      <td>228.62</td>\n",
       "      <td>230.87</td>\n",
       "      <td>228.30</td>\n",
       "      <td>230.56</td>\n",
       "      <td>8396</td>\n",
       "      <td>229.421</td>\n",
       "      <td>4324</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>2019-10-04 18:00:00</td>\n",
       "      <td>230.56</td>\n",
       "      <td>231.49</td>\n",
       "      <td>230.28</td>\n",
       "      <td>230.85</td>\n",
       "      <td>7069</td>\n",
       "      <td>230.899</td>\n",
       "      <td>3605</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>2019-10-04 19:00:00</td>\n",
       "      <td>230.84</td>\n",
       "      <td>231.48</td>\n",
       "      <td>230.04</td>\n",
       "      <td>231.00</td>\n",
       "      <td>3518</td>\n",
       "      <td>230.765</td>\n",
       "      <td>2125</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                 date    open    high     low   close  volume  average  \\\n",
       "0 2019-10-04 15:30:00  231.82  234.78  230.29  233.06   12066  232.914   \n",
       "1 2019-10-04 16:00:00  233.02  233.19  228.07  228.69   15847  229.846   \n",
       "2 2019-10-04 17:00:00  228.62  230.87  228.30  230.56    8396  229.421   \n",
       "3 2019-10-04 18:00:00  230.56  231.49  230.28  230.85    7069  230.899   \n",
       "4 2019-10-04 19:00:00  230.84  231.48  230.04  231.00    3518  230.765   \n",
       "\n",
       "   barCount  \n",
       "0      5981  \n",
       "1      7664  \n",
       "2      4324  \n",
       "3      3605  \n",
       "4      2125  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "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>date</th>\n",
       "      <th>open</th>\n",
       "      <th>high</th>\n",
       "      <th>low</th>\n",
       "      <th>close</th>\n",
       "      <th>volume</th>\n",
       "      <th>average</th>\n",
       "      <th>barCount</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>409</th>\n",
       "      <td>2019-12-30 17:00:00</td>\n",
       "      <td>413.03</td>\n",
       "      <td>421.06</td>\n",
       "      <td>412.61</td>\n",
       "      <td>419.18</td>\n",
       "      <td>14920</td>\n",
       "      <td>416.886</td>\n",
       "      <td>8149</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>410</th>\n",
       "      <td>2019-12-30 18:00:00</td>\n",
       "      <td>419.18</td>\n",
       "      <td>420.45</td>\n",
       "      <td>417.32</td>\n",
       "      <td>418.65</td>\n",
       "      <td>7629</td>\n",
       "      <td>419.017</td>\n",
       "      <td>4769</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>411</th>\n",
       "      <td>2019-12-30 19:00:00</td>\n",
       "      <td>418.70</td>\n",
       "      <td>420.78</td>\n",
       "      <td>416.13</td>\n",
       "      <td>416.42</td>\n",
       "      <td>7476</td>\n",
       "      <td>418.900</td>\n",
       "      <td>3883</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>412</th>\n",
       "      <td>2019-12-30 20:00:00</td>\n",
       "      <td>416.41</td>\n",
       "      <td>416.78</td>\n",
       "      <td>413.51</td>\n",
       "      <td>414.90</td>\n",
       "      <td>6936</td>\n",
       "      <td>415.059</td>\n",
       "      <td>3700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>413</th>\n",
       "      <td>2019-12-30 21:00:00</td>\n",
       "      <td>415.00</td>\n",
       "      <td>415.00</td>\n",
       "      <td>413.00</td>\n",
       "      <td>414.62</td>\n",
       "      <td>9204</td>\n",
       "      <td>414.130</td>\n",
       "      <td>5979</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                   date    open    high     low   close  volume  average  \\\n",
       "409 2019-12-30 17:00:00  413.03  421.06  412.61  419.18   14920  416.886   \n",
       "410 2019-12-30 18:00:00  419.18  420.45  417.32  418.65    7629  419.017   \n",
       "411 2019-12-30 19:00:00  418.70  420.78  416.13  416.42    7476  418.900   \n",
       "412 2019-12-30 20:00:00  416.41  416.78  413.51  414.90    6936  415.059   \n",
       "413 2019-12-30 21:00:00  415.00  415.00  413.00  414.62    9204  414.130   \n",
       "\n",
       "     barCount  \n",
       "409      8149  \n",
       "410      4769  \n",
       "411      3883  \n",
       "412      3700  \n",
       "413      5979  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "df = util.df(bars)\n",
    "\n",
    "display(df.head())\n",
    "display(df.tail())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Instruct the notebook to draw plot graphics inline:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Plot the close data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 19500 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "df.plot(y='close');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There is also a utility function to plot bars as a candlestick plot. It can accept either a DataFrame or a list of bars. Here it will print the last 100 bars:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 12316 characters]\n",
      "text/plain": [
       "<Figure size 720x432 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "util.barplot(bars[-100:], title=contract.symbol);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Historical data with realtime updates\n",
    "\n",
    "A new feature of the API is to get live updates for historical bars. This is done by setting `endDateTime` to an empty string and the `keepUpToDate` parameter to `True`.\n",
    "\n",
    "Let's get some bars with an keepUpToDate subscription:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "contract = Forex('EURUSD')\n",
    "\n",
    "bars = ib.reqHistoricalData(\n",
    "        contract,\n",
    "        endDateTime='',\n",
    "        durationStr='900 S',\n",
    "        barSizeSetting='10 secs',\n",
    "        whatToShow='MIDPOINT',\n",
    "        useRTH=True,\n",
    "        formatDate=1,\n",
    "        keepUpToDate=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Replot for every change of the last bar:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 10704 characters]\n",
      "text/plain": [
       "<Figure size 720x432 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 10704 characters]\n",
      "text/plain": [
       "<Figure size 720x432 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, clear_output\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def onBarUpdate(bars, hasNewBar):\n",
    "    plt.close()\n",
    "    plot = util.barplot(bars)\n",
    "    clear_output(wait=True)\n",
    "    display(plot)\n",
    "\n",
    "bars.updateEvent += onBarUpdate\n",
    "\n",
    "ib.sleep(10)\n",
    "ib.cancelHistoricalData(bars)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Realtime bars\n",
    "------------------\n",
    "\n",
    "With ``reqRealTimeBars`` a subscription is started that sends a new bar every 5 seconds.\n",
    "\n",
    "First we'll set up a event handler for bar updates:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def onBarUpdate(bars, hasNewBar):\n",
    "    print(bars[-1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then do the real request and connect the event handler,"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "bars = ib.reqRealTimeBars(contract, 5, 'MIDPOINT', False)\n",
    "bars.updateEvent += onBarUpdate"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "let it run for half a minute and then cancel the realtime bars."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Error 162, reqId 5: Historical Market Data Service error message:API historical data query cancelled: 5\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RealTimeBar(time=datetime.datetime(2019, 12, 31, 12, 27, 5, tzinfo=datetime.timezone.utc), endTime=-1, open_=1.122925, high=1.122975, low=1.122925, close=1.122975, volume=-1, wap=-1.0, count=-1)\n",
      "RealTimeBar(time=datetime.datetime(2019, 12, 31, 12, 27, 10, tzinfo=datetime.timezone.utc), endTime=-1, open_=1.122975, high=1.122975, low=1.122975, close=1.122975, volume=-1, wap=-1.0, count=-1)\n",
      "RealTimeBar(time=datetime.datetime(2019, 12, 31, 12, 27, 15, tzinfo=datetime.timezone.utc), endTime=-1, open_=1.122975, high=1.122975, low=1.122975, close=1.122975, volume=-1, wap=-1.0, count=-1)\n",
      "RealTimeBar(time=datetime.datetime(2019, 12, 31, 12, 27, 20, tzinfo=datetime.timezone.utc), endTime=-1, open_=1.122975, high=1.123025, low=1.122975, close=1.123025, volume=-1, wap=-1.0, count=-1)\n",
      "RealTimeBar(time=datetime.datetime(2019, 12, 31, 12, 27, 25, tzinfo=datetime.timezone.utc), endTime=-1, open_=1.123025, high=1.123025, low=1.122975, close=1.122975, volume=-1, wap=-1.0, count=-1)\n",
      "RealTimeBar(time=datetime.datetime(2019, 12, 31, 12, 27, 30, tzinfo=datetime.timezone.utc), endTime=-1, open_=1.122975, high=1.122975, low=1.122975, close=1.122975, volume=-1, wap=-1.0, count=-1)\n"
     ]
    }
   ],
   "source": [
    "ib.sleep(30)\n",
    "ib.cancelRealTimeBars(bars)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The advantage of reqRealTimeBars is that it behaves more robust when the connection to the IB server farms is interrupted. After the connection is restored, the bars from during the network outage will be backfilled and the live bars will resume.\n",
    "\n",
    "reqHistoricalData + keepUpToDate will, at the moment of writing, leave the whole API inoperable after a network interruption."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "ib.disconnect()"
   ]
  },
  {
   "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.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
