Polymarket Bot Tutorial · অধ্যায় 32 of 32
বাস্তব Polymarket bot ভুল এবং postmortems: phantom fills, sticky-fail dedup, lol-ctg-ccg whipsaw, NegRisk flag bug, premature go-live - প্রতিটি ঠিক করা commits এবং dates সহ।
এই অধ্যায়ে কী আছে
আমাদের production diary-তে থাকা এমন কিছু bug-এর কথা, যেগুলো বাস্তব টাকা খরচ করেছিল। নির্দিষ্ট ঘটনার চেয়ে pattern-টাই বেশি গুরুত্বপূর্ণ - একই ধরনের bug bot-এ বারবার ফিরে আসে, আর সমাধান সাধারণত missing watchdog, better strategy নয়। এই অধ্যায়ের উদ্দেশ্য হলো আপনার tuition বাঁচানো।
- Phantom fills (commits e68a087, 8bb7761)
- NegRisk flag bug (commit 06deaef)
- Sticky-fail dedup (commit 4c0bef1)
- Whipsaw incident: lol-ctg-ccg
- Premature go-live: 2025 wipe
- Sleep-through-bug: kill switch worked
- Lessons that generalize
Phantom fills (commits e68a087, 8bb7761)
আমাদের trader-এ প্রথম বড় phantom-fill incident, মে 2025-এ। Bot 22টি FOK buy দিয়েছিল, সবগুলোই CLOB-এ matched হয়েছিল। Bot সঙ্গে সঙ্গে 22টি GTC sell post করার চেষ্টা করে। সেগুলোর মধ্যে 8টি "balance: 0 / sum of active orders: 0 / order amount: 10000000." error দিয়ে reject হয়।
Root cause: settlement lag (অধ্যায় 12)। CLOB 100ms-এ match করেছিল, bot 200ms-এ sell post করেছিল, কিন্তু Polygon ERC-1155 transfer-এ প্রায় 2 সেকেন্ড লেগেছিল। Chain-এ তখনও zero balance দেখাচ্ছিল বলে CLOB sell reject করে।
Fix: একই token-এ কোনো successful buy এবং পরের GTC follow-up-এর মধ্যে 5-second blocking wait যোগ করা হয়েছে। Commits e68a087 এবং 8bb7761। তারপর থেকে zero phantom-fill incident।
Lesson: API time এবং chain time আলাদা timeline। যেসব code এগুলোকে synchronous ধরে নেয়, সেগুলো ঠিক এই failure mode-টাই পাবে।
NegRisk flag bug (commit 06deaef)
8 candidate-সহ একটি NegRisk multi-outcome event-এ momentary arb ছিল 1.8c (sum of YES asks = 0.982)। আমাদের arber সব 8টি FOK buy fire করেছিল। এর মধ্যে 6টি filled হয়; 2টি ভুল exchange contract-এ settle হয়।
Root cause: bot flags object-এ negRisk: true সেট না করেই createAndPostOrder কল করছিল। market-এর মধ্যে 2টির historical creation date আলাদা ছিল এবং তাদের flag প্রয়োজন ছিল; বাকি 6টির প্রয়োজন ছিল না, কারণ তাদের underlying contract default-এই NegRisk দিয়ে routing হচ্ছিল।
Fix: প্রতিটি market-এর জন্য Gamma থেকে market.negRisk পড়ে প্রতিটি order call-এ pass করা। Commit 06deaef। আমরা flag set করে arb আবার চালাই; বাকি 2টিও ঠিকভাবে settle হয়।
Lesson: market property কখনো default করবেন না। প্রতিবার source of truth থেকে explicitভাবে পড়ুন।
Sticky-fail dedup (commit 4c0bef1)
Bot 12 সেকেন্ডে failed buy 5 বার retry করেছিল। প্রথম attempt আসলে সফল হয়েছিল (network timeout-এর কারণে bot response দেখতে পায়নি); পরের 4টি retry আরও 4টি additional position তৈরি করে। মোট: আমরা যেখানে 1টি চেয়েছিলাম, একই market-এ 5টি position।
Root cause: idempotent client-order-id ছিল না। Bot-এর retry logic ছিল "failed হলে, নতুন salt দিয়ে আবার চেষ্টা করো।" CLOB-এর কাছে retry-গুলোকে duplicate হিসেবে চেনার কোনো উপায় ছিল না।
Fix: প্রথম attempt-এর আগে intended order প্রতি একটি deterministic UUID generate করা। সব retry একই client-order-id ব্যবহার করে, যাতে CLOB dedup করতে পারে। Commit 4c0bef1।
Lesson: idempotence ছাড়া retry মানে duplicate। প্রতিটি order-এর একটি stable client-side identifier দরকার।
Whipsaw incident: lol-ctg-ccg
একটি esports match (CTG vs CCG)-এ imbalance positive হওয়ায় bot 0.45-এ buy enter করেছিল। 30 সেকেন্ডের মধ্যে imbalance negative হয়ে যায় এবং আমাদের GTC sell 0.50-এ অন্য কারও order দ্বারা hit হয়। PnL: +5c × 10 shares = +$0.50।
10 মিনিট পরে, একই market-এর imbalance আবার positive হয়ে যায়। Bot আবার 0.42-এ enter করে। এবার imbalance আর recover করেনি; mid drift করে 0.18-এ নামে এবং position resolution-এ 0-তে গিয়ে শেষ হয়।
Root cause: strategy-টি imbalance-কে directional signal হিসেবে দেখছিল, কিন্তু বুঝতে পারেনি যে imbalance bounce করছিল - দুটো signal-ই noise ছিল, information নয়। Bot একই market-এ 20 মিনিটের মধ্যে দুইটি failed signal-এর মধ্যে whipsaw হয়ে যায়।
Fix: প্রতি market-এ cooldown - fill-এর পরে একই market-এ 30 মিনিট নতুন entry নয়। Different market-এ multiple entry allowed ছিল, কিন্তু একই market-এ back-to-back নয়।
Lesson: যে signal bounce করে, সেটা signal নয়। Act করার আগে persistence filter করুন।
Premature go-live: 2025 wipe
একটি নতুন market-making strategy 12টি paper trade পাস করেছিল। Builder 30 পর্যন্ত অপেক্ষা করেনি, "ভালোই লাগছে" ধরে live deploy করে দেয় $500 capital দিয়ে। 18 ঘণ্টার মধ্যে wallet $200-এ নেমে আসে।
Root cause: 12টি trade 60% WR আর 35% WR আলাদা করতে যথেষ্ট sample নয়। Strategy-টি বাস্তবে 35% WR ছিল; 12-trade paper window-তে কেবল একটি unrepresentative streak পড়ে গিয়েছিল।
30-trade gate একটি কারণেই আছে। 12-trade sample-এর variance এটাকে "strategy কাজ করছে না" - এর থেকে আলাদা করা যায় না।
Lesson: conviction-এর চেয়ে discipline জিতবে। 30-trade gate negotiable নয়।
Sleep-through-bug: kill switch worked
Bot-এর time-of-day filter-এ off-by-one bug ছিল - 02:00 UTC-এ pause করার কথা, কিন্তু আসলে 03:00 UTC-এ pause করছিল। 02:00-03:00 un-paused hour-এ Polygon RPC আমাদের request অনেক বেশি rate-limit করছিল; bot-এর read path stale data ফেরত দিচ্ছিল।
Bot stale price নিয়ে trading চালিয়ে যাচ্ছিল। Hour-এর PnL: 22টি trade জুড়ে -$3.20। Daily-loss kill switch -5%-এ trigger হয়, bot halt করে, 03:08 UTC-এ Telegram alert পাঠায়। Builder 09:00-এ উঠে দেখে bot halted, মোট ক্ষতি kill threshold-এ সীমাবদ্ধ।
Lesson: bug real ছিল, কিন্তু kill switch কাজ করেছে। -$3.20, -$50.00 নয়। Risk control bug আটকায় না; আপনি যেসব bug দেখতে পাননি, সেগুলোর cost সীমাবদ্ধ করে।
Lessons that generalize
সব postmortem জুড়েই চারটি pattern বারবার দেখা যায়।
- API time ≠ chain time. Settlement lag, RPC lag, WebSocket lag - এগুলো সবই gap তৈরি করে, যেগুলো bot code-এ explicitly handle করতে হয়।
- Retries need idempotence. client-order-id ছাড়া retry মানে duplicate-order risk। সবসময়।
- প্রতিটি market property explicitly পড়ুন. NegRisk flag, tick size, expiration. কখনো default নয়; সবসময় source of truth থেকে পড়ুন।
- kill switch floor, feature নয়. Risk control bug-এর ক্ষতি cap করে। Strategy bug prevent করে না; ধরে নেয় bot ঠিকমতো কাজ করছে। Bot সবসময় ঠিকমতো কাজ করবে না।
এই সিরিজের প্রতিটি অধ্যায়ের কোথাও না কোথাও এই patternগুলোর একটি embedded আছে। এগুলোই production bot-এর load-bearing principle। এগুলো বাদ দিলে নিজের postmortem-এ এগুলো আবার খুঁজে পাবেন।





