Inspiratorerne bag udviklingen af statistiktjenesten for Tinkoff Investments var:
- artikel om Habré “Hvad Tinkoff Investments ikke siger”
- analyse af platformbrugernes ønsker
- en artikel om beregning af provision .
- Hvad vil blive diskuteret?
- Udvikling af en statistiktjeneste trin for trin:
- Forbindelse til Tinkoff Invest API
- Tegning af data fra Tinkoff Invest API i en browser
- Modtagelse af mæglerrapporter og transaktioner
- GetBrokerReport
- Metode til at få datoen under hensyntagen til subtraktionen fra den aktuelle dato
- Anmodning om rapportgenerering
- Resultat:
- Få Udbytte Udenlandsk Udsteder
- Get OperationsByCursor
- Beregning og output af information af interesse
- Arbejder med priser
- Omkostningerne ved futureskontrakter
- OTC-markedet
- Matematiske operationer på værktøjer
- Microservice er klar!
- Konklusioner og planer for fremtiden
- https://opexbot.info
Hvad vil blive diskuteret?
- Kun den anvendte del om udvikling.
- Reel viden og erfaring, som er meget vigtig i arbejdet med finansielle instrumenter.
- Overblik over problemstillinger, der skal arbejdes med
Så jeg vil gerne beregne handelsstatistik og gøre det på en bekvem måde.
Udvikling af en statistiktjeneste trin for trin:
- Forbindelse til Tinkoff Invest API
- Tegning af data fra Tinkoff Invest API i en browser
- Modtagelse af mæglerrapporter og transaktioner
- Beregning og output af information af interesse
- Konklusioner og planer for fremtiden
Forbindelse til Tinkoff Invest API
For at oprette forbindelse til API’et kan du tage en hvilken som helst sdk fra dokumentationen https://github.com/Tinkoff/investAPI#sdk . Eller npm-pakken ` tinkoff-sdk-grpc-js `. Det er vigtigt, at pakken bliver opdateret til den nyeste version af udviklerne. Installere
npm i tinkoff-sdk-grpc-js
Tjekker
const { createSdk } = require(‘tinkoff-sdk-grpc-js’); // Token, der kan fås som denne const TOKEN = ‘YOURAPI’; // Navnet på den applikation, som du kan finde i TCS-logfilerne. const appName = ‘tcsstat’; const sdk = createSdk(TOKEN, appnavn); (async () => { console.log(afventer sdk.users.getAccounts()); })();
Resultat: en liste over dine konti vil blive vist i konsollen. Lad os for eksempel analysere nuancerne:
- På listen over konti er der en “Investeringsbank”, som du ikke kan arbejde med ved hjælp af API
- Bemærk venligst, at felterne kommer i camelCase, mens disse felter i dokumentationen er præsenteret i under_score.
- Sådan vil det være overalt, så du kan ikke bare tage og kopiere et felt fra dokumentationen.
Nyttig:
- Du kan finde denne kode i projektgrenen
https://github.com/pskucherov/tcsstat/tree/step1 https://github.com/pskucherov/tcsstat/compare/step1
Tegning af data fra Tinkoff Invest API i en browser
Jeg tog next.js og socket.io. Dette er ikke en stærk anbefaling, vælg efter dit skøn.
npx create-next-app@latest npm i socket.io socket.io-client
Vi går straks videre til venskabstrinnet næste+socket+investapi, og se afsnittet Nyttigt i dette trin for alle detaljer. Jeg vil beskrive detaljerne:
- På nodejs (server) siden er der en pages/api/investapi.js fil. Det er her, vi opretter socket.io-serveren og forbinder til investapi.
- På browser (klient) side forbinder vi til serveren via en socket og anmoder om kontodata fra mægleren.
- Vi modtager data fra mægleren på serveren og sender dem derefter til klienten. Når de modtages på klienten, vises de i browseren.
Resultat: i browserkonsollen kan vi se oplysninger om konti. Det vil sige, at i det sidste trin så vi oplysninger om konti i serverkonsollen (nodejs), i det aktuelle trin overførte vi disse oplysninger til klienten (browseren).
Lad os nu gøre det, så du kan vælge en konto fra browseren, og hvis der ikke er noget token, sendes der en fejl til konsollen. Arbejdet er enkelt og intet nyt, så jeg giver kun links til commits
- https://github.com/pskucherov/tcsstat/commit/7e1ac57061e5e971588479015b06d8814d6609a9
- https://github.com/pskucherov/tcsstat/commit/b28ac973a57494f5232589b4cb6b9fb13b8af759
Nyttig:
- Hvordan man får venner næste og socket er beskrevet i detaljer her .
- Venskabskode næste+socket+investapi:
https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 For hvem ovenstående er svært, så forbliver vi på dette stadie og håndterer koden. Hvis du har spørgsmål – spørg. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2
Modtagelse af mæglerrapporter og transaktioner
Der er tre metoder til at modtage mæglerrapporter og transaktioner
Helt fra begyndelsen er det vigtigt at vide:
- Mæglerrapporten genereres i T-3-tilstand, dvs. handler vises der efter deres faktiske udførelse.
- Derfor, hvis du anmoder om denne rapport for de sidste to dage, vil den være klar om tre dage.
- For at få transaktioner for de sidste dage bruger vi metoden til at modtage transaktioner, men husk at deres id og indhold kan ændre sig efter mæglerrapporten er genereret.
GetBrokerReport
For at få en mæglerrapport skal du tage konto-id, startdato og slutdato for rapporten, dog ikke mere end 31 dage. Vi sender en anmodning om at generere en rapport til API’et i generere _broker_report_request , få et taskId som svar. Derefter får vi ved hjælp af dette opgave-id data fra get _broker_report_response.
- Du skal gemme opgave-id’et for evigt præcist for disse datoer.
- Da hvis du mister den, vil rapporten for de anmodede datoer først komme som svar på genereringsanmodningen,
- Og så kommer den slet ikke.
Metode til at få datoen under hensyntagen til subtraktionen fra den aktuelle dato
const getDateSubDay = (subDay = 5, start = true) => { const date = new Date(); date.setUTCDate(date.getUTCDate() – underdag); if (start) { date.setUTCHours(0, 0, 0, 0); } andet { date.setUTCHours(23, 59, 59, 999); } returdato; };
Anmodning om rapportgenerering
const brokerReport = await (sdk.operations.getBrokerReport)({ generateBrokerReportRequest: { accountId, from, to, }, });
Resultat:
- Som et resultat af den første udførelse af kommandoen får vi taskId.
- Rapporten begynder at blive genereret på mæglerens side. Når den er klar er ukendt, venter vi og trækker med jævne mellemrum taskId’et i forventning om rapporten.
- Hvorfor? For hvis rapporten ikke er klar, giver den en fejl. Hvis rapporten ikke er klar på mæglerens side, så er dette en fejl i din kode. Behandl venligst: 30058|INVALID_ARGUMENT|opgaven er ikke fuldført endnu, prøv venligst igen senere
Koden til at vente og modtage en rapport ser nogenlunde sådan ud.
const timer = asynkron tid => { returner nyt løfte(resolve => setTimeout(resolve, time)); } const getBrokerResponseByTaskId = async (taskId, page = 0) => { prøv { return await (sdk.operations.getBrokerReport)({ getBrokerReportRequest: { taskId, page, }, }); } catch (e) { console.log(‘vent’, e); afvent timer(10000); return await getBrokerResponseByTaskId(taskId, side); } };
Så sker den samme magi. Vi stopper vores script, starter det igen, vi har ikke noget opgave-id. Vi udfører koden med taskId-anmodningen, men vi får ikke længere taskId, men straks rapporten. Magi! Og alt ville være fint, hvis det altid var sådan. Men om en måned vil der slet ikke være nogen data. Nyttigt :
https://github.com/pskucherov/tcsstat/tree/step3.1 https://github.com/pskucherov/tcsstat/compare/step3.1
- Hvis nogen støder på dette, så velkommen til problemet . Efter at de har repareret denne magi, vil den miste sin kraft og vil på en eller anden måde være anderledes. Men i øjeblikket (21/03/2023) fungerer det bare sådan.
Få Udbytte Udenlandsk Udsteder
Nogen tror måske, at metoden ligner den forrige, og du kan bruge en enkelt metode, hvor du kun ændrer navnet på operationerne. Men de gættede ikke! Navngivningen der er meget forskellig både i metoderne og i de returnerede oplysninger. Og sidetallet starter fra 0, derefter fra 1. For ikke at blive forvirret i alt dette, er det nemmere at skrive to forskellige metoder. Hvilket er mærkeligt, fordi logikken i arbejdet er den samme. Jeg spyttede i lang tid, da jeg prøvede at lave en metode, og der var mindre kode. Der vil ikke være eksempler her.
Get OperationsByCursor
Min favorit af de tre. Selvom det ikke er den mest nøjagtige, men den mest passende. Vi fremsætter en anmodning fra begyndelsen af oprettelsen af en konto til den maksimalt mulige dato (lukning af en konto eller den nuværende). Vi får svaret, tager markøren og anmoder igen, så længe der er data. Og koden er mere kortfattet end i eksemplerne ovenfor.
const timer = asynkron tid => { returner nyt løfte(resolve => setTimeout(resolve, time)); } const getOperationsByCursor = async (sdk, accountId, from, to, cursor = ”) => { prøv { 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 = ”); } };
Udkastet til at køre er her: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 Nu er vi klar til at tilføje modtagehandlinger til vores ansøgning. Hvis det gøres korrekt, skal du få mæglerrapporter for hele kontoens eksistens. Og for de manglende data, de samme T-3’er, genindlæses fra operationer. Men dette kan opdeles i en separat artikel. Af de vigtigste nuancer, du vil støde på, er at lime operationer og en mæglerrapport.
- Hvis du i dag modtog en mæglerrapport og transaktioner for de krævede datoer, læg det hele i databasen, så er der ingen problemer.
- Du vil få problemer i morgen, når du modtager den næste del af data fra rapporten og operationerne og beslutter dig for at synkronisere dem med den eksisterende database.
- En masse nuancer om mismatch eller ændring af id efter behandling
- Så for OTC-markedet passer id’erne slet ikke.
- Samt nuancerne af synkroniseringsinstrumenter, som igen ikke er sammenfaldende, på grund af API’ens ejendommeligheder. Men det er en anden historie.
Lad os tilføje få oplysninger om operationer til vores applikation. Hovedspørgsmålet vil være, hvor dataene vil blive behandlet og opbevaret.
- Hvis du gør det for dig selv, vil du forbruge de samme data fra forskellige enheder. Så skal du behandle og gemme data på serveren.
- Hvis du har mange forskellige data, der forbruges af mange forskellige brugere, så skal du beslutte, hvad der er vigtigere: brugernes hastighed eller besparelsen af jern på din side. Den, der har råd til en uendelig mængde hardware, tæller alt på sin server og gør det superhurtigt for brugerne, hvilket sparer brugerressourcer, såsom batteri og trafik, hvilket er meget vigtigt på telefoner.
Til gengæld er optælling i browseren i princippet ikke den mest optimale løsning. Derfor, hvad der ikke er dyrt, betragter vi det på vores server. Resten overlader vi til kunden. Jeg vil virkelig gerne tage og beregne provisionen på serveren. Men her kommer nuancen kaldet “interaktivitet”. Lad os sige, at du har tusindvis af operationer, og det tager fem minutter at modtage dem. Hvad vil brugeren have på dette tidspunkt? Spinner? Fremskridt? Info om hvor meget der blev uploadet? Det er ideelt at bruge “aktiv venter”, når brugeren i processen allerede kunne se noget. Her er resultatet:
- Sideindlæsning
- Alle fakturaer efterlyses
- Derefter anmodes alle transaktioner med provision for udførte transaktioner for alle konti. Efterhånden som data modtages, gengives de i browseren.
For ikke at filtrere dataene i begivenhederne hver gang, trækker vi vores egen begivenhed for hver konto. Sådan her:
socket.emit(‘sdk:getOperationsCommissionResult_’ + accountId, { items: data?.items, inProgress: Boolean(nextCursor), });
Udkastet til lancering er her: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Gå videre. Det er dejligt, at du har læst denne linje!
Beregning og output af information af interesse
Afhænger af, hvem der har brug for hvilke oplysninger. Derfor fortæller jeg dig straks de vigtigste nuancer, du vil støde på.
Arbejder med priser
Alle, der arbejder med økonomi, ved, at pengetransaktioner kun bør udføres med hele tal. På grund af unøjagtigheden af værdier efter decimaltegnet og den kumulative fejl med et stort antal operationer. Derfor er alle priser præsenteret i følgende MoneyValue- format
Mark | type | Beskrivelse |
---|---|---|
betalingsmiddel | snor | Streng ISO valutakode |
enheder | int64 | Heltalsdel af summen kan være et negativt tal |
nano | int32 | Brøkdel af mængden, kan være et negativt tal |
Vi behandler dem separat og bringer dem derefter til prisværdien:
quotation.units + quotation.nano / 1e9
Omkostningerne ved futureskontrakter
Prisen på futures præsenteres i point, når du har en valutafuture, skal du kende kursen. Og selvfølgelig prisen i point og pristrinnet. Når du beregner overskuddet fra transaktioner, kan dette skyde, fordi. hvis du beregner det samlede beløb ved at gange prisen med mængden. Her skal du være forsigtig. Indtil videre må vi se, hvordan det går. Det gælder valutafutures, andre steder er alt ok med dette.
OTC-markedet
Dette marked har mange ejendommeligheder, så lad os studere operationer på det separat. Når du begynder at synkronisere operationer, vil det vise sig, at du skal bringe figi / ticker til samme form for at matche instrumentet korrekt. Når du begynder at synkronisere dette med kurtagerapporten, vil det vise sig, at tradeID’et for samme transaktion har bogstaver i begyndelsen i transaktionerne, og de er ikke i kurtagerapporten. Derfor kan de ikke sammenlignes … ahem-ahem … til sammenligning! Jeg matchede handelstidspunktet, ticker og matchede, at et tradeId er indeholdt i et andet. Ok, jeg ved det ikke. Den, der støder på dette, og som bekymrer sig om det, kom til sagen eller start en ny.
Matematiske operationer på værktøjer
Det er umuligt uden at kigge efter at udføre matematiske operationer med hele listen. For ikke at tilføje varm til blød, kontrollerer vi altid valutaen og behandler kun, hvis vi er sikre på, at valutaen matcher, og pointene konverteres til den ønskede valuta. Bevæbnet med viden om at arbejde med banknumre, vil vi beregne den provision brugt på hver af konti. Sådan: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4
Microservice er klar!
https://github.com/pskucherov/tcsstat Som hjemmearbejde kan du tjekke, om tjenesten fungerer med en langsom forbindelse, når forbindelser er afbrudt, når internettet er afbrudt, når fejl eller udløb af grænser fra mæglerens side.
Konklusioner og planer for fremtiden
- Lærte om grundlæggende operationer og arbejde med Invest API
- Tid brugt ~ 10 timer
- Sværhedsgrad ~ junior+ / lav mellem
Hvis du fortsætter med at forfine mikrotjenesten, kan du ende med noget som dette
https://opexbot.info
Dette er min udvikling, for dem der er for dovne til at forstå, løbe og regne på egen hånd. Jeg planlægger at tilføje analyser der efter anmodning fra brugere. Hvis du kunne lide artiklen, så abonner på min telegramkanal .
Полезная статья. Не могу представить, сколько усилий автора потребовалось, чтобы все описать. Благодарю.