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:
@@ -10,7 +10,6 @@ vadimzhukck | https://github.com/vadimzhukck
|
|||||||
marcofranssen | https://github.com/marcofranssen
|
marcofranssen | https://github.com/marcofranssen
|
||||||
MadCozBadd | https://github.com/MadCozBadd
|
MadCozBadd | https://github.com/MadCozBadd
|
||||||
cranktakular | https://github.com/cranktakular
|
cranktakular | https://github.com/cranktakular
|
||||||
leilaes | https://github.com/leilaes
|
|
||||||
crackcomm | https://github.com/crackcomm
|
crackcomm | https://github.com/crackcomm
|
||||||
andreygrehov | https://github.com/andreygrehov
|
andreygrehov | https://github.com/andreygrehov
|
||||||
bretep | https://github.com/bretep
|
bretep | https://github.com/bretep
|
||||||
@@ -18,6 +17,7 @@ woshidama323 | https://github.com/woshidama323
|
|||||||
gam-phon | https://github.com/gam-phon
|
gam-phon | https://github.com/gam-phon
|
||||||
cornelk | https://github.com/cornelk
|
cornelk | https://github.com/cornelk
|
||||||
if1live | https://github.com/if1live
|
if1live | https://github.com/if1live
|
||||||
|
lozdog245 | https://github.com/lozdog245
|
||||||
soxipy | https://github.com/soxipy
|
soxipy | https://github.com/soxipy
|
||||||
herenow | https://github.com/herenow
|
herenow | https://github.com/herenow
|
||||||
blombard | https://github.com/blombard
|
blombard | https://github.com/blombard
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2014-2019 The GoCryptoTrader Developers
|
Copyright (c) 2014-2020 The GoCryptoTrader Developers
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -19,7 +19,6 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
|||||||
| Exchange | REST API | Streaming API | FIX API |
|
| Exchange | REST API | Streaming API | FIX API |
|
||||||
|----------|------|-----------|-----|
|
|----------|------|-----------|-----|
|
||||||
| Alphapoint | Yes | Yes | NA |
|
| Alphapoint | Yes | Yes | NA |
|
||||||
| ANXPRO | Yes | No | NA |
|
|
||||||
| Binance| Yes | Yes | NA |
|
| Binance| Yes | Yes | NA |
|
||||||
| Bitfinex | Yes | Yes | NA |
|
| Bitfinex | Yes | Yes | NA |
|
||||||
| Bitflyer | Yes | No | NA |
|
| Bitflyer | Yes | No | NA |
|
||||||
@@ -138,17 +137,16 @@ Binaries will be published once the codebase reaches a stable condition.
|
|||||||
|
|
||||||
|User|Contribution Amount|
|
|User|Contribution Amount|
|
||||||
|--|--|
|
|--|--|
|
||||||
| [thrasher-](https://github.com/thrasher-) | 551 |
|
| [thrasher-](https://github.com/thrasher-) | 625 |
|
||||||
| [shazbert](https://github.com/shazbert) | 176 |
|
| [shazbert](https://github.com/shazbert) | 185 |
|
||||||
| [gloriousCode](https://github.com/gloriousCode) | 155 |
|
| [gloriousCode](https://github.com/gloriousCode) | 163 |
|
||||||
| [xtda](https://github.com/xtda) | 18 |
|
| [xtda](https://github.com/xtda) | 34 |
|
||||||
| [ermalguni](https://github.com/ermalguni) | 14 |
|
| [ermalguni](https://github.com/ermalguni) | 14 |
|
||||||
| [vadimzhukck](https://github.com/vadimzhukck) | 10 |
|
| [vadimzhukck](https://github.com/vadimzhukck) | 10 |
|
||||||
| [140am](https://github.com/140am) | 8 |
|
| [140am](https://github.com/140am) | 8 |
|
||||||
| [marcofranssen](https://github.com/marcofranssen) | 8 |
|
| [marcofranssen](https://github.com/marcofranssen) | 8 |
|
||||||
| [MadCozBadd](https://github.com/MadCozBadd) | 6 |
|
| [MadCozBadd](https://github.com/MadCozBadd) | 7 |
|
||||||
| [cranktakular](https://github.com/cranktakular) | 5 |
|
| [cranktakular](https://github.com/cranktakular) | 5 |
|
||||||
| [leilaes](https://github.com/leilaes) | 3 |
|
|
||||||
| [crackcomm](https://github.com/crackcomm) | 3 |
|
| [crackcomm](https://github.com/crackcomm) | 3 |
|
||||||
| [andreygrehov](https://github.com/andreygrehov) | 2 |
|
| [andreygrehov](https://github.com/andreygrehov) | 2 |
|
||||||
| [bretep](https://github.com/bretep) | 2 |
|
| [bretep](https://github.com/bretep) | 2 |
|
||||||
@@ -156,6 +154,7 @@ Binaries will be published once the codebase reaches a stable condition.
|
|||||||
| [gam-phon](https://github.com/gam-phon) | 2 |
|
| [gam-phon](https://github.com/gam-phon) | 2 |
|
||||||
| [cornelk](https://github.com/cornelk) | 2 |
|
| [cornelk](https://github.com/cornelk) | 2 |
|
||||||
| [if1live](https://github.com/if1live) | 2 |
|
| [if1live](https://github.com/if1live) | 2 |
|
||||||
|
| [lozdog245](https://github.com/lozdog245) | 2 |
|
||||||
| [soxipy](https://github.com/soxipy) | 2 |
|
| [soxipy](https://github.com/soxipy) | 2 |
|
||||||
| [herenow](https://github.com/herenow) | 2 |
|
| [herenow](https://github.com/herenow) | 2 |
|
||||||
| [blombard](https://github.com/blombard) | 1 |
|
| [blombard](https://github.com/blombard) | 1 |
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ app and share different types of data
|
|||||||
|
|
||||||
+ Basic communication to your slack channel information includes:
|
+ Basic communication to your slack channel information includes:
|
||||||
- Working status of bot
|
- Working status of bot
|
||||||
- Recent ANX ticker
|
|
||||||
- Current ANX orderbook
|
|
||||||
|
|
||||||
### How to enable
|
### How to enable
|
||||||
|
|
||||||
@@ -49,9 +47,6 @@ via Slack:
|
|||||||
!status - Displays current working status of bot
|
!status - Displays current working status of bot
|
||||||
!help - Displays help text
|
!help - Displays help text
|
||||||
!settings - Displays current settings
|
!settings - Displays current settings
|
||||||
!ticker - Displays recent ANX ticker
|
|
||||||
!portfolio - Displays portfolio data
|
|
||||||
!orderbook - Displays current ANX orderbook
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ developed by Telegram Messenger LLP
|
|||||||
|
|
||||||
+ Creation of bot that can retrieve
|
+ Creation of bot that can retrieve
|
||||||
- Bot status
|
- Bot status
|
||||||
- ANX orderbook
|
|
||||||
- ANX ticker
|
|
||||||
|
|
||||||
### How to enable
|
### How to enable
|
||||||
|
|
||||||
@@ -49,9 +47,6 @@ via Telegram:
|
|||||||
/status - Displays the status of the bot
|
/status - Displays the status of the bot
|
||||||
/help - Displays current command list
|
/help - Displays current command list
|
||||||
/settings - Displays current bot settings
|
/settings - Displays current bot settings
|
||||||
/ticker - Displays current ANX ticker data
|
|
||||||
/portfolio - Displays your current portfolio
|
|
||||||
/orderbooks - Displays current orderbooks for ANX`
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ have multiple deposit accounts for different FIAT deposit currencies.
|
|||||||
```js
|
```js
|
||||||
"Exchanges": [
|
"Exchanges": [
|
||||||
{
|
{
|
||||||
"Name": "ANX",
|
"Name": "Bitfinex",
|
||||||
"Enabled": true,
|
"Enabled": true,
|
||||||
"Verbose": false,
|
"Verbose": false,
|
||||||
"Websocket": false,
|
"Websocket": false,
|
||||||
@@ -110,7 +110,7 @@ have multiple deposit accounts for different FIAT deposit currencies.
|
|||||||
"SWIFTCode": "91272837",
|
"SWIFTCode": "91272837",
|
||||||
"IBAN": "98218738671897",
|
"IBAN": "98218738671897",
|
||||||
"SupportedCurrencies": "USD",
|
"SupportedCurrencies": "USD",
|
||||||
"SupportedExchanges": "ANX,Kraken"
|
"SupportedExchanges": "Kraken,Bitstamp"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,109 +0,0 @@
|
|||||||
{{define "exchanges anx" -}}
|
|
||||||
{{template "header" .}}
|
|
||||||
## 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
|
|
||||||
{{template "contributions"}}
|
|
||||||
{{template "donations"}}
|
|
||||||
{{end}}
|
|
||||||
@@ -20,7 +20,6 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
|||||||
| Exchange | REST API | Streaming API | FIX API |
|
| Exchange | REST API | Streaming API | FIX API |
|
||||||
|----------|------|-----------|-----|
|
|----------|------|-----------|-----|
|
||||||
| Alphapoint | Yes | Yes | NA |
|
| Alphapoint | Yes | Yes | NA |
|
||||||
| ANXPRO | Yes | No | NA |
|
|
||||||
| Binance| Yes | Yes | NA |
|
| Binance| Yes | Yes | NA |
|
||||||
| Bitfinex | Yes | Yes | NA |
|
| Bitfinex | Yes | Yes | NA |
|
||||||
| Bitflyer | Yes | No | NA |
|
| Bitflyer | Yes | No | NA |
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseCLFlags() {
|
func parseCLFlags() {
|
||||||
flag.StringVar(&exchangesToUseOverride, "exchanges", "", "a + delimited list of exchange names to run tests against eg -exchanges=bitfinex+anx")
|
flag.StringVar(&exchangesToUseOverride, "exchanges", "", "a + delimited list of exchange names to run tests against eg -exchanges=bitfinex+okex")
|
||||||
flag.StringVar(&exchangesToExcludeOverride, "excluded-exchanges", "", "a + delimited list of exchange names to ignore when they're being temperamental eg -exchangesToExlude=lbank")
|
flag.StringVar(&exchangesToExcludeOverride, "excluded-exchanges", "", "a + delimited list of exchange names to ignore when they're being temperamental eg -exchangesToExlude=lbank")
|
||||||
flag.StringVar(&assetTypeOverride, "asset", "", "the asset type to run tests against (where applicable)")
|
flag.StringVar(&assetTypeOverride, "asset", "", "the asset type to run tests against (where applicable)")
|
||||||
flag.StringVar(¤cyPairOverride, "currency", "", "the currency to run tests against (where applicable)")
|
flag.StringVar(¤cyPairOverride, "currency", "", "the currency to run tests against (where applicable)")
|
||||||
|
|||||||
@@ -34,11 +34,6 @@
|
|||||||
},
|
},
|
||||||
"exchanges": {
|
"exchanges": {
|
||||||
"alphapoint": {},
|
"alphapoint": {},
|
||||||
"anx": {
|
|
||||||
"key": "Key",
|
|
||||||
"secret": "Secret",
|
|
||||||
"otpSecret": "-"
|
|
||||||
},
|
|
||||||
"binance": {
|
"binance": {
|
||||||
"key": "Key",
|
"key": "Key",
|
||||||
"secret": "Secret",
|
"secret": "Secret",
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ app and share different types of data
|
|||||||
|
|
||||||
+ Basic communication to your slack channel information includes:
|
+ Basic communication to your slack channel information includes:
|
||||||
- Working status of bot
|
- Working status of bot
|
||||||
- Recent ANX ticker
|
|
||||||
- Current ANX orderbook
|
|
||||||
|
|
||||||
### How to enable
|
### How to enable
|
||||||
|
|
||||||
@@ -67,9 +65,6 @@ via Slack:
|
|||||||
!status - Displays current working status of bot
|
!status - Displays current working status of bot
|
||||||
!help - Displays help text
|
!help - Displays help text
|
||||||
!settings - Displays current settings
|
!settings - Displays current settings
|
||||||
!ticker - Displays recent ANX ticker
|
|
||||||
!portfolio - Displays portfolio data
|
|
||||||
!orderbook - Displays current ANX orderbook
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ developed by Telegram Messenger LLP
|
|||||||
|
|
||||||
+ Creation of bot that can retrieve
|
+ Creation of bot that can retrieve
|
||||||
- Bot status
|
- Bot status
|
||||||
- ANX orderbook
|
|
||||||
- ANX ticker
|
|
||||||
|
|
||||||
### How to enable
|
### How to enable
|
||||||
|
|
||||||
@@ -67,9 +65,6 @@ via Telegram:
|
|||||||
/status - Displays the status of the bot
|
/status - Displays the status of the bot
|
||||||
/help - Displays current command list
|
/help - Displays current command list
|
||||||
/settings - Displays current bot settings
|
/settings - Displays current bot settings
|
||||||
/ticker - Displays current ANX ticker data
|
|
||||||
/portfolio - Displays your current portfolio
|
|
||||||
/orderbooks - Displays current orderbooks for ANX`
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ have multiple deposit accounts for different FIAT deposit currencies.
|
|||||||
```js
|
```js
|
||||||
"Exchanges": [
|
"Exchanges": [
|
||||||
{
|
{
|
||||||
"Name": "ANX",
|
"Name": "Bitfinex",
|
||||||
"Enabled": true,
|
"Enabled": true,
|
||||||
"Verbose": false,
|
"Verbose": false,
|
||||||
"Websocket": false,
|
"Websocket": false,
|
||||||
@@ -128,7 +128,7 @@ have multiple deposit accounts for different FIAT deposit currencies.
|
|||||||
"SWIFTCode": "91272837",
|
"SWIFTCode": "91272837",
|
||||||
"IBAN": "98218738671897",
|
"IBAN": "98218738671897",
|
||||||
"SupportedCurrencies": "USD",
|
"SupportedCurrencies": "USD",
|
||||||
"SupportedExchanges": "ANX,Kraken"
|
"SupportedExchanges": "Kraken,Bitstamp"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ func (c *Config) CheckClientBankAccounts() {
|
|||||||
SWIFTCode: "91272837",
|
SWIFTCode: "91272837",
|
||||||
IBAN: "98218738671897",
|
IBAN: "98218738671897",
|
||||||
SupportedCurrencies: "USD",
|
SupportedCurrencies: "USD",
|
||||||
SupportedExchanges: "ANX,Kraken",
|
SupportedExchanges: "Kraken,Bitstamp",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
// Default number of enabled exchanges. Modify this whenever an exchange is
|
// Default number of enabled exchanges. Modify this whenever an exchange is
|
||||||
// added or removed
|
// added or removed
|
||||||
defaultEnabledExchanges = 28
|
defaultEnabledExchanges = 27
|
||||||
testFakeExchangeName = "Stampbit"
|
testFakeExchangeName = "Stampbit"
|
||||||
testPair = "BTC-USD"
|
testPair = "BTC-USD"
|
||||||
)
|
)
|
||||||
@@ -1111,7 +1111,7 @@ func TestGetExchangeConfig(t *testing.T) {
|
|||||||
"GetExchangeConfig.LoadConfig Error: %s", err.Error(),
|
"GetExchangeConfig.LoadConfig Error: %s", err.Error(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_, err = GetExchangeConfig.GetExchangeConfig("ANX")
|
_, err = GetExchangeConfig.GetExchangeConfig("Bitfinex")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("GetExchangeConfig.GetExchangeConfig Error: %s",
|
t.Errorf("GetExchangeConfig.GetExchangeConfig Error: %s",
|
||||||
err.Error())
|
err.Error())
|
||||||
@@ -1184,7 +1184,7 @@ func TestUpdateExchangeConfig(t *testing.T) {
|
|||||||
t.Error("Expected error from non-existent exchange")
|
t.Error("Expected error from non-existent exchange")
|
||||||
}
|
}
|
||||||
|
|
||||||
e, err = c.GetExchangeConfig("ANX")
|
e, err = c.GetExchangeConfig("OKEX")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,83 +216,6 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"exchanges": [
|
"exchanges": [
|
||||||
{
|
|
||||||
"name": "ANX",
|
|
||||||
"enabled": true,
|
|
||||||
"verbose": false,
|
|
||||||
"httpTimeout": 15000000000,
|
|
||||||
"websocketResponseCheckTimeout": 30000000,
|
|
||||||
"websocketResponseMaxLimit": 7000000000,
|
|
||||||
"websocketTrafficTimeout": 30000000000,
|
|
||||||
"websocketOrderbookBufferLimit": 5,
|
|
||||||
"baseCurrencies": "USD,HKD,EUR,CAD,AUD,SGD,JPY,GBP,NZD",
|
|
||||||
"currencyPairs": {
|
|
||||||
"requestFormat": {
|
|
||||||
"uppercase": true
|
|
||||||
},
|
|
||||||
"configFormat": {
|
|
||||||
"uppercase": true,
|
|
||||||
"delimiter": "_"
|
|
||||||
},
|
|
||||||
"useGlobalFormat": true,
|
|
||||||
"assetTypes": [
|
|
||||||
"spot"
|
|
||||||
],
|
|
||||||
"pairs": {
|
|
||||||
"spot": {
|
|
||||||
"enabled": "BTC_USD,BTC_HKD,BTC_EUR,BTC_CAD,BTC_AUD,BTC_SGD,BTC_JPY,BTC_GBP,BTC_NZD,LTC_BTC,STR_BTC,XRP_BTC",
|
|
||||||
"available": "ATENC_GBP,ATENC_NZD,BTC_AUD,BTC_SGD,LTC_BTC,START_GBP,STR_BTC,XRP_BTC,ATENC_SGD,BTC_GBP,DOGE_BTC,OAX_ETH,START_AUD,START_JPY,ATENC_USD,BTC_EUR,GNT_ETH,START_EUR,ATENC_EUR,BTC_CAD,START_BTC,START_CAD,ATENC_HKD,ATENC_JPY,ETH_BTC,ETH_HKD,START_HKD,START_USD,ATENC_AUD,ETH_USD,START_SGD,ATENC_CAD,BTC_HKD,BTC_JPY,BTC_NZD,BTC_USD,START_NZD"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"api": {
|
|
||||||
"authenticatedSupport": false,
|
|
||||||
"authenticatedWebsocketApiSupport": false,
|
|
||||||
"endpoints": {
|
|
||||||
"url": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
|
|
||||||
"urlSecondary": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
|
|
||||||
"websocketURL": "NON_DEFAULT_HTTP_LINK_TO_WEBSOCKET_EXCHANGE_API"
|
|
||||||
},
|
|
||||||
"credentials": {
|
|
||||||
"key": "Key",
|
|
||||||
"secret": "Secret"
|
|
||||||
},
|
|
||||||
"credentialsValidator": {
|
|
||||||
"requiresKey": true,
|
|
||||||
"requiresSecret": true,
|
|
||||||
"requiresBase64DecodeSecret": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"features": {
|
|
||||||
"supports": {
|
|
||||||
"restAPI": true,
|
|
||||||
"restCapabilities": {
|
|
||||||
"autoPairUpdates": true
|
|
||||||
},
|
|
||||||
"websocketAPI": false,
|
|
||||||
"websocketCapabilities": {}
|
|
||||||
},
|
|
||||||
"enabled": {
|
|
||||||
"autoPairUpdates": true,
|
|
||||||
"websocketAPI": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"bankAccounts": [
|
|
||||||
{
|
|
||||||
"enabled": false,
|
|
||||||
"bankName": "",
|
|
||||||
"bankAddress": "",
|
|
||||||
"bankPostalCode": "",
|
|
||||||
"bankPostalCity": "",
|
|
||||||
"bankCountry": "",
|
|
||||||
"accountName": "",
|
|
||||||
"accountNumber": "",
|
|
||||||
"swiftCode": "",
|
|
||||||
"iban": "",
|
|
||||||
"supportedCurrencies": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Binance",
|
"name": "Binance",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
@@ -2489,7 +2412,7 @@
|
|||||||
"swiftCode": "91272837",
|
"swiftCode": "91272837",
|
||||||
"iban": "98218738671897",
|
"iban": "98218738671897",
|
||||||
"supportedCurrencies": "USD",
|
"supportedCurrencies": "USD",
|
||||||
"supportedExchanges": "ANX,Kraken"
|
"supportedExchanges": "Kraken,Bitstamp"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
"github.com/thrasher-corp/gocryptotrader/common"
|
"github.com/thrasher-corp/gocryptotrader/common"
|
||||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||||
"github.com/thrasher-corp/gocryptotrader/exchanges/anx"
|
|
||||||
"github.com/thrasher-corp/gocryptotrader/exchanges/binance"
|
"github.com/thrasher-corp/gocryptotrader/exchanges/binance"
|
||||||
"github.com/thrasher-corp/gocryptotrader/exchanges/bitfinex"
|
"github.com/thrasher-corp/gocryptotrader/exchanges/bitfinex"
|
||||||
"github.com/thrasher-corp/gocryptotrader/exchanges/bitflyer"
|
"github.com/thrasher-corp/gocryptotrader/exchanges/bitflyer"
|
||||||
@@ -146,8 +145,6 @@ func LoadExchange(name string, useWG bool, wg *sync.WaitGroup) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch nameLower {
|
switch nameLower {
|
||||||
case "anx":
|
|
||||||
exch = new(anx.ANX)
|
|
||||||
case "binance":
|
case "binance":
|
||||||
exch = new(binance.Binance)
|
exch = new(binance.Binance)
|
||||||
case "bitfinex":
|
case "bitfinex":
|
||||||
|
|||||||
@@ -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 (
|
const (
|
||||||
defaultTestExchange = "ANX"
|
defaultTestExchange = "Bitfinex"
|
||||||
defaultTestCurrencyPair = "BTC-USD"
|
defaultTestCurrencyPair = "BTC-USD"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1175,13 +1175,13 @@ func TestUpdatePairs(t *testing.T) {
|
|||||||
t.Fatal("TestUpdatePairs failed to load config")
|
t.Fatal("TestUpdatePairs failed to load config")
|
||||||
}
|
}
|
||||||
|
|
||||||
anxCfg, err := cfg.GetExchangeConfig(defaultTestExchange)
|
exchCfg, err := cfg.GetExchangeConfig(defaultTestExchange)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("TestUpdatePairs failed to load config")
|
t.Fatal("TestUpdatePairs failed to load config")
|
||||||
}
|
}
|
||||||
|
|
||||||
UAC := Base{Name: defaultTestExchange}
|
UAC := Base{Name: defaultTestExchange}
|
||||||
UAC.Config = anxCfg
|
UAC.Config = exchCfg
|
||||||
exchangeProducts := currency.NewPairsFromStrings([]string{"ltc", "btc", "usd", "aud", ""})
|
exchangeProducts := currency.NewPairsFromStrings([]string{"ltc", "btc", "usd", "aud", ""})
|
||||||
err = UAC.UpdatePairs(exchangeProducts, asset.Spot, true, false)
|
err = UAC.UpdatePairs(exchangeProducts, asset.Spot, true, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestNewOrder(t *testing.T) {
|
func TestNewOrder(t *testing.T) {
|
||||||
ID := NewOrder("ANX", 2000, 20.00)
|
ID := NewOrder("OKEX", 2000, 20.00)
|
||||||
if ID != 0 {
|
if ID != 0 {
|
||||||
t.Error("Orders_test.go NewOrder() - Error")
|
t.Error("Orders_test.go NewOrder() - Error")
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,7 @@ func TestDeleteOrder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetOrdersByExchange(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")
|
t.Error("Orders_test.go GetOrdersByExchange() - Error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,15 @@ import (
|
|||||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
testExchange = "OKEX"
|
||||||
|
)
|
||||||
|
|
||||||
func TestLenByPrice(t *testing.T) {
|
func TestLenByPrice(t *testing.T) {
|
||||||
p := currency.NewPairFromStrings("BTC", "USD")
|
p := currency.NewPairFromStrings("BTC", "USD")
|
||||||
Items = []Item{
|
Items = []Item{
|
||||||
{
|
{
|
||||||
Exchange: "ANX",
|
Exchange: testExchange,
|
||||||
Pair: p,
|
Pair: p,
|
||||||
AssetType: asset.Spot,
|
AssetType: asset.Spot,
|
||||||
Price: 1200,
|
Price: 1200,
|
||||||
@@ -104,7 +108,7 @@ func TestSwapByVolume(t *testing.T) {
|
|||||||
func TestAdd(t *testing.T) {
|
func TestAdd(t *testing.T) {
|
||||||
Items = Items[:0]
|
Items = Items[:0]
|
||||||
p := currency.NewPairFromStrings("BTC", "USD")
|
p := currency.NewPairFromStrings("BTC", "USD")
|
||||||
Add("ANX", p, asset.Spot, 1200, 42)
|
Add(testExchange, p, asset.Spot, 1200, 42)
|
||||||
|
|
||||||
if len(Items) < 1 {
|
if len(Items) < 1 {
|
||||||
t.Error("stats Add did not add exchange info.")
|
t.Error("stats Add did not add exchange info.")
|
||||||
@@ -117,14 +121,14 @@ func TestAdd(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.Base = currency.XBT
|
p.Base = currency.XBT
|
||||||
Add("ANX", p, asset.Spot, 1201, 43)
|
Add(testExchange, p, asset.Spot, 1201, 43)
|
||||||
|
|
||||||
if Items[1].Pair.String() != "XBTUSD" {
|
if Items[1].Pair.String() != "XBTUSD" {
|
||||||
t.Fatal("stats Add did not add exchange info.")
|
t.Fatal("stats Add did not add exchange info.")
|
||||||
}
|
}
|
||||||
|
|
||||||
p = currency.NewPairFromStrings("ETH", "USDT")
|
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" {
|
if Items[2].Pair.String() != "ETHUSD" {
|
||||||
t.Fatal("stats Add did not add exchange info.")
|
t.Fatal("stats Add did not add exchange info.")
|
||||||
@@ -146,7 +150,7 @@ func TestAppend(t *testing.T) {
|
|||||||
|
|
||||||
func TestAlreadyExists(t *testing.T) {
|
func TestAlreadyExists(t *testing.T) {
|
||||||
p := currency.NewPairFromStrings("BTC", "USD")
|
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.")
|
t.Error("stats AlreadyExists exchange does not exist.")
|
||||||
}
|
}
|
||||||
p.Base = currency.NewCode("dii")
|
p.Base = currency.NewCode("dii")
|
||||||
@@ -163,7 +167,7 @@ func TestSortExchangesByVolume(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
topVolume = SortExchangesByVolume(p, asset.Spot, false)
|
topVolume = SortExchangesByVolume(p, asset.Spot, false)
|
||||||
if topVolume[0].Exchange != "ANX" {
|
if topVolume[0].Exchange != testExchange {
|
||||||
t.Error("stats SortExchangesByVolume incorrectly sorted values.")
|
t.Error("stats SortExchangesByVolume incorrectly sorted values.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,7 +180,7 @@ func TestSortExchangesByPrice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
topPrice = SortExchangesByPrice(p, asset.Spot, false)
|
topPrice = SortExchangesByPrice(p, asset.Spot, false)
|
||||||
if topPrice[0].Exchange != "ANX" {
|
if topPrice[0].Exchange != testExchange {
|
||||||
t.Error("stats SortExchangesByPrice incorrectly sorted values.")
|
t.Error("stats SortExchangesByPrice incorrectly sorted values.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ func IsSupported(exchangeName string) bool {
|
|||||||
|
|
||||||
// Exchanges stores a list of supported exchanges
|
// Exchanges stores a list of supported exchanges
|
||||||
var Exchanges = []string{
|
var Exchanges = []string{
|
||||||
"anx",
|
|
||||||
"binance",
|
"binance",
|
||||||
"bitfinex",
|
"bitfinex",
|
||||||
"bitflyer",
|
"bitflyer",
|
||||||
|
|||||||
@@ -112,10 +112,10 @@ func TestExchangeAddressExists(t *testing.T) {
|
|||||||
|
|
||||||
func TestAddExchangeAddress(t *testing.T) {
|
func TestAddExchangeAddress(t *testing.T) {
|
||||||
newbase := Base{}
|
newbase := Base{}
|
||||||
newbase.AddExchangeAddress("ANX", currency.BTC, 100)
|
newbase.AddExchangeAddress("OKEX", currency.BTC, 100)
|
||||||
newbase.AddExchangeAddress("ANX", currency.BTC, 200)
|
newbase.AddExchangeAddress("OKEX", currency.BTC, 200)
|
||||||
|
|
||||||
if !newbase.ExchangeAddressExists("ANX", currency.BTC) {
|
if !newbase.ExchangeAddressExists("OKEX", currency.BTC) {
|
||||||
t.Error("TestExchangeAddressExists address doesn't exist")
|
t.Error("TestExchangeAddressExists address doesn't exist")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -305,12 +305,12 @@ func TestUpdatePortfolio(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetPortfolioByExchange(t *testing.T) {
|
func TestGetPortfolioByExchange(t *testing.T) {
|
||||||
newbase := Base{}
|
newbase := Base{}
|
||||||
newbase.AddExchangeAddress("ANX", currency.LTC, 0.07)
|
newbase.AddExchangeAddress("OKEX", currency.LTC, 0.07)
|
||||||
newbase.AddExchangeAddress("Bitfinex", currency.LTC, 0.05)
|
newbase.AddExchangeAddress("Bitfinex", currency.LTC, 0.05)
|
||||||
newbase.AddAddress("someaddress", "LTC", currency.NewCode(PortfolioAddressPersonal), 0.03)
|
newbase.AddAddress("someaddress", "LTC", currency.NewCode(PortfolioAddressPersonal), 0.03)
|
||||||
portfolio := GetPortfolio()
|
portfolio := GetPortfolio()
|
||||||
portfolio.Seed(newbase)
|
portfolio.Seed(newbase)
|
||||||
value := portfolio.GetPortfolioByExchange("ANX")
|
value := portfolio.GetPortfolioByExchange("OKEX")
|
||||||
result, ok := value[currency.LTC]
|
result, ok := value[currency.LTC]
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error("portfolio_test.go - GetPortfolioByExchange error")
|
t.Error("portfolio_test.go - GetPortfolioByExchange error")
|
||||||
@@ -333,7 +333,7 @@ func TestGetPortfolioByExchange(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetExchangePortfolio(t *testing.T) {
|
func TestGetExchangePortfolio(t *testing.T) {
|
||||||
newbase := Base{}
|
newbase := Base{}
|
||||||
newbase.AddAddress("ANX", PortfolioAddressExchange, currency.LTC, 0.03)
|
newbase.AddAddress("OKEX", PortfolioAddressExchange, currency.LTC, 0.03)
|
||||||
newbase.AddAddress("Bitfinex", PortfolioAddressExchange, currency.LTC, 0.05)
|
newbase.AddAddress("Bitfinex", PortfolioAddressExchange, currency.LTC, 0.05)
|
||||||
newbase.AddAddress("someaddress", PortfolioAddressPersonal, currency.LTC, 0.03)
|
newbase.AddAddress("someaddress", PortfolioAddressPersonal, currency.LTC, 0.03)
|
||||||
portfolio := GetPortfolio()
|
portfolio := GetPortfolio()
|
||||||
@@ -382,7 +382,7 @@ func TestGetPortfolioSummary(t *testing.T) {
|
|||||||
// Exchange holdings
|
// Exchange holdings
|
||||||
newbase.AddExchangeAddress("Bitfinex", currency.LTC, 20)
|
newbase.AddExchangeAddress("Bitfinex", currency.LTC, 20)
|
||||||
newbase.AddExchangeAddress("Bitfinex", currency.BTC, 100)
|
newbase.AddExchangeAddress("Bitfinex", currency.BTC, 100)
|
||||||
newbase.AddExchangeAddress("ANX", currency.ETH, 42)
|
newbase.AddExchangeAddress("OKEX", currency.ETH, 42)
|
||||||
|
|
||||||
portfolio := GetPortfolio()
|
portfolio := GetPortfolio()
|
||||||
portfolio.Seed(newbase)
|
portfolio.Seed(newbase)
|
||||||
|
|||||||
79
testdata/configtest.json
vendored
79
testdata/configtest.json
vendored
@@ -215,83 +215,6 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"exchanges": [
|
"exchanges": [
|
||||||
{
|
|
||||||
"name": "ANX",
|
|
||||||
"enabled": true,
|
|
||||||
"verbose": false,
|
|
||||||
"httpTimeout": 15000000000,
|
|
||||||
"websocketResponseCheckTimeout": 30000000,
|
|
||||||
"websocketResponseMaxLimit": 7000000000,
|
|
||||||
"websocketTrafficTimeout": 30000000000,
|
|
||||||
"websocketOrderbookBufferLimit": 5,
|
|
||||||
"baseCurrencies": "USD,HKD,EUR,CAD,AUD,SGD,JPY,GBP,NZD",
|
|
||||||
"currencyPairs": {
|
|
||||||
"requestFormat": {
|
|
||||||
"uppercase": true
|
|
||||||
},
|
|
||||||
"configFormat": {
|
|
||||||
"uppercase": true,
|
|
||||||
"delimiter": "_"
|
|
||||||
},
|
|
||||||
"useGlobalFormat": true,
|
|
||||||
"assetTypes": [
|
|
||||||
"spot"
|
|
||||||
],
|
|
||||||
"pairs": {
|
|
||||||
"spot": {
|
|
||||||
"enabled": "BTC_USD,BTC_HKD,BTC_EUR,BTC_CAD,BTC_AUD,BTC_SGD,BTC_JPY,BTC_GBP,BTC_NZD,LTC_BTC,STR_BTC,XRP_BTC",
|
|
||||||
"available": "ETH_HKD,START_GBP,BTC_CAD,OAX_ETH,START_SGD,LTC_BTC,STR_BTC,ATENC_NZD,BTC_AUD,BTC_SGD,ETH_BTC,XRP_BTC,START_JPY,ATENC_CAD,BTC_GBP,ETH_USD,GNT_ETH,START_AUD,START_HKD,ATENC_GBP,BTC_USD,START_BTC,START_CAD,START_EUR,BTC_JPY,BTC_NZD,DOGE_BTC,ATENC_EUR,ATENC_JPY,ATENC_USD,BTC_EUR,BTC_HKD,START_NZD,START_USD,ATENC_AUD,ATENC_HKD,ATENC_SGD"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"api": {
|
|
||||||
"authenticatedSupport": false,
|
|
||||||
"authenticatedWebsocketApiSupport": false,
|
|
||||||
"endpoints": {
|
|
||||||
"url": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
|
|
||||||
"urlSecondary": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
|
|
||||||
"websocketURL": "NON_DEFAULT_HTTP_LINK_TO_WEBSOCKET_EXCHANGE_API"
|
|
||||||
},
|
|
||||||
"credentials": {
|
|
||||||
"key": "Key",
|
|
||||||
"secret": "Secret"
|
|
||||||
},
|
|
||||||
"credentialsValidator": {
|
|
||||||
"requiresKey": true,
|
|
||||||
"requiresSecret": true,
|
|
||||||
"requiresBase64DecodeSecret": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"features": {
|
|
||||||
"supports": {
|
|
||||||
"restAPI": true,
|
|
||||||
"restCapabilities": {
|
|
||||||
"autoPairUpdates": true
|
|
||||||
},
|
|
||||||
"websocketAPI": false,
|
|
||||||
"websocketCapabilities": {}
|
|
||||||
},
|
|
||||||
"enabled": {
|
|
||||||
"autoPairUpdates": true,
|
|
||||||
"websocketAPI": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"bankAccounts": [
|
|
||||||
{
|
|
||||||
"enabled": false,
|
|
||||||
"bankName": "",
|
|
||||||
"bankAddress": "",
|
|
||||||
"bankPostalCode": "",
|
|
||||||
"bankPostalCity": "",
|
|
||||||
"bankCountry": "",
|
|
||||||
"accountName": "",
|
|
||||||
"accountNumber": "",
|
|
||||||
"swiftCode": "",
|
|
||||||
"iban": "",
|
|
||||||
"supportedCurrencies": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Binance",
|
"name": "Binance",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
@@ -2500,7 +2423,7 @@
|
|||||||
"swiftCode": "91272837",
|
"swiftCode": "91272837",
|
||||||
"iban": "98218738671897",
|
"iban": "98218738671897",
|
||||||
"supportedCurrencies": "USD",
|
"supportedCurrencies": "USD",
|
||||||
"supportedExchanges": "ANX,Kraken"
|
"supportedExchanges": "Kraken,Bitstamp"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
2404
testdata/http_mock/anx/anx.json
vendored
2404
testdata/http_mock/anx/anx.json
vendored
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user