mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
Merge branch 'master' into engine
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,6 +13,7 @@ testdata/writefiletest
|
||||
vendor/
|
||||
|
||||
# Binaries for programs and plugins
|
||||
gocryptotrader
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
|
||||
@@ -27,7 +27,6 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
||||
| BitMEX | Yes | Yes | NA |
|
||||
| Bitstamp | Yes | Yes | No |
|
||||
| Bittrex | Yes | No | NA |
|
||||
| BTCC | Yes | Yes | No |
|
||||
| BTCMarkets | Yes | No | NA |
|
||||
| BTSE | Yes | Yes | NA |
|
||||
| COINUT | Yes | Yes | NA |
|
||||
|
||||
@@ -55,7 +55,6 @@ const (
|
||||
bitmex = "..%s..%sexchanges%sbitmex%s"
|
||||
bitstamp = "..%s..%sexchanges%sbitstamp%s"
|
||||
bittrex = "..%s..%sexchanges%sbittrex%s"
|
||||
btcc = "..%s..%sexchanges%sbtcc%s"
|
||||
btcmarkets = "..%s..%sexchanges%sbtcmarkets%s"
|
||||
coinbasepro = "..%s..%sexchanges%scoinbasepro%s"
|
||||
coinut = "..%s..%sexchanges%scoinut%s"
|
||||
@@ -228,7 +227,6 @@ func addPaths() {
|
||||
codebasePaths["exchanges bitmex"] = fmt.Sprintf(bitmex, path, path, path, path)
|
||||
codebasePaths["exchanges bitstamp"] = fmt.Sprintf(bitstamp, path, path, path, path)
|
||||
codebasePaths["exchanges bittrex"] = fmt.Sprintf(bittrex, path, path, path, path)
|
||||
codebasePaths["exchanges btcc"] = fmt.Sprintf(btcc, path, path, path, path)
|
||||
codebasePaths["exchanges btcmarkets"] = fmt.Sprintf(btcmarkets, path, path, path, path)
|
||||
codebasePaths["exchanges coinut"] = fmt.Sprintf(coinut, path, path, path, path)
|
||||
codebasePaths["exchanges exmo"] = fmt.Sprintf(exmo, path, path, path, path)
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
{{define "exchanges btcc" -}}
|
||||
{{template "header" .}}
|
||||
## BTCC Exchange
|
||||
|
||||
### Current Features
|
||||
|
||||
+ REST Support
|
||||
+ Websocket Support
|
||||
|
||||
### How to enable
|
||||
|
||||
+ [Enable via configuration](https://github.com/thrasher-/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 b exchange.IBotExchange
|
||||
|
||||
for i := range bot.Exchanges {
|
||||
if bot.Exchanges[i].GetName() == "BTCC" {
|
||||
b = bot.Exchanges[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Public calls - wrapper functions
|
||||
|
||||
// Fetches current ticker information
|
||||
tick, err := b.FetchTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := b.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 := b.GetAccountInfo()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
+ If enabled via individually importing package, rudimentary example below:
|
||||
|
||||
```go
|
||||
// Public calls
|
||||
|
||||
// Fetches current ticker information
|
||||
ticker, err := b.GetTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := b.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 := b.GetUserInfo(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Submits an order and the exchange and returns its tradeID
|
||||
tradeID, err := b.Trade(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
### How to do Websocket 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}}
|
||||
@@ -28,7 +28,6 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
||||
| BitMEX | Yes | Yes | NA |
|
||||
| Bitstamp | Yes | Yes | No |
|
||||
| Bittrex | Yes | No | NA |
|
||||
| BTCC | Yes | Yes | No |
|
||||
| BTCMarkets | Yes | No | NA |
|
||||
| BTSE | Yes | Yes | NA |
|
||||
| COINUT | Yes | Yes | NA |
|
||||
|
||||
@@ -55,6 +55,7 @@ func (c IComm) PushEvent(event Event) {
|
||||
|
||||
// GetEnabledCommunicationMediums prints out enabled and connected communication
|
||||
// packages
|
||||
// (#debug output only)
|
||||
func (c IComm) GetEnabledCommunicationMediums() {
|
||||
var count int
|
||||
for i := range c {
|
||||
|
||||
@@ -2,6 +2,9 @@ package base
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -71,14 +74,150 @@ func TestGetStatus(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type CommunicationProvider struct {
|
||||
ICommunicate
|
||||
|
||||
isEnabled bool
|
||||
isConnected bool
|
||||
ConnectCalled bool
|
||||
PushEventCalled bool
|
||||
}
|
||||
|
||||
func (p *CommunicationProvider) IsEnabled() bool {
|
||||
return p.isEnabled
|
||||
}
|
||||
|
||||
func (p *CommunicationProvider) IsConnected() bool {
|
||||
return p.isConnected
|
||||
}
|
||||
|
||||
func (p *CommunicationProvider) Connect() error {
|
||||
p.ConnectCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *CommunicationProvider) PushEvent(e Event) error {
|
||||
p.PushEventCalled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *CommunicationProvider) GetName() string {
|
||||
return "someTestProvider"
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
i.Setup()
|
||||
var ic IComm
|
||||
testConfigs := []struct {
|
||||
isEnabled bool
|
||||
isConnected bool
|
||||
shouldConnectCalled bool
|
||||
provider ICommunicate
|
||||
}{
|
||||
{false, true, false, nil},
|
||||
{false, false, false, nil},
|
||||
{true, true, false, nil},
|
||||
{true, false, true, nil},
|
||||
}
|
||||
for _, config := range testConfigs {
|
||||
config.provider = &CommunicationProvider{
|
||||
isEnabled: config.isEnabled,
|
||||
isConnected: config.isConnected}
|
||||
ic = append(ic, config.provider)
|
||||
}
|
||||
|
||||
ic.Setup()
|
||||
|
||||
for idx, provider := range ic {
|
||||
exp := testConfigs[idx].shouldConnectCalled
|
||||
act := provider.(*CommunicationProvider).ConnectCalled
|
||||
if exp != act {
|
||||
t.Fatalf("provider should be enabled and not be connected: exp=%v, act=%v", exp, act)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPushEvent(t *testing.T) {
|
||||
i.PushEvent(Event{})
|
||||
var ic IComm
|
||||
testConfigs := []struct {
|
||||
Enabled bool
|
||||
Connected bool
|
||||
PushEventCalled bool
|
||||
provider ICommunicate
|
||||
}{
|
||||
{false, true, false, nil},
|
||||
{false, false, false, nil},
|
||||
{true, false, false, nil},
|
||||
{true, true, true, nil},
|
||||
}
|
||||
for _, config := range testConfigs {
|
||||
config.provider = &CommunicationProvider{
|
||||
isEnabled: config.Enabled,
|
||||
isConnected: config.Connected}
|
||||
ic = append(ic, config.provider)
|
||||
}
|
||||
|
||||
ic.PushEvent(Event{})
|
||||
|
||||
for idx, provider := range ic {
|
||||
exp := testConfigs[idx].PushEventCalled
|
||||
act := provider.(*CommunicationProvider).PushEventCalled
|
||||
if exp != act {
|
||||
t.Fatalf("provider should be enabled and connected: exp=%v, act=%v", exp, act)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEnabledCommunicationMediums(t *testing.T) {
|
||||
i.GetEnabledCommunicationMediums()
|
||||
func TestStageTickerData(t *testing.T) {
|
||||
_, ok := TickerStaged["bitstamp"]["someAsset"]["BTCUSD"]
|
||||
if ok {
|
||||
t.Fatalf("key should not exists")
|
||||
}
|
||||
|
||||
price := ticker.Price{}
|
||||
var i IComm
|
||||
i.Setup()
|
||||
|
||||
i.StageTickerData("bitstamp", "someAsset", &price)
|
||||
|
||||
_, ok = TickerStaged["bitstamp"]["someAsset"][price.Pair.String()]
|
||||
if !ok {
|
||||
t.Fatalf("key should exists")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrderbookData(t *testing.T) {
|
||||
_, ok := OrderbookStaged["bitstamp"]["someAsset"]["someOrderbook"]
|
||||
if ok {
|
||||
t.Fatal("key should not exists")
|
||||
}
|
||||
|
||||
ob := orderbook.Base{
|
||||
Asks: []orderbook.Item{
|
||||
{Amount: 1, Price: 2, ID: 3},
|
||||
{Amount: 4, Price: 5, ID: 6},
|
||||
},
|
||||
}
|
||||
var i IComm
|
||||
i.Setup()
|
||||
|
||||
i.StageOrderbookData("bitstamp", "someAsset", &ob)
|
||||
|
||||
orderbook, ok := OrderbookStaged["bitstamp"]["someAsset"][ob.Pair.String()]
|
||||
if !ok {
|
||||
t.Fatal("key should exists")
|
||||
}
|
||||
|
||||
if ob.Pair.String() != orderbook.CurrencyPair {
|
||||
t.Fatal("currency missmatched")
|
||||
}
|
||||
|
||||
_, totalAsks := ob.TotalAsksAmount()
|
||||
if totalAsks != orderbook.TotalAsks {
|
||||
t.Fatal("total asks missmatched")
|
||||
}
|
||||
|
||||
_, totalBids := ob.TotalBidsAmount()
|
||||
if totalBids != orderbook.TotalBids {
|
||||
t.Fatal("total bids missmatched")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
const (
|
||||
// Default number of enabled exchanges. Modify this whenever an exchange is
|
||||
// added or removed
|
||||
defaultEnabledExchanges = 28
|
||||
defaultEnabledExchanges = 27
|
||||
)
|
||||
|
||||
func TestGetCurrencyConfig(t *testing.T) {
|
||||
|
||||
@@ -491,46 +491,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BTCC",
|
||||
"enabled": true,
|
||||
"verbose": false,
|
||||
"websocket": false,
|
||||
"useSandbox": false,
|
||||
"restPollingDelay": 10,
|
||||
"httpTimeout": 15000000000,
|
||||
"httpUserAgent": "",
|
||||
"httpDebugging": false,
|
||||
"authenticatedApiSupport": false,
|
||||
"apiKey": "Key",
|
||||
"apiSecret": "Secret",
|
||||
"apiUrl": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
|
||||
"apiUrlSecondary": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
|
||||
"proxyAddress": "",
|
||||
"websocketUrl": "NON_DEFAULT_HTTP_LINK_TO_WEBSOCKET_EXCHANGE_API",
|
||||
"availablePairs": "BTCUSD",
|
||||
"enabledPairs": "BTCUSD",
|
||||
"baseCurrencies": "USD",
|
||||
"assetTypes": "SPOT",
|
||||
"supportsAutoPairUpdates": true,
|
||||
"configCurrencyPairFormat": {
|
||||
"uppercase": true
|
||||
},
|
||||
"requestCurrencyPairFormat": {
|
||||
"uppercase": true
|
||||
},
|
||||
"bankAccounts": [
|
||||
{
|
||||
"bankName": "",
|
||||
"bankAddress": "",
|
||||
"accountName": "",
|
||||
"accountNumber": "",
|
||||
"swiftCode": "",
|
||||
"iban": "",
|
||||
"supportedCurrencies": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BTSE",
|
||||
"enabled": true,
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/bitmex"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/bitstamp"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/bittrex"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/btcc"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/btcmarkets"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/btse"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/coinbasepro"
|
||||
@@ -148,8 +147,6 @@ func LoadExchange(name string, useWG bool, wg *sync.WaitGroup) error {
|
||||
exch = new(bitstamp.Bitstamp)
|
||||
case "bittrex":
|
||||
exch = new(bittrex.Bittrex)
|
||||
case "btcc":
|
||||
exch = new(btcc.BTCC)
|
||||
case "btc markets":
|
||||
exch = new(btcmarkets.BTCMarkets)
|
||||
case "btse":
|
||||
|
||||
@@ -229,7 +229,8 @@ func (a *Alphapoint) CancelOrder(order *exchange.OrderCancellation) error {
|
||||
|
||||
// CancelAllOrders cancels all orders for a given account
|
||||
func (a *Alphapoint) CancelAllOrders(orderCancellation *exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) {
|
||||
return exchange.CancelAllOrdersResponse{}, a.CancelAllExistingOrders(orderCancellation.AccountID)
|
||||
return exchange.CancelAllOrdersResponse{},
|
||||
a.CancelAllExistingOrders(orderCancellation.AccountID)
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
|
||||
@@ -325,8 +325,8 @@ func (b *Bithumb) CancelAllOrders(orderCancellation *exchange.OrderCancellation)
|
||||
cancelAllOrdersResponse := exchange.CancelAllOrdersResponse{
|
||||
OrderStatus: make(map[string]string),
|
||||
}
|
||||
var allOrders []OrderData
|
||||
|
||||
var allOrders []OrderData
|
||||
for _, currency := range b.GetEnabledPairs(assets.AssetTypeSpot) {
|
||||
orders, err := b.GetOrders("",
|
||||
orderCancellation.Side.ToString(),
|
||||
|
||||
@@ -417,7 +417,9 @@ func (b *Bitmex) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.Cancel
|
||||
}
|
||||
|
||||
for i := range orders {
|
||||
cancelAllOrdersResponse.OrderStatus[orders[i].OrderID] = orders[i].OrdRejReason
|
||||
if orders[i].OrdRejReason != "" {
|
||||
cancelAllOrdersResponse.OrderStatus[orders[i].OrderID] = orders[i].OrdRejReason
|
||||
}
|
||||
}
|
||||
|
||||
return cancelAllOrdersResponse, nil
|
||||
|
||||
@@ -344,8 +344,11 @@ func (b *Bitstamp) CancelOrder(order *exchange.OrderCancellation) error {
|
||||
|
||||
// CancelAllOrders cancels all orders associated with a currency pair
|
||||
func (b *Bitstamp) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) {
|
||||
isCancelAllSuccessful, err := b.CancelAllExistingOrders()
|
||||
if !isCancelAllSuccessful {
|
||||
success, err := b.CancelAllExistingOrders()
|
||||
if err != nil {
|
||||
return exchange.CancelAllOrdersResponse{}, err
|
||||
}
|
||||
if !success {
|
||||
err = errors.New("cancel all orders failed. Bitstamp provides no further information. Check order status to verify")
|
||||
}
|
||||
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
# GoCryptoTrader package Btcc
|
||||
|
||||
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
|
||||
|
||||
|
||||
[](https://travis-ci.org/thrasher-/gocryptotrader)
|
||||
[](https://github.com/thrasher-/gocryptotrader/blob/master/LICENSE)
|
||||
[](https://godoc.org/github.com/thrasher-/gocryptotrader/exchanges/btcc)
|
||||
[](http://codecov.io/github/thrasher-/gocryptotrader?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/thrasher-/gocryptotrader)
|
||||
|
||||
|
||||
This btcc package is part of the GoCryptoTrader codebase.
|
||||
|
||||
## This is still in active development
|
||||
|
||||
You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
|
||||
|
||||
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/enQtNTQ5NDAxMjA2Mjc5LTQyYjIxNGVhMWU5MDZlOGYzMmE0NTJmM2MzYWY5NGMzMmM4MzUwNTBjZTEzNjIwODM5NDcxODQwZDljMGQyNGY)
|
||||
|
||||
## BTCC Exchange
|
||||
|
||||
### Current Features
|
||||
|
||||
+ REST Support
|
||||
+ Websocket Support
|
||||
|
||||
### How to enable
|
||||
|
||||
+ [Enable via configuration](https://github.com/thrasher-/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 b exchange.IBotExchange
|
||||
|
||||
for i := range bot.Exchanges {
|
||||
if bot.Exchanges[i].GetName() == "BTCC" {
|
||||
b = bot.Exchanges[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Public calls - wrapper functions
|
||||
|
||||
// Fetches current ticker information
|
||||
tick, err := b.FetchTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := b.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 := b.GetAccountInfo()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
+ If enabled via individually importing package, rudimentary example below:
|
||||
|
||||
```go
|
||||
// Public calls
|
||||
|
||||
// Fetches current ticker information
|
||||
ticker, err := b.GetTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := b.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 := b.GetUserInfo(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Submits an order and the exchange and returns its tradeID
|
||||
tradeID, err := b.Trade(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
### How to do Websocket 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-/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-/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,54 +0,0 @@
|
||||
package btcc
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/thrasher-/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-/gocryptotrader/exchanges"
|
||||
)
|
||||
|
||||
const (
|
||||
btccAuthRate = 0
|
||||
btccUnauthRate = 0
|
||||
)
|
||||
|
||||
// BTCC is the main overaching type across the BTCC package
|
||||
// NOTE this package is websocket connection dependant, the REST endpoints have
|
||||
// been dropped
|
||||
type BTCC struct {
|
||||
exchange.Base
|
||||
Conn *websocket.Conn
|
||||
wsRequestMtx sync.Mutex
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
func (b *BTCC) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
var fee float64
|
||||
|
||||
switch feeBuilder.FeeType {
|
||||
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.001 * price * amount
|
||||
}
|
||||
|
||||
func getCryptocurrencyWithdrawalFee(c currency.Code) float64 {
|
||||
return WithdrawalFees[c]
|
||||
}
|
||||
|
||||
func getInternationalBankWithdrawalFee(c currency.Code, amount float64) float64 {
|
||||
return WithdrawalFees[c] * amount
|
||||
}
|
||||
@@ -1,344 +0,0 @@
|
||||
package btcc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
"github.com/thrasher-/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-/gocryptotrader/exchanges"
|
||||
)
|
||||
|
||||
// Please supply your own APIkeys here to do better tests
|
||||
const (
|
||||
apiKey = ""
|
||||
apiSecret = ""
|
||||
canManipulateRealOrders = false
|
||||
)
|
||||
|
||||
var b BTCC
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
cfg := config.GetConfig()
|
||||
cfg.LoadConfig("../../testdata/configtest.json")
|
||||
bConfig, err := cfg.GetExchangeConfig("BTCC")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - BTCC Setup() init error")
|
||||
}
|
||||
b.Setup(bConfig)
|
||||
|
||||
if !b.IsEnabled() || b.API.AuthenticatedSupport ||
|
||||
b.Websocket.IsEnabled() || len(b.BaseCurrencies) < 1 ||
|
||||
b.Verbose {
|
||||
t.Error("Test Failed - BTCC Setup values not set correctly")
|
||||
}
|
||||
}
|
||||
|
||||
// func TestGetTicker(t *testing.T) {
|
||||
// t.Skip()
|
||||
// _, err := b.GetTicker("BTCUSD")
|
||||
// if err != nil {
|
||||
// t.Error("Test failed - GetTicker() error", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestGetTradeHistory(t *testing.T) {
|
||||
// t.Skip()
|
||||
// _, err := b.GetTradeHistory("BTCUSD", 0, 0, time.Time{})
|
||||
// if err != nil {
|
||||
// t.Error("Test failed - GetTradeHistory() error", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestGetOrderBook(t *testing.T) {
|
||||
// t.Skip()
|
||||
// _, err := b.GetOrderBook("BTCUSD", 100)
|
||||
// if err != nil {
|
||||
// t.Error("Test failed - GetOrderBook() error", err)
|
||||
// }
|
||||
// _, err = b.GetOrderBook("BTCUSD", 0)
|
||||
// if err != nil {
|
||||
// t.Error("Test failed - GetOrderBook() error", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestGetAccountInfo(t *testing.T) {
|
||||
// t.Skip()
|
||||
// err := b.GetAccountInfo("")
|
||||
// if err == nil {
|
||||
// t.Error("Test failed - GetAccountInfo() error", err)
|
||||
// }
|
||||
// }
|
||||
func setFeeBuilder() *exchange.FeeBuilder {
|
||||
return &exchange.FeeBuilder{
|
||||
Amount: 1,
|
||||
FeeType: exchange.CryptocurrencyTradeFee,
|
||||
Pair: currency.NewPair(currency.BTC, currency.LTC),
|
||||
PurchasePrice: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetFeeByTypeOfflineTradeFee logic test
|
||||
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
||||
var feeBuilder = setFeeBuilder()
|
||||
b.GetFeeByType(feeBuilder)
|
||||
if apiKey == "" || apiSecret == "" {
|
||||
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) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
var feeBuilder = setFeeBuilder()
|
||||
|
||||
// CryptocurrencyTradeFee Basic
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Error(err)
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee High quantity
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.Amount = 1000
|
||||
feeBuilder.PurchasePrice = 1000
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee IsMaker
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.IsMaker = true
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CryptocurrencyTradeFee Negative purchase price
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.PurchasePrice = -1000
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CryptocurrencyWithdrawalFee Basic
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0.001) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.001), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// CyptocurrencyDepositFee Basic
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.CyptocurrencyDepositFee
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// InternationalBankDepositFee Basic
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.InternationalBankDepositFee
|
||||
feeBuilder.FiatCurrency = currency.USD
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// InternationalBankWithdrawalFee Basic
|
||||
feeBuilder = setFeeBuilder()
|
||||
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
|
||||
feeBuilder.FiatCurrency = currency.USD
|
||||
if resp, err := b.GetFee(feeBuilder); resp != float64(0.005) || err != nil {
|
||||
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.005), resp)
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatWithdrawPermissions(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
expectedResult := exchange.NoAPIWithdrawalMethodsText
|
||||
|
||||
withdrawPermissions := b.FormatWithdrawPermissions()
|
||||
|
||||
if withdrawPermissions != expectedResult {
|
||||
t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetActiveOrders(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
}
|
||||
|
||||
_, err := b.GetActiveOrders(&getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
var getOrdersRequest = exchange.GetOrdersRequest{
|
||||
OrderType: exchange.AnyOrderType,
|
||||
}
|
||||
|
||||
_, err := b.GetOrderHistory(&getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Errorf("Could not get order history: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
}
|
||||
|
||||
// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
func areTestAPIKeysSet() bool {
|
||||
return b.ValidateAPICredentials()
|
||||
}
|
||||
|
||||
func TestSubmitOrder(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
var p = currency.Pair{
|
||||
Delimiter: "-",
|
||||
Base: currency.BTC,
|
||||
Quote: currency.LTC,
|
||||
}
|
||||
_, err := b.SubmitOrder(p, exchange.BuyOrderSide, exchange.LimitOrderType, 1, 1, "clientId")
|
||||
if err != common.ErrNotYetImplemented {
|
||||
t.Errorf("Expected 'Not Yet Implemented', received %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelExchangeOrder(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
|
||||
|
||||
var orderCancellation = &exchange.OrderCancellation{
|
||||
OrderID: "1",
|
||||
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
AccountID: "1",
|
||||
CurrencyPair: currencyPair,
|
||||
}
|
||||
|
||||
err := b.CancelOrder(orderCancellation)
|
||||
if err != common.ErrNotYetImplemented {
|
||||
t.Errorf("Expected 'Not Yet Implemented', received %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
|
||||
|
||||
var orderCancellation = &exchange.OrderCancellation{
|
||||
OrderID: "1",
|
||||
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
AccountID: "1",
|
||||
CurrencyPair: currencyPair,
|
||||
}
|
||||
|
||||
_, err := b.CancelAllOrders(orderCancellation)
|
||||
|
||||
if err != common.ErrNotYetImplemented {
|
||||
t.Errorf("Expected 'Not Yet Implemented', received %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
withdrawCryptoRequest := exchange.CryptoWithdrawRequest{
|
||||
GenericWithdrawRequestInfo: exchange.GenericWithdrawRequestInfo{
|
||||
Amount: -1,
|
||||
Currency: currency.BTC,
|
||||
Description: "WITHDRAW IT ALL",
|
||||
},
|
||||
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
|
||||
}
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
_, err := b.WithdrawCryptocurrencyFunds(&withdrawCryptoRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestModifyOrder(t *testing.T) {
|
||||
_, err := b.ModifyOrder(&exchange.ModifyOrder{})
|
||||
if err == nil {
|
||||
t.Error("Test failed - ModifyOrder() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawFiat(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
var withdrawFiatRequest = exchange.FiatWithdrawRequest{}
|
||||
_, err := b.WithdrawFiatFunds(&withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawInternationalBank(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
TestSetup(t)
|
||||
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
var withdrawFiatRequest = exchange.FiatWithdrawRequest{}
|
||||
_, err := b.WithdrawFiatFundsToInternationalBank(&withdrawFiatRequest)
|
||||
if err != common.ErrFunctionNotSupported {
|
||||
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
package btcc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/currency"
|
||||
)
|
||||
|
||||
// WsAllTickerData defines multiple ticker data
|
||||
type WsAllTickerData []WsTicker
|
||||
|
||||
// WsOutgoing defines outgoing JSON
|
||||
type WsOutgoing struct {
|
||||
Action string `json:"action"`
|
||||
Symbol string `json:"symbol,omitempty"`
|
||||
Count int `json:"count,omitempty"`
|
||||
Len int `json:"len,omitempty"`
|
||||
}
|
||||
|
||||
// WsResponseMain defines the main websocket response
|
||||
type WsResponseMain struct {
|
||||
MsgType string `json:"MsgType"`
|
||||
CRID string `json:"CRID"`
|
||||
RC interface{} `json:"RC"`
|
||||
Reason string `json:"Reason"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
|
||||
// WsOrderbookSnapshot defines an orderbook from the websocket
|
||||
type WsOrderbookSnapshot struct {
|
||||
Timestamp int64 `json:"Timestamp"`
|
||||
Symbol string `json:"Symbol"`
|
||||
Version int64 `json:"Version"`
|
||||
Type string `json:"Type"`
|
||||
Content string `json:"Content"`
|
||||
List []struct {
|
||||
Side string `json:"Side"`
|
||||
Size interface{} `json:"Size"`
|
||||
Price float64 `json:"Price"`
|
||||
} `json:"List"`
|
||||
MsgType string `json:"MsgType"`
|
||||
}
|
||||
|
||||
// WsOrderbookSnapshotOld defines an old orderbook from the websocket connection
|
||||
type WsOrderbookSnapshotOld struct {
|
||||
MsgType string `json:"MsgType"`
|
||||
Symbol string `json:"Symbol"`
|
||||
Data map[string][]interface{} `json:"Data"`
|
||||
Timestamp int64 `json:"Timestamp"`
|
||||
}
|
||||
|
||||
// WsTrades defines trading data from the websocket
|
||||
type WsTrades struct {
|
||||
Trades []struct {
|
||||
TID int64 `json:"TID"`
|
||||
Timestamp int64 `json:"Timestamp"`
|
||||
Symbol string `json:"Symbol"`
|
||||
Side string `json:"Side"`
|
||||
Size float64 `json:"Size"`
|
||||
Price float64 `json:"Price"`
|
||||
MsgType string `json:"MsgType"`
|
||||
} `json:"Trades"`
|
||||
RC int64 `json:"RC"`
|
||||
CRID string `json:"CRID"`
|
||||
Reason string `json:"Reason"`
|
||||
MsgType string `json:"MsgType"`
|
||||
}
|
||||
|
||||
// WsTicker defines ticker data from the websocket
|
||||
type WsTicker struct {
|
||||
Symbol string `json:"Symbol"`
|
||||
BidPrice float64 `json:"BidPrice"`
|
||||
AskPrice float64 `json:"AskPrice"`
|
||||
Open float64 `json:"Open"`
|
||||
High float64 `json:"High"`
|
||||
Low float64 `json:"Low"`
|
||||
Last float64 `json:"Last"`
|
||||
LastQuantity float64 `json:"LastQuantity"`
|
||||
PrevCls float64 `json:"PrevCls"`
|
||||
Volume float64 `json:"Volume"`
|
||||
Volume24H float64 `json:"Volume24H"`
|
||||
Timestamp int64 `json:"Timestamp"`
|
||||
ExecutionLimitDown float64 `json:"ExecutionLimitDown"`
|
||||
ExecutionLimitUp float64 `json:"ExecutionLimitUp"`
|
||||
MsgType string `json:"MsgType"`
|
||||
}
|
||||
|
||||
// WithdrawalFees the large list of predefined withdrawal fees
|
||||
// Prone to change
|
||||
var WithdrawalFees = map[currency.Code]float64{
|
||||
currency.USD: 0.005,
|
||||
currency.USDT: 10,
|
||||
currency.BTC: 0.001,
|
||||
currency.ETH: 0.01,
|
||||
currency.BCH: 0.0001,
|
||||
currency.LTC: 0.001,
|
||||
currency.DASH: 0.002,
|
||||
}
|
||||
@@ -1,539 +0,0 @@
|
||||
package btcc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/assets"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
log "github.com/thrasher-/gocryptotrader/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
btccSocketioAddress = "wss://ws.btcc.com"
|
||||
|
||||
msgTypeHeartBeat = "Heartbeat"
|
||||
msgTypeGetActiveContracts = "GetActiveContractsResponse"
|
||||
msgTypeQuote = "QuoteResponse"
|
||||
msgTypeLogin = "LoginResponse"
|
||||
msgTypeAccountInfo = "AccountInfo"
|
||||
msgTypeExecReport = "ExecReport"
|
||||
msgTypePlaceOrder = "PlaceOrderResponse"
|
||||
msgTypeCancelAllOrders = "CancelAllOrdersResponse"
|
||||
msgTypeCancelOrder = "CancelOrderResponse"
|
||||
msgTypeCancelReplaceOrder = "CancelReplaceOrderResponse"
|
||||
msgTypeGetAccountInfo = "GetAccountInfoResponse"
|
||||
msgTypeRetrieveOrder = "RetrieveOrderResponse"
|
||||
msgTypeGetTrades = "GetTradesResponse"
|
||||
|
||||
msgTypeAllTickers = "AllTickersResponse"
|
||||
)
|
||||
|
||||
var (
|
||||
mtx sync.Mutex
|
||||
)
|
||||
|
||||
// WsConnect initiates a websocket client connection
|
||||
func (b *BTCC) WsConnect() error {
|
||||
if !b.Websocket.IsEnabled() || !b.IsEnabled() {
|
||||
return errors.New(exchange.WebsocketNotEnabled)
|
||||
}
|
||||
|
||||
var dialer websocket.Dialer
|
||||
var err error
|
||||
|
||||
if b.Websocket.GetProxyAddress() != "" {
|
||||
var proxy *url.URL
|
||||
proxy, err = url.Parse(b.Websocket.GetProxyAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dialer.Proxy = http.ProxyURL(proxy)
|
||||
}
|
||||
|
||||
b.Conn, _, err = dialer.Dial(b.Websocket.GetWebsocketURL(), http.Header{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = b.WsUpdateCurrencyPairs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go b.WsHandleData()
|
||||
b.GenerateDefaultSubscriptions()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WsReadData reads data from the websocket connection
|
||||
func (b *BTCC) WsReadData() (exchange.WebsocketResponse, error) {
|
||||
mtx.Lock()
|
||||
_, resp, err := b.Conn.ReadMessage()
|
||||
mtx.Unlock()
|
||||
if err != nil {
|
||||
return exchange.WebsocketResponse{}, err
|
||||
}
|
||||
|
||||
b.Websocket.TrafficAlert <- struct{}{}
|
||||
|
||||
return exchange.WebsocketResponse{
|
||||
Raw: resp,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WsHandleData handles read data
|
||||
func (b *BTCC) WsHandleData() {
|
||||
b.Websocket.Wg.Add(1)
|
||||
|
||||
defer func() {
|
||||
err := b.Conn.Close()
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- fmt.Errorf("btcc_websocket.go - Unable to close Websocket connection. Error: %s",
|
||||
err)
|
||||
}
|
||||
b.Websocket.Wg.Done()
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-b.Websocket.ShutdownC:
|
||||
return
|
||||
|
||||
default:
|
||||
resp, err := b.WsReadData()
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
return
|
||||
}
|
||||
|
||||
var Result WsResponseMain
|
||||
err = common.JSONDecode(resp.Raw, &Result)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
|
||||
switch Result.MsgType {
|
||||
case msgTypeHeartBeat:
|
||||
|
||||
case msgTypeGetActiveContracts:
|
||||
log.Debugf("Active Contracts: %s", resp.Raw)
|
||||
|
||||
case msgTypeQuote:
|
||||
log.Debugf("Quotes: %s", resp.Raw)
|
||||
|
||||
case msgTypeLogin:
|
||||
log.Debugf("Login: %s", resp.Raw)
|
||||
|
||||
case msgTypeAccountInfo:
|
||||
log.Debugf("Account info: %s", resp.Raw)
|
||||
|
||||
case msgTypeExecReport:
|
||||
log.Debugf("Exec Report: %s", resp.Raw)
|
||||
|
||||
case msgTypePlaceOrder:
|
||||
log.Debugf("Place order: %s", resp.Raw)
|
||||
|
||||
case msgTypeCancelAllOrders:
|
||||
log.Debugf("Cancel All orders: %s", resp.Raw)
|
||||
|
||||
case msgTypeCancelOrder:
|
||||
log.Debugf("Cancel order: %s", resp.Raw)
|
||||
|
||||
case msgTypeCancelReplaceOrder:
|
||||
log.Debugf("Replace order: %s", resp.Raw)
|
||||
|
||||
case msgTypeGetAccountInfo:
|
||||
log.Debugf("Account info: %s", resp.Raw)
|
||||
|
||||
case msgTypeRetrieveOrder:
|
||||
log.Debugf("Retrieve order: %s", resp.Raw)
|
||||
|
||||
case msgTypeGetTrades:
|
||||
var trades WsTrades
|
||||
|
||||
err = common.JSONDecode(resp.Raw, &trades)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
|
||||
case "OrderBook":
|
||||
// NOTE: This seems to be a websocket update not reflected in
|
||||
// current API docs, this comes in conjunction with the other
|
||||
// orderbook feeds
|
||||
var orderbook WsOrderbookSnapshot
|
||||
|
||||
err = common.JSONDecode(resp.Raw, &orderbook)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
|
||||
switch orderbook.Type {
|
||||
case "F":
|
||||
err = b.WsProcessOrderbookSnapshot(&orderbook)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
}
|
||||
|
||||
case "I":
|
||||
err = b.WsProcessOrderbookUpdate(&orderbook)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
}
|
||||
}
|
||||
|
||||
case "SubOrderBookResponse":
|
||||
|
||||
case "Ticker":
|
||||
var ticker WsTicker
|
||||
|
||||
err = common.JSONDecode(resp.Raw, &ticker)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
|
||||
tick := exchange.TickerData{}
|
||||
tick.AssetType = assets.AssetTypeSpot
|
||||
tick.ClosePrice = ticker.PrevCls
|
||||
tick.Exchange = b.GetName()
|
||||
tick.HighPrice = ticker.High
|
||||
tick.LowPrice = ticker.Low
|
||||
tick.OpenPrice = ticker.Open
|
||||
tick.Pair = currency.NewPairFromString(ticker.Symbol)
|
||||
tick.Quantity = ticker.Volume
|
||||
timestamp := time.Unix(ticker.Timestamp, 0)
|
||||
tick.Timestamp = timestamp
|
||||
|
||||
b.Websocket.DataHandler <- tick
|
||||
|
||||
default:
|
||||
|
||||
if common.StringContains(Result.MsgType, "OrderBook") {
|
||||
var oldOrderbookType WsOrderbookSnapshotOld
|
||||
err = common.JSONDecode(resp.Raw, &oldOrderbookType)
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
|
||||
symbol := common.SplitStrings(Result.MsgType, ".")
|
||||
err = b.WsProcessOldOrderbookSnapshot(oldOrderbookType, symbol[1])
|
||||
if err != nil {
|
||||
b.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WsUpdateCurrencyPairs updates currency pairs from the websocket connection
|
||||
func (b *BTCC) WsUpdateCurrencyPairs() error {
|
||||
var currencyResponse WsResponseMain
|
||||
for {
|
||||
_, resp, err := b.Conn.ReadMessage()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b.Websocket.TrafficAlert <- struct{}{}
|
||||
|
||||
err = common.JSONDecode(resp, ¤cyResponse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch currencyResponse.MsgType {
|
||||
case msgTypeAllTickers:
|
||||
var tickers WsAllTickerData
|
||||
err := common.JSONDecode(currencyResponse.Data, &tickers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var availableTickers currency.Pairs
|
||||
for i := range tickers {
|
||||
availableTickers = append(availableTickers,
|
||||
currency.NewPairFromString(tickers[i].Symbol))
|
||||
}
|
||||
|
||||
err = b.UpdatePairs(availableTickers, assets.AssetTypeSpot, false, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s failed to update available currencies. %s",
|
||||
b.Name,
|
||||
err)
|
||||
}
|
||||
|
||||
case "Heartbeat":
|
||||
|
||||
default:
|
||||
return fmt.Errorf("btcc_websocket.go error - Updating currency pairs resp incorrect: %s",
|
||||
string(resp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WsProcessOrderbookSnapshot processes a new orderbook snapshot
|
||||
func (b *BTCC) WsProcessOrderbookSnapshot(ob *WsOrderbookSnapshot) error {
|
||||
var asks, bids []orderbook.Item
|
||||
for _, data := range ob.List {
|
||||
var newSize float64
|
||||
switch result := data.Size.(type) {
|
||||
case float64:
|
||||
newSize = result
|
||||
case string:
|
||||
var err error
|
||||
newSize, err = strconv.ParseFloat(result, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if data.Side == "1" {
|
||||
asks = append(asks, orderbook.Item{Price: data.Price, Amount: newSize})
|
||||
continue
|
||||
}
|
||||
|
||||
bids = append(bids, orderbook.Item{Price: data.Price, Amount: newSize})
|
||||
}
|
||||
|
||||
var newOrderBook orderbook.Base
|
||||
|
||||
newOrderBook.Asks = asks
|
||||
newOrderBook.AssetType = assets.AssetTypeSpot
|
||||
newOrderBook.Bids = bids
|
||||
newOrderBook.Pair = currency.NewPairFromString(ob.Symbol)
|
||||
|
||||
err := b.Websocket.Orderbook.LoadSnapshot(&newOrderBook, b.GetName(), false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
|
||||
Exchange: b.GetName(),
|
||||
Asset: assets.AssetTypeSpot,
|
||||
Pair: currency.NewPairFromString(ob.Symbol),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WsProcessOrderbookUpdate processes an orderbook update
|
||||
func (b *BTCC) WsProcessOrderbookUpdate(ob *WsOrderbookSnapshot) error {
|
||||
var asks, bids []orderbook.Item
|
||||
for _, data := range ob.List {
|
||||
var newSize float64
|
||||
switch d := data.Size.(type) {
|
||||
case float64:
|
||||
newSize = d
|
||||
case string:
|
||||
var err error
|
||||
newSize, err = strconv.ParseFloat(d, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if data.Side == "1" {
|
||||
if newSize < 0 {
|
||||
asks = append(asks, orderbook.Item{Price: data.Price, Amount: 0})
|
||||
continue
|
||||
}
|
||||
asks = append(asks, orderbook.Item{Price: data.Price, Amount: newSize})
|
||||
continue
|
||||
}
|
||||
|
||||
if newSize < 0 {
|
||||
bids = append(bids, orderbook.Item{Price: data.Price, Amount: 0})
|
||||
continue
|
||||
}
|
||||
|
||||
bids = append(bids, orderbook.Item{Price: data.Price, Amount: newSize})
|
||||
}
|
||||
|
||||
p := currency.NewPairFromString(ob.Symbol)
|
||||
|
||||
err := b.Websocket.Orderbook.Update(bids, asks, p, time.Now(), b.GetName(), assets.AssetTypeSpot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
|
||||
Exchange: b.GetName(),
|
||||
Asset: assets.AssetTypeSpot,
|
||||
Pair: currency.NewPairFromString(ob.Symbol),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WsProcessOldOrderbookSnapshot processes an old orderbook snapshot
|
||||
func (b *BTCC) WsProcessOldOrderbookSnapshot(ob WsOrderbookSnapshotOld, symbol string) error {
|
||||
var asks, bids []orderbook.Item
|
||||
|
||||
askData := ob.Data["Asks"]
|
||||
bidData := ob.Data["Bids"]
|
||||
|
||||
for _, ask := range askData {
|
||||
data := ask.([]interface{})
|
||||
var price, amount float64
|
||||
|
||||
switch d := data[0].(type) {
|
||||
case string:
|
||||
var err error
|
||||
price, err = strconv.ParseFloat(d, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case float64:
|
||||
price = d
|
||||
}
|
||||
|
||||
switch d := data[0].(type) {
|
||||
case string:
|
||||
var err error
|
||||
amount, err = strconv.ParseFloat(d, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case float64:
|
||||
amount = d
|
||||
}
|
||||
|
||||
asks = append(asks, orderbook.Item{
|
||||
Price: price,
|
||||
Amount: amount,
|
||||
})
|
||||
}
|
||||
|
||||
for _, bid := range bidData {
|
||||
data := bid.([]interface{})
|
||||
var price, amount float64
|
||||
|
||||
switch d := data[1].(type) {
|
||||
case string:
|
||||
var err error
|
||||
price, err = strconv.ParseFloat(d, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case float64:
|
||||
price = d
|
||||
}
|
||||
|
||||
switch d := data[1].(type) {
|
||||
case string:
|
||||
var err error
|
||||
amount, err = strconv.ParseFloat(d, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case float64:
|
||||
amount = d
|
||||
}
|
||||
|
||||
bids = append(bids, orderbook.Item{
|
||||
Price: price,
|
||||
Amount: amount,
|
||||
})
|
||||
}
|
||||
|
||||
p := currency.NewPairFromString(symbol)
|
||||
err := b.Websocket.Orderbook.Update(bids, asks, p, time.Now(), b.GetName(), assets.AssetTypeSpot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
|
||||
Exchange: b.GetName(),
|
||||
Pair: p,
|
||||
Asset: assets.AssetTypeSpot,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateDefaultSubscriptions Adds default subscriptions to websocket to be handled by ManageSubscriptions()
|
||||
func (b *BTCC) GenerateDefaultSubscriptions() {
|
||||
subscriptions := []exchange.WebsocketChannelSubscription{}
|
||||
subscriptions = append(subscriptions, exchange.WebsocketChannelSubscription{
|
||||
Channel: "SubscribeAllTickers",
|
||||
})
|
||||
|
||||
var channels = []string{"SubOrderBook", "GetTrades", "Subscribe"}
|
||||
enabledCurrencies := b.GetEnabledPairs(assets.AssetTypeSpot)
|
||||
for i := range channels {
|
||||
for j := range enabledCurrencies {
|
||||
params := make(map[string]interface{})
|
||||
if channels[i] == "SubOrderBook" {
|
||||
params["len"] = "100"
|
||||
} else if channels[i] == "GetTrades" {
|
||||
params["count"] = "100"
|
||||
}
|
||||
subscriptions = append(subscriptions, exchange.WebsocketChannelSubscription{
|
||||
Channel: channels[i],
|
||||
Currency: enabledCurrencies[j],
|
||||
Params: params,
|
||||
})
|
||||
}
|
||||
}
|
||||
b.Websocket.SubscribeToChannels(subscriptions)
|
||||
}
|
||||
|
||||
// Subscribe sends a websocket message to receive data from the channel
|
||||
func (b *BTCC) Subscribe(channelToSubscribe exchange.WebsocketChannelSubscription) error {
|
||||
subscription := WsOutgoing{
|
||||
Action: channelToSubscribe.Channel,
|
||||
Symbol: channelToSubscribe.Currency.String(),
|
||||
}
|
||||
if subscription.Action == "SubOrderBook" {
|
||||
subscription.Len = 100
|
||||
} else if subscription.Action == "GetTrades" {
|
||||
subscription.Count = 100
|
||||
}
|
||||
|
||||
return b.wsSend(subscription)
|
||||
}
|
||||
|
||||
// Unsubscribe sends a websocket message to stop receiving data from the channel
|
||||
func (b *BTCC) Unsubscribe(channelToSubscribe exchange.WebsocketChannelSubscription) error {
|
||||
subscription := WsOutgoing{}
|
||||
switch channelToSubscribe.Channel {
|
||||
case "SubOrderBook":
|
||||
subscription.Action = "UnSubOrderBook"
|
||||
subscription.Symbol = channelToSubscribe.Currency.String()
|
||||
case "Subscribe":
|
||||
subscription.Action = "UnSubscribe"
|
||||
subscription.Symbol = channelToSubscribe.Currency.String()
|
||||
case "SubscribeAllTickers":
|
||||
subscription.Action = "UnSubscribeAllTickers"
|
||||
}
|
||||
|
||||
return b.wsSend(subscription)
|
||||
}
|
||||
|
||||
// WsSend sends data to the websocket server
|
||||
func (b *BTCC) wsSend(data interface{}) error {
|
||||
b.wsRequestMtx.Lock()
|
||||
defer b.wsRequestMtx.Unlock()
|
||||
if b.Verbose {
|
||||
log.Debugf("%v sending message to websocket %v", b.Name, data)
|
||||
}
|
||||
return b.Conn.WriteJSON(data)
|
||||
}
|
||||
@@ -1,295 +0,0 @@
|
||||
package btcc
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
"github.com/thrasher-/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/assets"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/request"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
log "github.com/thrasher-/gocryptotrader/logger"
|
||||
)
|
||||
|
||||
// GetDefaultConfig returns a default exchange config
|
||||
func (b *BTCC) GetDefaultConfig() (*config.ExchangeConfig, error) {
|
||||
b.SetDefaults()
|
||||
exchCfg := new(config.ExchangeConfig)
|
||||
exchCfg.Name = b.Name
|
||||
exchCfg.HTTPTimeout = exchange.DefaultHTTPTimeout
|
||||
exchCfg.BaseCurrencies = b.BaseCurrencies
|
||||
|
||||
err := b.SetupDefaults(exchCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if b.Features.Supports.RESTCapabilities.AutoPairUpdates {
|
||||
err = b.UpdateTradablePairs(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return exchCfg, nil
|
||||
}
|
||||
|
||||
// SetDefaults sets default values for the exchange
|
||||
func (b *BTCC) SetDefaults() {
|
||||
b.Name = "BTCC"
|
||||
b.Enabled = true
|
||||
b.Verbose = true
|
||||
b.API.CredentialsValidator.RequiresKey = true
|
||||
b.API.CredentialsValidator.RequiresSecret = true
|
||||
|
||||
b.CurrencyPairs = currency.PairsManager{
|
||||
AssetTypes: assets.AssetTypes{
|
||||
assets.AssetTypeSpot,
|
||||
},
|
||||
UseGlobalFormat: true,
|
||||
RequestFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
},
|
||||
ConfigFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
},
|
||||
}
|
||||
|
||||
b.Features = exchange.Features{
|
||||
Supports: exchange.FeaturesSupported{
|
||||
REST: false,
|
||||
Websocket: true,
|
||||
RESTCapabilities: exchange.ProtocolFeatures{
|
||||
AutoPairUpdates: false,
|
||||
TickerBatching: false,
|
||||
},
|
||||
WithdrawPermissions: exchange.NoAPIWithdrawalMethods,
|
||||
},
|
||||
Enabled: exchange.FeaturesEnabled{
|
||||
AutoPairUpdates: false,
|
||||
},
|
||||
}
|
||||
|
||||
b.Requester = request.New(b.Name,
|
||||
request.NewRateLimit(time.Second, btccAuthRate),
|
||||
request.NewRateLimit(time.Second, btccUnauthRate),
|
||||
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout))
|
||||
|
||||
b.WebsocketInit()
|
||||
b.Websocket.Functionality =
|
||||
exchange.WebsocketSubscribeSupported |
|
||||
exchange.WebsocketUnsubscribeSupported
|
||||
}
|
||||
|
||||
// Setup is run on startup to setup exchange with config values
|
||||
func (b *BTCC) Setup(exch *config.ExchangeConfig) error {
|
||||
if !exch.Enabled {
|
||||
b.SetEnabled(false)
|
||||
return nil
|
||||
}
|
||||
|
||||
err := b.SetupDefaults(exch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return b.WebsocketSetup(b.WsConnect,
|
||||
b.Subscribe,
|
||||
b.Unsubscribe,
|
||||
exch.Name,
|
||||
exch.Features.Enabled.Websocket,
|
||||
exch.Verbose,
|
||||
btccSocketioAddress,
|
||||
exch.API.Endpoints.WebsocketURL)
|
||||
}
|
||||
|
||||
// Start starts the BTCC go routine
|
||||
func (b *BTCC) Start(wg *sync.WaitGroup) {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
b.Run()
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
// Run implements the BTCC wrapper
|
||||
func (b *BTCC) Run() {
|
||||
if b.Verbose {
|
||||
log.Debugf("%s Websocket: %s.", b.GetName(), common.IsEnabled(b.Websocket.IsEnabled()))
|
||||
b.PrintEnabledPairs()
|
||||
}
|
||||
|
||||
if common.StringDataContains(b.GetEnabledPairs(assets.AssetTypeSpot).Strings(), "CNY") ||
|
||||
common.StringDataContains(b.GetAvailablePairs(assets.AssetTypeSpot).Strings(), "CNY") ||
|
||||
common.StringDataContains(b.BaseCurrencies.Strings(), "CNY") {
|
||||
log.Warn("WARNING: BTCC only supports BTCUSD now, upgrading available, enabled and base currencies to BTCUSD/USD")
|
||||
pairs := currency.NewPairsFromStrings([]string{"BTCUSD"})
|
||||
cfg := config.GetConfig()
|
||||
exchCfg, err := cfg.GetExchangeConfig(b.Name)
|
||||
if err != nil {
|
||||
log.Errorf("%s failed to get exchange config. %s\n", b.Name, err)
|
||||
return
|
||||
}
|
||||
|
||||
exchCfg.BaseCurrencies = currency.Currencies{currency.USD}
|
||||
exchCfg.CurrencyPairs.StorePairs(assets.AssetTypeSpot, pairs, true)
|
||||
exchCfg.CurrencyPairs.StorePairs(assets.AssetTypeSpot, pairs, false)
|
||||
b.BaseCurrencies = currency.Currencies{currency.USD}
|
||||
|
||||
err = b.UpdatePairs(pairs, assets.AssetTypeSpot, false, true)
|
||||
if err != nil {
|
||||
log.Errorf("%s failed to update available currencies. %s\n", b.Name, err)
|
||||
}
|
||||
|
||||
err = b.UpdatePairs(pairs, assets.AssetTypeSpot, true, true)
|
||||
if err != nil {
|
||||
log.Errorf("%s failed to update enabled currencies. %s\n", b.Name, err)
|
||||
}
|
||||
|
||||
err = cfg.UpdateExchangeConfig(exchCfg)
|
||||
if err != nil {
|
||||
log.Errorf("%s failed to update config. %s\n", b.Name, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FetchTradablePairs returns a list of the exchanges tradable pairs
|
||||
func (b *BTCC) FetchTradablePairs(asset assets.AssetType) ([]string, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// UpdateTradablePairs updates the exchanges available pairs and stores
|
||||
// them in the exchanges config
|
||||
func (b *BTCC) UpdateTradablePairs(forceUpdate bool) error {
|
||||
return common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// UpdateTicker updates and returns the ticker for a currency pair
|
||||
func (b *BTCC) UpdateTicker(p currency.Pair, assetType assets.AssetType) (ticker.Price, error) {
|
||||
return ticker.Price{}, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// FetchTicker returns the ticker for a currency pair
|
||||
func (b *BTCC) FetchTicker(p currency.Pair, assetType assets.AssetType) (ticker.Price, error) {
|
||||
return ticker.Price{}, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// FetchOrderbook returns the orderbook for a currency pair
|
||||
func (b *BTCC) FetchOrderbook(p currency.Pair, assetType assets.AssetType) (orderbook.Base, error) {
|
||||
return orderbook.Base{}, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// UpdateOrderbook updates and returns the orderbook for a currency pair
|
||||
func (b *BTCC) UpdateOrderbook(p currency.Pair, assetType assets.AssetType) (orderbook.Base, error) {
|
||||
return orderbook.Base{}, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetAccountInfo : Retrieves balances for all enabled currencies for
|
||||
// the Kraken exchange - TODO
|
||||
func (b *BTCC) GetAccountInfo() (exchange.AccountInfo, error) {
|
||||
return exchange.AccountInfo{}, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetFundingHistory returns funding history, deposits and
|
||||
// withdrawals
|
||||
func (b *BTCC) GetFundingHistory() ([]exchange.FundHistory, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetExchangeHistory returns historic trade data since exchange opening.
|
||||
func (b *BTCC) GetExchangeHistory(p currency.Pair, assetType assets.AssetType) ([]exchange.TradeHistory, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (b *BTCC) SubmitOrder(p currency.Pair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) {
|
||||
return exchange.SubmitOrderResponse{}, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// ModifyOrder will allow of changing orderbook placement and limit to
|
||||
// market conversion
|
||||
func (b *BTCC) ModifyOrder(action *exchange.ModifyOrder) (string, error) {
|
||||
return "", common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// CancelOrder cancels an order by its corresponding ID number
|
||||
func (b *BTCC) CancelOrder(order *exchange.OrderCancellation) error {
|
||||
return common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// CancelAllOrders cancels all orders associated with a currency pair
|
||||
func (b *BTCC) CancelAllOrders(orderCancellation *exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) {
|
||||
return exchange.CancelAllOrdersResponse{}, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetOrderInfo returns information on a current open order
|
||||
func (b *BTCC) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
|
||||
return exchange.OrderDetail{}, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetDepositAddress returns a deposit address for a specified currency
|
||||
func (b *BTCC) GetDepositAddress(cryptocurrency currency.Code, accountID string) (string, error) {
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func (b *BTCC) WithdrawCryptocurrencyFunds(withdrawRequest *exchange.CryptoWithdrawRequest) (string, error) {
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// WithdrawFiatFunds returns a withdrawal ID when a
|
||||
// withdrawal is submitted
|
||||
func (b *BTCC) WithdrawFiatFunds(withdrawRequest *exchange.FiatWithdrawRequest) (string, error) {
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a
|
||||
// withdrawal is submitted
|
||||
func (b *BTCC) WithdrawFiatFundsToInternationalBank(withdrawRequest *exchange.FiatWithdrawRequest) (string, error) {
|
||||
return "", common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetWebsocket returns a pointer to the exchange websocket
|
||||
func (b *BTCC) GetWebsocket() (*exchange.Websocket, error) {
|
||||
return b.Websocket, nil
|
||||
}
|
||||
|
||||
// GetFeeByType returns an estimate of fee based on type of transaction
|
||||
func (b *BTCC) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
if !b.AllowAuthenticatedRequest() && // Todo check connection status
|
||||
feeBuilder.FeeType == exchange.CryptocurrencyTradeFee {
|
||||
feeBuilder.FeeType = exchange.OfflineTradeFee
|
||||
}
|
||||
return b.GetFee(feeBuilder)
|
||||
}
|
||||
|
||||
// GetActiveOrders retrieves any orders that are active/open
|
||||
func (b *BTCC) GetActiveOrders(getOrdersRequest *exchange.GetOrdersRequest) ([]exchange.OrderDetail, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetOrderHistory retrieves account order information
|
||||
// Can Limit response to specific order status
|
||||
func (b *BTCC) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest) ([]exchange.OrderDetail, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// SubscribeToWebsocketChannels appends to ChannelsToSubscribe
|
||||
// which lets websocket.manageSubscriptions handle subscribing
|
||||
func (b *BTCC) SubscribeToWebsocketChannels(channels []exchange.WebsocketChannelSubscription) error {
|
||||
b.Websocket.SubscribeToChannels(channels)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnsubscribeToWebsocketChannels removes from ChannelsToSubscribe
|
||||
// which lets websocket.manageSubscriptions handle unsubscribing
|
||||
func (b *BTCC) UnsubscribeToWebsocketChannels(channels []exchange.WebsocketChannelSubscription) error {
|
||||
b.Websocket.UnsubscribeToChannels(channels)
|
||||
return nil
|
||||
}
|
||||
@@ -306,14 +306,13 @@ func (b *BTSE) CancelOrder(order *exchange.OrderCancellation) error {
|
||||
// If product ID is sent, all orders of that specified market will be cancelled
|
||||
// If not specified, all orders of all markets will be cancelled
|
||||
func (b *BTSE) CancelAllOrders(orderCancellation *exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) {
|
||||
var resp exchange.CancelAllOrdersResponse
|
||||
r, err := b.CancelOrders(b.FormatExchangeCurrency(
|
||||
orderCancellation.CurrencyPair, assets.AssetTypeSpot).String(),
|
||||
)
|
||||
orderCancellation.CurrencyPair, assets.AssetTypeSpot).String())
|
||||
if err != nil {
|
||||
return exchange.CancelAllOrdersResponse{}, err
|
||||
return resp, err
|
||||
}
|
||||
|
||||
var resp exchange.CancelAllOrdersResponse
|
||||
switch r.Code {
|
||||
case -1:
|
||||
return resp, errors.New("order cancellation unsuccessful")
|
||||
|
||||
@@ -336,7 +336,6 @@ func (e *EXMO) ModifyOrder(action *exchange.ModifyOrder) (string, error) {
|
||||
// CancelOrder cancels an order by its corresponding ID number
|
||||
func (e *EXMO) CancelOrder(order *exchange.OrderCancellation) error {
|
||||
orderIDInt, err := strconv.ParseInt(order.OrderID, 10, 64)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -349,6 +348,7 @@ func (e *EXMO) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.CancelAl
|
||||
cancelAllOrdersResponse := exchange.CancelAllOrdersResponse{
|
||||
OrderStatus: make(map[string]string),
|
||||
}
|
||||
|
||||
openOrders, err := e.GetOpenOrders()
|
||||
if err != nil {
|
||||
return cancelAllOrdersResponse, err
|
||||
@@ -388,7 +388,10 @@ func (e *EXMO) GetDepositAddress(cryptocurrency currency.Code, _ string) (string
|
||||
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func (e *EXMO) WithdrawCryptocurrencyFunds(withdrawRequest *exchange.CryptoWithdrawRequest) (string, error) {
|
||||
resp, err := e.WithdrawCryptocurrency(withdrawRequest.Currency.String(), withdrawRequest.Address, withdrawRequest.AddressTag, withdrawRequest.Amount)
|
||||
resp, err := e.WithdrawCryptocurrency(withdrawRequest.Currency.String(),
|
||||
withdrawRequest.Address,
|
||||
withdrawRequest.AddressTag,
|
||||
withdrawRequest.Amount)
|
||||
|
||||
return fmt.Sprintf("%v", resp), err
|
||||
}
|
||||
@@ -425,6 +428,7 @@ func (e *EXMO) GetActiveOrders(getOrdersRequest *exchange.GetOrdersRequest) ([]e
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var orders []exchange.OrderDetail
|
||||
for _, order := range resp {
|
||||
symbol := currency.NewPairDelimiter(order.Pair, "_")
|
||||
|
||||
@@ -377,15 +377,15 @@ func (g *Gateio) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.Cancel
|
||||
return cancelAllOrdersResponse, err
|
||||
}
|
||||
|
||||
uniqueSymbols := make(map[string]string)
|
||||
uniqueSymbols := make(map[string]int)
|
||||
for i := range openOrders.Orders {
|
||||
uniqueSymbols[openOrders.Orders[i].CurrencyPair] = openOrders.Orders[i].CurrencyPair
|
||||
uniqueSymbols[openOrders.Orders[i].CurrencyPair]++
|
||||
}
|
||||
|
||||
for unique := range uniqueSymbols {
|
||||
err = g.CancelAllExistingOrders(-1, uniqueSymbols[unique])
|
||||
err = g.CancelAllExistingOrders(-1, unique)
|
||||
if err != nil {
|
||||
return cancelAllOrdersResponse, err
|
||||
cancelAllOrdersResponse.OrderStatus[unique] = err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -256,12 +256,12 @@ func (g *Gemini) CancelExistingOrder(orderID int64) (Order, error) {
|
||||
// the UI. If sessions = true will only cancel the order that is called on this
|
||||
// session asssociated with the APIKEY
|
||||
func (g *Gemini) CancelExistingOrders(cancelBySession bool) (OrderResult, error) {
|
||||
response := OrderResult{}
|
||||
path := geminiOrderCancelAll
|
||||
if cancelBySession {
|
||||
path = geminiOrderCancelSession
|
||||
}
|
||||
|
||||
var response OrderResult
|
||||
err := g.SendAuthenticatedHTTPRequest(http.MethodPost, path, nil, &response)
|
||||
if err != nil {
|
||||
return response, err
|
||||
|
||||
@@ -334,13 +334,19 @@ func (h *HitBTC) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.Cancel
|
||||
cancelAllOrdersResponse := exchange.CancelAllOrdersResponse{
|
||||
OrderStatus: make(map[string]string),
|
||||
}
|
||||
|
||||
resp, err := h.CancelAllExistingOrders()
|
||||
if err != nil {
|
||||
return cancelAllOrdersResponse, err
|
||||
}
|
||||
|
||||
for i := range resp {
|
||||
cancelAllOrdersResponse.OrderStatus[strconv.FormatInt(resp[i].ID, 10)] = fmt.Sprintf("Could not cancel order %v. Status: %v", resp[i].ID, resp[i].Status)
|
||||
if resp[i].Status != "canceled" {
|
||||
cancelAllOrdersResponse.OrderStatus[strconv.FormatInt(resp[i].ID, 10)] =
|
||||
fmt.Sprintf("Could not cancel order %v. Status: %v",
|
||||
resp[i].ID,
|
||||
resp[i].Status)
|
||||
}
|
||||
}
|
||||
|
||||
return cancelAllOrdersResponse, nil
|
||||
|
||||
@@ -22,6 +22,7 @@ const (
|
||||
apiKey = ""
|
||||
apiSecret = ""
|
||||
canManipulateRealOrders = false
|
||||
testSymbol = "btcusdt"
|
||||
)
|
||||
|
||||
var h HUOBI
|
||||
@@ -47,7 +48,7 @@ func TestSetup(t *testing.T) {
|
||||
func TestGetSpotKline(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.GetSpotKline(KlinesRequestParams{
|
||||
Symbol: "btcusdt",
|
||||
Symbol: testSymbol,
|
||||
Period: TimeIntervalHour,
|
||||
Size: 0,
|
||||
})
|
||||
@@ -58,7 +59,7 @@ func TestGetSpotKline(t *testing.T) {
|
||||
|
||||
func TestGetMarketDetailMerged(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.GetMarketDetailMerged("btcusdt")
|
||||
_, err := h.GetMarketDetailMerged(testSymbol)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - Huobi TestGetMarketDetailMerged: %s", err)
|
||||
}
|
||||
@@ -67,7 +68,7 @@ func TestGetMarketDetailMerged(t *testing.T) {
|
||||
func TestGetDepth(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.GetDepth(OrderBookDataRequestParams{
|
||||
Symbol: "btcusdt",
|
||||
Symbol: testSymbol,
|
||||
Type: OrderBookDataRequestParamsTypeStep1,
|
||||
})
|
||||
|
||||
@@ -78,7 +79,7 @@ func TestGetDepth(t *testing.T) {
|
||||
|
||||
func TestGetTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.GetTrades("btcusdt")
|
||||
_, err := h.GetTrades(testSymbol)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - Huobi TestGetTrades: %s", err)
|
||||
}
|
||||
@@ -86,7 +87,7 @@ func TestGetTrades(t *testing.T) {
|
||||
|
||||
func TestGetLatestSpotPrice(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.GetLatestSpotPrice("btcusdt")
|
||||
_, err := h.GetLatestSpotPrice(testSymbol)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - Huobi GetLatestSpotPrice: %s", err)
|
||||
}
|
||||
@@ -94,7 +95,7 @@ func TestGetLatestSpotPrice(t *testing.T) {
|
||||
|
||||
func TestGetTradeHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.GetTradeHistory("btcusdt", "50")
|
||||
_, err := h.GetTradeHistory(testSymbol, "50")
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - Huobi TestGetTradeHistory: %s", err)
|
||||
}
|
||||
@@ -102,7 +103,7 @@ func TestGetTradeHistory(t *testing.T) {
|
||||
|
||||
func TestGetMarketDetail(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.GetMarketDetail("btcusdt")
|
||||
_, err := h.GetMarketDetail(testSymbol)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - Huobi TestGetTradeHistory: %s", err)
|
||||
}
|
||||
@@ -172,7 +173,7 @@ func TestSpotNewOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
arg := SpotNewOrderRequestParams{
|
||||
Symbol: "btcusdt",
|
||||
Symbol: testSymbol,
|
||||
AccountID: 1,
|
||||
Amount: 0.01,
|
||||
Price: 10.1,
|
||||
@@ -210,7 +211,7 @@ func TestGetMarginLoanOrders(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
_, err := h.GetMarginLoanOrders("btcusdt", "", "", "", "", "", "", "")
|
||||
_, err := h.GetMarginLoanOrders(testSymbol, "", "", "", "", "", "", "")
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - Huobi TestGetMarginLoanOrders: %s", err)
|
||||
}
|
||||
@@ -223,7 +224,7 @@ func TestGetMarginAccountBalance(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
_, err := h.GetMarginAccountBalance("btcusdt")
|
||||
_, err := h.GetMarginAccountBalance(testSymbol)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - Huobi TestGetMarginAccountBalance: %s", err)
|
||||
}
|
||||
|
||||
@@ -443,9 +443,7 @@ func (h *HUOBI) CancelOrder(order *exchange.OrderCancellation) error {
|
||||
|
||||
// CancelAllOrders cancels all orders associated with a currency pair
|
||||
func (h *HUOBI) CancelAllOrders(orderCancellation *exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) {
|
||||
cancelAllOrdersResponse := exchange.CancelAllOrdersResponse{
|
||||
OrderStatus: make(map[string]string),
|
||||
}
|
||||
var cancelAllOrdersResponse exchange.CancelAllOrdersResponse
|
||||
for _, currency := range h.GetEnabledPairs(assets.AssetTypeSpot) {
|
||||
resp, err := h.CancelOpenOrdersBatch(orderCancellation.AccountID,
|
||||
h.FormatExchangeCurrency(currency, assets.AssetTypeSpot).String())
|
||||
|
||||
@@ -18,6 +18,7 @@ const (
|
||||
apiKey = ""
|
||||
apiSecret = ""
|
||||
canManipulateRealOrders = false
|
||||
testSymbol = "btcusdt"
|
||||
)
|
||||
|
||||
var h HUOBIHADAX
|
||||
@@ -97,7 +98,7 @@ func TestSetup(t *testing.T) {
|
||||
func TestGetSpotKline(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.GetSpotKline(KlinesRequestParams{
|
||||
Symbol: "hptusdt",
|
||||
Symbol: testSymbol,
|
||||
Period: TimeIntervalHour,
|
||||
Size: 0,
|
||||
})
|
||||
@@ -108,7 +109,7 @@ func TestGetSpotKline(t *testing.T) {
|
||||
|
||||
func TestGetMarketDetailMerged(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.GetMarketDetailMerged("hptusdt")
|
||||
_, err := h.GetMarketDetailMerged(testSymbol)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - Huobi TestGetMarketDetailMerged: %s", err)
|
||||
}
|
||||
@@ -116,7 +117,7 @@ func TestGetMarketDetailMerged(t *testing.T) {
|
||||
|
||||
func TestGetDepth(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.GetDepth("hptusdt", "step1")
|
||||
_, err := h.GetDepth(testSymbol, "step1")
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - Huobi TestGetDepth: %s", err)
|
||||
}
|
||||
@@ -124,7 +125,7 @@ func TestGetDepth(t *testing.T) {
|
||||
|
||||
func TestGetTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.GetTrades("hptusdt")
|
||||
_, err := h.GetTrades(testSymbol)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - Huobi TestGetTrades: %s", err)
|
||||
}
|
||||
@@ -132,7 +133,7 @@ func TestGetTrades(t *testing.T) {
|
||||
|
||||
func TestGetLatestSpotPrice(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.GetLatestSpotPrice("hptusdt")
|
||||
_, err := h.GetLatestSpotPrice(testSymbol)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - Huobi GetLatestSpotPrice: %s", err)
|
||||
}
|
||||
@@ -140,7 +141,7 @@ func TestGetLatestSpotPrice(t *testing.T) {
|
||||
|
||||
func TestGetTradeHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.GetTradeHistory("hptusdt", "50")
|
||||
_, err := h.GetTradeHistory(testSymbol, "50")
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - Huobi TestGetTradeHistory: %s", err)
|
||||
}
|
||||
@@ -148,7 +149,7 @@ func TestGetTradeHistory(t *testing.T) {
|
||||
|
||||
func TestGetMarketDetail(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.GetMarketDetail("hptusdt")
|
||||
_, err := h.GetMarketDetail(testSymbol)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - Huobi TestGetTradeHistory: %s", err)
|
||||
}
|
||||
@@ -218,7 +219,7 @@ func TestSpotNewOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
arg := SpotNewOrderRequestParams{
|
||||
Symbol: "hptusdt",
|
||||
Symbol: testSymbol,
|
||||
AccountID: 000000,
|
||||
Amount: 0.01,
|
||||
Price: 10.1,
|
||||
@@ -266,7 +267,7 @@ func TestGetMarginLoanOrders(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
_, err := h.GetMarginLoanOrders("hptusdt", "", "", "", "", "", "", "")
|
||||
_, err := h.GetMarginLoanOrders(testSymbol, "", "", "", "", "", "", "")
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - Huobi TestGetMarginLoanOrders: %s", err)
|
||||
}
|
||||
@@ -279,7 +280,7 @@ func TestGetMarginAccountBalance(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
_, err := h.GetMarginAccountBalance("hptusdt")
|
||||
_, err := h.GetMarginAccountBalance(testSymbol)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed - Huobi TestGetMarginAccountBalance: %s", err)
|
||||
}
|
||||
|
||||
@@ -406,11 +406,10 @@ func (h *HUOBIHADAX) CancelOrder(order *exchange.OrderCancellation) error {
|
||||
|
||||
// CancelAllOrders cancels all orders associated with a currency pair
|
||||
func (h *HUOBIHADAX) CancelAllOrders(orderCancellation *exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) {
|
||||
cancelAllOrdersResponse := exchange.CancelAllOrdersResponse{
|
||||
OrderStatus: make(map[string]string),
|
||||
}
|
||||
var cancelAllOrdersResponse exchange.CancelAllOrdersResponse
|
||||
for _, currency := range h.GetEnabledPairs(assets.AssetTypeSpot) {
|
||||
resp, err := h.CancelOpenOrdersBatch(orderCancellation.AccountID, h.FormatExchangeCurrency(currency, assets.AssetTypeSpot).String())
|
||||
resp, err := h.CancelOpenOrdersBatch(orderCancellation.AccountID,
|
||||
h.FormatExchangeCurrency(currency, assets.AssetTypeSpot).String())
|
||||
if err != nil {
|
||||
return cancelAllOrdersResponse, err
|
||||
}
|
||||
|
||||
@@ -366,12 +366,10 @@ func (k *Kraken) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.Cancel
|
||||
return cancelAllOrdersResponse, err
|
||||
}
|
||||
|
||||
if openOrders.Count > 0 {
|
||||
for orderID := range openOrders.Open {
|
||||
_, err = k.CancelExistingOrder(orderID)
|
||||
if err != nil {
|
||||
cancelAllOrdersResponse.OrderStatus[orderID] = err.Error()
|
||||
}
|
||||
for orderID := range openOrders.Open {
|
||||
_, err = k.CancelExistingOrder(orderID)
|
||||
if err != nil {
|
||||
cancelAllOrdersResponse.OrderStatus[orderID] = err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -301,9 +301,7 @@ func (l *LakeBTC) CancelOrder(order *exchange.OrderCancellation) error {
|
||||
|
||||
// CancelAllOrders cancels all orders associated with a currency pair
|
||||
func (l *LakeBTC) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.CancelAllOrdersResponse, error) {
|
||||
cancelAllOrdersResponse := exchange.CancelAllOrdersResponse{
|
||||
OrderStatus: make(map[string]string),
|
||||
}
|
||||
var cancelAllOrdersResponse exchange.CancelAllOrdersResponse
|
||||
openOrders, err := l.GetOpenOrders()
|
||||
if err != nil {
|
||||
return cancelAllOrdersResponse, err
|
||||
@@ -311,8 +309,7 @@ func (l *LakeBTC) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.Cance
|
||||
|
||||
var ordersToCancel []string
|
||||
for _, order := range openOrders {
|
||||
orderIDString := strconv.FormatInt(order.ID, 10)
|
||||
ordersToCancel = append(ordersToCancel, orderIDString)
|
||||
ordersToCancel = append(ordersToCancel, strconv.FormatInt(order.ID, 10))
|
||||
}
|
||||
|
||||
return cancelAllOrdersResponse, l.CancelExistingOrders(ordersToCancel)
|
||||
|
||||
@@ -345,7 +345,7 @@ func (l *LocalBitcoins) CancelAllOrders(_ *exchange.OrderCancellation) (exchange
|
||||
adIDString := strconv.FormatInt(ads.AdList[i].Data.AdID, 10)
|
||||
err = l.DeleteAd(adIDString)
|
||||
if err != nil {
|
||||
cancelAllOrdersResponse.OrderStatus[strconv.FormatInt(ads.AdList[i].Data.AdID, 10)] = err.Error()
|
||||
cancelAllOrdersResponse.OrderStatus[adIDString] = err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -253,13 +253,15 @@ func (o *OKGroup) CancelOrder(orderCancellation *exchange.OrderCancellation) (er
|
||||
}
|
||||
|
||||
// CancelAllOrders cancels all orders associated with a currency pair
|
||||
func (o *OKGroup) CancelAllOrders(orderCancellation *exchange.OrderCancellation) (resp exchange.CancelAllOrdersResponse, _ error) {
|
||||
func (o *OKGroup) CancelAllOrders(orderCancellation *exchange.OrderCancellation) (resp exchange.CancelAllOrdersResponse, err error) {
|
||||
orderIDs := strings.Split(orderCancellation.OrderID, ",")
|
||||
resp.OrderStatus = make(map[string]string)
|
||||
var orderIDNumbers []int64
|
||||
for _, i := range orderIDs {
|
||||
orderIDNumber, err := strconv.ParseInt(i, 10, 64)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
orderIDNumber, strConvErr := strconv.ParseInt(i, 10, 64)
|
||||
if strConvErr != nil {
|
||||
resp.OrderStatus[i] = strConvErr.Error()
|
||||
continue
|
||||
}
|
||||
orderIDNumbers = append(orderIDNumbers, orderIDNumber)
|
||||
}
|
||||
|
||||
@@ -430,22 +430,21 @@ func (p *Poloniex) PlaceOrder(currency string, rate, amount float64, immediate,
|
||||
}
|
||||
|
||||
// CancelExistingOrder cancels and order by orderID
|
||||
func (p *Poloniex) CancelExistingOrder(orderID int64) (bool, error) {
|
||||
func (p *Poloniex) CancelExistingOrder(orderID int64) error {
|
||||
result := GenericResponse{}
|
||||
values := url.Values{}
|
||||
values.Set("orderNumber", strconv.FormatInt(orderID, 10))
|
||||
|
||||
err := p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexOrderCancel, values, &result)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
return err
|
||||
}
|
||||
|
||||
if result.Success != 1 {
|
||||
return false, errors.New(result.Error)
|
||||
return errors.New(result.Error)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// MoveOrder moves an order
|
||||
|
||||
@@ -348,14 +348,11 @@ func (p *Poloniex) ModifyOrder(action *exchange.ModifyOrder) (string, error) {
|
||||
// CancelOrder cancels an order by its corresponding ID number
|
||||
func (p *Poloniex) CancelOrder(order *exchange.OrderCancellation) error {
|
||||
orderIDInt, err := strconv.ParseInt(order.OrderID, 10, 64)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = p.CancelExistingOrder(orderIDInt)
|
||||
|
||||
return err
|
||||
return p.CancelExistingOrder(orderIDInt)
|
||||
}
|
||||
|
||||
// CancelAllOrders cancels all orders associated with a currency pair
|
||||
@@ -370,7 +367,7 @@ func (p *Poloniex) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.Canc
|
||||
|
||||
for _, openOrderPerCurrency := range openOrders.Data {
|
||||
for _, openOrder := range openOrderPerCurrency {
|
||||
_, err = p.CancelExistingOrder(openOrder.OrderNumber)
|
||||
err = p.CancelExistingOrder(openOrder.OrderNumber)
|
||||
if err != nil {
|
||||
cancelAllOrdersResponse.OrderStatus[strconv.FormatInt(openOrder.OrderNumber, 10)] = err.Error()
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ func TestSwapByPrice(t *testing.T) {
|
||||
Volume: 5,
|
||||
},
|
||||
{
|
||||
Exchange: "btcc",
|
||||
Exchange: "bitfinex",
|
||||
Pair: p,
|
||||
AssetType: assets.AssetTypeSpot,
|
||||
Price: 7863,
|
||||
@@ -73,7 +73,7 @@ func TestSwapByPrice(t *testing.T) {
|
||||
}
|
||||
|
||||
ByPrice.Swap(Items, 0, 1)
|
||||
if Items[0].Exchange != "btcc" || Items[1].Exchange != "bitstamp" {
|
||||
if Items[0].Exchange != "bitfinex" || Items[1].Exchange != "bitstamp" {
|
||||
t.Error("Test Failed - stats SwapByPrice did not swap values.")
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ func TestLessByVolume(t *testing.T) {
|
||||
func TestSwapByVolume(t *testing.T) {
|
||||
ByPrice.Swap(Items, 0, 1)
|
||||
|
||||
if Items[1].Exchange != "btcc" || Items[0].Exchange != "bitstamp" {
|
||||
if Items[1].Exchange != "bitfinex" || Items[0].Exchange != "bitstamp" {
|
||||
t.Error("Test Failed - stats SwapByVolume did not swap values.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ var Exchanges = []string{
|
||||
"bitmex",
|
||||
"bitstamp",
|
||||
"bittrex",
|
||||
"btcc",
|
||||
"btc markets",
|
||||
"btse",
|
||||
"coinbasepro",
|
||||
|
||||
@@ -248,6 +248,7 @@ func TestCreateNewTicker(t *testing.T) {
|
||||
|
||||
func TestProcessTicker(t *testing.T) { // non-appending function to tickers
|
||||
Tickers = []Ticker{}
|
||||
exchName := "bitstamp"
|
||||
newPair := currency.NewPairFromStrings("BTC", "USD")
|
||||
priceStruct := Price{
|
||||
Pair: newPair,
|
||||
@@ -260,17 +261,17 @@ func TestProcessTicker(t *testing.T) { // non-appending function to tickers
|
||||
PriceATH: 1337,
|
||||
}
|
||||
|
||||
err := ProcessTicker("btcc", &Price{}, assets.AssetTypeSpot)
|
||||
err := ProcessTicker(exchName, &Price{}, assets.AssetTypeSpot)
|
||||
if err == nil {
|
||||
t.Fatal("Test failed. ProcessTicker error cannot be nil")
|
||||
}
|
||||
|
||||
err = ProcessTicker("btcc", &priceStruct, assets.AssetTypeSpot)
|
||||
err = ProcessTicker(exchName, &priceStruct, assets.AssetTypeSpot)
|
||||
if err != nil {
|
||||
t.Fatal("Test failed. ProcessTicker error", err)
|
||||
}
|
||||
|
||||
result, err := GetTicker("btcc", newPair, assets.AssetTypeSpot)
|
||||
result, err := GetTicker(exchName, newPair, assets.AssetTypeSpot)
|
||||
if err != nil {
|
||||
t.Fatal("Test failed. TestProcessTicker failed to create and return a new ticker")
|
||||
}
|
||||
@@ -281,17 +282,17 @@ func TestProcessTicker(t *testing.T) { // non-appending function to tickers
|
||||
|
||||
secondPair := currency.NewPairFromStrings("BTC", "AUD")
|
||||
priceStruct.Pair = secondPair
|
||||
err = ProcessTicker("btcc", &priceStruct, assets.AssetTypeSpot)
|
||||
err = ProcessTicker(exchName, &priceStruct, assets.AssetTypeSpot)
|
||||
if err != nil {
|
||||
t.Fatal("Test failed. ProcessTicker error", err)
|
||||
}
|
||||
|
||||
result, err = GetTicker("btcc", secondPair, assets.AssetTypeSpot)
|
||||
result, err = GetTicker(exchName, secondPair, assets.AssetTypeSpot)
|
||||
if err != nil {
|
||||
t.Fatal("Test failed. TestProcessTicker failed to create and return a new ticker")
|
||||
}
|
||||
|
||||
result, err = GetTicker("btcc", newPair, assets.AssetTypeSpot)
|
||||
result, err = GetTicker(exchName, newPair, assets.AssetTypeSpot)
|
||||
if err != nil {
|
||||
t.Fatal("Test failed. TestProcessTicker failed to return an existing ticker")
|
||||
}
|
||||
|
||||
@@ -338,7 +338,8 @@ func (y *Yobit) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.CancelA
|
||||
for key := range activeOrders {
|
||||
orderIDInt, err := strconv.ParseInt(key, 10, 64)
|
||||
if err != nil {
|
||||
return cancelAllOrdersResponse, err
|
||||
cancelAllOrdersResponse.OrderStatus[key] = err.Error()
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = y.CancelExistingOrder(orderIDInt)
|
||||
|
||||
@@ -353,7 +353,6 @@ func (z *ZB) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.CancelAllO
|
||||
}
|
||||
var allOpenOrders []Order
|
||||
for _, currency := range z.GetEnabledPairs(assets.AssetTypeSpot) {
|
||||
var pageNumber int64
|
||||
// Limiting to 10 pages
|
||||
for i := 0; i < 10; i++ {
|
||||
openOrders, err := z.GetUnfinishedOrdersIgnoreTradeType(z.FormatExchangeCurrency(currency, assets.AssetTypeSpot).String(), 1, 10)
|
||||
@@ -366,7 +365,6 @@ func (z *ZB) CancelAllOrders(_ *exchange.OrderCancellation) (exchange.CancelAllO
|
||||
}
|
||||
|
||||
allOpenOrders = append(allOpenOrders, openOrders...)
|
||||
pageNumber++
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
40
testdata/configtest.json
vendored
40
testdata/configtest.json
vendored
@@ -461,46 +461,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BTCC",
|
||||
"enabled": true,
|
||||
"verbose": false,
|
||||
"websocket": false,
|
||||
"useSandbox": false,
|
||||
"restPollingDelay": 10,
|
||||
"httpTimeout": 15000000000,
|
||||
"httpUserAgent": "",
|
||||
"httpDebugging": false,
|
||||
"authenticatedApiSupport": false,
|
||||
"apiKey": "Key",
|
||||
"apiSecret": "Secret",
|
||||
"apiUrl": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
|
||||
"apiUrlSecondary": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
|
||||
"proxyAddress": "",
|
||||
"websocketUrl": "NON_DEFAULT_HTTP_LINK_TO_WEBSOCKET_EXCHANGE_API",
|
||||
"availablePairs": "BTCUSD",
|
||||
"enabledPairs": "BTCUSD",
|
||||
"baseCurrencies": "USD",
|
||||
"assetTypes": "SPOT",
|
||||
"supportsAutoPairUpdates": true,
|
||||
"configCurrencyPairFormat": {
|
||||
"uppercase": true
|
||||
},
|
||||
"requestCurrencyPairFormat": {
|
||||
"uppercase": true
|
||||
},
|
||||
"bankAccounts": [
|
||||
{
|
||||
"bankName": "",
|
||||
"bankAddress": "",
|
||||
"accountName": "",
|
||||
"accountNumber": "",
|
||||
"swiftCode": "",
|
||||
"iban": "",
|
||||
"supportedCurrencies": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BTSE",
|
||||
"enabled": true,
|
||||
|
||||
Reference in New Issue
Block a user