Инспираторите зад развојот на службата за статистика за Tinkoff Investments беа:
- статија на Хабре „Што не кажуваат Тинкоф инвестициите“
- анализа на желбите на корисниците на платформата
- напис за пресметка на провизии .
- Што ќе се дискутира?
- Развивање на услуга за статистика чекор по чекор:
- Поврзување со Tinkoff Invest API
- Цртање податоци од Tinkoff Invest API во прелистувач
- Примање брокерски извештаи и трансакции
- GetBrokerReport
- Начин за добивање на датумот, земајќи го предвид одземањето од тековниот датум
- Барање за генерирање извештаи
- Резултат:
- GetDividendsForeignIssuer
- GetOperationsByCursor
- Пресметка и излез на информации од интерес
- Работа со цени
- Трошокот за фјучерс договори
- пазар преку шалтер
- Математички операции на алатки
- Микросервисот е подготвен!
- Заклучоци и планови за во иднина
- https://opexbot.info
Што ќе се дискутира?
- Само применетиот дел за развој.
- Вистинско знаење и искуство, кои се многу важни при работа со финансиски инструменти.
- Преглед на прашања на кои треба да се работи
Значи, сакам да пресметам трговска статистика и да го направам тоа на пригоден начин.
Развивање на услуга за статистика чекор по чекор:
- Поврзување со Tinkoff Invest API
- Цртање податоци од Tinkoff Invest API во прелистувач
- Примање брокерски извештаи и трансакции
- Пресметка и излез на информации од интерес
- Заклучоци и планови за во иднина
Поврзување со Tinkoff Invest API
За да се поврзете со API, можете да земете која било sdk од документацијата https://github.com/Tinkoff/investAPI#sdk . Или npm пакет ` tinkoff-sdk-grpc-js` . Важно е пакетот да се ажурира на најновата верзија од страна на програмерите. Инсталирајте
npm и tinkoff-sdk-grpc-js
Проверка
const {createSdk } = бара (‘tinkoff-sdk-grpc-js’); // Токен што може да се добие вака const TOKEN = ‘YOURAPI’; // Името на апликацијата со која може да се најдете во дневниците на TCS. const appName = ‘tcsstat’; const sdk = createSdk(TOKEN, appName); (асинхронизиран () => { console.log(wait sdk.users.getAccounts()); })();
Резултат: списокот со вашите сметки ќе се прикаже во конзолата. На пример, да ги анализираме нијансите:
- Во списокот на сметки има „Инвестициска банка“, со која не можете да работите користејќи API
- Имајте предвид дека полињата доаѓаат во camelCase, додека во документацијата овие полиња се прикажани во under_score.
- Така ќе биде насекаде, така што не можете само да земете и копирате поле од документацијата.
Корисно:
- Овој код можете да го најдете во гранката на проектот
https://github.com/pskucherov/tcsstat/tree/step1 https://github.com/pskucherov/tcsstat/compare/step1
Цртање податоци од Tinkoff Invest API во прелистувач
Ги зедов next.js и socket.io. Ова не е силна препорака, изберете по ваша дискреција.
npx create-next-app@latest npm и socket.io socket.io-client
Веднаш продолжуваме со чекорот за пријателство next+socket+investapi и погледнете го делот Корисно од овој чекор за сите детали. Ќе ги опишам деталите:
- На страната nodejs (сервер), има датотека pages/api/investapi.js. Ова е местото каде што го создаваме серверот socket.io и се поврзуваме со investapi.
- На страната на прелистувачот (клиентот), се поврзуваме со серверот преку приклучок и бараме податоци за сметката од брокерот.
- Добиваме податоци од брокерот на серверот, а потоа ги испраќаме до клиентот. Кога ќе се примат на клиентот, тие се прикажуваат во прелистувачот.
Резултат: во конзолата на прелистувачот можеме да видиме информации за сметките. Тоа е, во последниот чекор, видовме информации за сметките во серверската конзола (nodejs), во тековниот чекор, ги префрливме овие информации на клиентот (прелистувачот).
Сега ајде да го направиме тоа така што можете да изберете сметка од прелистувачот, и ако нема токен, тогаш се испраќа грешка до конзолата. Работата е едноставна и ништо ново, затоа давам само линкови до обврзници
- https://github.com/pskucherov/tcsstat/commit/7e1ac57061e5e971588479015b06d8814d6609a9
- https://github.com/pskucherov/tcsstat/commit/b28ac973a57494f5232589b4cb6b9fb13b8af759
Корисно:
- Како да се дружите следната и сокетот е детално опишан овде .
- Код за пријателство next+socket+investapi:
https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 За кого горенаведеното е тешко, тогаш остануваме во оваа фаза и се занимаваме со кодот. Ако имате прашања – прашајте. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2
Примање брокерски извештаи и трансакции
Постојат три методи за примање брокерски извештаи и трансакции
Од самиот почеток важно е да се знае:
- Извештајот за посредување се генерира во режимот Т-3, т.е. занаетите се прикажуваат таму по нивното вистинско извршување.
- Според тоа, ако го побарате овој извештај за последните два дена, тој ќе биде готов за три дена.
- За да правиме зделки за последните денови, го користиме методот за примање операции, но запомнете дека нивниот ID и содржина може да се променат по формирањето на брокерскиот извештај.
GetBrokerReport
За да добиете извештај за посредување, треба да го земете идентификаторот на сметката, датумот на почеток и датумот на завршување на извештајот, но не повеќе од 31 ден. Испраќаме барање за генерирање извештај до API во генерира _broker_report_request , како одговор добиваме taskId. После тоа, користејќи го овој taskId, добиваме податоци од get _broker_report_response. [спојлер title=”Така вели документацијата, во реалноста има нијанси. Внимавајте на рацете:”]
- Треба да го зачувате TaskID засекогаш токму за овие датуми.
- Бидејќи ако го изгубите, тогаш за бараните датуми извештајот прво ќе дојде како одговор на барањето за генерирање,
- И тогаш воопшто нема да дојде.
[/спојлер] Ајде да почнеме да пишуваме код
Начин за добивање на датумот, земајќи го предвид одземањето од тековниот датум
const getDateSubDay = (subDay = 5, start = true) => { const date = new Date(); date.setUTCDate(date.getUTCDate() – подден); if (start) { date.setUTCHours(0, 0, 0, 0); } else { date.setUTCHours(23, 59, 59, 999); } датум на враќање; };
Барање за генерирање извештаи
const brokerReport = чекаат (sdk.operations.getBrokerReport) ({ genereBrokerReportRequest: { accountId, from, to, }, });
Резултат:
- Како резултат на првото извршување на командата, го добиваме taskId.
- Извештајот почнува да се генерира на страната на брокерот. Кога е подготвено е непознато, чекаме и периодично го повлекуваме taskId во пресрет на извештајот.
- Зошто? Затоа што ако извештајот не е подготвен, фрла грешка. Ако извештајот не е подготвен од страната на брокерот, тогаш ова е грешка во вашиот код. Ве молиме обработете: 30058|INVALID_ARGUMENT|задачата сè уште не е завршена, ве молиме обидете се повторно подоцна
Шифрата за чекање и примање извештај изгледа отприлика вака.
const timer = async time => { return new Promise(resolve => setTimeout(resolve, time)); } const getBrokerResponseByTaskId = async (taskId, страница = 0) => { try { return await (sdk.operations.getBrokerReport)({ getBrokerReportRequest: { taskId, page, }, }); } catch (e) { console.log(‘wait’, e); тајмер за чекање (10000); враќање чека getBrokerResponseByTaskId(taskId, страница); } };
Потоа се случува истата магија. Ја запираме нашата скрипта, ја започнуваме повторно, немаме taskId. Го извршуваме кодот со барањето taskId, но веќе не го добиваме taskId, туку веднаш извештајот. Магија! И се ќе беше во ред да беше секогаш вака. Но, за еден месец воопшто нема да има податоци. Корисно :
- Малку теорија е наведена овде и овде .
- Составувајќи го кодот заедно, нацртот ќе изгледа отприлика вака.
https://github.com/pskucherov/tcsstat/tree/step3.1 https://github.com/pskucherov/tcsstat/compare/step3.1
- Ако некој наиде на ова, тогаш добредојде на ова прашање . Откако ќе ја поправат оваа магија, таа ќе ја изгуби својата моќ и ќе биде некако поинаква. Но, во моменталниот момент (21.03.2023) функционира токму така.
GetDividendsForeignIssuer
Некој може да помисли дека методот е сличен на претходниот и можете да користите единствен метод во кој само го менувате името на операциите. Но, тие не погодија! Именувањето таму е многу различно и во методите и во вратените информации. И бројот на страници започнува од 0, потоа од 1. За да не се мешате во сето ова, полесно е да напишете два различни методи. Што е чудно, бидејќи логиката на работа е иста. Плукав долго време кога се обидов да направам еден метод и имаше помалку код. Тука нема да има примери.
GetOperationsByCursor
Мојот омилен од трите. Иако не најточно, но најадекватно. Бараме од почетокот на креирањето на сметка до максималниот можен датум (затворање сметка или тековната). Го добиваме одговорот, го земаме курсорот и повторно бараме се додека има податоци. И кодот е поконцизен отколку во примерите погоре.
const timer = async time => { return new Promise(resolve => setTimeout(resolve, time)); } const getOperationsByCursor = асинхронизиран (sdk, accountId, од, до, курсор = ”) => { try { const reqData = { accountId, од, до, ограничување: 1000, состојба: sdk.OperationState.OPERATION_STATE_EXECUTED, без провизии, неточно: без Трговија: неточно, без Ноќевања: лажно, курсорот, }; враќање на чекање sdk.operations.getOperationsByCursor(reqData); } catch (e) { await timer (60000); враќање чека getOperationsByCursor(sdk, accountId, from, to, cursor = ”); } };
Нацртот што треба да се изврши е тука: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 Сега сме подготвени да додадеме операции за примање на нашата апликација. Ако е направено правилно, тогаш треба да добивате брокерски извештаи за целото постоење на сметката. А за податоците што недостасуваат, истите тие Т-3, претовар од операции. Но, ова може да се подели во посебна статија. Од главните нијанси со кои ќе наидете е да ги залепите операциите и брокерскиот извештај.
- Ако денес сте добиле брокерски извештај и трансакции за бараните датуми, ставете го сето тоа во базата на податоци, тогаш нема проблеми.
- Ќе имате проблеми утре кога ќе го добиете следниот дел од податоците од извештајот и операциите и ќе одлучите да ги синхронизирате со постоечката база на податоци.
- Многу нијанси за неусогласеност или промена на ид по обработката
- Тогаш за пазарот преку шалтер, ид-ите воопшто не се совпаѓаат.
- Како и нијансите на синхронизирачките инструменти, кои повторно не се совпаѓаат, поради особеностите на API. Но, тоа е друга приказна.
Ајде да додадеме добивање информации за операциите во нашата апликација. Главното прашање ќе биде каде ќе се обработуваат и складираат податоците.
- Ако го направите тоа за себе, ќе ги консумирате истите податоци од различни уреди. Потоа треба да обработувате и складирате податоци на серверот.
- Ако имате многу различни податоци што ги консумираат многу различни корисници, тогаш треба да одлучите што е поважно: брзината на корисниците или заштедата на железо на ваша страна. Кој може да си дозволи бесконечна количина на хардвер, брои сè на својот сервер и го прави супер брз за корисниците, заштедувајќи ги корисничките ресурси, како што се батеријата и сообраќајот, што е многу важно за телефоните.
За возврат, броењето во прелистувачот во принцип не е најоптимално решение. Затоа, она што не е скапо, го сметаме на нашиот сервер. Остатокот го оставаме на клиентот. Навистина сакам да земам и да ја пресметам провизијата на серверот. Но, тука доаѓа нијансата наречена „интерактивност“. Да речеме дека имате илјадници операции и потребни се пет минути за да ги примите. Што ќе има корисникот во овој момент? Спинер? Напредок? Инфа за тоа колку е поставено? Идеално е да се користи „активно чекање“ кога корисникот во процесот веќе може да види нешто. Еве го резултатот:
- Вчитување на страницата
- Се бараат сите фактури
- После тоа, за сите сметки се бараат сите трансакции со провизии за извршени трансакции. Како што се примаат податоците, тие се прикажуваат во прелистувачот.
За да не ги филтрираме податоците во настаните секој пат, ние повлекуваме свој настан за секоја сметка. Како ова:
socket.emit(‘sdk:getOperationsCommissionResult_’ + accountId, { items: data?.items, inProgress: Boolean(nextCursor), });
Нацртот за лансирање е тука: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Продолжуваме понатаму. Прекрасно е што го прочитавте овој ред!
Пресметка и излез на информации од интерес
Зависи на кого какви информации му требаат. Затоа, веднаш ви ги кажувам главните нијанси со кои ќе се сретнете.
Работа со цени
Секој кој работи со финансии знае дека паричните трансакции треба да се вршат само со цели бројки. Поради неточноста на вредностите по децималната точка и кумулативната грешка со голем број операции. Затоа сите цени се претставени во следниот MoneyValue формат
Поле | тип | Опис |
---|---|---|
валута | низа | Низа ISO код за валута |
единици | int64 | Целиот дел од збирот може да биде негативен број |
нано | int32 | Дробен дел од износот, може да биде негативен број |
Ги обработуваме одделно, па ги доведуваме до ценовната вредност:
цитат.единици + цитат.нано / 1е9
Трошокот за фјучерс договори
Цената на фјучерсите е претставена во поени, кога имате валутна иднина, треба да ја знаете стапката. И секако цената во поени и чекорот на цената. Кога ќе го пресметате профитот од трансакциите, ова може да пука, бидејќи. ако вкупниот износ го пресметате со множење на цената со количината. Тука треба да бидете внимателни. Засега ќе видиме како ќе биде. Ова се однесува на фјучерси на валута, на други места се е ок со ова.
пазар преку шалтер
Овој пазар има многу особености, па ајде да ги проучиме операциите на него одделно. Кога ќе започнете да ги синхронизирате операциите, ќе испадне дека треба да го доведете фиги / тикер во иста форма за правилно да се совпадне со инструментот. Кога ќе почнете да го синхронизирате ова со брокерскиот извештај, ќе испадне дека tradeID на истата трансакција има букви на почетокот во трансакциите и тие ги нема во извештајот за посредување. Затоа, тие не можат да се споредат … ахем-ахем … со споредба! Го совпаднав времето на тргување, тикерот и совпаѓањето дека еден tradeId е содржан во друг. Точно, не знам. Кој и да се сретне со ова и кому му е гајле за тоа, дојдете до прашањето или започнете ново.
Математички операции на алатки
Невозможно е, без гледање, да се извршат математички операции со целата листа. За да не додадеме топло на меко, секогаш ја проверуваме валутата и обработуваме само ако сме сигурни дека валутата се совпаѓа, а поените се претвораат во саканата валута. Вооружени со знаење за работа со банкарски броеви, ќе ја пресметаме потрошената провизија за секоја од сметките. Вака: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4
Микросервисот е подготвен!
Htt _
Заклучоци и планови за во иднина
- Научи за основните операции и работа со Invest API
- Поминато време ~ 10 часа
- Ниво на тежина ~ помлад+ / низок среден
Ако продолжите да го усовршувате микросервисот, може да завршите со нешто како ова
https://opexbot.info
Ова е мојот развој, за оние кои се премногу мрзливи да сфатат, да трчаат и сами да сметаат. Планирам таму да додадам аналитика на барање на корисниците. Ако ви се допадна статијата, тогаш претплатете се на мојот канал за телеграма .
Полезная статья. Не могу представить, сколько усилий автора потребовалось, чтобы все описать. Благодарю.