26 בספטמבר 2026 · מחקר

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

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

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

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

יום 1: הגדרנו מה פירוש „אותה הרצה”

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

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

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

יום 2: השווינו בין העסקאות, לא בין ערכי Sharpe

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

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

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

יום 3: התברר שקובץ נתונים „זהה” היה שונה

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

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

בדיקה היסטורית שאפשר לשחזר מחייבת תשובה לשאלה: „איזו גרסה של העבר היא ראתה?”

יום 4: מצאנו ברירת מחדל חבויה

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

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

3מקורות לסטייה שאיתרנו
1.8%הפער הראשוני ביתרת הסיום
0הערך בהתאמה בין ערכי Sharpe בלבד

על מה היינו מדלגים בפעם הבאה

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

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

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

שחזוריותבדיקות היסטוריותהנדסת נתוניםמסחר מדומה
← כל הפוסטים