Wir entwickeln einen Microservice mit der Tinkoff Invest API, um die Arbeit mit Maklerberichten und die Berechnung von Provisionen zu automatisieren.

Программирование

Die Inspiratoren hinter der Entwicklung des Statistikdienstes für Tinkoff Investments waren:

Was wird besprochen?

  • Nur der angewandte Teil über die Entwicklung.
  • Echtes Wissen und Erfahrung, die bei der Arbeit mit Finanzinstrumenten sehr wichtig sind.
  • Überblick über die zu bearbeitenden Themen

Ich möchte also Handelsstatistiken berechnen und dies auf bequeme Weise tun. 

Entwicklung eines Statistikdienstes Schritt für Schritt: 

  1. Verbindung zur Tinkoff Invest-API
  2. Zeichnen von Daten aus der Tinkoff Invest API in einem Browser
  3. Empfangen von Maklerberichten und -transaktionen
  4. Berechnung und Ausgabe von interessanten Informationen
  5. Schlussfolgerungen und Pläne für die Zukunft

Verbindung zur Tinkoff Invest-API

Um sich mit der API zu verbinden, können Sie ein beliebiges SDK aus der Dokumentation https://github.com/Tinkoff/investAPI#sdk nehmen . Oder npm-Paket ` tinkoff-sdk-grpc-js `. Es ist wichtig, dass das Paket von den Entwicklern auf die neueste Version aktualisiert wird. Installieren

npm und tinkoff-sdk-grpc-js

Überprüfung

const { createSdk } = require(‚tinkoff-sdk-grpc-js‘);   // Token, das so erhalten werden kann   const TOKEN = ‚YOURAPI‘;   // Der Name der Anwendung, unter der Sie in den TCS-Protokollen gefunden werden können. const appName = ‚tcsstat‘;   const sdk = createSdk (TOKEN, AppName); (async() => {     console.log(await sdk.users.getAccounts()); })();

Ergebnis: Eine Liste Ihrer Konten wird in der Konsole angezeigt. Analysieren wir zum Beispiel die Nuancen:Wir entwickeln einen Microservice mit der Tinkoff Invest API, um die Arbeit mit Maklerberichten und die Berechnung von Provisionen zu automatisieren.

  • In der Liste der Konten gibt es eine „Investmentbank“, mit der Sie nicht über die API arbeiten können
  • Bitte beachten Sie, dass die Felder in camelCase kommen, während diese Felder in der Dokumentation in under_score dargestellt werden. 
  • Das wird überall so sein, man kann also nicht einfach ein Feld aus der Dokumentation nehmen und kopieren.

Nützlich:

  • Sie finden diesen Code im Projektzweig

https://github.com/pskucherov/tcsstat/tree/step1 https://github.com/pskucherov/tcsstat/compare/step1   

Zeichnen von Daten aus der Tinkoff Invest API in einem Browser

Ich habe next.js und socket.io genommen. Dies ist keine starke Empfehlung, wählen Sie nach eigenem Ermessen. 

npx create-next-app@latest npm i socket.io socket.io-client

Wir fahren sofort mit dem Freundschaftsschritt next+socket+investapi fort und sehen uns den nützlichen Abschnitt dieses Schrittes für alle Details an.  Ich beschreibe die Details: 

  • Auf der Seite von nodejs (Server) gibt es eine Datei pages/api/investapi.js. Hier erstellen wir den socket.io-Server und verbinden uns mit investapi.
  • Auf der Browser- (Client-) Seite verbinden wir uns über einen Socket mit dem Server und fordern Kontodaten vom Broker an. 
  • Wir empfangen Daten vom Broker auf dem Server und senden sie dann an den Client. Wenn sie auf dem Client empfangen werden, werden sie im Browser angezeigt. 

Ergebnis:  In der Browserkonsole können wir Informationen zu Konten sehen. Das heißt, im letzten Schritt haben wir Informationen zu Konten in der Serverkonsole (nodejs) gesehen, im aktuellen Schritt haben wir diese Informationen an den Client (Browser) übertragen.

Wir entwickeln einen Microservice mit der Tinkoff Invest API, um die Arbeit mit Maklerberichten und die Berechnung von Provisionen zu automatisieren.

Machen wir es jetzt so, dass Sie ein Konto aus dem Browser auswählen können, und wenn kein Token vorhanden ist, wird ein Fehler an die Konsole gesendet. Die Arbeit ist einfach und nichts Neues, daher gebe ich nur Links zu Commits

  1. https://github.com/pskucherov/tcsstat/commit/7e1ac57061e5e971588479015b06d8814d6609a9
  2. https://github.com/pskucherov/tcsstat/commit/b28ac973a57494f5232589b4cb6b9fb13b8af759 

Nützlich:

https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 Wem obiges schwerfällt, dem bleiben wir an dieser Stelle und beschäftigen uns mit dem Code. Wenn Sie Fragen haben – fragen Sie. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2

Empfangen von Maklerberichten und -transaktionen

Es gibt drei Methoden , um Maklerberichte und Transaktionen zu erhalten

  1. GetBrokerReport
  2. GetDividendsForeignIssuer
  3. GetOperationsByCursor

Von Anfang an ist es wichtig zu wissen: 

  • Der Maklerbericht wird im T-3-Modus erstellt, d. h. Trades werden dort nach ihrer tatsächlichen Ausführung angezeigt. 
  • Wenn Sie diesen Bericht also für die letzten zwei Tage anfordern, wird er in drei Tagen fertig sein. 
  • Um Transaktionen für die letzten Tage zu erhalten, verwenden wir die Methode zum Empfangen von Transaktionen, aber denken Sie daran, dass sich ihre ID und ihr Inhalt ändern können, nachdem der Maklerbericht erstellt wurde.

GetBrokerReport

Um einen Maklerbericht zu erhalten, müssen Sie die Konto-ID, das Startdatum und das Enddatum des Berichts angeben, jedoch nicht mehr als 31 Tage. Wir senden eine Anforderung zum Generieren eines Berichts an die API in generate _broker_report_request und erhalten als Antwort eine taskId. Danach erhalten wir unter Verwendung dieser taskId Daten von get _broker_report_response.

So sagt die Dokumentation, in Wirklichkeit gibt es Nuancen. Pass auf deine Hände auf:

  • Genau für diese Daten müssen Sie die TaskID für immer speichern. 
  • Denn wenn Sie es verlieren, kommt der Bericht für die angeforderten Daten zuerst als Antwort auf die Generierungsanforderung. 
  • Und dann kommt es gar nicht.

Fangen wir an, Code zu schreiben

Methode zum Erhalten des Datums unter Berücksichtigung der Subtraktion vom aktuellen Datum

const getDateSubDay = (subDay = 5, start = true) => {     const date = new Date();     date.setUTCDate(date.getUTCDate() – subDay);       if (Start) {         date.setUTCHours (0, 0, 0, 0);     } sonst {         date.setUTCHours (23, 59, 59, 999);     }       Rückgabedatum; };

Anfrage zur Berichterstellung 

const brokerReport = await (sdk.operations.getBrokerReport)({         generateBrokerReportRequest: {             accountId,             from,             to,         }, });

Ergebnis:

  • Als Ergebnis der ersten Ausführung des Befehls erhalten wir die taskId. 
  • Der Bericht wird auf der Maklerseite generiert. Wann es fertig ist, ist unbekannt, wir warten und ziehen regelmäßig die taskId in Erwartung des Berichts.
  • Warum? Denn wenn der Bericht nicht fertig ist, wirft er einen Fehler. Wenn der Bericht auf Seiten des Maklers nicht fertig ist, dann ist dies ein Fehler in Ihrem Code. Bitte verarbeiten: 30058|INVALID_ARGUMENT|Aufgabe noch nicht abgeschlossen, bitte versuchen Sie es später erneut

Der Code zum Warten und Empfangen eines Berichts sieht in etwa so aus.

const timer = async time => {     return new Promise(resolve => setTimeout(resolve, time)); }   const getBrokerResponseByTaskId = async (taskId, page = 0) => {     try {         return await (sdk.operations.getBrokerReport) ({             getBrokerReportRequest: {                 taskId,                 page,             },         });     } catch (e) {         console.log(‚wait‘, e);         Wartetimer (10000);         return await getBrokerResponseByTaskId(taskId, page);     } };

Dann geschieht die gleiche Magie. Wir stoppen unser Skript, starten es erneut, wir haben keine taskId. Wir führen den Code mit dem taskId-Request aus, bekommen aber nicht mehr die taskId, sondern gleich den Report. Magie! Und alles wäre gut, wenn es immer so wäre. Aber in einem Monat wird es überhaupt keine Daten mehr geben. Nützlich :

  • Ein bisschen Theorie wird hier und hier skizziert .
  • Wenn Sie den Code zusammensetzen, sieht der Entwurf in etwa so aus.

https://github.com/pskucherov/tcsstat/tree/step3.1 https://github.com/pskucherov/tcsstat/compare/step3.1

  • Wenn jemand darauf stößt, dann willkommen zum Thema . Nachdem sie diese Magie repariert haben, wird sie ihre Kraft verlieren und irgendwie anders sein. Aber zum jetzigen Zeitpunkt (21.03.2023) funktioniert es einfach so.

GetDividendsForeignIssuer

Jemand könnte denken, dass die Methode der vorherigen ähnlich ist und Sie eine einzige Methode verwenden können, bei der Sie nur den Namen der Operationen ändern. Aber sie haben es nicht erraten!  Die dortige Benennung ist sowohl in den Methoden als auch in den zurückgelieferten Informationen sehr unterschiedlich. Und die Seitenzählung beginnt bei 0, dann bei 1. Um bei all dem nicht durcheinander zu kommen, ist es einfacher, zwei verschiedene Methoden zu schreiben. Was seltsam ist, weil Die Logik der Arbeit ist die gleiche. Ich habe lange gespuckt, als ich versucht habe, eine Methode zu erstellen, und es gab weniger Code. Hier wird es keine Beispiele geben.

GetOperationsByCursor

Mein Favorit der drei. Zwar nicht die genaueste, aber die adäquateste. Wir stellen eine Anfrage vom Beginn der Erstellung eines Kontos bis zum maximal möglichen Datum (Schließung eines Kontos oder des aktuellen Kontos). Wir erhalten die Antwort, nehmen den Cursor und fordern erneut an, solange Daten vorhanden sind.  Und der Code ist prägnanter als in den obigen Beispielen.

const timer = async time => {     return new Promise(resolve => setTimeout(resolve, time)); }   const getOperationsByCursor = async (sdk, accountId, from, to, cursor = “) => {     try {         const reqData = {             accountId,             from,             to,             limit: 1000,             state: sdk.OperationState.OPERATION_STATE_EXECUTED,             withoutCommissions: false,             withoutTrades: false,             withoutOvernights: false,             Cursor,         };           Rückkehr Erwartung sdk.operations.getOperationsByCursor(reqData);     } catch (e) {         warte auf den Timer (60000);         return await getOperationsByCursor(sdk, accountId, from, to, cursor = “);     } };

Der auszuführende Entwurf ist hier: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 Jetzt können wir Empfangsvorgänge hinzufügen unsere Bewerbung. Wenn Sie es richtig gemacht haben, müssen Sie Maklerberichte für die gesamte Existenz des Kontos erhalten. Und für die fehlenden Daten laden die gleichen T-3s aus dem Betrieb neu. Dies kann jedoch in einen separaten Artikel unterteilt werden. Zu den wichtigsten Nuancen, denen Sie begegnen werden, gehören das Kleben von Vorgängen und ein Maklerbericht.

  •  Wenn Sie heute einen Maklerbericht und Transaktionen für die erforderlichen Daten erhalten haben, geben Sie alles in die Datenbank ein, dann gibt es keine Probleme. 
  • Sie werden morgen Probleme haben, wenn Sie den nächsten Teil der Daten aus dem Bericht und den Vorgängen erhalten und sich entscheiden, sie mit der vorhandenen Datenbank zu synchronisieren. 
  • Viele Nuancen über nicht übereinstimmende oder sich ändernde IDs nach der Verarbeitung
  • Dann stimmen die IDs für den OTC-Markt überhaupt nicht überein.
  •  Sowie die Nuancen der Synchronisierung von Instrumenten, die aufgrund der Besonderheiten der API wiederum nicht übereinstimmen. Aber das ist eine andere Geschichte.

Lassen Sie uns unserer Anwendung das Abrufen von Informationen über Operationen hinzufügen. Die Hauptfrage wird sein, wo die Daten verarbeitet und gespeichert werden.

  •  Wenn Sie es für sich selbst tun, verbrauchen Sie dieselben Daten von verschiedenen Geräten. Dann müssen Sie Daten auf dem Server verarbeiten und speichern.
  • Wenn Sie viele unterschiedliche Daten von vielen verschiedenen Benutzern verbrauchen, müssen Sie entscheiden, was wichtiger ist: die Geschwindigkeit der Benutzer oder die Einsparung von Eisen auf Ihrer Seite. Wer sich unendlich viel Hardware leisten kann, zählt alles auf seinem Server und macht es für die Benutzer superschnell, wodurch die Benutzerressourcen wie Akku und Datenverkehr gespart werden, was bei Telefonen sehr wichtig ist.

Das Zählen im Browser wiederum ist prinzipiell nicht die optimalste Lösung. Was nicht teuer ist, betrachten wir daher auf unserem Server. Den Rest überlassen wir dem Kunden. Ich möchte wirklich die Provision auf dem Server nehmen und berechnen. Aber hier kommt die Nuance namens „Interaktivität“. Angenommen, Sie haben Tausende von Vorgängen und es dauert fünf Minuten, sie zu erhalten. Was wird der Benutzer zu diesem Zeitpunkt haben? Spinner? Fortschritt? Infa darüber, wie viel hochgeladen wurde? Ideal ist das „aktive Warten“, wenn der Benutzer im Prozess schon etwas sehen konnte. Hier ist das Ergebnis:Wir entwickeln einen Microservice mit der Tinkoff Invest API, um die Arbeit mit Maklerberichten und die Berechnung von Provisionen zu automatisieren.

  • Seite wird geladen
  • Alle Rechnungen werden angefordert
  • Danach werden alle Transaktionen mit Provisionen für ausgeführte Transaktionen für alle Konten angefordert. Wenn Daten empfangen werden, werden sie im Browser gerendert.

Um die Daten in den Ereignissen nicht jedes Mal zu filtern, ziehen wir für jedes Konto ein eigenes Ereignis. So:

socket.emit(’sdk:getOperationsCommissionResult_‘ + accountId, {                 items: data?.items,                 inProgress: Boolean(nextCursor), });

Der Entwurf zum Starten ist hier: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Weiter geht’s. Schön, dass du diese Zeile gelesen hast! 

Berechnung und Ausgabe von interessanten Informationen

Je nachdem, wer welche Informationen benötigt. Deshalb sage ich Ihnen sofort die wichtigsten Nuancen, denen Sie begegnen werden.

Arbeiten mit Preisen 

Jeder, der mit Finanzen zu tun hat, weiß, dass Geldtransaktionen nur mit ganzen Zahlen durchgeführt werden sollten. Aufgrund der Ungenauigkeit der Werte nach dem Komma und des kumulativen Fehlers bei einer großen Anzahl von Operationen. Aus diesem Grund werden alle Preise im folgenden MoneyValue- Format dargestelltWir entwickeln einen Microservice mit der Tinkoff Invest API, um die Arbeit mit Maklerberichten und die Berechnung von Provisionen zu automatisieren.

Feld Typ Beschreibung
Währung Schnur String ISO-Währungscode
Einheiten int64 Ganzzahliger Teil der Summe, kann eine negative Zahl sein
nano int32 Bruchteil des Betrags, kann eine negative Zahl sein

Wir verarbeiten sie separat und bringen sie dann auf den Preiswert:

Angebot.Einheiten + Angebot.Nano / 1e9

Die Kosten von Terminkontrakten

Der Preis von Futures wird in Punkten angegeben, wenn Sie einen Währungs-Future haben, müssen Sie den Kurs kennen. Und natürlich der Preis in Punkten und die Preisstufe. Wenn Sie den Gewinn aus Transaktionen berechnen, kann dies schießen, weil. wenn Sie den Gesamtbetrag berechnen, indem Sie den Preis mit der Menge multiplizieren. Hier müssen Sie vorsichtig sein. Jetzt werden wir sehen, wie es weitergeht. Dies gilt für Devisentermingeschäfte, an anderen Stellen ist damit alles in Ordnung.Wir entwickeln einen Microservice mit der Tinkoff Invest API, um die Arbeit mit Maklerberichten und die Berechnung von Provisionen zu automatisieren. Wir entwickeln einen Microservice mit der Tinkoff Invest API, um die Arbeit mit Maklerberichten und die Berechnung von Provisionen zu automatisieren.

OTC-Markt

Dieser Markt hat viele Besonderheiten, also lassen Sie uns die Operationen darauf separat untersuchen.Wenn Sie mit der Synchronisierung der Operationen beginnen, wird sich herausstellen, dass Sie Figi / Ticker auf die gleiche Form bringen müssen, um das Instrument korrekt abzugleichen. Wenn Sie beginnen, dies mit dem Maklerbericht zu synchronisieren, stellt sich heraus, dass die TradeID derselben Transaktion in den Transaktionen Buchstaben am Anfang hat und sie nicht im Maklerbericht stehen. Daher können sie nicht verglichen werden … ähm-ähm … im Vergleich! Ich habe die Handelszeit, den Ticker und den Abgleich darauf abgestimmt, dass eine TradeId in einer anderen enthalten ist. Stimmt, ich weiß es nicht. Wer darauf stößt und sich darum kümmert, kommt zum Thema oder fängt ein neues an.Wir entwickeln einen Microservice mit der Tinkoff Invest API, um die Arbeit mit Maklerberichten und die Berechnung von Provisionen zu automatisieren.

Mathematische Operationen an Werkzeugen

Es ist unmöglich, mathematische Operationen mit der gesamten Liste durchzuführen, ohne hinzusehen. Um nicht warm zu weich zu addieren, prüfen wir immer die Währung und verarbeiten nur, wenn wir sicher sind, dass die Währung übereinstimmt und die Punkte in die gewünschte Währung umgerechnet werden. Ausgestattet mit dem Wissen über die Arbeit mit Banknummern berechnen wir die für jedes Konto ausgegebene Provision. So: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4Wir entwickeln einen Microservice mit der Tinkoff Invest API, um die Arbeit mit Maklerberichten und die Berechnung von Provisionen zu automatisieren.    

Microservice ist fertig!

https://github.com/pskucherov/tcsstat Als Hausaufgabe kann man prüfen, ob der Dienst bei langsamer Verbindung, bei Verbindungsabbrüchen, bei unterbrochener Internetverbindung, bei Fehlern oder abgelaufenen Limits seitens des Brokers funktioniert. 

Schlussfolgerungen und Pläne für die Zukunft

  • Sie haben etwas über grundlegende Vorgänge und die Arbeit mit der Invest-API gelernt
  • Zeitaufwand ~ 10 Stunden
  • Schwierigkeitsgrad ~ Junior+ / niedriges Mittel 

Wenn Sie den Microservice weiter verfeinern, erhalten Sie möglicherweise so etwas

https://opexbot.info

  Dies ist meine Entwicklung für diejenigen, die zu faul sind, um zu verstehen, zu laufen und alleine zu zählen. Ich plane, dort auf Wunsch der Benutzer Analysen hinzuzufügen. Wenn dir der Artikel gefallen hat, dann abonniere meinen Telegrammkanal . Wir entwickeln einen Microservice mit der Tinkoff Invest API, um die Arbeit mit Maklerberichten und die Berechnung von Provisionen zu automatisieren.

Pavel
Rate author
Add a comment

  1. Isakiiev

    Полезная статья. Не могу представить, сколько усилий автора потребовалось, чтобы все описать. Благодарю.

    Antworten