mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-18 23:16:49 +00:00
5
.gitignore
vendored
5
.gitignore
vendored
@@ -2,4 +2,7 @@ config.json
|
||||
config.dat
|
||||
node_modules
|
||||
lib
|
||||
.vscode
|
||||
.vscode
|
||||
|
||||
testdata/dump
|
||||
testdata/writefiletest
|
||||
@@ -2,13 +2,13 @@ language: go
|
||||
|
||||
go:
|
||||
- 1.8.x
|
||||
- master
|
||||
#- master
|
||||
|
||||
before_install:
|
||||
- go get -t -v ./...
|
||||
|
||||
script:
|
||||
- ./test.sh
|
||||
- ./testdata/test.sh
|
||||
|
||||
install:
|
||||
- go get github.com/gorilla/websocket
|
||||
|
||||
25
README.md
25
README.md
@@ -1,4 +1,5 @@
|
||||
## Cryptocurrency trading bot written in Golang
|
||||
# Cryptocurrency trading bot written in Golang
|
||||
|
||||
[](https://travis-ci.org/thrasher-/gocryptotrader)
|
||||
[](https://github.com/thrasher-/gocryptotrader/blob/master/LICENSE)
|
||||
[](https://godoc.org/github.com/thrasher-/gocryptotrader)
|
||||
@@ -21,6 +22,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
||||
| ANXPRO | Yes | No | NA |
|
||||
| Bitfinex | Yes | Yes | NA |
|
||||
| Bitstamp | Yes | Yes | NA |
|
||||
| Bittrex | Yes | No | NA |
|
||||
| BTCC | Yes | Yes | No |
|
||||
| BTCE | Yes | NA | NA |
|
||||
| BTCMarkets | Yes | NA | NA |
|
||||
@@ -41,6 +43,7 @@ We are aiming to support the top 20 highest volume exchanges based off the [Coin
|
||||
** NA means not applicable as the Exchange does not support the feature.
|
||||
|
||||
## Current Features
|
||||
|
||||
+ Support for all Exchange fiat and digital currencies, with the ability to individually toggle them on/off.
|
||||
+ AES encrypted config file.
|
||||
+ REST API support for all exchanges.
|
||||
@@ -54,6 +57,7 @@ We are aiming to support the top 20 highest volume exchanges based off the [Coin
|
||||
+ WebGUI.
|
||||
|
||||
## Planned Features
|
||||
|
||||
Planned features can be found on our [community Trello page](https://trello.com/b/ZAhMhpOy/gocryptotrader).
|
||||
|
||||
## Contribution
|
||||
@@ -62,24 +66,29 @@ Please feel free to submit any pull requests or suggest any desired features to
|
||||
|
||||
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.
|
||||
+ 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.
|
||||
|
||||
## Compiling instructions
|
||||
Download and install Go from https://golang.org/dl/
|
||||
|
||||
Download and install Go from [Go Downloads](https://golang.org/dl/)
|
||||
|
||||
```
|
||||
go get github.com/thrasher-/gocryptotrader
|
||||
cd $GOPATH/src/github.com/thrasher-/gocryptotrader
|
||||
go install
|
||||
cp $GOPATH/src/github.com/thrasher-/gocryptotrader/config_example.dat $GOPATH/bin/config.dat
|
||||
```
|
||||
Make any neccessary changes to the config file.
|
||||
Run the application!
|
||||
|
||||
Make any neccessary changes to the config file.
|
||||
Run the application!
|
||||
|
||||
## Donations
|
||||
|
||||
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to: 1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB
|
||||
|
||||
## Binaries
|
||||
|
||||
Binaries will be published once the codebase reaches a stable condition.
|
||||
|
||||
@@ -159,6 +159,11 @@ func TrimString(input, cutset string) string {
|
||||
return strings.Trim(input, cutset)
|
||||
}
|
||||
|
||||
// ReplaceString replaces a string with another
|
||||
func ReplaceString(input, old, new string, n int) string {
|
||||
return strings.Replace(input, old, new, n)
|
||||
}
|
||||
|
||||
// StringToUpper changes strings to uppercase
|
||||
func StringToUpper(input string) string {
|
||||
return strings.ToUpper(input)
|
||||
@@ -378,7 +383,8 @@ func OutputCSV(path string, data [][]string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
defer writer.Flush()
|
||||
writer.Flush()
|
||||
file.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -415,6 +421,11 @@ func WriteFile(file string, data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveFile removes a file
|
||||
func RemoveFile(file string) error {
|
||||
return os.Remove(file)
|
||||
}
|
||||
|
||||
// GetURIPath returns the path of a URL given a URI
|
||||
func GetURIPath(uri string) string {
|
||||
urip, err := url.Parse(uri)
|
||||
|
||||
@@ -310,6 +310,28 @@ func TestTrimString(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// ReplaceString replaces a string with another
|
||||
func TestReplaceString(t *testing.T) {
|
||||
t.Parallel()
|
||||
currency := "BTC-USD"
|
||||
expectedOutput := "BTCUSD"
|
||||
|
||||
actualResult := ReplaceString(currency, "-", "", -1)
|
||||
if expectedOutput != actualResult {
|
||||
t.Errorf(
|
||||
"Test failed. Expected '%s'. Actual '%s'", expectedOutput, actualResult,
|
||||
)
|
||||
}
|
||||
|
||||
currency = "BTC-USD--"
|
||||
actualResult = ReplaceString(currency, "-", "", 3)
|
||||
if expectedOutput != actualResult {
|
||||
t.Errorf(
|
||||
"Test failed. Expected '%s'. Actual '%s'", expectedOutput, actualResult,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoundFloat(t *testing.T) {
|
||||
t.Parallel()
|
||||
originalInput := float64(1.4545445445)
|
||||
@@ -630,6 +652,22 @@ func TestWriteFile(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveFile(t *testing.T) {
|
||||
TestWriteFile(t)
|
||||
path := "../testdata/writefiletest"
|
||||
err := RemoveFile(path)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed. Common RemoveFile error: %s", err)
|
||||
}
|
||||
|
||||
TestOutputCSV(t)
|
||||
path = "../testdata/dump"
|
||||
err = RemoveFile(path)
|
||||
if err != nil {
|
||||
t.Errorf("Test failed. Common RemoveFile error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetURIPath(t *testing.T) {
|
||||
t.Parallel()
|
||||
// mapping of input vs expected result
|
||||
|
||||
@@ -75,16 +75,23 @@ type Post struct {
|
||||
Data Config `json:"Data"`
|
||||
}
|
||||
|
||||
// CurrencyPairFormatConfig stores the users preferred currency pair display
|
||||
type CurrencyPairFormatConfig struct {
|
||||
Uppercase bool
|
||||
Delimiter string
|
||||
}
|
||||
|
||||
// Config is the overarching object that holds all the information for
|
||||
// prestart management of portfolio, SMSGlobal, webserver and enabled exchange
|
||||
type Config struct {
|
||||
Name string
|
||||
EncryptConfig int
|
||||
Cryptocurrencies string
|
||||
Portfolio portfolio.Base `json:"PortfolioAddresses"`
|
||||
SMS SMSGlobalConfig `json:"SMSGlobal"`
|
||||
Webserver WebserverConfig `json:"Webserver"`
|
||||
Exchanges []ExchangeConfig `json:"Exchanges"`
|
||||
Name string
|
||||
EncryptConfig int
|
||||
Cryptocurrencies string
|
||||
CurrencyPairFormat *CurrencyPairFormatConfig `json:"CurrencyPairFormat"`
|
||||
Portfolio portfolio.Base `json:"PortfolioAddresses"`
|
||||
SMS SMSGlobalConfig `json:"SMSGlobal"`
|
||||
Webserver WebserverConfig `json:"Webserver"`
|
||||
Exchanges []ExchangeConfig `json:"Exchanges"`
|
||||
}
|
||||
|
||||
// ExchangeConfig holds all the information needed for each enabled Exchange.
|
||||
@@ -114,6 +121,11 @@ func (c *Config) GetConfigEnabledExchanges() int {
|
||||
return counter
|
||||
}
|
||||
|
||||
// GetCurrencyPairDisplayConfig retrieves the currency pair display preference
|
||||
func (c *Config) GetCurrencyPairDisplayConfig() *CurrencyPairFormatConfig {
|
||||
return c.CurrencyPairFormat
|
||||
}
|
||||
|
||||
// GetExchangeConfig returns your exchange configurations by its indivdual name
|
||||
func (c *Config) GetExchangeConfig(name string) (ExchangeConfig, error) {
|
||||
for i := range c.Exchanges {
|
||||
@@ -396,6 +408,13 @@ func (c *Config) LoadConfig(configPath string) error {
|
||||
return fmt.Errorf(ErrCheckingConfigValues, err)
|
||||
}
|
||||
|
||||
if c.CurrencyPairFormat == nil {
|
||||
c.CurrencyPairFormat = &CurrencyPairFormatConfig{
|
||||
Delimiter: "-",
|
||||
Uppercase: true,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,22 @@ func TestGetConfigEnabledExchanges(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCurrencyPairDisplayConfig(t *testing.T) {
|
||||
cfg := GetConfig()
|
||||
err := cfg.LoadConfig(ConfigTestFile)
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"Test failed. GetCurrencyPairDisplayConfig. LoadConfig Error: %s", err.Error(),
|
||||
)
|
||||
}
|
||||
settings := cfg.GetCurrencyPairDisplayConfig()
|
||||
if settings.Delimiter != "-" || !settings.Uppercase {
|
||||
t.Errorf(
|
||||
"Test failed. GetCurrencyPairDisplayConfi. Invalid values",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetExchangeConfig(t *testing.T) {
|
||||
GetExchangeConfig := GetConfig()
|
||||
err := GetExchangeConfig.LoadConfig(ConfigTestFile)
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
"Name": "Skynet",
|
||||
"EncryptConfig": 0,
|
||||
"Cryptocurrencies": "BTC,LTC,ETH,XRP,NMC,NVC,PPC,XBT,DOGE,DASH",
|
||||
"CurrencyPairFormat": {
|
||||
"Uppercase": true,
|
||||
"Delimiter": "-"
|
||||
},
|
||||
"PortfolioAddresses": {
|
||||
"Addresses": [
|
||||
{
|
||||
@@ -87,6 +91,20 @@
|
||||
"EnabledPairs": "BTCUSD,BTCEUR,EURUSD,XRPUSD,XRPEUR",
|
||||
"BaseCurrencies": "USD,EUR"
|
||||
},
|
||||
{
|
||||
"Name": "Bittrex",
|
||||
"Enabled": true,
|
||||
"Verbose": false,
|
||||
"Websocket": false,
|
||||
"RESTPollingDelay": 10,
|
||||
"AuthenticatedAPISupport": false,
|
||||
"APIKey": "Key",
|
||||
"APISecret": "Secret",
|
||||
"ClientID": "",
|
||||
"AvailablePairs": "BTCLTC,BTCDOGE,BTCVTC,BTCPPC,BTCFTC,BTCRDD,BTCNXT,BTCDASH,BTCPOT,BTCBLK,BTCEMC2,BTCXMY,BTCAUR,BTCEFL,BTCGLD,BTCSLR,BTCPTC,BTCGRS,BTCNLG,BTCRBY,BTCXWC,BTCMONA,BTCTHC,BTCENRG,BTCERC,BTCNAUT,BTCVRC,BTCCURE,BTCXBB,BTCXMR,BTCCLOAK,BTCSTART,BTCKORE,BTCXDN,BTCTRUST,BTCNAV,BTCXST,BTCBTCD,BTCVIA,BTCUNO,BTCPINK,BTCIOC,BTCCANN,BTCSYS,BTCNEOS,BTCDGB,BTCBURST,BTCEXCL,BTCSWIFT,BTCDOPE,BTCBLOCK,BTCABY,BTCBYC,BTCXMG,BTCBLITZ,BTCBAY,BTCBTS,BTCFAIR,BTCSPR,BTCVTR,BTCXRP,BTCGAME,BTCCOVAL,BTCNXS,BTCXCP,BTCBITB,BTCGEO,BTCFLDC,BTCGRC,BTCFLO,BTCNBT,BTCMUE,BTCXEM,BTCCLAM,BTCDMD,BTCGAM,BTCSPHR,BTCOK,BTCSNRG,BTCPKB,BTCCPC,BTCAEON,BTCETH,BTCGCR,BTCTX,BTCBCY,BTCEXP,BTCINFX,BTCOMNI,BTCAMP,BTCAGRS,BTCXLM,BTCBTA,USDTBTC,BITCNYBTC,BTCCLUB,BTCVOX,BTCEMC,BTCFCT,BTCMAID,BTCEGC,BTCSLS,BTCRADS,BTCDCR,BTCSAFEX,BTCBSD,BTCXVG,BTCPIVX,BTCXVC,BTCMEME,BTCSTEEM,BTC2GIVE,BTCLSK,BTCPDC,BTCBRK,BTCDGD,ETHDGD,BTCWAVES,BTCRISE,BTCLBC,BTCSBD,BTCBRX,BTCDRACO,BTCETC,ETHETC,BTCSTRAT,BTCUNB,BTCSYNX,BTCTRIG,BTCEBST,BTCVRM,BTCSEQ,BTCXAUR,BTCSNGLS,BTCREP,BTCSHIFT,BTCARDR,BTCXZC,BTCNEO,BTCZEC,BTCZCL,BTCIOP,BTCDAR,BTCGOLOS,BTCHKG,BTCUBQ,BTCKMD,BTCGBG,BTCSIB,BTCION,BTCLMC,BTCQWARK,BTCCRW,BTCSWT,BTCTIME,BTCMLN,BTCARK,BTCDYN,BTCTKS,BTCMUSIC,BTCDTB,BTCINCNT,BTCGBYTE,BTCGNT,BTCNXC,BTCEDG,BTCLGD,BTCTRST,ETHGNT,ETHREP,USDTETH,ETHWINGS,BTCWINGS,BTCRLC,BTCGNO,BTCGUP,BTCLUN,ETHGUP,ETHRLC,ETHLUN,ETHSNGLS,ETHGNO,BTCAPX,BTCTKN,ETHTKN,BTCHMQ,ETHHMQ,BTCANT,ETHTRST,ETHANT,BTCSC,ETHBAT,BTCBAT,BTCZEN,BTC1ST,BTCQRL,ETH1ST,ETHQRL,BTCCRB,ETHCRB,ETHLGD,BTCPTOY,ETHPTOY,BTCMYST,ETHMYST,BTCCFI,ETHCFI,BTCBNT,ETHBNT,BTCNMR,ETHNMR,ETHTIME,ETHLTC,ETHXRP,BTCSNT,ETHSNT,BTCDCT,BTCXEL,BTCMCO,ETHMCO,BTCADT,ETHADT,BTCFUN,ETHFUN,BTCPAY,ETHPAY,BTCMTL,ETHMTL,BTCSTORJ,ETHSTORJ,BTCADX,ETHADX,ETHDASH,ETHSC,ETHZEC,USDTZEC,USDTLTC,USDTETC,USDTXRP,BTCOMG,ETHOMG,BTCCVC,ETHCVC,BTCPART,BTCQTUM,ETHQTUM,ETHXMR,ETHXEM,ETHXLM,ETHNEO,USDTXMR,USDTDASH,ETHBCC,USDTBCC,BTCBCC,USDTNEO,ETHWAVES,ETHSTRAT,ETHDGB,ETHFCT,ETHBTS",
|
||||
"EnabledPairs": "BTCLTC,BTCDOGE,BTCDASH",
|
||||
"BaseCurrencies": "USD"
|
||||
},
|
||||
{
|
||||
"Name": "BTCC",
|
||||
"Enabled": true,
|
||||
|
||||
@@ -43,6 +43,23 @@ func (c CurrencyPair) Pair() CurrencyItem {
|
||||
return c.FirstCurrency + CurrencyItem(c.Delimiter) + c.SecondCurrency
|
||||
}
|
||||
|
||||
// Display formats and returns the currency based on user preferences,
|
||||
// overriding the default Pair() display
|
||||
func (c CurrencyPair) Display(delimiter string, uppercase bool) CurrencyItem {
|
||||
var pair CurrencyItem
|
||||
|
||||
if delimiter != "" {
|
||||
pair = c.FirstCurrency + CurrencyItem(delimiter) + c.SecondCurrency
|
||||
} else {
|
||||
pair = c.FirstCurrency + c.SecondCurrency
|
||||
}
|
||||
|
||||
if uppercase {
|
||||
return pair.Upper()
|
||||
}
|
||||
return pair.Lower()
|
||||
}
|
||||
|
||||
// NewCurrencyPairDelimiter splits the desired currency string at delimeter,
|
||||
// the returns a CurrencyPair struct
|
||||
func NewCurrencyPairDelimiter(currency, delimiter string) CurrencyPair {
|
||||
|
||||
@@ -74,6 +74,37 @@ func TestPair(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDisplay(t *testing.T) {
|
||||
t.Parallel()
|
||||
pair := NewCurrencyPairDelimiter("BTC-USD", "-")
|
||||
actual := pair.Pair()
|
||||
expected := CurrencyItem("BTC-USD")
|
||||
if actual != expected {
|
||||
t.Errorf(
|
||||
"Test failed. Pair(): %s was not equal to expected value: %s",
|
||||
actual, expected,
|
||||
)
|
||||
}
|
||||
|
||||
actual = pair.Display("", false)
|
||||
expected = CurrencyItem("btcusd")
|
||||
if actual != expected {
|
||||
t.Errorf(
|
||||
"Test failed. Pair(): %s was not equal to expected value: %s",
|
||||
actual, expected,
|
||||
)
|
||||
}
|
||||
|
||||
actual = pair.Display("~", true)
|
||||
expected = CurrencyItem("BTC~USD")
|
||||
if actual != expected {
|
||||
t.Errorf(
|
||||
"Test failed. Pair(): %s was not equal to expected value: %s",
|
||||
actual, expected,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewCurrencyPair(t *testing.T) {
|
||||
t.Parallel()
|
||||
pair := NewCurrencyPair("BTC", "USD")
|
||||
|
||||
@@ -531,17 +531,21 @@ func (a *Alphapoint) SendRequest(method, path string, data map[string]interface{
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated request
|
||||
func (a *Alphapoint) SendAuthenticatedHTTPRequest(method, path string, data map[string]interface{}, result interface{}) error {
|
||||
if !a.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, a.Name)
|
||||
}
|
||||
|
||||
if a.Nonce.Get() == 0 {
|
||||
a.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
a.Nonce.Inc()
|
||||
}
|
||||
|
||||
headers := make(map[string]string)
|
||||
headers["Content-Type"] = "application/json"
|
||||
data["apiKey"] = a.APIKey
|
||||
nonce := time.Now().UnixNano()
|
||||
nonceStr := strconv.FormatInt(nonce, 10)
|
||||
data["apiNonce"] = nonce
|
||||
hmac := common.GetHMAC(
|
||||
common.HashSHA256,
|
||||
[]byte(nonceStr+a.ClientID+a.APIKey),
|
||||
[]byte(a.APISecret),
|
||||
)
|
||||
data["apiNonce"] = a.Nonce.Get()
|
||||
hmac := common.GetHMAC(common.HashSHA256, []byte(a.Nonce.String()+a.ClientID+a.APIKey), []byte(a.APISecret))
|
||||
data["apiSig"] = common.StringToUpper(common.HexEncodeToString(hmac))
|
||||
path = fmt.Sprintf("%s/ajax/v%s/%s", a.APIUrl, alphapointAPIVersion, path)
|
||||
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
package alphapoint
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
)
|
||||
|
||||
const (
|
||||
onlineTest = false
|
||||
|
||||
testAPIKey = ""
|
||||
testAPISecret = ""
|
||||
)
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
@@ -18,237 +26,121 @@ func TestSetDefaults(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testSetAPIKey(a *Alphapoint) {
|
||||
a.APIKey = testAPIKey
|
||||
a.APISecret = testAPISecret
|
||||
a.AuthenticatedAPISupport = true
|
||||
}
|
||||
|
||||
func testIsAPIKeysSet(a *Alphapoint) bool {
|
||||
if testAPIKey != "" && testAPISecret != "" && a.AuthenticatedAPISupport {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func TestGetTicker(t *testing.T) {
|
||||
GetTicker := Alphapoint{}
|
||||
GetTicker.SetDefaults()
|
||||
alpha := Alphapoint{}
|
||||
alpha.SetDefaults()
|
||||
|
||||
response, err := GetTicker.GetTicker("BTCUSD")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - Alphapoint GetTicker init error: ", err)
|
||||
}
|
||||
if reflect.ValueOf(response).NumField() != 13 {
|
||||
t.Error("Test Failed - Alphapoint GetTicker struct change/or updated")
|
||||
}
|
||||
if reflect.TypeOf(response.Ask).String() != "float64" {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.Ask value is not a float64")
|
||||
}
|
||||
if reflect.TypeOf(response.Bid).String() != "float64" {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.Bid value is not a float64")
|
||||
}
|
||||
if reflect.TypeOf(response.BuyOrderCount).String() != "float64" {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.BuyOrderCount value is not a float64")
|
||||
}
|
||||
if reflect.TypeOf(response.High).String() != "float64" {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.High value is not a float64")
|
||||
}
|
||||
if reflect.TypeOf(response.IsAccepted).String() != "bool" {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.IsAccepted value is not a bool")
|
||||
}
|
||||
if reflect.TypeOf(response.Last).String() != "float64" {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.Last value is not a float64")
|
||||
}
|
||||
if reflect.TypeOf(response.Low).String() != "float64" {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.Low value is not a float64")
|
||||
}
|
||||
if reflect.TypeOf(response.NumOfCreateOrders).String() != "float64" {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.NumOfCreateOrders value is not a float64")
|
||||
}
|
||||
if reflect.TypeOf(response.RejectReason).String() != "string" {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.RejectReason value is not a string")
|
||||
}
|
||||
if reflect.TypeOf(response.SellOrderCount).String() != "float64" {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.SellOrderCount value is not a float64")
|
||||
}
|
||||
if reflect.TypeOf(response.Total24HrNumTrades).String() != "float64" {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.Total24HrNumTrades value is not a float64")
|
||||
}
|
||||
if reflect.TypeOf(response.Total24HrQtyTraded).String() != "float64" {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.Total24HrQtyTraded value is not a float64")
|
||||
}
|
||||
if reflect.TypeOf(response.Volume).String() != "float64" {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.Volume value is not a float64")
|
||||
var ticker Ticker
|
||||
var err error
|
||||
|
||||
if onlineTest {
|
||||
ticker, err = alpha.GetTicker("BTCUSD")
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - Alphapoint GetTicker init error: ", err)
|
||||
}
|
||||
|
||||
_, err = alpha.GetTicker("wigwham")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - Alphapoint GetTicker error")
|
||||
}
|
||||
} else {
|
||||
mockResp := []byte(
|
||||
string(`{"high":253.101,"last":249.76,"bid":248.8901,"volume":5.813354,"low":231.21,"ask":248.9012,"Total24HrQtyTraded":52.654968,"Total24HrProduct2Traded":569.05762,"Total24HrNumTrades":4,"sellOrderCount":7,"buyOrderCount":11,"numOfCreateOrders":0,"isAccepted":true}`),
|
||||
)
|
||||
|
||||
err = common.JSONDecode(mockResp, &ticker)
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - Alphapoint GetTicker unmarshalling error: ", err)
|
||||
}
|
||||
|
||||
if ticker.Last != 249.76 {
|
||||
t.Error("Test failed - Alphapoint GetTicker expected last = 249.76")
|
||||
}
|
||||
}
|
||||
|
||||
if response.Ask < 0 {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.Ask value is negative")
|
||||
}
|
||||
if response.Bid < 0 {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.Bid value is negative")
|
||||
}
|
||||
if response.BuyOrderCount < 0 {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.High value is negative")
|
||||
}
|
||||
if response.High < 0 {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.Last value is negative")
|
||||
}
|
||||
if response.Last < 0 {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.Low value is negative")
|
||||
}
|
||||
if response.Low < 0 {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.Mid value is negative")
|
||||
}
|
||||
if response.NumOfCreateOrders < 0 {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.ask value is negative")
|
||||
}
|
||||
if response.SellOrderCount < 0 {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.ask value is negative")
|
||||
}
|
||||
if response.Total24HrNumTrades < 0 {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.ask value is negative")
|
||||
}
|
||||
if response.Total24HrQtyTraded < 0 {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.ask value is negative")
|
||||
}
|
||||
if response.Volume < 0 {
|
||||
t.Error("Test Failed - Alphapoint GetTicker.ask value is negative")
|
||||
}
|
||||
|
||||
_, err = GetTicker.GetTicker("wigwham")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - Alphapoint GetTicker error")
|
||||
if ticker.Last < 0 {
|
||||
t.Error("Test failed - Alphapoint GetTicker last < 0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTrades(t *testing.T) {
|
||||
GetTrades := Alphapoint{}
|
||||
GetTrades.SetDefaults()
|
||||
alpha := Alphapoint{}
|
||||
alpha.SetDefaults()
|
||||
|
||||
trades, err := GetTrades.GetTrades("BTCUSD", 0, 10)
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Init error: %s", err)
|
||||
}
|
||||
if reflect.ValueOf(trades).NumField() != 9 {
|
||||
t.Error("Test Failed - Alphapoint AlphapointTrades struct updated/changed")
|
||||
}
|
||||
if len(trades.Trades) == 0 {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades: Incorrect length")
|
||||
}
|
||||
if reflect.ValueOf(trades.Trades[0]).NumField() != 8 {
|
||||
t.Error("Test Failed - Alphapoint AlphapointTrades.Trades struct updated/changed")
|
||||
}
|
||||
if reflect.TypeOf(trades.Trades[0].BookServerOrderID).String() != "int" {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.BookServerOrderID value is not a int")
|
||||
}
|
||||
if reflect.TypeOf(trades.Trades[0].IncomingOrderSide).String() != "int" {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.IncomingOrderSide value is not a int")
|
||||
}
|
||||
if reflect.TypeOf(trades.Trades[0].IncomingServerOrderID).String() != "int" {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.IncomingServerOrderID value is not a int")
|
||||
}
|
||||
if reflect.TypeOf(trades.Trades[0].Price).String() != "float64" {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.Price value is not a float64")
|
||||
}
|
||||
if reflect.TypeOf(trades.Trades[0].Quantity).String() != "float64" {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.Quantity value is not a float64")
|
||||
}
|
||||
if reflect.TypeOf(trades.Trades[0].TID).String() != "int64" {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.TID value is not a int64")
|
||||
}
|
||||
if reflect.TypeOf(trades.Trades[0].UTCTicks).String() != "int64" {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.UTCTicks value is not a int64")
|
||||
}
|
||||
if reflect.TypeOf(trades.Trades[0].Unixtime).String() != "int" {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.Unixtime value is not a int")
|
||||
}
|
||||
if reflect.TypeOf(trades.Count).String() != "int" {
|
||||
t.Error("Test Failed - Alphapoint trades.Count value is not a int")
|
||||
}
|
||||
if reflect.TypeOf(trades.DateTimeUTC).String() != "int64" {
|
||||
t.Error("Test Failed - Alphapoint trades.DateTimeUTC value is not a int64")
|
||||
}
|
||||
if reflect.TypeOf(trades.Instrument).String() != "string" {
|
||||
t.Error("Test Failed - Alphapoint trades.Instrument value is not a string")
|
||||
}
|
||||
if reflect.TypeOf(trades.IsAccepted).String() != "bool" {
|
||||
t.Error("Test Failed - Alphapoint trades.IsAccepted value is not a bool")
|
||||
}
|
||||
if reflect.TypeOf(trades.RejectReason).String() != "string" {
|
||||
t.Error("Test Failed - Alphapoint trades.string value is not a string")
|
||||
}
|
||||
if reflect.TypeOf(trades.StartIndex).String() != "int" {
|
||||
t.Error("Test Failed - Alphapoint trades.Count value is not a int")
|
||||
var trades Trades
|
||||
var err error
|
||||
|
||||
if onlineTest {
|
||||
trades, err = alpha.GetTrades("BTCUSD", 0, 10)
|
||||
if err != nil {
|
||||
t.Fatalf("Test Failed - Init error: %s", err)
|
||||
}
|
||||
|
||||
_, err = alpha.GetTrades("wigwham", 0, 10)
|
||||
if err == nil {
|
||||
t.Fatal("Test Failed - GetTrades error")
|
||||
}
|
||||
} else {
|
||||
mockResp := []byte(
|
||||
string(`{"isAccepted":true,"dateTimeUtc":635507981548085938,"ins":"BTCUSD","startIndex":0,"count":10,"trades":[{"tid":0,"px":231.8379,"qty":4.913,"unixtime":1399951989,"utcticks":635355487898355234,"incomingOrderSide":0,"incomingServerOrderId":2598,"bookServerOrderId":2588},{"tid":1,"px":7895.1487,"qty":0.25,"unixtime":1403143708,"utcticks":635387405087297421,"incomingOrderSide":0,"incomingServerOrderId":284241,"bookServerOrderId":284235},{"tid":2,"px":7935.058,"qty":0.25,"unixtime":1403195348,"utcticks":635387921488684140,"incomingOrderSide":0,"incomingServerOrderId":575845,"bookServerOrderId":574078},{"tid":3,"px":7935.0448,"qty":0.25,"unixtime":1403195378,"utcticks":635387921780090390,"incomingOrderSide":0,"incomingServerOrderId":576028,"bookServerOrderId":575946},{"tid":4,"px":7933.9566,"qty":0.1168,"unixtime":1403195510,"utcticks":635387923108371640,"incomingOrderSide":0,"incomingServerOrderId":576974,"bookServerOrderId":576947},{"tid":5,"px":7961.0856,"qty":0.25,"unixtime":1403202307,"utcticks":635387991073850156,"incomingOrderSide":0,"incomingServerOrderId":600547,"bookServerOrderId":600338},{"tid":6,"px":7961.1388,"qty":0.011,"unixtime":1403202307,"utcticks":635387991073850156,"incomingOrderSide":0,"incomingServerOrderId":600547,"bookServerOrderId":600418},{"tid":7,"px":7961.2451,"qty":0.02,"unixtime":1403202307,"utcticks":635387991073850156,"incomingOrderSide":0,"incomingServerOrderId":600547,"bookServerOrderId":600428},{"tid":8,"px":7947.1437,"qty":0.09,"unixtime":1403202749,"utcticks":635387995498225156,"incomingOrderSide":0,"incomingServerOrderId":602183,"bookServerOrderId":601745},{"tid":9,"px":7818.5073,"qty":0.25,"unixtime":1403219720,"utcticks":635388165206506406,"incomingOrderSide":0,"incomingServerOrderId":661909,"bookServerOrderId":661620}]}`),
|
||||
)
|
||||
|
||||
err = common.JSONDecode(mockResp, &trades)
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - GetTrades unmarshalling error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
if trades.Count < 0 {
|
||||
t.Error("Test Failed - Alphapoint trades.Count value is negative")
|
||||
if !trades.IsAccepted {
|
||||
t.Error("Test Failed - GetTrades IsAccepted failed")
|
||||
}
|
||||
if trades.DateTimeUTC <= 0 {
|
||||
t.Error("Test Failed - Alphapoint trades.DateTimeUTC value is negative or 0")
|
||||
|
||||
if trades.Count <= 0 {
|
||||
t.Error("Test failed - GetTrades trades count is <= 0")
|
||||
}
|
||||
|
||||
if trades.Instrument != "BTCUSD" {
|
||||
t.Error("Test Failed - Alphapoint trades.Instrument value is incorrect")
|
||||
}
|
||||
if trades.IsAccepted != true {
|
||||
t.Error("Test Failed - Alphapoint trades.IsAccepted value is true")
|
||||
}
|
||||
if len(trades.RejectReason) > 0 {
|
||||
t.Error("Test Failed - Alphapoint trades.IsAccepted value has been returned")
|
||||
}
|
||||
if trades.StartIndex != 0 {
|
||||
t.Error("Test Failed - Alphapoint trades.StartIndex value is incorrect")
|
||||
}
|
||||
if trades.Trades[0].BookServerOrderID < 0 {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.BookServerOrderID value is negative")
|
||||
}
|
||||
if trades.Trades[0].IncomingOrderSide < 0 {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.BookServerOrderID value is negative")
|
||||
}
|
||||
if trades.Trades[0].IncomingServerOrderID < 0 {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.BookServerOrderID value is negative")
|
||||
}
|
||||
if trades.Trades[0].Price < 0 {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.BookServerOrderID value is negative")
|
||||
}
|
||||
if trades.Trades[0].Quantity < 0 {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.BookServerOrderID value is negative")
|
||||
}
|
||||
if trades.Trades[0].TID != 0 {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.BookServerOrderID value is negative")
|
||||
}
|
||||
if trades.Trades[0].UTCTicks < 0 {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.BookServerOrderID value is negative")
|
||||
}
|
||||
if trades.Trades[0].Unixtime < 0 {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades.BookServerOrderID value is negative")
|
||||
}
|
||||
|
||||
_, err = GetTrades.GetTrades("wigwham", 0, 10)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetTrades error")
|
||||
t.Error("Test failed - GetTrades instrument is != BTCUSD")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTradesByDate(t *testing.T) {
|
||||
GetTradesByDate := Alphapoint{}
|
||||
GetTradesByDate.SetDefaults()
|
||||
alpha := Alphapoint{}
|
||||
alpha.SetDefaults()
|
||||
|
||||
trades, err := GetTradesByDate.GetTradesByDate("BTCUSD", 1414799400, 1414800000)
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Init error: %s", err)
|
||||
}
|
||||
if reflect.ValueOf(trades).NumField() != 9 {
|
||||
t.Error("Test Failed - Alphapoint AlphapointTrades struct updated/changed")
|
||||
}
|
||||
if len(trades.Trades) != 0 {
|
||||
t.Error("Test Failed - Alphapoint trades.Trades: Incorrect length")
|
||||
}
|
||||
if reflect.TypeOf(trades.DateTimeUTC).String() != "int64" {
|
||||
t.Error("Test Failed - Alphapoint trades.Count value is not a int64")
|
||||
}
|
||||
if reflect.TypeOf(trades.EndDate).String() != "int64" {
|
||||
t.Error("Test Failed - Alphapoint trades.DateTimeUTC value is not a int64")
|
||||
}
|
||||
if reflect.TypeOf(trades.Instrument).String() != "string" {
|
||||
t.Error("Test Failed - Alphapoint trades.Instrument value is not a string")
|
||||
}
|
||||
if reflect.TypeOf(trades.IsAccepted).String() != "bool" {
|
||||
t.Error("Test Failed - Alphapoint trades.IsAccepted value is not a bool")
|
||||
}
|
||||
if reflect.TypeOf(trades.RejectReason).String() != "string" {
|
||||
t.Error("Test Failed - Alphapoint trades.string value is not a string")
|
||||
}
|
||||
if reflect.TypeOf(trades.StartDate).String() != "int64" {
|
||||
t.Error("Test Failed - Alphapoint trades.StartDate value is not a int64")
|
||||
var trades Trades
|
||||
var err error
|
||||
|
||||
if onlineTest {
|
||||
trades, err = alpha.GetTradesByDate("BTCUSD", 1414799400, 1414800000)
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Init error: %s", err)
|
||||
}
|
||||
_, err = alpha.GetTradesByDate("wigwham", 1414799400, 1414800000)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetTradesByDate error")
|
||||
}
|
||||
} else {
|
||||
mockResp := []byte(
|
||||
string(`{"isAccepted":true,"dateTimeUtc":635504540880633671,"ins":"BTCUSD","startDate":1414799400,"endDate":1414800000,"trades":[{"tid":11505,"px":334.669,"qty":0.1211,"unixtime":1414799403,"utcticks":635503962032459843,"incomingOrderSide":1,"incomingServerOrderId":5185651,"bookServerOrderId":5162440},{"tid":11506,"px":334.669,"qty":0.1211,"unixtime":1414799405,"utcticks":635503962058446171,"incomingOrderSide":1,"incomingServerOrderId":5186245,"bookServerOrderId":5162440},{"tid":11507,"px":336.498,"qty":0.011,"unixtime":1414799407,"utcticks":635503962072967656,"incomingOrderSide":0,"incomingServerOrderId":5186530,"bookServerOrderId":5178944},{"tid":11508,"px":335.948,"qty":0.011,"unixtime":1414799410,"utcticks":635503962108055546,"incomingOrderSide":0,"incomingServerOrderId":5187260,"bookServerOrderId":5186531}]}`),
|
||||
)
|
||||
|
||||
err = common.JSONDecode(mockResp, &trades)
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - GetTradesByDate unmarshalling error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
if trades.DateTimeUTC < 0 {
|
||||
@@ -269,173 +161,179 @@ func TestGetTradesByDate(t *testing.T) {
|
||||
if trades.StartDate < 0 {
|
||||
t.Error("Test Failed - Alphapoint trades.StartIndex value is negative")
|
||||
}
|
||||
|
||||
_, err = GetTradesByDate.GetTradesByDate("wigwham", 1414799400, 1414800000)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetTradesByDate() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderbook(t *testing.T) {
|
||||
GetOrderbook := Alphapoint{}
|
||||
GetOrderbook.SetDefaults()
|
||||
alpha := Alphapoint{}
|
||||
alpha.SetDefaults()
|
||||
|
||||
orderBook, err := GetOrderbook.GetOrderbook("BTCUSD")
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Init error: %s", err)
|
||||
}
|
||||
if reflect.ValueOf(orderBook).NumField() != 4 {
|
||||
t.Error("Test Failed - Alphapoint AlphapointOrderbook struct updated/changed")
|
||||
}
|
||||
if reflect.TypeOf(orderBook.IsAccepted).String() != "bool" {
|
||||
t.Error("Test Failed - Alphapoint orderBook.IsAccepted value is not a bool")
|
||||
}
|
||||
if reflect.TypeOf(orderBook.RejectReason).String() != "string" {
|
||||
t.Error("Test Failed - Alphapoint orderBook.RejectReason value is not a string")
|
||||
}
|
||||
_, err = GetOrderbook.GetOrderbook("wigwham")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetOrderbook() error")
|
||||
var orderBook Orderbook
|
||||
var err error
|
||||
|
||||
if onlineTest {
|
||||
orderBook, err = alpha.GetOrderbook("BTCUSD")
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Init error: %s", err)
|
||||
}
|
||||
|
||||
_, err = alpha.GetOrderbook("wigwham")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetOrderbook() error")
|
||||
}
|
||||
} else {
|
||||
mockResp := []byte(
|
||||
string(`{"bids":[{"qty":725,"px":66},{"qty":1289,"px":65},{"qty":1266,"px":64}],"asks":[{"qty":1,"px":67},{"qty":1,"px":69},{"qty":2,"px":70}],"isAccepted":true}`),
|
||||
)
|
||||
|
||||
err = common.JSONDecode(mockResp, &orderBook)
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - TestGetOrderbook unmarshalling error: ", err)
|
||||
}
|
||||
|
||||
if orderBook.Bids[0].Quantity != 725 {
|
||||
t.Error("Test Failed - TestGetOrderbook Bids[0].Quantity != 725")
|
||||
}
|
||||
}
|
||||
|
||||
if !orderBook.IsAccepted {
|
||||
t.Error("Test Failed - Alphapoint orderBook.IsAccepted value is negative")
|
||||
}
|
||||
|
||||
if len(orderBook.Asks) == 0 {
|
||||
t.Error("Test Failed - Alphapoint orderBook.Asks has len 0")
|
||||
}
|
||||
|
||||
if len(orderBook.Bids) == 0 {
|
||||
t.Error("Test Failed - Alphapoint orderBook.Bids has len 0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetProductPairs(t *testing.T) {
|
||||
GetProductPairs := Alphapoint{}
|
||||
GetProductPairs.SetDefaults()
|
||||
alpha := Alphapoint{}
|
||||
alpha.SetDefaults()
|
||||
|
||||
productPairs, err := GetProductPairs.GetProductPairs()
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Init error: %s", err)
|
||||
}
|
||||
if reflect.ValueOf(productPairs).NumField() != 3 {
|
||||
t.Error("Test Failed - Alphapoint GetProductPairs struct updated/changed")
|
||||
}
|
||||
if reflect.TypeOf(productPairs.IsAccepted).String() != "bool" {
|
||||
t.Error("Test Failed - Alphapoint productPairs.IsAccepted value is not a bool")
|
||||
}
|
||||
if reflect.TypeOf(productPairs.RejectReason).String() != "string" {
|
||||
t.Error("Test Failed - Alphapoint productPairs.RejectReason value is not a string")
|
||||
}
|
||||
var products ProductPairs
|
||||
var err error
|
||||
|
||||
if len(productPairs.ProductPairs) >= 1 {
|
||||
if reflect.ValueOf(productPairs.ProductPairs[0]).NumField() != 6 {
|
||||
t.Error("Test Failed - Alphapoint GetProductPairs.ProductPairs[] struct updated/changed")
|
||||
}
|
||||
if reflect.TypeOf(productPairs.ProductPairs[0].Name).String() != "string" {
|
||||
t.Error("Test Failed - Alphapoint productPairs.ProductPairs.Name value is not a string")
|
||||
}
|
||||
if reflect.TypeOf(productPairs.ProductPairs[0].Product1Decimalplaces).String() != "int" {
|
||||
t.Error("Test Failed - Alphapoint productPairs.ProductPairs.Product1Decimalplaces value is not a int")
|
||||
}
|
||||
if reflect.TypeOf(productPairs.ProductPairs[0].Product1Label).String() != "string" {
|
||||
t.Error("Test Failed - Alphapoint productPairs.ProductPairs.Product1Label value is not a string")
|
||||
}
|
||||
if reflect.TypeOf(productPairs.ProductPairs[0].Product2Decimalplaces).String() != "int" {
|
||||
t.Error("Test Failed - Alphapoint productPairs.ProductPairs.Product2Decimalplaces value is not a int")
|
||||
}
|
||||
if reflect.TypeOf(productPairs.ProductPairs[0].Product2Label).String() != "string" {
|
||||
t.Error("Test Failed - Alphapoint productPairs.ProductPairs.Product2Label value is not a string")
|
||||
}
|
||||
if reflect.TypeOf(productPairs.ProductPairs[0].Productpaircode).String() != "int" {
|
||||
t.Error("Test Failed - Alphapoint productPairs.ProductPairs.Productpaircode value is not a int")
|
||||
}
|
||||
|
||||
if productPairs.ProductPairs[0].Product1Decimalplaces < 0 {
|
||||
t.Error("Test Failed - Alphapoint productPairs.ProductPairs.Product1Decimalplaces value is negative")
|
||||
}
|
||||
if productPairs.ProductPairs[0].Product2Decimalplaces < 0 {
|
||||
t.Error("Test Failed - Alphapoint productPairs.ProductPairs.Product2Decimalplaces value is negative")
|
||||
}
|
||||
if productPairs.ProductPairs[0].Productpaircode < 0 {
|
||||
t.Error("Test Failed - Alphapoint productPairs.ProductPairs.Productpaircode value is negative")
|
||||
if onlineTest {
|
||||
products, err = alpha.GetProductPairs()
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Init error: %s", err)
|
||||
}
|
||||
} else {
|
||||
t.Error("Test Failed - Alphapoint productPairs.ProductPairs no product pairs.")
|
||||
mockResp := []byte(
|
||||
string(`{"productPairs":[{"name":"LTCUSD","productPairCode":100,"product1Label":"LTC","product1DecimalPlaces":8,"product2Label":"USD","product2DecimalPlaces":6}, {"name":"BTCUSD","productPairCode":99,"product1Label":"BTC","product1DecimalPlaces":8,"product2Label":"USD","product2DecimalPlaces":6}],"isAccepted":true}`),
|
||||
)
|
||||
|
||||
err = common.JSONDecode(mockResp, &products)
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - TestGetProductPairs unmarshalling error: ", err)
|
||||
}
|
||||
|
||||
if products.ProductPairs[0].Name != "LTCUSD" {
|
||||
t.Error("Test Failed - Alphapoint ProductPairs 0 != LTCUSD")
|
||||
}
|
||||
|
||||
if products.ProductPairs[1].Product1Label != "BTC" {
|
||||
t.Error("Test Failed - Alphapoint ProductPairs 1 != BTC")
|
||||
}
|
||||
}
|
||||
|
||||
if !products.IsAccepted {
|
||||
t.Error("Test Failed - Alphapoint ProductPairs.IsAccepted value is negative")
|
||||
}
|
||||
|
||||
if len(products.ProductPairs) == 0 {
|
||||
t.Error("Test Failed - Alphapoint ProductPairs len is 0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetProducts(t *testing.T) {
|
||||
GetProducts := Alphapoint{}
|
||||
GetProducts.SetDefaults()
|
||||
alpha := Alphapoint{}
|
||||
alpha.SetDefaults()
|
||||
|
||||
products, err := GetProducts.GetProducts()
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Init error: %s", err)
|
||||
}
|
||||
if reflect.ValueOf(products).NumField() != 3 {
|
||||
t.Error("Test Failed - Alphapoint GetProductPairs struct updated/changed")
|
||||
}
|
||||
if reflect.TypeOf(products.IsAccepted).String() != "bool" {
|
||||
t.Error("Test Failed - Alphapoint products.IsAccepted value is not a bool")
|
||||
}
|
||||
if reflect.TypeOf(products.RejectReason).String() != "string" {
|
||||
t.Error("Test Failed - Alphapoint products.RejectReason value is not a string")
|
||||
}
|
||||
var products Products
|
||||
var err error
|
||||
|
||||
if len(products.Products) >= 1 {
|
||||
if reflect.ValueOf(products.Products[0]).NumField() != 5 {
|
||||
t.Error("Test Failed - Alphapoint Getproducts.Products[] struct updated/changed")
|
||||
}
|
||||
if reflect.TypeOf(products.Products[0].DecimalPlaces).String() != "int" {
|
||||
t.Error("Test Failed - Alphapoint products.Products.DecimalPlaces value is not a int")
|
||||
}
|
||||
if reflect.TypeOf(products.Products[0].FullName).String() != "string" {
|
||||
t.Error("Test Failed - Alphapoint products.Products.FullName value is not a string")
|
||||
}
|
||||
if reflect.TypeOf(products.Products[0].IsDigital).String() != "bool" {
|
||||
t.Error("Test Failed - Alphapoint products.Products.IsDigital value is not a bool")
|
||||
}
|
||||
if reflect.TypeOf(products.Products[0].Name).String() != "string" {
|
||||
t.Error("Test Failed - Alphapoint products.Products.Name value is not a string")
|
||||
}
|
||||
if reflect.TypeOf(products.Products[0].ProductCode).String() != "int" {
|
||||
t.Error("Test Failed - Alphapoint products.Products.ProductCode value is not a int")
|
||||
}
|
||||
|
||||
if products.Products[0].DecimalPlaces < 0 {
|
||||
t.Error("Test Failed - Alphapoint products.Products.DecimalPlaces value is negative")
|
||||
}
|
||||
if products.Products[0].ProductCode < 0 {
|
||||
t.Log(products.Products[0].ProductCode)
|
||||
t.Error("Test Failed - Alphapoint products.Products.ProductCode value is negative")
|
||||
if onlineTest {
|
||||
products, err = alpha.GetProducts()
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Init error: %s", err)
|
||||
}
|
||||
} else {
|
||||
t.Error("Test Failed - Alphapoint products.Products no product pairs.")
|
||||
mockResp := []byte(
|
||||
string(`{"products": [{"name": "USD","isDigital": false,"productCode": 0,"decimalPlaces": 4,"fullName": "US Dollar"},{"name": "BTC","isDigital": true,"productCode": 1,"decimalPlaces": 6,"fullName": "Bitcoin"}],"isAccepted": true}`),
|
||||
)
|
||||
|
||||
err = common.JSONDecode(mockResp, &products)
|
||||
if err != nil {
|
||||
t.Fatal("Test Failed - TestGetProducts unmarshalling error: ", err)
|
||||
}
|
||||
|
||||
if products.Products[0].Name != "USD" {
|
||||
t.Error("Test Failed - Alphapoint Products 0 != USD")
|
||||
}
|
||||
|
||||
if products.Products[1].ProductCode != 1 {
|
||||
t.Error("Test Failed - Alphapoint Products 1 product code != 1")
|
||||
}
|
||||
}
|
||||
|
||||
if !products.IsAccepted {
|
||||
t.Error("Test Failed - Alphapoint Products.IsAccepted value is negative")
|
||||
}
|
||||
|
||||
if len(products.Products) == 0 {
|
||||
t.Error("Test Failed - Alphapoint Products len is 0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateAccount(t *testing.T) {
|
||||
CreateAccount := Alphapoint{}
|
||||
CreateAccount.SetDefaults()
|
||||
a := &Alphapoint{}
|
||||
a.SetDefaults()
|
||||
testSetAPIKey(a)
|
||||
|
||||
err := CreateAccount.CreateAccount("test", "account", "something@something.com", "0292383745", "lolcat123")
|
||||
if !testIsAPIKeysSet(a) {
|
||||
return
|
||||
}
|
||||
|
||||
err := a.CreateAccount("test", "account", "something@something.com", "0292383745", "lolcat123")
|
||||
if err != nil {
|
||||
t.Errorf("Test Failed - Init error: %s", err)
|
||||
}
|
||||
err = CreateAccount.CreateAccount("test", "account", "something@something.com", "0292383745", "bla")
|
||||
err = a.CreateAccount("test", "account", "something@something.com", "0292383745", "bla")
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - CreateAccount() error")
|
||||
}
|
||||
err = CreateAccount.CreateAccount("", "", "", "", "lolcat123")
|
||||
err = a.CreateAccount("", "", "", "", "lolcat123")
|
||||
if err == nil {
|
||||
t.Errorf("Test Failed - CreateAccount() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUserInfo(t *testing.T) {
|
||||
GetUserInfo := Alphapoint{}
|
||||
GetUserInfo.SetDefaults()
|
||||
a := &Alphapoint{}
|
||||
a.SetDefaults()
|
||||
testSetAPIKey(a)
|
||||
|
||||
_, err := GetUserInfo.GetUserInfo()
|
||||
if !testIsAPIKeysSet(a) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err := a.GetUserInfo()
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetUserInfo() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetUserInfo(t *testing.T) {
|
||||
a := Alphapoint{}
|
||||
a := &Alphapoint{}
|
||||
a.SetDefaults()
|
||||
testSetAPIKey(a)
|
||||
|
||||
if !testIsAPIKeysSet(a) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err := a.SetUserInfo("bla", "bla", "1", "meh", true, true)
|
||||
if err == nil {
|
||||
@@ -444,8 +342,13 @@ func TestSetUserInfo(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetAccountInfo(t *testing.T) {
|
||||
a := Alphapoint{}
|
||||
a := &Alphapoint{}
|
||||
a.SetDefaults()
|
||||
testSetAPIKey(a)
|
||||
|
||||
if !testIsAPIKeysSet(a) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err := a.GetAccountInfo()
|
||||
if err == nil {
|
||||
@@ -454,8 +357,13 @@ func TestGetAccountInfo(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetAccountTrades(t *testing.T) {
|
||||
a := Alphapoint{}
|
||||
a := &Alphapoint{}
|
||||
a.SetDefaults()
|
||||
testSetAPIKey(a)
|
||||
|
||||
if !testIsAPIKeysSet(a) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err := a.GetAccountTrades("", 1, 2)
|
||||
if err == nil {
|
||||
@@ -464,8 +372,13 @@ func TestGetAccountTrades(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetDepositAddresses(t *testing.T) {
|
||||
a := Alphapoint{}
|
||||
a := &Alphapoint{}
|
||||
a.SetDefaults()
|
||||
testSetAPIKey(a)
|
||||
|
||||
if !testIsAPIKeysSet(a) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err := a.GetDepositAddresses()
|
||||
if err == nil {
|
||||
@@ -474,8 +387,13 @@ func TestGetDepositAddresses(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWithdrawCoins(t *testing.T) {
|
||||
a := Alphapoint{}
|
||||
a := &Alphapoint{}
|
||||
a.SetDefaults()
|
||||
testSetAPIKey(a)
|
||||
|
||||
if !testIsAPIKeysSet(a) {
|
||||
return
|
||||
}
|
||||
|
||||
err := a.WithdrawCoins("", "", "", 0.01)
|
||||
if err == nil {
|
||||
@@ -484,8 +402,13 @@ func TestWithdrawCoins(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCreateOrder(t *testing.T) {
|
||||
a := Alphapoint{}
|
||||
a := &Alphapoint{}
|
||||
a.SetDefaults()
|
||||
testSetAPIKey(a)
|
||||
|
||||
if !testIsAPIKeysSet(a) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err := a.CreateOrder("", "", 1, 0.01, 0)
|
||||
if err == nil {
|
||||
@@ -494,8 +417,13 @@ func TestCreateOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestModifyOrder(t *testing.T) {
|
||||
a := Alphapoint{}
|
||||
a := &Alphapoint{}
|
||||
a.SetDefaults()
|
||||
testSetAPIKey(a)
|
||||
|
||||
if !testIsAPIKeysSet(a) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err := a.ModifyOrder("", 1, 1)
|
||||
if err == nil {
|
||||
@@ -504,8 +432,13 @@ func TestModifyOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCancelOrder(t *testing.T) {
|
||||
a := Alphapoint{}
|
||||
a := &Alphapoint{}
|
||||
a.SetDefaults()
|
||||
testSetAPIKey(a)
|
||||
|
||||
if !testIsAPIKeysSet(a) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err := a.CancelOrder("", 1)
|
||||
if err == nil {
|
||||
@@ -514,8 +447,13 @@ func TestCancelOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCancelAllOrders(t *testing.T) {
|
||||
a := Alphapoint{}
|
||||
a := &Alphapoint{}
|
||||
a.SetDefaults()
|
||||
testSetAPIKey(a)
|
||||
|
||||
if !testIsAPIKeysSet(a) {
|
||||
return
|
||||
}
|
||||
|
||||
err := a.CancelAllOrders("")
|
||||
if err == nil {
|
||||
@@ -524,8 +462,13 @@ func TestCancelAllOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetOrders(t *testing.T) {
|
||||
a := Alphapoint{}
|
||||
a := &Alphapoint{}
|
||||
a.SetDefaults()
|
||||
testSetAPIKey(a)
|
||||
|
||||
if !testIsAPIKeysSet(a) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err := a.GetOrders()
|
||||
if err == nil {
|
||||
@@ -534,8 +477,13 @@ func TestGetOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetOrderFee(t *testing.T) {
|
||||
a := Alphapoint{}
|
||||
a := &Alphapoint{}
|
||||
a.SetDefaults()
|
||||
testSetAPIKey(a)
|
||||
|
||||
if !testIsAPIKeysSet(a) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err := a.GetOrderFee("", "", 1, 1)
|
||||
if err == nil {
|
||||
|
||||
@@ -286,8 +286,18 @@ func (a *ANX) GetDepositAddress(currency, name string, new bool) (string, error)
|
||||
}
|
||||
|
||||
func (a *ANX) SendAuthenticatedHTTPRequest(path string, params map[string]interface{}, result interface{}) error {
|
||||
if !a.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, a.Name)
|
||||
}
|
||||
|
||||
if a.Nonce.Get() == 0 {
|
||||
a.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
a.Nonce.Inc()
|
||||
}
|
||||
|
||||
request := make(map[string]interface{})
|
||||
request["nonce"] = strconv.FormatInt(time.Now().UnixNano(), 10)[0:13]
|
||||
request["nonce"] = a.Nonce.String()[0:13]
|
||||
path = fmt.Sprintf("api/%s/%s", ANX_API_VERSION, path)
|
||||
|
||||
if params != nil {
|
||||
@@ -296,23 +306,23 @@ func (a *ANX) SendAuthenticatedHTTPRequest(path string, params map[string]interf
|
||||
}
|
||||
}
|
||||
|
||||
PayloadJson, err := common.JSONEncode(request)
|
||||
PayloadJSON, err := common.JSONEncode(request)
|
||||
|
||||
if err != nil {
|
||||
return errors.New("SendAuthenticatedHTTPRequest: Unable to JSON request")
|
||||
}
|
||||
|
||||
if a.Verbose {
|
||||
log.Printf("Request JSON: %s\n", PayloadJson)
|
||||
log.Printf("Request JSON: %s\n", PayloadJSON)
|
||||
}
|
||||
|
||||
hmac := common.GetHMAC(common.HashSHA512, []byte(path+string("\x00")+string(PayloadJson)), []byte(a.APISecret))
|
||||
hmac := common.GetHMAC(common.HashSHA512, []byte(path+string("\x00")+string(PayloadJSON)), []byte(a.APISecret))
|
||||
headers := make(map[string]string)
|
||||
headers["Rest-Key"] = a.APIKey
|
||||
headers["Rest-Sign"] = common.Base64Encode([]byte(hmac))
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
resp, err := common.SendHTTPRequest("POST", ANX_API_URL+path, headers, bytes.NewBuffer(PayloadJson))
|
||||
resp, err := common.SendHTTPRequest("POST", ANX_API_URL+path, headers, bytes.NewBuffer(PayloadJSON))
|
||||
|
||||
if a.Verbose {
|
||||
log.Printf("Received raw: \n%s\n", resp)
|
||||
|
||||
@@ -30,7 +30,7 @@ func (a *ANX) Run() {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("ANX %s: Last %f High %f Low %f Volume %f\n", currency.Pair(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
log.Printf("ANX %s: Last %f High %f Low %f Volume %f\n", exchange.FormatCurrency(currency).String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
stats.AddExchangeInfo(a.GetName(), currency.GetFirstCurrency().String(), currency.GetSecondCurrency().String(), ticker.Last, ticker.Volume)
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package anx
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStart(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestGetTickerPrice(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestGetOrderbookEx(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestGetExchangeAccountInfo(t *testing.T) {
|
||||
|
||||
}
|
||||
@@ -564,14 +564,20 @@ func (b *Bitfinex) CloseMarginFunding(SwapID int64) (Offer, error) {
|
||||
// SendAuthenticatedHTTPRequest sends an autheticated http request and json
|
||||
// unmarshals result to a supplied variable
|
||||
func (b *Bitfinex) SendAuthenticatedHTTPRequest(method, path string, params map[string]interface{}, result interface{}) error {
|
||||
if len(b.APIKey) == 0 {
|
||||
return errors.New("SendAuthenticatedHTTPRequest: Invalid API key")
|
||||
if !b.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name)
|
||||
}
|
||||
|
||||
if b.Nonce.Get() == 0 {
|
||||
b.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
b.Nonce.Inc()
|
||||
}
|
||||
|
||||
respErr := ErrorCapture{}
|
||||
request := make(map[string]interface{})
|
||||
request["request"] = fmt.Sprintf("/v%s/%s", bitfinexAPIVersion, path)
|
||||
request["nonce"] = strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
request["nonce"] = b.Nonce.String()
|
||||
|
||||
if params != nil {
|
||||
for key, value := range params {
|
||||
@@ -589,9 +595,7 @@ func (b *Bitfinex) SendAuthenticatedHTTPRequest(method, path string, params map[
|
||||
}
|
||||
|
||||
PayloadBase64 := common.Base64Encode(PayloadJSON)
|
||||
hmac := common.GetHMAC(
|
||||
common.HashSHA512_384, []byte(PayloadBase64), []byte(b.APISecret),
|
||||
)
|
||||
hmac := common.GetHMAC(common.HashSHA512_384, []byte(PayloadBase64), []byte(b.APISecret))
|
||||
headers := make(map[string]string)
|
||||
headers["X-BFX-APIKEY"] = b.APIKey
|
||||
headers["X-BFX-PAYLOAD"] = PayloadBase64
|
||||
|
||||
@@ -17,74 +17,70 @@ const (
|
||||
testAPISecret = ""
|
||||
)
|
||||
|
||||
var b Bitfinex
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
t.Parallel()
|
||||
b.SetDefaults()
|
||||
|
||||
setDefaults := Bitfinex{}
|
||||
setDefaults.SetDefaults()
|
||||
|
||||
if setDefaults.Name != "Bitfinex" || setDefaults.Enabled != false ||
|
||||
setDefaults.Verbose != false || setDefaults.Websocket != false ||
|
||||
setDefaults.RESTPollingDelay != 10 {
|
||||
if b.Name != "Bitfinex" || b.Enabled != false ||
|
||||
b.Verbose != false || b.Websocket != false ||
|
||||
b.RESTPollingDelay != 10 {
|
||||
t.Error("Test Failed - Bitfinex SetDefaults values not set correctly")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
t.Parallel()
|
||||
testConfig := config.ExchangeConfig{
|
||||
Enabled: true,
|
||||
AuthenticatedAPISupport: true,
|
||||
APIKey: "lamb",
|
||||
APISecret: "cutlets",
|
||||
APIKey: testAPIKey,
|
||||
APISecret: testAPISecret,
|
||||
RESTPollingDelay: time.Duration(10),
|
||||
Verbose: true,
|
||||
Verbose: false,
|
||||
Websocket: true,
|
||||
BaseCurrencies: currency.DefaultCurrencies,
|
||||
AvailablePairs: currency.MakecurrencyPairs(currency.DefaultCurrencies),
|
||||
EnabledPairs: currency.MakecurrencyPairs(currency.DefaultCurrencies),
|
||||
}
|
||||
setup := Bitfinex{}
|
||||
setup.Setup(testConfig)
|
||||
|
||||
if !setup.Enabled || !setup.AuthenticatedAPISupport || setup.APIKey != "lamb" ||
|
||||
setup.APISecret != "cutlets" || setup.RESTPollingDelay != time.Duration(10) ||
|
||||
!setup.Verbose || !setup.Websocket || len(setup.BaseCurrencies) < 1 ||
|
||||
len(setup.AvailablePairs) < 1 || len(setup.EnabledPairs) < 1 {
|
||||
b.Setup(testConfig)
|
||||
|
||||
if !b.Enabled || !b.AuthenticatedAPISupport || b.APIKey != testAPIKey ||
|
||||
b.APISecret != testAPISecret || b.RESTPollingDelay != time.Duration(10) ||
|
||||
b.Verbose || !b.Websocket || len(b.BaseCurrencies) < 1 ||
|
||||
len(b.AvailablePairs) < 1 || len(b.EnabledPairs) < 1 {
|
||||
t.Error("Test Failed - Bitfinex Setup values not set correctly")
|
||||
}
|
||||
testConfig.Enabled = false
|
||||
setup.Setup(testConfig)
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
bitfinex := Bitfinex{}
|
||||
_, err := bitfinex.GetTicker("BTCUSD", url.Values{})
|
||||
t.Parallel()
|
||||
_, err := b.GetTicker("BTCUSD", url.Values{})
|
||||
if err != nil {
|
||||
t.Error("BitfinexGetTicker init error: ", err)
|
||||
}
|
||||
|
||||
_, err = bitfinex.GetTicker("wigwham", url.Values{})
|
||||
_, err = b.GetTicker("wigwham", url.Values{})
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetTicker() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetStats(t *testing.T) {
|
||||
BitfinexGetStatsTest := Bitfinex{}
|
||||
_, err := BitfinexGetStatsTest.GetStats("BTCUSD")
|
||||
t.Parallel()
|
||||
_, err := b.GetStats("BTCUSD")
|
||||
if err != nil {
|
||||
t.Error("BitfinexGetStatsTest init error: ", err)
|
||||
}
|
||||
|
||||
_, err = BitfinexGetStatsTest.GetStats("wigwham")
|
||||
_, err = b.GetStats("wigwham")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetStats() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFundingBook(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
t.Parallel()
|
||||
_, err := b.GetFundingBook("USD")
|
||||
if err != nil {
|
||||
t.Error("Testing Failed - GetFundingBook() error")
|
||||
@@ -96,42 +92,45 @@ func TestGetFundingBook(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetLendbook(t *testing.T) {
|
||||
BitfinexGetLendbook := Bitfinex{}
|
||||
_, err := BitfinexGetLendbook.GetLendbook("BTCUSD", url.Values{})
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetLendbook("BTCUSD", url.Values{})
|
||||
if err != nil {
|
||||
t.Error("BitfinexGetLendbook init error: ", err)
|
||||
t.Error("Testing Failed - GetLendbook() error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderbook(t *testing.T) {
|
||||
BitfinexGetOrderbook := Bitfinex{}
|
||||
_, err := BitfinexGetOrderbook.GetOrderbook("BTCUSD", url.Values{})
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetOrderbook("BTCUSD", url.Values{})
|
||||
if err != nil {
|
||||
t.Error("BitfinexGetOrderbook init error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTrades(t *testing.T) {
|
||||
BitfinexGetTrades := Bitfinex{}
|
||||
_, err := BitfinexGetTrades.GetTrades("BTCUSD", url.Values{})
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetTrades("BTCUSD", url.Values{})
|
||||
if err != nil {
|
||||
t.Error("BitfinexGetTrades init error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetLends(t *testing.T) {
|
||||
BitfinexGetLends := Bitfinex{}
|
||||
t.Parallel()
|
||||
|
||||
_, err := BitfinexGetLends.GetLends("BTC", url.Values{})
|
||||
_, err := b.GetLends("BTC", url.Values{})
|
||||
if err != nil {
|
||||
t.Error("BitfinexGetLends init error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSymbols(t *testing.T) {
|
||||
BitfinexGetSymbols := Bitfinex{}
|
||||
t.Parallel()
|
||||
|
||||
symbols, err := BitfinexGetSymbols.GetSymbols()
|
||||
symbols, err := b.GetSymbols()
|
||||
if err != nil {
|
||||
t.Error("BitfinexGetSymbols init error: ", err)
|
||||
}
|
||||
@@ -177,17 +176,16 @@ func TestGetSymbols(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetSymbolsDetails(t *testing.T) {
|
||||
BitfinexGetSymbolsDetails := Bitfinex{}
|
||||
_, err := BitfinexGetSymbolsDetails.GetSymbolsDetails()
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetSymbolsDetails()
|
||||
if err != nil {
|
||||
t.Error("BitfinexGetSymbolsDetails init error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccountInfo(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetAccountInfo()
|
||||
if err == nil {
|
||||
@@ -196,9 +194,7 @@ func TestGetAccountInfo(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetAccountFees(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetAccountFees()
|
||||
if err == nil {
|
||||
@@ -207,9 +203,7 @@ func TestGetAccountFees(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetAccountSummary(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetAccountSummary()
|
||||
if err == nil {
|
||||
@@ -218,9 +212,7 @@ func TestGetAccountSummary(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewDeposit(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.NewDeposit("blabla", "testwallet", 1)
|
||||
if err == nil {
|
||||
@@ -229,9 +221,7 @@ func TestNewDeposit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetKeyPermissions(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetKeyPermissions()
|
||||
if err == nil {
|
||||
@@ -240,9 +230,7 @@ func TestGetKeyPermissions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetMarginInfo(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetMarginInfo()
|
||||
if err == nil {
|
||||
@@ -251,9 +239,7 @@ func TestGetMarginInfo(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetAccountBalance(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetAccountBalance()
|
||||
if err == nil {
|
||||
@@ -262,9 +248,7 @@ func TestGetAccountBalance(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWalletTransfer(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.WalletTransfer(0.01, "bla", "bla", "bla")
|
||||
if err == nil {
|
||||
@@ -273,9 +257,7 @@ func TestWalletTransfer(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWithdrawal(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.Withdrawal("LITECOIN", "deposit", "1000", 0.01)
|
||||
if err == nil {
|
||||
@@ -284,9 +266,7 @@ func TestWithdrawal(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewOrder(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.NewOrder("BTCUSD", 1, 2, true, "market", false)
|
||||
if err == nil {
|
||||
@@ -295,9 +275,8 @@ func TestNewOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewOrderMulti(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
newOrder := []PlaceOrder{
|
||||
{
|
||||
Symbol: "BTCUSD",
|
||||
@@ -316,9 +295,7 @@ func TestNewOrderMulti(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCancelOrder(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.CancelOrder(1337)
|
||||
if err == nil {
|
||||
@@ -327,9 +304,7 @@ func TestCancelOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCancelMultipleOrders(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.CancelMultipleOrders([]int64{1337, 1336})
|
||||
if err == nil {
|
||||
@@ -338,9 +313,7 @@ func TestCancelMultipleOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCancelAllOrders(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.CancelAllOrders()
|
||||
if err == nil {
|
||||
@@ -349,9 +322,7 @@ func TestCancelAllOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestReplaceOrder(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.ReplaceOrder(1337, "BTCUSD", 1, 1, true, "market", false)
|
||||
if err == nil {
|
||||
@@ -360,9 +331,7 @@ func TestReplaceOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetOrderStatus(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetOrderStatus(1337)
|
||||
if err == nil {
|
||||
@@ -371,9 +340,7 @@ func TestGetOrderStatus(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetActiveOrders(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetActiveOrders()
|
||||
if err == nil {
|
||||
@@ -382,9 +349,7 @@ func TestGetActiveOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetActivePositions(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetActivePositions()
|
||||
if err == nil {
|
||||
@@ -393,9 +358,7 @@ func TestGetActivePositions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestClaimPosition(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.ClaimPosition(1337)
|
||||
if err == nil {
|
||||
@@ -404,9 +367,7 @@ func TestClaimPosition(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetBalanceHistory(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetBalanceHistory("USD", time.Time{}, time.Time{}, 1, "deposit")
|
||||
if err == nil {
|
||||
@@ -415,9 +376,7 @@ func TestGetBalanceHistory(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetMovementHistory(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetMovementHistory("USD", "bitcoin", time.Time{}, time.Time{}, 1)
|
||||
if err == nil {
|
||||
@@ -426,9 +385,7 @@ func TestGetMovementHistory(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetTradeHistory(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetTradeHistory("BTCUSD", time.Time{}, time.Time{}, 1, 0)
|
||||
if err == nil {
|
||||
@@ -437,9 +394,7 @@ func TestGetTradeHistory(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewOffer(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.NewOffer("BTC", 1, 1, 1, "loan")
|
||||
if err == nil {
|
||||
@@ -448,9 +403,7 @@ func TestNewOffer(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCancelOffer(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.CancelOffer(1337)
|
||||
if err == nil {
|
||||
@@ -459,9 +412,7 @@ func TestCancelOffer(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetOfferStatus(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetOfferStatus(1337)
|
||||
if err == nil {
|
||||
@@ -470,9 +421,7 @@ func TestGetOfferStatus(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetActiveCredits(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetActiveCredits()
|
||||
if err == nil {
|
||||
@@ -481,9 +430,7 @@ func TestGetActiveCredits(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetActiveOffers(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetActiveOffers()
|
||||
if err == nil {
|
||||
@@ -492,9 +439,7 @@ func TestGetActiveOffers(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetActiveMarginFunding(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetActiveMarginFunding()
|
||||
if err == nil {
|
||||
@@ -503,9 +448,7 @@ func TestGetActiveMarginFunding(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetUnusedMarginFunds(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetUnusedMarginFunds()
|
||||
if err == nil {
|
||||
@@ -514,9 +457,7 @@ func TestGetUnusedMarginFunds(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetMarginTotalTakenFunds(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetMarginTotalTakenFunds()
|
||||
if err == nil {
|
||||
@@ -525,9 +466,7 @@ func TestGetMarginTotalTakenFunds(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCloseMarginFunding(t *testing.T) {
|
||||
b := Bitfinex{}
|
||||
b.APIKey = testAPIKey
|
||||
b.APISecret = testAPISecret
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.CloseMarginFunding(1337)
|
||||
if err == nil {
|
||||
|
||||
@@ -47,7 +47,7 @@ func (b *Bitfinex) Run() {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Printf("Bitfinex %s Last %f High %f Low %f Volume %f\n", currency.Pair().String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
log.Printf("Bitfinex %s Last %f High %f Low %f Volume %f\n", exchange.FormatCurrency(currency).String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
stats.AddExchangeInfo(b.GetName(), currency.GetFirstCurrency().String(), currency.GetSecondCurrency().String(), ticker.Last, ticker.Volume)
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -16,39 +16,44 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
BITSTAMP_API_URL = "https://www.bitstamp.net/api"
|
||||
BITSTAMP_API_VERSION = "2"
|
||||
BITSTAMP_API_TICKER = "ticker"
|
||||
BITSTAMP_API_TICKER_HOURLY = "ticker_hour"
|
||||
BITSTAMP_API_ORDERBOOK = "order_book"
|
||||
BITSTAMP_API_TRANSACTIONS = "transactions"
|
||||
BITSTAMP_API_EURUSD = "eur_usd"
|
||||
BITSTAMP_API_BALANCE = "balance"
|
||||
BITSTAMP_API_USER_TRANSACTIONS = "user_transactions"
|
||||
BITSTAMP_API_OPEN_ORDERS = "open_orders"
|
||||
BITSTAMP_API_ORDER_STATUS = "order_status"
|
||||
BITSTAMP_API_CANCEL_ORDER = "cancel_order"
|
||||
BITSTAMP_API_CANCEL_ALL_ORDERS = "cancel_all_orders"
|
||||
BITSTAMP_API_BUY = "buy"
|
||||
BITSTAMP_API_SELL = "sell"
|
||||
BITSTAMP_API_MARKET = "market"
|
||||
BITSTAMP_API_WITHDRAWAL_REQUESTS = "withdrawal_requests"
|
||||
BITSTAMP_API_BITCOIN_WITHDRAWAL = "bitcoin_withdrawal"
|
||||
BITSTAMP_API_BITCOIN_DEPOSIT = "bitcoin_deposit_address"
|
||||
BITSTAMP_API_UNCONFIRMED_BITCOIN = "unconfirmed_btc"
|
||||
BITSTAMP_API_RIPPLE_WITHDRAWAL = "ripple_withdrawal"
|
||||
BITSTAMP_API_RIPPLE_DESPOIT = "ripple_address"
|
||||
BITSTAMP_API_TRANSFER_TO_MAIN = "transfer-to-main"
|
||||
BITSTAMP_API_TRANSFER_FROM_MAIN = "transfer-from-main"
|
||||
BITSTAMP_API_XRP_WITHDRAWAL = "xrp_withdrawal"
|
||||
BITSTAMP_API_XRP_DESPOIT = "xrp_address"
|
||||
bitstampAPIURL = "https://www.bitstamp.net/api"
|
||||
bitstampAPIVersion = "2"
|
||||
bitstampAPITicker = "ticker"
|
||||
bitstampAPITickerHourly = "ticker_hour"
|
||||
bitstampAPIOrderbook = "order_book"
|
||||
bitstampAPITransactions = "transactions"
|
||||
bitstampAPIEURUSD = "eur_usd"
|
||||
bitstampAPIBalance = "balance"
|
||||
bitstampAPIUserTransactions = "user_transactions"
|
||||
bitstampAPIOpenOrders = "open_orders"
|
||||
bitstampAPIOrderStatus = "order_status"
|
||||
bitstampAPICancelOrder = "cancel_order"
|
||||
bitstampAPICancelAllOrders = "cancel_all_orders"
|
||||
bitstampAPIBuy = "buy"
|
||||
bitstampAPISell = "sell"
|
||||
bitstampAPIMarket = "market"
|
||||
bitstampAPIWithdrawalRequests = "withdrawal_requests"
|
||||
bitstampAPIBitcoinWithdrawal = "bitcoin_withdrawal"
|
||||
bitstampAPILTCWithdrawal = "ltc_withdrawal"
|
||||
bitstampAPIETHWithdrawal = "eth_withdrawal"
|
||||
bitstampAPIBitcoinDeposit = "bitcoin_deposit_address"
|
||||
bitstampAPILitecoinDeposit = "ltc_address"
|
||||
bitstampAPIEthereumDeposit = "eth_address"
|
||||
bitstampAPIUnconfirmedBitcoin = "unconfirmed_btc"
|
||||
bitstampAPITransferToMain = "transfer-to-main"
|
||||
bitstampAPITransferFromMain = "transfer-from-main"
|
||||
bitstampAPIXrpWithdrawal = "xrp_withdrawal"
|
||||
bitstampAPIXrpDeposit = "xrp_address"
|
||||
bitstampAPIReturnType = "string"
|
||||
)
|
||||
|
||||
// Bitstamp is the overarching type across the bitstamp package
|
||||
type Bitstamp struct {
|
||||
exchange.Base
|
||||
Balance BitstampBalances
|
||||
Balance Balances
|
||||
}
|
||||
|
||||
// SetDefaults sets default for Bitstamp
|
||||
func (b *Bitstamp) SetDefaults() {
|
||||
b.Name = "Bitstamp"
|
||||
b.Enabled = false
|
||||
@@ -57,6 +62,7 @@ func (b *Bitstamp) SetDefaults() {
|
||||
b.RESTPollingDelay = 10
|
||||
}
|
||||
|
||||
// Setup sets configuration values to bitstamp
|
||||
func (b *Bitstamp) Setup(exch config.ExchangeConfig) {
|
||||
if !exch.Enabled {
|
||||
b.SetEnabled(false)
|
||||
@@ -73,8 +79,9 @@ func (b *Bitstamp) Setup(exch config.ExchangeConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bitstamp) GetFee(currency string) float64 {
|
||||
switch currency {
|
||||
// GetFee returns fee on a currency pair
|
||||
func (b *Bitstamp) GetFee(currencyPair string) float64 {
|
||||
switch currencyPair {
|
||||
case "BTCUSD":
|
||||
return b.Balance.BTCUSDFee
|
||||
case "BTCEUR":
|
||||
@@ -90,39 +97,50 @@ func (b *Bitstamp) GetFee(currency string) float64 {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bitstamp) GetTicker(currency string, hourly bool) (BitstampTicker, error) {
|
||||
tickerEndpoint := BITSTAMP_API_TICKER
|
||||
// GetTicker returns ticker information
|
||||
func (b *Bitstamp) GetTicker(currency string, hourly bool) (Ticker, error) {
|
||||
response := Ticker{}
|
||||
tickerEndpoint := bitstampAPITicker
|
||||
|
||||
if hourly {
|
||||
tickerEndpoint = BITSTAMP_API_TICKER_HOURLY
|
||||
tickerEndpoint = bitstampAPITickerHourly
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("%s/v%s/%s/%s/", BITSTAMP_API_URL, BITSTAMP_API_VERSION, tickerEndpoint, common.StringToLower(currency))
|
||||
ticker := BitstampTicker{}
|
||||
|
||||
err := common.SendHTTPGetRequest(path, true, &ticker)
|
||||
|
||||
if err != nil {
|
||||
return ticker, err
|
||||
}
|
||||
|
||||
return ticker, nil
|
||||
path := fmt.Sprintf(
|
||||
"%s/v%s/%s/%s/",
|
||||
bitstampAPIURL,
|
||||
bitstampAPIVersion,
|
||||
tickerEndpoint,
|
||||
common.StringToLower(currency),
|
||||
)
|
||||
return response, common.SendHTTPGetRequest(path, true, &response)
|
||||
}
|
||||
|
||||
func (b *Bitstamp) GetOrderbook(currency string) (BitstampOrderbook, error) {
|
||||
// GetOrderbook Returns a JSON dictionary with "bids" and "asks". Each is a list
|
||||
// of open orders and each order is represented as a list holding the price and
|
||||
//the amount.
|
||||
func (b *Bitstamp) GetOrderbook(currency string) (Orderbook, error) {
|
||||
type response struct {
|
||||
Timestamp int64 `json:"timestamp,string"`
|
||||
Bids [][]string
|
||||
Asks [][]string
|
||||
Timestamp int64 `json:"timestamp,string"`
|
||||
Bids [][]string `json:"bids"`
|
||||
Asks [][]string `json:"asks"`
|
||||
}
|
||||
|
||||
resp := response{}
|
||||
path := fmt.Sprintf("%s/v%s/%s/%s/", BITSTAMP_API_URL, BITSTAMP_API_VERSION, BITSTAMP_API_ORDERBOOK, common.StringToLower(currency))
|
||||
|
||||
path := fmt.Sprintf(
|
||||
"%s/v%s/%s/%s/",
|
||||
bitstampAPIURL,
|
||||
bitstampAPIVersion,
|
||||
bitstampAPIOrderbook,
|
||||
common.StringToLower(currency),
|
||||
)
|
||||
|
||||
err := common.SendHTTPGetRequest(path, true, &resp)
|
||||
if err != nil {
|
||||
return BitstampOrderbook{}, err
|
||||
return Orderbook{}, err
|
||||
}
|
||||
|
||||
orderbook := BitstampOrderbook{}
|
||||
orderbook := Orderbook{}
|
||||
orderbook.Timestamp = resp.Timestamp
|
||||
|
||||
for _, x := range resp.Bids {
|
||||
@@ -136,7 +154,7 @@ func (b *Bitstamp) GetOrderbook(currency string) (BitstampOrderbook, error) {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
orderbook.Bids = append(orderbook.Bids, BitstampOrderbookBase{price, amount})
|
||||
orderbook.Bids = append(orderbook.Bids, OrderbookBase{price, amount})
|
||||
}
|
||||
|
||||
for _, x := range resp.Asks {
|
||||
@@ -150,44 +168,49 @@ func (b *Bitstamp) GetOrderbook(currency string) (BitstampOrderbook, error) {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
orderbook.Asks = append(orderbook.Asks, BitstampOrderbookBase{price, amount})
|
||||
orderbook.Asks = append(orderbook.Asks, OrderbookBase{price, amount})
|
||||
}
|
||||
|
||||
return orderbook, nil
|
||||
}
|
||||
|
||||
func (b *Bitstamp) GetTransactions(currency string, values url.Values) ([]BitstampTransactions, error) {
|
||||
path := common.EncodeURLValues(fmt.Sprintf("%s/v%s/%s/%s/", BITSTAMP_API_URL, BITSTAMP_API_VERSION, BITSTAMP_API_TRANSACTIONS, common.StringToLower(currency)), values)
|
||||
transactions := []BitstampTransactions{}
|
||||
err := common.SendHTTPGetRequest(path, true, &transactions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return transactions, nil
|
||||
// GetTransactions returns transaction information
|
||||
// value paramater ["time"] = "minute", "hour", "day" will collate your
|
||||
// response into time intervals. Implementation of value in test code.
|
||||
func (b *Bitstamp) GetTransactions(currencyPair string, values url.Values) ([]Transactions, error) {
|
||||
transactions := []Transactions{}
|
||||
path := common.EncodeURLValues(
|
||||
fmt.Sprintf(
|
||||
"%s/v%s/%s/%s/",
|
||||
bitstampAPIURL,
|
||||
bitstampAPIVersion,
|
||||
bitstampAPITransactions,
|
||||
common.StringToLower(currencyPair),
|
||||
),
|
||||
values,
|
||||
)
|
||||
|
||||
return transactions, common.SendHTTPGetRequest(path, true, &transactions)
|
||||
}
|
||||
|
||||
func (b *Bitstamp) GetEURUSDConversionRate() (BitstampEURUSDConversionRate, error) {
|
||||
rate := BitstampEURUSDConversionRate{}
|
||||
path := fmt.Sprintf("%s/%s", BITSTAMP_API_URL, BITSTAMP_API_EURUSD)
|
||||
err := common.SendHTTPGetRequest(path, true, &rate)
|
||||
// GetEURUSDConversionRate returns the conversion rate between Euro and USD
|
||||
func (b *Bitstamp) GetEURUSDConversionRate() (EURUSDConversionRate, error) {
|
||||
rate := EURUSDConversionRate{}
|
||||
path := fmt.Sprintf("%s/%s", bitstampAPIURL, bitstampAPIEURUSD)
|
||||
|
||||
if err != nil {
|
||||
return rate, err
|
||||
}
|
||||
return rate, nil
|
||||
return rate, common.SendHTTPGetRequest(path, true, &rate)
|
||||
}
|
||||
|
||||
func (b *Bitstamp) GetBalance() (BitstampBalances, error) {
|
||||
balance := BitstampBalances{}
|
||||
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_BALANCE, true, url.Values{}, &balance)
|
||||
// GetBalance returns full balance of currency held on the exchange
|
||||
func (b *Bitstamp) GetBalance() (Balances, error) {
|
||||
balance := Balances{}
|
||||
|
||||
if err != nil {
|
||||
return balance, err
|
||||
}
|
||||
return balance, nil
|
||||
return balance,
|
||||
b.SendAuthenticatedHTTPRequest(bitstampAPIBalance, true, url.Values{}, &balance)
|
||||
}
|
||||
|
||||
func (b *Bitstamp) GetUserTransactions(values url.Values) ([]BitstampUserTransactions, error) {
|
||||
// GetUserTransactions returns an array of transactions
|
||||
func (b *Bitstamp) GetUserTransactions(currencyPair string) ([]UserTransactions, error) {
|
||||
type Response struct {
|
||||
Date string `json:"datetime"`
|
||||
TransID int64 `json:"id"`
|
||||
@@ -200,25 +223,29 @@ func (b *Bitstamp) GetUserTransactions(values url.Values) ([]BitstampUserTransac
|
||||
Fee float64 `json:"fee,string"`
|
||||
OrderID int64 `json:"order_id"`
|
||||
}
|
||||
|
||||
response := []Response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_USER_TRANSACTIONS, true, values, &response)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if currencyPair != "" {
|
||||
if err := b.SendAuthenticatedHTTPRequest(bitstampAPIUserTransactions, true, url.Values{}, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if err := b.SendAuthenticatedHTTPRequest(bitstampAPIUserTransactions+"/"+currencyPair, true, url.Values{}, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
transactions := []BitstampUserTransactions{}
|
||||
transactions := []UserTransactions{}
|
||||
|
||||
for _, y := range response {
|
||||
tx := BitstampUserTransactions{}
|
||||
tx := UserTransactions{}
|
||||
tx.Date = y.Date
|
||||
tx.TransID = y.TransID
|
||||
tx.Type = y.Type
|
||||
|
||||
/* Hack due to inconsistent JSON values... */
|
||||
varType := reflect.TypeOf(y.USD).String()
|
||||
if varType == "string" {
|
||||
if varType == bitstampAPIReturnType {
|
||||
tx.USD, _ = strconv.ParseFloat(y.USD.(string), 64)
|
||||
} else {
|
||||
tx.USD = y.USD.(float64)
|
||||
@@ -228,14 +255,14 @@ func (b *Bitstamp) GetUserTransactions(values url.Values) ([]BitstampUserTransac
|
||||
tx.XRP = y.XRP
|
||||
|
||||
varType = reflect.TypeOf(y.BTC).String()
|
||||
if varType == "string" {
|
||||
if varType == bitstampAPIReturnType {
|
||||
tx.BTC, _ = strconv.ParseFloat(y.BTC.(string), 64)
|
||||
} else {
|
||||
tx.BTC = y.BTC.(float64)
|
||||
}
|
||||
|
||||
varType = reflect.TypeOf(y.BTCUSD).String()
|
||||
if varType == "string" {
|
||||
if varType == bitstampAPIReturnType {
|
||||
tx.BTCUSD, _ = strconv.ParseFloat(y.BTCUSD.(string), 64)
|
||||
} else {
|
||||
tx.BTCUSD = y.BTCUSD.(float64)
|
||||
@@ -249,184 +276,179 @@ func (b *Bitstamp) GetUserTransactions(values url.Values) ([]BitstampUserTransac
|
||||
return transactions, nil
|
||||
}
|
||||
|
||||
func (b *Bitstamp) GetOpenOrders(currency string) ([]BitstampOrder, error) {
|
||||
resp := []BitstampOrder{}
|
||||
path := fmt.Sprintf("%s/%s", BITSTAMP_API_OPEN_ORDERS, common.StringToLower(currency))
|
||||
err := b.SendAuthenticatedHTTPRequest(path, true, nil, &resp)
|
||||
// GetOpenOrders returns all open orders on the exchange
|
||||
func (b *Bitstamp) GetOpenOrders(currencyPair string) ([]Order, error) {
|
||||
resp := []Order{}
|
||||
path := fmt.Sprintf(
|
||||
"%s/%s", bitstampAPIOpenOrders, common.StringToLower(currencyPair),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
return resp, b.SendAuthenticatedHTTPRequest(path, true, nil, &resp)
|
||||
}
|
||||
|
||||
func (b *Bitstamp) GetOrderStatus(OrderID int64) (BitstampOrderStatus, error) {
|
||||
var req = url.Values{}
|
||||
// GetOrderStatus returns an the status of an order by its ID
|
||||
func (b *Bitstamp) GetOrderStatus(OrderID int64) (OrderStatus, error) {
|
||||
resp := OrderStatus{}
|
||||
req := url.Values{}
|
||||
req.Add("id", strconv.FormatInt(OrderID, 10))
|
||||
resp := BitstampOrderStatus{}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_CANCEL_ORDER, false, req, &resp)
|
||||
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
return resp,
|
||||
b.SendAuthenticatedHTTPRequest(bitstampAPIOrderStatus, false, req, &resp)
|
||||
}
|
||||
|
||||
// CancelOrder cancels order by ID
|
||||
func (b *Bitstamp) CancelOrder(OrderID int64) (bool, error) {
|
||||
var req = url.Values{}
|
||||
result := false
|
||||
var req = url.Values{}
|
||||
req.Add("id", strconv.FormatInt(OrderID, 10))
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_CANCEL_ORDER, true, req, &result)
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
return result,
|
||||
b.SendAuthenticatedHTTPRequest(bitstampAPICancelOrder, true, req, &result)
|
||||
}
|
||||
|
||||
// CancelAllOrders cancels all open orders on the exchange
|
||||
func (b *Bitstamp) CancelAllOrders() (bool, error) {
|
||||
result := false
|
||||
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_CANCEL_ALL_ORDERS, false, nil, &result)
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
return result,
|
||||
b.SendAuthenticatedHTTPRequest(bitstampAPICancelAllOrders, false, nil, &result)
|
||||
}
|
||||
|
||||
func (b *Bitstamp) PlaceOrder(currency string, price float64, amount float64, buy, market bool) (BitstampOrder, error) {
|
||||
// PlaceOrder places an order on the exchange.
|
||||
func (b *Bitstamp) PlaceOrder(currencyPair string, price float64, amount float64, buy, market bool) (Order, error) {
|
||||
var req = url.Values{}
|
||||
req.Add("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
req.Add("price", strconv.FormatFloat(price, 'f', -1, 64))
|
||||
response := BitstampOrder{}
|
||||
orderType := BITSTAMP_API_BUY
|
||||
path := ""
|
||||
response := Order{}
|
||||
orderType := bitstampAPIBuy
|
||||
|
||||
if !buy {
|
||||
orderType = BITSTAMP_API_SELL
|
||||
orderType = bitstampAPISell
|
||||
}
|
||||
|
||||
path = fmt.Sprintf("%s/%s", orderType, common.StringToLower(currency))
|
||||
path := fmt.Sprintf("%s/%s", orderType, common.StringToLower(currencyPair))
|
||||
|
||||
if market {
|
||||
path = fmt.Sprintf("%s/%s/%s", orderType, BITSTAMP_API_MARKET, common.StringToLower(currency))
|
||||
path = fmt.Sprintf("%s/%s/%s", orderType, bitstampAPIMarket, common.StringToLower(currencyPair))
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(path, true, req, &response)
|
||||
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
return response,
|
||||
b.SendAuthenticatedHTTPRequest(path, true, req, &response)
|
||||
}
|
||||
|
||||
func (b *Bitstamp) GetWithdrawalRequests(values url.Values) ([]BitstampWithdrawalRequests, error) {
|
||||
resp := []BitstampWithdrawalRequests{}
|
||||
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_WITHDRAWAL_REQUESTS, false, values, &resp)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// GetWithdrawalRequests returns withdrawl requests for the account
|
||||
// timedelta - positive integer with max value 50000000 which returns requests
|
||||
// from number of seconds ago to now.
|
||||
func (b *Bitstamp) GetWithdrawalRequests(timedelta int64) ([]WithdrawalRequests, error) {
|
||||
resp := []WithdrawalRequests{}
|
||||
if timedelta > 50000000 || timedelta < 0 {
|
||||
return resp, errors.New("time delta exceeded, max: 50000000 min: 0")
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
value := url.Values{}
|
||||
value.Set("timedelta", strconv.FormatInt(timedelta, 10))
|
||||
|
||||
if timedelta == 0 {
|
||||
value = url.Values{}
|
||||
}
|
||||
|
||||
return resp,
|
||||
b.SendAuthenticatedHTTPRequest(bitstampAPIWithdrawalRequests, false, value, &resp)
|
||||
}
|
||||
|
||||
func (b *Bitstamp) BitcoinWithdrawal(amount float64, address string, instant bool) (string, error) {
|
||||
// CryptoWithdrawal withdraws a cryptocurrency into a supplied wallet, returns ID
|
||||
// amount - The amount you want withdrawn
|
||||
// address - The wallet address of the cryptocurrency
|
||||
// symbol - the type of crypto ie "ltc", "btc", "eth"
|
||||
// destTag - only for XRP default to ""
|
||||
// instant - only for bitcoins
|
||||
func (b *Bitstamp) CryptoWithdrawal(amount float64, address, symbol, destTag string, instant bool) (string, error) {
|
||||
var req = url.Values{}
|
||||
req.Add("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
req.Add("address", address)
|
||||
|
||||
if instant {
|
||||
req.Add("instant", "1")
|
||||
} else {
|
||||
req.Add("instant", "0")
|
||||
}
|
||||
|
||||
type response struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
resp := response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_BITCOIN_WITHDRAWAL, false, req, &resp)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
switch common.StringToLower(symbol) {
|
||||
case "btc":
|
||||
if instant {
|
||||
req.Add("instant", "1")
|
||||
} else {
|
||||
req.Add("instant", "0")
|
||||
}
|
||||
return resp.ID,
|
||||
b.SendAuthenticatedHTTPRequest(bitstampAPIBitcoinWithdrawal, false, req, &resp)
|
||||
case "ltc":
|
||||
return resp.ID,
|
||||
b.SendAuthenticatedHTTPRequest(bitstampAPILTCWithdrawal, true, req, &resp)
|
||||
case "eth":
|
||||
return resp.ID,
|
||||
b.SendAuthenticatedHTTPRequest(bitstampAPIETHWithdrawal, true, req, &resp)
|
||||
case "xrp":
|
||||
if destTag != "" {
|
||||
req.Add("destination_tag", destTag)
|
||||
}
|
||||
return resp.ID,
|
||||
b.SendAuthenticatedHTTPRequest(bitstampAPIXrpWithdrawal, true, req, &resp)
|
||||
}
|
||||
|
||||
return resp.ID, nil
|
||||
return resp.ID,
|
||||
errors.New("incorrect symbol")
|
||||
}
|
||||
|
||||
func (b *Bitstamp) GetBitcoinDepositAddress() (string, error) {
|
||||
address := ""
|
||||
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_BITCOIN_DEPOSIT, false, url.Values{}, &address)
|
||||
|
||||
if err != nil {
|
||||
return address, err
|
||||
}
|
||||
return address, nil
|
||||
}
|
||||
|
||||
func (b *Bitstamp) GetUnconfirmedBitcoinDeposits() ([]BitstampUnconfirmedBTCTransactions, error) {
|
||||
response := []BitstampUnconfirmedBTCTransactions{}
|
||||
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_UNCONFIRMED_BITCOIN, false, nil, &response)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (b *Bitstamp) RippleWithdrawal(amount float64, address, currency string) (bool, error) {
|
||||
var req = url.Values{}
|
||||
req.Add("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
req.Add("address", address)
|
||||
req.Add("currency", currency)
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_RIPPLE_WITHDRAWAL, false, req, nil)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (b *Bitstamp) GetRippleDepositAddress() (string, error) {
|
||||
// GetCryptoDepositAddress returns a depositing address by crypto
|
||||
// crypto - example "btc", "ltc", "eth", or "xrp"
|
||||
func (b *Bitstamp) GetCryptoDepositAddress(crypto string) (string, error) {
|
||||
type response struct {
|
||||
Address string
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
resp := response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_RIPPLE_DESPOIT, false, nil, &resp)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
switch common.StringToLower(crypto) {
|
||||
case "btc":
|
||||
return resp.Address,
|
||||
b.SendAuthenticatedHTTPRequest(bitstampAPIBitcoinDeposit, false, nil, &resp.Address)
|
||||
case "ltc":
|
||||
return resp.Address,
|
||||
b.SendAuthenticatedHTTPRequest(bitstampAPILitecoinDeposit, true, nil, &resp)
|
||||
case "eth":
|
||||
return resp.Address,
|
||||
b.SendAuthenticatedHTTPRequest(bitstampAPIEthereumDeposit, true, nil, &resp)
|
||||
case "xrp":
|
||||
return resp.Address,
|
||||
b.SendAuthenticatedHTTPRequest(bitstampAPIXrpDeposit, true, nil, &resp)
|
||||
}
|
||||
|
||||
return resp.Address, nil
|
||||
return resp.Address, errors.New("incorrect cryptocurrency string")
|
||||
}
|
||||
|
||||
// GetUnconfirmedBitcoinDeposits returns unconfirmed transactions
|
||||
func (b *Bitstamp) GetUnconfirmedBitcoinDeposits() ([]UnconfirmedBTCTransactions, error) {
|
||||
response := []UnconfirmedBTCTransactions{}
|
||||
|
||||
return response,
|
||||
b.SendAuthenticatedHTTPRequest(bitstampAPIUnconfirmedBitcoin, false, nil, &response)
|
||||
}
|
||||
|
||||
// TransferAccountBalance transfers funds from either a main or sub account
|
||||
// amount - to transfers
|
||||
// currency - which currency to transfer
|
||||
// subaccount - name of account
|
||||
// toMain - bool either to or from account
|
||||
func (b *Bitstamp) TransferAccountBalance(amount float64, currency, subAccount string, toMain bool) (bool, error) {
|
||||
var req = url.Values{}
|
||||
req.Add("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
req.Add("currency", currency)
|
||||
req.Add("subAccount", subAccount)
|
||||
|
||||
path := BITSTAMP_API_TRANSFER_TO_MAIN
|
||||
path := bitstampAPITransferToMain
|
||||
if !toMain {
|
||||
path = BITSTAMP_API_TRANSFER_FROM_MAIN
|
||||
path = bitstampAPITransferFromMain
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(path, true, req, nil)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -434,55 +456,31 @@ func (b *Bitstamp) TransferAccountBalance(amount float64, currency, subAccount s
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (b *Bitstamp) XRPWithdrawal(amount float64, address, destTag string) (string, error) {
|
||||
var req = url.Values{}
|
||||
req.Add("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
req.Add("address", address)
|
||||
if destTag != "" {
|
||||
req.Add("destination_tag", destTag)
|
||||
}
|
||||
|
||||
type response struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
resp := response{}
|
||||
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_XRP_WITHDRAWAL, true, req, &resp)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.ID, nil
|
||||
}
|
||||
|
||||
func (b *Bitstamp) GetXRPDepositAddress() (BitstampXRPDepositResponse, error) {
|
||||
resp := BitstampXRPDepositResponse{}
|
||||
err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_XRP_DESPOIT, true, nil, &resp)
|
||||
|
||||
if err != nil {
|
||||
return BitstampXRPDepositResponse{}, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated request
|
||||
func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, v2 bool, values url.Values, result interface{}) (err error) {
|
||||
nonce := strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
if !b.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name)
|
||||
}
|
||||
|
||||
if b.Nonce.Get() == 0 {
|
||||
b.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
b.Nonce.Inc()
|
||||
}
|
||||
|
||||
if values == nil {
|
||||
values = url.Values{}
|
||||
}
|
||||
|
||||
values.Set("key", b.APIKey)
|
||||
values.Set("nonce", nonce)
|
||||
hmac := common.GetHMAC(common.HashSHA256, []byte(nonce+b.ClientID+b.APIKey), []byte(b.APISecret))
|
||||
values.Set("nonce", b.Nonce.String())
|
||||
hmac := common.GetHMAC(common.HashSHA256, []byte(b.Nonce.String()+b.ClientID+b.APIKey), []byte(b.APISecret))
|
||||
values.Set("signature", common.StringToUpper(common.HexEncodeToString(hmac)))
|
||||
|
||||
if v2 {
|
||||
path = fmt.Sprintf("%s/v%s/%s/", BITSTAMP_API_URL, BITSTAMP_API_VERSION, path)
|
||||
path = fmt.Sprintf("%s/v%s/%s/", bitstampAPIURL, bitstampAPIVersion, path)
|
||||
} else {
|
||||
path = fmt.Sprintf("%s/%s/", BITSTAMP_API_URL, path)
|
||||
path = fmt.Sprintf("%s/%s/", bitstampAPIURL, path)
|
||||
}
|
||||
|
||||
if b.Verbose {
|
||||
@@ -501,11 +499,17 @@ func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, v2 bool, values url
|
||||
log.Printf("Received raw: %s\n", resp)
|
||||
}
|
||||
|
||||
err = common.JSONDecode([]byte(resp), &result)
|
||||
|
||||
if err != nil {
|
||||
return errors.New("unable to JSON Unmarshal response")
|
||||
/* inconsistent errors, needs to be improved when in production*/
|
||||
if common.StringContains(resp, "500 error") {
|
||||
return errors.New("internal server: code 500")
|
||||
}
|
||||
|
||||
return nil
|
||||
capture := CaptureError{}
|
||||
if err = common.JSONDecode([]byte(resp), &capture); err == nil {
|
||||
if capture.Code != nil || capture.Error != nil || capture.Reason != nil || capture.Status != nil {
|
||||
errstring := fmt.Sprint("Status: ", capture.Status, ", Issue: ", capture.Error, ", Reason: ", capture.Reason, ", Code: ", capture.Code)
|
||||
return errors.New(errstring)
|
||||
}
|
||||
}
|
||||
return common.JSONDecode([]byte(resp), &result)
|
||||
}
|
||||
|
||||
346
exchanges/bitstamp/bitstamp_test.go
Normal file
346
exchanges/bitstamp/bitstamp_test.go
Normal file
@@ -0,0 +1,346 @@
|
||||
package bitstamp
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
)
|
||||
|
||||
// Please add your private keys and customerID for better tests
|
||||
const (
|
||||
apiKey = ""
|
||||
apiSecret = ""
|
||||
customerID = ""
|
||||
)
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
b.SetDefaults()
|
||||
|
||||
if b.Name != "Bitstamp" {
|
||||
t.Error("Test Failed - SetDefaults() error")
|
||||
}
|
||||
if b.Enabled != false {
|
||||
t.Error("Test Failed - SetDefaults() error")
|
||||
}
|
||||
if b.Verbose != false {
|
||||
t.Error("Test Failed - SetDefaults() error")
|
||||
}
|
||||
if b.Websocket != false {
|
||||
t.Error("Test Failed - SetDefaults() error")
|
||||
}
|
||||
if b.RESTPollingDelay != 10 {
|
||||
t.Error("Test Failed - SetDefaults() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
conf := config.ExchangeConfig{
|
||||
Name: "bla",
|
||||
Enabled: true,
|
||||
AuthenticatedAPISupport: true,
|
||||
}
|
||||
b.Setup(conf)
|
||||
|
||||
if b.Name != "bla" && b.Enabled != true && b.AuthenticatedAPISupport != true {
|
||||
t.Error("Test Failed - Setup() error")
|
||||
}
|
||||
conf.Enabled = false
|
||||
b.Setup(conf)
|
||||
}
|
||||
|
||||
func TestGetFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
if resp := b.GetFee("BTCUSD"); resp != 0 {
|
||||
t.Error("Test Failed - GetFee() error")
|
||||
}
|
||||
if resp := b.GetFee("BTCEUR"); resp != 0 {
|
||||
t.Error("Test Failed - GetFee() error")
|
||||
}
|
||||
if resp := b.GetFee("XRPEUR"); resp != 0 {
|
||||
t.Error("Test Failed - GetFee() error")
|
||||
}
|
||||
if resp := b.GetFee("XRPUSD"); resp != 0 {
|
||||
t.Error("Test Failed - GetFee() error")
|
||||
}
|
||||
if resp := b.GetFee("EURUSD"); resp != 0 {
|
||||
t.Error("Test Failed - GetFee() error")
|
||||
}
|
||||
if resp := b.GetFee("bla"); resp != 0 {
|
||||
t.Error("Test Failed - GetFee() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
_, err := b.GetTicker("BTCUSD", false)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetTicker() error", err)
|
||||
}
|
||||
_, err = b.GetTicker("BTCUSD", true)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetTicker() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
_, err := b.GetOrderbook("BTCUSD")
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetOrderbook() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTransactions(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
|
||||
value := url.Values{}
|
||||
value.Set("time", "hour")
|
||||
|
||||
_, err := b.GetTransactions("BTCUSD", value)
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetTransactions() error", err)
|
||||
}
|
||||
_, err = b.GetTransactions("wigwham", value)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetTransactions() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEURUSDConversionRate(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
_, err := b.GetEURUSDConversionRate()
|
||||
if err != nil {
|
||||
t.Error("Test Failed - GetEURUSDConversionRate() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBalance(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
b.APIKey = apiKey
|
||||
b.APISecret = apiSecret
|
||||
b.ClientID = customerID
|
||||
|
||||
_, err := b.GetBalance()
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetBalance() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUserTransactions(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
b.APIKey = apiKey
|
||||
b.APISecret = apiSecret
|
||||
b.ClientID = customerID
|
||||
|
||||
_, err := b.GetUserTransactions("")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetUserTransactions() error", err)
|
||||
}
|
||||
|
||||
_, err = b.GetUserTransactions("btcusd")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetUserTransactions() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOpenOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
b.APIKey = apiKey
|
||||
b.APISecret = apiSecret
|
||||
b.ClientID = customerID
|
||||
|
||||
_, err := b.GetOpenOrders("btcusd")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetOpenOrders() error", err)
|
||||
}
|
||||
_, err = b.GetOpenOrders("wigwham")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetOpenOrders() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderStatus(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
b.APIKey = apiKey
|
||||
b.APISecret = apiSecret
|
||||
b.ClientID = customerID
|
||||
|
||||
_, err := b.GetOrderStatus(1337)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetOpenOrders() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
b.APIKey = apiKey
|
||||
b.APISecret = apiSecret
|
||||
b.ClientID = customerID
|
||||
|
||||
resp, err := b.CancelOrder(1337)
|
||||
if err == nil || resp != false {
|
||||
t.Error("Test Failed - CancelOrder() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelAllOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
b.APIKey = apiKey
|
||||
b.APISecret = apiSecret
|
||||
b.ClientID = customerID
|
||||
|
||||
_, err := b.CancelAllOrders()
|
||||
if err == nil {
|
||||
t.Error("Test Failed - CancelAllOrders() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlaceOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
b.APIKey = apiKey
|
||||
b.APISecret = apiSecret
|
||||
b.ClientID = customerID
|
||||
|
||||
_, err := b.PlaceOrder("btcusd", 0.01, 1, true, true)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - PlaceOrder() error")
|
||||
}
|
||||
_, err = b.PlaceOrder("btcusd", 0.01, 1, true, false)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - PlaceOrder() error")
|
||||
}
|
||||
_, err = b.PlaceOrder("btcusd", 0.01, 1, false, false)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - PlaceOrder() error")
|
||||
}
|
||||
_, err = b.PlaceOrder("wigwham", 0.01, 1, false, false)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - PlaceOrder() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetWithdrawalRequests(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
b.APIKey = apiKey
|
||||
b.APISecret = apiSecret
|
||||
b.ClientID = customerID
|
||||
|
||||
_, err := b.GetWithdrawalRequests(0)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetWithdrawalRequests() error", err)
|
||||
}
|
||||
_, err = b.GetWithdrawalRequests(-1)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetWithdrawalRequests() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCryptoWithdrawal(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
b.APIKey = apiKey
|
||||
b.APISecret = apiSecret
|
||||
b.ClientID = customerID
|
||||
|
||||
_, err := b.CryptoWithdrawal(0, "bla", "btc", "", true)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - CryptoWithdrawal() error", err)
|
||||
}
|
||||
_, err = b.CryptoWithdrawal(0, "bla", "btc", "", false)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - CryptoWithdrawal() error", err)
|
||||
}
|
||||
_, err = b.CryptoWithdrawal(0, "bla", "ltc", "", false)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - CryptoWithdrawal() error", err)
|
||||
}
|
||||
_, err = b.CryptoWithdrawal(0, "bla", "eth", "", false)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - CryptoWithdrawal() error", err)
|
||||
}
|
||||
_, err = b.CryptoWithdrawal(0, "bla", "xrp", "someplace", false)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - CryptoWithdrawal() error", err)
|
||||
}
|
||||
_, err = b.CryptoWithdrawal(0, "bla", "ding!", "", false)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - CryptoWithdrawal() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBitcoinDepositAddress(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
b.APIKey = apiKey
|
||||
b.APISecret = apiSecret
|
||||
b.ClientID = customerID
|
||||
|
||||
_, err := b.GetCryptoDepositAddress("btc")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetCryptoDepositAddress() error", err)
|
||||
}
|
||||
_, err = b.GetCryptoDepositAddress("LTc")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetCryptoDepositAddress() error", err)
|
||||
}
|
||||
_, err = b.GetCryptoDepositAddress("eth")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetCryptoDepositAddress() error", err)
|
||||
}
|
||||
_, err = b.GetCryptoDepositAddress("xrp")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetCryptoDepositAddress() error", err)
|
||||
}
|
||||
_, err = b.GetCryptoDepositAddress("wigwham")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetCryptoDepositAddress() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUnconfirmedBitcoinDeposits(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
b.APIKey = apiKey
|
||||
b.APISecret = apiSecret
|
||||
b.ClientID = customerID
|
||||
|
||||
_, err := b.GetUnconfirmedBitcoinDeposits()
|
||||
if err == nil {
|
||||
t.Error("Test Failed - GetUnconfirmedBitcoinDeposits() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransferAccountBalance(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bitstamp{}
|
||||
b.APIKey = apiKey
|
||||
b.APISecret = apiSecret
|
||||
b.ClientID = customerID
|
||||
|
||||
_, err := b.TransferAccountBalance(1, "", "", true)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - TransferAccountBalance() error", err)
|
||||
}
|
||||
_, err = b.TransferAccountBalance(1, "btc", "", false)
|
||||
if err == nil {
|
||||
t.Error("Test Failed - TransferAccountBalance() error", err)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package bitstamp
|
||||
|
||||
type BitstampTicker struct {
|
||||
// Ticker holds ticker information
|
||||
type Ticker struct {
|
||||
Last float64 `json:"last,string"`
|
||||
High float64 `json:"high,string"`
|
||||
Low float64 `json:"low,string"`
|
||||
@@ -12,38 +13,21 @@ type BitstampTicker struct {
|
||||
Open float64 `json:"open,string"`
|
||||
}
|
||||
|
||||
type BitstampBalances struct {
|
||||
BTCReserved float64 `json:"btc_reserved,string"`
|
||||
BTCEURFee float64 `json:"btceur_fee,string"`
|
||||
BTCAvailable float64 `json:"btc_available,string"`
|
||||
XRPAvailable float64 `json:"xrp_available,string"`
|
||||
EURAvailable float64 `json:"eur_available,string"`
|
||||
USDReserved float64 `json:"usd_reserved,string"`
|
||||
EURReserved float64 `json:"eur_reserved,string"`
|
||||
XRPEURFee float64 `json:"xrpeur_fee,string"`
|
||||
XRPReserved float64 `json:"xrp_reserved,string"`
|
||||
XRPBalance float64 `json:"xrp_balance,string"`
|
||||
XRPUSDFee float64 `json:"xrpusd_fee,string"`
|
||||
EURBalance float64 `json:"eur_balance,string"`
|
||||
BTCBalance float64 `json:"btc_balance,string"`
|
||||
BTCUSDFee float64 `json:"btcusd_fee,string"`
|
||||
USDBalance float64 `json:"usd_balance,string"`
|
||||
USDAvailable float64 `json:"usd_available,string"`
|
||||
EURUSDFee float64 `json:"eurusd_fee,string"`
|
||||
}
|
||||
|
||||
type BitstampOrderbookBase struct {
|
||||
// OrderbookBase holds singular price information
|
||||
type OrderbookBase struct {
|
||||
Price float64
|
||||
Amount float64
|
||||
}
|
||||
|
||||
type BitstampOrderbook struct {
|
||||
// Orderbook holds orderbook information
|
||||
type Orderbook struct {
|
||||
Timestamp int64 `json:"timestamp,string"`
|
||||
Bids []BitstampOrderbookBase
|
||||
Asks []BitstampOrderbookBase
|
||||
Bids []OrderbookBase
|
||||
Asks []OrderbookBase
|
||||
}
|
||||
|
||||
type BitstampTransactions struct {
|
||||
// Transactions holds transaction data
|
||||
type Transactions struct {
|
||||
Date int64 `json:"date,string"`
|
||||
TradeID int64 `json:"tid,string"`
|
||||
Price float64 `json:"price,string"`
|
||||
@@ -51,12 +35,37 @@ type BitstampTransactions struct {
|
||||
Amount float64 `json:"amount,string"`
|
||||
}
|
||||
|
||||
type BitstampEURUSDConversionRate struct {
|
||||
// EURUSDConversionRate holds buy sell conversion rate information
|
||||
type EURUSDConversionRate struct {
|
||||
Buy float64 `json:"buy,string"`
|
||||
Sell float64 `json:"sell,string"`
|
||||
}
|
||||
|
||||
type BitstampUserTransactions struct {
|
||||
// Balances holds full balance information with the supplied APIKEYS
|
||||
type Balances struct {
|
||||
USDBalance float64 `json:"usd_balance,string"`
|
||||
BTCBalance float64 `json:"btc_balance,string"`
|
||||
EURBalance float64 `json:"eur_balance,string"`
|
||||
XRPBalance float64 `json:"xrp_balance,string"`
|
||||
USDReserved float64 `json:"usd_reserved,string"`
|
||||
BTCReserved float64 `json:"btc_reserved,string"`
|
||||
EURReserved float64 `json:"eur_reserved,string"`
|
||||
XRPReserved float64 `json:"xrp_reserved,string"`
|
||||
USDAvailable float64 `json:"usd_available,string"`
|
||||
BTCAvailable float64 `json:"btc_available,string"`
|
||||
EURAvailable float64 `json:"eur_available,string"`
|
||||
XRPAvailable float64 `json:"xrp_available,string"`
|
||||
BTCUSDFee float64 `json:"btcusd_fee,string"`
|
||||
BTCEURFee float64 `json:"btceur_fee,string"`
|
||||
EURUSDFee float64 `json:"eurusd_fee,string"`
|
||||
XRPUSDFee float64 `json:"xrpusd_fee,string"`
|
||||
XRPEURFee float64 `json:"xrpeur_fee,string"`
|
||||
XRPBTCFee float64 `json:"xrpbtc_fee,string"`
|
||||
Fee float64 `json:"fee,string"`
|
||||
}
|
||||
|
||||
// UserTransactions holds user transaction information
|
||||
type UserTransactions struct {
|
||||
Date string `json:"datetime"`
|
||||
TransID int64 `json:"id"`
|
||||
Type int `json:"type,string"`
|
||||
@@ -69,7 +78,8 @@ type BitstampUserTransactions struct {
|
||||
OrderID int64 `json:"order_id"`
|
||||
}
|
||||
|
||||
type BitstampOrder struct {
|
||||
// Order holds current open order data
|
||||
type Order struct {
|
||||
ID int64 `json:"id"`
|
||||
Date string `json:"datetime"`
|
||||
Type int `json:"type"`
|
||||
@@ -77,7 +87,8 @@ type BitstampOrder struct {
|
||||
Amount float64 `json:"amount"`
|
||||
}
|
||||
|
||||
type BitstampOrderStatus struct {
|
||||
// OrderStatus holds order status information
|
||||
type OrderStatus struct {
|
||||
Status string
|
||||
Transactions []struct {
|
||||
TradeID int64 `json:"tid"`
|
||||
@@ -88,22 +99,30 @@ type BitstampOrderStatus struct {
|
||||
}
|
||||
}
|
||||
|
||||
type BitstampWithdrawalRequests struct {
|
||||
OrderID int64 `json:"id"`
|
||||
Date string `json:"datetime"`
|
||||
Type int `json:"type"`
|
||||
Amount float64 `json:"amount,string"`
|
||||
Status int `json:"status"`
|
||||
Data interface{}
|
||||
// WithdrawalRequests holds request information on withdrawals
|
||||
type WithdrawalRequests struct {
|
||||
OrderID int64 `json:"id"`
|
||||
Date string `json:"datetime"`
|
||||
Type int `json:"type"`
|
||||
Amount float64 `json:"amount,string"`
|
||||
Status int `json:"status"`
|
||||
Data interface{}
|
||||
Address string `json:"address"` // Bitcoin withdrawals only
|
||||
TransactionID string `json:"transaction_id"` // Bitcoin withdrawals only
|
||||
}
|
||||
|
||||
type BitstampUnconfirmedBTCTransactions struct {
|
||||
// UnconfirmedBTCTransactions holds address information about unconfirmed
|
||||
// transactions
|
||||
type UnconfirmedBTCTransactions struct {
|
||||
Amount float64 `json:"amount,string"`
|
||||
Address string `json:"address"`
|
||||
Confirmations int `json:"confirmations"`
|
||||
}
|
||||
|
||||
type BitstampXRPDepositResponse struct {
|
||||
Address string `json:"address"`
|
||||
DestinationTag int64 `json:"destination_tag"`
|
||||
// CaptureError is used to capture unmarshalled errors
|
||||
type CaptureError struct {
|
||||
Status interface{} `json:"status"`
|
||||
Reason interface{} `json:"reason"`
|
||||
Code interface{} `json:"code"`
|
||||
Error interface{} `json:"error"`
|
||||
}
|
||||
|
||||
@@ -7,23 +7,28 @@ import (
|
||||
"github.com/toorop/go-pusher"
|
||||
)
|
||||
|
||||
type BitstampPusherOrderbook struct {
|
||||
// PusherOrderbook holds order book information to be pushed
|
||||
type PusherOrderbook struct {
|
||||
Asks [][]string `json:"asks"`
|
||||
Bids [][]string `json:"bids"`
|
||||
}
|
||||
type BitstampPusherTrade struct {
|
||||
|
||||
// PusherTrade holds trade information to be pushed
|
||||
type PusherTrade struct {
|
||||
Price float64 `json:"price"`
|
||||
Amount float64 `json:"amount"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
const (
|
||||
BITSTAMP_PUSHER_KEY = "de504dc5763aeef9ff52"
|
||||
// BitstampPusherKey holds the current pusher key
|
||||
BitstampPusherKey = "de504dc5763aeef9ff52"
|
||||
)
|
||||
|
||||
// PusherClient starts the push mechanism
|
||||
func (b *Bitstamp) PusherClient() {
|
||||
for b.Enabled && b.Websocket {
|
||||
pusherClient, err := pusher.NewClient(BITSTAMP_PUSHER_KEY)
|
||||
pusherClient, err := pusher.NewClient(BitstampPusherKey)
|
||||
if err != nil {
|
||||
log.Printf("%s Unable to connect to Websocket. Error: %s\n", b.GetName(), err)
|
||||
continue
|
||||
@@ -55,13 +60,13 @@ func (b *Bitstamp) PusherClient() {
|
||||
for b.Websocket {
|
||||
select {
|
||||
case data := <-dataChannelTrade:
|
||||
result := BitstampPusherOrderbook{}
|
||||
result := PusherOrderbook{}
|
||||
err := common.JSONDecode([]byte(data.Data), &result)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
case trade := <-tradeChannelTrade:
|
||||
result := BitstampPusherTrade{}
|
||||
result := PusherTrade{}
|
||||
err := common.JSONDecode([]byte(trade.Data), &result)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
||||
@@ -6,16 +6,18 @@ import (
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/currency/pair"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges"
|
||||
exchange "github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/stats"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
)
|
||||
|
||||
// Start starts a new go routine run
|
||||
func (b *Bitstamp) Start() {
|
||||
go b.Run()
|
||||
}
|
||||
|
||||
// Run starts a new websocket connection runs a new go routine pusher
|
||||
func (b *Bitstamp) Run() {
|
||||
if b.Verbose {
|
||||
log.Printf("%s Websocket: %s.", b.GetName(), common.IsEnabled(b.Websocket))
|
||||
@@ -36,7 +38,7 @@ func (b *Bitstamp) Run() {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("Bitstamp %s: Last %f High %f Low %f Volume %f\n", currency.Pair().String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
log.Printf("Bitstamp %s: Last %f High %f Low %f Volume %f\n", exchange.FormatCurrency(currency).String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
stats.AddExchangeInfo(b.GetName(), currency.GetFirstCurrency().String(), currency.GetSecondCurrency().String(), ticker.Last, ticker.Volume)
|
||||
}()
|
||||
}
|
||||
@@ -44,6 +46,7 @@ func (b *Bitstamp) Run() {
|
||||
}
|
||||
}
|
||||
|
||||
// GetTickerPrice returns ticker price information
|
||||
func (b *Bitstamp) GetTickerPrice(p pair.CurrencyPair) (ticker.TickerPrice, error) {
|
||||
tickerNew, err := ticker.GetTicker(b.GetName(), p)
|
||||
if err == nil {
|
||||
@@ -67,6 +70,7 @@ func (b *Bitstamp) GetTickerPrice(p pair.CurrencyPair) (ticker.TickerPrice, erro
|
||||
return tickerPrice, nil
|
||||
}
|
||||
|
||||
// GetOrderbookEx returns base orderbook information
|
||||
func (b *Bitstamp) GetOrderbookEx(p pair.CurrencyPair) (orderbook.OrderbookBase, error) {
|
||||
ob, err := orderbook.GetOrderbook(b.GetName(), p)
|
||||
if err == nil {
|
||||
@@ -94,11 +98,12 @@ func (b *Bitstamp) GetOrderbookEx(p pair.CurrencyPair) (orderbook.OrderbookBase,
|
||||
return orderBook, nil
|
||||
}
|
||||
|
||||
//GetExchangeAccountInfo : Retrieves balances for all enabled currencies for the Bitstamp exchange
|
||||
func (e *Bitstamp) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
|
||||
// GetExchangeAccountInfo retrieves balances for all enabled currencies for the
|
||||
// Bitstamp exchange
|
||||
func (b *Bitstamp) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
|
||||
var response exchange.AccountInfo
|
||||
response.ExchangeName = e.GetName()
|
||||
accountBalance, err := e.GetBalance()
|
||||
response.ExchangeName = b.GetName()
|
||||
accountBalance, err := b.GetBalance()
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ func (b *Bittrex) PlaceBuyLimit(currencyPair string, quantity, rate float64) ([]
|
||||
values.Set("market", currencyPair)
|
||||
values.Set("quantity", strconv.FormatFloat(quantity, 'E', -1, 64))
|
||||
values.Set("rate", strconv.FormatFloat(rate, 'E', -1, 64))
|
||||
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetBalances)
|
||||
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIBuyLimit)
|
||||
|
||||
return id, b.HTTPRequest(path, true, values, &id)
|
||||
}
|
||||
@@ -187,7 +187,7 @@ func (b *Bittrex) PlaceSellLimit(currencyPair string, quantity, rate float64) ([
|
||||
values.Set("market", currencyPair)
|
||||
values.Set("quantity", strconv.FormatFloat(quantity, 'E', -1, 64))
|
||||
values.Set("rate", strconv.FormatFloat(rate, 'E', -1, 64))
|
||||
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetBalances)
|
||||
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPISellLimit)
|
||||
|
||||
return id, b.HTTPRequest(path, true, values, &id)
|
||||
}
|
||||
@@ -200,7 +200,7 @@ func (b *Bittrex) GetOpenOrders(currencyPair string) ([]Order, error) {
|
||||
if !(currencyPair == "" || currencyPair == " ") {
|
||||
values.Set("market", currencyPair)
|
||||
}
|
||||
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetBalances)
|
||||
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetOpenOrders)
|
||||
|
||||
return orders, b.HTTPRequest(path, true, values, &orders)
|
||||
}
|
||||
@@ -210,7 +210,7 @@ func (b *Bittrex) CancelOrder(uuid string) ([]Balance, error) {
|
||||
var balances []Balance
|
||||
values := url.Values{}
|
||||
values.Set("uuid", uuid)
|
||||
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetBalances)
|
||||
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPICancel)
|
||||
|
||||
return balances, b.HTTPRequest(path, true, values, &balances)
|
||||
}
|
||||
@@ -283,16 +283,16 @@ func (b *Bittrex) GetOrderHistory(currencyPair string) ([]Order, error) {
|
||||
return orders, b.HTTPRequest(path, true, values, &orders)
|
||||
}
|
||||
|
||||
// GetWithdrawelHistory is used to retrieve your withdrawal history. If currency
|
||||
// GetWithdrawalHistory is used to retrieve your withdrawal history. If currency
|
||||
// omitted it will return the entire history
|
||||
func (b *Bittrex) GetWithdrawelHistory(currency string) ([]WithdrawalHistory, error) {
|
||||
func (b *Bittrex) GetWithdrawalHistory(currency string) ([]WithdrawalHistory, error) {
|
||||
var history []WithdrawalHistory
|
||||
values := url.Values{}
|
||||
|
||||
if !(currency == "" || currency == " ") {
|
||||
values.Set("currency", currency)
|
||||
}
|
||||
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetOrderHistory)
|
||||
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetWithdrawalHistory)
|
||||
|
||||
return history, b.HTTPRequest(path, true, values, &history)
|
||||
}
|
||||
@@ -306,7 +306,7 @@ func (b *Bittrex) GetDepositHistory(currency string) ([]WithdrawalHistory, error
|
||||
if !(currency == "" || currency == " ") {
|
||||
values.Set("currency", currency)
|
||||
}
|
||||
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetOrderHistory)
|
||||
path := fmt.Sprintf("%s/%s", bittrexAPIURL, bittrexAPIGetDepositHistory)
|
||||
|
||||
return history, b.HTTPRequest(path, true, values, &history)
|
||||
}
|
||||
@@ -314,10 +314,18 @@ func (b *Bittrex) GetDepositHistory(currency string) ([]WithdrawalHistory, error
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated http request to a desired
|
||||
// path
|
||||
func (b *Bittrex) SendAuthenticatedHTTPRequest(path string, values url.Values, result interface{}) (err error) {
|
||||
nonce := strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
if !b.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name)
|
||||
}
|
||||
|
||||
if b.Nonce.Get() == 0 {
|
||||
b.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
b.Nonce.Inc()
|
||||
}
|
||||
values.Set("apikey", b.APIKey)
|
||||
values.Set("apisecret", b.APISecret)
|
||||
values.Set("nonce", nonce)
|
||||
values.Set("nonce", b.Nonce.String())
|
||||
rawQuery := path + "?" + values.Encode()
|
||||
hmac := common.GetHMAC(
|
||||
common.HashSHA512, []byte(rawQuery), []byte(b.APISecret),
|
||||
|
||||
@@ -13,6 +13,7 @@ const (
|
||||
)
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
t.Parallel()
|
||||
b := Bittrex{}
|
||||
b.SetDefaults()
|
||||
if b.GetName() != "Bittrex" {
|
||||
@@ -21,6 +22,7 @@ func TestSetDefaults(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
t.Parallel()
|
||||
exch := config.ExchangeConfig{
|
||||
Name: "Bittrex",
|
||||
APIKey: apiKey,
|
||||
@@ -39,6 +41,7 @@ func TestSetup(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetMarkets(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
_, err := obj.GetMarkets()
|
||||
if err != nil {
|
||||
@@ -47,6 +50,7 @@ func TestGetMarkets(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetCurrencies(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
_, err := obj.GetCurrencies()
|
||||
if err != nil {
|
||||
@@ -55,6 +59,7 @@ func TestGetCurrencies(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
invalid := ""
|
||||
btc := "btc-ltc"
|
||||
doge := "btc-DOGE"
|
||||
@@ -75,6 +80,7 @@ func TestGetTicker(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetMarketSummaries(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
_, err := obj.GetMarketSummaries()
|
||||
if err != nil {
|
||||
@@ -83,6 +89,7 @@ func TestGetMarketSummaries(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetMarketSummary(t *testing.T) {
|
||||
t.Parallel()
|
||||
pairOne := "BTC-LTC"
|
||||
invalid := "WigWham"
|
||||
|
||||
@@ -98,6 +105,7 @@ func TestGetMarketSummary(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
_, err := obj.GetOrderbook("btc-ltc")
|
||||
if err != nil {
|
||||
@@ -110,6 +118,7 @@ func TestGetOrderbook(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetMarketHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
_, err := obj.GetMarketHistory("btc-ltc")
|
||||
if err != nil {
|
||||
@@ -122,6 +131,7 @@ func TestGetMarketHistory(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPlaceBuyLimit(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
@@ -132,6 +142,7 @@ func TestPlaceBuyLimit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPlaceSellLimit(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
@@ -142,6 +153,7 @@ func TestPlaceSellLimit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetOpenOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
@@ -156,6 +168,7 @@ func TestGetOpenOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCancelOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
@@ -166,6 +179,7 @@ func TestCancelOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetAccountBalances(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
@@ -176,6 +190,7 @@ func TestGetAccountBalances(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetAccountBalanceByCurrency(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
@@ -186,6 +201,7 @@ func TestGetAccountBalanceByCurrency(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetDepositAddress(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
@@ -196,6 +212,7 @@ func TestGetDepositAddress(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
@@ -206,6 +223,7 @@ func TestWithdraw(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
@@ -220,6 +238,7 @@ func TestGetOrder(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
@@ -234,20 +253,22 @@ func TestGetOrderHistory(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetWithdrawelHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
_, err := obj.GetWithdrawelHistory("")
|
||||
_, err := obj.GetWithdrawalHistory("")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - Bittrex - GetWithdrawelHistory() error")
|
||||
t.Error("Test Failed - Bittrex - GetWithdrawalHistory() error")
|
||||
}
|
||||
_, err = obj.GetWithdrawelHistory("btc-ltc")
|
||||
_, err = obj.GetWithdrawalHistory("btc-ltc")
|
||||
if err == nil {
|
||||
t.Error("Test Failed - Bittrex - GetWithdrawelHistory() error")
|
||||
t.Error("Test Failed - Bittrex - GetWithdrawalHistory() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDepositHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
obj := Bittrex{}
|
||||
obj.APIKey = apiKey
|
||||
obj.APISecret = apiSecret
|
||||
|
||||
137
exchanges/bittrex/bittrex_wrapper.go
Normal file
137
exchanges/bittrex/bittrex_wrapper.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package bittrex
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/currency/pair"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/stats"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
)
|
||||
|
||||
// Start stats the Bittrex go routine
|
||||
func (b *Bittrex) Start() {
|
||||
go b.Run()
|
||||
}
|
||||
|
||||
// Run implements the Bittrex wrapper
|
||||
func (b *Bittrex) Run() {
|
||||
if b.Verbose {
|
||||
log.Printf("%s polling delay: %ds.\n", b.GetName(), b.RESTPollingDelay)
|
||||
log.Printf("%s %d currencies enabled: %s.\n", b.GetName(), len(b.EnabledPairs), b.EnabledPairs)
|
||||
}
|
||||
|
||||
exchangeProducts, err := b.GetMarkets()
|
||||
if err != nil {
|
||||
log.Printf("%s Failed to get available symbols.\n", b.GetName())
|
||||
} else {
|
||||
var currencies []string
|
||||
for x := range exchangeProducts {
|
||||
if !exchangeProducts[x].IsActive {
|
||||
continue
|
||||
}
|
||||
currencies = append(currencies,
|
||||
common.ReplaceString(exchangeProducts[x].MarketName, "-", "", -1))
|
||||
}
|
||||
err = b.UpdateAvailableCurrencies(currencies)
|
||||
if err != nil {
|
||||
log.Printf("%s Failed to get config.\n", b.GetName())
|
||||
}
|
||||
}
|
||||
|
||||
for b.Enabled {
|
||||
for _, x := range b.EnabledPairs {
|
||||
currency := pair.NewCurrencyPair(x[0:3], x[3:])
|
||||
currency.Delimiter = "-"
|
||||
go func() {
|
||||
ticker, err := b.GetTickerPrice(currency)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("Bittrex %s Last %f Bid %f Ask %f Volume %f\n", exchange.FormatCurrency(currency).String(), ticker.Last, ticker.Bid, ticker.Ask, ticker.Volume)
|
||||
stats.AddExchangeInfo(b.GetName(), currency.GetFirstCurrency().String(), currency.GetSecondCurrency().String(), ticker.Last, ticker.Volume)
|
||||
}()
|
||||
}
|
||||
time.Sleep(time.Second * b.RESTPollingDelay)
|
||||
}
|
||||
}
|
||||
|
||||
//GetExchangeAccountInfo Retrieves balances for all enabled currencies for the Bittrexexchange
|
||||
func (b *Bittrex) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
|
||||
var response exchange.AccountInfo
|
||||
response.ExchangeName = b.GetName()
|
||||
accountBalance, err := b.GetAccountBalances()
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
for i := 0; i < len(accountBalance); i++ {
|
||||
var exchangeCurrency exchange.AccountCurrencyInfo
|
||||
exchangeCurrency.CurrencyName = accountBalance[i].Currency
|
||||
exchangeCurrency.TotalValue = accountBalance[i].Balance
|
||||
exchangeCurrency.Hold = accountBalance[i].Balance - accountBalance[i].Available
|
||||
response.Currencies = append(response.Currencies, exchangeCurrency)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// GetTickerPrice returns the ticker for a currencyp pair
|
||||
func (b *Bittrex) GetTickerPrice(p pair.CurrencyPair) (ticker.TickerPrice, error) {
|
||||
tickerNew, err := ticker.GetTicker(b.GetName(), p)
|
||||
if err == nil {
|
||||
return tickerNew, nil
|
||||
}
|
||||
|
||||
var tickerPrice ticker.TickerPrice
|
||||
tick, err := b.GetMarketSummary(p.Pair().Lower().String())
|
||||
if err != nil {
|
||||
return tickerPrice, err
|
||||
}
|
||||
tickerPrice.Pair = p
|
||||
tickerPrice.Ask = tick[0].Ask
|
||||
tickerPrice.Bid = tick[0].Bid
|
||||
tickerPrice.Last = tick[0].Last
|
||||
tickerPrice.Volume = tick[0].Volume
|
||||
ticker.ProcessTicker(b.GetName(), p, tickerPrice)
|
||||
return tickerPrice, nil
|
||||
}
|
||||
|
||||
// GetOrderbookEx returns the orderbook for a currencyp pair
|
||||
func (b *Bittrex) GetOrderbookEx(p pair.CurrencyPair) (orderbook.OrderbookBase, error) {
|
||||
ob, err := orderbook.GetOrderbook(b.GetName(), p)
|
||||
if err == nil {
|
||||
return ob, nil
|
||||
}
|
||||
|
||||
var orderBook orderbook.OrderbookBase
|
||||
orderbookNew, err := b.GetOrderbook(p.Pair().Lower().String())
|
||||
if err != nil {
|
||||
return orderBook, err
|
||||
}
|
||||
|
||||
for x := range orderbookNew.Buy {
|
||||
orderBook.Bids = append(orderBook.Bids,
|
||||
orderbook.OrderbookItem{
|
||||
Amount: orderbookNew.Buy[x].Quantity,
|
||||
Price: orderbookNew.Buy[x].Rate,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
for x := range orderbookNew.Sell {
|
||||
orderBook.Asks = append(orderBook.Asks,
|
||||
orderbook.OrderbookItem{
|
||||
Amount: orderbookNew.Sell[x].Quantity,
|
||||
Price: orderbookNew.Sell[x].Rate,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
orderBook.Pair = p
|
||||
orderbook.ProcessOrderbook(b.GetName(), p, orderBook)
|
||||
return orderBook, nil
|
||||
}
|
||||
@@ -15,37 +15,39 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
BTCC_API_URL = "https://api.btcchina.com/"
|
||||
BTCC_API_AUTHENTICATED_METHOD = "api_trade_v1.php"
|
||||
BTCC_API_VER = "2.0.1.3"
|
||||
BTCC_ORDER_BUY = "buyOrder2"
|
||||
BTCC_ORDER_SELL = "sellOrder2"
|
||||
BTCC_ORDER_CANCEL = "cancelOrder"
|
||||
BTCC_ICEBERG_BUY = "buyIcebergOrder"
|
||||
BTCC_ICEBERG_SELL = "sellIcebergOrder"
|
||||
BTCC_ICEBERG_ORDER = "getIcebergOrder"
|
||||
BTCC_ICEBERG_ORDERS = "getIcebergOrders"
|
||||
BTCC_ICEBERG_CANCEL = "cancelIcebergOrder"
|
||||
BTCC_ACCOUNT_INFO = "getAccountInfo"
|
||||
BTCC_DEPOSITS = "getDeposits"
|
||||
BTCC_MARKETDEPTH = "getMarketDepth2"
|
||||
BTCC_ORDER = "getOrder"
|
||||
BTCC_ORDERS = "getOrders"
|
||||
BTCC_TRANSACTIONS = "getTransactions"
|
||||
BTCC_WITHDRAWAL = "getWithdrawal"
|
||||
BTCC_WITHDRAWALS = "getWithdrawals"
|
||||
BTCC_WITHDRAWAL_REQUEST = "requestWithdrawal"
|
||||
BTCC_STOPORDER_BUY = "buyStopOrder"
|
||||
BTCC_STOPORDER_SELL = "sellStopOrder"
|
||||
BTCC_STOPORDER_CANCEL = "cancelStopOrder"
|
||||
BTCC_STOPORDER = "getStopOrder"
|
||||
BTCC_STOPORDERS = "getStopOrders"
|
||||
btccAPIUrl = "https://api.btcchina.com/"
|
||||
btccAPIAuthenticatedMethod = "api_trade_v1.php"
|
||||
btccAPIVersion = "2.0.1.3"
|
||||
btccOrderBuy = "buyOrder2"
|
||||
btccOrderSell = "sellOrder2"
|
||||
btccOrderCancel = "cancelOrder"
|
||||
btccIcebergBuy = "buyIcebergOrder"
|
||||
btccIcebergSell = "sellIcebergOrder"
|
||||
btccIcebergOrder = "getIcebergOrder"
|
||||
btccIcebergOrders = "getIcebergOrders"
|
||||
btccIcebergCancel = "cancelIcebergOrder"
|
||||
btccAccountInfo = "getAccountInfo"
|
||||
btccDeposits = "getDeposits"
|
||||
btccMarketdepth = "getMarketDepth2"
|
||||
btccOrder = "getOrder"
|
||||
btccOrders = "getOrders"
|
||||
btccTransactions = "getTransactions"
|
||||
btccWithdrawal = "getWithdrawal"
|
||||
btccWithdrawals = "getWithdrawals"
|
||||
btccWithdrawalRequest = "requestWithdrawal"
|
||||
btccStoporderBuy = "buyStopOrder"
|
||||
btccStoporderSell = "sellStopOrder"
|
||||
btccStoporderCancel = "cancelStopOrder"
|
||||
btccStoporder = "getStopOrder"
|
||||
btccStoporders = "getStopOrders"
|
||||
)
|
||||
|
||||
// BTCC is the main overaching type across the BTCC package
|
||||
type BTCC struct {
|
||||
exchange.Base
|
||||
}
|
||||
|
||||
// SetDefaults sets default values for the exchange
|
||||
func (b *BTCC) SetDefaults() {
|
||||
b.Name = "BTCC"
|
||||
b.Enabled = false
|
||||
@@ -55,7 +57,7 @@ func (b *BTCC) SetDefaults() {
|
||||
b.RESTPollingDelay = 10
|
||||
}
|
||||
|
||||
//Setup is run on startup to setup exchange with config values
|
||||
// Setup is run on startup to setup exchange with config values
|
||||
func (b *BTCC) Setup(exch config.ExchangeConfig) {
|
||||
if !exch.Enabled {
|
||||
b.SetEnabled(false)
|
||||
@@ -72,36 +74,40 @@ func (b *BTCC) Setup(exch config.ExchangeConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
// GetFee returns the fees associated with transactions
|
||||
func (b *BTCC) GetFee() float64 {
|
||||
return b.Fee
|
||||
}
|
||||
|
||||
func (b *BTCC) GetTicker(symbol string) (BTCCTicker, error) {
|
||||
type Response struct {
|
||||
Ticker BTCCTicker
|
||||
}
|
||||
|
||||
// GetTicker returns ticker information
|
||||
// currencyPair - Example "btccny", "ltccny" or "ltcbtc"
|
||||
func (b *BTCC) GetTicker(currencyPair string) (Ticker, error) {
|
||||
resp := Response{}
|
||||
req := fmt.Sprintf("%sdata/ticker?market=%s", BTCC_API_URL, symbol)
|
||||
err := common.SendHTTPGetRequest(req, true, &resp)
|
||||
if err != nil {
|
||||
return BTCCTicker{}, err
|
||||
}
|
||||
return resp.Ticker, nil
|
||||
req := fmt.Sprintf("%sdata/ticker?market=%s", btccAPIUrl, currencyPair)
|
||||
|
||||
return resp.Ticker, common.SendHTTPGetRequest(req, true, &resp)
|
||||
}
|
||||
|
||||
func (b *BTCC) GetTradesLast24h(symbol string) bool {
|
||||
req := fmt.Sprintf("%sdata/trades?market=%s", BTCC_API_URL, symbol)
|
||||
err := common.SendHTTPGetRequest(req, true, nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
// GetTradesLast24h returns the trades executed on the exchange over the past
|
||||
// 24 hours by currency pair
|
||||
// currencyPair - Example "btccny", "ltccny" or "ltcbtc"
|
||||
func (b *BTCC) GetTradesLast24h(currencyPair string) ([]Trade, error) {
|
||||
trades := []Trade{}
|
||||
req := fmt.Sprintf("%sdata/trades?market=%s", btccAPIUrl, currencyPair)
|
||||
|
||||
return trades, common.SendHTTPGetRequest(req, true, &trades)
|
||||
}
|
||||
|
||||
func (b *BTCC) GetTradeHistory(symbol string, limit, sinceTid int64, time time.Time) bool {
|
||||
req := fmt.Sprintf("%sdata/historydata?market=%s", BTCC_API_URL, symbol)
|
||||
// GetTradeHistory returns trade history data
|
||||
// currencyPair - Example "btccny", "ltccny" or "ltcbtc"
|
||||
// limit - limits the returned trades example "10"
|
||||
// sinceTid - returns trade records starting from id supplied example "5000"
|
||||
// time - returns trade records starting from unix time 1406794449
|
||||
func (b *BTCC) GetTradeHistory(currencyPair string, limit, sinceTid int64, time time.Time) ([]Trade, error) {
|
||||
trades := []Trade{}
|
||||
|
||||
req := fmt.Sprintf("%sdata/historydata?market=%s", btccAPIUrl, currencyPair)
|
||||
|
||||
v := url.Values{}
|
||||
|
||||
if limit > 0 {
|
||||
@@ -115,37 +121,33 @@ func (b *BTCC) GetTradeHistory(symbol string, limit, sinceTid int64, time time.T
|
||||
}
|
||||
|
||||
req = common.EncodeURLValues(req, v)
|
||||
err := common.SendHTTPGetRequest(req, true, nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
||||
return trades, common.SendHTTPGetRequest(req, true, &trades)
|
||||
}
|
||||
|
||||
func (b *BTCC) GetOrderBook(symbol string, limit int) (BTCCOrderbook, error) {
|
||||
result := BTCCOrderbook{}
|
||||
req := fmt.Sprintf("%sdata/orderbook?market=%s&limit=%d", BTCC_API_URL, symbol, limit)
|
||||
err := common.SendHTTPGetRequest(req, true, &result)
|
||||
if err != nil {
|
||||
return BTCCOrderbook{}, err
|
||||
// GetOrderBook returns current market order book
|
||||
// currencyPair - Example "btccny", "ltccny" or "ltcbtc"
|
||||
// limit - limits the returned trades example "10" if 0 will return full
|
||||
// orderbook
|
||||
func (b *BTCC) GetOrderBook(currencyPair string, limit int) (Orderbook, error) {
|
||||
result := Orderbook{}
|
||||
|
||||
req := fmt.Sprintf("%sdata/orderbook?market=%s&limit=%d", btccAPIUrl, currencyPair, limit)
|
||||
if limit == 0 {
|
||||
req = fmt.Sprintf("%sdata/orderbook?market=%s", btccAPIUrl, currencyPair)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
return result, common.SendHTTPGetRequest(req, true, &result)
|
||||
}
|
||||
|
||||
func (b *BTCC) GetAccountInfo(infoType string) {
|
||||
func (b *BTCC) GetAccountInfo(infoType string) error {
|
||||
params := make([]interface{}, 0)
|
||||
|
||||
if len(infoType) > 0 {
|
||||
params = append(params, infoType)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_ACCOUNT_INFO, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
return b.SendAuthenticatedHTTPRequest(btccAccountInfo, params)
|
||||
}
|
||||
|
||||
func (b *BTCC) PlaceOrder(buyOrder bool, price, amount float64, market string) {
|
||||
@@ -157,9 +159,9 @@ func (b *BTCC) PlaceOrder(buyOrder bool, price, amount float64, market string) {
|
||||
params = append(params, market)
|
||||
}
|
||||
|
||||
req := BTCC_ORDER_BUY
|
||||
req := btccOrderBuy
|
||||
if !buyOrder {
|
||||
req = BTCC_ORDER_SELL
|
||||
req = btccOrderSell
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(req, params)
|
||||
@@ -177,7 +179,7 @@ func (b *BTCC) CancelOrder(orderID int64, market string) {
|
||||
params = append(params, market)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_ORDER_CANCEL, params)
|
||||
err := b.SendAuthenticatedHTTPRequest(btccOrderCancel, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -192,7 +194,7 @@ func (b *BTCC) GetDeposits(currency string, pending bool) {
|
||||
params = append(params, pending)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_DEPOSITS, params)
|
||||
err := b.SendAuthenticatedHTTPRequest(btccDeposits, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -210,7 +212,7 @@ func (b *BTCC) GetMarketDepth(market string, limit int64) {
|
||||
params = append(params, market)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_MARKETDEPTH, params)
|
||||
err := b.SendAuthenticatedHTTPRequest(btccMarketdepth, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -229,7 +231,7 @@ func (b *BTCC) GetOrder(orderID int64, market string, detailed bool) {
|
||||
params = append(params, detailed)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_ORDER, params)
|
||||
err := b.SendAuthenticatedHTTPRequest(btccOrder, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -263,7 +265,7 @@ func (b *BTCC) GetOrders(openonly bool, market string, limit, offset, since int6
|
||||
params = append(params, detailed)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_ORDERS, params)
|
||||
err := b.SendAuthenticatedHTTPRequest(btccOrders, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -293,7 +295,7 @@ func (b *BTCC) GetTransactions(transType string, limit, offset, since int64, sin
|
||||
params = append(params, sinceType)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_TRANSACTIONS, params)
|
||||
err := b.SendAuthenticatedHTTPRequest(btccTransactions, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -308,7 +310,7 @@ func (b *BTCC) GetWithdrawal(withdrawalID int64, currency string) {
|
||||
params = append(params, currency)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_WITHDRAWAL, params)
|
||||
err := b.SendAuthenticatedHTTPRequest(btccWithdrawal, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -323,7 +325,7 @@ func (b *BTCC) GetWithdrawals(currency string, pending bool) {
|
||||
params = append(params, pending)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_WITHDRAWALS, params)
|
||||
err := b.SendAuthenticatedHTTPRequest(btccWithdrawals, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -335,7 +337,7 @@ func (b *BTCC) RequestWithdrawal(currency string, amount float64) {
|
||||
params = append(params, currency)
|
||||
params = append(params, amount)
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_WITHDRAWAL_REQUEST, params)
|
||||
err := b.SendAuthenticatedHTTPRequest(btccWithdrawalRequest, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -353,9 +355,9 @@ func (b *BTCC) IcebergOrder(buyOrder bool, price, amount, discAmount, variance f
|
||||
params = append(params, market)
|
||||
}
|
||||
|
||||
req := BTCC_ICEBERG_BUY
|
||||
req := btccIcebergBuy
|
||||
if !buyOrder {
|
||||
req = BTCC_ICEBERG_SELL
|
||||
req = btccIcebergSell
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(req, params)
|
||||
@@ -373,7 +375,7 @@ func (b *BTCC) GetIcebergOrder(orderID int64, market string) {
|
||||
params = append(params, market)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_ICEBERG_ORDER, params)
|
||||
err := b.SendAuthenticatedHTTPRequest(btccIcebergOrder, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -395,7 +397,7 @@ func (b *BTCC) GetIcebergOrders(limit, offset int64, market string) {
|
||||
params = append(params, market)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_ICEBERG_ORDERS, params)
|
||||
err := b.SendAuthenticatedHTTPRequest(btccIcebergOrders, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -410,7 +412,7 @@ func (b *BTCC) CancelIcebergOrder(orderID int64, market string) {
|
||||
params = append(params, market)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_ICEBERG_CANCEL, params)
|
||||
err := b.SendAuthenticatedHTTPRequest(btccIcebergCancel, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -439,9 +441,9 @@ func (b *BTCC) PlaceStopOrder(buyOder bool, stopPrice, price, amount, trailingAm
|
||||
params = append(params, market)
|
||||
}
|
||||
|
||||
req := BTCC_STOPORDER_BUY
|
||||
req := btccStoporderBuy
|
||||
if !buyOder {
|
||||
req = BTCC_STOPORDER_SELL
|
||||
req = btccStoporderSell
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(req, params)
|
||||
@@ -459,7 +461,7 @@ func (b *BTCC) GetStopOrder(orderID int64, market string) {
|
||||
params = append(params, market)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_STOPORDER, params)
|
||||
err := b.SendAuthenticatedHTTPRequest(btccStoporder, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -493,7 +495,7 @@ func (b *BTCC) GetStopOrders(status, orderType string, stopPrice float64, limit,
|
||||
params = append(params, market)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_STOPORDERS, params)
|
||||
err := b.SendAuthenticatedHTTPRequest(btccStoporders, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -508,7 +510,7 @@ func (b *BTCC) CancelStopOrder(orderID int64, market string) {
|
||||
params = append(params, market)
|
||||
}
|
||||
|
||||
err := b.SendAuthenticatedHTTPRequest(BTCC_STOPORDER_CANCEL, params)
|
||||
err := b.SendAuthenticatedHTTPRequest(btccStoporderCancel, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@@ -516,8 +518,16 @@ func (b *BTCC) CancelStopOrder(orderID int64, market string) {
|
||||
}
|
||||
|
||||
func (b *BTCC) SendAuthenticatedHTTPRequest(method string, params []interface{}) (err error) {
|
||||
nonce := strconv.FormatInt(time.Now().UnixNano(), 10)[0:16]
|
||||
encoded := fmt.Sprintf("tonce=%s&accesskey=%s&requestmethod=post&id=%d&method=%s¶ms=", nonce, b.APIKey, 1, method)
|
||||
if !b.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name)
|
||||
}
|
||||
|
||||
if b.Nonce.Get() == 0 {
|
||||
b.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
b.Nonce.Inc()
|
||||
}
|
||||
encoded := fmt.Sprintf("tonce=%s&accesskey=%s&requestmethod=post&id=%d&method=%s¶ms=", b.Nonce.String()[0:16], b.APIKey, 1, method)
|
||||
|
||||
if len(params) == 0 {
|
||||
params = make([]interface{}, 0)
|
||||
@@ -563,7 +573,7 @@ func (b *BTCC) SendAuthenticatedHTTPRequest(method string, params []interface{})
|
||||
postData["method"] = method
|
||||
postData["params"] = params
|
||||
postData["id"] = 1
|
||||
apiURL := BTCC_API_URL + BTCC_API_AUTHENTICATED_METHOD
|
||||
apiURL := btccAPIUrl + btccAPIAuthenticatedMethod
|
||||
data, err := common.JSONEncode(postData)
|
||||
|
||||
if err != nil {
|
||||
@@ -577,7 +587,7 @@ func (b *BTCC) SendAuthenticatedHTTPRequest(method string, params []interface{})
|
||||
headers := make(map[string]string)
|
||||
headers["Content-type"] = "application/json-rpc"
|
||||
headers["Authorization"] = "Basic " + common.Base64Encode([]byte(b.APIKey+":"+common.HexEncodeToString(hmac)))
|
||||
headers["Json-Rpc-Tonce"] = nonce
|
||||
headers["Json-Rpc-Tonce"] = b.Nonce.String()
|
||||
|
||||
resp, err := common.SendHTTPRequest("POST", apiURL, headers, strings.NewReader(string(data)))
|
||||
|
||||
|
||||
79
exchanges/btcc/btcc_test.go
Normal file
79
exchanges/btcc/btcc_test.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package btcc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
)
|
||||
|
||||
// Please supply your own APIkeys here to do better tests
|
||||
const (
|
||||
apiKey = ""
|
||||
apiSecret = ""
|
||||
)
|
||||
|
||||
var b BTCC
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
b.SetDefaults()
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
conf := config.ExchangeConfig{
|
||||
Enabled: true,
|
||||
}
|
||||
b.Setup(conf)
|
||||
|
||||
conf = config.ExchangeConfig{
|
||||
Enabled: false,
|
||||
APIKey: apiKey,
|
||||
APISecret: apiSecret,
|
||||
}
|
||||
b.Setup(conf)
|
||||
}
|
||||
|
||||
func TestGetFee(t *testing.T) {
|
||||
if b.GetFee() != 0 {
|
||||
t.Error("Test failed - GetFee() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
_, err := b.GetTicker("ltccny")
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetTicker() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTradesLast24h(t *testing.T) {
|
||||
_, err := b.GetTradesLast24h("ltccny")
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetTradesLast24h() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTradeHistory(t *testing.T) {
|
||||
_, err := b.GetTradeHistory("ltccny", 0, 0, time.Time{})
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetTradeHistory() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderBook(t *testing.T) {
|
||||
_, err := b.GetOrderBook("ltccny", 100)
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetOrderBook() error", err)
|
||||
}
|
||||
_, err = b.GetOrderBook("ltccny", 0)
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetOrderBook() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccountInfo(t *testing.T) {
|
||||
err := b.GetAccountInfo("")
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetAccountInfo() error", err)
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,45 @@
|
||||
package btcc
|
||||
|
||||
type BTCCTicker struct {
|
||||
High float64 `json:",string"`
|
||||
Low float64 `json:",string"`
|
||||
Buy float64 `json:",string"`
|
||||
Sell float64 `json:",string"`
|
||||
Last float64 `json:",string"`
|
||||
Vol float64 `json:",string"`
|
||||
Date int64
|
||||
Vwap float64 `json:",string"`
|
||||
Prev_close float64 `json:",string"`
|
||||
Open float64 `json:",string"`
|
||||
// Response is the generalized response type
|
||||
type Response struct {
|
||||
Ticker Ticker `json:"ticker"`
|
||||
BtcCny Ticker `json:"ticker_btccny"`
|
||||
LtcCny Ticker `json:"ticker_ltccny"`
|
||||
LtcBtc Ticker `json:"ticker_ltcbtc"`
|
||||
}
|
||||
|
||||
type BTCCProfile struct {
|
||||
// Ticker holds basic ticker information
|
||||
type Ticker struct {
|
||||
High float64 `json:"high,string"`
|
||||
Low float64 `json:"low,string"`
|
||||
Buy float64 `json:"buy,string"`
|
||||
Sell float64 `json:"sell,string"`
|
||||
Last float64 `json:"last,string"`
|
||||
Vol float64 `json:"vol,string"`
|
||||
Date int64 `json:"date"`
|
||||
Vwap float64 `json:"vwap,string"`
|
||||
PrevClose float64 `json:"prev_close,string"`
|
||||
Open float64 `json:"open,string"`
|
||||
}
|
||||
|
||||
// Trade holds executed trade data
|
||||
type Trade struct {
|
||||
Date int64 `json:"date,string"`
|
||||
Price float64 `json:"price"`
|
||||
Amount float64 `json:"amount"`
|
||||
TID int64 `json:"tid,string"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// Orderbook holds orderbook data
|
||||
type Orderbook struct {
|
||||
Bids [][]float64 `json:"bids"`
|
||||
Asks [][]float64 `json:"asks"`
|
||||
Date int64 `json:"date"`
|
||||
}
|
||||
|
||||
// Profile holds profile information
|
||||
type Profile struct {
|
||||
Username string
|
||||
TradePasswordEnabled bool `json:"trade_password_enabled,bool"`
|
||||
OTPEnabled bool `json:"otp_enabled,bool"`
|
||||
@@ -29,13 +55,8 @@ type BTCCProfile struct {
|
||||
APIKeyPermission int64 `json:"api_key_permission"`
|
||||
}
|
||||
|
||||
type BTCCOrderbook struct {
|
||||
Bids [][]float64 `json:"bids"`
|
||||
Asks [][]float64 `json:"asks"`
|
||||
Date int64 `json:"date"`
|
||||
}
|
||||
|
||||
type BTCCCurrencyGeneric struct {
|
||||
// CurrencyGeneric holds currency information
|
||||
type CurrencyGeneric struct {
|
||||
Currency string
|
||||
Symbol string
|
||||
Amount string
|
||||
@@ -43,7 +64,8 @@ type BTCCCurrencyGeneric struct {
|
||||
AmountDecimal float64 `json:"amount_decimal"`
|
||||
}
|
||||
|
||||
type BTCCOrder struct {
|
||||
// Order holds order information
|
||||
type Order struct {
|
||||
ID int64
|
||||
Type string
|
||||
Price float64
|
||||
@@ -52,16 +74,18 @@ type BTCCOrder struct {
|
||||
AmountOrig float64 `json:"amount_original"`
|
||||
Date int64
|
||||
Status string
|
||||
Detail BTCCOrderDetail
|
||||
Detail OrderDetail
|
||||
}
|
||||
|
||||
type BTCCOrderDetail struct {
|
||||
// OrderDetail holds order detail information
|
||||
type OrderDetail struct {
|
||||
Dateline int64
|
||||
Price float64
|
||||
Amount float64
|
||||
}
|
||||
|
||||
type BTCCWithdrawal struct {
|
||||
// Withdrawal holds withdrawal transaction information
|
||||
type Withdrawal struct {
|
||||
ID int64
|
||||
Address string
|
||||
Currency string
|
||||
@@ -71,7 +95,8 @@ type BTCCWithdrawal struct {
|
||||
Status string
|
||||
}
|
||||
|
||||
type BTCCDeposit struct {
|
||||
// Deposit holds deposit address information
|
||||
type Deposit struct {
|
||||
ID int64
|
||||
Address string
|
||||
Currency string
|
||||
@@ -80,17 +105,20 @@ type BTCCDeposit struct {
|
||||
Status string
|
||||
}
|
||||
|
||||
type BTCCBidAsk struct {
|
||||
// BidAsk holds bid and ask information
|
||||
type BidAsk struct {
|
||||
Price float64
|
||||
Amount float64
|
||||
}
|
||||
|
||||
type BTCCDepth struct {
|
||||
Bid []BTCCBidAsk
|
||||
Ask []BTCCBidAsk
|
||||
// Depth holds order book depth
|
||||
type Depth struct {
|
||||
Bid []BidAsk
|
||||
Ask []BidAsk
|
||||
}
|
||||
|
||||
type BTCCTransaction struct {
|
||||
// Transaction holds transaction information
|
||||
type Transaction struct {
|
||||
ID int64
|
||||
Type string
|
||||
BTCAmount float64 `json:"btc_amount"`
|
||||
@@ -99,7 +127,8 @@ type BTCCTransaction struct {
|
||||
Date int64
|
||||
}
|
||||
|
||||
type BTCCIcebergOrder struct {
|
||||
// IcebergOrder holds iceberg lettuce
|
||||
type IcebergOrder struct {
|
||||
ID int64
|
||||
Type string
|
||||
Price float64
|
||||
@@ -112,7 +141,8 @@ type BTCCIcebergOrder struct {
|
||||
Status string
|
||||
}
|
||||
|
||||
type BTCCStopOrder struct {
|
||||
// StopOrder holds stop order information
|
||||
type StopOrder struct {
|
||||
ID int64
|
||||
Type string
|
||||
StopPrice float64 `json:"stop_price"`
|
||||
@@ -126,19 +156,22 @@ type BTCCStopOrder struct {
|
||||
OrderID int64 `json:"order_id"`
|
||||
}
|
||||
|
||||
type BTCCWebsocketOrder struct {
|
||||
// WebsocketOrder holds websocket order information
|
||||
type WebsocketOrder struct {
|
||||
Price float64 `json:"price"`
|
||||
TotalAmount float64 `json:"totalamount"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type BTCCWebsocketGroupOrder struct {
|
||||
Asks []BTCCWebsocketOrder `json:"ask"`
|
||||
Bids []BTCCWebsocketOrder `json:"bid"`
|
||||
Market string `json:"market"`
|
||||
// WebsocketGroupOrder holds websocket group order book information
|
||||
type WebsocketGroupOrder struct {
|
||||
Asks []WebsocketOrder `json:"ask"`
|
||||
Bids []WebsocketOrder `json:"bid"`
|
||||
Market string `json:"market"`
|
||||
}
|
||||
|
||||
type BTCCWebsocketTrade struct {
|
||||
// WebsocketTrade holds websocket trade information
|
||||
type WebsocketTrade struct {
|
||||
Amount float64 `json:"amount"`
|
||||
Date float64 `json:"date"`
|
||||
Market string `json:"market"`
|
||||
@@ -147,7 +180,8 @@ type BTCCWebsocketTrade struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type BTCCWebsocketTicker struct {
|
||||
// WebsocketTicker holds websocket ticker information
|
||||
type WebsocketTicker struct {
|
||||
Buy float64 `json:"buy"`
|
||||
Date float64 `json:"date"`
|
||||
High float64 `json:"high"`
|
||||
|
||||
@@ -56,7 +56,7 @@ func (b *BTCC) OnMessage(message []byte, output chan socketio.Message) {
|
||||
|
||||
func (b *BTCC) OnTicker(message []byte, output chan socketio.Message) {
|
||||
type Response struct {
|
||||
Ticker BTCCWebsocketTicker `json:"ticker"`
|
||||
Ticker WebsocketTicker `json:"ticker"`
|
||||
}
|
||||
var resp Response
|
||||
err := common.JSONDecode(message, &resp)
|
||||
@@ -69,7 +69,7 @@ func (b *BTCC) OnTicker(message []byte, output chan socketio.Message) {
|
||||
|
||||
func (b *BTCC) OnGroupOrder(message []byte, output chan socketio.Message) {
|
||||
type Response struct {
|
||||
GroupOrder BTCCWebsocketGroupOrder `json:"grouporder"`
|
||||
GroupOrder WebsocketGroupOrder `json:"grouporder"`
|
||||
}
|
||||
var resp Response
|
||||
err := common.JSONDecode(message, &resp)
|
||||
@@ -81,7 +81,7 @@ func (b *BTCC) OnGroupOrder(message []byte, output chan socketio.Message) {
|
||||
}
|
||||
|
||||
func (b *BTCC) OnTrade(message []byte, output chan socketio.Message) {
|
||||
trade := BTCCWebsocketTrade{}
|
||||
trade := WebsocketTrade{}
|
||||
err := common.JSONDecode(message, &trade)
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/currency/pair"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges"
|
||||
exchange "github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/stats"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
@@ -36,7 +36,7 @@ func (b *BTCC) Run() {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("BTCC %s: Last %f High %f Low %f Volume %f\n", currency.Pair().String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
log.Printf("BTCC %s: Last %f High %f Low %f Volume %f\n", exchange.FormatCurrency(currency).String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
stats.AddExchangeInfo(b.GetName(), currency.GetFirstCurrency().String(), currency.GetSecondCurrency().String(), ticker.Last, ticker.Volume)
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -293,8 +293,16 @@ func (b *BTCE) RedeemCoupon(coupon string) (BTCERedeemCoupon, error) {
|
||||
}
|
||||
|
||||
func (b *BTCE) SendAuthenticatedHTTPRequest(method string, values url.Values, result interface{}) (err error) {
|
||||
nonce := strconv.FormatInt(time.Now().Unix(), 10)
|
||||
values.Set("nonce", nonce)
|
||||
if !b.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name)
|
||||
}
|
||||
|
||||
if b.Nonce.Get() == 0 {
|
||||
b.Nonce.Set(time.Now().Unix())
|
||||
} else {
|
||||
b.Nonce.Inc()
|
||||
}
|
||||
values.Set("nonce", b.Nonce.String())
|
||||
values.Set("method", method)
|
||||
|
||||
encoded := values.Encode()
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
@@ -15,22 +14,36 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
BTCMARKETS_API_URL = "https://api.btcmarkets.net"
|
||||
BTCMARKETS_API_VERSION = "0"
|
||||
BTCMARKETS_ACCOUNT_BALANCE = "/account/balance"
|
||||
BTCMARKETS_ORDER_CREATE = "/order/create"
|
||||
BTCMARKETS_ORDER_CANCEL = "/order/cancel"
|
||||
BTCMARKETS_ORDER_HISTORY = "/order/history"
|
||||
BTCMARKETS_ORDER_OPEN = "/order/open"
|
||||
BTCMARKETS_ORDER_TRADE_HISTORY = "/order/trade/history"
|
||||
BTCMARKETS_ORDER_DETAIL = "/order/detail"
|
||||
btcMarketsAPIURL = "https://api.btcmarkets.net"
|
||||
btcMarketsAPIVersion = "0"
|
||||
btcMarketsAccountBalance = "/account/balance"
|
||||
btcMarketsOrderCreate = "/order/create"
|
||||
btcMarketsOrderCancel = "/order/cancel"
|
||||
btcMarketsOrderHistory = "/order/history"
|
||||
btcMarketsOrderOpen = "/order/open"
|
||||
btcMarketsOrderTradeHistory = "/order/trade/history"
|
||||
btcMarketsOrderDetail = "/order/detail"
|
||||
btcMarketsWithdrawCrypto = "/fundtransfer/withdrawCrypto"
|
||||
btcMarketsWithdrawAud = "/fundtransfer/withdrawEFT"
|
||||
|
||||
//Status Values
|
||||
orderStatusNew = "New"
|
||||
orderStatusPlaced = "Placed"
|
||||
orderStatusFailed = "Failed"
|
||||
orderStatusError = "Error"
|
||||
orderStatusCancelled = "Cancelled"
|
||||
orderStatusPartiallyCancelled = "Partially Cancelled"
|
||||
orderStatusFullyMatched = "Fully Matched"
|
||||
orderStatusPartiallyMatched = "Partially Matched"
|
||||
)
|
||||
|
||||
// BTCMarkets is the overarching type across the BTCMarkets package
|
||||
type BTCMarkets struct {
|
||||
exchange.Base
|
||||
Ticker map[string]BTCMarketsTicker
|
||||
Ticker map[string]Ticker
|
||||
}
|
||||
|
||||
// SetDefaults sets basic defaults
|
||||
func (b *BTCMarkets) SetDefaults() {
|
||||
b.Name = "BTC Markets"
|
||||
b.Enabled = false
|
||||
@@ -38,9 +51,10 @@ func (b *BTCMarkets) SetDefaults() {
|
||||
b.Verbose = false
|
||||
b.Websocket = false
|
||||
b.RESTPollingDelay = 10
|
||||
b.Ticker = make(map[string]BTCMarketsTicker)
|
||||
b.Ticker = make(map[string]Ticker)
|
||||
}
|
||||
|
||||
// Setup takes in an exchange configuration and sets all paramaters
|
||||
func (b *BTCMarkets) Setup(exch config.ExchangeConfig) {
|
||||
if !exch.Enabled {
|
||||
b.SetEnabled(false)
|
||||
@@ -58,109 +72,90 @@ func (b *BTCMarkets) Setup(exch config.ExchangeConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
// GetFee returns the BTCMarkets fee on transactions
|
||||
func (b *BTCMarkets) GetFee() float64 {
|
||||
return b.Fee
|
||||
}
|
||||
|
||||
func (b *BTCMarkets) GetTicker(symbol string) (BTCMarketsTicker, error) {
|
||||
ticker := BTCMarketsTicker{}
|
||||
path := fmt.Sprintf("/market/%s/AUD/tick", symbol)
|
||||
err := common.SendHTTPGetRequest(BTCMARKETS_API_URL+path, true, &ticker)
|
||||
if err != nil {
|
||||
return BTCMarketsTicker{}, err
|
||||
}
|
||||
return ticker, nil
|
||||
// GetTicker returns a ticker
|
||||
// symbol - example "btc" or "ltc"
|
||||
func (b *BTCMarkets) GetTicker(symbol string) (Ticker, error) {
|
||||
ticker := Ticker{}
|
||||
path := fmt.Sprintf("/market/%s/AUD/tick", common.StringToUpper(symbol))
|
||||
|
||||
return ticker,
|
||||
common.SendHTTPGetRequest(btcMarketsAPIURL+path, true, &ticker)
|
||||
}
|
||||
|
||||
func (b *BTCMarkets) GetOrderbook(symbol string) (BTCMarketsOrderbook, error) {
|
||||
orderbook := BTCMarketsOrderbook{}
|
||||
path := fmt.Sprintf("/market/%s/AUD/orderbook", symbol)
|
||||
err := common.SendHTTPGetRequest(BTCMARKETS_API_URL+path, true, &orderbook)
|
||||
if err != nil {
|
||||
return BTCMarketsOrderbook{}, err
|
||||
}
|
||||
return orderbook, nil
|
||||
// GetOrderbook returns current orderbook
|
||||
// symbol - example "btc" or "ltc"
|
||||
func (b *BTCMarkets) GetOrderbook(symbol string) (Orderbook, error) {
|
||||
orderbook := Orderbook{}
|
||||
path := fmt.Sprintf("/market/%s/AUD/orderbook", common.StringToUpper(symbol))
|
||||
|
||||
return orderbook,
|
||||
common.SendHTTPGetRequest(btcMarketsAPIURL+path, true, &orderbook)
|
||||
}
|
||||
|
||||
func (b *BTCMarkets) GetTrades(symbol string, values url.Values) ([]BTCMarketsTrade, error) {
|
||||
trades := []BTCMarketsTrade{}
|
||||
path := common.EncodeURLValues(fmt.Sprintf("%s/market/%s/AUD/trades", BTCMARKETS_API_URL, symbol), values)
|
||||
err := common.SendHTTPGetRequest(path, true, &trades)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return trades, nil
|
||||
// GetTrades returns executed trades on the exchange
|
||||
// symbol - example "btc" or "ltc"
|
||||
// values - optional paramater "since" example values.Set(since, "59868345231")
|
||||
func (b *BTCMarkets) GetTrades(symbol string, values url.Values) ([]Trade, error) {
|
||||
trades := []Trade{}
|
||||
path := common.EncodeURLValues(fmt.Sprintf("%s/market/%s/AUD/trades", btcMarketsAPIURL, symbol), values)
|
||||
|
||||
return trades, common.SendHTTPGetRequest(path, true, &trades)
|
||||
}
|
||||
|
||||
func (b *BTCMarkets) Order(currency, instrument string, price, amount int64, orderSide, orderType, clientReq string) (int, error) {
|
||||
type Order struct {
|
||||
Currency string `json:"currency"`
|
||||
Instrument string `json:"instrument"`
|
||||
Price int64 `json:"price"`
|
||||
Volume int64 `json:"volume"`
|
||||
OrderSide string `json:"orderSide"`
|
||||
OrderType string `json:"ordertype"`
|
||||
ClientRequestId string `json:"clientRequestId"`
|
||||
// NewOrder requests a new order and returns an ID
|
||||
// currency - example "AUD"
|
||||
// instrument - example "BTC"
|
||||
// price - example 13000000000 (i.e x 100000000)
|
||||
// amount - example 100000000 (i.e x 100000000)
|
||||
// orderside - example "Bid" or "Ask"
|
||||
// orderType - example "limit"
|
||||
// clientReq - example "abc-cdf-1000"
|
||||
func (b *BTCMarkets) NewOrder(currency, instrument string, price, amount int64, orderSide, orderType, clientReq string) (int, error) {
|
||||
order := OrderToGo{
|
||||
Currency: common.StringToUpper(currency),
|
||||
Instrument: common.StringToUpper(instrument),
|
||||
Price: price * common.SatoshisPerBTC,
|
||||
Volume: amount * common.SatoshisPerBTC,
|
||||
OrderSide: orderSide,
|
||||
OrderType: orderType,
|
||||
ClientRequestID: clientReq,
|
||||
}
|
||||
order := Order{}
|
||||
order.Currency = currency
|
||||
order.Instrument = instrument
|
||||
order.Price = price * common.SatoshisPerBTC
|
||||
order.Volume = amount * common.SatoshisPerBTC
|
||||
order.OrderSide = orderSide
|
||||
order.OrderType = orderType
|
||||
order.ClientRequestId = clientReq
|
||||
|
||||
type Response struct {
|
||||
Success bool `json:"success"`
|
||||
ErrorCode int `json:"errorCode"`
|
||||
ErrorMessage string `json:"errorMessage"`
|
||||
ID int `json:"id"`
|
||||
ClientRequestID string `json:"clientRequestId"`
|
||||
}
|
||||
var resp Response
|
||||
|
||||
err := b.SendAuthenticatedRequest("POST", BTCMARKETS_ORDER_CREATE, order, &resp)
|
||||
resp := Response{}
|
||||
|
||||
err := b.SendAuthenticatedRequest("POST", btcMarketsOrderCreate, order, &resp)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if !resp.Success {
|
||||
return 0, fmt.Errorf("%s Unable to place order. Error message: %s\n", b.GetName(), resp.ErrorMessage)
|
||||
return 0, fmt.Errorf("%s Unable to place order. Error message: %s", b.GetName(), resp.ErrorMessage)
|
||||
}
|
||||
return resp.ID, nil
|
||||
}
|
||||
|
||||
// CancelOrder cancels an order by its ID
|
||||
// orderID - id for order example "1337"
|
||||
func (b *BTCMarkets) CancelOrder(orderID []int64) (bool, error) {
|
||||
resp := Response{}
|
||||
type CancelOrder struct {
|
||||
OrderIDs []int64 `json:"orderIds"`
|
||||
}
|
||||
orders := CancelOrder{}
|
||||
orders.OrderIDs = append(orders.OrderIDs, orderID...)
|
||||
|
||||
type Response struct {
|
||||
Success bool `json:"success"`
|
||||
ErrorCode int `json:"errorCode"`
|
||||
ErrorMessage string `json:"errorMessage"`
|
||||
Responses []struct {
|
||||
Success bool `json:"success"`
|
||||
ErrorCode int `json:"errorCode"`
|
||||
ErrorMessage string `json:"errorMessage"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
ClientRequestID string `json:"clientRequestId"`
|
||||
}
|
||||
var resp Response
|
||||
|
||||
err := b.SendAuthenticatedRequest("POST", BTCMARKETS_ORDER_CANCEL, orders, &resp)
|
||||
|
||||
err := b.SendAuthenticatedRequest("POST", btcMarketsOrderCancel, orders, &resp)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !resp.Success {
|
||||
return false, fmt.Errorf("%s Unable to cancel order. Error message: %s\n", b.GetName(), resp.ErrorMessage)
|
||||
return false, fmt.Errorf("%s Unable to cancel order. Error message: %s", b.GetName(), resp.ErrorMessage)
|
||||
}
|
||||
|
||||
ordersToBeCancelled := len(orderID)
|
||||
@@ -170,39 +165,37 @@ func (b *BTCMarkets) CancelOrder(orderID []int64) (bool, error) {
|
||||
ordersCancelled++
|
||||
log.Printf("%s Cancelled order %d.\n", b.GetName(), y.ID)
|
||||
} else {
|
||||
log.Printf("%s Unable to cancel order %d. Error message: %s\n", b.GetName(), y.ID, y.ErrorMessage)
|
||||
log.Printf("%s Unable to cancel order %d. Error message: %s", b.GetName(), y.ID, y.ErrorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
if ordersCancelled == ordersToBeCancelled {
|
||||
return true, nil
|
||||
} else {
|
||||
return false, fmt.Errorf("%s Unable to cancel order(s).", b.GetName())
|
||||
}
|
||||
return false, fmt.Errorf("%s Unable to cancel order(s)", b.GetName())
|
||||
}
|
||||
|
||||
func (b *BTCMarkets) GetOrders(currency, instrument string, limit, since int64, historic bool) ([]BTCMarketsOrder, error) {
|
||||
// GetOrders returns current order information on the exchange
|
||||
// currency - example "AUD"
|
||||
// instrument - example "BTC"
|
||||
// limit - example "10"
|
||||
// since - since a time example "33434568724"
|
||||
// historic - if false just normal Orders open
|
||||
func (b *BTCMarkets) GetOrders(currency, instrument string, limit, since int64, historic bool) ([]Order, error) {
|
||||
request := make(map[string]interface{})
|
||||
request["currency"] = currency
|
||||
request["instrument"] = instrument
|
||||
request["currency"] = common.StringToUpper(currency)
|
||||
request["instrument"] = common.StringToUpper(instrument)
|
||||
request["limit"] = limit
|
||||
request["since"] = since
|
||||
|
||||
path := BTCMARKETS_ORDER_OPEN
|
||||
path := btcMarketsOrderOpen
|
||||
if historic {
|
||||
path = BTCMARKETS_ORDER_HISTORY
|
||||
path = btcMarketsOrderHistory
|
||||
}
|
||||
|
||||
type response struct {
|
||||
Success bool `json:"success"`
|
||||
ErrorCode int `json:"errorCode"`
|
||||
ErrorMessage string `json:"errorMessage"`
|
||||
Orders []BTCMarketsOrder `json:"orders"`
|
||||
}
|
||||
resp := Response{}
|
||||
|
||||
resp := response{}
|
||||
err := b.SendAuthenticatedRequest("POST", path, request, &resp)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -225,23 +218,18 @@ func (b *BTCMarkets) GetOrders(currency, instrument string, limit, since int64,
|
||||
return resp.Orders, nil
|
||||
}
|
||||
|
||||
func (b *BTCMarkets) GetOrderDetail(orderID []int64) ([]BTCMarketsOrder, error) {
|
||||
// GetOrderDetail returns order information an a specific order
|
||||
// orderID - example "1337"
|
||||
func (b *BTCMarkets) GetOrderDetail(orderID []int64) ([]Order, error) {
|
||||
type OrderDetail struct {
|
||||
OrderIDs []int64 `json:"orderIds"`
|
||||
}
|
||||
orders := OrderDetail{}
|
||||
orders.OrderIDs = append(orders.OrderIDs, orderID...)
|
||||
|
||||
type response struct {
|
||||
Success bool `json:"success"`
|
||||
ErrorCode int `json:"errorCode"`
|
||||
ErrorMessage string `json:"errorMessage"`
|
||||
Orders []BTCMarketsOrder `json:"orders"`
|
||||
}
|
||||
|
||||
resp := response{}
|
||||
err := b.SendAuthenticatedRequest("POST", BTCMARKETS_ORDER_DETAIL, orders, &resp)
|
||||
resp := Response{}
|
||||
|
||||
err := b.SendAuthenticatedRequest("POST", btcMarketsOrderDetail, orders, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -264,10 +252,11 @@ func (b *BTCMarkets) GetOrderDetail(orderID []int64) ([]BTCMarketsOrder, error)
|
||||
return resp.Orders, nil
|
||||
}
|
||||
|
||||
func (b *BTCMarkets) GetAccountBalance() ([]BTCMarketsAccountBalance, error) {
|
||||
balance := []BTCMarketsAccountBalance{}
|
||||
err := b.SendAuthenticatedRequest("GET", BTCMARKETS_ACCOUNT_BALANCE, nil, &balance)
|
||||
// GetAccountBalance returns the full account balance
|
||||
func (b *BTCMarkets) GetAccountBalance() ([]AccountBalance, error) {
|
||||
balance := []AccountBalance{}
|
||||
|
||||
err := b.SendAuthenticatedRequest("GET", btcMarketsAccountBalance, nil, &balance)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -280,9 +269,64 @@ func (b *BTCMarkets) GetAccountBalance() ([]BTCMarketsAccountBalance, error) {
|
||||
return balance, nil
|
||||
}
|
||||
|
||||
// WithdrawCrypto withdraws cryptocurrency into a designated address
|
||||
func (b *BTCMarkets) WithdrawCrypto(amount int64, currency, address string) (string, error) {
|
||||
req := WithdrawRequestCrypto{
|
||||
Amount: amount,
|
||||
Currency: common.StringToUpper(currency),
|
||||
Address: address,
|
||||
}
|
||||
|
||||
resp := Response{}
|
||||
err := b.SendAuthenticatedRequest("POST", btcMarketsWithdrawCrypto, req, &resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !resp.Success {
|
||||
return "", errors.New(resp.ErrorMessage)
|
||||
}
|
||||
|
||||
return resp.Status, nil
|
||||
}
|
||||
|
||||
// WithdrawAUD withdraws AUD into a designated bank address
|
||||
// Does not return a TxID!
|
||||
func (b *BTCMarkets) WithdrawAUD(accountName, accountNumber, bankName, bsbNumber, currency string, amount int64) (string, error) {
|
||||
req := WithdrawRequestAUD{
|
||||
AccountName: accountName,
|
||||
AccountNumber: accountNumber,
|
||||
BankName: bankName,
|
||||
BSBNumber: bsbNumber,
|
||||
Amount: amount,
|
||||
Currency: common.StringToUpper(currency),
|
||||
}
|
||||
|
||||
resp := Response{}
|
||||
err := b.SendAuthenticatedRequest("POST", btcMarketsWithdrawAud, req, &resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !resp.Success {
|
||||
return "", errors.New(resp.ErrorMessage)
|
||||
}
|
||||
|
||||
return resp.Status, nil
|
||||
}
|
||||
|
||||
// SendAuthenticatedRequest sends an authenticated HTTP request
|
||||
func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data interface{}, result interface{}) (err error) {
|
||||
nonce := strconv.FormatInt(time.Now().UnixNano(), 10)[0:13]
|
||||
request := ""
|
||||
if !b.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name)
|
||||
}
|
||||
|
||||
if b.Nonce.Get() == 0 {
|
||||
b.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
b.Nonce.Inc()
|
||||
}
|
||||
var request string
|
||||
payload := []byte("")
|
||||
|
||||
if data != nil {
|
||||
@@ -290,15 +334,15 @@ func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data interfa
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request = path + "\n" + nonce + "\n" + string(payload)
|
||||
request = path + "\n" + b.Nonce.String()[0:13] + "\n" + string(payload)
|
||||
} else {
|
||||
request = path + "\n" + nonce + "\n"
|
||||
request = path + "\n" + b.Nonce.String()[0:13] + "\n"
|
||||
}
|
||||
|
||||
hmac := common.GetHMAC(common.HashSHA512, []byte(request), []byte(b.APISecret))
|
||||
|
||||
if b.Verbose {
|
||||
log.Printf("Sending %s request to URL %s with params %s\n", reqType, BTCMARKETS_API_URL+path, request)
|
||||
log.Printf("Sending %s request to URL %s with params %s\n", reqType, btcMarketsAPIURL+path, request)
|
||||
}
|
||||
|
||||
headers := make(map[string]string)
|
||||
@@ -306,10 +350,10 @@ func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data interfa
|
||||
headers["Accept-Charset"] = "UTF-8"
|
||||
headers["Content-Type"] = "application/json"
|
||||
headers["apikey"] = b.APIKey
|
||||
headers["timestamp"] = nonce
|
||||
headers["timestamp"] = b.Nonce.String()[0:13]
|
||||
headers["signature"] = common.Base64Encode(hmac)
|
||||
|
||||
resp, err := common.SendHTTPRequest(reqType, BTCMARKETS_API_URL+path, headers, bytes.NewBuffer(payload))
|
||||
resp, err := common.SendHTTPRequest(reqType, btcMarketsAPIURL+path, headers, bytes.NewBuffer(payload))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
131
exchanges/btcmarkets/btcmarkets_test.go
Normal file
131
exchanges/btcmarkets/btcmarkets_test.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package btcmarkets
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
)
|
||||
|
||||
var bm BTCMarkets
|
||||
|
||||
// Please supply your own keys here to do better tests
|
||||
const (
|
||||
apiKey = ""
|
||||
apiSecret = ""
|
||||
)
|
||||
|
||||
func TestSetDefaults(t *testing.T) {
|
||||
bm.SetDefaults()
|
||||
}
|
||||
|
||||
func TestSetup(t *testing.T) {
|
||||
conf := config.ExchangeConfig{}
|
||||
bm.Setup(conf)
|
||||
|
||||
conf = config.ExchangeConfig{
|
||||
APIKey: apiKey,
|
||||
APISecret: apiSecret,
|
||||
Enabled: true,
|
||||
AuthenticatedAPISupport: true,
|
||||
}
|
||||
bm.Setup(conf)
|
||||
}
|
||||
|
||||
func TestGetFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
if fee := bm.GetFee(); fee == 0 {
|
||||
t.Error("Test failed - GetFee() error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := bm.GetTicker("BTC")
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetTicker() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := bm.GetOrderbook("BTC")
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetOrderbook() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := bm.GetTrades("BTC", nil)
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetTrades() error", err)
|
||||
}
|
||||
|
||||
val := url.Values{}
|
||||
val.Set("since", "0")
|
||||
_, err = bm.GetTrades("BTC", val)
|
||||
if err != nil {
|
||||
t.Error("Test failed - GetTrades() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := bm.NewOrder("AUD", "BTC", 0, 0, "Bid", "limit", "testTest")
|
||||
if err == nil {
|
||||
t.Error("Test failed - NewOrder() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := bm.CancelOrder([]int64{1337})
|
||||
if err == nil {
|
||||
t.Error("Test failed - CancelOrder() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := bm.GetOrders("AUD", "BTC", 10, 0, false)
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetOrders() error", err)
|
||||
}
|
||||
_, err = bm.GetOrders("AUD", "BTC", 10, 0, true)
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetOrders() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderDetail(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := bm.GetOrderDetail([]int64{1337})
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetOrderDetail() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccountBalance(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := bm.GetAccountBalance()
|
||||
if err == nil {
|
||||
t.Error("Test failed - GetAccountBalance() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawCrypto(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := bm.WithdrawCrypto(0, "BTC", "LOLOLOL")
|
||||
if err == nil {
|
||||
t.Error("Test failed - WithdrawCrypto() error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawAUD(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := bm.WithdrawAUD("BLA", "1337", "blawest", "1336", "BTC", 10000000)
|
||||
if err == nil {
|
||||
t.Error("Test failed - WithdrawAUD() error", err)
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,35 @@
|
||||
package btcmarkets
|
||||
|
||||
type BTCMarketsTicker struct {
|
||||
BestBID float64
|
||||
BestAsk float64
|
||||
LastPrice float64
|
||||
Currency string
|
||||
Instrument string
|
||||
Timestamp int64
|
||||
// Response is the genralized response type
|
||||
type Response struct {
|
||||
Success bool `json:"success"`
|
||||
ErrorCode int `json:"errorCode"`
|
||||
ErrorMessage string `json:"errorMessage"`
|
||||
ID int `json:"id"`
|
||||
Responses []struct {
|
||||
Success bool `json:"success"`
|
||||
ErrorCode int `json:"errorCode"`
|
||||
ErrorMessage string `json:"errorMessage"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
ClientRequestID string `json:"clientRequestId"`
|
||||
Orders []Order `json:"orders"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type BTCMarketsTrade struct {
|
||||
TradeID int64 `json:"tid"`
|
||||
Amount float64 `json:"amount"`
|
||||
Price float64 `json:"price"`
|
||||
Date int64 `json:"date"`
|
||||
// Ticker holds ticker information
|
||||
type Ticker struct {
|
||||
BestBID float64 `json:"bestBid"`
|
||||
BestAsk float64 `json:"bestAsk"`
|
||||
LastPrice float64 `json:"lastPrice"`
|
||||
Currency string `json:"currency"`
|
||||
Instrument string `json:"instrument"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Volume float64 `json:"volume24h"`
|
||||
}
|
||||
|
||||
type BTCMarketsOrderbook struct {
|
||||
// Orderbook holds current orderbook information returned from the exchange
|
||||
type Orderbook struct {
|
||||
Currency string `json:"currency"`
|
||||
Instrument string `json:"instrument"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
@@ -24,7 +37,44 @@ type BTCMarketsOrderbook struct {
|
||||
Bids [][]float64 `json:"bids"`
|
||||
}
|
||||
|
||||
type BTCMarketsTradeResponse struct {
|
||||
// Trade holds trade information
|
||||
type Trade struct {
|
||||
TradeID int64 `json:"tid"`
|
||||
Amount float64 `json:"amount"`
|
||||
Price float64 `json:"price"`
|
||||
Date int64 `json:"date"`
|
||||
}
|
||||
|
||||
// OrderToGo holds order information to be sent to the exchange
|
||||
type OrderToGo struct {
|
||||
Currency string `json:"currency"`
|
||||
Instrument string `json:"instrument"`
|
||||
Price int64 `json:"price"`
|
||||
Volume int64 `json:"volume"`
|
||||
OrderSide string `json:"orderSide"`
|
||||
OrderType string `json:"ordertype"`
|
||||
ClientRequestID string `json:"clientRequestId"`
|
||||
}
|
||||
|
||||
// Order holds order information
|
||||
type Order struct {
|
||||
ID int64 `json:"id"`
|
||||
Currency string `json:"currency"`
|
||||
Instrument string `json:"instrument"`
|
||||
OrderSide string `json:"orderSide"`
|
||||
OrderType string `json:"ordertype"`
|
||||
CreationTime float64 `json:"creationTime"`
|
||||
Status string `json:"status"`
|
||||
ErrorMessage string `json:"errorMessage"`
|
||||
Price float64 `json:"price"`
|
||||
Volume float64 `json:"volume"`
|
||||
OpenVolume float64 `json:"openVolume"`
|
||||
ClientRequestID string `json:"clientRequestId"`
|
||||
Trades []TradeResponse `json:"trades"`
|
||||
}
|
||||
|
||||
// TradeResponse holds trade information
|
||||
type TradeResponse struct {
|
||||
ID int64 `json:"id"`
|
||||
CreationTime float64 `json:"creationTime"`
|
||||
Description string `json:"description"`
|
||||
@@ -33,24 +83,26 @@ type BTCMarketsTradeResponse struct {
|
||||
Fee float64 `json:"fee"`
|
||||
}
|
||||
|
||||
type BTCMarketsOrder struct {
|
||||
ID int64 `json:"id"`
|
||||
Currency string `json:"currency"`
|
||||
Instrument string `json:"instrument"`
|
||||
OrderSide string `json:"orderSide"`
|
||||
OrderType string `json:"ordertype"`
|
||||
CreationTime float64 `json:"creationTime"`
|
||||
Status string `json:"status"`
|
||||
ErrorMessage string `json:"errorMessage"`
|
||||
Price float64 `json:"price"`
|
||||
Volume float64 `json:"volume"`
|
||||
OpenVolume float64 `json:"openVolume"`
|
||||
ClientRequestId string `json:"clientRequestId"`
|
||||
Trades []BTCMarketsTradeResponse `json:"trades"`
|
||||
}
|
||||
|
||||
type BTCMarketsAccountBalance struct {
|
||||
// AccountBalance holds account balance details
|
||||
type AccountBalance struct {
|
||||
Balance float64 `json:"balance"`
|
||||
PendingFunds float64 `json:"pendingFunds"`
|
||||
Currency string `json:"currency"`
|
||||
}
|
||||
|
||||
// WithdrawRequestCrypto is a generalized withdraw request type
|
||||
type WithdrawRequestCrypto struct {
|
||||
Amount int64 `json:"amount"`
|
||||
Currency string `json:"currency"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
// WithdrawRequestAUD is a generalized withdraw request type
|
||||
type WithdrawRequestAUD struct {
|
||||
Amount int64 `json:"amount"`
|
||||
Currency string `json:"currency"`
|
||||
AccountName string `json:"accountName"`
|
||||
AccountNumber string `json:"accountNumber"`
|
||||
BankName string `json:"bankName"`
|
||||
BSBNumber string `json:"bsbNumber"`
|
||||
}
|
||||
|
||||
@@ -12,10 +12,12 @@ import (
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
)
|
||||
|
||||
// Start runs ticker monitor in a new routine
|
||||
func (b *BTCMarkets) Start() {
|
||||
go b.Run()
|
||||
}
|
||||
|
||||
// Run starts a go routine to monitor ticker price
|
||||
func (b *BTCMarkets) Run() {
|
||||
if b.Verbose {
|
||||
log.Printf("%s polling delay: %ds.\n", b.GetName(), b.RESTPollingDelay)
|
||||
@@ -33,7 +35,7 @@ func (b *BTCMarkets) Run() {
|
||||
BTCMarketsLastUSD, _ := currency.ConvertCurrency(ticker.Last, "AUD", "USD")
|
||||
BTCMarketsBestBidUSD, _ := currency.ConvertCurrency(ticker.Bid, "AUD", "USD")
|
||||
BTCMarketsBestAskUSD, _ := currency.ConvertCurrency(ticker.Ask, "AUD", "USD")
|
||||
log.Printf("BTC Markets %s: Last %f (%f) Bid %f (%f) Ask %f (%f)\n", curr.Pair().String(), BTCMarketsLastUSD, ticker.Last, BTCMarketsBestBidUSD, ticker.Bid, BTCMarketsBestAskUSD, ticker.Ask)
|
||||
log.Printf("BTC Markets %s: Last %f (%f) Bid %f (%f) Ask %f (%f)\n", exchange.FormatCurrency(curr).String(), BTCMarketsLastUSD, ticker.Last, BTCMarketsBestBidUSD, ticker.Bid, BTCMarketsBestAskUSD, ticker.Ask)
|
||||
stats.AddExchangeInfo(b.GetName(), curr.GetFirstCurrency().String(), curr.GetSecondCurrency().String(), ticker.Last, 0)
|
||||
stats.AddExchangeInfo(b.GetName(), curr.GetFirstCurrency().String(), "USD", BTCMarketsLastUSD, 0)
|
||||
}()
|
||||
@@ -42,6 +44,7 @@ func (b *BTCMarkets) Run() {
|
||||
}
|
||||
}
|
||||
|
||||
// GetTickerPrice returns ticker information
|
||||
func (b *BTCMarkets) GetTickerPrice(p pair.CurrencyPair) (ticker.TickerPrice, error) {
|
||||
tickerNew, err := ticker.GetTicker(b.GetName(), p)
|
||||
if err == nil {
|
||||
@@ -61,6 +64,7 @@ func (b *BTCMarkets) GetTickerPrice(p pair.CurrencyPair) (ticker.TickerPrice, er
|
||||
return tickerPrice, nil
|
||||
}
|
||||
|
||||
// GetOrderbookEx returns orderbook base on the currency pair
|
||||
func (b *BTCMarkets) GetOrderbookEx(p pair.CurrencyPair) (orderbook.OrderbookBase, error) {
|
||||
ob, err := orderbook.GetOrderbook(b.GetName(), p)
|
||||
if err == nil {
|
||||
@@ -88,11 +92,12 @@ func (b *BTCMarkets) GetOrderbookEx(p pair.CurrencyPair) (orderbook.OrderbookBas
|
||||
return orderBook, nil
|
||||
}
|
||||
|
||||
//GetExchangeAccountInfo : Retrieves balances for all enabled currencies for the BTCMarkets exchange
|
||||
func (e *BTCMarkets) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
|
||||
// GetExchangeAccountInfo retrieves balances for all enabled currencies for the
|
||||
// BTCMarkets exchange
|
||||
func (b *BTCMarkets) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
|
||||
var response exchange.AccountInfo
|
||||
response.ExchangeName = e.GetName()
|
||||
accountBalance, err := e.GetAccountBalance()
|
||||
response.ExchangeName = b.GetName()
|
||||
accountBalance, err := b.GetAccountBalance()
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package coinut
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
@@ -271,13 +272,21 @@ func (c *COINUT) GetOpenPosition(instrumentID int) ([]CoinutOpenPosition, error)
|
||||
//to-do: user position update via websocket
|
||||
|
||||
func (c *COINUT) SendAuthenticatedHTTPRequest(apiRequest string, params map[string]interface{}, result interface{}) (err error) {
|
||||
timestamp := time.Now().Unix()
|
||||
if !c.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, c.Name)
|
||||
}
|
||||
|
||||
if c.Nonce.Get() == 0 {
|
||||
c.Nonce.Set(time.Now().Unix())
|
||||
} else {
|
||||
c.Nonce.Inc()
|
||||
}
|
||||
payload := []byte("")
|
||||
|
||||
if params == nil {
|
||||
params = map[string]interface{}{}
|
||||
}
|
||||
params["nonce"] = timestamp
|
||||
params["nonce"] = c.Nonce.Get()
|
||||
params["request"] = apiRequest
|
||||
|
||||
payload, err = common.JSONEncode(params)
|
||||
|
||||
@@ -54,7 +54,7 @@ func (c *COINUT) Run() {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("COINUT %s: Last %f High %f Low %f Volume %f\n", currency.Pair().String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
log.Printf("COINUT %s: Last %f High %f Low %f Volume %f\n", exchange.FormatCurrency(currency).String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
stats.AddExchangeInfo(c.GetName(), currency.GetFirstCurrency().String(), currency.GetSecondCurrency().String(), ticker.Last, ticker.Volume)
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -7,12 +7,16 @@ import (
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
"github.com/thrasher-/gocryptotrader/currency/pair"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/nonce"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
)
|
||||
|
||||
const (
|
||||
warningBase64DecryptSecretKeyFailed = "WARNING -- Exchange %s unable to base64 decode secret key.. Disabling Authenticated API support."
|
||||
|
||||
// WarningAuthenticatedRequestWithoutCredentialsSet error message for authenticated request without credentails set
|
||||
WarningAuthenticatedRequestWithoutCredentialsSet = "WARNING -- Exchange %s authenticated HTTP request called but not supported due to unset/default API keys."
|
||||
// ErrExchangeNotFound is a constant for an error message
|
||||
ErrExchangeNotFound = "Exchange not found in dataset."
|
||||
)
|
||||
@@ -40,6 +44,7 @@ type Base struct {
|
||||
RESTPollingDelay time.Duration
|
||||
AuthenticatedAPISupport bool
|
||||
APISecret, APIKey, ClientID string
|
||||
Nonce nonce.Nonce
|
||||
TakerFee, MakerFee, Fee float64
|
||||
BaseCurrencies []string
|
||||
AvailablePairs []string
|
||||
@@ -60,6 +65,13 @@ type IBotExchange interface {
|
||||
GetOrderbookEx(currency pair.CurrencyPair) (orderbook.OrderbookBase, error)
|
||||
GetEnabledCurrencies() []string
|
||||
GetExchangeAccountInfo() (AccountInfo, error)
|
||||
GetAuthenticatedAPISupport() bool
|
||||
}
|
||||
|
||||
// GetAuthenticatedAPISupport returns whether the exchange supports
|
||||
// authenticated API requests
|
||||
func (e *Base) GetAuthenticatedAPISupport() bool {
|
||||
return e.AuthenticatedAPISupport
|
||||
}
|
||||
|
||||
// GetName is a method that returns the name of the exchange base
|
||||
@@ -73,6 +85,20 @@ func (e *Base) GetEnabledCurrencies() []string {
|
||||
return e.EnabledPairs
|
||||
}
|
||||
|
||||
// GetAvailableCurrencies is a method that returns the available currency pairs
|
||||
// of the exchange base
|
||||
func (e *Base) GetAvailableCurrencies() []string {
|
||||
return e.AvailablePairs
|
||||
}
|
||||
|
||||
// FormatCurrency is a method that formats and returns a currency pair
|
||||
// based on the user currency display preferences
|
||||
func FormatCurrency(p pair.CurrencyPair) pair.CurrencyItem {
|
||||
cfg := config.GetConfig()
|
||||
return p.Display(cfg.CurrencyPairFormat.Delimiter,
|
||||
cfg.CurrencyPairFormat.Uppercase)
|
||||
}
|
||||
|
||||
// SetEnabled is a method that sets if the exchange is enabled
|
||||
func (e *Base) SetEnabled(enabled bool) {
|
||||
e.Enabled = enabled
|
||||
|
||||
@@ -3,6 +3,8 @@ package exchange
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/currency/pair"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
)
|
||||
|
||||
@@ -30,6 +32,35 @@ func TestGetEnabledCurrencies(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAvailableCurrencies(t *testing.T) {
|
||||
availablePairs := []string{"BTCUSD", "BTCAUD", "LTCUSD", "LTCAUD"}
|
||||
GetEnabledCurrencies := Base{
|
||||
Name: "TESTNAME",
|
||||
AvailablePairs: availablePairs,
|
||||
}
|
||||
|
||||
enCurr := GetEnabledCurrencies.GetAvailableCurrencies()
|
||||
if enCurr[0] != "BTCUSD" {
|
||||
t.Error("Test Failed - Exchange GetAvailableCurrencies() incorrect string")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatCurrency(t *testing.T) {
|
||||
cfg := config.GetConfig()
|
||||
err := cfg.LoadConfig(config.ConfigTestFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to load config file. Error: %s", err)
|
||||
}
|
||||
|
||||
currency := pair.NewCurrencyPair("btc", "usd")
|
||||
expected := "BTC-USD"
|
||||
actual := FormatCurrency(currency).String()
|
||||
if actual != expected {
|
||||
t.Errorf("Test failed - Exchange TestFormatCurrency %s != %s",
|
||||
actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetEnabled(t *testing.T) {
|
||||
SetEnabled := Base{
|
||||
Name: "TESTNAME",
|
||||
|
||||
@@ -370,7 +370,15 @@ func (g *GDAX) GetReportStatus(reportID string) (GDAXReportResponse, error) {
|
||||
}
|
||||
|
||||
func (g *GDAX) SendAuthenticatedHTTPRequest(method, path string, params map[string]interface{}, result interface{}) (err error) {
|
||||
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
|
||||
if !g.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, g.Name)
|
||||
}
|
||||
|
||||
if g.Nonce.Get() == 0 {
|
||||
g.Nonce.Set(time.Now().Unix())
|
||||
} else {
|
||||
g.Nonce.Inc()
|
||||
}
|
||||
|
||||
payload := []byte("")
|
||||
|
||||
@@ -386,11 +394,11 @@ func (g *GDAX) SendAuthenticatedHTTPRequest(method, path string, params map[stri
|
||||
}
|
||||
}
|
||||
|
||||
message := timestamp + method + "/" + path + string(payload)
|
||||
message := g.Nonce.String() + method + "/" + path + string(payload)
|
||||
hmac := common.GetHMAC(common.HashSHA256, []byte(message), []byte(g.APISecret))
|
||||
headers := make(map[string]string)
|
||||
headers["CB-ACCESS-SIGN"] = common.Base64Encode([]byte(hmac))
|
||||
headers["CB-ACCESS-TIMESTAMP"] = timestamp
|
||||
headers["CB-ACCESS-TIMESTAMP"] = g.Nonce.String()
|
||||
headers["CB-ACCESS-KEY"] = g.APIKey
|
||||
headers["CB-ACCESS-PASSPHRASE"] = g.ClientID
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
@@ -54,7 +54,7 @@ func (g *GDAX) Run() {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("GDAX %s: Last %f High %f Low %f Volume %f\n", currency.Pair().String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
log.Printf("GDAX %s: Last %f High %f Low %f Volume %f\n", exchange.FormatCurrency(currency).String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
stats.AddExchangeInfo(g.GetName(), currency.GetFirstCurrency().String(), currency.GetSecondCurrency().String(), ticker.Last, ticker.Volume)
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -245,9 +245,19 @@ func (g *Gemini) PostHeartbeat() (bool, error) {
|
||||
}
|
||||
|
||||
func (g *Gemini) SendAuthenticatedHTTPRequest(method, path string, params map[string]interface{}, result interface{}) (err error) {
|
||||
if !g.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, g.Name)
|
||||
}
|
||||
|
||||
if g.Nonce.Get() == 0 {
|
||||
g.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
g.Nonce.Inc()
|
||||
}
|
||||
|
||||
request := make(map[string]interface{})
|
||||
request["request"] = fmt.Sprintf("/v%s/%s", GEMINI_API_VERSION, path)
|
||||
request["nonce"] = time.Now().UnixNano()
|
||||
request["nonce"] = g.Nonce.Get()
|
||||
|
||||
if params != nil {
|
||||
for key, value := range params {
|
||||
@@ -255,17 +265,17 @@ func (g *Gemini) SendAuthenticatedHTTPRequest(method, path string, params map[st
|
||||
}
|
||||
}
|
||||
|
||||
PayloadJson, err := common.JSONEncode(request)
|
||||
PayloadJSON, err := common.JSONEncode(request)
|
||||
|
||||
if err != nil {
|
||||
return errors.New("SendAuthenticatedHTTPRequest: Unable to JSON request")
|
||||
}
|
||||
|
||||
if g.Verbose {
|
||||
log.Printf("Request JSON: %s\n", PayloadJson)
|
||||
log.Printf("Request JSON: %s\n", PayloadJSON)
|
||||
}
|
||||
|
||||
PayloadBase64 := common.Base64Encode(PayloadJson)
|
||||
PayloadBase64 := common.Base64Encode(PayloadJSON)
|
||||
hmac := common.GetHMAC(common.HashSHA512_384, []byte(PayloadBase64), []byte(g.APISecret))
|
||||
headers := make(map[string]string)
|
||||
headers["X-GEMINI-APIKEY"] = g.APIKey
|
||||
|
||||
@@ -41,7 +41,7 @@ func (g *Gemini) Run() {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("Gemini %s Last %f Bid %f Ask %f Volume %f\n", currency.Pair().String(), ticker.Last, ticker.Bid, ticker.Ask, ticker.Volume)
|
||||
log.Printf("Gemini %s Last %f Bid %f Ask %f Volume %f\n", exchange.FormatCurrency(currency).String(), ticker.Last, ticker.Bid, ticker.Ask, ticker.Volume)
|
||||
stats.AddExchangeInfo(g.GetName(), currency.GetFirstCurrency().String(), currency.GetSecondCurrency().String(), ticker.Last, ticker.Volume)
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -177,6 +177,10 @@ func (h *HUOBI) GetOrderIDByTradeID(coinType, orderID int) {
|
||||
}
|
||||
|
||||
func (h *HUOBI) SendAuthenticatedRequest(method string, v url.Values) error {
|
||||
if !h.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, h.Name)
|
||||
}
|
||||
|
||||
v.Set("access_key", h.APIKey)
|
||||
v.Set("created", strconv.FormatInt(time.Now().Unix(), 10))
|
||||
v.Set("method", method)
|
||||
|
||||
@@ -40,7 +40,7 @@ func (h *HUOBI) Run() {
|
||||
HuobiLastUSD, _ := currency.ConvertCurrency(ticker.Last, "CNY", "USD")
|
||||
HuobiHighUSD, _ := currency.ConvertCurrency(ticker.High, "CNY", "USD")
|
||||
HuobiLowUSD, _ := currency.ConvertCurrency(ticker.Low, "CNY", "USD")
|
||||
log.Printf("Huobi %s: Last %f (%f) High %f (%f) Low %f (%f) Volume %f\n", curr.Pair().String(), HuobiLastUSD, ticker.Last, HuobiHighUSD, ticker.High, HuobiLowUSD, ticker.Low, ticker.Volume)
|
||||
log.Printf("Huobi %s: Last %f (%f) High %f (%f) Low %f (%f) Volume %f\n", exchange.FormatCurrency(curr).String(), HuobiLastUSD, ticker.Last, HuobiHighUSD, ticker.High, HuobiLowUSD, ticker.Low, ticker.Volume)
|
||||
stats.AddExchangeInfo(h.GetName(), curr.GetFirstCurrency().String(), curr.GetSecondCurrency().String(), ticker.Last, ticker.Volume)
|
||||
stats.AddExchangeInfo(h.GetName(), curr.GetFirstCurrency().String(), "USD", HuobiLastUSD, ticker.Volume)
|
||||
}()
|
||||
|
||||
@@ -3,6 +3,7 @@ package itbit
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@@ -226,14 +227,16 @@ func (i *ItBit) WalletTransfer(walletID, sourceWallet, destWallet string, amount
|
||||
}
|
||||
|
||||
func (i *ItBit) SendAuthenticatedHTTPRequest(method string, path string, params map[string]interface{}) (err error) {
|
||||
timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)[0:13]
|
||||
nonce, err := strconv.Atoi(timestamp)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
if !i.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, i.Name)
|
||||
}
|
||||
|
||||
if i.Nonce.Get() == 0 {
|
||||
i.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
i.Nonce.Inc()
|
||||
}
|
||||
|
||||
nonce--
|
||||
request := make(map[string]interface{})
|
||||
url := ITBIT_API_URL + path
|
||||
|
||||
@@ -257,21 +260,20 @@ func (i *ItBit) SendAuthenticatedHTTPRequest(method string, path string, params
|
||||
}
|
||||
}
|
||||
|
||||
nonceStr := strconv.Itoa(nonce)
|
||||
message, err := common.JSONEncode([]string{method, url, string(PayloadJSON), nonceStr, timestamp})
|
||||
message, err := common.JSONEncode([]string{method, url, string(PayloadJSON), i.Nonce.String(), i.Nonce.String()[0:13]})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
hash := common.GetSHA256([]byte(nonceStr + string(message)))
|
||||
hash := common.GetSHA256([]byte(i.Nonce.String() + string(message)))
|
||||
hmac := common.GetHMAC(common.HashSHA512, []byte(url+string(hash)), []byte(i.APISecret))
|
||||
signature := common.Base64Encode(hmac)
|
||||
|
||||
headers := make(map[string]string)
|
||||
headers["Authorization"] = i.ClientID + ":" + signature
|
||||
headers["X-Auth-Timestamp"] = timestamp
|
||||
headers["X-Auth-Nonce"] = nonceStr
|
||||
headers["X-Auth-Timestamp"] = i.Nonce.String()[0:13]
|
||||
headers["X-Auth-Nonce"] = i.Nonce.String()
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
resp, err := common.SendHTTPRequest(method, url, headers, bytes.NewBuffer([]byte(PayloadJSON)))
|
||||
|
||||
@@ -30,7 +30,7 @@ func (i *ItBit) Run() {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("ItBit %s: Last %f High %f Low %f Volume %f\n", currency.Pair().String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
log.Printf("ItBit %s: Last %f High %f Low %f Volume %f\n", exchange.FormatCurrency(currency).String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
stats.AddExchangeInfo(i.GetName(), currency.GetFirstCurrency().String(), currency.GetSecondCurrency().String(), ticker.Last, ticker.Volume)
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -509,8 +509,18 @@ func (k *Kraken) CancelOrder(orderID int64) {
|
||||
}
|
||||
|
||||
func (k *Kraken) SendAuthenticatedHTTPRequest(method string, values url.Values) (interface{}, error) {
|
||||
if !k.AuthenticatedAPISupport {
|
||||
return nil, fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, k.Name)
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("/%s/private/%s", KRAKEN_API_VERSION, method)
|
||||
values.Set("nonce", strconv.FormatInt(time.Now().UnixNano(), 10))
|
||||
if k.Nonce.Get() == 0 {
|
||||
k.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
k.Nonce.Inc()
|
||||
}
|
||||
|
||||
values.Set("nonce", k.Nonce.String())
|
||||
secret, err := common.Base64Decode(k.APISecret)
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -272,8 +272,17 @@ func (l *LakeBTC) CreateWithdraw(amount float64, accountID int64) (LakeBTCWithdr
|
||||
}
|
||||
|
||||
func (l *LakeBTC) SendAuthenticatedHTTPRequest(method, params string, result interface{}) (err error) {
|
||||
nonce := strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
req := fmt.Sprintf("tonce=%s&accesskey=%s&requestmethod=post&id=1&method=%s¶ms=%s", nonce, l.APIKey, method, params)
|
||||
if !l.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, l.Name)
|
||||
}
|
||||
|
||||
if l.Nonce.Get() == 0 {
|
||||
l.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
l.Nonce.Inc()
|
||||
}
|
||||
|
||||
req := fmt.Sprintf("tonce=%s&accesskey=%s&requestmethod=post&id=1&method=%s¶ms=%s", l.Nonce.String(), l.APIKey, method, params)
|
||||
hmac := common.GetHMAC(common.HashSHA1, []byte(req), []byte(l.APISecret))
|
||||
|
||||
if l.Verbose {
|
||||
@@ -291,7 +300,7 @@ func (l *LakeBTC) SendAuthenticatedHTTPRequest(method, params string, result int
|
||||
}
|
||||
|
||||
headers := make(map[string]string)
|
||||
headers["Json-Rpc-Tonce"] = nonce
|
||||
headers["Json-Rpc-Tonce"] = l.Nonce.String()
|
||||
headers["Authorization"] = "Basic " + common.Base64Encode([]byte(l.APIKey+":"+common.HexEncodeToString(hmac)))
|
||||
headers["Content-Type"] = "application/json-rpc"
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ func (l *LakeBTC) Run() {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
log.Printf("LakeBTC BTC %s: Last %f High %f Low %f Volume %f\n", x[3:], ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
log.Printf("LakeBTC %s: Last %f High %f Low %f Volume %f\n", exchange.FormatCurrency(currency).String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
stats.AddExchangeInfo(l.GetName(), currency.GetFirstCurrency().String(), currency.GetSecondCurrency().String(), ticker.Last, ticker.Volume)
|
||||
}
|
||||
time.Sleep(time.Second * l.RESTPollingDelay)
|
||||
|
||||
@@ -249,8 +249,16 @@ func (l *Liqui) WithdrawCoins(coin string, amount float64, address string) (Liqu
|
||||
}
|
||||
|
||||
func (l *Liqui) SendAuthenticatedHTTPRequest(method string, values url.Values, result interface{}) (err error) {
|
||||
nonce := strconv.FormatInt(time.Now().Unix(), 10)
|
||||
values.Set("nonce", nonce)
|
||||
if !l.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, l.Name)
|
||||
}
|
||||
|
||||
if l.Nonce.Get() == 0 {
|
||||
l.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
l.Nonce.Inc()
|
||||
}
|
||||
values.Set("nonce", l.Nonce.String())
|
||||
values.Set("method", method)
|
||||
|
||||
encoded := values.Encode()
|
||||
|
||||
@@ -52,7 +52,7 @@ func (l *Liqui) Run() {
|
||||
}
|
||||
for x, y := range ticker {
|
||||
currency := pair.NewCurrencyPairDelimiter(common.StringToUpper(x), "_")
|
||||
log.Printf("Liqui %s: Last %f High %f Low %f Volume %f\n", currency.Pair().String(), y.Last, y.High, y.Low, y.Vol_cur)
|
||||
log.Printf("Liqui %s: Last %f High %f Low %f Volume %f\n", exchange.FormatCurrency(currency).String(), y.Last, y.High, y.Low, y.Vol_cur)
|
||||
l.Ticker[x] = y
|
||||
stats.AddExchangeInfo(l.GetName(), currency.GetFirstCurrency().String(), currency.GetSecondCurrency().String(), y.Last, y.Vol_cur)
|
||||
}
|
||||
|
||||
@@ -267,7 +267,16 @@ func (l *LocalBitcoins) GetWalletAddress() (string, error) {
|
||||
}
|
||||
|
||||
func (l *LocalBitcoins) SendAuthenticatedHTTPRequest(method, path string, values url.Values, result interface{}) (err error) {
|
||||
nonce := strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
if !l.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, l.Name)
|
||||
}
|
||||
|
||||
if l.Nonce.Get() == 0 {
|
||||
l.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
l.Nonce.Inc()
|
||||
}
|
||||
|
||||
payload := ""
|
||||
path = "/api/" + path
|
||||
|
||||
@@ -275,11 +284,11 @@ func (l *LocalBitcoins) SendAuthenticatedHTTPRequest(method, path string, values
|
||||
payload = values.Encode()
|
||||
}
|
||||
|
||||
message := string(nonce) + l.APIKey + path + payload
|
||||
message := l.Nonce.String() + l.APIKey + path + payload
|
||||
hmac := common.GetHMAC(common.HashSHA256, []byte(message), []byte(l.APISecret))
|
||||
headers := make(map[string]string)
|
||||
headers["Apiauth-Key"] = l.APIKey
|
||||
headers["Apiauth-Nonce"] = string(nonce)
|
||||
headers["Apiauth-Nonce"] = l.Nonce.String()
|
||||
headers["Apiauth-Signature"] = common.StringToUpper(common.HexEncodeToString(hmac))
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ func (l *LocalBitcoins) Run() {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("LocalBitcoins BTC %s: Last %f Volume %f\n", currency.Pair().String(), ticker.Last, ticker.Volume)
|
||||
log.Printf("LocalBitcoins BTC %s: Last %f Volume %f\n", exchange.FormatCurrency(currency).String(), ticker.Last, ticker.Volume)
|
||||
stats.AddExchangeInfo(l.GetName(), currency.GetFirstCurrency().String(), currency.GetSecondCurrency().String(), ticker.Last, ticker.Volume)
|
||||
}
|
||||
time.Sleep(time.Second * l.RESTPollingDelay)
|
||||
|
||||
49
exchanges/nonce/nonce.go
Normal file
49
exchanges/nonce/nonce.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package nonce
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Nonce struct holds the nonce value
|
||||
type Nonce struct {
|
||||
n int64
|
||||
mtx sync.Mutex
|
||||
}
|
||||
|
||||
// Inc increments the nonce value
|
||||
func (n *Nonce) Inc() {
|
||||
n.mtx.Lock()
|
||||
n.n++
|
||||
n.mtx.Unlock()
|
||||
}
|
||||
|
||||
// Get retrives the nonce value
|
||||
func (n *Nonce) Get() int64 {
|
||||
n.mtx.Lock()
|
||||
defer n.mtx.Unlock()
|
||||
return n.n
|
||||
}
|
||||
|
||||
// GetInc increments and returns the value of the nonce
|
||||
func (n *Nonce) GetInc() int64 {
|
||||
n.mtx.Lock()
|
||||
defer n.mtx.Unlock()
|
||||
n.n++
|
||||
return n.n
|
||||
}
|
||||
|
||||
// Set sets the nonce value
|
||||
func (n *Nonce) Set(val int64) {
|
||||
n.mtx.Lock()
|
||||
n.n = val
|
||||
n.mtx.Unlock()
|
||||
}
|
||||
|
||||
// Returns a string version of the nonce
|
||||
func (n *Nonce) String() string {
|
||||
n.mtx.Lock()
|
||||
result := strconv.FormatInt(n.n, 10)
|
||||
n.mtx.Unlock()
|
||||
return result
|
||||
}
|
||||
75
exchanges/nonce/nonce_test.go
Normal file
75
exchanges/nonce/nonce_test.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package nonce
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestInc(t *testing.T) {
|
||||
var nonce Nonce
|
||||
nonce.Set(1)
|
||||
nonce.Inc()
|
||||
expected := int64(2)
|
||||
result := nonce.Get()
|
||||
if result != expected {
|
||||
t.Errorf("Test failed. Expected %d got %d", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
var nonce Nonce
|
||||
nonce.Set(112321313)
|
||||
expected := int64(112321313)
|
||||
result := nonce.Get()
|
||||
if expected != result {
|
||||
t.Errorf("Test failed. Expected %d got %d", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetInc(t *testing.T) {
|
||||
var nonce Nonce
|
||||
nonce.Set(1)
|
||||
expected := int64(2)
|
||||
result := nonce.GetInc()
|
||||
if expected != result {
|
||||
t.Errorf("Test failed. Expected %d got %d", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSet(t *testing.T) {
|
||||
var nonce Nonce
|
||||
nonce.Set(1)
|
||||
expected := int64(1)
|
||||
result := nonce.Get()
|
||||
if expected != result {
|
||||
t.Errorf("Test failed. Expected %d got %d", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
var nonce Nonce
|
||||
nonce.Set(12312313131)
|
||||
expected := "12312313131"
|
||||
result := nonce.String()
|
||||
if expected != result {
|
||||
t.Errorf("Test failed. Expected %s got %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonceConcurrency(t *testing.T) {
|
||||
var nonce Nonce
|
||||
nonce.Set(12312)
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
go nonce.Inc()
|
||||
}
|
||||
|
||||
// Allow sufficient time for all routines to finish
|
||||
time.Sleep(time.Second)
|
||||
|
||||
result := nonce.Get()
|
||||
expected := int64(12312 + 1000)
|
||||
if expected != result {
|
||||
t.Errorf("Test failed. Expected %d got %d", expected, result)
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package okcoin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@@ -877,6 +878,10 @@ func (o *OKCoin) GetFuturesUserPosition4Fix(symbol, contractType string) {
|
||||
}
|
||||
|
||||
func (o *OKCoin) SendAuthenticatedHTTPRequest(method string, v url.Values, result interface{}) (err error) {
|
||||
if !o.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, o.Name)
|
||||
}
|
||||
|
||||
v.Set("api_key", o.APIKey)
|
||||
hasher := common.GetMD5([]byte(v.Encode() + "&secret_key=" + o.APISecret))
|
||||
v.Set("sign", strings.ToUpper(common.HexEncodeToString(hasher)))
|
||||
|
||||
@@ -41,7 +41,7 @@ func (o *OKCoin) Run() {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("OKCoin Intl Futures %s (%s): Last %f High %f Low %f Volume %f\n", curr.Pair().String(), futuresValue, ticker.Last, ticker.High, ticker.Low, ticker.Vol)
|
||||
log.Printf("OKCoin Intl Futures %s (%s): Last %f High %f Low %f Volume %f\n", exchange.FormatCurrency(curr).String(), futuresValue, ticker.Last, ticker.High, ticker.Low, ticker.Vol)
|
||||
stats.AddExchangeInfo(o.GetName(), curr.GetFirstCurrency().String(), curr.GetSecondCurrency().String(), ticker.Last, ticker.Vol)
|
||||
}()
|
||||
}
|
||||
@@ -51,7 +51,7 @@ func (o *OKCoin) Run() {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("OKCoin Intl Spot %s: Last %f High %f Low %f Volume %f\n", curr.Pair().String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
log.Printf("OKCoin Intl Spot %s: Last %f High %f Low %f Volume %f\n", exchange.FormatCurrency(curr).String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
stats.AddExchangeInfo(o.GetName(), curr.GetFirstCurrency().String(), curr.GetSecondCurrency().String(), ticker.Last, ticker.Volume)
|
||||
}()
|
||||
} else {
|
||||
@@ -64,7 +64,7 @@ func (o *OKCoin) Run() {
|
||||
tickerLastUSD, _ := currency.ConvertCurrency(ticker.Last, "CNY", "USD")
|
||||
tickerHighUSD, _ := currency.ConvertCurrency(ticker.High, "CNY", "USD")
|
||||
tickerLowUSD, _ := currency.ConvertCurrency(ticker.Low, "CNY", "USD")
|
||||
log.Printf("OKCoin China %s: Last %f (%f) High %f (%f) Low %f (%f) Volume %f\n", curr.Pair().String(), tickerLastUSD, ticker.Last, tickerHighUSD, ticker.High, tickerLowUSD, ticker.Low, ticker.Volume)
|
||||
log.Printf("OKCoin China %s: Last %f (%f) High %f (%f) Low %f (%f) Volume %f\n", exchange.FormatCurrency(curr).String(), tickerLastUSD, ticker.Last, tickerHighUSD, ticker.High, tickerLowUSD, ticker.Low, ticker.Volume)
|
||||
stats.AddExchangeInfo(o.GetName(), curr.GetFirstCurrency().String(), curr.GetSecondCurrency().String(), ticker.Last, ticker.Volume)
|
||||
stats.AddExchangeInfo(o.GetName(), curr.GetFirstCurrency().String(), "USD", tickerLastUSD, ticker.Volume)
|
||||
}()
|
||||
|
||||
@@ -745,14 +745,19 @@ func (p *Poloniex) ToggleAutoRenew(orderNumber int64) (bool, error) {
|
||||
}
|
||||
|
||||
func (p *Poloniex) SendAuthenticatedHTTPRequest(method, endpoint string, values url.Values, result interface{}) error {
|
||||
if !p.AuthenticatedAPISupport {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, p.Name)
|
||||
}
|
||||
headers := make(map[string]string)
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
headers["Key"] = p.APIKey
|
||||
|
||||
nonce := time.Now().UnixNano()
|
||||
nonceStr := strconv.FormatInt(nonce, 10)
|
||||
|
||||
values.Set("nonce", nonceStr)
|
||||
if p.Nonce.Get() == 0 {
|
||||
p.Nonce.Set(time.Now().UnixNano())
|
||||
} else {
|
||||
p.Nonce.Inc()
|
||||
}
|
||||
values.Set("nonce", p.Nonce.String())
|
||||
values.Set("command", endpoint)
|
||||
|
||||
hmac := common.GetHMAC(common.HashSHA512, []byte(values.Encode()), []byte(p.APISecret))
|
||||
|
||||
@@ -36,7 +36,7 @@ func (p *Poloniex) Run() {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("Poloniex %s Last %f High %f Low %f Volume %f\n", currency.Pair().String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
log.Printf("Poloniex %s Last %f High %f Low %f Volume %f\n", exchange.FormatCurrency(currency).String(), ticker.Last, ticker.High, ticker.Low, ticker.Volume)
|
||||
stats.AddExchangeInfo(p.GetName(), currency.GetFirstCurrency().String(), currency.GetSecondCurrency().String(), ticker.Last, ticker.Volume)
|
||||
}()
|
||||
}
|
||||
|
||||
3
main.go
3
main.go
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/anx"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/bitfinex"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/bitstamp"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/bittrex"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/btcc"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/btce"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/btcmarkets"
|
||||
@@ -42,6 +43,7 @@ type ExchangeMain struct {
|
||||
btcc btcc.BTCC
|
||||
bitstamp bitstamp.Bitstamp
|
||||
bitfinex bitfinex.Bitfinex
|
||||
bittrex bittrex.Bittrex
|
||||
btce btce.BTCE
|
||||
btcmarkets btcmarkets.BTCMarkets
|
||||
coinut coinut.COINUT
|
||||
@@ -143,6 +145,7 @@ func main() {
|
||||
new(btcc.BTCC),
|
||||
new(bitstamp.Bitstamp),
|
||||
new(bitfinex.Bitfinex),
|
||||
new(bittrex.Bittrex),
|
||||
new(btce.BTCE),
|
||||
new(btcmarkets.BTCMarkets),
|
||||
new(coinut.COINUT),
|
||||
|
||||
4
testdata/configtest.dat
vendored
4
testdata/configtest.dat
vendored
@@ -2,6 +2,10 @@
|
||||
"Name": "Skynet",
|
||||
"EncryptConfig": 0,
|
||||
"Cryptocurrencies": "BTC,LTC,ETH,XRP,NMC,NVC,PPC,XBT,DOGE,DASH",
|
||||
"CurrencyPairFormat": {
|
||||
"Uppercase": true,
|
||||
"Delimiter": "-"
|
||||
},
|
||||
"PortfolioAddresses": {
|
||||
"Addresses": [
|
||||
{
|
||||
|
||||
0
coverage.txt → testdata/coverage.txt
vendored
0
coverage.txt → testdata/coverage.txt
vendored
11
test.sh → testdata/test.sh
vendored
11
test.sh → testdata/test.sh
vendored
@@ -1,12 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
echo "" > coverage.txt
|
||||
|
||||
if [ -n "$TRAVIS_BUILD_DIR" ]; then
|
||||
cd $TRAVIS_BUILD_DIR
|
||||
else
|
||||
cd $GOPATH/src/github.com/thrasher-/gocryptotrader
|
||||
fi
|
||||
|
||||
echo "" > testdata/coverage.txt
|
||||
|
||||
for d in $(go list ./... | grep -v vendor); do
|
||||
go test -race -coverprofile=profile.out -covermode=atomic -cover $d
|
||||
if [ -f profile.out ]; then
|
||||
cat profile.out >> coverage.txt
|
||||
cat profile.out >> testdata/coverage.txt
|
||||
rm profile.out
|
||||
fi
|
||||
done
|
||||
@@ -54,11 +54,15 @@ func GetAllEnabledExchangeAccountInfo() AllEnabledExchangeAccounts {
|
||||
var response AllEnabledExchangeAccounts
|
||||
for _, individualBot := range bot.exchanges {
|
||||
if individualBot != nil && individualBot.IsEnabled() {
|
||||
if !individualBot.GetAuthenticatedAPISupport() {
|
||||
log.Printf("GetAllEnabledExchangeAccountInfo: Skippping %s due to disabled authenticated API support.", individualBot.GetName())
|
||||
continue
|
||||
}
|
||||
individualExchange, err := individualBot.GetExchangeAccountInfo()
|
||||
if err != nil {
|
||||
log.Println(
|
||||
"Error encountered retrieving exchange account for '" + individualExchange.ExchangeName + "'",
|
||||
)
|
||||
log.Printf("Error encountered retrieving exchange account info for %s. Error %s",
|
||||
individualBot.GetName(), err)
|
||||
continue
|
||||
}
|
||||
response.Data = append(response.Data, individualExchange)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user