forked from thrasher-corp/gocryptotrader
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpair.go
160 lines (142 loc) · 4.4 KB
/
pair.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package currency
import (
"errors"
"fmt"
"strings"
"unicode"
)
var errCannotCreatePair = errors.New("cannot create currency pair")
// NewBTCUSDT is a shortcut for NewPair(BTC, USDT)
func NewBTCUSDT() Pair {
return NewPair(BTC, USDT)
}
// NewBTCUSD is a shortcut for NewPair(BTC, USD)
func NewBTCUSD() Pair {
return NewPair(BTC, USD)
}
// NewPairDelimiter splits the desired currency string at delimiter, then returns a Pair struct
func NewPairDelimiter(currencyPair, delimiter string) (Pair, error) {
if !strings.Contains(currencyPair, delimiter) {
return EMPTYPAIR,
fmt.Errorf("delimiter: [%s] not found in currencypair string", delimiter)
}
result := strings.Split(currencyPair, delimiter)
if len(result) < 2 {
return EMPTYPAIR,
fmt.Errorf("supplied pair: [%s] cannot be split with %s",
currencyPair,
delimiter)
}
if len(result) > 2 {
result[1] = strings.Join(result[1:], delimiter)
}
return Pair{
Delimiter: delimiter,
Base: NewCode(result[0]),
Quote: NewCode(result[1]),
}, nil
}
// NewPairFromStrings returns a CurrencyPair without a delimiter
func NewPairFromStrings(base, quote string) (Pair, error) {
if strings.Contains(base, " ") {
return EMPTYPAIR,
fmt.Errorf("cannot create pair, invalid base currency string [%s]",
base)
}
if strings.Contains(quote, " ") {
return EMPTYPAIR,
fmt.Errorf("cannot create pair, invalid quote currency string [%s]",
quote)
}
return Pair{Base: NewCode(base), Quote: NewCode(quote)}, nil
}
// NewPair returns a currency pair from currency codes
func NewPair(baseCurrency, quoteCurrency Code) Pair {
return Pair{
Base: baseCurrency,
Quote: quoteCurrency,
}
}
// NewPairWithDelimiter returns a CurrencyPair with a delimiter
func NewPairWithDelimiter(base, quote, delimiter string) Pair {
return Pair{
Base: NewCode(base),
Quote: NewCode(quote),
Delimiter: delimiter,
}
}
// NewPairFromString converts currency string into a new CurrencyPair
// with or without delimiter
func NewPairFromString(currencyPair string) (Pair, error) {
if len(currencyPair) < 3 {
return EMPTYPAIR,
fmt.Errorf("%w from %s string too short to be a currency pair",
errCannotCreatePair,
currencyPair)
}
for x := range currencyPair {
if unicode.IsPunct(rune(currencyPair[x])) {
return Pair{
Base: NewCode(currencyPair[:x]),
Delimiter: string(currencyPair[x]),
Quote: NewCode(currencyPair[x+1:]),
}, nil
}
}
return NewPairFromStrings(currencyPair[0:3], currencyPair[3:])
}
// NewPairFromFormattedPairs matches a supplied currency pair to a list of pairs
// with a specific format. This is helpful for exchanges which
// provide currency pairs with no delimiter so we can match it with a list and
// apply the same format
func NewPairFromFormattedPairs(currencyPair string, pairs Pairs, pairFmt PairFormat) (Pair, error) {
for x := range pairs {
if strings.EqualFold(pairFmt.Format(pairs[x]), currencyPair) {
return pairs[x], nil
}
}
return NewPairFromString(currencyPair)
}
// Format formats the given pair as a string
func (f PairFormat) Format(pair Pair) string {
return pair.Format(f).String()
}
// clone returns a clone of the PairFormat
func (f *PairFormat) clone() *PairFormat {
if f == nil {
return nil
}
c := *f
return &c
}
// MatchPairsWithNoDelimiter will move along a predictable index on the provided currencyPair
// it will then split on that index and verify whether that currencypair exists in the
// supplied pairs
// this allows for us to match strange currencies with no delimiter where it is difficult to
// infer where the delimiter is located eg BETHERETH is BETHER ETH
func MatchPairsWithNoDelimiter(currencyPair string, pairs Pairs, pairFmt PairFormat) (Pair, error) {
for i := range pairs {
fPair := pairs[i].Format(pairFmt)
maxLen := 6
if len(currencyPair) < maxLen {
maxLen = len(currencyPair)
}
for j := 1; j <= maxLen; j++ {
if fPair.Base.String() == currencyPair[0:j] &&
fPair.Quote.String() == currencyPair[j:] {
return fPair, nil
}
}
}
return EMPTYPAIR, fmt.Errorf("currency %v not found in supplied pairs", currencyPair)
}
// GetFormatting returns the formatting style of a pair
func (p Pair) GetFormatting() (PairFormat, error) {
if p.Base.UpperCase != p.Quote.UpperCase {
return PairFormat{}, fmt.Errorf("%w casing mismatch", errPairFormattingInconsistent)
}
return PairFormat{
Uppercase: p.Base.UpperCase,
Delimiter: p.Delimiter,
}, nil
}