The following code example submits a limit order to purchase an IWM SEP 38 CALL option and a market order to sell an existing RUT MAY 400 CALL option. When the code has finished running, the IWM option should be in submitted status and the RUT option should be in filled status.
require 'java'
require 'TwsApi.jar'
include_class 'ib.client.EClientSocket'
include_class 'ib.client.Contract'
include_class 'ib.client.Order'
include_class 'ib.client.AnyWrapper'
include_class 'ib.client.EWrapper'
class TestOptionsOrder
include EWrapper #note "class TestMktData < EWrapper" syntax is no longer supported in JRuby 1.0
attr_accessor :order_id
@mySocket
def initialize
puts 'init'
@mySocket = EClientSocket.new(self)
end
def eConnect
@mySocket.eConnect("127.0.0.1", 7496, 0)
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
def submitOptionsOrder(order_id, symbol, call_put, expiry, strike,
buy_sell, qty, order_type, limit_price, tif)
# --------------------------------
myContract = Contract.new
myContract.m_symbol = symbol
myContract.m_secType = 'OPT'
myContract.m_exchange = 'SMART'
myContract.m_currency = 'USD'
# options specific below ---
myContract.m_expiry = expiry # string format YYYYMM
myContract.m_right = call_put # CALL, PUT
myContract.m_strike = strike # number
myOrder = Order.new
myOrder.m_action = buy_sell # BUY, SELL
myOrder.m_totalQuantity = qty
myOrder.m_orderType = order_type # MKT, LMT, STP, SPLMT, TRAIL, etc
myOrder.m_lmtPrice = limit_price
myOrder.m_tif = tif # DAY, GTC
@mySocket.placeOrder(order_id, myContract, myOrder)
end
def cancelOrder(order_id)
@mySocket.cancelOrder(order_id)
end
# contract details will be received via the contractDetails() function on the EWrapper
def reqContractDetails (req_id, contract)
@mySocket.reqContractDetails(req_id, contract)
end
def eDisconnect
@mySocket.eDisconnect
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 ' exchange = ' + contract.m_exchange.to_s
puts ' currency = ' + contract.m_currency
puts ' localSymbol = ' + contract.m_localSymbol.to_s
puts ' multiplier = ' + contract.m_multiplier.to_s
puts ' expiry = ' + contract.m_expiry.to_s
puts ' strike = ' + contract.m_strike.to_s
puts ' right = ' + contract.m_right.to_s
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 ' TIF =' + order.m_tif.to_s
puts ' parent Id =' + order.m_parentId.to_s
puts ' permId =' + order.m_permId.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 ' commission =' + order_state.m_commission.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 '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
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 '--------------------------------------------------------'
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
# triggered right after logging into TWS
def nextValidId( order_id)
@order_id = order_id #storing order id to be used when placing order
puts 'nextValidId> Next Valid Order Id = ' + @order_id.to_s
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
# ---------------------------------------------------
# new callback methods added in API 9.60
# ---------------------------------------------------
def openOrderEnd() # invoked when all orders are sent to a client as a response to reqOpenOrders(),
# reqAllOpenOrders and right after connected to TWS
puts 'openOrderEnd> Ended ------------------------'
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
# ---------------------------------------------------
# -- 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
# *********************************************************************************************
# Running the code
# *********************************************************************************************
x = TestOptionsOrder.new()
begin
x.eConnect
puts 'connected ...'
sleep(2) # need this here to give time for nextValidId() to be called
puts '*****************************'
puts '**** LIMIT ORDER ****'
o1 = x.order_id
x.submitOptionsOrder(o1, 'IWM', 'CALL', '200909', 38,
'BUY', 2, 'LMT', 5, 'DAY')
sleep(5)
puts '*** requesting open orders ***'
x.reqAllOpenOrders
sleep(5)
puts '*****************************'
puts '**** MARKET ORDER - STC EXISTING POSITION ****'
o2 = x.order_id += 1
x.submitOptionsOrder(o2, 'RUT', 'CALL', '200904', 400,
'SELL', 1, 'MKT', 0, 'DAY')
sleep(5)
puts '*** requesting open orders ***'
x.reqAllOpenOrders
sleep(5)
x.eDisconnect
puts 'disconnected'
rescue Exception => e
puts 'Exception ' + e.message
x.eDisconnect
end
Running the code produces the following output:
init
Server Version:43
TWS Time at connection:20090317 15:26:34 EST
connected ...
nextValidId> Next Valid Order Id = 69
openOrderEnd> Ended ------------------------
[API.msg2] Market data farm connection is OK:usopt {-1, 2104}
[API.msg2] Market data farm connection is OK:usfarm {-1, 2104}
*****************************
**** LIMIT ORDER ****
--------------------------------------------------------
openOrder> open order: orderId=69 ---
contract_msg:
conid = 56413283
symbol = IWM
secType = OPT
exchange = SMART
currency = USD
localSymbol = IQXIL
multiplier =
expiry = 20090930
strike = 38.0
right = C
order_msg:
order id =69
client id =0
action =BUY
quantity =2
type =LMT
lmtPrice =5.0
TIF =DAY
parent Id =0
permId =263195297
order_state_msg:
status =Submitted
initMargin =
maintMargin =
commission =1.7976931348623157e+308
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
orderStatus>: orderId=69, clientId=0, permId=263195297, status=Submitted filled=0, remaining=2,
avgFillPrice=0.0, lastFillPrice=0.0, parent Id=0, whyHeld=
*** requesting open orders ***
--------------------------------------------------------
openOrder> open order: orderId=69 ---
contract_msg:
conid = 56413283
symbol = IWM
secType = OPT
exchange = SMART
currency = USD
localSymbol = IQXIL
multiplier =
expiry = 20090930
strike = 38.0
right = C
order_msg:
order id =69
client id =0
action =BUY
quantity =2
type =LMT
lmtPrice =5.0
TIF =DAY
parent Id =0
permId =263195297
order_state_msg:
status =Submitted
initMargin =
maintMargin =
commission =1.7976931348623157e+308
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
orderStatus>: orderId=69, clientId=0, permId=263195297, status=Submitted filled=0, remaining=2,
avgFillPrice=0.0, lastFillPrice=0.0, parent Id=0, whyHeld=
openOrderEnd> Ended ------------------------
*****************************
**** MARKET ORDER - STC EXISTING POSITION ****
*** requesting open orders ***
--------------------------------------------------------
openOrder> open order: orderId=69 ---
contract_msg:
conid = 56413283
symbol = IWM
secType = OPT
exchange = SMART
currency = USD
localSymbol = IQXIL
multiplier =
expiry = 20090930
strike = 38.0
right = C
order_msg:
order id =69
client id =0
action =BUY
quantity =2
type =LMT
lmtPrice =5.0
TIF =DAY
parent Id =0
permId =263195297
order_state_msg:
status =Submitted
initMargin =
maintMargin =
commission =1.7976931348623157e+308
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
orderStatus>: orderId=69, clientId=0, permId=263195297, status=Submitted filled=0, remaining=2,
avgFillPrice=0.0, lastFillPrice=0.0, parent Id=0, whyHeld=
openOrderEnd> Ended ------------------------
disconnected
Examining the output shows that the limit order for 2 IWM SEP 38 CALL @ 5.00 was created and is waiting to be filled. However, the market order for RUT APR 400 CALL wasn't even submitted. Why not? Switching over to TWS application shows the following pop up message box:
So it looks like this pop up is blocking my order coming through the API. After clicking on "Don't display this message again" and OK, control comes back to TWS. The IWM order is submitted:
The RUT order still hasn't been created, but this makes sense since my API code had already disconnected from TWS. I'm glad this glitch has happened because it points out one of the pitfalls of using API to interface with TWS. TWS is its own program and must be carefully monitored so that any of these pop ups can be detected and handled right away. This also means that any TWS configuration changes, version upgrade, re-installs may cause old pop ups to reappear. I checked TWS configurations and docs and could not find reference describing how to suppress pop ups.
To complete the original example, I modified the code to just submit the RUT order again
puts '*****************************'
puts '**** MARKET ORDER - STC EXISTING POSITION ****'
o2 = x.order_id += 1
x.submitOptionsOrder(o2, 'RUT', 'CALL', '200904', 400,
'SELL', 1, 'MKT', 0, 'DAY')
sleep(5)
puts '*** requesting open orders ***'
Running the code now successfully sells my RUT position. The status of the order is Filled. Note that openOrder() call back method was triggered multiple times for this single order. I'm not sure why this happens. It does make it harder to program the trading robot though.
init
Server Version:43
TWS Time at connection:20090317 15:42:52 EST
connected ...
nextValidId> Next Valid Order Id = 73
openOrderEnd> Ended ------------------------
[API.msg2] Market data farm connection is OK:usopt {-1, 2104}
[API.msg2] Market data farm connection is OK:usfarm {-1, 2104}
**** MARKET ORDER - STC EXISTING POSITION ****
--------------------------------------------------------
openOrder> open order: orderId=74 ---
contract_msg:
conid = 57330039
symbol = RUT
secType = OPT
exchange = SMART
currency = USD
localSymbol = RUWDX
multiplier =
expiry = 20090416
strike = 400.0
right = C
order_msg:
order id =74
client id =0
action =SELL
quantity =1
type =MKT
lmtPrice =0.0
TIF =DAY
parent Id =0
permId =263195311
order_state_msg:
status =Filled
initMargin =
maintMargin =
commission =1.7976931348623157e+308
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
orderStatus>: orderId=74, clientId=0, permId=263195311, status=Filled filled=1, remaining=0,
avgFillPrice=20.0, lastFillPrice=20.0, parent Id=0, whyHeld=
--------------------------------------------------------
openOrder> open order: orderId=74 ---
contract_msg:
conid = 57330039
symbol = RUT
secType = OPT
exchange = SMART
currency = USD
localSymbol = RUWDX
multiplier =
expiry = 20090416
strike = 400.0
right = C
order_msg:
order id =74
client id =0
action =SELL
quantity =1
type =MKT
lmtPrice =0.0
TIF =DAY
parent Id =0
permId =263195311
order_state_msg:
status =Filled
initMargin =
maintMargin =
commission =1.7976931348623157e+308
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
orderStatus>: orderId=74, clientId=0, permId=263195311, status=Filled filled=1, remaining=0,
avgFillPrice=20.0, lastFillPrice=20.0, parent Id=0, whyHeld=
*** requesting open orders ***
openOrderEnd> Ended ------------------------
--------------------------------------------------------
openOrder> open order: orderId=74 ---
contract_msg:
conid = 57330039
symbol = RUT
secType = OPT
exchange = SMART
currency = USD
localSymbol = RUWDX
multiplier =
expiry = 20090416
strike = 400.0
right = C
order_msg:
order id =74
client id =0
action =SELL
quantity =1
type =MKT
lmtPrice =0.0
TIF =DAY
parent Id =0
permId =263195311
order_state_msg:
status =Filled
initMargin =
maintMargin =
commission =1.18
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
orderStatus>: orderId=74, clientId=0, permId=263195311, status=Filled filled=1, remaining=0,
avgFillPrice=20.0, lastFillPrice=20.0, parent Id=0, whyHeld=
disconnected
NOTE: If an order is created but there is no option available, it will automatically be cancelled and the error() method will be called with message 'Limit price too far outside of NBBO'. In this example, I submitted a limit order to buy IWM SEP 75 CALL @ 7.75. There are no 75 call strikes in September.
init
Server Version:43
TWS Time at connection:20090317 15:11:41 EST
connected ...
nextValidId> Next Valid Order Id = 64
openOrderEnd> Ended ------------------------
[API.msg2] Market data farm connection is OK:usopt {-1, 2104}
[API.msg2] Market data farm connection is OK:usfarm {-1, 2104}
*****************************
**** LIMIT ORDER ****
--------------------------------------------------------
openOrder> open order: orderId=64 ---
contract_msg:
conid = 54336659
symbol = IWM
secType = OPT
exchange = SMART
currency = USD
localSymbol = IQQIW
multiplier =
expiry = 20090930
strike = 75.0
right = C
order_msg:
order id =64
client id =0
action =BUY
quantity =2
type =LMT
lmtPrice =7.75
TIF =DAY
parent Id =0
permId =263195279
order_state_msg:
status =PendingCancel
initMargin =
maintMargin =
commission =1.7976931348623157e+308
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
orderStatus>: orderId=64, clientId=0, permId=263195279, status=PendingCancel filled=0, remaining=2,
avgFillPrice=0.0, lastFillPrice=0.0, parent Id=0, whyHeld=
--------------------------------------------------------
openOrder> open order: orderId=64 ---
contract_msg:
conid = 54336659
symbol = IWM
secType = OPT
exchange = SMART
currency = USD
localSymbol = IQQIW
multiplier =
expiry = 20090930
strike = 75.0
right = C
order_msg:
order id =64
client id =0
action =BUY
quantity =2
type =LMT
lmtPrice =7.75
TIF =DAY
parent Id =0
permId =263195279
order_state_msg:
status =PendingCancel
initMargin =
maintMargin =
commission =1.7976931348623157e+308
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
orderStatus>: orderId=64, clientId=0, permId=263195279, status=PendingCancel filled=0, remaining=2,
avgFillPrice=0.0, lastFillPrice=0.0, parent Id=0, whyHeld=
[API.msg2] Order Canceled - reason:Limit price too far outside of NBBO {64, 202}
No comments:
Post a Comment