Vi utvecklar en mikrotjänst som använder Tinkoff Invest API för att automatisera arbetet med mäklarrapporter och beräkning av provisioner.

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

Inspiratörerna bakom utvecklingen av statistiktjänsten för Tinkoff Investments var:

Vad kommer att diskuteras?

  • Endast den tillämpade delen om utveckling.
  • Verklig kunskap och erfarenhet, som är mycket viktig i arbetet med finansiella instrument.
  • Översikt över frågor att arbeta med

jag vill beräkna handelsstatistik och göra det på ett bekvämt sätt. 

Utveckla en statistiktjänst steg för steg: 

  1. Anslutning till Tinkoff Invest API
  2. Rita data från Tinkoff Invest API i en webbläsare
  3. Ta emot mäklarrapporter och transaktioner
  4. Beräkning och utmatning av information av intresse
  5. Slutsatser och planer för framtiden

Anslutning till Tinkoff Invest API

För att ansluta till API:t kan du ta vilken sdk som helst från dokumentationen https://github.com/Tinkoff/investAPI#sdk . Eller npm-paketet ` tinkoff-sdk-grpc-js `. Det är viktigt att paketet uppdateras till den senaste versionen av utvecklarna. Installera

npm i tinkoff-sdk-grpc-js

Kontroll

const { createSdk } = require(’tinkoff-sdk-grpc-js’);   // Token som kan erhållas så här  const TOKEN = ’YOURAPI’;   // Namnet på programmet som du kan hitta i TCS-loggarna. const appName = ’tcsstat’;   const sdk = createSdk(TOKEN, appnamn); (async () => {     console.log(await sdk.users.getAccounts()); })();

Resultat: en lista över dina konton kommer att visas i konsolen. Låt oss till exempel analysera nyanserna:Vi utvecklar en mikrotjänst som använder Tinkoff Invest API för att automatisera arbetet med mäklarrapporter och beräkning av provisioner.

  • I listan över konton finns en ”Investeringsbank”, som du inte kan arbeta med med hjälp av API
  • Observera att fälten kommer i camelCase, medan dessa fält i dokumentationen presenteras i under_score. 
  • Det kommer att vara så här överallt, så du kan inte bara ta och kopiera ett fält från dokumentationen.

Användbar:

  • Du hittar denna kod i projektgrenen

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

Rita data från Tinkoff Invest API i en webbläsare

Jag tog next.js och socket.io. Detta är ingen stark rekommendation, välj efter eget gottfinnande. 

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

Vi fortsätter omedelbart till vänskapssteget nästa+socket+investapi, och se avsnittet Användbart i detta steg för alla detaljer.  Jag ska beskriva detaljerna: 

  • På nodejs (server) sidan finns en pages/api/investapi.js fil. Det är här vi skapar socket.io-servern och ansluter till investapi.
  • På webbläsarsidan (klient) ansluter vi till servern via ett uttag och begär kontodata från mäklaren. 
  • Vi tar emot data från mäklaren på servern och skickar den sedan till klienten. När de tas emot på klienten visas de i webbläsaren. 

Resultat:  i webbläsarkonsolen kan vi se information om konton. Det vill säga, i det sista steget såg vi information om konton i serverkonsolen (nodejs), i det aktuella steget överförde vi denna information till klienten (webbläsaren).

Vi utvecklar en mikrotjänst som använder Tinkoff Invest API för att automatisera arbetet med mäklarrapporter och beräkning av provisioner.

Låt oss nu göra det så att du kan välja ett konto från webbläsaren, och om det inte finns någon token skickas ett felmeddelande till konsolen. Arbetet är enkelt och inget nytt, så jag ger bara länkar till commits

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

Användbar:

  • Hur man får vänner nästa och socket beskrivs i detalj här
  • Vänskapskod nästa+socket+investapi:

https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 För vem ovanstående är svårt, förblir vi i detta skede och hanterar koden. Om du har frågor – fråga. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2

Ta emot mäklarrapporter och transaktioner

Det finns tre sätt att ta emot mäklarrapporter och transaktioner

  1. GetBrokerReport
  2. GetDividends Utländsk Emittent
  3. Get OperationsByCursor

Redan från början är det viktigt att veta: 

  • Mäklarrapporten genereras i T-3-läget, d.v.s. affärer visas där efter deras faktiska genomförande. 
  • Följaktligen, om du begär denna rapport för de senaste två dagarna, kommer den att vara klar inom tre dagar. 
  • För att få transaktioner för de senaste dagarna använder vi metoden för att ta emot transaktioner, men kom ihåg att deras id och innehåll kan ändras efter att mäklarrapporten har genererats.

GetBrokerReport

För att få en mäklarrapport behöver du ta konto-id, startdatum och slutdatum för rapporten, dock inte mer än 31 dagar. Vi skickar en begäran om att generera en rapport till API:t i generera _broker_report_request , få ett taskId som svar. Efter det får vi data från get _broker_report_response med hjälp av detta taskId.

Så dokumentationen säger, i verkligheten finns det nyanser. Se upp med händerna:
  • Du måste spara TaskID för alltid exakt för dessa datum. 
  • Eftersom om du förlorar den, kommer rapporten för de begärda datumen först som svar på genereringsförfrågan, 
  • Och då kommer det inte alls.
Låt oss börja skriva kod

Metod för att få datumet, med hänsyn till subtraktionen från det aktuella datumet

const getDateSubDay = (subDay = 5, start = true) => {     const date = new Date();     date.setUTCDate(date.getUTCDate() – underdag);       if (start) {         date.setUTCHours(0, 0, 0, 0);     } annat {         date.setUTCHours(23, 59, 59, 999);     }       returdatum; };

Begäran om rapportgenerering 

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

Resultat:

  • Som ett resultat av den första exekveringen av kommandot får vi taskId. 
  • Rapporten börjar genereras på mäklarens sida. När det är klart är okänt, väntar vi och drar med jämna mellanrum taskId i väntan på rapporten.
  • Varför? För om rapporten inte är klar ger den ett fel. Om rapporten inte är klar på mäklarens sida så är detta ett fel i din kod. Bearbeta: 30058|INVALID_ARGUMENT|uppgiften är inte slutförd ännu, försök igen senare

Koden för att vänta och ta emot en rapport ser ut ungefär så här.

const timer = asynkron tid => {     returnera nytt löfte(lös => setTimeout(lös, tid)); }   const getBrokerResponseByTaskId = async (taskId, page = 0) => {     try {         return await (sdk.operations.getBrokerReport)({             getBrokerReportRequest: {                 taskId,                 page,             },         });     } catch (e) {         console.log(’vänta’, e);         vänta timer(10000);         return await getBrokerResponseByTaskId(taskId, page);     } };

Sedan händer samma magi. Vi stoppar vårt manus, startar det igen, vi har inget uppgifts-ID. Vi exekverar koden med taskId-begäran, men vi får inte längre taskId, utan rapporten omedelbart. Magi! Och allt skulle vara bra om det alltid var så här. Men om en månad kommer det inte finnas några uppgifter alls. Användbart :

  • Lite teori beskrivs här och här .
  • Om du sätter ihop koden kommer utkastet att se ut ungefär så här.

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

  • Om någon stöter på detta, välkommen till frågan . Efter att de har reparerat denna magi, kommer den att förlora sin kraft och kommer att vara annorlunda på något sätt. Men för närvarande (2023-03-21) fungerar det precis så.

GetDividends Utländsk Emittent

Någon kanske tror att metoden liknar den tidigare och du kan använda en enda metod där du bara ändrar namnet på operationerna. Men de gissade inte!  Namnet där är väldigt olika både i metoderna och i den återlämnade informationen. Och sidräkningen börjar från 0, sedan från 1. För att inte bli förvirrad i allt detta är det lättare att skriva två olika metoder. Vilket är konstigt, eftersom logiken i arbetet är densamma. Jag spottade länge när jag försökte göra en metod och det blev mindre kod. Det kommer inte att finnas några exempel här.

Get OperationsByCursor

Min favorit av de tre. Även om inte den mest exakta, men den mest adekvata. Vi gör en begäran från början av att skapa ett konto till högsta möjliga datum (stängning av ett konto eller det nuvarande). Vi får svaret, tar markören och begär på nytt så länge det finns data.  Och koden är mer kortfattad än i exemplen ovan.

const timer = asynkron tid => {     returnera nytt löfte(lös => setTimeout(lös, tid)); }   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,         };           return await sdk.operations.getOperationsByCursor(reqData);     } catch (e) {         await timer(60000);         return await getOperationsByCursor(sdk, accountId, from, to, cursor = ”);     } };

Utkastet att köra finns här: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 Nu är vi redo att lägga till mottagningsoperationer till vår ansökan. Om det görs på rätt sätt måste du få mäklarrapporter för hela kontots existens. Och för de saknade data, samma T-3:or, laddas om från operationer. Men detta kan delas upp i en separat artikel. Av de viktigaste nyanserna som du kommer att stöta på är att limma operationer och en mäklarrapport.

  •  Om du idag fick en mäklarrapport och transaktioner för de datum som krävs, lägg allt i databasen, då är det inga problem. 
  • Du kommer att få problem imorgon när du får nästa del av data från rapporten och operationerna och bestämmer dig för att synkronisera dem med den befintliga databasen. 
  • Många nyanser om felmatchade eller ändra id efter bearbetning
  • Sedan för OTC-marknaden stämmer inte id:erna alls.
  •  Liksom nyanserna av synkroniseringsinstrument, som återigen inte sammanfaller, på grund av API:ets egenheter. Men det är en annan historia.

Låt oss lägga till information om operationer i vår applikation. Huvudfrågan blir var uppgifterna kommer att behandlas och lagras.

  •  Om du gör det för dig själv kommer du att konsumera samma data från olika enheter. Då behöver du bearbeta och lagra data på servern.
  • Om du har många olika data som konsumeras av många olika användare, måste du bestämma vad som är viktigare: användarnas hastighet eller sparandet av järn på din sida. Den som har råd med en oändlig mängd hårdvara räknar allt på sin server och gör det supersnabbt för användarna, vilket sparar användarresurserna, som batteri och trafik, vilket är väldigt viktigt på telefoner.

I sin tur är räkning i webbläsaren i princip inte den mest optimala lösningen. Därför, vad som inte är dyrt, anser vi det på vår server. Resten överlåter vi till kunden. Jag vill verkligen ta och beräkna provisionen på servern. Men här kommer nyansen som kallas ”interaktivitet”. Låt oss säga att du har tusentals operationer och att det tar fem minuter att ta emot dem. Vad kommer användaren att ha vid det här laget? Spinnare? Framsteg? Info om hur mycket som laddades upp? Det är idealiskt att använda ”aktiv väntan” när användaren i processen redan kunde se något. Här är resultatet:Vi utvecklar en mikrotjänst som använder Tinkoff Invest API för att automatisera arbetet med mäklarrapporter och beräkning av provisioner.

  • Sidan laddas
  • Alla fakturor efterfrågas
  • Därefter begärs alla transaktioner med provisioner för genomförda transaktioner för alla konton. När data tas emot renderas den i webbläsaren.

För att inte filtrera data i händelserna varje gång drar vi vår egen händelse för varje konto. Så här:

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

Utkastet att lansera finns här: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Gå vidare. Det är bra att du har läst den här raden! 

Beräkning och utmatning av information av intresse

Beror på vem som behöver vilken information. Därför berättar jag omedelbart de viktigaste nyanserna som du kommer att stöta på.

Jobbar med priser 

Alla som jobbar med ekonomi vet att pengatransaktioner endast ska utföras med heltal. På grund av felaktigheten i värden efter decimalkomma och det kumulativa felet med ett stort antal operationer. Det är därför alla priser presenteras i följande MoneyValue- formatVi utvecklar en mikrotjänst som använder Tinkoff Invest API för att automatisera arbetet med mäklarrapporter och beräkning av provisioner.

fälttypBeskrivning
valutasträngSträng ISO-valutakod
enheterint64Heltalsdel av summan kan vara ett negativt tal
nanoint32Bråkdel av beloppet kan vara ett negativt tal

Vi behandlar dem separat och tar dem sedan till prisvärdet:

quotation.units + quotation.nano / 1e9

Kostnaden för terminskontrakt

Priset på terminer presenteras i poäng, när du har en valutatermin behöver du veta kursen. Och givetvis priset i poäng och prissteg. När du beräknar vinsten från transaktioner, kan detta skjuta, eftersom. om du beräknar totalbeloppet genom att multiplicera priset med kvantiteten. Här måste du vara försiktig. Nu får vi se hur det går. Det gäller valutaterminer, på andra ställen är allt ok med detta.Vi utvecklar en mikrotjänst som använder Tinkoff Invest API för att automatisera arbetet med mäklarrapporter och beräkning av provisioner.Vi utvecklar en mikrotjänst som använder Tinkoff Invest API för att automatisera arbetet med mäklarrapporter och beräkning av provisioner.

OTC-marknaden

Den här marknaden har många egenheter, så låt oss studera operationer på den separat. När du börjar synkronisera operationer kommer det att visa sig att du måste ta figi / ticker till samma form för att korrekt matcha instrumentet. När du börjar synkronisera detta med mäklarrapporten kommer det att visa sig att tradeID för samma transaktion har bokstäver i början i transaktionerna och de finns inte i mäklarrapporten. Därför kan de inte jämföras … ahem-ahem … genom jämförelse! Jag matchade handelstiden, tickern och matchade att ett tradeId finns i ett annat. Okej, jag vet inte. Den som stöter på detta och som bryr sig om det, kom till frågan eller starta en ny.Vi utvecklar en mikrotjänst som använder Tinkoff Invest API för att automatisera arbetet med mäklarrapporter och beräkning av provisioner.

Matematiska operationer på verktyg

Det är omöjligt, utan att titta, att utföra matematiska operationer med hela listan. För att inte lägga till varm till mjuk kontrollerar vi alltid valutan och bearbetar endast om vi är säkra på att valutan matchar, och poängen omvandlas till önskad valuta. Beväpnade med kunskap om att arbeta med banknummer kommer vi att beräkna den provision som spenderas på vart och ett av kontona. Så här: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4Vi utvecklar en mikrotjänst som använder Tinkoff Invest API för att automatisera arbetet med mäklarrapporter och beräkning av provisioner.   

Microservice är redo!

https://github.com/pskucherov/tcsstat Som läxa kan du kontrollera om tjänsten fungerar med en långsam anslutning, när anslutningar bryts, när Internet kopplas bort, när fel eller gått ut gränser från mäklarens sida. 

Slutsatser och planer för framtiden

  • Lärde mig om grundläggande funktioner och att arbeta med Invest API
  • Tid tillbringad ~ 10 timmar
  • Svårighetsgrad ~ junior+ / låg medel 

Om du fortsätter att förfina mikrotjänsten kan du sluta med något sånt här

https://opexbot.info

  Det här är min utveckling, för den som är för lat för att förstå, springa och räkna på egen hand. Jag planerar att lägga till analyser där på begäran av användare. Om du gillade artikeln, prenumerera på min telegramkanal . Vi utvecklar en mikrotjänst som använder Tinkoff Invest API för att automatisera arbetet med mäklarrapporter och beräkning av provisioner.

Pavel
Rate author
Add a comment

  1. Isakiiev

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

    Svara