לא, אי אפשר לסחור על הטיית longshot favorite בפולימרקט. בדקתי מעל 100 אלגוריתמים על טרה-בייטים של דאטה, גם כ-Taker וגם כ-Maker, ואף אחד לא רווחי. השוק נראה הוגן — וזאת בדיוק התוצאה ששווה לפרסם.
לפני כמה חודשים חבר סיפר לי על ההטיה הזאת, ויצאתי לבדוק אם אפשר לסחור עליה. בניתי מערכת שאוספת כל הימור שהונח בשוקי הקריפטו של פולימרקט מאז ה-3.6, ובקלשי מאמצע יוני, צמוד למחירי המטבעות ברזולוציה של מילי-שניות, סימולטור בקטסט מעל הדאטה הזה, וצוות אייג׳נטים שמריץ עליו מעבדת מחקר לילית.
ההטיה: כדור לבן ותשעה שחורים
שימו בקופסה כדור אחד לבן ותשעה שחורים, ותנו לעוברי אורח לשלם 10 שקלים כדי לבחור:
- 11 שקלים אם יצא כדור שחור (90% סיכוי לזכות)
- 100 שקלים אם יצא הכדור הלבן (10% סיכוי לזכות)
תנסו ותראו שיותר מ-10% מהאוכלוסייה תהמר על הלבן. זו ההטיה: אנשים מעדיפים את הצד הפחות סביר בגלל המכפלה, לא בגלל הסיכוי.
למה זה אמור להיות סחיר דווקא בפולימרקט
פולימרקט היא זירת מסחר בהימורים בינאריים שמתומחרת peer to peer. אין בית שקובע את המכפלה — המהמרים עצמם קובעים אותה. כלומר ההטיה הפסיכולוגית לא נשארת בראש של המהמר, היא מתגלגלת ישר לתוך המחיר.
נחזור לקופסה. אם נעלה את המשחק לפולימרקט ונגלה ש-20% מהאנשים בוחרים בכדור הלבן, פרס הלבן יירד ל-50 שקלים ופרס השחור יעלה ל-12 — בלי ששיניתי את סבירות הזכייה במילימטר. במצב כזה אפשר לטעון, בצדק, שמספיק להמר תמיד על השחור ולאורך זמן לגרוף.
הטענה נכונה על הנייר. השאלה היחידה היא מה נשאר ממנה אחרי עמלות, אחרי latency, ואחרי בוטים מהירים ממני.
המכונה
הצינור שאוסף הכול
שלושה תהליכים שרצים על ECS Fargate מאותו image: אחד אוסף, אחד מארכב, ואחד מעשיר כל fill בזהות הארנק מהבלוקצ׳יין. מאחוריהם Postgres על RDS ו-S3 עם Parquet. מה שנכנס: ספר ההזמנות המלא של פולימרקט (סנפשוטים, כל דלתא ברמה 2, כל עסקה), קלשי, ופידים חיצוניים — Binance ברזולוציית תת-שנייה (@aggTrade ו-@bookTicker) ו-Chainlink גם כסדרה של שנייה וגם כאירועי אורקל על השרשרת.
ההחלטה הכי חשובה בכל הפרויקט הייתה משעממת: שעון אחד. כל שורה מכל פיד מקבלת חותמת זמן ברגע שהפריים ירד מהסוקט, לא ברגע שהיא נכנסה לדטהבייס. בלי זה, כל ניסיון להצמיד תנועה בביטקוין לתנועה בספר של פולימרקט הוא ניחוש מנומק.
הנפחים לא צנועים. יום אחד של עדכוני ספר שוקל בערך 88 ג׳יגה ב-Postgres, אז הארכוב עובד פר-שוק: כל שוק שנסגר נשאב ל-S3 ונמחק מהדטהבייס תוך דקות. בקלשי הבעיה הפוכה — כ-2,675 שווקים פעילים מול תקציב של בערך 10 בקשות בשנייה בלי מפתח, אז הדגימה מדורגת: שווקים של רבע שעה נדגמים כל 20-30 שניות, שווקים של שעה ויום כל רבע שעה.
הסימולטור
מעל הדאטה בניתי מנוע בקטסט, וזה החלק שלקח לי הרבה יותר human-CPU ממה שציפיתי. הוא מריץ מחדש את הספר אירוע-אירוע, מבצע פילים שהולכים לעומק הספר ולא במחיר האמצע, מודד עמלה של 0.07·p·(1−p) על כל fill של Taker (הנוסחה אומתה מול פילים אמיתיים שנושאים עמלה בארכיון), ומודל את ה-latency במקום להניח אותו — כל הרצה של המנוע מדווחת על פני טווח השהיות ולא בנקודה אחת. (המודד הנפרד של המעבדה, זה שהפיק את המספרים שלמטה, מתמחר בנקודה אחת: הפיל הישים בסנפשוט, כולל עמלה.)
הצד של ה-Maker קשה יותר, כי דאטה של רמה 2 לא מראה לי איפה ההזמנה שלי בתור. אז ה-fill נאמד בסוגריים בין הנחה אופטימית להנחה שמרנית, וכל תוצאה מדווחת בשני הקצוות. המחיר של הכנות הזאת: edge של Maker מתחת ל-5 סנט לכל fill פשוט לא ניתן להכרעה כאן, כי הסוגריים עצמם רחבים 3 עד 8 סנט. עדיף להגיד את זה מראש מאשר להמציא מספר.
הכלל שהכי השתלם: מה שהמנוע לא יודע לתמחר נכון — ביטולים, מכירה כ-Maker — זורק שגיאה, במקום לתמחר לא נכון בשקט.
המעבדה הלילית
את הדאטה ואת הסימולטור אני מוסר לצוות אייג׳נטים בלילות שלישי ורביעי (הסשן השבועי שלי בקלוד נגמר בחמישי, אז ככה אני מסיים את הטוקנים), יחד עם כוח החישוב שהם צריכים מ-AWS. חמישה תפקידים: מוביל מחקר, סקפטי, ושלושה חוקרים. כל איטרציה היא קונטקסט נקי — האייג׳נט קורא את המצב המשותף, עושה יחידת עבודה אחת, מתעד, ויוצא.
החוקים חשובים יותר מהחוקרים:
- רושמים את ההיפותזה מראש עם מזהה, לפני שמייצרים מספר.
- כל טענת רווח עוברת דרך מודד יחיד ומוסכם, כולל עמלות, מחוץ למדגם לפי תאריך, עם רווח בר-סמך מקובץ (clustered).
- ה-holdout מוגש בלי תוצאות עד שהקמפיין ננעל, וכל יום שמישהו כבר הסתכל על התוצאות שלו נרשם לרשימת ימים שרופים ולא יכול לשמש holdout לעולם.
- לסקפטי יש תפקיד אחד: להרוג מועמדים. ערבוב תחזיות, ערבוב בחירת השורות, חתכים חלופיים, פירוק לפי יום ולפי מטבע, בדיקת דליפה, ובדיקת קיבולת.
- תוצאה שלילית היא ניצחון. כל מבוי סתום נרשם לרשימת DO-NOT-RETRY כדי שאף אחד לא יחזור עליו.
ואייג׳נט לא מקדם שום דבר לקובץ המסקנות. הוא כותב "מסקנה מוצעת" בדוח של אותו מחזור, ואני מאשר או לא.
איפה הזמן באמת נשרף
בתחילת יולי עצרתי הכול והרצתי ביקורת קוד יריבה על המחקר עצמו — שמונה צירים, כל ממצא משוחזר לפני שהתקבל. מה שיצא משם היה לא נעים ומאוד מועיל:
- מכירה כ-Taker רצה על הצד הלא נכון של הספר.
- הזמנת limit שחוצה את הספר נרשמה כהזמנה נחה של Maker — כלומר עקפה את כל העמלה. אותה הזמנה בדיוק, פעם עם עמלה ופעם בלי.
- החתך שנקרא "valid" נפל בתוך חלון האימון של המודלים, בזמן שהכלי הדפיס בגאווה שהוא מחוץ למדגם.
- קבצי ההערכה הקנוניים השתנו בלי גרסאות, ככה שאף מספר שנרשם לא היה ניתן לשחזור.
ביטלתי כל מסקנה שהופקה לפני התאריך הזה, כולל כמה שאהבתי. זה החלק שאף אחד לא מספר עליו כשהוא מראה equity curve יפה: בקטסט שבור לא נותן תשובה שגויה אקראית, הוא נותן תשובה חיובית. כמעט כל באג שמצאתי בצד ה-Taker הטה את התוצאה לטובתי (בצד ה-Maker דווקא היו באגים שהטו לרעתי: ביטולים שהיו no-op שקט).
מה יצא
בשלושת הקמפיינים שרצו אחרי ההקשחה נרשמו מראש 47 היפותזות ואושרו 0. הקמפיין האחרון לבדו: 39 היפותזות בחמישה גלים, 0 אושרו.
התוצאה החזקה ביותר היא מודל שמשלב את כל הפאנלים ומייצר שיפור של בערך 0.002 ב-AUC מעל מחיר השוק. יש שם משהו — פשוט משהו שהעמלה אוכלת במלואו. ניתן לזיהוי, לא ניתן למסחר.
והמלכודת הכי מלמדת: מועמד אחד הראה +2.14 סנט לעסקה עם רווח בר-סמך שכולו מעל אפס, על 704 עסקאות. הסקפטי הרג אותו — בטיימפריים של 5 דקות הוא אפס נקי, השיפור שלו ב-AUC היה בסדר גודל של 0.0001, וכשמריצים 39 היפותזות מישהו חייב להיראות טוב. זה winner's curse בדיוק כמו בספר. בלי סקפטי, זה היה נכנס לשקף.
ההטיה עצמה נראתה בניתוח שקדם להקשחה — את המסקנות ההן ביטלתי יחד עם כל השאר, ומעולם לא גזרתי אותה מחדש תחת ההרנס המוקשח. מה שכן נמדד אחריה: אחרי העמלה, מחיר השוק הוגן. בוקר אחד קלוד הכריז שלדעתו השוק "הוגן" — אין כשלי שוק מדרגה ראשונה. אני נוטה להסכים.
על אלה שכתבו לקלוד "make money"
מי שמסתנוור משרלטנים שמספרים שכתבו למודל prompt של make money והוא ייצר להם 12 אלף דולר בלילה — Don't. זה חרטוט אחד גדול. בדקתי, עם טרה-בייטים של דאטה, עם סימולטור שמודד עמלות ו-latency, ועם אייג׳נט שכל תפקידו להרוג כל מספר ירוק שמופיע.
מה שכן קיבלתי
אייג׳נטים מצוינים בלהריץ ניסוי. הם גרועים בלהחליט אם הניסוי היה הוגן. כל הערך בפרויקט הזה לא היה באלגוריתמים אלא במכונה שיודעת להגיד "לא": רישום מראש, מודד יחיד, holdout אטום, וסקפטי שמנסה להפיל כל תוצאה חיובית. בלי זה, 100 אלגוריתמים וכוח חישוב זמין תמיד יפיקו משהו שנראה רווחי.
זה נכון גם בפרויקטים הרבה יותר משעממים. כשאני מטמיע AI בארגון, החלק היקר הוא לא לגרום למודל לעשות משהו — אלא לבנות את הבדיקה שמבדילה בין "עבד" ל"נראה שעבד". ככה אני עובד, שלב אחרי שלב.