Merge pull request #63 from shazbert/test

Test
This commit is contained in:
Adrian Gallagher
2017-11-23 14:35:46 +11:00
committed by GitHub
52 changed files with 2189 additions and 795 deletions

View File

@@ -79,7 +79,7 @@ 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
cp $GOPATH/src/github.com/thrasher-/gocryptotrader/config_example.json $GOPATH/bin/config.json
```
Make any neccessary changes to the config file.

View File

@@ -19,9 +19,9 @@ import (
// Constants declared here are filename strings and test strings
const (
ConfigFile = "config.dat"
OldConfigFile = "config.json"
ConfigTestFile = "../testdata/configtest.dat"
EncryptedConfigFile = "config.dat"
ConfigFile = "config.json"
ConfigTestFile = "../testdata/configtest.json"
configFileEncryptionPrompt = 0
configFileEncryptionEnabled = 1
configFileEncryptionDisabled = -1
@@ -47,7 +47,6 @@ var (
WarningWebserverRootWebFolderNotFound = "WARNING -- Webserver support disabled due to missing web folder."
WarningExchangeAuthAPIDefaultOrEmptyValues = "WARNING -- Exchange %s: Authenticated API support disabled due to default/empty APIKey/Secret/ClientID values."
WarningCurrencyExchangeProvider = "WARNING -- Currency exchange provider invalid valid. Reset to Fixer."
RenamingConfigFile = "Renaming config file %s to %s."
Cfg Config
)
@@ -104,6 +103,7 @@ type ExchangeConfig struct {
Enabled bool
Verbose bool
Websocket bool
UseSandbox bool
RESTPollingDelay time.Duration
AuthenticatedAPISupport bool
APIKey string
@@ -316,34 +316,37 @@ func GetFilePath(file string) string {
return file
}
if flag.Lookup("test.v") == nil {
return ConfigFile
data, err := common.ReadFile(EncryptedConfigFile)
if err == nil {
if ConfirmECS(data) {
return EncryptedConfigFile
}
err = os.Rename(EncryptedConfigFile, ConfigFile)
if err != nil {
log.Fatalf("Unable to rename config file: %s", err)
}
log.Printf("Renaming non-encrypted config file from %s to %s",
EncryptedConfigFile, ConfigFile)
return ConfigFile
}
if !ConfirmECS(data) {
return ConfigFile
}
err = os.Rename(ConfigFile, EncryptedConfigFile)
if err != nil {
log.Fatalf("Unable to rename config file: %s", err)
}
log.Printf("Renaming encrypted config file from %s to %s", ConfigFile,
EncryptedConfigFile)
return EncryptedConfigFile
}
return ConfigTestFile
}
// CheckConfig checks to see if there is an old configuration filename and path
// if found it will change it to correct filename.
func CheckConfig() error {
_, err := common.ReadFile(OldConfigFile)
if err == nil {
err = os.Rename(OldConfigFile, ConfigFile)
if err != nil {
return err
}
log.Printf(RenamingConfigFile+"\n", OldConfigFile, ConfigFile)
}
return nil
}
// ReadConfig verifies and checks for encryption and verifies the unencrypted
// file contains JSON.
func (c *Config) ReadConfig(configPath string) error {
defaultPath := GetFilePath(configPath)
err := CheckConfig()
if err != nil {
return err
}
file, err := common.ReadFile(defaultPath)
if err != nil {
return err

View File

@@ -68,7 +68,7 @@ var (
ErrCurrencyNotFound = errors.New("unable to find specified currency")
ErrQueryingYahoo = errors.New("unable to query Yahoo currency values")
ErrQueryingYahooZeroCount = errors.New("yahoo returned zero currency data")
YahooEnabled = true
YahooEnabled = false
)
// SetProvider sets the currency exchange service used by the currency

View File

@@ -323,35 +323,37 @@ func TestCheckAndAddCurrency(t *testing.T) {
}
func TestSeedCurrencyData(t *testing.T) {
SetProvider(true)
currencyRequestDefault := ""
currencyRequestUSDAUD := "USD,AUD"
currencyRequestObtuse := "WigWham"
// SetProvider(true)
if YahooEnabled {
currencyRequestDefault := ""
currencyRequestUSDAUD := "USD,AUD"
currencyRequestObtuse := "WigWham"
err := SeedCurrencyData(currencyRequestDefault)
if err != nil {
t.Errorf(
"Test Failed. SeedCurrencyData: Error %s with currency as %s.",
err, currencyRequestDefault,
)
}
err2 := SeedCurrencyData(currencyRequestUSDAUD)
if err2 != nil {
t.Errorf(
"Test Failed. SeedCurrencyData: Error %s with currency as %s.",
err2, currencyRequestUSDAUD,
)
}
err3 := SeedCurrencyData(currencyRequestObtuse)
if err3 == nil {
t.Errorf(
"Test Failed. SeedCurrencyData: Error %s with currency as %s.",
err3, currencyRequestObtuse,
)
err := SeedCurrencyData(currencyRequestDefault)
if err != nil {
t.Errorf(
"Test Failed. SeedCurrencyData: Error %s with currency as %s.",
err, currencyRequestDefault,
)
}
err2 := SeedCurrencyData(currencyRequestUSDAUD)
if err2 != nil {
t.Errorf(
"Test Failed. SeedCurrencyData: Error %s with currency as %s.",
err2, currencyRequestUSDAUD,
)
}
err3 := SeedCurrencyData(currencyRequestObtuse)
if err3 == nil {
t.Errorf(
"Test Failed. SeedCurrencyData: Error %s with currency as %s.",
err3, currencyRequestObtuse,
)
}
}
SetProvider(false)
err = SeedCurrencyData("")
//SetProvider(false)
err := SeedCurrencyData("")
if err != nil {
t.Errorf("Test failed. SeedCurrencyData via Fixer. Error: %s", err)
}
@@ -371,29 +373,31 @@ func TestMakecurrencyPairs(t *testing.T) {
}
func TestConvertCurrency(t *testing.T) {
SetProvider(true)
fiatCurrencies := DefaultCurrencies
for _, currencyFrom := range common.SplitStrings(fiatCurrencies, ",") {
for _, currencyTo := range common.SplitStrings(fiatCurrencies, ",") {
floatyMcfloat, err := ConvertCurrency(1000, currencyFrom, currencyTo)
if err != nil {
t.Errorf(
"Test Failed. ConvertCurrency: Error %s with return: %.2f Currency 1: %s Currency 2: %s",
err, floatyMcfloat, currencyFrom, currencyTo,
)
}
if reflect.TypeOf(floatyMcfloat).String() != "float64" {
t.Error("Test Failed. ConvertCurrency: Error, incorrect return type")
}
if floatyMcfloat <= 0 {
t.Error(
"Test Failed. ConvertCurrency: Error, negative return or a serious issue with current fiat",
)
// SetProvider(true)
if YahooEnabled {
fiatCurrencies := DefaultCurrencies
for _, currencyFrom := range common.SplitStrings(fiatCurrencies, ",") {
for _, currencyTo := range common.SplitStrings(fiatCurrencies, ",") {
floatyMcfloat, err := ConvertCurrency(1000, currencyFrom, currencyTo)
if err != nil {
t.Errorf(
"Test Failed. ConvertCurrency: Error %s with return: %.2f Currency 1: %s Currency 2: %s",
err, floatyMcfloat, currencyFrom, currencyTo,
)
}
if reflect.TypeOf(floatyMcfloat).String() != "float64" {
t.Error("Test Failed. ConvertCurrency: Error, incorrect return type")
}
if floatyMcfloat <= 0 {
t.Error(
"Test Failed. ConvertCurrency: Error, negative return or a serious issue with current fiat",
)
}
}
}
}
SetProvider(false)
// SetProvider(false)
_, err := ConvertCurrency(1000, "USD", "AUD")
if err != nil {
t.Errorf("Test failed. ConvertCurrency USD -> AUD. Error %s", err)
@@ -409,26 +413,26 @@ func TestConvertCurrency(t *testing.T) {
t.Errorf("Test failed. ConvertCurrency USD -> AUD. Error %s", err)
}
// Test non-existant currencies
// Test non-existent currencies
_, err = ConvertCurrency(1000, "ASDF", "USD")
if err == nil {
t.Errorf("Test failed. ConvertCurrency non-existant currency -> USD. Error %s", err)
t.Errorf("Test failed. ConvertCurrency non-existent currency -> USD. Error %s", err)
}
_, err = ConvertCurrency(1000, "USD", "ASDF")
if err == nil {
t.Errorf("Test failed. ConvertCurrency USD -> non-existant currency. Error %s", err)
t.Errorf("Test failed. ConvertCurrency USD -> non-existent currency. Error %s", err)
}
_, err = ConvertCurrency(1000, "CNY", "UAHF")
if err == nil {
t.Errorf("Test failed. ConvertCurrency non-USD currency CNY -> non-existant currency. Error %s", err)
t.Errorf("Test failed. ConvertCurrency non-USD currency CNY -> non-existent currency. Error %s", err)
}
_, err = ConvertCurrency(1000, "UASF", "UAHF")
if err == nil {
t.Errorf("Test failed. ConvertCurrency non-existant currency -> non-existant currency. Error %s", err)
t.Errorf("Test failed. ConvertCurrency non-existent currency -> non-existent currency. Error %s", err)
}
}
@@ -440,6 +444,10 @@ func TestFetchFixerCurrencyData(t *testing.T) {
}
func TestFetchYahooCurrencyData(t *testing.T) {
if !YahooEnabled {
t.Skip()
}
t.Parallel()
var fetchData []string
fiatCurrencies := DefaultCurrencies
@@ -460,6 +468,10 @@ func TestFetchYahooCurrencyData(t *testing.T) {
}
func TestQueryYahooCurrencyValues(t *testing.T) {
if !YahooEnabled {
t.Skip()
}
err := QueryYahooCurrencyValues(DefaultCurrencies)
if err != nil {
t.Errorf("Test Failed. QueryYahooCurrencyValues: Error, %s", err)

View File

@@ -15,7 +15,7 @@ func TestGetSymbolByCurrencyName(t *testing.T) {
_, err = GetSymbolByCurrencyName("BLAH")
if err == nil {
t.Errorf("Test failed. TestGetSymbolByCurrencyNam returned nil on non-existant currency")
t.Errorf("Test failed. TestGetSymbolByCurrencyNam returned nil on non-existent currency")
}
}

View File

@@ -43,7 +43,7 @@ type Trades struct {
Trades []Trade `json:"trades"`
}
// Trade is a sub-type which holds the singular trade that occured in the past
// Trade is a sub-type which holds the singular trade that occurred in the past
type Trade struct {
TID int64 `json:"tid"`
Price float64 `json:"px"`

View File

@@ -37,7 +37,7 @@ func TestSetup(t *testing.T) {
setup := ANX{}
setup.Name = "ANX"
anxSetupConfig := config.GetConfig()
anxSetupConfig.LoadConfig("../../testdata/configtest.dat")
anxSetupConfig.LoadConfig("../../testdata/configtest.json")
anxConfig, err := anxSetupConfig.GetExchangeConfig("ANX")
if err != nil {
t.Error("Test Failed - ANX Setup() init error")

View File

@@ -140,9 +140,11 @@ func (b *Bitfinex) GetFundingBook(symbol string) (FundingBook, error) {
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
}
// GetOrderbook retieves the entire orderbook bid and ask price on a currency
// pair
// GetOrderbook retieves the orderbook bid and ask price points for a currency
// pair - By default the response will return 25 bid and 25 ask price points.
// CurrencyPair - Example "BTCUSD"
// Values can contain limit amounts for both the asks and bids - Example
// "limit_bids" = 1000
func (b *Bitfinex) GetOrderbook(currencyPair string, values url.Values) (Orderbook, error) {
response := Orderbook{}
path := common.EncodeURLValues(
@@ -153,7 +155,10 @@ func (b *Bitfinex) GetOrderbook(currencyPair string, values url.Values) (Orderbo
}
// GetTrades returns a list of the most recent trades for the given curencyPair
// By default the response will return 100 trades
// CurrencyPair - Example "BTCUSD"
// Values can contain limit amounts for the number of trades returned - Example
// "limit_trades" = 1000
func (b *Bitfinex) GetTrades(currencyPair string, values url.Values) ([]TradeStructure, error) {
response := []TradeStructure{}
path := common.EncodeURLValues(
@@ -188,7 +193,7 @@ func (b *Bitfinex) GetLends(symbol string, values url.Values) ([]Lends, error) {
return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
}
// GetSymbols returns the avaliable currency pairs on the exchange
// GetSymbols returns the available currency pairs on the exchange
func (b *Bitfinex) GetSymbols() ([]string, error) {
products := []string{}
path := fmt.Sprint(bitfinexAPIURL + bitfinexSymbols)
@@ -444,7 +449,7 @@ func (b *Bitfinex) GetBalanceHistory(symbol string, timeSince, timeUntil time.Ti
b.SendAuthenticatedHTTPRequest("POST", bitfinexHistory, request, &response)
}
// GetMovementHistory returns an array of past deposits and withdrawels
// GetMovementHistory returns an array of past deposits and withdrawals
func (b *Bitfinex) GetMovementHistory(symbol, method string, timeSince, timeUntil time.Time, limit int) ([]MovementHistory, error) {
response := []MovementHistory{}
request := make(map[string]interface{})

View File

@@ -32,7 +32,7 @@ func TestSetup(t *testing.T) {
setup := Bitfinex{}
setup.Name = "Bitfinex"
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.dat")
cfg.LoadConfig("../../testdata/configtest.json")
bfxConfig, err := cfg.GetExchangeConfig("Bitfinex")
if err != nil {
t.Error("Test Failed - Bitfinex Setup() init error")

View File

@@ -40,7 +40,7 @@ type TradeStructure struct {
Type string `json:"sell"`
}
// Lendbook holds most recent funding data for a relevent currency
// Lendbook holds most recent funding data for a relevant currency
type Lendbook struct {
Bids []Book `json:"bids"`
Asks []Book `json:"asks"`
@@ -86,7 +86,7 @@ type AccountInfo struct {
} `json:"fees"`
}
// AccountFees stores withdrawel account fee data from Bitfinex
// AccountFees stores withdrawal account fee data from Bitfinex
type AccountFees struct {
Withdraw struct {
BTC float64 `json:"BTC,string"`
@@ -186,7 +186,7 @@ type WalletTransfer struct {
Message string `json:"message"`
}
// Withdrawal holds withdrawel status information
// Withdrawal holds withdrawal status information
type Withdrawal struct {
Status string `json:"status"`
Message string `json:"message"`
@@ -300,7 +300,7 @@ type Offer struct {
ExecutedAmount float64 `json:"executed_amount,string"`
}
// MarginFunds holds active funding information used in a margin positon
// MarginFunds holds active funding information used in a margin position
type MarginFunds struct {
ID int64 `json:"id"`
PositionID int64 `json:"position_id"`

View File

@@ -2,6 +2,7 @@ package bitfinex
import (
"log"
"net/url"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
@@ -78,7 +79,10 @@ func (b *Bitfinex) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderb
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (b *Bitfinex) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
var orderBook orderbook.Base
orderbookNew, err := b.GetOrderbook(p.Pair().String(), nil)
urlVals := url.Values{}
urlVals.Set("limit_bids", "100")
urlVals.Set("limit_asks", "100")
orderbookNew, err := b.GetOrderbook(p.Pair().String(), urlVals)
if err != nil {
return orderBook, err
}

View File

@@ -350,7 +350,7 @@ func (b *Bitstamp) PlaceOrder(currencyPair string, price float64, amount float64
b.SendAuthenticatedHTTPRequest(path, true, req, &response)
}
// GetWithdrawalRequests returns withdrawl requests for the account
// GetWithdrawalRequests returns withdrawal 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) {

View File

@@ -42,7 +42,7 @@ func TestSetup(t *testing.T) {
b := Bitstamp{}
b.Name = "Bitstamp"
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.dat")
cfg.LoadConfig("../../testdata/configtest.json")
bConfig, err := cfg.GetExchangeConfig("Bitstamp")
if err != nil {
t.Error("Test Failed - Bitstamp Setup() init error")

View File

@@ -27,7 +27,7 @@ func TestSetup(t *testing.T) {
b := Bittrex{}
b.Name = "Bittrex"
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.dat")
cfg.LoadConfig("../../testdata/configtest.json")
bConfig, err := cfg.GetExchangeConfig("Bittrex")
if err != nil {
t.Error("Test Failed - Bittrex Setup() init error")

View File

@@ -23,7 +23,7 @@ func TestSetup(t *testing.T) {
t.Parallel()
b.Name = "BTCC"
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.dat")
cfg.LoadConfig("../../testdata/configtest.json")
bConfig, err := cfg.GetExchangeConfig("BTCC")
if err != nil {
t.Error("Test Failed - BTCC Setup() init error")

View File

@@ -60,7 +60,7 @@ func (b *BTCMarkets) SetDefaults() {
b.AssetTypes = []string{ticker.Spot}
}
// Setup takes in an exchange configuration and sets all paramaters
// Setup takes in an exchange configuration and sets all parameters
func (b *BTCMarkets) Setup(exch config.ExchangeConfig) {
if !exch.Enabled {
b.SetEnabled(false)

View File

@@ -25,7 +25,7 @@ func TestSetup(t *testing.T) {
b := BTCMarkets{}
b.Name = "BTC Markets"
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.dat")
cfg.LoadConfig("../../testdata/configtest.json")
bConfig, err := cfg.GetExchangeConfig("BTC Markets")
if err != nil {
t.Error("Test Failed - BTC Markets Setup() init error")

View File

@@ -15,7 +15,7 @@ import (
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 error message for authenticated request without credentials 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."

View File

@@ -22,7 +22,7 @@ func TestSetAssetTypes(t *testing.T) {
err = b.SetAssetTypes()
if err == nil {
t.Fatal("Test failed. TestSetAssetTypes returned nil error for a non-existant exchange")
t.Fatal("Test failed. TestSetAssetTypes returned nil error for a non-existent exchange")
}
b.Name = "ANX"
@@ -77,9 +77,9 @@ func TestGetExchangeAssetTypes(t *testing.T) {
t.Fatal("Test failed. Bitfinex does not contain default asset type 'SPOT'")
}
_, err = GetExchangeAssetTypes("non-existant-exchange")
_, err = GetExchangeAssetTypes("non-existent-exchange")
if err == nil {
t.Fatal("Test failed. Got asset types for non-existant exchange")
t.Fatal("Test failed. Got asset types for non-existent exchange")
}
}
@@ -96,7 +96,7 @@ func TestSetCurrencyPairFormat(t *testing.T) {
err = b.SetCurrencyPairFormat()
if err == nil {
t.Fatal("Test failed. TestSetCurrencyPairFormat returned nil error for a non-existant exchange")
t.Fatal("Test failed. TestSetCurrencyPairFormat returned nil error for a non-existent exchange")
}
b.Name = "ANX"
@@ -349,9 +349,9 @@ func TestGetAndFormatExchangeCurrencies(t *testing.T) {
actual, expected)
}
_, err = GetAndFormatExchangeCurrencies("non-existant", pairs)
_, err = GetAndFormatExchangeCurrencies("non-existent", pairs)
if err == nil {
t.Errorf("Test failed - Exchange TestGetAndFormatExchangeCurrencies returned nil error on non-existant exchange")
t.Errorf("Test failed - Exchange TestGetAndFormatExchangeCurrencies returned nil error on non-existent exchange")
}
}

View File

@@ -16,6 +16,7 @@ import (
const (
gdaxAPIURL = "https://api.gdax.com/"
gdaxSandboxAPIURL = "https://public.sandbox.gdax.com"
gdaxAPIVersion = "0"
gdaxProducts = "products"
gdaxOrderbook = "book"
@@ -69,9 +70,10 @@ func (g *GDAX) SetDefaults() {
g.ConfigCurrencyPairFormat.Delimiter = ""
g.ConfigCurrencyPairFormat.Uppercase = true
g.AssetTypes = []string{ticker.Spot}
g.APIUrl = gdaxAPIURL
}
// Setup initialises the exchange paramaters with the current configuration
// Setup initialises the exchange parameters with the current configuration
func (g *GDAX) Setup(exch config.ExchangeConfig) {
if !exch.Enabled {
g.SetEnabled(false)
@@ -85,6 +87,9 @@ func (g *GDAX) Setup(exch config.ExchangeConfig) {
g.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
g.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
g.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
if exch.UseSandbox {
g.APIUrl = gdaxSandboxAPIURL
}
err := g.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)
@@ -110,17 +115,17 @@ func (g *GDAX) GetProducts() ([]Product, error) {
products := []Product{}
return products,
common.SendHTTPGetRequest(gdaxAPIURL+gdaxProducts, true, g.Verbose, &products)
common.SendHTTPGetRequest(g.APIUrl+gdaxProducts, true, g.Verbose, &products)
}
// GetOrderbook returns orderbook by currency pair and level
func (g *GDAX) GetOrderbook(symbol string, level int) (interface{}, error) {
orderbook := OrderbookResponse{}
path := fmt.Sprintf("%s/%s/%s", gdaxAPIURL+gdaxProducts, symbol, gdaxOrderbook)
path := fmt.Sprintf("%s/%s/%s", g.APIUrl+gdaxProducts, symbol, gdaxOrderbook)
if level > 0 {
levelStr := strconv.Itoa(level)
path = fmt.Sprintf("%s/%s/%s?level=%s", gdaxAPIURL+gdaxProducts, symbol, gdaxOrderbook, levelStr)
path = fmt.Sprintf("%s/%s/%s?level=%s", g.APIUrl+gdaxProducts, symbol, gdaxOrderbook, levelStr)
}
if err := common.SendHTTPGetRequest(path, true, g.Verbose, &orderbook); err != nil {
@@ -190,7 +195,7 @@ func (g *GDAX) GetOrderbook(symbol string, level int) (interface{}, error) {
func (g *GDAX) GetTicker(currencyPair string) (Ticker, error) {
ticker := Ticker{}
path := fmt.Sprintf(
"%s/%s/%s", gdaxAPIURL+gdaxProducts, currencyPair, gdaxTicker)
"%s/%s/%s", g.APIUrl+gdaxProducts, currencyPair, gdaxTicker)
log.Println(path)
return ticker, common.SendHTTPGetRequest(path, true, g.Verbose, &ticker)
@@ -201,7 +206,7 @@ func (g *GDAX) GetTicker(currencyPair string) (Ticker, error) {
func (g *GDAX) GetTrades(currencyPair string) ([]Trade, error) {
trades := []Trade{}
path := fmt.Sprintf(
"%s/%s/%s", gdaxAPIURL+gdaxProducts, currencyPair, gdaxTrades)
"%s/%s/%s", g.APIUrl+gdaxProducts, currencyPair, gdaxTrades)
return trades, common.SendHTTPGetRequest(path, true, g.Verbose, &trades)
}
@@ -226,7 +231,7 @@ func (g *GDAX) GetHistoricRates(currencyPair string, start, end, granularity int
}
path := common.EncodeURLValues(
fmt.Sprintf("%s/%s/%s", gdaxAPIURL+gdaxProducts, currencyPair, gdaxHistory),
fmt.Sprintf("%s/%s/%s", g.APIUrl+gdaxProducts, currencyPair, gdaxHistory),
values)
if err := common.SendHTTPGetRequest(path, true, g.Verbose, &resp); err != nil {
@@ -253,7 +258,7 @@ func (g *GDAX) GetHistoricRates(currencyPair string, start, end, granularity int
func (g *GDAX) GetStats(currencyPair string) (Stats, error) {
stats := Stats{}
path := fmt.Sprintf(
"%s/%s/%s", gdaxAPIURL+gdaxProducts, currencyPair, gdaxStats)
"%s/%s/%s", g.APIUrl+gdaxProducts, currencyPair, gdaxStats)
return stats, common.SendHTTPGetRequest(path, true, g.Verbose, &stats)
}
@@ -264,7 +269,7 @@ func (g *GDAX) GetCurrencies() ([]Currency, error) {
currencies := []Currency{}
return currencies,
common.SendHTTPGetRequest(gdaxAPIURL+gdaxCurrencies, true, g.Verbose, &currencies)
common.SendHTTPGetRequest(g.APIUrl+gdaxCurrencies, true, g.Verbose, &currencies)
}
// GetServerTime returns the API server time
@@ -272,7 +277,7 @@ func (g *GDAX) GetServerTime() (ServerTime, error) {
serverTime := ServerTime{}
return serverTime,
common.SendHTTPGetRequest(gdaxAPIURL+gdaxTime, true, g.Verbose, &serverTime)
common.SendHTTPGetRequest(g.APIUrl+gdaxTime, true, g.Verbose, &serverTime)
}
// GetAccounts returns a list of trading accounts associated with the APIKEYS
@@ -487,7 +492,7 @@ func (g *GDAX) GetOrders(status []string, currencyPair string) ([]GeneralizedOrd
params.Set("product_id", currencyPair)
}
path := common.EncodeURLValues(gdaxAPIURL+gdaxOrders, params)
path := common.EncodeURLValues(g.APIUrl+gdaxOrders, params)
path = common.GetURIPath(path)
return resp,
@@ -514,10 +519,10 @@ func (g *GDAX) GetFills(orderID, currencyPair string) ([]FillResponse, error) {
params.Set("product_id", currencyPair)
}
if len(params.Get("order_id")) == 0 && len(params.Get("product_id")) == 0 {
return resp, errors.New("no paramaters set")
return resp, errors.New("no parameters set")
}
path := common.EncodeURLValues(gdaxAPIURL+gdaxFills, params)
path := common.EncodeURLValues(g.APIUrl+gdaxFills, params)
uri := common.GetURIPath(path)
return resp,
@@ -533,7 +538,7 @@ func (g *GDAX) GetFundingRecords(status string) ([]Funding, error) {
params := url.Values{}
params.Set("status", status)
path := common.EncodeURLValues(gdaxAPIURL+gdaxFunding, params)
path := common.EncodeURLValues(g.APIUrl+gdaxFunding, params)
uri := common.GetURIPath(path)
return resp,
@@ -708,7 +713,7 @@ func (g *GDAX) GetCoinbaseAccounts() ([]CoinbaseAccounts, error) {
// E.g. BTC-USD. *Required* if type is fills
// accountID - ID of the account to generate an account report for. *Required*
// if type is account
// format - pdf or csv (defualt is pdf)
// format - pdf or csv (default is pdf)
// email - [optional] Email address to send the report to
func (g *GDAX) GetReport(reportType, startDate, endDate, currencyPair, accountID, format, email string) (Report, error) {
resp := Report{}
@@ -782,7 +787,7 @@ func (g *GDAX) SendAuthenticatedHTTPRequest(method, path string, params map[stri
headers["CB-ACCESS-PASSPHRASE"] = g.ClientID
headers["Content-Type"] = "application/json"
resp, err := common.SendHTTPRequest(method, gdaxAPIURL+path, headers, bytes.NewBuffer(payload))
resp, err := common.SendHTTPRequest(method, g.APIUrl+path, headers, bytes.NewBuffer(payload))
if err != nil {
return err
}

View File

@@ -21,7 +21,7 @@ func TestSetDefaults(t *testing.T) {
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.dat")
cfg.LoadConfig("../../testdata/configtest.json")
gdxConfig, err := cfg.GetExchangeConfig("Bitfinex")
if err != nil {
t.Error("Test Failed - GDAX Setup() init error")

View File

@@ -111,7 +111,7 @@ func (g *Gemini) SetDefaults() {
g.AssetTypes = []string{ticker.Spot}
}
// Setup sets exchange configuration paramaters
// Setup sets exchange configuration parameters
func (g *Gemini) Setup(exch config.ExchangeConfig) {
if !exch.Enabled {
g.SetEnabled(false)
@@ -125,6 +125,9 @@ func (g *Gemini) Setup(exch config.ExchangeConfig) {
g.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
g.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
g.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
if exch.UseSandbox {
g.APIUrl = geminiSandboxAPIURL
}
err := g.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)
@@ -139,7 +142,7 @@ func (g *Gemini) Setup(exch config.ExchangeConfig) {
// GetSymbols returns all available symbols for trading
func (g *Gemini) GetSymbols() ([]string, error) {
symbols := []string{}
path := fmt.Sprintf("%s/v%s/%s", geminiAPIURL, geminiAPIVersion, geminiSymbols)
path := fmt.Sprintf("%s/v%s/%s", g.APIUrl, geminiAPIVersion, geminiSymbols)
return symbols, common.SendHTTPGetRequest(path, true, g.Verbose, &symbols)
}
@@ -156,7 +159,7 @@ func (g *Gemini) GetTicker(currencyPair string) (Ticker, error) {
ticker := Ticker{}
resp := TickerResponse{}
path := fmt.Sprintf("%s/v%s/%s/%s", geminiAPIURL, geminiAPIVersion, geminiTicker, currencyPair)
path := fmt.Sprintf("%s/v%s/%s/%s", g.APIUrl, geminiAPIVersion, geminiTicker, currencyPair)
err := common.SendHTTPGetRequest(path, true, g.Verbose, &resp)
if err != nil {
@@ -182,7 +185,7 @@ func (g *Gemini) GetTicker(currencyPair string) (Ticker, error) {
// params - limit_bids or limit_asks [OPTIONAL] default 50, 0 returns all Values
// Type is an integer ie "params.Set("limit_asks", 30)"
func (g *Gemini) GetOrderbook(currencyPair string, params url.Values) (Orderbook, error) {
path := common.EncodeURLValues(fmt.Sprintf("%s/v%s/%s/%s", geminiAPIURL, geminiAPIVersion, geminiOrderbook, currencyPair), params)
path := common.EncodeURLValues(fmt.Sprintf("%s/v%s/%s/%s", g.APIUrl, geminiAPIVersion, geminiOrderbook, currencyPair), params)
orderbook := Orderbook{}
return orderbook, common.SendHTTPGetRequest(path, true, g.Verbose, &orderbook)
@@ -198,15 +201,15 @@ func (g *Gemini) GetOrderbook(currencyPair string, params url.Values) (Orderbook
// include_breaks boolean Optional. Whether to display broken trades. False by
// default. Can be '1' or 'true' to activate
func (g *Gemini) GetTrades(currencyPair string, params url.Values) ([]Trade, error) {
path := common.EncodeURLValues(fmt.Sprintf("%s/v%s/%s/%s", geminiAPIURL, geminiAPIVersion, geminiTrades, currencyPair), params)
path := common.EncodeURLValues(fmt.Sprintf("%s/v%s/%s/%s", g.APIUrl, geminiAPIVersion, geminiTrades, currencyPair), params)
trades := []Trade{}
return trades, common.SendHTTPGetRequest(path, true, g.Verbose, &trades)
}
// GetAuction returns auction infomation
// GetAuction returns auction information
func (g *Gemini) GetAuction(currencyPair string) (Auction, error) {
path := fmt.Sprintf("%s/v%s/%s/%s", geminiAPIURL, geminiAPIVersion, geminiAuction, currencyPair)
path := fmt.Sprintf("%s/v%s/%s/%s", g.APIUrl, geminiAPIVersion, geminiAuction, currencyPair)
auction := Auction{}
return auction, common.SendHTTPGetRequest(path, true, g.Verbose, &auction)
@@ -224,7 +227,7 @@ func (g *Gemini) GetAuction(currencyPair string) (Auction, error) {
// include_indicative - [bool] Whether to include publication of
// indicative prices and quantities.
func (g *Gemini) GetAuctionHistory(currencyPair string, params url.Values) ([]AuctionHistory, error) {
path := common.EncodeURLValues(fmt.Sprintf("%s/v%s/%s/%s/%s", geminiAPIURL, geminiAPIVersion, geminiAuction, currencyPair, geminiAuctionHistory), params)
path := common.EncodeURLValues(fmt.Sprintf("%s/v%s/%s/%s/%s", g.APIUrl, geminiAPIVersion, geminiAuction, currencyPair, geminiAuctionHistory), params)
auctionHist := []AuctionHistory{}
return auctionHist, common.SendHTTPGetRequest(path, true, g.Verbose, &auctionHist)
@@ -348,8 +351,8 @@ func (g *Gemini) GetDepositAddress(depositAddlabel, currency string) (DepositAdd
}
// WithdrawCrypto withdraws crypto currency to a whitelisted address
func (g *Gemini) WithdrawCrypto(address, currency string, amount float64) (WithdrawelAddress, error) {
response := WithdrawelAddress{}
func (g *Gemini) WithdrawCrypto(address, currency string, amount float64) (WithdrawalAddress, error) {
response := WithdrawalAddress{}
request := make(map[string]interface{})
request["address"] = address
request["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)

View File

@@ -47,7 +47,7 @@ func TestSetDefaults(t *testing.T) {
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.dat")
cfg.LoadConfig("../../testdata/configtest.json")
geminiConfig, err := cfg.GetExchangeConfig("Gemini")
if err != nil {
t.Error("Test Failed - Gemini Setup() init error")

View File

@@ -150,8 +150,8 @@ type DepositAddress struct {
Label string `json:"label"`
}
// WithdrawelAddress holds withdrawel information
type WithdrawelAddress struct {
// WithdrawalAddress holds withdrawal information
type WithdrawalAddress struct {
Address string `json:"address"`
Amount float64 `json:"amount"`
TXHash string `json:"txHash"`

View File

@@ -15,14 +15,16 @@ import (
)
const (
HUOBI_API_URL = "https://api.huobi.com/apiv2.php"
HUOBI_API_VERSION = "2"
huobiAPIURL = "https://api.huobi.com/apiv2.php"
huobiAPIVersion = "2"
)
// HUOBI is the overarching type across this package
type HUOBI struct {
exchange.Base
}
// SetDefaults sets default values for the exchange
func (h *HUOBI) SetDefaults() {
h.Name = "Huobi"
h.Enabled = false
@@ -37,6 +39,7 @@ func (h *HUOBI) SetDefaults() {
h.AssetTypes = []string{ticker.Spot}
}
// Setup sets user configuration
func (h *HUOBI) Setup(exch config.ExchangeConfig) {
if !exch.Enabled {
h.SetEnabled(false)
@@ -61,31 +64,28 @@ func (h *HUOBI) Setup(exch config.ExchangeConfig) {
}
}
// GetFee returns Huobi fee
func (h *HUOBI) GetFee() float64 {
return h.Fee
}
func (h *HUOBI) GetTicker(symbol string) (HuobiTicker, error) {
resp := HuobiTickerResponse{}
// GetTicker returns the Huobi ticker
func (h *HUOBI) GetTicker(symbol string) (Ticker, error) {
resp := TickerResponse{}
path := fmt.Sprintf("https://api.huobi.com/staticmarket/ticker_%s_json.js", symbol)
err := common.SendHTTPGetRequest(path, true, h.Verbose, &resp)
if err != nil {
return HuobiTicker{}, err
}
return resp.Ticker, nil
return resp.Ticker, common.SendHTTPGetRequest(path, true, h.Verbose, &resp)
}
func (h *HUOBI) GetOrderBook(symbol string) (HuobiOrderbook, error) {
// GetOrderBook returns the Huobi current orderbook for a currency pair
func (h *HUOBI) GetOrderBook(symbol string) (Orderbook, error) {
path := fmt.Sprintf("https://api.huobi.com/staticmarket/depth_%s_json.js", symbol)
resp := HuobiOrderbook{}
err := common.SendHTTPGetRequest(path, true, h.Verbose, &resp)
if err != nil {
return resp, err
}
return resp, nil
resp := Orderbook{}
return resp, common.SendHTTPGetRequest(path, true, h.Verbose, &resp)
}
// GetAccountInfo returns account information
func (h *HUOBI) GetAccountInfo() {
err := h.SendAuthenticatedRequest("get_account_info", url.Values{})
@@ -94,6 +94,7 @@ func (h *HUOBI) GetAccountInfo() {
}
}
// GetOrders returns full list of orders
func (h *HUOBI) GetOrders(coinType int) {
values := url.Values{}
values.Set("coin_type", strconv.Itoa(coinType))
@@ -104,6 +105,7 @@ func (h *HUOBI) GetOrders(coinType int) {
}
}
// GetOrderInfo returns specific info on an order
func (h *HUOBI) GetOrderInfo(orderID, coinType int) {
values := url.Values{}
values.Set("id", strconv.Itoa(orderID))
@@ -115,6 +117,7 @@ func (h *HUOBI) GetOrderInfo(orderID, coinType int) {
}
}
// Trade opens a trade on the Huobi exchange
func (h *HUOBI) Trade(orderType string, coinType int, price, amount float64) {
values := url.Values{}
if orderType != "buy" {
@@ -130,6 +133,7 @@ func (h *HUOBI) Trade(orderType string, coinType int, price, amount float64) {
}
}
// MarketTrade initiates a market trade
func (h *HUOBI) MarketTrade(orderType string, coinType int, price, amount float64) {
values := url.Values{}
if orderType != "buy_market" {
@@ -145,6 +149,7 @@ func (h *HUOBI) MarketTrade(orderType string, coinType int, price, amount float6
}
}
// CancelOrder cancels order by order ID
func (h *HUOBI) CancelOrder(orderID, coinType int) {
values := url.Values{}
values.Set("coin_type", strconv.Itoa(coinType))
@@ -156,6 +161,7 @@ func (h *HUOBI) CancelOrder(orderID, coinType int) {
}
}
// ModifyOrder modifies an order
func (h *HUOBI) ModifyOrder(orderType string, coinType, orderID int, price, amount float64) {
values := url.Values{}
values.Set("coin_type", strconv.Itoa(coinType))
@@ -169,6 +175,7 @@ func (h *HUOBI) ModifyOrder(orderType string, coinType, orderID int, price, amou
}
}
// GetNewDealOrders creates a new deal
func (h *HUOBI) GetNewDealOrders(coinType int) {
values := url.Values{}
values.Set("coin_type", strconv.Itoa(coinType))
@@ -179,6 +186,7 @@ func (h *HUOBI) GetNewDealOrders(coinType int) {
}
}
// GetOrderIDByTradeID returns ORDERID by Trade ID
func (h *HUOBI) GetOrderIDByTradeID(coinType, orderID int) {
values := url.Values{}
values.Set("coin_type", strconv.Itoa(coinType))
@@ -190,6 +198,7 @@ func (h *HUOBI) GetOrderIDByTradeID(coinType, orderID int) {
}
}
// SendAuthenticatedRequest sends an autheticated HTTP request to Huobi
func (h *HUOBI) SendAuthenticatedRequest(method string, v url.Values) error {
if !h.AuthenticatedAPISupport {
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, h.Name)
@@ -203,13 +212,13 @@ func (h *HUOBI) SendAuthenticatedRequest(method string, v url.Values) error {
encoded := v.Encode()
if h.Verbose {
log.Printf("Sending POST request to %s with params %s\n", HUOBI_API_URL, encoded)
log.Printf("Sending POST request to %s with params %s\n", huobiAPIURL, encoded)
}
headers := make(map[string]string)
headers["Content-Type"] = "application/x-www-form-urlencoded"
resp, err := common.SendHTTPRequest("POST", HUOBI_API_URL, headers, strings.NewReader(encoded))
resp, err := common.SendHTTPRequest("POST", huobiAPIURL, headers, strings.NewReader(encoded))
if err != nil {
return err

View File

@@ -0,0 +1,50 @@
package huobi
import (
"testing"
"github.com/thrasher-/gocryptotrader/config"
)
var h HUOBI
// Please supply your own APIKEYS here for due diligence testing
const (
apiKey = ""
apiSecret = ""
)
func TestSetDefaults(t *testing.T) {
h.SetDefaults()
}
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
huobiConfig, err := cfg.GetExchangeConfig("Huobi")
if err != nil {
t.Error("Test Failed - Huobi Setup() init error")
}
huobiConfig.AuthenticatedAPISupport = true
huobiConfig.APIKey = apiKey
huobiConfig.APISecret = apiSecret
h.Setup(huobiConfig)
}
func TestGetFee(t *testing.T) {
t.Parallel()
if h.GetFee() != 0 {
t.Error("test failed - Huobi GetFee() error")
}
}
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := h.GetTicker("btcusd")
if err == nil {
t.Error("test failed - Huobi GetTicker() error", err)
}
}

View File

@@ -1,6 +1,7 @@
package huobi
type HuobiTicker struct {
// Ticker holds ticker information
type Ticker struct {
High float64
Low float64
Last float64
@@ -9,12 +10,14 @@ type HuobiTicker struct {
Sell float64
}
type HuobiTickerResponse struct {
// TickerResponse holds the initial response type
type TickerResponse struct {
Time string
Ticker HuobiTicker
Ticker Ticker
}
type HuobiOrderbook struct {
// Orderbook holds the order book information
type Orderbook struct {
ID float64
TS float64
Bids [][]float64 `json:"bids"`

View File

@@ -51,7 +51,7 @@ func (i *ItBit) SetDefaults() {
i.AssetTypes = []string{ticker.Spot}
}
// Setup sets the exchange paramaters from exchange config
// Setup sets the exchange parameters from exchange config
func (i *ItBit) Setup(exch config.ExchangeConfig) {
if !exch.Enabled {
i.SetEnabled(false)

View File

@@ -22,7 +22,7 @@ func TestSetDefaults(t *testing.T) {
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.dat")
cfg.LoadConfig("../../testdata/configtest.json")
itbitConfig, err := cfg.GetExchangeConfig("ITBIT")
if err != nil {
t.Error("Test Failed - Gemini Setup() init error")
@@ -124,6 +124,7 @@ func TestGetOrder(t *testing.T) {
}
func TestCancelOrder(t *testing.T) {
t.Skip()
err := i.CancelOrder("1337", "1337order")
if err == nil {
t.Error("Test Failed - CancelOrder() error", err)

View File

@@ -1,7 +1,6 @@
package kraken
import (
"errors"
"fmt"
"log"
"net/url"
@@ -16,37 +15,39 @@ import (
)
const (
KRAKEN_API_URL = "https://api.kraken.com"
KRAKEN_API_VERSION = "0"
KRAKEN_SERVER_TIME = "Time"
KRAKEN_ASSETS = "Assets"
KRAKEN_ASSET_PAIRS = "AssetPairs"
KRAKEN_TICKER = "Ticker"
KRAKEN_OHLC = "OHLC"
KRAKEN_DEPTH = "Depth"
KRAKEN_TRADES = "Trades"
KRAKEN_SPREAD = "Spread"
KRAKEN_BALANCE = "Balance"
KRAKEN_TRADE_BALANCE = "TradeBalance"
KRAKEN_OPEN_ORDERS = "OpenOrders"
KRAKEN_CLOSED_ORDERS = "ClosedOrders"
KRAKEN_QUERY_ORDERS = "QueryOrders"
KRAKEN_TRADES_HISTORY = "TradesHistory"
KRAKEN_QUERY_TRADES = "QueryTrades"
KRAKEN_OPEN_POSITIONS = "OpenPositions"
KRAKEN_LEDGERS = "Ledgers"
KRAKEN_QUERY_LEDGERS = "QueryLedgers"
KRAKEN_TRADE_VOLUME = "TradeVolume"
KRAKEN_ORDER_CANCEL = "CancelOrder"
KRAKEN_ORDER_PLACE = "AddOrder"
krakenAPIURL = "https://api.kraken.com"
krakenAPIVersion = "0"
krakenServerTime = "Time"
krakenAssets = "Assets"
krakenAssetPairs = "AssetPairs"
krakenTicker = "Ticker"
krakenOHLC = "OHLC"
krakenDepth = "Depth"
krakenTrades = "Trades"
krakenSpread = "Spread"
krakenBalance = "Balance"
krakenTradeBalance = "TradeBalance"
krakenOpenOrders = "OpenOrders"
krakenClosedOrders = "ClosedOrders"
krakenQueryOrders = "QueryOrders"
krakenTradeHistory = "TradesHistory"
krakenQueryTrades = "QueryTrades"
krakenOpenPositions = "OpenPositions"
krakenLedgers = "Ledgers"
krakenQueryLedgers = "QueryLedgers"
krakenTradeVolume = "TradeVolume"
krakenOrderCancel = "CancelOrder"
krakenOrderPlace = "AddOrder"
)
// Kraken is the overarching type across the alphapoint package
type Kraken struct {
exchange.Base
CryptoFee, FiatFee float64
Ticker map[string]KrakenTicker
Ticker map[string]Ticker
}
// SetDefaults sets current default settings
func (k *Kraken) SetDefaults() {
k.Name = "Kraken"
k.Enabled = false
@@ -55,7 +56,7 @@ func (k *Kraken) SetDefaults() {
k.Verbose = false
k.Websocket = false
k.RESTPollingDelay = 10
k.Ticker = make(map[string]KrakenTicker)
k.Ticker = make(map[string]Ticker)
k.RequestCurrencyPairFormat.Delimiter = ""
k.RequestCurrencyPairFormat.Uppercase = true
k.RequestCurrencyPairFormat.Separator = ","
@@ -64,6 +65,7 @@ func (k *Kraken) SetDefaults() {
k.AssetTypes = []string{ticker.Spot}
}
// Setup sets current exchange configuration
func (k *Kraken) Setup(exch config.ExchangeConfig) {
if !exch.Enabled {
k.SetEnabled(false)
@@ -88,81 +90,75 @@ func (k *Kraken) Setup(exch config.ExchangeConfig) {
}
}
// GetFee returns current fee for either crypto or fiat
func (k *Kraken) GetFee(cryptoTrade bool) float64 {
if cryptoTrade {
return k.CryptoFee
} else {
return k.FiatFee
}
return k.FiatFee
}
func (k *Kraken) GetServerTime() error {
var result interface{}
path := fmt.Sprintf("%s/%s/public/%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_SERVER_TIME)
// GetServerTime returns current server time
func (k *Kraken) GetServerTime(unixTime bool) (interface{}, error) {
var result GeneralResponse
path := fmt.Sprintf("%s/%s/public/%s", krakenAPIURL, krakenAPIVersion, krakenServerTime)
err := common.SendHTTPGetRequest(path, true, k.Verbose, &result)
if err != nil {
return err
return nil, fmt.Errorf("getServerTime() error %s", err)
}
log.Println(result)
return nil
}
func (k *Kraken) GetAssets() error {
var result interface{}
path := fmt.Sprintf("%s/%s/public/%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_ASSETS)
err := common.SendHTTPGetRequest(path, true, k.Verbose, &result)
if err != nil {
return err
if unixTime {
return result.Result["unixtime"], nil
}
log.Println(result)
return nil
return result.Result["rfc1123"], nil
}
func (k *Kraken) GetAssetPairs() (map[string]KrakenAssetPairs, error) {
// GetAssets returns a full asset list
func (k *Kraken) GetAssets() (interface{}, error) {
var result GeneralResponse
path := fmt.Sprintf("%s/%s/public/%s", krakenAPIURL, krakenAPIVersion, krakenAssets)
return result.Result, common.SendHTTPGetRequest(path, true, k.Verbose, &result)
}
// GetAssetPairs returns a full asset pair list
func (k *Kraken) GetAssetPairs() (map[string]AssetPairs, error) {
type Response struct {
Result map[string]KrakenAssetPairs `json:"result"`
Error []interface{} `json:"error"`
Result map[string]AssetPairs `json:"result"`
Error []interface{} `json:"error"`
}
response := Response{}
path := fmt.Sprintf("%s/%s/public/%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_ASSET_PAIRS)
err := common.SendHTTPGetRequest(path, true, k.Verbose, &response)
path := fmt.Sprintf("%s/%s/public/%s", krakenAPIURL, krakenAPIVersion, krakenAssetPairs)
if err != nil {
return nil, err
}
return response.Result, nil
return response.Result, common.SendHTTPGetRequest(path, true, k.Verbose, &response)
}
func (k *Kraken) GetTicker(symbol string) error {
// GetTicker returns ticker information from kraken
func (k *Kraken) GetTicker(symbol string) (Ticker, error) {
ticker := Ticker{}
values := url.Values{}
values.Set("pair", symbol)
type Response struct {
Error []interface{} `json:"error"`
Data map[string]KrakenTickerResponse `json:"result"`
Error []interface{} `json:"error"`
Data map[string]TickerResponse `json:"result"`
}
resp := Response{}
path := fmt.Sprintf("%s/%s/public/%s?%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_TICKER, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &resp)
path := fmt.Sprintf("%s/%s/public/%s?%s", krakenAPIURL, krakenAPIVersion, krakenTicker, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &resp)
if err != nil {
return err
return ticker, err
}
if len(resp.Error) > 0 {
return errors.New(fmt.Sprintf("Kraken error: %s", resp.Error))
return ticker, fmt.Errorf("Kraken error: %s", resp.Error)
}
for x, y := range resp.Data {
x = x[1:4] + x[5:]
ticker := KrakenTicker{}
for _, y := range resp.Data {
ticker.Ask, _ = strconv.ParseFloat(y.Ask[0], 64)
ticker.Bid, _ = strconv.ParseFloat(y.Bid[0], 64)
ticker.Last, _ = strconv.ParseFloat(y.Last[0], 64)
@@ -172,25 +168,59 @@ func (k *Kraken) GetTicker(symbol string) error {
ticker.Low, _ = strconv.ParseFloat(y.Low[1], 64)
ticker.High, _ = strconv.ParseFloat(y.High[1], 64)
ticker.Open, _ = strconv.ParseFloat(y.Open, 64)
k.Ticker[x] = ticker
}
return nil
return ticker, nil
}
func (k *Kraken) GetOHLC(symbol string) error {
// GetOHLC returns an array of open high low close values of a currency pair
func (k *Kraken) GetOHLC(symbol string) ([]OpenHighLowClose, error) {
values := url.Values{}
values.Set("pair", symbol)
var result interface{}
path := fmt.Sprintf("%s/%s/public/%s?%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_OHLC, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &result)
if err != nil {
return err
type Response struct {
Error []interface{} `json:"error"`
Data map[string]interface{} `json:"result"`
}
log.Println(result)
return nil
var OHLC []OpenHighLowClose
var result Response
path := fmt.Sprintf("%s/%s/public/%s?%s", krakenAPIURL, krakenAPIVersion, krakenOHLC, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &result)
if err != nil {
return OHLC, err
}
if len(result.Error) != 0 {
return OHLC, fmt.Errorf("GetOHLC error: %s", result.Error)
}
for _, y := range result.Data[symbol].([]interface{}) {
o := OpenHighLowClose{}
for i, x := range y.([]interface{}) {
switch i {
case 0:
o.Time = x.(float64)
case 1:
o.Open, _ = strconv.ParseFloat(x.(string), 64)
case 2:
o.High, _ = strconv.ParseFloat(x.(string), 64)
case 3:
o.Low, _ = strconv.ParseFloat(x.(string), 64)
case 4:
o.Close, _ = strconv.ParseFloat(x.(string), 64)
case 5:
o.Vwap, _ = strconv.ParseFloat(x.(string), 64)
case 6:
o.Volume, _ = strconv.ParseFloat(x.(string), 64)
case 7:
o.Count = x.(float64)
}
}
OHLC = append(OHLC, o)
}
return OHLC, nil
}
// GetDepth returns the orderbook for a particular currency
@@ -199,12 +229,13 @@ func (k *Kraken) GetDepth(symbol string) (Orderbook, error) {
values.Set("pair", symbol)
var result interface{}
var ob Orderbook
path := fmt.Sprintf("%s/%s/public/%s?%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_DEPTH, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &result)
var orderBook Orderbook
path := fmt.Sprintf("%s/%s/public/%s?%s", krakenAPIURL, krakenAPIVersion, krakenDepth, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &result)
if err != nil {
return ob, err
return orderBook, err
}
data := result.(map[string]interface{})
@@ -223,14 +254,14 @@ func (k *Kraken) GetDepth(symbol string) (Orderbook, error) {
for x := range data {
entry := data[x].([]interface{})
price, err := strconv.ParseFloat(entry[0].(string), 64)
if err != nil {
return nil, err
price, priceErr := strconv.ParseFloat(entry[0].(string), 64)
if priceErr != nil {
return nil, priceErr
}
amount, err := strconv.ParseFloat(entry[1].(string), 64)
if err != nil {
return nil, err
amount, amountErr := strconv.ParseFloat(entry[1].(string), 64)
if amountErr != nil {
return nil, amountErr
}
result = append(result, OrderbookBase{Price: price, Amount: amount})
@@ -238,82 +269,116 @@ func (k *Kraken) GetDepth(symbol string) (Orderbook, error) {
return result, nil
}
ob.Bids, err = processOrderbook(bidsData)
orderBook.Bids, err = processOrderbook(bidsData)
if err != nil {
return ob, err
return orderBook, err
}
ob.Asks, err = processOrderbook(asksData)
orderBook.Asks, err = processOrderbook(asksData)
if err != nil {
return ob, err
return orderBook, err
}
return ob, nil
return orderBook, nil
}
func (k *Kraken) GetTrades(symbol string) error {
// GetTrades returns current trades on Kraken
func (k *Kraken) GetTrades(symbol string) ([]RecentTrades, error) {
values := url.Values{}
values.Set("pair", symbol)
var recentTrades []RecentTrades
var result interface{}
path := fmt.Sprintf("%s/%s/public/%s?%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_TRADES, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &result)
path := fmt.Sprintf("%s/%s/public/%s?%s", krakenAPIURL, krakenAPIVersion, krakenTrades, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &result)
if err != nil {
return err
return recentTrades, err
}
log.Println(result)
return nil
data := result.(map[string]interface{})
tradeInfo := data["result"].(map[string]interface{})
for _, x := range tradeInfo[symbol].([]interface{}) {
r := RecentTrades{}
for i, y := range x.([]interface{}) {
switch i {
case 0:
r.Price, _ = strconv.ParseFloat(y.(string), 64)
case 1:
r.Volume, _ = strconv.ParseFloat(y.(string), 64)
case 2:
r.Time = y.(float64)
case 3:
r.BuyOrSell = y.(string)
case 4:
r.MarketOrLimit = y.(string)
case 5:
r.Miscellaneous = y.(string)
}
}
recentTrades = append(recentTrades, r)
}
return recentTrades, nil
}
func (k *Kraken) GetSpread(symbol string) {
// GetSpread returns the full spread on Kraken
func (k *Kraken) GetSpread(symbol string) ([]Spread, error) {
values := url.Values{}
values.Set("pair", symbol)
var result interface{}
path := fmt.Sprintf("%s/%s/public/%s?%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_SPREAD, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &result)
var peanutButter []Spread
var response interface{}
path := fmt.Sprintf("%s/%s/public/%s?%s", krakenAPIURL, krakenAPIVersion, krakenSpread, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &response)
if err != nil {
log.Println(err)
return
}
}
func (k *Kraken) GetBalance() {
result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_BALANCE, url.Values{})
if err != nil {
log.Println(err)
return
return peanutButter, err
}
log.Println(result)
data := response.(map[string]interface{})
result := data["result"].(map[string]interface{})
for _, x := range result[symbol].([]interface{}) {
s := Spread{}
for i, y := range x.([]interface{}) {
switch i {
case 0:
s.Time = y.(float64)
case 1:
s.Bid, _ = strconv.ParseFloat(y.(string), 64)
case 2:
s.Ask, _ = strconv.ParseFloat(y.(string), 64)
}
}
peanutButter = append(peanutButter, s)
}
return peanutButter, nil
}
func (k *Kraken) GetTradeBalance(symbol, asset string) {
// GetBalance returns your balance associated with your keys
func (k *Kraken) GetBalance() (interface{}, error) {
return k.SendAuthenticatedHTTPRequest(krakenBalance, url.Values{})
}
// GetTradeBalance returns full information about your trades on Kraken
func (k *Kraken) GetTradeBalance(symbol, asset string) (interface{}, error) {
values := url.Values{}
if len(symbol) > 0 {
values.Set("aclass", symbol)
}
if len(asset) > 0 {
values.Set("asset", asset)
}
result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_TRADE_BALANCE, values)
if err != nil {
log.Println(err)
return
}
log.Println(result)
return k.SendAuthenticatedHTTPRequest(krakenTradeBalance, values)
}
func (k *Kraken) GetOpenOrders(showTrades bool, userref int64) {
// GetOpenOrders returns all current open orders
func (k *Kraken) GetOpenOrders(showTrades bool, userref int64) (interface{}, error) {
values := url.Values{}
if showTrades {
@@ -324,17 +389,11 @@ func (k *Kraken) GetOpenOrders(showTrades bool, userref int64) {
values.Set("userref", strconv.FormatInt(userref, 10))
}
result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_OPEN_ORDERS, values)
if err != nil {
log.Println(err)
return
}
log.Println(result)
return k.SendAuthenticatedHTTPRequest(krakenOpenOrders, values)
}
func (k *Kraken) GetClosedOrders(showTrades bool, userref, start, end, offset int64, closetime string) {
// GetClosedOrders returns a list of closed orders
func (k *Kraken) GetClosedOrders(showTrades bool, userref, start, end, offset int64, closetime string) (interface{}, error) {
values := url.Values{}
if showTrades {
@@ -361,17 +420,11 @@ func (k *Kraken) GetClosedOrders(showTrades bool, userref, start, end, offset in
values.Set("closetime", closetime)
}
result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_CLOSED_ORDERS, values)
if err != nil {
log.Println(err)
return
}
log.Println(result)
return k.SendAuthenticatedHTTPRequest(krakenClosedOrders, values)
}
func (k *Kraken) QueryOrdersInfo(showTrades bool, userref, txid int64) {
// QueryOrdersInfo returns order information
func (k *Kraken) QueryOrdersInfo(showTrades bool, userref, txid int64) (interface{}, error) {
values := url.Values{}
if showTrades {
@@ -386,17 +439,11 @@ func (k *Kraken) QueryOrdersInfo(showTrades bool, userref, txid int64) {
values.Set("txid", strconv.FormatInt(userref, 10))
}
result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_QUERY_ORDERS, values)
if err != nil {
log.Println(err)
return
}
log.Println(result)
return k.SendAuthenticatedHTTPRequest(krakenQueryOrders, values)
}
func (k *Kraken) GetTradesHistory(tradeType string, showRelatedTrades bool, start, end, offset int64) {
// GetTradesHistory returns trade history information
func (k *Kraken) GetTradesHistory(tradeType string, showRelatedTrades bool, start, end, offset int64) (interface{}, error) {
values := url.Values{}
if len(tradeType) > 0 {
@@ -419,17 +466,11 @@ func (k *Kraken) GetTradesHistory(tradeType string, showRelatedTrades bool, star
values.Set("offset", strconv.FormatInt(offset, 10))
}
result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_TRADES_HISTORY, values)
if err != nil {
log.Println(err)
return
}
log.Println(result)
return k.SendAuthenticatedHTTPRequest(krakenTradeHistory, values)
}
func (k *Kraken) QueryTrades(txid int64, showRelatedTrades bool) {
// QueryTrades returns information on a specific trade
func (k *Kraken) QueryTrades(txid int64, showRelatedTrades bool) (interface{}, error) {
values := url.Values{}
values.Set("txid", strconv.FormatInt(txid, 10))
@@ -437,17 +478,11 @@ func (k *Kraken) QueryTrades(txid int64, showRelatedTrades bool) {
values.Set("trades", "true")
}
result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_QUERY_TRADES, values)
if err != nil {
log.Println(err)
return
}
log.Println(result)
return k.SendAuthenticatedHTTPRequest(krakenQueryTrades, values)
}
func (k *Kraken) OpenPositions(txid int64, showPL bool) {
// OpenPositions returns current open positions
func (k *Kraken) OpenPositions(txid int64, showPL bool) (interface{}, error) {
values := url.Values{}
values.Set("txid", strconv.FormatInt(txid, 10))
@@ -455,17 +490,11 @@ func (k *Kraken) OpenPositions(txid int64, showPL bool) {
values.Set("docalcs", "true")
}
result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_OPEN_POSITIONS, values)
if err != nil {
log.Println(err)
return
}
log.Println(result)
return k.SendAuthenticatedHTTPRequest(krakenOpenPositions, values)
}
func (k *Kraken) GetLedgers(symbol, asset, ledgerType string, start, end, offset int64) {
// GetLedgers returns current ledgers
func (k *Kraken) GetLedgers(symbol, asset, ledgerType string, start, end, offset int64) (interface{}, error) {
values := url.Values{}
if len(symbol) > 0 {
@@ -492,45 +521,27 @@ func (k *Kraken) GetLedgers(symbol, asset, ledgerType string, start, end, offset
values.Set("offset", strconv.FormatInt(offset, 10))
}
result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_LEDGERS, values)
if err != nil {
log.Println(err)
return
}
log.Println(result)
return k.SendAuthenticatedHTTPRequest(krakenLedgers, values)
}
func (k *Kraken) QueryLedgers(id string) {
// QueryLedgers queries an individual ledger by ID
func (k *Kraken) QueryLedgers(id string) (interface{}, error) {
values := url.Values{}
values.Set("id", id)
result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_QUERY_LEDGERS, values)
if err != nil {
log.Println(err)
return
}
log.Println(result)
return k.SendAuthenticatedHTTPRequest(krakenQueryLedgers, values)
}
func (k *Kraken) GetTradeVolume(symbol string) {
// GetTradeVolume returns your trade volume by currency
func (k *Kraken) GetTradeVolume(symbol string) (interface{}, error) {
values := url.Values{}
values.Set("pair", symbol)
result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_TRADE_VOLUME, values)
if err != nil {
log.Println(err)
return
}
log.Println(result)
return k.SendAuthenticatedHTTPRequest(krakenTradeVolume, values)
}
func (k *Kraken) AddOrder(symbol, side, orderType string, price, price2, volume, leverage, position float64) {
// AddOrder adds a new order for Kraken exchange
func (k *Kraken) AddOrder(symbol, side, orderType string, price, price2, volume, leverage, position float64) (interface{}, error) {
values := url.Values{}
values.Set("pairs", symbol)
values.Set("type", side)
@@ -541,36 +552,24 @@ func (k *Kraken) AddOrder(symbol, side, orderType string, price, price2, volume,
values.Set("leverage", strconv.FormatFloat(leverage, 'f', -1, 64))
values.Set("position", strconv.FormatFloat(position, 'f', -1, 64))
result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_ORDER_PLACE, values)
if err != nil {
log.Println(err)
return
}
log.Println(result)
return k.SendAuthenticatedHTTPRequest(krakenOrderPlace, values)
}
func (k *Kraken) CancelOrder(orderID int64) {
// CancelOrder cancels order by orderID
func (k *Kraken) CancelOrder(orderID int64) (interface{}, error) {
values := url.Values{}
values.Set("txid", strconv.FormatInt(orderID, 10))
result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_ORDER_CANCEL, values)
if err != nil {
log.Println(err)
return
}
log.Println(result)
return k.SendAuthenticatedHTTPRequest(krakenOrderCancel, values)
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request
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)
path := fmt.Sprintf("/%s/private/%s", krakenAPIVersion, method)
if k.Nonce.Get() == 0 {
k.Nonce.Set(time.Now().UnixNano())
} else {
@@ -578,8 +577,8 @@ func (k *Kraken) SendAuthenticatedHTTPRequest(method string, values url.Values)
}
values.Set("nonce", k.Nonce.String())
secret, err := common.Base64Decode(k.APISecret)
secret, err := common.Base64Decode(k.APISecret)
if err != nil {
return nil, err
}
@@ -588,22 +587,33 @@ func (k *Kraken) SendAuthenticatedHTTPRequest(method string, values url.Values)
signature := common.Base64Encode(common.GetHMAC(common.HashSHA512, append([]byte(path), shasum...), secret))
if k.Verbose {
log.Printf("Sending POST request to %s, path: %s.", KRAKEN_API_URL, path)
log.Printf("Sending POST request to %s, path: %s.", krakenAPIURL, path)
}
headers := make(map[string]string)
headers["API-Key"] = k.APIKey
headers["API-Sign"] = signature
resp, err := common.SendHTTPRequest("POST", KRAKEN_API_URL+path, headers, strings.NewReader(values.Encode()))
rawResp, err := common.SendHTTPRequest("POST", krakenAPIURL+path, headers, strings.NewReader(values.Encode()))
if err != nil {
return nil, err
}
if k.Verbose {
log.Printf("Received raw: \n%s\n", resp)
log.Printf("Received raw: \n%s\n", rawResp)
}
return resp, nil
var resp interface{}
err = common.JSONDecode([]byte(rawResp), &resp)
if err != nil {
return nil, err
}
data := resp.(map[string]interface{})
if len(data["error"].([]interface{})) != 0 {
return nil, fmt.Errorf("kraken AuthenticattedHTTPRequest error: %s", data["error"])
}
return data["result"].(interface{}), nil
}

View File

@@ -0,0 +1,218 @@
package kraken
import (
"testing"
"github.com/thrasher-/gocryptotrader/config"
)
var k Kraken
// Please add your own APIkeys to do correct due diligence testing.
const (
apiKey = ""
apiSecret = ""
clientID = ""
)
func TestSetDefaults(t *testing.T) {
k.SetDefaults()
}
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
krakenConfig, err := cfg.GetExchangeConfig("Kraken")
if err != nil {
t.Error("Test Failed - kraken Setup() init error", err)
}
krakenConfig.AuthenticatedAPISupport = true
krakenConfig.APIKey = apiKey
krakenConfig.APISecret = apiSecret
krakenConfig.ClientID = clientID
k.Setup(krakenConfig)
}
func TestGetFee(t *testing.T) {
t.Parallel()
if k.GetFee(true) != 0.1 {
t.Error("Test Failed - kraken GetFee() error")
}
if k.GetFee(false) != 0.35 {
t.Error("Test Failed - kraken GetFee() error")
}
}
func TestGetServerTime(t *testing.T) {
t.Parallel()
_, err := k.GetServerTime(false)
if err != nil {
t.Error("Test Failed - GetServerTime() error", err)
}
_, err = k.GetServerTime(true)
if err != nil {
t.Error("Test Failed - GetServerTime() error", err)
}
}
func TestGetAssets(t *testing.T) {
t.Parallel()
_, err := k.GetAssets()
if err != nil {
t.Error("Test Failed - GetAssets() error", err)
}
}
func TestGetAssetPairs(t *testing.T) {
t.Parallel()
_, err := k.GetAssetPairs()
if err != nil {
t.Error("Test Failed - GetAssetPairs() error", err)
}
}
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := k.GetTicker("BCHEUR")
if err != nil {
t.Error("Test Failed - GetTicker() error", err)
}
}
func TestGetOHLC(t *testing.T) {
t.Parallel()
_, err := k.GetOHLC("BCHEUR")
if err != nil {
t.Error("Test Failed - GetOHLC() error", err)
}
}
func TestGetDepth(t *testing.T) {
t.Parallel()
_, err := k.GetDepth("BCHEUR")
if err != nil {
t.Error("Test Failed - GetDepth() error", err)
}
}
func TestGetTrades(t *testing.T) {
t.Parallel()
_, err := k.GetTrades("BCHEUR")
if err != nil {
t.Error("Test Failed - GetTrades() error", err)
}
}
func TestGetSpread(t *testing.T) {
t.Parallel()
_, err := k.GetSpread("BCHEUR")
if err != nil {
t.Error("Test Failed - GetSpread() error", err)
}
}
func TestGetBalance(t *testing.T) {
t.Parallel()
_, err := k.GetBalance()
if err == nil {
t.Error("Test Failed - GetBalance() error", err)
}
}
func TestGetTradeBalance(t *testing.T) {
t.Parallel()
_, err := k.GetTradeBalance("", "")
if err == nil {
t.Error("Test Failed - GetTradeBalance() error", err)
}
}
func TestGetOpenOrders(t *testing.T) {
t.Parallel()
_, err := k.GetOpenOrders(true, 0)
if err == nil {
t.Error("Test Failed - GetOpenOrders() error", err)
}
}
func TestGetClosedOrders(t *testing.T) {
t.Parallel()
_, err := k.GetClosedOrders(true, 0, 0, 0, 0, "")
if err == nil {
t.Error("Test Failed - GetClosedOrders() error", err)
}
}
func TestQueryOrdersInfo(t *testing.T) {
t.Parallel()
_, err := k.QueryOrdersInfo(false, 0, 0)
if err == nil {
t.Error("Test Failed - QueryOrdersInfo() error", err)
}
}
func TestGetTradesHistory(t *testing.T) {
t.Parallel()
_, err := k.GetTradesHistory("", false, 0, 0, 0)
if err == nil {
t.Error("Test Failed - GetTradesHistory() error", err)
}
}
func TestQueryTrades(t *testing.T) {
t.Parallel()
_, err := k.QueryTrades(0, false)
if err == nil {
t.Error("Test Failed - QueryTrades() error", err)
}
}
func TestOpenPositions(t *testing.T) {
t.Parallel()
_, err := k.OpenPositions(0, false)
if err == nil {
t.Error("Test Failed - OpenPositions() error", err)
}
}
func TestGetLedgers(t *testing.T) {
t.Parallel()
_, err := k.GetLedgers("bla", "bla", "bla", 0, 0, 0)
if err == nil {
t.Error("Test Failed - GetLedgers() error", err)
}
}
func TestQueryLedgers(t *testing.T) {
t.Parallel()
_, err := k.QueryLedgers("1337")
if err == nil {
t.Error("Test Failed - QueryLedgers() error", err)
}
}
func TestGetTradeVolume(t *testing.T) {
t.Parallel()
_, err := k.GetTradeVolume("BCHEUR")
if err == nil {
t.Error("Test Failed - GetTradeVolume() error", err)
}
}
func TestAddOrder(t *testing.T) {
t.Parallel()
_, err := k.AddOrder("bla", "bla", "bla", 0, 0, 0, 0, 0)
if err == nil {
t.Error("Test Failed - AddOrder() error", err)
}
}
func TestCancelOrder(t *testing.T) {
t.Parallel()
_, err := k.CancelOrder(1337)
if err == nil {
t.Error("Test Failed - CancelOrder() error", err)
}
}

View File

@@ -1,6 +1,13 @@
package kraken
type KrakenAssetPairs struct {
// GeneralResponse is a generalized response type
type GeneralResponse struct {
Result map[string]interface{} `json:"result"`
Error []interface{} `json:"error"`
}
// AssetPairs holds asset pair information
type AssetPairs struct {
Altname string `json:"altname"`
AclassBase string `json:"aclass_base"`
Base string `json:"base"`
@@ -19,7 +26,8 @@ type KrakenAssetPairs struct {
MarginStop int `json:"margin_stop"`
}
type KrakenTicker struct {
// Ticker is a standard ticker type
type Ticker struct {
Ask float64
Bid float64
Last float64
@@ -31,6 +39,41 @@ type KrakenTicker struct {
Open float64
}
// TickerResponse holds ticker information before its put into the Ticker struct
type TickerResponse struct {
Ask []string `json:"a"`
Bid []string `json:"b"`
Last []string `json:"c"`
Volume []string `json:"v"`
VWAP []string `json:"p"`
Trades []int64 `json:"t"`
Low []string `json:"l"`
High []string `json:"h"`
Open string `json:"o"`
}
// OpenHighLowClose contains ticker event information
type OpenHighLowClose struct {
Time float64
Open float64
High float64
Low float64
Close float64
Vwap float64
Volume float64
Count float64
}
// RecentTrades holds recent trade data
type RecentTrades struct {
Price float64
Volume float64
Time float64
BuyOrSell string
MarketOrLimit string
Miscellaneous interface{}
}
// OrderbookBase stores the orderbook price and amount data
type OrderbookBase struct {
Price float64
@@ -43,14 +86,9 @@ type Orderbook struct {
Asks []OrderbookBase
}
type KrakenTickerResponse struct {
Ask []string `json:"a"`
Bid []string `json:"b"`
Last []string `json:"c"`
Volume []string `json:"v"`
VWAP []string `json:"p"`
Trades []int64 `json:"t"`
Low []string `json:"l"`
High []string `json:"h"`
Open string `json:"o"`
// Spread holds the spread between trades
type Spread struct {
Time float64
Bid float64
Ask float64
}

View File

@@ -1,8 +1,12 @@
package kraken
import (
"fmt"
"log"
"net/url"
"strconv"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
@@ -44,7 +48,7 @@ func (k *Kraken) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Pri
if err != nil {
return tickerPrice, err
}
err = k.GetTicker(pairsCollated.String())
err = k.SetTicker(pairsCollated.String())
if err != nil {
return tickerPrice, err
}
@@ -68,6 +72,44 @@ func (k *Kraken) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Pri
return ticker.GetTicker(k.GetName(), p, assetType)
}
// SetTicker sets ticker information from kraken
func (k *Kraken) SetTicker(symbol string) error {
values := url.Values{}
values.Set("pair", symbol)
type Response struct {
Error []interface{} `json:"error"`
Data map[string]TickerResponse `json:"result"`
}
resp := Response{}
path := fmt.Sprintf("%s/%s/public/%s?%s", krakenAPIURL, krakenAPIVersion, krakenTicker, values.Encode())
err := common.SendHTTPGetRequest(path, true, k.Verbose, &resp)
if err != nil {
return err
}
if len(resp.Error) > 0 {
return fmt.Errorf("Kraken error: %s", resp.Error)
}
for x, y := range resp.Data {
ticker := Ticker{}
ticker.Ask, _ = strconv.ParseFloat(y.Ask[0], 64)
ticker.Bid, _ = strconv.ParseFloat(y.Bid[0], 64)
ticker.Last, _ = strconv.ParseFloat(y.Last[0], 64)
ticker.Volume, _ = strconv.ParseFloat(y.Volume[1], 64)
ticker.VWAP, _ = strconv.ParseFloat(y.VWAP[1], 64)
ticker.Trades = y.Trades[1]
ticker.Low, _ = strconv.ParseFloat(y.Low[1], 64)
ticker.High, _ = strconv.ParseFloat(y.High[1], 64)
ticker.Open, _ = strconv.ParseFloat(y.Open, 64)
k.Ticker[x] = ticker
}
return nil
}
// GetTickerPrice returns the ticker for a currency pair
func (k *Kraken) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
tickerNew, err := ticker.GetTicker(k.GetName(), p, assetType)

View File

@@ -15,26 +15,28 @@ import (
)
const (
LAKEBTC_API_URL = "https://api.lakebtc.com/api_v2"
LAKEBTC_API_VERSION = "2"
LAKEBTC_TICKER = "ticker"
LAKEBTC_ORDERBOOK = "bcorderbook"
LAKEBTC_TRADES = "bctrades"
LAKEBTC_GET_ACCOUNT_INFO = "getAccountInfo"
LAKEBTC_BUY_ORDER = "buyOrder"
LAKEBTC_SELL_ORDER = "sellOrder"
LAKEBTC_OPEN_ORDERS = "openOrders"
LAKEBTC_GET_ORDERS = "getOrders"
LAKEBTC_CANCEL_ORDER = "cancelOrder"
LAKEBTC_GET_TRADES = "getTrades"
LAKEBTC_GET_EXTERNAL_ACCOUNTS = "getExternalAccounts"
LAKEBTC_CREATE_WITHDRAW = "createWithdraw"
lakeBTCAPIURL = "https://api.lakebtc.com/api_v2"
lakeBTCAPIVersion = "2"
lakeBTCTicker = "ticker"
lakeBTCOrderbook = "bcorderbook"
lakeBTCTrades = "bctrades"
lakeBTCGetAccountInfo = "getAccountInfo"
lakeBTCBuyOrder = "buyOrder"
lakeBTCSellOrder = "sellOrder"
lakeBTCOpenOrders = "openOrders"
lakeBTCGetOrders = "getOrders"
lakeBTCCancelOrder = "cancelOrder"
lakeBTCGetTrades = "getTrades"
lakeBTCGetExternalAccounts = "getExternalAccounts"
lakeBTCCreateWithdraw = "createWithdraw"
)
// LakeBTC is the overarching type across the LakeBTC package
type LakeBTC struct {
exchange.Base
}
// SetDefaults sets LakeBTC defaults
func (l *LakeBTC) SetDefaults() {
l.Name = "LakeBTC"
l.Enabled = false
@@ -50,6 +52,7 @@ func (l *LakeBTC) SetDefaults() {
l.AssetTypes = []string{ticker.Spot}
}
// Setup sets exchange configuration profile
func (l *LakeBTC) Setup(exch config.ExchangeConfig) {
if !exch.Enabled {
l.SetEnabled(false)
@@ -74,26 +77,28 @@ func (l *LakeBTC) Setup(exch config.ExchangeConfig) {
}
}
// GetFee returns maker or taker fee
func (l *LakeBTC) GetFee(maker bool) float64 {
if maker {
return l.MakerFee
} else {
return l.TakerFee
}
return l.TakerFee
}
func (l *LakeBTC) GetTicker() (map[string]LakeBTCTicker, error) {
response := make(map[string]LakeBTCTickerResponse)
path := fmt.Sprintf("%s/%s", LAKEBTC_API_URL, LAKEBTC_TICKER)
err := common.SendHTTPGetRequest(path, true, l.Verbose, &response)
if err != nil {
// GetTicker returns the current ticker from lakeBTC
func (l *LakeBTC) GetTicker() (map[string]Ticker, error) {
response := make(map[string]TickerResponse)
path := fmt.Sprintf("%s/%s", lakeBTCAPIURL, lakeBTCTicker)
if err := common.SendHTTPGetRequest(path, true, l.Verbose, &response); err != nil {
return nil, err
}
result := make(map[string]LakeBTCTicker)
result := make(map[string]Ticker)
var addresses []string
for k, v := range response {
var ticker LakeBTCTicker
var ticker Ticker
key := common.StringToUpper(k)
if v.Ask != nil {
ticker.Ask, _ = strconv.ParseFloat(v.Ask.(string), 64)
@@ -119,18 +124,19 @@ func (l *LakeBTC) GetTicker() (map[string]LakeBTCTicker, error) {
return result, nil
}
func (l *LakeBTC) GetOrderBook(currency string) (LakeBTCOrderbook, error) {
// GetOrderBook returns the order book from LakeBTC
func (l *LakeBTC) GetOrderBook(currency string) (Orderbook, error) {
type Response struct {
Bids [][]string `json:"bids"`
Asks [][]string `json:"asks"`
}
path := fmt.Sprintf("%s/%s?symbol=%s", LAKEBTC_API_URL, LAKEBTC_ORDERBOOK, common.StringToLower(currency))
path := fmt.Sprintf("%s/%s?symbol=%s", lakeBTCAPIURL, lakeBTCOrderbook, common.StringToLower(currency))
resp := Response{}
err := common.SendHTTPGetRequest(path, true, l.Verbose, &resp)
if err != nil {
return LakeBTCOrderbook{}, err
return Orderbook{}, err
}
orderbook := LakeBTCOrderbook{}
orderbook := Orderbook{}
for _, x := range resp.Bids {
price, err := strconv.ParseFloat(x[0], 64)
@@ -143,7 +149,7 @@ func (l *LakeBTC) GetOrderBook(currency string) (LakeBTCOrderbook, error) {
log.Println(err)
continue
}
orderbook.Bids = append(orderbook.Bids, LakeBTCOrderbookStructure{price, amount})
orderbook.Bids = append(orderbook.Bids, OrderbookStructure{price, amount})
}
for _, x := range resp.Asks {
@@ -157,45 +163,40 @@ func (l *LakeBTC) GetOrderBook(currency string) (LakeBTCOrderbook, error) {
log.Println(err)
continue
}
orderbook.Asks = append(orderbook.Asks, LakeBTCOrderbookStructure{price, amount})
orderbook.Asks = append(orderbook.Asks, OrderbookStructure{price, amount})
}
return orderbook, nil
}
func (l *LakeBTC) GetTradeHistory(currency string) ([]LakeBTCTradeHistory, error) {
path := fmt.Sprintf("%s/%s?symbol=%s", LAKEBTC_API_URL, LAKEBTC_TRADES, common.StringToLower(currency))
resp := []LakeBTCTradeHistory{}
err := common.SendHTTPGetRequest(path, true, l.Verbose, &resp)
if err != nil {
return nil, err
}
return resp, nil
// GetTradeHistory returns the trade history for a given currency pair
func (l *LakeBTC) GetTradeHistory(currency string) ([]TradeHistory, error) {
path := fmt.Sprintf("%s/%s?symbol=%s", lakeBTCAPIURL, lakeBTCTrades, common.StringToLower(currency))
resp := []TradeHistory{}
return resp, common.SendHTTPGetRequest(path, true, l.Verbose, &resp)
}
func (l *LakeBTC) GetAccountInfo() (LakeBTCAccountInfo, error) {
resp := LakeBTCAccountInfo{}
err := l.SendAuthenticatedHTTPRequest(LAKEBTC_GET_ACCOUNT_INFO, "", &resp)
// GetAccountInfo returns your current account information
func (l *LakeBTC) GetAccountInfo() (AccountInfo, error) {
resp := AccountInfo{}
if err != nil {
return resp, err
}
return resp, nil
return resp, l.SendAuthenticatedHTTPRequest(lakeBTCGetAccountInfo, "", &resp)
}
func (l *LakeBTC) Trade(orderType int, amount, price float64, currency string) (LakeBTCTrade, error) {
resp := LakeBTCTrade{}
// Trade executes an order on the exchange and returns trade inforamtion or an
// error
func (l *LakeBTC) Trade(orderType int, amount, price float64, currency string) (Trade, error) {
resp := Trade{}
params := strconv.FormatFloat(price, 'f', -1, 64) + "," + strconv.FormatFloat(amount, 'f', -1, 64) + "," + currency
err := errors.New("")
if orderType == 1 {
err = l.SendAuthenticatedHTTPRequest(LAKEBTC_BUY_ORDER, params, &resp)
if err := l.SendAuthenticatedHTTPRequest(lakeBTCBuyOrder, params, &resp); err != nil {
return resp, err
}
} else {
err = l.SendAuthenticatedHTTPRequest(LAKEBTC_SELL_ORDER, params, &resp)
}
if err != nil {
return resp, err
if err := l.SendAuthenticatedHTTPRequest(lakeBTCSellOrder, params, &resp); err != nil {
return resp, err
}
}
if resp.Result != "order received" {
@@ -205,31 +206,26 @@ func (l *LakeBTC) Trade(orderType int, amount, price float64, currency string) (
return resp, nil
}
func (l *LakeBTC) GetOpenOrders() ([]LakeBTCOpenOrders, error) {
orders := []LakeBTCOpenOrders{}
err := l.SendAuthenticatedHTTPRequest(LAKEBTC_OPEN_ORDERS, "", &orders)
// GetOpenOrders returns all open orders associated with your account
func (l *LakeBTC) GetOpenOrders() ([]OpenOrders, error) {
orders := []OpenOrders{}
if err != nil {
return nil, err
}
return orders, nil
return orders, l.SendAuthenticatedHTTPRequest(lakeBTCOpenOrders, "", &orders)
}
func (l *LakeBTC) GetOrders(orders []int64) ([]LakeBTCOrders, error) {
// GetOrders returns your orders
func (l *LakeBTC) GetOrders(orders []int64) ([]Orders, error) {
var ordersStr []string
for _, x := range orders {
ordersStr = append(ordersStr, strconv.FormatInt(x, 10))
}
resp := []LakeBTCOrders{}
err := l.SendAuthenticatedHTTPRequest(LAKEBTC_GET_ORDERS, common.JoinStrings(ordersStr, ","), &resp)
if err != nil {
return nil, err
}
return resp, nil
resp := []Orders{}
return resp,
l.SendAuthenticatedHTTPRequest(lakeBTCGetOrders, common.JoinStrings(ordersStr, ","), &resp)
}
// CancelOrder cancels an order by ID number and returns an error
func (l *LakeBTC) CancelOrder(orderID int64) error {
type Response struct {
Result bool `json:"Result"`
@@ -237,54 +233,45 @@ func (l *LakeBTC) CancelOrder(orderID int64) error {
resp := Response{}
params := strconv.FormatInt(orderID, 10)
err := l.SendAuthenticatedHTTPRequest(LAKEBTC_CANCEL_ORDER, params, &resp)
err := l.SendAuthenticatedHTTPRequest(lakeBTCCancelOrder, params, &resp)
if err != nil {
return err
}
if resp.Result != true {
return errors.New("Unable to cancel order.")
return errors.New("unable to cancel order")
}
return nil
}
func (l *LakeBTC) GetTrades(timestamp int64) ([]LakeBTCAuthenticaltedTradeHistory, error) {
// GetTrades returns trades associated with your account by timestamp
func (l *LakeBTC) GetTrades(timestamp int64) ([]AuthenticatedTradeHistory, error) {
params := ""
if timestamp != 0 {
params = strconv.FormatInt(timestamp, 10)
}
trades := []LakeBTCAuthenticaltedTradeHistory{}
err := l.SendAuthenticatedHTTPRequest(LAKEBTC_GET_TRADES, params, &trades)
if err != nil {
return nil, err
}
return trades, nil
trades := []AuthenticatedTradeHistory{}
return trades, l.SendAuthenticatedHTTPRequest(lakeBTCGetTrades, params, &trades)
}
/* Only for BTC */
func (l *LakeBTC) GetExternalAccounts() ([]LakeBTCExternalAccounts, error) {
resp := []LakeBTCExternalAccounts{}
err := l.SendAuthenticatedHTTPRequest(LAKEBTC_GET_EXTERNAL_ACCOUNTS, "", &resp)
if err != nil {
return resp, err
}
return resp, nil
// GetExternalAccounts returns your external accounts WARNING: Only for BTC!
func (l *LakeBTC) GetExternalAccounts() ([]ExternalAccounts, error) {
resp := []ExternalAccounts{}
return resp, l.SendAuthenticatedHTTPRequest(lakeBTCGetExternalAccounts, "", &resp)
}
/* Only for BTC */
func (l *LakeBTC) CreateWithdraw(amount float64, accountID int64) (LakeBTCWithdraw, error) {
resp := LakeBTCWithdraw{}
// CreateWithdraw allows your to withdraw to external account WARNING: Only for
// BTC!
func (l *LakeBTC) CreateWithdraw(amount float64, accountID int64) (Withdraw, error) {
resp := Withdraw{}
params := strconv.FormatFloat(amount, 'f', -1, 64) + ",btc," + strconv.FormatInt(accountID, 10)
err := l.SendAuthenticatedHTTPRequest(LAKEBTC_CREATE_WITHDRAW, params, &resp)
if err != nil {
return resp, err
}
return resp, nil
return resp, l.SendAuthenticatedHTTPRequest(lakeBTCCreateWithdraw, params, &resp)
}
// SendAuthenticatedHTTPRequest sends an autheticated HTTP request to a LakeBTC
func (l *LakeBTC) SendAuthenticatedHTTPRequest(method, params string, result interface{}) (err error) {
if !l.AuthenticatedAPISupport {
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, l.Name)
@@ -300,7 +287,7 @@ func (l *LakeBTC) SendAuthenticatedHTTPRequest(method, params string, result int
hmac := common.GetHMAC(common.HashSHA1, []byte(req), []byte(l.APISecret))
if l.Verbose {
log.Printf("Sending POST request to %s calling method %s with params %s\n", LAKEBTC_API_URL, method, req)
log.Printf("Sending POST request to %s calling method %s with params %s\n", lakeBTCAPIURL, method, req)
}
postData := make(map[string]interface{})
@@ -318,7 +305,7 @@ func (l *LakeBTC) SendAuthenticatedHTTPRequest(method, params string, result int
headers["Authorization"] = "Basic " + common.Base64Encode([]byte(l.APIKey+":"+common.HexEncodeToString(hmac)))
headers["Content-Type"] = "application/json-rpc"
resp, err := common.SendHTTPRequest("POST", LAKEBTC_API_URL, headers, strings.NewReader(string(data)))
resp, err := common.SendHTTPRequest("POST", lakeBTCAPIURL, headers, strings.NewReader(string(data)))
if err != nil {
return err
}
@@ -342,10 +329,8 @@ func (l *LakeBTC) SendAuthenticatedHTTPRequest(method, params string, result int
}
err = common.JSONDecode([]byte(resp), &result)
if err != nil {
return errors.New("unable to JSON Unmarshal response")
}
return nil
}

View File

@@ -0,0 +1,124 @@
package lakebtc
import (
"testing"
"github.com/thrasher-/gocryptotrader/config"
)
var l LakeBTC
// Please add your own APIkeys to do correct due diligence testing.
const (
apiKey = ""
apiSecret = ""
)
func TestSetDefaults(t *testing.T) {
l.SetDefaults()
}
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
lakebtcConfig, err := cfg.GetExchangeConfig("LakeBTC")
if err != nil {
t.Error("Test Failed - LakeBTC Setup() init error")
}
lakebtcConfig.AuthenticatedAPISupport = true
lakebtcConfig.APIKey = apiKey
lakebtcConfig.APISecret = apiSecret
l.Setup(lakebtcConfig)
}
func TestGetFee(t *testing.T) {
t.Parallel()
if l.GetFee(false) != 0.2 {
t.Error("Test Failed - GetFee() error")
}
if l.GetFee(true) != 0.15 {
t.Error("Test Failed - GetFee() error")
}
}
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := l.GetTicker()
if err != nil {
t.Error("Test Failed - GetTicker() error", err)
}
}
func TestGetOrderBook(t *testing.T) {
t.Parallel()
_, err := l.GetOrderBook("BTCUSD")
if err != nil {
t.Error("Test Failed - GetOrderBook() error", err)
}
}
func TestGetTradeHistory(t *testing.T) {
t.Parallel()
_, err := l.GetTradeHistory("BTCUSD")
if err != nil {
t.Error("Test Failed - GetTradeHistory() error", err)
}
}
func TestTrade(t *testing.T) {
t.Parallel()
_, err := l.Trade(0, 0, 0, "USD")
if err == nil {
t.Error("Test Failed - Trade() error", err)
}
}
func TestGetOpenOrders(t *testing.T) {
t.Parallel()
_, err := l.GetOpenOrders()
if err == nil {
t.Error("Test Failed - GetOpenOrders() error", err)
}
}
func TestGetOrders(t *testing.T) {
t.Parallel()
_, err := l.GetOrders([]int64{1, 2})
if err == nil {
t.Error("Test Failed - GetOrders() error", err)
}
}
func TestCancelOrder(t *testing.T) {
t.Parallel()
err := l.CancelOrder(1337)
if err == nil {
t.Error("Test Failed - CancelOrder() error", err)
}
}
func TestGetTrades(t *testing.T) {
t.Parallel()
_, err := l.GetTrades(1337)
if err == nil {
t.Error("Test Failed - GetTrades() error", err)
}
}
func TestGetExternalAccounts(t *testing.T) {
t.Parallel()
_, err := l.GetExternalAccounts()
if err == nil {
t.Error("Test Failed - GetExternalAccounts() error", err)
}
}
func TestCreateWithdraw(t *testing.T) {
t.Parallel()
_, err := l.CreateWithdraw(0, 1337)
if err == nil {
t.Error("Test Failed - CreateWithdraw() error", err)
}
}

View File

@@ -1,6 +1,7 @@
package lakebtc
type LakeBTCTicker struct {
// Ticker holds ticker information
type Ticker struct {
Last float64
Bid float64
Ask float64
@@ -9,18 +10,21 @@ type LakeBTCTicker struct {
Volume float64
}
type LakeBTCOrderbookStructure struct {
// OrderbookStructure stores price and amount for order books
type OrderbookStructure struct {
Price float64
Amount float64
}
type LakeBTCOrderbook struct {
Bids []LakeBTCOrderbookStructure `json:"bids"`
Asks []LakeBTCOrderbookStructure `json:"asks"`
// Orderbook contains arrays of orderbook information
type Orderbook struct {
Bids []OrderbookStructure `json:"bids"`
Asks []OrderbookStructure `json:"asks"`
}
/* Silly hack due to API returning null instead of strings */
type LakeBTCTickerResponse struct {
// TickerResponse stores temp response
// Silly hack due to API returning null instead of strings
type TickerResponse struct {
Last interface{}
Bid interface{}
Ask interface{}
@@ -29,14 +33,16 @@ type LakeBTCTickerResponse struct {
Volume interface{}
}
type LakeBTCTradeHistory struct {
// TradeHistory holds trade history data
type TradeHistory struct {
Date int64 `json:"data"`
Price float64 `json:"price,string"`
Amount float64 `json:"amount,string"`
TID int64 `json:"tid"`
}
type LakeBTCAccountInfo struct {
// AccountInfo contains account information
type AccountInfo struct {
Balance map[string]string `json:"balance"`
Locked map[string]string `json:"locked"`
Profile struct {
@@ -46,12 +52,14 @@ type LakeBTCAccountInfo struct {
} `json:"profile"`
}
type LakeBTCTrade struct {
// Trade holds trade information
type Trade struct {
ID int64 `json:"id"`
Result string `json:"result"`
}
type LakeBTCOpenOrders struct {
// OpenOrders stores full information on your open orders
type OpenOrders struct {
ID int64 `json:"id"`
Amount float64 `json:"amount,string"`
Price float64 `json:"price,string"`
@@ -60,7 +68,8 @@ type LakeBTCOpenOrders struct {
At int64 `json:"at"`
}
type LakeBTCOrders struct {
// Orders holds current order information
type Orders struct {
ID int64 `json:"id"`
OriginalAmount float64 `json:"original_amount,string"`
Amount float64 `json:"amount,string"`
@@ -71,14 +80,17 @@ type LakeBTCOrders struct {
At int64 `json:"at"`
}
type LakeBTCAuthenticaltedTradeHistory struct {
// AuthenticatedTradeHistory is a store of personalised auth trade history
type AuthenticatedTradeHistory struct {
Type string `json:"type"`
Symbol string `json:"symbol"`
Amount float64 `json:"amount,string"`
Total float64 `json:"total,string"`
At int64 `json:"at"`
}
type LakeBTCExternalAccounts struct {
// ExternalAccounts holds external account information
type ExternalAccounts struct {
ID int64 `json:"id,string"`
Type string `json:"type"`
Address string `json:"address"`
@@ -88,7 +100,8 @@ type LakeBTCExternalAccounts struct {
UpdatedAt int64 `json:"updated_at,string"`
}
type LakeBTCWithdraw struct {
// Withdraw holds withdrawal information
type Withdraw struct {
ID int64 `json:"id,string"`
Amount float64 `json:"amount,string"`
Currency string `json:"currency"`

View File

@@ -20,7 +20,7 @@ func TestSetDefaults(t *testing.T) {
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.dat")
cfg.LoadConfig("../../testdata/configtest.json")
liquiConfig, err := cfg.GetExchangeConfig("Liqui")
if err != nil {
t.Error("Test Failed - liqui Setup() init error")

View File

@@ -12,26 +12,101 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
)
const (
LOCALBITCOINS_API_URL = "https://localbitcoins.com"
LOCALBITCOINS_API_TICKER = "/bitcoinaverage/ticker-all-currencies/"
LOCALBITCOINS_API_BITCOINCHARTS = "/bitcoincharts/"
LOCALBITCOINS_API_PINCODE = "pincode/"
LOCALBITCOINS_API_WALLET = "wallet/"
LOCALBITCOINS_API_MYSELF = "myself/"
LOCALBITCOINS_API_WALLET_BALANCE = "wallet-balance/"
LOCALBITCOINS_API_WALLET_SEND = "wallet-send/"
LOCALBITCOINS_API_WALLET_SEND_PIN = "wallet-send-pin/"
LOCALBITCOINS_API_WALLET_ADDRESS = "wallet-addr/"
localbitcoinsAPIURL = "https://localbitcoins.com"
// Autheticated Calls
localbitcoinsAPIAccountInfo = "api/account_info"
localbitcoinsAPIMyself = "myself/"
localbitcoinsAPIAds = "ads/"
localbitcoinsAPIAdGet = "ad-get/"
localbitcoinsAPIAdEdit = "ad/"
localbitcoinsAPIAdCreate = "ad-create/"
localbitcoinsAPIUpdateEquation = "ad-equation/"
localbitcoinsAPIDeleteAd = "ad-delete/"
localbitcoinsAPIRelease = "contact_release/"
localbitcoinsAPIReleaseByPin = "contact_release_pin/"
localbitcoinsAPIMarkAsPaid = "contact_mark_as_paid/"
localbitcoinsAPIMessages = "contact_messages/"
localbitcoinsAPISendMessage = "contact_message_post/"
localbitcoinsAPIDispute = "contact_dispute/"
localbitcoinsAPICancelTrade = "contact_cancel/"
localbitcoinsAPIFundTrade = "contact_fund/"
localbitcoinsAPIConfirmRealName = "contact_mark_realname/"
localbitcoinsAPIVerifyIdentity = "contact_mark_identified/"
localbitcoinsAPIInitiateTrade = "contact_create/"
localbitcoinsAPITradeInfo = "contact_info/"
localbitcoinsAPIDashboard = "dashboard/"
localbitcoinsAPIDashboardReleased = "dashboard/released/"
localbitcoinsAPIDashboardCancelled = "dashboard/canceled/"
localbitcoinsAPIDashboardClosed = "dashboard/closed/"
localbitcoinsAPIFeedback = "feedback/"
localbitcoinsAPILogout = "logout/"
localbitcoinsAPICreateInvoice = "merchant/new_invoice/"
localbitcoinsAPIGetNotification = "notifications/"
localbitcoinsAPIMarkNotification = "notifications/mark_as_read/"
localbitcoinsAPIPinCode = "pincode/"
localbitcoinsAPIVerifyUsername = "real_name_verifiers/"
localbitcoinsAPIWallet = "wallet/"
localbitcoinsAPIWalletBalance = "wallet-balance/"
localbitcoinsAPIWalletSend = "wallet-send/"
localbitcoinsAPIWalletSendPin = "wallet-send-pin/"
localbitcoinsAPIWalletAddress = "wallet-addr/"
// Un-Autheticated Calls
localbitcoinsAPICountryCodes = "/api/countrycodes/"
localbitcoinsAPICurrencies = "/api/currencies/"
localbitcoinsAPIPaymentMethods = "/api/payment_methods/"
localbitcoinsAPIPlaces = "/api/places/"
localbitcoinsAPITicker = "/bitcoinaverage/ticker-all-currencies/"
localbitcoinsAPIBitcoincharts = "/bitcoincharts/"
localbitcoinsAPICashBuy = "/buy-bitcoins-with-cash/"
localbitcoinsAPIOnlineBuy = "/buy-bitcoins-online/"
// Trade Types
tradeTypeLocalSell = "LOCAL_SELL"
tradeTypeLocalBuy = "LOCAL_BUY"
tradeTypeOnlineSell = "ONLINE_SELL"
tradeTypeOnlineBuy = "ONLINE_BUY"
// Reference Types
refTypeShort = "SHORT"
refTypeLong = "LONG"
refTypeNumbers = "NUMBERS"
refTypeLetters = "LETTERS"
// Feedback Values
feedbackTrust = "trust"
feedbackPositive = "positive"
feedbackNeutral = "neutral"
feedbackBlock = "block"
feedbackBlockWithoutFeedback = "block_without_feedback"
// State Values
stateNotOpened = "NOT_OPENED"
stateWaitingForPayment = "WAITING_FOR_PAYMENT"
statePaid = "PAID"
stateNotPaid = "DIDNT_PAID"
statePaidLate = "PAID_IN_LATE"
statePartlyPaid = "PAID_PARTLY"
statePaidAndConfirmed = "PAID_AND_CONFIRMED"
statePaidLateConfirmed = "PAID_IN_LATE_AND_CONFIRMED"
statePaidPartlyConfirmed = "PAID_PARTLY_AND_CONFIRMED"
)
var (
// Payment Methods
paymentMethodOne string
)
// LocalBitcoins is the overarching type across the localbitcoins package
type LocalBitcoins struct {
exchange.Base
}
// SetDefaults sets the package defaults for localbitcoins
func (l *LocalBitcoins) SetDefaults() {
l.Name = "LocalBitcoins"
l.Enabled = false
@@ -43,9 +118,9 @@ func (l *LocalBitcoins) SetDefaults() {
l.RequestCurrencyPairFormat.Uppercase = true
l.ConfigCurrencyPairFormat.Delimiter = ""
l.ConfigCurrencyPairFormat.Uppercase = true
l.AssetTypes = []string{ticker.Spot}
}
// Setup sets exchange configuration parameters
func (l *LocalBitcoins) Setup(exch config.ExchangeConfig) {
if !exch.Enabled {
l.SetEnabled(false)
@@ -63,107 +138,34 @@ func (l *LocalBitcoins) Setup(exch config.ExchangeConfig) {
if err != nil {
log.Fatal(err)
}
err = l.SetAssetTypes()
if err != nil {
log.Fatal(err)
}
}
}
// GetFee returns the fee for maker or taker
func (l *LocalBitcoins) GetFee(maker bool) float64 {
if maker {
return l.MakerFee
} else {
return l.TakerFee
}
return l.TakerFee
}
func (l *LocalBitcoins) GetTicker() (map[string]LocalBitcoinsTicker, error) {
result := make(map[string]LocalBitcoinsTicker)
err := common.SendHTTPGetRequest(LOCALBITCOINS_API_URL+LOCALBITCOINS_API_TICKER, true, l.Verbose, &result)
if err != nil {
return result, err
}
return result, nil
}
func (l *LocalBitcoins) GetTrades(currency string, values url.Values) ([]LocalBitcoinsTrade, error) {
path := common.EncodeURLValues(fmt.Sprintf("%s/%s/trades.json", LOCALBITCOINS_API_URL+LOCALBITCOINS_API_BITCOINCHARTS, currency), values)
result := []LocalBitcoinsTrade{}
err := common.SendHTTPGetRequest(path, true, l.Verbose, &result)
if err != nil {
return result, err
}
return result, nil
}
func (l *LocalBitcoins) GetOrderbook(currency string) (LocalBitcoinsOrderbook, error) {
// GetAccountInfo lets you retrieve the public user information on a
// LocalBitcoins user. The response contains the same information that is found
// on an account's public profile page.
func (l *LocalBitcoins) GetAccountInfo(username string, self bool) (AccountInfo, error) {
type response struct {
Bids [][]string `json:"bids"`
Asks [][]string `json:"asks"`
}
path := fmt.Sprintf("%s/%s/orderbook.json", LOCALBITCOINS_API_URL+LOCALBITCOINS_API_BITCOINCHARTS, currency)
resp := response{}
err := common.SendHTTPGetRequest(path, true, l.Verbose, &resp)
if err != nil {
return LocalBitcoinsOrderbook{}, err
}
orderbook := LocalBitcoinsOrderbook{}
for _, x := range resp.Bids {
price, err := strconv.ParseFloat(x[0], 64)
if err != nil {
log.Println(err)
continue
}
amount, err := strconv.ParseFloat(x[1], 64)
if err != nil {
log.Println(err)
continue
}
orderbook.Bids = append(orderbook.Bids, LocalBitcoinsOrderbookStructure{price, amount})
}
for _, x := range resp.Asks {
price, err := strconv.ParseFloat(x[0], 64)
if err != nil {
log.Println(err)
continue
}
amount, err := strconv.ParseFloat(x[1], 64)
if err != nil {
log.Println(err)
continue
}
orderbook.Asks = append(orderbook.Asks, LocalBitcoinsOrderbookStructure{price, amount})
}
return orderbook, nil
}
func (l *LocalBitcoins) GetAccountInfo(username string, self bool) (LocalBitcoinsAccountInfo, error) {
type response struct {
Data LocalBitcoinsAccountInfo `json:"data"`
Data AccountInfo `json:"data"`
}
resp := response{}
if self {
err := l.SendAuthenticatedHTTPRequest("GET", LOCALBITCOINS_API_MYSELF, nil, &resp)
err := l.SendAuthenticatedHTTPRequest("GET", localbitcoinsAPIMyself, nil, &resp)
if err != nil {
return resp.Data, err
}
} else {
path := fmt.Sprintf("%s/api/account_info/%s/", LOCALBITCOINS_API_URL, username)
path := fmt.Sprintf("%s/%s/%s/", localbitcoinsAPIURL, localbitcoinsAPIAccountInfo, username)
err := common.SendHTTPGetRequest(path, true, l.Verbose, &resp)
if err != nil {
return resp.Data, err
}
@@ -172,6 +174,269 @@ func (l *LocalBitcoins) GetAccountInfo(username string, self bool) (LocalBitcoin
return resp.Data, nil
}
// Getads returns information of single advertisement based on the ad ID, if
// adID ommited.
//
// adID - [optional] string if ommited returns all ads
func (l *LocalBitcoins) Getads(adID string) (AdData, error) {
type response struct {
Data AdData `json:"data"`
}
resp := response{}
if len(adID) > 0 {
return resp.Data,
l.SendAuthenticatedHTTPRequest("GET", localbitcoinsAPIAdGet+adID+"/", nil, &resp)
}
return resp.Data,
l.SendAuthenticatedHTTPRequest("GET", localbitcoinsAPIAds, nil, &resp)
}
// EditAd updates set advertisements
//
// params - see localbitcoins_types.go AdEdit for reference
// adID - string for the ad you already created
func (l *LocalBitcoins) EditAd(params AdEdit, adID string) error {
type response struct {
Data AdData `json:"data"`
}
resp := response{}
//request := make(map[string]interface{})
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIAdEdit+adID+"/", nil, &resp)
}
// CreateAd creates a new advertisement
//
// params - see localbitcoins_types.go AdCreate for reference
func (l *LocalBitcoins) CreateAd(params AdCreate) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIAdCreate, nil, nil)
}
// UpdatePriceEquation updates price equation of an advertisement. If there are
// problems with new equation, the price and equation are not updated and
// advertisement remains visible.
//
// equation - string of equation
// adID - string of specific ad identification
func (l *LocalBitcoins) UpdatePriceEquation(equation, adID string) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIUpdateEquation+adID, nil, nil)
}
// DeleteAd deletes the advertisement by adID.
//
// adID - string of specific ad identification
func (l *LocalBitcoins) DeleteAd(adID string) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIDeleteAd+adID, nil, nil)
}
// ReleaseFunds releases Bitcoin trades specified by ID {contact_id}. If the
// release was successful a message is returned on the data key.
func (l *LocalBitcoins) ReleaseFunds(contactID string) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIRelease+contactID, nil, nil)
}
// ReleaseFundsByPin releases Bitcoin trades specified by ID {contact_id}. if
// the current pincode is provided. If the release was successful a message is
// returned on the data key.
func (l *LocalBitcoins) ReleaseFundsByPin(pin int, contactID string) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIReleaseByPin+contactID, nil, nil)
}
// MarkAsPaid marks a trade as paid.
func (l *LocalBitcoins) MarkAsPaid(contactID string) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIMarkAsPaid+contactID, nil, nil)
}
// GetMessages returns all chat messages from the trade. Messages are on the message_list key.
func (l *LocalBitcoins) GetMessages(contactID string) (Message, error) {
type response struct {
MessageList Message `json:"message_list"`
}
resp := response{}
return resp.MessageList,
l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIMessages+contactID, nil, &resp)
}
// SendMessage posts a message and/or uploads an image to the trade. Encode
// images with multipart/form-data encoding.
func (l *LocalBitcoins) SendMessage(msg, contactID string) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPISendMessage+contactID, nil, nil)
}
// Dispute starts a dispute on the specified trade ID if the requirements for
// starting the dispute has been fulfilled.
//
// topic - [optional] String Short description of issue to LocalBitcoins customer support.
func (l *LocalBitcoins) Dispute(topic, contactID string) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIDispute+contactID, nil, nil)
}
// CancelTrade cancels the trade if the token owner is the Bitcoin buyer.
// Bitcoin sellers cannot cancel trades.
func (l *LocalBitcoins) CancelTrade(contactID string) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPICancelTrade+contactID, nil, nil)
}
// FundTrade attempts to fund an unfunded local trade from the token owners
// wallet. Works only if the token owner is the Bitcoin seller in the trade.
func (l *LocalBitcoins) FundTrade(contactID string) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIFundTrade+contactID, nil, nil)
}
// ConfirmRealName creates or updates real name confirmation.
func (l *LocalBitcoins) ConfirmRealName(contactID string) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIConfirmRealName+contactID, nil, nil)
}
// VerifyIdentity marks the identity of trade partner as verified. You must be
// the advertiser in this trade.
func (l *LocalBitcoins) VerifyIdentity(contactID string) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIVerifyIdentity+contactID, nil, nil)
}
// InitiateTrade sttempts to start a Bitcoin trade from the specified
// advertisement ID.
func (l *LocalBitcoins) InitiateTrade(amount int, message, adID string) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIInitiateTrade+adID, nil, nil)
}
// GetTradeInfo returns information about a single trade that the token owner is
// part in.
func (l *LocalBitcoins) GetTradeInfo(contactID string) error {
return l.SendAuthenticatedHTTPRequest("GET", localbitcoinsAPITradeInfo+contactID, nil, nil)
}
// GetCountryCodes returns a list of valid and recognized countrycodes
func (l *LocalBitcoins) GetCountryCodes() error {
return common.SendHTTPGetRequest(localbitcoinsAPIURL+localbitcoinsAPICountryCodes, true, l.Verbose, nil)
}
// GetCurrencies returns a list of valid and recognized fiat currencies. Also
// contains human readable name for every currency and boolean that tells if
// currency is an altcoin.
func (l *LocalBitcoins) GetCurrencies() error {
return common.SendHTTPGetRequest(localbitcoinsAPIURL+localbitcoinsAPICurrencies, true, l.Verbose, nil)
}
// GetDashboardInfo returns a list of trades on the data key contact_list. This
// API end point mirrors the website's dashboard, allowing access to contacts in
// different states.
// In addition all of these listings have buyer/ and seller/ sub-listings to
// view contacts where the token owner is either buying or selling, respectively.
// E.g. /api/dashboard/buyer/. All contacts where the token owner is
// participating are returned.
func (l *LocalBitcoins) GetDashboardInfo() (DashBoardInfo, error) {
resp := DashBoardInfo{}
return resp,
l.SendAuthenticatedHTTPRequest("GET", localbitcoinsAPIDashboard, nil, &resp)
}
// GetDashboardReleasedTrades returns a list of all released trades where the
// token owner is either a buyer or seller.
func (l *LocalBitcoins) GetDashboardReleasedTrades() (DashBoardInfo, error) {
resp := DashBoardInfo{}
return resp,
l.SendAuthenticatedHTTPRequest("GET", localbitcoinsAPIDashboardReleased, nil, &resp)
}
// GetDashboardCancelledTrades returns a list of all canceled trades where the
// token owner is either a buyer or seller.
func (l *LocalBitcoins) GetDashboardCancelledTrades() (DashBoardInfo, error) {
resp := DashBoardInfo{}
return resp,
l.SendAuthenticatedHTTPRequest("GET", localbitcoinsAPIDashboardCancelled, nil, &resp)
}
// GetDashboardClosedTrades returns a list of all closed trades where the token
// owner is either a buyer or seller.
func (l *LocalBitcoins) GetDashboardClosedTrades() (DashBoardInfo, error) {
resp := DashBoardInfo{}
return resp,
l.SendAuthenticatedHTTPRequest("GET", localbitcoinsAPIDashboardClosed, nil, &resp)
}
// SetFeedback gives feedback to user. Possible feedback values are: trust,
// positive, neutral, block, block_without_feedback, (check const values)
// This is only possible to set if there is a trade between the token owner and
// the user specified in {username} that is canceled or released. You may also
// set feedback message using msg field with few exceptions. Feedback
// block_without_feedback clears the message and with block the message is
// mandatory.
//
// feedback - string (use const valuesfor feedback)
// msg - [optional] Feedback message displayed alongside feedback on receivers
// profile page.
// username - username of trade contact
func (l *LocalBitcoins) SetFeedback(msg, feedback, username string) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIFeedback, nil, nil)
}
// Logout expires the current access token immediately. To get a new token
// afterwards, public apps will need to re-authenticate, confidential apps can
// turn in a refresh token.
func (l *LocalBitcoins) Logout() error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPILogout, nil, nil)
}
// CreateNewInvoice creates a new invoice.
func (l *LocalBitcoins) CreateNewInvoice(currency, description, returnURL string, amount float64, internal bool) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPICreateInvoice, nil, nil)
}
// GetInvoice returns information about a specific invoice created by the token
// owner.
func (l *LocalBitcoins) GetInvoice(invoiceID string) (Invoice, error) {
resp := Invoice{}
return resp, l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPICreateInvoice, nil, &resp)
}
// DeleteInvoice deletes a specific invoice. Deleting invoices is possible when
// it is sure that receiver cannot accidentally pay the invoice at the same time
// as the merchant is deleting it. You can use the API request
// /api/merchant/invoice/{invoice_id}/ to check if deleting is possible.
func (l *LocalBitcoins) DeleteInvoice(invoiceID string) (Invoice, error) {
resp := Invoice{}
return resp, l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPICreateInvoice, nil, &resp)
}
// GetNotifications returns recent notifications.
func (l *LocalBitcoins) GetNotifications() ([]NotificationInfo, error) {
resp := []NotificationInfo{}
return resp, l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIGetNotification, nil, &resp)
}
// MarkNotifications marks a specific notification as read.
func (l *LocalBitcoins) MarkNotifications(notificationID string) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIMarkNotification, nil, nil)
}
// GetPaymentMethods returns a list of valid payment methods. Also contains name
// and code for payment methods, and possible limitations in currencies and bank
// name choices.
func (l *LocalBitcoins) GetPaymentMethods() error {
return common.SendHTTPGetRequest(localbitcoinsAPIURL+localbitcoinsAPIPaymentMethods, true, l.Verbose, nil)
}
// GetPaymentMethodsByCountry returns a list of valid payment methods filtered
// by countrycodes.
func (l *LocalBitcoins) GetPaymentMethodsByCountry(countryCode string) error {
return common.SendHTTPGetRequest(localbitcoinsAPIURL+localbitcoinsAPIPaymentMethods+countryCode, true, l.Verbose, nil)
}
// CheckPincode checks the given PIN code against the token owners currently
// active PIN code. You can use this method to ensure the person using the
// session is the legitimate user.
// Due to only requiring the read scope, the user is not guaranteed to have set
// a PIN code. If you protect your application using this request, please make
// the user has set a PIN code for his account.
func (l *LocalBitcoins) CheckPincode(pin int) (bool, error) {
type response struct {
Data struct {
@@ -181,64 +446,91 @@ func (l *LocalBitcoins) CheckPincode(pin int) (bool, error) {
resp := response{}
values := url.Values{}
values.Set("pincode", strconv.Itoa(pin))
err := l.SendAuthenticatedHTTPRequest("POST", LOCALBITCOINS_API_PINCODE, values, &resp)
err := l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIPinCode, values, &resp)
if err != nil {
return false, err
}
if !resp.Data.PinOK {
return false, errors.New("Pin invalid.")
return false, errors.New("pin invalid")
}
return true, nil
}
func (l *LocalBitcoins) GetWalletInfo() (LocalBitcoinsWalletInfo, error) {
// GetPlaces Looks up places near lat, lon and provides full URLs to buy and
// sell listings for each.
func (l *LocalBitcoins) GetPlaces(lat, lon int, location, countryCode string) error {
return common.SendHTTPGetRequest(localbitcoinsAPIURL+localbitcoinsAPIPlaces, true, l.Verbose, nil)
}
// VerifyUsername returns list of real name verifiers for the user. Returns a
// list only when you have a trade with the user where you are the seller.
func (l *LocalBitcoins) VerifyUsername() error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIVerifyUsername, nil, nil)
}
// GetRecentMessages returns maximum of 25 newest trade messages. Does not
// return messages older than one month. Messages are ordered by sending time,
// and the newest one is first.
func (l *LocalBitcoins) GetRecentMessages(after string) error {
return l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIVerifyUsername, nil, nil)
}
// GetWalletInfo gets information about the token owner's wallet balance.
func (l *LocalBitcoins) GetWalletInfo() (WalletInfo, error) {
type response struct {
Data LocalBitcoinsWalletInfo `json:"data"`
Data WalletInfo `json:"data"`
}
resp := response{}
err := l.SendAuthenticatedHTTPRequest("GET", LOCALBITCOINS_API_WALLET, nil, &resp)
err := l.SendAuthenticatedHTTPRequest("GET", localbitcoinsAPIWallet, nil, &resp)
if err != nil {
return LocalBitcoinsWalletInfo{}, err
return WalletInfo{}, err
}
if resp.Data.Message != "OK" {
return LocalBitcoinsWalletInfo{}, errors.New("Unable to fetch wallet info.")
return WalletInfo{}, errors.New("unable to fetch wallet info")
}
return resp.Data, nil
}
func (l *LocalBitcoins) GetWalletBalance() (LocalBitcoinsWalletBalanceInfo, error) {
// GetWalletBalance Same as GetWalletInfo(), but only returns the message,
// receiving_address and total fields.
// Use this instead if you don't care about transactions at the moment.
func (l *LocalBitcoins) GetWalletBalance() (WalletBalanceInfo, error) {
type response struct {
Data LocalBitcoinsWalletBalanceInfo `json:"data"`
Data WalletBalanceInfo `json:"data"`
}
resp := response{}
err := l.SendAuthenticatedHTTPRequest("GET", LOCALBITCOINS_API_WALLET_BALANCE, nil, &resp)
err := l.SendAuthenticatedHTTPRequest("GET", localbitcoinsAPIWalletBalance, nil, &resp)
if err != nil {
return LocalBitcoinsWalletBalanceInfo{}, err
return WalletBalanceInfo{}, err
}
if resp.Data.Message != "OK" {
return LocalBitcoinsWalletBalanceInfo{}, errors.New("Unable to fetch wallet balance.")
return WalletBalanceInfo{}, errors.New("unable to fetch wallet balance")
}
return resp.Data, nil
}
// WalletSend sends amount of bitcoins from the token owner's wallet to address.
// On success, the response returns a message indicating success. It is highly
// recommended to minimize the lifetime of access tokens with the money
// permission. Use Logout() to make the current token expire instantly.
func (l *LocalBitcoins) WalletSend(address string, amount float64, pin int) (bool, error) {
values := url.Values{}
values.Set("address", address)
values.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
path := LOCALBITCOINS_API_WALLET_SEND
path := localbitcoinsAPIWalletSend
if pin > 0 {
values.Set("pincode", strconv.Itoa(pin))
path = LOCALBITCOINS_API_WALLET_SEND_PIN
path = localbitcoinsAPIWalletSendPin
}
type response struct {
@@ -254,12 +546,15 @@ func (l *LocalBitcoins) WalletSend(address string, amount float64, pin int) (boo
}
if resp.Data.Message != "Money is being sent" {
return false, errors.New("Unable to send Bitcoins.")
return false, errors.New("unable to send Bitcoins")
}
return true, nil
}
// GetWalletAddress returns an unused receiving address from the token owner's
// wallet. The address is returned in the address key of the response. Note that
// this API may keep returning the same (unused) address if requested repeatedly.
func (l *LocalBitcoins) GetWalletAddress() (string, error) {
type response struct {
Data struct {
@@ -268,18 +563,98 @@ func (l *LocalBitcoins) GetWalletAddress() (string, error) {
}
}
resp := response{}
err := l.SendAuthenticatedHTTPRequest("POST", LOCALBITCOINS_API_WALLET_ADDRESS, nil, &resp)
err := l.SendAuthenticatedHTTPRequest("POST", localbitcoinsAPIWalletAddress, nil, &resp)
if err != nil {
return "", err
}
if resp.Data.Message != "OK!" {
return "", errors.New("Unable to fetch wallet address.")
return "", errors.New("unable to fetch wallet address")
}
return resp.Data.Address, nil
}
// GetBitcoinsWithCashAd returns buy or sell as cash local advertisements.
func (l *LocalBitcoins) GetBitcoinsWithCashAd(locationID, locationSlug string, BuySide bool) error {
return common.SendHTTPGetRequest(localbitcoinsAPIURL+localbitcoinsAPICashBuy, true, l.Verbose, nil)
}
// GetBitcoinsOnlineAd this API returns buy or sell Bitcoin online ads.
func (l *LocalBitcoins) GetBitcoinsOnlineAd(countryCode, countryName, paymentMethod string, BuySide bool) error {
return common.SendHTTPGetRequest(localbitcoinsAPIURL+localbitcoinsAPIOnlineBuy, true, l.Verbose, nil)
}
// GetTicker returns list of all completed trades.
func (l *LocalBitcoins) GetTicker() (map[string]Ticker, error) {
result := make(map[string]Ticker)
return result,
common.SendHTTPGetRequest(localbitcoinsAPIURL+localbitcoinsAPITicker, true, l.Verbose, &result)
}
// GetTrades returns all closed trades in online buy and online sell categories,
// updated every 15 minutes.
func (l *LocalBitcoins) GetTrades(currency string, values url.Values) ([]Trade, error) {
path := common.EncodeURLValues(fmt.Sprintf("%s/%s/trades.json", localbitcoinsAPIURL+localbitcoinsAPIBitcoincharts, currency), values)
result := []Trade{}
return result, common.SendHTTPGetRequest(path, true, l.Verbose, &result)
}
// GetOrderbook returns buy and sell bitcoin online advertisements. Amount is
// the maximum amount available for the trade request. Price is the hourly
// updated price. The price is based on the price equation and commission %
// entered by the ad author.
func (l *LocalBitcoins) GetOrderbook(currency string) (Orderbook, error) {
type response struct {
Bids [][]string `json:"bids"`
Asks [][]string `json:"asks"`
}
path := fmt.Sprintf("%s/%s/orderbook.json", localbitcoinsAPIURL+localbitcoinsAPIBitcoincharts, currency)
resp := response{}
err := common.SendHTTPGetRequest(path, true, l.Verbose, &resp)
if err != nil {
return Orderbook{}, err
}
orderbook := Orderbook{}
for _, x := range resp.Bids {
price, err := strconv.ParseFloat(x[0], 64)
if err != nil {
log.Println(err)
continue
}
amount, err := strconv.ParseFloat(x[1], 64)
if err != nil {
log.Println(err)
continue
}
orderbook.Bids = append(orderbook.Bids, Price{price, amount})
}
for _, x := range resp.Asks {
price, err := strconv.ParseFloat(x[0], 64)
if err != nil {
log.Println(err)
continue
}
amount, err := strconv.ParseFloat(x[1], 64)
if err != nil {
log.Println(err)
continue
}
orderbook.Asks = append(orderbook.Asks, Price{price, amount})
}
return orderbook, nil
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request to
// localbitcoins
func (l *LocalBitcoins) SendAuthenticatedHTTPRequest(method, path string, values url.Values, result interface{}) (err error) {
if !l.AuthenticatedAPISupport {
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, l.Name)
@@ -306,16 +681,29 @@ func (l *LocalBitcoins) SendAuthenticatedHTTPRequest(method, path string, values
headers["Apiauth-Signature"] = common.StringToUpper(common.HexEncodeToString(hmac))
headers["Content-Type"] = "application/x-www-form-urlencoded"
resp, err := common.SendHTTPRequest(method, LOCALBITCOINS_API_URL+path, headers, bytes.NewBuffer([]byte(payload)))
if l.Verbose {
log.Printf("Raw Path: \n%s\n", path)
}
resp, err := common.SendHTTPRequest(method, localbitcoinsAPIURL+path, headers, bytes.NewBuffer([]byte(payload)))
if err != nil {
return err
}
if l.Verbose {
log.Printf("Received raw: \n%s\n", resp)
}
err = common.JSONDecode([]byte(resp), &result)
errCapture := GeneralError{}
if err = common.JSONDecode([]byte(resp), &errCapture); err == nil {
if len(errCapture.Error.Message) != 0 {
return errors.New(errCapture.Error.Message)
}
}
err = common.JSONDecode([]byte(resp), &result)
if err != nil {
return errors.New("unable to JSON Unmarshal response")
return err
}
return nil

View File

@@ -0,0 +1,75 @@
package localbitcoins
import (
"testing"
"github.com/thrasher-/gocryptotrader/config"
)
var l LocalBitcoins
// Please supply your own APIKEYS here for due diligence testing
const (
apiKey = ""
apiSecret = ""
)
func TestSetDefaults(t *testing.T) {
l.SetDefaults()
}
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
localbitcoinsConfig, err := cfg.GetExchangeConfig("LocalBitcoins")
if err != nil {
t.Error("Test Failed - LakeBTC Setup() init error")
}
localbitcoinsConfig.AuthenticatedAPISupport = true
localbitcoinsConfig.APIKey = apiKey
localbitcoinsConfig.APISecret = apiSecret
l.Setup(localbitcoinsConfig)
}
func TestGetFee(t *testing.T) {
t.Parallel()
if l.GetFee(false) != 0 || l.GetFee(true) != 0 {
t.Error("Test Failed - GetFee() error")
}
}
func TestGetAccountInfo(t *testing.T) {
t.Parallel()
_, err := l.GetAccountInfo("", true)
if err == nil {
t.Error("Test Failed - GetAccountInfo() error", err)
}
_, err = l.GetAccountInfo("bitcoinbaron", false)
if err != nil {
t.Error("Test Failed - GetAccountInfo() error", err)
}
}
func TestGetads(t *testing.T) {
t.Parallel()
_, err := l.Getads("")
if err == nil {
t.Error("Test Failed - Getads() - Full list, error", err)
}
_, err = l.Getads("1337")
if err == nil {
t.Error("Test Failed - Getads() error", err)
}
}
func TestEditAd(t *testing.T) {
t.Parallel()
edit := AdEdit{}
err := l.EditAd(edit, "1337")
if err == nil {
t.Error("Test Failed - EditAd() error", err)
}
}

View File

@@ -4,7 +4,318 @@ import (
"time"
)
type LocalBitcoinsTicker struct {
// GeneralError is an error capture type
type GeneralError struct {
Error struct {
Message string `json:"message"`
ErrorCode int `json:"error_code"`
} `json:"error"`
}
// AccountInfo holds public user information
type AccountInfo struct {
Username string `json:"username"`
FeedbackScore int `json:"feedback_score"`
FeedbackCount int `json:"feedback_count"`
RealNameVeriTrusted int `json:"real_name_verifications_trusted"`
TradingPartners int `json:"trading_partners_count"`
URL string `json:"url"`
RealNameVeriUntrusted int `json:"real_name_verifications_untrusted"`
HasFeedback bool `json:"has_feedback"`
IdentityVerifiedAt string `json:"identify_verified_at"`
TrustedCount int `json:"trusted_count"`
FeedbacksUnconfirmed int `json:"feedbacks_unconfirmed_count"`
BlockedCount int `json:"blocked_count"`
TradeVolumeText string `json:"trade_volume_text"`
HasCommonTrades bool `json:"has_common_trades"`
RealNameVeriRejected int `json:"real_name_verifications_rejected"`
AgeText string `json:"age_text"`
ConfirmedTradesText string `json:"confirmed_trade_count_text"`
CreatedAt string `json:"created_at"`
}
// AdData references the full possible return of ad data
type AdData struct {
AdList []struct {
Data struct {
Visible bool `json:"visible"`
HiddenByOpeningHours bool `json:"hidden_by_opening_hours"`
Location string `json:"location_string"`
CountryCode string `json:"countrycode"`
City string `json:"city"`
TradeType string `json:"trade_type"`
OnlineProvider string `json:"online_provider"`
FirstTimeLimitBTC string `json:"first_time_limit_btc"`
VolumeCoefficientBTC string `json:"volume_coefficient_btc"`
SMSVerficationRequired bool `json:"sms_verification_required"`
ReferenceType string `json:"reference_type"`
DisplayReference bool `json:"display_reference"`
Currency string `json:"currency"`
Lat float64 `json:"lat"`
Lon float64 `json:"lon"`
MinAmount string `json:"min_amount"`
MaxAmount string `json:"max_amount"`
MaXAmountAvailable string `json:"max_amount_available"`
LimitToFiatAmounts string `json:"limit_to_fiat_amounts"`
AdID int64 `json:"ad_id"`
TempPriceUSD string `json:"temp_price_usd"`
Floating bool `json:"floating"`
Profile interface{} `json:"profile"`
RequireFeedBackScore int `json:"require_feedback_score"`
RequireTradeVolume float64 `json:"require_trade_volume"`
RequireTrustedByAdvertiser bool `json:"require_trusted_by_advertiser"`
PaymentWindowMinutes int `json:"payment_window_minutes"`
BankName string `json:"bank_name"`
TrackMaxAmount bool `json:"track_max_amount"`
ATMModel string `json:"atm_model"`
PriceEquation string `json:"price_equation"`
OpeningHours interface{} `json:"opening_hours"`
AccountInfo string `json:"account_info"`
AccountDetails interface{} `json:"account_details"`
} `json:"data"`
Actions struct {
PublicView string `json:"public_view"`
HTMLEdit string `json:"html_edit"`
ChangeForm string `json:"change_form"`
ContactForm string `json:"contact_form"`
} `json:"actions"`
} `json:"ad_list"`
AdCount int `json:"ad_count"`
}
// AdEdit references an outgoing paramater type for EditAd() method
type AdEdit struct {
// Required Arguments
PriceEquation string `json:"price_equation"`
Latitude int `json:"lat"`
Longitude int `json:"lon"`
City string `json:"city"`
Location string `json:"location_string"`
CountryCode string `json:"countrycode"`
Currency string `json:"currency"`
AccountInfo string `json:"account_info"`
BankName string `json:"bank_name"`
MSG string `json:"msg"`
SMSVerficationRequired bool `json:"sms_verification_required"`
TrackMaxAmount bool `json:"track_max_amount"`
RequireTrustedByAdvertiser bool `json:"require_trusted_by_advertiser"`
RequireIdentification bool `json:"require_identification"`
// Optional Arguments
MinAmount int `json:"min_amount"`
MaxAmount int `json:"max_amount"`
OpeningHours []string `json:"opening_hours"`
LimitToFiatAmounts string `json:"limit_to_fiat_amounts"`
Visible bool `json:"visible,int"`
// Optional Arguments ONLINE_SELL ads
RequireTradeVolume int `json:"require_trade_volume"`
RequireFeedBackScore int `json:"require_feedback_score"`
FirstTimeLimitBTC int `json:"first_time_limit_btc"`
VolumeCoefficientBTC int `json:"volume_coefficient_btc"`
ReferenceType string `json:"reference_type"`
DisplayReference bool `json:"display_reference,int"`
// Optional Arguments ONLINE_BUY
PaymentWindowMinutes int `json:"payment_window_minutes"`
// Optional Arguments LOCAL_SELL
Floating bool `json:"floating,int"`
}
// AdCreate references an outgoing paramater type for CreateAd() method
type AdCreate struct {
// Required Arguments
PriceEquation string `json:"price_equation"`
Latitude int `json:"lat"`
Longitude int `json:"lon"`
City string `json:"city"`
Location string `json:"location_string"`
CountryCode string `json:"countrycode"`
Currency string `json:"currency"`
AccountInfo string `json:"account_info"`
BankName string `json:"bank_name"`
MSG string `json:"msg"`
SMSVerficationRequired bool `json:"sms_verification_required"`
TrackMaxAmount bool `json:"track_max_amount"`
RequireTrustedByAdvertiser bool `json:"require_trusted_by_advertiser"`
RequireIdentification bool `json:"require_identification"`
OnlineProvider string `json:"online_provider"`
TradeType string `json:"trade_type"`
// Optional Arguments
MinAmount int `json:"min_amount"`
MaxAmount int `json:"max_amount"`
OpeningHours []string `json:"opening_hours"`
LimitToFiatAmounts string `json:"limit_to_fiat_amounts"`
Visible bool `json:"visible,int"`
// Optional Arguments ONLINE_SELL ads
RequireTradeVolume int `json:"require_trade_volume"`
RequireFeedBackScore int `json:"require_feedback_score"`
FirstTimeLimitBTC int `json:"first_time_limit_btc"`
VolumeCoefficientBTC int `json:"volume_coefficient_btc"`
ReferenceType string `json:"reference_type"`
DisplayReference bool `json:"display_reference,int"`
// Optional Arguments ONLINE_BUY
PaymentWindowMinutes int `json:"payment_window_minutes"`
// Optional Arguments LOCAL_SELL
Floating bool `json:"floating,int"`
}
// Message holds the returned message data from a contact
type Message struct {
MSG string `json:"msg"`
Sender struct {
ID int64 `json:"id"`
Name string `json:"name"`
Username string `json:"username"`
TradeCount int64 `json:"trafe_count"`
LastOnline string `json:"last_online"`
} `json:"sender"`
CreatedAt string `json:"created_at"`
IsAdmin bool `json:"is_admin"`
AttachmentName string `json:"attachment_name"`
AttachmentType string `json:"attachment_type"`
AttachmentURL string `json:"attachment_url"`
}
// DashBoardInfo holds the full range of metadata for a dashboard image
type DashBoardInfo struct {
Data struct {
CreatedAt string `json:"created_at"`
Buyer struct {
Username string `json:"username"`
TradeCount string `json:"trade_count"`
FeedbackScore string `json:"feedback_score"`
Name string `json:"name"`
LastOnline string `json:"last_online"`
RealName string `json:"real_name"`
CompanyName string `json:"company_name"`
CountryCodeByIP string `json:"countrycode_by_ip"`
CountryCodeByPhoneNUmber string `json:"countrycode_by_phone_number"`
} `json:"buyer"`
Seller struct {
Username string `json:"username"`
TradeCount string `json:"trade_count"`
FeedbackScore string `json:"feedback_score"`
Name string `json:"name"`
LastOnline string `json:"last_online"`
} `json:"seller"`
ReferenceCode string `json:"reference_code"`
Currency string `json:"currency"`
Amount float64 `json:"amount,string"`
AmountBTC float64 `json:"amount_btc,string"`
FeeBTC float64 `json:"fee_btc,string"`
ExchangeRateUpdatedAt string `json:"exchange_rate_updated_at"`
Advertisement struct {
ID int `json:"id"`
TradeType string `json:"trade_type"`
Advertiser struct {
Username string `json:"username"`
TradeCount string `json:"trade_count"`
FeedbackScore string `json:"feedback_score"`
Name string `json:"name"`
LastOnline string `json:"last_online"`
} `json:"advertiser"`
} `json:"advertisement"`
ContactID int `json:"contact_id"`
CanceledAt string `json:"canceled_at"`
EscrowedAt string `json:"escrowed_at"`
FundedAt string `json:"funded_at"`
PaymentCompletedAt string `json:"payment_completed_at"`
DisputedAt string `json:"disputed_at"`
ClosedAt string `json:"closed_at"`
ReleasedAt string `json:"released_at"`
IsBuying bool `json:"is_buying"`
IsSelling bool `json:"is_selling"`
AccountDetails struct {
ReceiverName string `json:"receiver_name"`
IBAN string `json:"iban"`
SwiftBIC string `json:"swift_bic"`
Reference string `json:"reference"`
} `json:"account_details"`
AccountInfo string `json:"account_info"`
Floating bool `json:"floating"`
} `json:"data"`
Actions struct {
MarkAsPaidURL string `json:"mark_as_paid_url"`
AdvertisementPublicView string `json:"advertisement_public_view"`
MessageURL string `json:"message_url"`
MessagePostURL string `json:"message_post_url"`
} `json:"actions"`
}
// Invoice contains invoice data
type Invoice struct {
Invoice struct {
Description string `json:"description"`
Created string `json:"created"`
URL string `json:"url"`
Amount float64 `json:"amount,string"`
Internal bool `json:"internal"`
Currency string `json:"currency"`
State string `json:"state"`
ID string `json:"id"`
BTCAmount string `json:"btc_amount"`
BTCAddress string `json:"btc_address"`
DeletingAllowed bool `json:"deleting_allowed"`
} `json:"invoice"`
}
// NotificationInfo holds Notification data
type NotificationInfo struct {
URL string `json:"url"`
CreatedAt string `json:"created_at"`
ContactID int64 `json:"contact_id"`
Read bool `json:"read"`
MSG string `json:"msg"`
ID string `json:"id"`
}
// WalletInfo holds full wallet information data
type WalletInfo struct {
Message string `json:"message"`
Total Balance `json:"total"`
SentTransactions30d []WalletTransaction `json:"sent_transactions_30d"`
ReceivedTransactions30d []WalletTransaction `json:"received_transactions_30d"`
ReceivingAddressCount int `json:"receiving_address_count"`
ReceivingAddressList []WalletAddressList `json:"receiving_address_list"`
}
// Balance is a sub-type for WalletInfo & WalletBalanceInfo
type Balance struct {
Balance float64 `json:"balance,string"`
Sendable float64 `json:"Sendable,string"`
}
// WalletTransaction is a sub-type for WalletInfo
type WalletTransaction struct {
TXID string `json:"txid"`
Amount float64 `json:"amount,string"`
Description string `json:"description"`
TXType int `json:"tx_type"`
CreatedAt time.Time `json:"created_at"`
}
// WalletAddressList is a sub-type for WalletInfo & WalletBalanceInfo
type WalletAddressList struct {
Address string `json:"address"`
Received float64 `json:"received,string"`
}
// WalletBalanceInfo standard wallet balance information
type WalletBalanceInfo struct {
Message string `json:"message"`
Total Balance `json:"total"`
ReceivingAddressCount int `json:"receiving_address_count"` // always 1
ReceivingAddressList []WalletAddressList `json:"receiving_address_list"`
}
// Ticker contains ticker information
type Ticker struct {
Avg12h float64 `json:"avg_12h,string"`
Avg1h float64 `json:"avg_1h,string"`
Avg24h float64 `json:"avg_24h,string"`
@@ -14,71 +325,22 @@ type LocalBitcoinsTicker struct {
VolumeBTC float64 `json:"volume_btc,string"`
}
type LocalBitcoinsTrade struct {
// Trade holds closed trade information
type Trade struct {
TID int64 `json:"tid"`
Date int64 `json:"date"`
Amount float64 `json:"amount,string"`
Price float64 `json:"price,string"`
}
type LocalBitcoinsOrderbookStructure struct {
// Orderbook is a full range of bid and asks for localbitcoins
type Orderbook struct {
Bids []Price `json:"bids"`
Asks []Price `json:"asks"`
}
// Price is a sub-type for orderbook
type Price struct {
Price float64
Amount float64
}
type LocalBitcoinsOrderbook struct {
Bids []LocalBitcoinsOrderbookStructure `json:"bids"`
Asks []LocalBitcoinsOrderbookStructure `json:"asks"`
}
type LocalBitcoinsAccountInfo struct {
Username string `json:"username"`
CreatedAt time.Time `json:"created_at"`
AgeText string `json:"age_text"`
TradingPartners int `json:"trading_partners_count"`
FeedbacksUnconfirmed int `json:"feedbacks_unconfirmed_count"`
TradeVolumeText string `json:"trade_volume_text"`
HasCommonTrades bool `json:"has_common_trades"`
HasFeedback bool `json:"has_feedback"`
ConfirmedTradesText string `json:"confirmed_trade_count_text"`
BlockedCount int `json:"blocked_count"`
FeedbackScore int `json:"feedback_score"`
FeedbackCount int `json:"feedback_count"`
URL string `json:"url"`
TrustedCount int `json:"trusted_count"`
IdentityVerifiedAt time.Time `json:"identify_verified_at"`
}
type LocalBitcoinsBalance struct {
Balance float64 `json:"balance,string"`
Sendable float64 `json:"Sendable,string"`
}
type LocalBitcoinsWalletTransaction struct {
TXID string `json:"txid"`
Amount float64 `json:"amount,string"`
Description string `json:"description"`
TXType int `json:"tx_type"`
CreatedAt time.Time `json:"created_at"`
}
type LocalBitcoinsWalletAddressList struct {
Address string `json:"address"`
Received float64 `json:"received,string"`
}
type LocalBitcoinsWalletInfo struct {
Message string `json:"message"`
Total LocalBitcoinsBalance `json:"total"`
SentTransactions30d []LocalBitcoinsWalletTransaction `json:"sent_transactions_30d"`
ReceivedTransactions30d []LocalBitcoinsWalletTransaction `json:"received_transactions_30d"`
ReceivingAddressCount int `json:"receiving_address_count"`
ReceivingAddressList []LocalBitcoinsWalletAddressList `json:"receiving_address_list"`
}
type LocalBitcoinsWalletBalanceInfo struct {
Message string `json:"message"`
Total LocalBitcoinsBalance `json:"total"`
ReceivingAddressCount int `json:"receiving_address_count"` // always 1
ReceivingAddressList []LocalBitcoinsWalletAddressList `json:"receiving_address_list"`
}

View File

@@ -0,0 +1,35 @@
package okcoin
import (
"testing"
"github.com/thrasher-/gocryptotrader/config"
)
var o OKCoin
// Please supply your own APIKEYS here for due diligence testing
const (
apiKey = ""
apiSecret = ""
)
func TestSetDefaults(t *testing.T) {
o.SetDefaults()
}
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
okcoinConfig, err := cfg.GetExchangeConfig("OKCOIN International")
if err != nil {
t.Error("Test Failed - OKCoin Setup() init error")
}
okcoinConfig.AuthenticatedAPISupport = true
okcoinConfig.APIKey = apiKey
okcoinConfig.APISecret = apiSecret
o.Setup(okcoinConfig)
}

View File

@@ -92,21 +92,21 @@ func TestGetOrderbook(t *testing.T) {
t.Fatal("Test failed. TestGetOrderbook failed. Mismatched pairs")
}
_, err = GetOrderbook("nonexistant", currency, Spot)
_, err = GetOrderbook("nonexistent", currency, Spot)
if err == nil {
t.Fatal("Test failed. TestGetOrderbook retrieved non-existant orderbook")
t.Fatal("Test failed. TestGetOrderbook retrieved non-existent orderbook")
}
currency.FirstCurrency = "blah"
_, err = GetOrderbook("Exchange", currency, Spot)
if err == nil {
t.Fatal("Test failed. TestGetOrderbook retrieved non-existant orderbook using invalid first currency")
t.Fatal("Test failed. TestGetOrderbook retrieved non-existent orderbook using invalid first currency")
}
newCurrency := pair.NewCurrencyPair("BTC", "AUD")
_, err = GetOrderbook("Exchange", newCurrency, Spot)
if err == nil {
t.Fatal("Test failed. TestGetOrderbook retrieved non-existant orderbook using invalid second currency")
t.Fatal("Test failed. TestGetOrderbook retrieved non-existent orderbook using invalid second currency")
}
}

View File

@@ -16,42 +16,44 @@ import (
)
const (
POLONIEX_API_URL = "https://poloniex.com"
POLONIEX_API_TRADING_ENDPOINT = "tradingApi"
POLONIEX_API_VERSION = "1"
POLONIEX_BALANCES = "returnBalances"
POLONIEX_BALANCES_COMPLETE = "returnCompleteBalances"
POLONIEX_DEPOSIT_ADDRESSES = "returnDepositAddresses"
POLONIEX_GENERATE_NEW_ADDRESS = "generateNewAddress"
POLONIEX_DEPOSITS_WITHDRAWALS = "returnDepositsWithdrawals"
POLONIEX_ORDERS = "returnOpenOrders"
POLONIEX_TRADE_HISTORY = "returnTradeHistory"
POLONIEX_ORDER_BUY = "buy"
POLONIEX_ORDER_SELL = "sell"
POLONIEX_ORDER_CANCEL = "cancelOrder"
POLONIEX_ORDER_MOVE = "moveOrder"
POLONIEX_WITHDRAW = "withdraw"
POLONIEX_FEE_INFO = "returnFeeInfo"
POLONIEX_AVAILABLE_BALANCES = "returnAvailableAccountBalances"
POLONIEX_TRADABLE_BALANCES = "returnTradableBalances"
POLONIEX_TRANSFER_BALANCE = "transferBalance"
POLONIEX_MARGIN_ACCOUNT_SUMMARY = "returnMarginAccountSummary"
POLONIEX_MARGIN_BUY = "marginBuy"
POLONIEX_MARGIN_SELL = "marginSell"
POLONIEX_MARGIN_POSITION = "getMarginPosition"
POLONIEX_MARGIN_POSITION_CLOSE = "closeMarginPosition"
POLONIEX_CREATE_LOAN_OFFER = "createLoanOffer"
POLONIEX_CANCEL_LOAN_OFFER = "cancelLoanOffer"
POLONIEX_OPEN_LOAN_OFFERS = "returnOpenLoanOffers"
POLONIEX_ACTIVE_LOANS = "returnActiveLoans"
POLONIEX_LENDING_HISTORY = "returnLendingHistory"
POLONIEX_AUTO_RENEW = "toggleAutoRenew"
poloniexAPIURL = "https://poloniex.com"
poloniexAPITradingEndpoint = "tradingApi"
poloniexAPIVersion = "1"
poloniexBalances = "returnBalances"
poloniexBalancesComplete = "returnCompleteBalances"
poloniexDepositAddresses = "returnDepositAddresses"
poloniexGenerateNewAddress = "generateNewAddress"
poloniexDepositsWithdrawals = "returnDepositsWithdrawals"
poloniexOrders = "returnOpenOrders"
poloniexTradeHistory = "returnTradeHistory"
poloniexOrderBuy = "buy"
poloniexOrderSell = "sell"
poloniexOrderCancel = "cancelOrder"
poloniexOrderMove = "moveOrder"
poloniexWithdraw = "withdraw"
poloniexFeeInfo = "returnFeeInfo"
poloniexAvailableBalances = "returnAvailableAccountBalances"
poloniexTradableBalances = "returnTradableBalances"
poloniexTransferBalance = "transferBalance"
poloniexMarginAccountSummary = "returnMarginAccountSummary"
poloniexMarginBuy = "marginBuy"
poloniexMarginSell = "marginSell"
poloniexMarginPosition = "getMarginPosition"
poloniexMarginPositionClose = "closeMarginPosition"
poloniexCreateLoanOffer = "createLoanOffer"
poloniexCancelLoanOffer = "cancelLoanOffer"
poloniexOpenLoanOffers = "returnOpenLoanOffers"
poloniexActiveLoans = "returnActiveLoans"
poloniexLendingHistory = "returnLendingHistory"
poloniexAutoRenew = "toggleAutoRenew"
)
// Poloniex is the overarching type across the poloniex package
type Poloniex struct {
exchange.Base
}
// SetDefaults sets default settings for poloniex
func (p *Poloniex) SetDefaults() {
p.Name = "Poloniex"
p.Enabled = false
@@ -66,6 +68,7 @@ func (p *Poloniex) SetDefaults() {
p.AssetTypes = []string{ticker.Spot}
}
// Setup sets user exchange configuration settings
func (p *Poloniex) Setup(exch config.ExchangeConfig) {
if !exch.Enabled {
p.SetEnabled(false)
@@ -90,36 +93,32 @@ func (p *Poloniex) Setup(exch config.ExchangeConfig) {
}
}
// GetFee returns the fee for poloniex
func (p *Poloniex) GetFee() float64 {
return p.Fee
}
// GetTicker returns current ticker information
func (p *Poloniex) GetTicker() (map[string]PoloniexTicker, error) {
type response struct {
Data map[string]PoloniexTicker
}
resp := response{}
path := fmt.Sprintf("%s/public?command=returnTicker", POLONIEX_API_URL)
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp.Data)
path := fmt.Sprintf("%s/public?command=returnTicker", poloniexAPIURL)
if err != nil {
return resp.Data, err
}
return resp.Data, nil
return resp.Data, common.SendHTTPGetRequest(path, true, p.Verbose, &resp.Data)
}
// GetVolume returns a list of currencies with associated volume
func (p *Poloniex) GetVolume() (interface{}, error) {
var resp interface{}
path := fmt.Sprintf("%s/public?command=return24hVolume", POLONIEX_API_URL)
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
path := fmt.Sprintf("%s/public?command=return24hVolume", poloniexAPIURL)
if err != nil {
return resp, err
}
return resp, nil
return resp, common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
}
// GetOrderbook returns the full orderbook from poloniex
func (p *Poloniex) GetOrderbook(currencyPair string, depth int) (PoloniexOrderbook, error) {
vals := url.Values{}
vals.Set("currencyPair", currencyPair)
@@ -129,13 +128,18 @@ func (p *Poloniex) GetOrderbook(currencyPair string, depth int) (PoloniexOrderbo
}
resp := PoloniexOrderbookResponse{}
path := fmt.Sprintf("%s/public?command=returnOrderBook&%s", POLONIEX_API_URL, vals.Encode())
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
path := fmt.Sprintf("%s/public?command=returnOrderBook&%s", poloniexAPIURL, vals.Encode())
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
if err != nil {
return PoloniexOrderbook{}, err
}
if len(resp.Error) != 0 {
log.Println(resp.Error)
return PoloniexOrderbook{}, fmt.Errorf("Poloniex GetOrderbook() error: %s", resp.Error)
}
ob := PoloniexOrderbook{}
for x := range resp.Asks {
data := resp.Asks[x]
@@ -159,6 +163,7 @@ func (p *Poloniex) GetOrderbook(currencyPair string, depth int) (PoloniexOrderbo
return ob, nil
}
// GetTradeHistory returns trades history from poloniex
func (p *Poloniex) GetTradeHistory(currencyPair, start, end string) ([]PoloniexTradeHistory, error) {
vals := url.Values{}
vals.Set("currencyPair", currencyPair)
@@ -172,15 +177,12 @@ func (p *Poloniex) GetTradeHistory(currencyPair, start, end string) ([]PoloniexT
}
resp := []PoloniexTradeHistory{}
path := fmt.Sprintf("%s/public?command=returnTradeHistory&%s", POLONIEX_API_URL, vals.Encode())
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
path := fmt.Sprintf("%s/public?command=returnTradeHistory&%s", poloniexAPIURL, vals.Encode())
if err != nil {
return nil, err
}
return resp, nil
return resp, common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
}
// GetChartData returns chart data for a specific currency pair
func (p *Poloniex) GetChartData(currencyPair, start, end, period string) ([]PoloniexChartData, error) {
vals := url.Values{}
vals.Set("currencyPair", currencyPair)
@@ -198,43 +200,39 @@ func (p *Poloniex) GetChartData(currencyPair, start, end, period string) ([]Polo
}
resp := []PoloniexChartData{}
path := fmt.Sprintf("%s/public?command=returnChartData&%s", POLONIEX_API_URL, vals.Encode())
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
path := fmt.Sprintf("%s/public?command=returnChartData&%s", poloniexAPIURL, vals.Encode())
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
if err != nil {
return nil, err
}
return resp, nil
}
// GetCurrencies returns information about currencies
func (p *Poloniex) GetCurrencies() (map[string]PoloniexCurrencies, error) {
type Response struct {
Data map[string]PoloniexCurrencies
}
resp := Response{}
path := fmt.Sprintf("%s/public?command=returnCurrencies", POLONIEX_API_URL)
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp.Data)
path := fmt.Sprintf("%s/public?command=returnCurrencies", poloniexAPIURL)
if err != nil {
return resp.Data, err
}
return resp.Data, nil
return resp.Data, common.SendHTTPGetRequest(path, true, p.Verbose, &resp.Data)
}
// GetLoanOrders returns the list of loan offers and demands for a given
// currency, specified by the "currency" GET parameter.
func (p *Poloniex) GetLoanOrders(currency string) (PoloniexLoanOrders, error) {
resp := PoloniexLoanOrders{}
path := fmt.Sprintf("%s/public?command=returnLoanOrders&currency=%s", POLONIEX_API_URL, currency)
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
path := fmt.Sprintf("%s/public?command=returnLoanOrders&currency=%s", poloniexAPIURL, currency)
if err != nil {
return resp, err
}
return resp, nil
return resp, common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
}
func (p *Poloniex) GetBalances() (PoloniexBalance, error) {
var result interface{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_BALANCES, url.Values{}, &result)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexBalances, url.Values{}, &result)
if err != nil {
return PoloniexBalance{}, err
@@ -257,7 +255,7 @@ type PoloniexCompleteBalances struct {
func (p *Poloniex) GetCompleteBalances() (PoloniexCompleteBalances, error) {
var result interface{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_BALANCES_COMPLETE, url.Values{}, &result)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexBalancesComplete, url.Values{}, &result)
if err != nil {
return PoloniexCompleteBalances{}, err
@@ -282,7 +280,7 @@ func (p *Poloniex) GetCompleteBalances() (PoloniexCompleteBalances, error) {
func (p *Poloniex) GetDepositAddresses() (PoloniexDepositAddresses, error) {
var result interface{}
addresses := PoloniexDepositAddresses{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_DEPOSIT_ADDRESSES, url.Values{}, &result)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexDepositAddresses, url.Values{}, &result)
if err != nil {
return addresses, err
@@ -307,7 +305,7 @@ func (p *Poloniex) GenerateNewAddress(currency string) (string, error) {
values := url.Values{}
values.Set("currency", currency)
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_GENERATE_NEW_ADDRESS, values, &resp)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexGenerateNewAddress, values, &resp)
if err != nil {
return "", err
@@ -336,7 +334,7 @@ func (p *Poloniex) GetDepositsWithdrawals(start, end string) (PoloniexDepositsWi
values.Set("end", strconv.FormatInt(time.Now().Unix(), 10))
}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_DEPOSITS_WITHDRAWALS, values, &resp)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexDepositsWithdrawals, values, &resp)
if err != nil {
return resp, err
@@ -351,7 +349,7 @@ func (p *Poloniex) GetOpenOrders(currency string) (interface{}, error) {
if currency != "" {
values.Set("currencyPair", currency)
result := PoloniexOpenOrdersResponse{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_ORDERS, values, &result.Data)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexOrders, values, &result.Data)
if err != nil {
return result, err
@@ -361,7 +359,7 @@ func (p *Poloniex) GetOpenOrders(currency string) (interface{}, error) {
} else {
values.Set("currencyPair", "all")
result := PoloniexOpenOrdersResponseAll{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_ORDERS, values, &result.Data)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexOrders, values, &result.Data)
if err != nil {
return result, err
@@ -385,7 +383,7 @@ func (p *Poloniex) GetAuthenticatedTradeHistory(currency, start, end string) (in
if currency != "" && currency != "all" {
values.Set("currencyPair", currency)
result := PoloniexAuthenticatedTradeHistoryResponse{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_TRADE_HISTORY, values, &result.Data)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexTradeHistory, values, &result.Data)
if err != nil {
return result, err
@@ -395,7 +393,7 @@ func (p *Poloniex) GetAuthenticatedTradeHistory(currency, start, end string) (in
} else {
values.Set("currencyPair", "all")
result := PoloniexAuthenticatedTradeHistoryAll{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_TRADE_HISTORY, values, &result.Data)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexTradeHistory, values, &result.Data)
if err != nil {
return result, err
@@ -411,9 +409,9 @@ func (p *Poloniex) PlaceOrder(currency string, rate, amount float64, immediate,
var orderType string
if buy {
orderType = POLONIEX_ORDER_BUY
orderType = poloniexOrderBuy
} else {
orderType = POLONIEX_ORDER_SELL
orderType = poloniexOrderSell
}
values.Set("currencyPair", currency)
@@ -442,7 +440,7 @@ func (p *Poloniex) CancelOrder(orderID int64) (bool, error) {
values := url.Values{}
values.Set("orderNumber", strconv.FormatInt(orderID, 10))
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_ORDER_CANCEL, values, &result)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexOrderCancel, values, &result)
if err != nil {
return false, err
@@ -465,7 +463,7 @@ func (p *Poloniex) MoveOrder(orderID int64, rate, amount float64) (PoloniexMoveO
values.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_ORDER_MOVE, values, &result)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexOrderMove, values, &result)
if err != nil {
return result, err
@@ -486,7 +484,7 @@ func (p *Poloniex) Withdraw(currency, address string, amount float64) (bool, err
values.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
values.Set("address", address)
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_WITHDRAW, values, &result)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexWithdraw, values, &result)
if err != nil {
return false, err
@@ -501,7 +499,7 @@ func (p *Poloniex) Withdraw(currency, address string, amount float64) (bool, err
func (p *Poloniex) GetFeeInfo() (PoloniexFee, error) {
result := PoloniexFee{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_FEE_INFO, url.Values{}, &result)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexFeeInfo, url.Values{}, &result)
if err != nil {
return result, err
@@ -516,7 +514,7 @@ func (p *Poloniex) GetTradableBalances() (map[string]map[string]float64, error)
}
result := Response{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_TRADABLE_BALANCES, url.Values{}, &result.Data)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexTradableBalances, url.Values{}, &result.Data)
if err != nil {
return nil, err
@@ -543,7 +541,7 @@ func (p *Poloniex) TransferBalance(currency, from, to string, amount float64) (b
values.Set("fromAccount", from)
values.Set("toAccount", to)
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_TRANSFER_BALANCE, values, &result)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexTransferBalance, values, &result)
if err != nil {
return false, err
@@ -558,7 +556,7 @@ func (p *Poloniex) TransferBalance(currency, from, to string, amount float64) (b
func (p *Poloniex) GetMarginAccountSummary() (PoloniexMargin, error) {
result := PoloniexMargin{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_MARGIN_ACCOUNT_SUMMARY, url.Values{}, &result)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexMarginAccountSummary, url.Values{}, &result)
if err != nil {
return result, err
@@ -573,9 +571,9 @@ func (p *Poloniex) PlaceMarginOrder(currency string, rate, amount, lendingRate f
var orderType string
if buy {
orderType = POLONIEX_MARGIN_BUY
orderType = poloniexMarginBuy
} else {
orderType = POLONIEX_MARGIN_SELL
orderType = poloniexMarginSell
}
values.Set("currencyPair", currency)
@@ -601,7 +599,7 @@ func (p *Poloniex) GetMarginPosition(currency string) (interface{}, error) {
if currency != "" && currency != "all" {
values.Set("currencyPair", currency)
result := PoloniexMarginPosition{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_MARGIN_POSITION, values, &result)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexMarginPosition, values, &result)
if err != nil {
return result, err
@@ -616,7 +614,7 @@ func (p *Poloniex) GetMarginPosition(currency string) (interface{}, error) {
}
result := Response{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_MARGIN_POSITION, values, &result.Data)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexMarginPosition, values, &result.Data)
if err != nil {
return result, err
@@ -631,7 +629,7 @@ func (p *Poloniex) CloseMarginPosition(currency string) (bool, error) {
values.Set("currencyPair", currency)
result := PoloniexGenericResponse{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_MARGIN_POSITION_CLOSE, values, &result)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexMarginPositionClose, values, &result)
if err != nil {
return false, err
@@ -666,7 +664,7 @@ func (p *Poloniex) CreateLoanOffer(currency string, amount, rate float64, durati
result := Response{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_CREATE_LOAN_OFFER, values, &result)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexCreateLoanOffer, values, &result)
if err != nil {
return 0, err
@@ -684,7 +682,7 @@ func (p *Poloniex) CancelLoanOffer(orderNumber int64) (bool, error) {
values := url.Values{}
values.Set("orderID", strconv.FormatInt(orderNumber, 10))
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_CANCEL_LOAN_OFFER, values, &result)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexCancelLoanOffer, values, &result)
if err != nil {
return false, err
@@ -703,7 +701,7 @@ func (p *Poloniex) GetOpenLoanOffers() (map[string][]PoloniexLoanOffer, error) {
}
result := Response{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_OPEN_LOAN_OFFERS, url.Values{}, &result.Data)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexOpenLoanOffers, url.Values{}, &result.Data)
if err != nil {
return nil, err
@@ -718,7 +716,7 @@ func (p *Poloniex) GetOpenLoanOffers() (map[string][]PoloniexLoanOffer, error) {
func (p *Poloniex) GetActiveLoans() (PoloniexActiveLoans, error) {
result := PoloniexActiveLoans{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_ACTIVE_LOANS, url.Values{}, &result)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexActiveLoans, url.Values{}, &result)
if err != nil {
return result, err
@@ -739,7 +737,7 @@ func (p *Poloniex) GetLendingHistory(start, end string) ([]PoloniexLendingHistor
}
resp := []PoloniexLendingHistory{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_LENDING_HISTORY, vals, &resp)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexLendingHistory, vals, &resp)
if err != nil {
return nil, err
@@ -752,7 +750,7 @@ func (p *Poloniex) ToggleAutoRenew(orderNumber int64) (bool, error) {
values.Set("orderNumber", strconv.FormatInt(orderNumber, 10))
result := PoloniexGenericResponse{}
err := p.SendAuthenticatedHTTPRequest("POST", POLONIEX_AUTO_RENEW, values, &result)
err := p.SendAuthenticatedHTTPRequest("POST", poloniexAutoRenew, values, &result)
if err != nil {
return false, err
@@ -784,7 +782,7 @@ func (p *Poloniex) SendAuthenticatedHTTPRequest(method, endpoint string, values
hmac := common.GetHMAC(common.HashSHA512, []byte(values.Encode()), []byte(p.APISecret))
headers["Sign"] = common.HexEncodeToString(hmac)
path := fmt.Sprintf("%s/%s", POLONIEX_API_URL, POLONIEX_API_TRADING_ENDPOINT)
path := fmt.Sprintf("%s/%s", poloniexAPIURL, poloniexAPITradingEndpoint)
resp, err := common.SendHTTPRequest(method, path, headers, bytes.NewBufferString(values.Encode()))
if err != nil {

View File

@@ -0,0 +1,90 @@
package poloniex
import (
"testing"
"github.com/thrasher-/gocryptotrader/config"
)
var p Poloniex
// Please supply your own APIKEYS here for due diligence testing
const (
apiKey = ""
apiSecret = ""
)
func TestSetDefaults(t *testing.T) {
p.SetDefaults()
}
func TestSetup(t *testing.T) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
poloniexConfig, err := cfg.GetExchangeConfig("Poloniex")
if err != nil {
t.Error("Test Failed - Poloniex Setup() init error")
}
poloniexConfig.AuthenticatedAPISupport = true
poloniexConfig.APIKey = apiKey
poloniexConfig.APISecret = apiSecret
p.Setup(poloniexConfig)
}
func TestGetFee(t *testing.T) {
if p.GetFee() != 0 {
t.Error("Test faild - Poloniex GetFee() error")
}
}
func TestGetTicker(t *testing.T) {
_, err := p.GetTicker()
if err != nil {
t.Error("Test faild - Poloniex GetTicker() error")
}
}
func TestGetVolume(t *testing.T) {
_, err := p.GetVolume()
if err != nil {
t.Error("Test faild - Poloniex GetVolume() error")
}
}
func TestGetOrderbook(t *testing.T) {
_, err := p.GetOrderbook("BTC_XMR", 50)
if err != nil {
t.Error("Test faild - Poloniex GetOrderbook() error", err)
}
}
func TestGetTradeHistory(t *testing.T) {
_, err := p.GetTradeHistory("BTC_XMR", "", "")
if err != nil {
t.Error("Test faild - Poloniex GetTradeHistory() error", err)
}
}
func TestGetChartData(t *testing.T) {
_, err := p.GetChartData("BTC_XMR", "1405699200", "1405699400", "300")
if err != nil {
t.Error("Test faild - Poloniex GetChartData() error", err)
}
}
func TestGetCurrencies(t *testing.T) {
_, err := p.GetCurrencies()
if err != nil {
t.Error("Test faild - Poloniex GetCurrencies() error", err)
}
}
func TestGetLoanOrders(t *testing.T) {
_, err := p.GetLoanOrders("BTC")
if err != nil {
t.Error("Test faild - Poloniex GetLoanOrders() error", err)
}
}

View File

@@ -16,6 +16,7 @@ type PoloniexOrderbookResponse struct {
Asks [][]interface{} `json:"asks"`
Bids [][]interface{} `json:"bids"`
IsFrozen string `json:"isFrozen"`
Error string `json:"error"`
}
type PoloniexOrderbookItem struct {
@@ -47,6 +48,7 @@ type PoloniexChartData struct {
Volume float64 `json:"volume"`
QuoteVolume float64 `json:"quoteVolume"`
WeightedAverage float64 `json:"weightedAverage"`
Error string `json:"error"`
}
type PoloniexCurrencies struct {

View File

@@ -20,7 +20,7 @@ func TestSetDefaults(t *testing.T) {
func TestSetup(t *testing.T) {
wexConfig := config.GetConfig()
wexConfig.LoadConfig("../../testdata/configtest.dat")
wexConfig.LoadConfig("../../testdata/configtest.json")
conf, err := wexConfig.GetExchangeConfig("WEX")
if err != nil {
t.Error("Test Failed - WEX init error")

View File

@@ -36,7 +36,7 @@ type Base struct {
SendFrom string `json:"send_from"`
}
// New initalises the SMSGlobal var
// New initialises the SMSGlobal var
func New(username, password, sendFrom string, contacts []Contact) *Base {
if username == "" || password == "" || sendFrom == "" || len(contacts) == 0 {
return nil

View File

@@ -52,7 +52,7 @@ func TestGetContactByNumber(t *testing.T) {
_, err = result.GetContactByNumber("ASDASDASD")
if err == nil {
t.Fatal("Test failed. TestGetContactByNumber: Returned nil err on non-existant number")
t.Fatal("Test failed. TestGetContactByNumber: Returned nil err on non-existent number")
}
}
@@ -73,7 +73,7 @@ func TestGetContactByName(t *testing.T) {
_, err = result.GetContactByName("ASDASDASD")
if err == nil {
t.Fatal("Test failed. TestGetContactByName: Returned nil err on non-existant number")
t.Fatal("Test failed. TestGetContactByName: Returned nil err on non-existent number")
}
}

View File

@@ -62,6 +62,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -84,6 +85,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -104,6 +106,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -125,6 +128,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -147,6 +151,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -167,6 +172,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -189,6 +195,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -209,6 +216,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -231,6 +239,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -251,6 +260,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -271,6 +281,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -292,6 +303,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -313,6 +325,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -333,6 +346,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -356,6 +370,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -376,6 +391,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -397,6 +413,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
@@ -418,6 +435,7 @@
"Enabled": true,
"Verbose": false,
"Websocket": false,
"UseSandbox": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",

View File

@@ -20,8 +20,9 @@ func main() {
var inFile, outFile, key string
var encrypt bool
var err error
flag.StringVar(&inFile, "infile", "config.dat", "The config input file to process.")
flag.StringVar(&outFile, "outfile", "config.dat.out", "The config output file.")
configFile := config.GetFilePath("")
flag.StringVar(&inFile, "infile", configFile, "The config input file to process.")
flag.StringVar(&outFile, "outfile", configFile+".out", "The config output file.")
flag.BoolVar(&encrypt, "encrypt", true, "Wether to encrypt or decrypt.")
flag.StringVar(&key, "key", "", "The key to use for AES encryption.")
flag.Parse()

View File

@@ -57,7 +57,7 @@ func getOnlineOfflinePortfolio(coins []portfolio.Coin, online bool) {
func main() {
var inFile, key string
flag.StringVar(&inFile, "infile", "config.dat", "The config input file to process.")
flag.StringVar(&inFile, "infile", config.GetFilePath(""), "The config input file to process.")
flag.StringVar(&key, "key", "", "The key to use for AES encryption.")
flag.Parse()