कैंडल की रेंज का हिसाब जानते हैं: high - low। कई गणनाओं में चाहिए तो अपना फ़ंक्शन बना सकते हैं। कॉल से गणना का उद्देश्य दिखेगा और सूत्र एक जगह रहेगा।

फ़ंक्शन का इनपुट और नतीजा

def price_range(top: float, bottom: float) -> float:
    return top - bottom

def फ़ंक्शन परिभाषित करता है। नाम price_range है। top और bottom दो इनपुट चाहिए। दोनों दशमलव सहित नंबर हो सकते हैं।

-> float नतीजे का टाइप है। return गणना का नतीजा लौटाकर उस कॉल को समाप्त करता है।

price_range(105, 100) का नतीजा 5 है। फ़ंक्शन नहीं जानता कि ये कीमतें हैं और न कैंडल चुनता है। कॉल करने वाला दोनों वैल्यू देता है।

बॉडी चार स्पेस अंदर है। यहाँ परिभाषा main() के साथ फ़ाइल के सबसे बाहरी स्तर पर है। इसलिए दोनों कीमत पैरामीटर में देते हैं। फ़ंक्शन main() के भीतर भी बना सकते हैं; नीचे देखेंगे।

नाम का स्कोप

top और bottom केवल price_range में उपलब्ध पैरामीटर हैं। main() सीधे नहीं पढ़ सकता। वहाँ लौटा नतीजा लेते हैं।

स्कोप बताता है कि नाम कोड के किस हिस्से में उपलब्ध है। अलग फ़ंक्शन समान पैरामीटर नाम ले सकते हैं, बिना एक साझा वेरिएबल बने।

बाहरी स्तर का price_range अपने आप main() के स्थानीय वेरिएबल नहीं देखता। फ़ाइल की शुरुआत में इंपोर्ट close जैसे नाम ले सकता है। उपलब्धता पर परिभाषा की जगह का भी असर है।

परिभाषा और कॉल अलग हैं। परिभाषा नियम बताती है; कॉल उसे तय वैल्यू से चलाती है।

पूरा प्रोग्राम

price_functions.py बनाएँ। वही फ़ंक्शन पूरी कैंडल रेंज और ओपन से क्लोज़ का चिह्न सहित बदलाव निकालता है:

"""
@pyne edge
"""
from pynecore.lib import close, color, high, low, open, plot, script


def price_range(top: float, bottom: float) -> float:
    return top - bottom


@script.indicator("Price Functions", overlay=False)
def main():
    full_range = price_range(high, low)
    body_change = price_range(close, open)
    plot(full_range, "Full range", color=color.blue)
    plot(body_change, "Body change", color=color.orange)

डेमो पर चलाएँ। पूरी रेंज ऋणात्मक नहीं, क्योंकि हाई लो से कम नहीं। ओपन-क्लोज़ बदलाव ऋणात्मक हो सकता है। फ़ंक्शन कीमत नहीं बदलता; दो नंबर का अंतर देता है।

price_functions.py के दो कॉल पूरी कैंडल रेंज और चिह्न सहित बॉडी बदलाव दिखाते हैं।
वही अपना फ़ंक्शन अलग इनपुट से दो अलग नतीजे निकालता है।

यह फ़ंक्शन छोटा और हाथ से जाँचने योग्य है। बड़े प्रोग्राम में जटिल उपकामों को भी नाम दे सकते हैं, लेकिन हर जोड़ का अलग फ़ंक्शन बनाना ज़रूरी नहीं।

पैरामीटर का क्रम

price_range(high, low) में high, top को और low, bottom को जाता है। उलटने पर घटाव का चिह्न भी उलटेगा।

पैरामीटर का नाम भी दे सकते हैं:

full_range = price_range(top=high, bottom=low)

लंबा है, लेकिन जटिल कॉल में पढ़ना आसान कर सकता है। नाम परिभाषा वाले पैरामीटर से ठीक मिलना चाहिए।

main() के भीतर फ़ंक्शन

अंदर बना फ़ंक्शन आसपास के फ़ंक्शन के वेरिएबल पढ़ सकता है। कई गणनाएँ वही इनपुट सेटिंग लें तो उपयोगी है।

पिछले प्रोग्राम की दोनों लाइन मूविंग एवरेज से चिकनी करें। एक इनपुट में लंबाई दें और दोनों में वही लें। अंदर के फ़ंक्शन को केवल दो कीमत देंगे; लंबाई main() के पैरामीटर से मिलेगी।

price_functions.py में बाहर का price_range और इंडिकेटर डेकोरेटर रखें। pynecore.lib में input और ta जोड़ें; main() की परिभाषा इससे बदलें:

def main(
    length: int = input.int(5, title="Average length", minval=1, maxval=200),
):
    def average_difference(top: float, bottom: float) -> float:
        return ta.sma(price_range(top, bottom), length)

    average_range = average_difference(high, low)
    average_body_change = average_difference(close, open)
    plot(average_range, "Average range", color=color.blue)
    plot(average_body_change, "Average body change", color=color.orange)

length पहले वाला पूर्णांक इनपुट है। अंदर के average_difference को top और bottom कॉल से मिलते हैं। length आसपास के main() से पढ़ता है, इसलिए कॉल में दोबारा नहीं देना है।

अंदर की परिभाषा चार स्पेस से शुरू है क्योंकि main() का हिस्सा है। उसकी बॉडी की return लाइन आठ स्पेस से है। average_difference केवल main() में उपलब्ध है, फ़ाइल के बाहरी स्तर पर नहीं।

price_range कीमतों का अंतर निकालता है; ta.sma उसका मूविंग एवरेज। नीली लाइन कैंडल की पूरी रेंज का औसत और नारंगी ओपन-क्लोज़ के दिशात्मक बदलाव का औसत है। दोनों कॉल हर कैंडल पर हैं, इसलिए गणना लगातार है।

बदला प्रोग्राम चलाएँ और गियर से Inputs खोलें। Average length को 5 से 20 करके Save करें। खुला ग्राफ़ अपने आप दोबारा गणना करता है और दोनों लाइन बीस-कैंडल औसत बनती हैं। अंदर की दो कॉल नहीं बदलीं। लंबाई 1 करें तो मूल दोनों लाइन मिलती हैं।

बाहरी वेरिएबल तक इस पहुँच को क्लोज़र, अंग्रेज़ी में closure, कहते हैं। पढ़ सकना यह नहीं कि अंदर असाइनमेंट से अपने आप बाहरी वेरिएबल बदल सकते हैं। यहाँ केवल length पढ़ते हैं।

पैरामीटर वाले रूप में हर दी हुई वैल्यू कॉल में दिखती है और दूसरा कीमत-जोड़ा देना आसान है। अंदर का फ़ंक्शन तब सुविधाजनक है जब कई गणनाएँ main() के समान वेरिएबल पर बनती हैं।

अपने फ़ंक्शन का भी स्टेट हो सकता है

price_range केवल दिए हुए डेटा से गणना करता है। कैंडल के बीच बचने वाला वेरिएबल या हिस्ट्री नहीं है। इसलिए दो वैल्यू से कभी भी कॉल कर सकते हैं।

लेकिन average_difference स्टेट इस्तेमाल करता है, क्योंकि भीतर का ta.sma पुरानी वैल्यू लेता है। अपने फ़ंक्शन में सीधे Persistent या Series भी बना सकते हैं।

घटना गिनने वाला फ़ंक्शन

बढ़ती और गिरती कैंडल अलग गिनें। फ़ंक्शन लॉजिकल वैल्यू ले और याद रखे कि कितनी बार सत्य मिला है।

शुरुआत में Persistent इंपोर्ट करें:

from pynecore import Persistent

यह फ़ंक्शन main() से पहले बाहरी स्तर पर लिखें:

def count_events(event: bool) -> int:
    count: Persistent[int] = 0
    if event:
        count += 1
    return count

count शून्य से शुरू है। event सत्य हो तो एक बढ़ता है, वरना बचता है। return दोनों में अब तक का जोड़ देता है। कॉल समाप्त होने पर Persistent अगली कॉल के लिए बचा रहता है।

overlay=False रखें। main() की पुरानी परिभाषा और बॉडी इससे बदलें:

def main():
    bullish_count = count_events(close > open)
    bearish_count = count_events(close < open)
    plot(bullish_count, "Bullish count", color=color.green)
    plot(bearish_count, "Bearish count", color=color.red)

एक फ़ंक्शन दो अलग कोड स्थान से बुलाते हैं। हर कॉल स्थान का अलग count स्टेट है: पहला बढ़ती और दूसरा गिरती कैंडल गिनता है। पहली कॉल दूसरी का काउंटर नहीं बढ़ाती।

पहली चार कैंडल इस क्रम में हों तो नतीजे:

कैंडलओपन-क्लोज़ संबंधbullish_countbearish_count
पहलीक्लोज़ ऊपर10
दूसरीक्लोज़ नीचे11
तीसरीदोनों बराबर11
चौथीक्लोज़ ऊपर21

डेमो पर चलाएँ। हरी लाइन केवल बढ़ती और लाल केवल गिरती कैंडल पर एक बढ़ती है। नई रन दोनों को शून्य से बनाती है।

दोनों कॉल हर कैंडल पर हैं; बढ़ाने की शर्त अंदर है। स्टेट वाले फ़ंक्शन में कॉल का क्रम और आवृत्ति व्यवहार का हिस्सा हैं। केवल कुछ कैंडल पर बुलाएँ तो भीतर की हिस्ट्री केवल उन्हीं कॉल पर बढ़ेगी।

एक साझा काउंटर चाहिए तो एक बार कॉल करें और नतीजे का वेरिएबल कई जगह लें। दूसरी कॉल का स्थान नया स्वतंत्र काउंटर है।

फ़ंक्शन में कई निर्देश

बीच का नतीजा चाहिए तो return से पहले निकालें:

def midpoint(top: float, bottom: float) -> float:
    total = top + bottom
    return total / 2

total स्थानीय वेरिएबल है। कॉल खत्म होने पर main() का वेरिएबल नहीं बनता। केवल नतीजा लौटाया है।

स्वयं करके देखें

midpoint फ़ंक्शन जोड़ें और कैंडल की मध्य कीमत दिखाने वाला ओवरले इंडिकेटर बनाएँ। हाई और लो के लिए top और bottom लें।

अभ्यास का हल

ऊपर की midpoint परिभाषा main() से पहले रखें। डेकोरेटर में overlay=True और बॉडी में:

center = midpoint(high, low)
plot(center, "Midpoint", color=color.blue, linewidth=2)

पिछली दो लाइन की गणना और ड्रॉइंग इस रूप से हटा सकते हैं। अनावश्यक इंपोर्ट भी हटाएँ।

कॉल समझाएँ

price_range(close, open) में कौन-सी वैल्यू किस पैरामीटर में जाती है, return क्या करता है और main() को कहाँ नतीजा मिलता है, बताएँ। लंबी कॉल भी इन तीन चरणों से समझ सकते हैं।