// NewTestFeedContext provides a simple way of producing a FeedContext for tests. func NewTestFeedContext(t *testing.T) *TestFeedContext { c := core.NewTestConfig(t) ctx, err := core.NewContext(c) if err != nil { t.Fatal(err) } engine, err := ib.NewEngine(ib.NewEngineOptions{Gateway: c.IbGws[0]}) if err != nil { t.Fatal(err) } fc := &FeedContext{ Errors: make(chan FeedError), DB: ctx.DB, N: ctx.N, Eng: engine, } return &TestFeedContext{ ctx: ctx, FC: fc, } }
func (g *GatewayService) initGatewayService() { go func() { feeds := []*Feed{} esl := make(chan ib.EngineState) var err error g.ctx.Eng, err = ib.NewEngine(ib.NewEngineOptions{Gateway: g.ibGw, Client: int64(g.ibClientId)}) if err == nil { defer g.ctx.Eng.Stop() g.ctx.Eng.SubscribeState(esl) defer g.ctx.Eng.UnsubscribeState(esl) for _, ff := range g.ffs { feeds = append(feeds, ff.NewFeed(g.ctx)) } } else { g.errors <- GatewayError{err, g.ibGw} } for { select { case <-g.terminated: return case <-g.exit: errsink := make(chan struct{}) go func() { select { case <-errsink: return case <-g.ctx.Errors: } }() for _, feed := range feeds { (*feed).Close() } close(errsink) close(g.terminated) case feederr := <-g.ctx.Errors: g.errors <- GatewayError{feederr.Error, g.ibGw} case es := <-esl: if es != ib.EngineReady { // Engine should never report this state (in normal shutdown we've unsubscribed, so we would never receive this state change) err = g.ctx.Eng.FatalError() if err == nil { err = fmt.Errorf("%s without reporting fatal error", es.String()) } g.errors <- GatewayError{err, g.ibGw} } } } }() }
func main() { // Output TWS messages to a separate file and use a split screen terminal to show them. if false { f, err := os.OpenFile("stockcli.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) if err != nil { log.Fatalf("LOG ERROR: %v", err) } defer f.Close() log.SetOutput(f) } log.SetFlags(log.Ltime | log.Lmicroseconds) // load configuration from config, cerr := LoadConfigFromFile("config.js") if cerr != nil { log.Fatalf("ERROR loading initial config %v", cerr) return } acct := make([]*IBManager, 0) for _, a := range config.Accounts { log.Printf("SETUP: %s %v", a.Label, a.Paper) acct = append(acct, &IBManager{ label: a.Label, paper: a.Paper, opts: ib.EngineOptions{ Gateway: a.Gateway, Client: a.Client, }, elog: make(map[string]*ExecutionInfo), realtimeMap: make(map[int64]string), }) } for _, ac := range acct { var err error ac.engine, err = ib.NewEngine(ac.opts) if err != nil { log.Fatalf("error creating %s Engine %v ", ac.label, err) } defer ac.engine.Stop() if ac.engine.State() != ib.EngineReady { log.Fatalf("%s engine is not ready", ac.label) } go engineLoop(ac) } time.Sleep(1 * time.Second) acctselect := "" prompt := "> " // Loop until Readline returns nil (signalling EOF) lastresult := "" L: for { result := readline.Readline(&prompt) if result == nil { fmt.Println() continue } // prevent duplicate calls if *result == lastresult { continue } lastresult = *result strs := strings.Fields(strings.TrimSpace(*result)) if len(strs) == 0 { continue } if *result != "" { readline.AddHistory(*result) } command := strs[0] switch { case command == "exit": break L // exit loop case command == "quit": break L // exit loop case command == "summary": lastresult = "" applyFunc(true, acctselect, acct, func(ac *IBManager) error { reqAs := &ib.RequestAccountSummary{} reqAs.SetID(ac.engine.NextRequestID()) reqAs.Group = "All" reqAs.Tags = "BuyingPower,NetLiquidation,GrossPositionValue,TotalCashValue,SettledCash,InitMarginReq,MaintMarginReq,AvailableFunds,TotalCashValue,UnrealizedPnL" ac.engine.Send(reqAs) shownewline = true return nil }) case command == "open": lastresult = "" applyFunc(true, acctselect, acct, func(ac *IBManager) error { ac.engine.Send(&ib.RequestOpenOrders{}) shownewline = true return nil }) case command == "positions": lastresult = "" applyFunc(true, acctselect, acct, func(ac *IBManager) error { req := &ib.RequestPositions{} ac.engine.Send(req) shownewline = true return nil }) case command == "updates": lastresult = "" applyFunc(true, acctselect, acct, func(ac *IBManager) error { req := &ib.RequestAccountUpdates{} req.Subscribe = true ac.engine.Send(req) shownewline = true return nil }) case command == "noupdates": lastresult = "" applyFunc(true, acctselect, acct, func(ac *IBManager) error { req := &ib.RequestAccountUpdates{} req.Subscribe = false ac.engine.Send(req) return nil }) case command == "elog": lastresult = "" applyFunc(true, acctselect, acct, func(ac *IBManager) error { ac.elog = make(map[string]*ExecutionInfo) ereq := ib.RequestExecutions{} ereq.SetID(ac.engine.NextRequestID()) ac.engine.Send(&ereq) shownewline = true return nil }) case command == "select": lastresult = "" if len(strs) != 2 { fmt.Printf("select <label|all>\n") continue } if strs[1] == "all" { acctselect = "" prompt = "> " } else { for _, ac := range acct { if ac.label == strs[1] { acctselect = ac.label prompt = acctselect + " > " break } } } case command == "sell-t": if len(strs) != 4 { fmt.Printf("sell-t <symbol> <quantity> <trailamount>\n") continue } quantity, _ := strconv.ParseUint(strs[2], 10, 64) trailamount, _ := strconv.ParseFloat(strs[3], 64) applyFunc(false, acctselect, acct, func(ac *IBManager) error { doSellTrail(ac, strs[1], quantity, trailamount) shownewline = true return nil }) case command == "sell-tl": if len(strs) != 6 { fmt.Printf("sell-tl <symbol> <quantity> <stopprice> <trailamount> <limitoffset>\n") continue } quantity, _ := strconv.ParseUint(strs[2], 10, 64) stopprice, _ := strconv.ParseFloat(strs[3], 64) trailamount, _ := strconv.ParseFloat(strs[4], 64) limitoffset, _ := strconv.ParseFloat(strs[5], 64) applyFunc(false, acctselect, acct, func(ac *IBManager) error { doSellTrailLimit(ac, strs[1], quantity, trailamount, stopprice, limitoffset) shownewline = true return nil }) case command == "sell-l": if len(strs) != 4 { fmt.Printf("sell-l <symbol> <quantity> <limitprice>\n") continue } quantity, _ := strconv.ParseUint(strs[2], 10, 64) limitprice, _ := strconv.ParseFloat(strs[3], 64) applyFunc(false, acctselect, acct, func(ac *IBManager) error { doSell(ac, strs[1], quantity, false, limitprice) shownewline = true return nil }) case command == "sell-m": if len(strs) != 3 { fmt.Printf("sell-m <symbol> <quantity>\n") continue } quantity, _ := strconv.ParseUint(strs[2], 10, 64) applyFunc(false, acctselect, acct, func(ac *IBManager) error { doSell(ac, strs[1], quantity, true, 0) shownewline = true return nil }) case command == "buy-t": if len(strs) != 4 { fmt.Printf("buy-t <symbol> <quantity> <trailamount>\n") continue } quantity, _ := strconv.ParseUint(strs[2], 10, 64) trailamount, _ := strconv.ParseFloat(strs[3], 64) applyFunc(false, acctselect, acct, func(ac *IBManager) error { doBuyTrail(ac, strs[1], quantity, trailamount) shownewline = true return nil }) case command == "buy-if": if len(strs) != 4 { fmt.Printf("buy-if <symbol> <quantity> <trailamount>\n") continue } quantity, _ := strconv.ParseUint(strs[2], 10, 64) trailamount, _ := strconv.ParseFloat(strs[3], 64) applyFunc(false, acctselect, acct, func(ac *IBManager) error { doBuyTrailMarketIfTouched(ac, strs[1], quantity, trailamount) shownewline = true return nil }) case command == "buy-tl": if len(strs) != 6 { fmt.Printf("buy-tl <symbol> <quantity> <stopprice> <trailamount> <limitoffset>\n") continue } quantity, _ := strconv.ParseUint(strs[2], 10, 64) stopprice, _ := strconv.ParseFloat(strs[3], 64) trailamount, _ := strconv.ParseFloat(strs[4], 64) limitoffset, _ := strconv.ParseFloat(strs[5], 64) applyFunc(false, acctselect, acct, func(ac *IBManager) error { doBuyTrailLimit(ac, strs[1], quantity, trailamount, stopprice, limitoffset) shownewline = true return nil }) case command == "buy-l": if len(strs) != 4 { fmt.Printf("buy-l <symbol> <quantity> <limitprice>\n") continue } quantity, _ := strconv.ParseUint(strs[2], 10, 64) limitprice, _ := strconv.ParseFloat(strs[3], 64) applyFunc(false, acctselect, acct, func(ac *IBManager) error { doBuy(ac, strs[1], quantity, false, limitprice) shownewline = true return nil }) case command == "buy-m": if len(strs) != 3 { fmt.Printf("buy-m <symbol> <quantity>\n") continue } quantity, _ := strconv.ParseUint(strs[2], 10, 64) applyFunc(false, acctselect, acct, func(ac *IBManager) error { doBuy(ac, strs[1], quantity, true, 0) shownewline = true return nil }) case command == "bracket": if len(strs) != 6 { fmt.Printf("bracket <symbol> <quantity> <buyprice> <sellprice> <stopprice>\n") continue } quantity, _ := strconv.ParseUint(strs[2], 10, 64) buyprice, _ := strconv.ParseFloat(strs[3], 64) sellprice, _ := strconv.ParseFloat(strs[4], 64) stopprice, _ := strconv.ParseFloat(strs[5], 64) applyFunc(false, acctselect, acct, func(ac *IBManager) error { doBracket(ac, strs[1], quantity, buyprice, sellprice, stopprice) shownewline = true return nil }) case command == "brka": if len(strs) != 6 { fmt.Printf("brka <symbol> <quantity> <buyprice> <selloff> <stopoff>\n") continue } quantity, _ := strconv.ParseUint(strs[2], 10, 64) buyprice, _ := strconv.ParseFloat(strs[3], 64) sellprice, _ := strconv.ParseFloat(strs[4], 64) stopprice, _ := strconv.ParseFloat(strs[5], 64) applyFunc(false, acctselect, acct, func(ac *IBManager) error { doBracket(ac, strs[1], quantity, buyprice, buyprice+sellprice, buyprice-stopprice) shownewline = true return nil }) case command == "brkp1": if len(strs) != 4 { fmt.Printf("brkp1 <symbol> <quantity> <buyprice> {sell = buy + 0.20, stp = buy - 0.05} \n") continue } quantity, _ := strconv.ParseUint(strs[2], 10, 64) buyprice, _ := strconv.ParseFloat(strs[3], 64) sellprice := buyprice + 0.20 stopprice := buyprice - 0.05 applyFunc(false, acctselect, acct, func(ac *IBManager) error { doBracket(ac, strs[1], quantity, buyprice, sellprice, stopprice) shownewline = true return nil }) case command == "brkp2": if len(strs) != 4 { fmt.Printf("brkp2 <symbol> <quantity> <buyprice> {sell = buy + 0.11, stp = buy - 0.05} \n") continue } quantity, _ := strconv.ParseUint(strs[2], 10, 64) buyprice, _ := strconv.ParseFloat(strs[3], 64) sellprice := buyprice + 0.11 stopprice := buyprice - 0.05 applyFunc(false, acctselect, acct, func(ac *IBManager) error { doBracket(ac, strs[1], quantity, buyprice, sellprice, stopprice) shownewline = true return nil }) case command == "stop-m": if len(strs) != 4 { fmt.Printf("stop-m <symbol> <quantity> <stopprice>\n") continue } quantity, _ := strconv.ParseUint(strs[2], 10, 64) stopprice, _ := strconv.ParseFloat(strs[3], 64) applyFunc(false, acctselect, acct, func(ac *IBManager) error { doStopMarket(ac, strs[1], quantity, stopprice) shownewline = true return nil }) case command == "override": if len(strs) != 2 { fmt.Printf("override status %v\n", gUpdateOverride) continue } if strs[1] == "on" { gUpdateOverride = true } else { gUpdateOverride = false } fmt.Printf("override %v\n", gUpdateOverride) case command == "rth": if len(strs) != 2 { fmt.Printf("rth status %v\n", gEnableRTH) continue } if strs[1] == "on" { gEnableRTH = true } else { gEnableRTH = false } fmt.Printf("rth status %v\n", gEnableRTH) case command == "gtc": if len(strs) != 2 { fmt.Printf("gtc status %v\n", gEnableGTC) continue } if strs[1] == "on" { gEnableGTC = true } else { gEnableGTC = false } fmt.Printf("gtc status %v\n", gEnableGTC) case command == "acct-cancel": if len(strs) != 2 { fmt.Printf("acct-cancel status %v\n", gCancel) continue } if strs[1] == "on" { gCancel = true } else { gCancel = false } fmt.Printf("acct-cancel status %v\n", gCancel) case command == "realtimebar": if len(strs) != 2 { fmt.Printf("realtimebar <symbol>\n") continue } applyFunc(false, acctselect, acct, func(ac *IBManager) error { doRequestRealTimeBars(ac, strs[1]) return nil }) case command == "cancel": lastresult = "" if len(strs) != 2 { fmt.Printf("cancel <orderid>\n") continue } orderid := int64(0) if strs[1] != "all" { orderid, _ = strconv.ParseInt(strs[1], 10, 64) } applyFunc(true, acctselect, acct, func(ac *IBManager) error { if strs[1] == "all" { ac.engine.Send(&ib.RequestGlobalCancel{}) } else { request := ib.CancelOrder{} request.SetID(orderid) ac.engine.Send(&request) shownewline = true } return nil }) case command == "cancelall": lastresult = "" applyFunc(true, acctselect, acct, func(ac *IBManager) error { ac.engine.Send(&ib.RequestGlobalCancel{}) shownewline = true return nil }) case command != "": // Ignore blank lines fmt.Println(*result) } } }
func main() { //deal with os.Args checkArgErrors(os.Args[1], os.Args[2], os.Args[3], os.Args[4], os.Args[5]) theAction := os.Args[1] theAcct := acctNametoNumber(os.Args[2]) useLeverage := os.Args[3] == "l" argShares := os.Args[4] outsideRTH, err := strconv.ParseBool(os.Args[5]) if os.Args[5] == "outside" { outsideRTH = true } else { outsideRTH = false } myEngine, err := ib.NewEngine(ib.EngineOptions{}) if err != nil { panic(err) } myAccountManager, err := ib.NewAdvisorAccountManager(myEngine) if err != nil { panic(err) } <-myAccountManager.Refresh() defer myAccountManager.Close() valueMap := myAccountManager.Values() stockFromYahoo, err := stocks.GetQuote(ticker) if err != nil { fmt.Println(err) } aQuote, err := stockFromYahoo.GetPrice() if err != nil { fmt.Println(err) } quoteSlipped := Round((aQuote+(aQuote*slippage))*100) / 100 //check on shares based on leverage for aVk, aV := range valueMap { //availableFunds are either buyingPower or netliquadation correctAcct := (aVk.AccountCode == theAcct) correctForLever := (aVk.Key == "BuyingPower") && useLeverage correctForNoLever := (aVk.Key == "BuyingPower") && !useLeverage if correctAcct && correctForLever { shares = getShares(argShares, aV.Value, quoteSlipped) shares = shares - int64(float64(shares)*0.6) } if correctAcct && correctForNoLever { shares = getShares(argShares, aV.Value, quoteSlipped) } } // fmt.Println("quote", aQuote, "slipped-", quoteSlipped, "shares", shares) mgr := IBManager{engine: myEngine} mgr.engine.SubscribeAll(rc) mgr.engine.Send(&ib.RequestIDs{}) nextOrderID = getNextOrderID(mgr) // fmt.Println("the next order ID is: ", nextOrderID) if theAction == "buy" { doBuy(&mgr, "AAPL", shares, // number shares "LOC", // mkt, moc, lmt quoteSlipped, // price theAcct, // account "DAY", // DAY OPG nextOrderID, outsideRTH) //out side regular trading hours } else if theAction == "sell" { //positions := ib.RequestPositions doSell(&mgr, "AAPL", shares, "MARKET", "OPG", nextOrderID) } else { fmt.Println("neither a buy nor a sell") } // nextOrderID = getNextOrderID(mgr) }