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