Remove BTCC exchange

This commit is contained in:
Adrian Gallagher
2019-06-03 17:17:17 +10:00
parent 94ac7c917d
commit 8048962b60
16 changed files with 11 additions and 1658 deletions

View File

@@ -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 |

View File

@@ -13,7 +13,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) {

View File

@@ -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,

View File

@@ -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":

View File

@@ -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">
[![Build Status](https://travis-ci.org/thrasher-/gocryptotrader.svg?branch=master)](https://travis-ci.org/thrasher-/gocryptotrader)
[![Software License](https://img.shields.io/badge/License-MIT-orange.svg?style=flat-square)](https://github.com/thrasher-/gocryptotrader/blob/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/thrasher-/gocryptotrader?status.svg)](https://godoc.org/github.com/thrasher-/gocryptotrader/exchanges/btcc)
[![Coverage Status](http://codecov.io/github/thrasher-/gocryptotrader/coverage.svg?branch=master)](http://codecov.io/github/thrasher-/gocryptotrader?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/thrasher-/gocryptotrader)](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.GetTickerPrice()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := b.GetOrderbookEx()
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***

View File

@@ -1,136 +0,0 @@
package btcc
import (
"sync"
"time"
"github.com/gorilla/websocket"
"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/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
log "github.com/thrasher-/gocryptotrader/logger"
)
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
}
// SetDefaults sets default values for the exchange
func (b *BTCC) SetDefaults() {
b.Name = "BTCC"
b.Enabled = false
b.Fee = 0
b.Verbose = false
b.RESTPollingDelay = 10
b.APIWithdrawPermissions = exchange.NoAPIWithdrawalMethods
b.RequestCurrencyPairFormat.Delimiter = ""
b.RequestCurrencyPairFormat.Uppercase = true
b.ConfigCurrencyPairFormat.Delimiter = ""
b.ConfigCurrencyPairFormat.Uppercase = true
b.AssetTypes = []string{ticker.Spot}
b.SupportsAutoPairUpdating = true
b.SupportsRESTTickerBatching = 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) {
if !exch.Enabled {
b.SetEnabled(false)
} else {
b.Enabled = true
b.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
b.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
b.SetHTTPClientTimeout(exch.HTTPTimeout)
b.SetHTTPClientUserAgent(exch.HTTPUserAgent)
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.HTTPDebugging = exch.HTTPDebugging
b.Websocket.SetWsStatusAndConnection(exch.Websocket)
b.BaseCurrencies = exch.BaseCurrencies
b.AvailablePairs = exch.AvailablePairs
b.EnabledPairs = exch.EnabledPairs
err := b.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)
}
err = b.SetAssetTypes()
if err != nil {
log.Fatal(err)
}
err = b.SetAutoPairDefaults()
if err != nil {
log.Fatal(err)
}
err = b.SetAPIURL(exch)
if err != nil {
log.Fatal(err)
}
err = b.SetClientProxyAddress(exch.ProxyAddress)
if err != nil {
log.Fatal(err)
}
err = b.WebsocketSetup(b.WsConnect,
b.Subscribe,
b.Unsubscribe,
exch.Name,
exch.Websocket,
exch.Verbose,
btccSocketioAddress,
exch.WebsocketURL)
if err != nil {
log.Fatal(err)
}
}
}
// 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
}

View File

@@ -1,350 +0,0 @@
package btcc
import (
"testing"
"time"
"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.AuthenticatedAPISupport ||
b.RESTPollingDelay != time.Duration(10) || b.Verbose ||
b.Websocket.IsEnabled() || len(b.BaseCurrencies) < 1 ||
len(b.AvailablePairs) < 1 || len(b.EnabledPairs) < 1 {
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 {
if b.APIKey != "" && b.APIKey != "Key" &&
b.APISecret != "" && b.APISecret != "Secret" {
return true
}
return false
}
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)
var withdrawCryptoRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: currency.LTC,
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
Description: "WITHDRAW IT ALL",
}
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.WithdrawRequest{}
_, 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.WithdrawRequest{}
_, err := b.WithdrawFiatFundsToInternationalBank(&withdrawFiatRequest)
if err != common.ErrFunctionNotSupported {
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
}
}

View File

@@ -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,
}

View File

@@ -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/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 = "SPOT"
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, &currencyResponse)
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.UpdateCurrencies(availableTickers, 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 = "SPOT"
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: "SPOT",
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(), "SPOT")
if err != nil {
return err
}
b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
Exchange: b.GetName(),
Asset: "SPOT",
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(), "SPOT")
if err != nil {
return err
}
b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
Exchange: b.GetName(),
Pair: p,
Asset: "SPOT",
}
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.GetEnabledCurrencies()
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)
}

View File

@@ -1,191 +0,0 @@
package btcc
import (
"sync"
"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/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
log "github.com/thrasher-/gocryptotrader/logger"
)
// 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()))
log.Debugf("%s polling delay: %ds.\n", b.GetName(), b.RESTPollingDelay)
log.Debugf("%s %d currencies enabled: %s.\n", b.GetName(), len(b.EnabledPairs), b.EnabledPairs)
}
if common.StringDataContains(b.EnabledPairs.Strings(), "CNY") ||
common.StringDataContains(b.AvailablePairs.Strings(), "CNY") ||
common.StringDataContains(b.BaseCurrencies.Strings(), "CNY") {
log.Warn("BTCC only supports BTCUSD now, upgrading available, enabled and base currencies to BTCUSD/USD")
pairs := currency.Pairs{currency.Pair{Base: currency.BTC,
Quote: currency.USD}}
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.AvailablePairs = pairs
exchCfg.EnabledPairs = pairs
b.BaseCurrencies = currency.Currencies{currency.USD}
err = b.UpdateCurrencies(pairs, false, true)
if err != nil {
log.Errorf("%s failed to update available currencies. %s\n", b.Name, err)
}
err = b.UpdateCurrencies(pairs, 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
}
}
}
// UpdateTicker updates and returns the ticker for a currency pair
func (b *BTCC) UpdateTicker(p currency.Pair, assetType string) (ticker.Price, error) {
return ticker.Price{}, common.ErrFunctionNotSupported
}
// GetTickerPrice returns the ticker for a currency pair
func (b *BTCC) GetTickerPrice(p currency.Pair, assetType string) (ticker.Price, error) {
return ticker.Price{}, common.ErrFunctionNotSupported
}
// GetOrderbookEx returns the orderbook for a currency pair
func (b *BTCC) GetOrderbookEx(p currency.Pair, assetType string) (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 string) (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 string) ([]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.WithdrawRequest) (string, error) {
return "", common.ErrFunctionNotSupported
}
// WithdrawFiatFunds returns a withdrawal ID when a
// withdrawal is submitted
func (b *BTCC) WithdrawFiatFunds(withdrawRequest *exchange.WithdrawRequest) (string, error) {
return "", common.ErrFunctionNotSupported
}
// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a
// withdrawal is submitted
func (b *BTCC) WithdrawFiatFundsToInternationalBank(withdrawRequest *exchange.WithdrawRequest) (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.APIKey == "" || b.APISecret == "") && // 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
}

View File

@@ -63,7 +63,7 @@ func TestSwapByPrice(t *testing.T) {
Volume: 5,
},
{
Exchange: "btcc",
Exchange: "bitfinex",
Pair: p,
AssetType: "SPOT",
Price: 7863,
@@ -72,7 +72,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.")
}
}
@@ -95,7 +95,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.")
}
}

View File

@@ -247,6 +247,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,
@@ -259,17 +260,17 @@ func TestProcessTicker(t *testing.T) { // non-appending function to tickers
PriceATH: 1337,
}
err := ProcessTicker("btcc", &Price{}, Spot)
err := ProcessTicker(exchName, &Price{}, Spot)
if err == nil {
t.Fatal("Test failed. ProcessTicker error cannot be nil")
}
err = ProcessTicker("btcc", &priceStruct, Spot)
err = ProcessTicker(exchName, &priceStruct, Spot)
if err != nil {
t.Fatal("Test failed. ProcessTicker error", err)
}
result, err := GetTicker("btcc", newPair, Spot)
result, err := GetTicker(exchName, newPair, Spot)
if err != nil {
t.Fatal("Test failed. TestProcessTicker failed to create and return a new ticker")
}
@@ -280,17 +281,17 @@ func TestProcessTicker(t *testing.T) { // non-appending function to tickers
secondPair := currency.NewPairFromStrings("BTC", "AUD")
priceStruct.Pair = secondPair
err = ProcessTicker("btcc", &priceStruct, Spot)
err = ProcessTicker(exchName, &priceStruct, Spot)
if err != nil {
t.Fatal("Test failed. ProcessTicker error", err)
}
result, err = GetTicker("btcc", secondPair, Spot)
result, err = GetTicker(exchName, secondPair, Spot)
if err != nil {
t.Fatal("Test failed. TestProcessTicker failed to create and return a new ticker")
}
result, err = GetTicker("btcc", newPair, Spot)
result, err = GetTicker(exchName, newPair, Spot)
if err != nil {
t.Fatal("Test failed. TestProcessTicker failed to return an existing ticker")
}

View File

@@ -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,

View File

@@ -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)

View File

@@ -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.GetTickerPrice()
if err != nil {
// Handle error
}
// Fetches current orderbook information
ob, err := b.GetOrderbookEx()
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}}

View File

@@ -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 |