Strasmore Research
למידה Matt Connorמאת Matt Connor · עודכן 2026-08-04

מפסקי מסחר לבוטים: הגבלת הפסדים וגודל פוזיציה

מפסקי מסחר עוצרים בוט לפני שהפסד יומי מחמיר. למדו מתי מגבלת הפסד מופעלת, כיצד התאמת גודל לפי תנודתיות מצמצמת חשיפה, ואיך להגן על החשבון.

מפסקי מסחר לבוטים הם כללים שעוצרים אסטרטגיה אוטומטית מלשלוח פקודות לאחר שהושג גבול שנקבע מראש. הם פועלים בשכבת סיכון שבין האסטרטגיה לברוקר, ומוחלים על כל פקודה, בין אם האסטרטגיה מסכימה לכך ובין אם לאו. האסטרטגיה קובעת במה לסחור. שכבת הסיכון קובעת אם המסחר יתבצע בכלל.

ההפרדה הזו היא לב התכנון. לאסטרטגיה שמפקחת על עצמה אין מנגנון בקרה בלתי תלוי ברגע שבו ההנחות שלה עצמה נשברות — וזה בדיוק הרגע שבו יש ערך למנגנון בקרה.

מה עושה מפסק בטיחות בבוט מסחר

לשכבת ניהול הסיכונים יש ארבעה רכיבים, וכל אחד מהם נועד למנוע כשל מסוים ושגרתי.

  • תקרות קשיחות לגודל הפוזיציה, לחשיפה הנומינלית לכל סימול ולקצב שליחת הפקודות. הן מגבילות את הנזק מבאג, שאחרת עלול להיות בלתי מוגבל.
  • מפסק בטיחות לירידת ערך, שעוצר שליחת פקודות חדשות לאחר שהחשבון ירד בסכום מוגדר במהלך יום המסחר, או לאחר שירד בסכום מוגדר משיא ההון העצמי שלו.
  • קביעת גודל פקודה באופן מדורג, לפי התנודתיות האחרונה או לפי חלק יחסי מהימור Kelly, במקום לפי מספר מניות קבוע. כך הסיכון לעסקה נשאר בקירוב יציב גם כאשר טווח התנודות של השוק משתנה.
  • יומן ביקורת append-only של כל החלטה, לרבות פקודות ששכבת ניהול הסיכונים דחתה. זהו התיעוד היחיד שמאפשר להבחין בין מצב שבו “האסטרטגיה טעתה” לבין מצב שבו הבדיקה כלל לא הופעלה.

כל מה שמופיע להלן הוא המחשה מפורטת של אחד מארבעת הרכיבים האלה.

מהו גבול הפסד יומי סביר עבור בוט מסחר?

גבול הפסד יומי עוצר פקודות חדשות לאחר שההפסד במהלך יום המסחר חוצה סף מסוים. בחירת המספר היא תהליך כיול, לא עניין של העדפה: אם קובעים אותו בתוך טווח הרעש הרגיל של השוק, הבוט יישאר מושבת ברוב השבועות; אם קובעים אותו רחוק מדי, הוא לעולם לא יופעל. נקודת המוצא היא התדירות שבה השוק עצמו מציג יום ירידות בהיקף נתון.

שאילתהימי ירידה של SPY לפי גודל, לשנה, 2018 עד יולי 2026
ה-SQL המדויק מאחורי כל מספר
WITH daily AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2017-12-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY d
),
with_prev AS (
    SELECT d,
           close_px,
           any(close_px) OVER (ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_close
    FROM daily
)
SELECT toYear(d) AS year,
       countIf(close_px / prev_close - 1 <= -0.01) AS down_1pct_days,
       countIf(close_px / prev_close - 1 <= -0.02) AS down_2pct_days,
       countIf(close_px / prev_close - 1 <= -0.03) AS down_3pct_days
FROM with_prev
WHERE prev_close > 0
  AND d >= toDate('2018-01-01')
GROUP BY year
ORDER BY year
Run this yourself

מספר ימי המסחר שבהם הירידה הייתה 1% או יותר הסתכם ב-15 בשנת 2019 וב-45 בשנת 2020, מתוך כ-250 ימי מסחר בשנה. מספר הימים שבהם הירידה הייתה 3% או יותר שונה לחלוטין: 0 בשנת 2019, לעומת 16 בשנת 2020. השורה האחרונה של 9 כוללת נתונים עד 31 ביולי 2026 בלבד.

התמונה אינה יציבה אלא מקוטעת, וזו בדיוק הנקודה. ימים קשים מגיעים באשכולות. בוט שעוצר ביום הראשון של אשכול וחוזר לפעול ביום השני לא באמת עצר.

לשני הספים יש תפקידים שונים. גבול הפסד יומי, העומד בדרך כלל על 2% מההון בחשבון, מסיים את פעילות המסחר באותו יום. גבול drawdown נגרר, הנמדד משיא ההון, עומד בדרך כלל על כ-10% ומפסיק את האסטרטגיה עד לבדיקה אנושית. הראשון נועד לשגרה, ואילו השני אמור להיות נדיר. בוט שמוגבל רק באמצעות הראשון עלול לשחוק את החשבון ב-2% בכל פעם, בלי להפעיל אף מנגנון עצירה.

כיצד שינוי קנה המידה לפי תנודתיות משנה את גודל הפוזיציה?

התאמת גודל הפוזיציה לפי תנודתיות קובעת את גודל הפוזיציה ביחס הפוך לתנודתיות הממומשת בתקופה האחרונה: כאשר הטווח היומי מוכפל, גודל הפוזיציה מצטמצם בערך בחצי, כך שהסיכון הדולרי בכל עסקה נשאר קרוב לקבוע. התנודתיות הממומשת כאן היא סטיית התקן השנתית של התשואות היומיות, והיא משתנה במידה גדולה מכפי שרוב האנשים מצפים.

שאילתההתנודתיות הממומשת של SPY לפי חודש, והפוזיציה שיעד תנודתיות של 12% היה מחזיק
ה-SQL המדויק מאחורי כל מספר
WITH daily AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2023-12-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY d
),
rets AS (
    SELECT d,
           close_px / any(close_px) OVER (ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) - 1 AS ret
    FROM daily
)
SELECT formatDateTime(toStartOfMonth(d), '%Y-%m') AS month,
       round(stddevSamp(ret) * sqrt(252) * 100, 1) AS realized_vol_pct,
       round(least(100.0, 1200.0 / (stddevSamp(ret) * sqrt(252) * 100)), 1) AS vol_target_size_pct
FROM rets
WHERE d >= toDate('2024-01-01')
  AND isFinite(ret)
GROUP BY toStartOfMonth(d)
HAVING count() >= 15
ORDER BY toStartOfMonth(d)
Run this yourself

התנודתיות הממומשת, במונחים שנתיים, נמדדה 11.1% ב-2024-01 וב-12% ב-2026-07, לאורך 31 חודשים. העמודה השנייה ממירה כל נתון לגודל הפוזיציה שהייתה נושאת יעד תנודתיות של 12%, עד לתקרה של מלוא השורה: 100% לעומת 2024-01, מול 99.7% לעומת 2026-07. אותה אסטרטגיה, אותה מידת ביטחון, אך מספר מניות שונה לחלוטין.

קריטריון Kelly ניגש לאותה בעיה מהכיוון ההפוך. הוא קובע את גודל הפוזיציה לפי היתרון המשוער והשונות, ולא לפי התנודתיות בלבד. רוב המפעילים השיטתיים משתמשים בחלק מקריטריון זה — חצי Kelly או רבע Kelly — משום ששני הנתונים הם אומדנים המבוססים על מדגם סופי. קביעת גודל פוזיציה לפי קריטריון Kelly מסבירה את החישוב הזה.

מדוע בוט מסחר ממשיך להיכנס מחדש לאחר הפעלת פקודת עצירת הפסד?

פקודת עצירת הפסד מופעלת. הפוזיציה נסגרת. תשעים שניות לאחר מכן תנאי הכניסה מתקיים שוב, הבוט נכנס מחדש, סופג את אותו הפסד וחוזר על התהליך. אף רכיב יחיד אינו תקול. האסטרטגיה ביצעה את מה שתוכנתה לבצע, פקודת העצירה ביצעה את מה שתוכנתה לבצע, ובכל זאת החשבון ממשיך להישחק, עסקה הלוך ושוב אחת בכל פעם.

התדירות נובעת ישירות ממסלול המחיר. פאנל זה סופר, לכל סשן, כמה פעמים SPY נע ממחיר הגבוה ביותר מ־0.1% ממחיר הפתיחה שלו למחיר הנמוך ביותר מ־0.1% ממנו, או בכיוון ההפוך.

שאילתהבאיזו תדירות SPY חוצה מחדש את מחיר הפתיחה שלו, בכל סשן, לפי חודש
ה-SQL המדויק מאחורי כל מספר
WITH mins AS (
    SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           window_start AS ts,
           toFloat64(close) AS px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2025-08-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
),
opens AS (
    SELECT d, argMin(px, ts) AS open_px
    FROM mins
    GROUP BY d
),
zoned AS (
    SELECT m.d AS d,
           m.ts AS ts,
           multiIf(m.px >= o.open_px * 1.001, 1,
                   m.px <= o.open_px * 0.999, -1,
                   0) AS zone
    FROM mins AS m
    INNER JOIN opens AS o ON m.d = o.d
),
flips AS (
    SELECT d,
           zone,
           any(zone) OVER (PARTITION BY d ORDER BY ts ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_zone
    FROM zoned
    WHERE zone != 0
),
per_day AS (
    SELECT d, countIf(prev_zone != 0 AND zone != prev_zone) AS crossings
    FROM flips
    GROUP BY d
)
SELECT formatDateTime(toStartOfMonth(d), '%Y-%m') AS month,
       round(avg(crossings), 1) AS avg_crossings_per_session,
       max(crossings) AS max_crossings_in_a_session
FROM per_day
GROUP BY toStartOfMonth(d)
ORDER BY toStartOfMonth(d)
Run this yourself

SPY חצה את הטווח הזה בממוצע 0.7 פעמים בכל סשן בשנת 2025-08, ו־1.5 פעמים בשנת 2026-07. בסשן אחד בשנת 2026-07 נרשמו 5 חציות. לכל כלל שפותח פוזיציה בצד אחד של רמה ומפעיל עצירה בצדה האחר יש מספר כזה של הזדמנויות לפעול במהלך יום אחד.

ארבעה מנגנונים מגבילים את התופעה.

  • תקופת צינון לאחר כל הפעלת עצירת הפסד, הנמדדת בדקות או בנרות, שבמהלכה שום הוראה חדשה עבור אותו סימול אינה עוברת את שכבת ניהול הסיכון.
  • תקרת מספר עסקאות יומית לכל סימול, שהופכת לולאה בלתי מוגבלת ללולאה מוגבלת.
  • דגל עצירה שננעל במצבו. לאחר שמגבלת ההפסד היומית מופעלת, הדגל נשאר פעיל עד שאדם מאפס אותו.
  • שמירת הדגל מחוץ לזיכרון התהליך. מפקח שמפעיל מחדש בוט שקרס מוסר לו מצב התחלתי נקי, ומצב כזה הוא בדיוק מה שהדגל נועד למנוע.

הנקודה האחרונה מפתיעה מי שטיפל נכון בכל השאר. בוטים למסחר בגריד מציבים בכוונה סדרות מדורגות של הוראות, ולכן תקרת מספר העסקאות היא רכיב הכרחי ולא קישוט.

מה קורה כאשר בוט סוחר לפי פיד מחירים שאינו מעודכן?

ציטוט שהפסיק להתעדכן עדיין נראה כמו מספר. הבוט קורא אותו, מתמחר לפיו פקודה ושולח אותה לשוק שכבר נע. הכשל שקט: שום דבר אינו מעלה שגיאה, שום שגיאה אינה נרשמת, והעסקאות שבוצעו נראות מוזרות רק בדיעבד.

הגרסה שקל למדוד היא פער הפתיחה, שבו מחיר ידוע נותר ללא שינוי במשך שעות, בזמן שהמחיר הניתן למסחר משתנה.

שאילתהפער לילה מסגירת היום הקודם לפתיחת היום הבא: שש מניות, ינואר 2024 עד יולי 2026
ה-SQL המדויק מאחורי כל מספר
WITH daily AS (
    SELECT ticker,
           toDate(toTimeZone(window_start, 'America/New_York')) AS d,
           argMin(toFloat64(open), window_start) AS open_px,
           argMax(toFloat64(close), window_start) AS close_px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('SPY', 'KO', 'MSFT', 'AAPL', 'NVDA', 'TSLA')
      AND toDate(toTimeZone(window_start, 'America/New_York')) >= toDate('2024-01-01')
      AND toDate(toTimeZone(window_start, 'America/New_York')) <= toDate('2026-07-31')
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
    GROUP BY ticker, d
),
gaps AS (
    SELECT ticker,
           d,
           open_px,
           any(close_px) OVER (PARTITION BY ticker ORDER BY d ASC ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) AS prev_close
    FROM daily
)
SELECT ticker,
       round(quantileDeterministic(0.5)(abs(open_px / prev_close - 1) * 100, cityHash64(ticker, d)), 2) AS median_gap_pct,
       round(quantileDeterministic(0.95)(abs(open_px / prev_close - 1) * 100, cityHash64(ticker, d)), 2) AS p95_gap_pct,
       round(max(abs(open_px / prev_close - 1) * 100), 2) AS max_gap_pct
FROM gaps
WHERE prev_close > 0
GROUP BY ticker
ORDER BY p95_gap_pct DESC
Run this yourself

המניה עם פער המחיר הרחב ביותר באחוזון ה־95 הייתה TSLA, עם 4.41%, לעומת 1% עבור KO. בלילות רגילים התנודות היו מתונות בהרבה: פער חציוני של 1.01% ושל 0.24%, בהתאמה. שכבות ניהול סיכונים נבנות כדי להתמודד עם זנבות ההתפלגות, והפער החד־פעמי הגדול ביותר ב־TSLA במהלך חלון המדידה עמד על 14.57%. אלה המרחקים שבוט עומד בפניהם כאשר הוא פועל לפי מחיר שקרא לפני זמן מה. מדוע מניות נפתחות בפער מסביר את המנגנון.

אמצעי ההגנה פשוטים וזולים. יש להגדיר גיל מרבי לכל ציטוט שעל פיו שכבת ניהול הסיכונים מתמחרת, בדרך כלל כמה שניות באסטרטגיית מסחר תוך־יומית. יש לקבל מהפיד אות heartbeat בנפרד מהנתונים עצמם. כך ניתן להבחין בין חיבור שקט לבין שוק שקט. יש להתייחס לנתונים חסרים כאל עצירת מסחר ולא כאל מצב שבו המחיר נותר ללא שינוי, משום שבוט ללא מחירים אינו יכול להעריך גם את פקודות היציאה שלו.

אילו תקרות קשיחות צריכות להיכלל בשכבת הסיכון?

  • שווי נומינלי מרבי לכל סימול, כחלק מההון בחשבון. תקרה של 10% מונעת מסימול בעייתי אחד לסכן את החשבון כולו.
  • שווי נומינלי ברוטו מרבי בכל הפוזיציות הפתוחות. קביעה של 100% מההון פירושה שאין מינוף. זו החלטה שראוי לקבל במפורש, במקום לרשת אותה מהגדרת ברירת המחדל של הברוקר.
  • קצב פקודות מרבי, לדקה וליום. עשר פקודות בדקה הן קצב נדיב לרוב האסטרטגיות הקמעונאיות, ובכל זאת הוא מגביל לולאה שיוצאת משליטה בתוך דקה.
  • גודל פקודה מרבי, כחלק מהמחזור היומי הממוצע של הסימול. תקרה של 1% מונעת מבוט להזיז את המחיר שבו הוא מנסה לסחור, ו-המחזור היומי הממוצע הוא המכנה.

כל אחד מהפריטים האלה שייך לשכבת הסיכון ולא לאסטרטגיה, וכולם צריכים לפעול באמצעות אותו נתיב קוד בבדיקת עבר, במסחר על הנייר ובמסחר חי. מגבלה שקיימת רק במסחר חי היא מגבלה שאיש לא בדק.

מה צריך לכלול יומן ביקורת של בוט מסחר?

יומן שמאפשר הוספה בלבד כותב רשומה אחת לכל החלטה, ולעולם אינו עורך או מוחק רשומות. כל רשומה כוללת את חותמת הזמן, את הציטוט ששימש להחלטה ואת גילו, כל בדיקת מגבלה שהופעלה ואת תוצאתה, את הפקודה שנשלחה ואת תשובת הברוקר. פקודות שנדחו נרשמות באותה רמת פירוט כמו פקודות שבוצעו.

המטרה היא לאפשר שחזור. שישה שבועות לאחר יום מסחר גרוע, השאלה אינה מה היה ה-P&L. השאלה היא איזו בדיקה עברה, ועל סמך איזו קלט. ללא הקלט המתועד, תיאלצו להסיק מחדש את מצב הבוט ממצב השוק. זו אותה טעות כמו הטיית look-ahead בבדיקת אסטרטגיות היסטורית: שימוש במידע שלא היה בידי המערכת בזמן קבלת ההחלטה.

פרויקט riskguard הוא מימוש אחד בקוד פתוח להפרדה הזו. בו בדיקות המגבלות נמצאות ברכיב שהאסטרטגיה קוראת לו, במקום בלוגיקה הפזורה בתוך האסטרטגיה עצמה. זהו עיצוב אחד מבין כמה, וכדאי לקרוא עליו לפני שמאמצים אותו באופן אוטומטי. בכל רכיב שאתם מסתמכים עליו, יש להצמיד גרסה מתויגת ולא להשתמש בענף ברירת המחדל. ענף יכול להשתנות בין שתי הרצות של אותה בדיקת אסטרטגיה היסטורית, ושכבת סיכון שהשתנתה בשקט גרועה יותר מהיעדרה.

מדוע הפריסה הראשונה מתבצעת אצל ברוקר לדימוי מסחר

מתאם הברוקר מוגדר כברירת מחדל למסחר דמו, ומסחר אמיתי מחייב במכוון הגדרה מפורשת של דגל. כך נמנעת תקלה שגרתית: קובץ הגדרות שהועתק, או משתנה סביבה שלא נדרס, עלול לשלוח פקודות אמיתיות ולסכן כסף אמיתי.

הרצת דמו גם מפיקה את התוצר החשוב באמת: יומן החלטות מאותה שכבת סיכון, על בסיס מחירים חיים, שמראה אילו מגבלות הופעלו ואילו לא. זהו תיעוד על שכבת הסיכון, ושאלה זו נפרדת מהשאלה אם האסטרטגיה מניבה רווח. מסחר דמו לפני השקעת כסף אמיתי מסביר מה רשומת דמו מוכיחה ומה אינה מוכיחה, ו-מערכות מסחר מבוססות AI מרובות סוכנים מראה מדוע סמכות העצירה חייבת להיות מחוץ לכל סוכן, מרגע שכמה סוכנים יכולים להציב פקודות.

שאלות נפוצות על מפסק הגנה בבוט מסחר

מהו מפסק הגנה בבוט מסחר?

זהו כלל בשכבת ניהול הסיכונים שעוצר את הבוט משליחת פקודות חדשות לאחר שהושג גבול שנקבע מראש. לרוב מדובר בסף הפסד יומי או בירידה משיא ההון בחשבון. הכלל פועל באופן עצמאי מהאסטרטגיה, בכל פקודה, ונשאר מופעל עד לאיפוסו.

באיזו תדירות השוק רושם יום ירידות של 2%?

SPY רשמה 5 ימי מסחר שבהם ירדה ב-2% או יותר בשנת 2019, ו-25 בשנת 2020, מתוך כ-250 ימי מסחר בכל שנה. הפער בין שנה רגועה לשנה תחת לחץ מסביר מדוע יש לכייל את מגבלת ההפסד על בסיס היסטורי ולא על סמך תחושת בטן.

כיצד מונעים מבוט להיכנס מחדש לאחר עצירת הפסד?

חלון צינון לאחר כל עצירה ומכסה יומית על מספר העסקאות בכל סימול הופכים לולאה בלתי מוגבלת ללולאה מוגבלת. דגל העצירה צריך גם להינעל ולהישמר מחוץ לזיכרון התהליך. אחרת, מפקח שמפעיל מחדש בוט שקרס יעניק לו מצב חדש שבו העצירה אינה מופעלת.

כיצד בוט יכול לזהות שפיד המחירים התיישן?

הבוט צריך לבדוק את גיל כל ציטוט לפני שהוא מתמחר מולו פקודה, ולעקוב בנפרד אחר אות חיים מהפיד ואחר הנתונים. פערים ליליים ממחישים את היקף הסיכון שמחיר שהתיישן עלול להסתיר: התנועה הלילית באחוזון ה-95 הגיעה ל-4.41% ב-TSLA בין ינואר 2024 ליולי 2026.

האם בוט מסחר קטן באמת זקוק ליומן ביקורת?

יומן של ביצועים מתעד את מה שקרה. יומן החלטות מתעד את מה שהבוט סבר שמותר לו לעשות. זו הדרך היחידה להבחין בין אסטרטגיה שגויה לבין בדיקת סיכונים שלא הופעלה כלל. יומן שניתן להוסיף אליו בלבד, ושכולל גם דחיות, הוא הגרסה המינימלית השימושית.


כל הנתונים לעיל מגיעים משאילתה שמורה על נתוני נרות בני דקה, וכל פאנל מאפשר לפתוח את שאילתת ה-SQL שמאחוריו. אפשר להפעיל את אותן שאילתות על רשימת הסימולים שלכם במסוף Strasmore.

#risk-management#trading-bots#drawdown#position-sizing#automation