IB/TWS with PHP?

Discussion in 'Automated Trading' started by corbel, Apr 23, 2010.

  1. chuzek

    chuzek

    Likewise, I found the IB API very complicated compared to TD and Just2Trade and have pretty much written it off. Just2Trade not only has an easier to implement API, but depending on the quantity of your trades, it's also cheaper. All equity trades are a flat $2.50. IB is 0.013 per share with a minimum fee of $1.30. So unless you always plan on trading less than about 190 shares per trade, Just2Trade is cheaper. (Initially, I probably be trading less than that, but given the easier to implement API, I won't quibble over $1.20 or so).

    You are correct about TD encouraging people to stream quotes. If you've got PHP code on how to do it that you'd like to share, I'll replace my cron job method. In the meantime, I'm only calling it about every one to five minutes for less than ten stocks on average. I should hope they can handle such a small request.

    Thanks for the link, I had not seen that website before.
     
    #11     Apr 26, 2010
  2. chuzek

    chuzek

    I believe you are correct. They have a link at http://www.interactivebrokers.com/en/p.php?f=fixctci&ib_entity=llc

    I haven't reviewed the their particular FIX API, but it may be even more complicated than their regular API.
     
    #12     Apr 26, 2010
  3. byteme

    byteme

    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

    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).

    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.

    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.
     
    #13     Apr 26, 2010
  4. chuzek

    chuzek

    Likewise, I think IB is pretty challenging to code in PHP, that's why I'm aiming for a TD/Just2Trade combo that eliminates the quote asynchronicity.

    For me, there are numerous benefits to a web-app. First, I have complete access from any web-enabled device (even a "dumbphone" with web access) with no need for Java. Secondly, I can easily create email and SMS alerts (I suppose it's possible with C++ and Java, but it may be more complicated to code. It's done with one single line of code in PHP). Thirdly, if I miraculously create a successful algorithm, I'm easily able to manage the brokerage accounts for friends and family who don't know how or can't manage a desktop trading platform.
     
    #14     Apr 26, 2010
  5. byteme

    byteme

    Because it isn't an API!

    The APIs IB offer are in C++, Java, ActiveX etc. Not PHP and not via sockets. To get around the lack of PHP support you're reduced to trying to replicate their API by directly communicating with sockets and reverse engineering the official API implementations.

    IB aren't expecting people to do this. It was not designed that way.

    I'm obviously not communicating clearly enough: You can't use a socket based connection from a web page request unless you open/close the socket on each request. The web is request/response based. You can't store the socket in a session and continue receiving messages from the socket in between web requests. The web server will sit there doing nothing for a hundred years unless you make a new request.

    You have to go outside of the web server i.e. to desktop or server applications to make meaningful use of the socket connection as per my inital posts on this thread. At which point having a web application in the equation no longer makes any sense.
     
    #15     Apr 26, 2010
  6. chuzek

    chuzek

    I understand this and utilized TD's RESTful method of obtaining quotes. Marrying this to Just2Trade's API platform gives you all the needed functionality in a web based application.
     
    #16     Apr 26, 2010
  7. byteme

    byteme

    The question isn't about PHP but about using a web application.

    You can use PHP to do the socket connection and monitoring, e-mailing, SMS, placing orders, receiving execution reports etc. ALL outside of the web server in a process that's running continuously outside of the web server so you don't have to worry about reconnecting on every web request and you don't have to worry about missing execution reports or fill reports or status messages. Your PHP process will be running and monitoring this continuously.

    Then, if you need a web interface to show what's going on, simply pull that information from your PHP server on an as-needed basis. You can do this by building your normal PHP web application using CakePHP or Codeigniter or whatever you like and then the model can be whatever you want. Perhaps your PHP server process writes to a database? Orders filled, orders processing, last prices etc. i.e. a snapshot of the current state. It then becomes trivial to retrieve this in your web application in a way that is suitable for the request/response model of the web.

    Anyway, I'm sure you'll find something that works for you.
     
    #17     Apr 26, 2010
  8. byteme

    byteme

    As I said in the other thread, this is much more complicated - trying to build a FIX engine in PHP is a non-trivial undertaking and again, doesn't make sense to use from a web application. If you really want to you're better off trying to build a PHP extension using one of the C++ FIX engines.
     
    #18     Apr 26, 2010
  9. What about phix?
    http://sourceforge.net/projects/phix/
     
    #19     Jun 12, 2010
  10. I found this old discussion thread about using the IB API from PHP. I am looking at the same issues and I am wondering if you ever completed a satisfactory solution.

    My current approach is to use their java API from our php web server in response to ajax requests from the web app. If you have any thoughts or code that could help from your experience I would appreciate it.
     
    #20     Jan 30, 2013