mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-18 15:10:03 +00:00
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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{})
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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, ¤cies)
|
||||
common.SendHTTPGetRequest(g.APIUrl+gdaxCurrencies, true, g.Verbose, ¤cies)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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
|
||||
|
||||
50
exchanges/huobi/huobi_test.go
Normal file
50
exchanges/huobi/huobi_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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"`
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
218
exchanges/kraken/kraken_test.go
Normal file
218
exchanges/kraken/kraken_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
124
exchanges/lakebtc/lakebtc_test.go
Normal file
124
exchanges/lakebtc/lakebtc_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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"`
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
75
exchanges/localbitcoins/localbitcoins_test.go
Normal file
75
exchanges/localbitcoins/localbitcoins_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
35
exchanges/okcoin/okcoin_test.go
Normal file
35
exchanges/okcoin/okcoin_test.go
Normal 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)
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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¤cy=%s", POLONIEX_API_URL, currency)
|
||||
err := common.SendHTTPGetRequest(path, true, p.Verbose, &resp)
|
||||
path := fmt.Sprintf("%s/public?command=returnLoanOrders¤cy=%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 {
|
||||
|
||||
90
exchanges/poloniex/poloniex_test.go
Normal file
90
exchanges/poloniex/poloniex_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user