চারটি সংখ্যা, সবই আমাদের নিজস্ব পেপার-ট্রেডিং স্ট্যাক থেকে মাপা: একটি স্ট্র্যাটেজি, 1-minute BTCUSDT perpetual সিগন্যাল, 31 দিন এবং 1,418টি অর্ডার। বার ক্লোজ থেকে এক্সচেঞ্জের অর্ডার স্বীকার করা পর্যন্ত median সময়: 195 ms। 99তম percentile: 2,970 ms। সর্বোচ্চ realized volatility-র 1% মিনিটে median: 840 ms। আর এর আগের বছরের বেশির ভাগ সময় ব্যাকটেস্ট কনফিগে যে ল্যাটেন্সি কনস্ট্যান্ট ছিল: 0.
এই সংখ্যাগুলোর তিনটি একঘেয়ে। সবাই জানে শূন্য ভুল, একসময় সবাই সেটাকে কিছু একটা দিয়ে বদলায়, আর সেই কিছু একটা প্রায় সব সময়ই কারও আন্দাজে বেছে নেওয়া কনস্ট্যান্ট। 100 ms, 250 ms, “সতর্ক থাকি, 500।” আসলে যে সংখ্যাটা গুরুত্বপূর্ণ, সেটা 840; কারণ এটি বলে যে আপনার ল্যাটেন্সি বাজারের অবস্থার ওপর নির্ভরশীল, আর যে বাজার-অবস্থায় ল্যাটেন্সি বেড়ে যায়, ঠিক সেই অবস্থাতেই আপনার সিগন্যাল ভাবে সে কিছু একটা খুঁজে পেয়েছে।
195 মিলিসেকেন্ড কোথায় যায়
এখানে পুরো বাজেটটি দেওয়া হলো। প্রতিটি ধাপে monotonic-clock timestamp লিখে মাপা হয়েছে। বক্সটি ap-northeast-1-এ AWS instance, ভেন্যুর endpoint-গুলোর একই region-এ—colocation ছাড়া retail-ধাঁচের সেটআপ যতটা ভালো হতে পারে, প্রায় ততটাই।
| ধাপ | p50 | p95 | p99 |
|---|---|---|---|
| বার ক্লোজ → WS kline-closed event পাওয়া | 128 ms | 402 ms | 1,940 ms |
| Parse + feature state update | 3 ms | 9 ms | 28 ms |
| সিদ্ধান্ত: model eval + risk checks | 11 ms | 22 ms | 60 ms |
| Order submit → exchange ack | 47 ms | 180 ms | 1,100 ms |
| End-to-end (মাপা, যোগ করে পাওয়া নয়) | 195 ms | 690 ms | 2,970 ms |
আসল কথায় যাওয়ার আগে 2টি বিষয় খেয়াল করুন। প্রথমত, median-গুলো যোগ হয় না: 128 + 3 + 11 + 47 = 189, অথচ মাপা end-to-end median 195। Percentile যোগ করা যায় না। প্রতি ধাপের p99 যোগ করে ল্যাটেন্সি অনুমান করলে 3,128 ms পাবেন, যেখানে প্রকৃত p99 হলো 2,970। এখানে কাছাকাছি; ধাপগুলোর পারস্পরিক সম্পর্ক উল্টো দিকে হলে হিসাব ভয়ানক ভুল হবে। পুরো পথটা মাপুন।
দ্বিতীয়ত, ওপরের সারিটি দেখুন। median বাজেটের দুই-তৃতীয়াংশ চলে যায় এক্সচেঞ্জের কাছ থেকে বার বন্ধ হওয়ার খবরের অপেক্ষায়। নেটওয়ার্ক নয়, আপনার কোড নয়, order routing নয়। ভেন্যু ট্রেডগুলো একত্র করে kline বানায়, মিনিট শেষ হয়েছে বলে সিদ্ধান্ত নেয়, তারপর সেটি পাঠায়। পাঠানোর আগে একটি queue থাকে, আর সেই stream-এর অন্য সব subscriber-এর সঙ্গে queue-টি ভাগাভাগি করা হয়।
840-এর কথা
সিগন্যাল তৈরি করা মিনিটের realized volatility অনুযায়ী ওই 1,418টি অর্ডারের প্রতিটিকে ভাগ করলে বণ্টনটা স্পষ্ট হয়ে যায়।
| সিগন্যাল-বারের volatility bucket | অর্ডার | p50 end-to-end | p99 end-to-end |
|---|---|---|---|
| নিচের quartile | 201 | 141 ms | 488 ms |
| মাঝের 2টি quartile | 796 | 183 ms | 1,210 ms |
| ওপরের quartile | 407 | 312 ms | 2,880 ms |
| সব মিনিটের সর্বোচ্চ 1% | 14 | 840 ms | 4,100 ms |
প্রতিটি ধাপ একসঙ্গে ধীর হয়, তাই প্রভাবটা জমতে থাকে। ভেন্যুর aggregation ও broadcast queue-তে matching-engine-এর চাপ এসে পড়ে, ফলে 11,000টি ট্রেড থাকা একটি মিনিট 600টি ট্রেডের মিনিটের চেয়ে দেরিতে পাঠানো হয়। একই সময়ে আপনার নিজের process-কে আরও বেশি depth update ও trade print সামলাতে হয়, তাই যে feature update সাধারণত 3 ms নেয়, তা 28 ms নেয়। REST order path-এ সবার আতঙ্কের সঙ্গে প্রতিযোগিতা চলে, আর মাঝেমধ্যে 503-এর পর retry করতে হয়, যাতে একাই পুরো এক সেকেন্ড চলে যায়। আমাদের নমুনায় signal-bar trade count ও end-to-end latency-র correlation coefficient ছিল 0.41। খুব বেশি নয়। তবু একটি কনস্ট্যান্টকে অকার্যকর করার জন্য যথেষ্ট।
আর প্রাথমিক যাচাইয়ে টিকে থাকা স্ট্র্যাটেজিগুলো বেশির ভাগই breakout, reversal, dislocation, liquidation cascade-এ ট্রেড করে। সেগুলো ঠিক সেই bucket-এই সংকেত দেয় যেখানে ল্যাটেন্সি সবচেয়ে বেশি। যে momentum signal শুধু মিনিটে 40 bps নড়াচড়া হলেই ট্রিগার হয়, সেটি কাঠামোগতভাবেই এমন ব্যবস্থা করেছে যে আপনার স্ট্যাকের সবচেয়ে ধীর সংস্করণ দিয়েই সেটি কাজ পাবে।
একবার প্রায় প্রতি রাতে একই সময়ে দেখা দেওয়া 3.6-second-এর একটি outlier খুঁজতে আমরা পুরো দিন কাটিয়েছিলাম। কারণ ছিল logrotate: একই EBS volume-এ process যখন লিখছিল, তখন সেটি একটি 2 GB file কপি করে truncate করছিল, ফলে event loop আটকে যাচ্ছিল। বাজারের কোনো দোষ ছিল না। আগে মাপুন, তারপর microstructure-কে দোষ দিন।
এতে fill-এর কী হয়
অপেক্ষার সময় দাম সরে যায়। যেকোনো একটি মিনিটে আমাদের 195 ms median-এ গড় প্রতিকূল দাম-পরিবর্তন সিগন্যালের দিকের বিপরীতে প্রায় 1.1 bps ছিল। 312 ms-এ ওপরের quartile-এর মিনিটগুলোতে 5.8 bps। সর্বোচ্চ 1% মিনিটে 840 ms-এ, অর্ডার book-এ পৌঁছানোর আগেই প্রতিকূল দিকে প্রায় 14 bps সরে যায়।
BTC perps-এ spread-এর প্রভাব প্রায় নেই: 84,000 quote-এ এক tick হলো 0.012 bps, তাই ক্ষতিটা crossing cost থেকে নয়, প্রতিকূল দামের সরে যাওয়া থেকে আসে। একই স্ট্র্যাটেজি mid-cap perp-এ নিলে দ্বিতীয় প্রভাবটিও দেখা দেয়—আমাদের নমুনায় top-of-book spread শান্ত মিনিটে 1.4 bps থেকে ওপরের quartile-এ 6.2 bps হয়েছে, আর ওই দামে depth অর্ধেকেরও বেশি কমে গেছে। দামের সরে যাওয়া, চওড়া spread এবং কম depth—সবকিছুরই খরচ আপনাকে একসঙ্গে দিতে হয়, কারণগুলোর উৎস একই।
একই 31 দিন flat 200 ms-এর বদলে প্রতি bar-এর জন্য শর্তসাপেক্ষ latency দিয়ে replay করলে, ব্যাকটেস্টে গড় entry price 3.1 bps খারাপ হয়েছে; এর প্রায় পুরোটাই মাত্র 9% ট্রেডে কেন্দ্রীভূত। ব্যাকটেস্ট ও পেপার ট্রেডিংয়ের entry-price divergence 4.2 bps থেকে কমে 0.9 bps হয়েছে। সেই স্ট্র্যাটেজির in-sample Sharpe 1.7 থেকে 1.1-এ নেমেছে—সৎ সংখ্যাটি এটাই, এবং সব সময়ই এটাই ছিল।
তাহলে কনফিগে আসলে কী রাখবেন
একটি scalar নয়। এখন আমরা যা চালাই:
- সেট করবেন না, নমুনা থেকে নিন। প্রতিটি simulated order-এর latency ওই bar-এর নিজস্ব কার্যকলাপের শর্তে empirical distribution থেকে নিন—trade count ও absolute return যথেষ্ট, আর দুটিই standard kline-এ থাকে। প্রতি venue ও order type-এর জন্য একবার fit করে মাসে মাসে refit করুন।
- Tail বজায় রাখুন। lognormal fit করেই শেষ ভাববেন না; p99 থাকে retry storm ও GC pause-এ, যা কোনো smooth distribution-এ ঠিকমতো ধরা পড়ে না। আমরা p95-এর ওপর resampled tail-সহ empirical quantile ব্যবহার করি।
- Cancel-এর ক্ষেত্রেও latency প্রযোজ্য। Stop replacement বা hedge cancel-ও একই বিলম্বের মুখে পড়ে, আর দ্রুত বাজারে আপনার cancel একটি fill-এর সঙ্গে পাল্লা দেয়। আপনার simulator যদি সঙ্গে সঙ্গে cancel করে, তাহলে আপনার risk model কল্পনাপ্রসূত।
- Staleness guard যোগ করুন, সেটিও simulate করুন। আমাদের সিস্টেমে আসার সময় bar 1.5 seconds-এর বেশি পুরোনো হলে যেকোনো signal বাদ পড়ে। এর বাস্তব আচরণ ও বাস্তব খরচ আছে—নীরবে ট্রেড বাদ পড়ে, আর ব্যাকটেস্টেও একই ট্রেড বাদ দিতে হবে।
- পেপার ট্রেডিংয়ের সঙ্গে মিলিয়ে পুনঃক্যালিব্রেট করুন। আসল মান পাওয়ার জায়গা হলো পেপার ট্রেডিং। প্রতিটি অর্ডারের চারটি hop timestamp log করুন, তারপর simulator যা ধরে নিয়েছিল তার সঙ্গে বণ্টনের পার্থক্য প্রতি সপ্তাহে দেখুন।
অন্য asset class-এও একই সমস্যা। US equities: আপনার broker-এর বিলম্বের সঙ্গে consolidated tape-এর নিজস্ব aggregation delay যোগ হয়, আর একই কাঠামোগত কারণে message-rate-এর চাপ বাড়লে সেটিও দীর্ঘ হয়। Prediction market: বেশির ভাগ venue-তে order entry শুধু REST দিয়ে হয়; আমরা 100 ms-এর নিচে median মেপেছি, যা কোনো resolution event-এ সবাই একসঙ্গে এসে পড়লে কয়েক সেকেন্ডে পৌঁছে যায়। Crypto options: underlying যে মিনিটে নড়েছে, ঠিক সেই মিনিটেই আপনি যে quote ধরে মূল্য নির্ধারণ করছেন সেটি 2 seconds পুরোনো হতে পারে।
এই ভুলের সাধারণ ধরন হলো execution parameter-কে স্বতন্ত্র ধ্রুবক ধরে নেওয়া, যদিও সেটি আসলে আপনার signal চালানো একই state variable-এর ওপর নির্ভর করে। Fees স্থিতিশীল, funding স্থিতিশীল; latency নয়। এ সব থেকে একটি সংখ্যার কথা মনে রাখতে হলে অনুপাতটি মনে রাখুন: আমাদের p99, median-এর পনেরো গুণ, আর আমাদের signal-গুলো অসমানুপাতিকভাবে বেশি p99-এর কাছাকাছি সময়ে আসে।
চারটি hop instrument করে দেখুন। এক বিকেলের কাজ, আর parameter search-এ আরও এক সপ্তাহ দেওয়ার চেয়ে আপনার স্ট্র্যাটেজি সম্পর্কে বেশি কিছু জানাবে।
← সব পোস্ট


