<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Databento on Medium]]></title>
        <description><![CDATA[Stories by Databento on Medium]]></description>
        <link>https://medium.com/@databento?source=rss-0d024ea0f900------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*s7KzqPJQVwga2CQX7t5naA.jpeg</url>
            <title>Stories by Databento on Medium</title>
            <link>https://medium.com/@databento?source=rss-0d024ea0f900------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 00:54:40 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@databento/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Where should I colocate to trade on CME?]]></title>
            <link>https://databento.medium.com/where-should-i-colocate-to-trade-on-cme-708bdaf6a034?source=rss-0d024ea0f900------2</link>
            <guid isPermaLink="false">https://medium.com/p/708bdaf6a034</guid>
            <category><![CDATA[algorithmic-trading]]></category>
            <category><![CDATA[quantitative-finance]]></category>
            <category><![CDATA[futures-trading]]></category>
            <category><![CDATA[market-microstructure]]></category>
            <dc:creator><![CDATA[Databento]]></dc:creator>
            <pubDate>Fri, 19 Dec 2025 21:10:20 GMT</pubDate>
            <atom:updated>2025-12-19T21:10:58.667Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*msDqv5ZqLDvOjdqaHCH0zg.png" /></figure><p>The primary <a href="https://databento.com/blog/matching-engines-guide">matching engine</a> for CME Group’s futures and options markets is housed in CyrusOne Aurora I, a purpose-built data center for the CME Globex electronic trading platform. The facility is located at: <strong>2905 Diehl Road, Aurora, IL 60502</strong>.</p><p>Some vendors market “Chicago-based access” to CME without specifying the exact facility. Because facilities outside Aurora are significantly cheaper, this is sometimes used to obscure material performance tradeoffs when the vendor is not situated in the Aurora primary colocation facility.</p><p>When evaluating your vendor and colocation options, it’s important to confirm the specific data center and network path.</p><h3>CyrusOne Aurora I (CHI1)</h3><h4>Pros</h4><ul><li>Primary colocation site.</li><li>Fastest possible access to CME matching engine, highest determinism and timestamp accuracy.</li><li>Direct cross-connects to most institutional vendors offering CME data and execution services, such as Databento.</li></ul><h4>Cons</h4><ul><li>High cost (rack pricing often in the five-figure per month range).</li><li>CyrusOne typically requires larger footprints (e.g., multiple cabinets) for a a direct colocation agreement, so resellers and <a href="https://databento.com/microstructure/managed-services-provider">MSPs</a> are common for firms needing only a few servers or a single rack.</li><li>Fewer, more expensive, WAN network carrier options.</li></ul><h3>CyrusOne Aurora II and III (CHI2 and CHI3)</h3><h4>Pros</h4><ul><li>Lower cost than Aurora I.</li><li>Next highest determinism and timestamp accuracy after Aurora I.</li><li>Next lowest latency after Aurora I (on same campus).</li></ul><h4>Cons</h4><ul><li>Similar downsides as Aurora I.</li></ul><h3>350 E Cermak (Equinix CH1/4/5)</h3><h4>Pros</h4><ul><li>Major Internet and cloud interconnection hub.</li><li>Easier carrier access.</li><li>Relatively diverse selection of vendors.</li><li>Proximity to public cloud (e.g., AWS, Google) on-ramps.</li></ul><h4>Cons</h4><ul><li>Higher latency (at least 287 microseconds one-way on fiber) and less timestamp determinism than AUR1.</li></ul><h3>Other regional sites</h3><p>Some examples include CoreSite CH1, Databank ORD1, Databank ORD2, Digital Realty ORD11, and Equinix CH7 Westmont.</p><h4>Pros</h4><ul><li>Lower cost.</li></ul><h4>Cons</h4><ul><li>Not appropriate for latency-critical trading.</li><li>Increased jitter and latency.</li><li>Poor options for connecting to other services.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=708bdaf6a034" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Major CME microstructure changes that could be distorting your backtest — in 3 minutes]]></title>
            <link>https://databento.medium.com/major-cme-microstructure-changes-that-could-be-distorting-your-backtest-in-3-minutes-fd3bf564f610?source=rss-0d024ea0f900------2</link>
            <guid isPermaLink="false">https://medium.com/p/fd3bf564f610</guid>
            <category><![CDATA[futures-trading]]></category>
            <category><![CDATA[backtesting]]></category>
            <category><![CDATA[algotrading]]></category>
            <category><![CDATA[trading]]></category>
            <category><![CDATA[quant]]></category>
            <dc:creator><![CDATA[Databento]]></dc:creator>
            <pubDate>Mon, 02 Jun 2025 07:14:34 GMT</pubDate>
            <atom:updated>2025-06-02T07:14:34.783Z</atom:updated>
            <content:encoded><![CDATA[<h3>Major CME microstructure changes that could be distorting your backtest — in 3 minutes</h3><p>Changes in market microstructure, like updates to trading rules, matching engine behavior, or the wire protocol, can also affect your strategy’s performance.</p><p>These changes are especially relevant to intraday strategies and are often overlooked. It’s also easy to lose track of when these changes happened you’re backtesting over many years.</p><p>To help, we’ve put together a <strong>cheatsheet of major CME Globex microstructure changes</strong> to guide your use of Databento’s historical futures tick data — which spans back to 2010.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*5jrCqIQfPE5AN4CB" /></figure><h3>About Databento</h3><p>Databento is a licensed provider of market data and APIs for over 50 trading venues, including major futures venues like CME, CBOT, NYMEX, COMEX, ICE, EEX, and Eurex. We help firms of all sizes access market data more easily. Our coverage includes high-precision market data at tick-by-tick, L2, and L3 granularity going back to 2010.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fd3bf564f610" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to build a blazing fast real-time stock screener with Python and Databento]]></title>
            <link>https://databento.medium.com/how-to-build-a-blazing-fast-real-time-stock-screener-with-python-and-databento-0b1e76c4e2c1?source=rss-0d024ea0f900------2</link>
            <guid isPermaLink="false">https://medium.com/p/0b1e76c4e2c1</guid>
            <category><![CDATA[stocks]]></category>
            <category><![CDATA[etf]]></category>
            <category><![CDATA[stock-market]]></category>
            <category><![CDATA[algorithmic-trading]]></category>
            <category><![CDATA[trading]]></category>
            <dc:creator><![CDATA[Databento]]></dc:creator>
            <pubDate>Mon, 28 Apr 2025 12:26:33 GMT</pubDate>
            <atom:updated>2025-04-29T23:24:27.994Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hxiJtoYHX95iLWsphFbuMQ.png" /></figure><p>This tutorial shows you how to build a real-time <strong>stock screener</strong> (or <strong>scanner</strong>) that constantly analyzes a streaming real-time market data feed for changes on all U.S. equities—over 9,000 NMS stocks and ETFs.</p><p>At the end of this tutorial, you’ll be able to get output timestamped to the nanosecond like this:</p><pre>[2025-04-23T04:00:01.688717194-04:00] NVDA moved by 4.40% (current: 98.1900, previous: 102.7100)<br>[2025-04-23T04:00:02.121450448-04:00] BABA moved by 10.34% (current: 131.2750, previous: 118.9700)<br>[2025-04-23T06:36:23.507827237-04:00] AMZN moved by 7.36% (current: 193.8850, previous: 180.6000)</pre><p>You can also skip ahead to get the entire code on GitHub <a href="https://gist.github.com/databento-bot/67b8c023134e021e425501bc8f25ee9e">here</a>.</p><h3>What’s wrong with existing stock screener tools?</h3><p>A major challenge with implementing a stock scanner is that it needs to listen to all tickers on the market. Very few market data feeds are able to stream real-time prices continuously for all ~9,000 U.S. equity tickers, especially as a WAN-shaped feed over internet.</p><p>Many retail companies provide this as a commercial service, but they usually focus on retail trading use cases and don’t give you much programmatic customization over the alerts to trigger on. They also don’t provide very strong guarantees on delivery or timestamping accuracy.</p><p>Another problem is that most retail tools are bad at handling pre-market prices before the 9:30 AM open.</p><figure><img alt="Tesla, Inc. (TSLA) stock prices from Google Finance" src="https://cdn-images-1.medium.com/max/1024/1*1pJrWvA_PXmvf-zjlUbxHw.png" /><figcaption>Tesla, Inc. (TSLA) stock prices from Google Finance — pre-market moves are not shown and it’s hard to compare to the previous day.</figcaption></figure><h3>Stock screener example</h3><p>Our stock screener should:</p><ul><li>Handle the entire U.S. equities universe of ~9,000 symbols efficiently.</li><li>Have median sub-ms feed delay to NY4/5 (WAN-shaped).</li><li>Take less than 5 seconds to fetch historical data, subscribe, and start scanning.</li><li>Monitor all US stocks and ETFs for price movements exceeding a configurable threshold.</li><li>Compares current prices against previous day’s closing prices.</li><li>Displays alerts when significant moves are detected.</li></ul><h4>State management</h4><p>First, we’ll write a class to hold all of the state for this stock screener.</p><p>We need a few constants:</p><ul><li>PX_SCALE is used to express prices in decimal units. By default, Databento uses a fixed integer representation of decimal prices to avoid loss of precision, and each unit represents 1 “nanodollar” or 1e-9 of a dollar.</li><li>PX_NULL is used to handle null prices. This happens when one side of the book is empty—which happens more frequently than you might expect during pre-market hours or on illiquid stocks that you’ll encounter when consuming the entire universe of US stocks and ETFs.</li><li>PCT_MOVE_THRESHOLD will be our arbitrary threshold for triggering an alert. In this case, we’ll write a simple alert on whenever a stock moves 3% or more in either direction.</li></ul><p>Also, we’ll create 3 dictionaries so we can look up each symbol:</p><ul><li>self.symbol_directory will track the numeric instrument ID of the symbol, which raw exchange feeds like Nasdaq Basic change daily.</li><li>self.last_day_lookup will look up the last closing price of the ticker.</li><li>self.is_signal_lit helps us indicate if an alert has already fired for the ticker, so we only print once when the threshold is first exceeded.</li></ul><pre>from datetime import datetime, timedelta<br>from typing import Dict, Any<br><br>import databento as db<br>import pandas as pd<br>import pytz<br><br><br>class PriceMovementScanner:<br>    &quot;&quot;&quot;Scanner for detecting large price movements in all US equities.&quot;&quot;&quot;<br><br>    # Constants<br>    PX_SCALE: float = 1e-9<br>    PX_NULL: int = 2**63 - 1<br>    PCT_MOVE_THRESHOLD: float = 0.03<br><br>    def __init__(self, pct_threshold: float = None, today: str = TODAY) -&gt; None:<br>        &quot;&quot;&quot;Initialize scanner with configurable threshold and date.&quot;&quot;&quot;<br>        self.pct_threshold = pct_threshold or self.PCT_MOVE_THRESHOLD<br>        self.today = today<br>        self.today_midnight_ns = int(pd.Timestamp(today).timestamp() * 1e9)<br>        self.symbol_directory: Dict[int, str] = {}<br>        self.last_day_lookup: Dict[str, float] = self.get_last_day_lookup()<br>        self.is_signal_lit: Dict[str, bool] = {symbol: False for symbol in self.last_day_lookup}</pre><h4>Getting previous day’s stock and ETF prices</h4><p>We’ll add a class method for populating self.last_day_lookup using Databento’s historical client. Let’s understand what this is doing:</p><ul><li>dataset=&quot;EQUS.SUMMARY&quot; — This uses the <a href="https://databento.com/catalog/us-equities#EQUS.SUMMARY">Databento US Equities Summary</a> feed, which gives consolidated end-of-day prices (OHLCVs) across all NMS exchange and ATSs. This is designed to maximize CTA/UTP SIP coverage without license fees and provides official prices and volumes that are suited for daily EOD use.</li><li>schema=&quot;ohlcv-1d&quot; — This fetches daily <a href="https://databento.com/docs/schemas-and-data-formats/ohlcv?historical=python&amp;live=python&amp;reference=python">OHLCV aggregates</a>.</li><li>symbols=&quot;ALL_SYMBOLS&quot; — This fetches all ticker symbols on the dataset.</li></ul><pre>    def get_last_day_lookup(self) -&gt; Dict[str, float]:<br>        &quot;&quot;&quot;Get yesterday&#39;s closing prices for all symbols.&quot;&quot;&quot;<br>        client = db.Historical()<br><br>        now = pd.Timestamp(self.today).date()<br>        yesterday = (pd.Timestamp(self.today) - timedelta(days=1)).date()<br><br>        # Get yesterday&#39;s closing prices<br>        data = client.timeseries.get_range(<br>            dataset=&quot;EQUS.SUMMARY&quot;,<br>            schema=&quot;ohlcv-1d&quot;,<br>            symbols=&quot;ALL_SYMBOLS&quot;,<br>            start=yesterday,<br>            end=now,<br>        )<br><br>        # Request symbology: This is required for ALL_SYMBOLS requests<br>        # which don&#39;t automatically map instrument ID to raw ticker symbol<br>        symbology_json = data.request_symbology(client)<br>        data.insert_symbology_json(symbology_json, clear_existing=True)<br><br>        df = data.to_df()<br>        # TODO: Adjust for overnight splits here, e.g., using Databento corporate actions API<br><br>        return dict(zip(df[&quot;symbol&quot;], df[&quot;close&quot;]))</pre><p>As seen in the inline comment, a more complete implementation will use <a href="https://databento.com/corporate-actions">corporate actions data</a> to adjust the closing prices for overnight splits. This method is flexible for you to integrate other major events or fundamentals like dividends, market cap, EPS and P/E ratio updates.</p><p>You may also want to start screening only after the book has stabilized after the pre-market, either by using trade prices instead of mid-price, requiring the spread to reach a certain number of bps, or after a certain fixed time.</p><h4>Adding scanning and alerting</h4><p>First, this populates the symbol directory for symbol mapping messages, which are received initially when you subscribe to a real-time feed on Databento.</p><p>Then, we compute the midprice on each MBP-1 message (top of book update), and compare that against the closing price of the previous day.</p><pre>    def scan(self, event: Any) -&gt; None:<br>        &quot;&quot;&quot;<br>        Scan for large price movements in market data events.<br>        &quot;&quot;&quot;<br>        if isinstance(event, db.SymbolMappingMsg):<br>            self.symbol_directory[event.hd.instrument_id] = event.stype_out_symbol<br>            return<br><br>        if not isinstance(event, db.MBP1Msg):<br>            return<br>            <br>        # Skip if event is from replay before today using `.subscribe(..., start=...)` parameter<br>        #if event.hd.ts_event &lt; self.today_midnight_ns:<br>        #    return<br><br>        symbol = self.symbol_directory[event.instrument_id]<br>        bid = event.levels[0].bid_px<br>        ask = event.levels[0].ask_px<br><br>        if bid == self.PX_NULL or ask == self.PX_NULL:<br>            # Handle when one side of book is empty<br>            return<br><br>        mid = (event.levels[0].bid_px + event.levels[0].ask_px) * self.PX_SCALE * 0.5<br>        last = self.last_day_lookup[symbol]<br>        abs_r = abs(mid - last) / last<br><br>        if abs_r &gt; self.pct_threshold and not self.is_signal_lit[symbol]:<br>            ts = pd.Timestamp(event.hd.ts_event, unit=&#39;ns&#39;).tz_localize(&#39;UTC&#39;).tz_convert(&#39;US/Eastern&#39;)<br>            print(<br>                f&quot;[{ts.isoformat()}] {symbol} moved by {abs_r * 100:.2f}% &quot;<br>                f&quot;(current: {mid:.4f}, previous: {last:.4f})&quot;<br>            )<br>            self.is_signal_lit[symbol] = True</pre><h4>Running your stock screener</h4><p>Now, we just need to run the code. Observe our use of these parameters:</p><ul><li>dataset=&quot;EQUS.MINI&quot; — This uses the <a href="https://databento.com/catalog/us-equities#EQUS.MINI">Databento Equities Mini</a> feed, a cost-effective consolidated feed. You can also modify this code to scan all <a href="https://databento.com/options">options</a> or <a href="https://databento.com/futures">futures</a> by swapping this dataset ID.</li><li>schema=&quot;mbp-1&quot; — <a href="https://databento.com/docs/schemas-and-data-formats/mbp-1">MBP-1</a> provides every order book event that updates the best bid or offer (BBO), and includes every trade and changes to book depth, alongside total size and order count at BBO.</li><li>symbols=&quot;ALL_SYMBOLS&quot; — This instructs the client to subscribe to every symbol on the feed. If you only have specific tickers on your watchlist, you can also specify them here, like [&quot;AMZN&quot;, &quot;AAPL&quot;, &quot;GOOG&quot;, &quot;MSFT&quot;, &quot;NVDA&quot;] for Amazon, Apple, Google, Microsoft, and NVIDIA. By default, Databento uses Nasdaq symbology for U.S. stocks.</li><li>start=0 — <a href="https://databento.com/docs/api-reference-live/basics/intraday-replay">Intraday replay</a> is helpful for debugging this example outside of market hours.</li></ul><pre>def main() -&gt; None:<br>    scanner = PriceMovementScanner()<br>    live = db.Live()<br><br>    live.subscribe(<br>        dataset=&quot;EQUS.MINI&quot;,<br>        schema=&quot;mbp-1&quot;,<br>        symbols=&quot;ALL_SYMBOLS&quot;,<br>        start=0,<br>    )<br><br>    live.add_callback(scanner.scan)<br>    live.start()<br>    live.block_for_close()<br><br><br>if __name__ == &quot;__main__&quot;:<br>    main()</pre><h3>Results</h3><pre>[2025-04-24T04:00:00.007704938-04:00] TSLA moved by 5.43% (current: 245.4300, previous: 259.5100)<br>[2025-04-24T04:00:00.008339140-04:00] TQQQ moved by 11.78% (current: 46.0000, previous: 52.1400)<br>[2025-04-24T04:00:00.009881258-04:00] DBC moved by 5.84% (current: 22.5650, previous: 21.3200)<br>[2025-04-24T04:00:00.011338853-04:00] DBA moved by 4.81% (current: 25.9400, previous: 27.2500)<br>[2025-04-24T04:00:00.019717308-04:00] WEAT moved by 3.35% (current: 4.4650, previous: 4.6200)<br>[2025-04-24T04:00:00.048734686-04:00] RSST moved by 4.37% (current: 19.5950, previous: 20.4900)<br>[2025-04-24T04:00:00.052540506-04:00] BCI moved by 17.21% (current: 24.3800, previous: 20.8000)<br>[2025-04-24T04:00:00.111035469-04:00] SOYB moved by 4.26% (current: 22.8100, previous: 21.8777)<br>[2025-04-24T04:00:00.158550097-04:00] FTGC moved by 3.49% (current: 25.6250, previous: 24.7600)<br>[2025-04-24T04:00:00.158736420-04:00] CMDY moved by 3.03% (current: 51.7200, previous: 50.2000)</pre><p>You can see that our screener was able to pick up the pre-market move on Tesla, Inc. (TSLA) exactly 7.7 milliseconds after 4 AM EDT, much before the first piece published on Bloomberg News on that day at 5:30 AM EDT.</p><figure><img alt="Tesla, Inc. (TSLA) news on Bloomberg News" src="https://cdn-images-1.medium.com/max/1024/1*sv447bBOKSaTBhld8kXVKg.png" /></figure><figure><img alt="First news piece on Tesla, Inc. (TSLA) on Bloomberg News, April 24, 2025." src="https://cdn-images-1.medium.com/max/1024/1*A3sq99YkpYI02vOZbcZQdA.png" /></figure><h3>Full code</h3><p>You can get the full script for this example on GitHub <a href="https://gist.github.com/databento-bot/67b8c023134e021e425501bc8f25ee9e">here</a>.</p><p>If you’re interested instead in scanning stocks on <em>historical data </em>only, see our docs for an example on <a href="https://databento.com/docs/examples/equities/equities-premarket-movers?historical=python&amp;live=python&amp;reference=python">finding the top pre-market movers</a>.</p><p>Or <a href="https://databento.com/equities">learn more</a> about Databento U.S. equities coverage, which spans over 20,000+ stocks and ETFs since inception across all U.S. exchanges and ATSs. We’re an official distributor for all major proprietary feeds like Nasdaq TotalView, NYSE Integrated, NYSE Arca Integrated, and more.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0b1e76c4e2c1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Differences between US stock exchanges: April 2025]]></title>
            <link>https://databento.medium.com/differences-between-us-stock-exchanges-april-2025-d8c30697200a?source=rss-0d024ea0f900------2</link>
            <guid isPermaLink="false">https://medium.com/p/d8c30697200a</guid>
            <category><![CDATA[market-data]]></category>
            <category><![CDATA[hft]]></category>
            <category><![CDATA[trading]]></category>
            <category><![CDATA[quant]]></category>
            <category><![CDATA[stock-market]]></category>
            <dc:creator><![CDATA[Databento]]></dc:creator>
            <pubDate>Tue, 01 Apr 2025 23:28:10 GMT</pubDate>
            <atom:updated>2025-04-01T23:51:35.171Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bPrkZNsZh8d8nAOe9CfZxg.png" /></figure><p>Since US equities are fungible across exchanges, does it really matter where you trade? Our latest cheatsheet explores some of the key differences between the NMS exchanges, including:</p><ul><li><strong>Primary listing venues. </strong>These are important for IPOs.</li><li><strong>Venues with auction imbalance data.</strong> These are critical for strategies like index rebalancing.</li><li><strong>Maker-taker vs. taker-maker pricing models. </strong>These offer different ways to achieve effective execution prices that bypass the <a href="https://databento.com/microstructure/sub-penny-rule">sub-penny rule</a>.</li><li><strong>Retail price improvement programs.</strong> These are designed to attract retail order flow.</li><li><strong>Extended pre-market and post-market trading sessions.</strong></li><li><strong>Primary colocation site. </strong>These determine costs and infrastructure requirements for connecting to the venue.</li></ul><p>Correction: Cboe EDGA <a href="https://cdn.cboe.com/resources/release_notes/2024/Cboe-EDGA-Equities-Moves-to-Maker-Taker-Fee-Model.pdf">switched to a maker-taker fee model</a> in November 2024. This will be fixed in future updates of this cheatsheet.</p><h3>About Databento</h3><p>Interested to learn more? Check out Databento’s <a href="https://databento.com/microstructure">microstructure guide</a> and <a href="https://databento.com/blog">blog</a>.</p><p><a href="https://databento.com/">Databento</a> provides next-gen market data APIs built for speed and scale, helping firms of all sizes power their trading strategies and analytics. As an official distributor for 70+ exchanges, we deliver high-precision futures, options, and equities data directly from exchange colocation sites — offering both flexible pay-as-you-go and subscription pricing.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d8c30697200a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Getting queue position with L2 and order book data from Databento]]></title>
            <link>https://databento.medium.com/getting-queue-position-with-l2-and-order-book-data-from-databento-d3f8039b2515?source=rss-0d024ea0f900------2</link>
            <guid isPermaLink="false">https://medium.com/p/d3f8039b2515</guid>
            <category><![CDATA[market-data]]></category>
            <category><![CDATA[quant]]></category>
            <category><![CDATA[trading]]></category>
            <category><![CDATA[order-book]]></category>
            <category><![CDATA[futures-trading]]></category>
            <dc:creator><![CDATA[Databento]]></dc:creator>
            <pubDate>Mon, 03 Mar 2025 22:37:26 GMT</pubDate>
            <atom:updated>2025-03-03T22:37:59.813Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jqShJwF2KcXhFRyfdp6PDg.png" /></figure><p>In the <a href="https://databento.com/docs/examples/order-book/queue-position">latest API tutorial</a> added to <a href="http://databento.com/">Databento</a>’s docs, we show how you can track the exact queue position of an order with MBO data. This is compared against the estimated queue position from L2 (MBP) data only.</p><h3>Estimating queue position from L2 data</h3><p>Without MBO data, a common approach to estimate queue position is to define a parametric model for cancellations and update your estimated position each time the aggregate market depth at the price is reduced.</p><p>Suppose p(𝑥) denotes the probability of cancel in front of you when your order is positioned 0 ≤ 𝑥 ≤ 1 through the queue, then there are two trivial cases:</p><ul><li>If you just joined the queue, any cancellation or down-modification at the level must come from in front, i.e. 𝑝(𝑥=1) = 1.</li><li>If you are at the front of the queue, 𝑝(𝑥=0) = 0, all cancels and modifies must be from behind.</li></ul><p>This becomes a matter of fitting a monotonic function between those two points. Say, a naive model 𝑝(𝑥) = 𝑥 assumes cancels arrive uniformly through the queue. But with some market intuition, you’d expect cancels to be biased towards the back of the queue where orders have poor fill rate and hence lower value.</p><h3>Comparison against exact queue position from MBO data</h3><p>How strong is this bias? Probably much stronger than you’d think.</p><p>In this tutorial, we parameterize this bias -1 &lt; k ≤ 0 where k = 0 (no bias) corresponds to the naive model where cancels are uniformly distributed in the queue, and this bias is stronger as it becomes more negative.</p><p>Then, we show a few instances of estimated queue position vs. the exact queue position (ground truth) obtained from MBO data:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dcscZejjJdYdFMHaKahEOg.png" /></figure><p>It’s evident that cancels are mostly pulled from the back of the queue.</p><h3>Downsides of estimating queue position from L2 data</h3><p>The most common mistake and downside of this approach is underestimating the bias and being overly optimistic your good fill rates: There are many open source and commercial trading platforms that support backtesting with passive orders using L2 data; this feature is sometimes touted as “market replay”. All of these platforms we’ve come across have been overly optimistic. (They also underestimate your adverse fill rates, which is a separate topic.)</p><p>Another downside of this approach is that it only works on price levels that are “in scope” given the number of visible levels in your L2 data. For example, if you have MBP-10 data (ten levels of market depth), and if the BBO moves away from your order until it’s outside of the top ten levels, then further changes to the price level become censored, making it much harder to estimate your queue position.</p><p>Despite these shortcomings, modeling queue position from L2 data is still an important capability since some trading venues don’t provide MBO data.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d3f8039b2515" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Build a Pairs Trading Strategy in Python: A Step-by-Step Guide]]></title>
            <link>https://databento.medium.com/build-a-pairs-trading-strategy-in-python-a-step-by-step-guide-dcee006e1a50?source=rss-0d024ea0f900------2</link>
            <guid isPermaLink="false">https://medium.com/p/dcee006e1a50</guid>
            <category><![CDATA[pair-trading]]></category>
            <category><![CDATA[quant]]></category>
            <category><![CDATA[trading]]></category>
            <category><![CDATA[futures-trading]]></category>
            <category><![CDATA[algorithmic-trading]]></category>
            <dc:creator><![CDATA[Databento]]></dc:creator>
            <pubDate>Mon, 10 Feb 2025 07:34:53 GMT</pubDate>
            <atom:updated>2025-02-16T09:09:15.624Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Pairs trading with cointegration using Python, sklearn, and Databento" src="https://cdn-images-1.medium.com/max/1024/1*BQREm_RQgW7maHW5U4fbnQ.png" /></figure><p><strong>Pairs trading</strong> is a form of statistical arbitrage that takes advantage of mean reversion or convergence in the prices of two instruments.</p><p>The simplest variation of this strategy involves taking long and short positions simultaneously on a pair of <strong>cointegrated</strong> instruments. But more generally, you can construct a spread from any linear combination of the two instruments with the approach in this tutorial — even going long simultaneously on two instruments.</p><h3>Setup and dependencies</h3><p>We’ll make use of the following external libraries:</p><ul><li><a href="https://databento.com/docs">databento</a> for market data.</li><li><a href="https://pandas.pydata.org/">pandas</a> for data manipulation.</li><li><a href="https://matplotlib.org/">matplotlib</a> for plotting.</li><li><a href="https://www.statsmodels.org/">statsmodels</a> for the Engle-Granger two-step cointegration test.</li><li><a href="https://scikit-learn.org/">scikit-learn</a> to fit the linear regression between the two price series.</li></ul><pre>import databento as db<br>import pandas as pd<br>import matplotlib.pyplot as plt<br>from statsmodels.tsa.stattools import coint<br>from sklearn.linear_model import LinearRegression</pre><h3>CME WTI (CL) vs. ICE Brent crude oil (BRN)</h3><p>Most existing literature shows the application of this strategy to equities, however the strategy can be applied to any asset class.</p><p>We’ll demonstrate the pairs trading strategy on the two most liquid crude oil products traded on CME and ICE, the <a href="https://databento.com/datasets/GLBX.MDP3/Futures/CL">WTI crude oil futures</a> (CL) <a href="https://databento.com/datasets/IFEU.IMPACT/Futures/BRN">and Brent crude oil futures</a> (BRN) contracts respectively.</p><p>This also showcases the value of Databento’s supplemental receive timestamps, ts_recv, which are used to construct our OHLCV aggregates. Most academic literature avoids cross-venue arbitrage like this because timestamps from two different exchanges are based on the different reference clocks that cannot be synced easily. ts_recv mitigates this problem by providing a common reference time with sub-microsecond accuracy between geographically-distant venues.</p><p><em>Note: Databento timestamps CME crude and ICE Brent data on the same Aurora I gateway. If you’re using a different data source, you may have to apply a delay offset for the time between Aurora I and 350 E Cermak where their matching engines are situated respectively.</em></p><h3>Configuration</h3><p>Exchange and clearing fees can be found on <a href="https://www.cmegroup.com/company/clearing-fees.html">CME</a> and <a href="https://www.ice.com/publicdocs/IFEU_Exchange_Clearing_Fees.pdf">ICE</a>’s websites. Tick sizes and notional tick values can be obtained from <a href="https://databento.com/docs/schemas-and-data-formats/instrument-definitions">instrument definitions</a>.</p><pre># Instrument-specific configuration<br>SYMBOL_X = &quot;CLM4&quot;<br>SYMBOL_Y = &quot;BRN FMN0024!&quot;<br>TICK_SIZE_X = 0.01<br>TICK_SIZE_Y = 0.01<br>TICK_VALUE_X = 10.0<br>TICK_VALUE_Y = 10.0<br>FEES_PER_SIDE_X = 0.70      # NYMEX corporate member fees<br>FEES_PER_SIDE_Y = 0.88<br><br># Global configuration<br>COMMISSIONS_PER_SIDE = 0.08<br><br># Backtest configuration<br>START = &quot;2024-04-01&quot;<br>END = &quot;2024-05-15&quot;</pre><h3>Data extraction</h3><p>We’ll fetch 1-minute <a href="https://databento.com/docs/schemas-and-data-formats/ohlcv">OHLCV aggregates</a> for ease of demonstration, but you may specify schema=&quot;mbp-1&quot; to use <a href="https://databento.com/docs/schemas-and-data-formats/mbp-1">MBP-1</a> instead:</p><pre>def fetch_data():<br><br>    client = db.Historical()<br><br>    data = client.timeseries.get_range(<br>        dataset=&quot;GLBX.MDP3&quot;,<br>        schema=&quot;ohlcv-1m&quot;,<br>        stype_in=&quot;raw_symbol&quot;,<br>        symbols=[SYMBOL_X],<br>        start=START,<br>        end=END,<br>    )<br><br>    df_x = data.to_df()[&quot;close&quot;].to_frame(name=&quot;x&quot;)<br><br>    data = client.timeseries.get_range(<br>        dataset=&quot;IFEU.IMPACT&quot;,<br>        schema=&quot;ohlcv-1m&quot;,<br>        stype_in=&quot;raw_symbol&quot;,<br>        symbols=[SYMBOL_Y],<br>        start=START,<br>        end=END,<br>    )<br><br>    df_y = data.to_df()[&quot;close&quot;].to_frame(name=&quot;y&quot;)<br><br>    return df_x.join(df_y, how=&quot;outer&quot;).ffill()</pre><p>Since OHLCV aggregates only print when there’s a trade in the interval, you’ll need to use the .ffill() method to synchronize the two time series in cases where one leg doesn&#39;t print.</p><p><em>Tip: Although CL and BRN are liquid futures contracts, there’s the possibility that both sides don’t print in a given minute interval. A more complete implementation should resample during every minute of the trading session.</em></p><h3>Engle-Granger cointegration test</h3><p>The basis of this strategy is to check that the residuals of a linear regression between the prices of the two instruments exhibits <strong>stationarity</strong>, also called the <strong>Engle-Granger two-step cointegration test</strong>. This implies that the two instruments’ price series are cointegrated, and that the spread constructed based on this linear association of the two instruments’ prices is stationary. In turn, this implies that the spread is <strong>mean-reverting</strong>.</p><h3>Cointegration vs. correlation</h3><p>Cointegration is preferred over correlation when constructing a pairs trade, since correlation doesn’t apply to non-stationary time series, and financial instrument prices are typically non-stationary and trending. High correlation between such series can occur even without a meaningful relationship.</p><p>For instance, two price series which are trending in the same direction but diverging in the long run may exhibit a spurious, positive correlation.</p><p>On the other hand, cointegrated prices series may exhibit positive, negative, or even zero correlation over any period due to short-term fluctuations, but tend to track closely over the long run.</p><h3>Implementation</h3><p>The strategy is simple: First, over the lookback period (last 100 records), we run the cointegration test. If the two series are found to be cointegrated, then the coefficient of linear regression between the two series provides the ratio of the two instruments needed to construct the spread, also called the <strong>hedge ratio</strong>. We’ll also compute the sample mean and standard deviation over this period.</p><p>Then, over the forward window (also 100 records), we compute the spread (residual) and normalize it by taking its z-score.</p><pre>df = fetch_data()<br><br># Model and monetization parameters<br>LOOKBACK = 100<br>ENTRY_THRESHOLD = 1.5<br>EXIT_THRESHOLD = 0.5<br>P_THRESHOLD = 0.05<br><br># Initialization<br>df[&quot;cointegrated&quot;] = 0<br>df[&quot;residual&quot;] = 0.0<br>df[&quot;zscore&quot;] = 0.0<br>df[&quot;position_x&quot;] = 0<br>df[&quot;position_y&quot;] = 0<br>is_cointegrated = False<br>lr = LinearRegression()<br><br>for i in range(LOOKBACK, len(df), LOOKBACK):<br><br>    x = df[&quot;x&quot;].iloc[i-LOOKBACK:i].values[:,None]<br>    y = df[&quot;y&quot;].iloc[i-LOOKBACK:i].values[:,None]<br><br>    if is_cointegrated:<br>        # Compute and normalize signal on forward window<br>        x_new = df[&quot;x&quot;].iloc[i:i+LOOKBACK].values[:,None]<br>        y_new = df[&quot;y&quot;].iloc[i:i+LOOKBACK].values[:,None]<br>        spread_back = y - lr.coef_ * x<br>        spread_forward = y_new - lr.coef_ * x_new<br>        zscore = (spread_forward - spread_back.mean()) / spread_back.std()<br>        df.iloc[i:i+LOOKBACK, df.columns.get_loc(&quot;cointegrated&quot;)] = 1<br>        df.iloc[i:i+LOOKBACK, df.columns.get_loc(&quot;residual&quot;)] = spread_forward<br>        df.iloc[i:i+LOOKBACK, df.columns.get_loc(&quot;zscore&quot;)] = zscore<br><br>    _, p, _ = coint(x,y)<br>    is_cointegrated = p &lt; P_THRESHOLD<br>    lr.fit(x,y)</pre><p>If the normalized residual is negative, it means the instrument associated with y is underpriced, i.e. we’ll buy y and sell x to monetize the prediction that their prices will converge in the future. Conversely, if the normalized residual is positive, we’ll sell y and buy x.</p><p>Since the two products have a similar notional value and futures have large minimum order size, we’ll trade a static hedge ratio of 1. If you’re modifying this strategy to trade stocks or ETFs or products that have significant differences in volatility or notional value, you should consider using the dynamic hedge ratio lr.coef_ to scale your position.</p><p><em>Tip: The hedge ratio </em><em>lr.coef_ may be negative. This regularly occurs, for instance, if one leg of the pair is an inverse ETF.</em></p><pre># Standardized residual is negative =&gt; y is underpriced =&gt; sell x, buy y<br># Standardized residual is positive =&gt; y is overpriced =&gt; buy x, sell y<br>df.loc[df.zscore &lt; -ENTRY_THRESHOLD, &#39;position_y&#39;] = 1<br>df.loc[df.zscore &gt; ENTRY_THRESHOLD, &#39;position_y&#39;] = -1<br>df[&#39;position_x&#39;] = -df[&#39;position_y&#39;]</pre><p>It’s common to specify a score-based or time-based exit condition. For example, we can exit the position when the spread converges to within +/-0.5 standard deviations. This has the effect of longer holding periods and lower transaction costs.</p><pre># Exit positions when z-score crosses +/-0.5<br>hold_y_long = df[&quot;zscore&quot;].apply(lambda z: 1 if z &lt;= -EXIT_THRESHOLD else 0)<br>hold_y_short = df[&quot;zscore&quot;].apply(lambda z: 1 if z &gt;= EXIT_THRESHOLD else 0)<br><br># Carry forward positions until exit condition is met<br>df[&quot;position_y&quot;] = df[&quot;position_y&quot;].mask((df[&quot;position_y&quot;].shift() == -1) &amp; (hold_y_short == 1), -1)<br>df[&quot;position_y&quot;] = df[&quot;position_y&quot;].mask((df[&quot;position_y&quot;].shift() == 1) &amp; (hold_y_long == 1), 1)<br>df[&quot;position_x&quot;] = -df[&quot;position_y&quot;]</pre><p>Here’s a visualization of the strategy. The outer dashed lines show the entry conditions while the inner dashed lines show the exit conditions:</p><figure><img alt="Spread z-score with regression residuals" src="https://cdn-images-1.medium.com/max/1024/0*e8jofcraT1VpUAEX.png" /></figure><h3>Estimating slippage</h3><p>Exact instantaneous slippage from crossing the spread can be calculated using MBP-1 data and execution timestamps from the backtest. In the interest of time, you can gauge the viability of the strategy by applying a constant spread cost per contract side. This is typically assumed to be half a tick or one tick for liquid futures, but we can also estimate it quickly from a small slice of MBP-1 data:</p><pre>def estimate_slippage():<br><br>    import datetime<br><br>    client = db.Historical()<br><br>    data = client.timeseries.get_range(<br>        dataset=&quot;GLBX.MDP3&quot;,<br>        schema=&quot;mbp-1&quot;,<br>        stype_in=&quot;raw_symbol&quot;,<br>        symbols=[SYMBOL_X],<br>        start=START,<br>    )<br><br>    df = data.to_df()<br>    avg_spread_x = (df[&quot;ask_px_00&quot;] - df[&quot;bid_px_00&quot;]).mean()<br><br>    data = client.timeseries.get_range(<br>        dataset=&quot;IFEU.IMPACT&quot;,<br>        schema=&quot;mbp-1&quot;,<br>        stype_in=&quot;raw_symbol&quot;,<br>        symbols=[SYMBOL_Y],<br>        start=START,<br>    )<br><br>    df = data.to_df()<br>    avg_spread_y = (df[&quot;ask_px_00&quot;] - df[&quot;bid_px_00&quot;]).mean()<br><br>    return avg_spread_x, avg_spread_y<br><br>avg_spread_x, avg_spread_y = estimate_slippage()</pre><h3>Backtest</h3><p>We can now compute the gross PnL and transaction costs:</p><pre># Compute backtest results<br>df[&quot;pnl_x&quot;] = 0.0<br>df[&quot;pnl_y&quot;] = 0.0<br>df.iloc[:-1, df.columns.get_loc(&quot;pnl_x&quot;)] = df[&#39;position_x&#39;].iloc[:-1].values * df[&quot;x&quot;].diff()[1:].values / TICK_SIZE_X * TICK_VALUE_X<br>df.iloc[:-1, df.columns.get_loc(&quot;pnl_y&quot;)] = df[&#39;position_y&#39;].iloc[:-1].values * df[&quot;y&quot;].diff()[1:].values / TICK_SIZE_Y * TICK_VALUE_Y<br><br>df[&quot;volume_x&quot;] = df[&quot;position_x&quot;].diff().abs()<br>df[&quot;volume_y&quot;] = df[&quot;position_y&quot;].diff().abs()<br>df[&quot;tcost&quot;] = df[&quot;volume_x&quot;] * FEES_PER_SIDE_X + df[&quot;volume_y&quot;] * FEES_PER_SIDE_Y + \<br>              (df[&quot;volume_x&quot;] + df[&quot;volume_y&quot;]) * COMMISSIONS_PER_SIDE + \<br>              (df[&quot;volume_x&quot;] * avg_spread_x / TICK_SIZE_X / 2 * TICK_VALUE_X) + \<br>              (df[&quot;volume_y&quot;] * avg_spread_y / TICK_SIZE_Y / 2 * TICK_VALUE_Y).cumsum()<br>df[&quot;gross_pnl&quot;] = (df[&quot;pnl_x&quot;] + df[&quot;pnl_y&quot;]).cumsum()<br>df[&quot;net_pnl&quot;] = df[&quot;gross_pnl&quot;] - df[&quot;tcost&quot;]</pre><h3>Results</h3><pre># Plot and print results<br>daily_pnl = df[&quot;net_pnl&quot;].groupby(df.index.date).sum()<br>sr = daily_pnl.mean() / daily_pnl.std() * 252**.5<br>print(f&quot;Sharpe ratio: {sr:.2f}&quot;)<br><br>plt.plot(df[&quot;gross_pnl&quot;], label=&quot;Gross PnL&quot;)<br>plt.plot(df[&quot;net_pnl&quot;], label=&quot;Net PnL&quot;)<br>plt.plot(df[&quot;tcost&quot;], label=&quot;t-cost&quot;)<br>plt.xlabel(&quot;Date&quot;)<br>plt.ylabel(&quot;PnL (USD)&quot;)<br>plt.legend()<br>plt.show()</pre><pre>Sharpe ratio: 8.57</pre><figure><img alt="Cumulative PnL graph" src="https://cdn-images-1.medium.com/max/1024/0*e5gvPjPixGbn2NxY.png" /></figure><h3>Full code</h3><p>The full code example can be found on our GitHub <a href="https://gist.github.com/databento-bot/23ea8f2ef0de6f1290c1c6d2c87b60c3">here</a>.</p><h3>Practical considerations and improvements</h3><p>This tutorial is kept intentionally short using a simple vectorized implementation. Ideally, you should use <a href="https://databento.com/docs/schemas-and-data-formats/mbp-1">MBP-1</a> data with an event-driven backtest loop that incorporates the delays between your system and the exchange gateways. This can be done using the <a href="https://databento.com/docs/api-reference-historical/helpers/dbn-store-replay">market replay</a> method.</p><p>This strategy is very sensitive to slippage and the exact expiration month that’s traded; non-lead month contracts will have wider spreads which can make the strategy infeasible.</p><p>We assumed exchange fees and commissions that are realistic for a medium-sized trading firm or a team within a larger firm that’s already a CME member firm. In practice, achieving similar rates requires a <a href="https://www.cmegroup.com/company/membership/corporate/nymex.html">NYMEX 106.J corporate membership</a> and thousands of contract sides executed per day.</p><p>Scaling up to larger trade sizes will significantly expand the strategy’s state machine, since you’ll have to handle partial executions and different sizes on each leg of the spread to achieve optimal hedge ratio. MBP-1 data can also inform trade sizing.</p><p>We introduced a few free model and monetization parameters, namely LOOKBACK, ENTRY_THRESHOLD, EXIT_THRESHOLD. These can be optimized using any hyperparameter tuning method (e.g. grid search) and cross-validated.</p><p>There are also a few common variations of this strategy to consider:</p><ul><li><strong>Basket trading</strong> by constructing combinations of more than two instruments, using another procedure such as the Johansen test.</li><li>Calibrating an Ornstein-Uhlenbeck process, which gives a parametric model for time-based exit.</li><li>Using <strong>total least squares</strong> instead of ordinary least squares to determine the hedge ratio.</li><li>Scanning a wide universe systematically for cointegrated pairs, to discover unintuitive relationships. However, this runs the risk of poor generalization if too many pairs are tested. Dimensionality reduction methods like PCA can improve the search and generalization error.</li></ul><h3>Further reading</h3><p>Alexander, C. (2008). Market Risk Analysis: Practical Financial Econometrics (Vol. 2). Wiley.</p><p>Tsay, R. S. (2010). Analysis of Financial Time Series (3rd edition). Wiley.</p><p>Engle, R. F., &amp; Granger, C. W. J. (1987). Co-integration and error correction: Representation, estimation, and testing. Econometrica, 55(2), 251–276.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dcee006e1a50" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Easy, interactive financial charts in Python: Just 11 lines of code, no JavaScript required]]></title>
            <link>https://databento.medium.com/easy-interactive-financial-charts-in-python-just-11-lines-of-code-no-javascript-required-cde338eecd43?source=rss-0d024ea0f900------2</link>
            <guid isPermaLink="false">https://medium.com/p/cde338eecd43</guid>
            <category><![CDATA[market-data]]></category>
            <category><![CDATA[algorithmic-trading]]></category>
            <category><![CDATA[stocks]]></category>
            <category><![CDATA[trading]]></category>
            <category><![CDATA[tradingview]]></category>
            <dc:creator><![CDATA[Databento]]></dc:creator>
            <pubDate>Tue, 28 Jan 2025 10:35:48 GMT</pubDate>
            <atom:updated>2025-01-28T10:39:48.924Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Visualize market data using Databento and TradingView Lightweight Charts" src="https://cdn-images-1.medium.com/max/1024/1*CU58tLtnh19OHSiXVfxAfg.png" /></figure><h3>Overview</h3><p>This guide demonstrates how to display Databento’s market data with TradingView’s popular Lightweight Charts library, entirely in Python. It also shows how to display indicators in the charts.</p><p>TradingView is a popular charting platform and Databento is a provider of high-quality financial market data. This guide makes use of the <a href="https://github.com/louisnw01/lightweight-charts-python">lightweight-charts-python</a> library, which provides a user-friendly, Pythonic interface to a simplified version of TradingView — so you don’t need to learn or use JavaScript to take advantage of TradingView’s interactive features.</p><p>If you want to explore advanced features of Lightweight Charts, you can find the documentation <a href="https://www.tradingview.com/lightweight-charts/">here</a>.</p><p>We will make use of data from Databento’s <a href="https://databento.com/docs/schemas-and-data-formats/ohlcv?historical=python&amp;live=python&amp;reference=python">ohlcv-1m schema</a>. First, install databento and the lightweight-charts-python library:</p><pre>pip install databento<br>pip install lightweight-charts</pre><p>Import both libraries and pandas:</p><pre>import pandas as pd<br>import databento as db <br>from lightweight_charts import Chart</pre><p>Declare a main function and set your <a href="https://databento.com/docs/portal/api-keys?historical=python&amp;live=python&amp;reference=python">Databento API key</a>:</p><pre>if __name__ = &quot;__main__&quot;: <br>    key = &quot;YOUR_DB_API_KEY_HERE&quot;<br>    key = &quot;YOUR_DB_API_KEY_HERE&quot;<br>    client = Historical(key=key)</pre><h3>Getting Data from Databento</h3><p>Fetch the OHLCV data using Databento’s simple API. Databento has a simple <a href="https://databento.com/pricing">usage-based pricing</a> plan for new users that charges per data request. Depending on your needs, it might be a good idea to choose a subscription plan for flat-rate access or store the data locally to reduce costs that may be incurred on repeat requests.</p><pre>data = client.timeseries.get_range(<br>        dataset=&quot;XNAS.ITCH&quot;,<br>        symbols=[&quot;NVDA&quot;],<br>        schema=&quot;ohlcv-1m&quot;,<br>        start=&quot;2024-05-13T08:00&quot;,<br>        end=&quot;2024-05-13T23:59&quot;,<br>        limit=1000,<br>    ) <br><br># Optional: Save the data to file <br># path = &quot;instrument_data.dbn&quot;<br># data.to_file(path=path)</pre><h3>Displaying Data with Lightweight Charts</h3><p>Convert the data to a dataframe and and initialize lightweight_charts. If you saved the data to file in the previous step, you can load the data with the DBNStore helper class:</p><pre># Optional: Load data from file<br># from Databento import DBNStore<br># data = DBNStore.from_file(path=&quot;instrument_data.dbn&quot;)<br><br>df = data.to_df() <br><br># Setting toolbox to True allows you to make drawings on the chart<br>chart = Chart(toolbox=True)<br>chart.set(df)<br><br># Set block to True, otherwise the chart window will automatically close<br>chart.show(block = True)</pre><p>If everything goes alright, you get a basic chart as depicted below:</p><figure><img alt="An interactive market data chart using TradingView’s lightweight-charts-python library and Databento OHLCV data" src="https://cdn-images-1.medium.com/max/803/1*KE8TGL8ZKyipQg1Cq6GYrA.png" /></figure><h3>Plotting Lines</h3><p>There are various plot types that can be used to overlay derived data and analytics on the chart. Using an example from another Databento <a href="https://databento.com/blog/vwap-python">article</a>, we will plot the VWAP of NVDA during the session. Note that additional code from this point onwards will be included before calling the chart.set() and chart.show() methods.</p><pre># Calculate vwap and put the result in a new dataframe<br>df[&quot;pvt&quot;] = df[&quot;close&quot;] * df[&quot;volume&quot;]<br>df[&quot;pvt&quot;] = df[&quot;close&quot;] * df[&quot;volume&quot;]<br>df[&quot;vwap&quot;] = df[&quot;pvt&quot;].cumsum() / df[&quot;volume&quot;].cumsum()<br>ohlcv_vwap_df = pd.DataFrame({<br>&quot;vwap&quot;: df[&quot;vwap&quot;]<br>}, index=df.index)<br><br># Create a line bound to the chart, and set data to the line<br>line = chart.create_line(name=&quot;vwap&quot;, color=&quot;blue&quot;, width=3)<br>line.set(ohlcv_vwap_df)<br>    <br># Important: Put the code above before these two lines<br>chart.set(df)<br>chart.show(block=True)</pre><figure><img alt="Adding a VWAP indicator to TradingView Lightweight Charts in Python" src="https://cdn-images-1.medium.com/max/1024/1*gTZL_LCdaefe-NI93cuanw.png" /></figure><h3>Applying Custom Styles</h3><p>The lightweight-charts-python library supports customization of chart elements like font, colors, watermark, and gridlines. Below is an example using Databento branding:</p><pre>chart.layout(background_color=&#39;#F2F2FF&#39;, text_color=&#39;#090008&#39;, font_size=13,<br>                 font_family=&#39;Helvetica&#39;)<br>chart.candle_style(up_color=&#39;#A09EFA&#39;, down_color=&#39;#474BD7&#39;,<br>                       border_up_color=&#39;#6266E5&#39;, border_down_color=&#39;#222262&#39;,<br>                       wick_up_color=&#39;#6266E5&#39;, wick_down_color=&#39;#222262&#39;)<br>chart.volume_config(up_color=&#39;#777777&#39;, down_color=&#39;#cccccc&#39;)<br>chart.watermark(&#39;NVDA 1 min&#39;, color=&#39;#dddddd&#39;)<br>chart.crosshair(mode=&#39;normal&#39;, vert_color=&#39;#222222&#39;, vert_style=&#39;dotted&#39;,<br>                    horz_color=&#39;#222222&#39;, horz_style=&#39;dotted&#39;)<br>chart.legend(visible=True, font_size=14, color=&#39;#222222&#39;)<br>chart.grid(vert_enabled=False, horz_enabled=False)</pre><figure><img alt="Changing the style of TradingView Lightweight Charts in Python" src="https://cdn-images-1.medium.com/max/1024/1*JzndaumwfvyrAttHrGAo7A.png" /></figure><p>The lightweight-charts library also supports <strong>Jupyter</strong> and <strong>Streamlit</strong>. Simply follow the code below depending on your use case and replace accordingly:</p><pre># Jupyter<br>from lightweight_charts import JupyterChart<br>from lightweight_charts import JupyterChart<br><br>chart = JupyterChart()<br># ... set data to the chart<br>chart.load()<br><br># Streamlit<br>from lightweight_charts.widgets import StreamlitChart<br><br>chart = StreamlitChart()<br># Set data to the chart<br>chart.load()</pre><p>By combining Databento’s market data with the lightweight-charts-python library, you can create highly customizable and interactive TradingView-style visualizations with minimal effort. This guide covered foundational concepts, and future articles will explore advanced topics such as live data streaming and visualization of order book features.</p><figure><img alt="TradingView Lightweight Charts custom chart types" src="https://cdn-images-1.medium.com/max/1024/1*RAiKwLdrSUCaXmGL_vnxuw.png" /></figure><h3>Credits</h3><p>The following article was written by Idris Dosunmu, Databento user and Lead Product Manager at <a href="https://www.mintaragroup.com/">Mintara Digital</a> adapted for Medium. Mintara Digital is a digital product consultancy for fintechs, hedge funds, and family offices. The original post can be found <a href="https://databento.com/blog/visualize-market-data">here</a>.</p><p>On behalf of Databento, we’d like to thank Idris for generously sharing his knowledge via this tutorial. You can find Idris on LinkedIn <a href="https://www.linkedin.com/in/idrisdosunmu">here</a>.</p><p>For suggestions or requests for specific visualization techniques, please reach out to Idris via <a href="/service/mailto:idris@mintaragroup.com">idris@mintaragroup.com</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cde338eecd43" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Introducing intraday PCAP delivery]]></title>
            <link>https://databento.medium.com/introducing-intraday-pcap-delivery-335a8c693b3f?source=rss-0d024ea0f900------2</link>
            <guid isPermaLink="false">https://medium.com/p/335a8c693b3f</guid>
            <category><![CDATA[futures-trading]]></category>
            <category><![CDATA[hft]]></category>
            <category><![CDATA[algotrading]]></category>
            <category><![CDATA[market-data]]></category>
            <category><![CDATA[stocks]]></category>
            <dc:creator><![CDATA[Databento]]></dc:creator>
            <pubDate>Sat, 18 Jan 2025 12:26:40 GMT</pubDate>
            <atom:updated>2025-01-18T12:26:40.691Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KaJoGzLVGPIm-XbkIDRF0g.png" /></figure><p>Today we’re launching a major upgrade to Databento’s <a href="https://databento.com/pcaps">packet capture (PCAP) service </a>, with the introduction of intraday delivery.</p><h3>What’s new</h3><p>Previously, customers with a daily PCAP subscription needed to wait up to 24 hours to receive the previous day’s PCAP files. With our upgraded infrastructure, customers can receive PCAP files within 20 minutes of the original market data message in most cases.</p><p>Delivery is done through a standard AWS S3 bucket and is usually set up within 1 or 2 business days of signing an order form.</p><h3>What are PCAPs and how are they used for market data?</h3><p>Packet captures contain raw market data, in their original wire format and sequence.</p><p>The most valuable benefit of getting market data in PCAP format is its losslessness. PCAPs allow a user to replay the market precisely, incorporating effects like out-of-order packet arrival and microstructural features of the original market data messages that may not be found even in normalized MBO (L3) data. Many of our enterprise customers also rely on our PCAP files and normalized data simultaneously to audit our data integrity.</p><p>Databento’s PCAPs also include our PTP receive timestamps, which allow users to measure timestamp deltas that are necessary for accurate backtesting in sub-millisecond environments like TCA and smart order routing.</p><p>Since the PCAPs preserve the native feed protocol, latency-sensitive users can use PCAPs to test their parser and feed handler implementations and benchmark their trading systems through packet replay.</p><h3>How are intraday PCAP files useful?</h3><p>This solution was developed for several of our users who had time-sensitive pipelines for intraday or post-trade analytics.</p><p>While a few market data vendors provide PCAPs, none of them were able to provide deterministic guarantees on delivery time that were better than end-of-day (T+1) either due to licensing or technological limitations.</p><p>PCAPs files can be several GBs each after compression and can be slow to rotate and transfer out of capture servers at the colocation site. It’s possible to deliver PCAPs arbitrarily fast, but going to the extreme, a real-time stream of PCAPs will simply resemble the raw multicast feed and is inconvenient for a variety of data pipeline and ETL workflows that are designed around file or S3 access. Rotating the files too frequently, e.g. every minute, can be cumbersome on your ops team and file metadata.</p><p>With Databento’s extensive real-time distribution licenses and WAN bandwidth, we were able to create a fast path for these users to receive PCAP files intraday.</p><p>Intraday PCAP file deliveries are also ideal for customers who want to avoid real-time access fees, as delayed data license fees are usually much more affordable.</p><h3>What’s the real-world performance of your intraday PCAP delivery?</h3><p>Since going to production, we’ve been able to deliver the median PCAP file within 20 minutes of the first packet in the file. 99th percentile delivery time is within 43 minutes of the first packet in the file. We segment our PCAP files in 10-minute intervals, i.e. the file is delivered within 33 minutes of the last packet in the file at the 99th percentile.</p><h3>Who uses Databento’s market data PCAPs?</h3><p>Our existing users include major proprietary trading firms, quant hedge funds, leading ISVs, market data redistributors, and developers of low latency execution and feed handling solutions.</p><figure><img alt="Delay offset of intraday market data pcap delivery" src="https://cdn-images-1.medium.com/max/1024/1*vtdPalCoQnKfnyaWmqjWqQ.png" /></figure><h3>What other advantages set Databento’s PCAP service apart?</h3><p>Our team started Databento after using every commercial PCAP service at our previous roles in tier 1 trading firms. Some of us even architected the existing capture setups that are in use at other data vendors today. So we’ve built our PCAP service to improve on the many limitations of legacy market data providers. If you’re looking for a PCAP provider, just ask: can your vendor do these?</p><ul><li>Lossless, full OPRA A/B tapes up to 100 gigabit line rate.</li><li>Same data used and tested in our normalized data solutions, ensuring application-level checks (like book building) for data integrity on every ticker.</li><li>Precise truncation of packets at the file timestamp boundaries.</li><li>No out-of-order or missing file uploads unless there’s a data gap.</li><li>Authorized distributor of ICE and NYSE market data and pcaps.</li><li>Full order book and depth of market feeds from smaller US equity exchanges.</li><li>Accurate annotation of network topology and RX deltas in capture system.</li><li>FPGA-based hardware timestamps.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=335a8c693b3f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to build an order book (DoM) visualization using Databento, React, and Rust]]></title>
            <link>https://databento.medium.com/how-to-build-an-order-book-dom-visualization-using-databento-react-and-rust-9eac46d36cf6?source=rss-0d024ea0f900------2</link>
            <guid isPermaLink="false">https://medium.com/p/9eac46d36cf6</guid>
            <dc:creator><![CDATA[Databento]]></dc:creator>
            <pubDate>Tue, 24 Sep 2024 06:54:11 GMT</pubDate>
            <atom:updated>2024-09-24T06:57:09.332Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/937/1*2vOf3B0RbbVbJwvp7LV6PQ.png" /><figcaption>CL futures depth of market. Credit: <a href="https://www.geoffreyoung.com/">Geoff Young</a> (GitHub: gty3) for the implementation and tutorial.</figcaption></figure><h3>What is a depth of market (DoM) price ladder?</h3><p>The DoM price ladder is a common way to visualize a limit order book in market-by-price (L2) form.</p><p>In the past, most commercial implementations of the DoM have been on native desktop applications. The origins of this type of visualization can be traced to desktop charting apps like that of Trading Technologies (which held a <a href="https://patents.google.com/patent/US6772132B1/en">patent</a> for the design since over 20 years ago, that has since expired). Market depth data is large and difficult to process, and it tended to be easier to implement the DoM visualization with the necessary performance on a native desktop application.</p><p>These days, with the speed of modern web browsers and client-side rendering techniques, it’s possible to implement a fast, snappy DoM as a web-based UI. This approach has seen many iterations on different trading platforms, especially seeing a widespread adoption on crypto exchanges like <a href="https://www.coinbase.com/advanced-trade/spot/BTC-USD">Coinbase</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/293/1*JqYCYBZVG1GK1IyQ-JTwxw.png" /><figcaption>DoM as browser-based GUI application. Credit: Coinbase Pro.</figcaption></figure><p>This post highlights the typical stack you’d use to implement the DoM as a web-based browser application, similar to the one found on Coinbase.</p><h3>Recommended design and tools</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/265/1*vXt-a3p742TrCmqdRl4WEg.png" /><figcaption>Typical single-page application design with separate frontend and backend, and client-side rendering.</figcaption></figure><ul><li><strong>React.js.</strong> For the web frontend with client-side rendering.</li><li><strong>Databento.</strong> For simple, fast access to market depth (L2) or full order book (L3) data. This type of data is typically very expensive, due to its size, licensing costs, and scarcity—and Databento’s usage-based pricing plans make it easier to get around these cost constraints.</li><li><strong>Rust. </strong>A performant, memory-safe programming language. Databento provides an <a href="https://github.com/databento/databento-rs">official Rust client library</a>, which makes it easy to implement the backend in Rust.</li><li><strong>WebSocket</strong>, <strong>SSE or WebTransport over HTTP/3. </strong>To communicate between the backend and frontend. At the time of this writing (Sep 2024), Databento has a raw TCP API for its real-time data and doesn’t expose a WebSocket API. Most web browsers don’t allow you to open raw TCP sockets due to security restrictions, so your frontend won’t be able to get data directly from Databento. But this is not an issue as most browser applications should have backend service layer that fetches the data; the backend service can expose real-time data over WebSocket, SSE, or any protocol that supports streaming.</li></ul><h3>Code and live demo</h3><p>The code and implementation for this guide is contributed by Geoff Young (gty3 on GitHub).</p><p>See GitHub project for the code: <a href="https://github.com/gty3/dom-replay">https://github.com/gty3/dom-replay</a></p><p>See live demo: <a href="https://orderflowreplay.com/">https://orderflowreplay.com/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9eac46d36cf6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Matching Engines in 3 Minutes: Terminology Guide for Traders and Developers]]></title>
            <link>https://databento.medium.com/matching-engines-in-3-minutes-terminology-guide-for-traders-and-developers-5d32c2e70e2b?source=rss-0d024ea0f900------2</link>
            <guid isPermaLink="false">https://medium.com/p/5d32c2e70e2b</guid>
            <category><![CDATA[algorithmic-trading]]></category>
            <category><![CDATA[trading]]></category>
            <category><![CDATA[quant]]></category>
            <category><![CDATA[stocks]]></category>
            <category><![CDATA[hft]]></category>
            <dc:creator><![CDATA[Databento]]></dc:creator>
            <pubDate>Thu, 12 Sep 2024 18:41:50 GMT</pubDate>
            <atom:updated>2024-09-13T09:59:25.926Z</atom:updated>
            <content:encoded><![CDATA[<p>This guide is intended for traders, researchers, and engineers who are involved in algorithmic trading. It’s also useful for network and systems engineers who are making their first foray into financial trading infrastructure.</p><p>These are key terms that you’ll find useful in navigating colocation and server hosting for a trading system, and also in describing how your system interacts with a trading venue’s matching engine.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cnRHIPD0jl_c4OIy026KtQ.png" /></figure><p><strong>Primary colocation. </strong>The site with the lowest latency to the matching engine. Usually the data center where the matching engine is housed, but this is not always the case—some venues only allow connectivity outside of the data center where their matching engine resides. For example, NYSE’s primary colocation site is in NYSE’s Mahwah data center.</p><p><strong>Proximity hosting. </strong>Any non-primary colocation site offering a latency advantage due to proximity to the matching engine, typically within the same city or nearby. For example, any hosting location in New York or New Jersey could be considered a proximity hosting site for Nasdaq, whose primary colocation is in Carteret.</p><p><strong>Point of presence (PoP). </strong>Any location offering direct connections to a trading venue without intermediaries other than the primary colocation site. For example, EBS has PoPs in Secaucus and Slough.</p><p><strong>Latency equalization.</strong> Ensuring equal latency to the matching engine. Typically achieved by spooling optical fiber and ensuring equal length of cross-connects to the matching engine. Also called fiber equalization.</p><p><strong>Handoff. </strong>The point where traffic passes between the matching engine’s and the trading participant’s networks. A cross-connect to a matching engine’s extranet.</p><p><strong>Boundary switch.</strong> A network switch on which a trading venue’s handoff terminates.</p><p><strong>Load balancer. </strong>A typical part of a matching engine. Distributes messaging traffic across servers or gateways that compose the matching engine.</p><p><strong>Wire protocol. </strong>Specifies how to communicate with the matching engine. In financial trading environments, this often refers interchangeably to any communication protocol, and not only the physical and data link layers (OSI layers 1 and 2) as the term “wire” seems to imply. Includes application-level protocols (like ITCH, OUCH), which describe message structure for data and order entry, and session-level protocols (like MoldUDP64).</p><p><strong>Direct market access (DMA). </strong>The ability to send orders directly to a matching engine without intermediaries.</p><p><strong>Matching algorithm.</strong> The rules that determine order priority and how trades are matched. Examples include pure FIFO, pro rata, and price-broker-time.</p><p><strong>Gateways.</strong> The servers that receive order messages or publish market data.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5d32c2e70e2b" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>