{"record":{"id":"893c2981f26e9c9a","repo":"QuantConnect/Lean","slug":"expected-2-subscriptions-but-found-len-subscript","errorCode":null,"errorMessage":"Expected 2 subscriptions, but found {len(subscriptions)}","messagePattern":"Expected 2 subscriptions, but found (.+?)","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"Algorithm.Python/PandasDataFrameFromMultipleTickTypeTickHistoryRegressionAlgorithm.py","lineNumber":30,"sourceCode":"# limitations under the License.\n\nfrom AlgorithmImports import *\n\n### <summary>\n### Regression algorithm for asserting that tick history that includes multiple tick types (trade, quote) is correctly converted to a pandas\n### dataframe without raising exceptions. The main exception in this case was a \"non-unique multi-index\" error due to trades adn quote ticks with\n### duplicated timestamps.\n### </summary>\nclass PandasDataFrameFromMultipleTickTypeTickHistoryRegressionAlgorithm(QCAlgorithm):\n    def initialize(self):\n        self.set_start_date(2013, 10, 8)\n        self.set_end_date(2013, 10, 8)\n\n        spy = self.add_equity(\"SPY\", Resolution.MINUTE).symbol\n\n        subscriptions = [x for x in self.subscription_manager.subscriptions if x.symbol == spy]\n        if len(subscriptions) != 2:\n            raise AssertionError(f\"Expected 2 subscriptions, but found {len(subscriptions)}\")\n\n        history = pd.DataFrame()\n        try:\n            history = self.history(Tick, spy, timedelta(days=1), Resolution.TICK)\n        except Exception as e:\n            raise AssertionError(f\"History call failed: {e}\")\n\n        if history.shape[0] == 0:\n            raise AssertionError(\"SPY tick history is empty\")\n\n        if not np.array_equal(history.columns.to_numpy(), ['askprice', 'asksize', 'bidprice', 'bidsize', 'exchange', 'lastprice', 'quantity']):\n            raise AssertionError(\"Unexpected columns in SPY tick history\")\n\n        self.quit()\n","sourceCodeStart":12,"sourceCodeEnd":45,"githubUrl":"https://github.com/QuantConnect/Lean/blob/d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892/Algorithm.Python/PandasDataFrameFromMultipleTickTypeTickHistoryRegressionAlgorithm.py#L12-L45","documentation":"Regression assertion that adding equity SPY at Resolution.MINUTE produces exactly two internal subscriptions for that symbol — one for trade ticks and one for quote ticks, which together back the Tick history request. Lean's subscription manager creates separate SubscriptionDataConfig entries per tick type. The assertion fires when the count differs from the expected two.","triggerScenarios":"After add_equity('SPY', Resolution.MINUTE), the filter [x for x in self.subscription_manager.subscriptions if x.symbol == spy] returns a count other than 2. This occurs if the default tick-type set for equities changed, if subscription config creation was deduplicated/merged, or if add_equity resolved the symbol differently (e.g. canonical or a different market).","commonSituations":"Lean contributors run the multiple-tick-type history regression after touching SubscriptionManager, SecurityManager, or the equity subscription configuration. Users hit it after upgrading Lean if the default subscription/tick configuration for equities changed (e.g. quote data no longer subscribed by default), or when they pass a different Resolution/data-normalization that yields fewer configs.","solutions":["Inspect the actual subscriptions: log each config's tick_type and resolution to see which is missing.","If quote/trade data is missing, ensure the data is requested — e.g. add_equity with the fill-forward/quote settings that produce both tick types, or check data.json/Lean defaults.","As an engine regression: verify SubscriptionManager creates one config per supported tick type for the asset and that no dedup removed one.","Confirm the symbol resolves to the expected market so the correct subscription set applies."],"exampleFix":"# before\nsubscriptions = [x for x in self.subscription_manager.subscriptions if x.symbol == spy]\nif len(subscriptions) != 2:\n    raise AssertionError(f\"Expected 2 subscriptions, but found {len(subscriptions)}\")\n\n# after (diagnostic: report which tick types exist)\nsubscriptions = [x for x in self.subscription_manager.subscriptions if x.symbol == spy]\ntypes = sorted(str(x.tick_type) for x in subscriptions)\nif len(subscriptions) != 2:\n    raise AssertionError(\n        f\"Expected 2 subscriptions, but found {len(subscriptions)}: tick_types={types}\")","handlingStrategy":"validation","validationCode":"# Inspect actual subscription tick types before asserting the count\nspy = self.add_equity('SPY', Resolution.MINUTE).symbol\nsubs = [x for x in self.subscription_manager.subscriptions if x.symbol == spy]\ntick_types = sorted(str(x.tick_type) for x in subs)\nself.log(f\"SPY subscriptions: {len(subs)} tick_types={tick_types}\")\nassert len(subs) == 2, f\"Expected 2, got {len(subs)}: {tick_types}\"","typeGuard":"def has_tick_types(subscriptions, expected):\n    \"\"\"True when the subscriptions cover the expected set of tick types.\"\"\"\n    got = {str(x.tick_type) for x in subscriptions}\n    return expected.issubset(got)","tryCatchPattern":null,"preventionTips":["Log the tick_type of each subscription config before asserting a fixed count.","After a Lean upgrade, re-check the default equity subscription/tick-type configuration.","Confirm the symbol resolves to the expected market so the right subscription set applies."],"tags":["quantconnect","lean","subscriptions","tick-data","history","regression-test","python"],"backgroundTag":null,"analyzedSha":"d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892","analyzedAt":"2026-08-13T13:52:21.013Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}