آموزش Polymarket Bot · فصل 29 از 32

قبل از going live یک Polymarket paper trading engine بسازید: سفارش‌ها را در برابر قیمت‌های واقعی simulate کنید، P&L را track کنید، gate 30-trade را اعمال کنید (>=55% win rate، +PnL) قبل از هرگونه live capital، و code skeleton را پیاده‌سازی کنید.

این فصل چه چیزهایی را پوشش می‌دهد

Paper trading گام غیرقابل‌چشم‌پوشی بین ایده strategy و live deployment است. این فصل همان paper engine ساده‌ای است که روی هر bot زنده‌ای که منتشر کرده‌ایم gate گذاشته - با کمتر از 200 خط Python، همه tradeها را در یک diary از نوع JSONL track می‌کند و همان fees/slippage مسیر live را اعمال می‌کند.

  • چرا قبل از live، paper لازم است (همیشه)
  • gate 30-trade (تأییدشده با +55% WR و مثبت بودن PnL)
  • ساخت یک paper engine ساده
  • Track کردن paper diary در کنار live diary
  • وقتی paper با live diverge می‌شود (و چرا)
  • ارتقا به live: واریز اولیه کوچک
  • Code: minimal paper engine

چرا قبل از live، paper لازم است (همیشه)

gate 30-trade در paper تنها discipline‌ای است که 7.6% از Polymarket traders سودده را از 84.1% زیان‌ده جدا می‌کند. بیشتر builders این مرحله را رد می‌کنند و هزینه‌اش را می‌پردازند. دلیل صادقانه‌ای که این روش جواب می‌دهد این است: paper trading win rate واقعی strategy را روی تعداد sample کافی آشکار می‌کند تا signal را از luck جدا کند.

رد کردن paper هزینه‌ای بیشتر از صرفه‌جویی‌اش دارد. یک strategy که در backtest سودده به نظر می‌رسد اما در واقع coin flip است، پیش از آن‌که 30 نمونه از live data تولید کند، 200 تا 500 دلار از live capital را می‌سوزاند. paper-trading همان 30 trade، 0 دلار هزینه دارد.

paper engine لازم نیست پیچیده باشد. باید صادق باشد - همان fees، همان slippage، همان fill latency مسیر live. هرچه ساده‌تر بهتر، چون هر چیزی که optional باشد حذف می‌شود و bot زودتر از موعد وارد live می‌شود.

gate 30-trade (تأییدشده با +55% WR و مثبت بودن PnL)

این gate دوحالته است: 30 paper trade بسته‌شده، success criteria از پیش نوشته‌شده (معمولاً WR ≥ 55% برای یک strategy با positive EV)، وگرنه هیچ live deploymentی انجام نمی‌شود.

عدد 30 حداقل sample size است که در آن بازه اطمینان 95% برای win rate واقعی آن‌قدر باریک می‌شود که signal را از noise جدا کند. زیر 30، یک نرخ مشاهده‌شده 60% می‌تواند معادل نرخ واقعی 45 تا 75% باشد. از 30 به بالا، این بازه به حدود 50 تا 70% می‌رسد - هنوز پهن است، اما برای رد کردن این فرض که «این strategy فقط coin flip است» کافی است.

success criteria باید قبل از شروع paper run تعیین شوند. تعیین آن‌ها بعد از شروع، post-hoc rationalization تولید می‌کند (برای هر 30 trade راهی پیدا می‌کنید که آن‌ها را «به‌اندازه کافی خوب» تفسیر کنید).

ساخت یک paper engine ساده

paper engine در اصل همان live trading code است که تابع order-placement آن با یک simulated fill جایگزین شده است. این simulation شامل موارد زیر است:

  • Read کردن live order book: همان callی که live bot انجام می‌دهد.
  • Simulate fill: اگر هنگام خرید با FOK قیمت ≥ best ask باشد، سفارش را با volume-weighted average of asks consumed پر می‌کند؛ fill را در paper diary ثبت کنید.
  • اعمال fees: همان feesی را کم کنید که مسیر live پرداخت می‌کند.
  • Track کردن inventory: یک paper-balance و paper-positions dictionary موازی نگه دارید.

کل engine در 100 تا 200 خط Python جا می‌گیرد. discipline اصلی این است: هر فرضی که مسیر live می‌سازد (نرخ fill، latency، fee) باید در paper بازتولید شود، حتی اگر کمی بدتر از واقعیت باشد - paper باید floor باشد، نه ceiling.

Track کردن paper diary در کنار live diary

paper trading run یک JSONL diary تولید می‌کند که از نظر ساختار با live diaryی که bot بعداً می‌نویسد، قابل‌تشخیص نیست. همان fields: timestamp، action، market_slug، side، size، price، expected_fill_price، simulated_pnl_at_exit.

دو دلیل برای استفاده از همان format وجود دارد. اول، ابزارهای analysis که tradeهای live را می‌خوانند (PnL reports، win-rate calculators) بدون هیچ تغییری روی paper هم کار می‌کنند. دوم، مقایسه paper و live در آینده divergenceهایی را نشان می‌دهد که نشانه bug هستند.

Production tip: اجازه دهید paper engine در همان directoryی که live per_trade.jsonl قرار دارد، در per_trade_paper.jsonl بنویسد. با یک command هر دو را مقایسه کنید: diff -y <(jq -r .market_slug per_trade.jsonl) <(jq -r .market_slug per_trade_paper.jsonl).

وقتی paper با live diverge می‌شود (و چرا)

divergence بین paper و live اجتناب‌ناپذیر است. سه مورد رایج:

  • Slippage: paper در snapshotِ ask fill می‌شود؛ live book را walk می‌کند و ممکن است در بازارهای thin، 1 تا 2 سنت بدتر fill شود. راه‌حل: slippage را در paper با افزودن یک penalty برای هر trade معادل نصف spread simulate کنید.
  • Fill latency: paper فوری fill می‌شود؛ live بین 200 تا 500 میلی‌ثانیه زمان می‌برد و در این فاصله price ممکن است حرکت کند. راه‌حل: با waiting و re-reading book قبل از «fill» کردن در paper آن را simulate کنید.
  • Adverse selection: paper فرض می‌کند بهترین ask را می‌گیرید؛ live با botهای دیگر رقابت می‌کند که ممکن است آن ask را قبلاً برداشته باشند. راه‌حل: simulate کردنش سخت‌تر است؛ صادقانه به خودتان بگویید که paper overestimate می‌کند.

وقتی paper می‌گوید +5%/month و live در -2%/month اجرا می‌شود، شکاف معمولاً یکی از همین‌هاست. آن‌ها را یک‌به‌یک audit کنید، نه اینکه فرض کنید خود strategy اشتباه بوده است.

ارتقا به live: واریز اولیه کوچک

paper از gate 30 trade عبور می‌کند. برنامه deployment به live:

  1. 25 تا 50 دلار واریز کنید به‌عنوان smoke-test capital. آن را tuition در نظر بگیرید؛ اگر از دست رفت، درسش ارزشش را داشته است.
  2. bot را در حالت live برای 5 تا 10 trade با positionهای حداقل اندازه (5 سهم) اجرا کنید.
  3. تأیید کنید که هر fill در محدوده 2 سنت با انتظار paper مطابقت دارد. هر gap بزرگ‌تر را قبل از ادامه بررسی کنید.
  4. اگر 5 تا 10 live trade با paper مطابقت داشت، 200 تا 500 دلار واریز کنید و positionهای با اندازه عادی را اجرا کنید.
  5. اگر مطابقت نداشتند، متوقف شوید، debug کنید، fix کنید، و از مرحله 1 دوباره شروع کنید.

رایج‌ترین gap بین live و paper در نخستین deployment، fee فراموش‌شده یا برآورد نادرست slippage است. درست‌کردن آن‌ها ساده است؛ discipline اصلی این است که gap را قبل از scaling capital پیدا کنید.

Code: minimal paper engine

Reference: simple paper engine که live book را می‌خواند + FOK fill را simulate می‌کند.

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}

Production additions: paper sell function (mirror of buy)، paper GTC simulation (post on book at price, simulate fill when mid reaches price)، reconciliation بین paper diary و "would-have-been" live diary.

سؤالات متداول

gate 30-trade چیست؟
قانون داخلی ما برای عبور از paper به live: دست‌کم 30 paper trade بسته‌شده، win rate >= 55%، و net PnL مثبت پس از در نظر گرفتن slippage. اگر هرکدام از این‌ها fail شود، در paper می‌مانید. ما این rule را بعد از چند تلاش زودهنگام برای go-live ساختیم که accountها را در 2025 نابود کردند.
چرا 30 trade و نه 100؟
توان آماری. با 30 trade، win rate 55% تقریباً 70% احتمال دارد که edge واقعی باشد (نه noise). با 100 trade، این confidence به 90%+ می‌رسد. ما 30 را به‌عنوان حداقل bar انتخاب کردیم چون دوره‌های paper طولانی‌تر اغلب overfitting ایجاد می‌کنند - traderها به‌جای آزمودن strategy، بیش از حد آن را tweak می‌کنند.
اگر مطمئن باشم، می‌توانم paper trading را رد کنم؟
دقیقاً همان زمانی که نباید آن را رد کنید. botهایی که در Polymarket بهترین عملکرد را دارند توسط افرادی اجرا می‌شوند که قبلاً اشتباه کرده‌اند. gate 30-trade وجود دارد تا strategyهایی را که درست به نظر می‌رسند اما درست نیستند، گیر بیندازد. بیشتر strategyهای خود ما در ابتدا paper را رد کردند - همین ارزش آن است.
آیا نتایج paper با live مطابقت دارند؟
معمولاً بله برای strategyهای slow-moving (politics، weather)، و نه برای strategyهای سریع (5-min crypto، sports microstructure). شکاف این است که "paper trading slippage پرداخت نمی‌کند" - fillهای واقعی بدتر از قیمتی هستند که دیده‌اید. ما قبل از باور کردن paper returns برای live، آن‌ها را 30 تا 50% discount می‌کنیم، مخصوصاً برای strategyهای سریع.
چطور یک paper engine در Python پیاده‌سازی کنم؟
به real CLOB WebSocket برای marketهایی که معامله می‌کنید subscribe شوید. وقتی strategy شما تصمیم می‌گیرد «order بگذارد»، آن را در یک فایل JSONL با قیمت fill احتمالی log کنید (برای buy، current bid؛ برای sell، current ask). positionها را به‌صورت virtual track کنید. مقابل live price mark-to-market کنید. کل engine حدود 200 خط Python است.
چقدر باید paper trade کنم قبل از اینکه live شوم؟
تا وقتی gate 30-trade برآورده شود، یا 2 تا 4 هفته؛ هر کدام که طولانی‌تر است. اگر خیلی سریع به gate می‌رسید، دارید overfit می‌کنید؛ سرعت را کم کنید و مطمئن شوید win rate شما نسبت به تغییرات کوچک parameterها robust است. اگر بعد از ماه‌ها نتوانستید به gate برسید، احتمالاً strategy edge ندارد و باید آن را حذف کنید.