diff --git a/APIUtils.go b/APIUtils.go index 84459936..fb3768c1 100644 --- a/APIUtils.go +++ b/APIUtils.go @@ -3,7 +3,7 @@ package goex import ( "errors" "fmt" - "github.com/nntaoli-project/GoEx/internal/logger" + "github.com/nntaoli-project/goex/internal/logger" "reflect" "time" ) diff --git a/Const.go b/Const.go index 535cc1a9..ffd7a4dc 100644 --- a/Const.go +++ b/Const.go @@ -135,6 +135,7 @@ const ( ZB = "zb.com" BITFINEX = "bitfinex.com" BINANCE = "binance.com" + BINANCE_SWAP = "binance.com_swap" POLONIEX = "poloniex.com" COINEX = "coinex.com" BITHUMB = "bithumb.com" @@ -153,4 +154,5 @@ const ( CRYPTOPIA = "cryptopia.co.nz" HBDM = "hbdm.com" COINBENE = "coinbene.com" + ATOP = "a.top" ) diff --git a/HttpUtils.go b/HttpUtils.go index e10e5dab..60639b83 100644 --- a/HttpUtils.go +++ b/HttpUtils.go @@ -5,7 +5,7 @@ import ( "encoding/json" "errors" "fmt" - "github.com/nntaoli-project/GoEx/internal/logger" + "github.com/nntaoli-project/goex/internal/logger" "github.com/valyala/fasthttp" "github.com/valyala/fasthttp/fasthttpproxy" "io/ioutil" @@ -63,7 +63,7 @@ func NewHttpRequestWithFasthttp(client *http.Client, reqMethod, reqUrl, postData } func NewHttpRequest(client *http.Client, reqType string, reqUrl string, postData string, requstHeaders map[string]string) ([]byte, error) { - logger.Log.Debug("request url: ", reqUrl) + logger.Log.Debugf("[%s] request url: %s", reqType, reqUrl) lib := os.Getenv("HTTP_LIB") if lib == "fasthttp" { return NewHttpRequestWithFasthttp(client, reqType, reqUrl, postData, requstHeaders) @@ -216,3 +216,11 @@ func HttpDeleteForm(client *http.Client, reqUrl string, postData url.Values, hea headers["Content-Type"] = "application/x-www-form-urlencoded" return NewHttpRequest(client, "DELETE", reqUrl, postData.Encode(), headers) } + +func HttpPut(client *http.Client, reqUrl string, postData url.Values, headers map[string]string) ([]byte, error) { + if headers == nil { + headers = map[string]string{} + } + headers["Content-Type"] = "application/x-www-form-urlencoded" + return NewHttpRequest(client, "PUT", reqUrl, postData.Encode(), headers) +} diff --git a/LICENSE b/LICENSE index 793ceb12..42f213f2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 GoEx +Copyright (c) 2017 goex Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index c63ade55..3ca21ad3 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@
-GoEx - +goex +
-### GoEx目标 +### goex目标 -GoEx项目是为了统一并标准化各个数字资产交易平台的接口而设计,同一个策略可以随时切换到任意一个交易平台,而不需要更改任何代码。 +goex项目是为了统一并标准化各个数字资产交易平台的接口而设计,同一个策略可以随时切换到任意一个交易平台,而不需要更改任何代码。 -[English](https://github.com/nntaoli-project/GoEx/blob/dev/README_en.md) +[English](https://github.com/nntaoli-project/goex/blob/dev/README_en.md) -### GoEx已支持交易所 `22+` +### goex已支持交易所 `22+` | 交易所 | 行情接口 | 交易接口 | 版本号 | | --- | --- | --- | --- | @@ -35,14 +35,14 @@ GoEx项目是为了统一并标准化各个数字资产交易平台的接口而 | coinbig.com | Y | Y | * | |coinbene.com|Y|Y|*| -### 安装GoEx库 +### 安装goex库 -``` go get github.com/nntaoli-project/GoEx ``` +``` go get github.com/nntaoli-project/goex ``` >建议go mod 管理依赖 ``` require ( - github.com/nntaoli-project/GoEx v1.0.4 + github.com/nntaoli-project/goex v1.0.4 ) ``` @@ -53,8 +53,8 @@ require ( package main import ( - "github.com/nntaoli-project/GoEx" - "github.com/nntaoli-project/GoEx/builder" + "github.com/nntaoli-project/goex" + "github.com/nntaoli-project/goex/builder" "log" "time" ) @@ -87,9 +87,9 @@ require ( ```golang import ( - "github.com/nntaoli-project/GoEx" - "github.com/nntaoli-project/GoEx/huobi" - //"github.com/nntaoli-project/GoEx/okcoin" + "github.com/nntaoli-project/goex" + "github.com/nntaoli-project/goex/huobi" + //"github.com/nntaoli-project/goex/okcoin" "log" ) @@ -115,7 +115,7 @@ func main() { ### 更多文档 -[GoEx.TOP](https://goex.top) +[goex.TOP](https://goex.top) ### 注意事项 @@ -137,4 +137,4 @@ ETH:0x98573ddb33cdddce480c3bc1f9279ccd88ca1e93 ### 欢迎为作者付一碗面钱 -一碗面钱   一碗面钱 +一碗面钱   一碗面钱 diff --git a/README_en.md b/README_en.md index d164a895..5eb62a30 100644 --- a/README_en.md +++ b/README_en.md @@ -1,14 +1,14 @@
-GoEx +goex
-### GoEx +### goex -GoEx project is designed to unify and standardize the interfaces of each digital asset trading platform. The same strategy can be switched to any trading platform at any time without changing any code. +goex project is designed to unify and standardize the interfaces of each digital asset trading platform. The same strategy can be switched to any trading platform at any time without changing any code. -[中文](https://github.com/nntaoli-project/GoEx/blob/dev/README.md) +[中文](https://github.com/nntaoli-project/goex/blob/dev/README.md) -### Exchanges are supported by GoEx `22+` +### Exchanges are supported by goex `22+` | Exchange | Market API | Order API | Version | | --- | --- | --- | --- | | hbg.com | Y | Y | 1 | @@ -35,8 +35,8 @@ GoEx project is designed to unify and standardize the interfaces of each digital | btcchina.com | Y | Y | 1 | | coinbig.com | Y | Y | * | -### Install GoEx -``` go get github.com/nntaoli-project/GoEx ``` +### Install goex +``` go get github.com/nntaoli-project/goex ``` ### Example ```golang @@ -44,8 +44,8 @@ GoEx project is designed to unify and standardize the interfaces of each digital package main import ( - "github.com/nntaoli-project/GoEx" - "github.com/nntaoli-project/GoEx/builder" + "github.com/nntaoli-project/goex" + "github.com/nntaoli-project/goex/builder" "log" "time" ) @@ -77,9 +77,9 @@ GoEx project is designed to unify and standardize the interfaces of each digital ### websocket Example ```golang import ( - "github.com/nntaoli-project/GoEx" - "github.com/nntaoli-project/GoEx/huobi" - //"github.com/nntaoli-project/GoEx/okcoin" + "github.com/nntaoli-project/goex" + "github.com/nntaoli-project/goex/huobi" + //"github.com/nntaoli-project/goex/okcoin" "log" ) @@ -105,7 +105,7 @@ func main() { ### More Detail -[GoEx.TOP](https://goex.top) +[goex.TOP](https://goex.top) # Highly Recommended(IMPORTANCE) 1. use GoLand development. @@ -120,4 +120,4 @@ Join QQ group: [574829125](#) ### Buy me a Coffe -Buy me a Coffe   Buy me a Coffe +Buy me a Coffe   Buy me a Coffe diff --git a/aacoin/aacoin.go b/aacoin/aacoin.go index 3e67b836..e4f30ca4 100755 --- a/aacoin/aacoin.go +++ b/aacoin/aacoin.go @@ -1,7 +1,7 @@ package aacoin import ( - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/http" "net/url" diff --git a/aacoin/aacoin_test.go b/aacoin/aacoin_test.go index 9051c36a..75fee2ed 100644 --- a/aacoin/aacoin_test.go +++ b/aacoin/aacoin_test.go @@ -1,7 +1,7 @@ package aacoin import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "net/url" "testing" diff --git a/allcoin/allcoin.go b/allcoin/allcoin.go index d568b434..759640c0 100755 --- a/allcoin/allcoin.go +++ b/allcoin/allcoin.go @@ -3,7 +3,7 @@ package allcoin import ( "encoding/json" "errors" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "log" "net/http" "net/url" diff --git a/allcoin/allcoin_test.go b/allcoin/allcoin_test.go index f213ca12..9a794116 100644 --- a/allcoin/allcoin_test.go +++ b/allcoin/allcoin_test.go @@ -1,7 +1,7 @@ package allcoin import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "testing" ) diff --git a/atop/atop.go b/atop/atop.go new file mode 100644 index 00000000..00331e86 --- /dev/null +++ b/atop/atop.go @@ -0,0 +1,630 @@ +package atop + +/** + +LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) +LimitSell(amount, price string, currency CurrencyPair) (*Order, error) +MarketBuy(amount, price string, currency CurrencyPair) (*Order, error) +MarketSell(amount, price string, currency CurrencyPair) (*Order, error) +CancelOrder(orderId string, currency CurrencyPair) (bool, error) +GetOneOrder(orderId string, currency CurrencyPair) (*Order, error) +GetUnfinishOrders(currency CurrencyPair) ([]Order, error) +GetOrderHistorys(currency CurrencyPair, currentPage, pageSize int) ([]Order, error) +GetAccount() (*Account, error) + +GetTicker(currency CurrencyPair) (*Ticker, error) +GetDepth(size int, currency CurrencyPair) (*Depth, error) +GetKlineRecords(currency CurrencyPair, period , size, since int) ([]Kline, error) +//Non-individual, transaction record of the entire exchange +GetTrades(currencyPair CurrencyPair, since int64) ([]Trade, error) + +GetExchangeName() string +*/ + +import ( + "encoding/json" + "errors" + "fmt" + . "github.com/nntaoli-project/goex" + + "log" + "net/http" + "net/url" + "sort" + "strconv" + "strings" + "time" +) + +const ( + //test https://testapi.a.top + //product https://api.a.top + ApiBaseUrl = "https://testapi.a.top" + //ApiBaseUrl = "https://api.a.top" + + ////market data + + //Trading market configuration + GetMarketConfig = "/data/api/v1/getMarketConfig" + + //K line data + GetKLine = "/data/api/v1/getKLine" + + //Aggregate market + GetTicker = "/data/api/v1/getTicker?market=%s" + + //The latest Ticker for all markets + GetTickers = "/data/api/v1/getTickers" + + //Market depth data + GetDepth = "/data/api/v1/getDepth?market=%s" + + //Recent market record + GetTrades = "/data/api/v1/getTrades" + + ////trading + + //Get server time (no signature required) + GetServerTime = "/trade/api/v1/getServerTime" + + //Get atcount balance + GetBalance = "/trade/api/v1/getBalance" + + //Plate the order + PlateOrder = "/trade/api/v1/order" + + //Commissioned by batch + BatchOrder = "/trade/api/v1/batchOrder" + + //cancellations + CancelOrder = "/trade/api/v1/cancel" + + //From a single batch + BatchCancel = "/trade/api/v1/batchCancel" + + //The order information + GetOrder = "/trade/api/v1/getOrder" + + //Gets an outstanding order + GetOpenOrders = "/trade/api/v1/getOpenOrders" + + //Get orders history + GetHistorys = "/trade/api/v1/getHistorys" + + //Gets multiple order information + GetBatchOrders = "/trade/api/v1/getBatchOrders" + + //Gets the recharge address + GetPayInAddress = "/trade/api/v1/getPayInAddress" + + //Get the withdrawal address + GetPayOutAddress = "/trade/api/v1/getPayOutAddress" + + //Gets the recharge record + GetPayInRecord = "/trade/api/v1/getPayInRecord" + + //Get the withdrawal record + GetPayOutRecord = "/trade/api/v1/getPayOutRecord" + + //Withdrawal configuration + GetWithdrawConfig = "/trade/api/v1/getWithdrawConfig" + + //withdraw + Withdrawal = "/trade/api/v1/withdraw" +) + +var KlinePeriodConverter = map[int]string{ + KLINE_PERIOD_1MIN: "1min", + KLINE_PERIOD_3MIN: "3min", + KLINE_PERIOD_5MIN: "5min", + KLINE_PERIOD_15MIN: "15min", + KLINE_PERIOD_30MIN: "30min", + KLINE_PERIOD_60MIN: "1hour", + KLINE_PERIOD_1H: "1hour", + KLINE_PERIOD_2H: "2hour", + KLINE_PERIOD_4H: "4hour", + KLINE_PERIOD_6H: "6hour", + KLINE_PERIOD_8H: "8hour", + KLINE_PERIOD_12H: "12hour", + KLINE_PERIOD_1DAY: "1day", + KLINE_PERIOD_3DAY: "3day", + KLINE_PERIOD_1WEEK: "7day", + KLINE_PERIOD_1MONTH: "30day", +} + +type Atop struct { + accessKey, + secretKey string + httpClient *http.Client +} + +//hao +func (at *Atop) buildPostForm(postForm *url.Values) error { + postForm.Set("accesskey", at.accessKey) + nonce := strconv.FormatInt(time.Now().UnixNano()/1e6, 10) + postForm.Set("nonce", nonce) + payload := postForm.Encode() + //fmt.Println("payload", payload) + sign, _ := GetParamHmacSHA256Sign(at.secretKey, payload) + postForm.Set("signature", sign) + return nil +} + +func New(client *http.Client, apiKey, secretKey string) *Atop { + return &Atop{apiKey, secretKey, client} +} + +func (at *Atop) GetExchangeName() string { + return "atop.com" +} + +//hao +func (at *Atop) GetTicker(currency CurrencyPair) (*Ticker, error) { + market := strings.ToLower(currency.String()) + tickerUrl := ApiBaseUrl + fmt.Sprintf(GetTicker, market) + resp, err := HttpGet(at.httpClient, tickerUrl) + if err != nil { + return nil, err + } + respMap := resp + var ticker Ticker + ticker.Pair = currency + ticker.Date = uint64(time.Now().Unix()) + ticker.Last = ToFloat64(respMap["price"]) + ticker.Buy = ToFloat64(respMap["bid"]) + ticker.Sell = ToFloat64(respMap["ask"]) + ticker.Low = ToFloat64(respMap["low"]) + ticker.High = ToFloat64(respMap["high"]) + ticker.Vol = ToFloat64(respMap["coinVol"]) + return &ticker, nil +} + +//hao +func (at *Atop) GetDepth(size int, currency CurrencyPair) (*Depth, error) { + market := strings.ToLower(currency.String()) + depthUrl := ApiBaseUrl + fmt.Sprintf(GetDepth, market) + resp, err := HttpGet(at.httpClient, depthUrl) + if err != nil { + return nil, err + } + respMap := resp + + bids := respMap["bids"].([]interface{}) + asks := respMap["asks"].([]interface{}) + + depth := new(Depth) + depth.Pair = currency + for _, bid := range bids { + _bid := bid.([]interface{}) + amount := ToFloat64(_bid[1]) + price := ToFloat64(_bid[0]) + dr := DepthRecord{Amount: amount, Price: price} + depth.BidList = append(depth.BidList, dr) + } + + for _, ask := range asks { + _ask := ask.([]interface{}) + amount := ToFloat64(_ask[1]) + price := ToFloat64(_ask[0]) + dr := DepthRecord{Amount: amount, Price: price} + depth.AskList = append(depth.AskList, dr) + } + sort.Sort(depth.AskList) + return depth, nil +} + +//hao +func (at *Atop) plateOrder(amount, price string, currencyPair CurrencyPair, orderType, orderSide string) (*Order, error) { + pair := at.adaptCurrencyPair(currencyPair) + path := ApiBaseUrl + PlateOrder + params := url.Values{} + params.Set("market", pair.ToLower().String()) //btc_usdt eth_usdt + if orderSide == "buy" { + params.Set("type", strconv.Itoa(1)) + } else { + params.Set("type", strconv.Itoa(0)) + } + //params.Set("type", orderSide)//Transaction Type 1、buy 0、sell + params.Set("price", price) + params.Set("number", amount) + if orderType == "market" { + params.Set("entrustType", strconv.Itoa(1)) + } else { + params.Set("entrustType", strconv.Itoa(0)) + } + //params.Set("entrustType", orderType)//Delegate type 0、limit,1、market + at.buildPostForm(¶ms) + resp, err := HttpPostForm(at.httpClient, path, params) + //log.Println("resp:", string(resp), "err:", err) + if err != nil { + return nil, err + } + + respMap := make(map[string]interface{}) + err = json.Unmarshal(resp, &respMap) + if err != nil { + log.Println(string(resp)) + return nil, err + } + + code := respMap["code"].(float64) + if code != 200 { + return nil, errors.New(respMap["info"].(string)) + } + + //return &Order{}, nil + data := respMap["data"].(map[string]interface{}) + + orderId := data["id"].(float64) + side := BUY + if orderSide == "sale" { + side = SELL + } + + return &Order{ + Currency: pair, + //OrderID: + OrderID2: strconv.FormatFloat(orderId, 'f', 0, 64), + Price: ToFloat64(price), + Amount: ToFloat64(amount), + DealAmount: 0, + AvgPrice: 0, + Side: TradeSide(side), + Status: ORDER_UNFINISH, + OrderTime: int(time.Now().Unix())}, nil +} + +//hao +func (at *Atop) GetAccount() (*Account, error) { + params := url.Values{} + at.buildPostForm(¶ms) + path := ApiBaseUrl + GetBalance + //fmt.Println("GetBalance", path) + resp, err := HttpPostForm(at.httpClient, path, params) + if err != nil { + return nil, err + } + respMap := make(map[string]interface{}) + err = json.Unmarshal(resp, &respMap) + if err != nil { + return nil, err + } + data := respMap["data"].(map[string]interface{}) + atc := Account{} + atc.Exchange = at.GetExchangeName() + atc.SubAccounts = make(map[Currency]SubAccount) + for k, v := range data { + cur := NewCurrency(k, "") + vv := v.(map[string]interface{}) + sub := SubAccount{} + sub.Currency = cur + sub.Amount = ToFloat64(vv["available"]) + ToFloat64(vv["freeze"]) + sub.ForzenAmount = ToFloat64(vv["freeze"]) + atc.SubAccounts[cur] = sub + } + return &atc, nil +} + +//hao +func (at *Atop) LimitBuy(amount, price string, currencyPair CurrencyPair) (*Order, error) { + return at.plateOrder(amount, price, currencyPair, "limit", "buy") +} + +//hao +func (at *Atop) LimitSell(amount, price string, currencyPair CurrencyPair) (*Order, error) { + return at.plateOrder(amount, price, currencyPair, "limit", "sale") +} + +//hao +func (at *Atop) MarketBuy(amount, price string, currencyPair CurrencyPair) (*Order, error) { + return at.plateOrder(amount, price, currencyPair, "market", "buy") +} + +//hao +func (at *Atop) MarketSell(amount, price string, currencyPair CurrencyPair) (*Order, error) { + return at.plateOrder(amount, price, currencyPair, "market", "sale") +} + +func (at *Atop) CancelOrder(orderId string, currencyPair CurrencyPair) (bool, error) { + currencyPair = at.adaptCurrencyPair(currencyPair) + path := ApiBaseUrl + CancelOrder + params := url.Values{} + params.Set("api_key", at.accessKey) + params.Set("market", currencyPair.ToLower().String()) + params.Set("id", orderId) + + at.buildPostForm(¶ms) + + resp, err := HttpPostForm(at.httpClient, path, params) + + if err != nil { + return false, err + } + + respMap := make(map[string]interface{}) + err = json.Unmarshal(resp, &respMap) + if err != nil { + log.Println(string(resp)) + return false, err + } + code := respMap["code"].(float64) + if code != 200 { + return false, errors.New(respMap["info"].(string)) + } + + //orderIdCanceled := ToInt(respmap["orderId"]) + //if orderIdCanceled <= 0 { + // return false, errors.New(string(resp)) + //} + + return true, nil +} + +//hao? +func (at *Atop) GetOneOrder(orderId string, currencyPair CurrencyPair) (*Order, error) { + currencyPair = at.adaptCurrencyPair(currencyPair) + path := ApiBaseUrl + GetOrder + log.Println(path) + params := url.Values{} + params.Set("api_key", at.accessKey) + params.Set("market", currencyPair.ToLower().String()) + params.Set("id", orderId) + at.buildPostForm(¶ms) + resp, err := HttpPostForm(at.httpClient, path, params) + + if err != nil { + return nil, err + } + + respMap := make(map[string]interface{}) + err = json.Unmarshal(resp, &respMap) + if err != nil { + log.Println(string(resp)) + return nil, err + } + code := respMap["code"].(float64) + + if code != 200 { + return nil, errors.New(respMap["info"].(string)) + } + + data := respMap["data"].(map[string]interface{}) + + status := data["status"].(float64) + side := data["flag"] + + ord := Order{} + ord.Currency = currencyPair + //ord.OrderID = ToInt(orderId) + ord.OrderID2 = orderId + + if side == "sale" { + ord.Side = SELL + } else { + ord.Side = BUY + } + + switch status { + case 0: + ord.Status = ORDER_UNFINISH + case 1: + ord.Status = ORDER_PART_FINISH + case 2: + ord.Status = ORDER_FINISH + case 3: + ord.Status = ORDER_CANCEL + //case 4: + // ord.Status = new(TradeStatus)//settle + //case "PENDING_CANCEL": + // ord.Status = ORDER_CANCEL_ING + //case "REJECTED": + // ord.Status = ORDER_REJECT + } + ord.Amount = ToFloat64(data["number"]) + ord.Price = ToFloat64(data["price"]) + ord.DealAmount = ord.Amount - ToFloat64(data["completeNumber"]) //? + ord.AvgPrice = ToFloat64(data["avg_price"]) // response no avg price , fill price + + return &ord, nil +} + +//hao +func (at *Atop) GetUnfinishOrders(currencyPair CurrencyPair) ([]Order, error) { + pair := at.adaptCurrencyPair(currencyPair) + path := ApiBaseUrl + GetOpenOrders + params := url.Values{} + params.Set("market", pair.ToLower().String()) + params.Set("page", "1") + params.Set("pageSize", "10000") + at.buildPostForm(¶ms) + + resp, err := HttpPostForm(at.httpClient, path, params) + if err != nil { + return nil, err + } + respMap := make(map[string]interface{}) + err = json.Unmarshal(resp, &respMap) + if err != nil { + log.Println(string(resp)) + return nil, err + } + + code := respMap["code"].(float64) + if code != 200 { + return nil, errors.New(respMap["info"].(string)) + } + data := respMap["data"].([]interface{}) + orders := make([]Order, 0) + for _, ord := range data { + ordData := ord.(map[string]interface{}) + orderId := strconv.FormatFloat(ordData["id"].(float64), 'f', 0, 64) + orders = append(orders, Order{ + OrderID: 0, + OrderID2: orderId, + Currency: currencyPair, + Price: ToFloat64(ordData["price"]), + Amount: ToFloat64(ordData["number"]), + Side: TradeSide(ToInt(ordData["type"])), + Status: TradeStatus(ToInt(ordData["status"])), + OrderTime: ToInt(ordData["time"])}) + } + return orders, nil +} + +//hao +func (at *Atop) GetKlineRecords(currency CurrencyPair, period, size, since int) ([]Kline, error) { + pair := at.adaptCurrencyPair(currency) + params := url.Values{} + params.Set("market", pair.ToLower().String()) + //params.Set("type", "1min") //1min,5min,15min,30min,1hour,6hour,1day,7day,30day + params.Set("type", KlinePeriodConverter[period]) //1min,5min,15min,30min,1hour,6hour,1day,7day,30day + params.Set("since", fmt.Sprintf("%d", size)) //The first time is 0, followed by the value of the response since + + klineUrl := ApiBaseUrl + GetKLine + "?" + params.Encode() + kLines, err := HttpGet(at.httpClient, klineUrl) + if err != nil { + return nil, err + } + var klineRecords []Kline + for _, _record := range kLines["datas"].([]interface{}) { + r := Kline{Pair: currency} + record := _record.([]interface{}) + for i, e := range record { + switch i { + case 0: + r.Timestamp = int64(e.(float64)) //to unix timestramp + case 1: + r.Open = ToFloat64(e) + case 2: + r.High = ToFloat64(e) + case 3: + r.Low = ToFloat64(e) + case 4: + r.Close = ToFloat64(e) + case 5: + r.Vol = ToFloat64(e) + } + } + klineRecords = append(klineRecords, r) + } + + return klineRecords, nil +} + +// hao Non-individual, transaction record of the entire exchange +func (at *Atop) GetTrades(currencyPair CurrencyPair, since int64) ([]Trade, error) { + pair := at.adaptCurrencyPair(currencyPair) + params := url.Values{} + params.Set("market", pair.ToLower().String()) + + apiUrl := ApiBaseUrl + GetTrades + "?" + params.Encode() + + resp, err := HttpGet(at.httpClient, apiUrl) + if err != nil { + return nil, err + } + + var trades []Trade + for _, v := range resp { + m := v.(map[string]interface{}) + ty := SELL + if m["isBuyerMaker"].(bool) { + ty = BUY + } + trades = append(trades, Trade{ + Tid: ToInt64(m["id"]), + Type: ty, + Amount: ToFloat64(m["qty"]), + Price: ToFloat64(m["price"]), + Date: ToInt64(m["time"]), + Pair: currencyPair, + }) + } + + return trades, nil +} + +func (at *Atop) GetOrderHistorys(currency CurrencyPair, currentPage, pageSize int) ([]Order, error) { + //panic("not support") + pair := at.adaptCurrencyPair(currency) + path := ApiBaseUrl + GetHistorys + params := url.Values{} + params.Set("market", pair.ToLower().String()) + //params.Set("type", "1") + //params.Set("status", "0") + params.Set("page", fmt.Sprint(currentPage)) + params.Set("pageSize", fmt.Sprint(pageSize)) + + at.buildPostForm(¶ms) + resp, err := HttpPostForm(at.httpClient, path, params) + if err != nil { + return nil, err + } + respMap := make(map[string]interface{}) + err = json.Unmarshal(resp, &respMap) + if err != nil { + log.Println(string(resp)) + return nil, err + } + + code := respMap["code"].(float64) + if code != 200 { + return nil, errors.New(respMap["info"].(string)) + } + data := respMap["data"].(map[string]interface{}) + records := data["record"].([]interface{}) + orders := make([]Order, 0) + for _, ord := range records { + ordData := ord.(map[string]interface{}) + orderId := strconv.FormatFloat(ordData["id"].(float64), 'f', 0, 64) + orders = append(orders, Order{ + OrderID: 0, + OrderID2: orderId, + Currency: currency, + Price: ToFloat64(ordData["price"]), + Amount: ToFloat64(ordData["number"]), + Side: TradeSide(ToInt(ordData["type"])), + Status: TradeStatus(ToInt(ordData["status"])), + OrderTime: ToInt(ordData["time"])}) + } + return orders, nil + +} + +// hao +func (at *Atop) Withdraw(amount, memo string, currency Currency, fees, receiveAddr, safePwd string) (string, error) { + params := url.Values{} + coin := strings.ToLower(currency.Symbol) + path := ApiBaseUrl + Withdrawal + params.Set("coin", coin) + params.Set("address", receiveAddr) + params.Set("amount", amount) + params.Set("receiveAddr", receiveAddr) + params.Set("safePwd", safePwd) + //params.Set("memo", memo) + at.buildPostForm(¶ms) + + resp, err := HttpPostForm(at.httpClient, path, params) + + if err != nil { + return "", err + } + + respMap := make(map[string]interface{}) + err = json.Unmarshal(resp, &respMap) + if err != nil { + return "", err + } + + if respMap["code"].(float64) == 200 { + return respMap["id"].(string), nil + } + return "", errors.New(string(resp)) +} + +func (at *Atop) CancelWithdraw(id string, currency Currency, safePwd string) (bool, error) { + panic("not support") +} +func (at *Atop) adaptCurrencyPair(pair CurrencyPair) CurrencyPair { + return pair +} diff --git a/atop/atop_test.go b/atop/atop_test.go new file mode 100644 index 00000000..71acde68 --- /dev/null +++ b/atop/atop_test.go @@ -0,0 +1 @@ +package atop diff --git a/bigone/Bigone.go b/bigone/Bigone.go index bac5a858..d84412ee 100644 --- a/bigone/Bigone.go +++ b/bigone/Bigone.go @@ -8,7 +8,7 @@ import ( "time" "github.com/google/uuid" - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "github.com/nubo/jwt" ) diff --git a/bigone/BigoneV3.go b/bigone/BigoneV3.go index 9449cde5..ce4a946e 100644 --- a/bigone/BigoneV3.go +++ b/bigone/BigoneV3.go @@ -9,7 +9,7 @@ import ( "time" "github.com/google/uuid" - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "github.com/nubo/jwt" ) diff --git a/bigone/BigoneV3_test.go b/bigone/BigoneV3_test.go index b321b93f..3e36c129 100644 --- a/bigone/BigoneV3_test.go +++ b/bigone/BigoneV3_test.go @@ -1,7 +1,7 @@ package bigone import ( - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/http" "testing" diff --git a/bigone/Bigone_test.go b/bigone/Bigone_test.go index 39433f70..d0758457 100644 --- a/bigone/Bigone_test.go +++ b/bigone/Bigone_test.go @@ -1,7 +1,7 @@ package bigone import ( - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/http" "testing" ) diff --git a/binance/Binance.go b/binance/Binance.go index 5ebbab07..4c4e054b 100644 --- a/binance/Binance.go +++ b/binance/Binance.go @@ -3,11 +3,11 @@ package binance import ( "errors" "fmt" - . "github.com/nntaoli-project/GoEx" - "log" + . "github.com/nntaoli-project/goex" "net/http" "net/url" "strconv" + "strings" "time" ) @@ -20,7 +20,7 @@ const ( TICKERS_URI = "ticker/allBookTickers" DEPTH_URI = "depth?symbol=%s&limit=%d" ACCOUNT_URI = "account?" - ORDER_URI = "order?" + ORDER_URI = "order" UNFINISHED_ORDERS_INFO = "openOrders?" KLINE_URI = "klines" SERVER_TIME_URL = "time" @@ -46,32 +46,102 @@ var _INERNAL_KLINE_PERIOD_CONVERTER = map[int]string{ } type Filter struct { - FilterType string `json:"filterType"` - MaxPrice string `json:"maxPrice"` - MinPrice string `json:"minPrice"` - TickSize string `json:"tickSize"` + FilterType string `json:"filterType"` + MaxPrice float64 `json:"maxPrice,string"` + MinPrice float64 `json:"minPrice,string"` + TickSize float64 `json:"tickSize,string"` + MultiplierUp float64 `json:"multiplierUp,string"` + MultiplierDown float64 `json:"multiplierDown,string"` + AvgPriceMins int `json:"avgPriceMins"` + MinQty float64 `json:"minQty,string"` + MaxQty float64 `json:"maxQty,string"` + StepSize float64 `json:"stepSize,string"` + MinNotional float64 `json:"minNotional,string"` + ApplyToMarket bool `json:"applyToMarket"` + Limit int `json:"limit"` + MaxNumAlgoOrders int `json:"maxNumAlgoOrders"` + MaxNumIcebergOrders int `json:"maxNumIcebergOrders"` + MaxNumOrders int `json:"maxNumOrders"` } type RateLimit struct { Interval string `json:"interval"` - IntervalNum int `json:"intervalNum"` - Limit int `json:"limit"` + IntervalNum int64 `json:"intervalNum"` + Limit int64 `json:"limit"` RateLimitType string `json:"rateLimitType"` } type TradeSymbol struct { - BaseAsset string `json:"baseAsset"` - BaseAssetPrecision int `json:"baseAssetPrecision"` - Filters []Filter `json:"filters"` - IcebergAllowed bool `json:"icebergAllowed"` - IsMarginTradingAllowed bool `json:"isMarginTradingAllowed"` - IsSpotTradingAllowed bool `json:"isSpotTradingAllowed"` - OcoAllowed bool `json:"ocoAllowed"` - OrderTypes []string `json:"orderTypes"` - QuoteAsset string `json:"quoteAsset"` - QuotePrecision int `json:"quotePrecision"` - Status string `json:"status"` - Symbol string `json:"symbol"` + Symbol string `json:"symbol"` + Status string `json:"status"` + BaseAsset string `json:"baseAsset"` + BaseAssetPrecision int `json:"baseAssetPrecision"` + QuoteAsset string `json:"quoteAsset"` + QuotePrecision int `json:"quotePrecision"` + BaseCommissionPrecision int `json:"baseCommissionPrecision"` + QuoteCommissionPrecision int `json:"quoteCommissionPrecision"` + Filters []Filter `json:"filters"` + IcebergAllowed bool `json:"icebergAllowed"` + IsMarginTradingAllowed bool `json:"isMarginTradingAllowed"` + IsSpotTradingAllowed bool `json:"isSpotTradingAllowed"` + OcoAllowed bool `json:"ocoAllowed"` + QuoteOrderQtyMarketAllowed bool `json:"quoteOrderQtyMarketAllowed"` + OrderTypes []string `json:"orderTypes"` +} + +func (ts TradeSymbol) GetMinAmount() float64 { + for _, v := range ts.Filters { + if v.FilterType == "LOT_SIZE" { + return v.MinQty + } + } + return 0 +} + +func (ts TradeSymbol) GetAmountPrecision() int { + for _, v := range ts.Filters { + if v.FilterType == "LOT_SIZE" { + step := strconv.FormatFloat(v.StepSize, 'f', -1, 64) + pres := strings.Split(step, ".") + if len(pres) == 1 { + return 0 + } + return len(pres[1]) + } + } + return 0 +} + +func (ts TradeSymbol) GetMinPrice() float64 { + for _, v := range ts.Filters { + if v.FilterType == "PRICE_FILTER" { + return v.MinPrice + } + } + return 0 +} + +func (ts TradeSymbol) GetMinValue() float64 { + for _, v := range ts.Filters { + if v.FilterType == "MIN_NOTIONAL" { + return v.MinNotional + } + } + return 0 +} + +func (ts TradeSymbol) GetPricePrecision() int { + for _, v := range ts.Filters { + if v.FilterType == "PRICE_FILTER" { + step := strconv.FormatFloat(v.TickSize, 'f', -1, 64) + pres := strings.Split(step, ".") + if len(pres) == 1 { + return 0 + } + return len(pres[1]) + } + } + return 0 } type ExchangeInfo struct { @@ -83,19 +153,19 @@ type ExchangeInfo struct { } type Binance struct { - accessKey string - secretKey string - baseUrl string - apiV1 string - apiV3 string - httpClient *http.Client - timeoffset int64 //nanosecond - tradeSymbols []TradeSymbol + accessKey string + secretKey string + baseUrl string + apiV1 string + apiV3 string + httpClient *http.Client + timeOffset int64 //nanosecond + *ExchangeInfo } func (bn *Binance) buildParamsSigned(postForm *url.Values) error { postForm.Set("recvWindow", "60000") - tonce := strconv.FormatInt(time.Now().UnixNano()+bn.timeoffset, 10)[0:13] + tonce := strconv.FormatInt(time.Now().UnixNano()+bn.timeOffset, 10)[0:13] postForm.Set("timestamp", tonce) payload := postForm.Encode() sign, _ := GetParamHmacSHA256Sign(bn.secretKey, payload) @@ -131,6 +201,14 @@ func (bn *Binance) GetExchangeName() string { return BINANCE } +func (bn *Binance) Ping() bool { + _, err := HttpGet(bn.httpClient, bn.apiV3+"ping") + if err != nil { + return false + } + return true +} + func (bn *Binance) setTimeOffset() error { respmap, err := HttpGet(bn.httpClient, bn.apiV3+SERVER_TIME_URL) if err != nil { @@ -141,7 +219,7 @@ func (bn *Binance) setTimeOffset() error { st := time.Unix(stime/1000, 1000000*(stime%1000)) lt := time.Now() offset := st.Sub(lt).Nanoseconds() - bn.timeoffset = int64(offset) + bn.timeOffset = int64(offset) return nil } @@ -151,7 +229,6 @@ func (bn *Binance) GetTicker(currency CurrencyPair) (*Ticker, error) { tickerMap, err := HttpGet(bn.httpClient, tickerUri) if err != nil { - log.Println("GetTicker error:", err) return nil, err } @@ -169,17 +246,26 @@ func (bn *Binance) GetTicker(currency CurrencyPair) (*Ticker, error) { } func (bn *Binance) GetDepth(size int, currencyPair CurrencyPair) (*Depth, error) { - if size > 1000 { - size = 1000 - } else if size < 5 { + if size <= 5 { size = 5 + } else if size <= 10 { + size = 10 + } else if size <= 20 { + size = 20 + } else if size <= 50 { + size = 50 + } else if size <= 100 { + size = 100 + } else if size <= 500 { + size = 500 + } else { + size = 1000 } currencyPair2 := bn.adaptCurrencyPair(currencyPair) apiUrl := fmt.Sprintf(bn.apiV3+DEPTH_URI, currencyPair2.ToSymbol(""), size) resp, err := HttpGet(bn.httpClient, apiUrl) if err != nil { - log.Println("GetDepth error:", err) return nil, err } @@ -192,20 +278,31 @@ func (bn *Binance) GetDepth(size int, currencyPair CurrencyPair) (*Depth, error) depth := new(Depth) depth.Pair = currencyPair + depth.UTime = time.Now() + n := 0 for _, bid := range bids { _bid := bid.([]interface{}) amount := ToFloat64(_bid[1]) price := ToFloat64(_bid[0]) dr := DepthRecord{Amount: amount, Price: price} depth.BidList = append(depth.BidList, dr) + n++ + if n == size { + break + } } + n = 0 for _, ask := range asks { _ask := ask.([]interface{}) amount := ToFloat64(_ask[1]) price := ToFloat64(_ask[0]) dr := DepthRecord{Amount: amount, Price: price} depth.AskList = append(depth.AskList, dr) + n++ + if n == size { + break + } } return depth, nil @@ -226,7 +323,7 @@ func (bn *Binance) placeOrder(amount, price string, pair CurrencyPair, orderType params.Set("timeInForce", "GTC") params.Set("price", price) case "MARKET": - params.Set("newOrderRespType", "FULL") + params.Set("newOrderRespType", "RESULT") } bn.buildParamsSigned(¶ms) @@ -240,7 +337,6 @@ func (bn *Binance) placeOrder(amount, price string, pair CurrencyPair, orderType respmap := make(map[string]interface{}) err = json.Unmarshal(resp, &respmap) if err != nil { - log.Println(string(resp)) return nil, err } @@ -264,7 +360,7 @@ func (bn *Binance) placeOrder(amount, price string, pair CurrencyPair, orderType return &Order{ Currency: pair, OrderID: orderId, - OrderID2: fmt.Sprint(orderId), + OrderID2: strconv.Itoa(orderId), Price: ToFloat64(price), Amount: ToFloat64(amount), DealAmount: dealAmount, @@ -280,7 +376,6 @@ func (bn *Binance) GetAccount() (*Account, error) { path := bn.apiV3 + ACCOUNT_URI + params.Encode() respmap, err := HttpGet2(bn.httpClient, path, map[string]string{"X-MBX-APIKEY": bn.accessKey}) if err != nil { - log.Println(err) return nil, err } if _, isok := respmap["code"]; isok == true { @@ -338,7 +433,6 @@ func (bn *Binance) CancelOrder(orderId string, currencyPair CurrencyPair) (bool, respmap := make(map[string]interface{}) err = json.Unmarshal(resp, &respmap) if err != nil { - log.Println(string(resp)) return false, err } @@ -360,7 +454,7 @@ func (bn *Binance) GetOneOrder(orderId string, currencyPair CurrencyPair) (*Orde params.Set("orderId", orderId) bn.buildParamsSigned(¶ms) - path := bn.apiV3 + ORDER_URI + params.Encode() + path := bn.apiV3 + ORDER_URI + "?" + params.Encode() respmap, err := HttpGet2(bn.httpClient, path, map[string]string{"X-MBX-APIKEY": bn.accessKey}) if err != nil { @@ -433,11 +527,45 @@ func (bn *Binance) GetUnfinishOrders(currencyPair CurrencyPair) ([]Order, error) if side == "BUY" { orderSide = BUY } + ordId := ToInt(ord["orderId"]) + orders = append(orders, Order{ + OrderID: ordId, + OrderID2: strconv.Itoa(ordId), + Currency: currencyPair, + Price: ToFloat64(ord["price"]), + Amount: ToFloat64(ord["origQty"]), + Side: TradeSide(orderSide), + Status: ORDER_UNFINISH, + OrderTime: ToInt(ord["time"])}) + } + return orders, nil +} + +func (bn *Binance) GetAllUnfinishOrders() ([]Order, error) { + params := url.Values{} + + bn.buildParamsSigned(¶ms) + path := bn.apiV3 + UNFINISHED_ORDERS_INFO + params.Encode() + respmap, err := HttpGet3(bn.httpClient, path, map[string]string{"X-MBX-APIKEY": bn.accessKey}) + if err != nil { + return nil, err + } + + orders := make([]Order, 0) + for _, v := range respmap { + ord := v.(map[string]interface{}) + side := ord["side"].(string) + orderSide := SELL + if side == "BUY" { + orderSide = BUY + } + + ordId := ToInt(ord["orderId"]) orders = append(orders, Order{ OrderID: ToInt(ord["orderId"]), - OrderID2: fmt.Sprint(ToInt(ord["orderId"])), - Currency: currencyPair, + OrderID2: strconv.Itoa(ordId), + Currency: bn.toCurrencyPair(ord["symbol"].(string)), Price: ToFloat64(ord["price"]), Amount: ToFloat64(ord["origQty"]), Side: TradeSide(orderSide), @@ -468,22 +596,13 @@ func (bn *Binance) GetKlineRecords(currency CurrencyPair, period, size, since in for _, _record := range klines { r := Kline{Pair: currency} record := _record.([]interface{}) - for i, e := range record { - switch i { - case 0: - r.Timestamp = int64(e.(float64)) / 1000 //to unix timestramp - case 1: - r.Open = ToFloat64(e) - case 2: - r.High = ToFloat64(e) - case 3: - r.Low = ToFloat64(e) - case 4: - r.Close = ToFloat64(e) - case 5: - r.Vol = ToFloat64(e) - } - } + r.Timestamp = int64(record[0].(float64)) / 1000 //to unix timestramp + r.Open = ToFloat64(record[1]) + r.High = ToFloat64(record[2]) + r.Low = ToFloat64(record[3]) + r.Close = ToFloat64(record[4]) + r.Vol = ToFloat64(record[5]) + klineRecords = append(klineRecords, r) } @@ -528,10 +647,42 @@ func (bn *Binance) GetTrades(currencyPair CurrencyPair, since int64) ([]Trade, e } func (bn *Binance) GetOrderHistorys(currency CurrencyPair, currentPage, pageSize int) ([]Order, error) { - panic("not implements") + params := url.Values{} + currency1 := bn.adaptCurrencyPair(currency) + params.Set("symbol", currency1.ToSymbol("")) + + bn.buildParamsSigned(¶ms) + path := bn.apiV3 + "allOrders?" + params.Encode() + + respmap, err := HttpGet3(bn.httpClient, path, map[string]string{"X-MBX-APIKEY": bn.accessKey}) + if err != nil { + return nil, err + } + + orders := make([]Order, 0) + for _, v := range respmap { + ord := v.(map[string]interface{}) + side := ord["side"].(string) + orderSide := SELL + if side == "BUY" { + orderSide = BUY + } + ordId := ToInt(ord["orderId"]) + orders = append(orders, Order{ + OrderID: ToInt(ord["orderId"]), + OrderID2: strconv.Itoa(ordId), + Currency: currency, + Price: ToFloat64(ord["price"]), + Amount: ToFloat64(ord["origQty"]), + Side: TradeSide(orderSide), + Status: ORDER_UNFINISH, + OrderTime: ToInt(ord["time"])}) + } + return orders, nil + } -func (ba *Binance) adaptCurrencyPair(pair CurrencyPair) CurrencyPair { +func (bn *Binance) adaptCurrencyPair(pair CurrencyPair) CurrencyPair { if pair.CurrencyA.Eq(BCH) || pair.CurrencyA.Eq(BCC) { return NewCurrencyPair(NewCurrency("BCHABC", ""), pair.CurrencyB).AdaptUsdToUsdt() } @@ -543,31 +694,47 @@ func (ba *Binance) adaptCurrencyPair(pair CurrencyPair) CurrencyPair { return pair.AdaptUsdToUsdt() } -func (bn *Binance) getTradeSymbols() ([]TradeSymbol, error) { +func (bn *Binance) toCurrencyPair(symbol string) CurrencyPair { + if bn.ExchangeInfo == nil { + var err error + bn.ExchangeInfo, err = bn.GetExchangeInfo() + if err != nil { + return CurrencyPair{} + } + } + for _, v := range bn.ExchangeInfo.Symbols { + if v.Symbol == symbol { + return NewCurrencyPair2(v.BaseAsset + "_" + v.QuoteAsset) + } + } + return CurrencyPair{} +} + +func (bn *Binance) GetExchangeInfo() (*ExchangeInfo, error) { resp, err := HttpGet5(bn.httpClient, bn.apiV3+"exchangeInfo", nil) if err != nil { return nil, err } - info := new(ExchangeInfo) + info := &ExchangeInfo{} err = json.Unmarshal(resp, info) if err != nil { return nil, err } - return info.Symbols, nil + return info, nil } -func (bn *Binance) GetTradeSymbols(currencyPair CurrencyPair) (*TradeSymbol, error) { - if len(bn.tradeSymbols) == 0 { +func (bn *Binance) GetTradeSymbol(currencyPair CurrencyPair) (*TradeSymbol, error) { + if bn.ExchangeInfo == nil { var err error - bn.tradeSymbols, err = bn.getTradeSymbols() + bn.ExchangeInfo, err = bn.GetExchangeInfo() if err != nil { return nil, err } } - for k, v := range bn.tradeSymbols { + for k, v := range bn.ExchangeInfo.Symbols { if v.Symbol == currencyPair.ToSymbol("") { - return &bn.tradeSymbols[k], nil + return &bn.ExchangeInfo.Symbols[k], nil } } return nil, errors.New("symbol not found") diff --git a/binance/BinanceSwap.go b/binance/BinanceSwap.go new file mode 100644 index 00000000..ea1c3149 --- /dev/null +++ b/binance/BinanceSwap.go @@ -0,0 +1,733 @@ +package binance + +import ( + "errors" + "fmt" + . "github.com/nntaoli-project/goex" + "net/url" + "strconv" + "sync" + "time" +) + +const ( + baseUrl = "https://fapi.binance.com" +) + +type BinanceSwap struct { + Binance +} + +func NewBinanceSwap(config *APIConfig) *BinanceSwap { + if config.Endpoint == "" { + config.Endpoint = baseUrl + } + bs := &BinanceSwap{ + Binance: Binance{ + baseUrl: config.Endpoint, + accessKey: config.ApiKey, + apiV1: config.Endpoint + "/fapi/v1/", + secretKey: config.ApiSecretKey, + httpClient: config.HttpClient, + }, + } + bs.setTimeOffset() + return bs +} + +func (bs *BinanceSwap) SetBaseUri(uri string) { + bs.baseUrl = uri +} + +func (bs *BinanceSwap) GetExchangeName() string { + return BINANCE_SWAP +} + +func (bs *BinanceSwap) Ping() bool { + _, err := HttpGet(bs.httpClient, bs.apiV1+"ping") + if err != nil { + return false + } + return true +} + +func (bs *BinanceSwap) setTimeOffset() error { + respmap, err := HttpGet(bs.httpClient, bs.apiV1+SERVER_TIME_URL) + if err != nil { + return err + } + + stime := int64(ToInt(respmap["serverTime"])) + st := time.Unix(stime/1000, 1000000*(stime%1000)) + lt := time.Now() + offset := st.Sub(lt).Nanoseconds() + bs.timeOffset = int64(offset) + return nil +} + +/** + *获取交割预估价 + */ +func (bs *BinanceSwap) GetFutureEstimatedPrice(currencyPair CurrencyPair) (float64, error) { + panic("not supported.") +} + +/** + * 期货行情 + * @param currency_pair btc_usd:比特币 ltc_usd :莱特币 + * @param contractType 合约类型: this_week:当周 next_week:下周 month:当月 quarter:季度 + */ +func (bs *BinanceSwap) GetFutureTicker(currency CurrencyPair, contractType string) (*Ticker, error) { + currency2 := bs.adaptCurrencyPair(currency) + tickerPriceUri := bs.apiV1 + "ticker/price?symbol=" + currency2.ToSymbol("") + tickerBookUri := bs.apiV1 + "ticker/bookTicker?symbol=" + currency2.ToSymbol("") + tickerPriceMap := make(map[string]interface{}) + tickerBookeMap := make(map[string]interface{}) + var err1 error + var err2 error + wg := sync.WaitGroup{} + wg.Add(2) + go func() { + defer wg.Done() + tickerPriceMap, err1 = HttpGet(bs.httpClient, tickerPriceUri) + }() + go func() { + defer wg.Done() + tickerBookeMap, err2 = HttpGet(bs.httpClient, tickerBookUri) + }() + wg.Wait() + if err1 != nil { + return nil, err1 + } + if err2 != nil { + return nil, err2 + } + + var ticker Ticker + ticker.Pair = currency + ticker.Date = uint64(time.Now().UnixNano() / int64(time.Millisecond)) + ticker.Last = ToFloat64(tickerPriceMap["price"]) + ticker.Buy = ToFloat64(tickerBookeMap["bidPrice"]) + ticker.Sell = ToFloat64(tickerBookeMap["askPrice"]) + return &ticker, nil +} + +/** + * 期货深度 + * @param currencyPair btc_usd:比特币 ltc_usd :莱特币 + * @param contractType 合约类型: this_week:当周 next_week:下周 month:当月 quarter:季度 + * @param size 获取深度档数 + * @return + */ + +func (bs *BinanceSwap) GetFutureDepth(currency CurrencyPair, contractType string, size int) (*Depth, error) { + if size <= 5 { + size = 5 + } else if size <= 10 { + size = 10 + } else if size <= 20 { + size = 20 + } else if size <= 50 { + size = 50 + } else if size <= 100 { + size = 100 + } else if size <= 500 { + size = 500 + } else { + size = 1000 + } + currencyPair2 := bs.adaptCurrencyPair(currency) + + apiUrl := fmt.Sprintf(bs.apiV1+DEPTH_URI, currencyPair2.ToSymbol(""), size) + resp, err := HttpGet(bs.httpClient, apiUrl) + if err != nil { + return nil, err + } + + if _, isok := resp["code"]; isok { + return nil, errors.New(resp["msg"].(string)) + } + + bids := resp["bids"].([]interface{}) + asks := resp["asks"].([]interface{}) + + depth := new(Depth) + depth.Pair = currency + depth.UTime = time.Now() + n := 0 + for _, bid := range bids { + _bid := bid.([]interface{}) + amount := ToFloat64(_bid[1]) + price := ToFloat64(_bid[0]) + dr := DepthRecord{Amount: amount, Price: price} + depth.BidList = append(depth.BidList, dr) + n++ + if n == size { + break + } + } + + n = 0 + for _, ask := range asks { + _ask := ask.([]interface{}) + amount := ToFloat64(_ask[1]) + price := ToFloat64(_ask[0]) + dr := DepthRecord{Amount: amount, Price: price} + depth.AskList = append(depth.AskList, dr) + n++ + if n == size { + break + } + } + + return depth, nil +} + +func (bs *BinanceSwap) GetTrades(contractType string, currencyPair CurrencyPair, since int64) ([]Trade, error) { + param := url.Values{} + param.Set("symbol", bs.adaptCurrencyPair(currencyPair).ToSymbol("")) + param.Set("limit", "500") + if since > 0 { + param.Set("fromId", strconv.Itoa(int(since))) + } + apiUrl := bs.apiV1 + "historicalTrades?" + param.Encode() + resp, err := HttpGet3(bs.httpClient, apiUrl, map[string]string{ + "X-MBX-APIKEY": bs.accessKey}) + if err != nil { + return nil, err + } + + var trades []Trade + for _, v := range resp { + m := v.(map[string]interface{}) + ty := SELL + if m["isBuyerMaker"].(bool) { + ty = BUY + } + trades = append(trades, Trade{ + Tid: ToInt64(m["id"]), + Type: ty, + Amount: ToFloat64(m["qty"]), + Price: ToFloat64(m["price"]), + Date: ToInt64(m["time"]), + Pair: currencyPair, + }) + } + + return trades, nil + +} + +/** + * 期货指数 + * @param currencyPair btc_usd:比特币 ltc_usd :莱特币 + */ +func (bs *BinanceSwap) GetFutureIndex(currencyPair CurrencyPair) (float64, error) { + respmap, err := HttpGet(bs.httpClient, bs.apiV1+"premiumIndex?symbol="+bs.adaptCurrencyPair(currencyPair).ToSymbol("")) + if err != nil { + return 0.0, err + } + + return ToFloat64(respmap["markPrice"]), nil +} + +/** + *全仓账户 + */ +func (bs *BinanceSwap) GetFutureUserinfo() (*FutureAccount, error) { + params := url.Values{} + bs.buildParamsSigned(¶ms) + path := bs.apiV1 + ACCOUNT_URI + params.Encode() + respmap, err := HttpGet2(bs.httpClient, path, map[string]string{"X-MBX-APIKEY": bs.accessKey}) + if err != nil { + return nil, err + } + if _, isok := respmap["code"]; isok == true { + return nil, errors.New(respmap["msg"].(string)) + } + acc := &FutureAccount{} + acc.FutureSubAccounts = make(map[Currency]FutureSubAccount) + + balances := respmap["assets"].([]interface{}) + for _, v := range balances { + vv := v.(map[string]interface{}) + currency := NewCurrency(vv["asset"].(string), "").AdaptBccToBch() + acc.FutureSubAccounts[currency] = FutureSubAccount{ + Currency: currency, + AccountRights: ToFloat64(vv["walletBalance"]), + KeepDeposit: ToFloat64(vv["marginBalance"]), + ProfitUnreal: ToFloat64(vv["unrealizedProfit"]), + RiskRate: ToFloat64(vv["unrealizedProfit"]), + } + } + return acc, nil +} + +// transferType - 1: 现货账户向合约账户划转 2: 合约账户向现货账户划转 +func (bs *BinanceSwap) Transfer(currency Currency, transferType int, amount float64) (int64, error) { + params := url.Values{} + + params.Set("currency", currency.String()) + params.Set("amount", fmt.Sprint(amount)) + params.Set("type", strconv.Itoa(transferType)) + uri := "https://api.binance.com/sapi/v1/futures/transfer" + bs.buildParamsSigned(¶ms) + + resp, err := HttpPostForm2(bs.httpClient, uri, params, + map[string]string{"X-MBX-APIKEY": bs.accessKey}) + if err != nil { + return 0, err + } + + respmap := make(map[string]interface{}) + err = json.Unmarshal(resp, &respmap) + if err != nil { + return 0, err + } + + return ToInt64(respmap["tranId"]), nil +} + +/** + * @deprecated + * 期货下单 + * @param currencyPair btc_usd:比特币 ltc_usd :莱特币 + * @param contractType 合约类型: this_week:当周 next_week:下周 month:当月 quarter:季度 + * @param price 价格 + * @param amount 委托数量 + * @param openType 1:开多 2:开空 3:平多 4:平空 + * @param matchPrice 是否为对手价 0:不是 1:是 ,当取值为1时,price无效 + */ +func (bs *BinanceSwap) PlaceFutureOrder(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice, leverRate int) (string, error) { + + pair := bs.adaptCurrencyPair(currencyPair) + path := bs.apiV1 + ORDER_URI + params := url.Values{} + params.Set("symbol", pair.ToSymbol("")) + params.Set("quantity", amount) + + switch openType { + case OPEN_BUY, CLOSE_SELL: + params.Set("side", "BUY") + case OPEN_SELL, CLOSE_BUY: + params.Set("side", "SELL") + } + if matchPrice == 0 { + params.Set("type", "LIMIT") + params.Set("price", price) + params.Set("timeInForce", "GTC") + } else { + params.Set("type", "MARKET") + } + + bs.buildParamsSigned(¶ms) + resp, err := HttpPostForm2(bs.httpClient, path, params, + map[string]string{"X-MBX-APIKEY": bs.accessKey}) + if err != nil { + return "", err + } + + respmap := make(map[string]interface{}) + err = json.Unmarshal(resp, &respmap) + if err != nil { + return "", err + } + + orderId := ToInt(respmap["orderId"]) + if orderId <= 0 { + return "", errors.New(string(resp)) + } + return strconv.Itoa(orderId), nil +} + +/** + * 取消订单 + * @param symbol btc_usd:比特币 ltc_usd :莱特币 + * @param contractType 合约类型: this_week:当周 next_week:下周 month:当月 quarter:季度 + * @param orderId 订单ID + + */ +func (bs *BinanceSwap) FutureCancelOrder(currencyPair CurrencyPair, contractType, orderId string) (bool, error) { + currencyPair = bs.adaptCurrencyPair(currencyPair) + path := bs.apiV1 + ORDER_URI + params := url.Values{} + params.Set("symbol", bs.adaptCurrencyPair(currencyPair).ToSymbol("")) + params.Set("orderId", orderId) + + bs.buildParamsSigned(¶ms) + + resp, err := HttpDeleteForm(bs.httpClient, path, params, map[string]string{"X-MBX-APIKEY": bs.accessKey}) + + if err != nil { + return false, err + } + + respmap := make(map[string]interface{}) + err = json.Unmarshal(resp, &respmap) + if err != nil { + return false, err + } + + orderIdCanceled := ToInt(respmap["orderId"]) + if orderIdCanceled <= 0 { + return false, errors.New(string(resp)) + } + + return true, nil +} + +func (bs *BinanceSwap) FutureCancelAllOrders(currencyPair CurrencyPair, contractType string) (bool, error) { + currencyPair = bs.adaptCurrencyPair(currencyPair) + path := bs.apiV1 + "allOpenOrders" + params := url.Values{} + params.Set("symbol", bs.adaptCurrencyPair(currencyPair).ToSymbol("")) + + bs.buildParamsSigned(¶ms) + + resp, err := HttpDeleteForm(bs.httpClient, path, params, map[string]string{"X-MBX-APIKEY": bs.accessKey}) + + if err != nil { + return false, err + } + + respmap := make(map[string]interface{}) + err = json.Unmarshal(resp, &respmap) + if err != nil { + return false, err + } + + if ToInt(respmap["code"]) != 200 { + return false, errors.New(respmap["msg"].(string)) + } + + return true, nil +} + +func (bs *BinanceSwap) FutureCancelOrders(currencyPair CurrencyPair, contractType string, orderIdList []string) (bool, error) { + currencyPair = bs.adaptCurrencyPair(currencyPair) + path := bs.apiV1 + "batchOrders" + + if len(orderIdList) == 0 { + return false, errors.New("list is empty, no order will be cancel") + } + list, _ := json.Marshal(orderIdList) + params := url.Values{} + + params.Set("symbol", bs.adaptCurrencyPair(currencyPair).ToSymbol("")) + params.Set("orderIdList", string(list)) + + bs.buildParamsSigned(¶ms) + + resp, err := HttpDeleteForm(bs.httpClient, path, params, map[string]string{"X-MBX-APIKEY": bs.accessKey}) + + if err != nil { + return false, err + } + + respmap := make(map[string]interface{}) + err = json.Unmarshal(resp, &respmap) + if err != nil { + return false, err + } + + if ToInt(respmap["code"]) != 200 { + return false, errors.New(respmap["msg"].(string)) + } + + return true, nil +} + +/** + * 用户持仓查询 + * @param symbol btc_usd:比特币 ltc_usd :莱特币 + * @param contractType 合约类型: this_week:当周 next_week:下周 month:当月 quarter:季度 + * @return + */ +func (bs *BinanceSwap) GetFuturePosition(currencyPair CurrencyPair, contractType string) ([]FuturePosition, error) { + currencyPair1 := bs.adaptCurrencyPair(currencyPair) + + params := url.Values{} + bs.buildParamsSigned(¶ms) + path := bs.apiV1 + "positionRisk?" + params.Encode() + + result, err := HttpGet3(bs.httpClient, path, map[string]string{"X-MBX-APIKEY": bs.accessKey}) + + if err != nil { + return nil, err + } + + var positions []FuturePosition + for _, info := range result { + + cont := info.(map[string]interface{}) + if cont["symbol"] != currencyPair1.ToSymbol("") { + continue + } + p := FuturePosition{ + LeverRate: ToInt(cont["leverage"]), + Symbol: currencyPair, + ForceLiquPrice: ToFloat64(cont["liquidationPrice"]), + } + amount := ToFloat64(cont["positionAmt"]) + price := ToFloat64(cont["entryPrice"]) + upnl := ToFloat64(cont["unRealizedProfit"]) + if amount > 0 { + p.BuyAmount = amount + p.BuyPriceAvg = price + p.BuyProfitReal = upnl + } else if amount < 0 { + p.SellAmount = amount + p.SellPriceAvg = price + p.SellProfitReal = upnl + } + positions = append(positions, p) + } + return positions, nil +} + +/** + *获取订单信息 + */ +func (bs *BinanceSwap) GetFutureOrders(orderIds []string, currencyPair CurrencyPair, contractType string) ([]FutureOrder, error) { + if len(orderIds) == 0 { + return nil, errors.New("orderIds is empty") + } + currencyPair1 := bs.adaptCurrencyPair(currencyPair) + + params := url.Values{} + params.Set("symbol", currencyPair1.ToSymbol("")) + bs.buildParamsSigned(¶ms) + + path := bs.apiV1 + "allOrders?" + params.Encode() + + result, err := HttpGet3(bs.httpClient, path, map[string]string{"X-MBX-APIKEY": bs.accessKey}) + + if err != nil { + return nil, err + } + + orders := make([]FutureOrder, 0) + for _, info := range result { + + _ord := info.(map[string]interface{}) + if _ord["symbol"].(string) != currencyPair1.ToSymbol("") { + continue + } + orderId := ToInt(_ord["orderId"]) + ordId := strconv.Itoa(orderId) + + for _, id := range orderIds { + if id == ordId { + order := &FutureOrder{} + order = bs.parseOrder(_ord) + order.Currency = currencyPair + orders = append(orders, *order) + break + } + } + } + return orders, nil + +} + +/** + *获取单个订单信息 + */ +func (bs *BinanceSwap) GetFutureOrder(orderId string, currencyPair CurrencyPair, contractType string) (*FutureOrder, error) { + currencyPair1 := bs.adaptCurrencyPair(currencyPair) + + params := url.Values{} + params.Set("symbol", currencyPair1.ToSymbol("")) + params.Set("orderId", orderId) + bs.buildParamsSigned(¶ms) + + path := bs.apiV1 + "allOrders?" + params.Encode() + + result, err := HttpGet3(bs.httpClient, path, map[string]string{"X-MBX-APIKEY": bs.accessKey}) + + if err != nil { + return nil, err + } + + order := &FutureOrder{} + ordId, _ := strconv.Atoi(orderId) + for _, info := range result { + + _ord := info.(map[string]interface{}) + if _ord["symbol"].(string) != currencyPair1.ToSymbol("") { + continue + } + + if ToInt(_ord["orderId"]) != ordId { + continue + } + + order = bs.parseOrder(_ord) + order.Currency = currencyPair + return order, nil + } + return nil, errors.New(fmt.Sprintf("not found order:%s", orderId)) +} + +func (bs *BinanceSwap) parseOrder(rsp map[string]interface{}) *FutureOrder { + order := &FutureOrder{} + order.Price = ToFloat64(rsp["price"]) + order.Amount = ToFloat64(rsp["origQty"]) + order.DealAmount = ToFloat64(rsp["executedQty"]) + order.AvgPrice = ToFloat64(rsp["avgPrice"]) + order.OrderTime = ToInt64(rsp["time"]) + + status := rsp["status"].(string) + order.Status = bs.parseOrderStatus(status) + order.OrderID = ToInt64(rsp["orderId"]) + order.OrderID2 = strconv.Itoa(int(order.OrderID)) + order.OType = OPEN_BUY + if rsp["side"].(string) == "SELL" { + order.OType = OPEN_SELL + } + + //GTC - Good Till Cancel 成交为止 + //IOC - Immediate or Cancel 无法立即成交(吃单)的部分就撤销 + //FOK - Fill or Kill 无法全部立即成交就撤销 + //GTX - Good Till Crossing 无法成为挂单方就撤销 + ot := rsp["timeInForce"].(string) + switch ot { + case "GTC": + order.OrderType = ORDER_FEATURE_LIMIT + case "IOC": + order.OrderType = ORDER_FEATURE_IOC + case "FOK": + order.OrderType = ORDER_FEATURE_FOK + case "GTX": + order.OrderType = ORDER_FEATURE_IOC + + } + + //LIMIT 限价单 + //MARKET 市价单 + //STOP 止损限价单 + //STOP_MARKET 止损市价单 + //TAKE_RPOFIT 止盈限价单 + //TAKE_RPOFIT_MARKET 止盈市价单 + + return order +} + +func (bs *BinanceSwap) parseOrderStatus(sts string) TradeStatus { + orderStatus := ORDER_UNFINISH + switch sts { + case "PARTIALLY_FILLED", "partially_filled": + orderStatus = ORDER_PART_FINISH + case "FILLED", "filled": + orderStatus = ORDER_FINISH + case "CANCELED", "REJECTED", "EXPIRED": + orderStatus = ORDER_CANCEL + } + return orderStatus +} + +/** + *获取未完成订单信息 + */ +func (bs *BinanceSwap) GetUnfinishFutureOrders(currencyPair CurrencyPair, contractType string) ([]FutureOrder, error) { + currencyPair1 := bs.adaptCurrencyPair(currencyPair) + + params := url.Values{} + params.Set("symbol", currencyPair1.ToSymbol("")) + bs.buildParamsSigned(¶ms) + + path := bs.apiV1 + "openOrders?" + params.Encode() + + result, err := HttpGet3(bs.httpClient, path, map[string]string{"X-MBX-APIKEY": bs.accessKey}) + + if err != nil { + return nil, err + } + + orders := make([]FutureOrder, 0) + for _, info := range result { + + _ord := info.(map[string]interface{}) + if _ord["symbol"].(string) != currencyPair1.ToSymbol("") { + continue + } + order := &FutureOrder{} + order = bs.parseOrder(_ord) + order.Currency = currencyPair + orders = append(orders, *order) + } + return orders, nil +} + +/** + *获取交易费 + */ +func (bs *BinanceSwap) GetFee() (float64, error) { + panic("not supported.") +} + +/** + *获取每张合约价值 + */ +func (bs *BinanceSwap) GetContractValue(currencyPair CurrencyPair) (float64, error) { + panic("not supported.") +} + +/** + *获取交割时间 星期(0,1,2,3,4,5,6),小时,分,秒 + */ +func (bs *BinanceSwap) GetDeliveryTime() (int, int, int, int) { + panic("not supported.") +} + +/** + * 获取K线数据 + */ +func (bs *BinanceSwap) GetKlineRecords(contractType string, currency CurrencyPair, period, size, since int) ([]FutureKline, error) { + currency2 := bs.adaptCurrencyPair(currency) + params := url.Values{} + params.Set("symbol", currency2.ToSymbol("")) + params.Set("interval", _INERNAL_KLINE_PERIOD_CONVERTER[period]) + if since > 0 { + params.Set("startTime", strconv.Itoa(since)) + } + //params.Set("endTime", strconv.Itoa(int(time.Now().UnixNano()/1000000))) + params.Set("limit", strconv.Itoa(size)) + + klineUrl := bs.apiV1 + KLINE_URI + "?" + params.Encode() + klines, err := HttpGet3(bs.httpClient, klineUrl, nil) + if err != nil { + return nil, err + } + var klineRecords []FutureKline + + for _, _record := range klines { + r := Kline{Pair: currency} + record := _record.([]interface{}) + r.Timestamp = int64(record[0].(float64)) / 1000 //to unix timestramp + r.Open = ToFloat64(record[1]) + r.High = ToFloat64(record[2]) + r.Low = ToFloat64(record[3]) + r.Close = ToFloat64(record[4]) + r.Vol = ToFloat64(record[5]) + + klineRecords = append(klineRecords, FutureKline{Kline: &r}) + } + + return klineRecords, nil +} + +func (bs *BinanceSwap) GetServerTime() (int64, error) { + respmap, err := HttpGet(bs.httpClient, bs.apiV1+SERVER_TIME_URL) + if err != nil { + return 0, err + } + + stime := int64(ToInt(respmap["serverTime"])) + + return stime, nil +} + +func (bs *BinanceSwap) adaptCurrencyPair(pair CurrencyPair) CurrencyPair { + return pair.AdaptUsdToUsdt() +} diff --git a/binance/BinanceSwap_test.go b/binance/BinanceSwap_test.go new file mode 100644 index 00000000..ccc65145 --- /dev/null +++ b/binance/BinanceSwap_test.go @@ -0,0 +1,73 @@ +package binance + +import ( + goex "github.com/nntaoli-project/goex" + "net" + "net/http" + "net/url" + "testing" + "time" +) + +var bs = NewBinanceSwap(&goex.APIConfig{ + Endpoint: "https://testnet.binancefuture.com", + HttpClient: &http.Client{ + Transport: &http.Transport{ + Proxy: func(req *http.Request) (*url.URL, error) { + return url.Parse("socks5://127.0.0.1:1080") + return nil, nil + }, + Dial: (&net.Dialer{ + Timeout: 10 * time.Second, + }).Dial, + }, + Timeout: 10 * time.Second, + }, + ApiKey: "", + ApiSecretKey: "", +}) + +func TestBinanceSwap_Ping(t *testing.T) { + bs.Ping() +} + +func TestBinanceSwap_GetFutureDepth(t *testing.T) { + t.Log(bs.GetFutureDepth(goex.BTC_USDT, "", 1)) +} + +func TestBinanceSwap_GetFutureIndex(t *testing.T) { + t.Log(bs.GetFutureIndex(goex.BTC_USDT)) +} + +func TestBinanceSwap_GetKlineRecords(t *testing.T) { + kline, err := bs.GetKlineRecords("", goex.BTC_USDT, goex.KLINE_PERIOD_4H, 1, 0) + t.Log(err, kline[0].Kline) +} + +func TestBinanceSwap_GetTrades(t *testing.T) { + t.Log(bs.GetTrades("", goex.BTC_USDT, 0)) +} + +func TestBinanceSwap_GetFutureUserinfo(t *testing.T) { + t.Log(bs.GetFutureUserinfo()) +} + +func TestBinanceSwap_PlaceFutureOrder(t *testing.T) { + t.Log(bs.PlaceFutureOrder(goex.BTC_USDT, "", "8322", "0.01", goex.OPEN_BUY, 0, 0)) +} + +func TestBinanceSwap_PlaceFutureOrder2(t *testing.T) { + t.Log(bs.PlaceFutureOrder(goex.BTC_USDT, "", "8322", "0.01", goex.OPEN_BUY, 1, 0)) +} + +func TestBinanceSwap_GetFutureOrder(t *testing.T) { + t.Log(bs.GetFutureOrder("1431689723", goex.BTC_USDT, "")) +} + +func TestBinanceSwap_FutureCancelOrder(t *testing.T) { + t.Log(bs.FutureCancelOrder(goex.BTC_USDT, "", "1431554165")) +} + +func TestBinanceSwap_GetFuturePosition(t *testing.T) { + t.Log(bs.GetFuturePosition(goex.BTC_USDT, "")) +} diff --git a/binance/binance_ws.go b/binance/BinanceWs.go similarity index 93% rename from binance/binance_ws.go rename to binance/BinanceWs.go index f7a6a04a..8359a239 100644 --- a/binance/binance_ws.go +++ b/binance/BinanceWs.go @@ -4,7 +4,8 @@ import ( "errors" "fmt" "github.com/json-iterator/go" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" + "strconv" "strings" "time" "unsafe" @@ -20,6 +21,7 @@ type BinanceWs struct { depthCallback func(*Depth) tradeCallback func(*Trade) klineCallback func(*Kline, int) + wsConns []*WsConn } type AggTrade struct { @@ -91,15 +93,23 @@ func (bnWs *BinanceWs) SetCallbacks( } func (bnWs *BinanceWs) subscribe(endpoint string, handle func(msg []byte) error) { - wsBuilder := NewWsBuilder(). + wsConn := NewWsBuilder(). WsUrl(endpoint). AutoReconnect(). - ProtoHandleFunc(handle) - wsBuilder.ProxyUrl(bnWs.proxyUrl) - wsConn := wsBuilder.Build() + ProtoHandleFunc(handle). + ProxyUrl(bnWs.proxyUrl). + ReconnectInterval(time.Millisecond * 5). + Build() + bnWs.wsConns = append(bnWs.wsConns, wsConn) go bnWs.exitHandler(wsConn) } +func (bnWs *BinanceWs) Close() { + for _, con := range bnWs.wsConns { + con.CloseWs() + } +} + func (bnWs *BinanceWs) SubscribeDepth(pair CurrencyPair, size int) error { if bnWs.depthCallback == nil { return errors.New("please set depth callback func") @@ -159,7 +169,6 @@ func (bnWs *BinanceWs) SubscribeTicker(pair CurrencyPair) error { default: return errors.New("unknown message " + msgType) } - return nil } bnWs.subscribe(endpoint, handle) return nil @@ -207,7 +216,6 @@ func (bnWs *BinanceWs) SubscribeTrade(pair CurrencyPair) error { default: return errors.New("unknown message " + msgType) } - return nil } bnWs.subscribe(endpoint, handle) return nil @@ -247,7 +255,6 @@ func (bnWs *BinanceWs) SubscribeKline(pair CurrencyPair, period int) error { default: return errors.New("unknown message " + msgType) } - return nil } bnWs.subscribe(endpoint, handle) return nil @@ -333,7 +340,6 @@ func (bnWs *BinanceWs) SubscribeAggTrade(pair CurrencyPair, tradeCallback func(* default: return errors.New("unknown message " + msgType) } - return nil } bnWs.subscribe(endpoint, handle) return nil @@ -379,18 +385,18 @@ func (bnWs *BinanceWs) SubscribeDiffDepth(pair CurrencyPair, depthCallback func( } func (bnWs *BinanceWs) exitHandler(c *WsConn) { - ticker := time.NewTicker(time.Second) - defer ticker.Stop() + pingTicker := time.NewTicker(10 * time.Minute) + pongTicker := time.NewTicker(time.Second) + defer pingTicker.Stop() + defer pongTicker.Stop() defer c.CloseWs() for { select { - case t := <-ticker.C: - c.SendPingMessage([]byte(t.String())) - //if err != nil { - // fmt.Println("wsWrite err:", err) - // return - //} + case t := <-pingTicker.C: + c.SendPingMessage([]byte(strconv.Itoa(int(t.UnixNano() / int64(time.Millisecond))))) + case t := <-pongTicker.C: + c.SendPongMessage([]byte(strconv.Itoa(int(t.UnixNano() / int64(time.Millisecond))))) } } } diff --git a/binance/binance_ws_test.go b/binance/BinanceWs_test.go similarity index 86% rename from binance/binance_ws_test.go rename to binance/BinanceWs_test.go index 3ba7146b..1950d2af 100644 --- a/binance/binance_ws_test.go +++ b/binance/BinanceWs_test.go @@ -1,7 +1,7 @@ package binance import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "log" "testing" "time" @@ -18,14 +18,16 @@ func init() { func printfTicker(ticker *goex.Ticker) { log.Println("ticker:", ticker) } + func printfDepth(depth *goex.Depth) { log.Println("depth:", depth) } + func printfTrade(trade *goex.Trade) { log.Println("trade:", trade) log.Println("trade:", (*RawTrade)(unsafe.Pointer(trade))) - } + func printfAggTrade(aggTrade *goex.Trade) { log.Println("trade:", (*AggTrade)(unsafe.Pointer(aggTrade))) } @@ -34,33 +36,39 @@ func printfKline(kline *goex.Kline, period int) { } func TestBinanceWs_SubscribeTicker(t *testing.T) { - return bnWs.SubscribeTicker(goex.BTC_USDT) time.Sleep(time.Second * 5) } func TestBinanceWs_GetDepthWithWs(t *testing.T) { - return bnWs.SubscribeDepth(goex.BTC_USDT, 5) time.Sleep(time.Second * 10) } + func TestBinanceWs_GetKLineWithWs(t *testing.T) { return bnWs.SubscribeKline(goex.BTC_USDT, goex.KLINE_PERIOD_1MIN) time.Sleep(time.Second * 10) } + func TestBinanceWs_GetTradesWithWs(t *testing.T) { - return bnWs.SubscribeTrade(goex.BTC_USDT) time.Sleep(time.Second * 5) } + func TestBinanceWs_SubscribeAggTrade(t *testing.T) { - return bnWs.SubscribeAggTrade(goex.BTC_USDT, printfAggTrade) time.Sleep(time.Second * 5) } + func TestBinanceWs_SubscribeDiffDepth(t *testing.T) { bnWs.SubscribeDiffDepth(goex.BTC_USDT, printfDepth) time.Sleep(time.Second * 10) +} +func TestBinanceWs_SubscribeDepth(t *testing.T) { + bnWs.SubscribeDepth(goex.BTC_USDT, 5) + bnWs.SubscribeDepth(goex.LTC_USDT, 5) + bnWs.SubscribeDepth(goex.ETC_USDT, 5) + time.Sleep(time.Second * 60) } diff --git a/binance/Binance_test.go b/binance/Binance_test.go index 14554a7d..8a0bd813 100644 --- a/binance/Binance_test.go +++ b/binance/Binance_test.go @@ -1,7 +1,7 @@ package binance import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net" "net/http" "net/url" @@ -20,21 +20,35 @@ var ba = New(&http.Client{ }).Dial, }, Timeout: 10 * time.Second, -}, "", "") +}, "q6y6Gr7fF3jSJLncpfn2PmAA0xu4XRiRFHpFkyJy3d7K68WUxY0Gt8rrajCDUfbI", + "AP8C2kh4RyISN3fpRCFMZJddf233XbPcYWQ1S7gBan3pGjCQg2JnyQFSJrIaNzRh", +) func TestBinance_GetTicker(t *testing.T) { - return ticker, _ := ba.GetTicker(goex.LTC_BTC) t.Log(ticker) } + +func TestBinance_LimitBuy(t *testing.T) { + order, err := ba.LimitBuy("0.005", "8000", goex.BTC_USDT) + t.Log(order, err) +} + func TestBinance_LimitSell(t *testing.T) { - return - order, err := ba.LimitSell("1", "1", goex.LTC_BTC) + order, err := ba.LimitSell("0.01", "0.1", goex.LTC_BTC) t.Log(order, err) } +func TestBinance_CancelOrder(t *testing.T) { + t.Log(ba.CancelOrder("1156274704", goex.BTC_USDT)) +} + +func TestBinance_GetOneOrder(t *testing.T) { + t.Log(ba.GetOneOrder("1156274704", goex.BTC_USDT)) +} + func TestBinance_GetDepth(t *testing.T) { - return + //return dep, err := ba.GetDepth(5, goex.ETH_BTC) t.Log(err) if err == nil { @@ -44,13 +58,11 @@ func TestBinance_GetDepth(t *testing.T) { } func TestBinance_GetAccount(t *testing.T) { - return account, err := ba.GetAccount() t.Log(account, err) } func TestBinance_GetUnfinishOrders(t *testing.T) { - return orders, err := ba.GetUnfinishOrders(goex.ETH_BTC) t.Log(orders, err) } @@ -64,9 +76,14 @@ func TestBinance_GetKlineRecords(t *testing.T) { } func TestBinance_GetTrades(t *testing.T) { - t.Log(ba.GetTrades(goex.BTC_USDT , 0)) + t.Log(ba.GetTrades(goex.BTC_USDT, 0)) } func TestBinance_GetTradeSymbols(t *testing.T) { - t.Log(ba.GetTradeSymbols(goex.BTC_USDT)) + t.Log(ba.GetTradeSymbol(goex.BTC_USDT)) +} + +func TestBinance_SetTimeOffset(t *testing.T) { + t.Log(ba.setTimeOffset()) + t.Log(ba.timeOffset) } diff --git a/bitfinex/BitfinexLending.go b/bitfinex/BitfinexLending.go index 76684a02..ad13dbd0 100644 --- a/bitfinex/BitfinexLending.go +++ b/bitfinex/BitfinexLending.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "io/ioutil" "strconv" "strings" diff --git a/bitfinex/BitfinexMarginTrading.go b/bitfinex/BitfinexMarginTrading.go index 710b764a..b60c1759 100644 --- a/bitfinex/BitfinexMarginTrading.go +++ b/bitfinex/BitfinexMarginTrading.go @@ -1,6 +1,6 @@ package bitfinex -import . "github.com/nntaoli-project/GoEx" +import . "github.com/nntaoli-project/goex" type MarginLimits struct { Pair string `json:"on_pair"` diff --git a/bitfinex/bitfinex.go b/bitfinex/bitfinex.go index c8edd513..ae967f16 100644 --- a/bitfinex/bitfinex.go +++ b/bitfinex/bitfinex.go @@ -5,7 +5,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/http" "strconv" "strings" diff --git a/bitfinex/bitfinex_test.go b/bitfinex/bitfinex_test.go index 4bc33f62..f79ec0ee 100644 --- a/bitfinex/bitfinex_test.go +++ b/bitfinex/bitfinex_test.go @@ -1,7 +1,7 @@ package bitfinex import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "testing" ) diff --git a/bithumb/bithumb.go b/bithumb/bithumb.go index 09bbfb0d..52b73eba 100644 --- a/bithumb/bithumb.go +++ b/bithumb/bithumb.go @@ -5,7 +5,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "log" "net/http" "net/url" diff --git a/bithumb/bithumb_test.go b/bithumb/bithumb_test.go index c1498f3f..91e43814 100644 --- a/bithumb/bithumb_test.go +++ b/bithumb/bithumb_test.go @@ -1,7 +1,7 @@ package bithumb import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "testing" ) diff --git a/bitmex/bitmex.go b/bitmex/bitmex.go index 911797c2..a94510eb 100644 --- a/bitmex/bitmex.go +++ b/bitmex/bitmex.go @@ -4,12 +4,12 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx/internal/logger" + . "github.com/nntaoli-project/goex/internal/logger" "net/url" "strings" "time" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" ) const ( @@ -46,12 +46,13 @@ func (bm *bitmex) doAuthRequest(m, uri, param string, r interface{}) error { sign := bm.generateSignature(m, uri, param, fmt.Sprint(nonce)) resp, err := NewHttpRequest(bm.HttpClient, m, bm.Endpoint+uri, param, map[string]string{ - "User-Agent": "github.com/nntaoli-project/GoEx/bitmex", + "User-Agent": "github.com/nntaoli-project/goex/bitmex", "Content-Type": "application/json", "Accept": "application/json", "api-expires": fmt.Sprint(nonce), "api-key": bm.ApiKey, "api-signature": sign}) + Log.Debug("response:", string(resp)) if err != nil { return err } else { @@ -124,7 +125,7 @@ func (bm *bitmex) PlaceFutureOrder(currencyPair CurrencyPair, contractType, pric OrderId string `json:"orderID"` } - createOrderParameter.Text = "github.com/nntaoli-project/GoEx/bitmex" + createOrderParameter.Text = "github.com/nntaoli-project/goex/bitmex" createOrderParameter.Symbol = bm.adaptCurrencyPairToSymbol(currencyPair, contractType) createOrderParameter.OrdType = "Limit" createOrderParameter.TimeInForce = "GoodTillCancel" @@ -176,20 +177,25 @@ func (bm *bitmex) FutureCancelOrder(currencyPair CurrencyPair, contractType, ord } func (bm *bitmex) GetFuturePosition(currencyPair CurrencyPair, contractType string) ([]FuturePosition, error) { - var response []struct { - CurrentQty int `json:"currentQty"` - OpeningQty int `json:"openingQty"` - AvgCostPrice float64 `json:"avgCostPrice"` - AvgEntryPrice float64 `json:"avgEntryPrice"` - UnrealisedPnl float64 `json:"unrealisedPnl"` - UnrealisedPnlPcnt float64 `json:"unrealisedPnlPcnt"` - OpenOrderBuyQty float64 `json:"openOrderBuyQty"` - OpenOrderSellQty float64 `json:"OpenOrderSellQty"` - OpeningTimestamp time.Time `json:"openingTimestamp"` - LiquidationPrice float64 `json:"liquidationPrice"` - Leverage int `json:"leverage"` - } - er := bm.doAuthRequest("GET", "/api/v1/position", "", &response) + var ( + response []struct { + Symbol string `json:"symbol"` + CurrentQty int `json:"currentQty"` + OpeningQty int `json:"openingQty"` + AvgCostPrice float64 `json:"avgCostPrice"` + AvgEntryPrice float64 `json:"avgEntryPrice"` + UnrealisedPnl float64 `json:"unrealisedPnl"` + UnrealisedPnlPcnt float64 `json:"unrealisedPnlPcnt"` + OpenOrderBuyQty float64 `json:"openOrderBuyQty"` + OpenOrderSellQty float64 `json:"OpenOrderSellQty"` + OpeningTimestamp time.Time `json:"openingTimestamp"` + LiquidationPrice float64 `json:"liquidationPrice"` + Leverage int `json:"leverage"` + } + param = url.Values{} + ) + param.Set("filter", fmt.Sprintf(`{"symbol":"%s"}`, bm.adaptCurrencyPairToSymbol(currencyPair, contractType))) + er := bm.doAuthRequest("GET", "/api/v1/position?"+param.Encode(), "", &response) if er != nil { return nil, er } @@ -275,7 +281,8 @@ func (bm *bitmex) GetFee() (float64, error) { } func (bm *bitmex) GetFutureDepth(currencyPair CurrencyPair, contractType string, size int) (*Depth, error) { - uri := fmt.Sprintf("/api/v1/orderBook/L2?symbol=%s&depth=%d", bm.adaptCurrencyPairToSymbol(currencyPair, contractType), size) + sym := bm.adaptCurrencyPairToSymbol(currencyPair, contractType) + uri := fmt.Sprintf("/api/v1/orderBook/L2?symbol=%s&depth=%d", sym , size) resp, err := HttpGet3(bm.HttpClient, bm.Endpoint+uri, nil) if err != nil { return nil, HTTP_ERR_CODE.OriginErr(err.Error()) @@ -286,6 +293,7 @@ func (bm *bitmex) GetFutureDepth(currencyPair CurrencyPair, contractType string, dep := new(Depth) dep.UTime = time.Now() dep.Pair = currencyPair + dep.ContractType = sym for _, r := range resp { rr := r.(map[string]interface{}) diff --git a/bitmex/bitmex_test.go b/bitmex/bitmex_test.go index 26504863..4f577438 100644 --- a/bitmex/bitmex_test.go +++ b/bitmex/bitmex_test.go @@ -1,8 +1,8 @@ package bitmex import ( - "github.com/nntaoli-project/GoEx" - "github.com/nntaoli-project/GoEx/internal/logger" + "github.com/nntaoli-project/goex" + "github.com/nntaoli-project/goex/internal/logger" "github.com/stretchr/testify/assert" "net" "net/http" diff --git a/bitstamp/Bitstamp.go b/bitstamp/Bitstamp.go index 8991c4c8..f7fb83bb 100644 --- a/bitstamp/Bitstamp.go +++ b/bitstamp/Bitstamp.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "log" "net/http" "net/url" diff --git a/bitstamp/Bitstamp_test.go b/bitstamp/Bitstamp_test.go index 091c5f74..08bd3116 100644 --- a/bitstamp/Bitstamp_test.go +++ b/bitstamp/Bitstamp_test.go @@ -1,7 +1,7 @@ package bitstamp import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "github.com/stretchr/testify/assert" "log" "net/http" diff --git a/bittrex/bittrex.go b/bittrex/bittrex.go index 334c87bf..525422f6 100644 --- a/bittrex/bittrex.go +++ b/bittrex/bittrex.go @@ -2,7 +2,7 @@ package bittrex import ( "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/http" "sort" "errors" diff --git a/bittrex/bittrex_test.go b/bittrex/bittrex_test.go index 26505b52..9ead6b8d 100644 --- a/bittrex/bittrex_test.go +++ b/bittrex/bittrex_test.go @@ -1,7 +1,7 @@ package bittrex import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "testing" ) diff --git a/builder/APIBuilder.go b/builder/APIBuilder.go index b0e4edf4..bb242619 100644 --- a/builder/APIBuilder.go +++ b/builder/APIBuilder.go @@ -1,32 +1,34 @@ package builder import ( + "context" "fmt" - . "github.com/nntaoli-project/GoEx" - "github.com/nntaoli-project/GoEx/bigone" - "github.com/nntaoli-project/GoEx/binance" - "github.com/nntaoli-project/GoEx/bitfinex" - "github.com/nntaoli-project/GoEx/bithumb" - "github.com/nntaoli-project/GoEx/bitmex" - "github.com/nntaoli-project/GoEx/bitstamp" - "github.com/nntaoli-project/GoEx/bittrex" - "github.com/nntaoli-project/GoEx/coinbene" - "github.com/nntaoli-project/GoEx/fmex" - "github.com/nntaoli-project/GoEx/kucoin" + . "github.com/nntaoli-project/goex" + "github.com/nntaoli-project/goex/bigone" + "github.com/nntaoli-project/goex/binance" + "github.com/nntaoli-project/goex/bitfinex" + "github.com/nntaoli-project/goex/bithumb" + "github.com/nntaoli-project/goex/bitmex" + "github.com/nntaoli-project/goex/bitstamp" + "github.com/nntaoli-project/goex/bittrex" + "github.com/nntaoli-project/goex/coinbene" + "github.com/nntaoli-project/goex/fmex" + "github.com/nntaoli-project/goex/kucoin" - //"github.com/nntaoli-project/GoEx/coin58" - "github.com/nntaoli-project/GoEx/coinex" - "github.com/nntaoli-project/GoEx/fcoin" - "github.com/nntaoli-project/GoEx/gateio" - "github.com/nntaoli-project/GoEx/gdax" - "github.com/nntaoli-project/GoEx/hitbtc" - "github.com/nntaoli-project/GoEx/huobi" - "github.com/nntaoli-project/GoEx/kraken" - "github.com/nntaoli-project/GoEx/okcoin" - "github.com/nntaoli-project/GoEx/okex" - "github.com/nntaoli-project/GoEx/poloniex" - "github.com/nntaoli-project/GoEx/zb" + "github.com/nntaoli-project/goex/atop" + //"github.com/nntaoli-project/goex/coin58" + "github.com/nntaoli-project/goex/coinex" + "github.com/nntaoli-project/goex/fcoin" + "github.com/nntaoli-project/goex/gateio" + "github.com/nntaoli-project/goex/gdax" + "github.com/nntaoli-project/goex/hitbtc" + "github.com/nntaoli-project/goex/huobi" + "github.com/nntaoli-project/goex/kraken" + "github.com/nntaoli-project/goex/okcoin" + "github.com/nntaoli-project/goex/okex" + "github.com/nntaoli-project/goex/poloniex" + "github.com/nntaoli-project/goex/zb" "net" "net/http" "net/url" @@ -255,6 +257,8 @@ func (builder *APIBuilder) Build(exName string) (api API) { _api = bigone.New(builder.client, builder.apiKey, builder.secretkey) case HITBTC: _api = hitbtc.New(builder.client, builder.apiKey, builder.secretkey) + case ATOP: + _api = atop.New(builder.client, builder.apiKey, builder.secretkey) default: println("exchange name error [" + exName + "].") @@ -316,6 +320,10 @@ func (builder *APIBuilder) BuildFuture(exName string) (api FutureRestAPI) { ApiKey: builder.apiKey, ApiSecretKey: builder.secretkey, }) + + + + default: println(fmt.Sprintf("%s not support future", exName)) return nil diff --git a/builder/APIBuilder_test.go b/builder/APIBuilder_test.go index b49923b8..d8463ffe 100644 --- a/builder/APIBuilder_test.go +++ b/builder/APIBuilder_test.go @@ -1,7 +1,7 @@ package builder import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "github.com/stretchr/testify/assert" "testing" ) diff --git a/coinbene/CoinbeneSwap.go b/coinbene/CoinbeneSwap.go index 6c9ddc11..982ffc52 100644 --- a/coinbene/CoinbeneSwap.go +++ b/coinbene/CoinbeneSwap.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/http" "sort" "strings" diff --git a/coinbene/CoinbeneSwap_test.go b/coinbene/CoinbeneSwap_test.go index 637d6dea..3e1099b8 100644 --- a/coinbene/CoinbeneSwap_test.go +++ b/coinbene/CoinbeneSwap_test.go @@ -1,7 +1,7 @@ package coinbene import ( - goex "github.com/nntaoli-project/GoEx" + goex "github.com/nntaoli-project/goex" "net" "net/http" "net/url" diff --git a/coinbig/coinbig.go b/coinbig/coinbig.go index f2296f57..8a3b6256 100644 --- a/coinbig/coinbig.go +++ b/coinbig/coinbig.go @@ -1,7 +1,7 @@ package coinbig import ( - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/http" "net/url" diff --git a/coinbig/coinbig_test.go b/coinbig/coinbig_test.go index 8962b3f7..aa406348 100644 --- a/coinbig/coinbig_test.go +++ b/coinbig/coinbig_test.go @@ -1,7 +1,7 @@ package coinbig import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "testing" ) diff --git a/coinex/coinex.go b/coinex/coinex.go index 4d4ea1ff..9dfdeedb 100644 --- a/coinex/coinex.go +++ b/coinex/coinex.go @@ -12,7 +12,7 @@ import ( "strings" "time" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" ) type CoinEx struct { diff --git a/coinex/coinex_test.go b/coinex/coinex_test.go index cfa42e07..c25e97ee 100644 --- a/coinex/coinex_test.go +++ b/coinex/coinex_test.go @@ -2,7 +2,7 @@ package coinex import ( "fmt" - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "testing" ) diff --git a/coinpark/coinpark.go b/coinpark/coinpark.go index 57eefc2c..173a6a3a 100644 --- a/coinpark/coinpark.go +++ b/coinpark/coinpark.go @@ -4,7 +4,7 @@ import ( "net/http" //"log" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" //"net/url" "encoding/json" "errors" diff --git a/coinpark/coinpark_test.go b/coinpark/coinpark_test.go index d3cbcc76..c33040ac 100644 --- a/coinpark/coinpark_test.go +++ b/coinpark/coinpark_test.go @@ -1,7 +1,7 @@ package coinpark import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "testing" ) diff --git a/cryptopia/Cryptopia.go b/cryptopia/Cryptopia.go index 171b5860..c645d021 100644 --- a/cryptopia/Cryptopia.go +++ b/cryptopia/Cryptopia.go @@ -13,7 +13,7 @@ import ( "strconv" "strings" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/http" "net/http/httputil" diff --git a/cryptopia/Cryptopia_test.go b/cryptopia/Cryptopia_test.go index 0e7776e6..edfe0857 100644 --- a/cryptopia/Cryptopia_test.go +++ b/cryptopia/Cryptopia_test.go @@ -1,7 +1,7 @@ package cryptopia import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "testing" ) diff --git a/exx/exx.go b/exx/exx.go index ea21962b..20ece63e 100644 --- a/exx/exx.go +++ b/exx/exx.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "log" "net/http" "net/url" diff --git a/exx/exx_test.go b/exx/exx_test.go index 6f21d595..f1e314f6 100644 --- a/exx/exx_test.go +++ b/exx/exx_test.go @@ -1,7 +1,7 @@ package exx import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "net/url" "testing" diff --git a/fcoin/fcoin.go b/fcoin/fcoin.go index b52fd733..d30b0254 100644 --- a/fcoin/fcoin.go +++ b/fcoin/fcoin.go @@ -6,8 +6,8 @@ import ( "encoding/base64" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" - . "github.com/nntaoli-project/GoEx/internal/logger" + . "github.com/nntaoli-project/goex" + . "github.com/nntaoli-project/goex/internal/logger" "net/http" "net/url" "strings" diff --git a/fcoin/fcoin_margin.go b/fcoin/fcoin_margin.go index 5b3dd7ef..455c90a2 100644 --- a/fcoin/fcoin_margin.go +++ b/fcoin/fcoin_margin.go @@ -7,7 +7,7 @@ import ( "net/url" "strings" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" ) /** diff --git a/fcoin/fcoin_margin_test.go b/fcoin/fcoin_margin_test.go index 604bb696..4a7ef079 100644 --- a/fcoin/fcoin_margin_test.go +++ b/fcoin/fcoin_margin_test.go @@ -1,7 +1,7 @@ package fcoin import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "testing" ) diff --git a/fcoin/fcoin_swap.go b/fcoin/fcoin_swap.go index 700551cf..031018d7 100644 --- a/fcoin/fcoin_swap.go +++ b/fcoin/fcoin_swap.go @@ -3,7 +3,7 @@ package fcoin import ( "fmt" //"github.com/google/uuid" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "github.com/pkg/errors" //"strings "net/url" diff --git a/fcoin/fcoin_test.go b/fcoin/fcoin_test.go index 26b02479..82903240 100644 --- a/fcoin/fcoin_test.go +++ b/fcoin/fcoin_test.go @@ -1,7 +1,7 @@ package fcoin import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net" "net/http" "net/url" diff --git a/fcoin/fcoin_ws.go b/fcoin/fcoin_ws.go index 4df158d2..840e3a6f 100644 --- a/fcoin/fcoin_ws.go +++ b/fcoin/fcoin_ws.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" "github.com/json-iterator/go" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "math/rand" "net/http" "strings" diff --git a/fcoin/fcoin_ws_test.go b/fcoin/fcoin_ws_test.go index ebbf7e96..ee8cbfa4 100644 --- a/fcoin/fcoin_ws_test.go +++ b/fcoin/fcoin_ws_test.go @@ -1,7 +1,7 @@ package fcoin import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "log" "net" "net/http" diff --git a/fmex/fmex_swap.go b/fmex/fmex_swap.go index 2db5b94e..a293e165 100644 --- a/fmex/fmex_swap.go +++ b/fmex/fmex_swap.go @@ -6,7 +6,7 @@ import ( "encoding/base64" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/http" "net/url" "strings" @@ -315,7 +315,7 @@ func (fm *FMexSwap) MarginTransferOut(currency Currency, amount float64) (bool, func (fm *FMexSwap) PlaceFutureOrder(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice, leverRate int) (string, error) { params := url.Values{} - params.Set("source", "GoEx") + params.Set("source", "goex") params.Set("symbol", adaptContractType(currencyPair)) switch openType { @@ -386,7 +386,7 @@ func (fm *FMexSwap) PlaceFutureOrder2(ord *OrderParam) (string, error) { params := url.Values{} - params.Set("source", "GoEx") + params.Set("source", "goex") params.Set("symbol", adaptContractType(ord.Currency)) switch ord.Direction { diff --git a/fmex/fmex_swap_test.go b/fmex/fmex_swap_test.go index 802c6ba6..d8b026fe 100644 --- a/fmex/fmex_swap_test.go +++ b/fmex/fmex_swap_test.go @@ -1,7 +1,7 @@ package fmex import ( - goex "github.com/nntaoli-project/GoEx" + goex "github.com/nntaoli-project/goex" "net" "net/http" "net/url" diff --git a/fmex/fmex_ws.go b/fmex/fmex_ws.go index 3a1fd43d..84d7d470 100644 --- a/fmex/fmex_ws.go +++ b/fmex/fmex_ws.go @@ -11,7 +11,7 @@ import ( "unsafe" jsoniter "github.com/json-iterator/go" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" ) const ( diff --git a/fmex/fmex_ws_test.go b/fmex/fmex_ws_test.go index c687db52..e6e94695 100644 --- a/fmex/fmex_ws_test.go +++ b/fmex/fmex_ws_test.go @@ -1,7 +1,7 @@ package fmex import ( - goex "github.com/nntaoli-project/GoEx" + goex "github.com/nntaoli-project/goex" "log" "net" "net/http" diff --git a/gateio/gateio.go b/gateio/gateio.go index 43c9e99c..a5aed745 100644 --- a/gateio/gateio.go +++ b/gateio/gateio.go @@ -2,7 +2,7 @@ package gateio import ( "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/http" "sort" "strings" diff --git a/gateio/gateio_test.go b/gateio/gateio_test.go index 0389b434..bb5dc689 100644 --- a/gateio/gateio_test.go +++ b/gateio/gateio_test.go @@ -1,7 +1,7 @@ package gateio import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "testing" ) diff --git a/gdax/gdax.go b/gdax/gdax.go index 8f10a0f1..5c5e4e8d 100644 --- a/gdax/gdax.go +++ b/gdax/gdax.go @@ -2,7 +2,7 @@ package gdax import ( "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/http" "sort" ) diff --git a/gdax/gdax_test.go b/gdax/gdax_test.go index 37ef7f44..c107dbfd 100644 --- a/gdax/gdax_test.go +++ b/gdax/gdax_test.go @@ -1,7 +1,7 @@ package gdax import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "testing" ) diff --git a/go.mod b/go.mod index 723df842..c3646771 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/nntaoli-project/GoEx +module github.com/nntaoli-project/goex go 1.12 diff --git a/hitbtc/Hitbtc.go b/hitbtc/Hitbtc.go index 60a7b80a..36cb9ef1 100644 --- a/hitbtc/Hitbtc.go +++ b/hitbtc/Hitbtc.go @@ -13,7 +13,7 @@ import ( "strings" "time" - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" ) const ( diff --git a/hitbtc/Hitbtc_test.go b/hitbtc/Hitbtc_test.go index 21ca2e07..9cfe5042 100644 --- a/hitbtc/Hitbtc_test.go +++ b/hitbtc/Hitbtc_test.go @@ -1,7 +1,7 @@ package hitbtc import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "github.com/stretchr/testify/require" "net/http" "testing" diff --git a/huobi/Hbdm.go b/huobi/Hbdm.go index 6518fcac..b0f7fe8f 100644 --- a/huobi/Hbdm.go +++ b/huobi/Hbdm.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/url" "sort" "strings" diff --git a/huobi/Hbdm_Ws.go b/huobi/Hbdm_Ws.go index c5e0c581..cee722fa 100644 --- a/huobi/Hbdm_Ws.go +++ b/huobi/Hbdm_Ws.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "log" "sort" "strings" diff --git a/huobi/Hbdm_Ws_test.go b/huobi/Hbdm_Ws_test.go index a9f3df54..e2f42b52 100644 --- a/huobi/Hbdm_Ws_test.go +++ b/huobi/Hbdm_Ws_test.go @@ -1,7 +1,7 @@ package huobi import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "log" "testing" "time" diff --git a/huobi/Hbdm_test.go b/huobi/Hbdm_test.go index 7337a590..3dfe9f56 100644 --- a/huobi/Hbdm_test.go +++ b/huobi/Hbdm_test.go @@ -1,7 +1,7 @@ package huobi import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "testing" "time" ) diff --git a/huobi/HuobiPro.go b/huobi/HuobiPro.go index 3ee563dc..84d53088 100644 --- a/huobi/HuobiPro.go +++ b/huobi/HuobiPro.go @@ -4,8 +4,8 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" - . "github.com/nntaoli-project/GoEx/internal/logger" + . "github.com/nntaoli-project/goex" + . "github.com/nntaoli-project/goex/internal/logger" "math/big" "net/http" "net/url" diff --git a/huobi/HuobiPro_test.go b/huobi/HuobiPro_test.go index a1c23f7c..0f7662e4 100644 --- a/huobi/HuobiPro_test.go +++ b/huobi/HuobiPro_test.go @@ -1,8 +1,8 @@ package huobi import ( - "github.com/nntaoli-project/GoEx" - "github.com/nntaoli-project/GoEx/internal/logger" + "github.com/nntaoli-project/goex" + "github.com/nntaoli-project/goex/internal/logger" "github.com/stretchr/testify/assert" "net" "net/http" diff --git a/kraken/Kraken.go b/kraken/Kraken.go index dc383068..9acea9c9 100644 --- a/kraken/Kraken.go +++ b/kraken/Kraken.go @@ -8,7 +8,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/http" "net/url" "sort" diff --git a/kraken/Kraken_test.go b/kraken/Kraken_test.go index f4416be9..4b97d242 100644 --- a/kraken/Kraken_test.go +++ b/kraken/Kraken_test.go @@ -1,7 +1,7 @@ package kraken import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "github.com/stretchr/testify/assert" "net/http" "testing" diff --git a/kucoin/kucoin.go b/kucoin/kucoin.go index eb700d85..87369ff3 100644 --- a/kucoin/kucoin.go +++ b/kucoin/kucoin.go @@ -2,7 +2,7 @@ package kucoin import ( "github.com/Kucoin/kucoin-go-sdk" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" log "github.com/sirupsen/logrus" "time" ) diff --git a/kucoin/kucoin_test.go b/kucoin/kucoin_test.go index c97b94ce..2917df80 100644 --- a/kucoin/kucoin_test.go +++ b/kucoin/kucoin_test.go @@ -1,7 +1,7 @@ package kucoin import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "testing" "time" ) diff --git a/ocx/ocx.go b/ocx/ocx.go index 5b85ae80..e07eb76d 100644 --- a/ocx/ocx.go +++ b/ocx/ocx.go @@ -6,7 +6,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "log" "net/http" "net/url" diff --git a/ocx/ocx_test.go b/ocx/ocx_test.go index 10716c98..0f333a5c 100644 --- a/ocx/ocx_test.go +++ b/ocx/ocx_test.go @@ -1,7 +1,7 @@ package ocx import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "net/url" "testing" diff --git a/okcoin/OKCoin_CN.go b/okcoin/OKCoin_CN.go index 138548b7..83b7e2cf 100644 --- a/okcoin/OKCoin_CN.go +++ b/okcoin/OKCoin_CN.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/http" "net/url" "strconv" diff --git a/okcoin/OKCoin_CN_test.go b/okcoin/OKCoin_CN_test.go index 05da1f99..369996bd 100644 --- a/okcoin/OKCoin_CN_test.go +++ b/okcoin/OKCoin_CN_test.go @@ -1,7 +1,7 @@ package okcoin import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "testing" ) diff --git a/okcoin/OKCoin_COM.go b/okcoin/OKCoin_COM.go index c97055fe..0a38d5b8 100644 --- a/okcoin/OKCoin_COM.go +++ b/okcoin/OKCoin_COM.go @@ -3,7 +3,7 @@ package okcoin import ( "encoding/json" "errors" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/http" "net/url" "strconv" diff --git a/okcoin/OKEx.go b/okcoin/OKEx.go index 3e1272b2..1533d3a6 100644 --- a/okcoin/OKEx.go +++ b/okcoin/OKEx.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "io/ioutil" "log" "net/http" diff --git a/okcoin/OKExSpot.go b/okcoin/OKExSpot.go index 304e1b75..0b2473ac 100644 --- a/okcoin/OKExSpot.go +++ b/okcoin/OKExSpot.go @@ -3,7 +3,7 @@ package okcoin import ( "encoding/json" "errors" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "net/http" "net/url" "strconv" diff --git a/okcoin/OKExSpot_test.go b/okcoin/OKExSpot_test.go index a5e389a3..b1dbc092 100644 --- a/okcoin/OKExSpot_test.go +++ b/okcoin/OKExSpot_test.go @@ -1,7 +1,7 @@ package okcoin import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "github.com/stretchr/testify/assert" "net/http" "testing" diff --git a/okcoin/OKEx_Future_Ws.go b/okcoin/OKEx_Future_Ws.go index 9ddd7d3f..4a86d5a2 100644 --- a/okcoin/OKEx_Future_Ws.go +++ b/okcoin/OKEx_Future_Ws.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "log" "strings" "sync" diff --git a/okcoin/OKEx_Future_Ws_test.go b/okcoin/OKEx_Future_Ws_test.go index 53e26774..1482f20e 100644 --- a/okcoin/OKEx_Future_Ws_test.go +++ b/okcoin/OKEx_Future_Ws_test.go @@ -1,7 +1,7 @@ package okcoin import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "testing" "time" ) diff --git a/okcoin/OKEx_Spot_Ws.go b/okcoin/OKEx_Spot_Ws.go index 7542b5c9..b3eb03e6 100644 --- a/okcoin/OKEx_Spot_Ws.go +++ b/okcoin/OKEx_Spot_Ws.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "log" "strings" "sync" diff --git a/okcoin/OKEx_Spot_Ws_test.go b/okcoin/OKEx_Spot_Ws_test.go index 84620bd3..bc7bfce4 100644 --- a/okcoin/OKEx_Spot_Ws_test.go +++ b/okcoin/OKEx_Spot_Ws_test.go @@ -1,7 +1,7 @@ package okcoin import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "testing" "time" ) diff --git a/okcoin/OKEx_V3.go b/okcoin/OKEx_V3.go index 6d56bda5..e6219cea 100644 --- a/okcoin/OKEx_V3.go +++ b/okcoin/OKEx_V3.go @@ -16,7 +16,7 @@ import ( "time" "github.com/deckarep/golang-set" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" ) const ( diff --git a/okcoin/OKEx_V3_Future_Ws.go b/okcoin/OKEx_V3_Future_Ws.go index cf6a1334..8df99d89 100644 --- a/okcoin/OKEx_V3_Future_Ws.go +++ b/okcoin/OKEx_V3_Future_Ws.go @@ -10,7 +10,7 @@ import ( "sync" "time" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" ) type OKExV3FutureWs struct { diff --git a/okcoin/OKEx_V3_Future_Ws_test.go b/okcoin/OKEx_V3_Future_Ws_test.go index 71ac2730..cb788914 100644 --- a/okcoin/OKEx_V3_Future_Ws_test.go +++ b/okcoin/OKEx_V3_Future_Ws_test.go @@ -6,7 +6,7 @@ import ( "log" "testing" "sync" - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" ) diff --git a/okcoin/OKEx_V3_test.go b/okcoin/OKEx_V3_test.go index bab0e90c..638f0d40 100644 --- a/okcoin/OKEx_V3_test.go +++ b/okcoin/OKEx_V3_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "github.com/stretchr/testify/assert" ) diff --git a/okcoin/OKEx_V3_utils.go b/okcoin/OKEx_V3_utils.go index 20fead43..07c3f5dc 100644 --- a/okcoin/OKEx_V3_utils.go +++ b/okcoin/OKEx_V3_utils.go @@ -5,7 +5,7 @@ import ( "strconv" "time" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" ) type IContractIDProvider interface { diff --git a/okcoin/OKEx_test.go b/okcoin/OKEx_test.go index f8195c9e..634aad83 100644 --- a/okcoin/OKEx_test.go +++ b/okcoin/OKEx_test.go @@ -1,7 +1,7 @@ package okcoin import ( - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "github.com/stretchr/testify/assert" "net/http" "testing" diff --git a/okcoin/OKcoin_COM_test.go b/okcoin/OKcoin_COM_test.go index 4c3e893b..c11896f5 100644 --- a/okcoin/OKcoin_COM_test.go +++ b/okcoin/OKcoin_COM_test.go @@ -1,7 +1,7 @@ package okcoin import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "testing" ) diff --git a/okex/OKEx.go b/okex/OKEx.go index 6847d0b0..4bd6a30a 100644 --- a/okex/OKEx.go +++ b/okex/OKEx.go @@ -6,8 +6,8 @@ import ( "errors" "fmt" "github.com/google/uuid" - . "github.com/nntaoli-project/GoEx" - "github.com/nntaoli-project/GoEx/internal/logger" + . "github.com/nntaoli-project/goex" + "github.com/nntaoli-project/goex/internal/logger" "strings" "sync" "time" diff --git a/okex/OKExFuture.go b/okex/OKExFuture.go index 7d47cae8..3eca12db 100644 --- a/okex/OKExFuture.go +++ b/okex/OKExFuture.go @@ -4,8 +4,8 @@ import ( "errors" "fmt" "github.com/google/uuid" - . "github.com/nntaoli-project/GoEx" - "github.com/nntaoli-project/GoEx/internal/logger" + . "github.com/nntaoli-project/goex" + "github.com/nntaoli-project/goex/internal/logger" "sort" "strings" "sync" @@ -270,7 +270,7 @@ func (ok *OKExFuture) GetAccounts(currencyPair ...CurrencyPair) (*FutureAccount, } } else { //todo 逐仓模式 - return nil, errors.New("GoEx unsupported fixed margin mode") + return nil, errors.New("goex unsupported fixed margin mode") } return acc, nil diff --git a/okex/OKExMargin.go b/okex/OKExMargin.go index 37a80777..a76fe394 100644 --- a/okex/OKExMargin.go +++ b/okex/OKExMargin.go @@ -2,7 +2,7 @@ package okex import ( "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "github.com/pkg/errors" "strings" ) diff --git a/okex/OKExSpot.go b/okex/OKExSpot.go index 9db9e708..354694aa 100644 --- a/okex/OKExSpot.go +++ b/okex/OKExSpot.go @@ -3,7 +3,7 @@ package okex import ( "fmt" "github.com/go-openapi/errors" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "sort" "strings" "time" diff --git a/okex/OKExSwap.go b/okex/OKExSwap.go index 70283187..d7ee6af9 100644 --- a/okex/OKExSwap.go +++ b/okex/OKExSwap.go @@ -3,7 +3,7 @@ package okex import ( "fmt" "github.com/google/uuid" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "github.com/pkg/errors" "strings" "time" @@ -504,5 +504,5 @@ func (ok *OKExSwap) AdaptTradeStatus(status int) TradeStatus { } func (ok *OKExSwap) adaptContractType(currencyPair CurrencyPair) string { - return fmt.Sprintf("%s-SWAP", currencyPair.ToSymbol("-")) + return fmt.Sprintf("%s-SWAP", currencyPair.AdaptUsdtToUsd().ToSymbol("-")) } diff --git a/okex/OKExSwap_test.go b/okex/OKExSwap_test.go index c45a66ac..0444d505 100644 --- a/okex/OKExSwap_test.go +++ b/okex/OKExSwap_test.go @@ -1,7 +1,7 @@ package okex import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "net/url" "testing" diff --git a/okex/OKExWallet.go b/okex/OKExWallet.go index 367cc787..362762fb 100644 --- a/okex/OKExWallet.go +++ b/okex/OKExWallet.go @@ -2,7 +2,7 @@ package okex import ( "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "github.com/pkg/errors" "time" ) diff --git a/okex/OKEx_test.go b/okex/OKEx_test.go index 102c372d..aa477773 100644 --- a/okex/OKEx_test.go +++ b/okex/OKEx_test.go @@ -1,8 +1,8 @@ package okex import ( - "github.com/nntaoli-project/GoEx" - "github.com/nntaoli-project/GoEx/internal/logger" + "github.com/nntaoli-project/goex" + "github.com/nntaoli-project/goex/internal/logger" "github.com/stretchr/testify/assert" "net/http" "testing" diff --git a/poloniex/Poloniex.go b/poloniex/Poloniex.go index f324244a..441d3755 100644 --- a/poloniex/Poloniex.go +++ b/poloniex/Poloniex.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "log" "net/http" "net/url" diff --git a/poloniex/PoloniexMarginTrading.go b/poloniex/PoloniexMarginTrading.go index a7039dbf..b35f59aa 100644 --- a/poloniex/PoloniexMarginTrading.go +++ b/poloniex/PoloniexMarginTrading.go @@ -3,7 +3,7 @@ package poloniex import ( "encoding/json" "errors" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "log" "net/url" ) diff --git a/websocket.go b/websocket.go index 8f97afe8..444614c8 100644 --- a/websocket.go +++ b/websocket.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" "github.com/gorilla/websocket" - . "github.com/nntaoli-project/GoEx/internal/logger" + . "github.com/nntaoli-project/goex/internal/logger" "net/http" "net/http/httputil" "net/url" @@ -25,6 +25,7 @@ type WsConfig struct { ErrorHandleFunc func(err error) IsDump bool readDeadLineTime time.Duration + reconnectInterval time.Duration } type WsConn struct { @@ -33,6 +34,7 @@ type WsConn struct { WsConfig writeBufferChan chan []byte pingMessageBufferChan chan []byte + pongMessageBufferChan chan []byte closeMessageBufferChan chan []byte subs []interface{} close chan bool @@ -44,7 +46,9 @@ type WsBuilder struct { func NewWsBuilder() *WsBuilder { return &WsBuilder{&WsConfig{ - ReqHeaders: make(map[string][]string, 1)}} + ReqHeaders: make(map[string][]string, 1), + reconnectInterval: time.Second * 10, + }} } func (b *WsBuilder) WsUrl(wsUrl string) *WsBuilder { @@ -78,6 +82,11 @@ func (b *WsBuilder) Heartbeat(heartbeat func() []byte, t time.Duration) *WsBuild return b } +func (b *WsBuilder) ReconnectInterval(t time.Duration) *WsBuilder { + b.wsConfig.reconnectInterval = t + return b +} + func (b *WsBuilder) ProtoHandleFunc(f func([]byte) error) *WsBuilder { b.wsConfig.ProtoHandleFunc = f return b @@ -114,6 +123,7 @@ func (ws *WsConn) NewWs() *WsConn { ws.close = make(chan bool, 1) ws.pingMessageBufferChan = make(chan []byte, 10) + ws.pongMessageBufferChan = make(chan []byte, 10) ws.closeMessageBufferChan = make(chan []byte, 10) ws.writeBufferChan = make(chan []byte, 10) @@ -156,6 +166,7 @@ func (ws *WsConn) connect() error { dumpData, _ := httputil.DumpResponse(resp, true) Log.Debugf("[ws][%s] %s", ws.WsUrl, string(dumpData)) } + Log.Infof("[ws][%s] connected", ws.WsUrl) return nil } @@ -164,13 +175,13 @@ func (ws *WsConn) reconnect() { ws.c.Close() //主动关闭一次 var err error for retry := 1; retry <= 100; retry++ { - time.Sleep(time.Duration(retry*10) * time.Second) err = ws.connect() if err != nil { Log.Errorf("[ws] [%s] websocket reconnect fail , %s", ws.WsUrl, err.Error()) } else { break } + time.Sleep(ws.WsConfig.reconnectInterval * time.Duration(retry)) } if err != nil { @@ -211,6 +222,8 @@ func (ws *WsConn) writeRequest() { err = ws.c.WriteMessage(websocket.TextMessage, d) case d := <-ws.pingMessageBufferChan: err = ws.c.WriteMessage(websocket.PingMessage, d) + case d := <-ws.pongMessageBufferChan: + err = ws.c.WriteMessage(websocket.PongMessage, d) case d := <-ws.closeMessageBufferChan: err = ws.c.WriteMessage(websocket.CloseMessage, d) case <-heartTimer.C: @@ -247,6 +260,10 @@ func (ws *WsConn) SendPingMessage(msg []byte) { ws.pingMessageBufferChan <- msg } +func (ws *WsConn) SendPongMessage(msg []byte) { + ws.pongMessageBufferChan <- msg +} + func (ws *WsConn) SendCloseMessage(msg []byte) { ws.closeMessageBufferChan <- msg } @@ -269,61 +286,64 @@ func (ws *WsConn) receiveMessage() { }) ws.c.SetPongHandler(func(pong string) error { + Log.Debugf("[%s] received [pong] %s", ws.WsUrl, pong) ws.c.SetReadDeadline(time.Now().Add(ws.readDeadLineTime)) return nil }) ws.c.SetPingHandler(func(ping string) error { + Log.Debugf("[%s] received [ping] %s", ws.WsUrl, ping) ws.c.SetReadDeadline(time.Now().Add(ws.readDeadLineTime)) return nil }) for { - if len(ws.close) > 0 { + select { + case <-ws.close: Log.Infof("[ws][%s] close websocket , exiting receive message goroutine.", ws.WsUrl) return - } - - t, msg, err := ws.c.ReadMessage() + default: + t, msg, err := ws.c.ReadMessage() + + if err != nil { + Log.Errorf("[ws][%s] %s", ws.WsUrl, err.Error()) + if ws.IsAutoReconnect { + // if _, ok := err.(*websocket.CloseError); ok { + Log.Infof("[ws][%s] Unexpected Closed , Begin Retry Connect.", ws.WsUrl) + ws.reconnect() + // } + continue + } - if err != nil { - Log.Errorf("[ws][%s] %s", ws.WsUrl, err.Error()) - if ws.IsAutoReconnect { - // if _, ok := err.(*websocket.CloseError); ok { - Log.Infof("[ws][%s] Unexpected Closed , Begin Retry Connect.", ws.WsUrl) - ws.reconnect() - // } - continue - } + if ws.ErrorHandleFunc != nil { + ws.ErrorHandleFunc(err) + } - if ws.ErrorHandleFunc != nil { - ws.ErrorHandleFunc(err) + return } - return - } - - ws.c.SetReadDeadline(time.Now().Add(ws.readDeadLineTime)) + ws.c.SetReadDeadline(time.Now().Add(ws.readDeadLineTime)) - switch t { - case websocket.TextMessage: - ws.ProtoHandleFunc(msg) - case websocket.BinaryMessage: - if ws.UnCompressFunc == nil { + switch t { + case websocket.TextMessage: ws.ProtoHandleFunc(msg) - } else { - msg2, err := ws.UnCompressFunc(msg) - if err != nil { - Log.Errorf("[ws][%s] uncompress error %s", ws.WsUrl, err.Error()) + case websocket.BinaryMessage: + if ws.UnCompressFunc == nil { + ws.ProtoHandleFunc(msg) } else { - ws.ProtoHandleFunc(msg2) + msg2, err := ws.UnCompressFunc(msg) + if err != nil { + Log.Errorf("[ws][%s] uncompress error %s", ws.WsUrl, err.Error()) + } else { + ws.ProtoHandleFunc(msg2) + } } + case websocket.CloseMessage: + ws.CloseWs() + return + default: + Log.Errorf("[ws][%s] error websocket message type , content is :\n %s \n", ws.WsUrl, string(msg)) } - case websocket.CloseMessage: - ws.CloseWs() - return - default: - Log.Errorf("[ws][%s] error websocket message type , content is :\n %s \n", ws.WsUrl, string(msg)) } } } diff --git a/websocket_test.go b/websocket_test.go index 030468b2..34750e9f 100644 --- a/websocket_test.go +++ b/websocket_test.go @@ -2,7 +2,7 @@ package goex import ( "encoding/json" - . "github.com/nntaoli-project/GoEx/internal/logger" + . "github.com/nntaoli-project/goex/internal/logger" "testing" "time" ) diff --git a/zb/Zb.go b/zb/Zb.go index a227ef86..cd54f043 100644 --- a/zb/Zb.go +++ b/zb/Zb.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - . "github.com/nntaoli-project/GoEx" + . "github.com/nntaoli-project/goex" "log" "net/http" "net/url" diff --git a/zb/Zb_test.go b/zb/Zb_test.go index 2d9be391..e7d8e170 100644 --- a/zb/Zb_test.go +++ b/zb/Zb_test.go @@ -1,7 +1,7 @@ package zb import ( - "github.com/nntaoli-project/GoEx" + "github.com/nntaoli-project/goex" "net/http" "testing" )