پاسخ کوتاه
داده بازار زمانی برای هوش مصنوعی و بکتست آماده است که منبع، نماد، بازه زمانی و منطقه زمانی آن مشخص و مستند باشد، رکوردهای تکراری و جاافتاده بررسی و علتیابی شده باشند، روابط منطقی قیمت (مثل High ≥ Low) اعتبارسنجی شده باشد، هیچ اطلاعاتی از آینده وارد گذشته نشده باشد، و نسخهای فریزشده از همان دیتاست با متادیتای کامل ذخیره شده باشد.
مدل خوب داده بد را نجات نمیدهد. اگر دیتاست شما یک ساعت جابهجا باشد یا فیچرهایتان از کندلی که هنوز بسته نشده استفاده کنند، هر عددی که بکتست بیرون میدهد — هر قدر هم زیبا — درباره بازار چیزی نمیگوید.
دو نفر یک استراتژی کاملاً یکسان را روی یک نماد و یک بازه زمانی یکسان بکتست میکنند. نتیجه نفر اول مثبت است و نتیجه نفر دوم منفی. اولین فرضی که همه میکنند این است که یکی از آن دو در پیادهسازی اشتباه کرده. اما ممکن است هر دو پیادهسازی از نظر منطق درست باشند و اختلاف از لایه داده آمده باشد:
- دیتای دو نفر از دو Data Provider متفاوت آمده و آن دو تیکهای یکسانی ثبت نکردهاند.
- مُهر زمانی یکی UTC است و دیگری بر مبنای منطقه زمانی دیگری ذخیره شده — مثلاً چند ساعت اختلاف.
- یکی از دیتاستها در بازهای کندل جاافتاده دارد و ابزار بکتست بیسروصدا آن را پر کرده است.
- اسپرد در دو دیتاست متفاوت است، چون اسپرد در بکتست شبیهسازی نمیشود بلکه از خود داده تاریخی میآید.
- تعریف Session در دو پیادهسازی فرق دارد و «ابتدای لندن» برای هرکدام ساعت دیگری است.
هیچکدام از این پنج مورد به منطق استراتژی مربوط نیست. همه به داده مربوطاند. و این دقیقاً همان لایهای است که در محتوای فارسی حوزه معاملهگری تقریباً هیچوقت دربارهاش حرف زده نمیشود.
این مقاله مرحله قبل از بکتست است. اگر میخواهید بدانید بعد از آماده شدن داده، استراتژی را چطور باید اعتبارسنجی کرد، به راهنمای بکتست با هوش مصنوعی و اعتبارسنجی Strategy بروید. برای دیدن کل نقشه این حوزه هم نقشه کامل هوش مصنوعی در معاملهگری نقطه شروع بهتری است، و اگر با موضوع تازه آشنا شدهاید مقدمه هوش مصنوعی در معاملهگری را اول بخوانید.
اگر فقط ۳۰ ثانیه وقت دارید
یک دیتاست مناسب برای مدلسازی و بکتست باید این ده شرط را همزمان داشته باشد:
- منبع داده مشخص و ثبتشده باشد
- مُهر زمانی هر رکورد صحیح و یکنواخت باشد
- منطقه زمانی صراحتاً اعلام شده باشد
- داده جاافتاده بررسی و علتیابی شده باشد
- رکورد تکراری نداشته باشد
- رابطه Bid و Ask و اسپرد منطقی باشد
- مرز Sessionها مشخص و مستند باشد
- هیچ اطلاعاتی از آینده وارد گذشته نشده باشد
- نسخه دیتاست ثبت و فریز شده باشد
- قبل از بکتست از یک اعتبارسنجی خودکار عبور کرده باشد
این مقاله بخشی از خوشه «هوش مصنوعی در معاملهگری» فیلتور است — مجموعهای مهندسیمحور و بدون وعده سود.
مشاهده نقشه کامل AI در معاملهگری ←۰۱چرا کیفیت داده از خود مدل مهمتر است؟
هیچ مدلی — نه یک شبکه عصبی و نه یک اکسپرت ساده — بازار را نمیبیند. هر دو فقط عددهایی را میبینند که ما به آنها دادهایم. اگر آن عددها بازار را درست نمایندگی نکنند، خروجی مدل درباره یک بازار خیالی است، نه بازار واقعی.
این جمله در ظاهر بدیهی است، اما پیامد عملیاش را کمتر کسی جدی میگیرد. فرض کنید در یک کندل یکدقیقهای، مقدار High بهاشتباه چند پیپ بالاتر از مقدار واقعی ثبت شده باشد. یک خطای ظاهراً بیاهمیت. حالا ببینید چه اتفاقاتی میتواند بیفتد:
- حد ضرری که در واقعیت هرگز لمس نشده، در بکتست فعال میشود و یک معامله برنده به بازنده تبدیل میشود.
- حد سودی که در واقعیت نخورده، در بکتست میخورد و یک معامله بازنده به برنده تبدیل میشود.
- منطق شکست سقف (Breakout) یک سیگنال جعلی تولید میکند که هرگز وجود نداشته است.
- اگر برای مدل یادگیری ماشین برچسب میسازید، برچسب همان نمونه غلط میشود — و مدل یاد میگیرد الگویی را که وجود ندارد.
نکته مهم این است که این چهار پیامد خطای تصادفی نیستند. اگر خطای داده سیستماتیک باشد — مثلاً همیشه در ساعت خاصی یا همیشه در یک نماد خاص — مدل آن را بهعنوان یک الگوی واقعی یاد میگیرد. یعنی داده بد نهتنها نویز اضافه میکند، بلکه میتواند سیگنال جعلی بسازد. و سیگنال جعلی از نویز خطرناکتر است، چون نویز باعث میشود مدل ضعیف به نظر برسد، ولی سیگنال جعلی باعث میشود مدل قوی به نظر برسد.
ادبیات آکادمیک این را با اعداد نشان داده است. در بررسی گستردهای که کاپور و نارایانان روی پژوهشهای مبتنی بر یادگیری ماشین انجام دادند، ۲۹۴ مقاله در ۱۷ حوزه علمی شناسایی شدند که بهخاطر نشت داده (Data Leakage) به نتایج بیشازحد خوشبینانه رسیده بودند؛ آنها هشت نوع مجزای نشت داده را دستهبندی کردند که یکی از آنها مستقیماً «نشت زمانی» است[۱]. این حوزهها شامل پزشکی، امنیت رایانه و علوم اجتماعی میشود — یعنی مشکل، مشکلِ داده است نه مشکلِ بازار مالی. بازار مالی فقط جایی است که هزینهاش را سریعتر میپردازید.
۰۲داده بازار دقیقاً چیست؟
«داده بازار» یک چیز واحد نیست. دستکم شش لایه متفاوت وجود دارد که هرکدام سؤال متفاوتی را جواب میدهند و هزینه، حجم و دقت متفاوتی دارند. اولین تصمیم مهندسی شما انتخاب لایه درست است، نه انتخاب مدل.
OHLC — چهار عدد خلاصهشده
رایجترین شکل داده بازار. هر بازه زمانی (یک دقیقه، یک ساعت، یک روز) با چهار عدد خلاصه میشود: قیمت باز شدن، بالاترین قیمت، پایینترین قیمت و قیمت بسته شدن. این چهار عدد کل ماجرای داخل آن بازه را در خود فشرده میکنند — و همین فشردهسازی همان چیزی است که بعداً دردسر میسازد.
نکتهای که مدام از قلم میافتد: مُهر زمانی یک کندل معمولاً زمان باز شدن آن است، نه زمان بسته شدن. در متاتریدر ۵ صراحتاً فیلد زمان در ساختار کندل «زمان شروع دوره» تعریف شده است[۲]. اگر شما این را زمان بسته شدن فرض کنید، کل دیتاست شما یک تایمفریم به جلو جابهجا شده و — بدتر از آن — فیچرهایتان از اطلاعاتی استفاده میکنند که در آن لحظه هنوز موجود نبوده است.
OHLCV — حجم را اضافه کنید، اما بدانید کدام حجم
وقتی حجم به چهار عدد قبلی اضافه میشود، OHLCV داریم. اما اینجا یک تله جدی وجود دارد که در فارکس تقریباً همه در آن میافتند.
در متاتریدر برای نمادهای فارکس، آن چیزی که «حجم» نمایش داده میشود حجم تیک است، نه حجم واقعی معاملهشده. مستندات رسمی متاکوتس این را صریح میگوید: «برای بازار فارکس، حجمها شاخصی از تعداد تغییرات قیمت در هر دوره از تایمفریم انتخابشده است» — در حالی که «برای نمادهای بورسی این شاخصی از حجم واقعاً معاملهشده است»[۳]. در ساختار داده متاتریدر این دو، دو فیلد کاملاً جدا هستند: tick_volume و real_volume[۲].
حجم تیک یعنی «سرور بروکر من در این دقیقه چند بار قیمت را بهروز کرد». این عدد به تعداد ارائهدهندگان نقدینگی آن بروکر، به فیلترهای داخلیاش و به کیفیت اتصال بستگی دارد. دو بروکر برای یک دقیقه یکسان میتوانند دو حجم تیک کاملاً متفاوت گزارش کنند. اگر فیچری بسازید که به حجم تیک وابسته باشد، آن فیچر بخشی از رفتار بروکر را یاد میگیرد، نه رفتار بازار.
Tick Data — دانهریزترین لایه
هر تیک یک بهروزرسانی قیمت است. در فارکس معمولاً شامل Bid، Ask و زمان است؛ در بازارهای بورسی میتواند شامل قیمت و حجم آخرین معامله هم باشد. مستندات متاکوتس تصریح میکند که «برای ابزارهای فارکس معمولاً فیلدهای last، volume و volume_real خالی میمانند»[۴]. یعنی حتی در تیکدیتای فارکس هم لزوماً حجم واقعی ندارید.
Bid و Ask — دو قیمت، نه یکی
Bid بالاترین قیمتی است که کسی حاضر است بخرد و Ask پایینترین قیمتی که کسی حاضر است بفروشد. فاصله این دو، اسپرد است. اکثر چارتها فقط یکی از این دو (معمولاً Bid) را نمایش میدهند، اما شما با Ask میخرید و با Bid میفروشید. این تفاوت در بخش ۱۲ مفصلتر بررسی میشود.
Trade Data و دفتر سفارش
در بازارهایی که معاملات رسمی ثبت میشوند، داده معاملات (قیمت، حجم، جهت) در دسترس است. یک لایه عمیقتر، Order Book یا Level 2 است که سفارشهای در انتظار را در سطوح مختلف قیمت نشان میدهد. این لایه حجم بسیار بالایی دارد و برای اکثر استراتژیها لازم نیست — اما برای استراتژیهای حساس به نقدینگی و مدلسازی اثر بازار ضروری است.
داده بنیادی و جایگزین
ترازنامهها، گزارشهای درآمد، دادههای کلان اقتصادی، اخبار، احساسات شبکههای اجتماعی و دادههای ماهوارهای در این دسته قرار میگیرند. اینها یک مسئله کاملاً متفاوت در آمادهسازی دارند (بهخصوص از نظر تاریخ در دسترس بودن اطلاعات) و در این مقاله فقط در بخش ۱۵ به آن اشاره میشود. تمرکز این راهنما روی داده قیمت و بازار است.
۰۳تیکدیتا یا کندل؟ مقایسه واقعی
پاسخ «تیک همیشه بهتر است» غلط است. تیکدیتا دقیقتر است اما هزینه ذخیرهسازی، پردازش و اعتبارسنجی بهمراتب بالاتری دارد و اگر بد پاکسازی شود، از کندل تمیز بدتر است. انتخاب باید بر اساس حساسیت استراتژی انجام شود.
| نوع داده | حجم نسبی | دقت زمانی | کاربرد اصلی | مزیت | محدودیت | مناسب برای |
|---|---|---|---|---|---|---|
| Daily OHLC | بسیار کم | یک نقطه در روز | تحلیل پرتفوی، فاکتور | ساده، ارزان، سابقه طولانی | رفتار درونروز کاملاً پنهان است | استراتژیهای سوئینگ و بلندمدت |
| 1H / 4H OHLC | کم | ساعتی | استراتژیهای میانمدت | تعادل خوب حجم و اطلاعات | ترتیب لمس High و Low نامعلوم | روندی، شکست سطوح روزانه |
| 1m OHLC | متوسط | دقیقهای | پایه اکثر بکتستها | در دسترس، پوشش تاریخی خوب | مسیر داخل کندل بازسازی نمیشود | اکثر استراتژیهای درونروز |
| Tick (Bid/Ask) | بسیار زیاد | میلیثانیه | اجرا و اسپرد واقعی | ترتیب واقعی رویدادها | حجم عظیم، پاکسازی سخت، سابقه کوتاهتر | اسکالپ، حساس به اجرا، مدل هزینه |
| Level 2 / Book | عظیم | میلیثانیه | نقدینگی و اثر بازار | عمق واقعی بازار | گران، غالباً غیرقابل دسترس برای خرد | مدلهای ریزساختار بازار |
یک نکته که معمولاً نادیده گرفته میشود: در یک کندل یکساعته که هم High و هم Low نسبت به قیمت ورود شما فاصله دارند، شما نمیدانید کدامیک اول لمس شده است. اگر حد ضرر شما نزدیک Low و حد سود نزدیک High باشد، نتیجه آن معامله کاملاً به همین ترتیب نامعلوم بستگی دارد. موتورهای بکتست معمولاً یک فرض پیشفرض دارند (مثلاً «بدترین حالت» یا «اول Low») و شما باید بدانید آن فرض چیست. این یکی از مهمترین ابهامهایی است که داده دانهریزتر میتواند برطرف کند.
۰۴استراتژی شما به چه دانهبندی نیاز دارد؟
قاعده ساده است: هرچه تصمیم استراتژی به رویدادهای داخل کندل حساستر باشد، نیاز به داده دانهریزتر بیشتر میشود. اگر استراتژی فقط در بسته شدن کندل تصمیم میگیرد، داده دقیقتر عمدتاً هزینه است، نه دقت.
برای تصمیمگیری، این سه سؤال را از خودتان بپرسید:
- استراتژی چه زمانی تصمیم میگیرد؟ اگر فقط در لحظه بسته شدن کندل، همان تایمفریم کافی است. اگر میتواند در هر لحظه وارد شود، داده دانهریزتر لازم است.
- سفارشهای شرطی دارید؟ حد ضرر، حد سود، سفارشهای در انتظار و تریلینگ استاپ همگی داخل کندل فعال میشوند. هرچه این سفارشها به قیمت لحظه نزدیکتر باشند، ابهام درونکندل بیشتر روی نتیجه اثر میگذارد.
- هزینه معامله چقدر از سود مورد انتظار شماست؟ اگر سود مورد انتظار هر معامله چند برابر اسپرد است، خطای مدلسازی اسپرد اهمیت کمی دارد. اگر هماندازه اسپرد است، بدون داده Bid/Ask واقعی نتیجه بکتست بیمعنی است.
هرچه استراتژی به اتفاقات داخل کندل حساستر باشد، نیاز به داده دقیقتر بیشتر میشود.
و برعکس: استفاده از تیکدیتا برای استراتژیای که فقط در بسته شدن کندل روزانه تصمیم میگیرد، فقط هزینه و ریسک خطا اضافه میکند.
۰۵چرا منبع داده اهمیت دارد؟
دو ارائهدهنده داده برای یک نماد و یک بازه، اطلاعات کاملاً یکسانی نمیدهند. در فارکس این موضوع ساختاری است، نه یک نقص فنی — چون بازار اسپات فارکس یک بورس مرکزی واحد ندارد.
بانک تسویه بینالمللی در تحلیل نظرسنجی سهسالانه ۲۰۲۵ این را صریح میگوید: «برخلاف سهام یا قراردادهای آتی که در بورسهای متمرکز معامله میشوند، معاملات اسپات و بیشتر مشتقات ارزی خارج از بورس (OTC) انجام میشوند» و بازار در نتیجه «غیرمتمرکز و پراکنده» است[۵]. حجم روزانه معاملات ارزی OTC در آوریل ۲۰۲۵ به ۹٫۶ تریلیون دلار رسیده که ۳ تریلیون دلار آن اسپات بوده است[۶] — اما این حجم روی دهها ونیو و صدها رابطه دوطرفه پخش شده است.
پیامد عملی ساده است: «قیمت طلا در ساعت ۱۰:۳۰» یک عدد واحد جهانی نیست. عددی که شما دارید، قیمتی است که یک تجمیعکننده خاص از مجموعهای خاص از ارائهدهندگان نقدینگی در آن لحظه ثبت کرده است. دلایل تفاوت بین منابع:
- ترکیب نقدینگی: هر بروکر به مجموعه متفاوتی از بانکها و ارائهدهندگان وصل است.
- روش تجمیع: بعضی بهترین Bid و Ask را برمیدارند، بعضی میانگین وزنی میگیرند، بعضی مارکآپ اضافه میکنند.
- فیلترینگ: بعضی ارائهدهندگان تیکهای پرت را حذف میکنند و بعضی نه.
- دقت مُهر زمانی: بعضی تا میلیثانیه ثبت میکنند و بعضی تا ثانیه — و در ثانیههای شلوغ، ترتیب رویدادها گم میشود.
- پوشش تاریخی: دیتای قدیمیتر معمولاً کمدقتتر و پر از حفره است.
وسوسهانگیزترین اشتباه این است که وقتی منبع اول برای بازهای داده ندارد، آن بازه را از منبع دوم بردارید. نتیجه یک دیتاست است که در نقطه اتصال، سطح قیمت، اسپرد و رفتار تیکها ناگهان تغییر میکند. مدل شما آن نقطه اتصال را بهعنوان یک رویداد بازار یاد میگیرد. اگر مجبور به ترکیب هستید، حتماً یک ستون source در دیتاست نگه دارید و در تحلیل نتایج، رفتار مدل را در مرزهای منبع جداگانه بررسی کنید.
۰۶مشکل منطقه زمانی؛ خطای پنهانی که همه را میگیرد
منطقه زمانی رایجترین خطای خاموش در آمادهسازی داده بازار است. خاموش، چون هیچ ارور نمیدهد؛ دیتاست سالم به نظر میرسد، نمودار درست رسم میشود، بکتست اجرا میشود — و نتیجه درباره ساعت دیگری از روز است.
چهار مفهوم زمانی وجود دارد که مدام با هم اشتباه گرفته میشوند:
| مرجع | تعریف | مشکل رایج |
|---|---|---|
| UTC | زمان هماهنگ جهانی، بدون تغییر فصلی | تنها مرجع پایدار — ولی داده خام معمولاً با آن ذخیره نشده |
| زمان سرور بروکر | ساعت داخلی سرور معاملاتی | بین بروکرها متفاوت است و معمولاً مستند نیست |
| زمان بورس | ساعت رسمی محل معامله | برای هر نماد فرق دارد؛ تعطیلات محلی دارد |
| زمان محلی شما | ساعت سیستم عامل | بدترین انتخاب برای ذخیرهسازی؛ با سفر و تنظیمات تغییر میکند |
یک مثال ملموس. استراتژی میگوید: «در ابتدای سشن لندن معامله کن.» شما یک قانون مینویسید که در ساعت مشخصی از روز فعال شود. اگر دیتاست شما با زمان سرور بروکر ذخیره شده باشد و شما آن را UTC فرض کنید، استراتژی شما عملاً در ساعتی کاملاً دیگر تست میشود — احتمالاً وسط سشن آسیا یا بعد از باز شدن نیویورک. کد بدون خطا اجرا میشود، نتیجه هم عددی میدهد. آن عدد فقط ربطی به فرضیه شما ندارد.
مستندات رسمی متاکوتس برای اتصال پایتون صریح است: هنگام ساخت شیء datetime، پایتون ممکن است منطقه زمانی محلی سیستم را اعمال کند، اما داده تیک و زمان باز شدن کندل که از MetaTrader 5 به Python میرسد در UTC است؛ بنابراین ورودیهای زمانی این API را باید در UTC بسازید و خروجی را نیز UTC تفسیر کنید[۷]. این نکته را با «زمان سرور بروکر» یا ساعت نمایشدادهشده در منابع دیگر یکی نگیرید: اگر داده را از CSV بروکر، پلتفرم دیگری یا یک Data Provider جدا میگیرید، منطقه زمانی همان منبع باید صریحاً مستند و پیش از ترکیب دادهها یکسانسازی شود.
- همه چیز را در یک مرجع واحد ذخیره کنید — ترجیحاً UTC واقعی.
- منطقه زمانی را در متادیتای دیتاست بنویسید، نه در ذهنتان.
- برای تبدیل، از شناسه منطقه زمانی IANA (مثل
America/New_York) استفاده کنید، نه از عدد ثابت اختلاف. - افست سرور بروکر را با مقایسه یک رویداد شناختهشده (مثل زمان باز شدن بازار) اندازه بگیرید و ثبت کنید — حدس نزنید.
۰۷ساعت تابستانی؛ چرا افست ثابت جواب نمیدهد
ساعت تابستانی باعث میشود فاصله سشنهای بازار نسبت به UTC در طول سال جابهجا شود. بدتر اینکه کشورها این تغییر را در تاریخهای یکسانی انجام نمیدهند، پس چند هفته در سال وجود دارد که همپوشانی سشنها یک ساعت با حالت عادی فرق میکند.
قاعده رسمی آمریکا از سوی NIST: ساعت تابستانی «هر سال در دومین یکشنبه ماه مارس ساعت ۲ بامداد به وقت محلی» آغاز و «در اولین یکشنبه ماه نوامبر ساعت ۲ بامداد» تمام میشود؛ همان منبع تأکید میکند که «قواعد تاریخ گاهی تغییر میکنند، آخرین بار در سالهای ۱۹۸۶ و ۲۰۰۷»[۸]. در اتحادیه اروپا، دستورالعمل 2000/84/EC تعیین میکند که دوره تابستانی «در آخرین یکشنبه ماه مارس، ساعت ۱ بامداد به وقت گرینویچ» شروع و «در آخرین یکشنبه ماه اکتبر» پایان مییابد[۹].
این دو تاریخ روی هم منطبق نیستند. نتیجهای که مستقیماً از این دو منبع درمیآید: هر بهار حدود دو تا سه هفته و هر پاییز حدود یک هفته وجود دارد که فاصله ساعت نیویورک و لندن با حالت معمول فرق میکند، و بنابراین همپوشانی سشن لندن و نیویورک در آن بازه یک ساعت جابهجا میشود. اگر فیچر «آیا در بازه همپوشانی هستیم؟» را با افست ثابت بسازید، در آن هفتهها فیچرتان غلط است.
پایگاه داده مناطق زمانی IANA — مرجعی که تقریباً همه سیستمعاملها و کتابخانهها از آن استفاده میکنند — همین را به زبان مهندسی میگوید: «اینکه آیا و چه زمانی یک منطقه زمانی ساعتش را تغییر میدهد، و حتی افست پایه فرضی آن از UTC، متغیر است» و «همیشه منطقی نیست که درباره افست پایه یک منطقه زمانی صحبت کنیم، چون لزوماً یک عدد واحد نیست»[۱۰].
۰۸داده جاافتاده چیست و چه انواعی دارد؟
هر حفره در داده خطا نیست. بعضی حفرهها دقیقاً همان چیزی هستند که باید باشند — بازار بسته بوده. تشخیص ندادن این تفاوت، منشأ یکی از پرهزینهترین اشتباهات آمادهسازی داده است.
انواع داده جاافتاده و علت هرکدام:
| نوع | علت محتمل | آیا خطاست؟ | برخورد پیشنهادی |
|---|---|---|---|
| آخر هفته و تعطیلات | بازار بسته بوده | خیر — طبیعی | هیچکاری نکنید؛ فقط تقویم را مستند کنید |
| کندل جاافتاده در ساعات کمنقدینگی | هیچ معاملهای انجام نشده | معمولاً خیر | ثبت کنید؛ پر کردن معمولاً اشتباه است |
| حفره چندساعته وسط روز معاملاتی | قطعی سرور یا فید | بله — خطا | علامتگذاری و حذف کل بازه از تحلیل |
| گپ قیمتی در بازگشایی | رویداد خبری در زمان تعطیلی | خیر — رویداد واقعی | حفظ کنید؛ حذفش تحریف بازار است |
| حذف کامل یک نماد | تغییر نماد، ادغام، حذف از تابلو | بله — سوگیری بقا | سابقه نمادهای حذفشده را جدا نگه دارید |
ردیف آخر مهمتر از چیزی است که به نظر میرسد. اگر دیتاست شما فقط شامل نمادهایی باشد که امروز هنوز فعالاند، شما ناخواسته همه شکستها را از تاریخ حذف کردهاید. کارهارت و همکارانش در بررسی جامعی روی صندوقهای سرمایهگذاری آمریکا نشان دادند که این سوگیری با طول نمونه بزرگتر میشود: سوگیری سالانه از ۰٫۰۷ درصد برای نمونههای یکساله به حدود ۱ درصد برای نمونههای بیش از ۱۵ سال میرسد[۱۱]. یعنی هرچه تحقیق شما بلندمدتتر باشد، این خطا بزرگتر است — دقیقاً برعکس شهود رایج.
۰۹آیا باید داده جاافتاده را پر کنیم؟
در داده مالی، پر کردن کورکورانه خطرناکتر از حذف کردن است. هر مقداری که شما تولید میکنید یک قیمت مصنوعی است که هرگز در بازار وجود نداشته — و اگر استراتژی بتواند روی آن معامله کند، بکتست شما روی معاملاتی سود میسازد که ممکن نبودند.
سه روش رایج و ریسک هرکدام:
| روش | چه میکند | ریسک اصلی | کِی قابل قبول است |
|---|---|---|---|
| Forward Fill | آخرین مقدار معلوم را تکرار میکند | نوسان مصنوعی صفر میسازد؛ اندیکاتورهای نوسان را خراب میکند | برای دادههای وضعیتی که واقعاً تا اطلاع ثانوی معتبرند (مثل نرخ بهره اعلامشده) |
| Interpolation | بین دو نقطه معلوم مقدار میسازد | از آینده استفاده میکند — مقدار بعدی باید معلوم باشد تا وسط ساخته شود | برای شبیهسازی اجرای معامله معمولاً انتخاب مناسبی نیست؛ فقط با توجیه روشن و بدون استفاده از آینده |
| Drop | رکورد را حذف میکند | اگر جاافتادگی تصادفی نباشد، سوگیری وارد میکند | وقتی علت جاافتادگی مشخص و مستقل از قیمت است |
وقتی بین قیمت ساعت ۱۰:۰۰ و ۱۲:۰۰ با یک روش دوطرفه درونیابی میکنید تا مقدار ۱۱:۰۰ را بسازید، مقدار ساعت ۱۲ در ساخت عدد میانی نقش دارد. اگر مدل یا استراتژی در ساعت ۱۱ از آن استفاده کند، اطلاعات آینده وارد ورودی شده است. درونیابی لزوماً در همه کاربردها ممنوع نیست، اما برای دادهای که قرار است اجرای تاریخی معامله را بازسازی کند باید با احتیاط بسیار زیاد و بدون استفاده از اطلاعات آینده انجام شود.
توصیه عملی: قبل از هر تصمیمی درباره پر کردن، علت جاافتادگی را بفهمید. یک اسکریپت بنویسید که فهرست همه شکافها را با طول و زمان بیرون بدهد، آنها را با تقویم بازار مقایسه کنید، و فقط بعد از آن تصمیم بگیرید. در بسیاری از پروژهها بهترین کار این است که بازه معیوب را کلاً از تحلیل خارج کنید و این حذف را در متادیتا ثبت کنید — نه اینکه با داده ساختگی پرش کنید.
۱۰داده تکراری
رکورد تکراری بیسروصداترین نوع خطاست. نه ارور میدهد، نه در نمودار دیده میشود، اما هر آماری که روی تعداد یا مجموع حساب شود را منحرف میکند.
دو شکل رایج:
- تیک تکراری: یک بهروزرسانی قیمت دو بار در فایل ثبت شده — معمولاً بهخاطر قطع و وصل شدن اتصال یا ادغام دو فایل با بازه همپوشان.
- کندل تکراری: دو رکورد با مُهر زمانی یکسان اما مقادیر متفاوت — معمولاً وقتی داده از دو منبع یا دو بار دانلود ترکیب شده است.
چه چیزهایی خراب میشوند:
- حجم: اگر حجم تیک شمارش تغییرات قیمت است، تکرار مستقیماً آن را باد میکند.
- اندیکاتورها: هر میانگین متحرک، هر پنجره غلتان و هر شمارنده روی طول اشتباه محاسبه میشود.
- برچسبها: اگر برچسب یادگیری ماشین بر اساس تعداد گامهای آینده تعریف شده باشد، افق پیشبینی شما در بازههای دارای تکرار متفاوت میشود.
- شمارش معاملات: در بکتست، یک تیک تکراری میتواند باعث اجرای دوباره منطق ورود شود.
نکته ظریف: در تیکدیتا دو تیک با مُهر زمانی یکسان لزوماً تکراری نیستند. در بازارهای شلوغ چند بهروزرسانی میتواند در یک میلیثانیه اتفاق بیفتد. معیار تکراری بودن باید ترکیبی از زمان و همه مقادیر باشد (زمان + Bid + Ask + پرچمها)، نه فقط زمان.
۱۱داده پرت؛ و چرا حذف خودکار آن خطرناک است
هر حرکت شدید، خطای داده نیست. بازار واقعاً گاهی در چند ثانیه چند درصد حرکت میکند. اگر فیلتری بنویسید که هر جهش بزرگ را حذف کند، شما دقیقاً همان رویدادهایی را از تاریخ پاک کردهاید که مدیریت ریسک برایشان ساخته میشود.
دو رویداد مستند که هر فیلتر ساده «حذف پرت» آنها را دور میریخت:
سقوط ناگهانی ۶ مه ۲۰۱۰
گزارش مشترک SEC و CFTC: شاخصهای اصلی «ناگهان ۵ تا ۶ درصد دیگر در عرض چند دقیقه سقوط کردند و تقریباً به همان سرعت بازگشتند». در همان بازه «بیش از ۲۰٬۰۰۰ معامله روی بیش از ۳۰۰ اوراق بهادار با قیمتهایی بیش از ۶۰ درصد دورتر از ارزش لحظاتی قبل اجرا شد» و بسیاری از این معاملات «با قیمت یک سِنت یا کمتر، یا تا ۱۰۰٬۰۰۰ دلار» انجام شدند[۱۲].
جهش ین ژاپن، ۳ ژانویه ۲۰۱۹
بانک مرکزی استرالیا: این حرکت «در بازه حدود ۳۰ ثانیه و در غیاب هر خبر بااهمیتی» رخ داد؛ ین حدود ۳ درصد در برابر دلار آمریکا تقویت شد و دلار استرالیا حدود ۷ درصد در برابر ین افت کرد. علتها: نقدینگی بسیار کم در فاصله بسته شدن بازار آمریکا و باز شدن توکیو، تعطیلی رسمی ژاپن، و پلتفرمهایی که «طوری برنامهریزی شدهاند که در شرایط غیرعادی بازار بهطور خودکار خاموش شوند»[۱۳].
پاکسازی داده ≠ حذف هر چیزی که عجیب به نظر میرسد
وظیفه پاکسازی، تشخیص خطا است، نه زیباتر کردن نمودار. اگر معیار شما «این نقطه بد به نظر میرسد» باشد، شما در حال حذف تاریخ هستید، نه پاک کردن آن.
پس چطور تشخیص دهیم؟ تفاوت اصلی این است که یک رویداد واقعی بازار معمولاً در چند منبع مستقل دیده میشود، ساختار زمانی دارد (چند تیک پشت سر هم، اسپرد باز میشود، حجم تغییر میکند) و بازگشتش هم تدریجی است. یک خطای داده معمولاً یک نقطه منفرد است که در منابع دیگر وجود ندارد، اسپرد را غیرممکن میکند (مثلاً Bid بالاتر از Ask) یا با تیک بعدی بلافاصله به حالت قبل برمیگردد.
بهجای حذف نقاط پرت، یک ستون پرچم اضافه کنید: is_outlier، outlier_reason. داده را دستنخورده نگه دارید و در زمان مدلسازی تصمیم بگیرید که پرچمخوردهها را کنار بگذارید یا نه. این کار برگشتپذیر است؛ حذف نیست. و در گزارش نهایی میتوانید بگویید نتیجه با و بدون آن نقاط چقدر تفاوت میکند.
۱۲اسپرد و تفاوت Bid با Ask
اگر دیتاست شما فقط یک ستون قیمت دارد، شما نیمی از اطلاعات لازم برای شبیهسازی اجرا را ندارید. خرید و فروش روی دو قیمت متفاوت انجام میشوند و فاصله این دو در طول روز ثابت نیست.
مهمترین نکتهای که باید بدانید، و در مستندات رسمی متاکوتس صریح آمده است: در بکتستر متاتریدر، اسپرد شبیهسازی نمیشود بلکه از داده تاریخی گرفته میشود. متن دقیق: «در طول تست، اسپرد مدلسازی نمیشود بلکه از داده تاریخی برداشته میشود. اگر اسپرد در داده تاریخی کمتر یا مساوی صفر باشد، آخرین اسپرد شناختهشده توسط عامل تست استفاده میشود» و «در بکتستر، اسپرد همیشه شناور در نظر گرفته میشود»[۱۴].
معنی عملی این جمله: هزینه معاملاتی بکتست شما همان چیزی است که بروکرتان اتفاقی در تاریخچهاش ثبت کرده. نه شبیهسازی شده، نه مدل شده، و نه لزوماً همان چیزی که شما در آینده پرداخت خواهید کرد. اگر دیتای تاریخی شما از دورهای آمده که آن بروکر اسپردهای تنگتری داشته، بکتست شما بهطور سیستماتیک خوشبین است.
چند نکته دیگر درباره اسپرد در دیتاست:
- اسپرد در ساعات مختلف روز یکسان نیست. در ساعات کمنقدینگی و لحظات خبری میتواند بهطور محسوس بازتر شود. اگر استراتژی شما دقیقاً در همان لحظات معامله میکند، اسپرد میانگین گمراهکننده است.
- اسپرد صفر را خودکار خطا فرض نکنید. مقدار صفر میتواند در بعضی دادهها دیده شود؛ آن را Flag و با منبع داده بررسی کنید. اسپرد منفی یا Bid > Ask نیز باید بهعنوان ناهنجاری جدی بررسی شود، نه اینکه بیصدا حذف شود.
- اسپرد در آخر هفته و بازگشایی معمولاً غیرعادی است. این را بهعنوان خطا حذف نکنید، ولی در تحلیل جدا نگه دارید.
مدلسازی کامل هزینه معاملات (کمیسیون، سواپ، لغزش) موضوع مقاله بکتست است و اینجا تکرارش نمیکنیم؛ برای آن به راهنمای بکتست و اعتبارسنجی استراتژی مراجعه کنید. آنچه در لایه داده اهمیت دارد این است که ستونهای Bid و Ask را از ابتدا نگه دارید و دور نریزید.
۱۳دقت اعشار: پیپ، پوینت و اندازه تیک
سه مفهوم که مدام با هم اشتباه گرفته میشوند و اشتباه گرفتنشان باعث میشود محاسبه حد ضرر، اندازه پوزیشن و سود هر معامله بهاندازه یک ضریب ده غلط شود.
| مفهوم | تعریف | وضعیت |
|---|---|---|
| Point | واحد آخرین رقم اعشار قیمت نماد. در متاتریدر با SYMBOL_POINT («مقدار پوینت نماد») در دسترس است[۱۵]. | تعریف فنی و قابل خواندن از پلتفرم |
| Tick Size | حداقل تغییر ممکن قیمت. در متاتریدر SYMBOL_TRADE_TICK_SIZE («حداقل تغییر قیمت»)[۱۵]. | تعریف فنی و قابل خواندن از پلتفرم |
| Pip | واحد عرفی بازار فارکس برای بیان تغییر قیمت. | قرارداد عرفی است، نه یک فیلد فنی. در مستندات رسمی متاکوتس تعریف نشده است. |
چرا این تفکیک اهمیت دارد؟ چون تعداد ارقام اعشار (SYMBOL_DIGITS، «ارقام بعد از نقطه اعشار»[۱۵]) بین نمادها فرق دارد و حتی برای یک نماد بین بروکرها هم میتواند فرق کند. اگر کدی بنویسید که فرض کند حد ضرر ۵۰ پیپ یعنی 0.0050، آن کد روی نمادی با تعداد ارقام متفاوت مقدار کاملاً دیگری تولید میکند.
هیچوقت تعداد ارقام اعشار را در کد هاردکد نکنید. آن را از مشخصات نماد بخوانید و در متادیتای دیتاست ثبت کنید. و اگر داده را در فایل متنی ذخیره میکنید، مراقب باشید که تبدیل به عدد اعشاری شناور و برگشت، ارقام آخر را تغییر ندهد — برای داده قیمتی، ذخیرهسازی بهصورت رشته یا عدد صحیح مقیاسشده امنتر است.
۱۴آگاهی از سشن
یک کندل در بازگشایی لندن و یک کندل در نیمهشب، از نظر آماری دو موجود متفاوتاند: نوسان، حجم، اسپرد و رفتار نقدینگیشان فرق میکند. اگر مدل شما این تفاوت را نداند، مجبور میشود میانگینی بسازد که هیچکدام را خوب توصیف نمیکند.
فیچرهای زمانی که معمولاً ارزش افزودن دارند:
- ساعت روز — ترجیحاً بهصورت دو مؤلفه سینوسی و کسینوسی تا پیوستگی نیمهشب حفظ شود.
- روز هفته — دوشنبه و جمعه رفتار متفاوتی دارند.
- سشن فعال — آسیا، لندن، نیویورک، یا همپوشانی.
- فاصله از بازگشایی/بسته شدن — به دقیقه، نه بهصورت دستهای.
- روز قبل/بعد از تعطیلی — رفتار نقدینگی در این روزها متفاوت است.
اما یک قید حیاتی دارد و آن این است که همه این فیچرها باید فقط از اطلاعاتی ساخته شوند که در همان لحظه در دسترس بودهاند. «ساعت روز» بیخطر است چون در لحظه معلوم است. اما «آیا امروز روز پرنوسانی بود؟» یک فیچر آلوده است، چون تا پایان روز معلوم نمیشود. این ما را به مهمترین بخش این مقاله میرساند.
۱۵صحت نقطهای در زمان (Point-in-Time)
تعریف ساده: دیتاست باید در هر مُهر زمانی فقط اطلاعاتی داشته باشد که واقعاً تا همان لحظه قابل دانستن بوده است. هر چیز بیشتر از این، آینده است — و آینده در بکتست همیشه سودآور به نظر میرسد.
سادهترین مثال: فرض کنید فیچری میسازید به نام «دامنه امروز» که از High منهای Low کندل روزانه امروز حساب میشود. اگر استراتژی شما قرار است ساعت ۱۱ صبح تصمیم بگیرد، آن فیچر در ساعت ۱۱ وجود ندارد — چون High و Low روز تا پایان روز نهایی نمیشوند. مدل شما در بکتست عملاً میداند روز چطور تمام میشود.
این خطا در داده قیمتی نسبتاً قابل تشخیص است. در دادههای غیرقیمتی بهمراتب موذیتر است، چون خود پایگاه داده مرجع بعداً بازنویسی میشود. لیونگکویست، مالوی و مارستون در پژوهشی که در ژورنال فاینانس منتشر شد، هفت نسخه دانلودشده از یک پایگاه داده معتبر توصیههای تحلیلگران را بین سالهای ۲۰۰۰ تا ۲۰۰۷ با هم مقایسه کردند. نتیجه: بین ۱٫۶ تا ۲۱٫۷ درصد رکوردهای منطبق، از یک دانلود به دانلود بعدی متفاوت بودند — شامل تغییر توصیهها، اضافه و حذف شدن رکوردها و حذف نام تحلیلگران. مهمتر اینکه این تغییرات تصادفی نبودند و روی نتایج بکتست سه یافته شناختهشده اثر میگذاشتند[۱۶].
معنی این یافته برای شما: اگر امروز دادهای را دانلود کنید که ادعا میکند وضعیت سال ۲۰۱۸ را نشان میدهد، آن داده لزوماً همان چیزی نیست که در سال ۲۰۱۸ در دسترس بود. برای اینکه دیتاست شما نقطهای در زمان باشد، به دو ستون تاریخ نیاز دارید، نه یکی:
event_time— زمانی که رویداد در بازار اتفاق افتاد.known_time— زمانی که این اطلاعات برای شما قابل دانستن شد.
در داده قیمتی خام این دو معمولاً یکی هستند. اما بهمحض اینکه هر داده تجدیدنظرشوندهای (گزارش مالی، آمار اقتصادی، قیمت تعدیلشده) وارد پایپلاین شود، جدا کردنشان الزامی است. قانون در زمان مدلسازی این میشود: در هر لحظه t فقط رکوردهایی مجازند که known_time ≤ t.
۱۶نشت داده؛ تفاوتش با پاکسازی چیست؟
پاکسازی داده یعنی حذف خطا. نشت داده یعنی ورود اطلاعاتی که در زمان تصمیمگیری وجود نداشته است. اولی دیتاست را بهتر میکند؛ دومی دیتاست را به ظاهر بهتر میکند و در واقعیت بیارزش.
اگر فیچر آینده را میبیند، هوش مصنوعی باهوش نشده؛ دیتاست تقلب کرده است.
دقت بالای غیرمنتظره در داده مالی باید یکی از اولین محرکها برای بررسی نشت داده باشد، نه اینکه فوراً بهعنوان یک کشف معتبر پذیرفته شود.
شش شکل رایج نشت در پایپلاین داده بازار:
| نوع نشت | چطور اتفاق میافتد | راه جلوگیری |
|---|---|---|
| بازده آینده در فیچر | فیچری که مستقیم یا غیرمستقیم از قیمت بعدی ساخته شده | هر فیچر را با مهر زمانی محاسبهاش ممیزی کنید |
| نرمالسازی روی کل دیتاست | میانگین و انحراف معیار از کل داده (شامل آینده) گرفته شده | مقیاسگر فقط روی داده آموزش برازش شود |
| پر کردن با درونیابی | مقدار جاافتاده از مقادیر بعدی ساخته شده | فقط پر کردن رو به جلو، یا حذف |
| اندیکاتور با پنجره متمرکز | میانگین متحرک متمرکز بهجای غلتان رو به عقب | فقط پنجرههای رو به عقب |
| انتخاب فیچر روی کل داده | مهمترین فیچرها با دیدن نتایج کل دوره انتخاب شدهاند | انتخاب فیچر داخل هر فولد آموزش |
| سوگیری بقا در انتخاب نماد | فقط نمادهایی که امروز فعالاند در دیتاست هستند | سابقه نمادهای حذفشده را نگه دارید |
دستهبندی کاپور و نارایانان دقیقاً همین را از منظر علمی صورتبندی میکند: آنها هشت نوع نشت را در سه خانواده اصلی گروهبندی کردند — نبود جداسازی تمیز بین آموزش و آزمون (شامل پیشپردازش روی مجموع آموزش و آزمون، و انتخاب فیچر روی کل داده)، استفاده مدل از فیچرهای نامشروع، و مجموعه آزمونی که از توزیع مورد نظر نیامده (که «نشت زمانی» زیرشاخه آن است)[۱]. سه مورد از اینها مستقیماً در جدول بالا آمدهاند.
۱۷نرمالسازی و مقیاسبندی
مدلهای یادگیری ماشین معمولاً روی داده مقیاسشده بهتر آموزش میبینند. اما در سری زمانی مالی، خودِ عمل مقیاسبندی میتواند به یکی از تمیزترین راههای نشت آینده تبدیل شود.
سه رویکرد رایج:
- استانداردسازی: کم کردن میانگین و تقسیم بر انحراف معیار.
- مقیاسبندی کمینه-بیشینه: نگاشت به بازه صفر تا یک.
- تبدیل به بازده: بهجای مقیاسبندی سطح قیمت، خودِ متغیر عوض میشود (بخش بعد).
اگر میانگین و انحراف معیار را از کل دیتاست بگیرید و بعد داده را به آموزش و آزمون تقسیم کنید، آن میانگین حاوی اطلاعات دوره آزمون است. مدل شما در زمان آموزش میداند که قیمتهای آینده در چه محدودهای خواهند بود. مقیاسگر باید فقط روی داده آموزش برازش شود و همان پارامترها روی داده آزمون اعمال گردد. در اعتبارسنجی گامبهجلو، این کار باید در هر فولد جداگانه تکرار شود.
یک نکته اضافه که مخصوص داده مالی است: پارامترهای مقیاسبندی که روی داده سه سال پیش برازش شدهاند، ممکن است برای امروز بیمعنی باشند، چون سطح قیمت و رژیم نوسان تغییر کرده است. به همین دلیل بسیاری از تیمها بهجای مقیاسبندی سراسری، از نرمالسازی غلتان استفاده میکنند: میانگین و انحراف معیار از پنجرهای رو به عقب که در هر لحظه فقط گذشته را میبیند. این کار هم مشکل نشت را حل میکند و هم با تغییر رژیم سازگارتر است.
۱۸قیمت خام یا بازده؟
این یک انتخاب مسئلهمحور است، نه یک قانون. بازدهها بعضی تحلیلها را سادهتر میکنند، اما ادعای «بازده همیشه بهتر است» درست نیست و در برخی مسائل سطح قیمت دقیقاً همان چیزی است که لازم دارید.
چرا کار با سطح قیمت خام معمولاً سخت است: سری قیمت روند دارد و آمارههایش (میانگین، واریانس) در طول زمان ثابت نمیمانند. مدلی که روی سطح قیمت ۱٬۸۰۰ دلاری آموزش دیده، وقتی قیمت به ۳٬۰۰۰ میرسد در محدودهای قرار میگیرد که هرگز ندیده است. تبدیل به بازده (تغییر نسبی) یا لگاریتم بازده این مشکل را تا حد زیادی حل میکند.
اما چه زمانی سطح قیمت لازم است؟
- وقتی استراتژی به سطوح مطلق کار دارد (حمایت و مقاومت، اعداد رند، قیمتهای تاریخی).
- وقتی میخواهید هزینه معامله را بهدرستی حساب کنید — اسپرد بر حسب قیمت است، نه بر حسب بازده.
- وقتی روی سریهای تعدیلشده کار میکنید که سطحشان مصنوعی است (بخش ۲۰ و ۲۱).
راهحل عملی معمول: هر دو را نگه دارید. سطح قیمت را بهعنوان ستون پایه حفظ کنید و بازده را بهعنوان فیچر مشتق اضافه کنید. حذف کردن سطح قیمت از دیتاست یک تصمیم برگشتناپذیر است که بعداً پشیمانی میآورد.
۱۹مهندسی فیچر و پنجره غلتان
فیچرها همان جایی هستند که دانش دامنه وارد مدل میشود — و همان جایی که آینده معمولاً بهطور تصادفی نشت میکند. هر فیچر باید یک سؤال ساده را پاس کند: آیا در لحظه تصمیم، این عدد قابل محاسبه بود؟
خانوادههای رایج فیچر برای داده بازار (این فهرست آموزشی است و هیچکدام سیگنال معاملاتی محسوب نمیشوند):
- بازده در افقهای مختلف — بازده ۱، ۵، ۲۰ دوره گذشته.
- نوسان غلتان — انحراف معیار بازده در پنجرهای رو به عقب.
- دامنه — فاصله High و Low، و شاخصهای مبتنی بر آن مثل میانگین دامنه واقعی.
- فاصله از میانگین متحرک — بهصورت نسبی، نه مطلق، تا در سطوح قیمتی مختلف قابل مقایسه بماند.
- فیچرهای زمانی — سشن، ساعت، روز هفته (بخش ۱۴).
- فیچرهای اسپرد و نقدینگی — اسپرد نسبی، تعداد تیک در واحد زمان.
پنجره غلتان و قاعده طلایی آن
پنجره غلتان یعنی محاسبه یک آماره روی N دوره اخیر، بهازای هر نقطه زمانی. مثلاً نوسان ۲۰ دورهای. این ابزار پایهای مهندسی فیچر سری زمانی است، اما یک شرط دارد که نقض کردنش رایجترین منبع نشت است:
پنجره باید کاملاً رو به عقب باشد. یک میانگین متحرک «متمرکز» که ۱۰ دوره قبل و ۱۰ دوره بعد را میگیرد، در تحلیل توصیفی معنی دارد ولی در بکتست معادل تقلب است. همچنین مراقب باشید که فیچر ساختهشده از پنجرهای که به کندل جاری و هنوز بستهنشده ختم میشود، در زمان تصمیم کامل نیست. اگر استراتژی در بسته شدن کندل تصمیم میگیرد، فیچر باید تا کندل قبل محاسبه شود یا صراحتاً بعد از بسته شدن.
برچسبگذاری
اگر برای یادگیری نظارتشده برچسب میسازید، برچسب ذاتاً از آینده میآید — و این اشکال ندارد، چون برچسب هدف است نه ورودی. اشکال آنجاست که برچسب و فیچر همپوشانی زمانی پیدا کنند. اگر برچسب شما «بازده ۲۰ کندل آینده» است، نمونههای متوالی شما ۱۹ کندل مشترک دارند. این باعث میشود مجموعه آموزش و آزمون در مرزشان به هم نشت کنند. راهحل استاندارد این است که بین آموزش و آزمون یک فاصله خالی (بهاندازه افق برچسب) بگذارید.
۲۰اقدامات شرکتی در سهام
در بازار سهام، قیمت تاریخی بدون تعدیل، جهشهایی دارد که هیچ ربطی به عرضه و تقاضا ندارند. تقسیم سهم و پرداخت سود نقدی، قیمت را بهطور مکانیکی تغییر میدهند. اگر این را تعدیل نکنید، مدل شما یک سقوط ۵۰ درصدی جعلی میبیند.
روش استاندارد تعدیل که مرکز پژوهش قیمت اوراق بهادار (CRSP) بهکار میبرد ساده و صریح است: مقدار تعدیلشده برابر است با مقدار خام تقسیم بر ضریب تعدیل تجمعی — و برای تعداد سهام و حجم، عملیات معکوس (ضرب) انجام میشود. این ضریب در تاریخ کنارگذاری هر رویداد بهروز میشود و «تقسیم سهم، سود سهمی و سایر توزیعهای دارای ضریب قیمت مثل جداسازی شرکتها، توزیع سهام و حقتقدم» را پوشش میدهد[۱۷].
در سطح شاخص هم منطق مشابه است: S&P Dow Jones Indices در روششناسی رسمیاش میگوید مخرج شاخص برای «هر اقدام شرکتی اثرگذار بر قیمت» تعدیل میشود تا «سطح شاخص نپرد یا نیفتد»[۱۸].
- برای محاسبه بازده و آموزش مدل: معمولاً سری تعدیلشده درستتر است، چون جهشهای مکانیکی را حذف میکند.
- برای شبیهسازی اجرا و سطوح قیمتی: قیمت تعدیلشده در گذشته با قیمتی که واقعاً معامله شده فرق دارد. اگر استراتژی شما به سطوح مطلق کار دارد، این تفاوت مهم است.
- هر دو را نگه دارید و در متادیتا ثبت کنید که کدام ستون کدام است. ابهام در این مورد، منبع خطاهای بسیار سختی برای دیباگ است.
یک نکته مهم: این بخش را به فارکس تعمیم ندهید. جفتارزها اقدام شرکتی ندارند. مفهوم معادل در فارکس، سواپ شبانه است که مکانیزم و اثر کاملاً متفاوتی دارد.
۲۱قراردادهای آتی و سری پیوسته
قراردادهای آتی سررسید دارند. برای ساختن یک سری تاریخی بلندمدت، باید از قرارداد نزدیک به قرارداد بعدی «رول» کنید — و روش رول شما مستقیماً روی نتیجه بکتست اثر میگذارد.
CME Group رول فصلی را اینطور توصیف میکند: «انتقال موقعیت باز از قرارداد فصلی ماه نزدیک که در حال انقضاست به قرارداد فصلی مؤخر»، فعالیتی که «معمولاً در بازه دو هفتهای بلافاصله قبل از تاریخ انقضای قرارداد ماه نزدیک متمرکز است»[۱۹].
اما ساختن سری پیوسته کار بورس نیست؛ کار ارائهدهنده داده است. مستندات CSI Data سه معیار رایج برای زمان رول را مستند کرده است: انتقال بر اساس جابهجایی بیشترین حجم، بر اساس جابهجایی بیشترین موقعیت باز، یا بر اساس تقویم (روز مشخصی از ماه یا N روز قبل از انقضا). روش تعدیل هم صریح است: اختلاف قیمت دو قرارداد در روز رول به قیمتهای گذشته اضافه میشود[۲۰].
وقتی اختلافها را به قیمتهای گذشته اضافه میکنید، سطح قیمت گذشته دیگر واقعی نیست. مستندات CSI صریحاً هشدار میدهد که «قراردادهای تعدیلشده رو به عقب و رو به جلو میتوانند شامل اعداد منفی باشند»[۲۰]. پیامد عملی: محاسبه بازده درصدی روی یک سری تعدیلشده بیمعنی است، چون مخرج کسر یک عدد ساختگی و احتمالاً منفی است. روی چنین سریای باید با اختلاف مطلق قیمت کار کنید، یا از سری تعدیلشده نسبتی استفاده کنید.
حداقل کاری که باید بکنید: در متادیتای دیتاست بنویسید که سری پیوسته با چه روش رولی و چه نوع تعدیلی ساخته شده است. دو سری پیوسته از یک نماد با دو روش رول متفاوت، دو دیتاست متفاوتاند و نتیجه بکتستشان میتواند بهطور معناداری فرق کند.
۲۲داده رمزارز
در رمزارز، «قیمت بیتکوین» بدون ذکر صرافی یک عبارت ناقص است. بازار ۲۴ ساعته و ۷ روزه است، هر صرافی دفتر سفارش مستقل دارد و قیمتها میتوانند بهطور معناداری با هم فرق کنند.
این تفاوت مستند شده است. CME Group در روششناسی نرخ مرجع رمزارزش مینویسد: «قیمتهای اسپات بهطور تاریخی بین ونیوهای معاملاتی بهطور قابلتوجهی متفاوت بودهاند، بهویژه در دورههای نوسان بالا» و تجمیع چند صرافی «حساسیت نرخ را به قیمتهای حدی در یک یا چند صرافی بهشدت کاهش میدهد»[۲۱]. در تحلیل خود CME از دورهای مشخص آمده که «اختلاف قیمت بین صرافیهای معاملهکننده رمزارز در این دوره تا ۱٬۰۰۰ دلار رسید»[۲۲].
از منظر آکادمیک هم ماکاروف و شوآر در ژورنال اقتصاد مالی نشان دادند که «بازارهای رمزارز دورههایی از فرصتهای آربیتراژ بزرگ و مکرر بین صرافیها را نشان میدهند» و این انحرافات «بین کشورها بهمراتب بزرگتر از داخل یک کشور» هستند[۲۳].
نکته روششناختی جالبی که ارزش الگوبرداری دارد: نرخ مرجع CME روی یک پنجره ۶۰ دقیقهای محاسبه میشود که به دوازده بخش پنجدقیقهای با وزن برابر تقسیم شده و در هر بخش از میانه وزنی حجم استفاده میشود — دقیقاً به این دلیل که «یک معامله بزرگ یا خوشهای از معاملات در هر بخش، اثر محدودی خواهد داشت»[۲۱]. این یک الگوی عملی خوب برای هر جایی است که باید از چند منبع یک قیمت مرجع بسازید.
حداقل الزام برای دیتاست رمزارز: نام صرافی، نام دقیق جفت معاملاتی (که بین صرافیها متفاوت نوشته میشود)، و اینکه قیمت از معاملات آمده یا از میانه دفتر سفارش.
۲۳داده فارکس؛ چرا بین بروکرها فرق دارد
همان دلیل ساختاری که در بخش ۵ گفتیم: بازار اسپات فارکس بورس مرکزی واحد ندارد. پس هیچ «قیمت رسمی» و هیچ «حجم رسمی» وجود ندارد که همه بروکرها از آن تبعیت کنند.
مواردی که در دیتاست فارکس باید صریحاً ثبت شوند:
| مورد | چرا مهم است |
|---|---|
| نام بروکر / منبع فید | ترکیب نقدینگی و فیلترهای هر منبع متفاوت است |
| منطقه زمانی سرور و افست اندازهگیریشده | هیچ فیلد رسمی این را اعلام نمیکند؛ باید تجربی تعیین شود |
| نوع حجم (تیک یا واقعی) | در فارکس تقریباً همیشه تیک است، نه واقعی |
| وجود یا نبود ستون Ask | بدون آن، شبیهسازی اسپرد ممکن نیست |
| تعداد ارقام اعشار نماد | بین بروکرها برای یک نماد فرق میکند |
| ساعت بازگشایی و بسته شدن هفتگی | بروکرها ساعت شروع و پایان هفته متفاوتی دارند |
| در دسترس بودن تیک واقعی | بعضی منابع فقط کندل دارند و تیک را بازسازی میکنند |
یک نکته درباره متاتریدر که اثر مستقیم بر بکتست دارد: حالتهای مدلسازی بکتستر با هم برابر نیستند. مستندات رسمی متاکوتس حالت «هر تیک» را «دقیقترین اما کندترین حالت» توصیف میکند و حالت «هر تیک بر اساس تیکهای واقعی» را حالتی که «هیچ شبیهسازی انجام نمیشود» و «تا حد ممکن به شرایط واقعی نزدیک است». در مقابل، حالت «1 minute OHLC» فقط «چهار قیمت هر کندل دقیقهای را شبیهسازی میکند» و حالت «فقط قیمتهای باز شدن» تابع رویداد را «فقط در ابتدای کندل و در قیمت باز شدن» اجرا میکند[۱۴]. انتخاب این حالت یک تصمیم دادهای است، نه یک تنظیم فرعی.
۲۴مثال آموزشی: چکلیست XAUUSD قبل از بکتست
فرض کنیم استراتژیای روی طلا (XAUUSD) در تایمفریم یکدقیقهای دارید. قبل از اینکه دکمه شروع را بزنید، اینها را باید بدانید. این مثال فرضی و آموزشی است و هیچ استراتژی، سیگنال یا نتیجه مالیای ارائه نمیکند.
- مشخصات نماد: اندازه قرارداد، حداقل حجم، گام حجم و ارز سود چیست؟ این اعداد بین بروکرها متفاوتاند.
- تعداد ارقام اعشار: نماد شما با چند رقم اعشار قیمتگذاری میشود؟ محاسبات حد ضرر شما بر همین اساس است.
- منطقه زمانی سرور: افست سرور نسبت به UTC چقدر است و آیا در طول سال تغییر میکند؟
- تقویم معاملاتی: بازار طلا چه ساعتی هر روز بسته و باز میشود؟ وقفه روزانه دارد؟
- کندلهای جاافتاده: در بازه تحقیق شما چند دقیقه بدون کندل وجود دارد و آیا با تعطیلات همخوانی دارند؟
- اسپرد: توزیع اسپرد در ساعات مختلف چیست؟ حداقل، میانه و صدک ۹۹ آن چقدر است؟
- منبع تیک: تیکها واقعی هستند یا از کندلهای یکدقیقهای بازسازی شدهاند؟
- ساعت تابستانی: در بازه تحقیق شما چند بار تغییر ساعت اتفاق افتاده و آیا داده در آن نقاط پیوسته است؟
- گپهای غیرعادی: بزرگترین جهشهای قیمتی در بازه شما کداماند و هرکدام رویداد واقعی بوده یا خطای فید؟
- پوشش تاریخی: داده از چه تاریخی شروع میشود و کیفیت سالهای ابتدایی با سالهای اخیر یکسان است؟
اگر حتی به یکی از این ده سؤال جواب ندارید، نتیجه بکتست شما یک عدد است که تفسیرش ممکن نیست. این به معنی بد بودن استراتژی نیست؛ به معنی این است که هنوز نمیدانید بکتست چه چیزی را اندازه گرفته.
۲۵نسخهبندی دیتاست و متادیتا
اگر نتوانید بگویید نتیجه امروزتان روی کدام نسخه از داده بهدست آمده، نتیجهتان قابل دفاع نیست. نسخهبندی دیتاست سادهترین کاری است که بیشترین تفاوت را در اعتبار تحقیق ایجاد میکند.
یک الگوی نامگذاری فرضی — این فقط یک مثال است و استاندارد نیست:
xauusd_ticks_raw_v1 # untouched copy from the source
xauusd_ticks_clean_v2 # duplicates removed, outliers flagged
xauusd_m1_aligned_v2 # aggregated to M1, timestamps normalised
xauusd_features_v3 # derived features, leakage-audited
xauusd_train_v3 # training split, frozen
اما نام فایل کافی نیست. هر دیتاست باید یک فایل متادیتای همراه داشته باشد:
- نماد
- XAUUSD
- منبع
- نام بروکر / ارائهدهنده — با روش دریافت
- تاریخ دریافت
- تاریخ و ساعت دقیق دانلود
- بازه
- تاریخ شروع تا تاریخ پایان
- منطقه زمانی
- مرجع ذخیرهسازی + افست اندازهگیریشده سرور
- دانهبندی
- تیک / M1 / H1 — و روش تجمیع
- تعداد رکورد
- قبل و بعد از پاکسازی
- رکوردهای حذفشده
- تعداد + دلیل هر دسته
- جاافتادگی
- تعداد شکاف، بلندترین شکاف، وضعیت علتیابی
- قواعد پاکسازی
- فهرست دقیق قواعد اعمالشده و ترتیبشان
- تبدیلها
- تعدیل، رول، نرمالسازی — با پارامترها
- ستونها
- نام، واحد، معنی — یک دیکشنری داده کوچک
- چکسام
- هش فایل نهایی برای تشخیص تغییر ناخواسته
۲۶بازتولیدپذیری
معیار ساده: اگر شش ماه دیگر نتوانید همان دیتاست و همان پایپلاین را دقیقاً بازسازی کنید، نتیجه تحقیق شما قابل اعتماد نیست — حتی اگر امروز درست باشد.
چرا این در داده مالی سختتر از حوزههای دیگر است؟ چون منبع داده زیر پای شما تغییر میکند. یافته لیونگکویست و همکاران (بخش ۱۵) نشان داد که یک پایگاه داده معتبر میتواند بین دو دانلود، تا ۲۱٫۷ درصد رکوردهایش را تغییر دهد[۱۶]. یعنی «دوباره دانلود میکنم» یک استراتژی بازتولید نیست.
حداقل چیزهایی که باید حفظ شوند تا یک نتیجه بازتولیدپذیر باشد:
- کپی دستنخورده داده خام — با تاریخ دریافت و چکسام.
- کد پایپلاین — نسخهبندیشده در سیستم کنترل نسخه، نه چند سلول نوتبوک پراکنده.
- نسخه کتابخانهها — یک تغییر جزئی در رفتار گردکردن یا مرتبسازی میتواند نتیجه را جابهجا کند.
- بذر تصادفی — هرجا نمونهگیری یا مقداردهی تصادفی هست.
- پارامترهای تبدیل — میانگین و انحراف معیار مقیاسگر، مرزهای اسپلیت، قواعد رول.
- لاگ اجرا — چه چیزی حذف شد، چند رکورد، به چه دلیل.
داده خام را تغییر ندهید. هرگز.
فایل خام باید فقطخواندنی باشد و هر پاکسازی روی یک نسخه جدید انجام شود. اگر داده خام را در جا ویرایش کنید، هیچ راهی برای برگشت یا حسابرسی باقی نمیماند — و هر اشتباهی که کردهاید، دائمی میشود.
۲۷چکلیست اعتبارسنجی داده
این چکلیست را قبل از استفاده از هر دیتاست اجرا کنید. ترجیحاً بهصورت یک اسکریپت خودکار که خروجیاش یک گزارش است، نه یک بررسی چشمی.
- منبع داده مشخص و ثبت شده است؟
- نماد دقیقاً همان چیزی است که فکر میکنید (نه نماد مشابه با پسوند متفاوت)؟
- منطقه زمانی صراحتاً مستند شده است؟
- بازه زمانی داده همان بازه مورد نظر تحقیق است؟
- مُهرهای زمانی بهترتیب صعودی و بدون پرش به عقب هستند؟
- رکورد تکراری (زمان + همه مقادیر) وجود دارد؟
- تعداد و محل رکوردهای جاافتاده استخراج شده است؟
- هر شکاف با تقویم بازار تطبیق داده شده تا طبیعی بودنش تأیید شود؟
- قیمت منفی یا صفر وجود دارد؟
- رابطه High ≥ Low در همه رکوردها برقرار است؟
- رابطه High ≥ Open و High ≥ Close برقرار است؟
- رابطه Low ≤ Open و Low ≤ Close برقرار است؟
- رابطه Bid ≤ Ask در همه تیکها برقرار است؟
- توزیع اسپرد بررسی شده و مقادیر غیرعادی علامتگذاری شدهاند؟
- حجم منفی وجود دارد؟
- تعداد ارقام اعشار یکنواخت و مطابق مشخصات نماد است؟
- مرز سشنها و اثر ساعت تابستانی بررسی شده است؟
- هیچ فیچری از اطلاعات آینده استفاده نمیکند (ممیزی نقطهای در زمان انجام شده)؟
۲۸تستهای ساده کیفیت OHLC با کد
چند قاعده منطقی که با چند خط کد قابل بررسیاند و بخش بزرگی از خطاهای رایج را میگیرند. اینها قواعد اعتبارسنجیاند، نه قوانین مطلق برای هر دیتاست دنیا — در برخی منابع خاص ممکن است استثنا موجه باشد.
import pandas as pd
df = pd.read_csv("xauusd_m1.csv", parse_dates=["time"])
df = df.sort_values("time").reset_index(drop=True)
report = {}
# 1) duplicate timestamps (and fully duplicated rows)
report["dup_time"] = int(df["time"].duplicated().sum())
report["dup_full"] = int(df.duplicated().sum())
# 2) OHLC logical consistency
bad = (
(df["high"] < df["low"])
| (df["high"] < df["open"])
| (df["high"] < df["close"])
| (df["low"] > df["open"])
| (df["low"] > df["close"])
)
report["ohlc_violations"] = int(bad.sum())
# 3) impossible values
report["non_positive_price"] = int((df[["open","high","low","close"]] <= 0).any(axis=1).sum())
if "volume" in df:
report["negative_volume"] = int((df["volume"] < 0).sum())
# 4) time gaps (expected 1 minute)
gaps = df["time"].diff()
report["gap_count"] = int((gaps > pd.Timedelta("1min")).sum())
report["max_gap"] = str(gaps.max())
report["backward_time"] = int((gaps < pd.Timedelta(0)).sum())
for k, v in report.items():
print(f"{k:22s} {v}")
و برای تیکدیتا، مهمترین تست تکخطی این است:
# flag crossed/locked quotes for investigation
crossed = ticks["bid"] > ticks["ask"]
locked = ticks["bid"] == ticks["ask"]
print("crossed bid/ask:", int(crossed.sum()))
print("zero spread:", int(locked.sum()))
# spread distribution — flag, do not delete
ticks["spread"] = ticks["ask"] - ticks["bid"]
q = ticks["spread"].quantile([0.5, 0.99, 0.999])
print(q)
ticks["spread_flag"] = ticks["spread"] > q.loc[0.999]
print("flagged:", int(ticks["spread_flag"].sum()))
خروجی این اسکریپتها را ذخیره کنید و در متادیتای دیتاست بگذارید. یک گزارش اعتبارسنجی که کنار فایل داده نگه داشته میشود، شش ماه بعد ارزش بسیار بیشتری از چیزی دارد که فقط یک بار در ترمینال دیدید.
۲۹پایپلاین کامل آمادهسازی داده
این مسیر کلی است. هر مرحله ورودی مرحله بعد را میسازد و هیچکدام را نمیشود بدون هزینه پرید. نکته مهم این است که آخرین مرحله، شروع مقاله بعدی است — نه پایان کار.
- ۰۱داده خامدریافت از منبع، بدون هیچ تغییری. کپی فقطخواندنی نگه دارید.
- ۰۲اعتبارسنجیساختار، نوع ستونها، بازه، روابط منطقی قیمت، تکراری و جاافتاده.
- ۰۳پاکسازیحذف تکراریهای واقعی، پرچمگذاری پرتها — نه حذف کورکورانه.
- ۰۴نرمالسازی ساختارییکسانسازی نام ستونها، واحدها، دقت اعشار و نوع داده.
- ۰۵همزمانسازی زمانیتبدیل به مرجع زمانی واحد، افزودن سشن، مدیریت ساعت تابستانی.
- ۰۶ساخت فیچرفقط با پنجرههای رو به عقب و از اطلاعات در دسترس همان لحظه.
- ۰۷ممیزی نقطهای در زمانبررسی صریح اینکه هیچ ستونی آینده را نمیبیند.
- ۰۸نسخهبندی و فریزثبت متادیتا، چکسام، و قفل کردن دیتاست.
- ۰۹آماده بکتستحالا و فقط حالا میشود درباره کیفیت استراتژی حرف زد.
مرحله بعد: بکتست استراتژی
حالا که داده آماده است، سؤال بعدی این است که نتیجه بکتست را چطور باید خواند و چه چیزهایی آن را غیرواقعی میکنند.
۳۰هوش مصنوعی کجای آمادهسازی داده کمک میکند و کجا خطرناک است؟
هوش مصنوعی در این مرحله ابزار بسیار خوبی است — به شرطی که نقشش «دستیار بازرس» باشد نه «تصمیمگیرنده خودکار». تفاوت این دو، تفاوت بین صرفهجویی در وقت و خراب کردن بیسروصدای دیتاست است.
✓ کارهایی که واقعاً کمک میکند
- بررسی ساختار و اسکیمای فایل و پیدا کردن ناسازگاریها
- تولید قواعد اعتبارسنجی بر اساس توصیف دیتاست
- نوشتن اسکریپت پایتون برای تستهای کیفیت
- پیدا کردن رکوردهای تکراری و گزارش شکافها
- ساخت گزارش داده جاافتاده با تفکیک علت محتمل
- تحلیل توزیع ستونها و پیدا کردن نامزدهای ناهنجاری
- ساخت دیکشنری داده و مستندسازی پایپلاین
- مرور کد فیچرسازی برای پیدا کردن نشت احتمالی
✕ جاهایی که خطرناک است
- پر کردن داده جاافتاده بدون فهمیدن علتش
- حذف خودکار هر نقطهای که «پرت» تشخیص داده
- حدس زدن منطقه زمانی از روی ظاهر داده
- تفسیر اشتباه ستونها (جابهجا فهمیدن Bid و Ask)
- ساختن فیچری که ناخواسته آینده را میبیند
- تولید داده مصنوعی و استفاده از آن بهجای داده واقعی
- یکسان فرض کردن حجم تیک و حجم واقعی
- تعمیم قواعد یک بازار به بازار دیگر (سهام به فارکس)
یک مدل زبانی بدون دسترسی به داده واقعی، وقتی از او میخواهید «داده را تمیز کن»، کدی مینویسد که منطقی به نظر میرسد. اما منطقی به نظر رسیدن در پاکسازی داده مالی کافی نیست. کدی که میانگین بگیرد و مقادیر بیش از سه انحراف معیار را حذف کند، در روز ۶ مه ۲۰۱۰ یا ۳ ژانویه ۲۰۱۹ دقیقاً همان چیزی را حذف میکند که باید نگه داشته میشد. خروجی هر عملیات پاکسازی خودکار را با یک گزارش «چه چیزی حذف شد و چرا» بررسی کنید.
برای دیدن اینکه ایجنتها و ابزارهای هوش مصنوعی چطور در گردشکار واقعی مهندسی بهکار میروند:
خدمات هوش مصنوعی فیلتور ←۳۱هفت پرامپت کاربردی برای آمادهسازی داده
این پرامپتها برای استفاده در ChatGPT، Claude یا هر دستیار کدنویسی نوشته شدهاند. هدفشان این است که مدل بهجای تصمیم گرفتن، بازرسی کند و گزارش بدهد.
۳۲ده اشتباه رایج در آمادهسازی داده بازار
- اعتماد کامل به اولین منبع داده. بدون مقایسه با یک منبع دوم، هیچ راهی برای تشخیص خطای سیستماتیک وجود ندارد.
- نادیده گرفتن منطقه زمانی. خطایی که هیچ ارور نمیدهد و کل تحقیق را به ساعت دیگری از روز منتقل میکند.
- فراموش کردن ساعت تابستانی. افست ثابت در چند هفته از سال غلط است — و آن هفتهها بخشی از دوره بکتست شما هستند.
- پر کردن کورکورانه داده جاافتاده. ساختن قیمتی که هرگز وجود نداشته، و بعد معامله کردن روی آن.
- حذف خودکار داده پرت. پاک کردن دقیقاً همان رویدادهایی که ریسک واقعی را میسازند.
- ترکیب دو منبع بدون ستون مبدأ. ساختن یک شکست ساختاری در وسط دیتاست که مدل آن را رویداد بازار میفهمد.
- استفاده از کندل برای استراتژی حساس به اجرا. وقتی ترتیب لمس High و Low نتیجه را تعیین میکند، کندل جواب نمیدهد.
- نشت فیچر. پنجره متمرکز، شیفت اشتباه، یا فیچری که از کندل بستهنشده استفاده میکند.
- برازش مقیاسگر روی کل دیتاست. سادهترین و رایجترین راه ورود آینده به مدل.
- نداشتن نسخه دیتاست. نتیجهای که نمیدانید روی کدام داده بهدست آمده، قابل دفاع نیست.
۳۳چه زمانی داده آماده بکتست است؟
پاسخ مستقیم: وقتی هر هفت شرط زیر همزمان برقرار باشند. اگر حتی یکی برقرار نباشد، نتیجه بکتست را میشود محاسبه کرد اما نمیشود تفسیر کرد.
- منبع مشخص است. میدانید داده از کجا آمده، چه زمانی دریافت شده و با چه روشی.
- یکپارچگی بررسی شده است. تکراری، جاافتاده، روابط منطقی قیمت و مقادیر غیرممکن همگی تست شدهاند.
- همترازی زمانی صحیح است. منطقه زمانی مستند، ساعت تابستانی مدیریتشده و مرز سشنها تعریفشده است.
- قواعد پاکسازی مستند شدهاند. میتوانید بگویید چه چیزی حذف یا پرچمگذاری شد و چرا.
- نشت آینده وجود ندارد. یک ممیزی صریح نقطهای در زمان روی همه فیچرها انجام شده است.
- نسخه مشخص است. دیتاست فریز شده و چکسام دارد.
- فرضها مستند شدهاند. هر جا مجبور به انتخاب شدید (روش رول، تعدیل، پر کردن، حذف)، آن انتخاب نوشته شده است.
حالا که داده آماده است، استراتژی را درست بکتست کنیم
مرحله بعد این است که بفهمیم نتیجه بکتست چه چیزی را اندازه میگیرد، چرا نرخ برد گمراهکننده است و بیشبرازش چطور اتفاق میافتد.
۳۴جمعبندی
هدف این مقاله آموزش دانلود چند فایل CSV نبود. هدف ساختن یک ذهنیت بود:
قبل از اینکه از هوش مصنوعی بپرسیم استراتژی سودده است یا نه، باید مطمئن شویم چیزی که هوش مصنوعی و بکتست میبینند واقعاً نماینده بازار است.
یک دیتاست خوب شش ویژگی دارد: قابل ردیابی است (میدانید از کجا آمده)، قابل بازسازی است (میتوانید دوباره بسازیدش)، مستند است (فرضهایش نوشته شدهاند)، از نظر زمانی درست است (آینده در گذشته نیست)، متناسب با استراتژی است (دانهبندیاش با نیاز شما میخواند)، و از نظر کیفیت بررسی شده است.
اگر بعد از خواندن این مقاله نسبت به هر دیتاستی که به دستتان میرسد سختگیرتر شدهاید، مقاله کارش را انجام داده است.
۳۵پرسشهای متداول
داده تیک (Tick Data) چیست؟
تیک یک بهروزرسانی منفرد قیمت است. هر رکورد تیک معمولاً شامل زمان، قیمت خرید (Bid) و قیمت فروش (Ask) است و در بازارهای بورسی میتواند قیمت و حجم آخرین معامله را هم داشته باشد. تیکدیتا دانهریزترین لایه داده بازار است و ترتیب واقعی رویدادها را حفظ میکند، اما حجم بسیار بالایی دارد و پاکسازی آن بهمراتب سختتر از کندل است.
OHLC چیست و چه تفاوتی با OHLCV دارد؟
OHLC خلاصه یک بازه زمانی با چهار عدد است: قیمت باز شدن، بالاترین قیمت، پایینترین قیمت و قیمت بسته شدن. OHLCV همین چهار عدد بهعلاوه حجم است. در بازار فارکس آنچه معمولاً بهعنوان حجم نمایش داده میشود حجم تیک است، یعنی تعداد تغییرات قیمت در آن بازه، نه حجم واقعی معاملهشده؛ این دو در ساختار داده متاتریدر دو فیلد کاملاً جدا هستند.
برای بکتست، تیکدیتا بهتر است یا کندل؟
بستگی به استراتژی دارد و ادعای «تیک همیشه بهتر است» درست نیست. اگر استراتژی فقط در لحظه بسته شدن کندل تصمیم میگیرد و حد ضرر و حد سود آن نسبت به نوسان کندل دور است، داده کندل کافی است. اما اگر نتیجه معامله به این بستگی دارد که کدامیک از High یا Low اول لمس شده، یا اگر استراتژی به اسپرد لحظهای حساس است، کندل این اطلاعات را ندارد و تیکدیتا لازم میشود. تیکدیتای بدپاکسازیشده از کندل تمیز بدتر است.
بهترین تایمفریم برای داده چیست؟
تایمفریم جهانی و واحدی وجود ندارد و انتخاب آن کاملاً به منطق اجرا بستگی دارد. اگر تصمیم و اجرای استراتژی فقط پس از بستهشدن کندل انجام میشود، همان تایمفریم میتواند کافی باشد؛ اما هرچه نتیجه به ترتیب رویدادهای داخل کندل، سفارشهای شرطی یا اسپرد لحظهای حساستر باشد، داده دانهریزتر لازم میشود.
چرا منطقه زمانی در بکتست اینقدر مهم است؟
چون خطای منطقه زمانی ممکن است بدون هیچ خطای نرمافزاری، سشن و ساعت تصمیمگیری را جابهجا کند. در اتصال رسمی Python به MetaTrader 5، متاکوتس میگوید زمان تیک و بازشدن کندلِ دریافتی UTC است و ورودیهای زمانی API نیز باید UTC ساخته شوند. برای CSV بروکر یا هر منبع دیگر نباید منطقه زمانی را حدس زد؛ باید آن را از مستندات منبع ثبت و پیش از ترکیب دیتاستها یکسانسازی کرد.
داده جاافتاده را باید حذف کنیم یا پر کنیم؟
اول باید علت جاافتادگی مشخص شود. آخر هفته و تعطیلات بازار میتوانند شکاف طبیعی باشند، اما قطعی فید یا خرابی منبع نیاز به برخورد جداگانه دارد. برای شبیهسازی معامله، ساختن قیمت مصنوعی با درونیابی دوطرفه میتواند اطلاعات آینده را وارد داده کند؛ در بسیاری از موارد امنتر است بازه معیوب جدا و در متادیتا مستند شود، مگر اینکه روش جایگزینی از نظر زمانی و کاربرد تحقیق کاملاً توجیه شده باشد.
نشت داده (Data Leakage) چیست؟
نشت داده یعنی ورود اطلاعاتی به دیتاست که در لحظه تصمیمگیری واقعاً در دسترس نبوده است. رایجترین شکلهایش در داده بازار عبارتاند از: استفاده از بازده آینده در ساخت فیچر، برازش مقیاسگر روی کل دیتاست قبل از تقسیم آموزش و آزمون، درونیابی دوطرفهای که برای ساخت مقدار فعلی از نقطه آینده استفاده میکند، و محاسبه اندیکاتور با پنجره متمرکز. نشت داده باعث میشود مدل در بکتست بسیار قوی به نظر برسد و در واقعیت کار نکند. در یک بررسی منتشرشده در مجله Patterns، نشت داده در ۲۹۴ مقاله از ۱۷ حوزه علمی شناسایی شد.
چرا داده فارکس بین بروکرها فرق دارد؟
چون بازار اسپات فارکس یک بورس مرکزی واحد ندارد. بانک تسویه بینالمللی تصریح میکند که برخلاف سهام و قراردادهای آتی که در بورسهای متمرکز معامله میشوند، معاملات اسپات ارزی خارج از بورس انجام میشود و بازار غیرمتمرکز و پراکنده است. در نتیجه هر بروکر به مجموعه متفاوتی از ارائهدهندگان نقدینگی وصل است، روش تجمیع و فیلترینگ متفاوتی دارد و دقت مُهر زمانیاش هم فرق میکند. هیچ «قیمت رسمی» واحدی وجود ندارد که همه از آن تبعیت کنند.
آیا هوش مصنوعی میتواند داده بازار را تمیز کند؟
هوش مصنوعی در نقش دستیار بازرس بسیار مفید است: بررسی اسکیما، تولید قواعد اعتبارسنجی، نوشتن اسکریپت تست کیفیت، پیدا کردن رکوردهای تکراری، ساخت گزارش داده جاافتاده، پیدا کردن نامزدهای ناهنجاری و مرور کد فیچرسازی برای یافتن نشت. اما نباید بهصورت خودکار تصمیم بگیرد که کدام رکورد حذف شود. حذف خودکار نقاط پرت، پر کردن بدون فهمیدن علت، و حدس زدن منطقه زمانی سه راه سریع برای خراب کردن بیسروصدای دیتاست هستند.
از کجا بفهمیم دیتاست برای بکتست آماده است؟
وقتی هفت شرط همزمان برقرار باشند: منبع داده مشخص و ثبتشده باشد، یکپارچگی داده (تکراری، جاافتاده، روابط منطقی قیمت) بررسی شده باشد، همترازی زمانی و منطقه زمانی درست و مستند باشد، قواعد پاکسازی نوشته شده باشند، هیچ نشت آیندهای وجود نداشته باشد، نسخه دیتاست فریز و چکسامگیری شده باشد، و همه فرضهایی که مجبور به انتخابشان شدید مستند شده باشند.
۳۶منابع
- Kapoor, S. & Narayanan, A. (2023). «Leakage and the reproducibility crisis in machine-learning-based science.» Patterns, 4(9), 100804. cell.com
- MQL5 Documentation — «MqlRates» (ساختار کندل، فیلدهای
time،tick_volumeوreal_volume). mql5.com - MetaTrader 5 Help — «Volumes» (تعریف حجم در فارکس در برابر نمادهای بورسی). metatrader5.com
- MQL5 Book — «MqlTick» (خالی بودن فیلدهای حجم برای ابزارهای فارکس). mql5.com
- Krohn, I., Schrimpf, A. & Sushko, V. (۲۰۲۵). «The FX trade execution landscape through the prism of the 2025 BIS Triennial Survey.» BIS Quarterly Review, دسامبر ۲۰۲۵. bis.org
- Bank for International Settlements — «OTC foreign exchange turnover in April 2025.» bis.org
- MQL5 Documentation — «copy_rates_from» (یادداشت رسمی درباره ذخیرهسازی زمان بهصورت UTC بدون شیفت). mql5.com
- NIST — «Local Time FAQs» (قواعد رسمی ساعت تابستانی آمریکا). nist.gov
- Directive 2000/84/EC of the European Parliament and of the Council on summer-time arrangements. eur-lex.europa.eu
- IANA Time Zone Database — «Theory and pragmatics of the tz code and data». iana.org
- Carhart, M. M., Carpenter, J. N., Lynch, A. W. & Musto, D. K. (2002). «Mutual Fund Survivorship.» The Review of Financial Studies, 15(5), 1439–1463. academic.oup.com
- U.S. SEC & CFTC (۲۰۱۰). «Findings Regarding the Market Events of May 6, 2010.» sec.gov
- Reserve Bank of Australia (فوریه ۲۰۱۹). Statement on Monetary Policy, Box B: «The Recent Japanese Yen Flash Event». rba.gov.au
- MQL5 Documentation — «Testing Trading Strategies» (حالتهای مدلسازی و نحوه برخورد با اسپرد). mql5.com
- MQL5 Documentation — «Symbol Properties» (
SYMBOL_DIGITS،SYMBOL_POINT،SYMBOL_TRADE_TICK_SIZE). mql5.com - Ljungqvist, A., Malloy, C. & Marston, F. (2009). «Rewriting History.» The Journal of Finance, 64(4), 1935–1960. onlinelibrary.wiley.com
- CRSP — «CRSP Calculations» (ضریب تعدیل تجمعی و تعریف رویدادهای تقسیم). نسخه در دسترس: leiq.bus.umich.edu
- S&P Dow Jones Indices — «Index Mathematics Methodology». spglobal.com
- CME Group — «Get to know the quarterly roll in CME FX futures». cmegroup.com
- CSI Data — «Back-Adjusted Contracts» (روشهای رول و امکان تولید مقادیر منفی). csidata.com
- CME Group / CF Benchmarks — «CME CF Cryptocurrency Reference Rates Methodology Guide». cfbenchmarks.com
- CME Group — «Analysis of the CME CF Bitcoin Reference Rate». cmegroup.com
- Makarov, I. & Schoar, A. (2020). «Trading and arbitrage in cryptocurrency markets.» Journal of Financial Economics, 135(2), 293–319. doi.org