מדריך Polymarket Bot · פרק 29 מתוך 32

בנו מנוע paper trading ל־Polymarket לפני שעולים לאוויר: הדמיית פקודות מול מחירים אמיתיים, מעקב אחרי P&L, אכיפת שער ה־30 trades (>=55% win rate, +PnL) לפני כל הון חי, ומבנה קוד בסיסי.

מה מכסה הפרק הזה

Paper trading הוא השלב הלא־מתפשר בין רעיון אסטרטגי לפריסה חיה. הפרק הזה מציג את מנוע ה-paper הפשוט שחסם כל bot חי ששלחנו - פחות מ־200 שורות Python, עוקב אחרי כל עסקה ביומן JSONL, ומיישם את אותן עמלות/Slippage כמו במסלול החי.

  • למה paper לפני live (תמיד)
  • שער 30 ה־trades (מאומת +55% WR + PnL חיובי)
  • בניית מנוע paper פשוט
  • מעקב אחר יומן paper לצד יומן live
  • מתי paper חורג מ־live (ולמה)
  • מעבר ל־live: הפקדה ראשונה קטנה
  • קוד: מנוע paper מינימלי

למה paper לפני live (תמיד)

שער ה־paper של 30 trades הוא המשמעת היחידה שמפרידה בין 7.6% מה־Polymarket traders הרווחיים לבין 84.1% שמפסידים. רוב הבונים מדלגים עליו ומשלמים שכר לימוד. הסיבה הכנה שזה עובד: paper trading חושף את ה־win rate האמיתי של האסטרטגיה אחרי מספיק דגימות כדי להבדיל בין signal ל־luck.

דילוג על paper עולה יותר ממה שהוא חוסך. אסטרטגיה שנראית רווחית ב־backtest אבל בפועל היא הטלת מטבע תשרוף 200-500 דולר מהון חי לפני שתייצר sample size של 30 דגימות של data חי. לבצע paper על אותן 30 עסקאות עולה 0 דולר.

מנוע ה־paper לא צריך להיות מתוחכם. הוא צריך להיות כן - אותן עמלות, אותו Slippage, ואותה fill latency כמו במסלול החי. ככל שזה פשוט יותר, כך טוב יותר, כי כל דבר אופציונלי נחתך וה־bot עולה לאוויר מוקדם מדי.

שער 30 ה־trades (מאומת +55% WR + positive PnL)

השער הוא בינארי: 30 עסקאות paper סגורות, קריטריוני הצלחה שנקבעו מראש בכתב (בדרך כלל WR ≥ 55% באסטרטגיה עם positive EV), או שאין פריסה חיה.

30 הוא sample size מינימלי שבו רווח הסמך של 95% על ה־win rate האמיתי צר מספיק כדי להבדיל בין signal ל־noise. מתחת ל־30, שיעור נצפה של 60% יכול להתאים לשיעור אמיתי של 45-75%. ב־30 ומעלה, הטווח מצטמצם לכ־50-70% - עדיין רחב, אבל מספיק כדי לשלול "האסטרטגיה היא הטלת מטבע."

קריטריוני ההצלחה חייבים להיקבע לפני שמתחילים את ריצת ה־paper. קביעה שלהם אחרי כן מייצרת רציונליזציה בדיעבד (תמצאו דרך לפרש כל 30 עסקאות כ"מספיק טוב").

בניית מנוע paper פשוט

מנוע ה־paper הוא למעשה קוד המסחר החי, רק עם פונקציית הצבת הפקודה מוחלפת ב־simulated fill. ההדמיה:

  • קריאת live order book: אותה קריאה שה־bot החי היה מבצע.
  • הדמיית fill: אם קונים ב־FOK במחיר ≥ best ask, הפקודה מתמלאת לפי הממוצע המשוקלל־לפי־נפח של ה־asks שנצרכו; רושמים את המילוי ביומן ה־paper.
  • יישום עמלות: מפחיתים את אותן עמלות שהמסלול החי היה משלם.
  • מעקב inventory: מתחזקים מילון paper-balance ו־paper-positions מקביל.

כל המנוע נכנס ל־100-200 שורות Python. המשמעת המרכזית: כל הנחה שהמסלול החי עושה (fill rate, latency, fee) חייבת להיות משוחזרת ב־paper, אפילו אם היא מעט גרועה יותר מהמציאות - paper צריך להיות הרצפה, לא התקרה.

מעקב אחר יומן paper לצד יומן live

ריצת ה־paper trading מייצרת יומן JSONL שאינו ניתן להבחנה במבנה שלו מהיומן החי שה־bot יכתוב מאוחר יותר. אותם שדות: timestamp, action, market_slug, side, size, price, expected_fill_price, simulated_pnl_at_exit.

יש שתי סיבות להשתמש באותו פורמט. ראשית, כלי הניתוח שקוראים עסקאות live (דוחות PnL, מחשבי win rate) עובדים על paper בלי שינוי. שנית, השוואה בין paper ל־live בהמשך חושפת סטיות שמצביעות על באגים.

טיפ פרודקשן: גרמו למנוע ה־paper לכתוב אל per_trade_paper.jsonl באותה תיקייה כמו per_trade.jsonl החי. פקודה אחת משווה את שניהם: diff -y <(jq -r .market_slug per_trade.jsonl) <(jq -r .market_slug per_trade_paper.jsonl).

מתי paper חורג מ־live (ולמה)

סטיות בין paper ל־live הן בלתי נמנעות. שלוש נפוצות.

  • Slippage: ב־paper המילוי מתבצע לפי snapshot של ה־ask; ב־live ה־book נבלע ויכול למלא 1-2 סנט גרוע יותר בשווקים דלילים. פתרון: לדמות Slippage ב־paper על ידי הוספת קנס לכל עסקה השווה למחצית ה־spread.
  • Fill latency: ב־paper המילוי מיידי; ב־live זה לוקח 200-500ms שבמהלכם המחיר יכול לזוז. פתרון: לדמות זאת על ידי המתנה וקריאה מחדש של ה־book לפני "מילוי" ב־paper.
  • Adverse selection: ב־paper מניחים שאתם מקבלים את ה־best ask; ב־live אתם מתחרים ב־bots אחרים שאולי כבר הרימו את ה־ask הזה. פתרון: קשה יותר לדמות; צריך להודות ביושר בפני עצמכם ש־paper נוטה להעריך־יתר.

כש־paper אומר +5%/month ו־live רץ ב־-2%/month, הפער הוא בדרך כלל אחת מהסיבות האלה. בדקו אותן אחת־אחת במקום להניח שהאסטרטגיה עצמה הייתה שגויה.

מעבר ל־live: הפקדה ראשונה קטנה

ה־paper עבר 30 trades. תכנית הפריסה ל־live:

  1. להפקיד 25-50 דולר כהון smoke-test. להתייחס לזה כשכר לימוד; אם תפסידו אותו, הלקח היה שווה את זה.
  2. להריץ את ה־bot במצב live במשך 5-10 trades עם פוזיציות בגודל מינימלי (5 shares).
  3. לאמת שכל fill תואם לציפיות ה־paper בתוך 2 סנט. לחקור כל פער גדול יותר לפני שממשיכים.
  4. אם 5-10 עסקאות live תואמות ל־paper, להפקיד 200-500 דולר ולהריץ פוזיציות בגודל רגיל.
  5. אם הן לא תואמות, לעצור, לדבג, לתקן, ולהתחיל מחדש משלב 1.

הפער הנפוץ ביותר בין live ל־paper בפריסה ראשונה הוא עמלה חסרה או הערכת־חסר של Slippage. התיקון שלהם פשוט; המשמעת היא לתפוס את הפער לפני שמגדילים הון.

קוד: מנוע paper מינימלי

Reference: simple paper engine that reads live book + simulates FOK fill.

import json, time
PAPER_BAL = 10_000.0   # USD starting
positions = {}         # token_id -> shares

def paper_fok_buy(token_id, max_price, size):
    book = fetch_book(token_id)
    # Walk asks, fill what we can within max_price
    filled = 0; cost = 0
    for level in book.asks:
        px = float(level["price"])
        if px > max_price: break
        avail = float(level["size"])
        take = min(avail, size - filled)
        filled += take
        cost += take * px
        if filled >= size: break
    if filled < size:
        return {"status":"rejected","filled":0}  # FOK semantics

    global PAPER_BAL
    PAPER_BAL -= cost
    positions[token_id] = positions.get(token_id, 0) + filled

    log_paper({"ts": int(time.time()), "action":"buy",
               "token": token_id, "size": filled, "price": cost/filled})
    return {"status":"matched","filled":filled,"cost":cost}

תוספות פרודקשן: פונקציית paper sell (מראה של buy), סימולציית paper GTC (הצבה על ה־book במחיר, סימולציית fill כשה־mid מגיע למחיר), התאמה בין יומן ה־paper לבין יומן ה־"היה יכול להיות" החי.

שאלות נפוצות

מהו שער 30 ה־trades?
כלל החסימה הפנימי שלנו למעבר מ־paper ל־live: לפחות 30 עסקאות paper סגורות, win rate של 55% ומעלה, ו־PnL נטו חיובי אחרי Slippage. אם אחד מהתנאים האלה נכשל, נשארים ב־paper. המצאנו את הכלל הזה אחרי כמה ניסיונות מוקדמים מדי לעלות לאוויר שחיסלו חשבונות ב־2025.
למה 30 trades ולא 100?
עוצמה סטטיסטית. עם 30 עסקאות, ל־win rate של 55% יש בערך 70% הסתברות להיות edge אמיתי (ולא noise). עם 100 עסקאות, הביטחון הזה עולה ליותר מ־90%. בחרנו 30 כרף מינימום כי תקופות paper ארוכות יותר נוטות לעיתים ל־overfitting - traders משנים את האסטרטגיה יותר מדי זמן במקום לבדוק אותה.
אפשר לדלג על paper trading אם אני בטוח?
בדיוק כשאתם בטוחים זו הסיבה שלא כדאי לדלג. ה־bots שהכי מצליחים ב־Polymarket מופעלים על ידי אנשים שטעו בעבר. שער 30 ה־trades קיים כדי לתפוס את האסטרטגיות שנראות נכונות אבל לא. רוב האסטרטגיות שלנו נכשלו ב־paper בהתחלה - זה הערך.
האם תוצאות paper תואמות לתוצאות live?
בדרך כלל כן באסטרטגיות איטיות (פוליטיקה, מזג אוויר), לא באסטרטגיות מהירות (5-min crypto, microstructure של ספורט). הפער הוא "paper trading לא משלם Slippage" - המילויים בפועל גרועים יותר מהמחיר שראיתם. אנחנו מנמיכים את תשואות ה־paper ב־30-50% לפני שמאמינים להן עבור live, במיוחד באסטרטגיות מהירות.
איך מיישמים מנוע paper ב־Python?
מתחברים ל־CLOB WebSocket האמיתי של השווקים שאתם סוחרים בהם. כש־strategy מחליטה "להציב פקודה", רושמים אותה לקובץ JSONL עם מחיר המילוי שהיה צפוי להיות (bid נוכחי לקנייה, ask נוכחי למכירה). עוקבים אחרי הפוזיציות באופן וירטואלי. עושים mark-to-market מול המחיר החי. כל המנוע הוא בערך 200 שורות Python.
כמה זמן צריך לבצע paper trading לפני שעולים ל־live?
עד שמגיעים לשער 30 ה־trades, או 2-4 שבועות - מה שארוך יותר. אם אתם מגיעים לשער מהר מדי, יש לכם overfitting; האטו וודאו ש־win rate שלכם יציב לשינויים קטנים בפרמטרים. אם לא מצליחים להגיע לשער אחרי חודשים, כנראה שלאסטרטגיה אין edge ואתם צריכים להרוג אותה.