mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
Add REST and websocket support for BTSE (#250)
* Add REST and websocket support for BTSE exchange TO-DO: Finish wrappers and expand test coverage * Fill out wrapper funcs and expand test coverage
This commit is contained in:
@@ -29,6 +29,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
||||
| Bittrex | Yes | No | NA |
|
||||
| BTCC | Yes | Yes | No |
|
||||
| BTCMarkets | Yes | No | NA |
|
||||
| BTSE | Yes | Yes | NA |
|
||||
| COINUT | Yes | Yes | NA |
|
||||
| Exmo | Yes | NA | NA |
|
||||
| CoinbasePro | Yes | Yes | No|
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
const (
|
||||
// Default number of enabled exchanges. Modify this whenever an exchange is
|
||||
// added or removed
|
||||
defaultEnabledExchanges = 27
|
||||
defaultEnabledExchanges = 28
|
||||
)
|
||||
|
||||
func TestGetCurrencyConfig(t *testing.T) {
|
||||
|
||||
@@ -509,6 +509,47 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BTSE",
|
||||
"enabled": true,
|
||||
"verbose": false,
|
||||
"websocket": true,
|
||||
"useSandbox": false,
|
||||
"restPollingDelay": 10,
|
||||
"httpTimeout": 15000000000,
|
||||
"httpUserAgent": "",
|
||||
"authenticatedApiSupport": false,
|
||||
"apiKey": "Key",
|
||||
"apiSecret": "Secret",
|
||||
"apiUrl": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
|
||||
"apiUrlSecondary": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
|
||||
"proxyAddress": "",
|
||||
"websocketUrl": "NON_DEFAULT_HTTP_LINK_TO_WEBSOCKET_EXCHANGE_API",
|
||||
"availablePairs": "BTC-USD",
|
||||
"enabledPairs": "BTC-USD",
|
||||
"baseCurrencies": "USD",
|
||||
"assetTypes": "SPOT",
|
||||
"supportsAutoPairUpdates": true,
|
||||
"configCurrencyPairFormat": {
|
||||
"uppercase": true,
|
||||
"delimiter": "-"
|
||||
},
|
||||
"requestCurrencyPairFormat": {
|
||||
"uppercase": true,
|
||||
"delimiter": "-"
|
||||
},
|
||||
"bankAccounts": [
|
||||
{
|
||||
"bankName": "",
|
||||
"bankAddress": "",
|
||||
"accountName": "",
|
||||
"accountNumber": "",
|
||||
"swiftCode": "",
|
||||
"iban": "",
|
||||
"supportedCurrencies": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BTC Markets",
|
||||
"enabled": true,
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/bittrex"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/btcc"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/btcmarkets"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/btse"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/coinbasepro"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/coinut"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/exmo"
|
||||
@@ -154,6 +155,8 @@ func LoadExchange(name string, useWG bool, wg *sync.WaitGroup) error {
|
||||
exch = new(btcc.BTCC)
|
||||
case "btc markets":
|
||||
exch = new(btcmarkets.BTCMarkets)
|
||||
case "btse":
|
||||
exch = new(btse.BTSE)
|
||||
case "coinut":
|
||||
exch = new(coinut.COINUT)
|
||||
case "exmo":
|
||||
|
||||
@@ -155,7 +155,7 @@ func (a *Alphapoint) CancelAllOrders(orderCancellation exchange.OrderCancellatio
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (a *Alphapoint) GetOrderInfo(orderID int64) (float64, error) {
|
||||
func (a *Alphapoint) GetOrderInfo(orderID string) (float64, error) {
|
||||
orders, err := a.GetOrders()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -163,7 +163,7 @@ func (a *Alphapoint) GetOrderInfo(orderID int64) (float64, error) {
|
||||
|
||||
for x := range orders {
|
||||
for y := range orders[x].OpenOrders {
|
||||
if int64(orders[x].OpenOrders[y].ServerOrderID) == orderID {
|
||||
if strconv.Itoa(orders[x].OpenOrders[y].ServerOrderID) == orderID {
|
||||
return orders[x].OpenOrders[y].QtyRemaining, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@ func (a *ANX) CancelAllOrders(_ exchange.OrderCancellation) (exchange.CancelAllO
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (a *ANX) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (a *ANX) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ func (b *Binance) CancelAllOrders(_ exchange.OrderCancellation) (exchange.Cancel
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (b *Binance) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (b *Binance) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ func (b *Bitfinex) CancelAllOrders(_ exchange.OrderCancellation) (exchange.Cance
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (b *Bitfinex) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (b *Bitfinex) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ func (b *Bitflyer) CancelAllOrders(_ exchange.OrderCancellation) (exchange.Cance
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (b *Bitflyer) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (b *Bitflyer) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -244,7 +244,7 @@ func (b *Bithumb) CancelAllOrders(orderCancellation exchange.OrderCancellation)
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (b *Bithumb) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (b *Bithumb) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ func (b *Bitmex) CancelAllOrders(_ exchange.OrderCancellation) (exchange.CancelA
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (b *Bitmex) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (b *Bitmex) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ func (b *Bitstamp) CancelAllOrders(_ exchange.OrderCancellation) (exchange.Cance
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (b *Bitstamp) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (b *Bitstamp) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ func (b *Bittrex) CancelAllOrders(_ exchange.OrderCancellation) (exchange.Cancel
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (b *Bittrex) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (b *Bittrex) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ func (b *BTCC) CancelAllOrders(orderCancellation exchange.OrderCancellation) (ex
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (b *BTCC) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (b *BTCC) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
return exchange.OrderDetail{}, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ func TestCancelOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetOrderInfo(t *testing.T) {
|
||||
_, err := b.GetOrderInfo(1337)
|
||||
_, err := b.GetOrderInfo("1337")
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetOrderInfo() error", err)
|
||||
}
|
||||
|
||||
@@ -230,10 +230,15 @@ func (b *BTCMarkets) CancelAllOrders(_ exchange.OrderCancellation) (exchange.Can
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (b *BTCMarkets) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (b *BTCMarkets) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var OrderDetail exchange.OrderDetail
|
||||
|
||||
orders, err := b.GetOrderDetail([]int64{orderID})
|
||||
o, err := strconv.ParseInt(orderID, 10, 64)
|
||||
if err != nil {
|
||||
return OrderDetail, err
|
||||
}
|
||||
|
||||
orders, err := b.GetOrderDetail([]int64{o})
|
||||
if err != nil {
|
||||
return OrderDetail, err
|
||||
}
|
||||
|
||||
30
exchanges/btse/README.md
Normal file
30
exchanges/btse/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
# GoCryptoTrader Btse Exchange Wrapper
|
||||
|
||||
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
|
||||
|
||||
An exchange interface wrapper for the GoCryptoTrader application.
|
||||
|
||||
## This is still in active development
|
||||
|
||||
You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
|
||||
|
||||
## Current Btse Exchange Features
|
||||
|
||||
+ REST Support
|
||||
+ Websocket Support
|
||||
|
||||
+ Can be used as a package
|
||||
|
||||
## Notes
|
||||
|
||||
+ Please add notes here with any production issues
|
||||
+ Please provide link to exchange website and API documentation
|
||||
|
||||
## Contributors
|
||||
|
||||
+ Please add your information
|
||||
|
||||
|User|Github|Contribution|
|
||||
|--|--|--|
|
||||
|AliasGoesHere|https://github.com/AliasGoesHere |WHAT-YOU-DID|
|
||||
367
exchanges/btse/btse.go
Normal file
367
exchanges/btse/btse.go
Normal file
@@ -0,0 +1,367 @@
|
||||
package btse
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
"github.com/thrasher-/gocryptotrader/currency/symbol"
|
||||
exchange "github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/request"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
log "github.com/thrasher-/gocryptotrader/logger"
|
||||
)
|
||||
|
||||
// BTSE is the overarching type across this package
|
||||
type BTSE struct {
|
||||
exchange.Base
|
||||
WebsocketConn *websocket.Conn
|
||||
}
|
||||
|
||||
const (
|
||||
btseAPIURL = "https://api.btse.com/v1/restapi"
|
||||
btseAPIVersion = "1"
|
||||
|
||||
// Public endpoints
|
||||
btseMarkets = "markets"
|
||||
btseTrades = "trades"
|
||||
btseTicker = "ticker"
|
||||
btseStats = "stats"
|
||||
btseTime = "time"
|
||||
|
||||
// Authenticated endpoints
|
||||
btseAccount = "account"
|
||||
btseOrder = "order"
|
||||
btsePendingOrders = "pending"
|
||||
btseDeleteOrder = "deleteOrder"
|
||||
btseDeleteOrders = "deleteOrders"
|
||||
btseFills = "fills"
|
||||
)
|
||||
|
||||
// SetDefaults sets the basic defaults for BTSE
|
||||
func (b *BTSE) SetDefaults() {
|
||||
b.Name = "BTSE"
|
||||
b.Enabled = false
|
||||
b.Verbose = false
|
||||
b.RESTPollingDelay = 10
|
||||
b.APIWithdrawPermissions = exchange.NoAPIWithdrawalMethods
|
||||
b.RequestCurrencyPairFormat.Delimiter = "-"
|
||||
b.RequestCurrencyPairFormat.Uppercase = true
|
||||
b.ConfigCurrencyPairFormat.Delimiter = "-"
|
||||
b.ConfigCurrencyPairFormat.Uppercase = true
|
||||
b.AssetTypes = []string{ticker.Spot}
|
||||
b.Requester = request.New(b.Name,
|
||||
request.NewRateLimit(time.Second, 0),
|
||||
request.NewRateLimit(time.Second, 0),
|
||||
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout))
|
||||
b.APIUrlDefault = btseAPIURL
|
||||
b.APIUrl = b.APIUrlDefault
|
||||
b.SupportsAutoPairUpdating = true
|
||||
b.SupportsRESTTickerBatching = false
|
||||
b.WebsocketInit()
|
||||
b.Websocket.Functionality = exchange.WebsocketOrderbookSupported |
|
||||
exchange.WebsocketTickerSupported
|
||||
}
|
||||
|
||||
// Setup takes in the supplied exchange configuration details and sets params
|
||||
func (b *BTSE) Setup(exch config.ExchangeConfig) {
|
||||
if !exch.Enabled {
|
||||
b.SetEnabled(false)
|
||||
} else {
|
||||
b.Enabled = true
|
||||
b.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
|
||||
b.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
|
||||
b.SetHTTPClientTimeout(exch.HTTPTimeout)
|
||||
b.SetHTTPClientUserAgent(exch.HTTPUserAgent)
|
||||
b.RESTPollingDelay = exch.RESTPollingDelay
|
||||
b.Verbose = exch.Verbose
|
||||
b.Websocket.SetEnabled(exch.Websocket)
|
||||
b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
|
||||
b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
|
||||
b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
|
||||
err := b.SetCurrencyPairFormat()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = b.SetAssetTypes()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = b.SetAutoPairDefaults()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = b.SetAPIURL(exch)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = b.SetClientProxyAddress(exch.ProxyAddress)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = b.WebsocketSetup(b.WsConnect,
|
||||
exch.Name,
|
||||
exch.Websocket,
|
||||
btseWebsocket,
|
||||
exch.WebsocketURL)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetMarkets returns a list of markets available on BTSE
|
||||
func (b *BTSE) GetMarkets() (*Markets, error) {
|
||||
var m Markets
|
||||
return &m, b.SendHTTPRequest(http.MethodGet, btseMarkets, &m)
|
||||
}
|
||||
|
||||
// GetTrades returns a list of trades for the specified symbol
|
||||
func (b *BTSE) GetTrades(symbol string) (*Trades, error) {
|
||||
var t Trades
|
||||
endpoint := fmt.Sprintf("%s/%s", btseTrades, symbol)
|
||||
return &t, b.SendHTTPRequest(http.MethodGet, endpoint, &t)
|
||||
|
||||
}
|
||||
|
||||
// GetTicker returns the ticker for a specified symbol
|
||||
func (b *BTSE) GetTicker(symbol string) (*Ticker, error) {
|
||||
type tickerResponse struct {
|
||||
Price interface{} `json:"price"`
|
||||
Size float64 `json:"size,string"`
|
||||
Bid float64 `json:"bid,string"`
|
||||
Ask float64 `json:"ask,string"`
|
||||
Volume float64 `json:"volume,string"`
|
||||
Time string `json:"time"`
|
||||
}
|
||||
|
||||
var r tickerResponse
|
||||
endpoint := fmt.Sprintf("%s/%s", btseTicker, symbol)
|
||||
err := b.SendHTTPRequest(http.MethodGet, endpoint, &r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := strings.Replace(r.Price.(string), ",", "", -1)
|
||||
price, err := strconv.ParseFloat(p, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Ticker{
|
||||
Price: price,
|
||||
Size: r.Size,
|
||||
Bid: r.Bid,
|
||||
Ask: r.Ask,
|
||||
Volume: r.Volume,
|
||||
Time: r.Time,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetMarketStatistics gets market statistics for a specificed market
|
||||
func (b *BTSE) GetMarketStatistics(symbol string) (*MarketStatistics, error) {
|
||||
var m MarketStatistics
|
||||
endpoint := fmt.Sprintf("%s/%s", btseStats, symbol)
|
||||
return &m, b.SendHTTPRequest(http.MethodGet, endpoint, &m)
|
||||
}
|
||||
|
||||
// GetServerTime returns the exchanges server time
|
||||
func (b *BTSE) GetServerTime() (*ServerTime, error) {
|
||||
var s ServerTime
|
||||
return &s, b.SendHTTPRequest(http.MethodGet, btseTime, &s)
|
||||
}
|
||||
|
||||
// GetAccountBalance returns the users account balance
|
||||
func (b *BTSE) GetAccountBalance() (*AccountBalance, error) {
|
||||
var a AccountBalance
|
||||
return &a, b.SendAuthenticatedHTTPRequest(http.MethodGet, btseAccount, nil, &a)
|
||||
}
|
||||
|
||||
// CreateOrder creates an order
|
||||
func (b *BTSE) CreateOrder(amount, price float64, side, orderType, symbol, timeInForce, tag string) (*string, error) {
|
||||
req := make(map[string]interface{})
|
||||
req["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
|
||||
req["price"] = strconv.FormatFloat(price, 'f', -1, 64)
|
||||
req["side"] = side
|
||||
req["type"] = orderType
|
||||
req["product_id"] = symbol
|
||||
|
||||
if timeInForce != "" {
|
||||
req["time_in_force"] = timeInForce
|
||||
}
|
||||
|
||||
if tag != "" {
|
||||
req["tag"] = tag
|
||||
}
|
||||
|
||||
type orderResp struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
var r orderResp
|
||||
return &r.ID, b.SendAuthenticatedHTTPRequest(http.MethodPost, btseOrder, req, &r)
|
||||
}
|
||||
|
||||
// GetOrders returns all pending orders
|
||||
func (b *BTSE) GetOrders(productID string) (*OpenOrders, error) {
|
||||
req := make(map[string]interface{})
|
||||
if productID != "" {
|
||||
req["product_id"] = productID
|
||||
}
|
||||
var o OpenOrders
|
||||
return &o, b.SendAuthenticatedHTTPRequest(http.MethodGet, btsePendingOrders, req, &o)
|
||||
}
|
||||
|
||||
// CancelExistingOrder cancels an order
|
||||
func (b *BTSE) CancelExistingOrder(orderID, productID string) (*CancelOrder, error) {
|
||||
var c CancelOrder
|
||||
req := make(map[string]interface{})
|
||||
req["order_id"] = orderID
|
||||
req["product_id"] = productID
|
||||
return &c, b.SendAuthenticatedHTTPRequest(http.MethodPost, btseDeleteOrder, req, &c)
|
||||
}
|
||||
|
||||
// CancelOrders cancels all orders
|
||||
// productID optional. If product ID is sent, all orders of that specified market
|
||||
// will be cancelled. If not specified, all orders of all markets will be cancelled
|
||||
func (b *BTSE) CancelOrders(productID string) (*CancelOrder, error) {
|
||||
var c CancelOrder
|
||||
req := make(map[string]interface{})
|
||||
if productID != "" {
|
||||
req["product_id"] = productID
|
||||
}
|
||||
return &c, b.SendAuthenticatedHTTPRequest(http.MethodPost, btseDeleteOrders, req, &c)
|
||||
}
|
||||
|
||||
// GetFills gets all filled orders
|
||||
func (b *BTSE) GetFills(orderID, productID, before, after, limit string) (*FilledOrders, error) {
|
||||
if orderID != "" && productID != "" {
|
||||
return nil, errors.New("orderID and productID cannot co-exist in the same query")
|
||||
} else if orderID == "" && productID == "" {
|
||||
return nil, errors.New("orderID OR productID must be set")
|
||||
}
|
||||
|
||||
req := make(map[string]interface{})
|
||||
if orderID != "" {
|
||||
req["order_id"] = orderID
|
||||
}
|
||||
|
||||
if productID != "" {
|
||||
req["product_id"] = productID
|
||||
}
|
||||
|
||||
if before != "" {
|
||||
req["before"] = before
|
||||
}
|
||||
|
||||
if after != "" {
|
||||
req["after"] = after
|
||||
}
|
||||
|
||||
if limit != "" {
|
||||
req["limit"] = limit
|
||||
}
|
||||
|
||||
var o FilledOrders
|
||||
return &o, b.SendAuthenticatedHTTPRequest(http.MethodPost, btseFills, req, &o)
|
||||
}
|
||||
|
||||
// SendHTTPRequest sends an HTTP request to the desired endpoint
|
||||
func (b *BTSE) SendHTTPRequest(method, endpoint string, result interface{}) error {
|
||||
p := fmt.Sprintf("%s/%s", btseAPIURL, endpoint)
|
||||
return b.SendPayload(method, p, nil, nil, &result, false, b.Verbose)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to the desired endpoint
|
||||
func (b *BTSE) SendAuthenticatedHTTPRequest(method, endpoint string, req map[string]interface{}, result interface{}) error {
|
||||
if !b.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name)
|
||||
}
|
||||
|
||||
payload, err := common.JSONEncode(req)
|
||||
if err != nil {
|
||||
return errors.New("sendAuthenticatedAPIRequest: unable to JSON request")
|
||||
}
|
||||
|
||||
headers := make(map[string]string)
|
||||
headers["API-KEY"] = b.APIKey
|
||||
headers["API-PASSPHRASE"] = b.APISecret
|
||||
if len(payload) > 0 {
|
||||
headers["Content-Type"] = "application/json"
|
||||
}
|
||||
|
||||
p := fmt.Sprintf("%s/%s", btseAPIURL, endpoint)
|
||||
if b.Verbose {
|
||||
log.Debugf("Sending %s request to URL %s with params %s\n", method, p, string(payload))
|
||||
}
|
||||
return b.SendPayload(method, p, headers, strings.NewReader(string(payload)),
|
||||
&result, true, b.Verbose)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
func (b *BTSE) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
|
||||
var fee float64
|
||||
|
||||
switch feeBuilder.FeeType {
|
||||
case exchange.CryptocurrencyTradeFee:
|
||||
fee = calculateTradingFee(feeBuilder.IsMaker)
|
||||
case exchange.CryptocurrencyWithdrawalFee:
|
||||
if feeBuilder.FirstCurrency == symbol.BTC {
|
||||
fee = 0.0005
|
||||
} else if feeBuilder.FirstCurrency == symbol.USDT {
|
||||
fee = 5
|
||||
}
|
||||
case exchange.InternationalBankDepositFee:
|
||||
fee = getInternationalBankDepositFee(feeBuilder.Amount)
|
||||
case exchange.InternationalBankWithdrawalFee:
|
||||
fee = getInternationalBankWithdrawalFee(feeBuilder.Amount)
|
||||
}
|
||||
return fee, nil
|
||||
}
|
||||
|
||||
// getInternationalBankDepositFee returns international deposit fee
|
||||
// Only when the initial deposit amount is less than $1000 or equivalent,
|
||||
// BTSE will charge a small fee (0.25% or $3 USD equivalent, whichever is greater).
|
||||
// The small deposit fee is charged in whatever currency it comes in.
|
||||
func getInternationalBankDepositFee(amount float64) float64 {
|
||||
var fee float64
|
||||
if amount <= 1000 {
|
||||
fee = amount * 0.0025
|
||||
if fee < 3 {
|
||||
return 3
|
||||
}
|
||||
}
|
||||
return fee
|
||||
}
|
||||
|
||||
// getInternationalBankWithdrawalFee returns international withdrawal fee
|
||||
// 0.1% (min25 USD)
|
||||
func getInternationalBankWithdrawalFee(amount float64) float64 {
|
||||
fee := amount * 0.001
|
||||
|
||||
if fee < 25 {
|
||||
return 25
|
||||
}
|
||||
return fee
|
||||
}
|
||||
|
||||
// calculateTradingFee BTSE has fee tiers, but does not disclose them via API,
|
||||
// so the largest fee has to be assumed
|
||||
func calculateTradingFee(isMaker bool) float64 {
|
||||
fee := 0.00050
|
||||
if !isMaker {
|
||||
fee = 0.0015
|
||||
}
|
||||
return fee
|
||||
}
|
||||
|
||||
func parseOrderTime(timeStr string) time.Time {
|
||||
t, _ := time.Parse("2006-01-02 15:04:04", timeStr)
|
||||
return t
|
||||
}
|
||||
298
exchanges/btse/btse_test.go
Normal file
298
exchanges/btse/btse_test.go
Normal file
@@ -0,0 +1,298 @@
|
||||
package btse
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
"github.com/thrasher-/gocryptotrader/currency/pair"
|
||||
"github.com/thrasher-/gocryptotrader/currency/symbol"
|
||||
exchange "github.com/thrasher-/gocryptotrader/exchanges"
|
||||
)
|
||||
|
||||
// Please supply your own keys here to do better tests
|
||||
const (
|
||||
apiKey = ""
|
||||
apiSecret = ""
|
||||
canManipulateRealOrders = false
|
||||
)
|
||||
|
||||
var b BTSE
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
btseConfig, err := cfg.GetExchangeConfig("BTSE")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - BTSE Setup() init error")
|
||||
}
|
||||
|
||||
btseConfig.AuthenticatedAPISupport = true
|
||||
btseConfig.APIKey = apiKey
|
||||
btseConfig.APISecret = apiSecret
|
||||
|
||||
b.Setup(btseConfig)
|
||||
}
|
||||
|
||||
func TestGetMarkets(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
_, err := b.GetMarkets()
|
||||
if err != nil {
|
||||
t.Fatalf("Test failed. Err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTrades(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
_, err := b.GetTrades("BTC-USD")
|
||||
if err != nil {
|
||||
t.Fatalf("Test failed. Err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
_, err := b.GetTicker("BTC-USD")
|
||||
if err != nil {
|
||||
t.Fatalf("Test failed. Err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMarketStatistics(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
_, err := b.GetMarketStatistics("BTC-USD")
|
||||
if err != nil {
|
||||
t.Fatalf("Test failed. Err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetServerTime(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
_, err := b.GetServerTime()
|
||||
if err != nil {
|
||||
t.Fatalf("Test failed. Err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccount(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
_, err := b.GetAccountBalance()
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Errorf("Could not get account balance: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFills(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
_, err := b.GetFills("", "BTC-USD", "", "", "")
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Errorf("Could not get fills: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetActiveOrders(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
}
|
||||
|
||||
_, err := b.GetActiveOrders(getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
}
|
||||
|
||||
_, err := b.GetOrderHistory(getOrdersRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Fatal("Test failed. Expected different result")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatWithdrawPermissions(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
expected := exchange.NoAPIWithdrawalMethodsText
|
||||
actual := b.FormatWithdrawPermissions()
|
||||
if actual != expected {
|
||||
t.Errorf("Expected: %s, Received: %s", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFee(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
feeBuilder := exchange.FeeBuilder{
|
||||
FeeType: exchange.CryptocurrencyTradeFee,
|
||||
FirstCurrency: "BTC",
|
||||
SecondCurrency: "USD",
|
||||
IsMaker: true,
|
||||
Amount: 1000,
|
||||
}
|
||||
|
||||
if resp, err := b.GetFee(feeBuilder); resp != 0.00050 || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", 0.00050, resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
feeBuilder.IsMaker = false
|
||||
if resp, err := b.GetFee(feeBuilder); resp != 0.0015 || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", 0.0015, resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
|
||||
if resp, err := b.GetFee(feeBuilder); resp != 0.0005 || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", 0.0005, resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
feeBuilder.FirstCurrency = "USDT"
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(5) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(5), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
feeBuilder.FeeType = exchange.InternationalBankDepositFee
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(3) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(3), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
feeBuilder.Amount = 1000000
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(1000) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(1000), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
feeBuilder.Amount = 1000
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(25) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(25), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseOrderTime(t *testing.T) {
|
||||
expected := int64(1534794360)
|
||||
actual := parseOrderTime("2018-08-20 19:20:46").Unix()
|
||||
if expected != actual {
|
||||
t.Errorf("Test Failed. TestParseOrderTime expected: %d, got %d", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func areTestAPIKeysSet() bool {
|
||||
if b.APIKey != "" && b.APIKey != "Key" &&
|
||||
b.APISecret != "" && b.APISecret != "Secret" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
func TestSubmitOrder(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
var p = pair.CurrencyPair{
|
||||
Delimiter: "",
|
||||
FirstCurrency: symbol.BTC,
|
||||
SecondCurrency: symbol.USD,
|
||||
}
|
||||
response, err := b.SubmitOrder(p, exchange.SellOrderSide, exchange.LimitOrderType, 0.01, 1000000, "clientId")
|
||||
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
|
||||
t.Errorf("Order failed to be placed: %v", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelExchangeOrder(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
currencyPair := pair.NewCurrencyPairWithDelimiter(symbol.BTC, symbol.USD, "-")
|
||||
|
||||
var orderCancellation = exchange.OrderCancellation{
|
||||
OrderID: "0b66ccaf-dfd4-4b9f-a30b-2380b9c7b66d",
|
||||
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
AccountID: "1",
|
||||
CurrencyPair: currencyPair,
|
||||
}
|
||||
|
||||
err := b.CancelOrder(orderCancellation)
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
currencyPair := pair.NewCurrencyPairWithDelimiter(symbol.BTC, symbol.USD, "-")
|
||||
|
||||
var orderCancellation = exchange.OrderCancellation{
|
||||
OrderID: "1",
|
||||
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
AccountID: "1",
|
||||
CurrencyPair: currencyPair,
|
||||
}
|
||||
|
||||
resp, err := b.CancelAllOrders(orderCancellation)
|
||||
|
||||
if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Errorf("Could not cancel orders: %v", err)
|
||||
}
|
||||
|
||||
if len(resp.OrderStatus) > 0 {
|
||||
t.Errorf("%v orders failed to cancel", len(resp.OrderStatus))
|
||||
}
|
||||
}
|
||||
135
exchanges/btse/btse_types.go
Normal file
135
exchanges/btse/btse_types.go
Normal file
@@ -0,0 +1,135 @@
|
||||
package btse
|
||||
|
||||
// Market stores market data
|
||||
type Market struct {
|
||||
ID string `json:"id"`
|
||||
BaseCurrency string `json:"base_currency"`
|
||||
QuoteCurrency string `json:"quote_currency"`
|
||||
BaseMinSize float64 `json:"base_min_size"`
|
||||
BaseMaxSize float64 `json:"base_max_size"`
|
||||
BaseIncremementSize float64 `json:"base_increment_size"`
|
||||
QuoteMinPrice float64 `json:"quote_min_price"`
|
||||
QuoteIncrement float64 `json:"quote_increment"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// Markets stores an array of market data
|
||||
type Markets []Market
|
||||
|
||||
// Trade stores trade data
|
||||
type Trade struct {
|
||||
SerialID string `json:"serial_id"`
|
||||
Symbol string `json:"symbol"`
|
||||
Price float64 `json:"price"`
|
||||
Amount float64 `json:"amount"`
|
||||
Time string `json:"time"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// Trades stores an array of trade data
|
||||
type Trades []Trade
|
||||
|
||||
// Ticker stores the ticker data
|
||||
type Ticker struct {
|
||||
Price float64
|
||||
Size float64
|
||||
Bid float64
|
||||
Ask float64
|
||||
Volume float64
|
||||
Time string
|
||||
}
|
||||
|
||||
// MarketStatistics stores market statistics for a particular product
|
||||
type MarketStatistics struct {
|
||||
Open float64 `json:"open,string"`
|
||||
Low float64 `json:"low,string"`
|
||||
High float64 `json:"high,string"`
|
||||
Close float64 `json:"close,string"`
|
||||
Volume float64 `json:"volume,string"`
|
||||
Time string `json:"time"`
|
||||
}
|
||||
|
||||
// ServerTime stores the server time data
|
||||
type ServerTime struct {
|
||||
ISO string `json:"iso"`
|
||||
Epoch float64 `json:"epoch"`
|
||||
}
|
||||
|
||||
// CurrencyBalance stores the account info data
|
||||
type CurrencyBalance struct {
|
||||
Currency string `json:"currency"`
|
||||
Total float64 `json:"total,string"`
|
||||
Available float64 `json:"available,string"`
|
||||
}
|
||||
|
||||
// AccountBalance stores an array of currency balances
|
||||
type AccountBalance []CurrencyBalance
|
||||
|
||||
// Order stores the order info
|
||||
type Order struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Side string `json:"side"`
|
||||
Price float64 `json:"price"`
|
||||
Amount float64 `json:"amount"`
|
||||
Tag string `json:"tag"`
|
||||
ProductID string `json:"product_id"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// OpenOrder stores an open order info
|
||||
type OpenOrder struct {
|
||||
Order
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// OpenOrders stores an array of orders
|
||||
type OpenOrders []OpenOrder
|
||||
|
||||
// CancelOrder stores the cancel order response data
|
||||
type CancelOrder struct {
|
||||
Code int `json:"code"`
|
||||
Time int64 `json:"time"`
|
||||
}
|
||||
|
||||
// FilledOrder stores filled order data
|
||||
type FilledOrder struct {
|
||||
Price float64 `json:"price"`
|
||||
Amount float64 `json:"amount"`
|
||||
Fee float64 `json:"fee"`
|
||||
Side string `json:"side"`
|
||||
Tag string `json:"tag"`
|
||||
ID int64 `json:"id"`
|
||||
TradeID string `json:"trade_id"`
|
||||
ProductID string `json:"product_id"`
|
||||
OrderID string `json:"order_id"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// FilledOrders stores an array of filled orders
|
||||
type FilledOrders []FilledOrder
|
||||
|
||||
type websocketSubscribe struct {
|
||||
Type string `json:"type"`
|
||||
Channels []websocketChannel `json:"channels"`
|
||||
}
|
||||
|
||||
type websocketChannel struct {
|
||||
Name string `json:"name"`
|
||||
ProductIDs []string `json:"product_ids"`
|
||||
}
|
||||
|
||||
type wsTicker struct {
|
||||
BestAsk float64 `json:"best_ask,string"`
|
||||
BestBids float64 `json:"best_bid,string"`
|
||||
LastSize float64 `json:"last_size,string"`
|
||||
Price interface{} `json:"price"`
|
||||
ProductID string `json:"product_id"`
|
||||
}
|
||||
|
||||
type websocketOrderbookSnapshot struct {
|
||||
ProductID string `json:"product_id"`
|
||||
Type string `json:"type"`
|
||||
Bids [][]interface{} `json:"bids"`
|
||||
Asks [][]interface{} `json:"asks"`
|
||||
}
|
||||
223
exchanges/btse/btse_websocket.go
Normal file
223
exchanges/btse/btse_websocket.go
Normal file
@@ -0,0 +1,223 @@
|
||||
package btse
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/currency/pair"
|
||||
exchange "github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
)
|
||||
|
||||
const (
|
||||
btseWebsocket = "wss://ws.btse.com/api/ws-feed"
|
||||
)
|
||||
|
||||
// WebsocketSubscriber subscribes to websocket channels with respect to enabled
|
||||
// currencies
|
||||
func (b *BTSE) WebsocketSubscriber() error {
|
||||
subscribe := websocketSubscribe{
|
||||
Type: "subscribe",
|
||||
Channels: []websocketChannel{
|
||||
{
|
||||
Name: "snapshot",
|
||||
ProductIDs: b.EnabledPairs,
|
||||
},
|
||||
{
|
||||
Name: "ticker",
|
||||
ProductIDs: b.EnabledPairs,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
data, err := common.JSONEncode(subscribe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return b.WebsocketConn.WriteMessage(websocket.TextMessage, data)
|
||||
}
|
||||
|
||||
// WsConnect connects the websocket client
|
||||
func (b *BTSE) WsConnect() error {
|
||||
if !b.Websocket.IsEnabled() || !b.IsEnabled() {
|
||||
return errors.New(exchange.WebsocketNotEnabled)
|
||||
}
|
||||
|
||||
var dialer websocket.Dialer
|
||||
|
||||
if b.Websocket.GetProxyAddress() != "" {
|
||||
proxy, err := url.Parse(b.Websocket.GetProxyAddress())
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s websocket error - proxy address %s",
|
||||
b.Name, err)
|
||||
}
|
||||
|
||||
dialer.Proxy = http.ProxyURL(proxy)
|
||||
}
|
||||
|
||||
var err error
|
||||
b.WebsocketConn, _, err = dialer.Dial(b.Websocket.GetWebsocketURL(),
|
||||
http.Header{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s websocket error - unable to connect %s",
|
||||
b.Name, err)
|
||||
}
|
||||
|
||||
err = b.WebsocketSubscriber()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go b.WsHandleData()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WsReadData reads data from the websocket connection
|
||||
func (b *BTSE) WsReadData() (exchange.WebsocketResponse, error) {
|
||||
_, resp, err := b.WebsocketConn.ReadMessage()
|
||||
if err != nil {
|
||||
return exchange.WebsocketResponse{}, err
|
||||
}
|
||||
|
||||
b.Websocket.TrafficAlert <- struct{}{}
|
||||
return exchange.WebsocketResponse{Raw: resp}, nil
|
||||
}
|
||||
|
||||
// WsHandleData handles read data from websocket connection
|
||||
func (b *BTSE) WsHandleData() {
|
||||
b.Websocket.Wg.Add(1)
|
||||
|
||||
defer func() {
|
||||
err := b.WebsocketConn.Close()
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- fmt.Errorf("%s - Unable to to close Websocket connection. Error: %s",
|
||||
b.Name, err)
|
||||
}
|
||||
b.Websocket.Wg.Done()
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-b.Websocket.ShutdownC:
|
||||
return
|
||||
|
||||
default:
|
||||
resp, err := b.WsReadData()
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
return
|
||||
}
|
||||
|
||||
type MsgType struct {
|
||||
Type string `json:"type"`
|
||||
ProductID string `json:"product_id"`
|
||||
}
|
||||
|
||||
msgType := MsgType{}
|
||||
err = common.JSONDecode(resp.Raw, &msgType)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
|
||||
switch msgType.Type {
|
||||
case "ticker":
|
||||
var t wsTicker
|
||||
err = common.JSONDecode(resp.Raw, &t)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
p := strings.Replace(t.Price.(string), ",", "", -1)
|
||||
price, err := strconv.ParseFloat(p, 64)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
|
||||
b.Websocket.DataHandler <- exchange.TickerData{
|
||||
Timestamp: time.Now(),
|
||||
Pair: pair.NewCurrencyPairDelimiter(t.ProductID, "-"),
|
||||
AssetType: "SPOT",
|
||||
Exchange: b.GetName(),
|
||||
OpenPrice: price,
|
||||
}
|
||||
case "snapshot":
|
||||
snapshot := websocketOrderbookSnapshot{}
|
||||
err := common.JSONDecode(resp.Raw, &snapshot)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
|
||||
err = b.wsProcessSnapshot(snapshot)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ProcessSnapshot processes the initial orderbook snap shot
|
||||
func (b *BTSE) wsProcessSnapshot(snapshot websocketOrderbookSnapshot) error {
|
||||
var base orderbook.Base
|
||||
for _, bid := range snapshot.Bids {
|
||||
p := strings.Replace(bid[0].(string), ",", "", -1)
|
||||
price, err := strconv.ParseFloat(p, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a := strings.Replace(bid[1].(string), ",", "", -1)
|
||||
amount, err := strconv.ParseFloat(a, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
base.Bids = append(base.Bids,
|
||||
orderbook.Item{Price: price, Amount: amount})
|
||||
}
|
||||
|
||||
for _, ask := range snapshot.Asks {
|
||||
p := strings.Replace(ask[0].(string), ",", "", -1)
|
||||
price, err := strconv.ParseFloat(p, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a := strings.Replace(ask[1].(string), ",", "", -1)
|
||||
amount, err := strconv.ParseFloat(a, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
base.Asks = append(base.Asks,
|
||||
orderbook.Item{Price: price, Amount: amount})
|
||||
}
|
||||
|
||||
p := pair.NewCurrencyPairDelimiter(snapshot.ProductID, "-")
|
||||
base.AssetType = "SPOT"
|
||||
base.Pair = p
|
||||
base.CurrencyPair = snapshot.ProductID
|
||||
base.LastUpdated = time.Now()
|
||||
orderbook.ProcessOrderbook(b.Name, p, base, "SPOT")
|
||||
|
||||
b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
|
||||
Pair: p,
|
||||
Asset: "SPOT",
|
||||
Exchange: b.GetName(),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
346
exchanges/btse/btse_wrapper.go
Normal file
346
exchanges/btse/btse_wrapper.go
Normal file
@@ -0,0 +1,346 @@
|
||||
package btse
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/currency/pair"
|
||||
exchange "github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
log "github.com/thrasher-/gocryptotrader/logger"
|
||||
)
|
||||
|
||||
// Start starts the BTSE go routine
|
||||
func (b *BTSE) Start(wg *sync.WaitGroup) {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
b.Run()
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
// Run implements the BTSE wrapper
|
||||
func (b *BTSE) Run() {
|
||||
if b.Verbose {
|
||||
log.Debugf("%s Websocket: %s. (url: %s).\n", b.GetName(), common.IsEnabled(b.Websocket.IsEnabled()), b.Websocket.GetWebsocketURL())
|
||||
log.Debugf("%s polling delay: %ds.\n", b.GetName(), b.RESTPollingDelay)
|
||||
log.Debugf("%s %d currencies enabled: %s.\n", b.GetName(), len(b.EnabledPairs), b.EnabledPairs)
|
||||
}
|
||||
|
||||
markets, err := b.GetMarkets()
|
||||
if err != nil {
|
||||
log.Errorf("%s failed to get trading pairs. Err: %s", b.Name, err)
|
||||
} else {
|
||||
var currencies []string
|
||||
for _, m := range *markets {
|
||||
currencies = append(currencies, m.ID)
|
||||
}
|
||||
err = b.UpdateCurrencies(currencies, false, false)
|
||||
if err != nil {
|
||||
log.Errorf("%s Failed to update available currencies.\n", b.Name)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// UpdateTicker updates and returns the ticker for a currency pair
|
||||
func (b *BTSE) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
|
||||
var tickerPrice ticker.Price
|
||||
|
||||
t, err := b.GetTicker(exchange.FormatExchangeCurrency(b.Name, p).String())
|
||||
if err != nil {
|
||||
return tickerPrice, err
|
||||
}
|
||||
|
||||
s, err := b.GetMarketStatistics(exchange.FormatExchangeCurrency(b.Name, p).String())
|
||||
if err != nil {
|
||||
return tickerPrice, err
|
||||
|
||||
}
|
||||
|
||||
tickerPrice.Pair = p
|
||||
tickerPrice.Ask = t.Ask
|
||||
tickerPrice.Bid = t.Bid
|
||||
tickerPrice.Low = s.Low
|
||||
tickerPrice.Last = t.Price
|
||||
tickerPrice.Volume = s.Volume
|
||||
tickerPrice.High = s.High
|
||||
ticker.ProcessTicker(b.GetName(), p, tickerPrice, assetType)
|
||||
return ticker.GetTicker(b.Name, p, assetType)
|
||||
}
|
||||
|
||||
// GetTickerPrice returns the ticker for a currency pair
|
||||
func (b *BTSE) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
|
||||
tickerNew, err := ticker.GetTicker(b.GetName(), p, assetType)
|
||||
if err != nil {
|
||||
return b.UpdateTicker(p, assetType)
|
||||
}
|
||||
return tickerNew, nil
|
||||
}
|
||||
|
||||
// GetOrderbookEx returns orderbook base on the currency pair
|
||||
func (b *BTSE) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
|
||||
ob, err := orderbook.GetOrderbook(b.GetName(), p, assetType)
|
||||
if err != nil {
|
||||
return b.UpdateOrderbook(p, assetType)
|
||||
}
|
||||
return ob, nil
|
||||
}
|
||||
|
||||
// UpdateOrderbook updates and returns the orderbook for a currency pair
|
||||
func (b *BTSE) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
|
||||
return orderbook.Base{}, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetAccountInfo retrieves balances for all enabled currencies for the
|
||||
// BTSE exchange
|
||||
func (b *BTSE) GetAccountInfo() (exchange.AccountInfo, error) {
|
||||
var a exchange.AccountInfo
|
||||
balance, err := b.GetAccountBalance()
|
||||
if err != nil {
|
||||
return a, err
|
||||
}
|
||||
|
||||
var currencies []exchange.AccountCurrencyInfo
|
||||
for _, b := range *balance {
|
||||
currencies = append(currencies,
|
||||
exchange.AccountCurrencyInfo{
|
||||
CurrencyName: b.Currency,
|
||||
TotalValue: b.Total,
|
||||
Hold: b.Available,
|
||||
},
|
||||
)
|
||||
}
|
||||
a.Exchange = b.Name
|
||||
a.Accounts = []exchange.Account{
|
||||
{
|
||||
Currencies: currencies,
|
||||
},
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// GetFundingHistory returns funding history, deposits and
|
||||
// withdrawals
|
||||
func (b *BTSE) GetFundingHistory() ([]exchange.FundHistory, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetExchangeHistory returns historic trade data since exchange opening.
|
||||
func (b *BTSE) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (b *BTSE) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) {
|
||||
var resp exchange.SubmitOrderResponse
|
||||
r, err := b.CreateOrder(amount, price, side.ToString(),
|
||||
orderType.ToString(), exchange.FormatExchangeCurrency(b.Name, p).String(), "GTC", clientID)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if *r != "" {
|
||||
resp.IsOrderPlaced = true
|
||||
resp.OrderID = *r
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ModifyOrder will allow of changing orderbook placement and limit to
|
||||
// market conversion
|
||||
func (b *BTSE) ModifyOrder(action exchange.ModifyOrder) (string, error) {
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// CancelOrder cancels an order by its corresponding ID number
|
||||
func (b *BTSE) CancelOrder(order exchange.OrderCancellation) error {
|
||||
r, err := b.CancelExistingOrder(order.OrderID,
|
||||
exchange.FormatExchangeCurrency(b.Name, order.CurrencyPair).String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch r.Code {
|
||||
case -1:
|
||||
return errors.New("order cancellation unsuccessful")
|
||||
case 4:
|
||||
return errors.New("order cancellation timeout")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CancelAllOrders cancels all orders associated with a currency pair
|
||||
// If product ID is sent, all orders of that specified market will be cancelled
|
||||
// If not specified, all orders of all markets will be cancelled
|
||||
func (b *BTSE) CancelAllOrders(orderCancellation exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) {
|
||||
r, err := b.CancelOrders(exchange.FormatExchangeCurrency(b.Name,
|
||||
orderCancellation.CurrencyPair).String())
|
||||
if err != nil {
|
||||
return exchange.CancelAllOrdersResponse{}, err
|
||||
}
|
||||
|
||||
var resp exchange.CancelAllOrdersResponse
|
||||
switch r.Code {
|
||||
case -1:
|
||||
return resp, errors.New("order cancellation unsuccessful")
|
||||
case 4:
|
||||
return resp, errors.New("order cancellation timeout")
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (b *BTSE) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
o, err := b.GetOrders("")
|
||||
if err != nil {
|
||||
return exchange.OrderDetail{}, err
|
||||
}
|
||||
|
||||
var od exchange.OrderDetail
|
||||
if len(*o) == 0 {
|
||||
return od, errors.New("no orders found")
|
||||
}
|
||||
|
||||
for _, o := range *o {
|
||||
if o.ID != orderID {
|
||||
continue
|
||||
}
|
||||
|
||||
var side = exchange.BuyOrderSide
|
||||
if strings.EqualFold(o.Side, exchange.AskOrderSide.ToString()) {
|
||||
side = exchange.SellOrderSide
|
||||
}
|
||||
|
||||
od.CurrencyPair = pair.NewCurrencyPairDelimiter(o.ProductID,
|
||||
b.ConfigCurrencyPairFormat.Delimiter)
|
||||
od.Exchange = b.Name
|
||||
od.Amount = o.Amount
|
||||
od.ID = o.ID
|
||||
od.OrderDate = parseOrderTime(o.CreatedAt)
|
||||
od.OrderSide = side
|
||||
od.OrderType = exchange.OrderType(strings.ToUpper(o.Type))
|
||||
od.Price = o.Price
|
||||
od.Status = o.Status
|
||||
|
||||
fills, err := b.GetFills(orderID, "", "", "", "")
|
||||
if err != nil {
|
||||
return od, fmt.Errorf("unable to get order fills for orderID %s", orderID)
|
||||
}
|
||||
|
||||
for _, f := range *fills {
|
||||
createdAt, _ := time.Parse(time.RFC3339, f.CreatedAt)
|
||||
od.Trades = append(od.Trades, exchange.TradeHistory{
|
||||
Timestamp: createdAt,
|
||||
TID: f.ID,
|
||||
Price: f.Price,
|
||||
Amount: f.Amount,
|
||||
Exchange: b.Name,
|
||||
Type: exchange.OrderSide(f.Side).ToString(),
|
||||
Fee: f.Fee,
|
||||
})
|
||||
}
|
||||
}
|
||||
return od, nil
|
||||
}
|
||||
|
||||
// GetDepositAddress returns a deposit address for a specified currency
|
||||
func (b *BTSE) GetDepositAddress(cryptocurrency pair.CurrencyItem, accountID string) (string, error) {
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func (b *BTSE) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) {
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// WithdrawFiatFunds returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func (b *BTSE) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) {
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func (b *BTSE) WithdrawFiatFundsToInternationalBank(withdrawRequest exchange.WithdrawRequest) (string, error) {
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetWebsocket returns a pointer to the exchange websocket
|
||||
func (b *BTSE) GetWebsocket() (*exchange.Websocket, error) {
|
||||
return b.Websocket, nil
|
||||
}
|
||||
|
||||
// GetActiveOrders retrieves any orders that are active/open
|
||||
func (b *BTSE) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) ([]exchange.OrderDetail, error) {
|
||||
resp, err := b.GetOrders("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var orders []exchange.OrderDetail
|
||||
for _, order := range *resp {
|
||||
var side = exchange.BuyOrderSide
|
||||
if strings.EqualFold(order.Side, exchange.AskOrderSide.ToString()) {
|
||||
side = exchange.SellOrderSide
|
||||
}
|
||||
|
||||
openOrder := exchange.OrderDetail{
|
||||
CurrencyPair: pair.NewCurrencyPairDelimiter(order.ProductID,
|
||||
b.ConfigCurrencyPairFormat.Delimiter),
|
||||
Exchange: b.Name,
|
||||
Amount: order.Amount,
|
||||
ID: order.ID,
|
||||
OrderDate: parseOrderTime(order.CreatedAt),
|
||||
OrderSide: side,
|
||||
OrderType: exchange.OrderType(strings.ToUpper(order.Type)),
|
||||
Price: order.Price,
|
||||
Status: order.Status,
|
||||
}
|
||||
|
||||
fills, err := b.GetFills(order.ID, "", "", "", "")
|
||||
if err != nil {
|
||||
log.Errorf("unable to get order fills for orderID %s", order.ID)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, f := range *fills {
|
||||
createdAt, _ := time.Parse(time.RFC3339, f.CreatedAt)
|
||||
openOrder.Trades = append(openOrder.Trades, exchange.TradeHistory{
|
||||
Timestamp: createdAt,
|
||||
TID: f.ID,
|
||||
Price: f.Price,
|
||||
Amount: f.Amount,
|
||||
Exchange: b.Name,
|
||||
Type: exchange.OrderSide(f.Side).ToString(),
|
||||
Fee: f.Fee,
|
||||
})
|
||||
}
|
||||
orders = append(orders, openOrder)
|
||||
}
|
||||
|
||||
exchange.FilterOrdersByType(&orders, getOrdersRequest.OrderType)
|
||||
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks, getOrdersRequest.EndTicks)
|
||||
exchange.FilterOrdersBySide(&orders, getOrdersRequest.OrderSide)
|
||||
return orders, nil
|
||||
}
|
||||
|
||||
// GetOrderHistory retrieves account order information
|
||||
// Can Limit response to specific order status
|
||||
func (b *BTSE) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) ([]exchange.OrderDetail, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetFeeByType returns an estimate of fee based on type of transaction
|
||||
func (b *BTSE) GetFeeByType(feeBuilder exchange.FeeBuilder) (float64, error) {
|
||||
return b.GetFee(feeBuilder)
|
||||
}
|
||||
@@ -198,7 +198,7 @@ func (c *CoinbasePro) CancelAllOrders(_ exchange.OrderCancellation) (exchange.Ca
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (c *CoinbasePro) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (c *CoinbasePro) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -330,7 +330,7 @@ func (c *COINUT) CancelAllOrders(_ exchange.OrderCancellation) (exchange.CancelA
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (c *COINUT) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (c *COINUT) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ type IBotExchange interface {
|
||||
ModifyOrder(action ModifyOrder) (string, error)
|
||||
CancelOrder(order OrderCancellation) error
|
||||
CancelAllOrders(orders OrderCancellation) (CancelAllOrdersResponse, error)
|
||||
GetOrderInfo(orderID int64) (OrderDetail, error)
|
||||
GetOrderInfo(orderID string) (OrderDetail, error)
|
||||
GetDepositAddress(cryptocurrency pair.CurrencyItem, accountID string) (string, error)
|
||||
|
||||
GetOrderHistory(getOrdersRequest GetOrdersRequest) ([]OrderDetail, error)
|
||||
|
||||
@@ -252,7 +252,7 @@ func (e *EXMO) CancelAllOrders(_ exchange.OrderCancellation) (exchange.CancelAll
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (e *EXMO) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (e *EXMO) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ func (g *Gateio) CancelAllOrders(_ exchange.OrderCancellation) (exchange.CancelA
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (g *Gateio) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (g *Gateio) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ func (g *Gemini) CancelAllOrders(_ exchange.OrderCancellation) (exchange.CancelA
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (g *Gemini) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (g *Gemini) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ func (h *HitBTC) CancelAllOrders(_ exchange.OrderCancellation) (exchange.CancelA
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (h *HitBTC) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (h *HitBTC) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ func (h *HUOBI) CancelAllOrders(orderCancellation exchange.OrderCancellation) (e
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (h *HUOBI) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (h *HUOBI) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ func (h *HUOBIHADAX) CancelAllOrders(orderCancellation exchange.OrderCancellatio
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (h *HUOBIHADAX) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (h *HUOBIHADAX) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ func (i *ItBit) CancelAllOrders(orderCancellation exchange.OrderCancellation) (e
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (i *ItBit) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (i *ItBit) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ func (k *Kraken) CancelAllOrders(_ exchange.OrderCancellation) (exchange.CancelA
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (k *Kraken) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (k *Kraken) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ func (l *LakeBTC) CancelAllOrders(_ exchange.OrderCancellation) (exchange.Cancel
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (l *LakeBTC) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (l *LakeBTC) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ func (l *LocalBitcoins) CancelAllOrders(_ exchange.OrderCancellation) (exchange.
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (l *LocalBitcoins) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (l *LocalBitcoins) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ func (o *OKCoin) CancelAllOrders(orderCancellation exchange.OrderCancellation) (
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (o *OKCoin) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (o *OKCoin) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ func (o *OKEX) CancelAllOrders(_ exchange.OrderCancellation) (exchange.CancelAll
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (o *OKEX) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (o *OKEX) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ func (p *Poloniex) CancelAllOrders(_ exchange.OrderCancellation) (exchange.Cance
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (p *Poloniex) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (p *Poloniex) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ func TestGetOpenOrders(t *testing.T) {
|
||||
|
||||
func TestGetOrderInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := y.GetOrderInfo(6196974)
|
||||
_, err := y.GetOrderInfo("6196974")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetOrderInfo() error", err)
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ func (y *Yobit) CancelAllOrders(_ exchange.OrderCancellation) (exchange.CancelAl
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (y *Yobit) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (y *Yobit) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ func (z *ZB) CancelAllOrders(_ exchange.OrderCancellation) (exchange.CancelAllOr
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (z *ZB) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func (z *ZB) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
var orderDetail exchange.OrderDetail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
75
testdata/configtest.json
vendored
75
testdata/configtest.json
vendored
File diff suppressed because one or more lines are too long
@@ -30,6 +30,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
||||
| Bittrex | Yes | No | NA |
|
||||
| BTCC | Yes | Yes | No |
|
||||
| BTCMarkets | Yes | No | NA |
|
||||
| BTSE | Yes | Yes | NA |
|
||||
| COINUT | Yes | Yes | NA |
|
||||
| Exmo | Yes | NA | NA |
|
||||
| CoinbasePro | Yes | Yes | No|
|
||||
|
||||
@@ -137,7 +137,7 @@ func ({{.Variable}} *{{.CapitalName}}) CancelAllOrders(orderCancellation exchang
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetOrderInfo(orderID int64) (exchange.OrderDetail, error) {
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
return exchange.OrderDetail{}, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user