No IBKR ConID Error caused Strategy not to complete

A couple of my strategies received errors this morning and the strategy orders did not complete. I received the below error:

2025-08-11 09:33:43 quantrocket.zipline: ERROR requests.exceptions.HTTPError: ('400 Client Error: BAD REQUEST for url: http://houston/blotter/orders', {'status': 'error', 'msg': 'No IBKR ConId found for Sid FIBBG00L1KN476, is the Sid valid and did you collect the security listing from IBKR?'})

I checked in the Data Browser for the USStock-1min and the sid / symbol does exist. Does this mean IBKR does not allow trading this symbol?

The blotter periodically queries the master service for a mapping of sids to IBKR conids. This mapping lets the blotter take an order for a sid and send the corresponding conid to IBKR. The error means the blotter had no conid for this sid.

Check the securities master record and confirm the ibkr_ConId field is populated. This sid should have a conid (it does on my system), so verify it on yours. If it’s missing, collect the security from IBKR to populate it. You can then submit a manual, non-marketable order for this security to the blotter to confirm the fix without waiting for your strategy to run again.

@Brian a few things following up on this issue:

  • For sid FIBBG00L1KN476 I waited to see if the blotter would pick up and map the IBKR ConID and it has not. FWIW, my Local instance does have the ConID but my Cloud instance does not.
  • This week during my rebalance I ran into the same issue with a different security where the IBKR ConID is not showing up. The sid is FIBBG00DYNJGH9. In this case the ConID is not showing up in either my Local or Cloud instance.

If this is more than a one off how do you suggest I ensure IBKR ConIDs are being properly mapped for my entire "USStock-1min" bundle? Please advise. Thanks.

To get the ConIds into your master database, you need to collect the listings from IBKR. Pulling from the master db into the blotter is automatic, but pulling from IBKR to the master db is not. You should schedule a command like this on your crontab to run at least weekly and pick up new listings:

0 16 * * sun quantrocket ibg start --wait && quantrocket master collect-ibkr --sec-types 'STK' 'ETF' --countries 'US'

This ensures that as new stocks show up in the usstock bundle, the corresponding IBKR ConId should also be available in the master db.

1 Like

I'll give this a shot. Thank you Brian.

@Brian I've added the master db update to my crontab schedule and it appears to be working. I submitted all orders successfully during last week's rebalance but ran into issues again this week. I've received the below error message every day this week:

2025-09-11 09:40:06 quantrocket.zipline: ERROR Traceback (most recent call last):
2025-09-11 09:40:06 quantrocket.zipline: ERROR   File "sym://qrocket_qrzipline_bundles_sid_py", line 43, in real_sid_to_zipline_sid
2025-09-11 09:40:06 quantrocket.zipline: ERROR KeyError: 'FIBBG00NNN9QQ8'
2025-09-11 09:40:06 quantrocket.zipline: ERROR 
2025-09-11 09:40:06 quantrocket.zipline: ERROR During handling of the above exception, another exception occurred:
2025-09-11 09:40:06 quantrocket.zipline: ERROR 
2025-09-11 09:40:06 quantrocket.zipline: ERROR Traceback (most recent call last):
2025-09-11 09:40:06 quantrocket.zipline: ERROR   File "sym://qrocket_qrzipline_trade_trade_py", line 55, in mule_trade_algo
2025-09-11 09:40:06 quantrocket.zipline: ERROR   File "sym://qrocket_qrzipline_trade_trade_py", line 197, in trade_algo
2025-09-11 09:40:06 quantrocket.zipline: ERROR   File "/opt/conda/lib/python3.11/site-packages/zipline/algorithm.py", line 706, in run
2025-09-11 09:40:06 quantrocket.zipline: ERROR     for perf in self.get_generator():
2025-09-11 09:40:06 quantrocket.zipline: ERROR                 ^^^^^^^^^^^^^^^^^^^^
2025-09-11 09:40:06 quantrocket.zipline: ERROR   File "sym://qrocket_qrzipline_trade_algorithm_py", line 53, in get_generator
2025-09-11 09:40:06 quantrocket.zipline: ERROR   File "sym://qrocket_qrzipline_trade_execution_py", line 92, in get_new_transactions
2025-09-11 09:40:06 quantrocket.zipline: ERROR   File "sym://qrocket_qrzipline_bundles_sid_py", line 45, in real_sid_to_zipline_sid
2025-09-11 09:40:06 quantrocket.zipline: ERROR ValueError: No such sid in bundle: FIBBG00NNN9QQ8
2025-09-11 09:40:06 quantrocket.zipline: ERROR 

The interesting thing is that the sid referenced in the Error message does not match any of the securities in the Pipeline results.

Let me know your thoughts.

Thanks.

The sid in your error message (FIBBG00NNN9QQ8 ) is an old and no longer valid sid for KSPI. The correct sid for KSPI is FIBBG00L1KN476. Occasionally data providers issue new FIGIs (resulting in a new sid) due to corporate actions. This can result in two sids for what is logically a single security, and we have a process in place to merge the two sids into one when that happens.

The error message suggests that you have a historical KSPI execution in the blotter database under the old sid, but the bundle doesn't know about that sid but only about the new sid, resulting in the "No such sid in bundle" error. I have some ideas about how QuantRocket might handle this better in the next release, but for now, the best solution is to update the blotter database records for KSPI to use the new sid instead of the old sid. To do so, first set environment variables for your strategy and account in a JupyterLab Terminal. (This will allow you to run the subsequent commmands as-is.)

export ORDERREF=mystrategy
export ACCOUNT=myaccount

Next, query the records for the old sid to confirm they are there:

sqlite3 /var/lib/quantrocket/quantrocket.v2.blotter.executions.sqlite "SELECT Time, Sid, Side, Quantity, Price, OrderRef, Account FROM Execution WHERE Sid = 'FIBBG00NNN9QQ8' AND OrderRef = '$ORDERREF' AND Account = '$ACCOUNT'" 

Then, update the records to use the new sid:

sqlite3 /var/lib/quantrocket/quantrocket.v2.blotter.executions.sqlite "UPDATE Execution SET Sid = 'FIBBG00L1KN476' WHERE Sid = 'FIBBG00NNN9QQ8' AND OrderRef = '$ORDERREF' AND Account = '$ACCOUNT'" 

The next time Zipline runs, it will query your executions and see the new sid for KSPI, matching what's in the bundle.

@Brian sorry to be so pedantic but I want to make sure I do this correctly. For the below:

export ORDERREF=mystrategy
export ACCOUNT=myaccount

I assume "mystrategy" should be what I've named the actual strategy and "myaccount" should be my IBKR account #, is that correct?

Thank you.

Correct.

@Brian also, this error is showing up in multiple strategies. Should I run it in the Jupyter Lab terminal for each strategy seperately or should I list them all together (export ORDERREF=mystrategy1,mystrategy2,etc.)? Thank you.

Each one separately.

1 Like

@Brian I executed the suggested commands in the Jupyter Terminal and the first trading day after everything executed without error but then I received the same error the next trading day. Do I have to keep running these commands before each trading day?

Here is the latest error:

2025-09-19 09:43:05 quantrocket.zipline: ERROR Traceback (most recent call last):
2025-09-19 09:43:05 quantrocket.zipline: ERROR   File "sym://qrocket_qrzipline_bundles_sid_py", line 43, in real_sid_to_zipline_sid
2025-09-19 09:43:05 quantrocket.zipline: ERROR KeyError: 'FIBBG00NNN9QQ8'
2025-09-19 09:43:05 quantrocket.zipline: ERROR 
2025-09-19 09:43:05 quantrocket.zipline: ERROR During handling of the above exception, another exception occurred:
2025-09-19 09:43:05 quantrocket.zipline: ERROR 
2025-09-19 09:43:05 quantrocket.zipline: ERROR Traceback (most recent call last):
2025-09-19 09:43:06 quantrocket.zipline: ERROR   File "sym://qrocket_qrzipline_trade_trade_py", line 55, in mule_trade_algo
2025-09-19 09:43:06 quantrocket.zipline: ERROR   File "sym://qrocket_qrzipline_trade_trade_py", line 197, in trade_algo
2025-09-19 09:43:06 quantrocket.zipline: ERROR   File "/opt/conda/lib/python3.11/site-packages/zipline/algorithm.py", line 706, in run
2025-09-19 09:43:06 quantrocket.zipline: ERROR     for perf in self.get_generator():
2025-09-19 09:43:06 quantrocket.zipline: ERROR                 ^^^^^^^^^^^^^^^^^^^^
2025-09-19 09:43:06 quantrocket.zipline: ERROR   File "sym://qrocket_qrzipline_trade_algorithm_py", line 53, in get_generator
2025-09-19 09:43:06 quantrocket.zipline: ERROR   File "sym://qrocket_qrzipline_trade_execution_py", line 92, in get_new_transactions
2025-09-19 09:43:06 quantrocket.zipline: ERROR   File "sym://qrocket_qrzipline_bundles_sid_py", line 45, in real_sid_to_zipline_sid
2025-09-19 09:43:06 quantrocket.zipline: ERROR ValueError: No such sid in bundle: FIBBG00NNN9QQ8
2025-09-19 09:43:06 quantrocket.zipline: ERROR 

I've readied a patch that should handle mapping the old sid to the new sid. Please follow these steps to install it.

In your docker-compose.yml, replace this line:

    image: 'quantrocket/zipline:2.11.0'

With this line:

    image: 'quantrocket/zipline:2.11.0.patch20250919'

Then relaunch zipline (using the correct --context if you're running in the cloud):

docker compose up -d zipline

Then, update the usstock bundle, which will cause a new table of sid mappings to be pulled into the bundle. You can use this command (in a JupyterLab Terminal) to force ingest the bundle if it's already up to date (only a single sid is ingested, so it's fast):

curl -X POST 'http://houston/zipline/ingestions/usstock-1min?force=True&sids=FIBBG000BDTBL9' 

Then run your strategy and see if the issue is resolved.

@Brian the strategies ran successfully this morning after I applied the patch over the weekend. Thank you for the assistance.

@Brian the patch appears to have worked, I have not received the error since it was applied. That said, I did notice today that the strategies where I had the issue have a mismatch of listed "Positions" and "Total Holdings".

When I run the below:

from quantrocket.blotter import list_positions
positions = list_positions()
positions = pd.DataFrame(positions)

# Optional: Set pandas display options to show the entire DataFrame
pd.set_option('display.max_rows', None)  # Show all rows
pd.set_option('display.max_columns', None)  # Show all columns
pd.set_option('display.width', None)  # Adjust width to fit content

# Display the entire DataFrame
positions

It displays the 5 positions I'm holding in each strategy.

When I run the Total Holdings:

from quantrocket.blotter import download_pnl, read_pnl_csv
download_pnl("pnl.csv")
pnl = results.loc["TotalHoldings"]
pnl.tail(1)

The Total Holdings count is showing 7 so it's not matching up.

How can I clean this up?

Thanks.

The first step is you need to see exactly what the differences are. For the PNL dataframe, you should query with details=True and look at the last row of AbsExposures to see which stocks have positions. Compare that to the list of positions from list_positions. Cleanup depends on what's wrong.

@Brian I was able to confirm that the issue ties back to the same security that changed it's SID. Both the old and new SID are showing up in the TotalHoldings count but are not current positions which is causing the discrepancy. I used Grok to help me troubleshoot and below is a snippet of it's summary:

Cause of the MismatchKSPI Duplication:The extra securities in Live_Strategy_Five, Live_Strategy_Six, and Live_Strategy_Two are due to two KSPI entries (FIBBG00L1KN476 and FIBBG00NNN9QQ8) in the PNL database.
These entries appear in both AbsExposure and TotalHoldings but are not present in list_positions, indicating they are stale or erroneous entries.

Please let me know how to clean this up. Thank you.

My assumption is that your PNL shows offsetting positions in those two sids, when in fact you're flat for that security (and thus it doesn't show up in list_positions). That would explain 5 positions vs 7 total holdings. If that's not the case, the fix could be different than what I've shown below.

Assuming that's the case, you can use the earlier code to update the executions to the new sid. Then, you need to force the blotter to recalculate PNL from the executions database. You can do that by deleting a record from the LastCalculated table in the PNL database, like this:

export ORDERREF=mystrategy
export ACCOUNT=myaccount

sqlite3 /var/lib/quantrocket/quantrocket.v2.blotter.pnl.sqlite "DELETE FROM LastCalculated WHERE OrderRef = '${ORDERREF}' AND Account = '${ACCOUNT}'"  

After that, try querying PNL again.

If your strategy trades that security again, you might need to repeat these steps.

@Brian i followed the instructions and the Total Holdings have gone down from 7 to 6 for each strategy but I still only have 5 active positions for each. To be clear the strategies are NOT currently trading the problem security and the strategies only call for 5 active positions at a time. Thanks for the help and please advise.

PNL is calculated from executions, so I would query the executions for the strategy and closely scrutinize those to see what records may be the source of the unexpected position in the PNL output.