Skip to content

Commit

Permalink
Bitfinex: Implement UpdateOrderExecutionLimits and tests (thrasher-co…
Browse files Browse the repository at this point in the history
…rp#1269)

* Bitfinex: Order Execution Limits and Testing

* Bitfinex: added proposed changes

* Bitfinex: lint fixes- removed the unnecessary whitespace and replaced the value with indexing

* Bitfinex: Moved data len check before the string conversion, moved the error for the array conversion before the info len check

* Bitfinex: Change GetSiteInfoConfigData to return slice, add tests

* Bitfinex: Fixed lint issue by preallocating pairs
  • Loading branch information
Beadko authored Jul 31, 2023
1 parent 123ec8c commit 0cae2ad
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 15 deletions.
73 changes: 71 additions & 2 deletions exchanges/bitfinex/bitfinex.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"time"

"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/common/crypto"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
Expand Down Expand Up @@ -88,6 +89,9 @@ const (
bitfinexFuturesPairs = "conf/pub:list:pair:futures" // TODO: Implement
bitfinexSecuritiesPairs = "conf/pub:list:pair:securities" // TODO: Implement

bitfinexInfoPairs = "conf/pub:info:pair"
bitfinexInfoFuturePairs = "conf/pub:info:pair:futures"

// Bitfinex platform status values
// When the platform is marked in maintenance mode bots should stop trading
// activity. Cancelling orders will be possible.
Expand Down Expand Up @@ -470,10 +474,9 @@ func (b *Bitfinex) GetPairs(ctx context.Context, a asset.Item) ([]string, error)
}
}

// GetSiteListConfigData returns site configuration data by pub:{Action}:{Object}:{Detail}
// GetSiteListConfigData returns site configuration data by pub:list:{Object}:{Detail}
// string sets.
// NOTE: See https://docs.bitfinex.com/reference/rest-public-conf
// ALSO: This only accesses the lists not the maps.
func (b *Bitfinex) GetSiteListConfigData(ctx context.Context, set string) ([]string, error) {
if set == "" {
return nil, errSetCannotBeEmpty
Expand All @@ -491,6 +494,72 @@ func (b *Bitfinex) GetSiteListConfigData(ctx context.Context, set string) ([]str
return resp[0], nil
}

// GetSiteInfoConfigData returns site configuration data by pub:info:{AssetType} as a map
// path should be bitfinexInfoPairs or bitfinexInfoPairsFuture???
// NOTE: See https://docs.bitfinex.com/reference/rest-public-conf
func (b *Bitfinex) GetSiteInfoConfigData(ctx context.Context, assetType asset.Item) ([]order.MinMaxLevel, error) {
var path string
switch assetType {
case asset.Spot:
path = bitfinexInfoPairs
case asset.Futures:
path = bitfinexInfoFuturePairs
default:
return nil, fmt.Errorf("invalid asset type for GetSiteInfoConfigData: %s", assetType)
}
url := bitfinexAPIVersion2 + path
var resp [][][]any

err := b.SendHTTPRequest(ctx, exchange.RestSpot, url, &resp, status)
if err != nil {
return nil, err
}
if len(resp) != 1 {
return nil, errors.New("response did not contain only one item")
}
data := resp[0]
pairs := make([]order.MinMaxLevel, 0, len(data))
for i := range data {
if len(data[i]) != 2 {
return nil, errors.New("response contained a tuple without exactly 2 items")
}
pairSymbol, ok := data[i][0].(string)
if !ok {
return nil, fmt.Errorf("could not convert first item in SiteInfoConfigData to string: Type is %T", data[i][0])
}
if strings.Contains(pairSymbol, "TEST") {
continue
}
// SIC: Array type really is any. It contains nils and strings
info, ok := data[i][1].([]any)
if !ok {
return nil, fmt.Errorf("could not convert second item in SiteInfoConfigData to []any; Type is %T", data[i][1])
}
if len(info) < 5 {
return nil, errors.New("response contained order info with less than 5 elements")
}
minOrder, err := convert.FloatFromString(info[3])
if err != nil {
return nil, fmt.Errorf("could not convert MinOrderAmount: %s", err)
}
maxOrder, err := convert.FloatFromString(info[4])
if err != nil {
return nil, fmt.Errorf("could not convert MaxOrderAmount: %s", err)
}
pair, err := currency.NewPairFromString(pairSymbol)
if err != nil {
return nil, err
}
pairs = append(pairs, order.MinMaxLevel{
Asset: assetType,
Pair: pair,
MinimumBaseAmount: minOrder,
MaximumBaseAmount: maxOrder,
})
}
return pairs, nil
}

// GetDerivativeStatusInfo gets status data for the queried derivative
func (b *Bitfinex) GetDerivativeStatusInfo(ctx context.Context, keys, startTime, endTime string, sort, limit int64) ([]DerivativeDataResponse, error) {
params := url.Values{}
Expand Down
46 changes: 46 additions & 0 deletions exchanges/bitfinex/bitfinex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,39 @@ func TestGetPairs(t *testing.T) {
}
}

func TestUpdateTradablePairs(t *testing.T) {
t.Parallel()
if err := b.UpdateTradablePairs(context.Background(), true); err != nil {
t.Error("Bitfinex UpdateTradablePairs() error", err)
}
}

func TestUpdateOrderExecutionLimits(t *testing.T) {
t.Parallel()
tests := map[asset.Item][]currency.Pair{
asset.Spot: {
currency.NewPair(currency.ETH, currency.UST),
currency.NewPair(currency.BTC, currency.UST),
},
}
for assetItem, pairs := range tests {
if err := b.UpdateOrderExecutionLimits(context.Background(), assetItem); err != nil {
t.Errorf("Error fetching %s pairs for test: %v", assetItem, err)
continue
}
for _, pair := range pairs {
limits, err := b.GetOrderExecutionLimits(assetItem, pair)
if err != nil {
t.Errorf("GetOrderExecutionLimits() error during TestExecutionLimits; Asset: %s Pair: %s Err: %v", assetItem, pair, err)
continue
}
if limits.MinimumBaseAmount == 0 {
t.Errorf("UpdateOrderExecutionLimits empty minimum base amount; Pair: %s Expected Limit: %v", pair, limits.MinimumBaseAmount)
}
}
}
}

func TestAppendOptionalDelimiter(t *testing.T) {
t.Parallel()
curr1, err := currency.NewPairFromString("BTCUSD")
Expand Down Expand Up @@ -1773,6 +1806,19 @@ func TestGetSiteListConfigData(t *testing.T) {
}
}

func TestGetSiteInfoConfigData(t *testing.T) {
t.Parallel()
for _, assetType := range []asset.Item{asset.Spot, asset.Futures} {
pairs, err := b.GetSiteInfoConfigData(context.Background(), assetType)
if !errors.Is(err, nil) {
t.Errorf("Error from GetSiteInfoConfigData for %s type received: %v, expected: %v", assetType, err, nil)
}
if len(pairs) == 0 {
t.Errorf("GetSiteInfoConfigData returned no pairs for %s", assetType)
}
}
}

func TestOrderUpdate(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
Expand Down
11 changes: 0 additions & 11 deletions exchanges/bitfinex/bitfinex_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,17 +221,6 @@ type Lends struct {
Timestamp int64 `json:"timestamp"`
}

// SymbolDetails holds currency pair information
type SymbolDetails struct {
Pair string `json:"pair"`
PricePrecision int `json:"price_precision"`
InitialMargin float64 `json:"initial_margin,string"`
MinimumMargin float64 `json:"minimum_margin,string"`
MaximumOrderSize float64 `json:"maximum_order_size,string"`
MinimumOrderSize float64 `json:"minimum_order_size,string"`
Expiration string `json:"expiration"`
}

// AccountInfoFull adds the error message to Account info
type AccountInfoFull struct {
Info []AccountInfo
Expand Down
29 changes: 27 additions & 2 deletions exchanges/bitfinex/bitfinex_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,18 @@ func (b *Bitfinex) Run(ctx context.Context) {
b.PrintEnabledPairs()
}

if !b.GetEnabledFeatures().AutoPairUpdates {
return
if b.GetEnabledFeatures().AutoPairUpdates {
if err := b.UpdateTradablePairs(ctx, false); err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
b.Name,
err)
}
}
for _, a := range b.GetAssetTypes(true) {
if err := b.UpdateOrderExecutionLimits(ctx, a); err != nil && err != common.ErrNotYetImplemented {
log.Errorln(log.ExchangeSys, err.Error())
}
}

err := b.UpdateTradablePairs(ctx, false)
Expand Down Expand Up @@ -322,6 +332,21 @@ func (b *Bitfinex) UpdateTradablePairs(ctx context.Context, forceUpdate bool) er
return b.EnsureOnePairEnabled()
}

// UpdateOrderExecutionLimits sets exchange execution order limits for an asset type
func (b *Bitfinex) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) error {
if a != asset.Spot {
return common.ErrNotYetImplemented
}
limits, err := b.GetSiteInfoConfigData(ctx, a)
if err != nil {
return err
}
if err := b.LoadLimits(limits); err != nil {
return fmt.Errorf("%s Error loading exchange limits: %v", b.Name, err)
}
return nil
}

// UpdateTickers updates the ticker for all currency pairs of a given asset type
func (b *Bitfinex) UpdateTickers(ctx context.Context, a asset.Item) error {
enabled, err := b.GetEnabledPairs(a)
Expand Down

0 comments on commit 0cae2ad

Please sign in to comment.