{"id":202531,"date":"2024-02-20T17:25:43","date_gmt":"2024-02-20T22:25:43","guid":{"rendered":"https:\/\/ibkrcampus.com\/?p=202531"},"modified":"2024-02-20T19:25:47","modified_gmt":"2024-02-21T00:25:47","slug":"connecting-python-to-excel","status":"publish","type":"post","link":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/connecting-python-to-excel\/","title":{"rendered":"Connecting Python to Excel"},"content":{"rendered":"\n<p>Interactive Brokers&#8217; API Support often receive a variety of inquiries from our customers that use one of our Excel API offerings, but don\u2019t necessarily know the underlying code operations behind it. In many cases, we find that some customers are not familiar with how to manipulate the Java DDE code, or modify the C# source inherent to ActiveX or RTD releases. And while Interactive Brokers is looking to provide as many ways to implement our API as possible, not every variable can be accounted for.<\/p>\n\n\n\n<p>As such, this will be one article in a series describing how to build a customized Excel workbook using Python. The series will focus on porting our <a href=\"\/campus\/trading-course\/python-tws-api\/\">Python TWS API video series<\/a> to Excel workbooks, so much of the underlying code can be pulled directly from there before building implementations later. And while we will focus on the original series, it may shift over time to implement reader requests. So please be sure to comment on any ideas you might like to see implemented as we progress.<\/p>\n\n\n\n<p>This first article will cover requesting live market data through the API, so please be familiar with the code from our <a href=\"\/campus\/trading-lessons\/python-receiving-market-data\/\">Python API Market Data tutorial<\/a> before entering into this Excel series. <\/p>\n\n\n\n<p>Let\u2019s start by taking note of the packages we will be using throughout the article series. For this first article, we will be implementing the Interactive Brokers <strong>ibapi<\/strong> library, along with <strong>queue<\/strong>, <strong>threading<\/strong>, <strong>time<\/strong>, and <strong>xlwings<\/strong>. Users are welcome to explore more of xlwings on their own by reviewing the <a href=\"https:\/\/docs.xlwings.org\/en\/stable\/api\/index.html\">xlwings API reference<\/a>. We will also be separating our workflow into multiple files for readability, so please be aware that each file will be importing several of the files created throughout this lesson.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"h-creating-utils-py\">Creating utils.py<\/h4>\n\n\n\n<p>Let\u2019s start with creating a new Python file, utils.py. In our new file, we can add all of our imports relevant for this section of the tutorial. let\u2019s add the import for xlwings using <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">import xlwings as xw<\/code>. We will also be using the Queue object from the queue library, the Thread object from threading, and sleep from the time library. Users are also welcome to import the full library as they see fit, though for readability and runtime processing, we will only import the necessary components of these libraries.&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">import xlwings as xw\nfrom threading import Thread\nfrom queue import Queue\nfrom time import sleep\nfrom ibapi.ticktype import TickType, TickTypeEnum\nfrom ibapi.client import *\nfrom ibapi.wrapper import *<\/pre>\n\n\n\n<p>On a new line, let\u2019s create our workbook name as a global variable \u2013 I will use <code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">BN = \u201cPython_Excel.xlsx\u201d<\/code>. This will save the file to the same directory as the Python file; however, you can set an absolute path instead like <code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">'C:\\\\Users\\\\awise\\\\Desktop\\\\Python_Excel.xlsx'<\/code> to save the excel sheet to my desktop. I will also create a worksheet variable, <code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">LD = \u201cLive_Data\u201d<\/code>. This should result in the following code:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\"> BN = \u201cPython_Excel.xlsx\u201d\nLD = \u201cLive_Data\u201d<\/pre>\n\n\n\n<p>With our variables set, let\u2019s create a method to create a workbook if one does not exist. This is an optional step as users can create the workbook directly; however, this will help establish a baseline file for us to work in. To begin, we\u2019ll create a new method, createBook(), that we can use to build a fresh workbook if it doesn\u2019t exist. On a new line, let\u2019s create a variable, \u2018bk\u2019, set to a book variable, <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">bk = xw.Book()<\/code>. Next, we\u2019ll save the workbook with <code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">bk.save(BN)<\/code>. And we could end the method using <code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">bk.activate(BN)<\/code> though that will only establish our sheet as a current sheet.<\/p>\n\n\n\n<p>I will instead opt to modify our sheet to avoid some relative references. So next, I will add <code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">bk.sheets.add(name=LD)<\/code>. This will add a new sheet to our workbook based on our prior LD variable. Optionally, you can then delete the default sheet, Sheet1, using <code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">bk.sheets(\u2018Sheets\u2019).delete()<\/code>. Now we can actually end our method by saving our workbook by calling <code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">bk.save(BN) once again<\/code>. Our complete createBook() method should look like:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">def createBook():\n    bk = xw.Book()\n    bk.save(BN)\n    bk.activate(BN)\n    bk.sheets.add(name=LD)\n    bk.sheets('Sheet1').delete()\n    bk.save(BN)<\/pre>\n\n\n\n<p>Going back to the root indent level, we\u2019ll build a simple try loop to reference our file if it exists, or create the workbook if it doesn\u2019t.<\/p>\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">try:\n    xw.Book(BN)\nexcept FileNotFoundError:\n    createBook()<\/pre>\n\n\n<p>Now if we move to run our Python file, we should see the workbook created in the current directory, and the first sheet labeled as \u201cLive_Data\u201d. Closing the workbook and returning to our utils.py file, we can get to work on some of the more interesting methods. We\u2019re going to be building out some headers for our sheet; however, this will require a few prerequisite methods before we can get started.<\/p>\n\n\n\n<p>We\u2019ll start with a method to shift to the appropriate column as needed. Because Interactive Brokers tick types are centered around integer values that can be enumerated, it is best to find ways of converting an integer value to an associated column value. We\u2019ll manage this by a new letterIncr() method that takes an integer value, letter_int, as an argument and converts it to a character using the Python chr() and ord() methods. We\u2019ll assign the variable, incr_letter, to the ordered character value of an integer. It\u2019s important to increment our standard value by 2 because this will resolve Python\u2019s 0-value indexing with Excel\u2019s 1-value index, and we will skip the first column, A, as we can use that for our Symbol column manually. After calculating the column character, we can return our incr_letter variable. The resulting method should reflect the example below:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">def letterIncr(letter_int):\n    incr_letter = chr(ord('@')+letter_int+2)\n    return incr_letter<\/pre>\n\n\n\n<p>With our column assignment structure in place, let\u2019s focus on writing content into our workbook. Before writing however, we want to implement the Queue class to facilitate multithreading in our program. This will allow us to write to multiple cells simultaneously instead of updating one value at a time. This concept of concurrency and asynchronicity is further discussed in our <a href=\"\/campus\/ibkr-quant-news\/understanding-asynchronous-libraries-with-the-tws-api\/\">Understanding Asynchronous Libraries with TWS API<\/a> article.<\/p>\n\n\n\n<p>To implement threading for our workbook, we\u2019ll start by assigning the variable, q, to the Queue() class object. Now, we can create an iterator for however many threads we need. I will set my range to 50 working threads, though users may want to tweak these values depending on how many symbols they would like to handle in tandem with much their computer can withstand. Then we\u2019ll assign a new variable, t, to a thread which targets a writeToWorkbook() method along with setting the thread as a daemon. We will create the full writeToWorkbook() method momentarily. Finally, we\u2019ll start our thread, and on the root indent level, we\u2019ll call the join() method for q. The resulting code is displayed below:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">q = Queue()\n\nfor i in range(50):\n    t = Thread(\n        target=writeToWorkbook, \n        daemon=True\n      ).start()\nq.join()<\/pre>\n\n\n\n<p>Lets go ahead and create our writeToWorkbook() method. We\u2019ll begin by creating a while loop to continuously write to the sheet, as our queue will constantly be feeding data from Interactive Brokers in just a moment. Within the loop, we\u2019ll assign the variable, params, to q.get(). This will essentially capture all content sent to the queue. We\u2019ll then split params into three separate variables, book, cell, and content, so we can manipulate our request as we move along. Given we\u2019ve only received a list, we\u2019ll capture the arguments with index positions 0, 1, and 2 respectively. Finally, we\u2019ll reference xw.Book(BN) as our active Workbook, then declare the exact sheet with our book and cell within it\u2019s range to set the value. We\u2019re essentially accessing a nested reference of the workbook through xlwings\u2019 architecture. Clients may also optionally print the params variable so they can verify the sheet\u2019s values against the Python feed directly to observe latency issues. A final product for the writeToWorkbook() method is shown below:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">def writeToWorkbook():\n    while True:\n        params = q.get()\n        book = params[0]\n        cell = params[1]\n        content = params[2]\n        xw.Book(BN).sheets[book].range(cell).value = content\n        print(params)<\/pre>\n\n\n\n<p>Finally, much of our foundation is completed, and we can start working on displaying data within Excel. We can develop a simple buildHeaders() method to create our column headers. Reflecting on the work we\u2019ve done, let\u2019s put the Queue to work using <code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">q.put([LD, \u2018A1\u2019, \u2018Symbol\u2019])<\/code>. This will make cell A1 equal to the value, \u201cSymbol\u201d. We\u2019ll use this column to display which contracts we are working with. The method should currently appear as:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">def buildHeaders():\n    q.put([LD,'A1',\"Symbol\"])<\/pre>\n\n\n\n<p>While we will build this out further in a moment, we can test the current behavior to make sure cell A1 is assigning the Symbol value appropriately. At the bottom of the page, let\u2019s set the name-main idiom to our new buildHeaders() method, as shown below:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">if __name__ == \"__main__\":\n    buildHeaders()<\/pre>\n\n\n\n<p>If we save and run our file, after a moment, we should see our Python_Excel.xlsx file launch, and show \u201cSymbol\u201d in the first column of our Live_Data sheet.<\/p>\n\n\n\n<p><img decoding=\"async\" data-src=\"\/campus\/wp-content\/uploads\/sites\/2\/2024\/02\/pexcel_symbol.png\" alt=\"Python Excel sheet displaying the initial &quot;symbol&quot; value.\" width=\"525\" height=\"283\" class=\"alignnone size-full wp-image-202394 lazyload\" data-srcset=\"https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/02\/pexcel_symbol.png 525w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/02\/pexcel_symbol-300x162.png 300w\" data-sizes=\"(max-width: 525px) 100vw, 525px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 525px; aspect-ratio: 525\/283;\" \/><\/p>\n\n\n\n<h6 class=\"wp-block-heading\" id=\"h-completed-utils-py\">Completed utils.py<\/h6>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">import xlwings as xw\nfrom threading import Thread\nfrom queue import Queue\nfrom time import sleep\nfrom ibapi.ticktype import TickType, TickTypeEnum\nfrom ibapi.client import *\nfrom ibapi.wrapper import *\n\nBN = 'Python_Excel.xlsx'\nLD = 'Live_Data'\n\ndef createBook():\n    bk = xw.Book()\n    bk.save(BN)\n    bk.activate(BN)\n    bk.sheets.add(name=LD)\n    bk.sheets('Sheet1').delete()\n    bk.save(BN)\n\ndef buildHeaders():\n    q.put([LD,'A1',\"Symbol\"])\n    for i in range(9):\n        x = letterIncr(i)\n        q.put([LD,'{}1'.format(x),TickTypeEnum.toStr(i)])\n\ndef letterIncr(letter_int):\n    incr_letter = chr(ord('@')+letter_int+2)\n    return incr_letter\n\ndef writeToWorkbook():\n    while True:\n        params = q.get()\n        book = params[0]\n        cell = params[1]\n        content = params[2]\n        xw.Book(BN).sheets[book].range(cell).value = content\n        print(params)\n\nq = Queue()\n\nfor i in range(50):\n    t = Thread(\n        target=writeToWorkbook, \n        daemon=True\n      ).start()\nq.join()\n\n\ntry:\n    xw.Book(BN)\nexcept FileNotFoundError:\n    createBook()\n\nif __name__ == \"__main__\":\n    buildHeaders()<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"h-creating-livedata-py\">Creating LiveData.py<\/h4>\n\n\n\n<p>With a working utils file in place, we can start working on generating actual data in our excel sheet. Let\u2019s create a new file, LiveData.py. This is going to mirror the EWrapper portion of our reqMktData lesson in <a href=\"\/campus\/trading-lessons\/python-receiving-market-data\/\">Requesting Market Data<\/a> We can start the file by importing everything from utils with <code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">from utils import *<\/code> .That way we can carry our imports in a consolidated location along with the new utility methods we just created. Then we\u2019ll create the same TestApp class; however, we\u2019ll remove the nextValidId method and it\u2019s contents. So we should be left with the initializer, along with tickPrice and tickSize methods.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">from utils import *\n\nclass TestApp(EClient, EWrapper):\n    def __init__(self):\n        EClient.__init__(self, self)\n\n    def tickPrice(self, reqId, tickType, price, attrib):\n        print(f\"tickPrice. reqId: {reqId}, tickType: {TickTypeEnum.to_str(tickType)}, price: {price}, attribs: {attrib}\")\n    def tickSize(self, reqId, tickType, size):\n        print(f\"tickSize. reqId: {reqId}, tickType: {TickTypeEnum.to_str(tickType)}, size: {size}\")<\/pre>\n\n\n\n<p>Since we want the data to show in Excel rather than through Python, we\u2019ll need to modify our print statements accordingly. And in my case, I only want to deal with the first 9 tick types such as bid, ask, and last values, so I will add an if statement to both tickPrice and tickSize to only print data if the tickType variable is less than 9. Within that context, I\u2019ll assign a column header variable, col, using our letterIncr method from before. By passing our tickType variable, I can assign the same column variable to remain under that column. Given our whatToWrite method handles assignments at the cell level, we can use the reqId variable returned by tickPrice and tickSize to label the appropriate row. This would be handled with  <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">\"{}{}\".format(col, reqId)<\/code>. This means our column is automatically set based on the tickType, while the row is set by the contract requested. And finally, we can pass the price variable directly. While it can be passed directly as a float, maintaining the values as strings can prevent invalid formatting in Excel. I\u2019ll replicate this same structure in tickSize and the size variable. The resulting methods should appear similar to what\u2019s below:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">    def tickPrice(self, reqId: TickerId, tickType: TickType, price: float, attrib: TickAttrib,):\n      if tickType &lt; 9:\n        col = letterIncr(tickType)\n        q.put([LD,&quot;{}{}&quot;.format(col, reqId), str(price)])\n    \n    def tickSize(self, reqId: TickerId, tickType: TickType, size: float):\n      if tickType &lt; 9:\n        col = letterIncr(tickType)\n        q.put([LD,&quot;{}{}&quot;.format(col, reqId), str(size)])<\/pre>\n\n\n\n<h6 class=\"wp-block-heading\" id=\"h-completed-livedata-py\">Completed LiveData.py<\/h6>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">from utils import *\n\nclass TestApp(EClient, EWrapper):\n    def __init__(self):\n      EClient.__init__(self, self)\n\n    def tickPrice(self, reqId: TickerId, tickType: TickType, price: float, attrib: TickAttrib,):\n      if tickType &lt; 9:\n        col = letterIncr(tickType)\n        q.put([LD,&quot;{}{}&quot;.format(col, reqId), str(price)])\n    \n    def tickSize(self, reqId: TickerId, tickType: TickType, size: float):\n      if tickType &lt; 9:\n        col = letterIncr(tickType)\n        q.put([LD,&quot;{}{}&quot;.format(col, reqId), str(size)])<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"h-creating-pexcel-py\">Creating pexcel.py<\/h4>\n\n\n\n<p>Now we have a utility to handle the Excel connection, and a file used to process incoming data. All that leaves is requesting the initial information. Now in the third and final file for this article, I will create \u201cpexcel.py\u201d. Here I will import the content of my LiveData file, which includes utils.py as well. On a new line, I will set a variable for my port. This is because I frequently transition between Trader Workstation Paper Trading, and IB gateway, so having a variable hosted at the top of my page allows me to easily modify my connection. Next, I can create a reference to our buildHeaders() method to make sure the headers are built on connection. Then, I create our app connection and contract parameters. This is similar to the content of our nextValidId() method removed from the LiveData.py file.&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">from LiveData import *\n\nport = 7496\n\nbuildHeaders()\napp = TestApp()\napp.connect(\"127.0.0.1\", port, 100)<\/pre>\n\n\n\n<p>Next, we\u2019ll look to implement some additional threading so our client system can create several concurrent requests and avoid getting caught in the run loop. To do so, we\u2019ll sleep for a second before using our Threading library to once again run the app.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">sleep(1)\nThread(target=app.run).start()\nsleep(3)<\/pre>\n\n\n\n<p>Now, we can essentially copy in the content from the old nextValidId(). We can copy over the mycontract, Contract Object, but leave off the symbol. I\u2019d like to work with a specific set of symbols, AAPL, IBKR, TSLA, and MSFT, so I\u2019ll assign them to a list variable, symbols. Our pexcel.py file should now include:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">mycontract = Contract()\nmycontract.exchange = \"SMART\"\nmycontract.secType = \"STK\"\nmycontract.currency = \"USD\"\n\nsymbols = ['AAPL', 'IBKR', 'TSLA', 'MSFT']<\/pre>\n\n\n\n<p>We can now look to enumerate through these items to retrieve the symbol and request ID to be tracked throughout the program. We\u2019ll use <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">for enumer,symbol in enumerate(symbols):<\/code> to specify both our enumeration value and the direct symbol from our list. I\u2019ll then increment the enumer variable by two to once again resolve the indexing difference and the header issue. Then, I can set my contract\u2019s symbol variable to the new symbol variable from our enumerator. I can then write these symbols to specific rows using a similar structure as before in our q.put() method. And finally, we will create a market data request just like in the prior tutorial series but referencing our app instead of self, and then our enumerator as the request ID and mycontract as my contract variable. The full enumerator should appear as the following:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">for enumer,symbol in enumerate(symbols):\n    enumer += 2\n    mycontract.symbol = symbol\n\n    q.put([LD,\"A%s\" % enumer, symbol])\n\n    app.reqMktData(\n        reqId=enumer,\n        contract=mycontract,\n        genericTickList=\"\",\n        snapshot=False,\n        regulatorySnapshot=False,\n        mktDataOptions=[],\n    ) <\/pre>\n\n\n\n<p>And that concludes all of the coding in this lesson. Once you have saved all three of your files, you can now successfully run pexcel.py. The code should now launch an Excel file, Python_Excel.xlsx, with a newly created sheet, Live_Data, and a 10\u00d76 table indicating all of the headers we created from the tickType enumeration, all of the symbols we have requested data for, and a live feed of market data related to each column-row pair. The gif below should show an approximation of your own sheet\u2019s behavior.<\/p>\n\n\n\n<img decoding=\"async\" data-src=\"\/campus\/wp-content\/uploads\/sites\/2\/2024\/02\/excel_live_updates-700x429.gif\" alt=\"Excel sheet updating with Python data in real time\" width=\"700\" height=\"429\" class=\"alignnone size-medium wp-image-202410 lazyload\" data-srcset=\"https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/02\/excel_live_updates-700x429.gif 700w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/02\/excel_live_updates-300x184.gif 300w\" data-sizes=\"(max-width: 700px) 100vw, 700px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 700px; aspect-ratio: 700\/429;\" \/>\n\n\n\n<h6 class=\"wp-block-heading\" id=\"h-completed-pexcel-py\">Completed pexcel.py<\/h6>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">from LiveData import *\n\nport = 7496\n\nbuildHeaders()\napp = TestApp()\napp.connect(\"127.0.0.1\", port, 100)\n\nsleep(1)\nThread(target=app.run).start()\nsleep(3)\n\nmycontract = Contract()\nmycontract.exchange = \"SMART\"\nmycontract.secType = \"STK\"\nmycontract.currency = \"USD\"\n\nsymbols = ['AAPL', 'IBKR', 'TSLA', 'MSFT']\nfor enumer,symbol in enumerate(symbols):\n    enumer += 2\n    mycontract.symbol = symbol\n\n    q.put([LD,\"A%s\" % enumer, symbol])\n\n    app.reqMktData(\n        reqId=enumer,\n        contract=mycontract,\n        genericTickList=\"\",\n        snapshot=False,\n        regulatorySnapshot=False,\n        mktDataOptions=[],\n    )<\/pre>\n\n\n\n<p>With all of that being said, thank you for reading through the inaugural article on operating Excel through Python. Users who may be having difficulties with the code formatting, or would simply like to verify their code\u2019s behavior are welcome to review our <a href=\"https:\/\/github.com\/awiseib\/Python-Excel\/tree\/main\/Lesson_1\">github repository for the first lesson<\/a>. In future lessons, we plan to send requests from the Excel interface into Python, as well as manage other functionality of our original series such as requesting contract information, placing orders, and more. Please feel free to leave any comments or questions on the series in the comments section and we will look to provide more information on Python with Excel as soon as possible.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For this first article, we will be implementing the Interactive Brokers ibapi library, along with queue, threading, time, and xlwings.<\/p>\n","protected":false},"author":1173,"featured_media":202547,"comment_status":"open","ping_status":"closed","sticky":true,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[339,340,343,349,338,341,9764],"tags":[851,14154,595],"contributors-categories":[13576],"class_list":{"0":"post-202531","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-data-science","8":"category-api-development","9":"category-programing-languages","10":"category-python-development","11":"category-ibkr-quant-news","12":"category-quant-development","13":"category-tws-excel-api","14":"tag-algo-trading","15":"tag-excel-api","16":"tag-python","17":"contributors-categories-interactive-brokers"},"pp_statuses_selecting_workflow":false,"pp_workflow_action":"current","pp_status_selection":"publish","acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.9 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Connecting Python to Excel | IBKR Quant<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.interactivebrokers.com\/campus\/wp-json\/wp\/v2\/posts\/202531\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Connecting Python to Excel\" \/>\n<meta property=\"og:description\" content=\"For this first article, we will be implementing the Interactive Brokers ibapi library, along with queue, threading, time, and xlwings.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/connecting-python-to-excel\/\" \/>\n<meta property=\"og:site_name\" content=\"IBKR Campus US\" \/>\n<meta property=\"article:published_time\" content=\"2024-02-20T22:25:43+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-02-21T00:25:47+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/02\/api-dark-blue-grid.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1000\" \/>\n\t<meta property=\"og:image:height\" content=\"563\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Andrew Wise\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andrew Wise\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\n\t    \"@context\": \"https:\\\/\\\/schema.org\",\n\t    \"@graph\": [\n\t        {\n\t            \"@type\": \"NewsArticle\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/connecting-python-to-excel\\\/#article\",\n\t            \"isPartOf\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/connecting-python-to-excel\\\/\"\n\t            },\n\t            \"author\": {\n\t                \"name\": \"Andrew Wise\",\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/person\\\/68e347fb855adceb4ccfbfa350f5b783\"\n\t            },\n\t            \"headline\": \"Connecting Python to Excel\",\n\t            \"datePublished\": \"2024-02-20T22:25:43+00:00\",\n\t            \"dateModified\": \"2024-02-21T00:25:47+00:00\",\n\t            \"mainEntityOfPage\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/connecting-python-to-excel\\\/\"\n\t            },\n\t            \"wordCount\": 2309,\n\t            \"commentCount\": 5,\n\t            \"publisher\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#organization\"\n\t            },\n\t            \"image\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/connecting-python-to-excel\\\/#primaryimage\"\n\t            },\n\t            \"thumbnailUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/02\\\/api-dark-blue-grid.jpg\",\n\t            \"keywords\": [\n\t                \"Algo Trading\",\n\t                \"Excel API\",\n\t                \"Python\"\n\t            ],\n\t            \"articleSection\": [\n\t                \"Data Science\",\n\t                \"IBKR API Development\",\n\t                \"Programming Languages\",\n\t                \"Python Development\",\n\t                \"Quant\",\n\t                \"Quant Development\",\n\t                \"TWS Excel API\"\n\t            ],\n\t            \"inLanguage\": \"en-US\",\n\t            \"potentialAction\": [\n\t                {\n\t                    \"@type\": \"CommentAction\",\n\t                    \"name\": \"Comment\",\n\t                    \"target\": [\n\t                        \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/connecting-python-to-excel\\\/#respond\"\n\t                    ]\n\t                }\n\t            ]\n\t        },\n\t        {\n\t            \"@type\": \"WebPage\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/connecting-python-to-excel\\\/\",\n\t            \"url\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/connecting-python-to-excel\\\/\",\n\t            \"name\": \"Connecting Python to Excel | IBKR Campus US\",\n\t            \"isPartOf\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#website\"\n\t            },\n\t            \"primaryImageOfPage\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/connecting-python-to-excel\\\/#primaryimage\"\n\t            },\n\t            \"image\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/connecting-python-to-excel\\\/#primaryimage\"\n\t            },\n\t            \"thumbnailUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/02\\\/api-dark-blue-grid.jpg\",\n\t            \"datePublished\": \"2024-02-20T22:25:43+00:00\",\n\t            \"dateModified\": \"2024-02-21T00:25:47+00:00\",\n\t            \"inLanguage\": \"en-US\",\n\t            \"potentialAction\": [\n\t                {\n\t                    \"@type\": \"ReadAction\",\n\t                    \"target\": [\n\t                        \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/connecting-python-to-excel\\\/\"\n\t                    ]\n\t                }\n\t            ]\n\t        },\n\t        {\n\t            \"@type\": \"ImageObject\",\n\t            \"inLanguage\": \"en-US\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/ibkr-quant-news\\\/connecting-python-to-excel\\\/#primaryimage\",\n\t            \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/02\\\/api-dark-blue-grid.jpg\",\n\t            \"contentUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/02\\\/api-dark-blue-grid.jpg\",\n\t            \"width\": 1000,\n\t            \"height\": 563,\n\t            \"caption\": \"API\"\n\t        },\n\t        {\n\t            \"@type\": \"WebSite\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#website\",\n\t            \"url\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/\",\n\t            \"name\": \"IBKR Campus US\",\n\t            \"description\": \"Financial Education from Interactive Brokers\",\n\t            \"publisher\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#organization\"\n\t            },\n\t            \"potentialAction\": [\n\t                {\n\t                    \"@type\": \"SearchAction\",\n\t                    \"target\": {\n\t                        \"@type\": \"EntryPoint\",\n\t                        \"urlTemplate\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/?s={search_term_string}\"\n\t                    },\n\t                    \"query-input\": {\n\t                        \"@type\": \"PropertyValueSpecification\",\n\t                        \"valueRequired\": true,\n\t                        \"valueName\": \"search_term_string\"\n\t                    }\n\t                }\n\t            ],\n\t            \"inLanguage\": \"en-US\"\n\t        },\n\t        {\n\t            \"@type\": \"Organization\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#organization\",\n\t            \"name\": \"Interactive Brokers\",\n\t            \"alternateName\": \"IBKR\",\n\t            \"url\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/\",\n\t            \"logo\": {\n\t                \"@type\": \"ImageObject\",\n\t                \"inLanguage\": \"en-US\",\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/logo\\\/image\\\/\",\n\t                \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/05\\\/ibkr-campus-logo.jpg\",\n\t                \"contentUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/05\\\/ibkr-campus-logo.jpg\",\n\t                \"width\": 669,\n\t                \"height\": 669,\n\t                \"caption\": \"Interactive Brokers\"\n\t            },\n\t            \"image\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/logo\\\/image\\\/\"\n\t            },\n\t            \"publishingPrinciples\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/about-ibkr-campus\\\/\",\n\t            \"ethicsPolicy\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/cyber-security-notice\\\/\"\n\t        },\n\t        {\n\t            \"@type\": \"Person\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/person\\\/68e347fb855adceb4ccfbfa350f5b783\",\n\t            \"name\": \"Andrew Wise\",\n\t            \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/author\\\/andrew-wise\\\/\"\n\t        }\n\t    ]\n\t}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Connecting Python to Excel | IBKR Quant","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.interactivebrokers.com\/campus\/wp-json\/wp\/v2\/posts\/202531\/","og_locale":"en_US","og_type":"article","og_title":"Connecting Python to Excel","og_description":"For this first article, we will be implementing the Interactive Brokers ibapi library, along with queue, threading, time, and xlwings.","og_url":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/connecting-python-to-excel\/","og_site_name":"IBKR Campus US","article_published_time":"2024-02-20T22:25:43+00:00","article_modified_time":"2024-02-21T00:25:47+00:00","og_image":[{"width":1000,"height":563,"url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/02\/api-dark-blue-grid.jpg","type":"image\/jpeg"}],"author":"Andrew Wise","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Andrew Wise","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/connecting-python-to-excel\/#article","isPartOf":{"@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/connecting-python-to-excel\/"},"author":{"name":"Andrew Wise","@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/person\/68e347fb855adceb4ccfbfa350f5b783"},"headline":"Connecting Python to Excel","datePublished":"2024-02-20T22:25:43+00:00","dateModified":"2024-02-21T00:25:47+00:00","mainEntityOfPage":{"@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/connecting-python-to-excel\/"},"wordCount":2309,"commentCount":5,"publisher":{"@id":"https:\/\/ibkrcampus.com\/campus\/#organization"},"image":{"@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/connecting-python-to-excel\/#primaryimage"},"thumbnailUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/02\/api-dark-blue-grid.jpg","keywords":["Algo Trading","Excel API","Python"],"articleSection":["Data Science","IBKR API Development","Programming Languages","Python Development","Quant","Quant Development","TWS Excel API"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/connecting-python-to-excel\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/connecting-python-to-excel\/","url":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/connecting-python-to-excel\/","name":"Connecting Python to Excel | IBKR Campus US","isPartOf":{"@id":"https:\/\/ibkrcampus.com\/campus\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/connecting-python-to-excel\/#primaryimage"},"image":{"@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/connecting-python-to-excel\/#primaryimage"},"thumbnailUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/02\/api-dark-blue-grid.jpg","datePublished":"2024-02-20T22:25:43+00:00","dateModified":"2024-02-21T00:25:47+00:00","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/connecting-python-to-excel\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ibkrcampus.com\/campus\/ibkr-quant-news\/connecting-python-to-excel\/#primaryimage","url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/02\/api-dark-blue-grid.jpg","contentUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/02\/api-dark-blue-grid.jpg","width":1000,"height":563,"caption":"API"},{"@type":"WebSite","@id":"https:\/\/ibkrcampus.com\/campus\/#website","url":"https:\/\/ibkrcampus.com\/campus\/","name":"IBKR Campus US","description":"Financial Education from Interactive Brokers","publisher":{"@id":"https:\/\/ibkrcampus.com\/campus\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/ibkrcampus.com\/campus\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/ibkrcampus.com\/campus\/#organization","name":"Interactive Brokers","alternateName":"IBKR","url":"https:\/\/ibkrcampus.com\/campus\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/logo\/image\/","url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/05\/ibkr-campus-logo.jpg","contentUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/05\/ibkr-campus-logo.jpg","width":669,"height":669,"caption":"Interactive Brokers"},"image":{"@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/logo\/image\/"},"publishingPrinciples":"https:\/\/www.interactivebrokers.com\/campus\/about-ibkr-campus\/","ethicsPolicy":"https:\/\/www.interactivebrokers.com\/campus\/cyber-security-notice\/"},{"@type":"Person","@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/person\/68e347fb855adceb4ccfbfa350f5b783","name":"Andrew Wise","url":"https:\/\/www.interactivebrokers.com\/campus\/author\/andrew-wise\/"}]}},"jetpack_featured_media_url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/02\/api-dark-blue-grid.jpg","_links":{"self":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/posts\/202531","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/users\/1173"}],"replies":[{"embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/comments?post=202531"}],"version-history":[{"count":0,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/posts\/202531\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/media\/202547"}],"wp:attachment":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/media?parent=202531"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/categories?post=202531"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/tags?post=202531"},{"taxonomy":"contributors-categories","embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/contributors-categories?post=202531"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}