Repository: hummingbot/hummingbot
Pull request: Feat/ndax config parameters
**Before submitting this PR, please make sure**:

- [x] Your code builds clean without any errors or warnings
- [x] You are using approved title ("feat/", "fix/", "docs/", "refactor/")

**A description of the changes proposed in the pull request**:
Added configuration parameters to establish the connection with NDAX exchange.
Also added a fix to the initialization of the account ID (it is required for the client to get the account balance even before the connector is started)

**Tests performed by the developer**
I tested the changes manually by configuring the connection with NDAX and getting the balance without issues.

Closes #3793 

Problem statement:
Add NDAX parameters and configurations to the client
Add required parameters and configuration entries to make NDAX connector available and usable from the client.

### Definition of Done

- NDAX connector is included in connectors table
- NDAX connector can be created and all its parameters specified: user id, user name, API key, API secret
- The balance from the NDAX account can be retrieved

Hints from issue discussion:

Commit message: Fix tests that create NdaxExchange instances with the old parameter names

Patch to review:
diff --git a/hummingbot/connector/exchange/ndax/ndax_exchange.py b/hummingbot/connector/exchange/ndax/ndax_exchange.py
index 6c7ac4166e1..9c85425b790 100644
--- a/hummingbot/connector/exchange/ndax/ndax_exchange.py
+++ b/hummingbot/connector/exchange/ndax/ndax_exchange.py
@@ -60,19 +60,19 @@ def logger(cls) -> HummingbotLogger:
         return cls._logger
 
     def __init__(self,
-                 uid: str,
-                 api_key: str,
-                 secret_key: str,
-                 username: str,
+                 ndax_uid: str,
+                 ndax_api_key: str,
+                 ndax_secret_key: str,
+                 ndax_username: str,
                  account_id: int = None,
                  trading_pairs: Optional[List[str]] = None,
                  trading_required: bool = True
                  ):
         """
-        :param uid: User ID of the account
-        :param api_key: The API key to connect to private NDAX APIs.
-        :param secret_key: The API secret.
-        :param username: The username of the account in use.
+        :param ndax_uid: User ID of the account
+        :param ndax_api_key: The API key to connect to private NDAX APIs.
+        :param ndax_secret_key: The API secret.
+        :param ndax_username: The username of the account in use.
         :param account_id: The account ID associated with the trading account in use.
         :param trading_pairs: The market trading pairs which to track order book data.
         :param trading_required: Whether actual trading is needed.
@@ -80,7 +80,7 @@ def __init__(self,
         super().__init__()
         self._trading_required = trading_required
         self._trading_pairs = trading_pairs
-        self._auth = NdaxAuth(uid=uid, api_key=api_key, secret_key=secret_key, username=username)
+        self._auth = NdaxAuth(uid=ndax_uid, api_key=ndax_api_key, secret_key=ndax_secret_key, username=ndax_username)
         self._order_book_tracker = NdaxOrderBookTracker(trading_pairs=trading_pairs)
         self._user_stream_tracker = NdaxUserStreamTracker(self._auth)
         self._ev_loop = asyncio.get_event_loop()
@@ -259,6 +259,11 @@ async def _update_balances(self):
         local_asset_names = set(self._account_balances.keys())
         remote_asset_names = set()
 
+        # When the balances are requested by the client to test the connection, the account id will not be
+        # initialized yet
+        if not self._account_id:
+            self._account_id = await self._get_account_id()
+
         params = {
             "OMSId": 1,
             "AccountId": self.account_id
diff --git a/hummingbot/connector/exchange/ndax/ndax_utils.py b/hummingbot/connector/exchange/ndax/ndax_utils.py
index b3c146ade96..47788982383 100644
--- a/hummingbot/connector/exchange/ndax/ndax_utils.py
+++ b/hummingbot/connector/exchange/ndax/ndax_utils.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python
+from hummingbot.client.config.config_methods import using_exchange
+from hummingbot.client.config.config_var import ConfigVar
 
 CENTRALIZED = True
 
@@ -9,5 +10,65 @@
 DEFAULT_FEES = [2, 2]
 
 
+# USE_ETHEREUM_WALLET not required because default value is false
+# FEE_TYPE not required because default value is Percentage
+# FEE_TOKEN not required because the fee is not flat
+
+
 def convert_to_exchange_trading_pair(hb_trading_pair: str) -> str:
     return hb_trading_pair.replace("-", "")
+
+
+KEYS = {
+    "ndax_username":
+        ConfigVar(key="ndax_username",
+                  prompt="Enter your NDAX user name >>> ",
+                  required_if=using_exchange("ndax"),
+                  is_secure=False,
+                  is_connect_key=True),
+    "ndax_uid":
+        ConfigVar(key="ndax_uid",
+                  prompt="Enter your NDAX user ID (uid) >>> ",
+                  required_if=using_exchange("ndax"),
+                  is_secure=False,
+                  is_connect_key=True),
+    "ndax_api_key":
+        ConfigVar(key="ndax_api_key",
+                  prompt="Enter your NDAX API key >>> ",
+                  required_if=using_exchange("ndax"),
+                  is_secure=True,
+                  is_connect_key=True),
+    "ndax_secret_key":
+        ConfigVar(key="ndax_secret_key",
+                  prompt="Enter your NDAX secret key >>> ",
+                  required_if=using_exchange("ndax"),
+                  is_secure=True,
+                  is_connect_key=True),
+}
+
+# OTHER_DOMAINS = ["ndax_testnet"]
+# OTHER_DOMAINS_PARAMETER = {"ndax_testnet": "ndax_testnet"}
+# OTHER_DOMAINS_EXAMPLE_PAIR = {"ndax_testnet": "BTC-CAD"}
+# OTHER_DOMAINS_DEFAULT_FEES = {"ndax_testnet": [2, 2]}
+# OTHER_DOMAINS_KEYS = {
+#     "ndax_testnet": {
+#         "ndax_testnet_uid":
+#             ConfigVar(key="ndax_testnet_uid",
+#                       prompt="Enter your NDAX user ID (uid) >>> ",
+#                       required_if=using_exchange("ndax"),
+#                       is_secure=False,
+#                       is_connect_key=True),
+#         "ndax_testnet_api_key":
+#             ConfigVar(key="ndax_testnet_api_key",
+#                       prompt="Enter your NDAX API key >>> ",
+#                       required_if=using_exchange("ndax"),
+#                       is_secure=True,
+#                       is_connect_key=True),
+#         "ndax_testnet_secret_key":
+#             ConfigVar(key="ndax_testnet_secret_key",
+#                       prompt="Enter your NDAX secret key >>> ",
+#                       required_if=using_exchange("ndax"),
+#                       is_secure=True,
+#                       is_connect_key=True),
+#     }
+# }
diff --git a/hummingbot/connector/exchange/probit/probit_utils.py b/hummingbot/connector/exchange/probit/probit_utils.py
index 2631e9ec414..86995364d17 100644
--- a/hummingbot/connector/exchange/probit/probit_utils.py
+++ b/hummingbot/connector/exchange/probit/probit_utils.py
@@ -75,7 +75,7 @@ def convert_diff_message_to_order_book_row(message: OrderBookMessage) -> Tuple[L
 KEYS = {
     "probit_api_key":
         ConfigVar(key="probit_api_key",
-                  prompt="Enter your ProBit Client ID >>> ",
+                  prompt="Enter your ProBit API key >>> ",
                   required_if=using_exchange("probit"),
                   is_secure=True,
                   is_connect_key=True),
@@ -95,7 +95,7 @@ def convert_diff_message_to_order_book_row(message: OrderBookMessage) -> Tuple[L
     "probit_kr": {
         "probit_kr_api_key":
             ConfigVar(key="probit_kr_api_key",
-                      prompt="Enter your ProBit KR Client ID >>> ",
+                      prompt="Enter your ProBit KR API key >>> ",
                       required_if=using_exchange("probit_kr"),
                       is_secure=True,
                       is_connect_key=True),
diff --git a/hummingbot/templates/conf_fee_overrides_TEMPLATE.yml b/hummingbot/templates/conf_fee_overrides_TEMPLATE.yml
index 04212657548..8b05474c45d 100644
--- a/hummingbot/templates/conf_fee_overrides_TEMPLATE.yml
+++ b/hummingbot/templates/conf_fee_overrides_TEMPLATE.yml
@@ -3,7 +3,7 @@
 ########################################
 
 # For more detailed information: https://docs.hummingbot.io
-template_version: 6
+template_version: 7
 
 # Exchange trading fees, the values are in percentage value, e.g. 0.1 for 0.1%.
 # If the value is left blank, the default value (from corresponding market connector) will be used.
@@ -89,3 +89,9 @@ probit_taker_fee:
 
 probit_kr_maker_fee:
 probit_kr_taker_fee:
+
+ndax_maker_fee:
+ndax_taker_fee:
+
+#ndax_testnet_maker_fee:
+#ndax_testnet_taker_fee:
diff --git a/hummingbot/templates/conf_global_TEMPLATE.yml b/hummingbot/templates/conf_global_TEMPLATE.yml
index 03126d28097..572e916946f 100644
--- a/hummingbot/templates/conf_global_TEMPLATE.yml
+++ b/hummingbot/templates/conf_global_TEMPLATE.yml
@@ -3,7 +3,7 @@
 #################################
 
 # For more detailed information: https://docs.hummingbot.io
-template_version: 22
+template_version: 23
 
 # Exchange configs
 bamboo_relay_use_coordinator: false
@@ -108,6 +108,15 @@ probit_secret_key: null
 probit_kr_api_key: null
 probit_kr_secret_key: null
 
+ndax_username: null
+ndax_uid: null
+ndax_api_key: null
+ndax_secret_key: null
+
+#ndax_testnet_user_id: null
+#ndax_testnet_api_key: null
+#ndax_testnet_secret_key: null
+
 # Ethereum wallet address: required for trading on a DEX
 ethereum_wallet: null
 ethereum_rpc_url: null
diff --git a/setup.py b/setup.py
index 01b0285f84d..4ceea22216a 100755
--- a/setup.py
+++ b/setup.py
@@ -33,7 +33,6 @@ def build_extensions(self):
 
 def main():
     cpu_count = os.cpu_count() or 8
-    version = "20210715"
     packages = [
         "hummingbot",
         "hummingbot.client",
@@ -55,27 +54,29 @@ def main():
         "hummingbot.connector.connector.terra",
         "hummingbot.connector.exchange",
         "hummingbot.connector.exchange.ascend_ex",
+        "hummingbot.connector.exchange.bamboo_relay",
+        "hummingbot.connector.exchange.beaxy",
         "hummingbot.connector.exchange.binance",
         "hummingbot.connector.exchange.bitfinex",
         "hummingbot.connector.exchange.bittrex",
-        "hummingbot.connector.exchange.bamboo_relay",
         "hummingbot.connector.exchange.coinbase_pro",
         "hummingbot.connector.exchange.coinzoom",
+        "hummingbot.connector.exchange.crypto_com",
+        "hummingbot.connector.exchange.dolomite",
         "hummingbot.connector.exchange.dydx",
+        "hummingbot.connector.exchange.eterbase",
+        "hummingbot.connector.exchange.gate_io",
+        "hummingbot.connector.exchange.hitbtc",
         "hummingbot.connector.exchange.huobi",
-        "hummingbot.connector.exchange.radar_relay",
+        "hummingbot.connector.exchange.k2",
         "hummingbot.connector.exchange.kraken",
-        "hummingbot.connector.exchange.crypto_com",
         "hummingbot.connector.exchange.kucoin",
+        "hummingbot.connector.exchange.liquid",
         "hummingbot.connector.exchange.loopring",
+        "hummingbot.connector.exchange.ndax"
         "hummingbot.connector.exchange.okex",
-        "hummingbot.connector.exchange.liquid",
-        "hummingbot.connector.exchange.dolomite",
-        "hummingbot.connector.exchange.eterbase",
-        "hummingbot.connector.exchange.beaxy",
-        "hummingbot.connector.exchange.hitbtc",
-        "hummingbot.connector.exchange.gate_io",
-        "hummingbot.connector.exchange.k2",
+        "hummingbot.connector.exchange.probit"
+        "hummingbot.connector.exchange.radar_relay",
         "hummingbot.connector.derivative",
         "hummingbot.connector.derivative.binance_perpetual",
         "hummingbot.model",
@@ -95,6 +96,7 @@ def main():
         "hummingbot.wallet.ethereum.watcher",
         "hummingbot.wallet.ethereum.zero_ex",
     ]
+    version = "20210715"
     package_data = {
         "hummingbot": [
             "core/cpp/*",
diff --git a/test/hummingbot/connector/exchange/ndax/test_ndax_exchange.py b/test/hummingbot/connector/exchange/ndax/test_ndax_exchange.py
index c205a62e859..3848d3bf45a 100644
--- a/test/hummingbot/connector/exchange/ndax/test_ndax_exchange.py
+++ b/test/hummingbot/connector/exchange/ndax/test_ndax_exchange.py
@@ -43,10 +43,10 @@ def setUp(self) -> None:
         self.resume_test_event = asyncio.Event()
         self._finalMessage = 'FinalDummyMessage'
 
-        self.exchange = NdaxExchange(uid='001',
-                                     api_key='testAPIKey',
-                                     secret_key='testSecret',
-                                     username="hbot")
+        self.exchange = NdaxExchange(ndax_uid='001',
+                                     ndax_api_key='testAPIKey',
+                                     ndax_secret_key='testSecret',
+                                     ndax_username="hbot")
 
         self.exchange.logger().setLevel(1)
         self.exchange.logger().addHandler(self)


Code review comments:
diff_hunk: @@ -75,7 +75,7 @@ def convert_diff_message_to_order_book_row(message: OrderBookMessage) -> Tuple[L
 KEYS = {
     "probit_api_key":
         ConfigVar(key="probit_api_key",
-                  prompt="Enter your ProBit Client ID >>> ",
+                  prompt="Enter your ProBit API key >>> ",
path: hummingbot/connector/exchange/probit/probit_utils.py
text: @user1:
For this, we decided to use Client ID because that's what their UI suggest it was; a ClientID-Secret key pair

@author:
Thank you for the clarification Daniel. I will revert the change.

diff_hunk: @@ -55,27 +54,29 @@ def main():
         "hummingbot.connector.connector.terra",
         "hummingbot.connector.exchange",
         "hummingbot.connector.exchange.ascend_ex",
+        "hummingbot.connector.exchange.bamboo_relay",
+        "hummingbot.connector.exchange.beaxy",
         "hummingbot.connector.exchange.binance",
         "hummingbot.connector.exchange.bitfinex",
         "hummingbot.connector.exchange.bittrex",
-        "hummingbot.connector.exchange.bamboo_relay",
         "hummingbot.connector.exchange.coinbase_pro",
         "hummingbot.connector.exchange.coinzoom",
+        "hummingbot.connector.exchange.crypto_com",
+        "hummingbot.connector.exchange.dolomite",
         "hummingbot.connector.exchange.dydx",
+        "hummingbot.connector.exchange.eterbase",
+        "hummingbot.connector.exchange.gate_io",
+        "hummingbot.connector.exchange.hitbtc",
         "hummingbot.connector.exchange.huobi",
-        "hummingbot.connector.exchange.radar_relay",
+        "hummingbot.connector.exchange.k2",
         "hummingbot.connector.exchange.kraken",
-        "hummingbot.connector.exchange.crypto_com",
         "hummingbot.connector.exchange.kucoin",
+        "hummingbot.connector.exchange.liquid",
         "hummingbot.connector.exchange.loopring",
+        "hummingbot.connector.exchange.ndax"
         "hummingbot.connector.exchange.okex",
-        "hummingbot.connector.exchange.liquid",
-        "hummingbot.connector.exchange.dolomite",
-        "hummingbot.connector.exchange.eterbase",
-        "hummingbot.connector.exchange.beaxy",
-        "hummingbot.connector.exchange.hitbtc",
-        "hummingbot.connector.exchange.gate_io",
-        "hummingbot.connector.exchange.k2",
+        "hummingbot.connector.exchange.probit"
path: setup.py
text: @user1:
You're missing a `,` at the end of the probit entry