Estamos desarrollando un microservicio utilizando Tinkoff Invest API para automatizar el trabajo con informes de corretaje y el cálculo de comisiones.

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

Los inspiradores detrás del desarrollo del servicio de estadísticas para Tinkoff Investments fueron:

¿Qué se discutirá?

  • Sólo la parte aplicada sobre el desarrollo.
  • Conocimiento y experiencia reales, que son muy importantes en el trabajo con instrumentos financieros.
  • Descripción general de los problemas a trabajar

Entonces, quiero calcular las estadísticas comerciales y hacerlo de una manera conveniente. 

Desarrollando un servicio de estadísticas paso a paso: 

  1. Conexión a la API de Tinkoff Invest
  2. Dibujar datos de Tinkoff Invest API en un navegador
  3. Recepción de informes y transacciones de corretaje
  4. Cálculo y salida de información de interés
  5. Conclusiones y planes para el futuro.

Conexión a la API de Tinkoff Invest

Para conectarse a la API, puede tomar cualquier SDK de la documentación https://github.com/Tinkoff/investAPI#sdk . O el paquete npm ` tinkoff-sdk-grpc-js `. Es importante que los desarrolladores actualicen el paquete a la última versión. Instalar

npm tinkoff-sdk-grpc-js

Comprobación

const { createSdk } = require(‘tinkoff-sdk-grpc-js’);   // Token que se puede obtener así  const TOKEN = ‘TUPI’;   // El nombre de la aplicación por la que se le puede encontrar en los registros de TCS. const appName = ‘tcsstat’;   const sdk = createSdk(TOKEN, appName); (async () => {     console.log(await sdk.users.getAccounts()); })();

Resultado: se mostrará una lista de sus cuentas en la consola. Por ejemplo, analicemos los matices:Estamos desarrollando un microservicio utilizando Tinkoff Invest API para automatizar el trabajo con informes de corretaje y el cálculo de comisiones.

  • En el listado de cuentas hay un “Banco de inversión”, con el que no se puede trabajar usando la API
  • Tenga en cuenta que los campos vienen en camelCase, mientras que en la documentación estos campos se presentan en under_score. 
  • Será así en todas partes, por lo que no puede simplemente tomar y copiar un campo de la documentación.

Útil:

  • Puedes encontrar este código en la rama del proyecto.

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

Dibujar datos de Tinkoff Invest API en un navegador

Tomé next.js y socket.io. Esta no es una recomendación fuerte, elija a su discreción. 

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

Inmediatamente pasamos al paso de amistad next+socket+investapi, y vemos la sección Útil de este paso para conocer todos los detalles.  Voy a describir los detalles: 

  • En el lado de nodejs (servidor), hay un archivo pages/api/investapi.js. Aquí es donde creamos el servidor socket.io y nos conectamos a investapi.
  • En el lado del navegador (cliente), nos conectamos al servidor a través de un socket y solicitamos los datos de la cuenta al corredor. 
  • Recibimos datos del corredor en el servidor y luego los enviamos al cliente. Cuando se reciben en el cliente, se muestran en el navegador. 

Resultado:  en la consola del navegador podemos ver información sobre las cuentas. Es decir, en el último paso, vimos información sobre las cuentas en la consola del servidor (nodejs), en el paso actual, transferimos esta información al cliente (navegador).

Estamos desarrollando un microservicio utilizando Tinkoff Invest API para automatizar el trabajo con informes de corretaje y el cálculo de comisiones.

Ahora hagamos que pueda seleccionar una cuenta desde el navegador, y si no hay token, se envía un error a la consola. El trabajo es simple y nada nuevo, por lo que solo doy enlaces a confirmaciones.

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

Útil:

  • Cómo hacer amigos a continuación y socket se describe en detalle aquí
  • Código de amistad siguiente+socket+investapi:

https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 Para quienes lo anterior es difícil, permanecemos en esta etapa y nos ocupamos del código. Si tiene alguna pregunta, pregunte. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2

Recepción de informes y transacciones de corretaje

Hay tres métodos para recibir informes y transacciones de corretaje

  1. Obtener informe de intermediario
  2. ObtenerDividendosEmisor Extranjero
  3. ObtenerOperacionesPorCursor

Desde el principio es importante saber: 

  • El informe de corretaje se genera en el modo T-3, es decir las transacciones se muestran allí después de su ejecución real. 
  • Por lo tanto, si solicita este informe de los últimos dos días, estará listo en tres días. 
  • Para obtener transacciones de los últimos días, usamos el método para recibir transacciones, pero recuerde que su id y contenido pueden cambiar después de generar el informe de corretaje.

Obtener informe de intermediario

Para obtener un informe de corretaje, debe tomar la identificación de la cuenta, la fecha de inicio y la fecha de finalización del informe, pero no más de 31 días. Enviamos una solicitud para generar un informe a la API en generar _broker_report_request , obtenemos un ID de tarea en respuesta. Después de eso, usando este ID de tarea, obtenemos datos de get _broker_report_response.

Así dice la documentación, en realidad hay matices. Cuidado con las manos:
  • Debe guardar el TaskID para siempre exactamente para estas fechas. 
  • Dado que si lo pierde, entonces para las fechas solicitadas, el informe vendrá primero en respuesta a la solicitud de generación, 
  • Y entonces no vendrá en absoluto.
Empecemos a escribir código

Método para obtener la fecha, teniendo en cuenta la resta de la fecha actual

const getDateSubDay = (subDay = 5, start = true) => {     const date = new Date();     fecha.setUTCDate(fecha.getUTCDate() – subDía);       if (inicio) {         fecha.setUTCHours(0, 0, 0, 0);     } else {         fecha.setUTCHours(23, 59, 59, 999);     }       fecha de regreso; };

Solicitud de generación de informes 

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

Resultado:

  • Como resultado de la primera ejecución del comando, obtenemos el taskId. 
  • El informe comienza a generarse en el lado del corredor. Cuando está listo es desconocido, esperamos y extraemos periódicamente el taskId antes del informe.
  • ¿Por qué? Porque si el informe no está listo, arroja un error. Si el informe no está listo por parte del corredor, entonces se trata de un error en su código. Procese: 30058|INVALID_ARGUMENT|tarea aún no completada, inténtelo de nuevo más tarde

El código para esperar y recibir un informe se parece a esto.

const timer = async time => {     return new Promise(resolve => setTimeout(resolve, time)); }   const getBrokerResponseByTaskId = asíncrono (taskId, página = 0) => {     try {         return await (sdk.operations.getBrokerReport)({             getBrokerReportRequest: {                 taskId,                 página,             },         });     } catch (e) {         console.log(‘esperar’, e);         esperar temporizador (10000);         volver esperar getBrokerResponseByTaskId(taskId, página);     } };

Entonces ocurre la misma magia. Detenemos nuestro script, lo iniciamos de nuevo, no tenemos un ID de tarea. Ejecutamos el código con la solicitud taskId, pero ya no obtenemos el taskId, sino inmediatamente el informe. ¡Magia! Y todo estaría bien si siempre fuera así. Pero en un mes no habrá datos en absoluto. útil :

  • Un poco de teoría se describe aquí y aquí .
  • Al juntar el código, el borrador se verá así.

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

  • Si alguien se encuentra con esto, entonces bienvenido al problema . Después de que reparen esta magia, perderá su poder y será de alguna manera diferente. Pero en el momento actual (21/03/2023) funciona así.

ObtenerDividendosEmisor Extranjero

Alguien podría pensar que el método es similar al anterior y puedes usar un único método en el que solo cambias el nombre de las operaciones. ¡Pero no lo adivinaron!  La denominación allí es muy diferente tanto en los métodos como en la información devuelta. Y el recuento de páginas comienza desde 0, luego desde 1. Para no confundirse con todo esto, es más fácil escribir dos métodos diferentes. Lo cual es extraño, porque la lógica de trabajo es la misma. Escupí durante mucho tiempo cuando traté de hacer un método y había menos código. No habrá ejemplos aquí.

ObtenerOperacionesPorCursor

Mi favorito de los tres. Aunque no la más precisa, pero sí la más adecuada. Hacemos una solicitud desde el inicio de la creación de una cuenta hasta la fecha máxima posible (cierre de una cuenta o la actual). Obtenemos la respuesta, tomamos el cursor y volvemos a solicitar siempre que haya datos.  Y el código es más conciso que en los ejemplos anteriores.

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,             sin Comisiones: falso,             sinTrades: falso,             sinAlojamientos: falso,             cursor,         };           volver esperar sdk.operations.getOperationsByCursor(reqData);     } catch (e) {         temporizador de espera (60000);         return await getOperationsByCursor(sdk, accountId, from, to, cursor = »);     } };

El borrador para ejecutar está aquí: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 Ahora estamos listos para agregar operaciones de recepción a nuestra aplicación. Si se hace correctamente, debe obtener informes de corretaje para toda la existencia de la cuenta. Y para los datos faltantes, esos mismos T-3, recargar desde operaciones. Pero esto se puede separar en un artículo separado. De los principales matices que encontrará es pegar operaciones y un informe de corretaje.

  •  Si hoy recibió un informe de corretaje y transacciones para las fechas requeridas, póngalo todo en la base de datos, entonces no hay problemas. 
  • Tendrá problemas mañana cuando reciba la siguiente porción de datos del informe y las operaciones y decida sincronizarlos con la base de datos existente. 
  • Muchos matices sobre la identificación no coincidente o cambiante después del procesamiento
  • Luego, para el mercado OTC, las identificaciones no coinciden en absoluto.
  •  Así como los matices de sincronizar instrumentos, que de nuevo no coinciden, por las peculiaridades de la API. Pero esa es otra historia.

Agreguemos obtener información sobre operaciones a nuestra aplicación. La pregunta principal será dónde se procesarán y almacenarán los datos.

  •  Si lo haces por ti mismo, consumirás los mismos datos desde diferentes dispositivos. Luego necesita procesar y almacenar datos en el servidor.
  • Si tiene una gran cantidad de datos diferentes consumidos por muchos usuarios diferentes, entonces debe decidir qué es más importante: la velocidad de los usuarios o el ahorro de hierro de su lado. Quien puede permitirse una cantidad infinita de hardware cuenta todo en su servidor y lo hace súper rápido para los usuarios, ahorrando recursos al usuario, como la batería y el tráfico, que es muy importante en los teléfonos.

A su vez, contar en el navegador no es la solución más óptima en principio. Por lo tanto, lo que no es caro, lo consideramos en nuestro servidor. El resto lo dejamos al cliente. Tengo muchas ganas de tomar y calcular la comisión en el servidor. Pero aquí viene el matiz llamado “interactividad”. Digamos que tienes miles de operaciones y tardas cinco minutos en recibirlas. ¿Qué tendrá el usuario en este momento? ¿Hilandero? ¿Progreso? Infa acerca de cuánto se subió? Es ideal usar “espera activa” cuando el usuario en el proceso ya pudo ver algo. Aquí está el resultado:Estamos desarrollando un microservicio utilizando Tinkoff Invest API para automatizar el trabajo con informes de corretaje y el cálculo de comisiones.

  • Cargando página
  • Se solicitan todas las facturas
  • Después de eso, todas las transacciones con comisiones por transacciones ejecutadas se solicitan para todas las cuentas. A medida que se reciben los datos, se procesan en el navegador.

Para no filtrar los datos en los eventos cada vez, extraemos nuestro propio evento para cada cuenta. Como esto:

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

El borrador para lanzar está aquí: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Continuando. ¡Qué bueno que hayas leído esta línea! 

Cálculo y salida de información de interés

Depende de quién necesita qué información. Por eso, inmediatamente te cuento los principales matices que encontrarás.

Trabajando con precios 

Todos los que trabajan con finanzas saben que las transacciones de dinero solo deben realizarse con números enteros. Debido a la imprecisión de los valores posteriores al punto decimal y al error acumulativo con un gran número de operaciones. Es por eso que todos los precios se presentan en el siguiente formato MoneyValueEstamos desarrollando un microservicio utilizando Tinkoff Invest API para automatizar el trabajo con informes de corretaje y el cálculo de comisiones.

campotipoDescripción
divisacadenaCódigo de moneda ISO de cadena
unidadesint64Parte entera de la suma, puede ser un número negativo
nanoint32Parte fraccionaria de la cantidad, puede ser un número negativo

Los procesamos por separado, luego los llevamos al valor del precio:

cotización.unidades + cotización.nano / 1e9

El costo de los contratos de futuros

El precio de los futuros se presenta en puntos, cuando tiene un futuro de divisas, necesita saber la tasa. Y por supuesto el precio en puntos y el escalón de precio. Cuando calcula el beneficio de las transacciones, esto puede dispararse, porque. si calcula la cantidad total multiplicando el precio por la cantidad. Aquí hay que tener cuidado. Por ahora, veremos cómo va. Esto se aplica a los futuros de divisas, en otros lugares todo está bien con esto.Estamos desarrollando un microservicio utilizando Tinkoff Invest API para automatizar el trabajo con informes de corretaje y el cálculo de comisiones.Estamos desarrollando un microservicio utilizando Tinkoff Invest API para automatizar el trabajo con informes de corretaje y el cálculo de comisiones.

mercado OTC

Este mercado tiene muchas peculiaridades, así que estudiemos las operaciones en él por separado.Cuando comience a sincronizar las operaciones, resultará que necesita llevar figi / ticker al mismo formulario para que coincida correctamente con el instrumento. Cuando comience a sincronizar esto con el informe de corretaje, resultará que el tradeID de la misma transacción tiene letras al principio de las transacciones y no están en el informe de corretaje. Por lo tanto, no se pueden comparar… ejem-ejem… ¡por comparación! Hice coincidir el tiempo de negociación, el ticker y la coincidencia de que un tradeId está contenido en otro. Correcto, no sé. Quien se encuentre con esto y a quien le importe, venga al problema o comience uno nuevo.Estamos desarrollando un microservicio utilizando Tinkoff Invest API para automatizar el trabajo con informes de corretaje y el cálculo de comisiones.

Operaciones matemáticas sobre herramientas.

Es imposible, sin mirar, realizar operaciones matemáticas con toda la lista. Para no agregar cálido a suave, siempre verificamos la moneda y procesamos solo si estamos seguros de que la moneda coincide y los puntos se convierten a la moneda deseada. Armados con el conocimiento sobre cómo trabajar con números bancarios, calcularemos la comisión gastada en cada una de las cuentas. Así: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4Estamos desarrollando un microservicio utilizando Tinkoff Invest API para automatizar el trabajo con informes de corretaje y el cálculo de comisiones.   

¡El microservicio está listo!

https://github.com/pskucherov/tcsstat Como tarea, puede verificar si el servicio funciona con una conexión lenta, cuando las conexiones están rotas, cuando Internet está desconectado, cuando hay errores o límites vencidos por parte del corredor. 

Conclusiones y planes para el futuro.

  • Aprendió sobre las operaciones básicas y cómo trabajar con la API de Invest
  • Tiempo empleado ~ 10 horas
  • Nivel de dificultad ~ junior+ / medio bajo 

Si continúa refinando el microservicio, podría terminar con algo como esto

https://opexbot.info

  Este es mi desarrollo, para aquellos que son demasiado perezosos para comprender, correr y contar por sí mismos. Planeo agregar análisis allí a pedido de los usuarios. Si te gustó el artículo, suscríbete a mi canal de Telegram . Estamos desarrollando un microservicio utilizando Tinkoff Invest API para automatizar el trabajo con informes de corretaje y el cálculo de comisiones.

Pavel
Rate author
Add a comment

  1. Isakiiev

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

    Responder