كان الملهمون وراء تطوير خدمة الإحصاء لشركة Tinkoff Investments هم:
- مقال عن Habré “ما لا تقوله Tinkoff Investments”
- تحليل رغبات مستخدمي المنصة
- مقال عن حساب العمولات .
- ما الذي سيتم مناقشته؟
- تطوير خدمة إحصائية خطوة بخطوة:
- الاتصال بواجهة برمجة تطبيقات Tinkoff Invest
- رسم البيانات من Tinkoff Invest API في متصفح
- استلام تقارير ومعاملات الوساطة
- GetBrokerReport
- طريقة الحصول على التاريخ مع مراعاة الطرح من التاريخ الحالي
- طلب إنشاء التقرير
- نتيجة:
- GetDividendsForeignIssuer
- GetOperationsByCursor
- حساب وإخراج المعلومات ذات الأهمية
- التعامل مع الأسعار
- تكلفة العقود الآجلة
- سوق خارج البورصة
- العمليات الحسابية على الأدوات
- Microservice جاهز!
- استنتاجات وخطط للمستقبل
- https://opexbot.info
ما الذي سيتم مناقشته؟
- فقط الجزء التطبيقي حول التنمية.
- المعرفة والخبرة الحقيقية ، وهما أمران مهمان للغاية في التعامل مع الأدوات المالية.
- نظرة عامة على القضايا للعمل عليها
لذلك ، أريد حساب إحصاءات التجارة والقيام بذلك بطريقة مريحة.
تطوير خدمة إحصائية خطوة بخطوة:
- الاتصال بواجهة برمجة تطبيقات Tinkoff Invest
- رسم البيانات من Tinkoff Invest API في متصفح
- استلام تقارير ومعاملات الوساطة
- حساب وإخراج المعلومات ذات الأهمية
- استنتاجات وخطط للمستقبل
الاتصال بواجهة برمجة تطبيقات Tinkoff Invest
للاتصال بواجهة برمجة التطبيقات ، يمكنك أخذ أي SDK من الوثائق https://github.com/Tinkoff/investAPI#sdk . أو حزمة npm “ tinkoff-sdk-grpc-js ”. من المهم أن يتم تحديث الحزمة إلى أحدث إصدار بواسطة المطورين. ثَبَّتَ
npm أنا tinkoff-sdk-grpc-js
تدقيق
const {createSdk} = تتطلب (‘tinkoff-sdk-grpc-js’) ؛ // الرمز الذي يمكن الحصول عليه مثل هذا الرمز المميز = ‘YOURAPI’ ؛ // اسم التطبيق الذي يمكنك من خلاله العثور على سجلات TCS. const appName = ‘tcsstat’ ؛ const sdk = createSdk (رمز مميز ، اسم التطبيق) ؛ (async () => { console.log (await sdk.users.getAccounts ()) ؛ }) () ؛
النتيجة: سيتم عرض قائمة بحساباتك في وحدة التحكم. على سبيل المثال ، دعنا نحلل الفروق الدقيقة:
- يوجد في قائمة الحسابات “بنك استثماري” لا يمكنك العمل معه باستخدام واجهة برمجة التطبيقات
- يرجى ملاحظة أن الحقول تأتي في شكل camelCase ، بينما في التوثيق يتم تقديم هذه الحقول في under_score.
- سيكون الأمر كذلك في كل مكان ، لذا لا يمكنك أخذ ونسخ حقل من الوثائق.
مفيد:
- يمكنك العثور على هذا الرمز في فرع المشروع
https://github.com/pskucherov/tcsstat/tree/step1 https://github.com/pskucherov/tcsstat/compare/step1
رسم البيانات من Tinkoff Invest API في متصفح
أخذت next.js و socket.io. هذه ليست توصية قوية ، اختر حسب تقديرك.
npx create-next-app @ latest npm i socket.io socket.io-client
ننتقل على الفور إلى خطوة الصداقة التالية + المقبس + الاستثمار ، ونرى القسم المفيد من هذه الخطوة للحصول على جميع التفاصيل. سأصف التفاصيل:
- على جانب nodejs (الخادم) ، يوجد ملف pages / api / Investapi.js. هذا هو المكان الذي نقوم فيه بإنشاء خادم socket.io والاتصال بـ Investapi.
- من ناحية المتصفح (العميل) ، نقوم بالاتصال بالخادم عبر مقبس ونطلب بيانات الحساب من الوسيط.
- نتلقى البيانات من الوسيط على الخادم ، ثم نرسلها إلى العميل. عندما يتم استلامها على العميل ، يتم عرضها في المتصفح.
النتيجة: في وحدة تحكم المتصفح يمكننا رؤية معلومات حول الحسابات. أي ، في الخطوة الأخيرة ، رأينا معلومات حول الحسابات في وحدة تحكم الخادم (nodejs) ، في الخطوة الحالية ، قمنا بنقل هذه المعلومات إلى العميل (المتصفح).
الآن دعنا نجعلها بحيث يمكنك تحديد حساب من المتصفح ، وإذا لم يكن هناك رمز مميز ، فسيتم إرسال خطأ إلى وحدة التحكم. العمل بسيط وليس جديدًا ، لذلك أعطي فقط روابط للالتزامات
- 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 ، والحصول على TaskId ردًا. بعد ذلك ، باستخدام معرف المهمة هذا ، نحصل على بيانات من get _broker_report_response.
- تحتاج إلى حفظ TaskID إلى الأبد بالضبط لهذه التواريخ.
- نظرًا لأنه في حالة فقده ، فسيأتي التقرير أولاً في التواريخ المطلوبة استجابة لطلب الإنشاء ،
- وبعد ذلك لن يأتي على الإطلاق.
[/ spoiler] لنبدأ في كتابة التعليمات البرمجية
طريقة الحصول على التاريخ مع مراعاة الطرح من التاريخ الحالي
const getDateSubDay = (subDay = 5، start = true) => { const date = new Date ()؛ date.setUTCDate (date.getUTCDate () – subDay) ؛ إذا (ابدأ) { date.setUTCHours (0، 0، 0، 0) ؛ } else { date.setUTCHours (23، 59، 59، 999) ؛ } تاريخ العودة؛ } ؛
طلب إنشاء التقرير
const brokerReport = await (sdk.operations.getBrokerReport) ({ createBrokerReportRequest: { accountId، from، to، }، })؛
نتيجة:
- نتيجة للتنفيذ الأول للأمر ، نحصل على معرف المهمة.
- يبدأ إنشاء التقرير من جانب الوسيط. عندما يكون جاهزًا غير معروف ، ننتظر ونقوم بسحب المهمة بشكل دوري تحسبا للتقرير.
- لماذا؟ لأنه إذا لم يكن التقرير جاهزًا ، فسيظهر خطأ. إذا لم يكن التقرير جاهزًا من جانب الوسيط ، فهذا خطأ في الكود الخاص بك. الرجاء معالجة: 30058 | INVALID_ARGUMENT | المهمة لم تكتمل بعد ، يرجى المحاولة مرة أخرى لاحقًا
يبدو رمز انتظار واستلام التقرير شيئًا كهذا.
const timer = async time => { return new Promise (حل => setTimeout (حل ، الوقت)) ؛ } const getBrokerResponseByTaskId = async (taskId، page = 0) => { try { return await (sdk.operations.getBrokerReport) ({ getBrokerReportRequest: { taskId، page، }، })؛ } catch (e) { console.log (‘wait’، e)؛ انتظار مؤقت (10000) ؛ return await getBrokerResponseByTaskId (معرف مهمة ، صفحة) ؛ } }؛
ثم يحدث نفس السحر. نوقف البرنامج النصي الخاص بنا ، ونبدأه مرة أخرى ، ليس لدينا معرّف مهمة. نقوم بتنفيذ الكود مع طلب taskId ، لكننا لم نعد نحصل على معرف المهمة ، ولكننا نحصل على التقرير فورًا. سحر! وكل شيء سيكون على ما يرام إذا كان دائمًا على هذا النحو. لكن في غضون شهر لن تكون هناك بيانات على الإطلاق. مفيد :
https://github.com/pskucherov/tcsstat/tree/step3.1 https://github.com/pskucherov/tcsstat/compare/step3.1
- إذا واجه شخص ما هذا ، فمرحبا بكم في هذه القضية . بعد إصلاح هذا السحر ، سوف يفقد قوته وسيكون مختلفًا إلى حد ما. لكن في الوقت الحالي (03/21/2023) يعمل بنفس الطريقة.
GetDividendsForeignIssuer
قد يعتقد شخص ما أن الطريقة مشابهة للطريقة السابقة ويمكنك استخدام طريقة واحدة تقوم فيها فقط بتغيير اسم العمليات. لكنهم لم يخمنوا! التسمية هناك مختلفة تمامًا في كل من الأساليب والمعلومات التي يتم إرجاعها. ويبدأ عدد الصفحات من 0 ، ثم من 1. حتى لا يتم الخلط بين كل هذا ، فمن الأسهل كتابة طريقتين مختلفتين. وهو أمر غريب لأن منطق العمل هو نفسه. لقد بصقت لفترة طويلة عندما حاولت إنشاء طريقة واحدة وكان هناك رمز أقل. لن تكون هناك أمثلة هنا.
GetOperationsByCursor
المفضل لدي من الثلاثة وإن لم يكن الأكثر دقة ، ولكن الأكثر ملاءمة. نحن نقدم طلبًا من بداية إنشاء الحساب إلى أقصى تاريخ ممكن (إغلاق حساب أو إغلاق الحساب الحالي). نحصل على الإجابة ، نأخذ المؤشر ونعيد الطلب طالما أن هناك بيانات. والشفرة أكثر إيجازًا مما في الأمثلة أعلاه.
const timer = async time => { return new Promise (حل => setTimeout (حل ، الوقت)) ؛ } const getOperationsByCursor = async (sdk، accountId، from، to، cursor = ”) => { try { const reqData = { accountId، from، to، limit: 1000، state: sdk.OperationState.OPERATION_STATE_EXECUTED، withoutCommissions: false، بدون الصفقات: false، withoutOvernights: false، cursor، } ؛ return await sdk.operations.getOperationsByCursor (reqData) ؛ } catch (e) { await timer (60000)؛ العودة في انتظار getOperationsByCursor (sdk، accountId، from، to، cursor = ”) ؛ } }؛
المسودة المراد تشغيلها هنا: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 الآن نحن جاهزون لإضافة عمليات الاستلام إلى تطبيقنا. إذا تم القيام به بشكل صحيح ، فأنت بحاجة إلى الحصول على تقارير السمسرة لوجود الحساب بالكامل. وبالنسبة للبيانات المفقودة ، نفس T-3s ، إعادة التحميل من العمليات. لكن هذا يمكن فصله إلى مقال منفصل. من الفروق الدقيقة التي ستواجهها هي عمليات الغراء وتقرير السمسرة.
- إذا تلقيت اليوم تقرير وساطة ومعاملات للتواريخ المطلوبة ، ضع كل ذلك في قاعدة البيانات ، فلا توجد مشاكل.
- ستواجه مشاكل غدًا عندما تتلقى الجزء التالي من البيانات من التقرير والعمليات وتقرر مزامنتها مع قاعدة البيانات الحالية.
- الكثير من الفروق الدقيقة حول الهوية غير المتطابقة أو المتغيرة بعد المعالجة
- ثم بالنسبة لسوق OTC ، فإن المعرف لا يتطابق على الإطلاق.
- بالإضافة إلى الفروق الدقيقة في أدوات المزامنة ، والتي لا تتطابق مرة أخرى ، نظرًا لخصائص واجهة برمجة التطبيقات. لكن هذه قصة أخرى.
دعنا نضيف الحصول على معلومات حول العمليات إلى تطبيقنا. سيكون السؤال الرئيسي هو المكان الذي ستتم فيه معالجة البيانات وتخزينها.
- إذا قمت بذلك بنفسك ، فسوف تستهلك نفس البيانات من أجهزة مختلفة. ثم تحتاج إلى معالجة البيانات وتخزينها على الخادم.
- إذا كان لديك الكثير من البيانات المختلفة التي يستهلكها العديد من المستخدمين المختلفين ، فأنت بحاجة إلى تحديد ما هو أكثر أهمية: سرعة المستخدمين أو توفير الحديد من جانبك. كل من يستطيع تحمل كمية لا حصر لها من الأجهزة يحسب كل شيء على خادمه ويجعله سريعًا للغاية للمستخدمين ، مما يوفر موارد المستخدم ، مثل البطارية وحركة المرور ، وهو أمر مهم جدًا على الهواتف.
في المقابل ، لا يعد العد في المتصفح هو الحل الأمثل من حيث المبدأ. لذلك ، ما هو غير مكلف ، نعتبره على خادمنا. نترك الباقي للعميل. أريد حقًا أخذ العمولة وحسابها على الخادم. ولكن هنا يأتي فارق بسيط يسمى “التفاعل”. لنفترض أن لديك آلاف العمليات وأن الأمر يستغرق خمس دقائق لاستلامها. ماذا سيكون لدى المستخدم في هذا الوقت؟ سبينر؟ تقدم؟ INFA حول كم تم تحميله؟ من المثالي استخدام “الانتظار النشط” عندما يرى المستخدم شيئًا بالفعل في العملية. ها هي النتيجة:
- تحميل الصفحة
- جميع الفواتير مطلوبة
- بعد ذلك ، يتم طلب جميع المعاملات مع العمولات على المعاملات المنفذة لجميع الحسابات. عند استلام البيانات ، يتم عرضها في المتصفح.
من أجل عدم تصفية البيانات في الأحداث في كل مرة ، نقوم بسحب الحدث الخاص بنا لكل حساب. مثله:
socket.emit (‘sdk: getOperationsCommissionResult_’ + accountId، { items: data؟ .items، inProgress: Boolean (nextCursor)، })؛
المسودة التي سيتم إطلاقها هنا: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 الانتقال. من الرائع أنك قرأت هذا السطر!
حساب وإخراج المعلومات ذات الأهمية
يعتمد على من يحتاج إلى أي معلومات. لذلك ، أخبرك على الفور بالفروق الدقيقة الرئيسية التي ستواجهها.
التعامل مع الأسعار
يعرف كل من يعمل في الشؤون المالية أن المعاملات المالية يجب أن تتم فقط بأرقام صحيحة. بسبب عدم دقة القيم بعد الفاصلة العشرية والخطأ التراكمي مع عدد كبير من العمليات. هذا هو السبب في تقديم جميع الأسعار بتنسيق MoneyValue التالي
مجال | يكتب | وصف |
---|---|---|
عملة | خيط | سلسلة كود العملة ISO |
الوحدات | int64 | يمكن أن يكون الجزء الصحيح من المجموع عددًا سالبًا |
نانو | int32 | يمكن أن يكون الجزء الكسري من المبلغ عددًا سالبًا |
نقوم بمعالجتها بشكل منفصل ، ثم نأتي بها إلى قيمة السعر:
وحدات الاقتباس + الاقتباس. نانو / 1e9
تكلفة العقود الآجلة
يتم عرض سعر العقود الآجلة بالنقاط ، عندما يكون لديك عملة مستقبلية ، فأنت بحاجة إلى معرفة السعر. وبالطبع السعر بالنقاط وخطوة السعر. عندما تحسب الربح من المعاملات ، يمكن أن يحدث ذلك ، لأن. إذا قمت بحساب المبلغ الإجمالي بضرب السعر في الكمية. هنا عليك أن تكون حذرا. في الوقت الحالي ، سنرى كيف ستسير الأمور. هذا ينطبق على العقود الآجلة للعملة ، وفي أماكن أخرى كل شيء على ما يرام مع هذا.
سوق خارج البورصة
يحتوي هذا السوق على الكثير من الخصائص المميزة ، لذلك دعونا ندرس العمليات عليه بشكل منفصل.عند بدء عمليات المزامنة ، سوف يتضح أنك بحاجة إلى إحضار الشكل / المؤشر إلى نفس الشكل من أجل مطابقة الأداة بشكل صحيح. عندما تبدأ في مزامنة هذا مع تقرير السمسرة ، سيتضح أن معرف التجارة لنفس المعاملة يحتوي على أحرف في البداية في المعاملات وليست موجودة في تقرير الوساطة. لذلك ، لا يمكن مقارنتها … ahem-ahem … بالمقارنة! لقد قمت بمطابقة وقت التداول والمؤشر والمطابقة مع معرف تداول واحد موجود في آخر. صحيح ، لا أعلم. من يواجه هذا ومن يهتم به ، تعال إلى المشكلة أو ابدأ مشكلة جديدة.
العمليات الحسابية على الأدوات
من المستحيل ، دون النظر ، إجراء عمليات حسابية مع القائمة بأكملها. حتى لا نضيف الدفء إلى اللين ، نقوم دائمًا بفحص العملة والمعالجة فقط إذا كنا متأكدين من تطابق العملة ، ويتم تحويل النقاط إلى العملة المطلوبة. مسلحين بالمعرفة حول التعامل مع أرقام البنوك ، سنقوم بحساب العمولة التي يتم إنفاقها على كل حساب. مثل هذا: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4
Microservice جاهز!
https://github.com/pskucherov/tcsstat كواجب منزلي ، يمكنك التحقق مما إذا كانت الخدمة تعمل باتصال بطيء ، عند انقطاع الاتصالات ، عند قطع الاتصال بالإنترنت ، عند حدوث أخطاء أو انتهاء صلاحية الحدود من جانب الوسيط.
استنتاجات وخطط للمستقبل
- تعرفت على العمليات الأساسية والعمل مع Invest API
- قضى الوقت ~ 10 ساعات
- مستوى الصعوبة ~ مبتدئ + / متوسط منخفض
إذا واصلت تحسين الخدمة المصغرة ، فقد ينتهي بك الأمر بشيء من هذا القبيل
https://opexbot.info
هذا هو تطوري ، لأولئك الذين هم كسالى للغاية بحيث لا يمكنهم الفهم والركض والاعتماد على أنفسهم. أخطط لإضافة تحليلات هناك بناءً على طلب المستخدمين. إذا أعجبك المقال ، فقم بالاشتراك في قناة Telegram الخاصة بي .
Полезная статья. Не могу представить, сколько усилий автора потребовалось, чтобы все описать. Благодарю.