Nous développons un microservice utilisant l’API Tinkoff Invest pour automatiser le travail avec les rapports de courtage et le calcul des commissions.

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

Les inspirateurs du développement du service de statistiques pour Tinkoff Investments étaient :

De quoi sera-t-il question ?

  • Seule la partie appliquée sur le développement.
  • Des connaissances et une expérience réelles, qui sont très importantes pour travailler avec des instruments financiers.
  • Tour d’horizon des problèmes sur lesquels travailler

Donc, je veux calculer les statistiques commerciales et le faire de manière pratique. 

Développer un service de statistiques étape par étape : 

  1. Connexion à l’API Tinkoff Invest
  2. Extraire des données de l’API Tinkoff Invest dans un navigateur
  3. Réception des rapports et des transactions de courtage
  4. Calcul et sortie des informations d’intérêt
  5. Conclusions et plans pour l’avenir

Connexion à l’API Tinkoff Invest

Pour vous connecter à l’API, vous pouvez prendre n’importe quel sdk de la documentation https://github.com/Tinkoff/investAPI#sdk . Ou le package npm ` tinkoff-sdk-grpc-js `. Il est important que le package soit mis à jour vers la dernière version par les développeurs. Installer

npm je tinkoff-sdk-grpc-js

Vérification

const { createSdk } = require(‘tinkoff-sdk-grpc-js’);   // Token qui peut être obtenu comme ceci  const TOKEN = ‘YOURAPI’;   // Le nom de l’application par laquelle vous pouvez être trouvé dans les journaux TCS. const appName = ‘tcsstat’ ;   const sdk = createSdk(TOKEN, appName); (async() => {     console.log(wait sdk.users.getAccounts()); })();

Résultat : une liste de vos comptes s’affichera dans la console. Par exemple, analysons les nuances:Nous développons un microservice utilisant l'API Tinkoff Invest pour automatiser le travail avec les rapports de courtage et le calcul des commissions.

  • Dans la liste des comptes, il y a une «banque d’investissement», avec laquelle vous ne pouvez pas travailler à l’aide de l’API
  • Veuillez noter que les champs sont en camelCase, alors que dans la documentation ces champs sont présentés en under_score. 
  • Ce sera comme ça partout, donc vous ne pouvez pas simplement prendre et copier un champ de la documentation.

Utile:

  • Vous pouvez trouver ce code dans la branche du projet

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

Extraire des données de l’API Tinkoff Invest dans un navigateur

J’ai pris next.js et socket.io. Ce n’est pas une recommandation forte, choisissez à votre discrétion. 

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

Nous passons immédiatement à l’étape d’amitié next+socket+investapi, et voyons la section Utile de cette étape pour tous les détails.  Je vais décrire les détails: 

  • Côté nodejs (serveur), il y a un fichier pages/api/investapi.js. C’est ici que nous créons le serveur socket.io et que nous nous connectons à investapi.
  • Du côté du navigateur (client), nous nous connectons au serveur via un socket et demandons les données de compte au courtier. 
  • Nous recevons des données du courtier sur le serveur, puis les envoyons au client. Lorsqu’ils sont reçus sur le client, ils sont affichés dans le navigateur. 

Résultat :  dans la console du navigateur, nous pouvons voir des informations sur les comptes. Autrement dit, à la dernière étape, nous avons vu des informations sur les comptes dans la console du serveur (nodejs), à l’étape actuelle, nous avons transféré ces informations au client (navigateur).

Nous développons un microservice utilisant l'API Tinkoff Invest pour automatiser le travail avec les rapports de courtage et le calcul des commissions.

Faisons maintenant en sorte que vous puissiez sélectionner un compte dans le navigateur, et s’il n’y a pas de jeton, une erreur est envoyée à la console. Le travail est simple et rien de nouveau, donc je ne donne que des liens vers des commits

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

Utile:

  • Comment se faire des amis ensuite et socket est décrit en détail ici
  • Code d’amitié next+socket+investapi :

https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 Pour qui ce qui précède est difficile, alors nous restons à ce stade et traitons le code. Si vous avez des questions – demandez. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2

Réception des rapports et des transactions de courtage

Il existe trois méthodes pour recevoir des rapports et des transactions de courtage

  1. GetBrokerReport
  2. GetDividendsForeignIssuer
  3. GetOperationsByCursor

Dès le début, il est important de savoir : 

  • Le rapport de courtage est généré en mode T-3, c’est-à-dire les transactions y sont affichées après leur exécution effective. 
  • Par conséquent, si vous demandez ce rapport pour les deux derniers jours, il sera prêt dans trois jours. 
  • Pour obtenir les transactions des derniers jours, nous utilisons la méthode de réception des transactions, mais n’oubliez pas que leur identifiant et leur contenu peuvent changer après la génération du rapport de courtage.

GetBrokerReport

Pour obtenir un rapport de courtage, vous devez prendre l’identifiant du compte, la date de début et la date de fin du rapport, mais pas plus de 31 jours. Nous envoyons une requête pour générer un rapport à l’API dans generate _broker_report_request , obtenons un taskId en réponse. Après cela, en utilisant ce taskId, nous obtenons des données de get _broker_report_response.

Donc la documentation dit, en réalité il y a des nuances. Attention à vos mains :

  • Vous devez enregistrer le TaskID pour toujours exactement pour ces dates. 
  • Puisque si vous le perdez, alors pour les dates demandées le rapport viendra d’abord en réponse à la demande de génération, 
  • Et puis ça ne viendra plus du tout.

Commençons à écrire du code

Méthode pour obtenir la date, en tenant compte de la soustraction de la date actuelle

const getDateSubDay = (subDay = 5, start = true) => {     const date = new Date();     date.setUTCDate(date.getUTCDate() – subDay);       si (début) {         date.setUTCHours(0, 0, 0, 0);     } else {         date.setUTCHours(23, 59, 59, 999);     }       date de retour ; } ;

Demande de génération de rapport 

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

Résultat:

  • À la suite de la première exécution de la commande, nous obtenons le taskId. 
  • Le rapport commence à être généré du côté du courtier. Quand il est prêt est inconnu, nous attendons et extrayons périodiquement le taskId en prévision du rapport.
  • Pourquoi? Parce que si le rapport n’est pas prêt, il génère une erreur. Si le rapport n’est pas prêt du côté du courtier, il s’agit d’une erreur dans votre code. Veuillez traiter : 30058|INVALID_ARGUMENT|la tâche n’est pas encore terminée, veuillez réessayer plus tard

Le code pour attendre et recevoir un rapport ressemble à ceci.

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

Puis la même magie opère. On arrête notre script, on le redémarre, on n’a pas de taskId. Nous exécutons le code avec la requête taskId, mais nous n’obtenons plus le taskId, mais immédiatement le rapport. La magie! Et tout irait bien si c’était toujours comme ça. Mais dans un mois, il n’y aura plus aucune donnée. Utile :

  • Un peu de théorie est décrite ici et ici .
  • En rassemblant le code, le brouillon ressemblera à ceci.

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

  • Si quelqu’un rencontre cela, alors bienvenue sur le problème . Après avoir réparé cette magie, elle perdra son pouvoir et sera quelque peu différente. Mais pour le moment (21/03/2023), cela fonctionne exactement comme ça.

GetDividendsForeignIssuer

Quelqu’un pourrait penser que la méthode est similaire à la précédente et vous pouvez utiliser une seule méthode dans laquelle vous ne modifiez que le nom des opérations. Mais ils n’ont pas deviné !  La dénomination y est très différente à la fois dans les méthodes et dans les informations renvoyées. Et le nombre de pages commence à partir de 0, puis de 1. Pour ne pas s’embrouiller dans tout ça, il est plus simple d’écrire deux méthodes différentes. Ce qui est étrange, car la logique du travail est la même. J’ai craché longtemps quand j’ai essayé de faire une méthode et qu’il y avait moins de code. Il n’y aura pas d’exemples ici.

GetOperationsByCursor

Mon préféré des trois. Bien que pas le plus précis, mais le plus adéquat. Nous faisons une demande dès le début de la création d’un compte jusqu’à la date maximale possible (fermeture d’un compte ou de celui en cours). Nous obtenons la réponse, prenons le curseur et redemandons tant qu’il y a des données.  Et le code est plus concis que dans les exemples ci-dessus.

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,             curseur,         } ;           return wait sdk.operations.getOperationsByCursor(reqData);     } attraper (e) {         attendre la minuterie (60000);         return wait getOperationsByCursor(sdk, accountId, de, à, curseur =  »);     } } ;

Le brouillon à exécuter est ici : https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 Nous sommes maintenant prêts à ajouter des opérations de réception à notre candidature. Si cela est fait correctement, vous devez obtenir des rapports de courtage pour toute l’existence du compte. Et pour les données manquantes, ces mêmes T-3, rechargez depuis les opérations. Mais cela peut être séparé dans un article séparé. L’une des principales nuances que vous rencontrerez consiste à coller des opérations et un rapport de courtage.

  •  Si aujourd’hui vous avez reçu un rapport de courtage et des transactions pour les dates requises, mettez tout cela dans la base de données, il n’y a aucun problème. 
  • Vous aurez des problèmes demain lorsque vous recevrez la prochaine portion de données du rapport et des opérations et déciderez de les synchroniser avec la base de données existante. 
  • Beaucoup de nuances à propos de l’incompatibilité ou de la modification de l’identifiant après le traitement
  • Ensuite, pour le marché OTC, les identifiants ne correspondent pas du tout.
  •  Ainsi que les nuances des instruments de synchronisation, qui encore une fois ne coïncident pas, en raison des particularités de l’API. Mais c’est une autre histoire.

Ajoutons l’obtention d’informations sur les opérations à notre application. La principale question sera de savoir où les données seront traitées et stockées.

  •  Si vous le faites vous-même, vous consommerez les mêmes données provenant de différents appareils. Ensuite, vous devez traiter et stocker les données sur le serveur.
  • Si vous avez beaucoup de données différentes consommées par de nombreux utilisateurs différents, vous devez décider ce qui est le plus important : la vitesse des utilisateurs ou l’économie de fer de votre côté. Quiconque peut se permettre une quantité infinie de matériel compte tout sur son serveur et le rend super rapide pour les utilisateurs, économisant les ressources de l’utilisateur, telles que la batterie et le trafic, ce qui est très important sur les téléphones.

À son tour, compter dans le navigateur n’est pas la solution la plus optimale en principe. Par conséquent, ce qui n’est pas cher, nous le considérons sur notre serveur. Nous laissons le reste au client. Je veux vraiment prendre et calculer la commission sur le serveur. Mais voici la nuance appelée « interactivité ». Disons que vous avez des milliers d’opérations et qu’il faut cinq minutes pour les recevoir. Qu’est-ce que l’utilisateur aura à ce moment ? Fileur? Progrès? INFA environ combien a été téléchargé? Il est idéal d’utiliser « l’attente active » lorsque l’utilisateur dans le processus peut déjà voir quelque chose. Voici le Résultat :Nous développons un microservice utilisant l'API Tinkoff Invest pour automatiser le travail avec les rapports de courtage et le calcul des commissions.

  • Chargement des pages
  • Toutes les factures sont demandées
  • Après cela, toutes les transactions avec commissions pour les transactions exécutées sont demandées pour tous les comptes. Au fur et à mesure que les données sont reçues, elles sont rendues dans le navigateur.

Afin de ne pas filtrer les données dans les événements à chaque fois, nous extrayons notre propre événement pour chaque compte. Comme ça:

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

Le brouillon à lancer est ici : https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Passons à autre chose. C’est super que vous ayez lu cette ligne! 

Calcul et sortie des informations d’intérêt

Cela dépend de qui a besoin de quelle information. Par conséquent, je vous dis immédiatement les principales nuances que vous rencontrerez.

Travailler avec les prix 

Tous ceux qui travaillent dans le domaine financier savent que les transactions monétaires ne doivent être effectuées qu’avec des nombres entiers. En raison de l’inexactitude des valeurs après la virgule décimale et de l’erreur cumulée avec un grand nombre d’opérations. C’est pourquoi tous les prix sont présentés dans le format MoneyValue suivantNous développons un microservice utilisant l'API Tinkoff Invest pour automatiser le travail avec les rapports de courtage et le calcul des commissions.

champ taper Description
monnaie chaîne Chaîne Code de devise ISO
unités int64 Partie entière de la somme, peut être un nombre négatif
nano int32 Partie fractionnaire du montant, peut être un nombre négatif

Nous les traitons séparément, puis les ramenons à la valeur du prix :

devis.unités + devis.nano / 1e9

Le coût des contrats à terme

Le prix des contrats à terme est présenté en points, lorsque vous avez un contrat à terme sur devises, vous devez connaître le taux. Et bien sûr le prix en points et le pas de prix. Lorsque vous calculez le profit des transactions, cela peut tirer, car. si vous calculez le montant total en multipliant le prix par la quantité. Ici, vous devez être prudent. Pour l’instant, nous allons voir comment ça se passe. Cela s’applique aux contrats à terme sur devises, dans d’autres endroits, tout va bien avec cela.Nous développons un microservice utilisant l'API Tinkoff Invest pour automatiser le travail avec les rapports de courtage et le calcul des commissions. Nous développons un microservice utilisant l'API Tinkoff Invest pour automatiser le travail avec les rapports de courtage et le calcul des commissions.

Marché OTC

Ce marché a beaucoup de particularités, alors étudions les opérations dessus séparément.Lorsque vous commencerez à synchroniser les opérations, il s’avérera que vous devrez amener figi / ticker à la même forme afin de correspondre correctement à l’instrument. Lorsque vous commencez à synchroniser cela avec le rapport de courtage, il s’avérera que le tradeID de la même transaction a des lettres au début des transactions et qu’elles ne figurent pas dans le rapport de courtage. Par conséquent, ils ne peuvent pas être comparés … ahem-ahem … par comparaison! J’ai fait correspondre l’heure de la transaction, le ticker et la correspondance qu’un tradeId est contenu dans un autre. Exact, je ne sais pas. Quiconque rencontre cela et qui s’en soucie, venez au problème ou commencez-en un nouveau.Nous développons un microservice utilisant l'API Tinkoff Invest pour automatiser le travail avec les rapports de courtage et le calcul des commissions.

Opérations mathématiques sur les outils

Il est impossible, sans regarder, d’effectuer des opérations mathématiques avec toute la liste. Afin de ne pas ajouter de chaud à doux, nous vérifions toujours la devise et ne traitons que si nous sommes sûrs que la devise correspond, et les points sont convertis dans la devise souhaitée. Armés de connaissances sur le travail avec les numéros bancaires, nous calculerons la commission dépensée sur chacun des comptes. Comme ceci : https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4Nous développons un microservice utilisant l'API Tinkoff Invest pour automatiser le travail avec les rapports de courtage et le calcul des commissions.    

Le microservice est prêt !

https://github.com/pskucherov/tcsstat En devoir, vous pouvez vérifier si le service fonctionne avec une connexion lente, lorsque les connexions sont interrompues, lorsque Internet est déconnecté, en cas d’erreurs ou de limites expirées de la part du courtier. 

Conclusions et plans pour l’avenir

  • Apprentissage des opérations de base et utilisation de l’API Invest
  • Temps passé ~ 10 heures
  • Niveau de difficulté ~ junior+ / bas moyen 

Si vous continuez à affiner le microservice, vous pourriez vous retrouver avec quelque chose comme ça

https://opexbot.info

  C’est mon développement, pour ceux qui sont trop paresseux pour comprendre, courir et compter par eux-mêmes. Je prévois d’y ajouter des analyses à la demande des utilisateurs. Si vous avez aimé l’article, abonnez-vous à ma chaîne de télégrammes . Nous développons un microservice utilisant l'API Tinkoff Invest pour automatiser le travail avec les rapports de courtage et le calcul des commissions.

Pavel
Rate author
Add a comment

  1. Isakiiev

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

    Répondre