mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
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:
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
"api-secret-override": "",
|
||||
"api-client-id-override": "",
|
||||
"api-2fa-override": "",
|
||||
"fake-orders": false
|
||||
"real-orders": false
|
||||
}
|
||||
},
|
||||
"portfolio-settings": {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
errOrderCannotBeEmpty = errors.New("order cannot be empty")
|
||||
errOrderIDCannotBeEmpty = errors.New("orderID cannot be empty")
|
||||
)
|
||||
|
||||
type orderManagerConfig struct {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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: ¤cy.PairFormat{Uppercase: true},
|
||||
ConfigFormat: ¤cy.PairFormat{
|
||||
Delimiter: currency.DashDelimiter,
|
||||
Uppercase: true,
|
||||
},
|
||||
}
|
||||
coinFutures := currency.PairStore{
|
||||
RequestFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
Delimiter: currency.UnderscoreDelimiter,
|
||||
},
|
||||
ConfigFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
Delimiter: currency.UnderscoreDelimiter,
|
||||
},
|
||||
}
|
||||
usdtFutures := currency.PairStore{
|
||||
RequestFormat: ¤cy.PairFormat{
|
||||
Uppercase: true,
|
||||
},
|
||||
ConfigFormat: ¤cy.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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
4
testdata/configtest.json
vendored
4
testdata/configtest.json
vendored
@@ -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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user