Binance: Fixes expiring futures contract pair formatting (#836)

* Fixes expiring contract formatting

* minor simplification

* shazniterinos

* Removes secret scientific test

* continue to address nits

* Shazniterinos

* Adds `bypassConfigFormatUpgrades` feature. Fixes Binance pair parsing.

* lint fix

* Adds test for binance func

* Consistent messaging and oopsie fix
This commit is contained in:
Scott
2021-11-16 15:02:31 +11:00
committed by GitHub
parent 25e9d284d0
commit 7c7aebe22f
17 changed files with 661 additions and 373 deletions

View File

@@ -8,12 +8,13 @@ import (
// PairsManager manages asset pairs
type PairsManager struct {
RequestFormat *PairFormat `json:"requestFormat,omitempty"`
ConfigFormat *PairFormat `json:"configFormat,omitempty"`
UseGlobalFormat bool `json:"useGlobalFormat,omitempty"`
LastUpdated int64 `json:"lastUpdated,omitempty"`
Pairs map[asset.Item]*PairStore `json:"pairs"`
m sync.RWMutex
BypassConfigFormatUpgrades bool `json:"bypassConfigFormatUpgrades"`
RequestFormat *PairFormat `json:"requestFormat,omitempty"`
ConfigFormat *PairFormat `json:"configFormat,omitempty"`
UseGlobalFormat bool `json:"useGlobalFormat,omitempty"`
LastUpdated int64 `json:"lastUpdated,omitempty"`
Pairs map[asset.Item]*PairStore `json:"pairs"`
m sync.RWMutex
}
// PairStore stores a currency pair store

View File

@@ -172,7 +172,7 @@ func TestUExchangeInfo(t *testing.T) {
func TestUFuturesOrderbook(t *testing.T) {
t.Parallel()
_, err := b.UFuturesOrderbook(context.Background(), currency.Pair{Delimiter: "_", Base: currency.BTC, Quote: currency.USDT}, 1000)
_, err := b.UFuturesOrderbook(context.Background(), currency.NewPair(currency.BTC, currency.USDT), 1000)
if err != nil {
t.Error(err)
}
@@ -2647,3 +2647,139 @@ func TestWsOutboundAccountPosition(t *testing.T) {
t.Fatal(err)
}
}
func TestFormatExchangeCurrency(t *testing.T) {
t.Parallel()
type testos struct {
name string
pair currency.Pair
asset asset.Item
expectedDelimiter string
}
testerinos := []testos{
{
name: "spot-btcusdt",
pair: currency.NewPairWithDelimiter("BTC", "USDT", currency.UnderscoreDelimiter),
asset: asset.Spot,
expectedDelimiter: "",
},
{
name: "coinmarginedfutures-btcusd_perp",
pair: currency.NewPairWithDelimiter("BTCUSD", "PERP", currency.DashDelimiter),
asset: asset.CoinMarginedFutures,
expectedDelimiter: currency.UnderscoreDelimiter,
},
{
name: "coinmarginedfutures-btcusd_211231",
pair: currency.NewPairWithDelimiter("BTCUSD", "211231", currency.DashDelimiter),
asset: asset.CoinMarginedFutures,
expectedDelimiter: currency.UnderscoreDelimiter,
},
{
name: "margin-ltousdt",
pair: currency.NewPairWithDelimiter("LTO", "USDT", currency.UnderscoreDelimiter),
asset: asset.Margin,
expectedDelimiter: "",
},
{
name: "usdtmarginedfutures-btcusdt",
pair: currency.NewPairWithDelimiter("btc", "usdt", currency.DashDelimiter),
asset: asset.USDTMarginedFutures,
expectedDelimiter: "",
},
{
name: "usdtmarginedfutures-btcusdt_211231",
pair: currency.NewPairWithDelimiter("btcusdt", "211231", currency.UnderscoreDelimiter),
asset: asset.USDTMarginedFutures,
expectedDelimiter: currency.UnderscoreDelimiter,
},
}
for i := range testerinos {
tt := testerinos[i]
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
result, err := b.FormatExchangeCurrency(tt.pair, tt.asset)
if err != nil {
t.Error(err)
}
if result.Delimiter != tt.expectedDelimiter {
t.Errorf("received '%v' expected '%v'", result.Delimiter, tt.expectedDelimiter)
}
})
}
}
func TestFormatSymbol(t *testing.T) {
t.Parallel()
type testos struct {
name string
pair currency.Pair
asset asset.Item
expectedString string
}
testerinos := []testos{
{
name: "spot-BTCUSDT",
pair: currency.NewPairWithDelimiter("BTC", "USDT", currency.UnderscoreDelimiter),
asset: asset.Spot,
expectedString: "BTCUSDT",
},
{
name: "coinmarginedfutures-btcusdperp",
pair: currency.NewPairWithDelimiter("BTCUSD", "PERP", currency.DashDelimiter),
asset: asset.CoinMarginedFutures,
expectedString: "BTCUSD_PERP",
},
{
name: "coinmarginedfutures-BTCUSD_211231",
pair: currency.NewPairWithDelimiter("BTCUSD", "211231", currency.DashDelimiter),
asset: asset.CoinMarginedFutures,
expectedString: "BTCUSD_211231",
},
{
name: "margin-LTOUSDT",
pair: currency.NewPairWithDelimiter("LTO", "USDT", currency.UnderscoreDelimiter),
asset: asset.Margin,
expectedString: "LTOUSDT",
},
{
name: "usdtmarginedfutures-BTCUSDT",
pair: currency.NewPairWithDelimiter("btc", "usdt", currency.DashDelimiter),
asset: asset.USDTMarginedFutures,
expectedString: "BTCUSDT",
},
{
name: "usdtmarginedfutures-BTCUSDT_211231",
pair: currency.NewPairWithDelimiter("btcusdt", "211231", currency.UnderscoreDelimiter),
asset: asset.USDTMarginedFutures,
expectedString: "BTCUSDT_211231",
},
}
for i := range testerinos {
tt := testerinos[i]
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
result, err := b.FormatSymbol(tt.pair, tt.asset)
if err != nil {
t.Error(err)
}
if result != tt.expectedString {
t.Errorf("received '%v' expected '%v'", result, tt.expectedString)
}
})
}
}
func TestFormatUSDTMarginedFuturesPair(t *testing.T) {
t.Parallel()
pairFormat := currency.PairFormat{Uppercase: true}
resp := b.formatUSDTMarginedFuturesPair(currency.NewPair(currency.DOGE, currency.USDT), pairFormat)
if resp.String() != "DOGEUSDT" {
t.Errorf("received '%v' expected '%v'", resp.String(), "DOGEUSDT")
}
resp = b.formatUSDTMarginedFuturesPair(currency.NewPair(currency.DOGE, currency.NewCode("1234567890")), pairFormat)
if resp.String() != "DOGE_1234567890" {
t.Errorf("received '%v' expected '%v'", resp.String(), "DOGE_1234567890")
}
}

View File

@@ -84,6 +84,7 @@ func (b *Binance) SetDefaults() {
},
ConfigFormat: &currency.PairFormat{
Uppercase: true,
Delimiter: currency.UnderscoreDelimiter,
},
}
err := b.StoreAssetPairFormat(asset.Spot, fmt1)
@@ -264,6 +265,7 @@ func (b *Binance) Run() {
b.PrintEnabledPairs()
}
forceUpdate := false
a := b.GetAssetTypes(true)
for x := range a {
if err := b.UpdateOrderExecutionLimits(context.TODO(), a[x]); err != nil {
@@ -272,13 +274,60 @@ func (b *Binance) Run() {
b.Name,
err)
}
if a[x] == asset.USDTMarginedFutures && !b.BypassConfigFormatUpgrades {
format, err := b.GetPairFormat(asset.USDTMarginedFutures, false)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to get enabled currencies. Err %s\n",
b.Name,
err)
return
}
var enabled, avail currency.Pairs
enabled, err = b.CurrencyPairs.GetPairs(asset.USDTMarginedFutures, true)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to get enabled currencies. Err %s\n",
b.Name,
err)
return
}
avail, err = b.CurrencyPairs.GetPairs(asset.USDTMarginedFutures, false)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to get available currencies. Err %s\n",
b.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
var enabledPairs currency.Pairs
enabledPairs, err = currency.NewPairsFromStrings([]string{
currency.BTC.String() + format.Delimiter + currency.USDT.String(),
})
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to update currencies. Err %s\n",
b.Name,
err)
} else {
log.Warnf(log.ExchangeSys, exchange.ResetConfigPairsWarningMessage, b.Name, a[x], enabledPairs)
forceUpdate = true
err = b.UpdatePairs(enabledPairs, a[x], true, true)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
b.Name,
err)
}
}
}
}
}
if !b.GetEnabledFeatures().AutoPairUpdates {
if !b.GetEnabledFeatures().AutoPairUpdates && !forceUpdate {
return
}
if err := b.UpdateTradablePairs(context.TODO(), false); err != nil {
if err := b.UpdateTradablePairs(context.TODO(), forceUpdate); err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
b.Name,
@@ -295,53 +344,70 @@ func (b *Binance) FetchTradablePairs(ctx context.Context, a asset.Item) ([]strin
if err != nil {
return nil, err
}
tradingStatus := "TRADING"
var pairs []string
switch a {
case asset.Spot, asset.Margin:
info, err := b.GetExchangeInfo(ctx)
var info ExchangeInfo
info, err = b.GetExchangeInfo(ctx)
if err != nil {
return nil, err
}
for x := range info.Symbols {
if info.Symbols[x].Status == "TRADING" {
pair := info.Symbols[x].BaseAsset +
format.Delimiter +
info.Symbols[x].QuoteAsset
if a == asset.Spot && info.Symbols[x].IsSpotTradingAllowed {
pairs = append(pairs, pair)
}
if a == asset.Margin && info.Symbols[x].IsMarginTradingAllowed {
pairs = append(pairs, pair)
}
if info.Symbols[x].Status != tradingStatus {
continue
}
pair := info.Symbols[x].BaseAsset +
format.Delimiter +
info.Symbols[x].QuoteAsset
if a == asset.Spot && info.Symbols[x].IsSpotTradingAllowed {
pairs = append(pairs, pair)
}
if a == asset.Margin && info.Symbols[x].IsMarginTradingAllowed {
pairs = append(pairs, pair)
}
}
case asset.CoinMarginedFutures:
cInfo, err := b.FuturesExchangeInfo(ctx)
var cInfo CExchangeInfo
cInfo, err = b.FuturesExchangeInfo(ctx)
if err != nil {
return pairs, err
}
for z := range cInfo.Symbols {
if cInfo.Symbols[z].ContractStatus == "TRADING" {
curr, err := currency.NewPairFromString(cInfo.Symbols[z].Symbol)
if err != nil {
return nil, err
}
pairs = append(pairs, format.Format(curr))
if cInfo.Symbols[z].ContractStatus != tradingStatus {
continue
}
var curr currency.Pair
curr, err = currency.NewPairFromString(cInfo.Symbols[z].Symbol)
if err != nil {
return nil, err
}
pairs = append(pairs, format.Format(curr))
}
case asset.USDTMarginedFutures:
uInfo, err := b.UExchangeInfo(ctx)
var uInfo UFuturesExchangeInfo
uInfo, err = b.UExchangeInfo(ctx)
if err != nil {
return pairs, err
}
for u := range uInfo.Symbols {
if uInfo.Symbols[u].Status == "TRADING" {
curr, err := currency.NewPairFromString(uInfo.Symbols[u].Symbol)
if uInfo.Symbols[u].Status != tradingStatus {
continue
}
var curr currency.Pair
if uInfo.Symbols[u].ContractType == "PERPETUAL" {
curr, err = currency.NewPairFromStrings(uInfo.Symbols[u].BaseAsset, uInfo.Symbols[u].QuoteAsset)
if err != nil {
return nil, err
}
} else {
curr, err = currency.NewPairFromString(uInfo.Symbols[u].Symbol)
if err != nil {
return nil, err
}
pairs = append(pairs, format.Format(curr))
}
pairs = append(pairs, format.Format(curr))
}
}
return pairs, nil
@@ -1742,3 +1808,44 @@ func (b *Binance) GetAvailableTransferChains(ctx context.Context, cryptocurrency
}
return availableChains, nil
}
// FormatExchangeCurrency is a method that formats and returns a currency pair
// based on the user currency display preferences
// overrides default implementation to use optional delimiter
func (b *Binance) FormatExchangeCurrency(p currency.Pair, a asset.Item) (currency.Pair, error) {
pairFmt, err := b.GetPairFormat(a, true)
if err != nil {
return currency.Pair{}, err
}
if a == asset.USDTMarginedFutures {
return b.formatUSDTMarginedFuturesPair(p, pairFmt), nil
}
return p.Format(pairFmt.Delimiter, pairFmt.Uppercase), nil
}
// FormatSymbol formats the given pair to a string suitable for exchange API requests
// overrides default implementation to use optional delimiter
func (b *Binance) FormatSymbol(p currency.Pair, a asset.Item) (string, error) {
pairFmt, err := b.GetPairFormat(a, true)
if err != nil {
return p.String(), err
}
if a == asset.USDTMarginedFutures {
p = b.formatUSDTMarginedFuturesPair(p, pairFmt)
return p.String(), nil
}
return pairFmt.Format(p), nil
}
// formatUSDTMarginedFuturesPair Binance USDTMarginedFutures pairs have a delimiter
// only if the contract has an expiry date
func (b *Binance) formatUSDTMarginedFuturesPair(p currency.Pair, pairFmt currency.PairFormat) currency.Pair {
quote := p.Quote.String()
for _, c := range quote {
if c < '0' || c > '9' {
// character rune is alphabetic, cannot be expiring contract
return p.Format(pairFmt.Delimiter, pairFmt.Uppercase)
}
}
return p.Format(currency.UnderscoreDelimiter, pairFmt.Uppercase)
}

View File

@@ -554,36 +554,51 @@ type UFuturesExchangeInfo struct {
Limit int64 `json:"limit"`
RateLimitType string `json:"rateLimitType"`
} `json:"rateLimits"`
ServerTime int64 `json:"serverTime"`
Symbols []struct {
Symbol string `json:"symbol"`
Status string `json:"status"`
MaintenanceMarginPercent float64 `json:"maintMarginPercent,string"`
RequiredMarginPercent float64 `json:"requiredMarginPercent,string"`
BaseAsset string `json:"baseAsset"`
QuoteAsset string `json:"quoteAsset"`
PricePrecision int64 `json:"pricePrecision"`
QuantityPrecision int64 `json:"quantityPrecision"`
BaseAssetPrecision int64 `json:"baseAssetPrecision"`
QuotePrecision int64 `json:"quotePrecision"`
Filters []struct {
MinPrice float64 `json:"minPrice,string"`
MaxPrice float64 `json:"maxPrice,string"`
FilterType string `json:"filterType"`
TickSize float64 `json:"tickSize,string"`
StepSize float64 `json:"stepSize,string"`
MaxQty float64 `json:"maxQty,string"`
MinQty float64 `json:"minQty,string"`
Limit int64 `json:"limit"`
MultiplierDown float64 `json:"multiplierDown,string"`
MultiplierUp float64 `json:"multiplierUp,string"`
MultiplierDecimal float64 `json:"multiplierDecimal,string"`
Notional float64 `json:"notional,string"`
} `json:"filters"`
OrderTypes []string `json:"orderTypes"`
TimeInForce []string `json:"timeInForce"`
} `json:"symbols"`
Timezone string `json:"timezone"`
ServerTime int64 `json:"serverTime"`
Symbols []UFuturesSymbolInfo `json:"symbols"`
Timezone string `json:"timezone"`
}
// UFuturesSymbolInfo contains details of a currency symbol
// for a usdt margined future contract
type UFuturesSymbolInfo struct {
Symbol string `json:"symbol"`
Pair string `json:"pair"`
ContractType string `json:"contractType"`
DeliveryDate time.Time `json:"deliveryDate"`
OnboardDate time.Time `json:"onboardDate"`
Status string `json:"status"`
MaintenanceMarginPercent float64 `json:"maintMarginPercent,string"`
RequiredMarginPercent float64 `json:"requiredMarginPercent,string"`
BaseAsset string `json:"baseAsset"`
QuoteAsset string `json:"quoteAsset"`
MarginAsset string `json:"marginAsset"`
PricePrecision int64 `json:"pricePrecision"`
QuantityPrecision int64 `json:"quantityPrecision"`
BaseAssetPrecision int64 `json:"baseAssetPrecision"`
QuotePrecision int64 `json:"quotePrecision"`
UnderlyingType string `json:"underlyingType"`
UnderlyingSubType []string `json:"underlyingSubType"`
SettlePlan float64 `json:"settlePlan"`
TriggerProtect float64 `json:"triggerProtect,string"`
Filters []struct {
FilterType string `json:"filterType"`
MinPrice float64 `json:"minPrice,string"`
MaxPrice float64 `json:"maxPrice,string"`
TickSize float64 `json:"tickSize,string"`
StepSize float64 `json:"stepSize,string"`
MaxQty float64 `json:"maxQty,string"`
MinQty float64 `json:"minQty,string"`
Limit int64 `json:"limit"`
MultiplierDown float64 `json:"multiplierDown,string"`
MultiplierUp float64 `json:"multiplierUp,string"`
MultiplierDecimal float64 `json:"multiplierDecimal,string"`
Notional float64 `json:"notional,string"`
} `json:"filters"`
OrderTypes []string `json:"OrderType"`
TimeInForce []string `json:"timeInForce"`
LiquidationFee float64 `json:"liquidationFee,string"`
MarketTakeBound float64 `json:"marketTakeBound,string"`
}
// CExchangeInfo stores exchange info for cfutures

View File

@@ -423,3 +423,21 @@ func (a *wsListStatus) UnmarshalJSON(data []byte) error {
a.Data.TransactionTime = aux.Data.TransactionTime.Time()
return nil
}
// UnmarshalJSON deserialises the JSON info, including the timestamp
func (u *UFuturesSymbolInfo) UnmarshalJSON(data []byte) error {
type Alias UFuturesSymbolInfo
aux := &struct {
DeliveryDate binanceTime `json:"deliveryDate"`
OnboardDate binanceTime `json:"onboardDate"`
*Alias
}{
Alias: (*Alias)(u),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
u.DeliveryDate = aux.DeliveryDate.Time()
u.OnboardDate = aux.OnboardDate.Time()
return nil
}

View File

@@ -203,51 +203,53 @@ func (b *Bitstamp) Run() {
}
forceUpdate := false
format, err := b.GetPairFormat(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to get pair format. Err %s\n",
b.Name,
err)
return
}
enabled, err := b.CurrencyPairs.GetPairs(asset.Spot, true)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to get enabled currencies. Err %s\n",
b.Name,
err)
return
}
avail, err := b.CurrencyPairs.GetPairs(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to get available currencies. Err %s\n",
b.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
var enabledPairs currency.Pairs
enabledPairs, err = currency.NewPairsFromStrings([]string{
currency.BTC.String() + format.Delimiter + currency.USD.String(),
})
if !b.BypassConfigFormatUpgrades {
format, err := b.GetPairFormat(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to update currencies. Err %s\n",
log.Errorf(log.ExchangeSys, "%s failed to get pair format. Err %s\n",
b.Name,
err)
} else {
log.Warn(log.ExchangeSys,
"Bitstamp: Enabled and available pairs reset due to config upgrade, please enable the ones you would like to use again")
forceUpdate = true
return
}
err = b.UpdatePairs(enabledPairs, asset.Spot, true, true)
enabled, err := b.CurrencyPairs.GetPairs(asset.Spot, true)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to get enabled currencies. Err %s\n",
b.Name,
err)
return
}
avail, err := b.CurrencyPairs.GetPairs(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to get available currencies. Err %s\n",
b.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
var enabledPairs currency.Pairs
enabledPairs, err = currency.NewPairsFromStrings([]string{
currency.BTC.String() + format.Delimiter + currency.USD.String(),
})
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
log.Errorf(log.ExchangeSys, "%s failed to update currencies. Err %s\n",
b.Name,
err)
} else {
log.Warnf(log.ExchangeSys,
exchange.ResetConfigPairsWarningMessage, b.Name, asset.Spot, enabledPairs)
forceUpdate = true
err = b.UpdatePairs(enabledPairs, asset.Spot, true, true)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
b.Name,
err)
}
}
}
}
@@ -256,7 +258,7 @@ func (b *Bitstamp) Run() {
return
}
err = b.UpdateTradablePairs(context.TODO(), forceUpdate)
err := b.UpdateTradablePairs(context.TODO(), forceUpdate)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",

View File

@@ -220,7 +220,6 @@ func (b *BTCMarkets) Run() {
if !common.StringDataContains(pairs.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
log.Warnln(log.ExchangeSys, "Available pairs for BTC Markets reset due to config upgrade, please enable the pairs you would like again.")
forceUpdate = true
}
if forceUpdate {
@@ -230,6 +229,7 @@ func (b *BTCMarkets) Run() {
Delimiter: format.Delimiter,
},
}
log.Warnf(log.ExchangeSys, exchange.ResetConfigPairsWarningMessage, b.Name, asset.Spot, enabledPairs)
err = b.UpdatePairs(enabledPairs, asset.Spot, true, true)
if err != nil {
log.Errorf(log.ExchangeSys,

View File

@@ -207,54 +207,55 @@ func (c *CoinbasePro) Run() {
}
forceUpdate := false
format, err := c.GetPairFormat(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
return
}
enabled, err := c.CurrencyPairs.GetPairs(asset.Spot, true)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
return
}
avail, err := c.CurrencyPairs.GetPairs(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
var p currency.Pairs
p, err = currency.NewPairsFromStrings([]string{currency.BTC.String() +
format.Delimiter +
currency.USD.String()})
if !c.BypassConfigFormatUpgrades {
format, err := c.GetPairFormat(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
} else {
log.Warn(log.ExchangeSys,
"Enabled pairs for CoinbasePro reset due to config upgrade, please enable the ones you would like to use again")
forceUpdate = true
return
}
enabled, err := c.CurrencyPairs.GetPairs(asset.Spot, true)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
return
}
err = c.UpdatePairs(p, asset.Spot, true, true)
avail, err := c.CurrencyPairs.GetPairs(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
var p currency.Pairs
p, err = currency.NewPairsFromStrings([]string{currency.BTC.String() +
format.Delimiter +
currency.USD.String()})
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
} else {
forceUpdate = true
log.Warnf(log.ExchangeSys, exchange.ResetConfigPairsWarningMessage, c.Name, asset.Spot, p)
err = c.UpdatePairs(p, asset.Spot, true, true)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
}
}
}
}
@@ -263,7 +264,7 @@ func (c *CoinbasePro) Run() {
return
}
err = c.UpdateTradablePairs(context.TODO(), forceUpdate)
err := c.UpdateTradablePairs(context.TODO(), forceUpdate)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", c.Name, err)
}

View File

@@ -187,54 +187,55 @@ func (c *COINUT) Run() {
}
forceUpdate := false
format, err := c.GetPairFormat(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
return
}
enabled, err := c.CurrencyPairs.GetPairs(asset.Spot, true)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
return
}
avail, err := c.CurrencyPairs.GetPairs(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
var p currency.Pairs
p, err = currency.NewPairsFromStrings([]string{currency.LTC.String() +
format.Delimiter +
currency.USDT.String()})
if !c.BypassConfigFormatUpgrades {
format, err := c.GetPairFormat(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
} else {
log.Warn(log.ExchangeSys,
"Enabled pairs for Coinut reset due to config upgrade, please enable the ones you would like to use again")
forceUpdate = true
return
}
err = c.UpdatePairs(p, asset.Spot, true, true)
enabled, err := c.CurrencyPairs.GetPairs(asset.Spot, true)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
return
}
avail, err := c.CurrencyPairs.GetPairs(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
var p currency.Pairs
p, err = currency.NewPairsFromStrings([]string{currency.LTC.String() +
format.Delimiter +
currency.USDT.String()})
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
} else {
log.Warnf(log.ExchangeSys, exchange.ResetConfigPairsWarningMessage, c.Name, asset.Spot, p)
forceUpdate = true
err = c.UpdatePairs(p, asset.Spot, true, true)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
c.Name,
err)
}
}
}
}
@@ -243,7 +244,7 @@ func (c *COINUT) Run() {
return
}
err = c.UpdateTradablePairs(context.TODO(), forceUpdate)
err := c.UpdateTradablePairs(context.TODO(), forceUpdate)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", c.Name, err)
}

View File

@@ -37,6 +37,8 @@ const (
DefaultWebsocketResponseMaxLimit = time.Second * 7
// DefaultWebsocketOrderbookBufferLimit is the maximum number of orderbook updates that get stored before being applied
DefaultWebsocketOrderbookBufferLimit = 5
// ResetConfigPairsWarningMessage is displayed when a currency pair format in the config needs to be updated
ResetConfigPairsWarningMessage = "%s Enabled and available pairs for %s reset due to config upgrade, please enable the ones you would like to use again. Defaulting to %v"
)
var (
@@ -595,6 +597,7 @@ func (b *Base) SetupDefaults(exch *config.Exchange) error {
}
b.HTTPDebugging = exch.HTTPDebugging
b.BypassConfigFormatUpgrades = exch.CurrencyPairs.BypassConfigFormatUpgrades
b.SetHTTPClientUserAgent(exch.HTTPUserAgent)
b.SetCurrencyPairFormat()

View File

@@ -222,6 +222,7 @@ type Base struct {
HTTPUserAgent string
HTTPRecording bool
HTTPDebugging bool
BypassConfigFormatUpgrades bool
WebsocketResponseCheckTimeout time.Duration
WebsocketResponseMaxLimit time.Duration
WebsocketOrderbookBufferLimit int64

View File

@@ -201,50 +201,51 @@ func (g *Gemini) Run() {
}
forceUpdate := false
format, err := g.GetPairFormat(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to get enabled currencies. Err %s\n",
g.Name,
err)
return
}
enabled, err := g.CurrencyPairs.GetPairs(asset.Spot, true)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to get enabled currencies. Err %s\n",
g.Name,
err)
return
}
avail, err := g.CurrencyPairs.GetPairs(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to get available currencies. Err %s\n",
g.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
var enabledPairs currency.Pairs
enabledPairs, err = currency.NewPairsFromStrings([]string{
currency.BTC.String() + format.Delimiter + currency.USD.String()})
if !g.BypassConfigFormatUpgrades {
format, err := g.GetPairFormat(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to update currencies. Err %s\n",
log.Errorf(log.ExchangeSys, "%s failed to get enabled currencies. Err %s\n",
g.Name,
err)
} else {
log.Warn(log.ExchangeSys,
"Available pairs for Gemini reset due to config upgrade, please enable the ones you would like to use again")
forceUpdate = true
return
}
err = g.UpdatePairs(enabledPairs, asset.Spot, true, true)
enabled, err := g.CurrencyPairs.GetPairs(asset.Spot, true)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to get enabled currencies. Err %s\n",
g.Name,
err)
return
}
avail, err := g.CurrencyPairs.GetPairs(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to get available currencies. Err %s\n",
g.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
var enabledPairs currency.Pairs
enabledPairs, err = currency.NewPairsFromStrings([]string{
currency.BTC.String() + format.Delimiter + currency.USD.String()})
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
log.Errorf(log.ExchangeSys, "%s failed to update currencies. Err %s\n",
g.Name,
err)
} else {
log.Warnf(log.ExchangeSys, exchange.ResetConfigPairsWarningMessage, g.Name, asset.Spot, enabledPairs)
forceUpdate = true
err = g.UpdatePairs(enabledPairs, asset.Spot, true, true)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
g.Name,
err)
}
}
}
}
@@ -252,7 +253,7 @@ func (g *Gemini) Run() {
if !g.GetEnabledFeatures().AutoPairUpdates && !forceUpdate {
return
}
err = g.UpdateTradablePairs(context.TODO(), forceUpdate)
err := g.UpdateTradablePairs(context.TODO(), forceUpdate)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",

View File

@@ -203,40 +203,8 @@ func (h *HitBTC) Run() {
}
forceUpdate := false
format, err := h.GetPairFormat(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
h.Name,
err)
return
}
enabled, err := h.GetEnabledPairs(asset.Spot)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
h.Name,
err)
return
}
avail, err := h.GetAvailablePairs(asset.Spot)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
h.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
enabledPairs := []string{currency.BTC.String() + format.Delimiter + currency.USD.String()}
log.Warn(log.ExchangeSys,
"Available pairs for HitBTC reset due to config upgrade, please enable the ones you would like again.")
forceUpdate = true
var p currency.Pairs
p, err = currency.NewPairsFromStrings(enabledPairs)
if !h.BypassConfigFormatUpgrades {
format, err := h.GetPairFormat(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
@@ -244,11 +212,44 @@ func (h *HitBTC) Run() {
err)
return
}
err = h.UpdatePairs(p, asset.Spot, true, true)
enabled, err := h.GetEnabledPairs(asset.Spot)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update enabled currencies.\n",
h.Name)
"%s failed to update tradable pairs. Err: %s",
h.Name,
err)
return
}
avail, err := h.GetAvailablePairs(asset.Spot)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
h.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
enabledPairs := []string{currency.BTC.String() + format.Delimiter + currency.USD.String()}
log.Warnf(log.ExchangeSys, exchange.ResetConfigPairsWarningMessage, h.Name, asset.Spot, enabledPairs)
forceUpdate = true
var p currency.Pairs
p, err = currency.NewPairsFromStrings(enabledPairs)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
h.Name,
err)
return
}
err = h.UpdatePairs(p, asset.Spot, true, true)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update enabled currencies.\n",
h.Name)
}
}
}
@@ -256,7 +257,7 @@ func (h *HitBTC) Run() {
return
}
err = h.UpdateTradablePairs(context.TODO(), forceUpdate)
err := h.UpdateTradablePairs(context.TODO(), forceUpdate)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",

View File

@@ -300,9 +300,7 @@ func (h *HUOBI) Run() {
Delimiter: format.Delimiter,
},
}
log.Warn(log.ExchangeSys,
"Available and enabled pairs for Huobi reset due to config upgrade, please enable the ones you would like again")
log.Warnf(log.ExchangeSys, exchange.ResetConfigPairsWarningMessage, h.Name, asset.Spot, enabledPairs)
err = h.UpdatePairs(enabledPairs, asset.Spot, true, true)
if err != nil {
log.Errorf(log.ExchangeSys,

View File

@@ -260,54 +260,56 @@ func (k *Kraken) Run() {
}
forceUpdate := false
format, err := k.GetPairFormat(asset.UseDefault(), false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
k.Name,
err)
return
}
enabled, err := k.GetEnabledPairs(asset.UseDefault())
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
k.Name,
err)
return
}
avail, err := k.GetAvailablePairs(asset.UseDefault())
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
k.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) ||
common.StringDataContains(avail.Strings(), "ZUSD") {
var p currency.Pairs
p, err = currency.NewPairsFromStrings([]string{currency.XBT.String() +
format.Delimiter +
currency.USD.String()})
if !k.BypassConfigFormatUpgrades {
format, err := k.GetPairFormat(asset.UseDefault(), false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
"%s failed to update tradable pairs. Err: %s",
k.Name,
err)
} else {
log.Warn(log.ExchangeSys, "Available pairs for Kraken reset due to config upgrade, please enable the ones you would like again")
forceUpdate = true
return
}
enabled, err := k.GetEnabledPairs(asset.UseDefault())
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
k.Name,
err)
return
}
err = k.UpdatePairs(p, asset.UseDefault(), true, true)
avail, err := k.GetAvailablePairs(asset.UseDefault())
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
k.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) ||
common.StringDataContains(avail.Strings(), "ZUSD") {
var p currency.Pairs
p, err = currency.NewPairsFromStrings([]string{currency.XBT.String() +
format.Delimiter +
currency.USD.String()})
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
k.Name,
err)
} else {
log.Warnf(log.ExchangeSys, exchange.ResetConfigPairsWarningMessage, k.Name, asset.UseDefault(), p)
forceUpdate = true
err = k.UpdatePairs(p, asset.UseDefault(), true, true)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
k.Name,
err)
}
}
}
}
@@ -316,7 +318,7 @@ func (k *Kraken) Run() {
return
}
err = k.UpdateTradablePairs(context.TODO(), forceUpdate)
err := k.UpdateTradablePairs(context.TODO(), forceUpdate)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",

View File

@@ -173,55 +173,55 @@ func (o *OKCoin) Run() {
}
forceUpdate := false
format, err := o.GetPairFormat(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
o.Name,
err)
return
}
enabled, err := o.CurrencyPairs.GetPairs(asset.Spot, true)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
o.Name,
err)
return
}
avail, err := o.CurrencyPairs.GetPairs(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
o.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
var p currency.Pairs
p, err = currency.NewPairsFromStrings([]string{currency.BTC.String() +
format.Delimiter +
currency.USD.String()})
if !o.BypassConfigFormatUpgrades {
format, err := o.GetPairFormat(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies.\n",
o.Name)
} else {
log.Warnf(log.ExchangeSys,
"Enabled pairs for %v reset due to config upgrade, please enable the ones you would like again.\n",
o.Name)
forceUpdate = true
"%s failed to update currencies. Err: %s\n",
o.Name,
err)
return
}
enabled, err := o.CurrencyPairs.GetPairs(asset.Spot, true)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
o.Name,
err)
return
}
err = o.UpdatePairs(p, asset.Spot, true, true)
avail, err := o.CurrencyPairs.GetPairs(asset.Spot, false)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
o.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
var p currency.Pairs
p, err = currency.NewPairsFromStrings([]string{currency.BTC.String() +
format.Delimiter +
currency.USD.String()})
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
o.Name,
err)
return
"%s failed to update currencies.\n",
o.Name)
} else {
log.Warnf(log.ExchangeSys, exchange.ResetConfigPairsWarningMessage, o.Name, asset.Spot, p)
forceUpdate = true
err = o.UpdatePairs(p, asset.Spot, true, true)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies. Err: %s\n",
o.Name,
err)
return
}
}
}
}
@@ -230,7 +230,7 @@ func (o *OKCoin) Run() {
return
}
err = o.UpdateTradablePairs(context.TODO(), forceUpdate)
err := o.UpdateTradablePairs(context.TODO(), forceUpdate)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",

View File

@@ -244,46 +244,47 @@ func (o *OKEX) Run() {
}
forceUpdate := false
enabled, err := o.GetEnabledPairs(asset.Spot)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
o.Name,
err)
return
}
avail, err := o.GetAvailablePairs(asset.Spot)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
o.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
forceUpdate = true
var p currency.Pairs
p, err = currency.NewPairsFromStrings([]string{currency.BTC.String() +
format.Delimiter +
currency.USDT.String()})
if !o.BypassConfigFormatUpgrades {
var enabled, avail currency.Pairs
enabled, err = o.GetEnabledPairs(asset.Spot)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies.\n",
o.Name)
} else {
log.Warnf(log.ExchangeSys,
"Enabled pairs for %v reset due to config upgrade, please enable the ones you would like again.",
o.Name)
"%s failed to update tradable pairs. Err: %s",
o.Name,
err)
return
}
err = o.UpdatePairs(p, asset.Spot, true, forceUpdate)
avail, err = o.GetAvailablePairs(asset.Spot)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update tradable pairs. Err: %s",
o.Name,
err)
return
}
if !common.StringDataContains(enabled.Strings(), format.Delimiter) ||
!common.StringDataContains(avail.Strings(), format.Delimiter) {
forceUpdate = true
var p currency.Pairs
p, err = currency.NewPairsFromStrings([]string{currency.BTC.String() +
format.Delimiter +
currency.USDT.String()})
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies.\n",
o.Name)
return
} else {
log.Warnf(log.ExchangeSys, exchange.ResetConfigPairsWarningMessage, o.Name, asset.Spot, p)
err = o.UpdatePairs(p, asset.Spot, true, forceUpdate)
if err != nil {
log.Errorf(log.ExchangeSys,
"%s failed to update currencies.\n",
o.Name)
return
}
}
}
}