github.com/bitfinexcom/bitfinex-api-go@v0.0.0-20210608095005-9e0b26f200fb/tests/integration/v2/mock_ws_private_test.go (about)

     1  package tests
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/balanceinfo"
     8  	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/wallet"
     9  	"github.com/bitfinexcom/bitfinex-api-go/v2/websocket"
    10  )
    11  
    12  func TestAuthentication(t *testing.T) {
    13  	// create transport & nonce mocks
    14  	async := newTestAsync()
    15  	nonce := &IncrementingNonceGenerator{}
    16  
    17  	// create client
    18  	ws := websocket.NewWithAsyncFactoryNonce(newTestAsyncFactory(async), nonce).Credentials("apiKeyABC", "apiSecretXYZ")
    19  
    20  	// setup listener
    21  	listener := newListener()
    22  	listener.run(ws.Listen())
    23  
    24  	// set ws options
    25  	err_ws := ws.Connect()
    26  	if err_ws != nil {
    27  		t.Fatal(err_ws)
    28  	}
    29  	defer ws.Close()
    30  
    31  	// begin test
    32  	async.Publish(`{"event":"info","version":2}`)
    33  	ev, err := listener.nextInfoEvent()
    34  	if err != nil {
    35  		t.Fatal(err)
    36  	}
    37  	assert(t, fmt.Sprint(websocket.InfoEvent{Version: 2}), fmt.Sprint(*ev))
    38  
    39  	// assert outgoing auth request
    40  	if err := async.waitForMessage(0); err != nil {
    41  		t.Fatal(err.Error())
    42  	}
    43  	expected := websocket.SubscriptionRequest{SubID: "nonce1", Event: "auth", APIKey: "apiKeyABC"}
    44  	actual := *async.Sent[0].(*websocket.SubscriptionRequest)
    45  	assert(t, expected.SubID, actual.SubID)
    46  	assert(t, expected.Event, actual.Event)
    47  	assert(t, expected.APIKey, actual.APIKey)
    48  
    49  	// auth ack
    50  	async.Publish(`{"event":"auth","status":"OK","chanId":0,"userId":1,"subId":"nonce1","auth_id":"valid-auth-guid","caps":{"orders":{"read":1,"write":0},"account":{"read":1,"write":0},"funding":{"read":1,"write":0},"history":{"read":1,"write":0},"wallets":{"read":1,"write":0},"withdraw":{"read":0,"write":0},"positions":{"read":1,"write":0}}}`)
    51  
    52  	// assert incoming auth ack
    53  	av, err := listener.nextAuthEvent()
    54  	if err != nil {
    55  		t.Fatal(err)
    56  	}
    57  	expected2 := websocket.AuthEvent{Status: "OK", SubID: "nonce1", ChanID: 0}
    58  	actual2 := *av
    59  	assert(t, expected2.SubID, actual2.SubID)
    60  	assert(t, expected2.Status, actual2.Status)
    61  	assert(t, expected2.ChanID, actual2.ChanID)
    62  }
    63  
    64  func TestWalletBalanceUpdates(t *testing.T) {
    65  	// create transport & nonce mocks
    66  	async := newTestAsync()
    67  	nonce := &IncrementingNonceGenerator{}
    68  
    69  	// create client
    70  	ws := websocket.NewWithAsyncFactoryNonce(newTestAsyncFactory(async), nonce).Credentials("apiKeyABC", "apiSecretXYZ")
    71  
    72  	// setup listener
    73  	listener := newListener()
    74  	listener.run(ws.Listen())
    75  
    76  	// set ws options
    77  	//ws.SetReadTimeout(time.Second * 2)
    78  	err_ws := ws.Connect()
    79  	if err_ws != nil {
    80  		t.Fatal(err_ws)
    81  	}
    82  	defer ws.Close()
    83  
    84  	// begin test--authentication assertions in TestAuthentication
    85  	async.Publish(`{"event":"info","version":2}`)
    86  	// eat event
    87  	_, err := listener.nextInfoEvent()
    88  	if err != nil {
    89  		t.Fatal(err)
    90  	}
    91  
    92  	// auth ack
    93  	async.Publish(`{"event":"auth","status":"OK","chanId":0,"userId":1,"subId":"nonce1","auth_id":"valid-auth-guid","caps":{"orders":{"read":1,"write":0},"account":{"read":1,"write":0},"funding":{"read":1,"write":0},"history":{"read":1,"write":0},"wallets":{"read":1,"write":0},"withdraw":{"read":0,"write":0},"positions":{"read":1,"write":0}}}`)
    94  
    95  	// eat event
    96  	_, err = listener.nextAuthEvent()
    97  	if err != nil {
    98  		t.Fatal(err)
    99  	}
   100  
   101  	// publish account info post auth ack
   102  	async.Publish(`[0,"wu",["exchange","BTC",30,0,30,null,null,null]]`)
   103  	async.Publish(`[0,"wu",["exchange","USD",80000,0,80000,null,null,null]]`)
   104  	async.Publish(`[0,"wu",["exchange","ETH",100,0,100,null,null,null]]`)
   105  	async.Publish(`[0,"wu",["margin","BTC",10,0,10,null,null,null]]`)
   106  	async.Publish(`[0,"wu",["funding","BTC",10,0,10,null,null,null]]`)
   107  	async.Publish(`[0,"wu",["funding","USD",10000,0,10000,null,null,null]]`)
   108  	async.Publish(`[0,"wu",["margin","USD",10000,0,10000,null,null,null]]`)
   109  	async.Publish(`[0,"bu",[147260,147260]]`)
   110  
   111  	// assert incoming wallet & balance updates
   112  	wu, err := listener.nextWalletUpdate()
   113  	if err != nil {
   114  		t.Fatal(err)
   115  	}
   116  	assert(t, fmt.Sprint(wallet.Update{Type: "exchange", Currency: "BTC", Balance: 30, BalanceAvailable: 30}), fmt.Sprint(*wu))
   117  	wu, _ = listener.nextWalletUpdate()
   118  	assert(t, fmt.Sprint(wallet.Update{Type: "exchange", Currency: "USD", Balance: 80000, BalanceAvailable: 80000}), fmt.Sprint(*wu))
   119  	wu, _ = listener.nextWalletUpdate()
   120  	assert(t, fmt.Sprint(wallet.Update{Type: "exchange", Currency: "ETH", Balance: 100, BalanceAvailable: 100}), fmt.Sprint(*wu))
   121  	wu, _ = listener.nextWalletUpdate()
   122  	assert(t, fmt.Sprint(wallet.Update{Type: "margin", Currency: "BTC", Balance: 10, BalanceAvailable: 10}), fmt.Sprint(*wu))
   123  	wu, _ = listener.nextWalletUpdate()
   124  	assert(t, fmt.Sprint(wallet.Update{Type: "funding", Currency: "BTC", Balance: 10, BalanceAvailable: 10}), fmt.Sprint(*wu))
   125  	wu, _ = listener.nextWalletUpdate()
   126  	assert(t, fmt.Sprint(wallet.Update{Type: "funding", Currency: "USD", Balance: 10000, BalanceAvailable: 10000}), fmt.Sprint(*wu))
   127  	wu, _ = listener.nextWalletUpdate()
   128  	assert(t, fmt.Sprint(wallet.Update{Type: "margin", Currency: "USD", Balance: 10000, BalanceAvailable: 10000}), fmt.Sprint(*wu))
   129  	bu, err := listener.nextBalanceUpdate()
   130  	if err != nil {
   131  		t.Fatal(err)
   132  	}
   133  	// total aum, net aum
   134  	assert(t, fmt.Sprint(balanceinfo.Update{TotalAUM: 147260, NetAUM: 147260}), fmt.Sprint(*bu))
   135  }
   136  
   137  // func TestNewOrder(t *testing.T) {
   138  // 	// create transport & nonce mocks
   139  // 	async := newTestAsync()
   140  // 	nonce := &IncrementingNonceGenerator{}
   141  
   142  // 	// create client
   143  // 	ws := websocket.NewWithAsyncFactoryNonce(newTestAsyncFactory(async), nonce).Credentials("apiKeyABC", "apiSecretXYZ")
   144  
   145  // 	// setup listener
   146  // 	listener := newListener()
   147  // 	listener.run(ws.Listen())
   148  
   149  // 	// set ws options
   150  // 	//ws.SetReadTimeout(time.Second * 2)
   151  // 	err_ws := ws.Connect()
   152  // 	if err_ws != nil {
   153  // 		t.Fatal(err_ws)
   154  // 	}
   155  // 	defer ws.Close()
   156  
   157  // 	// begin test
   158  // 	async.Publish(`{"event":"info","version":2}`)
   159  // 	_, err := listener.nextInfoEvent()
   160  // 	if err != nil {
   161  // 		t.Fatal(err)
   162  // 	}
   163  
   164  // 	// initial logon info--Authentication & WalletUpdate assertions in prior tests
   165  // 	async.Publish(`{"event":"auth","status":"OK","chanId":0,"userId":1,"subId":"nonce1","auth_id":"valid-auth-guid","caps":{"orders":{"read":1,"write":0},"account":{"read":1,"write":0},"funding":{"read":1,"write":0},"history":{"read":1,"write":0},"wallets":{"read":1,"write":0},"withdraw":{"read":0,"write":0},"positions":{"read":1,"write":0}}}`)
   166  // 	async.Publish(`[0,"wu",["exchange","BTC",30,0,30,null,null,null]]`)
   167  // 	async.Publish(`[0,"wu",["exchange","USD",80000,0,80000,null,null,null]]`)
   168  // 	async.Publish(`[0,"wu",["exchange","ETH",100,0,100,null,null,null]]`)
   169  // 	async.Publish(`[0,"wu",["margin","BTC",10,0,10,null,null,null]]`)
   170  // 	async.Publish(`[0,"wu",["funding","BTC",10,0,10,null,null,null]]`)
   171  // 	async.Publish(`[0,"wu",["funding","USD",10000,0,10000,null,null,null]]`)
   172  // 	async.Publish(`[0,"wu",["margin","USD",10000,0,10000,null,null,null]]`)
   173  // 	async.Publish(`[0,"bu",[147260,147260]]`)
   174  
   175  // 	// submit order
   176  // 	err = ws.SubmitOrder(context.Background(), &order.NewRequest{
   177  // 		Symbol: "tBTCUSD",
   178  // 		CID:    123,
   179  // 		Amount: -0.456,
   180  // 	})
   181  // 	if err != nil {
   182  // 		t.Fatal(err)
   183  // 	}
   184  
   185  // 	// assert outgoing order request
   186  // 	if len(async.Sent) <= 1 {
   187  // 		t.Fatalf("expected >1 sent messages, got %d", len(async.Sent))
   188  // 	}
   189  
   190  // 	expected := order.NewRequest{Symbol: "tBTCUSD", CID: 123, Amount: -0.456}
   191  // 	actual := *async.Sent[1].(*order.NewRequest)
   192  // 	assert(t, expected.Symbol, actual.Symbol)
   193  // 	assert(t, expected.CID, actual.CID)
   194  // 	assert(t, expected.Amount, actual.Amount)
   195  
   196  // 	// order ack
   197  // 	async.Publish(`[0,"n",[null,"on-req",null,null,[1201469553,0,788,"tBTCUSD",1611922089073,1611922089073,0.001,0.001,"EXCHANGE LIMIT",null,null,null,0,"ACTIVE",null,null,33,0,0,0,null,null,null,0,0,null,null,null,"API>BFX",null,null,null],null,"SUCCESS","Submitting market buy order for 1.0 BTC."]]`)
   198  
   199  // 	// assert order ack notification
   200  // 	not, err := listener.nextNotification()
   201  // 	if err != nil {
   202  // 		t.Fatal(err)
   203  // 	}
   204  // 	expected2 := notification.Notification{Type: "on-req", NotifyInfo: order.New{ID: 1201469553, GID: 0, CID: 788, Symbol: "tBTCUSD", MTSCreated: 1611922089073, MTSUpdated: 1611922089073, Amount: 0.001, AmountOrig: 0.001, Type: "EXCHANGE LIMIT", TypePrev: "", MTSTif: 0, Flags: 0, Status: "ACTIVE", Price: 33, PriceAvg: 0, PriceTrailing: 0, PriceAuxLimit: 0, Notify: false, Hidden: false, PlacedID: 0, Routing: "API>BFX", Meta: nil}, Status: "SUCCESS", Text: "Submitting market buy order for 1.0 BTC."}
   205  // 	not.NotifyInfo = *not.NotifyInfo.(*order.New)
   206  // 	assert(t, fmt.Sprint(expected2), fmt.Sprint(*not))
   207  // }
   208  
   209  // func TestFills(t *testing.T) {
   210  // 	// create transport & nonce mocks
   211  // 	async := newTestAsync()
   212  // 	nonce := &IncrementingNonceGenerator{}
   213  
   214  // 	// create client
   215  // 	ws := websocket.NewWithAsyncFactoryNonce(newTestAsyncFactory(async), nonce).Credentials("apiKeyABC", "apiSecretXYZ")
   216  
   217  // 	// setup listener
   218  // 	listener := newListener()
   219  // 	listener.run(ws.Listen())
   220  
   221  // 	// set ws options
   222  // 	//ws.SetReadTimeout(time.Second * 2)
   223  // 	err_ws := ws.Connect()
   224  // 	if err_ws != nil {
   225  // 		t.Fatal(err_ws)
   226  // 	}
   227  // 	defer ws.Close()
   228  
   229  // 	// begin test
   230  // 	async.Publish(`{"event":"info","version":2}`)
   231  // 	_, err := listener.nextInfoEvent()
   232  // 	if err != nil {
   233  // 		t.Fatal(err)
   234  // 	}
   235  
   236  // 	// initial logon info
   237  // 	async.Publish(`{"event":"auth","status":"OK","chanId":0,"userId":1,"subId":"nonce1","auth_id":"valid-auth-guid","caps":{"orders":{"read":1,"write":0},"account":{"read":1,"write":0},"funding":{"read":1,"write":0},"history":{"read":1,"write":0},"wallets":{"read":1,"write":0},"withdraw":{"read":0,"write":0},"positions":{"read":1,"write":0}}}`)
   238  // 	// async.Publish(`[0,"ps",[["tBTCUSD","ACTIVE",7,916.52002351,0,0,null,null,null,null]]]`)
   239  // 	async.Publish(`[0,"ps",[["tETHUSD", "ACTIVE", -0.2, 167.01, 0, 0, nil, nil, nil, nil, nil, 142661142, 1579552390000, 1579552390000, nil, nil, nil, nil, nil, nil]]]`)
   240  // 	async.Publish(`[0,"ws",[["exchange","BTC",30,0,null,null,null,null],["exchange","USD",80000,0,null,null,null,null],["exchange","ETH",100,0,null,null,null,null],["margin","BTC",10,0,null,null,null,null],["margin","USD",9987.16871968,0,null,null,null,null],["funding","BTC",10,0,null,null,null,null],["funding","USD",10000,0,null,null,null,null]]]`)
   241  // 	// consume & assert snapshots
   242  // 	ps, err := listener.nextPositionSnapshot()
   243  // 	if err != nil {
   244  // 		t.Fatal(err)
   245  // 	}
   246  // 	eps := make([]*position.Position, 1)
   247  // 	eps[0] = &position.Position{
   248  // 		Id:        142661142,
   249  // 		Symbol:    "tETHUSD",
   250  // 		Status:    "ACTIVE",
   251  // 		Amount:    -0.2,
   252  // 		BasePrice: 167.01,
   253  // 		MtsCreate: 1579552390000,
   254  // 		MtsUpdate: 1579552390000,
   255  // 		Type:      "ps",
   256  // 	}
   257  // 	snap := &position.Snapshot{
   258  // 		Snapshot: eps,
   259  // 	}
   260  // 	assertSlice(t, snap, ps)
   261  // 	w, err := listener.nextWalletSnapshot()
   262  // 	if err != nil {
   263  // 		t.Fatal(err)
   264  // 	}
   265  // 	ews := make([]*wallet.Wallet, 7)
   266  // 	ews[0] = &wallet.Wallet{Type: "exchange", Currency: "BTC", Balance: 30}
   267  // 	ews[1] = &wallet.Wallet{Type: "exchange", Currency: "USD", Balance: 80000}
   268  // 	ews[2] = &wallet.Wallet{Type: "exchange", Currency: "ETH", Balance: 100}
   269  // 	ews[3] = &wallet.Wallet{Type: "margin", Currency: "BTC", Balance: 10}
   270  // 	ews[4] = &wallet.Wallet{Type: "margin", Currency: "USD", Balance: 9987.16871968}
   271  // 	ews[5] = &wallet.Wallet{Type: "funding", Currency: "BTC", Balance: 10}
   272  // 	ews[6] = &wallet.Wallet{Type: "funding", Currency: "USD", Balance: 10000}
   273  // 	wsnap := &wallet.Snapshot{
   274  // 		Snapshot: ews,
   275  // 	}
   276  // 	assertSlice(t, wsnap, w)
   277  
   278  // 	// submit order
   279  // 	err = ws.SubmitOrder(context.Background(), &order.NewRequest{
   280  // 		Symbol: "tBTCUSD",
   281  // 		CID:    123,
   282  // 		Amount: -0.456,
   283  // 	})
   284  // 	if err != nil {
   285  // 		t.Fatal(err)
   286  // 	}
   287  
   288  // 	// order ack
   289  // 	async.Publish(`[0,"n",[null,"on-req",null,null,[1234567,null,123,"tBTCUSD",null,null,1,1,"MARKET",null,null,null,null,null,null,null,915.5,null,null,null,null,null,null,0,null,null],null,"SUCCESS","Submitting market buy order for 1.0 BTC."]]`)
   290  
   291  // 	// assert order ack notification--Authentication, WalletUpdate, order acknowledgement assertions in prior tests
   292  // 	_, err = listener.nextNotification()
   293  // 	if err != nil {
   294  // 		t.Fatal(err)
   295  // 	}
   296  
   297  // 	// <..crossing orders generates a fill..>
   298  // 	// partial fills--position updates
   299  // 	async.Publish(`[0,"pu",["tBTCUSD","ACTIVE",0.21679716,915.9,0,0,null,null,null,null]]`)
   300  // 	async.Publish(`[0,"pu",["tBTCUSD","ACTIVE",1,916.13496085,0,0,null,null,null,null]]`)
   301  // 	pu, err := listener.nextPositionUpdate()
   302  // 	if err != nil {
   303  // 		t.Fatal(err)
   304  // 	}
   305  // 	assert(t, fmt.Sprint(position.Update{Symbol: "tBTCUSD", Status: "ACTIVE", Amount: 0.21679716, BasePrice: 915.9}), fmt.Sprint(*pu))
   306  // 	pu, _ = listener.nextPositionUpdate()
   307  // 	assert(t, fmt.Sprint(position.Update{Symbol: "tBTCUSD", Status: "ACTIVE", Amount: 1, BasePrice: 916.13496085}), fmt.Sprint(*pu))
   308  
   309  // 	// full fill--order terminal state message
   310  // 	async.Publish(`[0,"oc",[1234567,0,123,"tBTCUSD",1514909325236,1514909325631,0,1,"MARKET",null,null,null,0,"EXECUTED @ 916.2(0.78): was PARTIALLY FILLED @ 915.9(0.22)",null,null,915.5,916.13496085,null,null,null,null,null,0,0,0]]`)
   311  // 	oc, err := listener.nextOrderCancel()
   312  // 	if err != nil {
   313  // 		t.Fatal(err)
   314  // 	}
   315  // 	assert(t, fmt.Sprint(order.Cancel{ID: 1234567, CID: 123, Symbol: "tBTCUSD", MTSCreated: 1514909325236, MTSUpdated: 1514909325631, Amount: 0, AmountOrig: 1, Type: "MARKET", Status: "EXECUTED @ 916.2(0.78): was PARTIALLY FILLED @ 915.9(0.22)", Price: 915.5, PriceAvg: 916.13496085}), fmt.Sprint(*oc))
   316  
   317  // 	// fills--trade executions
   318  // 	async.Publish(`[0,"te",[1,"tBTCUSD",1514909325593,1234567,0.21679716,915.9,null,null,0]]`)
   319  // 	async.Publish(`[0,"te",[2,"tBTCUSD",1514909325597,1234567,0.78320284,916.2,null,null,0]]`)
   320  // 	te, err := listener.nextTradeExecution()
   321  // 	if err != nil {
   322  // 		t.Fatal(err)
   323  // 	}
   324  // 	assert(t, fmt.Sprint(tradeexecution.TradeExecution{ID: 1, Pair: "tBTCUSD", OrderID: 1234567, MTS: 1514909325593, ExecAmount: 0.21679716, ExecPrice: 915.9}), fmt.Sprint(*te))
   325  // 	te, err = listener.nextTradeExecution()
   326  // 	if err != nil {
   327  // 		t.Fatal(err)
   328  // 	}
   329  // 	assert(t, fmt.Sprint(tradeexecution.TradeExecution{ID: 2, Pair: "tBTCUSD", OrderID: 1234567, MTS: 1514909325597, ExecAmount: 0.78320284, ExecPrice: 916.2}), fmt.Sprint(*te))
   330  
   331  // 	// fills--trade updates
   332  // 	async.Publish(`[0,"tu",[1,"tBTCUSD",1514909325593,1234567,0.21679716,915.9,"MARKET",915.5,-1,-0.39712904,"USD"]]`)
   333  // 	async.Publish(`[0,"tu",[2,"tBTCUSD",1514909325597,1234567,0.78320284,916.2,"MARKET",915.5,-1,-1.43514088,"USD"]]`)
   334  // 	tu, err := listener.nextTradeUpdate()
   335  // 	if err != nil {
   336  // 		t.Fatal(err)
   337  // 	}
   338  // 	assert(t, fmt.Sprint(tradeexecutionupdate.TradeExecutionUpdate{ID: 1, Pair: "tBTCUSD", MTS: 1514909325593, ExecAmount: 0.21679716, ExecPrice: 915.9, OrderType: "MARKET", OrderPrice: 915.5, OrderID: 1234567, Maker: -1, Fee: -0.39712904, FeeCurrency: "USD"}), fmt.Sprint(*tu))
   339  // 	tu, _ = listener.nextTradeUpdate()
   340  // 	assert(t, fmt.Sprint(tradeexecutionupdate.TradeExecutionUpdate{ID: 2, Pair: "tBTCUSD", MTS: 1514909325597, ExecAmount: 0.78320284, ExecPrice: 916.2, OrderType: "MARKET", OrderPrice: 915.5, OrderID: 1234567, Maker: -1, Fee: -1.43514088, FeeCurrency: "USD"}), fmt.Sprint(*tu))
   341  
   342  // 	// fills--wallet updates from fee deduction
   343  // 	async.Publish(`[0,"wu",["margin","USD",9999.60287096,0,null]]`)
   344  // 	async.Publish(`[0,"wu",["margin","USD",9998.16773008,0,null]]`)
   345  // 	wu, err := listener.nextWalletUpdate()
   346  // 	if err != nil {
   347  // 		t.Fatal(err)
   348  // 	}
   349  // 	assert(t, fmt.Sprint(wallet.Update{Type: "margin", Currency: "USD", Balance: 9999.60287096}), fmt.Sprint(*wu))
   350  // 	wu, _ = listener.nextWalletUpdate()
   351  // 	assert(t, fmt.Sprint(wallet.Update{Type: "margin", Currency: "USD", Balance: 9998.16773008}), fmt.Sprint(*wu))
   352  
   353  // 	// margin info update for executed trades
   354  // 	async.Publish(`[0,"miu",["base",[-2.76536085,0,19150.16773008,19147.40236923]]]`)
   355  // 	async.Publish(`[0,"miu",["sym","tBTCUSD",[60162.93960325,61088.2924336,60162.93960325,60162.93960325,null,null,null,null]]]`)
   356  // 	mb, err := listener.nextMarginInfoBase()
   357  // 	if err != nil {
   358  // 		t.Fatal(err)
   359  // 	}
   360  // 	assert(t, fmt.Sprint(margin.InfoBase{UserProfitLoss: -2.76536085, MarginBalance: 19150.16773008, MarginNet: 19147.40236923}), fmt.Sprint(*mb))
   361  // 	mu, err := listener.nextMarginInfoUpdate()
   362  // 	if err != nil {
   363  // 		t.Fatal(err)
   364  // 	}
   365  // 	assert(t, fmt.Sprint(margin.InfoUpdate{Symbol: "tBTCUSD", TradableBalance: 60162.93960325}), fmt.Sprint(*mu))
   366  
   367  // 	// position update for executed trades
   368  // 	async.Publish(`[0,"pu",["tBTCUSD","ACTIVE",1,916.13496085,0,0,-2.76536085,-0.30185082,0,43.7962]]`)
   369  // 	pu, _ = listener.nextPositionUpdate()
   370  // 	assert(t, fmt.Sprint(position.Update{Symbol: "tBTCUSD", Status: "ACTIVE", Amount: 1, BasePrice: 916.13496085, ProfitLoss: -2.76536085, ProfitLossPercentage: -0.30185082, Leverage: 43.7962}), fmt.Sprint(*pu))
   371  
   372  // 	// wallet margin update for executed trades
   373  // 	async.Publish(`[0,"wu",["margin","BTC",10,0,10]]`)
   374  // 	async.Publish(`[0,"wu",["margin","USD",9998.16773008,0,9998.16773008]]`)
   375  // 	wu, _ = listener.nextWalletUpdate()
   376  // 	assert(t, fmt.Sprint(wallet.Update{Type: "margin", Currency: "BTC", Balance: 10, BalanceAvailable: 10}), fmt.Sprint(*wu))
   377  // 	wu, _ = listener.nextWalletUpdate()
   378  // 	assert(t, fmt.Sprint(wallet.Update{Type: "margin", Currency: "USD", Balance: 9998.16773008, BalanceAvailable: 9998.16773008}), fmt.Sprint(*wu))
   379  
   380  // 	// funding update for executed trades
   381  // 	async.Publish(`[0,"fiu",["sym","ftBTCUSD",[0,0,0,0]]]`)
   382  // 	fi, err := listener.nextFundingInfo()
   383  // 	if err != nil {
   384  // 		t.Fatal(err)
   385  // 	}
   386  // 	assert(t, fmt.Sprint(fundinginfo.FundingInfo{Symbol: "ftBTCUSD"}), fmt.Sprint(*fi))
   387  // }
   388  
   389  // func TestCancel(t *testing.T) {
   390  // 	// create transport & nonce mocks
   391  // 	async := newTestAsync()
   392  // 	nonce := &IncrementingNonceGenerator{}
   393  
   394  // 	// create client
   395  // 	ws := websocket.NewWithAsyncFactoryNonce(newTestAsyncFactory(async), nonce).Credentials("apiKeyABC", "apiSecretXYZ")
   396  
   397  // 	// setup listener
   398  // 	listener := newListener()
   399  // 	listener.run(ws.Listen())
   400  
   401  // 	// set ws options
   402  // 	//ws.SetReadTimeout(time.Second * 2)
   403  // 	err_ws := ws.Connect()
   404  // 	if err_ws != nil {
   405  // 		t.Fatal(err_ws)
   406  // 	}
   407  // 	defer ws.Close()
   408  
   409  // 	// begin test
   410  // 	async.Publish(`{"event":"info","version":2}`)
   411  // 	_, err := listener.nextInfoEvent()
   412  // 	if err != nil {
   413  // 		t.Fatal(err)
   414  // 	}
   415  
   416  // 	// initial logon info--Authentication & WalletUpdate assertions in prior tests
   417  // 	async.Publish(`{"event":"auth","status":"OK","chanId":0,"userId":1,"subId":"nonce1","auth_id":"valid-auth-guid","caps":{"orders":{"read":1,"write":0},"account":{"read":1,"write":0},"funding":{"read":1,"write":0},"history":{"read":1,"write":0},"wallets":{"read":1,"write":0},"withdraw":{"read":0,"write":0},"positions":{"read":1,"write":0}}}`)
   418  // 	async.Publish(`[0,"ps",[["tBTCUSD","ACTIVE",7,916.52002351,0,0,null,null,null,null]]]`)
   419  // 	async.Publish(`[0,"ws",[["exchange","BTC",30,0,null],["exchange","USD",80000,0,null],["exchange","ETH",100,0,null],["margin","BTC",10,0,null],["margin","USD",9987.16871968,0,null],["funding","BTC",10,0,null],["funding","USD",10000,0,null]]]`)
   420  // 	// consume & assert snapshots
   421  // 	_, err_ps := listener.nextPositionSnapshot()
   422  // 	if err_ps != nil {
   423  // 		t.Fatal(err_ps)
   424  // 	}
   425  // 	_, err_was := listener.nextWalletSnapshot()
   426  // 	if err_was != nil {
   427  // 		t.Fatal(err_was)
   428  // 	}
   429  
   430  // 	// submit order
   431  // 	err = ws.SubmitOrder(context.Background(), &order.NewRequest{
   432  // 		Symbol: "tBTCUSD",
   433  // 		CID:    123,
   434  // 		Amount: -0.456,
   435  // 		Type:   "LIMIT",
   436  // 		Price:  900.0,
   437  // 	})
   438  // 	if err != nil {
   439  // 		t.Fatal(err)
   440  // 	}
   441  
   442  // 	// assert outgoing order request
   443  // 	if len(async.Sent) <= 1 {
   444  // 		t.Fatalf("expected >1 sent messages, got %d", len(async.Sent))
   445  // 	}
   446  // 	assert(t, fmt.Sprint(order.NewRequest{Symbol: "tBTCUSD", CID: 123, Amount: -0.456, Type: "LIMIT", Price: 900.0}), fmt.Sprint(*async.Sent[1].(*order.NewRequest)))
   447  
   448  // 	// order pending new
   449  // 	async.Publish(`[0,"n",[null,"on-req",null,null,[1234567,null,123,"tBTCUSD",null,null,1,1,"LIMIT",null,null,null,null,null,null,null,900,null,null,null,null,null,null,0,null,null,null,null,null,null,null,null],null,"SUCCESS","Submitting limit buy order for 1.0 BTC."]]`)
   450  // 	// order working--limit order
   451  // 	async.Publish(`[0,"on",[1234567,0,123,"tBTCUSD",1515179518260,1515179518315,1,1,"LIMIT",null,null,null,0,"ACTIVE",null,null,900,0,null,null,null,null,null,0,0,null,null,null,null,null,null,null,null]]`)
   452  
   453  // 	// eat order ack notification
   454  // 	_, err_n := listener.nextNotification()
   455  // 	if err_n != nil {
   456  // 		t.Fatal(err_n)
   457  // 	}
   458  
   459  // 	on, err := listener.nextOrderNew()
   460  // 	if err != nil {
   461  // 		t.Fatal(err)
   462  // 	}
   463  
   464  // 	// assert order new update
   465  // 	assert(t, fmt.Sprint(order.New{ID: 1234567, CID: 123, Symbol: "tBTCUSD", MTSCreated: 1515179518260, MTSUpdated: 1515179518315, Type: "LIMIT", Amount: 1, AmountOrig: 1, Status: "ACTIVE", Price: 900.0}), fmt.Sprint(*on))
   466  
   467  // 	// publish cancel request
   468  // 	req := &order.CancelRequest{ID: on.ID}
   469  // 	pre := async.SentCount()
   470  // 	err = ws.SubmitCancel(context.Background(), req)
   471  // 	if err != nil {
   472  // 		t.Fatal(err)
   473  // 	}
   474  // 	if err := async.waitForMessage(pre); err != nil {
   475  // 		t.Fatal(err.Error())
   476  // 	}
   477  // 	// assert sent message
   478  // 	assert(t, req, async.Sent[pre].(*order.CancelRequest))
   479  
   480  // 	// cancel ack notify
   481  // 	async.Publish(`[0,"n",[null,"oc-req",null,null,[1149686139,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,0,null,null,null,null,null,null,null,null,null,null,null,null],null,"SUCCESS","Submitted for cancellation; waiting for confirmation (ID: 1149686139)."]]`)
   482  
   483  // 	// cancel confirm
   484  // 	async.Publish(`[0,"oc",[1234567,0,123,"tBTCUSD",1515179518260,1515179520203,1,1,"LIMIT",null,null,null,0,"CANCELED",null,null,900,0,null,null,null,null,null,0,0,0,null,null,null,null,null,null,null]]`)
   485  
   486  // 	// assert cancel ack
   487  // 	oc, err := listener.nextOrderCancel()
   488  // 	if err != nil {
   489  // 		t.Fatal(err)
   490  // 	}
   491  // 	assert(t, fmt.Sprint(order.Cancel{ID: 1234567, CID: 123, Symbol: "tBTCUSD", MTSCreated: 1515179518260, MTSUpdated: 1515179520203, Type: "LIMIT", Status: "CANCELED", Price: 900.0, Amount: 1, AmountOrig: 1}), fmt.Sprint(*oc))
   492  // }
   493  
   494  // func TestUpdateOrder(t *testing.T) {
   495  // 	// create transport & nonce mocks
   496  // 	async := newTestAsync()
   497  // 	nonce := &IncrementingNonceGenerator{}
   498  
   499  // 	// create client
   500  // 	ws := websocket.NewWithAsyncFactoryNonce(newTestAsyncFactory(async), nonce).Credentials("apiKeyABC", "apiSecretXYZ")
   501  
   502  // 	// setup listener
   503  // 	listener := newListener()
   504  // 	listener.run(ws.Listen())
   505  
   506  // 	err_ws := ws.Connect()
   507  // 	if err_ws != nil {
   508  // 		t.Fatal(err_ws)
   509  // 	}
   510  // 	defer ws.Close()
   511  
   512  // 	// begin test
   513  // 	async.Publish(`{"event":"info","version":2}`)
   514  // 	_, err := listener.nextInfoEvent()
   515  // 	if err != nil {
   516  // 		t.Fatal(err)
   517  // 	}
   518  
   519  // 	// initial logon info--Authentication & WalletUpdate assertions in prior tests
   520  // 	async.Publish(`{"event":"auth","status":"OK","chanId":0,"userId":1,"subId":"nonce1","auth_id":"valid-auth-guid","caps":{"orders":{"read":1,"write":0},"account":{"read":1,"write":0},"funding":{"read":1,"write":0},"history":{"read":1,"write":0},"wallets":{"read":1,"write":0},"withdraw":{"read":0,"write":0},"positions":{"read":1,"write":0}}}`)
   521  // 	async.Publish(`[0,"ps",[["tBTCUSD","ACTIVE",7,916.52002351,0,0,null,null,null,null]]]`)
   522  // 	async.Publish(`[0,"ws",[["exchange","BTC",30,0,null],["exchange","USD",80000,0,null],["exchange","ETH",100,0,null],["margin","BTC",10,0,null],["margin","USD",9987.16871968,0,null],["funding","BTC",10,0,null],["funding","USD",10000,0,null]]]`)
   523  // 	// consume & assert snapshots
   524  // 	_, errps := listener.nextPositionSnapshot()
   525  // 	if errps != nil {
   526  // 		t.Fatal(errps)
   527  // 	}
   528  // 	_, errws := listener.nextWalletSnapshot()
   529  // 	if errws != nil {
   530  // 		t.Fatal(errws)
   531  // 	}
   532  
   533  // 	// submit order
   534  // 	err = ws.SubmitOrder(context.Background(), &order.NewRequest{
   535  // 		Symbol: "tBTCUSD",
   536  // 		CID:    123,
   537  // 		Amount: -0.456,
   538  // 		Type:   "LIMIT",
   539  // 		Price:  900.0,
   540  // 	})
   541  // 	if err != nil {
   542  // 		t.Fatal(err)
   543  // 	}
   544  
   545  // 	// assert outgoing order request
   546  // 	if len(async.Sent) <= 1 {
   547  // 		t.Fatalf("expected >1 sent messages, got %d", len(async.Sent))
   548  // 	}
   549  // 	assert(t, fmt.Sprint(order.NewRequest{Symbol: "tBTCUSD", CID: 123, Amount: -0.456, Type: "LIMIT", Price: 900.0}), fmt.Sprint(*async.Sent[1].(*order.NewRequest)))
   550  
   551  // 	// order pending new
   552  // 	async.Publish(`[0,"n",[null,"on-req",null,null,[1234567,null,123,"tBTCUSD",null,null,1,1,"LIMIT",null,null,null,null,null,null,null,900,null,null,null,null,null,null,0,null,null,null,null,null,null,null,null,null,null],null,"SUCCESS","Submitting limit buy order for 1.0 BTC."]]`)
   553  // 	// order working--limit order
   554  // 	async.Publish(`[0,"on",[1234567,0,123,"tBTCUSD",1515179518260,1515179518315,1,1,"LIMIT",null,null,null,0,"ACTIVE",null,null,900,0,null,null,null,null,null,0,0,0,null,null,null,null,null,null,null]]`)
   555  
   556  // 	// eat order ack notification
   557  // 	_, errn := listener.nextNotification()
   558  // 	if errn != nil {
   559  // 		t.Fatal(errn)
   560  // 	}
   561  
   562  // 	on, err := listener.nextOrderNew()
   563  // 	if err != nil {
   564  // 		t.Fatal(err)
   565  // 	}
   566  
   567  // 	// assert order new update
   568  // 	assert(t, fmt.Sprint(order.New{ID: 1234567, CID: 123, Symbol: "tBTCUSD", MTSCreated: 1515179518260, MTSUpdated: 1515179518315, Type: "LIMIT", Amount: 1, AmountOrig: 1, Status: "ACTIVE", Price: 900.0}), fmt.Sprint(*on))
   569  
   570  // 	// publish update request
   571  // 	req := &order.UpdateRequest{
   572  // 		ID:     on.ID,
   573  // 		Amount: 0.04,
   574  // 		Price:  1200,
   575  // 	}
   576  // 	pre := async.SentCount()
   577  // 	err = ws.SubmitUpdateOrder(context.Background(), req)
   578  // 	if err != nil {
   579  // 		t.Fatal(err)
   580  // 	}
   581  // 	if err := async.waitForMessage(pre); err != nil {
   582  // 		t.Fatal(err.Error())
   583  // 	}
   584  // 	// assert sent message
   585  // 	assert(t, fmt.Sprint(*req), fmt.Sprint(*async.Sent[pre].(*order.UpdateRequest)))
   586  
   587  // 	// cancel ack notify
   588  // 	async.Publish(`[0,"n",[1547469854094,"ou-req",null,null,[1234567,0,123,"tBTCUSD",1547469854025,1547469854042,0.04,0.04,"LIMIT",null,null,null,0,"ACTIVE",null,null,1200,0,0,0,null,null,null,0,0,null,null,null,"API>BFX",null,null,null],null,"SUCCESS","Submitting update to exchange limit buy order for 0.04 BTC."]]`)
   589  // 	// cancel confirm
   590  // 	async.Publish(`[0,"ou",[1234567,0,123,"tBTCUSD",1547469854025,1547469854121,0.04,0.04,"LIMIT",null,null,null,0,"ACTIVE",null,null,1200,0,0,0,null,null,null,0,0,null,null,null,"API>BFX",null,null,null]]`)
   591  
   592  // 	// assert cancel ack
   593  // 	ou, err := listener.nextOrderUpdate()
   594  // 	if err != nil {
   595  // 		t.Fatal(err)
   596  // 	}
   597  // 	assert(t, fmt.Sprint(order.Update{ID: 1234567, GID: 0, CID: 123, Symbol: "tBTCUSD", MTSCreated: 1547469854025, MTSUpdated: 1547469854121, Amount: 0.04, AmountOrig: 0.04, Type: "LIMIT", TypePrev: "", Flags: 0, Status: "ACTIVE", Price: 1200, PriceAvg: 0, PriceTrailing: 0, PriceAuxLimit: 0, Notify: false, Hidden: false, PlacedID: 0}), fmt.Sprint(*ou))
   598  // }
   599  
   600  // func TestUsesAuthenticatedSocket(t *testing.T) {
   601  // 	// create transport & nonce mocks
   602  // 	async := newTestAsync()
   603  // 	// create client
   604  // 	p := websocket.NewDefaultParameters()
   605  // 	// lock the capacity to 3
   606  // 	p.CapacityPerConnection = 3
   607  // 	ws := websocket.NewWithParamsAsyncFactory(p, newTestAsyncFactory(async)).Credentials("apiKeyABC", "apiSecretXYZ")
   608  
   609  // 	// setup listener
   610  // 	listener := newListener()
   611  // 	listener.run(ws.Listen())
   612  
   613  // 	// set ws options
   614  // 	err_ws := ws.Connect()
   615  // 	if err_ws != nil {
   616  // 		t.Fatal(err_ws)
   617  // 	}
   618  // 	defer ws.Close()
   619  
   620  // 	// info welcome msg
   621  // 	async.Publish(`{"event":"info","version":2}`)
   622  // 	ev, err := listener.nextInfoEvent()
   623  // 	if err != nil {
   624  // 		t.Fatal(err)
   625  // 	}
   626  // 	assert(t, fmt.Sprint(websocket.InfoEvent{Version: 2}), fmt.Sprint(*ev))
   627  // 	// auth ack
   628  // 	async.Publish(`{"event":"auth","status":"OK","chanId":0,"userId":1,"subId":"nonce1","auth_id":"valid-auth-guid","caps":{"orders":{"read":1,"write":0},"account":{"read":1,"write":0},"funding":{"read":1,"write":0},"history":{"read":1,"write":0},"wallets":{"read":1,"write":0},"withdraw":{"read":0,"write":0},"positions":{"read":1,"write":0}}}`)
   629  // 	// force websocket to create new connections
   630  // 	tickers := []string{"tBTCUSD", "tETHUSD", "tBTCUSD", "tVETUSD", "tDGBUSD", "tEOSUSD", "tTRXUSD", "tEOSETH", "tBTCETH",
   631  // 		"tBTCEOS", "tXRPUSD", "tXRPBTC", "tTRXETH", "tTRXBTC", "tLTCUSD", "tLTCBTC", "tLTCETH"}
   632  // 	for i, ticker := range tickers {
   633  // 		// subscribe to 15m candles
   634  // 		id, err := ws.SubscribeCandles(context.Background(), ticker, common.FifteenMinutes)
   635  // 		if err != nil {
   636  // 			t.Fatal(err)
   637  // 		}
   638  // 		async.Publish(`{"event":"subscribed","channel":"candles","chanId":` + fmt.Sprintf("%d", i) + `,"key":"trade:15m:` + ticker + `","subId":"` + id + `"}`)
   639  // 	}
   640  // 	authSocket, err := ws.GetAuthenticatedSocket()
   641  // 	if err != nil {
   642  // 		t.Fatal(err)
   643  // 	}
   644  // 	fmt.Println(*authSocket)
   645  // }