Inspirátoři za vývojem statistické služby pro Tinkoff Investments byli:
- článek o Habrém „Co Tinkoff Investments neříkají“
- analýza přání uživatelů platformy
- článek o výpočtu provizí .
- O čem se bude diskutovat?
- Vývoj statistické služby krok za krokem:
- Připojení k Tinkoff Invest API
- Čerpání dat z Tinkoff Invest API v prohlížeči
- Příjem makléřských zpráv a transakcí
- GetBrokerReport
- Metoda pro získání data s přihlédnutím k odečtení od aktuálního data
- Požadavek na generování zprávy
- Výsledek:
- GetDividendsForeignIssuer
- GetOperationsByCursor
- Výpočet a výstup zájmových informací
- Práce s cenami
- Náklady na futures kontrakty
- OTC trh
- Matematické operace na nástrojích
- Mikroservis je připraven!
- Závěry a plány do budoucna
- https://opexbot.info
O čem se bude diskutovat?
- Pouze aplikovaná část o vývoji.
- Skutečné znalosti a zkušenosti, které jsou při práci s finančními nástroji velmi důležité.
- Přehled problémů, na kterých je třeba pracovat
Chci tedy vypočítat obchodní statistiky a udělat to pohodlným způsobem.
Vývoj statistické služby krok za krokem:
- Připojení k Tinkoff Invest API
- Čerpání dat z Tinkoff Invest API v prohlížeči
- Příjem makléřských zpráv a transakcí
- Výpočet a výstup zájmových informací
- Závěry a plány do budoucna
Připojení k Tinkoff Invest API
Pro připojení k API si můžete vzít libovolný sdk z dokumentace https://github.com/Tinkoff/investAPI#sdk . Nebo balíček npm ` tinkoff-sdk-grpc-js `. Je důležité, aby vývojáři aktualizovali balíček na nejnovější verzi. Nainstalujte
npm i tinkoff-sdk-grpc-js
Kontrola
const { createSdk } = require(‘tinkoff-sdk-grpc-js’); // Token, který lze získat takto const TOKEN = ‘YOURAPI’; // Název aplikace, pod kterou vás najdete v protokolech TCS. const appName = ‘tcsstat’; const sdk = createSdk(TOKEN, název aplikace); (async () => { console.log(wait sdk.users.getAccounts()); })();
Výsledek: v konzole se zobrazí seznam vašich účtů. Pojďme například analyzovat nuance:
- V seznamu účtů je „Investiční banka“, se kterou nelze pracovat pomocí API
- Vezměte prosím na vědomí, že pole přicházejí v camelCase, zatímco v dokumentaci jsou tato pole uvedena pod_score.
- Bude to tak všude, takže nemůžete jen tak vzít a zkopírovat pole z dokumentace.
Užitečný:
- Tento kód najdete ve větvi projektu
https://github.com/pskucherov/tcsstat/tree/step1 https://github.com/pskucherov/tcsstat/compare/step1
Čerpání dat z Tinkoff Invest API v prohlížeči
Vzal jsem next.js a socket.io. Toto není silné doporučení, vyberte si podle svého uvážení.
npx create-next-app@latest npm i socket.io socket.io-client
Okamžitě přejdeme ke kroku přátelství next+socket+investapi a všechny podrobnosti naleznete v části Užitečné tohoto kroku. Popíšu podrobnosti:
- Na straně nodejs (serveru) je soubor pages/api/investapi.js. Zde vytvoříme server socket.io a připojíme se k investapi.
- Na straně prohlížeče (klienta) se připojíme k serveru přes socket a vyžádáme si od brokera údaje o účtu.
- Data obdržíme od brokera na serveru a následně je odešleme klientovi. Když je klient obdrží, zobrazí se v prohlížeči.
Výsledek: v konzole prohlížeče můžeme vidět informace o účtech. To znamená, že v posledním kroku jsme viděli informace o účtech v konzoli serveru (nodejs), v aktuálním kroku jsme tyto informace přenesli do klienta (prohlížeče).
Nyní to uděláme tak, že si můžete vybrat účet z prohlížeče, a pokud neexistuje žádný token, do konzole se odešle chyba. Práce je jednoduchá a nic nového, proto uvádím pouze odkazy na commity
- https://github.com/pskucherov/tcsstat/commit/7e1ac57061e5e971588479015b06d8814d6609a9
- https://github.com/pskucherov/tcsstat/commit/b28ac973a57494f5232589b4cb6b9fb13b8af759
Užitečný:
- Jak získat přátele další a zásuvku je podrobně popsáno zde .
- Přátelský kód další+socket+investapi:
https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 Pro koho je výše uvedené obtížné, pak zůstáváme v této fázi a zabýváme se kódem. Máte-li dotazy – ptejte se. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2
Příjem makléřských zpráv a transakcí
Existují tři způsoby , jak přijímat makléřské zprávy a transakce
Od samého začátku je důležité vědět:
- Zpráva o zprostředkování je generována v režimu T-3, tzn. obchody se tam zobrazují po jejich skutečném provedení.
- Pokud tedy požádáte o tento přehled za poslední dva dny, bude připraven za tři dny.
- Pro získání transakcí za poslední dny používáme metodu pro příjem transakcí, ale pamatujte, že jejich ID a obsah se mohou po vygenerování zprávy o zprostředkování změnit.
GetBrokerReport
Chcete-li získat makléřskou zprávu, musíte vzít ID účtu, datum zahájení a datum ukončení zprávy, ale ne více než 31 dní. Požadavek na vygenerování sestavy posíláme do rozhraní API v generování _broker_report_request , jako odpověď získáme taskId. Poté pomocí tohoto taskId získáme data z get _broker_report_response.
- Musíte uložit TaskID navždy přesně pro tato data.
- Vzhledem k tomu, že pokud jej ztratíte, pak pro požadovaná data zpráva nejprve přijde jako odpověď na žádost o generování,
- A pak už to nepřijde vůbec.
Metoda pro získání data s přihlédnutím k odečtení od aktuálního data
const getDateSubDay = (subDay = 5, start = true) => { const date = new Date(); date.setUTCDate(date.getUTCDate() – subDay); if (start) { datum.setUTCHours(0, 0, 0, 0); } else { datum.setUTCHours(23, 59, 59, 999); } datum návratu; };
Požadavek na generování zprávy
const brokerReport = wait (sdk.operations.getBrokerReport)({ createBrokerReportRequest: { accountId, from, to, }, });
Výsledek:
- V důsledku prvního provedení příkazu získáme taskId.
- Report se začne generovat na straně brokera. Když je připraveno, není známo, čekáme a pravidelně vytahujeme taskId v očekávání zprávy.
- Proč? Protože pokud není sestava připravena, vyhodí chybu. Pokud report není na straně brokera připraven, jedná se o chybu ve vašem kódu. Zpracujte prosím: 30058|INVALID_ARGUMENT|úkol ještě není dokončen, zkuste to prosím znovu později
Kód pro čekání a příjem hlášení vypadá asi takto.
const timer = async time => { return new Promise(resolve => setTimeout(resolve, time)); } const getBrokerResponseByTaskId = async (taskId, stránka = 0) => { try { return wait (sdk.operations.getBrokerReport)({ getBrokerReportRequest: { taskId, page, }, }); } catch (e) { console.log(‘wait’, e); časovač čekání (10000); return wait getBrokerResponseByTaskId(taskId, page); } };
Pak se stane stejné kouzlo. Zastavíme náš skript, spustíme jej znovu, nemáme taskId. Spustíme kód s požadavkem taskId, ale už nedostaneme taskId, ale rovnou report. Kouzlo! A všechno by bylo v pořádku, kdyby to tak bylo pořád. Ale za měsíc tam nebudou vůbec žádná data. Užitečné :
https://github.com/pskucherov/tcsstat/tree/step3.1 https://github.com/pskucherov/tcsstat/compare/step3.1
- Pokud na to někdo narazí, tak vítejte v problému . Poté, co toto kouzlo opraví, ztratí svou sílu a bude nějak jiné. Ale v současné chvíli (21.3.2023) to tak funguje.
GetDividendsForeignIssuer
Někdo by si mohl myslet, že metoda je podobná té předchozí a můžete použít jedinou metodu, ve které pouze změníte název operací. Ale neuhádli! Pojmenování se tam velmi liší jak v metodách, tak ve vrácených informacích. A počet stránek začíná od 0, pak od 1. Abyste se v tom všem nepletli, je jednodušší napsat dvě různé metody. Což je zvláštní, protože logika práce je stejná. Dlouho jsem plival, když jsem se snažil udělat jednu metodu a bylo tam méně kódu. Nebudou zde žádné příklady.
GetOperationsByCursor
Můj nejoblíbenější ze tří. Sice ne nejpřesnější, ale nejadekvátnější. Požadavek provádíme od začátku založení účtu do maximálního možného data (zrušení účtu nebo stávajícího). Dostaneme odpověď, vezmeme kurzor a znovu požádáme, dokud jsou data. A kód je stručnější než ve výše uvedených příkladech.
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 = ”); } };
Koncept ke spuštění je zde: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 Nyní jsme připraveni přidat operace příjmu do naše aplikace. Pokud se to udělá správně, musíte získat zprávy o zprostředkování po celou dobu existence účtu. A pro chybějící data znovu načtěte tytéž T-3 z operací. Ale to lze rozdělit do samostatného článku. Mezi hlavní nuance, se kterými se setkáte, je slepení operací a makléřské zprávy.
- Pokud jste dnes obdrželi zprostředkovatelskou zprávu a transakce k požadovaným termínům, vložte to vše do databáze, pak nejsou žádné problémy.
- Zítra budete mít problémy, když obdržíte další část dat ze sestavy a operací a rozhodnete se je synchronizovat se stávající databází.
- Mnoho nuancí o neshodě nebo změně id po zpracování
- Pak pro OTC trh se ID vůbec neshodují.
- Stejně jako nuance synchronizačních nástrojů, které se opět neshodují, kvůli zvláštnostem API. Ale to je jiný příběh.
Do naší aplikace přidáme získávání informací o operacích. Hlavní otázkou bude, kde budou data zpracována a uložena.
- Pokud to uděláte pro sebe, budete spotřebovávat stejná data z různých zařízení. Poté musíte zpracovat a uložit data na serveru.
- Pokud máte mnoho různých dat spotřebovaných mnoha různými uživateli, musíte se rozhodnout, co je důležitější: rychlost uživatelů nebo úspora železa na vaší straně. Kdokoli si může dovolit nekonečné množství hardwaru, počítá vše na svém serveru a pro uživatele to dělá superrychlým, což šetří uživatelské zdroje, jako je baterie a provoz, což je u telefonů velmi důležité.
Počítání v prohlížeči zase není v zásadě nejoptimálnějším řešením. Co tedy není drahé, to zvažujeme na našem serveru. Zbytek necháme na klientovi. Opravdu chci vzít a vypočítat provizi na serveru. Zde však přichází nuance zvaná „interaktivita“. Řekněme, že máte tisíce operací a jejich přijetí trvá pět minut. Co bude mít uživatel v tuto chvíli? Spinner? Pokrok? Infa o tom, kolik bylo nahráno? Ideální je použít „aktivní čekání“, když uživatel v procesu již něco viděl. Zde je výsledek:
- Načítání stránky
- Všechny faktury jsou požadovány
- Poté jsou pro všechny účty požadovány všechny transakce s provizí za provedené transakce. Jakmile jsou data přijata, jsou vykreslena v prohlížeči.
Abychom data v událostech nefiltrovali pokaždé, stahujeme pro každý účet vlastní událost. Takhle:
socket.emit(‘sdk:getOperationsCommissionResult_’ + accountId, { items: data?.items, inProgress: Boolean(nextCursor), });
Návrh ke spuštění je zde: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Jdeme dál. Je skvělé, že jste si přečetli tento řádek!
Výpočet a výstup zájmových informací
Záleží na tom, kdo jaké informace potřebuje. Proto vám okamžitě řeknu hlavní nuance, se kterými se setkáte.
Práce s cenami
Každý, kdo pracuje s financemi, ví, že peněžní transakce by se měly provádět pouze s celými čísly. Kvůli nepřesnosti hodnot za desetinnou čárkou a kumulativní chybě s velkým počtem operací. Proto jsou všechny ceny prezentovány v následujícím formátu MoneyValue
pole | typ | Popis |
---|---|---|
měna | tětiva | Řetězec ISO kód měny |
Jednotky | int64 | Celá část součtu může být záporné číslo |
nano | int32 | Zlomková část částky může být záporné číslo |
Zpracováváme je samostatně a poté je dorovnáme na cenovou hodnotu:
kotace.jednotky + kotace.nano / 1e9
Náklady na futures kontrakty
Cena futures je uvedena v bodech, když máte měnový future, musíte znát kurz. A samozřejmě cena v bodech a cenový stupeň. Když počítáte zisk z transakcí, může to vystřelit, protože. pokud vypočítáte celkovou částku vynásobením ceny množstvím. Zde je třeba být opatrný. Zatím uvidíme, jak to půjde. To platí pro měnové futures, jinde je s tímto vše v pořádku.
OTC trh
Tento trh má mnoho zvláštností, takže si na něm prostudujeme operace zvlášť. Když začnete synchronizovat operace, ukáže se, že musíte uvést figi / ticker do stejné formy, abyste správně spárovali nástroj. Když to začnete synchronizovat se zprávou o zprostředkování, ukáže se, že tradeID stejné transakce má v transakcích na začátku písmena a ve zprávě o zprostředkování nejsou. Proto je nelze srovnávat … ehm-ehm … srovnáním! Porovnal jsem čas obchodu, ticker a shodu, že jedno tradeId je obsaženo v jiném. Jasně, já nevím. Kdo se s tím setká a koho to zajímá, přijďte na vydání nebo založte nové.
Matematické operace na nástrojích
Bez pohledu není možné provádět matematické operace s celým seznamem. Abychom nepřidávali teplé do měkkého, měnu kontrolujeme a zpracováváme vždy pouze v případě, že jsme si jisti, že měna odpovídá, a body jsou převedeny na požadovanou měnu. Vyzbrojeni znalostmi o práci s bankovními čísly spočítáme provizi vynaloženou na každý z účtů. Asi takto: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4
Mikroservis je připraven!
https://github.com/pskucherov/tcsstat Jako domácí úkol si můžete zkontrolovat, zda služba funguje s pomalým připojením, při přerušení připojení, odpojení internetu, při chybách nebo vypršení limitů na straně brokera.
Závěry a plány do budoucna
- Naučili jste se základní operace a práci s Invest API
- Čas strávený ~ 10 hodin
- Úroveň obtížnosti ~ junior+ / nízká střední
Pokud budete pokračovat ve zdokonalování mikroslužby, můžete skončit s něčím takovým
https://opexbot.info
To je můj vývoj, pro ty, kteří jsou příliš líní pochopit, běhat a počítat sami. Plánuji tam přidat analytiku na žádost uživatelů. Pokud se vám článek líbil, přihlaste se k odběru mého telegramového kanálu .
Полезная статья. Не могу представить, сколько усилий автора потребовалось, чтобы все описать. Благодарю.