L’ispiratori daretu à u sviluppu di u serviziu di statistiche per Tinkoff Investments eranu:
- articulu nantu à Habré “Ciò chì Tinkoff Investments ùn dicenu micca”
- analisi di i desideri di l’utilizatori di a piattaforma
- un articulu nantu à u calculu di cumissioni .
- Chì serà discutitu ?
- Sviluppà un serviziu di statistiche passu à passu:
- Cunnessione à l’API Tinkoff Invest
- Disegnu dati da Tinkoff Invest API in un navigatore
- Riceve rapporti di brokerage è transazzione
- Get Broker Report
- Metudu per ottene a data, tenendu in contu a sottrazione da a data attuale
- Richiesta di generazione di rapportu
- Risultatu:
- GetDividendsForeign Issuer
- GetOperationsByCursor
- Càlculu è output di l’infurmazioni d’interessu
- U travagliu cù i prezzi
- U costu di i cuntratti futuri
- Mercatu OTC
- Operazioni matematiche nantu à l’arnesi
- U microserviziu hè prontu!
- Cunclusioni è piani per u futuru
- https://opexbot.info
Chì serà discutitu ?
- Solu a parte applicata nantu à u sviluppu.
- Cunniscenza vera è sperienza, chì sò assai impurtanti in u travagliu cù strumenti finanziarii.
- Panoramica di i prublemi per travaglià
Allora, vogliu calculà e statistiche di u cummerciu è fà in una manera còmuda.
Sviluppà un serviziu di statistiche passu à passu:
- Cunnessione à l’API Tinkoff Invest
- Disegnu dati da Tinkoff Invest API in un navigatore
- Riceve rapporti di brokerage è transazzione
- Càlculu è output di l’infurmazioni d’interessu
- Cunclusioni è piani per u futuru
Cunnessione à l’API Tinkoff Invest
Per cunnette à l’API, pudete piglià qualsiasi sdk da a documentazione https://github.com/Tinkoff/investAPI#sdk . O pacchettu npm ` tinkoff-sdk-grpc-js `. Hè impurtante chì u pacchettu hè aghjurnatu à l’ultima versione da i sviluppatori. Installa
npm è tinkoff-sdk-grpc-js
Cuntrolla
const {createSdk} = require(‘tinkoff-sdk-grpc-js’); // Token chì pò esse acquistatu cusì cunst TOKEN = ‘YOURAPI’; // U nome di l’applicazione per quale pudete truvà in i logs TCS. const appName = ‘tcsstat’; const sdk = createSdk (TOKEN, appName); (async () => { console.log (attende sdk.users.getAccounts ()); })();
Risultatu: una lista di i vostri cunti serà visualizata in a cunsola. Per esempiu, analizemu e sfumature:
- In a lista di cunti ci hè un “bancu d’investimentu”, cù quale ùn pudete micca travaglià cù l’API
- Per piacè nutate chì i campi venenu in camelCase, mentri in a documentazione sti campi sò presentati in under_score.
- Serà cusì in ogni locu, perchè ùn pudete micca solu piglià è copià un campu da a documentazione.
Utile:
- Pudete truvà stu codice in u ramu prughjettu
https://github.com/pskucherov/tcsstat/tree/step1 https://github.com/pskucherov/tcsstat/compare/step1
Disegnu dati da Tinkoff Invest API in un navigatore
Aghju pigliatu next.js è socket.io. Questa ùn hè micca una raccomandazione forte, sceglite à a vostra discrezione.
npx create-next-app@latest npm i socket.io socket.io-client
Procedemu immediatamente à u passu di l’amicizia next+socket+investapi, è vede a sezione Utile di stu passu per tutti i dettagli. Descriveraghju i dettagli:
- Da u latu nodejs (servitore), ci hè un schedariu pages/api/investapi.js. Hè quì chì creamu u servitore socket.io è cunnette à investapi.
- Da u latu di u navigatore (cliente), cunnettamu à u servitore per via di un socket è dumandemu i dati di u contu da u broker.
- Ricevemu dati da u broker nantu à u servitore, dopu mandà à u cliente. Quandu sò ricevuti nantu à u cliente, sò visualizati in u navigatore.
Risultatu: in a cunsola di u navigatore pudemu vede infurmazioni nantu à i cunti. Questu hè, in l’ultimu passu, avemu vistu infurmazione nantu à i cunti in a cunsola di u servitore (nodejs), in u passu attuale, avemu trasfirutu sta informazione à u cliente (navigatore).
Avà facemu cusì chì pudete selezziunà un contu da u navigatore, è se ùn ci hè micca token, allora un errore hè mandatu à a cunsola. U travagliu hè simplice è nunda di novu, per quessa, dà solu ligami à cummette
- https://github.com/pskucherov/tcsstat/commit/7e1ac57061e5e971588479015b06d8814d6609a9
- https://github.com/pskucherov/tcsstat/commit/b28ac973a57494f5232589b4cb6b9fb13b8af759
Utile:
- Cumu fà amici dopu è socket hè descrittu in detail quì .
- Codice d’amicizia next+socket+investapi:
https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 Per quale u sopra hè difficiule, allora fermamu in questu stadiu è trattà cù u codice. Sì avete dumande – dumandate. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2
Riceve rapporti di brokerage è transazzione
Ci sò trè metudi per riceve rapporti di brokerage è transazzione
Da u principiu hè impurtante di sapè:
- U rapportu di brokerage hè generatu in u modu T-3, i.e. i mistieri sò affissati quì dopu a so esecuzione attuale.
- Dunque, se dumandate stu rapportu per l’ultimi dui ghjorni, serà pronta in trè ghjorni.
- Per fà affari per l’ultimi ghjorni, usemu u metudu per riceve operazioni, ma ricordate chì u so id è u cuntenutu pò cambià dopu à a furmazione di u rapportu di brokerage.
Get Broker Report
Per uttene un rapportu di correlazione, avete bisognu di piglià l’identificatore di u contu, a data di iniziu è a data di fine di u rapportu, ma micca più di 31 ghjorni. Mandemu una dumanda per generà un rapportu à l’API in generate _broker_report_request , uttene un taskId in risposta. Dopu à quessa, utilizendu stu taskId, uttene dati da get _broker_report_response.
- Avete bisognu di salvà u TaskID per sempre esattamente per queste date.
- Siccomu si perde, allora per e date richieste u rapportu vene prima in risposta à a dumanda di generazione,
- È tandu ùn vene micca in tuttu.
Metudu per ottene a data, tenendu in contu a sottrazione da a data attuale
const getDateSubDay = (subDay = 5, start = true) => { const date = new Date (); date.setUTCDate (date.getUTCDate () – subDay); if (iniziu) { date.setUTCHours (0, 0, 0, 0); } altru { date.setUTCHours (23, 59, 59, 999); } data di ritornu; };
Richiesta di generazione di rapportu
const brokerReport = await (sdk.operations.getBrokerReport) ({ generateBrokerReportRequest: { accountId, from, to, }, });
Risultatu:
- In u risultatu di a prima esecuzione di u cumandamentu, avemu u taskId.
- U rapportu cumencia à esse generatu da u broker. Quandu hè prontu hè scunnisciutu, aspittemu è tirà periodicamente u taskId in anticipazione di u rapportu.
- Perchè? Perchè se u rapportu ùn hè micca prontu, tira un errore. Se u rapportu ùn hè micca prontu da u broker, allora questu hè un errore in u vostru codice. Per piacè prucessu: 30058|INVALID_ARGUMENT| compitu ùn hè micca finitu ancu, per piacè pruvà più tardi
U codice per aspittà è riceve un rapportu pare cusì cusì.
const timer = async time => { return new Promise (resolve => setTimeout (resolve, time)); } const getBrokerResponseByTaskId = async (taskId, pagina = 0) => { try { return await (sdk.operations.getBrokerReport) ({ getBrokerReportRequest: { taskId, pagina, }, }); } catch (e) { console.log(‘wait’, e); aspittà timer (10000); ritornu aspittà getBrokerResponseByTaskId (taskId, pagina); } };
Allora a stessa magia succede. Firmemu u nostru script, ricuminciamu, ùn avemu micca un taskId. Eseguimu u codice cù a dumanda taskId, ma ùn avemu più u taskId, ma immediatamente u rapportu. Magia ! È tuttu saria bè s’ellu era sempre cusì. Ma in un mesi ùn ci sarà micca dati à tutti. Utile :
https://github.com/pskucherov/tcsstat/tree/step3.1 https://github.com/pskucherov/tcsstat/compare/step3.1
- Sè qualchissia vene in questu, allora benvenutu à u prublema . Dopu avè riparatu sta magia, perderà u so putere è serà in qualchì manera sfarente. Ma à u mumentu attuale (21/03/2023) funziona cusì cusì.
GetDividendsForeign Issuer
Qualchissia puderia pensà chì u metudu hè simili à u precedente è pudete aduprà un solu metudu in quale solu cambià u nome di l’operazioni. Ma ùn anu micca indovinatu ! A denominazione hè assai sfarente sia in i metudi è in l’infurmazioni restituiti. È u conte di pagina principia da 0, dopu da 1. Per ùn avè micca cunfunditu in tuttu questu, hè più faciule per scrive dui metudi diffirenti. Chì hè stranu, perchè a logica di u travagliu hè a stessa. Aghju sputatu per un bellu pezzu quandu aghju pruvatu à fà un metudu è ci era menu codice. Ùn ci sarà micca esempi quì.
GetOperationsByCursor
U mo preferitu di i trè. Ancu s’ellu ùn hè micca u più precisu, ma u più adattatu. Facemu una dumanda da u principiu di creazione di un contu à a data massima pussibule (chjude un contu o l’attuale). Avemu a risposta, pigliate u cursore è ri-dumandu finu à chì ci sò dati. È u codice hè più cuncisu chè in l’esempii sopra.
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, senzaTrades: false, senza Overnights: false, cursore, }; return await sdk.operations.getOperationsByCursor (reqData); } catch (e) { wait timer (60000); return await getOperationsByCursor (sdk, accountId, from, to, cursor = ”); } };
U prugettu per eseguisce hè quì: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 Avà simu pronti per aghjunghje operazioni di ricezione à a nostra applicazione. Sè fattu bè, allora avete bisognu di ottene rapporti di brokerage per tutta l’esistenza di u contu. È per i dati mancanti, quelli stessi T-3, ricaricà da l’operazioni. Ma questu pò esse separatu in un articulu separatu. Di i sfumaturi principali chì vi scontru hè di colla l’operazioni è un rapportu di brokerage.
- Sè oghje avete ricevutu un rapportu di brokerage è transazzione per e date richieste, mette tuttu in a basa di dati, allora ùn ci sò micca prublemi.
- Averete prublemi dumani quandu avete ricevutu a prossima parte di dati da u rapportu è l’operazioni è decide di sincronizà cù a basa di dati esistenti.
- Un saccu di sfumature nantu à l’identificazione incompatibile o cambiante dopu a trasfurmazioni
- Allora per u mercatu OTC, l’id ùn currispondenu à tuttu.
- In quantu à i sfumaturi di strumenti di sincronizazione, chì di novu ùn coincidenu micca, per via di e peculiarità di l’API. Ma questu hè un’altra storia.
Aghjunghjemu l’infurmazioni nantu à l’operazione à a nostra applicazione. A quistione principale serà induve i dati seranu trattati è almacenati.
- Sè vo fate per sè stessu, vi cunsumà u listessu dati da differente dispusitivi. Allora avete bisognu di processà è almacenà e dati nantu à u servitore.
- Sè vo avete assai dati differente cunsumati da parechji utilizatori differente, allura vi tocca à decide ciò chì hè più impurtante: a vitezza di l ‘utilizatori o u risparmiu di ferru da u vostru latu. Quellu chì pò permette una quantità infinita di hardware conta tuttu nantu à u so servitore è rende super veloce per l’utilizatori, salvendu e risorse di l’utilizatori, cum’è a bateria è u trafficu, chì hè assai impurtante in i telefoni.
A so volta, cuntà in u navigatore ùn hè micca a suluzione più ottima in principiu. Dunque, ciò chì ùn hè micca caru, avemu cunsideratu nantu à u nostru servitore. Lascemu u restu à u cliente. Vogliu veramente piglià è calculà a cumissioni nantu à u servitore. Ma quì vene a sfumatura chjamata “interattività”. Diciamu chì avete migliaia di operazioni è ci vole cinque minuti per riceve. Chì serà l’utilizatore à questu tempu? Spinner? Prugressu ? Infa quantu hè stata caricata? Hè ideale per aduprà “attesa attiva” quandu l’utilizatore in u prucessu puderia digià vede qualcosa. Eccu u Risultatu:
- Carica di pagina
- Tutte e fatture sò richieste
- Dopu quì, tutte e transazzione cù cumissioni per e transazzione eseguite sò dumandate per tutti i cunti. Quandu i dati sò ricevuti, sò resi in u navigatore.
Per ùn filtrà i dati in l’avvenimenti ogni volta, tiramu u nostru propiu avvenimentu per ogni contu. Cum’è què:
socket.emit(‘sdk:getOperationsCommissionResult_’ + accountId, { items: data?.items, inProgress: Boolean (nextCursor), });
U prugettu per lancià hè quì: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Avanzate. Hè bellu chì avete lettu sta linea!
Càlculu è output di l’infurmazioni d’interessu
Dipende da quale hà bisognu di quale infurmazione. Dunque, vi dicu subitu i sfumaturi principali chì vi scontru.
U travagliu cù i prezzi
Tutti quelli chì travaglianu cù finanzii sapi chì e transazzione di soldi deve esse realizatu solu cù numeri sanu. A causa di l’imprecisione di i valori dopu à u puntu decimale è l’errore cumulativu cù un gran numaru di operazioni. Hè per quessa chì tutti i prezzi sò presentati in u seguente formatu MoneyValue
campu | tipu | Descrizzione |
---|---|---|
munita | stringa | String codice di valuta ISO |
unità | int64 | Parte entera di a summa, pò esse un numeru negativu |
nanu | int32 | Parte fraccionaria di a quantità, pò esse un numeru negativu |
I processemu separatamente, poi purtemu à u valore di u prezzu:
quotazione.unità + quotazione.nano / 1e9
U costu di i cuntratti futuri
U prezzu di futuri hè prisentatu in punti, quandu avete un futuru di munita, avete bisognu di sapè a tarifa. E sicuru u prezzu in punti è u passu di prezzu. Quandu calculate u prufittu da e transazzione, questu pò sparà, perchè. se calcule a quantità tutale multiplichendu u prezzu per a quantità. Quì ci vole à esse attentu. Per avà, videremu cumu si passa. Questu hè applicatu à i futuri di valuta, in altri lochi tuttu hè bè cù questu.
Mercatu OTC
Stu mercatu hà assai peculiarità, dunque studiemu l’operazioni nantu à questu per separatamente. Quandu avete principiatu à sincronizà l’operazioni, vi scoprerà chì avete bisognu di purtà figi / ticker à a listessa forma per currispondenu currettamente à u strumentu. Quandu avete principiatu à sincronizà questu cù u rapportu di brokerage, vi sarà chì u tradeID di a listessa transazzione hà lettere à u principiu in e transazzione è ùn sò micca in u rapportu di brokerage. Dunque, ùn ponu esse paragunati … ahem-ahem … per paragone ! Aghju accumpagnatu u tempu di cummerciu, ticker è currispundenza chì un tradeId hè cuntenutu in un altru. Giustu, ùn sò micca. Quellu chì scontra questu è chì si preoccupa, vene à u prublema o principià un novu.
Operazioni matematiche nantu à l’arnesi
Hè impussibile, senza circà, per fà operazioni matematiche cù tutta a lista. Per ùn aghjunghje micca caldu à morbidu, avemu sempre verificatu a munita è prucessu solu s’è no simu sicuru chì a munita currisponde, è i punti sò cunvertiti in a valuta desiderata. Armatu di cunniscenze nantu à u travagliu cù i numeri bancari, calculeremu a cumissioni spesa nantu à ognunu di i cunti. Cume questu: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4
U microserviziu hè prontu!
https://github.com/pskucherov/tcsstat Cum’è un travagliu in casa, pudete verificà se u serviziu funziona cù una cunnessione lenta, quandu e cunnessione sò rotte, quandu l’Internet hè disconnected, quandu l’errore o i limiti scaduti da parte di u broker.
Cunclusioni è piani per u futuru
- Amparatu nantu à e operazioni basiche è travaglià cù l’API Invest
- U tempu passatu ~ 10 ore
- Livellu di difficultà ~ junior+ / bassu mediu
Se continuate à raffinà u microserviziu, pudete finisce cù qualcosa cum’è questu
https://opexbot.info
Questu hè u mo sviluppu, per quelli chì sò troppu pigri per capiscenu, curriri è cuntà per sè stessu. Pensu di aghjunghje analitiche quì à a dumanda di l’utilizatori. Se ti piace l’articulu, allora abbonate à u mo canale di telegram .
Полезная статья. Не могу представить, сколько усилий автора потребовалось, чтобы все описать. Благодарю.