De ynspirators efter de ûntwikkeling fan ‘e statistyktsjinst foar Tinkoff Investments wiene:
- artikel oer Habré “Wat Tinkoff Investments net sizze”
- analyze fan ‘e winsken fan platfoarm brûkers
- in artikel oer de berekkening fan kommisjes .
- Wat sil besprutsen wurde?
- Stap foar stap in statistyktsjinst ûntwikkelje:
- Ferbining mei Tinkoff Invest API
- Gegevens tekenje fan Tinkoff Invest API yn in browser
- Untfange brokerage rapporten en transaksjes
- GetBrokerReport
- Metoade foar it krijen fan de datum, rekken hâldend mei de subtraksje fan ‘e aktuele datum
- Rapport generaasje fersyk
- Resultaat:
- GetDividends Foreign Issuer
- GetOperationsByCursor
- Berekkening en útfier fan ynformaasje fan belang
- Wurkje mei prizen
- De kosten fan futureskontrakten
- OTC merk
- Wiskundige operaasjes op ark
- Microservice is klear!
- Konklúzjes en plannen foar de takomst
- https://opexbot.info
Wat sil besprutsen wurde?
- Allinnich it tapaste diel oer ûntwikkeling.
- Echte kennis en ûnderfining, dy’t tige wichtich binne by it wurkjen mei finansjele ynstruminten.
- Oersjoch fan saken om oan te wurkjen
Dat, ik wol hannelsstatistiken berekkenje en it op in handige manier dwaan.
Stap foar stap in statistyktsjinst ûntwikkelje:
- Ferbining mei Tinkoff Invest API
- Gegevens tekenje fan Tinkoff Invest API yn in browser
- Untfange brokerage rapporten en transaksjes
- Berekkening en útfier fan ynformaasje fan belang
- Konklúzjes en plannen foar de takomst
Ferbining mei Tinkoff Invest API
Om te ferbinen mei de API, kinne jo elke sdk nimme fan ‘e dokumintaasje https://github.com/Tinkoff/investAPI#sdk . Of npm-pakket ` tinkoff-sdk-grpc-js `. It is wichtich dat it pakket wurdt bywurke nei de lêste ferzje troch de ûntwikkelders. Ynstallearje
npm en tinkoff-sdk-grpc-js
Kontrolearje
const { createSdk } = require(‘tinkoff-sdk-grpc-js’); // Token dat kin wurde krigen as dizze const TOKEN = ‘YOURAPI’; // De namme fan de applikaasje wêrmei jo te finen binne yn de TCS-logs. const appName = ‘tcsstat’; const sdk = createSdk(TOKEN, appName); (async () => { console.log(await sdk.users.getAccounts()); })();
Resultaat: in list fan jo akkounts sil wurde werjûn yn ‘e konsole. Litte wy bygelyks de nuânses analysearje:
- Yn ‘e list mei akkounts is d’r in “Ynvestearringsbank”, wêrmei jo net kinne wurkje mei de API
- Tink derom dat de fjilden komme yn camelCase, wylst yn ‘e dokumintaasje dizze fjilden wurde presintearre yn under_score.
- It sil oeral sa wêze, dus jo kinne net gewoan in fjild nimme en kopiearje fan ‘e dokumintaasje.
Brûkber:
- Jo kinne dizze koade fine yn ‘e projekttak
https://github.com/pskucherov/tcsstat/tree/step1 https://github.com/pskucherov/tcsstat/compare/step1
Gegevens tekenje fan Tinkoff Invest API yn in browser
Ik naam next.js en socket.io. Dit is gjin sterke oanbefelling, kies nei jo goedtinken.
npx create-next-app@latest npm i socket.io socket.io-client
Wy geane daliks troch nei de freonskipsstap folgjende+socket+investapi, en sjoch de Nuttige seksje fan dizze stap foar alle details. Ik sil de details beskriuwe:
- Oan de nodejs (tsjinner) kant, der is in pages/api/investapi.js triem. Dit is wêr’t wy de socket.io-tsjinner meitsje en ferbine mei investapi.
- Oan ‘e side fan’ e browser (kliïnt) ferbine wy mei de tsjinner fia in socket en freegje accountgegevens fan ‘e makelder.
- Wy ûntfange gegevens fan ‘e brokker op’ e tsjinner, en stjoere it dan nei de kliïnt. As se wurde ûntfongen op ‘e kliïnt, wurde se werjûn yn’ e browser.
Resultaat: yn ‘e browserkonsole kinne wy ynformaasje oer akkounts sjen. Dat is, yn ‘e lêste stap seagen wy ynformaasje oer akkounts yn’ e serverkonsole (nodejs), yn ‘e aktuele stap hawwe wy dizze ynformaasje oerbrocht nei de kliïnt (browser).
No litte wy it sa meitsje dat jo in akkount kinne selektearje fan ‘e browser, en as d’r gjin token is, dan wurdt in flater stjoerd nei de konsole. It wurk is ienfâldich en neat nij, dus ik jou allinnich keppelings nei commits
- https://github.com/pskucherov/tcsstat/commit/7e1ac57061e5e971588479015b06d8814d6609a9
- https://github.com/pskucherov/tcsstat/commit/b28ac973a57494f5232589b4cb6b9fb13b8af759
Brûkber:
- Hoe meitsje freonen folgjende en socket wurdt beskreaun yn detail hjir .
- Freonskipskoade folgjende+socket+investapi:
https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 Foar wa’t it boppesteande dreech is, dan bliuwe wy op dit poadium en omgean mei de koade. As jo fragen hawwe – freegje. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2
Untfange brokerage rapporten en transaksjes
D’r binne trije metoaden om brokeragerapporten en transaksjes te ûntfangen
Fan it begjin ôf is it wichtich om te witten:
- It brokeragerapport wurdt generearre yn ‘e T-3-modus, d.w.s. hannelingen wurde dêr werjûn nei har eigentlike útfiering.
- Dêrom, as jo dit rapport foar de lêste twa dagen oanfreegje, sil it oer trije dagen klear wêze.
- Om deals te meitsjen foar de lêste dagen, brûke wy de metoade foar it ûntfangen fan operaasjes, mar tink derom dat har id en ynhâld kinne feroarje nei de foarming fan it brokeragerapport.
GetBrokerReport
Om in makelderrapport te krijen, moatte jo de akkount-id, startdatum en eindatum fan it rapport nimme, mar net mear as 31 dagen. Wy stjoere in fersyk om in rapport te generearjen nei de API yn generearje _broker_report_request , krije in taskId as antwurd. Dêrnei krije wy, mei dizze taakId, gegevens fan get _broker_report_response.
- Jo moatte de TaskID foar altyd krekt foar dizze datums bewarje.
- Sûnt as jo it ferlieze, dan sil it rapport foar de oanfrege datums earst komme yn reaksje op it generaasjefersyk,
- En dan komt it hielendal net.
[/ spoiler] Lit ús begjinne te skriuwen koade
Metoade foar it krijen fan de datum, rekken hâldend mei de subtraksje fan ‘e aktuele datum
const getDateSubDay = (subDay = 5, start = true) => { const date = new Date(); date.setUTCDate(date.getUTCDate() – subDay); if (start) { date.setUTCHours(0, 0, 0, 0); } else { date.setUTCHours(23, 59, 59, 999); } datum werom; };
Rapport generaasje fersyk
const brokerReport = await (sdk.operations.getBrokerReport)({ generBrokerReportRequest: { accountId, from, to, }, });
Resultaat:
- As gefolch fan ‘e earste útfiering fan it kommando krije wy de taskId.
- It rapport begjint te generearjen oan ‘e kant fan’ e makelder. As it klear is is ûnbekend, wy wachtsje en periodyk lûke de taskId yn ôfwachting fan it rapport.
- Wêrom? Want as it rapport net klear is, smyt it in flater. As it rapport net klear is oan ‘e kant fan’ e makelder, dan is dit in flater yn jo koade. Ferwurkje asjebleaft: 30058|INVALID_ARGUMENT|taak noch net foltôge, besykje it letter nochris
De koade foar it wachtsjen en ûntfangen fan in rapport sjocht der sa út.
const timer = async time => { 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(‘wachtsje’, e); wachtsje op timer (10000); return await getBrokerResponseByTaskId(taskId, page); } };
Dan bart deselde magy. Wy stopje ús skript, begjinne it opnij, wy hawwe gjin taskId. Wy útfiere de koade mei de taskId fersyk, mar wy krije net mear de taskId, mar daliks it rapport. Magic! En alles soe goed wêze as it altyd sa wie. Mar oer in moanne sille d’r hielendal gjin gegevens wêze. Nuttich :
- In bytsje teory wurdt sketst hjir en hjir .
- Troch de koade byinoar te setten, sil it ûntwerp der sa útsjen.
https://github.com/pskucherov/tcsstat/tree/step3.1 https://github.com/pskucherov/tcsstat/compare/step3.1
- As immen dit tsjinkomt, wolkom by it probleem . Nei’t se dizze magy reparearje, sil it syn krêft ferlieze en sil it op ien of oare manier oars wêze. Mar op it stuit (21/03/2023) wurket it krekt sa.
GetDividends Foreign Issuer
Immen kin tinke dat de metoade fergelykber is mei de foarige en jo kinne ien metoade brûke wêryn jo allinich de namme fan ‘e operaasjes feroarje. Mar se rieden net! De nammejouwing dêr is hiel oars sawol yn de metoaden as yn de weromjûn ynformaasje. En it oantal siden begjint fan 0, dan fan 1. Om net yn ‘e war te reitsjen yn dit alles, is it makliker om twa ferskillende metoaden te skriuwen. Wat nuver is, want de logika fan it wurk is itselde. Ik spatte foar in lange tiid doe’t ik besocht te meitsjen ien metoade en der wie minder koade. D’r sille hjir gjin foarbylden wêze.
GetOperationsByCursor
Myn favorite fan de trije. Hoewol net de meast krekte, mar de meast adekwate. Wy meitsje in fersyk fan it begjin fan it oanmeitsjen fan in akkount oant de maksimale mooglike datum (in akkount slute as de aktuele). Wy krije it antwurd, nim de rinnerke en freegje opnij sa lang as der gegevens binne. En de koade is koarter dan yn ‘e foarbylden hjirboppe.
const timer = async time => { 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, withoutTrades: falsk, sûnderOvernights: falsk, rinnerke, }; return await sdk.operations.getOperationsByCursor(reqData); } catch (e) { await timer(60000); return await getOperationsByCursor(sdk, accountId, from, to, cursor = ”); } };
It ûntwerp om te rinnen is hjir: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 No binne wy klear om ûntfangstaksjes ta te foegjen oan ús applikaasje. As jo korrekt dien binne, dan moatte jo brokeragerapporten krije foar it heule bestean fan it akkount. En foar de ûntbrekkende gegevens, dy deselde T-3’s, opnij laden fan operaasjes. Mar dit kin wurde skieden yn in apart artikel. Fan ‘e wichtichste nuânses dy’t jo sille tsjinkomme is om operaasjes en in makelderrapport te lijmen.
- As jo hjoed in brokeragerapport en transaksjes hawwe krigen foar de fereaske datums, set it allegear yn ‘e databank, dan binne d’r gjin problemen.
- Jo sille moarn problemen hawwe as jo it folgjende diel fan gegevens ûntfange fan it rapport en operaasjes en beslute om se te syngronisearjen mei de besteande databank.
- In protte nuânses oer net oerienkommende of feroarjende id nei ferwurking
- Dan foar de OTC-merk komme de id’s hielendal net oerien.
- Lykas de nuânses fan syngronisearjende ynstruminten, dy’t wer net gearfalle, troch de eigenaardichheden fan ‘e API. Mar dat is in oar ferhaal.
Litte wy ynformaasje oer operaasjes tafoegje oan ús applikaasje. De wichtichste fraach sil wêze wêr’t de gegevens wurde ferwurke en opslein.
- As jo it foar josels dogge, sille jo deselde gegevens fan ferskate apparaten konsumearje. Dan moatte jo gegevens ferwurkje en opslaan op ‘e tsjinner.
- As jo in protte ferskillende gegevens hawwe konsumearre troch in protte ferskillende brûkers, dan moatte jo beslute wat wichtiger is: de snelheid fan ‘e brûkers of it besparjen fan izer oan jo kant. Wa’t in ûneinige hoemannichte hardware kin betelje, telt alles op syn server en makket it supersnel foar brûkers, en besparret de brûkersboarnen, lykas batterij en ferkear, wat heul wichtich is op tillefoans.
Op syn beurt is tellen yn ‘e browser yn prinsipe net de meast optimale oplossing. Dêrom, wat net djoer is, beskôgje wy it op ús server. De rest litte wy oer oan de klant. Ik wol echt nimme en berekkenje de kommisje op de tsjinner. Mar hjir komt de nuânse neamd “ynteraktiviteit”. Litte wy sizze dat jo tûzenen operaasjes hawwe en it duorret fiif minuten om se te ûntfangen. Wat sil de brûker op dit stuit hawwe? Spinner? Foarútgong? Infa oer hoefolle waard upload? It is ideaal om “aktyf wachtsjen” te brûken as de brûker yn it proses al wat koe sjen. Hjir is it resultaat:
- Side laden
- Alle faktueren wurde frege
- Dêrnei wurde alle transaksjes mei kommisjes foar útfierde transaksjes oanfrege foar alle akkounts. As gegevens wurde ûntfongen, wurde se yn ‘e browser werjûn.
Om de gegevens net elke kear yn ‘e eveneminten te filterjen, lûke wy ús eigen evenemint foar elk akkount. Lykas dit:
socket.emit(‘sdk:getOperationsCommissionResult_’ + accountId, { items: data?.items, inProgress: Boolean(nextCursor), });
It ûntwerp om te lansearjen is hjir: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Trochgean. It is geweldich dat jo dizze rigel lêzen hawwe!
Berekkening en útfier fan ynformaasje fan belang
It hinget ôf fan wa’t nedich hokker ynformaasje. Dêrom fertel ik jo fuortendaliks de wichtichste nuânses dy’t jo sille tsjinkomme.
Wurkje mei prizen
Eltsenien dy’t wurket mei finânsjes wit dat jild transaksjes moatte wurde útfierd allinnich mei hiele sifers. Fanwege de ûnkrektens fan wearden nei it desimaal punt en de kumulative flater mei in grut oantal operaasjes. Dêrom wurde alle prizen presintearre yn it folgjende MoneyValue- formaat
fjild | type | Beskriuwing |
---|---|---|
muntsoarte | string | String ISO faluta koade |
units | ynt64 | Integer diel fan ‘e som, kin in negatyf getal wêze |
nano | ynt32 | Fraksjoneel diel fan it bedrach, kin in negatyf getal wêze |
Wy ferwurkje se apart, bringe se dan nei de priiswearde:
quotation.units + quotation.nano / 1e9
De kosten fan futureskontrakten
De priis fan futures wurdt presintearre yn punten, as jo in faluta takomst hawwe, moatte jo it taryf witte. En fansels de priis yn punten en de priisstap. As jo berekkenje de winst út transaksjes, dit kin sjitte, omdat. as jo it totale bedrach berekkenje troch de priis te fermannichfâldigjen mei de kwantiteit. Hjir moatte jo foarsichtich wêze. Foar no sille wy sjen hoe’t it giet. Dat jildt foar faluta futures, op oare plakken is alles ok mei dit.
OTC merk
Dizze merk hat in protte eigenaardichheden, dus litte wy de operaasjes derop apart studearje. As jo begjinne mei syngronisearjen fan operaasjes, sil it blike dat jo figi / ticker yn deselde foarm moatte bringe om it ynstrumint korrekt te passen. As jo begjinne mei it syngronisearjen fan dit mei it brokeragerapport, sil it blike dat de tradeID fan deselde transaksje letters oan it begjin hat yn ‘e transaksjes en se binne net yn it brokeragerapport. Dêrom kinne se net fergelike wurde … ahem-ahem … by ferliking! Ik kom oerien mei de hannel tiid, ticker en oerienkommende dat iene tradeId is befette yn in oar. Krekt, ik wit it net. Wa’t dit tsjinkomt en wa’t der om docht, kom nei de kwestje of begjin in nij.
Wiskundige operaasjes op ark
It is ûnmooglik, sûnder te sjen, wiskundige operaasjes út te fieren mei de heule list. Om net te foegjen waarm oan sêft, wy altyd kontrolearje de faluta en proses allinne as wy binne wis dat de faluta oerienkomt, en de punten wurde omboud ta de winske faluta. Bewapene mei kennis oer wurkjen mei banknûmers, sille wy de kommisje berekkenje dy’t bestege oan elk fan ‘e akkounts. Lykas dit: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4
Microservice is klear!
https://github.com/pskucherov/tcsstat As húswurk kinne jo kontrolearje oft de tsjinst wurket mei in stadige ferbining, as ferbiningen binne brutsen, as it ynternet is loskeppele, as flaters of ferrûne grinzen fan ‘e kant fan’ e brokker.
Konklúzjes en plannen foar de takomst
- Learre oer basis operaasjes en wurkje mei de Invest API
- Tiid bestege ~ 10 oeren
- Schwierichheidsnivo ~ junior+ / leech midden
As jo trochgean mei it ferfine fan ‘e mikrotsjinst, kinne jo mei soksoarte einigje
https://opexbot.info
Dit is myn ûntwikkeling, foar dyjingen dy’t te lui binne om sels te begripen, te rinnen en te rekkenjen. Ik plan om analytics dêr ta te foegjen op fersyk fan brûkers. As jo it artikel leuk fine, abonnearje dan op myn telegramkanaal .
Полезная статья. Не могу представить, сколько усилий автора потребовалось, чтобы все описать. Благодарю.