Polymarket Bot Tutorial · Chapter 29 of 32
لائیو ہونے سے پہلے Polymarket paper trading engine بنائیں: real prices کے خلاف orders simulate کریں، P&L track کریں، 30-trade gate نافذ کریں (>=55% win rate، +PnL) کسی بھی live capital سے پہلے، اور code skeleton تیار کریں۔
یہ chapter کیا cover کرتا ہے
Paper trading strategy idea اور live deployment کے درمیان ایک لازمی step ہے۔ یہ chapter سادہ paper engine ہے جس نے ہمارے ship کیے گئے ہر live bot کو gate کیا - 200 lines of Python سے کم، ہر trade کو JSONL diary میں track کرتا ہے، اور live path جیسی ہی fees/slippage apply کرتا ہے۔
- Live سے پہلے paper کیوں (ہمیشہ)
- 30-trade gate (verified +55% WR + positive PnL)
- Simple paper engine بنانا
- Paper diary کو live diary کے ساتھ track کرنا
- جب paper live سے diverge کرے (اور کیوں)
- Live کی طرف بڑھنا: چھوٹا پہلا deposit
- Code: minimal paper engine
Live سے پہلے paper کیوں (ہمیشہ)
30-trade paper gate وہ واحد discipline ہے جو profitable Polymarket traders کے 7.6% اور loss کرنے والے 84.1% کو الگ کرتی ہے۔ اکثر builders اسے skip کر دیتے ہیں اور tuition ادا کرتے ہیں۔ اس کے کام کرنے کی اصل وجہ یہ ہے: paper trading کافی samples پر strategy کی true win rate ظاہر کر دیتا ہے تاکہ signal اور luck میں فرق کیا جا سکے۔
Paper skip کرنا بچت سے زیادہ نقصان دیتا ہے۔ Backtest میں profitable نظر آنے والی strategy اگر حقیقت میں coin flip ہو تو live capital میں $200-500 ختم کر دے گی، اس سے پہلے کہ 30-sample size کا live data ملے۔ انہی 30 trades کو paper میں کرنا $0 پڑتا ہے۔
Paper engine کو sophisticated ہونے کی ضرورت نہیں۔ اسے honest ہونا چاہیے - same fees، same slippage، live path جیسی ہی fill latency۔ جتنا simple ہو اتنا بہتر، کیونکہ جو بھی optional ہوتا ہے وہ cut ہو جاتا ہے اور bot ضرورت سے پہلے live ship ہو جاتا ہے۔
30-trade gate (verified +55% WR + positive PnL)
یہ gate binary ہے: 30 closed paper trades، پہلے سے لکھے گئے success criteria (عام طور پر positive-EV strategy پر WR ≥ 55%)، ورنہ live deployment نہیں۔
30 وہ minimum sample size ہے جہاں true win rate پر 95% confidence interval signal کو noise سے الگ کرنے کے لیے کافی narrow ہو جاتا ہے۔ 30 سے کم پر، 60% observed rate کا مطلب 45-75% true rate ہو سکتا ہے۔ 30+ پر interval تقریباً 50-70% تک narrow ہو جاتا ہے - پھر بھی wide، لیکن "strategy coin flip ہے" کو رد کرنے کے لیے کافی۔
Success criteria paper run شروع ہونے سے پہلے set ہونے چاہییں۔ بعد میں set کرنے سے post-hoc rationalization پیدا ہوتی ہے (آپ کسی بھی 30 trades کو "کافی اچھا" سمجھنے کا طریقہ نکال لیں گے)۔
Simple paper engine بنانا
Paper engine بنیادی طور پر live trading code ہی ہوتا ہے، بس order-placement function کی جگہ simulated fill لگا دیا جاتا ہے۔ Simulation:
- Live order book پڑھیں: وہی call جو live bot کرے گا۔
- Fill simulate کریں: اگر FOK کے ساتھ buy کر رہے ہوں اور price ≥ best ask ہو، تو order کو consumed asks کے volume-weighted average پر fill کریں؛ fill کو paper diary میں record کریں۔
- Fees apply کریں: وہی fees subtract کریں جو live path دے گا۔
- Inventory track کریں: parallel paper-balance اور paper-positions dictionary maintain کریں۔
پورا engine 100-200 lines of Python میں fit ہو جاتا ہے۔ اصل discipline یہ ہے: live path جو بھی assumption بناتا ہے (fill rate، latency، fee) paper میں بھی reproduce ہونا چاہیے، چاہے حقیقت سے تھوڑا worse ہی کیوں نہ ہو - paper floor ہونا چاہیے، ceiling نہیں۔
Paper diary کو live diary کے ساتھ track کرنا
Paper trading run ایک JSONL diary produce کرتا ہے جو structure میں بعد میں bot کے لکھے گئے live diary سے الگ نہیں ہوتا۔ Same fields: timestamp، action، market_slug، side، size، price، expected_fill_price، simulated_pnl_at_exit۔
Same format استعمال کرنے کی دو وجوہات ہیں۔ پہلی، وہ analysis tools جو live trades پڑھتے ہیں (PnL reports، win-rate calculators) بغیر modification کے paper پر بھی کام کرتے ہیں۔ دوسری، بعد میں paper اور live کا comparison bugs کی نشاندہی کرتا ہے جو divergences پیدا کرتے ہیں۔
Production tip: paper engine کو live per_trade.jsonl کے same directory میں per_trade_paper.jsonl لکھنے دیں۔ ایک ہی command دونوں compare کرتی ہے: diff -y <(jq -r .market_slug per_trade.jsonl) <(jq -r .market_slug per_trade_paper.jsonl).
جب paper live سے diverge کرے (اور کیوں)
Paper اور live کے درمیان divergences ناگزیر ہیں۔ تین common ones:
- Slippage: paper ask snapshot پر fill ہوتا ہے؛ live book walk کرتا ہے اور thin markets میں 1-2c worse fill ہو سکتا ہے۔ حل: paper میں per-trade penalty شامل کر کے slippage simulate کریں جو spread کے half کے برابر ہو۔
- Fill latency: paper فوراً fill ہو جاتا ہے؛ live کو 200-500ms لگتے ہیں، اس دوران price move ہو سکتی ہے۔ حل: paper میں "fill" کرنے سے پہلے wait کریں اور book دوبارہ read کریں۔
- Adverse selection: paper فرض کرتا ہے کہ آپ کو best ask مل گیا؛ live میں دوسرے bots compete کر رہے ہوتے ہیں جنہوں نے شاید پہلے ہی وہ ask اٹھا لی ہو۔ حل: simulate کرنا مشکل ہے؛ اپنے آپ سے honest disclosure کہ paper overestimate کرتا ہے۔
جب paper +5%/month کہے اور live -2%/month پر چلے، تو gap عموماً انہی میں سے ایک ہوتا ہے۔ Strategy کو غلط ماننے کے بجائے ایک ایک کر کے audit کریں۔
Live کی طرف بڑھنا: چھوٹا پہلا deposit
Paper 30 trades pass کر چکا ہے۔ Live deployment plan:
- $25-50 smoke-test capital کے طور پر deposit کریں۔ اسے tuition سمجھیں؛ اگر یہ loss بھی ہو جائے تو سبق اپنی قیمت رکھتا ہے۔
- Bot کو live mode میں 5-10 trades کے لیے چلائیں، minimum size positions (5 shares) کے ساتھ۔
- ہر fill کو 2c کے اندر paper expectations کے مطابق verify کریں۔ آگے بڑھنے سے پہلے کسی بھی بڑے gap کی investigation کریں۔
- اگر 5-10 live trades paper سے match کریں تو $200-500 deposit کریں اور normal-size positions چلائیں۔
- اگر match نہ کریں تو halt کریں، debug کریں، fix کریں، step 1 سے restart کریں۔
پہلی deployment میں live-paper gap کی سب سے common وجہ missing fee یا slippage کا غلط اندازہ ہوتا ہے۔ انہیں fix کرنا سیدھا ہے؛ اصل discipline capital scale کرنے سے پہلے gap پکڑنا ہے۔
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 (buy کا mirror)، paper GTC simulation (price پر book پر post کریں، جب mid price پر پہنچے تو fill simulate کریں)، paper diary اور "would-have-been" live diary کے درمیان reconciliation۔





