Quote from corbel:
byteme, thanks again for all the information you're providing, and chuzek for relating your experience.
byteme, that code is exactly what I've been combing the internet for. I hope I can extract what I need to from your example.
No need to comb. If you dowload the IB API, all of the code is in there (Java) or the link I used before (Python):
http://code.google.com/p/ibpy/source/browse/#svn/trunk/ib/ext
I'm hoping that interaction with IB can be very simple and do this:
- connect to IB TWS, opening a socket
- write a string to the socket
- read the server's response on that socket
Well in principle it
is simple. The recurring problem though is that the server's response for market data is asynchronous and you are trying to wrap that up into a model that is synchronous (web requests).
For instance, it looks like just2trade provides the string for you that it wants to receive, so the php request would look a lot like what I have below. (where you'd replace "symbol" with "DELL" and "limitprice" with 44.51, etc):
It is not that straightforward with the IB TWS socket. You first have to connect (send a message, receive a message). Then you can subscribe to marketdata (send a message). Then you have to wait for any market data messages that come back and decode them accordingly. Asynchronous.
Heck, if byteme says the above isn't possible with IB, I may just stop my search now and jump ship.
There's no inherent reason why you can't use PHP with IB. I just don't see the benefits of building a web application to interact with the API. I see a lot of drawbacks though. If you want to use PHP, why not create a desktop application that isn't bound by the request/response model of the web? Remember, the place you are connecting to is a running instance of TWS (Trader Workstation or IB Gateway) running on somebody's computer. It's not like communicating with a remote web service that is hosted at with your broker. You have to take this into account also. In other words you need to be running your own server.
Why don't you try downloading TWS from the IB website in the first instance to understand how the whole setup works if you haven't already.
To request market data, you'll have to replicate this function (found in EClientSocket.java/EClientSocket.py):
Code:
def reqMktData(self, tickerId, contract, genericTickList, snapshot):
if not self.m_connected:
self.error(EClientErrors.NO_VALID_ID, EClientErrors.NOT_CONNECTED, "")
return
if self.m_serverVersion < self.MIN_SERVER_VER_SNAPSHOT_MKT_DATA and snapshot:
self.error(tickerId, EClientErrors.UPDATE_TWS, " It does not support snapshot market data requests.")
return
if self.m_serverVersion < self.MIN_SERVER_VER_UNDER_COMP:
if contract.m_underComp is not None:
self.error(tickerId, EClientErrors.UPDATE_TWS, " It does not support delta-neutral orders.")
return
VERSION = 8
try:
self.send(self.REQ_MKT_DATA)
self.send(VERSION)
self.send(tickerId)
self.send(contract.m_symbol)
self.send(contract.m_secType)
self.send(contract.m_expiry)
self.send(contract.m_strike)
self.send(contract.m_right)
if self.m_serverVersion >= 15:
self.send(contract.m_multiplier)
self.send(contract.m_exchange)
if self.m_serverVersion >= 14:
self.send(contract.m_primaryExch)
self.send(contract.m_currency)
if self.m_serverVersion >= 2:
self.send(contract.m_localSymbol)
if self.m_serverVersion >= 8 and self.BAG_SEC_TYPE.lower() == contract.m_secType.lower():
if contract.m_comboLegs is None:
self.send(0)
else:
self.send(len(contract.m_comboLegs))
comboLeg = ComboLeg()
## for-while
i = 0
while i < len(contract.m_comboLegs):
comboLeg = contract.m_comboLegs(i)
self.send(comboLeg.m_conId)
self.send(comboLeg.m_ratio)
self.send(comboLeg.m_action)
self.send(comboLeg.m_exchange)
i += 1
if self.m_serverVersion >= self.MIN_SERVER_VER_UNDER_COMP:
if contract.m_underComp is not None:
underComp = contract.m_underComp
self.send(True)
self.send(underComp.m_conId)
self.send(underComp.m_delta)
self.send(underComp.m_price)
else:
self.send(False)
if self.m_serverVersion >= 31:
self.send(genericTickList)
if self.m_serverVersion >= self.MIN_SERVER_VER_SNAPSHOT_MKT_DATA:
self.send(snapshot)
except (Exception, ), e:
self.error(tickerId, EClientErrors.FAIL_SEND_REQMKT, str(e))
self.close()
Basically you have to construct a message as follows:
Send: 1 (this represents a market data request)
Send: 8 (this is the version)
Send: (tickerID) (this is a number chosen by you to keep track of the tickers you have requested market data for)
Send: GOOG (this is the symbol you are requesting market data for)
Send: STK (this is the security type)
...repeat for other contract properties e.g. exchange, expiry, strike price etc.
...lots of if/elses depending on the verions and contract types
Then, you will have to be listening for messages coming back from the socket. Some of them will be unrelated to your market data request. You can't just ignore them though. You have to read the correct number of bytes for that particular message otherwise you won't be able to find the beginning of the next message. For each message you can decode it using the code found in EReader.java/EReader.py)
For example, you may receive a market data message for the ticker you subscribed to.
Read: 1 followed by a zero byte (this represents the beginning of a tick price message and means the following bytes will be part of a tick price message - perhaps bid, ask, or last price amongst others)
Each part of the message will be terminated by a zero byte.
The code here is pretty self explanatory:
http://code.google.com/p/ibpy/source/browse/trunk/ib/ext/EReader.py
In short, you're in for a lot of work that may be reduced if you can somehow code an automatic translator from the Java code to the PHP equivalent (this is how the Python version is generated I believe). In general, to re-iterate, people are not expected to code all of this. This isn't an official API. Only people that want to use the API from an unsupported languange go to the lengths needed to code this kind of stuff.
If you find a broker that has an
official socket based API then it will certainly be a lot simpler as the API will be designed for end-user use.
Once you have built your equivalent version of the API in PHP, you'll then have to get familiar with actually
using the API and all of it's quirks. Finally, in the end you may find that it's simply not practical to use the IB API for web-based requests as you can't keep the socket open across requests which means you have to open it, connect, request data, wait for data etc. for every page request and deal with request time-outs, disconnections etc. You'll also miss if TWS has it's own connection problems because you won't be connected to it all of the time and so it won't be able to notify you when these event's occur. I could go on....but you're free to try and pursue this route if you choose to.
At any rate, good luck.