Strasmore Research
गहन पड़ताल Matt Connorलेखक: Matt Connor · अपडेट किया गया: 2026-08-08

Python में बिना API Key के बैकटेस्ट कैसे करें

Python में बिना API Key के एक सटीक और पुनरुत्पादनीय बैकटेस्ट चलाने का तरीका जानें। इसमें पिन किए गए संस्करण और स्थिर डेटा का उपयोग करके इक्विटी कर्व की सीमाओं को समझना शामिल है।

2025
Python में एक पुनरुत्पादनीय (reproducible) बैकटेस्ट वह है जिसे कोई अनजान व्यक्ति एक साफ मशीन पर दोबारा चला सके और आपके सटीक आंकड़े प्राप्त कर सके, जिसमें कोई अकाउंट या API की की बाधा न हो। अधिकांश ट्यूटोरियल पहली ही पंक्ति में इस परीक्षण में विफल हो जाते हैं, जहाँ लाइव डाउनलोड अगले पाठक को थोड़ा अलग प्राइस हिस्ट्री देता है, जो लेखक को मिली थी। यह वॉकथ्रू एक ओपन-सोर्स इंजन, quantjourney-bt को संस्करण 0.12.4 पर पिन करता है, बिना किसी क्रेडेंशियल के इसके बंडल किए गए उदाहरण को चलाता है, और फिर वास्तविक बाजार डेटा का उपयोग करके यह दिखाता है कि एक एकल साफ रन भी आपको क्या नहीं बता सकता है।

बैकटेस्टिंग की चुनौतियाँ

पुनरुत्पादनीयता का महत्व

डेटा की निरंतरता और संस्करण नियंत्रण

एक बैकटेस्ट तभी विश्वसनीय होता है जब उसके इनपुट डेटा स्थिर हों। यदि आप लाइव डेटा फीड का उपयोग करते हैं, तो समय के साथ डेटा में होने वाले सुधार या समायोजन आपके परिणामों को बदल सकते हैं। एक पेशेवर विश्लेषक के रूप में, आपको यह सुनिश्चित करना चाहिए कि आपका डेटासेट स्थिर है और उसका संस्करण नियंत्रित है। यह सुनिश्चित करता है कि आपके द्वारा किए गए विश्लेषण को भविष्य में किसी भी समय दोहराया जा सके।

बैकटेस्ट को पुनरुत्पादनीय (reproducible) क्या बनाता है?

यहाँ पुनरुत्पादनीयता का एक संकीर्ण और परीक्षण योग्य अर्थ है: कोई दूसरा व्यक्ति एक साफ मशीन पर एक कमांड चलाता है और उसे दशमलव तक आपके समान आंकड़े प्राप्त होते हैं। दो सामान्य चीजें इसे बाधित करती हैं।

पहली है कोड। 0.x संस्करण वाली कोई लाइब्रेरी माइनर रिलीज़ के बीच संगतता (compatibility) का कोई वादा नहीं करती है। नाम में बदलाव, डिफ़ॉल्ट सेटिंग में बदलाव, या कॉलम के क्रम में बदलाव होने पर आपकी स्क्रिप्ट चलती तो रहती है, लेकिन चुपचाप कुछ और ही परिणाम देने लगती है।

दूसरी है डेटा। एक ट्यूटोरियल जिसकी पहली पंक्ति ही लाइव डाउनलोड है, वह कभी भी पुनरुत्पादनीय नहीं था। वेंडर इतिहास को संशोधित करते हैं, स्टॉक स्प्लिट के लिए समायोजन करते हैं, और डेटा के अंतराल को भरते हैं, जिससे एक महीने बाद वही स्क्रिप्ट अलग आंकड़े दिखाती है। बाद में, आप कोड में हुए बदलाव और डेटा में हुए बदलाव के बीच अंतर नहीं कर सकते।

इस प्रोजेक्ट से जो पैटर्न अपनाने योग्य है, वह है एक निश्चित इंजन संस्करण को एक छोटे बंडल किए गए डेटासेट के साथ जोड़ना, जो स्वयं पैकेज के भीतर ही मौजूद होता है।

इंस्टॉलेशन को पिन करें: pip install quantjourney-bt==0.12.4

quantjourney-bt QuantJourney बैकटेस्टर है, जिसे Apache License 2.0 के तहत जारी किया गया है और इसके लिए Python 3.11 या उससे नए संस्करण की आवश्यकता है। संस्करण 0.12.4 को 21 जुलाई 2026 को प्रकाशित किया गया था, और यह वही संस्करण है जिसे नीचे दिए गए प्रत्येक कमांड में संदर्भित किया गया है, जैसा कि अगस्त 2026 में प्रलेखित किया गया है।

एक अलग वातावरण (isolated environment) के भीतर काम करें। 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 हर उस resolved dependency को कैप्चर करता है, जिसे आपने कभी नाम नहीं दिया था।

दो वैकल्पिक अतिरिक्त (extras) मौजूद हैं। pip install "quantjourney-bt[wf]" वॉक-फॉरवर्ड और ऑप्टिमाइज़ेशन उदाहरणों के लिए Optuna जोड़ता है। pip install "quantjourney-bt[data]" बेंचमार्क के लिए उपयोग किया जाने वाला yfinance फॉलबैक जोड़ता है।

Apache-2.0 अनुमेय (permissive) है। आप कोड का व्यावसायिक रूप से उपयोग और संशोधन कर सकते हैं, आप किसी भी पुनर्वितरण के साथ लाइसेंस और नोटिस फ़ाइलों को रखते हैं, और योगदानकर्ता स्पष्ट रूप से पेटेंट अधिकार प्रदान करते हैं।

बिना API key के बंडल किए गए SMA उदाहरण को कैसे चलाएं

रिपॉजिटरी में एक लॉन्चर स्क्रिप्ट के साथ पचास रन करने योग्य रणनीति उदाहरण दिए गए हैं, जिन्हें वेट-आधारित पथ और ऑर्डर-आधारित पथ में विभाजित किया गया है, जिनमें पांच वॉक-फॉरवर्ड वर्कफ़्लो शामिल हैं। ./strategy.sh --list कैटलॉग को प्रिंट करता है। ./strategy.sh example_weights_01_sma_daily --check एक एकल रणनीति को इम्पोर्ट करता है और किसी भी डेटा को नहीं छूता है, जो यह पुष्टि करने का सबसे तेज़ तरीका है कि इंस्टॉलेशन सही है।

डेमो रन स्वयं एक पंक्ति का है: ./strategy.sh example_weights_01_sma_daily --sample-data --output /tmp/qj-sample

--sample-data फ्लैग इसका मुख्य उद्देश्य है। प्रोजेक्ट इसके पीछे के डेटासेट का वर्णन इस प्रकार करता है:

नमूना डेटासेट जानबूझकर छोटा और पुनरुत्पादनीय रखा गया है। यह इंस्टॉलेशन की जांच, रिपोर्ट तैयार करने और अकाउंट बनाए बिना इंजन के प्रवाह को समझने के लिए उपयोगी है।
स्रोत: quantjourney-bt README, संस्करण 0.12.4, 6 अगस्त 2026 को पढ़ा गया।

यह रन कंसोल पर परिणाम देने के बजाय एक डायरेक्टरी लिखता है: summary.txt और summary.json, एक metrics.csv, अपने equity_curve.png के बगल में एक equity_curve.csv, एक dashboard.html, एक plots/ फ़ोल्डर, और यह रिकॉर्ड करने के लिए एक run_metadata.json कि रन को कैसे कॉन्फ़िगर किया गया था। वह अंतिम फ़ाइल वह है जिसे अधिकांश लोग छोड़ देते हैं और वही है जो एक साल बाद परिणाम को ऑडिट करने योग्य बनाती है।

परिणामी मेट्रिक्स को ईमानदारी से पढ़ें। बंडल किया गया डेटासेट छोटा और वर्णनात्मक है, इसलिए summary.txt में प्रिंट किया गया Sharpe ratio और maximum drawdown केवल एक नमूना फ़ाइल का वर्णन करते हैं। वे किसी रणनीति के बारे में प्रमाण नहीं हैं, और उन्हें परिणाम के रूप में मानना आपकी पहली बड़ी गलती हो सकती है।

यह रन जो स्थापित करता है वह महत्वपूर्ण है: इंस्टॉलेशन काम करता है, और सिग्नल से लेकर टारगेट वेट और पुनर्गठित पोर्टफोलियो वैल्यू तक का पूरा इंजन प्रवाह, बिना किसी क्रेडेंशियल के आपकी मशीन पर अपने आर्टिफैक्ट्स तैयार करता है। वास्तविक इतिहास पर बैकटेस्ट के लिए प्रोजेक्ट की अपनी डेटा सेवा का एक क्रेडेंशियल-आधारित पथ मौजूद है। वह पथ प्रलेखित है, और यह वॉकथ्रू यहीं समाप्त होता है, उस हिस्से पर जिसे किसी से कुछ भी लेने की आवश्यकता नहीं है।

एक इन-सैंपल इक्विटी कर्व आपको क्या नहीं बताता है

सैंपल रन एक इक्विटी कर्व तैयार करता है। यहाँ बताया गया है कि वह कर्व क्या नहीं कर सकता, जिसे डेमो फ़ाइल के बजाय वास्तविक बाज़ार डेटा पर मापा गया है।

नीचे दिया गया पैनल उसी विचार को लेता है जिसका उपयोग उदाहरण रणनीति करती है, यानी 20-सत्र मूविंग एवरेज का 50-सत्र वाले को क्रॉस करना। इसे SPY पर लागू किया गया है और 2017 से 2025 तक प्रत्येक कैलेंडर वर्ष की अलग-अलग रिपोर्ट दी गई है। प्रत्येक सत्र में पोजीशन पिछले सत्र के क्लोजिंग भाव से तय होती है, इसलिए नियम कभी भी ऐसे नंबर पर ट्रेड नहीं करता जो उसके पास पहले से उपलब्ध न हो।

क्वेरीSPY पर 20/50 मूविंग-एवरेज क्रॉसओवर, वर्ष-दर-वर्ष, होल्डिंग के मुकाबले
हर आंकड़े के पीछे का पूरा 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% पर किया, जबकि उसी अवधि में SPY को होल्ड करने का रिटर्न 19.4% रहा। 2025 में वही दो कॉलम 10.4% और 16.4% दर्शाते हैं। दोनों पंक्तियों में कोड समान है। केवल विंडो बदली है।

क्रॉसओवर कॉलम दिखाता है कि अंतर्निहित साक्ष्य कितने कम हो जाते हैं। 2025 सत्रों में 4 पोजीशन बदलाव का मतलब है कि पूरे वर्ष का इक्विटी कर्व केवल कुछ निर्णयों पर टिका है, जो किसी परिणाम को घोषित करने के लिए बहुत छोटा सैंपल है।

क्या यही नियम अन्य नामों पर भी समान रूप से काम करता है?

तारीख की विंडो बदलना एक कर्व का विश्लेषण करने का एक तरीका है। यूनिवर्स बदलना दूसरा तरीका है। नीचे दिया गया पैनल मापदंडों को स्थिर रखता है और पांच लिक्विड नामों पर वर्ष दो हजार इक्कीस से दो हजार पच्चीस तक के पांच कैलेंडर वर्षों के लिए समान नियम लागू करता है।

क्वेरीपाँच लिक्विड नामों पर वही 20/50 नियम, 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% है। एक पैरामीटर सेट, पांच यूनिवर्स, और इतना व्यापक स्प्रेड कि बाद में विजेता चुनने से उस रन के बारे में कुछ पता नहीं चलता जिसे आपने अभी तक नहीं किया है।

इनमें से कोई भी क्रॉसओवर ट्रेड करने की सलाह नहीं है। क्रॉसओवर बैकटेस्ट के लिए एक मापक है, और बैकटेस्ट ही वह चीज है जिसे हम माप रहे हैं।

वेट्स बैकटेस्ट में लुक-अहेड बायस कहाँ से आता है

वेट्स-आधारित इंजन एक सिग्नल को टारगेट वेट्स में बदलता है, उन वेट्स के आधार पर ट्रेड फिल होने का अनुकरण करता है, और फिर परिणामी पोजीशन से पोर्टफोलियो वैल्यू का पुनर्निर्माण करता है। यह त्रुटि सिग्नल और वेट के बीच के जुड़ाव में छिपी होती है। यदि आज का वेट आज के क्लोजिंग प्राइस से निर्धारित होता है और फिर आज का ही रिटर्न अर्जित करता है, तो बैकटेस्ट ने ऐसी जानकारी पर ट्रेड किया है जो ऑर्डर दिए जाने के समय मौजूद ही नहीं थी। इसे लुक-अहेड बायस कहते हैं, और यह कोई एरर मैसेज नहीं देता। यह बस सब कुछ बेहतर दिखाने का काम करता है।

नीचे दिया गया पैनल 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 प्रतिशत अंक मापी गई। उन कॉलम में से केवल एक ही ऐसी मशीन द्वारा तैयार किया जा सकता है जिसे पहले से यह नहीं पता था कि सत्र कहाँ बंद हुआ, और उनके बीच का अंतर केवल अकाउंटिंग है, जिसके पीछे कोई विचार, कोई कौशल या कोई ट्रेड नहीं है।

यह इंजन टाइमिंग के प्रश्न पर अपनी स्थिति स्पष्ट करता है, जो किसी वादे से अधिक मूल्यवान है:

ओपन पर फिल के लिए, रेंज-सेंसिटिव स्लिपेज केवल पिछली पूर्ण बार को देखता है और वॉल्यूम क्षमता का पूर्वानुमान लैग्ड ऑब्जर्वेशन से लगाया जाता है; इंजन उस दिन के बाद के हाई, लो, क्लोज या पूरे दिन के वॉल्यूम का उपयोग नहीं करता है।
स्रोत: quantjourney-bt README, संस्करण 0.12.4, 6 अगस्त 2026 को पढ़ा गया।

एक प्रलेखित धारणा (documented assumption) की जांच उस स्रोत के आधार पर की जा सकती है जिसे आपने पहले ही इंस्टॉल कर लिया है। एक बिना प्रलेखित धारणा केवल एक अनुमान है।

वॉक-फॉरवर्ड एक्स्ट्रा क्यों मौजूद है

वॉक-फॉरवर्ड उदाहरण, WF01 से WF05 तक, [wf] एक्स्ट्रा और इसकी Optuna निर्भरता के साथ आते हैं। वॉक-फॉरवर्ड इतिहास के एक हिस्से पर पैरामीटर्स को फिट करता है, उन्हें अगले हिस्से पर मापता है, फिर इस जोड़ी को आगे बढ़ाता है और प्रक्रिया को दोहराता है। रोलिंग और एक्सपेंडिंग वेरिएंट्स में अंतर यह है कि क्या फिटिंग विंडो आगे बढ़ते समय अपने सबसे पुराने डेटा को हटाती है या नहीं। एक अन्य उदाहरण प्रत्येक सीमा पर एक पर्ज और एम्बार्गो जोड़ता है, जो सीम (seam) के सबसे निकट के अवलोकनों को हटा देता है, ताकि एक फिट किया गया हिस्सा उस हिस्से में लीक न हो सके जिस पर उसे मापा जा रहा है।

इनमें से कोई भी एक कमजोर विचार को काम करने वाले विचार में नहीं बदलता है। यह एक एकल संख्या को संख्याओं के एक वितरण से बदल देता है जिस पर आप बहस कर सकते हैं, और यही पूरा अपग्रेड है। इसके बाद का चरण अभी भी वास्तविक धन का निवेश नहीं है: वास्तविक धन से पहले पेपर ट्रेडिंग उन चीजों को मापता है जिन्हें बैकटेस्ट संरचनात्मक रूप से नहीं देख सकता, जिसकी शुरुआत इस बात से होती है कि क्या आपके ऑर्डर सिम्युलेटर द्वारा माने गए मूल्य के आसपास कहीं भी फिल (fill) होते हैं, और ट्रेडिंग बॉट्स के लिए सर्किट ब्रेकर्स इस बात को कवर करते हैं कि जिस दिन आपका कोड काम नहीं करता, उस दिन वह क्या करता है। इन सबके आधारभूत आंकड़ों के लिए, ओपन-सोर्स क्वांट ट्रेडिंग बुक पर हमारे नोट्स एक स्तर और गहराई में जाते हैं।

अक्सर पूछे जाने वाले प्रश्न

क्या मैं बिना API key के किसी रणनीति का backtest कर सकता हूँ?

हाँ। quantjourney-bt में --sample-data फ्लैग के पीछे एक बंडल किया गया सैंपल डेटासेट होता है, और इसकी उदाहरण रणनीतियाँ बिना किसी अकाउंट या क्रेडेंशियल के उस पर चल सकती हैं। यह डेटासेट छोटा और केवल समझाने के उद्देश्य से है, इसलिए इसे रणनीति के प्रमाण के बजाय केवल इंस्टॉलेशन और पाइपलाइन की जांच के रूप में देखें।

Python backtesting पैकेज के वर्ज़न को पिन क्यों करें?

0.x वर्ज़न वाले पैकेज में माइनर रिलीज़ के बीच अनुकूलता (compatibility) की कोई गारंटी नहीं होती है, और डिफ़ॉल्ट सेटिंग्स में बदलाव या किसी मेट्रिक का नाम बदलने पर इसकी सूचना नहीं मिलती है। pip install quantjourney-bt==0.12.4 के साथ पिन करने और requirements फ़ाइल में एनवायरनमेंट को रिकॉर्ड करने का मतलब है कि आज जो परिणाम आप प्राप्त करते हैं, उसे अगले वर्ष उसी इंजन पर दोबारा बनाया जा सकता है जिसने उसे तैयार किया था।

quantjourney-bt किस लाइसेंस के तहत जारी किया गया है?

Apache License 2.0। यह व्यावसायिक उपयोग और संशोधन की अनुमति देता है, यह शर्त रखता है कि आप किसी भी पुनर्वितरण (redistribution) के साथ लाइसेंस और नोटिस फ़ाइलों को सुरक्षित रखें, और इसमें योगदानकर्ताओं की ओर से स्पष्ट पेटेंट अनुदान शामिल है। वर्ज़न 0.12.4 को 21 जुलाई 2026 को प्रकाशित किया गया था और इसके लिए Python 3.11 या उससे नए वर्ज़न की आवश्यकता है।

क्या एक मजबूत backtest परिणाम का मतलब है कि रणनीति काम करती है?

नहीं। backtest एक समय-सीमा पर, एक यूनिवर्स में किया गया केवल एक मापन है। ऊपर दिए गए पैनल दिखाते हैं कि एक ही अपरिवर्तित नियम एक ticker पर बहुत अलग वार्षिक आंकड़े और पाँच नामों के बीच बहुत अलग आंकड़े दे सकता है। यही वह अंतर है जिसे walk-forward validation और out-of-sample टेस्टिंग उजागर करने के लिए बनाई गई हैं।

ऊपर दिए गए पैनलों की गणना कैसे की गई

दैनिक क्लोज (daily closes) प्रत्येक तिथि के लिए नियमित सत्र के अंतिम मिनट का प्रिंट है, जिसे न्यूयॉर्क के समय के अनुसार सुबह 9:30 बजे से शाम 4:00 बजे के बीच लिया गया है। यह सत्र की अवधि को हार्डकोड किए बिना आधे दिन के सत्रों को सही रखता है। तेज़ औसत (fast average) 20 सत्रों को और धीमा औसत (slow average) 50 सत्रों को कवर करता है, दोनों ही simple हैं, और प्रत्येक सीरीज़ के पहले 49 सत्र वार्म-अप हैं जिनमें कोई पोजीशन नहीं ली जाती है। वार्षिक आंकड़े उन सत्रों के लिए प्रत्येक सत्र के क्लोज-टू-क्लोज मूव को कंपाउंड करते हैं जिनमें नियम 'long' था, और 'hold' कॉलम तुलना के लिए उसी वर्ष के प्रत्येक सत्र को कंपाउंड करता है। क्रॉस-सेक्शन में पाँच नामों को निरंतर इतिहास के लिए चुना गया था जिनमें विंडो के भीतर कोई स्प्लिट नहीं हुआ, इसलिए क्लोज सीरीज़ में किसी समायोजन की आवश्यकता नहीं है। विंडो अतीत में निश्चित हैं, इसलिए ये पैनल हर बार रीजेनरेशन पर समान संख्याएँ दिखाते हैं।


यहाँ प्रत्येक पैनल के नीचे सटीक SQL मौजूद है, जो इस पेज पर दी गई संख्याओं को उतना ही दोबारा चलाने योग्य (re-runnable) बनाता है जितना कि पिन किया गया इंस्टॉलेशन है। कोई भी backtest कोड लिखने से पहले अपनी विंडो पर किसी नियम को मापने के लिए, Strasmore टर्मिनल पर सादी अंग्रेजी में प्रश्न पूछें।

#backtesting#python#open source#reproducibility#quantjourney