{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tick data\n", "\n", "For optimum results this notebook should be run during the Forex trading session." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "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=15)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Streaming tick data\n", "\n", "Create some Forex contracts:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "contracts = [Forex(pair) for pair in ('EURUSD', 'USDJPY', 'GBPUSD', 'USDCHF', 'USDCAD', 'AUDUSD')]\n", "ib.qualifyContracts(*contracts)\n", "\n", "eurusd = contracts[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Request streaming ticks for them:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "for contract in contracts:\n", " ib.reqMktData(contract, '', False, False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wait a few seconds for the tickers to get filled." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Ticker(contract=Forex('EURUSD', conId=12087792, exchange='IDEALPRO', localSymbol='EUR.USD', tradingClass='EUR.USD'), time=datetime.datetime(2019, 12, 31, 17, 5, 2, 127038, tzinfo=datetime.timezone.utc), bid=1.12245, bidSize=10700000, ask=1.1225, askSize=2000000, high=1.1239, low=1.11985, close=1.12, halted=0.0)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ticker = ib.ticker(eurusd)\n", "ib.sleep(2)\n", "\n", "ticker" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The price of Forex ticks is always nan. To get a midpoint price use ``midpoint()`` or ``marketPrice()``.\n", "\n", "The tickers are kept live updated, try this a few times to see if the price changes:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.1224750000000001" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ticker.marketPrice()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following cell will start a 30 second loop that prints a live updated ticker table.\n", "It is updated on every ticker change." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
bidSizebidaskaskSizehighlowclose
EURUSD115000001.12251.1225510000001.12391.119851.12
USDJPY8000000108.665108.67516000000108.885108.475108.87
GBPUSD60000001.3271.32715000001.328451.31061.3111
USDCHF100000000.96770.967870000000.96980.964650.96935
USDCAD10000001.29661.2966520000001.306951.295151.3068
AUDUSD95000000.703050.703110000000.703250.699450.6995
\n", "
" ], "text/plain": [ " bidSize bid ask askSize high low close\n", "EURUSD 11500000 1.1225 1.12255 1000000 1.1239 1.11985 1.12\n", "USDJPY 8000000 108.665 108.675 16000000 108.885 108.475 108.87\n", "GBPUSD 6000000 1.327 1.3271 500000 1.32845 1.3106 1.3111\n", "USDCHF 10000000 0.9677 0.9678 7000000 0.9698 0.96465 0.96935\n", "USDCAD 1000000 1.2966 1.29665 2000000 1.30695 1.29515 1.3068\n", "AUDUSD 9500000 0.70305 0.7031 1000000 0.70325 0.69945 0.6995" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from IPython.display import display, clear_output\n", "import pandas as pd\n", "\n", "df = pd.DataFrame(\n", " index=[c.pair() for c in contracts],\n", " columns=['bidSize', 'bid', 'ask', 'askSize', 'high', 'low', 'close'])\n", "\n", "def onPendingTickers(tickers):\n", " for t in tickers:\n", " df.loc[t.contract.pair()] = (\n", " t.bidSize, t.bid, t.ask, t.askSize, t.high, t.low, t.close)\n", " clear_output(wait=True)\n", " display(df) \n", "\n", "ib.pendingTickersEvent += onPendingTickers\n", "ib.sleep(30)\n", "ib.pendingTickersEvent -= onPendingTickers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "New tick data is available in the 'ticks' attribute of the pending tickers.\n", "The tick data will be cleared before the next update." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To stop the live tick subscriptions:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "for contract in contracts:\n", " ib.cancelMktData(contract)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Tick by Tick data ###\n", "\n", "The ticks in the previous section are time-sampled by IB in order to cut on bandwidth. So with ``reqMktdData`` not every tick from the exchanges is sent. The promise of ``reqTickByTickData`` is to send every tick, just how it appears in the TWS Time & Sales window. This functionality is severly nerfed by a total of just three simultaneous subscriptions, where bid-ask ticks and sale ticks also use up a subscription each.\n", "\n", "The tick-by-tick updates are available from ``ticker.tickByTicks`` and are signalled by ``ib.pendingTickersEvent`` or ``ticker.updateEvent``." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Ticker(contract=Forex('EURUSD', conId=12087792, exchange='IDEALPRO', localSymbol='EUR.USD', tradingClass='EUR.USD'), time=datetime.datetime(2019, 12, 31, 17, 5, 35, 432737, tzinfo=datetime.timezone.utc), bid=1.1225, bidSize=11000000, ask=1.1226, askSize=11500000, prevBid=1.12255, prevBidSize=11500000, prevAsk=1.12255, prevAskSize=1000000, high=1.1239, low=1.11985, close=1.12, halted=0.0, tickByTicks=[TickByTickBidAsk(time=datetime.datetime(2019, 12, 31, 17, 5, 35, 432737, tzinfo=datetime.timezone.utc), bidPrice=1.1225, askPrice=1.12255, bidSize=11500000, askSize=1000000, tickAttribBidAsk=TickAttribBidAsk(bidPastLow=False, askPastHigh=False)), TickByTickBidAsk(time=datetime.datetime(2019, 12, 31, 17, 5, 35, 432737, tzinfo=datetime.timezone.utc), bidPrice=1.1225, askPrice=1.12255, bidSize=11000000, askSize=1000000, tickAttribBidAsk=TickAttribBidAsk(bidPastLow=False, askPastHigh=False)), TickByTickBidAsk(time=datetime.datetime(2019, 12, 31, 17, 5, 35, 432737, tzinfo=datetime.timezone.utc), bidPrice=1.1225, askPrice=1.1226, bidSize=11000000, askSize=11500000, tickAttribBidAsk=TickAttribBidAsk(bidPastLow=False, askPastHigh=False))])\n" ] } ], "source": [ "ticker = ib.reqTickByTickData(eurusd, 'BidAsk')\n", "ib.sleep(2)\n", "print(ticker)\n", "\n", "ib.cancelTickByTickData(ticker.contract, 'BidAsk')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Historical tick data\n", "\n", "Historical tick data can be fetched with a maximum of 1000 ticks at a time. Either the start time or the end time must be given, and one of them must remain empty:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "HistoricalTickBidAsk(time=datetime.datetime(2019, 12, 31, 17, 5, 34, tzinfo=datetime.timezone.utc), tickAttribBidAsk=TickAttribBidAsk(bidPastLow=False, askPastHigh=False), priceBid=1.1225, priceAsk=1.1226, sizeBid=11000000, sizeAsk=11500000)" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import datetime\n", "\n", "start = ''\n", "end = datetime.datetime.now()\n", "ticks = ib.reqHistoricalTicks(eurusd, start, end, 1000, 'BID_ASK', useRth=False)\n", "\n", "ticks[-1]" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "ib.disconnect()" ] } ], "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 }