Bitfinex: Implement leaderboard API (#458)

* Bitfinex: Implement leaderboard API

* Expand test coverage

* fix grammer
This commit is contained in:
Adrian Gallagher
2020-03-05 08:40:23 +11:00
committed by GitHub
parent b686cf2e0e
commit ba07c86af9
3 changed files with 122 additions and 5 deletions

View File

@@ -57,6 +57,7 @@ const (
bitfinexMarginClose = "funding/close"
bitfinexLendbook = "lendbook/"
bitfinexLends = "lends/"
bitfinexLeaderboard = "rankings"
// Version 2 API endpoints
bitfinexAPIVersion2 = "/v2/"
@@ -506,11 +507,73 @@ func (b *Bitfinex) GetLiquidationFeed() error {
return common.ErrNotYetImplemented
}
// GetLeaderBoard returns leaderboard standings for unrealized
// profit (period delta), unrealized profit (inception), volume, and realized
// profit.
func (b *Bitfinex) GetLeaderBoard() error {
return common.ErrNotYetImplemented
// GetLeaderboard returns leaderboard standings for unrealized profit (period
// delta), unrealized profit (inception), volume, and realized profit.
// Allowed key values: "plu_diff" for unrealized profit (period delta), "plu"
// for unrealized profit (inception); "vol" for volume; "plr" for realized
// profit
// Allowed time frames are 3h, 1w and 1M
// Allowed symbols are trading pairs (e.g. tBTCUSD, tETHUSD and tGLOBAL:USD)
func (b *Bitfinex) GetLeaderboard(key, timeframe, symbol string, sort, limit int, start, end string) ([]LeaderboardEntry, error) {
validLeaderboardKey := func(input string) bool {
switch input {
case LeaderboardUnrealisedProfitPeriodDelta,
LeaderboardUnrealisedProfitInception,
LeaderboardVolume,
LeaderbookRealisedProfit:
return true
default:
return false
}
}
if !validLeaderboardKey(key) {
return nil, errors.New("invalid leaderboard key")
}
path := fmt.Sprintf("%s/%s:%s:%s/hist", b.API.Endpoints.URL+bitfinexAPIVersion2+bitfinexLeaderboard,
key,
timeframe,
symbol)
vals := url.Values{}
if sort != 0 {
vals.Set("sort", strconv.Itoa(sort))
}
if limit != 0 {
vals.Set("limit", strconv.Itoa(limit))
}
if start != "" {
vals.Set("start", start)
}
if end != "" {
vals.Set("end", end)
}
path = common.EncodeURLValues(path, vals)
var resp []interface{}
if err := b.SendHTTPRequest(path, &resp, leaderBoardReqRate); err != nil {
return nil, err
}
parseTwitterHandle := func(i interface{}) string {
r, ok := i.(string)
if !ok {
return ""
}
return r
}
var result []LeaderboardEntry
for x := range resp {
r := resp[x].([]interface{})
result = append(result, LeaderboardEntry{
Timestamp: time.Unix(0, int64(r[0].(float64))*int64(time.Millisecond)),
Username: r[2].(string),
Ranking: int(r[3].(float64)),
Value: r[6].(float64),
TwitterHandle: parseTwitterHandle(r[9]),
})
}
return result, nil
}
// GetMarketAveragePrice calculates the average execution price for Trading or

View File

@@ -159,6 +159,41 @@ func TestGetCandles(t *testing.T) {
}
}
func TestGetLeaderboard(t *testing.T) {
t.Parallel()
// Test invalid key
_, err := b.GetLeaderboard("", "", "", 0, 0, "", "")
if err == nil {
t.Error("an error should have been thrown for an invalid key")
}
// Test default
_, err = b.GetLeaderboard(LeaderboardUnrealisedProfitInception,
"1M",
"tGLOBAL:USD",
0,
0,
"",
"")
if err != nil {
t.Fatal(err)
}
// Test params
var result []LeaderboardEntry
result, err = b.GetLeaderboard(LeaderboardUnrealisedProfitInception,
"1M",
"tGLOBAL:USD",
-1,
1000,
"1582695181661",
"1583299981661")
if err != nil {
t.Fatal(err)
}
if len(result) == 0 {
t.Error("should have retrieved leaderboard data")
}
}
func TestGetAccountFees(t *testing.T) {
if !areTestAPIKeysSet() {
t.SkipNow()

View File

@@ -1,5 +1,7 @@
package bitfinex
import "time"
// AcceptedOrderType defines the accepted market types, exchange strings denote
// non-contract order types.
var AcceptedOrderType = []string{"market", "limit", "stop", "trailing-stop",
@@ -394,6 +396,23 @@ type Candle struct {
Volume float64
}
// Leaderboard keys
const (
LeaderboardUnrealisedProfitPeriodDelta = "plu_diff"
LeaderboardUnrealisedProfitInception = "plu"
LeaderboardVolume = "vol"
LeaderbookRealisedProfit = "plr"
)
// LeaderboardEntry holds leaderboard data
type LeaderboardEntry struct {
Timestamp time.Time
Username string
Ranking int
Value float64
TwitterHandle string
}
// WebsocketTicker holds ticker information
type WebsocketTicker struct {
Bid float64