A couple of things/definitions/conventions:
- a *low level message* is some data prefixed with its size
- a *high level message* is a list of fields separated by the NULL
character; the fields are all strings; the message ID is the first
field, the come others whose number and semantics depend on the
message itself
- a *request* is a message from client to TWS/IBGW (IB Gateway)
- an *answer* is a message from TWS/IBGW to client
How the code is organized:
- *comm* module: has tools that know how to handle (eg: encode/decode)
low and high level messages
- *Connection*: glorified socket
- *Reader*: thread that uses Connection to read packets, transform to
low level messages and put in a Queue
- *Decoder*: knows how to take a low level message and decode into high
level message
- *Client*:
- knows to send requests
- has the message loop which takes low level messages from Queue and
uses Decoder to tranform into high level message with which it then
calls the corresponding Wrapper method
- *Wrapper*: class that needs to be subclassed by the user so that it
can get the incoming messages
The info/data flow is:
- receiving:
- *Connection.recv\_msg()* (which is essentially a socket) receives the
packets
- uses *Connection.\ *recv*\ all\_msgs()* which tries to combine
smaller packets into bigger ones based on some trivial heuristic
- *Reader.run()* uses *Connection.recv\_msg()* to get a packet and then
uses *comm.read\_msg()* to try to make it a low level message. If
that can't be done yet (size prefix says so) then it waits for more
packets
- if a full low level message is received then it is placed in the
Queue (remember this is a standalone thread)
- the main thread runs the *Client.run()* loop which:
- gets a low level message from Queue
- uses *comm.py* to translate into high level message (fields)
- uses *Decoder.interpret()* to act based on that message
- *Decoder.interpret()* will translate the fields into function
parameters of the correct type and call with the
correct/corresponding method of *Wrapper* class
- sending:
- *Client* class has methods that implement the *requests*. The user
will call those request methods with the needed parameters and
*Client* will send them to the TWS/IBGW.
Implementation notes:
- the *Decoder* has two ways of handling a message (esentially decoding
the fields)
- some message very neatly map to a function call; meaning that the
number of fields and order are the same as the method parameters.
For example: Wrapper.tickSize(). In this case a simple mapping is
made between the incoming msg id and the Wrapper method:
IN.TICK\_SIZE: HandleInfo(wrap=Wrapper.tickSize),
- other messages are more complex, depend on version number heavily
or need field massaging. In this case the incoming message id is
mapped to a processing function that will do all that and call the
Wrapper method at the end. For example:
IN.TICK\_PRICE: HandleInfo(proc=processTickPriceMsg),
Instalation notes:
- you can use this to build a source distribution
python3 setup.py sdist
- you can use this to build a wheel
python3 setup.py bdist\_wheel
- you can use this to install the wheel
python3 -m pip install --user --upgrade
dist/ibapi-9.75.1-py3-none-any.whl
Raw data
{
"_id": null,
"home_page": "https://interactivebrokers.github.io/tws-api",
"name": "ibapi",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.1",
"maintainer_email": "",
"keywords": "ib,interactive brokers,ibpy,tws",
"author": "IBG LLC",
"author_email": "dnastase@interactivebrokers.com",
"download_url": "https://files.pythonhosted.org/packages/cc/78/8f1322aa1be1fe7d747d06d445ede80141e873525120bde809ccae5484fa/ibapi-9.81.1.post1.tar.gz",
"platform": "",
"description": "A couple of things/definitions/conventions:\n\n- a *low level message* is some data prefixed with its size\n- a *high level message* is a list of fields separated by the NULL\n character; the fields are all strings; the message ID is the first\n field, the come others whose number and semantics depend on the\n message itself\n- a *request* is a message from client to TWS/IBGW (IB Gateway)\n- an *answer* is a message from TWS/IBGW to client\n\nHow the code is organized:\n\n- *comm* module: has tools that know how to handle (eg: encode/decode)\n low and high level messages\n- *Connection*: glorified socket\n- *Reader*: thread that uses Connection to read packets, transform to\n low level messages and put in a Queue\n- *Decoder*: knows how to take a low level message and decode into high\n level message\n- *Client*:\n- knows to send requests\n- has the message loop which takes low level messages from Queue and\n uses Decoder to tranform into high level message with which it then\n calls the corresponding Wrapper method\n- *Wrapper*: class that needs to be subclassed by the user so that it\n can get the incoming messages\n\nThe info/data flow is:\n\n- receiving:\n- *Connection.recv\\_msg()* (which is essentially a socket) receives the\n packets\n\n - uses *Connection.\\ *recv*\\ all\\_msgs()* which tries to combine\n smaller packets into bigger ones based on some trivial heuristic\n\n- *Reader.run()* uses *Connection.recv\\_msg()* to get a packet and then\n uses *comm.read\\_msg()* to try to make it a low level message. If\n that can't be done yet (size prefix says so) then it waits for more\n packets\n- if a full low level message is received then it is placed in the\n Queue (remember this is a standalone thread)\n- the main thread runs the *Client.run()* loop which:\n\n - gets a low level message from Queue\n - uses *comm.py* to translate into high level message (fields)\n - uses *Decoder.interpret()* to act based on that message\n\n- *Decoder.interpret()* will translate the fields into function\n parameters of the correct type and call with the\n correct/corresponding method of *Wrapper* class\n\n- sending:\n- *Client* class has methods that implement the *requests*. The user\n will call those request methods with the needed parameters and\n *Client* will send them to the TWS/IBGW.\n\nImplementation notes:\n\n- the *Decoder* has two ways of handling a message (esentially decoding\n the fields)\n\n - some message very neatly map to a function call; meaning that the\n number of fields and order are the same as the method parameters.\n For example: Wrapper.tickSize(). In this case a simple mapping is\n made between the incoming msg id and the Wrapper method:\n\n IN.TICK\\_SIZE: HandleInfo(wrap=Wrapper.tickSize),\n\n - other messages are more complex, depend on version number heavily\n or need field massaging. In this case the incoming message id is\n mapped to a processing function that will do all that and call the\n Wrapper method at the end. For example:\n\n IN.TICK\\_PRICE: HandleInfo(proc=processTickPriceMsg),\n\nInstalation notes:\n\n- you can use this to build a source distribution\n\npython3 setup.py sdist\n\n- you can use this to build a wheel\n\npython3 setup.py bdist\\_wheel\n\n- you can use this to install the wheel\n\npython3 -m pip install --user --upgrade\ndist/ibapi-9.75.1-py3-none-any.whl",
"bugtrack_url": null,
"license": "IB API Non-Commercial License or the IB API Commercial License",
"summary": "Official Interactive Brokers API",
"version": "9.81.1.post1",
"split_keywords": [
"ib",
"interactive brokers",
"ibpy",
"tws"
],
"urls": [
{
"comment_text": "",
"digests": {
"md5": "fa8f7acfcde1002664c315bef1b8f252",
"sha256": "49f6678bf4cced996920f32ad4b48e6897749ac30ba14a661082285f4ec09cd6"
},
"downloads": -1,
"filename": "ibapi-9.81.1.post1.tar.gz",
"has_sig": false,
"md5_digest": "fa8f7acfcde1002664c315bef1b8f252",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.1",
"size": 61109,
"upload_time": "2020-12-06T03:18:39",
"upload_time_iso_8601": "2020-12-06T03:18:39.916478Z",
"url": "https://files.pythonhosted.org/packages/cc/78/8f1322aa1be1fe7d747d06d445ede80141e873525120bde809ccae5484fa/ibapi-9.81.1.post1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2020-12-06 03:18:39",
"github": false,
"gitlab": false,
"bitbucket": false,
"lcname": "ibapi"
}