Strasmore Research
بررسی عمیق Matt Connorتوسط Matt Connor · به‌روزرسانی شده در 2026-08-08

آموزش بک‌تست قابل‌بازتولید در پایتون بدون نیاز به API

اجرای بک‌تست قابل‌بازتولید در پایتون بدون نیاز به کلید API با استفاده از داده‌های قطعی و نصب نسخه‌های ثابت. بررسی دقیق محدودیت‌های منحنی سهام در تحلیل‌های مالی.

یک بک‌تست (backtest) قابل‌بازتولید در پایتون، آزمونی است که یک فرد غریبه می‌تواند آن را روی یک سیستم پاک اجرا کرده و دقیقاً به همان اعداد شما دست یابد، بدون آنکه نیازی به حساب کاربری یا کلید API داشته باشد. اکثر آموزش‌ها در همان خط اول این آزمون را مردود می‌شوند؛ جایی که دانلود زنده داده‌ها، تاریخچه قیمتی متفاوتی را نسبت به آنچه نویسنده دریافت کرده است، به خواننده بعدی ارائه می‌دهد. این راهنما از یک موتور متن‌باز به نام quantjourney-bt در نسخه 0.12.4 استفاده می‌کند، مثال‌های همراه آن را بدون نیاز به هیچ‌گونه اعتبارنامه‌ای اجرا کرده و سپس با استفاده از داده‌های واقعی بازار نشان می‌دهد که یک اجرای واحد و پاک، هنوز چه نکاتی را نمی‌تواند به شما بگوید.

چه چیزی یک بک‌تست را قابل‌تکرار می‌کند؟

قابلیت تکرار در اینجا معنایی محدود و قابل‌سنجش دارد: شخص دوم با اجرای یک دستور در یک سیستم پاک، دقیقاً همان اعداد شما را تا آخرین رقم اعشار به دست آورد. دو عامل معمول این فرآیند را مختل می‌کنند.

نخست، کد است. یک کتابخانه در نسخه 0.x هیچ تعهدی برای سازگاری میان نسخه‌های فرعی ندارد. تغییر نام، تغییر در تنظیمات پیش‌فرض، یا جابه‌جایی ترتیب ستون‌ها باعث می‌شود اسکریپت شما همچنان اجرا شود، اما بی‌سروصدا خروجی متفاوتی ارائه دهد.

دوم، داده‌هاست. آموزشی که خط اول آن دانلود زنده داده‌ها باشد، هرگز قابل‌تکرار نبوده است. فروشندگان داده، تاریخچه را بازبینی می‌کنند، تعدیل‌های مربوط به اسپلیت سهام را اعمال کرده و شکاف‌های قیمتی را پر می‌کنند؛ بنابراین همان اسکریپت یک ماه بعد اعداد متفاوتی را چاپ می‌کند. پس از وقوع این تغییرات، دیگر نمی‌توان تغییر کد را از تغییر داده تفکیک کرد.

الگویی که ارزش الگوبرداری از این پروژه را دارد، جفت کردن یک نسخه ثابت از موتور پردازش با یک مجموعه داده کوچک و بسته‌بندی‌شده است که درون خودِ پکیج ارائه می‌شود.

تثبیت نسخه نصب: pip install quantjourney-bt==0.12.4

quantjourney-bt بک‌تستر QuantJourney است که تحت مجوز Apache 2.0 منتشر شده و به پایتون 3.11 یا جدیدتر نیاز دارد. نسخه 0.12.4 در 21 ژوئیه 2026 منتشر شد و همان نسخه‌ای است که تمامی دستورات زیر به آن ارجاع دارند، چنان‌که در اوت 2026 مستند شده است.

در یک محیط ایزوله کار کنید. python3 -m venv .venv یک محیط ایجاد می‌کند، source .venv/bin/activate وارد آن می‌شود و python -m pip install -U pip نصب‌کننده را در آن به‌روزرسانی می‌کند. سپس نسخه دقیق را دریافت کنید: pip install quantjourney-bt==0.12.4.

این پروژه فرم بدون قید نسخه را مستند کرده است: pip install quantjourney-bt. بخش ==0.12.4 مسئولیت شماست و در نسخه 0.x ارزش خود را ثابت می‌کند. قید نسخه را جایی یادداشت کنید که نفر بعدی آن را پیدا کند: pip freeze > requirements.txt تمامی وابستگی‌های حل‌شده، از جمله مواردی که هرگز نام نبرده‌اید را ثبت می‌کند.

دو افزونه اختیاری وجود دارد. pip install "quantjourney-bt[wf]" کتابخانه Optuna را برای نمونه‌های walk-forward و بهینه‌سازی اضافه می‌کند. pip install "quantjourney-bt[data]" یک جایگزین yfinance برای بنچمارک‌ها اضافه می‌کند.

مجوز Apache-2.0 مجازکننده است. شما می‌توانید از کد به‌صورت تجاری استفاده و آن را اصلاح کنید، فایل‌های مجوز و اعلامیه را در هر بازنشر حفظ کنید و مشارکت‌کنندگان به‌صراحت حقوق ثبت اختراع را اعطا می‌کنند.

نحوه اجرای نمونه SMA بسته‌بندی‌شده بدون نیاز به API key

این مخزن شامل یک اسکریپت راه‌انداز به همراه پنجاه استراتژی نمونه قابل‌اجرا است که در دو مسیر مبتنی بر وزن و مبتنی بر سفارش تقسیم شده‌اند و پنج گردش کار walk-forward نیز در میان آن‌ها قرار دارد. ./strategy.sh --list کاتالوگ را چاپ می‌کند. ./strategy.sh example_weights_01_sma_daily --check یک استراتژی واحد را وارد (import) می‌کند و هیچ داده‌ای را لمس نمی‌کند، که سریع‌ترین راه برای اطمینان از صحت نصب است.

اجرای دمو تنها یک خط است: ./strategy.sh example_weights_01_sma_daily --sample-data --output /tmp/qj-sample

پرچم --sample-data تمام هدف این کار را در بر می‌گیرد. پروژه، مجموعه داده پشت این عملیات را این‌گونه توصیف می‌کند:

مجموعه داده نمونه به‌طور عمدی کوچک و قابل‌بازتولید است. این مجموعه برای بررسی نصب، تولید گزارش و مطالعه جریان موتور (engine flow) بدون نیاز به ایجاد حساب کاربری مفید است.
منبع: quantjourney-bt README، نسخه 0.12.4، خوانده‌شده در 6 اوت 2026.

این اجرا به‌جای نمایش نتیجه در کنسول، یک دایرکتوری ایجاد می‌کند: summary.txt و summary.json، یک metrics.csv، یک equity_curve.csv در کنار equity_curve.png آن، یک dashboard.html، یک پوشه plots/ و یک run_metadata.json که نحوه پیکربندی اجرا را ثبت می‌کند. آن فایل آخر، فایلی است که اکثر افراد از آن می‌گذرند و همان فایلی است که باعث می‌شود نتیجه پس از یک سال قابل‌حسابرسی باشد.

معیارهای حاصل را صادقانه بخوانید. مجموعه داده بسته‌بندی‌شده کوچک و صرفاً جهت نمایش است، بنابراین نسبت Sharpe و حداکثر افت ارزش (maximum drawdown) چاپ‌شده در summary.txt، تنها توصیف‌کننده یک فایل نمونه هستند. آن‌ها شواهدی درباره یک استراتژی نیستند و تلقی کردن آن‌ها به‌عنوان یک نتیجه، اولین اشتباهی است که ممکن است مرتکب شوید.

آنچه این اجرا ثابت می‌کند، ارزشمند است: نصب به‌درستی کار می‌کند و کل جریان موتور، از سیگنال تا وزن‌های هدف و ارزش بازسازی‌شده سبد سهام، بدون نیاز به هیچ‌گونه اعتبارنامه‌ای، خروجی‌های خود را روی دستگاه شما تولید می‌کند. یک مسیر دارای اعتبارنامه برای سرویس داده خودِ پروژه جهت انجام بک‌تست روی داده‌های تاریخی واقعی وجود دارد. آن مسیر مستند شده است و این راهنما در همین‌جا، یعنی بخشی که به هیچ‌کس و هیچ‌چیز وابسته نیست، به پایان می‌رسد.

آنچه یک منحنی حقوق صاحبان سهام درون‌نمونه به شما نمی‌گوید

اجرای نمونه، یک منحنی حقوق صاحبان سهام (equity curve) ترسیم می‌کند. در اینجا آنچه این منحنی قادر به انجام آن نیست، با استفاده از داده‌های واقعی بازار به‌جای یک فایل نمایشی، بررسی شده است.

پنل زیر از همان ایده‌ای استفاده می‌کند که استراتژی نمونه به‌کار می‌برد؛ یعنی تقاطع میانگین متحرک 20 دوره‌ای با میانگین متحرک 50 دوره‌ای. این استراتژی بر روی SPY اعمال شده و نتایج هر سال تقویمی از 2017 تا 2025 به‌طور جداگانه گزارش شده است. موقعیت معاملاتی در هر جلسه بر اساس قیمت بسته شدن جلسه قبل تعیین می‌شود، بنابراین این قاعده هرگز بر اساس عددی که هنوز در دسترس نبوده، معامله نمی‌کند.

پرس‌وجوتقاطع میانگین متحرک ۲۰/۵۰ در SPY به تفکیک سال، در مقایسه با استراتژی نگهداری (Buy and Hold)
کد دقیق SQL پشت هر عدد
WITH daily AS
(
    SELECT
        toDate(toTimeZone(window_start, 'America/New_York')) AS d,
        toFloat64(argMax(close, window_start))               AS px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= '2016-01-01 00:00:00'
      AND window_start <  '2026-01-01 05:00:00'
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) >= 570
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) < 960
    GROUP BY d
),
averaged AS
(
    SELECT
        d,
        px,
        avg(px) OVER (ORDER BY d ROWS BETWEEN 19 PRECEDING AND CURRENT ROW) AS fast_ma,
        avg(px) OVER (ORDER BY d ROWS BETWEEN 49 PRECEDING AND CURRENT ROW) AS slow_ma,
        row_number() OVER (ORDER BY d)                                      AS session_no
    FROM daily
),
positioned AS
(
    SELECT
        d,
        px,
        if(session_no >= 50 AND fast_ma > slow_ma, 1, 0) AS long_today,
        lagInFrame(if(session_no >= 50 AND fast_ma > slow_ma, 1, 0), 1)
            OVER (ORDER BY d ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS long_prior,
        lagInFrame(px, 1)
            OVER (ORDER BY d ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS px_prior
    FROM averaged
)
SELECT
    toYear(d)                                                                   AS year,
    round((exp(sum(log(if(long_prior = 1, px / px_prior, 1.0)))) - 1) * 100, 1) AS rule_pct,
    round((exp(sum(log(px / px_prior))) - 1) * 100, 1)                          AS hold_pct,
    countIf(long_today != long_prior)                                           AS crossover_count
FROM positioned
WHERE px_prior > 0
  AND toYear(d) >= 2017
GROUP BY year
ORDER BY year
Run this yourself

یک قاعده بدون تغییر، که 9 بار جداگانه اندازه‌گیری شده است. پیش از خواندن هر چیز دیگری، دو ستون درصد را از بالا به پایین مطالعه کنید. در 2017، این قاعده سال را با 16% در برابر 19.4% برای نگهداری SPY در همان دوره به پایان رساند. در 2025، همان دو ستون اعداد 10.4% و 16.4% را نشان می‌دهند. کد در هر دو ردیف یکسان است. تنها بازه زمانی تغییر کرده است.

ستون تقاطع نشان می‌دهد که شواهد زیربنایی تا چه حد محدود می‌شوند. 4 تغییر موقعیت در طول 2025 به این معناست که یک سال کامل از منحنی حقوق صاحبان سهام بر پایه تعداد انگشت‌شماری از تصمیمات استوار است، که نمونه بسیار کوچکی برای نامیدن آن به‌عنوان یک نتیجه قطعی محسوب می‌شود.

آیا این قاعده در سایر نمادها نیز به همین شکل عمل می‌کند؟

تغییر بازه زمانی، یک روش برای بررسی یک منحنی واحد است. تغییر دامنه دارایی‌ها، روش دیگر است. پنل زیر پارامترها را ثابت نگه می‌دارد و همان قاعده را روی پنج نماد نقدشونده طی پنج سال تقویمی 2021 تا 2025 اجرا می‌کند.

پرس‌وجواجرای همان قاعده ۲۰/۵۰ بر روی پنج نماد نقدشونده، از ۲۰۲۱ تا ۲۰۲۵
کد دقیق SQL پشت هر عدد
WITH daily AS
(
    SELECT
        ticker,
        toDate(toTimeZone(window_start, 'America/New_York')) AS d,
        toFloat64(argMax(close, window_start))               AS px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('SPY', 'QQQ', 'AAPL', 'MSFT', 'KO')
      AND window_start >= '2020-07-01 00:00:00'
      AND window_start <  '2026-01-01 05:00:00'
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) >= 570
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) < 960
    GROUP BY ticker, d
),
averaged AS
(
    SELECT
        ticker,
        d,
        px,
        avg(px) OVER (PARTITION BY ticker ORDER BY d ROWS BETWEEN 19 PRECEDING AND CURRENT ROW) AS fast_ma,
        avg(px) OVER (PARTITION BY ticker ORDER BY d ROWS BETWEEN 49 PRECEDING AND CURRENT ROW) AS slow_ma,
        row_number() OVER (PARTITION BY ticker ORDER BY d)                                      AS session_no
    FROM daily
),
positioned AS
(
    SELECT
        ticker,
        d,
        px,
        lagInFrame(if(session_no >= 50 AND fast_ma > slow_ma, 1, 0), 1)
            OVER (PARTITION BY ticker ORDER BY d ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS long_prior,
        lagInFrame(px, 1)
            OVER (PARTITION BY ticker ORDER BY d ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS px_prior
    FROM averaged
)
SELECT
    ticker                                                                      AS symbol,
    round((exp(sum(log(if(long_prior = 1, px / px_prior, 1.0)))) - 1) * 100, 1) AS rule_pct,
    round((exp(sum(log(px / px_prior))) - 1) * 100, 1)                          AS hold_pct,
    round(avg(long_prior) * 100, 0)                                             AS days_long_pct
FROM positioned
WHERE px_prior > 0
  AND d >= toDate('2021-01-01')
GROUP BY symbol
ORDER BY rule_pct DESC
Run this yourself

QQQ در بالای پنل در 40.2% قرار دارد و ردیف پایین، KO، در 3.8% جای گرفته است. ستون days_long_pct گزارش می‌دهد که هر نسخه چه میزان از بازه زمانی را صرف نگهداری دارایی کرده است، که برای ردیف بالا 67% است. یک مجموعه پارامتر، پنج دامنه دارایی، و یک اسپرد به اندازه‌ای گسترده که انتخاب برنده پس از وقوع رویداد، هیچ اطلاعاتی درباره عملکردی که هنوز انجام نداده‌اید، به دست نمی‌دهد.

هیچ‌کدام از این موارد توصیه‌ای برای معامله بر اساس تقاطع (crossover) نیست. تقاطع، یک معیار سنجش برای بک‌تست (backtest) است و آنچه ما در حال اندازه‌گیری آن هستیم، خودِ بک‌تست است.

جایی که سوگیری نگاه به آینده (look-ahead bias) در بک‌تست‌های مبتنی بر وزن‌دهی رخنه می‌کند

یک موتور مبتنی بر وزن‌دهی، سیگنال را به وزن‌های هدف تبدیل می‌کند، اجرای معاملات (fills) را بر اساس آن وزن‌ها شبیه‌سازی کرده و سپس ارزش سبد سهام را از موقعیت‌های حاصل بازسازی می‌کند. نقص کار در نقطه اتصال سیگنال و وزن پنهان است. اگر وزن امروز از قیمت پایانی (close) امروز استخراج شود و سپس بازدهی همان روز را کسب کند، بک‌تست بر اساس اطلاعاتی معامله کرده که در زمان ارسال سفارش وجود نداشته است. این همان سوگیری نگاه به آینده است و هیچ خطایی ایجاد نمی‌کند؛ صرفاً همه چیز را بهتر از واقعیت نشان می‌دهد.

پنل زیر هر دو نسخه از یک قاعده را بر روی تاریخچه یکسانی از SPY اجرا می‌کند.

پرس‌وجوهمان قاعده، مقایسه سیگنال جلسه معاملاتی پیشین با سیگنال همان جلسه در SPY به تفکیک سال
کد دقیق SQL پشت هر عدد
WITH daily AS
(
    SELECT
        toDate(toTimeZone(window_start, 'America/New_York')) AS d,
        toFloat64(argMax(close, window_start))               AS px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= '2016-01-01 00:00:00'
      AND window_start <  '2026-01-01 05:00:00'
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) >= 570
      AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
           + toMinute(toTimeZone(window_start, 'America/New_York'))) < 960
    GROUP BY d
),
averaged AS
(
    SELECT
        d,
        px,
        avg(px) OVER (ORDER BY d ROWS BETWEEN 19 PRECEDING AND CURRENT ROW) AS fast_ma,
        avg(px) OVER (ORDER BY d ROWS BETWEEN 49 PRECEDING AND CURRENT ROW) AS slow_ma,
        row_number() OVER (ORDER BY d)                                      AS session_no
    FROM daily
),
positioned AS
(
    SELECT
        d,
        px,
        if(session_no >= 50 AND fast_ma > slow_ma, 1, 0) AS long_today,
        lagInFrame(if(session_no >= 50 AND fast_ma > slow_ma, 1, 0), 1)
            OVER (ORDER BY d ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS long_prior,
        lagInFrame(px, 1)
            OVER (ORDER BY d ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS px_prior
    FROM averaged
)
SELECT
    toYear(d)                                                                   AS year,
    round((exp(sum(log(if(long_prior = 1, px / px_prior, 1.0)))) - 1) * 100, 1) AS next_bar_pct,
    round((exp(sum(log(if(long_today = 1, px / px_prior, 1.0)))) - 1) * 100, 1) AS same_bar_pct,
    round(abs(exp(sum(log(if(long_today = 1, px / px_prior, 1.0))))
              - exp(sum(log(if(long_prior = 1, px / px_prior, 1.0))))) * 100, 1) AS gap_pp
FROM positioned
WHERE px_prior > 0
  AND toYear(d) >= 2017
GROUP BY year
ORDER BY year
Run this yourself

در 2017 نسخه مربوط به جلسه معاملاتی پیشین، بازدهی 16% را ثبت کرد، در حالی که نسخه مربوط به همان جلسه، بازدهی 17.1% را نشان داد که 1.1 واحد درصد با هم اختلاف دارند. در 2025 فاصله بین این دو، 1.6 واحد درصد اندازه‌گیری شد. تنها یکی از این ستون‌ها می‌تواند توسط ماشینی تولید شده باشد که از قبل نمی‌دانسته جلسه معاملاتی با چه قیمتی بسته می‌شود؛ تفاوت میان آن‌ها صرفاً یک حساب‌وکتاب است، بدون اینکه ایده‌ای، مهارتی یا معامله‌ای در پس آن باشد.

این موتور موضع خود را در مورد مسئله زمان‌بندی اعلام می‌کند که ارزشی بیش از یک وعده دارد:

برای اجرای معاملات در قیمت بازگشایی (open)، لغزش قیمت (slippage) حساس به دامنه نوسان، تنها کندل تکمیل‌شده قبلی را می‌بیند و ظرفیت حجم معاملات از مشاهدات با وقفه (lagged) پیش‌بینی می‌شود؛ موتور از قیمت‌های بالا، پایین، بسته شدن یا حجم کامل همان روز استفاده نمی‌کند.
منبع: quantjourney-bt README، نسخه 0.12.4، تاریخ مطالعه 6 اوت 2026.

یک فرض مستند را می‌توان با کدی که قبلاً نصب کرده‌اید، بررسی کرد. فرضی که مستند نشده باشد، صرفاً یک حدس است.

چرا افزونه walk-forward وجود دارد

مثال‌های walk-forward، از WF01 تا WF05، به همراه افزونه [wf] و وابستگی آن به Optuna ارائه می‌شوند. در روش walk-forward، پارامترها روی یک بازه از داده‌های تاریخی برازش (fit) شده، سپس روی بازه بعدی اندازه‌گیری می‌شوند؛ در ادامه، این جفت‌بازه به جلو حرکت کرده و فرآیند تکرار می‌شود. تفاوت مدل‌های غلتان (rolling) و گسترش‌یابنده (expanding) در این است که آیا پنجره برازش با پیشروی، قدیمی‌ترین داده‌های خود را حذف می‌کند یا خیر. یک مثال دیگر، در هر مرز، عملیات پاک‌سازی (purge) و ممنوعیت (embargo) را اضافه می‌کند تا مشاهدات نزدیک به نقطه اتصال حذف شوند؛ بدین ترتیب، داده‌های یک بازه برازش‌شده نمی‌توانند به بازه‌ای که در حال اندازه‌گیری است نشت کنند.

هیچ‌کدام از این موارد، یک ایده ضعیف را به ایده‌ای کارآمد تبدیل نمی‌کند. این روش صرفاً یک عدد واحد را با توزیعی از اعداد جایگزین می‌کند که می‌توانید درباره آن بحث کنید، و کل ارتقا همین است. گام بعدی هنوز به معنای معامله با پول واقعی نیست: معامله کاغذی پیش از استفاده از پول واقعی مواردی را اندازه‌گیری می‌کند که بک‌تست به‌طور ساختاری قادر به دیدن آن‌ها نیست؛ از جمله اینکه آیا سفارش شما در قیمتی نزدیک به آنچه شبیه‌ساز فرض کرده، اجرا می‌شود یا خیر. همچنین مدارهای قطع‌کننده برای ربات‌های معاملاتی به عملکرد کد شما در روزهایی که بازار طبق انتظار پیش نمی‌رود، می‌پردازند. برای آگاهی از آمار زیربنایی تمام این موارد، یادداشت‌های ما در کتاب متن‌باز معاملات کمی یک سطح عمیق‌تر به موضوع نگاه می‌کنند.

پرسش‌های متداول

آیا می‌توان بدون کلید API یک استراتژی را بک‌تست کرد؟

بله. quantjourney-bt به همراه یک مجموعه داده نمونه که پشت پرچم --sample-data قرار دارد عرضه می‌شود و استراتژی‌های نمونه آن بدون نیاز به حساب کاربری یا اعتبارنامه، روی این داده‌ها اجرا می‌شوند. این مجموعه داده کوچک و صرفاً جهت آموزش است؛ بنابراین، این اجرا را به‌عنوان یک بررسی نصب و خط لوله (pipeline) در نظر بگیرید، نه به‌عنوان سندی برای اثبات عملکرد یک استراتژی.

چرا باید نسخه بسته‌های بک‌تست پایتون را ثابت (Pin) کرد؟

یک بسته در نسخه 0.x هیچ تضمینی برای سازگاری بین نسخه‌های فرعی ارائه نمی‌دهد و تغییر در مقادیر پیش‌فرض یا تغییر نام معیارها بدون اطلاع قبلی رخ می‌دهد. ثابت کردن نسخه با pip install quantjourney-bt==0.12.4 و ثبت محیط در یک فایل requirements به این معناست که نتیجه‌ای که امروز تولید می‌کنید، سال آینده نیز با همان موتوری که آن را ساخته است، قابل بازتولید خواهد بود.

quantjourney-bt تحت چه مجوزی منتشر شده است؟

مجوز Apache License 2.0. این مجوز اجازه استفاده تجاری و تغییر در کد را می‌دهد، مشروط بر اینکه فایل‌های مجوز و اعلامیه را در هر بازنشر حفظ کنید، و شامل اعطای صریح حق امتیاز (patent grant) از سوی مشارکت‌کنندگان است. نسخه 0.12.4 در 21 ژوئیه 2026 منتشر شده و به پایتون 3.11 یا جدیدتر نیاز دارد.

آیا نتیجه قوی در بک‌تست به معنای کارآمدی استراتژی است؟

خیر. بک‌تست تنها یک اندازه‌گیری در یک بازه زمانی مشخص و روی یک مجموعه دارایی خاص است. پنل‌های بالا نشان می‌دهند که یک قانون واحد و تغییرناپذیر، ارقام سالانه بسیار متفاوتی را روی یک تیکر (ticker) و ارقام بسیار متفاوتی را در پنج نام مختلف ایجاد می‌کند؛ این همان شکافی است که اعتبارسنجی walk-forward و تست‌های out-of-sample برای آشکار کردن آن طراحی شده‌اند.

نحوه محاسبه پنل‌های بالا

قیمت‌های پایانی روزانه، آخرین نرخ ثبت‌شده در دقیقه پایانی جلسه عادی معاملاتی برای هر تاریخ است که بر اساس زمان نیویورک بین ساعت 9:30 صبح تا 4:00 بعدازظهر محاسبه می‌شود؛ این روش باعث می‌شود روزهای نیمه‌تعطیل بدون نیاز به کدگذاری سخت‌افزاری طول جلسه، به‌درستی لحاظ شوند. میانگین سریع 20 جلسه و میانگین کند 50 جلسه را پوشش می‌دهد که هر دو از نوع ساده هستند و 49 جلسه اول هر سری، دوره گرم‌کردن (warm-up) محسوب شده و هیچ موقعیتی در آن‌ها اتخاذ نمی‌شود. ارقام سالانه، حرکت قیمت از بسته شدن تا بسته شدن هر جلسه را برای جلساتی که قانون در موقعیت خرید (long) بوده، ترکیب (compound) می‌کنند و ستون hold، تمام جلسات همان سال را برای مقایسه ترکیب می‌کند. پنج نام موجود در مقطع عرضی (cross-section) به دلیل تاریخچه پیوسته و عدم وجود اسپلیت در بازه زمانی انتخاب شده‌اند، بنابراین سری قیمت‌های پایانی نیازی به تعدیل ندارند. بازه‌های زمانی در گذشته ثابت هستند، بنابراین این پنل‌ها در هر بار بازتولید، اعداد یکسانی را ارائه می‌دهند.


هر پنل در اینجا دقیقاً حاوی کد SQL زیربنایی خود است که باعث می‌شود اعداد این صفحه به اندازه نصبِ ثابت‌شده، قابل بازاجرا باشند. برای اندازه‌گیری یک قانون در بازه زمانی مورد نظر خود پیش از نوشتن هرگونه کد بک‌تست، پرسش خود را به زبان ساده در ترمینال Strasmore مطرح کنید.

#backtesting#python#open source#reproducibility#quantjourney