mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-21 23:16:49 +00:00
Merge branch 'master' into engine
This commit is contained in:
@@ -30,7 +30,12 @@ test_script:
|
||||
# test back-end
|
||||
- go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.16.0
|
||||
- '%GOPATH%\bin\golangci-lint.exe run --verbose'
|
||||
- go test -race ./...
|
||||
- ps: >-
|
||||
if($env:APPVEYOR_SCHEDULED_BUILD -eq 'true') {
|
||||
go test -race ./... -tags=mock_test_off
|
||||
}else {
|
||||
go test -race ./...
|
||||
}
|
||||
|
||||
# test front-end
|
||||
- node --version
|
||||
|
||||
@@ -25,9 +25,13 @@ CodeLingoBot | https://github.com/CodeLingoBot
|
||||
CodeLingoTeam | https://github.com/CodeLingoTeam
|
||||
Daanikus | https://github.com/Daanikus
|
||||
daniel-cohen | https://github.com/daniel-cohen
|
||||
DirectX | https://github.com/DirectX
|
||||
frankzougc | https://github.com/frankzougc
|
||||
starit | https://github.com/starit
|
||||
Jimexist | https://github.com/Jimexist
|
||||
lookfirst | https://github.com/lookfirst
|
||||
mattkanwisher | https://github.com/mattkanwisher
|
||||
mKurrels | https://github.com/mKurrels
|
||||
m1kola | https://github.com/m1kola
|
||||
cavapoo2 | https://github.com/cavapoo2
|
||||
zeldrinn | https://github.com/zeldrinn
|
||||
|
||||
|
||||
5
Makefile
5
Makefile
@@ -4,6 +4,7 @@ LINTPKG = github.com/golangci/golangci-lint/cmd/golangci-lint@v1.16.0
|
||||
LINTBIN = $(GOPATH)/bin/golangci-lint
|
||||
GCTLISTENPORT=9050
|
||||
GCTPROFILERLISTENPORT=8085
|
||||
CRON = $(TRAVIS_EVENT_TYPE)
|
||||
|
||||
get:
|
||||
GO111MODULE=on go get $(GCTPKG)
|
||||
@@ -16,7 +17,11 @@ linter:
|
||||
check: linter test
|
||||
|
||||
test:
|
||||
ifeq ($(CRON), cron)
|
||||
go test -race -tags=mock_test_off -coverprofile=coverage.txt -covermode=atomic ./...
|
||||
else
|
||||
go test -race -coverprofile=coverage.txt -covermode=atomic ./...
|
||||
endif
|
||||
|
||||
build:
|
||||
GO111MODULE=on go build $(LDFLAGS)
|
||||
|
||||
19
README.md
19
README.md
@@ -39,7 +39,8 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
||||
| Huobi.Hadax | Yes | Yes | NA |
|
||||
| ItBit | Yes | NA | No |
|
||||
| Kraken | Yes | Yes | NA |
|
||||
| LakeBTC | Yes | Yes | NA |
|
||||
| Lbank | Yes | No | NA |
|
||||
| LakeBTC | Yes | No | NA |
|
||||
| LocalBitcoins | Yes | NA | NA |
|
||||
| OKCoin International | Yes | Yes | No |
|
||||
| OKEX | Yes | Yes | No |
|
||||
@@ -129,10 +130,11 @@ Binaries will be published once the codebase reaches a stable condition.
|
||||
### A very special thank you to all who have contributed to this program:
|
||||
|
||||
|User|Github|Contribution Amount|
|
||||
|--|--|--|| thrasher- | https://github.com/thrasher- | 540 |
|
||||
| shazbert | https://github.com/shazbert | 173 |
|
||||
| gloriousCode | https://github.com/gloriousCode | 150 |
|
||||
| xtda | https://github.com/xtda | 17 |
|
||||
|--|--|--|
|
||||
| thrasher- | https://github.com/thrasher- | 543 |
|
||||
| shazbert | https://github.com/shazbert | 174 |
|
||||
| gloriousCode | https://github.com/gloriousCode | 154 |
|
||||
| xtda | https://github.com/xtda | 18 |
|
||||
| ermalguni | https://github.com/ermalguni | 14 |
|
||||
| vadimzhukck | https://github.com/vadimzhukck | 10 |
|
||||
| 140am | https://github.com/140am | 8 |
|
||||
@@ -154,10 +156,13 @@ Binaries will be published once the codebase reaches a stable condition.
|
||||
| CodeLingoTeam | https://github.com/CodeLingoTeam | 1 |
|
||||
| Daanikus | https://github.com/Daanikus | 1 |
|
||||
| daniel-cohen | https://github.com/daniel-cohen | 1 |
|
||||
| DirectX | https://github.com/DirectX | 1 |
|
||||
| frankzougc | https://github.com/frankzougc | 1 |
|
||||
| starit | https://github.com/starit | 1 |
|
||||
| Jimexist | https://github.com/Jimexist | 1 |
|
||||
| lookfirst | https://github.com/lookfirst | 1 |
|
||||
| mattkanwisher | https://github.com/mattkanwisher | 1 |
|
||||
| mKurrels | https://github.com/mKurrels | 1 |
|
||||
| m1kola | https://github.com/m1kola | 1 |
|
||||
| cavapoo2 | https://github.com/cavapoo2 | 1 |
|
||||
| zeldrinn | https://github.com/zeldrinn | 1 |
|
||||
|
||||
|
||||
|
||||
98
cmd/documentation/exchanges_templates/lbank.tmpl
Normal file
98
cmd/documentation/exchanges_templates/lbank.tmpl
Normal file
@@ -0,0 +1,98 @@
|
||||
{{define "exchanges lbank" -}}
|
||||
{{template "header" .}}
|
||||
## Lbank Exchange
|
||||
|
||||
### Current Features
|
||||
|
||||
+ REST Support
|
||||
|
||||
### How to enable
|
||||
|
||||
+ [Enable via configuration](https://githul.com/thrasher-corp/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
|
||||
|
||||
+ Individual package example below:
|
||||
|
||||
```go
|
||||
// Exchanges will be abstracted out in further updates and examples will be
|
||||
// supplied then
|
||||
```
|
||||
|
||||
### How to do REST public/private calls
|
||||
|
||||
+ If enabled via "configuration".json file the exchange will be added to the
|
||||
IBotExchange array in the ```go var bot Bot``` and you will only be able to use
|
||||
the wrapper interface functions for accessing exchange data. View routines.go
|
||||
for an example of integration usage with GoCryptoTrader. Rudimentary example
|
||||
below:
|
||||
|
||||
main.go
|
||||
```go
|
||||
var l exchange.IBotExchange
|
||||
|
||||
for i := range bot.exchanges {
|
||||
if bot.exchanges[i].GetName() == "Lbank" {
|
||||
l = bot.exchanges[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Public calls - wrapper functions
|
||||
|
||||
// Fetches current ticker information
|
||||
tick, err := l.GetTickerPrice()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := l.GetOrderbookEx()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
|
||||
// set and AuthenticatedAPISupport is set to true
|
||||
|
||||
// Fetches current account information
|
||||
accountInfo, err := l.GetAccountInfo()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
+ If enabled via individually importing package, rudimentary example below:
|
||||
|
||||
```go
|
||||
// Public calls
|
||||
|
||||
// Fetches current ticker information
|
||||
ticker, err := l.GetTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := l.GetOrderBook()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Private calls - make sure your APIKEY and APISECRET are set and
|
||||
// AuthenticatedAPISupport is set to true
|
||||
|
||||
// GetUserInfo returns account info
|
||||
accountInfo, err := l.GetUserInfo(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Submits an order and the exchange and returns its tradeID
|
||||
tradeID, err := l.Trade(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||
{{template "contributions"}}
|
||||
{{template "donations"}}
|
||||
{{end}}
|
||||
@@ -40,7 +40,8 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
||||
| Huobi.Hadax | Yes | Yes | NA |
|
||||
| ItBit | Yes | NA | No |
|
||||
| Kraken | Yes | Yes | NA |
|
||||
| LakeBTC | Yes | Yes | NA |
|
||||
| Lbank | Yes | No | NA |
|
||||
| LakeBTC | Yes | No | NA |
|
||||
| LocalBitcoins | Yes | NA | NA |
|
||||
| OKCoin International | Yes | Yes | No |
|
||||
| OKEX | Yes | Yes | No |
|
||||
|
||||
@@ -85,7 +85,6 @@ have multiple deposit accounts for different FIAT deposit currencies.
|
||||
"websocketResponseCheckTimeout": 30000000,
|
||||
"websocketResponseMaxLimit": 7000000000,
|
||||
"httpTimeout": 15000000000,
|
||||
"AuthenticatedAPISupport": false,
|
||||
"APIKey": "Key",
|
||||
"APISecret": "Secret",
|
||||
"AvailablePairs": "ATENC_GBP,ATENC_NZD,BTC_AUD,BTC_SGD,LTC_BTC,START_GBP,...",
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
const (
|
||||
// Default number of enabled exchanges. Modify this whenever an exchange is
|
||||
// added or removed
|
||||
defaultEnabledExchanges = 27
|
||||
defaultEnabledExchanges = 28
|
||||
)
|
||||
|
||||
func TestGetCurrencyConfig(t *testing.T) {
|
||||
@@ -465,7 +465,7 @@ func TestCountEnabledExchanges(t *testing.T) {
|
||||
}
|
||||
enabledExch := GetConfigEnabledExchanges.CountEnabledExchanges()
|
||||
if enabledExch != defaultEnabledExchanges {
|
||||
t.Error("Test failed. GetConfigEnabledExchanges is wrong")
|
||||
t.Errorf("Test failed. Expected %v, Received %v", defaultEnabledExchanges, enabledExch)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1107,6 +1107,48 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "LBank",
|
||||
"enabled": true,
|
||||
"verbose": false,
|
||||
"websocket": false,
|
||||
"useSandbox": false,
|
||||
"restPollingDelay": 10,
|
||||
"httpTimeout": 15000000000,
|
||||
"httpUserAgent": "",
|
||||
"httpDebugging": false,
|
||||
"authenticatedApiSupport": false,
|
||||
"apiKey": "Key",
|
||||
"apiSecret": "Secret",
|
||||
"apiUrl": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
|
||||
"apiUrlSecondary": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
|
||||
"proxyAddress": "",
|
||||
"websocketUrl": "NON_DEFAULT_HTTP_LINK_TO_WEBSOCKET_EXCHANGE_API",
|
||||
"availablePairs": "fbc_usdt,hds_usdt,galt_usdt,dxn_usdt,iog_usdt,ioex_usdt,vollar_usdt,oath_usdt,bloc_usdt,btc_lbcn,eth_lbcn,usdt_lbcn,btc_usdt,eth_usdt,eth_btc,abbc_btc,bzky_eth,onot_eth,kisc_eth,bxa_usdt,atp_usdt,mat_usdt,sky_btc,sky_lbcn,rnt_usdt,vena_usdt,grin_usdt,ida_usdt,pnt_usdt,bsv_btc,bsv_usdt,opx_usdt,tena_eth,seer_lbcn,vet_lbcn,vtho_btc,vnx_lbcn,vnx_btc,amo_eth,ubex_btc,eos_btc,ubex_usdt,tns_lbcn,tns_btc,ali_eth,sdc_eth,sait_eth,artcn_usdt,dax_btc,dax_eth,dali_usdt,vet_usdt,ten_usdt,bch_usdt,neo_usdt,qtum_usdt,zec_usdt,vet_btc,pai_btc,pnt_btc,bch_btc,ltc_btc,neo_btc,dash_btc,etc_btc,qtum_btc,zec_btc,sc_btc,bts_btc,cpx_btc,xwc_btc,fil6_btc,fil12_btc,fil36_btc,eos_usdt,ut_eth,ela_eth,vet_eth,vtho_eth,pai_eth,bfdt_eth,her_eth,ptt_eth,tac_eth,idhub_eth,ssc_eth,skm_eth,iic_eth,ply_eth,ext_eth,eos_eth,yoyow_eth,trx_eth,qtum_eth,zec_eth,bts_eth,btm_eth,mith_eth,nas_eth,man_eth,dbc_eth,bto_eth,ddd_eth,cpx_eth,cs_eth,iht_eth,tky_eth,ocn_eth,dct_eth,zpt_eth,eko_eth,mda_eth,pst_eth,xwc_eth,put_eth,pnt_eth,aac_eth,fil6_eth,fil12_eth,fil36_eth,uip_eth,seer_eth,bsb_eth,cdc_eth,grams_eth,ddmx_eth,eai_eth,inc_eth,bnb_usdt,ht_usdt,bot_eth,kbc_btc,kbc_usdt,mai_usdt,phv_usdt,hnb_usdt,gt_usdt,b91_usdt,voken_usdt,cye_usdt,brc_usdt,btc_ausd",
|
||||
"enabledPairs": "btc_usdt",
|
||||
"baseCurrencies": "USD",
|
||||
"assetTypes": "SPOT",
|
||||
"supportsAutoPairUpdates": true,
|
||||
"configCurrencyPairFormat": {
|
||||
"uppercase": false,
|
||||
"delimiter": "_"
|
||||
},
|
||||
"requestCurrencyPairFormat": {
|
||||
"uppercase": false,
|
||||
"delimiter": "_"
|
||||
},
|
||||
"bankAccounts": [
|
||||
{
|
||||
"bankName": "",
|
||||
"bankAddress": "",
|
||||
"accountName": "",
|
||||
"accountNumber": "",
|
||||
"swiftCode": "",
|
||||
"iban": "",
|
||||
"supportedCurrencies": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "LocalBitcoins",
|
||||
"enabled": true,
|
||||
|
||||
@@ -733,6 +733,7 @@ func (c *Coinmarketcap) SendHTTPRequest(method, endpoint string, v url.Values, r
|
||||
false,
|
||||
false,
|
||||
c.Verbose,
|
||||
false,
|
||||
false)
|
||||
}
|
||||
|
||||
|
||||
@@ -193,6 +193,7 @@ func (c *CurrencyConverter) SendHTTPRequest(endPoint string, values url.Values,
|
||||
auth,
|
||||
false,
|
||||
c.Verbose,
|
||||
false,
|
||||
false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("currency converter API SendHTTPRequest error %s with path %s",
|
||||
|
||||
@@ -243,5 +243,6 @@ func (c *CurrencyLayer) SendHTTPRequest(endPoint string, values url.Values, resu
|
||||
auth,
|
||||
false,
|
||||
c.Verbose,
|
||||
false,
|
||||
false)
|
||||
}
|
||||
|
||||
@@ -179,6 +179,7 @@ func (e *ExchangeRates) SendHTTPRequest(endPoint string, values url.Values, resu
|
||||
false,
|
||||
false,
|
||||
e.Verbose,
|
||||
false,
|
||||
false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("exchangeRatesAPI SendHTTPRequest error %s with path %s",
|
||||
|
||||
@@ -267,5 +267,6 @@ func (f *Fixer) SendOpenHTTPRequest(endpoint string, v url.Values, result interf
|
||||
auth,
|
||||
false,
|
||||
f.Verbose,
|
||||
false,
|
||||
false)
|
||||
}
|
||||
|
||||
@@ -267,5 +267,6 @@ func (o *OXR) SendHTTPRequest(endpoint string, values url.Values, result interfa
|
||||
false,
|
||||
false,
|
||||
o.Verbose,
|
||||
false,
|
||||
false)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/itbit"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/kraken"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/lakebtc"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/lbank"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/localbitcoins"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/okcoin"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/okex"
|
||||
@@ -174,6 +175,8 @@ func LoadExchange(name string, useWG bool, wg *sync.WaitGroup) error {
|
||||
exch = new(kraken.Kraken)
|
||||
case "lakebtc":
|
||||
exch = new(lakebtc.LakeBTC)
|
||||
case "lbank":
|
||||
exch = new(lbank.Lbank)
|
||||
case "localbitcoins":
|
||||
exch = new(localbitcoins.LocalBitcoins)
|
||||
case "okcoin international":
|
||||
|
||||
@@ -517,7 +517,16 @@ func (a *Alphapoint) SendHTTPRequest(method, path string, data map[string]interf
|
||||
return errors.New("unable to JSON request")
|
||||
}
|
||||
|
||||
return a.SendPayload(method, path, headers, bytes.NewBuffer(PayloadJSON), result, false, false, a.Verbose, a.HTTPDebugging)
|
||||
return a.SendPayload(method,
|
||||
path,
|
||||
headers,
|
||||
bytes.NewBuffer(PayloadJSON),
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
a.Verbose,
|
||||
a.HTTPDebugging,
|
||||
a.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated request
|
||||
@@ -543,5 +552,14 @@ func (a *Alphapoint) SendAuthenticatedHTTPRequest(method, path string, data map[
|
||||
return errors.New("unable to JSON request")
|
||||
}
|
||||
|
||||
return a.SendPayload(method, path, headers, bytes.NewBuffer(PayloadJSON), result, true, true, a.Verbose, a.HTTPDebugging)
|
||||
return a.SendPayload(method,
|
||||
path,
|
||||
headers,
|
||||
bytes.NewBuffer(PayloadJSON),
|
||||
result,
|
||||
true,
|
||||
true,
|
||||
a.Verbose,
|
||||
a.HTTPDebugging,
|
||||
a.HTTPRecording)
|
||||
}
|
||||
|
||||
@@ -176,9 +176,13 @@ func (a *ANX) NewOrder(orderType string, buy bool, tradedCurrency string, traded
|
||||
// CancelOrderByIDs cancels orders, requires already knowing order IDs
|
||||
// There is no existing API call to retrieve orderIds
|
||||
func (a *ANX) CancelOrderByIDs(orderIds []string) (OrderCancelResponse, error) {
|
||||
var response OrderCancelResponse
|
||||
if len(orderIds) == 0 {
|
||||
return response, errors.New("no order ids provided")
|
||||
}
|
||||
|
||||
req := make(map[string]interface{})
|
||||
req["orderIds"] = orderIds
|
||||
var response OrderCancelResponse
|
||||
|
||||
err := a.SendAuthenticatedHTTPRequest(anxOrderCancel, req, &response)
|
||||
if response.ResultCode != "OK" {
|
||||
@@ -194,7 +198,7 @@ func (a *ANX) GetOrderList(isActiveOrdersOnly bool) ([]OrderResponse, error) {
|
||||
req["activeOnly"] = isActiveOrdersOnly
|
||||
|
||||
type OrderListResponse struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Timestamp int64 `json:"timestamp,string"`
|
||||
ResultCode string `json:"resultCode"`
|
||||
Count int64 `json:"count"`
|
||||
OrderResponses []OrderResponse `json:"orders"`
|
||||
@@ -206,7 +210,6 @@ func (a *ANX) GetOrderList(isActiveOrdersOnly bool) ([]OrderResponse, error) {
|
||||
}
|
||||
|
||||
if response.ResultCode != "OK" {
|
||||
log.Errorf(log.ExchangeSys, "Response code is not OK: %s\n", response.ResultCode)
|
||||
return nil, errors.New(response.ResultCode)
|
||||
}
|
||||
|
||||
@@ -232,7 +235,6 @@ func (a *ANX) OrderInfo(orderID string) (OrderResponse, error) {
|
||||
}
|
||||
|
||||
if response.ResultCode != "OK" {
|
||||
log.Errorf(log.ExchangeSys, "Response code is not OK: %s\n", response.ResultCode)
|
||||
return OrderResponse{}, errors.New(response.ResultCode)
|
||||
}
|
||||
return response.Order, nil
|
||||
@@ -252,7 +254,7 @@ func (a *ANX) Send(currency, address, otp, amount string) (string, error) {
|
||||
type SendResponse struct {
|
||||
TransactionID string `json:"transactionId"`
|
||||
ResultCode string `json:"resultCode"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Timestamp int64 `json:"timestamp,string"`
|
||||
}
|
||||
var response SendResponse
|
||||
|
||||
@@ -263,7 +265,6 @@ func (a *ANX) Send(currency, address, otp, amount string) (string, error) {
|
||||
}
|
||||
|
||||
if response.ResultCode != "OK" {
|
||||
log.Errorf(log.ExchangeSys, "Response code is not OK: %s\n", response.ResultCode)
|
||||
return "", errors.New(response.ResultCode)
|
||||
}
|
||||
return response.TransactionID, nil
|
||||
@@ -289,7 +290,6 @@ func (a *ANX) CreateNewSubAccount(currency, name string) (string, error) {
|
||||
}
|
||||
|
||||
if response.ResultCode != "OK" {
|
||||
log.Errorf(log.ExchangeSys, "Response code is not OK: %s\n", response.ResultCode)
|
||||
return "", errors.New(response.ResultCode)
|
||||
}
|
||||
return response.SubAccount, nil
|
||||
@@ -308,7 +308,7 @@ func (a *ANX) GetDepositAddressByCurrency(currency, name string, newAddr bool) (
|
||||
Address string `json:"address"`
|
||||
SubAccount string `json:"subAccount"`
|
||||
ResultCode string `json:"resultCode"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Timestamp int64 `json:"timestamp,string"`
|
||||
}
|
||||
var response AddressResponse
|
||||
|
||||
@@ -323,7 +323,6 @@ func (a *ANX) GetDepositAddressByCurrency(currency, name string, newAddr bool) (
|
||||
}
|
||||
|
||||
if response.ResultCode != "OK" {
|
||||
log.Errorf(log.ExchangeSys, "Response code is not OK: %s\n", response.ResultCode)
|
||||
return "", errors.New(response.ResultCode)
|
||||
}
|
||||
|
||||
@@ -332,7 +331,16 @@ func (a *ANX) GetDepositAddressByCurrency(currency, name string, newAddr bool) (
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (a *ANX) SendHTTPRequest(path string, result interface{}) error {
|
||||
return a.SendPayload(http.MethodGet, path, nil, nil, result, false, false, a.Verbose, a.HTTPDebugging)
|
||||
return a.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
a.Verbose,
|
||||
a.HTTPDebugging,
|
||||
a.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends a authenticated HTTP request
|
||||
@@ -365,9 +373,16 @@ func (a *ANX) SendAuthenticatedHTTPRequest(path string, params map[string]interf
|
||||
headers["Rest-Sign"] = crypto.Base64Encode(hmac)
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
return a.SendPayload(http.MethodPost, a.API.Endpoints.URL+path, headers,
|
||||
bytes.NewBuffer(PayloadJSON), result, true, true, a.Verbose,
|
||||
a.HTTPDebugging)
|
||||
return a.SendPayload(http.MethodPost,
|
||||
a.API.Endpoints.URL+path,
|
||||
headers,
|
||||
bytes.NewBuffer(PayloadJSON),
|
||||
result,
|
||||
true,
|
||||
true,
|
||||
a.Verbose,
|
||||
a.HTTPDebugging,
|
||||
a.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
32
exchanges/anx/anx_live_test.go
Normal file
32
exchanges/anx/anx_live_test.go
Normal file
@@ -0,0 +1,32 @@
|
||||
//+build mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is parsed and will do live testing
|
||||
// using all tests in (exchange)_test.go
|
||||
package anx
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
var mockTests = false
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
anxConfig, err := cfg.GetExchangeConfig("ANX")
|
||||
if err != nil {
|
||||
log.Fatalf("Test Failed - ANX Setup() init error: %s", err)
|
||||
}
|
||||
anxConfig.API.AuthenticatedSupport = true
|
||||
anxConfig.API.Credentials.Key = apiKey
|
||||
anxConfig.API.Credentials.Secret = apiSecret
|
||||
a.SetDefaults()
|
||||
a.Setup(anxConfig)
|
||||
log.Printf(sharedtestvalues.LiveTesting, a.GetName(), a.API.Endpoints.URL)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
45
exchanges/anx/anx_mock_test.go
Normal file
45
exchanges/anx/anx_mock_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
//+build !mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is not parsed and will try to mock
|
||||
// all tests in _test.go
|
||||
package anx
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/mock"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
const mockFile = "../../testdata/http_mock/anx/anx.json"
|
||||
|
||||
var mockTests = true
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
anxConfig, err := cfg.GetExchangeConfig("ANX")
|
||||
if err != nil {
|
||||
log.Fatal("Test Failed - Mock server error", err)
|
||||
}
|
||||
a.SkipAuthCheck = true
|
||||
anxConfig.API.AuthenticatedSupport = true
|
||||
anxConfig.API.Credentials.Key = apiKey
|
||||
anxConfig.API.Credentials.Secret = apiSecret
|
||||
a.SetDefaults()
|
||||
a.Setup(anxConfig)
|
||||
|
||||
serverDetails, newClient, err := mock.NewVCRServer(mockFile)
|
||||
if err != nil {
|
||||
log.Fatalf("Test Failed - Mock server error %s", err)
|
||||
}
|
||||
|
||||
a.HTTPClient = newClient
|
||||
a.API.Endpoints.URL = serverDetails + "/"
|
||||
|
||||
log.Printf(sharedtestvalues.MockTesting, a.GetName(), a.API.Endpoints.URL)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
@@ -19,52 +18,16 @@ const (
|
||||
|
||||
var a ANX
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
a.SetDefaults()
|
||||
|
||||
if a.Name != "ANX" {
|
||||
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
|
||||
}
|
||||
if !a.Enabled {
|
||||
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
|
||||
}
|
||||
if !a.Verbose {
|
||||
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
anxSetupConfig := config.GetConfig()
|
||||
anxSetupConfig.LoadConfig("../../testdata/configtest.json")
|
||||
anxConfig, err := anxSetupConfig.GetExchangeConfig("ANX")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - ANX Setup() init error")
|
||||
}
|
||||
|
||||
a.Setup(anxConfig)
|
||||
a.API.Credentials.Key = apiKey
|
||||
a.API.Credentials.Secret = apiSecret
|
||||
a.API.AuthenticatedSupport = true
|
||||
|
||||
if !a.Enabled {
|
||||
t.Error("Test Failed - ANX Setup() incorrect values set")
|
||||
}
|
||||
if a.Verbose {
|
||||
t.Error("Test Failed - ANX Setup() incorrect values set")
|
||||
}
|
||||
if len(a.BaseCurrencies) == 0 {
|
||||
t.Error("Test Failed - ANX Setup() incorrect values set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCurrencies(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := a.GetCurrencies()
|
||||
if err != nil {
|
||||
t.Fatalf("Test failed. TestGetCurrencies failed. Err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchTradablePairs(t *testing.T) {
|
||||
func TestGetTradablePairs(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := a.FetchTradablePairs(asset.Spot)
|
||||
if err != nil {
|
||||
t.Fatalf("Test failed. TestGetTradablePairs failed. Err: %s", err)
|
||||
@@ -72,6 +35,7 @@ func TestFetchTradablePairs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
ticker, err := a.GetTicker("BTCUSD")
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - ANX GetTicker() error: %s", err)
|
||||
@@ -82,16 +46,18 @@ func TestGetTicker(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetDepth(t *testing.T) {
|
||||
ticker, err := a.GetDepth("BTCUSD")
|
||||
t.Parallel()
|
||||
depth, err := a.GetDepth("BTCUSD")
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - ANX GetDepth() error: %s", err)
|
||||
}
|
||||
if ticker.Result != "success" {
|
||||
if depth.Result != "success" {
|
||||
t.Error("Test Failed - ANX GetDepth() unsuccessful")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAPIKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
apiKey, apiSecret, err := a.GetAPIKey("userName", "passWord", "", "1337")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - ANX GetAPIKey() Incorrect")
|
||||
@@ -116,6 +82,7 @@ func setFeeBuilder() *exchange.FeeBuilder {
|
||||
|
||||
// TestGetFeeByTypeOfflineTradeFee logic test
|
||||
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
var feeBuilder = setFeeBuilder()
|
||||
a.GetFeeByType(feeBuilder)
|
||||
if apiKey == "" || apiSecret == "" {
|
||||
@@ -130,9 +97,7 @@ func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetFee(t *testing.T) {
|
||||
a.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
t.Parallel()
|
||||
var feeBuilder = setFeeBuilder()
|
||||
|
||||
// CryptocurrencyTradeFee Basic
|
||||
@@ -202,7 +167,7 @@ func TestGetFee(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFormatWithdrawPermissions(t *testing.T) {
|
||||
a.SetDefaults()
|
||||
t.Parallel()
|
||||
expectedResult := exchange.AutoWithdrawCryptoWithSetupText + " & " + exchange.WithdrawCryptoWith2FAText + " & " +
|
||||
exchange.WithdrawCryptoWithEmailText + " & " + exchange.WithdrawFiatViaWebsiteOnlyText
|
||||
|
||||
@@ -214,34 +179,36 @@ func TestFormatWithdrawPermissions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetActiveOrders(t *testing.T) {
|
||||
a.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
t.Parallel()
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
}
|
||||
|
||||
_, err := a.GetActiveOrders(&getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
a.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
t.Parallel()
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
}
|
||||
|
||||
_, err := a.GetOrderHistory(&getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not get order history: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - GetBalance() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,10 +220,8 @@ func areTestAPIKeysSet() bool {
|
||||
}
|
||||
|
||||
func TestSubmitOrder(t *testing.T) {
|
||||
a.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
@@ -267,13 +232,14 @@ func TestSubmitOrder(t *testing.T) {
|
||||
Quote: currency.USD,
|
||||
},
|
||||
OrderSide: exchange.BuyOrderSide,
|
||||
OrderType: exchange.LimitOrderType,
|
||||
OrderType: exchange.MarketOrderType,
|
||||
Price: 1,
|
||||
Amount: 1,
|
||||
ClientID: "meowOrder",
|
||||
}
|
||||
response, err := a.SubmitOrder(orderSubmission)
|
||||
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
|
||||
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) && !mockTests {
|
||||
// TODO: QA Pass to submit order
|
||||
t.Errorf("Order failed to be placed: %v", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
@@ -281,10 +247,8 @@ func TestSubmitOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCancelExchangeOrder(t *testing.T) {
|
||||
a.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
@@ -298,18 +262,19 @@ func TestCancelExchangeOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
err := a.CancelOrder(orderCancellation)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not cancel order: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not cancel order: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
a.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
@@ -323,11 +288,13 @@ func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
resp, err := a.CancelAllOrders(orderCancellation)
|
||||
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not cancel order: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err == nil:
|
||||
t.Errorf("QA pass needs to be completed and mock needs to be updated error cannot be nil")
|
||||
}
|
||||
|
||||
if len(resp.OrderStatus) > 0 {
|
||||
@@ -336,20 +303,20 @@ func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetAccountInfo(t *testing.T) {
|
||||
if apiKey != "" || apiSecret != "" {
|
||||
_, err := a.GetAccountInfo()
|
||||
if err != nil {
|
||||
t.Error("test failed - GetAccountInfo() error:", err)
|
||||
}
|
||||
} else {
|
||||
_, err := a.GetAccountInfo()
|
||||
if err == nil {
|
||||
t.Error("test failed - GetAccountInfo() error")
|
||||
}
|
||||
t.Parallel()
|
||||
_, err := a.GetAccountInfo()
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Error("test failed - GetAccountInfo() error:", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("test failed - GetAccountInfo() error")
|
||||
case mockTests && err != nil:
|
||||
t.Error("test failed - GetAccountInfo() error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestModifyOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := a.ModifyOrder(&exchange.ModifyOrder{})
|
||||
if err == nil {
|
||||
t.Error("Test failed - ModifyOrder() error")
|
||||
@@ -357,10 +324,8 @@ func TestModifyOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
a.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
@@ -375,55 +340,54 @@ func TestWithdraw(t *testing.T) {
|
||||
}
|
||||
|
||||
_, err := a.WithdrawCryptocurrencyFunds(&withdrawCryptoRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
if areTestAPIKeysSet() && err != nil && !mockTests {
|
||||
t.Errorf("Withdraw failed to be placed: %v", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
} else if !areTestAPIKeysSet() && err == nil && mockTests {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawFiat(t *testing.T) {
|
||||
a.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
var withdrawFiatRequest = exchange.FiatWithdrawRequest{}
|
||||
|
||||
_, err := a.WithdrawFiatFunds(&withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
|
||||
t.Errorf("Expected '%v', received: '%v'",
|
||||
common.ErrFunctionNotSupported,
|
||||
err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawInternationalBank(t *testing.T) {
|
||||
a.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
var withdrawFiatRequest = exchange.FiatWithdrawRequest{}
|
||||
|
||||
_, err := a.WithdrawFiatFundsToInternationalBank(&withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
|
||||
t.Errorf("Expected '%v', received: '%v'",
|
||||
common.ErrFunctionNotSupported,
|
||||
err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDepositAddress(t *testing.T) {
|
||||
if areTestAPIKeysSet() {
|
||||
_, err := a.GetDepositAddress(currency.BTC, "")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetDepositAddress() error", err)
|
||||
}
|
||||
} else {
|
||||
_, err := a.GetDepositAddress(currency.BTC, "")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetDepositAddress() error cannot be nil")
|
||||
}
|
||||
t.Parallel()
|
||||
_, err := a.GetDepositAddress(currency.BTC, "")
|
||||
if areTestAPIKeysSet() && err != nil && !mockTests {
|
||||
t.Error("Test Failed - GetDepositAddress() error", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Test Failed - GetDepositAddress() error cannot be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := currency.Pair{
|
||||
Delimiter: "_",
|
||||
Base: currency.BTC,
|
||||
Quote: currency.USD}
|
||||
|
||||
_, err := a.UpdateOrderbook(q, "spot")
|
||||
if err != nil {
|
||||
t.Fatalf("Update for orderbook failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ func (a *ANX) SetDefaults() {
|
||||
}
|
||||
a.API.CredentialsValidator.RequiresKey = true
|
||||
a.API.CredentialsValidator.RequiresSecret = true
|
||||
a.API.CredentialsValidator.RequiresBase64DecodeSecret = true
|
||||
|
||||
a.CurrencyPairs = currency.PairsManager{
|
||||
AssetTypes: asset.Items{
|
||||
@@ -464,7 +465,7 @@ func (a *ANX) GetWebsocket() (*wshandler.Websocket, error) {
|
||||
|
||||
// GetFeeByType returns an estimate of fee based on type of transaction
|
||||
func (a *ANX) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
if !a.AllowAuthenticatedRequest() && // Todo check connection status
|
||||
if (!a.AllowAuthenticatedRequest() || a.SkipAuthCheck) && // Todo check connection status
|
||||
feeBuilder.FeeType == exchange.CryptocurrencyTradeFee {
|
||||
feeBuilder.FeeType = exchange.OfflineTradeFee
|
||||
}
|
||||
|
||||
@@ -159,20 +159,10 @@ func (b *Binance) GetRecentTrades(rtr RecentTradeRequestParams) ([]RecentTrade,
|
||||
// limit: Optional. Default 500; max 1000.
|
||||
// fromID:
|
||||
func (b *Binance) GetHistoricalTrades(symbol string, limit int, fromID int64) ([]HistoricalTrade, error) {
|
||||
var resp []HistoricalTrade
|
||||
|
||||
if err := b.CheckLimit(limit); err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
params := url.Values{}
|
||||
params.Set("symbol", strings.ToUpper(symbol))
|
||||
params.Set("limit", strconv.Itoa(limit))
|
||||
params.Set("fromid", strconv.FormatInt(fromID, 10))
|
||||
|
||||
path := fmt.Sprintf("%s%s?%s", b.API.Endpoints.URL, historicalTrades, params.Encode())
|
||||
|
||||
return resp, b.SendHTTPRequest(path, &resp)
|
||||
// Dropping support due to response for market data is always
|
||||
// {"code":-2014,"msg":"API-key format invalid."}
|
||||
// TODO: replace with newer API vs REST endpoint
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetAggregatedTrades returns aggregated trade activity
|
||||
@@ -476,7 +466,16 @@ func (b *Binance) GetAccount() (*Account, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated request
|
||||
func (b *Binance) SendHTTPRequest(path string, result interface{}) error {
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose, b.HTTPDebugging)
|
||||
return b.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthHTTPRequest sends an authenticated HTTP request
|
||||
@@ -512,7 +511,16 @@ func (b *Binance) SendAuthHTTPRequest(method, path string, params url.Values, re
|
||||
Message string `json:"msg"`
|
||||
}{}
|
||||
|
||||
err := b.SendPayload(method, path, headers, bytes.NewBuffer(nil), &interim, true, false, b.Verbose, b.HTTPDebugging)
|
||||
err := b.SendPayload(method,
|
||||
path,
|
||||
headers,
|
||||
bytes.NewBuffer(nil),
|
||||
&interim,
|
||||
true,
|
||||
false,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -632,7 +640,7 @@ func getCryptocurrencyWithdrawalFee(c currency.Code) float64 {
|
||||
}
|
||||
|
||||
// WithdrawCrypto sends cryptocurrency to the address of your choosing
|
||||
func (b *Binance) WithdrawCrypto(asset, address, addressTag, name, amount string) (int64, error) {
|
||||
func (b *Binance) WithdrawCrypto(asset, address, addressTag, name, amount string) (string, error) {
|
||||
var resp WithdrawResponse
|
||||
path := fmt.Sprintf("%s%s", b.API.Endpoints.URL, withdraw)
|
||||
|
||||
@@ -648,7 +656,7 @@ func (b *Binance) WithdrawCrypto(asset, address, addressTag, name, amount string
|
||||
}
|
||||
|
||||
if err := b.SendAuthHTTPRequest(http.MethodPost, path, params, &resp); err != nil {
|
||||
return -1, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !resp.Success {
|
||||
|
||||
32
exchanges/binance/binance_live_test.go
Normal file
32
exchanges/binance/binance_live_test.go
Normal file
@@ -0,0 +1,32 @@
|
||||
//+build mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is parsed and will do live testing
|
||||
// using all tests in (exchange)_test.go
|
||||
package binance
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
var mockTests = false
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
binanceConfig, err := cfg.GetExchangeConfig("Binance")
|
||||
if err != nil {
|
||||
log.Fatal("Test Failed - Binance Setup() init error", err)
|
||||
}
|
||||
binanceConfig.API.AuthenticatedSupport = true
|
||||
binanceConfig.API.Credentials.Key = apiKey
|
||||
binanceConfig.API.Credentials.Secret = apiSecret
|
||||
b.SetDefaults()
|
||||
b.Setup(binanceConfig)
|
||||
log.Printf(sharedtestvalues.LiveTesting, b.GetName(), b.API.Endpoints.URL)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
45
exchanges/binance/binance_mock_test.go
Normal file
45
exchanges/binance/binance_mock_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
//+build !mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is not parsed and will try to mock
|
||||
// all tests in _test.go
|
||||
package binance
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/mock"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
const mockfile = "../../testdata/http_mock/binance/binance.json"
|
||||
|
||||
var mockTests = true
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
binanceConfig, err := cfg.GetExchangeConfig("Binance")
|
||||
if err != nil {
|
||||
log.Fatal("Test Failed - Binance Setup() init error", err)
|
||||
}
|
||||
b.SkipAuthCheck = true
|
||||
binanceConfig.API.AuthenticatedSupport = true
|
||||
binanceConfig.API.Credentials.Key = apiKey
|
||||
binanceConfig.API.Credentials.Secret = apiSecret
|
||||
b.SetDefaults()
|
||||
b.Setup(binanceConfig)
|
||||
|
||||
serverDetails, newClient, err := mock.NewVCRServer(mockfile)
|
||||
if err != nil {
|
||||
log.Fatalf("Test Failed - Mock server error %s", err)
|
||||
}
|
||||
|
||||
b.HTTPClient = newClient
|
||||
b.API.Endpoints.URL = serverDetails
|
||||
|
||||
log.Printf(sharedtestvalues.MockTesting, b.GetName(), b.API.Endpoints.URL)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
@@ -19,26 +18,22 @@ const (
|
||||
|
||||
var b Binance
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
func areTestAPIKeysSet() bool {
|
||||
return b.ValidateAPICredentials()
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
binanceConfig, err := cfg.GetExchangeConfig("Binance")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Binance Setup() init error")
|
||||
func setFeeBuilder() *exchange.FeeBuilder {
|
||||
return &exchange.FeeBuilder{
|
||||
Amount: 1,
|
||||
FeeType: exchange.CryptocurrencyTradeFee,
|
||||
Pair: currency.NewPair(currency.BTC, currency.LTC),
|
||||
PurchasePrice: 1,
|
||||
}
|
||||
|
||||
binanceConfig.API.AuthenticatedSupport = true
|
||||
binanceConfig.API.Credentials.Key = apiKey
|
||||
binanceConfig.API.Credentials.Secret = apiSecret
|
||||
b.Setup(binanceConfig)
|
||||
}
|
||||
|
||||
func TestFetchTradablePairs(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.FetchTradablePairs(asset.Spot)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Binance FetchTradablePairs(asset asets.AssetType) error", err)
|
||||
@@ -47,6 +42,7 @@ func TestFetchTradablePairs(t *testing.T) {
|
||||
|
||||
func TestGetOrderBook(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetOrderBook(OrderBookDataRequestParams{
|
||||
Symbol: "BTCUSDT",
|
||||
Limit: 10,
|
||||
@@ -72,14 +68,19 @@ func TestGetRecentTrades(t *testing.T) {
|
||||
|
||||
func TestGetHistoricalTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := b.GetHistoricalTrades("BTCUSDT", 5, 1337)
|
||||
if err == nil {
|
||||
|
||||
_, err := b.GetHistoricalTrades("BTCUSDT", 5, 0)
|
||||
if !mockTests && err == nil {
|
||||
t.Error("Test Failed - Binance GetHistoricalTrades() expecting error")
|
||||
}
|
||||
if mockTests && err == nil {
|
||||
t.Error("Test Failed - Binance GetHistoricalTrades() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAggregatedTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetAggregatedTrades("BTCUSDT", 5)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Binance GetAggregatedTrades() error", err)
|
||||
@@ -88,6 +89,7 @@ func TestGetAggregatedTrades(t *testing.T) {
|
||||
|
||||
func TestGetSpotKline(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetSpotKline(KlinesRequestParams{
|
||||
Symbol: "BTCUSDT",
|
||||
Interval: TimeIntervalFiveMinutes,
|
||||
@@ -100,6 +102,7 @@ func TestGetSpotKline(t *testing.T) {
|
||||
|
||||
func TestGetAveragePrice(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetAveragePrice("BTCUSDT")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Binance GetAveragePrice() error", err)
|
||||
@@ -108,6 +111,7 @@ func TestGetAveragePrice(t *testing.T) {
|
||||
|
||||
func TestGetPriceChangeStats(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetPriceChangeStats("BTCUSDT")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Binance GetPriceChangeStats() error", err)
|
||||
@@ -116,6 +120,7 @@ func TestGetPriceChangeStats(t *testing.T) {
|
||||
|
||||
func TestGetTickers(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetTickers()
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Binance TestGetTickers error", err)
|
||||
@@ -124,6 +129,7 @@ func TestGetTickers(t *testing.T) {
|
||||
|
||||
func TestGetLatestSpotPrice(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetLatestSpotPrice("BTCUSDT")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Binance GetLatestSpotPrice() error", err)
|
||||
@@ -132,117 +138,59 @@ func TestGetLatestSpotPrice(t *testing.T) {
|
||||
|
||||
func TestGetBestPrice(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetBestPrice("BTCUSDT")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Binance GetBestPrice() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if apiKey == "" || apiSecret == "" {
|
||||
t.Skip()
|
||||
}
|
||||
_, err := b.NewOrder(&NewOrderRequest{
|
||||
Symbol: "BTCUSDT",
|
||||
Side: exchange.SellOrderSide.ToString(),
|
||||
TradeType: BinanceRequestParamsOrderLimit,
|
||||
TimeInForce: BinanceRequestParamsTimeGTC,
|
||||
Quantity: 0.01,
|
||||
Price: 1536.1,
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
t.Error("Test Failed - Binance NewOrder() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelExistingOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if apiKey == "" || apiSecret == "" {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
_, err := b.CancelExistingOrder("BTCUSDT", 82584683, "")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Binance CancelExistingOrder() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if apiKey == "" || apiSecret == "" {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
_, err := b.QueryOrder("BTCUSDT", "", 1337)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - Binance QueryOrder() error", err)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("Test Failed - QueryOrder() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Test Failed - QueryOrder() expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock QueryOrder() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if apiKey == "" || apiSecret == "" {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
_, err := b.OpenOrders("BTCUSDT")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Binance OpenOrders() error", err)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("Test Failed - OpenOrders() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Test Failed - OpenOrders() expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock OpenOrders() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if apiKey == "" || apiSecret == "" {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
_, err := b.AllOrders("BTCUSDT", "", "")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Binance AllOrders() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccount(t *testing.T) {
|
||||
if apiKey == "" || apiSecret == "" {
|
||||
t.Skip()
|
||||
}
|
||||
t.Parallel()
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
account, err := b.GetAccount()
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - Binance GetAccount() error", err)
|
||||
}
|
||||
if account.MakerCommission <= 0 {
|
||||
t.Fatalf("Test Failed. Expected > 0, Received %d", account.MakerCommission)
|
||||
}
|
||||
if account.TakerCommission <= 0 {
|
||||
t.Fatalf("Test Failed. Expected > 0, Received %d", account.TakerCommission)
|
||||
}
|
||||
|
||||
t.Logf("Current makerFee: %d", account.MakerCommission)
|
||||
t.Logf("Current takerFee: %d", account.TakerCommission)
|
||||
}
|
||||
|
||||
func setFeeBuilder() *exchange.FeeBuilder {
|
||||
return &exchange.FeeBuilder{
|
||||
Amount: 1,
|
||||
FeeType: exchange.CryptocurrencyTradeFee,
|
||||
Pair: currency.NewPair(currency.BTC, currency.LTC),
|
||||
PurchasePrice: 1,
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("Test Failed - AllOrders() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Test Failed - AllOrders() expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock AllOrders() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetFeeByTypeOfflineTradeFee logic test
|
||||
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var feeBuilder = setFeeBuilder()
|
||||
b.GetFeeByType(feeBuilder)
|
||||
if apiKey == "" || apiSecret == "" {
|
||||
@@ -257,12 +205,11 @@ func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetFee(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
var feeBuilder = setFeeBuilder()
|
||||
|
||||
if apiKey != "" || apiSecret != "" {
|
||||
if areTestAPIKeysSet() || mockTests {
|
||||
// CryptocurrencyTradeFee Basic
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0.1) || err != nil {
|
||||
t.Error(err)
|
||||
@@ -332,19 +279,18 @@ func TestGetFee(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFormatWithdrawPermissions(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
t.Parallel()
|
||||
|
||||
expectedResult := exchange.AutoWithdrawCryptoText + " & " + exchange.NoFiatWithdrawalsText
|
||||
|
||||
withdrawPermissions := b.FormatWithdrawPermissions()
|
||||
|
||||
if withdrawPermissions != expectedResult {
|
||||
t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetActiveOrders(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
@@ -359,16 +305,18 @@ func TestGetActiveOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
_, err = b.GetActiveOrders(&getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("Test Failed - GetActiveOrders() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Test Failed - GetActiveOrders() expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock GetActiveOrders() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
@@ -384,125 +332,133 @@ func TestGetOrderHistory(t *testing.T) {
|
||||
currency.BTC)}
|
||||
|
||||
_, err = b.GetOrderHistory(&getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Errorf("Could not get order history: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("Test Failed - GetOrderHistory() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Test Failed - GetOrderHistory() expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock GetOrderHistory() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
func areTestAPIKeysSet() bool {
|
||||
return b.ValidateAPICredentials()
|
||||
}
|
||||
|
||||
func TestSubmitOrder(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
var orderSubmission = &exchange.OrderSubmission{
|
||||
Pair: currency.Pair{
|
||||
Delimiter: "_",
|
||||
Base: currency.BTC,
|
||||
Quote: currency.USD,
|
||||
Base: currency.LTC,
|
||||
Quote: currency.BTC,
|
||||
},
|
||||
OrderSide: exchange.BuyOrderSide,
|
||||
OrderType: exchange.LimitOrderType,
|
||||
OrderType: exchange.MarketOrderType,
|
||||
Price: 1,
|
||||
Amount: 1,
|
||||
Amount: 1000000000,
|
||||
ClientID: "meowOrder",
|
||||
}
|
||||
|
||||
response, err := b.SubmitOrder(orderSubmission)
|
||||
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
|
||||
t.Errorf("Order failed to be placed: %v", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
_, err := b.SubmitOrder(orderSubmission)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("Test Failed - SubmitOrder() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Test Failed - SubmitOrder() expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock SubmitOrder() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelExchangeOrder(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
var orderCancellation = &exchange.OrderCancellation{
|
||||
OrderID: "1",
|
||||
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
AccountID: "1",
|
||||
CurrencyPair: currencyPair,
|
||||
CurrencyPair: currency.NewPair(currency.LTC, currency.BTC),
|
||||
}
|
||||
|
||||
err := b.CancelOrder(orderCancellation)
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("Test Failed - CancelExchangeOrder() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Test Failed - CancelExchangeOrder() expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock CancelExchangeOrder() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
var orderCancellation = &exchange.OrderCancellation{
|
||||
OrderID: "1",
|
||||
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
AccountID: "1",
|
||||
CurrencyPair: currencyPair,
|
||||
CurrencyPair: currency.NewPair(currency.LTC, currency.BTC),
|
||||
}
|
||||
|
||||
resp, err := b.CancelAllOrders(orderCancellation)
|
||||
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Errorf("Could not cancel order: %v", err)
|
||||
}
|
||||
|
||||
if len(resp.OrderStatus) > 0 {
|
||||
t.Errorf("%v orders failed to cancel", len(resp.OrderStatus))
|
||||
_, err := b.CancelAllOrders(orderCancellation)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("Test Failed - CancelAllExchangeOrders() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Test Failed - CancelAllExchangeOrders() expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock CancelAllExchangeOrders() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccountInfo(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
if apiKey == "" || apiSecret == "" {
|
||||
t.Skip()
|
||||
}
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetAccountInfo()
|
||||
if err != nil {
|
||||
t.Error("test failed - GetAccountInfo() error", err)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("Test Failed - GetAccountInfo() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Test Failed - GetAccountInfo() expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock GetAccountInfo() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestModifyOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.ModifyOrder(&exchange.ModifyOrder{})
|
||||
if err == nil {
|
||||
t.Error("Test failed - ModifyOrder() error")
|
||||
t.Error("Test failed - ModifyOrder() error cannot be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
withdrawCryptoRequest := exchange.CryptoWithdrawRequest{
|
||||
GenericWithdrawRequestInfo: exchange.GenericWithdrawRequestInfo{
|
||||
Amount: -1,
|
||||
Amount: 0,
|
||||
Currency: currency.BTC,
|
||||
Description: "WITHDRAW IT ALL",
|
||||
},
|
||||
@@ -510,24 +466,20 @@ func TestWithdraw(t *testing.T) {
|
||||
}
|
||||
|
||||
_, err := b.WithdrawCryptocurrencyFunds(&withdrawCryptoRequest)
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Errorf("Withdraw failed to be placed: %v", err)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("Test Failed - Withdraw() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Test Failed - Withdraw() expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock Withdraw() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawFiat(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
var withdrawFiatRequest = exchange.FiatWithdrawRequest{}
|
||||
t.Parallel()
|
||||
|
||||
var withdrawFiatRequest exchange.FiatWithdrawRequest
|
||||
_, err := b.WithdrawFiatFunds(&withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
|
||||
@@ -535,15 +487,9 @@ func TestWithdrawFiat(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWithdrawInternationalBank(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
var withdrawFiatRequest = exchange.FiatWithdrawRequest{}
|
||||
t.Parallel()
|
||||
|
||||
var withdrawFiatRequest exchange.FiatWithdrawRequest
|
||||
_, err := b.WithdrawFiatFundsToInternationalBank(&withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
|
||||
@@ -551,15 +497,15 @@ func TestWithdrawInternationalBank(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetDepositAddress(t *testing.T) {
|
||||
if areTestAPIKeysSet() {
|
||||
_, err := b.GetDepositAddress(currency.BTC, "")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetDepositAddress() error", err)
|
||||
}
|
||||
} else {
|
||||
_, err := b.GetDepositAddress(currency.BTC, "")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetDepositAddress() error cannot be nil")
|
||||
}
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetDepositAddress(currency.BTC, "")
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("Test Failed - GetDepositAddress() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Test Failed - GetDepositAddress() error cannot be nil")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock GetDepositAddress() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,7 +314,7 @@ type NewOrderResponse struct {
|
||||
Price float64 `json:"price,string"`
|
||||
Qty float64 `json:"qty,string"`
|
||||
Commission float64 `json:"commission,string"`
|
||||
CommissionAsset float64 `json:"commissionAsset,string"`
|
||||
CommissionAsset string `json:"commissionAsset"`
|
||||
} `json:"fills"`
|
||||
}
|
||||
|
||||
@@ -610,5 +610,5 @@ var WithdrawalFees = map[currency.Code]float64{
|
||||
type WithdrawResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Msg string `json:"msg"`
|
||||
ID int64 `json:"id"`
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
@@ -444,9 +444,10 @@ func (b *Binance) GetDepositAddress(cryptocurrency currency.Code, _ string) (str
|
||||
// submitted
|
||||
func (b *Binance) WithdrawCryptocurrencyFunds(withdrawRequest *exchange.CryptoWithdrawRequest) (string, error) {
|
||||
amountStr := strconv.FormatFloat(withdrawRequest.Amount, 'f', -1, 64)
|
||||
id, err := b.WithdrawCrypto(withdrawRequest.Currency.String(), withdrawRequest.Address, withdrawRequest.AddressTag, withdrawRequest.Description, amountStr)
|
||||
|
||||
return strconv.FormatInt(id, 10), err
|
||||
return b.WithdrawCrypto(withdrawRequest.Currency.String(),
|
||||
withdrawRequest.Address,
|
||||
withdrawRequest.AddressTag,
|
||||
withdrawRequest.Description, amountStr)
|
||||
}
|
||||
|
||||
// WithdrawFiatFunds returns a withdrawal ID when a
|
||||
@@ -468,7 +469,7 @@ func (b *Binance) GetWebsocket() (*wshandler.Websocket, error) {
|
||||
|
||||
// GetFeeByType returns an estimate of fee based on type of transaction
|
||||
func (b *Binance) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
if !b.AllowAuthenticatedRequest() && // Todo check connection status
|
||||
if (!b.AllowAuthenticatedRequest() || b.SkipAuthCheck) && // Todo check connection status
|
||||
feeBuilder.FeeType == exchange.CryptocurrencyTradeFee {
|
||||
feeBuilder.FeeType = exchange.OfflineTradeFee
|
||||
}
|
||||
|
||||
@@ -922,7 +922,16 @@ func (b *Bitfinex) CloseMarginFunding(swapID int64) (Offer, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated request
|
||||
func (b *Bitfinex) SendHTTPRequest(path string, result interface{}, verbose bool) error {
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, verbose, b.HTTPDebugging)
|
||||
return b.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
verbose,
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an autheticated http request and json
|
||||
@@ -968,7 +977,8 @@ func (b *Bitfinex) SendAuthenticatedHTTPRequest(method, path string, params map[
|
||||
true,
|
||||
true,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging)
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -306,7 +306,16 @@ func (b *Bitflyer) GetTradingCommission() {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated request
|
||||
func (b *Bitflyer) SendHTTPRequest(path string, result interface{}) error {
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose, b.HTTPDebugging)
|
||||
return b.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthHTTPRequest sends an authenticated HTTP request
|
||||
|
||||
@@ -459,7 +459,16 @@ func (b *Bithumb) MarketSellOrder(currency string, units float64) (MarketSell, e
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (b *Bithumb) SendHTTPRequest(path string, result interface{}) error {
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose, b.HTTPDebugging)
|
||||
return b.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to bithumb
|
||||
@@ -503,7 +512,8 @@ func (b *Bithumb) SendAuthenticatedHTTPRequest(path string, params url.Values, r
|
||||
true,
|
||||
true,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging)
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -775,14 +775,32 @@ func (b *Bitmex) SendHTTPRequest(path string, params Parameter, result interface
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = b.SendPayload(http.MethodGet, encodedPath, nil, nil, &respCheck, false, false, b.Verbose, b.HTTPDebugging)
|
||||
err = b.SendPayload(http.MethodGet,
|
||||
encodedPath,
|
||||
nil,
|
||||
nil,
|
||||
&respCheck,
|
||||
false,
|
||||
false,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.CaptureError(respCheck, result)
|
||||
}
|
||||
}
|
||||
err := b.SendPayload(http.MethodGet, path, nil, nil, &respCheck, false, false, b.Verbose, b.HTTPDebugging)
|
||||
err := b.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
&respCheck,
|
||||
false,
|
||||
false,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -834,7 +852,8 @@ func (b *Bitmex) SendAuthenticatedHTTPRequest(verb, path string, params Paramete
|
||||
true,
|
||||
false,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging)
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package bitstamp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -68,7 +69,6 @@ func (b *Bitstamp) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
switch feeBuilder.FeeType {
|
||||
case exchange.CryptocurrencyTradeFee:
|
||||
var err error
|
||||
|
||||
b.Balance, err = b.GetBalance()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -260,16 +260,15 @@ func (b *Bitstamp) GetEURUSDConversionRate() (EURUSDConversionRate, error) {
|
||||
|
||||
// GetBalance returns full balance of currency held on the exchange
|
||||
func (b *Bitstamp) GetBalance() (Balances, error) {
|
||||
balance := Balances{}
|
||||
path := fmt.Sprintf("%s/%s", b.API.Endpoints.URL, bitstampAPIBalance)
|
||||
|
||||
return balance, b.SendHTTPRequest(path, &balance)
|
||||
var balance Balances
|
||||
return balance,
|
||||
b.SendAuthenticatedHTTPRequest(bitstampAPIBalance, true, nil, &balance)
|
||||
}
|
||||
|
||||
// GetUserTransactions returns an array of transactions
|
||||
func (b *Bitstamp) GetUserTransactions(currencyPair string) ([]UserTransactions, error) {
|
||||
type Response struct {
|
||||
Date int64 `json:"datetime"`
|
||||
Date string `json:"datetime"`
|
||||
TransID int64 `json:"id"`
|
||||
Type int `json:"type,string"`
|
||||
USD interface{} `json:"usd"`
|
||||
@@ -282,12 +281,18 @@ func (b *Bitstamp) GetUserTransactions(currencyPair string) ([]UserTransactions,
|
||||
}
|
||||
var response []Response
|
||||
|
||||
if currencyPair != "" {
|
||||
if err := b.SendAuthenticatedHTTPRequest(bitstampAPIUserTransactions, true, url.Values{}, &response); err != nil {
|
||||
if currencyPair == "" {
|
||||
if err := b.SendAuthenticatedHTTPRequest(bitstampAPIUserTransactions,
|
||||
true,
|
||||
url.Values{},
|
||||
&response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if err := b.SendAuthenticatedHTTPRequest(bitstampAPIUserTransactions+"/"+currencyPair, true, url.Values{}, &response); err != nil {
|
||||
if err := b.SendAuthenticatedHTTPRequest(bitstampAPIUserTransactions+"/"+currencyPair,
|
||||
true,
|
||||
url.Values{},
|
||||
&response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -383,10 +388,11 @@ func (b *Bitstamp) PlaceOrder(currencyPair string, price, amount float64, buy, m
|
||||
orderType = exchange.SellOrderSide.ToLower().ToString()
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s/%s", orderType, strings.ToLower(currencyPair))
|
||||
|
||||
var path string
|
||||
if market {
|
||||
path = fmt.Sprintf("%s/%s/%s", orderType, bitstampAPIMarket, strings.ToLower(currencyPair))
|
||||
} else {
|
||||
path = fmt.Sprintf("%s/%s", orderType, strings.ToLower(currencyPair))
|
||||
}
|
||||
|
||||
return response,
|
||||
@@ -546,28 +552,41 @@ func (b *Bitstamp) GetUnconfirmedBitcoinDeposits() ([]UnconfirmedBTCTransactions
|
||||
// currency - which currency to transfer
|
||||
// subaccount - name of account
|
||||
// toMain - bool either to or from account
|
||||
func (b *Bitstamp) TransferAccountBalance(amount float64, currency, subAccount string, toMain bool) (bool, error) {
|
||||
func (b *Bitstamp) TransferAccountBalance(amount float64, currency, subAccount string, toMain bool) error {
|
||||
var req = url.Values{}
|
||||
req.Add("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
req.Add("currency", currency)
|
||||
|
||||
if subAccount == "" {
|
||||
return errors.New("missing subAccount parameter")
|
||||
}
|
||||
|
||||
req.Add("subAccount", subAccount)
|
||||
|
||||
path := bitstampAPITransferToMain
|
||||
if !toMain {
|
||||
var path string
|
||||
if toMain {
|
||||
path = bitstampAPITransferToMain
|
||||
} else {
|
||||
path = bitstampAPITransferFromMain
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(path, true, req, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
var resp interface{}
|
||||
|
||||
return true, nil
|
||||
return b.SendAuthenticatedHTTPRequest(path, true, req, &resp)
|
||||
}
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (b *Bitstamp) SendHTTPRequest(path string, result interface{}) error {
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose, b.HTTPDebugging)
|
||||
return b.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated request
|
||||
@@ -603,15 +622,26 @@ func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, v2 bool, values url
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
|
||||
encodedValues := values.Encode()
|
||||
readerValues := strings.NewReader(encodedValues)
|
||||
readerValues := bytes.NewBufferString(encodedValues)
|
||||
|
||||
interim := json.RawMessage{}
|
||||
|
||||
errCap := struct {
|
||||
Error string `json:"error"`
|
||||
Error string `json:"error"`
|
||||
Status string `json:"status"`
|
||||
Reason interface{} `json:"reason"`
|
||||
}{}
|
||||
|
||||
err := b.SendPayload(http.MethodPost, path, headers, readerValues, &interim, true, true, b.Verbose, b.HTTPDebugging)
|
||||
err := b.SendPayload(http.MethodPost,
|
||||
path,
|
||||
headers,
|
||||
readerValues,
|
||||
&interim,
|
||||
true,
|
||||
true,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -620,6 +650,21 @@ func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, v2 bool, values url
|
||||
if errCap.Error != "" {
|
||||
return errors.New(errCap.Error)
|
||||
}
|
||||
if data, ok := errCap.Reason.(map[string][]string); ok {
|
||||
var details string
|
||||
for _, v := range data {
|
||||
details += strings.Join(v, "")
|
||||
}
|
||||
return errors.New(details)
|
||||
}
|
||||
|
||||
if data, ok := errCap.Reason.(string); ok {
|
||||
return errors.New(data)
|
||||
}
|
||||
|
||||
if errCap.Status != "" {
|
||||
return errors.New(errCap.Status)
|
||||
}
|
||||
}
|
||||
|
||||
return common.JSONDecode(interim, result)
|
||||
|
||||
33
exchanges/bitstamp/bitstamp_live_test.go
Normal file
33
exchanges/bitstamp/bitstamp_live_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
//+build mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is parsed and will do live testing
|
||||
// using all tests in (exchange)_test.go
|
||||
package bitstamp
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
var mockTests = false
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
bitstampConfig, err := cfg.GetExchangeConfig("Bitstamp")
|
||||
if err != nil {
|
||||
log.Fatal("Test Failed - Bitstamp Setup() init error", err)
|
||||
}
|
||||
bitstampConfig.API.AuthenticatedSupport = true
|
||||
bitstampConfig.API.Credentials.Key = apiKey
|
||||
bitstampConfig.API.Credentials.Secret = apiSecret
|
||||
bitstampConfig.API.Credentials.ClientID = customerID
|
||||
b.SetDefaults()
|
||||
b.Setup(bitstampConfig)
|
||||
log.Printf(sharedtestvalues.LiveTesting, b.GetName(), b.API.Endpoints.URL)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
46
exchanges/bitstamp/bitstamp_mock_test.go
Normal file
46
exchanges/bitstamp/bitstamp_mock_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
//+build !mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is not parsed and will try to mock
|
||||
// all tests in _test.go
|
||||
package bitstamp
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/mock"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
const mockfile = "../../testdata/http_mock/bitstamp/bitstamp.json"
|
||||
|
||||
var mockTests = true
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
bitstampConfig, err := cfg.GetExchangeConfig("Bitstamp")
|
||||
if err != nil {
|
||||
log.Fatal("Test Failed - Bitstamp Setup() init error", err)
|
||||
}
|
||||
b.SkipAuthCheck = true
|
||||
bitstampConfig.API.AuthenticatedSupport = true
|
||||
bitstampConfig.API.Credentials.Key = apiKey
|
||||
bitstampConfig.API.Credentials.Secret = apiSecret
|
||||
bitstampConfig.API.Credentials.ClientID = customerID
|
||||
b.SetDefaults()
|
||||
b.Setup(bitstampConfig)
|
||||
|
||||
serverDetails, newClient, err := mock.NewVCRServer(mockfile)
|
||||
if err != nil {
|
||||
log.Fatalf("Test Failed - Mock server error %s", err)
|
||||
}
|
||||
|
||||
b.HTTPClient = newClient
|
||||
b.API.Endpoints.URL = serverDetails + "/api"
|
||||
|
||||
log.Printf(sharedtestvalues.MockTesting, b.GetName(), b.API.Endpoints.URL)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
)
|
||||
@@ -19,40 +18,8 @@ const (
|
||||
|
||||
var b Bitstamp
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
|
||||
if b.Name != "Bitstamp" {
|
||||
t.Error("Test Failed - SetDefaults() error")
|
||||
}
|
||||
if !b.Enabled {
|
||||
t.Error("Test Failed - SetDefaults() error")
|
||||
}
|
||||
if !b.Verbose {
|
||||
t.Error("Test Failed - SetDefaults() error")
|
||||
}
|
||||
if b.Websocket.IsEnabled() {
|
||||
t.Error("Test Failed - SetDefaults() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
bConfig, err := cfg.GetExchangeConfig("Bitstamp")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Bitstamp Setup() init error")
|
||||
}
|
||||
bConfig.API.Credentials.Key = apiKey
|
||||
bConfig.API.Credentials.Secret = apiSecret
|
||||
bConfig.API.Credentials.ClientID = customerID
|
||||
|
||||
b.Setup(bConfig)
|
||||
|
||||
if !b.IsEnabled() || b.API.AuthenticatedSupport ||
|
||||
b.Verbose || b.Websocket.IsEnabled() || len(b.BaseCurrencies) < 1 {
|
||||
t.Error("Test Failed - Bitstamp Setup values not set correctly")
|
||||
}
|
||||
func areTestAPIKeysSet() bool {
|
||||
return b.ValidateAPICredentials()
|
||||
}
|
||||
|
||||
func setFeeBuilder() *exchange.FeeBuilder {
|
||||
@@ -66,53 +33,66 @@ func setFeeBuilder() *exchange.FeeBuilder {
|
||||
|
||||
// TestGetFeeByTypeOfflineTradeFee logic test
|
||||
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var feeBuilder = setFeeBuilder()
|
||||
b.GetFeeByType(feeBuilder)
|
||||
if apiKey == "" || apiSecret == "" {
|
||||
if feeBuilder.FeeType != exchange.OfflineTradeFee {
|
||||
t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType)
|
||||
t.Errorf("Expected %v, received %v",
|
||||
exchange.OfflineTradeFee,
|
||||
feeBuilder.FeeType)
|
||||
}
|
||||
} else {
|
||||
if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee {
|
||||
t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType)
|
||||
t.Errorf("Expected %v, received %v",
|
||||
exchange.CryptocurrencyTradeFee,
|
||||
feeBuilder.FeeType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFee(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
var feeBuilder = setFeeBuilder()
|
||||
|
||||
// CryptocurrencyTradeFee Basic
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || (areTestAPIKeysSet() && err != nil) {
|
||||
t.Error(err)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0),
|
||||
resp)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee High quantity
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.Amount = 1000
|
||||
feeBuilder.PurchasePrice = 1000
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || (areTestAPIKeysSet() && err != nil) {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0),
|
||||
resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee IsMaker
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.IsMaker = true
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || (areTestAPIKeysSet() && err != nil) {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0),
|
||||
resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee Negative purchase price
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.PurchasePrice = -1000
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || (areTestAPIKeysSet() && err != nil) {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0),
|
||||
resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -120,7 +100,9 @@ func TestGetFee(t *testing.T) {
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0),
|
||||
resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -128,7 +110,9 @@ func TestGetFee(t *testing.T) {
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.CyptocurrencyDepositFee
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0),
|
||||
resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -137,7 +121,9 @@ func TestGetFee(t *testing.T) {
|
||||
feeBuilder.FeeType = exchange.InternationalBankDepositFee
|
||||
feeBuilder.FiatCurrency = currency.HKD
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(7.5) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(7.5), resp)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(7.5),
|
||||
resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -146,15 +132,15 @@ func TestGetFee(t *testing.T) {
|
||||
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
|
||||
feeBuilder.FiatCurrency = currency.HKD
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(15) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(15), resp)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(15),
|
||||
resp)
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculateTradingFee(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
b.Balance = Balances{}
|
||||
t.Parallel()
|
||||
b.Balance.BTCUSDFee = 1
|
||||
b.Balance.BTCEURFee = 0
|
||||
|
||||
@@ -176,18 +162,16 @@ func TestCalculateTradingFee(t *testing.T) {
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetTicker(currency.BTC.String()+currency.USD.String(), false)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetTicker() error", err)
|
||||
}
|
||||
_, err = b.GetTicker(currency.BTC.String()+currency.USD.String(), true)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetTicker() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetOrderbook(currency.BTC.String() + currency.USD.String())
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetOrderbook() error", err)
|
||||
@@ -196,6 +180,7 @@ func TestGetOrderbook(t *testing.T) {
|
||||
|
||||
func TestGetTradingPairs(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetTradingPairs()
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetTradingPairs() error", err)
|
||||
@@ -204,6 +189,7 @@ func TestGetTradingPairs(t *testing.T) {
|
||||
|
||||
func TestGetTransactions(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
value := url.Values{}
|
||||
value.Set("time", "hour")
|
||||
|
||||
@@ -211,14 +197,11 @@ func TestGetTransactions(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetTransactions() error", err)
|
||||
}
|
||||
_, err = b.GetTransactions("wigwham", value)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetTransactions() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEURUSDConversionRate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetEURUSDConversionRate()
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetEURUSDConversionRate() error", err)
|
||||
@@ -227,21 +210,28 @@ func TestGetEURUSDConversionRate(t *testing.T) {
|
||||
|
||||
func TestGetBalance(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetBalance()
|
||||
if err != nil {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Error("Test Failed - GetBalance() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - GetBalance() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUserTransactions(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := b.GetUserTransactions("")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetUserTransactions() error", err)
|
||||
}
|
||||
|
||||
_, err = b.GetUserTransactions("btcusd")
|
||||
if err == nil {
|
||||
_, err := b.GetUserTransactions("btcusd")
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Error("Test Failed - GetUserTransactions() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - GetUserTransactions() error", err)
|
||||
}
|
||||
}
|
||||
@@ -250,54 +240,27 @@ func TestGetOpenOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetOpenOrders("btcusd")
|
||||
if err == nil {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Error("Test Failed - GetOpenOrders() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - GetOpenOrders() error", err)
|
||||
}
|
||||
_, err = b.GetOpenOrders("wigwham")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetOpenOrders() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderStatus(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !b.ValidateAPICredentials() {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
_, err := b.GetOrderStatus(1337)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetOpenOrders() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelExistingOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
resp, err := b.CancelExistingOrder(1337)
|
||||
if err == nil || resp {
|
||||
t.Error("Test Failed - CancelExistingOrder() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelAllExistingOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.CancelAllExistingOrders()
|
||||
if err == nil {
|
||||
t.Error("Test Failed - CancelAllExistingOrders() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlaceOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !b.ValidateAPICredentials() {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
_, err := b.PlaceOrder("btcusd", 0.01, 1, true, true)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - PlaceOrder() error")
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Error("Test Failed - GetOrderStatus() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err == nil:
|
||||
t.Error("Expecting an error until a QA pass can be completed")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,33 +268,13 @@ func TestGetWithdrawalRequests(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetWithdrawalRequests(0)
|
||||
if err == nil {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Error("Test Failed - GetWithdrawalRequests() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - GetWithdrawalRequests() error", err)
|
||||
}
|
||||
_, err = b.GetWithdrawalRequests(-1)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetWithdrawalRequests() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCryptoWithdrawal(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !b.ValidateAPICredentials() {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
_, err := b.CryptoWithdrawal(0, "bla", "btc", "", true)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - CryptoWithdrawal() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBitcoinDepositAddress(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetCryptoDepositAddress(currency.BTC)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetCryptoDepositAddress() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,81 +282,90 @@ func TestGetUnconfirmedBitcoinDeposits(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetUnconfirmedBitcoinDeposits()
|
||||
if err == nil {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Error("Test Failed - GetUnconfirmedBitcoinDeposits() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - GetUnconfirmedBitcoinDeposits() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransferAccountBalance(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !b.ValidateAPICredentials() {
|
||||
|
||||
if !areTestAPIKeysSet() && !mockTests {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
_, err := b.TransferAccountBalance(1, "", "", true)
|
||||
if err == nil {
|
||||
err := b.TransferAccountBalance(0.01, "btc", "testAccount", true)
|
||||
if !mockTests && err != nil {
|
||||
t.Error("Test Failed - TransferAccountBalance() error", err)
|
||||
}
|
||||
|
||||
_, err = b.TransferAccountBalance(1, "btc", "", false)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - TransferAccountBalance() error", err)
|
||||
if mockTests && err == nil {
|
||||
t.Error("Expecting an error until a QA pass can be completed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatWithdrawPermissions(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
expectedResult := exchange.AutoWithdrawCryptoText + " & " + exchange.AutoWithdrawFiatText
|
||||
t.Parallel()
|
||||
|
||||
expectedResult := exchange.AutoWithdrawCryptoText +
|
||||
" & " +
|
||||
exchange.AutoWithdrawFiatText
|
||||
|
||||
withdrawPermissions := b.FormatWithdrawPermissions()
|
||||
|
||||
if withdrawPermissions != expectedResult {
|
||||
t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions)
|
||||
t.Errorf("Expected: %s, Received: %s",
|
||||
expectedResult,
|
||||
withdrawPermissions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetActiveOrders(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
}
|
||||
|
||||
_, err := b.GetActiveOrders(&getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
}
|
||||
|
||||
_, err := b.GetOrderHistory(&getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not get order history: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not get order history: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
func areTestAPIKeysSet() bool {
|
||||
return b.ValidateAPICredentials()
|
||||
}
|
||||
|
||||
func TestSubmitOrder(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Parallel()
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
@@ -429,18 +381,20 @@ func TestSubmitOrder(t *testing.T) {
|
||||
ClientID: "meowOrder",
|
||||
}
|
||||
response, err := b.SubmitOrder(orderSubmission)
|
||||
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) && !mockTests:
|
||||
t.Errorf("Order failed to be placed: %v", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err == nil:
|
||||
t.Error("Expecting an error until QA pass is completed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelExchangeOrder(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
@@ -454,19 +408,20 @@ func TestCancelExchangeOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
err := b.CancelOrder(orderCancellation)
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
switch {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
case mockTests && err == nil:
|
||||
t.Error("Expecting an error until QA pass is completed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
@@ -480,11 +435,12 @@ func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
resp, err := b.CancelAllOrders(orderCancellation)
|
||||
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
switch {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
}
|
||||
|
||||
@@ -494,6 +450,8 @@ func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestModifyOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.ModifyOrder(&exchange.ModifyOrder{})
|
||||
if err == nil {
|
||||
t.Error("Test failed - ModifyOrder() error")
|
||||
@@ -501,8 +459,11 @@ func TestModifyOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
withdrawCryptoRequest := exchange.CryptoWithdrawRequest{
|
||||
GenericWithdrawRequestInfo: exchange.GenericWithdrawRequestInfo{
|
||||
@@ -513,24 +474,21 @@ func TestWithdraw(t *testing.T) {
|
||||
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
}
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
_, err := b.WithdrawCryptocurrencyFunds(&withdrawCryptoRequest)
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
switch {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Withdraw failed to be placed: %v", err)
|
||||
case mockTests && err == nil:
|
||||
t.Error("Expecting an error until QA pass is completed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawFiat(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
@@ -555,19 +513,20 @@ func TestWithdrawFiat(t *testing.T) {
|
||||
}
|
||||
|
||||
_, err := b.WithdrawFiatFunds(&withdrawFiatRequest)
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
switch {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Withdraw failed to be placed: %v", err)
|
||||
case mockTests && err == nil:
|
||||
t.Error("Expecting an error until QA pass is completed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawInternationalBank(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
@@ -598,24 +557,26 @@ func TestWithdrawInternationalBank(t *testing.T) {
|
||||
}
|
||||
|
||||
_, err := b.WithdrawFiatFundsToInternationalBank(&withdrawFiatRequest)
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
switch {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Withdraw failed to be placed: %v", err)
|
||||
case mockTests && err == nil:
|
||||
t.Error("Expecting an error until QA pass is completed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDepositAddress(t *testing.T) {
|
||||
if areTestAPIKeysSet() && customerID != "" {
|
||||
_, err := b.GetDepositAddress(currency.BTC, "")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetDepositAddress error", err)
|
||||
}
|
||||
} else {
|
||||
_, err := b.GetDepositAddress(currency.BTC, "")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetDepositAddress error cannot be nil")
|
||||
}
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetDepositAddress(currency.BTC, "")
|
||||
switch {
|
||||
case areTestAPIKeysSet() && customerID != "" && err != nil && !mockTests:
|
||||
t.Error("Test Failed - GetDepositAddress error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Test Failed - GetDepositAddress error cannot be nil")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - GetDepositAddress error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ type Balances struct {
|
||||
|
||||
// UserTransactions holds user transaction information
|
||||
type UserTransactions struct {
|
||||
Date int64 `json:"datetime"`
|
||||
Date string `json:"datetime"`
|
||||
TransID int64 `json:"id"`
|
||||
Type int `json:"type,string"`
|
||||
USD float64 `json:"usd"`
|
||||
@@ -125,15 +125,15 @@ type WithdrawalRequests struct {
|
||||
|
||||
// CryptoWithdrawalResponse response from a crypto withdrawal request
|
||||
type CryptoWithdrawalResponse struct {
|
||||
ID string `json:"id"`
|
||||
Error string `json:"error"`
|
||||
ID string `json:"id"`
|
||||
Error map[string][]string `json:"error"`
|
||||
}
|
||||
|
||||
// FIATWithdrawalResponse response from a fiat withdrawal request
|
||||
type FIATWithdrawalResponse struct {
|
||||
ID string `json:"id"`
|
||||
Status string `json:"status"`
|
||||
Reason string `json:"reason"`
|
||||
ID string `json:"id"`
|
||||
Status string `json:"status"`
|
||||
Reason map[string][]string `json:"reason"`
|
||||
}
|
||||
|
||||
// UnconfirmedBTCTransactions holds address information about unconfirmed
|
||||
|
||||
@@ -235,7 +235,7 @@ func (b *Bitstamp) FetchTicker(p currency.Pair, assetType asset.Item) (ticker.Pr
|
||||
|
||||
// GetFeeByType returns an estimate of fee based on type of transaction
|
||||
func (b *Bitstamp) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
if !b.AllowAuthenticatedRequest() && // Todo check connection status
|
||||
if (!b.AllowAuthenticatedRequest() || b.SkipAuthCheck) && // Todo check connection status
|
||||
feeBuilder.FeeType == exchange.CryptocurrencyTradeFee {
|
||||
feeBuilder.FeeType = exchange.OfflineTradeFee
|
||||
}
|
||||
@@ -409,8 +409,12 @@ func (b *Bitstamp) WithdrawCryptocurrencyFunds(withdrawRequest *exchange.CryptoW
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if resp.Error != "" {
|
||||
return "", errors.New(resp.Error)
|
||||
if len(resp.Error) != 0 {
|
||||
var details string
|
||||
for _, v := range resp.Error {
|
||||
details += strings.Join(v, "")
|
||||
}
|
||||
return "", errors.New(details)
|
||||
}
|
||||
|
||||
return resp.ID, nil
|
||||
@@ -427,7 +431,11 @@ func (b *Bitstamp) WithdrawFiatFunds(withdrawRequest *exchange.FiatWithdrawReque
|
||||
return "", err
|
||||
}
|
||||
if resp.Status == errStr {
|
||||
return "", errors.New(resp.Reason)
|
||||
var details string
|
||||
for _, v := range resp.Reason {
|
||||
details += strings.Join(v, "")
|
||||
}
|
||||
return "", errors.New(details)
|
||||
}
|
||||
|
||||
return resp.ID, nil
|
||||
@@ -446,7 +454,11 @@ func (b *Bitstamp) WithdrawFiatFundsToInternationalBank(withdrawRequest *exchang
|
||||
return "", err
|
||||
}
|
||||
if resp.Status == errStr {
|
||||
return "", errors.New(resp.Reason)
|
||||
var details string
|
||||
for _, v := range resp.Reason {
|
||||
details += strings.Join(v, "")
|
||||
}
|
||||
return "", errors.New(details)
|
||||
}
|
||||
|
||||
return resp.ID, nil
|
||||
@@ -533,7 +545,12 @@ func (b *Bitstamp) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest)
|
||||
quoteCurrency.String(),
|
||||
b.GetPairFormat(asset.Spot, false).Delimiter)
|
||||
}
|
||||
orderDate := time.Unix(order.Date, 0)
|
||||
|
||||
orderDate, err := time.Parse("2006-01-02 15:04:05", order.Date)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orders = append(orders, exchange.OrderDetail{
|
||||
ID: fmt.Sprintf("%v", order.OrderID),
|
||||
OrderDate: orderDate,
|
||||
|
||||
@@ -427,7 +427,16 @@ func (b *Bittrex) GetDepositHistory(currency string) (WithdrawalHistory, error)
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (b *Bittrex) SendHTTPRequest(path string, result interface{}) error {
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose, b.HTTPDebugging)
|
||||
return b.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated http request to a desired
|
||||
@@ -448,7 +457,16 @@ func (b *Bittrex) SendAuthenticatedHTTPRequest(path string, values url.Values, r
|
||||
headers := make(map[string]string)
|
||||
headers["apisign"] = crypto.HexEncodeToString(hmac)
|
||||
|
||||
return b.SendPayload(http.MethodGet, rawQuery, headers, nil, result, true, true, b.Verbose, b.HTTPDebugging)
|
||||
return b.SendPayload(http.MethodGet,
|
||||
rawQuery,
|
||||
headers,
|
||||
nil,
|
||||
result,
|
||||
true,
|
||||
true,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -364,7 +364,16 @@ func (b *BTCMarkets) WithdrawAUD(accountName, accountNumber, bankName, bsbNumber
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (b *BTCMarkets) SendHTTPRequest(path string, result interface{}) error {
|
||||
return b.SendPayload(http.MethodGet, path, nil, nil, result, false, false, b.Verbose, b.HTTPDebugging)
|
||||
return b.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedRequest sends an authenticated HTTP request
|
||||
@@ -415,7 +424,8 @@ func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data, result
|
||||
true,
|
||||
true,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging)
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -176,8 +176,16 @@ func (b *BTSE) GetFills(orderID, productID, before, after, limit string) (*Fille
|
||||
|
||||
// SendHTTPRequest sends an HTTP request to the desired endpoint
|
||||
func (b *BTSE) SendHTTPRequest(method, endpoint string, result interface{}) error {
|
||||
p := fmt.Sprintf("%s/%s", b.API.Endpoints.URL, endpoint)
|
||||
return b.SendPayload(method, p, nil, nil, &result, false, false, b.Verbose, b.HTTPDebugging)
|
||||
return b.SendPayload(method,
|
||||
fmt.Sprintf("%s/%s", b.API.Endpoints.URL, endpoint),
|
||||
nil,
|
||||
nil,
|
||||
&result,
|
||||
false,
|
||||
false,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to the desired endpoint
|
||||
@@ -203,8 +211,16 @@ func (b *BTSE) SendAuthenticatedHTTPRequest(method, endpoint string, req map[str
|
||||
if b.Verbose {
|
||||
log.Debugf(log.ExchangeSys, "Sending %s request to URL %s with params %s\n", method, p, string(payload))
|
||||
}
|
||||
return b.SendPayload(method, p, headers, strings.NewReader(string(payload)),
|
||||
&result, true, false, b.Verbose, b.HTTPDebugging)
|
||||
return b.SendPayload(method,
|
||||
p,
|
||||
headers,
|
||||
strings.NewReader(string(payload)),
|
||||
&result,
|
||||
true,
|
||||
false,
|
||||
b.Verbose,
|
||||
b.HTTPDebugging,
|
||||
b.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -710,7 +710,16 @@ func (c *CoinbasePro) GetTrailingVolume() ([]Volume, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (c *CoinbasePro) SendHTTPRequest(path string, result interface{}) error {
|
||||
return c.SendPayload(http.MethodGet, path, nil, nil, result, false, false, c.Verbose, c.HTTPDebugging)
|
||||
return c.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
c.Verbose,
|
||||
c.HTTPDebugging,
|
||||
c.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP reque
|
||||
@@ -751,7 +760,8 @@ func (c *CoinbasePro) SendAuthenticatedHTTPRequest(method, path string, params m
|
||||
true,
|
||||
true,
|
||||
c.Verbose,
|
||||
c.HTTPDebugging)
|
||||
c.HTTPDebugging,
|
||||
c.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -295,7 +295,7 @@ func (c *COINUT) SendHTTPRequest(apiRequest string, params map[string]interface{
|
||||
true,
|
||||
c.Verbose,
|
||||
c.HTTPDebugging,
|
||||
)
|
||||
c.HTTPRecording)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -462,6 +462,11 @@ func (e *Base) SetupDefaults(exch *config.ExchangeConfig) error {
|
||||
// AllowAuthenticatedRequest checks to see if the required fields have been set before sending an authenticated
|
||||
// API request
|
||||
func (e *Base) AllowAuthenticatedRequest() bool {
|
||||
// Skip auth check
|
||||
if e.SkipAuthCheck {
|
||||
return true
|
||||
}
|
||||
|
||||
// Individual package usage, allow request if API credentials are valid a
|
||||
// and without needing to set AuthenticatedSupport to true
|
||||
if !e.LoadedByConfig && !e.ValidateAPICredentials() {
|
||||
|
||||
@@ -304,12 +304,14 @@ type Base struct {
|
||||
Enabled bool
|
||||
Verbose bool
|
||||
LoadedByConfig bool
|
||||
SkipAuthCheck bool
|
||||
API API
|
||||
BaseCurrencies currency.Currencies
|
||||
CurrencyPairs currency.PairsManager
|
||||
Features Features
|
||||
HTTPTimeout time.Duration
|
||||
HTTPUserAgent string
|
||||
HTTPRecording bool
|
||||
HTTPDebugging bool
|
||||
WebsocketResponseCheckTimeout time.Duration
|
||||
WebsocketResponseMaxLimit time.Duration
|
||||
|
||||
@@ -302,7 +302,16 @@ func (e *EXMO) GetWalletHistory(date int64) (WalletHistory, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (e *EXMO) SendHTTPRequest(path string, result interface{}) error {
|
||||
return e.SendPayload(http.MethodGet, path, nil, nil, result, false, false, e.Verbose, e.HTTPDebugging)
|
||||
return e.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
e.Verbose,
|
||||
e.HTTPDebugging,
|
||||
e.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request
|
||||
@@ -342,7 +351,8 @@ func (e *EXMO) SendAuthenticatedHTTPRequest(method, endpoint string, vals url.Va
|
||||
true,
|
||||
true,
|
||||
e.Verbose,
|
||||
e.HTTPDebugging)
|
||||
e.HTTPDebugging,
|
||||
e.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -306,7 +306,16 @@ func (g *Gateio) CancelExistingOrder(orderID int64, symbol string) (bool, error)
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (g *Gateio) SendHTTPRequest(path string, result interface{}) error {
|
||||
return g.SendPayload(http.MethodGet, path, nil, nil, result, false, false, g.Verbose, g.HTTPDebugging)
|
||||
return g.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
g.Verbose,
|
||||
g.HTTPDebugging,
|
||||
g.HTTPRecording)
|
||||
}
|
||||
|
||||
// CancelAllExistingOrders all orders for a given symbol and side
|
||||
@@ -407,7 +416,8 @@ func (g *Gateio) SendAuthenticatedHTTPRequest(method, endpoint, param string, re
|
||||
true,
|
||||
false,
|
||||
g.Verbose,
|
||||
g.HTTPDebugging)
|
||||
g.HTTPDebugging,
|
||||
g.HTTPRecording)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -53,11 +53,6 @@ const (
|
||||
geminiRoleFundManager = "fundmanager"
|
||||
)
|
||||
|
||||
var (
|
||||
// Session manager
|
||||
Session map[int]*Gemini
|
||||
)
|
||||
|
||||
// Gemini is the overarching type across the Gemini package, create multiple
|
||||
// instances with differing APIkeys for segregation of roles for authenticated
|
||||
// requests & sessions by appending new sessions to the Session map using
|
||||
@@ -71,31 +66,6 @@ type Gemini struct {
|
||||
RequiresHeartBeat bool
|
||||
}
|
||||
|
||||
// AddSession adds a new session to the gemini base
|
||||
func AddSession(g *Gemini, sessionID int, apiKey, apiSecret, role string, needsHeartbeat, isSandbox bool) error {
|
||||
if Session == nil {
|
||||
Session = make(map[int]*Gemini)
|
||||
}
|
||||
|
||||
_, ok := Session[sessionID]
|
||||
if ok {
|
||||
return errors.New("sessionID already being used")
|
||||
}
|
||||
|
||||
g.API.Credentials.Key = apiKey
|
||||
g.API.Credentials.Secret = apiSecret
|
||||
g.Role = role
|
||||
g.RequiresHeartBeat = needsHeartbeat
|
||||
g.API.Endpoints.URL = geminiAPIURL
|
||||
|
||||
if isSandbox {
|
||||
g.API.Endpoints.URL = geminiSandboxAPIURL
|
||||
}
|
||||
|
||||
Session[sessionID] = g
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSymbols returns all available symbols for trading
|
||||
func (g *Gemini) GetSymbols() ([]string, error) {
|
||||
var symbols []string
|
||||
@@ -155,9 +125,15 @@ func (g *Gemini) GetTicker(currencyPair string) (Ticker, error) {
|
||||
// params - limit_bids or limit_asks [OPTIONAL] default 50, 0 returns all Values
|
||||
// Type is an integer ie "params.Set("limit_asks", 30)"
|
||||
func (g *Gemini) GetOrderbook(currencyPair string, params url.Values) (Orderbook, error) {
|
||||
path := common.EncodeURLValues(fmt.Sprintf("%s/v%s/%s/%s", g.API.Endpoints.URL, geminiAPIVersion, geminiOrderbook, currencyPair), params)
|
||||
orderbook := Orderbook{}
|
||||
path := common.EncodeURLValues(
|
||||
fmt.Sprintf("%s/v%s/%s/%s",
|
||||
g.API.Endpoints.URL,
|
||||
geminiAPIVersion,
|
||||
geminiOrderbook,
|
||||
currencyPair),
|
||||
params)
|
||||
|
||||
var orderbook Orderbook
|
||||
return orderbook, g.SendHTTPRequest(path, &orderbook)
|
||||
}
|
||||
|
||||
@@ -202,20 +178,9 @@ func (g *Gemini) GetAuctionHistory(currencyPair string, params url.Values) ([]Au
|
||||
return auctionHist, g.SendHTTPRequest(path, &auctionHist)
|
||||
}
|
||||
|
||||
func (g *Gemini) isCorrectSession() error {
|
||||
if g.Role != geminiRoleTrader {
|
||||
return errors.New("incorrect role for APIKEY cannot use this function")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewOrder Only limit orders are supported through the API at present.
|
||||
// returns order ID if successful
|
||||
func (g *Gemini) NewOrder(symbol string, amount, price float64, side, orderType string) (int64, error) {
|
||||
if err := g.isCorrectSession(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
req := make(map[string]interface{})
|
||||
req["symbol"] = symbol
|
||||
req["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
|
||||
@@ -300,6 +265,7 @@ func (g *Gemini) GetOrders() ([]Order, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch r := response.(type) {
|
||||
case orders:
|
||||
return r.orders, nil
|
||||
@@ -317,7 +283,7 @@ func (g *Gemini) GetTradeHistory(currencyPair string, timestamp int64) ([]TradeH
|
||||
req := make(map[string]interface{})
|
||||
req["symbol"] = currencyPair
|
||||
|
||||
if timestamp != 0 {
|
||||
if timestamp > 0 {
|
||||
req["timestamp"] = timestamp
|
||||
}
|
||||
|
||||
@@ -406,7 +372,16 @@ func (g *Gemini) PostHeartbeat() (string, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated request
|
||||
func (g *Gemini) SendHTTPRequest(path string, result interface{}) error {
|
||||
return g.SendPayload(http.MethodGet, path, nil, nil, result, false, false, g.Verbose, g.HTTPDebugging)
|
||||
return g.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
g.Verbose,
|
||||
g.HTTPDebugging,
|
||||
g.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to the
|
||||
@@ -416,7 +391,6 @@ func (g *Gemini) SendAuthenticatedHTTPRequest(method, path string, params map[st
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, g.Name)
|
||||
}
|
||||
|
||||
headers := make(map[string]string)
|
||||
req := make(map[string]interface{})
|
||||
req["request"] = fmt.Sprintf("/v%s/%s", geminiAPIVersion, path)
|
||||
req["nonce"] = g.Requester.GetNonce(true).String()
|
||||
@@ -437,6 +411,7 @@ func (g *Gemini) SendAuthenticatedHTTPRequest(method, path string, params map[st
|
||||
PayloadBase64 := crypto.Base64Encode(PayloadJSON)
|
||||
hmac := crypto.GetHMAC(crypto.HashSHA512_384, []byte(PayloadBase64), []byte(g.API.Credentials.Secret))
|
||||
|
||||
headers := make(map[string]string)
|
||||
headers["Content-Length"] = "0"
|
||||
headers["Content-Type"] = "text/plain"
|
||||
headers["X-GEMINI-APIKEY"] = g.API.Credentials.Key
|
||||
@@ -444,8 +419,16 @@ func (g *Gemini) SendAuthenticatedHTTPRequest(method, path string, params map[st
|
||||
headers["X-GEMINI-SIGNATURE"] = crypto.HexEncodeToString(hmac)
|
||||
headers["Cache-Control"] = "no-cache"
|
||||
|
||||
return g.SendPayload(method, g.API.Endpoints.URL+"/v1/"+path, headers,
|
||||
strings.NewReader(""), result, true, false, g.Verbose, g.HTTPDebugging)
|
||||
return g.SendPayload(method,
|
||||
g.API.Endpoints.URL+"/v1/"+path,
|
||||
headers,
|
||||
nil,
|
||||
result,
|
||||
true,
|
||||
false,
|
||||
g.Verbose,
|
||||
g.HTTPDebugging,
|
||||
g.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
@@ -481,9 +464,9 @@ func getOfflineTradeFee(price, amount float64) float64 {
|
||||
func calculateTradingFee(notionVolume *NotionalVolume, purchasePrice, amount float64, isMaker bool) float64 {
|
||||
var volumeFee float64
|
||||
if isMaker {
|
||||
volumeFee = (float64(notionVolume.MakerFee) / 100)
|
||||
volumeFee = (float64(notionVolume.APIMakerFeeBPS) / 10000)
|
||||
} else {
|
||||
volumeFee = (float64(notionVolume.TakerFee) / 100)
|
||||
volumeFee = (float64(notionVolume.APITakerFeeBPS) / 10000)
|
||||
}
|
||||
|
||||
return volumeFee * amount * purchasePrice
|
||||
|
||||
33
exchanges/gemini/gemini_live_test.go
Normal file
33
exchanges/gemini/gemini_live_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
//+build mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is parsed and will do live testing
|
||||
// using all tests in (exchange)_test.go
|
||||
package gemini
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
var mockTests = false
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
geminiConfig, err := cfg.GetExchangeConfig("Gemini")
|
||||
if err != nil {
|
||||
log.Fatal("Test Failed - Gemini Setup() init error", err)
|
||||
}
|
||||
geminiConfig.API.AuthenticatedSupport = true
|
||||
geminiConfig.API.Credentials.Key = apiKey
|
||||
geminiConfig.API.Credentials.Secret = apiSecret
|
||||
g.SetDefaults()
|
||||
g.Setup(geminiConfig)
|
||||
g.API.Endpoints.URL = geminiSandboxAPIURL
|
||||
log.Printf(sharedtestvalues.LiveTesting, g.GetName(), g.API.Endpoints.URL)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
45
exchanges/gemini/gemini_mock_test.go
Normal file
45
exchanges/gemini/gemini_mock_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
//+build !mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is not parsed and will try to mock
|
||||
// all tests in _test.go
|
||||
package gemini
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/mock"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
const mockFile = "../../testdata/http_mock/gemini/gemini.json"
|
||||
|
||||
var mockTests = true
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
geminiConfig, err := cfg.GetExchangeConfig("Gemini")
|
||||
if err != nil {
|
||||
log.Fatal("Test Failed - Mock server error", err)
|
||||
}
|
||||
g.SkipAuthCheck = true
|
||||
geminiConfig.API.AuthenticatedSupport = true
|
||||
geminiConfig.API.Credentials.Key = apiKey
|
||||
geminiConfig.API.Credentials.Secret = apiSecret
|
||||
g.SetDefaults()
|
||||
g.Setup(geminiConfig)
|
||||
|
||||
serverDetails, newClient, err := mock.NewVCRServer(mockFile)
|
||||
if err != nil {
|
||||
log.Fatalf("Test Failed - Mock server error %s", err)
|
||||
}
|
||||
|
||||
g.HTTPClient = newClient
|
||||
g.API.Endpoints.URL = serverDetails
|
||||
|
||||
log.Printf(sharedtestvalues.MockTesting, g.GetName(), g.API.Endpoints.URL)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
@@ -15,75 +14,21 @@ import (
|
||||
)
|
||||
|
||||
// Please enter sandbox API keys & assigned roles for better testing procedures
|
||||
|
||||
const (
|
||||
apiKey1 = ""
|
||||
apiSecret1 = ""
|
||||
apiKeyRole1 = ""
|
||||
sessionHeartBeat1 = false
|
||||
|
||||
apiKey2 = ""
|
||||
apiSecret2 = ""
|
||||
apiKeyRole2 = ""
|
||||
sessionHeartBeat2 = false
|
||||
|
||||
apiKey = ""
|
||||
apiSecret = ""
|
||||
apiKeyRole = ""
|
||||
sessionHeartBeat = false
|
||||
canManipulateRealOrders = false
|
||||
)
|
||||
|
||||
func TestAddSession(t *testing.T) {
|
||||
var g1 Gemini
|
||||
if Session[1] == nil {
|
||||
err := AddSession(&g1, 1, apiKey1, apiSecret1, apiKeyRole1, true, true)
|
||||
if err != nil {
|
||||
t.Error("Test failed - AddSession() error", err)
|
||||
}
|
||||
err = AddSession(&g1, 1, apiKey1, apiSecret1, apiKeyRole1, true, true)
|
||||
if err == nil {
|
||||
t.Error("Test failed - AddSession() error", err)
|
||||
}
|
||||
}
|
||||
const testCurrency = "btcusd"
|
||||
|
||||
if len(Session) <= 1 {
|
||||
var g2 Gemini
|
||||
err := AddSession(&g2, 2, apiKey2, apiSecret2, apiKeyRole2, false, true)
|
||||
if err != nil {
|
||||
t.Error("Test failed - AddSession() error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
Session[1].SetDefaults()
|
||||
Session[2].SetDefaults()
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
geminiConfig, err := cfg.GetExchangeConfig("Gemini")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Gemini Setup() init error")
|
||||
}
|
||||
|
||||
geminiConfig.API.AuthenticatedSupport = true
|
||||
geminiConfig.API.AuthenticatedWebsocketSupport = true
|
||||
|
||||
Session[1].Setup(geminiConfig)
|
||||
Session[2].Setup(geminiConfig)
|
||||
|
||||
Session[1].API.Credentials.Key = apiKey1
|
||||
Session[1].API.Credentials.Secret = apiSecret1
|
||||
|
||||
Session[2].API.Credentials.Key = apiKey2
|
||||
Session[2].API.Credentials.Secret = apiSecret2
|
||||
|
||||
Session[1].API.Endpoints.URL = geminiSandboxAPIURL
|
||||
Session[2].API.Endpoints.URL = geminiSandboxAPIURL
|
||||
}
|
||||
var g Gemini
|
||||
|
||||
func TestGetSymbols(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[1].GetSymbols()
|
||||
_, err := g.GetSymbols()
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetSymbols() error", err)
|
||||
}
|
||||
@@ -91,11 +36,11 @@ func TestGetSymbols(t *testing.T) {
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[2].GetTicker("BTCUSD")
|
||||
_, err := g.GetTicker("BTCUSD")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetTicker() error", err)
|
||||
}
|
||||
_, err = Session[1].GetTicker("bla")
|
||||
_, err = g.GetTicker("bla")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetTicker() error", err)
|
||||
}
|
||||
@@ -103,7 +48,7 @@ func TestGetTicker(t *testing.T) {
|
||||
|
||||
func TestGetOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[1].GetOrderbook("btcusd", url.Values{})
|
||||
_, err := g.GetOrderbook(testCurrency, url.Values{})
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetOrderbook() error", err)
|
||||
}
|
||||
@@ -111,25 +56,25 @@ func TestGetOrderbook(t *testing.T) {
|
||||
|
||||
func TestGetTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[2].GetTrades("btcusd", url.Values{})
|
||||
_, err := g.GetTrades(testCurrency, url.Values{})
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetTrades() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetNotionalVolume(t *testing.T) {
|
||||
if apiKey2 != "" && apiSecret2 != "" {
|
||||
t.Parallel()
|
||||
_, err := Session[2].GetNotionalVolume()
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetNotionalVolume() error", err)
|
||||
}
|
||||
t.Parallel()
|
||||
_, err := g.GetNotionalVolume()
|
||||
if err != nil && mockTests {
|
||||
t.Error("Test Failed - GetNotionalVolume() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
t.Error("Test Failed - GetNotionalVolume() error cannot be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAuction(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[1].GetAuction("btcusd")
|
||||
_, err := g.GetAuction(testCurrency)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetAuction() error", err)
|
||||
}
|
||||
@@ -137,7 +82,7 @@ func TestGetAuction(t *testing.T) {
|
||||
|
||||
func TestGetAuctionHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[2].GetAuctionHistory("btcusd", url.Values{})
|
||||
_, err := g.GetAuctionHistory(testCurrency, url.Values{})
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetAuctionHistory() error", err)
|
||||
}
|
||||
@@ -145,81 +90,87 @@ func TestGetAuctionHistory(t *testing.T) {
|
||||
|
||||
func TestNewOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[1].NewOrder("btcusd", 1, 4500,
|
||||
exchange.BuyOrderSide.ToLower().ToString(), "exchange limit")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - NewOrder() error", err)
|
||||
}
|
||||
_, err = Session[2].NewOrder("btcusd", 1, 4500,
|
||||
exchange.BuyOrderSide.ToLower().ToString(), "exchange limit")
|
||||
if err == nil {
|
||||
_, err := g.NewOrder(testCurrency, 1, 9000, "buy", "exchange limit")
|
||||
if err != nil && mockTests {
|
||||
t.Error("Test Failed - NewOrder() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
t.Error("Test Failed - NewOrder() error cannot be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelExistingOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[1].CancelExistingOrder(1337)
|
||||
if err == nil {
|
||||
_, err := g.CancelExistingOrder(265555413)
|
||||
if err != nil && mockTests {
|
||||
t.Error("Test Failed - CancelExistingOrder() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
t.Error("Test Failed - CancelExistingOrder() error cannot be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelExistingOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[1].CancelExistingOrders(false)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - CancelExistingOrders() error", err)
|
||||
}
|
||||
_, err = Session[2].CancelExistingOrders(true)
|
||||
if err == nil {
|
||||
_, err := g.CancelExistingOrders(false)
|
||||
if err != nil && mockTests {
|
||||
t.Error("Test Failed - CancelExistingOrders() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
t.Error("Test Failed - CancelExistingOrders() error cannot be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderStatus(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[2].GetOrderStatus(1337)
|
||||
if err == nil {
|
||||
_, err := g.GetOrderStatus(265563260)
|
||||
if err != nil && mockTests {
|
||||
t.Error("Test Failed - GetOrderStatus() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
t.Error("Test Failed - GetOrderStatus() error cannot be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[1].GetOrders()
|
||||
if err == nil {
|
||||
_, err := g.GetOrders()
|
||||
if err != nil && mockTests {
|
||||
t.Error("Test Failed - GetOrders() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
t.Error("Test Failed - GetOrders() error cannot be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTradeHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[1].GetTradeHistory("btcusd", 0)
|
||||
if err == nil {
|
||||
_, err := g.GetTradeHistory(testCurrency, 0)
|
||||
if err != nil && mockTests {
|
||||
t.Error("Test Failed - GetTradeHistory() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
t.Error("Test Failed - GetTradeHistory() error cannot be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTradeVolume(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[2].GetTradeVolume()
|
||||
if err == nil {
|
||||
_, err := g.GetTradeVolume()
|
||||
if err != nil && mockTests {
|
||||
t.Error("Test Failed - GetTradeVolume() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
t.Error("Test Failed - GetTradeVolume() error cannot be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBalances(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[1].GetBalances()
|
||||
if err == nil {
|
||||
_, err := g.GetBalances()
|
||||
if err != nil && mockTests {
|
||||
t.Error("Test Failed - GetBalances() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
t.Error("Test Failed - GetBalances() error cannot be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCryptoDepositAddress(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[1].GetCryptoDepositAddress("LOL123", "btc")
|
||||
_, err := g.GetCryptoDepositAddress("LOL123", "btc")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetCryptoDepositAddress() error", err)
|
||||
}
|
||||
@@ -227,7 +178,7 @@ func TestGetCryptoDepositAddress(t *testing.T) {
|
||||
|
||||
func TestWithdrawCrypto(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[1].WithdrawCrypto("LOL123", "btc", 1)
|
||||
_, err := g.WithdrawCrypto("LOL123", "btc", 1)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - WithdrawCrypto() error", err)
|
||||
}
|
||||
@@ -235,9 +186,11 @@ func TestWithdrawCrypto(t *testing.T) {
|
||||
|
||||
func TestPostHeartbeat(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := Session[2].PostHeartbeat()
|
||||
if err == nil {
|
||||
_, err := g.PostHeartbeat()
|
||||
if err != nil && mockTests {
|
||||
t.Error("Test Failed - PostHeartbeat() error", err)
|
||||
} else if err == nil && !mockTests {
|
||||
t.Error("Test Failed - PostHeartbeat() error cannot be nil")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,61 +209,75 @@ func setFeeBuilder() *exchange.FeeBuilder {
|
||||
|
||||
// TestGetFeeByTypeOfflineTradeFee logic test
|
||||
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
||||
TestAddSession(t)
|
||||
TestSetDefaults(t)
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
var feeBuilder = setFeeBuilder()
|
||||
Session[1].GetFeeByType(feeBuilder)
|
||||
if apiKey1 == "" || apiSecret1 == "" {
|
||||
g.GetFeeByType(feeBuilder)
|
||||
|
||||
if !areTestAPIKeysSet() {
|
||||
if feeBuilder.FeeType != exchange.OfflineTradeFee {
|
||||
t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType)
|
||||
t.Errorf("Expected %v, received %v",
|
||||
exchange.OfflineTradeFee,
|
||||
feeBuilder.FeeType)
|
||||
}
|
||||
} else {
|
||||
if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee {
|
||||
t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType)
|
||||
t.Errorf("Expected %v, received %v",
|
||||
exchange.CryptocurrencyTradeFee,
|
||||
feeBuilder.FeeType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
var feeBuilder = setFeeBuilder()
|
||||
if apiKey1 != "" && apiSecret1 != "" {
|
||||
if areTestAPIKeysSet() || mockTests {
|
||||
// CryptocurrencyTradeFee Basic
|
||||
if resp, err := Session[1].GetFee(feeBuilder); resp != float64(0.01) || err != nil {
|
||||
if resp, err := g.GetFee(feeBuilder); resp != float64(0.0035) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0.0035),
|
||||
resp)
|
||||
t.Error(err)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.01), resp)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee High quantity
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.Amount = 1000
|
||||
feeBuilder.PurchasePrice = 1000
|
||||
if resp, err := Session[1].GetFee(feeBuilder); resp != float64(100) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(100), resp)
|
||||
if resp, err := g.GetFee(feeBuilder); resp != float64(3500) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(3500),
|
||||
resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee IsMaker
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.IsMaker = true
|
||||
if resp, err := Session[1].GetFee(feeBuilder); resp != float64(0.01) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.01), resp)
|
||||
if resp, err := g.GetFee(feeBuilder); resp != float64(0.001) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0.001),
|
||||
resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee Negative purchase price
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.PurchasePrice = -1000
|
||||
if resp, err := Session[1].GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
if resp, err := g.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0),
|
||||
resp)
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
// CryptocurrencyWithdrawalFee Basic
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
|
||||
if resp, err := Session[1].GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
if resp, err := g.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0),
|
||||
resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -318,24 +285,30 @@ func TestGetFee(t *testing.T) {
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.Pair.Base = currency.NewCode("hello")
|
||||
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
|
||||
if resp, err := Session[1].GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
if resp, err := g.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0),
|
||||
resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CyptocurrencyDepositFee Basic
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.CyptocurrencyDepositFee
|
||||
if resp, err := Session[1].GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
if resp, err := g.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0),
|
||||
resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// InternationalBankDepositFee Basic
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.InternationalBankDepositFee
|
||||
if resp, err := Session[1].GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
if resp, err := g.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0),
|
||||
resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -343,74 +316,78 @@ func TestGetFee(t *testing.T) {
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
|
||||
feeBuilder.FiatCurrency = currency.USD
|
||||
if resp, err := Session[1].GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
if resp, err := g.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0),
|
||||
resp)
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatWithdrawPermissions(t *testing.T) {
|
||||
TestAddSession(t)
|
||||
TestSetDefaults(t)
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
expectedResult := exchange.AutoWithdrawCryptoWithAPIPermissionText +
|
||||
" & " +
|
||||
exchange.AutoWithdrawCryptoWithSetupText +
|
||||
" & " +
|
||||
exchange.WithdrawFiatViaWebsiteOnlyText
|
||||
|
||||
expectedResult := exchange.AutoWithdrawCryptoWithAPIPermissionText + " & " + exchange.AutoWithdrawCryptoWithSetupText + " & " + exchange.WithdrawFiatViaWebsiteOnlyText
|
||||
|
||||
withdrawPermissions := Session[1].FormatWithdrawPermissions()
|
||||
withdrawPermissions := g.FormatWithdrawPermissions()
|
||||
|
||||
if withdrawPermissions != expectedResult {
|
||||
t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions)
|
||||
t.Errorf("Expected: %s, Received: %s",
|
||||
expectedResult,
|
||||
withdrawPermissions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetActiveOrders(t *testing.T) {
|
||||
TestAddSession(t)
|
||||
TestSetDefaults(t)
|
||||
TestSetup(t)
|
||||
|
||||
t.Parallel()
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
Currencies: []currency.Pair{currency.NewPair(currency.LTC, currency.BTC)},
|
||||
OrderType: exchange.AnyOrderType,
|
||||
Currencies: []currency.Pair{
|
||||
currency.NewPair(currency.LTC, currency.BTC),
|
||||
},
|
||||
}
|
||||
|
||||
_, err := Session[1].GetActiveOrders(&getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
_, err := g.GetActiveOrders(&getOrdersRequest)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
TestAddSession(t)
|
||||
TestSetDefaults(t)
|
||||
TestSetup(t)
|
||||
|
||||
t.Parallel()
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
Currencies: []currency.Pair{currency.NewPair(currency.LTC, currency.BTC)},
|
||||
}
|
||||
|
||||
_, err := Session[1].GetOrderHistory(&getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
_, err := g.GetOrderHistory(&getOrdersRequest)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Errorf("Could not get order history: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case err != nil && mockTests:
|
||||
t.Errorf("Could not get order history: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
func areTestAPIKeysSet() bool {
|
||||
return Session[1].ValidateAPICredentials()
|
||||
return g.ValidateAPICredentials()
|
||||
}
|
||||
|
||||
func TestSubmitOrder(t *testing.T) {
|
||||
TestAddSession(t)
|
||||
TestSetDefaults(t)
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
@@ -422,51 +399,46 @@ func TestSubmitOrder(t *testing.T) {
|
||||
},
|
||||
OrderSide: exchange.BuyOrderSide,
|
||||
OrderType: exchange.LimitOrderType,
|
||||
Price: 1,
|
||||
Price: 10,
|
||||
Amount: 1,
|
||||
ClientID: "meowOrder",
|
||||
ClientID: "1234234",
|
||||
}
|
||||
response, err := Session[1].SubmitOrder(orderSubmission)
|
||||
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
|
||||
|
||||
response, err := g.SubmitOrder(orderSubmission)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced):
|
||||
t.Errorf("Order failed to be placed: %v", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Order failed to be placed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelExchangeOrder(t *testing.T) {
|
||||
TestAddSession(t)
|
||||
TestSetDefaults(t)
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
|
||||
|
||||
var orderCancellation = &exchange.OrderCancellation{
|
||||
OrderID: "1",
|
||||
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
AccountID: "1",
|
||||
CurrencyPair: currencyPair,
|
||||
OrderID: "266029865",
|
||||
}
|
||||
|
||||
err := Session[1].CancelOrder(orderCancellation)
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
err := g.CancelOrder(orderCancellation)
|
||||
switch {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
case err != nil && mockTests:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
TestAddSession(t)
|
||||
TestSetDefaults(t)
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
@@ -479,12 +451,13 @@ func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
CurrencyPair: currencyPair,
|
||||
}
|
||||
|
||||
resp, err := Session[1].CancelAllOrders(orderCancellation)
|
||||
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
resp, err := g.CancelAllOrders(orderCancellation)
|
||||
switch {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
}
|
||||
|
||||
@@ -494,16 +467,15 @@ func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestModifyOrder(t *testing.T) {
|
||||
_, err := Session[1].ModifyOrder(&exchange.ModifyOrder{})
|
||||
t.Parallel()
|
||||
_, err := g.ModifyOrder(&exchange.ModifyOrder{})
|
||||
if err == nil {
|
||||
t.Error("Test failed - ModifyOrder() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
TestAddSession(t)
|
||||
TestSetDefaults(t)
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
withdrawCryptoRequest := exchange.CryptoWithdrawRequest{
|
||||
GenericWithdrawRequestInfo: exchange.GenericWithdrawRequestInfo{
|
||||
Amount: -1,
|
||||
@@ -513,53 +485,55 @@ func TestWithdraw(t *testing.T) {
|
||||
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
}
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
_, err := Session[1].WithdrawCryptocurrencyFunds(&withdrawCryptoRequest)
|
||||
_, err := g.WithdrawCryptocurrencyFunds(&withdrawCryptoRequest)
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
if areTestAPIKeysSet() && err != nil && !mockTests {
|
||||
t.Errorf("Withdraw failed to be placed: %v", err)
|
||||
}
|
||||
if areTestAPIKeysSet() && err == nil && mockTests {
|
||||
t.Errorf("Withdraw failed to be placed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawFiat(t *testing.T) {
|
||||
TestAddSession(t)
|
||||
TestSetDefaults(t)
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
var withdrawFiatRequest = exchange.FiatWithdrawRequest{}
|
||||
_, err := Session[1].WithdrawFiatFunds(&withdrawFiatRequest)
|
||||
_, err := g.WithdrawFiatFunds(&withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
|
||||
t.Errorf("Expected '%v', received: '%v'",
|
||||
common.ErrFunctionNotSupported,
|
||||
err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawInternationalBank(t *testing.T) {
|
||||
TestAddSession(t)
|
||||
TestSetDefaults(t)
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
var withdrawFiatRequest = exchange.FiatWithdrawRequest{}
|
||||
_, err := Session[1].WithdrawFiatFundsToInternationalBank(&withdrawFiatRequest)
|
||||
_, err := g.WithdrawFiatFundsToInternationalBank(&withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
|
||||
t.Errorf("Expected '%v', received: '%v'",
|
||||
common.ErrFunctionNotSupported,
|
||||
err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDepositAddress(t *testing.T) {
|
||||
_, err := Session[1].GetDepositAddress(currency.BTC, "")
|
||||
t.Parallel()
|
||||
_, err := g.GetDepositAddress(currency.BTC, "")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetDepositAddress error cannot be nil")
|
||||
}
|
||||
@@ -567,13 +541,12 @@ func TestGetDepositAddress(t *testing.T) {
|
||||
|
||||
// TestWsAuth dials websocket, sends login request.
|
||||
func TestWsAuth(t *testing.T) {
|
||||
TestAddSession(t)
|
||||
TestSetDefaults(t)
|
||||
TestSetup(t)
|
||||
g := Session[1]
|
||||
t.Parallel()
|
||||
g.API.Endpoints.WebsocketURL = geminiWebsocketSandboxEndpoint
|
||||
|
||||
if !g.Websocket.IsEnabled() && !g.API.AuthenticatedWebsocketSupport || !areTestAPIKeysSet() {
|
||||
if !g.Websocket.IsEnabled() &&
|
||||
!g.API.AuthenticatedWebsocketSupport ||
|
||||
!areTestAPIKeysSet() {
|
||||
t.Skip(wshandler.WebsocketNotEnabled)
|
||||
}
|
||||
var dialer websocket.Dialer
|
||||
|
||||
@@ -145,16 +145,23 @@ type TradeVolume struct {
|
||||
SellTakerCount float64 `json:"sell_taker_count"`
|
||||
}
|
||||
|
||||
// NotionalVolume api call for fees
|
||||
// NotionalVolume api call for fees, all return fee amounts are in basis points
|
||||
type NotionalVolume struct {
|
||||
MakerFee int64 `json:"maker_fee_bps"`
|
||||
TakerFee int64 `json:"taker_fee_bps"`
|
||||
AuctionFee int64 `json:"auction_fee_bps"`
|
||||
ThirtyDayVolume float64 `json:"notional_30d_volume"`
|
||||
LastedUpdated int64 `json:"last_updated_ms"`
|
||||
AccountID int64 `json:"account_id"`
|
||||
Date string `json:"date"`
|
||||
APIAuctionFeeBPS int64 `json:"api_auction_fee_bps"`
|
||||
APIMakerFeeBPS int64 `json:"api_maker_fee_bps"`
|
||||
APITakerFeeBPS int64 `json:"api_taker_fee_bps"`
|
||||
BlockMakerFeeBPS int64 `json:"block_maker_fee_bps"`
|
||||
BlockTakerFeeBPS int64 `json:"block_taker_fee_bps"`
|
||||
FixAuctionFeeBPS int64 `json:"fix_auction_fee_bps"`
|
||||
FixMakerFeeBPS int64 `json:"fix_maker_fee_bps"`
|
||||
FixTakerFeeBPS int64 `json:"fix_taker_fee_bps"`
|
||||
OneDayNotionalVolumes []OneDayNotionalVolume `json:"notional_1d_volume"`
|
||||
ThirtyDayVolume float64 `json:"notional_30d_volume"`
|
||||
WebAuctionFeeBPS int64 `json:"web_auction_fee_bps"`
|
||||
WebMakerFeeBPS int64 `json:"web_maker_fee_bps"`
|
||||
WebTakerFeeBPS int64 `json:"web_taker_fee_bps"`
|
||||
LastedUpdated int64 `json:"last_updated_ms"`
|
||||
Date string `json:"date"`
|
||||
}
|
||||
|
||||
// OneDayNotionalVolume Contains the notioanl volume for a single day
|
||||
|
||||
@@ -305,11 +305,16 @@ func (g *Gemini) SubmitOrder(order *exchange.OrderSubmission) (exchange.SubmitOr
|
||||
return submitOrderResponse, err
|
||||
}
|
||||
|
||||
response, err := g.NewOrder(order.Pair.String(),
|
||||
if order.OrderType != exchange.LimitOrderType {
|
||||
return submitOrderResponse, errors.New("only limit orders are enabled through this exchange")
|
||||
}
|
||||
|
||||
response, err := g.NewOrder(
|
||||
g.FormatExchangeCurrency(order.Pair, asset.Spot).String(),
|
||||
order.Amount,
|
||||
order.Price,
|
||||
order.OrderSide.ToString(),
|
||||
order.OrderType.ToString())
|
||||
"exchange limit")
|
||||
if response > 0 {
|
||||
submitOrderResponse.OrderID = fmt.Sprintf("%v", response)
|
||||
}
|
||||
@@ -401,7 +406,7 @@ func (g *Gemini) GetWebsocket() (*wshandler.Websocket, error) {
|
||||
|
||||
// GetFeeByType returns an estimate of fee based on type of transaction
|
||||
func (g *Gemini) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
if !g.AllowAuthenticatedRequest() && // Todo check connection status
|
||||
if (!g.AllowAuthenticatedRequest() || g.SkipAuthCheck) && // Todo check connection status
|
||||
feeBuilder.FeeType == exchange.CryptocurrencyTradeFee {
|
||||
feeBuilder.FeeType = exchange.OfflineTradeFee
|
||||
}
|
||||
|
||||
@@ -508,7 +508,16 @@ func (h *HitBTC) TransferBalance(currency, from, to string, amount float64) (boo
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (h *HitBTC) SendHTTPRequest(path string, result interface{}) error {
|
||||
return h.SendPayload(http.MethodGet, path, nil, nil, result, false, false, h.Verbose, h.HTTPDebugging)
|
||||
return h.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
h.Verbose,
|
||||
h.HTTPDebugging,
|
||||
h.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated http request
|
||||
@@ -530,7 +539,8 @@ func (h *HitBTC) SendAuthenticatedHTTPRequest(method, endpoint string, values ur
|
||||
true,
|
||||
false,
|
||||
h.Verbose,
|
||||
h.HTTPDebugging)
|
||||
h.HTTPDebugging,
|
||||
h.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -776,7 +776,16 @@ func (h *HUOBI) CancelWithdraw(withdrawID int64) (int64, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (h *HUOBI) SendHTTPRequest(path string, result interface{}) error {
|
||||
return h.SendPayload(http.MethodGet, path, nil, nil, result, false, false, h.Verbose, h.HTTPDebugging)
|
||||
return h.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
h.Verbose,
|
||||
h.HTTPDebugging,
|
||||
h.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends authenticated requests to the HUOBI API
|
||||
@@ -852,7 +861,16 @@ func (h *HUOBI) SendAuthenticatedHTTPRequest(method, endpoint string, values url
|
||||
body = encoded
|
||||
}
|
||||
|
||||
return h.SendPayload(method, urlPath, headers, bytes.NewReader(body), result, true, false, h.Verbose, h.HTTPDebugging)
|
||||
return h.SendPayload(method,
|
||||
urlPath,
|
||||
headers,
|
||||
bytes.NewReader(body),
|
||||
result,
|
||||
true,
|
||||
false,
|
||||
h.Verbose,
|
||||
h.HTTPDebugging,
|
||||
h.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -773,7 +773,16 @@ func (h *HUOBIHADAX) CancelWithdraw(withdrawID int64) (int64, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (h *HUOBIHADAX) SendHTTPRequest(path string, result interface{}) error {
|
||||
return h.SendPayload(http.MethodGet, path, nil, nil, result, false, false, h.Verbose, h.HTTPDebugging)
|
||||
return h.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
h.Verbose,
|
||||
h.HTTPDebugging,
|
||||
h.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPPostRequest sends authenticated requests to the HUOBI API
|
||||
@@ -801,7 +810,16 @@ func (h *HUOBIHADAX) SendAuthenticatedHTTPPostRequest(method, endpoint, postBody
|
||||
|
||||
urlPath := common.EncodeURLValues(fmt.Sprintf("%s%s", h.API.Endpoints.URL, endpoint),
|
||||
signatureParams)
|
||||
return h.SendPayload(method, urlPath, headers, bytes.NewBufferString(postBodyValues), result, true, false, h.Verbose, h.HTTPDebugging)
|
||||
return h.SendPayload(method,
|
||||
urlPath,
|
||||
headers,
|
||||
bytes.NewBufferString(postBodyValues),
|
||||
result,
|
||||
true,
|
||||
false,
|
||||
h.Verbose,
|
||||
h.HTTPDebugging,
|
||||
h.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends authenticated requests to the HUOBI API
|
||||
@@ -827,7 +845,16 @@ func (h *HUOBIHADAX) SendAuthenticatedHTTPRequest(method, endpoint string, value
|
||||
|
||||
urlPath := common.EncodeURLValues(fmt.Sprintf("%s%s", h.API.Endpoints.URL, endpoint),
|
||||
values)
|
||||
return h.SendPayload(method, urlPath, headers, bytes.NewBufferString(""), result, true, false, h.Verbose, h.HTTPDebugging)
|
||||
return h.SendPayload(method,
|
||||
urlPath,
|
||||
headers,
|
||||
bytes.NewBufferString(""),
|
||||
result,
|
||||
true,
|
||||
false,
|
||||
h.Verbose,
|
||||
h.HTTPDebugging,
|
||||
h.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -276,7 +276,16 @@ func (i *ItBit) WalletTransfer(walletID, sourceWallet, destWallet string, amount
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (i *ItBit) SendHTTPRequest(path string, result interface{}) error {
|
||||
return i.SendPayload(http.MethodGet, path, nil, nil, result, false, false, i.Verbose, i.HTTPDebugging)
|
||||
return i.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
i.Verbose,
|
||||
i.HTTPDebugging,
|
||||
i.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated request to itBit
|
||||
@@ -331,7 +340,16 @@ func (i *ItBit) SendAuthenticatedHTTPRequest(method, path string, params map[str
|
||||
RequestID string `json:"requestId"`
|
||||
}{}
|
||||
|
||||
err = i.SendPayload(method, urlPath, headers, bytes.NewBuffer(PayloadJSON), &intermediary, true, true, i.Verbose, i.HTTPDebugging)
|
||||
err = i.SendPayload(method,
|
||||
urlPath,
|
||||
headers,
|
||||
bytes.NewBuffer(PayloadJSON),
|
||||
&intermediary,
|
||||
true,
|
||||
true,
|
||||
i.Verbose,
|
||||
i.HTTPDebugging,
|
||||
i.HTTPRecording)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -846,7 +846,16 @@ func GetError(apiErrors []string) error {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP requests
|
||||
func (k *Kraken) SendHTTPRequest(path string, result interface{}) error {
|
||||
return k.SendPayload(http.MethodGet, path, nil, nil, result, false, false, k.Verbose, k.HTTPDebugging)
|
||||
return k.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
k.Verbose,
|
||||
k.HTTPDebugging,
|
||||
k.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request
|
||||
@@ -883,7 +892,8 @@ func (k *Kraken) SendAuthenticatedHTTPRequest(method string, params url.Values,
|
||||
true,
|
||||
true,
|
||||
k.Verbose,
|
||||
k.HTTPDebugging)
|
||||
k.HTTPDebugging,
|
||||
k.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -251,7 +251,16 @@ func (l *LakeBTC) CreateWithdraw(amount float64, accountID string) (Withdraw, er
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated http request
|
||||
func (l *LakeBTC) SendHTTPRequest(path string, result interface{}) error {
|
||||
return l.SendPayload(http.MethodGet, path, nil, nil, result, false, false, l.Verbose, l.HTTPDebugging)
|
||||
return l.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
l.Verbose,
|
||||
l.HTTPDebugging,
|
||||
l.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an autheticated HTTP request to a LakeBTC
|
||||
@@ -284,8 +293,16 @@ func (l *LakeBTC) SendAuthenticatedHTTPRequest(method, params string, result int
|
||||
headers["Authorization"] = "Basic " + crypto.Base64Encode([]byte(l.API.Credentials.Key+":"+crypto.HexEncodeToString(hmac)))
|
||||
headers["Content-Type"] = "application/json-rpc"
|
||||
|
||||
return l.SendPayload(http.MethodPost, l.API.Endpoints.URL, headers,
|
||||
strings.NewReader(string(data)), result, true, true, l.Verbose, l.HTTPDebugging)
|
||||
return l.SendPayload(http.MethodPost,
|
||||
l.API.Endpoints.URL,
|
||||
headers,
|
||||
strings.NewReader(string(data)),
|
||||
result,
|
||||
true,
|
||||
true,
|
||||
l.Verbose,
|
||||
l.HTTPDebugging,
|
||||
l.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
133
exchanges/lbank/README.md
Normal file
133
exchanges/lbank/README.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# GoCryptoTrader package Lbank
|
||||
|
||||
<img src="https://github.com/thrasher-corp/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
|
||||
|
||||
|
||||
[](https://travis-ci.org/thrasher-corp/gocryptotrader)
|
||||
[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
|
||||
[](https://godoc.org/github.com/thrasher-corp/gocryptotrader/exchanges/lbank)
|
||||
[](http://codecov.io/github/thrasher-corp/gocryptotrader?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/thrasher-corp/gocryptotrader)
|
||||
|
||||
|
||||
This lbank package is part of the GoCryptoTrader codebase.
|
||||
|
||||
## This is still in active development
|
||||
|
||||
You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
|
||||
|
||||
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/enQtNTQ5NDAxMjA2Mjc5LTQyYjIxNGVhMWU5MDZlOGYzMmE0NTJmM2MzYWY5NGMzMmM4MzUwNTBjZTEzNjIwODM5NDcxODQwZDljMGQyNGY)
|
||||
|
||||
## Lbank Exchange
|
||||
|
||||
### Current Features
|
||||
|
||||
+ REST Support
|
||||
|
||||
### How to enable
|
||||
|
||||
+ [Enable via configuration](https://githul.com/thrasher-corp/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
|
||||
|
||||
+ Individual package example below:
|
||||
|
||||
```go
|
||||
// Exchanges will be abstracted out in further updates and examples will be
|
||||
// supplied then
|
||||
```
|
||||
|
||||
### How to do REST public/private calls
|
||||
|
||||
+ If enabled via "configuration".json file the exchange will be added to the
|
||||
IBotExchange array in the ```go var bot Bot``` and you will only be able to use
|
||||
the wrapper interface functions for accessing exchange data. View routines.go
|
||||
for an example of integration usage with GoCryptoTrader. Rudimentary example
|
||||
below:
|
||||
|
||||
main.go
|
||||
```go
|
||||
var l exchange.IBotExchange
|
||||
|
||||
for i := range bot.exchanges {
|
||||
if bot.exchanges[i].GetName() == "Lbank" {
|
||||
l = bot.exchanges[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Public calls - wrapper functions
|
||||
|
||||
// Fetches current ticker information
|
||||
tick, err := l.GetTickerPrice()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := l.GetOrderbookEx()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
|
||||
// set and AuthenticatedAPISupport is set to true
|
||||
|
||||
// Fetches current account information
|
||||
accountInfo, err := l.GetAccountInfo()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
+ If enabled via individually importing package, rudimentary example below:
|
||||
|
||||
```go
|
||||
// Public calls
|
||||
|
||||
// Fetches current ticker information
|
||||
ticker, err := l.GetTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := l.GetOrderBook()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Private calls - make sure your APIKEY and APISECRET are set and
|
||||
// AuthenticatedAPISupport is set to true
|
||||
|
||||
// GetUserInfo returns account info
|
||||
accountInfo, err := l.GetUserInfo(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Submits an order and the exchange and returns its tradeID
|
||||
tradeID, err := l.Trade(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||
|
||||
## Contribution
|
||||
|
||||
Please feel free to submit any pull requests or suggest any desired features to be added.
|
||||
|
||||
When submitting a PR, please abide by our coding guidelines:
|
||||
|
||||
+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
|
||||
+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
|
||||
+ Code must adhere to our [coding style](https://github.com/thrasher-corp/gocryptotrader/blob/master/doc/coding_style.md).
|
||||
+ Pull requests need to be based on and opened against the `master` branch.
|
||||
|
||||
## Donations
|
||||
|
||||
<img src="https://github.com/thrasher-corp/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
|
||||
|
||||
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
|
||||
|
||||
***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***
|
||||
|
||||
562
exchanges/lbank/lbank.go
Normal file
562
exchanges/lbank/lbank.go
Normal file
@@ -0,0 +1,562 @@
|
||||
package lbank
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
gctcrypto "github.com/thrasher-corp/gocryptotrader/common/crypto"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
|
||||
)
|
||||
|
||||
// Lbank is the overarching type across this package
|
||||
type Lbank struct {
|
||||
exchange.Base
|
||||
privateKey *rsa.PrivateKey
|
||||
WebsocketConn *wshandler.WebsocketConnection
|
||||
}
|
||||
|
||||
const (
|
||||
lbankAPIURL = "https://api.lbkex.com"
|
||||
lbankAPIVersion = "1"
|
||||
lbankAuthRateLimit = 0
|
||||
lbankUnAuthRateLimit = 0
|
||||
lbankFeeNotFound = 0.0
|
||||
|
||||
// Public endpoints
|
||||
lbankTicker = "ticker.do"
|
||||
lbankCurrencyPairs = "currencyPairs.do"
|
||||
lbankMarketDepths = "depth.do"
|
||||
lbankTrades = "trades.do"
|
||||
lbankKlines = "kline.do"
|
||||
lbankPairInfo = "accuracy.do"
|
||||
lbankUSD2CNYRate = "usdToCny.do"
|
||||
lbankWithdrawConfig = "withdrawConfigs.do"
|
||||
|
||||
// Authenticated endpoints
|
||||
lbankUserInfo = "user_info.do"
|
||||
lbankPlaceOrder = "create_order.do"
|
||||
lbankCancelOrder = "cancel_order.do"
|
||||
lbankQueryOrder = "orders_info.do"
|
||||
lbankQueryHistoryOrder = "orders_info_history.do"
|
||||
lbankOrderTransactionDetails = "order_transaction_detail.do"
|
||||
lbankPastTransactions = "transaction_history.do"
|
||||
lbankOpeningOrders = "orders_info_no_deal.do"
|
||||
lbankWithdrawalRecords = "withdraws.do"
|
||||
lbankWithdraw = "withdraw.do"
|
||||
lbankRevokeWithdraw = "withdrawCancel.do"
|
||||
)
|
||||
|
||||
// GetTicker returns a ticker for the specified symbol
|
||||
// symbol: eth_btc
|
||||
func (l *Lbank) GetTicker(symbol string) (TickerResponse, error) {
|
||||
var t TickerResponse
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
path := fmt.Sprintf("%s/v%s/%s?%s", l.API.Endpoints.URL, lbankAPIVersion, lbankTicker, params.Encode())
|
||||
return t, l.SendHTTPRequest(path, &t)
|
||||
}
|
||||
|
||||
// GetCurrencyPairs returns a list of supported currency pairs by the exchange
|
||||
func (l *Lbank) GetCurrencyPairs() ([]string, error) {
|
||||
path := fmt.Sprintf("%s/v%s/%s", l.API.Endpoints.URL, lbankAPIVersion,
|
||||
lbankCurrencyPairs)
|
||||
var result []string
|
||||
return result, l.SendHTTPRequest(path, &result)
|
||||
}
|
||||
|
||||
// GetMarketDepths returns arrays of asks, bids and timestamp
|
||||
func (l *Lbank) GetMarketDepths(symbol, size, merge string) (MarketDepthResponse, error) {
|
||||
var m MarketDepthResponse
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
params.Set("size", size)
|
||||
params.Set("merge", merge)
|
||||
path := fmt.Sprintf("%s/v%s/%s?%s", l.API.Endpoints.URL, lbankAPIVersion, lbankMarketDepths, params.Encode())
|
||||
return m, l.SendHTTPRequest(path, &m)
|
||||
}
|
||||
|
||||
// GetTrades returns an array of available trades regarding a particular exchange
|
||||
func (l *Lbank) GetTrades(symbol, size, time string) ([]TradeResponse, error) {
|
||||
var g []TradeResponse
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
params.Set("size", size)
|
||||
params.Set("time", time)
|
||||
path := fmt.Sprintf("%s/v%s/%s?%s", l.API.Endpoints.URL, lbankAPIVersion, lbankTrades, params.Encode())
|
||||
return g, l.SendHTTPRequest(path, &g)
|
||||
}
|
||||
|
||||
// GetKlines returns kline data
|
||||
func (l *Lbank) GetKlines(symbol, size, klineType, time string) ([]KlineResponse, error) {
|
||||
var klineTemp interface{}
|
||||
var k []KlineResponse
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
params.Set("size", size)
|
||||
params.Set("type", klineType)
|
||||
params.Set("time", time)
|
||||
path := fmt.Sprintf("%s/v%s/%s?%s", l.API.Endpoints.URL, lbankAPIVersion, lbankKlines, params.Encode())
|
||||
err := l.SendHTTPRequest(path, &klineTemp)
|
||||
if err != nil {
|
||||
return k, err
|
||||
}
|
||||
|
||||
resp, ok := klineTemp.([]interface{})
|
||||
if !ok {
|
||||
return nil, errors.New("response received is invalid")
|
||||
}
|
||||
|
||||
for i := range resp {
|
||||
resp2, ok := resp[i].([]interface{})
|
||||
if !ok {
|
||||
return nil, errors.New("response received is invalid")
|
||||
}
|
||||
var tempResp KlineResponse
|
||||
for x := range resp2 {
|
||||
switch x {
|
||||
case 0:
|
||||
tempResp.TimeStamp = int64(resp2[x].(float64))
|
||||
case 1:
|
||||
if val, ok := resp2[x].(int64); ok {
|
||||
tempResp.OpenPrice = float64(val)
|
||||
} else {
|
||||
tempResp.OpenPrice = resp2[x].(float64)
|
||||
}
|
||||
case 2:
|
||||
if val, ok := resp2[x].(int64); ok {
|
||||
tempResp.HigestPrice = float64(val)
|
||||
} else {
|
||||
tempResp.HigestPrice = resp2[x].(float64)
|
||||
}
|
||||
case 3:
|
||||
if val, ok := resp2[x].(int64); ok {
|
||||
tempResp.LowestPrice = float64(val)
|
||||
} else {
|
||||
tempResp.LowestPrice = resp2[x].(float64)
|
||||
}
|
||||
|
||||
case 4:
|
||||
if val, ok := resp2[x].(int64); ok {
|
||||
tempResp.ClosePrice = float64(val)
|
||||
} else {
|
||||
tempResp.ClosePrice = resp2[x].(float64)
|
||||
}
|
||||
|
||||
case 5:
|
||||
if val, ok := resp2[x].(int64); ok {
|
||||
tempResp.TradingVolume = float64(val)
|
||||
} else {
|
||||
tempResp.TradingVolume = resp2[x].(float64)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
k = append(k, tempResp)
|
||||
}
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// GetUserInfo gets users account info
|
||||
func (l *Lbank) GetUserInfo() (InfoFinalResponse, error) {
|
||||
var resp InfoFinalResponse
|
||||
path := fmt.Sprintf("%s/v%s/%s?", l.API.Endpoints.URL, lbankAPIVersion, lbankUserInfo)
|
||||
err := l.SendAuthHTTPRequest(http.MethodPost, path, nil, &resp)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if resp.Error != 0 {
|
||||
return resp, ErrorCapture(resp.Error)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// CreateOrder creates an order
|
||||
func (l *Lbank) CreateOrder(pair, side string, amount, price float64) (CreateOrderResponse, error) {
|
||||
var resp CreateOrderResponse
|
||||
if !strings.EqualFold(side, "buy") && !strings.EqualFold(side, "sell") {
|
||||
return resp, errors.New("side type invalid can only be 'buy' or 'sell'")
|
||||
}
|
||||
if amount <= 0 {
|
||||
return resp, errors.New("amount can't be smaller than or equal to 0")
|
||||
}
|
||||
if price <= 0 {
|
||||
return resp, errors.New("price can't be smaller than or equal to 0")
|
||||
}
|
||||
params := url.Values{}
|
||||
|
||||
params.Set("symbol", pair)
|
||||
params.Set("type", strings.ToLower(side))
|
||||
params.Set("price", strconv.FormatFloat(price, 'f', -1, 64))
|
||||
params.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
path := fmt.Sprintf("%s/v%s/%s?", l.API.Endpoints.URL, lbankAPIVersion, lbankPlaceOrder)
|
||||
err := l.SendAuthHTTPRequest(http.MethodPost, path, params, &resp)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if resp.Error != 0 {
|
||||
return resp, ErrorCapture(resp.Error)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// RemoveOrder cancels a given order
|
||||
func (l *Lbank) RemoveOrder(pair, orderID string) (RemoveOrderResponse, error) {
|
||||
var resp RemoveOrderResponse
|
||||
params := url.Values{}
|
||||
params.Set("symbol", pair)
|
||||
params.Set("order_id", orderID)
|
||||
path := fmt.Sprintf("%s/v%s/%s", l.API.Endpoints.URL, lbankAPIVersion, lbankCancelOrder)
|
||||
err := l.SendAuthHTTPRequest(http.MethodPost, path, params, &resp)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if resp.Error != 0 {
|
||||
return resp, ErrorCapture(resp.Error)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// QueryOrder finds out information about orders (can pass up to 3 comma separated values to this)
|
||||
// Lbank returns an empty string as their []OrderResponse instead of returning an empty array, so when len(tempResp.Orders) > 2 its not empty and should be unmarshalled separately
|
||||
func (l *Lbank) QueryOrder(pair, orderIDs string) (QueryOrderFinalResponse, error) {
|
||||
var resp QueryOrderFinalResponse
|
||||
var tempResp QueryOrderResponse
|
||||
params := url.Values{}
|
||||
params.Set("symbol", pair)
|
||||
params.Set("order_id", orderIDs)
|
||||
path := fmt.Sprintf("%s/v%s/%s?", l.API.Endpoints.URL, lbankAPIVersion, lbankQueryOrder)
|
||||
err := l.SendAuthHTTPRequest(http.MethodPost, path, params, &tempResp)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
var totalOrders []OrderResponse
|
||||
if len(tempResp.Orders) > 2 {
|
||||
err = json.Unmarshal(tempResp.Orders, &totalOrders)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
}
|
||||
resp.ErrCapture = tempResp.ErrCapture
|
||||
resp.Orders = totalOrders
|
||||
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if resp.Error != 0 {
|
||||
return resp, ErrorCapture(resp.Error)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// QueryOrderHistory finds order info in the past 2 days
|
||||
// Lbank returns an empty string as their []OrderResponse instead of returning an empty array, so when len(tempResp.Orders) > 2 its not empty and should be unmarshalled separately
|
||||
func (l *Lbank) QueryOrderHistory(pair, pageNumber, pageLength string) (OrderHistoryFinalResponse, error) {
|
||||
var resp OrderHistoryFinalResponse
|
||||
var tempResp OrderHistoryResponse
|
||||
params := url.Values{}
|
||||
params.Set("symbol", pair)
|
||||
params.Set("current_page", pageNumber)
|
||||
params.Set("page_length", pageLength)
|
||||
path := fmt.Sprintf("%s/v%s/%s?", l.API.Endpoints.URL, lbankAPIVersion, lbankQueryHistoryOrder)
|
||||
err := l.SendAuthHTTPRequest(http.MethodPost, path, params, &tempResp)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
var totalOrders []OrderResponse
|
||||
if len(tempResp.Orders) > 2 {
|
||||
err = json.Unmarshal(tempResp.Orders, &totalOrders)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
}
|
||||
resp.ErrCapture = tempResp.ErrCapture
|
||||
resp.PageLength = tempResp.PageLength
|
||||
resp.Orders = totalOrders
|
||||
resp.CurrentPage = tempResp.CurrentPage
|
||||
|
||||
if resp.Error != 0 {
|
||||
return resp, ErrorCapture(resp.Error)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetPairInfo finds information about all trading pairs
|
||||
func (l *Lbank) GetPairInfo() ([]PairInfoResponse, error) {
|
||||
var resp []PairInfoResponse
|
||||
path := fmt.Sprintf("%s/v%s/%s?", l.API.Endpoints.URL, lbankAPIVersion, lbankPairInfo)
|
||||
return resp, l.SendHTTPRequest(path, &resp)
|
||||
}
|
||||
|
||||
// OrderTransactionDetails gets info about transactions
|
||||
func (l *Lbank) OrderTransactionDetails(symbol, orderID string) (TransactionHistoryResp, error) {
|
||||
var resp TransactionHistoryResp
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
params.Set("order_id", orderID)
|
||||
path := fmt.Sprintf("%s/v%s/%s?", l.API.Endpoints.URL, lbankAPIVersion, lbankOrderTransactionDetails)
|
||||
err := l.SendAuthHTTPRequest(http.MethodPost, path, params, &resp)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if resp.Error != 0 {
|
||||
return resp, ErrorCapture(resp.Error)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// TransactionHistory stores info about transactions
|
||||
func (l *Lbank) TransactionHistory(symbol, transactionType, startDate, endDate, from, direct, size string) (TransactionHistoryResp, error) {
|
||||
var resp TransactionHistoryResp
|
||||
params := url.Values{}
|
||||
params.Set("symbol", symbol)
|
||||
params.Set("type", transactionType)
|
||||
params.Set("start_date", startDate)
|
||||
params.Set("end_date", endDate)
|
||||
params.Set("from", from)
|
||||
params.Set("direct", direct)
|
||||
params.Set("size", size)
|
||||
path := fmt.Sprintf("%s/v%s/%s?", l.API.Endpoints.URL, lbankAPIVersion, lbankPastTransactions)
|
||||
err := l.SendAuthHTTPRequest(http.MethodPost, path, params, &resp)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if resp.Error != 0 {
|
||||
return resp, ErrorCapture(resp.Error)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetOpenOrders gets opening orders
|
||||
// Lbank returns an empty string as their []OrderResponse instead of returning an empty array, so when len(tempResp.Orders) > 2 its not empty and should be unmarshalled separately
|
||||
func (l *Lbank) GetOpenOrders(pair, pageNumber, pageLength string) (OpenOrderFinalResponse, error) {
|
||||
var resp OpenOrderFinalResponse
|
||||
var tempResp OpenOrderResponse
|
||||
params := url.Values{}
|
||||
params.Set("symbol", pair)
|
||||
params.Set("current_page", pageNumber)
|
||||
params.Set("page_length", pageLength)
|
||||
path := fmt.Sprintf("%s/v%s/%s", l.API.Endpoints.URL, lbankAPIVersion, lbankOpeningOrders)
|
||||
err := l.SendAuthHTTPRequest(http.MethodPost, path, params, &tempResp)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
var totalOrders []OrderResponse
|
||||
if len(tempResp.Orders) > 2 {
|
||||
err = json.Unmarshal(tempResp.Orders, &totalOrders)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
}
|
||||
resp.ErrCapture = tempResp.ErrCapture
|
||||
resp.PageLength = tempResp.PageLength
|
||||
resp.PageNumber = tempResp.PageNumber
|
||||
resp.Orders = totalOrders
|
||||
|
||||
if resp.Error != 0 {
|
||||
return resp, ErrorCapture(resp.Error)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// USD2RMBRate finds USD-CNY Rate
|
||||
func (l *Lbank) USD2RMBRate() (ExchangeRateResponse, error) {
|
||||
var resp ExchangeRateResponse
|
||||
path := fmt.Sprintf("%s/v%s/%s", l.API.Endpoints.URL, lbankAPIVersion, lbankUSD2CNYRate)
|
||||
return resp, l.SendHTTPRequest(path, &resp)
|
||||
}
|
||||
|
||||
// GetWithdrawConfig gets information about withdrawals
|
||||
func (l *Lbank) GetWithdrawConfig(assetCode string) ([]WithdrawConfigResponse, error) {
|
||||
var resp []WithdrawConfigResponse
|
||||
params := url.Values{}
|
||||
params.Set("assetCode", assetCode)
|
||||
path := fmt.Sprintf("%s/v%s/%s?%s", l.API.Endpoints.URL, lbankAPIVersion, lbankWithdrawConfig, params.Encode())
|
||||
return resp, l.SendHTTPRequest(path, &resp)
|
||||
}
|
||||
|
||||
// Withdraw sends a withdrawal request
|
||||
func (l *Lbank) Withdraw(account, assetCode, amount, memo, mark string) (WithdrawResponse, error) {
|
||||
var resp WithdrawResponse
|
||||
params := url.Values{}
|
||||
params.Set("account", account)
|
||||
params.Set("assetCode", assetCode)
|
||||
params.Set("amount", amount)
|
||||
if memo != "" {
|
||||
params.Set("memo", memo)
|
||||
}
|
||||
if mark != "" {
|
||||
params.Set("mark", mark)
|
||||
}
|
||||
path := fmt.Sprintf("%s/v%s/%s", l.API.Endpoints.URL, lbankAPIVersion, lbankWithdraw)
|
||||
err := l.SendAuthHTTPRequest(http.MethodPost, path, params, &resp)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if resp.Error != 0 {
|
||||
return resp, ErrorCapture(resp.Error)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// RevokeWithdraw cancels the withdrawal given the withdrawalID
|
||||
func (l *Lbank) RevokeWithdraw(withdrawID string) (RevokeWithdrawResponse, error) {
|
||||
var resp RevokeWithdrawResponse
|
||||
params := url.Values{}
|
||||
if withdrawID != "" {
|
||||
params.Set("withdrawId", withdrawID)
|
||||
}
|
||||
path := fmt.Sprintf("%s/v%s/%s?", l.API.Endpoints.URL, lbankAPIVersion, lbankRevokeWithdraw)
|
||||
err := l.SendAuthHTTPRequest(http.MethodPost, path, params, &resp)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if resp.Error != 0 {
|
||||
return resp, ErrorCapture(resp.Error)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetWithdrawalRecords gets withdrawal records
|
||||
func (l *Lbank) GetWithdrawalRecords(assetCode, status, pageNo, pageSize string) (WithdrawalResponse, error) {
|
||||
var resp WithdrawalResponse
|
||||
params := url.Values{}
|
||||
params.Set("assetCode", assetCode)
|
||||
params.Set("status", status)
|
||||
params.Set("pageNo", pageNo)
|
||||
params.Set("pageSize", pageSize)
|
||||
path := fmt.Sprintf("%s/v%s/%s", l.API.Endpoints.URL, lbankAPIVersion, lbankWithdrawalRecords)
|
||||
err := l.SendAuthHTTPRequest(http.MethodPost, path, params, &resp)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if resp.Error != 0 {
|
||||
return resp, ErrorCapture(resp.Error)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ErrorCapture captures errors
|
||||
func ErrorCapture(code int64) error {
|
||||
msg, ok := errorCodes[code]
|
||||
if !ok {
|
||||
return fmt.Errorf("undefined code please check api docs for error code definition: %v", code)
|
||||
}
|
||||
return errors.New(msg)
|
||||
}
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (l *Lbank) SendHTTPRequest(path string, result interface{}) error {
|
||||
return l.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
&result,
|
||||
false,
|
||||
false,
|
||||
l.Verbose,
|
||||
l.HTTPDebugging,
|
||||
l.HTTPRecording)
|
||||
}
|
||||
|
||||
func (l *Lbank) loadPrivKey() error {
|
||||
key := strings.Join([]string{
|
||||
"-----BEGIN RSA PRIVATE KEY-----",
|
||||
l.API.Credentials.Secret,
|
||||
"-----END RSA PRIVATE KEY-----",
|
||||
}, "\n")
|
||||
|
||||
block, _ := pem.Decode([]byte(key))
|
||||
if block == nil {
|
||||
return errors.New("pem block is nil")
|
||||
}
|
||||
|
||||
p, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to decode priv key: %s", err)
|
||||
}
|
||||
|
||||
var ok bool
|
||||
l.privateKey, ok = p.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
return errors.New("unable to parse RSA private key")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Lbank) sign(data string) (string, error) {
|
||||
if l.privateKey == nil {
|
||||
return "", errors.New("private key not loaded")
|
||||
}
|
||||
md5hash := gctcrypto.GetMD5([]byte(data))
|
||||
m := strings.ToUpper(gctcrypto.HexEncodeToString(md5hash))
|
||||
s := gctcrypto.GetSHA256([]byte(m))
|
||||
r, err := rsa.SignPKCS1v15(rand.Reader, l.privateKey, crypto.SHA256, s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return gctcrypto.Base64Encode(r), nil
|
||||
}
|
||||
|
||||
// SendAuthHTTPRequest sends an authenticated request
|
||||
func (l *Lbank) SendAuthHTTPRequest(method, endpoint string, vals url.Values, result interface{}) error {
|
||||
if vals == nil {
|
||||
vals = url.Values{}
|
||||
}
|
||||
|
||||
vals.Set("api_key", l.API.Credentials.Key)
|
||||
sig, err := l.sign(vals.Encode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vals.Set("sign", sig)
|
||||
payload := vals.Encode()
|
||||
headers := make(map[string]string)
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
|
||||
return l.SendPayload(method,
|
||||
endpoint,
|
||||
headers,
|
||||
bytes.NewBufferString(payload),
|
||||
&result,
|
||||
true,
|
||||
false,
|
||||
l.Verbose,
|
||||
l.HTTPDebugging,
|
||||
l.HTTPRecording)
|
||||
}
|
||||
396
exchanges/lbank/lbank_test.go
Normal file
396
exchanges/lbank/lbank_test.go
Normal file
@@ -0,0 +1,396 @@
|
||||
package lbank
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
)
|
||||
|
||||
// Please supply your own keys here for due diligence testing
|
||||
const (
|
||||
testAPIKey = ""
|
||||
testAPISecret = ""
|
||||
canManipulateRealOrders = false
|
||||
)
|
||||
|
||||
var l Lbank
|
||||
var setupRan bool
|
||||
var m sync.Mutex
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
t.Parallel()
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
if setupRan {
|
||||
return
|
||||
}
|
||||
l.SetDefaults()
|
||||
cfg := config.GetConfig()
|
||||
err := cfg.LoadConfig("../../testdata/configtest.json")
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Lbank Setup() init error:, %v", err)
|
||||
}
|
||||
lbankConfig, err := cfg.GetExchangeConfig("Lbank")
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Lbank Setup() init error: %v", err)
|
||||
}
|
||||
lbankConfig.API.AuthenticatedSupport = true
|
||||
lbankConfig.API.Credentials.Secret = testAPISecret
|
||||
lbankConfig.API.Credentials.Key = testAPIKey
|
||||
l.Setup(lbankConfig)
|
||||
setupRan = true
|
||||
}
|
||||
|
||||
func areTestAPIKeysSet() bool {
|
||||
return l.AllowAuthenticatedRequest()
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
TestSetup(t)
|
||||
_, err := l.GetTicker("btc_usdt")
|
||||
if err != nil {
|
||||
t.Errorf("test failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCurrencyPairs(t *testing.T) {
|
||||
TestSetup(t)
|
||||
_, err := l.GetCurrencyPairs()
|
||||
if err != nil {
|
||||
t.Errorf("test failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMarketDepths(t *testing.T) {
|
||||
TestSetup(t)
|
||||
_, err := l.GetMarketDepths("btc_usdt", "60", "1")
|
||||
if err != nil {
|
||||
t.Errorf("GetMarketDepth failed: %v", err)
|
||||
}
|
||||
a, _ := l.GetMarketDepths("btc_usdt", "60", "0")
|
||||
if len(a.Asks) != 60 {
|
||||
t.Errorf("length requested doesnt match the output")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTrades(t *testing.T) {
|
||||
TestSetup(t)
|
||||
_, err := l.GetTrades("btc_usdt", "600", fmt.Sprintf("%v", time.Now().Unix()))
|
||||
if err != nil {
|
||||
t.Errorf("test failed: %v", err)
|
||||
}
|
||||
a, err := l.GetTrades("btc_usdt", "600", "0")
|
||||
if len(a) != 600 && err != nil {
|
||||
t.Errorf("test failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetKlines(t *testing.T) {
|
||||
TestSetup(t)
|
||||
_, err := l.GetKlines("btc_usdt", "600", "minute1", fmt.Sprintf("%v", time.Now().Unix()))
|
||||
if err != nil {
|
||||
t.Errorf("test failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateOrderbook(t *testing.T) {
|
||||
TestSetup(t)
|
||||
p := currency.Pair{
|
||||
Delimiter: "_",
|
||||
Base: currency.ETH,
|
||||
Quote: currency.BTC}
|
||||
|
||||
_, err := l.UpdateOrderbook(p.Lower(), "spot")
|
||||
if err != nil {
|
||||
t.Errorf("Update for orderbook failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUserInfo(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := l.GetUserInfo()
|
||||
if err != nil {
|
||||
t.Errorf("invalid key or sign: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateOrder(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), "_")
|
||||
_, err := l.CreateOrder(cp.Lower().String(), "what", 1231, 12314)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - CreateOrder error cannot be nil")
|
||||
}
|
||||
_, err = l.CreateOrder(cp.Lower().String(), "buy", 0, 0)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - CreateOrder error cannot be nil")
|
||||
}
|
||||
_, err = l.CreateOrder(cp.Lower().String(), "sell", 1231, 0)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - CreateOrder error cannot be nil")
|
||||
}
|
||||
_, err = l.CreateOrder(cp.Lower().String(), "buy", 58, 681)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveOrder(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
cp := currency.NewPairWithDelimiter(currency.ETH.String(), currency.BTC.String(), "_")
|
||||
_, err := l.RemoveOrder(cp.Lower().String(), "24f7ce27-af1d-4dca-a8c1-ef1cbeec1b23")
|
||||
if err != nil {
|
||||
t.Errorf("unable to remove order: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryOrder(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), "_")
|
||||
_, err := l.QueryOrder(cp.Lower().String(), "1")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryOrderHistory(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), "_")
|
||||
_, err := l.QueryOrderHistory(cp.Lower().String(), "1", "100")
|
||||
if err != nil {
|
||||
t.Errorf("test failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPairInfo(t *testing.T) {
|
||||
TestSetup(t)
|
||||
_, err := l.GetPairInfo()
|
||||
if err != nil {
|
||||
t.Errorf("couldnt get pair info: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrderTransactionDetails(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := l.OrderTransactionDetails("eth_btc", "24f7ce27-af1d-4dca-a8c1-ef1cbeec1b23")
|
||||
if err != nil {
|
||||
t.Errorf("couldnt get transaction details: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransactionHistory(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := l.TransactionHistory("btc_usdt", "", "", "", "", "", "")
|
||||
if err != nil {
|
||||
t.Errorf("couldnt get transaction history: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOpenOrders(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), "_")
|
||||
_, err := l.GetOpenOrders(cp.Lower().String(), "1", "50")
|
||||
if err != nil {
|
||||
t.Error("unexpected error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUSD2RMBRate(t *testing.T) {
|
||||
TestSetup(t)
|
||||
_, err := l.USD2RMBRate()
|
||||
if err != nil {
|
||||
t.Error("unable to acquire the rate")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetWithdrawConfig(t *testing.T) {
|
||||
TestSetup(t)
|
||||
_, err := l.GetWithdrawConfig("eth")
|
||||
if err != nil {
|
||||
t.Errorf("unable to get withdraw config: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
_, err := l.Withdraw("", "", "", "", "")
|
||||
if err != nil {
|
||||
t.Errorf("unable to withdraw: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetWithdrawRecords(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := l.GetWithdrawalRecords("eth", "0", "1", "20")
|
||||
if err != nil {
|
||||
t.Errorf("unable to get withdrawal records: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadPrivKey(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
err := l.loadPrivKey()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
l.API.Credentials.Secret = "errortest"
|
||||
err = l.loadPrivKey()
|
||||
if err == nil {
|
||||
t.Errorf("expected error due to pemblock nil, got err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
l.API.Credentials.Secret = testAPISecret
|
||||
l.loadPrivKey()
|
||||
_, err := l.sign("hello123")
|
||||
if err != nil {
|
||||
t.Errorf("test failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubmitOrder(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
var orderSubmission = &exchange.OrderSubmission{
|
||||
Pair: currency.Pair{
|
||||
Base: currency.BTC,
|
||||
Quote: currency.USDT,
|
||||
Delimiter: "_",
|
||||
},
|
||||
OrderSide: exchange.BuyOrderSide,
|
||||
OrderType: exchange.LimitOrderType,
|
||||
Price: 1,
|
||||
Amount: 1,
|
||||
ClientID: "meowOrder",
|
||||
}
|
||||
response, err := l.SubmitOrder(orderSubmission)
|
||||
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
|
||||
t.Errorf("Order failed to be placed: %v", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelOrder(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
cp := currency.NewPairWithDelimiter(currency.ETH.String(), currency.BTC.String(), "_")
|
||||
var a exchange.OrderCancellation
|
||||
a.CurrencyPair = cp
|
||||
a.OrderID = "24f7ce27-af1d-4dca-a8c1-ef1cbeec1b23"
|
||||
err := l.CancelOrder(&a)
|
||||
if err != nil {
|
||||
t.Errorf("test failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderInfo(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := l.GetOrderInfo("9ead39f5-701a-400b-b635-d7349eb0f6b")
|
||||
if err != nil {
|
||||
t.Errorf("test failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAllOpenOrderID(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := l.getAllOpenOrderID()
|
||||
if err != nil {
|
||||
t.Errorf("test failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFeeByType(t *testing.T) {
|
||||
TestSetup(t)
|
||||
cp := currency.NewPairWithDelimiter(currency.BTC.String(), currency.USDT.String(), "_")
|
||||
var input exchange.FeeBuilder
|
||||
input.Amount = 2
|
||||
input.FeeType = exchange.CryptocurrencyWithdrawalFee
|
||||
input.Pair = cp
|
||||
a, err := l.GetFeeByType(&input)
|
||||
if err != nil {
|
||||
t.Errorf("test failed. couldnt get fee: %v", err)
|
||||
}
|
||||
if a != 0.0005 {
|
||||
t.Errorf("testGetFeeByType failed. Expected: 0.0005, Received: %v", a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccountInfo(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := l.GetAccountInfo()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
TestSetup(t)
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
var input exchange.GetOrdersRequest
|
||||
input.OrderSide = exchange.BuyOrderSide
|
||||
_, err := l.GetOrderHistory(&input)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
270
exchanges/lbank/lbank_types.go
Normal file
270
exchanges/lbank/lbank_types.go
Normal file
@@ -0,0 +1,270 @@
|
||||
package lbank
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Ticker stores the ticker price data for a currency pair
|
||||
type Ticker struct {
|
||||
Change float64 `json:"change"`
|
||||
High float64 `json:"high"`
|
||||
Latest float64 `json:"latest"`
|
||||
Low float64 `json:"low"`
|
||||
Turnover float64 `json:"turnover"`
|
||||
Volume float64 `json:"vol"`
|
||||
}
|
||||
|
||||
// TickerResponse stores the ticker price data and timestamp for a currency pair
|
||||
type TickerResponse struct {
|
||||
Symbol string `json:"symbol"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Ticker Ticker `json:"ticker"`
|
||||
}
|
||||
|
||||
// MarketDepthResponse stores arrays for asks, bids and a timestamp for a currecy pair
|
||||
type MarketDepthResponse struct {
|
||||
ErrCapture `json:",omitempty"`
|
||||
Asks [][]float64 `json:"asks"`
|
||||
Bids [][]float64 `json:"bids"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
// TradeResponse stores date_ms, amount, price, type, tid for a currency pair
|
||||
type TradeResponse struct {
|
||||
DateMS int64 `json:"date_ms"`
|
||||
Amount float64 `json:"amount"`
|
||||
Price float64 `json:"price"`
|
||||
Type string `json:"type"`
|
||||
TID string `json:"tid"`
|
||||
}
|
||||
|
||||
// KlineResponse stores kline info for given currency exchange
|
||||
type KlineResponse struct {
|
||||
TimeStamp int64 `json:"timestamp"`
|
||||
OpenPrice float64 `json:"openprice"`
|
||||
HigestPrice float64 `json:"highestprice"`
|
||||
LowestPrice float64 `json:"lowestprice"`
|
||||
ClosePrice float64 `json:"closeprice"`
|
||||
TradingVolume float64 `json:"tradingvolume"`
|
||||
}
|
||||
|
||||
// InfoResponse stores info
|
||||
type InfoResponse struct {
|
||||
Freeze map[string]string `json:"freeze"`
|
||||
Asset map[string]string `json:"asset"`
|
||||
Free map[string]string `json:"Free"`
|
||||
}
|
||||
|
||||
// InfoFinalResponse stores info
|
||||
type InfoFinalResponse struct {
|
||||
ErrCapture `json:",omitempty"`
|
||||
Info InfoResponse `json:"info"`
|
||||
}
|
||||
|
||||
// CreateOrderResponse stores the result of the Order and
|
||||
type CreateOrderResponse struct {
|
||||
ErrCapture `json:",omitempty"`
|
||||
OrderID string `json:"order_id"`
|
||||
}
|
||||
|
||||
// RemoveOrderResponse stores the result when an order is cancelled
|
||||
type RemoveOrderResponse struct {
|
||||
ErrCapture `json:",omitempty"`
|
||||
Err string `json:"error"`
|
||||
OrderID string `json:"order_id"`
|
||||
Success string `json:"success"`
|
||||
}
|
||||
|
||||
// OrderResponse stores the data related to the given OrderIDs
|
||||
type OrderResponse struct {
|
||||
Symbol string `json:"symbol"`
|
||||
Amount float64 `json:"amount"`
|
||||
CreateTime int64 `json:"created_time"`
|
||||
Price float64 `json:"price"`
|
||||
AvgPrice float64 `json:"avg_price"`
|
||||
Type string `json:"type"`
|
||||
OrderID string `json:"order_id"`
|
||||
DealAmount float64 `json:"deal_amount"`
|
||||
Status int64 `json:"status"`
|
||||
}
|
||||
|
||||
// QueryOrderResponse stores the data from queries
|
||||
type QueryOrderResponse struct {
|
||||
ErrCapture `json:",omitempty"`
|
||||
Orders json.RawMessage `json:"orders"`
|
||||
}
|
||||
|
||||
// QueryOrderFinalResponse stores data from queries
|
||||
type QueryOrderFinalResponse struct {
|
||||
ErrCapture
|
||||
Orders []OrderResponse
|
||||
}
|
||||
|
||||
// OrderHistory stores data for past orders
|
||||
type OrderHistory struct {
|
||||
Result bool `json:"result,string"`
|
||||
Total string `json:"total"`
|
||||
PageLength uint8 `json:"page_length"`
|
||||
Orders json.RawMessage `json:"orders"`
|
||||
CurrentPage uint8 `json:"current_page"`
|
||||
ErrorCode int64 `json:"error_code"`
|
||||
}
|
||||
|
||||
// OrderHistoryResponse stores past orders
|
||||
type OrderHistoryResponse struct {
|
||||
ErrCapture `json:",omitempty"`
|
||||
PageLength uint8 `json:"page_length"`
|
||||
Orders json.RawMessage `json:"orders"`
|
||||
CurrentPage uint8 `json:"current_page"`
|
||||
}
|
||||
|
||||
// OrderHistoryFinalResponse stores past orders
|
||||
type OrderHistoryFinalResponse struct {
|
||||
ErrCapture
|
||||
PageLength uint8
|
||||
Orders []OrderResponse
|
||||
CurrentPage uint8
|
||||
}
|
||||
|
||||
// PairInfoResponse stores information about trading pairs
|
||||
type PairInfoResponse struct {
|
||||
MinimumQuantity string `json:"minTranQua"`
|
||||
PriceAccuracy string `json:"priceAccuracy"`
|
||||
QuantityAccuracy string `json:"quantityAccuracy"`
|
||||
Symbol string `json:"symbol"`
|
||||
}
|
||||
|
||||
// TransactionTemp stores details about transactions
|
||||
type TransactionTemp struct {
|
||||
TxUUID string `json:"txUuid"`
|
||||
OrderUUID string `json:"orderUuid"`
|
||||
TradeType string `json:"tradeType"`
|
||||
DealTime int64 `json:"dealTime"`
|
||||
DealPrice float64 `json:"dealPrice"`
|
||||
DealQuantity float64 `json:"dealQuantity"`
|
||||
DealVolPrice float64 `json:"dealVolumePrice"`
|
||||
TradeFee float64 `json:"tradeFee"`
|
||||
TradeFeeRate float64 `json:"tradeFeeRate"`
|
||||
}
|
||||
|
||||
// TransactionHistoryResp stores details about past transactions
|
||||
type TransactionHistoryResp struct {
|
||||
ErrCapture `json:",omitempty"`
|
||||
Transaction []TransactionTemp `json:"transaction"`
|
||||
}
|
||||
|
||||
// OpenOrderResponse stores information about the opening orders
|
||||
type OpenOrderResponse struct {
|
||||
ErrCapture `json:",omitempty"`
|
||||
PageLength uint8 `json:"page_length"`
|
||||
PageNumber uint8 `json:"page_number"`
|
||||
Total string `json:"total"`
|
||||
Orders json.RawMessage `json:"orders"`
|
||||
}
|
||||
|
||||
// OpenOrderFinalResponse stores the unmarshalled value of OpenOrderResponse
|
||||
type OpenOrderFinalResponse struct {
|
||||
ErrCapture
|
||||
PageLength uint8
|
||||
PageNumber uint8
|
||||
Total string
|
||||
Orders []OrderResponse
|
||||
}
|
||||
|
||||
// ExchangeRateResponse stores information about USD-RMB rate
|
||||
type ExchangeRateResponse struct {
|
||||
USD2CNY string `json:"USD2CNY"`
|
||||
}
|
||||
|
||||
// WithdrawConfigResponse stores info about withdrawal configurations
|
||||
type WithdrawConfigResponse struct {
|
||||
AssetCode string `json:"assetCode"`
|
||||
Minimum string `json:"min"`
|
||||
CanWithDraw bool `json:"canWithDraw"`
|
||||
Fee string `json:"fee"`
|
||||
}
|
||||
|
||||
// WithdrawResponse stores info about the withdrawal
|
||||
type WithdrawResponse struct {
|
||||
ErrCapture `json:",omitempty"`
|
||||
WithdrawID string `json:"withdrawId"`
|
||||
Fee float64 `json:"fee"`
|
||||
}
|
||||
|
||||
// RevokeWithdrawResponse stores info about the revoked withdrawal
|
||||
type RevokeWithdrawResponse struct {
|
||||
ErrCapture `json:",omitempty"`
|
||||
WithdrawID string `json:"string"`
|
||||
}
|
||||
|
||||
// ListDataResponse contains some of withdrawal data
|
||||
type ListDataResponse struct {
|
||||
ErrCapture `json:",omitempty"`
|
||||
Amount float64 `json:"amount"`
|
||||
AssetCode string `json:"assetCode"`
|
||||
Address string `json:"address"`
|
||||
Fee float64 `json:"fee"`
|
||||
ID int64 `json:"id"`
|
||||
Time int64 `json:"time"`
|
||||
TXHash string `json:"txhash"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// WithdrawalResponse stores data for withdrawals
|
||||
type WithdrawalResponse struct {
|
||||
ErrCapture `json:",omitempty"`
|
||||
TotalPages int64 `json:"totalPages"`
|
||||
PageSize int64 `json:"pageSize"`
|
||||
PageNo int64 `json:"pageNo"`
|
||||
List []ListDataResponse `json:"list"`
|
||||
}
|
||||
|
||||
// ErrCapture helps with error info
|
||||
type ErrCapture struct {
|
||||
Error int64 `json:"error_code"`
|
||||
Result bool `json:"result,string"`
|
||||
}
|
||||
|
||||
// GetAllOpenIDResp stores orderIds and currency pairs for open orders
|
||||
type GetAllOpenIDResp struct {
|
||||
CurrencyPair string
|
||||
OrderID string
|
||||
}
|
||||
|
||||
var errorCodes = map[int64]string{
|
||||
10000: "Internal error",
|
||||
10001: "The required parameters can not be empty",
|
||||
10002: "Validation Failed",
|
||||
10003: "Invalid parameter",
|
||||
10004: "Request too frequent",
|
||||
10005: "Secret key does not exist",
|
||||
10006: "User does not exist",
|
||||
10007: "Invalid signature",
|
||||
10008: "Invalid Trading Pair",
|
||||
10009: "Price and/or Amount are required for limit order",
|
||||
10010: "Price and/or Amount must be more than 0",
|
||||
10013: "The amount is too small",
|
||||
10014: "Insufficient amount of money in account",
|
||||
10015: "Invalid order type",
|
||||
10016: "Insufficient account balance",
|
||||
10017: "Server Error",
|
||||
10018: "Page size should be between 1 and 50",
|
||||
10019: "Cancel NO more than 3 orders in one request",
|
||||
10020: "Volume < 0.001",
|
||||
10021: "Price < 0.01",
|
||||
10022: "Access denied",
|
||||
10023: "Market Order is not supported yet.",
|
||||
10024: "User cannot trade on this pair",
|
||||
10025: "Order has been filled",
|
||||
10026: "Order has been cancelld",
|
||||
10027: "Order is cancelling",
|
||||
10028: "Wrong query time",
|
||||
10029: "'from' is not in the query time",
|
||||
10030: "'from' does not match the transaction type of inqury",
|
||||
10100: "Has no privilege to withdraw",
|
||||
10101: "Invalid fee rate to withdraw",
|
||||
10102: "Too little to withdraw",
|
||||
10103: "Exceed daily limitation of withdraw",
|
||||
10104: "Cancel was rejected",
|
||||
10105: "Request has been cancelled",
|
||||
}
|
||||
668
exchanges/lbank/lbank_wrapper.go
Normal file
668
exchanges/lbank/lbank_wrapper.go
Normal file
@@ -0,0 +1,668 @@
|
||||
package lbank
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
|
||||
log "github.com/thrasher-corp/gocryptotrader/logger"
|
||||
)
|
||||
|
||||
// GetDefaultConfig returns a default exchange config
|
||||
func (l *Lbank) GetDefaultConfig() (*config.ExchangeConfig, error) {
|
||||
l.SetDefaults()
|
||||
exchCfg := new(config.ExchangeConfig)
|
||||
exchCfg.Name = l.Name
|
||||
exchCfg.HTTPTimeout = exchange.DefaultHTTPTimeout
|
||||
exchCfg.BaseCurrencies = l.BaseCurrencies
|
||||
|
||||
err := l.SetupDefaults(exchCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if l.Features.Supports.RESTCapabilities.AutoPairUpdates {
|
||||
err = l.UpdateTradablePairs(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return exchCfg, nil
|
||||
}
|
||||
|
||||
// SetDefaults sets the basic defaults for Lbank
|
||||
func (l *Lbank) SetDefaults() {
|
||||
l.Name = "Lbank"
|
||||
l.Enabled = true
|
||||
l.Verbose = true
|
||||
l.API.CredentialsValidator.RequiresKey = true
|
||||
l.API.CredentialsValidator.RequiresSecret = true
|
||||
|
||||
l.CurrencyPairs = currency.PairsManager{
|
||||
AssetTypes: asset.Items{
|
||||
asset.Spot,
|
||||
},
|
||||
|
||||
UseGlobalFormat: true,
|
||||
RequestFormat: ¤cy.PairFormat{
|
||||
Delimiter: "_",
|
||||
},
|
||||
ConfigFormat: ¤cy.PairFormat{
|
||||
Delimiter: "_",
|
||||
},
|
||||
}
|
||||
|
||||
l.Features = exchange.Features{
|
||||
Supports: exchange.FeaturesSupported{
|
||||
REST: true,
|
||||
RESTCapabilities: exchange.ProtocolFeatures{
|
||||
AutoPairUpdates: true,
|
||||
},
|
||||
WithdrawPermissions: exchange.AutoWithdrawCryptoWithAPIPermission |
|
||||
exchange.NoFiatWithdrawals,
|
||||
},
|
||||
Enabled: exchange.FeaturesEnabled{
|
||||
AutoPairUpdates: true,
|
||||
},
|
||||
}
|
||||
|
||||
l.Requester = request.New(l.Name,
|
||||
request.NewRateLimit(time.Second, lbankAuthRateLimit),
|
||||
request.NewRateLimit(time.Second, lbankUnAuthRateLimit),
|
||||
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout))
|
||||
|
||||
l.API.Endpoints.URLDefault = lbankAPIURL
|
||||
l.API.Endpoints.URL = l.API.Endpoints.URLDefault
|
||||
}
|
||||
|
||||
// Setup sets exchange configuration profile
|
||||
func (l *Lbank) Setup(exch *config.ExchangeConfig) error {
|
||||
if !exch.Enabled {
|
||||
l.SetEnabled(false)
|
||||
return nil
|
||||
}
|
||||
|
||||
err := l.SetupDefaults(exch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if l.API.AuthenticatedSupport {
|
||||
err = l.loadPrivKey()
|
||||
if err != nil {
|
||||
l.API.AuthenticatedSupport = false
|
||||
log.Errorf(log.ExchangeSys, "%s couldn't load private key, setting authenticated support to false", l.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start starts the LakeBTC go routine
|
||||
func (l *Lbank) Start(wg *sync.WaitGroup) {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
l.Run()
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
// Run implements the Lbank wrapper
|
||||
func (l *Lbank) Run() {
|
||||
if l.Verbose {
|
||||
l.PrintEnabledPairs()
|
||||
}
|
||||
|
||||
if !l.GetEnabledFeatures().AutoPairUpdates {
|
||||
return
|
||||
}
|
||||
|
||||
err := l.UpdateTradablePairs(false)
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", l.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
// FetchTradablePairs returns a list of the exchanges tradable pairs
|
||||
func (l *Lbank) FetchTradablePairs(asset asset.Item) ([]string, error) {
|
||||
currencies, err := l.GetCurrencyPairs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return currencies, nil
|
||||
}
|
||||
|
||||
// UpdateTradablePairs updates the exchanges available pairs and stores
|
||||
// them in the exchanges config
|
||||
func (l *Lbank) UpdateTradablePairs(forceUpdate bool) error {
|
||||
pairs, err := l.FetchTradablePairs(asset.Spot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return l.UpdatePairs(currency.NewPairsFromStrings(pairs), asset.Spot, false, forceUpdate)
|
||||
}
|
||||
|
||||
// UpdateTicker updates and returns the ticker for a currency pair
|
||||
func (l *Lbank) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
|
||||
var tickerPrice ticker.Price
|
||||
tickerInfo, err := l.GetTicker(l.FormatExchangeCurrency(p, assetType).String())
|
||||
if err != nil {
|
||||
return tickerPrice, err
|
||||
}
|
||||
tickerPrice.Pair = p
|
||||
tickerPrice.Last = tickerInfo.Ticker.Latest
|
||||
tickerPrice.High = tickerInfo.Ticker.High
|
||||
tickerPrice.Volume = tickerInfo.Ticker.Volume
|
||||
tickerPrice.Low = tickerInfo.Ticker.Low
|
||||
|
||||
err = ticker.ProcessTicker(l.GetName(), &tickerPrice, assetType)
|
||||
if err != nil {
|
||||
return tickerPrice, err
|
||||
}
|
||||
|
||||
return ticker.GetTicker(l.Name, p, assetType)
|
||||
}
|
||||
|
||||
// FetchTicker returns the ticker for a currency pair
|
||||
func (l *Lbank) FetchTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
|
||||
tickerNew, err := ticker.GetTicker(l.GetName(),
|
||||
l.FormatExchangeCurrency(p, assetType), assetType)
|
||||
if err != nil {
|
||||
return l.UpdateTicker(p, assetType)
|
||||
}
|
||||
return tickerNew, nil
|
||||
}
|
||||
|
||||
// FetchOrderbook returns orderbook base on the currency pair
|
||||
func (l *Lbank) FetchOrderbook(currency currency.Pair, assetType asset.Item) (orderbook.Base, error) {
|
||||
ob, err := orderbook.Get(l.GetName(), currency, assetType)
|
||||
if err != nil {
|
||||
return l.UpdateOrderbook(currency, assetType)
|
||||
}
|
||||
return ob, nil
|
||||
}
|
||||
|
||||
// UpdateOrderbook updates and returns the orderbook for a currency pair
|
||||
func (l *Lbank) UpdateOrderbook(p currency.Pair, assetType asset.Item) (orderbook.Base, error) {
|
||||
var orderBook orderbook.Base
|
||||
a, err := l.GetMarketDepths(l.FormatExchangeCurrency(p, assetType).String(), "60", "1")
|
||||
if err != nil {
|
||||
return orderBook, err
|
||||
}
|
||||
for i := range a.Asks {
|
||||
orderBook.Asks = append(orderBook.Asks, orderbook.Item{
|
||||
Price: a.Asks[i][0],
|
||||
Amount: a.Asks[i][1]})
|
||||
}
|
||||
for i := range a.Bids {
|
||||
orderBook.Bids = append(orderBook.Bids, orderbook.Item{
|
||||
Price: a.Bids[i][0],
|
||||
Amount: a.Bids[i][1]})
|
||||
}
|
||||
orderBook.Pair = p
|
||||
orderBook.ExchangeName = l.GetName()
|
||||
orderBook.AssetType = assetType
|
||||
err = orderBook.Process()
|
||||
if err != nil {
|
||||
return orderBook, err
|
||||
}
|
||||
|
||||
return orderbook.Get(l.Name, p, assetType)
|
||||
}
|
||||
|
||||
// GetAccountInfo retrieves balances for all enabled currencies for the
|
||||
// Lbank exchange
|
||||
func (l *Lbank) GetAccountInfo() (exchange.AccountInfo, error) {
|
||||
var info exchange.AccountInfo
|
||||
data, err := l.GetUserInfo()
|
||||
if err != nil {
|
||||
return info, err
|
||||
}
|
||||
var account exchange.Account
|
||||
for key, val := range data.Info.Asset {
|
||||
c := currency.NewCode(key)
|
||||
hold, ok := data.Info.Freeze[key]
|
||||
if !ok {
|
||||
return info, fmt.Errorf("hold data not found with %s", key)
|
||||
}
|
||||
totalVal, err := strconv.ParseFloat(val, 64)
|
||||
if err != nil {
|
||||
return info, err
|
||||
}
|
||||
totalHold, err := strconv.ParseFloat(hold, 64)
|
||||
if err != nil {
|
||||
return info, err
|
||||
}
|
||||
account.Currencies = append(account.Currencies,
|
||||
exchange.AccountCurrencyInfo{CurrencyName: c,
|
||||
TotalValue: totalVal,
|
||||
Hold: totalHold})
|
||||
}
|
||||
|
||||
info.Accounts = append(info.Accounts, account)
|
||||
info.Exchange = l.GetName()
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// GetFundingHistory returns funding history, deposits and
|
||||
// withdrawals
|
||||
func (l *Lbank) GetFundingHistory() ([]exchange.FundHistory, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetExchangeHistory returns historic trade data since exchange opening.
|
||||
func (l *Lbank) GetExchangeHistory(p currency.Pair, assetType asset.Item) ([]exchange.TradeHistory, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (l *Lbank) SubmitOrder(order *exchange.OrderSubmission) (exchange.SubmitOrderResponse, error) {
|
||||
var resp exchange.SubmitOrderResponse
|
||||
if order == nil {
|
||||
return resp, exchange.ErrOrderSubmissionIsNil
|
||||
}
|
||||
|
||||
if err := order.Validate(); err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if order.OrderSide != exchange.BuyOrderSide &&
|
||||
order.OrderSide != exchange.SellOrderSide {
|
||||
return resp,
|
||||
fmt.Errorf("%s order side is not supported by the exchange",
|
||||
order.OrderSide)
|
||||
}
|
||||
tempResp, err := l.CreateOrder(
|
||||
l.FormatExchangeCurrency(order.Pair, asset.Spot).String(),
|
||||
order.OrderSide.ToString(),
|
||||
order.Amount,
|
||||
order.Price)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
resp.IsOrderPlaced = true
|
||||
resp.OrderID = tempResp.OrderID
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ModifyOrder will allow of changing orderbook placement and limit to
|
||||
// market conversion
|
||||
func (l *Lbank) ModifyOrder(action *exchange.ModifyOrder) (string, error) {
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// CancelOrder cancels an order by its corresponding ID number
|
||||
func (l *Lbank) CancelOrder(order *exchange.OrderCancellation) error {
|
||||
_, err := l.RemoveOrder(l.FormatExchangeCurrency(order.CurrencyPair,
|
||||
order.AssetType).String(), order.OrderID)
|
||||
return err
|
||||
}
|
||||
|
||||
// CancelAllOrders cancels all orders associated with a currency pair
|
||||
func (l *Lbank) CancelAllOrders(orders *exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) {
|
||||
var resp exchange.CancelAllOrdersResponse
|
||||
orderIDs, err := l.getAllOpenOrderID()
|
||||
if err != nil {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
for key := range orderIDs {
|
||||
if key != orders.CurrencyPair.String() {
|
||||
continue
|
||||
}
|
||||
var x, y = 0, 0
|
||||
var input string
|
||||
var tempSlice []string
|
||||
for x <= len(orderIDs[key]) {
|
||||
x++
|
||||
for y != x {
|
||||
tempSlice = append(tempSlice, orderIDs[key][y])
|
||||
if y%3 == 0 {
|
||||
input = strings.Join(tempSlice, ",")
|
||||
CancelResponse, err2 := l.RemoveOrder(key, input)
|
||||
if err2 != nil {
|
||||
return resp, err2
|
||||
}
|
||||
tempStringSuccess := strings.Split(CancelResponse.Success, ",")
|
||||
for k := range tempStringSuccess {
|
||||
resp.OrderStatus[tempStringSuccess[k]] = "Cancelled"
|
||||
}
|
||||
tempStringError := strings.Split(CancelResponse.Err, ",")
|
||||
for l := range tempStringError {
|
||||
resp.OrderStatus[tempStringError[l]] = "Failed"
|
||||
}
|
||||
tempSlice = tempSlice[:0]
|
||||
y++
|
||||
}
|
||||
y++
|
||||
}
|
||||
input = strings.Join(tempSlice, ",")
|
||||
CancelResponse, err2 := l.RemoveOrder(key, input)
|
||||
if err2 != nil {
|
||||
return resp, err2
|
||||
}
|
||||
tempStringSuccess := strings.Split(CancelResponse.Success, ",")
|
||||
for k := range tempStringSuccess {
|
||||
resp.OrderStatus[tempStringSuccess[k]] = "Cancelled"
|
||||
}
|
||||
tempStringError := strings.Split(CancelResponse.Err, ",")
|
||||
for l := range tempStringError {
|
||||
resp.OrderStatus[tempStringError[l]] = "Failed"
|
||||
}
|
||||
tempSlice = tempSlice[:0]
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (l *Lbank) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var resp exchange.OrderDetail
|
||||
orderIDs, err := l.getAllOpenOrderID()
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
for key, val := range orderIDs {
|
||||
for i := range val {
|
||||
if val[i] != orderID {
|
||||
continue
|
||||
}
|
||||
tempResp, err := l.QueryOrder(key, orderID)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
resp.Exchange = l.GetName()
|
||||
resp.CurrencyPair = currency.NewPairFromString(key)
|
||||
if strings.EqualFold(tempResp.Orders[0].Type, "buy") {
|
||||
resp.OrderSide = exchange.BuyOrderSide
|
||||
} else {
|
||||
resp.OrderSide = exchange.SellOrderSide
|
||||
}
|
||||
z := tempResp.Orders[0].Status
|
||||
switch {
|
||||
case z == -1:
|
||||
resp.Status = "cancelled"
|
||||
case z == 0:
|
||||
resp.Status = "on trading"
|
||||
case z == 1:
|
||||
resp.Status = "filled partially"
|
||||
case z == 2:
|
||||
resp.Status = "Filled totally"
|
||||
case z == 4:
|
||||
resp.Status = "Cancelling"
|
||||
default:
|
||||
resp.Status = "Invalid Order Status"
|
||||
}
|
||||
resp.Price = tempResp.Orders[0].Price
|
||||
resp.Amount = tempResp.Orders[0].Amount
|
||||
resp.ExecutedAmount = tempResp.Orders[0].DealAmount
|
||||
resp.RemainingAmount = tempResp.Orders[0].Amount - tempResp.Orders[0].DealAmount
|
||||
resp.Fee, err = l.GetFeeByType(&exchange.FeeBuilder{
|
||||
FeeType: exchange.CryptocurrencyTradeFee,
|
||||
Amount: tempResp.Orders[0].Amount,
|
||||
PurchasePrice: tempResp.Orders[0].Price})
|
||||
if err != nil {
|
||||
resp.Fee = lbankFeeNotFound
|
||||
}
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetDepositAddress returns a deposit address for a specified currency
|
||||
func (l *Lbank) GetDepositAddress(cryptocurrency currency.Code, accountID string) (string, error) {
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func (l *Lbank) WithdrawCryptocurrencyFunds(withdrawRequest *exchange.CryptoWithdrawRequest) (string, error) {
|
||||
resp, err := l.Withdraw(withdrawRequest.Address, withdrawRequest.Currency.String(), strconv.FormatFloat(withdrawRequest.Amount, 'f', -1, 64), "", withdrawRequest.Description)
|
||||
return resp.WithdrawID, err
|
||||
}
|
||||
|
||||
// WithdrawFiatFunds returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func (l *Lbank) WithdrawFiatFunds(withdrawRequest *exchange.FiatWithdrawRequest) (string, error) {
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func (l *Lbank) WithdrawFiatFundsToInternationalBank(withdrawRequest *exchange.FiatWithdrawRequest) (string, error) {
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetWebsocket returns a pointer to the exchange websocket
|
||||
func (l *Lbank) GetWebsocket() (*wshandler.Websocket, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetActiveOrders retrieves any orders that are active/open
|
||||
func (l *Lbank) GetActiveOrders(getOrdersRequest *exchange.GetOrdersRequest) ([]exchange.OrderDetail, error) {
|
||||
var finalResp []exchange.OrderDetail
|
||||
var resp exchange.OrderDetail
|
||||
tempData, err := l.getAllOpenOrderID()
|
||||
if err != nil {
|
||||
return finalResp, err
|
||||
}
|
||||
|
||||
for key, val := range tempData {
|
||||
for x := range val {
|
||||
tempResp, err := l.QueryOrder(key, val[x])
|
||||
if err != nil {
|
||||
return finalResp, err
|
||||
}
|
||||
resp.Exchange = l.GetName()
|
||||
resp.CurrencyPair = currency.NewPairFromString(key)
|
||||
if strings.EqualFold(tempResp.Orders[0].Type, "buy") {
|
||||
resp.OrderSide = exchange.BuyOrderSide
|
||||
} else {
|
||||
resp.OrderSide = exchange.SellOrderSide
|
||||
}
|
||||
z := tempResp.Orders[0].Status
|
||||
switch {
|
||||
case z == -1:
|
||||
resp.Status = "cancelled"
|
||||
case z == 1:
|
||||
resp.Status = "on trading"
|
||||
case z == 2:
|
||||
resp.Status = "filled partially"
|
||||
case z == 3:
|
||||
resp.Status = "Filled totally"
|
||||
case z == 4:
|
||||
resp.Status = "Cancelling"
|
||||
default:
|
||||
resp.Status = "Invalid Order Status"
|
||||
}
|
||||
resp.Price = tempResp.Orders[0].Price
|
||||
resp.Amount = tempResp.Orders[0].Amount
|
||||
resp.OrderDate = time.Unix(tempResp.Orders[0].CreateTime, 9)
|
||||
resp.ExecutedAmount = tempResp.Orders[0].DealAmount
|
||||
resp.RemainingAmount = tempResp.Orders[0].Amount - tempResp.Orders[0].DealAmount
|
||||
resp.Fee, err = l.GetFeeByType(&exchange.FeeBuilder{
|
||||
FeeType: exchange.CryptocurrencyTradeFee,
|
||||
Amount: tempResp.Orders[0].Amount,
|
||||
PurchasePrice: tempResp.Orders[0].Price})
|
||||
if err != nil {
|
||||
resp.Fee = lbankFeeNotFound
|
||||
}
|
||||
for y := int(0); y < len(getOrdersRequest.Currencies); y++ {
|
||||
if getOrdersRequest.Currencies[y].String() != key {
|
||||
continue
|
||||
}
|
||||
if getOrdersRequest.OrderSide == "ANY" {
|
||||
finalResp = append(finalResp, resp)
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(getOrdersRequest.OrderSide.ToString(), tempResp.Orders[0].Type) {
|
||||
finalResp = append(finalResp, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return finalResp, nil
|
||||
}
|
||||
|
||||
// GetOrderHistory retrieves account order information *
|
||||
// Can Limit response to specific order status
|
||||
func (l *Lbank) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest) ([]exchange.OrderDetail, error) {
|
||||
var finalResp []exchange.OrderDetail
|
||||
var resp exchange.OrderDetail
|
||||
var tempCurr currency.Pairs
|
||||
var x int
|
||||
if len(getOrdersRequest.Currencies) == 0 {
|
||||
tempCurr = l.GetEnabledPairs(asset.Spot)
|
||||
} else {
|
||||
for x < len(getOrdersRequest.Currencies) {
|
||||
tempCurr = getOrdersRequest.Currencies
|
||||
}
|
||||
}
|
||||
for a := range tempCurr {
|
||||
p := l.FormatExchangeCurrency(tempCurr[a], asset.Spot).String()
|
||||
b := int64(1)
|
||||
tempResp, err := l.QueryOrderHistory(p, strconv.FormatInt(b, 10), "200")
|
||||
if err != nil {
|
||||
return finalResp, err
|
||||
}
|
||||
for len(tempResp.Orders) != 0 {
|
||||
tempResp, err = l.QueryOrderHistory(p, strconv.FormatInt(b, 10), "200")
|
||||
if err != nil {
|
||||
return finalResp, err
|
||||
}
|
||||
for x := 0; x < len(tempResp.Orders); x++ {
|
||||
resp.Exchange = l.GetName()
|
||||
resp.CurrencyPair = currency.NewPairFromString(tempResp.Orders[x].Symbol)
|
||||
if strings.EqualFold(tempResp.Orders[x].Type, "buy") {
|
||||
resp.OrderSide = exchange.BuyOrderSide
|
||||
} else {
|
||||
resp.OrderSide = exchange.SellOrderSide
|
||||
}
|
||||
z := tempResp.Orders[x].Status
|
||||
switch {
|
||||
case z == -1:
|
||||
resp.Status = "cancelled"
|
||||
case z == 1:
|
||||
resp.Status = "on trading"
|
||||
case z == 2:
|
||||
resp.Status = "filled partially"
|
||||
case z == 3:
|
||||
resp.Status = "Filled totally"
|
||||
case z == 4:
|
||||
resp.Status = "Cancelling"
|
||||
default:
|
||||
resp.Status = "Invalid Order Status"
|
||||
}
|
||||
resp.Price = tempResp.Orders[x].Price
|
||||
resp.Amount = tempResp.Orders[x].Amount
|
||||
resp.OrderDate = time.Unix(tempResp.Orders[x].CreateTime, 9)
|
||||
resp.ExecutedAmount = tempResp.Orders[x].DealAmount
|
||||
resp.RemainingAmount = tempResp.Orders[x].Price - tempResp.Orders[x].DealAmount
|
||||
resp.Fee, err = l.GetFeeByType(&exchange.FeeBuilder{
|
||||
FeeType: exchange.CryptocurrencyTradeFee,
|
||||
Amount: tempResp.Orders[x].Amount,
|
||||
PurchasePrice: tempResp.Orders[x].Price})
|
||||
if err != nil {
|
||||
resp.Fee = lbankFeeNotFound
|
||||
}
|
||||
finalResp = append(finalResp, resp)
|
||||
b++
|
||||
}
|
||||
}
|
||||
}
|
||||
return finalResp, nil
|
||||
}
|
||||
|
||||
// GetFeeByType returns an estimate of fee based on the type of transaction *
|
||||
func (l *Lbank) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
var resp float64
|
||||
if feeBuilder.FeeType == exchange.CryptocurrencyTradeFee {
|
||||
return feeBuilder.Amount * feeBuilder.PurchasePrice * 0.002, nil
|
||||
}
|
||||
if feeBuilder.FeeType == exchange.CryptocurrencyWithdrawalFee {
|
||||
withdrawalFee, err := l.GetWithdrawConfig(feeBuilder.Pair.Base.Lower().String())
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
var tempFee string
|
||||
temp := strings.Split(withdrawalFee[0].Fee, ":\"")
|
||||
if len(temp) > 1 {
|
||||
tempFee = strings.TrimRight(temp[1], ",\"type")
|
||||
} else {
|
||||
tempFee = temp[0]
|
||||
}
|
||||
resp, err = strconv.ParseFloat(tempFee, 64)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetAllOpenOrderID returns all open orders by currency pairs
|
||||
func (l *Lbank) getAllOpenOrderID() (map[string][]string, error) {
|
||||
allPairs := l.GetEnabledPairs(asset.Spot)
|
||||
resp := make(map[string][]string)
|
||||
for a := range allPairs {
|
||||
p := l.FormatExchangeCurrency(allPairs[a], asset.Spot).String()
|
||||
b := int64(1)
|
||||
tempResp, err := l.GetOpenOrders(p, strconv.FormatInt(b, 10), "200")
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
tempData := len(tempResp.Orders)
|
||||
for tempData != 0 {
|
||||
tempResp, err = l.GetOpenOrders(p, strconv.FormatInt(b, 10), "200")
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if len(tempResp.Orders) == 0 {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
for c := 0; c < tempData; c++ {
|
||||
resp[p] = append(resp[p], tempResp.Orders[c].OrderID)
|
||||
|
||||
}
|
||||
tempData = len(tempResp.Orders)
|
||||
b++
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// SubscribeToWebsocketChannels appends to ChannelsToSubscribe
|
||||
// which lets websocket.manageSubscriptions handle subscribing
|
||||
func (l *Lbank) SubscribeToWebsocketChannels(channels []wshandler.WebsocketChannelSubscription) error {
|
||||
return common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// UnsubscribeToWebsocketChannels removes from ChannelsToSubscribe
|
||||
// which lets websocket.manageSubscriptions handle unsubscribing
|
||||
func (l *Lbank) UnsubscribeToWebsocketChannels(channels []wshandler.WebsocketChannelSubscription) error {
|
||||
return common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// AuthenticateWebsocket authenticates it
|
||||
func (l *Lbank) AuthenticateWebsocket() error {
|
||||
return common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetSubscriptions gets subscriptions
|
||||
func (l *Lbank) GetSubscriptions() ([]wshandler.WebsocketChannelSubscription, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package localbitcoins
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -142,16 +143,36 @@ func (l *LocalBitcoins) GetAccountInformation(username string, self bool) (Accou
|
||||
// adID - [optional] string if omitted returns all ads
|
||||
func (l *LocalBitcoins) Getads(args ...string) (AdData, error) {
|
||||
var resp struct {
|
||||
Data AdData `json:"data"`
|
||||
Data AdData `json:"data"`
|
||||
Error struct {
|
||||
Message string `json:"message"`
|
||||
Code int `json:"error_code"`
|
||||
} `json:"error"`
|
||||
}
|
||||
|
||||
var err error
|
||||
if len(args) == 0 {
|
||||
return resp.Data, l.SendAuthenticatedHTTPRequest(http.MethodGet, localbitcoinsAPIAds, nil, &resp)
|
||||
err = l.SendAuthenticatedHTTPRequest(http.MethodGet,
|
||||
localbitcoinsAPIAds,
|
||||
nil,
|
||||
&resp)
|
||||
} else {
|
||||
params := url.Values{"ads": {strings.Join(args, ",")}}
|
||||
|
||||
err = l.SendAuthenticatedHTTPRequest(http.MethodGet,
|
||||
localbitcoinsAPIAdGet,
|
||||
params,
|
||||
&resp)
|
||||
}
|
||||
|
||||
params := url.Values{"ads": {strings.Join(args, ",")}}
|
||||
if err != nil {
|
||||
return resp.Data, err
|
||||
}
|
||||
|
||||
return resp.Data, l.SendAuthenticatedHTTPRequest(http.MethodGet, localbitcoinsAPIAdGet, params, &resp)
|
||||
if resp.Error.Message != "" {
|
||||
return resp.Data, errors.New(resp.Error.Message)
|
||||
}
|
||||
return resp.Data, nil
|
||||
}
|
||||
|
||||
// EditAd updates set advertisements
|
||||
@@ -160,12 +181,27 @@ func (l *LocalBitcoins) Getads(args ...string) (AdData, error) {
|
||||
// adID - string for the ad you already created
|
||||
// TODO
|
||||
func (l *LocalBitcoins) EditAd(_ *AdEdit, adID string) error {
|
||||
type response struct {
|
||||
Data AdData `json:"data"`
|
||||
resp := struct {
|
||||
Data AdData `json:"data"`
|
||||
Error struct {
|
||||
Message string `json:"message"`
|
||||
Code int `json:"error_code"`
|
||||
}
|
||||
}{}
|
||||
|
||||
err := l.SendAuthenticatedHTTPRequest(http.MethodPost,
|
||||
localbitcoinsAPIAdEdit+adID+"/",
|
||||
nil,
|
||||
&resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp := response{}
|
||||
return l.SendAuthenticatedHTTPRequest(http.MethodPost, localbitcoinsAPIAdEdit+adID+"/", nil, &resp)
|
||||
if resp.Error.Message != "" {
|
||||
return errors.New(resp.Error.Message)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateAd creates a new advertisement
|
||||
@@ -192,7 +228,26 @@ func (l *LocalBitcoins) UpdatePriceEquation(adID string) error {
|
||||
// adID - string of specific ad identification
|
||||
// TODO
|
||||
func (l *LocalBitcoins) DeleteAd(adID string) error {
|
||||
return l.SendAuthenticatedHTTPRequest(http.MethodPost, localbitcoinsAPIDeleteAd+adID, nil, nil)
|
||||
resp := struct {
|
||||
Error struct {
|
||||
Message string `json:"message"`
|
||||
Code int `json:"error_code"`
|
||||
} `json:"error"`
|
||||
}{}
|
||||
|
||||
err := l.SendAuthenticatedHTTPRequest(http.MethodPost,
|
||||
localbitcoinsAPIDeleteAd+adID+"/",
|
||||
nil,
|
||||
&resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.Error.Message != "" {
|
||||
return errors.New(resp.Error.Message)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReleaseFunds releases Bitcoin trades specified by ID {contact_id}. If the
|
||||
@@ -517,7 +572,7 @@ func (l *LocalBitcoins) GetWalletBalance() (WalletBalanceInfo, error) {
|
||||
// On success, the response returns a message indicating success. It is highly
|
||||
// recommended to minimize the lifetime of access tokens with the money
|
||||
// permission. Use Logout() to make the current token expire instantly.
|
||||
func (l *LocalBitcoins) WalletSend(address string, amount float64, pin int64) (bool, error) {
|
||||
func (l *LocalBitcoins) WalletSend(address string, amount float64, pin int64) error {
|
||||
values := url.Values{}
|
||||
values.Set("address", address)
|
||||
values.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
@@ -528,23 +583,34 @@ func (l *LocalBitcoins) WalletSend(address string, amount float64, pin int64) (b
|
||||
path = localbitcoinsAPIWalletSendPin
|
||||
}
|
||||
|
||||
type response struct {
|
||||
resp := struct {
|
||||
Error struct {
|
||||
Message string `json:"message"`
|
||||
Errors map[string]string `json:"errors"`
|
||||
Code int `json:"error_code"`
|
||||
} `json:"error"`
|
||||
Data struct {
|
||||
Message string `json:"message"`
|
||||
} `json:"data"`
|
||||
}
|
||||
}{}
|
||||
|
||||
resp := response{}
|
||||
err := l.SendAuthenticatedHTTPRequest(http.MethodPost, path, values, &resp)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.Data.Message != "Money is being sent" {
|
||||
return false, errors.New("unable to send Bitcoins")
|
||||
if len(resp.Error.Errors) != 0 {
|
||||
var details string
|
||||
for _, val := range resp.Error.Errors {
|
||||
details += val
|
||||
}
|
||||
return errors.New(details)
|
||||
}
|
||||
return errors.New(resp.Data.Message)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetWalletAddress returns an unused receiving address from the token owner's
|
||||
@@ -665,7 +731,16 @@ func (l *LocalBitcoins) GetOrderbook(currency string) (Orderbook, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (l *LocalBitcoins) SendHTTPRequest(path string, result interface{}) error {
|
||||
return l.SendPayload(http.MethodGet, path, nil, nil, result, false, false, l.Verbose, l.HTTPDebugging)
|
||||
return l.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
l.Verbose,
|
||||
l.HTTPDebugging,
|
||||
l.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to
|
||||
@@ -695,8 +770,16 @@ func (l *LocalBitcoins) SendAuthenticatedHTTPRequest(method, path string, params
|
||||
path += "?" + encoded
|
||||
}
|
||||
|
||||
return l.SendPayload(method, l.API.Endpoints.URL+path, headers,
|
||||
strings.NewReader(encoded), result, true, true, l.Verbose, l.HTTPDebugging)
|
||||
return l.SendPayload(method,
|
||||
l.API.Endpoints.URL+path,
|
||||
headers,
|
||||
bytes.NewBufferString(encoded),
|
||||
result,
|
||||
true,
|
||||
true,
|
||||
l.Verbose,
|
||||
l.HTTPDebugging,
|
||||
l.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
32
exchanges/localbitcoins/localbitcoins_live_test.go
Normal file
32
exchanges/localbitcoins/localbitcoins_live_test.go
Normal file
@@ -0,0 +1,32 @@
|
||||
//+build mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is parsed and will do live testing
|
||||
// using all tests in (exchange)_test.go
|
||||
package localbitcoins
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
var mockTests = false
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
localbitcoinsConfig, err := cfg.GetExchangeConfig("LocalBitcoins")
|
||||
if err != nil {
|
||||
log.Fatal("Test Failed - LocalBitcoins Setup() init error", err)
|
||||
}
|
||||
localbitcoinsConfig.API.AuthenticatedSupport = true
|
||||
localbitcoinsConfig.API.Credentials.Key = apiKey
|
||||
localbitcoinsConfig.API.Credentials.Secret = apiSecret
|
||||
l.SetDefaults()
|
||||
l.Setup(localbitcoinsConfig)
|
||||
log.Printf(sharedtestvalues.LiveTesting, l.GetName(), l.API.Endpoints.URL)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
45
exchanges/localbitcoins/localbitcoins_mock_test.go
Normal file
45
exchanges/localbitcoins/localbitcoins_mock_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
//+build !mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is not parsed and will try to mock
|
||||
// all tests in _test.go
|
||||
package localbitcoins
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/mock"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
const mockfile = "../../testdata/http_mock/localbitcoins/localbitcoins.json"
|
||||
|
||||
var mockTests = true
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
localbitcoinsConfig, err := cfg.GetExchangeConfig("LocalBitcoins")
|
||||
if err != nil {
|
||||
log.Fatal("Test Failed - Localbitcoins Setup() init error", err)
|
||||
}
|
||||
l.SkipAuthCheck = true
|
||||
localbitcoinsConfig.API.AuthenticatedSupport = true
|
||||
localbitcoinsConfig.API.Credentials.Key = apiKey
|
||||
localbitcoinsConfig.API.Credentials.Secret = apiSecret
|
||||
l.SetDefaults()
|
||||
l.Setup(localbitcoinsConfig)
|
||||
|
||||
serverDetails, newClient, err := mock.NewVCRServer(mockfile)
|
||||
if err != nil {
|
||||
log.Fatalf("Test Failed - Mock server error %s", err)
|
||||
}
|
||||
|
||||
l.HTTPClient = newClient
|
||||
l.API.Endpoints.URL = serverDetails
|
||||
|
||||
log.Printf(sharedtestvalues.MockTesting, l.GetName(), l.API.Endpoints.URL)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
@@ -4,13 +4,10 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
)
|
||||
|
||||
var l LocalBitcoins
|
||||
|
||||
// Please supply your own APIKEYS here for due diligence testing
|
||||
|
||||
const (
|
||||
@@ -19,26 +16,11 @@ const (
|
||||
canManipulateRealOrders = false
|
||||
)
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
l.SetDefaults()
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
localbitcoinsConfig, err := cfg.GetExchangeConfig("LocalBitcoins")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - LakeBTC Setup() init error")
|
||||
}
|
||||
localbitcoinsConfig.API.AuthenticatedSupport = true
|
||||
localbitcoinsConfig.API.Credentials.Key = apiKey
|
||||
localbitcoinsConfig.API.Credentials.Secret = apiSecret
|
||||
|
||||
l.Setup(localbitcoinsConfig)
|
||||
}
|
||||
var l LocalBitcoins
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := l.GetTicker()
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - GetTicker() returned: %s", err)
|
||||
@@ -47,6 +29,7 @@ func TestGetTicker(t *testing.T) {
|
||||
|
||||
func TestGetTradableCurrencies(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := l.GetTradableCurrencies()
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - GetTradableCurrencies() returned: %s", err)
|
||||
@@ -55,43 +38,42 @@ func TestGetTradableCurrencies(t *testing.T) {
|
||||
|
||||
func TestGetAccountInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !l.ValidateAPICredentials() {
|
||||
t.Skip()
|
||||
}
|
||||
_, err := l.GetAccountInformation("", true)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetAccountInformation() error", err)
|
||||
}
|
||||
_, err = l.GetAccountInformation("bitcoinbaron", false)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetAccountInformation() error", err)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not get AccountInformation: %s", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not get AccountInformation: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetads(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !l.ValidateAPICredentials() {
|
||||
t.Skip()
|
||||
}
|
||||
_, err := l.Getads("")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - Getads() - Full list, error", err)
|
||||
}
|
||||
_, err = l.Getads("1337")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - Getads() error", err)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not get ads: %s", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err == nil:
|
||||
t.Error("Expecting error until QA pass")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEditAd(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !l.ValidateAPICredentials() {
|
||||
t.Skip()
|
||||
}
|
||||
edit := AdEdit{}
|
||||
|
||||
var edit AdEdit
|
||||
err := l.EditAd(&edit, "1337")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - EditAd() error", err)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not edit order: %s", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err == nil:
|
||||
t.Error("Expecting error until QA pass")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +92,7 @@ func setFeeBuilder() *exchange.FeeBuilder {
|
||||
|
||||
// TestGetFeeByTypeOfflineTradeFee logic test
|
||||
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
var feeBuilder = setFeeBuilder()
|
||||
l.GetFeeByType(feeBuilder)
|
||||
if apiKey == "" || apiSecret == "" {
|
||||
@@ -124,7 +107,7 @@ func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetFee(t *testing.T) {
|
||||
l.SetDefaults()
|
||||
t.Parallel()
|
||||
var feeBuilder = setFeeBuilder()
|
||||
// CryptocurrencyTradeFee Basic
|
||||
if resp, err := l.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
@@ -200,45 +183,53 @@ func TestGetFee(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFormatWithdrawPermissions(t *testing.T) {
|
||||
l.SetDefaults()
|
||||
expectedResult := exchange.AutoWithdrawCryptoText + " & " + exchange.WithdrawFiatViaWebsiteOnlyText
|
||||
t.Parallel()
|
||||
|
||||
expectedResult := exchange.AutoWithdrawCryptoText +
|
||||
" & " +
|
||||
exchange.WithdrawFiatViaWebsiteOnlyText
|
||||
|
||||
withdrawPermissions := l.FormatWithdrawPermissions()
|
||||
|
||||
if withdrawPermissions != expectedResult {
|
||||
t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions)
|
||||
t.Errorf("Expected: %s, Received: %s",
|
||||
expectedResult,
|
||||
withdrawPermissions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetActiveOrders(t *testing.T) {
|
||||
l.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
}
|
||||
|
||||
_, err := l.GetActiveOrders(&getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not get active orders: %s", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not get active orders: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
l.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
}
|
||||
|
||||
_, err := l.GetOrderHistory(&getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not get order history: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not get order history: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,10 +240,9 @@ func areTestAPIKeysSet() bool {
|
||||
}
|
||||
|
||||
func TestSubmitOrder(t *testing.T) {
|
||||
l.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
@@ -268,62 +258,62 @@ func TestSubmitOrder(t *testing.T) {
|
||||
ClientID: "meowOrder",
|
||||
}
|
||||
response, err := l.SubmitOrder(orderSubmission)
|
||||
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) && !mockTests:
|
||||
t.Errorf("Order failed to be placed: %v", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err == nil:
|
||||
t.Error("Expecting an error until QA pass")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelExchangeOrder(t *testing.T) {
|
||||
l.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
|
||||
|
||||
var orderCancellation = &exchange.OrderCancellation{
|
||||
OrderID: "1",
|
||||
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
AccountID: "1",
|
||||
CurrencyPair: currencyPair,
|
||||
CurrencyPair: currency.NewPair(currency.LTC, currency.BTC),
|
||||
}
|
||||
|
||||
err := l.CancelOrder(orderCancellation)
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
switch {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
case mockTests && err == nil:
|
||||
t.Error("Expecting an error until QA pass")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
l.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
|
||||
|
||||
var orderCancellation = &exchange.OrderCancellation{
|
||||
OrderID: "1",
|
||||
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
AccountID: "1",
|
||||
CurrencyPair: currencyPair,
|
||||
CurrencyPair: currency.NewPair(currency.LTC, currency.BTC),
|
||||
}
|
||||
|
||||
resp, err := l.CancelAllOrders(orderCancellation)
|
||||
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
switch {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
}
|
||||
|
||||
@@ -333,15 +323,17 @@ func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestModifyOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := l.ModifyOrder(&exchange.ModifyOrder{})
|
||||
if err == nil {
|
||||
t.Error("Test failed - ModifyOrder() error")
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Error("Test failed - ModifyOrder() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
l.SetDefaults()
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
|
||||
withdrawCryptoRequest := exchange.CryptoWithdrawRequest{
|
||||
GenericWithdrawRequestInfo: exchange.GenericWithdrawRequestInfo{
|
||||
Amount: -1,
|
||||
@@ -351,59 +343,55 @@ func TestWithdraw(t *testing.T) {
|
||||
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
}
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
_, err := l.WithdrawCryptocurrencyFunds(&withdrawCryptoRequest)
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
switch {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Withdraw failed to be placed: %v", err)
|
||||
case mockTests && err == nil:
|
||||
t.Error("Expecting an error until QA pass")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawFiat(t *testing.T) {
|
||||
l.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
t.Parallel()
|
||||
|
||||
var withdrawFiatRequest = exchange.FiatWithdrawRequest{}
|
||||
_, err := l.WithdrawFiatFunds(&withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
|
||||
t.Errorf("Expected '%v', received: '%v'",
|
||||
common.ErrFunctionNotSupported,
|
||||
err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawInternationalBank(t *testing.T) {
|
||||
l.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
t.Parallel()
|
||||
|
||||
var withdrawFiatRequest = exchange.FiatWithdrawRequest{}
|
||||
_, err := l.WithdrawFiatFundsToInternationalBank(&withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
|
||||
t.Errorf("Expected '%v', received: '%v'",
|
||||
common.ErrFunctionNotSupported,
|
||||
err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDepositAddress(t *testing.T) {
|
||||
if apiKey != "" || apiSecret != "" {
|
||||
_, err := l.GetDepositAddress(currency.BTC, "")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetDepositAddress() error", err)
|
||||
}
|
||||
} else {
|
||||
_, err := l.GetDepositAddress(currency.BTC, "")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetDepositAddress() error cannot be nil")
|
||||
}
|
||||
t.Parallel()
|
||||
|
||||
_, err := l.GetDepositAddress(currency.BTC, "")
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Error("Test Failed - GetDepositAddress() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Test Failed - GetDepositAddress() expecting an error when no APIKeys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - GetDepositAddress() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,8 +380,10 @@ func (l *LocalBitcoins) GetDepositAddress(cryptocurrency currency.Code, _ string
|
||||
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func (l *LocalBitcoins) WithdrawCryptocurrencyFunds(withdrawRequest *exchange.CryptoWithdrawRequest) (string, error) {
|
||||
_, err := l.WalletSend(withdrawRequest.Address, withdrawRequest.Amount, withdrawRequest.PIN)
|
||||
return "", err
|
||||
return "",
|
||||
l.WalletSend(withdrawRequest.Address,
|
||||
withdrawRequest.Amount,
|
||||
withdrawRequest.PIN)
|
||||
}
|
||||
|
||||
// WithdrawFiatFunds returns a withdrawal ID when a
|
||||
@@ -403,7 +405,7 @@ func (l *LocalBitcoins) GetWebsocket() (*wshandler.Websocket, error) {
|
||||
|
||||
// GetFeeByType returns an estimate of fee based on type of transaction
|
||||
func (l *LocalBitcoins) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
if !l.AllowAuthenticatedRequest() && // Todo check connection status
|
||||
if (!l.AllowAuthenticatedRequest() || l.SkipAuthCheck) && // Todo check connection status
|
||||
feeBuilder.FeeType == exchange.CryptocurrencyTradeFee {
|
||||
feeBuilder.FeeType = exchange.OfflineTradeFee
|
||||
}
|
||||
|
||||
174
exchanges/mock/README.md
Normal file
174
exchanges/mock/README.md
Normal file
@@ -0,0 +1,174 @@
|
||||
# GoCryptoTrader package Mock
|
||||
|
||||
<img src="https://github.com/thrasher-corp/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
|
||||
|
||||
|
||||
[](https://travis-ci.org/thrasher-corp/gocryptotrader)
|
||||
[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
|
||||
[](https://godoc.org/github.com/thrasher-corp/gocryptotrader/exchanges/mock)
|
||||
[](http://codecov.io/github/thrasher-corp/gocryptotrader?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/thrasher-corp/gocryptotrader)
|
||||
|
||||
|
||||
This Mock package is part of the GoCryptoTrader codebase.
|
||||
|
||||
## This is still in active development
|
||||
|
||||
You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
|
||||
|
||||
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/enQtNTQ5NDAxMjA2Mjc5LTQyYjIxNGVhMWU5MDZlOGYzMmE0NTJmM2MzYWY5NGMzMmM4MzUwNTBjZTEzNjIwODM5NDcxODQwZDljMGQyNGY)
|
||||
|
||||
## Mock Testing Suite
|
||||
|
||||
### Current Features
|
||||
|
||||
+ REST recording service
|
||||
+ REST mock response server
|
||||
|
||||
### How to enable
|
||||
|
||||
+ Mock testing is enabled by default in some exchanges; to disable and run live endpoint testing parse -tags=mock_test_off as a go test param.
|
||||
|
||||
+ To record a live endpoint create two files for an exchange.
|
||||
|
||||
### file one - your_current_exchange_name_live_test.go
|
||||
|
||||
```go
|
||||
//+build mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is parsed and will do live testing
|
||||
// using all tests in (exchange)_test.go
|
||||
package your_current_exchange_name
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"log"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
var mockTests = false
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
your_current_exchange_nameConfig, err := cfg.GetExchangeConfig("your_current_exchange_name")
|
||||
if err != nil {
|
||||
log.Fatal("Test Failed - your_current_exchange_name Setup() init error", err)
|
||||
}
|
||||
your_current_exchange_nameConfig.AuthenticatedAPISupport = true
|
||||
your_current_exchange_nameConfig.APIKey = apiKey
|
||||
your_current_exchange_nameConfig.APISecret = apiSecret
|
||||
l.SetDefaults()
|
||||
l.Setup(&your_current_exchange_nameConfig)
|
||||
log.Printf(sharedtestvalues.LiveTesting, l.GetName(), l.APIUrl)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
```
|
||||
|
||||
### file two - your_current_exchange_name_mock_test.go
|
||||
|
||||
```go
|
||||
//+build !mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is not parsed and will try to mock
|
||||
// all tests in _test.go
|
||||
package your_current_exchange_name
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"log"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/mock"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
const mockfile = "../../testdata/http_mock/your_current_exchange_name/your_current_exchange_name.json"
|
||||
|
||||
var mockTests = true
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
your_current_exchange_nameConfig, err := cfg.GetExchangeConfig("your_current_exchange_name")
|
||||
if err != nil {
|
||||
log.Fatal("Test Failed - your_current_exchange_name Setup() init error", err)
|
||||
}
|
||||
your_current_exchange_nameConfig.AuthenticatedAPISupport = true
|
||||
your_current_exchange_nameConfig.APIKey = apiKey
|
||||
your_current_exchange_nameConfig.APISecret = apiSecret
|
||||
l.SetDefaults()
|
||||
l.Setup(&your_current_exchange_nameConfig)
|
||||
|
||||
serverDetails, newClient, err := mock.NewVCRServer(mockfile)
|
||||
if err != nil {
|
||||
log.Fatalf("Test Failed - Mock server error %s", err)
|
||||
}
|
||||
|
||||
g.HTTPClient = newClient
|
||||
g.APIUrl = serverDetails
|
||||
|
||||
log.Printf(sharedtestvalues.MockTesting, l.GetName(), l.APIUrl)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+ Once those files are completed go through each invidual test function and add
|
||||
|
||||
```go
|
||||
var s SomeExchange
|
||||
|
||||
func TestDummyTest(t *testing.T) {
|
||||
s.APIURL = exchangeDefaultURL // This will overwrite the current mock url at localhost
|
||||
s.Verbose = true // This will show you some fancy debug output
|
||||
s.HTTPRecording = true // This will record the request and response payloads
|
||||
|
||||
err := s.SomeExchangeEndpointFunction()
|
||||
// check error
|
||||
}
|
||||
```
|
||||
|
||||
+ After this is completed it should populate a new mocktest.json file for you with the relavent payloads in testdata
|
||||
+ To check if the recording was successful, comment out recording and apiurl changes, then re-run test.
|
||||
|
||||
```go
|
||||
var s SomeExchange
|
||||
|
||||
func TestDummyTest(t *testing.T) {
|
||||
// s.APIURL = exchangeDefaultURL // This will overwrite the current mock url at localhost
|
||||
s.Verbose = true // This will show you some fancy debug output
|
||||
// s.HTTPRecording = true // This will record the request and response payloads
|
||||
|
||||
err := s.SomeExchangeEndpointFunction()
|
||||
// check error
|
||||
}
|
||||
```
|
||||
|
||||
+ The payload should be the same.
|
||||
|
||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||
|
||||
## Contribution
|
||||
|
||||
Please feel free to submit any pull requests or suggest any desired features to be added.
|
||||
|
||||
When submitting a PR, please abide by our coding guidelines:
|
||||
|
||||
+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
|
||||
+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
|
||||
+ Code must adhere to our [coding style](https://github.com/thrasher-corp/gocryptotrader/blob/master/doc/coding_style.md).
|
||||
+ Pull requests need to be based on and opened against the `master` branch.
|
||||
|
||||
## Donations
|
||||
|
||||
<img src="https://github.com/thrasher-corp/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
|
||||
|
||||
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
|
||||
|
||||
***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***
|
||||
|
||||
71
exchanges/mock/common.go
Normal file
71
exchanges/mock/common.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MatchURLVals matches url.Value query strings
|
||||
func MatchURLVals(v1, v2 url.Values) bool {
|
||||
if len(v1) != len(v2) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(v1) == 0 && len(v2) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
for key, val := range v1 {
|
||||
if key == "nonce" || key == "signature" || key == "timestamp" || key == "tonce" || key == "key" { // delta values
|
||||
if _, ok := v2[key]; !ok {
|
||||
return false
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if val2, ok := v2[key]; ok {
|
||||
if strings.Join(val2, "") == strings.Join(val, "") {
|
||||
continue
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// DeriveURLValsFromJSONMap gets url vals from a map[string]string encoded JSON body
|
||||
func DeriveURLValsFromJSONMap(payload []byte) (url.Values, error) {
|
||||
var vals = url.Values{}
|
||||
if string(payload) == "" {
|
||||
return vals, nil
|
||||
}
|
||||
intermediary := make(map[string]interface{})
|
||||
err := json.Unmarshal(payload, &intermediary)
|
||||
if err != nil {
|
||||
return vals, err
|
||||
}
|
||||
|
||||
for k, v := range intermediary {
|
||||
switch val := v.(type) {
|
||||
case string:
|
||||
vals.Add(k, val)
|
||||
case bool:
|
||||
vals.Add(k, strconv.FormatBool(val))
|
||||
case float64:
|
||||
vals.Add(k, strconv.FormatFloat(val, 'f', -1, 64))
|
||||
case map[string]interface{}, []interface{}, nil:
|
||||
vals.Add(k, fmt.Sprintf("%v", val))
|
||||
default:
|
||||
log.Println(reflect.TypeOf(val))
|
||||
return vals, errors.New("unhandled conversion type, please add as needed")
|
||||
}
|
||||
}
|
||||
|
||||
return vals, nil
|
||||
}
|
||||
140
exchanges/mock/common_test.go
Normal file
140
exchanges/mock/common_test.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMatchURLVals(t *testing.T) {
|
||||
testVal, testVal2, testVal3, emptyVal := url.Values{}, url.Values{}, url.Values{}, url.Values{}
|
||||
testVal.Add("test", "test")
|
||||
testVal2.Add("test2", "test2")
|
||||
testVal3.Add("test", "diferentValString")
|
||||
|
||||
nonceVal1, nonceVal2 := url.Values{}, url.Values{}
|
||||
nonceVal1.Add("nonce", "012349723587")
|
||||
nonceVal2.Add("nonce", "9327373874")
|
||||
|
||||
var expected = false
|
||||
received := MatchURLVals(testVal, emptyVal)
|
||||
if received != expected {
|
||||
t.Errorf("Test Failed - MatchURLVals error expected %v received %v",
|
||||
expected,
|
||||
received)
|
||||
}
|
||||
|
||||
received = MatchURLVals(emptyVal, testVal)
|
||||
if received != expected {
|
||||
t.Errorf("Test Failed - MatchURLVals error expected %v received %v",
|
||||
expected,
|
||||
received)
|
||||
}
|
||||
|
||||
received = MatchURLVals(testVal, testVal2)
|
||||
if received != expected {
|
||||
t.Errorf("Test Failed - MatchURLVals error expected %v received %v",
|
||||
expected,
|
||||
received)
|
||||
}
|
||||
|
||||
received = MatchURLVals(testVal2, testVal)
|
||||
if received != expected {
|
||||
t.Errorf("Test Failed - MatchURLVals error expected %v received %v",
|
||||
expected,
|
||||
received)
|
||||
}
|
||||
|
||||
received = MatchURLVals(testVal, testVal3)
|
||||
if received != expected {
|
||||
t.Errorf("Test Failed - MatchURLVals error expected %v received %v",
|
||||
expected,
|
||||
received)
|
||||
}
|
||||
|
||||
received = MatchURLVals(nonceVal1, testVal2)
|
||||
if received != expected {
|
||||
t.Errorf("Test Failed - MatchURLVals error expected %v received %v",
|
||||
expected,
|
||||
received)
|
||||
}
|
||||
|
||||
expected = true
|
||||
received = MatchURLVals(emptyVal, emptyVal)
|
||||
if received != expected {
|
||||
t.Errorf("Test Failed - MatchURLVals error expected %v received %v",
|
||||
expected,
|
||||
received)
|
||||
}
|
||||
|
||||
received = MatchURLVals(testVal, testVal)
|
||||
if received != expected {
|
||||
t.Errorf("Test Failed - MatchURLVals error expected %v received %v",
|
||||
expected,
|
||||
received)
|
||||
}
|
||||
|
||||
received = MatchURLVals(nonceVal1, nonceVal2)
|
||||
if received != expected {
|
||||
t.Errorf("Test Failed - MatchURLVals error expected %v received %v",
|
||||
expected,
|
||||
received)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeriveURLValsFromJSON(t *testing.T) {
|
||||
test1 := struct {
|
||||
Things []string `json:"things"`
|
||||
Data struct {
|
||||
Numbers []int `json:"numbers"`
|
||||
Number float64 `json:"number"`
|
||||
SomeString string `json:"somestring"`
|
||||
} `json:"data"`
|
||||
}{
|
||||
Things: []string{"hello", "world"},
|
||||
Data: struct {
|
||||
Numbers []int `json:"numbers"`
|
||||
Number float64 `json:"number"`
|
||||
SomeString string `json:"somestring"`
|
||||
}{
|
||||
Numbers: []int{1, 3, 3, 7},
|
||||
Number: 3.14,
|
||||
SomeString: "hello, peoples",
|
||||
},
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(test1)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - marshal error", err)
|
||||
}
|
||||
|
||||
_, err = DeriveURLValsFromJSONMap(payload)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - DeriveURLValsFromJSON error", err)
|
||||
}
|
||||
|
||||
test2 := map[string]string{
|
||||
"val": "1",
|
||||
"val2": "2",
|
||||
"val3": "3",
|
||||
"val4": "4",
|
||||
"val5": "5",
|
||||
"val6": "6",
|
||||
"val7": "7",
|
||||
}
|
||||
|
||||
payload, err = json.Marshal(test2)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - marshal error", err)
|
||||
}
|
||||
|
||||
vals, err := DeriveURLValsFromJSONMap(payload)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - DeriveURLValsFromJSON error", err)
|
||||
}
|
||||
|
||||
if vals["val"][0] != "1" {
|
||||
t.Error("Test Failed - DeriveURLValsFromJSON unexpected value",
|
||||
vals["val"][0])
|
||||
}
|
||||
}
|
||||
440
exchanges/mock/recording.go
Normal file
440
exchanges/mock/recording.go
Normal file
@@ -0,0 +1,440 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/crypto"
|
||||
)
|
||||
|
||||
// HTTPResponse defines expected response from the end point including request
|
||||
// data for pathing on the VCR server
|
||||
type HTTPResponse struct {
|
||||
Data json.RawMessage `json:"data"`
|
||||
QueryString string `json:"queryString"`
|
||||
BodyParams string `json:"bodyParams"`
|
||||
Headers map[string][]string `json:"headers"`
|
||||
}
|
||||
|
||||
// HTTPRecord will record the request and response to a default JSON file for
|
||||
// mocking purposes
|
||||
func HTTPRecord(res *http.Response, service string, respContents []byte) error {
|
||||
if res == nil {
|
||||
return errors.New("http.Response cannot be nil")
|
||||
}
|
||||
|
||||
if res.Request == nil {
|
||||
return errors.New("http.Request cannot be nil")
|
||||
}
|
||||
|
||||
if res.Request.Method == "" {
|
||||
return errors.New("request method not supplied")
|
||||
}
|
||||
|
||||
if service == "" {
|
||||
return errors.New("service not supplied cannot access correct mock file")
|
||||
}
|
||||
service = strings.ToLower(service)
|
||||
|
||||
fileout := filepath.Join(DefaultDirectory, service, service+".json")
|
||||
|
||||
contents, err := ioutil.ReadFile(fileout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var m VCRMock
|
||||
err = json.Unmarshal(contents, &m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if m.Routes == nil {
|
||||
m.Routes = make(map[string]map[string][]HTTPResponse)
|
||||
}
|
||||
|
||||
var httpResponse HTTPResponse
|
||||
cleanedContents, err := CheckResponsePayload(respContents)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(cleanedContents, &httpResponse.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var body string
|
||||
if res.Request.GetBody != nil {
|
||||
bodycopy, bodyErr := res.Request.GetBody()
|
||||
if bodyErr != nil {
|
||||
return bodyErr
|
||||
}
|
||||
payload, bodyErr := ioutil.ReadAll(bodycopy)
|
||||
if bodyErr != nil {
|
||||
return bodyErr
|
||||
}
|
||||
body = string(payload)
|
||||
}
|
||||
|
||||
switch res.Request.Header.Get(contentType) {
|
||||
case applicationURLEncoded:
|
||||
vals, urlErr := url.ParseQuery(body)
|
||||
if urlErr != nil {
|
||||
return urlErr
|
||||
}
|
||||
|
||||
httpResponse.BodyParams, urlErr = GetFilteredURLVals(vals)
|
||||
if urlErr != nil {
|
||||
return urlErr
|
||||
}
|
||||
|
||||
case textPlain:
|
||||
payload := res.Request.Header.Get("X-Gemini-Payload")
|
||||
j, dErr := crypto.Base64Decode(payload)
|
||||
if dErr != nil {
|
||||
return dErr
|
||||
}
|
||||
|
||||
httpResponse.BodyParams = string(j)
|
||||
|
||||
default:
|
||||
httpResponse.BodyParams = body
|
||||
}
|
||||
|
||||
httpResponse.Headers, err = GetFilteredHeader(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
httpResponse.QueryString, err = GetFilteredURLVals(res.Request.URL.Query())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, ok := m.Routes[res.Request.URL.Path]
|
||||
if !ok {
|
||||
m.Routes[res.Request.URL.Path] = make(map[string][]HTTPResponse)
|
||||
m.Routes[res.Request.URL.Path][res.Request.Method] = []HTTPResponse{httpResponse}
|
||||
} else {
|
||||
mockResponses, ok := m.Routes[res.Request.URL.Path][res.Request.Method]
|
||||
if !ok {
|
||||
m.Routes[res.Request.URL.Path][res.Request.Method] = []HTTPResponse{httpResponse}
|
||||
} else {
|
||||
switch res.Request.Method { // Based off method - check add or replace
|
||||
case http.MethodGet:
|
||||
for i := range mockResponses {
|
||||
mockQuery, urlErr := url.ParseQuery(mockResponses[i].QueryString)
|
||||
if urlErr != nil {
|
||||
return urlErr
|
||||
}
|
||||
|
||||
if MatchURLVals(mockQuery, res.Request.URL.Query()) {
|
||||
mockResponses = append(mockResponses[:i], mockResponses[i+1:]...) // Delete Old
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
case http.MethodPost:
|
||||
for i := range mockResponses {
|
||||
cType, ok := mockResponses[i].Headers[contentType]
|
||||
if !ok {
|
||||
return errors.New("cannot find content type within mock responses")
|
||||
}
|
||||
|
||||
jCType := strings.Join(cType, "")
|
||||
var found bool
|
||||
switch jCType {
|
||||
case applicationURLEncoded:
|
||||
respQueryVals, urlErr := url.ParseQuery(body)
|
||||
if urlErr != nil {
|
||||
return urlErr
|
||||
}
|
||||
|
||||
mockRespVals, urlErr := url.ParseQuery(mockResponses[i].BodyParams)
|
||||
if urlErr != nil {
|
||||
log.Fatal(urlErr)
|
||||
}
|
||||
|
||||
if MatchURLVals(respQueryVals, mockRespVals) {
|
||||
// if found will delete instance and overwrite with new
|
||||
// data
|
||||
mockResponses = append(mockResponses[:i], mockResponses[i+1:]...)
|
||||
found = true
|
||||
}
|
||||
|
||||
case applicationJSON, textPlain:
|
||||
reqVals, jErr := DeriveURLValsFromJSONMap([]byte(body))
|
||||
if jErr != nil {
|
||||
return jErr
|
||||
}
|
||||
|
||||
mockVals, jErr := DeriveURLValsFromJSONMap([]byte(mockResponses[i].BodyParams))
|
||||
if jErr != nil {
|
||||
return jErr
|
||||
}
|
||||
|
||||
if MatchURLVals(reqVals, mockVals) {
|
||||
// if found will delete instance and overwrite with new
|
||||
// data
|
||||
mockResponses = append(mockResponses[:i], mockResponses[i+1:]...)
|
||||
found = true
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unhandled content type %s", jCType)
|
||||
}
|
||||
if found {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unhandled request method %s", res.Request.Method)
|
||||
}
|
||||
|
||||
m.Routes[res.Request.URL.Path][res.Request.Method] = append(mockResponses, httpResponse)
|
||||
}
|
||||
}
|
||||
|
||||
payload, err := json.MarshalIndent(m, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return common.WriteFile(fileout, payload)
|
||||
}
|
||||
|
||||
// GetFilteredHeader filters excluded http headers for insertion into a mock
|
||||
// test file
|
||||
func GetFilteredHeader(res *http.Response) (http.Header, error) {
|
||||
items, err := GetExcludedItems()
|
||||
if err != nil {
|
||||
return res.Header, err
|
||||
}
|
||||
|
||||
for i := range items.Headers {
|
||||
if res.Request.Header.Get(items.Headers[i]) != "" {
|
||||
res.Request.Header.Set(items.Headers[i], "")
|
||||
}
|
||||
}
|
||||
|
||||
return res.Request.Header, nil
|
||||
}
|
||||
|
||||
// GetFilteredURLVals filters excluded url value variables for insertion into a
|
||||
// mock test file
|
||||
func GetFilteredURLVals(vals url.Values) (string, error) {
|
||||
items, err := GetExcludedItems()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for key, val := range vals {
|
||||
for i := range items.Variables {
|
||||
if strings.EqualFold(items.Variables[i], val[0]) {
|
||||
vals.Set(key, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
return vals.Encode(), nil
|
||||
}
|
||||
|
||||
// CheckResponsePayload checks to see if there are any response body variables
|
||||
// that should not be there.
|
||||
func CheckResponsePayload(data []byte) ([]byte, error) {
|
||||
items, err := GetExcludedItems()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var intermediary interface{}
|
||||
err = json.Unmarshal(data, &intermediary)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
payload, err := CheckJSON(intermediary, &items)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.MarshalIndent(payload, "", " ")
|
||||
}
|
||||
|
||||
// Reflection consts
|
||||
const (
|
||||
Int64 = "int64"
|
||||
Float64 = "float64"
|
||||
Slice = "slice"
|
||||
String = "string"
|
||||
Bool = "bool"
|
||||
Invalid = "invalid"
|
||||
)
|
||||
|
||||
// CheckJSON recursively parses json data to retract keywords, quite intensive.
|
||||
func CheckJSON(data interface{}, excluded *Exclusion) (interface{}, error) {
|
||||
var context map[string]interface{}
|
||||
if reflect.TypeOf(data).String() == "[]interface {}" {
|
||||
var sData []interface{}
|
||||
for i := range data.([]interface{}) {
|
||||
checkedData, err := CheckJSON(data.([]interface{})[i], excluded)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sData = append(sData, checkedData)
|
||||
}
|
||||
return sData, nil
|
||||
}
|
||||
|
||||
conv, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(conv, &context)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(context) == 0 {
|
||||
// Nil for some reason, should error out before in json.Unmarshal
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
for key, val := range context {
|
||||
switch reflect.ValueOf(val).Kind().String() {
|
||||
case String:
|
||||
if IsExcluded(key, excluded.Variables) {
|
||||
context[key] = "" // Zero val string
|
||||
}
|
||||
case Int64:
|
||||
if IsExcluded(key, excluded.Variables) {
|
||||
context[key] = 0 // Zero val int
|
||||
}
|
||||
case Float64:
|
||||
if IsExcluded(key, excluded.Variables) {
|
||||
context[key] = 0.0 // Zero val float
|
||||
}
|
||||
case Slice:
|
||||
slice := val.([]interface{})
|
||||
if len(slice) < 1 {
|
||||
// Empty slice found
|
||||
context[key] = slice
|
||||
} else {
|
||||
if _, ok := slice[0].(map[string]interface{}); ok {
|
||||
var cleanSlice []interface{}
|
||||
for i := range slice {
|
||||
cleanMap, sErr := CheckJSON(slice[i], excluded)
|
||||
if sErr != nil {
|
||||
return nil, sErr
|
||||
}
|
||||
cleanSlice = append(cleanSlice, cleanMap)
|
||||
}
|
||||
context[key] = cleanSlice
|
||||
} else if IsExcluded(key, excluded.Variables) {
|
||||
context[key] = nil // Zero val slice
|
||||
}
|
||||
}
|
||||
|
||||
case Bool, Invalid: // Skip these bad boys for now
|
||||
default:
|
||||
// Recursively check map data
|
||||
contextValue, err := CheckJSON(val, excluded)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
context[key] = contextValue
|
||||
}
|
||||
}
|
||||
|
||||
return context, nil
|
||||
}
|
||||
|
||||
// IsExcluded cross references the key with the excluded variables
|
||||
func IsExcluded(key string, excludedVars []string) bool {
|
||||
for i := range excludedVars {
|
||||
if strings.EqualFold(key, excludedVars[i]) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var excludedList Exclusion
|
||||
var m sync.Mutex
|
||||
var set bool
|
||||
var exclusionFile = DefaultDirectory + "exclusion.json"
|
||||
|
||||
var defaultExcludedHeaders = []string{"Key",
|
||||
"X-Mbx-Apikey",
|
||||
"Rest-Key",
|
||||
"Apiauth-Key"}
|
||||
var defaultExcludedVariables = []string{"bsb",
|
||||
"user",
|
||||
"name",
|
||||
"real_name",
|
||||
"receiver_name",
|
||||
"account_number",
|
||||
"username"}
|
||||
|
||||
// Exclusion defines a list of items to be excluded from the main mock output
|
||||
// this attempts a catch all approach and needs to be updated per exchange basis
|
||||
type Exclusion struct {
|
||||
Headers []string `json:"headers"`
|
||||
Variables []string `json:"variables"`
|
||||
}
|
||||
|
||||
// GetExcludedItems checks to see if the variable is in the exclusion list as to
|
||||
// not display secure items in mock file generator output
|
||||
func GetExcludedItems() (Exclusion, error) {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
if !set {
|
||||
file, err := ioutil.ReadFile(exclusionFile)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "no such file or directory") {
|
||||
return excludedList, err
|
||||
}
|
||||
|
||||
excludedList.Headers = defaultExcludedHeaders
|
||||
excludedList.Variables = defaultExcludedVariables
|
||||
|
||||
data, mErr := json.MarshalIndent(excludedList, "", " ")
|
||||
if mErr != nil {
|
||||
return excludedList, mErr
|
||||
}
|
||||
|
||||
mErr = ioutil.WriteFile(exclusionFile, data, os.ModePerm)
|
||||
if mErr != nil {
|
||||
return excludedList, mErr
|
||||
}
|
||||
|
||||
} else {
|
||||
err = json.Unmarshal(file, &excludedList)
|
||||
if err != nil {
|
||||
return excludedList, err
|
||||
}
|
||||
|
||||
if len(excludedList.Headers) == 0 || len(excludedList.Variables) == 0 {
|
||||
return excludedList, errors.New("exclusion list does not have names")
|
||||
}
|
||||
}
|
||||
|
||||
set = true
|
||||
}
|
||||
|
||||
return excludedList, nil
|
||||
}
|
||||
186
exchanges/mock/recording_test.go
Normal file
186
exchanges/mock/recording_test.go
Normal file
@@ -0,0 +1,186 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetFilteredHeader(t *testing.T) {
|
||||
resp := http.Response{}
|
||||
resp.Request = &http.Request{}
|
||||
resp.Request.Header = http.Header{}
|
||||
resp.Request.Header.Set("Key", "RiskyVals")
|
||||
fMap, err := GetFilteredHeader(&resp)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if fMap.Get("Key") != "" {
|
||||
t.Error("Test Failed - risky vals where not replaced correctly")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFilteredURLVals(t *testing.T) {
|
||||
superSecretData := "Dr Seuss"
|
||||
shadyVals := url.Values{}
|
||||
shadyVals.Set("real_name", superSecretData)
|
||||
cleanVals, err := GetFilteredURLVals(shadyVals)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetFilteredURLVals error", err)
|
||||
}
|
||||
|
||||
if strings.Contains(cleanVals, superSecretData) {
|
||||
t.Error("Test Failed - Super secret data found")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckResponsePayload(t *testing.T) {
|
||||
testbody := struct {
|
||||
SomeJSON string `json:"stuff"`
|
||||
}{
|
||||
SomeJSON: "REAAAAHHHHH",
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(testbody)
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - json marshal error", err)
|
||||
}
|
||||
|
||||
data, err := CheckResponsePayload(payload)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - CheckBody error", err)
|
||||
}
|
||||
|
||||
expected := `{
|
||||
"stuff": "REAAAAHHHHH"
|
||||
}`
|
||||
|
||||
if string(data) != expected {
|
||||
t.Error("unexpected returned data")
|
||||
}
|
||||
}
|
||||
|
||||
type TestStructLevel0 struct {
|
||||
StringVal string `json:"stringVal"`
|
||||
FloatVal float64 `json:"floatVal"`
|
||||
IntVal int64 `json:"intVal"`
|
||||
StructVal TestStructLevel1 `json:"structVal"`
|
||||
}
|
||||
|
||||
type TestStructLevel1 struct {
|
||||
OkayVal string `json:"okayVal"`
|
||||
OkayVal2 float64 `json:"okayVal2"`
|
||||
BadVal string `json:"user"`
|
||||
BadVal2 int `json:"bsb"`
|
||||
OtherData TestStructLevel2 `json:"otherVals"`
|
||||
}
|
||||
|
||||
type TestStructLevel2 struct {
|
||||
OkayVal string `json:"okayVal"`
|
||||
OkayVal2 float64 `json:"okayVal2"`
|
||||
BadVal float32 `json:"name"`
|
||||
BadVal2 int32 `json:"real_name"`
|
||||
OtherData TestStructLevel3 `json:"moreOtherVals"`
|
||||
}
|
||||
|
||||
type TestStructLevel3 struct {
|
||||
OkayVal string `json:"okayVal"`
|
||||
OkayVal2 float64 `json:"okayVal2"`
|
||||
BadVal int64 `json:"receiver_name"`
|
||||
BadVal2 string `json:"account_number"`
|
||||
}
|
||||
|
||||
func TestCheckJSON(t *testing.T) {
|
||||
level3 := TestStructLevel3{
|
||||
OkayVal: "stuff",
|
||||
OkayVal2: 129219,
|
||||
BadVal: 1337,
|
||||
BadVal2: "Super Secret Password",
|
||||
}
|
||||
|
||||
level2 := TestStructLevel2{
|
||||
OkayVal: "stuff",
|
||||
OkayVal2: 129219,
|
||||
BadVal: 0.222,
|
||||
BadVal2: 1337888888,
|
||||
OtherData: level3,
|
||||
}
|
||||
|
||||
level1 := TestStructLevel1{
|
||||
OkayVal: "stuff",
|
||||
OkayVal2: 120938,
|
||||
BadVal: "CritcalBankingStuff",
|
||||
BadVal2: 1337,
|
||||
OtherData: level2,
|
||||
}
|
||||
|
||||
testVal := TestStructLevel0{
|
||||
StringVal: "somestringstuff",
|
||||
FloatVal: 3.14,
|
||||
IntVal: 1337,
|
||||
StructVal: level1,
|
||||
}
|
||||
|
||||
exclusionList, err := GetExcludedItems()
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetExcludedItems error", err)
|
||||
}
|
||||
|
||||
vals, err := CheckJSON(testVal, &exclusionList)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Check JSON error", err)
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(vals)
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - json marshal error", err)
|
||||
}
|
||||
|
||||
newStruct := TestStructLevel0{}
|
||||
err = json.Unmarshal(payload, &newStruct)
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - Umarshal error", err)
|
||||
}
|
||||
|
||||
if newStruct.StructVal.BadVal != "" {
|
||||
t.Error("Value not wiped correctly")
|
||||
}
|
||||
|
||||
if newStruct.StructVal.BadVal2 != 0 {
|
||||
t.Error("Value not wiped correctly")
|
||||
}
|
||||
|
||||
if newStruct.StructVal.OtherData.BadVal != 0 {
|
||||
t.Error("Value not wiped correctly")
|
||||
}
|
||||
|
||||
if newStruct.StructVal.OtherData.BadVal2 != 0 {
|
||||
t.Error("Value not wiped correctly")
|
||||
}
|
||||
|
||||
if newStruct.StructVal.OtherData.OtherData.BadVal != 0 {
|
||||
t.Error("Value not wiped correctly")
|
||||
}
|
||||
|
||||
if newStruct.StructVal.OtherData.OtherData.BadVal2 != "" {
|
||||
t.Error("Value not wiped correctly")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetExcludedItems(t *testing.T) {
|
||||
exclusionList, err := GetExcludedItems()
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetExcludedItems error", err)
|
||||
}
|
||||
|
||||
if len(exclusionList.Headers) == 0 {
|
||||
t.Error("Test Failed - Header exclusion list not popoulated")
|
||||
}
|
||||
|
||||
if len(exclusionList.Variables) == 0 {
|
||||
t.Error("Test Failed - Variable exclusion list not popoulated")
|
||||
}
|
||||
}
|
||||
283
exchanges/mock/server.go
Normal file
283
exchanges/mock/server.go
Normal file
@@ -0,0 +1,283 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/crypto"
|
||||
)
|
||||
|
||||
// DefaultDirectory defines the main mock directory
|
||||
const DefaultDirectory = "../../testdata/http_mock/"
|
||||
|
||||
const (
|
||||
contentType = "Content-Type"
|
||||
applicationURLEncoded = "application/x-www-form-urlencoded"
|
||||
applicationJSON = "application/json"
|
||||
textPlain = "text/plain"
|
||||
)
|
||||
|
||||
// VCRMock defines the main mock JSON file and attributes
|
||||
type VCRMock struct {
|
||||
Routes map[string]map[string][]HTTPResponse `json:"routes"`
|
||||
}
|
||||
|
||||
// NewVCRServer starts a new VCR server for replaying HTTP requests for testing
|
||||
// purposes and returns the server connection details
|
||||
func NewVCRServer(path string) (string, *http.Client, error) {
|
||||
if path == "" {
|
||||
return "", nil, errors.New("no path to json mock file found")
|
||||
}
|
||||
|
||||
var mockFile VCRMock
|
||||
|
||||
contents, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
pathing := strings.Split(path, "/")
|
||||
dirPathing := pathing[:len(pathing)-1]
|
||||
dir := strings.Join(dirPathing, "/")
|
||||
err = common.CreateDir(dir)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
data, jErr := json.MarshalIndent(mockFile, "", " ")
|
||||
if jErr != nil {
|
||||
return "", nil, jErr
|
||||
}
|
||||
|
||||
err = common.WriteFile(path, data)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
contents = data
|
||||
}
|
||||
|
||||
if !json.Valid(contents) {
|
||||
return "",
|
||||
nil,
|
||||
fmt.Errorf("contents of file %s are not valid JSON", path)
|
||||
}
|
||||
|
||||
// Get mocking data for the specific service
|
||||
err = json.Unmarshal(contents, &mockFile)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
newMux := http.NewServeMux()
|
||||
// Range over routes and assign responses to explicit paths and http
|
||||
// methods
|
||||
if len(mockFile.Routes) != 0 {
|
||||
for pattern, mockResponses := range mockFile.Routes {
|
||||
RegisterHandler(pattern, mockResponses, newMux)
|
||||
}
|
||||
} else {
|
||||
newMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
err := json.NewEncoder(w).Encode("There is no mock data available in file please record a new HTTP response. Please follow README.md in the mock package.")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
tlsServer := httptest.NewTLSServer(newMux)
|
||||
|
||||
return tlsServer.URL, tlsServer.Client(), nil
|
||||
}
|
||||
|
||||
// RegisterHandler registers a generalised mock response logic for specific
|
||||
// routes
|
||||
func RegisterHandler(pattern string, mock map[string][]HTTPResponse, mux *http.ServeMux) {
|
||||
mux.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
|
||||
httpResponses, ok := mock[r.Method]
|
||||
if !ok {
|
||||
log.Fatalf("Mock Test Failure - Method %s not present in mock file",
|
||||
r.Method)
|
||||
}
|
||||
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
vals, err := url.ParseRequestURI(r.RequestURI)
|
||||
if err != nil {
|
||||
log.Fatal("Mock Test Failure - Parse request URI error", err)
|
||||
}
|
||||
|
||||
payload, err := MatchAndGetResponse(httpResponses, vals.Query(), true)
|
||||
if err != nil {
|
||||
log.Fatalf("Mock Test Failure - MatchAndGetResponse error %s for %s",
|
||||
err, r.RequestURI)
|
||||
}
|
||||
|
||||
MessageWriteJSON(w, http.StatusOK, payload)
|
||||
return
|
||||
|
||||
case http.MethodPost:
|
||||
switch r.Header.Get(contentType) {
|
||||
case applicationURLEncoded:
|
||||
readBody, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
log.Fatal("Mock Test Failure - ReadAll error", err)
|
||||
}
|
||||
|
||||
vals, err := url.ParseQuery(string(readBody))
|
||||
if err != nil {
|
||||
log.Fatal("Mock Test Failure - parse query error", err)
|
||||
}
|
||||
|
||||
payload, err := MatchAndGetResponse(httpResponses, vals, false)
|
||||
if err != nil {
|
||||
log.Fatal("Mock Test Failure - MatchAndGetResponse error ", err)
|
||||
}
|
||||
|
||||
MessageWriteJSON(w, http.StatusOK, payload)
|
||||
return
|
||||
|
||||
case "":
|
||||
payload, err := MatchAndGetResponse(httpResponses, r.URL.Query(), true)
|
||||
if err != nil {
|
||||
log.Fatal("Mock Test Failure - MatchAndGetResponse error ", err)
|
||||
}
|
||||
|
||||
MessageWriteJSON(w, http.StatusOK, payload)
|
||||
return
|
||||
|
||||
case applicationJSON:
|
||||
readBody, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
log.Fatalf("Mock Test Failure - %v", err)
|
||||
}
|
||||
|
||||
reqVals, err := DeriveURLValsFromJSONMap(readBody)
|
||||
if err != nil {
|
||||
log.Fatalf("Mock Test Failure - %v", err)
|
||||
}
|
||||
|
||||
payload, err := MatchAndGetResponse(httpResponses, reqVals, false)
|
||||
if err != nil {
|
||||
log.Fatal("Mock Test Failure - MatchAndGetResponse error ", err)
|
||||
}
|
||||
|
||||
MessageWriteJSON(w, http.StatusOK, payload)
|
||||
return
|
||||
|
||||
case textPlain:
|
||||
headerData, ok := r.Header["X-Gemini-Payload"]
|
||||
if !ok {
|
||||
log.Fatal("Mock Test Failure - Cannot find header in request")
|
||||
}
|
||||
|
||||
base64data := strings.Join(headerData, "")
|
||||
|
||||
jsonThings, err := crypto.Base64Decode(base64data)
|
||||
if err != nil {
|
||||
log.Fatal("Mock Test Failure - ", err)
|
||||
}
|
||||
|
||||
reqVals, err := DeriveURLValsFromJSONMap(jsonThings)
|
||||
if err != nil {
|
||||
log.Fatalf("Mock Test Failure - %v", err)
|
||||
}
|
||||
|
||||
payload, err := MatchAndGetResponse(httpResponses, reqVals, false)
|
||||
if err != nil {
|
||||
log.Fatal("Mock Test Failure - MatchAndGetResponse error ", err)
|
||||
}
|
||||
|
||||
MessageWriteJSON(w, http.StatusOK, payload)
|
||||
return
|
||||
|
||||
default:
|
||||
log.Fatalf("Mock Test Failure - Unhandled content type %v",
|
||||
r.Header.Get(contentType))
|
||||
}
|
||||
|
||||
case http.MethodDelete:
|
||||
payload, err := MatchAndGetResponse(httpResponses, r.URL.Query(), true)
|
||||
if err != nil {
|
||||
log.Println(r.URL.Query())
|
||||
log.Fatal("Mock Test Failure - MatchAndGetResponse error ", err)
|
||||
}
|
||||
|
||||
MessageWriteJSON(w, http.StatusOK, payload)
|
||||
return
|
||||
|
||||
default:
|
||||
log.Fatal("Mock Test Failure - Unhandled HTTP method:",
|
||||
r.Header.Get(contentType))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// MessageWriteJSON writes JSON to a connection
|
||||
func MessageWriteJSON(w http.ResponseWriter, status int, data interface{}) {
|
||||
w.Header().Set(contentType, applicationJSON)
|
||||
w.WriteHeader(status)
|
||||
if data != nil {
|
||||
err := json.NewEncoder(w).Encode(data)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
log.Fatal("Mock Test Failure - JSON encode error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MatchAndGetResponse matches incoming request values with mockdata response
|
||||
// values and returns the payload
|
||||
func MatchAndGetResponse(mockData []HTTPResponse, requestVals url.Values, isQueryData bool) (json.RawMessage, error) {
|
||||
for i := range mockData {
|
||||
var data string
|
||||
if isQueryData {
|
||||
data = mockData[i].QueryString
|
||||
} else {
|
||||
data = mockData[i].BodyParams
|
||||
}
|
||||
|
||||
var mockVals = url.Values{}
|
||||
var err error
|
||||
if json.Valid([]byte(data)) {
|
||||
something := make(map[string]interface{})
|
||||
err = json.Unmarshal([]byte(data), &something)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for k, v := range something {
|
||||
switch val := v.(type) {
|
||||
case string:
|
||||
mockVals.Add(k, val)
|
||||
case bool:
|
||||
mockVals.Add(k, strconv.FormatBool(val))
|
||||
case float64:
|
||||
mockVals.Add(k, strconv.FormatFloat(val, 'f', -1, 64))
|
||||
case map[string]interface{}, []interface{}, nil:
|
||||
mockVals.Add(k, fmt.Sprintf("%v", val))
|
||||
default:
|
||||
log.Println(reflect.TypeOf(val))
|
||||
log.Fatal("unhandled type please add as needed")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mockVals, err = url.ParseQuery(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if MatchURLVals(mockVals, requestVals) {
|
||||
return mockData[i].Data, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("no data could be matched")
|
||||
}
|
||||
117
exchanges/mock/server_test.go
Normal file
117
exchanges/mock/server_test.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
)
|
||||
|
||||
type responsePayload struct {
|
||||
Price float64 `json:"price"`
|
||||
Amount float64 `json:"amount"`
|
||||
Currency string `json:"currency"`
|
||||
}
|
||||
|
||||
const queryString = "currency=btc&command=getprice"
|
||||
const testFile = "test.json"
|
||||
|
||||
func TestNewVCRServer(t *testing.T) {
|
||||
_, _, err := NewVCRServer("")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - NewVCRServer error cannot be nil")
|
||||
}
|
||||
|
||||
// Set up mock data
|
||||
test1 := VCRMock{}
|
||||
test1.Routes = make(map[string]map[string][]HTTPResponse)
|
||||
test1.Routes["/test"] = make(map[string][]HTTPResponse)
|
||||
|
||||
rp, err := json.Marshal(responsePayload{Price: 8000.0,
|
||||
Amount: 1,
|
||||
Currency: "bitcoin"})
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - marshal error", err)
|
||||
}
|
||||
|
||||
testValue := HTTPResponse{Data: rp, QueryString: queryString, BodyParams: queryString}
|
||||
test1.Routes["/test"][http.MethodGet] = []HTTPResponse{testValue}
|
||||
|
||||
payload, err := json.Marshal(test1)
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - marshal error", err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(testFile, payload, os.ModePerm)
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - marshal error", err)
|
||||
}
|
||||
|
||||
deets, client, err := NewVCRServer(testFile)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - NewVCRServer error", err)
|
||||
}
|
||||
|
||||
common.HTTPClient = client // Set common package global HTTP Client
|
||||
|
||||
_, err = common.SendHTTPRequest(http.MethodGet,
|
||||
"http://localhost:300/somethingElse?"+queryString,
|
||||
nil,
|
||||
bytes.NewBufferString(""))
|
||||
if err == nil {
|
||||
t.Error("Test Failed - Sending http request expected an error")
|
||||
}
|
||||
|
||||
// Expected good outcome
|
||||
r, err := common.SendHTTPRequest(http.MethodGet,
|
||||
deets,
|
||||
nil,
|
||||
bytes.NewBufferString(""))
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Sending http request error", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(r, "404 page not found") {
|
||||
t.Error("Test Failed - Was not expecting any value returned:", r)
|
||||
}
|
||||
|
||||
r, err = common.SendHTTPRequest(http.MethodGet,
|
||||
deets+"/test?"+queryString,
|
||||
nil,
|
||||
bytes.NewBufferString(""))
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Sending http request error", err)
|
||||
}
|
||||
|
||||
var res responsePayload
|
||||
err = json.Unmarshal([]byte(r), &res)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - unmarshal error", err)
|
||||
}
|
||||
|
||||
if res.Price != 8000 {
|
||||
t.Error("Test Failed - response error expected 8000 but received:",
|
||||
res.Price)
|
||||
}
|
||||
|
||||
if res.Amount != 1 {
|
||||
t.Error("Test Failed - response error expected 1 but received:",
|
||||
res.Amount)
|
||||
}
|
||||
|
||||
if res.Currency != "bitcoin" {
|
||||
t.Error("Test Failed - response error expected \"bitcoin\" but received:",
|
||||
res.Currency)
|
||||
}
|
||||
|
||||
// clean up test.json file
|
||||
err = os.Remove(testFile)
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - Remove error", err)
|
||||
}
|
||||
}
|
||||
@@ -576,7 +576,15 @@ func (o *OKGroup) SendHTTPRequest(httpMethod, requestType, requestPath string, d
|
||||
|
||||
errCap := errCapFormat{}
|
||||
errCap.Result = true
|
||||
err = o.SendPayload(strings.ToUpper(httpMethod), path, headers, bytes.NewBuffer(payload), &intermediary, authenticated, false, o.Verbose, o.HTTPDebugging)
|
||||
err = o.SendPayload(strings.ToUpper(httpMethod),
|
||||
path, headers,
|
||||
bytes.NewBuffer(payload),
|
||||
&intermediary,
|
||||
authenticated,
|
||||
false,
|
||||
o.Verbose,
|
||||
o.HTTPDebugging,
|
||||
o.HTTPRecording)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -224,8 +224,8 @@ func (p *Poloniex) GetLoanOrders(currency string) (LoanOrders, error) {
|
||||
// GetBalances returns balances for your account.
|
||||
func (p *Poloniex) GetBalances() (Balance, error) {
|
||||
var result interface{}
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexBalances, url.Values{}, &result)
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexBalances, url.Values{}, &result)
|
||||
if err != nil {
|
||||
return Balance{}, err
|
||||
}
|
||||
@@ -244,8 +244,8 @@ func (p *Poloniex) GetBalances() (Balance, error) {
|
||||
// GetCompleteBalances returns complete balances from your account.
|
||||
func (p *Poloniex) GetCompleteBalances() (CompleteBalances, error) {
|
||||
var result interface{}
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexBalancesComplete, url.Values{}, &result)
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexBalancesComplete, url.Values{}, &result)
|
||||
if err != nil {
|
||||
return CompleteBalances{}, err
|
||||
}
|
||||
@@ -270,14 +270,18 @@ func (p *Poloniex) GetCompleteBalances() (CompleteBalances, error) {
|
||||
func (p *Poloniex) GetDepositAddresses() (DepositAddresses, error) {
|
||||
var result interface{}
|
||||
addresses := DepositAddresses{}
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexDepositAddresses, url.Values{}, &result)
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexDepositAddresses, url.Values{}, &result)
|
||||
if err != nil {
|
||||
return addresses, err
|
||||
}
|
||||
|
||||
addresses.Addresses = make(map[string]string)
|
||||
data := result.(map[string]interface{})
|
||||
data, ok := result.(map[string]interface{})
|
||||
if !ok {
|
||||
return addresses, errors.New("return val not map[string]interface{}")
|
||||
}
|
||||
|
||||
for x, y := range data {
|
||||
addresses.Addresses[x] = y.(string)
|
||||
}
|
||||
@@ -297,7 +301,6 @@ func (p *Poloniex) GenerateNewAddress(currency string) (string, error) {
|
||||
values.Set("currency", currency)
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexGenerateNewAddress, values, &resp)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -498,7 +501,6 @@ func (p *Poloniex) Withdraw(currency, address string, amount float64) (bool, err
|
||||
values.Set("address", address)
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexWithdraw, values, &result)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -525,7 +527,6 @@ func (p *Poloniex) GetTradableBalances() (map[string]map[string]float64, error)
|
||||
result := Response{}
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexTradableBalances, url.Values{}, &result.Data)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -553,7 +554,6 @@ func (p *Poloniex) TransferBalance(currency, from, to string, amount float64) (b
|
||||
values.Set("toAccount", to)
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexTransferBalance, values, &result)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -619,7 +619,6 @@ func (p *Poloniex) CloseMarginPosition(currency string) (bool, error) {
|
||||
result := GenericResponse{}
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexMarginPositionClose, values, &result)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -655,7 +654,6 @@ func (p *Poloniex) CreateLoanOffer(currency string, amount, rate float64, durati
|
||||
result := Response{}
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexCreateLoanOffer, values, &result)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -674,7 +672,6 @@ func (p *Poloniex) CancelLoanOffer(orderNumber int64) (bool, error) {
|
||||
values.Set("orderID", strconv.FormatInt(orderNumber, 10))
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexCancelLoanOffer, values, &result)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -694,7 +691,6 @@ func (p *Poloniex) GetOpenLoanOffers() (map[string][]LoanOffer, error) {
|
||||
result := Response{}
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexOpenLoanOffers, url.Values{}, &result.Data)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -725,15 +721,10 @@ func (p *Poloniex) GetLendingHistory(start, end string) ([]LendingHistory, error
|
||||
}
|
||||
|
||||
var resp []LendingHistory
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost,
|
||||
return resp, p.SendAuthenticatedHTTPRequest(http.MethodPost,
|
||||
poloniexLendingHistory,
|
||||
vals,
|
||||
&resp)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ToggleAutoRenew allows for the autorenew of a contract
|
||||
@@ -746,7 +737,6 @@ func (p *Poloniex) ToggleAutoRenew(orderNumber int64) (bool, error) {
|
||||
poloniexAutoRenew,
|
||||
values,
|
||||
&result)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -768,7 +758,8 @@ func (p *Poloniex) SendHTTPRequest(path string, result interface{}) error {
|
||||
false,
|
||||
false,
|
||||
p.Verbose,
|
||||
p.HTTPDebugging)
|
||||
p.HTTPDebugging,
|
||||
p.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request
|
||||
@@ -777,13 +768,11 @@ func (p *Poloniex) SendAuthenticatedHTTPRequest(method, endpoint string, values
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet,
|
||||
p.Name)
|
||||
}
|
||||
|
||||
headers := make(map[string]string)
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
headers["Key"] = p.API.Credentials.Key
|
||||
|
||||
n := p.Requester.GetNonce(true).String()
|
||||
|
||||
values.Set("nonce", n)
|
||||
values.Set("nonce", p.Requester.GetNonce(true).String())
|
||||
values.Set("command", endpoint)
|
||||
|
||||
hmac := crypto.GetHMAC(crypto.HashSHA512,
|
||||
@@ -802,7 +791,8 @@ func (p *Poloniex) SendAuthenticatedHTTPRequest(method, endpoint string, values
|
||||
true,
|
||||
true,
|
||||
p.Verbose,
|
||||
p.HTTPDebugging)
|
||||
p.HTTPDebugging,
|
||||
p.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
32
exchanges/poloniex/poloniex_live_test.go
Normal file
32
exchanges/poloniex/poloniex_live_test.go
Normal file
@@ -0,0 +1,32 @@
|
||||
//+build mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is parsed and will do live testing
|
||||
// using all tests in (exchange)_test.go
|
||||
package poloniex
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
var mockTests = false
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
poloniexConfig, err := cfg.GetExchangeConfig("Poloniex")
|
||||
if err != nil {
|
||||
log.Fatal("Test Failed - Poloniex Setup() init error", err)
|
||||
}
|
||||
poloniexConfig.API.AuthenticatedSupport = true
|
||||
poloniexConfig.API.Credentials.Key = apiKey
|
||||
poloniexConfig.API.Credentials.Secret = apiSecret
|
||||
p.SetDefaults()
|
||||
p.Setup(poloniexConfig)
|
||||
log.Printf(sharedtestvalues.LiveTesting, p.GetName(), p.API.Endpoints.URL)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
45
exchanges/poloniex/poloniex_mock_test.go
Normal file
45
exchanges/poloniex/poloniex_mock_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
//+build !mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is not parsed and will try to mock
|
||||
// all tests in _test.go
|
||||
package poloniex
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/mock"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
const mockfile = "../../testdata/http_mock/poloniex/poloniex.json"
|
||||
|
||||
var mockTests = true
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
poloniexConfig, err := cfg.GetExchangeConfig("Poloniex")
|
||||
if err != nil {
|
||||
log.Fatal("Test Failed - Poloniex Setup() init error", err)
|
||||
}
|
||||
p.SkipAuthCheck = true
|
||||
poloniexConfig.API.AuthenticatedSupport = true
|
||||
poloniexConfig.API.Credentials.Key = apiKey
|
||||
poloniexConfig.API.Credentials.Secret = apiSecret
|
||||
p.SetDefaults()
|
||||
p.Setup(poloniexConfig)
|
||||
|
||||
serverDetails, newClient, err := mock.NewVCRServer(mockfile)
|
||||
if err != nil {
|
||||
log.Fatalf("Test Failed - Mock server error %s", err)
|
||||
}
|
||||
|
||||
p.HTTPClient = newClient
|
||||
p.API.Endpoints.URL = serverDetails
|
||||
|
||||
log.Printf(sharedtestvalues.MockTesting, p.GetName(), p.API.Endpoints.URL)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
@@ -7,15 +7,12 @@ import (
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
|
||||
)
|
||||
|
||||
var p Poloniex
|
||||
|
||||
// Please supply your own APIKEYS here for due diligence testing
|
||||
const (
|
||||
apiKey = ""
|
||||
@@ -23,31 +20,17 @@ const (
|
||||
canManipulateRealOrders = false
|
||||
)
|
||||
|
||||
var isSetup bool
|
||||
var p Poloniex
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
if !isSetup {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
poloniexConfig, err := cfg.GetExchangeConfig("Poloniex")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Poloniex Setup() init error")
|
||||
}
|
||||
poloniexConfig.API.AuthenticatedSupport = true
|
||||
poloniexConfig.API.AuthenticatedWebsocketSupport = true
|
||||
poloniexConfig.API.Credentials.Key = apiKey
|
||||
poloniexConfig.API.Credentials.Secret = apiSecret
|
||||
p.SetDefaults()
|
||||
p.Setup(poloniexConfig)
|
||||
isSetup = true
|
||||
}
|
||||
func areTestAPIKeysSet() bool {
|
||||
return p.ValidateAPICredentials()
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := p.GetTicker()
|
||||
if err != nil {
|
||||
t.Error("Test faild - Poloniex GetTicker() error")
|
||||
t.Error("Test Failed - Poloniex GetTicker() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,37 +98,43 @@ func setFeeBuilder() *exchange.FeeBuilder {
|
||||
// TestGetFeeByTypeOfflineTradeFee logic test
|
||||
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var feeBuilder = setFeeBuilder()
|
||||
p.GetFeeByType(feeBuilder)
|
||||
if apiKey == "" || apiSecret == "" {
|
||||
if feeBuilder.FeeType != exchange.OfflineTradeFee {
|
||||
t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType)
|
||||
t.Errorf("Expected %v, received %v",
|
||||
exchange.OfflineTradeFee,
|
||||
feeBuilder.FeeType)
|
||||
}
|
||||
} else {
|
||||
if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee {
|
||||
t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType)
|
||||
t.Errorf("Expected %v, received %v",
|
||||
exchange.CryptocurrencyTradeFee,
|
||||
feeBuilder.FeeType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
var feeBuilder = setFeeBuilder()
|
||||
|
||||
if areTestAPIKeysSet() {
|
||||
if areTestAPIKeysSet() || mockTests {
|
||||
// CryptocurrencyTradeFee Basic
|
||||
if resp, err := p.GetFee(feeBuilder); resp != float64(0.002) || err != nil {
|
||||
if resp, err := p.GetFee(feeBuilder); resp != float64(0.0025) || err != nil {
|
||||
t.Error(err)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.0015), resp)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0.0025), resp)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee High quantity
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.Amount = 1000
|
||||
feeBuilder.PurchasePrice = 1000
|
||||
if resp, err := p.GetFee(feeBuilder); resp != float64(2000) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(2000), resp)
|
||||
if resp, err := p.GetFee(feeBuilder); resp != float64(2500) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(2500), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -153,7 +142,8 @@ func TestGetFee(t *testing.T) {
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.PurchasePrice = -1000
|
||||
if resp, err := p.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -161,7 +151,8 @@ func TestGetFee(t *testing.T) {
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
|
||||
if resp, err := p.GetFee(feeBuilder); resp != float64(0.001) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.001), resp)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0.001), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -170,7 +161,8 @@ func TestGetFee(t *testing.T) {
|
||||
feeBuilder.Pair.Base = currency.NewCode("hello")
|
||||
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
|
||||
if resp, err := p.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -178,7 +170,8 @@ func TestGetFee(t *testing.T) {
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.CyptocurrencyDepositFee
|
||||
if resp, err := p.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -186,7 +179,8 @@ func TestGetFee(t *testing.T) {
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.InternationalBankDepositFee
|
||||
if resp, err := p.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -195,66 +189,67 @@ func TestGetFee(t *testing.T) {
|
||||
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
|
||||
feeBuilder.FiatCurrency = currency.USD
|
||||
if resp, err := p.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f",
|
||||
float64(0), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatWithdrawPermissions(t *testing.T) {
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
expectedResult := exchange.AutoWithdrawCryptoWithAPIPermissionText + " & " + exchange.NoFiatWithdrawalsText
|
||||
expectedResult := exchange.AutoWithdrawCryptoWithAPIPermissionText +
|
||||
" & " +
|
||||
exchange.NoFiatWithdrawalsText
|
||||
|
||||
withdrawPermissions := p.FormatWithdrawPermissions()
|
||||
|
||||
if withdrawPermissions != expectedResult {
|
||||
t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions)
|
||||
t.Errorf("Expected: %s, Received: %s",
|
||||
expectedResult,
|
||||
withdrawPermissions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetActiveOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
}
|
||||
|
||||
_, err := p.GetActiveOrders(&getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("Test Failed - GetActiveOrders() error", err)
|
||||
case !areTestAPIKeysSet() && !mockTests && err == nil:
|
||||
t.Error("Test Failed - Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock GetActiveOrders() err", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
}
|
||||
|
||||
_, err := p.GetOrderHistory(&getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Errorf("Could not get order history: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not mock get order history: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
func areTestAPIKeysSet() bool {
|
||||
return p.ValidateAPICredentials()
|
||||
}
|
||||
|
||||
func TestSubmitOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
@@ -265,51 +260,50 @@ func TestSubmitOrder(t *testing.T) {
|
||||
Quote: currency.LTC,
|
||||
},
|
||||
OrderSide: exchange.BuyOrderSide,
|
||||
OrderType: exchange.LimitOrderType,
|
||||
Price: 1,
|
||||
Amount: 1,
|
||||
ClientID: "meowOrder",
|
||||
OrderType: exchange.MarketOrderType,
|
||||
Price: 10,
|
||||
Amount: 10000000,
|
||||
ClientID: "hi",
|
||||
}
|
||||
|
||||
response, err := p.SubmitOrder(orderSubmission)
|
||||
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced):
|
||||
t.Errorf("Order failed to be placed: %v", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
case !areTestAPIKeysSet() && !mockTests && err == nil:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock SubmitOrder() err", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelExchangeOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
|
||||
|
||||
var orderCancellation = &exchange.OrderCancellation{
|
||||
OrderID: "1",
|
||||
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
AccountID: "1",
|
||||
CurrencyPair: currencyPair,
|
||||
CurrencyPair: currency.NewPair(currency.LTC, currency.BTC),
|
||||
}
|
||||
|
||||
err := p.CancelOrder(orderCancellation)
|
||||
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
switch {
|
||||
case !areTestAPIKeysSet() && !mockTests && err == nil:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock CancelExchangeOrder() err", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
@@ -323,14 +317,14 @@ func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
resp, err := p.CancelAllOrders(orderCancellation)
|
||||
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
switch {
|
||||
case !areTestAPIKeysSet() && !mockTests && err == nil:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock CancelAllExchangeOrders() err", err)
|
||||
}
|
||||
|
||||
if len(resp.OrderStatus) > 0 {
|
||||
t.Errorf("%v orders failed to cancel", len(resp.OrderStatus))
|
||||
}
|
||||
@@ -338,87 +332,90 @@ func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
|
||||
func TestModifyOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
_, err := p.ModifyOrder(&exchange.ModifyOrder{OrderID: "1337", Price: 1337})
|
||||
if err == nil {
|
||||
t.Error("Test Failed - ModifyOrder() error")
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && mockTests:
|
||||
t.Error("Test Failed - ModifyOrder() error", err)
|
||||
case !areTestAPIKeysSet() && !mockTests && err == nil:
|
||||
t.Error("Test Failed - ModifyOrder() error cannot be nil")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock ModifyOrder() err", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
withdrawCryptoRequest := exchange.CryptoWithdrawRequest{
|
||||
GenericWithdrawRequestInfo: exchange.GenericWithdrawRequestInfo{
|
||||
Amount: -1,
|
||||
Currency: currency.BTC,
|
||||
Amount: 0,
|
||||
Currency: currency.LTC,
|
||||
Description: "WITHDRAW IT ALL",
|
||||
},
|
||||
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
}
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
_, err := p.WithdrawCryptocurrencyFunds(&withdrawCryptoRequest)
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Errorf("Withdraw failed to be placed: %v", err)
|
||||
case !areTestAPIKeysSet() && !mockTests && err == nil:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock Withdraw() err", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawFiat(t *testing.T) {
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
var withdrawFiatRequest = exchange.FiatWithdrawRequest{}
|
||||
var withdrawFiatRequest exchange.FiatWithdrawRequest
|
||||
_, err := p.WithdrawFiatFunds(&withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
|
||||
t.Errorf("Expected '%v', received: '%v'",
|
||||
common.ErrFunctionNotSupported, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawInternationalBank(t *testing.T) {
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
var withdrawFiatRequest = exchange.FiatWithdrawRequest{}
|
||||
var withdrawFiatRequest exchange.FiatWithdrawRequest
|
||||
_, err := p.WithdrawFiatFundsToInternationalBank(&withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
|
||||
t.Errorf("Expected '%v', received: '%v'",
|
||||
common.ErrFunctionNotSupported, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDepositAddress(t *testing.T) {
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() {
|
||||
_, err := p.GetDepositAddress(currency.DASH, "")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetDepositAddress()", err)
|
||||
}
|
||||
} else {
|
||||
_, err := p.GetDepositAddress(currency.DASH, "")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetDepositAddress()")
|
||||
}
|
||||
_, err := p.GetDepositAddress(currency.DASH, "")
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("Test Failed - GetDepositAddress()", err)
|
||||
case !areTestAPIKeysSet() && !mockTests && err == nil:
|
||||
t.Error("Test Failed - GetDepositAddress() cannot be nil")
|
||||
case mockTests && err != nil:
|
||||
t.Error("Test Failed - Mock GetDepositAddress() err", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWsHandleAccountData(t *testing.T) {
|
||||
t.Parallel()
|
||||
TestSetup(t)
|
||||
p.Websocket.DataHandler = sharedtestvalues.GetWebsocketInterfaceChannelOverride()
|
||||
jsons := []string{
|
||||
`[["n",225,807230187,0,"1000.00000000","0.10000000","2018-11-07 16:42:42"],["b",267,"e","-0.10000000"]]`,
|
||||
@@ -438,7 +435,7 @@ func TestWsHandleAccountData(t *testing.T) {
|
||||
// TestWsAuth dials websocket, sends login request.
|
||||
// Will receive a message only on failure
|
||||
func TestWsAuth(t *testing.T) {
|
||||
TestSetup(t)
|
||||
t.Parallel()
|
||||
if !p.Websocket.IsEnabled() && !p.API.AuthenticatedWebsocketSupport || !areTestAPIKeysSet() {
|
||||
t.Skip(wshandler.WebsocketNotEnabled)
|
||||
}
|
||||
|
||||
@@ -457,7 +457,7 @@ func (p *Poloniex) GetWebsocket() (*wshandler.Websocket, error) {
|
||||
|
||||
// GetFeeByType returns an estimate of fee based on type of transaction
|
||||
func (p *Poloniex) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
if !p.AllowAuthenticatedRequest() && // Todo check connection status
|
||||
if (!p.AllowAuthenticatedRequest() || p.SkipAuthCheck) && // Todo check connection status
|
||||
feeBuilder.FeeType == exchange.CryptocurrencyTradeFee {
|
||||
feeBuilder.FeeType = exchange.OfflineTradeFee
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/mock"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/nonce"
|
||||
log "github.com/thrasher-corp/gocryptotrader/logger"
|
||||
)
|
||||
@@ -81,6 +82,7 @@ type Job struct {
|
||||
AuthRequest bool
|
||||
Verbose bool
|
||||
HTTPDebugging bool
|
||||
Record bool
|
||||
}
|
||||
|
||||
// NewRateLimit creates a new RateLimit
|
||||
@@ -279,14 +281,21 @@ func (r *Requester) checkRequest(method, path string, body io.Reader, headers ma
|
||||
}
|
||||
|
||||
// DoRequest performs a HTTP/HTTPS request with the supplied params
|
||||
func (r *Requester) DoRequest(req *http.Request, path string, body io.Reader, result interface{}, authRequest, verbose, httpDebug bool) error {
|
||||
func (r *Requester) DoRequest(req *http.Request, path string, body io.Reader, result interface{}, authRequest, verbose, httpDebug, httpRecord bool) error {
|
||||
if verbose {
|
||||
log.Debugf(log.Global,
|
||||
"%s exchange request path: %s requires rate limiter: %v", r.Name, path, r.RequiresRateLimiter())
|
||||
"%s exchange request path: %s requires rate limiter: %v",
|
||||
r.Name,
|
||||
path,
|
||||
r.RequiresRateLimiter())
|
||||
|
||||
for k, d := range req.Header {
|
||||
log.Debugf(log.Global, "%s exchange request header [%s]: %s", r.Name, k, d)
|
||||
}
|
||||
log.Debugln(log.Global, body)
|
||||
log.Debugf(log.Global,
|
||||
"%s exchange request type: %s", r.Name, req.Method)
|
||||
log.Debugf(log.Global,
|
||||
"%s exchange request body: %v", r.Name, body)
|
||||
}
|
||||
|
||||
var timeoutError error
|
||||
@@ -344,6 +353,14 @@ func (r *Requester) DoRequest(req *http.Request, path string, body io.Reader, re
|
||||
return err
|
||||
}
|
||||
|
||||
if httpRecord {
|
||||
// This dumps http responses for future mocking implementations
|
||||
err = mock.HTTPRecord(resp, r.Name, contents)
|
||||
if err != nil {
|
||||
return fmt.Errorf("mock recording failure %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 && resp.StatusCode != 201 && resp.StatusCode != 202 {
|
||||
err = fmt.Errorf("unsuccessful HTTP status code: %d", resp.StatusCode)
|
||||
if verbose {
|
||||
@@ -387,7 +404,7 @@ func (r *Requester) worker() {
|
||||
if !r.IsRateLimited(x.AuthRequest) {
|
||||
r.IncrementRequests(x.AuthRequest)
|
||||
|
||||
err := r.DoRequest(x.Request, x.Path, x.Body, x.Result, x.AuthRequest, x.Verbose, x.HTTPDebugging)
|
||||
err := r.DoRequest(x.Request, x.Path, x.Body, x.Result, x.AuthRequest, x.Verbose, x.HTTPDebugging, x.Record)
|
||||
x.JobResult <- &JobResult{
|
||||
Error: err,
|
||||
Result: x.Result,
|
||||
@@ -411,7 +428,7 @@ func (r *Requester) worker() {
|
||||
log.Debugf(log.ExchangeSys, "%s request. No longer rate limited! Doing request", r.Name)
|
||||
}
|
||||
|
||||
err := r.DoRequest(x.Request, x.Path, x.Body, x.Result, x.AuthRequest, x.Verbose, x.HTTPDebugging)
|
||||
err := r.DoRequest(x.Request, x.Path, x.Body, x.Result, x.AuthRequest, x.Verbose, x.HTTPDebugging, x.Record)
|
||||
x.JobResult <- &JobResult{
|
||||
Error: err,
|
||||
Result: x.Result,
|
||||
@@ -424,7 +441,7 @@ func (r *Requester) worker() {
|
||||
}
|
||||
|
||||
// SendPayload handles sending HTTP/HTTPS requests
|
||||
func (r *Requester) SendPayload(method, path string, headers map[string]string, body io.Reader, result interface{}, authRequest, nonceEnabled, verbose, httpDebugging bool) error {
|
||||
func (r *Requester) SendPayload(method, path string, headers map[string]string, body io.Reader, result interface{}, authRequest, nonceEnabled, verbose, httpDebugging, record bool) error {
|
||||
if !nonceEnabled {
|
||||
r.lock()
|
||||
}
|
||||
@@ -462,7 +479,7 @@ func (r *Requester) SendPayload(method, path string, headers map[string]string,
|
||||
|
||||
if !r.RequiresRateLimiter() {
|
||||
r.unlock()
|
||||
return r.DoRequest(req, path, body, result, authRequest, verbose, httpDebugging)
|
||||
return r.DoRequest(req, path, body, result, authRequest, verbose, httpDebugging, record)
|
||||
}
|
||||
|
||||
if len(r.Jobs) == MaxRequestJobs {
|
||||
@@ -491,6 +508,7 @@ func (r *Requester) SendPayload(method, path string, headers map[string]string,
|
||||
AuthRequest: authRequest,
|
||||
Verbose: verbose,
|
||||
HTTPDebugging: httpDebugging,
|
||||
Record: record,
|
||||
}
|
||||
|
||||
if verbose {
|
||||
|
||||
@@ -200,7 +200,7 @@ func TestCheckRequest(t *testing.T) {
|
||||
|
||||
func TestDoRequest(t *testing.T) {
|
||||
var test = new(Requester)
|
||||
err := test.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true, false)
|
||||
err := test.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true, false, false)
|
||||
if err == nil {
|
||||
t.Fatal("not iniitalised")
|
||||
}
|
||||
@@ -211,17 +211,17 @@ func TestDoRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
r.Name = "bitfinex"
|
||||
err = r.SendPayload("BLAH", "https://www.google.com", nil, nil, nil, false, false, true, false)
|
||||
err = r.SendPayload("BLAH", "https://www.google.com", nil, nil, nil, false, false, true, false, false)
|
||||
if err == nil {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
|
||||
err = r.SendPayload(http.MethodGet, "", nil, nil, nil, false, false, true, false)
|
||||
err = r.SendPayload(http.MethodGet, "", nil, nil, nil, false, false, true, false, false)
|
||||
if err == nil {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true, false)
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true, false, false)
|
||||
if err != nil {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
@@ -233,7 +233,7 @@ func TestDoRequest(t *testing.T) {
|
||||
r.SetRateLimit(false, time.Second, 0)
|
||||
r.SetRateLimit(true, time.Second, 0)
|
||||
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true, false)
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true, false, false)
|
||||
if err != nil {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
@@ -250,7 +250,7 @@ func TestDoRequest(t *testing.T) {
|
||||
t.Fatal("unexepcted values")
|
||||
}
|
||||
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true, false)
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, false, false, true, false, false)
|
||||
if err != nil {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
@@ -261,27 +261,27 @@ func TestDoRequest(t *testing.T) {
|
||||
t.Fatal("unexepcted values")
|
||||
}
|
||||
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, true, false, true, false)
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, nil, true, false, true, false, false)
|
||||
if err != nil {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
|
||||
var result interface{}
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, result, false, false, true, false)
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, result, false, false, true, false, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
headers := make(map[string]string)
|
||||
headers["content-type"] = "content/text"
|
||||
err = r.SendPayload(http.MethodPost, "https://bitfinex.com", headers, nil, result, false, false, true, false)
|
||||
err = r.SendPayload(http.MethodPost, "https://bitfinex.com", headers, nil, result, false, false, true, false, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r.StartCycle()
|
||||
r.UnauthLimit.SetRequests(100)
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, result, false, false, false, false)
|
||||
err = r.SendPayload(http.MethodGet, "https://www.google.com", nil, nil, result, false, false, false, false, false)
|
||||
if err != nil {
|
||||
t.Fatal("unexpected values")
|
||||
}
|
||||
@@ -297,7 +297,7 @@ func TestDoRequest(t *testing.T) {
|
||||
}
|
||||
|
||||
r.HTTPClient.Timeout = 1 * time.Second
|
||||
err = r.SendPayload(http.MethodPost, "https://httpstat.us/200?sleep=20000", nil, nil, nil, false, false, true, false)
|
||||
err = r.SendPayload(http.MethodPost, "https://httpstat.us/200?sleep=20000", nil, nil, nil, false, false, true, false, false)
|
||||
if err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -327,6 +327,6 @@ func BenchmarkRequestLockMech(b *testing.B) {
|
||||
var r = new(Requester)
|
||||
var meep interface{}
|
||||
for n := 0; n < b.N; n++ {
|
||||
r.SendPayload(http.MethodGet, "127.0.0.1", nil, nil, &meep, false, false, false, false)
|
||||
r.SendPayload(http.MethodGet, "127.0.0.1", nil, nil, &meep, false, false, false, false, false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,9 @@ const (
|
||||
// WebsocketChannelOverrideCapacity used in websocket testing
|
||||
// Defines channel capacity as defaults size can block tests
|
||||
WebsocketChannelOverrideCapacity = 20
|
||||
|
||||
MockTesting = "Mock testing framework in use for %s exchange @ %s on REST endpoints only"
|
||||
LiveTesting = "Mock testing bypassed; live testing of REST endpoints in use for %s exchange @ %s"
|
||||
)
|
||||
|
||||
// GetWebsocketInterfaceChannelOverride returns a new interface based channel
|
||||
|
||||
@@ -23,6 +23,7 @@ var Exchanges = []string{
|
||||
"itbit",
|
||||
"kraken",
|
||||
"lakebtc",
|
||||
"lbank",
|
||||
"localbitcoins",
|
||||
"okcoin international",
|
||||
"okex",
|
||||
|
||||
@@ -264,7 +264,8 @@ func (y *Yobit) SendHTTPRequest(path string, result interface{}) error {
|
||||
false,
|
||||
false,
|
||||
y.Verbose,
|
||||
y.HTTPDebugging)
|
||||
y.HTTPDebugging,
|
||||
y.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to Yobit
|
||||
@@ -305,7 +306,8 @@ func (y *Yobit) SendAuthenticatedHTTPRequest(path string, params url.Values, res
|
||||
true,
|
||||
true,
|
||||
y.Verbose,
|
||||
y.HTTPDebugging)
|
||||
y.HTTPDebugging,
|
||||
y.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
|
||||
@@ -286,7 +286,16 @@ func (z *ZB) GetCryptoAddress(currency currency.Code) (UserAddress, error) {
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (z *ZB) SendHTTPRequest(path string, result interface{}) error {
|
||||
return z.SendPayload(http.MethodGet, path, nil, nil, result, false, false, z.Verbose, z.HTTPDebugging)
|
||||
return z.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
z.Verbose,
|
||||
z.HTTPDebugging,
|
||||
z.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends authenticated requests to the zb API
|
||||
@@ -324,7 +333,8 @@ func (z *ZB) SendAuthenticatedHTTPRequest(httpMethod string, params url.Values,
|
||||
true,
|
||||
false,
|
||||
z.Verbose,
|
||||
z.HTTPDebugging)
|
||||
z.HTTPDebugging,
|
||||
z.HTTPRecording)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
1
testdata/README.md
vendored
1
testdata/README.md
vendored
@@ -42,3 +42,4 @@ When submitting a PR, please abide by our coding guidelines:
|
||||
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
|
||||
|
||||
***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***
|
||||
|
||||
|
||||
43
testdata/configtest.json
vendored
43
testdata/configtest.json
vendored
@@ -443,6 +443,49 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "LBank",
|
||||
"enabled": true,
|
||||
"verbose": false,
|
||||
"websocket": false,
|
||||
"useSandbox": false,
|
||||
"restPollingDelay": 10,
|
||||
"httpTimeout": 15000000000,
|
||||
"httpUserAgent": "",
|
||||
"httpDebugging": false,
|
||||
"authenticatedApiSupport": false,
|
||||
"authenticatedWebsocketApiSupport": false,
|
||||
"apiKey": "Key",
|
||||
"apiSecret": "Secret",
|
||||
"apiUrl": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
|
||||
"apiUrlSecondary": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
|
||||
"proxyAddress": "",
|
||||
"websocketUrl": "NON_DEFAULT_HTTP_LINK_TO_WEBSOCKET_EXCHANGE_API",
|
||||
"availablePairs": "fbc_usdt,hds_usdt,galt_usdt,dxn_usdt,iog_usdt,ioex_usdt,vollar_usdt,oath_usdt,bloc_usdt,btc_lbcn,eth_lbcn,usdt_lbcn,btc_usdt,eth_usdt,eth_btc,abbc_btc,bzky_eth,onot_eth,kisc_eth,bxa_usdt,atp_usdt,mat_usdt,sky_btc,sky_lbcn,rnt_usdt,vena_usdt,grin_usdt,ida_usdt,pnt_usdt,bsv_btc,bsv_usdt,opx_usdt,tena_eth,seer_lbcn,vet_lbcn,vtho_btc,vnx_lbcn,vnx_btc,amo_eth,ubex_btc,eos_btc,ubex_usdt,tns_lbcn,tns_btc,ali_eth,sdc_eth,sait_eth,artcn_usdt,dax_btc,dax_eth,dali_usdt,vet_usdt,ten_usdt,bch_usdt,neo_usdt,qtum_usdt,zec_usdt,vet_btc,pai_btc,pnt_btc,bch_btc,ltc_btc,neo_btc,dash_btc,etc_btc,qtum_btc,zec_btc,sc_btc,bts_btc,cpx_btc,xwc_btc,fil6_btc,fil12_btc,fil36_btc,eos_usdt,ut_eth,ela_eth,vet_eth,vtho_eth,pai_eth,bfdt_eth,her_eth,ptt_eth,tac_eth,idhub_eth,ssc_eth,skm_eth,iic_eth,ply_eth,ext_eth,eos_eth,yoyow_eth,trx_eth,qtum_eth,zec_eth,bts_eth,btm_eth,mith_eth,nas_eth,man_eth,dbc_eth,bto_eth,ddd_eth,cpx_eth,cs_eth,iht_eth,tky_eth,ocn_eth,dct_eth,zpt_eth,eko_eth,mda_eth,pst_eth,xwc_eth,put_eth,pnt_eth,aac_eth,fil6_eth,fil12_eth,fil36_eth,uip_eth,seer_eth,bsb_eth,cdc_eth,grams_eth,ddmx_eth,eai_eth,inc_eth,bnb_usdt,ht_usdt,bot_eth,kbc_btc,kbc_usdt,mai_usdt,phv_usdt,hnb_usdt,gt_usdt,b91_usdt,voken_usdt,cye_usdt,brc_usdt,btc_ausd",
|
||||
"enabledPairs": "eth_btc",
|
||||
"baseCurrencies": "USD",
|
||||
"assetTypes": "SPOT",
|
||||
"supportsAutoPairUpdates": true,
|
||||
"configCurrencyPairFormat": {
|
||||
"uppercase": false,
|
||||
"delimiter": "_"
|
||||
},
|
||||
"requestCurrencyPairFormat": {
|
||||
"uppercase": false,
|
||||
"delimiter": "_"
|
||||
},
|
||||
"bankAccounts": [
|
||||
{
|
||||
"bankName": "",
|
||||
"bankAddress": "",
|
||||
"accountName": "",
|
||||
"accountNumber": "",
|
||||
"swiftCode": "",
|
||||
"iban": "",
|
||||
"supportedCurrencies": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Bittrex",
|
||||
"enabled": true,
|
||||
|
||||
2404
testdata/http_mock/anx/anx.json
vendored
Normal file
2404
testdata/http_mock/anx/anx.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
45467
testdata/http_mock/binance/binance.json
vendored
Normal file
45467
testdata/http_mock/binance/binance.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
42842
testdata/http_mock/bitstamp/bitstamp.json
vendored
Normal file
42842
testdata/http_mock/bitstamp/bitstamp.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
19
testdata/http_mock/exclusion.json
vendored
Normal file
19
testdata/http_mock/exclusion.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"headers": [
|
||||
"Key",
|
||||
"X-Mbx-Apikey",
|
||||
"Rest-Key",
|
||||
"Apiauth-Key",
|
||||
"X-Gemini-Apikey"
|
||||
],
|
||||
"variables": [
|
||||
"bsb",
|
||||
"user",
|
||||
"name",
|
||||
"real_name",
|
||||
"receiver_name",
|
||||
"account_number",
|
||||
"username",
|
||||
"login"
|
||||
]
|
||||
}
|
||||
2734
testdata/http_mock/gemini/gemini.json
vendored
Normal file
2734
testdata/http_mock/gemini/gemini.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3400
testdata/http_mock/localbitcoins/localbitcoins.json
vendored
Normal file
3400
testdata/http_mock/localbitcoins/localbitcoins.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9031
testdata/http_mock/poloniex/poloniex.json
vendored
Normal file
9031
testdata/http_mock/poloniex/poloniex.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user