├── .github
├── release-drafter.yml
└── workflows
│ └── release-drafter.yml
├── .gitignore
├── LICENSE
├── README.md
├── client.go
├── client_test.go
├── common.go
├── connection.go
├── connection_test.go
├── const.go
├── contract.go
├── decoder.go
├── decoder_test.go
├── errors.go
├── execution.go
├── go.mod
├── go.sum
├── order.go
├── orderCondition.go
├── scanner.go
├── utils.go
├── utils_test.go
└── wrapper.go
/.github/release-drafter.yml:
--------------------------------------------------------------------------------
1 | name-template: 'Interactive Brokers API $RESOLVED_VERSION'
2 | tag-template: 'v$RESOLVED_VERSION'
3 | categories:
4 | - title: 'Features'
5 | labels:
6 | - 'feature'
7 | - title: 'Enhancement'
8 | labels:
9 | - 'enhancement'
10 | - title: 'Bug Fixes'
11 | labels:
12 | - 'fix'
13 | - 'bugfix'
14 | - 'bug'
15 | change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
16 | change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.
17 | version-resolver:
18 | major:
19 | labels:
20 | - 'major'
21 | minor:
22 | labels:
23 | - 'minor'
24 | patch:
25 | labels:
26 | - 'patch'
27 | default: patch
28 | template: |
29 | ## CONTRIBUTORS
30 |
31 | $CONTRIBUTORS
--------------------------------------------------------------------------------
/.github/workflows/release-drafter.yml:
--------------------------------------------------------------------------------
1 | name: Release Drafter
2 |
3 | on:
4 | push:
5 | # branches to consider in the event; optional, defaults to all
6 | tags:
7 | - v*
8 | pull_request:
9 | # Only following types are handled by the action, but one can default to all as well
10 | types: [opened, reopened, synchronize]
11 |
12 | jobs:
13 | update_release_draft:
14 | runs-on: ubuntu-latest
15 | steps:
16 | - uses: release-drafter/release-drafter@v5
17 | # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
18 | # with:
19 | # config-name: my-config.yml
20 | env:
21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | debug.test
2 | .vscode
3 |
4 | .idea
5 | .idea/*
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Hadrianl_yang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Interactive Brokers API - GoLang Implement
2 |
3 |
7 |
8 | * Interactive Brokers API 9.80
9 | * pure golang Implement
10 | * Unofficial, use at you own risk
11 |
12 | ## INSTALL
13 |
14 | `go get -u github.com/hadrianl/ibapi`
15 |
16 | ---
17 |
18 | ## USAGE
19 |
20 | Implement `IbWrapper` to handle datas delivered via tws or gateway, `Wrapper` in demo is a default implement that just output data to std.
21 | [Go to IbWrapper](https://github.com/hadrianl/ibapi/blob/83846bf1194bbdc4f039c8c66033f717e015e9fc/wrapper.go#L11)
22 |
23 | 1. **implement** your own `IbWrapper`
24 | 2. **connect** to TWS or Gateway
25 | 3. **handshake** with TWS or Gateway
26 | 4. **run** the loop
27 | 5. do some **request**
28 |
29 | ### Demo 1
30 |
31 | ```golang
32 | import (
33 | . "github.com/hadrianl/ibapi"
34 | "time"
35 | )
36 |
37 | func main(){
38 | // internal api log is zap log, you could use GetLogger to get the logger
39 | // besides, you could use SetAPILogger to set you own log option
40 | // or you can just use the other logger
41 | log := GetLogger().Sugar()
42 | defer log.Sync()
43 | // implement your own IbWrapper to handle the msg delivered via tws or gateway
44 | // Wrapper{} below is a default implement which just log the msg
45 | ic := NewIbClient(&Wrapper{})
46 |
47 | // tcp connect with tws or gateway
48 | // fail if tws or gateway had not yet set the trust IP
49 | if err := ic.Connect("127.0.0.1", 4002, 0);err != nil {
50 | log.Panic("Connect failed:", err)
51 | }
52 |
53 | // handshake with tws or gateway, send handshake protocol to tell tws or gateway the version of client
54 | // and receive the server version and connection time from tws or gateway.
55 | // fail if someone else had already connected to tws or gateway with same clientID
56 | if err := ic.HandShake();err != nil {
57 | log.Panic("HandShake failed:", err)
58 | }
59 |
60 | // make some request, msg would be delivered via wrapper.
61 | // req will not send to TWS or Gateway until ic.Run()
62 | // you could just call ic.Run() before these
63 | ic.ReqCurrentTime()
64 | ic.ReqAutoOpenOrders(true)
65 | ic.ReqAccountUpdates(true, "")
66 | ic.ReqExecutions(ic.GetReqID(), ExecutionFilter{})
67 |
68 | // start to send req and receive msg from tws or gateway after this
69 | ic.Run()
70 | <-time.After(time.Second * 60)
71 | ic.Disconnect()
72 | }
73 |
74 | ```
75 |
76 | ### Demo 2 with context
77 |
78 | ```golang
79 | import (
80 | . "github.com/hadrianl/ibapi"
81 | "time"
82 | "context"
83 | )
84 |
85 | func main(){
86 | var err error
87 | SetAPILogger(zap.NewDevelopmentConfig()) // log is default for production(json encode, info level), set to development(console encode, debug level) here
88 | log := GetLogger().Sugar()
89 | defer log.Sync()
90 | ibwrapper := &Wrapper{}
91 | ctx, _ := context.WithTimeout(context.Background(), time.Second*30)
92 | ic := NewIbClient(ibwrapper)
93 | ic.SetContext(ctx)
94 | err = ic.Connect("127.0.0.1", 4002, 0)
95 | if err != nil {
96 | log.Panic("Connect failed:", err)
97 | }
98 |
99 | err = ic.HandShake()
100 | if err != nil {
101 | log.Panic("HandShake failed:", err)
102 | }
103 |
104 | ic.ReqCurrentTime()
105 | ic.ReqAutoOpenOrders(true)
106 | ic.ReqAccountUpdates(true, "")
107 | ic.ReqExecutions(ic.GetReqID(), ExecutionFilter{})
108 |
109 | ic.Run()
110 | err = ic.LoopUntilDone() // block until ctx or ic is done
111 | log.Info(err)
112 | }
113 |
114 | ```
115 |
116 | ---
117 |
118 | ## Reference
119 |
120 | 1. [Offical Document](https://interactivebrokers.github.io/tws-api/)
121 | 2. [Order Types](https://www.interactivebrokers.com/en/index.php?f=4985)
122 | 3. [Product](https://www.interactivebrokers.com/en/index.php?f=4599)
123 | 4. [Margin](https://www.interactivebrokers.com/en/index.php?f=24176)
124 | 5. [Market Data](https://www.interactivebrokers.com/en/index.php?f=14193)
125 | 6. [Commissions](https://www.interactivebrokers.com/en/index.php?f=1590)
126 |
--------------------------------------------------------------------------------
/client_test.go:
--------------------------------------------------------------------------------
1 | package ibapi
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "net/http"
7 | _ "net/http/pprof"
8 | "os"
9 | "os/signal"
10 | "runtime"
11 | "strings"
12 | "syscall"
13 | "testing"
14 | "time"
15 |
16 | "go.uber.org/zap"
17 | // "time"
18 | )
19 |
20 | func TestClient(t *testing.T) {
21 | SetAPILogger(zap.NewDevelopmentConfig())
22 | log := GetLogger()
23 | defer log.Sync()
24 | runtime.GOMAXPROCS(4)
25 |
26 | ic := NewIbClient(new(Wrapper))
27 |
28 | if err := ic.Connect("localhost", 7497, 100); err != nil {
29 | log.Panic("failed to connect", zap.Error(err))
30 | }
31 |
32 | ic.SetConnectionOptions("+PACEAPI")
33 |
34 | if err := ic.HandShake(); err != nil {
35 | log.Panic("failed to hand shake", zap.Error(err))
36 | }
37 | ic.Run()
38 |
39 | // ####################### request base info ##################################################################
40 | ic.ReqCurrentTime()
41 | ic.ReqAutoOpenOrders(true)
42 | //ic.ReqAutoOpenOrders(false)
43 | ic.ReqAccountUpdates(true, "")
44 | //ic.ReqAccountUpdates(false, "")
45 | ic.ReqExecutions(ic.GetReqID(), ExecutionFilter{})
46 | ic.ReqAllOpenOrders()
47 | ic.ReqPositions()
48 | // ic.CancelPositions()
49 | // ic.ReqAccountUpdatesMulti(ic.GetReqID(), "DU1382837", "", true)
50 | // ic.CancelAccountUpdatesMulti()
51 | // ic.ReqPositionsMulti(ic.GetReqID(), "DU1382837", "")
52 | // ic.CancelPositionsMulti()
53 | // tags := []string{"AccountType", "NetLiquidation", "TotalCashValue", "SettledCash",
54 | // "AccruedCash", "BuyingPower", "EquityWithLoanValue",
55 | // "PreviousEquityWithLoanValue", "GrossPositionValue", "ReqTEquity",
56 | // "ReqTMargin", "SMA", "InitMarginReq", "MaintMarginReq", "AvailableFunds",
57 | // "ExcessLiquidity", "Cushion", "FullInitMarginReq", "FullMaintMarginReq",
58 | // "FullAvailableFunds", "FullExcessLiquidity", "LookAheadNextChange",
59 | // "LookAheadInitMarginReq", "LookAheadMaintMarginReq",
60 | // "LookAheadAvailableFunds", "LookAheadExcessLiquidity",
61 | // "HighestSeverity", "DayTradesRemaining", "Leverage", "$LEDGER:ALL"}
62 | // ic.ReqAccountSummary(ic.GetReqID(), "All", strings.Join(tags, ","))
63 | // ic.CancelAccountSummary()
64 |
65 | // ########################## request market data #################################################
66 | // hsi := Contract{ContractID: 389657869, Symbol: "HSI", SecurityType: "FUT", Exchange: "HKFE"}
67 | // ic.ReqHistoricalData(ic.GetReqID(), &hsi, "", "4800 S", "1 min", "TRADES", false, 1, true, nil)
68 | // // ic.CancelHistoricalData()
69 | // ic.ReqMktDepth(ic.GetReqID(), &hsi, 5, true, nil)
70 | // //ic.CancelMktDepth()
71 | // ic.ReqMktData(ic.GetReqID(), &hsi, "", false, false, nil)
72 | // // ic.CancelMktData()
73 | // ic.ReqRealTimeBars(ic.GetReqID(), &hsi, 5, "TRADES", false, nil)
74 | // // ic.CancelRealTimeBars()
75 | // ic.ReqTickByTickData(ic.GetReqID(), &hsi, "Last", 5, false)
76 | // ic.CancelTickByTickData()
77 | // ic.ReqHistoricalTicks(ic.GetReqID(), &hsi, "20190916 09:15:00", "", 100, "Trades", false, false, nil)
78 | // ic.ReqHistogramData(ic.GetReqID(), &hsi, false, "3 days")
79 | // // ic.CancelHistogramData()
80 |
81 | // ############################# request combo historical data ################################################
82 | // hsiSpread := new(Contract)
83 | // hsiSpread.Symbol = "HSI"
84 | // hsiSpread.SecurityType = "BAG"
85 | // hsiSpread.Currency = "HKD"
86 | // hsiSpread.Exchange = "HKFE"
87 | // leg1 := ComboLeg{ContractID: 389657869, Ratio: 1, Action: "BUY", Exchange: "HKFE"}
88 | // leg2 := ComboLeg{ContractID: 424418656, Ratio: 1, Action: "SELL", Exchange: "HKFE"}
89 | // hsiSpread.ComboLegs = append(hsiSpread.ComboLegs, leg1, leg2)
90 | // ic.ReqHistoricalData(ic.GetReqID(), hsiSpread, "", "4800 S", "1 min", "TRADES", false, 1, false, nil)
91 |
92 | // ######################### request contract ############################################################
93 | // hsi := Contract{Symbol: "HSI", SecurityType: "FUT", Exchange: "HKFE"}
94 | // ic.ReqContractDetails(ic.GetReqID(), &hsi)
95 | // ic.ReqMatchingSymbols(ic.GetReqID(), "IB")
96 |
97 | // ######################### market scanner #############################################################
98 | // ic.ReqScannerParameters()
99 | // scanSub := new(ScannerSubscription)
100 | // scanSub.Instrument = "FUT.HK"
101 | // scanSub.LocationCode = "FUT.HK"
102 | // scanSub.ScanCode = "HOT_BY_VOLUME"
103 | // // t1 := TagValue{"usdMarketCapAbove", "10000"}
104 | // // t2 := TagValue{"optVolumeAbove", "1000"}
105 | // // t3 := TagValue{"avgVolumeAbove", "100000000"}
106 | // ic.ReqScannerSubscription(ic.GetReqID(), scanSub, nil, nil)
107 | // // ic.CancelScannerSubscription()
108 |
109 | // ############################### display group ########################################################
110 | // ic.QueryDisplayGroups(ic.GetReqID())
111 | // subGroupID := ic.GetReqID()
112 | // ic.SubscribeToGroupEvents(subGroupID, 4)
113 | // ic.UpdateDisplayGroup(subGroupID, "389657869@HKFE")
114 | // // ic.UnsubscribeFromGroupEvents(subGroupID)
115 |
116 | // ############################ others #########################################################################
117 |
118 | // ic.ReqFamilyCodes()
119 | // ic.ReqScannerParameters()
120 | // ic.ReqManagedAccts()
121 | // ic.ReqSoftDollarTiers(ic.GetReqID())
122 | // ic.ReqNewsProviders()
123 | // ic.ReqMarketDataType(1)
124 | // ic.ReqPnLSingle(ic.GetReqID(), "DU1382837", "", 351872027)
125 | // ic.ReqNewsBulletins(true)
126 | // ic.ReqSmartComponents(ic.GetReqID(), "a6")
127 | // ic.ReqMktDepthExchanges()
128 | // ic.ReqMatchingSymbols(ic.GetReqID(), "HSI")
129 | // ic.ReqSecDefOptParams(ic.GetReqID(), "HSI", "", "IND", 1328298)
130 | // ic.ReqGlobalCancel()
131 | // ic.ReqIDs()
132 | ic.ReqCompletedOrders(false)
133 | // lmtOrder := NewLimitOrder("BUY", 26640, 1)
134 | // mktOrder := NewMarketOrder("BUY", 1)
135 | // ic.PlaceOrder(ibwrapper.GetNextOrderID(), &hsi1909, lmtOrder)
136 | // ic.CancelOrder(ibwrapper.OrderID() - 1)
137 | // ic.ReqHeadTimeStamp(ic.GetReqID(), &hsi, "TRADES", false, 1)
138 | // ic.ReqNewsBulletins(true)
139 | // ic.ReqFundamentalData()
140 |
141 | ic.LoopUntilDone(
142 | func() {
143 | <-time.After(time.Second * 25)
144 | ic.Disconnect()
145 | })
146 | // loop:
147 | // for {
148 | // select {
149 | // case <-time.After(time.Second * 60):
150 | // ic.Disconnect()
151 | // break loop
152 | // }
153 | // }
154 |
155 | }
156 |
157 | func TestClientReconnect(t *testing.T) {
158 | log, _ = zap.NewDevelopment() // log is default for production(json encode, info level), set to development(console encode, debug level) here
159 | defer log.Sync()
160 | runtime.GOMAXPROCS(4)
161 |
162 | ic := NewIbClient(new(Wrapper))
163 |
164 | for {
165 | if err := ic.Connect("localhost", 4002, 0); err != nil {
166 | log.Error("failed to connect, reconnect after 5 sec", zap.Error(err))
167 | time.Sleep(5 * time.Second)
168 | continue
169 | }
170 |
171 | ic.SetConnectionOptions("+PACEAPI")
172 |
173 | if err := ic.HandShake(); err != nil {
174 | log.Error("failed to hand shake, reconnect after 5 sec", zap.Error(err))
175 | time.Sleep(5 * time.Second)
176 | continue
177 | }
178 | ic.Run()
179 | ic.LoopUntilDone(func() {
180 | <-time.After(25 * time.Second) // block 25 sec and disconnect
181 | ic.Disconnect()
182 | })
183 | }
184 |
185 | }
186 |
187 | func TestClientWithContext(t *testing.T) {
188 | // log.SetLevel(log.DebugLevel)
189 | runtime.GOMAXPROCS(4)
190 | var err error
191 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*30000)
192 | sigs := make(chan os.Signal, 1)
193 | signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
194 | ibwrapper := new(Wrapper)
195 | ic := NewIbClient(ibwrapper)
196 | ic.SetContext(ctx)
197 | err = ic.Connect("localhost", 7497, 0)
198 | if err != nil {
199 | log.Panic("failed to connect", zap.Error(err))
200 | }
201 |
202 | ic.SetConnectionOptions("+PACEAPI")
203 | err = ic.HandShake()
204 | if err != nil {
205 | log.Panic("failed to hand shake", zap.Error(err))
206 | }
207 | ic.Run()
208 |
209 | ic.ReqCurrentTime()
210 | // ic.ReqAutoOpenOrders(true)
211 | ic.ReqAccountUpdates(true, "")
212 | // ic.ReqExecutions(ic.GetReqID(), ExecutionFilter{})
213 |
214 | hsi := Contract{ContractID: 500007591, Symbol: "HSI", SecurityType: "FUT", Exchange: "HKFE"}
215 | // hsi := Contract{Symbol: "HSI", SecurityType: "FUT", Exchange: "HKFE"}
216 | // ic.ReqMktDepth(ic.GetReqID(), &hsi1909, 5, true, nil)
217 | ic.ReqContractDetails(ic.GetReqID(), &hsi)
218 | // ic.ReqAllOpenOrders()
219 | ic.ReqMktData(ic.GetReqID(), &hsi, "", false, false, nil)
220 | // ic.ReqPositions()
221 | // ic.ReqRealTimeBars(ic.GetReqID(), &hsi1909, 5, "TRADES", false, nil)
222 |
223 | tags := []string{"AccountType", "NetLiquidation", "TotalCashValue", "SettledCash",
224 | "AccruedCash", "BuyingPower", "EquityWithLoanValue",
225 | "PreviousEquityWithLoanValue", "GrossPositionValue", "ReqTEquity",
226 | "ReqTMargin", "SMA", "InitMarginReq", "MaintMarginReq", "AvailableFunds",
227 | "ExcessLiquidity", "Cushion", "FullInitMarginReq", "FullMaintMarginReq",
228 | "FullAvailableFunds", "FullExcessLiquidity", "LookAheadNextChange",
229 | "LookAheadInitMarginReq", "LookAheadMaintMarginReq",
230 | "LookAheadAvailableFunds", "LookAheadExcessLiquidity",
231 | "HighestSeverity", "DayTradesRemaining", "Leverage", "$LEDGER:ALL"}
232 | ic.ReqAccountSummary(ic.GetReqID(), "All", strings.Join(tags, ","))
233 |
234 | ic.ReqHistoricalData(ic.GetReqID(), &hsi, "", "4800 S", "1 min", "TRADES", false, 1, true, nil)
235 |
236 | pprofServe := func() {
237 | http.ListenAndServe("localhost:6060", nil)
238 | }
239 |
240 | go pprofServe()
241 |
242 | f := func() {
243 | sig := <-sigs
244 | fmt.Print(sig)
245 | cancel()
246 | }
247 |
248 | err = ic.LoopUntilDone(f)
249 | fmt.Println(err)
250 |
251 | }
252 |
253 | func BenchmarkPlaceOrder(b *testing.B) {
254 | ibwrapper := new(Wrapper)
255 | ic := NewIbClient(ibwrapper)
256 | ic.setConnState(2)
257 | ic.serverVersion = 151
258 | contract := new(Contract)
259 | order := new(Order)
260 |
261 | go func() {
262 | for {
263 | <-ic.reqChan
264 | }
265 | }()
266 |
267 | for i := 0; i < b.N; i++ {
268 | ic.PlaceOrder(1, contract, order)
269 | }
270 | }
271 |
272 | func BenchmarkAppendEmptySlice(b *testing.B) {
273 | arr := []byte("benchmark test of append and copy")
274 | for i := 0; i < b.N; i++ {
275 | _ = append([]byte{}, arr...)
276 | }
277 | }
278 |
279 | func BenchmarkCopySlice(b *testing.B) {
280 | arr := []byte("benchmark test of append and copy")
281 | for i := 0; i < b.N; i++ {
282 | oarr := arr
283 | newSlice := make([]byte, len(oarr))
284 | copy(newSlice, oarr)
285 | _ = newSlice
286 | }
287 | }
288 |
289 | func TestPlaceOrder(t *testing.T) {
290 | SetAPILogger(zap.NewDevelopmentConfig())
291 | log := GetLogger()
292 | defer log.Sync()
293 | runtime.GOMAXPROCS(4)
294 | var err error
295 |
296 | ibwrapper := new(Wrapper)
297 | ic := NewIbClient(ibwrapper)
298 |
299 | err = ic.Connect("localhost", 7497, 0)
300 | if err != nil {
301 | log.Panic("failed to connect", zap.Error(err))
302 | }
303 |
304 | ic.SetConnectionOptions("+PACEAPI")
305 | err = ic.HandShake()
306 | if err != nil {
307 | log.Panic("failed to hand shake", zap.Error(err))
308 | }
309 | ic.Run()
310 |
311 | ic.ReqCurrentTime()
312 | // ic.ReqAutoOpenOrders(true)
313 | ic.ReqAccountUpdates(true, "")
314 | // ic.ReqExecutions(ic.GetReqID(), ExecutionFilter{})
315 |
316 | // hsi := Contract{ContractID: 500007591, Symbol: "HSI", SecurityType: "FUT", Exchange: "HKFE"}
317 | aapl := Contract{ContractID: 265598, Symbol: "AAPL", SecurityType: "STK", Exchange: "NYSE"}
318 | ic.ReqContractDetails(ic.GetReqID(), &aapl)
319 |
320 | ic.ReqMktData(ic.GetReqID(), &aapl, "", false, false, nil)
321 |
322 | lmtOrder := NewLimitOrder("BUY", 144, 1)
323 | // mktOrder := NewMarketOrder("BUY", 1)
324 | ic.PlaceOrder(ibwrapper.GetNextOrderID(), &aapl, lmtOrder)
325 |
326 | ic.LoopUntilDone(
327 | func() {
328 | <-time.After(time.Second * 25)
329 | ic.Disconnect()
330 | })
331 |
332 | fmt.Println(err)
333 |
334 | }
335 |
--------------------------------------------------------------------------------
/common.go:
--------------------------------------------------------------------------------
1 | package ibapi
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | // Account ...
8 | type Account struct {
9 | Name string
10 | }
11 |
12 | // TickAttrib describes additional information for price ticks
13 | type TickAttrib struct {
14 | CanAutoExecute bool
15 | PastLimit bool
16 | PreOpen bool
17 | }
18 |
19 | func (t TickAttrib) String() string {
20 | return fmt.Sprintf("TickAttrib",
21 | t.CanAutoExecute,
22 | t.PastLimit,
23 | t.PreOpen)
24 | }
25 |
26 | // AlgoParams ...
27 | type AlgoParams struct {
28 | }
29 |
30 | // TagValue ...
31 | type TagValue struct {
32 | Tag string
33 | Value string
34 | }
35 |
36 | func (tv TagValue) String() string {
37 | return fmt.Sprintf("TagValue<%s=%s>", tv.Tag, tv.Value)
38 | }
39 |
40 | // OrderComboLeg ...
41 | type OrderComboLeg struct {
42 | Price float64 `default:"UNSETFLOAT"`
43 | }
44 |
45 | func (o OrderComboLeg) String() string {
46 | return fmt.Sprintf("OrderComboLeg;", o.Price)
47 | }
48 |
49 | // ------------ComboLeg--------------------
50 |
51 | // ComboLegOpenClose ...
52 | type ComboLegOpenClose int64
53 |
54 | // ComboLegShortSaleSlot ...
55 | type ComboLegShortSaleSlot int64
56 |
57 | const (
58 | SAME_POS ComboLegOpenClose = 0
59 | OPEN_POS = 1
60 | CLOSE_POS = 2
61 | UNKNOWN_POS = 3
62 | ClearingBroker ComboLegShortSaleSlot = 1
63 | ThirdParty = 2
64 | )
65 |
66 | // ComboLeg ...
67 | type ComboLeg struct {
68 | ContractID int64
69 | Ratio int64
70 | Action string
71 | Exchange string
72 | OpenClose int64
73 |
74 | // for stock legs when doing short sale
75 | ShortSaleSlot int64
76 | DesignatedLocation string
77 | ExemptCode int64 `default:"-1"`
78 | }
79 |
80 | func (c ComboLeg) String() string {
81 | return fmt.Sprintf("ComboLeg<%d, %d, %s, %s, %d, %d, %s, %d>",
82 | c.ContractID,
83 | c.Ratio,
84 | c.Action,
85 | c.Exchange,
86 | c.OpenClose,
87 | c.ShortSaleSlot,
88 | c.DesignatedLocation,
89 | c.ExemptCode)
90 | }
91 |
92 | // -----------------------------------------------------
93 |
94 | // ExecutionFilter ...
95 | type ExecutionFilter struct {
96 | ClientID int64
97 | AccountCode string
98 | Time string
99 | Symbol string
100 | SecurityType string
101 | Exchange string
102 | Side string
103 | }
104 |
105 | // BarData ...
106 | type BarData struct {
107 | Date string
108 | Open float64
109 | High float64
110 | Low float64
111 | Close float64
112 | Volume float64
113 | BarCount int64
114 | Average float64
115 | }
116 |
117 | func (b BarData) String() string {
118 | return fmt.Sprintf("BarData",
119 | b.Date,
120 | b.Open,
121 | b.High,
122 | b.Low,
123 | b.Close,
124 | b.Volume,
125 | b.Average,
126 | b.BarCount)
127 | }
128 |
129 | // RealTimeBar ...
130 | type RealTimeBar struct {
131 | Time int64
132 | endTime int64
133 | Open float64
134 | High float64
135 | Low float64
136 | Close float64
137 | Volume int64
138 | Wap float64
139 | Count int64
140 | }
141 |
142 | func (rb RealTimeBar) String() string {
143 | return fmt.Sprintf("RealTimeBar",
144 | rb.Time,
145 | rb.Open,
146 | rb.High,
147 | rb.Low,
148 | rb.Close,
149 | rb.Volume,
150 | rb.Wap,
151 | rb.Count)
152 | }
153 |
154 | // CommissionReport ...
155 | type CommissionReport struct {
156 | ExecID string
157 | Commission float64
158 | Currency string
159 | RealizedPNL float64
160 | Yield float64
161 | YieldRedemptionDate int64 //YYYYMMDD
162 | }
163 |
164 | func (cr CommissionReport) String() string {
165 | return fmt.Sprintf("CommissionReport",
166 | cr.ExecID,
167 | cr.Commission,
168 | cr.Currency,
169 | cr.RealizedPNL,
170 | cr.Yield,
171 | cr.YieldRedemptionDate)
172 | }
173 |
174 | // FamilyCode ...
175 | type FamilyCode struct {
176 | AccountID string
177 | FamilyCode string
178 | }
179 |
180 | func (f FamilyCode) String() string {
181 | return fmt.Sprintf("FamilyCode",
182 | f.AccountID,
183 | f.FamilyCode)
184 | }
185 |
186 | // SmartComponent ...
187 | type SmartComponent struct {
188 | BitNumber int64
189 | Exchange string
190 | ExchangeLetter string
191 | }
192 |
193 | func (s SmartComponent) String() string {
194 | return fmt.Sprintf("SmartComponent",
195 | s.BitNumber,
196 | s.Exchange,
197 | s.ExchangeLetter)
198 | }
199 |
200 | // DepthMktDataDescription ...
201 | type DepthMktDataDescription struct {
202 | Exchange string
203 | SecurityType string
204 | ListingExchange string
205 | ServiceDataType string
206 | AggGroup int64 `default:"UNSETINT"`
207 | }
208 |
209 | // DepthMktDataDescription ...
210 | func (d DepthMktDataDescription) String() string {
211 | aggGroup := ""
212 | if d.AggGroup != UNSETINT {
213 | aggGroup = fmt.Sprint(d.AggGroup)
214 | }
215 |
216 | return fmt.Sprintf("DepthMktDataDescription",
217 | d.Exchange,
218 | d.SecurityType,
219 | d.ListingExchange,
220 | d.ServiceDataType,
221 | aggGroup)
222 | }
223 |
224 | // NewsProvider ...
225 | type NewsProvider struct {
226 | Code string
227 | Name string
228 | }
229 |
230 | func (np NewsProvider) String() string {
231 | return fmt.Sprintf("NewsProvider",
232 | np.Code,
233 | np.Name)
234 | }
235 |
236 | // HistogramData ...
237 | type HistogramData struct {
238 | Price float64
239 | Count int64
240 | }
241 |
242 | func (hgd HistogramData) String() string {
243 | return fmt.Sprintf("HistogramData",
244 | hgd.Price,
245 | hgd.Count)
246 | }
247 |
248 | // PriceIncrement ...
249 | type PriceIncrement struct {
250 | LowEdge float64
251 | Increment float64
252 | }
253 |
254 | func (p PriceIncrement) String() string {
255 | return fmt.Sprintf("PriceIncrement",
256 | p.LowEdge,
257 | p.Increment)
258 | }
259 |
260 | // HistoricalTick is the historical tick's description.
261 | // Used when requesting historical tick data with whatToShow = MIDPOINT
262 | type HistoricalTick struct {
263 | Time int64
264 | Price float64
265 | Size int64
266 | }
267 |
268 | func (h HistoricalTick) String() string {
269 | return fmt.Sprintf("Tick",
270 | h.Time,
271 | h.Price,
272 | h.Size)
273 | }
274 |
275 | // HistoricalTickBidAsk is the historical tick's description.
276 | // Used when requesting historical tick data with whatToShow = BID_ASK
277 | type HistoricalTickBidAsk struct {
278 | Time int64
279 | TickAttirbBidAsk TickAttribBidAsk
280 | PriceBid float64
281 | PriceAsk float64
282 | SizeBid int64
283 | SizeAsk int64
284 | }
285 |
286 | func (h HistoricalTickBidAsk) String() string {
287 | return fmt.Sprintf("TickBidAsk",
288 | h.Time,
289 | h.TickAttirbBidAsk,
290 | h.PriceBid,
291 | h.PriceAsk,
292 | h.SizeBid,
293 | h.SizeAsk)
294 | }
295 |
296 | // TickAttribBidAsk ...
297 | type TickAttribBidAsk struct {
298 | BidPastLow bool
299 | AskPastHigh bool
300 | }
301 |
302 | func (t TickAttribBidAsk) String() string {
303 | return fmt.Sprintf("TickAttribBidAsk",
304 | t.BidPastLow,
305 | t.AskPastHigh)
306 | }
307 |
308 | // HistoricalTickLast is the historical last tick's description.
309 | // Used when requesting historical tick data with whatToShow = TRADES
310 | type HistoricalTickLast struct {
311 | Time int64
312 | TickAttribLast TickAttribLast
313 | Price float64
314 | Size int64
315 | Exchange string
316 | SpecialConditions string
317 | }
318 |
319 | func (h HistoricalTickLast) String() string {
320 | return fmt.Sprintf("TickLast",
321 | h.Time,
322 | h.TickAttribLast,
323 | h.Price,
324 | h.Size,
325 | h.Exchange,
326 | h.SpecialConditions)
327 | }
328 |
329 | // TickAttribLast ...
330 | type TickAttribLast struct {
331 | PastLimit bool
332 | Unreported bool
333 | }
334 |
335 | func (t TickAttribLast) String() string {
336 | return fmt.Sprintf("TickAttribLast",
337 | t.PastLimit,
338 | t.Unreported)
339 | }
340 |
--------------------------------------------------------------------------------
/connection.go:
--------------------------------------------------------------------------------
1 | /* connection handle the tcp socket to the TWS or IB Gateway*/
2 |
3 | package ibapi
4 |
5 | import (
6 | "net"
7 | "strconv"
8 |
9 | "go.uber.org/zap"
10 | )
11 |
12 | // IbConnection wrap the tcp connection with TWS or Gateway
13 | type IbConnection struct {
14 | *net.TCPConn
15 | host string
16 | port int
17 | clientID int64
18 | state int
19 | numBytesSent int
20 | numMsgSent int
21 | numBytesRecv int
22 | numMsgRecv int
23 | }
24 |
25 | func (ibconn *IbConnection) Write(bs []byte) (int, error) {
26 | n, err := ibconn.TCPConn.Write(bs)
27 |
28 | ibconn.numBytesSent += n
29 | ibconn.numMsgSent++
30 |
31 | log.Debug("conn write", zap.Int("nBytes", n))
32 |
33 | return n, err
34 | }
35 |
36 | func (ibconn *IbConnection) Read(bs []byte) (int, error) {
37 | n, err := ibconn.TCPConn.Read(bs)
38 |
39 | ibconn.numBytesRecv += n
40 | ibconn.numMsgRecv++
41 |
42 | log.Debug("conn read", zap.Int("nBytes", n))
43 |
44 | return n, err
45 | }
46 |
47 | func (ibconn *IbConnection) setState(state int) {
48 | ibconn.state = state
49 | }
50 |
51 | func (ibconn *IbConnection) reset() {
52 | ibconn.numBytesSent = 0
53 | ibconn.numBytesRecv = 0
54 | ibconn.numMsgSent = 0
55 | ibconn.numMsgRecv = 0
56 | }
57 |
58 | func (ibconn *IbConnection) disconnect() error {
59 | log.Debug("conn disconnect",
60 | zap.Int("nMsgSent", ibconn.numMsgSent),
61 | zap.Int("nBytesSent", ibconn.numBytesSent),
62 | zap.Int("nMsgRecv", ibconn.numMsgRecv),
63 | zap.Int("nBytesRecv", ibconn.numBytesRecv),
64 | )
65 | return ibconn.Close()
66 | }
67 |
68 | func (ibconn *IbConnection) connect(host string, port int) error {
69 | var err error
70 | var addr *net.TCPAddr
71 | ibconn.host = host
72 | ibconn.port = port
73 | ibconn.reset()
74 |
75 | server := ibconn.host + ":" + strconv.Itoa(port)
76 | if addr, err = net.ResolveTCPAddr("tcp4", server); err != nil {
77 | log.Error("failed to resove tcp address", zap.Error(err), zap.String("host", server))
78 | return err
79 | }
80 |
81 | if ibconn.TCPConn, err = net.DialTCP("tcp4", nil, addr); err != nil {
82 | log.Error("failed to dial tcp", zap.Error(err), zap.Any("address", addr))
83 | return err
84 | }
85 |
86 | log.Debug("tcp socket connected", zap.Any("address", ibconn.TCPConn.RemoteAddr()))
87 |
88 | return err
89 | }
90 |
--------------------------------------------------------------------------------
/connection_test.go:
--------------------------------------------------------------------------------
1 | package ibapi
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "go.uber.org/zap"
8 | )
9 |
10 | func TestConnection(t *testing.T) {
11 | fmt.Println("connection testing!")
12 | conn := &IbConnection{}
13 | conn.connect("127.0.0.1", 4002)
14 | buf := make([]byte, 4096)
15 | _, err := conn.Read(buf)
16 | if err != nil {
17 | log.Panic("read error", zap.Error(err))
18 | }
19 | fmt.Println(string(buf))
20 | conn.disconnect()
21 | }
22 |
--------------------------------------------------------------------------------
/const.go:
--------------------------------------------------------------------------------
1 | package ibapi
2 |
3 | // IN identifies the msg type of the buf received from TWS or Gateway
4 | type IN = int64
5 |
6 | // OUT identifies the msg type of the buf sended to TWS or Gateway
7 | type OUT = int64
8 | type FiledType = int64
9 | type Version = int
10 |
11 | const (
12 | INT FiledType = 1
13 | STR FiledType = 2
14 | FLT FiledType = 3
15 | )
16 |
17 | const (
18 | mTICK_PRICE IN = 1
19 | mTICK_SIZE IN = 2
20 | mORDER_STATUS IN = 3
21 | mERR_MSG IN = 4
22 | mOPEN_ORDER IN = 5
23 | mACCT_VALUE IN = 6
24 | mPORTFOLIO_VALUE IN = 7
25 | mACCT_UPDATE_TIME IN = 8
26 | mNEXT_VALID_ID IN = 9
27 | mCONTRACT_DATA IN = 10
28 | mEXECUTION_DATA IN = 11
29 | mMARKET_DEPTH IN = 12
30 | mMARKET_DEPTH_L2 IN = 13
31 | mNEWS_BULLETINS IN = 14
32 | mMANAGED_ACCTS IN = 15
33 | mRECEIVE_FA IN = 16
34 | mHISTORICAL_DATA IN = 17
35 | mBOND_CONTRACT_DATA IN = 18
36 | mSCANNER_PARAMETERS IN = 19
37 | mSCANNER_DATA IN = 20
38 | mTICK_OPTION_COMPUTATION IN = 21
39 | mTICK_GENERIC IN = 45
40 | mTICK_STRING IN = 46
41 | mTICK_EFP IN = 47
42 | mCURRENT_TIME IN = 49
43 | mREAL_TIME_BARS IN = 50
44 | mFUNDAMENTAL_DATA IN = 51
45 | mCONTRACT_DATA_END IN = 52
46 | mOPEN_ORDER_END IN = 53
47 | mACCT_DOWNLOAD_END IN = 54
48 | mEXECUTION_DATA_END IN = 55
49 | mDELTA_NEUTRAL_VALIDATION IN = 56
50 | mTICK_SNAPSHOT_END IN = 57
51 | mMARKET_DATA_TYPE IN = 58
52 | mCOMMISSION_REPORT IN = 59
53 | mPOSITION_DATA IN = 61
54 | mPOSITION_END IN = 62
55 | mACCOUNT_SUMMARY IN = 63
56 | mACCOUNT_SUMMARY_END IN = 64
57 | mVERIFY_MESSAGE_API IN = 65
58 | mVERIFY_COMPLETED IN = 66
59 | mDISPLAY_GROUP_LIST IN = 67
60 | mDISPLAY_GROUP_UPDATED IN = 68
61 | mVERIFY_AND_AUTH_MESSAGE_API IN = 69
62 | mVERIFY_AND_AUTH_COMPLETED IN = 70
63 | mPOSITION_MULTI IN = 71
64 | mPOSITION_MULTI_END IN = 72
65 | mACCOUNT_UPDATE_MULTI IN = 73
66 | mACCOUNT_UPDATE_MULTI_END IN = 74
67 | mSECURITY_DEFINITION_OPTION_PARAMETER IN = 75
68 | mSECURITY_DEFINITION_OPTION_PARAMETER_END IN = 76
69 | mSOFT_DOLLAR_TIERS IN = 77
70 | mFAMILY_CODES IN = 78
71 | mSYMBOL_SAMPLES IN = 79
72 | mMKT_DEPTH_EXCHANGES IN = 80
73 | mTICK_REQ_PARAMS IN = 81
74 | mSMART_COMPONENTS IN = 82
75 | mNEWS_ARTICLE IN = 83
76 | mTICK_NEWS IN = 84
77 | mNEWS_PROVIDERS IN = 85
78 | mHISTORICAL_NEWS IN = 86
79 | mHISTORICAL_NEWS_END IN = 87
80 | mHEAD_TIMESTAMP IN = 88
81 | mHISTOGRAM_DATA IN = 89
82 | mHISTORICAL_DATA_UPDATE IN = 90
83 | mREROUTE_MKT_DATA_REQ IN = 91
84 | mREROUTE_MKT_DEPTH_REQ IN = 92
85 | mMARKET_RULE IN = 93
86 | mPNL IN = 94
87 | mPNL_SINGLE IN = 95
88 | mHISTORICAL_TICKS IN = 96
89 | mHISTORICAL_TICKS_BID_ASK IN = 97
90 | mHISTORICAL_TICKS_LAST IN = 98
91 | mTICK_BY_TICK IN = 99
92 | mORDER_BOUND IN = 100
93 | mCOMPLETED_ORDER IN = 101
94 | mCOMPLETED_ORDERS_END IN = 102
95 | mREPLACE_FA_END IN = 103
96 | mWSH_META_DATA IN = 104
97 | mWSH_EVENT_DATA IN = 105
98 | )
99 |
100 | const (
101 | mREQ_MKT_DATA OUT = 1
102 | mCANCEL_MKT_DATA OUT = 2
103 | mPLACE_ORDER OUT = 3
104 | mCANCEL_ORDER OUT = 4
105 | mREQ_OPEN_ORDERS OUT = 5
106 | mREQ_ACCT_DATA OUT = 6
107 | mREQ_EXECUTIONS OUT = 7
108 | mREQ_IDS OUT = 8
109 | mREQ_CONTRACT_DATA OUT = 9
110 | mREQ_MKT_DEPTH OUT = 10
111 | mCANCEL_MKT_DEPTH OUT = 11
112 | mREQ_NEWS_BULLETINS OUT = 12
113 | mCANCEL_NEWS_BULLETINS OUT = 13
114 | mSET_SERVER_LOGLEVEL OUT = 14
115 | mREQ_AUTO_OPEN_ORDERS OUT = 15
116 | mREQ_ALL_OPEN_ORDERS OUT = 16
117 | mREQ_MANAGED_ACCTS OUT = 17
118 | mREQ_FA OUT = 18
119 | mREPLACE_FA OUT = 19
120 | mREQ_HISTORICAL_DATA OUT = 20
121 | mEXERCISE_OPTIONS OUT = 21
122 | mREQ_SCANNER_SUBSCRIPTION OUT = 22
123 | mCANCEL_SCANNER_SUBSCRIPTION OUT = 23
124 | mREQ_SCANNER_PARAMETERS OUT = 24
125 | mCANCEL_HISTORICAL_DATA OUT = 25
126 | mREQ_CURRENT_TIME OUT = 49
127 | mREQ_REAL_TIME_BARS OUT = 50
128 | mCANCEL_REAL_TIME_BARS OUT = 51
129 | mREQ_FUNDAMENTAL_DATA OUT = 52
130 | mCANCEL_FUNDAMENTAL_DATA OUT = 53
131 | mREQ_CALC_IMPLIED_VOLAT OUT = 54
132 | mREQ_CALC_OPTION_PRICE OUT = 55
133 | mCANCEL_CALC_IMPLIED_VOLAT OUT = 56
134 | mCANCEL_CALC_OPTION_PRICE OUT = 57
135 | mREQ_GLOBAL_CANCEL OUT = 58
136 | mREQ_MARKET_DATA_TYPE OUT = 59
137 | mREQ_POSITIONS OUT = 61
138 | mREQ_ACCOUNT_SUMMARY OUT = 62
139 | mCANCEL_ACCOUNT_SUMMARY OUT = 63
140 | mCANCEL_POSITIONS OUT = 64
141 | mVERIFY_REQUEST OUT = 65
142 | mVERIFY_MESSAGE OUT = 66
143 | mQUERY_DISPLAY_GROUPS OUT = 67
144 | mSUBSCRIBE_TO_GROUP_EVENTS OUT = 68
145 | mUPDATE_DISPLAY_GROUP OUT = 69
146 | mUNSUBSCRIBE_FROM_GROUP_EVENTS OUT = 70
147 | mSTART_API OUT = 71
148 | mVERIFY_AND_AUTH_REQUEST OUT = 72
149 | mVERIFY_AND_AUTH_MESSAGE OUT = 73
150 | mREQ_POSITIONS_MULTI OUT = 74
151 | mCANCEL_POSITIONS_MULTI OUT = 75
152 | mREQ_ACCOUNT_UPDATES_MULTI OUT = 76
153 | mCANCEL_ACCOUNT_UPDATES_MULTI OUT = 77
154 | mREQ_SEC_DEF_OPT_PARAMS OUT = 78
155 | mREQ_SOFT_DOLLAR_TIERS OUT = 79
156 | mREQ_FAMILY_CODES OUT = 80
157 | mREQ_MATCHING_SYMBOLS OUT = 81
158 | mREQ_MKT_DEPTH_EXCHANGES OUT = 82
159 | mREQ_SMART_COMPONENTS OUT = 83
160 | mREQ_NEWS_ARTICLE OUT = 84
161 | mREQ_NEWS_PROVIDERS OUT = 85
162 | mREQ_HISTORICAL_NEWS OUT = 86
163 | mREQ_HEAD_TIMESTAMP OUT = 87
164 | mREQ_HISTOGRAM_DATA OUT = 88
165 | mCANCEL_HISTOGRAM_DATA OUT = 89
166 | mCANCEL_HEAD_TIMESTAMP OUT = 90
167 | mREQ_MARKET_RULE OUT = 91
168 | mREQ_PNL OUT = 92
169 | mCANCEL_PNL OUT = 93
170 | mREQ_PNL_SINGLE OUT = 94
171 | mCANCEL_PNL_SINGLE OUT = 95
172 | mREQ_HISTORICAL_TICKS OUT = 96
173 | mREQ_TICK_BY_TICK_DATA OUT = 97
174 | mCANCEL_TICK_BY_TICK_DATA OUT = 98
175 | mREQ_COMPLETED_ORDERS OUT = 99
176 | mREQ_WSH_META_DATA OUT = 100
177 | mCANCEL_WSH_META_DATA OUT = 101
178 | mREQ_WSH_EVENT_DATA OUT = 102
179 | mCANCEL_WSH_EVENT_DATA OUT = 103
180 | )
181 |
182 | const (
183 | // mMIN_SERVER_VER_REAL_TIME_BARS = 34
184 | // mMIN_SERVER_VER_SCALE_ORDERS = 35
185 | // mMIN_SERVER_VER_SNAPSHOT_MKT_DATA = 35
186 | // mMIN_SERVER_VER_SSHORT_COMBO_LEGS = 35
187 | // mMIN_SERVER_VER_WHAT_IF_ORDERS = 36
188 | // mMIN_SERVER_VER_CONTRACT_CONID = 37
189 | mMIN_SERVER_VER_PTA_ORDERS Version = 39
190 | mMIN_SERVER_VER_FUNDAMENTAL_DATA Version = 40
191 | mMIN_SERVER_VER_DELTA_NEUTRAL Version = 40
192 | mMIN_SERVER_VER_CONTRACT_DATA_CHAIN Version = 40
193 | mMIN_SERVER_VER_SCALE_ORDERS2 Version = 40
194 | mMIN_SERVER_VER_ALGO_ORDERS Version = 41
195 | mMIN_SERVER_VER_EXECUTION_DATA_CHAIN Version = 42
196 | mMIN_SERVER_VER_NOT_HELD Version = 44
197 | mMIN_SERVER_VER_SEC_ID_TYPE Version = 45
198 | mMIN_SERVER_VER_PLACE_ORDER_CONID Version = 46
199 | mMIN_SERVER_VER_REQ_MKT_DATA_CONID Version = 47
200 | mMIN_SERVER_VER_REQ_CALC_IMPLIED_VOLAT Version = 49
201 | mMIN_SERVER_VER_REQ_CALC_OPTION_PRICE Version = 50
202 | mMIN_SERVER_VER_SSHORTX_OLD Version = 51
203 | mMIN_SERVER_VER_SSHORTX Version = 52
204 | mMIN_SERVER_VER_REQ_GLOBAL_CANCEL Version = 53
205 | mMIN_SERVER_VER_HEDGE_ORDERS Version = 54
206 | mMIN_SERVER_VER_REQ_MARKET_DATA_TYPE Version = 55
207 | mMIN_SERVER_VER_OPT_OUT_SMART_ROUTING Version = 56
208 | mMIN_SERVER_VER_SMART_COMBO_ROUTING_PARAMS Version = 57
209 | mMIN_SERVER_VER_DELTA_NEUTRAL_CONID Version = 58
210 | mMIN_SERVER_VER_SCALE_ORDERS3 Version = 60
211 | mMIN_SERVER_VER_ORDER_COMBO_LEGS_PRICE Version = 61
212 | mMIN_SERVER_VER_TRAILING_PERCENT Version = 62
213 | mMIN_SERVER_VER_DELTA_NEUTRAL_OPEN_CLOSE Version = 66
214 | mMIN_SERVER_VER_POSITIONS Version = 67
215 | mMIN_SERVER_VER_ACCOUNT_SUMMARY Version = 67
216 | mMIN_SERVER_VER_TRADING_CLASS Version = 68
217 | mMIN_SERVER_VER_SCALE_TABLE Version = 69
218 | mMIN_SERVER_VER_LINKING Version = 70
219 | mMIN_SERVER_VER_ALGO_ID Version = 71
220 | mMIN_SERVER_VER_OPTIONAL_CAPABILITIES Version = 72
221 | mMIN_SERVER_VER_ORDER_SOLICITED Version = 73
222 | mMIN_SERVER_VER_LINKING_AUTH Version = 74
223 | mMIN_SERVER_VER_PRIMARYEXCH Version = 75
224 | mMIN_SERVER_VER_RANDOMIZE_SIZE_AND_PRICE Version = 76
225 | mMIN_SERVER_VER_FRACTIONAL_POSITIONS Version = 101
226 | mMIN_SERVER_VER_PEGGED_TO_BENCHMARK Version = 102
227 | mMIN_SERVER_VER_MODELS_SUPPORT Version = 103
228 | mMIN_SERVER_VER_SEC_DEF_OPT_PARAMS_REQ Version = 104
229 | mMIN_SERVER_VER_EXT_OPERATOR Version = 105
230 | mMIN_SERVER_VER_SOFT_DOLLAR_TIER Version = 106
231 | mMIN_SERVER_VER_REQ_FAMILY_CODES Version = 107
232 | mMIN_SERVER_VER_REQ_MATCHING_SYMBOLS Version = 108
233 | mMIN_SERVER_VER_PAST_LIMIT Version = 109
234 | mMIN_SERVER_VER_MD_SIZE_MULTIPLIER Version = 110
235 | mMIN_SERVER_VER_CASH_QTY Version = 111
236 | mMIN_SERVER_VER_REQ_MKT_DEPTH_EXCHANGES Version = 112
237 | mMIN_SERVER_VER_TICK_NEWS Version = 113
238 | mMIN_SERVER_VER_REQ_SMART_COMPONENTS Version = 114
239 | mMIN_SERVER_VER_REQ_NEWS_PROVIDERS Version = 115
240 | mMIN_SERVER_VER_REQ_NEWS_ARTICLE Version = 116
241 | mMIN_SERVER_VER_REQ_HISTORICAL_NEWS Version = 117
242 | mMIN_SERVER_VER_REQ_HEAD_TIMESTAMP Version = 118
243 | mMIN_SERVER_VER_REQ_HISTOGRAM Version = 119
244 | mMIN_SERVER_VER_SERVICE_DATA_TYPE Version = 120
245 | mMIN_SERVER_VER_AGG_GROUP Version = 121
246 | mMIN_SERVER_VER_UNDERLYING_INFO Version = 122
247 | mMIN_SERVER_VER_CANCEL_HEADTIMESTAMP Version = 123
248 | mMIN_SERVER_VER_SYNT_REALTIME_BARS Version = 124
249 | mMIN_SERVER_VER_CFD_REROUTE Version = 125
250 | mMIN_SERVER_VER_MARKET_RULES Version = 126
251 | mMIN_SERVER_VER_PNL Version = 127
252 | mMIN_SERVER_VER_NEWS_QUERY_ORIGINS Version = 128
253 | mMIN_SERVER_VER_UNREALIZED_PNL Version = 129
254 | mMIN_SERVER_VER_HISTORICAL_TICKS Version = 130
255 | mMIN_SERVER_VER_MARKET_CAP_PRICE Version = 131
256 | mMIN_SERVER_VER_PRE_OPEN_BID_ASK Version = 132
257 | mMIN_SERVER_VER_REAL_EXPIRATION_DATE Version = 134
258 | mMIN_SERVER_VER_REALIZED_PNL Version = 135
259 | mMIN_SERVER_VER_LAST_LIQUIDITY Version = 136
260 | mMIN_SERVER_VER_TICK_BY_TICK Version = 137
261 | mMIN_SERVER_VER_DECISION_MAKER Version = 138
262 | mMIN_SERVER_VER_MIFID_EXECUTION Version = 139
263 | mMIN_SERVER_VER_TICK_BY_TICK_IGNORE_SIZE Version = 140
264 | mMIN_SERVER_VER_AUTO_PRICE_FOR_HEDGE Version = 141
265 | mMIN_SERVER_VER_WHAT_IF_EXT_FIELDS Version = 142
266 | mMIN_SERVER_VER_SCANNER_GENERIC_OPTS Version = 143
267 | mMIN_SERVER_VER_API_BIND_ORDER Version = 144
268 | mMIN_SERVER_VER_ORDER_CONTAINER Version = 145
269 | mMIN_SERVER_VER_SMART_DEPTH Version = 146
270 | mMIN_SERVER_VER_REMOVE_NULL_ALL_CASTING Version = 147
271 | mMIN_SERVER_VER_D_PEG_ORDERS Version = 148
272 | mMIN_SERVER_VER_MKT_DEPTH_PRIM_EXCHANGE Version = 149
273 | mMIN_SERVER_VER_COMPLETED_ORDERS Version = 150
274 | mMIN_SERVER_VER_PRICE_MGMT_ALGO Version = 151
275 | mMIN_SERVER_VER_STOCK_TYPE Version = 152
276 | mMIN_SERVER_VER_ENCODE_MSG_ASCII7 Version = 153
277 | mMIN_SERVER_VER_SEND_ALL_FAMILY_CODES Version = 154
278 | mMIN_SERVER_VER_NO_DEFAULT_OPEN_CLOSE Version = 155
279 | mMIN_SERVER_VER_PRICE_BASED_VOLATILITY Version = 156
280 | mMIN_SERVER_VER_REPLACE_FA_END Version = 157
281 | mMIN_SERVER_VER_DURATION Version = 158
282 | mMIN_SERVER_VER_MARKET_DATA_IN_SHARES Version = 159
283 | mMIN_SERVER_VER_POST_TO_ATS Version = 160
284 | mMIN_SERVER_VER_WSHE_CALENDAR Version = 161
285 |
286 | MIN_CLIENT_VER Version = 100
287 | MAX_CLIENT_VER Version = mMIN_SERVER_VER_WSHE_CALENDAR
288 | )
289 |
290 | // tick const
291 | const (
292 | BID_SIZE = iota
293 | BID
294 | ASK
295 | ASK_SIZE
296 | LAST
297 | LAST_SIZE
298 | HIGH
299 | LOW
300 | VOLUME
301 | CLOSE
302 | BID_OPTION_COMPUTATION
303 | ASK_OPTION_COMPUTATION
304 | LAST_OPTION_COMPUTATION
305 | MODEL_OPTION
306 | OPEN
307 | LOW_13_WEEK
308 | HIGH_13_WEEK
309 | LOW_26_WEEK
310 | HIGH_26_WEEK
311 | LOW_52_WEEK
312 | HIGH_52_WEEK
313 | AVG_VOLUME
314 | OPEN_INTEREST
315 | OPTION_HISTORICAL_VOL
316 | OPTION_IMPLIED_VOL
317 | OPTION_BID_EXCH
318 | OPTION_ASK_EXCH
319 | OPTION_CALL_OPEN_INTEREST
320 | OPTION_PUT_OPEN_INTEREST
321 | OPTION_CALL_VOLUME
322 | OPTION_PUT_VOLUME
323 | INDEX_FUTURE_PREMIUM
324 | BID_EXCH
325 | ASK_EXCH
326 | AUCTION_VOLUME
327 | AUCTION_PRICE
328 | AUCTION_IMBALANCE
329 | MARK_PRICE
330 | BID_EFP_COMPUTATION
331 | ASK_EFP_COMPUTATION
332 | LAST_EFP_COMPUTATION
333 | OPEN_EFP_COMPUTATION
334 | HIGH_EFP_COMPUTATION
335 | LOW_EFP_COMPUTATION
336 | CLOSE_EFP_COMPUTATION
337 | LAST_TIMESTAMP
338 | SHORTABLE
339 | FUNDAMENTAL_RATIOS
340 | RT_VOLUME
341 | HALTED
342 | BID_YIELD
343 | ASK_YIELD
344 | LAST_YIELD
345 | CUST_OPTION_COMPUTATION
346 | TRADE_COUNT
347 | TRADE_RATE
348 | VOLUME_RATE
349 | LAST_RTH_TRADE
350 | RT_HISTORICAL_VOL
351 | IB_DIVIDENDS
352 | BOND_FACTOR_MULTIPLIER
353 | REGULATORY_IMBALANCE
354 | NEWS_TICK
355 | SHORT_TERM_VOLUME_3_MIN
356 | SHORT_TERM_VOLUME_5_MIN
357 | SHORT_TERM_VOLUME_10_MIN
358 | DELAYED_BID
359 | DELAYED_ASK
360 | DELAYED_LAST
361 | DELAYED_BID_SIZE
362 | DELAYED_ASK_SIZE
363 | DELAYED_LAST_SIZE
364 | DELAYED_HIGH
365 | DELAYED_LOW
366 | DELAYED_VOLUME
367 | DELAYED_CLOSE
368 | DELAYED_OPEN
369 | RT_TRD_VOLUME
370 | CREDITMAN_MARK_PRICE
371 | CREDITMAN_SLOW_MARK_PRICE
372 | DELAYED_BID_OPTION
373 | DELAYED_ASK_OPTION
374 | DELAYED_LAST_OPTION
375 | DELAYED_MODEL_OPTION
376 | LAST_EXCH
377 | LAST_REG_TIME
378 | FUTURES_OPEN_INTEREST
379 | AVG_OPT_VOLUME
380 | DELAYED_LAST_TIMESTAMP
381 | SHORTABLE_SHARES
382 | NOT_SET
383 | )
384 |
385 | // ConnectionState
386 | const (
387 | DISCONNECTED = iota
388 | CONNECTING
389 | CONNECTED
390 | REDIRECT
391 | )
392 |
--------------------------------------------------------------------------------
/contract.go:
--------------------------------------------------------------------------------
1 | package ibapi
2 |
3 | import "fmt"
4 |
5 | //Contract describes an instrument's definition
6 | type Contract struct {
7 | ContractID int64
8 | Symbol string
9 | SecurityType string
10 | Expiry string
11 | Strike float64
12 | Right string
13 | Multiplier string
14 | Exchange string
15 | Currency string
16 | LocalSymbol string
17 | TradingClass string
18 | PrimaryExchange string // pick an actual (ie non-aggregate) exchange that the contract trades on. DO NOT SET TO SMART.
19 | IncludeExpired bool
20 | SecurityIDType string // CUSIP;SEDOL;ISIN;RIC
21 | SecurityID string
22 |
23 | // combos les
24 | ComboLegsDescription string
25 | ComboLegs []ComboLeg
26 | // UnderComp *UnderComp
27 |
28 | DeltaNeutralContract *DeltaNeutralContract
29 | }
30 |
31 | func (c Contract) String() string {
32 | basicStr := fmt.Sprintf("Contract", c.Expiry, c.Multiplier, c.SecurityID, c.SecurityIDType)
42 | case "OPT":
43 | basicStr += fmt.Sprintf(", Expiry: %s, Strike: %f, Right: %s, SecurityID: %s, SecurityIDType: %s>", c.Expiry, c.Strike, c.Right, c.SecurityID, c.SecurityIDType)
44 | default:
45 | basicStr += fmt.Sprint(">")
46 | }
47 |
48 | for i, leg := range c.ComboLegs {
49 | basicStr += fmt.Sprintf("-Leg<%d>: %s", i, leg)
50 | }
51 |
52 | if c.DeltaNeutralContract != nil {
53 | basicStr += fmt.Sprintf("-%s", c.DeltaNeutralContract)
54 | }
55 |
56 | return basicStr
57 | }
58 |
59 | // DeltaNeutralContract is Delta-Neutral Contract
60 | type DeltaNeutralContract struct {
61 | ContractID int64
62 | Delta float64
63 | Price float64
64 | }
65 |
66 | func (c DeltaNeutralContract) String() string {
67 | return fmt.Sprintf("DeltaNeutralContract",
68 | c.ContractID,
69 | c.Delta,
70 | c.Price)
71 | }
72 |
73 | // ContractDetails contain a Contract and other details about this contract, can be request by ReqContractDetails
74 | type ContractDetails struct {
75 | Contract Contract
76 | MarketName string
77 | MinTick float64
78 | OrderTypes string
79 | ValidExchanges string
80 | PriceMagnifier int64
81 |
82 | UnderContractID int64
83 | LongName string
84 | ContractMonth string
85 | Industry string
86 | Category string
87 | Subcategory string
88 | TimezoneID string
89 | TradingHours string
90 | LiquidHours string
91 | EVRule string
92 | EVMultiplier int64
93 | MdSizeMultiplier int64
94 | AggGroup int64
95 | UnderSymbol string
96 | UnderSecurityType string
97 | MarketRuleIDs string
98 | SecurityIDList []TagValue
99 | RealExpirationDate string
100 | LastTradeTime string
101 | StockType string
102 |
103 | // BOND values
104 | Cusip string
105 | Ratings string
106 | DescAppend string
107 | BondType string
108 | CouponType string
109 | Callable bool
110 | Putable bool
111 | Coupon int64
112 | Convertible bool
113 | Maturity string
114 | IssueDate string
115 | NextOptionDate string
116 | NextOptionType string
117 | NextOptionPartial bool
118 | Notes string
119 | }
120 |
121 | func (c ContractDetails) String() string {
122 | return fmt.Sprintf("ContractDetails", c.Contract, c.MarketName, c.UnderContractID, c.LongName)
123 | }
124 |
125 | // ContractDescription includes contract and DerivativeSecTypes
126 | type ContractDescription struct {
127 | Contract Contract
128 | DerivativeSecTypes []string
129 | }
130 |
131 | // NewComboLeg create a default comboleg
132 | func NewComboLeg() ComboLeg {
133 | comboLeg := ComboLeg{}
134 | comboLeg.ExemptCode = -1
135 | return comboLeg
136 | }
137 |
--------------------------------------------------------------------------------
/decoder.go:
--------------------------------------------------------------------------------
1 | package ibapi
2 |
3 | import (
4 | "strings"
5 | "time"
6 |
7 | "go.uber.org/zap"
8 | )
9 |
10 | const (
11 | TIME_FORMAT string = "2006-01-02 15:04:05 +0700 CST"
12 | )
13 |
14 | // ibDecoder help to decode the msg bytes received from TWS or Gateway
15 | type ibDecoder struct {
16 | wrapper IbWrapper
17 | version Version
18 | msgID2process map[IN]func(*MsgBuffer)
19 | // errChan chan error
20 | }
21 |
22 | func (d *ibDecoder) setVersion(version Version) {
23 | d.version = version
24 | }
25 |
26 | func (d *ibDecoder) setWrapper(w IbWrapper) {
27 | d.wrapper = w
28 | }
29 |
30 | func (d *ibDecoder) interpret(msgBytes []byte) {
31 | msgBuf := NewMsgBuffer(msgBytes)
32 | if msgBuf.Len() == 0 {
33 | log.Debug("no fields")
34 | return
35 | }
36 |
37 | // try not to handle the error produced by decoder and wrapper, user should be responsible for this
38 | // // if decode error ocours,handle the error
39 | // defer func() {
40 | // if err := recover(); err != nil {
41 | // log.Error("failed to decode", zap.Error(err.(error)))
42 | // d.errChan <- err.(error)
43 | // }
44 | // }()
45 |
46 | // log.Debug("interpret", zap.Binary("MsgBytes", msgBuf.Bytes()))
47 |
48 | // read the msg type
49 | MsgID := msgBuf.readInt()
50 | if processer, ok := d.msgID2process[MsgID]; ok {
51 | processer(msgBuf)
52 | } else {
53 | log.Warn("msg ID not found!!!", zap.Int64("msgID", MsgID), zap.Binary("MsgBytes", msgBuf.Bytes()))
54 | }
55 |
56 | }
57 |
58 | // func (d *ibDecoder) interpretWithSignature(fs [][]byte, processer interface{}) {
59 | // if processer == nil {
60 | // fmt.Println("No processer")
61 | // }
62 |
63 | // processerType := reflect.TypeOf(processer)
64 | // params := make([]interface{}, processerType.NumIn())
65 | // for i, f := range fs[1:] {
66 | // switch processerType.In(i).Kind() {
67 | // case reflect.Int:
68 | // param := strconv.Atoi(string(f))
69 | // case reflect.Float64:
70 | // param, _ := strconv.ParseFloat(string(f), 64)
71 | // default:
72 | // param := string(f)
73 | // }
74 | // params = append(params, param)
75 |
76 | // }
77 |
78 | // processer(params...)
79 | // }
80 |
81 | func (d *ibDecoder) setmsgID2process() {
82 | d.msgID2process = map[IN]func(*MsgBuffer){
83 | mTICK_PRICE: d.processTickPriceMsg,
84 | mTICK_SIZE: d.wrapTickSize,
85 | mORDER_STATUS: d.processOrderStatusMsg,
86 | mERR_MSG: d.wrapError,
87 | mOPEN_ORDER: d.processOpenOrder,
88 | mACCT_VALUE: d.wrapUpdateAccountValue,
89 | mPORTFOLIO_VALUE: d.processPortfolioValueMsg,
90 | mACCT_UPDATE_TIME: d.wrapUpdateAccountTime,
91 | mNEXT_VALID_ID: d.wrapNextValidID,
92 | mCONTRACT_DATA: d.processContractDataMsg,
93 | mEXECUTION_DATA: d.processExecutionDataMsg,
94 | mMARKET_DEPTH: d.wrapUpdateMktDepth,
95 | mMARKET_DEPTH_L2: d.wrapUpdateMktDepthL2,
96 | mNEWS_BULLETINS: d.wrapUpdateNewsBulletin,
97 | mMANAGED_ACCTS: d.wrapManagedAccounts,
98 | mRECEIVE_FA: d.wrapReceiveFA,
99 | mHISTORICAL_DATA: d.processHistoricalDataMsg,
100 | mHISTORICAL_DATA_UPDATE: d.processHistoricalDataUpdateMsg,
101 | mBOND_CONTRACT_DATA: d.processBondContractDataMsg,
102 | mSCANNER_PARAMETERS: d.wrapScannerParameters,
103 | mSCANNER_DATA: d.processScannerDataMsg,
104 | mTICK_OPTION_COMPUTATION: d.processTickOptionComputationMsg,
105 | mTICK_GENERIC: d.wrapTickGeneric,
106 | mTICK_STRING: d.wrapTickString,
107 | mTICK_EFP: d.wrapTickEFP,
108 | mCURRENT_TIME: d.wrapCurrentTime,
109 | mREAL_TIME_BARS: d.processRealTimeBarMsg,
110 | mFUNDAMENTAL_DATA: d.wrapFundamentalData,
111 | mCONTRACT_DATA_END: d.wrapContractDetailsEnd,
112 |
113 | mACCT_DOWNLOAD_END: d.wrapAccountDownloadEnd,
114 | mOPEN_ORDER_END: d.wrapOpenOrderEnd,
115 | mEXECUTION_DATA_END: d.wrapExecDetailsEnd,
116 | mDELTA_NEUTRAL_VALIDATION: d.processDeltaNeutralValidationMsg,
117 | mTICK_SNAPSHOT_END: d.wrapTickSnapshotEnd,
118 | mMARKET_DATA_TYPE: d.wrapMarketDataType,
119 | mCOMMISSION_REPORT: d.processCommissionReportMsg,
120 | mPOSITION_DATA: d.processPositionDataMsg,
121 | mPOSITION_END: d.wrapPositionEnd,
122 | mACCOUNT_SUMMARY: d.wrapAccountSummary,
123 | mACCOUNT_SUMMARY_END: d.wrapAccountSummaryEnd,
124 | mVERIFY_MESSAGE_API: d.wrapVerifyMessageAPI,
125 | mVERIFY_COMPLETED: d.wrapVerifyCompleted,
126 | mDISPLAY_GROUP_LIST: d.wrapDisplayGroupList,
127 | mDISPLAY_GROUP_UPDATED: d.wrapDisplayGroupUpdated,
128 | mVERIFY_AND_AUTH_MESSAGE_API: d.wrapVerifyAndAuthMessageAPI,
129 | mVERIFY_AND_AUTH_COMPLETED: d.wrapVerifyAndAuthCompleted,
130 | mPOSITION_MULTI: d.processPositionMultiMsg,
131 | mPOSITION_MULTI_END: d.wrapPositionMultiEnd,
132 | mACCOUNT_UPDATE_MULTI: d.wrapAccountUpdateMulti,
133 | mACCOUNT_UPDATE_MULTI_END: d.wrapAccountUpdateMultiEnd,
134 | mSECURITY_DEFINITION_OPTION_PARAMETER: d.processSecurityDefinitionOptionParameterMsg,
135 | mSECURITY_DEFINITION_OPTION_PARAMETER_END: d.wrapSecurityDefinitionOptionParameterEndMsg,
136 | mSOFT_DOLLAR_TIERS: d.processSoftDollarTiersMsg,
137 | mFAMILY_CODES: d.processFamilyCodesMsg,
138 | mSYMBOL_SAMPLES: d.processSymbolSamplesMsg,
139 | mSMART_COMPONENTS: d.processSmartComponents,
140 | mTICK_REQ_PARAMS: d.processTickReqParams,
141 | mMKT_DEPTH_EXCHANGES: d.processMktDepthExchanges,
142 | mHEAD_TIMESTAMP: d.processHeadTimestamp,
143 | mTICK_NEWS: d.processTickNews,
144 | mNEWS_PROVIDERS: d.processNewsProviders,
145 | mNEWS_ARTICLE: d.processNewsArticle,
146 | mHISTORICAL_NEWS: d.processHistoricalNews,
147 | mHISTORICAL_NEWS_END: d.processHistoricalNewsEnd,
148 | mHISTOGRAM_DATA: d.processHistogramData,
149 | mREROUTE_MKT_DATA_REQ: d.processRerouteMktDataReq,
150 | mREROUTE_MKT_DEPTH_REQ: d.processRerouteMktDepthReq,
151 | mMARKET_RULE: d.processMarketRuleMsg,
152 | mPNL: d.processPnLMsg,
153 | mPNL_SINGLE: d.processPnLSingleMsg,
154 | mHISTORICAL_TICKS: d.processHistoricalTicks,
155 | mHISTORICAL_TICKS_BID_ASK: d.processHistoricalTicksBidAsk,
156 | mHISTORICAL_TICKS_LAST: d.processHistoricalTicksLast,
157 | mTICK_BY_TICK: d.processTickByTickMsg,
158 | mORDER_BOUND: d.processOrderBoundMsg,
159 | mCOMPLETED_ORDER: d.processCompletedOrderMsg,
160 | mCOMPLETED_ORDERS_END: d.processCompletedOrdersEndMsg,
161 | mREPLACE_FA_END: d.processReplaceFAEndMsg,
162 | mWSH_META_DATA: d.processWshMetaDataMsg,
163 | mWSH_EVENT_DATA: d.processWshEventDataMsg,
164 | }
165 | }
166 |
167 | func (d *ibDecoder) wrapTickSize(msgBuf *MsgBuffer) {
168 | _ = msgBuf.readString()
169 | reqID := msgBuf.readInt()
170 | tickType := msgBuf.readInt()
171 | size := msgBuf.readInt()
172 | d.wrapper.TickSize(reqID, tickType, size)
173 | }
174 |
175 | func (d *ibDecoder) wrapNextValidID(msgBuf *MsgBuffer) {
176 | _ = msgBuf.readString()
177 | reqID := msgBuf.readInt()
178 | d.wrapper.NextValidID(reqID)
179 |
180 | }
181 |
182 | func (d *ibDecoder) wrapManagedAccounts(msgBuf *MsgBuffer) {
183 | _ = msgBuf.readString()
184 | accNames := msgBuf.readString()
185 | accsList := strings.Split(accNames, ",")
186 | d.wrapper.ManagedAccounts(accsList)
187 |
188 | }
189 |
190 | func (d *ibDecoder) wrapUpdateAccountValue(msgBuf *MsgBuffer) {
191 | _ = msgBuf.readString()
192 | tag := msgBuf.readString()
193 | val := msgBuf.readString()
194 | currency := msgBuf.readString()
195 | accName := msgBuf.readString()
196 |
197 | d.wrapper.UpdateAccountValue(tag, val, currency, accName)
198 | }
199 |
200 | func (d *ibDecoder) wrapUpdateAccountTime(msgBuf *MsgBuffer) {
201 | _ = msgBuf.readString()
202 | ts := msgBuf.readString()
203 | today := time.Now()
204 | // time.
205 | t, err := time.ParseInLocation("04:05", ts, time.Local)
206 | if err != nil {
207 | log.Panic("failed to parse account time", zap.Error(err))
208 | }
209 | t = t.AddDate(today.Year(), int(today.Month())-1, today.Day()-1)
210 |
211 | d.wrapper.UpdateAccountTime(t)
212 | }
213 |
214 | func (d *ibDecoder) wrapError(msgBuf *MsgBuffer) {
215 | _ = msgBuf.readString()
216 | reqID := msgBuf.readInt()
217 | errorCode := msgBuf.readInt()
218 | errorString := msgBuf.readString()
219 |
220 | d.wrapper.Error(reqID, errorCode, errorString)
221 | }
222 |
223 | func (d *ibDecoder) wrapCurrentTime(msgBuf *MsgBuffer) {
224 | _ = msgBuf.readString()
225 | ts := msgBuf.readInt()
226 | t := time.Unix(ts, 0)
227 |
228 | d.wrapper.CurrentTime(t)
229 | }
230 |
231 | func (d *ibDecoder) wrapUpdateMktDepth(msgBuf *MsgBuffer) {
232 | _ = msgBuf.readString()
233 | reqID := msgBuf.readInt()
234 | position := msgBuf.readInt()
235 | operation := msgBuf.readInt()
236 | side := msgBuf.readInt()
237 | price := msgBuf.readFloat()
238 | size := msgBuf.readInt()
239 |
240 | d.wrapper.UpdateMktDepth(reqID, position, operation, side, price, size)
241 |
242 | }
243 |
244 | func (d *ibDecoder) wrapUpdateMktDepthL2(msgBuf *MsgBuffer) {
245 | _ = msgBuf.readString()
246 | reqID := msgBuf.readInt()
247 | position := msgBuf.readInt()
248 | marketMaker := msgBuf.readString()
249 | operation := msgBuf.readInt()
250 | side := msgBuf.readInt()
251 | price := msgBuf.readFloat()
252 | size := msgBuf.readInt()
253 | isSmartDepth := msgBuf.readBool()
254 |
255 | d.wrapper.UpdateMktDepthL2(reqID, position, marketMaker, operation, side, price, size, isSmartDepth)
256 |
257 | }
258 |
259 | func (d *ibDecoder) wrapUpdateNewsBulletin(msgBuf *MsgBuffer) {
260 | _ = msgBuf.readString()
261 | msgID := msgBuf.readInt()
262 | msgType := msgBuf.readInt()
263 | newsMessage := msgBuf.readString()
264 | originExch := msgBuf.readString()
265 |
266 | d.wrapper.UpdateNewsBulletin(msgID, msgType, newsMessage, originExch)
267 | }
268 |
269 | func (d *ibDecoder) wrapReceiveFA(msgBuf *MsgBuffer) {
270 | _ = msgBuf.readString()
271 | faData := msgBuf.readInt()
272 | cxml := msgBuf.readString()
273 |
274 | d.wrapper.ReceiveFA(faData, cxml)
275 | }
276 |
277 | func (d *ibDecoder) wrapScannerParameters(msgBuf *MsgBuffer) {
278 | _ = msgBuf.readString()
279 | xml := msgBuf.readString()
280 |
281 | d.wrapper.ScannerParameters(xml)
282 | }
283 |
284 | func (d *ibDecoder) wrapTickGeneric(msgBuf *MsgBuffer) {
285 | _ = msgBuf.readString()
286 | reqID := msgBuf.readInt()
287 | tickType := msgBuf.readInt()
288 | value := msgBuf.readFloat()
289 |
290 | d.wrapper.TickGeneric(reqID, tickType, value)
291 |
292 | }
293 |
294 | func (d *ibDecoder) wrapTickString(msgBuf *MsgBuffer) {
295 | _ = msgBuf.readString()
296 | reqID := msgBuf.readInt()
297 | tickType := msgBuf.readInt()
298 | value := msgBuf.readString()
299 |
300 | d.wrapper.TickString(reqID, tickType, value)
301 |
302 | }
303 |
304 | func (d *ibDecoder) wrapTickEFP(msgBuf *MsgBuffer) {
305 | _ = msgBuf.readString()
306 | reqID := msgBuf.readInt()
307 | tickType := msgBuf.readInt()
308 | basisPoints := msgBuf.readFloat()
309 | formattedBasisPoints := msgBuf.readString()
310 | totalDividends := msgBuf.readFloat()
311 | holdDays := msgBuf.readInt()
312 | futureLastTradeDate := msgBuf.readString()
313 | dividendImpact := msgBuf.readFloat()
314 | dividendsToLastTradeDate := msgBuf.readFloat()
315 |
316 | d.wrapper.TickEFP(reqID, tickType, basisPoints, formattedBasisPoints, totalDividends, holdDays, futureLastTradeDate, dividendImpact, dividendsToLastTradeDate)
317 |
318 | }
319 |
320 | func (d *ibDecoder) wrapMarketDataType(msgBuf *MsgBuffer) {
321 | _ = msgBuf.readString()
322 | reqID := msgBuf.readInt()
323 | marketDataType := msgBuf.readInt()
324 |
325 | d.wrapper.MarketDataType(reqID, marketDataType)
326 | }
327 |
328 | func (d *ibDecoder) wrapAccountSummary(msgBuf *MsgBuffer) {
329 | _ = msgBuf.readString()
330 | reqID := msgBuf.readInt()
331 | account := msgBuf.readString()
332 | tag := msgBuf.readString()
333 | value := msgBuf.readString()
334 | currency := msgBuf.readString()
335 |
336 | d.wrapper.AccountSummary(reqID, account, tag, value, currency)
337 | }
338 |
339 | func (d *ibDecoder) wrapVerifyMessageAPI(msgBuf *MsgBuffer) {
340 | // Deprecated Function: keep it temporarily, not know how it works
341 | _ = msgBuf.readString()
342 | apiData := msgBuf.readString()
343 |
344 | d.wrapper.VerifyMessageAPI(apiData)
345 | }
346 |
347 | func (d *ibDecoder) wrapVerifyCompleted(msgBuf *MsgBuffer) {
348 | _ = msgBuf.readString()
349 | isSuccessful := msgBuf.readBool()
350 | err := msgBuf.readString()
351 |
352 | d.wrapper.VerifyCompleted(isSuccessful, err)
353 | }
354 |
355 | func (d *ibDecoder) wrapDisplayGroupList(msgBuf *MsgBuffer) {
356 | _ = msgBuf.readString()
357 | reqID := msgBuf.readInt()
358 | groups := msgBuf.readString()
359 |
360 | d.wrapper.DisplayGroupList(reqID, groups)
361 | }
362 |
363 | func (d *ibDecoder) wrapDisplayGroupUpdated(msgBuf *MsgBuffer) {
364 | _ = msgBuf.readString()
365 | reqID := msgBuf.readInt()
366 | contractInfo := msgBuf.readString()
367 |
368 | d.wrapper.DisplayGroupUpdated(reqID, contractInfo)
369 | }
370 |
371 | func (d *ibDecoder) wrapVerifyAndAuthMessageAPI(msgBuf *MsgBuffer) {
372 | _ = msgBuf.readString()
373 | apiData := msgBuf.readString()
374 | xyzChallange := msgBuf.readString()
375 |
376 | d.wrapper.VerifyAndAuthMessageAPI(apiData, xyzChallange)
377 | }
378 |
379 | func (d *ibDecoder) wrapVerifyAndAuthCompleted(msgBuf *MsgBuffer) {
380 | _ = msgBuf.readString()
381 | isSuccessful := msgBuf.readBool()
382 | err := msgBuf.readString()
383 |
384 | d.wrapper.VerifyAndAuthCompleted(isSuccessful, err)
385 | }
386 |
387 | func (d *ibDecoder) wrapAccountUpdateMulti(msgBuf *MsgBuffer) {
388 | _ = msgBuf.readString()
389 | reqID := msgBuf.readInt()
390 | acc := msgBuf.readString()
391 | modelCode := msgBuf.readString()
392 | tag := msgBuf.readString()
393 | val := msgBuf.readString()
394 | currency := msgBuf.readString()
395 |
396 | d.wrapper.AccountUpdateMulti(reqID, acc, modelCode, tag, val, currency)
397 | }
398 |
399 | func (d *ibDecoder) wrapFundamentalData(msgBuf *MsgBuffer) {
400 | _ = msgBuf.readString()
401 | reqID := msgBuf.readInt()
402 | data := msgBuf.readString()
403 |
404 | d.wrapper.FundamentalData(reqID, data)
405 | }
406 |
407 | //--------------wrap end func ---------------------------------
408 |
409 | func (d *ibDecoder) wrapAccountDownloadEnd(msgBuf *MsgBuffer) {
410 | _ = msgBuf.readString()
411 | accName := msgBuf.readString()
412 |
413 | d.wrapper.AccountDownloadEnd(accName)
414 | }
415 |
416 | func (d *ibDecoder) wrapOpenOrderEnd(msgBuf *MsgBuffer) {
417 |
418 | d.wrapper.OpenOrderEnd()
419 | }
420 |
421 | func (d *ibDecoder) wrapExecDetailsEnd(msgBuf *MsgBuffer) {
422 | _ = msgBuf.readString()
423 | reqID := msgBuf.readInt()
424 |
425 | d.wrapper.ExecDetailsEnd(reqID)
426 | }
427 |
428 | func (d *ibDecoder) wrapTickSnapshotEnd(msgBuf *MsgBuffer) {
429 | _ = msgBuf.readString()
430 | reqID := msgBuf.readInt()
431 |
432 | d.wrapper.TickSnapshotEnd(reqID)
433 | }
434 |
435 | func (d *ibDecoder) wrapPositionEnd(msgBuf *MsgBuffer) {
436 |
437 | d.wrapper.PositionEnd()
438 | }
439 |
440 | func (d *ibDecoder) wrapAccountSummaryEnd(msgBuf *MsgBuffer) {
441 | _ = msgBuf.readString()
442 | reqID := msgBuf.readInt()
443 |
444 | d.wrapper.AccountSummaryEnd(reqID)
445 | }
446 |
447 | func (d *ibDecoder) wrapPositionMultiEnd(msgBuf *MsgBuffer) {
448 | _ = msgBuf.readString()
449 | reqID := msgBuf.readInt()
450 |
451 | d.wrapper.PositionMultiEnd(reqID)
452 | }
453 |
454 | func (d *ibDecoder) wrapAccountUpdateMultiEnd(msgBuf *MsgBuffer) {
455 | _ = msgBuf.readString()
456 | reqID := msgBuf.readInt()
457 |
458 | d.wrapper.AccountUpdateMultiEnd(reqID)
459 | }
460 |
461 | func (d *ibDecoder) wrapSecurityDefinitionOptionParameterEndMsg(msgBuf *MsgBuffer) {
462 | reqID := msgBuf.readInt()
463 |
464 | d.wrapper.SecurityDefinitionOptionParameterEnd(reqID)
465 | }
466 |
467 | func (d *ibDecoder) wrapContractDetailsEnd(msgBuf *MsgBuffer) {
468 | _ = msgBuf.readString()
469 | reqID := msgBuf.readInt()
470 |
471 | d.wrapper.ContractDetailsEnd(reqID)
472 | }
473 |
474 | // ------------------------------------------------------------------
475 |
476 | func (d *ibDecoder) processTickPriceMsg(msgBuf *MsgBuffer) {
477 | _ = msgBuf.readString()
478 | reqID := msgBuf.readInt()
479 | tickType := msgBuf.readInt()
480 | price := msgBuf.readFloat()
481 | size := msgBuf.readInt()
482 | attrMask := msgBuf.readInt()
483 |
484 | attrib := TickAttrib{}
485 | attrib.CanAutoExecute = attrMask == 1
486 |
487 | if d.version >= mMIN_SERVER_VER_PAST_LIMIT {
488 | attrib.CanAutoExecute = attrMask&0x1 != 0
489 | attrib.PastLimit = attrMask&0x2 != 0
490 | if d.version >= mMIN_SERVER_VER_PRE_OPEN_BID_ASK {
491 | attrib.PreOpen = attrMask&0x4 != 0
492 | }
493 | }
494 |
495 | d.wrapper.TickPrice(reqID, tickType, price, attrib)
496 |
497 | var sizeTickType int64
498 | switch tickType {
499 | case BID:
500 | sizeTickType = BID_SIZE
501 | case ASK:
502 | sizeTickType = ASK_SIZE
503 | case LAST:
504 | sizeTickType = LAST_SIZE
505 | case DELAYED_BID:
506 | sizeTickType = DELAYED_BID_SIZE
507 | case DELAYED_ASK:
508 | sizeTickType = DELAYED_ASK_SIZE
509 | case DELAYED_LAST:
510 | sizeTickType = DELAYED_LAST_SIZE
511 | default:
512 | sizeTickType = NOT_SET
513 | }
514 |
515 | if sizeTickType != NOT_SET {
516 | d.wrapper.TickSize(reqID, sizeTickType, size)
517 | }
518 |
519 | }
520 |
521 | func (d *ibDecoder) processOrderStatusMsg(msgBuf *MsgBuffer) {
522 | if d.version < mMIN_SERVER_VER_MARKET_CAP_PRICE {
523 | _ = msgBuf.readString()
524 | }
525 | orderID := msgBuf.readInt()
526 | status := msgBuf.readString()
527 |
528 | filled := msgBuf.readFloat()
529 |
530 | remaining := msgBuf.readFloat()
531 |
532 | avgFilledPrice := msgBuf.readFloat()
533 |
534 | permID := msgBuf.readInt()
535 | parentID := msgBuf.readInt()
536 | lastFillPrice := msgBuf.readFloat()
537 | clientID := msgBuf.readInt()
538 | whyHeld := msgBuf.readString()
539 |
540 | mktCapPrice := 0.0
541 | if d.version >= mMIN_SERVER_VER_MARKET_CAP_PRICE {
542 | mktCapPrice = msgBuf.readFloat()
543 | }
544 |
545 | d.wrapper.OrderStatus(orderID, status, filled, remaining, avgFilledPrice, permID, parentID, lastFillPrice, clientID, whyHeld, mktCapPrice)
546 |
547 | }
548 |
549 | func (d *ibDecoder) processOpenOrder(msgBuf *MsgBuffer) {
550 |
551 | var version int64
552 | if d.version < mMIN_SERVER_VER_ORDER_CONTAINER {
553 | version = msgBuf.readInt()
554 | } else {
555 | version = int64(d.version)
556 | }
557 |
558 | o := &Order{}
559 | o.OrderID = msgBuf.readInt()
560 |
561 | c := &Contract{}
562 |
563 | // read contract fields
564 | c.ContractID = msgBuf.readInt()
565 | c.Symbol = msgBuf.readString()
566 | c.SecurityType = msgBuf.readString()
567 | c.Expiry = msgBuf.readString()
568 | c.Strike = msgBuf.readFloat()
569 | c.Right = msgBuf.readString()
570 | if version >= 32 {
571 | c.Multiplier = msgBuf.readString()
572 | }
573 | c.Exchange = msgBuf.readString()
574 | c.Currency = msgBuf.readString()
575 | c.LocalSymbol = msgBuf.readString()
576 | if version >= 32 {
577 | c.TradingClass = msgBuf.readString()
578 | }
579 |
580 | // read order fields
581 | o.Action = msgBuf.readString()
582 | if d.version >= mMIN_SERVER_VER_FRACTIONAL_POSITIONS {
583 | o.TotalQuantity = msgBuf.readFloat()
584 | } else {
585 | o.TotalQuantity = float64(msgBuf.readInt())
586 | }
587 | o.OrderType = msgBuf.readString()
588 | if version < 29 {
589 | o.LimitPrice = msgBuf.readFloat()
590 | } else {
591 | o.LimitPrice = msgBuf.readFloatCheckUnset()
592 | }
593 | if version < 30 {
594 | o.AuxPrice = msgBuf.readFloat()
595 | } else {
596 | o.AuxPrice = msgBuf.readFloatCheckUnset()
597 | }
598 | o.TIF = msgBuf.readString()
599 | o.OCAGroup = msgBuf.readString()
600 | o.Account = msgBuf.readString()
601 | o.OpenClose = msgBuf.readString()
602 | o.Origin = msgBuf.readInt()
603 | o.OrderRef = msgBuf.readString()
604 | o.ClientID = msgBuf.readInt()
605 | o.PermID = msgBuf.readInt()
606 | o.OutsideRTH = msgBuf.readBool()
607 | o.Hidden = msgBuf.readBool()
608 | o.DiscretionaryAmount = msgBuf.readFloat()
609 | o.GoodAfterTime = msgBuf.readString()
610 | _ = msgBuf.readString() // skip sharesAllocation
611 |
612 | // FAParams
613 | o.FAGroup = msgBuf.readString()
614 | o.FAMethod = msgBuf.readString()
615 | o.FAPercentage = msgBuf.readString()
616 | o.FAProfile = msgBuf.readString()
617 | // ---------
618 | if d.version >= mMIN_SERVER_VER_MODELS_SUPPORT {
619 | o.ModelCode = msgBuf.readString()
620 | }
621 | o.GoodTillDate = msgBuf.readString()
622 | o.Rule80A = msgBuf.readString()
623 | o.PercentOffset = msgBuf.readFloatCheckUnset() //show_unset
624 | o.SettlingFirm = msgBuf.readString()
625 |
626 | // ShortSaleParams
627 | o.ShortSaleSlot = msgBuf.readInt()
628 | o.DesignatedLocation = msgBuf.readString()
629 | if d.version == mMIN_SERVER_VER_SSHORTX_OLD {
630 | _ = msgBuf.readString()
631 | } else if version >= 23 {
632 | o.ExemptCode = msgBuf.readInt()
633 | }
634 | // ----------
635 | o.AuctionStrategy = msgBuf.readInt()
636 |
637 | // BoxOrderParams
638 | o.StartingPrice = msgBuf.readFloatCheckUnset() //show_unset
639 | o.StockRefPrice = msgBuf.readFloatCheckUnset() //show_unset
640 | o.Delta = msgBuf.readFloatCheckUnset() //show_unset
641 | // ----------
642 |
643 | // PegToStkOrVolOrderParams
644 | o.StockRangeLower = msgBuf.readFloatCheckUnset() //show_unset
645 | o.StockRangeUpper = msgBuf.readFloatCheckUnset() //show_unset
646 | // ----------
647 |
648 | o.DisplaySize = msgBuf.readInt()
649 | o.BlockOrder = msgBuf.readBool()
650 | o.SweepToFill = msgBuf.readBool()
651 | o.AllOrNone = msgBuf.readBool()
652 | o.MinQty = msgBuf.readIntCheckUnset() //show_unset
653 | o.OCAType = msgBuf.readInt()
654 | o.ETradeOnly = msgBuf.readBool()
655 | o.FirmQuoteOnly = msgBuf.readBool()
656 | o.NBBOPriceCap = msgBuf.readFloatCheckUnset() //show_unset
657 | o.ParentID = msgBuf.readInt()
658 | o.TriggerMethod = msgBuf.readInt()
659 |
660 | // VolOrderParams
661 | o.Volatility = msgBuf.readFloatCheckUnset() //show_unset
662 | o.VolatilityType = msgBuf.readInt()
663 | o.DeltaNeutralOrderType = msgBuf.readString()
664 | o.DeltaNeutralAuxPrice = msgBuf.readFloatCheckUnset() //show_unset
665 | if version >= 27 && o.DeltaNeutralOrderType != "" {
666 | o.DeltaNeutralContractID = msgBuf.readInt()
667 | o.DeltaNeutralSettlingFirm = msgBuf.readString()
668 | o.DeltaNeutralClearingAccount = msgBuf.readString()
669 | o.DeltaNeutralClearingIntent = msgBuf.readString()
670 | }
671 | if version >= 31 && o.DeltaNeutralOrderType != "" {
672 | o.DeltaNeutralOpenClose = msgBuf.readString()
673 | o.DeltaNeutralShortSale = msgBuf.readBool()
674 | o.DeltaNeutralShortSaleSlot = msgBuf.readInt()
675 | o.DeltaNeutralDesignatedLocation = msgBuf.readString()
676 | }
677 | o.ContinuousUpdate = msgBuf.readBool()
678 | o.ReferencePriceType = msgBuf.readInt()
679 | // ---------
680 |
681 | // TrailParams
682 | o.TrailStopPrice = msgBuf.readFloatCheckUnset()
683 | if version >= 30 {
684 | o.TrailingPercent = msgBuf.readFloatCheckUnset() //show_unset
685 | }
686 | // ----------
687 |
688 | // BasisPoints
689 | o.BasisPoints = msgBuf.readFloatCheckUnset()
690 | o.BasisPointsType = msgBuf.readIntCheckUnset()
691 | // ----------
692 |
693 | // ComboLegs
694 | c.ComboLegsDescription = msgBuf.readString()
695 | if version >= 29 {
696 | {
697 | n := msgBuf.readInt()
698 | c.ComboLegs = make([]ComboLeg, 0, n)
699 | for ; n > 0; n-- {
700 | comboleg := ComboLeg{}
701 | comboleg.ContractID = msgBuf.readInt()
702 | comboleg.Ratio = msgBuf.readInt()
703 | comboleg.Action = msgBuf.readString()
704 | comboleg.Exchange = msgBuf.readString()
705 | comboleg.OpenClose = msgBuf.readInt()
706 | comboleg.ShortSaleSlot = msgBuf.readInt()
707 | comboleg.DesignatedLocation = msgBuf.readString()
708 | comboleg.ExemptCode = msgBuf.readInt()
709 | c.ComboLegs = append(c.ComboLegs, comboleg)
710 | }
711 | }
712 |
713 | {
714 | n := msgBuf.readInt()
715 | o.OrderComboLegs = make([]OrderComboLeg, 0, n)
716 | for ; n > 0; n-- {
717 | orderComboLeg := OrderComboLeg{}
718 | orderComboLeg.Price = msgBuf.readFloatCheckUnset()
719 | o.OrderComboLegs = append(o.OrderComboLegs, orderComboLeg)
720 | }
721 | }
722 |
723 | }
724 | if version >= 26 {
725 | n := msgBuf.readInt()
726 | o.SmartComboRoutingParams = make([]TagValue, 0, n)
727 | for ; n > 0; n-- {
728 | tagValue := TagValue{}
729 | tagValue.Tag = msgBuf.readString()
730 | tagValue.Value = msgBuf.readString()
731 | o.SmartComboRoutingParams = append(o.SmartComboRoutingParams, tagValue)
732 | }
733 | }
734 | // ----------
735 |
736 | // ScaleOrderParams
737 | if version >= 20 {
738 | o.ScaleInitLevelSize = msgBuf.readIntCheckUnset() //show_unset
739 | o.ScaleSubsLevelSize = msgBuf.readIntCheckUnset() //show_unset
740 | } else {
741 | o.NotSuppScaleNumComponents = msgBuf.readIntCheckUnset()
742 | o.ScaleInitLevelSize = msgBuf.readIntCheckUnset()
743 | }
744 | o.ScalePriceIncrement = msgBuf.readFloatCheckUnset()
745 | if version >= 28 && o.ScalePriceIncrement != UNSETFLOAT && o.ScalePriceIncrement > 0.0 {
746 | o.ScalePriceAdjustValue = msgBuf.readFloatCheckUnset()
747 | o.ScalePriceAdjustInterval = msgBuf.readIntCheckUnset()
748 | o.ScaleProfitOffset = msgBuf.readFloatCheckUnset()
749 | o.ScaleAutoReset = msgBuf.readBool()
750 | o.ScaleInitPosition = msgBuf.readIntCheckUnset()
751 | o.ScaleInitFillQty = msgBuf.readIntCheckUnset()
752 | o.ScaleRandomPercent = msgBuf.readBool()
753 | }
754 | // ----------
755 |
756 | if version >= 24 {
757 | o.HedgeType = msgBuf.readString()
758 | if o.HedgeType != "" {
759 | o.HedgeParam = msgBuf.readString()
760 | }
761 | }
762 |
763 | if version >= 25 {
764 | o.OptOutSmartRouting = msgBuf.readBool()
765 | }
766 |
767 | // ClearingParams
768 | o.ClearingAccount = msgBuf.readString()
769 | o.ClearingIntent = msgBuf.readString()
770 | // ----------
771 |
772 | if version >= 22 {
773 | o.NotHeld = msgBuf.readBool()
774 | }
775 |
776 | // DeltaNeutral
777 | if version >= 20 {
778 | deltaNeutralContractPresent := msgBuf.readBool()
779 | if deltaNeutralContractPresent {
780 | c.DeltaNeutralContract = new(DeltaNeutralContract)
781 | c.DeltaNeutralContract.ContractID = msgBuf.readInt()
782 | c.DeltaNeutralContract.Delta = msgBuf.readFloat()
783 | c.DeltaNeutralContract.Price = msgBuf.readFloat()
784 | }
785 | }
786 | // ----------
787 |
788 | // AlgoParams
789 | if version >= 21 {
790 | o.AlgoStrategy = msgBuf.readString()
791 | if o.AlgoStrategy != "" {
792 | n := msgBuf.readInt()
793 | o.AlgoParams = make([]TagValue, 0, n)
794 | for ; n > 0; n-- {
795 | tagValue := TagValue{}
796 | tagValue.Tag = msgBuf.readString()
797 | tagValue.Value = msgBuf.readString()
798 | o.AlgoParams = append(o.AlgoParams, tagValue)
799 | }
800 | }
801 | }
802 | // ----------
803 |
804 | if version >= 33 {
805 | o.Solictied = msgBuf.readBool()
806 | }
807 |
808 | orderState := &OrderState{}
809 |
810 | // WhatIfInfoAndCommission
811 | o.WhatIf = msgBuf.readBool()
812 | orderState.Status = msgBuf.readString()
813 | if d.version >= mMIN_SERVER_VER_WHAT_IF_EXT_FIELDS {
814 | orderState.InitialMarginBefore = msgBuf.readString()
815 | orderState.MaintenanceMarginBefore = msgBuf.readString()
816 | orderState.EquityWithLoanBefore = msgBuf.readString()
817 | orderState.InitialMarginChange = msgBuf.readString()
818 | orderState.MaintenanceMarginChange = msgBuf.readString()
819 | orderState.EquityWithLoanChange = msgBuf.readString()
820 | }
821 |
822 | orderState.InitialMarginAfter = msgBuf.readString()
823 | orderState.MaintenanceMarginAfter = msgBuf.readString()
824 | orderState.EquityWithLoanAfter = msgBuf.readString()
825 |
826 | orderState.Commission = msgBuf.readFloatCheckUnset()
827 | orderState.MinCommission = msgBuf.readFloatCheckUnset()
828 | orderState.MaxCommission = msgBuf.readFloatCheckUnset()
829 | orderState.CommissionCurrency = msgBuf.readString()
830 | orderState.WarningText = msgBuf.readString()
831 | // ----------
832 |
833 | // VolRandomizeFlags
834 | if version >= 34 {
835 | o.RandomizeSize = msgBuf.readBool()
836 | o.RandomizePrice = msgBuf.readBool()
837 | }
838 | // ----------
839 |
840 | if d.version >= mMIN_SERVER_VER_PEGGED_TO_BENCHMARK {
841 | // PegToBenchParams
842 | if o.OrderType == "PEG BENCH" {
843 | o.ReferenceContractID = msgBuf.readInt()
844 | o.IsPeggedChangeAmountDecrease = msgBuf.readBool()
845 | o.PeggedChangeAmount = msgBuf.readFloat()
846 | o.ReferenceChangeAmount = msgBuf.readFloat()
847 | o.ReferenceExchangeID = msgBuf.readString()
848 | }
849 | // ----------
850 |
851 | // Conditions
852 | n := msgBuf.readInt()
853 | o.Conditions = make([]OrderConditioner, 0, n)
854 | if n > 0 {
855 | for ; n > 0; n-- {
856 | conditionType := msgBuf.readInt()
857 | cond, _ := InitOrderCondition(conditionType)
858 | cond.decode(msgBuf)
859 |
860 | o.Conditions = append(o.Conditions, cond)
861 | }
862 | o.ConditionsIgnoreRth = msgBuf.readBool()
863 | o.ConditionsCancelOrder = msgBuf.readBool()
864 | }
865 | // ----------
866 |
867 | // AdjustedOrderParams
868 | o.AdjustedOrderType = msgBuf.readString()
869 | o.TriggerPrice = msgBuf.readFloat()
870 | o.TrailStopPrice = msgBuf.readFloat()
871 | o.LimitPriceOffset = msgBuf.readFloat()
872 | o.AdjustedStopPrice = msgBuf.readFloat()
873 | o.AdjustedStopLimitPrice = msgBuf.readFloat()
874 | o.AdjustedTrailingAmount = msgBuf.readFloat()
875 | o.AdjustableTrailingUnit = msgBuf.readInt()
876 | // ----------
877 | }
878 |
879 | // SoftDollarTier
880 | if d.version >= mMIN_SERVER_VER_SOFT_DOLLAR_TIER {
881 | name := msgBuf.readString()
882 | value := msgBuf.readString()
883 | displayName := msgBuf.readString()
884 | o.SoftDollarTier = SoftDollarTier{name, value, displayName}
885 | }
886 | // ----------
887 |
888 | if d.version >= mMIN_SERVER_VER_CASH_QTY {
889 | o.CashQty = msgBuf.readFloat()
890 | }
891 |
892 | if d.version >= mMIN_SERVER_VER_AUTO_PRICE_FOR_HEDGE {
893 | o.DontUseAutoPriceForHedge = msgBuf.readBool()
894 | }
895 |
896 | if d.version >= mMIN_SERVER_VER_ORDER_CONTAINER {
897 | o.IsOmsContainer = msgBuf.readBool()
898 | }
899 |
900 | if d.version >= mMIN_SERVER_VER_D_PEG_ORDERS {
901 | o.DiscretionaryUpToLimitPrice = msgBuf.readBool()
902 | }
903 |
904 | if d.version >= mMIN_SERVER_VER_PRICE_MGMT_ALGO {
905 | o.UsePriceMgmtAlgo = msgBuf.readBool()
906 | }
907 |
908 | if d.version >= mMIN_SERVER_VER_DURATION {
909 | o.Duration = msgBuf.readIntCheckUnset()
910 | }
911 |
912 | if d.version >= mMIN_SERVER_VER_POST_TO_ATS {
913 | o.PostToAts = msgBuf.readIntCheckUnset()
914 | }
915 |
916 | d.wrapper.OpenOrder(o.OrderID, c, o, orderState)
917 |
918 | }
919 |
920 | func (d *ibDecoder) processPortfolioValueMsg(msgBuf *MsgBuffer) {
921 | v := msgBuf.readInt()
922 |
923 | c := &Contract{}
924 | c.ContractID = msgBuf.readInt()
925 | c.Symbol = msgBuf.readString()
926 | c.SecurityType = msgBuf.readString()
927 | c.Expiry = msgBuf.readString()
928 | c.Strike = msgBuf.readFloat()
929 | c.Right = msgBuf.readString()
930 | if v >= 7 {
931 | c.Multiplier = msgBuf.readString()
932 | c.PrimaryExchange = msgBuf.readString()
933 | }
934 | c.Currency = msgBuf.readString()
935 | c.LocalSymbol = msgBuf.readString()
936 | if v >= 8 {
937 | c.TradingClass = msgBuf.readString()
938 | }
939 | var position float64
940 | if d.version >= mMIN_SERVER_VER_FRACTIONAL_POSITIONS {
941 | position = msgBuf.readFloat()
942 | } else {
943 | position = float64(msgBuf.readInt())
944 | }
945 | marketPrice := msgBuf.readFloat()
946 | marketValue := msgBuf.readFloat()
947 | averageCost := msgBuf.readFloat()
948 | unrealizedPNL := msgBuf.readFloat()
949 | realizedPNL := msgBuf.readFloat()
950 | accName := msgBuf.readString()
951 | if v == 6 && d.version == 39 {
952 | c.PrimaryExchange = msgBuf.readString()
953 | }
954 |
955 | d.wrapper.UpdatePortfolio(c, position, marketPrice, marketValue, averageCost, unrealizedPNL, realizedPNL, accName)
956 |
957 | }
958 |
959 | func (d *ibDecoder) processContractDataMsg(msgBuf *MsgBuffer) {
960 | v := msgBuf.readInt()
961 | var reqID int64 = -1
962 | if v >= 3 {
963 | reqID = msgBuf.readInt()
964 | }
965 |
966 | cd := ContractDetails{}
967 | cd.Contract = Contract{}
968 | cd.Contract.Symbol = msgBuf.readString()
969 | cd.Contract.SecurityType = msgBuf.readString()
970 |
971 | lastTradeDateOrContractMonth := msgBuf.readString()
972 | if lastTradeDateOrContractMonth != "" {
973 | splitted := strings.Split(lastTradeDateOrContractMonth, " ")
974 | l := len(splitted)
975 |
976 | if l > 0 {
977 | cd.Contract.Expiry = splitted[0]
978 | }
979 | if l > 1 {
980 | cd.LastTradeTime = splitted[1]
981 | }
982 | }
983 |
984 | cd.Contract.Strike = msgBuf.readFloat()
985 | cd.Contract.Right = msgBuf.readString()
986 | cd.Contract.Exchange = msgBuf.readString()
987 | cd.Contract.Currency = msgBuf.readString()
988 | cd.Contract.LocalSymbol = msgBuf.readString()
989 | cd.MarketName = msgBuf.readString()
990 | cd.Contract.TradingClass = msgBuf.readString()
991 | cd.Contract.ContractID = msgBuf.readInt()
992 | cd.MinTick = msgBuf.readFloat()
993 | if d.version >= mMIN_SERVER_VER_MD_SIZE_MULTIPLIER {
994 | cd.MdSizeMultiplier = msgBuf.readInt()
995 | }
996 | cd.Contract.Multiplier = msgBuf.readString()
997 | cd.OrderTypes = msgBuf.readString()
998 | cd.ValidExchanges = msgBuf.readString()
999 | cd.PriceMagnifier = msgBuf.readInt()
1000 | if v >= 4 {
1001 | cd.UnderContractID = msgBuf.readInt()
1002 | }
1003 | if v >= 5 {
1004 | if d.version >= mMIN_SERVER_VER_ENCODE_MSG_ASCII7 {
1005 | cd.LongName = msgBuf.readString() // FIXME: unicode-escape
1006 | } else {
1007 | cd.LongName = msgBuf.readString()
1008 | }
1009 |
1010 | cd.Contract.PrimaryExchange = msgBuf.readString()
1011 | }
1012 | if v >= 6 {
1013 | cd.ContractMonth = msgBuf.readString()
1014 | cd.Industry = msgBuf.readString()
1015 | cd.Category = msgBuf.readString()
1016 | cd.Subcategory = msgBuf.readString()
1017 | cd.TimezoneID = msgBuf.readString()
1018 | cd.TradingHours = msgBuf.readString()
1019 | cd.LiquidHours = msgBuf.readString()
1020 | }
1021 | if v >= 8 {
1022 | cd.EVRule = msgBuf.readString()
1023 | cd.EVMultiplier = msgBuf.readInt()
1024 | }
1025 | if v >= 7 {
1026 | n := msgBuf.readInt()
1027 | cd.SecurityIDList = make([]TagValue, 0, n)
1028 | for ; n > 0; n-- {
1029 | tagValue := TagValue{}
1030 | tagValue.Tag = msgBuf.readString()
1031 | tagValue.Value = msgBuf.readString()
1032 | cd.SecurityIDList = append(cd.SecurityIDList, tagValue)
1033 | }
1034 | }
1035 |
1036 | if d.version >= mMIN_SERVER_VER_AGG_GROUP {
1037 | cd.AggGroup = msgBuf.readInt()
1038 | }
1039 |
1040 | if d.version >= mMIN_SERVER_VER_UNDERLYING_INFO {
1041 | cd.UnderSymbol = msgBuf.readString()
1042 | cd.UnderSecurityType = msgBuf.readString()
1043 | }
1044 |
1045 | if d.version >= mMIN_SERVER_VER_MARKET_RULES {
1046 | cd.MarketRuleIDs = msgBuf.readString()
1047 | }
1048 |
1049 | if d.version >= mMIN_SERVER_VER_REAL_EXPIRATION_DATE {
1050 | cd.RealExpirationDate = msgBuf.readString()
1051 | }
1052 |
1053 | if d.version >= mMIN_SERVER_VER_STOCK_TYPE {
1054 | cd.StockType = msgBuf.readString()
1055 | }
1056 |
1057 | d.wrapper.ContractDetails(reqID, &cd)
1058 |
1059 | }
1060 | func (d *ibDecoder) processBondContractDataMsg(msgBuf *MsgBuffer) {
1061 | v := msgBuf.readInt()
1062 |
1063 | var reqID int64 = -1
1064 |
1065 | if v >= 3 {
1066 | reqID = msgBuf.readInt()
1067 | }
1068 |
1069 | c := &ContractDetails{}
1070 | c.Contract.Symbol = msgBuf.readString()
1071 | c.Contract.SecurityType = msgBuf.readString()
1072 | c.Cusip = msgBuf.readString()
1073 | c.Coupon = msgBuf.readInt()
1074 |
1075 | splittedExpiry := strings.Split(msgBuf.readString(), " ")
1076 | switch s := len(splittedExpiry); {
1077 | case s > 0:
1078 | c.Maturity = splittedExpiry[0]
1079 | fallthrough
1080 | case s > 1:
1081 | c.LastTradeTime = splittedExpiry[1]
1082 | fallthrough
1083 | case s > 2:
1084 | c.TimezoneID = splittedExpiry[2]
1085 | }
1086 |
1087 | c.IssueDate = msgBuf.readString()
1088 | c.Ratings = msgBuf.readString()
1089 | c.BondType = msgBuf.readString()
1090 | c.CouponType = msgBuf.readString()
1091 | c.Convertible = msgBuf.readBool()
1092 | c.Callable = msgBuf.readBool()
1093 | c.Putable = msgBuf.readBool()
1094 | c.DescAppend = msgBuf.readString()
1095 | c.Contract.Exchange = msgBuf.readString()
1096 | c.Contract.Currency = msgBuf.readString()
1097 | c.MarketName = msgBuf.readString()
1098 | c.Contract.TradingClass = msgBuf.readString()
1099 | c.Contract.ContractID = msgBuf.readInt()
1100 | c.MinTick = msgBuf.readFloat()
1101 |
1102 | if d.version >= mMIN_SERVER_VER_MD_SIZE_MULTIPLIER {
1103 | c.MdSizeMultiplier = msgBuf.readInt()
1104 | }
1105 |
1106 | c.OrderTypes = msgBuf.readString()
1107 | c.ValidExchanges = msgBuf.readString()
1108 | c.NextOptionDate = msgBuf.readString()
1109 | c.NextOptionType = msgBuf.readString()
1110 | c.NextOptionPartial = msgBuf.readBool()
1111 | c.Notes = msgBuf.readString()
1112 |
1113 | if v >= 4 {
1114 | c.LongName = msgBuf.readString()
1115 | }
1116 |
1117 | if v >= 6 {
1118 | c.EVRule = msgBuf.readString()
1119 | c.EVMultiplier = msgBuf.readInt()
1120 | }
1121 |
1122 | if v >= 5 {
1123 | n := msgBuf.readInt()
1124 | c.SecurityIDList = make([]TagValue, 0, n)
1125 | for ; n > 0; n-- {
1126 | tagValue := TagValue{}
1127 | tagValue.Tag = msgBuf.readString()
1128 | tagValue.Value = msgBuf.readString()
1129 | c.SecurityIDList = append(c.SecurityIDList, tagValue)
1130 | }
1131 | }
1132 |
1133 | if d.version >= mMIN_SERVER_VER_AGG_GROUP {
1134 | c.AggGroup = msgBuf.readInt()
1135 | }
1136 |
1137 | if d.version >= mMIN_SERVER_VER_MARKET_RULES {
1138 | c.MarketRuleIDs = msgBuf.readString()
1139 | }
1140 |
1141 | d.wrapper.BondContractDetails(reqID, c)
1142 |
1143 | }
1144 | func (d *ibDecoder) processScannerDataMsg(msgBuf *MsgBuffer) {
1145 | _ = msgBuf.readString()
1146 | reqID := msgBuf.readInt()
1147 | for n := msgBuf.readInt(); n > 0; n-- {
1148 | sd := ScanData{}
1149 | sd.ContractDetails = ContractDetails{}
1150 |
1151 | sd.Rank = msgBuf.readInt()
1152 | sd.ContractDetails.Contract.ContractID = msgBuf.readInt()
1153 | sd.ContractDetails.Contract.Symbol = msgBuf.readString()
1154 | sd.ContractDetails.Contract.SecurityType = msgBuf.readString()
1155 | sd.ContractDetails.Contract.Expiry = msgBuf.readString()
1156 | sd.ContractDetails.Contract.Strike = msgBuf.readFloat()
1157 | sd.ContractDetails.Contract.Right = msgBuf.readString()
1158 | sd.ContractDetails.Contract.Exchange = msgBuf.readString()
1159 | sd.ContractDetails.Contract.Currency = msgBuf.readString()
1160 | sd.ContractDetails.Contract.LocalSymbol = msgBuf.readString()
1161 | sd.ContractDetails.MarketName = msgBuf.readString()
1162 | sd.ContractDetails.Contract.TradingClass = msgBuf.readString()
1163 | sd.Distance = msgBuf.readString()
1164 | sd.Benchmark = msgBuf.readString()
1165 | sd.Projection = msgBuf.readString()
1166 | sd.Legs = msgBuf.readString()
1167 |
1168 | d.wrapper.ScannerData(reqID, sd.Rank, &(sd.ContractDetails), sd.Distance, sd.Benchmark, sd.Projection, sd.Legs)
1169 |
1170 | }
1171 |
1172 | d.wrapper.ScannerDataEnd(reqID)
1173 |
1174 | }
1175 | func (d *ibDecoder) processExecutionDataMsg(msgBuf *MsgBuffer) {
1176 | var v int64
1177 | if d.version < mMIN_SERVER_VER_LAST_LIQUIDITY {
1178 | v = msgBuf.readInt()
1179 | } else {
1180 | v = int64(d.version)
1181 | }
1182 |
1183 | var reqID int64 = -1
1184 | if v >= 7 {
1185 | reqID = msgBuf.readInt()
1186 | }
1187 |
1188 | orderID := msgBuf.readInt()
1189 |
1190 | // read contact fields
1191 | c := Contract{}
1192 | c.ContractID = msgBuf.readInt()
1193 | c.Symbol = msgBuf.readString()
1194 | c.SecurityType = msgBuf.readString()
1195 | c.Expiry = msgBuf.readString()
1196 | c.Strike = msgBuf.readFloat()
1197 | c.Right = msgBuf.readString()
1198 | if v >= 9 {
1199 | c.Multiplier = msgBuf.readString()
1200 | }
1201 | c.Exchange = msgBuf.readString()
1202 | c.Currency = msgBuf.readString()
1203 | c.LocalSymbol = msgBuf.readString()
1204 | if v >= 10 {
1205 | c.TradingClass = msgBuf.readString()
1206 | }
1207 |
1208 | // read execution fields
1209 | e := Execution{}
1210 | e.OrderID = orderID
1211 | e.ExecID = msgBuf.readString()
1212 | e.Time = msgBuf.readString()
1213 | e.AccountCode = msgBuf.readString()
1214 | e.Exchange = msgBuf.readString()
1215 | e.Side = msgBuf.readString()
1216 | e.Shares = msgBuf.readFloat()
1217 | e.Price = msgBuf.readFloat()
1218 | e.PermID = msgBuf.readInt()
1219 | e.ClientID = msgBuf.readInt()
1220 | e.Liquidation = msgBuf.readInt()
1221 | if v >= 6 {
1222 | e.CumQty = msgBuf.readFloat()
1223 | e.AveragePrice = msgBuf.readFloat()
1224 | }
1225 | if v >= 8 {
1226 | e.OrderRef = msgBuf.readString()
1227 | }
1228 | if v >= 9 {
1229 | e.EVRule = msgBuf.readString()
1230 | e.EVMultiplier = msgBuf.readFloat()
1231 | }
1232 | if d.version >= mMIN_SERVER_VER_MODELS_SUPPORT {
1233 | e.ModelCode = msgBuf.readString()
1234 | }
1235 | if d.version >= mMIN_SERVER_VER_LAST_LIQUIDITY {
1236 | e.LastLiquidity = msgBuf.readInt()
1237 | }
1238 |
1239 | d.wrapper.ExecDetails(reqID, &c, &e)
1240 |
1241 | }
1242 |
1243 | func (d *ibDecoder) processHistoricalDataMsg(msgBuf *MsgBuffer) {
1244 | if d.version < mMIN_SERVER_VER_SYNT_REALTIME_BARS {
1245 | _ = msgBuf.readString()
1246 | }
1247 |
1248 | reqID := msgBuf.readInt()
1249 | startDatestr := msgBuf.readString()
1250 | endDateStr := msgBuf.readString()
1251 |
1252 | for n := msgBuf.readInt(); n > 0; n-- {
1253 | bar := &BarData{}
1254 | bar.Date = msgBuf.readString()
1255 | bar.Open = msgBuf.readFloat()
1256 | bar.High = msgBuf.readFloat()
1257 | bar.Low = msgBuf.readFloat()
1258 | bar.Close = msgBuf.readFloat()
1259 | bar.Volume = msgBuf.readFloat()
1260 | bar.Average = msgBuf.readFloat()
1261 | if d.version < mMIN_SERVER_VER_SYNT_REALTIME_BARS {
1262 | _ = msgBuf.readString()
1263 | }
1264 | bar.BarCount = msgBuf.readInt()
1265 |
1266 | d.wrapper.HistoricalData(reqID, bar)
1267 | }
1268 |
1269 | d.wrapper.HistoricalDataEnd(reqID, startDatestr, endDateStr)
1270 |
1271 | }
1272 | func (d *ibDecoder) processHistoricalDataUpdateMsg(msgBuf *MsgBuffer) {
1273 | reqID := msgBuf.readInt()
1274 | bar := &BarData{}
1275 | bar.BarCount = msgBuf.readInt()
1276 | bar.Date = msgBuf.readString()
1277 | bar.Open = msgBuf.readFloat()
1278 | bar.Close = msgBuf.readFloat()
1279 | bar.High = msgBuf.readFloat()
1280 | bar.Low = msgBuf.readFloat()
1281 | bar.Average = msgBuf.readFloat()
1282 | bar.Volume = msgBuf.readFloat()
1283 |
1284 | d.wrapper.HistoricalDataUpdate(reqID, bar)
1285 |
1286 | }
1287 | func (d *ibDecoder) processRealTimeBarMsg(msgBuf *MsgBuffer) {
1288 | _ = msgBuf.readString()
1289 | reqID := msgBuf.readInt()
1290 |
1291 | rtb := &RealTimeBar{}
1292 | rtb.Time = msgBuf.readInt()
1293 | rtb.Open = msgBuf.readFloat()
1294 | rtb.High = msgBuf.readFloat()
1295 | rtb.Low = msgBuf.readFloat()
1296 | rtb.Close = msgBuf.readFloat()
1297 | rtb.Volume = msgBuf.readInt()
1298 | rtb.Wap = msgBuf.readFloat()
1299 | rtb.Count = msgBuf.readInt()
1300 |
1301 | d.wrapper.RealtimeBar(reqID, rtb.Time, rtb.Open, rtb.High, rtb.Low, rtb.Close, rtb.Volume, rtb.Wap, rtb.Count)
1302 | }
1303 |
1304 | /*
1305 | void tickOptionComputation (
1306 | int tickerId, -- the request's unique identifier.
1307 | int field, -- Specifies the type of option computation. Pass the field value into TickType.getField(int tickType) to retrieve the field description. For example, a field value of 13 will map to modelOptComp, etc. 10 = Bid 11 = Ask 12 = Las
1308 | int tickAttrib, -- 0 - return based, 1- price based.
1309 | double impliedVolatility,
1310 | double delta,
1311 | double optPrice,
1312 | double pvDividend,
1313 | double gamma,
1314 | double vega,
1315 | double theta,
1316 | double undPrice
1317 | )
1318 | */
1319 | func (d *ibDecoder) processTickOptionComputationMsg(msgBuf *MsgBuffer) {
1320 | optPrice := UNSETFLOAT
1321 | pvDividend := UNSETFLOAT
1322 | gamma := UNSETFLOAT
1323 | vega := UNSETFLOAT
1324 | theta := UNSETFLOAT
1325 | undPrice := UNSETFLOAT
1326 |
1327 | var v int64
1328 | if d.version < mMIN_SERVER_VER_PRICE_BASED_VOLATILITY {
1329 | v = msgBuf.readInt()
1330 | } else {
1331 | v = int64(d.version)
1332 | }
1333 |
1334 | reqID := msgBuf.readInt() // tickerId
1335 | tickType := msgBuf.readInt() // field
1336 |
1337 | var tickAttrib int64
1338 | if d.version >= mMIN_SERVER_VER_PRICE_BASED_VOLATILITY {
1339 | tickAttrib = msgBuf.readInt() // tickAtrib
1340 | }
1341 |
1342 | impliedVol := msgBuf.readFloat()
1343 | delta := msgBuf.readFloat()
1344 |
1345 | if v >= 6 || tickType == MODEL_OPTION || tickType == DELAYED_MODEL_OPTION {
1346 | optPrice = msgBuf.readFloat()
1347 | pvDividend = msgBuf.readFloat()
1348 | }
1349 |
1350 | if v >= 6 {
1351 | gamma = msgBuf.readFloat()
1352 | vega = msgBuf.readFloat()
1353 | theta = msgBuf.readFloat()
1354 | undPrice = msgBuf.readFloat()
1355 |
1356 | }
1357 |
1358 | switch {
1359 | case impliedVol < 0:
1360 | impliedVol = UNSETFLOAT
1361 | fallthrough
1362 | case delta == -2:
1363 | delta = UNSETFLOAT
1364 | fallthrough
1365 | case optPrice == -1:
1366 | optPrice = UNSETFLOAT
1367 | fallthrough
1368 | case pvDividend == -1:
1369 | pvDividend = UNSETFLOAT
1370 | fallthrough
1371 | case gamma == -2:
1372 | gamma = UNSETFLOAT
1373 | fallthrough
1374 | case vega == -2:
1375 | vega = UNSETFLOAT
1376 | fallthrough
1377 | case theta == -2:
1378 | theta = UNSETFLOAT
1379 | fallthrough
1380 | case undPrice == -1:
1381 | undPrice = UNSETFLOAT
1382 | }
1383 |
1384 | d.wrapper.TickOptionComputation(reqID, tickType, tickAttrib, impliedVol, delta, optPrice, pvDividend, gamma, vega, theta, undPrice)
1385 |
1386 | }
1387 |
1388 | func (d *ibDecoder) processDeltaNeutralValidationMsg(msgBuf *MsgBuffer) {
1389 | _ = msgBuf.readString()
1390 | reqID := msgBuf.readInt()
1391 | deltaNeutralContract := DeltaNeutralContract{}
1392 |
1393 | deltaNeutralContract.ContractID = msgBuf.readInt()
1394 | deltaNeutralContract.Delta = msgBuf.readFloat()
1395 | deltaNeutralContract.Price = msgBuf.readFloat()
1396 |
1397 | d.wrapper.DeltaNeutralValidation(reqID, deltaNeutralContract)
1398 |
1399 | }
1400 |
1401 | // func (d *ibDecoder) processMarketDataTypeMsg(msgBuf *MsgBuffer) {
1402 |
1403 | // }
1404 | func (d *ibDecoder) processCommissionReportMsg(msgBuf *MsgBuffer) {
1405 | _ = msgBuf.readString()
1406 | cr := CommissionReport{}
1407 | cr.ExecID = msgBuf.readString()
1408 | cr.Commission = msgBuf.readFloat()
1409 | cr.Currency = msgBuf.readString()
1410 | cr.RealizedPNL = msgBuf.readFloat()
1411 | cr.Yield = msgBuf.readFloat()
1412 | cr.YieldRedemptionDate = msgBuf.readInt()
1413 |
1414 | d.wrapper.CommissionReport(cr)
1415 |
1416 | }
1417 |
1418 | func (d *ibDecoder) processPositionDataMsg(msgBuf *MsgBuffer) {
1419 | v := msgBuf.readInt()
1420 | acc := msgBuf.readString()
1421 |
1422 | // read contract fields
1423 | c := new(Contract)
1424 | c.ContractID = msgBuf.readInt()
1425 | c.Symbol = msgBuf.readString()
1426 | c.SecurityType = msgBuf.readString()
1427 | c.Expiry = msgBuf.readString()
1428 | c.Strike = msgBuf.readFloat()
1429 | c.Right = msgBuf.readString()
1430 | c.Multiplier = msgBuf.readString()
1431 | c.Exchange = msgBuf.readString()
1432 | c.Currency = msgBuf.readString()
1433 | c.LocalSymbol = msgBuf.readString()
1434 | if v >= 2 {
1435 | c.TradingClass = msgBuf.readString()
1436 | }
1437 |
1438 | var p float64
1439 | if d.version >= mMIN_SERVER_VER_FRACTIONAL_POSITIONS {
1440 | p = msgBuf.readFloat()
1441 | } else {
1442 | p = float64(msgBuf.readInt())
1443 | }
1444 |
1445 | var avgCost float64
1446 | if v >= 3 {
1447 | avgCost = msgBuf.readFloat()
1448 | }
1449 |
1450 | d.wrapper.Position(acc, c, p, avgCost)
1451 |
1452 | }
1453 |
1454 | func (d *ibDecoder) processPositionMultiMsg(msgBuf *MsgBuffer) {
1455 | _ = msgBuf.readString()
1456 | reqID := msgBuf.readInt()
1457 | acc := msgBuf.readString()
1458 |
1459 | // read contract fields
1460 | c := new(Contract)
1461 | c.ContractID = msgBuf.readInt()
1462 | c.Symbol = msgBuf.readString()
1463 | c.SecurityType = msgBuf.readString()
1464 | c.Expiry = msgBuf.readString()
1465 | c.Strike = msgBuf.readFloat()
1466 | c.Right = msgBuf.readString()
1467 | c.Multiplier = msgBuf.readString()
1468 | c.Exchange = msgBuf.readString()
1469 | c.Currency = msgBuf.readString()
1470 | c.LocalSymbol = msgBuf.readString()
1471 | c.TradingClass = msgBuf.readString()
1472 |
1473 | p := msgBuf.readFloat()
1474 | avgCost := msgBuf.readFloat()
1475 | modelCode := msgBuf.readString()
1476 |
1477 | d.wrapper.PositionMulti(reqID, acc, modelCode, c, p, avgCost)
1478 |
1479 | }
1480 |
1481 | func (d *ibDecoder) processSecurityDefinitionOptionParameterMsg(msgBuf *MsgBuffer) {
1482 | reqID := msgBuf.readInt()
1483 | exchange := msgBuf.readString()
1484 | underlyingContractID := msgBuf.readInt()
1485 | tradingClass := msgBuf.readString()
1486 | multiplier := msgBuf.readString()
1487 |
1488 | expN := msgBuf.readInt()
1489 | expirations := make([]string, 0, expN)
1490 | for ; expN > 0; expN-- {
1491 | expiration := msgBuf.readString()
1492 | expirations = append(expirations, expiration)
1493 | }
1494 |
1495 | strikeN := msgBuf.readInt()
1496 | strikes := make([]float64, 0, strikeN)
1497 | for ; strikeN > 0; strikeN-- {
1498 | strike := msgBuf.readFloat()
1499 | strikes = append(strikes, strike)
1500 | }
1501 |
1502 | d.wrapper.SecurityDefinitionOptionParameter(reqID, exchange, underlyingContractID, tradingClass, multiplier, expirations, strikes)
1503 |
1504 | }
1505 |
1506 | func (d *ibDecoder) processSoftDollarTiersMsg(msgBuf *MsgBuffer) {
1507 | reqID := msgBuf.readInt()
1508 |
1509 | n := msgBuf.readInt()
1510 | tiers := make([]SoftDollarTier, 0, n)
1511 | for ; n > 0; n-- {
1512 | tier := SoftDollarTier{}
1513 | tier.Name = msgBuf.readString()
1514 | tier.Value = msgBuf.readString()
1515 | tier.DisplayName = msgBuf.readString()
1516 | tiers = append(tiers, tier)
1517 | }
1518 |
1519 | d.wrapper.SoftDollarTiers(reqID, tiers)
1520 |
1521 | }
1522 |
1523 | func (d *ibDecoder) processFamilyCodesMsg(msgBuf *MsgBuffer) {
1524 | n := msgBuf.readInt()
1525 | familyCodes := make([]FamilyCode, 0, n)
1526 | for ; n > 0; n-- {
1527 | familyCode := FamilyCode{}
1528 | familyCode.AccountID = msgBuf.readString()
1529 | familyCode.FamilyCode = msgBuf.readString()
1530 | familyCodes = append(familyCodes, familyCode)
1531 | }
1532 |
1533 | d.wrapper.FamilyCodes(familyCodes)
1534 |
1535 | }
1536 |
1537 | func (d *ibDecoder) processSymbolSamplesMsg(msgBuf *MsgBuffer) {
1538 | reqID := msgBuf.readInt()
1539 |
1540 | n := msgBuf.readInt()
1541 | contractDescriptions := make([]ContractDescription, 0, n)
1542 | for ; n > 0; n-- {
1543 | cd := ContractDescription{}
1544 | cd.Contract.ContractID = msgBuf.readInt()
1545 | cd.Contract.Symbol = msgBuf.readString()
1546 | cd.Contract.SecurityType = msgBuf.readString()
1547 | cd.Contract.PrimaryExchange = msgBuf.readString()
1548 | cd.Contract.Currency = msgBuf.readString()
1549 |
1550 | sdtN := msgBuf.readInt()
1551 | cd.DerivativeSecTypes = make([]string, 0, sdtN)
1552 | for ; sdtN > 0; sdtN-- {
1553 | derivativeSecType := msgBuf.readString()
1554 | cd.DerivativeSecTypes = append(cd.DerivativeSecTypes, derivativeSecType)
1555 | }
1556 | contractDescriptions = append(contractDescriptions, cd)
1557 | }
1558 |
1559 | d.wrapper.SymbolSamples(reqID, contractDescriptions)
1560 |
1561 | }
1562 |
1563 | func (d *ibDecoder) processSmartComponents(msgBuf *MsgBuffer) {
1564 | reqID := msgBuf.readInt()
1565 |
1566 | n := msgBuf.readInt()
1567 | smartComponents := make([]SmartComponent, 0, n)
1568 | for ; n > 0; n-- {
1569 | smartComponent := SmartComponent{}
1570 | smartComponent.BitNumber = msgBuf.readInt()
1571 | smartComponent.Exchange = msgBuf.readString()
1572 | smartComponent.ExchangeLetter = msgBuf.readString()
1573 | smartComponents = append(smartComponents, smartComponent)
1574 | }
1575 |
1576 | d.wrapper.SmartComponents(reqID, smartComponents)
1577 |
1578 | }
1579 |
1580 | func (d *ibDecoder) processTickReqParams(msgBuf *MsgBuffer) {
1581 | tickerID := msgBuf.readInt()
1582 | minTick := msgBuf.readFloat()
1583 | bboExchange := msgBuf.readString()
1584 | snapshotPermissions := msgBuf.readInt()
1585 |
1586 | d.wrapper.TickReqParams(tickerID, minTick, bboExchange, snapshotPermissions)
1587 | }
1588 |
1589 | func (d *ibDecoder) processMktDepthExchanges(msgBuf *MsgBuffer) {
1590 | n := msgBuf.readInt()
1591 | depthMktDataDescriptions := make([]DepthMktDataDescription, 0, n)
1592 | for ; n > 0; n-- {
1593 | desc := DepthMktDataDescription{}
1594 | desc.Exchange = msgBuf.readString()
1595 | desc.SecurityType = msgBuf.readString()
1596 | if d.version >= mMIN_SERVER_VER_SERVICE_DATA_TYPE {
1597 | desc.ListingExchange = msgBuf.readString()
1598 | desc.SecurityType = msgBuf.readString()
1599 | desc.AggGroup = msgBuf.readInt()
1600 | } else {
1601 | _ = msgBuf.readString()
1602 | }
1603 |
1604 | depthMktDataDescriptions = append(depthMktDataDescriptions, desc)
1605 | }
1606 |
1607 | d.wrapper.MktDepthExchanges(depthMktDataDescriptions)
1608 | }
1609 |
1610 | func (d *ibDecoder) processHeadTimestamp(msgBuf *MsgBuffer) {
1611 | reqID := msgBuf.readInt()
1612 | headTimestamp := msgBuf.readString()
1613 |
1614 | d.wrapper.HeadTimestamp(reqID, headTimestamp)
1615 | }
1616 |
1617 | func (d *ibDecoder) processTickNews(msgBuf *MsgBuffer) {
1618 | tickerID := msgBuf.readInt()
1619 | timeStamp := msgBuf.readInt()
1620 | providerCode := msgBuf.readString()
1621 | articleID := msgBuf.readString()
1622 | headline := msgBuf.readString()
1623 | extraData := msgBuf.readString()
1624 |
1625 | d.wrapper.TickNews(tickerID, timeStamp, providerCode, articleID, headline, extraData)
1626 | }
1627 |
1628 | func (d *ibDecoder) processNewsProviders(msgBuf *MsgBuffer) {
1629 | n := msgBuf.readInt()
1630 | newsProviders := make([]NewsProvider, 0, n)
1631 | for ; n > 0; n-- {
1632 | provider := NewsProvider{}
1633 | provider.Name = msgBuf.readString()
1634 | provider.Code = msgBuf.readString()
1635 | newsProviders = append(newsProviders, provider)
1636 | }
1637 |
1638 | d.wrapper.NewsProviders(newsProviders)
1639 | }
1640 |
1641 | func (d *ibDecoder) processNewsArticle(msgBuf *MsgBuffer) {
1642 | reqID := msgBuf.readInt()
1643 | articleType := msgBuf.readInt()
1644 | articleText := msgBuf.readString()
1645 |
1646 | d.wrapper.NewsArticle(reqID, articleType, articleText)
1647 | }
1648 |
1649 | func (d *ibDecoder) processHistoricalNews(msgBuf *MsgBuffer) {
1650 | reqID := msgBuf.readInt()
1651 | time := msgBuf.readString()
1652 | providerCode := msgBuf.readString()
1653 | articleID := msgBuf.readString()
1654 | headline := msgBuf.readString()
1655 |
1656 | d.wrapper.HistoricalNews(reqID, time, providerCode, articleID, headline)
1657 | }
1658 |
1659 | func (d *ibDecoder) processHistoricalNewsEnd(msgBuf *MsgBuffer) {
1660 | reqID := msgBuf.readInt()
1661 | hasMore := msgBuf.readBool()
1662 |
1663 | d.wrapper.HistoricalNewsEnd(reqID, hasMore)
1664 | }
1665 |
1666 | func (d *ibDecoder) processHistogramData(msgBuf *MsgBuffer) {
1667 | reqID := msgBuf.readInt()
1668 |
1669 | n := msgBuf.readInt()
1670 | histogram := make([]HistogramData, 0, n)
1671 | for ; n > 0; n-- {
1672 | p := HistogramData{}
1673 | p.Price = msgBuf.readFloat()
1674 | p.Count = msgBuf.readInt()
1675 | histogram = append(histogram, p)
1676 | }
1677 |
1678 | d.wrapper.HistogramData(reqID, histogram)
1679 | }
1680 |
1681 | func (d *ibDecoder) processRerouteMktDataReq(msgBuf *MsgBuffer) {
1682 | reqID := msgBuf.readInt()
1683 | contractID := msgBuf.readInt()
1684 | exchange := msgBuf.readString()
1685 |
1686 | d.wrapper.RerouteMktDataReq(reqID, contractID, exchange)
1687 | }
1688 |
1689 | func (d *ibDecoder) processRerouteMktDepthReq(msgBuf *MsgBuffer) {
1690 | reqID := msgBuf.readInt()
1691 | contractID := msgBuf.readInt()
1692 | exchange := msgBuf.readString()
1693 |
1694 | d.wrapper.RerouteMktDepthReq(reqID, contractID, exchange)
1695 | }
1696 |
1697 | func (d *ibDecoder) processMarketRuleMsg(msgBuf *MsgBuffer) {
1698 | marketRuleID := msgBuf.readInt()
1699 |
1700 | n := msgBuf.readInt()
1701 | priceIncrements := make([]PriceIncrement, 0, n)
1702 | for ; n > 0; n-- {
1703 | priceInc := PriceIncrement{}
1704 | priceInc.LowEdge = msgBuf.readFloat()
1705 | priceInc.Increment = msgBuf.readFloat()
1706 | priceIncrements = append(priceIncrements, priceInc)
1707 | }
1708 |
1709 | d.wrapper.MarketRule(marketRuleID, priceIncrements)
1710 | }
1711 |
1712 | func (d *ibDecoder) processPnLMsg(msgBuf *MsgBuffer) {
1713 | reqID := msgBuf.readInt()
1714 | dailyPnL := msgBuf.readFloat()
1715 | var unrealizedPnL float64
1716 | var realizedPnL float64
1717 |
1718 | if d.version >= mMIN_SERVER_VER_UNREALIZED_PNL {
1719 | unrealizedPnL = msgBuf.readFloat()
1720 | }
1721 |
1722 | if d.version >= mMIN_SERVER_VER_REALIZED_PNL {
1723 | realizedPnL = msgBuf.readFloat()
1724 | }
1725 |
1726 | d.wrapper.Pnl(reqID, dailyPnL, unrealizedPnL, realizedPnL)
1727 |
1728 | }
1729 | func (d *ibDecoder) processPnLSingleMsg(msgBuf *MsgBuffer) {
1730 | reqID := msgBuf.readInt()
1731 | position := msgBuf.readInt()
1732 | dailyPnL := msgBuf.readFloat()
1733 | var unrealizedPnL float64
1734 | var realizedPnL float64
1735 |
1736 | if d.version >= mMIN_SERVER_VER_UNREALIZED_PNL {
1737 | unrealizedPnL = msgBuf.readFloat()
1738 | }
1739 |
1740 | if d.version >= mMIN_SERVER_VER_REALIZED_PNL {
1741 | realizedPnL = msgBuf.readFloat()
1742 | }
1743 |
1744 | value := msgBuf.readFloat()
1745 |
1746 | d.wrapper.PnlSingle(reqID, position, dailyPnL, unrealizedPnL, realizedPnL, value)
1747 | }
1748 | func (d *ibDecoder) processHistoricalTicks(msgBuf *MsgBuffer) {
1749 | reqID := msgBuf.readInt()
1750 |
1751 | n := msgBuf.readInt()
1752 | ticks := make([]HistoricalTick, 0, n)
1753 | for ; n > 0; n-- {
1754 | historicalTick := HistoricalTick{}
1755 | historicalTick.Time = msgBuf.readInt()
1756 | _ = msgBuf.readString()
1757 | historicalTick.Price = msgBuf.readFloat()
1758 | historicalTick.Size = msgBuf.readInt()
1759 | ticks = append(ticks, historicalTick)
1760 | }
1761 |
1762 | done := msgBuf.readBool()
1763 |
1764 | d.wrapper.HistoricalTicks(reqID, ticks, done)
1765 | }
1766 | func (d *ibDecoder) processHistoricalTicksBidAsk(msgBuf *MsgBuffer) {
1767 | reqID := msgBuf.readInt()
1768 |
1769 | n := msgBuf.readInt()
1770 | ticks := make([]HistoricalTickBidAsk, 0, n)
1771 | for ; n > 0; n-- {
1772 | historicalTickBidAsk := HistoricalTickBidAsk{}
1773 | historicalTickBidAsk.Time = msgBuf.readInt()
1774 |
1775 | mask := msgBuf.readInt()
1776 | tickAttribBidAsk := TickAttribBidAsk{}
1777 | tickAttribBidAsk.AskPastHigh = mask&1 != 0
1778 | tickAttribBidAsk.BidPastLow = mask&2 != 0
1779 |
1780 | historicalTickBidAsk.TickAttirbBidAsk = tickAttribBidAsk
1781 | historicalTickBidAsk.PriceBid = msgBuf.readFloat()
1782 | historicalTickBidAsk.PriceAsk = msgBuf.readFloat()
1783 | historicalTickBidAsk.SizeBid = msgBuf.readInt()
1784 | historicalTickBidAsk.SizeAsk = msgBuf.readInt()
1785 | ticks = append(ticks, historicalTickBidAsk)
1786 | }
1787 |
1788 | done := msgBuf.readBool()
1789 |
1790 | d.wrapper.HistoricalTicksBidAsk(reqID, ticks, done)
1791 | }
1792 | func (d *ibDecoder) processHistoricalTicksLast(msgBuf *MsgBuffer) {
1793 | reqID := msgBuf.readInt()
1794 |
1795 | n := msgBuf.readInt()
1796 | ticks := make([]HistoricalTickLast, 0, n)
1797 | for ; n > 0; n-- {
1798 | historicalTickLast := HistoricalTickLast{}
1799 | historicalTickLast.Time = msgBuf.readInt()
1800 |
1801 | mask := msgBuf.readInt()
1802 | tickAttribLast := TickAttribLast{}
1803 | tickAttribLast.PastLimit = mask&1 != 0
1804 | tickAttribLast.Unreported = mask&2 != 0
1805 |
1806 | historicalTickLast.TickAttribLast = tickAttribLast
1807 | historicalTickLast.Price = msgBuf.readFloat()
1808 | historicalTickLast.Size = msgBuf.readInt()
1809 | historicalTickLast.Exchange = msgBuf.readString()
1810 | historicalTickLast.SpecialConditions = msgBuf.readString()
1811 | ticks = append(ticks, historicalTickLast)
1812 | }
1813 |
1814 | done := msgBuf.readBool()
1815 |
1816 | d.wrapper.HistoricalTicksLast(reqID, ticks, done)
1817 | }
1818 | func (d *ibDecoder) processTickByTickMsg(msgBuf *MsgBuffer) {
1819 | reqID := msgBuf.readInt()
1820 | tickType := msgBuf.readInt()
1821 | time := msgBuf.readInt()
1822 |
1823 | switch tickType {
1824 | case 0:
1825 | case 1, 2:
1826 | price := msgBuf.readFloat()
1827 | size := msgBuf.readInt()
1828 |
1829 | mask := msgBuf.readInt()
1830 | tickAttribLast := TickAttribLast{}
1831 | tickAttribLast.PastLimit = mask&1 != 0
1832 | tickAttribLast.Unreported = mask&2 != 0
1833 |
1834 | exchange := msgBuf.readString()
1835 | specialConditions := msgBuf.readString()
1836 |
1837 | d.wrapper.TickByTickAllLast(reqID, tickType, time, price, size, tickAttribLast, exchange, specialConditions)
1838 | case 3:
1839 | bidPrice := msgBuf.readFloat()
1840 | askPrice := msgBuf.readFloat()
1841 | bidSize := msgBuf.readInt()
1842 | askSize := msgBuf.readInt()
1843 |
1844 | mask := msgBuf.readInt()
1845 | tickAttribBidAsk := TickAttribBidAsk{}
1846 | tickAttribBidAsk.BidPastLow = mask&1 != 0
1847 | tickAttribBidAsk.AskPastHigh = mask&2 != 0
1848 |
1849 | d.wrapper.TickByTickBidAsk(reqID, time, bidPrice, askPrice, bidSize, askSize, tickAttribBidAsk)
1850 | case 4:
1851 | midPoint := msgBuf.readFloat()
1852 |
1853 | d.wrapper.TickByTickMidPoint(reqID, time, midPoint)
1854 | }
1855 | }
1856 |
1857 | func (d *ibDecoder) processOrderBoundMsg(msgBuf *MsgBuffer) {
1858 | reqID := msgBuf.readInt()
1859 | apiClientID := msgBuf.readInt()
1860 | apiOrderID := msgBuf.readInt()
1861 |
1862 | d.wrapper.OrderBound(reqID, apiClientID, apiOrderID)
1863 |
1864 | }
1865 |
1866 | func (d *ibDecoder) processMarketDepthL2Msg(msgBuf *MsgBuffer) {
1867 | _ = msgBuf.readString()
1868 | _ = msgBuf.readInt()
1869 | reqID := msgBuf.readInt()
1870 |
1871 | position := msgBuf.readInt()
1872 | marketMaker := msgBuf.readString()
1873 | operation := msgBuf.readInt()
1874 | side := msgBuf.readInt()
1875 | price := msgBuf.readFloat()
1876 | size := msgBuf.readInt()
1877 |
1878 | isSmartDepth := false
1879 | if d.version >= mMIN_SERVER_VER_SMART_DEPTH {
1880 | isSmartDepth = msgBuf.readBool()
1881 | }
1882 |
1883 | d.wrapper.UpdateMktDepthL2(reqID, position, marketMaker, operation, side, price, size, isSmartDepth)
1884 | }
1885 |
1886 | func (d *ibDecoder) processCompletedOrderMsg(msgBuf *MsgBuffer) {
1887 | o := &Order{}
1888 | c := &Contract{}
1889 | orderState := &OrderState{}
1890 |
1891 | version := UNSETINT
1892 |
1893 | c.ContractID = msgBuf.readInt()
1894 | c.Symbol = msgBuf.readString()
1895 | c.SecurityType = msgBuf.readString()
1896 | c.Expiry = msgBuf.readString()
1897 | c.Strike = msgBuf.readFloat()
1898 | c.Right = msgBuf.readString()
1899 |
1900 | if d.version >= 32 {
1901 | c.Multiplier = msgBuf.readString()
1902 | }
1903 |
1904 | c.Exchange = msgBuf.readString()
1905 | c.Currency = msgBuf.readString()
1906 | c.LocalSymbol = msgBuf.readString()
1907 |
1908 | if d.version >= 32 {
1909 | c.TradingClass = msgBuf.readString()
1910 | }
1911 |
1912 | o.Action = msgBuf.readString()
1913 | if d.version >= mMIN_SERVER_VER_FRACTIONAL_POSITIONS {
1914 | o.TotalQuantity = msgBuf.readFloat()
1915 | } else {
1916 | o.TotalQuantity = float64(msgBuf.readInt())
1917 | }
1918 |
1919 | o.OrderType = msgBuf.readString()
1920 | if version < 29 {
1921 | o.LimitPrice = msgBuf.readFloat()
1922 | } else {
1923 | o.LimitPrice = msgBuf.readFloatCheckUnset()
1924 | }
1925 |
1926 | if version < 30 {
1927 | o.AuxPrice = msgBuf.readFloat()
1928 | } else {
1929 | o.AuxPrice = msgBuf.readFloatCheckUnset()
1930 | }
1931 |
1932 | o.TIF = msgBuf.readString()
1933 | o.OCAGroup = msgBuf.readString()
1934 | o.Account = msgBuf.readString()
1935 | o.OpenClose = msgBuf.readString()
1936 |
1937 | o.Origin = msgBuf.readInt()
1938 |
1939 | o.OrderRef = msgBuf.readString()
1940 | o.PermID = msgBuf.readInt()
1941 |
1942 | o.OutsideRTH = msgBuf.readBool()
1943 | o.Hidden = msgBuf.readBool()
1944 | o.DiscretionaryAmount = msgBuf.readFloat()
1945 | o.GoodAfterTime = msgBuf.readString()
1946 |
1947 | o.FAGroup = msgBuf.readString()
1948 | o.FAMethod = msgBuf.readString()
1949 | o.FAPercentage = msgBuf.readString()
1950 | o.FAProfile = msgBuf.readString()
1951 |
1952 | if d.version >= mMIN_SERVER_VER_MODELS_SUPPORT {
1953 | o.ModelCode = msgBuf.readString()
1954 | }
1955 |
1956 | o.GoodTillDate = msgBuf.readString()
1957 |
1958 | o.Rule80A = msgBuf.readString()
1959 | o.PercentOffset = msgBuf.readFloatCheckUnset() //show_unset
1960 | o.SettlingFirm = msgBuf.readString()
1961 |
1962 | //ShortSaleParams
1963 | o.ShortSaleSlot = msgBuf.readInt()
1964 | o.DesignatedLocation = msgBuf.readString()
1965 |
1966 | if d.version == mMIN_SERVER_VER_SSHORTX_OLD {
1967 | _ = msgBuf.readString()
1968 | } else if version >= 23 {
1969 | o.ExemptCode = msgBuf.readInt()
1970 | }
1971 |
1972 | //BoxOrderParams
1973 | o.StartingPrice = msgBuf.readFloatCheckUnset() //show_unset
1974 | o.StockRefPrice = msgBuf.readFloatCheckUnset() //show_unset
1975 | o.Delta = msgBuf.readFloatCheckUnset() //show_unset
1976 |
1977 | //PegToStkOrVolOrderParams
1978 | o.StockRangeLower = msgBuf.readFloatCheckUnset() //show_unset
1979 | o.StockRangeUpper = msgBuf.readFloatCheckUnset() //show_unset
1980 |
1981 | o.DisplaySize = msgBuf.readInt()
1982 | o.SweepToFill = msgBuf.readBool()
1983 | o.AllOrNone = msgBuf.readBool()
1984 | o.MinQty = msgBuf.readIntCheckUnset() //show_unset
1985 | o.OCAType = msgBuf.readInt()
1986 | o.TriggerMethod = msgBuf.readInt()
1987 |
1988 | //VolOrderParams
1989 | o.Volatility = msgBuf.readFloatCheckUnset() //show_unset
1990 | o.VolatilityType = msgBuf.readInt()
1991 | o.DeltaNeutralOrderType = msgBuf.readString()
1992 | o.DeltaNeutralAuxPrice = msgBuf.readFloatCheckUnset()
1993 |
1994 | if version >= 27 && o.DeltaNeutralOrderType != "" {
1995 | o.DeltaNeutralContractID = msgBuf.readInt()
1996 | }
1997 |
1998 | if version >= 31 && o.DeltaNeutralOrderType != "" {
1999 | o.DeltaNeutralShortSale = msgBuf.readBool()
2000 | o.DeltaNeutralShortSaleSlot = msgBuf.readInt()
2001 | o.DeltaNeutralDesignatedLocation = msgBuf.readString()
2002 | }
2003 |
2004 | o.ContinuousUpdate = msgBuf.readBool()
2005 | o.ReferencePriceType = msgBuf.readInt()
2006 |
2007 | //TrailParams
2008 | o.TrailStopPrice = msgBuf.readFloatCheckUnset()
2009 | if version >= 30 {
2010 | o.TrailingPercent = msgBuf.readFloatCheckUnset() //show_unset
2011 | }
2012 |
2013 | //ComboLegs
2014 | c.ComboLegsDescription = msgBuf.readString()
2015 | if version >= 29 {
2016 | combolegN := msgBuf.readInt()
2017 | c.ComboLegs = make([]ComboLeg, 0, combolegN)
2018 | for ; combolegN > 0; combolegN-- {
2019 | // fmt.Println("comboLegsCount:", comboLegsCount)
2020 | comboleg := ComboLeg{}
2021 | comboleg.ContractID = msgBuf.readInt()
2022 | comboleg.Ratio = msgBuf.readInt()
2023 | comboleg.Action = msgBuf.readString()
2024 | comboleg.Exchange = msgBuf.readString()
2025 | comboleg.OpenClose = msgBuf.readInt()
2026 | comboleg.ShortSaleSlot = msgBuf.readInt()
2027 | comboleg.DesignatedLocation = msgBuf.readString()
2028 | comboleg.ExemptCode = msgBuf.readInt()
2029 | c.ComboLegs = append(c.ComboLegs, comboleg)
2030 | }
2031 |
2032 | orderComboLegN := msgBuf.readInt()
2033 | o.OrderComboLegs = make([]OrderComboLeg, 0, orderComboLegN)
2034 | for ; orderComboLegN > 0; orderComboLegN-- {
2035 | orderComboLeg := OrderComboLeg{}
2036 | orderComboLeg.Price = msgBuf.readFloatCheckUnset()
2037 | o.OrderComboLegs = append(o.OrderComboLegs, orderComboLeg)
2038 | }
2039 | }
2040 |
2041 | //SmartComboRoutingParams
2042 | if version >= 26 {
2043 | n := msgBuf.readInt()
2044 | o.SmartComboRoutingParams = make([]TagValue, 0, n)
2045 | for ; n > 0; n-- {
2046 | tagValue := TagValue{}
2047 | tagValue.Tag = msgBuf.readString()
2048 | tagValue.Value = msgBuf.readString()
2049 | o.SmartComboRoutingParams = append(o.SmartComboRoutingParams, tagValue)
2050 | }
2051 | }
2052 |
2053 | //ScaleOrderParams
2054 | if version >= 20 {
2055 | o.ScaleInitLevelSize = msgBuf.readIntCheckUnset() //show_unset
2056 | o.ScaleSubsLevelSize = msgBuf.readIntCheckUnset() //show_unset
2057 | } else {
2058 | o.NotSuppScaleNumComponents = msgBuf.readIntCheckUnset()
2059 | o.ScaleInitLevelSize = msgBuf.readIntCheckUnset()
2060 | }
2061 |
2062 | o.ScalePriceIncrement = msgBuf.readFloatCheckUnset()
2063 |
2064 | if version >= 28 && o.ScalePriceIncrement != UNSETFLOAT && o.ScalePriceIncrement > 0.0 {
2065 | o.ScalePriceAdjustValue = msgBuf.readFloatCheckUnset()
2066 | o.ScalePriceAdjustInterval = msgBuf.readIntCheckUnset()
2067 | o.ScaleProfitOffset = msgBuf.readFloatCheckUnset()
2068 | o.ScaleAutoReset = msgBuf.readBool()
2069 | o.ScaleInitPosition = msgBuf.readIntCheckUnset()
2070 | o.ScaleInitFillQty = msgBuf.readIntCheckUnset()
2071 | o.ScaleRandomPercent = msgBuf.readBool()
2072 | }
2073 |
2074 | //HedgeParams
2075 | if version >= 24 {
2076 | o.HedgeType = msgBuf.readString()
2077 | if o.HedgeType != "" {
2078 | o.HedgeParam = msgBuf.readString()
2079 | }
2080 | }
2081 |
2082 | o.ClearingAccount = msgBuf.readString()
2083 | o.ClearingIntent = msgBuf.readString()
2084 |
2085 | if version >= 22 {
2086 | o.NotHeld = msgBuf.readBool()
2087 | }
2088 |
2089 | // DeltaNeutral
2090 | if version >= 20 {
2091 | deltaNeutralContractPresent := msgBuf.readBool()
2092 | if deltaNeutralContractPresent {
2093 | c.DeltaNeutralContract = new(DeltaNeutralContract)
2094 | c.DeltaNeutralContract.ContractID = msgBuf.readInt()
2095 | c.DeltaNeutralContract.Delta = msgBuf.readFloat()
2096 | c.DeltaNeutralContract.Price = msgBuf.readFloat()
2097 | }
2098 | }
2099 |
2100 | if version >= 21 {
2101 | o.AlgoStrategy = msgBuf.readString()
2102 | if o.AlgoStrategy != "" {
2103 | n := msgBuf.readInt()
2104 | o.AlgoParams = make([]TagValue, 0, n)
2105 | for ; n > 0; n-- {
2106 | tagValue := TagValue{}
2107 | tagValue.Tag = msgBuf.readString()
2108 | tagValue.Value = msgBuf.readString()
2109 | o.AlgoParams = append(o.AlgoParams, tagValue)
2110 | }
2111 | }
2112 | }
2113 |
2114 | if version >= 33 {
2115 | o.Solictied = msgBuf.readBool()
2116 | }
2117 |
2118 | orderState.Status = msgBuf.readString()
2119 |
2120 | // VolRandomizeFlags
2121 | if version >= 34 {
2122 | o.RandomizeSize = msgBuf.readBool()
2123 | o.RandomizePrice = msgBuf.readBool()
2124 | }
2125 |
2126 | if d.version >= mMIN_SERVER_VER_PEGGED_TO_BENCHMARK {
2127 | // PegToBenchParams
2128 | if o.OrderType == "PEG BENCH" {
2129 | o.ReferenceContractID = msgBuf.readInt()
2130 | o.IsPeggedChangeAmountDecrease = msgBuf.readBool()
2131 | o.PeggedChangeAmount = msgBuf.readFloat()
2132 | o.ReferenceChangeAmount = msgBuf.readFloat()
2133 | o.ReferenceExchangeID = msgBuf.readString()
2134 | }
2135 |
2136 | // Conditions
2137 | if n := msgBuf.readInt(); n > 0 {
2138 | o.Conditions = make([]OrderConditioner, 0, n)
2139 | for ; n > 0; n-- {
2140 | conditionType := msgBuf.readInt()
2141 | cond, _ := InitOrderCondition(conditionType)
2142 | cond.decode(msgBuf)
2143 |
2144 | o.Conditions = append(o.Conditions, cond)
2145 | }
2146 | o.ConditionsIgnoreRth = msgBuf.readBool()
2147 | o.ConditionsCancelOrder = msgBuf.readBool()
2148 | }
2149 | }
2150 |
2151 | // StopPriceAndLmtPriceOffset
2152 | o.TrailStopPrice = msgBuf.readFloat()
2153 | o.LimitPriceOffset = msgBuf.readFloat()
2154 |
2155 | if d.version >= mMIN_SERVER_VER_CASH_QTY {
2156 | o.CashQty = msgBuf.readFloat()
2157 | }
2158 |
2159 | if d.version >= mMIN_SERVER_VER_AUTO_PRICE_FOR_HEDGE {
2160 | o.DontUseAutoPriceForHedge = msgBuf.readBool()
2161 | }
2162 |
2163 | if d.version >= mMIN_SERVER_VER_ORDER_CONTAINER {
2164 | o.IsOmsContainer = msgBuf.readBool()
2165 | }
2166 |
2167 | o.AutoCancelDate = msgBuf.readString()
2168 | o.FilledQuantity = msgBuf.readFloat()
2169 | o.RefFuturesConID = msgBuf.readInt()
2170 | o.AutoCancelParent = msgBuf.readBool()
2171 | o.Shareholder = msgBuf.readString()
2172 | o.ImbalanceOnly = msgBuf.readBool()
2173 | o.RouteMarketableToBbo = msgBuf.readBool()
2174 | o.ParentPermID = msgBuf.readInt()
2175 |
2176 | orderState.CompletedTime = msgBuf.readString()
2177 | orderState.CompletedStatus = msgBuf.readString()
2178 |
2179 | d.wrapper.CompletedOrder(c, o, orderState)
2180 | }
2181 |
2182 | // ----------------------------------------------------
2183 |
2184 | func (d *ibDecoder) processCompletedOrdersEndMsg(msgBuf *MsgBuffer) {
2185 | d.wrapper.CompletedOrdersEnd()
2186 | }
2187 |
2188 | func (d *ibDecoder) processReplaceFAEndMsg(msgBuf *MsgBuffer) {
2189 | reqID := msgBuf.readInt()
2190 | text := msgBuf.readString()
2191 |
2192 | d.wrapper.ReplaceFAEnd(reqID, text)
2193 | }
2194 |
2195 | func (d *ibDecoder) processWshMetaDataMsg(msgBuf *MsgBuffer) {
2196 | reqID := msgBuf.readInt()
2197 | dataJson := msgBuf.readString()
2198 |
2199 | d.wrapper.WshMetaData(reqID, dataJson)
2200 | }
2201 |
2202 | func (d *ibDecoder) processWshEventDataMsg(msgBuf *MsgBuffer) {
2203 | reqID := msgBuf.readInt()
2204 | dataJson := msgBuf.readString()
2205 |
2206 | d.wrapper.WshEventData(reqID, dataJson)
2207 | }
2208 |
--------------------------------------------------------------------------------
/decoder_test.go:
--------------------------------------------------------------------------------
1 | package ibapi
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | )
7 |
8 | var decoder = &ibDecoder{
9 | wrapper: &Wrapper{},
10 | }
11 |
12 | func init() {
13 | decoder.setVersion(151)
14 | decoder.setmsgID2process()
15 | }
16 |
17 | func TestDecodeLongName(t *testing.T) {
18 | longName := "\\xef"
19 | fmt.Println(longName)
20 | }
21 |
22 | func BenchmarkDecode(b *testing.B) {
23 | // log, _ = zap.NewDevelopment()
24 | msgUpdateAccountValue := []byte{54, 0, 50, 0, 78, 101, 116, 76, 105, 113, 117, 105, 100, 97, 116, 105, 111, 110, 66, 121, 67, 117, 114, 114, 101, 110, 99, 121, 0, 45, 49, 49, 48, 53, 54, 49, 50, 0, 72, 75, 68, 0, 68, 85, 49, 51, 56, 50, 56, 51, 55, 0}
25 | msgHistoricalDataUpdate := []byte{57, 48, 0, 50, 0, 50, 48, 57, 0, 50, 48, 50, 48, 48, 53, 50, 54, 32, 32, 49, 54, 58, 50, 48, 58, 48, 48, 0, 50, 51, 52, 48, 51, 0, 50, 51, 52, 48, 52, 0, 50, 51, 52, 48, 54, 0, 50, 51, 52, 48, 48, 0, 50, 51, 52, 48, 51, 46, 52, 51, 56, 49, 54, 50, 53, 52, 52, 49, 55, 0, 50, 56, 51, 0}
26 | msgUpdateMktDepthL2 := []byte{49, 51, 0, 49, 0, 51, 0, 48, 0, 72, 75, 70, 69, 0, 49, 0, 49, 0, 50, 51, 52, 48, 51, 0, 56, 0, 49, 0}
27 | msgError := []byte{52, 0, 50, 0, 45, 49, 0, 50, 49, 48, 54, 0, 72, 77, 68, 83, 32, 100, 97, 116, 97, 32, 102, 97, 114, 109, 32, 99, 111, 110, 110, 101, 99, 116, 105, 111, 110, 32, 105, 115, 32, 79, 75, 58, 102, 117, 110, 100, 102, 97, 114, 109, 0}
28 | // var updateAccountValueMsgBuf = NewMsgBuffer(nil)
29 | for i := 0; i < b.N; i++ {
30 | // updateAccountValueMsgBuf.Write(msgBytes)
31 | decoder.interpret(msgUpdateAccountValue)
32 | decoder.interpret(msgHistoricalDataUpdate)
33 | decoder.interpret(msgUpdateMktDepthL2)
34 | decoder.interpret(msgError)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/errors.go:
--------------------------------------------------------------------------------
1 | package ibapi
2 |
3 | // IbError is ib internal errors
4 | type IbError struct {
5 | code int64
6 | msg string
7 | }
8 |
9 | func (ie IbError) Error() string {
10 | return ie.msg
11 | }
12 |
13 | var (
14 | ALREADY_CONNECTED = IbError{501, "Already connected."}
15 | CONNECT_FAIL = IbError{502, `Couldn't connect to TWS. Confirm that "Enable ActiveX and Socket EClients"
16 | is enabled and connection port is the same as "Socket Port" on the
17 | TWS "Edit->Global Configuration...->API->Settings" menu. Live Trading ports:
18 | TWS: 7496; IB Gateway: 4001. Simulated Trading ports for new installations
19 | of version 954.1 or newer: TWS: 7497; IB Gateway: 4002`}
20 | UPDATE_TWS = IbError{503, "The TWS is out of date and must be upgraded."}
21 | NOT_CONNECTED = IbError{504, "Not connected"}
22 | UNKNOWN_ID = IbError{505, "Fatal Error: Unknown message id."}
23 | UNSUPPORTED_VERSION = IbError{506, "Unsupported version"}
24 | BAD_LENGTH = IbError{507, "Bad message length"}
25 | BAD_MESSAGE = IbError{508, "Bad message"}
26 | SOCKET_EXCEPTION = IbError{509, "Exception caught while reading socket - "}
27 | FAIL_CREATE_SOCK = IbError{520, "Failed to create socket"}
28 | SSL_FAIL = IbError{530, "SSL specific error: "}
29 | )
30 |
--------------------------------------------------------------------------------
/execution.go:
--------------------------------------------------------------------------------
1 | package ibapi
2 |
3 | import "fmt"
4 |
5 | // Execution is the information of an order`s execution
6 | type Execution struct {
7 | ExecID string
8 | Time string
9 | AccountCode string
10 | Exchange string
11 | Side string
12 | Shares float64
13 | Price float64
14 | PermID int64
15 | ClientID int64
16 | OrderID int64
17 | Liquidation int64
18 | CumQty float64
19 | AveragePrice float64
20 | OrderRef string
21 | EVRule string
22 | EVMultiplier float64
23 | ModelCode string
24 | LastLiquidity int64
25 | }
26 |
27 | func (e Execution) String() string {
28 | return fmt.Sprintf("ExecId: %s, Time: %s, Account: %s, Exchange: %s, Side: %s, Shares: %f, Price: %f, PermId: %d, ClientId: %d, OrderId: %d, Liquidation: %d, CumQty: %f, AvgPrice: %f, OrderRef: %s, EvRule: %s, EvMultiplier: %f, ModelCode: %s, LastLiquidity: %d",
29 | e.ExecID, e.Time, e.AccountCode, e.Exchange, e.Side, e.Shares, e.Price, e.PermID, e.ClientID, e.OrderID, e.Liquidation, e.CumQty, e.AveragePrice, e.OrderRef, e.EVRule, e.EVMultiplier, e.ModelCode, e.LastLiquidity)
30 | }
31 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/hadrianl/ibapi
2 |
3 | go 1.14
4 |
5 | require (
6 | go.uber.org/multierr v1.6.0 // indirect
7 | go.uber.org/zap v1.16.0
8 | )
9 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
7 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
8 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
9 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
10 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
11 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
12 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
13 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
14 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
15 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
16 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
17 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
18 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
19 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
20 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
21 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
22 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
23 | go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
24 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
25 | go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
26 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
27 | go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
28 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
29 | go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
30 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
31 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
32 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
33 | go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
34 | go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
35 | go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
36 | go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
37 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
38 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
39 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
40 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
41 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
42 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
43 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
44 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
45 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
46 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
47 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
48 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
49 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
50 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
51 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
52 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
53 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
54 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
55 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
56 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
57 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
58 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
59 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
60 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
61 | honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
62 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
63 |
--------------------------------------------------------------------------------
/order.go:
--------------------------------------------------------------------------------
1 | package ibapi
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | const (
8 | CUSTOMER int64 = iota
9 | FIRM
10 | UNKNOWN
11 | )
12 |
13 | const (
14 | AUCTION_UNSET int64 = iota
15 | AUCTION_MATCH
16 | AUCTION_IMPROVEMENT
17 | AUCTION_TRANSPARENT
18 | )
19 |
20 | //Order is the origin type of order,do not try to new one unless you definitely know how to fill all the fields!Use NewDefaultOrder instead!
21 | type Order struct {
22 | OrderID int64
23 | ClientID int64
24 | PermID int64
25 | Action string
26 | TotalQuantity float64
27 | OrderType string
28 | LimitPrice float64 `default:"UNSETFLOAT"`
29 | AuxPrice float64 `default:"UNSETFLOAT"`
30 | TIF string
31 | ActiveStartTime string
32 | ActiveStopTime string
33 | OCAGroup string
34 | OCAType int64 // 1 = CANCEL_WITH_BLOCK, 2 = REDUCE_WITH_BLOCK, 3 = REDUCE_NON_BLOCK
35 | OrderRef string
36 | Transmit bool `default:"true"`
37 | ParentID int64
38 | BlockOrder bool
39 | SweepToFill bool
40 | DisplaySize int64
41 | TriggerMethod int64 // 0=Default, 1=Double_Bid_Ask, 2=Last, 3=Double_Last, 4=Bid_Ask, 7=Last_or_Bid_Ask, 8=Mid-point
42 | OutsideRTH bool
43 | Hidden bool
44 | GoodAfterTime string // Format: 20060505 08:00:00 {time zone}
45 | GoodTillDate string // Format: 20060505 08:00:00 {time zone}
46 | OverridePercentageConstraints bool
47 | Rule80A string // Individual = 'I', Agency = 'A', AgentOtherMember = 'W', IndividualPTIA = 'J', AgencyPTIA = 'U', AgentOtherMemberPTIA = 'M', IndividualPT = 'K', AgencyPT = 'Y', AgentOtherMemberPT = 'N'
48 | AllOrNone bool
49 | MinQty int64 `default:"UNSETINT"`
50 | PercentOffset float64 `default:"UNSETFLOAT"` // REL orders only
51 | TrailStopPrice float64 `default:"UNSETFLOAT"`
52 | TrailingPercent float64 `default:"UNSETFLOAT"` // TRAILLIMIT orders only
53 | //---- financial advisors only -----
54 | FAGroup string
55 | FAProfile string
56 | FAMethod string
57 | FAPercentage string
58 | // ---------------------------------
59 | // ---------institutional only------
60 | OpenClose string // O=Open, C=Close
61 | Origin int64 // 0=Customer, 1=Firm
62 | ShortSaleSlot int64 // 1 if you hold the shares, 2 if they will be delivered from elsewhere. Only for Action=SSHORT
63 | DesignatedLocation string // used only when shortSaleSlot=2
64 | ExemptCode int64 `default:"-1"`
65 | // ---------------------------------
66 | // ------- SMART routing only ------
67 | DiscretionaryAmount float64
68 | ETradeOnly bool `default:"true"`
69 | FirmQuoteOnly bool `default:"true"`
70 | NBBOPriceCap float64 `default:"UNSETFLOAT"`
71 | OptOutSmartRouting bool
72 | // --------------------------------
73 | // ---BOX exchange orders only ----
74 | AuctionStrategy int64
75 | StartingPrice float64 `default:"UNSETFLOAT"`
76 | StockRefPrice float64 `default:"UNSETFLOAT"`
77 | Delta float64 `default:"UNSETFLOAT"`
78 | // --------------------------------
79 | // --pegged to stock and VOL orders only--
80 | StockRangeLower float64 `default:"UNSETFLOAT"`
81 | StockRangeUpper float64 `default:"UNSETFLOAT"`
82 |
83 | RandomizePrice bool
84 | RandomizeSize bool
85 |
86 | // ---VOLATILITY ORDERS ONLY--------
87 | Volatility float64 `default:"UNSETFLOAT"`
88 | VolatilityType int64 `default:"UNSETINT"`
89 | DeltaNeutralOrderType string
90 | DeltaNeutralAuxPrice float64 `default:"UNSETFLOAT"`
91 | DeltaNeutralContractID int64
92 | DeltaNeutralSettlingFirm string
93 | DeltaNeutralClearingAccount string
94 | DeltaNeutralClearingIntent string
95 | DeltaNeutralOpenClose string
96 | DeltaNeutralShortSale bool
97 | DeltaNeutralShortSaleSlot int64
98 | DeltaNeutralDesignatedLocation string
99 | ContinuousUpdate bool
100 | ReferencePriceType int64 `default:"UNSETINT"` // 1=Average, 2 = BidOrAsk
101 | // DeltaNeutral DeltaNeutralData `when:"DeltaNeutralOrderType" cond:"is" value:""`
102 | // -------------------------------------
103 | // ------COMBO ORDERS ONLY-----------
104 | BasisPoints float64 `default:"UNSETFLOAT"` // EFP orders only
105 | BasisPointsType int64 `default:"UNSETINT"` // EFP orders only
106 | // -----------------------------------
107 | //-----------SCALE ORDERS ONLY------------
108 | ScaleInitLevelSize int64 `default:"UNSETINT"`
109 | ScaleSubsLevelSize int64 `default:"UNSETINT"`
110 | ScalePriceIncrement float64 `default:"UNSETFLOAT"`
111 | ScalePriceAdjustValue float64 `default:"UNSETFLOAT"`
112 | ScalePriceAdjustInterval int64 `default:"UNSETINT"`
113 | ScaleProfitOffset float64 `default:"UNSETFLOAT"`
114 | ScaleAutoReset bool
115 | ScaleInitPosition int64 `default:"UNSETINT"`
116 | ScaleInitFillQty int64 `default:"UNSETINT"`
117 | ScaleRandomPercent bool
118 | ScaleTable string
119 | NotSuppScaleNumComponents int64
120 | //--------------------------------------
121 | // ---------HEDGE ORDERS--------------
122 | HedgeType string
123 | HedgeParam string
124 | //--------------------------------------
125 | //-----------Clearing info ----------------
126 | Account string
127 | SettlingFirm string
128 | ClearingAccount string // True beneficiary of the order
129 | ClearingIntent string // "" (Default), "IB", "Away", "PTA" (PostTrade)
130 | // ----------------------------------------
131 | // --------- ALGO ORDERS ONLY --------------
132 | AlgoStrategy string
133 |
134 | AlgoParams []TagValue
135 | SmartComboRoutingParams []TagValue
136 | AlgoID string
137 | // -----------------------------------------
138 |
139 | // ----------what if order -------------------
140 | WhatIf bool
141 |
142 | // --------------Not Held ------------------
143 | NotHeld bool
144 | Solictied bool
145 | //--------------------------------------
146 |
147 | // models
148 | ModelCode string
149 |
150 | // ------order combo legs -----------------
151 | OrderComboLegs []OrderComboLeg
152 | OrderMiscOptions []TagValue
153 | //----------------------------------------
154 | //-----------VER PEG2BENCH fields----------
155 | ReferenceContractID int64
156 | PeggedChangeAmount float64
157 | IsPeggedChangeAmountDecrease bool
158 | ReferenceChangeAmount float64
159 | ReferenceExchangeID string
160 | AdjustedOrderType string
161 | TriggerPrice float64 `default:"UNSETFLOAT"`
162 | AdjustedStopPrice float64 `default:"UNSETFLOAT"`
163 | AdjustedStopLimitPrice float64 `default:"UNSETFLOAT"`
164 | AdjustedTrailingAmount float64 `default:"UNSETFLOAT"`
165 | AdjustableTrailingUnit int64
166 | LimitPriceOffset float64 `default:"UNSETFLOAT"`
167 |
168 | Conditions []OrderConditioner
169 | ConditionsCancelOrder bool
170 | ConditionsIgnoreRth bool
171 |
172 | //------ext operator--------------
173 | ExtOperator string
174 |
175 | //-----native cash quantity --------
176 | CashQty float64 `default:"UNSETFLOAT"`
177 |
178 | //--------------------------------
179 | Mifid2DecisionMaker string
180 | Mifid2DecisionAlgo string
181 | Mifid2ExecutionTrader string
182 | Mifid2ExecutionAlgo string
183 |
184 | //-------------
185 | DontUseAutoPriceForHedge bool
186 |
187 | IsOmsContainer bool
188 |
189 | DiscretionaryUpToLimitPrice bool
190 |
191 | AutoCancelDate string
192 | FilledQuantity float64 `default:"UNSETFLOAT"`
193 | RefFuturesConID int64
194 | AutoCancelParent bool
195 | Shareholder string
196 | ImbalanceOnly bool
197 | RouteMarketableToBbo bool
198 | ParentPermID int64
199 |
200 | UsePriceMgmtAlgo bool
201 | Duration int64 `default:"UNSETINT"`
202 | PostToAts int64 `default:"UNSETINT"`
203 |
204 | SoftDollarTier SoftDollarTier
205 | }
206 |
207 | func (o Order) String() string {
208 | s := fmt.Sprintf("Order -- <%s %s %.2f@%f %s> --",
209 | o.OrderID,
210 | o.ClientID,
211 | o.PermID,
212 | o.OrderType,
213 | o.Action,
214 | o.TotalQuantity,
215 | o.LimitPrice,
216 | o.TIF)
217 |
218 | for i, leg := range o.OrderComboLegs {
219 | s += fmt.Sprintf(" CMB<%d>-%s", i, leg)
220 | }
221 |
222 | for i, cond := range o.Conditions {
223 | s += fmt.Sprintf(" COND<%d>-%s", i, cond)
224 | }
225 |
226 | return s
227 | }
228 |
229 | // OrderState is the state of Order
230 | type OrderState struct {
231 | Status string
232 | InitialMarginBefore string
233 | InitialMarginChange string
234 | InitialMarginAfter string
235 | MaintenanceMarginBefore string
236 | MaintenanceMarginChange string
237 | MaintenanceMarginAfter string
238 | EquityWithLoanBefore string
239 | EquityWithLoanChange string
240 | EquityWithLoanAfter string
241 | Commission float64 `default:"UNSETFLOAT"`
242 | MinCommission float64 `default:"UNSETFLOAT"`
243 | MaxCommission float64 `default:"UNSETFLOAT"`
244 | CommissionCurrency string
245 | WarningText string
246 | CompletedTime string
247 | CompletedStatus string
248 | }
249 |
250 | func (state OrderState) String() string {
251 | return fmt.Sprintf(
252 | "OrderState",
253 | state.Status,
254 | state.Commission,
255 | state.CommissionCurrency,
256 | state.CompletedTime,
257 | state.CompletedStatus,
258 | )
259 | }
260 |
261 | // SoftDollarTier is a container for storing Soft Dollar Tier information
262 | type SoftDollarTier struct {
263 | Name string
264 | Value string
265 | DisplayName string
266 | }
267 |
268 | func (s SoftDollarTier) String() string {
269 | return fmt.Sprintf("SoftDollarTier",
270 | s.Name,
271 | s.Value,
272 | s.DisplayName)
273 | }
274 |
275 | // NewOrder create a default order
276 | func NewOrder() *Order {
277 | order := &Order{}
278 | order.LimitPrice = UNSETFLOAT
279 | order.AuxPrice = UNSETFLOAT
280 |
281 | order.Transmit = true
282 |
283 | order.MinQty = UNSETINT
284 | order.PercentOffset = UNSETFLOAT
285 | order.TrailStopPrice = UNSETFLOAT
286 | order.TrailingPercent = UNSETFLOAT
287 |
288 | order.OpenClose = "O"
289 |
290 | order.ExemptCode = -1
291 |
292 | order.ETradeOnly = true
293 | order.FirmQuoteOnly = true
294 | order.NBBOPriceCap = UNSETFLOAT
295 |
296 | order.AuctionStrategy = AUCTION_UNSET
297 | order.StartingPrice = UNSETFLOAT
298 | order.StockRefPrice = UNSETFLOAT
299 | order.Delta = UNSETFLOAT
300 |
301 | order.StockRangeLower = UNSETFLOAT
302 | order.StockRangeUpper = UNSETFLOAT
303 |
304 | order.Volatility = UNSETFLOAT
305 | order.VolatilityType = UNSETINT
306 | order.DeltaNeutralAuxPrice = UNSETFLOAT
307 | order.ReferencePriceType = UNSETINT
308 |
309 | order.BasisPoints = UNSETFLOAT
310 | order.BasisPointsType = UNSETINT
311 |
312 | order.ScaleInitLevelSize = UNSETINT
313 | order.ScaleSubsLevelSize = UNSETINT
314 | order.ScalePriceIncrement = UNSETFLOAT
315 | order.ScalePriceAdjustValue = UNSETFLOAT
316 | order.ScalePriceAdjustInterval = UNSETINT
317 | order.ScaleProfitOffset = UNSETFLOAT
318 | order.ScaleInitPosition = UNSETINT
319 | order.ScaleInitFillQty = UNSETINT
320 |
321 | order.TriggerPrice = UNSETFLOAT
322 | order.AdjustedStopPrice = UNSETFLOAT
323 | order.AdjustedStopLimitPrice = UNSETFLOAT
324 | order.AdjustedTrailingAmount = UNSETFLOAT
325 | order.LimitPriceOffset = UNSETFLOAT
326 |
327 | order.CashQty = UNSETFLOAT
328 | order.FilledQuantity = UNSETFLOAT
329 | order.Duration = UNSETINT
330 | order.PostToAts = UNSETINT
331 |
332 | return order
333 | }
334 |
335 | // NewLimitOrder create a limit order with action, limit price and quantity
336 | func NewLimitOrder(action string, lmtPrice float64, quantity float64) *Order {
337 | o := NewOrder()
338 | o.OrderType = "LMT"
339 | o.Action = action
340 | o.LimitPrice = lmtPrice
341 | o.TotalQuantity = quantity
342 |
343 | return o
344 | }
345 |
346 | // NewMarketOrder create a market order with action and quantity
347 | func NewMarketOrder(action string, quantity float64) *Order {
348 | o := NewOrder()
349 | o.OrderType = "MKT"
350 | o.Action = action
351 | o.TotalQuantity = quantity
352 |
353 | return o
354 | }
355 |
--------------------------------------------------------------------------------
/orderCondition.go:
--------------------------------------------------------------------------------
1 | /*
2 | ordercondition contains several OrderCondition, such as Price, Time, Margin, Execution, Volume, PercentChange
3 | */
4 |
5 | package ibapi
6 |
7 | import "go.uber.org/zap"
8 |
9 | type OrderConditioner interface {
10 | CondType() int64
11 | setCondType(condType int64)
12 | decode(*MsgBuffer)
13 | toFields() []interface{}
14 | }
15 |
16 | type OrderCondition struct {
17 | conditionType int64
18 | IsConjunctionConnection bool
19 |
20 | // Price = 1
21 | // Time = 3
22 | // Margin = 4
23 | // Execution = 5
24 | // Volume = 6
25 | // PercentChange = 7
26 | }
27 |
28 | func (oc OrderCondition) decode(msgBuf *MsgBuffer) {
29 | connector := msgBuf.readString()
30 | oc.IsConjunctionConnection = connector == "a"
31 | }
32 |
33 | func (oc OrderCondition) toFields() []interface{} {
34 | if oc.IsConjunctionConnection {
35 | return []interface{}{"a"}
36 | }
37 | return []interface{}{"o"}
38 | }
39 |
40 | func (oc OrderCondition) CondType() int64 {
41 | return oc.conditionType
42 | }
43 |
44 | func (oc OrderCondition) setCondType(condType int64) {
45 | oc.conditionType = condType
46 | }
47 |
48 | type ExecutionCondition struct {
49 | OrderCondition
50 | SecType string
51 | Exchange string
52 | Symbol string
53 | }
54 |
55 | func (ec ExecutionCondition) decode(msgBuf *MsgBuffer) { // 4 fields
56 | ec.OrderCondition.decode(msgBuf)
57 | ec.SecType = msgBuf.readString()
58 | ec.Exchange = msgBuf.readString()
59 | ec.Symbol = msgBuf.readString()
60 | }
61 |
62 | func (ec ExecutionCondition) toFields() []interface{} {
63 | return append(ec.OrderCondition.toFields(), ec.SecType, ec.Exchange, ec.Symbol)
64 | }
65 |
66 | type OperatorCondition struct {
67 | OrderCondition
68 | IsMore bool
69 | }
70 |
71 | func (oc OperatorCondition) decode(msgBuf *MsgBuffer) { // 2 fields
72 | oc.OrderCondition.decode(msgBuf)
73 | oc.IsMore = msgBuf.readBool()
74 | }
75 |
76 | func (oc OperatorCondition) toFields() []interface{} {
77 | return append(oc.OrderCondition.toFields(), oc.IsMore)
78 | }
79 |
80 | type MarginCondition struct {
81 | OperatorCondition
82 | Percent float64
83 | }
84 |
85 | func (mc MarginCondition) decode(msgBuf *MsgBuffer) { // 3 fields
86 | mc.OperatorCondition.decode(msgBuf)
87 | mc.Percent = msgBuf.readFloat()
88 | }
89 |
90 | func (mc MarginCondition) toFields() []interface{} {
91 | return append(mc.OperatorCondition.toFields(), mc.Percent)
92 | }
93 |
94 | type ContractCondition struct {
95 | OperatorCondition
96 | ConID int64
97 | Exchange string
98 | }
99 |
100 | func (cc ContractCondition) decode(msgBuf *MsgBuffer) { // 4 fields
101 | cc.OperatorCondition.decode(msgBuf)
102 | cc.ConID = msgBuf.readInt()
103 | cc.Exchange = msgBuf.readString()
104 | }
105 |
106 | func (cc ContractCondition) toFields() []interface{} {
107 | return append(cc.OperatorCondition.toFields(), cc.ConID, cc.Exchange)
108 | }
109 |
110 | type TimeCondition struct {
111 | OperatorCondition
112 | Time string
113 | }
114 |
115 | func (tc TimeCondition) decode(msgBuf *MsgBuffer) { // 3 fields
116 | tc.OperatorCondition.decode(msgBuf)
117 | // tc.Time = decodeTime(fields[2], "20060102")
118 | tc.Time = msgBuf.readString()
119 | }
120 |
121 | func (tc TimeCondition) toFields() []interface{} {
122 | return append(tc.OperatorCondition.toFields(), tc.Time)
123 | }
124 |
125 | type PriceCondition struct {
126 | ContractCondition
127 | Price float64
128 | TriggerMethod int64
129 | }
130 |
131 | func (pc PriceCondition) decode(msgBuf *MsgBuffer) { // 6 fields
132 | pc.ContractCondition.decode(msgBuf)
133 | pc.Price = msgBuf.readFloat()
134 | pc.TriggerMethod = msgBuf.readInt()
135 | }
136 |
137 | func (pc PriceCondition) toFields() []interface{} {
138 | return append(pc.ContractCondition.toFields(), pc.Price, pc.TriggerMethod)
139 | }
140 |
141 | type PercentChangeCondition struct {
142 | ContractCondition
143 | ChangePercent float64
144 | }
145 |
146 | func (pcc PercentChangeCondition) decode(msgBuf *MsgBuffer) { // 5 fields
147 | pcc.ContractCondition.decode(msgBuf)
148 | pcc.ChangePercent = msgBuf.readFloat()
149 | }
150 |
151 | func (pcc PercentChangeCondition) toFields() []interface{} {
152 | return append(pcc.ContractCondition.toFields(), pcc.ChangePercent)
153 | }
154 |
155 | type VolumeCondition struct {
156 | ContractCondition
157 | Volume int64
158 | }
159 |
160 | func (vc VolumeCondition) decode(msgBuf *MsgBuffer) { // 5 fields
161 | vc.ContractCondition.decode(msgBuf)
162 | vc.Volume = msgBuf.readInt()
163 | }
164 |
165 | func (vc VolumeCondition) toFields() []interface{} {
166 | return append(vc.ContractCondition.toFields(), vc.Volume)
167 | }
168 |
169 | func InitOrderCondition(conType int64) (OrderConditioner, int) {
170 | var cond OrderConditioner
171 | var condSize int
172 | switch conType {
173 | case 1:
174 | cond = PriceCondition{}
175 | cond.setCondType(1)
176 | condSize = 6
177 | case 3:
178 | cond = TimeCondition{}
179 | cond.setCondType(3)
180 | condSize = 3
181 | case 4:
182 | cond = MarginCondition{}
183 | cond.setCondType(4)
184 | condSize = 3
185 | case 5:
186 | cond = ExecutionCondition{}
187 | cond.setCondType(5)
188 | condSize = 4
189 | case 6:
190 | cond = VolumeCondition{}
191 | cond.setCondType(6)
192 | condSize = 5
193 | case 7:
194 | cond = PercentChangeCondition{}
195 | cond.setCondType(7)
196 | condSize = 5
197 | default:
198 | log.Panic("unkonwn conType",
199 | zap.Int64("conType", conType),
200 | )
201 | }
202 | return cond, condSize
203 | }
204 |
--------------------------------------------------------------------------------
/scanner.go:
--------------------------------------------------------------------------------
1 | package ibapi
2 |
3 | import "fmt"
4 |
5 | // ScanData is the data retureed by IB, which matches the ScannerSubscription
6 | type ScanData struct {
7 | ContractDetails ContractDetails
8 | Rank int64
9 | Distance string
10 | Benchmark string
11 | Projection string
12 | Legs string
13 | }
14 |
15 | func (s ScanData) String() string {
16 | return fmt.Sprintf("Rank: %d, ContractDetails: %v, Distance: %s, Benchmark: %s, Projection: %s, Legs String: %s",
17 | s.Rank,
18 | s.ContractDetails,
19 | s.Distance,
20 | s.Benchmark,
21 | s.Projection,
22 | s.Legs)
23 | }
24 |
25 | // ScannerSubscription defines a market scanner request
26 | type ScannerSubscription struct {
27 | NumberOfRows int64 `default:"-1"`
28 | Instrument string
29 | LocationCode string
30 | ScanCode string
31 | AbovePrice float64 `default:"UNSETFLOAT"`
32 | BelowPrice float64 `default:"UNSETFLOAT"`
33 | AboveVolume int64 `default:"UNSETINT"`
34 | MarketCapAbove float64 `default:"UNSETFLOAT"`
35 | MarketCapBelow float64 `default:"UNSETFLOAT"`
36 | MoodyRatingAbove string
37 | MoodyRatingBelow string
38 | SpRatingAbove string
39 | SpRatingBelow string
40 | MaturityDateAbove string
41 | MaturityDateBelow string
42 | CouponRateAbove float64 `default:"UNSETFLOAT"`
43 | CouponRateBelow float64 `default:"UNSETFLOAT"`
44 | ExcludeConvertible bool
45 | AverageOptionVolumeAbove int64 `default:"UNSETINT"`
46 | ScannerSettingPairs string
47 | StockTypeFilter string
48 | }
49 |
50 | func (s ScannerSubscription) String() string {
51 | return fmt.Sprintf("Instrument: %s, LocationCode: %s, ScanCode: %s",
52 | s.Instrument,
53 | s.LocationCode,
54 | s.ScanCode)
55 | }
56 |
57 | // NewScannerSubscription create a default ScannerSubscription
58 | func NewScannerSubscription() *ScannerSubscription {
59 | scannerSubscription := &ScannerSubscription{}
60 |
61 | scannerSubscription.NumberOfRows = -1
62 | scannerSubscription.AbovePrice = UNSETFLOAT
63 | scannerSubscription.BelowPrice = UNSETFLOAT
64 | scannerSubscription.AboveVolume = UNSETINT
65 | scannerSubscription.MarketCapAbove = UNSETFLOAT
66 | scannerSubscription.MarketCapBelow = UNSETFLOAT
67 |
68 | scannerSubscription.CouponRateAbove = UNSETFLOAT
69 | scannerSubscription.CouponRateBelow = UNSETFLOAT
70 | scannerSubscription.AverageOptionVolumeAbove = UNSETINT
71 |
72 | return scannerSubscription
73 | }
74 |
--------------------------------------------------------------------------------
/utils.go:
--------------------------------------------------------------------------------
1 | package ibapi
2 |
3 | import (
4 | "bufio"
5 | "bytes"
6 | "encoding/binary"
7 | "io"
8 | "math"
9 | "reflect"
10 | "strconv"
11 | "time"
12 |
13 | "go.uber.org/zap"
14 | // log "github.com/sirupsen/logrus"
15 | )
16 |
17 | const (
18 | fieldSplit byte = '\x00'
19 | // UNSETFLOAT represent unset value of float64.
20 | UNSETFLOAT float64 = math.MaxFloat64
21 | // UNSETINT represent unset value of int64.
22 | UNSETINT int64 = math.MaxInt64
23 | // NO_VALID_ID represent that the callback func of wrapper is not attached to any request.
24 | NO_VALID_ID int64 = -1
25 | // MAX_MSG_LEN is the max length that receiver could take.
26 | MAX_MSG_LEN int = 0xFFFFFF
27 | )
28 |
29 | var log *zap.Logger
30 |
31 | func init() {
32 | log, _ = zap.NewProduction()
33 | }
34 |
35 | // APILogger sets the options of internal logger for API, such as level, encoder, output, see uber.org/zap for more information
36 | func SetAPILogger(cfg zap.Config, opts ...zap.Option) error {
37 | newlogger, err := cfg.Build(opts...)
38 | log = newlogger
39 | return err
40 | }
41 |
42 | // GetLogger gets a clone of the internal logger with the option, see uber.org/zap for more information
43 | func GetLogger() *zap.Logger {
44 | return log
45 | }
46 |
47 | func bytesToTime(b []byte) time.Time {
48 | // format := "20060102 15:04:05 Mountain Standard Time"
49 | // 214 208 185 250 177 234 215 188 202 177 188 228
50 | format := "20060102 15:04:05 MST"
51 | t := string(b)
52 | localtime, err := time.ParseInLocation(format, t, time.Local)
53 | if err != nil {
54 | log.Error("btyes to time error", zap.Error(err))
55 | }
56 | return localtime
57 | }
58 |
59 | // readMsgBytes try to read the msg based on the message size
60 | func readMsgBytes(reader *bufio.Reader) ([]byte, error) {
61 | sizeBytes := make([]byte, 4) // sync.Pool?
62 | //try to get 4bytes sizeBytes
63 | for n, r := 0, 4; n < r; {
64 | tempMsgBytes := make([]byte, r-n)
65 | tn, err := reader.Read(tempMsgBytes)
66 | if err != nil {
67 | return nil, err
68 | }
69 |
70 | copy(sizeBytes[n:n+tn], tempMsgBytes)
71 | n += tn
72 | }
73 |
74 | size := int(binary.BigEndian.Uint32(sizeBytes))
75 | log.Debug("readMsgBytes", zap.Int("size", size))
76 |
77 | msgBytes := make([]byte, size)
78 |
79 | // XXX: maybe there is a better way to get fixed size of bytes
80 | for n, r := 0, size; n < r; {
81 | tempMsgBytes := make([]byte, r-n)
82 | tn, err := reader.Read(tempMsgBytes)
83 | if err != nil {
84 | return nil, err
85 | }
86 |
87 | copy(msgBytes[n:n+tn], tempMsgBytes)
88 | n += tn
89 |
90 | }
91 |
92 | log.Debug("readMsgBytes", zap.Binary("msgBytes", msgBytes))
93 | return msgBytes, nil
94 |
95 | }
96 |
97 | // scanFields defines how to unpack the buf
98 | func scanFields(data []byte, atEOF bool) (advance int, token []byte, err error) {
99 | if atEOF {
100 | return 0, nil, io.EOF
101 | }
102 |
103 | if len(data) < 4 {
104 | return 0, nil, nil
105 | }
106 |
107 | totalSize := int(binary.BigEndian.Uint32(data[:4])) + 4
108 |
109 | if totalSize > len(data) {
110 | return 0, nil, nil
111 | }
112 |
113 | // msgBytes := make([]byte, totalSize-4, totalSize-4)
114 | // copy(msgBytes, data[4:totalSize])
115 | // not copy here, copied by callee more reasonable
116 | return totalSize, data[4:totalSize], nil
117 | }
118 |
119 | // func field2Bytes(field interface{}) []byte {
120 | // // var bs []byte
121 | // bs := make([]byte, 0, 9)
122 |
123 | // switch v := field.(type) {
124 |
125 | // case int64:
126 | // bs = encodeInt64(v)
127 | // case float64:
128 | // bs = encodeFloat64(v)
129 | // case string:
130 | // bs = encodeString(v)
131 | // case bool:
132 | // bs = encodeBool(v)
133 | // case int:
134 | // bs = encodeInt(v)
135 | // case []byte:
136 | // bs = v
137 |
138 | // // case time.Time:
139 | // // b = encodeTime(msg.(time.Time))
140 |
141 | // default:
142 | // log.Panic("failed to covert the field", zap.Reflect("field", field))
143 | // }
144 |
145 | // return append(bs, fieldSplit)
146 | // }
147 |
148 | // makeMsgBytes is a universal way to make the request ,but not an efficient way
149 | // TODO: do some test and improve!!!
150 | func makeMsgBytes(fields ...interface{}) []byte {
151 |
152 | msgBytes := make([]byte, 4, 8*len(fields)+4) // pre alloc memory
153 |
154 | for _, f := range fields {
155 | switch v := f.(type) {
156 | case int64:
157 | msgBytes = strconv.AppendInt(msgBytes, v, 10)
158 | case float64:
159 | msgBytes = strconv.AppendFloat(msgBytes, v, 'g', 10, 64)
160 | case string:
161 | msgBytes = append(msgBytes, []byte(v)...)
162 | case bool:
163 | if v {
164 | msgBytes = append(msgBytes, '1')
165 | } else {
166 | msgBytes = append(msgBytes, '0')
167 | }
168 | case int:
169 | msgBytes = strconv.AppendInt(msgBytes, int64(v), 10)
170 | case []byte:
171 | msgBytes = append(msgBytes, v...)
172 | default:
173 | log.Panic("failed to covert the field", zap.Reflect("field", f)) // never reach here
174 | }
175 |
176 | msgBytes = append(msgBytes, fieldSplit)
177 | }
178 |
179 | // add the size header
180 | binary.BigEndian.PutUint32(msgBytes, uint32(len(msgBytes)-4))
181 |
182 | return msgBytes
183 | }
184 |
185 | func splitMsgBytes(data []byte) [][]byte {
186 | fields := bytes.Split(data, []byte{fieldSplit})
187 | return fields[:len(fields)-1]
188 | }
189 |
190 | func decodeInt(field []byte) int64 {
191 | if bytes.Equal(field, []byte{}) {
192 | return 0
193 | }
194 | i, err := strconv.ParseInt(string(field), 10, 64)
195 | if err != nil {
196 | log.Panic("failed to decode int", zap.Error(err))
197 | }
198 | return i
199 | }
200 |
201 | func decodeString(field []byte) string {
202 | return string(field)
203 | }
204 |
205 | // func encodeInt64(i int64) []byte {
206 | // return []byte(strconv.FormatInt(i, 10))
207 | // }
208 |
209 | // func encodeInt(i int) []byte {
210 | // return []byte(strconv.Itoa(i))
211 | // }
212 |
213 | // func encodeFloat64(f float64) []byte {
214 | // return []byte(strconv.FormatFloat(f, 'g', 10, 64))
215 | // }
216 |
217 | // func encodeString(str string) []byte {
218 | // return []byte(str)
219 | // }
220 |
221 | // func encodeBool(b bool) []byte {
222 | // if b {
223 | // return []byte{'1'}
224 | // }
225 | // return []byte{'0'}
226 |
227 | // }
228 |
229 | func handleEmpty(d interface{}) string {
230 | switch v := d.(type) {
231 | case int64:
232 | if v == UNSETINT {
233 | return ""
234 | }
235 | return strconv.FormatInt(v, 10)
236 |
237 | case float64:
238 | if v == UNSETFLOAT {
239 | return ""
240 | }
241 | return strconv.FormatFloat(v, 'g', 10, 64)
242 |
243 | default:
244 | log.Panic("no handler for such type", zap.Reflect("val", d))
245 | return "" // never reach here
246 | }
247 | }
248 |
249 | //InitDefault try to init the object with the default tag, that is a common way but not a efficent way
250 | func InitDefault(o interface{}) {
251 | t := reflect.TypeOf(o).Elem()
252 | v := reflect.ValueOf(o).Elem()
253 |
254 | fieldCount := t.NumField()
255 |
256 | for i := 0; i < fieldCount; i++ {
257 | field := t.Field(i)
258 |
259 | if v.Field(i).Kind() == reflect.Struct {
260 | InitDefault(v.Field(i).Addr().Interface())
261 | continue
262 | }
263 |
264 | if defaultValue, ok := field.Tag.Lookup("default"); ok {
265 |
266 | switch defaultValue {
267 | case "UNSETFLOAT":
268 | v.Field(i).SetFloat(UNSETFLOAT)
269 | case "UNSETINT":
270 | v.Field(i).SetInt(UNSETINT)
271 | case "-1":
272 | v.Field(i).SetInt(-1)
273 | case "true":
274 | v.Field(i).SetBool(true)
275 | default:
276 | log.Panic("Unknown defaultValue", zap.Reflect("default", v))
277 | }
278 | }
279 |
280 | }
281 | }
282 |
283 | // MsgBuffer is the buffer that contains a whole msg
284 | type MsgBuffer struct {
285 | bytes.Buffer
286 | bs []byte
287 | err error
288 | }
289 |
290 | func (m *MsgBuffer) readInt() int64 {
291 | var i int64
292 | m.bs, m.err = m.ReadBytes(fieldSplit)
293 | if m.err != nil {
294 | log.Panic("decode int64 error", zap.Error(m.err))
295 | }
296 |
297 | m.bs = m.bs[:len(m.bs)-1]
298 | if bytes.Equal(m.bs, nil) {
299 | return 0
300 | }
301 |
302 | i, m.err = strconv.ParseInt(string(m.bs), 10, 64)
303 | if m.err != nil {
304 | log.Panic("decode int64 error", zap.Error(m.err))
305 | }
306 |
307 | return i
308 | }
309 |
310 | func (m *MsgBuffer) readIntCheckUnset() int64 {
311 | var i int64
312 | m.bs, m.err = m.ReadBytes(fieldSplit)
313 | if m.err != nil {
314 | log.Panic("decode int64 error", zap.Error(m.err))
315 | }
316 |
317 | m.bs = m.bs[:len(m.bs)-1]
318 | if bytes.Equal(m.bs, nil) {
319 | return UNSETINT
320 | }
321 |
322 | i, m.err = strconv.ParseInt(string(m.bs), 10, 64)
323 | if m.err != nil {
324 | log.Panic("decode int64 error", zap.Error(m.err))
325 | }
326 |
327 | return i
328 | }
329 |
330 | func (m *MsgBuffer) readFloat() float64 {
331 | var f float64
332 | m.bs, m.err = m.ReadBytes(fieldSplit)
333 | if m.err != nil {
334 | log.Panic("decode float64 error", zap.Error(m.err))
335 | }
336 |
337 | m.bs = m.bs[:len(m.bs)-1]
338 | if bytes.Equal(m.bs, nil) {
339 | return 0.0
340 | }
341 |
342 | f, m.err = strconv.ParseFloat(string(m.bs), 64)
343 | if m.err != nil {
344 | log.Panic("decode float64 error", zap.Error(m.err))
345 | }
346 |
347 | return f
348 | }
349 |
350 | func (m *MsgBuffer) readFloatCheckUnset() float64 {
351 | var f float64
352 | m.bs, m.err = m.ReadBytes(fieldSplit)
353 | if m.err != nil {
354 | log.Panic("decode float64 error", zap.Error(m.err))
355 | }
356 |
357 | m.bs = m.bs[:len(m.bs)-1]
358 | if bytes.Equal(m.bs, nil) {
359 | return UNSETFLOAT
360 | }
361 |
362 | f, m.err = strconv.ParseFloat(string(m.bs), 64)
363 | if m.err != nil {
364 | log.Panic("decode float64 error", zap.Error(m.err))
365 | }
366 |
367 | return f
368 | }
369 |
370 | func (m *MsgBuffer) readBool() bool {
371 | m.bs, m.err = m.ReadBytes(fieldSplit)
372 | if m.err != nil {
373 | log.Panic("decode bool error", zap.Error(m.err))
374 | }
375 |
376 | m.bs = m.bs[:len(m.bs)-1]
377 |
378 | if bytes.Equal(m.bs, []byte{'0'}) || bytes.Equal(m.bs, nil) {
379 | return false
380 | }
381 | return true
382 | }
383 |
384 | func (m *MsgBuffer) readString() string {
385 | m.bs, m.err = m.ReadBytes(fieldSplit)
386 | if m.err != nil {
387 | log.Panic("decode string error", zap.Error(m.err))
388 | }
389 |
390 | return string(m.bs[:len(m.bs)-1])
391 | }
392 |
393 | // NewMsgBuffer create a new MsgBuffer
394 | func NewMsgBuffer(bs []byte) *MsgBuffer {
395 | return &MsgBuffer{
396 | *bytes.NewBuffer(bs),
397 | nil,
398 | nil}
399 | }
400 |
401 | // Reset reset buffer, []byte, err
402 | func (m *MsgBuffer) Reset() {
403 | m.Buffer.Reset()
404 | m.bs = m.bs[:0]
405 | m.err = nil
406 | }
407 |
--------------------------------------------------------------------------------
/utils_test.go:
--------------------------------------------------------------------------------
1 | package ibapi
2 |
3 | import (
4 | _ "net/http/pprof"
5 | "testing"
6 | // "time"
7 | )
8 |
9 | // func makeMsgBytesOld(fields ...interface{}) []byte {
10 |
11 | // // make the whole the slice of msgBytes
12 | // msgBytesSlice := make([][]byte, 0, len(fields))
13 | // for _, f := range fields {
14 | // // make the field into msgBytes
15 | // msgBytes := field2Bytes(f)
16 | // msgBytesSlice = append(msgBytesSlice, msgBytes)
17 | // }
18 | // msg := bytes.Join(msgBytesSlice, nil)
19 |
20 | // // add the size header
21 | // sizeBytes := make([]byte, 4, 4+len(msg))
22 | // binary.BigEndian.PutUint32(sizeBytes, uint32(len(msg)))
23 |
24 | // return append(sizeBytes, msg...)
25 | // }
26 |
27 | // func TestMakeMsgEqual(t *testing.T) {
28 | // var v1 int64 = 19901130
29 | // var v2 float64 = 0.123456
30 | // var v3 string = "bla bla bla"
31 | // var v4 bool = true
32 | // var v5 []byte = []byte("hadrianl")
33 | // var v6 int = 20201130
34 |
35 | // oldBytes := makeMsgBytesOld(v3, v1, v2, v3, v4, v5, v6)
36 | // newBytes := makeMsgBytes(v3, v1, v2, v3, v4, v5, v6)
37 | // t.Log("old:", oldBytes)
38 | // t.Log("new:", newBytes)
39 |
40 | // if !bytes.Equal(oldBytes, newBytes) {
41 | // t.Fatal("bytes not equal!")
42 | // }
43 | // }
44 |
45 | func BenchmarkMakeMsg(b *testing.B) {
46 | // log, _ = zap.NewDevelopment()
47 | var v1 int64 = 19901130
48 | var v2 float64 = 0.123456
49 | var v3 string = "bla bla bla"
50 | var v4 bool = true
51 | var v5 []byte = []byte("hadrianl")
52 | var v6 int = 20201130
53 | // var updateAccountValueMsgBuf = NewMsgBuffer(nil)
54 | for i := 0; i < b.N; i++ {
55 | // updateAccountValueMsgBuf.Write(msgBytes)
56 | makeMsgBytes(v1, v2, v3, v4, v5, v6)
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/wrapper.go:
--------------------------------------------------------------------------------
1 | package ibapi
2 |
3 | import (
4 | "sync/atomic"
5 | "time"
6 |
7 | "go.uber.org/zap"
8 | )
9 |
10 | // IbWrapper contain the funcs to handle the msg from TWS or Gateway
11 | type IbWrapper interface {
12 | TickPrice(reqID int64, tickType int64, price float64, attrib TickAttrib)
13 | TickSize(reqID int64, tickType int64, size int64)
14 | OrderStatus(orderID int64, status string, filled float64, remaining float64, avgFillPrice float64, permID int64, parentID int64, lastFillPrice float64, clientID int64, whyHeld string, mktCapPrice float64)
15 | Error(reqID int64, errCode int64, errString string)
16 | OpenOrder(orderID int64, contract *Contract, order *Order, orderState *OrderState)
17 | UpdateAccountValue(tag string, val string, currency string, accName string)
18 | UpdatePortfolio(contract *Contract, position float64, marketPrice float64, marketValue float64, averageCost float64, unrealizedPNL float64, realizedPNL float64, accName string)
19 | UpdateAccountTime(accTime time.Time)
20 | NextValidID(reqID int64)
21 | ContractDetails(reqID int64, conDetails *ContractDetails)
22 | ExecDetails(reqID int64, contract *Contract, execution *Execution)
23 | UpdateMktDepth(reqID int64, position int64, operation int64, side int64, price float64, size int64)
24 | UpdateMktDepthL2(reqID int64, position int64, marketMaker string, operation int64, side int64, price float64, size int64, isSmartDepth bool)
25 | UpdateNewsBulletin(msgID int64, msgType int64, newsMessage string, originExchange string)
26 | ManagedAccounts(accountsList []string)
27 | ReceiveFA(faData int64, cxml string)
28 | HistoricalData(reqID int64, bar *BarData)
29 | HistoricalDataEnd(reqID int64, startDateStr string, endDateStr string)
30 | HistoricalDataUpdate(reqID int64, bar *BarData)
31 | BondContractDetails(reqID int64, conDetails *ContractDetails)
32 | ScannerParameters(xml string)
33 | ScannerData(reqID int64, rank int64, conDetails *ContractDetails, distance string, benchmark string, projection string, legs string)
34 | ScannerDataEnd(reqID int64)
35 | TickOptionComputation(reqID int64, tickType int64, tickAttrib int64, impliedVol float64, delta float64, optPrice float64, pvDiviedn float64, gamma float64, vega float64, theta float64, undPrice float64)
36 | TickGeneric(reqID int64, tickType int64, value float64)
37 | TickString(reqID int64, tickType int64, value string)
38 | TickEFP(reqID int64, tickType int64, basisPoints float64, formattedBasisPoints string, totalDividends float64, holdDays int64, futureLastTradeDate string, dividendImpact float64, dividendsToLastTradeDate float64)
39 | CurrentTime(t time.Time)
40 | RealtimeBar(reqID int64, time int64, open float64, high float64, low float64, close float64, volume int64, wap float64, count int64)
41 | FundamentalData(reqID int64, data string)
42 | ContractDetailsEnd(reqID int64)
43 | OpenOrderEnd()
44 | AccountDownloadEnd(accName string)
45 | ExecDetailsEnd(reqID int64)
46 | DeltaNeutralValidation(reqID int64, deltaNeutralContract DeltaNeutralContract)
47 | TickSnapshotEnd(reqID int64)
48 | MarketDataType(reqID int64, marketDataType int64)
49 | Position(account string, contract *Contract, position float64, avgCost float64)
50 | PositionEnd()
51 | AccountSummary(reqID int64, account string, tag string, value string, currency string)
52 | AccountSummaryEnd(reqID int64)
53 | VerifyMessageAPI(apiData string)
54 | VerifyCompleted(isSuccessful bool, err string)
55 | DisplayGroupList(reqID int64, groups string)
56 | DisplayGroupUpdated(reqID int64, contractInfo string)
57 | VerifyAndAuthMessageAPI(apiData string, xyzChallange string)
58 | VerifyAndAuthCompleted(isSuccessful bool, err string)
59 | PositionMulti(reqID int64, account string, modelCode string, contract *Contract, position float64, avgCost float64)
60 | PositionMultiEnd(reqID int64)
61 | AccountUpdateMulti(reqID int64, account string, modleCode string, tag string, value string, currency string)
62 | AccountUpdateMultiEnd(reqID int64)
63 | SecurityDefinitionOptionParameter(reqID int64, exchange string, underlyingContractID int64, tradingClass string, multiplier string, expirations []string, strikes []float64)
64 | SecurityDefinitionOptionParameterEnd(reqID int64)
65 | SoftDollarTiers(reqID int64, tiers []SoftDollarTier)
66 | FamilyCodes(famCodes []FamilyCode)
67 | SymbolSamples(reqID int64, contractDescriptions []ContractDescription)
68 | SmartComponents(reqID int64, smartComps []SmartComponent)
69 | TickReqParams(tickerID int64, minTick float64, bboExchange string, snapshotPermissions int64)
70 | MktDepthExchanges(depthMktDataDescriptions []DepthMktDataDescription)
71 | HeadTimestamp(reqID int64, headTimestamp string)
72 | TickNews(tickerID int64, timeStamp int64, providerCode string, articleID string, headline string, extraData string)
73 | NewsProviders(newsProviders []NewsProvider)
74 | NewsArticle(reqID int64, articleType int64, articleText string)
75 | HistoricalNews(reqID int64, time string, providerCode string, articleID string, headline string)
76 | HistoricalNewsEnd(reqID int64, hasMore bool)
77 | HistogramData(reqID int64, histogram []HistogramData)
78 | RerouteMktDataReq(reqID int64, contractID int64, exchange string)
79 | RerouteMktDepthReq(reqID int64, contractID int64, exchange string)
80 | MarketRule(marketRuleID int64, priceIncrements []PriceIncrement)
81 | Pnl(reqID int64, dailyPnL float64, unrealizedPnL float64, realizedPnL float64)
82 | PnlSingle(reqID int64, position int64, dailyPnL float64, unrealizedPnL float64, realizedPnL float64, value float64)
83 | HistoricalTicks(reqID int64, ticks []HistoricalTick, done bool)
84 | HistoricalTicksBidAsk(reqID int64, ticks []HistoricalTickBidAsk, done bool)
85 | HistoricalTicksLast(reqID int64, ticks []HistoricalTickLast, done bool)
86 | TickByTickAllLast(reqID int64, tickType int64, time int64, price float64, size int64, tickAttribLast TickAttribLast, exchange string, specialConditions string)
87 | TickByTickBidAsk(reqID int64, time int64, bidPrice float64, askPrice float64, bidSize int64, askSize int64, tickAttribBidAsk TickAttribBidAsk)
88 | TickByTickMidPoint(reqID int64, time int64, midPoint float64)
89 | OrderBound(reqID int64, apiClientID int64, apiOrderID int64)
90 | CompletedOrder(contract *Contract, order *Order, orderState *OrderState)
91 | CompletedOrdersEnd()
92 | CommissionReport(commissionReport CommissionReport)
93 | ConnectAck()
94 | ConnectionClosed()
95 | ReplaceFAEnd(reqID int64, text string)
96 | WshMetaData(reqID int64, dataJson string)
97 | WshEventData(reqID int64, dataJson string)
98 | }
99 |
100 | // Wrapper is the default wrapper provided by this golang implement.
101 | type Wrapper struct {
102 | orderID int64
103 | }
104 |
105 | func (w *Wrapper) GetNextOrderID() (i int64) {
106 | i = w.orderID
107 | atomic.AddInt64(&w.orderID, 1)
108 | return
109 | }
110 |
111 | func (w Wrapper) ConnectAck() {
112 | log.Info("...")
113 | }
114 |
115 | func (w Wrapper) ConnectionClosed() {
116 | log.Info("...")
117 | }
118 |
119 | func (w *Wrapper) NextValidID(reqID int64) {
120 | atomic.StoreInt64(&w.orderID, reqID)
121 | log.With(zap.Int64("reqID", reqID)).Info("")
122 | }
123 |
124 | func (w Wrapper) ManagedAccounts(accountsList []string) {
125 | log.Info("", zap.Strings("accountList", accountsList))
126 | }
127 |
128 | func (w Wrapper) TickPrice(reqID int64, tickType int64, price float64, attrib TickAttrib) {
129 | log.With(zap.Int64("reqID", reqID)).Info("", zap.Int64("tickType", tickType), zap.Float64("price", price))
130 | }
131 |
132 | func (w Wrapper) UpdateAccountTime(accTime time.Time) {
133 | log.Info("", zap.Time("accountTime", accTime))
134 | }
135 |
136 | func (w Wrapper) UpdateAccountValue(tag string, value string, currency string, account string) {
137 | log.Info("", zap.String("tag", tag), zap.String("value", value), zap.String("currency", currency), zap.String("account", account))
138 | }
139 |
140 | func (w Wrapper) AccountDownloadEnd(accName string) {
141 | log.Info("", zap.String("accountName", accName))
142 | }
143 |
144 | func (w Wrapper) AccountUpdateMulti(reqID int64, account string, modelCode string, tag string, value string, currency string) {
145 | log.With(zap.Int64("reqID", reqID)).Info("",
146 | zap.String("account", account),
147 | zap.String("modelCode", modelCode),
148 | zap.String("tag", tag),
149 | zap.String("value", value),
150 | zap.String("curreny", currency),
151 | )
152 | }
153 |
154 | func (w Wrapper) AccountUpdateMultiEnd(reqID int64) {
155 | log.With(zap.Int64("reqID", reqID)).Info("")
156 | }
157 |
158 | func (w Wrapper) AccountSummary(reqID int64, account string, tag string, value string, currency string) {
159 | log.With(zap.Int64("reqID", reqID)).Info("",
160 | zap.String("account", account),
161 | zap.String("tag", tag),
162 | zap.String("value", value),
163 | zap.String("curreny", currency),
164 | )
165 |
166 | }
167 |
168 | func (w Wrapper) AccountSummaryEnd(reqID int64) {
169 | log.With(zap.Int64("reqID", reqID)).Info("")
170 | }
171 |
172 | func (w Wrapper) VerifyMessageAPI(apiData string) {
173 | log.Info("", zap.String("apiData", apiData))
174 | }
175 |
176 | func (w Wrapper) VerifyCompleted(isSuccessful bool, err string) {
177 | log.Info("", zap.Bool("isSuccessful", isSuccessful), zap.String("error", err))
178 | }
179 |
180 | func (w Wrapper) VerifyAndAuthMessageAPI(apiData string, xyzChallange string) {
181 | log.Info("", zap.String("apiData", apiData), zap.String("xyzChallange", xyzChallange))
182 | }
183 |
184 | func (w Wrapper) VerifyAndAuthCompleted(isSuccessful bool, err string) {
185 | log.Info("", zap.Bool("isSuccessful", isSuccessful), zap.String("error", err))
186 | }
187 |
188 | func (w Wrapper) DisplayGroupList(reqID int64, groups string) {
189 | log.With(zap.Int64("reqID", reqID)).Info("", zap.String("groups", groups))
190 | }
191 |
192 | func (w Wrapper) DisplayGroupUpdated(reqID int64, contractInfo string) {
193 | log.With(zap.Int64("reqID", reqID)).Info("", zap.String("contractInfo", contractInfo))
194 | }
195 |
196 | func (w Wrapper) PositionMulti(reqID int64, account string, modelCode string, contract *Contract, position float64, avgCost float64) {
197 | log.With(zap.Int64("reqID", reqID)).Info("",
198 | zap.String("account", account),
199 | zap.String("modelCode", modelCode),
200 | zap.Any("contract", contract),
201 | zap.Float64("position", position),
202 | zap.Float64("avgCost", avgCost),
203 | )
204 | }
205 |
206 | func (w Wrapper) PositionMultiEnd(reqID int64) {
207 | log.With(zap.Int64("reqID", reqID)).Info("")
208 | }
209 |
210 | func (w Wrapper) UpdatePortfolio(contract *Contract, position float64, marketPrice float64, marketValue float64, averageCost float64, unrealizedPNL float64, realizedPNL float64, accName string) {
211 | log.Info("",
212 | zap.String("localSymbol", contract.LocalSymbol),
213 | zap.Float64("position", position),
214 | zap.Float64("marketPrice", marketPrice),
215 | zap.Float64("averageCost", averageCost),
216 | zap.Float64("unrealizedPNL", unrealizedPNL),
217 | zap.Float64("realizedPNL", realizedPNL),
218 | zap.String("accName", accName),
219 | )
220 | }
221 |
222 | func (w Wrapper) Position(account string, contract *Contract, position float64, avgCost float64) {
223 | log.Info("",
224 | zap.String("account", account),
225 | zap.Any("contract", contract),
226 | zap.Float64("position", position),
227 | zap.Float64("avgCost", avgCost),
228 | )
229 | }
230 |
231 | func (w Wrapper) PositionEnd() {
232 | log.Info("")
233 | }
234 |
235 | func (w Wrapper) Pnl(reqID int64, dailyPnL float64, unrealizedPnL float64, realizedPnL float64) {
236 | log.With(zap.Int64("reqID", reqID)).Info("",
237 | zap.Float64("dailyPnL", dailyPnL),
238 | zap.Float64("unrealizedPnL", unrealizedPnL),
239 | zap.Float64("realizedPnL", realizedPnL),
240 | )
241 | }
242 |
243 | func (w Wrapper) PnlSingle(reqID int64, position int64, dailyPnL float64, unrealizedPnL float64, realizedPnL float64, value float64) {
244 | log.With(zap.Int64("reqID", reqID)).Info("",
245 | zap.Float64("dailyPnL", dailyPnL),
246 | zap.Float64("unrealizedPnL", unrealizedPnL),
247 | zap.Float64("realizedPnL", realizedPnL),
248 | zap.Float64("value", value),
249 | )
250 | }
251 |
252 | func (w Wrapper) OpenOrder(orderID int64, contract *Contract, order *Order, orderState *OrderState) {
253 | log.With(zap.Int64("orderID", orderID)).Info("",
254 | zap.Any("contract", contract),
255 | zap.Any("order", order),
256 | zap.Any("orderState", orderState),
257 | )
258 | }
259 |
260 | func (w Wrapper) OpenOrderEnd() {
261 | log.Info("")
262 |
263 | }
264 |
265 | func (w Wrapper) OrderStatus(orderID int64, status string, filled float64, remaining float64, avgFillPrice float64, permID int64, parentID int64, lastFillPrice float64, clientID int64, whyHeld string, mktCapPrice float64) {
266 | log.With(zap.Int64("orderID", orderID)).Info("",
267 | zap.String("status", status),
268 | zap.Float64("filled", filled),
269 | zap.Float64("remaining", remaining),
270 | zap.Float64("avgFillPrice", avgFillPrice),
271 | )
272 | }
273 |
274 | func (w Wrapper) ExecDetails(reqID int64, contract *Contract, execution *Execution) {
275 | log.With(zap.Int64("reqID", reqID)).Info("",
276 | zap.Any("contract", contract),
277 | zap.Any("execution", execution),
278 | )
279 | }
280 |
281 | func (w Wrapper) ExecDetailsEnd(reqID int64) {
282 | log.With(zap.Int64("reqID", reqID)).Info("")
283 | }
284 |
285 | func (w Wrapper) DeltaNeutralValidation(reqID int64, deltaNeutralContract DeltaNeutralContract) {
286 | log.With(zap.Int64("reqID", reqID)).Info("",
287 | zap.Any("deltaNeutralContract", deltaNeutralContract),
288 | )
289 | }
290 |
291 | func (w Wrapper) CommissionReport(commissionReport CommissionReport) {
292 | log.Info("",
293 | zap.Any("commissionReport", commissionReport),
294 | )
295 | }
296 |
297 | func (w Wrapper) OrderBound(reqID int64, apiClientID int64, apiOrderID int64) {
298 | log.With(zap.Int64("reqID", reqID)).Info("",
299 | zap.Int64("apiClientID", apiClientID),
300 | zap.Int64("apiOrderID", apiOrderID),
301 | )
302 | }
303 |
304 | func (w Wrapper) ContractDetails(reqID int64, conDetails *ContractDetails) {
305 | log.With(zap.Int64("reqID", reqID)).Info("",
306 | zap.Any("conDetails", conDetails),
307 | )
308 | }
309 |
310 | func (w Wrapper) ContractDetailsEnd(reqID int64) {
311 | log.With(zap.Int64("reqID", reqID)).Info("")
312 | }
313 |
314 | func (w Wrapper) BondContractDetails(reqID int64, conDetails *ContractDetails) {
315 | log.With(zap.Int64("reqID", reqID)).Info("",
316 | zap.Any("conDetails", conDetails),
317 | )
318 | }
319 |
320 | func (w Wrapper) SymbolSamples(reqID int64, contractDescriptions []ContractDescription) {
321 | log.With(zap.Int64("reqID", reqID)).Info("",
322 | zap.Any("contractDescriptions", contractDescriptions),
323 | )
324 | }
325 |
326 | func (w Wrapper) SmartComponents(reqID int64, smartComps []SmartComponent) {
327 | log.With(zap.Int64("reqID", reqID)).Info("",
328 | zap.Any("smartComps", smartComps),
329 | )
330 | }
331 |
332 | func (w Wrapper) MarketRule(marketRuleID int64, priceIncrements []PriceIncrement) {
333 | log.Info("",
334 | zap.Int64("marketRuleID", marketRuleID),
335 | zap.Any("priceIncrements", priceIncrements),
336 | )
337 | }
338 |
339 | func (w Wrapper) RealtimeBar(reqID int64, time int64, open float64, high float64, low float64, close float64, volume int64, wap float64, count int64) {
340 | log.With(zap.Int64("reqID", reqID)).Info("",
341 | zap.Int64("time", time),
342 | zap.Float64("open", open),
343 | zap.Float64("high", high),
344 | zap.Float64("low", low),
345 | zap.Float64("close", close),
346 | zap.Int64("volume", volume),
347 | zap.Float64("wap", wap),
348 | zap.Int64("count", count),
349 | )
350 | }
351 |
352 | func (w Wrapper) HistoricalData(reqID int64, bar *BarData) {
353 | log.With(zap.Int64("reqID", reqID)).Info("",
354 | zap.Any("bar", bar),
355 | )
356 | }
357 |
358 | func (w Wrapper) HistoricalDataEnd(reqID int64, startDateStr string, endDateStr string) {
359 | log.With(zap.Int64("reqID", reqID)).Info("",
360 | zap.String("startDate", startDateStr),
361 | zap.String("endDate", endDateStr),
362 | )
363 | }
364 |
365 | func (w Wrapper) HistoricalDataUpdate(reqID int64, bar *BarData) {
366 | log.With(zap.Int64("reqID", reqID)).Info("",
367 | zap.Any("bar", bar),
368 | )
369 | }
370 |
371 | func (w Wrapper) HeadTimestamp(reqID int64, headTimestamp string) {
372 | log.With(zap.Int64("reqID", reqID)).Info("",
373 | zap.String("headTimestamp", headTimestamp),
374 | )
375 | }
376 |
377 | func (w Wrapper) HistoricalTicks(reqID int64, ticks []HistoricalTick, done bool) {
378 | log.With(zap.Int64("reqID", reqID)).Info("",
379 | zap.Any("ticks", ticks),
380 | zap.Bool("done", done),
381 | )
382 | }
383 |
384 | func (w Wrapper) HistoricalTicksBidAsk(reqID int64, ticks []HistoricalTickBidAsk, done bool) {
385 | log.With(zap.Int64("reqID", reqID)).Info("",
386 | zap.Any("ticks", ticks),
387 | zap.Bool("done", done),
388 | )
389 | }
390 |
391 | func (w Wrapper) HistoricalTicksLast(reqID int64, ticks []HistoricalTickLast, done bool) {
392 | log.With(zap.Int64("reqID", reqID)).Info("",
393 | zap.Any("ticks", ticks),
394 | zap.Bool("done", done),
395 | )
396 | }
397 |
398 | func (w Wrapper) TickSize(reqID int64, tickType int64, size int64) {
399 | log.With(zap.Int64("reqID", reqID)).Info("",
400 | zap.Int64("tickType", tickType),
401 | zap.Int64("size", size),
402 | )
403 | }
404 |
405 | func (w Wrapper) TickSnapshotEnd(reqID int64) {
406 | log.With(zap.Int64("reqID", reqID)).Info("")
407 | }
408 |
409 | func (w Wrapper) MarketDataType(reqID int64, marketDataType int64) {
410 | log.With(zap.Int64("reqID", reqID)).Info("",
411 | zap.Int64("marketDataType", marketDataType),
412 | )
413 | }
414 |
415 | func (w Wrapper) TickByTickAllLast(reqID int64, tickType int64, time int64, price float64, size int64, tickAttribLast TickAttribLast, exchange string, specialConditions string) {
416 | log.With(zap.Int64("reqID", reqID)).Info("",
417 | zap.Int64("tickType", tickType),
418 | zap.Int64("time", time),
419 | zap.Float64("price", price),
420 | zap.Int64("size", size),
421 | )
422 | }
423 |
424 | func (w Wrapper) TickByTickBidAsk(reqID int64, time int64, bidPrice float64, askPrice float64, bidSize int64, askSize int64, tickAttribBidAsk TickAttribBidAsk) {
425 | log.With(zap.Int64("reqID", reqID)).Info("",
426 | zap.Int64("time", time),
427 | zap.Float64("bidPrice", bidPrice),
428 | zap.Float64("askPrice", askPrice),
429 | zap.Int64("bidPrice", bidSize),
430 | zap.Int64("askPrice", askSize),
431 | )
432 | }
433 |
434 | func (w Wrapper) TickByTickMidPoint(reqID int64, time int64, midPoint float64) {
435 | log.With(zap.Int64("reqID", reqID)).Info("",
436 | zap.Int64("time", time),
437 | zap.Float64("midPoint", midPoint),
438 | )
439 | }
440 |
441 | func (w Wrapper) TickString(reqID int64, tickType int64, value string) {
442 | log.With(zap.Int64("reqID", reqID)).Info("",
443 | zap.Int64("tickType", tickType),
444 | zap.String("value", value),
445 | )
446 | }
447 |
448 | func (w Wrapper) TickGeneric(reqID int64, tickType int64, value float64) {
449 | log.With(zap.Int64("reqID", reqID)).Info("",
450 | zap.Int64("tickType", tickType),
451 | zap.Float64("value", value),
452 | )
453 | }
454 |
455 | func (w Wrapper) TickEFP(reqID int64, tickType int64, basisPoints float64, formattedBasisPoints string, totalDividends float64, holdDays int64, futureLastTradeDate string, dividendImpact float64, dividendsToLastTradeDate float64) {
456 | log.With(zap.Int64("reqID", reqID)).Info("",
457 | zap.Int64("tickType", tickType),
458 | zap.Float64("basisPoints", basisPoints),
459 | )
460 | }
461 |
462 | func (w Wrapper) TickReqParams(reqID int64, minTick float64, bboExchange string, snapshotPermissions int64) {
463 | log.With(zap.Int64("reqID", reqID)).Info("",
464 | zap.Float64("minTick", minTick),
465 | zap.String("bboExchange", bboExchange),
466 | zap.Int64("snapshotPermissions", snapshotPermissions),
467 | )
468 | }
469 | func (w Wrapper) MktDepthExchanges(depthMktDataDescriptions []DepthMktDataDescription) {
470 | log.Info("",
471 | zap.Any("depthMktDataDescriptions", depthMktDataDescriptions),
472 | )
473 | }
474 |
475 | /*Returns the order book.
476 |
477 | tickerId - the request's identifier
478 | position - the order book's row being updated
479 | operation - how to refresh the row:
480 | 0 = insert (insert this new order into the row identified by 'position')
481 | 1 = update (update the existing order in the row identified by 'position')
482 | 2 = delete (delete the existing order at the row identified by 'position').
483 | side - 0 for ask, 1 for bid
484 | price - the order's price
485 | size - the order's size*/
486 | func (w Wrapper) UpdateMktDepth(reqID int64, position int64, operation int64, side int64, price float64, size int64) {
487 | log.With(zap.Int64("reqID", reqID)).Info("",
488 | zap.Int64("position", position),
489 | zap.Int64("operation", operation),
490 | zap.Int64("side", side),
491 | zap.Float64("price", price),
492 | zap.Int64("size", size),
493 | )
494 | }
495 |
496 | func (w Wrapper) UpdateMktDepthL2(reqID int64, position int64, marketMaker string, operation int64, side int64, price float64, size int64, isSmartDepth bool) {
497 | log.With(zap.Int64("reqID", reqID)).Info("",
498 | zap.Int64("position", position),
499 | zap.String("marketMaker", marketMaker),
500 | zap.Int64("operation", operation),
501 | zap.Int64("side", side),
502 | zap.Float64("price", price),
503 | zap.Int64("size", size),
504 | zap.Bool("isSmartDepth", isSmartDepth),
505 | )
506 | }
507 |
508 | func (w Wrapper) TickOptionComputation(reqID int64, tickType int64, tickAttrib int64, impliedVol float64, delta float64, optPrice float64, pvDiviedn float64, gamma float64, vega float64, theta float64, undPrice float64) {
509 | log.With(zap.Int64("reqID", reqID)).Info("",
510 | zap.Int64("tickType", tickType),
511 | zap.Int64("tickAttrib", tickAttrib),
512 | zap.Float64("impliedVol", impliedVol),
513 | zap.Float64("delta", delta),
514 | zap.Float64("optPrice", optPrice),
515 | zap.Float64("pvDiviedn", pvDiviedn),
516 | zap.Float64("gamma", gamma),
517 | zap.Float64("vega", vega),
518 | zap.Float64("theta", theta),
519 | zap.Float64("undPrice", undPrice),
520 | )
521 | }
522 |
523 | func (w Wrapper) FundamentalData(reqID int64, data string) {
524 | log.With(zap.Int64("reqID", reqID)).Info("",
525 | zap.String("data", data),
526 | )
527 | }
528 |
529 | func (w Wrapper) ScannerParameters(xml string) {
530 | log.Info("",
531 | zap.String("xml", xml),
532 | )
533 |
534 | }
535 |
536 | func (w Wrapper) ScannerData(reqID int64, rank int64, conDetails *ContractDetails, distance string, benchmark string, projection string, legs string) {
537 | log.With(zap.Int64("reqID", reqID)).Info("",
538 | zap.Int64("rank", rank),
539 | zap.Any("conDetails", conDetails),
540 | zap.String("distance", distance),
541 | zap.String("benchmark", benchmark),
542 | zap.String("projection", projection),
543 | zap.String("legs", legs),
544 | )
545 | }
546 |
547 | func (w Wrapper) ScannerDataEnd(reqID int64) {
548 | log.With(zap.Int64("reqID", reqID)).Info("")
549 | }
550 |
551 | func (w Wrapper) HistogramData(reqID int64, histogram []HistogramData) {
552 | log.With(zap.Int64("reqID", reqID)).Info("",
553 | zap.Any("histogram", histogram),
554 | )
555 | }
556 |
557 | func (w Wrapper) RerouteMktDataReq(reqID int64, contractID int64, exchange string) {
558 | log.With(zap.Int64("reqID", reqID)).Info("",
559 | zap.Int64("contractID", contractID),
560 | zap.String("exchange", exchange),
561 | )
562 | }
563 |
564 | func (w Wrapper) RerouteMktDepthReq(reqID int64, contractID int64, exchange string) {
565 | log.With(zap.Int64("reqID", reqID)).Info("",
566 | zap.Int64("contractID", contractID),
567 | zap.String("exchange", exchange),
568 | )
569 | }
570 |
571 | func (w Wrapper) SecurityDefinitionOptionParameter(reqID int64, exchange string, underlyingContractID int64, tradingClass string, multiplier string, expirations []string, strikes []float64) {
572 | log.With(zap.Int64("reqID", reqID)).Info("",
573 | zap.String("exchange", exchange),
574 | zap.Int64("underlyingContractID", underlyingContractID),
575 | zap.String("tradingClass", tradingClass),
576 | zap.String("multiplier", multiplier),
577 | zap.Strings("expirations", expirations),
578 | zap.Float64s("strikes", strikes),
579 | )
580 | }
581 |
582 | func (w Wrapper) SecurityDefinitionOptionParameterEnd(reqID int64) {
583 | log.With(zap.Int64("reqID", reqID)).Info("")
584 | }
585 |
586 | func (w Wrapper) SoftDollarTiers(reqID int64, tiers []SoftDollarTier) {
587 | log.With(zap.Int64("reqID", reqID)).Info("",
588 | zap.Any("tiers", tiers),
589 | )
590 | }
591 |
592 | func (w Wrapper) FamilyCodes(famCodes []FamilyCode) {
593 | log.Info("",
594 | zap.Any("famCodes", famCodes),
595 | )
596 | }
597 |
598 | func (w Wrapper) NewsProviders(newsProviders []NewsProvider) {
599 | log.Info("",
600 | zap.Any("newsProviders", newsProviders),
601 | )
602 | }
603 |
604 | func (w Wrapper) TickNews(tickerID int64, timeStamp int64, providerCode string, articleID string, headline string, extraData string) {
605 | log.With(zap.Int64("tickerID", tickerID)).Info("",
606 | zap.Int64("timeStamp", timeStamp),
607 | zap.String("providerCode", providerCode),
608 | zap.String("articleID", articleID),
609 | zap.String("headline", headline),
610 | zap.String("extraData", extraData),
611 | )
612 | }
613 |
614 | func (w Wrapper) NewsArticle(reqID int64, articleType int64, articleText string) {
615 | log.With(zap.Int64("reqID", reqID)).Info("",
616 | zap.Int64("articleType", articleType),
617 | zap.String("articleText", articleText),
618 | )
619 | }
620 |
621 | func (w Wrapper) HistoricalNews(reqID int64, time string, providerCode string, articleID string, headline string) {
622 | log.With(zap.Int64("reqID", reqID)).Info("",
623 | zap.String("time", time),
624 | zap.String("providerCode", providerCode),
625 | zap.String("articleID", articleID),
626 | zap.String("headline", headline),
627 | )
628 | }
629 |
630 | func (w Wrapper) HistoricalNewsEnd(reqID int64, hasMore bool) {
631 | log.With(zap.Int64("reqID", reqID)).Info("",
632 | zap.Bool("hasMore", hasMore),
633 | )
634 | }
635 |
636 | func (w Wrapper) UpdateNewsBulletin(msgID int64, msgType int64, newsMessage string, originExch string) {
637 | log.With(zap.Int64("msgID", msgID)).Info("",
638 | zap.Int64("msgType", msgType),
639 | zap.String("newsMessage", newsMessage),
640 | zap.String("originExch", originExch),
641 | )
642 | }
643 |
644 | func (w Wrapper) ReceiveFA(faData int64, cxml string) {
645 | log.Info("",
646 | zap.Int64("faData", faData),
647 | zap.String("cxml", cxml),
648 | )
649 | }
650 |
651 | func (w Wrapper) CurrentTime(t time.Time) {
652 | log.Info("",
653 | zap.Time("time", t),
654 | )
655 | }
656 |
657 | func (w Wrapper) Error(reqID int64, errCode int64, errString string) {
658 | log.With(zap.Int64("reqID", reqID)).Info("",
659 | zap.Int64("errCode", errCode),
660 | zap.String("errString", errString),
661 | )
662 | }
663 |
664 | func (w Wrapper) CompletedOrder(contract *Contract, order *Order, orderState *OrderState) {
665 | log.Info("",
666 | zap.Any("contract", contract),
667 | zap.Any("order", order),
668 | zap.Any("orderState", orderState),
669 | )
670 | }
671 |
672 | func (w Wrapper) CompletedOrdersEnd() {
673 | log.Info(":")
674 | }
675 |
676 | func (w Wrapper) ReplaceFAEnd(reqID int64, text string) {
677 | log.With(zap.Int64("reqID", reqID)).Info("", zap.String("text", text))
678 | }
679 |
680 | func (w Wrapper) WshMetaData(reqID int64, dataJson string) {
681 | log.With(zap.Int64("reqID", reqID)).Info("", zap.String("dataJson", dataJson))
682 | }
683 | func (w Wrapper) WshEventData(reqID int64, dataJson string) {
684 | log.With(zap.Int64("reqID", reqID)).Info("", zap.String("dataJson", dataJson))
685 | }
686 |
--------------------------------------------------------------------------------