Navdihniki za razvoj statistične storitve za Tinkoff Investments so bili:
- članek na Habréju “Česa Tinkoff Investments ne povedo”
- analiza želja uporabnikov platforme
- članek o obračunu provizij .
- O čem se bo razpravljalo?
- Razvoj statistične storitve korak za korakom:
- Povezava z API-jem Tinkoff Invest
- Črpanje podatkov iz Tinkoff Invest API v brskalniku
- Prejemanje posredniških poročil in transakcij
- GetBrokerReport
- Metoda za pridobitev datuma z upoštevanjem odštevanja od trenutnega datuma
- Zahteva za ustvarjanje poročila
- rezultat:
- GetDividendsForeignIssuer
- GetOperationsByCursor
- Izračun in izpis zanimivih informacij
- Delo s cenami
- Stroški terminskih pogodb
- OTC trg
- Matematične operacije na orodjih
- Mikroservis je pripravljen!
- Zaključki in načrti za prihodnost
- https://opexbot.info
O čem se bo razpravljalo?
- Samo aplikativni del o razvoju.
- Pravo znanje in izkušnje, ki so zelo pomembne pri delu s finančnimi instrumenti.
- Pregled vprašanj, na katerih je treba delati
Torej želim izračunati trgovinsko statistiko in to narediti na priročen način.
Razvoj statistične storitve korak za korakom:
- Povezava z API-jem Tinkoff Invest
- Črpanje podatkov iz Tinkoff Invest API v brskalniku
- Prejemanje posredniških poročil in transakcij
- Izračun in izpis zanimivih informacij
- Zaključki in načrti za prihodnost
Povezava z API-jem Tinkoff Invest
Za povezavo z API-jem lahko vzamete kateri koli sdk iz dokumentacije https://github.com/Tinkoff/investAPI#sdk . Ali paket npm ` tinkoff-sdk-grpc-js` . Pomembno je, da razvijalci paket posodobijo na najnovejšo različico. Namestite
npm in tinkoff-sdk-grpc-js
Preverjanje
const { createSdk } = require(‘tinkoff-sdk-grpc-js’); // Žeton, ki ga je mogoče pridobiti na ta način const TOKEN = ‘YOURAPI’; // Ime aplikacije, po kateri vas je mogoče najti v dnevnikih TCS. const appName = ‘tcsstat’; const sdk = createSdk(TOKEN, appName); (async () => { console.log(await sdk.users.getAccounts()); })();
Rezultat: v konzoli bo prikazan seznam vaših računov. Na primer, analizirajmo nianse:
- Na seznamu računov je »Investicijska banka«, s katero ne morete delati z uporabo API-ja
- Upoštevajte, da so polja v obliki camelCase, medtem ko so v dokumentaciji ta polja predstavljena v under_score.
- Povsod bo tako, zato ne morete kar vzeti in kopirati polja iz dokumentacije.
Uporabno:
- To kodo najdete v veji projekta
https://github.com/pskucherov/tcsstat/tree/step1 https://github.com/pskucherov/tcsstat/compare/step1
Črpanje podatkov iz Tinkoff Invest API v brskalniku
Vzel sem next.js in socket.io. To ni močno priporočilo, izberite po lastni presoji.
npx create-next-app@najnovejši npm i socket.io socket.io-client
Takoj nadaljujemo s korakom prijateljstva next+socket+investapi in si za vse podrobnosti oglejte razdelek Uporabno tega koraka. Opisal bom podrobnosti:
- Na strani nodejs (strežnik) je datoteka pages/api/investapi.js. Tukaj ustvarimo strežnik socket.io in se povežemo z investapi.
- Na strani brskalnika (odjemalca) se prek vtičnice povežemo s strežnikom in od posrednika zahtevamo podatke o računu.
- Podatke prejmemo od posrednika na strežniku, nato pa jih pošljemo stranki. Ko jih prejme odjemalec, se prikažejo v brskalniku.
Rezultat: v konzoli brskalnika lahko vidimo podatke o računih. Se pravi, da smo v zadnjem koraku videli podatke o računih v strežniški konzoli (nodejs), v trenutnem koraku smo te podatke prenesli v odjemalca (brskalnik).
Zdaj pa naredimo tako, da lahko izberete račun iz brskalnika in če ni žetona, se na konzolo pošlje napaka. Delo je preprosto in nič novega, zato dajem le povezave do komitov
- https://github.com/pskucherov/tcsstat/commit/7e1ac57061e5e971588479015b06d8814d6609a9
- https://github.com/pskucherov/tcsstat/commit/b28ac973a57494f5232589b4cb6b9fb13b8af759
Uporabno:
- Kako se spoprijateljiti z naslednjim in vtičnico, je podrobno opisano tukaj .
- Koda prijateljstva next+socket+investapi:
https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 Za tiste, ki jim je zgornje težko, ostanemo na tej stopnji in se ukvarjamo s kodo. Če imate vprašanja – vprašajte. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2
Prejemanje posredniških poročil in transakcij
Obstajajo trije načini za prejemanje posredniških poročil in transakcij
Že od samega začetka je pomembno vedeti:
- Borzno poročilo se ustvari v načinu T-3, t.j. posli so tam prikazani po njihovi dejanski izvedbi.
- V skladu s tem, če zahtevate to poročilo za zadnja dva dni, bo pripravljeno v treh dneh.
- Za pridobitev transakcij za zadnje dni uporabljamo metodo za prejemanje transakcij, vendar ne pozabite, da se lahko njihov ID in vsebina spremenita, ko je ustvarjeno posredniško poročilo.
GetBrokerReport
Če želite pridobiti posredniško poročilo, morate vzeti ID računa, začetni in končni datum poročila, vendar ne več kot 31 dni. API-ju pošljemo zahtevo za ustvarjanje poročila v create _broker_report_request , v odgovor prejmemo taskId. Nato z uporabo tega taskId pridobimo podatke iz get _broker_report_response.
- Natančno za te datume morate za vedno shraniti TaskID.
- Ker če ga izgubite, bo poročilo za zahtevane datume najprej prišlo kot odgovor na zahtevo za generiranje,
- In potem sploh ne pride.
Metoda za pridobitev datuma z upoštevanjem odštevanja od trenutnega datuma
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 vrnitve; };
Zahteva za ustvarjanje poročila
const brokerReport = čakaj (sdk.operations.getBrokerReport)({ generirajBrokerReportRequest: { accountId, from, to, }, });
rezultat:
- Kot rezultat prve izvedbe ukaza dobimo taskId.
- Poročilo se začne generirati na strani posrednika. Ko je pripravljen, ni znano, čakamo in občasno potegnemo taskId v pričakovanju poročila.
- Zakaj? Ker če poročilo ni pripravljeno, vrže napako. Če poročilo ni pripravljeno na strani posrednika, je to napaka v vaši kodi. Obdelajte: 30058|INVALID_ARGUMENT|opravilo še ni dokončano, poskusite znova pozneje
Koda za čakanje in prejem poročila izgleda nekako takole.
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(‘wait’, e); čakalni časovnik (10000); return await getBrokerResponseByTaskId(taskId, stran); } };
Potem se zgodi ista čarovnija. Ustavimo naš skript, ga znova zaženemo, nimamo TaskId. Izvedemo kodo z zahtevo taskId, vendar ne dobimo več taskId, ampak takoj poročilo. Čarovnija! In vse bi bilo v redu, če bi bilo vedno tako. Čez en mesec pa podatkov sploh ne bo. Uporabno :
https://github.com/pskucherov/tcsstat/tree/step3.1 https://github.com/pskucherov/tcsstat/compare/step3.1
- Če kdo naleti na to, potem dobrodošli v temi . Ko popravijo to magijo, bo izgubila svojo moč in bo nekako drugačna. A v tem trenutku (21.3.2023) deluje ravno tako.
GetDividendsForeignIssuer
Nekdo bi lahko mislil, da je metoda podobna prejšnji in lahko uporabite eno samo metodo, v kateri spremenite samo ime operacij. A niso uganili! Poimenovanje se zelo razlikuje tako v metodah kot v vrnjenih informacijah. In štetje strani se začne od 0, nato od 1. Da se ne bi zmedli pri vsem tem, je lažje napisati dve različni metodi. Kar je čudno, saj logika dela je enaka. Dolgo sem pljuval, ko sem poskušal narediti eno metodo in je bilo manj kode. Tu ne bo primerov.
GetOperationsByCursor
Moja najljubša od treh. Čeprav ni najbolj natančen, vendar najbolj primeren. Zahtevo izvajamo od začetka ustvarjanja računa do najdaljšega možnega datuma (zaprtje računa ali tekočega). Dobimo odgovor, vzamemo kazalec in ponovno zahtevamo, dokler so podatki. In koda je bolj jedrnata kot v zgornjih primerih.
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, stanje: 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 = ”); } };
Osnutek za zagon je tukaj: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 Zdaj smo pripravljeni dodati operacije prejemanja v našo aplikacijo. Če je opravljeno pravilno, potem morate pridobiti posredniška poročila za celoten obstoj računa. In za manjkajoče podatke, isti T-3, znova naložite iz operacij. Toda to je mogoče ločiti v ločenem članku. Od glavnih odtenkov, s katerimi se boste srečali, je povezovanje operacij in posredniškega poročila.
- Če ste danes prejeli posredniško poročilo in transakcije za zahtevane datume, vse to vnesite v bazo, potem ni težav.
- Težave boste imeli jutri, ko boste prejeli naslednji del podatkov iz poročila in poslovanja ter se odločili, da jih sinhronizirate z obstoječo bazo.
- Veliko nians glede neusklajenega ali spreminjanja ID-ja po obdelavi
- Za OTC trg se id-ji sploh ne ujemajo.
- Kot tudi nianse sinhronizacije instrumentov, ki spet ne sovpadajo zaradi posebnosti API-ja. Toda to je druga zgodba.
Dodajmo naši aplikaciji pridobivanje informacij o operacijah. Glavno vprašanje bo, kje se bodo podatki obdelovali in shranjevali.
- Če to storite zase, boste porabili iste podatke iz različnih naprav. Nato morate podatke obdelati in shraniti na strežnik.
- Če imate veliko različnih podatkov, ki jih porabi veliko različnih uporabnikov, potem se morate odločiti, kaj je bolj pomembno: hitrost uporabnikov ali prihranek železa na vaši strani. Kdor si lahko privošči neskončno veliko strojne opreme, šteje vse na svojem strežniku in uporabnikom naredi super hitro ter prihrani uporabniška sredstva, kot sta baterija in promet, kar je na telefonih zelo pomembno.
Po drugi strani pa štetje v brskalniku načeloma ni najbolj optimalna rešitev. Torej, kar ni drago, upoštevamo na našem strežniku. Ostalo prepustimo naročniku. Resnično želim vzeti in izračunati provizijo na strežniku. Toda tu se pojavi odtenek, imenovan »interaktivnost«. Recimo, da imate na tisoče operacij in traja pet minut, da jih prejmete. Kaj bo imel uporabnik v tem trenutku? Spinner? Napredek? Infa o tem, koliko je bilo naloženo? Idealno je uporabiti “aktivno čakanje”, ko uporabnik v procesu že lahko nekaj vidi. Tukaj je rezultat:
- Nalaganje strani
- Vsi računi so zahtevani
- Nato se za vse račune zahtevajo vse transakcije s provizijami za izvršene transakcije. Ko so podatki prejeti, se upodobijo v brskalniku.
Da ne bi vsakič filtrirali podatkov v dogodkih, za vsak račun potegnemo svoj dogodek. Všečkaj to:
socket.emit(‘sdk:getOperationsCommissionResult_’ + accountId, { items: data?.items, inProgress: Boolean(nextCursor), });
Osnutek za lansiranje je tukaj: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Nadaljujemo. Super je, da ste prebrali to vrstico!
Izračun in izpis zanimivih informacij
Odvisno od tega, kdo potrebuje kakšne informacije. Zato vam takoj povem glavne nianse, s katerimi se boste srečali.
Delo s cenami
Vsi, ki se ukvarjajo s financami, vedo, da je treba denarne transakcije izvajati samo s celimi števili. Zaradi netočnosti vrednosti za decimalno vejico in kumulativne napake pri velikem številu operacij. Zato so vse cene predstavljene v naslednjem formatu MoneyValue
polje | vrsta | Opis |
---|---|---|
valuta | vrvica | Niz kode valute ISO |
enote | int64 | Celo število vsote je lahko negativno število |
nano | int32 | Ulomek zneska je lahko negativno število |
Obdelamo jih posebej, nato jih pripeljemo do cenovne vrednosti:
kotacija.enote + kotacija.nano / 1e9
Stroški terminskih pogodb
Cena terminskih pogodb je predstavljena v točkah, ko imate valutno terminsko pogodbo, morate poznati tečaj. In seveda cena v točkah in cenovni korak. Ko računate dobiček iz transakcij, lahko to izstreli, saj. če izračunate skupni znesek tako, da pomnožite ceno s količino. Tukaj morate biti previdni. Zaenkrat bomo videli, kako bo. To velja za valutne terminske pogodbe, drugje je s tem vse v redu.
OTC trg
Ta trg ima veliko posebnosti, zato preučimo operacije na njem ločeno.Ko začnete sinhronizirati operacije, se bo izkazalo, da morate figi / ticker prinesti v isto obliko, da se pravilno ujema z instrumentom. Ko začnete to sinhronizirati s poročilom o posredovanju, se bo izkazalo, da ima tradeID iste transakcije črke na začetku v transakcijah in jih ni v poročilu o posredovanju. Zato jih ni mogoče primerjati … ah-ah … s primerjavo! Ujemal sem čas trgovanja, oznako in ujemanje, da je en tradeId vsebovan v drugem. Prav, ne vem. Kdor se s tem srečuje in ga to zanima, naj pride na temo ali začne novo.
Matematične operacije na orodjih
Brez pogleda je nemogoče izvesti matematične operacije s celotnim seznamom. Da ne dodajamo toplo k mehkemu, vedno preverimo valuto in obdelamo le, če smo prepričani, da se valuta ujema, in točke pretvorimo v želeno valuto. Oboroženi z znanjem o delu z bančnimi številkami bomo izračunali provizijo, porabljeno za vsakega od računov. Takole: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4
Mikroservis je pripravljen!
https://github.com/pskucherov/tcsstat Kot domačo nalogo lahko preverite, ali storitev deluje s počasno povezavo, ko so povezave prekinjene, ko je internetna povezava prekinjena, ko so napake ali potekle omejitve s strani posrednika.
Zaključki in načrti za prihodnost
- Spoznal osnovne operacije in delo z API-jem Invest
- Porabljen čas ~ 10 ur
- Težavnostna stopnja ~ junior+ / nizka srednja
Če nadaljujete z izpopolnjevanjem mikrostoritve, lahko na koncu dobite nekaj takega
https://opexbot.info
To je moj razvoj, za tiste, ki so preleni, da bi razumeli, tekali in računali sami. Tam nameravam dodati analitiko na zahtevo uporabnikov. Če vam je bil članek všeč, se naročite na moj telegram kanal .
Полезная статья. Не могу представить, сколько усилий автора потребовалось, чтобы все описать. Благодарю.