iklan header

The placing of orders to interactive brokers with swigibpy / python

We are nearly at the stop of our journey of simplistic examples of a way to get the swigibpy package to mediate among the exceptional global of Python and the darkish place that is the Interactive agents C API. Having found out a way to get 'photograph' and streaming fees out of the API we are now geared up to genuinely do a little buying and selling- post orders, test they're active, probably cancel them, get hold of fills and get ancient execution facts.

Interactive brokers now have a local python API. An up to date model of this post which uses that API is right here: http://qoppac.Blogspot.Co.United kingdom/2017/03/setting-orders-in-native-python-ib-api.Html

Where do I start?

You need to get the code from the subsequent repo.

The example code to run is in test4_IB.py. If you have a live or simulated Gateway / TWS session running (one associated with a real account number) it should work just fine.Note that you can also run this with the edemo account, but the results will be very ugly. This is because you are seeing the orders placed by everyone who is playing around with this account, so you could get all kinds of randomeness.

WARNING I highly recommend that you do not run this code on a real money trading account until / unless you know exactly what you are doing! In particular real trading code should check market liquidity before trading, particularly for market orders.

The output ought to be as in green underneath. Of direction feel free to alternate the agreement traded and the portions...

Expiry is 20150908

Getting orderid from IB

Using order identification of 1

Placed order, orderid is 1

Getting orderid from IB

Using order identity of 2

Placed restrict order, orderid is two

recived fill as follows:

{'orderid': '1', 'account': 'DU15031', 'exchange': 'DTB', 'symbol': 'GBL', 'permid': 193880352, 'execid': '00004468.559df2a0.01.01', 'clientid': '999', 'expiry': '20150908', 'price': 156.37, 'qty': 10, 'side': 'BOT', 'times': '20150709  14:05:11'}

Active orders: (ought to simply be limit order)

2: 'orderid': 2, 'symbol': 'GBL', 'qty': 10, 'side': 'SELL', 'clientid': 999L, 'expiry': '20150908'

Cancelling ultimate orders

Cancelling 2

Waiting for cancellation to finish

No energetic orders now

False

Following performed seeing that middle of the night this morning:

{'1': {'orderid': '1', 'account': 'DU15031', 'exchange': 'DTB', 'symbol': 'GBL', 'permid': 193880352, 'execid': '00004468.559df2a0.01.01', 'clientid': '999', 'expiry': '20150908', 'price': 156.37, 'qty': 10, 'side': 'BOT', 'times': '20150709  14:05:11'}}

Contract details - what is it?

As typical there is the tedious enterprise of getting a consumer item and defining a settlement. The first proper thing we need to do is get the settlement details. This may also sound a piece bizarre, we have already got the settlement details on account that we've got simply described it? In practice the definition of a contract is very light and the details we get returned are much richer.

There is one unique case where you should try this. To see why assume it's miles a few months time and you are buying and selling hundreds of futures contracts. A fill comes in for a particular agreement device code and month/year. However as we shall see the identity for the contract isn't always the 'yyyymm' code we use to define the contract, however the complete expiry 'yyyymmdd'. You can't simply take the primary 6 characters of that both on account that some futures clearly expire the month earlier than they ought to. So to be at the secure aspect I generally get the expiry from IB earlier than buying and selling to make sure I am making use of fills against the proper thingy.

Actually I don't do that right now before buying and selling but in a separate process that populates a database of agreement facts...

From test4_IB.Py

callback = IBWrapper()

    patron=IBclient(callback)

    ibcontract = IBcontract()

    ibcontract.SecType = "FUT"

    ibcontract.Expiry="201509"

    ibcontract.Symbol="GBL"

    ibcontract.Trade="DTB"

    cdetails=client.Get_contract_details(ibcontract)

WARNING: If you are trading the VIX, which now has weekly expiries, you will need to specify the full expiry date in yyyymmdd format.

I may not undergo the customer code in element but there are 'gotchas' in the server code that seem a few instances so lets have a look at an excerpt.

From wrapper_v4.Py, class IBWrapper:

def contractDetails(self, reqId, contractDetails):

        contract_details=self.Data_contractdetails[reqId]

contract_details["contractMonth"]=contractDetails.ContractMonth

        ## <SNIP - code removed>

contract_details["evMultiplier"]=contractDetails.EvMultiplier

        contract2 = contractDetails.Summary

        contract_details["expiry"]=contract2.Expiry

        ## <SNIP - code removed>

contract_details is of course a worldwide object that receives picked up by means of the consumer item while populated. The first of the two gotchas here is an old one; in case you are submitting multiple of those to the identical API session be careful to use significant request ID's. More subtle is that we do not just do some thing like contract_details=contractDetails.Instead we surely extract the statistics into a new item. The purpose is that the little jobbys are just weird recommendations that turns into hints to something else, commonly some bizarre reminiscence address, by the time you look at them out of doors of the callback example. So you have to capture their essence within the wild earlier than they get away. This is the widely known quantum guidelines impact.

To find out greater approximately contract and contractDetails gadgets observe themanual (C / SocketClient Properties).

Note I use a dicts or dicts of dicts right here for contracts, orders and fills but in truth I have little instructions for them to hold matters neater.

Order putting - can I purchase it?

Now the moment we've all been waiting for... we're actually going to buy something. For fun we're going to place two orders, a market order and a limit order.

From test4_IB.Py

## Place the order, asking IB to inform us what the subsequent order id is

    ## Note restrict fee of 0

    orderid1=purchaser.Place_new_IB_order(ibcontract, 10, zero.Zero, "MKT", orderid=None)

    print ""

    print "Placed marketplace order, orderid is %d" % orderid1

    ## And here's a restriction order, not going ever to be stuffed

    ## Note limit price of 100

    orderid2=purchaser.Place_new_IB_order(ibcontract, -10, two hundred.Zero, "LMT", orderid=None)

    print ""

    print "Placed limit order, orderid is %d" % orderid2

From wrapper_v4.Py, class IBclient:

def place_new_IB_order(self, ibcontract, exchange, lmtPrice, orderType, orderid=None):

<SNIP>

        iborder = IBOrder()

        iborder.Motion = bs_resolve(trade)

        iborder.LmtPrice = lmtPrice

        iborder.OrderType = orderType

        iborder.TotalQuantity = abs(exchange)

        iborder.Tif='DAY'

        iborder.Transmit=True

## We can eithier deliver our personal ID or ask IB to give us the following valid one

        if orderid is None:

            print "Getting orderid from IB"

            orderid=self.Get_next_brokerorderid()

        print "Using order identification of %d" % orderid

         # Place the order

        self.Tws.PlaceOrder(

                orderid,                                    # orderId,

                ibcontract,                                   # contract,

                iborder                                       # order

            )

        go back orderid

Obvious first thing to notice here is the concept of an orderid. This is a number that identifies to IB what the order is; at least temporarily and for today only. Only restriction on order id's is that the next order is higher than the last. This means if you submit an order with an id of 999999 you will lose all the orderids below that. You can also reset the id 'clock' to 1 via an option on the Gateway or TWS API configuration menu.  Safest thing to do is ask IB for the next orderid as done here by supplying None to the calling function.

In practice I generate my own orderid's preferring to reserve them first in my own database. This is great so long as you're running a unmarried linear process wherein there may be no risk of an 'older' order being submitted before a 'newer' one.

Notice the limit rate of 0.0 for the market order might not be used. For more information on more funky order types see the docs:

Active order repute- have I offered it?

IB can tell us what orders we are working. Unless you ask very quickly (or submit your order outside of trading hours) this is likely only to return limit orders.

From test4_IB.Py

order_structure=client.Get_open_orders()

    print "Active orders: (ought to simply be limit order)"

    print order_structure

    print ""

From wrapper_v4.Py, class IBclient:

def get_open_orders(self):

        """

        Returns a list of any open orders

        """

        <SNIP>

self.Tws.ReqAllOpenOrders()

        iserror=False

        completed=False

        at the same time as now not finished and no longer iserror:

            finished=self.Cb.Flag_order_structure_finished

            iserror=self.Cb.Flag_iserror

            if (time.time() - start_time) > MAX_WAIT_SECONDS:

                ## You must have idea that IB might teldl you we had finished

                finished=True

            bybypass

        order_structure=self.Cb.Data_order_structure

        if iserror:

            print self.Cb.Error_msg

            print "Problem getting open orders"

        go back order_structure

From wrapper_v4.Py, class IBWrapper:

    def init_openorders(self):

        setattr(self, "data_order_structure", )

        setattr(self, "flag_order_structure_finished", False)

    def add_order_data(self, orderdetails):

        if "data_order_structure" no longer in dir(self):

            orderdata=

        else:

            orderdata=self.Data_order_structure

        orderid=orderdetails['orderid']

        orderdata[orderid]=orderdetails

        setattr(self, "data_order_structure", orderdata)

    def openOrder(self, orderID, contract, order, orderState):

        """

        Tells us about any orders we're running now

        Note those gadgets aren't continual or thrilling so we must extract what we want

        """

        ## Get a choice of exciting matters approximately the order

        orderdetails=dict(symbol=contract.Symbol , expiry=agreement.Expiry,  qty=int(order.totalQuantity) ,

                       facet=order.Motion , orderid=int(orderID), clientid=order.ClientId )

        self.Add_order_data(orderdetails)

    def openOrderEnd(self):

        """

        Finished getting open orders

        """

        setattr(self, "flag_order_structure_finished", True)

In practice I have observed that the perfect quit condition for receiving open orders does not usually trigger so you do need an max ready time (which is right exercise anyway). Here we are just getting a selection of the to be had information about the order (see ). Again we do not simply keep the order object itself as this is just a quantum pointer with the intention to trade.

Fill statistics - how a great deal did it price me?

What happens when an order is filled; completely or partially? Well the following method in the wrapper function is triggered. Notice that the logic is slightly more complicated because this function fulfills two duties. When it's called for a fill then reqId=-1, and action_ib_fill will be called.

From wrapper_v4.Py, class IBWrapper:

def execDetails(self, reqId, settlement, execution):

    def execDetails(self, reqId, settlement, execution):

        """

        This is referred to as if

        a) we've got submitted an order and a fill has come lower back

        b) We have asked for current fills to take delivery of to us

        We populate the filldata item and additionally name action_ib_fill in case we need to do some thing with the

          fill information

        See API docs, C , SocketClient Properties, Contract and Execution for extra details

        """

        reqId=int(reqId)

        execid=execution.ExecId

        exectime=execution.Time

        thisorderid=int(execution.OrderId)

        account=execution.AcctNumber

        alternate=execution.Change

        permid=execution.PermId

        avgprice=execution.Charge

        cumQty=execution.CumQty

        clientid=execution.ClientId

        symbol=contract.Symbol

        expiry=agreement.Expiry

        facet=execution.Aspect

        execdetails=dict(facet=str(facet), instances=str(exectime), orderid=str(thisorderid), qty=int(cumQty), rate=drift(avgprice), image=str(image), expiry=str(expiry), clientid=str(clientid), execid=str(execid), account=str(account), change=str(exchange), permid=int(permid))

        if reqId==FILL_CODE:

            ## This is a fill from a change we have simply accomplished

            action_ib_fill(execdetails)

        else:

            ## This is simply execution records we've got asked for

            self.Add_fill_data(reqId, execdetails)

Again we extract the beneficial statistics from the settlement and execution gadgets in place of saving them directly. More at the IB internet site doctors

A brief technical note; the date is the contract expiry not where relevant first or last notice date. This means you should be wary of using this date to tell you when to roll certain kinds of futures contracts eg US bonds.

From IButils:

def action_ib_fill(execlist):

print "recived fill as follows:"

    print ""

    print execlist

    print ""

Although this is very boring in practice this would be the function that would update your order status database (as a pro at this stuff, naturally you would have such a thing). It won't be obvious from this simple example unless you can submit a very large order in a thin market but the fills come in as cumulative order updates, not separate fills. Its worth looking at an example. Suppose you try and buy 10 lots, and you get fills of:

  • 3 lots @ 100.0
  • 6 lots @ 100.2
  • 1 lot @ 100.5
Then the fills that come in will look like this:

  • qty: 3 lots, price=100.0
  • qty: 9 lots, price=100.13333333
  • qty: 10 lots, price=100.17
So if you do care about each partial fill you are going to have to hope that you see every little fill coming in and use a differencing process to see the detail of each.

By the manner 'orderid' is most effective a brief element for IB; after tommorrow it may not partner it with this order. Instead you have to use 'permid' on your report retaining. 'execid' is extraordinary for each element fill so you ought to use it to ensure you are not which include fill records you already have; in practice this isn't tricky because of the cumulative nature of the records.

Order cancelling - what if I don't need it any more?

Its very easy indeed to cancel an order; we don't even need a call in the client object to do it.

From test4_IB.Py

print "Cancelling the limit order"

    consumer.Tws.CancelOrder(orderid2)

    print "Waiting for cancellation to complete"

    whilst customer.Any_open_orders():

        bybypass

    print "No energetic orders now"

    print purchaser.Any_open_orders()

    print ""

Past execution data - sorry, repeat that, how much?!

It is clearly very important that fill information is correctly captured by your trading software. One reason being to keep track of what your position is; as we shall see in the next post IB doesn't offer mere mortals a super accurate current position facility. So I generally use my own knowledge of trade history to decide where I am, position wise. Because the fills usually arrive in the wrapper function only once its possible under certain conditions to miss them; eg if your API client dies before you see the fill or just isn't running when one arrives on a previously closed market in the middle of the night. Its generally good practice then to reconcile what IB has for a record of fills versus your own.

This information is only to be had up to nighttime of the day you change. So I run a reconciliation three times an afternoon. If you lose a fill from earlier than today you may want to find it at the IB website account management microsite, and manually input it into your database.

Here is how we do it.

From test4_IB.Py

execlist=purchaser.Get_executions()

    print "Following performed seeing that middle of the night this morning:"

    print ""

    print execlist

From wrapper_v4.Py, class IBclient:

def get_executions(self):

        """

        Returns a listing of all executions carried out today

        """

        assert kind(reqId) is int

        if reqId==FILL_CODE:

            improve Exception("Can't call get_executions with a reqId of %d as that is reserved for fills %d" % reqId)

        self.Cb.Init_fill_data()

        self.Cb.Init_error()

        ## We can trade ExecutionFilter to subset unique orders

        self.Tws.ReqExecutions(reqId, ExecutionFilter())

        iserror=False

        completed=False

        start_time=time.Time()

        at the same time as now not finished and no longer iserror:

            finished=self.Cb.Flag_fill_data_finished

            iserror=self.Cb.Flag_iserror

            if (time.time() - start_time) > MAX_WAIT_SECONDS:

                finished=True

            bybypass

        if iserror:

            print self.Cb.Error_msg

            print "Problem getting executions"

        execlist=self.Cb.Data_fill_data[reqId]

        return execlist

We can change ExecutionFilter to subset exceptional orders (

From wrapper_v4.Py, class IBWrapper:

def execDetails(self, reqId, settlement, execution):

        <SNIP - same code as before>

        execdetails=dict(facet=str(facet), instances=str(exectime), orderid=str(thisorderid), qty=int(cumQty), rate=drift(avgprice), image=str(image), expiry=str(expiry), clientid=str(clientid), execid=str(execid), account=str(account), change=str(exchange), permid=int(permid))

        if reqId==FILL_CODE:

            ## This is a fill from a change we have simply accomplished

            action_ib_fill(execdetails)

        else:

            ## This is simply execution records we've got asked for

            self.Add_fill_data(reqId, execdetails)

    def add_fill_data(self, reqId, execdetails):

        if "data_fill_data" not in dir(self):

            filldata=

        else:

            filldata=self.Data_fill_data

        if reqId not in filldata.Keys():

            filldata[reqId]=

        execid=execdetails['orderid']

        filldata[reqId][execid]=execdetails

        setattr(self, "data_fill_data", filldata)

    def execDetailsEnd(self, reqId):

        """

        No extra orders to take a look at if execution details asked

        """

        setattr(self, "flag_fill_data_finished", True)

Its the equal hardworking characteristic as before, best this time the reqId will not be -1 (appearing here as FILL_CODE instead of being hardcoded) so we append the fill this is received to a listing that is lower back to the consumer.

Are we completed?

Yes, as a minimum with this publish. The ultimate thing I will show you how to do is to get accounting statistics, so the tedium is almost over.

This is the fourth in a sequence of 5 posts on constructing a easy interface in python to the IB API using swigiby. The first three posts are:

http://qoppac.Blogspot.Co.United kingdom/2014/03/the use of-swigibpy-so-that-python-will-play.Html

http://qoppac.Blogspot.Co.Uk/2014/04/getting-fees-out-of-ib-api-with.Html

http://qoppac.Blogspot.Co.United kingdom/2014/04/streaming-costs-from-ib-api-swigibpy.Html

The next post is

http://qoppac.Blogspot.Co.Uk/2014/05/getting-accounting-statistics-out-of.Html

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel