mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
Exchanges: Remove ANX from codebase (#408)
* Remove ANX from codebase * Doc changes
This commit is contained in:
@@ -1,143 +0,0 @@
|
||||
# GoCryptoTrader package Anx
|
||||
|
||||
<img src="https://github.com/thrasher-corp/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
|
||||
|
||||
|
||||
[](https://travis-ci.org/thrasher-corp/gocryptotrader)
|
||||
[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
|
||||
[](https://godoc.org/github.com/thrasher-corp/gocryptotrader/exchanges/anx)
|
||||
[](http://codecov.io/github/thrasher-corp/gocryptotrader?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/thrasher-corp/gocryptotrader)
|
||||
|
||||
|
||||
This anx package is part of the GoCryptoTrader codebase.
|
||||
|
||||
## This is still in active development
|
||||
|
||||
You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
|
||||
|
||||
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/enQtNTQ5NDAxMjA2Mjc5LTc5ZDE1ZTNiOGM3ZGMyMmY1NTAxYWZhODE0MWM5N2JlZDk1NDU0YTViYzk4NTk3OTRiMDQzNGQ1YTc4YmRlMTk)
|
||||
|
||||
## ANX Exchange
|
||||
|
||||
### Current Features
|
||||
|
||||
+ REST functions
|
||||
|
||||
### Features not yet included
|
||||
|
||||
+ Long polling streaming
|
||||
|
||||
### How to enable
|
||||
|
||||
+ [Enable via configuration](https://github.com/thrasher-corp/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
|
||||
|
||||
+ Individual package example below:
|
||||
|
||||
```go
|
||||
// Exchanges will be abstracted out in further updates and examples will be
|
||||
// supplied then
|
||||
```
|
||||
|
||||
### How to do REST public/private calls
|
||||
|
||||
+ If enabled via "configuration".json file the exchange will be added to the
|
||||
IBotExchange array in the ```go var bot Bot``` and you will only be able to use
|
||||
the wrapper interface functions for accessing exchange data. View routines.go
|
||||
for an example of integration usage with GoCryptoTrader. Rudimentary example
|
||||
below:
|
||||
|
||||
main.go
|
||||
```go
|
||||
var a exchange.IBotExchange
|
||||
|
||||
for i := range bot.Exchanges {
|
||||
if bot.Exchanges[i].GetName() == "ANX" {
|
||||
a = bot.Exchanges[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Public calls - wrapper functions
|
||||
|
||||
// Fetches current ticker information
|
||||
tick, err := a.FetchTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := a.FetchOrderbook()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
|
||||
// set and AuthenticatedAPISupport is set to true
|
||||
|
||||
// Fetches current account information
|
||||
accountInfo, err := a.GetAccountInfo()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
+ If enabled via individually importing package, rudimentary example below:
|
||||
|
||||
```go
|
||||
// Public calls
|
||||
|
||||
// Fetches current ticker information
|
||||
ticker, err := a.GetTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := a.GetOrderBook()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Private calls - make sure your APIKEY and APISECRET are set and
|
||||
// AuthenticatedAPISupport is set to true
|
||||
|
||||
// GetUserInfo returns account info
|
||||
accountInfo, err := a.GetUserInfo(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Submits an order and the exchange and returns its tradeID
|
||||
tradeID, err := a.Trade(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
### How to do LongPolling public/private calls
|
||||
|
||||
```go
|
||||
// Exchanges will be abstracted out in further updates and examples will be
|
||||
// supplied then
|
||||
```
|
||||
|
||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||
|
||||
## Contribution
|
||||
|
||||
Please feel free to submit any pull requests or suggest any desired features to be added.
|
||||
|
||||
When submitting a PR, please abide by our coding guidelines:
|
||||
|
||||
+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
|
||||
+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
|
||||
+ Code must adhere to our [coding style](https://github.com/thrasher-corp/gocryptotrader/blob/master/doc/coding_style.md).
|
||||
+ Pull requests need to be based on and opened against the `master` branch.
|
||||
|
||||
## Donations
|
||||
|
||||
<img src="https://github.com/thrasher-corp/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
|
||||
|
||||
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
|
||||
|
||||
***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***
|
||||
@@ -1,474 +0,0 @@
|
||||
package anx
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common/crypto"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
log "github.com/thrasher-corp/gocryptotrader/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
anxAPIURL = "https://anxpro.com/"
|
||||
anxAPIVersion = "3"
|
||||
anxAPIKey = "apiKey"
|
||||
anxCurrencies = "currencyStatic"
|
||||
anxDataToken = "dataToken"
|
||||
anxOrderNew = "order/new"
|
||||
anxOrderCancel = "order/cancel"
|
||||
anxOrderList = "order/list"
|
||||
anxOrderInfo = "order/info"
|
||||
anxSend = "send"
|
||||
anxSubaccountNew = "subaccount/new"
|
||||
anxReceieveAddress = "receive"
|
||||
anxCreateAddress = "receive/create"
|
||||
anxTicker = "money/ticker"
|
||||
anxDepth = "money/depth/full"
|
||||
anxAccount = "account"
|
||||
|
||||
// ANX rate limites for authenticated and unauthenticated requests
|
||||
anxAuthRate = 0
|
||||
anxUnauthRate = 0
|
||||
)
|
||||
|
||||
// ANX is the overarching type across the alphapoint package
|
||||
type ANX struct {
|
||||
exchange.Base
|
||||
}
|
||||
|
||||
// GetCurrencies returns a list of supported currencies (both fiat
|
||||
// and cryptocurrencies)
|
||||
func (a *ANX) GetCurrencies() (CurrenciesStore, error) {
|
||||
var result CurrenciesStaticResponse
|
||||
path := fmt.Sprintf("%sapi/3/%s", a.API.Endpoints.URL, anxCurrencies)
|
||||
|
||||
err := a.SendHTTPRequest(path, &result)
|
||||
if err != nil {
|
||||
return CurrenciesStore{}, err
|
||||
}
|
||||
|
||||
return result.CurrenciesResponse, nil
|
||||
}
|
||||
|
||||
// GetTicker returns the current ticker
|
||||
func (a *ANX) GetTicker(currency string) (Ticker, error) {
|
||||
var t Ticker
|
||||
path := fmt.Sprintf("%sapi/2/%s/%s", a.API.Endpoints.URL, currency, anxTicker)
|
||||
return t, a.SendHTTPRequest(path, &t)
|
||||
}
|
||||
|
||||
// GetDepth returns current orderbook depth.
|
||||
func (a *ANX) GetDepth(currency string) (Depth, error) {
|
||||
var depth Depth
|
||||
path := fmt.Sprintf("%sapi/2/%s/%s", a.API.Endpoints.URL, currency, anxDepth)
|
||||
return depth, a.SendHTTPRequest(path, &depth)
|
||||
}
|
||||
|
||||
// GetAPIKey returns a new generated API key set.
|
||||
func (a *ANX) GetAPIKey(username, password, otp, deviceID string) (apiKey, apiSecret string, err error) {
|
||||
req := make(map[string]interface{})
|
||||
req["nonce"] = strconv.FormatInt(time.Now().UnixNano(), 10)[0:13]
|
||||
req["username"] = username
|
||||
req["password"] = password
|
||||
|
||||
if otp != "" {
|
||||
req["otp"] = otp
|
||||
}
|
||||
|
||||
req["deviceId"] = deviceID
|
||||
|
||||
type APIKeyResponse struct {
|
||||
APIKey string `json:"apiKey"`
|
||||
APISecret string `json:"apiSecret"`
|
||||
ResultCode string `json:"resultCode"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
var response APIKeyResponse
|
||||
|
||||
err = a.SendAuthenticatedHTTPRequest(anxAPIKey, req, &response)
|
||||
if err != nil {
|
||||
return apiKey, apiSecret, err
|
||||
}
|
||||
|
||||
if response.ResultCode != "OK" {
|
||||
return apiKey, apiSecret, errors.New("Response code is not OK: " + response.ResultCode)
|
||||
}
|
||||
|
||||
apiKey = response.APIKey
|
||||
apiSecret = response.APISecret
|
||||
return apiKey, apiSecret, err
|
||||
}
|
||||
|
||||
// GetDataToken returns token data
|
||||
func (a *ANX) GetDataToken() (string, error) {
|
||||
req := make(map[string]interface{})
|
||||
|
||||
type DataTokenResponse struct {
|
||||
ResultCode string `json:"resultCode"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Token string `json:"token"`
|
||||
UUID string `json:"uuid"`
|
||||
}
|
||||
var response DataTokenResponse
|
||||
|
||||
err := a.SendAuthenticatedHTTPRequest(anxDataToken, req, &response)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if response.ResultCode != "OK" {
|
||||
return "", errors.New("Response code is not OK: %s" + response.ResultCode)
|
||||
}
|
||||
return response.Token, nil
|
||||
}
|
||||
|
||||
// NewOrder sends a new order request to the exchange.
|
||||
func (a *ANX) NewOrder(orderType string, buy bool, tradedCurrency string, tradedCurrencyAmount float64, settlementCurrency string, settlementCurrencyAmount, limitPriceSettlement float64,
|
||||
replace bool, replaceUUID string, replaceIfActive bool) (string, error) {
|
||||
req := make(map[string]interface{})
|
||||
var order Order
|
||||
order.OrderType = orderType
|
||||
order.BuyTradedCurrency = buy
|
||||
|
||||
if buy {
|
||||
order.TradedCurrencyAmount = tradedCurrencyAmount
|
||||
} else {
|
||||
order.SettlementCurrencyAmount = settlementCurrencyAmount
|
||||
}
|
||||
|
||||
order.TradedCurrency = tradedCurrency
|
||||
order.SettlementCurrency = settlementCurrency
|
||||
order.LimitPriceInSettlementCurrency = limitPriceSettlement
|
||||
|
||||
if replace {
|
||||
order.ReplaceExistingOrderUUID = replaceUUID
|
||||
order.ReplaceOnlyIfActive = replaceIfActive
|
||||
}
|
||||
|
||||
req["order"] = order
|
||||
|
||||
type OrderResponse struct {
|
||||
OrderID string `json:"orderId"`
|
||||
Timestamp int64 `json:"timestamp,string"`
|
||||
ResultCode string `json:"resultCode"`
|
||||
}
|
||||
var response OrderResponse
|
||||
|
||||
err := a.SendAuthenticatedHTTPRequest(anxOrderNew, req, &response)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if response.ResultCode != "OK" {
|
||||
return "", errors.New("Response code is not OK: " + response.ResultCode)
|
||||
}
|
||||
return response.OrderID, nil
|
||||
}
|
||||
|
||||
// CancelOrderByIDs cancels orders, requires already knowing order IDs
|
||||
// There is no existing API call to retrieve orderIds
|
||||
func (a *ANX) CancelOrderByIDs(orderIds []string) (OrderCancelResponse, error) {
|
||||
var response OrderCancelResponse
|
||||
if len(orderIds) == 0 {
|
||||
return response, errors.New("no order ids provided")
|
||||
}
|
||||
|
||||
req := make(map[string]interface{})
|
||||
req["orderIds"] = orderIds
|
||||
|
||||
err := a.SendAuthenticatedHTTPRequest(anxOrderCancel, req, &response)
|
||||
if response.ResultCode != "OK" {
|
||||
return response, errors.New(response.ResultCode)
|
||||
}
|
||||
|
||||
return response, err
|
||||
}
|
||||
|
||||
// GetOrderList retrieves orders from the exchange
|
||||
func (a *ANX) GetOrderList(isActiveOrdersOnly bool) ([]OrderResponse, error) {
|
||||
req := make(map[string]interface{})
|
||||
req["activeOnly"] = isActiveOrdersOnly
|
||||
|
||||
type OrderListResponse struct {
|
||||
Timestamp int64 `json:"timestamp,string"`
|
||||
ResultCode string `json:"resultCode"`
|
||||
Count int64 `json:"count"`
|
||||
OrderResponses []OrderResponse `json:"orders"`
|
||||
}
|
||||
var response OrderListResponse
|
||||
err := a.SendAuthenticatedHTTPRequest(anxOrderList, req, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if response.ResultCode != "OK" {
|
||||
return nil, errors.New(response.ResultCode)
|
||||
}
|
||||
|
||||
return response.OrderResponses, err
|
||||
}
|
||||
|
||||
// OrderInfo returns information about a specific order
|
||||
func (a *ANX) OrderInfo(orderID string) (OrderResponse, error) {
|
||||
req := make(map[string]interface{})
|
||||
req["orderId"] = orderID
|
||||
|
||||
type OrderInfoResponse struct {
|
||||
Order OrderResponse `json:"order"`
|
||||
ResultCode string `json:"resultCode"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
var response OrderInfoResponse
|
||||
|
||||
err := a.SendAuthenticatedHTTPRequest(anxOrderInfo, req, &response)
|
||||
|
||||
if err != nil {
|
||||
return OrderResponse{}, err
|
||||
}
|
||||
|
||||
if response.ResultCode != "OK" {
|
||||
return OrderResponse{}, errors.New(response.ResultCode)
|
||||
}
|
||||
return response.Order, nil
|
||||
}
|
||||
|
||||
// Send withdraws a currency to an address
|
||||
func (a *ANX) Send(currency, address, otp, amount string) (string, error) {
|
||||
req := make(map[string]interface{})
|
||||
req["ccy"] = currency
|
||||
req["amount"] = amount
|
||||
req["address"] = address
|
||||
|
||||
if otp != "" {
|
||||
req["otp"] = otp
|
||||
}
|
||||
|
||||
type SendResponse struct {
|
||||
TransactionID string `json:"transactionId"`
|
||||
ResultCode string `json:"resultCode"`
|
||||
Timestamp int64 `json:"timestamp,string"`
|
||||
}
|
||||
var response SendResponse
|
||||
|
||||
err := a.SendAuthenticatedHTTPRequest(anxSend, req, &response)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if response.ResultCode != "OK" {
|
||||
return "", errors.New(response.ResultCode)
|
||||
}
|
||||
return response.TransactionID, nil
|
||||
}
|
||||
|
||||
// CreateNewSubAccount generates a new sub account
|
||||
func (a *ANX) CreateNewSubAccount(currency, name string) (string, error) {
|
||||
req := make(map[string]interface{})
|
||||
req["ccy"] = currency
|
||||
req["customRef"] = name
|
||||
|
||||
type SubaccountResponse struct {
|
||||
SubAccount string `json:"subAccount"`
|
||||
ResultCode string `json:"resultCode"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
var response SubaccountResponse
|
||||
|
||||
err := a.SendAuthenticatedHTTPRequest(anxSubaccountNew, req, &response)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if response.ResultCode != "OK" {
|
||||
return "", errors.New(response.ResultCode)
|
||||
}
|
||||
return response.SubAccount, nil
|
||||
}
|
||||
|
||||
// GetDepositAddressByCurrency returns a deposit address for a specific currency
|
||||
func (a *ANX) GetDepositAddressByCurrency(currency, name string, newAddr bool) (string, error) {
|
||||
req := make(map[string]interface{})
|
||||
req["ccy"] = currency
|
||||
|
||||
if name != "" {
|
||||
req["subAccount"] = name
|
||||
}
|
||||
|
||||
type AddressResponse struct {
|
||||
Address string `json:"address"`
|
||||
SubAccount string `json:"subAccount"`
|
||||
ResultCode string `json:"resultCode"`
|
||||
Timestamp int64 `json:"timestamp,string"`
|
||||
}
|
||||
var response AddressResponse
|
||||
|
||||
path := anxReceieveAddress
|
||||
if newAddr {
|
||||
path = anxCreateAddress
|
||||
}
|
||||
|
||||
err := a.SendAuthenticatedHTTPRequest(path, req, &response)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if response.ResultCode != "OK" {
|
||||
return "", errors.New(response.ResultCode)
|
||||
}
|
||||
|
||||
return response.Address, nil
|
||||
}
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (a *ANX) SendHTTPRequest(path string, result interface{}) error {
|
||||
return a.SendPayload(http.MethodGet,
|
||||
path,
|
||||
nil,
|
||||
nil,
|
||||
result,
|
||||
false,
|
||||
false,
|
||||
a.Verbose,
|
||||
a.HTTPDebugging,
|
||||
a.HTTPRecording)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends a authenticated HTTP request
|
||||
func (a *ANX) SendAuthenticatedHTTPRequest(path string, params map[string]interface{}, result interface{}) error {
|
||||
if !a.AllowAuthenticatedRequest() {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, a.Name)
|
||||
}
|
||||
|
||||
n := a.Requester.GetNonce(true)
|
||||
req := make(map[string]interface{})
|
||||
req["nonce"] = n.String()[0:13]
|
||||
path = fmt.Sprintf("api/%s/%s", anxAPIVersion, path)
|
||||
|
||||
for key, value := range params {
|
||||
req[key] = value
|
||||
}
|
||||
|
||||
PayloadJSON, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return errors.New("unable to JSON request")
|
||||
}
|
||||
|
||||
if a.Verbose {
|
||||
log.Debugf(log.ExchangeSys, "Request JSON: %s\n", PayloadJSON)
|
||||
}
|
||||
|
||||
hmac := crypto.GetHMAC(crypto.HashSHA512, []byte(path+string("\x00")+string(PayloadJSON)), []byte(a.API.Credentials.Secret))
|
||||
headers := make(map[string]string)
|
||||
headers["Rest-Key"] = a.API.Credentials.Key
|
||||
headers["Rest-Sign"] = crypto.Base64Encode(hmac)
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
return a.SendPayload(http.MethodPost,
|
||||
a.API.Endpoints.URL+path,
|
||||
headers,
|
||||
bytes.NewBuffer(PayloadJSON),
|
||||
result,
|
||||
true,
|
||||
true,
|
||||
a.Verbose,
|
||||
a.HTTPDebugging,
|
||||
a.HTTPRecording)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
func (a *ANX) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
var fee float64
|
||||
|
||||
switch feeBuilder.FeeType {
|
||||
case exchange.CryptocurrencyTradeFee:
|
||||
fee = a.calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount, feeBuilder.IsMaker)
|
||||
case exchange.CryptocurrencyWithdrawalFee:
|
||||
fee = getCryptocurrencyWithdrawalFee(feeBuilder.Pair.Base)
|
||||
case exchange.InternationalBankWithdrawalFee:
|
||||
fee = getInternationalBankWithdrawalFee(feeBuilder.FiatCurrency, feeBuilder.Amount)
|
||||
case exchange.OfflineTradeFee:
|
||||
fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount)
|
||||
}
|
||||
if fee < 0 {
|
||||
fee = 0
|
||||
}
|
||||
return fee, nil
|
||||
}
|
||||
|
||||
// getOfflineTradeFee calculates the worst case-scenario trading fee
|
||||
func getOfflineTradeFee(price, amount float64) float64 {
|
||||
return 0.002 * price * amount
|
||||
}
|
||||
|
||||
func (a *ANX) calculateTradingFee(purchasePrice, amount float64, isMaker bool) float64 {
|
||||
var fee float64
|
||||
|
||||
if isMaker {
|
||||
fee = 0.01 * amount * purchasePrice
|
||||
} else {
|
||||
fee = 0.02 * amount * purchasePrice
|
||||
}
|
||||
|
||||
return fee
|
||||
}
|
||||
|
||||
func getCryptocurrencyWithdrawalFee(c currency.Code) float64 {
|
||||
return WithdrawalFees[c]
|
||||
}
|
||||
|
||||
func getInternationalBankWithdrawalFee(c currency.Code, amount float64) float64 {
|
||||
var fee float64
|
||||
|
||||
if c == currency.HKD {
|
||||
fee = 250 + (WithdrawalFees[c] * amount)
|
||||
}
|
||||
// TODO, other fiat currencies require consultation with ANXPRO
|
||||
return fee
|
||||
}
|
||||
|
||||
// GetAccountInformation retrieves details including API permissions
|
||||
func (a *ANX) GetAccountInformation() (AccountInformation, error) {
|
||||
var response AccountInformation
|
||||
err := a.SendAuthenticatedHTTPRequest(anxAccount, nil, &response)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
if response.ResultCode != "OK" {
|
||||
log.Errorf(log.ExchangeSys, "Response code is not OK: %s\n", response.ResultCode)
|
||||
return response, errors.New(response.ResultCode)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// CheckAPIWithdrawPermission checks if the API key is allowed to withdraw
|
||||
func (a *ANX) CheckAPIWithdrawPermission() (bool, error) {
|
||||
accountInfo, err := a.GetAccountInformation()
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var apiAllowsWithdraw bool
|
||||
|
||||
for _, a := range accountInfo.Rights {
|
||||
if a == "withdraw" {
|
||||
apiAllowsWithdraw = true
|
||||
}
|
||||
}
|
||||
|
||||
if !apiAllowsWithdraw {
|
||||
log.Warn(log.ExchangeSys, "API key is missing withdrawal permissions")
|
||||
}
|
||||
|
||||
return apiAllowsWithdraw, nil
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
//+build mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is parsed and will do live testing
|
||||
// using all tests in (exchange)_test.go
|
||||
package anx
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
var mockTests = false
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
err := cfg.LoadConfig("../../testdata/configtest.json", true)
|
||||
if err != nil {
|
||||
log.Fatalf("ANX Setup() load config error: %s", err)
|
||||
}
|
||||
anxConfig, err := cfg.GetExchangeConfig("ANX")
|
||||
if err != nil {
|
||||
log.Fatalf("ANX Setup() init error: %s", err)
|
||||
}
|
||||
anxConfig.API.AuthenticatedSupport = true
|
||||
anxConfig.API.Credentials.Key = apiKey
|
||||
anxConfig.API.Credentials.Secret = apiSecret
|
||||
a.SetDefaults()
|
||||
err = a.Setup(anxConfig)
|
||||
if err != nil {
|
||||
log.Fatal("ANX setup error", err)
|
||||
}
|
||||
log.Printf(sharedtestvalues.LiveTesting, a.Name, a.API.Endpoints.URL)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
//+build !mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is not parsed and will try to mock
|
||||
// all tests in _test.go
|
||||
package anx
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/mock"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
)
|
||||
|
||||
const mockFile = "../../testdata/http_mock/anx/anx.json"
|
||||
|
||||
var mockTests = true
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cfg := config.GetConfig()
|
||||
err := cfg.LoadConfig("../../testdata/configtest.json", true)
|
||||
if err != nil {
|
||||
log.Fatal("ANX load config error", err)
|
||||
}
|
||||
anxConfig, err := cfg.GetExchangeConfig("ANX")
|
||||
if err != nil {
|
||||
log.Fatal("Mock server error", err)
|
||||
}
|
||||
a.SkipAuthCheck = true
|
||||
anxConfig.API.AuthenticatedSupport = true
|
||||
anxConfig.API.Credentials.Key = apiKey
|
||||
anxConfig.API.Credentials.Secret = apiSecret
|
||||
a.SetDefaults()
|
||||
err = a.Setup(anxConfig)
|
||||
if err != nil {
|
||||
log.Fatal("ANX setup error", err)
|
||||
}
|
||||
|
||||
serverDetails, newClient, err := mock.NewVCRServer(mockFile)
|
||||
if err != nil {
|
||||
log.Fatalf("Mock server error %s", err)
|
||||
}
|
||||
|
||||
a.HTTPClient = newClient
|
||||
a.API.Endpoints.URL = serverDetails + "/"
|
||||
|
||||
log.Printf(sharedtestvalues.MockTesting, a.Name, a.API.Endpoints.URL)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
@@ -1,391 +0,0 @@
|
||||
package anx
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/withdraw"
|
||||
)
|
||||
|
||||
// Please supply your own keys here for due diligence testing
|
||||
const (
|
||||
apiKey = ""
|
||||
apiSecret = ""
|
||||
canManipulateRealOrders = false
|
||||
)
|
||||
|
||||
var a ANX
|
||||
|
||||
func TestGetCurrencies(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := a.GetCurrencies()
|
||||
if err != nil {
|
||||
t.Fatalf("TestGetCurrencies failed. Err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTradablePairs(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := a.FetchTradablePairs(asset.Spot)
|
||||
if err != nil {
|
||||
t.Fatalf("TestGetTradablePairs failed. Err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
ticker, err := a.GetTicker("BTCUSD")
|
||||
if err != nil {
|
||||
t.Errorf("ANX GetTicker() error: %s", err)
|
||||
}
|
||||
if ticker.Result != "success" {
|
||||
t.Error("ANX GetTicker() unsuccessful")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDepth(t *testing.T) {
|
||||
t.Parallel()
|
||||
depth, err := a.GetDepth("BTCUSD")
|
||||
if err != nil {
|
||||
t.Errorf("ANX GetDepth() error: %s", err)
|
||||
}
|
||||
if depth.Result != "success" {
|
||||
t.Error("ANX GetDepth() unsuccessful")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAPIKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
apiKey, apiSecret, err := a.GetAPIKey("userName", "passWord", "", "1337")
|
||||
if err == nil {
|
||||
t.Error("ANX GetAPIKey() Expected error")
|
||||
}
|
||||
if apiKey != "" {
|
||||
t.Error("ANX GetAPIKey() Expected error")
|
||||
}
|
||||
if apiSecret != "" {
|
||||
t.Error("ANX GetAPIKey() Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func setFeeBuilder() *exchange.FeeBuilder {
|
||||
return &exchange.FeeBuilder{
|
||||
Amount: 1,
|
||||
FeeType: exchange.CryptocurrencyTradeFee,
|
||||
Pair: currency.NewPair(currency.BTC, currency.LTC),
|
||||
IsMaker: false,
|
||||
PurchasePrice: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetFeeByTypeOfflineTradeFee logic test
|
||||
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
var feeBuilder = setFeeBuilder()
|
||||
a.GetFeeByType(feeBuilder)
|
||||
if !areTestAPIKeysSet() {
|
||||
if feeBuilder.FeeType != exchange.OfflineTradeFee {
|
||||
t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType)
|
||||
}
|
||||
} else {
|
||||
if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee {
|
||||
t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
var feeBuilder = setFeeBuilder()
|
||||
|
||||
// CryptocurrencyTradeFee Basic
|
||||
if resp, err := a.GetFee(feeBuilder); resp != float64(0.02) || err != nil {
|
||||
t.Error(err)
|
||||
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee High quantity
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.Amount = 1000
|
||||
feeBuilder.PurchasePrice = 1000
|
||||
if resp, err := a.GetFee(feeBuilder); resp != float64(20000) || err != nil {
|
||||
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(20000), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee IsMaker
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.IsMaker = true
|
||||
if resp, err := a.GetFee(feeBuilder); resp != float64(0.01) || err != nil {
|
||||
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0.01), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee Negative purchase price
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.PurchasePrice = -1000
|
||||
if resp, err := a.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CryptocurrencyWithdrawalFee Basic
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
|
||||
if resp, err := a.GetFee(feeBuilder); resp != float64(0.002) || err != nil {
|
||||
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CyptocurrencyDepositFee Basic
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.CyptocurrencyDepositFee
|
||||
if resp, err := a.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// InternationalBankDepositFee Basic
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.InternationalBankDepositFee
|
||||
feeBuilder.FiatCurrency = currency.HKD
|
||||
if resp, err := a.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// InternationalBankWithdrawalFee Basic
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
|
||||
feeBuilder.FiatCurrency = currency.HKD
|
||||
if resp, err := a.GetFee(feeBuilder); resp != float64(250.01) || err != nil {
|
||||
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(250.01), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatWithdrawPermissions(t *testing.T) {
|
||||
t.Parallel()
|
||||
expectedResult := exchange.AutoWithdrawCryptoWithSetupText + " & " + exchange.WithdrawCryptoWith2FAText + " & " +
|
||||
exchange.WithdrawCryptoWithEmailText + " & " + exchange.WithdrawFiatViaWebsiteOnlyText
|
||||
withdrawPermissions := a.FormatWithdrawPermissions()
|
||||
if withdrawPermissions != expectedResult {
|
||||
t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetActiveOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
var getOrdersRequest = order.GetOrdersRequest{
|
||||
OrderType: order.AnyType,
|
||||
}
|
||||
|
||||
_, err := a.GetActiveOrders(&getOrdersRequest)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
var getOrdersRequest = order.GetOrdersRequest{
|
||||
OrderType: order.AnyType,
|
||||
}
|
||||
|
||||
_, err := a.GetOrderHistory(&getOrdersRequest)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not get order history: %s", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Error("GetBalance() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
func areTestAPIKeysSet() bool {
|
||||
return a.ValidateAPICredentials()
|
||||
}
|
||||
|
||||
func TestSubmitOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
var orderSubmission = &order.Submit{
|
||||
Pair: currency.Pair{
|
||||
Delimiter: "_",
|
||||
Base: currency.BTC,
|
||||
Quote: currency.USD,
|
||||
},
|
||||
OrderSide: order.Buy,
|
||||
OrderType: order.Limit,
|
||||
Price: 1,
|
||||
Amount: 1,
|
||||
ClientID: "meowOrder",
|
||||
}
|
||||
response, err := a.SubmitOrder(orderSubmission)
|
||||
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) && !mockTests {
|
||||
// TODO: QA Pass to submit order
|
||||
t.Errorf("Order failed to be placed: %v", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelExchangeOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
currencyPair := currency.NewPair(currency.BTC, currency.LTC)
|
||||
var orderCancellation = &order.Cancel{
|
||||
OrderID: "1",
|
||||
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
AccountID: "1",
|
||||
CurrencyPair: currencyPair,
|
||||
}
|
||||
|
||||
err := a.CancelOrder(orderCancellation)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not cancel order: %s", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
t.Errorf("Could not cancel order: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
currencyPair := currency.NewPair(currency.BTC, currency.LTC)
|
||||
var orderCancellation = &order.Cancel{
|
||||
OrderID: "1",
|
||||
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
AccountID: "1",
|
||||
CurrencyPair: currencyPair,
|
||||
}
|
||||
|
||||
resp, err := a.CancelAllOrders(orderCancellation)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Errorf("Could not cancel order: %s", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
case mockTests && err == nil:
|
||||
t.Errorf("QA pass needs to be completed and mock needs to be updated error cannot be nil")
|
||||
}
|
||||
|
||||
if len(resp.Status) > 0 {
|
||||
t.Errorf("%v orders failed to cancel", len(resp.Status))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccountInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := a.GetAccountInfo()
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil && !mockTests:
|
||||
t.Error("GetAccountInfo() error:", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("GetAccountInfo() error")
|
||||
case mockTests && err != nil:
|
||||
t.Error("GetAccountInfo() error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestModifyOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := a.ModifyOrder(&order.Modify{})
|
||||
if err == nil {
|
||||
t.Error("ModifyOrder() Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
withdrawCryptoRequest := withdraw.CryptoRequest{
|
||||
GenericInfo: withdraw.GenericInfo{
|
||||
Amount: -1,
|
||||
Currency: currency.BTC,
|
||||
Description: "WITHDRAW IT ALL",
|
||||
},
|
||||
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
AddressTag: "0123456789",
|
||||
}
|
||||
|
||||
_, err := a.WithdrawCryptocurrencyFunds(&withdrawCryptoRequest)
|
||||
if areTestAPIKeysSet() && err != nil && !mockTests {
|
||||
t.Errorf("Withdraw failed to be placed: %v", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil && mockTests {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawFiat(t *testing.T) {
|
||||
t.Parallel()
|
||||
var withdrawFiatRequest = withdraw.FiatRequest{}
|
||||
_, err := a.WithdrawFiatFunds(&withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'",
|
||||
common.ErrFunctionNotSupported,
|
||||
err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawInternationalBank(t *testing.T) {
|
||||
t.Parallel()
|
||||
var withdrawFiatRequest = withdraw.FiatRequest{}
|
||||
_, err := a.WithdrawFiatFundsToInternationalBank(&withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'",
|
||||
common.ErrFunctionNotSupported,
|
||||
err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDepositAddress(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := a.GetDepositAddress(currency.BTC, "")
|
||||
if areTestAPIKeysSet() && err != nil && !mockTests {
|
||||
t.Error("GetDepositAddress() error", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("GetDepositAddress() error cannot be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := currency.Pair{
|
||||
Delimiter: "_",
|
||||
Base: currency.BTC,
|
||||
Quote: currency.USD}
|
||||
|
||||
_, err := a.UpdateOrderbook(q, "spot")
|
||||
if err == nil {
|
||||
t.Fatalf("error cannot be nil as the endpoint returns no orderbook information")
|
||||
}
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
package anx
|
||||
|
||||
import "github.com/thrasher-corp/gocryptotrader/currency"
|
||||
|
||||
// List of strings
|
||||
const (
|
||||
CancelOrderNotFound string = "ORDER_NOT_FOUND"
|
||||
CancelRequestSubmitted string = "CANCEL_REQUEST_SUBMITTED"
|
||||
CancelOrderWrongState string = "ORDER_CANCEL_WRONG_STATE"
|
||||
)
|
||||
|
||||
// CurrencyData holds the currency information
|
||||
type CurrencyData struct {
|
||||
Decimals int `json:"decimals"`
|
||||
MinOrderSize float64 `json:"minOrderSize"`
|
||||
MaxOrderSize float64 `json:"maxOrderSize"`
|
||||
DisplayDenominator float64 `json:"displayDenominator"`
|
||||
SummaryDecimals int `json:"summaryDecimals"`
|
||||
DisplayUnit string `json:"displayUnit"`
|
||||
Symbol string `json:"symbol"`
|
||||
Type string `json:"type"`
|
||||
ConfirmationThresholds []struct {
|
||||
ConfosRequired int `json:"confosRequired"`
|
||||
} `json:"confirmationThresholds"`
|
||||
NetworkFee float64 `json:"networkFee"`
|
||||
EngineSettings struct {
|
||||
DepositsEnabled bool `json:"depositsEnabled"`
|
||||
WithdrawalsEnabled bool `json:"withdrawalsEnabled"`
|
||||
DisplayEnabled bool `json:"displayEnabled"`
|
||||
MobileAccessEnabled bool `json:"mobileAccessEnabled"`
|
||||
} `json:"engineSettings"`
|
||||
MinOrderValue float64 `json:"minOrderValue"`
|
||||
MaxOrderValue float64 `json:"maxOrderValue"`
|
||||
MaxMarketOrderValue float64 `json:"maxMarketOrderValue"`
|
||||
MaxMarketOrderSize float64 `json:"maxMarketOrderSize"`
|
||||
DigitalCurrencyType string `json:"digitalCurrencyType"`
|
||||
AssetName string `json:"assetName"`
|
||||
AssetDivisibility int `json:"assetDivisibility"`
|
||||
AssetIcon string `json:"assetIcon"`
|
||||
AssetIssueQuantity string `json:"assetIssueQuantity"`
|
||||
}
|
||||
|
||||
// Currencies stores a list of currencies
|
||||
type Currencies map[string]CurrencyData
|
||||
|
||||
// CurrencyPairData holds the currency information
|
||||
type CurrencyPairData struct {
|
||||
PriceDecimals int `json:"priceDecimals"`
|
||||
EngineSettings struct {
|
||||
TradingEnabled bool `json:"tradingEnabled"`
|
||||
DisplayEnabled bool `json:"displayEnabled"`
|
||||
CancelOnly bool `json:"cancelOnly"`
|
||||
VerifyRequired bool `json:"verifyRequired"`
|
||||
RestrictedBuy bool `json:"restrictedBuy"`
|
||||
RestrictedSell bool `json:"restrictedSell"`
|
||||
} `json:"engineSettings"`
|
||||
MinOrderRate float64 `json:"minOrderRate"`
|
||||
MaxOrderRate float64 `json:"maxOrderRate"`
|
||||
DisplayPriceDecimals int `json:"displayPriceDecimals"`
|
||||
TradedCcy string `json:"tradedCcy"`
|
||||
SettlementCcy string `json:"settlementCcy"`
|
||||
PreferredMarket string `json:"preferredMarket"`
|
||||
ChartEnabled bool `json:"chartEnabled"`
|
||||
SimpleTradeEnabled bool `json:"simpleTradeEnabled"`
|
||||
}
|
||||
|
||||
// AccountInformation Used by Get account information
|
||||
// Retrieves details of the account and api's
|
||||
type AccountInformation struct {
|
||||
UserUUID string `json:"userUuid"`
|
||||
Rights []string `json:"Rights"`
|
||||
ResultCode string `json:"resultCode"`
|
||||
Wallets map[string]struct {
|
||||
Balance Amount `json:"Balance"`
|
||||
AvailableBalance Amount `json:"Available_Balance"`
|
||||
DailyWithdrawalLimit Amount `json:"Daily_Withdrawal_Limit"`
|
||||
MaxWithdraw Amount `json:"Max_Withdraw"`
|
||||
} `json:"Wallets"`
|
||||
}
|
||||
|
||||
// Amount basic storage of wallet details
|
||||
type Amount struct {
|
||||
DisplayShort string `json:"displayShort"`
|
||||
ValueInt int64 `json:"valueInt"`
|
||||
Currency string `json:"currency"`
|
||||
Display string `json:"display"`
|
||||
Value float64 `json:"value"`
|
||||
}
|
||||
|
||||
// CurrencyPairs stores currency pair info
|
||||
type CurrencyPairs map[string]CurrencyPairData
|
||||
|
||||
// CurrenciesStore stores the available cryptocurrencies
|
||||
// and fiat currencies
|
||||
type CurrenciesStore struct {
|
||||
Currencies Currencies `json:"currencies"`
|
||||
CurrencyPairs CurrencyPairs `json:"currencyPairs"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
ResultCode string `json:"resultCode"`
|
||||
}
|
||||
|
||||
// CurrenciesStaticResponse stores the currencyStatic response
|
||||
type CurrenciesStaticResponse struct {
|
||||
CurrenciesResponse CurrenciesStore `json:"CurrencyStatic"`
|
||||
}
|
||||
|
||||
// Order holds order information
|
||||
type Order struct {
|
||||
OrderType string `json:"orderType"`
|
||||
BuyTradedCurrency bool `json:"buyTradedCurrency"`
|
||||
TradedCurrency string `json:"tradedCurrency"`
|
||||
SettlementCurrency string `json:"settlementCurrency"`
|
||||
TradedCurrencyAmount float64 `json:"tradedCurrencyAmount,string"`
|
||||
SettlementCurrencyAmount float64 `json:"settlementCurrencyAmount,string"`
|
||||
LimitPriceInSettlementCurrency float64 `json:"limitPriceInSettlementCurrency,string"`
|
||||
ReplaceExistingOrderUUID string `json:"replaceExistingOrderUuid"`
|
||||
ReplaceOnlyIfActive bool `json:"replaceOnlyIfActive"`
|
||||
}
|
||||
|
||||
// OrderResponse holds order response data
|
||||
type OrderResponse struct {
|
||||
BuyTradedCurrency bool `json:"buyTradedCurrency"`
|
||||
ExecutedAverageRate string `json:"executedAverageRate"`
|
||||
LimitPriceInSettlementCurrency string `json:"limitPriceInSettlementCurrency"`
|
||||
OrderID string `json:"orderId"`
|
||||
OrderStatus string `json:"orderStatus"`
|
||||
OrderType string `json:"orderType"`
|
||||
ReplaceExistingOrderUUID string `json:"replaceExistingOrderId"`
|
||||
SettlementCurrency string `json:"settlementCurrency"`
|
||||
SettlementCurrencyAmount float64 `json:"settlementCurrencyAmount,string"`
|
||||
SettlementCurrencyOutstanding string `json:"settlementCurrencyOutstanding"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
TradedCurrency string `json:"tradedCurrency"`
|
||||
TradedCurrencyAmount float64 `json:"tradedCurrencyAmount,string"`
|
||||
TradedCurrencyOutstanding string `json:"tradedCurrencyOutstanding"`
|
||||
}
|
||||
|
||||
// OrderCancelResponse returned when cancelling multiple orders
|
||||
type OrderCancelResponse struct {
|
||||
OrderCancellationResponses []OrderCancellationResponse `json:"orderIds"`
|
||||
ResultCode string `json:"resultCode"`
|
||||
UUID int64 `json:"uuid"`
|
||||
ErrorCode int64 `json:"errorCode"`
|
||||
}
|
||||
|
||||
// OrderCancellationResponse contains the orderID and error when cancelling multiple orders
|
||||
type OrderCancellationResponse struct {
|
||||
UUID string `json:"uuid"`
|
||||
Error string `json:"errorCode"`
|
||||
}
|
||||
|
||||
// TickerComponent is a sub-type for ticker
|
||||
type TickerComponent struct {
|
||||
Currency string `json:"currency"`
|
||||
Display string `json:"display"`
|
||||
DisplayShort string `json:"display_short"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// Ticker contains ticker data
|
||||
type Ticker struct {
|
||||
Result string `json:"result"`
|
||||
Data struct {
|
||||
High TickerComponent `json:"high"`
|
||||
Low TickerComponent `json:"low"`
|
||||
Average TickerComponent `json:"avg"`
|
||||
VolumeWeightedAveragePrice TickerComponent `json:"vwap"`
|
||||
Volume TickerComponent `json:"vol"`
|
||||
Last TickerComponent `json:"last"`
|
||||
Buy TickerComponent `json:"buy"`
|
||||
Sell TickerComponent `json:"sell"`
|
||||
Now int64 `json:"now,string"`
|
||||
UpdateTime int64 `json:"dataUpdateTime,string"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// DepthItem contains depth information
|
||||
type DepthItem struct {
|
||||
Price float64 `json:"price,string"`
|
||||
PriceInt float64 `json:"price_int,string"`
|
||||
Amount float64 `json:"amount,string"`
|
||||
AmountInt int64 `json:"amount_int,string"`
|
||||
}
|
||||
|
||||
// Depth contains full depth information
|
||||
type Depth struct {
|
||||
Result string `json:"result"`
|
||||
Data struct {
|
||||
Now string `json:"now"`
|
||||
DataUpdateTime string `json:"dataUpdateTime"`
|
||||
Asks []DepthItem `json:"asks"`
|
||||
Bids []DepthItem `json:"bids"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// WithdrawalFees the large list of predefined withdrawal fees
|
||||
// Prone to change
|
||||
var WithdrawalFees = map[currency.Code]float64{
|
||||
currency.BTC: 0.002,
|
||||
currency.DOGE: 0.1,
|
||||
currency.ETH: 0.005,
|
||||
currency.GNT: 0.001,
|
||||
currency.LTC: 0.02,
|
||||
currency.OAX: 0.001,
|
||||
currency.XRP: 1,
|
||||
currency.HKD: 0.01,
|
||||
}
|
||||
@@ -1,545 +0,0 @@
|
||||
package anx
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/convert"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/protocol"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/withdraw"
|
||||
log "github.com/thrasher-corp/gocryptotrader/logger"
|
||||
)
|
||||
|
||||
// GetDefaultConfig returns a default exchange config for Alphapoint
|
||||
func (a *ANX) GetDefaultConfig() (*config.ExchangeConfig, error) {
|
||||
a.SetDefaults()
|
||||
exchCfg := new(config.ExchangeConfig)
|
||||
exchCfg.Name = a.Name
|
||||
exchCfg.HTTPTimeout = exchange.DefaultHTTPTimeout
|
||||
exchCfg.BaseCurrencies = a.BaseCurrencies
|
||||
|
||||
err := a.SetupDefaults(exchCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if a.Features.Supports.RESTCapabilities.AutoPairUpdates {
|
||||
err = a.UpdateTradablePairs(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return exchCfg, nil
|
||||
}
|
||||
|
||||
// SetDefaults sets current default settings
|
||||
func (a *ANX) SetDefaults() {
|
||||
a.Name = "ANX"
|
||||
a.Enabled = true
|
||||
a.Verbose = true
|
||||
a.BaseCurrencies = currency.Currencies{
|
||||
currency.USD,
|
||||
currency.HKD,
|
||||
currency.EUR,
|
||||
currency.CAD,
|
||||
currency.AUD,
|
||||
currency.SGD,
|
||||
currency.JPY,
|
||||
currency.GBP,
|
||||
currency.NZD,
|
||||
}
|
||||
a.API.CredentialsValidator.RequiresKey = true
|
||||
a.API.CredentialsValidator.RequiresSecret = true
|
||||
a.API.CredentialsValidator.RequiresBase64DecodeSecret = true
|
||||
|
||||
a.CurrencyPairs = currency.PairsManager{
|
||||
AssetTypes: asset.Items{
|
||||
asset.Spot,
|
||||
},
|
||||
UseGlobalFormat: true,
|
||||
RequestFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
},
|
||||
ConfigFormat: ¤cy.PairFormat{
|
||||
Delimiter: "_",
|
||||
Uppercase: true,
|
||||
},
|
||||
}
|
||||
|
||||
a.Features = exchange.Features{
|
||||
Supports: exchange.FeaturesSupported{
|
||||
REST: true,
|
||||
Websocket: false,
|
||||
RESTCapabilities: protocol.Features{
|
||||
TickerFetching: true,
|
||||
OrderbookFetching: true,
|
||||
AutoPairUpdates: true,
|
||||
AccountInfo: true,
|
||||
CryptoDeposit: true,
|
||||
CryptoWithdrawal: true,
|
||||
GetOrder: true,
|
||||
GetOrders: true,
|
||||
CancelOrders: true,
|
||||
CancelOrder: true,
|
||||
SubmitOrder: true,
|
||||
DepositHistory: true,
|
||||
WithdrawalHistory: true,
|
||||
UserTradeHistory: true,
|
||||
TradeFee: true,
|
||||
FiatWithdrawalFee: true,
|
||||
CryptoWithdrawalFee: true,
|
||||
},
|
||||
WithdrawPermissions: exchange.WithdrawCryptoWithEmail |
|
||||
exchange.AutoWithdrawCryptoWithSetup |
|
||||
exchange.WithdrawCryptoWith2FA |
|
||||
exchange.WithdrawFiatViaWebsiteOnly,
|
||||
},
|
||||
Enabled: exchange.FeaturesEnabled{
|
||||
AutoPairUpdates: false,
|
||||
},
|
||||
}
|
||||
|
||||
a.Requester = request.New(a.Name,
|
||||
request.NewRateLimit(time.Second, anxAuthRate),
|
||||
request.NewRateLimit(time.Second, anxUnauthRate),
|
||||
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout))
|
||||
|
||||
a.API.Endpoints.URLDefault = anxAPIURL
|
||||
a.API.Endpoints.URL = a.API.Endpoints.URLDefault
|
||||
}
|
||||
|
||||
// Setup is run on startup to setup exchange with config values
|
||||
func (a *ANX) Setup(exch *config.ExchangeConfig) error {
|
||||
if !exch.Enabled {
|
||||
a.SetEnabled(false)
|
||||
return nil
|
||||
}
|
||||
|
||||
return a.SetupDefaults(exch)
|
||||
}
|
||||
|
||||
// Start starts the ANX go routine
|
||||
func (a *ANX) Start(wg *sync.WaitGroup) {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
a.Run()
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
// Run implements the ANX wrapper
|
||||
func (a *ANX) Run() {
|
||||
if a.Verbose {
|
||||
a.PrintEnabledPairs()
|
||||
}
|
||||
|
||||
forceUpdate := false
|
||||
delim := a.GetPairFormat(asset.Spot, false).Delimiter
|
||||
if !common.StringDataContains(a.GetEnabledPairs(asset.Spot).Strings(), delim) ||
|
||||
!common.StringDataContains(a.GetAvailablePairs(asset.Spot).Strings(), delim) {
|
||||
enabledPairs := currency.NewPairsFromStrings(
|
||||
[]string{currency.BTC.String() + delim + currency.USD.String()},
|
||||
)
|
||||
log.Warn(log.ExchangeSys,
|
||||
"Enabled pairs for ANX reset due to config upgrade, please enable the ones you would like again.")
|
||||
forceUpdate = true
|
||||
err := a.UpdatePairs(enabledPairs, asset.Spot, true, true)
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys, "%s failed to update currencies.\n", a.Name)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !a.GetEnabledFeatures().AutoPairUpdates && !forceUpdate {
|
||||
return
|
||||
}
|
||||
|
||||
err := a.UpdateTradablePairs(forceUpdate)
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", a.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateTradablePairs updates the exchanges available pairs and stores
|
||||
// them in the exchanges config
|
||||
func (a *ANX) UpdateTradablePairs(forceUpdate bool) error {
|
||||
pairs, err := a.FetchTradablePairs(asset.Spot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return a.UpdatePairs(currency.NewPairsFromStrings(pairs), asset.Spot, false, forceUpdate)
|
||||
}
|
||||
|
||||
// FetchTradablePairs returns a list of the exchanges tradable pairs
|
||||
func (a *ANX) FetchTradablePairs(asset asset.Item) ([]string, error) {
|
||||
result, err := a.GetCurrencies()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var currencies []string
|
||||
for x := range result.CurrencyPairs {
|
||||
currencies = append(currencies, result.CurrencyPairs[x].TradedCcy+
|
||||
a.GetPairFormat(asset, false).Delimiter+
|
||||
result.CurrencyPairs[x].SettlementCcy)
|
||||
}
|
||||
|
||||
return currencies, nil
|
||||
}
|
||||
|
||||
// UpdateTicker updates and returns the ticker for a currency pair
|
||||
func (a *ANX) UpdateTicker(p currency.Pair, assetType asset.Item) (*ticker.Price, error) {
|
||||
tickerPrice := new(ticker.Price)
|
||||
tick, err := a.GetTicker(a.FormatExchangeCurrency(p, assetType).String())
|
||||
if err != nil {
|
||||
return tickerPrice, err
|
||||
}
|
||||
last, _ := convert.FloatFromString(tick.Data.Last.Value)
|
||||
high, _ := convert.FloatFromString(tick.Data.High.Value)
|
||||
low, _ := convert.FloatFromString(tick.Data.Low.Value)
|
||||
bid, _ := convert.FloatFromString(tick.Data.Buy.Value)
|
||||
ask, _ := convert.FloatFromString(tick.Data.Sell.Value)
|
||||
volume, _ := convert.FloatFromString(tick.Data.Volume.Value)
|
||||
|
||||
tickerPrice = &ticker.Price{
|
||||
Last: last,
|
||||
High: high,
|
||||
Low: low,
|
||||
Bid: bid,
|
||||
Ask: ask,
|
||||
Volume: volume,
|
||||
Pair: p,
|
||||
LastUpdated: time.Unix(0, tick.Data.UpdateTime),
|
||||
}
|
||||
|
||||
err = ticker.ProcessTicker(a.Name, tickerPrice, assetType)
|
||||
if err != nil {
|
||||
return tickerPrice, err
|
||||
}
|
||||
|
||||
return ticker.GetTicker(a.Name, p, assetType)
|
||||
}
|
||||
|
||||
// FetchTicker returns the ticker for a currency pair
|
||||
func (a *ANX) FetchTicker(p currency.Pair, assetType asset.Item) (*ticker.Price, error) {
|
||||
tickerNew, err := ticker.GetTicker(a.Name, p, assetType)
|
||||
if err != nil {
|
||||
return a.UpdateTicker(p, assetType)
|
||||
}
|
||||
return tickerNew, nil
|
||||
}
|
||||
|
||||
// FetchOrderbook returns the orderbook for a currency pair
|
||||
func (a *ANX) FetchOrderbook(p currency.Pair, assetType asset.Item) (*orderbook.Base, error) {
|
||||
ob, err := orderbook.Get(a.Name, p, assetType)
|
||||
if err != nil {
|
||||
return a.UpdateOrderbook(p, assetType)
|
||||
}
|
||||
return ob, nil
|
||||
}
|
||||
|
||||
// UpdateOrderbook updates and returns the orderbook for a currency pair
|
||||
func (a *ANX) UpdateOrderbook(p currency.Pair, assetType asset.Item) (*orderbook.Base, error) {
|
||||
orderBook := new(orderbook.Base)
|
||||
orderbookNew, err := a.GetDepth(a.FormatExchangeCurrency(p, assetType).String())
|
||||
if err != nil {
|
||||
return orderBook, err
|
||||
}
|
||||
|
||||
for x := range orderbookNew.Data.Asks {
|
||||
orderBook.Asks = append(orderBook.Asks,
|
||||
orderbook.Item{
|
||||
Price: orderbookNew.Data.Asks[x].Price,
|
||||
Amount: orderbookNew.Data.Asks[x].Amount})
|
||||
}
|
||||
|
||||
for x := range orderbookNew.Data.Bids {
|
||||
orderBook.Bids = append(orderBook.Bids,
|
||||
orderbook.Item{
|
||||
Price: orderbookNew.Data.Bids[x].Price,
|
||||
Amount: orderbookNew.Data.Bids[x].Amount})
|
||||
}
|
||||
|
||||
orderBook.Pair = p
|
||||
orderBook.ExchangeName = a.Name
|
||||
orderBook.AssetType = assetType
|
||||
err = orderBook.Process()
|
||||
if err != nil {
|
||||
return orderBook, err
|
||||
}
|
||||
|
||||
return orderbook.Get(a.Name, p, assetType)
|
||||
}
|
||||
|
||||
// GetAccountInfo retrieves balances for all enabled currencies on the
|
||||
// exchange
|
||||
func (a *ANX) GetAccountInfo() (exchange.AccountInfo, error) {
|
||||
var info exchange.AccountInfo
|
||||
|
||||
raw, err := a.GetAccountInformation()
|
||||
if err != nil {
|
||||
return info, err
|
||||
}
|
||||
|
||||
var balance []exchange.AccountCurrencyInfo
|
||||
for c := range raw.Wallets {
|
||||
balance = append(balance, exchange.AccountCurrencyInfo{
|
||||
CurrencyName: currency.NewCode(c),
|
||||
TotalValue: raw.Wallets[c].AvailableBalance.Value,
|
||||
Hold: raw.Wallets[c].Balance.Value,
|
||||
})
|
||||
}
|
||||
|
||||
info.Exchange = a.Name
|
||||
info.Accounts = append(info.Accounts, exchange.Account{
|
||||
Currencies: balance,
|
||||
})
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// GetFundingHistory returns funding history, deposits and
|
||||
// withdrawals
|
||||
func (a *ANX) GetFundingHistory() ([]exchange.FundHistory, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetExchangeHistory returns historic trade data since exchange opening.
|
||||
func (a *ANX) GetExchangeHistory(p currency.Pair, assetType asset.Item) ([]exchange.TradeHistory, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (a *ANX) SubmitOrder(s *order.Submit) (order.SubmitResponse, error) {
|
||||
var submitOrderResponse order.SubmitResponse
|
||||
if err := s.Validate(); err != nil {
|
||||
return submitOrderResponse, err
|
||||
}
|
||||
|
||||
var isBuying bool
|
||||
var limitPriceInSettlementCurrency float64
|
||||
|
||||
if s.OrderSide == order.Buy {
|
||||
isBuying = true
|
||||
}
|
||||
|
||||
if s.OrderType == order.Limit {
|
||||
limitPriceInSettlementCurrency = s.Price
|
||||
}
|
||||
|
||||
response, err := a.NewOrder(s.OrderType.String(),
|
||||
isBuying,
|
||||
s.Pair.Base.String(),
|
||||
s.Amount,
|
||||
s.Pair.Quote.String(),
|
||||
s.Amount,
|
||||
limitPriceInSettlementCurrency,
|
||||
false,
|
||||
"",
|
||||
false)
|
||||
if err != nil {
|
||||
return submitOrderResponse, err
|
||||
}
|
||||
if response != "" {
|
||||
submitOrderResponse.OrderID = response
|
||||
}
|
||||
if s.OrderType == order.Market {
|
||||
submitOrderResponse.FullyMatched = true
|
||||
}
|
||||
submitOrderResponse.IsOrderPlaced = true
|
||||
|
||||
return submitOrderResponse, nil
|
||||
}
|
||||
|
||||
// ModifyOrder will allow of changing orderbook placement and limit to
|
||||
// market conversion
|
||||
func (a *ANX) ModifyOrder(action *order.Modify) (string, error) {
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// CancelOrder cancels an order by its corresponding ID number
|
||||
func (a *ANX) CancelOrder(order *order.Cancel) error {
|
||||
orderIDs := []string{order.OrderID}
|
||||
_, err := a.CancelOrderByIDs(orderIDs)
|
||||
return err
|
||||
}
|
||||
|
||||
// CancelAllOrders cancels all orders associated with a currency pair
|
||||
func (a *ANX) CancelAllOrders(_ *order.Cancel) (order.CancelAllResponse, error) {
|
||||
cancelAllOrdersResponse := order.CancelAllResponse{
|
||||
Status: make(map[string]string),
|
||||
}
|
||||
placedOrders, err := a.GetOrderList(true)
|
||||
if err != nil {
|
||||
return cancelAllOrdersResponse, err
|
||||
}
|
||||
|
||||
var orderIDs []string
|
||||
for i := range placedOrders {
|
||||
orderIDs = append(orderIDs, placedOrders[i].OrderID)
|
||||
}
|
||||
|
||||
resp, err := a.CancelOrderByIDs(orderIDs)
|
||||
if err != nil {
|
||||
return cancelAllOrdersResponse, err
|
||||
}
|
||||
|
||||
for i := range resp.OrderCancellationResponses {
|
||||
if resp.OrderCancellationResponses[i].Error != CancelRequestSubmitted {
|
||||
cancelAllOrdersResponse.Status[resp.OrderCancellationResponses[i].UUID] = resp.OrderCancellationResponses[i].Error
|
||||
}
|
||||
}
|
||||
|
||||
return cancelAllOrdersResponse, err
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (a *ANX) GetOrderInfo(orderID string) (order.Detail, error) {
|
||||
var orderDetail order.Detail
|
||||
return orderDetail, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetDepositAddress returns a deposit address for a specified currency
|
||||
func (a *ANX) GetDepositAddress(cryptocurrency currency.Code, _ string) (string, error) {
|
||||
return a.GetDepositAddressByCurrency(cryptocurrency.String(), "", false)
|
||||
}
|
||||
|
||||
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func (a *ANX) WithdrawCryptocurrencyFunds(withdrawRequest *withdraw.CryptoRequest) (string, error) {
|
||||
return a.Send(withdrawRequest.Currency.String(), withdrawRequest.Address, "", strconv.FormatFloat(withdrawRequest.Amount, 'f', -1, 64))
|
||||
}
|
||||
|
||||
// WithdrawFiatFunds returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func (a *ANX) WithdrawFiatFunds(withdrawRequest *withdraw.FiatRequest) (string, error) {
|
||||
// Fiat withdrawals available via website
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func (a *ANX) WithdrawFiatFundsToInternationalBank(withdrawRequest *withdraw.FiatRequest) (string, error) {
|
||||
// Fiat withdrawals available via website
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetWebsocket returns a pointer to the exchange websocket
|
||||
func (a *ANX) GetWebsocket() (*wshandler.Websocket, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetFeeByType returns an estimate of fee based on type of transaction
|
||||
func (a *ANX) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
if (!a.AllowAuthenticatedRequest() || a.SkipAuthCheck) && // Todo check connection status
|
||||
feeBuilder.FeeType == exchange.CryptocurrencyTradeFee {
|
||||
feeBuilder.FeeType = exchange.OfflineTradeFee
|
||||
}
|
||||
return a.GetFee(feeBuilder)
|
||||
}
|
||||
|
||||
// GetActiveOrders retrieves any orders that are active/open
|
||||
func (a *ANX) GetActiveOrders(getOrdersRequest *order.GetOrdersRequest) ([]order.Detail, error) {
|
||||
resp, err := a.GetOrderList(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var orders []order.Detail
|
||||
for i := range resp {
|
||||
orderDate := time.Unix(resp[i].Timestamp, 0)
|
||||
orderType := order.Type(strings.ToUpper(resp[i].OrderType))
|
||||
|
||||
orderDetail := order.Detail{
|
||||
Amount: resp[i].TradedCurrencyAmount,
|
||||
CurrencyPair: currency.NewPairWithDelimiter(resp[i].TradedCurrency,
|
||||
resp[i].SettlementCurrency,
|
||||
a.GetPairFormat(asset.Spot, false).Delimiter),
|
||||
OrderDate: orderDate,
|
||||
Exchange: a.Name,
|
||||
ID: resp[i].OrderID,
|
||||
OrderType: orderType,
|
||||
Price: resp[i].SettlementCurrencyAmount,
|
||||
Status: order.Status(resp[i].OrderStatus),
|
||||
}
|
||||
|
||||
orders = append(orders, orderDetail)
|
||||
}
|
||||
|
||||
order.FilterOrdersByType(&orders, getOrdersRequest.OrderType)
|
||||
order.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks,
|
||||
getOrdersRequest.EndTicks)
|
||||
order.FilterOrdersByCurrencies(&orders, getOrdersRequest.Currencies)
|
||||
return orders, nil
|
||||
}
|
||||
|
||||
// GetOrderHistory retrieves account order information
|
||||
// Can Limit response to specific order status
|
||||
func (a *ANX) GetOrderHistory(req *order.GetOrdersRequest) ([]order.Detail, error) {
|
||||
resp, err := a.GetOrderList(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var orders []order.Detail
|
||||
for i := range resp {
|
||||
orderDate := time.Unix(resp[i].Timestamp, 0)
|
||||
orderType := order.Type(strings.ToUpper(resp[i].OrderType))
|
||||
|
||||
orderDetail := order.Detail{
|
||||
Amount: resp[i].TradedCurrencyAmount,
|
||||
OrderDate: orderDate,
|
||||
Exchange: a.Name,
|
||||
ID: resp[i].OrderID,
|
||||
OrderType: orderType,
|
||||
Price: resp[i].SettlementCurrencyAmount,
|
||||
Status: order.Status(resp[i].OrderStatus),
|
||||
CurrencyPair: currency.NewPairWithDelimiter(resp[i].TradedCurrency,
|
||||
resp[i].SettlementCurrency,
|
||||
a.GetPairFormat(asset.Spot, false).Delimiter),
|
||||
}
|
||||
|
||||
orders = append(orders, orderDetail)
|
||||
}
|
||||
|
||||
order.FilterOrdersByType(&orders, req.OrderType)
|
||||
order.FilterOrdersByTickRange(&orders, req.StartTicks, req.EndTicks)
|
||||
order.FilterOrdersByCurrencies(&orders, req.Currencies)
|
||||
return orders, nil
|
||||
}
|
||||
|
||||
// SubscribeToWebsocketChannels appends to ChannelsToSubscribe
|
||||
// which lets websocket.manageSubscriptions handle subscribing
|
||||
func (a *ANX) SubscribeToWebsocketChannels(channels []wshandler.WebsocketChannelSubscription) error {
|
||||
return common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// UnsubscribeToWebsocketChannels removes from ChannelsToSubscribe
|
||||
// which lets websocket.manageSubscriptions handle unsubscribing
|
||||
func (a *ANX) UnsubscribeToWebsocketChannels(channels []wshandler.WebsocketChannelSubscription) error {
|
||||
return common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetSubscriptions returns a copied list of subscriptions
|
||||
func (a *ANX) GetSubscriptions() ([]wshandler.WebsocketChannelSubscription, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// AuthenticateWebsocket sends an authentication message to the websocket
|
||||
func (a *ANX) AuthenticateWebsocket() error {
|
||||
return common.ErrFunctionNotSupported
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTestExchange = "ANX"
|
||||
defaultTestExchange = "Bitfinex"
|
||||
defaultTestCurrencyPair = "BTC-USD"
|
||||
)
|
||||
|
||||
@@ -1175,13 +1175,13 @@ func TestUpdatePairs(t *testing.T) {
|
||||
t.Fatal("TestUpdatePairs failed to load config")
|
||||
}
|
||||
|
||||
anxCfg, err := cfg.GetExchangeConfig(defaultTestExchange)
|
||||
exchCfg, err := cfg.GetExchangeConfig(defaultTestExchange)
|
||||
if err != nil {
|
||||
t.Fatal("TestUpdatePairs failed to load config")
|
||||
}
|
||||
|
||||
UAC := Base{Name: defaultTestExchange}
|
||||
UAC.Config = anxCfg
|
||||
UAC.Config = exchCfg
|
||||
exchangeProducts := currency.NewPairsFromStrings([]string{"ltc", "btc", "usd", "aud", ""})
|
||||
err = UAC.UpdatePairs(exchangeProducts, asset.Spot, true, false)
|
||||
if err != nil {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
)
|
||||
|
||||
func TestNewOrder(t *testing.T) {
|
||||
ID := NewOrder("ANX", 2000, 20.00)
|
||||
ID := NewOrder("OKEX", 2000, 20.00)
|
||||
if ID != 0 {
|
||||
t.Error("Orders_test.go NewOrder() - Error")
|
||||
}
|
||||
@@ -25,7 +25,7 @@ func TestDeleteOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetOrdersByExchange(t *testing.T) {
|
||||
if value := GetOrdersByExchange("ANX"); len(value) != 0 {
|
||||
if value := GetOrdersByExchange("OKEX"); len(value) != 0 {
|
||||
t.Error("Orders_test.go GetOrdersByExchange() - Error")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,15 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
)
|
||||
|
||||
const (
|
||||
testExchange = "OKEX"
|
||||
)
|
||||
|
||||
func TestLenByPrice(t *testing.T) {
|
||||
p := currency.NewPairFromStrings("BTC", "USD")
|
||||
Items = []Item{
|
||||
{
|
||||
Exchange: "ANX",
|
||||
Exchange: testExchange,
|
||||
Pair: p,
|
||||
AssetType: asset.Spot,
|
||||
Price: 1200,
|
||||
@@ -104,7 +108,7 @@ func TestSwapByVolume(t *testing.T) {
|
||||
func TestAdd(t *testing.T) {
|
||||
Items = Items[:0]
|
||||
p := currency.NewPairFromStrings("BTC", "USD")
|
||||
Add("ANX", p, asset.Spot, 1200, 42)
|
||||
Add(testExchange, p, asset.Spot, 1200, 42)
|
||||
|
||||
if len(Items) < 1 {
|
||||
t.Error("stats Add did not add exchange info.")
|
||||
@@ -117,14 +121,14 @@ func TestAdd(t *testing.T) {
|
||||
}
|
||||
|
||||
p.Base = currency.XBT
|
||||
Add("ANX", p, asset.Spot, 1201, 43)
|
||||
Add(testExchange, p, asset.Spot, 1201, 43)
|
||||
|
||||
if Items[1].Pair.String() != "XBTUSD" {
|
||||
t.Fatal("stats Add did not add exchange info.")
|
||||
}
|
||||
|
||||
p = currency.NewPairFromStrings("ETH", "USDT")
|
||||
Add("ANX", p, asset.Spot, 300, 1000)
|
||||
Add(testExchange, p, asset.Spot, 300, 1000)
|
||||
|
||||
if Items[2].Pair.String() != "ETHUSD" {
|
||||
t.Fatal("stats Add did not add exchange info.")
|
||||
@@ -146,7 +150,7 @@ func TestAppend(t *testing.T) {
|
||||
|
||||
func TestAlreadyExists(t *testing.T) {
|
||||
p := currency.NewPairFromStrings("BTC", "USD")
|
||||
if !AlreadyExists("ANX", p, asset.Spot, 1200, 42) {
|
||||
if !AlreadyExists(testExchange, p, asset.Spot, 1200, 42) {
|
||||
t.Error("stats AlreadyExists exchange does not exist.")
|
||||
}
|
||||
p.Base = currency.NewCode("dii")
|
||||
@@ -163,7 +167,7 @@ func TestSortExchangesByVolume(t *testing.T) {
|
||||
}
|
||||
|
||||
topVolume = SortExchangesByVolume(p, asset.Spot, false)
|
||||
if topVolume[0].Exchange != "ANX" {
|
||||
if topVolume[0].Exchange != testExchange {
|
||||
t.Error("stats SortExchangesByVolume incorrectly sorted values.")
|
||||
}
|
||||
}
|
||||
@@ -176,7 +180,7 @@ func TestSortExchangesByPrice(t *testing.T) {
|
||||
}
|
||||
|
||||
topPrice = SortExchangesByPrice(p, asset.Spot, false)
|
||||
if topPrice[0].Exchange != "ANX" {
|
||||
if topPrice[0].Exchange != testExchange {
|
||||
t.Error("stats SortExchangesByPrice incorrectly sorted values.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ func IsSupported(exchangeName string) bool {
|
||||
|
||||
// Exchanges stores a list of supported exchanges
|
||||
var Exchanges = []string{
|
||||
"anx",
|
||||
"binance",
|
||||
"bitfinex",
|
||||
"bitflyer",
|
||||
|
||||
Reference in New Issue
Block a user