Strasmore Research
Học tập Matt ConnorBởi Matt Connor · data as of October 6, 2026 · refreshed weekly

Mô hình cốc tay cầm: breakout có thật sự đi tiếp?

Mô hình cốc tay cầm có thực sự đi tiếp sau breakout? Luật vẽ được viết thành ngưỡng cụ thể, đo trên cổ phiếu Mỹ từ 2015, tách kết quả theo khối lượng ngày breakout.

Mô hình cốc tay cầm là mẫu hình giá được dạy nhiều nhất trong tài liệu kiểu CANSLIM, và câu hỏi đáng tiền duy nhất là sau khi giá vượt vành cốc thì nó có đi tiếp hay không. Trên 3632 tín hiệu ở cổ phiếu Mỹ kể từ 2015, dựng bằng một bộ luật cố định ghi rõ ngay bên dưới, 32.7% số breakout chạm mức +10% trước khi giá thủng đáy tay cầm trong 60 ngày tiếp theo. Toàn bộ ngưỡng đều công khai, nên bạn có thể sửa luật rồi đo lại theo cách của mình.

Viết mô hình cốc tay cầm thành luật đo được

Một mẫu hình chỉ kiểm chứng được khi nó có ngưỡng bằng số. Tài liệu phổ thông dạy cốc tay cầm bằng hình vẽ, mà hình vẽ thì mỗi người nhìn một kiểu, nên tỷ lệ thành công ai nói cũng khác. Đây là bộ luật đứng sau mọi con số trong trang này, đo trên giá ngày của cổ phiếu niêm yết tại Mỹ.

  • Xu hướng tăng trước nền giá: giá đóng cửa ở phiên mở đầu nền cao hơn giá đóng cửa của 120 phiên trước đó ít nhất 10%.
  • Thân cốc: cửa sổ 110 phiên, kết thúc 11 phiên trước ngày breakout. Vành cốc là mức giá cao nhất trong cửa sổ đó, đáy cốc là mức thấp nhất.
  • Độ sâu cốc nằm trong khoảng 12% đến 50%, tính từ vành xuống đáy.
  • Tay cầm: 10 phiên liền trước ngày breakout. Toàn bộ giá cao nhất của 10 phiên này nằm dưới vành, đáy tay cầm cao hơn đáy cốc, và mức lùi của tay cầm so với vành không quá một nửa độ sâu cốc.
  • Ngày breakout: giá đóng cửa vượt hẳn vành cốc.
  • Điều kiện thanh khoản, tính ngay tại thời điểm đó: giá trị giao dịch bình quân 50 phiên liền trước từ 100 triệu USD trở lên, giá đóng cửa từ 10 USD.
  • Cách chấm điểm: theo dõi 60 ngày lịch sau breakout, tức khoảng 40 phiên. Tín hiệu được tính là đạt khi giá cao nhất chạm mục tiêu trước ngày giá thấp nhất chạm đáy tay cầm. Chạm cả hai trong cùng một phiên được tính là hỏng.

Vì tay cầm bắt buộc nằm dưới vành, một phiên chỉ được ghi nhận là breakout khi 10 phiên trước đó chưa có phiên nào đóng cửa trên vành. Các phiên tăng tiếp sau đó không bị đếm thành tín hiệu mới. Vành cốc theo luật này thường rơi vào vùng đỉnh 52 tuần của cổ phiếu, dù điều kiện ở đây chỉ nhìn lại 110 phiên, tức khoảng nửa năm.

Tỷ lệ đi tiếp sau breakout là bao nhiêu

Một mẫu hình không có tỷ lệ thành công duy nhất. Nó có một đường cong: mục tiêu càng xa thì tỷ lệ chạm tới càng thấp, trong khi mức dừng vẫn giữ nguyên là đáy tay cầm. Bảng dưới đo cùng một tập tín hiệu ở năm mốc mục tiêu.

Truy vấnTỷ lệ chạm mục tiêu trước khi thủng đáy tay cầm, theo từng mốc
target_labelsignal_counthit_rate_pctstopped_first_pct
+5%363258.231.2
+10%363232.738.9
+15%363217.740.6
+20%363210.441.1
+25%36326.441.2
Câu lệnh SQL chính xác đằng sau mỗi con số
WITH
    universe AS
    (
        SELECT ticker
        FROM global_markets.stocks_daily_aggs
        WHERE date >= '2014-06-01'
          AND ifNull(otc, 0) = 0
          AND ticker NOT IN ('SPCX')
        GROUP BY ticker
        HAVING count() >= 250
           AND avg(toFloat64(close) * volume) >= 2e7
    ),
    daily AS
    (
        SELECT
            ticker,
            date,
            toFloat64(close)  AS close,
            toFloat64(high)   AS high,
            toFloat64(low)    AS low,
            toFloat64(volume) AS volume
        FROM global_markets.stocks_daily_aggs
        WHERE date >= '2014-06-01'
          AND ticker IN (SELECT ticker FROM universe)
    ),
    featured AS
    (
        SELECT
            ticker,
            date,
            close,
            volume,
            max(high)   OVER cup    AS rim,
            min(low)    OVER cup    AS cup_low,
            max(high)   OVER handle AS handle_high,
            min(low)    OVER handle AS handle_low,
            avg(volume) OVER vol50  AS adv50,
            lagInFrame(close, 120)  OVER trend AS base_start_close,
            lagInFrame(close, 240)  OVER trend AS trend_start_close,
            count()     OVER trend  AS history_bars
        FROM daily
        WINDOW
            cup    AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 120 PRECEDING AND 11 PRECEDING),
            handle AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 10 PRECEDING AND 1 PRECEDING),
            vol50  AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 50 PRECEDING AND 1 PRECEDING),
            trend  AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 240 PRECEDING AND CURRENT ROW)
    ),
    signals AS
    (
        SELECT
            ticker,
            date       AS breakout_date,
            close      AS breakout_close,
            handle_low AS handle_low
        FROM featured
        WHERE history_bars = 241
          AND date >= '2015-01-01'
          AND date <= today() - 65
          AND rim > 0
          AND adv50 > 0
          AND close >= 10
          AND adv50 * close >= 1e8
          AND close > rim
          AND handle_high <= rim
          AND handle_low > cup_low
          AND (1 - cup_low / rim) >= 0.12
          AND (1 - cup_low / rim) <= 0.50
          AND (rim - handle_low) / rim <= 0.5 * (1 - cup_low / rim)
          AND base_start_close >= 1.10 * trend_start_close
    ),
    paths AS
    (
        SELECT
            min(if(b.low  <= s.handle_low,            b.date, toDate('2099-12-31'))) AS stop_date,
            min(if(b.high >= s.breakout_close * 1.05, b.date, toDate('2099-12-31'))) AS hit_05,
            min(if(b.high >= s.breakout_close * 1.10, b.date, toDate('2099-12-31'))) AS hit_10,
            min(if(b.high >= s.breakout_close * 1.15, b.date, toDate('2099-12-31'))) AS hit_15,
            min(if(b.high >= s.breakout_close * 1.20, b.date, toDate('2099-12-31'))) AS hit_20,
            min(if(b.high >= s.breakout_close * 1.25, b.date, toDate('2099-12-31'))) AS hit_25
        FROM daily AS b
        INNER JOIN signals AS s ON s.ticker = b.ticker
        WHERE b.date >  s.breakout_date
          AND b.date <= s.breakout_date + 60
        GROUP BY
            s.ticker,
            s.breakout_date,
            s.breakout_close,
            s.handle_low
    )
SELECT
    concat('+', toString(goal.1), '%')                    AS target_label,
    count()                                               AS signal_count,
    round(100 * countIf(goal.2 < stop_date) / count(), 1) AS hit_rate_pct,
    round(100 * countIf(goal.2 >= stop_date
                        AND stop_date < toDate('2099-12-31')) / count(), 1) AS stopped_first_pct
FROM
(
    SELECT
        stop_date,
        arrayJoin([(5, hit_05), (10, hit_10), (15, hit_15), (20, hit_20), (25, hit_25)]) AS goal
    FROM paths
)
GROUP BY target_label
ORDER BY min(goal.1)
Tự chạy truy vấn này

Ở mốc gần nhất +5%, 58.2% số tín hiệu chạm đích trước khi giá quay về đáy tay cầm. Ở mốc +10% con số là 32.7%, còn ở mốc xa nhất +25% chỉ còn 6.4%. Cũng tại mốc +10%, 38.9% số tín hiệu thủng đáy tay cầm trước. Phần còn lại là những trường hợp lình xình, hết 60 ngày mà không chạm mốc nào trong hai mốc.

Đường cong này là thứ nên dùng thay cho câu "cốc tay cầm thắng khoảng 65%" mà bạn hay gặp. Một tỷ lệ chỉ có nghĩa khi gắn với một mục tiêu cụ thể và một mức dừng cụ thể.

Khối lượng ngày breakout có đổi kết quả không

Tài liệu CANSLIM nhấn mạnh khối lượng của phiên vượt vành. Điều kiện đó đo được trực tiếp: lấy khối lượng ngày breakout chia cho khối lượng bình quân 50 phiên trước đó, rồi tách tín hiệu thành từng nhóm. Mục tiêu giữ cố định ở +10%.

Truy vấnTỷ lệ đạt mục tiêu +10%, tách theo khối lượng ngày breakout so với bình quân 50 phiên
volume_bucketsignal_counthit_rate_pctstopped_first_pct
Dưới 1x132931.339.9
1x đến 1,5x123033.841.1
1,5x đến 2x47430.642.4
2x đến 3x3573534.2
Trên 3x2423622.3
Câu lệnh SQL chính xác đằng sau mỗi con số
WITH
    universe AS
    (
        SELECT ticker
        FROM global_markets.stocks_daily_aggs
        WHERE date >= '2014-06-01'
          AND ifNull(otc, 0) = 0
          AND ticker NOT IN ('SPCX')
        GROUP BY ticker
        HAVING count() >= 250
           AND avg(toFloat64(close) * volume) >= 2e7
    ),
    daily AS
    (
        SELECT
            ticker,
            date,
            toFloat64(close)  AS close,
            toFloat64(high)   AS high,
            toFloat64(low)    AS low,
            toFloat64(volume) AS volume
        FROM global_markets.stocks_daily_aggs
        WHERE date >= '2014-06-01'
          AND ticker IN (SELECT ticker FROM universe)
    ),
    featured AS
    (
        SELECT
            ticker,
            date,
            close,
            volume,
            max(high)   OVER cup    AS rim,
            min(low)    OVER cup    AS cup_low,
            max(high)   OVER handle AS handle_high,
            min(low)    OVER handle AS handle_low,
            avg(volume) OVER vol50  AS adv50,
            lagInFrame(close, 120)  OVER trend AS base_start_close,
            lagInFrame(close, 240)  OVER trend AS trend_start_close,
            count()     OVER trend  AS history_bars
        FROM daily
        WINDOW
            cup    AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 120 PRECEDING AND 11 PRECEDING),
            handle AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 10 PRECEDING AND 1 PRECEDING),
            vol50  AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 50 PRECEDING AND 1 PRECEDING),
            trend  AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 240 PRECEDING AND CURRENT ROW)
    ),
    signals AS
    (
        SELECT
            ticker,
            date           AS breakout_date,
            close          AS breakout_close,
            handle_low     AS handle_low,
            volume / adv50 AS rel_volume
        FROM featured
        WHERE history_bars = 241
          AND date >= '2015-01-01'
          AND date <= today() - 65
          AND rim > 0
          AND adv50 > 0
          AND close >= 10
          AND adv50 * close >= 1e8
          AND close > rim
          AND handle_high <= rim
          AND handle_low > cup_low
          AND (1 - cup_low / rim) >= 0.12
          AND (1 - cup_low / rim) <= 0.50
          AND (rim - handle_low) / rim <= 0.5 * (1 - cup_low / rim)
          AND base_start_close >= 1.10 * trend_start_close
    ),
    paths AS
    (
        SELECT
            s.rel_volume                                                             AS rel_volume,
            min(if(b.low  <= s.handle_low,            b.date, toDate('2099-12-31'))) AS stop_date,
            min(if(b.high >= s.breakout_close * 1.10, b.date, toDate('2099-12-31'))) AS hit_date
        FROM daily AS b
        INNER JOIN signals AS s ON s.ticker = b.ticker
        WHERE b.date >  s.breakout_date
          AND b.date <= s.breakout_date + 60
        GROUP BY
            s.ticker,
            s.breakout_date,
            s.breakout_close,
            s.handle_low,
            s.rel_volume
    )
SELECT
    multiIf(rel_volume < 1,   'Dưới 1x',
            rel_volume < 1.5, '1x đến 1,5x',
            rel_volume < 2,   '1,5x đến 2x',
            rel_volume < 3,   '2x đến 3x',
                              'Trên 3x')                    AS volume_bucket,
    count()                                                 AS signal_count,
    round(100 * countIf(hit_date < stop_date) / count(), 1) AS hit_rate_pct,
    round(100 * countIf(stop_date <= hit_date
                        AND stop_date < toDate('2099-12-31')) / count(), 1) AS stopped_first_pct
FROM paths
GROUP BY volume_bucket
ORDER BY min(rel_volume)
Tự chạy truy vấn này

Nhóm Dưới 1x đạt 31.3% trên 1329 tín hiệu. Nhóm Trên 3x đạt 36% trên 242 tín hiệu. Khoảng cách giữa hai đầu bảng chính là toàn bộ giá trị thực nghiệm của câu "breakout phải có khối lượng lớn", và bạn nên nhìn con số đó trước khi nhìn lời khuyên. Bài chỉ báo khối lượng có dự báo được gì không đi sâu hơn vào giới hạn của nhóm chỉ báo này, còn cách tính mẫu số nằm ở bài khối lượng giao dịch bình quân.

Một lưu ý khi đọc cột signal_count: các nhóm khối lượng cao luôn ít tín hiệu hơn hẳn. Tỷ lệ của một nhóm chỉ vài chục quan sát dao động mạnh, và không nên đặt ngang hàng với tỷ lệ của nhóm vài nghìn quan sát.

Con số có ổn định qua từng năm không

Một tỷ lệ gộp mười năm có thể che việc phần lớn kết quả đến từ vài năm thuận lợi. Tách theo năm breakout là cách kiểm tra rẻ nhất.

Truy vấnSố tín hiệu và tỷ lệ đạt mục tiêu +10% theo từng năm breakout
yearsignal_counthit_rate_pct
20159915.2
20166819.1
201736928.2
201829523.7
201925531
202023643.6
202167430.3
202213632.4
202320039
202461837.4
202540833.8
202627440.1
Câu lệnh SQL chính xác đằng sau mỗi con số
WITH
    universe AS
    (
        SELECT ticker
        FROM global_markets.stocks_daily_aggs
        WHERE date >= '2014-06-01'
          AND ifNull(otc, 0) = 0
          AND ticker NOT IN ('SPCX')
        GROUP BY ticker
        HAVING count() >= 250
           AND avg(toFloat64(close) * volume) >= 2e7
    ),
    daily AS
    (
        SELECT
            ticker,
            date,
            toFloat64(close)  AS close,
            toFloat64(high)   AS high,
            toFloat64(low)    AS low,
            toFloat64(volume) AS volume
        FROM global_markets.stocks_daily_aggs
        WHERE date >= '2014-06-01'
          AND ticker IN (SELECT ticker FROM universe)
    ),
    featured AS
    (
        SELECT
            ticker,
            date,
            close,
            volume,
            max(high)   OVER cup    AS rim,
            min(low)    OVER cup    AS cup_low,
            max(high)   OVER handle AS handle_high,
            min(low)    OVER handle AS handle_low,
            avg(volume) OVER vol50  AS adv50,
            lagInFrame(close, 120)  OVER trend AS base_start_close,
            lagInFrame(close, 240)  OVER trend AS trend_start_close,
            count()     OVER trend  AS history_bars
        FROM daily
        WINDOW
            cup    AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 120 PRECEDING AND 11 PRECEDING),
            handle AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 10 PRECEDING AND 1 PRECEDING),
            vol50  AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 50 PRECEDING AND 1 PRECEDING),
            trend  AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 240 PRECEDING AND CURRENT ROW)
    ),
    signals AS
    (
        SELECT
            ticker,
            date       AS breakout_date,
            close      AS breakout_close,
            handle_low AS handle_low
        FROM featured
        WHERE history_bars = 241
          AND date >= '2015-01-01'
          AND date <= today() - 65
          AND rim > 0
          AND adv50 > 0
          AND close >= 10
          AND adv50 * close >= 1e8
          AND close > rim
          AND handle_high <= rim
          AND handle_low > cup_low
          AND (1 - cup_low / rim) >= 0.12
          AND (1 - cup_low / rim) <= 0.50
          AND (rim - handle_low) / rim <= 0.5 * (1 - cup_low / rim)
          AND base_start_close >= 1.10 * trend_start_close
    ),
    paths AS
    (
        SELECT
            s.breakout_date                                                          AS breakout_date,
            min(if(b.low  <= s.handle_low,            b.date, toDate('2099-12-31'))) AS stop_date,
            min(if(b.high >= s.breakout_close * 1.10, b.date, toDate('2099-12-31'))) AS hit_date
        FROM daily AS b
        INNER JOIN signals AS s ON s.ticker = b.ticker
        WHERE b.date >  s.breakout_date
          AND b.date <= s.breakout_date + 60
        GROUP BY
            s.ticker,
            s.breakout_date,
            s.breakout_close,
            s.handle_low
    )
SELECT
    toYear(breakout_date)                                   AS year,
    count()                                                 AS signal_count,
    round(100 * countIf(hit_date < stop_date) / count(), 1) AS hit_rate_pct
FROM paths
GROUP BY year
ORDER BY year
Tự chạy truy vấn này

Bảng trải từ 2015 đến 2026, tức 12 năm breakout. Riêng năm 2015 ghi nhận 99 tín hiệu với tỷ lệ đạt 15.2%. Hai cột đọc kèm nhau mới đủ: số tín hiệu mỗi năm dày lên trong các giai đoạn thị trường leo thang và mỏng đi trong các giai đoạn giá rơi, nên một năm có tỷ lệ cao mà chỉ vài chục tín hiệu không nói lên nhiều điều. Năm cuối bảng chỉ gồm các breakout đã đủ 60 ngày dữ liệu phía sau, vì vậy số tín hiệu của năm đó còn thiếu phần đuôi.

Cổ phiếu thanh khoản thấp hơn thì sao

Cùng một bộ luật, tách theo giá trị giao dịch bình quân 50 phiên trước breakout. Đây là cách nhìn gần nhất với câu hỏi "mẫu hình này có chạy ở hàng thanh khoản thấp không" mà dữ liệu cho phép trả lời.

Truy vấnTỷ lệ đạt mục tiêu +10% theo giá trị giao dịch bình quân trước breakout
liquidity_bucketsignal_counthit_rate_pctstopped_first_pct
Dưới 300 triệu USD21853238.9
300 triệu đến 1 tỷ USD107232.640.3
1 tỷ đến 5 tỷ USD31236.935.6
Trên 5 tỷ USD6341.330.2
Câu lệnh SQL chính xác đằng sau mỗi con số
WITH
    universe AS
    (
        SELECT ticker
        FROM global_markets.stocks_daily_aggs
        WHERE date >= '2014-06-01'
          AND ifNull(otc, 0) = 0
          AND ticker NOT IN ('SPCX')
        GROUP BY ticker
        HAVING count() >= 250
           AND avg(toFloat64(close) * volume) >= 2e7
    ),
    daily AS
    (
        SELECT
            ticker,
            date,
            toFloat64(close)  AS close,
            toFloat64(high)   AS high,
            toFloat64(low)    AS low,
            toFloat64(volume) AS volume
        FROM global_markets.stocks_daily_aggs
        WHERE date >= '2014-06-01'
          AND ticker IN (SELECT ticker FROM universe)
    ),
    featured AS
    (
        SELECT
            ticker,
            date,
            close,
            volume,
            max(high)   OVER cup    AS rim,
            min(low)    OVER cup    AS cup_low,
            max(high)   OVER handle AS handle_high,
            min(low)    OVER handle AS handle_low,
            avg(volume) OVER vol50  AS adv50,
            lagInFrame(close, 120)  OVER trend AS base_start_close,
            lagInFrame(close, 240)  OVER trend AS trend_start_close,
            count()     OVER trend  AS history_bars
        FROM daily
        WINDOW
            cup    AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 120 PRECEDING AND 11 PRECEDING),
            handle AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 10 PRECEDING AND 1 PRECEDING),
            vol50  AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 50 PRECEDING AND 1 PRECEDING),
            trend  AS (PARTITION BY ticker ORDER BY date ROWS BETWEEN 240 PRECEDING AND CURRENT ROW)
    ),
    signals AS
    (
        SELECT
            ticker,
            date                AS breakout_date,
            close               AS breakout_close,
            handle_low          AS handle_low,
            adv50 * close / 1e6 AS adv_usd_mn
        FROM featured
        WHERE history_bars = 241
          AND date >= '2015-01-01'
          AND date <= today() - 65
          AND rim > 0
          AND adv50 > 0
          AND close >= 10
          AND adv50 * close >= 1e8
          AND close > rim
          AND handle_high <= rim
          AND handle_low > cup_low
          AND (1 - cup_low / rim) >= 0.12
          AND (1 - cup_low / rim) <= 0.50
          AND (rim - handle_low) / rim <= 0.5 * (1 - cup_low / rim)
          AND base_start_close >= 1.10 * trend_start_close
    ),
    paths AS
    (
        SELECT
            s.adv_usd_mn                                                             AS adv_usd_mn,
            min(if(b.low  <= s.handle_low,            b.date, toDate('2099-12-31'))) AS stop_date,
            min(if(b.high >= s.breakout_close * 1.10, b.date, toDate('2099-12-31'))) AS hit_date
        FROM daily AS b
        INNER JOIN signals AS s ON s.ticker = b.ticker
        WHERE b.date >  s.breakout_date
          AND b.date <= s.breakout_date + 60
        GROUP BY
            s.ticker,
            s.breakout_date,
            s.breakout_close,
            s.handle_low,
            s.adv_usd_mn
    )
SELECT
    multiIf(adv_usd_mn < 300,  'Dưới 300 triệu USD',
            adv_usd_mn < 1000, '300 triệu đến 1 tỷ USD',
            adv_usd_mn < 5000, '1 tỷ đến 5 tỷ USD',
                               'Trên 5 tỷ USD')             AS liquidity_bucket,
    count()                                                 AS signal_count,
    round(100 * countIf(hit_date < stop_date) / count(), 1) AS hit_rate_pct,
    round(100 * countIf(stop_date <= hit_date
                        AND stop_date < toDate('2099-12-31')) / count(), 1) AS stopped_first_pct
FROM paths
GROUP BY liquidity_bucket
ORDER BY min(adv_usd_mn)
Tự chạy truy vấn này

Nhóm thấp nhất, Dưới 300 triệu USD, đạt 32% trên 2185 tín hiệu, trong khi nhóm Trên 5 tỷ USD đạt 41.3%. Cần nói thẳng một giới hạn: cả bốn nhóm đều từ 100 triệu USD mỗi phiên trở lên, nên bảng này không phải phép thử trên cổ phiếu thanh khoản mỏng thật sự. Với hàng thanh khoản thấp, chi phí vào lệnh và khoảng trượt giá còn chưa được tính vào bất kỳ con số nào ở trên.

Biên độ dao động của HOSE làm mẫu hình méo đi ra sao

Toàn bộ số liệu trên đo bằng cổ phiếu niêm yết tại Mỹ. Không có dữ liệu HOSE, HNX hay UPCoM ở đây, và cũng không nên suy diễn thẳng sang bảng điện trong nước, vì cơ chế giá khác nhau ở một điểm rất lớn.

HOSE áp biên độ 7% mỗi phiên, HNX 10%, UPCoM 15%. Thị trường Mỹ không có trần sàn theo phiên. Một phiên vượt vành cốc ở Mỹ có thể mở gap 8% rồi đóng cửa cách xa vành, và chính cú nhảy đó làm mẫu hình nhìn rõ trên biểu đồ. Trên HOSE, cùng lượng cầu ấy bị chia nhỏ thành chuỗi phiên trần nối tiếp, phần giá chưa kịp thể hiện sẽ dồn sang các phiên sau.

Hai hệ quả rất cụ thể cho người vẽ chart tại Việt Nam. Thứ nhất, điểm breakout không còn là một phiên dứt khoát, mà là một chuỗi phiên, nên luật "giá đóng cửa vượt vành" phải được định nghĩa lại trước khi đo. Thứ hai, cái trông như tay cầm nhiều khi chỉ là vài phiên đi ngang sau khi biên độ đã hết dư địa trong ngày, chứ không phải nhịp chốt lời nông mà lý thuyết mô tả. Vì vậy, tỷ lệ đo trên thị trường Mỹ nên được coi là trần trên cho VN-Index, chứ không phải con số kỳ vọng.

Hai lỗi làm con số đẹp hơn thực tế

Vẽ vành cốc sau khi đã biết kết quả. Khi nhìn lại biểu đồ, mắt người tự động chọn đúng cái vành mà giá đã vượt qua và đi tiếp. Đó là thiên lệch nhìn trước, và nó đủ sức đẩy tỷ lệ thành công của bất kỳ mẫu hình nào lên mức không ai lặp lại được khi giao dịch thật. Bộ luật ở trang này chỉ dùng dữ liệu có trước ngày breakout, kể cả điều kiện thanh khoản, nên không có thông tin tương lai nào lọt vào thời điểm ra tín hiệu. Bài thiên lệch nhìn trước trong backtest mô tả các kiểu rò rỉ thường gặp, còn quy trình backtest một chiến lược nói về cách cố định luật trước khi chạy số.

Breakout khối lượng mỏng ở cổ phiếu ít giao dịch. Ở một mã giao dịch vài tỷ đồng mỗi phiên, một lệnh mua vừa phải cũng đủ đẩy giá qua vành và tạo ra đúng hình dạng mà mẫu hình đòi hỏi. Tín hiệu trông giống hệt nhau trên biểu đồ, nhưng mức giá bạn khớp được lại khác xa mức giá hiển thị. Đó là lý do mọi con số ở trên đều gắn với một ngưỡng thanh khoản tối thiểu, và cũng là lý do bảng cuối cùng được tách theo giá trị giao dịch thay vì gộp chung.

Ghi chú dữ liệu và những giới hạn đã biết
  • Mẫu quan sát gồm cổ phiếu và chứng chỉ quỹ niêm yết tại Mỹ đạt ngưỡng thanh khoản tại thời điểm breakout. Dữ liệu ngày không tách riêng quỹ ETF, nên nhóm này nằm chung trong mẫu.
  • Có một bộ lọc sơ bộ nhằm giảm khối lượng tính toán: chỉ giữ các mã có ít nhất 250 phiên và giá trị giao dịch bình quân toàn giai đoạn từ 20 triệu USD. Điều kiện thực sự ràng buộc vẫn là điều kiện 100 triệu USD tính tại ngày breakout.
  • Các mã đã hủy niêm yết vẫn được tính nếu đạt điều kiện tại thời điểm breakout, nhưng mẫu nghiêng về nhóm vốn hóa lớn còn tồn tại tới nay.
  • Trần độ sâu 50% loại bỏ phần lớn trường hợp méo hình do chia tách cổ phiếu tỷ lệ lớn trong cửa sổ quan sát. Chia tách tỷ lệ nhỏ vẫn có thể lọt vào mẫu.
  • Mọi kết quả đo trên giá ngày, không tính phí giao dịch, thuế hay trượt giá, và không giả định bất kỳ cách quản lý vị thế nào ngoài hai mốc đã nêu.

FAQ

Mô hình cốc tay cầm là gì?

Đó là mẫu hình giá gồm một nhịp giảm rồi hồi phục tạo thành đáy tròn giống lòng cốc, sau đó là một nhịp chỉnh nông hơn sát vành cốc gọi là tay cầm, và kết thúc bằng phiên giá vượt lên trên vành. Trang này quy mỗi phần của mô tả đó thành một ngưỡng bằng số để có thể đếm được.

Tỷ lệ thành công của mô hình cốc tay cầm là bao nhiêu?

Không có một con số duy nhất. Theo bộ luật ở đây, với mục tiêu +10% và mức dừng là đáy tay cầm trong 60 ngày, tỷ lệ đạt là 32.7% trên 3632 tín hiệu ở cổ phiếu Mỹ từ 2015. Đổi mục tiêu hoặc đổi khung thời gian thì con số đổi theo, như bảng đường cong mục tiêu cho thấy.

Tay cầm nên sâu bao nhiêu?

Trong bộ luật này, tay cầm bị giới hạn ở mức lùi không quá một nửa độ sâu của cốc, và đáy tay cầm phải nằm cao hơn đáy cốc. Đây là ngưỡng do chúng tôi đặt ra để đo được, không phải quy ước bắt buộc. Bạn có thể nới hoặc siết ngưỡng này rồi chạy lại để xem tỷ lệ dịch chuyển tới đâu.

Mẫu hình này áp dụng cho cổ phiếu Việt Nam được không?

Hình dạng thì vẫn vẽ được, nhưng con số thì không chuyển thẳng sang được. Biên độ 7% của HOSE cắt nhỏ các cú vượt vành vốn là phần dễ nhận biết nhất của mẫu hình ở thị trường Mỹ, nên tỷ lệ đo trên dữ liệu Mỹ chỉ nên dùng làm trần trên khi đọc biểu đồ trong nước.

Khối lượng ngày breakout quan trọng tới mức nào?

Bảng tách theo khối lượng ở trên trả lời trực tiếp: nhóm Dưới 1x đạt 31.3% còn nhóm Trên 3x đạt 36%. Hãy đọc kèm số lượng tín hiệu của từng nhóm, vì các nhóm khối lượng cao có cỡ mẫu nhỏ hơn nhiều.


Mỗi bảng ở trên đều kèm nguyên văn câu lệnh SQL ngay bên dưới. Bạn mở ra, đổi ngưỡng độ sâu cốc hoặc số phiên của tay cầm, rồi hỏi lại bằng tiếng Việt trên terminal Strasmore để xem con số dịch chuyển tới đâu.

#chart patterns#cup and handle#breakouts#volume#technical analysis