mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
Bitfinex: Implement UpdateOrderExecutionLimits and tests (#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
This commit is contained in:
@@ -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"
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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{}
|
||||
|
||||
@@ -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")
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user