@@ -18,7 +18,6 @@ import (
1818 "fmt"
1919 "os"
2020 "os/signal"
21- "slices"
2221 "strconv"
2322 "sync"
2423 "syscall"
@@ -142,8 +141,8 @@ func (me *MsgEncoder) encodeInt64(v int64) *MsgEncoder {
142141
143142// encodeInt64 adds a raw int64 value to the message
144143func (me * MsgEncoder ) encodeRawInt64 (v int64 ) * MsgEncoder {
145- var arrayOfBytes [8 ]byte
146- binary .BigEndian .PutUint64 (arrayOfBytes [:], uint64 (v ))
144+ var arrayOfBytes [RAW_INT_LEN ]byte
145+ binary .BigEndian .PutUint32 (arrayOfBytes [:], uint32 (v ))
147146 me .buf .Write (arrayOfBytes [:])
148147 return me
149148}
@@ -180,6 +179,12 @@ func (me *MsgEncoder) encodeBytes(v []byte) *MsgEncoder {
180179 return me
181180}
182181
182+ // encodeBytes adds raw bytes to the message
183+ func (me * MsgEncoder ) encodeProto (v []byte ) * MsgEncoder {
184+ me .buf .Write (v )
185+ return me
186+ }
187+
183188// encodeDecimal adds a Decimal value to the message
184189func (me * MsgEncoder ) encodeDecimal (v Decimal ) * MsgEncoder {
185190 me .buf .WriteString (DecimalToString (v ))
@@ -380,7 +385,10 @@ func (c *EClient) validateInvalidSymbols(host string) error {
380385}
381386
382387func (c * EClient ) useProtoBuf (msgID int64 ) bool {
383- return c .serverVersion >= MIN_SERVER_VER_PROTOBUF && slices .Contains (PROTOBUF_MSG_IDS , msgID )
388+ if version , exists := PROTOBUF_MSG_IDS [OUT (msgID )]; exists {
389+ return version <= c .serverVersion
390+ }
391+ return false
384392}
385393
386394// startAPI initiates the message exchange between the client application and the TWS/IB Gateway.
@@ -1149,6 +1157,11 @@ func (c *EClient) ExerciseOptions(reqID TickerID, contract *Contract, exerciseAc
11491157// order contains the details of the traded order.
11501158func (c * EClient ) PlaceOrder (orderID OrderID , contract * Contract , order * Order ) {
11511159
1160+ if c .useProtoBuf (PLACE_ORDER ) {
1161+ c .placeOrderProtoBuf (createPlaceOrderRequestProto (orderID , contract , order ))
1162+ return
1163+ }
1164+
11521165 if ! c .IsConnected () {
11531166 c .wrapper .Error (orderID , currentTimeMillis (), NOT_CONNECTED .Code , NOT_CONNECTED .Msg , "" )
11541167 return
@@ -1271,7 +1284,7 @@ func (c *EClient) PlaceOrder(orderID OrderID, contract *Contract, order *Order)
12711284 return
12721285 }
12731286
1274- if c .serverVersion < MIN_SERVER_VER_ORDER_SOLICITED && order .Solictied {
1287+ if c .serverVersion < MIN_SERVER_VER_ORDER_SOLICITED && order .Solicited {
12751288 c .wrapper .Error (orderID , currentTimeMillis (), UPDATE_TWS .Code , UPDATE_TWS .Msg + " It does not support order solicited parameter." , "" )
12761289 return
12771290 }
@@ -1316,7 +1329,7 @@ func (c *EClient) PlaceOrder(orderID OrderID, contract *Contract, order *Order)
13161329 return
13171330 }
13181331
1319- if c .serverVersion < MIN_SERVER_VER_PRICE_MGMT_ALGO && order .UsePriceMgmtAlgo {
1332+ if c .serverVersion < MIN_SERVER_VER_PRICE_MGMT_ALGO && order .UsePriceMgmtAlgo != USE_PRICE_MGMT_ALGO_DEFAULT {
13201333 c .wrapper .Error (orderID , currentTimeMillis (), UPDATE_TWS .Code , UPDATE_TWS .Msg + " It does not support Use price management algo requests" , "" )
13211334 return
13221335 }
@@ -1681,7 +1694,7 @@ func (c *EClient) PlaceOrder(orderID OrderID, contract *Contract, order *Order)
16811694 }
16821695
16831696 if c .serverVersion >= MIN_SERVER_VER_ORDER_SOLICITED {
1684- me .encodeBool (order .Solictied )
1697+ me .encodeBool (order .Solicited )
16851698 }
16861699
16871700 if c .serverVersion >= MIN_SERVER_VER_RANDOMIZE_SIZE_AND_PRICE {
@@ -1754,7 +1767,7 @@ func (c *EClient) PlaceOrder(orderID OrderID, contract *Contract, order *Order)
17541767 }
17551768
17561769 if c .serverVersion >= MIN_SERVER_VER_PRICE_MGMT_ALGO {
1757- me .encodeBool (order .UsePriceMgmtAlgo )
1770+ me .encodeIntMax (order .UsePriceMgmtAlgo )
17581771 }
17591772
17601773 if c .serverVersion >= MIN_SERVER_VER_DURATION {
@@ -1825,10 +1838,40 @@ func (c *EClient) PlaceOrder(orderID OrderID, contract *Contract, order *Order)
18251838 c .reqChan <- me .Bytes ()
18261839}
18271840
1841+ func (c * EClient ) placeOrderProtoBuf (placeOrderRequestProto * protobuf.PlaceOrderRequest ) {
1842+
1843+ orderID := NO_VALID_ID
1844+ if placeOrderRequestProto .OrderId != nil {
1845+ orderID = int64 (* placeOrderRequestProto .OrderId )
1846+ }
1847+
1848+ if ! c .IsConnected () {
1849+ c .wrapper .Error (orderID , currentTimeMillis (), NOT_CONNECTED .Code , NOT_CONNECTED .Msg , "" )
1850+ return
1851+ }
1852+ me := NewMsgEncoder (150 , c .serverVersion )
1853+ me .encodeMsgID (PLACE_ORDER + PROTOBUF_MSG_ID )
1854+
1855+ msg , err := proto .Marshal (placeOrderRequestProto )
1856+ if err != nil {
1857+ c .wrapper .Error (orderID , currentTimeMillis (), 0 , "Failed to marshal PlaceOrderRequest: " + err .Error (), "" )
1858+ return
1859+ }
1860+
1861+ me .encodeProto (msg )
1862+
1863+ c .reqChan <- me .Bytes ()
1864+ }
1865+
18281866// CancelOrder cancel an order by orderId.
18291867// It can only be used to cancel an order that was placed originally by a client with the same client ID
18301868func (c * EClient ) CancelOrder (orderID OrderID , orderCancel OrderCancel ) {
18311869
1870+ if c .useProtoBuf (CANCEL_ORDER ) {
1871+ c .cancelOrderProtoBuf (createCancelOrderRequestProto (orderID , & orderCancel ))
1872+ return
1873+ }
1874+
18321875 if ! c .IsConnected () {
18331876 c .wrapper .Error (orderID , currentTimeMillis (), NOT_CONNECTED .Code , NOT_CONNECTED .Msg , "" )
18341877 return
@@ -1873,6 +1916,33 @@ func (c *EClient) CancelOrder(orderID OrderID, orderCancel OrderCancel) {
18731916 c .reqChan <- me .Bytes ()
18741917}
18751918
1919+ func (c * EClient ) cancelOrderProtoBuf (cancelOrderRequestProto * protobuf.CancelOrderRequest ) {
1920+
1921+ orderID := NO_VALID_ID
1922+ if cancelOrderRequestProto .OrderId != nil {
1923+ orderID = int64 (* cancelOrderRequestProto .OrderId )
1924+ }
1925+
1926+ if ! c .IsConnected () {
1927+ c .wrapper .Error (orderID , currentTimeMillis (), NOT_CONNECTED .Code , NOT_CONNECTED .Msg , "" )
1928+ return
1929+ }
1930+
1931+ me := NewMsgEncoder (9 , c .serverVersion )
1932+ me .encodeMsgID (CANCEL_ORDER + PROTOBUF_MSG_ID )
1933+
1934+ msg , err := proto .Marshal (cancelOrderRequestProto )
1935+ if err != nil {
1936+ c .wrapper .Error (orderID , currentTimeMillis (), 0 , "Failed to marshal CancelOrderRequest: " + err .Error (), "" )
1937+ return
1938+ }
1939+
1940+ me .encodeProto (msg )
1941+
1942+ c .reqChan <- me .Bytes ()
1943+ }
1944+
1945+ // CancelOrderAsync cancel an order by orderId.
18761946// ReqOpenOrders requests the open orders that were placed from this client.
18771947// Each open order will be fed back through the openOrder() and orderStatus() functions on the EWrapper.
18781948// The client with a clientId of 0 will also receive the TWS-owned open orders.
@@ -1941,6 +2011,11 @@ func (c *EClient) ReqAllOpenOrders() {
19412011// ReqGlobalCancel cancels all open orders globally. It cancels both API and TWS open orders.
19422012func (c * EClient ) ReqGlobalCancel (orderCancel OrderCancel ) {
19432013
2014+ if c .useProtoBuf (REQ_ALL_OPEN_ORDERS ) {
2015+ c .reqGlobalCancelProtoBuf (createGlobalCancelRequestProto (& orderCancel ))
2016+ return
2017+ }
2018+
19442019 if ! c .IsConnected () {
19452020 c .wrapper .Error (NO_VALID_ID , currentTimeMillis (), NOT_CONNECTED .Code , NOT_CONNECTED .Msg , "" )
19462021 return
@@ -1968,6 +2043,27 @@ func (c *EClient) ReqGlobalCancel(orderCancel OrderCancel) {
19682043 c .reqChan <- me .Bytes ()
19692044}
19702045
2046+ func (c * EClient ) reqGlobalCancelProtoBuf (globalCancelRequestProto * protobuf.GlobalCancelRequest ) {
2047+
2048+ if ! c .IsConnected () {
2049+ c .wrapper .Error (NO_VALID_ID , currentTimeMillis (), NOT_CONNECTED .Code , NOT_CONNECTED .Msg , "" )
2050+ return
2051+ }
2052+
2053+ me := NewMsgEncoder (4 , c .serverVersion )
2054+ me .encodeMsgID (REQ_GLOBAL_CANCEL + PROTOBUF_MSG_ID )
2055+
2056+ msg , err := proto .Marshal (globalCancelRequestProto )
2057+ if err != nil {
2058+ c .wrapper .Error (NO_VALID_ID , currentTimeMillis (), 0 , "Failed to marshal GlobalCancelRequest: " + err .Error (), "" )
2059+ return
2060+ }
2061+
2062+ me .encodeProto (msg )
2063+
2064+ c .reqChan <- me .Bytes ()
2065+ }
2066+
19712067// ReqIDs request from TWS the next valid ID that can be used when placing an order.
19722068// After calling this function, the nextValidId() event will be triggered, and the id returned is that next valid ID.
19732069// That ID will reflect any autobinding that has occurred (which generates new IDs and increments the next valid ID therein).
@@ -2350,69 +2446,12 @@ func (c *EClient) CancelPnLSingle(reqID int64) {
23502446// execFilter contains attributes that describe the filter criteria used to determine which execution reports are returned.
23512447// NOTE: Time format must be 'yyyymmdd-hh:mm:ss' Eg: '20030702-14:55'
23522448func (c * EClient ) ReqExecutions (reqID int64 , execFilter * ExecutionFilter ) {
2353- if c .useProtoBuf (REQ_EXECUTIONS ) {
2354- c .reqExecutionsNonProtobuf (reqID , execFilter )
2355- } else {
2356- c .reqExecutionProtobuf (reqID , execFilter )
2357- }
2358- }
2359-
2360- func (c * EClient ) reqExecutionProtobuf (reqID int64 , execFilter * ExecutionFilter ) {
23612449
2362- if ! c . IsConnected ( ) {
2363- c .wrapper . Error ( NO_VALID_ID , currentTimeMillis (), NOT_CONNECTED . Code , NOT_CONNECTED . Msg , "" )
2450+ if c . useProtoBuf ( REQ_EXECUTIONS ) {
2451+ c .reqExecutionProtobuf ( createExecutionRequestProto ( reqID , execFilter ) )
23642452 return
23652453 }
23662454
2367- execFilterPB := protobuf.ExecutionFilter {}
2368- if execFilter .ClientID != UNSET_INT {
2369- clientID := int32 (execFilter .ClientID )
2370- execFilterPB .ClientId = & clientID
2371- }
2372- if execFilter .AcctCode != "" {
2373- execFilterPB .AcctCode = & execFilter .AcctCode
2374- }
2375- if execFilter .Time != "" {
2376- execFilterPB .Time = & execFilter .Time
2377- }
2378- if execFilter .Symbol != "" {
2379- execFilterPB .Symbol = & execFilter .Symbol
2380- }
2381- if execFilter .SecType != "" {
2382- execFilterPB .SecType = & execFilter .SecType
2383- }
2384- if execFilter .Exchange != "" {
2385- execFilterPB .Exchange = & execFilter .Exchange
2386- }
2387- if execFilter .Side != "" {
2388- execFilterPB .Side = & execFilter .Side
2389- }
2390- if execFilter .LastNDays != UNSET_INT {
2391- lastNDays := int32 (execFilter .LastNDays )
2392- execFilterPB .LastNDays = & lastNDays
2393- }
2394- if execFilter .SpecificDates != nil {
2395- execFilterPB .SpecificDates = make ([]int32 , len (execFilter .SpecificDates ))
2396- for i , date := range execFilter .SpecificDates {
2397- execFilterPB .SpecificDates [i ] = int32 (date )
2398- }
2399- }
2400-
2401- executionRequest := protobuf.ExecutionRequest {}
2402- id := int32 (reqID )
2403- executionRequest .ReqId = & id
2404- executionRequest .ExecutionFilter = & execFilterPB
2405-
2406- msg , err := proto .Marshal (& executionRequest )
2407- if err != nil {
2408- log .Panic ().Err (err ).Msg ("reqExecutionProtobuf marshal error" )
2409- }
2410-
2411- c .reqChan <- msg
2412- }
2413-
2414- func (c * EClient ) reqExecutionsNonProtobuf (reqID int64 , execFilter * ExecutionFilter ) {
2415-
24162455 if ! c .IsConnected () {
24172456 c .wrapper .Error (NO_VALID_ID , currentTimeMillis (), NOT_CONNECTED .Code , NOT_CONNECTED .Msg , "" )
24182457 return
@@ -2454,6 +2493,31 @@ func (c *EClient) reqExecutionsNonProtobuf(reqID int64, execFilter *ExecutionFil
24542493 c .reqChan <- me .Bytes ()
24552494}
24562495
2496+ func (c * EClient ) reqExecutionProtobuf (executionRequestProto * protobuf.ExecutionRequest ) {
2497+
2498+ reqID := NO_VALID_ID
2499+ if executionRequestProto .ReqId != nil {
2500+ reqID = int64 (* executionRequestProto .ReqId )
2501+ }
2502+
2503+ if ! c .IsConnected () {
2504+ c .wrapper .Error (reqID , currentTimeMillis (), NOT_CONNECTED .Code , NOT_CONNECTED .Msg , "" )
2505+ return
2506+ }
2507+
2508+ me := NewMsgEncoder (0 , c .serverVersion )
2509+ me .encodeMsgID (REQ_EXECUTIONS + PROTOBUF_MSG_ID )
2510+
2511+ msg , err := proto .Marshal (executionRequestProto )
2512+ if err != nil {
2513+ log .Panic ().Err (err ).Msg ("reqExecutionProtobuf marshal error" )
2514+ }
2515+
2516+ me .encodeProto (msg )
2517+
2518+ c .reqChan <- me .Bytes ()
2519+ }
2520+
24572521// ##########################################################################
24582522// # Contract Details
24592523// ##########################################################################
0 commit comments