Error "An active subscription is required" when requesting securities with get_securities

Hi,
I'm having an issue with get_securities(exchanges=["NYSE"]) when trying to execute this code:

from quantrocket.license import set_license
set_license("xxxxxxxxxxxx")
from quantrocket.ibg import set_credentials
set_credentials("ibg1", username="xxxxxxxxxxx", trading_mode="paper")
from quantrocket.master import collect_ibkr_listings
collect_ibkr_listings(exchanges = ["NYSE"])
from quantrocket.master import get_securities
securities = get_securities(exchanges=["NYSE"], sec_types=["STK"])
import pandas as pd
pd.options.display.max_columns = None
pd.options.display.max_rows = None
securities.to_csv("nyse_listings.csv")
securities.head()

I'm getting this error message

---------------------------------------------------------------------------
HTTPError                                 Traceback (most recent call last)
Input In [4], in <cell line: 6>()
      4 set_credentials("ibg1", username="xxxxxxxx", trading_mode="paper")
      5 from quantrocket.master import collect_ibkr_listings
----> 6 collect_ibkr_listings(exchanges = ["NYSE"])
      7 from quantrocket.master import get_securities
      8 securities = get_securities(exchanges=["NYSE"], sec_types=["STK"])

File /opt/conda/lib/python3.9/site-packages/quantrocket/master.py:378, in collect_ibkr_listings(exchanges, sec_types, currencies, symbols, universes, sids)
    375     params["sids"] = sids
    377 response = houston.post("/master/securities/ibkr", params=params)
--> 378 houston.raise_for_status_with_json(response)
    379 return response.json()

File /opt/conda/lib/python3.9/site-packages/quantrocket/houston.py:225, in Houston.raise_for_status_with_json(response)
    223     e.json_response = {}
    224     e.args = e.args + ("please check the logs for more details",)
--> 225 raise e

File /opt/conda/lib/python3.9/site-packages/quantrocket/houston.py:217, in Houston.raise_for_status_with_json(response)
    212 """
    213 Raises 400/500 error codes, attaching a json response to the
    214 exception, if possible.
    215 """
    216 try:
--> 217     response.raise_for_status()
    218 except requests.exceptions.HTTPError as e:
    219     try:

File /opt/conda/lib/python3.9/site-packages/requests/models.py:1021, in Response.raise_for_status(self)
   1016     http_error_msg = (
   1017         f"{self.status_code} Server Error: {reason} for url: {self.url}"
   1018     )
   1020 if http_error_msg:
-> 1021     raise HTTPError(http_error_msg, response=self)

HTTPError: ('403 Client Error: FORBIDDEN for url: http://houston/master/securities/ibkr?exchanges=NYSE', {'status': 'error', 'error': 'An active subscription is required (view license details if this is unexpected, see http://qrok.it/h/lkey for help)'})

I've also tried doing the same with IBKR live account:

from quantrocket.license import set_license
set_license("xxxxxxxxxxxx")
from quantrocket.ibg import set_credentials
set_credentials("ibg1", username="xxxxxx", trading_mode="live")
from quantrocket.master import collect_ibkr_listings
collect_ibkr_listings(exchanges = ["NYSE"])
from quantrocket.master import get_securities
securities = get_securities(exchanges=["NYSE"], sec_types=["STK"])
import pandas as pd
pd.options.display.max_columns = None
pd.options.display.max_rows = None
securities.to_csv("nyse_listings.csv")
securities.head()

I've done the 2 factor authentication and the got this error:

---------------------------------------------------------------------------
HTTPError                                 Traceback (most recent call last)
Input In [6], in <cell line: 4>()
      2 set_license("xxxxxxxxxxxxxxxxxxx")
      3 from quantrocket.ibg import set_credentials
----> 4 set_credentials("ibg1", username="xxxxxxxxx", trading_mode="live")
      5 from quantrocket.master import collect_ibkr_listings
      6 collect_ibkr_listings(exchanges = ["NYSE"])

File /opt/conda/lib/python3.9/site-packages/quantrocket/ibg.py:142, in set_credentials(gateway, username, password, trading_mode)
    139     data["trading_mode"] = trading_mode
    141 response = houston.put("/{0}/credentials".format(gateway), data=data, timeout=180)
--> 142 houston.raise_for_status_with_json(response)
    143 return response.json()

File /opt/conda/lib/python3.9/site-packages/quantrocket/houston.py:225, in Houston.raise_for_status_with_json(response)
    223     e.json_response = {}
    224     e.args = e.args + ("please check the logs for more details",)
--> 225 raise e

File /opt/conda/lib/python3.9/site-packages/quantrocket/houston.py:217, in Houston.raise_for_status_with_json(response)
    212 """
    213 Raises 400/500 error codes, attaching a json response to the
    214 exception, if possible.
    215 """
    216 try:
--> 217     response.raise_for_status()
    218 except requests.exceptions.HTTPError as e:
    219     try:

File /opt/conda/lib/python3.9/site-packages/requests/models.py:1021, in Response.raise_for_status(self)
   1016     http_error_msg = (
   1017         f"{self.status_code} Server Error: {reason} for url: {self.url}"
   1018     )
   1020 if http_error_msg:
-> 1021     raise HTTPError(http_error_msg, response=self)

HTTPError: ('400 Client Error: BAD REQUEST for url: http://houston/ibg1/credentials', {'status': 'error', 'msg': 'please stop IB Gateway before setting credentials (current status is: running)'})
​

I've "NYSE (Network A/CTA) - Trader Workstation" subscription provided by Interactive Brokers. I also have subscription sharing with a paper account enabled. I've changed the username and license key with "xxxxxxxxx" before posting.

Why am I getting this error? What would be the steps to workaround/fix?

First error: This means that to collect more than the sample data, you need a paid QuantRocket license.

Second error: Make sure to read the error messages as they try to tell you what the issue is. In this case, the message is "please stop IB Gateway before setting credentials". To stop IB Gateway, see the docs.

If I ask for sample data:

from quantrocket.license import set_license
set_license("xxxxxx")
from quantrocket.ibg import set_credentials
set_credentials("ibg1", username="xxxxxxx", trading_mode="paper")
from quantrocket.master import collect_ibkr_listings
collect_ibkr_listings(exchanges = ["FREE"])
from quantrocket.master import get_securities
securities = get_securities(exchanges=["FREE"], sec_types=["STK"])
import pandas as pd
pd.options.display.max_columns = None
pd.options.display.max_rows = None
securities.to_csv("nyse_listings.csv")
securities.head()

I get:

---------------------------------------------------------------------------
HTTPError                                 Traceback (most recent call last)
File /opt/conda/lib/python3.9/site-packages/quantrocket/master.py:756, in download_master_file(filepath_or_buffer, output, exchanges, sec_types, currencies, universes, symbols, sids, exclude_universes, exclude_sids, exclude_delisted, exclude_expired, frontmonth, vendors, fields)
    755 try:
--> 756     houston.raise_for_status_with_json(response)
    757 except requests.HTTPError as e:
    758     # Raise a dedicated exception

File /opt/conda/lib/python3.9/site-packages/quantrocket/houston.py:225, in Houston.raise_for_status_with_json(response)
    224     e.args = e.args + ("please check the logs for more details",)
--> 225 raise e

File /opt/conda/lib/python3.9/site-packages/quantrocket/houston.py:217, in Houston.raise_for_status_with_json(response)
    216 try:
--> 217     response.raise_for_status()
    218 except requests.exceptions.HTTPError as e:

File /opt/conda/lib/python3.9/site-packages/requests/models.py:1021, in Response.raise_for_status(self)
   1020 if http_error_msg:
-> 1021     raise HTTPError(http_error_msg, response=self)

HTTPError: ('400 Client Error: BAD REQUEST for url: http://houston/master/securities.csv?exchanges=FREE', {'status': 'error', 'msg': 'No securities match the query parameters'})

During handling of the above exception, another exception occurred:

NoMasterData                              Traceback (most recent call last)
Input In [6], in <cell line: 8>()
      6 collect_ibkr_listings(exchanges = ["FREE"])
      7 from quantrocket.master import get_securities
----> 8 securities = get_securities(exchanges=["FREE"])
      9 import pandas as pd
     10 pd.options.display.max_columns = None

File /opt/conda/lib/python3.9/site-packages/quantrocket/master.py:891, in get_securities(symbols, exchanges, sec_types, currencies, universes, sids, exclude_universes, exclude_sids, exclude_delisted, exclude_expired, frontmonth, vendors, fields)
    888     raise ImportError("pandas must be installed to use this function")
    890 f = six.StringIO()
--> 891 download_master_file(
    892     f, exchanges=exchanges, sec_types=sec_types,
    893     currencies=currencies, universes=universes,
    894     symbols=symbols, sids=sids,
    895     exclude_universes=exclude_universes,
    896     exclude_sids=exclude_sids,
    897     exclude_delisted=exclude_delisted,
    898     exclude_expired=exclude_expired, frontmonth=frontmonth,
    899     vendors=vendors, fields=fields)
    901 securities = pd.read_csv(f, index_col="Sid")
    903 for col in securities.columns:

File /opt/conda/lib/python3.9/site-packages/quantrocket/master.py:760, in download_master_file(filepath_or_buffer, output, exchanges, sec_types, currencies, universes, symbols, sids, exclude_universes, exclude_sids, exclude_delisted, exclude_expired, frontmonth, vendors, fields)
    757 except requests.HTTPError as e:
    758     # Raise a dedicated exception
    759     if "no securities match the query parameters" in repr(e).lower():
--> 760         raise NoMasterData(e)
    761     raise
    763 filepath_or_buffer = filepath_or_buffer or sys.stdout

NoMasterData: ('400 Client Error: BAD REQUEST for url: http://houston/master/securities.csv?exchanges=FREE', {'status': 'error', 'msg': 'No securities match the query parameters'})

Am I doing something wrong?

Although you can use "FREE" to collect the sample data, the collected sample data will then be stored in the database with the real exchanges, so you can't query the "FREE" exchange. Try removing that from your query:

securities = get_securities(sec_types=["STK"])