26 সেপ্টেম্বর, 2026 · গবেষণা

আমরা একটি কৌশলের ব্যাকটেস্ট পুনরায় চালিয়ে দেখেছিলাম। সংখ্যাগুলো কোথায় বদলে গেল, তা এখানে।

আমরা একটি কৌশলের ব্যাকটেস্ট পুনরায় চালিয়ে দেখেছিলাম। সংখ্যাগুলো কোথায় বদলে গেল, তা এখানে।

সংরক্ষিত একটি ব্যাকটেস্ট আবার চালিয়ে আমরা ভিন্ন ইকুইটি কার্ভ পেলাম। কৌশলের কোড একই, তারিখের পরিসর একই, সিম্বলও একই। শেষের ব্যালেন্সে 1.8% পার্থক্য ছিল, আর 3টি ট্রেডের সময় 1 বার করে সরে গিয়েছিল।

গবেষণার ফলের ওপর আস্থা হারানোর জন্য এটুকুই যথেষ্ট। কোনো সহকর্মী, ভবিষ্যতের আপনি, কিংবা পেপার-ট্রেডিং সার্ভিস যদি রানটি পুনরায় তৈরি করতে না পারে, তাহলে কোনো পরিবর্তনে কৌশল উন্নত হয়েছে, নাকি শুধু পরীক্ষাটাই বদলে গেছে—তা বোঝা যায় না। বিচ্যুতির উৎস খুঁজতে আমরা যে ধাপগুলো অনুসরণ করেছি, সেগুলো এখানে।

দিন 1: “একই রান” বলতে কী বোঝায়, তা লিখে রাখলাম

আমাদের প্রথম ভুল ছিল কৌশলের ফাইলটিকেই পুরো পরীক্ষা ধরে নেওয়া। আসলে তা নয়। রানটি ইনপুট ডেটা, ইঞ্জিনের সংস্করণ, ক্যালেন্ডার, ইনস্ট্রুমেন্টের মেটাডেটা এবং এক্সিকিউশন সেটিংসের ওপরও নির্ভর করত। কোডটি গণনার মাত্র একটি অংশ বর্ণনা করেছিল।

কিছু বদলানোর আগেই আমরা একটি রান ম্যানিফেস্ট তৈরি করলাম। তাতে কৌশলের কমিট, ডেটা স্ন্যাপশটের আইডি, তারিখের পরিসর, ভেন্যু, ফি সূচি, ফান্ডিংয়ের উৎস, ফিল মডেল এবং সফটওয়্যারের সংস্করণ লিখে রাখলাম। ফলাফলের অর্ডার ও ফিলও সংরক্ষণ করলাম, কারণ শুধু ইকুইটি কার্ভ দেখে বোঝা যায় না—দুটি রান প্রথম কোথায় আলাদা হয়েছে।

উপাদানযা নথিবদ্ধ করবেনকেন জরুরি
মার্কেট ডেটাস্ন্যাপশট আইডি, স্কিমার সংস্করণ, সমন্বয়ভেন্ডররা পুরোনো রেকর্ড সংশোধন করে এবং করপোরেট অ্যাকশন হালনাগাদ করে
এক্সিকিউশনফি টিয়ার, ফান্ডিং সিরিজ, ফিল ও ইমপ্যাক্ট সেটিংসডিফল্ট ও অ্যাকাউন্ট-সংক্রান্ত অনুমান ফল বদলে দেয়
রানটাইমকোড কমিট, ইঞ্জিন ও ডিপেন্ডেন্সির সংস্করণলাইব্রেরি অর্ডার, রাউন্ডিং বা ইন্ডিকেটরের আচরণ বদলে দিতে পারে
আউটপুটঅর্ডার, ফিল, পজিশন ও মেট্রিকরান দুটি কোথা থেকে অমিল হতে শুরু করেছে তা দেখায়

দিন 2: Sharpe নয়, ট্রেডগুলো তুলনা করলাম

সারাংশের মেট্রিকগুলো মনোযোগ সরিয়ে দিচ্ছিল। দুই রানের Sharpe প্রায় একই ছিল, কিন্তু ফিল লগে দেখা গেল প্রথম অমিলটি ঘটেছে ফান্ডিং সেটেলমেন্টে। এক রান সেটেলমেন্টের টাইমস্ট্যাম্পে খোলা পজিশনে রেট প্রয়োগ করেছিল; অন্যটি ওই টাইমস্ট্যাম্পের রিব্যালান্সের পরের পজিশন ব্যবহার করেছিল।

কৌশলের কোড বদলায়নি। বদলেছিল ইঞ্জিনের ইভেন্ট সাজানোর ক্রম। সংস্করণের ছোট একটি আপডেটে ক্রমটি স্পষ্টভাবে নির্ধারিত হয়েছিল; আগে দুটি ইভেন্ট কীভাবে সাজানো হতো, তার ওপরই তা নির্ভর করত।

রান চুক্তিতে আমরা ক্রমটি নির্দিষ্ট করলাম: সেটেলমেন্টে নিয়ে আসা পজিশনে আগে ফান্ডিং প্রয়োগ করতে হবে, তারপর ওই টাইমস্ট্যাম্পের কৌশলগত সিদ্ধান্তগুলো প্রক্রিয়া করতে হবে। ভেন্যু ও ইঞ্জিনভেদে সঠিক নিয়ম আলাদা হতে পারে। নিয়মটি অস্পষ্ট রাখাই ভুল।

দিন 3: “একই” ডেটা ফাইলটি আসলে আলাদা ছিল

ইভেন্টের ক্রম নির্দিষ্ট করার পর বাকি অমিলগুলো কয়েকটি ইকুইটি ট্রেডে জমা হয়েছিল। ভেন্ডর ঐতিহাসিক স্প্লিট সমন্বয় সংশোধন করেছিল। আমাদের ফাইলের নাম ও সারির সংখ্যা আগের মতোই ছিল, তাই ফাইলটি অপরিবর্তিত বলে মনে হয়েছিল।

এখন প্রতিটি অপরিবর্তনীয় ডেটা স্ন্যাপশটের ফিঙ্গারপ্রিন্ট রাখি এবং তার সঙ্গে সমন্বয়ের নীতিও সংরক্ষণ করি। হ্যাশ জানায় বাইট বদলেছে কি না; কেন বদলেছে, তা বলে না। তাই ম্যানিফেস্টে উৎস, সংগ্রহের সময় এবং রূপান্তরের সংস্করণও থাকে। যে ডেটা সংশোধিত হতে পারে, তার ক্ষেত্রে এসব বিবরণও ফলাফলের অংশ।

পুনরুৎপাদনযোগ্য ব্যাকটেস্টের উত্তর থাকা দরকার: “অতীতের কোন সংস্করণটি সে দেখেছিল?”

দিন 4: ডিফল্টের আড়ালে থাকা একটি সেটিং খুঁজে পেলাম

শেষ পার্থক্যটি ছিল maker ফি শূন্যে সেট থাকা, কারণ কৌশলের কনফিগে ফিল্ডটি বাদ পড়েছিল। নতুন ইঞ্জিন অ্যাকাউন্টের ডিফল্ট ফি প্রয়োগ করেছিল। ওই এক ডিফল্টেই প্রান্তিক ট্রেডগুলো যথেষ্ট বদলে যায়, যা শেষের ব্যালেন্সের পার্থক্যের বেশির ভাগ ব্যাখ্যা করে।

অর্থনৈতিকভাবে গুরুত্বপূর্ণ সেটিংগুলো আমরা স্পষ্টভাবে নির্ধারণ করলাম এবং ইঞ্জিনকে রান রেকর্ডে কার্যকর কনফিগারেশন ছাপাতে বললাম। অনুসন্ধানের সময় ডিফল্ট সুবিধাজনক। সময়ের ব্যবধানে ফল তুলনা করার সময় এগুলো নির্ভরযোগ্য প্রমাণ নয়।

3বিচ্যুতির উৎস পাওয়া গেছে
1.8%শুরুর শেষ-ব্যালেন্স পার্থক্য
0শুধু মিলে যাওয়া Sharpe-এর মূল্য

পরের বার যা বাদ দেব

প্রথম অমিল ফিল দেখার আগে আমরা মোট মেট্রিক তুলনা করতেই অর্ধেক দিন কাটিয়েছিলাম। সেখান থেকে শুরু করবেন না। দুই ইভেন্ট লগ টাইমস্ট্যাম্প অনুযায়ী সাজিয়ে প্রথম বিচ্যুতিটি তুলনা করুন; পরের অমিলগুলো প্রায়ই ওই এক কারণ থেকেই আসে।

কনটেইনার ইমেজ একাই রানকে পুনরুৎপাদনযোগ্য করে—এই ধারণাটিও বাদ দিতাম। এটি সফটওয়্যার পরিবেশের বড় অংশ নির্দিষ্ট করে, কিন্তু বাইরের ডেটা ফাইল, রানটাইমে আনা ফি সূচি বা ভেন্ডরের সংশোধিত ইতিহাস নয়।

ব্যাকটেস্ট বদলে গেলে দুই রানের ম্যানিফেস্ট ও লগ সংরক্ষণ করুন, তারপর একবারে বিচ্যুতির একটি উৎস ঠিক করুন। উপযোগী ফল শুধু এমন কার্ভ নয় যা আবার চালানো যায়। বরং এমন একটি রেকর্ড, যা জানায় কোন ডেটা ও অনুমান থেকে ফলটি তৈরি হয়েছে এবং পরের রান কেন আলাদা হতে পারে।

পুনরুৎপাদনযোগ্যতাব্যাকটেস্টিংডেটা প্রকৌশলপেপার ট্রেডিং
শেয়ার করুনXLinkedInFacebookRedditHacker NewsWhatsAppTelegramEmail
← সব পোস্ট