├── APIprintable.pdf ├── Connection.py ├── FTC_NLV_Demo.ipynb ├── IB API Installation instructions.pdf ├── IBWrapper.py ├── IbPy Demo v2018-04-05.ipynb ├── README.md ├── Vol1 IB Python Practical Implementation Guide - Draft.pdf ├── Vol3 IB JAVA API Guide - Draft v2016-01-19 .pdf ├── ib-insync notebooks ├── bar_data.ipynb ├── basics.ipynb ├── contract_details.ipynb ├── market_depth.ipynb ├── option_chain.ipynb ├── ordering.ipynb └── tick_data.ipynb ├── ib_class.py ├── ib_insync.ipynb └── xiang.py /APIprintable.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anthonyng2/ib/40c06bf4b1e16092dd22ee61d49b1794e034d01b/APIprintable.pdf -------------------------------------------------------------------------------- /Connection.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Interaction Brokers Connection 4 | 5 | Connection Demo 6 | """ 7 | 8 | from IBWrapper import IBWrapper 9 | from ib.ext.EClientSocket import EClientSocket 10 | 11 | accountName = "DI246990" 12 | callback = IBWrapper() # Instantiate IBWrapper. callback 13 | tws = EClientSocket(callback) # Instantiate EClientSocket and return data to callback 14 | host = "" # For local host 15 | port = 4002 16 | clientId = 5 17 | 18 | tws.eConnect(host, port, clientId) # Connect to TWS 19 | 20 | tws.eDisconnect() 21 | -------------------------------------------------------------------------------- /FTC_NLV_Demo.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Mass Account Summary Extraction\n", 8 | "At the Financial Training Centre (FTC) of the School of Business Management in NYP, we conduct trading simulation using Interactive Brokers (IB) TWS. To encourage healthy competition, we extract their NLV from IB and rank them according to their profit and loss (PnL)." 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "**import necessary libraries**" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 1, 21 | "metadata": { 22 | "collapsed": true 23 | }, 24 | "outputs": [], 25 | "source": [ 26 | "import warnings\n", 27 | "warnings.filterwarnings('ignore')\n", 28 | "import pandas as pd\n", 29 | "import numpy as np" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "metadata": {}, 35 | "source": [ 36 | "**import IbPy library**" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 2, 42 | "metadata": { 43 | "collapsed": false 44 | }, 45 | "outputs": [], 46 | "source": [ 47 | "import time\n", 48 | "from datetime import datetime\n", 49 | "from IBWrapper import IBWrapper, contract\n", 50 | "from ib.ext.EClientSocket import EClientSocket\n", 51 | "from ib.ext.ScannerSubscription import ScannerSubscription" 52 | ] 53 | }, 54 | { 55 | "cell_type": "markdown", 56 | "metadata": {}, 57 | "source": [ 58 | "**Extract current batch of students' IB account number**" 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": 3, 64 | "metadata": { 65 | "collapsed": true 66 | }, 67 | "outputs": [], 68 | "source": [ 69 | "def obtain_ib_acct():\n", 70 | " return pd.read_excel(\"G:/live/CURRENT_BATCH_IB.xlsx\", sheetname=\"2016S1R2\")[['ADM_NO','NAME','IB ACCT']]" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": 4, 76 | "metadata": { 77 | "collapsed": false 78 | }, 79 | "outputs": [], 80 | "source": [ 81 | "df = obtain_ib_acct() # Obtain current batch IB account number " 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": 5, 87 | "metadata": { 88 | "collapsed": true 89 | }, 90 | "outputs": [], 91 | "source": [ 92 | "callback = IBWrapper() # Instantiate IBWrapper. callback \n", 93 | "tws = EClientSocket(callback) # Instantiate EClientSocket and return data to callback" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 6, 99 | "metadata": { 100 | "collapsed": true 101 | }, 102 | "outputs": [], 103 | "source": [ 104 | "host = \"\"\n", 105 | "port = 4001\n", 106 | "clientId = 202" 107 | ] 108 | }, 109 | { 110 | "cell_type": "markdown", 111 | "metadata": {}, 112 | "source": [ 113 | "**Connect to TWS**" 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": 7, 119 | "metadata": { 120 | "collapsed": false 121 | }, 122 | "outputs": [ 123 | { 124 | "name": "stdout", 125 | "output_type": "stream", 126 | "text": [ 127 | "Server Version: 76\n", 128 | "TWS Time at connection:20160513 11:43:38 SGT\n" 129 | ] 130 | } 131 | ], 132 | "source": [ 133 | "tws.eConnect(host, port, clientId) # Connect to TWS" 134 | ] 135 | }, 136 | { 137 | "cell_type": "code", 138 | "execution_count": 8, 139 | "metadata": { 140 | "collapsed": false 141 | }, 142 | "outputs": [], 143 | "source": [ 144 | "tws.setServerLogLevel(5) # Set error output to verbose" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": 9, 150 | "metadata": { 151 | "collapsed": true 152 | }, 153 | "outputs": [], 154 | "source": [ 155 | "create = contract() # Instantiate contract class\n", 156 | "callback.initiate_variables()" 157 | ] 158 | }, 159 | { 160 | "cell_type": "markdown", 161 | "metadata": {}, 162 | "source": [ 163 | "**Submit request for Account Summary. Asking for NLV for \"All\" accounts**" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": 10, 169 | "metadata": { 170 | "collapsed": false 171 | }, 172 | "outputs": [], 173 | "source": [ 174 | "reqID = 1001\n", 175 | "tws.reqAccountSummary(reqID,\"All\",\"NetLiquidation\")" 176 | ] 177 | }, 178 | { 179 | "cell_type": "markdown", 180 | "metadata": {}, 181 | "source": [ 182 | "**TWS often send back duplicate data. We drop the duplicates and keep the last figure**" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": 11, 188 | "metadata": { 189 | "collapsed": false 190 | }, 191 | "outputs": [], 192 | "source": [ 193 | "res = pd.DataFrame(callback.account_Summary,\n", 194 | " columns = [\"reqID\", \"IB ACCT\", \"Key\", \n", 195 | " \"NLV\", \"Currency\"])[[\"IB ACCT\", \"NLV\"]]\n", 196 | "res[\"IB ACCT\"].drop_duplicates(keep = \"last\", inplace=True)" 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": 12, 202 | "metadata": { 203 | "collapsed": false 204 | }, 205 | "outputs": [], 206 | "source": [ 207 | "current_batch_nlv = pd.merge(df, res, on=\"IB ACCT\")" 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": 13, 213 | "metadata": { 214 | "collapsed": false 215 | }, 216 | "outputs": [], 217 | "source": [ 218 | "import matplotlib\n", 219 | "%matplotlib inline\n", 220 | "matplotlib.style.use(\"ggplot\")" 221 | ] 222 | }, 223 | { 224 | "cell_type": "markdown", 225 | "metadata": {}, 226 | "source": [ 227 | "**Calculate each student's PnL and visualise the data**" 228 | ] 229 | }, 230 | { 231 | "cell_type": "code", 232 | "execution_count": 14, 233 | "metadata": { 234 | "collapsed": false 235 | }, 236 | "outputs": [ 237 | { 238 | "data": { 239 | "text/plain": [ 240 | "" 241 | ] 242 | }, 243 | "execution_count": 14, 244 | "metadata": {}, 245 | "output_type": "execute_result" 246 | }, 247 | { 248 | "data": { 249 | "image/png": "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\nueDVhKNXEr///e/Pu87Z8sXPPvuMXbt28cknn9CvXz++/PJLMjIynCqzvPHGG/nTn/7Er371K6fa\n0tLHH39MWlqaXZLU6/VMnz6dxx57zKlkYrvpaXtt09zcrLq9NocPH3a4Es7VJdpqSnfb4+ry1uLi\nYrZs2YKnpycTJkxwqksQUG6S7969m9raWoYOHUpqaqrDV3ItWSwWZQruiIgIZsyYwezZs50uTGmZ\nPDdt2nTBv+GL2bZtG4sXL7a7mR8aGspTTz3FokWLHE4mtueHbL744gu2bNlCt27d+MMf/uBQrPau\njKqrq9m2bZuqvy9JJj9pbm5WnmTubO+9957DN/RmzJiBn58ft956K/fffz9XX301M2fOdLpePzIy\nkpqaGrKzs1U/7avRaNq92tJqtU5dhdXV1ZGUlKT8v2h5A9+ZeO09ZW6xWDh58mSHb7y35qoS7ZZP\nSrdk6+Z64403HIrnyvLWBQsWUFtbyx133KGUi7esFnOkMmz69On07NmTUaNG0bNnTzQaDV9//TVf\nf/014HhBik3LEw2j0UhdXZ3y3tEKsZZdyf/6179U3Yc83+c7W1hhU1JSwubNm9FoNEyYMMGpCsKW\n1V/Hjh0jJyeHzz//nLvvvlvV1OeSTH7i4+OjDFXgjoYPH05RURG7d+9Gq9USGRmpqrvMlU/79urV\ni7y8PCWOTX5+vlJ+6AhXPrEO7Ze1Go1GAgICHE4Ari7Rbl1t5QquKm+96qqr8Pf358MPP2x3yBxH\nKsOGDx+ORqPh8OHDHD58uM16Z5JJ65MO+O+Jh9oKMbVd0VdffTXffvttm9Euvv32W6fKbz/++GO2\nbNmCXq8nLi7Oob/P9vzwww9s3ryZb7/9ljvvvJPp06crlXbOkmqun8yfP/9ne0Ds4Ycf5m9/+5vD\n+9luYBYUFPDJJ59QV1fHjBkzuOGGGxz+gj799NNMmzatzVnst99+63B3iNls5qWXXsLLy0s5W/36\n669paGhg3rx5mEwmh9rW+ol1Wymvs10ir776KlOnTlX10JjNlClTlBLt9pKIoyXa7Tl9+jR79+6l\noKDA4eFQtm/fzn/+8592y1ujo6MdHu7lSqW2qq7lyVrLeyZ5eXkOn6zBue+dyWTiuuuua3fMP0fK\n7//6179SUVHB+PHjGTlyZJvvsTPP/IAkE0V7Z3NqXKj7oqGhweGB3lprbGxk//79FBQUsH//fl57\n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\nGIsJEREp9j9/gAuGbM4ggQAAAABJRU5ErkJggg==\n", 250 | "text/plain": [ 251 | "" 252 | ] 253 | }, 254 | "metadata": {}, 255 | "output_type": "display_data" 256 | } 257 | ], 258 | "source": [ 259 | "Init_bal = 1000000\n", 260 | "current_batch_nlv[\"PnL\"] = current_batch_nlv[\"NLV\"].astype(float) - Init_bal\n", 261 | "current_batch_nlv.sort_values(by = \"PnL\", ascending=False, inplace=True)\n", 262 | "current_batch_nlv.plot(kind=\"bar\", x=current_batch_nlv[\"NAME\"].str.split(\" \").str.get(0))" 263 | ] 264 | }, 265 | { 266 | "cell_type": "markdown", 267 | "metadata": {}, 268 | "source": [ 269 | "**Not a good trading period. Obviously**" 270 | ] 271 | }, 272 | { 273 | "cell_type": "code", 274 | "execution_count": 15, 275 | "metadata": { 276 | "collapsed": false 277 | }, 278 | "outputs": [], 279 | "source": [ 280 | "tws.eDisconnect()" 281 | ] 282 | } 283 | ], 284 | "metadata": { 285 | "kernelspec": { 286 | "display_name": "Python 2", 287 | "language": "python", 288 | "name": "python2" 289 | }, 290 | "language_info": { 291 | "codemirror_mode": { 292 | "name": "ipython", 293 | "version": 2 294 | }, 295 | "file_extension": ".py", 296 | "mimetype": "text/x-python", 297 | "name": "python", 298 | "nbconvert_exporter": "python", 299 | "pygments_lexer": "ipython2", 300 | "version": "2.7.11" 301 | } 302 | }, 303 | "nbformat": 4, 304 | "nbformat_minor": 0 305 | } 306 | -------------------------------------------------------------------------------- /IB API Installation instructions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anthonyng2/ib/40c06bf4b1e16092dd22ee61d49b1794e034d01b/IB API Installation instructions.pdf -------------------------------------------------------------------------------- /IBWrapper.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Wrapper - Organised by groups. E.g., Accont and Portfolio group, Orders group etc 3 | 2016-01-31 4 | Updated 20 Nov 2016 for Python 3. 5 | Updated 5 Apr 2018 to include limit price 6 | ''' 7 | from __future__ import print_function 8 | from ib.ext.EWrapper import EWrapper 9 | from ib.ext.Contract import Contract 10 | from ib.ext.ExecutionFilter import ExecutionFilter 11 | from ib.ext.Order import Order 12 | 13 | class IBWrapper(EWrapper): 14 | def initiate_variables(self): 15 | # Account and Portfolio 16 | setattr(self, "accountDownloadEnd_flag", False) 17 | setattr(self, "update_AccountTime", None) 18 | setattr(self, "update_AccountValue", []) 19 | setattr(self, "update_Portfolio", []) 20 | setattr(self, 'account_Summary', []) 21 | setattr(self, 'account_SummaryEnd_flag', False) 22 | setattr(self, 'update_Position', []) 23 | setattr(self, 'positionEnd_flag', False) 24 | # Orders 25 | setattr(self, 'order_Status', []) 26 | setattr(self, 'open_Order', []) 27 | setattr(self, 'open_OrderEnd_flag', True) 28 | # Market Data 29 | setattr(self, 'tick_Price', []) 30 | setattr(self, 'tick_Size', []) 31 | setattr(self, 'tick_OptionComputation', []) 32 | setattr(self, 'tick_Generic', []) 33 | setattr(self, 'tick_String', []) 34 | setattr(self, 'tick_EFP', []) 35 | setattr(self, 'tickSnapshotEnd_reqId', []) 36 | setattr(self, 'tickSnapshotEnd_flag', False) 37 | # Connection and Server 38 | setattr(self, 'connection_Closed', False) 39 | # Executions 40 | setattr(self, "exec_Details_reqId", []) 41 | setattr(self, "exec_Details_contract", []) 42 | setattr(self, "exec_Details_execution", []) 43 | setattr(self, "exec_DetailsEnd_flag", False) 44 | # Contract 45 | setattr(self, "contract_Details_flag", False) 46 | # Market Depth 47 | setattr(self, 'update_MktDepth', []) 48 | setattr(self, 'update_MktDepthL2', []) 49 | # Historical Data 50 | setattr(self, 'historical_Data', []) 51 | setattr(self, 'historical_DataEnd_flag', False) 52 | # Market Scanners 53 | setattr(self, 'scanner_Data_End_flag', False) 54 | setattr(self, 'scanner_Data', []) 55 | # Real Time Bars 56 | setattr(self, 'real_timeBar', []) 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | # Account and Portfolio ################################################### 66 | def updateAccountValue(self, key, value, currency, accountName): 67 | update_AccountValue = self.update_AccountValue 68 | update_AccountValue.append((key, value, currency, accountName)) 69 | 70 | def updatePortfolio(self, contract, position, marketPrice, marketValue, 71 | averageCost, unrealizedPnL, realizedPnL, accountName): 72 | update_Portfolio = self.update_Portfolio 73 | update_Portfolio.append((contract.m_conId, contract.m_currency, 74 | contract.m_expiry, contract.m_includeExpired, 75 | contract.m_localSymbol, contract.m_multiplier, 76 | contract.m_primaryExch, contract.m_right, 77 | contract.m_secType, contract.m_strike, 78 | contract.m_symbol, contract.m_tradingClass, 79 | position, marketPrice, marketValue, 80 | averageCost, unrealizedPnL, realizedPnL, 81 | accountName)) 82 | 83 | def updateAccountTime(self, timeStamp): 84 | self.update_AccountTime = timeStamp 85 | 86 | def accountDownloadEnd(self, accountName=None): 87 | self.accountDownloadEnd_accountName = accountName 88 | self.accountDownloadEnd_flag = True 89 | 90 | def accountSummary(self, reqId=None, account=None, tag=None, value=None, 91 | currency=None): 92 | account_Summary = self.account_Summary 93 | account_Summary.append((reqId, account, tag, value, currency)) 94 | 95 | def accountSummaryEnd(self, reqId): 96 | self.accountSummaryEnd_reqId = reqId 97 | self.account_SummaryEnd_flag = True 98 | 99 | def position(self, account, contract, pos, avgCost): 100 | update_Position = self.update_Position 101 | update_Position.append((account, contract.m_conId, contract.m_currency, 102 | contract.m_exchange, contract.m_expiry, 103 | contract.m_includeExpired, contract.m_localSymbol, 104 | contract.m_multiplier, contract.m_right, 105 | contract.m_secType, contract.m_strike, 106 | contract.m_symbol, contract.m_tradingClass, 107 | pos, avgCost)) 108 | 109 | def positionEnd(self): 110 | setattr(self, 'positionEnd_flag', True) 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | # Orders ################################################################### 122 | def orderStatus(self, orderId, status, filled, remaining, avgFillPrice, 123 | permId, parentId, lastFillPrice, clientId, whyHeld): 124 | order_Status = self.order_Status 125 | order_Status.append((orderId, status, filled, remaining, avgFillPrice, 126 | permId, parentId, lastFillPrice, clientId, whyHeld)) 127 | 128 | def openOrder(self, orderId, contract, order, orderState): 129 | open_Order = self.open_Order 130 | open_Order.append((orderId, contract, order, orderState)) 131 | 132 | def openOrderEnd(self): 133 | setattr(self, 'open_OrderEnd_flag', True) 134 | 135 | def nextValidId(self, orderId): 136 | self.next_ValidId = orderId 137 | 138 | def deltaNeutralValidation(self, reqId, underComp): 139 | pass 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | # Market Data ############################################################## 150 | def tickPrice(self, tickerId, field, price, canAutoExecute): 151 | tick_Price = self.tick_Price 152 | tick_Price.append((tickerId, field, price, canAutoExecute)) 153 | 154 | def tickSize(self, tickerId, field, size): 155 | tick_Size = self.tick_Size 156 | tick_Size.append((tickerId, field, size)) 157 | 158 | def tickOptionComputation(self, tickerId, field, impliedVol, delta, 159 | optPrice, pvDividend, gamma, vega, theta, 160 | undPrice): 161 | tick_OptionComputation = self.tick_OptionComputation 162 | tick_OptionComputation.append((tickerId, field, impliedVol, delta, 163 | optPrice, pvDividend, gamma, vega, 164 | theta, undPrice)) 165 | 166 | def tickGeneric(self, tickerId, tickType, value): 167 | tick_Generic = self.tick_Generic 168 | tick_Generic.append((tickerId, tickType, value)) 169 | 170 | def tickString(self, tickerId, field, value): 171 | tick_String = self.tick_String 172 | tick_String.append((tickerId, field, value)) 173 | 174 | def tickEFP(self, tickerId, tickType, basisPoints, formattedBasisPoints, 175 | impliedFuture, holdDays, futureExpiry, dividendImpact, 176 | dividendsToExpiry): 177 | tick_EFP = self.tick_EFP 178 | tick_EFP.append((tickerId, tickType, basisPoints, formattedBasisPoints, 179 | impliedFuture, holdDays, futureExpiry, dividendImpact, 180 | dividendsToExpiry)) 181 | 182 | def tickSnapshotEnd(self, reqId): 183 | self.tickSnapshotEnd_reqId = reqId 184 | setattr(self, 'tickSnapshotEnd_flag', True) 185 | 186 | def marketDataType(self, reqId, marketDataType): 187 | setattr(self, 'market_DataType', marketDataType) 188 | print("market_DataType" + str(self.market_DataType)) 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | # Connection and Server #################################################### 200 | def currentTime(self, time): 201 | self.current_Time = time 202 | 203 | def error(self, id=None, errorCode=None, errorString=None): 204 | #print id 205 | print([id, errorCode, errorString]) 206 | 207 | def error_0(self, strval=None): 208 | print("error_0") 209 | 210 | def error_1(self, id=0, errorCode=None, errorMsg=None): 211 | print("error_1") 212 | 213 | '''def error_0(self, strval): 214 | pass 215 | 216 | def error_1(self, id, errorCode, errorMsg): 217 | pass''' 218 | 219 | def connectionClosed(self): 220 | self.connection_Closed = True 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | # Executions ############################################################### 232 | def execDetails(self, reqId, contract, execution): 233 | self.exec_Details_reqId = reqId 234 | self.exec_Details_contract = contract 235 | self.exec_Details_execution = execution 236 | 237 | def execDetailsEnd(self, reqId): 238 | self.exec_DetailsEnd_reqId = reqId 239 | setattr(self, "exec_DetailsEnd_flag", True) 240 | 241 | def commissionReport(self, commissionReport): 242 | self.commission_Report = commissionReport 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | # Contract ################################################################# 253 | def contractDetails(self, reqId, contractDetails): 254 | self.contract_Details_reqId = reqId 255 | self.contract_Details = contractDetails 256 | 257 | def contractDetailsEnd(self, reqId): 258 | self.contract_DetailsEnd_reqId = reqId 259 | self.contract_Details_flag = True 260 | 261 | def bondContractDetails(self, reqId, contractDetails): 262 | self.bond_ContractDetails_reqId = reqId 263 | self.bond_ContractDetails = contractDetails 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | # Market Depth ############################################################# 274 | def updateMktDepth(self, tickerId, position, operation, side, price, size): 275 | update_MktDepth = self.update_MktDepth 276 | update_MktDepth.append((tickerId, position, operation, side, price, size)) 277 | #df = pd.DataFrame(self.update_MktDepth, columns = ["tickerId", "position", 278 | # "operation", "side", 279 | # "price", "size"]) 280 | 281 | def updateMktDepthL2(self, tickerId, position, marketMaker, operation, 282 | side, price, size): 283 | # I don't get any of this so I can't test it. Following are just place holders. 284 | print("blah blah. You have L2 data!!!") 285 | update_MktDepthL2 = self.update_MktDepthL2 286 | update_MktDepthL2.append((tickerId, position, operation, side, 287 | price, size)) 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | # News Bulletin ############################################################ 298 | def updateNewsBulletin(self, msgId, msgType, message, origExchange): 299 | # During the time I test this, I don't get anything. Can't verify. Sorry. 300 | print("You get News!!!") 301 | self.update_NewsBulletin_msgId = msgId 302 | self.update_NewsBulletin_msgType = msgType 303 | self.update_NewsBulletin_message = message 304 | self.update_NewsBulletin_origExchange = origExchange 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | # Financial Advisors ####################################################### 315 | def managedAccounts(self, accountsList): 316 | self.managed_Accounts = accountsList 317 | 318 | def receiveFA(self, faDataType, xml): 319 | pass 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | # Historical Data ######################################################### 331 | def historicalData(self, reqId, date, open, high, low, close, volume, 332 | count, WAP, hasGaps): 333 | historical_Data = self.historical_Data 334 | historical_Data.append((reqId, date, open, high, low, close, volume, 335 | count, WAP, hasGaps)) 336 | #df = pd.DataFrame(self.historical_Data, columns = ["reqId", "date", "open", 337 | # "high", "low", "close", 338 | # "volume", "count", "WAP", 339 | # "hasGaps"]) 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | # Market Scanners ######################################################### 349 | def scannerParameters(self, xml): 350 | self.scanner_Parameters = xml 351 | 352 | def scannerData(self, reqId, rank, contractDetails, distance, benchmark, 353 | projetion, legsStr): 354 | scanner_Data = self.scanner_Data 355 | scanner_Data.append((reqId, rank, contractDetails, distance, benchmark, 356 | projetion, legsStr)) 357 | 358 | def scannerDataEnd(self, reqId): 359 | self.scanner_Data_End_reqID = reqId 360 | self.scanner_Data_End_flag = True 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | # Real Tume Bars ########################################################### 372 | def realtimeBar(self, reqId, time, open, high, low, close, volume, 373 | wap, count): 374 | real_timeBar = self.real_timeBar 375 | real_timeBar.append((reqId, time, open, high, low, close, volume, 376 | wap, count)) 377 | #df = pd.DataFrame(self.real_timeBar, columns = ["reqId", "time", "open", "high", 378 | # "low", "close", "volume", "wap", 379 | # "count"]) 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | # Fundamental Data ######################################################### 390 | def fundamentalData(self, reqId, data): 391 | print("Getting Fundamental Data Feed Through") 392 | self.fundamental_Data_reqId = reqId 393 | self.fundamental_Data_data = data 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | # Display Groups ######################################################### 404 | def displayGroupList(self, reqId, groups): 405 | pass 406 | 407 | def displayGroupUpdate(self, reqId, contractInfo): 408 | pass 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | # Create Contract 444 | class contract(): 445 | def create_contract(self, symbol, secType, exchange, currency, 446 | right = None, strike = None, expiry = None, 447 | multiplier = None, tradingClass = None, 448 | localSymbol = None, includeExpired=None): 449 | contract = Contract() 450 | contract.m_symbol = symbol 451 | contract.m_secType = secType 452 | contract.m_exchange = exchange 453 | contract.m_currency = currency 454 | contract.m_right = right 455 | contract.m_strike = strike 456 | contract.m_expiry = expiry 457 | contract.m_multiplier = multiplier 458 | contract.m_tradingClass = tradingClass 459 | contract.m_localSymbol = localSymbol 460 | contract.m_includeExpired = includeExpired 461 | return contract 462 | 463 | def create_order(self, account, orderType, totalQuantity, action, 464 | lmt_price=None): 465 | order = Order() 466 | order.m_account = account 467 | order.m_orderType = orderType 468 | order.m_totalQuantity = totalQuantity 469 | order.m_action = action 470 | if orderType == "LMT": 471 | order.m_lmtPrice = lmt_price 472 | return order 473 | 474 | def exec_filter(self, client_id, accountName, contract): 475 | filt = ExecutionFilter() 476 | filt.m_clientId = client_id 477 | filt.m_acctCode = accountName 478 | #filt.m_time = "20160122-00:00:00" 479 | filt.m_symbol = contract.m_symbol 480 | filt.m_secType = contract.m_secType 481 | filt.m_exchange = contract.m_exchange 482 | return filt 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | ''' 501 | openOrder contains the following fields: 502 | self.tmp = [orderId, contract.m_comboLegs, 503 | contract.m_comboLegsDescrip, 504 | contract.m_conId, 505 | contract.m_currency, 506 | contract.m_exchange, 507 | contract.m_expiry, 508 | contract.m_includeExpired, 509 | contract.m_localSymbol, 510 | contract.m_multiplier, 511 | contract.m_primaryExch, 512 | contract.m_right, 513 | contract.m_secId, 514 | contract.m_secIdType, 515 | contract.m_secType, 516 | contract.m_strike, 517 | contract.m_symbol, 518 | contract.m_tradingClass, 519 | contract.m_underComp, 520 | order.m_account, 521 | order.m_action, 522 | order.m_activeStartTime, 523 | order.m_activeStopTime, 524 | order.m_algoParams, 525 | order.m_algoStrategy, 526 | order.m_allOrNone, 527 | order.m_auctionStrategy, 528 | order.m_auxPrice, 529 | order.m_basisPoints, 530 | order.m_basisPointsType, 531 | order.m_blockOrder, 532 | order.m_clearingAccount, 533 | order.m_clearingIntent, 534 | order.m_clientId, 535 | order.m_continuousUpdate, 536 | order.m_delta, 537 | order.m_deltaNeutralAuxPrice, 538 | order.m_deltaNeutralClearingAccount, 539 | order.m_deltaNeutralClearingIntent, 540 | order.m_deltaNeutralConId, 541 | order.m_deltaNeutralDesignatedLocation, 542 | order.m_deltaNeutralOpenClose, 543 | order.m_deltaNeutralOrderType, 544 | order.m_deltaNeutralSettlingFirm, 545 | order.m_deltaNeutralShortSale, 546 | order.m_deltaNeutralShortSaleSlot, 547 | order.m_designatedLocation, 548 | order.m_discretionaryAmt, 549 | order.m_displaySize, 550 | order.m_eTradeOnly, 551 | order.m_exemptCode, 552 | order.m_faGroup, 553 | order.m_faMethod, 554 | order.m_faPercentage, 555 | order.m_faProfile, 556 | order.m_firmQuoteOnly, 557 | order.m_goodAfterTime, 558 | order.m_goodTillDate, 559 | order.m_hedgeParam, 560 | order.m_hedgeType, 561 | order.m_hidden, 562 | order.m_lmtPrice, 563 | order.m_minQty, 564 | order.m_nbboPriceCap, 565 | order.m_notHeld, 566 | order.m_ocaGroup, 567 | order.m_ocaType, 568 | order.m_openClose, 569 | order.m_optOutSmartRouting, 570 | order.m_orderComboLegs, 571 | order.m_orderId, 572 | order.m_orderRef, 573 | order.m_orderType, 574 | order.m_origin, 575 | order.m_outsideRth, 576 | order.m_overridePercentageConstraints, 577 | order.m_parentId, 578 | order.m_percentOffset, 579 | order.m_permId, 580 | order.m_referencePriceType, 581 | order.m_rule80A, 582 | order.m_scaleAutoReset, 583 | order.m_scaleInitFillQty, 584 | order.m_scaleInitLevelSize, 585 | order.m_scaleInitPosition, 586 | order.m_scalePriceAdjustInterval, 587 | order.m_scalePriceAdjustValue, 588 | order.m_scalePriceIncrement, 589 | order.m_scaleProfitOffset, 590 | order.m_scaleRandomPercent, 591 | order.m_scaleSubsLevelSize, 592 | order.m_scaleTable, 593 | order.m_settlingFirm, 594 | order.m_shortSaleSlot, 595 | order.m_smartComboRoutingParams, 596 | order.m_startingPrice, 597 | order.m_stockRangeLower, 598 | order.m_stockRangeUpper, 599 | order.m_stockRefPrice, 600 | order.m_sweepToFill, 601 | order.m_tif, 602 | order.m_totalQuantity, 603 | order.m_trailStopPrice, 604 | order.m_trailingPercent, 605 | order.m_transmit, 606 | order.m_triggerMethod, 607 | order.m_volatility, 608 | order.m_volatilityType, 609 | order.m_whatIf, 610 | orderState.m_commission, 611 | orderState.m_commissionCurrency, 612 | orderState.m_equityWithLoan, 613 | orderState.m_initMargin, 614 | orderState.m_maintMargin, 615 | orderState.m_maxCommission, 616 | orderState.m_minCommission, 617 | orderState.m_status, 618 | orderState.m_warningText] 619 | ''' 620 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ib Files 2 | 3 | Released 1 Feb 2016 4 | 5 | Updated 12 May 2016 with [Tutorial](https://nbviewer.jupyter.org/github/anthonyng2/ib/blob/master/IbPy%20Demo.ipynb) 6 | 7 | * ib_class.py : Demonstrates how to call IB using IbPy for account and other information. The codes are intentionally kept in self contained groups. E.g., Account and Portfolio, Orders etc. 8 | * IBWrapper.py : Wrapper functions to receive data from IB. 9 | 10 | These codes have been tested on gateway Build 952.2f and TWS and **ONLY on paper trading account**. Please carry out your own test on your own account.It is best to be read in conjuction with the [IB Java API](http://interactivebrokers.github.io/tws-api/#gsc.tab=0) manual. 11 | 12 | # IbPy - Interactive Brokers Python API 13 | [IbPy](https://github.com/blampe/IbPy) was originally written by Troy Melhase. 14 | 15 | IB TWS and Gateway can be obtained via [IB website](https://www.interactivebrokers.com.hk/en/index.php?f=16042) 16 | 17 | # Introduction 18 | [Interactive Brokers](https://www.interactivebrokers.com/en/index.php?f=14839&ns=T) offers a trading lab for education institution. 19 | 20 | The instructor receives a "master" account with the ability to view all the students account information. However, as our class size often varies from 20 to 40, extracting key information from each account can be tedious and time consuming. Hence the reason for turning to IB API and writing these codes. The students' Net Liquidation Value (NLV) are download automatically and posted to [plotly](https://plot.ly/) 21 | 22 | It allows the students to view each others' NLV. Naturally, this encourages competition, learning and camaraderie as well as communication and sharing. You can find a sample notebook [here](http://nbviewer.jupyter.org/github/anthonyng2/ib/blob/master/FTC_NLV_Demo.ipynb) 23 | 24 | The following example is a great way to start. However, if you are comfortable with Python and Pandas, you can check out this [Jupyter tutorial](https://nbviewer.jupyter.org/github/anthonyng2/ib/blob/master/IbPy%20Demo.ipynb) 25 | 26 | # Example 27 | Below is a sample code snippets for Account and Portfolio Group. Best to leave the portion prior to Account and Portfolio alone as it sets up the necessary state to receive information from IB. 28 | 29 | 30 | import time 31 | from datetime import datetime 32 | from IBWrapper import IBWrapper, contract 33 | from ib.ext.EClientSocket import EClientSocket 34 | from ib.ext.ScannerSubscription import ScannerSubscription 35 | 36 | if __name__=="__main__": 37 | callback = IBWrapper() # Instantiate IBWrapper 38 | tws = EClientSocket(callback) # Instantiate EClientSocket 39 | host = "" 40 | port = 7496 41 | clientId = 5000 42 | tws.eConnect(host, port, clientId) # Connect to TWS 43 | tws.setServerLogLevel(5) 44 | accountName = "DU123456" # Make sure you use your own 45 | create = contract() # Instantiate contract class 46 | 47 | # Initiate attributes to receive data. At some point we need a separate class for this 48 | callback.initiate_variables() 49 | 50 | # Account and Portfolio ############################################################## 51 | # reqAccountUpdates ---> updateAccountTime self.update_AccountTime 52 | # updateAccountValue self.update_AccountValue 53 | # updatePortfolio self.update_Portfolio 54 | # accountDownloadEnd self.accountDownloadEnd_flag 55 | # reqAccountSummary ---> accountSummary self.account_Summary 56 | # cancelAccountSummary 57 | # accountSummaryEnd self.account_SummaryEnd_flag 58 | # reqPositions ---> position self.update_Position 59 | # cancelPositions 60 | # positionEnd self.positionEnd_flag 61 | ###################################################################################### 62 | print "Testing Account and Portfolio \n" 63 | #tws.reqAccountUpdates(1, accountName) 64 | tws.reqAccountSummary(1,"All","NetLiquidation") 65 | #tws.reqPositions() 66 | time.sleep(2) 67 | 68 | The following is the output 69 | 70 | Server Version: 76 71 | TWS Time at connection:20160202 09:33:21 SGT 72 | Testing Account and Portfolio 73 | 74 | 75 | In [4]: callback.account_Summary 76 | Out[4]: 77 | [(1, 'DI123456', 'NetLiquidation', '1012293.85', 'USD'), 78 | (1, 'DU123456', 'NetLiquidation', '803908.12', 'USD'), 79 | ... 80 | (1, 'DU123457', 'NetLiquidation', '831895.74', 'USD'), 81 | (1, 'DU123458', 'NetLiquidation', '1149361.71', 'USD'), 82 | (1, 'DU123459', 'NetLiquidation', '895145.61', 'USD'), 83 | (1, 'DU123460', 'NetLiquidation', '981381.33', 'USD')] 84 | 85 | 86 | I'm very interested in your experience with the code. Please do drop me a note with any feedback you may have. 87 | 88 | Anthony Ng 89 | 90 | 91 | Look for me @ [https://www.algo-hunter.com](https://www.algo-hunter.com) 92 | -------------------------------------------------------------------------------- /Vol1 IB Python Practical Implementation Guide - Draft.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anthonyng2/ib/40c06bf4b1e16092dd22ee61d49b1794e034d01b/Vol1 IB Python Practical Implementation Guide - Draft.pdf -------------------------------------------------------------------------------- /Vol3 IB JAVA API Guide - Draft v2016-01-19 .pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anthonyng2/ib/40c06bf4b1e16092dd22ee61d49b1794e034d01b/Vol3 IB JAVA API Guide - Draft v2016-01-19 .pdf -------------------------------------------------------------------------------- /ib-insync notebooks/contract_details.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Contract details\n", 8 | "-------------------" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "metadata": {}, 15 | "outputs": [ 16 | { 17 | "name": "stderr", 18 | "output_type": "stream", 19 | "text": [ 20 | "ERROR:ib_insync.wrapper:Error 321, reqId 1: Error validating request:-'aS' : cause - ALL account is not supported\n" 21 | ] 22 | }, 23 | { 24 | "data": { 25 | "text/plain": [ 26 | "" 27 | ] 28 | }, 29 | "execution_count": 1, 30 | "metadata": {}, 31 | "output_type": "execute_result" 32 | } 33 | ], 34 | "source": [ 35 | "from ib_insync import *\n", 36 | "util.startLoop()\n", 37 | "\n", 38 | "ib = IB()\n", 39 | "ib.connect('127.0.0.1', 4002, clientId=2)" 40 | ] 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "metadata": {}, 45 | "source": [ 46 | "Suppose we want to find the contract details for AMD stock.\n", 47 | "Let's create a stock object and request the details for it:" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 2, 53 | "metadata": {}, 54 | "outputs": [ 55 | { 56 | "data": { 57 | "text/plain": [ 58 | "30" 59 | ] 60 | }, 61 | "execution_count": 2, 62 | "metadata": {}, 63 | "output_type": "execute_result" 64 | } 65 | ], 66 | "source": [ 67 | "amd = Stock('AMD')\n", 68 | "\n", 69 | "cds = ib.reqContractDetails(amd)\n", 70 | "\n", 71 | "len(cds)" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": {}, 77 | "source": [ 78 | "We get a long list of contract details. Lets print the first one:" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": 3, 84 | "metadata": {}, 85 | "outputs": [ 86 | { 87 | "data": { 88 | "text/plain": [ 89 | "ContractDetails(summary=Contract(secType='STK', conId=4391, symbol='AMD', exchange='SMART', primaryExchange='NASDAQ', currency='USD', localSymbol='AMD', tradingClass='SCM'), marketName='SCM', minTick=0.01, orderTypes='ACTIVETIM,ADJUST,ALERT,ALGO,ALLOC,AON,AVGCOST,BASKET,COND,CONDORDER,DARKONLY,DARKPOLL,DAY,DEACT,DEACTDIS,DEACTEOD,DIS,GAT,GTC,GTD,GTT,HID,IBKRATS,ICE,IMB,IOC,LIT,LMT,LOC,MIT,MKT,MOC,MTL,NGCOMB,NODARK,NONALGO,OCA,OPG,OPGREROUT,PEGBENCH,POSTONLY,PREOPGRTH,REL,RPI,RTH,SCALE,SCALEODD,SCALERST,SNAPMID,SNAPMKT,SNAPREL,SOLICITED,STP,STPLMT,SWEEP,TRAIL,TRAILLIT,TRAILLMT,TRAILMIT,WHATIF', validExchanges='SMART,AMEX,NYSE,CBOE,ISE,CHX,ARCA,ISLAND,VWAP,DRCTEDGE,BEX,BATS,EDGEA,CSFBALGO,JEFFALGO,BYX,IEX,TPLUS1,NYSENAT,PSX', priceMagnifier=1, longName='ADVANCED MICRO DEVICES', industry='Technology', category='Semiconductors', subcategory='Electronic Compo-Semicon', timeZoneId='EST', tradingHours='20180622:0400-2000;20180625:0400-2000', liquidHours='20180622:0930-1600;20180625:0930-1600', mdSizeMultiplier=100)" 90 | ] 91 | }, 92 | "execution_count": 3, 93 | "metadata": {}, 94 | "output_type": "execute_result" 95 | } 96 | ], 97 | "source": [ 98 | "cds[0]" 99 | ] 100 | }, 101 | { 102 | "cell_type": "markdown", 103 | "metadata": {}, 104 | "source": [ 105 | "The contract itself is in the 'summary' property of the contract details. Lets make a list of contracts and look at the first:" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": 4, 111 | "metadata": {}, 112 | "outputs": [ 113 | { 114 | "data": { 115 | "text/plain": [ 116 | "Contract(secType='STK', conId=4391, symbol='AMD', exchange='SMART', primaryExchange='NASDAQ', currency='USD', localSymbol='AMD', tradingClass='SCM')" 117 | ] 118 | }, 119 | "execution_count": 4, 120 | "metadata": {}, 121 | "output_type": "execute_result" 122 | } 123 | ], 124 | "source": [ 125 | "contracts = [cd.summary for cd in cds]\n", 126 | "\n", 127 | "contracts[0]" 128 | ] 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "metadata": {}, 133 | "source": [ 134 | "To better spot the difference between all the contracts it's handy to convert to a DataFrame. There is a utility function to do that:" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": 5, 140 | "metadata": {}, 141 | "outputs": [ 142 | { 143 | "data": { 144 | "text/html": [ 145 | "
\n", 146 | "\n", 159 | "\n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | " \n", 237 | " \n", 238 | " \n", 239 | " \n", 240 | " \n", 241 | " \n", 242 | " \n", 243 | " \n", 244 | " \n", 245 | " \n", 246 | " \n", 247 | " \n", 248 | " \n", 249 | " \n", 250 | " \n", 251 | " \n", 252 | " \n", 253 | " \n", 254 | " \n", 255 | " \n", 256 | " \n", 257 | " \n", 258 | " \n", 259 | " \n", 260 | " \n", 261 | " \n", 262 | " \n", 263 | " \n", 264 | " \n", 265 | " \n", 266 | " \n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | " \n", 301 | " \n", 302 | " \n", 303 | " \n", 304 | " \n", 305 | " \n", 306 | " \n", 307 | " \n", 308 | " \n", 309 | " \n", 310 | " \n", 311 | " \n", 312 | " \n", 313 | " \n", 314 | " \n", 315 | " \n", 316 | " \n", 317 | " \n", 318 | " \n", 319 | " \n", 320 | " \n", 321 | " \n", 322 | " \n", 323 | " \n", 324 | " \n", 325 | " \n", 326 | " \n", 327 | " \n", 328 | " \n", 329 | " \n", 330 | " \n", 331 | " \n", 332 | " \n", 333 | " \n", 334 | " \n", 335 | " \n", 336 | " \n", 337 | " \n", 338 | " \n", 339 | " \n", 340 | " \n", 341 | " \n", 342 | " \n", 343 | " \n", 344 | " \n", 345 | " \n", 346 | " \n", 347 | " \n", 348 | " \n", 349 | " \n", 350 | " \n", 351 | " \n", 352 | " \n", 353 | " \n", 354 | " \n", 355 | " \n", 356 | " \n", 357 | " \n", 358 | " \n", 359 | " \n", 360 | " \n", 361 | " \n", 362 | " \n", 363 | " \n", 364 | " \n", 365 | " \n", 366 | " \n", 367 | " \n", 368 | " \n", 369 | " \n", 370 | " \n", 371 | " \n", 372 | " \n", 373 | " \n", 374 | " \n", 375 | " \n", 376 | " \n", 377 | " \n", 378 | " \n", 379 | " \n", 380 | " \n", 381 | " \n", 382 | " \n", 383 | " \n", 384 | " \n", 385 | " \n", 386 | " \n", 387 | " \n", 388 | " \n", 389 | " \n", 390 | " \n", 391 | " \n", 392 | " \n", 393 | " \n", 394 | " \n", 395 | " \n", 396 | " \n", 397 | " \n", 398 | " \n", 399 | " \n", 400 | " \n", 401 | " \n", 402 | " \n", 403 | " \n", 404 | " \n", 405 | " \n", 406 | " \n", 407 | " \n", 408 | " \n", 409 | " \n", 410 | " \n", 411 | " \n", 412 | " \n", 413 | " \n", 414 | " \n", 415 | " \n", 416 | " \n", 417 | " \n", 418 | " \n", 419 | " \n", 420 | " \n", 421 | " \n", 422 | " \n", 423 | " \n", 424 | " \n", 425 | " \n", 426 | " \n", 427 | " \n", 428 | " \n", 429 | " \n", 430 | " \n", 431 | " \n", 432 | " \n", 433 | " \n", 434 | " \n", 435 | " \n", 436 | " \n", 437 | " \n", 438 | " \n", 439 | " \n", 440 | " \n", 441 | " \n", 442 | " \n", 443 | " \n", 444 | " \n", 445 | " \n", 446 | " \n", 447 | " \n", 448 | " \n", 449 | " \n", 450 | " \n", 451 | " \n", 452 | " \n", 453 | " \n", 454 | " \n", 455 | " \n", 456 | " \n", 457 | " \n", 458 | " \n", 459 | " \n", 460 | " \n", 461 | " \n", 462 | " \n", 463 | " \n", 464 | " \n", 465 | " \n", 466 | " \n", 467 | " \n", 468 | " \n", 469 | " \n", 470 | " \n", 471 | " \n", 472 | " \n", 473 | " \n", 474 | " \n", 475 | " \n", 476 | " \n", 477 | " \n", 478 | " \n", 479 | " \n", 480 | " \n", 481 | " \n", 482 | " \n", 483 | " \n", 484 | " \n", 485 | " \n", 486 | " \n", 487 | " \n", 488 | " \n", 489 | " \n", 490 | " \n", 491 | " \n", 492 | " \n", 493 | " \n", 494 | " \n", 495 | " \n", 496 | " \n", 497 | " \n", 498 | " \n", 499 | " \n", 500 | " \n", 501 | " \n", 502 | " \n", 503 | " \n", 504 | " \n", 505 | " \n", 506 | " \n", 507 | " \n", 508 | " \n", 509 | " \n", 510 | " \n", 511 | " \n", 512 | " \n", 513 | " \n", 514 | " \n", 515 | " \n", 516 | " \n", 517 | " \n", 518 | " \n", 519 | " \n", 520 | " \n", 521 | " \n", 522 | " \n", 523 | " \n", 524 | " \n", 525 | " \n", 526 | " \n", 527 | " \n", 528 | " \n", 529 | " \n", 530 | " \n", 531 | " \n", 532 | " \n", 533 | " \n", 534 | " \n", 535 | " \n", 536 | " \n", 537 | " \n", 538 | " \n", 539 | " \n", 540 | " \n", 541 | " \n", 542 | " \n", 543 | " \n", 544 | " \n", 545 | " \n", 546 | " \n", 547 | " \n", 548 | " \n", 549 | " \n", 550 | " \n", 551 | " \n", 552 | " \n", 553 | " \n", 554 | " \n", 555 | " \n", 556 | " \n", 557 | " \n", 558 | " \n", 559 | " \n", 560 | " \n", 561 | " \n", 562 | " \n", 563 | " \n", 564 | " \n", 565 | " \n", 566 | " \n", 567 | " \n", 568 | " \n", 569 | " \n", 570 | " \n", 571 | " \n", 572 | " \n", 573 | " \n", 574 | " \n", 575 | " \n", 576 | " \n", 577 | " \n", 578 | " \n", 579 | " \n", 580 | " \n", 581 | " \n", 582 | " \n", 583 | " \n", 584 | " \n", 585 | " \n", 586 | " \n", 587 | " \n", 588 | " \n", 589 | " \n", 590 | " \n", 591 | " \n", 592 | " \n", 593 | " \n", 594 | " \n", 595 | " \n", 596 | " \n", 597 | " \n", 598 | " \n", 599 | " \n", 600 | " \n", 601 | " \n", 602 | " \n", 603 | " \n", 604 | " \n", 605 | " \n", 606 | " \n", 607 | " \n", 608 | " \n", 609 | " \n", 610 | " \n", 611 | " \n", 612 | " \n", 613 | " \n", 614 | " \n", 615 | " \n", 616 | " \n", 617 | " \n", 618 | " \n", 619 | " \n", 620 | " \n", 621 | " \n", 622 | " \n", 623 | " \n", 624 | " \n", 625 | " \n", 626 | " \n", 627 | " \n", 628 | " \n", 629 | " \n", 630 | " \n", 631 | " \n", 632 | " \n", 633 | " \n", 634 | " \n", 635 | " \n", 636 | " \n", 637 | " \n", 638 | " \n", 639 | " \n", 640 | " \n", 641 | " \n", 642 | " \n", 643 | " \n", 644 | " \n", 645 | " \n", 646 | " \n", 647 | " \n", 648 | " \n", 649 | " \n", 650 | " \n", 651 | " \n", 652 | " \n", 653 | " \n", 654 | " \n", 655 | " \n", 656 | " \n", 657 | " \n", 658 | " \n", 659 | " \n", 660 | " \n", 661 | " \n", 662 | " \n", 663 | " \n", 664 | " \n", 665 | " \n", 666 | " \n", 667 | " \n", 668 | " \n", 669 | " \n", 670 | " \n", 671 | " \n", 672 | " \n", 673 | " \n", 674 | " \n", 675 | " \n", 676 | " \n", 677 | " \n", 678 | " \n", 679 | " \n", 680 | " \n", 681 | " \n", 682 | " \n", 683 | " \n", 684 | " \n", 685 | " \n", 686 | " \n", 687 | " \n", 688 | " \n", 689 | " \n", 690 | " \n", 691 | " \n", 692 | " \n", 693 | " \n", 694 | " \n", 695 | " \n", 696 | " \n", 697 | " \n", 698 | " \n", 699 | " \n", 700 | " \n", 701 | " \n", 702 | " \n", 703 | " \n", 704 | " \n", 705 | " \n", 706 | " \n", 707 | " \n", 708 | " \n", 709 | " \n", 710 | " \n", 711 | " \n", 712 | " \n", 713 | " \n", 714 | " \n", 715 | " \n", 716 | " \n", 717 | " \n", 718 | " \n", 719 | " \n", 720 | " \n", 721 | " \n", 722 | " \n", 723 | " \n", 724 | " \n", 725 | " \n", 726 | " \n", 727 | " \n", 728 | " \n", 729 | " \n", 730 | " \n", 731 | " \n", 732 | " \n", 733 | " \n", 734 | " \n", 735 | " \n", 736 | " \n", 737 | " \n", 738 | " \n", 739 | " \n", 740 | " \n", 741 | " \n", 742 | " \n", 743 | " \n", 744 | " \n", 745 | " \n", 746 | " \n", 747 | " \n", 748 | " \n", 749 | " \n", 750 | " \n", 751 | " \n", 752 | " \n", 753 | " \n", 754 | " \n", 755 | " \n", 756 | " \n", 757 | " \n", 758 | " \n", 759 | " \n", 760 | " \n", 761 | " \n", 762 | " \n", 763 | " \n", 764 | " \n", 765 | " \n", 766 | " \n", 767 | " \n", 768 | " \n", 769 | " \n", 770 | " \n", 771 | " \n", 772 | " \n", 773 | " \n", 774 | " \n", 775 | " \n", 776 | " \n", 777 | " \n", 778 | " \n", 779 | " \n", 780 | " \n", 781 | " \n", 782 | " \n", 783 | " \n", 784 | " \n", 785 | " \n", 786 | " \n", 787 | " \n", 788 | " \n", 789 | " \n", 790 | " \n", 791 | " \n", 792 | " \n", 793 | " \n", 794 | " \n", 795 | " \n", 796 | " \n", 797 | " \n", 798 | " \n", 799 | " \n", 800 | " \n", 801 | " \n", 802 | " \n", 803 | " \n", 804 | " \n", 805 | " \n", 806 | " \n", 807 | " \n", 808 | " \n", 809 | " \n", 810 | " \n", 811 | " \n", 812 | " \n", 813 | " \n", 814 | " \n", 815 | "
secTypeconIdsymbollastTradeDateOrContractMonthstrikerightmultiplierexchangeprimaryExchangecurrencylocalSymboltradingClassincludeExpiredsecIdTypesecIdcomboLegsDescripcomboLegsunderComp
0STK4391AMD0.0SMARTNASDAQUSDAMDSCMFalseNoneNone
1STK4391AMD0.0AMEXNASDAQUSDAMDSCMFalseNoneNone
2STK32596680AMD0.0SMARTIBISEURAMDUSSTARSFalseNoneNone
3STK4391AMD0.0NYSENASDAQUSDAMDSCMFalseNoneNone
4STK4391AMD0.0CBOENASDAQUSDAMDSCMFalseNoneNone
5STK4391AMD0.0ISENASDAQUSDAMDSCMFalseNoneNone
6STK4391AMD0.0CHXNASDAQUSDAMDSCMFalseNoneNone
7STK4391AMD0.0ARCANASDAQUSDAMDSCMFalseNoneNone
8STK4391AMD0.0ISLANDNASDAQUSDAMDSCMFalseNoneNone
9STK4391AMD0.0DRCTEDGENASDAQUSDAMDSCMFalseNoneNone
10STK4391AMD0.0BEXNASDAQUSDAMDSCMFalseNoneNone
11STK4391AMD0.0BATSNASDAQUSDAMDSCMFalseNoneNone
12STK4391AMD0.0EDGEANASDAQUSDAMDSCMFalseNoneNone
13STK4391AMD0.0CSFBALGONASDAQUSDAMDSCMFalseNoneNone
14STK4391AMD0.0JEFFALGONASDAQUSDAMDSCMFalseNoneNone
15STK4391AMD0.0BYXNASDAQUSDAMDSCMFalseNoneNone
16STK4391AMD0.0IEXNASDAQUSDAMDSCMFalseNoneNone
17STK4391AMD0.0TPLUS1NASDAQUSDAMDSCMFalseNoneNone
18STK4391AMD0.0NYSENATNASDAQUSDAMDSCMFalseNoneNone
19STK4391AMD0.0PSXNASDAQUSDAMDSCMFalseNoneNone
20STK32596680AMD0.0FWBIBISEURAMDUSSTARSFalseNoneNone
21STK32596680AMD0.0IBISIBISEURAMDUSSTARSFalseNoneNone
22STK32596680AMD0.0BVMEIBISEURAMDAMDFalseNoneNone
23STK32596680AMD0.0SWBIBISEURAMDXETRAFalseNoneNone
24STK32596680AMD0.0TGATEIBISEURAMDAMDFalseNoneNone
25STK48818298AMD0.0MEXIMEXIMXNAMDAMDFalseNoneNone
26STK172603743AMD0.0EBSEBSCHFAMDAMDFalseNoneNone
27STK298633607AMD0.0ASXASXAUDAMDAMDFalseNoneNone
28STK172603743AMD0.0SMARTEBSCHFAMDAMDFalseNoneNone
29STK298633607AMD0.0SMARTASXAUDAMDAMDFalseNoneNone
\n", 816 | "
" 817 | ], 818 | "text/plain": [ 819 | " secType conId symbol lastTradeDateOrContractMonth strike right \\\n", 820 | "0 STK 4391 AMD 0.0 \n", 821 | "1 STK 4391 AMD 0.0 \n", 822 | "2 STK 32596680 AMD 0.0 \n", 823 | "3 STK 4391 AMD 0.0 \n", 824 | "4 STK 4391 AMD 0.0 \n", 825 | "5 STK 4391 AMD 0.0 \n", 826 | "6 STK 4391 AMD 0.0 \n", 827 | "7 STK 4391 AMD 0.0 \n", 828 | "8 STK 4391 AMD 0.0 \n", 829 | "9 STK 4391 AMD 0.0 \n", 830 | "10 STK 4391 AMD 0.0 \n", 831 | "11 STK 4391 AMD 0.0 \n", 832 | "12 STK 4391 AMD 0.0 \n", 833 | "13 STK 4391 AMD 0.0 \n", 834 | "14 STK 4391 AMD 0.0 \n", 835 | "15 STK 4391 AMD 0.0 \n", 836 | "16 STK 4391 AMD 0.0 \n", 837 | "17 STK 4391 AMD 0.0 \n", 838 | "18 STK 4391 AMD 0.0 \n", 839 | "19 STK 4391 AMD 0.0 \n", 840 | "20 STK 32596680 AMD 0.0 \n", 841 | "21 STK 32596680 AMD 0.0 \n", 842 | "22 STK 32596680 AMD 0.0 \n", 843 | "23 STK 32596680 AMD 0.0 \n", 844 | "24 STK 32596680 AMD 0.0 \n", 845 | "25 STK 48818298 AMD 0.0 \n", 846 | "26 STK 172603743 AMD 0.0 \n", 847 | "27 STK 298633607 AMD 0.0 \n", 848 | "28 STK 172603743 AMD 0.0 \n", 849 | "29 STK 298633607 AMD 0.0 \n", 850 | "\n", 851 | " multiplier exchange primaryExchange currency localSymbol tradingClass \\\n", 852 | "0 SMART NASDAQ USD AMD SCM \n", 853 | "1 AMEX NASDAQ USD AMD SCM \n", 854 | "2 SMART IBIS EUR AMD USSTARS \n", 855 | "3 NYSE NASDAQ USD AMD SCM \n", 856 | "4 CBOE NASDAQ USD AMD SCM \n", 857 | "5 ISE NASDAQ USD AMD SCM \n", 858 | "6 CHX NASDAQ USD AMD SCM \n", 859 | "7 ARCA NASDAQ USD AMD SCM \n", 860 | "8 ISLAND NASDAQ USD AMD SCM \n", 861 | "9 DRCTEDGE NASDAQ USD AMD SCM \n", 862 | "10 BEX NASDAQ USD AMD SCM \n", 863 | "11 BATS NASDAQ USD AMD SCM \n", 864 | "12 EDGEA NASDAQ USD AMD SCM \n", 865 | "13 CSFBALGO NASDAQ USD AMD SCM \n", 866 | "14 JEFFALGO NASDAQ USD AMD SCM \n", 867 | "15 BYX NASDAQ USD AMD SCM \n", 868 | "16 IEX NASDAQ USD AMD SCM \n", 869 | "17 TPLUS1 NASDAQ USD AMD SCM \n", 870 | "18 NYSENAT NASDAQ USD AMD SCM \n", 871 | "19 PSX NASDAQ USD AMD SCM \n", 872 | "20 FWB IBIS EUR AMD USSTARS \n", 873 | "21 IBIS IBIS EUR AMD USSTARS \n", 874 | "22 BVME IBIS EUR AMD AMD \n", 875 | "23 SWB IBIS EUR AMD XETRA \n", 876 | "24 TGATE IBIS EUR AMD AMD \n", 877 | "25 MEXI MEXI MXN AMD AMD \n", 878 | "26 EBS EBS CHF AMD AMD \n", 879 | "27 ASX ASX AUD AMD AMD \n", 880 | "28 SMART EBS CHF AMD AMD \n", 881 | "29 SMART ASX AUD AMD AMD \n", 882 | "\n", 883 | " includeExpired secIdType secId comboLegsDescrip comboLegs underComp \n", 884 | "0 False None None \n", 885 | "1 False None None \n", 886 | "2 False None None \n", 887 | "3 False None None \n", 888 | "4 False None None \n", 889 | "5 False None None \n", 890 | "6 False None None \n", 891 | "7 False None None \n", 892 | "8 False None None \n", 893 | "9 False None None \n", 894 | "10 False None None \n", 895 | "11 False None None \n", 896 | "12 False None None \n", 897 | "13 False None None \n", 898 | "14 False None None \n", 899 | "15 False None None \n", 900 | "16 False None None \n", 901 | "17 False None None \n", 902 | "18 False None None \n", 903 | "19 False None None \n", 904 | "20 False None None \n", 905 | "21 False None None \n", 906 | "22 False None None \n", 907 | "23 False None None \n", 908 | "24 False None None \n", 909 | "25 False None None \n", 910 | "26 False None None \n", 911 | "27 False None None \n", 912 | "28 False None None \n", 913 | "29 False None None " 914 | ] 915 | }, 916 | "execution_count": 5, 917 | "metadata": {}, 918 | "output_type": "execute_result" 919 | } 920 | ], 921 | "source": [ 922 | "util.df(contracts)" 923 | ] 924 | }, 925 | { 926 | "cell_type": "markdown", 927 | "metadata": {}, 928 | "source": [ 929 | "Or use a dict comprehension of set comprehensions..." 930 | ] 931 | }, 932 | { 933 | "cell_type": "code", 934 | "execution_count": 6, 935 | "metadata": {}, 936 | "outputs": [ 937 | { 938 | "data": { 939 | "text/plain": [ 940 | "{'comboLegs': {None},\n", 941 | " 'comboLegsDescrip': {''},\n", 942 | " 'conId': {4391, 32596680, 48818298, 172603743, 298633607},\n", 943 | " 'currency': {'AUD', 'CHF', 'EUR', 'MXN', 'USD'},\n", 944 | " 'exchange': {'AMEX',\n", 945 | " 'ARCA',\n", 946 | " 'ASX',\n", 947 | " 'BATS',\n", 948 | " 'BEX',\n", 949 | " 'BVME',\n", 950 | " 'BYX',\n", 951 | " 'CBOE',\n", 952 | " 'CHX',\n", 953 | " 'CSFBALGO',\n", 954 | " 'DRCTEDGE',\n", 955 | " 'EBS',\n", 956 | " 'EDGEA',\n", 957 | " 'FWB',\n", 958 | " 'IBIS',\n", 959 | " 'IEX',\n", 960 | " 'ISE',\n", 961 | " 'ISLAND',\n", 962 | " 'JEFFALGO',\n", 963 | " 'MEXI',\n", 964 | " 'NYSE',\n", 965 | " 'NYSENAT',\n", 966 | " 'PSX',\n", 967 | " 'SMART',\n", 968 | " 'SWB',\n", 969 | " 'TGATE',\n", 970 | " 'TPLUS1'},\n", 971 | " 'includeExpired': {False},\n", 972 | " 'lastTradeDateOrContractMonth': {''},\n", 973 | " 'localSymbol': {'AMD'},\n", 974 | " 'multiplier': {''},\n", 975 | " 'primaryExchange': {'ASX', 'EBS', 'IBIS', 'MEXI', 'NASDAQ'},\n", 976 | " 'right': {''},\n", 977 | " 'secId': {''},\n", 978 | " 'secIdType': {''},\n", 979 | " 'secType': {'STK'},\n", 980 | " 'strike': {0.0},\n", 981 | " 'symbol': {'AMD'},\n", 982 | " 'tradingClass': {'AMD', 'SCM', 'USSTARS', 'XETRA'},\n", 983 | " 'underComp': {None}}" 984 | ] 985 | }, 986 | "execution_count": 6, 987 | "metadata": {}, 988 | "output_type": "execute_result" 989 | } 990 | ], 991 | "source": [ 992 | "{key: set(getattr(c, key) for c in contracts) for key in Contract.defaults}" 993 | ] 994 | }, 995 | { 996 | "cell_type": "markdown", 997 | "metadata": {}, 998 | "source": [ 999 | "We can see from this that AMD trades in different currencies on different exchanges.\n", 1000 | "Suppose we want the one in USD on the SMART exchange. The AMD contract is adjusted to\n", 1001 | "reflect that and becomes unique:" 1002 | ] 1003 | }, 1004 | { 1005 | "cell_type": "code", 1006 | "execution_count": 10, 1007 | "metadata": {}, 1008 | "outputs": [], 1009 | "source": [ 1010 | "amd = Stock('AMD', 'SMART', 'USD')\n", 1011 | "\n", 1012 | "assert len(ib.reqContractDetails(amd)) == 1" 1013 | ] 1014 | }, 1015 | { 1016 | "cell_type": "code", 1017 | "execution_count": 8, 1018 | "metadata": {}, 1019 | "outputs": [ 1020 | { 1021 | "data": { 1022 | "text/plain": [ 1023 | "Stock(symbol='AMD', exchange='SMART', currency='USD')" 1024 | ] 1025 | }, 1026 | "execution_count": 8, 1027 | "metadata": {}, 1028 | "output_type": "execute_result" 1029 | } 1030 | ], 1031 | "source": [ 1032 | "amd" 1033 | ] 1034 | }, 1035 | { 1036 | "cell_type": "markdown", 1037 | "metadata": {}, 1038 | "source": [ 1039 | "Lets try the same for Intel:" 1040 | ] 1041 | }, 1042 | { 1043 | "cell_type": "code", 1044 | "execution_count": 11, 1045 | "metadata": {}, 1046 | "outputs": [], 1047 | "source": [ 1048 | "intc = Stock('INTC', 'SMART', 'USD')\n", 1049 | "\n", 1050 | "assert len(ib.reqContractDetails(intc)) == 1" 1051 | ] 1052 | }, 1053 | { 1054 | "cell_type": "markdown", 1055 | "metadata": {}, 1056 | "source": [ 1057 | "Let's try a non-existing contract:" 1058 | ] 1059 | }, 1060 | { 1061 | "cell_type": "code", 1062 | "execution_count": 12, 1063 | "metadata": {}, 1064 | "outputs": [ 1065 | { 1066 | "name": "stderr", 1067 | "output_type": "stream", 1068 | "text": [ 1069 | "ERROR:ib_insync.wrapper:Error 200, reqId 8: No security definition has been found for the request\n" 1070 | ] 1071 | } 1072 | ], 1073 | "source": [ 1074 | "xxx = Stock('XXX', 'SMART', 'USD')\n", 1075 | "\n", 1076 | "assert len(ib.reqContractDetails(xxx)) == 0" 1077 | ] 1078 | }, 1079 | { 1080 | "cell_type": "markdown", 1081 | "metadata": {}, 1082 | "source": [ 1083 | "or a Forex contract" 1084 | ] 1085 | }, 1086 | { 1087 | "cell_type": "code", 1088 | "execution_count": 13, 1089 | "metadata": {}, 1090 | "outputs": [], 1091 | "source": [ 1092 | "eurusd = Forex('EURUSD')\n", 1093 | "\n", 1094 | "assert len(ib.reqContractDetails(eurusd)) == 1" 1095 | ] 1096 | }, 1097 | { 1098 | "cell_type": "markdown", 1099 | "metadata": {}, 1100 | "source": [ 1101 | "With the ``qualifyContracts`` method the extra information that is send back\n", 1102 | "from the contract details request is used to fill in the original contracts.\n", 1103 | "\n", 1104 | "Lets do that with ``amd`` and compare before and aftwards:" 1105 | ] 1106 | }, 1107 | { 1108 | "cell_type": "code", 1109 | "execution_count": 14, 1110 | "metadata": {}, 1111 | "outputs": [ 1112 | { 1113 | "data": { 1114 | "text/plain": [ 1115 | "Stock(symbol='AMD', exchange='SMART', currency='USD')" 1116 | ] 1117 | }, 1118 | "execution_count": 14, 1119 | "metadata": {}, 1120 | "output_type": "execute_result" 1121 | } 1122 | ], 1123 | "source": [ 1124 | "amd" 1125 | ] 1126 | }, 1127 | { 1128 | "cell_type": "code", 1129 | "execution_count": 15, 1130 | "metadata": {}, 1131 | "outputs": [ 1132 | { 1133 | "data": { 1134 | "text/plain": [ 1135 | "Stock(conId=4391, symbol='AMD', exchange='SMART', primaryExchange='NASDAQ', currency='USD', localSymbol='AMD', tradingClass='SCM')" 1136 | ] 1137 | }, 1138 | "execution_count": 15, 1139 | "metadata": {}, 1140 | "output_type": "execute_result" 1141 | } 1142 | ], 1143 | "source": [ 1144 | "ib.qualifyContracts(amd)\n", 1145 | "amd" 1146 | ] 1147 | }, 1148 | { 1149 | "cell_type": "markdown", 1150 | "metadata": {}, 1151 | "source": [ 1152 | "**TIP:** When printing a contract, the output can be copy-pasted and it will be valid Python code.\n", 1153 | "\n", 1154 | "The ``conId`` that is returned can by itself be used to uniquely specify a contract:" 1155 | ] 1156 | }, 1157 | { 1158 | "cell_type": "code", 1159 | "execution_count": 16, 1160 | "metadata": {}, 1161 | "outputs": [], 1162 | "source": [ 1163 | "contract_4391 = Contract(conId=4391)\n", 1164 | "\n", 1165 | "ib.qualifyContracts(contract_4391)\n", 1166 | "\n", 1167 | "assert contract_4391 == amd" 1168 | ] 1169 | }, 1170 | { 1171 | "cell_type": "markdown", 1172 | "metadata": {}, 1173 | "source": [ 1174 | "A whole bunch of contracts can be qualified at the same time. A list of all the successfull ones is returned:" 1175 | ] 1176 | }, 1177 | { 1178 | "cell_type": "code", 1179 | "execution_count": 17, 1180 | "metadata": {}, 1181 | "outputs": [ 1182 | { 1183 | "name": "stderr", 1184 | "output_type": "stream", 1185 | "text": [ 1186 | "ERROR:ib_insync.wrapper:Error 200, reqId 14: No security definition has been found for the request\n", 1187 | "ERROR:ib_insync.ib:Unknown contract: Stock(symbol='XXX', exchange='SMART', currency='USD')\n" 1188 | ] 1189 | } 1190 | ], 1191 | "source": [ 1192 | "qualContracts = ib.qualifyContracts(amd, intc, xxx, eurusd)\n", 1193 | "\n", 1194 | "assert intc in qualContracts\n", 1195 | "assert xxx not in qualContracts" 1196 | ] 1197 | }, 1198 | { 1199 | "cell_type": "markdown", 1200 | "metadata": {}, 1201 | "source": [ 1202 | "There is also a new API function to request contracts that match a pattern:" 1203 | ] 1204 | }, 1205 | { 1206 | "cell_type": "code", 1207 | "execution_count": 18, 1208 | "metadata": {}, 1209 | "outputs": [ 1210 | { 1211 | "data": { 1212 | "text/plain": [ 1213 | "[Contract(secType='STK', conId=172096099, symbol='INTELLECT', primaryExchange='NSE', currency='INR'),\n", 1214 | " Contract(secType='STK', conId=38709539, symbol='INTC', primaryExchange='MEXI', currency='MXN'),\n", 1215 | " Contract(secType='STK', conId=11463493, symbol='INTC', primaryExchange='EBS', currency='USD'),\n", 1216 | " Contract(secType='STK', conId=12178234, symbol='INTC', primaryExchange='EBS', currency='CHF'),\n", 1217 | " Contract(secType='STK', conId=12177196, symbol='INL', primaryExchange='FWB', currency='EUR'),\n", 1218 | " Contract(secType='STK', conId=270639, symbol='INTC', primaryExchange='NASDAQ.NMS', currency='USD'),\n", 1219 | " Contract(secType='STK', conId=8988636, symbol='4335', primaryExchange='SEHK', currency='HKD'),\n", 1220 | " Contract(secType='STK', conId=165301734, symbol='601877', primaryExchange='SEHKNTL', currency='CNH'),\n", 1221 | " Contract(secType='STK', conId=257312042, symbol='002600', primaryExchange='SEHKSZSE', currency='CNH'),\n", 1222 | " Contract(secType='STK', conId=257311331, symbol='002050', primaryExchange='SEHKSZSE', currency='CNH'),\n", 1223 | " Contract(secType='STK', conId=280799963, symbol='300450', primaryExchange='CHINEXT', currency='CNH'),\n", 1224 | " Contract(secType='STK', conId=165302232, symbol='600545', primaryExchange='SEHKNTL', currency='CNH'),\n", 1225 | " Contract(secType='STK', conId=125919360, symbol='I', primaryExchange='NYSE', currency='USD'),\n", 1226 | " Contract(secType='STK', conId=257312978, symbol='300058', primaryExchange='CHINEXT', currency='CNH'),\n", 1227 | " Contract(secType='STK', conId=257311579, symbol='002711', primaryExchange='SEHKSZSE', currency='CNH'),\n", 1228 | " Contract(secType='STK', conId=257312028, symbol='000584', primaryExchange='SEHKSZSE', currency='CNH')]" 1229 | ] 1230 | }, 1231 | "execution_count": 18, 1232 | "metadata": {}, 1233 | "output_type": "execute_result" 1234 | } 1235 | ], 1236 | "source": [ 1237 | "matches = ib.reqMatchingSymbols('Intel')\n", 1238 | "matchContracts = [m.contract for m in matches]\n", 1239 | "\n", 1240 | "matchContracts" 1241 | ] 1242 | }, 1243 | { 1244 | "cell_type": "code", 1245 | "execution_count": 19, 1246 | "metadata": {}, 1247 | "outputs": [], 1248 | "source": [ 1249 | "assert intc in matchContracts" 1250 | ] 1251 | }, 1252 | { 1253 | "cell_type": "code", 1254 | "execution_count": 20, 1255 | "metadata": {}, 1256 | "outputs": [], 1257 | "source": [ 1258 | "ib.disconnect()" 1259 | ] 1260 | }, 1261 | { 1262 | "cell_type": "markdown", 1263 | "metadata": {}, 1264 | "source": [ 1265 | "***" 1266 | ] 1267 | } 1268 | ], 1269 | "metadata": { 1270 | "kernelspec": { 1271 | "display_name": "Python 3", 1272 | "language": "python", 1273 | "name": "python3" 1274 | }, 1275 | "language_info": { 1276 | "codemirror_mode": { 1277 | "name": "ipython", 1278 | "version": 3 1279 | }, 1280 | "file_extension": ".py", 1281 | "mimetype": "text/x-python", 1282 | "name": "python", 1283 | "nbconvert_exporter": "python", 1284 | "pygments_lexer": "ipython3", 1285 | "version": "3.6.4" 1286 | } 1287 | }, 1288 | "nbformat": 4, 1289 | "nbformat_minor": 2 1290 | } 1291 | -------------------------------------------------------------------------------- /ib-insync notebooks/market_depth.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Market depth (order book)\n", 8 | "==============" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 7, 14 | "metadata": {}, 15 | "outputs": [ 16 | { 17 | "name": "stderr", 18 | "output_type": "stream", 19 | "text": [ 20 | "ERROR:ib_insync.wrapper:Error 321, reqId 1: Error validating request:-'aS' : cause - ALL account is not supported\n" 21 | ] 22 | }, 23 | { 24 | "data": { 25 | "text/plain": [ 26 | "" 27 | ] 28 | }, 29 | "execution_count": 7, 30 | "metadata": {}, 31 | "output_type": "execute_result" 32 | } 33 | ], 34 | "source": [ 35 | "from ib_insync import *\n", 36 | "util.startLoop()\n", 37 | "\n", 38 | "ib = IB()\n", 39 | "ib.connect('127.0.0.1', 4002, clientId=16)" 40 | ] 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "metadata": {}, 45 | "source": [ 46 | "To get a list of all exchanges that support market depth data and display the first five:" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": 8, 52 | "metadata": {}, 53 | "outputs": [ 54 | { 55 | "data": { 56 | "text/plain": [ 57 | "[DepthMktDataDescription(exchange='DTB', secType='OPT'),\n", 58 | " DepthMktDataDescription(exchange='LSEETF', secType='STK'),\n", 59 | " DepthMktDataDescription(exchange='SGX', secType='FUT'),\n", 60 | " DepthMktDataDescription(exchange='ARCA', secType='STK'),\n", 61 | " DepthMktDataDescription(exchange='AEB', secType='IOPT')]" 62 | ] 63 | }, 64 | "execution_count": 8, 65 | "metadata": {}, 66 | "output_type": "execute_result" 67 | } 68 | ], 69 | "source": [ 70 | "l = ib.reqMktDepthExchanges()\n", 71 | "l[:5]" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": {}, 77 | "source": [ 78 | "Let's subscribe to market depth data for EURUSD:" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": 9, 84 | "metadata": {}, 85 | "outputs": [], 86 | "source": [ 87 | "contract = Forex('EURUSD')\n", 88 | "ib.qualifyContracts(contract)\n", 89 | "ticker = ib.reqMktDepth(contract)" 90 | ] 91 | }, 92 | { 93 | "cell_type": "markdown", 94 | "metadata": {}, 95 | "source": [ 96 | "To see the order book live updated:" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 11, 102 | "metadata": {}, 103 | "outputs": [ 104 | { 105 | "data": { 106 | "text/html": [ 107 | "
\n", 108 | "\n", 121 | "\n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | "
bidSizebidPriceaskPriceaskSize
035000001.163071.16311000000
1140000001.163051.163115500000
210000001.163041.163122000000
310000001.163031.163137500000
410000001.163021.163154500000
\n", 169 | "
" 170 | ], 171 | "text/plain": [ 172 | " bidSize bidPrice askPrice askSize\n", 173 | "0 3500000 1.16307 1.1631 1000000\n", 174 | "1 14000000 1.16305 1.16311 5500000\n", 175 | "2 1000000 1.16304 1.16312 2000000\n", 176 | "3 1000000 1.16303 1.16313 7500000\n", 177 | "4 1000000 1.16302 1.16315 4500000" 178 | ] 179 | }, 180 | "metadata": {}, 181 | "output_type": "display_data" 182 | } 183 | ], 184 | "source": [ 185 | "from IPython.display import display, clear_output\n", 186 | "import pandas as pd\n", 187 | "\n", 188 | "df = pd.DataFrame(index=range(5),\n", 189 | " columns='bidSize bidPrice askPrice askSize'.split())\n", 190 | "\n", 191 | "for t in ib.loopUntil(timeout=15):\n", 192 | " l = ticker.domBids\n", 193 | " for i in range(5):\n", 194 | " df.iloc[i, 0] = l[i].size if i < len(l) else 0\n", 195 | " df.iloc[i, 1] = l[i].price if i < len(l) else 0\n", 196 | " l = ticker.domAsks\n", 197 | " for i in range(5):\n", 198 | " df.iloc[i, 2] = l[i].price if i < len(l) else 0\n", 199 | " df.iloc[i, 3] = l[i].size if i < len(l) else 0\n", 200 | " clear_output(wait=True)\n", 201 | " display(df)" 202 | ] 203 | }, 204 | { 205 | "cell_type": "markdown", 206 | "metadata": {}, 207 | "source": [ 208 | "Stop the market depth subscription:" 209 | ] 210 | }, 211 | { 212 | "cell_type": "code", 213 | "execution_count": 12, 214 | "metadata": {}, 215 | "outputs": [], 216 | "source": [ 217 | "ib.cancelMktDepth(contract)" 218 | ] 219 | }, 220 | { 221 | "cell_type": "code", 222 | "execution_count": 13, 223 | "metadata": {}, 224 | "outputs": [], 225 | "source": [ 226 | "ib.disconnect()" 227 | ] 228 | }, 229 | { 230 | "cell_type": "markdown", 231 | "metadata": { 232 | "collapsed": true 233 | }, 234 | "source": [ 235 | "***" 236 | ] 237 | } 238 | ], 239 | "metadata": { 240 | "kernelspec": { 241 | "display_name": "Python 3", 242 | "language": "python", 243 | "name": "python3" 244 | }, 245 | "language_info": { 246 | "codemirror_mode": { 247 | "name": "ipython", 248 | "version": 3 249 | }, 250 | "file_extension": ".py", 251 | "mimetype": "text/x-python", 252 | "name": "python", 253 | "nbconvert_exporter": "python", 254 | "pygments_lexer": "ipython3", 255 | "version": "3.6.4" 256 | } 257 | }, 258 | "nbformat": 4, 259 | "nbformat_minor": 2 260 | } 261 | -------------------------------------------------------------------------------- /ib-insync notebooks/option_chain.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Option chains\n", 8 | "=======" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "metadata": { 15 | "scrolled": true 16 | }, 17 | "outputs": [ 18 | { 19 | "name": "stderr", 20 | "output_type": "stream", 21 | "text": [ 22 | "ERROR:ib_insync.wrapper:Error 321, reqId 1: Error validating request:-'aS' : cause - ALL account is not supported\n" 23 | ] 24 | }, 25 | { 26 | "data": { 27 | "text/plain": [ 28 | "" 29 | ] 30 | }, 31 | "execution_count": 1, 32 | "metadata": {}, 33 | "output_type": "execute_result" 34 | } 35 | ], 36 | "source": [ 37 | "from ib_insync import *\n", 38 | "util.startLoop()\n", 39 | "\n", 40 | "ib = IB()\n", 41 | "ib.connect('127.0.0.1', 4002, clientId=3)" 42 | ] 43 | }, 44 | { 45 | "cell_type": "markdown", 46 | "metadata": {}, 47 | "source": [ 48 | "Suppose we want to find the options on the SPY. There are two ways to do that:\n", 49 | "* The old way by requesting contract details\n", 50 | "* The new and faster way\n", 51 | "\n", 52 | "So first the old way. It starts with an ambiguous Option contract and uses that\n", 53 | "as a wildcard to get the details of all contracts that match:\n", 54 | "\n", 55 | "** This will take a while **" 56 | ] 57 | }, 58 | { 59 | "cell_type": "markdown", 60 | "metadata": { 61 | "heading_collapsed": true 62 | }, 63 | "source": [ 64 | "### Old Way" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": 8, 70 | "metadata": { 71 | "hidden": true 72 | }, 73 | "outputs": [ 74 | { 75 | "name": "stdout", 76 | "output_type": "stream", 77 | "text": [ 78 | "978\n" 79 | ] 80 | }, 81 | { 82 | "data": { 83 | "text/plain": [ 84 | "Contract(secType='OPT', conId=247623427, symbol='IBM', lastTradeDateOrContractMonth='20190118', strike=115.0, right='C', multiplier='100', exchange='SMART', currency='USD', localSymbol='IBM 190118C00115000', tradingClass='IBM')" 85 | ] 86 | }, 87 | "execution_count": 8, 88 | "metadata": {}, 89 | "output_type": "execute_result" 90 | } 91 | ], 92 | "source": [ 93 | "option = Option('IBM', exchange='SMART')\n", 94 | "cds = ib.reqContractDetails(option)\n", 95 | "\n", 96 | "contracts = [cd.summary for cd in cds]\n", 97 | "\n", 98 | "print(len(contracts))\n", 99 | "contracts[0]" 100 | ] 101 | }, 102 | { 103 | "cell_type": "markdown", 104 | "metadata": { 105 | "hidden": true 106 | }, 107 | "source": [ 108 | "So that's a few thousand contracts. Let's put in some restrictions to get this number down:\n", 109 | "\n", 110 | "* Use only the first 3 expirations after today that are on a Friday\n", 111 | "* Use only strike prices within +- 20 dollar of the current SPY market price\n", 112 | "* Use only strike prices that are a multitude of 5 dollar\n", 113 | "\n", 114 | "For the first restriction the expirations are filtered with an isFriday method,\n", 115 | "made unique with set(), then sorted and finally the first 3 taken:" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": 9, 121 | "metadata": { 122 | "hidden": true 123 | }, 124 | "outputs": [ 125 | { 126 | "data": { 127 | "text/plain": [ 128 | "['20180629', '20180706', '20180713']" 129 | ] 130 | }, 131 | "execution_count": 9, 132 | "metadata": {}, 133 | "output_type": "execute_result" 134 | } 135 | ], 136 | "source": [ 137 | "import datetime\n", 138 | "\n", 139 | "def isFriday(date):\n", 140 | " y = int(date[0:4])\n", 141 | " m = int(date[4:6])\n", 142 | " d = int(date[6:8])\n", 143 | " dd = datetime.date(y, m, d)\n", 144 | " return dd.weekday() == 4 and dd > datetime.date.today()\n", 145 | "\n", 146 | "expirations = sorted(set(c.lastTradeDateOrContractMonth for c in contracts\n", 147 | " if isFriday(c.lastTradeDateOrContractMonth)))[:3]\n", 148 | "\n", 149 | "expirations" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": { 155 | "hidden": true 156 | }, 157 | "source": [ 158 | "Hmmm... perhaps we could have just taken the next three Fridays?\n", 159 | "But the number of contracts is going down nicely:" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": 10, 165 | "metadata": { 166 | "hidden": true 167 | }, 168 | "outputs": [ 169 | { 170 | "name": "stdout", 171 | "output_type": "stream", 172 | "text": [ 173 | "214\n" 174 | ] 175 | } 176 | ], 177 | "source": [ 178 | "contracts = [c for c in contracts if c.lastTradeDateOrContractMonth in expirations]\n", 179 | "\n", 180 | "print(len(contracts))" 181 | ] 182 | }, 183 | { 184 | "cell_type": "markdown", 185 | "metadata": { 186 | "hidden": true 187 | }, 188 | "source": [ 189 | "To get the current price, first create the SPY contract:" 190 | ] 191 | }, 192 | { 193 | "cell_type": "code", 194 | "execution_count": 17, 195 | "metadata": { 196 | "hidden": true 197 | }, 198 | "outputs": [ 199 | { 200 | "data": { 201 | "text/plain": [ 202 | "[Stock(conId=8314, symbol='IBM', exchange='SMART', primaryExchange='NYSE', currency='USD', localSymbol='IBM', tradingClass='IBM')]" 203 | ] 204 | }, 205 | "execution_count": 17, 206 | "metadata": {}, 207 | "output_type": "execute_result" 208 | } 209 | ], 210 | "source": [ 211 | "ibm = Stock('IBM', exchange='SMART', primaryExchange='NYSE')\n", 212 | "\n", 213 | "ib.qualifyContracts(ibm)" 214 | ] 215 | }, 216 | { 217 | "cell_type": "markdown", 218 | "metadata": { 219 | "hidden": true 220 | }, 221 | "source": [ 222 | "Then get the ticker. Requesting a ticker can take up to 11 seconds." 223 | ] 224 | }, 225 | { 226 | "cell_type": "code", 227 | "execution_count": 18, 228 | "metadata": { 229 | "hidden": true 230 | }, 231 | "outputs": [ 232 | { 233 | "data": { 234 | "text/plain": [ 235 | "Ticker(contract=Stock(conId=8314, symbol='IBM', exchange='SMART', primaryExchange='NYSE', currency='USD', localSymbol='IBM', tradingClass='IBM'), time=datetime.datetime(2018, 6, 22, 5, 25, 33, 398320, tzinfo=datetime.timezone.utc), bid=-1.0, bidSize=0, ask=-1.0, askSize=0, close=141.25, ticks=[], tickByTicks=[], domBids=[], domAsks=[], domTicks=[])" 236 | ] 237 | }, 238 | "execution_count": 18, 239 | "metadata": {}, 240 | "output_type": "execute_result" 241 | } 242 | ], 243 | "source": [ 244 | "[ticker] = ib.reqTickers(ibm)\n", 245 | "\n", 246 | "ticker" 247 | ] 248 | }, 249 | { 250 | "cell_type": "markdown", 251 | "metadata": { 252 | "hidden": true 253 | }, 254 | "source": [ 255 | "Apply the final two restrictions:" 256 | ] 257 | }, 258 | { 259 | "cell_type": "code", 260 | "execution_count": 19, 261 | "metadata": { 262 | "hidden": true 263 | }, 264 | "outputs": [ 265 | { 266 | "data": { 267 | "text/plain": [ 268 | "141.25" 269 | ] 270 | }, 271 | "execution_count": 19, 272 | "metadata": {}, 273 | "output_type": "execute_result" 274 | } 275 | ], 276 | "source": [ 277 | "ticker.marketPrice()" 278 | ] 279 | }, 280 | { 281 | "cell_type": "code", 282 | "execution_count": 20, 283 | "metadata": { 284 | "hidden": true 285 | }, 286 | "outputs": [ 287 | { 288 | "name": "stdout", 289 | "output_type": "stream", 290 | "text": [ 291 | "48\n", 292 | "Contract(secType='OPT', conId=317355679, symbol='IBM', lastTradeDateOrContractMonth='20180629', strike=130.0, right='C', multiplier='100', exchange='SMART', currency='USD', localSymbol='IBM 180629C00130000', tradingClass='IBM')\n" 293 | ] 294 | } 295 | ], 296 | "source": [ 297 | "ibmPrice = ticker.marketPrice()\n", 298 | "\n", 299 | "contracts = [c for c in contracts if\n", 300 | " ibmPrice - 20 < c.strike < ibmPrice + 20 and\n", 301 | " c.strike % 5 == 0]\n", 302 | "\n", 303 | "print(len(contracts))\n", 304 | "print(contracts[0])\n", 305 | "\n", 306 | "oldContracts = contracts # remember for later" 307 | ] 308 | }, 309 | { 310 | "cell_type": "markdown", 311 | "metadata": { 312 | "heading_collapsed": true 313 | }, 314 | "source": [ 315 | "### New Way" 316 | ] 317 | }, 318 | { 319 | "cell_type": "markdown", 320 | "metadata": { 321 | "hidden": true 322 | }, 323 | "source": [ 324 | "Finally we have a list of usable option contracts.\n", 325 | "\n", 326 | "Okay so now the new and faster way:" 327 | ] 328 | }, 329 | { 330 | "cell_type": "code", 331 | "execution_count": 22, 332 | "metadata": { 333 | "hidden": true, 334 | "scrolled": true 335 | }, 336 | "outputs": [ 337 | { 338 | "data": { 339 | "text/html": [ 340 | "
\n", 341 | "\n", 354 | "\n", 355 | " \n", 356 | " \n", 357 | " \n", 358 | " \n", 359 | " \n", 360 | " \n", 361 | " \n", 362 | " \n", 363 | " \n", 364 | " \n", 365 | " \n", 366 | " \n", 367 | " \n", 368 | " \n", 369 | " \n", 370 | " \n", 371 | " \n", 372 | " \n", 373 | " \n", 374 | " \n", 375 | " \n", 376 | " \n", 377 | " \n", 378 | " \n", 379 | " \n", 380 | " \n", 381 | " \n", 382 | " \n", 383 | " \n", 384 | " \n", 385 | " \n", 386 | " \n", 387 | " \n", 388 | " \n", 389 | " \n", 390 | " \n", 391 | " \n", 392 | " \n", 393 | " \n", 394 | " \n", 395 | " \n", 396 | " \n", 397 | " \n", 398 | " \n", 399 | " \n", 400 | " \n", 401 | " \n", 402 | " \n", 403 | " \n", 404 | " \n", 405 | " \n", 406 | " \n", 407 | " \n", 408 | " \n", 409 | " \n", 410 | " \n", 411 | " \n", 412 | " \n", 413 | " \n", 414 | " \n", 415 | " \n", 416 | " \n", 417 | " \n", 418 | " \n", 419 | " \n", 420 | " \n", 421 | " \n", 422 | " \n", 423 | " \n", 424 | " \n", 425 | " \n", 426 | " \n", 427 | " \n", 428 | " \n", 429 | " \n", 430 | " \n", 431 | " \n", 432 | " \n", 433 | " \n", 434 | " \n", 435 | " \n", 436 | " \n", 437 | " \n", 438 | " \n", 439 | " \n", 440 | " \n", 441 | " \n", 442 | " \n", 443 | " \n", 444 | " \n", 445 | " \n", 446 | " \n", 447 | " \n", 448 | " \n", 449 | " \n", 450 | " \n", 451 | " \n", 452 | " \n", 453 | " \n", 454 | " \n", 455 | " \n", 456 | " \n", 457 | " \n", 458 | " \n", 459 | " \n", 460 | " \n", 461 | " \n", 462 | " \n", 463 | " \n", 464 | " \n", 465 | " \n", 466 | " \n", 467 | " \n", 468 | " \n", 469 | " \n", 470 | " \n", 471 | " \n", 472 | " \n", 473 | " \n", 474 | " \n", 475 | " \n", 476 | " \n", 477 | " \n", 478 | " \n", 479 | " \n", 480 | " \n", 481 | " \n", 482 | " \n", 483 | " \n", 484 | " \n", 485 | " \n", 486 | " \n", 487 | " \n", 488 | " \n", 489 | " \n", 490 | " \n", 491 | " \n", 492 | " \n", 493 | " \n", 494 | " \n", 495 | " \n", 496 | " \n", 497 | " \n", 498 | " \n", 499 | " \n", 500 | " \n", 501 | " \n", 502 | " \n", 503 | " \n", 504 | " \n", 505 | " \n", 506 | " \n", 507 | " \n", 508 | " \n", 509 | " \n", 510 | " \n", 511 | " \n", 512 | "
exchangeunderlyingConIdtradingClassmultiplierexpirationsstrikes
0NASDAQOM8314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
1PSE8314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
2PHLX8314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
3BOX8314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
4PEARL8314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
5CBOE28314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
6EDGX8314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
7GEMINI8314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
8MERCURY8314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
9MIAX8314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
10CBOE8314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
11NASDAQBX8314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
12ISE8314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
13BATS8314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
14AMEX8314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
15SMART8314IBM100{20180720, 20180921, 20181116, 20180629, 20180...{128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134...
\n", 513 | "
" 514 | ], 515 | "text/plain": [ 516 | " exchange underlyingConId tradingClass multiplier \\\n", 517 | "0 NASDAQOM 8314 IBM 100 \n", 518 | "1 PSE 8314 IBM 100 \n", 519 | "2 PHLX 8314 IBM 100 \n", 520 | "3 BOX 8314 IBM 100 \n", 521 | "4 PEARL 8314 IBM 100 \n", 522 | "5 CBOE2 8314 IBM 100 \n", 523 | "6 EDGX 8314 IBM 100 \n", 524 | "7 GEMINI 8314 IBM 100 \n", 525 | "8 MERCURY 8314 IBM 100 \n", 526 | "9 MIAX 8314 IBM 100 \n", 527 | "10 CBOE 8314 IBM 100 \n", 528 | "11 NASDAQBX 8314 IBM 100 \n", 529 | "12 ISE 8314 IBM 100 \n", 530 | "13 BATS 8314 IBM 100 \n", 531 | "14 AMEX 8314 IBM 100 \n", 532 | "15 SMART 8314 IBM 100 \n", 533 | "\n", 534 | " expirations \\\n", 535 | "0 {20180720, 20180921, 20181116, 20180629, 20180... \n", 536 | "1 {20180720, 20180921, 20181116, 20180629, 20180... \n", 537 | "2 {20180720, 20180921, 20181116, 20180629, 20180... \n", 538 | "3 {20180720, 20180921, 20181116, 20180629, 20180... \n", 539 | "4 {20180720, 20180921, 20181116, 20180629, 20180... \n", 540 | "5 {20180720, 20180921, 20181116, 20180629, 20180... \n", 541 | "6 {20180720, 20180921, 20181116, 20180629, 20180... \n", 542 | "7 {20180720, 20180921, 20181116, 20180629, 20180... \n", 543 | "8 {20180720, 20180921, 20181116, 20180629, 20180... \n", 544 | "9 {20180720, 20180921, 20181116, 20180629, 20180... \n", 545 | "10 {20180720, 20180921, 20181116, 20180629, 20180... \n", 546 | "11 {20180720, 20180921, 20181116, 20180629, 20180... \n", 547 | "12 {20180720, 20180921, 20181116, 20180629, 20180... \n", 548 | "13 {20180720, 20180921, 20181116, 20180629, 20180... \n", 549 | "14 {20180720, 20180921, 20181116, 20180629, 20180... \n", 550 | "15 {20180720, 20180921, 20181116, 20180629, 20180... \n", 551 | "\n", 552 | " strikes \n", 553 | "0 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... \n", 554 | "1 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... \n", 555 | "2 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... \n", 556 | "3 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... \n", 557 | "4 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... \n", 558 | "5 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... \n", 559 | "6 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... \n", 560 | "7 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... \n", 561 | "8 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... \n", 562 | "9 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... \n", 563 | "10 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... \n", 564 | "11 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... \n", 565 | "12 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... \n", 566 | "13 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... \n", 567 | "14 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... \n", 568 | "15 {128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134... " 569 | ] 570 | }, 571 | "execution_count": 22, 572 | "metadata": {}, 573 | "output_type": "execute_result" 574 | } 575 | ], 576 | "source": [ 577 | "chains = ib.reqSecDefOptParams(ibm.symbol, '', ibm.secType, ibm.conId)\n", 578 | "\n", 579 | "util.df(chains)" 580 | ] 581 | }, 582 | { 583 | "cell_type": "markdown", 584 | "metadata": { 585 | "hidden": true 586 | }, 587 | "source": [ 588 | "We want the options that trade on SMART:" 589 | ] 590 | }, 591 | { 592 | "cell_type": "code", 593 | "execution_count": 23, 594 | "metadata": { 595 | "hidden": true 596 | }, 597 | "outputs": [ 598 | { 599 | "data": { 600 | "text/plain": [ 601 | "OptionChain(exchange='SMART', underlyingConId=8314, tradingClass='IBM', multiplier='100', expirations={'20180720', '20180921', '20181116', '20180629', '20180817', '20180713', '20180727', '20190118', '20180622', '20180803', '20181019', '20181221', '20200117', '20180706', '20190621'}, strikes={128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134.0, 135.0, 136.0, 137.0, 138.0, 139.0, 140.0, 141.0, 142.0, 143.0, 144.0, 145.0, 146.0, 147.0, 148.0, 149.0, 150.0, 152.5, 155.0, 157.5, 160.0, 162.5, 165.0, 167.5, 170.0, 172.5, 175.0, 180.0, 185.0, 190.0, 195.0, 200.0, 75.0, 205.0, 80.0, 210.0, 85.0, 215.0, 90.0, 220.0, 95.0, 225.0, 100.0, 230.0, 105.0, 250.0, 235.0, 110.0, 240.0, 115.0, 120.0, 121.0, 122.0, 123.0, 124.0, 125.0, 126.0, 127.0})" 602 | ] 603 | }, 604 | "execution_count": 23, 605 | "metadata": {}, 606 | "output_type": "execute_result" 607 | } 608 | ], 609 | "source": [ 610 | "chain = next(c for c in chains if c.exchange == 'SMART')\n", 611 | "chain" 612 | ] 613 | }, 614 | { 615 | "cell_type": "markdown", 616 | "metadata": { 617 | "hidden": true 618 | }, 619 | "source": [ 620 | "What we have here is a matrix of expirations x strikes. From this we can build all the contracts:" 621 | ] 622 | }, 623 | { 624 | "cell_type": "code", 625 | "execution_count": 24, 626 | "metadata": { 627 | "hidden": true 628 | }, 629 | "outputs": [ 630 | { 631 | "name": "stdout", 632 | "output_type": "stream", 633 | "text": [ 634 | "48\n", 635 | "\n", 636 | "Option(conId=317356108, symbol='IBM', lastTradeDateOrContractMonth='20180629', strike=130.0, right='P', multiplier='100', exchange='SMART', currency='USD', localSymbol='IBM 180629P00130000', tradingClass='IBM')\n" 637 | ] 638 | } 639 | ], 640 | "source": [ 641 | "strikes = [strike for strike in chain.strikes if\n", 642 | " strike % 5 == 0 and\n", 643 | " ibmPrice - 20 < strike < ibmPrice + 20]\n", 644 | "expirations = sorted(exp for exp in chain.expirations if isFriday(exp))[:3]\n", 645 | "rights = ['P', 'C']\n", 646 | "\n", 647 | "contracts = [Option('IBM', expiration, strike, right, 'SMART')\n", 648 | " for right in rights for expiration in expirations for strike in strikes]\n", 649 | "\n", 650 | "ib.qualifyContracts(*contracts)\n", 651 | "\n", 652 | "print(len(contracts))\n", 653 | "print()\n", 654 | "print(contracts[0])" 655 | ] 656 | }, 657 | { 658 | "cell_type": "markdown", 659 | "metadata": { 660 | "hidden": true 661 | }, 662 | "source": [ 663 | "Let's see if the new way ends up with the same contracts as the old way:" 664 | ] 665 | }, 666 | { 667 | "cell_type": "code", 668 | "execution_count": 25, 669 | "metadata": { 670 | "hidden": true 671 | }, 672 | "outputs": [ 673 | { 674 | "data": { 675 | "text/plain": [ 676 | "True" 677 | ] 678 | }, 679 | "execution_count": 25, 680 | "metadata": {}, 681 | "output_type": "execute_result" 682 | } 683 | ], 684 | "source": [ 685 | "set(contracts) == set(oldContracts)" 686 | ] 687 | }, 688 | { 689 | "cell_type": "markdown", 690 | "metadata": { 691 | "hidden": true 692 | }, 693 | "source": [ 694 | "Yep. Now to get the market data for all options in one go:" 695 | ] 696 | }, 697 | { 698 | "cell_type": "code", 699 | "execution_count": 26, 700 | "metadata": { 701 | "hidden": true 702 | }, 703 | "outputs": [ 704 | { 705 | "data": { 706 | "text/plain": [ 707 | "Ticker(contract=Option(conId=317356108, symbol='IBM', lastTradeDateOrContractMonth='20180629', strike=130.0, right='P', multiplier='100', exchange='SMART', currency='USD', localSymbol='IBM 180629P00130000', tradingClass='IBM'), time=datetime.datetime(2018, 6, 22, 5, 30, 47, 520558, tzinfo=datetime.timezone.utc), bid=-1.0, bidSize=0, ask=-1.0, askSize=0, close=0.03, ticks=[], tickByTicks=[], domBids=[], domAsks=[], domTicks=[])" 708 | ] 709 | }, 710 | "execution_count": 26, 711 | "metadata": {}, 712 | "output_type": "execute_result" 713 | } 714 | ], 715 | "source": [ 716 | "tickers = ib.reqTickers(*contracts)\n", 717 | "\n", 718 | "tickers[0]" 719 | ] 720 | }, 721 | { 722 | "cell_type": "markdown", 723 | "metadata": { 724 | "hidden": true 725 | }, 726 | "source": [ 727 | "The option greeks are available from the ``modelGreeks`` attribute, and if there is a bid, ask resp. last price available also from ``bidGreeks``, ``askGreeks`` and ``lastGreeks``. For streaming ticks the greek values will be kept up to date to the current market situation." 728 | ] 729 | }, 730 | { 731 | "cell_type": "markdown", 732 | "metadata": { 733 | "hidden": true 734 | }, 735 | "source": [ 736 | "***" 737 | ] 738 | } 739 | ], 740 | "metadata": { 741 | "kernelspec": { 742 | "display_name": "Python 3", 743 | "language": "python", 744 | "name": "python3" 745 | }, 746 | "language_info": { 747 | "codemirror_mode": { 748 | "name": "ipython", 749 | "version": 3 750 | }, 751 | "file_extension": ".py", 752 | "mimetype": "text/x-python", 753 | "name": "python", 754 | "nbconvert_exporter": "python", 755 | "pygments_lexer": "ipython3", 756 | "version": "3.6.4" 757 | } 758 | }, 759 | "nbformat": 4, 760 | "nbformat_minor": 2 761 | } 762 | -------------------------------------------------------------------------------- /ib-insync notebooks/ordering.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Ordering\n", 8 | "\n", 9 | "\n", 10 | "## Warning: This notebook will place live orders\n", 11 | "\n", 12 | "Use a papertrading account when running this notebook.\n" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 1, 18 | "metadata": { 19 | "scrolled": true 20 | }, 21 | "outputs": [ 22 | { 23 | "name": "stderr", 24 | "output_type": "stream", 25 | "text": [ 26 | "ERROR:ib_insync.wrapper:Error 321, reqId 12: Error validating request:-'aS' : cause - ALL account is not supported\n" 27 | ] 28 | }, 29 | { 30 | "data": { 31 | "text/plain": [ 32 | "" 33 | ] 34 | }, 35 | "execution_count": 1, 36 | "metadata": {}, 37 | "output_type": "execute_result" 38 | } 39 | ], 40 | "source": [ 41 | "from ib_insync import *\n", 42 | "util.startLoop()\n", 43 | "\n", 44 | "ib = IB()\n", 45 | "ib.connect('127.0.0.1', 4002, clientId=23)" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "Create a contract and a market order:" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": 2, 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [ 61 | "contract = Stock('AAPL', 'SMART', 'USD')\n", 62 | "ib.qualifyContracts(contract)\n", 63 | "\n", 64 | "order = MarketOrder('BUY', 100)" 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "metadata": {}, 70 | "source": [ 71 | "placeOrder will place the order order and return a ``Trade`` object right away (non-blocking):" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 3, 77 | "metadata": {}, 78 | "outputs": [ 79 | { 80 | "data": { 81 | "text/plain": [ 82 | "Trade(contract=Stock(conId=265598, symbol='AAPL', exchange='SMART', primaryExchange='NASDAQ', currency='USD', localSymbol='AAPL', tradingClass='NMS'), order=MarketOrder(orderId=15, action='BUY', totalQuantity=100), orderStatus=OrderStatus(status='PendingSubmit'), fills=[], log=[TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 52, 14, 113511, tzinfo=datetime.timezone.utc), status='PendingSubmit', message='')])" 83 | ] 84 | }, 85 | "execution_count": 3, 86 | "metadata": {}, 87 | "output_type": "execute_result" 88 | } 89 | ], 90 | "source": [ 91 | "trade = ib.placeOrder(contract, order)\n", 92 | "\n", 93 | "trade" 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "metadata": {}, 99 | "source": [ 100 | "``trade`` contains the order and everything related to it, such as order status, fills and a log.\n", 101 | "It will be live updated with every status change or fill of the order." 102 | ] 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": 4, 107 | "metadata": { 108 | "scrolled": true 109 | }, 110 | "outputs": [ 111 | { 112 | "data": { 113 | "text/plain": [ 114 | "[TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 52, 14, 113511, tzinfo=datetime.timezone.utc), status='PendingSubmit', message=''),\n", 115 | " TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 52, 14, 627143, tzinfo=datetime.timezone.utc), status='PreSubmitted', message='')]" 116 | ] 117 | }, 118 | "execution_count": 4, 119 | "metadata": {}, 120 | "output_type": "execute_result" 121 | } 122 | ], 123 | "source": [ 124 | "ib.sleep(1)\n", 125 | "trade.log" 126 | ] 127 | }, 128 | { 129 | "cell_type": "markdown", 130 | "metadata": {}, 131 | "source": [ 132 | "``trade`` will also available from ``ib.trades()``:" 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": 5, 138 | "metadata": {}, 139 | "outputs": [], 140 | "source": [ 141 | "assert trade in ib.trades()" 142 | ] 143 | }, 144 | { 145 | "cell_type": "markdown", 146 | "metadata": {}, 147 | "source": [ 148 | "Likewise for ``order``:" 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": 6, 154 | "metadata": {}, 155 | "outputs": [], 156 | "source": [ 157 | "assert order in ib.orders()" 158 | ] 159 | }, 160 | { 161 | "cell_type": "markdown", 162 | "metadata": {}, 163 | "source": [ 164 | "Now let's create a limit order with an unrealistic limit:" 165 | ] 166 | }, 167 | { 168 | "cell_type": "code", 169 | "execution_count": 7, 170 | "metadata": {}, 171 | "outputs": [ 172 | { 173 | "data": { 174 | "text/plain": [ 175 | "Trade(contract=Stock(conId=265598, symbol='AAPL', exchange='SMART', primaryExchange='NASDAQ', currency='USD', localSymbol='AAPL', tradingClass='NMS'), order=LimitOrder(orderId=16, action='BUY', totalQuantity=100, lmtPrice=0.05), orderStatus=OrderStatus(status='PendingSubmit'), fills=[], log=[TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 53, 19, 502037, tzinfo=datetime.timezone.utc), status='PendingSubmit', message='')])" 176 | ] 177 | }, 178 | "execution_count": 7, 179 | "metadata": {}, 180 | "output_type": "execute_result" 181 | } 182 | ], 183 | "source": [ 184 | "limitOrder = LimitOrder('BUY', 100, 0.05)\n", 185 | "limitTrade = ib.placeOrder(contract, limitOrder)\n", 186 | "\n", 187 | "limitTrade" 188 | ] 189 | }, 190 | { 191 | "cell_type": "markdown", 192 | "metadata": {}, 193 | "source": [ 194 | "``status`` will change from \"PendingSubmit\" to \"Submitted\":" 195 | ] 196 | }, 197 | { 198 | "cell_type": "code", 199 | "execution_count": 8, 200 | "metadata": {}, 201 | "outputs": [ 202 | { 203 | "ename": "AssertionError", 204 | "evalue": "", 205 | "output_type": "error", 206 | "traceback": [ 207 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 208 | "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", 209 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msleep\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0mlimitTrade\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0morderStatus\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstatus\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'Submitted'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 210 | "\u001b[0;31mAssertionError\u001b[0m: " 211 | ] 212 | } 213 | ], 214 | "source": [ 215 | "ib.sleep(1)\n", 216 | "assert limitTrade.orderStatus.status == 'Submitted'" 217 | ] 218 | }, 219 | { 220 | "cell_type": "code", 221 | "execution_count": 9, 222 | "metadata": {}, 223 | "outputs": [], 224 | "source": [ 225 | "assert limitTrade in ib.openTrades()" 226 | ] 227 | }, 228 | { 229 | "cell_type": "markdown", 230 | "metadata": {}, 231 | "source": [ 232 | "Let's modify the limit price and resubmit:" 233 | ] 234 | }, 235 | { 236 | "cell_type": "code", 237 | "execution_count": 10, 238 | "metadata": {}, 239 | "outputs": [ 240 | { 241 | "data": { 242 | "text/plain": [ 243 | "Trade(contract=Stock(conId=265598, symbol='AAPL', exchange='SMART', primaryExchange='NASDAQ', currency='USD', localSymbol='AAPL', tradingClass='NMS'), order=LimitOrder(orderId=16, action='BUY', totalQuantity=100, lmtPrice=0.1), orderStatus=OrderStatus(status='PreSubmitted', remaining=100.0, permId=2113698761, clientId=23, whyHeld='locate', mktCapPrice=None), fills=[], log=[TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 53, 19, 502037, tzinfo=datetime.timezone.utc), status='PendingSubmit', message=''), TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 53, 19, 825797, tzinfo=datetime.timezone.utc), status='PreSubmitted', message=''), TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 54, 26, 409070, tzinfo=datetime.timezone.utc), status='PreSubmitted', message='Modify')])" 244 | ] 245 | }, 246 | "execution_count": 10, 247 | "metadata": {}, 248 | "output_type": "execute_result" 249 | } 250 | ], 251 | "source": [ 252 | "limitOrder.lmtPrice = 0.10\n", 253 | "\n", 254 | "ib.placeOrder(contract, limitOrder)" 255 | ] 256 | }, 257 | { 258 | "cell_type": "markdown", 259 | "metadata": {}, 260 | "source": [ 261 | "And now cancel it:" 262 | ] 263 | }, 264 | { 265 | "cell_type": "code", 266 | "execution_count": 11, 267 | "metadata": {}, 268 | "outputs": [ 269 | { 270 | "data": { 271 | "text/plain": [ 272 | "Trade(contract=Stock(conId=265598, symbol='AAPL', exchange='SMART', primaryExchange='NASDAQ', currency='USD', localSymbol='AAPL', tradingClass='NMS'), order=LimitOrder(orderId=16, action='BUY', totalQuantity=100, lmtPrice=0.1), orderStatus=OrderStatus(status='PreSubmitted', remaining=100.0, permId=2113698761, clientId=23, whyHeld='locate', mktCapPrice=None), fills=[], log=[TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 53, 19, 502037, tzinfo=datetime.timezone.utc), status='PendingSubmit', message=''), TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 53, 19, 825797, tzinfo=datetime.timezone.utc), status='PreSubmitted', message=''), TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 54, 26, 409070, tzinfo=datetime.timezone.utc), status='PreSubmitted', message='Modify'), TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 54, 33, 554896, tzinfo=datetime.timezone.utc), status='PendingCancel', message='')])" 273 | ] 274 | }, 275 | "execution_count": 11, 276 | "metadata": {}, 277 | "output_type": "execute_result" 278 | } 279 | ], 280 | "source": [ 281 | "ib.cancelOrder(limitOrder)" 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "execution_count": 12, 287 | "metadata": {}, 288 | "outputs": [ 289 | { 290 | "data": { 291 | "text/plain": [ 292 | "[TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 53, 19, 502037, tzinfo=datetime.timezone.utc), status='PendingSubmit', message=''),\n", 293 | " TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 53, 19, 825797, tzinfo=datetime.timezone.utc), status='PreSubmitted', message=''),\n", 294 | " TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 54, 26, 409070, tzinfo=datetime.timezone.utc), status='PreSubmitted', message='Modify'),\n", 295 | " TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 54, 33, 554896, tzinfo=datetime.timezone.utc), status='PendingCancel', message=''),\n", 296 | " TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 54, 33, 907979, tzinfo=datetime.timezone.utc), status='Cancelled', message='')]" 297 | ] 298 | }, 299 | "execution_count": 12, 300 | "metadata": {}, 301 | "output_type": "execute_result" 302 | } 303 | ], 304 | "source": [ 305 | "limitTrade.log" 306 | ] 307 | }, 308 | { 309 | "cell_type": "markdown", 310 | "metadata": {}, 311 | "source": [ 312 | "Some note of warning: reqContractDetails can happily report that a contract is unique,\n", 313 | "while placeOrder() will complain that the contract is ambiguous. An example is INTC:" 314 | ] 315 | }, 316 | { 317 | "cell_type": "code", 318 | "execution_count": 13, 319 | "metadata": {}, 320 | "outputs": [ 321 | { 322 | "name": "stderr", 323 | "output_type": "stream", 324 | "text": [ 325 | "ERROR:ib_insync.wrapper:Error 200, reqId 18: The contract description specified for INTC is ambiguous.\n", 326 | "WARNING:ib_insync.wrapper:Canceled order: Trade(contract=Stock(symbol='INTC', exchange='SMART', currency='USD'), order=LimitOrder(orderId=18, action='BUY', totalQuantity=100, lmtPrice=0.05), orderStatus=OrderStatus(status='Cancelled'), fills=[], log=[TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 54, 59, 238244, tzinfo=datetime.timezone.utc), status='PendingSubmit', message=''), TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 54, 59, 536095, tzinfo=datetime.timezone.utc), status='Cancelled', message='Error 200, reqId 18: The contract description specified for INTC is ambiguous.')])\n" 327 | ] 328 | } 329 | ], 330 | "source": [ 331 | "intc = Stock('INTC', 'SMART', 'USD')\n", 332 | "\n", 333 | "assert len(ib.reqContractDetails(intc)) == 1\n", 334 | "\n", 335 | "intcOrder = LimitOrder('BUY', 100, 0.05)\n", 336 | "trade = ib.placeOrder(intc, intcOrder)\n", 337 | "ib.sleep(1);" 338 | ] 339 | }, 340 | { 341 | "cell_type": "code", 342 | "execution_count": 14, 343 | "metadata": {}, 344 | "outputs": [], 345 | "source": [ 346 | "assert trade.orderStatus.status == 'Cancelled'" 347 | ] 348 | }, 349 | { 350 | "cell_type": "markdown", 351 | "metadata": {}, 352 | "source": [ 353 | "So it is always a good\n", 354 | "idea to a qualify a contract before trading it." 355 | ] 356 | }, 357 | { 358 | "cell_type": "code", 359 | "execution_count": 15, 360 | "metadata": {}, 361 | "outputs": [], 362 | "source": [ 363 | "ib.qualifyContracts(intc)\n", 364 | "\n", 365 | "intcOrder = LimitOrder('BUY', 100, 0.05)\n", 366 | "trade = ib.placeOrder(intc, intcOrder)" 367 | ] 368 | }, 369 | { 370 | "cell_type": "code", 371 | "execution_count": 16, 372 | "metadata": {}, 373 | "outputs": [ 374 | { 375 | "data": { 376 | "text/plain": [ 377 | "Trade(contract=Stock(conId=270639, symbol='INTC', exchange='SMART', primaryExchange='NASDAQ', currency='USD', localSymbol='INTC', tradingClass='NMS'), order=LimitOrder(orderId=20, action='BUY', totalQuantity=100, lmtPrice=0.05), orderStatus=OrderStatus(status='PreSubmitted', remaining=100.0, permId=2113698762, clientId=23, whyHeld='locate', mktCapPrice=None), fills=[], log=[TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 55, 30, 988670, tzinfo=datetime.timezone.utc), status='PendingSubmit', message=''), TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 55, 31, 288631, tzinfo=datetime.timezone.utc), status='PreSubmitted', message=''), TradeLogEntry(time=datetime.datetime(2018, 6, 22, 5, 56, 0, 675344, tzinfo=datetime.timezone.utc), status='PendingCancel', message='')])" 378 | ] 379 | }, 380 | "execution_count": 16, 381 | "metadata": {}, 382 | "output_type": "execute_result" 383 | } 384 | ], 385 | "source": [ 386 | "ib.cancelOrder(intcOrder)" 387 | ] 388 | }, 389 | { 390 | "cell_type": "markdown", 391 | "metadata": {}, 392 | "source": [ 393 | "placeOrder is not blocking and will not wait on what happens with the order.\n", 394 | "To make the order placement blocking, that is to wait until the order is either\n", 395 | "filled or canceled, consider the following:" 396 | ] 397 | }, 398 | { 399 | "cell_type": "code", 400 | "execution_count": 17, 401 | "metadata": {}, 402 | "outputs": [ 403 | { 404 | "ename": "KeyboardInterrupt", 405 | "evalue": "", 406 | "output_type": "error", 407 | "traceback": [ 408 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 409 | "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", 410 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n", 411 | "\u001b[0;32m~/anaconda3/envs/ib/lib/python3.6/site-packages/ib_insync/ib.py\u001b[0m in \u001b[0;36mwaitOnUpdate\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 228\u001b[0m \u001b[0mWait\u001b[0m \u001b[0mon\u001b[0m \u001b[0many\u001b[0m \u001b[0mnew\u001b[0m \u001b[0mupdate\u001b[0m \u001b[0mto\u001b[0m \u001b[0marrive\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mthe\u001b[0m \u001b[0mnetwork\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 229\u001b[0m \"\"\"\n\u001b[0;32m--> 230\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwrapper\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdateEvent\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwait\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 231\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 232\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", 412 | "\u001b[0;32m~/anaconda3/envs/ib/lib/python3.6/site-packages/ib_insync/ib.py\u001b[0m in \u001b[0;36mrun\u001b[0;34m(*awaitables)\u001b[0m\n\u001b[1;32m 156\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 157\u001b[0m \u001b[0mfuture\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0masyncio\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgather\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mawaitables\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 158\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mutil\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msyncAwait\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfuture\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 159\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 160\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", 413 | "\u001b[0;32m~/anaconda3/envs/ib/lib/python3.6/site-packages/ib_insync/util.py\u001b[0m in \u001b[0;36msyncAwait\u001b[0;34m(future)\u001b[0m\n\u001b[1;32m 240\u001b[0m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_syncAwaitQt\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfuture\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 241\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 242\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_syncAwaitAsyncio\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfuture\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 243\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 244\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", 414 | "\u001b[0;32m~/anaconda3/envs/ib/lib/python3.6/site-packages/ib_insync/util.py\u001b[0m in \u001b[0;36m_syncAwaitAsyncio\u001b[0;34m(future)\u001b[0m\n\u001b[1;32m 253\u001b[0m \u001b[0mpreserved_task\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcurrent_tasks\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mloop\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 254\u001b[0m \u001b[0;32mwhile\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mfuture\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdone\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 255\u001b[0;31m \u001b[0mloop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_run_once\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 256\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mloop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_stopping\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 257\u001b[0m \u001b[0;32mbreak\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 415 | "\u001b[0;32m~/anaconda3/envs/ib/lib/python3.6/asyncio/base_events.py\u001b[0m in \u001b[0;36m_run_once\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 1393\u001b[0m timeout * 1e3, dt * 1e3)\n\u001b[1;32m 1394\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1395\u001b[0;31m \u001b[0mevent_list\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_selector\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mselect\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1396\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_process_events\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mevent_list\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1397\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", 416 | "\u001b[0;32m~/anaconda3/envs/ib/lib/python3.6/selectors.py\u001b[0m in \u001b[0;36mselect\u001b[0;34m(self, timeout)\u001b[0m\n\u001b[1;32m 575\u001b[0m \u001b[0mready\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 576\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 577\u001b[0;31m \u001b[0mkev_list\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_kqueue\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcontrol\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmax_ev\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 578\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mInterruptedError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 579\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mready\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 417 | "\u001b[0;31mKeyboardInterrupt\u001b[0m: " 418 | ] 419 | } 420 | ], 421 | "source": [ 422 | "%%time\n", 423 | "order = MarketOrder('BUY', 100)\n", 424 | "\n", 425 | "trade = ib.placeOrder(contract, order)\n", 426 | "while not trade.isDone():\n", 427 | " ib.waitOnUpdate()" 428 | ] 429 | }, 430 | { 431 | "cell_type": "markdown", 432 | "metadata": {}, 433 | "source": [ 434 | "What are our positions?" 435 | ] 436 | }, 437 | { 438 | "cell_type": "code", 439 | "execution_count": 18, 440 | "metadata": { 441 | "scrolled": true 442 | }, 443 | "outputs": [ 444 | { 445 | "data": { 446 | "text/plain": [ 447 | "[Position(account='DU774248', contract=Contract(secType='STK', conId=10098, symbol='BAC', exchange='NYSE', currency='USD', localSymbol='BAC', tradingClass='BAC'), position=300.0, avgCost=23.835),\n", 448 | " Position(account='DU774248', contract=Contract(secType='CASH', conId=12087802, symbol='CHF', currency='USD', localSymbol='CHF.USD', tradingClass='CHF.USD'), position=30000.0, avgCost=1.0082),\n", 449 | " Position(account='DU774248', contract=Contract(secType='CASH', conId=14433401, symbol='AUD', currency='USD', localSymbol='AUD.USD', tradingClass='AUD.USD'), position=150000.0, avgCost=0.7881105),\n", 450 | " Position(account='DU774248', contract=Contract(secType='STK', conId=4725951, symbol='AEO', exchange='NYSE', currency='USD', localSymbol='AEO', tradingClass='AEO'), position=500.0, avgCost=10.605),\n", 451 | " Position(account='DU774248', contract=Contract(secType='CASH', conId=12087792, symbol='EUR', currency='USD', localSymbol='EUR.USD', tradingClass='EUR.USD'), position=8600000.0, avgCost=1.18190765),\n", 452 | " Position(account='DU774248', contract=Contract(secType='STK', conId=166090175, symbol='BABA', exchange='NYSE', currency='USD', localSymbol='BABA', tradingClass='BABA'), position=400.0, avgCost=155.7275),\n", 453 | " Position(account='DU774248', contract=Contract(secType='STK', conId=148782724, symbol='WB', exchange='NASDAQ', currency='USD', localSymbol='WB', tradingClass='NMS'), position=500.0, avgCost=92.445),\n", 454 | " Position(account='DU774248', contract=Contract(secType='CASH', conId=12087797, symbol='GBP', currency='USD', localSymbol='GBP.USD', tradingClass='GBP.USD'), position=120000.0, avgCost=1.2789556),\n", 455 | " Position(account='DU774247', contract=Contract(secType='CASH', conId=12087820, symbol='USD', currency='CHF', localSymbol='USD.CHF', tradingClass='USD.CHF'), position=2000000.0, avgCost=0.960028),\n", 456 | " Position(account='DU774247', contract=Contract(secType='CASH', conId=114900061, symbol='SGD', currency='CNH', localSymbol='SGD.CNH', tradingClass='SGD.CNH'), position=1000000.0, avgCost=4.89405),\n", 457 | " Position(account='DU774247', contract=Contract(secType='CASH', conId=12087792, symbol='EUR', currency='USD', localSymbol='EUR.USD', tradingClass='EUR.USD'), position=1000000.0, avgCost=1.18305565),\n", 458 | " Position(account='DU774247', contract=Contract(secType='CASH', conId=12345777, symbol='USD', currency='HKD', localSymbol='USD.HKD', tradingClass='USD.HKD'), position=-1000000.0, avgCost=7.82385),\n", 459 | " Position(account='DU774246', contract=Contract(secType='CASH', conId=12087802, symbol='CHF', currency='USD', localSymbol='CHF.USD', tradingClass='CHF.USD'), position=-250000.0, avgCost=1.0082),\n", 460 | " Position(account='DU774246', contract=Contract(secType='CASH', conId=28027113, symbol='NOK', currency='SEK', localSymbol='NOK.SEK', tradingClass='NOK.SEK'), position=500000.0, avgCost=1.0139),\n", 461 | " Position(account='DU774246', contract=Contract(secType='CASH', conId=61664943, symbol='SGD', currency='JPY', localSymbol='SGD.JPY', tradingClass='SGD.JPY'), position=-500000.0, avgCost=80.523),\n", 462 | " Position(account='DU774246', contract=Contract(secType='CASH', conId=14433401, symbol='AUD', currency='USD', localSymbol='AUD.USD', tradingClass='AUD.USD'), position=25000.0, avgCost=0.7943),\n", 463 | " Position(account='DU774246', contract=Contract(secType='CASH', conId=37928772, symbol='USD', currency='SGD', localSymbol='USD.SGD', tradingClass='USD.SGD'), position=100000.0, avgCost=1.36305),\n", 464 | " Position(account='DU774246', contract=Contract(secType='CASH', conId=12087792, symbol='EUR', currency='USD', localSymbol='EUR.USD', tradingClass='EUR.USD'), position=5000000.0, avgCost=1.184054),\n", 465 | " Position(account='DU774246', contract=Contract(secType='CASH', conId=35045199, symbol='USD', currency='MXN', localSymbol='USD.MXN', tradingClass='USD.MXN'), position=-300000.0, avgCost=17.6767),\n", 466 | " Position(account='DU774246', contract=Contract(secType='CASH', conId=12087797, symbol='GBP', currency='USD', localSymbol='GBP.USD', tradingClass='GBP.USD'), position=500000.0, avgCost=1.29657595),\n", 467 | " Position(account='DU774246', contract=Contract(secType='CASH', conId=12345777, symbol='USD', currency='HKD', localSymbol='USD.HKD', tradingClass='USD.HKD'), position=100000.0, avgCost=7.82085),\n", 468 | " Position(account='DU774245', contract=Contract(secType='CASH', conId=15016062, symbol='USD', currency='CAD', localSymbol='USD.CAD', tradingClass='USD.CAD'), position=-5000000.0, avgCost=1.247152),\n", 469 | " Position(account='DU774244', contract=Contract(secType='CASH', conId=12087820, symbol='USD', currency='CHF', localSymbol='USD.CHF', tradingClass='USD.CHF'), position=1000000.0, avgCost=0.96475),\n", 470 | " Position(account='DU774244', contract=Contract(secType='CASH', conId=114900061, symbol='SGD', currency='CNH', localSymbol='SGD.CNH', tradingClass='SGD.CNH'), position=500000.0, avgCost=4.89662),\n", 471 | " Position(account='DU774244', contract=Contract(secType='CASH', conId=14433401, symbol='AUD', currency='USD', localSymbol='AUD.USD', tradingClass='AUD.USD'), position=-5000000.0, avgCost=0.7902382),\n", 472 | " Position(account='DU774244', contract=Contract(secType='CASH', conId=35045199, symbol='USD', currency='MXN', localSymbol='USD.MXN', tradingClass='USD.MXN'), position=-500000.0, avgCost=17.6632),\n", 473 | " Position(account='DU774243', contract=Contract(secType='CASH', conId=114900061, symbol='SGD', currency='CNH', localSymbol='SGD.CNH', tradingClass='SGD.CNH'), position=-1000000.0, avgCost=4.83754),\n", 474 | " Position(account='DU774243', contract=Contract(secType='CASH', conId=12087807, symbol='EUR', currency='GBP', localSymbol='EUR.GBP', tradingClass='EUR.GBP'), position=1000000.0, avgCost=0.90934),\n", 475 | " Position(account='DU774243', contract=Contract(secType='CASH', conId=34838409, symbol='USD', currency='CZK', localSymbol='USD.CZK', tradingClass='USD.CZK'), position=-500000.0, avgCost=21.85),\n", 476 | " Position(account='DU774242', contract=Contract(secType='STK', conId=10098, symbol='BAC', exchange='NYSE', currency='USD', localSymbol='BAC', tradingClass='BAC'), position=-500.0, avgCost=23.84453),\n", 477 | " Position(account='DU774242', contract=Contract(secType='CASH', conId=37928772, symbol='USD', currency='SGD', localSymbol='USD.SGD', tradingClass='USD.SGD'), position=500000.0, avgCost=1.361115),\n", 478 | " Position(account='DU774242', contract=Contract(secType='CASH', conId=12087792, symbol='EUR', currency='USD', localSymbol='EUR.USD', tradingClass='EUR.USD'), position=1000000.0, avgCost=1.18270365),\n", 479 | " Position(account='DU774242', contract=Contract(secType='STK', conId=107113386, symbol='FB', exchange='NASDAQ', currency='USD', localSymbol='FB', tradingClass='NMS'), position=1200.0, avgCost=170.61416665),\n", 480 | " Position(account='DU774242', contract=Contract(secType='STK', conId=272093, symbol='MSFT', exchange='NASDAQ', currency='USD', localSymbol='MSFT', tradingClass='NMS'), position=-500.0, avgCost=72.9531956),\n", 481 | " Position(account='DU774242', contract=Contract(secType='STK', conId=3691937, symbol='AMZN', exchange='NASDAQ', currency='USD', localSymbol='AMZN', tradingClass='NMS'), position=-200.0, avgCost=954.9728205),\n", 482 | " Position(account='DU774242', contract=Contract(secType='CASH', conId=15016062, symbol='USD', currency='CAD', localSymbol='USD.CAD', tradingClass='USD.CAD'), position=2000000.0, avgCost=1.273895),\n", 483 | " Position(account='DU774242', contract=Contract(secType='CASH', conId=37893486, symbol='USD', currency='SEK', localSymbol='USD.SEK', tradingClass='USD.SEK'), position=-3000000.0, avgCost=8.06397335),\n", 484 | " Position(account='DU774242', contract=Contract(secType='CASH', conId=15016059, symbol='USD', currency='JPY', localSymbol='USD.JPY', tradingClass='USD.JPY'), position=3500000.0, avgCost=109.33064285),\n", 485 | " Position(account='DU274370', contract=Contract(secType='STK', conId=233346091, symbol='UNISQ', exchange='VALUE', currency='USD', localSymbol='UNISQ', tradingClass='UNISQ'), position=10000.0, avgCost=8.45272515),\n", 486 | " Position(account='DU274370', contract=Contract(secType='CASH', conId=14433401, symbol='AUD', currency='USD', localSymbol='AUD.USD', tradingClass='AUD.USD'), position=3000000.0, avgCost=0.7084579),\n", 487 | " Position(account='DU274370', contract=Contract(secType='STK', conId=265598, symbol='AAPL', exchange='NASDAQ', currency='USD', localSymbol='AAPL', tradingClass='NMS'), position=5000.0, avgCost=103.7464686),\n", 488 | " Position(account='DU274370', contract=Contract(secType='CASH', conId=113342317, symbol='USD', currency='CNH', localSymbol='USD.CNH', tradingClass='USD.CNH'), position=400000.0, avgCost=6.742225),\n", 489 | " Position(account='DI246990', contract=Contract(secType='STK', conId=9408, symbol='MCD', exchange='NYSE', currency='USD', localSymbol='MCD', tradingClass='MCD'), position=-4.0, avgCost=121.264725),\n", 490 | " Position(account='DI246990', contract=Contract(secType='STK', conId=43645865, symbol='IBKR', exchange='NASDAQ', currency='USD', localSymbol='IBKR', tradingClass='NMS'), position=7.0, avgCost=38.8378),\n", 491 | " Position(account='DI246990', contract=Contract(secType='FUT', conId=279396694, symbol='ES', lastTradeDateOrContractMonth='20180921', multiplier='50', currency='USD', localSymbol='ESU8', tradingClass='ES'), position=22.0, avgCost=132968.52727275),\n", 492 | " Position(account='DI246990', contract=Contract(secType='CASH', conId=12087792, symbol='EUR', currency='USD', localSymbol='EUR.USD', tradingClass='EUR.USD'), position=150000.0, avgCost=1.12228245),\n", 493 | " Position(account='DI246990', contract=Contract(secType='STK', conId=14121, symbol='DBK', exchange='IBIS', currency='EUR', localSymbol='DBK', tradingClass='XETRA'), position=224.0, avgCost=17.85),\n", 494 | " Position(account='DI246990', contract=Contract(secType='STK', conId=265598, symbol='AAPL', exchange='NASDAQ', currency='USD', localSymbol='AAPL', tradingClass='NMS'), position=200.0, avgCost=174.95),\n", 495 | " Position(account='DI246990', contract=Contract(secType='STK', conId=208813720, symbol='GOOG', exchange='NASDAQ', currency='USD', localSymbol='GOOG', tradingClass='NMS'), position=850.0, avgCost=1009.70058825),\n", 496 | " Position(account='DI246990', contract=Contract(secType='CASH', conId=15016059, symbol='USD', currency='JPY', localSymbol='USD.JPY', tradingClass='USD.JPY'), position=400000.0, avgCost=107.25325),\n", 497 | " Position(account='DU958103', contract=Contract(secType='STK', conId=166090175, symbol='BABA', exchange='NYSE', currency='USD', localSymbol='BABA', tradingClass='BABA'), position=1500.0, avgCost=183.67433335),\n", 498 | " Position(account='DU958103', contract=Contract(secType='STK', conId=5946, symbol='COG', exchange='NYSE', currency='USD', localSymbol='COG', tradingClass='COG'), position=15000.0, avgCost=23.93026665),\n", 499 | " Position(account='DU816496', contract=Contract(secType='STK', conId=51529211, symbol='GLD', exchange='ARCA', currency='USD', localSymbol='GLD', tradingClass='GLD'), position=1000.0, avgCost=121.61),\n", 500 | " Position(account='DU816496', contract=Contract(secType='CASH', conId=15016062, symbol='USD', currency='CAD', localSymbol='USD.CAD', tradingClass='USD.CAD'), position=2000000.0, avgCost=1.253355),\n", 501 | " Position(account='DU914400', contract=Contract(secType='CASH', conId=12087792, symbol='EUR', currency='USD', localSymbol='EUR.USD', tradingClass='EUR.USD'), position=25000.0, avgCost=1.20717),\n", 502 | " Position(account='DU816494', contract=Contract(secType='CASH', conId=12087820, symbol='USD', currency='CHF', localSymbol='USD.CHF', tradingClass='USD.CHF'), position=-1575071.0, avgCost=0.976748),\n", 503 | " Position(account='DU816494', contract=Contract(secType='CASH', conId=14433401, symbol='AUD', currency='USD', localSymbol='AUD.USD', tradingClass='AUD.USD'), position=1956232.0, avgCost=0.7825014),\n", 504 | " Position(account='DU816494', contract=Contract(secType='CASH', conId=12087792, symbol='EUR', currency='USD', localSymbol='EUR.USD', tradingClass='EUR.USD'), position=1000000.0, avgCost=1.17312345),\n", 505 | " Position(account='DU816494', contract=Contract(secType='CASH', conId=12087797, symbol='GBP', currency='USD', localSymbol='GBP.USD', tradingClass='GBP.USD'), position=705106.0, avgCost=1.3340473),\n", 506 | " Position(account='DU816494', contract=Contract(secType='CASH', conId=15016059, symbol='USD', currency='JPY', localSymbol='USD.JPY', tradingClass='USD.JPY'), position=-1000000.0, avgCost=113.045),\n", 507 | " Position(account='DU905543', contract=Contract(secType='STK', conId=9939, symbol='MU', exchange='NASDAQ', currency='USD', localSymbol='MU', tradingClass='NMS'), position=10000.0, avgCost=45.9029),\n", 508 | " Position(account='DU905543', contract=Contract(secType='STK', conId=15124833, symbol='NFLX', exchange='NASDAQ', currency='USD', localSymbol='NFLX', tradingClass='NMS'), position=1000.0, avgCost=205.024),\n", 509 | " Position(account='DU905543', contract=Contract(secType='STK', conId=107113386, symbol='FB', exchange='NASDAQ', currency='USD', localSymbol='FB', tradingClass='NMS'), position=1500.0, avgCost=185.81833335),\n", 510 | " Position(account='DU905543', contract=Contract(secType='STK', conId=4815747, symbol='NVDA', exchange='NASDAQ', currency='USD', localSymbol='NVDA', tradingClass='NMS'), position=500.0, avgCost=213.365),\n", 511 | " Position(account='DU905543', contract=Contract(secType='STK', conId=210918190, symbol='RYAAY', exchange='NASDAQ', currency='USD', localSymbol='RYAAY', tradingClass='NMS'), position=500.0, avgCost=107.083),\n", 512 | " Position(account='DU905542', contract=Contract(secType='CASH', conId=12087797, symbol='GBP', currency='USD', localSymbol='GBP.USD', tradingClass='GBP.USD'), position=5000.0, avgCost=1.3541),\n", 513 | " Position(account='DU905541', contract=Contract(secType='CASH', conId=12087792, symbol='EUR', currency='USD', localSymbol='EUR.USD', tradingClass='EUR.USD'), position=2035000.0, avgCost=1.20453605),\n", 514 | " Position(account='DU905541', contract=Contract(secType='CASH', conId=15016059, symbol='USD', currency='JPY', localSymbol='USD.JPY', tradingClass='USD.JPY'), position=1000000.0, avgCost=112.349),\n", 515 | " Position(account='DU973432', contract=Contract(secType='STK', conId=15224443, symbol='TRI', exchange='NYSE', currency='USD', localSymbol='TRI', tradingClass='TRI'), position=1000.0, avgCost=39.595),\n", 516 | " Position(account='DU973432', contract=Contract(secType='STK', conId=4901, symbol='VZ', exchange='NYSE', currency='USD', localSymbol='VZ', tradingClass='VZ'), position=500.0, avgCost=49.805),\n", 517 | " Position(account='DU973432', contract=Contract(secType='STK', conId=107113386, symbol='FB', exchange='NASDAQ', currency='USD', localSymbol='FB', tradingClass='NMS'), position=1000.0, avgCost=175.61),\n", 518 | " Position(account='DU973432', contract=Contract(secType='CASH', conId=12087797, symbol='GBP', currency='USD', localSymbol='GBP.USD', tradingClass='GBP.USD'), position=10000.0, avgCost=1.38953),\n", 519 | " Position(account='DU905544', contract=Contract(secType='STK', conId=268084, symbol='CSCO', exchange='NASDAQ', currency='USD', localSymbol='CSCO', tradingClass='NMS'), position=10000.0, avgCost=39.1984),\n", 520 | " Position(account='DU905544', contract=Contract(secType='STK', conId=1520593, symbol='JPM', exchange='NYSE', currency='USD', localSymbol='JPM', tradingClass='JPM'), position=10500.0, avgCost=108.36166665),\n", 521 | " Position(account='DU905544', contract=Contract(secType='CASH', conId=12087792, symbol='EUR', currency='USD', localSymbol='EUR.USD', tradingClass='EUR.USD'), position=320000.0, avgCost=1.20358255),\n", 522 | " Position(account='DU905544', contract=Contract(secType='STK', conId=272093, symbol='MSFT', exchange='NASDAQ', currency='USD', localSymbol='MSFT', tradingClass='NMS'), position=100.0, avgCost=86.74),\n", 523 | " Position(account='DU958081', contract=Contract(secType='STK', conId=3691937, symbol='AMZN', exchange='NASDAQ', currency='USD', localSymbol='AMZN', tradingClass='NMS'), position=300.0, avgCost=1478.795),\n", 524 | " Position(account='DU958081', contract=Contract(secType='STK', conId=166090175, symbol='BABA', exchange='NYSE', currency='USD', localSymbol='BABA', tradingClass='BABA'), position=100.0, avgCost=177.33),\n", 525 | " Position(account='DU958081', contract=Contract(secType='STK', conId=7516, symbol='GE', exchange='NYSE', currency='USD', localSymbol='GE', tradingClass='GE'), position=-200.0, avgCost=14.5145455),\n", 526 | " Position(account='DU958082', contract=Contract(secType='STK', conId=166090175, symbol='BABA', exchange='NYSE', currency='USD', localSymbol='BABA', tradingClass='BABA'), position=700.0, avgCost=186.11642855),\n", 527 | " Position(account='DU958080', contract=Contract(secType='STK', conId=109911821, symbol='NOW', exchange='NYSE', currency='USD', localSymbol='NOW', tradingClass='NOW'), position=500.0, avgCost=146.201),\n", 528 | " Position(account='DU958080', contract=Contract(secType='STK', conId=306081855, symbol='DHCP', exchange='NYSE', currency='USD', localSymbol='DHCP', tradingClass='DHCP'), position=500.0, avgCost=10.505),\n", 529 | " Position(account='DU958080', contract=Contract(secType='STK', conId=35359385, symbol='BIDU', exchange='NASDAQ', currency='USD', localSymbol='BIDU', tradingClass='NMS'), position=100.0, avgCost=236.24),\n", 530 | " Position(account='DU958080', contract=Contract(secType='STK', conId=225590118, symbol='UA', exchange='NYSE', currency='USD', localSymbol='UA', tradingClass='UA'), position=-1000.0, avgCost=15.2845278),\n", 531 | " Position(account='DU958080', contract=Contract(secType='STK', conId=756733, symbol='SPY', exchange='ARCA', currency='USD', localSymbol='SPY', tradingClass='SPY'), position=1200.0, avgCost=269.9975),\n", 532 | " Position(account='DU958080', contract=Contract(secType='STK', conId=92950764, symbol='KMPR', exchange='NYSE', currency='USD', localSymbol='KMPR', tradingClass='KMPR'), position=400.0, avgCost=55.805),\n", 533 | " Position(account='DU958080', contract=Contract(secType='STK', conId=11017, symbol='PEP', exchange='NASDAQ', currency='USD', localSymbol='PEP', tradingClass='NMS'), position=300.0, avgCost=111.905),\n", 534 | " Position(account='DU958080', contract=Contract(secType='STK', conId=166090175, symbol='BABA', exchange='NYSE', currency='USD', localSymbol='BABA', tradingClass='BABA'), position=200.0, avgCost=174.005),\n", 535 | " Position(account='DU958080', contract=Contract(secType='STK', conId=105068604, symbol='WMIH', exchange='NASDAQ', currency='USD', localSymbol='WMIH', tradingClass='SCM'), position=5000.0, avgCost=1.255),\n", 536 | " Position(account='DU958089', contract=Contract(secType='STK', conId=107113386, symbol='FB', exchange='NASDAQ', currency='USD', localSymbol='FB', tradingClass='NMS'), position=200.0, avgCost=176.44),\n", 537 | " Position(account='DU958089', contract=Contract(secType='STK', conId=3691937, symbol='AMZN', exchange='NASDAQ', currency='USD', localSymbol='AMZN', tradingClass='NMS'), position=100.0, avgCost=1407.51),\n", 538 | " Position(account='DU774252', contract=Contract(secType='CASH', conId=12087792, symbol='EUR', currency='USD', localSymbol='EUR.USD', tradingClass='EUR.USD'), position=100000.0, avgCost=1.1837937),\n", 539 | " Position(account='DU774252', contract=Contract(secType='STK', conId=265598, symbol='AAPL', exchange='NASDAQ', currency='USD', localSymbol='AAPL', tradingClass='NMS'), position=21917.0, avgCost=164.7965283),\n", 540 | " Position(account='DU813164', contract=Contract(secType='STK', conId=3691937, symbol='AMZN', exchange='NASDAQ', currency='USD', localSymbol='AMZN', tradingClass='NMS'), position=100.0, avgCost=948.355),\n", 541 | " Position(account='DU813164', contract=Contract(secType='STK', conId=166090175, symbol='BABA', exchange='NYSE', currency='USD', localSymbol='BABA', tradingClass='BABA'), position=-200.0, avgCost=170.16345),\n", 542 | " Position(account='DU813162', contract=Contract(secType='STK', conId=15468463, symbol='GOLD', exchange='NASDAQ', currency='USD', localSymbol='GOLD', tradingClass='NMS'), position=5001.0, avgCost=98.3463957),\n", 543 | " Position(account='DU813162', contract=Contract(secType='STK', conId=13272, symbol='UNH', exchange='NYSE', currency='USD', localSymbol='UNH', tradingClass='UNH'), position=-100.0, avgCost=192.325438),\n", 544 | " Position(account='DU813162', contract=Contract(secType='STK', conId=208813720, symbol='GOOG', exchange='NASDAQ', currency='USD', localSymbol='GOOG', tradingClass='NMS'), position=-200.0, avgCost=951.872892)]" 545 | ] 546 | }, 547 | "execution_count": 18, 548 | "metadata": {}, 549 | "output_type": "execute_result" 550 | } 551 | ], 552 | "source": [ 553 | "ib.positions()" 554 | ] 555 | }, 556 | { 557 | "cell_type": "markdown", 558 | "metadata": { 559 | "collapsed": true 560 | }, 561 | "source": [ 562 | "What's the total of commissions paid today?" 563 | ] 564 | }, 565 | { 566 | "cell_type": "code", 567 | "execution_count": 19, 568 | "metadata": {}, 569 | "outputs": [ 570 | { 571 | "data": { 572 | "text/plain": [ 573 | "0" 574 | ] 575 | }, 576 | "execution_count": 19, 577 | "metadata": {}, 578 | "output_type": "execute_result" 579 | } 580 | ], 581 | "source": [ 582 | "sum(fill.commissionReport.commission for fill in ib.fills())" 583 | ] 584 | }, 585 | { 586 | "cell_type": "markdown", 587 | "metadata": { 588 | "collapsed": true 589 | }, 590 | "source": [ 591 | "whatIfOrder can be used to see the commission and the margin impact of an order without actually sending the order:" 592 | ] 593 | }, 594 | { 595 | "cell_type": "code", 596 | "execution_count": 20, 597 | "metadata": {}, 598 | "outputs": [ 599 | { 600 | "data": { 601 | "text/plain": [ 602 | "OrderState(status='PreSubmitted', initMargin='450357.7', maintMargin='411864.39', equityWithLoan='1402339.82', minCommission=1.265372, maxCommission=1.505372, commissionCurrency='USD')" 603 | ] 604 | }, 605 | "execution_count": 20, 606 | "metadata": {}, 607 | "output_type": "execute_result" 608 | } 609 | ], 610 | "source": [ 611 | "order = MarketOrder('SELL', 200)\n", 612 | "ib.whatIfOrder(contract, order)" 613 | ] 614 | }, 615 | { 616 | "cell_type": "code", 617 | "execution_count": 21, 618 | "metadata": {}, 619 | "outputs": [], 620 | "source": [ 621 | "ib.disconnect()" 622 | ] 623 | }, 624 | { 625 | "cell_type": "markdown", 626 | "metadata": {}, 627 | "source": [ 628 | "***" 629 | ] 630 | } 631 | ], 632 | "metadata": { 633 | "kernelspec": { 634 | "display_name": "Python 3", 635 | "language": "python", 636 | "name": "python3" 637 | }, 638 | "language_info": { 639 | "codemirror_mode": { 640 | "name": "ipython", 641 | "version": 3 642 | }, 643 | "file_extension": ".py", 644 | "mimetype": "text/x-python", 645 | "name": "python", 646 | "nbconvert_exporter": "python", 647 | "pygments_lexer": "ipython3", 648 | "version": "3.6.4" 649 | } 650 | }, 651 | "nbformat": 4, 652 | "nbformat_minor": 2 653 | } 654 | -------------------------------------------------------------------------------- /ib-insync notebooks/tick_data.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Tick data\n", 8 | "\n", 9 | "For optimum results this notebook should be run during the Forex trading session." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [ 17 | { 18 | "name": "stderr", 19 | "output_type": "stream", 20 | "text": [ 21 | "ERROR:ib_insync.wrapper:Error 321, reqId 1: Error validating request:-'aS' : cause - ALL account is not supported\n" 22 | ] 23 | }, 24 | { 25 | "data": { 26 | "text/plain": [ 27 | "" 28 | ] 29 | }, 30 | "execution_count": 1, 31 | "metadata": {}, 32 | "output_type": "execute_result" 33 | } 34 | ], 35 | "source": [ 36 | "from ib_insync import *\n", 37 | "util.startLoop()\n", 38 | "\n", 39 | "ib = IB()\n", 40 | "ib.connect('127.0.0.1', 4002, clientId=5)" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": {}, 46 | "source": [ 47 | "Create some Forex contracts:" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 2, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "contracts = [Forex(pair) for pair in 'EURUSD USDJPY GBPUSD USDCHF USDCAD AUDUSD'.split()]\n", 57 | "\n", 58 | "eurusd = contracts[0]" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "metadata": {}, 64 | "source": [ 65 | "Request streaming ticks for them:" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": 3, 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "for contract in contracts:\n", 75 | " ib.reqMktData(contract, '', False, False)" 76 | ] 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "metadata": {}, 81 | "source": [ 82 | "Wait a few seconds for the tickers to get filled." 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 4, 88 | "metadata": {}, 89 | "outputs": [ 90 | { 91 | "data": { 92 | "text/plain": [ 93 | "Ticker(contract=Forex('EURUSD', exchange='IDEALPRO'), time=datetime.datetime(2018, 6, 22, 5, 43, 15, 337546, tzinfo=datetime.timezone.utc), bid=1.16281, bidSize=1000000, ask=1.16283, askSize=1500000, prevBid=1.1628, prevBidSize=8500000, prevAsk=1.16282, prevAskSize=2500000, high=1.16385, low=1.16005, close=1.1603, ticks=[], tickByTicks=[], domBids=[], domAsks=[], domTicks=[])" 94 | ] 95 | }, 96 | "execution_count": 4, 97 | "metadata": {}, 98 | "output_type": "execute_result" 99 | } 100 | ], 101 | "source": [ 102 | "ticker = ib.ticker(eurusd)\n", 103 | "ib.sleep(2)\n", 104 | "\n", 105 | "ticker" 106 | ] 107 | }, 108 | { 109 | "cell_type": "markdown", 110 | "metadata": {}, 111 | "source": [ 112 | "The price of Forex ticks is always nan. To get a midpoint price use ``marketPrice()``.\n", 113 | "\n", 114 | "The tickers are kept\n", 115 | "live updated, try this a few times to see if the price changes:" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": 5, 121 | "metadata": {}, 122 | "outputs": [ 123 | { 124 | "data": { 125 | "text/plain": [ 126 | "1.16283" 127 | ] 128 | }, 129 | "execution_count": 5, 130 | "metadata": {}, 131 | "output_type": "execute_result" 132 | } 133 | ], 134 | "source": [ 135 | "ticker.marketPrice()" 136 | ] 137 | }, 138 | { 139 | "cell_type": "markdown", 140 | "metadata": {}, 141 | "source": [ 142 | "The following cell will start a 60 second loop that prints a live updated ticker table.\n", 143 | "It is updated on every ticker change." 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": 6, 149 | "metadata": {}, 150 | "outputs": [ 151 | { 152 | "data": { 153 | "text/html": [ 154 | "
\n", 155 | "\n", 168 | "\n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | " \n", 237 | " \n", 238 | " \n", 239 | " \n", 240 | " \n", 241 | " \n", 242 | " \n", 243 | " \n", 244 | " \n", 245 | " \n", 246 | " \n", 247 | " \n", 248 | " \n", 249 | " \n", 250 | "
symbolbidSizebidaskaskSizehighlowclose
0EURUSD80000001.162781.162815000001.163851.160051.1603
1USDJPY2000000109.964109.9663000000110.075109.85109.97
2GBPUSD10000001.327181.3272210000001.328251.323951.3245
3USDCHF40000000.99010.9901740000000.991950.989950.99185
4USDCAD30000001.329691.3297520000001.33221.329051.3316
5AUDUSD25000000.739590.739625000000.74030.73740.73795
\n", 251 | "
" 252 | ], 253 | "text/plain": [ 254 | " symbol bidSize bid ask askSize high low close\n", 255 | "0 EURUSD 8000000 1.16278 1.16281 500000 1.16385 1.16005 1.1603\n", 256 | "1 USDJPY 2000000 109.964 109.966 3000000 110.075 109.85 109.97\n", 257 | "2 GBPUSD 1000000 1.32718 1.32722 1000000 1.32825 1.32395 1.3245\n", 258 | "3 USDCHF 4000000 0.9901 0.99017 4000000 0.99195 0.98995 0.99185\n", 259 | "4 USDCAD 3000000 1.32969 1.32975 2000000 1.3322 1.32905 1.3316\n", 260 | "5 AUDUSD 2500000 0.73959 0.73962 500000 0.7403 0.7374 0.73795" 261 | ] 262 | }, 263 | "metadata": {}, 264 | "output_type": "display_data" 265 | } 266 | ], 267 | "source": [ 268 | "from IPython.display import display, clear_output\n", 269 | "import pandas as pd\n", 270 | "\n", 271 | "df = pd.DataFrame(columns='symbol bidSize bid ask askSize high low close'.split())\n", 272 | "df['symbol'] = [c.symbol + c.currency for c in contracts]\n", 273 | "contract2Row = {c: i for (i, c) in enumerate(contracts)}\n", 274 | "\n", 275 | "def onPendingTickers(tickers):\n", 276 | " for t in tickers:\n", 277 | " row = contract2Row[t.contract]\n", 278 | " df.iloc[row, 1:] = (t.bidSize, t.bid, t.ask, t.askSize, t.high, t.low, t.close)\n", 279 | " clear_output(wait=True)\n", 280 | " display(df) \n", 281 | "\n", 282 | "ib.setCallback('pendingTickers', onPendingTickers)\n", 283 | "ib.sleep(60)" 284 | ] 285 | }, 286 | { 287 | "cell_type": "markdown", 288 | "metadata": {}, 289 | "source": [ 290 | "New tick data is available in the 'ticks' attribute of the pending tickers.\n", 291 | "The tick data will be cleared before the next update." 292 | ] 293 | }, 294 | { 295 | "cell_type": "markdown", 296 | "metadata": { 297 | "collapsed": true 298 | }, 299 | "source": [ 300 | "To stop the live tick subscriptions:" 301 | ] 302 | }, 303 | { 304 | "cell_type": "code", 305 | "execution_count": 7, 306 | "metadata": {}, 307 | "outputs": [], 308 | "source": [ 309 | "for contract in contracts:\n", 310 | " ib.cancelMktData(contract)" 311 | ] 312 | }, 313 | { 314 | "cell_type": "code", 315 | "execution_count": 8, 316 | "metadata": {}, 317 | "outputs": [], 318 | "source": [ 319 | "ib.disconnect()" 320 | ] 321 | }, 322 | { 323 | "cell_type": "markdown", 324 | "metadata": { 325 | "collapsed": true 326 | }, 327 | "source": [ 328 | "***" 329 | ] 330 | } 331 | ], 332 | "metadata": { 333 | "kernelspec": { 334 | "display_name": "Python 3", 335 | "language": "python", 336 | "name": "python3" 337 | }, 338 | "language_info": { 339 | "codemirror_mode": { 340 | "name": "ipython", 341 | "version": 3 342 | }, 343 | "file_extension": ".py", 344 | "mimetype": "text/x-python", 345 | "name": "python", 346 | "nbconvert_exporter": "python", 347 | "pygments_lexer": "ipython3", 348 | "version": "3.6.4" 349 | } 350 | }, 351 | "nbformat": 4, 352 | "nbformat_minor": 2 353 | } 354 | -------------------------------------------------------------------------------- /ib_class.py: -------------------------------------------------------------------------------- 1 | import time 2 | from datetime import datetime 3 | from IBWrapper import IBWrapper, contract 4 | from ib.ext.EClientSocket import EClientSocket 5 | from ib.ext.ScannerSubscription import ScannerSubscription 6 | from __future__ import print_function 7 | 8 | if __name__=="__main__": 9 | callback = IBWrapper() # Instantiate IBWrapper 10 | tws = EClientSocket(callback) # Instantiate EClientSocket 11 | host = "" 12 | port = 7496 13 | clientId = 5000 14 | tws.eConnect(host, port, clientId) # Connect to TWS 15 | tws.setServerLogLevel(5) 16 | accountName = "DU123456" # Change to your own account 17 | create = contract() # Instantiate contract class 18 | 19 | # Initiate attributes to receive data. At some point we need a separate class for this 20 | callback.initiate_variables() 21 | 22 | # Account and Portfolio ############################################################## 23 | # reqAccountUpdates ---> updateAccountTime self.update_AccountTime 24 | # updateAccountValue self.update_AccountValue 25 | # updatePortfolio self.update_Portfolio 26 | # accountDownloadEnd self.accountDownloadEnd_flag 27 | # reqAccountSummary ---> accountSummary self.account_Summary 28 | # cancelAccountSummary 29 | # accountSummaryEnd self.account_SummaryEnd_flag 30 | # reqPositions ---> position self.update_Position 31 | # cancelPositions 32 | # positionEnd self.positionEnd_flag 33 | ###################################################################################''' 34 | print "Testing Account and Portfolio \n" 35 | tws.reqAccountUpdates(1, accountName) 36 | tws.reqAccountSummary(1,"All","NetLiquidation") 37 | #tws.cancelAccountSummary(1) 38 | tws.reqPositions() 39 | #tws.cancelPositions() 40 | 41 | 42 | 43 | 44 | 45 | 46 | # Orders ############################################################################# 47 | # placeOrder ---> orderStatus** self.order_Status 48 | # cancelorder 49 | # ---> openOrderEnd self.open_OrderEnd_flag 50 | # reqOpenOrders ---> openOrder* self.open_Order 51 | # ---> orderStatus** 52 | # reqAllOpenOrders ---> openOrder* 53 | # ---> orderStatus** 54 | # reqAutoOpenOrders ---> openOrder* 55 | # ---> orderStatus** 56 | # reqIds ---> nextValidId self.next_ValidId 57 | # ---> deltaNeutralValidation 58 | # exerciseOptions 59 | # reqGlobalCancel 60 | ###################################################################################''' 61 | print "Testing Orders Group \n" 62 | # Example 1 - placing order to buy stock 63 | tws.reqIds(1) # Need to request next valid order Id 64 | time.sleep(2) # wait for response from server 65 | order_id = callback.next_ValidId 66 | contract_info1 = create.create_contract('GOOG', 'STK', 'SMART', 'USD') 67 | order_info1 = create.create_order(accountName, 'MKT', 100, 'BUY') 68 | tws.placeOrder(order_id, contract_info1, order_info1) 69 | 70 | # Example 2 - placing order to buy FX 71 | tws.reqIds(1) 72 | time.sleep(1) 73 | order_id = callback.next_ValidId 74 | contract_info2 = create.create_contract('EUR', 'CASH', 'IDEALPRO', 'USD') 75 | order_info2 = create.create_order(accountName, 'MKT', 100000, 'BUY') 76 | tws.placeOrder(order_id, contract_info2, order_info2) 77 | 78 | #tws.cancelOrder(order_id) # Cancel example 2 order 79 | #tws.reqOpenOrders() 80 | #tws.reqAllOpenOrders() 81 | #tws.reqAutoOpenOrders(1) # clientId had to be 0 for this to work 82 | tws.reqGlobalCancel() 83 | 84 | 85 | 86 | 87 | 88 | # Market Data ######################################################################## 89 | # reqMktData ---> tickPrice self.tick_Price 90 | # ---> tickSize self.tick_Size 91 | # ---> tickOptionComputation self.tick_OptionComputation 92 | # ---> tickGeneric self.tick_Generic 93 | # ---> tickString self.tick_String 94 | # ---> tickEFP self.tick_EFP 95 | # ---> tickSnapshotEnd self.tickSnapshotEnd_flag 96 | # cancelMktData 97 | # calculateImpliedVolatility >tickOptionComputation self.tick_OptionComputation 98 | # cancelcalculateImpliedVolatility 99 | # calculateOptionPrice ---> tickOptionComputation self.tick_OptionComputation 100 | # cancelCalculateOptionPrice 101 | # reqMktDataType ---> marketDataType self.market_DataType 102 | ###################################################################################''' 103 | '''print "Testing Market Data Group \n" 104 | contract_info3 = create.create_contract('EUR', 'CASH', 'IDEALPRO', 'USD') 105 | tws.reqMktData(1, contract_info3, "", False) 106 | 107 | contract_info4 = create.create_contract('NFLX 160318C00100000', 108 | 'OPT', 'SMART', 'USD', 109 | 'CALL', '100', '20160318', 110 | 100, "NFLX") 111 | tws.calculateImpliedVolatility(2, contract_info4, 3.60, 94.41) 112 | tws.calculateOptionPrice(3, contract_info4, 0.42, 94.41) 113 | tws.reqMarketDataType(2) # need to test this when mkt opens 114 | time.sleep(2) 115 | tws.cancelMktData(1) 116 | tws.cancelCalculateImpliedVolatility(2) 117 | tws.cancelCalculateOptionPrice(3) 118 | 119 | 120 | 121 | 122 | 123 | # Connection and Server ############################################################## 124 | # EClientSocket 125 | # eConnect 126 | # eDisconnect ---> connectionClosed 127 | # isConnected 128 | # setServerLogLevel 129 | # reqCurrentTime ---> currentTime self.current_Time 130 | # serverVersion 131 | # TwsConnectionTime 132 | # ---> error 133 | ###################################################################################''' 134 | print "Testing Connection and Server Group \n" 135 | print tws.isConnected() 136 | tws.setServerLogLevel(5) 137 | tws.reqCurrentTime() 138 | print "Server Version " + str(tws.serverVersion()) 139 | print "TWS Connection Time %s " % tws.TwsConnectionTime() 140 | 141 | 142 | 143 | 144 | 145 | # Executions ######################################################################### 146 | # reqExecutions ---> execDetails self.exec_Details_reqId 147 | # self.exec_Details_contract 148 | # self.exec_Details_execution 149 | # ---> execDetailsEnd self.exec_DetailsEnd_flag 150 | # ---> commissionReport self.commission_Report 151 | ###################################################################################''' 152 | print "Testing Executions Group \n" 153 | order_id = [] 154 | tws.reqIds(1) 155 | while not order_id: 156 | time.sleep(0.1) 157 | order_id = callback.next_ValidId 158 | print "waiting for id" 159 | order_id = callback.next_ValidId 160 | print ("Just got it. The next order id is: ", order_id) 161 | contract_info5 = create.create_contract('EUR', 'CASH', 'IDEALPRO', 'USD') 162 | order_info5 = create.create_order(accountName, 'MKT', 100000, 'BUY') 163 | tws.placeOrder(order_id, contract_info5, order_info5) 164 | time.sleep(2) 165 | tws.reqExecutions(0, create.exec_filter(9999, accountName, contract_info5)) 166 | 167 | 168 | 169 | 170 | 171 | # Contract ########################################################################### 172 | # reqContractDetails ---> contractDetails self.contract_Details_reqId 173 | # self.contract_Details 174 | # ---> contractDetailsEnd self.contract_DetailsEnd_reqId 175 | # self.contract_Details_flag 176 | # ---> bondContractDetails self.bond_ContractDetails_reqId 177 | # self.bond_ContractDetails 178 | ###################################################################################''' 179 | print "Testing Contract Group \n" 180 | # Example 1 - Option 181 | contract_Details6 = create.create_contract('NFLX 160318C00100000', 'OPT', 'SMART', 182 | 'USD', 'CALL', '100', '20160318', 183 | 100, "NFLX") 184 | tws.reqContractDetails(5000, contract_Details6) 185 | while not callback.contract_Details_flag: 186 | time.sleep(1) 187 | callback.contract_Details_flag = False 188 | print callback.contract_Details_reqId 189 | print callback.contract_Details.__dict__ 190 | 191 | # Example 2 - Stock 192 | contract_Details7 = create.create_contract('EUR', 'CASH', 'IDEALPRO', 'USD') 193 | tws.reqContractDetails(5001, contract_Details7) 194 | while not callback.contract_Details_flag: 195 | time.sleep(1) 196 | callback.contract_Details_flag = False 197 | print callback.contract_Details_reqId 198 | print callback.contract_Details.__dict__ 199 | 200 | # Example 3 - FX 201 | contract_Details8 = create.create_contract('IBCID143913442', 202 | 'BOND', 'SMART', 203 | 'USD','CORP') 204 | tws.reqContractDetails(5002, contract_Details8) 205 | while not callback.contract_Details_flag: 206 | time.sleep(1) 207 | callback.contract_Details_flag = False 208 | print callback.bond_ContractDetails_reqId 209 | print callback.bond_ContractDetails.__dict__ 210 | 211 | 212 | 213 | 214 | 215 | # Market Depth ####################################################################### 216 | # reqMktDepth ---> updateMktDepth self.update_MktDepth 217 | # ---> update_MktDepthL2 self.update_MktDepthL2 218 | ###################################################################################''' 219 | print "Testing Market Depth Group \n" 220 | contract_info9 = create.create_contract('EUR', 'CASH', 'IDEALPRO', 'USD') 221 | tws.reqMktDepth(7000, contract_info9, 3) 222 | time.sleep(5) 223 | print callback.update_MktDepth 224 | tws.cancelMktDepth(7000) 225 | 226 | 227 | 228 | 229 | 230 | # News Bulletin ###################################################################### 231 | # reqNewsBulletins ---> updateNewsBulletin self.update_NewsBulletin_msgId 232 | # self.update_NewsBulletin_msgType 233 | # self.update_NewsBulletin_message 234 | # self.update_NewsBulletin_origExchange 235 | ###################################################################################''' 236 | print "Testing News Bulletin Group \n" 237 | tws.reqNewsBulletins(1) 238 | time.sleep(20) 239 | tws.cancelNewsBulletins() 240 | 241 | 242 | 243 | 244 | 245 | # Financial Advisors Group ########################################################### 246 | # reqManagedAccts ---> managedAccounts self.managed_Accounts 247 | ###################################################################################''' 248 | print "Testing Financial Advisors Group \n" 249 | tws.reqManagedAccts() 250 | #tws.requestFA() # non FA account. Unable to test. 251 | 252 | 253 | 254 | 255 | 256 | 257 | # Historical Data #################################################################### 258 | # reqHistoricalData ---> historicalData self.historical_Data 259 | ###################################################################################''' 260 | print "Testing Historical Data Group \n" 261 | contract_Details10 = create.create_contract('EUR', 'CASH', 'IDEALPRO', 'USD') 262 | data_endtime = datetime.now().strftime("%Y%m%d %H:%M:%S") 263 | tws.reqHistoricalData(9000, contract_Details10, data_endtime, 264 | "1 M", "1 day", "BID", 0, 1) 265 | time.sleep(3) 266 | tws.cancelHistoricalData(9000) 267 | 268 | 269 | 270 | 271 | 272 | # Market Scanners #################################################################### 273 | # reqScannerParameters ---> scannerParameters self.scanner_Parameters 274 | # ---> scannerData self.scanner_Data 275 | # ---> scannerDataEnd self.scanner_Data_End_reqID 276 | # self.scanner_Data_reqID 277 | ###################################################################################''' 278 | print "Testing Market Scanners Group \n" 279 | subscript = ScannerSubscription() 280 | subscript.numberOfRows(3) 281 | subscript.locationCode('STK.NYSE') 282 | tws.reqScannerSubscription(700, subscript) 283 | tws.reqScannerParameters() 284 | time.sleep(3) 285 | tws.cancelScannerSubscription(700) 286 | 287 | 288 | 289 | 290 | 291 | # Real Time Bars ##################################################################### 292 | # reqRealTimeBars ---> realtimeBar self.real_timeBar 293 | ###################################################################################''' 294 | print "Testing Real Time Bars Group \n" 295 | contract_Details11 = create.create_contract('EUR', 'CASH', 'IDEALPRO', 'USD') 296 | tws.reqRealTimeBars(10000, contract_Details11, 5, "MIDPOINT", 0) 297 | time.sleep(10) 298 | tws.cancelRealTimeBars(10000) 299 | 300 | 301 | 302 | 303 | 304 | # Fundamental Data ################################################################### 305 | # reportType = ReportSnapshot 306 | # ReportsFinSummary 307 | # ReportsFinSummary 308 | # ReportRatios 309 | # ReportFinStatements 310 | # RESC 311 | # Calendar Report 312 | # Unfortunately, no access. 430, 'We are sorry, but fundamentals data for the 313 | # security specified is not available.Not allowed' 314 | ###################################################################################''' 315 | '''print "Testing Fundamental Data Group \n" 316 | contract_info12 = create.create_contract('AAPL', 'STK', 'SMART', 'USD') 317 | reportType = "ReportSnapshot" 318 | tws.reqFundamentalData(10100, contract_info12, reportType) 319 | time.sleep(10) 320 | tws.cancelFundamentalData(10100)''' 321 | 322 | 323 | 324 | 325 | 326 | # Disconnect from TWS 327 | time.sleep(2) 328 | tws.isConnected() 329 | tws.eDisconnect() 330 | -------------------------------------------------------------------------------- /xiang.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This is a very rough implementation of long short SMA 3 | Do not trade with this. 4 | It is for education purpose. Use at your own risk. 5 | 6 | obtain_hist_data :- extract historical data. 7 | SMA :- calculate moving averages 8 | 9 | check_existin_pos :- check if we already have a position. 10 | 11 | ''' 12 | 13 | 14 | import pandas as pd 15 | import numpy as np 16 | import time 17 | from datetime import datetime 18 | from IBWrapper import IBWrapper, contract 19 | from ib.ext.EClientSocket import EClientSocket 20 | 21 | def obtain_hist_data(tws, callback): 22 | # Request historical data for calculation of moving averages 23 | # the historical lookback is hardcoded 24 | # as is the frequency 25 | # should really check the data returned is the same ID we called. 26 | # fixed to look back from today 27 | 28 | tickerId = 9004 29 | data_endtime = datetime.now().strftime("%Y%m%d %H:%M:%S") 30 | tws.reqHistoricalData(tickerId, 31 | contract_Details, 32 | data_endtime, 33 | "6 M", 34 | "1 day", 35 | "TRADES", 36 | 0, 37 | 1) 38 | time.sleep(2) 39 | data = pd.DataFrame(callback.historical_Data, 40 | columns = ["reqId", "date", "open", 41 | "high", "low", "close", 42 | "volume", "count", "WAP", 43 | "hasGaps"]) 44 | return data 45 | 46 | 47 | def SMA(data, short_length, long_length): 48 | # calculate two moving averages 49 | data = data.dropna() 50 | short_SMA = data['close'].rolling(short_length).mean() 51 | long_SMA = data['close'].rolling(long_length).mean() 52 | 53 | return short_SMA.iloc[-1], long_SMA.iloc[-1] 54 | 55 | def check_existing_pos(): 56 | # 0 is no position, 1 means we have existing position 57 | # we need to write an algo to send request to IB to check 58 | # whether we have existing position 59 | # you will need a proper identifier for your position. 60 | pos = 1 61 | return pos 62 | 63 | # connect 64 | accountName = "DU000000" 65 | callback = IBWrapper() # Instantiate IBWrapper. callback 66 | tws = EClientSocket(callback) # Instantiate EClientSocket and return data to callback 67 | host = "" 68 | port = 4002 69 | clientId = 4002 70 | order_id = 1001 71 | 72 | tws.eConnect(host, port, clientId) # Connect to TWS 73 | 74 | # Let's work with APPLE stock. 75 | create = contract() 76 | callback.initiate_variables() 77 | contract_Details = create.create_contract('AAPL', 'STK', 'SMART', 'USD') 78 | 79 | ''' 80 | This should be the beginning of the while loop 81 | This is an infinite loop. 82 | ''' 83 | while 1: 84 | # let's get some historical data 85 | data = obtain_hist_data(tws, callback) 86 | 87 | 88 | short_SMA, long_SMA = SMA(data, 5, 10) 89 | print("short_SMA {}, long_SMA {}".format(short_SMA, long_SMA)) 90 | 91 | # trading decision 92 | # ideally we need a check to see if we already have a position. 93 | # Else we keep sending a buy 94 | if short_SMA > long_SMA: 95 | pos = check_existing_pos() 96 | print(pos) 97 | if not pos: 98 | print("[INFO] order placing...") 99 | tws.reqIds(1) 100 | order_id = callback.next_ValidId + 1 101 | # placing order 102 | order_info = create.create_order(accountName, "MKT", 250, "BUY") 103 | tws.placeOrder(order_id, contract_Details, order_info) 104 | time.sleep(2) 105 | order_status_update = pd.DataFrame(callback.order_Status, 106 | columns = ['orderId', 'status', 'filled', 'remaining', 'avgFillPrice', 107 | 'permId', 'parentId', 'lastFillPrice', 'clientId', 'whyHeld']) 108 | # if the order is filled, it should be picked up by the 109 | # check_existing_pos function. The place order should not 110 | # be fired. 111 | 112 | # disconnnet 113 | tws.eDisconnect() 114 | 115 | --------------------------------------------------------------------------------