{"id":7012,"date":"2026-10-31T12:46:35","date_gmt":"2026-10-31T12:46:35","guid":{"rendered":"https:\/\/eodhd.com\/financial-academy\/?p=7012"},"modified":"2026-10-31T12:46:35","modified_gmt":"2026-10-31T12:46:35","slug":"tick-volume-dollar-bars-python-eodhd-tick-data-spy","status":"publish","type":"post","link":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy","title":{"rendered":"Tick, Volume and Dollar Bars in Python with EODHD Tick Data: A Test on SPY"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Typically, charts and models in finance look at the market on a clock: one observation every minute, every hour, every day. In Chapter 2 of Advances in Financial Machine Learning, Marcos L\u00f3pez de Prado (2018) argues that this is a poor way to sample a market, because information does not arrive at a constant pace. Bars that close after a fixed number of trades, a fixed number of shares or a fixed amount of money traded should sample the market more evenly, and the returns of such bars should be better behaved.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This post puts that claim to a small test. We download 25 trading days of tick data for SPY, the exchange-traded fund that tracks the S&amp;P 500, from 1 September to 6 October 2026 with the EODHD Ticks API (EODHD, n.d.-a), build tick, volume and dollar bars with ordinary time bars as a baseline, and run a reduced version of Exercise 2.1 from the book: four statistical checks on 20 trading days. On the way we meet a practical problem that the book touches only briefly: a few hundred off-exchange trades, printed far from the market and mostly contingent trades, are enough to distort volume and dollar bars badly. We show what they do, what the sl field tells us about them, and how a simple price filter removes them.<\/p>\n\n\n\n<p style=\"text-align: center\"><a class=\"maxbutton-1 maxbutton maxbutton-subscribe-to-api external-css btn\" href=\"https:\/\/eodhd.com\/register\"><span class='mb-text'>Register &amp; Get Data<\/span><\/a><\/p>\n\n\n\n\n\n\n<h2 id=\"h-standard-bars-in-a-nutshell\" class=\"wp-block-heading\">Standard Bars in a Nutshell<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A bar summarises a stretch of trading by its open, high, low, close and volume. What differs between bar types is the rule that decides when a bar ends.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Time bars end after a fixed amount of clock time, for example every 8 minutes.<\/li>\n\n\n\n<li>Tick bars end after a fixed number of trades.<\/li>\n\n\n\n<li>Volume bars end after a fixed number of shares have traded.<\/li>\n\n\n\n<li>Dollar bars end after a fixed amount of money, price times shares, has traded.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The book calls all four standard bars (Section 2.3.1); the last three sample by activity instead of by the clock. Trading is far from uniform over the day: it is busy at the open and the close and after news, and quiet around lunch. A clock samples the quiet periods as often as the busy ones. Activity-based bars take more samples when much is happening and fewer when little is, which is the intuition behind the claim that their returns are closer to independent and closer to normal.<\/p>\n\n\n\n<h2 id=\"h-what-we-test-a-reduced-exercise-2-1\" class=\"wp-block-heading\">What We Test: A Reduced Exercise 2.1<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Exercise 2.1 of the book works with E-mini S&amp;P 500 futures tick data. Part (a) asks for tick, volume and dollar bars. Part (b) asks for the number of bars per week and which bar type gives the most stable count. Part (c) asks for the serial correlation of returns. Part (d) asks for the variance of returns in every monthly subset and then the variance of those variances. Part (e) asks for the Jarque-Bera normality test. Years of futures ticks with a contract roll are too heavy for a blog post, so we reduce the exercise in four ways.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>One instrument: the SPY ETF (ticker SPY.US), which has no futures roll and therefore needs no ETF trick.<\/li>\n\n\n\n<li>One short window: 20 trading days, from 9 September to 6 October 2026, plus 5 earlier trading days that are used only to set the bar sizes.<\/li>\n\n\n\n<li>Daily instead of weekly and monthly subsets: bar counts and return variances are computed for each trading day.<\/li>\n\n\n\n<li>Bars are formed inside each trading day, so that no return spans the overnight gap.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">In this post the four checks are called a) to d). They correspond to parts (b) to (e) of the book exercise, while part (a), forming the bars, is the subject of the sections before them.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>a) How stable is the daily number of bars?<\/li>\n\n\n\n<li>b) How large is the serial correlation of consecutive returns?<\/li>\n\n\n\n<li>c) How stable is the daily variance of returns?<\/li>\n\n\n\n<li>d) How close to normal are the returns?<\/li>\n<\/ul>\n\n\n\n<h2 id=\"h-preparations\" class=\"wp-block-heading\">Preparations<\/h2>\n\n\n\n<p class=\"bordered_paragraph wp-block-paragraph\">Create a project folder with its own virtual environment, so that nothing is installed into the global Python, and install the libraries used in this post: numpy, pandas, scipy, matplotlib, pyarrow, requests and python-dotenv.<\/p>\n\n\n\n            <div class=\"code__wrapper\">\n                <div class=\"code__content\">\n                    \n<pre class=\"wp-block-code has-text-color has-background\" style=\"color:#ffffff;background-color:#000000\"><code class=\"\">python -m venv .venv\n.venv\\Scripts\\activate          # Linux\/macOS: source .venv\/bin\/activate\npip install numpy pandas scipy matplotlib pyarrow requests python-dotenv<\/code><\/pre>\n\n                <\/div>\n                <div class=\"code__btns\">\n                    <button class=\"code__copy\" class=\"copy\" title=\"Copy url\">\n                        <svg class=\"code__copy__icon\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n                            <use xlink:href=\"\/img\/icons\/copy.svg#copy\"><\/use>\n                        <\/svg>\n                        <img decoding=\"async\" class=\"code__copy__approve\" alt=\"\" src=\"\/img\/approve_ico.svg\" loading=\"eager\">\n                    <\/button>\n                <\/div>\n            <\/div>\n        \n\n\n<p class=\"bordered_paragraph wp-block-paragraph\">Keep your EODHD API token in a file named .env next to the scripts, in one line (EODHD_API_TOKEN=your_token), and read it from there. Do not write the token into the code, and do not commit the .env file to a repository.<\/p>\n\n\n\n<h2 id=\"h-api-key-activation\" class=\"wp-block-heading\">API Key Activation<\/h2>\n\n\n\n<p class=\"bordered_paragraph wp-block-paragraph\">1. Use the &#8220;demo&#8221; API key to test EODHD&#8217;s data from a limited set of tickers without registering: AAPL.US | TSLA.US | VTI.US | AMZN.US | BTC-USD | EUR-USD. Real-Time Data and all of the APIs (except Bulk) are included without API call limitations with these tickers and the demo key. Note: SPY.US, used in this example, is not on the demo list, and the <a href=\"https:\/\/eodhd.com\/financial-apis\/tick-data-api-us-stock-market\" target=\"_blank\" rel=\"noreferrer noopener\">US tick data API<\/a> needs a plan that includes it, so a registered key with that access is required to run the code as it is.<br>\n2. Register to get your free API key (limited to 20 API calls per day) with access to <a href=\"https:\/\/eodhd.com\/financial-apis\/api-for-historical-data-and-volumes\" target=\"_blank\" rel=\"noreferrer noopener\">End-Of-Day Historical Data<\/a> with only the past year for any ticker, and the <a href=\"https:\/\/eodhd.com\/financial-apis\/exchanges-api-list-of-tickers-and-trading-hours\" target=\"_blank\" rel=\"noreferrer noopener\">list of tickers per exchange<\/a>.<br>\n3. To unlock your API key, we recommend choosing the subscription plan which covers your needs.<\/p>\n\n\n\n<p style=\"text-align: center\"><a class=\"maxbutton-1 maxbutton maxbutton-subscribe-to-api external-css btn\" href=\"https:\/\/eodhd.com\/register\"><span class='mb-text'>Register &amp; Get Data<\/span><\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Each request to the Ticks API consumes one API call, and a whole trading session of SPY comes back in a single request, so this post needs one call per trading day.<\/p>\n\n\n\n<h2 id=\"h-downloading-spy-ticks-with-the-eodhd-ticks-api\" class=\"wp-block-heading\">Downloading SPY Ticks with the EODHD Ticks API<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The <a href=\"https:\/\/eodhd.com\/financial-apis\/tick-data-api-us-stock-market\" target=\"_blank\" rel=\"noreferrer noopener\">US tick data API<\/a> (EODHD, n.d.-a) returns the trades of a US stock or ETF for a time range given in Unix seconds: timestamp in milliseconds, price, size in shares, sequence number, venue code and the sale-conditions field sl, among other fields. If the request sets no limit, the whole time range comes back in one response, and it costs one API call however many rows it holds. SPY trades between 341,748 and 616,305 times in a regular session in our sample, so we ask for each session (9:30 to 16:00 New York time) in one request. A compact version of the logic:<\/p>\n\n\n\n            <div class=\"code__wrapper\">\n                <div class=\"code__content\">\n                    \n<pre class=\"wp-block-code has-text-color has-background\" style=\"color:#ffffff;background-color:#000000\"><code class=\"\">import os\nimport requests\nimport pandas as pd\nfrom dotenv import load_dotenv\n\nload_dotenv()                                  # reads EODHD_API_TOKEN from the .env file\nTOKEN = os.getenv(\"EODHD_API_TOKEN\")\nURL = \"https:\/\/eodhd.com\/api\/ticks\"\n\ndef get_ticks(session, t_from, t_to, ticker=\"SPY.US\"):\n    \"\"\"All ticks in [t_from, t_to] (Unix seconds) in one request; no limit parameter is sent.\"\"\"\n    params = {\"api_token\": TOKEN, \"fmt\": \"json\", \"s\": ticker, \"from\": t_from, \"to\": t_to}\n    resp = session.get(URL, params=params, timeout=300)\n    resp.raise_for_status()\n    return pd.DataFrame(resp.json())           # columns: ts, price, shares, seq, mkt, sub_mkt, sl<\/code><\/pre>\n\n                <\/div>\n                <div class=\"code__btns\">\n                    <button class=\"code__copy\" class=\"copy\" title=\"Copy url\">\n                        <svg class=\"code__copy__icon\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n                            <use xlink:href=\"\/img\/icons\/copy.svg#copy\"><\/use>\n                        <\/svg>\n                        <img decoding=\"async\" class=\"code__copy__approve\" alt=\"\" src=\"\/img\/approve_ico.svg\" loading=\"eager\">\n                    <\/button>\n                <\/div>\n            <\/div>\n        \n\n\n<p class=\"wp-block-paragraph\">Each day is saved as one parquet file, so a repeated run downloads only the days that are missing. Records with zero shares are dropped, and the sale-conditions field sl is kept, because the next section uses it.<\/p>\n\n\n\n<h2 id=\"h-off-market-prints-and-how-to-filter-them\" class=\"wp-block-heading\">Off-Market Prints and How to Filter Them<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Our first run on the unfiltered ticks looked wrong. Volume and dollar bars showed a lag-1 autocorrelation of about \u22120.41, which is far from what one expects from 50 bars a day on a liquid ETF. The reason sits in a handful of trades. Some prints are reported at a price clearly away from the surrounding trades, and some of them are large. A bar closes on the tick that pushes the running total over the bar size, and a large trade is much more likely to be that tick than a small one. The off-market price then becomes the closing price of the bar: the return into that bar contains a spurious jump and the next return jumps back, which is what a negative autocorrelation looks like.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The off-market print filter we use is deliberately simple. A tick is dropped, price and size together, if its price differs by more than 0.25% from the median price of the 201 ticks around it, 100 before and 100 after.<\/p>\n\n\n\n<p align=\"center\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Off_Market_Print_Filter-scaled.png\" alt=\"Formula for the off-market print filter: drop a tick if its price differs from the median price of the 201 surrounding ticks by more than 0.25 percent\" style=\"width:768px;max-width:100%;height:auto\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Both numbers are pragmatic choices, not estimated values. A deviation of 0.25% is far outside the normal tick-to-tick noise of SPY, and on the five days we used to test it, the set of removed ticks hardly changed when the window was anywhere between 51 and 1,001 ticks.<\/p>\n\n\n\n            <div class=\"code__wrapper\">\n                <div class=\"code__content\">\n                    \n<pre class=\"wp-block-code has-text-color has-background\" style=\"color:#ffffff;background-color:#000000\"><code class=\"\">def clean_day(day, pct=0.25, window=201):\n    \"\"\"Drop off-market prints from one day of ticks (columns: ts, price, shares).\"\"\"\n    med = day[\"price\"].rolling(window, center=True, min_periods=1).median()\n    dev_pct = 100.0 * (day[\"price\"] - med).abs() \/ med\n    drop = (dev_pct &gt; pct).to_numpy()\n    return day.loc[~drop].reset_index(drop=True)<\/code><\/pre>\n\n                <\/div>\n                <div class=\"code__btns\">\n                    <button class=\"code__copy\" class=\"copy\" title=\"Copy url\">\n                        <svg class=\"code__copy__icon\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n                            <use xlink:href=\"\/img\/icons\/copy.svg#copy\"><\/use>\n                        <\/svg>\n                        <img decoding=\"async\" class=\"code__copy__approve\" alt=\"\" src=\"\/img\/approve_ico.svg\" loading=\"eager\">\n                    <\/button>\n                <\/div>\n            <\/div>\n        \n\n\n<p class=\"wp-block-paragraph\">Over the 25 days the filter removes 598 ticks, which is 0.005% of all ticks but 8.99% of all shares traded. On the 20 analysis days alone it removes 519 ticks (0.006%) that carry 9.63% of the shares. The same filter is applied to the warm-up days and to the analysis days. At the end of the post we show the results with and without it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What are these prints? The venue code and the sale-conditions field sl of the API answer that question. All 598 removed ticks carry the venue code D, which EODHD lists as the FINRA Alternative Display Facility, so they were traded off the exchanges and reported through a FINRA trade reporting facility (596 through the Nasdaq facility and 2 through the NYSE one, according to sub_mkt). They are real trades, not errors in the data. The table splits them by the letters of their sale conditions.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\" id=\"SPY_Removed_Ticks_by_Sale_Condition_Table\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/SPY_Removed_Ticks_by_Sale_Condition_Table.png\" alt=\"Table of the ticks removed by the filter, split by sale condition: contingent trades, bunched trades, odd lots and other\" style=\"width:803px\" \/><figcaption class=\"wp-element-caption\">Notes: The ticks removed by the off-market print filter over the 25 days, grouped by the letters of their sale-conditions field sl; a tick that carries V is counted under V, otherwise under B, otherwise under I. Letter meanings as listed by EODHD (n.d.-a). Source: Author&#8217;s own elaboration based on data from EODHD (n.d.-b).<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The price rule does not catch every trade of this kind. Over the 25 days, 7,941 ticks carry the condition V, together 11.3% of all shares, and the filter removes 428 of them, the ones that lie furthest from the market.<\/p>\n\n\n\n<h2 id=\"h-forming-the-bars\" class=\"wp-block-heading\">Forming the Bars<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Bars are formed inside each trading day. At 9:30 the running total starts at zero. A bar closes on the first tick that brings the running total to the bar size or above, the closing price is the price of that tick, and the running total then returns to zero. Ticks left over at 16:00 form an unfinished bar, which we drop. The return of a bar is the log change of its closing price from the previous bar of the same day, so the first bar of each day has no return.<\/p>\n\n\n\n<p align=\"center\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Bar_Closing_Rule-scaled.png\" alt=\"Formula for the bar closing rule: a bar closes on the first tick where the running total since the previous close reaches the bar size; each tick adds 1 for tick bars, its shares for volume bars, and price times shares for dollar bars\" style=\"width:792px;max-width:100%;height:auto\"><\/p>\n\n\n\n<p align=\"center\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Bar_Size_From_Warm_Up_Days-scaled.png\" alt=\"Formula for the bar size: the average daily activity over the 5 warm-up days divided by 50 bars per day, rounded to two significant figures\" style=\"width:583px;max-width:100%;height:auto\"><\/p>\n\n\n\n<p align=\"center\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Warm_Up_Day_Activity_Definition.png\" alt=\"Formula for the total activity of one warm-up day: the sum over its ticks of 1 for tick bars, shares for volume bars, and price times shares for dollar bars\" style=\"width:347px;max-width:100%;height:auto\"><\/p>\n\n\n\n<p>How large should a bar be? We aim at about 50 bars per day for every type. To avoid look-ahead, the bar sizes come only from the five trading days before the analysis window, 1 to 8 September 2026 (7 September was a US holiday). The size is the average daily number of ticks, shares or dollars of those days, divided by 50 and rounded to two significant figures, and it stays fixed for all 20 analysis days. In the formula above, <img decoding=\"async\" alt=\"A sub w, superscript k: total activity of bar type k on warm-up day w\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Warm_Up_Day_Activity_A_w_k.png\" style=\"height:1.5750em;vertical-align:-0.2845em;display:inline\"> is the total traded on warm-up day w, measured in the unit of the bar type: it adds up the same quantity <img decoding=\"async\" alt=\"m sub l: the quantity that tick l adds to the running total\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Tick_Increment_m_l.png\" style=\"height:0.8906em;vertical-align:-0.2685em;display:inline\"> as the bar rule, but over all ticks l of that day, so it is the number of ticks for tick bars, the number of shares for volume bars, and the number of dollars (price times shares) for dollar bars. The quantities <img decoding=\"async\" alt=\"v sub l: number of shares of tick l\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Tick_Size_v_l.png\" style=\"height:0.9000em;vertical-align:-0.2769em;display:inline\"> and <img decoding=\"async\" alt=\"p sub l: price of tick l\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Tick_Price_p_l.png\" style=\"height:0.9375em;vertical-align:-0.3151em;display:inline\"> are the number of shares and the price of tick l, and <img decoding=\"async\" alt=\"W equals 5: the number of warm-up days\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Number_of_Warm_Up_Days_W.png\" style=\"height:1.0125em;vertical-align:-0.1696em;display:inline\"> is the number of warm-up days. The book uses a constant bar size for standard bars, and so do we. Time bars use 8 minutes, which gives 48 complete bars in a 6.5-hour session.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\" id=\"SPY_Bar_Sizes_and_Bars_per_Day_Table\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/SPY_Bar_Sizes_and_Bars_per_Day_Table.png\" alt=\"Table of the four bar types, their fixed bar sizes (8 minutes, 8,400 ticks, 560,000 shares, 430 million dollars) and the mean number of bars per day\" style=\"width:410px\" \/><figcaption class=\"wp-element-caption\">Notes: Bar sizes fixed from the five warm-up days, and the resulting number of bars per day on the 20 analysis days. Source: Author&#8217;s own elaboration based on data from EODHD (n.d.-b).<\/figcaption><\/figure>\n\n\n\n            <div class=\"code__wrapper\">\n                <div class=\"code__content\">\n                    \n<pre class=\"wp-block-code has-text-color has-background\" style=\"color:#ffffff;background-color:#000000\"><code class=\"\">def close_indices(measure, T):\n    \"\"\"Index of the tick that closes each bar; the running total restarts at zero.\"\"\"\n    out, acc = [], 0.0\n    for i, m in enumerate(measure):\n        acc += m\n        if acc &gt;= T:\n            out.append(i)\n            acc = 0.0\n    return out\n\n# measure = 1 for every tick (tick bars), shares (volume bars), price * shares (dollar bars)\n\ndef bar_size(warmup, bars_per_day=50, sig=2):\n    \"\"\"Average daily activity over the warm-up days divided by the bars per day.\"\"\"\n    n = warmup[\"date\"].nunique()\n    activity = {\"tick\": len(warmup) \/ n,\n                \"volume\": warmup[\"shares\"].sum() \/ n,\n                \"dollar\": (warmup[\"price\"] * warmup[\"shares\"]).sum() \/ n}\n    return {k: float(f\"{v \/ bars_per_day:.{sig - 1}e}\") for k, v in activity.items()}<\/code><\/pre>\n\n                <\/div>\n                <div class=\"code__btns\">\n                    <button class=\"code__copy\" class=\"copy\" title=\"Copy url\">\n                        <svg class=\"code__copy__icon\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\n                            <use xlink:href=\"\/img\/icons\/copy.svg#copy\"><\/use>\n                        <\/svg>\n                        <img decoding=\"async\" class=\"code__copy__approve\" alt=\"\" src=\"\/img\/approve_ico.svg\" loading=\"eager\">\n                    <\/button>\n                <\/div>\n            <\/div>\n        \n\n\n<p class=\"wp-block-paragraph\">Because the bar sizes are fixed, the number of bars per day is not: a busy day produces more bars than a quiet one. Check a) measures exactly this.<\/p>\n\n\n\n<h2 id=\"h-notation-for-the-four-checks\" class=\"wp-block-heading\">Notation for the Four Checks<\/h2>\n\n\n\n<p>Let <img decoding=\"async\" alt=\"D: the number of analysis days\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Number_of_Days_D.png\" style=\"height:0.9563em;vertical-align:-0.1134em;display:inline\"> = 20 be the number of analysis days and <img decoding=\"async\" alt=\"k: the bar type\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Bar_Type_k.png\" style=\"height:1.0125em;vertical-align:-0.1104em;display:inline\"> the bar type. On day d, <img decoding=\"async\" alt=\"n sub d, superscript k: number of bars of type k on day d\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Bar_Count_n_d_k.png\" style=\"height:1.7438em;vertical-align:-0.4524em;display:inline\"> is the number of bars of type k and <img decoding=\"async\" alt=\"r sub d,i, superscript k: return of the i-th bar of type k on day d\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Bar_Return_r_d_i_k.png\" style=\"height:1.9125em;vertical-align:-0.6208em;display:inline\"> is the return of its i-th bar, with <img decoding=\"async\" alt=\"i equals 2 up to n sub d, superscript k\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Index_i_From_2_To_n.png\" style=\"height:1.7438em;vertical-align:-0.4524em;display:inline\">. All returns of one type together number <img decoding=\"async\" alt=\"N superscript k: total number of returns for bar type k\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Return_Count_N_k.png\" style=\"height:1.2188em;vertical-align:-0.0952em;display:inline\">. The sample variance of the returns of one day is <img decoding=\"async\" alt=\"Sample variance of the returns on day d for bar type k\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Daily_Variance_Sigma_Hat_d_k.png\" style=\"height:1.7438em;vertical-align:-0.4523em;display:inline\">.<\/p>\n\n\n\n<p align=\"center\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Bar_Return_Definition.png\" alt=\"Formula for the bar return: the natural log of the closing price of bar i divided by the closing price of bar i minus 1, for i from 2 to the number of bars that day\" style=\"width:353px;max-width:100%;height:auto\"><\/p>\n\n\n\n<p align=\"center\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Total_Return_Count.png\" alt=\"Formula for the total number of returns: the sum over days of the bar count minus 1\" style=\"width:210px;max-width:100%;height:auto\"><\/p>\n\n\n\n<p align=\"center\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Daily_Return_Variance-scaled.png\" alt=\"Formula for the sample variance of the returns of one day, and for the mean return of that day\" style=\"width:622px;max-width:100%;height:auto\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With 20 days, checks a) and c) rest on 20 numbers each. To see how much they could move, we resample the 20 days with replacement 2,000 times, recompute the statistic each time, and report the 2.5th and 97.5th percentiles as a 95% bootstrap interval.<\/p>\n\n\n\n<h2 id=\"h-check-a-how-stable-is-the-daily-number-of-bars\" class=\"wp-block-heading\">Check a): How Stable Is the Daily Number of Bars?<\/h2>\n\n\n\n<p>We count the bars on each day, <img decoding=\"async\" alt=\"n sub d, superscript k: number of bars of type k on day d\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Bar_Count_n_d_k.png\" style=\"height:1.7438em;vertical-align:-0.4524em;display:inline\">, and compare the spread of the counts across days with their mean. The coefficient of variation <img decoding=\"async\" alt=\"CV superscript k: coefficient of variation for bar type k\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Coefficient_of_Variation_CV_k.png\" style=\"height:1.2937em;vertical-align:-0.1125em;display:inline\"> is the standard deviation of the daily counts divided by their mean, so a smaller value means a steadier count. Time bars score zero by construction and serve only as a reference.<\/p>\n\n\n\n<p align=\"center\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Mean_and_Std_of_Daily_Bar_Count-scaled.png\" alt=\"Formulas for the mean and the standard deviation of the daily number of bars across the analysis days\" style=\"width:573px;max-width:100%;height:auto\"><\/p>\n\n\n\n<p align=\"center\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Coefficient_of_Variation_of_Daily_Bar_Count.png\" alt=\"Formula for the coefficient of variation: the standard deviation of the daily bar count divided by its mean\" style=\"width:138px;max-width:100%;height:auto\"><\/p>\n\n\n\n<h2 id=\"h-check-b-how-large-is-the-serial-correlation-of-returns\" class=\"wp-block-heading\">Check b): How Large Is the Serial Correlation of Returns?<\/h2>\n\n\n\n<p>We correlate each return with the previous return of the same bar type. Pairs never cross the overnight gap, because the first bar of a day has no return. The correlation is <img decoding=\"async\" alt=\"Estimated lag-1 autocorrelation for bar type k\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Lag1_Autocorrelation_Rho_Hat_k.png\" style=\"height:1.4625em;vertical-align:-0.3383em;display:inline\">, computed over <img decoding=\"async\" alt=\"M superscript k: number of return pairs for bar type k\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Pair_Count_M_k.png\" style=\"height:1.2188em;vertical-align:-0.0952em;display:inline\"> pairs, and if returns were independent, about 95% of the values would fall inside <img decoding=\"async\" alt=\"Plus or minus 1.96 divided by the square root of M\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Autocorrelation_Band.png\" style=\"height:1.5656em;vertical-align:-0.3949em;display:inline\">. The symbols with a minus and a plus sign below denote the averages of the lagged and of the current returns over all pairs.<\/p>\n\n\n\n<p align=\"center\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Lag1_Autocorrelation_of_Bar_Returns-scaled.png\" alt=\"Formula for the lag-1 autocorrelation of bar returns: the sum of products of consecutive return deviations divided by the square root of the product of the two sums of squared deviations\" style=\"width:568px;max-width:100%;height:auto\"><\/p>\n\n\n\n<p align=\"center\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Autocorrelation_Pair_Count_and_Band-scaled.png\" alt=\"Formula for the number of return pairs M as the sum over days of the bar count minus 2, and the 95 percent band under independence, plus or minus 1.96 divided by the square root of M\" style=\"width:697px;max-width:100%;height:auto\"><\/p>\n\n\n\n<h2 id=\"h-check-c-how-stable-is-the-daily-variance-of-returns\" class=\"wp-block-heading\">Check c): How Stable Is the Daily Variance of Returns?<\/h2>\n\n\n\n<p>Each day has one variance. If a bar type samples the market in a stable way, its daily variances should be similar from day to day. We take the variance of the 20 daily variances. Because the bar types have different variance scales, we also divide it by the squared mean variance, which gives the scale-free number <img decoding=\"async\" alt=\"Relative variance of the daily variances for bar type k\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Relative_Variance_of_Variances_V_k.png\" style=\"height:1.7438em;vertical-align:-0.4525em;display:inline\"> that can be compared across types.<\/p>\n\n\n\n<p align=\"center\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Variance_of_Daily_Variances-scaled.png\" alt=\"Formulas for the mean of the daily variances and for the variance of the daily variances\" style=\"width:598px;max-width:100%;height:auto\"><\/p>\n\n\n\n<p align=\"center\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Relative_Variance_of_Variances.png\" alt=\"Formula for the relative variance of the daily variances: the variance of the daily variances divided by the squared mean daily variance\" style=\"width:164px;max-width:100%;height:auto\"><\/p>\n\n\n\n<h2 id=\"h-check-d-how-close-to-normal-are-the-returns\" class=\"wp-block-heading\">Check d): How Close to Normal Are the Returns?<\/h2>\n\n\n\n<p>We pool the <img decoding=\"async\" alt=\"N superscript k: total number of returns for bar type k\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Return_Count_N_k.png\" style=\"height:1.2188em;vertical-align:-0.0952em;display:inline\"> returns of all days and compute the Jarque-Bera statistic <img decoding=\"async\" alt=\"JB superscript k: Jarque-Bera statistic for bar type k\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Jarque_Bera_Statistic_JB_k.png\" style=\"height:1.2937em;vertical-align:-0.1089em;display:inline\"> from their skewness and excess kurtosis. For normal returns it is close to zero and follows a <img decoding=\"async\" alt=\"Chi-square distribution with 2 degrees of freedom\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Chi_Square_Two_Degrees.png\" style=\"height:1.4625em;vertical-align:-0.4515em;display:inline\"> distribution, so large values reject normality. As in the book, we use the statistic itself to rank the bar types.<\/p>\n\n\n\n<p align=\"center\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Skewness_and_Excess_Kurtosis_of_Pooled_Returns-scaled.png\" alt=\"Formulas for the skewness and the excess kurtosis of the pooled returns, computed from their central moments\" style=\"width:715px;max-width:100%;height:auto\"><\/p>\n\n\n\n<p align=\"center\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Bars_Math_Jarque_Bera_Statistic.png\" alt=\"Formula for the Jarque-Bera statistic: N divided by 6, times the sum of the squared skewness and the squared excess kurtosis divided by 4\" style=\"width:360px;max-width:100%;height:auto\"><\/p>\n\n\n\n<h2 id=\"h-results\" class=\"wp-block-heading\">Results<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The table collects all four checks. Every statistic is computed on the filtered ticks; the bar sizes are the ones from the table above.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\" id=\"SPY_Bar_Checks_Results_Table\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/SPY_Bar_Checks_Results_Table-scaled.png\" alt=\"Table with the results of the four checks for time, tick, volume and dollar bars of SPY\" style=\"width:862px\" \/><figcaption class=\"wp-element-caption\">Notes: Results of checks a) to d) on 20 trading days of SPY, with the off-market print filter. Brackets: 95% bootstrap intervals over days; p-values of the Jarque\u2013Bera test from the chi-square distribution with 2 degrees of freedom. Source: Author&#8217;s own elaboration based on data from EODHD (n.d.-b).<\/figcaption><\/figure>\n\n\n\n<h2 id=\"h-reading-check-a-the-count-is-not-stable\" class=\"wp-block-heading\">Reading Check a): The Count Is Not Stable<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Tick bars have the smallest coefficient of variation (0.141), followed by dollar (0.157) and volume (0.159) bars. The bootstrap intervals overlap almost completely, from 0.09 to 0.20, so 20 days do not separate the three types. More important is what the chart shows: with a fixed bar size, none of the counts is stable. On 16 September, the busiest day of the analysis window with 616,305 ticks, the filtered data gave 73 tick bars and 79 volume bars. On 22 September, the quietest day of the analysis window with 360,983 ticks, it gave 42 tick bars and 46 volume bars. The count follows the day&#8217;s activity, and that is what a fixed bar size means.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\" id=\"SPY_Daily_Bar_Count_by_Bar_Type_Chart\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/SPY_Daily_Bar_Count_by_Bar_Type_Chart.png\" alt=\"Line chart of the number of time, tick, volume and dollar bars per trading day for SPY from 9 September to 6 October 2026\" \/><figcaption class=\"wp-element-caption\">Notes: Bars per trading day. The time-bar count is constant; the three activity-based counts move with the day&#8217;s activity. Volume and dollar bar counts are identical on 14 of the 20 days, so the green line covers the orange one. Source: Author&#8217;s own elaboration based on data from EODHD (n.d.-b).<\/figcaption><\/figure>\n\n\n\n<h2 id=\"h-reading-check-b-small-serial-correlation-everywhere\" class=\"wp-block-heading\">Reading Check b): Small Serial Correlation Everywhere<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">All four estimates are small. Tick bars give 0.043 and time bars \u22120.047, both inside their 95% bands of about \u00b10.06. Volume and dollar bars give \u22120.081 and \u22120.065, just outside the bands of about \u00b10.06. By the criterion of the book, the lowest serial correlation, tick bars win, but by a hair, and we would not read much into differences of this size. A small negative value for volume and dollar bars points in the same direction as the off-market effect described above, so part of it may be large prints that survive the filter. We have not tested that.<\/p>\n\n\n\n<h2 id=\"h-reading-check-c-the-activity-based-bars-are-steadier\" class=\"wp-block-heading\">Reading Check c): The Activity-Based Bars Are Steadier<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Relative to the squared mean, the variance of the daily variances is 0.58 for time bars, against 0.29 for tick, 0.27 for volume and 0.32 for dollar bars: about half for the three activity-based types, and volume bars come out lowest. The bootstrap intervals overlap (time 0.29 to 0.81, volume 0.14 to 0.39), so with 20 days this is an indication, not a proof. The chart shows where the gap comes from. On 16 September the daily variance of time bars is 2.96 times its sample mean, against 1.95 for tick, 1.60 for dollar and 1.35 for volume bars. All types see the same turbulent days, but the activity-based bars swing less.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\" id=\"SPY_Daily_Return_Variance_by_Bar_Type_Chart\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/SPY_Daily_Return_Variance_by_Bar_Type_Chart.png\" alt=\"Line chart of the daily return variance of time, tick, volume and dollar bars for SPY, each divided by its sample mean\" \/><figcaption class=\"wp-element-caption\">Notes: Daily return variance of each bar type divided by its own sample mean. Source: Author&#8217;s own elaboration based on data from EODHD (n.d.-b).<\/figcaption><\/figure>\n\n\n\n<h2 id=\"h-reading-check-d-closer-to-normal-but-not-normal\" class=\"wp-block-heading\">Reading Check d): Closer to Normal, but Not Normal<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">All four types reject normality, with p-values below 10<sup>\u221216<\/sup>, so the ranking matters more than the verdict. Time bars have a Jarque-Bera statistic of 3,151 and an excess kurtosis of 9.0. The activity-based bars are far closer: tick 77 (1.3), volume 224 (2.2) and dollar 342 (2.7). The lowest statistic belongs to tick bars. The QQ plots show the picture: tails are still heavier than normal for every type, but time bars have three returns more than six standard deviations away. Pooling returns across days with different volatility also fattens the tails, so part of the excess kurtosis may come from mixing calm and turbulent days rather than from the bars themselves.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\" id=\"SPY_Bar_Returns_Normal_QQ_Plots_Chart\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/SPY_Bar_Returns_Normal_QQ_Plots_Chart.png\" alt=\"Four normal QQ plots of standardized bar returns for time, tick, volume and dollar bars of SPY\" \/><figcaption class=\"wp-element-caption\">Notes: Normal QQ plots of standardized bar returns, pooled over the 20 days. Source: Author&#8217;s own elaboration based on data from EODHD (n.d.-b).<\/figcaption><\/figure>\n\n\n\n<h2 id=\"h-what-the-filter-changed\" class=\"wp-block-heading\">What the Filter Changed<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The last table repeats the whole analysis on the raw ticks, including the bar sizes, which are now set from the unfiltered warm-up days: 600,000 shares and $460,000,000 instead of 560,000 shares and $430,000,000, while the tick bar size stays at 8,400 ticks. Time bars are identical in both runs. Tick bars hardly move, because the filter removes only 0.006% of the ticks. Volume and dollar bars change completely: the lag-1 autocorrelation goes from \u22120.41 and \u22120.41 to \u22120.08 and \u22120.07, the relative variance of variances from 1.37 and 1.69 to 0.27 and 0.32, and the Jarque-Bera statistic from 5,183 and 5,665 to 224 and 342.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\" id=\"SPY_Bar_Checks_With_and_Without_Filter_Table\"><img decoding=\"async\" src=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/SPY_Bar_Checks_With_and_Without_Filter_Table-scaled.png\" alt=\"Table comparing tick, volume and dollar bar statistics computed on raw ticks and on filtered ticks\" style=\"width:987px\" \/><figcaption class=\"wp-element-caption\">Notes: Tick, volume and dollar bars with and without the off-market print filter (same 20 days; the raw run sets its bar sizes from the unfiltered warm-up days). Time bars are identical in both runs. Source: Author&#8217;s own elaboration based on data from EODHD (n.d.-b).<\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">On the raw ticks, volume and dollar bars would look worse than plain time bars on checks b), c) and d), and a reader could conclude that the activity-based bars do not work. With the filter they look better than time bars on c) and d) and comparable on b). In this experiment, the cleaning of the data decided the answer more than the choice of the bar type.<\/p>\n\n\n\n<h2 id=\"h-caveats\" class=\"wp-block-heading\">Caveats<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">These results come from 20 trading days of one ETF, so they illustrate the method rather than settle the question. The bar sizes are static and were set from only five days. The filter parameters are pragmatic choices, and the check of their sensitivity covered only five days. The price filter removes only the contingent trades that lie furthest from the market, so a filter on the sale conditions themselves would remove more, and we did not test its effect. Daily subsets replace the weekly and monthly subsets of the book, and the bootstrap treats days as independent. Finally, the book works with E-mini futures; SPY has a different microstructure, so the numbers are not directly comparable with those in the book.<\/p>\n\n\n\n<h2 id=\"h-conclusion\" class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A reduced version of Exercise 2.1 on 20 days of SPY ticks gives a mixed but useful picture. Activity-based bars do not give a stable number of bars per day, because a fixed bar size follows the activity. They do give a steadier daily variance than time bars, and returns that are far closer to normal, although still not normal. Serial correlation is small for every type. The most practical lesson sits outside the bars themselves: a few hundred off-exchange trades printed far from the market, 0.006% of the ticks, were enough to distort volume and dollar bars, and a simple price filter fixed that. The sl field shows what kind of trades they are, mostly contingent ones. If you build such bars from tick data, inspect the prints before you trust the statistics.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Natural next steps are a longer window and more tickers, a filter on the sale-condition codes instead of the price, and the imbalance and run bars from the next sections of the same chapter.<\/p>\n\n\n\n<p style=\"text-align: center\"><a class=\"maxbutton-1 maxbutton maxbutton-subscribe-to-api external-css btn\" href=\"https:\/\/eodhd.com\/register\"><span class='mb-text'>Register &amp; Get Data<\/span><\/a><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<p class=\"wp-block-paragraph\">This post is for illustrative and educational purposes only and does not constitute investment advice. The results come from a short sample and a simple data filter, and they have not been validated for trading or risk-management use. Always conduct independent research and consult a qualified professional before making investment decisions. EODHD does not provide financial advice; data may be subject to delays or inaccuracies as described in EODHD&#8217;s terms of use.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">References<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>L\u00f3pez de Prado, M. (2018). <em>Advances in Financial Machine Learning<\/em>. Wiley.<\/li>\n\n\n\n<li>EODHD. (n.d.-a). <a href=\"https:\/\/eodhd.com\/financial-apis\/tick-data-api-us-stock-market\" target=\"_blank\" rel=\"noreferrer noopener\">US Tick Data API documentation<\/a>.<\/li>\n\n\n\n<li>EODHD. (n.d.-b). <a href=\"https:\/\/eodhd.com\/\" target=\"_blank\" rel=\"noreferrer noopener\"><em>EODHD Financial Data APIs<\/em><\/a> [Data set].<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Typically, charts and models in finance look at the market on a clock: one observation every minute, every hour, every day. In Chapter 2 of Advances in Financial Machine Learning, Marcos L\u00f3pez de Prado (2018) argues that this is a poor way to sample a market, because information does not arrive at a constant pace. Bars that close after a fixed number of trades, a fixed number of shares or a fixed amount of money traded should sample the market more evenly, and the returns of such bars should be better behaved.<\/p>\n","protected":false},"author":35,"featured_media":7056,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[42],"tags":[],"coding-language":[30],"ready-to-go-solution":[],"qualification":[31],"financial-apis-category":[],"financial-apis-manuals":[],"class_list":["post-7012","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-stocks-data-analysis-examples","coding-language-python","qualification-experienced","has_thumb"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v21.9 (Yoast SEO v26.7) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Tick, Volume and Dollar Bars in Python with EODHD Tick Data: A Test on SPY | EODHD APIs Academy<\/title>\n<meta name=\"description\" content=\"Build tick, volume and dollar bars in Python from EODHD tick data and test them on SPY: bar counts, autocorrelation, variance stability and normality.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Tick, Volume and Dollar Bars in Python with EODHD Tick Data: A Test on SPY\" \/>\n<meta property=\"og:description\" content=\"Build tick, volume and dollar bars in Python from EODHD tick data and test them on SPY: bar counts, autocorrelation, variance stability and normality.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy\" \/>\n<meta property=\"og:site_name\" content=\"Financial Academy\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/eodhistoricaldata\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-31T12:46:35+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Tick_Volume_and_Dollar_Bars_in_Python_with_EODHD_Tick_Data_A_Test_on_SPY.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1600\" \/>\n\t<meta property=\"og:image:height\" content=\"540\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Dr Krzysztof Ozimek\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@EOD_data\" \/>\n<meta name=\"twitter:site\" content=\"@EOD_data\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Dr Krzysztof Ozimek\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"25 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy#article\",\"isPartOf\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy\"},\"author\":{\"name\":\"Dr Krzysztof Ozimek\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#\/schema\/person\/336127aadd139da968cebcaa479c6bdd\"},\"headline\":\"Tick, Volume and Dollar Bars in Python with EODHD Tick Data: A Test on SPY\",\"datePublished\":\"2026-10-31T12:46:35+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy\"},\"wordCount\":3440,\"publisher\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#organization\"},\"image\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy#primaryimage\"},\"thumbnailUrl\":\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Tick_Volume_and_Dollar_Bars_in_Python_with_EODHD_Tick_Data_A_Test_on_SPY.png\",\"articleSection\":[\"Stocks Data Analysis Examples\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy\",\"url\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy\",\"name\":\"Tick, Volume and Dollar Bars in Python with EODHD Tick Data: A Test on SPY | EODHD APIs Academy\",\"isPartOf\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy#primaryimage\"},\"image\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy#primaryimage\"},\"thumbnailUrl\":\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Tick_Volume_and_Dollar_Bars_in_Python_with_EODHD_Tick_Data_A_Test_on_SPY.png\",\"datePublished\":\"2026-10-31T12:46:35+00:00\",\"description\":\"Build tick, volume and dollar bars in Python from EODHD tick data and test them on SPY: bar counts, autocorrelation, variance stability and normality.\",\"breadcrumb\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy#primaryimage\",\"url\":\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Tick_Volume_and_Dollar_Bars_in_Python_with_EODHD_Tick_Data_A_Test_on_SPY.png\",\"contentUrl\":\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Tick_Volume_and_Dollar_Bars_in_Python_with_EODHD_Tick_Data_A_Test_on_SPY.png\",\"width\":1600,\"height\":540,\"caption\":\"Source: Author\u2019s own illustration.\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/eodhd.com\/financial-academy\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Tick, Volume and Dollar Bars in Python with EODHD Tick Data: A Test on SPY\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#website\",\"url\":\"https:\/\/eodhd.com\/financial-academy\/\",\"name\":\"Financial APIs Academy | EODHD\",\"description\":\"Financial Stock Market Academy\",\"publisher\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/eodhd.com\/financial-academy\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#organization\",\"name\":\"EODHD (EOD Historical Data)\",\"url\":\"https:\/\/eodhd.com\/financial-academy\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2023\/12\/EODHD-Logo.png\",\"contentUrl\":\"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2023\/12\/EODHD-Logo.png\",\"width\":159,\"height\":82,\"caption\":\"EODHD (EOD Historical Data)\"},\"image\":{\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/eodhistoricaldata\",\"https:\/\/x.com\/EOD_data\",\"https:\/\/www.reddit.com\/r\/EODHistoricalData\/\",\"https:\/\/eod-historical-data.medium.com\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#\/schema\/person\/336127aadd139da968cebcaa479c6bdd\",\"name\":\"Dr Krzysztof Ozimek\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/eodhd.com\/financial-academy\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/a6452711c7d6505227f6a6fed1d0fe4e30309b049e5c2c693c8b4a7d6aa484d4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/a6452711c7d6505227f6a6fed1d0fe4e30309b049e5c2c693c8b4a7d6aa484d4?s=96&d=mm&r=g\",\"caption\":\"Dr Krzysztof Ozimek\"},\"description\":\"Quantitative Finance Educator, Researcher, and Author | Close to 30 years of teaching experience\",\"sameAs\":[\"https:\/\/drkrzysztofozimek.com\",\"https:\/\/www.linkedin.com\/in\/krzysztofozimek\/\"],\"url\":\"https:\/\/eodhd.com\/financial-academy\/author\/krzysztofozimek\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Tick, Volume and Dollar Bars in Python with EODHD Tick Data: A Test on SPY | EODHD APIs Academy","description":"Build tick, volume and dollar bars in Python from EODHD tick data and test them on SPY: bar counts, autocorrelation, variance stability and normality.","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:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy","og_locale":"en_US","og_type":"article","og_title":"Tick, Volume and Dollar Bars in Python with EODHD Tick Data: A Test on SPY","og_description":"Build tick, volume and dollar bars in Python from EODHD tick data and test them on SPY: bar counts, autocorrelation, variance stability and normality.","og_url":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy","og_site_name":"Financial Academy","article_publisher":"https:\/\/www.facebook.com\/eodhistoricaldata","article_published_time":"2026-10-31T12:46:35+00:00","og_image":[{"width":1600,"height":540,"url":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Tick_Volume_and_Dollar_Bars_in_Python_with_EODHD_Tick_Data_A_Test_on_SPY.png","type":"image\/png"}],"author":"Dr Krzysztof Ozimek","twitter_card":"summary_large_image","twitter_creator":"@EOD_data","twitter_site":"@EOD_data","twitter_misc":{"Written by":"Dr Krzysztof Ozimek","Est. reading time":"25 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy#article","isPartOf":{"@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy"},"author":{"name":"Dr Krzysztof Ozimek","@id":"https:\/\/eodhd.com\/financial-academy\/#\/schema\/person\/336127aadd139da968cebcaa479c6bdd"},"headline":"Tick, Volume and Dollar Bars in Python with EODHD Tick Data: A Test on SPY","datePublished":"2026-10-31T12:46:35+00:00","mainEntityOfPage":{"@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy"},"wordCount":3440,"publisher":{"@id":"https:\/\/eodhd.com\/financial-academy\/#organization"},"image":{"@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy#primaryimage"},"thumbnailUrl":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Tick_Volume_and_Dollar_Bars_in_Python_with_EODHD_Tick_Data_A_Test_on_SPY.png","articleSection":["Stocks Data Analysis Examples"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy","url":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy","name":"Tick, Volume and Dollar Bars in Python with EODHD Tick Data: A Test on SPY | EODHD APIs Academy","isPartOf":{"@id":"https:\/\/eodhd.com\/financial-academy\/#website"},"primaryImageOfPage":{"@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy#primaryimage"},"image":{"@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy#primaryimage"},"thumbnailUrl":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Tick_Volume_and_Dollar_Bars_in_Python_with_EODHD_Tick_Data_A_Test_on_SPY.png","datePublished":"2026-10-31T12:46:35+00:00","description":"Build tick, volume and dollar bars in Python from EODHD tick data and test them on SPY: bar counts, autocorrelation, variance stability and normality.","breadcrumb":{"@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy#primaryimage","url":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Tick_Volume_and_Dollar_Bars_in_Python_with_EODHD_Tick_Data_A_Test_on_SPY.png","contentUrl":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Tick_Volume_and_Dollar_Bars_in_Python_with_EODHD_Tick_Data_A_Test_on_SPY.png","width":1600,"height":540,"caption":"Source: Author\u2019s own illustration."},{"@type":"BreadcrumbList","@id":"https:\/\/eodhd.com\/financial-academy\/stocks-data-analysis-examples\/tick-volume-dollar-bars-python-eodhd-tick-data-spy#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/eodhd.com\/financial-academy\/"},{"@type":"ListItem","position":2,"name":"Tick, Volume and Dollar Bars in Python with EODHD Tick Data: A Test on SPY"}]},{"@type":"WebSite","@id":"https:\/\/eodhd.com\/financial-academy\/#website","url":"https:\/\/eodhd.com\/financial-academy\/","name":"Financial APIs Academy | EODHD","description":"Financial Stock Market Academy","publisher":{"@id":"https:\/\/eodhd.com\/financial-academy\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/eodhd.com\/financial-academy\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/eodhd.com\/financial-academy\/#organization","name":"EODHD (EOD Historical Data)","url":"https:\/\/eodhd.com\/financial-academy\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/eodhd.com\/financial-academy\/#\/schema\/logo\/image\/","url":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2023\/12\/EODHD-Logo.png","contentUrl":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2023\/12\/EODHD-Logo.png","width":159,"height":82,"caption":"EODHD (EOD Historical Data)"},"image":{"@id":"https:\/\/eodhd.com\/financial-academy\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/eodhistoricaldata","https:\/\/x.com\/EOD_data","https:\/\/www.reddit.com\/r\/EODHistoricalData\/","https:\/\/eod-historical-data.medium.com\/"]},{"@type":"Person","@id":"https:\/\/eodhd.com\/financial-academy\/#\/schema\/person\/336127aadd139da968cebcaa479c6bdd","name":"Dr Krzysztof Ozimek","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/eodhd.com\/financial-academy\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/a6452711c7d6505227f6a6fed1d0fe4e30309b049e5c2c693c8b4a7d6aa484d4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/a6452711c7d6505227f6a6fed1d0fe4e30309b049e5c2c693c8b4a7d6aa484d4?s=96&d=mm&r=g","caption":"Dr Krzysztof Ozimek"},"description":"Quantitative Finance Educator, Researcher, and Author | Close to 30 years of teaching experience","sameAs":["https:\/\/drkrzysztofozimek.com","https:\/\/www.linkedin.com\/in\/krzysztofozimek\/"],"url":"https:\/\/eodhd.com\/financial-academy\/author\/krzysztofozimek"}]}},"jetpack_featured_media_url":"https:\/\/eodhd.com\/financial-academy\/wp-content\/uploads\/2026\/10\/Tick_Volume_and_Dollar_Bars_in_Python_with_EODHD_Tick_Data_A_Test_on_SPY.png","jetpack_shortlink":"https:\/\/wp.me\/pdOdVT-1P6","jetpack_sharing_enabled":true,"acf":[],"_links":{"self":[{"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/posts\/7012","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/users\/35"}],"replies":[{"embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/comments?post=7012"}],"version-history":[{"count":14,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/posts\/7012\/revisions"}],"predecessor-version":[{"id":7112,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/posts\/7012\/revisions\/7112"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/media\/7056"}],"wp:attachment":[{"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/media?parent=7012"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/categories?post=7012"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/tags?post=7012"},{"taxonomy":"coding-language","embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/coding-language?post=7012"},{"taxonomy":"ready-to-go-solution","embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/ready-to-go-solution?post=7012"},{"taxonomy":"qualification","embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/qualification?post=7012"},{"taxonomy":"financial-apis-category","embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/financial-apis-category?post=7012"},{"taxonomy":"financial-apis-manuals","embeddable":true,"href":"https:\/\/eodhd.com\/financial-academy\/wp-json\/wp\/v2\/financial-apis-manuals?post=7012"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}