STRASMORE/EXPLORE 2,469 QUERIES

bos_horizon

Answered against 22 years of US equities and 12 years of US options data and published with the query that produced it. This result is stored as of 2026-09-22, from market-structure-and-break-of-structure.

as of table 5×6read in context →
bos_horizon — 5 rows by 6 columns, computed from US exchange, SIP and OPRA data.
horizon_labelbos_eventscontinuation_pctbase_rate_pctedge_ppback_inside_pct
1 วัน44854.953.31.621.7
3 วัน44859.2563.240.2
5 วัน44857.156.60.549.1
10 วัน44856.958.1-1.262.5
20 วัน44860.760.10.670.8
Rows × columns
5 × 6
Computed
Completeness
No missing values
Source
US exchange, SIP and OPRA market data
Licence
Strasmore terms · free, no signup
Formats
JSON · CSV · the SQL below

What each column holds

Column definitions for bos_horizon, derived from the stored result.
ColumnTypeRangeNotes
horizon_label text 5 distinct values (1 วัน, 10 วัน, 20 วัน…)
bos_events number every row is 448
continuation_pct number 54.9 to 60.7 percent
base_rate_pct number 53.3 to 60.1 percent
edge_pp number -1.2 to 3.2
back_inside_pct number 21.7 to 70.8 percent

Computed from Strasmore's warehouse of US exchange, SIP and OPRA market data. Equity prices are delayed; options greeks and implied volatility are end-of-day. This result is stored, not recomputed on load — it is exactly the numbers that were returned on , and the query below is what returned them.

Run it yourself

This is the exact query behind the result above. Change a ticker, a date or a column and run it against the warehouse — no account, no key. The no-signup tier is smaller than the one this page was computed on; a query that reaches past it comes back saying which plan runs it.

WITH
px AS
(
    SELECT
        ticker,
        date,
        toFloat64(high)  AS h,
        toFloat64(close) AS c
    FROM global_markets.stocks_daily_aggs
    WHERE ticker IN ('AAPL', 'JPM', 'KO', 'MSFT', 'QQQ', 'SPY')
      AND date >= '2021-01-01'
      AND date <  '2026-09-01'
),
sorted AS
(
    SELECT
        ticker,
        arraySort(x -> x.1, groupArray((date, h, c))) AS bars
    FROM px
    GROUP BY ticker
),
arrs AS
(
    SELECT
        ticker,
        arrayMap(x -> x.2, bars) AS highs,
        arrayMap(x -> x.3, bars) AS closes
    FROM sorted
),
pivots AS
(
    SELECT
        ticker,
        highs,
        closes,
        arrayJoin(arrayFilter(i ->
            (i > 3)
            AND (i <= length(highs) - 3)
            AND (highs[i] > arrayMax(arraySlice(highs, i - 3, 3)))
            AND (highs[i] > arrayMax(arraySlice(highs, i + 1, 3))),
            arrayEnumerate(highs))) AS pivot_i
    FROM arrs
),
breaks AS
(
    SELECT
        ticker,
        closes,
        pivot_i,
        highs[pivot_i] AS level,
        pivot_i + 3 + arrayFirstIndex(x -> x > highs[pivot_i], arraySlice(closes, pivot_i + 4, 30)) AS break_i
    FROM pivots
    WHERE arrayFirstIndex(x -> x > highs[pivot_i], arraySlice(closes, pivot_i + 4, 30)) > 0
),
events AS
(
    SELECT
        ticker,
        break_i,
        argMax(level, pivot_i) AS level,
        any(closes)            AS closes
    FROM breaks
    GROUP BY ticker, break_i
),
after_bos AS
(
    SELECT
        n,
        count()                                                    AS bos_events,
        round(100 * avg(closes[break_i + n] > closes[break_i]), 1) AS continuation_pct,
        round(100 * avg(arrayMin(arraySlice(closes, break_i + 1, n)) < level), 1) AS back_inside_pct
    FROM
    (
        SELECT
            break_i,
            level,
            closes,
            arrayJoin([1, 3, 5, 10, 20]) AS n
        FROM events
        WHERE break_i + 20 <= length(closes)
    )
    GROUP BY n
),
base AS
(
    SELECT
        n,
        round(100 * avg(closes[t + n] > closes[t]), 1) AS base_rate_pct
    FROM
    (
        SELECT
            closes,
            t,
            arrayJoin([1, 3, 5, 10, 20]) AS n
        FROM
        (
            SELECT
                closes,
                arrayJoin(arrayEnumerate(closes)) AS t
            FROM arrs
        )
        WHERE t + 20 <= length(closes)
    )
    GROUP BY n
)
SELECT
    concat(toString(a.n), ' วัน')                 AS horizon_label,
    a.bos_events                                   AS bos_events,
    a.continuation_pct                             AS continuation_pct,
    b.base_rate_pct                                AS base_rate_pct,
    round(a.continuation_pct - b.base_rate_pct, 1) AS edge_pp,
    a.back_inside_pct                              AS back_inside_pct
FROM after_bos AS a
INNER JOIN base AS b ON b.n = a.n
ORDER BY a.n
⌘/Ctrl + Enter