Tinkoff Investments के लिए सांख्यिकी सेवा के विकास के प्रेरक थे:
- हैबे पर लेख “टिंकॉफ इन्वेस्टमेंट्स क्या नहीं कह रहे हैं”
- मंच उपयोगकर्ताओं की इच्छाओं का विश्लेषण
- कमीशन की गणना के बारे में एक लेख ।
- क्या चर्चा होगी?
- चरण दर चरण एक सांख्यिकी सेवा का विकास करना:
- Tinkoff Invest API से कनेक्शन
- किसी ब्राउज़र में Tinkoff Invest API से डेटा आरेखित करना
- ब्रोकरेज रिपोर्ट और लेनदेन प्राप्त करना
- GetBrokerReport
- तिथि प्राप्त करने की विधि, वर्तमान तिथि से घटाव को ध्यान में रखते हुए
- रिपोर्ट जनरेशन अनुरोध
- परिणाम:
- लाभांश विदेशी जारीकर्ता प्राप्त करें
- GetOperationsByCursor
- ब्याज की जानकारी की गणना और आउटपुट
- कीमतों के साथ काम करना
- वायदा अनुबंधों की लागत
- ओटीसी बाजार
- उपकरणों पर गणितीय संचालन
- माइक्रोसर्विस तैयार है!
- निष्कर्ष और भविष्य के लिए योजनाएं
- https://opexbot.info
क्या चर्चा होगी?
- विकास के बारे में केवल लागू हिस्सा।
- वास्तविक ज्ञान और अनुभव, जो वित्तीय साधनों के साथ काम करने में बहुत महत्वपूर्ण हैं।
- काम करने के लिए मुद्दों का अवलोकन
इसलिए, मैं व्यापार आंकड़ों की गणना करना चाहता हूं और इसे सुविधाजनक तरीके से करना चाहता हूं।
चरण दर चरण एक सांख्यिकी सेवा का विकास करना:
- Tinkoff Invest API से कनेक्शन
- किसी ब्राउज़र में Tinkoff Invest API से डेटा आरेखित करना
- ब्रोकरेज रिपोर्ट और लेनदेन प्राप्त करना
- ब्याज की जानकारी की गणना और आउटपुट
- निष्कर्ष और भविष्य के लिए योजनाएं
Tinkoff Invest API से कनेक्शन
एपीआई से कनेक्ट करने के लिए, आप प्रलेखन https://github.com/Tinkoff/investAPI#sdk से कोई भी एसडीके ले सकते हैं । या एनपीएम पैकेज ‘ टिंकऑफ-एसडीके-जीआरपीसी-जेएस ‘। यह महत्वपूर्ण है कि डेवलपर्स द्वारा पैकेज को नवीनतम संस्करण में अपडेट किया जाए। स्थापित करना
एनपीएम और टिंकऑफ़-एसडीके-जीआरपीसी-जेएस
चेकिंग
const { createSdk } = आवश्यकता (‘टिंकऑफ-एसडीके-जीआरपीसी-जेएस’); // टोकन जो इस तरह प्राप्त किया जा सकता है const TOKEN = ‘YOURAPI’; // एप्लिकेशन का नाम जिसके द्वारा आप टीसीएस लॉग में पाए जा सकते हैं। const appName = ‘tcsstat’; const sdk = createSdk (टोकन, ऐपनाम); (async () => { कंसोल.लॉग (sdk.users.getAccounts () की प्रतीक्षा करें); })();
परिणाम: आपके खातों की एक सूची कंसोल में प्रदर्शित की जाएगी। उदाहरण के लिए, आइए बारीकियों का विश्लेषण करें:
- खातों की सूची में एक “निवेश बैंक” है, जिसके साथ आप एपीआई का उपयोग करके काम नहीं कर सकते
- कृपया ध्यान दें कि फ़ील्ड कैमलकेस में आते हैं, जबकि दस्तावेज़ीकरण में ये फ़ील्ड अंडर_स्कोर में प्रस्तुत किए जाते हैं।
- यह हर जगह ऐसा ही होगा, इसलिए आप दस्तावेज़ीकरण से किसी फ़ील्ड को ले और कॉपी नहीं कर सकते।
उपयोगी:
- आप इस कोड को प्रोजेक्ट शाखा में पा सकते हैं
https://github.com/pskucherov/tcsstat/tree/step1 https://github.com/pskucherov/tcsstat/compare/step1
किसी ब्राउज़र में Tinkoff Invest API से डेटा आरेखित करना
मैंने अगला.जेएस और सॉकेट.आईओ लिया। यह एक मजबूत सिफारिश नहीं है, अपने विवेकानुसार चुनें।
npx create-next-app@latest npm और socket.io socket.io-client
हम तुरंत फ्रेंडशिप स्टेप नेक्स्ट+सॉकेट+इन्वेस्टैपी पर आगे बढ़ते हैं, और सभी विवरणों के लिए इस चरण का उपयोगी खंड देखते हैं। मैं विवरण का वर्णन करूंगा:
- नोडज (सर्वर) की ओर, एक पेज/एपीआई/निवेशपी.जेएस फ़ाइल है। यहीं पर हम socket.io सर्वर बनाते हैं और Investapi से जुड़ते हैं।
- ब्राउज़र (क्लाइंट) की तरफ, हम एक सॉकेट के माध्यम से सर्वर से जुड़ते हैं और ब्रोकर से खाता डेटा का अनुरोध करते हैं।
- हम सर्वर पर ब्रोकर से डेटा प्राप्त करते हैं, फिर उसे क्लाइंट को भेजते हैं। जब वे क्लाइंट पर प्राप्त होते हैं, तो वे ब्राउज़र में प्रदर्शित होते हैं।
परिणाम: ब्राउज़र कंसोल में हम खातों के बारे में जानकारी देख सकते हैं। अर्थात्, अंतिम चरण में, हमने सर्वर कंसोल (नोडज) में खातों के बारे में जानकारी देखी, वर्तमान चरण में, हमने इस जानकारी को क्लाइंट (ब्राउज़र) में स्थानांतरित कर दिया।
अब इसे बनाते हैं ताकि आप ब्राउज़र से एक खाते का चयन कर सकें, और यदि कोई टोकन नहीं है, तो कंसोल पर एक त्रुटि भेजी जाती है। काम सरल है और कुछ भी नया नहीं है, इसलिए मैं केवल कमिट करने के लिए लिंक देता हूं
- https://github.com/pskucherov/tcsstat/commit/7e1ac57061e5e971588479015b06d8814d6609a9
- https://github.com/pskucherov/tcsstat/commit/b28ac973a57494f5232589b4cb6b9fb13b8af759
उपयोगी:
- दोस्तों को आगे कैसे बनाया जाए और सॉकेट को यहां विस्तार से वर्णित किया गया है ।
- मैत्री कोड अगला + सॉकेट + निवेश:
https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 जिनके लिए उपरोक्त कठिन है, तो हम इस स्तर पर रहते हैं और कोड से निपटते हैं। यदि आपके कोई प्रश्न हैं – पूछें। https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2
ब्रोकरेज रिपोर्ट और लेनदेन प्राप्त करना
ब्रोकरेज रिपोर्ट और लेन-देन प्राप्त करने के तीन तरीके हैं
शुरू से ही यह जानना जरूरी है कि:
- ब्रोकरेज रिपोर्ट T-3 मोड में उत्पन्न होती है, अर्थात। ट्रेडों को उनके वास्तविक निष्पादन के बाद वहां प्रदर्शित किया जाता है।
- इस हिसाब से अगर आप पिछले दो दिनों की इस रिपोर्ट का अनुरोध करते हैं, तो यह तीन दिनों में तैयार हो जाएगी।
- अंतिम दिनों के लेन-देन प्राप्त करने के लिए, हम लेन-देन प्राप्त करने की विधि का उपयोग करते हैं, लेकिन याद रखें कि ब्रोकरेज रिपोर्ट उत्पन्न होने के बाद उनकी आईडी और सामग्री बदल सकती है।
GetBrokerReport
ब्रोकरेज रिपोर्ट प्राप्त करने के लिए, आपको खाता आईडी, आरंभ तिथि और रिपोर्ट की समाप्ति तिथि लेने की आवश्यकता है, लेकिन 31 दिनों से अधिक नहीं। हम _broker_report_request जनरेट करने के लिए API को एक रिपोर्ट जनरेट करने का अनुरोध भेजते हैं , प्रतिक्रिया में एक टास्कआईड प्राप्त करते हैं। उसके बाद, इस टास्कआईड का उपयोग करके, हम _broker_report_response से डेटा प्राप्त करते हैं । [स्पॉइलर शीर्षक = “तो प्रलेखन कहता है, वास्तव में बारीकियाँ हैं। अपने हाथ देखें:”]
- आपको इन तिथियों के लिए टास्कआईडी को हमेशा के लिए सहेजना होगा।
- चूंकि यदि आप इसे खो देते हैं, तो अनुरोधित तिथियों के लिए रिपोर्ट सबसे पहले जनरेशन अनुरोध के जवाब में आएगी,
- और फिर यह बिल्कुल नहीं आएगा।
[/स्पॉइलर] चलिए कोड लिखना शुरू करते हैं
तिथि प्राप्त करने की विधि, वर्तमान तिथि से घटाव को ध्यान में रखते हुए
const getDateSubDay = (सबडे = 5, प्रारंभ = सत्य) => { const दिनांक = नई तिथि (); date.setUTCDate(date.getUTCDate() – सबडे); अगर (प्रारंभ) { date.setUTCHours (0, 0, 0, 0); } और { date.setUTCHours (23, 59, 59, 999); } वापसी की तारीख; };
रिपोर्ट जनरेशन अनुरोध
const BrokerReport = प्रतीक्षा (sdk.operations.getBrokerReport) ({ जेनरेटब्रोकररिपोर्ट: { खाता आईडी, से, से, }, });
परिणाम:
- कमांड के पहले निष्पादन के परिणामस्वरूप, हमें टास्कआईड मिलता है।
- ब्रोकर की तरफ से रिपोर्ट तैयार होने लगती है। जब यह तैयार हो जाता है अज्ञात है, हम प्रतीक्षा करते हैं और समय-समय पर टास्कआईड को रिपोर्ट की प्रत्याशा में खींचते हैं।
- क्यों? क्योंकि अगर रिपोर्ट तैयार नहीं है, यह एक त्रुटि फेंकता है। यदि ब्रोकर की ओर से रिपोर्ट तैयार नहीं है, तो यह आपके कोड में त्रुटि है। कृपया संसाधित करें: 30058|INVALID_ARGUMENT|कार्य अभी तक पूरा नहीं हुआ है, कृपया बाद में पुनः प्रयास करें
प्रतीक्षा करने और रिपोर्ट प्राप्त करने का कोड कुछ इस तरह दिखता है।
const टाइमर = async समय => { नया वादा वापस करें (संकल्प => सेटटाइमआउट (संकल्प, समय)); } const getBrokerResponseByTaskId = async (taskId, पृष्ठ = 0) => { कोशिश करें { वापसी का इंतजार (sdk.operations.getBrokerReport)({ getBrokerReportRequest: { taskId, page, }, }); } पकड़ (ई) { कंसोल.लॉग (‘प्रतीक्षा’, ई); टाइमर का इंतजार (10000); वापसी का इंतजार getBrokerResponseByTaskId (टास्कआईड, पेज); } };
फिर वही जादू होता है। हम अपनी स्क्रिप्ट को रोकते हैं, इसे फिर से शुरू करते हैं, हमारे पास टास्कआईड नहीं है। हम टास्कआईड अनुरोध के साथ कोड निष्पादित करते हैं, लेकिन अब हमें टास्कआईड नहीं मिलता है, लेकिन तुरंत रिपोर्ट मिलती है। जादू! और सब कुछ ठीक होता अगर हमेशा ऐसा ही होता। लेकिन एक महीने में कोई डेटा नहीं होगा। उपयोगी :
https://github.com/pskucherov/tcsstat/tree/step3.1 https://github.com/pskucherov/tcsstat/compare/step3.1
- अगर किसी के सामने यह आता है, तो इस मुद्दे पर आपका स्वागत है । जब वे इस जादू को दुरुस्त कर लेंगे, तो यह अपनी शक्ति खो देगा और किसी तरह अलग हो जाएगा। लेकिन वर्तमान समय में (03/21/2023) यह ऐसे ही काम करता है।
लाभांश विदेशी जारीकर्ता प्राप्त करें
कोई सोच सकता है कि विधि पिछले एक के समान है और आप एक ही विधि का उपयोग कर सकते हैं जिसमें आप केवल संचालन का नाम बदलते हैं। लेकिन उन्होंने अनुमान नहीं लगाया! विधियों और दी गई जानकारी दोनों में नामकरण बहुत अलग है। और पृष्ठ संख्या 0 से शुरू होती है, फिर 1 से। इस सब में भ्रमित न होने के लिए, दो अलग-अलग तरीकों को लिखना आसान है। जो अजीब है, क्योंकि कार्य का तर्क समान है। जब मैंने एक तरीका बनाने की कोशिश की और कम कोड था तो मैं लंबे समय तक थूकता रहा। यहां कोई उदाहरण नहीं होगा।
GetOperationsByCursor
तीनों में से मेरा पसंदीदा। हालांकि सबसे सटीक नहीं, लेकिन सबसे पर्याप्त। हम एक खाता बनाने की शुरुआत से अधिकतम संभव तिथि (खाता बंद करने या वर्तमान एक) से अनुरोध करते हैं। हमें उत्तर मिलता है, कर्सर लें और जब तक डेटा है तब तक पुनः अनुरोध करें। और उपरोक्त उदाहरणों की तुलना में कोड अधिक संक्षिप्त है।
const टाइमर = async समय => { नया वादा वापस करें (संकल्प => सेटटाइमआउट (संकल्प, समय)); } const getOperationsByCursor = async (sdk, accountId, from, to, कर्सर = ”) => { try { const reqData = { accountId, from, to, limit: 1000, state: sdk.OperationState.OPERATION_STATE_EXECUTED, withoutCommissions: false, बिना ट्रेड्स: झूठा, बिना ओवरनाइट्स: झूठा, कर्सर, }; वापसी प्रतीक्षा sdk.operations.getOperationsByCursor (reqData); } कैच (ई) { प्रतीक्षा टाइमर (60000); वापसी प्रतीक्षा getOperationsByCursor (एसडीके, खाता आईडी, से, से, कर्सर = ”); } };
चलाने के लिए मसौदा यहां है: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 अब हम प्राप्त करने के संचालन को जोड़ने के लिए तैयार हैं हमारा आवेदन। यदि सही ढंग से किया जाता है, तो आपको खाते के संपूर्ण अस्तित्व के लिए ब्रोकरेज रिपोर्ट प्राप्त करने की आवश्यकता होती है। और लापता डेटा के लिए, वही T-3s, संचालन से पुनः लोड होते हैं। लेकिन इसे एक अलग लेख में अलग किया जा सकता है। आप जिन मुख्य बारीकियों का सामना करेंगे उनमें से संचालन और ब्रोकरेज रिपोर्ट को गोंद करना है।
- यदि आज आपको आवश्यक तिथियों के लिए ब्रोकरेज रिपोर्ट और लेन-देन प्राप्त हुआ है, तो इसे डेटाबेस में डाल दें, तो कोई समस्या नहीं है।
- जब आप रिपोर्ट और संचालन से डेटा का अगला भाग प्राप्त करते हैं और उन्हें मौजूदा डेटाबेस के साथ सिंक्रनाइज़ करने का निर्णय लेते हैं, तो आपको कल समस्याएँ होंगी।
- प्रसंस्करण के बाद बेमेल या आईडी बदलने के बारे में बहुत सारी बारीकियाँ
- फिर ओटीसी बाजार के लिए, आईडी बिल्कुल मेल नहीं खाती।
- साथ ही उपकरणों को सिंक्रनाइज़ करने की बारीकियां, जो एपीआई की ख़ासियत के कारण फिर से मेल नहीं खाती हैं। लेकिन वो दूसरी कहानी है।
आइए हमारे आवेदन में संचालन के बारे में जानकारी प्राप्त करना जोड़ें। मुख्य प्रश्न यह होगा कि डेटा को संसाधित और संग्रहीत कहाँ किया जाएगा।
- यदि आप इसे अपने लिए करते हैं, तो आप विभिन्न उपकरणों से समान डेटा का उपभोग करेंगे। फिर आपको सर्वर पर डेटा को प्रोसेस और स्टोर करने की आवश्यकता है।
- यदि आपके पास कई अलग-अलग उपयोगकर्ताओं द्वारा उपयोग किए जाने वाले बहुत से अलग-अलग डेटा हैं, तो आपको यह तय करने की आवश्यकता है कि क्या अधिक महत्वपूर्ण है: उपयोगकर्ताओं की गति या आपके पक्ष में लोहे की बचत। जो कोई भी असीमित मात्रा में हार्डवेयर खरीद सकता है, वह अपने सर्वर पर सब कुछ गिनता है और इसे उपयोगकर्ताओं के लिए सुपर फास्ट बनाता है, उपयोगकर्ता संसाधनों, जैसे बैटरी और ट्रैफ़िक को बचाता है, जो फोन पर बहुत महत्वपूर्ण है।
बदले में, ब्राउज़र में गिनती सिद्धांत रूप में सबसे इष्टतम समाधान नहीं है। इसलिए जो महंगा नहीं है, उसे हम अपने सर्वर पर मानते हैं। बाकी हम ग्राहक पर छोड़ देते हैं। मैं वास्तव में सर्वर पर कमीशन लेना और उसकी गणना करना चाहता हूं। लेकिन यहाँ “अंतरक्रियाशीलता” नामक अति सूक्ष्म अंतर आता है। मान लीजिए कि आपके पास हजारों ऑपरेशन हैं और उन्हें प्राप्त करने में पांच मिनट लगते हैं। इस समय उपयोगकर्ता के पास क्या होगा? स्पिनर? प्रगति? कितना अपलोड किया गया था इसके बारे में जानकारी? “सक्रिय प्रतीक्षा” का उपयोग करना आदर्श है जब प्रक्रिया में उपयोगकर्ता पहले से ही कुछ देख सकता है। यहाँ परिणाम है:
- पृष्ठ लोड हो रहा है
- सभी चालान मांगे गए हैं
- उसके बाद, निष्पादित लेनदेन के लिए कमीशन के साथ सभी लेनदेन सभी खातों के लिए अनुरोध किए जाते हैं। जैसे ही डेटा प्राप्त होता है, इसे ब्राउज़र में प्रस्तुत किया जाता है।
प्रत्येक बार ईवेंट में डेटा को फ़िल्टर न करने के लिए, हम प्रत्येक खाते के लिए अपना स्वयं का ईवेंट निकालते हैं। इस कदर:
सॉकेट.एमिट (‘sdk: getOperationsCommissionResult_’ + accountId, { आइटम: डेटा? .आइटम, इनप्रोग्रेस: बूलियन (अगला कर्सर), });
लॉन्च करने का मसौदा यहां है: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 आगे बढ़ना। यह बहुत अच्छा है कि आपने यह पंक्ति पढ़ी है!
ब्याज की जानकारी की गणना और आउटपुट
यह इस बात पर निर्भर करता है कि किसे किस जानकारी की आवश्यकता है। इसलिए, मैं आपको तुरंत उन मुख्य बारीकियों के बारे में बताता हूं जिनका आप सामना करेंगे।
कीमतों के साथ काम करना
वित्त के साथ काम करने वाला प्रत्येक व्यक्ति जानता है कि धन का लेन-देन केवल पूर्ण संख्याओं के साथ ही किया जाना चाहिए। बड़ी संख्या में संचालन के साथ दशमलव बिंदु और संचयी त्रुटि के बाद मूल्यों की अशुद्धि के कारण। यही कारण है कि सभी कीमतों को निम्नलिखित मनीवैल्यू प्रारूप में प्रस्तुत किया गया है
मैदान | प्रकार | विवरण |
---|---|---|
मुद्रा | डोरी | स्ट्रिंग आईएसओ मुद्रा कोड |
इकाइयां | int64 | योग का पूर्णांक भाग, एक ऋणात्मक संख्या हो सकती है |
नैनो | int32 | राशि का आंशिक भाग, एक ऋणात्मक संख्या हो सकती है |
हम उन्हें अलग से प्रोसेस करते हैं, फिर उन्हें मूल्य मूल्य पर लाते हैं:
कोटेशन.यूनिट + कोटेशन.नैनो / 1e9
वायदा अनुबंधों की लागत
फ़्यूचर्स की कीमत अंकों में प्रस्तुत की जाती है, जब आपके पास करेंसी फ़्यूचर होता है, तो आपको दर जानने की आवश्यकता होती है। और निश्चित रूप से पॉइंट्स में कीमत और प्राइस स्टेप। जब आप लेन-देन से लाभ की गणना करते हैं, तो यह गोली मार सकता है, क्योंकि। यदि आप मूल्य को मात्रा से गुणा करके कुल राशि की गणना करते हैं। यहां आपको सावधान रहने की जरूरत है। अभी के लिए, हम देखेंगे कि यह कैसे जाता है। यह करेंसी फ्यूचर्स पर लागू होता है, अन्य जगहों पर इसके साथ सब कुछ ठीक है।
ओटीसी बाजार
इस बाजार में बहुत सारी विशिष्टताएँ हैं, इसलिए आइए इस पर अलग-अलग संचालन का अध्ययन करें। जब आप संचालन को सिंक्रनाइज़ करना शुरू करते हैं, तो यह पता चलेगा कि उपकरण को सही ढंग से मिलान करने के लिए आपको उसी रूप में फिगी / टिकर लाने की आवश्यकता है। जब आप ब्रोकरेज रिपोर्ट के साथ इसे सिंक्रोनाइज करना शुरू करते हैं, तो यह पता चलेगा कि उसी लेनदेन के ट्रेड आईडी में लेनदेन की शुरुआत में अक्षर हैं और वे ब्रोकरेज रिपोर्ट में नहीं हैं। इसलिए उनकी तुलना नहीं की जा सकती… अहम-अहम… तुलना करके! मैं व्यापार समय, टिकर और मिलान से मेल खाता हूं कि एक व्यापार आईडी दूसरे में निहित है। ठीक है, मुझे नहीं पता। जो कोई भी इसका सामना करता है और जो इसकी परवाह करता है, मुद्दे पर आएं या एक नई शुरुआत करें।
उपकरणों पर गणितीय संचालन
बिना देखे, पूरी सूची के साथ गणितीय संक्रियाएं करना असंभव है। नरम में गर्म न जोड़ने के लिए, हम हमेशा मुद्रा की जांच करते हैं और केवल तभी प्रक्रिया करते हैं जब हम सुनिश्चित हों कि मुद्रा मेल खाती है, और अंक वांछित मुद्रा में परिवर्तित हो जाते हैं। बैंक नंबरों के साथ काम करने के बारे में ज्ञान से लैस, हम प्रत्येक खाते पर खर्च किए गए कमीशन की गणना करेंगे। इस तरह: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4
माइक्रोसर्विस तैयार है!
https://github.com/pskucherov/tcsstat एक होमवर्क के रूप में, आप जांच सकते हैं कि क्या सेवा धीमे कनेक्शन के साथ काम करती है, जब कनेक्शन टूट जाते हैं, जब इंटरनेट डिस्कनेक्ट हो जाता है, जब ब्रोकर की ओर से त्रुटियां या समय सीमा समाप्त हो जाती है।
निष्कर्ष और भविष्य के लिए योजनाएं
- बुनियादी संचालन और इन्वेस्ट एपीआई के साथ काम करने के बारे में सीखा
- समय बिताया ~ 10 घंटे
- कठिनाई स्तर ~ जूनियर + / निम्न मध्यम
यदि आप माइक्रोसेवा को परिष्कृत करना जारी रखते हैं, तो आप कुछ इस तरह से समाप्त हो सकते हैं
https://opexbot.info
यह मेरा विकास है, उन लोगों के लिए जो अपने दम पर समझने, दौड़ने और गिनने में बहुत आलसी हैं। मैं उपयोगकर्ताओं के अनुरोध पर वहां एनालिटिक्स जोड़ने की योजना बना रहा हूं। अगर आपको लेख पसंद आया हो तो मेरे टेलीग्राम चैनल को सब्सक्राइब करें ।
Полезная статья. Не могу представить, сколько усилий автора потребовалось, чтобы все описать. Благодарю.