Inšpirátormi za vývojom štatistickej služby pre Tinkoff Investments boli:
- článok o Habrém „Čo Tinkoff Investments nehovorí“
- analýza želaní používateľov platformy
- článok o výpočte provízií .
- O čom sa bude diskutovať?
- Vývoj štatistickej služby krok za krokom:
- Pripojenie k Tinkoff Invest API
- Čerpanie údajov z Tinkoff Invest API v prehliadači
- Prijímanie maklérskych správ a transakcií
- GetBrokerReport
- Metóda získania dátumu, berúc do úvahy odpočet od aktuálneho dátumu
- Žiadosť o generovanie správy
- výsledok:
- GetDividendsForeignIssuer
- GetOperationsByCursor
- Výpočet a výstup zaujímavých informácií
- Práca s cenami
- Náklady na futures kontrakty
- OTC trh
- Matematické operácie na nástrojoch
- Mikroservis je pripravený!
- Závery a plány do budúcnosti
- https://opexbot.info
O čom sa bude diskutovať?
- Iba aplikovaná časť o vývoji.
- Skutočné znalosti a skúsenosti, ktoré sú pri práci s finančnými nástrojmi veľmi dôležité.
- Prehľad problémov, na ktorých treba pracovať
Chcem teda vypočítať obchodné štatistiky a urobiť to pohodlným spôsobom.
Vývoj štatistickej služby krok za krokom:
- Pripojenie k Tinkoff Invest API
- Čerpanie údajov z Tinkoff Invest API v prehliadači
- Prijímanie maklérskych správ a transakcií
- Výpočet a výstup zaujímavých informácií
- Závery a plány do budúcnosti
Pripojenie k Tinkoff Invest API
Ak sa chcete pripojiť k API, môžete si vziať akékoľvek sdk z dokumentácie https://github.com/Tinkoff/investAPI#sdk . Alebo balík npm ` tinkoff-sdk-grpc-js `. Je dôležité, aby vývojári aktualizovali balík na najnovšiu verziu. Inštalácia
npm a tinkoff-sdk-grpc-js
Kontrola
const { createSdk } = require(‘tinkoff-sdk-grpc-js’); // Token, ktorý možno získať takto const TOKEN = ‘YOURAPI’; // Názov aplikácie, pod ktorou vás možno nájsť v protokoloch TCS. const appName = ‘tcsstat’; const sdk = createSdk(TOKEN, názov aplikácie); (async () => { console.log(wait sdk.users.getAccounts()); })();
Výsledok: v konzole sa zobrazí zoznam vašich účtov. Napríklad analyzujme nuansy:
- V zozname účtov je „Investičná banka“, s ktorou nemôžete pracovať pomocou API
- Upozorňujeme, že polia prichádzajú v tvare camelCase, zatiaľ čo v dokumentácii sú tieto polia uvedené v podhodnote.
- Bude to tak všade, takže nemôžete len vziať a skopírovať pole z dokumentácie.
Užitočné:
- Tento kód nájdete vo vetve projektu
https://github.com/pskucherov/tcsstat/tree/step1 https://github.com/pskucherov/tcsstat/compare/step1
Čerpanie údajov z Tinkoff Invest API v prehliadači
Vzal som next.js a socket.io. Toto nie je silné odporúčanie, vyberte si podľa vlastného uváženia.
npx create-next-app@latest npm i socket.io socket.io-client
Okamžite prejdeme na krok priateľstva next+socket+investapi a všetky podrobnosti nájdete v časti Užitočné tohto kroku. Opíšem podrobnosti:
- Na strane nodejs (serveru) je súbor pages/api/investapi.js. Tu vytvoríme server socket.io a pripojíme sa k investapi.
- Na strane prehliadača (klienta) sa pripojíme k serveru cez socket a vyžiadame si od brokera údaje o účte.
- Údaje od makléra dostaneme na server a následne ich pošleme klientovi. Keď sú prijaté na klientovi, zobrazia sa v prehliadači.
Výsledok: v konzole prehliadača môžeme vidieť informácie o účtoch. To znamená, že v poslednom kroku sme videli informácie o účtoch v konzole servera (nodejs), v aktuálnom kroku sme tieto informácie preniesli do klienta (prehliadača).
Teraz to urobme tak, že si môžete vybrať účet z prehliadača a ak neexistuje žiadny token, do konzoly sa odošle chyba. Práca je jednoduchá a nič nové, preto uvádzam len odkazy na commity
- https://github.com/pskucherov/tcsstat/commit/7e1ac57061e5e971588479015b06d8814d6609a9
- https://github.com/pskucherov/tcsstat/commit/b28ac973a57494f5232589b4cb6b9fb13b8af759
Užitočné:
- Ako získať priateľov ďalej a zásuvku je podrobne popísané tu .
- Kód priateľstva next+socket+investapi:
https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 Pre koho je vyššie uvedené ťažké, potom zostávame v tejto fáze a zaoberáme sa kódom. Ak máte otázky – pýtajte sa. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2
Prijímanie maklérskych správ a transakcií
Existujú tri spôsoby prijímania maklérskych správ a transakcií
Od samého začiatku je dôležité vedieť:
- Správa o sprostredkovaní sa generuje v režime T-3, t.j. obchody sa tam zobrazujú po ich skutočnom vykonaní.
- Ak si teda vyžiadate tento prehľad za posledné dva dni, bude pripravený do troch dní.
- Na získanie transakcií za posledné dni používame metódu prijímania transakcií, ale nezabudnite, že ich ID a obsah sa môžu po vygenerovaní správy o sprostredkovaní zmeniť.
GetBrokerReport
Ak chcete získať správu o sprostredkovaní, musíte uviesť ID účtu, dátum začiatku a dátum ukončenia správy, ale nie viac ako 31 dní. Požiadavku na vygenerovanie prehľadu odošleme do rozhrania API v generácii _broker_report_request , ako odpoveď dostaneme taskId. Potom pomocou tohto taskId získame údaje z get _broker_report_response.
- Musíte uložiť TaskID navždy presne pre tieto dátumy.
- Pretože ak ho stratíte, pre požadované dátumy sa správa najskôr zobrazí ako odpoveď na žiadosť o generovanie,
- A potom to nepríde vôbec.
Metóda získania dátumu, berúc do úvahy odpočet od aktuálneho dátumu
const getDateSubDay = (subDay = 5, začiatok = true) => { const date = new Date(); dátum.setUTCDate(dátum.getUTCDate() – poddeň); if (start) { date.setUTCHours(0, 0, 0, 0); } else { date.setUTCHours(23, 59, 59, 999); } dátum návratu; };
Žiadosť o generovanie správy
const brokerReport = wait (sdk.operations.getBrokerReport)({ createBrokerReportRequest: { accountId, from, to, }, });
výsledok:
- V dôsledku prvého vykonania príkazu získame taskId.
- Report sa začne generovať na strane brokera. Keď nie je známe, že je pripravený, počkáme a pravidelne stiahneme taskId v očakávaní správy.
- prečo? Pretože ak zostava nie je pripravená, vyhodí chybu. Ak správa nie je pripravená na strane makléra, ide o chybu vo vašom kóde. Spracujte prosím: 30058|INVALID_ARGUMENT|úloha ešte nie je dokončená, skúste to znova neskôr
Kód čakania a prijatia hlásenia vyzerá asi takto.
const timer = async time => { return new Promise(resolve => setTimeout(resolve, time)); } const getBrokerResponseByTaskId = async (taskId, page = 0) => { try { return wait (sdk.operations.getBrokerReport)({ getBrokerReportRequest: { taskId, page, }, }); } catch (e) { console.log(‘wait’, e); časovač čakania (10000); return wait getBrokerResponseByTaskId(taskId, page); } };
Potom sa stane rovnaká mágia. Zastavíme náš skript, spustíme ho znova, nemáme taskId. Spustíme kód s požiadavkou taskId, ale už nedostaneme taskId, ale hneď správu. Kúzlo! A všetko by bolo v poriadku, keby to tak bolo vždy. Ale o mesiac tam nebudú vôbec žiadne dáta. Užitočné :
https://github.com/pskucherov/tcsstat/tree/step3.1 https://github.com/pskucherov/tcsstat/compare/step3.1
- Ak sa s tým niekto stretne, vitajte v problematike . Keď túto mágiu opravia, stratí svoju silu a bude akosi iná. Ale momentálne (21.3.2023) to funguje presne tak.
GetDividendsForeignIssuer
Niekto by si mohol myslieť, že metóda je podobná predchádzajúcej a môžete použiť jednu metódu, v ktorej zmeníte iba názov operácií. Ale neuhádli! Pomenovanie sa tam veľmi líši v metódach aj vo vrátených informáciách. A počet strán začína od 0, potom od 1. Aby ste sa v tom všetkom nezamotali, je jednoduchšie napísať dve rôzne metódy. Čo je zvláštne, pretože logika práce je rovnaká. Pľuval som dlho, keď som sa snažil urobiť jednu metódu a bolo tam menej kódu. Nebudú tu žiadne príklady.
GetOperationsByCursor
Môj najobľúbenejší z troch. Síce nie najpresnejšie, ale najprimeranejšie. Žiadosť robíme od začiatku založenia účtu do maximálneho možného dátumu (zrušenie účtu alebo aktuálneho). Dostaneme odpoveď, vezmeme kurzor a znova požiadame, pokiaľ sú k dispozícii údaje. A kód je stručnejší ako v príkladoch vyššie.
const timer = async time => { return new Promise(resolve => setTimeout(resolve, time)); } const getOperationsByCursor = async (sdk, accountId, from, to, kurzor = ”) => { try { const reqData = { accountId, from, to, limit: 1000, state: sdk.OperationState.OPERATION_STATE_EXECUTED, withoutCommissions: false, withoutTrades: false, withoutOvernights: false, kurzor, }; return wait sdk.operations.getOperationsByCursor(reqData); } catch (e) { wait timer(60000); return wait getOperationsByCursor(sdk, accountId, from, to, cursor = ”); } };
Návrh na spustenie je tu: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 Teraz sme pripravení pridať operácie prijímania do našu aplikáciu. Ak sa to urobí správne, musíte získať správy o sprostredkovaní za celú existenciu účtu. A pre chýbajúce údaje sa tie isté T-3 načítajú z operácií. To sa však dá rozdeliť do samostatného článku. Medzi hlavné nuansy, s ktorými sa stretnete, patrí lepenie operácií a maklérska správa.
- Ak ste dnes dostali sprostredkovateľskú správu a transakcie k požadovaným dátumom, vložte to všetko do databázy, potom nie sú žiadne problémy.
- Zajtra budete mať problémy, keď dostanete ďalšiu časť údajov zo správy a operácií a rozhodnete sa ich synchronizovať s existujúcou databázou.
- Veľa nuancií o nezhode alebo zmene ID po spracovaní
- Potom pre OTC trh sa ID vôbec nezhodujú.
- Rovnako ako nuansy synchronizačných nástrojov, ktoré sa opäť nezhodujú kvôli zvláštnostiam API. Ale to je už iný príbeh.
Pridajme do našej aplikácie získavanie informácií o operáciách. Hlavnou otázkou bude, kde sa budú údaje spracovávať a uchovávať.
- Ak to urobíte pre seba, budete konzumovať rovnaké dáta z rôznych zariadení. Potom musíte spracovať a uložiť údaje na serveri.
- Ak máte veľa rôznych dát spotrebovaných mnohými rôznymi používateľmi, musíte sa rozhodnúť, čo je dôležitejšie: rýchlosť používateľov alebo úspora železa na vašej strane. Ktokoľvek si môže dovoliť nekonečné množstvo hardvéru, počíta všetko na svojom serveri a robí to pre používateľov super rýchlym, čím šetrí zdroje používateľa, ako je batéria a prevádzka, čo je na telefónoch veľmi dôležité.
Počítanie v prehliadači zasa nie je v princípe najoptimálnejším riešením. Čo teda nie je drahé, to zvažujeme na našom serveri. Ostatné necháme na klientovi. Naozaj chcem vziať a vypočítať províziu na serveri. Tu však prichádza nuansa nazývaná „interaktivita“. Povedzme, že máte tisíce operácií a ich prijatie trvá päť minút. Čo bude mať používateľ v tomto čase? Spinner? Pokrok? Infa o tom, koľko sa odovzdalo? Ideálne je použiť „aktívne čakanie“, keď používateľ v procese už niečo vidí. Tu je výsledok:
- Načítavanie stránky
- Vyžadujú sa všetky faktúry
- Potom sú pre všetky účty požadované všetky transakcie s províziou za uskutočnené transakcie. Po prijatí údajov sa tieto údaje vykreslia v prehliadači.
Aby sme údaje v udalostiach nefiltrovali zakaždým, pre každý účet vytiahneme vlastnú udalosť. Páči sa ti to:
socket.emit(‘sdk:getOperationsCommissionResult_’ + accountId, { items: data?.items, inProgress: Boolean(nextCursor), });
Návrh na spustenie je tu: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Ideme ďalej. Je skvelé, že ste si prečítali tento riadok!
Výpočet a výstup zaujímavých informácií
Záleží na tom, kto aké informácie potrebuje. Preto vám okamžite poviem hlavné nuansy, s ktorými sa stretnete.
Práca s cenami
Každý, kto pracuje s financiami, vie, že peňažné transakcie by sa mali vykonávať len s celými číslami. Kvôli nepresnosti hodnôt za desatinnou čiarkou a kumulatívnej chybe s veľkým počtom operácií. Preto sú všetky ceny prezentované v nasledujúcom formáte MoneyValue
lúka | typu | Popis |
---|---|---|
mena | reťazec | Reťazec ISO kódu meny |
Jednotky | int64 | Celá časť súčtu môže byť záporné číslo |
nano | int32 | Zlomková časť sumy môže byť záporné číslo |
Samostatne ich spracovávame, potom ich uvádzame na cenovú hodnotu:
ponuka.jednotky + ponuka.nano / 1e9
Náklady na futures kontrakty
Cena futures je prezentovaná v bodoch, keď máte menovú futures, musíte poznať kurz. A samozrejme cena v bodoch a cenový stupeň. Keď spočítate zisk z transakcií, môže to vystreliť, pretože. ak vypočítate celkovú sumu vynásobením ceny množstvom. Tu si treba dávať pozor. Zatiaľ uvidíme, ako to pôjde. To platí pre menové futures, na iných miestach je s tým všetko v poriadku.
OTC trh
Tento trh má veľa zvláštností, takže poďme študovať operácie na ňom oddelene. Keď začnete synchronizovať operácie, ukáže sa, že musíte uviesť figi / ticker do rovnakej formy, aby ste správne spárovali nástroj. Keď to začnete synchronizovať s maklérskou správou, ukáže sa, že tradeID tej istej transakcie má v transakciách na začiatku písmená a tie nie sú v sprostredkovateľskej správe. Preto ich nemožno porovnávať … ehm-ehm … porovnaním! Priradil som čas obchodu, ticker a párovanie, že jedno tradeId je obsiahnuté v inom. Dobre, neviem. Kto sa s tým stretne a komu na tom záleží, príďte do čísla alebo založte nové.
Matematické operácie na nástrojoch
Bez toho, aby ste sa pozreli, nie je možné vykonávať matematické operácie s celým zoznamom. Aby sme nepridali teplé do mäkkého, menu kontrolujeme a spracovávame vždy len vtedy, ak sme si istí, že sa mena zhoduje, a body sú prepočítané na požadovanú menu. Vyzbrojení znalosťami o práci s bankovými číslami vypočítame províziu vynaloženú na každý z účtov. Takto: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4
Mikroservis je pripravený!
https://github.com/pskucherov/tcsstat Ako domácu úlohu si môžete skontrolovať, či služba funguje s pomalým pripojením, pri prerušení pripojenia, pri odpojení internetu, pri chybách alebo vypršaní limitov na strane brokera.
Závery a plány do budúcnosti
- Naučili ste sa základné operácie a prácu s Invest API
- Čas strávený ~ 10 hodín
- Úroveň obtiažnosti ~ junior+ / nízka stredná
Ak budete pokračovať v zdokonaľovaní mikroslužby, môžete skončiť s niečím takýmto
https://opexbot.info
Toto je môj vývoj, pre tých, ktorí sú príliš leniví na to, aby pochopili, utekali a počítali sami. Plánujem tam pridať analytiku na žiadosť používateľov. Ak sa vám článok páčil, prihláste sa na odber môjho telegramového kanála .
Полезная статья. Не могу представить, сколько усилий автора потребовалось, чтобы все описать. Благодарю.