rpcserver/exchanges: Add additional param checks plus other minor bugfixes/improvements (#652)

* deleting the unwanted file created during testing + adding more verbose errors for cli

* wip

* checking params throughout wip

* improving errors

* wip

* thrasher patch

* better err name

* whip

* testing and fixing errors WIP

* upgrades and better errors

* broken test

* wip

* adding some tests

* using tempDir

* mini improvement

* little changes

* better time check

* fixing error

* more glorious changes

* end of day wip

* shazzy changes

* checking error

* appveyor

* last changes:
This commit is contained in:
Adam
2021-03-30 13:40:01 +11:00
committed by GitHub
parent 2855e68bac
commit 08f1b5d5d3
13 changed files with 457 additions and 283 deletions

View File

@@ -135,5 +135,5 @@ type LiveData struct {
APISecretOverride string `json:"api-secret-override"`
APIClientIDOverride string `json:"api-client-id-override"`
API2FAOverride string `json:"api-2fa-override"`
RealOrders bool `json:"fake-orders"`
RealOrders bool `json:"real-orders"`
}

View File

@@ -44,7 +44,7 @@
"api-secret-override": "",
"api-client-id-override": "",
"api-2fa-override": "",
"fake-orders": false
"real-orders": false
}
},
"portfolio-settings": {

View File

@@ -2,6 +2,8 @@ package report
import (
"errors"
"io/ioutil"
"os"
"path/filepath"
"testing"
"time"
@@ -23,7 +25,11 @@ func TestGenerateReport(t *testing.T) {
e := testExchange
a := asset.Spot
p := currency.NewPair(currency.BTC, currency.USDT)
tempDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("Problem creating temp dir at %s: %s\n", tempDir, err)
}
defer os.RemoveAll(tempDir)
d := Data{
Config: &config.Config{},
OutputPath: filepath.Join("..", "results"),
@@ -290,7 +296,8 @@ func TestGenerateReport(t *testing.T) {
},
},
}
err := d.GenerateReport()
d.OutputPath = tempDir
err = d.GenerateReport()
if err != nil {
t.Error(err)
}

View File

@@ -159,7 +159,7 @@ func (p *PairsManager) IsAssetEnabled(a asset.Item) error {
}
if !*c.AssetEnabled {
return errors.New("asset not enabled")
return fmt.Errorf("asset %s not enabled", a)
}
return nil
}

View File

@@ -35,16 +35,25 @@ func addPassingFakeExchange(baseExchangeName string, bot *Engine) error {
if testExch == nil {
return ErrExchangeNotFound
}
base := testExch.GetBase()
bot.Config.Exchanges = append(bot.Config.Exchanges, config.ExchangeConfig{
Name: fakePassExchange,
Enabled: true,
Verbose: false,
})
b := true
var pairStoreData = currency.PairStore{
AssetEnabled: &b,
}
var currencyMap = make(map[asset.Item]*currency.PairStore)
currencyMap[asset.Spot] = &pairStoreData
bot.exchangeManager.add(&FakePassingExchange{
Base: exchange.Base{
Name: fakePassExchange,
Name: fakePassExchange,
CurrencyPairs: currency.PairsManager{
Pairs: currencyMap},
Enabled: true,
LoadedByConfig: true,
SkipAuthCheck: true,
@@ -221,7 +230,6 @@ func (h *FakePassingExchange) GetSubscriptions() ([]stream.ChannelSubscription,
return nil, nil
}
func (h *FakePassingExchange) GetDefaultConfig() (*config.ExchangeConfig, error) { return nil, nil }
func (h *FakePassingExchange) GetBase() *exchange.Base { return nil }
func (h *FakePassingExchange) SupportsAsset(_ asset.Item) bool { return true }
func (h *FakePassingExchange) GetHistoricCandles(_ currency.Pair, _ asset.Item, _, _ time.Time, _ kline.Interval) (kline.Item, error) {
return kline.Item{}, nil

View File

@@ -37,13 +37,13 @@ func CreateTestBot(t *testing.T) *Engine {
}
if bot.GetExchangeByName(testExchange) == nil {
err := bot.LoadExchange(testExchange, false, nil)
err = bot.LoadExchange(testExchange, false, nil)
if err != nil {
t.Fatalf("SetupTest: Failed to load exchange: %s", err)
}
}
if bot.GetExchangeByName(fakePassExchange) == nil {
err := addPassingFakeExchange(testExchange, bot)
err = addPassingFakeExchange(testExchange, bot)
if err != nil {
t.Fatalf("SetupTest: Failed to load exchange: %s", err)
}

View File

@@ -294,7 +294,7 @@ func (o *orderManager) Cancel(cancel *order.Cancel) error {
// and stores the result in the order manager
func (o *orderManager) GetOrderInfo(exchangeName, orderID string, cp currency.Pair, a asset.Item) (order.Detail, error) {
if orderID == "" {
return order.Detail{}, errOrderCannotBeEmpty
return order.Detail{}, errOrderIDCannotBeEmpty
}
exch := o.orderStore.bot.GetExchangeByName(exchangeName)

View File

@@ -9,7 +9,7 @@ import (
)
var (
errOrderCannotBeEmpty = errors.New("order cannot be empty")
errOrderIDCannotBeEmpty = errors.New("orderID cannot be empty")
)
type orderManagerConfig struct {

View File

@@ -29,6 +29,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/database/models/sqlite3"
"github.com/thrasher-corp/gocryptotrader/database/repository/audit"
exchangeDB "github.com/thrasher-corp/gocryptotrader/database/repository/exchange"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
@@ -55,10 +56,12 @@ var (
errInvalidArguments = errors.New("invalid arguments received")
errExchangeNameUnset = errors.New("exchange name unset")
errCurrencyPairUnset = errors.New("currency pair unset")
errStartEndTimesUnset = errors.New("invalid start and end times")
errInvalidTimes = errors.New("invalid start and end times")
errAssetTypeDisabled = errors.New("asset type is disabled")
errAssetTypeUnset = errors.New("asset type unset")
errDispatchSystem = errors.New("dispatch system offline")
errCurrencyNotEnabled = errors.New("currency not enabled")
errCurrencyPairInvalid = errors.New("currency provided is not found in the available pairs list")
)
// RPCServer struct
@@ -335,6 +338,16 @@ func (s *RPCServer) GetTicker(_ context.Context, r *gctrpc.GetTickerRequest) (*g
return nil, err
}
e := s.GetExchangeByName(r.Exchange)
err = checkParams(r.Exchange, e, a, currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
})
if err != nil {
return nil, err
}
t, err := s.GetSpecificTicker(currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
@@ -494,12 +507,14 @@ func (s *RPCServer) GetOrderbooks(_ context.Context, r *gctrpc.GetOrderbooksRequ
// GetAccountInfo returns an account balance for a specific exchange
func (s *RPCServer) GetAccountInfo(_ context.Context, r *gctrpc.GetAccountInfoRequest) (*gctrpc.GetAccountInfoResponse, error) {
exch := s.GetExchangeByName(r.Exchange)
if exch == nil {
return nil, errExchangeNotLoaded
assetType, err := asset.New(r.AssetType)
if err != nil {
return nil, err
}
assetType, err := asset.New(r.AssetType)
exch := s.GetExchangeByName(r.Exchange)
err = checkParams(r.Exchange, exch, assetType, currency.Pair{})
if err != nil {
return nil, err
}
@@ -514,12 +529,13 @@ func (s *RPCServer) GetAccountInfo(_ context.Context, r *gctrpc.GetAccountInfoRe
// UpdateAccountInfo forces an update of the account info
func (s *RPCServer) UpdateAccountInfo(ctx context.Context, r *gctrpc.GetAccountInfoRequest) (*gctrpc.GetAccountInfoResponse, error) {
exch := s.GetExchangeByName(r.Exchange)
if exch == nil {
return nil, errExchangeNotLoaded
assetType, err := asset.New(r.AssetType)
if err != nil {
return nil, err
}
assetType, err := asset.New(r.AssetType)
exch := s.GetExchangeByName(r.Exchange)
err = checkParams(r.Exchange, exch, assetType, currency.Pair{})
if err != nil {
return nil, err
}
@@ -552,16 +568,13 @@ func createAccountInfoRequest(h account.Holdings) (*gctrpc.GetAccountInfoRespons
// GetAccountInfoStream streams an account balance for a specific exchange
func (s *RPCServer) GetAccountInfoStream(r *gctrpc.GetAccountInfoRequest, stream gctrpc.GoCryptoTrader_GetAccountInfoStreamServer) error {
if r.Exchange == "" {
return errExchangeNameUnset
assetType, err := asset.New(r.AssetType)
if err != nil {
return err
}
exch := s.GetExchangeByName(r.Exchange)
if exch == nil {
return errExchangeNotLoaded
}
assetType, err := asset.New(r.AssetType)
err = checkParams(r.Exchange, exch, assetType, currency.Pair{})
if err != nil {
return err
}
@@ -803,17 +816,25 @@ func (s *RPCServer) GetOrders(_ context.Context, r *gctrpc.GetOrdersRequest) (*g
if r == nil {
return nil, errInvalidArguments
}
exch := s.GetExchangeByName(r.Exchange)
if exch == nil {
return nil, errExchangeNotLoaded
}
if r.Pair == nil {
return nil, errCurrencyPairUnset
}
a, err := asset.New(r.AssetType)
if err != nil {
return nil, err
}
if r.Pair == nil {
return nil, errCurrencyPairUnset
}
cp := currency.NewPairWithDelimiter(
r.Pair.Base,
r.Pair.Quote,
r.Pair.Delimiter)
exch := s.GetExchangeByName(r.Exchange)
err = checkParams(r.Exchange, exch, a, cp)
if err != nil {
return nil, err
}
var start, end time.Time
if r.StartDate != "" {
start, err = time.Parse(common.SimpleTimeFormat, r.StartDate)
@@ -828,23 +849,7 @@ func (s *RPCServer) GetOrders(_ context.Context, r *gctrpc.GetOrdersRequest) (*g
}
}
if !start.IsZero() && !end.IsZero() && start.After(end) {
return nil, errStartEndTimesUnset
}
cp := currency.NewPairWithDelimiter(
r.Pair.Base,
r.Pair.Quote,
r.Pair.Delimiter)
var pairs currency.Pairs
pairs, err = exch.GetEnabledPairs(a)
if err != nil {
return nil, err
}
if !pairs.Contains(cp, false) {
return nil, fmt.Errorf("%s %w %v, please check your config",
exch.GetName(),
errCurrencyNotEnabled,
cp.String())
return nil, errInvalidTimes
}
request := &order.GetOrdersRequest{
@@ -917,10 +922,7 @@ func (s *RPCServer) GetOrder(_ context.Context, r *gctrpc.GetOrderRequest) (*gct
if r == nil {
return nil, errInvalidArguments
}
exch := s.GetExchangeByName(r.Exchange)
if exch == nil {
return nil, errExchangeNotLoaded
}
if r.Pair == nil {
return nil, errCurrencyPairUnset
}
@@ -936,6 +938,12 @@ func (s *RPCServer) GetOrder(_ context.Context, r *gctrpc.GetOrderRequest) (*gct
return nil, err
}
exch := s.GetExchangeByName(r.Exchange)
err = checkParams(r.Exchange, exch, a, pair)
if err != nil {
return nil, err
}
result, err := s.OrderManager.GetOrderInfo(r.Exchange, r.OrderId, pair, a)
if err != nil {
return nil, fmt.Errorf("error whilst trying to retrieve info for order %s: %w", r.OrderId, err)
@@ -986,12 +994,23 @@ func (s *RPCServer) GetOrder(_ context.Context, r *gctrpc.GetOrderRequest) (*gct
// SubmitOrder submits an order specified by exchange, currency pair and asset
// type
func (s *RPCServer) SubmitOrder(_ context.Context, r *gctrpc.SubmitOrderRequest) (*gctrpc.SubmitOrderResponse, error) {
p, err := currency.NewPairFromStrings(r.Pair.Base, r.Pair.Quote)
a, err := asset.New(r.AssetType)
if err != nil {
return nil, err
}
a, err := asset.New(r.AssetType)
if r.Pair == nil {
return nil, errCurrencyPairUnset
}
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
exch := s.GetExchangeByName(r.Exchange)
err = checkParams(r.Exchange, exch, a, p)
if err != nil {
return nil, err
}
@@ -1032,12 +1051,18 @@ func (s *RPCServer) SubmitOrder(_ context.Context, r *gctrpc.SubmitOrderRequest)
// SimulateOrder simulates an order specified by exchange, currency pair and asset
// type
func (s *RPCServer) SimulateOrder(_ context.Context, r *gctrpc.SimulateOrderRequest) (*gctrpc.SimulateOrderResponse, error) {
exch := s.GetExchangeByName(r.Exchange)
if exch == nil {
return nil, errExchangeNotLoaded
if r.Pair == nil {
return nil, errCurrencyPairUnset
}
p, err := currency.NewPairFromStrings(r.Pair.Base, r.Pair.Quote)
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
exch := s.GetExchangeByName(r.Exchange)
err := checkParams(r.Exchange, exch, asset.Spot, p)
if err != nil {
return nil, err
}
@@ -1073,12 +1098,18 @@ func (s *RPCServer) SimulateOrder(_ context.Context, r *gctrpc.SimulateOrderRequ
// WhaleBomb finds the amount required to reach a specific price target for a given exchange, pair
// and asset type
func (s *RPCServer) WhaleBomb(_ context.Context, r *gctrpc.WhaleBombRequest) (*gctrpc.SimulateOrderResponse, error) {
exch := s.GetExchangeByName(r.Exchange)
if exch == nil {
return nil, errExchangeNotLoaded
if r.Pair == nil {
return nil, errCurrencyPairUnset
}
p, err := currency.NewPairFromStrings(r.Pair.Base, r.Pair.Quote)
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
exch := s.GetExchangeByName(r.Exchange)
err := checkParams(r.Exchange, exch, asset.Item(""), p)
if err != nil {
return nil, err
}
@@ -1114,17 +1145,23 @@ func (s *RPCServer) WhaleBomb(_ context.Context, r *gctrpc.WhaleBombRequest) (*g
// CancelOrder cancels an order specified by exchange, currency pair and asset
// type
func (s *RPCServer) CancelOrder(_ context.Context, r *gctrpc.CancelOrderRequest) (*gctrpc.GenericResponse, error) {
exch := s.GetExchangeByName(r.Exchange)
if exch == nil {
return nil, errExchangeNotLoaded
if r.Pair == nil {
return nil, errCurrencyPairUnset
}
p, err := currency.NewPairFromStrings(r.Pair.Base, r.Pair.Quote)
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
a, err := asset.New(r.AssetType)
if err != nil {
return nil, err
}
a, err := asset.New(r.AssetType)
exch := s.GetExchangeByName(r.Exchange)
err = checkParams(r.Exchange, exch, a, p)
if err != nil {
return nil, err
}
@@ -1146,17 +1183,19 @@ func (s *RPCServer) CancelOrder(_ context.Context, r *gctrpc.CancelOrderRequest)
// CancelBatchOrders cancels an orders specified by exchange, currency pair and asset type
func (s *RPCServer) CancelBatchOrders(_ context.Context, r *gctrpc.CancelBatchOrdersRequest) (*gctrpc.CancelBatchOrdersResponse, error) {
exch := s.GetExchangeByName(r.Exchange)
if exch == nil {
return nil, errExchangeNotLoaded
pair := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
pair, err := currency.NewPairFromStrings(r.Pair.Base, r.Pair.Quote)
assetType, err := asset.New(r.AssetType)
if err != nil {
return nil, err
}
assetType, err := asset.New(r.AssetType)
exch := s.GetExchangeByName(r.Exchange)
err = checkParams(r.Exchange, exch, assetType, pair)
if err != nil {
return nil, err
}
@@ -1228,6 +1267,12 @@ func (s *RPCServer) AddEvent(_ context.Context, r *gctrpc.AddEventRequest) (*gct
return nil, err
}
exch := s.GetExchangeByName(r.Exchange)
err = checkParams(r.Exchange, exch, a, p)
if err != nil {
return nil, err
}
id, err := Add(r.Exchange, r.Item, evtCondition, p, a, r.Action)
if err != nil {
return nil, err
@@ -1535,22 +1580,15 @@ func (s *RPCServer) SetExchangePair(_ context.Context, r *gctrpc.SetExchangePair
return nil, err
}
if r.AssetType == "" {
return nil, errors.New("asset type must be specified")
}
a, err := asset.New(r.AssetType)
if err != nil {
return nil, err
}
if !exchCfg.CurrencyPairs.GetAssetTypes().Contains(a) {
return nil, fmt.Errorf("specified asset %s is not supported by exchange", a)
}
exch := s.GetExchangeByName(r.Exchange)
if exch == nil {
return nil, errExchangeNotLoaded
err = checkParams(r.Exchange, exch, a, currency.Pair{})
if err != nil {
return nil, err
}
base := exch.GetBase()
@@ -1617,24 +1655,19 @@ func (s *RPCServer) SetExchangePair(_ context.Context, r *gctrpc.SetExchangePair
// GetOrderbookStream streams the requested updated orderbook
func (s *RPCServer) GetOrderbookStream(r *gctrpc.GetOrderbookStreamRequest, stream gctrpc.GoCryptoTrader_GetOrderbookStreamServer) error {
if r.Exchange == "" {
return errExchangeNameUnset
}
if r.Pair.String() == "" {
return errCurrencyPairUnset
}
if r.AssetType == "" {
return errAssetTypeUnset
}
p, err := currency.NewPairFromStrings(r.Pair.Base, r.Pair.Quote)
a, err := asset.New(r.AssetType)
if err != nil {
return err
}
a, err := asset.New(r.AssetType)
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
exch := s.GetExchangeByName(r.Exchange)
err = checkParams(r.Exchange, exch, a, p)
if err != nil {
return err
}
@@ -1735,6 +1768,11 @@ func (s *RPCServer) GetTickerStream(r *gctrpc.GetTickerStreamRequest, stream gct
return errExchangeNameUnset
}
a, err := asset.New(r.AssetType)
if err != nil {
return err
}
if r.Pair.String() == "" {
return errCurrencyPairUnset
}
@@ -1748,11 +1786,6 @@ func (s *RPCServer) GetTickerStream(r *gctrpc.GetTickerStreamRequest, stream gct
return err
}
a, err := asset.New(r.AssetType)
if err != nil {
return err
}
pipe, err := ticker.SubscribeTicker(r.Exchange, p, a)
if err != nil {
return err
@@ -1874,17 +1907,6 @@ func (s *RPCServer) GetAuditEvent(_ context.Context, r *gctrpc.GetAuditEventRequ
// GetHistoricCandles returns historical candles for a given exchange
func (s *RPCServer) GetHistoricCandles(_ context.Context, r *gctrpc.GetHistoricCandlesRequest) (*gctrpc.GetHistoricCandlesResponse, error) {
if r.Exchange == "" {
return nil, errExchangeNameUnset
}
if r.Pair.String() == "" {
return nil, errCurrencyPairUnset
}
if r.Start == r.End {
return nil, errStartEndTimesUnset
}
var klineItem kline.Item
UTCStartTime, err := time.Parse(common.SimpleTimeFormat, r.Start)
if err != nil {
return nil, err
@@ -1894,6 +1916,31 @@ func (s *RPCServer) GetHistoricCandles(_ context.Context, r *gctrpc.GetHistoricC
if err != nil {
return nil, err
}
if UTCStartTime.After(UTCEndTime) || UTCStartTime.Equal(UTCEndTime) {
return nil, errInvalidTimes
}
if r.Pair == nil {
return nil, errCurrencyPairUnset
}
pair := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
a, err := asset.New(r.AssetType)
if err != nil {
return nil, err
}
exch := s.GetExchangeByName(r.Exchange)
err = checkParams(r.Exchange, exch, a, pair)
if err != nil {
return nil, err
}
interval := kline.Interval(r.TimeInterval)
resp := gctrpc.GetHistoricCandlesResponse{
@@ -1903,16 +1950,7 @@ func (s *RPCServer) GetHistoricCandles(_ context.Context, r *gctrpc.GetHistoricC
End: r.End,
}
a, err := asset.New(r.AssetType)
if err != nil {
return nil, err
}
pair := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
var klineItem kline.Item
if r.UseDb {
klineItem, err = kline.LoadFromDatabase(r.Exchange,
pair,
@@ -1924,18 +1962,14 @@ func (s *RPCServer) GetHistoricCandles(_ context.Context, r *gctrpc.GetHistoricC
return nil, err
}
} else {
exchangeEngine := s.GetExchangeByName(r.Exchange)
if exchangeEngine == nil {
return nil, errors.New("Exchange " + r.Exchange + " not found")
}
if r.ExRequest {
klineItem, err = exchangeEngine.GetHistoricCandlesExtended(pair,
klineItem, err = exch.GetHistoricCandlesExtended(pair,
a,
UTCStartTime,
UTCEndTime,
interval)
} else {
klineItem, err = exchangeEngine.GetHistoricCandles(pair,
klineItem, err = exch.GetHistoricCandles(pair,
a,
UTCStartTime,
UTCEndTime,
@@ -2596,27 +2630,23 @@ func (s *RPCServer) GetSavedTrades(_ context.Context, r *gctrpc.GetSavedTradesRe
if r.End == "" || r.Start == "" || r.Exchange == "" || r.Pair == nil || r.AssetType == "" || r.Pair.String() == "" {
return nil, errInvalidArguments
}
exch := s.GetExchangeByName(r.Exchange)
if exch == nil {
return nil, errExchangeNotLoaded
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
cp, err := currency.NewPairFromStrings(r.Pair.Base, r.Pair.Quote)
a, err := asset.New(r.AssetType)
if err != nil {
return nil, err
}
a := asset.Item(r.AssetType)
if !a.IsValid() {
return nil, errors.New("invalid asset")
}
var pairs currency.Pairs
pairs, err = exch.GetEnabledPairs(a)
exch := s.GetExchangeByName(r.Exchange)
err = checkParams(r.Exchange, exch, a, p)
if err != nil {
return nil, err
}
if !pairs.Contains(cp, false) {
return nil, errors.New("currency not enabled")
}
var UTCStartTime, UTCEndTime time.Time
UTCStartTime, err = time.Parse(common.SimpleTimeFormat, r.Start)
@@ -2658,7 +2688,6 @@ func (s *RPCServer) ConvertTradesToCandles(_ context.Context, r *gctrpc.ConvertT
if r.End == "" || r.Start == "" || r.Exchange == "" || r.Pair == nil || r.AssetType == "" || r.Pair.String() == "" || r.TimeInterval == 0 {
return nil, errInvalidArguments
}
exch := s.GetExchangeByName(r.Exchange)
UTCStartTime, err := time.Parse(common.SimpleTimeFormat, r.Start)
if err != nil {
return nil, err
@@ -2668,26 +2697,22 @@ func (s *RPCServer) ConvertTradesToCandles(_ context.Context, r *gctrpc.ConvertT
if err != nil {
return nil, err
}
if exch == nil {
return nil, errExchangeNotLoaded
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
var cp currency.Pair
cp, err = currency.NewPairFromStrings(r.Pair.Base, r.Pair.Quote)
a, err := asset.New(r.AssetType)
if err != nil {
return nil, err
}
a := asset.Item(r.AssetType)
if !a.IsValid() {
return nil, errors.New("invalid asset")
}
var pairs currency.Pairs
pairs, err = exch.GetEnabledPairs(a)
exch := s.GetExchangeByName(r.Exchange)
err = checkParams(r.Exchange, exch, a, p)
if err != nil {
return nil, err
}
if !pairs.Contains(cp, false) {
return nil, errors.New("currency not enabled")
}
var trades []trade.Data
trades, err = trade.GetTradesInRange(r.Exchange, r.AssetType, r.Pair.Base, r.Pair.Quote, UTCStartTime, UTCEndTime)
@@ -2740,27 +2765,22 @@ func (s *RPCServer) FindMissingSavedCandleIntervals(_ context.Context, r *gctrpc
if r.End == "" || r.Start == "" || r.ExchangeName == "" || r.Pair == nil || r.AssetType == "" || r.Pair.String() == "" || r.Interval <= 0 {
return nil, errInvalidArguments
}
exch := s.GetExchangeByName(r.ExchangeName)
if exch == nil {
return nil, errExchangeNotLoaded
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
cp, err := currency.NewPairFromStrings(r.Pair.Base, r.Pair.Quote)
a, err := asset.New(r.AssetType)
if err != nil {
return nil, err
}
a := asset.Item(r.AssetType)
if !a.IsValid() {
return nil, errors.New("invalid asset")
}
var pairs currency.Pairs
pairs, err = exch.GetEnabledPairs(a)
exch := s.GetExchangeByName(r.ExchangeName)
err = checkParams(r.ExchangeName, exch, a, p)
if err != nil {
return nil, err
}
if !pairs.Contains(cp, false) {
return nil, errors.New("currency not enabled")
}
var UTCStartTime, UTCEndTime time.Time
UTCStartTime, err = time.Parse(common.SimpleTimeFormat, r.Start)
@@ -2773,12 +2793,8 @@ func (s *RPCServer) FindMissingSavedCandleIntervals(_ context.Context, r *gctrpc
}
klineItem, err := kline.LoadFromDatabase(
r.ExchangeName,
currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
},
asset.Item(strings.ToLower(r.AssetType)),
p,
a,
kline.Interval(r.Interval),
UTCStartTime,
UTCEndTime,
@@ -2834,11 +2850,22 @@ func (s *RPCServer) FindMissingSavedTradeIntervals(_ context.Context, r *gctrpc.
if r.End == "" || r.Start == "" || r.ExchangeName == "" || r.Pair == nil || r.AssetType == "" || r.Pair.String() == "" {
return nil, errInvalidArguments
}
exch := s.GetExchangeByName(r.ExchangeName)
if exch == nil {
return nil, errExchangeNotLoaded
p := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
a, err := asset.New(r.AssetType)
if err != nil {
return nil, err
}
exch := s.GetExchangeByName(r.ExchangeName)
err = checkParams(r.ExchangeName, exch, a, p)
if err != nil {
return nil, err
}
var err error
var UTCStartTime, UTCEndTime time.Time
UTCStartTime, err = time.Parse(common.SimpleTimeFormat, r.Start)
if err != nil {
@@ -2858,23 +2885,6 @@ func (s *RPCServer) FindMissingSavedTradeIntervals(_ context.Context, r *gctrpc.
intervalMap[iterationTime] = false
iterationTime = iterationTime.Add(time.Hour)
}
var cp currency.Pair
cp, err = currency.NewPairFromStrings(r.Pair.Base, r.Pair.Quote)
if err != nil {
return nil, err
}
a := asset.Item(r.AssetType)
if !a.IsValid() {
return nil, errors.New("invalid asset")
}
var pairs currency.Pairs
pairs, err = exch.GetEnabledPairs(a)
if err != nil {
return nil, err
}
if !pairs.Contains(cp, false) {
return nil, errors.New("currency not enabled")
}
var trades []trade.Data
trades, err = trade.GetTradesInRange(
@@ -2950,26 +2960,22 @@ func (s *RPCServer) GetHistoricTrades(r *gctrpc.GetSavedTradesRequest, stream gc
if r.Exchange == "" || r.Pair == nil || r.AssetType == "" || r.Pair.String() == "" {
return errInvalidArguments
}
cp := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
a, err := asset.New(r.AssetType)
if err != nil {
return err
}
exch := s.GetExchangeByName(r.Exchange)
if exch == nil {
return errExchangeNotLoaded
}
cp, err := currency.NewPairFromStrings(r.Pair.Base, r.Pair.Quote)
err = checkParams(r.Exchange, exch, a, cp)
if err != nil {
return err
}
a := asset.Item(r.AssetType)
if !a.IsValid() {
return errors.New("invalid asset")
}
var pairs currency.Pairs
pairs, err = exch.GetEnabledPairs(a)
if err != nil {
return err
}
if !pairs.Contains(cp, false) {
return errors.New("currency not enabled")
}
var trades []trade.Data
var UTCStartTime, UTCEndTime time.Time
UTCStartTime, err = time.Parse(common.SimpleTimeFormat, r.Start)
@@ -2989,7 +2995,7 @@ func (s *RPCServer) GetHistoricTrades(r *gctrpc.GetSavedTradesRequest, stream gc
for iterateStartTime := UTCStartTime; iterateStartTime.Before(UTCEndTime); iterateStartTime = iterateStartTime.Add(time.Hour) {
iterateEndTime := iterateStartTime.Add(time.Hour)
trades, err = exch.GetHistoricTrades(cp, asset.Item(r.AssetType), iterateStartTime, iterateEndTime)
trades, err = exch.GetHistoricTrades(cp, a, iterateStartTime, iterateEndTime)
if err != nil {
return err
}
@@ -3027,26 +3033,22 @@ func (s *RPCServer) GetRecentTrades(_ context.Context, r *gctrpc.GetSavedTradesR
if r.Exchange == "" || r.Pair == nil || r.AssetType == "" || r.Pair.String() == "" {
return nil, errInvalidArguments
}
cp := currency.Pair{
Delimiter: r.Pair.Delimiter,
Base: currency.NewCode(r.Pair.Base),
Quote: currency.NewCode(r.Pair.Quote),
}
a, err := asset.New(r.AssetType)
if err != nil {
return nil, err
}
exch := s.GetExchangeByName(r.Exchange)
if exch == nil {
return nil, errExchangeNotLoaded
}
cp, err := currency.NewPairFromStrings(r.Pair.Base, r.Pair.Quote)
err = checkParams(r.Exchange, exch, a, cp)
if err != nil {
return nil, err
}
a := asset.Item(r.AssetType)
if !a.IsValid() {
return nil, errors.New("invalid asset")
}
var pairs currency.Pairs
pairs, err = exch.GetEnabledPairs(a)
if err != nil {
return nil, err
}
if !pairs.Contains(cp, false) {
return nil, errors.New("currency not enabled")
}
var trades []trade.Data
trades, err = exch.GetRecentTrades(cp, asset.Item(r.AssetType))
if err != nil {
@@ -3072,3 +3074,40 @@ func (s *RPCServer) GetRecentTrades(_ context.Context, r *gctrpc.GetSavedTradesR
return resp, nil
}
func checkParams(exchName string, e exchange.IBotExchange, a asset.Item, p currency.Pair) error {
if e == nil {
return fmt.Errorf("%s %w", exchName, errExchangeNotLoaded)
}
if !e.IsEnabled() {
return fmt.Errorf("%s %w", exchName, errExchangeDisabled)
}
if a.IsValid() {
b := e.GetBase()
if b == nil {
return fmt.Errorf("%s %w", exchName, errExchangeBaseNotFound)
}
err := b.CurrencyPairs.IsAssetEnabled(a)
if err != nil {
return fmt.Errorf("%v %w", a, errAssetTypeDisabled)
}
}
if p.IsEmpty() {
return nil
}
enabledPairs, err := e.GetEnabledPairs(a)
if err != nil {
return err
}
if enabledPairs.Contains(p, true) {
return nil
}
availablePairs, err := e.GetAvailablePairs(a)
if err != nil {
return err
}
if availablePairs.Contains(p, true) {
return fmt.Errorf("%v %w", p, errCurrencyNotEnabled)
}
return fmt.Errorf("%v %w", p, errCurrencyPairInvalid)
}

View File

@@ -20,7 +20,9 @@ import (
"github.com/thrasher-corp/gocryptotrader/database/repository"
dbexchange "github.com/thrasher-corp/gocryptotrader/database/repository/exchange"
sqltrade "github.com/thrasher-corp/gocryptotrader/database/repository/trade"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/binance"
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/exchanges/trade"
@@ -119,7 +121,7 @@ func TestGetSavedTrades(t *testing.T) {
t.Error(unexpectedLackOfError)
return
}
if err != errExchangeNotLoaded {
if !errors.Is(err, errExchangeNotLoaded) {
t.Error(err)
}
_, err = s.GetSavedTrades(context.Background(), &gctrpc.GetSavedTradesRequest{
@@ -201,7 +203,7 @@ func TestConvertTradesToCandles(t *testing.T) {
t.Error(unexpectedLackOfError)
return
}
if err != errExchangeNotLoaded {
if !errors.Is(err, errExchangeNotLoaded) {
t.Error(err)
}
@@ -328,16 +330,29 @@ func TestGetHistoricCandles(t *testing.T) {
defer CleanRPCTest(t, engerino)
s := RPCServer{Engine: engerino}
// error checks
defaultStart := time.Date(2020, 1, 1, 1, 1, 1, 1, time.UTC)
defaultEnd := time.Date(2020, 1, 2, 2, 2, 2, 2, time.UTC)
cp := currency.NewPair(currency.BTC, currency.USD)
_, err := s.GetHistoricCandles(context.Background(), &gctrpc.GetHistoricCandlesRequest{
Exchange: "",
Pair: &gctrpc.CurrencyPair{
Base: cp.Base.String(),
Quote: cp.Quote.String(),
},
Start: defaultStart.Format(common.SimpleTimeFormat),
End: defaultEnd.Format(common.SimpleTimeFormat),
AssetType: asset.Spot.String(),
})
if !errors.Is(err, errExchangeNameUnset) {
t.Errorf("expected %v, received %v", errExchangeNameUnset, err)
if !errors.Is(err, errExchangeNotLoaded) {
t.Errorf("expected %v, received %v", errExchangeNotLoaded, err)
}
_, err = s.GetHistoricCandles(context.Background(), &gctrpc.GetHistoricCandlesRequest{
Exchange: testExchange,
Pair: &gctrpc.CurrencyPair{},
Exchange: testExchange,
Start: defaultStart.Format(common.SimpleTimeFormat),
End: defaultEnd.Format(common.SimpleTimeFormat),
Pair: nil,
AssetType: asset.Spot.String(),
})
if !errors.Is(err, errCurrencyPairUnset) {
t.Errorf("expected %v, received %v", errCurrencyPairUnset, err)
@@ -348,14 +363,13 @@ func TestGetHistoricCandles(t *testing.T) {
Base: currency.BTC.String(),
Quote: currency.USD.String(),
},
Start: "2020-01-02 15:04:05",
End: "2020-01-02 15:04:05",
})
if !errors.Is(err, errStartEndTimesUnset) {
t.Errorf("expected %v, received %v", errStartEndTimesUnset, err)
if !errors.Is(err, errInvalidTimes) {
t.Errorf("expected %v, received %v", errInvalidTimes, err)
}
var results *gctrpc.GetHistoricCandlesResponse
defaultStart := time.Date(2020, 1, 1, 1, 1, 1, 1, time.UTC)
defaultEnd := time.Date(2020, 1, 2, 2, 2, 2, 2, time.UTC)
cp := currency.NewPair(currency.BTC, currency.USD)
// default run
results, err = s.GetHistoricCandles(context.Background(), &gctrpc.GetHistoricCandlesRequest{
Exchange: testExchange,
@@ -720,7 +734,7 @@ func TestGetRecentTrades(t *testing.T) {
t.Error(unexpectedLackOfError)
return
}
if err != errExchangeNotLoaded {
if !errors.Is(err, errExchangeNotLoaded) {
t.Error(err)
}
_, err = s.GetRecentTrades(context.Background(), &gctrpc.GetSavedTradesRequest{
@@ -764,7 +778,7 @@ func TestGetHistoricTrades(t *testing.T) {
t.Error(unexpectedLackOfError)
return
}
if err != errExchangeNotLoaded {
if !errors.Is(err, errExchangeNotLoaded) {
t.Error(err)
}
err = s.GetHistoricTrades(&gctrpc.GetSavedTradesRequest{
@@ -795,7 +809,6 @@ func TestGetAccountInfo(t *testing.T) {
if err != nil {
t.Fatalf("TestGetAccountInfo: Failed to get account info: %s", err)
}
if r.Accounts[0].Currencies[0].TotalValue != 10 {
t.Fatal("TestGetAccountInfo: Unexpected value of the 'TotalValue'")
}
@@ -810,12 +823,18 @@ func TestUpdateAccountInfo(t *testing.T) {
t.Fatalf("TestGetAccountInfo: Failed to get account info: %s", err)
}
updateResponse, err := s.UpdateAccountInfo(context.Background(), &gctrpc.GetAccountInfoRequest{Exchange: fakePassExchange, AssetType: asset.Futures.String()})
if err != nil {
t.Fatalf("TestGetAccountInfo: Failed to update account info: %s", err)
_, err = s.UpdateAccountInfo(context.Background(), &gctrpc.GetAccountInfoRequest{Exchange: fakePassExchange, AssetType: asset.Futures.String()})
if !errors.Is(err, errAssetTypeDisabled) {
t.Errorf("expected %v, received %v", errAssetTypeDisabled, err)
}
if getResponse.Accounts[0].Currencies[0].TotalValue == updateResponse.Accounts[0].Currencies[0].TotalValue {
updateResp, err := s.UpdateAccountInfo(context.Background(), &gctrpc.GetAccountInfoRequest{
Exchange: fakePassExchange,
AssetType: asset.Spot.String(),
})
if !errors.Is(err, nil) {
t.Error(err)
} else if getResponse.Accounts[0].Currencies[0].TotalValue == updateResp.Accounts[0].Currencies[0].TotalValue {
t.Fatalf("TestGetAccountInfo: Unexpected value of the 'TotalValue'")
}
}
@@ -826,12 +845,21 @@ func TestGetOrders(t *testing.T) {
defer CleanRPCTest(t, engerino)
s := RPCServer{Engine: engerino}
p := &gctrpc.CurrencyPair{
Delimiter: "-",
Base: currency.BTC.String(),
Quote: currency.USDT.String(),
}
_, err := s.GetOrders(context.Background(), nil)
if !errors.Is(err, errInvalidArguments) {
t.Errorf("expected %v, received %v", errInvalidArguments, err)
}
_, err = s.GetOrders(context.Background(), &gctrpc.GetOrdersRequest{})
_, err = s.GetOrders(context.Background(), &gctrpc.GetOrdersRequest{
AssetType: asset.Spot.String(),
Pair: p,
})
if !errors.Is(err, errExchangeNotLoaded) {
t.Errorf("expected %v, received %v", errExchangeNotLoaded, err)
}
@@ -842,17 +870,13 @@ func TestGetOrders(t *testing.T) {
}
_, err = s.GetOrders(context.Background(), &gctrpc.GetOrdersRequest{
Exchange: exchName,
Exchange: exchName,
AssetType: asset.Spot.String(),
})
if !errors.Is(err, errCurrencyPairUnset) {
t.Errorf("expected %v, received %v", errCurrencyPairUnset, err)
}
p := &gctrpc.CurrencyPair{
Delimiter: "-",
Base: currency.BTC.String(),
Quote: currency.USDT.String(),
}
_, err = s.GetOrders(context.Background(), &gctrpc.GetOrdersRequest{
Exchange: exchName,
Pair: p,
@@ -868,8 +892,8 @@ func TestGetOrders(t *testing.T) {
StartDate: time.Now().Format(common.SimpleTimeFormat),
EndDate: time.Now().Add(-time.Hour).Format(common.SimpleTimeFormat),
})
if !errors.Is(err, errStartEndTimesUnset) {
t.Errorf("expected %v, received %v", errStartEndTimesUnset, err)
if !errors.Is(err, errInvalidTimes) {
t.Errorf("expected %v, received %v", errInvalidTimes, err)
}
_, err = s.GetOrders(context.Background(), &gctrpc.GetOrdersRequest{
@@ -911,6 +935,12 @@ func TestGetOrder(t *testing.T) {
defer CleanRPCTest(t, engerino)
s := RPCServer{Engine: engerino}
p := &gctrpc.CurrencyPair{
Delimiter: "-",
Base: "BTC",
Quote: "USDT",
}
_, err := s.GetOrder(context.Background(), nil)
if !errors.Is(err, errInvalidArguments) {
t.Errorf("expected %v, received %v", errInvalidArguments, err)
@@ -919,9 +949,10 @@ func TestGetOrder(t *testing.T) {
_, err = s.GetOrder(context.Background(), &gctrpc.GetOrderRequest{
Exchange: exchName,
OrderId: "",
Pair: nil,
Asset: "",
Pair: p,
Asset: "spot",
})
if !errors.Is(err, errExchangeNotLoaded) {
t.Errorf("expected %v, received %v", errExchangeNotLoaded, err)
}
@@ -941,12 +972,6 @@ func TestGetOrder(t *testing.T) {
t.Errorf("expected %v, received %v", errCurrencyPairUnset, err)
}
p := &gctrpc.CurrencyPair{
Delimiter: "-",
Base: "BTC",
Quote: "USDT",
}
_, err = s.GetOrder(context.Background(), &gctrpc.GetOrderRequest{
Exchange: exchName,
OrderId: "",
@@ -963,8 +988,8 @@ func TestGetOrder(t *testing.T) {
Pair: p,
Asset: asset.Spot.String(),
})
if !errors.Is(err, errOrderCannotBeEmpty) {
t.Errorf("expected %v, received %v", errOrderCannotBeEmpty, err)
if !errors.Is(err, errOrderIDCannotBeEmpty) {
t.Errorf("expected %v, received %v", errOrderIDCannotBeEmpty, err)
}
err = engerino.OrderManager.Start(engerino)
if err != nil {
@@ -980,3 +1005,98 @@ func TestGetOrder(t *testing.T) {
t.Error("expected error")
}
}
func TestCheckVars(t *testing.T) {
var e exchange.IBotExchange
err := checkParams("Binance", e, asset.Spot, currency.NewPair(currency.BTC, currency.USDT))
if !errors.Is(err, errExchangeNotLoaded) {
t.Errorf("expected %v, got %v", errExchangeNotLoaded, err)
}
e = &binance.Binance{}
_, ok := e.(*binance.Binance)
if !ok {
t.Fatal("invalid ibotexchange interface")
}
err = checkParams("Binance", e, asset.Spot, currency.NewPair(currency.BTC, currency.USDT))
if !errors.Is(err, errExchangeDisabled) {
t.Errorf("expected %v, got %v", errExchangeDisabled, err)
}
e.SetEnabled(true)
err = checkParams("Binance", e, asset.Spot, currency.NewPair(currency.BTC, currency.USDT))
if !errors.Is(err, errAssetTypeDisabled) {
t.Errorf("expected %v, got %v", errAssetTypeDisabled, err)
}
fmt1 := currency.PairStore{
RequestFormat: &currency.PairFormat{Uppercase: true},
ConfigFormat: &currency.PairFormat{
Delimiter: currency.DashDelimiter,
Uppercase: true,
},
}
coinFutures := currency.PairStore{
RequestFormat: &currency.PairFormat{
Uppercase: true,
Delimiter: currency.UnderscoreDelimiter,
},
ConfigFormat: &currency.PairFormat{
Uppercase: true,
Delimiter: currency.UnderscoreDelimiter,
},
}
usdtFutures := currency.PairStore{
RequestFormat: &currency.PairFormat{
Uppercase: true,
},
ConfigFormat: &currency.PairFormat{
Uppercase: true,
},
}
err = e.GetBase().StoreAssetPairFormat(asset.Spot, fmt1)
if err != nil {
t.Error(err)
}
err = e.GetBase().StoreAssetPairFormat(asset.Margin, fmt1)
if err != nil {
t.Error(err)
}
err = e.GetBase().StoreAssetPairFormat(asset.CoinMarginedFutures, coinFutures)
if err != nil {
t.Error(err)
}
err = e.GetBase().StoreAssetPairFormat(asset.USDTMarginedFutures, usdtFutures)
if err != nil {
t.Error(err)
}
err = checkParams("Binance", e, asset.Spot, currency.NewPair(currency.BTC, currency.USDT))
if !errors.Is(err, errCurrencyPairInvalid) {
t.Errorf("expected %v, got %v", errCurrencyPairInvalid, err)
}
var data = []currency.Pair{
{Delimiter: currency.DashDelimiter, Base: currency.BTC, Quote: currency.USDT},
}
e.GetBase().CurrencyPairs.StorePairs(asset.Spot, data, false)
err = checkParams("Binance", e, asset.Spot, currency.NewPair(currency.BTC, currency.USDT))
if !errors.Is(err, errCurrencyNotEnabled) {
t.Errorf("expected %v, got %v", errCurrencyNotEnabled, err)
}
e.GetBase().CurrencyPairs.EnablePair(
asset.Spot,
currency.Pair{Delimiter: currency.DashDelimiter, Base: currency.BTC, Quote: currency.USDT},
)
err = checkParams("Binance", e, asset.Spot, currency.NewPair(currency.BTC, currency.USDT))
if err != nil {
t.Error(err)
}
}

View File

@@ -232,7 +232,7 @@ func TestUpdateTicker(t *testing.T) {
t.Fatal(err)
}
cp = currency.NewPair(currency.DASH, currency.KRW)
cp = currency.NewPair(currency.BTC, currency.KRW)
_, err = b.UpdateTicker(cp, asset.Spot)
if err != nil {
t.Fatal(err)

View File

@@ -58,7 +58,7 @@ var (
// order size, order pricing, total notional values, total maximum orders etc
// for execution on an exchange.
type ExecutionLimits struct {
m map[asset.Item]map[currency.Code]map[currency.Code]*Limits
m map[asset.Item]map[*currency.Item]map[*currency.Item]*Limits
mtx sync.RWMutex
}
@@ -94,26 +94,26 @@ func (e *ExecutionLimits) LoadLimits(levels []MinMaxLevel) error {
e.mtx.Lock()
defer e.mtx.Unlock()
if e.m == nil {
e.m = make(map[asset.Item]map[currency.Code]map[currency.Code]*Limits)
e.m = make(map[asset.Item]map[*currency.Item]map[*currency.Item]*Limits)
}
for x := range levels {
m1, ok := e.m[levels[x].Asset]
if !ok {
m1 = make(map[currency.Code]map[currency.Code]*Limits)
m1 = make(map[*currency.Item]map[*currency.Item]*Limits)
e.m[levels[x].Asset] = m1
}
m2, ok := m1[levels[x].Pair.Base]
m2, ok := m1[levels[x].Pair.Base.Item]
if !ok {
m2 = make(map[currency.Code]*Limits)
m1[levels[x].Pair.Base] = m2
m2 = make(map[*currency.Item]*Limits)
m1[levels[x].Pair.Base.Item] = m2
}
limit, ok := m2[levels[x].Pair.Quote]
limit, ok := m2[levels[x].Pair.Quote.Item]
if !ok {
limit = new(Limits)
m2[levels[x].Pair.Quote] = limit
m2[levels[x].Pair.Quote.Item] = limit
}
if levels[x].MinPrice > levels[x].MaxPrice {
@@ -169,12 +169,12 @@ func (e *ExecutionLimits) GetOrderExecutionLimits(a asset.Item, cp currency.Pair
return nil, errExchangeLimitAsset
}
m2, ok := m1[cp.Base]
m2, ok := m1[cp.Base.Item]
if !ok {
return nil, errExchangeLimitBase
}
limit, ok := m2[cp.Quote]
limit, ok := m2[cp.Quote.Item]
if !ok {
return nil, errExchangeLimitQuote
}
@@ -198,12 +198,12 @@ func (e *ExecutionLimits) CheckOrderExecutionLimits(a asset.Item, cp currency.Pa
return errCannotValidateAsset
}
m2, ok := m1[cp.Base]
m2, ok := m1[cp.Base.Item]
if !ok {
return errCannotValidateBaseCurrency
}
limit, ok := m2[cp.Quote]
limit, ok := m2[cp.Quote.Item]
if !ok {
return errCannotValidateQuoteCurrency
}

View File

@@ -507,8 +507,8 @@
],
"pairs": {
"spot": {
"enabled": "BTCKRW,ETHKRW,DASHKRW,LTCKRW,ETCKRW,XRPKRW,BCHKRW,ZECKRW,QTUMKRW,BTGKRW,EOSKRW",
"available": "BHPKRW,STEEMKRW,GTOKRW,ETCKRW,STRATKRW,FXKRW,LTCKRW,MIXKRW,THETAKRW,QTUMKRW,ADAKRW,MCOKRW,INSKRW,RDNKRW,CONKRW,FABKRW,ETHKRW,HDACKRW,BTCKRW,POWRKRW,CMTKRW,LBAKRW,ETHOSKRW,HCKRW,ETZKRW,PPTKRW,XVGKRW,WTCKRW,TMTGKRW,LOOMKRW,WETKRW,ABTKRW,ITCKRW,GXCKRW,ORBSKRW,ICXKRW,BSVKRW,MXCKRW,MITHKRW,ZECKRW,AEKRW,SALTKRW,ARNKRW,TRUEKRW,ENJKRW,GNTKRW,PLYKRW,REPKRW,ZRXKRW,BTGKRW,APISKRW,QKCKRW,LRCKRW,DVPKRW,DADKRW,CHRKRW,BCHKRW,NPXSKRW,PIVXKRW,AMOKRW,RNTKRW,XEMKRW,FCTKRW,WOMKRW,WAXPKRW,DACKRW,OMGKRW,PCMKRW,CROKRW,FNBKRW,ANKRKRW,EOSKRW,KNCKRW,OCNKRW,MTLKRW,XSRKRW,VALORKRW,TRVKRW,AUTOKRW,HYCKRW,AOAKRW,BTTKRW,MBLKRW,VETKRW,XRPKRW,ZILKRW,ELFKRW,LAMBKRW,POLYKRW,IOSTKRW,BZNTKRW,DASHKRW,CTXCKRW,BATKRW,FZZKRW,PAYKRW,BCDKRW,SNTKRW,WAVESKRW,XLMKRW,LINKKRW,OGOKRW,WICCKRW,TRXKRW"
"enabled": "BTCKRW,ETHKRW,LTCKRW,ETCKRW,XRPKRW,BCHKRW,QTUMKRW,BTGKRW,EOSKRW",
"available": "BHPKRW,STEEMKRW,GTOKRW,ETCKRW,STRATKRW,FXKRW,LTCKRW,MIXKRW,THETAKRW,QTUMKRW,ADAKRW,MCOKRW,INSKRW,RDNKRW,CONKRW,FABKRW,ETHKRW,HDACKRW,BTCKRW,POWRKRW,CMTKRW,LBAKRW,ETHOSKRW,HCKRW,ETZKRW,PPTKRW,XVGKRW,WTCKRW,TMTGKRW,LOOMKRW,WETKRW,ABTKRW,ITCKRW,GXCKRW,ORBSKRW,ICXKRW,BSVKRW,MXCKRW,MITHKRW,AEKRW,SALTKRW,ARNKRW,TRUEKRW,ENJKRW,GNTKRW,PLYKRW,REPKRW,ZRXKRW,BTGKRW,APISKRW,QKCKRW,LRCKRW,DVPKRW,DADKRW,CHRKRW,BCHKRW,NPXSKRW,PIVXKRW,AMOKRW,RNTKRW,XEMKRW,FCTKRW,WOMKRW,WAXPKRW,DACKRW,OMGKRW,PCMKRW,CROKRW,FNBKRW,ANKRKRW,EOSKRW,KNCKRW,OCNKRW,MTLKRW,XSRKRW,VALORKRW,TRVKRW,AUTOKRW,HYCKRW,AOAKRW,BTTKRW,MBLKRW,VETKRW,XRPKRW,ZILKRW,ELFKRW,LAMBKRW,POLYKRW,IOSTKRW,BZNTKRW,CTXCKRW,BATKRW,FZZKRW,PAYKRW,BCDKRW,SNTKRW,WAVESKRW,XLMKRW,LINKKRW,OGOKRW,WICCKRW,TRXKRW"
}
}
},