ABONAMENTE VIDEO REDACȚIA
RO
EN
NOU
Numărul 140
Numărul 139 Numărul 138 Numărul 137 Numărul 136 Numărul 135 Numărul 134 Numărul 133 Numărul 132 Numărul 131 Numărul 130 Numărul 129 Numărul 128 Numărul 127 Numărul 126 Numărul 125 Numărul 124 Numărul 123 Numărul 122 Numărul 121 Numărul 120 Numărul 119 Numărul 118 Numărul 117 Numărul 116 Numărul 115 Numărul 114 Numărul 113 Numărul 112 Numărul 111 Numărul 110 Numărul 109 Numărul 108 Numărul 107 Numărul 106 Numărul 105 Numărul 104 Numărul 103 Numărul 102 Numărul 101 Numărul 100 Numărul 99 Numărul 98 Numărul 97 Numărul 96 Numărul 95 Numărul 94 Numărul 93 Numărul 92 Numărul 91 Numărul 90 Numărul 89 Numărul 88 Numărul 87 Numărul 86 Numărul 85 Numărul 84 Numărul 83 Numărul 82 Numărul 81 Numărul 80 Numărul 79 Numărul 78 Numărul 77 Numărul 76 Numărul 75 Numărul 74 Numărul 73 Numărul 72 Numărul 71 Numărul 70 Numărul 69 Numărul 68 Numărul 67 Numărul 66 Numărul 65 Numărul 64 Numărul 63 Numărul 62 Numărul 61 Numărul 60 Numărul 59 Numărul 58 Numărul 57 Numărul 56 Numărul 55 Numărul 54 Numărul 53 Numărul 52 Numărul 51 Numărul 50 Numărul 49 Numărul 48 Numărul 47 Numărul 46 Numărul 45 Numărul 44 Numărul 43 Numărul 42 Numărul 41 Numărul 40 Numărul 39 Numărul 38 Numărul 37 Numărul 36 Numărul 35 Numărul 34 Numărul 33 Numărul 32 Numărul 31 Numărul 30 Numărul 29 Numărul 28 Numărul 27 Numărul 26 Numărul 25 Numărul 24 Numărul 23 Numărul 22 Numărul 21 Numărul 20 Numărul 19 Numărul 18 Numărul 17 Numărul 16 Numărul 15 Numărul 14 Numărul 13 Numărul 12 Numărul 11 Numărul 10 Numărul 9 Numărul 8 Numărul 7 Numărul 6 Numărul 5 Numărul 4 Numărul 3 Numărul 2 Numărul 1
×
▼ LISTĂ EDIȚII ▼
Numărul 73
Abonament PDF

Tranzacţionarea automată, criptomonedele şi programatorii

Ioan Moldovan
Software Engineer @ TORA



PROGRAMARE

De ani buni trăim revoluţie după revoluţie. Revoluţia din '89, revoluţiile Facebook, Big Data Revolution, Deep Learning Revolution, Blockchain Revolution etc. . Atât de multe, încât programatorul abia are timp să ţină pasul, schimbările de paradigmă succedându-se aproape mai rapid decât schimbările de prim-miniştri. Toate au ramificaţii şi în tranzacţionarea automată. Companiile ce activează în domeniul financiar sunt evident "early adopters", pentru că pentru acestea viteza şi informaţia înseamnă oportunităţi şi bani. Ca urmare a dezvoltării tehnologice, aceste companii sunt într-o cursă continuă, iar unele din motoare sunt dezvoltarea de software specializat şi cei care stau în spatele acestei dezvoltări. În acelaşi timp are loc şi o creştere a accesibilităţii acestui domeniu: accesul la platformele de trading devine mult mai uşor odată cu explozia criptomonedelor.

Putem spune că dezvoltatorii de software sunt într-o poziţie oarecum privilegiată, fiindu-le foarte uşor să devină participanţi pe aceste burse şi să intre în competiţia pentru resurse, având deja multe dintre cunoştinţele necesare. Această remarcă nu se doreşte a fi un sfat pentru investiţii, ci doar o observaţie a faptului că programatorii sunt bine poziţionaţi pentru a intra în această competiţie, iar provocările şi oportunităţile de a învăţa sunt multiple.

Este evident că bursele pe care se tranzacţionează criptomonede sunt foarte volatile şi speculative, că un bubble (care poate nu va fi singurul) a trecut deja, însă tocmai de aceea, atâta timp cât volumele nu devin derizorii, tranzacţionarea automată devine mult mai interesantă decât strategiile foarte optimiste de gen HODL. Cei care sunt dispuşi să îşi asume riscul de a pierde tot ce investesc în schimbul promisiunii unor câştiguri, o pot face pariind pe propriile abilităţi de a face predicţii asupra mişcărilor preţurilor sau exploatând modul de funcţionare al acestor exchange-uri. Iar aceste abilităţi sunt la îndemâna dezvoltatorilor de software.

Tematica tranzacţionării automate şi a predicţiei evoluţiei preţurilor este foarte complexă şi imposibil de condensat în câteva pagini. Acest articol se doreşte o scurtă prezentare a unor tehnici folosite în domeniu: vom descrie unele tipuri de algoritmi speculativi şi vom menţiona termeni care pot fi folosiţi ca punct de start pentru investigarea mai detaliată pe cont propriu a semnalelor folosite pentru predicţie. De asemenea, vom încerca să trecem în revistă componentele unui sistem de tranzacţionare automată, care ar putea fi folosite ca inspiraţie pentru cei care încep noi proiecte.

Tipuri de tranzacţionare automată

Există mai multe modalităţi de tranzacţionare, fiecare cu avantajele şi dezavantajele ei, implicând grade de risc diferite.

Una din modalităţile de tranzacţionare automată cu risc minim este construirea unui algoritm de arbitraj între exchange-uri. În forma lor cea mai simplă, aceşti algoritmi urmăresc simultan mai multe burse pentru o anumită pereche de monede (de exemplu, ADA şi ETH) şi realizează simultan operaţiunea de a cumpăra şi de a vinde. Astfel, urmărind preţurile de pe două exchange-uri oarecare (cum ar fi Binance şi Bittrex), în momentul în care discrepanţa este suficient de mare încât să existe oportunitatea unui profit, un algoritm poate cumpăra ADA cu ETH pe Binance, simultan cu vânzarea de ADA pentru ETH pe Bittrex, încasând diferenţa. Această diferenţă trebuie să fie suficient de mare pentru a putea acoperi costurile de tranzacţionare, costurile de alimentare a contului, precum şi riscul păstrării blocate a unor sume în aceste criptomonede (deoarece operaţiunea de a vinde nu poate fi realizată pe majoritatea perechilor tranzacţionate fără a le deţine în prealabil). Şi, pentru că viaţa nu poate fi simplă, trebuie să acopere şi riscul de a nu obţine preţul teoretic din momentul observaţiei (din cauza mişcărilor care pot avea loc înainte ca acţiunile algoritmului să ajungă pe market) sau de a avea erori de comunicare cu exchange-ul, ce pot lăsa algoritmul "descoperit", nereuşind să realizeze ambele operaţiuni simultan.

Un alt arbitraj posibil este cel în care așa-zisă intrare şi ieşire se realizează pe acelaşi exchange. Mai precis, deşi se cumpără şi se vinde simultan pe două exchange-uri (ca şi în scenariul de mai sus), această operaţiune este întotdeauna urmată de una complementară, de vânzare şi cumpărare în acelaşi timp. Presupunând că mişcarea perechii ADAETH pe cele două burse menţionate anterior nu este perfect sincronă, există momente în care acea diferenţă este mică şi momente când este mare. Pariul în acest caz este că mişcarea diferenţei va fi ciclică. Un algoritm foarte simplu este de exemplu cumpărarea şi vânzarea în momentul în care diferenţa este sub percentila 5 a distribuţiei de valori posibile şi de a vinde/cumpăra în momentul în care diferenţa este peste percentila 95. Şi în acest caz trebuie analizat dacă această diferenţă depăşeşte comisioanele de tranzacţionare şi riscurile aferente, însă nu mai este necesară rularea banilor între exchange-uri (acțiune ce vine cu costuri suplimentare).

Aceste tipuri de arbitraj sunt un exemplu de strategii simple care sunt market-neutral, în care profiturile şi pierderile nu sunt afectate de mişcarea globală a preţului (în raport cu moneda de bază, ETH în exemplul nostru), ci doar de evoluţia diferenţei preţurilor. Cum e de aşteptat, dat fiind că este destul de uşoară construirea unor astfel de algoritmi şi riscurile sunt relativ mici, piaţa este destul de aglomerată, iar cu cât sunt mai mulţi algoritmi care fac asta, cu atât oportunităţile de profit scad. Algoritmii speculativi de arbitraj au şi un rol pozitiv, acela de a egaliza preţurile între exchange-uri, precum şi de creştere a lichidităţii, uşurând întâlnirea dintre cerere şi ofertă chiar dacă se tranzacţionează în locuri diferite.

O altă categorie destul de mare de algoritmi care pot fi construiţi sunt cei care urmăresc diferenţele între perechi de monede (aşa-numitul pairs trading). În cazul acestor algoritmi se urmăresc diferenţele între două instrumente (ex. : ADAETH şi XRPETH) şi pariul este că relaţia istorică dintre evoluţia preţurilor celor două se va menţine şi în viitor. Ca şi în cazul celui de-al doilea mod de arbitraj, diferenţa dintre preţuri (sau dintre cummulative returns) este cea relevantă pentru luarea deciziei de a cumpăra şi vinde simultan două criptomonede în cantităţi diferite, astfel încât cele două perechi să fie hedged, adică pierderile de pe o monedă să fie compensate de câştigurile de pe cealaltă, dacă toata piaţa se mişcă într-o anumită direcţie. Există atât metode clasice, cum ar fi cointegrarea pentru a determina natura relaţiei dintre preţuri şi folosirea regresiei liniare sau a filtrelor Kalman pe date istorice pentru a determina factorul de hedging. Mai mult, se pot folosi şi algoritmi de Machine Learning care să detecteze outliers şi momente în care relaţia dintre două instrumente este la un extrem de la care va reveni, fără a rupe legătura existentă istoric.

Fig 1. Exemplificarea evoluţiei unei perechi de criptomonede la nivel de zile

Există şi alte modele mai complicate de trading, triangular arbitrage şi basket trading, mai ales pe exchange-uri precum Binance, unde găsim o varietate uriaşă de perechi (ajungând la 10 instrumente tranzacţionabile între BNB, LTC, BTC, ETH şi USDT ). E important de reţinut că e greu de găsit un algoritm care să funcţioneze, dar în acelaşi timp search space-ul e infinit şi lucruri care aparent nu au sens s-ar putea să se dovedească utile. "The map is not the territory", orice metrică ce reduce activitatea complexă de pe exchange-uri simplifică "nepermis" de mult, dar în acelaşi timp orice metrică poate fi o proiecţie purtătoare de informaţie şi s-ar putea ca ceva simplu să se dovedească profitabil în suficient de multe cazuri astfel încât să acopere pierderile atunci când decizia e greşită. De aceea, experimentarea prin calcularea unor lucruri care vă vin în minte din alte domenii sau a unor intuiţii simple s-ar putea dovedi la fel de utilă ca şi folosirea unor tehnici consacrate, mai ales în cazul fluctuaţiilor relaţiilor dintre criptomonede, care sunt toate puternic corelate.

Un alt tip de algoritmi sunt cei numiţi de quoting (sau fishing). Înainte de a vedea ce fac aceşti algoritmi trebuie menţionat că există două modalităţi de tranzacţionare:

Primul tip de actor se numeşte maker şi acţiunile sale se numesc limit orders, iar al doilea tip de actor se numeşte taker (sau aggressor) şi acţiunile sale se numesc market orders. În cazul în care cineva tranzacţionează o cantitate foarte mare ca şi taker (fie intenţionat, fie din greşeală), preţul se poate schimba semnificativ, iar această mişcare este aproape întotdeauna urmată de un recul, în care preţul îşi revine foarte rapid. O strategie simplă este de a pune orders ca şi maker la o anumită distanţă de preţul curent de tranzacţionare şi a aştepta astfel de evenimente speciale, urmând ca algoritmul să profite de diferenţa dintre mişcarea bruscă a preţului şi recul. Riscul în acest caz este ca mişcarea bruscă să fie continuată de o evoluţie a preţului în aceeaşi direcţie, scopul fiind de a găsi acea combinaţie optimă între distanţa faţă de preţul curent la care se aşteaptă şi momentul în care se face tranzacţia inversă, astfel încât cazurile defavorabile să fie compensate de cazurile profitabile.

Aproape toate exchange-urile din spaţiul crypto oferă comisioane diferite pentru cei care oferă lichiditate (makers) şi cei care iau lichiditate (takers). Ca urmare, poate deveni profitabilă construirea unui alt tip de algoritmi, cei de market making, în care intenţia este de a cumpăra şi de a vinde cvasi-simultan ca maker (sau într-un orizont de timp cât mai scurt, pentru a reduce riscul generat de posibilele mişcări ale preţului). Acest tip de algoritmi pot fi priviţi ca fiind complementari celor de fishing, oferă lichiditate dar nu aşteaptă evenimente speciale ci doresc să exploateze lipsa evenimentelor speciale. Şi aici posibilităţile de implementare sunt variate, ideea de bază este de a profita de acele momente în care preţul este relativ stabil şi se poate realiza cumpărarea şi vânzarea succesivă la o diferenţă mai mare decât comisioanele. Se poate ajunge la versiuni mai complicate de market making în care creşte distanţa dintre momentul cumpărării şi cel al vânzării şi profitul potenţial este mai mare, problema fiind reformulată în detectarea absenţei unui trend şi predicţia volatilităţii preţului într-o fereastră de timp viitoare. Riscul este acelaşi ca şi în cazul anterior, dacă mişcarea preţului continuă într-o direcţie nefavorabilă, algoritmul va ieşi în pierdere.

O ultimă categorie de algoritmi pe care o menţionăm (şi cea mai complexă de altfel) este cea a strategiilor direcţionale, în care se încearcă predicţia mişcării preţului. O parte a acestor strategiile speculative, în care distanţa dintre a cumpăra şi a vinde este mică, este frecvent numită scalping în jargonul traderilor de pe piaţa valutară. Termenul este folosit cel mai des în contextul folosirii indicatorilor tehnici pentru luarea deciziilor. Combinarea unor astfel de indicatori tehnici cu metrici de analiză a time series poate fi, pe lângă o experienţă de învăţare şi începutul construirii unui algoritm profitabil.

În tranzacţionarea direcţională există două pariuri posibile:

În aceste două categorii pot intra şi algoritmii care încearcă detectarea manipulării preţului criptomonedelor (pump and dump), manipulare foarte comună pe această piaţă nereglementată (etapa de pump fiind asimilată momentumului, iar etapa de dump putând fi privită ca mean-reversion).

Rolul algoritmului este de a cumpăra (dacă avem fie predicţie de momentum şi o serie de preţuri crescătoare, fie predicţie de mean-reversion şi o serie descrescătoare) sau vinde (în cazurile simetrice). Algoritmul va încerca să profite de diferenţa de preţ între două momente de timp, iar riscul la care ne expunem este ca predicţia să fie greşită, ca timpul de aşteptare să fie prea lung sau profitul/pierderile ţintite să fie greu de obţinut. Problema se transformă în a găsi un semnal şi o parametrizare care să ne dea un raport bun între cazurile câştigătoare şi cele cu pierderi, iar căutarea se face încercând optimizarea pe date istorice. Fiindcă totalul profitului potenţial poate fi înşelător (puţine evenimente speciale şi nereproductibile putând să fie sursa câştigurilor), se urmăresc diverşi indicatori de performanţă care încearcă să condenseze raportul dintre câştiguri şi risc într-un singur număr. Varietatea este foarte mare, amintim ca relevante raporturile Sharpe, Sortino, Calmar, ori - mai informative - Tail Ratio sau Common Sense Ratio.

Semnale folosite în tranzacţionarea automată

Un exemplu foarte cunoscut de indicator tehnic este Relative Strength Index (Fig. 2), care oferă o modalitate de decizie simplă: dacă RSI este peste un prag (valori comun folosite fiind 70 sau 80), atunci este un indicator al faptului că este foarte probabil să urmeze o scădere a preţului. Dacă este sub un prag (cum ar fi 20), atunci este un indicator al faptului că urmează o creştere. Problemele care intervin sunt alegerea intervalului pe care se calculează şi a orizontului de aşteptare pentru ca preţul să urmeze traiectoria prezisă.

Fig 2. Exemplu de semnal pentru a vinde al indicatorului RSI (chart generat folosind cryptowat.ch)

Schimbarea intervalului pe care se calculează poate duce la obţinerea de semnale contradictorii. În mod evident, reducerea intenţiilor tuturor participanţilor pe bursă la un singur număr este înşelătoare, însă există informaţie exploatabilă în această metrică, fie şi pentru simplul fapt că este folosită de foarte mulţi oameni, devenind astfel un self-fulfilled prophecy datorită credinţei împărtăşite. Combinarea mai multor astfel de indicatori tehnici, (dintre care mai amintim On-Balance Volume, Moving-Average Convergence/Divergence şi Bollinger Bands) cu tehnici de modelare de time series şi algoritmi de Machine Learning deschide o multitudine de posibilităţi.

Să detaliem un exemplu de algoritm direcţional: acţiunile de bază sunt de a cumpăra sau a vinde pe baza unui stimul (de exemplu indicatorul RSI) şi de a "lichida" (a face acţiunea inversă) pe baza altui stimul mai simplu, ca într-una din următoarele situaţii: preţul a mers în direcţia dorită cu X% (o regulă numită stop profit) sau preţul a mers în direcţia inversă cu Y% (stop loss). Există diverse feluri în care acest algoritm poate fi extins, cum ar fi prin adăugarea unei reguli de draw down: dacă preţul s-a întors cu Z% faţă de maximul atins în direcţia dorită sau a unui time to live: dacă au trecut mai mult de N secunde de la tranzacţia iniţială, aspect care poate fi relevant, deoarece există un trade-off între pierderile ce pot fi încasate imediat şi oportunităţile pierdute. Un algoritm care implementează aceste condiţii este deja suficient pentru a deveni profitabil. Cu cât complexitatea creşte, cu atât performanţa cuantificată pe date istorice devine un predictor mai slab pentru performanţa viitoare, de aceea uneori un model mai simplu este preferabil unuia complicat dacă aduce câştiguri comparabile.

Întrebarea cea mai importantă în construirea algoritmului rămâne "când?": care e momentul potrivit pentru iniţierea unei tranzacţii şi care e momentul optim al operaţiunii inverse. Nu există o reţetă şi aici intră în joc creativitatea fiecăruia şi răspunsurile (parţiale) pe care le pot da statisticile pe datele istorice şi, de ce nu, algoritmii de Machine Learning. Profitul sau pierderile calculate în backtesting (referitor la suma investită şi la suma tranzacţionată) sau analiza cazurilor individuale când rezultatele sunt foarte bune ori foarte proaste ajută şi ele în alegerea metricilor şi parametrilor care să ducă la un algoritm profitabil.

Ce semnale se folosesc?

Utilizatorii retail care tranzacţionează criptomonede acţionează în mare parte pe baza unor indicatori tehnici precum cei amintiți anterior (MACD, RSI, AROON etc.), dar şi desenând linii de Support-Resistance sau Fibonacci Retracements (care, asemeni horoscopului, sunt evidente "celor care au ochi de văzut"). Toate se pot dovedi utile dacă sunt împărtăşite (un bull flag devine un semn de continuare a direcţiei dacă suficient de multă lume crede în el), dar sunt doar un mod de a interpreta activitatea de pe market. Avantajul programatorilor în competiţia cu FX traders sau alte categorii de persoane prezente pe bursele de tranzacţionare a criptomonedelor poate veni nu doar din posibilitatea de a construi algoritmi automaţi pe cont propriu, ci şi din accesibilitatea Machine Learningului sau din cunoaşterea şi deschiderea la folosirea altor metode de prelucrare a datelor pe lângă cele încetăţenite în domeniu. Cel mai probabil analiza Fourier învăţată în facultate nu va fi de folos din cauza naturii semnalului, însă orice idei pot fi încercate.

Pe lângă indicatorii tehnici există multe alte semnale care pot fi folosite, unele legate de activitatea trecută, cum ar fi mişcarea preţului pe anumite ferestre de timp (calculată drept compound returns), altele legate de intenţiile instantanee (forma sau dinamica orderbookului). E foarte probabil ca acelaşi semnal (de exemplu, manipularea preţului sau existenţa cuiva care cumpără cantităţi mari la intervale fixe de timp, ducând preţul în sus) să fie surprins de metrici diferite, de aceea orice poate deveni relevant în luarea deciziei de trading. Exemplificăm metrici posibile menţionând moving averages (existând o ȋntreagă suită, weighted, exponential etc.), indicatori de trend obţinuţi din regresii liniare sau SVM (care pot fi făcute şi cu algoritmi online, ce nu necesită revizitarea ȋntregii istorii ȋn fiecare moment când calculeaza), Dynamic Linear Models etc. Modelarea de time series folosind Vector AutoRegressions s-ar putea să fie interesantă pentru unii. Sau dinamica preţului, mişcarea acestuia fiind ȋn teorie un random walk şi existând metrici precum Variance Ratio (care ne pot spune cât de departe suntem de această ipoteză), Hurst Exponent (care ne poate spune dacă preţul a fost mean-reverting, brownian motion sau momentum), Detrended Fluctuation Analysis (care ne oferă informaţii despre memoria seriei), Maximal Lyapunov Exponent (care ne poate da o măsură, uneori ȋnşelătoare, a predictibilităţii seriei), sau o ȋntreagă suită de teste statistice pentru verificarea prezenţei unui salt brusc (cum ar fi Aït-Sahalia/Jacod). Condensarea seriei într-un singur număr pierde întotdeauna informaţie, dar urmărirea mai multor serii simultan poate fi utilă, de exemplu un indicator tehnic de trend cum ar fi ADX ar putea fi potenţat de confirmarea acestuia via Hurst Exponent.

Toţi indicatorii şi toate metricile care pot fi calculate sunt reactive, problema rămâne găsirea unei combinaţii cu putere predictivă şi acest lucru s-ar putea să nu fie deloc simplu. Dar validarea relevanţei acestor indicatori şi metrici, precum şi a deciziilor de cumpărare sau vânzare se poate face simulând activitatea algoritmului pe date istorice (așa-numitul backtesting), şi care, deşi are limitări şi porneşte de la asumpţia că trecutul e similar viitorului, reprezintă o unealtă foarte puternică şi importantă în procesul de tranzacţionare.

O altă decizie importantă este alegerea momentului în care, dacă lucrurile merg prost, se decide ieşirea pe pierdere. Aceasta poate fi şi ea luată pe bază de semnale complicate, nu doar urmărind profitul sau pierderile, însă pentru început e suficientă folosirea unor praguri de profit sau pierdere. Într-o lume ideală decizia raţională este păstrarea unei simetrii între stop loss şi stop profit, dar oamenii au tendinţa de a evita pierderile (loss aversion), iar acest bias cognitiv al actorilor de pe market e foarte probabil să duca la folosirea de valori diferite. Există şi alte decizii posibile pentru tratarea pierderilor: Cost Averaging este o strategie prin care, deşi suntem în pierdere, creştem expunerea şi facem încă o tranzacţie în aceeaşi direcţie. Pariul în acest caz este de mean-reversion, considerăm că putem recupera suma pierdută deoarece preţul se va întoarce aproape de valoarea la care noi am luat decizia greşită. Sau, în cazul optimismului extrem, se poate decide suspendarea tranzacţionării şi aşteptarea nedefinită a unui preţ favorabil.

Arhitectura unui sistem de tranzacţionare automată

În cazul fondurilor de investiţii, structura sistemului este evident mai complicată decât ceea ce este necesar pentru un proiect individual, dar componentele folosite în industrie pot fi folosite ca inspiraţie. Evident că arhitectura poate varia în funcţie de companie, strategie de trading, de burse şi de instrumente urmărite. În mod normal într-un astfel de sistem avem:

Aceste componente pot coexista în același proces pentru viteză sau pot fi distribuite. Putem clasifica funcționarea sistemului şi există o separare foarte clară la nivel de deploy între două moduri: "live", când toate acțiunile sunt reale și tranzacționăm bani reali, și "backtest", când tranzacționăm bani virtuali și facem replay pe date istorice.

Această modularizare este mai mult decât este necesar pentru un proiect individual. Primul pas poate fi ceva mult mai simplu: câteva linii de cod care folosesc o librărie pre-existentă pentru conexiunea live la exchange, stabilirea unui trend general pe ultima săptămână și o acțiune de cumpărare sau vânzare de fiecare dată când există o mișcare în sens contrar, urmată de o lichidare în câștig ori în pierdere la un prag oarecare. Ori, de ce nu chiar la întâmplare. Random ajută!

NUMĂRUL 138 - Maps & AI

Sponsori

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • Connatix
  • BoatyardX
  • .msg systems
  • Yardi
  • Colors in projects

INTERVIURI VIDEO