Daily engine changes

1) Although gRPC does server side validation currently, validate basic things
on gctcli before relaying the request to the gRPC server
2) Make pair format consistent for the exchange sycner
3) Fix OKEX ticker failure due to thinking futures info is authenticated
4) Start filling out config tests
5) Extend timeout for golangci config so that AppVeyor has time to
complete (Travis is fine)
6) Add IsSupported exchange func for easy lookup
This commit is contained in:
Adrian Gallagher
2019-09-10 17:07:00 +10:00
parent 0824ee04c9
commit e8b517ef0a
11 changed files with 490 additions and 174 deletions

View File

@@ -1,5 +1,5 @@
run:
deadline: 40s
deadline: 1m0s
issues-exit-code: 1
tests: true
skip-dirs:

View File

@@ -2,6 +2,7 @@ package main
import (
"context"
"errors"
"fmt"
"strconv"
@@ -82,12 +83,6 @@ func enableSubsystem(c *cli.Context) error {
return nil
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var subsystemName string
if c.IsSet("subsystem") {
subsystemName = c.String("subsystem")
@@ -95,6 +90,16 @@ func enableSubsystem(c *cli.Context) error {
subsystemName = c.Args().First()
}
if subsystemName == "" {
return errors.New("invalid subsystem supplied")
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.EnableSubsystem(context.Background(),
&gctrpc.GenericSubsystemRequest{
@@ -129,12 +134,6 @@ func disableSubsystem(c *cli.Context) error {
return nil
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var subsystemName string
if c.IsSet("subsystem") {
subsystemName = c.String("subsystem")
@@ -142,6 +141,16 @@ func disableSubsystem(c *cli.Context) error {
subsystemName = c.Args().First()
}
if subsystemName == "" {
return errors.New("invalid subsystem supplied")
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.DisableSubsystem(context.Background(),
&gctrpc.GenericSubsystemRequest{
@@ -268,12 +277,6 @@ func enableExchange(c *cli.Context) error {
return nil
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var exchangeName string
if c.IsSet("exchange") {
exchangeName = c.String("exchange")
@@ -281,6 +284,16 @@ func enableExchange(c *cli.Context) error {
exchangeName = c.Args().First()
}
if !validExchange(exchangeName) {
return errInvalidExchange
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.EnableExchange(context.Background(),
&gctrpc.GenericExchangeNameRequest{
@@ -315,12 +328,6 @@ func disableExchange(c *cli.Context) error {
return nil
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var exchangeName string
if c.IsSet("exchange") {
exchangeName = c.String("exchange")
@@ -328,6 +335,16 @@ func disableExchange(c *cli.Context) error {
exchangeName = c.Args().First()
}
if !validExchange(exchangeName) {
return errInvalidExchange
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.DisableExchange(context.Background(),
&gctrpc.GenericExchangeNameRequest{
@@ -362,12 +379,6 @@ func getExchangeOTPCode(c *cli.Context) error {
return nil
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var exchangeName string
if c.IsSet("exchange") {
exchangeName = c.String("exchange")
@@ -375,6 +386,16 @@ func getExchangeOTPCode(c *cli.Context) error {
exchangeName = c.Args().First()
}
if !validExchange(exchangeName) {
return errInvalidExchange
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.GetExchangeOTPCode(context.Background(),
&gctrpc.GenericExchangeNameRequest{
@@ -434,12 +455,6 @@ func getExchangeInfo(c *cli.Context) error {
return nil
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var exchangeName string
if c.IsSet("exchange") {
exchangeName = c.String("exchange")
@@ -447,6 +462,16 @@ func getExchangeInfo(c *cli.Context) error {
exchangeName = c.Args().First()
}
if !validExchange(exchangeName) {
return errInvalidExchange
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.GetExchangeInfo(context.Background(),
&gctrpc.GenericExchangeNameRequest{
@@ -489,12 +514,6 @@ func getTicker(c *cli.Context) error {
return nil
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var exchangeName string
var currencyPair string
var assetType string
@@ -505,23 +524,33 @@ func getTicker(c *cli.Context) error {
exchangeName = c.Args().First()
}
if !validExchange(exchangeName) {
return errInvalidExchange
}
if c.IsSet("pair") {
currencyPair = c.String("pair")
} else {
currencyPair = c.Args().Get(1)
}
if !validPair(currencyPair) {
return errInvalidPair
}
if c.IsSet("asset") {
assetType = c.String("asset")
} else {
assetType = c.Args().Get(2)
}
if !validPair(currencyPair) {
return errInvalidPair
conn, err := setupClient()
if err != nil {
return err
}
p := currency.NewPairDelimiter(currencyPair, pairDelimiter)
defer conn.Close()
p := currency.NewPairDelimiter(currencyPair, pairDelimiter)
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.GetTicker(context.Background(),
&gctrpc.GetTickerRequest{
@@ -545,7 +574,7 @@ func getTicker(c *cli.Context) error {
var getTickersCommand = cli.Command{
Name: "gettickers",
Usage: "gets all tickers for all enabled exchanes and currency pairs",
Usage: "gets all tickers for all enabled exchanges and currency pairs",
Action: getTickers,
}
@@ -593,12 +622,6 @@ func getOrderbook(c *cli.Context) error {
return nil
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var exchangeName string
var currencyPair string
var assetType string
@@ -609,23 +632,33 @@ func getOrderbook(c *cli.Context) error {
exchangeName = c.Args().First()
}
if !validExchange(exchangeName) {
return errInvalidExchange
}
if c.IsSet("pair") {
currencyPair = c.String("pair")
} else {
currencyPair = c.Args().Get(1)
}
if !validPair(currencyPair) {
return errInvalidPair
}
if c.IsSet("asset") {
assetType = c.String("asset")
} else {
assetType = c.Args().Get(2)
}
if !validPair(currencyPair) {
return errInvalidPair
conn, err := setupClient()
if err != nil {
return err
}
p := currency.NewPairDelimiter(currencyPair, pairDelimiter)
defer conn.Close()
p := currency.NewPairDelimiter(currencyPair, pairDelimiter)
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.GetOrderbook(context.Background(),
&gctrpc.GetOrderbookRequest{
@@ -649,7 +682,7 @@ func getOrderbook(c *cli.Context) error {
var getOrderbooksCommand = cli.Command{
Name: "getorderbooks",
Usage: "gets all orderbooks for all enabled exchanes and currency pairs",
Usage: "gets all orderbooks for all enabled exchanges and currency pairs",
Action: getOrderbooks,
}
@@ -689,12 +722,6 @@ func getAccountInfo(c *cli.Context) error {
return nil
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var exchange string
if c.IsSet("exchange") {
exchange = c.String("exchange")
@@ -702,6 +729,16 @@ func getAccountInfo(c *cli.Context) error {
exchange = c.Args().First()
}
if !validExchange(exchange) {
return errInvalidExchange
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.GetAccountInfo(context.Background(),
&gctrpc.GetAccountInfoRequest{
@@ -1009,12 +1046,6 @@ var getOrdersCommand = cli.Command{
}
func getOrders(c *cli.Context) error {
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var exchangeName string
var assetType string
var currencyPair string
@@ -1025,6 +1056,10 @@ func getOrders(c *cli.Context) error {
exchangeName = c.Args().First()
}
if !validExchange(exchangeName) {
return errInvalidExchange
}
if c.IsSet("asset_type") {
assetType = c.String("asset_type")
} else {
@@ -1040,8 +1075,14 @@ func getOrders(c *cli.Context) error {
if !validPair(currencyPair) {
return errInvalidPair
}
p := currency.NewPairDelimiter(currencyPair, pairDelimiter)
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
p := currency.NewPairDelimiter(currencyPair, pairDelimiter)
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.GetOrders(context.Background(), &gctrpc.GetOrdersRequest{
Exchange: exchangeName,
@@ -1083,12 +1124,6 @@ func getOrder(c *cli.Context) error {
return nil
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var exchangeName string
var orderID string
@@ -1098,12 +1133,22 @@ func getOrder(c *cli.Context) error {
exchangeName = c.Args().First()
}
if !validExchange(exchangeName) {
return errInvalidExchange
}
if c.IsSet("order_id") {
orderID = c.String("order_id")
} else {
orderID = c.Args().Get(1)
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.GetOrder(context.Background(), &gctrpc.GetOrderRequest{
Exchange: exchangeName,
@@ -1120,7 +1165,7 @@ func getOrder(c *cli.Context) error {
var submitOrderCommand = cli.Command{
Name: "submitorder",
Usage: "submit order submits an exchange order",
ArgsUsage: "<exchange> <currency_pair> <side> <order_type> <amount> <price> <client_id>",
ArgsUsage: "<exchange> <pair> <side> <order_type> <amount> <price> <client_id>",
Action: submitOrder,
Flags: []cli.Flag{
cli.StringFlag{
@@ -1128,7 +1173,7 @@ var submitOrderCommand = cli.Command{
Usage: "the exchange to submit the order for",
},
cli.StringFlag{
Name: "currency_pair",
Name: "pair",
Usage: "the currency pair",
},
cli.StringFlag{
@@ -1160,12 +1205,6 @@ func submitOrder(c *cli.Context) error {
return nil
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var exchangeName string
var currencyPair string
var orderSide string
@@ -1180,12 +1219,20 @@ func submitOrder(c *cli.Context) error {
exchangeName = c.Args().First()
}
if c.IsSet("currency_pair") {
currencyPair = c.String("currency_pair")
if !validExchange(exchangeName) {
return errInvalidExchange
}
if c.IsSet("pair") {
currencyPair = c.String("pair")
} else {
currencyPair = c.Args().Get(1)
}
if !validPair(currencyPair) {
return errInvalidPair
}
if c.IsSet("side") {
orderSide = c.String("side")
} else {
@@ -1216,11 +1263,13 @@ func submitOrder(c *cli.Context) error {
clientID = c.Args().Get(6)
}
if !validPair(currencyPair) {
return errInvalidPair
conn, err := setupClient()
if err != nil {
return err
}
p := currency.NewPairDelimiter(currencyPair, pairDelimiter)
defer conn.Close()
p := currency.NewPairDelimiter(currencyPair, pairDelimiter)
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.SubmitOrder(context.Background(), &gctrpc.SubmitOrderRequest{
Exchange: exchangeName,
@@ -1246,7 +1295,7 @@ func submitOrder(c *cli.Context) error {
var simulateOrderCommand = cli.Command{
Name: "simulateorder",
Usage: "simulate order simulates an exchange order",
ArgsUsage: "<exchange> <currency_pair> <side> <amount>",
ArgsUsage: "<exchange> <pair> <side> <amount>",
Action: simulateOrder,
Flags: []cli.Flag{
cli.StringFlag{
@@ -1254,7 +1303,7 @@ var simulateOrderCommand = cli.Command{
Usage: "the exchange to simulate the order for",
},
cli.StringFlag{
Name: "currency_pair",
Name: "pair",
Usage: "the currency pair",
},
cli.StringFlag{
@@ -1274,12 +1323,6 @@ func simulateOrder(c *cli.Context) error {
return nil
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var exchangeName string
var currencyPair string
var orderSide string
@@ -1291,12 +1334,20 @@ func simulateOrder(c *cli.Context) error {
exchangeName = c.Args().First()
}
if c.IsSet("currency_pair") {
currencyPair = c.String("currency_pair")
if !validExchange(exchangeName) {
return errInvalidExchange
}
if c.IsSet("pair") {
currencyPair = c.String("pair")
} else {
currencyPair = c.Args().Get(1)
}
if !validPair(currencyPair) {
return errInvalidPair
}
if c.IsSet("side") {
orderSide = c.String("side")
} else {
@@ -1309,11 +1360,13 @@ func simulateOrder(c *cli.Context) error {
amount, _ = strconv.ParseFloat(c.Args().Get(3), 64)
}
if !validPair(currencyPair) {
return errInvalidPair
conn, err := setupClient()
if err != nil {
return err
}
p := currency.NewPairDelimiter(currencyPair, pairDelimiter)
defer conn.Close()
p := currency.NewPairDelimiter(currencyPair, pairDelimiter)
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.SimulateOrder(context.Background(), &gctrpc.SimulateOrderRequest{
Exchange: exchangeName,
@@ -1336,7 +1389,7 @@ func simulateOrder(c *cli.Context) error {
var whaleBombCommand = cli.Command{
Name: "whalebomb",
Usage: "whale bomb finds the amount required to reach a price target",
ArgsUsage: "<exchange> <currency_pair> <side> <price>",
ArgsUsage: "<exchange> <pair> <side> <price>",
Action: whaleBomb,
Flags: []cli.Flag{
cli.StringFlag{
@@ -1344,7 +1397,7 @@ var whaleBombCommand = cli.Command{
Usage: "the exchange to whale bomb",
},
cli.StringFlag{
Name: "currency_pair",
Name: "pair",
Usage: "the currency pair",
},
cli.StringFlag{
@@ -1364,12 +1417,6 @@ func whaleBomb(c *cli.Context) error {
return nil
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var exchangeName string
var currencyPair string
var orderSide string
@@ -1381,12 +1428,20 @@ func whaleBomb(c *cli.Context) error {
exchangeName = c.Args().First()
}
if c.IsSet("currency_pair") {
currencyPair = c.String("currency_pair")
if !validExchange(exchangeName) {
return errInvalidExchange
}
if c.IsSet("pair") {
currencyPair = c.String("pair")
} else {
currencyPair = c.Args().Get(1)
}
if !validPair(currencyPair) {
return errInvalidPair
}
if c.IsSet("side") {
orderSide = c.String("side")
} else {
@@ -1399,11 +1454,13 @@ func whaleBomb(c *cli.Context) error {
price, _ = strconv.ParseFloat(c.Args().Get(3), 64)
}
if !validPair(currencyPair) {
return errInvalidPair
conn, err := setupClient()
if err != nil {
return err
}
p := currency.NewPairDelimiter(currencyPair, pairDelimiter)
defer conn.Close()
p := currency.NewPairDelimiter(currencyPair, pairDelimiter)
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.WhaleBomb(context.Background(), &gctrpc.WhaleBombRequest{
Exchange: exchangeName,
@@ -1426,7 +1483,7 @@ func whaleBomb(c *cli.Context) error {
var cancelOrderCommand = cli.Command{
Name: "cancelorder",
Usage: "cancel order cancels an exchange order",
ArgsUsage: "<exchange> <account_id> <order_id> <currency_pair> <asset_type> <wallet_address> <side>",
ArgsUsage: "<exchange> <account_id> <order_id> <pair> <asset_type> <wallet_address> <side>",
Action: cancelOrder,
Flags: []cli.Flag{
cli.StringFlag{
@@ -1442,7 +1499,7 @@ var cancelOrderCommand = cli.Command{
Usage: "the order id",
},
cli.StringFlag{
Name: "currency_pair",
Name: "pair",
Usage: "the currency pair to cancel the order for",
},
cli.StringFlag{
@@ -1466,12 +1523,6 @@ func cancelOrder(c *cli.Context) error {
return nil
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var exchangeName string
var accountID string
var orderID string
@@ -1486,6 +1537,10 @@ func cancelOrder(c *cli.Context) error {
exchangeName = c.Args().First()
}
if !validExchange(exchangeName) {
return errInvalidExchange
}
if c.IsSet("order_id") {
orderID = c.String("order_id")
} else {
@@ -1496,8 +1551,8 @@ func cancelOrder(c *cli.Context) error {
accountID = c.String("account_id")
}
if c.IsSet("currency_pair") {
currencyPair = c.String("currency_pair")
if c.IsSet("pair") {
currencyPair = c.String("pair")
}
if c.IsSet("asset_type") {
@@ -1520,6 +1575,12 @@ func cancelOrder(c *cli.Context) error {
p = currency.NewPairDelimiter(currencyPair, pairDelimiter)
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.CancelOrder(context.Background(), &gctrpc.CancelOrderRequest{
Exchange: exchangeName,
@@ -1556,12 +1617,6 @@ var cancelAllOrdersCommand = cli.Command{
}
func cancelAllOrders(c *cli.Context) error {
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
var exchangeName string
if c.IsSet("exchange") {
exchangeName = c.String("exchange")
@@ -1569,6 +1624,19 @@ func cancelAllOrders(c *cli.Context) error {
exchangeName = c.Args().First()
}
// exchange name is an optional param
if exchangeName != "" {
if !validExchange(exchangeName) {
return errInvalidExchange
}
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.CancelAllOrders(context.Background(), &gctrpc.CancelAllOrdersRequest{
Exchange: exchangeName,
@@ -1607,7 +1675,7 @@ func getEvents(_ *cli.Context) error {
var addEventCommand = cli.Command{
Name: "addevent",
Usage: "adds an event",
ArgsUsage: "<exchange> <item> <condition> <price> <check_bids> <check_bids_and_asks> <orderbook_amount> <currency_pair> <asset_type> <action>",
ArgsUsage: "<exchange> <item> <condition> <price> <check_bids> <check_bids_and_asks> <orderbook_amount> <pair> <asset_type> <action>",
Action: addEvent,
Flags: []cli.Flag{
cli.StringFlag{
@@ -1639,7 +1707,7 @@ var addEventCommand = cli.Command{
Usage: "the orderbook amount to trigger the event",
},
cli.StringFlag{
Name: "currency_pair",
Name: "pair",
Usage: "the currency pair",
},
cli.StringFlag{
@@ -1704,8 +1772,8 @@ func addEvent(c *cli.Context) error {
orderbookAmount = c.Float64("orderbook_amount")
}
if c.IsSet("currency_pair") {
currencyPair = c.String("currency_pair")
if c.IsSet("pair") {
currencyPair = c.String("pair")
} else {
return fmt.Errorf("currency pair is required")
}
@@ -1720,17 +1788,17 @@ func addEvent(c *cli.Context) error {
return fmt.Errorf("action is required")
}
if !validPair(currencyPair) {
return errInvalidPair
}
conn, err := setupClient()
if err != nil {
return err
}
defer conn.Close()
if !validPair(currencyPair) {
return errInvalidPair
}
p := currency.NewPairDelimiter(currencyPair, pairDelimiter)
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.AddEvent(context.Background(), &gctrpc.AddEventRequest{
Exchange: exchangeName,
@@ -1831,6 +1899,10 @@ func getCryptocurrencyDepositAddresses(c *cli.Context) error {
exchangeName = c.Args().First()
}
if !validExchange(exchangeName) {
return errInvalidExchange
}
conn, err := setupClient()
if err != nil {
return err
@@ -1880,6 +1952,10 @@ func getCryptocurrencyDepositAddress(c *cli.Context) error {
exchangeName = c.Args().First()
}
if !validExchange(exchangeName) {
return errInvalidExchange
}
if c.IsSet("cryptocurrency") {
cryptocurrency = c.String("cryptocurrency")
} else {
@@ -2086,6 +2162,10 @@ func getExchangePairs(c *cli.Context) error {
exchange = c.Args().First()
}
if !validExchange(exchange) {
return errInvalidExchange
}
if c.IsSet("asset") {
asset = c.String("asset")
} else {
@@ -2099,7 +2179,6 @@ func getExchangePairs(c *cli.Context) error {
defer conn.Close()
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.GetExchangePairs(context.Background(),
&gctrpc.GetExchangePairsRequest{
Exchange: exchange,
@@ -2150,12 +2229,20 @@ func enableExchangePair(c *cli.Context) error {
exchange = c.Args().First()
}
if !validExchange(exchange) {
return errInvalidExchange
}
if c.IsSet("pair") {
pair = c.String("pair")
} else {
pair = c.Args().Get(1)
}
if !validPair(pair) {
return errInvalidPair
}
if c.IsSet("asset") {
asset = c.String("asset")
} else {
@@ -2168,10 +2255,6 @@ func enableExchangePair(c *cli.Context) error {
}
defer conn.Close()
if !validPair(pair) {
return errInvalidPair
}
p := currency.NewPairDelimiter(pair, pairDelimiter)
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.EnableExchangePair(context.Background(),
@@ -2229,12 +2312,20 @@ func disableExchangePair(c *cli.Context) error {
exchange = c.Args().First()
}
if !validExchange(exchange) {
return errInvalidExchange
}
if c.IsSet("pair") {
pair = c.String("pair")
} else {
pair = c.Args().Get(1)
}
if !validPair(pair) {
return errInvalidPair
}
if c.IsSet("asset") {
asset = c.String("asset")
} else {
@@ -2247,10 +2338,6 @@ func disableExchangePair(c *cli.Context) error {
}
defer conn.Close()
if !validPair(pair) {
return errInvalidPair
}
p := currency.NewPairDelimiter(pair, pairDelimiter)
client := gctrpc.NewGoCryptoTraderClient(conn)
result, err := client.DisableExchangePair(context.Background(),

View File

@@ -3,12 +3,19 @@ package main
import (
"errors"
"strings"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
)
var (
errInvalidPair = errors.New("invalid currency pair supplied")
errInvalidPair = errors.New("invalid currency pair supplied")
errInvalidExchange = errors.New("invalid exchange supplied")
)
func validPair(pair string) bool {
return strings.Contains(pair, pairDelimiter)
}
func validExchange(exch string) bool {
return exchange.IsSupported(exch)
}

View File

@@ -446,10 +446,6 @@ func (c *Config) CheckExchangeAssetsConsistency(exchName string) {
return
}
if exchCfg.CurrencyPairs == nil {
return
}
exchangeAssetTypes, err := c.GetExchangeAssetTypes(exchName)
if err != nil {
return
@@ -458,7 +454,9 @@ func (c *Config) CheckExchangeAssetsConsistency(exchName string) {
storedAssetTypes := exchCfg.CurrencyPairs.GetAssetTypes()
for x := range storedAssetTypes {
if !exchangeAssetTypes.Contains(storedAssetTypes[x]) {
log.Warnf(log.ConfigMgr, "%s has non-needed stored asset type %v. Removing..\n", exchName, storedAssetTypes[x])
log.Warnf(log.ConfigMgr,
"%s has non-needed stored asset type %v. Removing..\n",
exchName, storedAssetTypes[x])
exchCfg.CurrencyPairs.Delete(storedAssetTypes[x])
}
}

View File

@@ -15,6 +15,7 @@ const (
// Default number of enabled exchanges. Modify this whenever an exchange is
// added or removed
defaultEnabledExchanges = 28
testFakeExchangeName = "Stampbit"
)
func TestGetCurrencyConfig(t *testing.T) {
@@ -143,6 +144,70 @@ func TestCheckClientBankAccounts(t *testing.T) {
// TO-DO: Complete test coverage
}
func TestPurgeExchangeCredentials(t *testing.T) {
t.Parallel()
var c Config
c.Exchanges = []ExchangeConfig{
{
Name: "test",
API: APIConfig{
AuthenticatedSupport: true,
AuthenticatedWebsocketSupport: true,
CredentialsValidator: &APICredentialsValidatorConfig{
RequiresKey: true,
RequiresSecret: true,
RequiresClientID: true,
},
Credentials: APICredentialsConfig{
Key: "asdf123",
Secret: "secretp4ssw0rd",
ClientID: "1337",
OTPSecret: "otp",
PEMKey: "aaa",
},
},
},
{
Name: "test123",
API: APIConfig{
CredentialsValidator: &APICredentialsValidatorConfig{
RequiresKey: true,
},
Credentials: APICredentialsConfig{
Key: "asdf",
Secret: DefaultAPISecret,
},
},
},
}
c.PurgeExchangeAPICredentials()
exchCfg, err := c.GetExchangeConfig("test")
if err != nil {
t.Error(err)
}
if exchCfg.API.Credentials.Key != DefaultAPIKey &&
exchCfg.API.Credentials.ClientID != DefaultAPIClientID &&
exchCfg.API.Credentials.Secret != DefaultAPISecret &&
exchCfg.API.Credentials.OTPSecret != "" &&
exchCfg.API.Credentials.PEMKey != "" {
t.Error("unexpected values")
}
exchCfg, err = c.GetExchangeConfig("test123")
if err != nil {
t.Error(err)
}
if exchCfg.API.Credentials.Key != "asdf" {
t.Error("unexpected values")
}
}
func TestGetCommunicationsConfig(t *testing.T) {
cfg := GetConfig()
err := cfg.LoadConfig(ConfigTestFile)
@@ -224,6 +289,18 @@ func TestCheckCommunicationsConfig(t *testing.T) {
t.Error("Test failed. CheckCommunicationsConfig error:", err)
}
cfg.Communications.SMSGlobalConfig.From = ""
cfg.CheckCommunicationsConfig()
if cfg.Communications.SMSGlobalConfig.From != cfg.Name {
t.Error("Test failed. CheckCommunicationsConfig From value should of been set to the config name")
}
cfg.Communications.SMSGlobalConfig.From = "aaaaaaaaaaaaaaaaaaa"
cfg.CheckCommunicationsConfig()
if cfg.Communications.SMSGlobalConfig.From != "aaaaaaaaaaa" {
t.Error("Test failed. CheckCommunicationsConfig From value should of been trimmed to 11 characters")
}
cfg.SMS = &SMSGlobalConfig{}
cfg.CheckCommunicationsConfig()
if cfg.SMS != nil {
@@ -266,6 +343,122 @@ func TestCheckCommunicationsConfig(t *testing.T) {
}
}
func TestGetExchangeAssetTypes(t *testing.T) {
t.Parallel()
var c Config
_, err := c.GetExchangeAssetTypes("void")
if err == nil {
t.Error("err should of been thrown on a non-existent exchange")
}
c.Exchanges = append(c.Exchanges,
ExchangeConfig{
Name: testFakeExchangeName,
CurrencyPairs: &currency.PairsManager{
AssetTypes: asset.Items{
asset.Spot,
asset.Futures,
},
},
},
)
var assets asset.Items
assets, err = c.GetExchangeAssetTypes(testFakeExchangeName)
if err != nil {
t.Error(err)
}
if assets.JoinToString(",") != "spot,futures" {
t.Error("unexpected results")
}
c.Exchanges[0].CurrencyPairs = nil
_, err = c.GetExchangeAssetTypes(testFakeExchangeName)
if err == nil {
t.Error("a nil pair manager should throw an error")
}
}
func TestSupportsExchangeAssetType(t *testing.T) {
t.Parallel()
var c Config
_, err := c.SupportsExchangeAssetType("void", asset.Spot)
if err == nil {
t.Error("unexpected result for non-existent exchange")
}
c.Exchanges = append(c.Exchanges,
ExchangeConfig{
Name: testFakeExchangeName,
CurrencyPairs: &currency.PairsManager{
AssetTypes: asset.Items{
asset.Spot,
asset.Futures,
},
},
},
)
supports, err := c.SupportsExchangeAssetType(testFakeExchangeName, asset.Spot)
if err != nil {
t.Error(err)
}
if !supports {
t.Error("exchange should support spot asset item")
}
_, err = c.SupportsExchangeAssetType(testFakeExchangeName, "asdf")
if err == nil {
t.Error("invalid asset item should throw an error")
}
c.Exchanges[0].CurrencyPairs = nil
_, err = c.SupportsExchangeAssetType(testFakeExchangeName, asset.Spot)
if err == nil {
t.Error("a nil pair manager should throw an error")
}
}
func TestCheckExchangeAssetsConsistency(t *testing.T) {
t.Parallel()
var c Config
// Test for non-existent exchange
c.CheckExchangeAssetsConsistency("void")
c.Exchanges = append(c.Exchanges,
ExchangeConfig{
Name: testFakeExchangeName,
},
)
// Tests for nil currency pairs store but valid exchange name
c.CheckExchangeAssetsConsistency(testFakeExchangeName)
// Simulate testing a diff between stored asset types (config loading)
// and pair store
c.Exchanges[0].CurrencyPairs = &currency.PairsManager{
AssetTypes: asset.Items{
asset.Spot,
asset.Futures,
asset.Index,
},
}
c.Exchanges[0].CurrencyPairs.Pairs = make(map[asset.Item]*currency.PairStore)
c.Exchanges[0].CurrencyPairs.Pairs[asset.PerpetualContract] = &currency.PairStore{}
c.CheckExchangeAssetsConsistency(testFakeExchangeName)
supports, err := c.SupportsExchangeAssetType(testFakeExchangeName, asset.PerpetualContract)
if err != nil {
t.Error(err)
}
if supports {
t.Error("perpetual contract should of been removed from the pair manager")
}
}
func TestCheckPairConsistency(t *testing.T) {
cfg := GetConfig()
err := cfg.LoadConfig(ConfigTestFile)

View File

@@ -92,8 +92,8 @@ func (e *ExchangeCurrencyPairSyncer) add(c *CurrencyPairSyncAgent) {
defer e.mux.Unlock()
if e.Cfg.SyncTicker {
log.Debugf(log.SyncMgr, "%s: Added ticker sync item %v: using websocket: %v using REST: %v\n", c.Exchange, c.Pair.String(),
c.Ticker.IsUsingWebsocket, c.Ticker.IsUsingREST)
log.Debugf(log.SyncMgr, "%s: Added ticker sync item %v: using websocket: %v using REST: %v\n",
c.Exchange, FormatCurrency(c.Pair).String(), c.Ticker.IsUsingWebsocket, c.Ticker.IsUsingREST)
if atomic.LoadInt32(&e.initSyncCompleted) != 1 {
e.initSyncWG.Add(1)
createdCounter++
@@ -101,8 +101,8 @@ func (e *ExchangeCurrencyPairSyncer) add(c *CurrencyPairSyncAgent) {
}
if e.Cfg.SyncOrderbook {
log.Debugf(log.SyncMgr, "%s: Added orderbook sync item %v: using websocket: %v using REST: %v\n", c.Exchange, c.Pair.String(),
c.Orderbook.IsUsingWebsocket, c.Orderbook.IsUsingREST)
log.Debugf(log.SyncMgr, "%s: Added orderbook sync item %v: using websocket: %v using REST: %v\n",
c.Exchange, FormatCurrency(c.Pair).String(), c.Orderbook.IsUsingWebsocket, c.Orderbook.IsUsingREST)
if atomic.LoadInt32(&e.initSyncCompleted) != 1 {
e.initSyncWG.Add(1)
createdCounter++
@@ -110,8 +110,8 @@ func (e *ExchangeCurrencyPairSyncer) add(c *CurrencyPairSyncAgent) {
}
if e.Cfg.SyncTrades {
log.Debugf(log.SyncMgr, "%s: Added trade sync item %v: using websocket: %v using REST: %v\n", c.Exchange, c.Pair.String(),
c.Trade.IsUsingWebsocket, c.Trade.IsUsingREST)
log.Debugf(log.SyncMgr, "%s: Added trade sync item %v: using websocket: %v using REST: %v\n",
c.Exchange, FormatCurrency(c.Pair).String(), c.Trade.IsUsingWebsocket, c.Trade.IsUsingREST)
if atomic.LoadInt32(&e.initSyncCompleted) != 1 {
e.initSyncWG.Add(1)
createdCounter++
@@ -218,7 +218,8 @@ func (e *ExchangeCurrencyPairSyncer) update(exchangeName string, p currency.Pair
e.CurrencyPairs[x].Ticker.HaveData = true
e.CurrencyPairs[x].Ticker.IsProcessing = false
if atomic.LoadInt32(&e.initSyncCompleted) != 1 && !origHadData {
log.Debugf(log.SyncMgr, "%s ticker sync complete %v [%d/%d].\n", exchangeName, p, removedCounter, createdCounter)
log.Debugf(log.SyncMgr, "%s ticker sync complete %v [%d/%d].\n",
exchangeName, FormatCurrency(p).String(), removedCounter, createdCounter)
removedCounter++
e.initSyncWG.Done()
}
@@ -232,7 +233,8 @@ func (e *ExchangeCurrencyPairSyncer) update(exchangeName string, p currency.Pair
e.CurrencyPairs[x].Orderbook.HaveData = true
e.CurrencyPairs[x].Orderbook.IsProcessing = false
if atomic.LoadInt32(&e.initSyncCompleted) != 1 && !origHadData {
log.Debugf(log.SyncMgr, "%s orderbook sync complete %v [%d/%d].\n", exchangeName, p, removedCounter, createdCounter)
log.Debugf(log.SyncMgr, "%s orderbook sync complete %v [%d/%d].\n",
exchangeName, FormatCurrency(p).String(), removedCounter, createdCounter)
removedCounter++
e.initSyncWG.Done()
}
@@ -246,7 +248,8 @@ func (e *ExchangeCurrencyPairSyncer) update(exchangeName string, p currency.Pair
e.CurrencyPairs[x].Trade.HaveData = true
e.CurrencyPairs[x].Trade.IsProcessing = false
if atomic.LoadInt32(&e.initSyncCompleted) != 1 && !origHadData {
log.Debugf(log.SyncMgr, "%s trade sync complete %v [%d/%d].\n", exchangeName, p, removedCounter, createdCounter)
log.Debugf(log.SyncMgr, "%s trade sync complete %v [%d/%d].\n",
exchangeName, FormatCurrency(p).String(), removedCounter, createdCounter)
removedCounter++
e.initSyncWG.Done()
}
@@ -346,7 +349,7 @@ func (e *ExchangeCurrencyPairSyncer) worker() {
c.Ticker.IsUsingWebsocket = false
c.Ticker.IsUsingREST = true
log.Warnf(log.SyncMgr, "%s %s: No ticker update after 10 seconds, switching from websocket to rest\n",
c.Exchange, c.Pair.String())
c.Exchange, FormatCurrency(p).String())
e.setProcessing(c.Exchange, c.Pair, c.AssetType, SyncItemTicker, false)
}
}
@@ -374,7 +377,7 @@ func (e *ExchangeCurrencyPairSyncer) worker() {
e.mux.Unlock()
} else {
if e.Cfg.Verbose {
log.Debugf(log.OrderMgr, "%s Using recent batching cache\n", exchangeName)
log.Debugf(log.SyncMgr, "%s Using recent batching cache\n", exchangeName)
}
result, err = Bot.Exchanges[x].FetchTicker(c.Pair, c.AssetType)
}
@@ -408,7 +411,7 @@ func (e *ExchangeCurrencyPairSyncer) worker() {
c.Orderbook.IsUsingWebsocket = false
c.Orderbook.IsUsingREST = true
log.Warnf(log.SyncMgr, "%s %s: No orderbook update after 15 seconds, switching from websocket to rest\n",
c.Exchange, c.Pair.String())
c.Exchange, FormatCurrency(c.Pair).String())
e.setProcessing(c.Exchange, c.Pair, c.AssetType, SyncItemOrderbook, false)
}
}
@@ -531,10 +534,10 @@ func (e *ExchangeCurrencyPairSyncer) Start() {
}
if atomic.CompareAndSwapInt32(&e.initSyncStarted, 0, 1) {
log.Debugln(log.SyncMgr, "Exchange CurrencyPairSyncer initial sync started.")
log.Debugf(log.SyncMgr,
"Exchange CurrencyPairSyncer initial sync started. %d items to process.\n",
createdCounter)
e.initSyncStartTime = time.Now()
log.Debugln(log.SyncMgr, createdCounter)
log.Debugln(log.SyncMgr, removedCounter)
}
go func() {
@@ -542,7 +545,8 @@ func (e *ExchangeCurrencyPairSyncer) Start() {
if atomic.CompareAndSwapInt32(&e.initSyncCompleted, 0, 1) {
log.Debugf(log.SyncMgr, "Exchange CurrencyPairSyncer initial sync is complete.\n")
completedTime := time.Now()
log.Debugf(log.SyncMgr, "Exchange CurrencyPairSyncer initiial sync took %v [%v sync items].\n", completedTime.Sub(e.initSyncStartTime), createdCounter)
log.Debugf(log.SyncMgr, "Exchange CurrencyPairSyncer initiial sync took %v [%v sync items].\n",
completedTime.Sub(e.initSyncStartTime), createdCounter)
if !e.Cfg.SyncContinuously {
log.Debugln(log.SyncMgr, "Exchange CurrencyPairSyncer stopping.")

View File

@@ -207,7 +207,7 @@ func (o *OKEX) GetFuturesOrderBook(request okgroup.GetFuturesOrderBookRequest) (
// GetAllFuturesTokenInfo Get the last traded price, best bid/ask price, 24 hour trading volume and more info of all contracts.
func (o *OKEX) GetAllFuturesTokenInfo() (resp []okgroup.GetFuturesTokenInfoResponse, _ error) {
requestURL := fmt.Sprintf("%v/%v", okgroup.OKGroupInstruments, okgroup.OKGroupTicker)
return resp, o.SendHTTPRequest(http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, true)
return resp, o.SendHTTPRequest(http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, false)
}
// GetFuturesTokenInfoForCurrency Get the last traded price, best bid/ask price, 24 hour trading volume and more info of a contract.

View File

@@ -1045,7 +1045,9 @@ func TestGetAllFuturesTokenInfo(t *testing.T) {
TestSetDefaults(t)
t.Parallel()
_, err := o.GetAllFuturesTokenInfo()
testStandardErrorHandling(t, err)
if err != nil {
t.Error(err)
}
}
// TestGetAllFuturesTokenInfo API endpoint test

View File

@@ -1,5 +1,17 @@
package exchange
import "strings"
// IsSupported returns whether or not a specific exchange is supported
func IsSupported(exchangeName string) bool {
for x := range Exchanges {
if strings.EqualFold(exchangeName, Exchanges[x]) {
return true
}
}
return false
}
// Exchanges stores a list of supported exchanges
var Exchanges = []string{
"anx",

13
exchanges/support_test.go Normal file
View File

@@ -0,0 +1,13 @@
package exchange
import "testing"
func TestIsSupported(t *testing.T) {
if ok := IsSupported("BiTStaMp"); !ok {
t.Error("supported exchange should be valid")
}
if ok := IsSupported("meowexch"); ok {
t.Error("non-supported exchange should be in valid")
}
}

View File

@@ -62,9 +62,9 @@ func main() {
flag.BoolVar(&settings.EnableOpenExchangeRates, "openexchangerates", false, "overrides config and sets up foreign exchange Open Exchange Rates")
// Exchange tuning settings
flag.BoolVar(&settings.EnableExchangeAutoPairUpdates, "exchangeautopairupdates", true, "enables automatic available currency pair updates for supported exchanges")
flag.BoolVar(&settings.EnableExchangeAutoPairUpdates, "exchangeautopairupdates", false, "enables automatic available currency pair updates for supported exchanges")
flag.BoolVar(&settings.DisableExchangeAutoPairUpdates, "exchangedisableautopairupdates", false, "disables exchange auto pair updates")
flag.BoolVar(&settings.EnableExchangeWebsocketSupport, "exchangewebsocketsupport", true, "enables Websocket support for exchanges")
flag.BoolVar(&settings.EnableExchangeWebsocketSupport, "exchangewebsocketsupport", false, "enables Websocket support for exchanges")
flag.BoolVar(&settings.EnableExchangeRESTSupport, "exchangerestsupport", true, "enables REST support for exchanges")
flag.BoolVar(&settings.EnableExchangeVerbose, "exchangeverbose", false, "increases exchange logging verbosity")
flag.BoolVar(&settings.ExchangePurgeCredentials, "exchangepurgecredentials", false, "purges the stored exchange API credentials")