Inspiratori razvoja statističke usluge za Tinkoff Investments bili su:
- članak na Habréu “Što Tinkoff Investments ne govori”
- analiza želja korisnika platforme
- članak o obračunu provizija .
- O čemu će se razgovarati?
- Razvoj statističke usluge korak po korak:
- Povezivanje s Tinkoff Invest API-jem
- Crtanje podataka iz Tinkoff Invest API-ja u pregledniku
- Primanje brokerskih izvješća i transakcija
- GetBrokerReport
- Metoda dobivanja datuma, uzimajući u obzir oduzimanje od tekućeg datuma
- Zahtjev za generiranje izvješća
- Proizlaziti:
- GetDividendsForeignIssuer
- GetOperationsByCursor
- Izračun i izlaz informacija od interesa
- Rad s cijenama
- Trošak terminskih ugovora
- OTC tržište
- Matematičke operacije na alatima
- Mikroservis je spreman!
- Zaključci i planovi za budućnost
- https://opexbot.info
O čemu će se razgovarati?
- Samo primijenjeni dio o razvoju.
- Stvarno znanje i iskustvo, koji su vrlo važni u radu s financijskim instrumentima.
- Pregled problema na kojima treba raditi
Dakle, želim izračunati trgovinsku statistiku i to na prikladan način.
Razvoj statističke usluge korak po korak:
- Povezivanje s Tinkoff Invest API-jem
- Crtanje podataka iz Tinkoff Invest API-ja u pregledniku
- Primanje brokerskih izvješća i transakcija
- Izračun i izlaz informacija od interesa
- Zaključci i planovi za budućnost
Povezivanje s Tinkoff Invest API-jem
Za spajanje na API, možete uzeti bilo koji sdk iz dokumentacije https://github.com/Tinkoff/investAPI#sdk . Ili npm paket ” tinkoff-sdk-grpc-js “. Važno je da programeri ažuriraju paket na najnoviju verziju. Instalirati
npm i tinkoff-sdk-grpc-js
Provjeravanje
const { createSdk } = require(‘tinkoff-sdk-grpc-js’); // Token koji se može dobiti ovako const TOKEN = ‘YOURAPI’; // Naziv aplikacije po kojoj vas je moguće pronaći u TCS zapisima. const appName = ‘tcsstat’; const sdk = createSdk(TOKEN, appName); (async () => { console.log(await sdk.users.getAccounts()); })();
Rezultat: na konzoli će se prikazati popis vaših računa. Na primjer, analizirajmo nijanse:
- Na popisu računa nalazi se “Investicijska banka”, s kojom ne možete raditi pomoću API-ja
- Imajte na umu da polja dolaze u camelCase formatu, dok su u dokumentaciji ova polja prikazana u under_score.
- Tako će biti svugdje, tako da ne možete samo uzeti i kopirati polje iz dokumentacije.
Koristan:
- Ovaj kod možete pronaći u ogranku projekta
https://github.com/pskucherov/tcsstat/tree/step1 https://github.com/pskucherov/tcsstat/compare/step1
Crtanje podataka iz Tinkoff Invest API-ja u pregledniku
Uzeo sam next.js i socket.io. Ovo nije jaka preporuka, odaberite po vlastitom nahođenju.
npx create-next-app@najnovije npm i socket.io socket.io-client
Odmah prelazimo na korak prijateljstva next+socket+investapi i pogledajte odjeljak Korisno ovog koraka za sve detalje. Opisat ću detalje:
- Na nodejs (poslužiteljskoj) strani nalazi se datoteka pages/api/investapi.js. Ovdje kreiramo socket.io server i spajamo se na investapi.
- Na strani preglednika (klijenta), spajamo se na poslužitelj putem utičnice i tražimo podatke o računu od brokera.
- Podatke primamo od brokera na serveru, zatim ih šaljemo klijentu. Kada ih primi klijent, prikazuju se u pregledniku.
Rezultat: u konzoli preglednika možemo vidjeti podatke o računima. Odnosno, u zadnjem koraku vidjeli smo informacije o računima u konzoli poslužitelja (nodejs), u trenutnom koraku smo te informacije prenijeli na klijenta (preglednik).
Sada napravimo tako da možete odabrati račun iz preglednika, a ako nema tokena, šalje se pogreška na konzolu. Rad je jednostavan i ništa novo, pa dajem samo linkove na komitove
- https://github.com/pskucherov/tcsstat/commit/7e1ac57061e5e971588479015b06d8814d6609a9
- https://github.com/pskucherov/tcsstat/commit/b28ac973a57494f5232589b4cb6b9fb13b8af759
Koristan:
- Ovdje je detaljno opisano kako napraviti prijatelje pored i utičnicu .
- Kod prijateljstva next+socket+investapi:
https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 Kome je gore navedeno teško, ostajemo u ovoj fazi i bavimo se kodom. Ako imate pitanja – pitajte. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2
Primanje brokerskih izvješća i transakcija
Postoje tri metode za primanje brokerskih izvješća i transakcija
Od samog početka važno je znati:
- Brokersko izvješće se generira u T-3 modu, tj. trgovine se tamo prikazuju nakon njihovog stvarnog izvršenja.
- Sukladno tome, ako tražite ovaj izvještaj za posljednja dva dana, bit će spreman za tri dana.
- Da bismo dobili transakcije za posljednje dane, koristimo metodu za primanje transakcija, ali zapamtite da se njihov ID i sadržaj mogu promijeniti nakon generiranja brokerskog izvješća.
GetBrokerReport
Da biste dobili brokersko izvješće, morate uzeti ID računa, datum početka i datum završetka izvješća, ali ne više od 31 dana. Šaljemo zahtjev za generiranje izvješća API-ju u generiranju _broker_report_requesta , dobivamo taskId kao odgovor. Nakon toga, koristeći ovaj taskId, dobivamo podatke iz get _broker_report_response.
- Morate zauvijek spremiti TaskID točno za ove datume.
- Budući da ako ga izgubite, tada će za tražene datume izvješće prvo doći kao odgovor na zahtjev za generiranje,
- A onda uopće neće doći.
Metoda dobivanja datuma, uzimajući u obzir oduzimanje od tekućeg datuma
const getDateSubDay = (subDay = 5, start = true) => { const date = new Date(); date.setUTCDate(date.getUTCDate() – subDay); if (početak) { datum.setUTCHours(0, 0, 0, 0); } else { date.setUTCHours(23, 59, 59, 999); } povratni datum; };
Zahtjev za generiranje izvješća
const brokerReport = čekaj (sdk.operations.getBrokerReport)({ generirajBrokerReportRequest: { accountId, from, to, }, });
Proizlaziti:
- Kao rezultat prvog izvršavanja naredbe dobivamo taskId.
- Izvješće se počinje generirati na strani brokera. Nije poznato kada je spreman, čekamo i povremeno povlačimo taskId u iščekivanju izvješća.
- Zašto? Jer ako izvješće nije spremno, javlja se pogreška. Ako izvješće nije spremno na strani brokera, to je pogreška u vašem kodu. Obradite: 30058|INVALID_ARGUMENT|zadatak još nije dovršen, pokušajte ponovno kasnije
Kod za čekanje i primanje izvješća izgleda otprilike ovako.
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); mjerač čekanja (10000); return await getBrokerResponseByTaskId(taskId, stranica); } };
Tada se događa ista magija. Zaustavljamo našu skriptu, pokrećemo je ponovno, nemamo taskId. Izvršavamo kod sa taskId zahtjevom, ali više ne dobivamo taskId, nego odmah izvještaj. Magija! I sve bi bilo u redu da je uvijek ovako. Ali za mjesec dana neće biti nikakvih podataka. Korisno :
https://github.com/pskucherov/tcsstat/tree/step3.1 https://github.com/pskucherov/tcsstat/compare/step3.1
- Ako netko naiđe na ovo, onda dobrodošao u problem . Nakon što poprave ovu magiju, ona će izgubiti snagu i bit će nekako drugačija. Ali u trenutnom trenutku (21.3.2023.) radi baš tako.
GetDividendsForeignIssuer
Netko bi mogao pomisliti da je metoda slična prethodnoj i da možete koristiti jednu metodu u kojoj samo mijenjate nazive operacija. Ali nisu pogodili! Imenovanje je vrlo različito iu metodama iu vraćenim informacijama. I broj stranica počinje od 0, pa od 1. Da se ne bi zabunili u svemu tome, lakše je napisati dvije različite metode. Što je čudno, jer logika rada je ista. Dugo sam pljuvao kad sam pokušao napraviti jednu metodu i bilo je manje koda. Ovdje neće biti primjera.
GetOperationsByCursor
Moj favorit od njih tri. Iako ne najprecizniji, ali najadekvatniji. Zahtjev vršimo od početka kreiranja računa do maksimalno mogućeg datuma (zatvaranje računa ili tekućeg). Dobivamo odgovor, uzimamo kursor i ponovno tražimo sve dok ima podataka. A kôd je koncizniji nego u gornjim primjerima.
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 = ”); } };
Nacrt za pokretanje je ovdje: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 Sada smo spremni dodati operacije primanja u našu aplikaciju. Ako je učinjeno ispravno, tada morate dobiti brokerska izvješća za cijelo postojanje računa. A za podatke koji nedostaju, ti isti T-3, ponovno učitavanje iz operacija. Ali to se može izdvojiti u poseban članak. Od glavnih nijansi s kojima ćete se susresti je spajanje operacija i brokerskog izvješća.
- Ako ste danas dobili brokersko izvješće i transakcije za tražene datume, sve to stavite u bazu, onda nema problema.
- Probleme ćete imati sutra kada dobijete sljedeću porciju podataka iz izvješća i poslovanja i odlučite ih sinkronizirati s postojećom bazom.
- Puno nijansi o nepodudaranju ili promjeni ID-a nakon obrade
- Onda za OTC tržište, id-ovi se uopće ne podudaraju.
- Kao i nijanse sinkronizacije instrumenata, koje se opet ne podudaraju, zbog osobitosti API-ja. Ali to je druga priča.
Dodajmo našoj aplikaciji dobivanje informacija o operacijama. Glavno pitanje bit će gdje će se podaci obrađivati i pohranjivati.
- Ako to radite za sebe, trošit ćete iste podatke s različitih uređaja. Zatim trebate obraditi i pohraniti podatke na poslužitelj.
- Ako imate puno različitih podataka koje konzumira mnogo različitih korisnika, tada morate odlučiti što je važnije: brzina korisnika ili ušteda željeza na vašoj strani. Tko god si može priuštiti beskonačnu količinu hardvera, sve broji na svom serveru i čini ga super brzim za korisnike, štedeći korisničke resurse, poput baterije i prometa, što je jako bitno na telefonima.
Zauzvrat, brojanje u pregledniku u načelu nije najoptimalnije rješenje. Stoga ono što nije skupo smatramo na našem poslužitelju. Ostalo prepuštamo klijentu. Stvarno želim uzeti i izračunati proviziju na serveru. Ali ovdje dolazi nijansa zvana “interaktivnost”. Recimo da imate tisuće operacija i potrebno je pet minuta da ih primite. Što će korisnik imati u ovom trenutku? Spinner? Napredak? Informacije o tome koliko je uploadano? Idealno je koristiti “aktivno čekanje” kada korisnik u procesu već može nešto vidjeti. Evo rezultata:
- Stranica se učitava
- Sve fakture su tražene
- Nakon toga se za sve račune traže sve transakcije s provizijama za izvršene transakcije. Kako se podaci primaju, oni se prikazuju u pregledniku.
Kako ne bismo svaki put filtrirali podatke u događajima, povlačimo vlastiti događaj za svaki račun. Kao ovo:
socket.emit(‘sdk:getOperationsCommissionResult_’ + accountId, { items: data?.items, inProgress: Boolean(nextCursor), });
Nacrt za pokretanje je ovdje: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Idemo dalje. Sjajno je što ste pročitali ovaj redak!
Izračun i izlaz informacija od interesa
Ovisi kome koja informacija treba. Stoga vam odmah kažem glavne nijanse s kojima ćete se susresti.
Rad s cijenama
Svi koji se bave financijama znaju da se novčane transakcije smiju obavljati samo s cijelim brojevima. Zbog netočnosti vrijednosti iza decimalne točke i kumulativne pogreške s velikim brojem operacija. Zbog toga su sve cijene prikazane u sljedećem MoneyValue formatu
polje | tip | Opis |
---|---|---|
valuta | niz | String ISO kod valute |
jedinice | int64 | Cjelobrojni dio zbroja, može biti negativan broj |
nano | int32 | Razlomak iznosa, može biti negativan broj |
Posebno ih obrađujemo, a zatim dovodimo do cjenovne vrijednosti:
kotacija.jedinice + kotacija.nano / 1e9
Trošak terminskih ugovora
Cijena fjučersa prikazana je u bodovima, kada imate valutni fjučers, morate znati stopu. I naravno cijena u bodovima i cjenovni korak. Kada izračunate dobit od transakcija, ovo može pucati, jer. ako ukupni iznos izračunate množenjem cijene s količinom. Ovdje morate biti oprezni. Za sada ćemo vidjeti kako će ići. Ovo se odnosi na valutne fjučerse, na drugim mjestima s ovim je sve u redu.
OTC tržište
Ovo tržište ima puno posebnosti, pa proučimo operacije na njemu posebno.Kada počnete sinkronizirati operacije, ispostavit će se da trebate dovesti figi / ticker u isti oblik kako biste ispravno uskladili instrument. Kada to počnete sinkronizirati s brokerskim izvješćem, ispostavit će se da tradeID iste transakcije ima slova na početku u transakcijama, a nema ih u brokerskom izvješću. Stoga se ne mogu uspoređivati … ajme-ajme … usporedbom! Usporedio sam vrijeme trgovine, ticker i podudaranje da je jedan tradeId sadržan u drugom. Da, ne znam. Tko se s tim susreće i kome je stalo do toga, neka dođe na broj ili započne novi.
Matematičke operacije na alatima
Nemoguće je, bez gledanja, izvesti matematičke operacije s cijelim popisom. Kako ne bismo dodavali toplo na meko, uvijek provjeravamo valutu i obrađujemo samo ako smo sigurni da valuta odgovara, a bodovi se pretvaraju u željenu valutu. Naoružani znanjem o radu s bankovnim brojevima, izračunat ćemo proviziju potrošenu na svakom od računa. Ovako: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4
Mikroservis je spreman!
https://github.com/pskucherov/tcsstat Kao domaću zadaću možete provjeriti radi li usluga sa sporom vezom, kada su veze prekinute, kada je internet prekinut, kada su pogreške ili istekli limiti od strane brokera.
Zaključci i planovi za budućnost
- Naučili o osnovnim operacijama i radu s Invest API-jem
- Utrošeno vrijeme ~ 10 sati
- Razina težine ~ junior+ / niska srednja
Ako nastavite usavršavati mikroservis, mogli biste završiti s nečim ovakvim
https://opexbot.info
Ovo je moj razvoj, za one koji su previše lijeni da razumiju, trče i računaju sami. Planiram tamo dodati analitiku na zahtjev korisnika. Ako vam se članak svidio, pretplatite se na moj telegram kanal .
Полезная статья. Не могу представить, сколько усилий автора потребовалось, чтобы все описать. Благодарю.