-
Notifications
You must be signed in to change notification settings - Fork 65
Description
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":"ibapi@v0.0.0-20230925013244-4f647c0e9c16/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":"ibapi@v0.0.0-20230925013244-4f647c0e9c16/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":"ibapi@v0.0.0-20230925013244-4f647c0e9c16/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?