Skip to content

deepln-io/longbridge-goapi

Repository files navigation

Long Bridge Broker Golang API

PkgGoDev

Long Bridge is a promising broker emerging in the stock market with first rate trading app. Recently (May 10, 2022) they released the OpenAPI for quants https://longbridgeapp.com/en/topics/2543341?channel=t2543341&invite-code=0VMCD7.

This is a go implementation of full long bridge broker APIs based on the document in https://open.longbridgeapp.com/en/docs.

For API in other languages, please refer to longbridge's official github site at https://github.com/longbridgeapp.

Features

  • Support full long bridge APIs for trading, accessing to account portfolio and subscribing real time market data.
  • Strong typed APIs.
  • Maintain auto reconnection of long connection for trading and quote subscriptions to fit for full automatic production environment.
  • Support both secured web socket and TCP connection.
  • Pure golang implementation.

Installation

go get github.com/deepln-io/longbridge-goapi

How to use it

The package provides two sets of APIs through TradeClient and QuoteClient for trading and quote respectively.

The library automatically manages the connection to long bridge servers and will reconnect if disconnected. This is useful for real production systems when a trading bot is running continuously overnight.

To use the trade notification, set order notification call back through TradeClient.OnOrderChange(order *longbridge.Order).

Note to run the examples, please make sure that your long bridge account is ready with access token, app key and secret available. Set them in env variable before running.

export LB_ACCESS_TOKEN="<access token from your account's developer center>"
export LB_APP_KEY="<your app key>"
export LB_APP_SECRET="<your app secret>"

Examples

Get the stock static information. The code connects to long bridge, gets down the static security information, and prints them out.

package main
import (
    "log"
    "os"

    "github.com/deepln-io/longbridge-goapi"
)

func main() {
	c, err := longbridge.NewQuoteClient(&longbridge.Config{
		AccessToken: os.Getenv("LB_ACCESS_TOKEN"),
		AppKey:      os.Getenv("LB_APP_KEY"),
		AppSecret:   os.Getenv("LB_APP_SECRET"),
		QuoteEndpoint: "tcp://openapi-quote.longbridgeapp.com:2020",  // Optionally choose TCP connection here
	})
	if err != nil {
		log.Fatalf("Error creating longbridge client: %v", err)
	}
	defer c.Close()
	ss, err := c.GetStaticInfo([]string{"700.HK", "AAPL.US"})
	if err != nil {
		log.Fatalf("Error getting static info: %v", err)
	}
	for _, s := range ss {
		log.Printf("%#v\n", s)
	}
}

Get real time price Make sure you have real time quote access permission from Long Bridge.

package main
import (
    "log"
    "os"

    "github.com/deepln-io/longbridge-goapi"
)

func main() {
	c, err := longbridge.NewQuoteClient(&longbridge.Config{
		AccessToken: os.Getenv("LB_ACCESS_TOKEN"),
		AppKey:      os.Getenv("LB_APP_KEY"),
		AppSecret:   os.Getenv("LB_APP_SECRET"),
	})
	if err != nil {
		log.Fatalf("Error creating longbridge client: %v", err)
	}
	defer c.Close()
	qs, err := c.GetRealtimeQuote([]string{"5.HK", "MSFT.US"})
	if err != nil {
		log.Fatalf("Error getting real time quote: %v", err)
	}
	for _, q := range qs {
		log.Printf("%#v\n", q)
	}
}

Get account positions

package main
import (
    "log"
    "os"

    "github.com/deepln-io/longbridge-goapi"
)

func main() {
	c, err := longbridge.NewTradeClient(&longbridge.Config{
		AccessToken:   os.Getenv("LB_ACCESS_TOKEN"),
		AppKey:        os.Getenv("LB_APP_KEY"),
		AppSecret:     os.Getenv("LB_APP_SECRET"),
	})
	if err != nil {
		log.Fatalf("Error creating longbridge client: %v", err)
	}
	defer c.Close()
	positions, err := c.GetStockPositions()
	if err != nil {
		log.Fatalf("Error getting stock positions: %v", err)
	}
	for _, position := range positions {
		log.Printf("%+v", position)
	}
}

Place an order

package main
import (
    "log"
    "os"
    "time"

    "github.com/deepln-io/longbridge-goapi"
)

func main() {
    c, err := longbridge.NewTradeClient(&longbridge.Config{
		AccessToken:   os.Getenv("LB_ACCESS_TOKEN"),
		AppKey:        os.Getenv("LB_APP_KEY"),
		AppSecret:     os.Getenv("LB_APP_SECRET"),
	})
	if err != nil {
		log.Fatalf("Error creating longbridge client: %v", err)
	}
	defer c.Close()
	orderID, err := c.PlaceOrder(&longbridge.PlaceOrderReq{
		Symbol:      "AMD.US",
		OrderType:   longbridge.LimitOrder,
		Price:       180,
		Quantity:    1,
		ExpireDate:  time.Now().AddDate(0, 1, 0),
		Side:        longbridge.Sell,
		OutsideRTH:  longbridge.AnyTime,
		TimeInForce: longbridge.GoodTilCancel,
		Remark:      "钓鱼单",
	})
	if err != nil {
		log.Fatalf("Error placing order: %v", err)
	}

Place, modify and cancel order

package main
import (
    "log"
    "os"
    "time"

    "github.com/deepln-io/longbridge-goapi"
)

func main() {
	c, err := longbridge.NewTradeClient(&longbridge.Config{
		AccessToken:   os.Getenv("LB_ACCESS_TOKEN"),
		AppKey:        os.Getenv("LB_APP_KEY"),
		AppSecret:     os.Getenv("LB_APP_SECRET"),
	})
	if err != nil {
		log.Fatalf("Error creating longbridge client: %v", err)
	}
	defer c.Close()
	orderID, err := c.PlaceOrder(&longbridge.PlaceOrderReq{
		Symbol:      "AMD.US",
		OrderType:   longbridge.LimitOrder,
		Price:       180,
		Quantity:    1,
		ExpireDate:  time.Now().AddDate(0, 1, 0),
		Side:        longbridge.Sell,
		OutsideRTH:  longbridge.AnyTime,
		TimeInForce: longbridge.GoodTilCancel,
		Remark:      "钓鱼单",
	})
	if err != nil {
		log.Fatalf("Error placing order: %v", err)
	}
	time.Sleep(time.Second)
	if err := c.ModifyOrder(&longbridge.ModifyOrderReq{
		OrderID:      orderID,
		Quantity:     1,
		Price:        200,
		TriggerPrice: 200,
	}); err != nil {
		log.Fatalf("Error modifying submitted order (id: %v): %v", orderID, err)
	}
	log.Printf("Order modified successfully, ID: %v", orderID)

	time.Sleep(time.Second)
	if err := c.CancelOrder(orderID); err != nil {
		log.Fatalf("Error cancelling submitted order (id: %v): %v", orderID, err)
	}

	log.Printf("Order cancelled successfully, ID: %v", orderID)
}

Pull real time tick data

package main
import (
    "log"
    "os"

    "github.com/deepln-io/longbridge-goapi"
)

func main() {
	c, err := longbridge.NewQuoteClient(&longbridge.Config{
		AccessToken: os.Getenv("LB_ACCESS_TOKEN"),
		AppKey:      os.Getenv("LB_APP_KEY"),
		AppSecret:   os.Getenv("LB_APP_SECRET"),
	})
	if err != nil {
		log.Fatalf("Error creating longbridge client: %v", err)
	}
	defer c.Close()
	ts, err := c.GetTickers("AAPL.US", 10)
	if err != nil {
		log.Fatalf("Error getting tickers for: %v", err)
	}
	for _, t := range ts {
		log.Printf("%#v", t)
	}
}

Subscribe level 2 tick data with callback

package main
import (
    "log"
    "os"
    "time"

    "github.com/deepln-io/longbridge-goapi"
)

func main() {
	c, err := longbridge.NewQuoteClient(&longbridge.Config{
		AccessToken: os.Getenv("LB_ACCESS_TOKEN"),
		AppKey:      os.Getenv("LB_APP_KEY"),
		AppSecret:   os.Getenv("LB_APP_SECRET"),
	})
	if err != nil {
		log.Fatalf("Error creating longbridge client: %v", err)
	}
	defer c.Close()
	c.OnPushTickers = func(t *longbridge.PushTickers) {
		log.Printf("Got tickers for %s, seq=%d", t.Symbol, t.Sequence)
		for _, ticker := range t.Tickers {
			log.Printf("Ticker: %#v", ticker)
		}
	}

	ss, err := c.SubscribePush([]string{"AAPL.US"},
		[]longbridge.SubscriptionType{longbridge.SubscriptionTicker}, true)
	if err != nil {
		log.Fatalf("Error subscribe quote push: %v", err)
	}
	for _, s := range ss {
		log.Printf("%#v", s)
	}

	time.Sleep(30 * time.Second)
	if err := c.UnsubscribePush(nil,
		[]longbridge.SubscriptionType{longbridge.SubscriptionTicker}, true); err != nil {
		log.Fatalf("Error unsubscribing all symbols' quote push: %v", err)
	}
}

Acknowledge

Thanks the long bridge development team for patiently replying a lot of technical questions to clarify the API details during our development.

License

MIT License

Development

When longbridge protobuf files are updated, run the script gen-pb.sh in internal dir and push the changes.

Contributing

We are always happy to welcome new contributors! If you have any questions, please feel free to reach out by opening an issue or leaving a comment.