Dezvoltăm un microserviciu folosind API-ul Tinkoff Invest pentru a automatiza lucrul cu rapoartele de brokeraj și calcularea comisiilor.

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

Inspiratorii din spatele dezvoltării serviciului de statistică pentru Tinkoff Investments au fost:

Ce se va discuta?

  • Doar partea aplicată despre dezvoltare.
  • Cunoștințe și experiență reale, care sunt foarte importante în lucrul cu instrumente financiare.
  • Prezentare generală a problemelor la care trebuie să lucrați

Deci, vreau să calculez statisticile comerciale și să o fac într-un mod convenabil. 

Dezvoltarea unui serviciu de statistică pas cu pas: 

  1. Conexiune la Tinkoff Invest API
  2. Desenarea datelor din API-ul Tinkoff Invest într-un browser
  3. Primirea rapoartelor de brokeraj și tranzacții
  4. Calculul și obținerea informațiilor de interes
  5. Concluzii și planuri de viitor

Conexiune la Tinkoff Invest API

Pentru a vă conecta la API, puteți lua orice sdk din documentația https://github.com/Tinkoff/investAPI#sdk . Sau pachetul npm ` tinkoff-sdk-grpc-js `. Este important ca pachetul să fie actualizat la cea mai recentă versiune de către dezvoltatori. Instalare

npm și tinkoff-sdk-grpc-js

Control

const { createSdk } = require(‘tinkoff-sdk-grpc-js’);   // Token care poate fi obținut astfel  const TOKEN = ‘YOURAPI’;   // Numele aplicației prin care puteți fi găsit în jurnalele TCS. const appName = ‘tcsstat’;   const sdk = createSdk(TOKEN, appName); (async () => {     console.log(wait sdk.users.getAccounts()); })();

Rezultat: o listă a conturilor dvs. va fi afișată în consolă. De exemplu, să analizăm nuanțele:Dezvoltăm un microserviciu folosind API-ul Tinkoff Invest pentru a automatiza lucrul cu rapoartele de brokeraj și calcularea comisiilor.

  • În lista de conturi există o „Bancă de investiții”, cu care nu puteți lucra folosind API-ul
  • Vă rugăm să rețineți că câmpurile vin în camelCase, în timp ce în documentație aceste câmpuri sunt prezentate sub_score. 
  • Va fi așa peste tot, așa că nu puteți doar să luați și să copiați un câmp din documentație.

Util:

  • Puteți găsi acest cod în ramura de proiect

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

Desenarea datelor din API-ul Tinkoff Invest într-un browser

Am luat next.js și socket.io. Aceasta nu este o recomandare puternică, alegeți la discreția dvs. 

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

Trecem imediat la pasul de prietenie next+socket+investapi și vedem secțiunea Utilă a acestui pas pentru toate detaliile.  Voi descrie detaliile: 

  • Pe partea nodejs (server), există un fișier pages/api/investapi.js. Aici creăm serverul socket.io și ne conectăm la investapi.
  • Pe partea de browser (client), ne conectăm la server printr-un socket și solicităm datele contului de la broker. 
  • Primim date de la broker pe server, apoi le trimitem clientului. Când sunt primite pe client, sunt afișate în browser. 

Rezultat:  în consola browserului putem vedea informații despre conturi. Adică, în ultimul pas, am văzut informații despre conturi în consola serverului (nodejs), în pasul curent, am transferat aceste informații către client (browser).

Dezvoltăm un microserviciu folosind API-ul Tinkoff Invest pentru a automatiza lucrul cu rapoartele de brokeraj și calcularea comisiilor.

Acum să facem astfel încât să puteți selecta un cont din browser, iar dacă nu există nici un token, atunci o eroare este trimisă la consolă. Lucrarea este simplă și nimic nou, așa că dau doar link-uri către comite

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

Util:

  • Cum să vă faceți prieteni în continuare și socket este descris în detaliu aici
  • Cod de prietenie next+socket+investapi:

https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 Pentru care cele de mai sus sunt dificile, atunci rămânem în această etapă și ne ocupăm de cod. Dacă aveți întrebări – întrebați. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2

Primirea rapoartelor de brokeraj și tranzacții

Există trei metode de a primi rapoarte de brokeraj și tranzacții

  1. GetBrokerReport
  2. GetDividendsForeignIssuer
  3. GetOperationsByCursor

De la bun început este important să știți: 

  • Raportul de intermediere este generat în modul T-3, adică. tranzacțiile sunt afișate acolo după executarea lor efectivă. 
  • În consecință, dacă solicitați acest raport pentru ultimele două zile, acesta va fi gata în trei zile. 
  • Pentru a obține tranzacții din ultimele zile, folosim metoda de primire a tranzacțiilor, dar rețineți că id-ul și conținutul acestora se pot schimba după generarea raportului de brokeraj.

GetBrokerReport

Pentru a obține un raport de brokeraj, trebuie să luați ID-ul contului, data de începere și data de încheiere a raportului, dar nu mai mult de 31 de zile. Trimitem o solicitare de a genera un raport către API în generate _broker_report_request , primim un taskId ca răspuns. După aceea, folosind acest taskId, obținem date de la get _broker_report_response.

Deci documentația spune, în realitate există nuanțe. Ai grijă la mâini:

  • Trebuie să salvați TaskID pentru totdeauna exact pentru aceste date. 
  • Deoarece dacă îl pierdeți, atunci pentru datele solicitate raportul va veni mai întâi ca răspuns la cererea de generare, 
  • Și atunci nu va veni deloc.

Să începem să scriem cod

Metoda de obținere a datei, ținând cont de scăderea din data curentă

const getDateSubDay = (subDay = 5, start = true) => {     const date = new Date();     date.setUTCDate(date.getUTCDate() – subZiu);       if (start) {         date.setUTCHours(0, 0, 0, 0);     } else {         date.setUTCHours(23, 59, 59, 999);     }       data de întoarcere; };

Cerere de generare a raportului 

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

Rezultat:

  • Ca rezultat al primei execuții a comenzii, obținem taskId. 
  • Raportul începe să fie generat de partea brokerului. Când este gata este necunoscut, așteptăm și extragem periodic taskId-ul în așteptarea raportului.
  • De ce? Pentru că dacă raportul nu este gata, aruncă o eroare. Dacă raportul nu este gata de partea brokerului, atunci aceasta este o eroare în codul dvs. Vă rugăm să procesați: 30058|INVALID_ARGUMENT|sarcina nu a fost finalizată încă, vă rugăm să încercați din nou mai târziu

Codul pentru așteptarea și primirea unui raport arată cam așa.

const timer = timp asincron => {     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);         temporizator de așteptare (10000);         return await getBrokerResponseByTaskId(taskId, pagina);     } };

Apoi se întâmplă aceeași magie. Ne oprim scriptul, îl pornim din nou, nu avem un taskId. Executăm codul cu cererea taskId, dar nu mai primim taskId, ci imediat raportul. Magie! Și totul ar fi bine dacă ar fi mereu așa. Dar peste o lună nu vor mai exista date deloc. Util :

  • Un pic de teorie este subliniat aici și aici .
  • Punând cap la cap codul, schița va arăta cam așa.

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

  • Dacă cineva întâlnește asta, atunci bine ați venit la problemă . După ce vor repara această magie, își va pierde puterea și va fi cumva diferit. Dar în momentul actual (21.03.2023) funcționează exact așa.

GetDividendsForeignIssuer

Cineva ar putea crede că metoda este similară cu cea anterioară și poți folosi o singură metodă în care schimbi doar numele operațiilor. Dar nu au ghicit!  Denumirea acolo este foarte diferită atât în ​​metode, cât și în informațiile returnate. Iar numărul paginilor începe de la 0, apoi de la 1. Pentru a nu vă încurca în toate acestea, este mai ușor să scrieți două metode diferite. Ceea ce este ciudat, pentru că logica muncii este aceeași. Am scuipat mult timp când am încercat să fac o singură metodă și era mai puțin cod. Nu vor fi exemple aici.

GetOperationsByCursor

Preferatul meu dintre cei trei. Deși nu este cel mai precis, dar cel mai adecvat. Facem o solicitare de la începutul creării unui cont până la data maximă posibilă (închiderea unui cont sau cel curent). Primim răspunsul, luăm cursorul și solicităm din nou atâta timp cât există date.  Și codul este mai concis decât în ​​exemplele de mai sus.

const timer = timp asincron => {     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,             fărăComerțuri: fals,             fărăOvernights: fals,             cursor,         };           return await sdk.operations.getOperationsByCursor(reqData);     } catch (e) {         await timer(60000);         return await getOperationsByCursor(sdk, accountId, from, to, cursor = ”);     } };

Schița de rulat este aici: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 Acum suntem gata să adăugăm operațiuni de primire la aplicația noastră. Dacă este făcut corect, atunci trebuie să obțineți rapoarte de brokeraj pentru întreaga existență a contului. Și pentru datele lipsă, aceleași T-3-uri, reîncărcați din operațiuni. Dar acest lucru poate fi separat într-un articol separat. Dintre principalele nuanțe pe care le veți întâlni este să lipiți operațiunile și un raport de brokeraj.

  •  Dacă astăzi ați primit un raport de brokeraj și tranzacții pentru datele solicitate, puneți totul în baza de date, atunci nu există probleme. 
  • Veți avea probleme mâine când veți primi următoarea porțiune de date din raport și operațiuni și decideți să le sincronizați cu baza de date existentă. 
  • O mulțime de nuanțe despre nepotrivirea sau schimbarea ID-ului după procesare
  • Apoi, pentru piața OTC, id-urile nu se potrivesc deloc.
  •  La fel și nuanțele instrumentelor de sincronizare, care din nou nu coincid, din cauza particularităților API. Dar asta este o altă poveste.

Să adăugăm în aplicația noastră obținerea de informații despre operațiuni. Principala întrebare va fi unde vor fi prelucrate și stocate datele.

  •  Dacă o faci singur, vei consuma aceleași date de pe dispozitive diferite. Apoi, trebuie să procesați și să stocați datele pe server.
  • Dacă aveți o mulțime de date diferite consumate de mulți utilizatori diferiți, atunci trebuie să decideți ce este mai important: viteza utilizatorilor sau economisirea de fier de partea dvs. Cine își poate permite o cantitate infinită de hardware numără totul pe serverul său și îl face super rapid pentru utilizatori, economisind resursele utilizatorului, cum ar fi bateria și traficul, ceea ce este foarte important pe telefoane.

La rândul său, numărarea în browser nu este cea mai optimă soluție în principiu. Prin urmare, ceea ce nu este scump, îl considerăm pe serverul nostru. Restul îl lăsăm clientului. Chiar vreau să iau și să calculez comisionul pe server. Dar aici vine nuanța numită „interactivitate”. Să presupunem că aveți mii de operații și durează cinci minute pentru a le primi. Ce va avea utilizatorul în acest moment? spinner? Progres? Infa despre cât a fost încărcat? Este ideal să folosiți „așteptarea activă” atunci când utilizatorul din proces ar putea vedea deja ceva. Iată rezultatul:Dezvoltăm un microserviciu folosind API-ul Tinkoff Invest pentru a automatiza lucrul cu rapoartele de brokeraj și calcularea comisiilor.

  • Se încarcă pagina
  • Toate facturile sunt solicitate
  • După aceea, toate tranzacțiile cu comisioane pentru tranzacțiile executate sunt solicitate pentru toate conturile. Pe măsură ce datele sunt primite, acestea sunt redate în browser.

Pentru a nu filtra datele din evenimente de fiecare dată, tragem propriul eveniment pentru fiecare cont. Ca aceasta:

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

Schița de lansat este aici: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Continuăm. E grozav că ai citit acest rând! 

Calculul și obținerea informațiilor de interes

Depinde cine are nevoie de ce informații. Prin urmare, vă spun imediat principalele nuanțe pe care le veți întâlni.

Lucrul cu prețurile 

Toți cei care lucrează cu finanțe știu că tranzacțiile cu bani ar trebui efectuate numai cu numere întregi. Datorită inexactității valorilor după virgulă zecimală și a erorii cumulate cu un număr mare de operații. De aceea toate prețurile sunt prezentate în următorul format MoneyValueDezvoltăm un microserviciu folosind API-ul Tinkoff Invest pentru a automatiza lucrul cu rapoartele de brokeraj și calcularea comisiilor.

camp tip Descriere
valută şir Cod de monedă ISO
unitati int64 O parte întreagă a sumei poate fi un număr negativ
nano int32 O parte fracțională a sumei poate fi un număr negativ

Le procesăm separat, apoi le aducem la valoarea prețului:

cotatie.unitati + cotatie.nano / 1e9

Costul contractelor futures

Prețul futures este prezentat în puncte, atunci când aveți un viitor valutar, trebuie să cunoașteți cursul. Și desigur prețul în puncte și treapta de preț. Când calculezi profitul din tranzacții, asta se poate trage, pentru că. dacă calculezi suma totală înmulțind prețul cu cantitatea. Aici trebuie să fii atent. Deocamdată, vom vedea cum merge. Acest lucru este valabil pentru contractele futures pe valută, în alte locuri totul este în regulă cu asta.Dezvoltăm un microserviciu folosind API-ul Tinkoff Invest pentru a automatiza lucrul cu rapoartele de brokeraj și calcularea comisiilor. Dezvoltăm un microserviciu folosind API-ul Tinkoff Invest pentru a automatiza lucrul cu rapoartele de brokeraj și calcularea comisiilor.

piata OTC

Această piață are o mulțime de particularități, așa că să studiem operațiunile pe ea separat.Când începeți operațiile de sincronizare, se va dovedi că trebuie să aduceți figi / ticker în aceeași formă pentru a potrivi corect instrumentul. Când începeți să sincronizați acest lucru cu raportul de brokeraj, se va dovedi că tradeID-ul aceleiași tranzacții are litere la început în tranzacții și nu sunt în raportul de brokeraj. Prin urmare, ele nu pot fi comparate… ahem-ahem… prin comparație! Am corelat timpul de tranzacționare, ticker și potrivirea că un tradeId este conținut în altul. Corect, nu știu. Oricine se confruntă cu asta și cui îi pasă de asta, vine la problemă sau începe una nouă.Dezvoltăm un microserviciu folosind API-ul Tinkoff Invest pentru a automatiza lucrul cu rapoartele de brokeraj și calcularea comisiilor.

Operatii matematice pe unelte

Este imposibil, fără a căuta, să efectuați operații matematice cu întreaga listă. Pentru a nu adăuga cald la moale, verificăm întotdeauna moneda și procesăm doar dacă suntem siguri că moneda se potrivește, iar punctele sunt convertite în moneda dorită. Înarmați cu cunoștințe despre lucrul cu numerele bancare, vom calcula comisionul cheltuit pentru fiecare dintre conturi. Cam așa: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4Dezvoltăm un microserviciu folosind API-ul Tinkoff Invest pentru a automatiza lucrul cu rapoartele de brokeraj și calcularea comisiilor.    

Microserviciul este gata!

https://github.com/pskucherov/tcsstat Ca teme, puteți verifica dacă serviciul funcționează cu o conexiune lentă, când conexiunile sunt întrerupte, când internetul este deconectat, când erori sau limite expirate din partea brokerului. 

Concluzii și planuri de viitor

  • Ați învățat despre operațiunile de bază și despre lucrul cu API-ul Invest
  • Timp petrecut ~ 10 ore
  • Nivel de dificultate ~ junior+ / mediu scăzut 

Dacă continuați să perfecționați microserviciul, s-ar putea să ajungeți cu așa ceva

https://opexbot.info

  Aceasta este dezvoltarea mea, pentru cei cărora le este prea lene să înțeleagă, să alerge și să conteze pe cont propriu. Plănuiesc să adaug analize acolo la cererea utilizatorilor. Dacă ți-a plăcut articolul, atunci abonează-te la canalul meu Telegram . Dezvoltăm un microserviciu folosind API-ul Tinkoff Invest pentru a automatiza lucrul cu rapoartele de brokeraj și calcularea comisiilor.

Pavel
Rate author
Add a comment

  1. Isakiiev

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

    Reply