Currency: Remove Pair Index formatting/parsing (#1520)

* Currency: Remove Pair Index formatting/parsing

This feature was originally for exchanges with only one pair (e.g. KRW) which made parsing easier.
However there's no examples of this left, and we can reduce complexity
overall by removing it.

* Exchange: Partial assertify tests and fixes

* Currency: Fix panic on a delimiterless small currency
This commit is contained in:
Gareth Kirwan
2024-04-19 09:03:12 +02:00
committed by GitHub
parent 7b842c2773
commit fdf6014dca
11 changed files with 103 additions and 603 deletions

View File

@@ -448,22 +448,9 @@ func (c *Config) CheckPairConfigFormats(exchName string) error {
}
for y := range loadedPairs {
if pairFmt.Delimiter != "" && pairFmt.Index != "" {
return fmt.Errorf(
"exchange %s %s %s cannot have an index and delimiter set at the same time",
exchName, pairsType, assetType)
}
if pairFmt.Delimiter != "" {
if !strings.Contains(loadedPairs[y].String(), pairFmt.Delimiter) {
return fmt.Errorf(
"exchange %s %s %s pairs does not contain delimiter",
exchName, pairsType, assetType)
}
}
if pairFmt.Index != "" {
if !strings.Contains(loadedPairs[y].String(), pairFmt.Index) {
return fmt.Errorf("exchange %s %s %s pairs does not contain an index",
exchName, pairsType, assetType)
return fmt.Errorf("exchange %s %s %s pairs does not contain delimiter", exchName, pairsType, assetType)
}
}
}

View File

@@ -9,6 +9,7 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/common/file"
@@ -695,7 +696,6 @@ func TestCheckPairConfigFormats(t *testing.T) {
if err != nil {
t.Fatal(err)
}
// Test having a pair index and delimiter set at the same time throws an error
c.Exchanges[0].CurrencyPairs.Pairs = map[asset.Item]*currency.PairStore{
asset.Spot: {
RequestFormat: &currency.PairFormat{
@@ -705,7 +705,6 @@ func TestCheckPairConfigFormats(t *testing.T) {
ConfigFormat: &currency.PairFormat{
Uppercase: true,
Delimiter: "~",
Index: "USD",
},
Available: currency.Pairs{
avail,
@@ -716,32 +715,7 @@ func TestCheckPairConfigFormats(t *testing.T) {
},
}
if err := c.CheckPairConfigFormats(testFakeExchangeName); err == nil {
t.Error("invalid pair delimiter and index should throw an error")
}
// Test wrong pair delimiter throws an error
c.Exchanges[0].CurrencyPairs.Pairs[asset.Spot].ConfigFormat.Index = ""
if err := c.CheckPairConfigFormats(testFakeExchangeName); err == nil {
t.Error("invalid pair delimiter should throw an error")
}
// Test wrong pair index in the enabled pairs throw an error
c.Exchanges[0].CurrencyPairs.Pairs[asset.Spot] = &currency.PairStore{
ConfigFormat: &currency.PairFormat{
Index: currency.AUD.String(),
},
}
c.Exchanges[0].CurrencyPairs.Pairs[asset.Spot].Available = currency.Pairs{
currency.NewPair(currency.BTC, currency.AUD),
}
c.Exchanges[0].CurrencyPairs.Pairs[asset.Spot].Enabled = currency.Pairs{
currency.NewPair(currency.BTC, currency.KRW),
}
if err := c.CheckPairConfigFormats(testFakeExchangeName); err == nil {
t.Error("invalid pair index should throw an error")
}
assert.ErrorContains(t, c.CheckPairConfigFormats(testFakeExchangeName), "does not contain delimiter", "Invalid pair delimiter should throw an error")
}
func TestCheckPairConsistency(t *testing.T) {

View File

@@ -701,20 +701,19 @@
"baseCurrencies": "KRW",
"currencyPairs": {
"requestFormat": {
"uppercase": true
"uppercase": true,
"delimiter": "_"
},
"configFormat": {
"uppercase": true,
"index": "KRW"
"delimiter": "-"
},
"useGlobalFormat": true,
"assetTypes": [
"spot"
],
"pairs": {
"spot": {
"enabled": "BTCKRW,ETHKRW,DASHKRW,LTCKRW,ETCKRW,XRPKRW,BCHKRW,XMRKRW,ZECKRW,QTUMKRW,BTGKRW,EOSKRW",
"available": "FNBKRW,ETHKRW,MTLKRW,SNTKRW,BATKRW,OGOKRW,BTCKRW,DADKRW,BCHKRW,FABKRW,MBLKRW,ADAKRW,MXCKRW,SXPKRW,STRATKRW,LAMBKRW,FLETAKRW,EMKRW,ZILKRW,CTXCKRW,OMGKRW,CROKRW,LRCKRW,LUNAKRW,DASHKRW,QBZKRW,COSKRW,TRVKRW,LINKKRW,MCOKRW,VALORKRW,EGGKRW,LBAKRW,PCMKRW,FCTKRW,ITCKRW,ENJKRW,SOCKRW,METAKRW,VSYSKRW,DACKRW,EOSKRW,REPKRW,XLMKRW,ICXKRW,CONKRW,BTTKRW,XRPKRW,ZECKRW,QTUMKRW,BTGKRW,XSRKRW,XEMKRW,FXKRW,THETAKRW,RNTKRW,WTCKRW,LTCKRW,TRUEKRW,GXCKRW,NPXSKRW,BASICKRW,AIONKRW,PIVXKRW,AMOKRW,TRXKRW,QKCKRW,ETCKRW,AEKRW,IOSTKRW,ORBSKRW,IPXKRW,ZRXKRW,XPRKRW,APIXKRW,MIXKRW,WAXPKRW,BSVKRW,GNTKRW,BOAKRW,DVPKRW,WICCKRW,ARPAKRW,LOOMKRW,FZZKRW,COSMKRW,ELFKRW,HDACKRW,VETKRW,HYCKRW,POWRKRW,WETKRW,BCDKRW,ELKRW,AOAKRW,WOMKRW,WAVESKRW,ANKRKRW,TMTGKRW,CHRKRW,PLXKRW,BZNTKRW,INSKRW,KNCKRW,STEEMKRW"
"assetEnabled": true,
"enabled": "USDT-KRW,QTUM-KRW,BTC-KRW,ETH-KRW,ETC-KRW,XRP-KRW,BCH-KRW,BTG-KRW,EOS-KRW",
"available": "AVAX-KRW,STRAX-KRW,KSM-KRW,RPL-KRW,ADA-KRW,ONT-KRW,EOS-KRW,STAT-KRW,APM-KRW,XPLA-KRW,STMX-KRW,FET-KRW,XVS-KRW,ROA-KRW,JOE-KRW,BNT-KRW,T-KRW,AUDIO-KRW,MIX-KRW,PUNDIX-KRW,USDC-KRW,ALGO-KRW,CTXC-KRW,IQ-KRW,RLY-KRW,GRT-KRW,NMR-KRW,FTM-KRW,WNCG-KRW,NCT-KRW,CSPR-KRW,TFUEL-KRW,EGG-KRW,MOC-KRW,BAT-KRW,ETC-KRW,TIA-KRW,GRACY-KRW,FRONT-KRW,DAI-KRW,ANKR-KRW,META-KRW,HOOK-KRW,BEL-KRW,MAGIC-KRW,ENTC-KRW,HUNT-KRW,STX-KRW,FIT-KRW,STEEM-KRW,CTSI-KRW,JUP-KRW,CAKE-KRW,DOGE-KRW,SUN-KRW,OCEAN-KRW,SOL-KRW,REQ-KRW,BNB-KRW,GAL-KRW,MBL-KRW,LRC-KRW,ILV-KRW,PEPE-KRW,IOST-KRW,XLM-KRW,CRV-KRW,NFT-KRW,PYR-KRW,TRX-KRW,TAVA-KRW,PYTH-KRW,TT-KRW,AAVE-KRW,KLAY-KRW,BAL-KRW,EVZ-KRW,FX-KRW,UMA-KRW,FLOW-KRW,ALEX-KRW,ELF-KRW,CVC-KRW,FLOKI-KRW,MASK-KRW,GAS-KRW,VIX-KRW,CELR-KRW,BLY-KRW,ARK-KRW,FNSA-KRW,OXT-KRW,VALOR-KRW,XTZ-KRW,HBAR-KRW,ONG-KRW,MTL-KRW,WAVES-KRW,ORBS-KRW,MANTA-KRW,ICX-KRW,SNX-KRW,API3-KRW,PENDLE-KRW,FLZ-KRW,APE-KRW,POWR-KRW,OGN-KRW,EDU-KRW,ARB-KRW,AXS-KRW,MBX-KRW,XRP-KRW,MATIC-KRW,USDT-KRW,1INCH-KRW,STORJ-KRW,UOS-KRW,RVN-KRW,LPT-KRW,OSMO-KRW,ALICE-KRW,LDO-KRW,TEMCO-KRW,COMP-KRW,VET-KRW,SFP-KRW,WIKEN-KRW,LBL-KRW,SHIB-KRW,GMT-KRW,AZIT-KRW,ZBCN-KRW,FLUX-KRW,ALT-KRW,AGI-KRW,SPURS-KRW,GRS-KRW,C98-KRW,ZIL-KRW,BCH-KRW,QTCON-KRW,SEI-KRW,GRND-KRW,SWAP-KRW,ETH-KRW,RSS3-KRW,STPT-KRW,FXS-KRW,SAND-KRW,MAP-KRW,MAV-KRW,LINK-KRW,MVC-KRW,QTUM-KRW,DAR-KRW,FANC-KRW,HIGH-KRW,ARKM-KRW,MANA-KRW,SUSHI-KRW,DVI-KRW,XEC-KRW,BTC-KRW,EL-KRW,THETA-KRW,CELO-KRW,KNC-KRW,POLA-KRW,LOOM-KRW,JASMY-KRW,INJ-KRW,KAVA-KRW,NEO-KRW,BIGTIME-KRW,MINA-KRW,NPT-KRW,IMX-KRW,ASM-KRW,FCT2-KRW,RLC-KRW,HIFI-KRW,CTC-KRW,DYDX-KRW,ZTX-KRW,AGIX-KRW,WEMIX-KRW,GTC-KRW,LM-KRW,OP-KRW,ONIT-KRW,ACS-KRW,LSK-KRW,REI-KRW,ATOM-KRW,WLD-KRW,GLM-KRW,COS-KRW,BTT-KRW,BFC-KRW,ACE-KRW,SC-KRW,BORA-KRW,GHX-KRW,ADP-KRW,STRK-KRW,LEVER-KRW,BOBA-KRW,BOA-KRW,HFT-KRW,RNDR-KRW,ENJ-KRW,RSR-KRW,XPR-KRW,IOTX-KRW,CYBER-KRW,WAXP-KRW,OBSR-KRW,MEV-KRW,UNI-KRW,APT-KRW,DAO-KRW,WAXL-KRW,SIX-KRW,GMX-KRW,RDNT-KRW,BTG-KRW,MNT-KRW,BLUR-KRW,XCN-KRW,YGG-KRW,MXC-KRW,ACH-KRW,RAD-KRW,MLK-KRW,DOT-KRW,JST-KRW,ZRX-KRW,STG-KRW,SOFI-KRW,WOM-KRW,TDROP-KRW,SNT-KRW,COTI-KRW,WOO-KRW,OAS-KRW,CRO-KRW,AQT-KRW,EGLD-KRW,ARPA-KRW,BSV-KRW,ASTR-KRW,AMO-KRW,AERGO-KRW,ID-KRW,SUI-KRW,GALA-KRW,CKB-KRW,BIOT-KRW,CFX-KRW,CHR-KRW,FLR-KRW,FITFI-KRW,YFI-KRW,CTK-KRW,W-KRW,MED-KRW,MKR-KRW,SXP-KRW,HIVE-KRW,CRTS-KRW,CHZ-KRW"
}
}
},
@@ -765,7 +764,13 @@
"iban": "",
"supportedCurrencies": ""
}
]
],
"orderbook": {
"verificationBypass": false,
"websocketBufferLimit": 5,
"websocketBufferEnabled": false,
"publishPeriod": 10000000000
}
},
{
"name": "Bitmex",

View File

@@ -110,9 +110,8 @@ func CopyPairFormat(p Pair, pairs []Pair, exact bool) Pair {
return EMPTYPAIR
}
// FormatPairs formats a string array to a list of currency pairs with the
// supplied currency pair format
func FormatPairs(pairs []string, delimiter, index string) (Pairs, error) {
// FormatPairs formats a string array to a list of currency pairs with the supplied currency pair format
func FormatPairs(pairs []string, delimiter string) (Pairs, error) {
var result = make(Pairs, len(pairs))
for x := range pairs {
if pairs[x] == "" {
@@ -122,8 +121,8 @@ func FormatPairs(pairs []string, delimiter, index string) (Pairs, error) {
switch {
case delimiter != "":
result[x], err = NewPairDelimiter(pairs[x], delimiter)
case index != "":
result[x], err = NewPairFromIndex(pairs[x], index)
case len(pairs[x]) < 3:
err = errNoDelimiter
default:
result[x], err = NewPairFromStrings(pairs[x][:3], pairs[x][3:])
}

View File

@@ -36,7 +36,6 @@ type PairFormat struct {
Uppercase bool `json:"uppercase"`
Delimiter string `json:"delimiter,omitempty"`
Separator string `json:"separator,omitempty"`
Index string `json:"index,omitempty"`
}
// key is used to store the asset type and symbol in a map

View File

@@ -77,21 +77,6 @@ func NewPairWithDelimiter(base, quote, delimiter string) Pair {
}
}
// NewPairFromIndex returns a CurrencyPair via a currency string and specific
// index
func NewPairFromIndex(currencyPair, index string) (Pair, error) {
i := strings.Index(currencyPair, index)
if i == -1 {
return EMPTYPAIR,
fmt.Errorf("index %s not found in currency pair string", index)
}
if i == 0 {
return NewPairFromStrings(currencyPair[0:len(index)],
currencyPair[len(index):])
}
return NewPairFromStrings(currencyPair[0:i], currencyPair[i:])
}
// NewPairFromString converts currency string into a new CurrencyPair
// with or without delimiter
func NewPairFromString(currencyPair string) (Pair, error) {

View File

@@ -7,6 +7,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const (
@@ -410,48 +411,6 @@ func TestNewPairDelimiter(t *testing.T) {
}
}
// TestNewPairFromIndex returns a CurrencyPair via a currency string and
// specific index
func TestNewPairFromIndex(t *testing.T) {
t.Parallel()
curr := defaultPair
index := "BTC"
pair, err := NewPairFromIndex(curr, index)
if err != nil {
t.Error("NewPairFromIndex() error", err)
}
pair.Delimiter = "-"
actual := pair.String()
expected := defaultPairWDelimiter
if actual != expected {
t.Errorf(
"Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
curr = "DOGEBTC"
pair, err = NewPairFromIndex(curr, index)
if err != nil {
t.Error("NewPairFromIndex() error", err)
}
pair.Delimiter = "-"
actual = pair.String()
expected = "DOGE-BTC"
if actual != expected {
t.Errorf(
"Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestNewPairFromString(t *testing.T) {
t.Parallel()
pairStr := defaultPairWDelimiter
@@ -561,36 +520,26 @@ func TestContainsCurrency(t *testing.T) {
}
func TestFormatPairs(t *testing.T) {
_, err := FormatPairs([]string{""}, "-", "")
if !errors.Is(err, errEmptyPairString) {
t.Fatalf("received: '%v' but expected: '%v'", err, errEmptyPairString)
}
_, err := FormatPairs([]string{""}, "-")
assert.ErrorIs(t, err, errEmptyPairString, "Should error on empty string")
newP, err := FormatPairs([]string{defaultPairWDelimiter}, "-", "")
if err != nil {
t.Error("FormatPairs() error", err)
}
_, err = FormatPairs([]string{"NO"}, "")
assert.ErrorIs(t, err, errNoDelimiter, "Should error on a small string with no delimiter")
if newP[0].String() != defaultPairWDelimiter {
t.Error("TestFormatPairs: Expected pair was not found")
}
newP, err := FormatPairs([]string{defaultPairWDelimiter}, "-")
assert.NoError(t, err)
require.NotEmpty(t, newP)
assert.Equal(t, defaultPairWDelimiter, newP[0].String(), "Pair should format correctly")
newP, err = FormatPairs([]string{defaultPair}, "", "BTC")
if err != nil {
t.Error("FormatPairs() error", err)
}
newP, err = FormatPairs([]string{defaultPair}, "")
assert.NoError(t, err)
require.NotEmpty(t, newP)
assert.Equal(t, defaultPair, newP[0].String(), "Pair should format correctly")
if newP[0].String() != defaultPair {
t.Error("TestFormatPairs: Expected pair was not found")
}
newP, err = FormatPairs([]string{"ETHUSD"}, "", "")
if err != nil {
t.Error("FormatPairs() error", err)
}
if newP[0].String() != "ETHUSD" {
t.Error("TestFormatPairs: Expected pair was not found")
}
newP, err = FormatPairs([]string{"ETHUSD"}, "")
assert.NoError(t, err)
require.NotEmpty(t, newP)
assert.Equal(t, "ETHUSD", newP[0].String(), "Pair should format correctly")
}
func TestCopyPairFormat(t *testing.T) {
@@ -847,7 +796,6 @@ func TestPairFormat_Format(t *testing.T) {
Uppercase bool
Delimiter string
Separator string
Index string
}
tests := []struct {
name string
@@ -892,7 +840,6 @@ func TestPairFormat_Format(t *testing.T) {
Uppercase: tt.fields.Uppercase,
Delimiter: tt.fields.Delimiter,
Separator: tt.fields.Separator,
Index: tt.fields.Index,
}
if got := f.Format(tt.arg); got != tt.want {
t.Errorf("PairFormat.Format() = %v, want %v", got, tt.want)

View File

@@ -5,9 +5,8 @@ import (
"errors"
"fmt"
"math/rand"
"slices"
"strings"
"github.com/thrasher-corp/gocryptotrader/log"
)
var (
@@ -59,18 +58,8 @@ func (p Pairs) Join() string {
// Format formats the pair list to the exchange format configuration
func (p Pairs) Format(pairFmt PairFormat) Pairs {
pairs := make(Pairs, len(p))
copy(pairs, p)
var err error
pairs := slices.Clone(p)
for x := range pairs {
if pairFmt.Index != "" {
pairs[x], err = NewPairFromIndex(p[x].String(), pairFmt.Index)
if err != nil {
log.Errorf(log.Global, "failed to create NewPairFromIndex. Err: %s\n", err)
return nil
}
}
pairs[x].Base.UpperCase = pairFmt.Uppercase
pairs[x].Quote.UpperCase = pairFmt.Uppercase
pairs[x].Delimiter = pairFmt.Delimiter

View File

@@ -4,6 +4,9 @@ import (
"encoding/json"
"errors"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestPairsUpper(t *testing.T) {
@@ -91,40 +94,9 @@ func TestPairsJoin(t *testing.T) {
func TestPairsFormat(t *testing.T) {
t.Parallel()
pairs, err := NewPairsFromStrings([]string{"btc_usd", "btc_aud", "btc_ltc"})
if err != nil {
t.Fatal(err)
}
expected := "BTC-USD,BTC-AUD,BTC-LTC"
formatting := PairFormat{Delimiter: "-", Index: "", Uppercase: true}
if pairs.Format(formatting).Join() != expected {
t.Errorf("Pairs Join() error expected %s but received %s",
expected, pairs.Format(formatting).Join())
}
expected = "btc:usd,btc:aud,btc:ltc"
formatting = PairFormat{Delimiter: ":", Index: "", Uppercase: false}
if pairs.Format(formatting).Join() != expected {
t.Errorf("Pairs Join() error expected %s but received %s",
expected, pairs.Format(formatting).Join())
}
formatting = PairFormat{Delimiter: ":", Index: "KRW", Uppercase: false}
if pairs.Format(formatting).Join() != "" {
t.Errorf("Pairs Join() error expected %s but received %s",
expected, pairs.Format(formatting).Join())
}
pairs, err = NewPairsFromStrings([]string{"DASHKRW", "BTCKRW"})
if err != nil {
t.Fatal(err)
}
expected = "dash-krw,btc-krw"
formatting = PairFormat{Delimiter: "-", Index: "KRW", Uppercase: false}
if pairs.Format(formatting).Join() != expected {
t.Errorf("Pairs Join() error expected %s but received %s",
expected, pairs.Format(formatting).Join())
}
require.NoError(t, err, "NewPairsFromStrings must not error")
assert.Equal(t, "BTC-USD,BTC-AUD,BTC-LTC", pairs.Format(PairFormat{Delimiter: "-", Uppercase: true}).Join(), "Format should return the correct value")
assert.Equal(t, "btc:usd,btc:aud,btc:ltc", pairs.Format(PairFormat{Delimiter: ":", Uppercase: false}).Join(), "Format should return the correct value")
}
func TestPairsUnmarshalJSON(t *testing.T) {
@@ -613,7 +585,7 @@ func BenchmarkPairsFormat(b *testing.B) {
NewPair(DAI, XRP),
}
formatting := PairFormat{Delimiter: "/", Index: "", Uppercase: false}
formatting := PairFormat{Delimiter: "/", Uppercase: false}
for x := 0; x < b.N; x++ {
_ = pairs.Format(formatting)

View File

@@ -35,8 +35,11 @@ import (
)
const (
defaultTestExchange = "Bitfinex"
defaultTestCurrencyPair = "BTC-USD"
defaultTestExchange = "Bitfinex"
)
var (
btcusdPair = currency.NewPairWithDelimiter("BTC", "USD", "-")
)
func TestSupportsRESTTickerBatchUpdates(t *testing.T) {
@@ -745,356 +748,33 @@ func TestGetPairFormat(t *testing.T) {
}
}
func TestGetEnabledPairs(t *testing.T) {
func TestGetPairs(t *testing.T) {
t.Parallel()
b := Base{
Name: "TESTNAME",
}
b := Base{Name: "TESTNAME"}
defaultPairs, err := currency.NewPairsFromStrings([]string{defaultTestCurrencyPair})
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.StorePairs(asset.Spot, defaultPairs, true)
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.StorePairs(asset.Spot, defaultPairs, false)
if err != nil {
t.Fatal(err)
}
format := currency.PairFormat{
Delimiter: "-",
Index: "",
Uppercase: true,
}
err = b.CurrencyPairs.SetAssetEnabled(asset.Spot, true)
if err != nil {
t.Fatal(err)
}
b.CurrencyPairs.UseGlobalFormat = true
b.CurrencyPairs.RequestFormat = &format
b.CurrencyPairs.ConfigFormat = &format
c, err := b.GetEnabledPairs(asset.Spot)
if err != nil {
t.Fatal(err)
}
if c[0].String() != defaultTestCurrencyPair {
t.Error("Exchange GetAvailablePairs() incorrect string")
}
format.Delimiter = "~"
b.CurrencyPairs.RequestFormat = &format
c, err = b.GetEnabledPairs(asset.Spot)
if err != nil {
t.Fatal(err)
}
if c[0].String() != "BTC~USD" {
t.Error("Exchange GetAvailablePairs() incorrect string")
}
format.Delimiter = ""
b.CurrencyPairs.ConfigFormat = &format
c, err = b.GetEnabledPairs(asset.Spot)
if err != nil {
t.Fatal(err)
}
if c[0].String() != "BTCUSD" {
t.Error("Exchange GetAvailablePairs() incorrect string")
}
btcdoge, err := currency.NewPairsFromStrings([]string{"BTCDOGE"})
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.StorePairs(asset.Spot, btcdoge, true)
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.StorePairs(asset.Spot, btcdoge, false)
if err != nil {
t.Fatal(err)
}
format.Index = currency.BTC.String()
b.CurrencyPairs.ConfigFormat = &format
c, err = b.GetEnabledPairs(asset.Spot)
if err != nil {
t.Fatal(err)
}
if c[0].Base != currency.BTC && c[0].Quote != currency.DOGE {
t.Error("Exchange GetAvailablePairs() incorrect string")
}
btcusdUnderscore, err := currency.NewPairsFromStrings([]string{"BTC_USD"})
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.StorePairs(asset.Spot, btcusdUnderscore, true)
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.StorePairs(asset.Spot, btcusdUnderscore, false)
if err != nil {
t.Fatal(err)
}
b.CurrencyPairs.RequestFormat.Delimiter = ""
b.CurrencyPairs.ConfigFormat.Delimiter = "_"
c, err = b.GetEnabledPairs(asset.Spot)
if err != nil {
t.Fatal(err)
}
if c[0].Base != currency.BTC && c[0].Quote != currency.USD {
t.Error("Exchange GetAvailablePairs() incorrect string")
}
err = b.CurrencyPairs.StorePairs(asset.Spot, btcdoge, true)
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.StorePairs(asset.Spot, btcdoge, false)
if err != nil {
t.Fatal(err)
}
b.CurrencyPairs.RequestFormat.Delimiter = ""
b.CurrencyPairs.ConfigFormat.Delimiter = ""
b.CurrencyPairs.ConfigFormat.Index = currency.BTC.String()
c, err = b.GetEnabledPairs(asset.Spot)
if err != nil {
t.Fatal(err)
}
if c[0].Base != currency.BTC && c[0].Quote != currency.DOGE {
t.Error("Exchange GetAvailablePairs() incorrect string")
}
btcusd, err := currency.NewPairsFromStrings([]string{"BTCUSD"})
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.StorePairs(asset.Spot, btcusd, true)
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.StorePairs(asset.Spot, btcusd, false)
if err != nil {
t.Fatal(err)
}
b.CurrencyPairs.ConfigFormat.Index = ""
c, err = b.GetEnabledPairs(asset.Spot)
if err != nil {
t.Fatal(err)
}
if c[0].Base != currency.BTC && c[0].Quote != currency.USD {
t.Error("Exchange GetAvailablePairs() incorrect string")
}
}
func TestGetAvailablePairs(t *testing.T) {
t.Parallel()
b := Base{
Name: "TESTNAME",
}
defaultPairs, err := currency.NewPairsFromStrings([]string{defaultTestCurrencyPair})
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.StorePairs(asset.Spot, defaultPairs, false)
if err != nil {
t.Fatal(err)
}
format := currency.PairFormat{
Delimiter: "-",
Index: "",
Uppercase: true,
}
assetType := asset.Spot
b.CurrencyPairs.UseGlobalFormat = true
b.CurrencyPairs.RequestFormat = &format
b.CurrencyPairs.ConfigFormat = &format
c, err := b.GetAvailablePairs(assetType)
if err != nil {
t.Fatal(err)
}
if c[0].String() != defaultTestCurrencyPair {
t.Error("Exchange GetAvailablePairs() incorrect string")
}
format.Delimiter = "~"
b.CurrencyPairs.RequestFormat = &format
c, err = b.GetAvailablePairs(assetType)
if err != nil {
t.Fatal(err)
}
if c[0].String() != "BTC~USD" {
t.Error("Exchange GetAvailablePairs() incorrect string")
}
format.Delimiter = ""
b.CurrencyPairs.ConfigFormat = &format
c, err = b.GetAvailablePairs(assetType)
if err != nil {
t.Fatal(err)
}
if c[0].String() != "BTCUSD" {
t.Error("Exchange GetAvailablePairs() incorrect string")
}
dogePairs, err := currency.NewPairsFromStrings([]string{"BTCDOGE"})
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.StorePairs(asset.Spot, dogePairs, false)
if err != nil {
t.Fatal(err)
}
format.Index = currency.BTC.String()
b.CurrencyPairs.ConfigFormat = &format
c, err = b.GetAvailablePairs(assetType)
if err != nil {
t.Fatal(err)
}
if c[0].Base != currency.BTC && c[0].Quote != currency.DOGE {
t.Error("Exchange GetAvailablePairs() incorrect string")
}
btcusdUnderscore, err := currency.NewPairsFromStrings([]string{"BTC_USD"})
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.StorePairs(asset.Spot, btcusdUnderscore, false)
if err != nil {
t.Fatal(err)
}
b.CurrencyPairs.RequestFormat.Delimiter = ""
b.CurrencyPairs.ConfigFormat.Delimiter = "_"
c, err = b.GetAvailablePairs(assetType)
if err != nil {
t.Fatal(err)
}
if c[0].Base != currency.BTC && c[0].Quote != currency.USD {
t.Error("Exchange GetAvailablePairs() incorrect string")
}
err = b.CurrencyPairs.StorePairs(asset.Spot, dogePairs, false)
if err != nil {
t.Fatal(err)
}
b.CurrencyPairs.RequestFormat.Delimiter = ""
b.CurrencyPairs.ConfigFormat.Delimiter = "_"
b.CurrencyPairs.ConfigFormat.Index = currency.BTC.String()
c, err = b.GetAvailablePairs(assetType)
if err != nil {
t.Fatal(err)
}
if c[0].Base != currency.BTC && c[0].Quote != currency.DOGE {
t.Error("Exchange GetAvailablePairs() incorrect string")
}
btcusd, err := currency.NewPairsFromStrings([]string{"BTCUSD"})
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.StorePairs(asset.Spot, btcusd, false)
if err != nil {
t.Fatal(err)
}
b.CurrencyPairs.ConfigFormat.Index = ""
c, err = b.GetAvailablePairs(assetType)
if err != nil {
t.Fatal(err)
}
if c[0].Base != currency.BTC && c[0].Quote != currency.USD {
t.Error("Exchange GetAvailablePairs() incorrect string")
}
}
func TestSupportsPair(t *testing.T) {
t.Parallel()
b := Base{
Name: "TESTNAME",
CurrencyPairs: currency.PairsManager{
Pairs: map[asset.Item]*currency.PairStore{
asset.Spot: {
AssetEnabled: convert.BoolPtr(true),
},
for _, d := range []string{"-", "~", "", "_"} {
b.CurrencyPairs = currency.PairsManager{
UseGlobalFormat: true,
ConfigFormat: &currency.PairFormat{
Uppercase: true,
Delimiter: d,
},
},
}
}
pairs, err := currency.NewPairsFromStrings([]string{defaultTestCurrencyPair,
"ETH-USD"})
if err != nil {
t.Fatal(err)
}
require.NoError(t, b.CurrencyPairs.StorePairs(asset.Spot, currency.Pairs{btcusdPair}, false), "StorePairs must not error for available pairs")
c, err := b.GetAvailablePairs(asset.Spot)
require.NoError(t, err, "GetAvailablePairs must not error")
require.Len(t, c, 1, "Must have one enabled pair")
assert.Equal(t, "BTC"+d+"USD", c[0].String(), "GetAvailablePairs format must use config format")
err = b.CurrencyPairs.StorePairs(asset.Spot, pairs, false)
if err != nil {
t.Fatal(err)
}
require.NoError(t, b.CurrencyPairs.StorePairs(asset.Spot, currency.Pairs{btcusdPair}, true), "StorePairs must not error for enabled pairs")
require.NoError(t, b.CurrencyPairs.SetAssetEnabled(asset.Spot, true), "SetAssetEnabled must not error")
defaultpairs, err := currency.NewPairsFromStrings([]string{defaultTestCurrencyPair})
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.StorePairs(asset.Spot, defaultpairs, true)
if err != nil {
t.Fatal(err)
}
format := &currency.PairFormat{
Delimiter: "-",
Index: "",
}
b.CurrencyPairs.UseGlobalFormat = true
b.CurrencyPairs.RequestFormat = format
b.CurrencyPairs.ConfigFormat = format
assetType := asset.Spot
if b.SupportsPair(currency.NewPair(currency.BTC, currency.USD), true, assetType) != nil {
t.Error("Exchange SupportsPair() incorrect value")
}
if b.SupportsPair(currency.NewPair(currency.ETH, currency.USD), false, assetType) != nil {
t.Error("Exchange SupportsPair() incorrect value")
}
asdasdf, err := currency.NewPairFromStrings("ASD", "ASDF")
if err != nil {
t.Fatal(err)
}
if b.SupportsPair(asdasdf, true, assetType) == nil {
t.Error("Exchange SupportsPair() incorrect value")
c, err = b.GetEnabledPairs(asset.Spot)
require.NoError(t, err, "GetEnabledPairs must not error")
require.Len(t, c, 1, "Must have one enabled pair")
assert.Equal(t, "BTC"+d+"USD", c[0].String(), "GetEnabledPairs format must use config format")
}
}
@@ -1155,17 +835,9 @@ func TestFormatExchangeCurrency(t *testing.T) {
Delimiter: "-",
}
p := currency.NewPair(currency.BTC, currency.USD)
expected := defaultTestCurrencyPair
actual, err := b.FormatExchangeCurrency(p, asset.Spot)
if err != nil {
t.Fatal(err)
}
if actual.String() != expected {
t.Errorf("Exchange TestFormatExchangeCurrency %s != %s",
actual, expected)
}
actual, err := b.FormatExchangeCurrency(btcusdPair, asset.Spot)
require.NoError(t, err, "FormatExchangeCurrency must not error")
assert.Equal(t, "BTC-USD", actual.String(), "FormatExchangeCurrency should format pair correctly")
}
func TestSetEnabled(t *testing.T) {
@@ -1235,25 +907,14 @@ func TestSetupDefaults(t *testing.T) {
}
// Test asset types
p, err := currency.NewPairDelimiter(defaultTestCurrencyPair, "-")
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.Store(asset.Spot, &currency.PairStore{
Enabled: currency.Pairs{p},
})
if err != nil {
t.Fatal(err)
}
err = b.SetupDefaults(&cfg)
if err != nil {
t.Fatal(err)
}
err = b.CurrencyPairs.Store(asset.Spot, &currency.PairStore{Enabled: currency.Pairs{btcusdPair}})
require.NoError(t, err, "Store must not error")
require.NoError(t, b.SetupDefaults(&cfg), "SetupDefaults must not error")
ps, err := cfg.CurrencyPairs.Get(asset.Spot)
if err != nil {
t.Fatal(err)
}
if !ps.Enabled.Contains(p, true) {
if !ps.Enabled.Contains(btcusdPair, true) {
t.Error("default pair should be stored in the configs pair store")
}
@@ -1445,48 +1106,26 @@ func TestUpdatePairs(t *testing.T) {
t.Errorf("Exchange UpdatePairs() error: %s", err)
}
// Test empty pair
p, err := currency.NewPairDelimiter(defaultTestCurrencyPair, "-")
if err != nil {
t.Fatal(err)
}
pairs := currency.Pairs{currency.EMPTYPAIR, p}
err = UAC.UpdatePairs(pairs, asset.Spot, true, true)
if !errors.Is(err, currency.ErrCurrencyPairEmpty) {
t.Fatalf("received: '%v' but expected: '%v'", err, currency.ErrCurrencyPairEmpty)
}
err = UAC.UpdatePairs(currency.Pairs{currency.EMPTYPAIR, btcusdPair}, asset.Spot, true, true)
assert.ErrorIs(t, err, currency.ErrCurrencyPairEmpty, "UpdatePairs should error on empty pairs")
pairs = currency.Pairs{p, p}
err = UAC.UpdatePairs(pairs, asset.Spot, false, true)
if !errors.Is(err, currency.ErrPairDuplication) {
t.Fatalf("received: '%v' but expected: '%v'", err, currency.ErrPairDuplication)
}
err = UAC.UpdatePairs(currency.Pairs{btcusdPair, btcusdPair}, asset.Spot, false, true)
assert.ErrorIs(t, err, currency.ErrPairDuplication, "UpdatePairs should error on Duplicates")
pairs = currency.Pairs{p}
err = UAC.UpdatePairs(pairs, asset.Spot, false, true)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}
err = UAC.UpdatePairs(currency.Pairs{btcusdPair}, asset.Spot, false, true)
assert.NoError(t, err, "UpdatePairs should not error")
err = UAC.UpdatePairs(pairs, asset.Spot, true, true)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}
err = UAC.UpdatePairs(currency.Pairs{btcusdPair}, asset.Spot, true, true)
assert.NoError(t, err, "UpdatePairs should not error")
UAC.CurrencyPairs.UseGlobalFormat = true
UAC.CurrencyPairs.ConfigFormat = &currency.PairFormat{
Delimiter: "-",
}
UAC.CurrencyPairs.ConfigFormat = &currency.PairFormat{Delimiter: "-"}
uacPairs, err := UAC.GetEnabledPairs(asset.Spot)
if err != nil {
t.Fatal(err)
}
if !uacPairs.Contains(p, true) {
t.Fatal("expected currency pair not found")
}
require.NoError(t, err, "GetEnabledPairs must not error")
assert.True(t, uacPairs.Contains(btcusdPair, true), "Should contain currency pair")
pairs = currency.Pairs{
pairs := currency.Pairs{
currency.NewPair(currency.XRP, currency.USD),
currency.NewPair(currency.BTC, currency.USD),
currency.NewPair(currency.LTC, currency.USD),

View File

@@ -690,24 +690,22 @@
"websocketResponseCheckTimeout": 30000000,
"websocketResponseMaxLimit": 7000000000,
"websocketTrafficTimeout": 30000000000,
"websocketOrderbookBufferLimit": 5,
"baseCurrencies": "KRW",
"currencyPairs": {
"requestFormat": {
"uppercase": true
"uppercase": true,
"delimiter": "_"
},
"configFormat": {
"uppercase": true,
"index": "KRW"
"delimiter": "-"
},
"useGlobalFormat": true,
"assetTypes": [
"spot"
],
"pairs": {
"spot": {
"enabled": "BTCKRW,ETHKRW,ETCKRW,XRPKRW,BCHKRW,QTUMKRW,BTGKRW,EOSKRW",
"available": "BHPKRW,STEEMKRW,GTOKRW,ETCKRW,STRATKRW,FXKRW,MIXKRW,THETAKRW,QTUMKRW,ADAKRW,MCOKRW,INSKRW,RDNKRW,CONKRW,FABKRW,ETHKRW,HDACKRW,BTCKRW,POWRKRW,CMTKRW,LBAKRW,ETHOSKRW,HCKRW,ETZKRW,PPTKRW,XVGKRW,WTCKRW,TMTGKRW,LOOMKRW,WETKRW,ABTKRW,ITCKRW,GXCKRW,ORBSKRW,ICXKRW,BSVKRW,MXCKRW,MITHKRW,AEKRW,SALTKRW,ARNKRW,TRUEKRW,ENJKRW,GNTKRW,PLYKRW,REPKRW,ZRXKRW,BTGKRW,APISKRW,QKCKRW,LRCKRW,DVPKRW,DADKRW,CHRKRW,BCHKRW,NPXSKRW,PIVXKRW,AMOKRW,RNTKRW,XEMKRW,FCTKRW,WOMKRW,WAXPKRW,DACKRW,OMGKRW,PCMKRW,CROKRW,FNBKRW,ANKRKRW,EOSKRW,KNCKRW,OCNKRW,MTLKRW,XSRKRW,VALORKRW,TRVKRW,AUTOKRW,HYCKRW,AOAKRW,BTTKRW,MBLKRW,VETKRW,XRPKRW,ZILKRW,ELFKRW,LAMBKRW,POLYKRW,IOSTKRW,BZNTKRW,CTXCKRW,BATKRW,FZZKRW,PAYKRW,BCDKRW,SNTKRW,WAVESKRW,XLMKRW,LINKKRW,OGOKRW,WICCKRW,TRXKRW"
"assetEnabled": true,
"enabled": "USDT-KRW,QTUM-KRW,BTC-KRW,ETH-KRW,ETC-KRW,XRP-KRW,BCH-KRW,BTG-KRW,EOS-KRW",
"available": "AVAX-KRW,STRAX-KRW,KSM-KRW,RPL-KRW,ADA-KRW,ONT-KRW,EOS-KRW,STAT-KRW,APM-KRW,XPLA-KRW,STMX-KRW,FET-KRW,XVS-KRW,ROA-KRW,JOE-KRW,BNT-KRW,T-KRW,AUDIO-KRW,MIX-KRW,PUNDIX-KRW,USDC-KRW,ALGO-KRW,CTXC-KRW,IQ-KRW,RLY-KRW,GRT-KRW,NMR-KRW,FTM-KRW,WNCG-KRW,NCT-KRW,CSPR-KRW,TFUEL-KRW,EGG-KRW,MOC-KRW,BAT-KRW,ETC-KRW,TIA-KRW,GRACY-KRW,FRONT-KRW,DAI-KRW,ANKR-KRW,META-KRW,HOOK-KRW,BEL-KRW,MAGIC-KRW,ENTC-KRW,HUNT-KRW,STX-KRW,FIT-KRW,STEEM-KRW,CTSI-KRW,JUP-KRW,CAKE-KRW,DOGE-KRW,SUN-KRW,OCEAN-KRW,SOL-KRW,REQ-KRW,BNB-KRW,GAL-KRW,MBL-KRW,LRC-KRW,ILV-KRW,PEPE-KRW,IOST-KRW,XLM-KRW,CRV-KRW,NFT-KRW,PYR-KRW,TRX-KRW,TAVA-KRW,PYTH-KRW,TT-KRW,AAVE-KRW,KLAY-KRW,BAL-KRW,EVZ-KRW,FX-KRW,UMA-KRW,FLOW-KRW,ALEX-KRW,ELF-KRW,CVC-KRW,FLOKI-KRW,MASK-KRW,GAS-KRW,VIX-KRW,CELR-KRW,BLY-KRW,ARK-KRW,FNSA-KRW,OXT-KRW,VALOR-KRW,XTZ-KRW,HBAR-KRW,ONG-KRW,MTL-KRW,WAVES-KRW,ORBS-KRW,MANTA-KRW,ICX-KRW,SNX-KRW,API3-KRW,PENDLE-KRW,FLZ-KRW,APE-KRW,POWR-KRW,OGN-KRW,EDU-KRW,ARB-KRW,AXS-KRW,MBX-KRW,XRP-KRW,MATIC-KRW,USDT-KRW,1INCH-KRW,STORJ-KRW,UOS-KRW,RVN-KRW,LPT-KRW,OSMO-KRW,ALICE-KRW,LDO-KRW,TEMCO-KRW,COMP-KRW,VET-KRW,SFP-KRW,WIKEN-KRW,LBL-KRW,SHIB-KRW,GMT-KRW,AZIT-KRW,ZBCN-KRW,FLUX-KRW,ALT-KRW,AGI-KRW,SPURS-KRW,GRS-KRW,C98-KRW,ZIL-KRW,BCH-KRW,QTCON-KRW,SEI-KRW,GRND-KRW,SWAP-KRW,ETH-KRW,RSS3-KRW,STPT-KRW,FXS-KRW,SAND-KRW,MAP-KRW,MAV-KRW,LINK-KRW,MVC-KRW,QTUM-KRW,DAR-KRW,FANC-KRW,HIGH-KRW,ARKM-KRW,MANA-KRW,SUSHI-KRW,DVI-KRW,XEC-KRW,BTC-KRW,EL-KRW,THETA-KRW,CELO-KRW,KNC-KRW,POLA-KRW,LOOM-KRW,JASMY-KRW,INJ-KRW,KAVA-KRW,NEO-KRW,BIGTIME-KRW,MINA-KRW,NPT-KRW,IMX-KRW,ASM-KRW,FCT2-KRW,RLC-KRW,HIFI-KRW,CTC-KRW,DYDX-KRW,ZTX-KRW,AGIX-KRW,WEMIX-KRW,GTC-KRW,LM-KRW,OP-KRW,ONIT-KRW,ACS-KRW,LSK-KRW,REI-KRW,ATOM-KRW,WLD-KRW,GLM-KRW,COS-KRW,BTT-KRW,BFC-KRW,ACE-KRW,SC-KRW,BORA-KRW,GHX-KRW,ADP-KRW,STRK-KRW,LEVER-KRW,BOBA-KRW,BOA-KRW,HFT-KRW,RNDR-KRW,ENJ-KRW,RSR-KRW,XPR-KRW,IOTX-KRW,CYBER-KRW,WAXP-KRW,OBSR-KRW,MEV-KRW,UNI-KRW,APT-KRW,DAO-KRW,WAXL-KRW,SIX-KRW,GMX-KRW,RDNT-KRW,BTG-KRW,MNT-KRW,BLUR-KRW,XCN-KRW,YGG-KRW,MXC-KRW,ACH-KRW,RAD-KRW,MLK-KRW,DOT-KRW,JST-KRW,ZRX-KRW,STG-KRW,SOFI-KRW,WOM-KRW,TDROP-KRW,SNT-KRW,COTI-KRW,WOO-KRW,OAS-KRW,CRO-KRW,AQT-KRW,EGLD-KRW,ARPA-KRW,BSV-KRW,ASTR-KRW,AMO-KRW,AERGO-KRW,ID-KRW,SUI-KRW,GALA-KRW,CKB-KRW,BIOT-KRW,CFX-KRW,CHR-KRW,FLR-KRW,FITFI-KRW,YFI-KRW,CTK-KRW,W-KRW,MED-KRW,MKR-KRW,SXP-KRW,HIVE-KRW,CRTS-KRW,CHZ-KRW"
}
}
},
@@ -758,7 +756,13 @@
"iban": "",
"supportedCurrencies": ""
}
]
],
"orderbook": {
"verificationBypass": false,
"websocketBufferLimit": 5,
"websocketBufferEnabled": false,
"publishPeriod": 10000000000
}
},
{
"name": "Bitstamp",