From 774760dde9320603084bdbbf750e326377331778 Mon Sep 17 00:00:00 2001 From: Michael Wilner Date: Thu, 13 Sep 2018 10:25:24 -0500 Subject: [PATCH 1/7] First cut at websocket callback structure --- .gitignore | 2 ++ examples/v2/ws-callbacks/README.md | 3 ++ examples/v2/ws-callbacks/main.go | 56 ++++++++++++++++++++++++++++++ v2/websocket/api.go | 6 ++-- v2/websocket/channels.go | 6 ++-- v2/websocket/client.go | 40 +++++++++++++++++---- v2/websocket/events.go | 12 +++---- 7 files changed, 107 insertions(+), 18 deletions(-) create mode 100644 .gitignore create mode 100644 examples/v2/ws-callbacks/README.md create mode 100644 examples/v2/ws-callbacks/main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..c6ef2182b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea + diff --git a/examples/v2/ws-callbacks/README.md b/examples/v2/ws-callbacks/README.md new file mode 100644 index 000000000..b46429664 --- /dev/null +++ b/examples/v2/ws-callbacks/README.md @@ -0,0 +1,3 @@ +# Websocket callbacks + +This is a simple example showing off how to connect to the websocket service, subscribe to a few events, and register callbacks for them diff --git a/examples/v2/ws-callbacks/main.go b/examples/v2/ws-callbacks/main.go new file mode 100644 index 000000000..8e743a857 --- /dev/null +++ b/examples/v2/ws-callbacks/main.go @@ -0,0 +1,56 @@ +package main + +import ( + "context" + "log" + "time" + + "github.com/bitfinexcom/bitfinex-api-go/v2" + "github.com/bitfinexcom/bitfinex-api-go/v2/websocket" +) + +func bookUpdateCallback(msg interface{}) { + log.Printf("BookUpdate - callback triggered for: %#v", msg) +} + +func tradeCallback(msg interface{}) { + log.Printf("Trade ------ callback triggered for: %#v", msg) +} + +func main() { + c := websocket.New() + + err := c.Connect() + if err != nil { + log.Fatal("Error connecting to web socket : ", err) + } + + // register callbacks for book updates and trades + c.RegisterCallback(bitfinex.BookUpdate{}, bookUpdateCallback) + c.RegisterCallback(bitfinex.Trade{}, tradeCallback) + + // subscribe to BTCUSD book + ctx, cxl1 := context.WithTimeout(context.Background(), time.Second*5) + defer cxl1() + _, err = c.SubscribeBook(ctx, bitfinex.TradingPrefix+bitfinex.BTCUSD, bitfinex.Precision0, bitfinex.FrequencyRealtime, 25) + if err != nil { + log.Fatal(err) + } + + // subscribe to BTCUSD trades + ctx, cxl2 := context.WithTimeout(context.Background(), time.Second*5) + defer cxl2() + _, err = c.SubscribeTrades(ctx, bitfinex.TradingPrefix+bitfinex.BTCUSD) + if err != nil { + log.Fatal(err) + } + + for obj := range c.Listen() { + switch obj.(type) { + case error: + log.Printf("channel closed: %s", obj) + break + default: + } + } +} diff --git a/v2/websocket/api.go b/v2/websocket/api.go index 35975bf37..82731d695 100644 --- a/v2/websocket/api.go +++ b/v2/websocket/api.go @@ -17,7 +17,7 @@ func (c *Client) Send(ctx context.Context, msg interface{}) error { // Subscribe sends a subscription request to the Bitfinex API and tracks the subscription status by ID. func (c *Client) Subscribe(ctx context.Context, req *SubscriptionRequest) (string, error) { c.subscriptions.add(req) - err := c.asynchronous.Send(ctx, req) + err := c.Send(ctx, req) if err != nil { // propagate send error return "", err @@ -80,12 +80,12 @@ func (c *Client) SubscribeCandles(ctx context.Context, symbol string, resolution // SubmitOrder sends an order request. func (c *Client) SubmitOrder(ctx context.Context, order *bitfinex.OrderNewRequest) error { - return c.asynchronous.Send(ctx, order) + return c.Send(ctx, order) } // SubmitCancel sends a cancel request. func (c *Client) SubmitCancel(ctx context.Context, cancel *bitfinex.OrderCancelRequest) error { - return c.asynchronous.Send(ctx, cancel) + return c.Send(ctx, cancel) } // LookupSubscription looks up a subscription request by ID diff --git a/v2/websocket/channels.go b/v2/websocket/channels.go index c932aaf01..89b69d3ca 100644 --- a/v2/websocket/channels.go +++ b/v2/websocket/channels.go @@ -70,7 +70,7 @@ func (c *Client) handlePublicChannel(chanID int64, channel, objType string, data return err } if msg != nil { - c.listener <- msg + c.deliverMsg(msg) } } else if len(flt) > 1 { msg, err := factory.BuildSnapshot(chanID, flt) @@ -78,7 +78,7 @@ func (c *Client) handlePublicChannel(chanID int64, channel, objType string, data return err } if msg != nil { - c.listener <- msg + c.deliverMsg(msg) } } } else { @@ -108,7 +108,7 @@ func (c *Client) handlePrivateChannel(raw []interface{}) error { } // private data is returned as strongly typed data, publish directly if obj != nil { - c.listener <- obj + c.deliverMsg(obj) } } } diff --git a/v2/websocket/client.go b/v2/websocket/client.go index f79c7f848..528cd37b3 100644 --- a/v2/websocket/client.go +++ b/v2/websocket/client.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "log" + "reflect" "strings" "sync" "time" @@ -90,6 +91,9 @@ func (w *WebsocketAsynchronousFactory) Create() Asynchronous { return newWs(w.parameters.URL, w.parameters.LogTransport) } +// ClientCallback provides a specified callback type for handling API objects +type ClientCallback func(interface{}) + // Client provides a unified interface for users to interact with the Bitfinex V2 Websocket API. type Client struct { asyncFactory AsynchronousFactory // for re-creating transport during reconnects @@ -117,7 +121,10 @@ type Client struct { shutdown chan bool // downstream listener channel to deliver API objects - listener chan interface{} + listenerChan chan interface{} + + // callback function handlers to deliver API objects + callbacks map[reflect.Type][]ClientCallback } // Credentials assigns authentication credentials to a connection request. @@ -133,6 +140,18 @@ func (c *Client) CancelOnDisconnect(cxl bool) *Client { return c } +func (c *Client) deliverMsg(msg interface{}) { + if c.callbacks != nil { + msgType := reflect.ValueOf(msg).Elem().Type() + if val, ok := c.callbacks[msgType]; ok { + for _, callback := range val { + go callback(msg) + } + } + } + c.listenerChan <- msg +} + func (c *Client) sign(msg string) string { sig := hmac.New(sha512.New384, []byte(c.apiSecret)) sig.Write([]byte(msg)) @@ -183,7 +202,7 @@ func NewWithParamsAsyncFactoryNonce(params *Parameters, async AsynchronousFactor nonce: nonce, isConnected: false, parameters: params, - listener: make(chan interface{}), + listenerChan: make(chan interface{}), terminal: false, } c.registerPublicFactories() @@ -212,6 +231,15 @@ func (c *Client) registerPublicFactories() { c.registerFactory(ChanCandles, newCandlesFactory(c.subscriptions)) } +// RegisterCallback attaches a provided callback handler for a specified object type +func (c *Client) RegisterCallback(objectForType interface{}, callback ClientCallback) { + if c.callbacks == nil { + c.callbacks = make(map[reflect.Type][]ClientCallback) + } + typeOfObject := reflect.TypeOf(objectForType) + c.callbacks[typeOfObject] = append(c.callbacks[typeOfObject], callback) +} + // IsConnected returns true if the underlying asynchronous transport is connected to an endpoint. func (c *Client) IsConnected() bool { return c.isConnected @@ -335,11 +363,11 @@ func (c *Client) listenUpstream() { // terminal, unrecoverable state. called after async is closed. func (c *Client) close(e error) { - if c.listener != nil { + if c.listenerChan != nil { if e != nil { - c.listener <- e + c.listenerChan <- e } - close(c.listener) + close(c.listenerChan) } // shutdowns goroutines close(c.shutdown) @@ -372,7 +400,7 @@ func (c *Client) closeAsyncAndWait(t time.Duration) { // Listen provides an atomic interface for receiving API messages. // When a websocket connection is terminated, the publisher channel will close. func (c *Client) Listen() <-chan interface{} { - return c.listener + return c.listenerChan } // Close provides an interface for a user initiated shutdown. diff --git a/v2/websocket/events.go b/v2/websocket/events.go index 21b6b6736..16ed9f022 100644 --- a/v2/websocket/events.go +++ b/v2/websocket/events.go @@ -115,7 +115,7 @@ func (c *Client) handleEvent(msg []byte) error { return err } c.handleOpen() - c.listener <- &i + c.deliverMsg(&i) case "auth": a := AuthEvent{} err = json.Unmarshal(msg, &a) @@ -128,7 +128,7 @@ func (c *Client) handleEvent(msg []byte) error { c.Authentication = RejectedAuthentication } c.handleAuthAck(&a) - c.listener <- &a + c.deliverMsg(&a) return nil case "subscribed": s := SubscribeEvent{} @@ -140,7 +140,7 @@ func (c *Client) handleEvent(msg []byte) error { if err != nil { return err } - c.listener <- &s + c.deliverMsg(&s) return nil case "unsubscribed": s := UnsubscribeEvent{} @@ -149,21 +149,21 @@ func (c *Client) handleEvent(msg []byte) error { return err } c.subscriptions.removeByChannelID(s.ChanID) - c.listener <- &s + c.deliverMsg(&s) case "error": er := ErrorEvent{} err = json.Unmarshal(msg, &er) if err != nil { return err } - c.listener <- &er + c.deliverMsg(&er) case "conf": ec := ConfEvent{} err = json.Unmarshal(msg, &ec) if err != nil { return err } - c.listener <- &ec + c.deliverMsg(&ec) default: return fmt.Errorf("unknown event: %s", msg) // TODO: or just log? } From 3ab54c7f48a51787284d7a7af787de25629af642 Mon Sep 17 00:00:00 2001 From: Michael Wilner Date: Thu, 13 Sep 2018 12:45:01 -0500 Subject: [PATCH 2/7] Implement integration tests around the new callback functionality --- .../v2/live_websocket_public_test.go | 70 +++++++++++ tests/integration/v2/mock_ws_public_test.go | 111 +++++++++++++++++- 2 files changed, 178 insertions(+), 3 deletions(-) diff --git a/tests/integration/v2/live_websocket_public_test.go b/tests/integration/v2/live_websocket_public_test.go index 0dc013339..1c5616203 100644 --- a/tests/integration/v2/live_websocket_public_test.go +++ b/tests/integration/v2/live_websocket_public_test.go @@ -248,6 +248,76 @@ func TestPublicBooks(t *testing.T) { } } +func TestPublicCallbacks(t *testing.T) { + c := websocket.New() + wg := sync.WaitGroup{} + wg.Add(3) // 1. Info with version, 2. Subscription event, 3. data message + + err := c.Connect() + if err != nil { + t.Fatal("Error connecting to web socket : ", err) + } + defer c.Close() + + unSubs := make(chan interface{}, 10) + bookSnaps := make(chan interface{}, 10) + bookUps1 := make(chan interface{}, 10) + bookUps2 := make(chan interface{}, 10) + + //Register callbacks for above interfaces + c.RegisterCallback(websocket.UnsubscribeEvent{}, func(m interface{}) { unSubs <- m }) + c.RegisterCallback(bitfinex.BookUpdate{}, func(m interface{}) { bookUps1 <- m }) + c.RegisterCallback(bitfinex.BookUpdate{}, func(m interface{}) { bookUps2 <- m }) + c.RegisterCallback(bitfinex.BookUpdateSnapshot{}, func(m interface{}) { bookSnaps <- m }) + + errch := make(chan error) + go func() { + for { + select { + case msg := <-c.Listen(): + if msg == nil { + return + } + log.Printf("recv msg: %#v", msg) + switch msg.(type) { + case error: + errch <- msg.(error) + default: + t.Logf("test recv: %#v", msg) + } + } + } + }() + + ctx, cxl := context.WithTimeout(context.Background(), time.Second*5) + defer cxl() + id, err := c.SubscribeBook(ctx, bitfinex.TradingPrefix+bitfinex.BTCUSD, bitfinex.Precision0, bitfinex.FrequencyRealtime, 1) + if err != nil { + t.Fatal(err) + } + + if err := wait2(bookSnaps, 1, errch, 5*time.Second); err != nil { + t.Fatalf("failed to receive book snapshot message from websocket: %s", err) + } + + if err := wait2(bookUps1, 1, errch, 5*time.Second); err != nil { + t.Fatalf("failed to receive book update message to 1/2 channels from websocket: %s", err) + } + + if err := wait2(bookUps2, 1, errch, 5*time.Second); err != nil { + t.Fatalf("failed to receive book update message to 2/2 channels from websocket: %s", err) + } + + err = c.Unsubscribe(ctx, id) + if err != nil { + t.Fatal(err) + } + + if err := wait2(unSubs, 1, errch, 5*time.Second); err != nil { + t.Errorf("failed to receive unsubscribe message from websocket: %s", err) + } +} + func TestPublicCandles(t *testing.T) { c := websocket.New() wg := sync.WaitGroup{} diff --git a/tests/integration/v2/mock_ws_public_test.go b/tests/integration/v2/mock_ws_public_test.go index 353d9814e..e0350bd1c 100644 --- a/tests/integration/v2/mock_ws_public_test.go +++ b/tests/integration/v2/mock_ws_public_test.go @@ -2,10 +2,10 @@ package tests import ( "context" - "testing" - - bitfinex "github.com/bitfinexcom/bitfinex-api-go/v2" + "github.com/bitfinexcom/bitfinex-api-go/v2" "github.com/bitfinexcom/bitfinex-api-go/v2/websocket" + "testing" + "time" ) // method of testing with mocked endpoints @@ -82,3 +82,108 @@ func TestTicker(t *testing.T) { } assert(t, &websocket.UnsubscribeEvent{ChanID: 5, Status: "OK"}, unsub) } + +func TestMockTickerCallback(t *testing.T) { + // create transport & nonce mocks + async := newTestAsync() + nonce := &IncrementingNonceGenerator{} + + // create client + ws := websocket.NewWithAsyncFactoryNonce(newTestAsyncFactory(async), nonce) + + // setup listener + listener := newListener() + listener.run(ws.Listen()) + + // set ws options + ws.Connect() + defer ws.Close() + + // register callbacks for messages + callbackInfo := make(chan interface{}, 10) + callbackTick1 := make(chan interface{}, 10) + callbackTick2 := make(chan interface{}, 10) + ws.RegisterCallback(websocket.InfoEvent{}, func (info interface{}) { callbackInfo <- info }) + ws.RegisterCallback(bitfinex.Ticker{}, func (tick interface{}) { callbackTick1 <- tick }) + ws.RegisterCallback(bitfinex.Ticker{}, func (tick interface{}) { callbackTick2 <- tick }) + + // info welcome msg + expectedInfoEvent := websocket.InfoEvent{Version: 2} + async.Publish(`{"event":"info","version":2}`) + ev, err := listener.nextInfoEvent() + if err != nil { + t.Fatal(err) + } + assert(t, &expectedInfoEvent, ev) + select { + case val := <-callbackInfo: + assert(t, &expectedInfoEvent, val) + case <-time.After(time.Second): + t.Fatal("Did not receive an info callback") + } + + + // subscribe + id, err := ws.SubscribeTicker(context.Background(), "tBTCUSD") + if err != nil { + t.Fatal(err) + } + + // subscribe ack + async.Publish(`{"event":"subscribed","channel":"ticker","chanId":5,"symbol":"tBTCUSD","subId":"nonce1","pair":"BTCUSD"}`) + sub, err := listener.nextSubscriptionEvent() + if err != nil { + t.Fatal(err) + } + assert(t, &websocket.SubscribeEvent{ + SubID: "nonce1", + Channel: "ticker", + ChanID: 5, + Symbol: "tBTCUSD", + Pair: "BTCUSD", + }, sub) + + // publish the tick data + expectedTick := bitfinex.Ticker{ + Symbol: "tBTCUSD", + Bid: 14957, + Ask: 14958, + BidSize: 68.17328796, + AskSize: 55.29588132, + DailyChange: -659, + DailyChangePerc: -0.0422, + LastPrice: 14971, + Volume: 53723.08813995, + High: 16494, + Low: 14454, + } + async.Publish(`[5,[14957,68.17328796,14958,55.29588132,-659,-0.0422,14971,53723.08813995,16494,14454]]`) + tick, err := listener.nextTick() + if err != nil { + t.Fatal(err) + } + // ensure delivery of the tick matches between serial methods and the multiple callbacks + assert(t, &expectedTick, tick) + select { + case val := <-callbackTick1: + assert(t, &expectedTick, val) + case <-time.After(time.Second): + t.Fatal("Did not receive an tick callback 1/2") + } + select { + case val := <-callbackTick2: + assert(t, &expectedTick, val) + case <-time.After(time.Second): + t.Fatal("Did not receive an tick callback 2/2") + } + + // unsubscribe + ws.Unsubscribe(context.Background(), id) + async.Publish(`{"event":"unsubscribed","chanId":5,"status":"OK"}`) + unsub, err := listener.nextUnsubscriptionEvent() + if err != nil { + t.Fatal(err) + } + assert(t, &websocket.UnsubscribeEvent{ChanID: 5, Status: "OK"}, unsub) +} + From 1bc6c3166fa4bbcc7ec90b2000f3d30d78a72c0d Mon Sep 17 00:00:00 2001 From: Michael Wilner Date: Fri, 14 Sep 2018 09:54:24 -0500 Subject: [PATCH 3/7] Authenticated order convenience methods for callbacks --- v2/websocket/util.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 v2/websocket/util.go diff --git a/v2/websocket/util.go b/v2/websocket/util.go new file mode 100644 index 000000000..ddc2e6403 --- /dev/null +++ b/v2/websocket/util.go @@ -0,0 +1,19 @@ +package websocket + +import "github.com/bitfinexcom/bitfinex-api-go/v2" + +func (c *Client) OnOrderSnapshot(callback ClientCallback) { + c.RegisterCallback(bitfinex.OrderSnapshot{}, callback) +} + +func (c *Client) OnOrderNew(callback ClientCallback) { + c.RegisterCallback(bitfinex.OrderNew{}, callback) +} + +func (c *Client) OnOrderUpdate(callback ClientCallback) { + c.RegisterCallback(bitfinex.OrderUpdate{}, callback) +} + +func (c *Client) OnOrderCancel(callback ClientCallback) { + c.RegisterCallback(bitfinex.OrderCancel{}, callback) +} From 37a2803e4bb7e45fb9054018ca20116024046085 Mon Sep 17 00:00:00 2001 From: Michael Wilner Date: Fri, 14 Sep 2018 10:00:18 -0500 Subject: [PATCH 4/7] Authenticated position convenience methods for callbacks --- v2/websocket/util.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/v2/websocket/util.go b/v2/websocket/util.go index ddc2e6403..8367c1769 100644 --- a/v2/websocket/util.go +++ b/v2/websocket/util.go @@ -17,3 +17,19 @@ func (c *Client) OnOrderUpdate(callback ClientCallback) { func (c *Client) OnOrderCancel(callback ClientCallback) { c.RegisterCallback(bitfinex.OrderCancel{}, callback) } + +func (c *Client) OnPositionSnapshot(callback ClientCallback) { + c.RegisterCallback(bitfinex.PositionSnapshot{}, callback) +} + +func (c *Client) OnPositionNew(callback ClientCallback) { + c.RegisterCallback(bitfinex.PositionNew{}, callback) +} + +func (c *Client) OnPositionUpdate(callback ClientCallback) { + c.RegisterCallback(bitfinex.PositionUpdate{}, callback) +} + +func (c *Client) OnPositionCancel(callback ClientCallback) { + c.RegisterCallback(bitfinex.PositionCancel{}, callback) +} From 396ba15b0b4ce0eba537a03f1bb79cb9b781828f Mon Sep 17 00:00:00 2001 From: Michael Wilner Date: Fri, 14 Sep 2018 10:05:22 -0500 Subject: [PATCH 5/7] Authenticated trade convenience methods for callbacks --- v2/websocket/util.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/v2/websocket/util.go b/v2/websocket/util.go index 8367c1769..7e4e70a47 100644 --- a/v2/websocket/util.go +++ b/v2/websocket/util.go @@ -33,3 +33,11 @@ func (c *Client) OnPositionUpdate(callback ClientCallback) { func (c *Client) OnPositionCancel(callback ClientCallback) { c.RegisterCallback(bitfinex.PositionCancel{}, callback) } + +func (c *Client) OnTradeExecution(callback ClientCallback) { + c.RegisterCallback(bitfinex.TradeExecution{}, callback) +} + +func (c *Client) OnTradeExecutionUpdate(callback ClientCallback) { + c.RegisterCallback(bitfinex.TradeExecutionUpdate{}, callback) +} From 9cae5cd10af0a0afe1c190deb918265da328e57a Mon Sep 17 00:00:00 2001 From: Michael Wilner Date: Fri, 14 Sep 2018 10:57:13 -0500 Subject: [PATCH 6/7] Funding convenience methods for callbacks --- v2/websocket/util.go | 60 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/v2/websocket/util.go b/v2/websocket/util.go index 7e4e70a47..c31e0a120 100644 --- a/v2/websocket/util.go +++ b/v2/websocket/util.go @@ -2,6 +2,8 @@ package websocket import "github.com/bitfinexcom/bitfinex-api-go/v2" +//Order Callback Convenience Methods + func (c *Client) OnOrderSnapshot(callback ClientCallback) { c.RegisterCallback(bitfinex.OrderSnapshot{}, callback) } @@ -18,6 +20,8 @@ func (c *Client) OnOrderCancel(callback ClientCallback) { c.RegisterCallback(bitfinex.OrderCancel{}, callback) } +//Position Callback Convenience Methods + func (c *Client) OnPositionSnapshot(callback ClientCallback) { c.RegisterCallback(bitfinex.PositionSnapshot{}, callback) } @@ -34,6 +38,8 @@ func (c *Client) OnPositionCancel(callback ClientCallback) { c.RegisterCallback(bitfinex.PositionCancel{}, callback) } +//TradeExecution Callback Convenience Methods + func (c *Client) OnTradeExecution(callback ClientCallback) { c.RegisterCallback(bitfinex.TradeExecution{}, callback) } @@ -41,3 +47,57 @@ func (c *Client) OnTradeExecution(callback ClientCallback) { func (c *Client) OnTradeExecutionUpdate(callback ClientCallback) { c.RegisterCallback(bitfinex.TradeExecutionUpdate{}, callback) } + +//FundingOffer Callback Convenience Methods + +func (c *Client) OnFundingOfferSnapshot(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingOfferSnapshot{}, callback) +} + +func (c *Client) OnFundingOfferNew(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingOfferNew{}, callback) +} + +func (c *Client) OnFundingOfferUpdate(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingOfferUpdate{}, callback) +} + +func (c *Client) OnFundingOfferCancel(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingOfferCancel{}, callback) +} + +//FundingCredit Callback Convenience Methods + +func (c *Client) OnFundingCreditSnapshot(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingCreditSnapshot{}, callback) +} + +func (c *Client) OnFundingCreditNew(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingCreditNew{}, callback) +} + +func (c *Client) OnFundingCreditUpdate(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingCreditUpdate{}, callback) +} + +func (c *Client) OnFundingCreditCancel(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingCreditCancel{}, callback) +} + +//FundingLoan Callback Convenience Methods + +func (c *Client) OnFundingLoanSnapshot(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingLoanSnapshot{}, callback) +} + +func (c *Client) OnFundingLoanNew(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingLoanNew{}, callback) +} + +func (c *Client) OnFundingLoanUpdate(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingLoanUpdate{}, callback) +} + +func (c *Client) OnFundingLoanCancel(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingLoanCancel{}, callback) +} From 97ba46aceb941089c40600c6fd97bd512b606188 Mon Sep 17 00:00:00 2001 From: Michael Wilner Date: Fri, 14 Sep 2018 11:35:56 -0500 Subject: [PATCH 7/7] WebSocket convenience methods covered --- v2/websocket/util.go | 100 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/v2/websocket/util.go b/v2/websocket/util.go index c31e0a120..90e687a5d 100644 --- a/v2/websocket/util.go +++ b/v2/websocket/util.go @@ -101,3 +101,103 @@ func (c *Client) OnFundingLoanUpdate(callback ClientCallback) { func (c *Client) OnFundingLoanCancel(callback ClientCallback) { c.RegisterCallback(bitfinex.FundingLoanCancel{}, callback) } + +//Misc Funding Callback Convenience Methods + +func (c *Client) OnFundingInfo(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingInfo{}, callback) +} + +func (c *Client) OnFundingTrade(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingTrade{}, callback) +} + +func (c *Client) OnFundingTradeSnapshot(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingTradeSnapshot{}, callback) +} + +func (c *Client) OnFundingTradeExecution(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingTradeExecution{}, callback) +} + +func (c *Client) OnFundingTradeUpdate(callback ClientCallback) { + c.RegisterCallback(bitfinex.FundingTradeUpdate{}, callback) +} + +//Balance Callback Convenience Methods + +func (c *Client) OnBalanceInfo(callback ClientCallback) { + c.RegisterCallback(bitfinex.BalanceInfo{}, callback) +} + +func (c *Client) OnBalanceUpdate(callback ClientCallback) { + c.RegisterCallback(bitfinex.BalanceUpdate{}, callback) +} + +//Margin Callback Convenience Methods + +func (c *Client) OnMarginInfoBase(callback ClientCallback) { + c.RegisterCallback(bitfinex.MarginInfoBase{}, callback) +} + +func (c *Client) OnMarginInfoUpdate(callback ClientCallback) { + c.RegisterCallback(bitfinex.MarginInfoUpdate{}, callback) +} + +func (c *Client) OnNotification(callback ClientCallback) { + c.RegisterCallback(bitfinex.Notification{}, callback) +} + +//Wallet Callback Convenience Methods + +func (c *Client) OnWalletSnapshot(callback ClientCallback) { + c.RegisterCallback(bitfinex.WalletSnapshot{}, callback) +} + +func (c *Client) OnWalletUpdate(callback ClientCallback) { + c.RegisterCallback(bitfinex.WalletUpdate{}, callback) +} + +//Public Book Callback Convenience Methods + +func (c *Client) OnBookUpdateSnapshot(callback ClientCallback) { + c.RegisterCallback(bitfinex.BookUpdateSnapshot{}, callback) +} + +func (c *Client) OnBookUpdate(callback ClientCallback) { + c.RegisterCallback(bitfinex.BookUpdate{}, callback) +} + +//Public Candle Callback Convenience Methods + +func (c *Client) OnCandleSnapshot(callback ClientCallback) { + c.RegisterCallback(bitfinex.CandleSnapshot{}, callback) +} + +func (c *Client) OnCandle(callback ClientCallback) { + c.RegisterCallback(bitfinex.Candle{}, callback) +} + +//Public Trade Callback Convenience Methods + +func (c *Client) OnTradeSnapshot(callback ClientCallback) { + c.RegisterCallback(bitfinex.TradeSnapshot{}, callback) +} + +func (c *Client) OnTrade(callback ClientCallback) { + c.RegisterCallback(bitfinex.Trade{}, callback) +} + +//Public Ticker Callback Convenience Methods + +func (c *Client) OnTicker(callback ClientCallback) { + c.RegisterCallback(bitfinex.Ticker{}, callback) +} + +func (c *Client) OnTickerSnapshot(callback ClientCallback) { + c.RegisterCallback(bitfinex.TickerSnapshot{}, callback) +} + +func (c *Client) OnTickerUpdate(callback ClientCallback) { + c.RegisterCallback(bitfinex.TickerUpdate{}, callback) +}