AmiBroker Auto-Trading interface for Interactive Brokers 1.0.3 Beta Read Me

February 25, 2005 11:06

THIS IS A BETA VERSION OF THE SOFTWARE. EXPECT BUGS !!!

PLEASE USE ONLY DEMO TWS, NOT REAL ACCOUNT !!!

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.0.3) can be downloaded from:
http://www.amibroker.com/at/at1003beta.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";

}

// 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);



FAQ

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


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

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

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

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

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

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

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

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

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

10) 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
}


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

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