{"slug":"double-top-pattern-follow-through","qid":"outcome_mix","label":"outcome_mix","post_title":"double-top-pattern-follow-through","post_url":"/blog/lang/th/double-top-pattern-follow-through#q-outcome_mix","columns":["outcome_label","signal_count","share_pct"],"rows":[{"outcome_label":"ถึงเป้า measured move ก่อน","signal_count":21,"share_pct":24.1},{"outcome_label":"ปิดกลับเหนือเนคไลน์ก่อน","signal_count":65,"share_pct":74.7},{"outcome_label":"ไม่เกิดทั้งสองอย่าง","signal_count":1,"share_pct":1.1}],"shape":"ranking","sql":"WITH\npx AS (\n    SELECT ticker, date,\n           toFloat64(argMax(high, _ingest_time))  AS h,\n           toFloat64(argMax(low, _ingest_time))   AS l,\n           toFloat64(argMax(close, _ingest_time)) AS c\n    FROM global_markets.stocks_daily_aggs\n    WHERE ticker IN ('AAPL','MSFT','NVDA','AMZN','GOOGL','META','JPM','JNJ','KO','XOM')\n      AND date >= '2015-01-01' AND date < today()\n    GROUP BY ticker, date),\nsplits AS (\n    SELECT ticker, groupArray(execution_date) AS split_dates\n    FROM global_markets.stocks_splits\n    WHERE execution_date >= '2014-01-01'\n    GROUP BY ticker),\npivots AS (\n    SELECT ticker, date, h, l, c,\n           toUInt8(h = max(h) OVER (PARTITION BY ticker ORDER BY date ROWS BETWEEN 10 PRECEDING AND 10 FOLLOWING)) AS is_peak\n    FROM px),\nframed AS (\n    SELECT ticker, date, h, is_peak,\n           groupArray(h)       OVER (PARTITION BY ticker ORDER BY date ROWS BETWEEN 60 PRECEDING AND CURRENT ROW) AS h_back,\n           groupArray(l)       OVER (PARTITION BY ticker ORDER BY date ROWS BETWEEN 60 PRECEDING AND CURRENT ROW) AS l_back,\n           groupArray(is_peak) OVER (PARTITION BY ticker ORDER BY date ROWS BETWEEN 60 PRECEDING AND CURRENT ROW) AS p_back,\n           groupArray(c)       OVER (PARTITION BY ticker ORDER BY date ROWS BETWEEN CURRENT ROW AND 90 FOLLOWING) AS c_fwd,\n           groupArray(l)       OVER (PARTITION BY ticker ORDER BY date ROWS BETWEEN CURRENT ROW AND 90 FOLLOWING) AS l_fwd,\n           groupArray(date)    OVER (PARTITION BY ticker ORDER BY date ROWS BETWEEN CURRENT ROW AND 90 FOLLOWING) AS d_fwd\n    FROM pivots),\npaired AS (\n    SELECT ticker, date AS peak2_date, h AS peak2_high, h_back, l_back, c_fwd, l_fwd, d_fwd,\n           arrayFirst(g -> (p_back[61 - g] = 1)\n                       AND (abs((h_back[61 - g] / h) - 1) <= 0.03)\n                       AND (arrayMin(arraySlice(l_back, 61 - g, g + 1)) <= (0.95 * least(h_back[61 - g], h))),\n                      range(15, 61)) AS gap\n    FROM framed\n    WHERE is_peak = 1 AND length(l_back) = 61 AND length(c_fwd) = 91),\nnecked AS (\n    SELECT ticker, peak2_date, gap,\n           greatest(h_back[61 - gap], peak2_high)          AS peak_high,\n           arrayMin(arraySlice(l_back, 61 - gap, gap + 1)) AS neckline,\n           c_fwd, l_fwd, d_fwd\n    FROM (\n        SELECT p.ticker AS ticker, p.peak2_date AS peak2_date, p.peak2_high AS peak2_high,\n               p.h_back AS h_back, p.l_back AS l_back, p.c_fwd AS c_fwd, p.l_fwd AS l_fwd,\n               p.d_fwd AS d_fwd, p.gap AS gap, s.split_dates AS split_dates\n        FROM paired AS p\n        LEFT JOIN splits AS s ON p.ticker = s.ticker)\n    WHERE gap > 0\n      AND arrayCount(d -> (d >= (peak2_date - 150)) AND (d <= (peak2_date + 180)), split_dates) = 0),\nconfirmed AS (\n    SELECT ticker,\n           d_fwd[k_rel + 11] AS confirm_date,\n           arrayFirstIndex(x -> x <= ((2 * neckline) - peak_high), arraySlice(l_fwd, k_rel + 12, 60)) AS target_idx,\n           arrayFirstIndex(x -> x > neckline, arraySlice(c_fwd, k_rel + 12, 60))                      AS recover_idx\n    FROM (SELECT *, arrayFirstIndex(x -> x < neckline, arraySlice(c_fwd, 12, 20)) AS k_rel FROM necked)\n    WHERE k_rel > 0\n    ORDER BY ticker, confirm_date\n    LIMIT 1 BY ticker, confirm_date)\nSELECT\n    tup.1                                   AS outcome_label,\n    tup.2                                   AS signal_count,\n    round(100 * (tup.2 / total_signals), 1) AS share_pct\nFROM (\n    SELECT count() AS total_signals,\n           countIf((target_idx > 0) AND ((recover_idx = 0) OR (target_idx <= recover_idx))) AS n_target,\n           countIf((NOT ((target_idx > 0) AND ((recover_idx = 0) OR (target_idx <= recover_idx)))) AND (recover_idx > 0)) AS n_recover,\n           countIf((target_idx = 0) AND (recover_idx = 0)) AS n_stall\n    FROM confirmed)\nARRAY JOIN [('ถึงเป้า measured move ก่อน', n_target), ('ปิดกลับเหนือเนคไลน์ก่อน', n_recover), ('ไม่เกิดทั้งสองอย่าง', n_stall)] AS tup","computed_at":"2026-09-28T15:45:42.177751+00:00","elapsed":82.801887453}