La inspirantoj malantaŭ la evoluo de la statistika servo por Tinkoff Investments estis:
- artikolo pri Habré “Kion Tinkoff Investments ne diras”
- analizo de la deziroj de platformaj uzantoj
- artikolo pri la kalkulo de komisionoj .
- Pri kio oni diskutos?
- Evoluigante statistikan servon paŝon post paŝo:
- Konekto al Tinkoff Invest API
- Desegnante datumojn de Tinkoff Invest API en retumilo
- Ricevante kurtaĝajn raportojn kaj transakciojn
- GetBrokerRaport
- Metodo por ricevi la daton, konsiderante la subtraho de la aktuala dato
- Peto pri generado de raporto
- Rezulto:
- GetDividendsForeignIssuer
- GetOperationsByCursor
- Kalkulo kaj eligo de interesaj informoj
- Laborante kun prezoj
- La kosto de estontaj kontraktoj
- OTC-merkato
- Matematikaj operacioj pri iloj
- Mikroservo estas preta!
- Konkludoj kaj planoj por la estonteco
- https://opexbot.info
Pri kio oni diskutos?
- Nur la aplikata parto pri evoluo.
- Reala scio kaj sperto, kiuj estas tre gravaj por labori kun financaj instrumentoj.
- Superrigardo de aferoj por labori
Do, mi volas kalkuli komercajn statistikojn kaj fari ĝin en oportuna maniero.
Evoluigante statistikan servon paŝon post paŝo:
- Konekto al Tinkoff Invest API
- Desegnante datumojn de Tinkoff Invest API en retumilo
- Ricevante kurtaĝajn raportojn kaj transakciojn
- Kalkulo kaj eligo de interesaj informoj
- Konkludoj kaj planoj por la estonteco
Konekto al Tinkoff Invest API
Por konektiĝi al la API, vi povas preni ajnan sdk el la dokumentado https://github.com/Tinkoff/investAPI#sdk . Aŭ npm-pakaĵo ` tinkoff-sdk-grpc-js `. Gravas, ke la pakaĵo estas ĝisdatigita al la plej nova versio de la programistoj. Instali
npm i tinkoff-sdk-grpc-js
Kontrolado
const { createSdk } = require(‘tinkoff-sdk-grpc-js’); // Token kiu povas esti akirita tiel const TOKEN = ‘YOURAPI’; // La nomo de la aplikaĵo per kiu vi troviĝas en la protokoloj de TCS. const appName = ‘tcsstat’; const sdk = createSdk(TOKEN, appName); (async () => { console.log (atendo sdk.users.getAccounts ()); })();
Rezulto: listo de viaj kontoj estos montrata en la konzolo. Ekzemple, ni analizu la nuancojn:
- En la listo de kontoj estas “Investa banko”, kun kiu vi ne povas labori uzante la API
- Bonvolu noti, ke la kampoj venas en camelCase, dum en la dokumentaro ĉi tiuj kampoj estas prezentitaj en sub_poentaro.
- Ĉie estos tiel, do vi ne povas simple preni kaj kopii kampon el la dokumentaro.
Utila:
- Vi povas trovi ĉi tiun kodon en la projektbranĉo
https://github.com/pskucherov/tcsstat/tree/step1 https://github.com/pskucherov/tcsstat/compare/step1
Desegnante datumojn de Tinkoff Invest API en retumilo
Mi prenis next.js kaj socket.io. Ĉi tio ne estas forta rekomendo, elektu laŭ via bontrovo.
npx create-next-app@latest npm i socket.io socket.io-kliento
Ni tuj iras al la amikeca paŝo sekva+socket+investapi, kaj vidu la Utilan sekcion de ĉi tiu paŝo por ĉiuj detaloj. Mi priskribos la detalojn:
- Ĉe la flanko nodejs (servilo), estas dosiero pages/api/investapi.js. Ĉi tie ni kreas la servilon socket.io kaj konektas al investapi.
- Ĉe la retumilo (kliento), ni konektas al la servilo per ingo kaj petas kontajn datumojn de la makleristo.
- Ni ricevas datumojn de la makleristo sur la servilo, poste sendas ĝin al la kliento. Kiam ili estas ricevitaj sur la kliento, ili estas montrataj en la retumilo.
Rezulto: en la retumila konzolo ni povas vidi informojn pri kontoj. Tio estas, en la lasta paŝo, ni vidis informojn pri kontoj en la servila konzolo (nodejs), en la nuna paŝo, ni transdonis ĉi tiun informon al la kliento (retumilo).
Nun ni faru ĝin tiel, ke vi povas elekti konton el la retumilo, kaj se ne ekzistas signo, tiam eraro estas sendita al la konzolo. La laboro estas simpla kaj nenio nova, do mi donas nur ligilojn al kommits
- https://github.com/pskucherov/tcsstat/commit/7e1ac57061e5e971588479015b06d8814d6609a9
- https://github.com/pskucherov/tcsstat/commit/b28ac973a57494f5232589b4cb6b9fb13b8af759
Utila:
- Kiel fari amikojn poste kaj socket estas priskribita detale ĉi tie .
- Amikeca kodo sekva+socket+investapi:
https://github.com/pskucherov/tcsstat/commit/a443a4ac1bb4f0aa898f638128755fe7391ee381 Por kiuj la supre estas malfacila, tiam ni restas en ĉi tiu etapo kaj traktas la kodon. Se vi havas demandojn – demandu. https://github.com/pskucherov/tcsstat/tree/step2 https://github.com/pskucherov/tcsstat/compare/step1…step2
Ricevante kurtaĝajn raportojn kaj transakciojn
Estas tri metodoj por ricevi kurtaĝajn raportojn kaj transakciojn
De la komenco estas grave scii:
- La kurtaga raporto estas generita en la T-3-reĝimo, t.e. komercoj estas montrataj tie post sia reala ekzekuto.
- Sekve, se vi petos ĉi tiun raporton dum la lastaj du tagoj, ĝi estos preta post tri tagoj.
- Por akiri transakciojn dum la lastaj tagoj, ni uzas la metodon por ricevi transakciojn, sed memoru, ke ilia identigilo kaj enhavo povas ŝanĝiĝi post kiam la kurtaĝa raporto estas generita.
GetBrokerRaport
Por ricevi kurtagan raporton, vi devas preni la kontan identigilon, komencan daton kaj findaton de la raporto, sed ne pli ol 31 tagojn. Ni sendas peton por generi raporton al la API en generate _broker_report_request , ricevas taskId en respondo. Post tio, uzante ĉi tiun taskId, ni ricevas datumojn de get _broker_report_response.
- Vi devas konservi la TaskID por ĉiam ĝuste por ĉi tiuj datoj.
- Ĉar se vi perdos ĝin, tiam por la petitaj datoj la raporto unue venos responde al la generacia peto,
- Kaj tiam ĝi tute ne venos.
Metodo por ricevi la daton, konsiderante la subtraho de la aktuala dato
const getDateSubTay = (subTay = 5, start = true) => { const dato = nova Dato (); dato.setUTCDate (date.getUTCDate () – subTago); if (komenco) { dato.setUTCHours (0, 0, 0, 0); } else { date.setUTCHours (23, 59, 59, 999); } revendato; };
Peto pri generado de raporto
const brokerReport = atendi (sdk.operations.getBrokerReport) ({ generiBrokerReportRequest: { accountId, from, to, }, });
Rezulto:
- Kiel rezulto de la unua ekzekuto de la komando, ni ricevas la taskId.
- La raporto komencas esti generita flanke de la makleristo. Kiam ĝi estas preta estas nekonata, ni atendas kaj periode tiras la taskId en antaŭĝojo de la raporto.
- Kial? Ĉar se la raporto ne estas preta, ĝi ĵetas eraron. Se la raporto ne estas preta flanke de la makleristo, tiam ĉi tio estas eraro en via kodo. Bonvolu procesi: 30058|INVALID_ARGUMENT|tasko ankoraŭ ne kompletigita, bonvolu provi denove poste
La kodo por atendi kaj ricevi raporton aspektas kiel ĉi tio.
const timer = nesinkrona tempo => { return new Promise (solvi => setTimeout (solvi, tempo)); } const getBrokerResponseByTaskId = async (taskId, paĝo = 0) => { provu { return await (sdk.operations.getBrokerReport)({ getBrokerReportRequest: { taskId, paĝo, }, }); } catch (e) { console.log(‘atendu’, e); atendi tempigilon (10000); reveni atendu getBrokerResponseByTaskId (taskId, paĝo); } };
Tiam la sama magio okazas. Ni ĉesas nian skripton, rekomencu ĝin, ni ne havas taskId. Ni plenumas la kodon kun la peto taskId, sed ni ne plu ricevas la taskId, sed tuj la raporton. Magio! Kaj ĉio estus bone, se ĉiam estus tiel. Sed post monato tute ne estos datumoj. Utila :
https://github.com/pskucherov/tcsstat/tree/step3.1 https://github.com/pskucherov/tcsstat/compare/step3.1
- Se iu renkontas ĉi tion, do bonvenon al la afero . Post kiam ili riparos ĉi tiun magion, ĝi perdos sian potencon kaj estos iel malsama. Sed en la nuna momento (21/03/2023) ĝi funkcias ĝuste tiel.
GetDividendsForeignIssuer
Iu povus pensi, ke la metodo similas al la antaŭa kaj vi povas uzi ununuran metodon, en kiu vi nur ŝanĝas la nomon de la operacioj. Sed ili ne divenis! La nomado tie estas tre malsama kaj en la metodoj kaj en la redonitaj informoj. Kaj la paĝkalkulo komenciĝas de 0, poste de 1. Por ne konfuziĝi pri ĉio ĉi, estas pli facile skribi du malsamajn metodojn. Kio estas stranga, ĉar la logiko de laboro estas la sama. Mi kraĉis longe, kiam mi provis fari unu metodon kaj estis malpli da kodo. Ne estos ekzemploj ĉi tie.
GetOperationsByCursor
Mia plej ŝatata el la tri. Kvankam ne la plej preciza, sed la plej taŭga. Ni faras peton de la komenco de kreado de konto ĝis la maksimuma ebla dato (fermo de konto aŭ la nuna). Ni ricevas la respondon, prenu la kursoron kaj re-petas tiel longe kiel estas datumoj. Kaj la kodo estas pli konciza ol en la supraj ekzemploj.
const timer = nesinkrona tempo => { return new Promise (solvi => setTimeout (solvi, tempo)); } const getOperationsByCursor = async (sdk, accountId, from, to, cursor = ”) => { provu { const reqData = { accountId, from, to, limit: 1000, state: sdk.OperationState.OPERATION_STATE_EXECUTED, withoutCommissions: false, senKomercoj: falsa, senTranoktoj: falsa, kursoro, }; return await sdk.operations.getOperationsByCursor (reqData); } catch (e) { atendi timer(60000); return await getOperationsByCursor (sdk, accountId, from, to, kursoro = ”); } };
La malneto rulebla estas ĉi tie: https://github.com/pskucherov/tcsstat/tree/step3.3 https://github.com/pskucherov/tcsstat/compare/step3.3 Nun ni pretas aldoni ricevajn operaciojn al nia aplikaĵo. Se farite ĝuste, tiam vi devas ricevi kurtaĝajn raportojn por la tuta ekzisto de la konto. Kaj por la mankantaj datumoj, tiuj samaj T-3s, reŝargi de operacioj. Sed ĉi tio povas esti apartigita en apartan artikolon. El la ĉefaj nuancoj, kiujn vi renkontos, estas glui operaciojn kaj kurtaĝan raporton.
- Se hodiaŭ vi ricevis kurtaĝan raporton kaj transakciojn por la postulataj datoj, metu ĉion en la datumbazon, tiam ne estas problemoj.
- Vi havos problemojn morgaŭ kiam vi ricevos la sekvan parton de datumoj de la raporto kaj operacioj kaj decidos sinkronigi ilin kun la ekzistanta datumbazo.
- Multaj nuancoj pri misagordado aŭ ŝanĝado de identigilo post prilaborado
- Tiam por la OTC-merkato, la identigiloj tute ne kongruas.
- Same kiel la nuancoj de sinkronigaj instrumentoj, kiuj denove ne koincidas, pro la proprecoj de la API. Sed tio estas alia historio.
Ni aldonu ricevi informojn pri operacioj al nia aplikaĵo. La ĉefa demando estos kie la datumoj estos prilaboritaj kaj stokitaj.
- Se vi faras ĝin por vi mem, vi konsumos la samajn datumojn de malsamaj aparatoj. Tiam vi devas prilabori kaj stoki datumojn sur la servilo.
- Se vi havas multajn malsamajn datumojn konsumitaj de multaj malsamaj uzantoj, tiam vi devas decidi kio estas pli grava: la rapideco de la uzantoj aŭ la ŝparado de fero sur via flanko. Kiu povas pagi senfinan kvanton da aparataro, kalkulas ĉion sur sia servilo kaj faras ĝin superrapida por uzantoj, ŝparante la uzantrimedojn, kiel kuirilaron kaj trafikon, kio estas tre grava ĉe telefonoj.
Siavice, kalkuli en la retumilo principe ne estas la plej optimuma solvo. Tial, kio ne estas multekosta, ni konsideras ĝin sur nia servilo. La reston ni lasas al la kliento. Mi vere volas preni kaj kalkuli la komisionon sur la servilo. Sed jen venas la nuanco nomata “interagado”. Ni diru, ke vi havas milojn da operacioj kaj necesas kvin minutoj por ricevi ilin. Kion havos la uzanto ĉi-momente? Ŝpinisto? Ĉu progreso? Infa pri kiom estis alŝutita? Estas ideale uzi “aktivan atendon” kiam la uzanto en la procezo jam povis vidi ion. Jen la Rezulto:
- Paĝa ŝarĝo
- Ĉiuj fakturoj estas petitaj
- Post tio, ĉiuj transakcioj kun komisionoj por efektivigitaj transakcioj estas petitaj por ĉiuj kontoj. Ĉar datumoj estas ricevitaj, ĝi estas prezentita en la retumilo.
Por ne filtri la datumojn en la eventoj ĉiufoje, ni tiras nian propran eventon por ĉiu konto. Kiel tio:
socket.emit(‘sdk:getOperationsCommissionResult_’ + accountId, { items: data?.items, inProgress: Boolean(nextCursor), });
La malneto por lanĉi estas ĉi tie: https://github.com/pskucherov/tcsstat/tree/step3 https://github.com/pskucherov/tcsstat/compare/step2…step3 Plu. Estas bonege, ke vi legis ĉi tiun linion!
Kalkulo kaj eligo de interesaj informoj
Dependas de kiu bezonas kiajn informojn. Tial mi tuj rakontas al vi la ĉefajn nuancojn, kiujn vi renkontos.
Laborante kun prezoj
Ĉiuj, kiuj laboras kun financo, scias, ke montransakcioj devas esti faritaj nur per tutaj nombroj. Pro la malprecizeco de valoroj post la dekuma punkto kaj la akumula eraro kun granda nombro da operacioj. Tial ĉiuj prezoj estas prezentitaj en la sekva MoneyValue- formato
kampo | tajpu | Priskribo |
---|---|---|
valuto | ŝnuro | Ŝnuro ISO-valutkodo |
unuoj | int64 | Entjera parto de la sumo, povas esti negativa nombro |
nano | int32 | Frakcia parto de la kvanto, povas esti negativa nombro |
Ni procesas ilin aparte, tiam alportas ilin al la prezvaloro:
citaĵo.unuoj + citaĵo.nano / 1e9
La kosto de estontaj kontraktoj
La prezo de estontecoj estas prezentita en punktoj, kiam vi havas valutan estontecon, vi devas scii la kurzon. Kaj kompreneble la prezo en punktoj kaj la prezo paŝo. Kiam vi kalkulas la profiton de transakcioj, ĉi tio povas pafi, ĉar. se vi kalkulas la totalan kvanton multobligante la prezon per la kvanto. Ĉi tie vi devas esti singarda. Nuntempe, ni vidos kiel ĝi iras. Ĉi tio validas por valutaj estontecoj, en aliaj lokoj ĉio estas en ordo kun ĉi tio.
OTC-merkato
Ĉi tiu merkato havas multajn proprecojn, do ni studu operaciojn sur ĝi aparte. Kiam vi komencos sinkronigi operaciojn, montriĝos, ke vi devas alporti figi / ticker al la sama formo por ĝuste kongrui kun la instrumento. Kiam vi komencas sinkronigi ĉi tion kun la raporto pri kurtaĝo, montros, ke la tradeID de la sama transakcio havas literojn komence en la transakcioj kaj ili ne estas en la raporto pri kurtaĝo. Sekve, ili ne povas esti kompareblaj … ahem-ahem … kompare! Mi kongruis kun la komerca tempo, ticker kaj kongruo, ke unu tradeId estas enhavita en alia. Prave, mi ne scias. Kiu renkontas ĉi tion kaj kiu zorgas pri ĝi, venu al la afero aŭ komencu novan.
Matematikaj operacioj pri iloj
Estas neeble, sen rigardi, fari matematikajn operaciojn kun la tuta listo. Por ne aldoni varman al mola, ni ĉiam kontrolas la valuton kaj procesas nur se ni estas certaj, ke la valuto kongruas, kaj la punktoj estas konvertitaj al la dezirata valuto. Armitaj kun scio pri laborado kun bankaj nombroj, ni kalkulos la komisionon elspezitan por ĉiu el la kontoj. Tiel: https://github.com/pskucherov/tcsstat/tree/step4 https://github.com/pskucherov/tcsstat/compare/step3…step4
Mikroservo estas preta!
https://github.com/pskucherov/tcsstat Kiel hejmtasko, vi povas kontroli ĉu la servo funkcias kun malrapida konekto, kiam ligoj estas rompitaj, kiam la interreto estas malkonektita, kiam eraroj aŭ eksvalidiĝintaj limoj de la makleristo.
Konkludoj kaj planoj por la estonteco
- Lernis pri bazaj operacioj kaj laborado kun la Invest API
- Tempo pasigita ~ 10 horoj
- Malfacilnivelo ~ juniora+ / malalta meza
Se vi daŭre rafinis la mikroservon, vi povus fini kun io tia
https://opexbot.info
Jen mia evoluo, por tiuj, kiuj tro maldiligentas kompreni, kuri kaj kalkuli memstare. Mi planas aldoni analizojn tie laŭ peto de uzantoj. Se vi ŝatis la artikolon, tiam abonu mian telegraman kanalon .
Полезная статья. Не могу представить, сколько усилий автора потребовалось, чтобы все описать. Благодарю.