AmiBroker Auto-Trading interface for Interactive Brokers 1.3.8 Read Me

May 29, 2014 21:03

June 3, 2013: The auto-trading interface is now open-source. For the details see: http://www.amibroker.com/devlog/2013/06/03/ibcontroller-1-3-8-source-codes-released/

AUTOMATIC TRADING BRINGS CERTAIN RISKS !
PLEASE TEST CAREFULLY YOUR CODE USING FIRST DEMO TWS AND THEN PAPER TRADING ACCOUNT !

AUTOMATIC TRADING INTEFACE IS INTENDED TO MAKE TRADING EASIER AND FASTER BUT IT IS NOT INTENDED TO BE RUN WITHOUT SUPERVISION.

DON'T LEAVE AUTOMATIC TRADING UNATTENDED AS CERTAIN CIRCUMSTANCES MAY OCCUR LIKE INTERNET FAILURE, POWER FAILURE, OTHER UNEXPECTED SITUATION THAT MAY LEAD TO SERIOUS FINANCIAL LOSS.

INSTALLATION INSTRUCTIONS

Just run the installer and follow the instructions.

See CHANGE LOG below for detailed list of changes.

REQUIREMENTS

DOWNLOAD

The most recent version of IBController (1.3.8) can be downloaded from:
http://www.amibroker.com/at/at1380beta.exe

USAGE INSTRUCTIONS

Introduction

The IB Controller (BrokerIB.EXE) is a separate application that acts as a buffer between AmiBroker and Interactive Brokers TWS. It accepts commands from AmiBroker and send orders to / retrieves information from TWS. It also allows to cancel/transmit orders manually. The IB controller application is run automatically by AmiBroker if the formula contains the following call:

ibc = GetTradingInterface("IB");

After this call the BrokerIB.EXE (IB Controller) application is launched and the ibc variable contains the pointer to OLE automation object that has several methods (functions) that allow to place/modify/cancel orders via TWS and to query portfolio information. Those methods (functions) are called as any automation object methods, for example:

ibc = GetTradingInterface("IB");

if( ibc.IsConnected() ) // check if connection to IB was successfull
{
   ibc.PlaceOrder("MSFT", "BUY", 100, "MKT", 0, 0, "DAY", False ); // place order but do not transmit yet
}

Note that this is low-level interface for advanced users that is made available in so called phase-one of implementing automated trading via IB. There will be higher-level interface that will be implemented later.

IB Controller Methods (Functions):

Examples:

1. Placing and transmitting Market Buy Order for 100 shares when MACD crosses above Signal line:

Buy = Cross( MACD(), Signal() );

if( LastValue( Buy ) )
{
  ibc =
GetTradingInterface("IB");

  
// check if we are connected OK
  
if( ibc.IsConnected() )
  {
    
// check if we do not have already open position on this stock
     
if( ibc.GetPositionSize( Name() ) == 0 )
     {
        
// transmit order
        ibc.PlaceOrder(
Name(), "Buy", 100, "MKT", 0, 0, "Day", True );
     }
  }
}

2. Placing/modifying a limit order on current price plus $0.10 but without transmitting it (manual transmit required).

This code can be run many times and it will modify existing order as long as it is not transmitted. It uses static variables to store orderId from last run.


Buy = L > Ref( H, -1 ); // buy when prices gap up

if( LastValue( Buy ) )
{
   ibc =
GetTradingInterface("IB");

  
// check if we are connected OK
   
if( ibc.IsConnected() )
    {
      
// place orders only if we do not have already open position on this symbol
      
if( ibc.GetPositionSize( Name() ) == 0 )
       {
        
// retrieve orderID from previous run, will be empty if no order was placed before  
          OrderID =
StaticVarGetText("OrderID"+Name());
      
          
// place or modify the order - don't transmit yet
          OrderID = ibc.ModifyOrder( OrderID,
Name(), "BUY", 100,
                                 
"LMT", LastValue( C ) + 0.10, 0, "Day", False );

         
// store orderID for next run so we know which order to modify
         
StaticVarSetText("OrderID"+Name(), OrderID);
       }
    }
}

3. Placing/modifying manually from Parameters dialog. Code to be applied in Indicator Builder. (Modified to use new features in 1.0.2)

This code can be run many times and it will modify existing order as long as it is not transmitted. It uses static variables to store orderId from last run.

// Param block
TriggerOrder=
ParamTrigger("Place order","Click here to place order");
Mode=
ParamToggle("Mode","Modify existing|Always place new order");
ACT =
ParamList("Action", "BUY|SELL|SSHORT");
OT =
ParamList("Order Type", "MKT|LMT|STP");
TIF =
ParamList("Time In Force", "DAY|GTC|IOC");
Ticker =
ParamStr("Ticker",Name());
NumShares =
Param("Number of Shares",10,10,100,10);
LimitPrice =
LastValue(C) + Param("Limit Price offset",0,-0.1,0.1,0.01);
StopPrice =
LastValue(C) + Param("Stop price offset",0,-0.1,0.1,0.01);
Transmit =
ParamToggle("Transmit","Do NOT transmit|Transmit",0);
TriggerCancel =
ParamTrigger("Cancel Order","Click here to Cancel order");

Msg =
""; // this variable stores error message text

// create instance of trading interface
ibc =
GetTradingInterface("IB");

// retrieve orderID from previous run, will be empty if no order was placed before
OrderID =
StaticVarGetText("OrderID"+Ticker);

if( TriggerOrder )
{
// check if we are connected OK
if( ibc.IsConnected() )
{
  
if( Mode == 1 ) OrderID = ""; // if mode set to 'always new' then clear orderid

  
// place orders only if we do not have already open position on this symbol
  
// place or modify the order - don't transmit yet
   OrderID = ibc.ModifyOrder( OrderID, Ticker,
         ACT, NumShares, OT, LimitPrice, StopPrice, TIF, Transmit);
  

  
// store orderID for next run so we know which order to modify

  
StaticVarSetText("OrderID"+Ticker, OrderID);
  
  
if( Mode == 1 )
       Msg =
"New order has been placed with ID = ";
  
else
       Msg =
"Order placed/modified with ID = ";

   Msg = Msg + OrderID +
" on " + Now();
}
else
{
   Msg =
"Placing order failed because of no connection to TWS";
}
}

if( TriggerCancel )
{
  
if( OrderId != "" )
   {
    
if( ibc.CancelOrder( OrderId ) )
       Msg =
"Request to cancel order " + OrderID + " sent successfully";
    
else
       Msg =
"Request to cancel order " + OrderID + " failed.";
   }
  
else
     Msg =
"Can not cancel order becase OrderID is empty";

}

execlist = ibc.GetExecList(
0,""); // all

execinfo =
"";
for( i = 0; ( OId = StrExtract( execlist, i ) ) != ""; i++ )
{
   execinfo = execinfo + OID +
" Symbol: " + ibc.GetExecInfo( OID, "Symbol" ) +
            
" Filled: " + ibc.GetExecInfo( OID, "Filled" ) +
            
" Avg. price: " + ibc.GetExecInfo( OID, "Avg. price" ) + "\n";

}



// monitoring code
Title =
Msg +
"\nLast TWS message: "+ ibc.GetLastError(0) +
"\nAvailable funds: " + ibc.GetAccountValue("AvailableFunds")+
"  Gross Pos. Value: " + ibc.GetAccountValue("GrossPositionValue")+
"\nOrderID = "+OrderId+
"\nTicker = "+Ticker+
"\nAction = "+ACT+
"\nShares = "+NumToStr(NumShares,1.0)+
"\nOrderType = "+OT+
"\nLimitPrice = "+NumToStr(LimitPrice,1.3)+
"\nStopPrice = "+NumToStr(StopPrice,1.3)+
"\nTimeInForce= "+TIF+
"\nTransmit = "+NumToStr(Transmit,1.0)+"\n"+
"\nGetStatus = "+ibc.GetStatus( OrderID )+
"\nGetPositionSize = "+ibc.GetPositionSize( Ticker )+
"\nIsConnected = "+NumToStr(ibc.IsConnected(),1.0) +
"\nExecInfo\n" + execinfo;


4. Placing bracket order

// create instance of trading interface
ibc =
GetTradingInterface("IB");
parentID = ibc.PlaceOrder("MSFT", "BUY", 1000, "LMT", 27, 0, "GTC", False );
ibc.PlaceOrder(
"MSFT", "SELL", 1000, "LMT", 28, 0, "GTC", False, 100, "", parentID );
ibc.PlaceOrder(
"MSFT", "SELL", 1000, "STP", 26, 26, "GTC", True, 100, "", parentID );

Note that TRANSMIT flag is set to FALSE on all bracket orders except the last one. This ensures that orders wait until bracket order set is completed. Setting Transmit flag to TRUE on the very last one transmits entire bracket.

5. Iterating through open positions:

ibc = GetTradingInterface("IB");

openpos = ibc.GetPositionList();

for( i = 0; ( symbol = StrExtract( openpos, i ) ) != ""; i++ )
{
  
printf("Position " + i + "\tSymbol: " + symbol + "\tSize: " + ibc.GetPositionSize( symbol ) + "\n" );
}

6. Placing OCA group orders:

ibc.PlaceOrder("MSFT", "SELL", 1000, "LMT", 28, 0, "GTC", True, 100, "", 0, "MYGROUP" );
ibc.PlaceOrder(
"MSFT", "SELL", 1000, "STP", 26, 26, "GTC", True, 100, "", 0, "MYGROUP" );

FAQ

1) Why IBController has BETA status?

The reason is simple - because it relies on IB API we have no control upon. You need to be aware of the fact that Interactive Brokers may and actually do change TWS and API quite often and any future changes in the API/TWS may produce incompatiblities without any warning. We try to adjust IBController as soon as such incompatibilities surface, but we can only do that "after the fact". Due to this there can be periods when IBController does not work properly with certain version(s) of TWS. That is the only reason why IBController is marked as BETA.

2) What exactly is the OrderID, where is the number stored? How does it increment? Can we assign our own OrderIDs?

OrderID is a string that represents the unique order number that is assigned by IB Controller (for orders placed via IB Controller) or TWS (for orders placed in TWS) when you place the order. It is automatically incremented on each NEW order. The implementation takes care that generated ID is unique for given session of TWS. You should NOT assign your own IDs because you may risk generating duplicates that will be rejected by TWS.


3) The IB Interface contains a lot of useful information, can we access this information in afl?

GetAccountValue() function (introduced in 1.0.2) allows that.

4) IMPORTANT. During development i often "lose" my connection to the TWS and cannot get it going again. Under what conditions can/does this happen?

This is probably caused by placing ModifyOrder calls too often so TWS is not able handle them and sends error messages ("Unable to modify this order as its still being processed") and it results in IsConnected() returning false. This should be addressed by next version. If such thing happens you can simply close IB Controller window.

5) Is it possible to read IB Last/Bif/Ask prices while running a eSignal database?

Right now there is no access to price data via IBController but maybe in the future

6) Why do we have a PlaceOrder() and a ModifyOrder(), if ModifyOrder can be used in both cases?

Just for completeness. Indeed ModifyOrder alone would be enough.

7) Can we retrieve the "Executions" and "Pending" page (string) from the IB Controller window, for display on the chart?

Pending - yes you can retrieve the status of the order while it is on "Pending" page using GetStatus. As for "execution" tab - as it is already described in the read me this is in the works.

8) It appears the startup sequence of TWS and AB is significant, is it?

Not actually TWS and AB - they are independent. But what is important to run TWS before running IB Controller. If you however have your trading code in indicator then it may be auto-refreshed at AB start and in this individual case you would need to run TWS before AB. Anyway if something fails you can simply close IB controller window and it will re-open automatically and reconnect on next call to GetTradingInterface.

9) When the TWS/AB connection is broken during trading, what is the best way to restore it?

Close IB Controller manually. It will re-open automatically and reconnect on next call to GetTradingInterface.

10) What is the consequence of repeated PlaceOrder() or ModifyOrder() execution due to AB Refresh? What happens when, instead of using Cross() with use ">" or "<"?

Franly auto-trading interface is NOT indented to be used in indicators. It is intended to be used in AA window. But if you prefer to run it in IB you can do this too, but then you should check pending orders and check portfolio position size for given symbol not to buy too many shares. To answer your question: multiple PlaceOrder calls will result in multiple orders placed. Multiple ModifyOrder() calls may result in the same (if OrderID is empty) or may just result in updating the values of already exisiting, pending order if you specify correct OrderID of order placed before (see the example 2.)

11) A "clear" Message button would be nice in the IBc window, i have to scroll down continuously to see the latest message (perhaps last-on-top scrolling?)

It is already available in version 1.0.2

12) What is the best way to write a single-(user initiated)-execution line of code? ... this is where the ParamTask() i suggested earlier would come in handy.

Use new AFL ParamTrigger function

ParamTrigger( "Name", "Button text")
- to be used in indicator builder - to create triggers (buttons).

If you place ParamTrigger in the indicator code it will create a "button" in Parameter dialog that can be pressed.
Normally ParamTrigger will return zero (0) but when button in the param window is pressed then it will refresh the chart and ParamTrigger will return 1 (one) for this single execution (further refreshes will return zero, until the button is pressed again)

Example:

trigger = ParamTrigger("Place Order", "Click here to place order");

if( trigger )
{
// your one-shot code here
}


13) When placing orders from an indicator (the thing to do in RT trading) and editing the code will result in additional afl executions, how can i prevent randon order placement from the extra passes? Parameters and Signals may not be the same as a result of using loops, DLLs, and things.

Use static variables as given in example 2 to MODIFY existing order instead of placing many new orders. Or use code given in response to question 10

14) I got an warning from TWS that is treated as error in Pending list. How can I solve that?

You can put specific TWS code onto "Ignore list" (use File->Error code ignore list to enter codes in comma separated list). Any code entered here will be ignored by Pending List page, but still will be displayed in the messages window.

15) some message in the IBc are not clear/precise in their meaning ...

Well these messages come from TWS and I have no influence on their wording :-)

CHANGE LOG

CHANGES FOR VERSION 1.3.8

CHANGES FOR VERSION 1.3.7

CHANGES FOR VERSION 1.3.6

CHANGES FOR VERSION 1.3.5

CHANGES FOR VERSION 1.3.2

CHANGES FOR VERSION 1.3.1

CHANGES FOR VERSION 1.3.0


CHANGES FOR VERSION 1.2.1

CHANGES FOR VERSION 1.2.0

CHANGES FOR VERSION 1.1.1

CHANGES FOR VERSION 1.1.0



CHANGES FOR VERSION 1.0.8


CHANGES FOR VERSION 1.0.7

CHANGES FOR VERSION 1.0.6

CHANGES FOR VERSION 1.0.5

CHANGES FOR VERSION 1.0.4

CHANGES FOR VERSION 1.0.3

CHANGES FOR VERSION 1.0.2

CHANGES FOR VERSION 1.0.1

CHANGES FOR VERSION 1.0.0

HOW TO REPORT BUGS

If you experience any problem with this beta version please send detailed description of the problem (especially the steps needed to reproduce it) to bugs at amibroker.com