mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
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:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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"`
|
||||
|
||||
Reference in New Issue
Block a user