We ontwikkelen een microservice met behulp van de Tinkoff Invest API om het werken met makelaarsrapporten en het berekenen van commissies te automatiseren.

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

De inspirators achter de ontwikkeling van de statistische dienst voor Tinkoff Investments waren:

Wat wordt er besproken?

  • Alleen het toegepaste gedeelte over ontwikkeling.
  • Echte kennis en ervaring, die erg belangrijk zijn bij het werken met financiële instrumenten.
  • Overzicht van zaken om aan te werken

Dus ik wil handelsstatistieken berekenen en dit op een handige manier doen. 

Stap voor stap een statistiekdienst ontwikkelen: 

  1. Verbinding met de Tinkoff Invest-API
  2. Gegevens uit de Tinkoff Invest API in een browser halen
  3. Het ontvangen van makelaarsrapporten en transacties
  4. Berekening en output van informatie van belang
  5. Conclusies en plannen voor de toekomst

Verbinding met de Tinkoff Invest-API

Om verbinding te maken met de API, kunt u elke sdk uit de documentatie https://github.com/Tinkoff/investAPI#sdk nemen . Of npm-pakket ` tinkoff-sdk-grpc-js` . Het is belangrijk dat het pakket door de ontwikkelaars wordt bijgewerkt naar de nieuwste versie. Installeren

npm en tinkoff-sdk-grpc-js

Controleren

const { createSdk } = vereisen(’tinkoff-sdk-grpc-js’);   // Token dat zo kan worden verkregen   const TOKEN = ‘YOURAPI’;   // De naam van de applicatie waarmee u in de TCS-logboeken kunt worden gevonden. const appName = ’tcsstat’;   const sdk = createSdk(TOKEN, appName); (async () => {     console.log(wacht op sdk.users.getAccounts()); })();

Resultaat: een lijst met uw accounts wordt weergegeven in de console. Laten we bijvoorbeeld de nuances analyseren:We ontwikkelen een microservice met behulp van de Tinkoff Invest API om het werken met makelaarsrapporten en het berekenen van commissies te automatiseren.

  • In de lijst met rekeningen staat een “Investeringsbank”, waarmee u niet kunt werken met behulp van de API
  • Houd er rekening mee dat de velden in camelCase staan, terwijl deze velden in de documentatie worden gepresenteerd in under_score. 
  • Het zal overal zo zijn, dus je kunt niet zomaar een veld uit de documentatie nemen en kopiëren.

Bruikbaar:

  • U vindt deze code in de projecttak

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

Gegevens uit de Tinkoff Invest API in een browser halen

Ik nam next.js en socket.io. Dit is geen sterke aanbeveling, kies naar eigen goeddunken. 

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

We gaan onmiddellijk verder met de vriendschapsstap volgende+socket+investapi, en zie het Nuttige gedeelte van deze stap voor alle details.  Ik zal de details beschrijven: 

  • Aan de nodejs (server) kant is er een pages/api/investapi.js bestand. Hier maken we de socket.io-server en maken we verbinding met investapi.
  • Aan de browser (client) kant maken we via een socket verbinding met de server en vragen we accountgegevens op bij de broker. 
  • We ontvangen gegevens van de makelaar op de server en sturen deze vervolgens naar de klant. Wanneer ze op de client worden ontvangen, worden ze weergegeven in de browser. 

Resultaat:  in de browserconsole kunnen we informatie over accounts zien. Dat wil zeggen, in de laatste stap zagen we informatie over accounts in de serverconsole (nodejs), in de huidige stap hebben we deze informatie overgedragen aan de client (browser).

We ontwikkelen een microservice met behulp van de Tinkoff Invest API om het werken met makelaarsrapporten en het berekenen van commissies te automatiseren.

Laten we er nu voor zorgen dat u een account vanuit de browser kunt selecteren en als er geen token is, wordt er een fout naar de console gestuurd. Het werk is eenvoudig en niets nieuws, dus geef ik alleen links naar commits

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

Bruikbaar:

  • Hoe je vervolgens vrienden kunt maken en socket wordt hier in detail beschreven . 
  • Vriendschapscode next+socket+investapi:

https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 Voor wie het bovenstaande moeilijk is, blijven we in dit stadium en behandelen we de code. Als je vragen hebt – stel ze. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2

Het ontvangen van makelaarsrapporten en transacties

Er zijn drie methoden om makelaarsrapporten en transacties te ontvangen

  1. GetBrokerReport
  2. GetDividendsForeignIssuer
  3. GetOperationsByCursor

Vanaf het allereerste begin is het belangrijk om te weten: 

  • Het makelaarsrapport wordt gegenereerd in de T-3-modus, d.w.z. transacties worden daar weergegeven na hun daadwerkelijke uitvoering. 
  • Dus als u dit rapport van de afgelopen twee dagen opvraagt, is het binnen drie dagen klaar. 
  • Om transacties van de afgelopen dagen op te halen, gebruiken we de methode voor het ontvangen van transacties, maar onthoud dat hun id en inhoud kunnen veranderen nadat het makelaarsrapport is gegenereerd.

GetBrokerReport

Om een ​​makelaarsrapport te krijgen, moet u rekening houden met de account-ID, de startdatum en de einddatum van het rapport, maar niet meer dan 31 dagen. We sturen een verzoek om een ​​rapport te genereren naar de API om _broker_report_request te genereren , krijgen een taskId als antwoord. Daarna krijgen we met behulp van deze taskId gegevens van get _broker_report_response.

Dus de documentatie zegt, in werkelijkheid zijn er nuances. Let op je handen:

  • U moet de TaskID voor altijd bewaren, precies voor deze datums. 
  • Aangezien als u het verliest, het rapport voor de gevraagde datums eerst zal komen als reactie op het generatieverzoek, 
  • En dan komt het helemaal niet.
Laten we beginnen met het schrijven van code

Methode om de datum te krijgen, rekening houdend met de aftrekking van de huidige datum

const getDateSubDay = (subDay = 5, start = true) => {     const date = nieuwe datum();     date.setUTCDate(date.getUTCDate() – subDay);       als (start) {         datum.setUTCHours(0, 0, 0, 0);     } else {         datum.setUTCHours(23, 59, 59, 999);     }       retourdatum; };

Verzoek om rapport te genereren 

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

Resultaat:

  • Als resultaat van de eerste uitvoering van de opdracht krijgen we de taskId. 
  • Het rapport wordt gegenereerd aan de kant van de makelaar. Wanneer het gereed is is onbekend, we wachten af ​​en trekken periodiek de taskId in afwachting van de melding.
  • Waarom? Want als het rapport niet klaar is, geeft het een foutmelding. Als het rapport niet klaar is aan de kant van de makelaar, dan is dit een fout in uw code. Gelieve te verwerken: 30058|INVALID_ARGUMENT|taak nog niet voltooid, probeer het later opnieuw

De code voor wachten en ontvangen van een melding ziet er ongeveer zo uit.

const timer = asynchrone tijd => {     return new Promise(resolve => setTimeout(resolve, time)); }   const getBrokerResponseByTaskId = async (taskId, pagina = 0) => {     probeer {         return wait (sdk.operations.getBrokerReport)({             getBrokerReportRequest: {                 taskId,                 page,             },         });     } vangst (e) {         console.log(‘wacht’, e);         wacht timer (10000);         return wait getBrokerResponseByTaskId(taskId, pagina);     } };

Dan gebeurt dezelfde magie. We stoppen ons script, starten het opnieuw, we hebben geen taskId. We voeren de code uit met het taskId-verzoek, maar we krijgen niet meer de taskId, maar meteen het rapport. Magie! En alles zou goed zijn als het altijd zo was. Maar over een maand zijn er helemaal geen gegevens. nuttig :

  • Een stukje theorie wordt hier en hier geschetst .
  • Door de code samen te stellen, ziet het concept er ongeveer zo uit.

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

  • Als iemand dit tegenkomt, welkom bij het probleem . Nadat ze deze magie hebben gerepareerd, verliest het zijn kracht en zal het op de een of andere manier anders zijn. Maar op dit moment (21/03/2023) werkt het gewoon zo.

GetDividendsForeignIssuer

Iemand zou kunnen denken dat de methode vergelijkbaar is met de vorige en dat u een enkele methode kunt gebruiken waarin u alleen de naam van de bewerkingen wijzigt. Maar ze raadden niet!  De naamgeving daar is heel verschillend, zowel in de methoden als in de geretourneerde informatie. En het aantal pagina’s begint bij 0 en vervolgens bij 1. Om bij dit alles niet in de war te raken, is het gemakkelijker om twee verschillende methoden te schrijven. Wat vreemd is, want de logica van het werk is hetzelfde. Ik spuugde lang toen ik probeerde één methode te maken en er was minder code. Er zullen hier geen voorbeelden zijn.

GetOperationsByCursor

Mijn favoriet van de drie. Hoewel niet de meest nauwkeurige, maar wel de meest geschikte. We doen een verzoek vanaf het begin van het aanmaken van een account tot de maximaal mogelijke datum (het sluiten van een account of de huidige). We krijgen het antwoord, nemen de cursor en vragen opnieuw zolang er gegevens zijn.  En de code is beknopter dan in de bovenstaande voorbeelden.

const timer = asynchrone tijd => {     return new Promise(resolve => setTimeout(resolve, time)); }   const getOperationsByCursor = async (sdk, accountId, from, to, cursor = ”) => {     probeer {         const reqData = {             accountId,             from,             to,             limit: 1000,             state: sdk.OperationState.OPERATION_STATE_EXECUTED,             withoutCommissions: false,             withoutTrades: false,             withoutOvernights: false,             cursor,         };           return wachten sdk.operations.getOperationsByCursor(reqData);     } vangst (e) {         wacht timer(60000);         return wait getOperationsByCursor(sdk, accountId, from, to, cursor = ”);     } };

Het uit te voeren concept is hier: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 Nu zijn we klaar om ontvangstbewerkingen toe te voegen aan onze applicatie. Indien correct gedaan, moet u makelaarsrapporten ontvangen voor het gehele bestaan ​​van het account. En voor de ontbrekende gegevens, diezelfde T-3’s, herladen vanuit operaties. Maar dit kan worden gescheiden in een apart artikel. Van de belangrijkste nuances die u zult tegenkomen, is het lijmen van operaties en een makelaarsrapport.

  •  Als u vandaag een makelaarsrapport en transacties voor de vereiste data heeft ontvangen, zet dit dan allemaal in de database, dan zijn er geen problemen. 
  • U zult morgen problemen krijgen wanneer u het volgende deel van de gegevens uit het rapport en de bewerkingen ontvangt en besluit deze te synchroniseren met de bestaande database. 
  • Veel nuances over niet-overeenkomende of veranderende id na verwerking
  • Dan komen de id’s voor de OTC-markt helemaal niet overeen.
  •  Evenals de nuances van synchronisatie-instrumenten, die wederom niet samenvallen vanwege de eigenaardigheden van de API. Maar dat is een ander verhaal.

Laten we informatie over bewerkingen toevoegen aan onze applicatie. De belangrijkste vraag zal zijn waar de gegevens worden verwerkt en opgeslagen.

  •  Als u het voor uzelf doet, verbruikt u dezelfde gegevens van verschillende apparaten. Vervolgens moet u gegevens verwerken en opslaan op de server.
  • Als u veel verschillende gegevens heeft die door veel verschillende gebruikers worden verbruikt, moet u beslissen wat belangrijker is: de snelheid van de gebruikers of de besparing van ijzer aan uw kant. Degene die zich een oneindige hoeveelheid hardware kan veroorloven, telt alles op zijn server en maakt het supersnel voor gebruikers, waardoor gebruikersbronnen worden bespaard, zoals batterij en verkeer, wat erg belangrijk is op telefoons.

Rekenen in de browser is dan weer in principe niet de meest optimale oplossing. Daarom, wat niet duur is, beschouwen we het op onze server. De rest laten we over aan de opdrachtgever. Ik wil echt de commissie op de server nemen en berekenen. Maar hier komt de nuance die “interactiviteit” wordt genoemd. Stel dat u duizenden bewerkingen heeft en dat het vijf minuten duurt om ze te ontvangen. Wat heeft de gebruiker op dit moment? Spinner? Voortgang? Info over hoeveel er is geüpload? Het is ideaal om “actief wachten” te gebruiken wanneer de gebruiker in het proces al iets zou kunnen zien. Hier is het resultaat:We ontwikkelen een microservice met behulp van de Tinkoff Invest API om het werken met makelaarsrapporten en het berekenen van commissies te automatiseren.

  • Pagina laden
  • Alle facturen worden opgevraagd
  • Daarna worden alle transacties met provisies voor uitgevoerde transacties opgevraagd voor alle rekeningen. Terwijl gegevens worden ontvangen, worden deze weergegeven in de browser.

Om de gegevens in de evenementen niet elke keer te filteren, trekken we ons eigen evenement voor elk account. Soortgelijk:

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

Het te lanceren concept is hier: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Verder gaan. Leuk dat je deze regel hebt gelezen! 

Berekening en output van informatie van belang

Hangt ervan af wie welke informatie nodig heeft. Daarom vertel ik je meteen de belangrijkste nuances die je zult tegenkomen.

Werken met prijzen 

Iedereen die met financiën werkt, weet dat geldtransacties alleen met hele getallen mogen worden uitgevoerd. Vanwege de onnauwkeurigheid van waarden achter de komma en de cumulatieve fout bij een groot aantal bewerkingen. Daarom worden alle prijzen gepresenteerd in het volgende MoneyValue- formaatWe ontwikkelen een microservice met behulp van de Tinkoff Invest API om het werken met makelaarsrapporten en het berekenen van commissies te automatiseren.

veldtypeBeschrijving
munteenheidsnaarString ISO-valutacode
eenhedenint64Integer deel van de som, kan een negatief getal zijn
nanoint32Een fractie van het bedrag kan een negatief getal zijn

We verwerken ze apart en brengen ze vervolgens naar de prijswaarde:

offerte.eenheden + offerte.nano / 1e9

De kosten van termijncontracten

De prijs van futures wordt weergegeven in punten, als u een valutafuture heeft, moet u de koers weten. En natuurlijk de prijs in punten en de prijsstap. Wanneer je de winst uit transacties berekent, kan dit schieten, want. als u het totale bedrag berekent door de prijs te vermenigvuldigen met de hoeveelheid. Hier moet je voorzichtig zijn. Voor nu zien we wel hoe het loopt. Dit geldt voor valutafutures, op andere plaatsen is hier alles in orde.We ontwikkelen een microservice met behulp van de Tinkoff Invest API om het werken met makelaarsrapporten en het berekenen van commissies te automatiseren.We ontwikkelen een microservice met behulp van de Tinkoff Invest API om het werken met makelaarsrapporten en het berekenen van commissies te automatiseren.

OTC-markt

Deze markt heeft veel eigenaardigheden, dus laten we de bewerkingen er apart op bestuderen.Wanneer u begint met het synchroniseren van bewerkingen, zal blijken dat u figi / ticker in dezelfde vorm moet brengen om het instrument correct te matchen. Wanneer je dit gaat synchroniseren met het brokerage rapport, zal blijken dat de tradeID van dezelfde transactie letters heeft aan het begin van de transacties en deze staan ​​niet in het brokerage rapport. Daarom kunnen ze niet worden vergeleken … ahem-ahem … ter vergelijking! Ik matchte de handelstijd, ticker en matching dat de ene tradeId in de andere zit. Juist, ik weet het niet. Wie dit tegenkomt en er belang bij heeft, komt ter sprake of begint een nieuwe.We ontwikkelen een microservice met behulp van de Tinkoff Invest API om het werken met makelaarsrapporten en het berekenen van commissies te automatiseren.

Wiskundige bewerkingen op gereedschappen

Het is onmogelijk om zonder te kijken wiskundige bewerkingen uit te voeren met de hele lijst. Om geen warm tot zacht toe te voegen, controleren we altijd de valuta en verwerken we alleen als we zeker weten dat de valuta overeenkomt en de punten worden omgerekend naar de gewenste valuta. Gewapend met kennis over het werken met banknummers, berekenen we de commissie die op elk van de rekeningen wordt uitgegeven. Zoals dit: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4We ontwikkelen een microservice met behulp van de Tinkoff Invest API om het werken met makelaarsrapporten en het berekenen van commissies te automatiseren.   

Microservice is er klaar voor!

https://github.com/pskucherov/tcsstat Als huiswerk kunt u controleren of de service werkt met een trage verbinding, wanneer verbindingen worden verbroken, wanneer de internetverbinding wordt verbroken, wanneer fouten of verlopen limieten van de kant van de makelaar. 

Conclusies en plannen voor de toekomst

  • Geleerd over basisbewerkingen en werken met de Invest API
  • Bestede tijd ~ 10 uur
  • Moeilijkheidsgraad ~ junior+ / laag midden 

Als je doorgaat met het verfijnen van de microservice, krijg je misschien zoiets als dit

https://opexbot.info

  Dit is mijn ontwikkeling, voor degenen die te lui zijn om zelf te begrijpen, rennen en rekenen. Ik ben van plan daar op verzoek van gebruikers analyses toe te voegen. Als je het artikel leuk vond, abonneer je dan op mijn telegramkanaal . We ontwikkelen een microservice met behulp van de Tinkoff Invest API om het werken met makelaarsrapporten en het berekenen van commissies te automatiseren.

Pavel
Rate author
Add a comment

  1. Isakiiev

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

    Beantwoorden