Stiamo sviluppando un microservizio utilizzando l’API Tinkoff Invest per automatizzare il lavoro con i rapporti di intermediazione e il calcolo delle commissioni.

Программирование

Gli ispiratori dietro lo sviluppo del servizio statistico per Tinkoff Investments sono stati:

Di cosa si discuterà?

  • Solo la parte applicata sullo sviluppo.
  • Conoscenza ed esperienza reali, che sono molto importanti quando si lavora con strumenti finanziari.
  • Panoramica dei problemi su cui lavorare

Quindi, voglio calcolare le statistiche commerciali e farlo in modo conveniente. 

Sviluppare un servizio di statistica passo dopo passo: 

  1. Connessione all’API di Tinkoff Invest
  2. Disegno di dati dall’API Tinkoff Invest in un browser
  3. Ricevere rapporti e transazioni di intermediazione
  4. Calcolo e produzione di informazioni di interesse
  5. Conclusioni e progetti per il futuro

Connessione all’API di Tinkoff Invest

Per connetterti all’API, puoi prendere qualsiasi sdk dalla documentazione https://github.com/Tinkoff/investAPI#sdk . Oppure il pacchetto npm ` tinkoff-sdk-grpc-js` . È importante che il pacchetto sia aggiornato all’ultima versione dagli sviluppatori. Installare

npm io tinkoff-sdk-grpc-js

Controllo

const { createSdk } = require(‘tinkoff-sdk-grpc-js’);   // Token che può essere ottenuto in questo modo  const TOKEN = ‘YOURAPI’;   // Il nome dell’applicazione con cui puoi essere trovato nei log di TCS. const appName = ‘tcsstat’;   const sdk = createSdk(TOKEN, appName); (async () => {     console.log(attendere sdk.users.getAccounts()); })();

Risultato: nella console verrà visualizzato un elenco dei tuoi account. Ad esempio, analizziamo le sfumature:Stiamo sviluppando un microservizio utilizzando l'API Tinkoff Invest per automatizzare il lavoro con i rapporti di intermediazione e il calcolo delle commissioni.

  • Nell’elenco dei conti è presente una “Banca d’investimento”, con la quale non è possibile lavorare utilizzando l’API
  • Si noti che i campi sono in camelCase, mentre nella documentazione questi campi sono presentati in under_score. 
  • Sarà così ovunque, quindi non puoi semplicemente prendere e copiare un campo dalla documentazione.

Utile:

  • Puoi trovare questo codice nel ramo del progetto

https://github.com/pskucherov/tcsstat/tree/step1 https://github.com/pskucherov/tcsstat/compare/step1   

Disegno di dati dall’API Tinkoff Invest in un browser

Ho preso next.js e socket.io. Questa non è una raccomandazione forte, scegli a tua discrezione. 

npx create-next-app@latest npm i socket.io socket.io-client

Procediamo immediatamente al passo dell’amicizia next+socket+investapi, e vediamo la sezione Utile di questo passo per tutti i dettagli.  Descrivo i dettagli: 

  • Sul lato nodejs (server), c’è un file pages/api/investapi.js. Qui è dove creiamo il server socket.io e ci connettiamo a investapi.
  • Sul lato browser (client), ci colleghiamo al server tramite un socket e richiediamo i dati dell’account al broker. 
  • Riceviamo i dati dal broker sul server, quindi li inviamo al client. Quando vengono ricevuti sul client, vengono visualizzati nel browser. 

Risultato:  nella console del browser possiamo vedere le informazioni sugli account. Cioè, nell’ultimo passaggio, abbiamo visto le informazioni sugli account nella console del server (nodejs), nel passaggio corrente, abbiamo trasferito queste informazioni al client (browser).

Stiamo sviluppando un microservizio utilizzando l'API Tinkoff Invest per automatizzare il lavoro con i rapporti di intermediazione e il calcolo delle commissioni.

Ora facciamo in modo che tu possa selezionare un account dal browser e, se non è presente alcun token, viene inviato un errore alla console. Il lavoro è semplice e niente di nuovo, quindi fornisco solo collegamenti ai commit

  1. https://github.com/pskucherov/tcsstat/commit/7e1ac57061e5e971588479015b06d8814d6609a9
  2. https://github.com/pskucherov/tcsstat/commit/b28ac973a57494f5232589b4cb6b9fb13b8af759 

Utile:

  • Come fare amicizia dopo e presa è descritto in dettaglio qui
  • Codice amicizia next+socket+investapi:

https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 Per chi quanto sopra è difficile, rimaniamo in questa fase e ci occupiamo del codice. Se hai domande, chiedi. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2

Ricevere rapporti e transazioni di intermediazione

Esistono tre metodi per ricevere rapporti e transazioni di intermediazione

  1. GetBrokerReport
  2. GetDividendsForeignIssuer
  3. GetOperationsByCursor

Fin dall’inizio è importante sapere: 

  • Il report di intermediazione viene generato in modalità T-3, ovvero le negoziazioni vengono visualizzate lì dopo la loro effettiva esecuzione. 
  • Di conseguenza, se richiedi questo rapporto per gli ultimi due giorni, sarà pronto in tre giorni. 
  • Per ottenere le transazioni degli ultimi giorni, utilizziamo il metodo per la ricezione delle transazioni, ma ricorda che il loro ID e contenuto possono cambiare dopo la generazione del rapporto di intermediazione.

GetBrokerReport

Per ottenere un rapporto di intermediazione, è necessario prendere l’ID dell’account, la data di inizio e la data di fine del rapporto, ma non più di 31 giorni. Inviamo una richiesta per generare un report all’API in generate _broker_report_request , otteniamo un taskId in risposta. Successivamente, utilizzando questo taskId, otteniamo i dati da get _broker_report_response.

Così dice la documentazione, in realtà ci sono delle sfumature. Guardati le mani:
  • Devi salvare il TaskID per sempre esattamente per queste date. 
  • Poiché se lo perdi, per le date richieste il rapporto arriverà prima in risposta alla richiesta di generazione, 
  • E poi non verrà affatto.
Iniziamo a scrivere il codice

Metodo per ottenere la data, tenendo conto della sottrazione dalla data corrente

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);     }       data di ritorno; };

Richiesta generazione report 

const brokerReport = wait (sdk.operations.getBrokerReport)({         generateBrokerReportRequest: {             accountId,             from,             to,         }, });

Risultato:

  • Come risultato della prima esecuzione del comando, otteniamo il taskId. 
  • Il rapporto inizia a essere generato dal lato del broker. Quando è pronto non è noto, attendiamo ed estraiamo periodicamente il taskId in previsione del report.
  • Perché? Perché se il rapporto non è pronto, genera un errore. Se il report non è pronto da parte del broker, si tratta di un errore nel codice. Elabora: 30058|INVALID_ARGUMENT|attività non ancora completata, riprova più tardi

Il codice per l’attesa e la ricezione di un rapporto è simile a questo.

const timer = tempo asincrono => {     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);         attesa timer(10000);         return wait getBrokerResponseByTaskId(taskId, page);     } };

Poi accade la stessa magia. Fermiamo il nostro script, lo ricominciamo, non abbiamo un taskId. Eseguiamo il codice con la richiesta taskId, ma non otteniamo più il taskId, ma subito il report. Magia! E andrebbe tutto bene se fosse sempre così. Ma tra un mese non ci saranno più dati. Utile :

  • Un po’ di teoria è delineata qui e qui .
  • Mettendo insieme il codice, la bozza sarà simile a questa.

https://github.com/pskucherov/tcsstat/tree/step3.1 https://github.com/pskucherov/tcsstat/compare/step3.1

  • Se qualcuno si imbatte in questo, allora benvenuto al problema . Dopo aver riparato questa magia, perderà il suo potere e sarà in qualche modo diversa. Ma al momento attuale (21/03/2023) funziona proprio così.

GetDividendsForeignIssuer

Qualcuno potrebbe pensare che il metodo sia simile al precedente e che tu possa utilizzare un unico metodo in cui cambi solo il nome delle operazioni. Ma non hanno indovinato!  La denominazione è molto diversa sia nei metodi che nelle informazioni restituite. E il conteggio delle pagine parte da 0, poi da 1. Per non confondersi in tutto questo, è più facile scrivere due metodi diversi. Il che è strano, perché la logica del lavoro è la stessa. Ho sputato a lungo quando ho provato a creare un metodo e c’era meno codice. Non ci saranno esempi qui.

GetOperationsByCursor

Il mio preferito dei tre. Sebbene non sia il più preciso, ma il più adeguato. Facciamo una richiesta dall’inizio della creazione di un account fino alla data massima possibile (chiusura di un account o quella corrente). Otteniamo la risposta, prendiamo il cursore e richiediamo finché ci sono dati.  E il codice è più conciso rispetto agli esempi precedenti.

const timer = tempo asincrono => {     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,             withoutTrades: false,             withoutOvernights: false,             cursor,         };           return wait sdk.operations.getOperationsByCursor(reqData);     } catch (e) {         wait timer(60000);         return wait getOperationsByCursor(sdk, accountId, from, to, cursor = ”);     } };

La bozza da eseguire è qui: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 Ora siamo pronti per aggiungere le operazioni di ricezione a la nostra applicazione. Se fatto correttamente, è necessario ottenere rapporti di intermediazione per l’intera esistenza dell’account. E per i dati mancanti, quegli stessi T-3, ricaricati dalle operazioni. Ma questo può essere separato in un articolo separato. Delle principali sfumature che incontrerai è incollare le operazioni e un rapporto di intermediazione.

  •  Se oggi hai ricevuto un rapporto di intermediazione e transazioni per le date richieste, inserisci tutto nel database, quindi non ci sono problemi. 
  • Domani avrai problemi quando riceverai la porzione successiva di dati dal rapporto e dalle operazioni e deciderai di sincronizzarli con il database esistente. 
  • Molte sfumature sull’ID non corrispondente o sulla modifica dopo l’elaborazione
  • Quindi per il mercato OTC, gli ID non corrispondono affatto.
  •  Così come le sfumature degli strumenti di sincronizzazione, che ancora una volta non coincidono, a causa delle peculiarità dell’API. Ma questa è un’altra storia.

Aggiungiamo ottenere informazioni sulle operazioni alla nostra applicazione. La domanda principale sarà dove i dati verranno elaborati e archiviati.

  •  Se lo fai per te stesso, consumerai gli stessi dati da dispositivi diversi. Quindi è necessario elaborare e archiviare i dati sul server.
  • Se hai molti dati diversi consumati da molti utenti diversi, allora devi decidere cosa è più importante: la velocità degli utenti o il risparmio di ferro dalla tua parte. Chi può permettersi una quantità infinita di hardware conta tutto sul suo server e lo rende super veloce per gli utenti, risparmiando le risorse dell’utente, come la batteria e il traffico, che è molto importante sui telefoni.

A sua volta, il conteggio nel browser non è in linea di principio la soluzione ottimale. Pertanto, ciò che non è costoso, lo consideriamo sul nostro server. Il resto lo lasciamo al cliente. Voglio davvero prendere e calcolare la commissione sul server. Ma ecco che arriva la sfumatura chiamata “interattività”. Diciamo che hai migliaia di operazioni e ci vogliono cinque minuti per riceverle. Cosa avrà l’utente in questo momento? Filatore? Progresso? Informazioni su quanto è stato caricato? È ideale utilizzare “l’attesa attiva” quando l’utente nel processo potrebbe già vedere qualcosa. Ecco il risultato:Stiamo sviluppando un microservizio utilizzando l'API Tinkoff Invest per automatizzare il lavoro con i rapporti di intermediazione e il calcolo delle commissioni.

  • Caricamento della pagina
  • Tutte le fatture sono richieste
  • Successivamente, tutte le transazioni con commissioni per le transazioni eseguite vengono richieste per tutti i conti. Man mano che i dati vengono ricevuti, vengono visualizzati nel browser.

Per non filtrare ogni volta i dati negli eventi, estraiamo il nostro evento per ciascun account. Come questo:

socket.emit(‘sdk:getOperationsCommissionResult_’ + accountId, {                 items: data?.items,                 inProgress: Boolean(nextCursor), });

La bozza da lanciare è qui: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Andiamo avanti. È fantastico che tu abbia letto questa riga! 

Calcolo e produzione di informazioni di interesse

Dipende da chi ha bisogno di quali informazioni. Pertanto, ti dico subito le principali sfumature che incontrerai.

Lavorare con i prezzi 

Tutti coloro che lavorano con la finanza sanno che le transazioni monetarie dovrebbero essere eseguite solo con numeri interi. A causa dell’imprecisione dei valori dopo il punto decimale e dell’errore cumulativo con un numero elevato di operazioni. Ecco perché tutti i prezzi sono presentati nel seguente formato MoneyValueStiamo sviluppando un microservizio utilizzando l'API Tinkoff Invest per automatizzare il lavoro con i rapporti di intermediazione e il calcolo delle commissioni.

campotipoDescrizione
valutacordaStringa codice valuta ISO
unitàint64Parte intera della somma, può essere un numero negativo
nanoint32La parte frazionaria dell’importo può essere un numero negativo

Li elaboriamo separatamente, quindi li portiamo al valore del prezzo:

quotazione.unità + quotazione.nano / 1e9

Il costo dei contratti futures

Il prezzo dei futures è presentato in punti, quando hai un future in valuta, devi conoscere il tasso. E ovviamente il prezzo in punti e il gradino di prezzo. Quando calcoli il profitto dalle transazioni, questo può sparare, perché. se calcoli l’importo totale moltiplicando il prezzo per la quantità. Qui devi stare attento. Per ora vedremo come va. Questo vale per i futures su valute, in altri posti va tutto bene.Stiamo sviluppando un microservizio utilizzando l'API Tinkoff Invest per automatizzare il lavoro con i rapporti di intermediazione e il calcolo delle commissioni.Stiamo sviluppando un microservizio utilizzando l'API Tinkoff Invest per automatizzare il lavoro con i rapporti di intermediazione e il calcolo delle commissioni.

mercato OTC

Questo mercato ha molte peculiarità, quindi studiamo le operazioni su di esso separatamente: quando inizi a sincronizzare le operazioni, risulterà che devi portare figi / ticker nella stessa forma per abbinare correttamente lo strumento. Quando inizi a sincronizzare questo con il rapporto di intermediazione, risulterà che il tradeID della stessa transazione ha lettere all’inizio delle transazioni e non sono nel rapporto di intermediazione. Pertanto, non possono essere confrontati … ehm-ehm … per confronto! Ho abbinato il tempo di scambio, il ticker e ho abbinato che un tradeId è contenuto in un altro. Esatto, non lo so. Chiunque incontri questo e chi se ne frega, vieni al problema o iniziane uno nuovo.Stiamo sviluppando un microservizio utilizzando l'API Tinkoff Invest per automatizzare il lavoro con i rapporti di intermediazione e il calcolo delle commissioni.

Operazioni matematiche sugli utensili

È impossibile, senza guardare, eseguire operazioni matematiche con l’intero elenco. Per non aggiungere warm a soft, controlliamo sempre la valuta ed elaboriamo solo se siamo sicuri che la valuta corrisponda e che i punti siano convertiti nella valuta desiderata. Armati della conoscenza del lavoro con i numeri bancari, calcoleremo la commissione spesa su ciascuno dei conti. In questo modo: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4Stiamo sviluppando un microservizio utilizzando l'API Tinkoff Invest per automatizzare il lavoro con i rapporti di intermediazione e il calcolo delle commissioni.   

Il microservizio è pronto!

https://github.com/pskucherov/tcsstat Come compito a casa, puoi verificare se il servizio funziona con una connessione lenta, quando le connessioni sono interrotte, quando Internet è disconnesso, quando errori o limiti scaduti da parte del broker. 

Conclusioni e progetti per il futuro

  • Imparato le operazioni di base e l’utilizzo dell’API Invest
  • Tempo trascorso ~ 10 ore
  • Livello di difficoltà ~ junior+ / medio basso 

Se continui a perfezionare il microservizio, potresti ritrovarti con qualcosa di simile

https://opexbot.info

  Questo è il mio sviluppo, per chi è troppo pigro per capire, correre e contare da solo. Ho intenzione di aggiungere analisi lì su richiesta degli utenti. Se ti è piaciuto l’articolo, iscriviti al mio canale Telegram . Stiamo sviluppando un microservizio utilizzando l'API Tinkoff Invest per automatizzare il lavoro con i rapporti di intermediazione e il calcolo delle commissioni.

Pavel
Rate author
Add a comment

  1. Isakiiev

    Полезная статья. Не могу представить, сколько усилий автора потребовалось, чтобы все описать. Благодарю.

    Rispondi