Kraken rework + localbitcoins fixes (#170)

* OpenPosition

* AddOrder

* strict json schema

* localbitcoins DashBoard

* specific txid for OpenPositions

* catch exchange (not http) errors

* exchange errors: more informative

* proper API error handling

* strict AddOrder params/options encoding/validating

* TradeVolume and CancelOrder

* QueryLedgers

* GetLedgers

* GetTradesHistory

* QueryTrades

* GetClosedOrders

* GetClosedOrders: strict params

* QueryOrdersInfo

* UserRef is int32 according to doc

* CancelOrder

* GetOpenOrders

* GetTradeBalance

* GetBalance

* GetAssetPairs

* GetAsset

* GetServerTime

* no need for GeneralResponse

* TestGetServerTime fix
This commit is contained in:
soxipy
2018-08-06 14:38:41 +03:00
committed by Adrian Gallagher
parent 391e81b00e
commit efc6c8d31e
5 changed files with 648 additions and 195 deletions

View File

@@ -111,40 +111,51 @@ func (k *Kraken) GetFee(cryptoTrade bool) float64 {
}
// GetServerTime returns current server time
func (k *Kraken) GetServerTime(unixTime bool) (interface{}, error) {
var result GeneralResponse
func (k *Kraken) GetServerTime() (TimeResponse, error) {
path := fmt.Sprintf("%s/%s/public/%s", krakenAPIURL, krakenAPIVersion, krakenServerTime)
err := k.SendHTTPRequest(path, &result)
if err != nil {
return nil, fmt.Errorf("getServerTime() error %s", err)
var response struct {
Error []string `json:"error"`
Result TimeResponse `json:"result"`
}
if unixTime {
return result.Result["unixtime"], nil
if err := k.SendHTTPRequest(path, &response); err != nil {
return response.Result, err
}
return result.Result["rfc1123"], nil
return response.Result, GetError(response.Error)
}
// GetAssets returns a full asset list
func (k *Kraken) GetAssets() (interface{}, error) {
var result GeneralResponse
func (k *Kraken) GetAssets() (map[string]Asset, error) {
path := fmt.Sprintf("%s/%s/public/%s", krakenAPIURL, krakenAPIVersion, krakenAssets)
return result.Result, k.SendHTTPRequest(path, &result)
var response struct {
Error []string `json:"error"`
Result map[string]Asset `json:"result"`
}
if err := k.SendHTTPRequest(path, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// GetAssetPairs returns a full asset pair list
func (k *Kraken) GetAssetPairs() (map[string]AssetPairs, error) {
type Response struct {
Result map[string]AssetPairs `json:"result"`
Error []interface{} `json:"error"`
}
response := Response{}
path := fmt.Sprintf("%s/%s/public/%s", krakenAPIURL, krakenAPIVersion, krakenAssetPairs)
return response.Result, k.SendHTTPRequest(path, &response)
var response struct {
Error []string `json:"error"`
Result map[string]AssetPairs `json:"result"`
}
if err := k.SendHTTPRequest(path, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// GetTicker returns ticker information from kraken
@@ -371,208 +382,422 @@ func (k *Kraken) GetSpread(symbol string) ([]Spread, error) {
}
// GetBalance returns your balance associated with your keys
func (k *Kraken) GetBalance() (interface{}, error) {
return k.SendAuthenticatedHTTPRequest(krakenBalance, url.Values{})
func (k *Kraken) GetBalance() (map[string]float64, error) {
var response struct {
Error []string `json:"error"`
Result map[string]string `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenBalance, url.Values{}, &response); err != nil {
return nil, err
}
result := make(map[string]float64)
for curency, balance := range response.Result {
var err error
if result[curency], err = strconv.ParseFloat(balance, 64); err != nil {
return nil, err
}
}
return result, GetError(response.Error)
}
// GetTradeBalance returns full information about your trades on Kraken
func (k *Kraken) GetTradeBalance(symbol, asset string) (interface{}, error) {
values := url.Values{}
func (k *Kraken) GetTradeBalance(args ...TradeBalanceOptions) (TradeBalanceInfo, error) {
params := url.Values{}
if args != nil {
if len(args[0].Aclass) != 0 {
params.Set("aclass", args[0].Aclass)
}
if len(args[0].Asset) != 0 {
params.Set("asset", args[0].Asset)
}
if len(symbol) > 0 {
values.Set("aclass", symbol)
}
if len(asset) > 0 {
values.Set("asset", asset)
}
return k.SendAuthenticatedHTTPRequest(krakenTradeBalance, values)
var response struct {
Error []string `json:"error"`
Result TradeBalanceInfo `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenTradeBalance, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// GetOpenOrders returns all current open orders
func (k *Kraken) GetOpenOrders(showTrades bool, userref int64) (interface{}, error) {
values := url.Values{}
func (k *Kraken) GetOpenOrders(args ...OrderInfoOptions) (OpenOrders, error) {
params := url.Values{}
if showTrades {
values.Set("trades", "true")
if args[0].Trades {
params.Set("trades", "true")
}
if userref != 0 {
values.Set("userref", strconv.FormatInt(userref, 10))
if args[0].UserRef != 0 {
params.Set("userref", strconv.FormatInt(int64(args[0].UserRef), 10))
}
return k.SendAuthenticatedHTTPRequest(krakenOpenOrders, values)
var response struct {
Error []string `json:"error"`
Result OpenOrders `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenOpenOrders, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// 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{}
func (k *Kraken) GetClosedOrders(args ...GetClosedOrdersOptions) (ClosedOrders, error) {
params := url.Values{}
if showTrades {
values.Set("trades", "true")
if args != nil {
if args[0].Trades {
params.Set("trades", "true")
}
if args[0].UserRef != 0 {
params.Set("userref", strconv.FormatInt(int64(args[0].UserRef), 10))
}
if len(args[0].Start) != 0 {
params.Set("start", args[0].Start)
}
if len(args[0].End) != 0 {
params.Set("end", args[0].End)
}
if args[0].Ofs != 0 {
params.Set("ofs", strconv.FormatInt(args[0].Ofs, 10))
}
if len(args[0].CloseTime) != 0 {
params.Set("closetime", args[0].CloseTime)
}
}
if userref != 0 {
values.Set("userref", strconv.FormatInt(userref, 10))
var response struct {
Error []string `json:"error"`
Result ClosedOrders `json:"result"`
}
if start != 0 {
values.Set("start", strconv.FormatInt(start, 10))
if err := k.SendAuthenticatedHTTPRequest(krakenClosedOrders, params, &response); err != nil {
return response.Result, err
}
if end != 0 {
values.Set("end", strconv.FormatInt(end, 10))
}
if offset != 0 {
values.Set("ofs", strconv.FormatInt(offset, 10))
}
if len(closetime) > 0 {
values.Set("closetime", closetime)
}
return k.SendAuthenticatedHTTPRequest(krakenClosedOrders, values)
return response.Result, GetError(response.Error)
}
// QueryOrdersInfo returns order information
func (k *Kraken) QueryOrdersInfo(showTrades bool, userref, txid int64) (interface{}, error) {
values := url.Values{}
if showTrades {
values.Set("trades", "true")
func (k *Kraken) QueryOrdersInfo(args OrderInfoOptions, txid string, txids ...string) (map[string]OrderInfo, error) {
params := url.Values{
"txid": {txid},
}
if userref != 0 {
values.Set("userref", strconv.FormatInt(userref, 10))
if txids != nil {
params.Set("txid", txid+","+strings.Join(txids, ","))
}
if txid != 0 {
values.Set("txid", strconv.FormatInt(userref, 10))
if args.Trades {
params.Set("trades", "true")
}
return k.SendAuthenticatedHTTPRequest(krakenQueryOrders, values)
if args.UserRef != 0 {
params.Set("userref", strconv.FormatInt(int64(args.UserRef), 10))
}
var response struct {
Error []string `json:"error"`
Result map[string]OrderInfo `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenQueryOrders, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// GetTradesHistory returns trade history information
func (k *Kraken) GetTradesHistory(tradeType string, showRelatedTrades bool, start, end, offset int64) (interface{}, error) {
values := url.Values{}
func (k *Kraken) GetTradesHistory(args ...GetTradesHistoryOptions) (TradesHistory, error) {
params := url.Values{}
if len(tradeType) > 0 {
values.Set("aclass", tradeType)
if args != nil {
if len(args[0].Type) != 0 {
params.Set("type", args[0].Type)
}
if args[0].Trades {
params.Set("trades", "true")
}
if len(args[0].Start) != 0 {
params.Set("start", args[0].Start)
}
if len(args[0].End) != 0 {
params.Set("end", args[0].End)
}
if args[0].Ofs != 0 {
params.Set("ofs", strconv.FormatInt(args[0].Ofs, 10))
}
}
if showRelatedTrades {
values.Set("trades", "true")
var response struct {
Error []string `json:"error"`
Result TradesHistory `json:"result"`
}
if start != 0 {
values.Set("start", strconv.FormatInt(start, 10))
if err := k.SendAuthenticatedHTTPRequest(krakenTradeHistory, params, &response); err != nil {
return response.Result, err
}
if end != 0 {
values.Set("end", strconv.FormatInt(end, 10))
}
if offset != 0 {
values.Set("offset", strconv.FormatInt(offset, 10))
}
return k.SendAuthenticatedHTTPRequest(krakenTradeHistory, values)
return response.Result, GetError(response.Error)
}
// 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))
if showRelatedTrades {
values.Set("trades", "true")
func (k *Kraken) QueryTrades(trades bool, txid string, txids ...string) (map[string]TradeInfo, error) {
params := url.Values{
"txid": {txid},
}
return k.SendAuthenticatedHTTPRequest(krakenQueryTrades, values)
if trades {
params.Set("trades", "true")
}
if txids != nil {
params.Set("txid", txid+","+strings.Join(txids, ","))
}
var response struct {
Error []string `json:"error"`
Result map[string]TradeInfo `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenQueryTrades, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// 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))
func (k *Kraken) OpenPositions(docalcs bool, txids ...string) (map[string]Position, error) {
params := url.Values{}
if showPL {
values.Set("docalcs", "true")
if txids != nil {
params.Set("txid", strings.Join(txids, ","))
}
return k.SendAuthenticatedHTTPRequest(krakenOpenPositions, values)
if docalcs {
params.Set("docalcs", "true")
}
var response struct {
Error []string `json:"error"`
Result map[string]Position `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenOpenPositions, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// GetLedgers returns current ledgers
func (k *Kraken) GetLedgers(symbol, asset, ledgerType string, start, end, offset int64) (interface{}, error) {
values := url.Values{}
func (k *Kraken) GetLedgers(args ...GetLedgersOptions) (Ledgers, error) {
params := url.Values{}
if len(symbol) > 0 {
values.Set("aclass", symbol)
if args != nil {
if len(args[0].Aclass) != 0 {
params.Set("aclass", args[0].Aclass)
}
if len(args[0].Asset) != 0 {
params.Set("asset", args[0].Asset)
}
if len(args[0].Type) != 0 {
params.Set("type", args[0].Type)
}
if len(args[0].Start) != 0 {
params.Set("start", args[0].Start)
}
if len(args[0].End) != 0 {
params.Set("end", args[0].End)
}
if args[0].Ofs != 0 {
params.Set("ofs", strconv.FormatInt(args[0].Ofs, 10))
}
}
if len(asset) > 0 {
values.Set("asset", asset)
var response struct {
Error []string `json:"error"`
Result Ledgers `json:"result"`
}
if len(ledgerType) > 0 {
values.Set("type", ledgerType)
if err := k.SendAuthenticatedHTTPRequest(krakenLedgers, params, &response); err != nil {
return response.Result, err
}
if start != 0 {
values.Set("start", strconv.FormatInt(start, 10))
}
if end != 0 {
values.Set("end", strconv.FormatInt(end, 10))
}
if offset != 0 {
values.Set("offset", strconv.FormatInt(offset, 10))
}
return k.SendAuthenticatedHTTPRequest(krakenLedgers, values)
return response.Result, GetError(response.Error)
}
// QueryLedgers queries an individual ledger by ID
func (k *Kraken) QueryLedgers(id string) (interface{}, error) {
values := url.Values{}
values.Set("id", id)
func (k *Kraken) QueryLedgers(id string, ids ...string) (map[string]LedgerInfo, error) {
params := url.Values{
"id": {id},
}
return k.SendAuthenticatedHTTPRequest(krakenQueryLedgers, values)
if ids != nil {
params.Set("id", id+","+strings.Join(ids, ","))
}
var response struct {
Error []string `json:"error"`
Result map[string]LedgerInfo `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenQueryLedgers, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// GetTradeVolume returns your trade volume by currency
func (k *Kraken) GetTradeVolume(symbol string) (interface{}, error) {
values := url.Values{}
values.Set("pair", symbol)
func (k *Kraken) GetTradeVolume(feeinfo bool, symbol ...string) (TradeVolumeResponse, error) {
params := url.Values{}
return k.SendAuthenticatedHTTPRequest(krakenTradeVolume, values)
if symbol != nil {
params.Set("pair", strings.Join(symbol, ","))
}
if feeinfo {
params.Set("fee-info", "true")
}
var response struct {
Error []string `json:"error"`
Result TradeVolumeResponse `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenTradeVolume, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// 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)
values.Set("ordertype", orderType)
values.Set("price", strconv.FormatFloat(price, 'f', -1, 64))
values.Set("price2", strconv.FormatFloat(price, 'f', -1, 64))
values.Set("volume", strconv.FormatFloat(volume, 'f', -1, 64))
values.Set("leverage", strconv.FormatFloat(leverage, 'f', -1, 64))
values.Set("position", strconv.FormatFloat(position, 'f', -1, 64))
func (k *Kraken) AddOrder(symbol, side, orderType string, volume, price, price2, leverage float64, args AddOrderOptions) (AddOrderResponse, error) {
params := url.Values{
"pair": {symbol},
"type": {side},
"ordertype": {orderType},
"volume": {strconv.FormatFloat(volume, 'f', -1, 64)},
}
return k.SendAuthenticatedHTTPRequest(krakenOrderPlace, values)
if price != 0 {
params.Set("price", strconv.FormatFloat(price, 'f', -1, 64))
}
if price2 != 0 {
params.Set("price2", strconv.FormatFloat(price2, 'f', -1, 64))
}
if leverage != 0 {
params.Set("leverage", strconv.FormatFloat(leverage, 'f', -1, 64))
}
if len(args.Oflags) != 0 {
params.Set("oflags", args.Oflags)
}
if len(args.StartTm) != 0 {
params.Set("starttm", args.StartTm)
}
if len(args.ExpireTm) != 0 {
params.Set("expiretm", args.ExpireTm)
}
if len(args.CloseOrderType) != 0 {
params.Set("close[ordertype]", args.ExpireTm)
}
if args.ClosePrice != 0 {
params.Set("close[price]", strconv.FormatFloat(args.ClosePrice, 'f', -1, 64))
}
if args.ClosePrice2 != 0 {
params.Set("close[price2]", strconv.FormatFloat(args.ClosePrice2, 'f', -1, 64))
}
if args.Validate {
params.Set("validate", "true")
}
var response struct {
Error []string `json:"error"`
Result AddOrderResponse `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenOrderPlace, params, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// CancelOrder cancels order by orderID
func (k *Kraken) CancelOrder(orderID int64) (interface{}, error) {
values := url.Values{}
values.Set("txid", strconv.FormatInt(orderID, 10))
func (k *Kraken) CancelOrder(txid string) (CancelOrderResponse, error) {
values := url.Values{
"txid": {txid},
}
return k.SendAuthenticatedHTTPRequest(krakenOrderCancel, values)
var response struct {
Error []string `json:"error"`
Result CancelOrderResponse `json:"result"`
}
if err := k.SendAuthenticatedHTTPRequest(krakenOrderCancel, values, &response); err != nil {
return response.Result, err
}
return response.Result, GetError(response.Error)
}
// GetError parse Exchange errors in response and return the first one
// Error format from API doc:
// error = array of error messages in the format of:
// <char-severity code><string-error category>:<string-error type>[:<string-extra info>]
// severity code can be E for error or W for warning
func GetError(errors []string) error {
for _, e := range errors {
switch e[0] {
case 'W':
log.Printf("Kraken API warning: %v\n", e[1:])
default:
return fmt.Errorf("Kraken API error: %v", e[1:])
}
}
return nil
}
// SendHTTPRequest sends an unauthenticated HTTP requests
@@ -581,9 +806,9 @@ func (k *Kraken) SendHTTPRequest(path string, result interface{}) error {
}
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request
func (k *Kraken) SendAuthenticatedHTTPRequest(method string, values url.Values) (interface{}, error) {
func (k *Kraken) SendAuthenticatedHTTPRequest(method string, params url.Values, result interface{}) (err error) {
if !k.AuthenticatedAPISupport {
return nil, fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, k.Name)
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, k.Name)
}
path := fmt.Sprintf("/%s/private/%s", krakenAPIVersion, method)
@@ -593,35 +818,24 @@ func (k *Kraken) SendAuthenticatedHTTPRequest(method string, values url.Values)
k.Nonce.Inc()
}
values.Set("nonce", k.Nonce.String())
params.Set("nonce", k.Nonce.String())
secret, err := common.Base64Decode(k.APISecret)
if err != nil {
return nil, err
return err
}
shasum := common.GetSHA256([]byte(values.Get("nonce") + values.Encode()))
encoded := params.Encode()
shasum := common.GetSHA256([]byte(params.Get("nonce") + encoded))
signature := common.Base64Encode(common.GetHMAC(common.HashSHA512, append([]byte(path), shasum...), secret))
if k.Verbose {
log.Printf("Sending POST request to %s, path: %s.", krakenAPIURL, path)
log.Printf("Sending POST request to %s, path: %s, params: %s", krakenAPIURL, path, encoded)
}
headers := make(map[string]string)
headers["API-Key"] = k.APIKey
headers["API-Sign"] = signature
var resp interface{}
err = k.SendPayload("POST", krakenAPIURL+path, headers, strings.NewReader(values.Encode()), &resp, true, k.Verbose)
if err != nil {
return resp, 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
return k.SendPayload("POST", krakenAPIURL+path, headers, strings.NewReader(encoded), result, true, k.Verbose)
}

View File

@@ -47,11 +47,7 @@ func TestGetFee(t *testing.T) {
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)
_, err := k.GetServerTime()
if err != nil {
t.Error("Test Failed - GetServerTime() error", err)
}
@@ -123,7 +119,8 @@ func TestGetBalance(t *testing.T) {
func TestGetTradeBalance(t *testing.T) {
t.Parallel()
_, err := k.GetTradeBalance("", "")
args := TradeBalanceOptions{Asset: "ZEUR"}
_, err := k.GetTradeBalance(args)
if err == nil {
t.Error("Test Failed - GetTradeBalance() error", err)
}
@@ -131,7 +128,8 @@ func TestGetTradeBalance(t *testing.T) {
func TestGetOpenOrders(t *testing.T) {
t.Parallel()
_, err := k.GetOpenOrders(true, 0)
args := OrderInfoOptions{Trades: true}
_, err := k.GetOpenOrders(args)
if err == nil {
t.Error("Test Failed - GetOpenOrders() error", err)
}
@@ -139,7 +137,8 @@ func TestGetOpenOrders(t *testing.T) {
func TestGetClosedOrders(t *testing.T) {
t.Parallel()
_, err := k.GetClosedOrders(true, 0, 0, 0, 0, "")
args := GetClosedOrdersOptions{Trades: true, Start: "OE4KV4-4FVQ5-V7XGPU"}
_, err := k.GetClosedOrders(args)
if err == nil {
t.Error("Test Failed - GetClosedOrders() error", err)
}
@@ -147,7 +146,8 @@ func TestGetClosedOrders(t *testing.T) {
func TestQueryOrdersInfo(t *testing.T) {
t.Parallel()
_, err := k.QueryOrdersInfo(false, 0, 0)
args := OrderInfoOptions{Trades: true}
_, err := k.QueryOrdersInfo(args, "OR6ZFV-AA6TT-CKFFIW", "OAMUAJ-HLVKG-D3QJ5F")
if err == nil {
t.Error("Test Failed - QueryOrdersInfo() error", err)
}
@@ -155,7 +155,8 @@ func TestQueryOrdersInfo(t *testing.T) {
func TestGetTradesHistory(t *testing.T) {
t.Parallel()
_, err := k.GetTradesHistory("", false, 0, 0, 0)
args := GetTradesHistoryOptions{Trades: true, Start: "TMZEDR-VBJN2-NGY6DX", End: "TVRXG2-R62VE-RWP3UW"}
_, err := k.GetTradesHistory(args)
if err == nil {
t.Error("Test Failed - GetTradesHistory() error", err)
}
@@ -163,7 +164,7 @@ func TestGetTradesHistory(t *testing.T) {
func TestQueryTrades(t *testing.T) {
t.Parallel()
_, err := k.QueryTrades(0, false)
_, err := k.QueryTrades(true, "TMZEDR-VBJN2-NGY6DX", "TFLWIB-KTT7L-4TWR3L", "TDVRAH-2H6OS-SLSXRX")
if err == nil {
t.Error("Test Failed - QueryTrades() error", err)
}
@@ -171,7 +172,7 @@ func TestQueryTrades(t *testing.T) {
func TestOpenPositions(t *testing.T) {
t.Parallel()
_, err := k.OpenPositions(0, false)
_, err := k.OpenPositions(false)
if err == nil {
t.Error("Test Failed - OpenPositions() error", err)
}
@@ -179,7 +180,8 @@ func TestOpenPositions(t *testing.T) {
func TestGetLedgers(t *testing.T) {
t.Parallel()
_, err := k.GetLedgers("bla", "bla", "bla", 0, 0, 0)
args := GetLedgersOptions{Start: "LRUHXI-IWECY-K4JYGO", End: "L5NIY7-JZQJD-3J4M2V", Ofs: 15}
_, err := k.GetLedgers(args)
if err == nil {
t.Error("Test Failed - GetLedgers() error", err)
}
@@ -187,7 +189,7 @@ func TestGetLedgers(t *testing.T) {
func TestQueryLedgers(t *testing.T) {
t.Parallel()
_, err := k.QueryLedgers("1337")
_, err := k.QueryLedgers("LVTSFS-NHZVM-EXNZ5M")
if err == nil {
t.Error("Test Failed - QueryLedgers() error", err)
}
@@ -195,7 +197,7 @@ func TestQueryLedgers(t *testing.T) {
func TestGetTradeVolume(t *testing.T) {
t.Parallel()
_, err := k.GetTradeVolume("BCHEUR")
_, err := k.GetTradeVolume(true, "OAVY7T-MV5VK-KHDF5X")
if err == nil {
t.Error("Test Failed - GetTradeVolume() error", err)
}
@@ -203,7 +205,8 @@ func TestGetTradeVolume(t *testing.T) {
func TestAddOrder(t *testing.T) {
t.Parallel()
_, err := k.AddOrder("bla", "bla", "bla", 0, 0, 0, 0, 0)
args := AddOrderOptions{Oflags: "fcib"}
_, err := k.AddOrder("XXBTZUSD", "sell", "market", 0.00000001, 0, 0, 0, args)
if err == nil {
t.Error("Test Failed - AddOrder() error", err)
}
@@ -211,7 +214,7 @@ func TestAddOrder(t *testing.T) {
func TestCancelOrder(t *testing.T) {
t.Parallel()
_, err := k.CancelOrder(1337)
_, err := k.CancelOrder("OAVY7T-MV5VK-KHDF5X")
if err == nil {
t.Error("Test Failed - CancelOrder() error", err)
}

View File

@@ -1,9 +1,17 @@
package kraken
// GeneralResponse is a generalized response type
type GeneralResponse struct {
Result map[string]interface{} `json:"result"`
Error []interface{} `json:"error"`
// TimeResponse type
type TimeResponse struct {
Unixtime int64 `json:"unixtime"`
Rfc1123 string `json:"rfc1123"`
}
// Asset holds asset information
type Asset struct {
Altname string `json:"altname"`
AclassBase string `json:"aclass_base"`
Decimals int `json:"decimals"`
DisplayDecimals int `json:"display_decimals"`
}
// AssetPairs holds asset pair information
@@ -92,3 +100,211 @@ type Spread struct {
Bid float64
Ask float64
}
// TradeBalanceOptions type
type TradeBalanceOptions struct {
Aclass string
Asset string
}
// TradeBalanceInfo type
type TradeBalanceInfo struct {
EquivalentBalance float64 `json:"eb,string"` // combined balance of all currencies
TradeBalance float64 `json:"tb,string"` // combined balance of all equity currencies
MarginAmount float64 `json:"m,string"` // margin amount of open positions
Net float64 `json:"n,string"` // unrealized net profit/loss of open positions
Equity float64 `json:"e,string"` // trade balance + unrealized net profit/loss
FreeMargin float64 `json:"mf,string"` // equity - initial margin (maximum margin available to open new positions)
MarginLevel float64 `json:"ml,string"` // (equity / initial margin) * 100
}
// OrderInfo type
type OrderInfo struct {
RefID string `json:"refid"`
UserRef int32 `json:"userref"`
Status string `json:"status"`
OpenTm float64 `json:"opentm"`
StartTm float64 `json:"starttm"`
ExpireTm float64 `json:"expiretm"`
Descr struct {
Pair string `json:"pair"`
Type string `json:"type"`
OrderType string `json:"ordertype"`
Price float64 `json:"price,string"`
Price2 float64 `json:"price2,string"`
Leverage string `json:"leverage"`
Order string `json:"order"`
Close string `json:"close"`
} `json:"descr"`
Vol float64 `json:"vol,string"`
VolExec float64 `json:"vol_exec,string"`
Cost float64 `json:"cost,string"`
Fee float64 `json:"fee,string"`
Price float64 `json:"price,string"`
StopPrice float64 `json:"stopprice,string"`
LimitPrice float64 `json:"limitprice,string"`
Misc string `json:"misc"`
Oflags string `json:"oflags"`
Trades []string `json:"trades"`
}
// OpenOrders type
type OpenOrders struct {
Open map[string]OrderInfo `json:"open"`
Count int64 `json:"count"`
}
// ClosedOrders type
type ClosedOrders struct {
Closed map[string]OrderInfo `json:"closed"`
Count int64 `json:"count"`
}
// GetClosedOrdersOptions type
type GetClosedOrdersOptions struct {
Trades bool
UserRef int32
Start string
End string
Ofs int64
CloseTime string
}
// OrderInfoOptions type
type OrderInfoOptions struct {
Trades bool
UserRef int32
}
// GetTradesHistoryOptions type
type GetTradesHistoryOptions struct {
Type string
Trades bool
Start string
End string
Ofs int64
}
// TradesHistory type
type TradesHistory struct {
Trades map[string]TradeInfo `json:"trades"`
Count int64 `json:"count"`
}
// TradeInfo type
type TradeInfo struct {
OrderTxID string `json:"ordertxid"`
Pair string `json:"pair"`
Time float64 `json:"time"`
Type string `json:"type"`
OrderType string `json:"ordertype"`
Price float64 `json:"price,string"`
Cost float64 `json:"cost,string"`
Fee float64 `json:"fee,string"`
Vol float64 `json:"vol,string"`
Margin float64 `json:"margin,string"`
Misc string `json:"misc"`
PosTxID string `json:"postxid"`
Cprice float64 `json:"cprice,string"`
Cfee float64 `json:"cfee,string"`
Cvol float64 `json:"cvol,string"`
Cmargin float64 `json:"cmargin,string"`
Trades []string `json:"trades"`
PosStatus string `json:"posstatus"`
}
// Position holds the opened position
type Position struct {
Ordertxid string `json:"ordertxid"`
Pair string `json:"pair"`
Time float64 `json:"time"`
Type string `json:"type"`
OrderType string `json:"ordertype"`
Cost float64 `json:"cost,string"`
Fee float64 `json:"fee,string"`
Vol float64 `json:"vol,string"`
VolClosed float64 `json:"vol_closed,string"`
Margin float64 `json:"margin,string"`
Rollovertm int64 `json:"rollovertm,string"`
Misc string `json:"misc"`
Oflags string `json:"oflags"`
PosStatus string `json:"posstatus"`
Net string `json:"net"`
Terms string `json:"terms"`
}
// GetLedgersOptions type
type GetLedgersOptions struct {
Aclass string
Asset string
Type string
Start string
End string
Ofs int64
}
// Ledgers type
type Ledgers struct {
Ledger map[string]LedgerInfo `json:"ledger"`
Count int64 `json:"count"`
}
// LedgerInfo type
type LedgerInfo struct {
Refid string `json:"refid"`
Time float64 `json:"time"`
Type string `json:"type"`
Aclass string `json:"aclass"`
Asset string `json:"asset"`
Amount float64 `json:"amount,string"`
Fee float64 `json:"fee,string"`
Balance float64 `json:"balance,string"`
}
// TradeVolumeResponse type
type TradeVolumeResponse struct {
Currency string `json:"currency"`
Volume float64 `json:"volume,string"`
Fees map[string]TradeVolumeFee `json:"fees"`
FeesMaker map[string]TradeVolumeFee `json:"fees_maker"`
}
// TradeVolumeFee type
type TradeVolumeFee struct {
Fee float64 `json:"fee,string"`
MinFee float64 `json:"minfee,string"`
MaxFee float64 `json:"maxfee,string"`
NextFee float64 `json:"nextfee,string"`
NextVolume float64 `json:"nextvolume,string"`
TierVolume float64 `json:"tiervolume,string"`
}
// AddOrderResponse type
type AddOrderResponse struct {
Description OrderDescription `json:"descr"`
TransactionIds []string `json:"txid"`
}
// OrderDescription represents an orders description
type OrderDescription struct {
Close string `json:"close"`
Order string `json:"order"`
}
// AddOrderOptions represents the AddOrder options
type AddOrderOptions struct {
UserRef int32
Oflags string
StartTm string
ExpireTm string
CloseOrderType string
ClosePrice float64
ClosePrice2 float64
Validate bool
}
// CancelOrderResponse type
type CancelOrderResponse struct {
Count int64 `json:"count"`
Pending interface{} `json:"pending"`
}

View File

@@ -341,37 +341,57 @@ func (l *LocalBitcoins) GetCurrencies() error {
// 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{}
func (l *LocalBitcoins) GetDashboardInfo() ([]DashBoardInfo, error) {
var resp struct {
Data struct {
ContactList []DashBoardInfo `json:"contact_list"`
ContactCount int `json:"contact_count"`
}
}
return resp,
return resp.Data.ContactList,
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{}
func (l *LocalBitcoins) GetDashboardReleasedTrades() ([]DashBoardInfo, error) {
var resp struct {
Data struct {
ContactList []DashBoardInfo `json:"contact_list"`
ContactCount int `json:"contact_count"`
}
}
return resp,
return resp.Data.ContactList,
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{}
func (l *LocalBitcoins) GetDashboardCancelledTrades() ([]DashBoardInfo, error) {
var resp struct {
Data struct {
ContactList []DashBoardInfo `json:"contact_list"`
ContactCount int `json:"contact_count"`
}
}
return resp,
return resp.Data.ContactList,
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{}
func (l *LocalBitcoins) GetDashboardClosedTrades() ([]DashBoardInfo, error) {
var resp struct {
Data struct {
ContactList []DashBoardInfo `json:"contact_list"`
ContactCount int `json:"contact_count"`
}
}
return resp,
return resp.Data.ContactList,
l.SendAuthenticatedHTTPRequest("GET", localbitcoinsAPIDashboardClosed, nil, &resp)
}

View File

@@ -189,7 +189,7 @@ type DashBoardInfo struct {
Buyer struct {
Username string `json:"username"`
TradeCount string `json:"trade_count"`
FeedbackScore string `json:"feedback_score"`
FeedbackScore int `json:"feedback_score"`
Name string `json:"name"`
LastOnline string `json:"last_online"`
RealName string `json:"real_name"`
@@ -200,7 +200,7 @@ type DashBoardInfo struct {
Seller struct {
Username string `json:"username"`
TradeCount string `json:"trade_count"`
FeedbackScore string `json:"feedback_score"`
FeedbackScore int `json:"feedback_score"`
Name string `json:"name"`
LastOnline string `json:"last_online"`
} `json:"seller"`
@@ -216,7 +216,7 @@ type DashBoardInfo struct {
Advertiser struct {
Username string `json:"username"`
TradeCount string `json:"trade_count"`
FeedbackScore string `json:"feedback_score"`
FeedbackScore int `json:"feedback_score"`
Name string `json:"name"`
LastOnline string `json:"last_online"`
} `json:"advertiser"`