{"id":229694,"date":"2025-08-27T10:16:46","date_gmt":"2025-08-27T14:16:46","guid":{"rendered":"https:\/\/ibkrcampus.com\/campus\/?p=229694"},"modified":"2025-08-27T10:16:42","modified_gmt":"2025-08-27T14:16:42","slug":"calculate-synthetic-nbbo-from-prop-feeds","status":"publish","type":"post","link":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/calculate-synthetic-nbbo-from-prop-feeds\/","title":{"rendered":"Calculate Synthetic NBBO from Prop Feeds"},"content":{"rendered":"\n<p><em>The article &#8220;Calculate Synthetic NBBO from Prop Feeds<\/em>&#8220;<em> was originally published on <a href=\"https:\/\/databento.com\/docs\/examples\/equities\/consolidated-bbo\">DataBento<\/a> blog.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"overview\">Overview<\/h2>\n\n\n\n<p>In this example, we will calculate a synthetic NBBO by taking the best bid and offer seen across the different exchanges. Unlike the official SIP NBBO which ignores odd lots and is calculated by CTA and UTP in their datacenters, this synthetic NBBO is derived from the direct prop feeds. Databento provides top-of-book coverage for all equity exchanges (except LTSE, which only provides &lt;0.01% of total market volume). Databento captures all equity data in the NY4 datacenter with PTP timestamps. See our&nbsp;<a href=\"https:\/\/databento.com\/docs\/architecture\/timestamping-guide\">timestamping guide<\/a>&nbsp;for more information.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"design\">Design<\/h2>\n\n\n\n<p>We&#8217;ll use the&nbsp;<a href=\"https:\/\/databento.com\/docs\/schemas-and-data-formats\/mbp-1\">MBP-1 schema<\/a>&nbsp;and download data for the different equity exchanges. Next, we&#8217;ll process the data sequentially based on&nbsp;<a href=\"https:\/\/databento.com\/docs\/standards-and-conventions\/common-fields-enums-types#ts-recv\">ts_recv<\/a>, which is the timestamp when Databento received the data from the exchange. We&#8217;ll calculate the synthetic NBBO by taking the best bid and offer across these exchanges. After that, we&#8217;ll plot this over a 100-millisecond window to take a closer look at how the synthetic NBBO reacts when price moves.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-example\">Example<\/h2>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import os\nfrom collections import defaultdict\nfrom dataclasses import dataclass, field\nfrom heapq import merge\nfrom typing import Union\nimport databento as db\nimport matplotlib.dates as mdates\nimport matplotlib.pyplot as plt\nimport pandas as pd\n\n@dataclass()\nclass PriceLevel:\n    price: float\n    size: int = 0\n    count: int = 0\n    update_time: int = 0\n\n    def __str__(self) -&gt; str:\n        return f\"{self.size:4} @ {self.price:6.2f} | {self.count:2} order(s)\"\n\n    @staticmethod\n    def _bid_sort(r) -&gt; tuple[float, int, int]:\n        return r.price, r.size, -r.update_time\n\n    @staticmethod\n    def _ask_sort(r) -&gt; tuple[float, int, int]:\n        return -r.price, r.size, -r.update_time\n\n@dataclass()\nclass MbpBook:\n    offer: Union[PriceLevel, None] = field(default=None)\n    bid: Union[PriceLevel, None] = field(default=None)\n\n    def bbo(self) -&gt; tuple[Union[PriceLevel, None], Union[PriceLevel, None]]:\n        return self.bid, self.offer\n\n    def apply(self, mbp1: db.MBP1Msg) -&gt; None:\n        level = mbp1.levels[0]\n        ts_recv = mbp1.ts_recv\n\n        if level.bid_px == db.UNDEF_PRICE:\n            self.bid = None\n        else:\n            self.bid = PriceLevel(level.pretty_bid_px, level.bid_sz, level.bid_ct, ts_recv)\n\n        if level.ask_px == db.UNDEF_PRICE:\n            self.offer = None\n        else:\n            self.offer = PriceLevel(level.pretty_ask_px, level.ask_sz, level.ask_ct, ts_recv)\n\n@dataclass()\nclass MbpMarket:\n    books: defaultdict[int, defaultdict[int, MbpBook]] = field(\n        default_factory=lambda: defaultdict(lambda: defaultdict(MbpBook)),\n    )\n\n    def get_book(self, instrument_id: int, publisher_id: int) -&gt; MbpBook:\n        return self.books[instrument_id][publisher_id]\n\n    def bbo(\n        self,\n        instrument_id: int,\n        publisher_id: int,\n    ) -&gt; tuple[Union[PriceLevel, None], Union[PriceLevel, None]]:\n        return self.books[instrument_id][publisher_id].bbo()\n\n    def aggregated_bbo(\n        self,\n        instrument_id: int,\n    ) -&gt; tuple[Union[PriceLevel, None], Union[PriceLevel, None]]:\n        \"\"\"Calculate the aggregated BBO across all venues\"\"\"\n        agg_bbo: list[Union[PriceLevel, None]] = [None, None]\n        all_bbos = list(zip(*(book.bbo() for book in self.books[instrument_id].values())))\n        for idx, reducer in ((0, max), (1, min)):\n            all_best = [b for b in all_bbos[idx] if b]\n            if all_best:\n                best_price = reducer(b.price for b in all_best)\n                best = [b for b in all_best if b.price == best_price]\n                agg_bbo[idx] = PriceLevel(\n                    price=best_price,\n                    size=sum(b.size for b in best),\n                    count=sum(b.count for b in best),\n                )\n        return tuple(agg_bbo)\n\n    def consolidated_bbo(\n        self,\n        instrument_id: int,\n    ) -&gt; tuple[Union[PriceLevel, None], Union[PriceLevel, None]]:\n        all_bids, all_offers = zip(*(book.bbo() for book in self.books[instrument_id].values()))\n\n        best_bid = max((b for b in all_bids if b), key=PriceLevel._bid_sort, default=None)\n        best_offer = max((o for o in all_offers if o), key=PriceLevel._ask_sort, default=None)\n\n        return best_bid, best_offer\n\n    def apply(self, msg: db.MBP1Msg) -&gt; None:\n        book = self.books[msg.instrument_id][msg.publisher_id]\n        book.apply(msg)\n\nif __name__ == \"__main__\":\n    equity_datasets = [\n        \"XNAS.ITCH\",  # Nasdaq\n        \"XBOS.ITCH\",  # Nasdaq BX\n        \"XPSX.ITCH\",  # Nasdaq PSX\n        \"XNYS.PILLAR\",  # NYSE\n        \"ARCX.PILLAR\",  # NYSE Arca\n        \"XASE.PILLAR\",  # NYSE American\n        \"XCHI.PILLAR\",  # NYSE Texas\n        \"XCIS.TRADESBBO\",  # NYSE National\n        \"MEMX.MEMOIR\",  # Members Exchange\n        \"EPRL.DOM\",  # MIAX Pearl\n        \"IEXG.TOPS\",  # IEX\n        \"BATS.PITCH\",  # Cboe BZX\n        \"BATY.PITCH\",  # Cboe BYX\n        \"EDGA.PITCH\",  # Cboe EDGA\n        \"EDGX.PITCH\",  # Cboe EDGX\n    ]\n\n    symbol = \"NVDA\"\n    start = pd.Timestamp(2025, 6, 17, 9, 30, tz=\"US\/Eastern\")\n    end = pd.Timestamp(2025, 6, 17, 10, 0, tz=\"US\/Eastern\")\n    schema = \"mbp-1\"\n\n    client = db.Historical(key=\"YOUR_API_KEY\")\n\n    # Get data for all datasets\n    dataset_data_dict: dict[str, db.DBNStore] = {}\n    for dataset in equity_datasets:\n        dataset_name = dataset.replace(\".\", \"-\").lower()\n        data_path = f\"{dataset_name}-{symbol}-{start.date().isoformat().replace('-', '')}.{schema}.dbn.zst\"\n        if os.path.exists(data_path):\n            data = db.DBNStore.from_file(data_path)\n        else:\n            data = client.timeseries.get_range(\n                dataset=dataset,\n                start=start,\n                end=end,\n                symbols=symbol,\n                schema=schema,\n                path=data_path,\n            )\n        dataset_data_dict[dataset] = data\n\n    # Merge all datasets into one stream sorted by ts_recv\n    data = merge(*dataset_data_dict.values(), key=lambda x: x.ts_recv)\n\n    # Iterate over the records and calculate the consolidated BBO\n    cbbo_list: list[tuple[pd.Timestamp, float, float]] = []\n    market = MbpMarket()\n    for record in data:\n        market.apply(record)\n        best_bid, best_offer = market.consolidated_bbo(record.instrument_id)\n\n        cbbo_list.append((\n            record.pretty_ts_recv,\n            best_bid.price if best_bid is not None else float(\"Nan\"),\n            best_offer.price if best_offer is not None else float(\"Nan\"),\n        ))\n\n    # Create DataFrame\n    df = pd.DataFrame(cbbo_list, columns=[\"Timestamp\", \"Bid\", \"Offer\"])\n    df = df.set_index(\"Timestamp\")\n    df[\"is_crossed\"] = df[\"Bid\"] &gt;= df[\"Offer\"]\n\n    # Now we'll plot a small slice of time when the book is crossed\n    start_time = pd.Timestamp(2025, 6, 17, 9, 56, 31, 650000, tz=\"US\/Eastern\")\n    end_time = pd.Timestamp(2025, 6, 17, 9, 56, 31, 750000, tz=\"US\/Eastern\")\n\n    df = df.loc[start_time:end_time]\n\n    fig, ax = plt.subplots(figsize=(11, 6))\n\n    # Shade periods where book is not crossed green\n    plt.fill_between(\n        df.index,\n        df[\"Bid\"],\n        df[\"Offer\"],\n        where=~df[\"is_crossed\"],\n        alpha=0.2,\n        linewidth=0,\n        color=\"green\",\n        step=\"post\",\n        label=\"Normal market\",\n    )\n\n    # Shade periods where book is crossed red\n    plt.fill_between(\n        df.index,\n        df[\"Offer\"],\n        df[\"Bid\"],\n        where=df[\"is_crossed\"],\n        alpha=0.2,\n        linewidth=0,\n        color=\"red\",\n        step=\"post\",\n        label=\"Crossed market\",\n    )\n\n    # Plot BBO lines\n    for col, color in [(\"Offer\", \"C1\"), (\"Bid\", \"C0\")]:\n        plt.hlines(\n            y=df[col][:-1],\n            xmin=df.index[:-1],\n            xmax=df.index[1:],\n            colors=color,\n            label=col,\n        )\n\n    plt.gca().xaxis.set_major_formatter(mdates.DateFormatter(\"%H:%M:%S.%f\", tz=\"US\/Eastern\"))\n    plt.ylabel(\"Price (USD)\")\n    plt.xlabel(\"Timestamp (ET)\")\n    plt.title(f\"{symbol} synthetic NBBO\")\n    plt.legend()\n    plt.tight_layout()\n    plt.show()<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-results\">Results<\/h2>\n\n\n\n<p>Notice that the synthetic NBBO may occasionally appear crossed, unlike the regulatory NBBO published by the SIPs. This is expected behavior due to two factors: first, proprietary feeds include odd lot quotations, which are excluded from SIP NBBO calculations; second, the feeds originate from different data centers, resulting in receive-time deltas. These characteristics can temporarily produce crossed markets, but they also enable the construction of a more predictive microprice.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1100\" height=\"600\" data-src=\"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2025\/08\/databento-nvda-calculate-synthetic-1100x600.png\" alt=\"Calculate Synthetic NBBO from Prop Feeds\" class=\"wp-image-229698 lazyload\" data-srcset=\"https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2025\/08\/databento-nvda-calculate-synthetic-1100x600.png 1100w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2025\/08\/databento-nvda-calculate-synthetic-700x382.png 700w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2025\/08\/databento-nvda-calculate-synthetic-300x164.png 300w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2025\/08\/databento-nvda-calculate-synthetic-768x419.png 768w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2025\/08\/databento-nvda-calculate-synthetic-1536x838.png 1536w, https:\/\/ibkrcampus.com\/campus\/wp-content\/uploads\/sites\/2\/2025\/08\/databento-nvda-calculate-synthetic-2048x1117.png 2048w\" data-sizes=\"(max-width: 1100px) 100vw, 1100px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1100px; aspect-ratio: 1100\/600;\" \/><\/figure>\n\n\n\n<p>Source: DataBento<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this example, we will calculate a synthetic NBBO by taking the best bid and offer seen across the different exchanges.<\/p>\n","protected":false},"author":186,"featured_media":229702,"comment_status":"open","ping_status":"closed","sticky":true,"template":"","format":"standard","meta":{"_acf_changed":true,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[339,343,349,338,341],"tags":[851,806,19593,4659,1224,595],"contributors-categories":[18930],"class_list":{"0":"post-229694","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-data-science","8":"category-programing-languages","9":"category-python-development","10":"category-ibkr-quant-news","11":"category-quant-development","12":"tag-algo-trading","13":"tag-data-science","14":"tag-databento-python-package","15":"tag-matplotlib","16":"tag-pandas","17":"tag-python","18":"contributors-categories-databento"},"pp_statuses_selecting_workflow":false,"pp_workflow_action":"current","pp_status_selection":"publish","acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.9 (Yoast SEO v27.8) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Calculate Synthetic NBBO from Prop Feeds | IBKR Quant<\/title>\n<meta name=\"description\" content=\"In this example, we will calculate a synthetic NBBO by taking the best bid and offer seen across the different exchanges.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.interactivebrokers.com\/campus\/wp-json\/wp\/v2\/posts\/229694\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Calculate Synthetic NBBO from Prop Feeds\" \/>\n<meta property=\"og:description\" content=\"In this example, we will calculate a synthetic NBBO by taking the best bid and offer seen across the different exchanges.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/calculate-synthetic-nbbo-from-prop-feeds\/\" \/>\n<meta property=\"og:site_name\" content=\"IBKR Campus US\" \/>\n<meta property=\"article:published_time\" content=\"2025-08-27T14:16:46+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2025\/08\/stock-market-blue-purple-charts.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1000\" \/>\n\t<meta property=\"og:image:height\" content=\"563\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Contributor Author\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Contributor Author\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"2 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\n\t    \"@context\": \"https:\\\/\\\/schema.org\",\n\t    \"@graph\": [\n\t        {\n\t            \"@type\": \"NewsArticle\",\n\t            \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/calculate-synthetic-nbbo-from-prop-feeds\\\/#article\",\n\t            \"isPartOf\": {\n\t                \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/calculate-synthetic-nbbo-from-prop-feeds\\\/\"\n\t            },\n\t            \"author\": {\n\t                \"name\": \"Contributor Author\",\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/person\\\/e823e46b42ca381080387e794318a485\"\n\t            },\n\t            \"headline\": \"Calculate Synthetic NBBO from Prop Feeds\",\n\t            \"datePublished\": \"2025-08-27T14:16:46+00:00\",\n\t            \"mainEntityOfPage\": {\n\t                \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/calculate-synthetic-nbbo-from-prop-feeds\\\/\"\n\t            },\n\t            \"wordCount\": 264,\n\t            \"commentCount\": 0,\n\t            \"publisher\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#organization\"\n\t            },\n\t            \"image\": {\n\t                \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/calculate-synthetic-nbbo-from-prop-feeds\\\/#primaryimage\"\n\t            },\n\t            \"thumbnailUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2025\\\/08\\\/stock-market-blue-purple-charts.jpg\",\n\t            \"keywords\": [\n\t                \"Algo Trading\",\n\t                \"Data Science\",\n\t                \"databento Python package\",\n\t                \"Matplotlib\",\n\t                \"Pandas\",\n\t                \"Python\"\n\t            ],\n\t            \"articleSection\": [\n\t                \"Data Science\",\n\t                \"Programming Languages\",\n\t                \"Python Development\",\n\t                \"Quant\",\n\t                \"Quant Development\"\n\t            ],\n\t            \"inLanguage\": \"en-US\",\n\t            \"potentialAction\": [\n\t                {\n\t                    \"@type\": \"CommentAction\",\n\t                    \"name\": \"Comment\",\n\t                    \"target\": [\n\t                        \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/calculate-synthetic-nbbo-from-prop-feeds\\\/#respond\"\n\t                    ]\n\t                }\n\t            ]\n\t        },\n\t        {\n\t            \"@type\": \"WebPage\",\n\t            \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/calculate-synthetic-nbbo-from-prop-feeds\\\/\",\n\t            \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/calculate-synthetic-nbbo-from-prop-feeds\\\/\",\n\t            \"name\": \"Calculate Synthetic NBBO from Prop Feeds | IBKR Campus US\",\n\t            \"isPartOf\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#website\"\n\t            },\n\t            \"primaryImageOfPage\": {\n\t                \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/calculate-synthetic-nbbo-from-prop-feeds\\\/#primaryimage\"\n\t            },\n\t            \"image\": {\n\t                \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/calculate-synthetic-nbbo-from-prop-feeds\\\/#primaryimage\"\n\t            },\n\t            \"thumbnailUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2025\\\/08\\\/stock-market-blue-purple-charts.jpg\",\n\t            \"datePublished\": \"2025-08-27T14:16:46+00:00\",\n\t            \"description\": \"In this example, we will calculate a synthetic NBBO by taking the best bid and offer seen across the different exchanges.\",\n\t            \"inLanguage\": \"en-US\",\n\t            \"potentialAction\": [\n\t                {\n\t                    \"@type\": \"ReadAction\",\n\t                    \"target\": [\n\t                        \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/calculate-synthetic-nbbo-from-prop-feeds\\\/\"\n\t                    ]\n\t                }\n\t            ]\n\t        },\n\t        {\n\t            \"@type\": \"ImageObject\",\n\t            \"inLanguage\": \"en-US\",\n\t            \"@id\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/ibkr-quant-news\\\/calculate-synthetic-nbbo-from-prop-feeds\\\/#primaryimage\",\n\t            \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2025\\\/08\\\/stock-market-blue-purple-charts.jpg\",\n\t            \"contentUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2025\\\/08\\\/stock-market-blue-purple-charts.jpg\",\n\t            \"width\": 1000,\n\t            \"height\": 563,\n\t            \"caption\": \"Stock Market Charts\"\n\t        },\n\t        {\n\t            \"@type\": \"WebSite\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#website\",\n\t            \"url\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/\",\n\t            \"name\": \"IBKR Campus US\",\n\t            \"description\": \"Financial Education from Interactive Brokers\",\n\t            \"publisher\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#organization\"\n\t            },\n\t            \"potentialAction\": [\n\t                {\n\t                    \"@type\": \"SearchAction\",\n\t                    \"target\": {\n\t                        \"@type\": \"EntryPoint\",\n\t                        \"urlTemplate\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/?s={search_term_string}\"\n\t                    },\n\t                    \"query-input\": {\n\t                        \"@type\": \"PropertyValueSpecification\",\n\t                        \"valueRequired\": true,\n\t                        \"valueName\": \"search_term_string\"\n\t                    }\n\t                }\n\t            ],\n\t            \"inLanguage\": \"en-US\"\n\t        },\n\t        {\n\t            \"@type\": \"Organization\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#organization\",\n\t            \"name\": \"Interactive Brokers\",\n\t            \"alternateName\": \"IBKR\",\n\t            \"url\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/\",\n\t            \"logo\": {\n\t                \"@type\": \"ImageObject\",\n\t                \"inLanguage\": \"en-US\",\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/logo\\\/image\\\/\",\n\t                \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/05\\\/ibkr-campus-logo.jpg\",\n\t                \"contentUrl\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/05\\\/ibkr-campus-logo.jpg\",\n\t                \"width\": 669,\n\t                \"height\": 669,\n\t                \"caption\": \"Interactive Brokers\"\n\t            },\n\t            \"image\": {\n\t                \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/logo\\\/image\\\/\"\n\t            },\n\t            \"publishingPrinciples\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/about-ibkr-campus\\\/\",\n\t            \"ethicsPolicy\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/cyber-security-notice\\\/\"\n\t        },\n\t        {\n\t            \"@type\": \"Person\",\n\t            \"@id\": \"https:\\\/\\\/ibkrcampus.com\\\/campus\\\/#\\\/schema\\\/person\\\/e823e46b42ca381080387e794318a485\",\n\t            \"name\": \"Contributor Author\",\n\t            \"url\": \"https:\\\/\\\/www.interactivebrokers.com\\\/campus\\\/author\\\/contributor-author\\\/\"\n\t        }\n\t    ]\n\t}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Calculate Synthetic NBBO from Prop Feeds | IBKR Quant","description":"In this example, we will calculate a synthetic NBBO by taking the best bid and offer seen across the different exchanges.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.interactivebrokers.com\/campus\/wp-json\/wp\/v2\/posts\/229694\/","og_locale":"en_US","og_type":"article","og_title":"Calculate Synthetic NBBO from Prop Feeds","og_description":"In this example, we will calculate a synthetic NBBO by taking the best bid and offer seen across the different exchanges.","og_url":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/calculate-synthetic-nbbo-from-prop-feeds\/","og_site_name":"IBKR Campus US","article_published_time":"2025-08-27T14:16:46+00:00","og_image":[{"width":1000,"height":563,"url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2025\/08\/stock-market-blue-purple-charts.jpg","type":"image\/jpeg"}],"author":"Contributor Author","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Contributor Author","Est. reading time":"2 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/calculate-synthetic-nbbo-from-prop-feeds\/#article","isPartOf":{"@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/calculate-synthetic-nbbo-from-prop-feeds\/"},"author":{"name":"Contributor Author","@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/person\/e823e46b42ca381080387e794318a485"},"headline":"Calculate Synthetic NBBO from Prop Feeds","datePublished":"2025-08-27T14:16:46+00:00","mainEntityOfPage":{"@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/calculate-synthetic-nbbo-from-prop-feeds\/"},"wordCount":264,"commentCount":0,"publisher":{"@id":"https:\/\/ibkrcampus.com\/campus\/#organization"},"image":{"@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/calculate-synthetic-nbbo-from-prop-feeds\/#primaryimage"},"thumbnailUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2025\/08\/stock-market-blue-purple-charts.jpg","keywords":["Algo Trading","Data Science","databento Python package","Matplotlib","Pandas","Python"],"articleSection":["Data Science","Programming Languages","Python Development","Quant","Quant Development"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/calculate-synthetic-nbbo-from-prop-feeds\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/calculate-synthetic-nbbo-from-prop-feeds\/","url":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/calculate-synthetic-nbbo-from-prop-feeds\/","name":"Calculate Synthetic NBBO from Prop Feeds | IBKR Campus US","isPartOf":{"@id":"https:\/\/ibkrcampus.com\/campus\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/calculate-synthetic-nbbo-from-prop-feeds\/#primaryimage"},"image":{"@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/calculate-synthetic-nbbo-from-prop-feeds\/#primaryimage"},"thumbnailUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2025\/08\/stock-market-blue-purple-charts.jpg","datePublished":"2025-08-27T14:16:46+00:00","description":"In this example, we will calculate a synthetic NBBO by taking the best bid and offer seen across the different exchanges.","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/calculate-synthetic-nbbo-from-prop-feeds\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.interactivebrokers.com\/campus\/ibkr-quant-news\/calculate-synthetic-nbbo-from-prop-feeds\/#primaryimage","url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2025\/08\/stock-market-blue-purple-charts.jpg","contentUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2025\/08\/stock-market-blue-purple-charts.jpg","width":1000,"height":563,"caption":"Stock Market Charts"},{"@type":"WebSite","@id":"https:\/\/ibkrcampus.com\/campus\/#website","url":"https:\/\/ibkrcampus.com\/campus\/","name":"IBKR Campus US","description":"Financial Education from Interactive Brokers","publisher":{"@id":"https:\/\/ibkrcampus.com\/campus\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/ibkrcampus.com\/campus\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/ibkrcampus.com\/campus\/#organization","name":"Interactive Brokers","alternateName":"IBKR","url":"https:\/\/ibkrcampus.com\/campus\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/logo\/image\/","url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/05\/ibkr-campus-logo.jpg","contentUrl":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2024\/05\/ibkr-campus-logo.jpg","width":669,"height":669,"caption":"Interactive Brokers"},"image":{"@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/logo\/image\/"},"publishingPrinciples":"https:\/\/www.interactivebrokers.com\/campus\/about-ibkr-campus\/","ethicsPolicy":"https:\/\/www.interactivebrokers.com\/campus\/cyber-security-notice\/"},{"@type":"Person","@id":"https:\/\/ibkrcampus.com\/campus\/#\/schema\/person\/e823e46b42ca381080387e794318a485","name":"Contributor Author","url":"https:\/\/www.interactivebrokers.com\/campus\/author\/contributor-author\/"}]}},"jetpack_featured_media_url":"https:\/\/www.interactivebrokers.com\/campus\/wp-content\/uploads\/sites\/2\/2025\/08\/stock-market-blue-purple-charts.jpg","_links":{"self":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/posts\/229694","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/users\/186"}],"replies":[{"embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/comments?post=229694"}],"version-history":[{"count":0,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/posts\/229694\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/media\/229702"}],"wp:attachment":[{"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/media?parent=229694"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/categories?post=229694"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/tags?post=229694"},{"taxonomy":"contributors-categories","embeddable":true,"href":"https:\/\/ibkrcampus.com\/campus\/wp-json\/wp\/v2\/contributors-categories?post=229694"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}