Code Monkey home page Code Monkey logo

ibapi's Introduction

Interactive Brokers API - GoLang Implement

  • Interactive Brokers API 9.80
  • pure golang Implement
  • Unofficial, use at you own risk

INSTALL

go get -u github.com/hadrianl/ibapi


USAGE

Implement IbWrapper to handle datas delivered via tws or gateway, Wrapper in demo is a default implement that just output data to std. Go to IbWrapper

  1. implement your own IbWrapper
  2. connect to TWS or Gateway
  3. handshake with TWS or Gateway
  4. run the loop
  5. do some request

Demo 1

import (
    . "github.com/hadrianl/ibapi"
    "time"
)

func main(){
    // internal api log is zap log, you could use GetLogger to get the logger
    // besides, you could use SetAPILogger to set you own log option
    // or you can just use the other logger  
    log := GetLogger().Sugar()
    defer log.Sync()
    // implement your own IbWrapper to handle the msg delivered via tws or gateway
    // Wrapper{} below is a default implement which just log the msg 
    ic := NewIbClient(&Wrapper{})

    // tcp connect with tws or gateway
    // fail if tws or gateway had not yet set the trust IP
    if err := ic.Connect("127.0.0.1", 4002, 0);err != nil {
        log.Panic("Connect failed:", err)
    }

    // handshake with tws or gateway, send handshake protocol to tell tws or gateway the version of client
    // and receive the server version and connection time from tws or gateway.
    // fail if someone else had already connected to tws or gateway with same clientID
    if err := ic.HandShake();err != nil {
        log.Panic("HandShake failed:", err)
    }

    // make some request, msg would be delivered via wrapper.
    // req will not send to TWS or Gateway until ic.Run()
    // you could just call ic.Run() before these
    ic.ReqCurrentTime()
    ic.ReqAutoOpenOrders(true)
    ic.ReqAccountUpdates(true, "")
    ic.ReqExecutions(ic.GetReqID(), ExecutionFilter{})

    // start to send req and receive msg from tws or gateway after this
    ic.Run()
    <-time.After(time.Second * 60)
    ic.Disconnect()
}

Demo 2 with context

import (
    . "github.com/hadrianl/ibapi"
    "time"
    "context"
)

func main(){
    var err error
    SetAPILogger(zap.NewDevelopmentConfig()) // log is default for production(json encode, info level), set to development(console encode, debug level) here
    log := GetLogger().Sugar()
    defer log.Sync()
    ibwrapper := &Wrapper{}
    ctx, _ := context.WithTimeout(context.Background(), time.Second*30)
    ic := NewIbClient(ibwrapper)
    ic.SetContext(ctx)
    err = ic.Connect("127.0.0.1", 4002, 0)
    if err != nil {
        log.Panic("Connect failed:", err)
    }

    err = ic.HandShake()
    if err != nil {
        log.Panic("HandShake failed:", err)
    }

    ic.ReqCurrentTime()
    ic.ReqAutoOpenOrders(true)
    ic.ReqAccountUpdates(true, "")
    ic.ReqExecutions(ic.GetReqID(), ExecutionFilter{})

    ic.Run()
    err = ic.LoopUntilDone()  // block until ctx or ic is done
    log.Info(err)
}

Reference

  1. Offical Document
  2. Order Types
  3. Product
  4. Margin
  5. Market Data
  6. Commissions

ibapi's People

Contributors

hadrianl avatar marvin-hansen avatar pchavanne avatar rerosum avatar sachinbhutani avatar t00ts avatar travisgroth avatar trey2k avatar vkopachev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ibapi's Issues

PERFORMANCE

1.use zap instead of logrus;
2.benchmark test
3.sync.Pool?
4.field2Bytes may need to fix, do not use type-assertion
5.array instead of slice,such as sizebtyes
6.readMsgBytes? read exactly size instead of loop?
7.a better way to Init defalut object? no reflect?

Change client level to Debug

When running the sample code, I get a flood of logs on info level that really should be better on debug level.
Specifically,

  • msg start / end
  • msg decoding
  • state change

I understand, during development that level of detailed log helps.

In practice, I suggest patching the util with a factory function that either returns or dev or production logger depending on some (enum) parameter, and the set the bulk of client logs to debug level. That way, people can at least switch log level easily without fiddling around with zap configs.

clientID clarification

Hello,

This is an odd edge case, and it's sort of on the boundary between ibapi and the tws system, but it doesn't seem to be documented clearly anywhere.

I hit a problem where I could connect to the client, but the handshake was timing out; I was able to connect with another script.

The bug turned out to be -- I believe -- that the clientID I was using was too large: in ibapi, it's an int64, but the tws docs only say int.

I don't know whether the correct fix is to use an int32 or to document that using too large a clientID will cause an unexplained failure, but I thought it was worth mentioning.

C

recover type inconsistent

First, thanks for putting together this project!

I somehow got an error decoding a float the other day and the recovery code in goDecode failed. It seems like the value passed to panic() from a zap logger Panic call is a string, not an error type. Also after some experimentation, it looks like if a NoOp logger is configured, the call to zap's Panic will just exit 0.

I was initially thinking of just adding a type check in the recieve/request/decode loops, but I'm actually wondering if all the logger panics should be changed to a standard golang panics instead. This would allow the retry code to work and at least produce a stack trace rather than dying silently if I've disabled logging in the wrapper by setting it to NoOp.

Another option would be to do the type check and change the default wrapper log messages to debug so there's little temptation to set a NoOp logger.

Thoughts? I don't mind taking a pass at the change but I wanted to discuss an approach before putting together a PR.

Order ID and price are not populated correctly for CompletedOrders Reply

Hi,

The Completed Orders req is now working, however it seems that Order ID and price are not populated correctly for the CompletedOrders reply:
"msg":"<CompletedOrder>{contract 25 0 Contract<CondID: 107113386, Symbol: FB, SecurityType: STK, Exchange: SMART, Currency: USD>} {order 25 0 Order<OrderID: 0, ClientID: 0, PermID: 1413528998> -- <MKT BUY [email protected] DAY> --

reqhistoricadata endDateTime issue

Has anyone else run into this recently? Basically if I pass an empty string to reqhistoricaldata for endDateTime I get that I am supposed to pass a date string. But then if I do that it says you have to use an empty string if you want historical updates, which I do.

I have asked IB; they seem to think nothing changed on their end but then my python code also does this. At this point I do not knonw what is going on or where the bug is in my code. I have reinstalled this package and tried many different things.

Errors in PlaceOrder (PostToATS attribute)

I dot errors when trying to place an order (checked on both stock and future). It blocks order submission on latest TWS version
10274 The 'PostToATS' order attribute may not be specified for this order or is invalid.

I also have two warnings on sending order
10983 Buy MKT 2168: Warning: The 'EtradeOnly' order attribute is not supported.
10983 Buy MKT 2169: Warning: The 'FirmQuoteOnly' order attribute is not supported.

Thanks for your work

Extracting data of requests

How extracting data of request ?
In the past, I used gofinance/ib, it was easy to extract the data of my requests. Can you tell me how to do and document this ?

Example :
reqContract -> struct Contract
etc...

Can't place a order

contract := new(ibapi.Contract)
contract.Symbol = "MSFT"
contract.Exchange = "SMART"
contract.Currency = "USD"
lmt := ibapi.NewLimitOrder("BUY", 244.26, 100)
ic.PlaceOrder(newOrderId(), contract, lmt)

The order doesn't show on TWS nor get a openorder message

{"level":"info","ts":1670503751.6900978,"caller":"[email protected]/wrapper.go:656","msg":"","reqID":0,"errCode":10149,"errString":"Invalid order id: 0"}

Infinite loop on client connection errors

Client gets stuck in an infinite loop when there are connection issues. The easiest way to reproduce this is by connecting to the api with the same connection id.

    err = ic.Connect(host, port, 0)
{"level":"info","ts":1616442356.7662585,"caller":"[email protected]/client.go:90","msg":"set wrapper","wrapper":{"AccountValues":null,"AccountPositions":null,"OpenOrders":null}}
{"level":"info","ts":1616442356.7665522,"caller":"[email protected]/client.go:290","msg":"reset ibClient"}
{"level":"info","ts":1616442356.766604,"caller":"[email protected]/client.go:79","msg":"connection state is changed","previous":0,"current":0}
{"level":"info","ts":1616442356.7666292,"caller":"[email protected]/client.go:79","msg":"connection state is changed","previous":0,"current":1}
{"level":"info","ts":1616442356.7697575,"caller":"[email protected]/client.go:181","msg":"try to handShake with TWS or GateWay"}
{"level":"info","ts":1616442356.769828,"caller":"[email protected]/client.go:200","msg":"handShake init..."}
{"level":"info","ts":1616442356.774035,"caller":"[email protected]/client.go:227","msg":"init info","serverVersion":157}
{"level":"info","ts":1616442356.7741022,"caller":"[email protected]/client.go:228","msg":"init info","connectionTime":"20210322 15:45:56 EST"}
{"level":"info","ts":1616442356.7742827,"caller":"[email protected]/client.go:2891","msg":"receiver start"}
{"level":"panic","ts":1616442357.3725574,"caller":"[email protected]/client.go:2927","msg":"scanner Error","stacktrace":"github.com/hadrianl/ibapi.(*IbClient).goReceive\n\t/user/go/pkg/mod/github.com/hadrianl/[email protected]/client.go:2927"}
{"level":"info","ts":1616442357.37279,"caller":"runtime/panic.go:969","msg":"receiver end"}
{"level":"error","ts":1616442357.3728147,"caller":"[email protected]/client.go:2895","msg":"receiver got unexpected error","error":"scanner Error","stacktrace":"github.com/hadrianl/ibapi.(*IbClient).goReceive.func1\n\t/user/go/pkg/mod/github.com/hadrianl/[email protected]/client.go:2895\nruntime.gopanic\n\t/usr/local/go/src/runtime/panic.go:969\ngo.uber.org/zap/zapcore.(*CheckedEntry).Write\n\t/user/go/pkg/mod/go.uber.org/[email protected]/zapcore/entry.go:234\ngo.uber.org/zap.(*Logger).Panic\n\t/user/go/pkg/mod/go.uber.org/[email protected]/logger.go:226\ngithub.com/hadrianl/ibapi.(*IbClient).goReceive\n\t/user/go/pkg/mod/github.com/hadrianl/[email protected]/client.go:2927"}
{"level":"info","ts":1616442357.3729947,"caller":"[email protected]/client.go:2898","msg":"try to restart receiver"}
{"level":"info","ts":1616442357.3730626,"caller":"[email protected]/client.go:2891","msg":"receiver start"}
{"level":"panic","ts":1616442357.3730989,"caller":"[email protected]/client.go:2927","msg":"scanner Error","stacktrace":"github.com/hadrianl/ibapi.(*IbClient).goReceive\n\t/user/go/pkg/mod/github.com/hadrianl/[email protected]/client.go:2927"}

Smarter "wait" for historical market data than a simple sleep?

Waiting for a set amount of seconds is a bit of a naive approach to waiting for data to come back from TWS. Is there a better way to wait/block code for, say, the "msg": "<HistoricalDataEnd>" when waiting for historical data? For this simple example, we can assume that we're wanting data for 1, synchronous request:

package main

import (
	"time"

	"github.com/hadrianl/ibapi"
)

func main() {
	// internal api log is zap log, you could use GetLogger to get the logger
	// besides, you could use SetAPILogger to set you own log option
	// or you can just use the other logger
	log := ibapi.GetLogger().Sugar()
	defer log.Sync()

	// implement your own IbWrapper to handle the msg delivered via tws or gateway
	// Wrapper{} below is a default implement which just log the msg
	ic := ibapi.NewIbClient(&ibapi.Wrapper{})

	// tcp connect with tws or gateway
	// fail if tws or gateway had not yet set the trust IP
	if err := ic.Connect("127.0.0.1", 4002, 0); err != nil {
		log.Panic("Connect failed:", err)
	}

	// handshake with tws or gateway, send handshake protocol to tell tws or gateway the version of client
	// and receive the server version and connection time from tws or gateway.
	// fail if someone else had already connected to tws or gateway with same clientID
	if err := ic.HandShake(); err != nil {
		log.Panic("HandShake failed:", err)
	}

	// Create a contract for SPY ETF
	spyContract := ibapi.Contract{
		Symbol:       "SPY",
		SecurityType: "STK",
		Exchange:     "SMART",
		Currency:     "USD",
	}

	// Set the request ID
	reqID := ic.GetReqID()

	// Get the contract details to ensure proper contract is created
	// ic.ReqContractDetails(reqID, &spyContract)

	// Request delayed market data for SPY
	ic.ReqMarketDataType(3) // 3 or 4 for delayed, 1 when you have subscribed to real-time market data

	// Request historical data for SPY
	ic.ReqHistoricalData(reqID, &spyContract, time.Now().Format("20060102 15:04:05"), "1 W", "5 mins", "TRADES", false, 2, false, []ibapi.TagValue{})

	ic.Run()

	// Wait for a response (naive)
	<-time.After(time.Second * 15)

	// Wait for the log message {"level":"info","ts":1.......,"msg":"<HistoricalDataEnd>","reqID":1,"startDate":"20240101  19:32:40","endDate":"20240108  19:32:40"}
	// i.e. "msg":"<HistoricalDataEnd>" is received
	// ??????????

	// Cancel the historical data request
	ic.CancelHistoricalData(reqID)

	ic.Disconnect()
}

Decode error when requesting completed orders

When firing m.Client.ReqCompletedOrders method, a decode error is generated when parsing the reply: {"level":"error","ts":1600076419.379908,"caller":"ibapi/client.go:2934","msg":"decoder got unexpected error","error":"interface conversion: string is not error: missing method Error",

Server version: 115
IBGW version: 978

Error 110 work around

I'm getting the error: Error 110. The price does not conform to the minimum price variation for this contract. On IBKR page, I found out that this information is stored in minTick, which is called by tickReqParams requiring bunch of input parameters, possibly data feed subscription The thing is I don't use IBKR data, but of alpaca, so I cannot call the tickReqParams and since the minimum increment basically depends only on a stock/symbol, is there any work around with your package to get to the minTick value? Thank you in advance.

LoopUntilDone does not terminate on connection loss

Hi,

I might be missing something, but I'm trying to wrap the connection and loop logic so that it can automatically retry when TWS or the api gateway are restarted. It seems like LoopUntilDone() doesn't terminate when it loses the connection. Instead of terminating, I get stuck in the goReceive code:

2021-02-02T22:45:24.260-0500    error   [email protected]/client.go:2895 receiver got unexpected error   {"error": "scanner Error"}
github.com/hadrianl/ibapi.(*IbClient).goReceive.func1
        github.com/hadrianl/[email protected]/client.go:2895
runtime.gopanic
        runtime/panic.go:969
go.uber.org/zap/zapcore.(*CheckedEntry).Write
        go.uber.org/[email protected]/zapcore/entry.go:234
go.uber.org/zap.(*Logger).Panic
        go.uber.org/[email protected]/logger.go:226
github.com/hadrianl/ibapi.(*IbClient).goReceive
        github.com/hadrianl/[email protected]/client.go:2927
2021-02-02T22:45:24.260-0500    panic   [email protected]/client.go:2927 scanner Error
github.com/hadrianl/ibapi.(*IbClient).goReceive
        github.com/hadrianl/[email protected]/client.go:2927

This message repeats forever.

I think the base issue is here: https://github.com/hadrianl/ibapi/blob/master/client.go#L2919

Unlike bufio.Reader, bufio.Scanner returns nil upon io.EOF: https://golang.org/pkg/bufio/#Scanner.Scan

This is easily fixed and seems straightforward. However, the ic.Disconnect() https://github.com/hadrianl/ibapi/blob/master/client.go#L2921 gets stuck on the wait group here https://github.com/hadrianl/ibapi/blob/master/client.go#L136 without further changes, because it is waiting on itself.

The naive approach is to call ic.Disconnect with a new goroutine, and that does work but I'm not sure that's really the right approach for how you want to be handling this case in the context of the rest of the code. It definitely feels like a hack. Here's a diff that demonstrates a potential fix https://github.com/hadrianl/ibapi/compare/master...travisgroth:disconnect_on_conn_loss?expand=1

Happy to open that as a PR or figure out a better way. I haven't followed all the teardown code but I'm wondering if disconnect should just not call ic.wg.Wait().

Your API version does not support fractional size rules. Please upgrade to a minimum version 163

Code:

func marketData(c *cli.Context) error {
	var err error
	ibwrapper := &Wrapper{}
	ctx, _ := context.WithTimeout(context.Background(), time.Second*30)
	ic := NewIbClient(ibwrapper)
	ic.SetContext(ctx)
	err = ic.Connect(c.String("api_host"), c.Int("api_port"), 0)
	if err != nil {
		log.Panic("Connect failed:", err)
	}
	if err := ic.HandShake(); err != nil {
		log.Panic("HandShake failed:", err)
	}

	ic.ReqCurrentTime()

	contract := Contract{Symbol: "EUR", SecurityType: "CASH", Currency: "USD", Exchange: "IDEALPRO"}
	ic.ReqTickByTickData(1, &contract, "BidAsk", 0, true)

	ic.Run()
	err = ic.LoopUntilDone()
	return nil
}

Log:

"level":"info","ts":1689142639.5435812,"caller":"[email protected]/client.go:107","msg":"Connect to client","host":"192.168.16.4","port":7497,"clientID":0}
{"level":"info","ts":1689142639.5439203,"caller":"[email protected]/client.go:177","msg":"HandShake with TWS or GateWay"}
{"level":"info","ts":1689142639.5537026,"caller":"[email protected]/client.go:223","msg":"handShake info","serverVersion":161}
{"level":"info","ts":1689142639.553725,"caller":"[email protected]/client.go:224","msg":"handShake info","connectionTime":"20230712 09:17:19 EET"}
{"level":"info","ts":1689142639.5560975,"caller":"[email protected]/wrapper.go:125","msg":"<ManagedAccounts>","accountList":["U........"]}
{"level":"info","ts":1689142639.5985842,"caller":"[email protected]/wrapper.go:121","msg":"<NextValidID>","reqID":1}
{"level":"info","ts":1689142639.5986145,"caller":"[email protected]/wrapper.go:112","msg":"<ConnectAck>..."}
{"level":"info","ts":1689142639.5986314,"caller":"[email protected]/client.go:272","msg":"HandShake completed"}
{"level":"info","ts":1689142639.5986576,"caller":"[email protected]/client.go:3046","msg":"run client"}
{"level":"info","ts":1689142639.5987244,"caller":"[email protected]/wrapper.go:658","msg":"<Error>","reqID":-1,"errCode":2104,"errString":"Market data farm connection is OK:usfuture"}
{"level":"info","ts":1689142639.5987353,"caller":"[email protected]/wrapper.go:658","msg":"<Error>","reqID":-1,"errCode":2104,"errString":"Market data farm connection is OK:eufarm"}
{"level":"info","ts":1689142639.5987415,"caller":"[email protected]/wrapper.go:658","msg":"<Error>","reqID":-1,"errCode":2104,"errString":"Market data farm connection is OK:cashfarm"}
{"level":"info","ts":1689142639.5987535,"caller":"[email protected]/wrapper.go:658","msg":"<Error>","reqID":-1,"errCode":2104,"errString":"Market data farm connection is OK:usfarm"}
{"level":"info","ts":1689142639.5987659,"caller":"[email protected]/wrapper.go:658","msg":"<Error>","reqID":-1,"errCode":2106,"errString":"HMDS data farm connection is OK:euhmds"}
{"level":"info","ts":1689142639.5987751,"caller":"[email protected]/wrapper.go:658","msg":"<Error>","reqID":-1,"errCode":2106,"errString":"HMDS data farm connection is OK:ushmds"}
{"level":"info","ts":1689142639.5987809,"caller":"[email protected]/wrapper.go:658","msg":"<Error>","reqID":-1,"errCode":2158,"errString":"Sec-def data farm connection is OK:secdefeu"}
{"level":"info","ts":1689142639.600078,"caller":"[email protected]/wrapper.go:652","msg":"<CurrentTime>","time":1689142639}
{"level":"info","ts":1689142639.6430283,"caller":"[email protected]/wrapper.go:658","msg":"<Error>","reqID":1,"errCode":10285,"errString":"Your API version does not support fractional size rules. Please upgrade to a minimum version 163."}

lastTradeDateOrContractMonth missing from Contract

I am trying to migrate from the interactive brokers python api to Golang.
However, to request market data for Option security type, we use the lastTradeDateOrContractMonth property of the Contract object to set the option time in a YY-MM-DD format.
this property probably with its implementation is missing.

will it be possible to include this!

Running this on a Mac and TWS version issue

So I am running the latest Trader Workstation on a Mac.

I get "It does not support secIdType and secId parameters." and can't seem to get past this.

Has anyone successfully used TWS on a Mac? Not sure why the latest TWS doesn't support these things. I tried commenting them out but that didn't work.

How to request historical data multiple times?

I'm a bit confused on this one and can't seem to get a working example.

I create a historical data request for the SPY ticker, 1 day's worth of the latest 5 minute bars. For this simple example, I want to sleep for 5 minutes, then request historical data again. Right now, all it does is just show the bars pulled from the initial request, it doesn't seem to be updating at all.

To recreate this example, I have made the following modifications to the wrapper.go file:

var GlobalHistoricalDataSlice []types.TOHLCV
func GetHistoricalData() []types.TOHLCV {
	return GlobalHistoricalDataSlice
}

func (w Wrapper) HistoricalData(reqID int64, bar *BarData) {
	log.With(zap.Int64("reqID", reqID)).Info("<HistoricalData>",
		zap.Any("bar", bar),
	)
	// Append the bar data to the GlobalHistoricalDataSlice. Bar data is in this format:
	// {"level":"info","ts":1704830870.0692365,"caller":"ibapi2/wrapper.go:353","msg":"<HistoricalData>","reqID":1,"bar":"BarData<Date: 1704800100, Open: 472.910000, High: 472.910000, Low: 472.800000, Close: 472.800000, Volume: 5.000000, Average: 472.856000, BarCount: 4>"}
	// Need to convert it to:
	// type TOHLCV struct {
	// 	DateTime time.Time
	// 	Open     float64
	// 	High     float64
	// 	Low      float64
	// 	Close    float64
	// 	Volume   float64
	// }

	// convert the datetime string "1704818100" format to Int64
	var dateTime int64
	dateTime, _ = strconv.ParseInt(bar.Date, 10, 64)

	// Convert the int dateTime to time.Time for the TOHLCV struct
	var dateTime2 = time.Unix(dateTime, 0)

	GlobalHistoricalDataSlice = append(GlobalHistoricalDataSlice, types.TOHLCV{
		DateTime: dateTime2,
		Open:     bar.Open,
		High:     bar.High,
		Low:      bar.Low,
		Close:    bar.Close,
		Volume:   bar.Volume,
	})
}

As you can see, I created a get method that returns the latest data appended in the newly created GlobalHistoricalDataSlice. This just converts the BarData to a struct of my own creation in the types folder:

package types

import "time"

// Struct used when defining TOHLCV data
type TOHLCV struct {
	DateTime time.Time
	Open     float64
	High     float64
	Low      float64
	Close    float64
	Volume   float64
}

Now the main script looks like this:

package main

import (
    "fmt"
    "time"

    "go_ib/ibapi2"
)

func main() {

    log := ibapi2.GetLogger().Sugar()
    defer log.Sync()

    wrapper := ibapi2.Wrapper{}

    ic := ibapi2.NewIbClient(&wrapper)

    if err := ic.Connect("127.0.0.1", 4002, 0); err != nil {
        log.Panic("Connect failed:", err)
    }

    if err := ic.HandShake(); err != nil {
        log.Panic("HandShake failed:", err)
    }

    // Create a contract for SPY ETF
    spyContract := ibapi2.Contract{
        Symbol:       "SPY",
        SecurityType: "STK",
        Exchange:     "SMART",
        Currency:     "USD",
    }

    // Set the request ID
    reqID := ic.GetReqID()

    // Get the contract details to ensure proper contract is created
    // ic.ReqContractDetails(reqID, &spyContract)

    // Request delayed market data for SPY
    ic.ReqMarketDataType(3) // 3 or 4 for delayed, 1 when you have subscribed to real-time market data
    ic.ReqHistoricalData(reqID, &spyContract, "", "1 D", "5 mins", "TRADES", false, 2, true, []ibapi2.TagValue{}) // time.Now().In(time.FixedZone("EST", -5*60*60)).Format("20060102 15:04:05")
    ic.Run()

    // Example log output:
    /*
        {"level":"info","ts":1704767599.3692198,"caller":"[email protected]/wrapper.go:353","msg":"<HistoricalData>","reqID":1,"bar":"BarData<Date: 1704186000, Open: 476.250000, High: 476.360000, Low: 476.000000, Close: 476.270000, Volume: 323.000000, Average: 476.301000, BarCount: 70>"}
        ...
        {"level":"info","ts":1704767599.4046462,"caller":"[email protected]/wrapper.go:353","msg":"<HistoricalData>","reqID":1,"bar":"BarData<Date: 1704743700, Open: 473.510000, High: 474.000000, Low: 473.500000, Close: 473.760000, Volume: 10218.000000, Average: 473.790000, BarCount: 5146>"}
        {"level":"info","ts":1704767599.4046462,"caller":"[email protected]/wrapper.go:359","msg":"<HistoricalDataEnd>","reqID":1,"startDate":"20240101  20:33:17","endDate":"20240108  20:33:17"}
    */

    // Wait a bit to receive some data
    <-time.After(time.Second * 15)

    // First inspection of the historical data
    fmt.Printf("First inspection of the historical data:\n")
    for _, bar := range ibapi2.GetHistoricalData() {
        fmt.Printf("Date: %v, Open: %v, High: %v, Low: %v, Close: %v, Volume: %v\n",
            bar.DateTime,
            bar.Open,
            bar.High,
            bar.Low,
            bar.Close,
            bar.Volume,
        )
    }

    // Wait 10 minutes to allow for more 5-minute data to be generated by IB
    <-time.After(time.Second * 610)

    // Request more historical data for SPY. Run ic.Run() again?
    //ic.ReqHistoricalData(reqID, &spyContract, "", "1 D", "5 mins", "TRADES", false, 2, true, []ibapi2.TagValue{})
    //ic.Run()

    // Second inspection of the historical data
    fmt.Print("Second inspection of the historical data:\n")
    for _, bar := range ibapi2.GetHistoricalData() {
        fmt.Printf("Date: %v, Open: %v, High: %v, Low: %v, Close: %v, Volume: %v\n",
            bar.DateTime,
            bar.Open,
            bar.High,
            bar.Low,
            bar.Close,
            bar.Volume,
        )
    }

    // Cancel the historical data request
    ic.CancelHistoricalData(reqID)

    ic.Disconnect()
}

You can see that I am employing the wait of about 10 minutes which should pull fresher up to date bar data after the first pull, however when you inspect the outputs, the bar data is the same. When you re-run the entire script, the more recent data IS pulled, however I thought there would be a better way to pull up to date data with the SAME ic instance without having to disconnect/reconnect/make a new client etc. I also have commented out a section that tries to run the ic.Run() method again, but again the output of bars pulled from the server doesn't change.

Any ideas?

The TWS is out of date and must be upgraded. It does not support tick-by-tick data requests

Getting The TWS is out of date and must be upgraded. It does not support tick-by-tick data requests error when executing ReqTickByTickData. TWS Build 10.23.2a, Jun 15, 2023 4:54:18 PM.

Code:

package main

import (
	"context"
	. "github.com/hadrianl/ibapi"
	"github.com/urfave/cli/v2"
	"log"
	"time"
)

func marketData(c *cli.Context) error {
	var err error
	ibwrapper := &Wrapper{}
	ctx, _ := context.WithTimeout(context.Background(), time.Second*30)
	ic := NewIbClient(ibwrapper)
	ic.SetContext(ctx)
	err = ic.Connect(c.String("api_addr"), c.Int("api_port"), 0)
	if err != nil {
		log.Panic("Connect failed:", err)
	}
	ic.ReqTickByTickData(1, &Contract{Symbol: "EUR", SecurityType: "CFD", Currency: "USD", Exchange: "IDEALPRO"}, "BidAsk", 1, true)
	ic.ReqAccountSummary(2, "All", "$LEDGER:ALL")
	err = ic.HandShake()
	if err != nil {
		log.Panic("Handshake failed:", err)
	}
	select {}
}

Log:

$ bin/ibkr marketdata 
{"level":"info","ts":1688961194.2617188,"caller":"[email protected]/client.go:107","msg":"Connect to client","host":"","port":7497,"clientID":0}
{"level":"info","ts":1688961194.2618957,"caller":"[email protected]/wrapper.go:658","msg":"<Error>","reqID":-1,"errCode":503,"errString":"The TWS is out of date and must be upgraded. It does not support tick-by-tick data requests."}
{"level":"info","ts":1688961194.2619295,"caller":"[email protected]/client.go:177","msg":"HandShake with TWS or GateWay"}
{"level":"info","ts":1688961194.3337462,"caller":"[email protected]/client.go:223","msg":"handShake info","serverVersion":161}
{"level":"info","ts":1688961194.3337836,"caller":"[email protected]/client.go:224","msg":"handShake info","connectionTime":"20230710 06:53:14 EET"}
{"level":"info","ts":1688961194.3649023,"caller":"[email protected]/wrapper.go:125","msg":"<ManagedAccounts>","accountList":["U<hidden>"]}
{"level":"info","ts":1688961194.3649392,"caller":"[email protected]/wrapper.go:121","msg":"<NextValidID>","reqID":1}
{"level":"info","ts":1688961194.3649545,"caller":"[email protected]/wrapper.go:112","msg":"<ConnectAck>..."}
{"level":"info","ts":1688961194.3649628,"caller":"[email protected]/client.go:272","msg":"HandShake completed"}

Order Conditions not working

Hi,

It seems there's a problem with InitOrderCondition, the condition is not being passed upon OrderCondition, so the value is always 0. I tried initializing it with a TimeCondition and a margin condition, but this always crashes the ib client. I also tried to assert it to time condition, but both the asserted and original OrderConditioner doesn't seem to be carrying conType forward and since this variable isn't exported, it's not possible to set it from an outside package.

I did a workaround and created a factory function to solve my problem, but of course, this is not optimal.

func NewTimeCondition(time string, isMore bool, isConj bool) TimeCondition {
	oc := OrderCondition{
		conditionType:           3,
		IsConjunctionConnection: isConj,
	}
	tc := TimeCondition{
		OperatorCondition: OperatorCondition{oc, isMore},
		Time:              time,
	}
	return tc
}

I'm using golang 1.17/MacOS 12.0.1

ReqHistoricalData() example?

I can't get ReqHistoricalData() to work. Do you have an example?

c := ibapi.Contract{ContractID: 309359839, Symbol: "HSI", SecurityType: "FUT", Exchange: "HKFE"}
ic.ReqMarketDataType(3)
ic.ReqHistoricalData(ic.GetReqID(), &c, "", "1 W", "1 D", "MIDPOINT", false, 1, true, nil)

is this API ready for production development

Hi, I'm insterested in work with interactive broker with go and I'd like to know the status of this API and what is missing?...do you think that I can use this without problems for my development? thank you so much

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.