reqOpenOrders() and reqAllOpenOrders() are both one time calls and current open order information is provided through the callback methods.
reqAutoOpenOrders() works a little bit differently. It is a 'continuous' method such that it gets turned 'on' when called with a TRUE parameter. Current open order information will be fed through the callback methods. In addition, any future open orders will also get reported until the method is turned 'off' with a FALSE parameter. I'm not sure how useful this 'continuous' method will be for my application, so I will not pay attention to this method now.
In this example, I have set up two open orders. One is a day order to buy CAT stock and the other is a good-to-cancel options order to sell RUT MARCH 490 call.
The code demonstrating reqAllOpenOrders() is as follows:
require 'java'
require 'TwsApi.jar'
include_class 'ib.client.EClientSocket'
include_class 'ib.client.Contract'
include_class 'ib.client.Order'
include_class 'ib.client.OrderState'
include_class 'ib.client.AnyWrapper'
include_class 'ib.client.EWrapper'
class TestOrderStatus
include EWrapper #note "class TestMktData < EWrapper" syntax is no longer supported in JRuby 1.0
@mySocket
def initialize
puts 'init'
@mySocket = EClientSocket.new(self)
end
def eConnect
@mySocket.eConnect("127.0.0.1", 7496, 0)
end
# To request the open orders that were placed from this client. Each open
# order will be fed back through the openOrder() and orderStatus() functions
# on the EWrapper.
# This is a one time shot call. When its done you DO NOT continue to receive
# information about new placed orders
def reqOpenOrders
@mySocket.reqOpenOrders
end
# Request all open orders that were placed from all API clients linked to one TWS,
# and also from the TWS
# This is a one time shot call. When its done you DO NOT continue to receive
# information about new placed orders
def reqAllOpenOrders
@mySocket.reqAllOpenOrders
end
# Request that newly created TWS orders be implicitly associated with the client
# Bind - If set to TRUE, newly created TWS orders will be implicitly associated
# with the client. If set to FALSE, no association will be made.
#
def reqAutoOpenOrders(bind)
@mySocket.reqAutoOpenOrders(bind)
end
def eDisconnect
@mySocket.eDisconnect
end
def requestStockQuote(id, ticker)
# --------------------------------
myContract = Contract.new
myContract.m_symbol = ticker
myContract.m_secType = 'STK'
myContract.m_exchange = 'SMART'
myContract.m_currency = 'USD'
request_id = id
ticklist = ''
puts '>requestStockQuote - calling reqMktData id='+id.to_s+', ticker='+ticker
@mySocket.reqMktData(request_id, myContract, ticklist, true)
end
def contract_msg(contract)
puts ' contract_msg:'
puts ' conid = ' + contract.m_conId.to_s
puts ' symbol = ' + contract.m_symbol
puts ' secType = ' + contract.m_secType
puts ' expiry = ' + contract.m_expiry.to_s
puts ' strike = ' + contract.m_strike.to_s
puts ' right = ' + contract.m_right
puts ' multiplier = ' + contract.m_multiplier.to_s
puts ' exchange = ' + contract.m_exchange.to_s
puts ' primaryExch = ' + contract.m_primaryExch.to_s
puts ' currency = ' + contract.m_currency
puts ' localSymbol = ' + contract.m_localSymbol
end
def order_msg(order)
puts ' order_msg:'
puts ' order id =' + order.m_orderId.to_s
puts ' client id =' + order.m_clientId.to_s
puts ' action =' + order.m_action.to_s
puts ' quantity =' + order.m_totalQuantity.to_s
puts ' type =' + order.m_orderType.to_s
puts ' lmtPrice =' + order.m_lmtPrice.to_s
puts ' auxPrice =' + order.m_auxPrice.to_s
puts ' TIF =' + order.m_tif.to_s
puts ' parent Id =' + order.m_parentId.to_s
puts ' permId =' + order.m_permId.to_s
puts ' outsideRth =' + order.m_outsideRth.to_s
puts ' hidden =' + order.m_hidden.to_s
puts ' discretionaryAmt=' + order.m_discretionaryAmt.to_s
puts ' triggerMethod=' + order.m_triggerMethod.to_s
puts ' goodAfterTime=' + order.m_goodAfterTime.to_s
puts ' goodTillDate =' + order.m_goodTillDate.to_s
puts ' faGroup =' + order.m_faGroup.to_s
puts ' faMethod =' + order.m_faMethod.to_s
puts ' faPercentage =' + order.m_faPercentage.to_s
puts ' faProfile =' + order.m_faProfile.to_s
puts ' shortSaleSlot=' + order.m_shortSaleSlot.to_s
puts ' designatedLocation=' + order.m_designatedLocation.to_s
puts ' ocaGroup =' + order.m_ocaGroup.to_s
puts ' ocaType =' + order.m_ocaType.to_s
puts ' rule80A =' + order.m_rule80A.to_s
puts ' allOrNone =' + order.m_allOrNone.to_s #yes=1, no=0
puts ' minQty =' + order.m_minQty.to_s
puts ' percentOffset=' + order.m_percentOffset.to_s
puts ' eTradeOnly =' + order.m_eTradeOnly.to_s
puts ' firmQuoteOnly=' + order.m_firmQuoteOnly.to_s
puts ' nbboPriceCap =' + order.m_nbboPriceCap.to_s
puts ' auctionStrategy=' + order.m_auctionStrategy.to_s
puts ' startingPrice=' + order.m_startingPrice.to_s
puts ' stockRefPrice=' + order.m_stockRefPrice.to_s
puts ' delta =' + order.m_delta.to_s
puts ' stockRangeLower=' + order.m_stockRangeLower.to_s
puts ' stockRangeUpper=' + order.m_stockRangeUpper.to_s
puts ' volatility =' + order.m_volatility.to_s
puts ' volatilityType=' + order.m_volatilityType.to_s
puts ' deltaNeutralOrderType=' + order.m_deltaNeutralOrderType.to_s
puts ' deltaNeutralAuxPrice=' + order.m_deltaNeutralAuxPrice.to_s
puts ' continuousUpdate=' + order.m_continuousUpdate.to_s
puts ' referencePriceType=' + order.m_referencePriceType.to_s
puts ' trailStopPrice=' + order.m_trailStopPrice.to_s
puts ' account =' + order.m_account # institutional only
puts ' settlingFirm =' + order.m_settlingFirm.to_s
puts ' clearingAccount=' + order.m_clearingAccount.to_s
puts ' clearingIntent=' + order.m_clearingIntent.to_s
puts ' whatIf =' + order.m_whatIf.to_s
end
def order_state_msg(order_state)
puts ' order_state_msg:'
puts ' status =' + order_state.m_status.to_s
puts ' initMargin =' + order_state.m_initMargin.to_s
puts ' maintMargin =' + order_state.m_maintMargin.to_s
puts ' equityWithLoan=' + order_state.m_equityWithLoan.to_s
puts ' commission =' + order_state.m_commission.to_s
puts ' minCommission =' + order_state.m_minCommission.to_s
puts ' maxCommission =' + order_state.m_maxCommission.to_s
puts ' commissionCurrency=' + order_state.m_commissionCurrency.to_s
puts ' warningText =' + order_state.m_warningText.to_s
end
#///////////////////////////////////////////////////////////////////////
#// Interface methods
#///////////////////////////////////////////////////////////////////////
def tickPrice( ticker_id, field, price, can_auto_execute)
end
def tickSize( ticker_id, field, size)
end
def tickOptionComputation( ticker_id, field, implied_vol,
delta, model_price, pv_dividend)
end
def tickGeneric( ticker_id, tick_type, value)
end
def tickString( ticker_id, tick_type, value)
end
def tickEFP( ticker_id, tick_type, basis_points,
formatted_basis_points, implied_future, hold_days,
future_expiry, dividend_impact, dividends_to_expiry)
end
def orderStatus( order_id, status, filled, remaining,
avg_fill_price, perm_id, parent_id, last_fill_price,
client_id, why_held)
puts 'orderStatus>: orderId=' + order_id.to_s + ', clientId=' + client_id.to_s + ', permId=' + perm_id.to_s +
', status=' + status + ' filled=' + filled.to_s + ', remaining=' + remaining.to_s + ', '
puts ' avgFillPrice=' + avg_fill_price.to_s + ', lastFillPrice=' + last_fill_price.to_s +
', parent Id=' + parent_id.to_s + ', whyHeld=' + why_held.to_s
end
def openOrder( order_id, contract, order, order_state)
puts 'openOrder> open order: orderId=' + order_id.to_s + ' --- '
contract_msg(contract)
order_msg(order)
order_state_msg(order_state)
end
def updateAccountValue( key, value, currency, account_name)
end
def updatePortfolio( contract, position, market_price, market_value,
average_cost, unrealized_pnl, realized_pnl, account_name)
end
def updateAccountTime( time_stamp)
end
def nextValidId( order_id)
end
def contractDetails( req_id, contract_details)
end
def bondContractDetails( req_id, contract_details)
end
def contractDetailsEnd( req_id)
end
def execDetails( order_id, contract, execution)
end
def updateMktDepth( ticker_id, position, operation, side, price, size)
end
def updateMktDepthL2( ticker_id, position, market_maker, operation,
side, price, size)
end
def updateNewsBulletin( msg_id, msgType, message, orig_exchange)
end
def managedAccounts( accounts_list)
end
def receiveFA( fa_data_type, xml)
end
def historicalData( req_id, date, open, high, low,
close, volume, count, eWAP, has_gaps)
end
def scannerParameters( xml)
end
def scannerData( req_id, rank, contract_details, distance,
benchmark, projection, legs_str)
end
def scannerDataEnd( req_id)
end
def realtimeBar( req_id, time, open, high, low, close, volume, wap, count)
end
def currentTime( time)
end
def fundamentalData( req_id, data)
end
# ---------------------------------------------------
# -- methods from AnyWrapper -- must be declared
# ---------------------------------------------------
def connectionClosed()
puts ' [API.connectionClosed] Closed connection with TWS'
end
def error(err_obj_str)
puts ' [API.msg1] ' + err_obj_str if err_obj_str.is_a?(String)
puts ' [API.msg3] ' + err_obj_str.getMessage() if err_obj_str.is_a?(Exception)
end
def error(one, two, str)
puts ' [API.msg2] ' + str + ' {' + one.to_s + ', ' + two.to_s + '}'
end
end # class TestOrderStatus
#*********************************************************************************************
# Running the code
# *********************************************************************************************
x = TestOrderStatus.new()
begin
x.eConnect
puts 'connected ...'
x.reqAllOpenOrders # requesting open orders information
x.requestStockQuote(-99, 'DONE_OPEN_ORDERS') # call to reqMktData() for invalid quote.
# Will generate error AFTER all
# open orders info are returned
sleep(5)
x.eDisconnect
puts 'disconnected'
rescue Exception => e
puts 'Exception>>' + e.message
x.eDisconnect
end
Examining the code shows the program structure to be consistent with my previous examples of TWS API. Information is requested and it is delivered asynchronously via callback methods. However, a major drawback to this model is that there is no event or indicator that the information being delivered is finished. This is where a workaround is needed. One way to do this is to immediately issue a reqMktData() with an invalid ticker symbol to intentionally cause an error. This error will be fed through error() callback method after the open order request is finished.
Line 287 demonstrates this workaround. It's not very elegant and I will have to keep this in mind when designing the application.
Running the code produces the following output:
init
Server Version:43
TWS Time at connection:20090301 16:07:19 EST
connected ...
>requestStockQuote - calling reqMktData id=-99, ticker=DONE_OPEN_ORDERS
openOrder> open order: orderId=2 ---
contract_msg:
conid = 54528396
symbol = RUT
secType = OPT
expiry = 20090319
strike = 490.0
right = C
multiplier =
exchange = SMART
primaryExch =
currency = USD
localSymbol = RUWCA
order_msg:
order id =2
client id =0
action =SELL
quantity =1
type =LMT
lmtPrice =2.0
auxPrice =0.0
TIF =GTC
parent Id =0
permId =1664800509
outsideRth =false
hidden =false
discretionaryAmt=0.0
triggerMethod=0
goodAfterTime=
goodTillDate =
faGroup =
faMethod =
faPercentage =
faProfile =
shortSaleSlot=0
designatedLocation=
ocaGroup =
ocaType =3
rule80A =
allOrNone =false
minQty =0
percentOffset=0.0
eTradeOnly =false
firmQuoteOnly=false
nbboPriceCap =0.0
auctionStrategy=0
startingPrice=0.0
stockRefPrice=0.0
delta =0.0
stockRangeLower=0.0
stockRangeUpper=0.0
volatility =0.0
volatilityType=0
deltaNeutralOrderType=None
deltaNeutralAuxPrice=0.0
continuousUpdate=0
referencePriceType=0
trailStopPrice=0.0
account =DU58265
settlingFirm =DEMO
clearingAccount=
clearingIntent=IB
whatIf =false
order_state_msg:
status =PendingSubmit
initMargin =
maintMargin =
equityWithLoan=
commission =1.7976931348623157e+308
minCommission =1.7976931348623157e+308
maxCommission =1.7976931348623157e+308
commissionCurrency=USD
warningText =
orderStatus>: orderId=2, clientId=0, permId=1664800509, status=PendingSubmit filled=0, remaining=1,
avgFillPrice=0.0, lastFillPrice=0.0, parent Id=0, whyHeld=
openOrder> open order: orderId=1 ---
contract_msg:
conid = 5437
symbol = CAT
secType = STK
expiry =
strike = 0.0
right = ?
multiplier =
exchange = SMART
primaryExch =
currency = USD
localSymbol = CAT
order_msg:
order id =1
client id =0
action =BUY
quantity =100
type =LMT
lmtPrice =20.0
auxPrice =0.0
TIF =DAY
parent Id =0
permId =1664800505
outsideRth =false
hidden =false
discretionaryAmt=0.0
triggerMethod=0
goodAfterTime=
goodTillDate =
faGroup =
faMethod =
faPercentage =
faProfile =
shortSaleSlot=0
designatedLocation=
ocaGroup =
ocaType =3
rule80A =
allOrNone =false
minQty =0
percentOffset=0.0
eTradeOnly =false
firmQuoteOnly=false
nbboPriceCap =0.0
auctionStrategy=0
startingPrice=0.0
stockRefPrice=0.0
delta =0.0
stockRangeLower=0.0
stockRangeUpper=0.0
volatility =0.0
volatilityType=0
deltaNeutralOrderType=None
deltaNeutralAuxPrice=0.0
continuousUpdate=0
referencePriceType=0
trailStopPrice=0.0
account =DU58265
settlingFirm =DEMO
clearingAccount=
clearingIntent=IB
whatIf =false
order_state_msg:
status =PreSubmitted
initMargin =
maintMargin =
equityWithLoan=
commission =1.7976931348623157e+308
minCommission =1.7976931348623157e+308
maxCommission =1.7976931348623157e+308
commissionCurrency=USD
warningText =
orderStatus>: orderId=1, clientId=0, permId=1664800505, status=PreSubmitted filled=0, remaining=100,
avgFillPrice=0.0, lastFillPrice=0.0, parent Id=0, whyHeld=
[API.msg2] Market data farm connection is OK:usopt {-1, 2104}
[API.msg2] Market data farm connection is OK:usfarm {-1, 2104}
openOrder> open order: orderId=2 ---
contract_msg:
conid = 54528396
symbol = RUT
secType = OPT
expiry = 20090319
strike = 490.0
right = C
multiplier =
exchange = SMART
primaryExch =
currency = USD
localSymbol = RUWCA
order_msg:
order id =2
client id =0
action =SELL
quantity =1
type =LMT
lmtPrice =2.0
auxPrice =0.0
TIF =GTC
parent Id =0
permId =1664800509
outsideRth =false
hidden =false
discretionaryAmt=0.0
triggerMethod=0
goodAfterTime=
goodTillDate =
faGroup =
faMethod =
faPercentage =
faProfile =
shortSaleSlot=0
designatedLocation=
ocaGroup =
ocaType =3
rule80A =
allOrNone =false
minQty =0
percentOffset=0.0
eTradeOnly =false
firmQuoteOnly=false
nbboPriceCap =0.0
auctionStrategy=0
startingPrice=0.0
stockRefPrice=0.0
delta =0.0
stockRangeLower=0.0
stockRangeUpper=0.0
volatility =0.0
volatilityType=0
deltaNeutralOrderType=None
deltaNeutralAuxPrice=0.0
continuousUpdate=0
referencePriceType=0
trailStopPrice=0.0
account =DU58265
settlingFirm =DEMO
clearingAccount=
clearingIntent=IB
whatIf =false
order_state_msg:
status =PendingSubmit
initMargin =
maintMargin =
equityWithLoan=
commission =1.7976931348623157e+308
minCommission =1.7976931348623157e+308
maxCommission =1.7976931348623157e+308
commissionCurrency=USD
warningText =
orderStatus>: orderId=2, clientId=0, permId=1664800509, status=PendingSubmit filled=0, remaining=1,
avgFillPrice=0.0, lastFillPrice=0.0, parent Id=0, whyHeld=
openOrder> open order: orderId=1 ---
contract_msg:
conid = 5437
symbol = CAT
secType = STK
expiry =
strike = 0.0
right = ?
multiplier =
exchange = SMART
primaryExch =
currency = USD
localSymbol = CAT
order_msg:
order id =1
client id =0
action =BUY
quantity =100
type =LMT
lmtPrice =20.0
auxPrice =0.0
TIF =DAY
parent Id =0
permId =1664800505
outsideRth =false
hidden =false
discretionaryAmt=0.0
triggerMethod=0
goodAfterTime=
goodTillDate =
faGroup =
faMethod =
faPercentage =
faProfile =
shortSaleSlot=0
designatedLocation=
ocaGroup =
ocaType =3
rule80A =
allOrNone =false
minQty =0
percentOffset=0.0
eTradeOnly =false
firmQuoteOnly=false
nbboPriceCap =0.0
auctionStrategy=0
startingPrice=0.0
stockRefPrice=0.0
delta =0.0
stockRangeLower=0.0
stockRangeUpper=0.0
volatility =0.0
volatilityType=0
deltaNeutralOrderType=None
deltaNeutralAuxPrice=0.0
continuousUpdate=0
referencePriceType=0
trailStopPrice=0.0
account =DU58265
settlingFirm =DEMO
clearingAccount=
clearingIntent=IB
whatIf =false
order_state_msg:
status =PreSubmitted
initMargin =
maintMargin =
equityWithLoan=
commission =1.7976931348623157e+308
minCommission =1.7976931348623157e+308
maxCommission =1.7976931348623157e+308
commissionCurrency=USD
warningText =
orderStatus>: orderId=1, clientId=0, permId=1664800505, status=PreSubmitted filled=0, remaining=100,
avgFillPrice=0.0, lastFillPrice=0.0, parent Id=0, whyHeld=
[API.msg2] No security definition has been found for the request {-99, 200}
disconnected
Note that even though I currently have two open orders (RUT call option and CAT), callback methods get triggered twice for each order. I'm not sure why this happens, but fortunately, orderId is unique so I can use it to tell if an order is an original or duplicate.
After experimenting some more, I found out that when a connection is made to TWS, a call to reqAllOpenOrders() is automatically issued. Since my code example explicitly calls reqAllOpenOrders(), two sets of information get printed. Changing the code to the following proves my point:
# *********************************************************************************************
# Running the code
# *********************************************************************************************
x = TestOrderStatus.new()
begin
x.eConnect
puts 'connected ...'
sleep(5)
x.eDisconnect
puts 'disconnected'
rescue Exception => e
puts 'Exception>>' + e.message
x.eDisconnect
end
init
Server Version:43
TWS Time at connection:20090301 17:11:38 EST
connected ...
openOrder> open order: orderId=2 ---
contract_msg:
conid = 54528396
symbol = RUT
secType = OPT
expiry = 20090319
strike = 490.0
right = C
multiplier =
exchange = SMART
primaryExch =
currency = USD
localSymbol = RUWCA
order_msg:
order id =2
client id =0
action =SELL
quantity =1
type =LMT
lmtPrice =2.0
auxPrice =0.0
TIF =GTC
parent Id =0
permId =1664800509
outsideRth =false
hidden =false
discretionaryAmt=0.0
triggerMethod=0
goodAfterTime=
goodTillDate =
faGroup =
faMethod =
faPercentage =
faProfile =
shortSaleSlot=0
designatedLocation=
ocaGroup =
ocaType =3
rule80A =
allOrNone =false
minQty =0
percentOffset=0.0
eTradeOnly =false
firmQuoteOnly=false
nbboPriceCap =0.0
auctionStrategy=0
startingPrice=0.0
stockRefPrice=0.0
delta =0.0
stockRangeLower=0.0
stockRangeUpper=0.0
volatility =0.0
volatilityType=0
deltaNeutralOrderType=None
deltaNeutralAuxPrice=0.0
continuousUpdate=0
referencePriceType=0
trailStopPrice=0.0
account =DU58265
settlingFirm =DEMO
clearingAccount=
clearingIntent=IB
whatIf =false
order_state_msg:
status =PendingSubmit
initMargin =
maintMargin =
equityWithLoan=
commission =1.7976931348623157e+308
minCommission =1.7976931348623157e+308
maxCommission =1.7976931348623157e+308
commissionCurrency=USD
warningText =
orderStatus>: orderId=2, clientId=0, permId=1664800509, status=PendingSubmit filled=0, remaining=1,
avgFillPrice=0.0, lastFillPrice=0.0, parent Id=0, whyHeld=
openOrder> open order: orderId=1 ---
contract_msg:
conid = 5437
symbol = CAT
secType = STK
expiry =
strike = 0.0
right = ?
multiplier =
exchange = SMART
primaryExch =
currency = USD
localSymbol = CAT
order_msg:
order id =1
client id =0
action =BUY
quantity =100
type =LMT
lmtPrice =20.0
auxPrice =0.0
TIF =DAY
parent Id =0
permId =1664800505
outsideRth =false
hidden =false
discretionaryAmt=0.0
triggerMethod=0
goodAfterTime=
goodTillDate =
faGroup =
faMethod =
faPercentage =
faProfile =
shortSaleSlot=0
designatedLocation=
ocaGroup =
ocaType =3
rule80A =
allOrNone =false
minQty =0
percentOffset=0.0
eTradeOnly =false
firmQuoteOnly=false
nbboPriceCap =0.0
auctionStrategy=0
startingPrice=0.0
stockRefPrice=0.0
delta =0.0
stockRangeLower=0.0
stockRangeUpper=0.0
volatility =0.0
volatilityType=0
deltaNeutralOrderType=None
deltaNeutralAuxPrice=0.0
continuousUpdate=0
referencePriceType=0
trailStopPrice=0.0
account =DU58265
settlingFirm =DEMO
clearingAccount=
clearingIntent=IB
whatIf =false
order_state_msg:
status =PreSubmitted
initMargin =
maintMargin =
equityWithLoan=
commission =1.7976931348623157e+308
minCommission =1.7976931348623157e+308
maxCommission =1.7976931348623157e+308
commissionCurrency=USD
warningText =
orderStatus>: orderId=1, clientId=0, permId=1664800505, status=PreSubmitted filled=0, remaining=100,
avgFillPrice=0.0, lastFillPrice=0.0, parent Id=0, whyHeld=
[API.msg2] Market data farm connection is OK:usopt {-1, 2104}
[API.msg2] Market data farm connection is OK:usfarm {-1, 2104}
disconnected
03/09/09 Update
Upgrading to API v. 9.60 requires addition of these new callback methods.
# ---------------------------------------------------
# new callback methods added in API 9.60
# ---------------------------------------------------
def openOrderEnd() # invoked when all orders are sent to a client as a response to reqOpenOrders() and right after connected to TWS
puts 'openOrderEnd()'
end
def accountDownloadEnd(account_name) #invoked when a complete snapshot of an account state is sent to a client as a response to reqAccountUpdates()
end
def execDetailsEnd( req_id) # invoked when all executions are sent to a client as a response to reqExecutions()
end
def deltaNeutralValidation(req_id, under_comp) # for Delta-Neutral DN RFQ
end
Running the code produces the same result except openOrderEnd() method is called back.
...
openOrderEnd()
disconnected
2 comments:
Hi,
Interesting blog post.
Any reason you didn't use the ib-ruby library?
I think there is now (just added) 'end-of-...' call back method for data such as orders, and others - haven't used it but seems it's worth updating the API version you use.
HTH
I did look at ib-ruby, but I felt it was better for me to stay with TWS Java API since it has a larger user base.
And yes, I just looked at IB site yesterday and noticed the endxxx callback methods on new v. 5.60. I've made the decision to upgrade to this version and will post new entry shortly.
Thanks!
Post a Comment