Currency package update (#247)

* Initial currency overhaul before service system implementation

* Remove redundant currency string in orderbook.Base
Unexport lastupdated field in orderbook.Base as it was being instantiated multiple times
Add error handling for process orderbook

*  Remove redundant currency string in ticker.Price
 Unexport lastupdated field in ticker.Price
 Add error handling for process ticker function and fix tests

* Phase Two Update

* Update translations to use map type - thankyou to kempeng for spotting this

* Change pair method name from Display -> Format for better readability

* Fixes misspelling and tests

* Implement requested changes from GloriousCode

* Remove reduntant function and streamlined return in currency_translation.go

* Revert pair method naming conventions

* Change currency naming conventions

* Changed code type to exported Item type with underlying string to reduce complexity

* Added interim orderbook process method to orderbook.Base type

* Changed feebuilder struct field to currency.Pair

* Adds fall over system for backup fx providers

* deprecate function and children and fix linter issue with btcmarkets

* Fixed requested changes

* Fix bug and move mtx for rates

* Fixed after rebase oopsies

* Fix linter issues

* Fixes race conditions in testing functions

* Final phase coinmarketcap update

* fix linter issues

* Implement requested changes

* Adds configuration variables to increase/decrease time durations between updating currency file and fetching new currency rates

* Add a collection of tests to improve codecov

* After rebase oopsy fixes for btse

* Fix requested changes

* fix after rebase oopsies and add more efficient comparison checks within currency pair

* Fix linter issues
This commit is contained in:
Ryan O'Hara-Reid
2019-03-19 11:49:05 +11:00
committed by Adrian Gallagher
parent ed760e184e
commit 0990f9d118
189 changed files with 11982 additions and 8055 deletions

View File

@@ -102,7 +102,7 @@ func (b *Base) GetTicker(exchangeName string) string {
for i := range tickerPrices {
packagedTickers = append(packagedTickers, fmt.Sprintf(
"Currency Pair: %s Ask: %f, Bid: %f High: %f Last: %f Low: %f ATH: %f Volume: %f",
tickerPrices[i].CurrencyPair,
tickerPrices[i].Pair,
tickerPrices[i].Ask,
tickerPrices[i].Bid,
tickerPrices[i].High,

View File

@@ -80,7 +80,7 @@ func (c IComm) StageTickerData(exchangeName, assetType string, tickerPrice *tick
TickerStaged[exchangeName][assetType] = make(map[string]ticker.Price)
}
TickerStaged[exchangeName][assetType][tickerPrice.CurrencyPair] = *tickerPrice
TickerStaged[exchangeName][assetType][tickerPrice.Pair.String()] = *tickerPrice
}
// StageOrderbookData stages updated orderbook data for the communications
@@ -97,12 +97,11 @@ func (c IComm) StageOrderbookData(exchangeName, assetType string, ob *orderbook.
OrderbookStaged[exchangeName][assetType] = make(map[string]Orderbook)
}
_, totalAsks := ob.CalculateTotalAsks()
_, totalBids := ob.CalculateTotalBids()
_, totalAsks := ob.TotalAsksAmount()
_, totalBids := ob.TotalBidsAmount()
OrderbookStaged[exchangeName][assetType][ob.CurrencyPair] = Orderbook{
CurrencyPair: ob.CurrencyPair,
OrderbookStaged[exchangeName][assetType][ob.Pair.String()] = Orderbook{
CurrencyPair: ob.Pair.String(),
TotalAsks: totalAsks,
TotalBids: totalBids,
LastUpdated: ob.LastUpdated.String()}
TotalBids: totalBids}
}

View File

@@ -16,7 +16,6 @@ import (
"github.com/thrasher-/gocryptotrader/currency"
"github.com/thrasher-/gocryptotrader/currency/forexprovider"
"github.com/thrasher-/gocryptotrader/currency/forexprovider/base"
"github.com/thrasher-/gocryptotrader/currency/pair"
log "github.com/thrasher-/gocryptotrader/logger"
"github.com/thrasher-/gocryptotrader/portfolio"
)
@@ -114,8 +113,8 @@ type Config struct {
// Deprecated config settings, will be removed at a future date
CurrencyPairFormat *CurrencyPairFormatConfig `json:"currencyPairFormat,omitempty"`
FiatDisplayCurrency string `json:"fiatDispayCurrency,omitempty"`
Cryptocurrencies string `json:"cryptocurrencies,omitempty"`
FiatDisplayCurrency currency.Code `json:"fiatDispayCurrency,omitempty"`
Cryptocurrencies currency.Currencies `json:"cryptocurrencies,omitempty"`
SMS *SMSGlobalConfig `json:"smsGlobal,omitempty"`
}
@@ -143,9 +142,9 @@ type ExchangeConfig struct {
ProxyAddress string `json:"proxyAddress"`
WebsocketURL string `json:"websocketUrl"`
ClientID string `json:"clientId,omitempty"`
AvailablePairs string `json:"availablePairs"`
EnabledPairs string `json:"enabledPairs"`
BaseCurrencies string `json:"baseCurrencies"`
AvailablePairs currency.Pairs `json:"availablePairs"`
EnabledPairs currency.Pairs `json:"enabledPairs"`
BaseCurrencies currency.Currencies `json:"baseCurrencies"`
AssetTypes string `json:"assetTypes"`
SupportsAutoPairUpdates bool `json:"supportsAutoPairUpdates"`
PairsLastUpdated int64 `json:"pairsLastUpdated,omitempty"`
@@ -178,11 +177,13 @@ type BankTransaction struct {
// CurrencyConfig holds all the information needed for currency related manipulation
type CurrencyConfig struct {
ForexProviders []base.Settings `json:"forexProviders"`
CryptocurrencyProvider CryptocurrencyProvider `json:"cryptocurrencyProvider"`
Cryptocurrencies string `json:"cryptocurrencies"`
CurrencyPairFormat *CurrencyPairFormatConfig `json:"currencyPairFormat"`
FiatDisplayCurrency string `json:"fiatDisplayCurrency"`
ForexProviders []base.Settings `json:"forexProviders"`
CryptocurrencyProvider CryptocurrencyProvider `json:"cryptocurrencyProvider"`
Cryptocurrencies currency.Currencies `json:"cryptocurrencies"`
CurrencyPairFormat *CurrencyPairFormatConfig `json:"currencyPairFormat"`
FiatDisplayCurrency currency.Code `json:"fiatDisplayCurrency"`
CurrencyFileUpdateDuration time.Duration `json:"currencyFileUpdateDuration"`
ForeignExchangeUpdateDuration time.Duration `json:"foreignExchangeUpdateDuration"`
}
// CryptocurrencyProvider defines coinmarketcap tools
@@ -539,10 +540,10 @@ func (c *Config) CheckPairConsistency(exchName string) error {
return err
}
var pairs, pairsRemoved []pair.CurrencyPair
var pairs, pairsRemoved currency.Pairs
update := false
for x := range enabledPairs {
if !pair.Contains(availPairs, enabledPairs[x], true) {
if !availPairs.Contains(enabledPairs[x], true) {
update = true
pairsRemoved = append(pairsRemoved, enabledPairs[x])
continue
@@ -560,10 +561,13 @@ func (c *Config) CheckPairConsistency(exchName string) error {
}
if len(pairs) == 0 {
exchCfg.EnabledPairs = pair.RandomPairFromPairs(availPairs).Pair().String()
log.Debugf("Exchange %s: No enabled pairs found in available pairs, randomly added %v\n", exchName, exchCfg.EnabledPairs)
exchCfg.EnabledPairs = append(exchCfg.EnabledPairs,
availPairs.GetRandomPair())
log.Debugf("Exchange %s: No enabled pairs found in available pairs, randomly added %v\n",
exchName,
exchCfg.EnabledPairs)
} else {
exchCfg.EnabledPairs = common.JoinStrings(pair.PairsToStringArray(pairs), ",")
exchCfg.EnabledPairs = pairs
}
err = c.UpdateExchangeConfig(&exchCfg)
@@ -571,44 +575,44 @@ func (c *Config) CheckPairConsistency(exchName string) error {
return err
}
log.Debugf("Exchange %s: Removing enabled pair(s) %v from enabled pairs as it isn't an available pair", exchName, pair.PairsToStringArray(pairsRemoved))
log.Debugf("Exchange %s: Removing enabled pair(s) %v from enabled pairs as it isn't an available pair",
exchName,
pairsRemoved.Strings())
return nil
}
// SupportsPair returns true or not whether the exchange supports the supplied
// pair
func (c *Config) SupportsPair(exchName string, p pair.CurrencyPair) (bool, error) {
func (c *Config) SupportsPair(exchName string, p currency.Pair) (bool, error) {
pairs, err := c.GetAvailablePairs(exchName)
if err != nil {
return false, err
}
return pair.Contains(pairs, p, false), nil
return pairs.Contains(p, false), nil
}
// GetAvailablePairs returns a list of currency pairs for a specifc exchange
func (c *Config) GetAvailablePairs(exchName string) ([]pair.CurrencyPair, error) {
func (c *Config) GetAvailablePairs(exchName string) (currency.Pairs, error) {
exchCfg, err := c.GetExchangeConfig(exchName)
if err != nil {
return nil, err
}
pairs := pair.FormatPairs(common.SplitStrings(exchCfg.AvailablePairs, ","),
exchCfg.ConfigCurrencyPairFormat.Delimiter,
exchCfg.ConfigCurrencyPairFormat.Index)
return pairs, nil
return exchCfg.AvailablePairs.Format(exchCfg.ConfigCurrencyPairFormat.Delimiter,
exchCfg.ConfigCurrencyPairFormat.Index,
exchCfg.ConfigCurrencyPairFormat.Uppercase), nil
}
// GetEnabledPairs returns a list of currency pairs for a specifc exchange
func (c *Config) GetEnabledPairs(exchName string) ([]pair.CurrencyPair, error) {
func (c *Config) GetEnabledPairs(exchName string) (currency.Pairs, error) {
exchCfg, err := c.GetExchangeConfig(exchName)
if err != nil {
return nil, err
}
pairs := pair.FormatPairs(common.SplitStrings(exchCfg.EnabledPairs, ","),
exchCfg.ConfigCurrencyPairFormat.Delimiter,
exchCfg.ConfigCurrencyPairFormat.Index)
return pairs, nil
return exchCfg.AvailablePairs.Format(exchCfg.ConfigCurrencyPairFormat.Delimiter,
exchCfg.ConfigCurrencyPairFormat.Index,
exchCfg.ConfigCurrencyPairFormat.Uppercase), nil
}
// GetEnabledExchanges returns a list of enabled exchanges
@@ -758,13 +762,13 @@ func (c *Config) CheckExchangeConfigValues() error {
if exch.Name == "" {
return fmt.Errorf(ErrExchangeNameEmpty, i)
}
if exch.AvailablePairs == "" {
if len(exch.AvailablePairs) == 0 {
return fmt.Errorf(ErrExchangeAvailablePairsEmpty, exch.Name)
}
if exch.EnabledPairs == "" {
if len(exch.EnabledPairs) == 0 {
return fmt.Errorf(ErrExchangeEnabledPairsEmpty, exch.Name)
}
if exch.BaseCurrencies == "" {
if len(exch.BaseCurrencies) == 0 {
return fmt.Errorf(ErrExchangeBaseCurrenciesEmpty, exch.Name)
}
if exch.AuthenticatedAPISupport { // non-fatal error
@@ -962,12 +966,12 @@ func (c *Config) CheckCurrencyConfigValues() error {
}
}
if c.Currency.Cryptocurrencies == "" {
if c.Cryptocurrencies != "" {
if c.Currency.Cryptocurrencies.Join() == "" {
if c.Cryptocurrencies.Join() != "" {
c.Currency.Cryptocurrencies = c.Cryptocurrencies
c.Cryptocurrencies = ""
c.Cryptocurrencies = nil
} else {
c.Currency.Cryptocurrencies = currency.DefaultCryptoCurrencies
c.Currency.Cryptocurrencies = currency.GetDefaultCryptocurrencies()
}
}
@@ -983,12 +987,12 @@ func (c *Config) CheckCurrencyConfigValues() error {
}
}
if c.Currency.FiatDisplayCurrency == "" {
if c.FiatDisplayCurrency != "" {
if c.Currency.FiatDisplayCurrency.IsEmpty() {
if c.FiatDisplayCurrency.IsEmpty() {
c.Currency.FiatDisplayCurrency = c.FiatDisplayCurrency
c.FiatDisplayCurrency = ""
c.FiatDisplayCurrency = currency.NewCode("")
} else {
c.Currency.FiatDisplayCurrency = "USD"
c.Currency.FiatDisplayCurrency = currency.USD
}
}
return nil
@@ -997,24 +1001,24 @@ func (c *Config) CheckCurrencyConfigValues() error {
// RetrieveConfigCurrencyPairs splits, assigns and verifies enabled currency
// pairs either cryptoCurrencies or fiatCurrencies
func (c *Config) RetrieveConfigCurrencyPairs(enabledOnly bool) error {
cryptoCurrencies := common.SplitStrings(c.Cryptocurrencies, ",")
fiatCurrencies := common.SplitStrings(currency.DefaultCurrencies, ",")
cryptoCurrencies := c.Currency.Cryptocurrencies
fiatCurrencies := currency.GetFiatCurrencies()
for x := range c.Exchanges {
if !c.Exchanges[x].Enabled && enabledOnly {
continue
}
baseCurrencies := common.SplitStrings(c.Exchanges[x].BaseCurrencies, ",")
baseCurrencies := c.Exchanges[x].BaseCurrencies
for y := range baseCurrencies {
if !common.StringDataCompare(fiatCurrencies, common.StringToUpper(baseCurrencies[y])) {
fiatCurrencies = append(fiatCurrencies, common.StringToUpper(baseCurrencies[y]))
if !fiatCurrencies.Contains(baseCurrencies[y]) {
fiatCurrencies = append(fiatCurrencies, baseCurrencies[y])
}
}
}
for x := range c.Exchanges {
var pairs []pair.CurrencyPair
var pairs []currency.Pair
var err error
if !c.Exchanges[x].Enabled && enabledOnly {
pairs, err = c.GetEnabledPairs(c.Exchanges[x].Name)
@@ -1027,20 +1031,20 @@ func (c *Config) RetrieveConfigCurrencyPairs(enabledOnly bool) error {
}
for y := range pairs {
if !common.StringDataCompare(fiatCurrencies, pairs[y].FirstCurrency.Upper().String()) &&
!common.StringDataCompare(cryptoCurrencies, pairs[y].FirstCurrency.Upper().String()) {
cryptoCurrencies = append(cryptoCurrencies, pairs[y].FirstCurrency.Upper().String())
if !fiatCurrencies.Contains(pairs[y].Base) &&
!cryptoCurrencies.Contains(pairs[y].Base) {
cryptoCurrencies = append(cryptoCurrencies, pairs[y].Base)
}
if !common.StringDataCompare(fiatCurrencies, pairs[y].SecondCurrency.Upper().String()) &&
!common.StringDataCompare(cryptoCurrencies, pairs[y].SecondCurrency.Upper().String()) {
cryptoCurrencies = append(cryptoCurrencies, pairs[y].SecondCurrency.Upper().String())
if !fiatCurrencies.Contains(pairs[y].Quote) &&
!cryptoCurrencies.Contains(pairs[y].Quote) {
cryptoCurrencies = append(cryptoCurrencies, pairs[y].Quote)
}
}
}
currency.Update(fiatCurrencies, false)
currency.Update(cryptoCurrencies, true)
currency.UpdateCurrencies(fiatCurrencies, false)
currency.UpdateCurrencies(cryptoCurrencies, true)
return nil
}

View File

@@ -4,7 +4,7 @@ import (
"testing"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
log "github.com/thrasher-/gocryptotrader/logger"
)
@@ -304,8 +304,8 @@ func TestCheckPairConsistency(t *testing.T) {
cfg.Exchanges = append(cfg.Exchanges, ExchangeConfig{
Name: "TestExchange",
Enabled: true,
AvailablePairs: "DOGE_USD,DOGE_AUD",
EnabledPairs: "DOGE_USD,DOGE_AUD,DOGE_BTC",
AvailablePairs: currency.NewPairsFromStrings([]string{"DOGE_USD,DOGE_AUD"}),
EnabledPairs: currency.NewPairsFromStrings([]string{"DOGE_USD,DOGE_AUD,DOGE_BTC"}),
ConfigCurrencyPairFormat: &CurrencyPairFormatConfig{
Uppercase: true,
Delimiter: "_",
@@ -326,7 +326,7 @@ func TestCheckPairConsistency(t *testing.T) {
t.Error("Test failed. CheckPairConsistency error:", err)
}
tec.EnabledPairs = "DOGE_LTC,BTC_LTC"
tec.EnabledPairs = currency.NewPairsFromStrings([]string{"DOGE_LTC,BTC_LTC"})
err = cfg.UpdateExchangeConfig(&tec)
if err != nil {
t.Error("Test failed. CheckPairConsistency Update config failed, error:", err)
@@ -347,14 +347,16 @@ func TestSupportsPair(t *testing.T) {
)
}
_, err = cfg.SupportsPair("asdf", pair.NewCurrencyPair("BTC", "USD"))
_, err = cfg.SupportsPair("asdf",
currency.NewPair(currency.BTC, currency.USD))
if err == nil {
t.Error(
"Test failed. TestSupportsPair. Non-existent exchange returned nil error",
)
}
_, err = cfg.SupportsPair("Bitfinex", pair.NewCurrencyPair("BTC", "USD"))
_, err = cfg.SupportsPair("Bitfinex",
currency.NewPair(currency.BTC, currency.USD))
if err != nil {
t.Errorf(
"Test failed. TestSupportsPair. Incorrect values. Err: %s", err,
@@ -687,7 +689,7 @@ func TestCheckExchangeConfigValues(t *testing.T) {
)
}
checkExchangeConfigValues.Exchanges[0].BaseCurrencies = ""
checkExchangeConfigValues.Exchanges[0].BaseCurrencies = currency.NewCurrenciesFromStringArray([]string{""})
err = checkExchangeConfigValues.CheckExchangeConfigValues()
if err == nil {
t.Errorf(
@@ -695,7 +697,7 @@ func TestCheckExchangeConfigValues(t *testing.T) {
)
}
checkExchangeConfigValues.Exchanges[0].EnabledPairs = ""
checkExchangeConfigValues.Exchanges[0].EnabledPairs = currency.NewPairsFromStrings([]string{""})
err = checkExchangeConfigValues.CheckExchangeConfigValues()
if err == nil {
t.Errorf(
@@ -703,7 +705,7 @@ func TestCheckExchangeConfigValues(t *testing.T) {
)
}
checkExchangeConfigValues.Exchanges[0].AvailablePairs = ""
checkExchangeConfigValues.Exchanges[0].AvailablePairs = currency.NewPairsFromStrings([]string{""})
err = checkExchangeConfigValues.CheckExchangeConfigValues()
if err == nil {
t.Errorf(
@@ -719,7 +721,7 @@ func TestCheckExchangeConfigValues(t *testing.T) {
)
}
checkExchangeConfigValues.Cryptocurrencies = ""
checkExchangeConfigValues.Cryptocurrencies = currency.NewCurrenciesFromStringArray([]string{""})
err = checkExchangeConfigValues.CheckExchangeConfigValues()
if err == nil {
t.Errorf(
@@ -728,7 +730,7 @@ func TestCheckExchangeConfigValues(t *testing.T) {
}
checkExchangeConfigValues.Exchanges = checkExchangeConfigValues.Exchanges[:0]
checkExchangeConfigValues.Cryptocurrencies = "TESTYTEST"
checkExchangeConfigValues.Cryptocurrencies = currency.NewCurrenciesFromStringArray([]string{"TESTYTEST"})
err = checkExchangeConfigValues.CheckExchangeConfigValues()
if err == nil {
t.Errorf(
@@ -924,12 +926,12 @@ func TestUpdateConfig(t *testing.T) {
t.Fatalf("Test failed. Error should of been thrown for invalid path")
}
newCfg.Currency.Cryptocurrencies = ""
newCfg.Currency.Cryptocurrencies = currency.NewCurrenciesFromStringArray([]string{""})
err = c.UpdateConfig(ConfigTestFile, newCfg)
if err != nil {
t.Errorf("Test failed. %s", err)
}
if c.Currency.Cryptocurrencies == "" {
if c.Currency.Cryptocurrencies.Join() == "" {
t.Fatalf("Test failed. Cryptocurrencies should have been repopulated")
}
}

View File

@@ -72,7 +72,9 @@
"uppercase": true,
"delimiter": "-"
},
"fiatDisplayCurrency": "USD"
"fiatDisplayCurrency": "USD",
"currencyFileUpdateDuration": 0,
"foreignExchangeUpdateDuration": 0
},
"communications": {
"slack": {

2102
currency/code.go Normal file

File diff suppressed because it is too large Load Diff

426
currency/code_test.go Normal file
View File

@@ -0,0 +1,426 @@
package currency
import (
"testing"
"github.com/thrasher-/gocryptotrader/common"
)
func TestRoleString(t *testing.T) {
if Unset.String() != UnsetRollString {
t.Errorf("Test Failed - Role String() error expected %s but recieved %s",
UnsetRollString,
Unset)
}
if Fiat.String() != FiatCurrencyString {
t.Errorf("Test Failed - Role String() error expected %s but recieved %s",
FiatCurrencyString,
Fiat)
}
if Cryptocurrency.String() != CryptocurrencyString {
t.Errorf("Test Failed - Role String() error expected %s but recieved %s",
CryptocurrencyString,
Cryptocurrency)
}
if Token.String() != TokenString {
t.Errorf("Test Failed - Role String() error expected %s but recieved %s",
TokenString,
Token)
}
if Contract.String() != ContractString {
t.Errorf("Test Failed - Role String() error expected %s but recieved %s",
ContractString,
Contract)
}
var random Role = 1 << 7
if random.String() != "UNKNOWN" {
t.Errorf("Test Failed - Role String() error expected %s but recieved %s",
"UNKNOWN",
random)
}
}
func TestRoleMarshalJSON(t *testing.T) {
d, err := common.JSONEncode(Fiat)
if err != nil {
t.Error("Test Failed - Role MarshalJSON() error", err)
}
expected := `"fiatCurrency"`
if string(d) != expected {
t.Errorf("Test Failed - Role MarshalJSON() error expected %s but recieved %s",
expected,
string(d))
}
}
func TestRoleUnmarshalJSON(t *testing.T) {
type AllTheRoles struct {
RoleOne Role `json:"RoleOne"`
RoleTwo Role `json:"RoleTwo"`
RoleThree Role `json:"RoleThree"`
RoleFour Role `json:"RoleFour"`
RoleFive Role `json:"RoleFive"`
RoleUnknown Role `json:"RoleUnknown"`
}
var outgoing = AllTheRoles{
RoleOne: Unset,
RoleTwo: Cryptocurrency,
RoleThree: Fiat,
RoleFour: Token,
RoleFive: Contract,
}
e, err := common.JSONEncode(1337)
if err != nil {
t.Fatal("Test Failed - Role UnmarshalJSON() error", err)
}
var incoming AllTheRoles
err = common.JSONDecode(e, &incoming)
if err == nil {
t.Fatal("Test Failed - Role UnmarshalJSON() error", err)
}
e, err = common.JSONEncode(outgoing)
if err != nil {
t.Fatal("Test Failed - Role UnmarshalJSON() error", err)
}
err = common.JSONDecode(e, &incoming)
if err != nil {
t.Fatal("Test Failed - Role UnmarshalJSON() error", err)
}
if incoming.RoleOne != Unset {
t.Errorf("Test Failed - Role String() error expected %s but recieved %s",
Unset,
incoming.RoleOne)
}
if incoming.RoleTwo != Cryptocurrency {
t.Errorf("Test Failed - Role String() error expected %s but recieved %s",
Cryptocurrency,
incoming.RoleTwo)
}
if incoming.RoleThree != Fiat {
t.Errorf("Test Failed - Role String() error expected %s but recieved %s",
Fiat,
incoming.RoleThree)
}
if incoming.RoleFour != Token {
t.Errorf("Test Failed - Role String() error expected %s but recieved %s",
Token,
incoming.RoleFour)
}
if incoming.RoleFive != Contract {
t.Errorf("Test Failed - Role String() error expected %s but recieved %s",
Contract,
incoming.RoleFive)
}
if incoming.RoleUnknown != Unset {
t.Errorf("Test Failed - Role String() error expected %s but recieved %s",
incoming.RoleFive,
incoming.RoleUnknown)
}
}
func TestBaseCode(t *testing.T) {
var main BaseCodes
if main.HasData() {
t.Errorf("Test Failed - BaseCode HasData() error expected false but recieved %v",
main.HasData())
}
catsCode := main.Register("CATS")
if !main.HasData() {
t.Errorf("Test Failed - BaseCode HasData() error expected true but recieved %v",
main.HasData())
}
if !main.Register("CATS").Match(catsCode) {
t.Errorf("Test Failed - BaseCode Match() error expected true but recieved %v",
false)
}
if main.Register("DOGS").Match(catsCode) {
t.Errorf("Test Failed - BaseCode Match() error expected false but recieved %v",
true)
}
loadedCurrencies := main.GetCurrencies()
if loadedCurrencies.Contains(main.Register("OWLS")) {
t.Errorf("Test Failed - BaseCode Contains() error expected false but recieved %v",
true)
}
if !loadedCurrencies.Contains(catsCode) {
t.Errorf("Test Failed - BaseCode Contains() error expected true but recieved %v",
false)
}
err := main.UpdateContract("Bitcoin Perpetual", "XBTUSD", "Bitmex")
if err != nil {
t.Error("Test Failed - BaseCode UpdateContract error", err)
}
err = main.UpdateCryptocurrency("Bitcoin", "BTC", 1337)
if err != nil {
t.Error("Test Failed - BaseCode UpdateContract error", err)
}
err = main.UpdateFiatCurrency("Australian Dollar", "AUD", 1336)
if err != nil {
t.Error("Test Failed - BaseCode UpdateContract error", err)
}
err = main.UpdateToken("Populous", "PPT", "ETH", 1335)
if err != nil {
t.Error("Test Failed - BaseCode UpdateContract error", err)
}
contract := main.Register("XBTUSD")
if contract.IsFiatCurrency() {
t.Errorf("Test Failed - BaseCode IsFiatCurrency() error expected false but recieved %v",
true)
}
if contract.IsCryptocurrency() {
t.Errorf("Test Failed - BaseCode IsFiatCurrency() error expected false but recieved %v",
true)
}
if contract.IsDefaultFiatCurrency() {
t.Errorf("Test Failed - BaseCode IsDefaultFiatCurrency() error expected false but recieved %v",
true)
}
if contract.IsDefaultFiatCurrency() {
t.Errorf("Test Failed - BaseCode IsFiatCurrency() error expected false but recieved %v",
true)
}
err = main.LoadItem(Item{
ID: 0,
FullName: "Cardano",
Role: Cryptocurrency,
Symbol: "ADA",
})
if err != nil {
t.Error("Test Failed - BaseCode LoadItem() error", err)
}
full, err := main.GetFullCurrencyData()
if err != nil {
t.Error("Test Failed - BaseCode GetFullCurrencyData error", err)
}
if len(full.Contracts) != 1 {
t.Errorf("Test Failed - BaseCode GetFullCurrencyData() error expected 1 but recieved %v",
len(full.Contracts))
}
if len(full.Cryptocurrency) != 2 {
t.Errorf("Test Failed - BaseCode GetFullCurrencyData() error expected 1 but recieved %v",
len(full.Cryptocurrency))
}
if len(full.FiatCurrency) != 1 {
t.Errorf("Test Failed - BaseCode GetFullCurrencyData() error expected 1 but recieved %v",
len(full.FiatCurrency))
}
if len(full.Token) != 1 {
t.Errorf("Test Failed - BaseCode GetFullCurrencyData() error expected 1 but recieved %v",
len(full.Token))
}
if len(full.UnsetCurrency) != 3 {
t.Errorf("Test Failed - BaseCode GetFullCurrencyData() error expected 3 but recieved %v",
len(full.UnsetCurrency))
}
if !full.LastMainUpdate.IsZero() {
t.Errorf("Test Failed - BaseCode GetFullCurrencyData() error expected 0 but recieved %s",
full.LastMainUpdate)
}
}
func TestCodeString(t *testing.T) {
expected := "TEST"
cc := NewCode("TEST")
if cc.String() != expected {
t.Errorf("Test Failed - Currency Code String() error expected %s but recieved %s",
expected, cc)
}
}
func TestCodeLower(t *testing.T) {
expected := "test"
cc := NewCode("TEST")
if cc.Lower().String() != expected {
t.Errorf("Test Failed - Currency Code Lower() error expected %s but recieved %s",
expected,
cc.Lower())
}
}
func TestCodeUpper(t *testing.T) {
expected := "TEST"
cc := NewCode("test")
if cc.Upper().String() != expected {
t.Errorf("Test Failed - Currency Code Upper() error expected %s but recieved %s",
expected,
cc.Upper())
}
}
func TestCodeUnmarshalJSON(t *testing.T) {
var unmarshalHere Code
expected := "BRO"
encoded, err := common.JSONEncode(expected)
if err != nil {
t.Fatal("Test Failed - Currency Code UnmarshalJSON error", err)
}
err = common.JSONDecode(encoded, &unmarshalHere)
if err != nil {
t.Fatal("Test Failed - Currency Code UnmarshalJSON error", err)
}
err = common.JSONDecode(encoded, &unmarshalHere)
if err != nil {
t.Fatal("Test Failed - Currency Code UnmarshalJSON error", err)
}
if unmarshalHere.String() != expected {
t.Errorf("Test Failed - Currency Code Upper() error expected %s but recieved %s",
expected,
unmarshalHere)
}
}
func TestCodeMarshalJSON(t *testing.T) {
quickstruct := struct {
Codey Code `json:"sweetCodes"`
}{
Codey: NewCode("BRO"),
}
expectedJSON := `{"sweetCodes":"BRO"}`
encoded, err := common.JSONEncode(quickstruct)
if err != nil {
t.Fatal("Test Failed - Currency Code UnmarshalJSON error", err)
}
if string(encoded) != expectedJSON {
t.Errorf("Test Failed - Currency Code Upper() error expected %s but recieved %s",
expectedJSON,
string(encoded))
}
quickstruct = struct {
Codey Code `json:"sweetCodes"`
}{
Codey: Code{}, // nil code
}
encoded, err = common.JSONEncode(quickstruct)
if err != nil {
t.Fatal("Test Failed - Currency Code UnmarshalJSON error", err)
}
newExpectedJSON := `{"sweetCodes":""}`
if string(encoded) != newExpectedJSON {
t.Errorf("Test Failed - Currency Code Upper() error expected %s but recieved %s",
newExpectedJSON, string(encoded))
}
}
func TestIsDefaultCurrency(t *testing.T) {
if !USD.IsDefaultFiatCurrency() {
t.Errorf("Test Failed. TestIsDefaultCurrency Cannot match currency %s.",
USD)
}
if !AUD.IsDefaultFiatCurrency() {
t.Errorf("Test Failed. TestIsDefaultCurrency Cannot match currency, %s.",
AUD)
}
if LTC.IsDefaultFiatCurrency() {
t.Errorf("Test Failed. TestIsDefaultCurrency Function return is incorrect with, %s.",
LTC)
}
}
func TestIsDefaultCryptocurrency(t *testing.T) {
if !BTC.IsDefaultCryptocurrency() {
t.Errorf("Test Failed. TestIsDefaultCryptocurrency cannot match currency, %s.",
BTC)
}
if !LTC.IsDefaultCryptocurrency() {
t.Errorf("Test Failed. TestIsDefaultCryptocurrency cannot match currency, %s.",
LTC)
}
if AUD.IsDefaultCryptocurrency() {
t.Errorf("Test Failed. TestIsDefaultCryptocurrency function return is incorrect with, %s.",
AUD)
}
}
func TestIsFiatCurrency(t *testing.T) {
if !USD.IsFiatCurrency() {
t.Errorf(
"Test Failed. TestIsFiatCurrency cannot match currency, %s.", USD)
}
if !CNY.IsFiatCurrency() {
t.Errorf(
"Test Failed. TestIsFiatCurrency cannot match currency, %s.", CNY)
}
if LINO.IsFiatCurrency() {
t.Errorf(
"Test Failed. TestIsFiatCurrency cannot match currency, %s.", LINO,
)
}
}
func TestIsCryptocurrency(t *testing.T) {
if !BTC.IsCryptocurrency() {
t.Errorf("Test Failed. TestIsFiatCurrency cannot match currency, %s.",
BTC)
}
if !LTC.IsCryptocurrency() {
t.Errorf("Test Failed. TestIsFiatCurrency cannot match currency, %s.",
LTC)
}
if AUD.IsCryptocurrency() {
t.Errorf("Test Failed. TestIsFiatCurrency cannot match currency, %s.",
AUD)
}
}
func TestItemString(t *testing.T) {
expected := "Hello,World"
newItem := Item{
FullName: expected,
}
if newItem.String() != expected {
t.Errorf("Test Failed - Item String() error expected %s but recieved %s",
expected,
newItem)
}
}

View File

@@ -71,14 +71,20 @@ type CryptoCurrencyInfo map[string]struct {
// CryptoCurrencyMap defines a cryptocurrency struct
type CryptoCurrencyMap struct {
ID int `json:"id"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Slug string `json:"slug"`
IsActive int `json:"is_active"`
FirstHistoricalData time.Time `json:"first_historical_data"`
LastHistoricalData time.Time `json:"last_historical_data"`
Platform interface{} `json:"platform"`
ID int `json:"id"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Slug string `json:"slug"`
IsActive int `json:"is_active"`
FirstHistoricalData time.Time `json:"first_historical_data"`
LastHistoricalData time.Time `json:"last_historical_data"`
Platform struct {
ID int `json:"id"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Slug string `json:"slug"`
TokenAddress string `json:"token_address"`
} `json:"platform"`
}
// CryptocurrencyHistoricalListings defines a historical listing data

361
currency/conversion.go Normal file
View File

@@ -0,0 +1,361 @@
package currency
import (
"errors"
"fmt"
"sync"
log "github.com/thrasher-/gocryptotrader/logger"
)
// ConversionRates defines protected conversion rate map for concurrent updating
// and retrieval of foreign exchange rates for mainly fiat currencies
type ConversionRates struct {
m map[*Item]map[*Item]*float64
mtx sync.Mutex
}
// HasData returns if conversion rates are present
func (c *ConversionRates) HasData() bool {
c.mtx.Lock()
defer c.mtx.Unlock()
if c.m == nil {
return false
}
return len(c.m) != 0
}
// GetRate returns a rate from the conversion rate list
func (c *ConversionRates) GetRate(from, to Code) (float64, error) {
if from.Item == USDT.Item {
from = USD
}
if to.Item == USDT.Item {
to = USD
}
if from.Item == RUR.Item {
from = RUB
}
if to.Item == RUR.Item {
to = RUB
}
if from.Item == to.Item {
return 1, nil
}
c.mtx.Lock()
defer c.mtx.Unlock()
p, ok := c.m[from.Item][to.Item]
if !ok {
return 0, fmt.Errorf("rate not found for from %s to %s conversion",
from,
to)
}
return *p, nil
}
// Register registers a new conversion rate if not found adds it and allows for
// quick updates
func (c *ConversionRates) Register(from, to Code) (Conversion, error) {
if from.IsCryptocurrency() {
return Conversion{}, errors.New("from currency is a cryptocurrency value")
}
if to.IsCryptocurrency() {
return Conversion{}, errors.New("to currency is a cryptocurrency value")
}
c.mtx.Lock()
defer c.mtx.Unlock()
p, ok := c.m[from.Item][to.Item]
if !ok {
log.Errorf("currency conversion rate not found from %s to %s", from, to)
return Conversion{}, errors.New("no rate found")
}
i, ok := c.m[to.Item][from.Item]
if !ok {
log.Errorf("currency conversion inversion rate not found from %s to %s",
to,
from)
return Conversion{}, errors.New("no rate found")
}
return Conversion{From: from, To: to, rate: p, mtx: &c.mtx, inverseRate: i},
nil
}
// Update updates the full conversion rate values including inversion and
// cross rates
func (c *ConversionRates) Update(m map[string]float64) error {
if len(m) == 0 {
return errors.New("no data given")
}
if storage.IsVerbose() {
log.Debug("Conversion rates are being updated.")
}
solidvalues := make(map[Code]map[Code]float64)
var list []Code // Verification list, cross check all currencies coming in
var mainBaseCurrency Code
for key, val := range m {
code1, err := storage.ValidateFiatCode(key[:3])
if err != nil {
return err
}
if mainBaseCurrency == (Code{}) {
mainBaseCurrency = code1
}
code2, err := storage.ValidateFiatCode(key[3:])
if err != nil {
return err
}
if code1 == code2 { // Get rid of same conversions
continue
}
var codeOneFound, codeTwoFound bool
// Check and add to our funky list
for i := range list {
if list[i] == code1 {
codeOneFound = true
if codeTwoFound {
break
}
}
if list[i] == code2 {
codeTwoFound = true
if codeOneFound {
break
}
}
}
if !codeOneFound {
list = append(list, code1)
}
if !codeTwoFound {
list = append(list, code2)
}
if solidvalues[code1] == nil {
solidvalues[code1] = make(map[Code]float64)
}
solidvalues[code1][code2] = val
// Input inverse values 1/val to swap from -> to and vice versa
if solidvalues[code2] == nil {
solidvalues[code2] = make(map[Code]float64)
}
solidvalues[code2][code1] = 1 / val
}
for _, base := range list {
for _, term := range list {
if base == term {
continue
}
_, ok := solidvalues[base][term]
if !ok {
var crossRate float64
// Check inversion to speed things up
v, ok := solidvalues[term][base]
if !ok {
v1, ok := solidvalues[mainBaseCurrency][base]
if !ok {
return fmt.Errorf("value not found base %s term %s",
mainBaseCurrency,
base)
}
v2, ok := solidvalues[mainBaseCurrency][term]
if !ok {
return fmt.Errorf("value not found base %s term %s",
mainBaseCurrency,
term)
}
crossRate = v2 / v1
} else {
crossRate = 1 / v
}
if storage.IsVerbose() {
log.Debugf("Conversion from %s to %s deriving cross rate value %f",
base,
term,
crossRate)
}
solidvalues[base][term] = crossRate
}
}
}
c.m = nil
for key, val := range solidvalues {
for key2, val2 := range val {
if c.m == nil {
c.m = make(map[*Item]map[*Item]*float64)
}
if c.m[key.Item] == nil {
c.m[key.Item] = make(map[*Item]*float64)
}
p := c.m[key.Item][key2.Item]
if p == nil {
newPalsAndFriends := val2
c.m[key.Item][key2.Item] = &newPalsAndFriends
} else {
*p = val2
}
}
}
return nil
}
// GetFullRates returns the full conversion list
func (c *ConversionRates) GetFullRates() Conversions {
var conversions Conversions
c.mtx.Lock()
for key, val := range c.m {
for key2, val2 := range val {
conversions = append(conversions, Conversion{
From: Code{Item: key},
To: Code{Item: key2},
rate: val2,
mtx: &c.mtx,
})
}
}
c.mtx.Unlock()
return conversions
}
// Conversions define a list of conversion data
type Conversions []Conversion
// Slice exposes the underlying Conversion slice type
func (c Conversions) Slice() []Conversion {
return c
}
// NewConversionFromString splits a string from a foreign exchange provider
func NewConversionFromString(p string) (Conversion, error) {
return NewConversionFromStrings(p[:3], p[3:])
}
// NewConversion returns a conversion rate object that allows for
// obtaining efficient rate values when needed
func NewConversion(from, to Code) (Conversion, error) {
return storage.NewConversion(from, to)
}
// NewConversionFromStrings assigns or finds a new conversion unit
func NewConversionFromStrings(from, to string) (Conversion, error) {
return NewConversion(NewCode(from), NewCode(to))
}
// Conversion defines a specific currency conversion for a rate
type Conversion struct {
From Code
To Code
rate *float64
inverseRate *float64
mtx *sync.Mutex
}
// IsInvalid returns true if both from and to currencies are the same
func (c Conversion) IsInvalid() bool {
if c.From.Item == nil || c.To.Item == nil {
return true
}
return c.From.Item == c.To.Item
}
// IsFiat checks to see if the from and to currency is a fiat e.g. EURUSD
func (c Conversion) IsFiat() bool {
return storage.IsFiatCurrency(c.From) && storage.IsFiatCurrency(c.To)
}
// String returns the stringed fields
func (c Conversion) String() string {
return c.From.String() + c.To.String()
}
// GetRate returns system rate if availabled
func (c Conversion) GetRate() (float64, error) {
c.mtx.Lock()
defer c.mtx.Unlock()
if c.rate == nil {
return 0, errors.New("rate undefined")
}
return *c.rate, nil
}
// GetInversionRate returns the rate of the inversion of the conversion pair
func (c Conversion) GetInversionRate() (float64, error) {
if c.mtx == nil {
return 0, errors.New("mutex copy failure")
}
c.mtx.Lock()
defer c.mtx.Unlock()
if c.rate == nil {
return 0, errors.New("rate undefined")
}
return *c.inverseRate, nil
}
// Convert for example converts $1 USD to the equivalent Japanese Yen or vice
// versa.
func (c Conversion) Convert(fromAmount float64) (float64, error) {
if c.IsInvalid() {
return fromAmount, nil
}
if !c.IsFiat() {
return 0, errors.New("not fiat pair")
}
r, err := c.GetRate()
if err != nil {
return 0, err
}
return r * fromAmount, nil
}
// ConvertInverse converts backwards if needed
func (c Conversion) ConvertInverse(fromAmount float64) (float64, error) {
if c.IsInvalid() {
return fromAmount, nil
}
if !c.IsFiat() {
return 0, errors.New("not fiat pair")
}
r, err := c.GetInversionRate()
if err != nil {
return 0, err
}
return r * fromAmount, nil
}

177
currency/conversion_test.go Normal file
View File

@@ -0,0 +1,177 @@
package currency
import (
"testing"
"github.com/thrasher-/gocryptotrader/common"
)
func TestNewConversionFromString(t *testing.T) {
expected := "AUDUSD"
conv, err := NewConversionFromString(expected)
if err != nil {
t.Error("Test Failed - NewConversionFromString() error", err)
}
if conv.String() != expected {
t.Errorf("Test Failed - NewConversion() error expected %s but received %s",
expected,
conv)
}
newexpected := common.StringToLower(expected)
conv, err = NewConversionFromString(newexpected)
if err != nil {
t.Error("Test Failed - NewConversionFromString() error", err)
}
if conv.String() != newexpected {
t.Errorf("Test Failed - NewConversion() error expected %s but received %s",
newexpected,
conv)
}
}
func TestNewConversionFromStrings(t *testing.T) {
from := "AUD"
to := "USD"
expected := "AUDUSD"
conv, err := NewConversionFromStrings(from, to)
if err != nil {
t.Error("Test Failed - NewConversionFromString() error", err)
}
if conv.String() != expected {
t.Errorf("Test Failed - NewConversion() error expected %s but received %s",
expected,
conv)
}
}
func TestNewConversion(t *testing.T) {
from := NewCode("AUD")
to := NewCode("USD")
expected := "AUDUSD"
conv, err := NewConversion(from, to)
if err != nil {
t.Error("Test Failed - NewConversionFromCode() error", err)
}
if conv.String() != expected {
t.Errorf("Test Failed - NewConversion() error expected %s but received %s",
expected,
conv)
}
}
func TestConversionIsInvalid(t *testing.T) {
from := AUD
to := USD
conv, err := NewConversion(from, to)
if err != nil {
t.Fatal("Test Failed - NewConversion() error", err)
}
if conv.IsInvalid() {
t.Errorf("Test Failed - IsInvalid() error expected false but received %v",
conv.IsInvalid())
}
to = AUD
conv, err = NewConversion(from, to)
if err == nil {
t.Fatal("Test Failed - NewConversion() error", err)
}
}
func TestConversionIsFiatPair(t *testing.T) {
from := AUD
to := USD
conv, err := NewConversion(from, to)
if err != nil {
t.Fatal("Test Failed - NewConversion() error", err)
}
if !conv.IsFiat() {
t.Errorf("Test Failed - IsFiatPair() error expected true but received %v",
conv.IsFiat())
}
to = LTC
conv, err = NewConversion(from, to)
if err == nil {
t.Fatal("Test Failed - NewConversion() error", err)
}
}
func TestConversionsRatesSystem(t *testing.T) {
var SuperDuperConversionSystem ConversionRates
if SuperDuperConversionSystem.HasData() {
t.Fatalf("Test Failed - HasData() error expected false but recieved %v",
SuperDuperConversionSystem.HasData())
}
testmap := map[string]float64{
"USDAUD": 1.3969317581,
"USDBRL": 3.7047257979,
"USDCAD": 1.3186386881,
"USDCHF": 1,
"USDCNY": 6.7222712044,
"USDCZK": 22.6406277552,
"USDDKK": 6.5785575736,
"USDEUR": 0.8816787163,
"USDGBP": 0.7665755599,
"USDHKD": 7.8492329395,
"USDILS": 3.6152354082,
"USDINR": 71.154558279,
"USDJPY": 110.7476635514,
"USDKRW": 1122.7913948157,
"USDMXN": 19.1589666725,
"USDNOK": 8.5818197849,
"USDNZD": 1.4559160642,
"USDPLN": 3.8304531829,
"USDRUB": 65.7533062952,
"USDSEK": 9.3196085346,
"USDSGD": 1.3512608006,
"USDTHB": 31.0950449656,
"USDZAR": 14.138070887,
}
err := SuperDuperConversionSystem.Update(testmap)
if err != nil {
t.Fatal("Test Failed - Update() error", err)
}
err = SuperDuperConversionSystem.Update(nil)
if err == nil {
t.Fatal("Test Failed - Update() error cannnot be nil")
}
if !SuperDuperConversionSystem.HasData() {
t.Fatalf("Test Failed - HasData() error expected true but recieved %v",
SuperDuperConversionSystem.HasData())
}
// * to a rate
p := SuperDuperConversionSystem.m[USD.Item][AUD.Item]
// inverse * to a rate
pi := SuperDuperConversionSystem.m[AUD.Item][USD.Item]
r := *p * 1000
expectedRate := 1396.9317581
if r != expectedRate {
t.Errorf("Test Failed - Convert() error expected %.13f but recieved %.13f",
expectedRate,
r)
}
inverseR := *pi * expectedRate
expectedInverseRate := float64(1000)
if inverseR != expectedInverseRate {
t.Errorf("Test Failed - Convert() error expected %.13f but recieved %.13f",
expectedInverseRate,
inverseR)
}
}

95
currency/currencies.go Normal file
View File

@@ -0,0 +1,95 @@
package currency
import "github.com/thrasher-/gocryptotrader/common"
// NewCurrenciesFromStringArray returns a Currencies object from strings
func NewCurrenciesFromStringArray(currencies []string) Currencies {
var list Currencies
for i := range currencies {
if currencies[i] == "" {
continue
}
list = append(list, NewCode(currencies[i]))
}
return list
}
// Currencies define a range of supported currency codes
type Currencies []Code
// Strings returns an array of currency strings
func (c Currencies) Strings() []string {
var list []string
for _, d := range c {
list = append(list, d.String())
}
return list
}
// Contains checks to see if a currency code is contained in the currency list
func (c Currencies) Contains(cc Code) bool {
for i := range c {
if c[i].Item == cc.Item {
return true
}
}
return false
}
// Join returns a comma serparated string
func (c Currencies) Join() string {
return common.JoinStrings(c.Strings(), ",")
}
// UnmarshalJSON comforms type to the umarshaler interface
func (c *Currencies) UnmarshalJSON(d []byte) error {
var configCurrencies string
err := common.JSONDecode(d, &configCurrencies)
if err != nil {
return err
}
var allTheCurrencies Currencies
for _, data := range common.SplitStrings(configCurrencies, ",") {
allTheCurrencies = append(allTheCurrencies, NewCode(data))
}
*c = allTheCurrencies
return nil
}
// MarshalJSON conforms type to the marshaler interface
func (c Currencies) MarshalJSON() ([]byte, error) {
return common.JSONEncode(c.Join())
}
// Match returns if the full list equals the supplied list
func (c Currencies) Match(other Currencies) bool {
if len(c) != len(other) {
return false
}
for _, d := range c {
var found bool
for i := range other {
if d == other[i] {
found = true
break
}
}
if !found {
return false
}
}
return true
}
// Slice exposes the underlying type
func (c Currencies) Slice() []Code {
return c
}
// HasData checks to see if Currencies type has actual currencies
func (c Currencies) HasData() bool {
return len(c) != 0
}

View File

@@ -0,0 +1,50 @@
package currency
import (
"testing"
"github.com/thrasher-/gocryptotrader/common"
)
func TestCurrenciesUnmarshalJSON(t *testing.T) {
var unmarshalHere Currencies
expected := "btc,usd,ltc,bro,things"
encoded, err := common.JSONEncode(expected)
if err != nil {
t.Fatal("Test Failed - Currencies UnmarshalJSON() error", err)
}
err = common.JSONDecode(encoded, &unmarshalHere)
if err != nil {
t.Fatal("Test Failed - Currencies UnmarshalJSON() error", err)
}
err = common.JSONDecode(encoded, &unmarshalHere)
if err != nil {
t.Fatal("Test Failed - Currencies UnmarshalJSON() error", err)
}
if unmarshalHere.Join() != expected {
t.Errorf("Test Failed - Currencies UnmarshalJSON() error expected %s but received %s",
expected, unmarshalHere.Join())
}
}
func TestCurrenciesMarshalJSON(t *testing.T) {
quickStruct := struct {
C Currencies `json:"amazingCurrencies"`
}{
C: NewCurrenciesFromStringArray([]string{"btc", "usd", "ltc", "bro", "things"}),
}
encoded, err := common.JSONEncode(quickStruct)
if err != nil {
t.Fatal("Test Failed - Currencies MarshalJSON() error", err)
}
expected := `{"amazingCurrencies":"btc,usd,ltc,bro,things"}`
if string(encoded) != expected {
t.Errorf("Test Failed - Currencies MarshalJSON() error expected %s but received %s",
expected, string(encoded))
}
}

View File

@@ -1,320 +1,119 @@
package currency
import (
"errors"
"fmt"
"time"
// GetDefaultExchangeRates returns the currency exchange rates based off the
// default fiat values
func GetDefaultExchangeRates() (Conversions, error) {
return storage.GetDefaultForeignExchangeRates()
}
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/coinmarketcap"
"github.com/thrasher-/gocryptotrader/currency/forexprovider"
"github.com/thrasher-/gocryptotrader/currency/pair"
log "github.com/thrasher-/gocryptotrader/logger"
)
// GetExchangeRates returns the full fiat currency exchange rates base off
// configuration parameters supplied to the currency storage
func GetExchangeRates() (Conversions, error) {
return storage.GetExchangeRates()
}
const (
// DefaultBaseCurrency is the base currency used for conversion
DefaultBaseCurrency = "USD"
// DefaultCurrencies has the default minimum of FIAT values
DefaultCurrencies = "USD,AUD,EUR,CNY"
// DefaultCryptoCurrencies has the default minimum of crytpocurrency values
DefaultCryptoCurrencies = "BTC,LTC,ETH,DOGE,DASH,XRP,XMR"
)
// UpdateBaseCurrency updates storage base currency
func UpdateBaseCurrency(c Code) error {
return storage.UpdateBaseCurrency(c)
}
// Manager is the overarching type across this package
var (
FXRates map[string]float64
// GetBaseCurrency returns the storage base currency
func GetBaseCurrency() Code {
return storage.GetBaseCurrency()
}
FiatCurrencies []string
CryptoCurrencies []string
// GetDefaultBaseCurrency returns storage default base currency
func GetDefaultBaseCurrency() Code {
return storage.GetDefaultBaseCurrency()
}
BaseCurrency string
FXProviders *forexprovider.ForexProviders
// GetCryptocurrencies returns the storage enabled cryptocurrencies
func GetCryptocurrencies() Currencies {
return storage.GetCryptocurrencies()
}
CryptocurrencyProvider *coinmarketcap.Coinmarketcap
TotalCryptocurrencies []Data
TotalExchanges []Data
)
// GetDefaultCryptocurrencies returns a list of default cryptocurrencies
func GetDefaultCryptocurrencies() Currencies {
return storage.GetDefaultCryptocurrencies()
}
// SetDefaults sets the default currency provider and settings for
// currency conversion used outside of the bot setting
func SetDefaults() {
FXRates = make(map[string]float64)
BaseCurrency = DefaultBaseCurrency
// GetFiatCurrencies returns the storage enabled fiat currencies
func GetFiatCurrencies() Currencies {
return storage.GetFiatCurrencies()
}
FXProviders = forexprovider.NewDefaultFXProvider()
err := SeedCurrencyData(DefaultCurrencies)
if err != nil {
log.Errorf("Failed to seed currency data. Err: %s", err)
// GetDefaultFiatCurrencies returns a list of default fiat currencies
func GetDefaultFiatCurrencies() Currencies {
return storage.GetDefaultFiatCurrencies()
}
// UpdateCurrencies updates the local cryptocurrency or fiat currency store
func UpdateCurrencies(c Currencies, isCryptocurrency bool) {
if isCryptocurrency {
storage.UpdateEnabledCryptoCurrencies(c)
return
}
storage.UpdateEnabledFiatCurrencies(c)
}
// SeedCurrencyData returns rates correlated with suported currencies
func SeedCurrencyData(currencies string) error {
if FXRates == nil {
FXRates = make(map[string]float64)
}
if FXProviders == nil {
FXProviders = forexprovider.NewDefaultFXProvider()
}
newRates, err := FXProviders.GetCurrencyData(BaseCurrency, currencies)
if err != nil {
return err
}
for key, value := range newRates {
FXRates[key] = value
}
return nil
// ConvertCurrency converts an amount from one currency to another
func ConvertCurrency(amount float64, from, to Code) (float64, error) {
return storage.ConvertCurrency(amount, from, to)
}
// GetExchangeRates returns the currency exchange rates
func GetExchangeRates() map[string]float64 {
return FXRates
// SeedForeignExchangeData seeds FX data with the currencies supplied
func SeedForeignExchangeData(c Currencies) error {
return storage.SeedForeignExchangeRatesByCurrencies(c)
}
// IsDefaultCurrency checks if the currency passed in matches the default fiat
// currency
func IsDefaultCurrency(currency string) bool {
defaultCurrencies := common.SplitStrings(DefaultCurrencies, ",")
return common.StringDataCompare(defaultCurrencies, common.StringToUpper(currency))
// GetTotalMarketCryptocurrencies returns the full market cryptocurrencies
func GetTotalMarketCryptocurrencies() ([]Code, error) {
return storage.GetTotalMarketCryptocurrencies()
}
// IsDefaultCryptocurrency checks if the currency passed in matches the default
// cryptocurrency
func IsDefaultCryptocurrency(currency string) bool {
cryptoCurrencies := common.SplitStrings(DefaultCryptoCurrencies, ",")
return common.StringDataCompare(cryptoCurrencies, common.StringToUpper(currency))
// RunStorageUpdater runs a new foreign exchange updater instance
func RunStorageUpdater(o BotOverrides, m MainConfiguration, filepath string, v bool) error {
return storage.RunUpdater(o, m, filepath, v)
}
// IsFiatCurrency checks if the currency passed is an enabled fiat currency
func IsFiatCurrency(currency string) bool {
return common.StringDataCompare(FiatCurrencies, common.StringToUpper(currency))
}
// IsCryptocurrency checks if the currency passed is an enabled CRYPTO currency.
func IsCryptocurrency(currency string) bool {
return common.StringDataCompare(CryptoCurrencies, common.StringToUpper(currency))
}
// IsCryptoPair checks to see if the pair is a crypto pair e.g. BTCLTC
func IsCryptoPair(p pair.CurrencyPair) bool {
return IsCryptocurrency(p.FirstCurrency.String()) &&
IsCryptocurrency(p.SecondCurrency.String())
}
// IsCryptoFiatPair checks to see if the pair is a crypto fiat pair e.g. BTCUSD
func IsCryptoFiatPair(p pair.CurrencyPair) bool {
return IsCryptocurrency(p.FirstCurrency.String()) && !IsCryptocurrency(p.SecondCurrency.String()) ||
!IsCryptocurrency(p.FirstCurrency.String()) && IsCryptocurrency(p.SecondCurrency.String())
}
// IsFiatPair checks to see if the pair is a fiat pair e.g. EURUSD
func IsFiatPair(p pair.CurrencyPair) bool {
return IsFiatCurrency(p.FirstCurrency.String()) &&
IsFiatCurrency(p.SecondCurrency.String())
}
// Update updates the local crypto currency or base currency store
func Update(input []string, cryptos bool) {
for x := range input {
if cryptos {
if !common.StringDataCompare(CryptoCurrencies, input[x]) {
CryptoCurrencies = append(CryptoCurrencies, common.StringToUpper(input[x]))
// CopyPairFormat copies the pair format from a list of pairs once matched
func CopyPairFormat(p Pair, pairs []Pair, exact bool) Pair {
for x := range pairs {
if exact {
if p.Equal(pairs[x]) {
return pairs[x]
}
}
if p.EqualIncludeReciprocal(pairs[x]) {
return pairs[x]
}
}
return Pair{Base: NewCode(""), Quote: NewCode("")}
}
// 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) {
var result Pairs
for x := range pairs {
if pairs[x] == "" {
continue
}
var p Pair
if delimiter != "" {
p = NewPairDelimiter(pairs[x], delimiter)
} else {
if !common.StringDataCompare(FiatCurrencies, input[x]) {
FiatCurrencies = append(FiatCurrencies, common.StringToUpper(input[x]))
if index != "" {
var err error
p, err = NewPairFromIndex(pairs[x], index)
if err != nil {
return Pairs{}, err
}
} else {
p = NewPairFromStrings(pairs[x][0:3], pairs[x][3:])
}
}
result = append(result, p)
}
}
func extractBaseCurrency() string {
for k := range FXRates {
return k[0:3]
}
return ""
}
// ConvertCurrency for example converts $1 USD to the equivalent Japanese Yen
// or vice versa.
func ConvertCurrency(amount float64, from, to string) (float64, error) {
if FXProviders == nil {
SetDefaults()
}
from = common.StringToUpper(from)
to = common.StringToUpper(to)
if from == to {
return amount, nil
}
if from == "RUR" {
from = "RUB"
}
if to == "RUR" {
to = "RUB"
}
if len(FXRates) == 0 {
SeedCurrencyData(from + "," + to)
}
// Need to extract the base currency to see if we actually got it from the Forex API
// Fixer free API sets the base currency to EUR
baseCurr := extractBaseCurrency()
var resultFrom float64
var resultTo float64
// check to see if we're converting from the base currency
if to == baseCurr {
var ok bool
resultFrom, ok = FXRates[baseCurr+from]
if !ok {
return 0, fmt.Errorf("currency conversion failed. Unable to find %s in currency map [%s -> %s]", from, from, to)
}
return amount / resultFrom, nil
}
// Check to see if we're converting from the base currency
if from == baseCurr {
var ok bool
resultTo, ok = FXRates[baseCurr+to]
if !ok {
return 0, fmt.Errorf("currency conversion failed. Unable to find %s in currency map [%s -> %s]", to, from, to)
}
return resultTo * amount, nil
}
// Otherwise convert to base currency, then to the target currency
resultFrom, ok := FXRates[baseCurr+from]
if !ok {
return 0, fmt.Errorf("currency conversion failed. Unable to find %s in currency map [%s -> %s]", from, from, to)
}
converted := amount / resultFrom
resultTo, ok = FXRates[baseCurr+to]
if !ok {
return 0, fmt.Errorf("currency conversion failed. Unable to find %s in currency map [%s -> %s]", to, from, to)
}
return converted * resultTo, nil
}
// Data defines information pertaining to exchange or a cryptocurrency from
// coinmarketcap
type Data struct {
ID int
Name string
Symbol string `json:",omitempty"`
Slug string
Active bool
LastUpdated time.Time
}
// SeedCryptocurrencyMarketData seeds cryptocurrency market data
func SeedCryptocurrencyMarketData(settings coinmarketcap.Settings) error {
if !settings.Enabled {
return errors.New("not enabled please set in config.json with apikey and account levels")
}
if CryptocurrencyProvider == nil {
err := setupCryptoProvider(settings)
if err != nil {
return err
}
}
cryptoData, err := CryptocurrencyProvider.GetCryptocurrencyIDMap()
if err != nil {
return err
}
for x := range cryptoData {
var active bool
if cryptoData[x].IsActive == 1 {
active = true
}
TotalCryptocurrencies = append(TotalCryptocurrencies, Data{
ID: cryptoData[x].ID,
Name: cryptoData[x].Name,
Symbol: cryptoData[x].Symbol,
Slug: cryptoData[x].Slug,
Active: active,
LastUpdated: time.Now(),
})
}
return nil
}
// SeedExchangeMarketData seeds exchange market data
func SeedExchangeMarketData(settings coinmarketcap.Settings) error {
if !settings.Enabled {
return errors.New("not enabled please set in config.json with apikey and account levels")
}
if CryptocurrencyProvider == nil {
err := setupCryptoProvider(settings)
if err != nil {
return err
}
}
exchangeData, err := CryptocurrencyProvider.GetExchangeMap(0, 0)
if err != nil {
return err
}
for _, data := range exchangeData {
var active bool
if data.IsActive == 1 {
active = true
}
TotalExchanges = append(TotalExchanges, Data{
ID: data.ID,
Name: data.Name,
Slug: data.Slug,
Active: active,
LastUpdated: time.Now(),
})
}
return nil
}
func setupCryptoProvider(settings coinmarketcap.Settings) error {
if settings.APIkey == "" ||
settings.APIkey == "key" ||
settings.AccountPlan == "" ||
settings.AccountPlan == "accountPlan" {
return errors.New("currencyprovider error api key or plan not set in config.json")
}
CryptocurrencyProvider = new(coinmarketcap.Coinmarketcap)
CryptocurrencyProvider.SetDefaults()
CryptocurrencyProvider.Setup(settings)
return nil
}
// GetTotalMarketCryptocurrencies returns the total seeded market
// cryptocurrencies
func GetTotalMarketCryptocurrencies() []Data {
return TotalCryptocurrencies
}
// GetTotalMarketExchanges returns the total seeded market exchanges
func GetTotalMarketExchanges() []Data {
return TotalExchanges
return result, nil
}

View File

@@ -2,259 +2,125 @@ package currency
import (
"testing"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
)
func TestSetDefaults(t *testing.T) {
FXRates = nil
BaseCurrency = "BLAH"
FXProviders = nil
SetDefaults()
if FXRates == nil {
t.Fatal("Expected FXRates to be non-nil")
}
if BaseCurrency != DefaultBaseCurrency {
t.Fatal("Expected BaseCurrency to be 'USD'")
}
if FXProviders == nil {
t.Fatal("Expected FXRates to be non-nil")
}
}
func TestSeedCurrencyData(t *testing.T) {
err := SeedCurrencyData("AUD")
func TestGetDefaultExchangeRates(t *testing.T) {
rates, err := GetDefaultExchangeRates()
if err != nil {
t.Fatal(err)
t.Error("Test failed - GetDefaultExchangeRates() err", err)
}
for _, val := range rates {
if !val.IsFiat() {
t.Errorf("Test failed - GetDefaultExchangeRates() %s is not fiat pair",
val)
}
}
}
func TestGetExchangeRates(t *testing.T) {
result := make(map[string]float64)
for k, v := range GetExchangeRates() {
result[k] = v
}
backup := FXRates
FXRates = nil
result = GetExchangeRates()
if result != nil {
t.Fatal("Expected nil map")
rates, err := GetExchangeRates()
if err != nil {
t.Error("Test failed - GetExchangeRates() err", err)
}
FXRates = backup
}
func TestIsDefaultCurrency(t *testing.T) {
t.Parallel()
var str1, str2, str3 string = "USD", "usd", "cats123"
if !IsDefaultCurrency(str1) {
t.Errorf(
"Test Failed. TestIsDefaultCurrency: \nCannot match currency, %s.", str1,
)
}
if !IsDefaultCurrency(str2) {
t.Errorf(
"Test Failed. TestIsDefaultCurrency: \nCannot match currency, %s.", str2,
)
}
if IsDefaultCurrency(str3) {
t.Errorf(
"Test Failed. TestIsDefaultCurrency: \nFunction return is incorrect with, %s.",
str3,
)
for _, val := range rates {
if !val.IsFiat() {
t.Errorf("Test failed - GetExchangeRates() %s is not fiat pair",
val)
}
}
}
func TestIsDefaultCryptocurrency(t *testing.T) {
t.Parallel()
var str1, str2, str3 string = symbol.BTC, symbol.BTC, "dogs123"
if !IsDefaultCryptocurrency(str1) {
t.Errorf(
"Test Failed. TestIsDefaultCryptocurrency: \nCannot match currency, %s.",
str1,
)
func TestUpdateBaseCurrency(t *testing.T) {
err := UpdateBaseCurrency(AUD)
if err != nil {
t.Error("Test failed - UpdateBaseCurrency() err", err)
}
if !IsDefaultCryptocurrency(str2) {
t.Errorf(
"Test Failed. TestIsDefaultCryptocurrency: \nCannot match currency, %s.",
str2,
)
err = UpdateBaseCurrency(LTC)
if err == nil {
t.Error("Test failed - UpdateBaseCurrency() cannot be nil")
}
if IsDefaultCryptocurrency(str3) {
t.Errorf(
"Test Failed. TestIsDefaultCryptocurrency: \nFunction return is incorrect with, %s.",
str3,
)
if GetBaseCurrency() != AUD {
t.Errorf("Test failed - GetBaseCurrency() expected %s but recieved %s",
AUD, GetBaseCurrency())
}
}
func TestIsFiatCurrency(t *testing.T) {
if IsFiatCurrency("") {
t.Error("Test failed. TestIsFiatCurrency returned true on an empty string")
}
FiatCurrencies = []string{"USD", "AUD"}
var str1, str2, str3 string = symbol.BTC, "USD", "birds123"
if IsFiatCurrency(str1) {
t.Errorf(
"Test Failed. TestIsFiatCurrency: \nCannot match currency, %s.", str1,
)
}
if !IsFiatCurrency(str2) {
t.Errorf(
"Test Failed. TestIsFiatCurrency: \nCannot match currency, %s.", str2,
)
}
if IsFiatCurrency(str3) {
t.Errorf(
"Test Failed. TestIsFiatCurrency: \nCannot match currency, %s.", str3,
)
func TestGetDefaultBaseCurrency(t *testing.T) {
if GetDefaultBaseCurrency() != USD {
t.Errorf("Test failed - GetDefaultBaseCurrency() expected %s but recieved %s",
USD, GetDefaultBaseCurrency())
}
}
func TestIsCryptocurrency(t *testing.T) {
if IsCryptocurrency("") {
t.Error("Test failed. TestIsCryptocurrency returned true on an empty string")
}
CryptoCurrencies = []string{symbol.BTC, symbol.LTC, symbol.DASH}
var str1, str2, str3 string = "USD", symbol.BTC, "pterodactyl123"
if IsCryptocurrency(str1) {
t.Errorf(
"Test Failed. TestIsFiatCurrency: \nCannot match currency, %s.", str1,
)
}
if !IsCryptocurrency(str2) {
t.Errorf(
"Test Failed. TestIsFiatCurrency: \nCannot match currency, %s.", str2,
)
}
if IsCryptocurrency(str3) {
t.Errorf(
"Test Failed. TestIsFiatCurrency: \nCannot match currency, %s.", str3,
)
func TestGetDefaulCryptoCurrencies(t *testing.T) {
expected := Currencies{BTC, LTC, ETH, DOGE, DASH, XRP, XMR}
if !GetDefaultCryptocurrencies().Match(expected) {
t.Errorf("Test failed - GetDefaultCryptocurrencies() expected %s but recieved %s",
expected, GetDefaultCryptocurrencies())
}
}
func TestIsCryptoPair(t *testing.T) {
if IsCryptocurrency("") {
t.Error("Test failed. TestIsCryptocurrency returned true on an empty string")
}
CryptoCurrencies = []string{symbol.BTC, symbol.LTC, symbol.DASH}
FiatCurrencies = []string{"USD"}
if !IsCryptoPair(pair.NewCurrencyPair(symbol.BTC, symbol.LTC)) {
t.Error("Test Failed. TestIsCryptoPair. Expected true result")
}
if IsCryptoPair(pair.NewCurrencyPair(symbol.BTC, "USD")) {
t.Error("Test Failed. TestIsCryptoPair. Expected false result")
func TestGetDefaultFiatCurrencies(t *testing.T) {
expected := Currencies{USD, AUD, EUR, CNY}
if !GetDefaultFiatCurrencies().Match(expected) {
t.Errorf("Test failed - GetDefaultFiatCurrencies() expected %s but recieved %s",
expected, GetDefaultFiatCurrencies())
}
}
func TestIsCryptoFiatPair(t *testing.T) {
if IsCryptocurrency("") {
t.Error("Test failed. TestIsCryptocurrency returned true on an empty string")
func TestUpdateCurrencies(t *testing.T) {
fiat := Currencies{HKN, JPY}
UpdateCurrencies(fiat, false)
rFiat := GetFiatCurrencies()
if !rFiat.Contains(HKN) || !rFiat.Contains(JPY) {
t.Error("Test failed - UpdateCurrencies() currencies did not update")
}
CryptoCurrencies = []string{symbol.BTC, symbol.LTC, symbol.DASH}
FiatCurrencies = []string{"USD"}
if !IsCryptoFiatPair(pair.NewCurrencyPair(symbol.BTC, "USD")) {
t.Error("Test Failed. TestIsCryptoPair. Expected true result")
}
if IsCryptoFiatPair(pair.NewCurrencyPair(symbol.BTC, symbol.LTC)) {
t.Error("Test Failed. TestIsCryptoPair. Expected false result")
crypto := Currencies{ZAR, ZCAD, B2}
UpdateCurrencies(crypto, true)
rCrypto := GetCryptocurrencies()
if !rCrypto.Contains(ZAR) || !rCrypto.Contains(ZCAD) || !rCrypto.Contains(B2) {
t.Error("Test failed - UpdateCurrencies() currencies did not update")
}
}
func TestIsFiatPair(t *testing.T) {
CryptoCurrencies = []string{symbol.BTC, symbol.LTC, symbol.DASH}
FiatCurrencies = []string{"USD", "AUD", "EUR"}
if !IsFiatPair(pair.NewCurrencyPair("AUD", "USD")) {
t.Error("Test Failed. TestIsFiatPair. Expected true result")
}
if IsFiatPair(pair.NewCurrencyPair(symbol.BTC, "AUD")) {
t.Error("Test Failed. TestIsFiatPair. Expected false result")
}
}
func TestUpdate(t *testing.T) {
CryptoCurrencies = []string{symbol.BTC, symbol.LTC, symbol.DASH}
FiatCurrencies = []string{"USD", "AUD"}
Update([]string{"ETH"}, true)
Update([]string{"JPY"}, false)
if !IsCryptocurrency("ETH") {
t.Error(
"Test Failed. TestUpdate: \nCannot match currency: ETH",
)
}
if !IsFiatCurrency("JPY") {
t.Errorf(
"Test Failed. TestUpdate: \nCannot match currency: JPY",
)
}
}
func TestExtractBaseCurrency(t *testing.T) {
backup := FXRates
FXRates = nil
FXRates = make(map[string]float64)
if extractBaseCurrency() != "" {
t.Fatalf("Test failed. Expected '' as base currency")
}
FXRates["USDAUD"] = 120
if extractBaseCurrency() != "USD" {
t.Fatalf("Test failed. Expected 'USD' as base currency")
}
FXRates = backup
}
func TestConvertCurrency(t *testing.T) {
_, err := ConvertCurrency(100, "AUD", "USD")
_, err := ConvertCurrency(100, AUD, USD)
if err != nil {
t.Fatal(err)
}
_, err = ConvertCurrency(100, "USD", "AUD")
r, err := ConvertCurrency(100, AUD, AUD)
if err != nil {
t.Fatal(err)
}
_, err = ConvertCurrency(100, "CNY", "AUD")
if r != 100 {
t.Errorf("Test Failed - ConvertCurrency error, incorrect rate return %2.f but received %2.f",
100.00, r)
}
_, err = ConvertCurrency(100, USD, AUD)
if err != nil {
t.Fatal(err)
}
_, err = ConvertCurrency(100, "meow", "USD")
_, err = ConvertCurrency(100, CNY, AUD)
if err != nil {
t.Fatal(err)
}
_, err = ConvertCurrency(100, LTC, USD)
if err == nil {
t.Fatal("Expected err on non-existent currency")
}
_, err = ConvertCurrency(100, "USD", "meow")
_, err = ConvertCurrency(100, USD, LTC)
if err == nil {
t.Fatal("Expected err on non-existent currency")
}
}

View File

@@ -0,0 +1,62 @@
package currency
import (
"time"
"github.com/thrasher-/gocryptotrader/currency/coinmarketcap"
)
// MainConfiguration is the main configuration from the config.json file
type MainConfiguration struct {
ForexProviders []FXSettings
CryptocurrencyProvider coinmarketcap.Settings
Cryptocurrencies Currencies
CurrencyPairFormat interface{}
FiatDisplayCurrency Code
CurrencyDelay time.Duration
FxRateDelay time.Duration
}
// BotOverrides defines a bot overriding factor for quick running currency
// subsystems
type BotOverrides struct {
Coinmarketcap bool
FxCurrencyConverter bool
FxCurrencyLayer bool
FxFixer bool
FxOpenExchangeRates bool
}
// CoinmarketcapSettings refers to settings
type CoinmarketcapSettings coinmarketcap.Settings
// SystemsSettings defines incoming system settings
type SystemsSettings struct {
Coinmarketcap coinmarketcap.Settings
Currencyconverter FXSettings
Currencylayer FXSettings
Fixer FXSettings
Openexchangerates FXSettings
}
// FXSettings defines foreign exchange requester settings
type FXSettings struct {
Name string `json:"name"`
Enabled bool `json:"enabled"`
Verbose bool `json:"verbose"`
RESTPollingDelay time.Duration `json:"restPollingDelay"`
APIKey string `json:"apiKey"`
APIKeyLvl int `json:"apiKeyLvl"`
PrimaryProvider bool `json:"primaryProvider"`
}
// File defines a full currency file generated by the currency storage
// analysis system
type File struct {
LastMainUpdate time.Time `json:"lastMainUpdate"`
Cryptocurrency []Item `json:"cryptocurrencies"`
FiatCurrency []Item `json:"fiatCurrencies"`
UnsetCurrency []Item `json:"unsetCurrencies"`
Contracts []Item `json:"contracts"`
Token []Item `json:"tokens"`
}

View File

@@ -4,6 +4,9 @@ import (
"time"
)
// DefaultTimeOut is the default timeout for foreign exchange providers
const DefaultTimeOut = time.Second * 15
// Settings enforces standard variables across the provider packages
type Settings struct {
Name string `json:"name"`

View File

@@ -3,44 +3,153 @@ package base
import (
"errors"
"fmt"
"sync"
log "github.com/thrasher-/gocryptotrader/logger"
"github.com/thrasher-/gocryptotrader/common"
)
// IFXProviders contains an array of foreign exchange interfaces
type IFXProviders []IFXProvider
// IFXProvider enforces standard functions for all foreign exchange providers
// supported in GoCryptoTrader
type IFXProvider interface {
Setup(config Settings)
Setup(config Settings) error
GetRates(baseCurrency, symbols string) (map[string]float64, error)
GetName() string
IsEnabled() bool
IsPrimaryProvider() bool
GetSupportedCurrencies() ([]string, error)
}
// FXHandler defines a full suite of FX data providers with failure backup with
// unsupported currency shunt procedure
type FXHandler struct {
Primary Provider
Support []Provider
mtx sync.Mutex
}
// Provider defines a singular foreign exchange provider with its supported
// currencies to cross reference request currencies and if not supported shunt
// request traffic to and from other providers so that we can maintain full
// currency list integration
type Provider struct {
Provider IFXProvider
SupportedCurrencies []string
}
// GetNewRate access rates by predetermined logic based on how a provider
// handles requests
func (p *Provider) GetNewRate(base string, currencies []string) (map[string]float64, error) {
if !p.Provider.IsEnabled() {
return nil, fmt.Errorf("provider %s is not enabled",
p.Provider.GetName())
}
switch p.Provider.GetName() {
case "ExchangeRates":
return p.Provider.GetRates(base, "") // Zero value to get all rates
default:
return p.Provider.GetRates(base, common.JoinStrings(currencies, ","))
}
}
// CheckCurrencies cross references supplied currencies with exchange supported
// currencies, if there are any currencies not supported it returns a list
// to pass on to the next provider
func (p Provider) CheckCurrencies(currencies []string) []string {
var spillOver []string
for _, c := range currencies {
if !common.StringDataCompareUpper(p.SupportedCurrencies, c) {
spillOver = append(spillOver, c)
}
}
return spillOver
}
// GetCurrencyData returns currency data from enabled FX providers
func (fxp IFXProviders) GetCurrencyData(baseCurrency, symbols string) (map[string]float64, error) {
for x := range fxp {
if fxp[x].IsPrimaryProvider() && fxp[x].IsEnabled() {
rates, err := fxp[x].GetRates(baseCurrency, symbols)
if err != nil {
log.Error(err)
for y := range fxp {
if !fxp[y].IsPrimaryProvider() && fxp[x].IsEnabled() {
rates, err = fxp[y].GetRates(baseCurrency, symbols)
if err != nil {
log.Error(err)
continue
}
return rates, nil
}
}
return nil, fmt.Errorf("forex provider %s unable to acquire rates data", fxp[x].GetName())
}
return rates, nil
}
func (f *FXHandler) GetCurrencyData(baseCurrency string, currencies []string) (map[string]float64, error) {
var fullRange = currencies
if !common.StringDataCompareUpper(currencies, baseCurrency) {
fullRange = append(fullRange, baseCurrency)
}
return nil, errors.New("no forex providers enabled")
f.mtx.Lock()
defer f.mtx.Unlock()
if f.Primary.Provider == nil {
return nil, errors.New("primary foreign exchange provider details not set")
}
shunt := f.Primary.CheckCurrencies(fullRange)
rates, err := f.Primary.GetNewRate(baseCurrency, currencies)
if err != nil {
return f.backupGetRate(baseCurrency, currencies)
}
if len(shunt) != 0 {
rateNew, err := f.backupGetRate(baseCurrency, shunt)
if err != nil {
return nil, fmt.Errorf("failed to update rate map for currencies %v %v",
shunt,
err)
}
for key, val := range rateNew {
rates[key] = val
}
return rates, nil
}
return rates, nil
}
// backupGetRate uses the currencies that are supported and falls through, and
// errors when unsupported currency found
func (f *FXHandler) backupGetRate(base string, currencies []string) (map[string]float64, error) {
if f.Support == nil {
return nil, errors.New("no supporting foreign exchange providers set")
}
var shunt []string
rate := make(map[string]float64)
for i := range f.Support {
if len(shunt) != 0 {
shunt = f.Support[i].CheckCurrencies(shunt)
newRate, err := f.Support[i].GetNewRate(base, shunt)
if err != nil {
continue
}
for k, v := range newRate {
rate[k] = v
}
if len(shunt) != 0 {
continue
}
return rate, nil
}
shunt = f.Support[i].CheckCurrencies(currencies)
newRate, err := f.Support[i].GetNewRate(base, currencies)
if err != nil {
continue
}
for k, v := range newRate {
rate[k] = v
}
if len(shunt) != 0 {
continue
}
return rate, nil
}
return nil, fmt.Errorf("currencies %s not supported", shunt)
}

View File

@@ -1 +0,0 @@
package base

View File

@@ -3,10 +3,13 @@ package currencyconverter
import (
"errors"
"fmt"
"net/http"
"net/url"
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/forexprovider/base"
"github.com/thrasher-/gocryptotrader/exchanges/request"
log "github.com/thrasher-/gocryptotrader/logger"
)
@@ -22,15 +25,19 @@ const (
APIEndpointUsage = "usage"
defaultAPIKey = "Key"
authRate = 0
unAuthRate = 0
)
// CurrencyConverter stores the struct for the CurrencyConverter API
type CurrencyConverter struct {
base.Base
Requester *request.Requester
}
// Setup sets appropriate values for CurrencyLayer
func (c *CurrencyConverter) Setup(config base.Settings) {
func (c *CurrencyConverter) Setup(config base.Settings) error {
c.Name = config.Name
c.APIKey = config.APIKey
c.APIKeyLvl = config.APIKeyLvl
@@ -38,6 +45,11 @@ func (c *CurrencyConverter) Setup(config base.Settings) {
c.RESTPollingDelay = config.RESTPollingDelay
c.Verbose = config.Verbose
c.PrimaryProvider = config.PrimaryProvider
c.Requester = request.New(c.Name,
request.NewRateLimit(time.Second*10, authRate),
request.NewRateLimit(time.Second*10, unAuthRate),
common.NewHTTPClientWithTimeout(base.DefaultTimeOut))
return nil
}
// GetRates is a wrapper function to return rates
@@ -128,8 +140,8 @@ func (c *CurrencyConverter) Convert(from, to string) (map[string]float64, error)
return result, nil
}
// GetCurrencies returns a list of the supported currencies
func (c *CurrencyConverter) GetCurrencies() (map[string]CurrencyItem, error) {
// GetSupportedCurrencies returns a list of the supported currencies
func (c *CurrencyConverter) GetSupportedCurrencies() ([]string, error) {
var result Currencies
err := c.SendHTTPRequest(APIEndpointCurrencies, url.Values{}, &result)
@@ -137,7 +149,12 @@ func (c *CurrencyConverter) GetCurrencies() (map[string]CurrencyItem, error) {
return nil, err
}
return result.Results, nil
var currencies []string
for key := range result.Results {
currencies = append(currencies, key)
}
return currencies, nil
}
// GetCountries returns a list of the supported countries and
@@ -157,16 +174,23 @@ func (c *CurrencyConverter) GetCountries() (map[string]CountryItem, error) {
// upgrades request to SSL.
func (c *CurrencyConverter) SendHTTPRequest(endPoint string, values url.Values, result interface{}) error {
var path string
var auth bool
if c.APIKey == "" || c.APIKey == defaultAPIKey {
path = fmt.Sprintf("%s%s/%s?", APIEndpointFreeURL, APIEndpointVersion, endPoint)
auth = true
} else {
path = fmt.Sprintf("%s%s%s?", APIEndpointURL, APIEndpointVersion, endPoint)
values.Set("apiKey", c.APIKey)
}
path += values.Encode()
err := common.SendHTTPGetRequest(path, true, c.Verbose, &result)
err := c.Requester.SendPayload(http.MethodGet,
path,
nil,
nil,
&result,
auth,
c.Verbose)
if err != nil {
return fmt.Errorf("currency converter API SendHTTPRequest error %s with path %s",
err,

View File

@@ -80,12 +80,12 @@ func TestConvert(t *testing.T) {
}
}
func TestGetCurrencies(t *testing.T) {
func TestGetSupportedCurrencies(t *testing.T) {
if !IsAPIKeysSet() {
t.Skip()
}
_, err := c.GetCurrencies()
_, err := c.GetSupportedCurrencies()
if err != nil {
t.Fatal(err)
}

View File

@@ -14,11 +14,15 @@ package currencylayer
import (
"errors"
"fmt"
"net/http"
"net/url"
"strconv"
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/forexprovider/base"
"github.com/thrasher-/gocryptotrader/exchanges/request"
log "github.com/thrasher-/gocryptotrader/logger"
)
// const declarations consist of endpoints and APIKey privileges
@@ -36,6 +40,9 @@ const (
APIEndpointConversion = "convert"
APIEndpointTimeframe = "timeframe"
APIEndpointChange = "change"
authRate = 0
unAuthRate = 0
)
// CurrencyLayer is a foreign exchange rate provider at
@@ -43,10 +50,17 @@ const (
// account. Has automatic upgrade to a SSL connection.
type CurrencyLayer struct {
base.Base
Requester *request.Requester
}
// Setup sets appropriate values for CurrencyLayer
func (c *CurrencyLayer) Setup(config base.Settings) {
func (c *CurrencyLayer) Setup(config base.Settings) error {
if config.APIKeyLvl < 0 || config.APIKeyLvl > 3 {
log.Errorf("apikey incorrectly set in config.json for %s, please set appropriate account levels",
config.Name)
return errors.New("apikey set failure")
}
c.Name = config.Name
c.APIKey = config.APIKey
c.APIKeyLvl = config.APIKeyLvl
@@ -54,6 +68,12 @@ func (c *CurrencyLayer) Setup(config base.Settings) {
c.RESTPollingDelay = config.RESTPollingDelay
c.Verbose = config.Verbose
c.PrimaryProvider = config.PrimaryProvider
c.Requester = request.New(c.Name,
request.NewRateLimit(time.Second*10, authRate),
request.NewRateLimit(time.Second*10, unAuthRate),
common.NewHTTPClientWithTimeout(base.DefaultTimeOut))
return nil
}
// GetRates is a wrapper function to return rates for GoCryptoTrader
@@ -62,7 +82,7 @@ func (c *CurrencyLayer) GetRates(baseCurrency, symbols string) (map[string]float
}
// GetSupportedCurrencies returns supported currencies
func (c *CurrencyLayer) GetSupportedCurrencies() (map[string]string, error) {
func (c *CurrencyLayer) GetSupportedCurrencies() ([]string, error) {
var resp SupportedCurrencies
if err := c.SendHTTPRequest(APIEndpointList, url.Values{}, &resp); err != nil {
@@ -72,7 +92,13 @@ func (c *CurrencyLayer) GetSupportedCurrencies() (map[string]string, error) {
if !resp.Success {
return nil, errors.New(resp.Error.Info)
}
return resp.Currencies, nil
var currencies []string
for key := range resp.Currencies {
currencies = append(currencies, key)
}
return currencies, nil
}
// GetliveData returns live quotes for foreign exchange currencies
@@ -198,12 +224,20 @@ func (c *CurrencyLayer) SendHTTPRequest(endPoint string, values url.Values, resu
var path string
values.Set("access_key", c.APIKey)
var auth bool
if c.APIKeyLvl == AccountFree {
path = fmt.Sprintf("%s%s%s", APIEndpointURL, endPoint, "?")
} else {
auth = true
path = fmt.Sprintf("%s%s%s", APIEndpointURLSSL, endPoint, "?")
}
path += values.Encode()
return common.SendHTTPGetRequest(path, true, c.Verbose, result)
return c.Requester.SendPayload(http.MethodGet,
path,
nil,
nil,
&result,
auth,
c.Verbose)
}

View File

@@ -2,6 +2,8 @@ package currencylayer
import (
"testing"
"github.com/thrasher-/gocryptotrader/currency/forexprovider/base"
)
var c CurrencyLayer
@@ -10,54 +12,126 @@ var c CurrencyLayer
// minimize your API calls using this test.
const (
APIkey = ""
Apilevel = 3
Apilevel = 0
)
var isSet bool
func setup() error {
if !isSet {
defaultCfg := base.Settings{
Name: "CurrencyLayer",
Enabled: true,
}
if APIkey != "" {
defaultCfg.APIKey = APIkey
}
if Apilevel > -2 && Apilevel < 4 {
defaultCfg.APIKeyLvl = Apilevel
}
err := c.Setup(defaultCfg)
if err != nil {
return err
}
isSet = true
}
return nil
}
func areAPIKeysSet() bool {
return APIkey != "" && Apilevel != -1
}
func TestGetRates(t *testing.T) {
_, err := c.GetRates("USD", "AUD")
if err == nil {
err := setup()
if err != nil {
t.Skip("Test Failed - CurrencyLayer GetRates error", err)
}
_, err = c.GetRates("USD", "AUD")
if areAPIKeysSet() && err != nil {
t.Error("test error - currencylayer GetRates() error", err)
} else if !areAPIKeysSet() && err == nil {
t.Error("test error - currencylayer GetRates() error cannot be nil")
}
}
func TestGetSupportedCurrencies(t *testing.T) {
_, err := c.GetSupportedCurrencies()
if err == nil {
err := setup()
if err != nil {
t.Fatal("Test Failed - CurrencyLayer GetSupportedCurrencies error", err)
}
_, err = c.GetSupportedCurrencies()
if areAPIKeysSet() && err != nil {
t.Error("test error - currencylayer GetSupportedCurrencies() error", err)
} else if !areAPIKeysSet() && err == nil {
t.Error("test error - currencylayer GetSupportedCurrencies() error cannot be nil")
}
}
func TestGetliveData(t *testing.T) {
_, err := c.GetliveData("AUD", "USD")
if err == nil {
err := setup()
if err != nil {
t.Fatal("Test Failed - CurrencyLayer GetliveData error", err)
}
_, err = c.GetliveData("AUD", "USD")
if areAPIKeysSet() && err != nil {
t.Error("test error - currencylayer GetliveData() error", err)
} else if !areAPIKeysSet() && err == nil {
t.Error("test error - currencylayer GetliveData() error cannot be nil")
}
}
func TestGetHistoricalData(t *testing.T) {
_, err := c.GetHistoricalData("2016-12-15", []string{"AUD"}, "USD")
if err == nil {
err := setup()
if err != nil {
t.Fatal("Test Failed - CurrencyLayer GetHistoricalData error", err)
}
_, err = c.GetHistoricalData("2016-12-15", []string{"AUD"}, "USD")
if areAPIKeysSet() && err != nil {
t.Error("test error - currencylayer GetHistoricalData() error", err)
} else if !areAPIKeysSet() && err == nil {
t.Error("test error - currencylayer GetHistoricalData() error cannot be nil")
}
}
func TestConvert(t *testing.T) {
_, err := c.Convert("USD", "AUD", "", 1)
if err == nil {
t.Error("test error - currencylayer Convert() error")
err := setup()
if err != nil {
t.Fatal("Test Failed - CurrencyLayer Convert error", err)
}
_, err = c.Convert("USD", "AUD", "", 1)
if areAPIKeysSet() && err != nil && c.APIKeyLvl >= AccountBasic {
t.Error("test error - currencylayer Convert() error", err)
} else if !areAPIKeysSet() && err == nil {
t.Error("test error - currencylayer Convert() error cannot be nil")
}
}
func TestQueryTimeFrame(t *testing.T) {
_, err := c.QueryTimeFrame("2010-12-0", "2010-12-5", "USD", []string{"AUD"})
if err == nil {
t.Error("test error - currencylayer QueryTimeFrame() error")
err := setup()
if err != nil {
t.Fatal("Test Failed - CurrencyLayer QueryTimeFrame error", err)
}
_, err = c.QueryTimeFrame("2010-12-0", "2010-12-5", "USD", []string{"AUD"})
if areAPIKeysSet() && err != nil && c.APIKeyLvl >= AccountPro {
t.Error("test error - currencylayer QueryTimeFrame() error", err)
} else if !areAPIKeysSet() && err == nil {
t.Error("test error - currencylayer QueryTimeFrame() error cannot be nil")
}
}
func TestQueryCurrencyChange(t *testing.T) {
_, err := c.QueryCurrencyChange("2010-12-0", "2010-12-5", "USD", []string{"AUD"})
if err == nil {
t.Error("test error - currencylayer QueryCurrencyChange() error")
err := setup()
if err != nil {
t.Fatal("Test Failed - CurrencyLayer QueryCurrencyChange() error", err)
}
_, err = c.QueryCurrencyChange("2010-12-0", "2010-12-5", "USD", []string{"AUD"})
if areAPIKeysSet() && err != nil && c.APIKeyLvl == AccountEnterprise {
t.Error("test error - currencylayer QueryCurrencyChange() error", err)
} else if !areAPIKeysSet() && err == nil {
t.Error("test error - currencylayer QueryCurrencyChange() error cannot be nil")
}
}

View File

@@ -1,12 +1,15 @@
package currencylayer
// Error Defines the response error if an error occurred
type Error struct {
Code int `json:"code"`
Info string `json:"info"`
}
// LiveRates is a response type holding rates priced now.
type LiveRates struct {
Success bool `json:"success"`
Error struct {
Code int `json:"code"`
Info string `json:"info"`
} `json:"error"`
Success bool `json:"success"`
Error Error `json:"error"`
Terms string `json:"terms"`
Privacy string `json:"privacy"`
Timestamp int64 `json:"timestamp"`
@@ -16,11 +19,8 @@ type LiveRates struct {
// SupportedCurrencies holds supported currency information
type SupportedCurrencies struct {
Success bool `json:"success"`
Error struct {
Code int `json:"code"`
Info string `json:"info"`
} `json:"error"`
Success bool `json:"success"`
Error Error `json:"error"`
Terms string `json:"terms"`
Privacy string `json:"privacy"`
Currencies map[string]string `json:"currencies"`
@@ -28,11 +28,8 @@ type SupportedCurrencies struct {
// HistoricalRates is a response type holding rates priced from the past.
type HistoricalRates struct {
Success bool `json:"success"`
Error struct {
Code int `json:"code"`
Info string `json:"info"`
} `json:"error"`
Success bool `json:"success"`
Error Error `json:"error"`
Terms string `json:"terms"`
Privacy string `json:"privacy"`
Historical bool `json:"historical"`
@@ -44,11 +41,8 @@ type HistoricalRates struct {
// ConversionRate is a response type holding a converted rate.
type ConversionRate struct {
Success bool `json:"success"`
Error struct {
Code int `json:"code"`
Info string `json:"info"`
} `json:"error"`
Success bool `json:"success"`
Error Error `json:"error"`
Privacy string `json:"privacy"`
Terms string `json:"terms"`
Query struct {
@@ -67,11 +61,8 @@ type ConversionRate struct {
// TimeFrame is a response type holding exchange rates for a time period
type TimeFrame struct {
Success bool `json:"success"`
Error struct {
Code int `json:"code"`
Info string `json:"info"`
} `json:"error"`
Success bool `json:"success"`
Error Error `json:"error"`
Terms string `json:"terms"`
Privacy string `json:"privacy"`
Timeframe bool `json:"timeframe"`
@@ -83,11 +74,8 @@ type TimeFrame struct {
// ChangeRate is the response type that holds rate change data.
type ChangeRate struct {
Success bool `json:"success"`
Error struct {
Code int `json:"code"`
Info string `json:"info"`
} `json:"error"`
Success bool `json:"success"`
Error Error `json:"error"`
Terms string `json:"terms"`
Privacy string `json:"privacy"`
Change bool `json:"change"`

View File

@@ -3,11 +3,14 @@ package exchangerates
import (
"errors"
"fmt"
"net/http"
"net/url"
"strings"
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/forexprovider/base"
"github.com/thrasher-/gocryptotrader/exchanges/request"
log "github.com/thrasher-/gocryptotrader/logger"
)
@@ -15,23 +18,32 @@ const (
exchangeRatesAPI = "https://api.exchangeratesapi.io"
exchangeRatesLatest = "latest"
exchangeRatesHistory = "history"
exchangeRatesSupportedCurrencies = "USD,ISK,CAD,MXN,CHF,AUD,CNY,GBP,SEK,NOK,TRY,IDR,ZAR," +
"HRK,EUR,HKD,ILS,NZD,MYR,JPY,CZK,JPY,CZK,SGD,RUB,RON,HUF,BGN,INR,KRW," +
"DKK,THB,PHP,PLN,BRL"
exchangeRatesSupportedCurrencies = "EUR,CHF,USD,BRL,ISK,PHP,KRW,BGN,MXN," +
"RON,CAD,SGD,NZD,THB,HKD,JPY,NOK,HRK,ILS,GBP,DKK,HUF,MYR,RUB,TRY,IDR," +
"ZAR,INR,AUD,CZK,SEK,CNY,PLN"
authRate = 0
unAuthRate = 0
)
// ExchangeRates stores the struct for the ExchangeRatesAPI API
type ExchangeRates struct {
base.Base
Requester *request.Requester
}
// Setup sets appropriate values for CurrencyLayer
func (e *ExchangeRates) Setup(config base.Settings) {
func (e *ExchangeRates) Setup(config base.Settings) error {
e.Name = config.Name
e.Enabled = config.Enabled
e.RESTPollingDelay = config.RESTPollingDelay
e.Verbose = config.Verbose
e.PrimaryProvider = config.PrimaryProvider
e.Requester = request.New(e.Name,
request.NewRateLimit(time.Second*10, authRate),
request.NewRateLimit(time.Second*10, unAuthRate),
common.NewHTTPClientWithTimeout(base.DefaultTimeOut))
return nil
}
func cleanCurrencies(baseCurrency, symbols string) string {
@@ -150,10 +162,21 @@ func (e *ExchangeRates) GetRates(baseCurrency, symbols string) (map[string]float
return standardisedRates, nil
}
// GetSupportedCurrencies returns the supported currency list
func (e *ExchangeRates) GetSupportedCurrencies() ([]string, error) {
return common.SplitStrings(exchangeRatesSupportedCurrencies, ","), nil
}
// SendHTTPRequest sends a HTTPS request to the desired endpoint and returns the result
func (e *ExchangeRates) SendHTTPRequest(endPoint string, values url.Values, result interface{}) error {
path := common.EncodeURLValues(exchangeRatesAPI+"/"+endPoint, values)
err := common.SendHTTPGetRequest(path, true, e.Verbose, &result)
err := e.Requester.SendPayload(http.MethodGet,
path,
nil,
nil,
&result,
false,
e.Verbose)
if err != nil {
return fmt.Errorf("exchangeRatesAPI SendHTTPRequest error %s with path %s",
err,

View File

@@ -2,12 +2,26 @@ package exchangerates
import (
"testing"
"github.com/thrasher-/gocryptotrader/currency/forexprovider/base"
)
var e ExchangeRates
var initialSetup bool
func setup() {
e.Setup(base.Settings{
Name: "ExchangeRates",
Enabled: true,
})
initialSetup = true
}
func TestGetLatestRates(t *testing.T) {
e.Verbose = true
if !initialSetup {
setup()
}
result, err := e.GetLatestRates("USD", "")
if err != nil {
t.Fatalf("failed to GetLatestRates. Err: %s", err)
@@ -40,6 +54,9 @@ func TestGetLatestRates(t *testing.T) {
}
func TestCleanCurrencies(t *testing.T) {
if !initialSetup {
setup()
}
result := cleanCurrencies("USD", "USD,AUD")
if result != "AUD" {
t.Fatalf("unexpected result. AUD should be the only symbol")
@@ -60,6 +77,9 @@ func TestCleanCurrencies(t *testing.T) {
}
func TestGetRates(t *testing.T) {
if !initialSetup {
setup()
}
_, err := e.GetRates("USD", "AUD")
if err != nil {
t.Fatalf("failed to GetRates. Err: %s", err)
@@ -67,7 +87,9 @@ func TestGetRates(t *testing.T) {
}
func TestGetHistoricalRates(t *testing.T) {
e.Verbose = true
if !initialSetup {
setup()
}
_, err := e.GetHistoricalRates("-1", "USD", []string{"AUD"})
if err == nil {
t.Fatalf("unexpected result. Invalid date should throw an error")
@@ -80,6 +102,9 @@ func TestGetHistoricalRates(t *testing.T) {
}
func TestGetTimeSeriesRates(t *testing.T) {
if !initialSetup {
setup()
}
_, err := e.GetTimeSeriesRates("", "", "USD", []string{"EUR", "USD"})
if err == nil {
t.Fatal("unexpected result. Empty startDate endDate params should throw an error")

View File

@@ -10,11 +10,15 @@ package fixer
import (
"errors"
"net/http"
"net/url"
"strconv"
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/forexprovider/base"
"github.com/thrasher-/gocryptotrader/exchanges/request"
log "github.com/thrasher-/gocryptotrader/logger"
)
const (
@@ -24,22 +28,32 @@ const (
fixerAPIProfessionalPlus
fixerAPIEnterprise
fixerAPI = "http://data.fixer.io/api/"
fixerAPISSL = "https://data.fixer.io/api/"
fixerAPILatest = "latest"
fixerAPIConvert = "convert"
fixerAPITimeSeries = "timeseries"
fixerAPIFluctuation = "fluctuation"
fixerAPI = "http://data.fixer.io/api/"
fixerAPISSL = "https://data.fixer.io/api/"
fixerAPILatest = "latest"
fixerAPIConvert = "convert"
fixerAPITimeSeries = "timeseries"
fixerAPIFluctuation = "fluctuation"
fixerSupportedCurrencies = "symbols"
authRate = 0
unAuthRate = 0
)
// Fixer is a foreign exchange rate provider at https://fixer.io/
// NOTE DEFAULT BASE CURRENCY IS EUR upgrade to basic to change
type Fixer struct {
base.Base
Requester *request.Requester
}
// Setup sets appropriate values for fixer object
func (f *Fixer) Setup(config base.Settings) {
func (f *Fixer) Setup(config base.Settings) error {
if config.APIKeyLvl < 0 || config.APIKeyLvl > 4 {
log.Errorf("apikey incorrectly set in config.json for %s, please set appropriate account levels",
config.Name)
return errors.New("apikey set failure")
}
f.APIKey = config.APIKey
f.APIKeyLvl = config.APIKeyLvl
f.Enabled = config.Enabled
@@ -47,6 +61,32 @@ func (f *Fixer) Setup(config base.Settings) {
f.RESTPollingDelay = config.RESTPollingDelay
f.Verbose = config.Verbose
f.PrimaryProvider = config.PrimaryProvider
f.Requester = request.New(f.Name,
request.NewRateLimit(time.Second*10, authRate),
request.NewRateLimit(time.Second*10, unAuthRate),
common.NewHTTPClientWithTimeout(base.DefaultTimeOut))
return nil
}
// GetSupportedCurrencies returns supported currencies
func (f *Fixer) GetSupportedCurrencies() ([]string, error) {
var resp Symbols
err := f.SendOpenHTTPRequest(fixerSupportedCurrencies, nil, &resp)
if err != nil {
return nil, err
}
if !resp.Success {
return nil, errors.New(resp.Error.Type + resp.Error.Info)
}
var currencies []string
for key := range resp.Map {
currencies = append(currencies, key)
}
return currencies, nil
}
// GetRates is a wrapper function to return rates
@@ -209,10 +249,19 @@ func (f *Fixer) SendOpenHTTPRequest(endpoint string, v url.Values, result interf
var path string
v.Set("access_key", f.APIKey)
var auth bool
if f.APIKeyLvl == fixerAPIFree {
path = fixerAPI + endpoint + "?" + v.Encode()
} else {
path = fixerAPISSL + endpoint + "?" + v.Encode()
auth = true
}
return common.SendHTTPGetRequest(path, true, f.Verbose, result)
return f.Requester.SendPayload(http.MethodGet,
path,
nil,
nil,
result,
auth,
f.Verbose)
}

View File

@@ -2,12 +2,8 @@ package fixer
// Rates contains the data fields for the currencies you have requested.
type Rates struct {
Success bool `json:"success"`
Error struct {
Code int `json:"code"`
Type string `json:"type"`
Info string `json:"info"`
} `json:"error"`
Success bool `json:"success"`
Error RespError `json:"error"`
Historical bool `json:"historical"`
Timestamp int64 `json:"timestamp"`
Base string `json:"base"`
@@ -17,13 +13,9 @@ type Rates struct {
// Conversion contains data for currency conversion
type Conversion struct {
Success bool `json:"success"`
Error struct {
Code int `json:"code"`
Type string `json:"type"`
Info string `json:"info"`
} `json:"error"`
Query struct {
Success bool `json:"success"`
Error RespError `json:"error"`
Query struct {
From string `json:"from"`
To string `json:"to"`
Amount float64 `json:"amount"`
@@ -39,12 +31,8 @@ type Conversion struct {
// TimeSeries holds timeseries data
type TimeSeries struct {
Success bool `json:"success"`
Error struct {
Code int `json:"code"`
Type string `json:"type"`
Info string `json:"info"`
} `json:"error"`
Success bool `json:"success"`
Error RespError `json:"error"`
Timeseries bool `json:"timeseries"`
StartDate string `json:"start_date"`
EndDate string `json:"end_date"`
@@ -54,12 +42,8 @@ type TimeSeries struct {
// Fluctuation holds fluctuation data
type Fluctuation struct {
Success bool `json:"success"`
Error struct {
Code int `json:"code"`
Type string `json:"type"`
Info string `json:"info"`
} `json:"error"`
Success bool `json:"success"`
Error RespError `json:"error"`
Fluctuation bool `json:"fluctuation"`
StartDate string `json:"start_date"`
EndDate string `json:"end_date"`
@@ -74,3 +58,17 @@ type Flux struct {
Change float64 `json:"change"`
ChangePCT float64 `json:"change_pct"`
}
// RespError defines a general resp error sub type
type RespError struct {
Code int `json:"code"`
Type string `json:"type"`
Info string `json:"info"`
}
// Symbols defines a symbols list
type Symbols struct {
Success bool `json:"success"`
Error RespError `json:"error"`
Map map[string]string `json:"symbols"`
}

View File

@@ -3,68 +3,135 @@
package forexprovider
import (
"errors"
"github.com/thrasher-/gocryptotrader/currency/forexprovider/base"
currencyconverter "github.com/thrasher-/gocryptotrader/currency/forexprovider/currencyconverterapi"
"github.com/thrasher-/gocryptotrader/currency/forexprovider/currencylayer"
exchangerates "github.com/thrasher-/gocryptotrader/currency/forexprovider/exchangeratesapi.io"
fixer "github.com/thrasher-/gocryptotrader/currency/forexprovider/fixer.io"
"github.com/thrasher-/gocryptotrader/currency/forexprovider/openexchangerates"
log "github.com/thrasher-/gocryptotrader/logger"
)
// ForexProviders is an array of foreign exchange interfaces
// ForexProviders is a foreign exchange handler type
type ForexProviders struct {
base.IFXProviders
base.FXHandler
}
// GetAvailableForexProviders returns a list of supported forex providers
func GetAvailableForexProviders() []string {
return []string{"CurrencyConverter", "CurrencyLayer", "ExchangeRates", "Fixer", "OpenExchangeRates"}
return []string{"CurrencyConverter",
"CurrencyLayer",
"ExchangeRates",
"Fixer",
"OpenExchangeRates"}
}
// NewDefaultFXProvider returns the default forex provider (currencyconverterAPI)
func NewDefaultFXProvider() *ForexProviders {
fxp := new(ForexProviders)
currencyC := new(exchangerates.ExchangeRates)
currencyC.PrimaryProvider = true
currencyC.Enabled = true
currencyC.Name = "ExchangeRates"
fxp.IFXProviders = append(fxp.IFXProviders, currencyC)
return fxp
handler := new(ForexProviders)
provider := new(exchangerates.ExchangeRates)
err := provider.Setup(base.Settings{
PrimaryProvider: true,
Enabled: true,
Name: "ExchangeRates",
})
if err != nil {
panic(err)
}
currencies, _ := provider.GetSupportedCurrencies()
providerBase := base.Provider{
Provider: provider,
SupportedCurrencies: currencies,
}
handler.FXHandler = base.FXHandler{
Primary: providerBase,
}
return handler
}
// SetProvider sets provider to the FX handler
func (f *ForexProviders) SetProvider(b base.IFXProvider) error {
currencies, err := b.GetSupportedCurrencies()
if err != nil {
return err
}
providerBase := base.Provider{
Provider: b,
SupportedCurrencies: currencies,
}
if b.IsPrimaryProvider() {
f.FXHandler = base.FXHandler{
Primary: providerBase,
}
return nil
}
f.FXHandler.Support = append(f.FXHandler.Support, providerBase)
return nil
}
// StartFXService starts the forex provider service and returns a pointer to it
func StartFXService(fxProviders []base.Settings) *ForexProviders {
fxp := new(ForexProviders)
func StartFXService(fxProviders []base.Settings) (*ForexProviders, error) {
handler := new(ForexProviders)
for i := range fxProviders {
if fxProviders[i].Name == "CurrencyConverter" && fxProviders[i].Enabled {
currencyC := new(currencyconverter.CurrencyConverter)
currencyC.Setup(fxProviders[i])
fxp.IFXProviders = append(fxp.IFXProviders, currencyC)
}
if fxProviders[i].Name == "CurrencyLayer" && fxProviders[i].Enabled {
currencyLayerP := new(currencylayer.CurrencyLayer)
currencyLayerP.Setup(fxProviders[i])
fxp.IFXProviders = append(fxp.IFXProviders, currencyLayerP)
}
if fxProviders[i].Name == "ExchangeRates" && fxProviders[i].Enabled {
exchangeRatesP := new(exchangerates.ExchangeRates)
exchangeRatesP.Setup(fxProviders[i])
fxp.IFXProviders = append(fxp.IFXProviders, exchangeRatesP)
}
if fxProviders[i].Name == "Fixer" && fxProviders[i].Enabled {
fixerP := new(fixer.Fixer)
fixerP.Setup(fxProviders[i])
fxp.IFXProviders = append(fxp.IFXProviders, fixerP)
}
if fxProviders[i].Name == "OpenExchangeRates" && fxProviders[i].Enabled {
OpenExchangeRatesP := new(openexchangerates.OXR)
OpenExchangeRatesP.Setup(fxProviders[i])
fxp.IFXProviders = append(fxp.IFXProviders, OpenExchangeRatesP)
switch {
case fxProviders[i].Name == "CurrencyConverter" && fxProviders[i].Enabled:
provider := new(currencyconverter.CurrencyConverter)
err := provider.Setup(fxProviders[i])
if err != nil {
return nil, err
}
handler.SetProvider(provider)
case fxProviders[i].Name == "CurrencyLayer" && fxProviders[i].Enabled:
provider := new(currencylayer.CurrencyLayer)
err := provider.Setup(fxProviders[i])
if err != nil {
return nil, err
}
handler.SetProvider(provider)
case fxProviders[i].Name == "ExchangeRates" && fxProviders[i].Enabled:
provider := new(exchangerates.ExchangeRates)
err := provider.Setup(fxProviders[i])
if err != nil {
return nil, err
}
handler.SetProvider(provider)
case fxProviders[i].Name == "Fixer" && fxProviders[i].Enabled:
provider := new(fixer.Fixer)
err := provider.Setup(fxProviders[i])
if err != nil {
return nil, err
}
handler.SetProvider(provider)
case fxProviders[i].Name == "OpenExchangeRates" && fxProviders[i].Enabled:
provider := new(openexchangerates.OXR)
err := provider.Setup(fxProviders[i])
if err != nil {
return nil, err
}
handler.SetProvider(provider)
}
}
if len(fxp.IFXProviders) == 0 {
log.Error("No foreign exchange providers enabled")
if handler.Primary.Provider == nil {
return nil, errors.New("no foreign exchange providers enabled")
}
return fxp
return handler, nil
}

View File

@@ -14,9 +14,12 @@ import (
"net/http"
"net/url"
"strconv"
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/forexprovider/base"
"github.com/thrasher-/gocryptotrader/exchanges/request"
log "github.com/thrasher-/gocryptotrader/logger"
)
// These consts contain endpoint information
@@ -33,6 +36,21 @@ const (
APIEndpointConvert = "convert/%s/%s/%s"
APIEndpointOHLC = "ohlc.json"
APIEndpointUsage = "usage.json"
oxrSupportedCurrencies = "AED,AFN,ALL,AMD,ANG,AOA,ARS,AUD,AWG,AZN,BAM,BBD," +
"BDT,BGN,BHD,BIF,BMD,BND,BOB,BRL,BSD,BTC,BTN,BWP,BYN,BYR,BZD,CAD,CDF," +
"CHF,CLF,CLP,CNH,CNY,COP,CRC,CUC,CUP,CVE,CZK,DJF,DKK,DOP,DZD,EEK,EGP," +
"ERN,ETB,EUR,FJD,FKP,GBP,GEL,GGP,GHS,GIP,GMD,GNF,GTQ,GYD,HKD,HNL,HRK," +
"HTG,HUF,IDR,ILS,IMP,INR,IQD,IRR,ISK,JEP,JMD,JOD,JPY,KES,KGS,KHR,KMF," +
"KPW,KRW,KWD,KYD,KZT,LAK,LBP,LKR,LRD,LSL,LYD,MAD,MDL,MGA,MKD,MMK,MNT," +
"MOP,MRO,MRU,MTL,MUR,MVR,MWK,MXN,MYR,MZN,NAD,NGN,NIO,NOK,NPR,NZD,OMR," +
"PAB,PEN,PGK,PHP,PKR,PLN,PYG,QAR,RON,RSD,RUB,RWF,SAR,SBD,SCR,SDG,SEK," +
"SGD,SHP,SLL,SOS,SRD,SSP,STD,STN,SVC,SYP,SZL,THB,TJS,TMT,TND,TOP,TRY," +
"TTD,TWD,TZS,UAH,UGX,USD,UYU,UZS,VEF,VND,VUV,WST,XAF,XAG,XAU,XCD,XDR," +
"XOF,XPD,XPF,XPT,YER,ZAR,ZMK,ZMW"
authRate = 0
unAuthRate = 0
)
// OXR is a foreign exchange rate provider at https://openexchangerates.org/
@@ -40,10 +58,16 @@ const (
// DOCs : https://docs.openexchangerates.org/docs
type OXR struct {
base.Base
Requester *request.Requester
}
// Setup sets values for the OXR object
func (o *OXR) Setup(config base.Settings) {
func (o *OXR) Setup(config base.Settings) error {
if config.APIKeyLvl < 0 || config.APIKeyLvl > 2 {
log.Errorf("apikey incorrectly set in config.json for %s, please set appropriate account levels",
config.Name)
return errors.New("apikey set failure")
}
o.APIKey = config.APIKey
o.APIKeyLvl = config.APIKeyLvl
o.Enabled = config.Enabled
@@ -51,6 +75,11 @@ func (o *OXR) Setup(config base.Settings) {
o.RESTPollingDelay = config.RESTPollingDelay
o.Verbose = config.Verbose
o.PrimaryProvider = config.PrimaryProvider
o.Requester = request.New(o.Name,
request.NewRateLimit(time.Second*10, authRate),
request.NewRateLimit(time.Second*10, unAuthRate),
common.NewHTTPClientWithTimeout(base.DefaultTimeOut))
return nil
}
// GetRates is a wrapper function to return rates
@@ -125,6 +154,11 @@ func (o *OXR) GetCurrencies(showInactive, prettyPrint, showAlternative bool) (ma
return resp, o.SendHTTPRequest(APIEndpointCurrencies, v, &resp)
}
// GetSupportedCurrencies returns a list of supported currencies
func (o *OXR) GetSupportedCurrencies() ([]string, error) {
return common.SplitStrings(oxrSupportedCurrencies, ","), nil
}
// GetTimeSeries returns historical exchange rates for a given time period,
// where available.
func (o *OXR) GetTimeSeries(baseCurrency, startDate, endDate string, symbols []string, prettyPrint, showAlternative bool) (map[string]interface{}, error) {
@@ -223,9 +257,11 @@ func (o *OXR) SendHTTPRequest(endpoint string, values url.Values, result interfa
headers["Authorization"] = "Token " + o.APIKey
path := APIURL + endpoint + "?" + values.Encode()
resp, err := common.SendHTTPRequest(http.MethodGet, path, headers, nil)
if err != nil {
return err
}
return common.JSONDecode([]byte(resp), result)
return o.Requester.SendPayload(http.MethodGet,
path,
headers,
nil,
result,
false,
o.Verbose)
}

View File

@@ -2,6 +2,8 @@ package openexchangerates
import (
"testing"
"github.com/thrasher-/gocryptotrader/currency/forexprovider/base"
)
// please set apikey for due diligence testing NOTE testing uses your allocated
@@ -13,7 +15,20 @@ const (
var o OXR
var initialSetup bool
func setup() {
o.Setup(base.Settings{
Name: "OpenExchangeRates",
Enabled: true,
})
initialSetup = true
}
func TestGetRates(t *testing.T) {
if !initialSetup {
setup()
}
_, err := o.GetRates("USD", "AUD")
if err == nil {
t.Error("test failed - GetRates() error", err)
@@ -21,6 +36,9 @@ func TestGetRates(t *testing.T) {
}
func TestGetLatest(t *testing.T) {
if !initialSetup {
setup()
}
_, err := o.GetLatest("USD", "AUD", false, false)
if err == nil {
t.Error("test failed - GetLatest() error", err)
@@ -28,6 +46,9 @@ func TestGetLatest(t *testing.T) {
}
func TestGetHistoricalRates(t *testing.T) {
if !initialSetup {
setup()
}
_, err := o.GetHistoricalRates("2017-12-01", "USD", []string{"CNH", "AUD", "ANG"}, false, false)
if err == nil {
t.Error("test failed - GetRates() error", err)
@@ -35,6 +56,9 @@ func TestGetHistoricalRates(t *testing.T) {
}
func TestGetCurrencies(t *testing.T) {
if !initialSetup {
setup()
}
_, err := o.GetCurrencies(true, true, true)
if err != nil {
t.Error("test failed - GetCurrencies() error", err)
@@ -42,6 +66,9 @@ func TestGetCurrencies(t *testing.T) {
}
func TestGetTimeSeries(t *testing.T) {
if !initialSetup {
setup()
}
_, err := o.GetTimeSeries("USD", "2017-12-01", "2017-12-02", []string{"CNH", "AUD", "ANG"}, false, false)
if err == nil {
t.Error("test failed - GetTimeSeries() error", err)
@@ -49,6 +76,9 @@ func TestGetTimeSeries(t *testing.T) {
}
func TestConvertCurrency(t *testing.T) {
if !initialSetup {
setup()
}
_, err := o.ConvertCurrency(1337, "USD", "AUD")
if err == nil {
t.Error("test failed - ConvertCurrency() error", err)
@@ -56,6 +86,9 @@ func TestConvertCurrency(t *testing.T) {
}
func TestGetOHLC(t *testing.T) {
if !initialSetup {
setup()
}
_, err := o.GetOHLC("2017-07-17T08:30:00Z", "1m", "USD", []string{"AUD"}, false)
if err == nil {
t.Error("test failed - GetOHLC() error", err)
@@ -63,6 +96,9 @@ func TestGetOHLC(t *testing.T) {
}
func TestGetUsageStats(t *testing.T) {
if !initialSetup {
setup()
}
_, err := o.GetUsageStats(false)
if err == nil {
t.Error("test failed - GetUsageStats() error", err)

190
currency/pair.go Normal file
View File

@@ -0,0 +1,190 @@
package currency
import (
"fmt"
"strings"
"github.com/thrasher-/gocryptotrader/common"
)
// NewPairDelimiter splits the desired currency string at delimeter, the returns
// a Pair struct
func NewPairDelimiter(currencyPair, delimiter string) Pair {
result := strings.Split(currencyPair, delimiter)
return Pair{
Delimiter: delimiter,
Base: NewCode(result[0]),
Quote: NewCode(result[1]),
}
}
// NewPairFromStrings returns a CurrencyPair without a delimiter
func NewPairFromStrings(baseCurrency, quoteCurrency string) Pair {
return Pair{
Base: NewCode(baseCurrency),
Quote: NewCode(quoteCurrency),
}
}
// 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,
}
}
// 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 Pair{},
fmt.Errorf("index %s not found in currency pair string", index)
}
if i == 0 {
return NewPairFromStrings(currencyPair[0:len(index)],
currencyPair[len(index):]),
nil
}
return NewPairFromStrings(currencyPair[0:i], currencyPair[i:]), nil
}
// NewPairFromString converts currency string into a new CurrencyPair
// with or without delimeter
func NewPairFromString(currencyPair string) Pair {
delimiters := []string{"_", "-"}
var delimiter string
for _, x := range delimiters {
if strings.Contains(currencyPair, x) {
delimiter = x
return NewPairDelimiter(currencyPair, delimiter)
}
}
return NewPairFromStrings(currencyPair[0:3], currencyPair[3:])
}
// Pair holds currency pair information
type Pair struct {
Delimiter string `json:"delimiter"`
Base Code `json:"base"`
Quote Code `json:"quote"`
}
// String returns a currency pair string
func (p Pair) String() string {
return p.Base.String() + p.Delimiter + p.Quote.String()
}
// Lower converts the pair object to lowercase
func (p Pair) Lower() Pair {
return Pair{
Delimiter: p.Delimiter,
Base: p.Base.Lower(),
Quote: p.Quote.Lower(),
}
}
// Upper converts the pair object to uppercase
func (p Pair) Upper() Pair {
return Pair{
Delimiter: p.Delimiter,
Base: p.Base.Upper(),
Quote: p.Quote.Upper(),
}
}
// UnmarshalJSON comforms type to the umarshaler interface
func (p *Pair) UnmarshalJSON(d []byte) error {
var pair string
err := common.JSONDecode(d, &pair)
if err != nil {
return err
}
*p = NewPairFromString(pair)
return nil
}
// MarshalJSON conforms type to the marshaler interface
func (p Pair) MarshalJSON() ([]byte, error) {
return common.JSONEncode(p.String())
}
// Format changes the currency based on user preferences overriding the default
// String() display
func (p Pair) Format(delimiter string, uppercase bool) Pair {
p.Delimiter = delimiter
if uppercase {
return p.Upper()
}
return p.Lower()
}
// Equal compares two currency pairs and returns whether or not they are equal
func (p Pair) Equal(cPair Pair) bool {
return p.Base.Item == cPair.Base.Item && p.Quote.Item == cPair.Quote.Item
}
// EqualIncludeReciprocal compares two currency pairs and returns whether or not
// they are the same including reciprocal currencies.
func (p Pair) EqualIncludeReciprocal(cPair Pair) bool {
if p.Base.Item == cPair.Base.Item &&
p.Quote.Item == cPair.Quote.Item ||
p.Base.Item == cPair.Quote.Item &&
p.Quote.Item == cPair.Base.Item {
return true
}
return false
}
// IsCryptoPair checks to see if the pair is a crypto pair e.g. BTCLTC
func (p Pair) IsCryptoPair() bool {
return storage.IsCryptocurrency(p.Base) &&
storage.IsCryptocurrency(p.Quote)
}
// IsCryptoFiatPair checks to see if the pair is a crypto fiat pair e.g. BTCUSD
func (p Pair) IsCryptoFiatPair() bool {
return storage.IsCryptocurrency(p.Base) &&
storage.IsFiatCurrency(p.Quote) ||
storage.IsFiatCurrency(p.Base) &&
storage.IsCryptocurrency(p.Quote)
}
// IsFiatPair checks to see if the pair is a fiat pair e.g. EURUSD
func (p Pair) IsFiatPair() bool {
return storage.IsFiatCurrency(p.Base) && storage.IsFiatCurrency(p.Quote)
}
// IsInvalid checks invalid pair if base and quote are the same
func (p Pair) IsInvalid() bool {
return p.Base.Item == p.Quote.Item
}
// Swap turns the currency pair into its reciprocal
func (p Pair) Swap() Pair {
p.Base, p.Quote = p.Quote, p.Base
return p
}
// IsEmpty returns whether or not the pair is empty or is missing a currency
// code
func (p Pair) IsEmpty() bool {
return p.Base.IsEmpty() || p.Quote.IsEmpty()
}
// ContainsCurrency checks to see if a pair contains a specific currency
func (p Pair) ContainsCurrency(c Code) bool {
return p.Base.Item == c.Item || p.Quote.Item == c.Item
}

View File

@@ -1,57 +0,0 @@
# GoCryptoTrader package Pair
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
[![Build Status](https://travis-ci.org/thrasher-/gocryptotrader.svg?branch=master)](https://travis-ci.org/thrasher-/gocryptotrader)
[![Software License](https://img.shields.io/badge/License-MIT-orange.svg?style=flat-square)](https://github.com/thrasher-/gocryptotrader/blob/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/thrasher-/gocryptotrader?status.svg)](https://godoc.org/github.com/thrasher-/gocryptotrader/currency/pair)
[![Coverage Status](http://codecov.io/github/thrasher-/gocryptotrader/coverage.svg?branch=master)](http://codecov.io/github/thrasher-/gocryptotrader?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/thrasher-/gocryptotrader)](https://goreportcard.com/report/github.com/thrasher-/gocryptotrader)
This pair package is part of the GoCryptoTrader codebase.
## This is still in active development
You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/enQtNTQ5NDAxMjA2Mjc5LTQyYjIxNGVhMWU5MDZlOGYzMmE0NTJmM2MzYWY5NGMzMmM4MzUwNTBjZTEzNjIwODM5NDcxODQwZDljMGQyNGY)
## Current Features for pair
+ Provides a new data structure for a currency pair
+ Methods to manipulate, create and retrieve different parts of the currency pair
+ Example below:
```go
import "github.com/thrasher-/gocryptotrader/currency/pair"
// Create new pair
newPair := pair.NewCurrencyPair("BTC", "USD")
// Retrieve different parts of the pair
bitcoinString := newPair.GetFirstCurrency
```
### Please click GoDocs chevron above to view current GoDoc information for this package
## Contribution
Please feel free to submit any pull requests or suggest any desired features to be added.
When submitting a PR, please abide by our coding guidelines:
+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
+ Code must adhere to our [coding style](https://github.com/thrasher-/gocryptotrader/blob/master/doc/coding_style.md).
+ Pull requests need to be based on and opened against the `master` branch.
## Donations
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***

View File

@@ -1,246 +0,0 @@
package pair
import (
"math/rand"
"strings"
"github.com/thrasher-/gocryptotrader/common"
)
// CurrencyItem is an exported string with methods to manipulate the data instead
// of using array/slice access modifiers
type CurrencyItem string
// Lower converts the CurrencyItem object c to lowercase
func (c CurrencyItem) Lower() CurrencyItem {
return CurrencyItem(strings.ToLower(string(c)))
}
// Upper converts the CurrencyItem object c to uppercase
func (c CurrencyItem) Upper() CurrencyItem {
return CurrencyItem(strings.ToUpper(string(c)))
}
// String converts the CurrencyItem object c to string
func (c CurrencyItem) String() string {
return string(c)
}
// CurrencyPair holds currency pair information
type CurrencyPair struct {
Delimiter string `json:"delimiter"`
FirstCurrency CurrencyItem `json:"first_currency"`
SecondCurrency CurrencyItem `json:"second_currency"`
}
// Pair returns a currency pair string
func (c CurrencyPair) Pair() CurrencyItem {
return c.FirstCurrency + CurrencyItem(c.Delimiter) + c.SecondCurrency
}
// Display formats and returns the currency based on user preferences,
// overriding the default Pair() display
func (c CurrencyPair) Display(delimiter string, uppercase bool) CurrencyItem {
var pair CurrencyItem
if delimiter != "" {
pair = c.FirstCurrency + CurrencyItem(delimiter) + c.SecondCurrency
} else {
pair = c.FirstCurrency + c.SecondCurrency
}
if uppercase {
return pair.Upper()
}
return pair.Lower()
}
// Equal compares two currency pairs and returns whether or not they are equal
func (c CurrencyPair) Equal(p CurrencyPair, exact bool) bool {
if !exact {
if c.FirstCurrency.Upper() == p.FirstCurrency.Upper() &&
c.SecondCurrency.Upper() == p.SecondCurrency.Upper() ||
c.FirstCurrency.Upper() == p.SecondCurrency.Upper() &&
c.SecondCurrency.Upper() == p.FirstCurrency.Upper() {
return true
}
} else {
if c.FirstCurrency.Upper() == p.FirstCurrency.Upper() &&
c.SecondCurrency.Upper() == p.SecondCurrency.Upper() {
return true
}
}
return false
}
// Swap swaps the pairs first and second currencies
func (c CurrencyPair) Swap() CurrencyPair {
p := c
p.FirstCurrency = c.SecondCurrency
p.SecondCurrency = c.FirstCurrency
return p
}
// Empty returns whether or not the pair is empty
func (c CurrencyPair) Empty() bool {
if c.FirstCurrency == "" || c.SecondCurrency == "" {
return true
}
return false
}
// NewCurrencyPairDelimiter splits the desired currency string at delimeter,
// the returns a CurrencyPair struct
func NewCurrencyPairDelimiter(currency, delimiter string) CurrencyPair {
result := strings.Split(currency, delimiter)
return CurrencyPair{
Delimiter: delimiter,
FirstCurrency: CurrencyItem(result[0]),
SecondCurrency: CurrencyItem(result[1]),
}
}
// NewCurrencyPair returns a CurrencyPair without a delimiter
func NewCurrencyPair(firstCurrency, secondCurrency string) CurrencyPair {
return CurrencyPair{
FirstCurrency: CurrencyItem(firstCurrency),
SecondCurrency: CurrencyItem(secondCurrency),
}
}
// NewCurrencyPairWithDelimiter returns a CurrencyPair with a delimiter
func NewCurrencyPairWithDelimiter(firstCurrency, secondCurrency, delimiter string) CurrencyPair {
return CurrencyPair{
FirstCurrency: CurrencyItem(firstCurrency),
SecondCurrency: CurrencyItem(secondCurrency),
Delimiter: delimiter,
}
}
// NewCurrencyPairFromIndex returns a CurrencyPair via a currency string and
// specific index
func NewCurrencyPairFromIndex(currency, index string) CurrencyPair {
i := strings.Index(currency, index)
if i == 0 {
return NewCurrencyPair(currency[0:len(index)], currency[len(index):])
}
return NewCurrencyPair(currency[0:i], currency[i:])
}
// NewCurrencyPairFromString converts currency string into a new CurrencyPair
// with or without delimeter
func NewCurrencyPairFromString(currency string) CurrencyPair {
delimiters := []string{"_", "-"}
var delimiter string
for _, x := range delimiters {
if strings.Contains(currency, x) {
delimiter = x
return NewCurrencyPairDelimiter(currency, delimiter)
}
}
return NewCurrencyPair(currency[0:3], currency[3:])
}
// Contains checks to see if a specified pair exists inside a currency pair
// array
func Contains(pairs []CurrencyPair, p CurrencyPair, exact bool) bool {
for x := range pairs {
if pairs[x].Equal(p, exact) {
return true
}
}
return false
}
// ContainsCurrency checks to see if a pair contains a specific currency
func ContainsCurrency(p CurrencyPair, c string) bool {
return p.FirstCurrency.Upper().String() == common.StringToUpper(c) ||
p.SecondCurrency.Upper().String() == common.StringToUpper(c)
}
// RemovePairsByFilter checks to see if a pair contains a specific currency
// and removes it from the list of pairs
func RemovePairsByFilter(p []CurrencyPair, filter string) []CurrencyPair {
var pairs []CurrencyPair
for x := range p {
if ContainsCurrency(p[x], filter) {
continue
}
pairs = append(pairs, p[x])
}
return pairs
}
// FormatPairs formats a string array to a list of currency pairs with the
// supplied currency pair format
func FormatPairs(pairs []string, delimiter, index string) []CurrencyPair {
var result []CurrencyPair
for x := range pairs {
if pairs[x] == "" {
continue
}
var p CurrencyPair
if delimiter != "" {
p = NewCurrencyPairDelimiter(pairs[x], delimiter)
} else {
if index != "" {
p = NewCurrencyPairFromIndex(pairs[x], index)
} else {
p = NewCurrencyPair(pairs[x][0:3], pairs[x][3:])
}
}
result = append(result, p)
}
return result
}
// CopyPairFormat copies the pair format from a list of pairs once matched
func CopyPairFormat(p CurrencyPair, pairs []CurrencyPair, exact bool) CurrencyPair {
for x := range pairs {
if p.Equal(pairs[x], exact) {
return pairs[x]
}
}
return CurrencyPair{}
}
// FindPairDifferences returns pairs which are new or have been removed
func FindPairDifferences(oldPairs, newPairs []string) (newPs, removedPs []string) {
for x := range newPairs {
if newPairs[x] == "" {
continue
}
if !common.StringDataCompareUpper(oldPairs, newPairs[x]) {
newPs = append(newPs, newPairs[x])
}
}
for x := range oldPairs {
if oldPairs[x] == "" {
continue
}
if !common.StringDataCompareUpper(newPairs, oldPairs[x]) {
removedPs = append(removedPs, oldPairs[x])
}
}
return newPs, removedPs
}
// PairsToStringArray returns a list of pairs as a string array
func PairsToStringArray(pairs []CurrencyPair) []string {
var p []string
for x := range pairs {
p = append(p, pairs[x].Pair().String())
}
return p
}
// RandomPairFromPairs returns a random pair from a list of pairs
func RandomPairFromPairs(pairs []CurrencyPair) CurrencyPair {
pairsLen := len(pairs)
if pairsLen == 0 {
return CurrencyPair{}
}
return pairs[rand.Intn(pairsLen)]
}

View File

@@ -1,440 +0,0 @@
package pair
import (
"testing"
)
func TestLower(t *testing.T) {
t.Parallel()
pair := CurrencyItem("BTCUSD")
actual := pair.Lower()
expected := CurrencyItem("btcusd")
if actual != expected {
t.Errorf("Test failed. Lower(): %s was not equal to expected value: %s",
actual, expected)
}
}
func TestUpper(t *testing.T) {
t.Parallel()
pair := CurrencyItem("btcusd")
actual := pair.Upper()
expected := CurrencyItem("BTCUSD")
if actual != expected {
t.Errorf("Test failed. Upper(): %s was not equal to expected value: %s",
actual, expected)
}
}
func TestString(t *testing.T) {
t.Parallel()
pair := NewCurrencyPair("BTC", "USD")
actual := "BTCUSD"
expected := pair.Pair().String()
if actual != expected {
t.Errorf("Test failed. String(): %s was not equal to expected value: %s",
actual, expected)
}
}
func TestFirstCurrency(t *testing.T) {
t.Parallel()
pair := NewCurrencyPair("BTC", "USD")
actual := pair.FirstCurrency
expected := CurrencyItem("BTC")
if actual != expected {
t.Errorf(
"Test failed. GetFirstCurrency(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestSecondCurrency(t *testing.T) {
t.Parallel()
pair := NewCurrencyPair("BTC", "USD")
actual := pair.SecondCurrency
expected := CurrencyItem("USD")
if actual != expected {
t.Errorf(
"Test failed. GetSecondCurrency(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestPair(t *testing.T) {
t.Parallel()
pair := NewCurrencyPair("BTC", "USD")
actual := pair.Pair()
expected := CurrencyItem("BTCUSD")
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestDisplay(t *testing.T) {
t.Parallel()
pair := NewCurrencyPairDelimiter("BTC-USD", "-")
actual := pair.Pair()
expected := CurrencyItem("BTC-USD")
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
actual = pair.Display("", false)
expected = CurrencyItem("btcusd")
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
actual = pair.Display("~", true)
expected = CurrencyItem("BTC~USD")
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestEqual(t *testing.T) {
t.Parallel()
pair := NewCurrencyPair("BTC", "USD")
secondPair := NewCurrencyPair("btc", "uSd")
actual := pair.Equal(secondPair, false)
expected := true
if actual != expected {
t.Errorf(
"Test failed. Equal(): %v was not equal to expected value: %v",
actual, expected,
)
}
secondPair.SecondCurrency = "ETH"
actual = pair.Equal(secondPair, false)
expected = false
if actual != expected {
t.Errorf(
"Test failed. Equal(): %v was not equal to expected value: %v",
actual, expected,
)
}
secondPair = NewCurrencyPair("USD", "BTC")
actual = pair.Equal(secondPair, false)
expected = true
if actual != expected {
t.Errorf(
"Test failed. Equal(): %v was not equal to expected value: %v",
actual, expected,
)
}
}
func TestSwap(t *testing.T) {
t.Parallel()
pair := NewCurrencyPair("BTC", "USD")
actual := pair.Swap().Pair()
expected := CurrencyItem("USDBTC")
if actual != expected {
t.Errorf(
"Test failed. TestSwap: %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestEmpty(t *testing.T) {
t.Parallel()
pair := NewCurrencyPair("BTC", "USD")
if pair.Empty() {
t.Error("Test failed. Empty() returned true when the pair was initialised")
}
var p CurrencyPair
if !p.Empty() {
t.Error("Test failed. Empty() returned true when the pair wasn't initialised")
}
}
func TestNewCurrencyPair(t *testing.T) {
t.Parallel()
pair := NewCurrencyPair("BTC", "USD")
actual := pair.Pair()
expected := CurrencyItem("BTCUSD")
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestNewCurrencyPairWithDelimiter(t *testing.T) {
t.Parallel()
pair := NewCurrencyPairWithDelimiter("BTC", "USD", "-test-")
actual := pair.Pair()
expected := CurrencyItem("BTC-test-USD")
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
pair = NewCurrencyPairWithDelimiter("BTC", "USD", "")
actual = pair.Pair()
expected = CurrencyItem("BTCUSD")
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestNewCurrencyPairDelimiter(t *testing.T) {
t.Parallel()
pair := NewCurrencyPairDelimiter("BTC-USD", "-")
actual := pair.Pair()
expected := CurrencyItem("BTC-USD")
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
actual = CurrencyItem(pair.Delimiter)
expected = "-"
if actual != expected {
t.Errorf(
"Test failed. Delmiter: %s was not equal to expected value: %s",
actual, expected,
)
}
}
// TestNewCurrencyPairFromIndex returns a CurrencyPair via a currency string and
// specific index
func TestNewCurrencyPairFromIndex(t *testing.T) {
t.Parallel()
currency := "BTCUSD"
index := "BTC"
pair := NewCurrencyPairFromIndex(currency, index)
pair.Delimiter = "-"
actual := pair.Pair()
expected := CurrencyItem("BTC-USD")
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
currency = "DOGEBTC"
pair = NewCurrencyPairFromIndex(currency, index)
pair.Delimiter = "-"
actual = pair.Pair()
expected = CurrencyItem("DOGE-BTC")
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestNewCurrencyPairFromString(t *testing.T) {
t.Parallel()
pairStr := "BTC-USD"
pair := NewCurrencyPairFromString(pairStr)
actual := pair.Pair()
expected := CurrencyItem("BTC-USD")
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
pairStr = "BTCUSD"
pair = NewCurrencyPairFromString(pairStr)
actual = pair.Pair()
expected = CurrencyItem("BTCUSD")
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestContains(t *testing.T) {
pairOne := NewCurrencyPair("BTC", "USD")
var pairs []CurrencyPair
pairs = append(pairs, pairOne, NewCurrencyPair("LTC", "USD"))
if !Contains(pairs, pairOne, true) {
t.Errorf("Test failed. TestContains: Expected pair was not found")
}
if Contains(pairs, NewCurrencyPair("ETH", "USD"), false) {
t.Errorf("Test failed. TestContains: Non-existent pair was found")
}
}
func TestContainsCurrency(t *testing.T) {
p := NewCurrencyPair("BTC", "USD")
if !ContainsCurrency(p, "BTC") {
t.Error("Test failed. TestContainsCurrency: Expected currency was not found")
}
if ContainsCurrency(p, "ETH") {
t.Error("Test failed. TestContainsCurrency: Non-existent currency was found")
}
}
func TestRemovePairsByFilter(t *testing.T) {
var pairs []CurrencyPair
pairs = append(pairs, NewCurrencyPair("BTC", "USD"),
NewCurrencyPair("LTC", "USD"),
NewCurrencyPair("LTC", "USDT"))
pairs = RemovePairsByFilter(pairs, "USDT")
if Contains(pairs, NewCurrencyPair("LTC", "USDT"), true) {
t.Error("Test failed. TestRemovePairsByFilter unexpected result")
}
}
func TestFormatPairs(t *testing.T) {
if len(FormatPairs([]string{""}, "-", "")) > 0 {
t.Error("Test failed. TestFormatPairs: Empty string returned a valid pair")
}
if FormatPairs([]string{"BTC-USD"}, "-", "")[0].Pair().String() != "BTC-USD" {
t.Error("Test failed. TestFormatPairs: Expected pair was not found")
}
if FormatPairs([]string{"BTCUSD"}, "", "BTC")[0].Pair().String() != "BTCUSD" {
t.Error("Test failed. TestFormatPairs: Expected pair was not found")
}
if FormatPairs([]string{"ETHUSD"}, "", "")[0].Pair().String() != "ETHUSD" {
t.Error("Test failed. TestFormatPairs: Expected pair was not found")
}
}
func TestCopyPairFormat(t *testing.T) {
pairOne := NewCurrencyPair("BTC", "USD")
pairOne.Delimiter = "-"
var pairs []CurrencyPair
pairs = append(pairs, pairOne, NewCurrencyPair("LTC", "USD"))
testPair := NewCurrencyPair("BTC", "USD")
testPair.Delimiter = "~"
result := CopyPairFormat(testPair, pairs, false)
if result.Pair().String() != "BTC-USD" {
t.Error("Test failed. TestCopyPairFormat: Expected pair was not found")
}
result = CopyPairFormat(NewCurrencyPair("ETH", "USD"), pairs, true)
if result.Pair().String() != "" {
t.Error("Test failed. TestCopyPairFormat: Unexpected non empty pair returned")
}
}
func TestFindPairDifferences(t *testing.T) {
pairList := []string{"BTC-USD", "ETH-USD", "LTC-USD"}
// Test new pair update
newPairs, removedPairs := FindPairDifferences(pairList, []string{"DASH-USD"})
if len(newPairs) != 1 && len(removedPairs) != 3 {
t.Error("Test failed. TestFindPairDifferences: Unexpected values")
}
// Test that we don't allow empty strings for new pairs
newPairs, removedPairs = FindPairDifferences(pairList, []string{""})
if len(newPairs) != 0 && len(removedPairs) != 3 {
t.Error("Test failed. TestFindPairDifferences: Unexpected values")
}
// Test that we don't allow empty strings for new pairs
newPairs, removedPairs = FindPairDifferences([]string{""}, pairList)
if len(newPairs) != 3 && len(removedPairs) != 0 {
t.Error("Test failed. TestFindPairDifferences: Unexpected values")
}
// Test that the supplied pair lists are the same, so
// no newPairs or removedPairs
newPairs, removedPairs = FindPairDifferences(pairList, pairList)
if len(newPairs) != 0 && len(removedPairs) != 0 {
t.Error("Test failed. TestFindPairDifferences: Unexpected values")
}
}
func TestPairsToStringArray(t *testing.T) {
var pairs []CurrencyPair
pairs = append(pairs, NewCurrencyPair("BTC", "USD"))
expected := []string{"BTCUSD"}
actual := PairsToStringArray(pairs)
if actual[0] != expected[0] {
t.Error("Test failed. TestPairsToStringArray: Unexpected values")
}
}
func TestRandomPairFromPairs(t *testing.T) {
// Test that an empty pairs array returns an empty currency pair
result := RandomPairFromPairs([]CurrencyPair{})
if !result.Empty() {
t.Error("Test failed. TestRandomPairFromPairs: Unexpected values")
}
// Test that a populated pairs array returns a non-empty currency pair
var pairs []CurrencyPair
pairs = append(pairs, NewCurrencyPair("BTC", "USD"))
result = RandomPairFromPairs(pairs)
if result.Empty() {
t.Error("Test failed. TestRandomPairFromPairs: Unexpected values")
}
// Test that a populated pairs array over a number of attempts returns ALL
// currency pairs
pairs = append(pairs, NewCurrencyPair("ETH", "USD"))
expectedResults := make(map[string]bool)
for i := 0; i < 50; i++ {
p := RandomPairFromPairs(pairs).Pair().String()
_, ok := expectedResults[p]
if !ok {
expectedResults[p] = true
}
}
for x := range pairs {
_, ok := expectedResults[pairs[x].Pair().String()]
if !ok {
t.Error("Test failed. TestRandomPairFromPairs: Unexpected values")
}
}
}

563
currency/pair_test.go Normal file
View File

@@ -0,0 +1,563 @@
package currency
import (
"testing"
"github.com/thrasher-/gocryptotrader/common"
)
const (
defaultPair = "BTCUSD"
defaultPairWDelimiter = "BTC-USD"
)
func TestLower(t *testing.T) {
t.Parallel()
pair := NewPairFromString(defaultPair)
actual := pair.Lower()
expected := NewPairFromString(defaultPair).Lower()
if actual != expected {
t.Errorf("Test failed. Lower(): %s was not equal to expected value: %s",
actual, expected)
}
}
func TestUpper(t *testing.T) {
t.Parallel()
pair := NewPairFromString(defaultPair)
actual := pair.Upper()
expected := NewPairFromString(defaultPair)
if actual != expected {
t.Errorf("Test failed. Upper(): %s was not equal to expected value: %s",
actual, expected)
}
}
func TestPairUnmarshalJSON(t *testing.T) {
var unmarshalHere Pair
configPair := NewPairDelimiter("btc_usd", "_")
encoded, err := common.JSONEncode(configPair)
if err != nil {
t.Fatal("Test Failed - Pair UnmarshalJSON() error", err)
}
err = common.JSONDecode(encoded, &unmarshalHere)
if err != nil {
t.Fatal("Test Failed - Pair UnmarshalJSON() error", err)
}
err = common.JSONDecode(encoded, &unmarshalHere)
if err != nil {
t.Fatal("Test Failed - Pair UnmarshalJSON() error", err)
}
if !unmarshalHere.Equal(configPair) {
t.Errorf("Test Failed - Pairs UnmarshalJSON() error expected %s but received %s",
configPair, unmarshalHere)
}
}
func TestPairMarshalJSON(t *testing.T) {
quickstruct := struct {
Pair Pair `json:"superPair"`
}{
Pair{Base: BTC, Quote: USD, Delimiter: "-"},
}
encoded, err := common.JSONEncode(quickstruct)
if err != nil {
t.Fatal("Test Failed - Pair MarshalJSON() error", err)
}
expected := `{"superPair":"BTC-USD"}`
if string(encoded) != expected {
t.Errorf("Test Failed - Pair MarshalJSON() error expected %s but received %s",
expected, string(encoded))
}
}
func TestIsCryptoPair(t *testing.T) {
if !NewPair(BTC, LTC).IsCryptoPair() {
t.Error("Test Failed. TestIsCryptoPair. Expected true result")
}
if NewPair(BTC, USD).IsCryptoPair() {
t.Error("Test Failed. TestIsCryptoPair. Expected false result")
}
}
func TestIsCryptoFiatPair(t *testing.T) {
if !NewPair(BTC, USD).IsCryptoFiatPair() {
t.Error("Test Failed. TestIsCryptoPair. Expected true result")
}
if NewPair(BTC, LTC).IsCryptoFiatPair() {
t.Error("Test Failed. TestIsCryptoPair. Expected false result")
}
}
func TestIsFiatPair(t *testing.T) {
if !NewPair(AUD, USD).IsFiatPair() {
t.Error("Test Failed. TestIsFiatPair. Expected true result")
}
if NewPair(BTC, AUD).IsFiatPair() {
t.Error("Test Failed. TestIsFiatPair. Expected false result")
}
}
func TestString(t *testing.T) {
t.Parallel()
pair := NewPair(BTC, USD)
actual := defaultPair
expected := pair.String()
if actual != expected {
t.Errorf("Test failed. String(): %s was not equal to expected value: %s",
actual, expected)
}
}
func TestFirstCurrency(t *testing.T) {
t.Parallel()
pair := NewPair(BTC, USD)
actual := pair.Base
expected := BTC
if actual != expected {
t.Errorf(
"Test failed. GetFirstCurrency(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestSecondCurrency(t *testing.T) {
t.Parallel()
pair := NewPair(BTC, USD)
actual := pair.Quote
expected := USD
if actual != expected {
t.Errorf(
"Test failed. GetSecondCurrency(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestPair(t *testing.T) {
t.Parallel()
pair := NewPair(BTC, USD)
actual := pair.String()
expected := defaultPair
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestDisplay(t *testing.T) {
t.Parallel()
pair := NewPairDelimiter(defaultPairWDelimiter, "-")
actual := pair.String()
expected := defaultPairWDelimiter
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
actual = pair.Format("", false).String()
expected = "btcusd"
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
actual = pair.Format("~", true).String()
expected = "BTC~USD"
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestEquall(t *testing.T) {
t.Parallel()
pair := NewPair(BTC, USD)
secondPair := NewPair(BTC, USD)
actual := pair.Equal(secondPair)
expected := true
if actual != expected {
t.Errorf(
"Test failed. Equal(): %v was not equal to expected value: %v",
actual, expected,
)
}
secondPair.Quote = ETH
actual = pair.Equal(secondPair)
expected = false
if actual != expected {
t.Errorf(
"Test failed. Equal(): %v was not equal to expected value: %v",
actual, expected,
)
}
secondPair = NewPair(USD, BTC)
actual = pair.Equal(secondPair)
expected = false
if actual != expected {
t.Errorf(
"Test failed. Equal(): %v was not equal to expected value: %v",
actual, expected,
)
}
}
func TestEqualIncludeReciprocal(t *testing.T) {
t.Parallel()
pair := NewPair(BTC, USD)
secondPair := NewPair(BTC, USD)
actual := pair.EqualIncludeReciprocal(secondPair)
expected := true
if actual != expected {
t.Errorf(
"Test failed. Equal(): %v was not equal to expected value: %v",
actual, expected,
)
}
secondPair.Quote = ETH
actual = pair.EqualIncludeReciprocal(secondPair)
expected = false
if actual != expected {
t.Errorf(
"Test failed. Equal(): %v was not equal to expected value: %v",
actual, expected,
)
}
secondPair = NewPair(USD, BTC)
actual = pair.EqualIncludeReciprocal(secondPair)
expected = true
if actual != expected {
t.Errorf(
"Test failed. Equal(): %v was not equal to expected value: %v",
actual, expected,
)
}
}
func TestSwap(t *testing.T) {
t.Parallel()
pair := NewPair(BTC, USD)
actual := pair.Swap().String()
expected := "USDBTC"
if actual != expected {
t.Errorf(
"Test failed. TestSwap: %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestEmpty(t *testing.T) {
t.Parallel()
pair := NewPair(BTC, USD)
if pair.IsEmpty() {
t.Error("Test failed. Empty() returned true when the pair was initialised")
}
p := NewPair(NewCode(""), NewCode(""))
if !p.IsEmpty() {
t.Error("Test failed. Empty() returned true when the pair wasn't initialised")
}
}
func TestNewPair(t *testing.T) {
t.Parallel()
pair := NewPair(BTC, USD)
actual := pair.String()
expected := defaultPair
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestNewPairWithDelimiter(t *testing.T) {
t.Parallel()
pair := NewPairWithDelimiter("BTC", "USD", "-test-")
actual := pair.String()
expected := "BTC-test-USD"
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
pair = NewPairWithDelimiter("BTC", "USD", "")
actual = pair.String()
expected = defaultPair
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestNewPairDelimiter(t *testing.T) {
t.Parallel()
pair := NewPairDelimiter(defaultPairWDelimiter, "-")
actual := pair.String()
expected := defaultPairWDelimiter
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
actual = pair.Delimiter
expected = "-"
if actual != expected {
t.Errorf(
"Test failed. Delmiter: %s was not equal to expected value: %s",
actual, expected,
)
}
}
// TestNewPairFromIndex returns a CurrencyPair via a currency string and
// specific index
func TestNewPairFromIndex(t *testing.T) {
t.Parallel()
currency := defaultPair
index := "BTC"
pair, err := NewPairFromIndex(currency, index)
if err != nil {
t.Error("test failed - NewPairFromIndex() error", err)
}
pair.Delimiter = "-"
actual := pair.String()
expected := defaultPairWDelimiter
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
currency = "DOGEBTC"
pair, err = NewPairFromIndex(currency, index)
if err != nil {
t.Error("test failed - NewPairFromIndex() error", err)
}
pair.Delimiter = "-"
actual = pair.String()
expected = "DOGE-BTC"
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestNewPairFromString(t *testing.T) {
t.Parallel()
pairStr := defaultPairWDelimiter
pair := NewPairFromString(pairStr)
actual := pair.String()
expected := defaultPairWDelimiter
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
pairStr = defaultPair
pair = NewPairFromString(pairStr)
actual = pair.String()
expected = defaultPair
if actual != expected {
t.Errorf(
"Test failed. Pair(): %s was not equal to expected value: %s",
actual, expected,
)
}
}
func TestContainsCurrency(t *testing.T) {
p := NewPair(BTC, USD)
if !p.ContainsCurrency(BTC) {
t.Error("Test failed. TestContainsCurrency: Expected currency was not found")
}
if p.ContainsCurrency(ETH) {
t.Error("Test failed. TestContainsCurrency: Non-existent currency was found")
}
}
func TestFormatPairs(t *testing.T) {
newP, err := FormatPairs([]string{""}, "-", "")
if err != nil {
t.Error("Test Failed - FormatPairs() error", err)
}
if len(newP) > 0 {
t.Error("Test failed. TestFormatPairs: Empty string returned a valid pair")
}
newP, err = FormatPairs([]string{defaultPairWDelimiter}, "-", "")
if err != nil {
t.Error("Test Failed - FormatPairs() error", err)
}
if newP[0].String() != defaultPairWDelimiter {
t.Error("Test failed. TestFormatPairs: Expected pair was not found")
}
newP, err = FormatPairs([]string{defaultPair}, "", "BTC")
if err != nil {
t.Error("Test Failed - FormatPairs() error", err)
}
if newP[0].String() != defaultPair {
t.Error("Test failed. TestFormatPairs: Expected pair was not found")
}
newP, err = FormatPairs([]string{"ETHUSD"}, "", "")
if err != nil {
t.Error("Test Failed - FormatPairs() error", err)
}
if newP[0].String() != "ETHUSD" {
t.Error("Test failed. TestFormatPairs: Expected pair was not found")
}
}
func TestCopyPairFormat(t *testing.T) {
pairOne := NewPair(BTC, USD)
pairOne.Delimiter = "-"
var pairs []Pair
pairs = append(pairs, pairOne, NewPair(LTC, USD))
testPair := NewPair(BTC, USD)
testPair.Delimiter = "~"
result := CopyPairFormat(testPair, pairs, false)
if result.String() != defaultPairWDelimiter {
t.Error("Test failed. TestCopyPairFormat: Expected pair was not found")
}
result = CopyPairFormat(NewPair(ETH, USD), pairs, true)
if result.String() != "" {
t.Error("Test failed. TestCopyPairFormat: Unexpected non empty pair returned")
}
}
func TestFindPairDifferences(t *testing.T) {
pairList := NewPairsFromStrings([]string{defaultPairWDelimiter, "ETH-USD", "LTC-USD"})
// Test new pair update
newPairs, removedPairs := pairList.FindDifferences(NewPairsFromStrings([]string{"DASH-USD"}))
if len(newPairs) != 1 && len(removedPairs) != 3 {
t.Error("Test failed. TestFindPairDifferences: Unexpected values")
}
// Test that we don't allow empty strings for new pairs
newPairs, removedPairs = pairList.FindDifferences(NewPairsFromStrings([]string{""}))
if len(newPairs) != 0 && len(removedPairs) != 3 {
t.Error("Test failed. TestFindPairDifferences: Unexpected values")
}
// Test that we don't allow empty strings for new pairs
newPairs, removedPairs = NewPairsFromStrings([]string{""}).FindDifferences(pairList)
if len(newPairs) != 3 && len(removedPairs) != 0 {
t.Error("Test failed. TestFindPairDifferences: Unexpected values")
}
// Test that the supplied pair lists are the same, so
// no newPairs or removedPairs
newPairs, removedPairs = pairList.FindDifferences(pairList)
if len(newPairs) != 0 && len(removedPairs) != 0 {
t.Error("Test failed. TestFindPairDifferences: Unexpected values")
}
}
func TestPairsToStringArray(t *testing.T) {
var pairs Pairs
pairs = append(pairs, NewPair(BTC, USD))
expected := []string{defaultPair}
actual := pairs.Strings()
if actual[0] != expected[0] {
t.Error("Test failed. TestPairsToStringArray: Unexpected values")
}
}
func TestRandomPairFromPairs(t *testing.T) {
// Test that an empty pairs array returns an empty currency pair
var emptyPairs Pairs
result := emptyPairs.GetRandomPair()
if !result.IsEmpty() {
t.Error("Test failed. TestRandomPairFromPairs: Unexpected values")
}
// Test that a populated pairs array returns a non-empty currency pair
var pairs Pairs
pairs = append(pairs, NewPair(BTC, USD))
result = pairs.GetRandomPair()
if result.IsEmpty() {
t.Error("Test failed. TestRandomPairFromPairs: Unexpected values")
}
// Test that a populated pairs array over a number of attempts returns ALL
// currency pairs
pairs = append(pairs, NewPair(ETH, USD))
expectedResults := make(map[string]bool)
for i := 0; i < 50; i++ {
p := pairs.GetRandomPair().String()
_, ok := expectedResults[p]
if !ok {
expectedResults[p] = true
}
}
for x := range pairs {
_, ok := expectedResults[pairs[x].String()]
if !ok {
t.Error("Test failed. TestRandomPairFromPairs: Unexpected values")
}
}
}
func TestIsInvalid(t *testing.T) {
p := NewPair(LTC, LTC)
if !p.IsInvalid() {
t.Error("Test Failed - IsInvalid() error expect true but received false")
}
}

158
currency/pairs.go Normal file
View File

@@ -0,0 +1,158 @@
package currency
import (
"math/rand"
"github.com/thrasher-/gocryptotrader/common"
)
// NewPairsFromStrings takes in currency pair strings and returns a currency
// pair list
func NewPairsFromStrings(pairs []string) Pairs {
var ps Pairs
for _, p := range pairs {
if p == "" {
continue
}
ps = append(ps, NewPairFromString(p))
}
return ps
}
// Pairs defines a list of pairs
type Pairs []Pair
// Strings returns a slice of strings referring to each currency pair
func (p Pairs) Strings() []string {
var list []string
for i := range p {
list = append(list, p[i].String())
}
return list
}
// Join returns a comma separated list of currency pairs
func (p Pairs) Join() string {
return common.JoinStrings(p.Strings(), ",")
}
// Format formats the pair list to the exchange format configuration
func (p Pairs) Format(delimiter, index string, uppercase bool) Pairs {
var pairs Pairs
for i := range p {
var formattedPair Pair
formattedPair.Delimiter = delimiter
formattedPair.Base = p[i].Base
formattedPair.Quote = p[i].Quote
if index != "" {
formattedPair.Quote = NewCode(index)
}
if uppercase {
pairs = append(pairs, formattedPair.Upper())
} else {
pairs = append(pairs, formattedPair)
}
}
return pairs
}
// UnmarshalJSON comforms type to the umarshaler interface
func (p *Pairs) UnmarshalJSON(d []byte) error {
var pairs string
err := common.JSONDecode(d, &pairs)
if err != nil {
return err
}
var allThePairs Pairs
for _, data := range common.SplitStrings(pairs, ",") {
allThePairs = append(allThePairs, NewPairFromString(data))
}
*p = allThePairs
return nil
}
// MarshalJSON conforms type to the marshaler interface
func (p Pairs) MarshalJSON() ([]byte, error) {
return common.JSONEncode(p.Join())
}
// Upper returns an upper formatted pair list
func (p Pairs) Upper() Pairs {
var upper Pairs
for i := range p {
upper = append(upper, p[i].Upper())
}
return upper
}
// Slice exposes the underlying type
func (p Pairs) Slice() []Pair {
return p
}
// Contains checks to see if a specified pair exists inside a currency pair
// array
func (p Pairs) Contains(check Pair, exact bool) bool {
for _, pair := range p.Slice() {
if exact {
if pair.Equal(check) {
return true
}
} else {
if pair.EqualIncludeReciprocal(check) {
return true
}
}
}
return false
}
// RemovePairsByFilter checks to see if a pair contains a specific currency
// and removes it from the list of pairs
func (p Pairs) RemovePairsByFilter(filter Code) Pairs {
var pairs Pairs
for _, pair := range p.Slice() {
if pair.ContainsCurrency(filter) {
continue
}
pairs = append(pairs, pair)
}
return pairs
}
// FindDifferences returns pairs which are new or have been removed
func (p Pairs) FindDifferences(pairs Pairs) (newPairs, removedPairs Pairs) {
for x := range pairs {
if pairs[x].String() == "" {
continue
}
if !p.Contains(pairs[x], true) {
newPairs = append(newPairs, pairs[x])
}
}
for _, oldPair := range p {
if oldPair.String() == "" {
continue
}
if !pairs.Contains(oldPair, true) {
removedPairs = append(removedPairs, oldPair)
}
}
return
}
// GetRandomPair returns a random pair from a list of pairs
func (p Pairs) GetRandomPair() Pair {
pairsLen := len(p)
if pairsLen == 0 {
return Pair{Base: NewCode(""), Quote: NewCode("")}
}
return p[rand.Intn(pairsLen)]
}

133
currency/pairs_test.go Normal file
View File

@@ -0,0 +1,133 @@
package currency
import (
"testing"
"github.com/thrasher-/gocryptotrader/common"
)
func TestPairsUpper(t *testing.T) {
pairs := NewPairsFromStrings([]string{"btc_usd", "btc_aud", "btc_ltc"})
expected := "BTC_USD,BTC_AUD,BTC_LTC"
if pairs.Upper().Join() != expected {
t.Errorf("Test Failed - Pairs Join() error expected %s but received %s",
expected, pairs.Join())
}
}
func TestPairsString(t *testing.T) {
pairs := NewPairsFromStrings([]string{"btc_usd", "btc_aud", "btc_ltc"})
expected := []string{"btc_usd", "btc_aud", "btc_ltc"}
for i, p := range pairs {
if p.String() != expected[i] {
t.Errorf("Test Failed - Pairs String() error expected %s but received %s",
expected, p.String())
}
}
}
func TestPairsJoin(t *testing.T) {
pairs := NewPairsFromStrings([]string{"btc_usd", "btc_aud", "btc_ltc"})
expected := "btc_usd,btc_aud,btc_ltc"
if pairs.Join() != expected {
t.Errorf("Test Failed - Pairs Join() error expected %s but received %s",
expected, pairs.Join())
}
}
func TestPairsFormat(t *testing.T) {
pairs := NewPairsFromStrings([]string{"btc_usd", "btc_aud", "btc_ltc"})
expected := "BTC-USD,BTC-AUD,BTC-LTC"
if pairs.Format("-", "", true).Join() != expected {
t.Errorf("Test Failed - Pairs Join() error expected %s but received %s",
expected, pairs.Format("-", "", true).Join())
}
expected = "btc:usd,btc:aud,btc:ltc"
if pairs.Format(":", "", false).Join() != expected {
t.Errorf("Test Failed - Pairs Join() error expected %s but received %s",
expected, pairs.Format("-", "", true).Join())
}
expected = "btc:krw,btc:krw,btc:krw"
if pairs.Format(":", "krw", false).Join() != expected {
t.Errorf("Test Failed - Pairs Join() error expected %s but received %s",
expected, pairs.Format("-", "", true).Join())
}
}
func TestPairsUnmarshalJSON(t *testing.T) {
var unmarshalHere Pairs
configPairs := "btc_usd,btc_aud,btc_ltc"
encoded, err := common.JSONEncode(configPairs)
if err != nil {
t.Fatal("Test Failed - Pairs UnmarshalJSON() error", err)
}
err = common.JSONDecode(encoded, &unmarshalHere)
if err != nil {
t.Fatal("Test Failed - Pairs UnmarshalJSON() error", err)
}
err = common.JSONDecode(encoded, &unmarshalHere)
if err != nil {
t.Fatal("Test Failed - Pairs UnmarshalJSON() error", err)
}
if unmarshalHere.Join() != configPairs {
t.Errorf("Test Failed - Pairs UnmarshalJSON() error expected %s but received %s",
configPairs, unmarshalHere.Join())
}
}
func TestPairsMarshalJSON(t *testing.T) {
quickstruct := struct {
Pairs Pairs `json:"soManyPairs"`
}{
Pairs: NewPairsFromStrings([]string{"btc_usd", "btc_aud", "btc_ltc"}),
}
encoded, err := common.JSONEncode(quickstruct)
if err != nil {
t.Fatal("Test Failed - Pairs MarshalJSON() error", err)
}
expected := `{"soManyPairs":"btc_usd,btc_aud,btc_ltc"}`
if string(encoded) != expected {
t.Errorf("Test Failed - Pairs MarshalJSON() error expected %s but received %s",
expected, string(encoded))
}
}
func TestRemovePairsByFilter(t *testing.T) {
var pairs = Pairs{
NewPair(BTC, USD),
NewPair(LTC, USD),
NewPair(LTC, USDT),
}
pairs = pairs.RemovePairsByFilter(USDT)
if pairs.Contains(NewPair(LTC, USDT), true) {
t.Error("Test failed. TestRemovePairsByFilter unexpected result")
}
}
func TestContains(t *testing.T) {
var pairs = Pairs{
NewPair(BTC, USD),
NewPair(LTC, USD),
}
if !pairs.Contains(NewPair(BTC, USD), true) {
t.Errorf("Test failed. TestContains: Expected pair was not found")
}
if pairs.Contains(NewPair(ETH, USD), false) {
t.Errorf("Test failed. TestContains: Non-existent pair was found")
}
}

754
currency/storage.go Normal file
View File

@@ -0,0 +1,754 @@
package currency
import (
"encoding/json"
"errors"
"fmt"
"sync"
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/coinmarketcap"
"github.com/thrasher-/gocryptotrader/currency/forexprovider"
"github.com/thrasher-/gocryptotrader/currency/forexprovider/base"
log "github.com/thrasher-/gocryptotrader/logger"
)
// CurrencyFileUpdateDelay defines the rate at which the currency.json file is
// updated
const (
DefaultCurrencyFileDelay = 168 * time.Hour
DefaultForeignExchangeDelay = 1 * time.Minute
)
func init() {
storage.SetDefaults()
}
// storage is an overarching type that keeps track of and updates currency,
// currency exchange rates and pairs
var storage Storage
// Storage contains the loaded storage currencies supported on available crypto
// or fiat marketplaces
// NOTE: All internal currencies are upper case
type Storage struct {
// FiatCurrencies defines the running fiat currencies in the currency
// storage
fiatCurrencies Currencies
// Cryptocurrencies defines the running cryptocurrencies in the currency
// storage
cryptocurrencies Currencies
// CurrencyCodes is a full basket of currencies either crypto, fiat, ico or
// contract being tracked by the currency storage system
currencyCodes BaseCodes
// Main converting currency
baseCurrency Code
// FXRates defines a protected conversion rate map
fxRates ConversionRates
// DefaultBaseCurrency is the base currency used for conversion
defaultBaseCurrency Code
// DefaultFiatCurrencies has the default minimum of FIAT values
defaultFiatCurrencies Currencies
// DefaultCryptoCurrencies has the default minimum of crytpocurrency values
defaultCryptoCurrencies Currencies
// FiatExchangeMarkets defines an interface to access FX data for fiat
// currency rates
fiatExchangeMarkets *forexprovider.ForexProviders
// CurrencyAnalysis defines a full market analysis suite to receieve and
// define different fiat currencies, cryptocurrencies and markets
currencyAnalysis *coinmarketcap.Coinmarketcap
// Path defines the main folder to dump and find currency JSON
path string
// Update delay variables
currencyFileUpdateDelay time.Duration
foreignExchangeUpdateDelay time.Duration
mtx sync.Mutex
wg sync.WaitGroup
shutdownC chan struct{}
updaterRunning bool
Verbose bool
}
// SetDefaults sets storage defaults for basic package functionality
func (s *Storage) SetDefaults() {
s.defaultBaseCurrency = USD
s.baseCurrency = s.defaultBaseCurrency
s.SetDefaultFiatCurrencies(USD, AUD, EUR, CNY)
s.SetDefaultCryptocurrencies(BTC, LTC, ETH, DOGE, DASH, XRP, XMR)
s.SetupConversionRates()
s.fiatExchangeMarkets = forexprovider.NewDefaultFXProvider()
}
// RunUpdater runs the foreign exchange updater service. This will set up a JSON
// dump file and keep foreign exchange rates updated as fast as possible without
// triggering rate limiters, it will also run a full cryptocurrency check
// through coin market cap and expose analytics for exchange services
func (s *Storage) RunUpdater(overrides BotOverrides, settings MainConfiguration, filePath string, verbose bool) error {
s.mtx.Lock()
if !settings.Cryptocurrencies.HasData() {
s.mtx.Unlock()
return errors.New("currency storage error, no cryptocurrencies loaded")
}
s.cryptocurrencies = settings.Cryptocurrencies
if settings.FiatDisplayCurrency.IsEmpty() {
s.mtx.Unlock()
return errors.New("currency storage error, no fiat display currency set in config")
}
s.baseCurrency = settings.FiatDisplayCurrency
log.Debugf("Fiat display currency: %s.", s.baseCurrency)
if settings.CryptocurrencyProvider.Enabled {
log.Debugf("Setting up currency analysis system with Coinmarketcap...")
c := &coinmarketcap.Coinmarketcap{}
c.SetDefaults()
c.Setup(coinmarketcap.Settings{
Name: settings.CryptocurrencyProvider.Name,
Enabled: true,
AccountPlan: settings.CryptocurrencyProvider.AccountPlan,
APIkey: settings.CryptocurrencyProvider.APIkey,
Verbose: settings.CryptocurrencyProvider.Verbose,
})
s.currencyAnalysis = c
}
if filePath == "" {
s.mtx.Unlock()
return errors.New("currency package runUpdater error filepath not set")
}
s.path = filePath + common.GetOSPathSlash() + "currency.json"
if settings.CurrencyDelay.Nanoseconds() == 0 {
s.currencyFileUpdateDelay = DefaultCurrencyFileDelay
} else {
s.currencyFileUpdateDelay = settings.CurrencyDelay
}
if settings.FxRateDelay.Nanoseconds() == 0 {
s.foreignExchangeUpdateDelay = DefaultForeignExchangeDelay
} else {
s.foreignExchangeUpdateDelay = settings.FxRateDelay
}
var fxSettings []base.Settings
for i := range settings.ForexProviders {
switch settings.ForexProviders[i].Name {
case "CurrencyConverter":
if overrides.FxCurrencyConverter ||
settings.ForexProviders[i].Enabled {
settings.ForexProviders[i].Enabled = true
fxSettings = append(fxSettings,
base.Settings(settings.ForexProviders[i]))
}
case "CurrencyLayer":
if overrides.FxCurrencyLayer || settings.ForexProviders[i].Enabled {
settings.ForexProviders[i].Enabled = true
fxSettings = append(fxSettings,
base.Settings(settings.ForexProviders[i]))
}
case "Fixer":
if overrides.FxFixer || settings.ForexProviders[i].Enabled {
settings.ForexProviders[i].Enabled = true
fxSettings = append(fxSettings,
base.Settings(settings.ForexProviders[i]))
}
case "OpenExchangeRates":
if overrides.FxOpenExchangeRates ||
settings.ForexProviders[i].Enabled {
settings.ForexProviders[i].Enabled = true
fxSettings = append(fxSettings,
base.Settings(settings.ForexProviders[i]))
}
case "ExchangeRates":
// TODO ADD OVERRIDE
if settings.ForexProviders[i].Enabled {
settings.ForexProviders[i].Enabled = true
fxSettings = append(fxSettings,
base.Settings(settings.ForexProviders[i]))
}
}
}
if len(fxSettings) != 0 {
var err error
s.fiatExchangeMarkets, err = forexprovider.StartFXService(fxSettings)
if err != nil {
s.mtx.Unlock()
return err
}
log.Debugf("Primary foreign exchange conversion provider %s enabled",
s.fiatExchangeMarkets.Primary.Provider.GetName())
for i := range s.fiatExchangeMarkets.Support {
log.Debugf("Support forex conversion provider %s enabled",
s.fiatExchangeMarkets.Support[i].Provider.GetName())
}
// Mutex present in this go routine to lock down retrieving rate data
// until this system initially updates
go s.ForeignExchangeUpdater()
} else {
log.Warnf("No foreign exchange providers enabled in config.json")
s.mtx.Unlock()
}
return nil
}
// SetupConversionRates sets default conversion rate values
func (s *Storage) SetupConversionRates() {
s.fxRates = ConversionRates{
m: make(map[*Item]map[*Item]*float64),
}
}
// SetDefaultFiatCurrencies assigns the default fiat currency list and adds it
// to the running list
func (s *Storage) SetDefaultFiatCurrencies(c ...Code) {
for _, currency := range c {
s.defaultFiatCurrencies = append(s.defaultFiatCurrencies, currency)
s.fiatCurrencies = append(s.fiatCurrencies, currency)
}
}
// SetDefaultCryptocurrencies assigns the default cryptocurrency list and adds
// it to the running list
func (s *Storage) SetDefaultCryptocurrencies(c ...Code) {
for _, currency := range c {
s.defaultCryptoCurrencies = append(s.defaultCryptoCurrencies, currency)
s.cryptocurrencies = append(s.cryptocurrencies, currency)
}
}
// SetupForexProviders sets up a new instance of the forex providers
func (s *Storage) SetupForexProviders(setting ...base.Settings) error {
addr, err := forexprovider.StartFXService(setting)
if err != nil {
return err
}
s.fiatExchangeMarkets = addr
return nil
}
// ForeignExchangeUpdater is a routine that seeds foreign exchange rate and keeps
// updated as fast as possible
func (s *Storage) ForeignExchangeUpdater() {
log.Debugf("Foreign exchange updater started, seeding FX rate list..")
s.wg.Add(1)
defer s.wg.Done()
err := s.SeedCurrencyAnalysisData()
if err != nil {
log.Error(err)
}
err = s.SeedForeignExchangeRates()
if err != nil {
log.Error(err)
}
// Unlock main rate retrieval mutex so all routines waiting can get access
// to data
s.mtx.Unlock()
// Set tickers to client defined rates or defaults
SeedForeignExchangeTick := time.NewTicker(s.foreignExchangeUpdateDelay)
SeedCurrencyAnalysisTick := time.NewTicker(s.currencyFileUpdateDelay)
for {
select {
case <-s.shutdownC:
return
case <-SeedForeignExchangeTick.C:
err := s.SeedForeignExchangeRates()
if err != nil {
log.Error(err)
}
case <-SeedCurrencyAnalysisTick.C:
err := s.SeedCurrencyAnalysisData()
if err != nil {
log.Error(err)
}
}
}
}
// SeedCurrencyAnalysisData sets a new instance of a coinmarketcap data.
func (s *Storage) SeedCurrencyAnalysisData() error {
b, err := common.ReadFile(s.path)
if err != nil {
err = s.FetchCurrencyAnalysisData()
if err != nil {
return s.WriteCurrencyDataToFile(s.path, false)
}
return s.WriteCurrencyDataToFile(s.path, true)
}
var fromFile File
err = common.JSONDecode(b, &fromFile)
if err != nil {
return err
}
err = s.LoadFileCurrencyData(fromFile)
if err != nil {
return err
}
// Based on update delay update the file
if fromFile.LastMainUpdate.After(fromFile.LastMainUpdate.Add(s.currencyFileUpdateDelay)) ||
fromFile.LastMainUpdate.IsZero() {
err = s.FetchCurrencyAnalysisData()
if err != nil {
return s.WriteCurrencyDataToFile(s.path, false)
}
return s.WriteCurrencyDataToFile(s.path, true)
}
return nil
}
// FetchCurrencyAnalysisData fetches a new fresh batch of currency data and
// loads it into memory
func (s *Storage) FetchCurrencyAnalysisData() error {
if s.currencyAnalysis == nil {
log.Warn("Currency analysis system offline please set api keys for coinmarketcap")
return errors.New("currency analysis system offline")
}
return s.UpdateCurrencies()
}
// WriteCurrencyDataToFile writes the full currency data to a designated file
func (s *Storage) WriteCurrencyDataToFile(path string, mainUpdate bool) error {
data, err := s.currencyCodes.GetFullCurrencyData()
if err != nil {
return err
}
if mainUpdate {
t := time.Now()
data.LastMainUpdate = t
s.currencyCodes.LastMainUpdate = t
}
var encoded []byte
encoded, err = json.MarshalIndent(data, "", " ")
if err != nil {
return err
}
return common.WriteFile(path, encoded)
}
// LoadFileCurrencyData loads currencies into the currency codes
func (s *Storage) LoadFileCurrencyData(f File) error {
for _, contract := range f.Contracts {
err := s.currencyCodes.LoadItem(contract)
if err != nil {
return err
}
}
for _, crypto := range f.Cryptocurrency {
err := s.currencyCodes.LoadItem(crypto)
if err != nil {
return err
}
}
for _, fiat := range f.FiatCurrency {
err := s.currencyCodes.LoadItem(fiat)
if err != nil {
return err
}
}
for _, token := range f.Token {
err := s.currencyCodes.LoadItem(token)
if err != nil {
return err
}
}
for _, unset := range f.UnsetCurrency {
err := s.currencyCodes.LoadItem(unset)
if err != nil {
return err
}
}
s.currencyCodes.LastMainUpdate = f.LastMainUpdate
return nil
}
// UpdateCurrencies updates currency roll and information using coin market cap
func (s *Storage) UpdateCurrencies() error {
m, err := s.currencyAnalysis.GetCryptocurrencyIDMap()
if err != nil {
return err
}
for x := range m {
if m[x].IsActive != 1 {
continue
}
if m[x].Platform.Symbol != "" {
err := s.currencyCodes.UpdateToken(m[x].Name,
m[x].Symbol,
m[x].Platform.Symbol,
m[x].ID)
if err != nil {
return err
}
continue
}
err := s.currencyCodes.UpdateCryptocurrency(m[x].Name,
m[x].Symbol,
m[x].ID)
if err != nil {
return err
}
}
return nil
}
// SeedForeignExchangeRatesByCurrencies seeds the foreign exchange rates by
// currencies supplied
func (s *Storage) SeedForeignExchangeRatesByCurrencies(c Currencies) error {
s.fxRates.mtx.Lock()
defer s.fxRates.mtx.Unlock()
rates, err := s.fiatExchangeMarkets.GetCurrencyData(s.baseCurrency.String(),
c.Strings())
if err != nil {
return err
}
return s.updateExchangeRates(rates)
}
// SeedForeignExchangeRate returns a singular exchange rate
func (s *Storage) SeedForeignExchangeRate(from, to Code) (map[string]float64, error) {
return s.fiatExchangeMarkets.GetCurrencyData(from.String(),
[]string{to.String()})
}
// GetDefaultForeignExchangeRates returns foreign exchange rates based off
// default fiat currencies.
func (s *Storage) GetDefaultForeignExchangeRates() (Conversions, error) {
if !s.updaterRunning {
err := s.SeedDefaultForeignExchangeRates()
if err != nil {
return nil, err
}
}
return s.fxRates.GetFullRates(), nil
}
// SeedDefaultForeignExchangeRates seeds the default foreign exchange rates
func (s *Storage) SeedDefaultForeignExchangeRates() error {
s.fxRates.mtx.Lock()
defer s.fxRates.mtx.Unlock()
rates, err := s.fiatExchangeMarkets.GetCurrencyData(
s.defaultBaseCurrency.String(),
s.defaultFiatCurrencies.Strings())
if err != nil {
return err
}
return s.updateExchangeRates(rates)
}
// GetExchangeRates returns storage seeded exchange rates
func (s *Storage) GetExchangeRates() (Conversions, error) {
if !s.updaterRunning {
err := s.SeedForeignExchangeRates()
if err != nil {
return nil, err
}
}
return s.fxRates.GetFullRates(), nil
}
// SeedForeignExchangeRates seeds the foreign exchange rates from storage config
// currencies
func (s *Storage) SeedForeignExchangeRates() error {
s.fxRates.mtx.Lock()
defer s.fxRates.mtx.Unlock()
rates, err := s.fiatExchangeMarkets.GetCurrencyData(
s.baseCurrency.String(),
s.fiatCurrencies.Strings())
if err != nil {
return err
}
return s.updateExchangeRates(rates)
}
// UpdateForeignExchangeRates sets exchange rates on the FX map
func (s *Storage) updateExchangeRates(m map[string]float64) error {
err := s.fxRates.Update(m)
if err != nil {
return err
}
if s.path != "" {
return s.WriteCurrencyDataToFile(s.path, false)
}
return nil
}
// SetupCryptoProvider sets congiguration parameters and starts a new instance
// of the currency analyser
func (s *Storage) SetupCryptoProvider(settings coinmarketcap.Settings) error {
if settings.APIkey == "" ||
settings.APIkey == "key" ||
settings.AccountPlan == "" ||
settings.AccountPlan == "accountPlan" {
return errors.New("currencyprovider error api key or plan not set in config.json")
}
s.currencyAnalysis = new(coinmarketcap.Coinmarketcap)
s.currencyAnalysis.SetDefaults()
s.currencyAnalysis.Setup(settings)
return nil
}
// GetTotalMarketCryptocurrencies returns the total seeded market
// cryptocurrencies
func (s *Storage) GetTotalMarketCryptocurrencies() (Currencies, error) {
if !s.currencyCodes.HasData() {
return nil, errors.New("market currency codes not populated")
}
return s.currencyCodes.GetCurrencies(), nil
}
// IsDefaultCurrency returns if a currency is a default currency
func (s *Storage) IsDefaultCurrency(c Code) bool {
t, _ := GetTranslation(c)
for _, d := range s.defaultFiatCurrencies {
if d.Match(c) || d.Match(t) {
return true
}
}
return false
}
// IsDefaultCryptocurrency returns if a cryptocurrency is a default
// cryptocurrency
func (s *Storage) IsDefaultCryptocurrency(c Code) bool {
t, _ := GetTranslation(c)
for _, d := range s.defaultCryptoCurrencies {
if d.Match(c) || d.Match(t) {
return true
}
}
return false
}
// IsFiatCurrency returns if a currency is part of the enabled fiat currency
// list
func (s *Storage) IsFiatCurrency(c Code) bool {
if c.Item.Role != Unset {
return c.Item.Role == Fiat
}
t, _ := GetTranslation(c)
for _, d := range s.fiatCurrencies {
if d.Match(c) || d.Match(t) {
return true
}
}
return false
}
// IsCryptocurrency returns if a cryptocurrency is part of the enabled
// cryptocurrency list
func (s *Storage) IsCryptocurrency(c Code) bool {
if c.Item.Role != Unset {
return c.Item.Role == Cryptocurrency
}
t, _ := GetTranslation(c)
for _, d := range s.cryptocurrencies {
if d.Match(c) || d.Match(t) {
return true
}
}
return false
}
// ValidateCode validates string against currency list and returns a currency
// code
func (s *Storage) ValidateCode(newCode string) Code {
return s.currencyCodes.Register(newCode)
}
// ValidateFiatCode validates a fiat currency string and returns a currency
// code
func (s *Storage) ValidateFiatCode(newCode string) (Code, error) {
c, err := s.currencyCodes.RegisterFiat(newCode)
if err != nil {
return c, err
}
if !s.fiatCurrencies.Contains(c) {
s.fiatCurrencies = append(s.fiatCurrencies, c)
}
return c, nil
}
// ValidateCryptoCode validates a cryptocurrency string and returns a currency
// code
// TODO: Update and add in RegisterCrypto member func
func (s *Storage) ValidateCryptoCode(newCode string) Code {
c := s.currencyCodes.Register(newCode)
if !s.cryptocurrencies.Contains(c) {
s.cryptocurrencies = append(s.cryptocurrencies, c)
}
return c
}
// UpdateBaseCurrency changes base currency
func (s *Storage) UpdateBaseCurrency(c Code) error {
if c.IsFiatCurrency() {
s.baseCurrency = c
return nil
}
return fmt.Errorf("currency %s not fiat failed to set currency", c)
}
// GetCryptocurrencies returns the cryptocurrency list
func (s *Storage) GetCryptocurrencies() Currencies {
return s.cryptocurrencies
}
// GetDefaultCryptocurrencies returns a list of default cryptocurrencies
func (s *Storage) GetDefaultCryptocurrencies() Currencies {
return s.defaultCryptoCurrencies
}
// GetFiatCurrencies returns the fiat currencies list
func (s *Storage) GetFiatCurrencies() Currencies {
return s.fiatCurrencies
}
// GetDefaultFiatCurrencies returns the default fiat currencies list
func (s *Storage) GetDefaultFiatCurrencies() Currencies {
return s.defaultFiatCurrencies
}
// GetDefaultBaseCurrency returns the default base currency
func (s *Storage) GetDefaultBaseCurrency() Code {
return s.defaultBaseCurrency
}
// GetBaseCurrency returns the current storage base currency
func (s *Storage) GetBaseCurrency() Code {
return s.baseCurrency
}
// UpdateEnabledCryptoCurrencies appends new cryptocurrencies to the enabled
// currency list
func (s *Storage) UpdateEnabledCryptoCurrencies(c Currencies) {
for _, i := range c {
if !s.cryptocurrencies.Contains(i) {
s.cryptocurrencies = append(s.cryptocurrencies, i)
}
}
}
// UpdateEnabledFiatCurrencies appends new fiat currencies to the enabled
// currency list
func (s *Storage) UpdateEnabledFiatCurrencies(c Currencies) {
for _, i := range c {
if !s.fiatCurrencies.Contains(i) && !s.cryptocurrencies.Contains(i) {
s.fiatCurrencies = append(s.fiatCurrencies, i)
}
}
}
// ConvertCurrency for example converts $1 USD to the equivalent Japanese Yen
// or vice versa.
func (s *Storage) ConvertCurrency(amount float64, from, to Code) (float64, error) {
s.mtx.Lock()
defer s.mtx.Unlock()
if !s.fxRates.HasData() {
err := s.SeedDefaultForeignExchangeRates()
if err != nil {
return 0, err
}
}
r, err := s.fxRates.GetRate(from, to)
if err != nil {
return 0, err
}
return r * amount, nil
}
// GetStorageRate returns the rate of the conversion value
func (s *Storage) GetStorageRate(from, to Code) (float64, error) {
s.mtx.Lock()
defer s.mtx.Unlock()
if !s.fxRates.HasData() {
err := s.SeedDefaultForeignExchangeRates()
if err != nil {
return 0, err
}
}
return s.fxRates.GetRate(from, to)
}
// NewConversion returns a new conversion object that has a pointer to a related
// rate with its inversion.
func (s *Storage) NewConversion(from, to Code) (Conversion, error) {
s.mtx.Lock()
defer s.mtx.Unlock()
if !s.fxRates.HasData() {
err := storage.SeedDefaultForeignExchangeRates()
if err != nil {
return Conversion{}, err
}
}
return s.fxRates.Register(from, to)
}
// IsVerbose returns if the storage is in verbose mode
func (s *Storage) IsVerbose() bool {
return s.Verbose
}

27
currency/storage_test.go Normal file
View File

@@ -0,0 +1,27 @@
package currency
import "testing"
func TestRunUpdater(t *testing.T) {
var newStorage Storage
err := newStorage.RunUpdater(BotOverrides{}, MainConfiguration{}, "", false)
if err == nil {
t.Fatal("Test Failed storage RunUpdater() error cannot be nil")
}
mainConfig := MainConfiguration{
Cryptocurrencies: NewCurrenciesFromStringArray([]string{"BTC"}),
FiatDisplayCurrency: USD,
}
err = newStorage.RunUpdater(BotOverrides{}, mainConfig, "", false)
if err == nil {
t.Fatal("Test Failed storage RunUpdater() error cannot be nil")
}
err = newStorage.RunUpdater(BotOverrides{}, mainConfig, "/bla", false)
if err != nil {
t.Fatal("Test Failed storage RunUpdater() error", err)
}
}

127
currency/symbol.go Normal file
View File

@@ -0,0 +1,127 @@
package currency
import "errors"
// symbols map holds the currency name and symbol mappings
var symbols = map[*Item]string{
ALL.Item: "Lek",
AFN.Item: "؋",
ARS.Item: "$",
AWG.Item: "ƒ",
AUD.Item: "$",
AZN.Item: "ман",
BSD.Item: "$",
BBD.Item: "$",
BYN.Item: "Br",
BZD.Item: "BZ$",
BMD.Item: "$",
BOB.Item: "$b",
BAM.Item: "KM",
BWP.Item: "P",
BGN.Item: "лв",
BRL.Item: "R$",
BND.Item: "$",
KHR.Item: "៛",
CAD.Item: "$",
KYD.Item: "$",
CLP.Item: "$",
CNY.Item: "¥",
COP.Item: "$",
CRC.Item: "₡",
HRK.Item: "kn",
CUP.Item: "₱",
CZK.Item: "Kč",
DKK.Item: "kr",
DOP.Item: "RD$",
XCD.Item: "$",
EGP.Item: "£",
SVC.Item: "$",
EUR.Item: "€",
FKP.Item: "£",
FJD.Item: "$",
GHS.Item: "¢",
GIP.Item: "£",
GTQ.Item: "Q",
GGP.Item: "£",
GYD.Item: "$",
HNL.Item: "L",
HKD.Item: "$",
HUF.Item: "Ft",
ISK.Item: "kr",
INR.Item: "₹",
IDR.Item: "Rp",
IRR.Item: "﷼",
IMP.Item: "£",
ILS.Item: "₪",
JMD.Item: "J$",
JPY.Item: "¥",
JEP.Item: "£",
KZT.Item: "лв",
KPW.Item: "₩",
KRW.Item: "₩",
KGS.Item: "лв",
LAK.Item: "₭",
LBP.Item: "£",
LRD.Item: "$",
MKD.Item: "ден",
MYR.Item: "RM",
MUR.Item: "₨",
MXN.Item: "$",
MNT.Item: "₮",
MZN.Item: "MT",
NAD.Item: "$",
NPR.Item: "₨",
ANG.Item: "ƒ",
NZD.Item: "$",
NIO.Item: "C$",
NGN.Item: "₦",
NOK.Item: "kr",
OMR.Item: "﷼",
PKR.Item: "₨",
PAB.Item: "B/.",
PYG.Item: "Gs",
PEN.Item: "S/.",
PHP.Item: "₱",
PLN.Item: "zł",
QAR.Item: "﷼",
RON.Item: "lei",
RUB.Item: "₽",
RUR.Item: "₽",
SHP.Item: "£",
SAR.Item: "﷼",
RSD.Item: "Дин.",
SCR.Item: "₨",
SGD.Item: "$",
SBD.Item: "$",
SOS.Item: "S",
ZAR.Item: "R",
LKR.Item: "₨",
SEK.Item: "kr",
CHF.Item: "CHF",
SRD.Item: "$",
SYP.Item: "£",
TWD.Item: "NT$",
THB.Item: "฿",
TTD.Item: "TT$",
TRY.Item: "₺",
TVD.Item: "$",
UAH.Item: "₴",
GBP.Item: "£",
USD.Item: "$",
USDT.Item: "$",
UYU.Item: "$U",
UZS.Item: "лв",
VEF.Item: "Bs",
VND.Item: "₫",
YER.Item: "﷼",
ZWD.Item: "Z$",
}
// GetSymbolByCurrencyName returns a currency symbol
func GetSymbolByCurrencyName(currency Code) (string, error) {
result, ok := symbols[currency.Item]
if !ok {
return "", errors.New("currency symbol not found")
}
return result, nil
}

View File

@@ -1,56 +0,0 @@
# GoCryptoTrader package Symbol
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
[![Build Status](https://travis-ci.org/thrasher-/gocryptotrader.svg?branch=master)](https://travis-ci.org/thrasher-/gocryptotrader)
[![Software License](https://img.shields.io/badge/License-MIT-orange.svg?style=flat-square)](https://github.com/thrasher-/gocryptotrader/blob/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/thrasher-/gocryptotrader?status.svg)](https://godoc.org/github.com/thrasher-/gocryptotrader/currency/symbol)
[![Coverage Status](http://codecov.io/github/thrasher-/gocryptotrader/coverage.svg?branch=master)](http://codecov.io/github/thrasher-/gocryptotrader?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/thrasher-/gocryptotrader)](https://goreportcard.com/report/github.com/thrasher-/gocryptotrader)
This symbol package is part of the GoCryptoTrader codebase.
## This is still in active development
You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/enQtNTQ5NDAxMjA2Mjc5LTQyYjIxNGVhMWU5MDZlOGYzMmE0NTJmM2MzYWY5NGMzMmM4MzUwNTBjZTEzNjIwODM5NDcxODQwZDljMGQyNGY)
## Current Features for symbol
+ This package services the currency package by providing symbol mapping.
+ Example below:
```go
import "github.com/thrasher-/gocryptotrader/currency/symbol"
// Get the string of the symbol by the currency
chineseYen := "CNY"
symbol := symbol.GetSymbolByCurrencyName(chineseYen)
// symbol == "¥"
```
### Please click GoDocs chevron above to view current GoDoc information for this package
## Contribution
Please feel free to submit any pull requests or suggest any desired features to be added.
When submitting a PR, please abide by our coding guidelines:
+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
+ Code must adhere to our [coding style](https://github.com/thrasher-/gocryptotrader/blob/master/doc/coding_style.md).
+ Pull requests need to be based on and opened against the `master` branch.
## Donations
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,10 @@
package symbol
package currency
import "testing"
func TestGetSymbolByCurrencyName(t *testing.T) {
expected := "₩"
actual, err := GetSymbolByCurrencyName("KPW")
actual, err := GetSymbolByCurrencyName(KPW)
if err != nil {
t.Errorf("Test failed. TestGetSymbolByCurrencyName error: %s", err)
}
@@ -13,7 +13,7 @@ func TestGetSymbolByCurrencyName(t *testing.T) {
t.Errorf("Test failed. TestGetSymbolByCurrencyName differing values")
}
_, err = GetSymbolByCurrencyName("BLAH")
_, err = GetSymbolByCurrencyName(Code{})
if err == nil {
t.Errorf("Test failed. TestGetSymbolByCurrencyNam returned nil on non-existent currency")
}

22
currency/translation.go Normal file
View File

@@ -0,0 +1,22 @@
package currency
var translations = map[Code]Code{
BTC: XBT,
ETH: XETH,
DOGE: XDG,
USD: USDT,
XBT: BTC,
XETH: ETH,
XDG: DOGE,
USDT: USD,
}
// GetTranslation returns similar strings for a particular currency if not found
// returns the code back
func GetTranslation(currency Code) (Code, bool) {
val, ok := translations[currency]
if !ok {
return currency, ok
}
return val, ok
}

View File

@@ -1,55 +0,0 @@
# GoCryptoTrader package Translation
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
[![Build Status](https://travis-ci.org/thrasher-/gocryptotrader.svg?branch=master)](https://travis-ci.org/thrasher-/gocryptotrader)
[![Software License](https://img.shields.io/badge/License-MIT-orange.svg?style=flat-square)](https://github.com/thrasher-/gocryptotrader/blob/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/thrasher-/gocryptotrader?status.svg)](https://godoc.org/github.com/thrasher-/gocryptotrader/currency/translation)
[![Coverage Status](http://codecov.io/github/thrasher-/gocryptotrader/coverage.svg?branch=master)](http://codecov.io/github/thrasher-/gocryptotrader?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/thrasher-/gocryptotrader)](https://goreportcard.com/report/github.com/thrasher-/gocryptotrader)
This translation package is part of the GoCryptoTrader codebase.
## This is still in active development
You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/enQtNTQ5NDAxMjA2Mjc5LTQyYjIxNGVhMWU5MDZlOGYzMmE0NTJmM2MzYWY5NGMzMmM4MzUwNTBjZTEzNjIwODM5NDcxODQwZDljMGQyNGY)
## Current Features for translation
+ This package services the currency package with translation functions.
+ Example below:
```go
import "github.com/thrasher-/gocryptotrader/currency/translation"
// Is translatable
b := translation.HasTranslation("BTC")
// b == true; translation = XBT
```
### Please click GoDocs chevron above to view current GoDoc information for this package
## Contribution
Please feel free to submit any pull requests or suggest any desired features to be added.
When submitting a PR, please abide by our coding guidelines:
+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
+ Code must adhere to our [coding style](https://github.com/thrasher-/gocryptotrader/blob/master/doc/coding_style.md).
+ Pull requests need to be based on and opened against the `master` branch.
## Donations
<img src="https://github.com/thrasher-/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***

View File

@@ -1,34 +0,0 @@
package translation
import (
"errors"
"github.com/thrasher-/gocryptotrader/currency/pair"
)
var translations = map[pair.CurrencyItem]pair.CurrencyItem{
"BTC": "XBT",
"ETH": "XETH",
"DOGE": "XDG",
"USD": "USDT",
}
// GetTranslation returns similar strings for a particular currency
func GetTranslation(currency pair.CurrencyItem) (pair.CurrencyItem, error) {
for k, v := range translations {
if k == currency {
return v, nil
}
if v == currency {
return k, nil
}
}
return "", errors.New("no translation found for specified currency")
}
// HasTranslation returns whether or not a particular currency has a translation
func HasTranslation(currency pair.CurrencyItem) bool {
_, err := GetTranslation(currency)
return (err == nil)
}

View File

@@ -1,61 +0,0 @@
package translation
import (
"testing"
"github.com/thrasher-/gocryptotrader/currency/pair"
)
func TestGetTranslation(t *testing.T) {
currencyPair := pair.NewCurrencyPair("BTC", "USD")
expected := pair.CurrencyItem("XBT")
actual, err := GetTranslation(currencyPair.FirstCurrency)
if err != nil {
t.Error("GetTranslation: failed to retrieve translation for BTC")
}
if expected != actual {
t.Error("GetTranslation: translation result was different to expected result")
}
currencyPair.FirstCurrency = "NEO"
_, err = GetTranslation(currencyPair.FirstCurrency)
if err == nil {
t.Error("GetTranslation: no error on non translatable currency")
}
expected = "BTC"
currencyPair.FirstCurrency = "XBT"
actual, err = GetTranslation(currencyPair.FirstCurrency)
if err != nil {
t.Error("GetTranslation: failed to retrieve translation for BTC")
}
if expected != actual {
t.Error("GetTranslation: translation result was different to expected result")
}
}
func TestHasTranslation(t *testing.T) {
currencyPair := pair.NewCurrencyPair("BTC", "USD")
expected := true
actual := HasTranslation(currencyPair.FirstCurrency)
if expected != actual {
t.Error("HasTranslation: translation result was different to expected result")
}
currencyPair.FirstCurrency = "XBT"
expected = true
actual = HasTranslation(currencyPair.FirstCurrency)
if expected != actual {
t.Error("HasTranslation: translation result was different to expected result")
}
currencyPair.FirstCurrency = "NEO"
expected = false
actual = HasTranslation(currencyPair.FirstCurrency)
if expected != actual {
t.Error("HasTranslation: translation result was different to expected result")
}
}

View File

@@ -0,0 +1,34 @@
package currency
import "testing"
func TestGetTranslation(t *testing.T) {
currencyPair := NewPair(BTC, USD)
expected := XBT
actual, ok := GetTranslation(currencyPair.Base)
if !ok {
t.Error("GetTranslation: failed to retrieve translation for BTC")
}
if expected != actual {
t.Error("GetTranslation: translation result was different to expected result")
}
currencyPair.Base = NEO
_, ok = GetTranslation(currencyPair.Base)
if ok {
t.Error("GetTranslation: no error on non translatable currency")
}
expected = BTC
currencyPair.Base = XBT
actual, ok = GetTranslation(currencyPair.Base)
if !ok {
t.Error("GetTranslation: failed to retrieve translation for BTC")
}
if expected != actual {
t.Error("GetTranslation: translation result was different to expected result")
}
}

View File

@@ -29,7 +29,7 @@ package events
// func TestAddEvent(t *testing.T) {
// testSetup(t)
//
// pair := pair.NewCurrencyPair("BTC", "USD")
// pair := currency.NewPairFromStrings("BTC", "USD")
// eventID, err := AddEvent("ANX", "price", ">,==", pair, "SPOT", actionTest)
// if err != nil && eventID != 0 {
// t.Errorf("Test Failed. AddEvent: Error, %s", err)
@@ -59,7 +59,7 @@ package events
// func TestRemoveEvent(t *testing.T) {
// testSetup(t)
//
// pair := pair.NewCurrencyPair("BTC", "USD")
// pair := currency.NewPairFromStrings("BTC", "USD")
// eventID, err := AddEvent("ANX", "price", ">,==", pair, "SPOT", actionTest)
// if err != nil && eventID != 0 {
// t.Errorf("Test Failed. RemoveEvent: Error, %s", err)
@@ -75,7 +75,7 @@ package events
// func TestGetEventCounter(t *testing.T) {
// testSetup(t)
//
// pair := pair.NewCurrencyPair("BTC", "USD")
// pair := currency.NewPairFromStrings("BTC", "USD")
// one, err := AddEvent("ANX", "price", ">,==", pair, "SPOT", actionTest)
// if err != nil {
// t.Errorf("Test Failed. GetEventCounter: Error, %s", err)
@@ -114,7 +114,7 @@ package events
// func TestExecuteAction(t *testing.T) {
// testSetup(t)
//
// pair := pair.NewCurrencyPair("BTC", "USD")
// pair := currency.NewPairFromStrings("BTC", "USD")
// one, err := AddEvent("ANX", "price", ">,==", pair, "SPOT", actionTest)
// if err != nil {
// t.Fatalf("Test Failed. ExecuteAction: Error, %s", err)
@@ -160,7 +160,7 @@ package events
// func TestEventToString(t *testing.T) {
// testSetup(t)
//
// pair := pair.NewCurrencyPair("BTC", "USD")
// pair := currency.NewPairFromStrings("BTC", "USD")
// one, err := AddEvent("ANX", "price", ">,==", pair, "SPOT", actionTest)
// if err != nil {
// t.Errorf("Test Failed. EventToString: Error, %s", err)
@@ -180,7 +180,7 @@ package events
// testSetup(t)
//
// // Test invalid currency pair
// newPair := pair.NewCurrencyPair("A", "B")
// newPair := currency.NewPairFromStrings("A", "B")
// one, err := AddEvent("ANX", "price", ">=,10", newPair, "SPOT", actionTest)
// if err != nil {
// t.Errorf("Test Failed. CheckCondition: Error, %s", err)
@@ -193,7 +193,7 @@ package events
// // Test last price == 0
// var tickerNew ticker.Price
// tickerNew.Last = 0
// newPair = pair.NewCurrencyPair("BTC", "USD")
// newPair = currency.NewPairFromStrings("BTC", "USD")
// ticker.ProcessTicker("ANX", newPair, tickerNew, ticker.Spot)
// Events[one].Pair = newPair
// conditionBool = Events[one].CheckCondition()
@@ -287,7 +287,7 @@ package events
// func TestCheckEvents(t *testing.T) {
// testSetup(t)
//
// pair := pair.NewCurrencyPair("BTC", "USD")
// pair := currency.NewPairFromStrings("BTC", "USD")
// _, err := AddEvent("ANX", "price", ">=,10", pair, "SPOT", actionTest)
// if err != nil {
// t.Fatal("Test failed. TestChcheckEvents add event")

View File

@@ -9,7 +9,7 @@ import (
"github.com/thrasher-/gocryptotrader/communications"
"github.com/thrasher-/gocryptotrader/communications/base"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
log "github.com/thrasher-/gocryptotrader/logger"
)
@@ -42,7 +42,7 @@ type Event struct {
Exchange string
Item string
Condition string
Pair pair.CurrencyPair
Pair currency.Pair
Asset string
Action string
Executed bool
@@ -60,7 +60,7 @@ func SetComms(commsP *communications.Communications) {
// AddEvent adds an event to the Events chain and returns an index/eventID
// and an error
func AddEvent(exchange, item, condition string, currencyPair pair.CurrencyPair, asset, action string) (int, error) {
func AddEvent(exchange, item, condition string, currencyPair currency.Pair, asset, action string) (int, error) {
err := IsValidEvent(exchange, item, condition, action)
if err != nil {
return 0, err
@@ -129,8 +129,13 @@ func (e *Event) ExecuteAction() bool {
func (e *Event) String() string {
condition := common.SplitStrings(e.Condition, ",")
return fmt.Sprintf(
"If the %s%s [%s] %s on %s is %s then %s.", e.Pair.FirstCurrency.String(),
e.Pair.SecondCurrency.String(), e.Asset, e.Item, e.Exchange, condition[0]+" "+condition[1], e.Action,
"If the %s%s [%s] %s on %s is %s then %s.", e.Pair.Base.String(),
e.Pair.Quote.String(),
e.Asset,
e.Item,
e.Exchange,
condition[0]+" "+condition[1],
e.Action,
)
}

View File

@@ -4,8 +4,7 @@ import (
"testing"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
)
@@ -541,10 +540,10 @@ func TestSubmitOrder(t *testing.T) {
if areTestAPIKeysSet(a) && !canManipulateRealOrders {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var p = pair.CurrencyPair{
Delimiter: "_",
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.USD,
var p = currency.Pair{
Delimiter: "_",
Base: currency.BTC,
Quote: currency.USD,
}
response, err := a.SubmitOrder(p, exchange.BuyOrderSide, exchange.MarketOrderType, 1, 1, "clientId")
if !areTestAPIKeysSet(a) && err == nil {
@@ -567,7 +566,7 @@ func TestCancelExchangeOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.BTC, symbol.LTC)
currencyPair := currency.NewPair(currency.BTC, currency.LTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -593,7 +592,7 @@ func TestCancelAllExchangeOrders(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.BTC, symbol.LTC)
currencyPair := currency.NewPair(currency.BTC, currency.LTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -631,7 +630,7 @@ func TestWithdraw(t *testing.T) {
a.SetDefaults()
var withdrawCryptoRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.BTC,
Currency: currency.BTC,
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
Description: "WITHDRAW IT ALL",
AddressTag: "0123456789",

View File

@@ -7,7 +7,7 @@ import (
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -26,7 +26,7 @@ func (a *Alphapoint) GetAccountInfo() (exchange.AccountInfo, error) {
var currencies []exchange.AccountCurrencyInfo
for i := 0; i < len(account.Currencies); i++ {
var exchangeCurrency exchange.AccountCurrencyInfo
exchangeCurrency.CurrencyName = account.Currencies[i].Name
exchangeCurrency.CurrencyName = currency.NewCode(account.Currencies[i].Name)
exchangeCurrency.TotalValue = float64(account.Currencies[i].Balance)
exchangeCurrency.Hold = float64(account.Currencies[i].Hold)
@@ -41,9 +41,9 @@ func (a *Alphapoint) GetAccountInfo() (exchange.AccountInfo, error) {
}
// UpdateTicker updates and returns the ticker for a currency pair
func (a *Alphapoint) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (a *Alphapoint) UpdateTicker(p currency.Pair, assetType string) (ticker.Price, error) {
var tickerPrice ticker.Price
tick, err := a.GetTicker(p.Pair().String())
tick, err := a.GetTicker(p.String())
if err != nil {
return tickerPrice, err
}
@@ -55,12 +55,17 @@ func (a *Alphapoint) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker
tickerPrice.High = tick.High
tickerPrice.Volume = tick.Volume
tickerPrice.Last = tick.Last
ticker.ProcessTicker(a.GetName(), p, tickerPrice, assetType)
err = ticker.ProcessTicker(a.GetName(), tickerPrice, assetType)
if err != nil {
return tickerPrice, err
}
return ticker.GetTicker(a.Name, p, assetType)
}
// GetTickerPrice returns the ticker for a currency pair
func (a *Alphapoint) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (a *Alphapoint) GetTickerPrice(p currency.Pair, assetType string) (ticker.Price, error) {
tick, err := ticker.GetTicker(a.GetName(), p, assetType)
if err != nil {
return a.UpdateTicker(p, assetType)
@@ -69,30 +74,40 @@ func (a *Alphapoint) GetTickerPrice(p pair.CurrencyPair, assetType string) (tick
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (a *Alphapoint) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
func (a *Alphapoint) UpdateOrderbook(p currency.Pair, assetType string) (orderbook.Base, error) {
var orderBook orderbook.Base
orderbookNew, err := a.GetOrderbook(p.Pair().String())
orderbookNew, err := a.GetOrderbook(p.String())
if err != nil {
return orderBook, err
}
for x := range orderbookNew.Bids {
data := orderbookNew.Bids[x]
orderBook.Bids = append(orderBook.Bids, orderbook.Item{Amount: data.Quantity, Price: data.Price})
orderBook.Bids = append(orderBook.Bids,
orderbook.Item{Amount: data.Quantity, Price: data.Price})
}
for x := range orderbookNew.Asks {
data := orderbookNew.Asks[x]
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: data.Quantity, Price: data.Price})
orderBook.Asks = append(orderBook.Asks,
orderbook.Item{Amount: data.Quantity, Price: data.Price})
}
orderbook.ProcessOrderbook(a.GetName(), p, orderBook, assetType)
return orderbook.GetOrderbook(a.Name, p, assetType)
orderBook.Pair = p
orderBook.ExchangeName = a.GetName()
orderBook.AssetType = assetType
err = orderBook.Process()
if err != nil {
return orderBook, err
}
return orderbook.Get(a.Name, p, assetType)
}
// GetOrderbookEx returns the orderbook for a currency pair
func (a *Alphapoint) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.GetOrderbook(a.GetName(), p, assetType)
func (a *Alphapoint) GetOrderbookEx(p currency.Pair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.Get(a.GetName(), p, assetType)
if err != nil {
return a.UpdateOrderbook(p, assetType)
}
@@ -108,7 +123,7 @@ func (a *Alphapoint) GetFundingHistory() ([]exchange.FundHistory, error) {
}
// GetExchangeHistory returns historic trade data since exchange opening.
func (a *Alphapoint) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
func (a *Alphapoint) GetExchangeHistory(p currency.Pair, assetType string) ([]exchange.TradeHistory, error) {
var resp []exchange.TradeHistory
return resp, common.ErrNotYetImplemented
@@ -116,10 +131,14 @@ func (a *Alphapoint) GetExchangeHistory(p pair.CurrencyPair, assetType string) (
// SubmitOrder submits a new order and returns a true value when
// successfully submitted
func (a *Alphapoint) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
func (a *Alphapoint) SubmitOrder(p currency.Pair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
var submitOrderResponse exchange.SubmitOrderResponse
response, err := a.CreateOrder(p.Pair().String(), side.ToString(), orderType.ToString(), amount, price)
response, err := a.CreateOrder(p.String(),
side.ToString(),
orderType.ToString(),
amount, price)
if response > 0 {
submitOrderResponse.OrderID = fmt.Sprintf("%v", response)
}
@@ -172,7 +191,7 @@ func (a *Alphapoint) GetOrderInfo(orderID string) (float64, error) {
}
// GetDepositAddress returns a deposit address for a specified currency
func (a *Alphapoint) GetDepositAddress(cryptocurrency pair.CurrencyItem, _ string) (string, error) {
func (a *Alphapoint) GetDepositAddress(cryptocurrency currency.Code, _ string) (string, error) {
addreses, err := a.GetDepositAddresses()
if err != nil {
return "", err

View File

@@ -10,7 +10,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -87,9 +87,9 @@ func (a *ANX) Setup(exch config.ExchangeConfig) {
a.SetHTTPClientUserAgent(exch.HTTPUserAgent)
a.RESTPollingDelay = exch.RESTPollingDelay
a.Verbose = exch.Verbose
a.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
a.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
a.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
a.BaseCurrencies = exch.BaseCurrencies
a.AvailablePairs = exch.AvailablePairs
a.EnabledPairs = exch.EnabledPairs
err := a.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)
@@ -451,9 +451,9 @@ func (a *ANX) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
case exchange.CryptocurrencyTradeFee:
fee = a.calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount, feeBuilder.IsMaker)
case exchange.CryptocurrencyWithdrawalFee:
fee = getCryptocurrencyWithdrawalFee(feeBuilder.FirstCurrency)
fee = getCryptocurrencyWithdrawalFee(feeBuilder.Pair.Base)
case exchange.InternationalBankWithdrawalFee:
fee = getInternationalBankWithdrawalFee(feeBuilder.CurrencyItem, feeBuilder.Amount)
fee = getInternationalBankWithdrawalFee(feeBuilder.FiatCurrency, feeBuilder.Amount)
}
if fee < 0 {
fee = 0
@@ -473,15 +473,15 @@ func (a *ANX) calculateTradingFee(purchasePrice, amount float64, isMaker bool) f
return fee
}
func getCryptocurrencyWithdrawalFee(currency string) float64 {
return WithdrawalFees[currency]
func getCryptocurrencyWithdrawalFee(c currency.Code) float64 {
return WithdrawalFees[c]
}
func getInternationalBankWithdrawalFee(currency string, amount float64) float64 {
func getInternationalBankWithdrawalFee(c currency.Code, amount float64) float64 {
var fee float64
if currency == symbol.HKD {
fee = 250 + (WithdrawalFees[currency] * amount)
if c == currency.HKD {
fee = 250 + (WithdrawalFees[c] * amount)
}
// TODO, other fiat currencies require consultation with ANXPRO
return fee

View File

@@ -5,8 +5,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
)
@@ -131,13 +130,11 @@ func TestGetAPIKey(t *testing.T) {
func setFeeBuilder() exchange.FeeBuilder {
return exchange.FeeBuilder{
Amount: 1,
Delimiter: "",
FeeType: exchange.CryptocurrencyTradeFee,
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
IsMaker: false,
PurchasePrice: 1,
Amount: 1,
FeeType: exchange.CryptocurrencyTradeFee,
Pair: currency.NewPair(currency.BTC, currency.LTC),
IsMaker: false,
PurchasePrice: 1,
}
}
@@ -197,7 +194,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankDepositFee
feeBuilder.CurrencyItem = symbol.HKD
feeBuilder.FiatCurrency = currency.HKD
if resp, err := a.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
@@ -206,7 +203,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.CurrencyItem = symbol.HKD
feeBuilder.FiatCurrency = currency.HKD
if resp, err := a.GetFee(feeBuilder); resp != float64(250.01) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(250.01), resp)
t.Error(err)
@@ -275,10 +272,10 @@ func TestSubmitOrder(t *testing.T) {
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var p = pair.CurrencyPair{
Delimiter: "_",
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.USD,
var p = currency.Pair{
Delimiter: "_",
Base: currency.BTC,
Quote: currency.USD,
}
response, err := a.SubmitOrder(p, exchange.BuyOrderSide, exchange.MarketOrderType, 1, 1, "clientId")
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
@@ -296,7 +293,7 @@ func TestCancelExchangeOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.BTC, symbol.LTC)
currencyPair := currency.NewPair(currency.BTC, currency.LTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -321,7 +318,7 @@ func TestCancelAllExchangeOrders(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.BTC, symbol.LTC)
currencyPair := currency.NewPair(currency.BTC, currency.LTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -374,7 +371,7 @@ func TestWithdraw(t *testing.T) {
var withdrawCryptoRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.BTC,
Currency: currency.BTC,
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
Description: "WITHDRAW IT ALL",
AddressTag: "0123456789",
@@ -422,12 +419,12 @@ func TestWithdrawInternationalBank(t *testing.T) {
func TestGetDepositAddress(t *testing.T) {
if areTestAPIKeysSet() {
_, err := a.GetDepositAddress(symbol.BTC, "")
_, err := a.GetDepositAddress(currency.BTC, "")
if err != nil {
t.Error("Test Failed - GetDepositAddress() error", err)
}
} else {
_, err := a.GetDepositAddress(symbol.BTC, "")
_, err := a.GetDepositAddress(currency.BTC, "")
if err == nil {
t.Error("Test Failed - GetDepositAddress() error cannot be nil")
}

View File

@@ -1,6 +1,6 @@
package anx
import "github.com/thrasher-/gocryptotrader/currency/symbol"
import "github.com/thrasher-/gocryptotrader/currency"
// List of strings
const (
@@ -9,8 +9,8 @@ const (
CancelOrderWrongState string = "ORDER_CANCEL_WRONG_STATE"
)
// Currency holds the currency information
type Currency struct {
// CurrencyData holds the currency information
type CurrencyData struct {
Decimals int `json:"decimals"`
MinOrderSize float64 `json:"minOrderSize"`
MaxOrderSize float64 `json:"maxOrderSize"`
@@ -41,10 +41,10 @@ type Currency struct {
}
// Currencies stores a list of currencies
type Currencies map[string]Currency
type Currencies map[string]CurrencyData
// CurrencyPair holds the currency information
type CurrencyPair struct {
// CurrencyPairData holds the currency information
type CurrencyPairData struct {
PriceDecimals int `json:"priceDecimals"`
EngineSettings struct {
TradingEnabled bool `json:"tradingEnabled"`
@@ -88,7 +88,7 @@ type Amount struct {
}
// CurrencyPairs stores currency pair info
type CurrencyPairs map[string]CurrencyPair
type CurrencyPairs map[string]CurrencyPairData
// CurrenciesStore stores the available cryptocurrencies
// and fiat currencies
@@ -195,13 +195,13 @@ type Depth struct {
// WithdrawalFees the large list of predefined withdrawal fees
// Prone to change
var WithdrawalFees = map[string]float64{
symbol.BTC: 0.002,
symbol.DOGE: 0.1,
symbol.ETH: 0.005,
symbol.GNT: 0.001,
symbol.LTC: 0.02,
symbol.OAX: 0.001,
symbol.XRP: 1,
symbol.HKD: 0.01,
var WithdrawalFees = map[currency.Code]float64{
currency.BTC: 0.002,
currency.DOGE: 0.1,
currency.ETH: 0.005,
currency.GNT: 0.001,
currency.LTC: 0.02,
currency.OAX: 0.001,
currency.XRP: 1,
currency.HKD: 0.01,
}

View File

@@ -8,7 +8,7 @@ import (
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -31,17 +31,25 @@ func (a *ANX) Run() {
log.Debugf("%s %d currencies enabled: %s.\n", a.GetName(), len(a.EnabledPairs), a.EnabledPairs)
}
exchangeProducts, err := a.GetTradablePairs()
tradablePairs, err := a.GetTradablePairs()
if err != nil {
log.Debugf("%s Failed to get available symbols.\n", a.GetName())
} else {
forceUpgrade := false
if !common.StringDataContains(a.EnabledPairs, "_") || !common.StringDataContains(a.AvailablePairs, "_") {
if !common.StringDataContains(a.EnabledPairs.Strings(), "_") ||
!common.StringDataContains(a.AvailablePairs.Strings(), "_") {
forceUpgrade = true
}
if forceUpgrade {
enabledPairs := []string{"BTC_USD,BTC_HKD,BTC_EUR,BTC_CAD,BTC_AUD,BTC_SGD,BTC_JPY,BTC_GBP,BTC_NZD,LTC_BTC,DOG_EBTC,STR_BTC,XRP_BTC"}
newPairs := []string{"BTC_USD,BTC_HKD,BTC_EUR,BTC_CAD,BTC_AUD,BTC_SGD,BTC_JPY,BTC_GBP,BTC_NZD,LTC_BTC,DOG_EBTC,STR_BTC,XRP_BTC"}
var enabledPairs currency.Pairs
for _, p := range newPairs {
enabledPairs = append(enabledPairs,
currency.NewPairDelimiter(p, "_"))
}
log.Warn("Enabled pairs for ANX reset due to config upgrade, please enable the ones you would like again.")
err = a.UpdateCurrencies(enabledPairs, true, true)
@@ -49,6 +57,13 @@ func (a *ANX) Run() {
log.Errorf("%s Failed to get config.\n", a.GetName())
}
}
var exchangeProducts currency.Pairs
for _, p := range tradablePairs {
exchangeProducts = append(exchangeProducts,
currency.NewPairDelimiter(p, "_"))
}
err = a.UpdateCurrencies(exchangeProducts, false, forceUpgrade)
if err != nil {
log.Errorf("%s Failed to get config.\n", a.GetName())
@@ -72,7 +87,7 @@ func (a *ANX) GetTradablePairs() ([]string, error) {
}
// UpdateTicker updates and returns the ticker for a currency pair
func (a *ANX) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (a *ANX) UpdateTicker(p currency.Pair, assetType string) (ticker.Price, error) {
var tickerPrice ticker.Price
tick, err := a.GetTicker(exchange.FormatExchangeCurrency(a.GetName(), p).String())
if err != nil {
@@ -134,12 +149,17 @@ func (a *ANX) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price,
} else {
tickerPrice.High = 0
}
ticker.ProcessTicker(a.GetName(), p, tickerPrice, assetType)
err = ticker.ProcessTicker(a.GetName(), tickerPrice, assetType)
if err != nil {
return tickerPrice, err
}
return ticker.GetTicker(a.Name, p, assetType)
}
// GetTickerPrice returns the ticker for a currency pair
func (a *ANX) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (a *ANX) GetTickerPrice(p currency.Pair, assetType string) (ticker.Price, error) {
tickerNew, err := ticker.GetTicker(a.GetName(), p, assetType)
if err != nil {
return a.UpdateTicker(p, assetType)
@@ -148,8 +168,8 @@ func (a *ANX) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Pric
}
// GetOrderbookEx returns the orderbook for a currency pair
func (a *ANX) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.GetOrderbook(a.GetName(), p, assetType)
func (a *ANX) GetOrderbookEx(p currency.Pair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.Get(a.GetName(), p, assetType)
if err != nil {
return a.UpdateOrderbook(p, assetType)
}
@@ -157,7 +177,7 @@ func (a *ANX) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.B
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (a *ANX) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
func (a *ANX) UpdateOrderbook(p currency.Pair, assetType string) (orderbook.Base, error) {
var orderBook orderbook.Base
orderbookNew, err := a.GetDepth(exchange.FormatExchangeCurrency(a.GetName(), p).String())
if err != nil {
@@ -178,8 +198,15 @@ func (a *ANX) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.
Amount: orderbookNew.Data.Bids[x].Amount})
}
orderbook.ProcessOrderbook(a.GetName(), p, orderBook, assetType)
return orderbook.GetOrderbook(a.Name, p, assetType)
orderBook.Pair = p
orderBook.ExchangeName = a.GetName()
orderBook.AssetType = assetType
err = orderBook.Process()
if err != nil {
return orderBook, err
}
return orderbook.Get(a.Name, p, assetType)
}
// GetAccountInfo retrieves balances for all enabled currencies on the
@@ -193,9 +220,9 @@ func (a *ANX) GetAccountInfo() (exchange.AccountInfo, error) {
}
var balance []exchange.AccountCurrencyInfo
for currency, info := range raw.Wallets {
for c, info := range raw.Wallets {
balance = append(balance, exchange.AccountCurrencyInfo{
CurrencyName: currency,
CurrencyName: currency.NewCode(c),
TotalValue: info.AvailableBalance.Value,
Hold: info.Balance.Value,
})
@@ -217,14 +244,14 @@ func (a *ANX) GetFundingHistory() ([]exchange.FundHistory, error) {
}
// GetExchangeHistory returns historic trade data since exchange opening.
func (a *ANX) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
func (a *ANX) GetExchangeHistory(p currency.Pair, assetType string) ([]exchange.TradeHistory, error) {
var resp []exchange.TradeHistory
return resp, common.ErrNotYetImplemented
}
// SubmitOrder submits a new order
func (a *ANX) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
func (a *ANX) SubmitOrder(p currency.Pair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
var submitOrderResponse exchange.SubmitOrderResponse
var isBuying bool
@@ -240,9 +267,9 @@ func (a *ANX) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderTyp
response, err := a.NewOrder(orderType.ToString(),
isBuying,
p.FirstCurrency.String(),
p.Base.String(),
amount,
p.SecondCurrency.String(),
p.Quote.String(),
amount,
limitPriceInSettlementCurrency,
false,
@@ -309,7 +336,7 @@ func (a *ANX) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
}
// GetDepositAddress returns a deposit address for a specified currency
func (a *ANX) GetDepositAddress(cryptocurrency pair.CurrencyItem, _ string) (string, error) {
func (a *ANX) GetDepositAddress(cryptocurrency currency.Code, _ string) (string, error) {
return a.GetDepositAddressByCurrency(cryptocurrency.String(), "", false)
}
@@ -356,21 +383,23 @@ func (a *ANX) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) ([]exc
orderType := exchange.OrderType(strings.ToUpper(order.OrderType))
orderDetail := exchange.OrderDetail{
Amount: order.TradedCurrencyAmount,
CurrencyPair: pair.NewCurrencyPairWithDelimiter(order.TradedCurrency, order.SettlementCurrency, a.ConfigCurrencyPairFormat.Delimiter),
OrderDate: orderDate,
Exchange: a.Name,
ID: order.OrderID,
OrderType: orderType,
Price: order.SettlementCurrencyAmount,
Status: order.OrderStatus,
Amount: order.TradedCurrencyAmount,
CurrencyPair: currency.NewPairWithDelimiter(order.TradedCurrency,
order.SettlementCurrency, a.ConfigCurrencyPairFormat.Delimiter),
OrderDate: orderDate,
Exchange: a.Name,
ID: order.OrderID,
OrderType: orderType,
Price: order.SettlementCurrencyAmount,
Status: order.OrderStatus,
}
orders = append(orders, orderDetail)
}
exchange.FilterOrdersByType(&orders, getOrdersRequest.OrderType)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks, getOrdersRequest.EndTicks)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks,
getOrdersRequest.EndTicks)
exchange.FilterOrdersByCurrencies(&orders, getOrdersRequest.Currencies)
return orders, nil
@@ -390,21 +419,24 @@ func (a *ANX) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) ([]exc
orderType := exchange.OrderType(strings.ToUpper(order.OrderType))
orderDetail := exchange.OrderDetail{
Amount: order.TradedCurrencyAmount,
OrderDate: orderDate,
Exchange: a.Name,
ID: order.OrderID,
OrderType: orderType,
Price: order.SettlementCurrencyAmount,
Status: order.OrderStatus,
CurrencyPair: pair.NewCurrencyPairWithDelimiter(order.TradedCurrency, order.SettlementCurrency, a.ConfigCurrencyPairFormat.Delimiter),
Amount: order.TradedCurrencyAmount,
OrderDate: orderDate,
Exchange: a.Name,
ID: order.OrderID,
OrderType: orderType,
Price: order.SettlementCurrencyAmount,
Status: order.OrderStatus,
CurrencyPair: currency.NewPairWithDelimiter(order.TradedCurrency,
order.SettlementCurrency,
a.ConfigCurrencyPairFormat.Delimiter),
}
orders = append(orders, orderDetail)
}
exchange.FilterOrdersByType(&orders, getOrdersRequest.OrderType)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks, getOrdersRequest.EndTicks)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks,
getOrdersRequest.EndTicks)
exchange.FilterOrdersByCurrencies(&orders, getOrdersRequest.Currencies)
return orders, nil

View File

@@ -13,6 +13,7 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -111,9 +112,9 @@ func (b *Binance) Setup(exch config.ExchangeConfig) {
b.SetHTTPClientUserAgent(exch.HTTPUserAgent)
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
b.BaseCurrencies = exch.BaseCurrencies
b.AvailablePairs = exch.AvailablePairs
b.EnabledPairs = exch.EnabledPairs
err := b.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)
@@ -706,7 +707,7 @@ func (b *Binance) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
}
fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount, multiplier)
case exchange.CryptocurrencyWithdrawalFee:
fee = getCryptocurrencyWithdrawalFee(feeBuilder.FirstCurrency)
fee = getCryptocurrencyWithdrawalFee(feeBuilder.Pair.Base)
}
if fee < 0 {
fee = 0
@@ -735,8 +736,8 @@ func calculateTradingFee(purchasePrice, amount, multiplier float64) float64 {
}
// getCryptocurrencyWithdrawalFee returns the fee for withdrawing from the exchange
func getCryptocurrencyWithdrawalFee(currency string) float64 {
return WithdrawalFees[currency]
func getCryptocurrencyWithdrawalFee(c currency.Code) float64 {
return WithdrawalFees[c]
}
// WithdrawCrypto sends cryptocurrency to the address of your choosing

View File

@@ -5,8 +5,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
)
@@ -234,13 +233,10 @@ func TestGetAccount(t *testing.T) {
func setFeeBuilder() exchange.FeeBuilder {
return exchange.FeeBuilder{
Amount: 1,
Delimiter: "",
FeeType: exchange.CryptocurrencyTradeFee,
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
IsMaker: false,
PurchasePrice: 1,
Amount: 1,
FeeType: exchange.CryptocurrencyTradeFee,
Pair: currency.NewPair(currency.BTC, currency.LTC),
PurchasePrice: 1,
}
}
@@ -303,7 +299,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankDepositFee
feeBuilder.CurrencyItem = symbol.HKD
feeBuilder.FiatCurrency = currency.HKD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
@@ -312,7 +308,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.CurrencyItem = symbol.HKD
feeBuilder.FiatCurrency = currency.HKD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
@@ -342,7 +338,9 @@ func TestGetActiveOrders(t *testing.T) {
t.Error("Expected: 'At least one currency is required to fetch order history'. received nil")
}
getOrdersRequest.Currencies = []pair.CurrencyPair{pair.NewCurrencyPair(symbol.LTC, symbol.BTC)}
getOrdersRequest.Currencies = []currency.Pair{
currency.NewPair(currency.LTC, currency.BTC),
}
_, err = b.GetActiveOrders(getOrdersRequest)
if areTestAPIKeysSet() && err != nil {
@@ -365,7 +363,9 @@ func TestGetOrderHistory(t *testing.T) {
t.Error("Expected: 'At least one currency is required to fetch order history'. received nil")
}
getOrdersRequest.Currencies = []pair.CurrencyPair{pair.NewCurrencyPair(symbol.LTC, symbol.BTC)}
getOrdersRequest.Currencies = []currency.Pair{
currency.NewPair(currency.LTC,
currency.BTC)}
_, err = b.GetOrderHistory(getOrdersRequest)
if areTestAPIKeysSet() && err != nil {
@@ -390,10 +390,10 @@ func TestSubmitOrder(t *testing.T) {
b.SetDefaults()
TestSetup(t)
var p = pair.CurrencyPair{
Delimiter: "",
FirstCurrency: symbol.LTC,
SecondCurrency: symbol.BTC,
var p = currency.Pair{
Delimiter: "",
Base: currency.LTC,
Quote: currency.BTC,
}
response, err := b.SubmitOrder(p, exchange.BuyOrderSide, exchange.MarketOrderType, 1, 1, "clientId")
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
@@ -407,7 +407,7 @@ func TestCancelExchangeOrder(t *testing.T) {
b.SetDefaults()
TestSetup(t)
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -429,7 +429,7 @@ func TestCancelAllExchangeOrders(t *testing.T) {
b.SetDefaults()
TestSetup(t)
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -482,7 +482,7 @@ func TestWithdraw(t *testing.T) {
var withdrawCryptoRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.BTC,
Currency: currency.BTC,
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
Description: "WITHDRAW IT ALL",
}
@@ -530,12 +530,12 @@ func TestWithdrawInternationalBank(t *testing.T) {
func TestGetDepositAddress(t *testing.T) {
if areTestAPIKeysSet() {
_, err := b.GetDepositAddress(symbol.BTC, "")
_, err := b.GetDepositAddress(currency.BTC, "")
if err != nil {
t.Error("Test Failed - GetDepositAddress() error", err)
}
} else {
_, err := b.GetDepositAddress(symbol.BTC, "")
_, err := b.GetDepositAddress(currency.BTC, "")
if err == nil {
t.Error("Test Failed - GetDepositAddress() error cannot be nil")
}

View File

@@ -3,7 +3,7 @@ package binance
import (
"encoding/json"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
)
// Response holds basic binance api response data
@@ -450,171 +450,171 @@ var (
// WithdrawalFees the large list of predefined withdrawal fees
// Prone to change
var WithdrawalFees = map[string]float64{
symbol.BNB: 0.13,
symbol.BTC: 0.0005,
symbol.NEO: 0,
symbol.ETH: 0.01,
symbol.LTC: 0.001,
symbol.QTUM: 0.01,
symbol.EOS: 0.1,
symbol.SNT: 35,
symbol.BNT: 1,
symbol.GAS: 0,
symbol.BCC: 0.001,
symbol.BTM: 5,
symbol.USDT: 3.4,
symbol.HCC: 0.0005,
symbol.OAX: 6.5,
symbol.DNT: 54,
symbol.MCO: 0.31,
symbol.ICN: 3.5,
symbol.ZRX: 1.9,
symbol.OMG: 0.4,
symbol.WTC: 0.5,
symbol.LRC: 12.3,
symbol.LLT: 67.8,
symbol.YOYO: 1,
symbol.TRX: 1,
symbol.STRAT: 0.1,
symbol.SNGLS: 54,
symbol.BQX: 3.9,
symbol.KNC: 3.5,
symbol.SNM: 25,
symbol.FUN: 86,
symbol.LINK: 4,
symbol.XVG: 0.1,
symbol.CTR: 35,
symbol.SALT: 2.3,
symbol.MDA: 2.3,
symbol.IOTA: 0.5,
symbol.SUB: 11.4,
symbol.ETC: 0.01,
symbol.MTL: 2,
symbol.MTH: 45,
symbol.ENG: 2.2,
symbol.AST: 14.4,
symbol.DASH: 0.002,
symbol.BTG: 0.001,
symbol.EVX: 2.8,
symbol.REQ: 29.9,
symbol.VIB: 30,
symbol.POWR: 8.2,
symbol.ARK: 0.2,
symbol.XRP: 0.25,
symbol.MOD: 2,
symbol.ENJ: 26,
symbol.STORJ: 5.1,
symbol.KMD: 0.002,
symbol.RCN: 47,
symbol.NULS: 0.01,
symbol.RDN: 2.5,
symbol.XMR: 0.04,
symbol.DLT: 19.8,
symbol.AMB: 8.9,
symbol.BAT: 8,
symbol.ZEC: 0.005,
symbol.BCPT: 14.5,
symbol.ARN: 3,
symbol.GVT: 0.13,
symbol.CDT: 81,
symbol.GXS: 0.3,
symbol.POE: 134,
symbol.QSP: 36,
symbol.BTS: 1,
symbol.XZC: 0.02,
symbol.LSK: 0.1,
symbol.TNT: 47,
symbol.FUEL: 79,
symbol.MANA: 18,
symbol.BCD: 0.01,
symbol.DGD: 0.04,
symbol.ADX: 6.3,
symbol.ADA: 1,
symbol.PPT: 0.41,
symbol.CMT: 12,
symbol.XLM: 0.01,
symbol.CND: 58,
symbol.LEND: 84,
symbol.WABI: 6.6,
symbol.SBTC: 0.0005,
symbol.BCX: 0.5,
symbol.WAVES: 0.002,
symbol.TNB: 139,
symbol.GTO: 20,
symbol.ICX: 0.02,
symbol.OST: 32,
symbol.ELF: 3.9,
symbol.AION: 3.2,
symbol.CVC: 10.9,
symbol.REP: 0.2,
symbol.GNT: 8.9,
symbol.DATA: 37,
symbol.ETF: 1,
symbol.BRD: 3.8,
symbol.NEBL: 0.01,
symbol.VIBE: 17.3,
symbol.LUN: 0.36,
symbol.CHAT: 60.7,
symbol.RLC: 3.4,
symbol.INS: 3.5,
symbol.IOST: 105.6,
symbol.STEEM: 0.01,
symbol.NANO: 0.01,
symbol.AE: 1.3,
symbol.VIA: 0.01,
symbol.BLZ: 10.3,
symbol.SYS: 1,
symbol.NCASH: 247.6,
symbol.POA: 0.01,
symbol.ONT: 1,
symbol.ZIL: 37.2,
symbol.STORM: 152,
symbol.XEM: 4,
symbol.WAN: 0.1,
symbol.WPR: 43.4,
symbol.QLC: 1,
symbol.GRS: 0.2,
symbol.CLOAK: 0.02,
symbol.LOOM: 11.9,
symbol.BCN: 1,
symbol.TUSD: 1.35,
symbol.ZEN: 0.002,
symbol.SKY: 0.01,
symbol.THETA: 24,
symbol.IOTX: 90.5,
symbol.QKC: 24.6,
symbol.AGI: 29.81,
symbol.NXS: 0.02,
symbol.SC: 0.1,
symbol.EON: 10,
symbol.NPXS: 897,
symbol.KEY: 223,
symbol.NAS: 0.1,
symbol.ADD: 100,
symbol.MEETONE: 300,
symbol.ATD: 100,
symbol.MFT: 175,
symbol.EOP: 5,
symbol.DENT: 596,
symbol.IQ: 50,
symbol.ARDR: 2,
symbol.HOT: 1210,
symbol.VET: 100,
symbol.DOCK: 68,
symbol.POLY: 7,
symbol.VTHO: 21,
symbol.ONG: 0.1,
symbol.PHX: 1,
symbol.HC: 0.005,
symbol.GO: 0.01,
symbol.PAX: 1.4,
symbol.EDO: 1.3,
symbol.WINGS: 8.9,
symbol.NAV: 0.2,
symbol.TRIG: 49.1,
symbol.APPC: 12.4,
symbol.PIVX: 0.02,
var WithdrawalFees = map[currency.Code]float64{
currency.BNB: 0.13,
currency.BTC: 0.0005,
currency.NEO: 0,
currency.ETH: 0.01,
currency.LTC: 0.001,
currency.QTUM: 0.01,
currency.EOS: 0.1,
currency.SNT: 35,
currency.BNT: 1,
currency.GAS: 0,
currency.BCC: 0.001,
currency.BTM: 5,
currency.USDT: 3.4,
currency.HCC: 0.0005,
currency.OAX: 6.5,
currency.DNT: 54,
currency.MCO: 0.31,
currency.ICN: 3.5,
currency.ZRX: 1.9,
currency.OMG: 0.4,
currency.WTC: 0.5,
currency.LRC: 12.3,
currency.LLT: 67.8,
currency.YOYO: 1,
currency.TRX: 1,
currency.STRAT: 0.1,
currency.SNGLS: 54,
currency.BQX: 3.9,
currency.KNC: 3.5,
currency.SNM: 25,
currency.FUN: 86,
currency.LINK: 4,
currency.XVG: 0.1,
currency.CTR: 35,
currency.SALT: 2.3,
currency.MDA: 2.3,
currency.IOTA: 0.5,
currency.SUB: 11.4,
currency.ETC: 0.01,
currency.MTL: 2,
currency.MTH: 45,
currency.ENG: 2.2,
currency.AST: 14.4,
currency.DASH: 0.002,
currency.BTG: 0.001,
currency.EVX: 2.8,
currency.REQ: 29.9,
currency.VIB: 30,
currency.POWR: 8.2,
currency.ARK: 0.2,
currency.XRP: 0.25,
currency.MOD: 2,
currency.ENJ: 26,
currency.STORJ: 5.1,
currency.KMD: 0.002,
currency.RCN: 47,
currency.NULS: 0.01,
currency.RDN: 2.5,
currency.XMR: 0.04,
currency.DLT: 19.8,
currency.AMB: 8.9,
currency.BAT: 8,
currency.ZEC: 0.005,
currency.BCPT: 14.5,
currency.ARN: 3,
currency.GVT: 0.13,
currency.CDT: 81,
currency.GXS: 0.3,
currency.POE: 134,
currency.QSP: 36,
currency.BTS: 1,
currency.XZC: 0.02,
currency.LSK: 0.1,
currency.TNT: 47,
currency.FUEL: 79,
currency.MANA: 18,
currency.BCD: 0.01,
currency.DGD: 0.04,
currency.ADX: 6.3,
currency.ADA: 1,
currency.PPT: 0.41,
currency.CMT: 12,
currency.XLM: 0.01,
currency.CND: 58,
currency.LEND: 84,
currency.WABI: 6.6,
currency.SBTC: 0.0005,
currency.BCX: 0.5,
currency.WAVES: 0.002,
currency.TNB: 139,
currency.GTO: 20,
currency.ICX: 0.02,
currency.OST: 32,
currency.ELF: 3.9,
currency.AION: 3.2,
currency.CVC: 10.9,
currency.REP: 0.2,
currency.GNT: 8.9,
currency.DATA: 37,
currency.ETF: 1,
currency.BRD: 3.8,
currency.NEBL: 0.01,
currency.VIBE: 17.3,
currency.LUN: 0.36,
currency.CHAT: 60.7,
currency.RLC: 3.4,
currency.INS: 3.5,
currency.IOST: 105.6,
currency.STEEM: 0.01,
currency.NANO: 0.01,
currency.AE: 1.3,
currency.VIA: 0.01,
currency.BLZ: 10.3,
currency.SYS: 1,
currency.NCASH: 247.6,
currency.POA: 0.01,
currency.ONT: 1,
currency.ZIL: 37.2,
currency.STORM: 152,
currency.XEM: 4,
currency.WAN: 0.1,
currency.WPR: 43.4,
currency.QLC: 1,
currency.GRS: 0.2,
currency.CLOAK: 0.02,
currency.LOOM: 11.9,
currency.BCN: 1,
currency.TUSD: 1.35,
currency.ZEN: 0.002,
currency.SKY: 0.01,
currency.THETA: 24,
currency.IOTX: 90.5,
currency.QKC: 24.6,
currency.AGI: 29.81,
currency.NXS: 0.02,
currency.SC: 0.1,
currency.EON: 10,
currency.NPXS: 897,
currency.KEY: 223,
currency.NAS: 0.1,
currency.ADD: 100,
currency.MEETONE: 300,
currency.ATD: 100,
currency.MFT: 175,
currency.EOP: 5,
currency.DENT: 596,
currency.IQ: 50,
currency.ARDR: 2,
currency.HOT: 1210,
currency.VET: 100,
currency.DOCK: 68,
currency.POLY: 7,
currency.VTHO: 21,
currency.ONG: 0.1,
currency.PHX: 1,
currency.HC: 0.005,
currency.GO: 0.01,
currency.PAX: 1.4,
currency.EDO: 1.3,
currency.WINGS: 8.9,
currency.NAV: 0.2,
currency.TRIG: 49.1,
currency.APPC: 12.4,
currency.PIVX: 0.02,
}
// WithdrawResponse contains status of withdrawal request

View File

@@ -12,7 +12,7 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -26,7 +26,7 @@ var lastUpdateID map[string]int64
var m sync.Mutex
// SeedLocalCache seeds depth data
func (b *Binance) SeedLocalCache(p pair.CurrencyPair) error {
func (b *Binance) SeedLocalCache(p currency.Pair) error {
var newOrderBook orderbook.Base
formattedPair := exchange.FormatExchangeCurrency(b.Name, p)
@@ -58,9 +58,7 @@ func (b *Binance) SeedLocalCache(p pair.CurrencyPair) error {
orderbook.Item{Amount: Asks.Quantity, Price: Asks.Price})
}
newOrderBook.Pair = pair.NewCurrencyPairFromString(formattedPair.String())
newOrderBook.CurrencyPair = formattedPair.String()
newOrderBook.LastUpdated = time.Now()
newOrderBook.Pair = currency.NewPairFromString(formattedPair.String())
newOrderBook.AssetType = ticker.Spot
return b.Websocket.Orderbook.LoadSnapshot(newOrderBook, b.GetName(), false)
@@ -113,7 +111,7 @@ func (b *Binance) UpdateLocalCache(ob WebsocketDepthStream) error {
}
updatedTime := time.Unix(ob.Timestamp, 0)
currencyPair := pair.NewCurrencyPairFromString(ob.Pair)
currencyPair := currency.NewPairFromString(ob.Pair)
return b.Websocket.Orderbook.Update(updateBid,
updateAsk,
@@ -134,16 +132,16 @@ func (b *Binance) WSConnect() error {
tick := strings.ToLower(
strings.Replace(
strings.Join(b.EnabledPairs, "@ticker/"), "-", "", -1)) + "@ticker"
strings.Join(b.EnabledPairs.Strings(), "@ticker/"), "-", "", -1)) + "@ticker"
trade := strings.ToLower(
strings.Replace(
strings.Join(b.EnabledPairs, "@trade/"), "-", "", -1)) + "@trade"
strings.Join(b.EnabledPairs.Strings(), "@trade/"), "-", "", -1)) + "@trade"
kline := strings.ToLower(
strings.Replace(
strings.Join(b.EnabledPairs, "@kline_1m/"), "-", "", -1)) + "@kline_1m"
strings.Join(b.EnabledPairs.Strings(), "@kline_1m/"), "-", "", -1)) + "@kline_1m"
depth := strings.ToLower(
strings.Replace(
strings.Join(b.EnabledPairs, "@depth/"), "-", "", -1)) + "@depth"
strings.Join(b.EnabledPairs.Strings(), "@depth/"), "-", "", -1)) + "@depth"
wsurl := b.Websocket.GetWebsocketURL() +
"/stream?streams=" +
@@ -255,7 +253,7 @@ func (b *Binance) WsHandleData() {
}
b.Websocket.DataHandler <- exchange.TradeData{
CurrencyPair: pair.NewCurrencyPairFromString(trade.Symbol),
CurrencyPair: currency.NewPairFromString(trade.Symbol),
Timestamp: time.Unix(0, trade.TimeStamp),
Price: price,
Amount: amount,
@@ -277,7 +275,7 @@ func (b *Binance) WsHandleData() {
var wsTicker exchange.TickerData
wsTicker.Timestamp = time.Unix(0, t.EventTime)
wsTicker.Pair = pair.NewCurrencyPairFromString(t.Symbol)
wsTicker.Pair = currency.NewPairFromString(t.Symbol)
wsTicker.AssetType = ticker.Spot
wsTicker.Exchange = b.GetName()
wsTicker.ClosePrice, _ = strconv.ParseFloat(t.CurrDayClose, 64)
@@ -301,7 +299,7 @@ func (b *Binance) WsHandleData() {
var wsKline exchange.KlineData
wsKline.Timestamp = time.Unix(0, kline.EventTime)
wsKline.Pair = pair.NewCurrencyPairFromString(kline.Symbol)
wsKline.Pair = currency.NewPairFromString(kline.Symbol)
wsKline.AssetType = ticker.Spot
wsKline.Exchange = b.GetName()
wsKline.StartTime = time.Unix(0, kline.Kline.StartTime)
@@ -332,7 +330,7 @@ func (b *Binance) WsHandleData() {
continue
}
currencyPair := pair.NewCurrencyPairFromString(depth.Pair)
currencyPair := currency.NewPairFromString(depth.Pair)
b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
Pair: currencyPair,

View File

@@ -9,7 +9,7 @@ import (
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -44,13 +44,18 @@ func (b *Binance) Run() {
log.Errorf("%s Failed to get exchange info.\n", b.GetName())
} else {
forceUpgrade := false
if !common.StringDataContains(b.EnabledPairs, "-") ||
!common.StringDataContains(b.AvailablePairs, "-") {
if !common.StringDataContains(b.EnabledPairs.Strings(), "-") ||
!common.StringDataContains(b.AvailablePairs.Strings(), "-") {
forceUpgrade = true
}
if forceUpgrade {
enabledPairs := []string{"BTC-USDT"}
enabledPairs := currency.Pairs{currency.Pair{
Base: currency.BTC,
Quote: currency.USDT,
Delimiter: "-",
}}
log.Warn("Available pairs for Binance reset due to config upgrade, please enable the ones you would like again")
err = b.UpdateCurrencies(enabledPairs, true, true)
@@ -58,7 +63,14 @@ func (b *Binance) Run() {
log.Errorf("%s Failed to get config.\n", b.GetName())
}
}
err = b.UpdateCurrencies(symbols, false, forceUpgrade)
var newSymbols currency.Pairs
for _, p := range symbols {
newSymbols = append(newSymbols,
currency.NewPairFromString(p))
}
err = b.UpdateCurrencies(newSymbols, false, forceUpgrade)
if err != nil {
log.Errorf("%s Failed to get config.\n", b.GetName())
}
@@ -66,7 +78,7 @@ func (b *Binance) Run() {
}
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Binance) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *Binance) UpdateTicker(p currency.Pair, assetType string) (ticker.Price, error) {
var tickerPrice ticker.Price
tick, err := b.GetTickers()
if err != nil {
@@ -86,14 +98,14 @@ func (b *Binance) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Pr
tickerPrice.Last = tick[y].LastPrice
tickerPrice.Low = tick[y].LowPrice
tickerPrice.Volume = tick[y].Volume
ticker.ProcessTicker(b.Name, x, tickerPrice, assetType)
ticker.ProcessTicker(b.Name, tickerPrice, assetType)
}
}
return ticker.GetTicker(b.Name, p, assetType)
}
// GetTickerPrice returns the ticker for a currency pair
func (b *Binance) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *Binance) GetTickerPrice(p currency.Pair, assetType string) (ticker.Price, error) {
tickerNew, err := ticker.GetTicker(b.GetName(), p, assetType)
if err != nil {
return b.UpdateTicker(p, assetType)
@@ -102,8 +114,8 @@ func (b *Binance) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.
}
// GetOrderbookEx returns orderbook base on the currency pair
func (b *Binance) GetOrderbookEx(currency pair.CurrencyPair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.GetOrderbook(b.GetName(), currency, assetType)
func (b *Binance) GetOrderbookEx(currency currency.Pair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.Get(b.GetName(), currency, assetType)
if err != nil {
return b.UpdateOrderbook(currency, assetType)
}
@@ -111,7 +123,7 @@ func (b *Binance) GetOrderbookEx(currency pair.CurrencyPair, assetType string) (
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (b *Binance) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
func (b *Binance) UpdateOrderbook(p currency.Pair, assetType string) (orderbook.Base, error) {
var orderBook orderbook.Base
orderbookNew, err := b.GetOrderBook(OrderBookDataRequestParams{Symbol: exchange.FormatExchangeCurrency(b.Name, p).String(), Limit: 1000})
if err != nil {
@@ -128,8 +140,16 @@ func (b *Binance) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderb
orderbook.Item{Amount: asks.Quantity, Price: asks.Price})
}
orderbook.ProcessOrderbook(b.GetName(), p, orderBook, assetType)
return orderbook.GetOrderbook(b.Name, p, assetType)
orderBook.Pair = p
orderBook.ExchangeName = b.GetName()
orderBook.AssetType = assetType
err = orderBook.Process()
if err != nil {
return orderBook, err
}
return orderbook.Get(b.Name, p, assetType)
}
// GetAccountInfo retrieves balances for all enabled currencies for the
@@ -154,7 +174,7 @@ func (b *Binance) GetAccountInfo() (exchange.AccountInfo, error) {
}
currencyBalance = append(currencyBalance, exchange.AccountCurrencyInfo{
CurrencyName: balance.Asset,
CurrencyName: currency.NewCode(balance.Asset),
TotalValue: freeCurrency + lockedCurrency,
Hold: freeCurrency,
})
@@ -176,13 +196,13 @@ func (b *Binance) GetFundingHistory() ([]exchange.FundHistory, error) {
}
// GetExchangeHistory returns historic trade data since exchange opening.
func (b *Binance) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
func (b *Binance) GetExchangeHistory(p currency.Pair, assetType string) ([]exchange.TradeHistory, error) {
var resp []exchange.TradeHistory
return resp, common.ErrNotYetImplemented
}
// SubmitOrder submits a new order
func (b *Binance) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
func (b *Binance) SubmitOrder(p currency.Pair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
var submitOrderResponse exchange.SubmitOrderResponse
var sideType RequestParamsSideType
@@ -204,7 +224,7 @@ func (b *Binance) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orde
}
var orderRequest = NewOrderRequest{
Symbol: p.FirstCurrency.String() + p.SecondCurrency.String(),
Symbol: p.Base.String() + p.Quote.String(),
Side: sideType,
Price: price,
Quantity: amount,
@@ -271,7 +291,7 @@ func (b *Binance) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
}
// GetDepositAddress returns a deposit address for a specified currency
func (b *Binance) GetDepositAddress(cryptocurrency pair.CurrencyItem, _ string) (string, error) {
func (b *Binance) GetDepositAddress(cryptocurrency currency.Code, _ string) (string, error) {
return b.GetDepositAddressForCurrency(cryptocurrency.String())
}
@@ -313,8 +333,8 @@ func (b *Binance) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) ([
}
var orders []exchange.OrderDetail
for _, currency := range getOrdersRequest.Currencies {
resp, err := b.OpenOrders(exchange.FormatExchangeCurrency(b.Name, currency).String())
for _, c := range getOrdersRequest.Currencies {
resp, err := b.OpenOrders(exchange.FormatExchangeCurrency(b.Name, c).String())
if err != nil {
return nil, err
}
@@ -333,7 +353,7 @@ func (b *Binance) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) ([
OrderType: orderType,
Price: order.Price,
Status: order.Status,
CurrencyPair: pair.NewCurrencyPairFromString(order.Symbol),
CurrencyPair: currency.NewPairFromString(order.Symbol),
})
}
}
@@ -353,8 +373,8 @@ func (b *Binance) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) ([
}
var orders []exchange.OrderDetail
for _, currency := range getOrdersRequest.Currencies {
resp, err := b.AllOrders(exchange.FormatExchangeCurrency(b.Name, currency).String(), "", "1000")
for _, c := range getOrdersRequest.Currencies {
resp, err := b.AllOrders(exchange.FormatExchangeCurrency(b.Name, c).String(), "", "1000")
if err != nil {
return nil, err
}
@@ -376,7 +396,7 @@ func (b *Binance) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) ([
OrderSide: orderSide,
OrderType: orderType,
Price: order.Price,
CurrencyPair: pair.NewCurrencyPairFromString(order.Symbol),
CurrencyPair: currency.NewPairFromString(order.Symbol),
Status: order.Status,
})
}

View File

@@ -11,7 +11,7 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -130,9 +130,9 @@ func (b *Bitfinex) Setup(exch config.ExchangeConfig) {
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket.SetWsStatusAndConnection(exch.Websocket)
b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
b.BaseCurrencies = exch.BaseCurrencies
b.AvailablePairs = exch.AvailablePairs
b.EnabledPairs = exch.EnabledPairs
err := b.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)
@@ -196,7 +196,8 @@ func (b *Bitfinex) GetLatestSpotPrice(symbol string) (float64, error) {
// GetTicker returns ticker information
func (b *Bitfinex) GetTicker(symbol string) (Ticker, error) {
response := Ticker{}
path := common.EncodeURLValues(b.APIUrl+bitfinexAPIVersion+bitfinexTicker+symbol, url.Values{})
path := common.EncodeURLValues(b.APIUrl+bitfinexAPIVersion+bitfinexTicker+symbol,
url.Values{})
if err := b.SendHTTPRequest(path, &response, b.Verbose); err != nil {
return response, err
@@ -214,7 +215,11 @@ func (b *Bitfinex) GetTickerV2(symb string) (Tickerv2, error) {
var response []interface{}
var tick Tickerv2
path := fmt.Sprintf("%s/v%s/%s/%s", b.APIUrl, bitfinexAPIVersion2, bitfinexTickerV2, symb)
path := fmt.Sprintf("%s/v%s/%s/%s",
b.APIUrl,
bitfinexAPIVersion2,
bitfinexTickerV2,
symb)
err := b.SendHTTPRequest(path, &response, b.Verbose)
if err != nil {
return tick, err
@@ -464,7 +469,8 @@ func (b *Bitfinex) GetLendbook(symbol string, values url.Values) (Lendbook, erro
if len(symbol) == 6 {
symbol = symbol[:3]
}
path := common.EncodeURLValues(b.APIUrl+bitfinexAPIVersion+bitfinexLendbook+symbol, values)
path := common.EncodeURLValues(b.APIUrl+bitfinexAPIVersion+bitfinexLendbook+symbol,
values)
return response, b.SendHTTPRequest(path, &response, b.Verbose)
}
@@ -475,7 +481,8 @@ func (b *Bitfinex) GetLendbook(symbol string, values url.Values) (Lendbook, erro
// Symbol - example "USD"
func (b *Bitfinex) GetLends(symbol string, values url.Values) ([]Lends, error) {
response := []Lends{}
path := common.EncodeURLValues(b.APIUrl+bitfinexAPIVersion+bitfinexLends+symbol, values)
path := common.EncodeURLValues(b.APIUrl+bitfinexAPIVersion+bitfinexLends+symbol,
values)
return response, b.SendHTTPRequest(path, &response, b.Verbose)
}
@@ -496,16 +503,19 @@ func (b *Bitfinex) GetSymbolsDetails() ([]SymbolDetails, error) {
return response, b.SendHTTPRequest(path, &response, b.Verbose)
}
// GetAccountInformation returns information about your account incl. trading fees
// GetAccountInformation returns information about your account incl. trading
// fees
func (b *Bitfinex) GetAccountInformation() ([]AccountInfo, error) {
var responses []AccountInfo
return responses, b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexAccountInfo, nil, &responses)
return responses, b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexAccountInfo, nil, &responses)
}
// GetAccountFees - Gets all fee rates for all currencies
func (b *Bitfinex) GetAccountFees() (AccountFees, error) {
response := AccountFees{}
return response, b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexAccountFees, nil, &response)
return response, b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexAccountFees, nil, &response)
}
// GetAccountSummary returns a 30-day summary of your trading volume and return
@@ -532,7 +542,10 @@ func (b *Bitfinex) NewDeposit(method, walletName string, renew int) (DepositResp
req["renew"] = renew
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexDeposit, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexDeposit,
req,
&response)
}
// GetKeyPermissions checks the permissions of the key being used to generate
@@ -541,7 +554,8 @@ func (b *Bitfinex) GetKeyPermissions() (KeyPermissions, error) {
response := KeyPermissions{}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexKeyPermissions, nil, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexKeyPermissions, nil, &response)
}
// GetMarginInfo shows your trading wallet information for margin trading
@@ -549,7 +563,8 @@ func (b *Bitfinex) GetMarginInfo() ([]MarginInfo, error) {
response := []MarginInfo{}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexMarginInfo, nil, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexMarginInfo, nil, &response)
}
// GetAccountBalance returns full wallet balance information
@@ -557,7 +572,8 @@ func (b *Bitfinex) GetAccountBalance() ([]Balance, error) {
response := []Balance{}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexBalances, nil, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexBalances, nil, &response)
}
// WalletTransfer move available balances between your wallets
@@ -574,32 +590,40 @@ func (b *Bitfinex) WalletTransfer(amount float64, currency, walletFrom, walletTo
req["walletTo"] = walletTo
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexTransfer, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexTransfer,
req,
&response)
}
// WithdrawCryptocurrency requests a withdrawal from one of your wallets.
// For FIAT, use WithdrawFIAT
func (b *Bitfinex) WithdrawCryptocurrency(withdrawType, wallet, address, currency, paymentID string, amount float64) ([]Withdrawal, error) {
func (b *Bitfinex) WithdrawCryptocurrency(withdrawType, wallet, address, paymentID string, amount float64, c currency.Code) ([]Withdrawal, error) {
response := []Withdrawal{}
req := make(map[string]interface{})
req["withdraw_type"] = withdrawType
req["walletselected"] = wallet
req["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
req["address"] = address
if currency == symbol.XMR {
if c == currency.XMR {
req["paymend_id"] = paymentID
}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexWithdrawal, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexWithdrawal,
req,
&response)
}
// WithdrawFIAT requests a withdrawal from one of your wallets.
// For Cryptocurrency, use WithdrawCryptocurrency
func (b *Bitfinex) WithdrawFIAT(withdrawType, wallet, wireCurrency,
accountName, bankName, bankAddress, bankCity, bankCountry, swift, transactionMessage,
intermediaryBankName, intermediaryBankAddress, intermediaryBankCity, intermediaryBankCountry, intermediaryBankSwift string,
amount, accountNumber, intermediaryBankAccountNumber float64, isExpressWire, requiresIntermediaryBank bool) ([]Withdrawal, error) {
accountName, bankName, bankAddress, bankCity, bankCountry, swift,
transactionMessage, intermediaryBankName, intermediaryBankAddress,
intermediaryBankCity, intermediaryBankCountry, intermediaryBankSwift string,
amount, accountNumber, intermediaryBankAccountNumber float64, isExpressWire,
requiresIntermediaryBank bool) ([]Withdrawal, error) {
response := []Withdrawal{}
req := make(map[string]interface{})
req["withdraw_type"] = withdrawType
@@ -622,12 +646,18 @@ func (b *Bitfinex) WithdrawFIAT(withdrawType, wallet, wireCurrency,
req["intermediary_bank_address"] = intermediaryBankAddress
req["intermediary_bank_city"] = intermediaryBankCity
req["intermediary_bank_country"] = intermediaryBankCountry
req["intermediary_bank_account"] = strconv.FormatFloat(intermediaryBankAccountNumber, 'f', -1, 64)
req["intermediary_bank_account"] = strconv.FormatFloat(intermediaryBankAccountNumber,
'f',
-1,
64)
req["intermediary_bank_swift"] = intermediaryBankSwift
}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexWithdrawal, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexWithdrawal,
req,
&response)
}
// NewOrder submits a new order and returns a order information
@@ -649,7 +679,10 @@ func (b *Bitfinex) NewOrder(currencyPair string, amount, price float64, buy bool
}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexOrderNew, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexOrderNew,
req,
&response)
}
// NewOrderMulti allows several new orders at once
@@ -659,7 +692,10 @@ func (b *Bitfinex) NewOrderMulti(orders []PlaceOrder) (OrderMultiResponse, error
req["orders"] = orders
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexOrderNewMulti, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexOrderNewMulti,
req,
&response)
}
// CancelExistingOrder cancels a single order by OrderID
@@ -669,7 +705,10 @@ func (b *Bitfinex) CancelExistingOrder(orderID int64) (Order, error) {
req["order_id"] = orderID
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexOrderCancel, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexOrderCancel,
req,
&response)
}
// CancelMultipleOrders cancels multiple orders
@@ -679,7 +718,10 @@ func (b *Bitfinex) CancelMultipleOrders(orderIDs []int64) (string, error) {
req["order_ids"] = orderIDs
return response.Result,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexOrderCancelMulti, req, nil)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexOrderCancelMulti,
req,
nil)
}
// CancelAllExistingOrders cancels all active and open orders
@@ -687,7 +729,10 @@ func (b *Bitfinex) CancelAllExistingOrders() (string, error) {
response := GenericResponse{}
return response.Result,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexOrderCancelAll, nil, nil)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexOrderCancelAll,
nil,
nil)
}
// ReplaceOrder replaces an older order with a new order
@@ -709,7 +754,10 @@ func (b *Bitfinex) ReplaceOrder(orderID int64, symbol string, amount, price floa
}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexOrderCancelReplace, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexOrderCancelReplace,
req,
&response)
}
// GetOrderStatus returns order status information
@@ -719,7 +767,10 @@ func (b *Bitfinex) GetOrderStatus(orderID int64) (Order, error) {
req["order_id"] = orderID
return orderStatus,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexOrderStatus, req, &orderStatus)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexOrderStatus,
req,
&orderStatus)
}
// GetInactiveOrders returns order status information
@@ -729,7 +780,10 @@ func (b *Bitfinex) GetInactiveOrders() ([]Order, error) {
req["limit"] = "100"
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexInactiveOrders, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexInactiveOrders,
req,
&response)
}
// GetOpenOrders returns all active orders and statuses
@@ -737,7 +791,10 @@ func (b *Bitfinex) GetOpenOrders() ([]Order, error) {
var response []Order
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexOrders, nil, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexOrders,
nil,
&response)
}
// GetActivePositions returns an array of active positions
@@ -745,7 +802,10 @@ func (b *Bitfinex) GetActivePositions() ([]Position, error) {
response := []Position{}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexPositions, nil, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexPositions,
nil,
&response)
}
// ClaimPosition allows positions to be claimed
@@ -755,7 +815,10 @@ func (b *Bitfinex) ClaimPosition(positionID int) (Position, error) {
req["position_id"] = positionID
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexClaimPosition, nil, nil)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexClaimPosition,
nil,
nil)
}
// GetBalanceHistory returns balance history for the account
@@ -778,7 +841,10 @@ func (b *Bitfinex) GetBalanceHistory(symbol string, timeSince, timeUntil time.Ti
}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexHistory, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexHistory,
req,
&response)
}
// GetMovementHistory returns an array of past deposits and withdrawals
@@ -801,7 +867,10 @@ func (b *Bitfinex) GetMovementHistory(symbol, method string, timeSince, timeUnti
}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexHistoryMovements, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexHistoryMovements,
req,
&response)
}
// GetTradeHistory returns past executed trades
@@ -822,7 +891,10 @@ func (b *Bitfinex) GetTradeHistory(currencyPair string, timestamp, until time.Ti
}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexTradeHistory, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexTradeHistory,
req,
&response)
}
// NewOffer submits a new offer
@@ -836,7 +908,10 @@ func (b *Bitfinex) NewOffer(symbol string, amount, rate float64, period int64, d
req["direction"] = direction
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexOfferNew, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexOfferNew,
req,
&response)
}
// CancelOffer cancels offer by offerID
@@ -846,7 +921,10 @@ func (b *Bitfinex) CancelOffer(offerID int64) (Offer, error) {
req["offer_id"] = offerID
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexOfferCancel, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexOfferCancel,
req,
&response)
}
// GetOfferStatus checks offer status whether it has been cancelled, execute or
@@ -857,7 +935,10 @@ func (b *Bitfinex) GetOfferStatus(offerID int64) (Offer, error) {
req["offer_id"] = offerID
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexOrderStatus, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexOrderStatus,
req,
&response)
}
// GetActiveCredits returns all available credits
@@ -865,7 +946,10 @@ func (b *Bitfinex) GetActiveCredits() ([]Offer, error) {
response := []Offer{}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexActiveCredits, nil, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexActiveCredits,
nil,
&response)
}
// GetActiveOffers returns all current active offers
@@ -873,7 +957,10 @@ func (b *Bitfinex) GetActiveOffers() ([]Offer, error) {
response := []Offer{}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexOffers, nil, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexOffers,
nil,
&response)
}
// GetActiveMarginFunding returns an array of active margin funds
@@ -881,7 +968,10 @@ func (b *Bitfinex) GetActiveMarginFunding() ([]MarginFunds, error) {
response := []MarginFunds{}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexMarginActiveFunds, nil, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexMarginActiveFunds,
nil,
&response)
}
// GetUnusedMarginFunds returns an array of funding borrowed but not currently
@@ -890,7 +980,10 @@ func (b *Bitfinex) GetUnusedMarginFunds() ([]MarginFunds, error) {
response := []MarginFunds{}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexMarginUnusedFunds, nil, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexMarginUnusedFunds,
nil,
&response)
}
// GetMarginTotalTakenFunds returns an array of active funding used in a
@@ -899,7 +992,10 @@ func (b *Bitfinex) GetMarginTotalTakenFunds() ([]MarginTotalTakenFunds, error) {
response := []MarginTotalTakenFunds{}
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexMarginTotalFunds, nil, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexMarginTotalFunds,
nil,
&response)
}
// CloseMarginFunding closes an unused or used taken fund
@@ -909,7 +1005,10 @@ func (b *Bitfinex) CloseMarginFunding(swapID int64) (Offer, error) {
req["swap_id"] = swapID
return response,
b.SendAuthenticatedHTTPRequest(http.MethodPost, bitfinexMarginClose, req, &response)
b.SendAuthenticatedHTTPRequest(http.MethodPost,
bitfinexMarginClose,
req,
&response)
}
// SendHTTPRequest sends an unauthenticated request
@@ -921,7 +1020,8 @@ func (b *Bitfinex) SendHTTPRequest(path string, result interface{}, verbose bool
// unmarshals result to a supplied variable
func (b *Bitfinex) SendAuthenticatedHTTPRequest(method, path string, params map[string]interface{}, result interface{}) error {
if !b.AuthenticatedAPISupport {
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name)
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet,
b.Name)
}
if b.Nonce.Get() == 0 {
@@ -948,13 +1048,20 @@ func (b *Bitfinex) SendAuthenticatedHTTPRequest(method, path string, params map[
}
PayloadBase64 := common.Base64Encode(PayloadJSON)
hmac := common.GetHMAC(common.HashSHA512_384, []byte(PayloadBase64), []byte(b.APISecret))
hmac := common.GetHMAC(common.HashSHA512_384, []byte(PayloadBase64),
[]byte(b.APISecret))
headers := make(map[string]string)
headers["X-BFX-APIKEY"] = b.APIKey
headers["X-BFX-PAYLOAD"] = PayloadBase64
headers["X-BFX-SIGNATURE"] = common.HexEncodeToString(hmac)
return b.SendPayload(method, b.APIUrl+bitfinexAPIVersion+path, headers, nil, result, true, b.Verbose)
return b.SendPayload(method,
b.APIUrl+bitfinexAPIVersion+path,
headers,
nil,
result,
true,
b.Verbose)
}
// GetFee returns an estimate of fee based on type of transaction
@@ -967,7 +1074,11 @@ func (b *Bitfinex) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
if err != nil {
return 0, err
}
fee, err = b.CalculateTradingFee(accountInfos, feeBuilder.PurchasePrice, feeBuilder.Amount, feeBuilder.FirstCurrency, feeBuilder.IsMaker)
fee, err = b.CalculateTradingFee(accountInfos,
feeBuilder.PurchasePrice,
feeBuilder.Amount,
feeBuilder.Pair.Base,
feeBuilder.IsMaker)
if err != nil {
return 0, err
}
@@ -979,7 +1090,8 @@ func (b *Bitfinex) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
if err != nil {
return 0, err
}
fee, err = b.GetCryptocurrencyWithdrawalFee(feeBuilder.FirstCurrency, accountFees)
fee, err = b.GetCryptocurrencyWithdrawalFee(feeBuilder.Pair.Base,
accountFees)
if err != nil {
return 0, err
}
@@ -995,8 +1107,8 @@ func (b *Bitfinex) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
}
// GetCryptocurrencyWithdrawalFee returns an estimate of fee based on type of transaction
func (b *Bitfinex) GetCryptocurrencyWithdrawalFee(currency string, accountFees AccountFees) (fee float64, err error) {
switch result := accountFees.Withdraw[currency].(type) {
func (b *Bitfinex) GetCryptocurrencyWithdrawalFee(c currency.Code, accountFees AccountFees) (fee float64, err error) {
switch result := accountFees.Withdraw[c.String()].(type) {
case string:
fee, err = strconv.ParseFloat(result, 64)
if err != nil {
@@ -1018,10 +1130,10 @@ func getInternationalBankWithdrawalFee(amount float64) float64 {
}
// CalculateTradingFee returns an estimate of fee based on type of whether is maker or taker fee
func (b *Bitfinex) CalculateTradingFee(accountInfos []AccountInfo, purchasePrice, amount float64, currency string, isMaker bool) (fee float64, err error) {
func (b *Bitfinex) CalculateTradingFee(accountInfos []AccountInfo, purchasePrice, amount float64, c currency.Code, isMaker bool) (fee float64, err error) {
for _, i := range accountInfos {
for _, j := range i.Fees {
if currency == j.Pairs {
if c.String() == j.Pairs {
if isMaker {
fee = j.MakerFees
} else {
@@ -1038,77 +1150,75 @@ func (b *Bitfinex) CalculateTradingFee(accountInfos []AccountInfo, purchasePrice
}
// ConvertSymbolToWithdrawalType You need to have specific withdrawal types to withdraw from Bitfinex
func (b *Bitfinex) ConvertSymbolToWithdrawalType(currency string) string {
switch currency {
case symbol.BTC:
func (b *Bitfinex) ConvertSymbolToWithdrawalType(c currency.Code) string {
switch c {
case currency.BTC:
return "bitcoin"
case symbol.LTC:
case currency.LTC:
return "litecoin"
case symbol.ETH:
case currency.ETH:
return "ethereum"
case symbol.ETC:
case currency.ETC:
return "ethereumc"
case symbol.USDT:
case currency.USDT:
return "tetheruso"
case "Wire":
return "wire"
case symbol.ZEC:
case currency.ZEC:
return "zcash"
case symbol.XMR:
case currency.XMR:
return "monero"
case symbol.DSH:
case currency.DSH:
return "dash"
case symbol.XRP:
case currency.XRP:
return "ripple"
case symbol.SAN:
case currency.SAN:
return "santiment"
case symbol.OMG:
case currency.OMG:
return "omisego"
case symbol.BCH:
case currency.BCH:
return "bcash"
case symbol.ETP:
case currency.ETP:
return "metaverse"
case symbol.AVT:
case currency.AVT:
return "aventus"
case symbol.EDO:
case currency.EDO:
return "eidoo"
case symbol.BTG:
case currency.BTG:
return "bgold"
case symbol.DATA:
case currency.DATA:
return "datacoin"
case symbol.GNT:
case currency.GNT:
return "golem"
case symbol.SNT:
case currency.SNT:
return "status"
default:
return common.StringToLower(currency)
return c.Lower().String()
}
}
// ConvertSymbolToDepositMethod returns a converted currency deposit method
func (b *Bitfinex) ConvertSymbolToDepositMethod(currency string) (method string, err error) {
switch currency {
case symbol.BTC:
func (b *Bitfinex) ConvertSymbolToDepositMethod(c currency.Code) (method string, err error) {
switch c {
case currency.BTC:
method = "bitcoin"
case symbol.LTC:
case currency.LTC:
method = "litecoin"
case symbol.ETH:
case currency.ETH:
method = "ethereum"
case symbol.ETC:
case currency.ETC:
method = "ethereumc"
case symbol.USDT:
case currency.USDT:
method = "tetheruso"
case symbol.ZEC:
case currency.ZEC:
method = "zcash"
case symbol.XMR:
case currency.XMR:
method = "monero"
case symbol.BCH:
case currency.BCH:
method = "bcash"
case symbol.MIOTA:
case currency.MIOTA:
method = "iota"
default:
err = fmt.Errorf("currency %s not supported in method list",
currency)
c)
}
return
}

View File

@@ -8,8 +8,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
)
@@ -613,13 +612,10 @@ func TestCloseMarginFunding(t *testing.T) {
func setFeeBuilder() exchange.FeeBuilder {
return exchange.FeeBuilder{
Amount: 1,
Delimiter: "",
FeeType: exchange.CryptocurrencyTradeFee,
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
IsMaker: false,
PurchasePrice: 1,
Amount: 1,
FeeType: exchange.CryptocurrencyTradeFee,
Pair: currency.NewPair(currency.BTC, currency.LTC),
PurchasePrice: 1,
}
}
@@ -680,7 +676,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankDepositFee
feeBuilder.CurrencyItem = symbol.HKD
feeBuilder.FiatCurrency = currency.HKD
if resp, err := b.GetFee(feeBuilder); resp != float64(0.001) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.001), resp)
t.Error(err)
@@ -689,7 +685,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.CurrencyItem = symbol.HKD
feeBuilder.FiatCurrency = currency.HKD
if resp, err := b.GetFee(feeBuilder); resp != float64(0.001) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.001), resp)
t.Error(err)
@@ -756,10 +752,10 @@ func TestSubmitOrder(t *testing.T) {
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var p = pair.CurrencyPair{
Delimiter: "",
FirstCurrency: symbol.LTC,
SecondCurrency: symbol.BTC,
var p = currency.Pair{
Delimiter: "",
Base: currency.LTC,
Quote: currency.BTC,
}
response, err := b.SubmitOrder(p, exchange.BuyOrderSide, exchange.MarketOrderType, 1, 1, "clientId")
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
@@ -777,7 +773,7 @@ func TestCancelExchangeOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -803,7 +799,7 @@ func TestCancelAllExchangeOrdera(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -842,7 +838,7 @@ func TestWithdraw(t *testing.T) {
var withdrawCryptoRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.BTC,
Currency: currency.BTC,
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
Description: "WITHDRAW IT ALL",
}
@@ -866,7 +862,7 @@ func TestWithdrawFiat(t *testing.T) {
var withdrawFiatRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.BTC,
Currency: currency.BTC,
Description: "WITHDRAW IT ALL",
BankAccountName: "Satoshi Nakamoto",
BankAccountNumber: 12345,
@@ -874,7 +870,7 @@ func TestWithdrawFiat(t *testing.T) {
BankCity: "Tarry Town",
BankCountry: "Hyrule",
BankName: "Federal Reserve Bank",
WireCurrency: symbol.USD,
WireCurrency: currency.USD.String(),
SwiftCode: "Taylor",
RequiresIntermediaryBank: false,
IsExpressWire: false,
@@ -899,7 +895,7 @@ func TestWithdrawInternationalBank(t *testing.T) {
var withdrawFiatRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.BTC,
Currency: currency.BTC,
Description: "WITHDRAW IT ALL",
BankAccountName: "Satoshi Nakamoto",
BankAccountNumber: 12345,
@@ -907,7 +903,7 @@ func TestWithdrawInternationalBank(t *testing.T) {
BankCity: "Tarry Town",
BankCountry: "Hyrule",
BankName: "Federal Reserve Bank",
WireCurrency: symbol.USD,
WireCurrency: currency.USD.String(),
SwiftCode: "Taylor",
RequiresIntermediaryBank: true,
IsExpressWire: false,
@@ -930,12 +926,12 @@ func TestWithdrawInternationalBank(t *testing.T) {
func TestGetDepositAddress(t *testing.T) {
if areTestAPIKeysSet() {
_, err := b.GetDepositAddress(symbol.BTC, "deposit")
_, err := b.GetDepositAddress(currency.BTC, "deposit")
if err != nil {
t.Error("Test Failed - GetDepositAddress() error", err)
}
} else {
_, err := b.GetDepositAddress(symbol.BTC, "deposit")
_, err := b.GetDepositAddress(currency.BTC, "deposit")
if err == nil {
t.Error("Test Failed - GetDepositAddress() error cannot be nil")
}

View File

@@ -11,7 +11,7 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
log "github.com/thrasher-/gocryptotrader/logger"
@@ -171,7 +171,7 @@ func (b *Bitfinex) WsConnect() error {
if x == "book" {
params["prec"] = "P0"
}
params["pair"] = y
params["pair"] = y.String()
err = b.WsSubscribe(x, params)
if err != nil {
return err
@@ -306,7 +306,7 @@ func (b *Bitfinex) WsDataHandler() {
}
if len(newOrderbook) > 1 {
err := b.WsInsertSnapshot(pair.NewCurrencyPairFromString(chanInfo.Pair),
err := b.WsInsertSnapshot(currency.NewPairFromString(chanInfo.Pair),
"SPOT",
newOrderbook)
@@ -317,7 +317,7 @@ func (b *Bitfinex) WsDataHandler() {
continue
}
err := b.WsUpdateOrderbook(pair.NewCurrencyPairFromString(chanInfo.Pair),
err := b.WsUpdateOrderbook(currency.NewPairFromString(chanInfo.Pair),
"SPOT",
newOrderbook[0])
@@ -332,7 +332,7 @@ func (b *Bitfinex) WsDataHandler() {
ClosePrice: chanData[7].(float64),
HighPrice: chanData[9].(float64),
LowPrice: chanData[10].(float64),
Pair: pair.NewCurrencyPairFromString(chanInfo.Pair),
Pair: currency.NewPairFromString(chanInfo.Pair),
Exchange: b.GetName(),
AssetType: "SPOT",
}
@@ -485,7 +485,7 @@ func (b *Bitfinex) WsDataHandler() {
}
b.Websocket.DataHandler <- exchange.TradeData{
CurrencyPair: pair.NewCurrencyPairFromString(chanInfo.Pair),
CurrencyPair: currency.NewPairFromString(chanInfo.Pair),
Timestamp: time.Unix(trades[0].Timestamp, 0),
Price: trades[0].Price,
Amount: newAmount,
@@ -504,7 +504,7 @@ func (b *Bitfinex) WsDataHandler() {
// WsInsertSnapshot add the initial orderbook snapshot when subscribed to a
// channel
func (b *Bitfinex) WsInsertSnapshot(p pair.CurrencyPair, assetType string, books []WebsocketBook) error {
func (b *Bitfinex) WsInsertSnapshot(p currency.Pair, assetType string, books []WebsocketBook) error {
if len(books) == 0 {
return errors.New("bitfinex.go error - no orderbooks submitted")
}
@@ -526,8 +526,6 @@ func (b *Bitfinex) WsInsertSnapshot(p pair.CurrencyPair, assetType string, books
newOrderbook.Asks = ask
newOrderbook.AssetType = assetType
newOrderbook.Bids = bid
newOrderbook.CurrencyPair = p.Pair().String()
newOrderbook.LastUpdated = time.Now()
newOrderbook.Pair = p
err := b.Websocket.Orderbook.LoadSnapshot(newOrderbook, b.GetName(), false)
@@ -543,7 +541,7 @@ func (b *Bitfinex) WsInsertSnapshot(p pair.CurrencyPair, assetType string, books
// WsUpdateOrderbook updates the orderbook list, removing and adding to the
// orderbook sides
func (b *Bitfinex) WsUpdateOrderbook(p pair.CurrencyPair, assetType string, book WebsocketBook) error {
func (b *Bitfinex) WsUpdateOrderbook(p currency.Pair, assetType string, book WebsocketBook) error {
if book.Count > 0 {
if book.Amount > 0 {

View File

@@ -10,7 +10,7 @@ import (
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -38,7 +38,13 @@ func (b *Bitfinex) Run() {
if err != nil {
log.Errorf("%s Failed to get available symbols.\n", b.GetName())
} else {
err = b.UpdateCurrencies(exchangeProducts, false, false)
var newExchangeProducts currency.Pairs
for _, p := range exchangeProducts {
newExchangeProducts = append(newExchangeProducts,
currency.NewPairFromString(p))
}
err = b.UpdateCurrencies(newExchangeProducts, false, false)
if err != nil {
log.Errorf("%s Failed to update available symbols.\n", b.GetName())
}
@@ -46,13 +52,13 @@ func (b *Bitfinex) Run() {
}
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bitfinex) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *Bitfinex) UpdateTicker(p currency.Pair, assetType string) (ticker.Price, error) {
var tickerPrice ticker.Price
enabledPairs := b.GetEnabledCurrencies()
var pairs []string
for x := range enabledPairs {
pairs = append(pairs, "t"+enabledPairs[x].Pair().String())
pairs = append(pairs, "t"+enabledPairs[x].String())
}
tickerNew, err := b.GetTickersV2(common.JoinStrings(pairs, ","))
@@ -61,7 +67,9 @@ func (b *Bitfinex) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.P
}
for x := range tickerNew {
newP := pair.NewCurrencyPair(tickerNew[x].Symbol[1:4], tickerNew[x].Symbol[4:])
newP := currency.NewPairFromStrings(tickerNew[x].Symbol[1:4],
tickerNew[x].Symbol[4:])
var tick ticker.Price
tick.Pair = newP
tick.Ask = tickerNew[x].Ask
@@ -70,13 +78,17 @@ func (b *Bitfinex) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.P
tick.Last = tickerNew[x].Last
tick.Volume = tickerNew[x].Volume
tick.High = tickerNew[x].High
ticker.ProcessTicker(b.Name, tick.Pair, tick, assetType)
err = ticker.ProcessTicker(b.Name, tick, assetType)
if err != nil {
return tickerPrice, err
}
}
return ticker.GetTicker(b.Name, p, assetType)
}
// GetTickerPrice returns the ticker for a currency pair
func (b *Bitfinex) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *Bitfinex) GetTickerPrice(p currency.Pair, assetType string) (ticker.Price, error) {
tick, err := ticker.GetTicker(b.GetName(), p, ticker.Spot)
if err != nil {
return b.UpdateTicker(p, assetType)
@@ -85,8 +97,8 @@ func (b *Bitfinex) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker
}
// GetOrderbookEx returns the orderbook for a currency pair
func (b *Bitfinex) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.GetOrderbook(b.GetName(), p, assetType)
func (b *Bitfinex) GetOrderbookEx(p currency.Pair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.Get(b.GetName(), p, assetType)
if err != nil {
return b.UpdateOrderbook(p, assetType)
}
@@ -94,26 +106,38 @@ func (b *Bitfinex) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderb
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (b *Bitfinex) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
func (b *Bitfinex) UpdateOrderbook(p currency.Pair, assetType string) (orderbook.Base, error) {
var orderBook orderbook.Base
urlVals := url.Values{}
urlVals.Set("limit_bids", "100")
urlVals.Set("limit_asks", "100")
orderbookNew, err := b.GetOrderbook(p.Pair().String(), urlVals)
orderbookNew, err := b.GetOrderbook(p.String(), urlVals)
if err != nil {
return orderBook, err
}
for x := range orderbookNew.Asks {
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Price: orderbookNew.Asks[x].Price, Amount: orderbookNew.Asks[x].Amount})
orderBook.Asks = append(orderBook.Asks,
orderbook.Item{Price: orderbookNew.Asks[x].Price,
Amount: orderbookNew.Asks[x].Amount})
}
for x := range orderbookNew.Bids {
orderBook.Bids = append(orderBook.Bids, orderbook.Item{Price: orderbookNew.Bids[x].Price, Amount: orderbookNew.Bids[x].Amount})
orderBook.Bids = append(orderBook.Bids,
orderbook.Item{Price: orderbookNew.Bids[x].Price,
Amount: orderbookNew.Bids[x].Amount})
}
orderbook.ProcessOrderbook(b.GetName(), p, orderBook, assetType)
return orderbook.GetOrderbook(b.Name, p, assetType)
orderBook.Pair = p
orderBook.ExchangeName = b.GetName()
orderBook.AssetType = assetType
err = orderBook.Process()
if err != nil {
return orderBook, err
}
return orderbook.Get(b.Name, p, assetType)
}
// GetAccountInfo retrieves balances for all enabled currencies on the
@@ -137,7 +161,7 @@ func (b *Bitfinex) GetAccountInfo() (exchange.AccountInfo, error) {
if Accounts[i].ID == bal.Type {
Accounts[i].Currencies = append(Accounts[i].Currencies,
exchange.AccountCurrencyInfo{
CurrencyName: bal.Currency,
CurrencyName: currency.NewCode(bal.Currency),
TotalValue: bal.Amount,
Hold: bal.Amount - bal.Available,
})
@@ -157,14 +181,14 @@ func (b *Bitfinex) GetFundingHistory() ([]exchange.FundHistory, error) {
}
// GetExchangeHistory returns historic trade data since exchange opening.
func (b *Bitfinex) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
func (b *Bitfinex) GetExchangeHistory(p currency.Pair, assetType string) ([]exchange.TradeHistory, error) {
var resp []exchange.TradeHistory
return resp, common.ErrNotYetImplemented
}
// SubmitOrder submits a new order
func (b *Bitfinex) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
func (b *Bitfinex) SubmitOrder(p currency.Pair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
var submitOrderResponse exchange.SubmitOrderResponse
var isBuying bool
@@ -172,7 +196,12 @@ func (b *Bitfinex) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, ord
isBuying = true
}
response, err := b.NewOrder(p.Pair().String(), amount, price, isBuying, orderType.ToString(), false)
response, err := b.NewOrder(p.String(),
amount,
price,
isBuying,
orderType.ToString(),
false)
if response.OrderID > 0 {
submitOrderResponse.OrderID = fmt.Sprintf("%v", response.OrderID)
@@ -217,8 +246,8 @@ func (b *Bitfinex) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
}
// GetDepositAddress returns a deposit address for a specified currency
func (b *Bitfinex) GetDepositAddress(cryptocurrency pair.CurrencyItem, accountID string) (string, error) {
method, err := b.ConvertSymbolToDepositMethod(cryptocurrency.String())
func (b *Bitfinex) GetDepositAddress(cryptocurrency currency.Code, accountID string) (string, error) {
method, err := b.ConvertSymbolToDepositMethod(cryptocurrency)
if err != nil {
return "", err
}
@@ -233,12 +262,17 @@ func (b *Bitfinex) GetDepositAddress(cryptocurrency pair.CurrencyItem, accountID
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is submitted
func (b *Bitfinex) WithdrawCryptocurrencyFunds(withdrawRequest exchange.WithdrawRequest) (string, error) {
withdrawalType := b.ConvertSymbolToWithdrawalType(withdrawRequest.Currency.String())
withdrawalType := b.ConvertSymbolToWithdrawalType(withdrawRequest.Currency)
// Bitfinex has support for three types, exchange, margin and deposit
// As this is for trading, I've made the wrapper default 'exchange'
// TODO: Discover an automated way to make the decision for wallet type to withdraw from
walletType := "exchange"
resp, err := b.WithdrawCryptocurrency(withdrawalType, walletType, withdrawRequest.Address, withdrawRequest.Currency.String(), withdrawRequest.Description, withdrawRequest.Amount)
resp, err := b.WithdrawCryptocurrency(withdrawalType,
walletType,
withdrawRequest.Address,
withdrawRequest.Description,
withdrawRequest.Amount,
withdrawRequest.Currency)
if err != nil {
return "", err
}
@@ -328,7 +362,7 @@ func (b *Bitfinex) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) (
OrderSide: orderSide,
Price: order.Price,
RemainingAmount: order.RemainingAmount,
CurrencyPair: pair.NewCurrencyPairFromString(order.Symbol),
CurrencyPair: currency.NewPairFromString(order.Symbol),
ExecutedAmount: order.ExecutedAmount,
}
@@ -389,7 +423,7 @@ func (b *Bitfinex) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) (
Price: order.Price,
RemainingAmount: order.RemainingAmount,
ExecutedAmount: order.ExecutedAmount,
CurrencyPair: pair.NewCurrencyPairFromString(order.Symbol),
CurrencyPair: currency.NewPairFromString(order.Symbol),
}
switch {

View File

@@ -10,7 +10,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -115,9 +115,9 @@ func (b *Bitflyer) Setup(exch config.ExchangeConfig) {
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket.SetWsStatusAndConnection(exch.Websocket)
b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
b.BaseCurrencies = exch.BaseCurrencies
b.AvailablePairs = exch.AvailablePairs
b.EnabledPairs = exch.EnabledPairs
err := b.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)
@@ -400,9 +400,9 @@ func (b *Bitflyer) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
case exchange.CryptocurrencyTradeFee:
fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount)
case exchange.InternationalBankDepositFee:
fee = getDepositFee(feeBuilder.BankTransactionType, feeBuilder.CurrencyItem)
fee = getDepositFee(feeBuilder.BankTransactionType, feeBuilder.FiatCurrency)
case exchange.InternationalBankWithdrawalFee:
fee = getWithdrawalFee(feeBuilder.BankTransactionType, feeBuilder.CurrencyItem, feeBuilder.Amount)
fee = getWithdrawalFee(feeBuilder.BankTransactionType, feeBuilder.FiatCurrency, feeBuilder.Amount)
}
if fee < 0 {
fee = 0
@@ -417,16 +417,18 @@ func calculateTradingFee(purchasePrice, amount float64) float64 {
return fee * amount * purchasePrice
}
func getDepositFee(bankTransactionType exchange.InternationalBankTransactionType, currency string) (fee float64) {
if bankTransactionType == exchange.WireTransfer && currency == symbol.JPY {
fee = 324
func getDepositFee(bankTransactionType exchange.InternationalBankTransactionType, c currency.Code) (fee float64) {
if bankTransactionType == exchange.WireTransfer {
if c.Item == currency.JPY.Item {
fee = 324
}
}
return fee
}
func getWithdrawalFee(bankTransactionType exchange.InternationalBankTransactionType, currency string, amount float64) (fee float64) {
func getWithdrawalFee(bankTransactionType exchange.InternationalBankTransactionType, c currency.Code, amount float64) (fee float64) {
if bankTransactionType == exchange.WireTransfer {
if currency == symbol.JPY {
if c.Item == currency.JPY.Item {
if amount < 30000 {
fee = 540
} else {

View File

@@ -6,8 +6,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
)
@@ -124,20 +123,20 @@ func TestGetExchangeStatus(t *testing.T) {
func TestCheckFXString(t *testing.T) {
t.Parallel()
p := pair.NewCurrencyPairDelimiter("FXBTC_JPY", "_")
p := currency.NewPairDelimiter("FXBTC_JPY", "_")
p = b.CheckFXString(p)
if p.FirstCurrency.String() != "FX_BTC" {
if p.Base.String() != "FX_BTC" {
t.Error("test failed - Bitflyer - CheckFXString() error")
}
}
func TestGetTickerPrice(t *testing.T) {
t.Parallel()
var p pair.CurrencyPair
var p currency.Pair
currencies := b.GetAvailableCurrencies()
for _, pair := range currencies {
if pair.Pair().String() == "FXBTC_JPY" {
if pair.String() == "FXBTC_JPY" {
p = pair
break
}
@@ -152,13 +151,10 @@ func TestGetTickerPrice(t *testing.T) {
func setFeeBuilder() exchange.FeeBuilder {
return exchange.FeeBuilder{
Amount: 1,
Delimiter: "",
FeeType: exchange.CryptocurrencyTradeFee,
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
IsMaker: false,
Pair: currency.NewPair(currency.BTC, currency.LTC),
PurchasePrice: 1,
CurrencyItem: symbol.JPY,
FiatCurrency: currency.JPY,
BankTransactionType: exchange.WireTransfer,
}
}
@@ -220,7 +216,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankDepositFee
feeBuilder.CurrencyItem = symbol.JPY
feeBuilder.FiatCurrency = currency.JPY
if resp, err := b.GetFee(feeBuilder); resp != float64(324) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(324), resp)
t.Error(err)
@@ -229,7 +225,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.CurrencyItem = symbol.JPY
feeBuilder.FiatCurrency = currency.JPY
if resp, err := b.GetFee(feeBuilder); resp != float64(540) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(540), resp)
t.Error(err)
@@ -295,10 +291,10 @@ func TestSubmitOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var p = pair.CurrencyPair{
Delimiter: "",
FirstCurrency: symbol.LTC,
SecondCurrency: symbol.BTC,
var p = currency.Pair{
Delimiter: "",
Base: currency.LTC,
Quote: currency.BTC,
}
_, err := b.SubmitOrder(p, exchange.BuyOrderSide, exchange.MarketOrderType, 1, 1, "clientId")
if err != common.ErrNotYetImplemented {
@@ -314,7 +310,7 @@ func TestCancelExchangeOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
@@ -337,7 +333,7 @@ func TestCancelAllExchangeOrders(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
WalletAddress: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
@@ -357,7 +353,7 @@ func TestWithdraw(t *testing.T) {
TestSetup(t)
var withdrawCryptoRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.BTC,
Currency: currency.BTC,
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
Description: "WITHDRAW IT ALL",
}

View File

@@ -5,7 +5,7 @@ import (
"sync"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -49,12 +49,12 @@ func (b *Bitflyer) Run() {
}
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bitflyer) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *Bitflyer) UpdateTicker(p currency.Pair, assetType string) (ticker.Price, error) {
var tickerPrice ticker.Price
p = b.CheckFXString(p)
tickerNew, err := b.GetTicker(p.Pair().String())
tickerNew, err := b.GetTicker(p.String())
if err != nil {
return tickerPrice, err
}
@@ -66,12 +66,16 @@ func (b *Bitflyer) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.P
tickerPrice.Last = tickerNew.Last
tickerPrice.Volume = tickerNew.Volume
// tickerPrice.High
ticker.ProcessTicker(b.GetName(), p, tickerPrice, assetType)
err = ticker.ProcessTicker(b.GetName(), tickerPrice, assetType)
if err != nil {
return tickerPrice, err
}
return ticker.GetTicker(b.Name, p, assetType)
}
// GetTickerPrice returns the ticker for a currency pair
func (b *Bitflyer) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *Bitflyer) GetTickerPrice(p currency.Pair, assetType string) (ticker.Price, error) {
tick, err := ticker.GetTicker(b.GetName(), p, ticker.Spot)
if err != nil {
return b.UpdateTicker(p, assetType)
@@ -80,17 +84,17 @@ func (b *Bitflyer) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker
}
// CheckFXString upgrades currency pair if needed
func (b *Bitflyer) CheckFXString(p pair.CurrencyPair) pair.CurrencyPair {
if common.StringContains(p.FirstCurrency.String(), "FX") {
p.FirstCurrency = "FX_BTC"
func (b *Bitflyer) CheckFXString(p currency.Pair) currency.Pair {
if common.StringContains(p.Base.String(), "FX") {
p.Base = currency.FX_BTC
return p
}
return p
}
// GetOrderbookEx returns the orderbook for a currency pair
func (b *Bitflyer) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.GetOrderbook(b.GetName(), p, assetType)
func (b *Bitflyer) GetOrderbookEx(p currency.Pair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.Get(b.GetName(), p, assetType)
if err != nil {
return b.UpdateOrderbook(p, assetType)
}
@@ -98,12 +102,12 @@ func (b *Bitflyer) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderb
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (b *Bitflyer) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
func (b *Bitflyer) UpdateOrderbook(p currency.Pair, assetType string) (orderbook.Base, error) {
var orderBook orderbook.Base
p = b.CheckFXString(p)
orderbookNew, err := b.GetOrderBook(p.Pair().String())
orderbookNew, err := b.GetOrderBook(p.String())
if err != nil {
return orderBook, err
}
@@ -116,8 +120,16 @@ func (b *Bitflyer) UpdateOrderbook(p pair.CurrencyPair, assetType string) (order
orderBook.Bids = append(orderBook.Bids, orderbook.Item{Price: orderbookNew.Bids[x].Price, Amount: orderbookNew.Bids[x].Size})
}
orderbook.ProcessOrderbook(b.GetName(), p, orderBook, assetType)
return orderbook.GetOrderbook(b.Name, p, assetType)
orderBook.Pair = p
orderBook.ExchangeName = b.GetName()
orderBook.AssetType = assetType
err = orderBook.Process()
if err != nil {
return orderBook, err
}
return orderbook.Get(b.Name, p, assetType)
}
// GetAccountInfo retrieves balances for all enabled currencies on the
@@ -146,14 +158,14 @@ func (b *Bitflyer) GetFundingHistory() ([]exchange.FundHistory, error) {
}
// GetExchangeHistory returns historic trade data since exchange opening.
func (b *Bitflyer) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
func (b *Bitflyer) GetExchangeHistory(p currency.Pair, assetType string) ([]exchange.TradeHistory, error) {
var resp []exchange.TradeHistory
return resp, common.ErrNotYetImplemented
}
// SubmitOrder submits a new order
func (b *Bitflyer) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) {
func (b *Bitflyer) SubmitOrder(p currency.Pair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) {
var submitOrderResponse exchange.SubmitOrderResponse
return submitOrderResponse, common.ErrNotYetImplemented
@@ -184,7 +196,7 @@ func (b *Bitflyer) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
}
// GetDepositAddress returns a deposit address for a specified currency
func (b *Bitflyer) GetDepositAddress(cryptocurrency pair.CurrencyItem, accountID string) (string, error) {
func (b *Bitflyer) GetDepositAddress(cryptocurrency currency.Code, accountID string) (string, error) {
return "", common.ErrNotYetImplemented
}

View File

@@ -13,7 +13,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -97,9 +97,9 @@ func (b *Bithumb) Setup(exch config.ExchangeConfig) {
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket.SetWsStatusAndConnection(exch.Websocket)
b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
b.BaseCurrencies = exch.BaseCurrencies
b.AvailablePairs = exch.AvailablePairs
b.EnabledPairs = exch.EnabledPairs
err := b.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)
@@ -614,11 +614,11 @@ func (b *Bithumb) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
case exchange.CryptocurrencyTradeFee:
fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount)
case exchange.CyptocurrencyDepositFee:
fee = getDepositFee(feeBuilder.FirstCurrency, feeBuilder.Amount)
fee = getDepositFee(feeBuilder.Pair.Base, feeBuilder.Amount)
case exchange.CryptocurrencyWithdrawalFee:
fee = getWithdrawalFee(feeBuilder.FirstCurrency)
fee = getWithdrawalFee(feeBuilder.Pair.Base)
case exchange.InternationalBankWithdrawalFee:
fee = getWithdrawalFee(feeBuilder.CurrencyItem)
fee = getWithdrawalFee(feeBuilder.FiatCurrency)
}
if fee < 0 {
fee = 0
@@ -633,31 +633,31 @@ func calculateTradingFee(purchasePrice, amount float64) float64 {
}
// getDepositFee returns fee on a currency when depositing small amounts to bithumb
func getDepositFee(currency string, amount float64) float64 {
func getDepositFee(c currency.Code, amount float64) float64 {
var fee float64
switch currency {
case symbol.BTC:
switch c {
case currency.BTC:
if amount <= 0.005 {
fee = 0.001
}
case symbol.LTC:
case currency.LTC:
if amount <= 0.3 {
fee = 0.01
}
case symbol.DASH:
case currency.DASH:
if amount <= 0.04 {
fee = 0.01
}
case symbol.BCH:
case currency.BCH:
if amount <= 0.03 {
fee = 0.001
}
case symbol.ZEC:
case currency.ZEC:
if amount <= 0.02 {
fee = 0.001
}
case symbol.BTG:
case currency.BTG:
if amount <= 0.15 {
fee = 0.001
}
@@ -667,8 +667,8 @@ func getDepositFee(currency string, amount float64) float64 {
}
// getWithdrawalFee returns fee on a currency when withdrawing out of bithumb
func getWithdrawalFee(currency string) float64 {
return WithdrawalFees[currency]
func getWithdrawalFee(c currency.Code) float64 {
return WithdrawalFees[c]
}
var errCode = map[string]string{

View File

@@ -5,8 +5,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
)
@@ -195,13 +194,10 @@ func TestMarketSellOrder(t *testing.T) {
func setFeeBuilder() exchange.FeeBuilder {
return exchange.FeeBuilder{
Amount: 1,
Delimiter: "",
FeeType: exchange.CryptocurrencyTradeFee,
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
IsMaker: false,
PurchasePrice: 1,
Amount: 1,
FeeType: exchange.CryptocurrencyTradeFee,
Pair: currency.NewPair(currency.BTC, currency.LTC),
PurchasePrice: 1,
}
}
@@ -260,7 +256,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankDepositFee
feeBuilder.CurrencyItem = symbol.HKD
feeBuilder.FiatCurrency = currency.HKD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
@@ -269,7 +265,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.CurrencyItem = symbol.HKD
feeBuilder.FiatCurrency = currency.HKD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
@@ -338,10 +334,10 @@ func TestSubmitOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var p = pair.CurrencyPair{
Delimiter: "",
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
var p = currency.Pair{
Delimiter: "",
Base: currency.BTC,
Quote: currency.LTC,
}
response, err := b.SubmitOrder(p, exchange.BuyOrderSide, exchange.MarketOrderType, 1, 1, "clientId")
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
@@ -359,7 +355,7 @@ func TestCancelExchangeOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -385,7 +381,7 @@ func TestCancelAllExchangeOrders(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -424,12 +420,12 @@ func TestGetAccountInfo(t *testing.T) {
}
func TestModifyOrder(t *testing.T) {
curr := pair.NewCurrencyPairFromString("BTCUSD")
curr := currency.NewPairFromString("BTCUSD")
_, err := b.ModifyOrder(exchange.ModifyOrder{OrderID: "1337",
Price: 100,
Amount: 1000,
OrderSide: exchange.SellOrderSide,
Currency: curr})
Price: 100,
Amount: 1000,
OrderSide: exchange.SellOrderSide,
CurrencyPair: curr})
if err == nil {
t.Error("Test Failed - ModifyOrder() error")
}
@@ -444,7 +440,7 @@ func TestWithdraw(t *testing.T) {
var withdrawCryptoRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.BTC,
Currency: currency.BTC,
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
Description: "WITHDRAW IT ALL",
}
@@ -468,7 +464,7 @@ func TestWithdrawFiat(t *testing.T) {
var withdrawFiatRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.KRW,
Currency: currency.KRW,
Description: "WITHDRAW IT ALL",
BankAccountName: "Satoshi Nakamoto",
BankAccountNumber: 12345,
@@ -477,7 +473,7 @@ func TestWithdrawFiat(t *testing.T) {
BankCity: "Tarry Town",
BankCountry: "Hyrule",
BankName: "Federal Reserve Bank",
WireCurrency: symbol.KRW,
WireCurrency: currency.KRW.String(),
SwiftCode: "Taylor",
RequiresIntermediaryBank: false,
IsExpressWire: false,
@@ -510,12 +506,12 @@ func TestWithdrawInternationalBank(t *testing.T) {
func TestGetDepositAddress(t *testing.T) {
if testAPIKey != "" && testAPISecret != "" {
_, err := b.GetDepositAddress(symbol.BTC, "")
_, err := b.GetDepositAddress(currency.BTC, "")
if err != nil {
t.Error("Test Failed - GetDepositAddress() error", err)
}
} else {
_, err := b.GetDepositAddress(symbol.BTC, "")
_, err := b.GetDepositAddress(currency.BTC, "")
if err == nil {
t.Error("Test Failed - GetDepositAddress() error cannot be nil")
}

View File

@@ -1,6 +1,6 @@
package bithumb
import "github.com/thrasher-/gocryptotrader/currency/symbol"
import "github.com/thrasher-/gocryptotrader/currency"
// Ticker holds ticker data
type Ticker struct {
@@ -225,51 +225,51 @@ type MarketSell struct {
// WithdrawalFees the large list of predefined withdrawal fees
// Prone to change
var WithdrawalFees = map[string]float64{
symbol.KRW: 1000,
symbol.BTC: 0.001,
symbol.ETH: 0.01,
symbol.DASH: 0.01,
symbol.LTC: 0.01,
symbol.ETC: 0.01,
symbol.XRP: 1,
symbol.BCH: 0.001,
symbol.XMR: 0.05,
symbol.ZEC: 0.001,
symbol.QTUM: 0.05,
symbol.BTG: 0.001,
symbol.ICX: 1,
symbol.TRX: 5,
symbol.ELF: 5,
symbol.MITH: 5,
symbol.MCO: 0.5,
symbol.OMG: 0.4,
symbol.KNC: 3,
symbol.GNT: 12,
symbol.HSR: 0.2,
symbol.ZIL: 30,
symbol.ETHOS: 2,
symbol.PAY: 2.4,
symbol.WAX: 5,
symbol.POWR: 5,
symbol.LRC: 10,
symbol.GTO: 15,
symbol.STEEM: 0.01,
symbol.STRAT: 0.2,
symbol.PPT: 0.5,
symbol.CTXC: 4,
symbol.CMT: 20,
symbol.THETA: 24,
symbol.WTC: 0.7,
symbol.ITC: 5,
symbol.TRUE: 4,
symbol.ABT: 5,
symbol.RNT: 20,
symbol.PLY: 20,
symbol.WAVES: 0.01,
symbol.LINK: 10,
symbol.ENJ: 35,
symbol.PST: 30,
var WithdrawalFees = map[currency.Code]float64{
currency.KRW: 1000,
currency.BTC: 0.001,
currency.ETH: 0.01,
currency.DASH: 0.01,
currency.LTC: 0.01,
currency.ETC: 0.01,
currency.XRP: 1,
currency.BCH: 0.001,
currency.XMR: 0.05,
currency.ZEC: 0.001,
currency.QTUM: 0.05,
currency.BTG: 0.001,
currency.ICX: 1,
currency.TRX: 5,
currency.ELF: 5,
currency.MITH: 5,
currency.MCO: 0.5,
currency.OMG: 0.4,
currency.KNC: 3,
currency.GNT: 12,
currency.HSR: 0.2,
currency.ZIL: 30,
currency.ETHOS: 2,
currency.PAY: 2.4,
currency.WAX: 5,
currency.POWR: 5,
currency.LRC: 10,
currency.GTO: 15,
currency.STEEM: 0.01,
currency.STRAT: 0.2,
currency.PPT: 0.5,
currency.CTXC: 4,
currency.CMT: 20,
currency.THETA: 24,
currency.WTC: 0.7,
currency.ITC: 5,
currency.TRUE: 4,
currency.ABT: 5,
currency.RNT: 20,
currency.PLY: 20,
currency.WAVES: 0.01,
currency.LINK: 10,
currency.ENJ: 35,
currency.PST: 30,
}
// FullBalance defines a return type with full balance data

View File

@@ -9,8 +9,7 @@ import (
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -38,7 +37,13 @@ func (b *Bithumb) Run() {
if err != nil {
log.Errorf("%s Failed to get available symbols.\n", b.GetName())
} else {
err = b.UpdateCurrencies(exchangeProducts, false, false)
var newExchangeProducts currency.Pairs
for _, p := range exchangeProducts {
newExchangeProducts = append(newExchangeProducts,
currency.NewPairFromString(p))
}
err = b.UpdateCurrencies(newExchangeProducts, false, false)
if err != nil {
log.Errorf("%s Failed to update available symbols.\n", b.GetName())
}
@@ -60,7 +65,7 @@ func (b *Bithumb) GetTradingPairs() ([]string, error) {
}
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bithumb) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *Bithumb) UpdateTicker(p currency.Pair, assetType string) (ticker.Price, error) {
var tickerPrice ticker.Price
tickers, err := b.GetAllTickers()
@@ -69,7 +74,7 @@ func (b *Bithumb) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Pr
}
for _, x := range b.GetEnabledCurrencies() {
currency := x.FirstCurrency.String()
currency := x.Base.String()
var tp ticker.Price
tp.Pair = x
tp.Ask = tickers[currency].SellPrice
@@ -78,13 +83,17 @@ func (b *Bithumb) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Pr
tp.Last = tickers[currency].ClosingPrice
tp.Volume = tickers[currency].Volume1Day
tp.High = tickers[currency].MaxPrice
ticker.ProcessTicker(b.Name, x, tp, assetType)
err = ticker.ProcessTicker(b.Name, tp, assetType)
if err != nil {
return tickerPrice, err
}
}
return ticker.GetTicker(b.Name, p, assetType)
}
// GetTickerPrice returns the ticker for a currency pair
func (b *Bithumb) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *Bithumb) GetTickerPrice(p currency.Pair, assetType string) (ticker.Price, error) {
tickerNew, err := ticker.GetTicker(b.GetName(), p, assetType)
if err != nil {
return b.UpdateTicker(p, assetType)
@@ -93,8 +102,8 @@ func (b *Bithumb) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.
}
// GetOrderbookEx returns orderbook base on the currency pair
func (b *Bithumb) GetOrderbookEx(currency pair.CurrencyPair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.GetOrderbook(b.GetName(), currency, assetType)
func (b *Bithumb) GetOrderbookEx(currency currency.Pair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.Get(b.GetName(), currency, assetType)
if err != nil {
return b.UpdateOrderbook(currency, assetType)
}
@@ -102,9 +111,9 @@ func (b *Bithumb) GetOrderbookEx(currency pair.CurrencyPair, assetType string) (
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (b *Bithumb) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
func (b *Bithumb) UpdateOrderbook(p currency.Pair, assetType string) (orderbook.Base, error) {
var orderBook orderbook.Base
currency := p.FirstCurrency.String()
currency := p.Base.String()
orderbookNew, err := b.GetOrderBook(currency)
if err != nil {
@@ -119,8 +128,16 @@ func (b *Bithumb) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderb
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: asks.Quantity, Price: asks.Price})
}
orderbook.ProcessOrderbook(b.GetName(), p, orderBook, assetType)
return orderbook.GetOrderbook(b.Name, p, assetType)
orderBook.Pair = p
orderBook.ExchangeName = b.GetName()
orderBook.AssetType = assetType
err = orderBook.Process()
if err != nil {
return orderBook, err
}
return orderbook.Get(b.Name, p, assetType)
}
// GetAccountInfo retrieves balances for all enabled currencies for the
@@ -141,7 +158,7 @@ func (b *Bithumb) GetAccountInfo() (exchange.AccountInfo, error) {
}
exchangeBalances = append(exchangeBalances, exchange.AccountCurrencyInfo{
CurrencyName: key,
CurrencyName: currency.NewCode(key),
TotalValue: totalAmount,
Hold: hold,
})
@@ -163,7 +180,7 @@ func (b *Bithumb) GetFundingHistory() ([]exchange.FundHistory, error) {
}
// GetExchangeHistory returns historic trade data since exchange opening.
func (b *Bithumb) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
func (b *Bithumb) GetExchangeHistory(p currency.Pair, assetType string) ([]exchange.TradeHistory, error) {
var resp []exchange.TradeHistory
return resp, common.ErrNotYetImplemented
@@ -171,17 +188,17 @@ func (b *Bithumb) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]e
// SubmitOrder submits a new order
// TODO: Fill this out to support limit orders
func (b *Bithumb) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, _ exchange.OrderType, amount, _ float64, _ string) (exchange.SubmitOrderResponse, error) {
func (b *Bithumb) SubmitOrder(p currency.Pair, side exchange.OrderSide, _ exchange.OrderType, amount, _ float64, _ string) (exchange.SubmitOrderResponse, error) {
var submitOrderResponse exchange.SubmitOrderResponse
var err error
var orderID string
if side == exchange.BuyOrderSide {
var result MarketBuy
result, err = b.MarketBuyOrder(p.FirstCurrency.String(), amount)
result, err = b.MarketBuyOrder(p.Base.String(), amount)
orderID = result.OrderID
} else if side == exchange.SellOrderSide {
var result MarketSell
result, err = b.MarketSellOrder(p.FirstCurrency.String(), amount)
result, err = b.MarketSellOrder(p.Base.String(), amount)
orderID = result.OrderID
}
@@ -200,7 +217,7 @@ func (b *Bithumb) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, _ ex
// market conversion
func (b *Bithumb) ModifyOrder(action exchange.ModifyOrder) (string, error) {
order, err := b.ModifyTrade(action.OrderID,
action.Currency.FirstCurrency.String(),
action.CurrencyPair.Base.String(),
common.StringToLower(action.OrderSide.ToString()),
action.Amount,
int64(action.Price))
@@ -214,7 +231,9 @@ func (b *Bithumb) ModifyOrder(action exchange.ModifyOrder) (string, error) {
// CancelOrder cancels an order by its corresponding ID number
func (b *Bithumb) CancelOrder(order exchange.OrderCancellation) error {
_, err := b.CancelTrade(order.Side.ToString(), order.OrderID, order.CurrencyPair.FirstCurrency.String())
_, err := b.CancelTrade(order.Side.ToString(),
order.OrderID,
order.CurrencyPair.Base.String())
return err
}
@@ -226,7 +245,11 @@ func (b *Bithumb) CancelAllOrders(orderCancellation exchange.OrderCancellation)
var allOrders []OrderData
for _, currency := range b.GetEnabledCurrencies() {
orders, err := b.GetOrders("", orderCancellation.Side.ToString(), "100", "", currency.FirstCurrency.String())
orders, err := b.GetOrders("",
orderCancellation.Side.ToString(),
"100",
"",
currency.Base.String())
if err != nil {
return cancelAllOrdersResponse, err
}
@@ -234,7 +257,9 @@ func (b *Bithumb) CancelAllOrders(orderCancellation exchange.OrderCancellation)
}
for _, order := range allOrders {
_, err := b.CancelTrade(orderCancellation.Side.ToString(), order.OrderID, orderCancellation.CurrencyPair.FirstCurrency.String())
_, err := b.CancelTrade(orderCancellation.Side.ToString(),
order.OrderID,
orderCancellation.CurrencyPair.Base.String())
if err != nil {
cancelAllOrdersResponse.OrderStatus[order.OrderID] = err.Error()
}
@@ -250,7 +275,7 @@ func (b *Bithumb) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
}
// GetDepositAddress returns a deposit address for a specified currency
func (b *Bithumb) GetDepositAddress(cryptocurrency pair.CurrencyItem, _ string) (string, error) {
func (b *Bithumb) GetDepositAddress(cryptocurrency currency.Code, _ string) (string, error) {
addr, err := b.GetWalletAddress(cryptocurrency.String())
if err != nil {
return "", err
@@ -272,7 +297,7 @@ func (b *Bithumb) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (s
if math.Mod(withdrawRequest.Amount, 1) != 0 {
return "", errors.New("currency KRW does not support decimal places")
}
if withdrawRequest.Currency.String() != symbol.KRW {
if withdrawRequest.Currency != currency.KRW {
return "", errors.New("only KRW is supported")
}
bankDetails := fmt.Sprintf("%v_%v", withdrawRequest.BankCode, withdrawRequest.BankName)
@@ -326,7 +351,9 @@ func (b *Bithumb) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) ([
Price: order.Price,
RemainingAmount: order.UnitsRemaining,
Status: string(exchange.ActiveOrderStatus),
CurrencyPair: pair.NewCurrencyPairWithDelimiter(order.OrderCurrency, order.PaymentCurrency, b.ConfigCurrencyPairFormat.Delimiter),
CurrencyPair: currency.NewPairWithDelimiter(order.OrderCurrency,
order.PaymentCurrency,
b.ConfigCurrencyPairFormat.Delimiter),
}
if order.Type == "bid" {
@@ -339,7 +366,8 @@ func (b *Bithumb) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) ([
}
exchange.FilterOrdersBySide(&orders, getOrdersRequest.OrderSide)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks, getOrdersRequest.EndTicks)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks,
getOrdersRequest.EndTicks)
exchange.FilterOrdersByCurrencies(&orders, getOrdersRequest.Currencies)
return orders, nil
@@ -367,7 +395,9 @@ func (b *Bithumb) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) ([
OrderDate: orderDate,
Price: order.Price,
RemainingAmount: order.UnitsRemaining,
CurrencyPair: pair.NewCurrencyPairWithDelimiter(order.OrderCurrency, order.PaymentCurrency, b.ConfigCurrencyPairFormat.Delimiter),
CurrencyPair: currency.NewPairWithDelimiter(order.OrderCurrency,
order.PaymentCurrency,
b.ConfigCurrencyPairFormat.Delimiter),
}
if order.Type == "bid" {
@@ -380,7 +410,8 @@ func (b *Bithumb) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) ([
}
exchange.FilterOrdersBySide(&orders, getOrdersRequest.OrderSide)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks, getOrdersRequest.EndTicks)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks,
getOrdersRequest.EndTicks)
exchange.FilterOrdersByCurrencies(&orders, getOrdersRequest.Currencies)
return orders, nil

View File

@@ -12,7 +12,7 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -149,9 +149,9 @@ func (b *Bitmex) Setup(exch config.ExchangeConfig) {
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket.SetWsStatusAndConnection(exch.Websocket)
b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
b.BaseCurrencies = exch.BaseCurrencies
b.AvailablePairs = exch.AvailablePairs
b.EnabledPairs = exch.EnabledPairs
err := b.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)
@@ -705,13 +705,13 @@ func (b *Bitmex) ConfirmWithdrawal(token string) (TransactionInfo, error) {
}
// GetCryptoDepositAddress returns a deposit address for a cryptocurency
func (b *Bitmex) GetCryptoDepositAddress(currency string) (string, error) {
func (b *Bitmex) GetCryptoDepositAddress(cryptoCurrency string) (string, error) {
var address string
if !strings.EqualFold(currency, symbol.XBT) {
if !strings.EqualFold(cryptoCurrency, currency.XBT.String()) {
return "",
fmt.Errorf("cryptocurrency %s deposits are not supported by exchange only bitcoin",
currency)
cryptoCurrency)
}
return address, b.SendAuthenticatedHTTPRequest(http.MethodGet,

View File

@@ -7,8 +7,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
)
@@ -363,13 +362,10 @@ func TestGetPreviousTrades(t *testing.T) {
func setFeeBuilder() exchange.FeeBuilder {
return exchange.FeeBuilder{
Amount: 1,
Delimiter: "",
FeeType: exchange.CryptocurrencyTradeFee,
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
IsMaker: false,
PurchasePrice: 1,
Amount: 1,
FeeType: exchange.CryptocurrencyTradeFee,
Pair: currency.NewPair(currency.BTC, currency.LTC),
PurchasePrice: 1,
}
}
@@ -429,7 +425,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankDepositFee
feeBuilder.CurrencyItem = symbol.HKD
feeBuilder.FiatCurrency = currency.HKD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
@@ -438,7 +434,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.CurrencyItem = symbol.HKD
feeBuilder.FiatCurrency = currency.HKD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
@@ -478,8 +474,9 @@ func TestGetOrderHistory(t *testing.T) {
TestSetup(t)
var getOrdersRequest = exchange.GetOrdersRequest{
OrderType: exchange.AnyOrderType,
Currencies: []pair.CurrencyPair{pair.NewCurrencyPair(symbol.LTC, symbol.BTC)},
OrderType: exchange.AnyOrderType,
Currencies: []currency.Pair{currency.NewPair(currency.LTC,
currency.BTC)},
}
_, err := b.GetOrderHistory(getOrdersRequest)
@@ -508,10 +505,10 @@ func TestSubmitOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var p = pair.CurrencyPair{
Delimiter: "",
FirstCurrency: symbol.XBT,
SecondCurrency: symbol.USD,
var p = currency.Pair{
Delimiter: "",
Base: currency.XBT,
Quote: currency.USD,
}
response, err := b.SubmitOrder(p, exchange.BuyOrderSide, exchange.MarketOrderType, 1, 1, "clientId")
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
@@ -529,7 +526,7 @@ func TestCancelExchangeOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "123456789012345678901234567890123456",
@@ -555,7 +552,7 @@ func TestCancelAllExchangeOrders(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "123456789012345678901234567890123456",
@@ -604,7 +601,7 @@ func TestWithdraw(t *testing.T) {
TestSetup(t)
var withdrawCryptoRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: "XBt",
Currency: currency.XBT,
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
Description: "WITHDRAW IT ALL",
OneTimePassword: 000000,
@@ -657,12 +654,12 @@ func TestWithdrawInternationalBank(t *testing.T) {
func TestGetDepositAddress(t *testing.T) {
if areTestAPIKeysSet() {
_, err := b.GetDepositAddress(symbol.BTC, "")
_, err := b.GetDepositAddress(currency.BTC, "")
if err != nil {
t.Error("Test Failed - GetDepositAddress() error", err)
}
} else {
_, err := b.GetDepositAddress(symbol.BTC, "")
_, err := b.GetDepositAddress(currency.BTC, "")
if err == nil {
t.Error("Test Failed - GetDepositAddress() error cannot be nil")
}

View File

@@ -10,7 +10,7 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
log "github.com/thrasher-/gocryptotrader/logger"
@@ -236,7 +236,7 @@ func (b *Bitmex) wsHandleIncomingData() {
continue
}
p := pair.NewCurrencyPairFromString(orderbooks.Data[0].Symbol)
p := currency.NewPairFromString(orderbooks.Data[0].Symbol)
// TODO: update this to support multiple asset types
err = b.processOrderbook(orderbooks.Data, orderbooks.Action, p, "CONTRACT")
if err != nil {
@@ -269,7 +269,7 @@ func (b *Bitmex) wsHandleIncomingData() {
Timestamp: timestamp,
Price: trade.Price,
Amount: float64(trade.Size),
CurrencyPair: pair.NewCurrencyPairFromString(trade.Symbol),
CurrencyPair: currency.NewPairFromString(trade.Symbol),
Exchange: b.GetName(),
AssetType: "CONTRACT",
Side: trade.Side,
@@ -300,10 +300,10 @@ func (b *Bitmex) wsHandleIncomingData() {
}
}
var snapshotloaded = make(map[pair.CurrencyPair]map[string]bool)
var snapshotloaded = make(map[currency.Pair]map[string]bool)
// ProcessOrderbook processes orderbook updates
func (b *Bitmex) processOrderbook(data []OrderBookL2, action string, currencyPair pair.CurrencyPair, assetType string) error { // nolint: unparam
func (b *Bitmex) processOrderbook(data []OrderBookL2, action string, currencyPair currency.Pair, assetType string) error { // nolint: unparam
if len(data) < 1 {
return errors.New("bitmex_websocket.go error - no orderbook data")
}
@@ -345,8 +345,6 @@ func (b *Bitmex) processOrderbook(data []OrderBookL2, action string, currencyPai
newOrderbook.Asks = asks
newOrderbook.Bids = bids
newOrderbook.AssetType = assetType
newOrderbook.CurrencyPair = currencyPair.Pair().String()
newOrderbook.LastUpdated = time.Now()
newOrderbook.Pair = currencyPair
err := b.Websocket.Orderbook.LoadSnapshot(newOrderbook, b.GetName(), false)
@@ -415,8 +413,8 @@ func (b *Bitmex) websocketSubscribe() error {
// Orderbook and Trade subscribe
// NOTE more added here in future
subscriber.Arguments = append(subscriber.Arguments,
bitmexWSOrderbookL2+":"+contract.Pair().String(),
bitmexWSTrade+":"+contract.Pair().String())
bitmexWSOrderbookL2+":"+contract.String(),
bitmexWSTrade+":"+contract.String())
}
return b.WebsocketConn.WriteJSON(subscriber)

View File

@@ -8,7 +8,7 @@ import (
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -42,7 +42,13 @@ func (b *Bitmex) Run() {
exchangeProducts = append(exchangeProducts, info.Symbol)
}
err = b.UpdateCurrencies(exchangeProducts, false, false)
var NewExchangeProducts currency.Pairs
for _, p := range exchangeProducts {
NewExchangeProducts = append(NewExchangeProducts,
currency.NewPairFromString(p))
}
err = b.UpdateCurrencies(NewExchangeProducts, false, false)
if err != nil {
log.Errorf("%s Failed to update available currencies.\n", b.GetName())
}
@@ -50,7 +56,7 @@ func (b *Bitmex) Run() {
}
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bitmex) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *Bitmex) UpdateTicker(p currency.Pair, assetType string) (ticker.Price, error) {
var tickerPrice ticker.Price
currency := exchange.FormatExchangeCurrency(b.Name, p)
@@ -68,18 +74,13 @@ func (b *Bitmex) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Pri
}
tickerPrice.Pair = p
tickerPrice.LastUpdated = time.Now()
tickerPrice.CurrencyPair = tick[0].Symbol
tickerPrice.Last = tick[0].Price
tickerPrice.Volume = float64(tick[0].Size)
ticker.ProcessTicker(b.Name, p, tickerPrice, assetType)
return tickerPrice, nil
return tickerPrice, ticker.ProcessTicker(b.Name, tickerPrice, assetType)
}
// GetTickerPrice returns the ticker for a currency pair
func (b *Bitmex) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *Bitmex) GetTickerPrice(p currency.Pair, assetType string) (ticker.Price, error) {
tickerNew, err := ticker.GetTicker(b.GetName(), p, assetType)
if err != nil {
return b.UpdateTicker(p, assetType)
@@ -88,8 +89,8 @@ func (b *Bitmex) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.P
}
// GetOrderbookEx returns orderbook base on the currency pair
func (b *Bitmex) GetOrderbookEx(currency pair.CurrencyPair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.GetOrderbook(b.GetName(), currency, assetType)
func (b *Bitmex) GetOrderbookEx(currency currency.Pair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.Get(b.GetName(), currency, assetType)
if err != nil {
return b.UpdateOrderbook(currency, assetType)
}
@@ -97,7 +98,7 @@ func (b *Bitmex) GetOrderbookEx(currency pair.CurrencyPair, assetType string) (o
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (b *Bitmex) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
func (b *Bitmex) UpdateOrderbook(p currency.Pair, assetType string) (orderbook.Base, error) {
var orderBook orderbook.Base
orderbookNew, err := b.GetOrderbook(OrderBookGetL2Params{
@@ -119,9 +120,17 @@ func (b *Bitmex) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbo
continue
}
}
orderbook.ProcessOrderbook(b.GetName(), p, orderBook, assetType)
return orderbook.GetOrderbook(b.Name, p, assetType)
orderBook.Pair = p
orderBook.ExchangeName = b.GetName()
orderBook.AssetType = assetType
err = orderBook.Process()
if err != nil {
return orderBook, err
}
return orderbook.Get(b.Name, p, assetType)
}
// GetAccountInfo retrieves balances for all enabled currencies for the
@@ -138,7 +147,7 @@ func (b *Bitmex) GetAccountInfo() (exchange.AccountInfo, error) {
var balances []exchange.AccountCurrencyInfo
for _, data := range bal {
balances = append(balances, exchange.AccountCurrencyInfo{
CurrencyName: data.Currency,
CurrencyName: currency.NewCode(data.Currency),
TotalValue: float64(data.WalletBalance),
})
}
@@ -158,14 +167,14 @@ func (b *Bitmex) GetFundingHistory() ([]exchange.FundHistory, error) {
}
// GetExchangeHistory returns historic trade data since exchange opening.
func (b *Bitmex) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
func (b *Bitmex) GetExchangeHistory(p currency.Pair, assetType string) ([]exchange.TradeHistory, error) {
var resp []exchange.TradeHistory
return resp, common.ErrNotYetImplemented
}
// SubmitOrder submits a new order
func (b *Bitmex) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
func (b *Bitmex) SubmitOrder(p currency.Pair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
var submitOrderResponse exchange.SubmitOrderResponse
if math.Mod(amount, 1) != 0 {
@@ -175,7 +184,7 @@ func (b *Bitmex) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, order
var orderNewParams = OrderNewParams{
OrdType: side.ToString(),
Symbol: p.Pair().String(),
Symbol: p.String(),
OrderQty: amount,
Side: side.ToString(),
}
@@ -252,7 +261,7 @@ func (b *Bitmex) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
}
// GetDepositAddress returns a deposit address for a specified currency
func (b *Bitmex) GetDepositAddress(cryptocurrency pair.CurrencyItem, _ string) (string, error) {
func (b *Bitmex) GetDepositAddress(cryptocurrency currency.Code, _ string) (string, error) {
return b.GetCryptoDepositAddress(cryptocurrency.String())
}
@@ -319,14 +328,16 @@ func (b *Bitmex) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) ([]
}
orderDetail := exchange.OrderDetail{
Price: order.Price,
Amount: float64(order.OrderQty),
Exchange: b.Name,
ID: order.OrderID,
OrderSide: orderSide,
OrderType: orderType,
Status: order.OrdStatus,
CurrencyPair: pair.NewCurrencyPairWithDelimiter(order.Symbol, order.SettlCurrency, b.ConfigCurrencyPairFormat.Delimiter),
Price: order.Price,
Amount: float64(order.OrderQty),
Exchange: b.Name,
ID: order.OrderID,
OrderSide: orderSide,
OrderType: orderType,
Status: order.OrdStatus,
CurrencyPair: currency.NewPairWithDelimiter(order.Symbol,
order.SettlCurrency,
b.ConfigCurrencyPairFormat.Delimiter),
}
orders = append(orders, orderDetail)
@@ -334,7 +345,8 @@ func (b *Bitmex) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) ([]
exchange.FilterOrdersBySide(&orders, getOrdersRequest.OrderSide)
exchange.FilterOrdersByType(&orders, getOrdersRequest.OrderType)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks, getOrdersRequest.EndTicks)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks,
getOrdersRequest.EndTicks)
exchange.FilterOrdersByCurrencies(&orders, getOrdersRequest.Currencies)
return orders, nil
@@ -359,14 +371,16 @@ func (b *Bitmex) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) ([]
}
orderDetail := exchange.OrderDetail{
Price: order.Price,
Amount: float64(order.OrderQty),
Exchange: b.Name,
ID: order.OrderID,
OrderSide: orderSide,
OrderType: orderType,
Status: order.OrdStatus,
CurrencyPair: pair.NewCurrencyPairWithDelimiter(order.Symbol, order.SettlCurrency, b.ConfigCurrencyPairFormat.Delimiter),
Price: order.Price,
Amount: float64(order.OrderQty),
Exchange: b.Name,
ID: order.OrderID,
OrderSide: orderSide,
OrderType: orderType,
Status: order.OrdStatus,
CurrencyPair: currency.NewPairWithDelimiter(order.Symbol,
order.SettlCurrency,
b.ConfigCurrencyPairFormat.Delimiter),
}
orders = append(orders, orderDetail)

View File

@@ -13,7 +13,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -104,9 +104,9 @@ func (b *Bitstamp) Setup(exch config.ExchangeConfig) {
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket.SetWsStatusAndConnection(exch.Websocket)
b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
b.BaseCurrencies = exch.BaseCurrencies
b.AvailablePairs = exch.AvailablePairs
b.EnabledPairs = exch.EnabledPairs
b.APIKey = exch.APIKey
b.APISecret = exch.APISecret
b.SetAPIKeys(exch.APIKey, exch.APISecret, b.ClientID, false)
@@ -154,7 +154,10 @@ func (b *Bitstamp) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
if err != nil {
return 0, err
}
fee = b.CalculateTradingFee(feeBuilder.FirstCurrency+feeBuilder.SecondCurrency, feeBuilder.PurchasePrice, feeBuilder.Amount)
fee = b.CalculateTradingFee(feeBuilder.Pair.Base,
feeBuilder.Pair.Quote,
feeBuilder.PurchasePrice,
feeBuilder.Amount)
case exchange.CyptocurrencyDepositFee:
fee = 0
case exchange.InternationalBankDepositFee:
@@ -192,19 +195,19 @@ func getInternationalBankDepositFee(amount float64) float64 {
}
// CalculateTradingFee returns fee on a currency pair
func (b *Bitstamp) CalculateTradingFee(currency string, purchasePrice, amount float64) float64 {
func (b *Bitstamp) CalculateTradingFee(base, quote currency.Code, purchasePrice, amount float64) float64 {
var fee float64
switch currency {
case symbol.BTC + symbol.USD:
switch base.String() + quote.String() {
case currency.BTC.String() + currency.USD.String():
fee = b.Balance.BTCUSDFee
case symbol.BTC + symbol.EUR:
case currency.BTC.String() + currency.EUR.String():
fee = b.Balance.BTCEURFee
case symbol.XRP + symbol.EUR:
case currency.XRP.String() + currency.EUR.String():
fee = b.Balance.XRPEURFee
case symbol.XRP + symbol.USD:
case currency.XRP.String() + currency.USD.String():
fee = b.Balance.XRPUSDFee
case symbol.EUR + symbol.USD:
case currency.EUR.String() + currency.USD.String():
fee = b.Balance.EURUSDFee
default:
fee = 0
@@ -572,27 +575,27 @@ func (b *Bitstamp) OpenInternationalBankWithdrawal(amount float64, currency,
// GetCryptoDepositAddress returns a depositing address by crypto
// crypto - example "btc", "ltc", "eth", "xrp" or "bch"
func (b *Bitstamp) GetCryptoDepositAddress(crypto string) (string, error) {
func (b *Bitstamp) GetCryptoDepositAddress(crypto currency.Code) (string, error) {
var resp string
switch crypto {
case symbol.BTC:
case currency.BTC:
return resp,
b.SendAuthenticatedHTTPRequest(bitstampAPIBitcoinDeposit, false, nil, &resp)
case symbol.LTC:
case currency.LTC:
return resp,
b.SendAuthenticatedHTTPRequest(bitstampAPILitecoinDeposit, true, nil, &resp)
case symbol.ETH:
case currency.ETH:
return resp,
b.SendAuthenticatedHTTPRequest(bitstampAPIEthereumDeposit, true, nil, &resp)
case symbol.XRP:
case currency.XRP:
return resp,
b.SendAuthenticatedHTTPRequest(bitstampAPIXrpDeposit, true, nil, &resp)
case symbol.BCH:
case currency.BCH:
return resp,
b.SendAuthenticatedHTTPRequest(bitstampAPIBitcoinCashDeposit, true, nil, &resp)

View File

@@ -6,8 +6,7 @@ import (
"time"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
)
@@ -64,13 +63,10 @@ func TestSetup(t *testing.T) {
func setFeeBuilder() exchange.FeeBuilder {
return exchange.FeeBuilder{
Amount: 1,
Delimiter: "",
FeeType: exchange.CryptocurrencyTradeFee,
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
IsMaker: false,
PurchasePrice: 1,
Amount: 1,
FeeType: exchange.CryptocurrencyTradeFee,
Pair: currency.NewPair(currency.BTC, currency.LTC),
PurchasePrice: 1,
}
}
@@ -130,7 +126,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankDepositFee
feeBuilder.CurrencyItem = symbol.HKD
feeBuilder.FiatCurrency = currency.HKD
if resp, err := b.GetFee(feeBuilder); resp != float64(7.5) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(7.5), resp)
t.Error(err)
@@ -139,7 +135,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.CurrencyItem = symbol.HKD
feeBuilder.FiatCurrency = currency.HKD
if resp, err := b.GetFee(feeBuilder); resp != float64(15) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(15), resp)
t.Error(err)
@@ -153,27 +149,29 @@ func TestCalculateTradingFee(t *testing.T) {
b.Balance.BTCUSDFee = 1
b.Balance.BTCEURFee = 0
if resp := b.CalculateTradingFee(symbol.BTC+symbol.USD, 0, 0); resp != 0 {
if resp := b.CalculateTradingFee(currency.BTC, currency.USD, 0, 0); resp != 0 {
t.Error("Test Failed - GetFee() error")
}
if resp := b.CalculateTradingFee(symbol.BTC+symbol.USD, 2, 2); resp != float64(4) {
if resp := b.CalculateTradingFee(currency.BTC, currency.USD, 2, 2); resp != float64(4) {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(4), resp)
}
if resp := b.CalculateTradingFee(symbol.BTC+symbol.EUR, 2, 2); resp != float64(0) {
if resp := b.CalculateTradingFee(currency.BTC, currency.EUR, 2, 2); resp != float64(0) {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
}
if resp := b.CalculateTradingFee("bla", 0, 0); resp != 0 {
dummy1, dummy2 := currency.NewCode(""), currency.NewCode("")
if resp := b.CalculateTradingFee(dummy1, dummy2, 0, 0); resp != 0 {
t.Error("Test Failed - GetFee() error")
}
}
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := b.GetTicker(symbol.BTC+symbol.USD, false)
_, err := b.GetTicker(currency.BTC.String()+currency.USD.String(), false)
if err != nil {
t.Error("Test Failed - GetTicker() error", err)
}
_, err = b.GetTicker(symbol.BTC+symbol.USD, true)
_, err = b.GetTicker(currency.BTC.String()+currency.USD.String(), true)
if err != nil {
t.Error("Test Failed - GetTicker() error", err)
}
@@ -181,7 +179,7 @@ func TestGetTicker(t *testing.T) {
func TestGetOrderbook(t *testing.T) {
t.Parallel()
_, err := b.GetOrderbook(symbol.BTC + symbol.USD)
_, err := b.GetOrderbook(currency.BTC.String() + currency.USD.String())
if err != nil {
t.Error("Test Failed - GetOrderbook() error", err)
}
@@ -200,7 +198,7 @@ func TestGetTransactions(t *testing.T) {
value := url.Values{}
value.Set("time", "hour")
_, err := b.GetTransactions(symbol.BTC+symbol.USD, value)
_, err := b.GetTransactions(currency.BTC.String()+currency.USD.String(), value)
if err != nil {
t.Error("Test Failed - GetTransactions() error", err)
}
@@ -325,7 +323,7 @@ func TestCryptoWithdrawal(t *testing.T) {
func TestGetBitcoinDepositAddress(t *testing.T) {
t.Parallel()
_, err := b.GetCryptoDepositAddress("btc")
_, err := b.GetCryptoDepositAddress(currency.BTC)
if err == nil {
t.Error("Test Failed - GetCryptoDepositAddress() error", err)
}
@@ -418,10 +416,10 @@ func TestSubmitOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var p = pair.CurrencyPair{
Delimiter: "",
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.USD,
var p = currency.Pair{
Delimiter: "",
Base: currency.BTC,
Quote: currency.USD,
}
response, err := b.SubmitOrder(p, exchange.BuyOrderSide, exchange.MarketOrderType, 1, 1, "clientId")
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
@@ -439,7 +437,7 @@ func TestCancelExchangeOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -465,7 +463,7 @@ func TestCancelAllExchangeOrders(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -500,7 +498,7 @@ func TestWithdraw(t *testing.T) {
TestSetup(t)
var withdrawCryptoRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.BTC,
Currency: currency.BTC,
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
Description: "WITHDRAW IT ALL",
}
@@ -528,7 +526,7 @@ func TestWithdrawFiat(t *testing.T) {
var withdrawFiatRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.USD,
Currency: currency.USD,
Description: "WITHDRAW IT ALL",
BankAccountName: "Satoshi Nakamoto",
BankAccountNumber: 12345,
@@ -536,7 +534,7 @@ func TestWithdrawFiat(t *testing.T) {
BankCity: "Tarry Town",
BankCountry: "AU",
BankName: "Federal Reserve Bank",
WireCurrency: symbol.USD,
WireCurrency: currency.USD.String(),
SwiftCode: "CTBAAU2S",
RequiresIntermediaryBank: false,
IsExpressWire: false,
@@ -563,7 +561,7 @@ func TestWithdrawInternationalBank(t *testing.T) {
var withdrawFiatRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.USD,
Currency: currency.USD,
Description: "WITHDRAW IT ALL",
BankAccountName: "Satoshi Nakamoto",
BankAccountNumber: 12345,
@@ -571,7 +569,7 @@ func TestWithdrawInternationalBank(t *testing.T) {
BankCity: "Tarry Town",
BankCountry: "AU",
BankName: "Federal Reserve Bank",
WireCurrency: symbol.USD,
WireCurrency: currency.USD.String(),
SwiftCode: "CTBAAU2S",
RequiresIntermediaryBank: false,
IsExpressWire: false,
@@ -596,12 +594,12 @@ func TestWithdrawInternationalBank(t *testing.T) {
func TestGetDepositAddress(t *testing.T) {
if areTestAPIKeysSet() && customerID != "" {
_, err := b.GetDepositAddress(symbol.BTC, "")
_, err := b.GetDepositAddress(currency.BTC, "")
if err != nil {
t.Error("Test Failed - GetDepositAddress error", err)
}
} else {
_, err := b.GetDepositAddress(symbol.BTC, "")
_, err := b.GetDepositAddress(currency.BTC, "")
if err == nil {
t.Error("Test Failed - GetDepositAddress error cannot be nil")
}

View File

@@ -8,7 +8,7 @@ import (
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
log "github.com/thrasher-/gocryptotrader/logger"
@@ -60,7 +60,7 @@ func (b *Bitstamp) findPairFromChannel(channelName string) (string, error) {
tradingPair := strings.ToUpper(split[len(split)-1])
for _, enabledPair := range b.EnabledPairs {
if enabledPair == tradingPair {
if enabledPair.String() == tradingPair {
return tradingPair, nil
}
}
@@ -102,7 +102,7 @@ func (b *Bitstamp) WsConnect() error {
go b.WsReadData()
for _, p := range b.GetEnabledCurrencies() {
orderbookSeed, err := b.GetOrderbook(p.Pair().String())
orderbookSeed, err := b.GetOrderbook(p.String())
if err != nil {
return err
}
@@ -127,9 +127,7 @@ func (b *Bitstamp) WsConnect() error {
newOrderbook.Asks = asks
newOrderbook.Bids = bids
newOrderbook.CurrencyPair = p.Pair().String()
newOrderbook.Pair = p
newOrderbook.LastUpdated = time.Unix(0, orderbookSeed.Timestamp)
newOrderbook.AssetType = "SPOT"
err = b.Websocket.Orderbook.LoadSnapshot(newOrderbook, b.GetName(), false)
@@ -144,7 +142,7 @@ func (b *Bitstamp) WsConnect() error {
}
err = b.WebsocketConn.Client.Subscribe(fmt.Sprintf("live_trades_%s",
strings.ToLower(p.Pair().String())))
p.Lower().String()))
if err != nil {
return fmt.Errorf("%s Websocket Trade subscription error: %s",
@@ -153,7 +151,7 @@ func (b *Bitstamp) WsConnect() error {
}
err = b.WebsocketConn.Client.Subscribe(fmt.Sprintf("diff_order_book_%s",
strings.ToLower(p.Pair().String())))
p.Lower().String()))
if err != nil {
return fmt.Errorf("%s Websocket Trade subscription error: %s",
@@ -194,7 +192,7 @@ func (b *Bitstamp) WsReadData() {
}
currencyPair := common.SplitStrings(data.Channel, "_")
p := pair.NewCurrencyPairFromString(common.StringToUpper(currencyPair[3]))
p := currency.NewPairFromString(common.StringToUpper(currencyPair[3]))
err = b.WsUpdateOrderbook(result, p, "SPOT")
if err != nil {
@@ -217,7 +215,7 @@ func (b *Bitstamp) WsReadData() {
b.Websocket.DataHandler <- exchange.TradeData{
Price: result.Price,
Amount: result.Amount,
CurrencyPair: pair.NewCurrencyPairFromString(currencyPair[2]),
CurrencyPair: currency.NewPairFromString(currencyPair[2]),
Exchange: b.GetName(),
AssetType: "SPOT",
}
@@ -226,7 +224,7 @@ func (b *Bitstamp) WsReadData() {
}
// WsUpdateOrderbook updates local cache of orderbook information
func (b *Bitstamp) WsUpdateOrderbook(ob PusherOrderbook, p pair.CurrencyPair, assetType string) error {
func (b *Bitstamp) WsUpdateOrderbook(ob PusherOrderbook, p currency.Pair, assetType string) error {
if len(ob.Asks) == 0 && len(ob.Bids) == 0 {
return errors.New("bitstamp_websocket.go error - no orderbook data")
}

View File

@@ -9,8 +9,7 @@ import (
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -46,7 +45,14 @@ func (b *Bitstamp) Run() {
p := strings.Split(pairs[x].Name, "/")
currencies = append(currencies, p[0]+p[1])
}
err = b.UpdateCurrencies(currencies, false, false)
var newCurrencies currency.Pairs
for _, p := range currencies {
newCurrencies = append(newCurrencies,
currency.NewPairFromString(p))
}
err = b.UpdateCurrencies(newCurrencies, false, false)
if err != nil {
log.Errorf("%s Failed to update available currencies.\n", b.Name)
}
@@ -54,9 +60,9 @@ func (b *Bitstamp) Run() {
}
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bitstamp) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *Bitstamp) UpdateTicker(p currency.Pair, assetType string) (ticker.Price, error) {
var tickerPrice ticker.Price
tick, err := b.GetTicker(p.Pair().String(), false)
tick, err := b.GetTicker(p.String(), false)
if err != nil {
return tickerPrice, err
@@ -68,12 +74,17 @@ func (b *Bitstamp) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.P
tickerPrice.Last = tick.Last
tickerPrice.Volume = tick.Volume
tickerPrice.High = tick.High
ticker.ProcessTicker(b.GetName(), p, tickerPrice, assetType)
err = ticker.ProcessTicker(b.GetName(), tickerPrice, assetType)
if err != nil {
return tickerPrice, err
}
return ticker.GetTicker(b.Name, p, assetType)
}
// GetTickerPrice returns the ticker for a currency pair
func (b *Bitstamp) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *Bitstamp) GetTickerPrice(p currency.Pair, assetType string) (ticker.Price, error) {
tick, err := ticker.GetTicker(b.GetName(), p, assetType)
if err != nil {
return b.UpdateTicker(p, assetType)
@@ -88,8 +99,8 @@ func (b *Bitstamp) GetFeeByType(feeBuilder exchange.FeeBuilder) (float64, error)
}
// GetOrderbookEx returns the orderbook for a currency pair
func (b *Bitstamp) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.GetOrderbook(b.GetName(), p, assetType)
func (b *Bitstamp) GetOrderbookEx(p currency.Pair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.Get(b.GetName(), p, assetType)
if err != nil {
return b.UpdateOrderbook(p, assetType)
}
@@ -97,9 +108,9 @@ func (b *Bitstamp) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderb
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (b *Bitstamp) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
func (b *Bitstamp) UpdateOrderbook(p currency.Pair, assetType string) (orderbook.Base, error) {
var orderBook orderbook.Base
orderbookNew, err := b.GetOrderbook(p.Pair().String())
orderbookNew, err := b.GetOrderbook(p.String())
if err != nil {
return orderBook, err
}
@@ -114,8 +125,16 @@ func (b *Bitstamp) UpdateOrderbook(p pair.CurrencyPair, assetType string) (order
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: data.Amount, Price: data.Price})
}
orderbook.ProcessOrderbook(b.GetName(), p, orderBook, assetType)
return orderbook.GetOrderbook(b.Name, p, assetType)
orderBook.Pair = p
orderBook.ExchangeName = b.GetName()
orderBook.AssetType = assetType
err = orderBook.Process()
if err != nil {
return orderBook, err
}
return orderbook.Get(b.Name, p, assetType)
}
// GetAccountInfo retrieves balances for all enabled currencies for the
@@ -130,22 +149,22 @@ func (b *Bitstamp) GetAccountInfo() (exchange.AccountInfo, error) {
var currencies = []exchange.AccountCurrencyInfo{
{
CurrencyName: "BTC",
CurrencyName: currency.BTC,
TotalValue: accountBalance.BTCAvailable,
Hold: accountBalance.BTCReserved,
},
{
CurrencyName: "XRP",
CurrencyName: currency.XRP,
TotalValue: accountBalance.XRPAvailable,
Hold: accountBalance.XRPReserved,
},
{
CurrencyName: "USD",
CurrencyName: currency.USD,
TotalValue: accountBalance.USDAvailable,
Hold: accountBalance.USDReserved,
},
{
CurrencyName: "EUR",
CurrencyName: currency.EUR,
TotalValue: accountBalance.EURAvailable,
Hold: accountBalance.EURReserved,
},
@@ -165,18 +184,18 @@ func (b *Bitstamp) GetFundingHistory() ([]exchange.FundHistory, error) {
}
// GetExchangeHistory returns historic trade data since exchange opening.
func (b *Bitstamp) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
func (b *Bitstamp) GetExchangeHistory(p currency.Pair, assetType string) ([]exchange.TradeHistory, error) {
var resp []exchange.TradeHistory
return resp, common.ErrNotYetImplemented
}
// SubmitOrder submits a new order
func (b *Bitstamp) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
func (b *Bitstamp) SubmitOrder(p currency.Pair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
var submitOrderResponse exchange.SubmitOrderResponse
buy := side == exchange.BuyOrderSide
market := orderType == exchange.MarketOrderType
response, err := b.PlaceOrder(p.Pair().String(), price, amount, buy, market)
response, err := b.PlaceOrder(p.String(), price, amount, buy, market)
if response.ID > 0 {
submitOrderResponse.OrderID = fmt.Sprintf("%v", response.ID)
@@ -224,8 +243,8 @@ func (b *Bitstamp) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
}
// GetDepositAddress returns a deposit address for a specified currency
func (b *Bitstamp) GetDepositAddress(cryptocurrency pair.CurrencyItem, _ string) (string, error) {
return b.GetCryptoDepositAddress(cryptocurrency.String())
func (b *Bitstamp) GetDepositAddress(cryptocurrency currency.Code, _ string) (string, error) {
return b.GetCryptoDepositAddress(cryptocurrency)
}
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
@@ -290,7 +309,7 @@ func (b *Bitstamp) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) (
if len(getOrdersRequest.Currencies) != 1 {
currPair = "all"
} else {
currPair = getOrdersRequest.Currencies[0].Pair().String()
currPair = getOrdersRequest.Currencies[0].String()
}
resp, err := b.GetOpenOrders(currPair)
@@ -299,17 +318,15 @@ func (b *Bitstamp) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) (
}
for _, order := range resp {
symbolOne := order.Currency[0:3]
symbolTwo := order.Currency[len(order.Currency)-3:]
orderDate := time.Unix(order.Date, 0)
orders = append(orders, exchange.OrderDetail{
Amount: order.Amount,
ID: fmt.Sprintf("%v", order.ID),
Price: order.Price,
OrderDate: orderDate,
CurrencyPair: pair.NewCurrencyPair(symbolOne, symbolTwo),
Exchange: b.Name,
Amount: order.Amount,
ID: fmt.Sprintf("%v", order.ID),
Price: order.Price,
OrderDate: orderDate,
CurrencyPair: currency.NewPairFromStrings(order.Currency[0:3],
order.Currency[len(order.Currency)-3:]),
Exchange: b.Name,
})
}
@@ -324,7 +341,7 @@ func (b *Bitstamp) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) (
func (b *Bitstamp) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) ([]exchange.OrderDetail, error) {
var currPair string
if len(getOrdersRequest.Currencies) == 1 {
currPair = getOrdersRequest.Currencies[0].Pair().String()
currPair = getOrdersRequest.Currencies[0].String()
}
resp, err := b.GetUserTransactions(currPair)
if err != nil {
@@ -336,30 +353,31 @@ func (b *Bitstamp) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) (
if order.Type != 2 {
continue
}
quoteCurrency := ""
baseCurrency := ""
var quoteCurrency, baseCurrency currency.Code
switch {
case order.BTC > 0:
baseCurrency = symbol.BTC
baseCurrency = currency.BTC
case order.XRP > 0:
baseCurrency = symbol.XRP
baseCurrency = currency.XRP
default:
log.Warnf("no base currency found for OrderID '%v'", order.OrderID)
}
switch {
case order.USD > 0:
quoteCurrency = symbol.USD
quoteCurrency = currency.USD
case order.EUR > 0:
quoteCurrency = symbol.EUR
quoteCurrency = currency.EUR
default:
log.Warnf("no quote currency found for orderID '%v'", order.OrderID)
}
var currPair pair.CurrencyPair
if quoteCurrency != "" && baseCurrency != "" {
currPair = pair.NewCurrencyPairWithDelimiter(baseCurrency, quoteCurrency, b.ConfigCurrencyPairFormat.Delimiter)
var currPair currency.Pair
if quoteCurrency.String() != "" && baseCurrency.String() != "" {
currPair = currency.NewPairWithDelimiter(baseCurrency.String(),
quoteCurrency.String(),
b.ConfigCurrencyPairFormat.Delimiter)
}
orderDate := time.Unix(order.Date, 0)
@@ -371,7 +389,8 @@ func (b *Bitstamp) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) (
})
}
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks, getOrdersRequest.EndTicks)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks,
getOrdersRequest.EndTicks)
exchange.FilterOrdersByCurrencies(&orders, getOrdersRequest.Currencies)
return orders, nil

View File

@@ -10,6 +10,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -99,9 +100,9 @@ func (b *Bittrex) Setup(exch config.ExchangeConfig) {
b.SetHTTPClientUserAgent(exch.HTTPUserAgent)
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
b.BaseCurrencies = exch.BaseCurrencies
b.AvailablePairs = exch.AvailablePairs
b.EnabledPairs = exch.EnabledPairs
err := b.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)
@@ -528,7 +529,7 @@ func (b *Bittrex) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
case exchange.CryptocurrencyTradeFee:
fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount)
case exchange.CryptocurrencyWithdrawalFee:
fee, err = b.GetWithdrawalFee(feeBuilder.FirstCurrency)
fee, err = b.GetWithdrawalFee(feeBuilder.Pair.Base)
}
if fee < 0 {
fee = 0
@@ -537,7 +538,7 @@ func (b *Bittrex) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
}
// GetWithdrawalFee returns the fee for withdrawing from the exchange
func (b *Bittrex) GetWithdrawalFee(currency string) (float64, error) {
func (b *Bittrex) GetWithdrawalFee(c currency.Code) (float64, error) {
var fee float64
currencies, err := b.GetCurrencies()
@@ -545,7 +546,7 @@ func (b *Bittrex) GetWithdrawalFee(currency string) (float64, error) {
return 0, err
}
for _, result := range currencies.Result {
if result.Currency == currency {
if result.Currency == c.String() {
fee = result.TxFee
}
}

View File

@@ -6,8 +6,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
)
@@ -222,13 +221,10 @@ func TestGetDepositHistory(t *testing.T) {
func setFeeBuilder() exchange.FeeBuilder {
return exchange.FeeBuilder{
Amount: 1,
Delimiter: "",
FeeType: exchange.CryptocurrencyTradeFee,
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
IsMaker: false,
PurchasePrice: 1,
Amount: 1,
FeeType: exchange.CryptocurrencyTradeFee,
Pair: currency.NewPair(currency.BTC, currency.LTC),
PurchasePrice: 1,
}
}
@@ -288,7 +284,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankDepositFee
feeBuilder.CurrencyItem = symbol.HKD
feeBuilder.FiatCurrency = currency.HKD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
@@ -297,7 +293,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.CurrencyItem = symbol.HKD
feeBuilder.FiatCurrency = currency.HKD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
@@ -320,8 +316,9 @@ func TestGetActiveOrders(t *testing.T) {
TestSetup(t)
var getOrdersRequest = exchange.GetOrdersRequest{
OrderType: exchange.AnyOrderType,
Currencies: []pair.CurrencyPair{pair.NewCurrencyPair(symbol.BTC, symbol.LTC)},
OrderType: exchange.AnyOrderType,
Currencies: []currency.Pair{currency.NewPair(currency.LTC,
currency.BTC)},
}
getOrdersRequest.Currencies[0].Delimiter = "-"
@@ -368,10 +365,10 @@ func TestSubmitOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var p = pair.CurrencyPair{
Delimiter: "-",
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
var p = currency.Pair{
Delimiter: "-",
Base: currency.BTC,
Quote: currency.LTC,
}
response, err := b.SubmitOrder(p, exchange.BuyOrderSide, exchange.LimitOrderType, 1, 1, "clientId")
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
@@ -389,7 +386,7 @@ func TestCancelExchangeOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -415,7 +412,7 @@ func TestCancelAllExchangeOrders(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -450,7 +447,7 @@ func TestWithdraw(t *testing.T) {
TestSetup(t)
var withdrawCryptoRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.LTC,
Currency: currency.LTC,
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
Description: "WITHDRAW IT ALL",
}
@@ -502,12 +499,12 @@ func TestWithdrawInternationalBank(t *testing.T) {
func TestGetDepositAddress(t *testing.T) {
if areTestAPIKeysSet() {
_, err := b.GetDepositAddress(symbol.BTC, "")
_, err := b.GetDepositAddress(currency.BTC, "")
if err != nil {
t.Error("Test Failed - GetDepositAddress() error", err)
}
} else {
_, err := b.GetDepositAddress(symbol.BTC, "")
_, err := b.GetDepositAddress(currency.BTC, "")
if err == nil {
t.Error("Test Failed - GetDepositAddress() error cannot be nil")
}

View File

@@ -8,7 +8,7 @@ import (
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -36,19 +36,23 @@ func (b *Bittrex) Run() {
log.Errorf("%s Failed to get available symbols.\n", b.GetName())
} else {
forceUpgrade := false
if !common.StringDataContains(b.EnabledPairs, "-") || !common.StringDataContains(b.AvailablePairs, "-") {
if !common.StringDataContains(b.EnabledPairs.Strings(), "-") ||
!common.StringDataContains(b.AvailablePairs.Strings(), "-") {
forceUpgrade = true
}
var currencies []string
for x := range exchangeProducts.Result {
if !exchangeProducts.Result[x].IsActive || exchangeProducts.Result[x].MarketName == "" {
if !exchangeProducts.Result[x].IsActive ||
exchangeProducts.Result[x].MarketName == "" {
continue
}
currencies = append(currencies, exchangeProducts.Result[x].MarketName)
}
if forceUpgrade {
enabledPairs := []string{"USDT-BTC"}
enabledPairs := currency.Pairs{currency.Pair{Base: currency.USDT,
Quote: currency.BTC, Delimiter: "-"}}
log.Warn("Available pairs for Bittrex reset due to config upgrade, please enable the ones you would like again")
err = b.UpdateCurrencies(enabledPairs, true, true)
@@ -56,7 +60,14 @@ func (b *Bittrex) Run() {
log.Errorf("%s Failed to get config.", b.GetName())
}
}
err = b.UpdateCurrencies(currencies, false, forceUpgrade)
var newCurrencies currency.Pairs
for _, p := range currencies {
newCurrencies = append(newCurrencies,
currency.NewPairFromString(p))
}
err = b.UpdateCurrencies(newCurrencies, false, forceUpgrade)
if err != nil {
log.Errorf("%s Failed to get config.", b.GetName())
}
@@ -76,7 +87,7 @@ func (b *Bittrex) GetAccountInfo() (exchange.AccountInfo, error) {
var currencies []exchange.AccountCurrencyInfo
for i := 0; i < len(accountBalance.Result); i++ {
var exchangeCurrency exchange.AccountCurrencyInfo
exchangeCurrency.CurrencyName = accountBalance.Result[i].Currency
exchangeCurrency.CurrencyName = currency.NewCode(accountBalance.Result[i].Currency)
exchangeCurrency.TotalValue = accountBalance.Result[i].Balance
exchangeCurrency.Hold = accountBalance.Result[i].Balance - accountBalance.Result[i].Available
currencies = append(currencies, exchangeCurrency)
@@ -90,7 +101,7 @@ func (b *Bittrex) GetAccountInfo() (exchange.AccountInfo, error) {
}
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bittrex) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *Bittrex) UpdateTicker(p currency.Pair, assetType string) (ticker.Price, error) {
var tickerPrice ticker.Price
tick, err := b.GetMarketSummaries()
if err != nil {
@@ -110,14 +121,14 @@ func (b *Bittrex) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Pr
tickerPrice.Bid = tick.Result[y].Bid
tickerPrice.Last = tick.Result[y].Last
tickerPrice.Volume = tick.Result[y].Volume
ticker.ProcessTicker(b.GetName(), x, tickerPrice, assetType)
ticker.ProcessTicker(b.GetName(), tickerPrice, assetType)
}
}
return ticker.GetTicker(b.Name, p, assetType)
}
// GetTickerPrice returns the ticker for a currency pair
func (b *Bittrex) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *Bittrex) GetTickerPrice(p currency.Pair, assetType string) (ticker.Price, error) {
tick, err := ticker.GetTicker(b.GetName(), p, ticker.Spot)
if err != nil {
return b.UpdateTicker(p, assetType)
@@ -126,8 +137,8 @@ func (b *Bittrex) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.
}
// GetOrderbookEx returns the orderbook for a currency pair
func (b *Bittrex) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.GetOrderbook(b.GetName(), p, assetType)
func (b *Bittrex) GetOrderbookEx(p currency.Pair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.Get(b.GetName(), p, assetType)
if err != nil {
return b.UpdateOrderbook(p, assetType)
}
@@ -135,7 +146,7 @@ func (b *Bittrex) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbo
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (b *Bittrex) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
func (b *Bittrex) UpdateOrderbook(p currency.Pair, assetType string) (orderbook.Base, error) {
var orderBook orderbook.Base
orderbookNew, err := b.GetOrderbook(exchange.FormatExchangeCurrency(b.GetName(), p).String())
if err != nil {
@@ -160,8 +171,16 @@ func (b *Bittrex) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderb
)
}
orderbook.ProcessOrderbook(b.GetName(), p, orderBook, assetType)
return orderbook.GetOrderbook(b.Name, p, assetType)
orderBook.Pair = p
orderBook.ExchangeName = b.GetName()
orderBook.AssetType = assetType
err = orderBook.Process()
if err != nil {
return orderBook, err
}
return orderbook.Get(b.Name, p, assetType)
}
// GetFundingHistory returns funding history, deposits and
@@ -172,14 +191,14 @@ func (b *Bittrex) GetFundingHistory() ([]exchange.FundHistory, error) {
}
// GetExchangeHistory returns historic trade data since exchange opening.
func (b *Bittrex) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
func (b *Bittrex) GetExchangeHistory(p currency.Pair, assetType string) ([]exchange.TradeHistory, error) {
var resp []exchange.TradeHistory
return resp, common.ErrNotYetImplemented
}
// SubmitOrder submits a new order
func (b *Bittrex) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
func (b *Bittrex) SubmitOrder(p currency.Pair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
var submitOrderResponse exchange.SubmitOrderResponse
buy := side == exchange.BuyOrderSide
var response UUID
@@ -190,9 +209,9 @@ func (b *Bittrex) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orde
}
if buy {
response, err = b.PlaceBuyLimit(p.Pair().String(), amount, price)
response, err = b.PlaceBuyLimit(p.String(), amount, price)
} else {
response, err = b.PlaceSellLimit(p.Pair().String(), amount, price)
response, err = b.PlaceSellLimit(p.String(), amount, price)
}
if response.Result.ID != "" {
@@ -246,7 +265,7 @@ func (b *Bittrex) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
}
// GetDepositAddress returns a deposit address for a specified currency
func (b *Bittrex) GetDepositAddress(cryptocurrency pair.CurrencyItem, _ string) (string, error) {
func (b *Bittrex) GetDepositAddress(cryptocurrency currency.Code, _ string) (string, error) {
depositAddr, err := b.GetCryptoDepositAddress(cryptocurrency.String())
if err != nil {
return "", err
@@ -289,7 +308,7 @@ func (b *Bittrex) GetFeeByType(feeBuilder exchange.FeeBuilder) (float64, error)
func (b *Bittrex) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) ([]exchange.OrderDetail, error) {
var currPair string
if len(getOrdersRequest.Currencies) == 1 {
currPair = getOrdersRequest.Currencies[0].Pair().String()
currPair = getOrdersRequest.Currencies[0].String()
}
resp, err := b.GetOpenOrders(currPair)
@@ -305,7 +324,8 @@ func (b *Bittrex) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) ([
b.Name, "GetActiveOrders", order.OrderUUID, order.Opened)
}
currency := pair.NewCurrencyPairDelimiter(order.Exchange, b.ConfigCurrencyPairFormat.Delimiter)
pair := currency.NewPairDelimiter(order.Exchange,
b.ConfigCurrencyPairFormat.Delimiter)
orderType := exchange.OrderType(strings.ToUpper(order.Type))
orders = append(orders, exchange.OrderDetail{
@@ -316,12 +336,13 @@ func (b *Bittrex) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) ([
ID: order.OrderUUID,
Exchange: b.Name,
OrderType: orderType,
CurrencyPair: currency,
CurrencyPair: pair,
})
}
exchange.FilterOrdersByType(&orders, getOrdersRequest.OrderType)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks, getOrdersRequest.EndTicks)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks,
getOrdersRequest.EndTicks)
exchange.FilterOrdersByCurrencies(&orders, getOrdersRequest.Currencies)
return orders, nil
@@ -332,7 +353,7 @@ func (b *Bittrex) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) ([
func (b *Bittrex) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) ([]exchange.OrderDetail, error) {
var currPair string
if len(getOrdersRequest.Currencies) == 1 {
currPair = getOrdersRequest.Currencies[0].Pair().String()
currPair = getOrdersRequest.Currencies[0].String()
}
resp, err := b.GetOrderHistoryForCurrency(currPair)
@@ -348,7 +369,8 @@ func (b *Bittrex) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) ([
b.Name, "GetActiveOrders", order.OrderUUID, order.Opened)
}
currency := pair.NewCurrencyPairDelimiter(order.Exchange, b.ConfigCurrencyPairFormat.Delimiter)
pair := currency.NewPairDelimiter(order.Exchange,
b.ConfigCurrencyPairFormat.Delimiter)
orderType := exchange.OrderType(strings.ToUpper(order.Type))
orders = append(orders, exchange.OrderDetail{
@@ -360,12 +382,13 @@ func (b *Bittrex) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) ([
Exchange: b.Name,
OrderType: orderType,
Fee: order.Commission,
CurrencyPair: currency,
CurrencyPair: pair,
})
}
exchange.FilterOrdersByType(&orders, getOrdersRequest.OrderType)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks, getOrdersRequest.EndTicks)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks,
getOrdersRequest.EndTicks)
exchange.FilterOrdersByCurrencies(&orders, getOrdersRequest.Currencies)
return orders, nil

View File

@@ -6,6 +6,7 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -60,9 +61,9 @@ func (b *BTCC) Setup(exch config.ExchangeConfig) {
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket.SetWsStatusAndConnection(exch.Websocket)
b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
b.BaseCurrencies = exch.BaseCurrencies
b.AvailablePairs = exch.AvailablePairs
b.EnabledPairs = exch.EnabledPairs
err := b.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)
@@ -100,9 +101,9 @@ func (b *BTCC) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
switch feeBuilder.FeeType {
case exchange.CryptocurrencyWithdrawalFee:
fee = getCryptocurrencyWithdrawalFee(feeBuilder.FirstCurrency)
fee = getCryptocurrencyWithdrawalFee(feeBuilder.Pair.Base)
case exchange.InternationalBankWithdrawalFee:
fee = getInternationalBankWithdrawalFee(feeBuilder.CurrencyItem, feeBuilder.Amount)
fee = getInternationalBankWithdrawalFee(feeBuilder.FiatCurrency, feeBuilder.Amount)
}
if fee < 0 {
fee = 0
@@ -110,10 +111,10 @@ func (b *BTCC) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
return fee, nil
}
func getCryptocurrencyWithdrawalFee(currency string) float64 {
return WithdrawalFees[currency]
func getCryptocurrencyWithdrawalFee(c currency.Code) float64 {
return WithdrawalFees[c]
}
func getInternationalBankWithdrawalFee(currency string, amount float64) float64 {
return WithdrawalFees[currency] * amount
func getInternationalBankWithdrawalFee(c currency.Code, amount float64) float64 {
return WithdrawalFees[c] * amount
}

View File

@@ -6,8 +6,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
)
@@ -78,13 +77,10 @@ func TestSetup(t *testing.T) {
// }
func setFeeBuilder() exchange.FeeBuilder {
return exchange.FeeBuilder{
Amount: 1,
Delimiter: "",
FeeType: exchange.CryptocurrencyTradeFee,
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
IsMaker: false,
PurchasePrice: 1,
Amount: 1,
FeeType: exchange.CryptocurrencyTradeFee,
Pair: currency.NewPair(currency.BTC, currency.LTC),
PurchasePrice: 1,
}
}
@@ -144,7 +140,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankDepositFee
feeBuilder.CurrencyItem = symbol.USD
feeBuilder.FiatCurrency = currency.USD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
@@ -153,7 +149,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.CurrencyItem = symbol.USD
feeBuilder.FiatCurrency = currency.USD
if resp, err := b.GetFee(feeBuilder); resp != float64(0.005) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.005), resp)
t.Error(err)
@@ -221,10 +217,10 @@ func TestSubmitOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var p = pair.CurrencyPair{
Delimiter: "-",
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
var p = currency.Pair{
Delimiter: "-",
Base: currency.BTC,
Quote: currency.LTC,
}
_, err := b.SubmitOrder(p, exchange.BuyOrderSide, exchange.LimitOrderType, 1, 1, "clientId")
if err != common.ErrNotYetImplemented {
@@ -240,7 +236,7 @@ func TestCancelExchangeOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -263,7 +259,7 @@ func TestCancelAllExchangeOrders(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -284,7 +280,7 @@ func TestWithdraw(t *testing.T) {
TestSetup(t)
var withdrawCryptoRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.LTC,
Currency: currency.LTC,
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
Description: "WITHDRAW IT ALL",
}

View File

@@ -1,7 +1,10 @@
package btcc
import "encoding/json"
import "github.com/thrasher-/gocryptotrader/currency/symbol"
import (
"encoding/json"
"github.com/thrasher-/gocryptotrader/currency"
)
// WsAllTickerData defines multiple ticker data
type WsAllTickerData []WsTicker
@@ -84,12 +87,12 @@ type WsTicker struct {
// WithdrawalFees the large list of predefined withdrawal fees
// Prone to change
var WithdrawalFees = map[string]float64{
symbol.USD: 0.005,
symbol.USDT: 10,
symbol.BTC: 0.001,
symbol.ETH: 0.01,
symbol.BCH: 0.0001,
symbol.LTC: 0.001,
symbol.DASH: 0.002,
var WithdrawalFees = map[currency.Code]float64{
currency.USD: 0.005,
currency.USDT: 10,
currency.BTC: 0.001,
currency.ETH: 0.01,
currency.BCH: 0.0001,
currency.LTC: 0.001,
currency.DASH: 0.002,
}

View File

@@ -11,7 +11,7 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
log "github.com/thrasher-/gocryptotrader/logger"
@@ -221,7 +221,7 @@ func (b *BTCC) WsHandleData() {
tick.HighPrice = ticker.High
tick.LowPrice = ticker.Low
tick.OpenPrice = ticker.Open
tick.Pair = pair.NewCurrencyPairFromString(ticker.Symbol)
tick.Pair = currency.NewPairFromString(ticker.Symbol)
tick.Quantity = ticker.Volume
timestamp := time.Unix(ticker.Timestamp, 0)
tick.Timestamp = timestamp
@@ -300,9 +300,10 @@ func (b *BTCC) WsUpdateCurrencyPairs() error {
return err
}
var availableTickers []string
var availableTickers currency.Pairs
for _, tickerData := range tickers {
availableTickers = append(availableTickers, tickerData.Symbol)
availableTickers = append(availableTickers,
currency.NewPairFromString(tickerData.Symbol))
}
err = b.UpdateCurrencies(availableTickers, false, true)
@@ -407,9 +408,7 @@ func (b *BTCC) WsProcessOrderbookSnapshot(ob WsOrderbookSnapshot) error {
newOrderbook.Asks = asks
newOrderbook.AssetType = "SPOT"
newOrderbook.Bids = bids
newOrderbook.CurrencyPair = ob.Symbol
newOrderbook.LastUpdated = time.Now()
newOrderbook.Pair = pair.NewCurrencyPairFromString(ob.Symbol)
newOrderbook.Pair = currency.NewPairFromString(ob.Symbol)
err := b.Websocket.Orderbook.LoadSnapshot(newOrderbook, b.GetName(), false)
if err != nil {
@@ -419,7 +418,7 @@ func (b *BTCC) WsProcessOrderbookSnapshot(ob WsOrderbookSnapshot) error {
b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
Exchange: b.GetName(),
Asset: "SPOT",
Pair: pair.NewCurrencyPairFromString(ob.Symbol),
Pair: currency.NewPairFromString(ob.Symbol),
}
return nil
@@ -458,7 +457,7 @@ func (b *BTCC) WsProcessOrderbookUpdate(ob WsOrderbookSnapshot) error {
bids = append(bids, orderbook.Item{Price: data.Price, Amount: newSize})
}
p := pair.NewCurrencyPairFromString(ob.Symbol)
p := currency.NewPairFromString(ob.Symbol)
err := b.Websocket.Orderbook.Update(bids, asks, p, time.Now(), b.GetName(), "SPOT")
if err != nil {
@@ -468,7 +467,7 @@ func (b *BTCC) WsProcessOrderbookUpdate(ob WsOrderbookSnapshot) error {
b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
Exchange: b.GetName(),
Asset: "SPOT",
Pair: pair.NewCurrencyPairFromString(ob.Symbol),
Pair: currency.NewPairFromString(ob.Symbol),
}
return nil
@@ -545,7 +544,8 @@ func (b *BTCC) WsProcessOldOrderbookSnapshot(ob WsOrderbookSnapshotOld, symbol s
})
}
p := pair.NewCurrencyPairFromString(symbol)
p := currency.NewPairFromString(symbol)
err := b.Websocket.Orderbook.Update(bids, asks, p, time.Now(), b.GetName(), "SPOT")
if err != nil {
return err

View File

@@ -5,7 +5,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -29,9 +29,12 @@ func (b *BTCC) Run() {
log.Debugf("%s %d currencies enabled: %s.\n", b.GetName(), len(b.EnabledPairs), b.EnabledPairs)
}
if common.StringDataContains(b.EnabledPairs, "CNY") || common.StringDataContains(b.AvailablePairs, "CNY") || common.StringDataContains(b.BaseCurrencies, "CNY") {
if common.StringDataContains(b.EnabledPairs.Strings(), "CNY") ||
common.StringDataContains(b.AvailablePairs.Strings(), "CNY") ||
common.StringDataContains(b.BaseCurrencies.Strings(), "CNY") {
log.Warn("BTCC only supports BTCUSD now, upgrading available, enabled and base currencies to BTCUSD/USD")
pairs := []string{"BTCUSD"}
pairs := currency.Pairs{currency.Pair{Base: currency.BTC,
Quote: currency.USD}}
cfg := config.GetConfig()
exchCfg, err := cfg.GetExchangeConfig(b.Name)
if err != nil {
@@ -39,10 +42,10 @@ func (b *BTCC) Run() {
return
}
exchCfg.BaseCurrencies = "USD"
exchCfg.AvailablePairs = pairs[0]
exchCfg.EnabledPairs = pairs[0]
b.BaseCurrencies = []string{"USD"}
exchCfg.BaseCurrencies = currency.Currencies{currency.USD}
exchCfg.AvailablePairs = pairs
exchCfg.EnabledPairs = pairs
b.BaseCurrencies = currency.Currencies{currency.USD}
err = b.UpdateCurrencies(pairs, false, true)
if err != nil {
@@ -63,22 +66,22 @@ func (b *BTCC) Run() {
}
// UpdateTicker updates and returns the ticker for a currency pair
func (b *BTCC) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *BTCC) UpdateTicker(p currency.Pair, assetType string) (ticker.Price, error) {
return ticker.Price{}, common.ErrFunctionNotSupported
}
// GetTickerPrice returns the ticker for a currency pair
func (b *BTCC) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *BTCC) GetTickerPrice(p currency.Pair, assetType string) (ticker.Price, error) {
return ticker.Price{}, common.ErrFunctionNotSupported
}
// GetOrderbookEx returns the orderbook for a currency pair
func (b *BTCC) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
func (b *BTCC) GetOrderbookEx(p currency.Pair, assetType string) (orderbook.Base, error) {
return orderbook.Base{}, common.ErrFunctionNotSupported
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (b *BTCC) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
func (b *BTCC) UpdateOrderbook(p currency.Pair, assetType string) (orderbook.Base, error) {
return orderbook.Base{}, common.ErrFunctionNotSupported
}
@@ -95,12 +98,12 @@ func (b *BTCC) GetFundingHistory() ([]exchange.FundHistory, error) {
}
// GetExchangeHistory returns historic trade data since exchange opening.
func (b *BTCC) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
func (b *BTCC) GetExchangeHistory(p currency.Pair, assetType string) ([]exchange.TradeHistory, error) {
return nil, common.ErrFunctionNotSupported
}
// SubmitOrder submits a new order
func (b *BTCC) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) {
func (b *BTCC) SubmitOrder(p currency.Pair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) {
return exchange.SubmitOrderResponse{}, common.ErrNotYetImplemented
}
@@ -126,7 +129,7 @@ func (b *BTCC) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
}
// GetDepositAddress returns a deposit address for a specified currency
func (b *BTCC) GetDepositAddress(cryptocurrency pair.CurrencyItem, accountID string) (string, error) {
func (b *BTCC) GetDepositAddress(cryptocurrency currency.Code, accountID string) (string, error) {
return "", common.ErrFunctionNotSupported
}

View File

@@ -10,7 +10,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -89,9 +89,9 @@ func (b *BTCMarkets) Setup(exch config.ExchangeConfig) {
b.SetHTTPClientUserAgent(exch.HTTPUserAgent)
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
b.BaseCurrencies = exch.BaseCurrencies
b.AvailablePairs = exch.AvailablePairs
b.EnabledPairs = exch.EnabledPairs
err := b.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)
@@ -287,7 +287,6 @@ func (b *BTCMarkets) GetOrders(currency, instrument string, limit, since int64,
func (b *BTCMarkets) GetOpenOrders() ([]Order, error) {
type marketsResp struct {
Response
Orders []Order `json:"orders"`
}
req := make(map[string]interface{})
var resp marketsResp
@@ -369,9 +368,9 @@ func (b *BTCMarkets) GetAccountBalance() ([]AccountBalance, error) {
}
// GetTradingFee returns the account's trading fee for a currency pair
func (b *BTCMarkets) GetTradingFee(firstPair, secondPair string) (TradingFee, error) {
func (b *BTCMarkets) GetTradingFee(base, quote currency.Code) (TradingFee, error) {
var tradingFee TradingFee
path := fmt.Sprintf(btcMarketsTradingFee, firstPair, secondPair)
path := fmt.Sprintf(btcMarketsTradingFee, base, quote)
return tradingFee, b.SendAuthenticatedRequest(http.MethodGet, path, nil, &tradingFee)
}
@@ -386,7 +385,10 @@ func (b *BTCMarkets) WithdrawCrypto(amount float64, currency, address string) (s
}
resp := Response{}
err := b.SendAuthenticatedRequest(http.MethodPost, btcMarketsWithdrawCrypto, req, &resp)
err := b.SendAuthenticatedRequest(http.MethodPost,
btcMarketsWithdrawCrypto,
req,
&resp)
if err != nil {
return "", err
}
@@ -413,7 +415,9 @@ func (b *BTCMarkets) WithdrawAUD(accountName, accountNumber, bankName, bsbNumber
}
resp := Response{}
err := b.SendAuthenticatedRequest(http.MethodPost, btcMarketsWithdrawAud, req, &resp)
err := b.SendAuthenticatedRequest(http.MethodPost, btcMarketsWithdrawAud,
req,
&resp)
if err != nil {
return "", err
}
@@ -433,7 +437,8 @@ func (b *BTCMarkets) SendHTTPRequest(path string, result interface{}) error {
// SendAuthenticatedRequest sends an authenticated HTTP request
func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data, result interface{}) (err error) {
if !b.AuthenticatedAPISupport {
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, b.Name)
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet,
b.Name)
}
if b.Nonce.Get() == 0 {
@@ -454,10 +459,14 @@ func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data, result
req = path + "\n" + b.Nonce.String()[0:13] + "\n"
}
hmac := common.GetHMAC(common.HashSHA512, []byte(req), []byte(b.APISecret))
hmac := common.GetHMAC(common.HashSHA512,
[]byte(req), []byte(b.APISecret))
if b.Verbose {
log.Debugf("Sending %s request to URL %s with params %s\n", reqType, b.APIUrl+path, req)
log.Debugf("Sending %s request to URL %s with params %s\n",
reqType,
b.APIUrl+path,
req)
}
headers := make(map[string]string)
@@ -468,7 +477,13 @@ func (b *BTCMarkets) SendAuthenticatedRequest(reqType, path string, data, result
headers["timestamp"] = b.Nonce.String()[0:13]
headers["signature"] = common.Base64Encode(hmac)
return b.SendPayload(reqType, b.APIUrl+path, headers, bytes.NewBuffer(payload), result, true, b.Verbose)
return b.SendPayload(reqType,
b.APIUrl+path,
headers,
bytes.NewBuffer(payload),
result,
true,
b.Verbose)
}
// GetFee returns an estimate of fee based on type of transaction
@@ -477,15 +492,20 @@ func (b *BTCMarkets) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
switch feeBuilder.FeeType {
case exchange.CryptocurrencyTradeFee:
tradingFee, err := b.GetTradingFee(feeBuilder.FirstCurrency, feeBuilder.SecondCurrency)
tradingFee, err := b.GetTradingFee(feeBuilder.Pair.Base,
feeBuilder.Pair.Quote)
if err != nil {
return 0, err
}
fee = calculateTradingFee(tradingFee, feeBuilder.PurchasePrice, feeBuilder.Amount)
fee = calculateTradingFee(tradingFee,
feeBuilder.PurchasePrice,
feeBuilder.Amount)
case exchange.CryptocurrencyWithdrawalFee:
fee = getCryptocurrencyWithdrawalFee(feeBuilder.FirstCurrency)
fee = getCryptocurrencyWithdrawalFee(feeBuilder.Pair.Base)
case exchange.InternationalBankWithdrawalFee:
fee = getInternationalBankWithdrawalFee(feeBuilder.CurrencyItem)
fee = getInternationalBankWithdrawalFee(feeBuilder.FiatCurrency)
}
if fee < 0 {
fee = 0
@@ -498,14 +518,14 @@ func calculateTradingFee(tradingFee TradingFee, purchasePrice, amount float64) (
return fee * amount * purchasePrice
}
func getCryptocurrencyWithdrawalFee(currency string) float64 {
return WithdrawalFees[currency]
func getCryptocurrencyWithdrawalFee(c currency.Code) float64 {
return WithdrawalFees[c]
}
func getInternationalBankWithdrawalFee(currency string) float64 {
func getInternationalBankWithdrawalFee(c currency.Code) float64 {
var fee float64
if currency == symbol.AUD {
if c == currency.AUD {
fee = 0
}
return fee

View File

@@ -6,8 +6,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
)
@@ -168,13 +167,10 @@ func TestGetOrderInfo(t *testing.T) {
func setFeeBuilder() exchange.FeeBuilder {
return exchange.FeeBuilder{
Amount: 1,
Delimiter: "",
FeeType: exchange.CryptocurrencyTradeFee,
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
IsMaker: false,
PurchasePrice: 1,
Amount: 1,
FeeType: exchange.CryptocurrencyTradeFee,
Pair: currency.NewPair(currency.BTC, currency.LTC),
PurchasePrice: 1,
}
}
@@ -187,7 +183,7 @@ func TestGetFee(t *testing.T) {
if apiKey != "" || apiSecret != "" {
// CryptocurrencyTradeFee Fiat
feeBuilder = setFeeBuilder()
feeBuilder.SecondCurrency = symbol.USD
feeBuilder.Pair.Quote = currency.USD
if resp, err := b.GetFee(feeBuilder); resp != float64(0.00849999) || err != nil {
t.Error(err)
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.00849999), resp)
@@ -245,7 +241,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankDepositFee
feeBuilder.CurrencyItem = symbol.AUD
feeBuilder.FiatCurrency = currency.AUD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
@@ -254,7 +250,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.CurrencyItem = symbol.AUD
feeBuilder.FiatCurrency = currency.AUD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
@@ -293,8 +289,9 @@ func TestGetOrderHistory(t *testing.T) {
TestSetup(t)
var getOrdersRequest = exchange.GetOrdersRequest{
OrderType: exchange.AnyOrderType,
Currencies: []pair.CurrencyPair{pair.NewCurrencyPair(symbol.BTC, symbol.LTC)},
OrderType: exchange.AnyOrderType,
Currencies: []currency.Pair{currency.NewPair(currency.LTC,
currency.BTC)},
}
_, err := b.GetOrderHistory(getOrdersRequest)
@@ -323,10 +320,10 @@ func TestSubmitOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var p = pair.CurrencyPair{
Delimiter: "-",
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
var p = currency.Pair{
Delimiter: "-",
Base: currency.BTC,
Quote: currency.LTC,
}
response, err := b.SubmitOrder(p, exchange.BuyOrderSide, exchange.LimitOrderType, 1, 1, "clientId")
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
@@ -344,7 +341,7 @@ func TestCancelExchangeOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -370,7 +367,7 @@ func TestCancelAllExchangeOrders(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -405,7 +402,7 @@ func TestWithdraw(t *testing.T) {
TestSetup(t)
var withdrawCryptoRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.LTC,
Currency: currency.LTC,
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
Description: "WITHDRAW IT ALL",
}
@@ -433,7 +430,7 @@ func TestWithdrawFiat(t *testing.T) {
var withdrawFiatRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.AUD,
Currency: currency.AUD,
Description: "WITHDRAW IT ALL",
BankAccountName: "Satoshi Nakamoto",
BankAccountNumber: 12345,
@@ -441,7 +438,7 @@ func TestWithdrawFiat(t *testing.T) {
BankCity: "Tarry Town",
BankCountry: "Hyrule",
BankName: "Commonwealth Bank of Australia",
WireCurrency: symbol.AUD,
WireCurrency: currency.AUD.String(),
SwiftCode: "Taylor",
RequiresIntermediaryBank: false,
IsExpressWire: false,
@@ -473,7 +470,7 @@ func TestWithdrawInternationalBank(t *testing.T) {
}
func TestGetDepositAddress(t *testing.T) {
_, err := b.GetDepositAddress(symbol.BTC, "")
_, err := b.GetDepositAddress(currency.BTC, "")
if err == nil {
t.Error("Test Failed - GetDepositAddress() error cannot be nil")
}

View File

@@ -1,6 +1,6 @@
package btcmarkets
import "github.com/thrasher-/gocryptotrader/currency/symbol"
import "github.com/thrasher-/gocryptotrader/currency"
// Response is the genralized response type
type Response struct {
@@ -129,14 +129,14 @@ type WithdrawRequestAUD struct {
// WithdrawalFees the large list of predefined withdrawal fees
// Prone to change
var WithdrawalFees = map[string]float64{
symbol.AUD: 0,
symbol.BTC: 0.001,
symbol.ETH: 0.001,
symbol.ETC: 0.001,
symbol.LTC: 0.0001,
symbol.XRP: 0.15,
symbol.BCH: 0.0001,
symbol.OMG: 0.15,
symbol.POWR: 5,
var WithdrawalFees = map[currency.Code]float64{
currency.AUD: 0,
currency.BTC: 0.001,
currency.ETH: 0.001,
currency.ETC: 0.001,
currency.LTC: 0.0001,
currency.XRP: 0.15,
currency.BCH: 0.0001,
currency.OMG: 0.15,
currency.POWR: 5,
}

View File

@@ -9,8 +9,7 @@ import (
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -38,17 +37,22 @@ func (b *BTCMarkets) Run() {
log.Errorf("%s failed to get active market. Err: %s", b.Name, err)
} else {
forceUpgrade := false
if !common.StringDataContains(b.EnabledPairs, "-") || !common.StringDataContains(b.AvailablePairs, "-") {
if !common.StringDataContains(b.EnabledPairs.Strings(), "-") ||
!common.StringDataContains(b.AvailablePairs.Strings(), "-") {
forceUpgrade = true
}
var currencies []string
var currencies currency.Pairs
for x := range markets {
currencies = append(currencies, markets[x].Instrument+"-"+markets[x].Currency)
currencies = append(currencies,
currency.NewPairWithDelimiter(markets[x].Instrument,
markets[x].Currency, "-"))
}
if forceUpgrade {
enabledPairs := []string{"BTC-AUD"}
enabledPairs := currency.Pairs{currency.Pair{Base: currency.BTC,
Quote: currency.AUD, Delimiter: "-"}}
log.Warn("Available pairs for BTC Makrets reset due to config upgrade, please enable the pairs you would like again.")
err = b.UpdateCurrencies(enabledPairs, true, true)
@@ -64,10 +68,9 @@ func (b *BTCMarkets) Run() {
}
// UpdateTicker updates and returns the ticker for a currency pair
func (b *BTCMarkets) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *BTCMarkets) UpdateTicker(p currency.Pair, assetType string) (ticker.Price, error) {
var tickerPrice ticker.Price
tick, err := b.GetTicker(p.FirstCurrency.String(),
p.SecondCurrency.String())
tick, err := b.GetTicker(p.Base.String(), p.Quote.String())
if err != nil {
return tickerPrice, err
}
@@ -75,12 +78,17 @@ func (b *BTCMarkets) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker
tickerPrice.Ask = tick.BestAsk
tickerPrice.Bid = tick.BestBID
tickerPrice.Last = tick.LastPrice
ticker.ProcessTicker(b.GetName(), p, tickerPrice, assetType)
err = ticker.ProcessTicker(b.GetName(), tickerPrice, assetType)
if err != nil {
return tickerPrice, err
}
return ticker.GetTicker(b.Name, p, assetType)
}
// GetTickerPrice returns the ticker for a currency pair
func (b *BTCMarkets) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *BTCMarkets) GetTickerPrice(p currency.Pair, assetType string) (ticker.Price, error) {
tickerNew, err := ticker.GetTicker(b.GetName(), p, assetType)
if err != nil {
return b.UpdateTicker(p, assetType)
@@ -89,8 +97,8 @@ func (b *BTCMarkets) GetTickerPrice(p pair.CurrencyPair, assetType string) (tick
}
// GetOrderbookEx returns orderbook base on the currency pair
func (b *BTCMarkets) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.GetOrderbook(b.GetName(), p, assetType)
func (b *BTCMarkets) GetOrderbookEx(p currency.Pair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.Get(b.GetName(), p, assetType)
if err != nil {
return b.UpdateOrderbook(p, assetType)
}
@@ -98,10 +106,10 @@ func (b *BTCMarkets) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orde
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (b *BTCMarkets) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
func (b *BTCMarkets) UpdateOrderbook(p currency.Pair, assetType string) (orderbook.Base, error) {
var orderBook orderbook.Base
orderbookNew, err := b.GetOrderbook(p.FirstCurrency.String(),
p.SecondCurrency.String())
orderbookNew, err := b.GetOrderbook(p.Base.String(),
p.Quote.String())
if err != nil {
return orderBook, err
}
@@ -116,8 +124,16 @@ func (b *BTCMarkets) UpdateOrderbook(p pair.CurrencyPair, assetType string) (ord
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: data[1], Price: data[0]})
}
orderbook.ProcessOrderbook(b.GetName(), p, orderBook, assetType)
return orderbook.GetOrderbook(b.Name, p, assetType)
orderBook.Pair = p
orderBook.ExchangeName = b.GetName()
orderBook.AssetType = assetType
err = orderBook.Process()
if err != nil {
return orderBook, err
}
return orderbook.Get(b.Name, p, assetType)
}
// GetAccountInfo retrieves balances for all enabled currencies for the
@@ -134,7 +150,7 @@ func (b *BTCMarkets) GetAccountInfo() (exchange.AccountInfo, error) {
var currencies []exchange.AccountCurrencyInfo
for i := 0; i < len(accountBalance); i++ {
var exchangeCurrency exchange.AccountCurrencyInfo
exchangeCurrency.CurrencyName = accountBalance[i].Currency
exchangeCurrency.CurrencyName = currency.NewCode(accountBalance[i].Currency)
exchangeCurrency.TotalValue = accountBalance[i].Balance
exchangeCurrency.Hold = accountBalance[i].PendingFunds
@@ -156,16 +172,22 @@ func (b *BTCMarkets) GetFundingHistory() ([]exchange.FundHistory, error) {
}
// GetExchangeHistory returns historic trade data since exchange opening.
func (b *BTCMarkets) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
func (b *BTCMarkets) GetExchangeHistory(p currency.Pair, assetType string) ([]exchange.TradeHistory, error) {
var resp []exchange.TradeHistory
return resp, common.ErrNotYetImplemented
}
// SubmitOrder submits a new order
func (b *BTCMarkets) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) {
func (b *BTCMarkets) SubmitOrder(p currency.Pair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) {
var submitOrderResponse exchange.SubmitOrderResponse
response, err := b.NewOrder(p.FirstCurrency.Upper().String(), p.SecondCurrency.Upper().String(), price, amount, side.ToString(), orderType.ToString(), clientID)
response, err := b.NewOrder(p.Base.Upper().String(),
p.Quote.Upper().String(),
price,
amount,
side.ToString(),
orderType.ToString(),
clientID)
if response > 0 {
submitOrderResponse.OrderID = fmt.Sprintf("%v", response)
@@ -270,14 +292,16 @@ func (b *BTCMarkets) GetOrderInfo(orderID string) (exchange.OrderDetail, error)
OrderDetail.OrderType = orderType
OrderDetail.Price = order.Price
OrderDetail.Status = order.Status
OrderDetail.CurrencyPair = pair.NewCurrencyPairWithDelimiter(order.Instrument, order.Currency, b.ConfigCurrencyPairFormat.Delimiter)
OrderDetail.CurrencyPair = currency.NewPairWithDelimiter(order.Instrument,
order.Currency,
b.ConfigCurrencyPairFormat.Delimiter)
}
return OrderDetail, nil
}
// GetDepositAddress returns a deposit address for a specified currency
func (b *BTCMarkets) GetDepositAddress(cryptocurrency pair.CurrencyItem, accountID string) (string, error) {
func (b *BTCMarkets) GetDepositAddress(cryptocurrency currency.Code, accountID string) (string, error) {
return "", common.ErrFunctionNotSupported
}
@@ -289,7 +313,7 @@ func (b *BTCMarkets) WithdrawCryptocurrencyFunds(withdrawRequest exchange.Withdr
// WithdrawFiatFunds returns a withdrawal ID when a
// withdrawal is submitted
func (b *BTCMarkets) WithdrawFiatFunds(withdrawRequest exchange.WithdrawRequest) (string, error) {
if withdrawRequest.Currency != symbol.AUD {
if withdrawRequest.Currency != currency.AUD {
return "", errors.New("only AUD is supported for withdrawals")
}
return b.WithdrawAUD(withdrawRequest.BankAccountName, fmt.Sprintf("%v", withdrawRequest.BankAccountNumber), withdrawRequest.BankName, fmt.Sprintf("%v", withdrawRequest.BankCode), withdrawRequest.Amount)
@@ -339,7 +363,9 @@ func (b *BTCMarkets) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest)
OrderType: orderType,
Price: order.Price,
Status: order.Status,
CurrencyPair: pair.NewCurrencyPairWithDelimiter(order.Instrument, order.Currency, b.ConfigCurrencyPairFormat.Delimiter),
CurrencyPair: currency.NewPairWithDelimiter(order.Instrument,
order.Currency,
b.ConfigCurrencyPairFormat.Delimiter),
}
for _, trade := range order.Trades {
@@ -359,7 +385,8 @@ func (b *BTCMarkets) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest)
}
exchange.FilterOrdersByType(&orders, getOrdersRequest.OrderType)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks, getOrdersRequest.EndTicks)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks,
getOrdersRequest.EndTicks)
exchange.FilterOrdersBySide(&orders, getOrdersRequest.OrderSide)
return orders, nil
@@ -374,7 +401,11 @@ func (b *BTCMarkets) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest)
var respOrders []Order
for _, currency := range getOrdersRequest.Currencies {
resp, err := b.GetOrders(currency.FirstCurrency.String(), currency.SecondCurrency.String(), 200, 0, true)
resp, err := b.GetOrders(currency.Base.String(),
currency.Quote.String(),
200,
0,
true)
if err != nil {
return nil, err
}
@@ -402,7 +433,9 @@ func (b *BTCMarkets) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest)
OrderType: orderType,
Price: order.Price,
Status: order.Status,
CurrencyPair: pair.NewCurrencyPairWithDelimiter(order.Instrument, order.Currency, b.ConfigCurrencyPairFormat.Delimiter),
CurrencyPair: currency.NewPairWithDelimiter(order.Instrument,
order.Currency,
b.ConfigCurrencyPairFormat.Delimiter),
}
for _, trade := range order.Trades {

View File

@@ -11,7 +11,7 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -82,9 +82,9 @@ func (b *BTSE) Setup(exch config.ExchangeConfig) {
b.RESTPollingDelay = exch.RESTPollingDelay
b.Verbose = exch.Verbose
b.Websocket.SetWsStatusAndConnection(exch.Websocket)
b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
b.BaseCurrencies = exch.BaseCurrencies
b.AvailablePairs = exch.AvailablePairs
b.EnabledPairs = exch.EnabledPairs
err := b.SetCurrencyPairFormat()
if err != nil {
log.Fatal(err)
@@ -312,9 +312,9 @@ func (b *BTSE) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
case exchange.CryptocurrencyTradeFee:
fee = calculateTradingFee(feeBuilder.IsMaker)
case exchange.CryptocurrencyWithdrawalFee:
if feeBuilder.FirstCurrency == symbol.BTC {
if feeBuilder.Pair.Base.Match(currency.BTC) {
fee = 0.0005
} else if feeBuilder.FirstCurrency == symbol.USDT {
} else if feeBuilder.Pair.Base.Match(currency.USDT) {
fee = 5
}
case exchange.InternationalBankDepositFee:

View File

@@ -5,8 +5,7 @@ import (
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
)
@@ -146,11 +145,10 @@ func TestGetFee(t *testing.T) {
TestSetup(t)
feeBuilder := exchange.FeeBuilder{
FeeType: exchange.CryptocurrencyTradeFee,
FirstCurrency: "BTC",
SecondCurrency: "USD",
IsMaker: true,
Amount: 1000,
FeeType: exchange.CryptocurrencyTradeFee,
Pair: currency.NewPair(currency.BTC, currency.USD),
IsMaker: true,
Amount: 1000,
}
if resp, err := b.GetFee(feeBuilder); resp != 0.00050 || err != nil {
@@ -170,7 +168,7 @@ func TestGetFee(t *testing.T) {
t.Error(err)
}
feeBuilder.FirstCurrency = "USDT"
feeBuilder.Pair.Base = currency.USDT
if resp, err := b.GetFee(feeBuilder); resp != float64(5) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(5), resp)
t.Error(err)
@@ -227,10 +225,10 @@ func TestSubmitOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var p = pair.CurrencyPair{
Delimiter: "",
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.USD,
var p = currency.Pair{
Delimiter: "",
Base: currency.BTC,
Quote: currency.USD,
}
response, err := b.SubmitOrder(p, exchange.SellOrderSide, exchange.LimitOrderType, 0.01, 1000000, "clientId")
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
@@ -248,7 +246,9 @@ func TestCancelExchangeOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPairWithDelimiter(symbol.BTC, symbol.USD, "-")
currencyPair := currency.NewPairWithDelimiter(currency.BTC.String(),
currency.USD.String(),
"-")
var orderCancellation = exchange.OrderCancellation{
OrderID: "0b66ccaf-dfd4-4b9f-a30b-2380b9c7b66d",
@@ -274,7 +274,9 @@ func TestCancelAllExchangeOrders(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPairWithDelimiter(symbol.BTC, symbol.USD, "-")
currencyPair := currency.NewPairWithDelimiter(currency.BTC.String(),
currency.USD.String(),
"-")
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",

View File

@@ -11,7 +11,7 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
)
@@ -28,11 +28,11 @@ func (b *BTSE) WebsocketSubscriber() error {
Channels: []websocketChannel{
{
Name: "snapshot",
ProductIDs: b.EnabledPairs,
ProductIDs: b.EnabledPairs.Strings(),
},
{
Name: "ticker",
ProductIDs: b.EnabledPairs,
ProductIDs: b.EnabledPairs.Strings(),
},
},
}
@@ -146,7 +146,7 @@ func (b *BTSE) WsHandleData() {
b.Websocket.DataHandler <- exchange.TickerData{
Timestamp: time.Now(),
Pair: pair.NewCurrencyPairDelimiter(t.ProductID, "-"),
Pair: currency.NewPairDelimiter(t.ProductID, "-"),
AssetType: "SPOT",
Exchange: b.GetName(),
OpenPrice: price,
@@ -206,12 +206,16 @@ func (b *BTSE) wsProcessSnapshot(snapshot websocketOrderbookSnapshot) error {
orderbook.Item{Price: price, Amount: amount})
}
p := pair.NewCurrencyPairDelimiter(snapshot.ProductID, "-")
p := currency.NewPairDelimiter(snapshot.ProductID, "-")
base.AssetType = "SPOT"
base.Pair = p
base.CurrencyPair = snapshot.ProductID
base.LastUpdated = time.Now()
orderbook.ProcessOrderbook(b.Name, p, base, "SPOT")
base.ExchangeName = b.Name
err := base.Process()
if err != nil {
return err
}
b.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
Pair: p,

View File

@@ -8,7 +8,7 @@ import (
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -40,7 +40,9 @@ func (b *BTSE) Run() {
for _, m := range *markets {
currencies = append(currencies, m.ID)
}
err = b.UpdateCurrencies(currencies, false, false)
err = b.UpdateCurrencies(currency.NewPairsFromStrings(currencies),
false,
false)
if err != nil {
log.Errorf("%s Failed to update available currencies.\n", b.Name)
}
@@ -49,7 +51,7 @@ func (b *BTSE) Run() {
}
// UpdateTicker updates and returns the ticker for a currency pair
func (b *BTSE) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *BTSE) UpdateTicker(p currency.Pair, assetType string) (ticker.Price, error) {
var tickerPrice ticker.Price
t, err := b.GetTicker(exchange.FormatExchangeCurrency(b.Name, p).String())
@@ -70,12 +72,16 @@ func (b *BTSE) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price
tickerPrice.Last = t.Price
tickerPrice.Volume = s.Volume
tickerPrice.High = s.High
ticker.ProcessTicker(b.GetName(), p, tickerPrice, assetType)
err = ticker.ProcessTicker(b.GetName(), tickerPrice, assetType)
if err != nil {
return tickerPrice, err
}
return ticker.GetTicker(b.Name, p, assetType)
}
// GetTickerPrice returns the ticker for a currency pair
func (b *BTSE) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (b *BTSE) GetTickerPrice(p currency.Pair, assetType string) (ticker.Price, error) {
tickerNew, err := ticker.GetTicker(b.GetName(), p, assetType)
if err != nil {
return b.UpdateTicker(p, assetType)
@@ -84,8 +90,8 @@ func (b *BTSE) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Pri
}
// GetOrderbookEx returns orderbook base on the currency pair
func (b *BTSE) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.GetOrderbook(b.GetName(), p, assetType)
func (b *BTSE) GetOrderbookEx(p currency.Pair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.Get(b.GetName(), p, assetType)
if err != nil {
return b.UpdateOrderbook(p, assetType)
}
@@ -93,7 +99,7 @@ func (b *BTSE) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (b *BTSE) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
func (b *BTSE) UpdateOrderbook(p currency.Pair, assetType string) (orderbook.Base, error) {
return orderbook.Base{}, common.ErrFunctionNotSupported
}
@@ -110,7 +116,7 @@ func (b *BTSE) GetAccountInfo() (exchange.AccountInfo, error) {
for _, b := range *balance {
currencies = append(currencies,
exchange.AccountCurrencyInfo{
CurrencyName: b.Currency,
CurrencyName: currency.NewCode(b.Currency),
TotalValue: b.Total,
Hold: b.Available,
},
@@ -132,12 +138,12 @@ func (b *BTSE) GetFundingHistory() ([]exchange.FundHistory, error) {
}
// GetExchangeHistory returns historic trade data since exchange opening.
func (b *BTSE) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
func (b *BTSE) GetExchangeHistory(p currency.Pair, assetType string) ([]exchange.TradeHistory, error) {
return nil, common.ErrNotYetImplemented
}
// SubmitOrder submits a new order
func (b *BTSE) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) {
func (b *BTSE) SubmitOrder(p currency.Pair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, clientID string) (exchange.SubmitOrderResponse, error) {
var resp exchange.SubmitOrderResponse
r, err := b.CreateOrder(amount, price, side.ToString(),
orderType.ToString(), exchange.FormatExchangeCurrency(b.Name, p).String(), "GTC", clientID)
@@ -220,7 +226,7 @@ func (b *BTSE) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
side = exchange.SellOrderSide
}
od.CurrencyPair = pair.NewCurrencyPairDelimiter(o.ProductID,
od.CurrencyPair = currency.NewPairDelimiter(o.ProductID,
b.ConfigCurrencyPairFormat.Delimiter)
od.Exchange = b.Name
od.Amount = o.Amount
@@ -253,7 +259,7 @@ func (b *BTSE) GetOrderInfo(orderID string) (exchange.OrderDetail, error) {
}
// GetDepositAddress returns a deposit address for a specified currency
func (b *BTSE) GetDepositAddress(cryptocurrency pair.CurrencyItem, accountID string) (string, error) {
func (b *BTSE) GetDepositAddress(cryptocurrency currency.Code, accountID string) (string, error) {
return "", common.ErrFunctionNotSupported
}
@@ -295,7 +301,7 @@ func (b *BTSE) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) ([]ex
}
openOrder := exchange.OrderDetail{
CurrencyPair: pair.NewCurrencyPairDelimiter(order.ProductID,
CurrencyPair: currency.NewPairDelimiter(order.ProductID,
b.ConfigCurrencyPairFormat.Delimiter),
Exchange: b.Name,
Amount: order.Amount,

View File

@@ -13,7 +13,7 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/request"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -104,9 +104,9 @@ func (c *CoinbasePro) Setup(exch config.ExchangeConfig) {
c.RESTPollingDelay = exch.RESTPollingDelay
c.Verbose = exch.Verbose
c.Websocket.SetWsStatusAndConnection(exch.Websocket)
c.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
c.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
c.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
c.BaseCurrencies = exch.BaseCurrencies
c.AvailablePairs = exch.AvailablePairs
c.EnabledPairs = exch.EnabledPairs
if exch.UseSandbox {
c.APIUrl = coinbaseproSandboxAPIURL
}
@@ -798,7 +798,8 @@ func (c *CoinbasePro) SendHTTPRequest(path string, result interface{}) error {
// SendAuthenticatedHTTPRequest sends an authenticated HTTP reque
func (c *CoinbasePro) SendAuthenticatedHTTPRequest(method, path string, params map[string]interface{}, result interface{}) (err error) {
if !c.AuthenticatedAPISupport {
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet, c.Name)
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet,
c.Name)
}
payload := []byte("")
@@ -824,7 +825,13 @@ func (c *CoinbasePro) SendAuthenticatedHTTPRequest(method, path string, params m
headers["CB-ACCESS-PASSPHRASE"] = c.ClientID
headers["Content-Type"] = "application/json"
return c.SendPayload(method, c.APIUrl+path, headers, bytes.NewBuffer(payload), result, true, c.Verbose)
return c.SendPayload(method,
c.APIUrl+path,
headers,
bytes.NewBuffer(payload),
result,
true,
c.Verbose)
}
// GetFee returns an estimate of fee based on type of transaction
@@ -836,11 +843,17 @@ func (c *CoinbasePro) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
if err != nil {
return 0, err
}
fee = c.calculateTradingFee(trailingVolume, feeBuilder.FirstCurrency, feeBuilder.Delimiter, feeBuilder.SecondCurrency, feeBuilder.PurchasePrice, feeBuilder.Amount, feeBuilder.IsMaker)
fee = c.calculateTradingFee(trailingVolume,
feeBuilder.Pair.Base,
feeBuilder.Pair.Quote,
feeBuilder.Pair.Delimiter,
feeBuilder.PurchasePrice,
feeBuilder.Amount,
feeBuilder.IsMaker)
case exchange.InternationalBankWithdrawalFee:
fee = getInternationalBankWithdrawalFee(feeBuilder.CurrencyItem)
fee = getInternationalBankWithdrawalFee(feeBuilder.FiatCurrency)
case exchange.InternationalBankDepositFee:
fee = getInternationalBankDepositFee(feeBuilder.CurrencyItem)
fee = getInternationalBankDepositFee(feeBuilder.FiatCurrency)
}
if fee < 0 {
@@ -850,10 +863,10 @@ func (c *CoinbasePro) GetFee(feeBuilder exchange.FeeBuilder) (float64, error) {
return fee, nil
}
func (c *CoinbasePro) calculateTradingFee(trailingVolume []Volume, firstCurrency, delimiter, secondCurrency string, purchasePrice, amount float64, isMaker bool) float64 {
func (c *CoinbasePro) calculateTradingFee(trailingVolume []Volume, base, quote currency.Code, delimiter string, purchasePrice, amount float64, isMaker bool) float64 {
var fee float64
for _, i := range trailingVolume {
if strings.EqualFold(i.ProductID, firstCurrency+delimiter+secondCurrency) {
if strings.EqualFold(i.ProductID, base.String()+delimiter+quote.String()) {
switch {
case isMaker:
fee = 0
@@ -870,24 +883,24 @@ func (c *CoinbasePro) calculateTradingFee(trailingVolume []Volume, firstCurrency
return fee * amount * purchasePrice
}
func getInternationalBankWithdrawalFee(currency string) float64 {
func getInternationalBankWithdrawalFee(c currency.Code) float64 {
var fee float64
if currency == symbol.USD {
if c == currency.USD {
fee = 25
} else if currency == symbol.EUR {
} else if c == currency.EUR {
fee = 0.15
}
return fee
}
func getInternationalBankDepositFee(currency string) float64 {
func getInternationalBankDepositFee(c currency.Code) float64 {
var fee float64
if currency == symbol.USD {
if c == currency.USD {
fee = 10
} else if currency == symbol.EUR {
} else if c == currency.EUR {
fee = 0.15
}

View File

@@ -5,8 +5,7 @@ import (
"time"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency/symbol"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
)
@@ -224,13 +223,10 @@ func TestAuthRequests(t *testing.T) {
func setFeeBuilder() exchange.FeeBuilder {
return exchange.FeeBuilder{
Amount: 1,
Delimiter: "",
FeeType: exchange.CryptocurrencyTradeFee,
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
IsMaker: false,
PurchasePrice: 1,
Amount: 1,
FeeType: exchange.CryptocurrencyTradeFee,
Pair: currency.NewPair(currency.BTC, currency.LTC),
PurchasePrice: 1,
}
}
@@ -292,7 +288,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankDepositFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankDepositFee
feeBuilder.CurrencyItem = symbol.EUR
feeBuilder.FiatCurrency = currency.EUR
if resp, err := c.GetFee(feeBuilder); resp != float64(0.15) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
@@ -301,7 +297,7 @@ func TestGetFee(t *testing.T) {
// InternationalBankWithdrawalFee Basic
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.CurrencyItem = symbol.USD
feeBuilder.FiatCurrency = currency.USD
if resp, err := c.GetFee(feeBuilder); resp != float64(25) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
@@ -318,7 +314,7 @@ func TestCalculateTradingFee(t *testing.T) {
},
}
if resp := c.calculateTradingFee(volume, "btc", "_", "usd", 1, 1, false); resp != float64(0.003) {
if resp := c.calculateTradingFee(volume, currency.BTC, currency.USD, "_", 1, 1, false); resp != float64(0.003) {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.003), resp)
}
@@ -330,7 +326,7 @@ func TestCalculateTradingFee(t *testing.T) {
},
}
if resp := c.calculateTradingFee(volume, "btc", "_", "usd", 1, 1, false); resp != float64(0.003) {
if resp := c.calculateTradingFee(volume, currency.BTC, currency.USD, "_", 1, 1, false); resp != float64(0.003) {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.003), resp)
}
@@ -342,7 +338,7 @@ func TestCalculateTradingFee(t *testing.T) {
},
}
if resp := c.calculateTradingFee(volume, "btc", "_", "usd", 1, 1, false); resp != float64(0.003) {
if resp := c.calculateTradingFee(volume, currency.BTC, currency.USD, "_", 1, 1, false); resp != float64(0.003) {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.003), resp)
}
@@ -354,7 +350,7 @@ func TestCalculateTradingFee(t *testing.T) {
},
}
if resp := c.calculateTradingFee(volume, "btc", "_", "usd", 1, 1, false); resp != float64(0.002) {
if resp := c.calculateTradingFee(volume, currency.BTC, currency.USD, "_", 1, 1, false); resp != float64(0.002) {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.002), resp)
}
@@ -366,7 +362,7 @@ func TestCalculateTradingFee(t *testing.T) {
},
}
if resp := c.calculateTradingFee(volume, "btc", "_", "usd", 1, 1, false); resp != float64(0.001) {
if resp := c.calculateTradingFee(volume, currency.BTC, currency.USD, "_", 1, 1, false); resp != float64(0.001) {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.001), resp)
}
@@ -378,7 +374,7 @@ func TestCalculateTradingFee(t *testing.T) {
},
}
if resp := c.calculateTradingFee(volume, "btc", "_", "usd", 1, 1, false); resp != float64(0) {
if resp := c.calculateTradingFee(volume, currency.BTC, currency.USD, "_", 1, 1, false); resp != float64(0) {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
}
@@ -390,7 +386,7 @@ func TestCalculateTradingFee(t *testing.T) {
},
}
if resp := c.calculateTradingFee(volume, "btc", "_", "usd", 1, 1, true); resp != float64(0) {
if resp := c.calculateTradingFee(volume, currency.BTC, currency.USD, "_", 1, 1, true); resp != float64(0) {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
}
}
@@ -412,8 +408,9 @@ func TestGetActiveOrders(t *testing.T) {
TestSetup(t)
var getOrdersRequest = exchange.GetOrdersRequest{
OrderType: exchange.AnyOrderType,
Currencies: []pair.CurrencyPair{pair.NewCurrencyPair(symbol.BTC, symbol.LTC)},
OrderType: exchange.AnyOrderType,
Currencies: []currency.Pair{currency.NewPair(currency.BTC,
currency.LTC)},
}
_, err := c.GetActiveOrders(getOrdersRequest)
@@ -429,8 +426,9 @@ func TestGetOrderHistory(t *testing.T) {
TestSetup(t)
var getOrdersRequest = exchange.GetOrdersRequest{
OrderType: exchange.AnyOrderType,
Currencies: []pair.CurrencyPair{pair.NewCurrencyPair(symbol.BTC, symbol.LTC)},
OrderType: exchange.AnyOrderType,
Currencies: []currency.Pair{currency.NewPair(currency.BTC,
currency.LTC)},
}
_, err := c.GetOrderHistory(getOrdersRequest)
@@ -459,10 +457,10 @@ func TestSubmitOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var p = pair.CurrencyPair{
Delimiter: "-",
FirstCurrency: symbol.BTC,
SecondCurrency: symbol.LTC,
var p = currency.Pair{
Delimiter: "-",
Base: currency.BTC,
Quote: currency.LTC,
}
response, err := c.SubmitOrder(p, exchange.BuyOrderSide, exchange.LimitOrderType, 1, 1, "clientId")
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
@@ -481,7 +479,7 @@ func TestCancelExchangeOrder(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -508,7 +506,7 @@ func TestCancelAllExchangeOrders(t *testing.T) {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
currencyPair := pair.NewCurrencyPair(symbol.LTC, symbol.BTC)
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
var orderCancellation = exchange.OrderCancellation{
OrderID: "1",
@@ -543,7 +541,7 @@ func TestWithdraw(t *testing.T) {
TestSetup(t)
var withdrawCryptoRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.LTC,
Currency: currency.LTC,
Address: "1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB",
Description: "WITHDRAW IT ALL",
}
@@ -571,7 +569,7 @@ func TestWithdrawFiat(t *testing.T) {
var withdrawFiatRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.USD,
Currency: currency.USD,
BankName: "Federal Reserve Bank",
}
@@ -594,7 +592,7 @@ func TestWithdrawInternationalBank(t *testing.T) {
var withdrawFiatRequest = exchange.WithdrawRequest{
Amount: 100,
Currency: symbol.USD,
Currency: currency.USD,
BankName: "Federal Reserve Bank",
}
@@ -608,7 +606,7 @@ func TestWithdrawInternationalBank(t *testing.T) {
}
func TestGetDepositAddress(t *testing.T) {
_, err := c.GetDepositAddress(symbol.BTC, "")
_, err := c.GetDepositAddress(currency.BTC, "")
if err == nil {
t.Error("Test Failed - GetDepositAddress() error", err)
}

View File

@@ -10,7 +10,7 @@ import (
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
)
@@ -23,7 +23,7 @@ const (
// currencies
func (c *CoinbasePro) WebsocketSubscriber() error {
currencies := []string{}
for _, x := range c.EnabledPairs {
for _, x := range c.EnabledPairs.Strings() {
currency := x[0:3] + "-" + x[3:]
currencies = append(currencies, currency)
}
@@ -156,7 +156,7 @@ func (c *CoinbasePro) WsHandleData() {
c.Websocket.DataHandler <- exchange.TickerData{
Timestamp: time.Now(),
Pair: pair.NewCurrencyPairFromString(ticker.ProductID),
Pair: currency.NewPairFromString(ticker.ProductID),
AssetType: "SPOT",
Exchange: c.GetName(),
OpenPrice: ticker.Price,
@@ -230,12 +230,9 @@ func (c *CoinbasePro) ProcessSnapshot(snapshot WebsocketOrderbookSnapshot) error
orderbook.Item{Price: price, Amount: amount})
}
p := pair.NewCurrencyPairFromString(snapshot.ProductID)
pair := currency.NewPairFromString(snapshot.ProductID)
base.AssetType = "SPOT"
base.Pair = p
base.CurrencyPair = snapshot.ProductID
base.LastUpdated = time.Now()
base.Pair = pair
err := c.Websocket.Orderbook.LoadSnapshot(base, c.GetName(), false)
if err != nil {
@@ -243,7 +240,7 @@ func (c *CoinbasePro) ProcessSnapshot(snapshot WebsocketOrderbookSnapshot) error
}
c.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
Pair: p,
Pair: pair,
Asset: "SPOT",
Exchange: c.GetName(),
}
@@ -270,7 +267,7 @@ func (c *CoinbasePro) ProcessUpdate(update WebsocketL2Update) error {
return errors.New("coibasepro_websocket.go error - no data in websocket update")
}
p := pair.NewCurrencyPairFromString(update.ProductID)
p := currency.NewPairFromString(update.ProductID)
err := c.Websocket.Orderbook.Update(Bids, Asks, p, time.Now(), c.GetName(), "SPOT")
if err != nil {

View File

@@ -8,7 +8,7 @@ import (
"time"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/currency/pair"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
@@ -42,7 +42,14 @@ func (c *CoinbasePro) Run() {
currencies = append(currencies, x.ID[0:3]+x.ID[4:])
}
}
err = c.UpdateCurrencies(currencies, false, false)
var newCurrencies currency.Pairs
for _, p := range currencies {
newCurrencies = append(newCurrencies,
currency.NewPairFromString(p))
}
err = c.UpdateCurrencies(newCurrencies, false, false)
if err != nil {
log.Errorf("%s Failed to update available currencies.\n", c.GetName())
}
@@ -62,7 +69,7 @@ func (c *CoinbasePro) GetAccountInfo() (exchange.AccountInfo, error) {
var currencies []exchange.AccountCurrencyInfo
for i := 0; i < len(accountBalance); i++ {
var exchangeCurrency exchange.AccountCurrencyInfo
exchangeCurrency.CurrencyName = accountBalance[i].Currency
exchangeCurrency.CurrencyName = currency.NewCode(accountBalance[i].Currency)
exchangeCurrency.TotalValue = accountBalance[i].Available
exchangeCurrency.Hold = accountBalance[i].Hold
@@ -77,7 +84,7 @@ func (c *CoinbasePro) GetAccountInfo() (exchange.AccountInfo, error) {
}
// UpdateTicker updates and returns the ticker for a currency pair
func (c *CoinbasePro) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (c *CoinbasePro) UpdateTicker(p currency.Pair, assetType string) (ticker.Price, error) {
var tickerPrice ticker.Price
tick, err := c.GetTicker(exchange.FormatExchangeCurrency(c.Name, p).String())
if err != nil {
@@ -95,12 +102,17 @@ func (c *CoinbasePro) UpdateTicker(p pair.CurrencyPair, assetType string) (ticke
tickerPrice.Last = tick.Price
tickerPrice.High = stats.High
tickerPrice.Low = stats.Low
ticker.ProcessTicker(c.GetName(), p, tickerPrice, assetType)
err = ticker.ProcessTicker(c.GetName(), tickerPrice, assetType)
if err != nil {
return tickerPrice, err
}
return ticker.GetTicker(c.Name, p, assetType)
}
// GetTickerPrice returns the ticker for a currency pair
func (c *CoinbasePro) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
func (c *CoinbasePro) GetTickerPrice(p currency.Pair, assetType string) (ticker.Price, error) {
tickerNew, err := ticker.GetTicker(c.GetName(), p, assetType)
if err != nil {
return c.UpdateTicker(p, assetType)
@@ -109,8 +121,8 @@ func (c *CoinbasePro) GetTickerPrice(p pair.CurrencyPair, assetType string) (tic
}
// GetOrderbookEx returns orderbook base on the currency pair
func (c *CoinbasePro) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.GetOrderbook(c.GetName(), p, assetType)
func (c *CoinbasePro) GetOrderbookEx(p currency.Pair, assetType string) (orderbook.Base, error) {
ob, err := orderbook.Get(c.GetName(), p, assetType)
if err != nil {
return c.UpdateOrderbook(p, assetType)
}
@@ -118,7 +130,7 @@ func (c *CoinbasePro) GetOrderbookEx(p pair.CurrencyPair, assetType string) (ord
}
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (c *CoinbasePro) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
func (c *CoinbasePro) UpdateOrderbook(p currency.Pair, assetType string) (orderbook.Base, error) {
var orderBook orderbook.Base
orderbookNew, err := c.GetOrderbook(exchange.FormatExchangeCurrency(c.Name, p).String(), 2)
if err != nil {
@@ -135,8 +147,16 @@ func (c *CoinbasePro) UpdateOrderbook(p pair.CurrencyPair, assetType string) (or
orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: obNew.Asks[x].Amount, Price: obNew.Asks[x].Price})
}
orderbook.ProcessOrderbook(c.GetName(), p, orderBook, assetType)
return orderbook.GetOrderbook(c.Name, p, assetType)
orderBook.Pair = p
orderBook.ExchangeName = c.GetName()
orderBook.AssetType = assetType
err = orderBook.Process()
if err != nil {
return orderBook, err
}
return orderbook.Get(c.Name, p, assetType)
}
// GetFundingHistory returns funding history, deposits and
@@ -147,23 +167,36 @@ func (c *CoinbasePro) GetFundingHistory() ([]exchange.FundHistory, error) {
}
// GetExchangeHistory returns historic trade data since exchange opening.
func (c *CoinbasePro) GetExchangeHistory(p pair.CurrencyPair, assetType string) ([]exchange.TradeHistory, error) {
func (c *CoinbasePro) GetExchangeHistory(p currency.Pair, assetType string) ([]exchange.TradeHistory, error) {
var resp []exchange.TradeHistory
return resp, common.ErrNotYetImplemented
}
// SubmitOrder submits a new order
func (c *CoinbasePro) SubmitOrder(p pair.CurrencyPair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
func (c *CoinbasePro) SubmitOrder(p currency.Pair, side exchange.OrderSide, orderType exchange.OrderType, amount, price float64, _ string) (exchange.SubmitOrderResponse, error) {
var submitOrderResponse exchange.SubmitOrderResponse
var response string
var err error
switch orderType {
case exchange.MarketOrderType:
response, err = c.PlaceMarginOrder("", amount, amount, side.ToString(), p.Pair().String(), "")
response, err = c.PlaceMarginOrder("",
amount,
amount,
side.ToString(),
p.String(),
"")
case exchange.LimitOrderType:
response, err = c.PlaceLimitOrder("", price, amount, side.ToString(), "", "", p.Pair().String(), "", false)
response, err = c.PlaceLimitOrder("",
price,
amount,
side.ToString(),
"",
"",
p.String(),
"",
false)
default:
err = errors.New("order type not supported")
}
@@ -204,7 +237,7 @@ func (c *CoinbasePro) GetOrderInfo(orderID string) (exchange.OrderDetail, error)
}
// GetDepositAddress returns a deposit address for a specified currency
func (c *CoinbasePro) GetDepositAddress(cryptocurrency pair.CurrencyItem, accountID string) (string, error) {
func (c *CoinbasePro) GetDepositAddress(cryptocurrency currency.Code, accountID string) (string, error) {
return "", common.ErrFunctionNotSupported
}
@@ -262,7 +295,8 @@ func (c *CoinbasePro) GetFeeByType(feeBuilder exchange.FeeBuilder) (float64, err
func (c *CoinbasePro) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest) ([]exchange.OrderDetail, error) {
var respOrders []GeneralizedOrderResponse
for _, currency := range getOrdersRequest.Currencies {
resp, err := c.GetOrders([]string{"open", "pending", "active"}, exchange.FormatExchangeCurrency(c.Name, currency).String())
resp, err := c.GetOrders([]string{"open", "pending", "active"},
exchange.FormatExchangeCurrency(c.Name, currency).String())
if err != nil {
return nil, err
}
@@ -271,7 +305,8 @@ func (c *CoinbasePro) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest
var orders []exchange.OrderDetail
for _, order := range respOrders {
currency := pair.NewCurrencyPairDelimiter(order.ProductID, c.ConfigCurrencyPairFormat.Delimiter)
currency := currency.NewPairDelimiter(order.ProductID,
c.ConfigCurrencyPairFormat.Delimiter)
orderSide := exchange.OrderSide(strings.ToUpper(order.Side))
orderType := exchange.OrderType(strings.ToUpper(order.Type))
orderDate, err := time.Parse(time.RFC3339, order.CreatedAt)
@@ -304,7 +339,8 @@ func (c *CoinbasePro) GetActiveOrders(getOrdersRequest exchange.GetOrdersRequest
func (c *CoinbasePro) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest) ([]exchange.OrderDetail, error) {
var respOrders []GeneralizedOrderResponse
for _, currency := range getOrdersRequest.Currencies {
resp, err := c.GetOrders([]string{"done", "settled"}, exchange.FormatExchangeCurrency(c.Name, currency).String())
resp, err := c.GetOrders([]string{"done", "settled"},
exchange.FormatExchangeCurrency(c.Name, currency).String())
if err != nil {
return nil, err
}
@@ -313,7 +349,8 @@ func (c *CoinbasePro) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest
var orders []exchange.OrderDetail
for _, order := range respOrders {
currency := pair.NewCurrencyPairDelimiter(order.ProductID, c.ConfigCurrencyPairFormat.Delimiter)
currency := currency.NewPairDelimiter(order.ProductID,
c.ConfigCurrencyPairFormat.Delimiter)
orderSide := exchange.OrderSide(strings.ToUpper(order.Side))
orderType := exchange.OrderType(strings.ToUpper(order.Type))
orderDate, err := time.Parse(time.RFC3339, order.CreatedAt)
@@ -335,7 +372,8 @@ func (c *CoinbasePro) GetOrderHistory(getOrdersRequest exchange.GetOrdersRequest
}
exchange.FilterOrdersByType(&orders, getOrdersRequest.OrderType)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks, getOrdersRequest.EndTicks)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks,
getOrdersRequest.EndTicks)
exchange.FilterOrdersBySide(&orders, getOrdersRequest.OrderSide)
return orders, nil

Some files were not shown because too many files have changed in this diff Show More