De inspirators achter de ontwikkeling van de statistische dienst voor Tinkoff Investments waren:
- artikel over Habré “Wat Tinkoff Investments niet zegt”
- analyse van de wensen van platformgebruikers
- een artikel over de berekening van provisies .
- Wat wordt er besproken?
- Stap voor stap een statistiekdienst ontwikkelen:
- Verbinding met de Tinkoff Invest-API
- Gegevens uit de Tinkoff Invest API in een browser halen
- Het ontvangen van makelaarsrapporten en transacties
- GetBrokerReport
- Methode om de datum te krijgen, rekening houdend met de aftrekking van de huidige datum
- Verzoek om rapport te genereren
- Resultaat:
- GetDividendsForeignIssuer
- GetOperationsByCursor
- Berekening en output van informatie van belang
- Werken met prijzen
- De kosten van termijncontracten
- OTC-markt
- Wiskundige bewerkingen op gereedschappen
- Microservice is er klaar voor!
- Conclusies en plannen voor de toekomst
- https://opexbot.info
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:
- Verbinding met de Tinkoff Invest-API
- Gegevens uit de Tinkoff Invest API in een browser halen
- Het ontvangen van makelaarsrapporten en transacties
- Berekening en output van informatie van belang
- 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:
- 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).
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
- https://github.com/pskucherov/tcsstat/commit/7e1ac57061e5e971588479015b06d8814d6609a9
- 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
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.
- 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.
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:
- 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- formaat
veld | type | Beschrijving |
---|---|---|
munteenheid | snaar | String ISO-valutacode |
eenheden | int64 | Integer deel van de som, kan een negatief getal zijn |
nano | int32 | Een 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.
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.
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…step4
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 .
Полезная статья. Не могу представить, сколько усилий автора потребовалось, чтобы все описать. Благодарю.