Budapesti Műszaki és Gazdaságtudományi Egyetem Villamosmérnöki és Informatikai Kar Irányítástechnika és Informatika Tanszék
Sali Dániel Attila
TŐZSDEI STRATÉGIÁK TESZTELÉSÉHEZ VALÓ GRIDES KERETRENDSZER FEJLESZTÉSE
KONZULENS
Kápolnai Richárd Péter BUDAPEST, 2010
HALLGATÓI NYILATKOZAT Alulírott Sali Dániel Attila, szigorló hallgató kijelentem, hogy ezt a diplomatervet meg nem engedett segítség nélkül, saját magam készítettem, csak a megadott forrásokat (szakirodalom, eszközök, stb.) használtam fel. Minden olyan részt, melyet szó szerint, vagy azonos értelemben, de átfogalmazva más forrásból átvettem, egyértelműen, a forrás megadásával megjelöltem. Hozzájárulok, hogy a jelen munkám alapadatait (szerző(k), cím, angol és magyar nyelvű tartalmi kivonat, készítés éve, konzulens(ek) neve) a BME VIK nyilvánosan hozzáférhető elektronikus formában, a munka teljes szövegét pedig az egyetem belső hálózatán keresztül (vagy autentikált felhasználók számára) közzétegye. Kijelentem, hogy a benyújtott munka és annak elektronikus verziója megegyezik. A teljes szöveg közzététele dékáni engedéllyel titkosított diplomatervekre nem vonatkozik. Kelt: Budapest, 2010. december 19.
..................................................................... Sali Dániel Attila
Tartalomjegyzék Tartalomjegyzék ............................................................................................................. 3 Összefoglaló ..................................................................................................................... 5 Abstract............................................................................................................................ 6 1 Bevezetés ....................................................................................................................... 7 2 Idősorelemzés és backtesting ...................................................................................... 9 2.1 A technikai elemzés ................................................................................................ 9 2.2 Kereskedési stratégiák .......................................................................................... 10 2.3 A Backtesting ........................................................................................................ 12 2.3.1 A backtesting célja ......................................................................................... 12 2.3.2 A backtesting korlátai .................................................................................... 13 2.4 Backtesting rendszerek ......................................................................................... 14 2.5 Paraméterek vizsgálata.......................................................................................... 15 3 Az elkészített rendszer ............................................................................................... 17 3.1 Célkitűzések .......................................................................................................... 17 3.2 Választott megoldások .......................................................................................... 18 3.2.1 A pénzügyi modell ......................................................................................... 18 3.3 A szimuláció motorja ............................................................................................ 20 3.3.1 Felhasználótól elvárt komponensek ............................................................... 25 4 Alkalmazásfejlesztés grid rendszerekre................................................................... 26 4.1 A grid, mint szolgáltatás ....................................................................................... 26 4.2 Alkalmazások „gridesítése” .................................................................................. 28 4.2.1 Az EGEE Grid biztonsága ............................................................................. 28 4.3 A Saleve keretrendszer ......................................................................................... 32 4.3.1 Fejlesztés a Saleve keretrendszer használatával ............................................ 34 4.3.2 A Saleve keretrendszer továbbfejlesztése ...................................................... 35 5 . Rendszerintegráció .................................................................................................. 39 5.1 A backtesting keretrendszer elemei ...................................................................... 41 5.1.1 A felhasználói kezelőfelület........................................................................... 42
5.1.2 A Saleve kliens .............................................................................................. 44 5.1.3 Saleve feladatok (jobok) létrehozása ............................................................. 45 5.1.4 A grid jobok futása, eredmények begyűjtése ................................................. 46 6 Az implementált rendszer tesztelése, értékelése ...................................................... 48 6.1 Továbbfejlesztési lehetőségek .............................................................................. 50 7 Köszönetnyilvánítás ................................................................................................... 52 Irodalomjegyzék............................................................................................................ 53 Függelék ......................................................................................................................... 57
Összefoglaló A diplomaterv célja egy olyan tőzsdei kereskedési stratégiaelemző programozói kertrendszer létrehozása, mely lehetővé teszi a fejlesztő számára új stratégiák létrehozását
és
paraméterezésének
szimulációját,
és
segíti
meghatározásában.
a
Az
fejlesztőt
elkészített
a és
stratégia
optimális
bemutatott
rendszer
különlegessége, hogy a kereskedési stratégia szimulációját nem a felhasználó számítógépén hajtja végre, hanem ehhez egy grid infrastruktúrát használ. A diplomaterv az idősorelemzés pénzügyi hátterének bemutatásával kezdődik, majd leírásra kerül a szimulációt végző szoftverkomponens. Ismertetve lesz egy Saleve nevű keretrendszer, mely nagyban megkönnyíti a grid infrastruktúra használatát. Ez a Saleve keretrendszer továbbfejlesztésre került a diplomamunkában. Ezt követően prezentálva lesz a teljes rendszer, bemutatva azt, hogyan lett a szimulációs motor integrálva a kliens-szerver alapú, grides háttérrel rendelkező keretbe. Végül egy felhasználói leírás következik, mellyel a rendszer működése ellenőrizhető, illetve javaslatok szerepelnek a rendszer továbbfejlesztésének irányait illetően.
5
Abstract The objective of the thesis is to create a stock trading simulation framework, which allows a developer to create and simulate new trading strategies, and to help the trader to determine the optimal parameters of a trading strategy. The specialty of the developed system is the possibility to use a grid infrastructure as a back-end on which the calculations of the trading simulations are executed. The thesis starts with the introduction of the financial theory behind the backtesting procedure, and continues with the presentation of the simulation engine. A framework named Saleve will be presented, which greatly eased the burdens associated with the use of a grid back-end infrastructure. This framework is upgraded in the thesis. Consequently, the entire backtesting framework is presented, emphasizing on the integration of the simulation engine into the client-server architecture of the gridsupported framework. Finally, a user’s guide is given in the form of a testing manuscript, and suggestions are given regarding to possible enhancements and developments of the backtesting framework.
6
1 Bevezetés A tőzsdei kereskedés során kereskedési stratégiájának kialakításához egy befektető két alapvető elemzési módszert alkalmazhat: A fundamentális elemzés a részvények piaci és belső, tényleges értéke közötti eltérést keresi, feltételezi, hogy van olyan a részvénnyel kapcsolatos információ, melyet a részvény ára nem tükröz, hogy ezt kihasználva érjen el profitot a kereskedés során. A technikai elemzés ezzel szemben feltételezi, hogy a piac nem tökéletesen hatékony, és bizonyos minták ismétlődnek, tehát olykor a részvény jövőbeli árfolyamát a múltbéli árfolyamának elemzésével lehet megbecsülni. Dolgozatomban egy olyan, saját fejlesztésű, technikai elemzéshez használható eszközt mutatok be, mely különböző, a kereskedő által megadott kereskedési stratégiát képes historikus tőzsdei árfolyam-idősorokon szimulálni. A szimuláció lehetőséget teremt az eltérő elveken működő, eltérő komplexitású, különböző paraméterekkel futtatott stratégiák összehasonlítására, a legeredményesebb stratégia kiválasztására. A vizsgált stratégiák komplexitása, és az egyes stratégiák elemzésénél alkalmazott nagyméretű paramétertér nagy számítási kapacitást igényel a szimuláció során. Ezért a diplomamunkám során egy olyan rendszert fejlesztettem, mely a számításokat egy elosztott, nagy teljesítményű számítási szolgáltatás, egy Grid rendszer felhasználásával végzi. Azonban egy Grid rendszer használata olyan speciális szakismereteket igényel, melyek nem várhatóak el egy pénzügyi matematikai beállítottsággal rendelkező, algoritmikusan
gondolkodni
tudó,
alapszinten
programozni
képes
elemző
felhasználótól. Ezért a diplomamunkaként elkészített rendszer célja, hogy egy keretet biztosítson a felhasználónak, hogy elvégezhesse szimulációit, anélkül, hogy a szimulációt ténylegesen futtató rendszer programozását és használatát meg kellene ismernie. A következőkben a diplomatervet pénzügyi oldalról közelítem, részletesebben bemutatom az idősorelemzés módszertanát, a jelentősebb portfólió kereskedési stratégiákat. Ez után a keretrendszer informatikai alapjait mutatom be, a Grid szolgáltatás
felhasználását
alkalmazásfejlesztői
7
nézőpontból.
A
pénzügyi
és
informatikai megközelítéseket egységbe foglalom, bemutatom, hogyan épül fel egy egész rendszer a diplomatervemben a két megközelítésből. Végezetül a rendszer kritikai elemzése következik, elemzem, hogy mennyire teljesíti a legfontosabb támasztott követelményt, hogy egy informatikai szaktudás nélküli felhasználó is képes legyen a rendszer segítségével nagyteljesítményű számító rendszereket felhasználva tőzsdei kereskedési stratégiák szimulációjára. Értékelem, hogy a diplomatervem milyen mértékben teljesíti a kiírásban felsorolt feladatokat és javaslatokat teszek a rendszer továbbfejlesztésére.
8
2 Idősorelemzés és backtesting 2.1 A technikai elemzés A tőzsdei spekulációk során a technikai elemzést alkalmazó befektetők elfogadják azt a tézist, hogy nem képesek tökéletesen meghatározni egy értékpapír belső értékét, azaz az értékpapírt kibocsájtó vállalat értékét. Ehhez a spekulálónak meg kell ismernie a vállalat eredményeit, gazdasági folyamatait, az iparágban levő hasonló vállalatokat, a vállalat környezetét. Mindezen információk beszerzése, naprakészen tartása komoly erőfeszítéseket, sok időt és jó információforrásokat igényel. A technikai elemzés során ezzel szemben az elemzést végző egy alapvető hipotézist fogad el: a piac nem tökéletesen hatékony, és bizonyos minták nagy eséllyel ismétlődnek. A technikai elemzés során tehát az értékpapírok historikus idősoraiban próbálunk meg ismert és felismerhető „helyzeteket” keresni, mivel előzetes ismereteink vannak a várható reakcióról, s ezt a feltételezést kihasználva tudunk nyereségesen kereskedni. Egy ilyen technikai elemzést végez el a Portfolio.hu (a forrásban meg nem nevezett) szerzője [1]: „Az 1200-1170-es szintek által jelzett sávból fölfelé tört ki az amerikai index, és a sáv által jelzett emelkedést már többé kevésbe abszolválta is az S&P500. Az ellenállás az 1230 pontos lokális csúcs, amely áttörése megerősítené az emelkedő trendet.”
9
2.2.1. ábra A Portfolio.hu elemzésénél használt idősor
Ha értelmezzük az idézetet, akkor megfigyelhető, hogy az elemző felismert egy ismert mintát („az ellenállás az 1230 pontos lokális csúcs”), melyből ismeretei és múltbéli tapasztalatai alapján következtetést von le a várható jövőbeli árfolyamértékre. (Mely szerint, ha áttöri az index az 1230 pontos határt, akkor további emelkedés várható.)
2.2 Kereskedési stratégiák Ezek alapján egy technikai elemzést alkalmazó befektető tőzsdei stratégiáját úgy adhatjuk meg, hogy figyeli a jelenlegi árfolyamot felismerhető minták és helyzetek után kutatva, majd amennyiben sikeresen felismer egy mintát, végrehajtja a minta által meghatározott kereskedési cselekményt (vesz vagy elad értékpapírt). Az eljárást ismerve bizonyára felmerül az olvasóban a kérdés, hogy mégis milyen mintákat keressen a befektető, és milyen cselekményeket végezzen a minták felismerése esetén. Egy kereskedési stratégia ezeket a mintákat és cselekményeket határozza meg. Technikai elemzésen alapuló kereskedési stratégiából megszámlálhatatlan sokat alkottak az idők során, azonban ezek jellemzően könnyen meghatározható mintákat figyelnek. Eltérés elsősorban a mintavétel időtartalmában és hosszában van, illetve a stratégiatípusokon belül a konkrét paraméterezésben található. Néhány ismertebb stratégia [2]:
10
Mozgóátlag-átlépések [3]: Az elemző meghatároz egy hosszú és egy rövidtávú mozgóátlag-ablak méretet (legyen N és n), azt figyeli, hogy hogyan viszonyul az értékpapír rövidtávú árfolyamátlaga az elmúlt N nap nyitó/záró árfolyamainak átlagához. Amennyiben a rövidtávú árfolyam-átlag konzisztensen a hosszú távú átlag felett helyezkedik el, úgy egy növekvő trend állapítható meg, azaz érdemes vásárolni az értékpapírból, vagy kivárni az eladással. Ennek a kereskedési stratégiának a jellemző paraméterei a két átlag-ablak nagysága, napban megadva.
Kitörés árfolyamsávból [2]: Amennyiben az elemző azt érzékeli, hogy az árfolyam kis ingadozással egy adott érték körüli sávban tartózkodik, úgy meghatároz egy alsó és egy felső korlátot. Ha meghaladja a felső értéket az
árfolyam,
azt
vételi
jelként
kezeli:
2.2. ábra Kitörés árfolyamsávból. Forrás: Tradetrek.com
Ennél a stratégiának a jellemző paraméterei a sávot meghatározó árfolyam-ingadozás nagysága és a sáv minimális hossza.
Rés kereskedés („Gap trading”) [4]: Azokat a helyzeteket figyeli, amikor a napi nyitóárfolyam magasabb, mint az előző napi záró árfolyam. Egy ilyen „rést” felismerve követi a nyitás utáni első óra árfolyammozgását, amennyiben később meghaladja ezt a sávot az árfolyam, akkor vesz az értékpapírból, ha a sáv az árfolyam alá süllyed, akkor eladja papírjait. 11
Ennél a stratégiának a jellemző paramétere a nyitás utáni kivárás hossza (általában 1 óra), illetve a sáv szélessége. Bár ezek a technikai kereskedési stratégiák egyszerű, beazonosításhoz kis számítást
igénylő
mintákat
használnak,
mégis
eredményesebbek
lehetnek
a
véletlenszerű kereskedésnél. Egy ilyen elemzést ír le a Journal of Finance 1992 decembberi
száma,
ahol
mozgóátlag-átlépéses
és
a
sávkitöréses
stratégia
eredményességét mutatták ki [5].
2.3 A Backtesting Mivel, mint ahogy azt az előző pontban bemutattam, egy spekuláns számára többféle stratégia áll rendelkezésre, széles tartományban megadható paraméterekkel, ezért szükség van egy módszerre, mellyel ki lehet választani a befektetési környezethez legjobban illő stratégiát. Kiindulva a technikai elemzés azon feltételezéseiből, hogy az egyes értékpapírok árfolyamaiban ismétlődő minták szerepelnek, célszerű lenne a stratégiákat ismert, múltbéli árfolyamokon vizsgálni. A stratégiákat azonos historikus idősor adatokon futtatva, szimulációt végezve lehetőséget teremt arra, hogy a stratégiák eredményességét összevessük. Ezt a szimulációt nevezi az angol szakirodalom backtesting-nek. Az a hipotézisünk, hogy az a stratégia, amelyik jól teljesít korábbi adatokon, a minták ismétlődése miatt a jövőben is jól fog teljesíteni.
2.3.1 A backtesting célja A „jól teljesít” jelző a pénzügyi világban nem csak az abszolút értelemben magas hozamot elérő stratégiát jellemzi, hanem az elérhető hozamot jellemzi a vállalt kockázathoz hasonlítva, tehát egy stratégia akkor teljesít jól, ha azonos kockázati szinten a szinthez tartozó átlagnál magasabb hozamot biztosít, vagy egy adott várható hozamszintet alacsonyabb kockázati szint mellett képes elérni. A kockázat a pénzügyi világban a hozamértékek szórásának nagyságát jelenti, azaz a kis kockázatú értékpapírok árfolyama kevésbé ingadozik, mint a nagy kockázatú értékpapírok árfolyama. A stratégia szimuláció tehát nem csak arra alkalmas, hogy meghatározza az adott stratégiával a múltban milyen hozamok lettek volna elérhetőek, hanem a stratégia alkalmazásának kockázata is mérhető. A backtesting szimulációt nem csak tőzsdei stratégiák értékeléséhez alkalmazzák, hanem a pénzügyi szektorban gyakran használt kockáztatott érték mutató 12
(Value at Risk, VaR) számításával és szimulálásával a pénzügyi intézmények értékelhetik a kockázatkezelésüket. Az intézmények által használt VaR modellek backtest-tel történő értékelését írja le a Federal Reserve (az Egyesült Államok nemzeti bankjának) egyik tanulmánya [6].
2.3.2 A backtesting korlátai Mint minden szimulációnál, a historikus idősorokat alkalmazó szimulációknál is figyelni kell arra, hogy a szimuláció csak addig szolgáltat reális értékeket, amíg a szimulált tevékenység nem befolyásolja számottevően a szimuláció környezetét. Ez a kereskedési stratégiák elemzése esetén azt jelenti, hogy addig lesz értékelhető a szimuláció eredménye, amíg a stratégia követése során végrehajtott kereskedések nem befolyásolnák az árfolyamot olyannyira, hogy a kereskedés után a historikus árfolyam már nem tükrözné hűen a kialakult piaci árfolyamot. Ez akkor következhet be, ha a szimulált stratégia olyan volumenű kereskedést végez, melynek hatására a valóságban a piac az árfolyam elmozdításával reagálna. Az ilyen stratégiák bonyolultabban szimulálhatóak, ezektől eltekintünk, hiszen a kisbefektető szemszögéből egy nagy forgalmú piacon az árfolyamra való hatás elhanyagolható. Historikus idősorokon végzett szimuláció esetében egy másik jelenségre is fontos ügyelni: Ha egy olyan adathalmazt használunk, mely több évre visszamenőleg tartalmazza egy adott cég árfolyamait, az implicit módon azt a többletinformációt tartalmazza, hogy az adott cég fennmaradt az évek során. Tehát, ha mondjuk az S&P 500 [7] indexben szereplő részvények árfolyamait használjuk fel, akkor a stratégiánk eredményesebbnek mutatkozhat, mint a valóságban lenne, ahol nem csak az 500 legjelentősebb, legerősebb amerikai vállalat részvényeivel lehet kereskedni. Ezt a torzító hatást nevezi az angol szakirodalom survivorship biasnek [8] [9]. Ügyelni kell még arra is, hogy amennyiben részvényárfolyamokat használunk idősorelemzéshez, az árfolyamértékek osztalék kifizetés (és más változások, pl. feldarabolás) után korrigálva legyenek, különben az osztalék kifizetés napján egy hirtelen, meg nem magyarázható árfolyamesés lenne az idősorban. A legtöbb, historikus tőzsdei árfolyamokat közlő weboldal már korrigált értékeket biztosít a felhasználók számára. A korrekció pontos és szabványos számítását a Chicago Booth egyetem Center for Research in Security Prices kutatóintézete dolgozta ki [10].
13
2.4 Backtesting rendszerek Bár az egyszerű kereskedési stratégia-szimulációk nem alkalmaznak bonyolult számításokat, mégis a backtesting a számítógépek megjelenésével vált széleskörűen alkalmazott eszközzé. Az első szimulációt végezni képes elemzőrendszert, a ProfitTaker-t Louis B. Mendelsohn fejlesztette ki személyi számítógépekhez 1983-ban [11]. Napjainkban több, egyéni befektetők számára fejlesztett, kereskedelmi forgalomban levő backtesting-re képes rendszer van, ezek közül mutatnám be a jelentősebbeket:
Tradecision [12]: Lehetőséget ad stratégiák szimulációjára egyes részvények
árfolyamát
használva,
a
stratégiák
szabadon
paraméterezhetőek és új stratégia hozható létre egy saját programozási nyelv használatával. Nem képes portfóliók kereskedelmét szimulálni. Ára: $1195 –től.
MultiCharts [13]: Az általam ismert legmodernebb backtesting-re képes szoftver, képes portfóliókkal is kereskedni. Egyszerűbb stratégiák programozhatóak, az eszköz saját, nem teljes értékű programozási nyelve segítségével.
Lehetőséget
ad
automatizált
kereskedelemre
brókercégekhez csatlakozó szoftverkomponensek segítségével. Ára: $1497-től.
AmiBroker [14]: Szintén egy nagy tudású portfólió elemző szoftver, képes portfóliókat kezelni a kereskedési szimulációk során. Lehetőséget ad saját stratégiák fejlesztésére egy C-hez hasonló programozási nyelv használatával. Ára: $279
Ashkon StockPredictor: Egy alapszintű elemző szoftver, nem képes portfólió elemzésre, csak egyedi részvények árfolyamaival képes szimulációkat végezni. Beépített stratégiákat tartalmaz, melyeket paraméterezni enged.
A historikus idősorokon végzett szimuláció értéke nem csak a szimulátoron és az alkalmazott stratégián múlik, hanem kulcsfontosságú az idősor információtartalma, melyet a szimuláció során használunk. Jelenleg szabadon hozzáférhetőek a Budapesti Értéktőzsdén [15] és a jelentősebb nemzetközi tőzsdéken [16] jegyzett részvények historikus árfolyamindexei az elmúlt évtizedekre. Ezek a historikus árfolyamindexek 14
napi felbontásúak, nyitó- és záró árat, napi minimum és maximum árat, illetve a forgalom nagyságát tartalmazzák. Ilyen napi felbontású árfolyamadatokkal már lehetséges értékelhető szimulációkat végezni, azonban csak olyan stratégiákat lehet elemezni, melyek kereskedési frekvenciája napi kereskedésnél alacsonyabb. Ezek a stratégiák jellemzően inkább hosszú távú trendeket keresnek. Egy mozgóátlagokat vizsgáló stratégia elemezhető ilyen adatsoron, de egy gap-trading (lásd 2.2) stratégia nem alkalmazható, mert szükség lenne nap közbeni árfolyamértékekre is. Nagyobb felbontású árfolyamadatok is elérhetőek az Interneten, például a Portfolio.hu valós időben még a 5 legjobb ajánlatot is elérhetővé teszi a könyvből egy adott értékpapírra [17], de ennek a szolgáltatásnak a díja magas. Ilyen, szinte teljes információhalmazon viszont minden stratégiát ki lehet próbálni, mert minden olyan információ a rendelkezésünkre áll, ami valós kereskedés esetén is elérhető. A listán szereplő szoftvereknek csak a fele képes portfóliók kezelésére, és e szoftverekhez is csak korlátozott mértékben, egy új, redukált funkcionalitású programozási nyelv megtanulása árán lehet új kereskedés stratégiát hozzáadni. Ahogy azt dolgozatom bevezetésében is kifejtettem, a diplomatervem célja egy olyan backtesting rendszer fejlesztése, melyhez a felhasználó könnyen fejleszthet saját stratégiát. A felsorolt szoftverek mind a kliens számítógépén végzik a szimulációt, ez egyszerű számítások és durvább, napi felbontású adathalmaz esetén még elfogadható, gyors megoldás, de amennyiben egy komplex stratégiát kellene tesztelnünk valós felbontású (az összes tranzakciót és a legjobb n ajánlatot tartalmazó) adatsoron, sok, eltérő paramétert megadva a stratégiához, akkor egy személyi számítógép számítási kapacitása nem lesz elegendő.
2.5 Paraméterek vizsgálata A
szimulációs
eljárások
során
az
adott
eljárást
több
paraméter
figyelembevételével végzik. Minden ilyen paraméternek van egy értékkészlete, mely olyan paraméter-értékeket tartalmaz, melyeket érdemes lehet a szimulációnál használni. A paraméterek értékkészleteinek Descartes-szorzata a paramétertér, a tér pontjai olyan paraméter-érték vektorok, melyek minden paramétertípusból tartalmaznak egy, az értelmezési tartományon belüli értéket. A szimulációt végzők célja lehet, hogy meghatározzák az egyes paraméterek azon értékeit, azaz a paramétertér azon pontjait, melyekre a szimuláció értékelésük szerint optimális eredményt szolgáltat. Egy
15
szimuláció paraméterterének vizsgálatát és például az optimális paramétertér-pont meghatározását nevezi az angol szakirodalom parameter study-nak. A kereskedési stratégiák eredményessége is nagyban függ a stratégiák alkalmazásánál használt paraméterektől, hiszen például a hosszú- és rövidtávú mozgóátlagokat figyelő stratégia érzékenységét és jelzési gyakoriságát meghatározza az átlagok időintervalluma, ha rövid időintervallumot (3-5 nap) választunk a rövidtávú átlag alapjának, akkor várhatóan gyakrabban metszik egymást az átlagértékek és keletkezik vételi vagy eladási jel. Tehát a kereskedési stratégiák paraméterezésének vizsgálata is egy parameter study feladat. A diplomamunkám során elkészített rendszernek célja volt, hogy a felhasználó a rendszer alkalmazásával vizsgálhassa egyes paraméterezések, paramétertér-pontok eredményességét úgy, hogy meghatározza a szimuláció paraméterterét, és az egyes paramétertér-pontokhoz tartozó eredményeket összeveti.
16
3 Az elkészített rendszer Az 2.4. fejezet végén felvetett két problémára (nincs jelenleg a piacon alapvető programozási ismeretekkel tetszőlegesen bővíthető backtesting rendszer, illetve, hogy a meglévő rendszerek nem alkalmasak nagy számításigényű szimulációk elvégzésére) kívánok megoldást kínálni a diplomamunkaként általam fejlesztett keretrendszerrel.
3.1 Célkitűzések A
diplomamunka
során
fejlesztendő
rendszerrel
szemben
az
alábbi
kritériumokat állítottuk fel: 1. Mivel a fejlesztendő rendszer keretrendszer, ezért legfontosabb funkciója, hogy a felhasználó képes legyen saját, vizsgálandó stratégiát definiálni, egy széles körben ismert programozási nyelvet használva, anélkül, hogy a rendszer teljes forráskódját ismernie kellene, 2. A felhasználó az általa választott idősorokon futtathassa az általa megírt kereskedési stratégiákat, a rendszer képes legyen az idősorok betöltésére és felhasználására, 3. A felhasználó tetszőleges, általa megadott paraméterekkel futtathassa a szimulációt, hogy megállapíthassa az adott idősorhoz a választott stratégia számára legeredményesebb paraméterhalmazt, 4. A keretrendszer által elvégzett elemzés eredményeit a felhasználó az általa választott módon értékelhesse ki, amennyiben az egyszerűbb mutatóknál (hozam) több információt szeretne az elemzésből kinyerni, 5. A keretrendszer
egyszerű beállítások
elvégzésével
az
elemzést
nagy
számításteljesítményű környezetben, egy gridben végezhesse, hogy lehetséges legyen egyszerre több szimulációt futtatni, illetve egy stratégiát különböző paraméter értékekkel vizsgálni, az optimális paramétereket keresve. A diplomatervem elkészítését megelőző kutatómunkám során kerestem olyan rendszert, mely teljesíti ezeket a feltételeket, de nyilvánosan elérhető ilyen rendszert nem találtam, ezért van alapom feltételezni, hogy az általam fejlesztett rendszer új és egyedi.
17
3.2 Választott megoldások Ahhoz, hogy a felhasználónak lehetősége legyen saját fejlesztésű stratégiákat kipróbálnia a keretrendszerrel, szükséges volt legelőször a felhasználónak nyújtott felületet specifikálni, azaz azt megadni, hogyan fog az ő programja illeszkedni a keretrendszerbe. Meg kellett határozni, hogy milyen szolgáltatásokat biztosít a fejlesztett stratégia számára a keretrendszer, illetve a keretrendszer mit vár el a stratégiától, hogyan tudja a stratégia jelezni a vételi és eladási tranzakciót. A diplomamunkám során fejlesztett keretrendszernek nem volt célja, hogy a kereskedelmi forgalomban kapható szoftverek minden tudásával rendelkezzen, hiszen ehhez nagyon kevés lett volna a rendelkezésre álló idő, inkább az újdonságok, más rendszerekben nem létező funkciók implementálása volt a cél. Ezért egy egyszerűsített pénzügyi modellt alkalmaztam a diplomamunkámban. Mivel a valós idejű árfolyam idősorok nagyon sokba kerülnek, és az alkalmazott modell sem használná fel a többlet információt a szabadon hozzáférhető, napi felbontású historikus adatsorokhoz képest, ezért a munkám során az ingyenesen elérhető, kevésbé részletes historikus adatsorokat használtam.
3.2.1 A pénzügyi modell A pénzügyi modell határozza meg, hogy milyen környezetet biztosít a keretrendszer a felhasználó stratégiájának, a stratégia milyen információk alapján hozhatja meg a vételi vagy eladási döntéseket egy adott pillanatban. Az általam használt modellben a kereskedés leggyakrabban naponként történik, a nyitó árfolyamot figyelembe véve, mert a rendelkezésemre álló idősorok napi felbontásúak. Azért kell a nyitó árfolyamot használni, mert a valóságban is csak a kereskedési nap végére lesz ismert a záróárfolyam, elméleti hiba lenne a kereskedés során ismertnek feltételezni az értékét. Mivel a fejlesztett rendszertől elvárás, hogy ne csak egy részvény kereskedelmét irányító stratégia szimulációjára legyen képes, hanem egy több részvényből álló portfólió kezelését tudja szimulálni, ezért a rendszernek nem csak egy adott részvény árfolyamának idősorára van szüksége, hanem a portfólióba választható összes részvény historikus adatsorát igényli. Erről a 2. célkitűzés értelmében a felhasználónak kell gondoskodnia. A diplomatervem fejlesztése során, teszteléshez az S&P 500-ban [7] , az
18
500 legjelentősebb amerikai részvényt tömörítő indexben szereplő részvények adatsorait használom. A kereskedelmi forgalomban kapható backtesting rendszerek a felhasználó stratégiájától vételi és eladási jelek előállítását követelik meg, ahogy a szimuláció halad előre az időben. Egy ilyen jel egy adott mennyiségű részvény eladását vagy vételét jelenti. A diplomamunkámban használt pénzügyi modell azonban nem közvetlenül vételi és eladási jelek előállítását kéri a stratégiától, hanem ezen egyszerűsítve azt várja el, hogy minden kereskedési napon a felhasználó stratégiája minden részvényt egy általa tetszőlegesen választott pontszámmal értékeljen. A rendszer ez után kiválasztja az n (megadható paraméter) legnagyobb pontszámot kapott részvényt, és egyenlő értékben vásárol belőlük a portfólióba, a rendelkezésre álló készpénzből. A következő kereskedési nap előtt eladja a rendszer az összes portfólióban levő részvényt, majd újraértékelteti az új kereskedési napon az aznapi nyitóárfolyam szerint a rendelkezésre álló részvényeket. Ezt a folyamatot a következő ábra illusztrálja:
Felhasználó
Paraméterek
stratégiája Napi árfolyamok
Pontszámok
Portfólió
Részvények
Vásárlás az n legjobb
pontozása
pontszámú részvényből Új kereskedési nap
Napi árfolyamok
Napi árfolyamok
Portfólió
Portfólió
Készpénz
Készpénz
Portfólió
Portfólió frissítése,
részvényeinek
tranzakciók és a
eladása
portfólió értékének mentése 3.1. ábra A szimuláció lépései
19
3.3 A szimuláció motorja A szimuláció motorja Java programozási nyelven íródott, fő feladata a fent említett szimulációs eljárás implementálása, és egy interfész biztosítása a programozó felhasználó számára, hogy új kereskedési stratégiát implementálhasson. Ez a motor nagyban épül a diplomatervezés első féléve során elkészített, csak a felhasználó számítógépén futó backtesting keretrendszerre, felhasználja annak adatszerkezetét, és az ott kipróbált bővítési interfészt alkalmazza a mostani rendszerben is. Az újdonság a mostani rendszer motorjában, hogy nem közvetlenül a felhasználói kezelőfelülethez kapcsolódik, nincs szoros kohézió, hanem „önmagában” fut majd egy grid rendszer számítási csomópontján. Ebből kifolyólag úgy kellett megírni, hogy minden szükséges bemeneti adatról feltételezhető, hogy lokálisan elérhető, és az eredményt is egy lokális fájlba írja. A szimulációs motort alkotó fontosabb osztályok és a közöttük levő kapcsolatok láthatóak a 3.2 ábrán, az UML osztálydiagramon.
20
3.2. ábra A motor osztálydiagramja
21
A szimuláció motorjának fejlesztését a belső adatszerkezet definiálásával kezdtem, a rendelkezésre álló adatsorok adataiból kiindulva. Az adatszerkezet az alábbi entitásokból áll: DailyData: Egy részvény napi árfolyamadatát (nyitó-, maximum-, minimumés osztalék-kifizetéssel korrigált záróárfolyamot) tartalmazó entitásosztály. Stock: Egy részvényt reprezentáló entitásosztály, tartalmazza a részvény kódját és a részvény adatsorát, mint DailyData-k dátumindexelt tömbjét. StockData: Egy idősort reprezentáló osztály, tartalmazza az idősor nevét (pl.: S&P 500), az idősor kezdő- és végdátumát,a tartalmazott napok számát és egy név-Stock hash-táblát, hogy név alapján gyorsan hozzá lehessen férni a részvény objektumhoz. StockDataFactory: Az idősorok betöltéséhez használt interfész, mely lehetővé teszi, hogy többféle forrásból származó idősorokat egységesen tudjuk memóriába tölteni. CSVStockDataFactory:
Implementálja
a
StockDataFactory
interfészt, az számomra rendelkezésre álló, CSV fájlokban található idősorokat olvassa fel, hoz létre StockData objektumot.
Parameter: A felhasználó által specifkált, egy elemző algoritmusnak átadott paramétert jelképez. A paraméternek van egy kódja, mely azonosítja funkcióját a rendszerben, egy leírása, mely a felhasználónak szól, egy minimális és egy maximális, lebegőpontos értéke, illetve egy lépésköz két érték között, hogy a paraméter értéktartománya diszkrét legyen.
ParamValue: Egy paraméter egy konkrét értékét tartalmazó osztály.
Portfolio: Egy befektetői részvényportfóliót reprezentál, mely tartalmazza a birtokolt részvényösszetételt, a rendelkezésre álló készpénzt és a portfólió összértékét. Ez az osztály tartalmazza a részvények adásvételét implementáló metódusokat: o buyStock: Az adott napon vesz az adott részvényből a megadott darabszámot, amennyiben van elég készpénz. o sellStock: Elad az adott napon az adott részvényből a megadott darabszámot, készpénzre váltva értéküket.
22
o liquidate: Eladja az adott napon az összes birtokolt részvényt, készpénzre váltva értéküket. o addStocks: Eladja az összes birtokolt részvényt, majd a megadott részvényekből vásárol, egyenlő értékben, a teljes rendelkezésre álló készpénzt elhasználva. PortfolioState: A portfólió értékét tárolja egy adott napon, a szimuláció eredményét ezen osztály egy listája adja. Transaction: A Portfolio osztály feljegyzi a kereskedési műveletek során végrehajtott tranzakciókat, egy tranzakció a kereskedés időpontját, kereskedett részvény nevét, a kereskedett mennyiséget és értéket, illetve a kereskedés után a portfólió értékét. Backtest: A felhasználó által megadható stratégia ősosztálya, használata a 3.3.1. fejezetben kerül leírásra. Engine: A szimulációs motor belépési pontja, betölti az idősorokat és a felhasználó által megadott stratégiát, létrehozza a számításokat végző szálakat, végül összeállítja az eredményt. EngineThread: A szimuláció számításait végző szál, a Thread osztály leszármazottja. Ezeket az osztályokat használhatja a felhasználó ahhoz, hogy a backtest algoritmusát kifejlessze, a pontos interfészek később kerülnek leírásra.
23
A szimulációs motor futás közbeni működése a következő UML szekvencia diagramon látható:
3.3. ábra A szimuláció futása
A szimulációs motor belépési pontja az Engine osztály, az elemzést az idősor adatok betöltésével és a felhasználó általadott backtest algoritmusosztály futás közbeni példányosításával létrehozandó
kezdi
osztály
StockDataFactory
(a
createBacktest()
class
fájlja).
egy
Az
függvény
idősor
leszármazottját
adatok (jelen
argumentuma
a
betöltéséhez
a
esetben
a
CSVStockDataFactory -t) használja. A szimulációs motor a vizsgálandó paramétertér-pontokat egy bemeneti feladatleíró fájlból tölti be, minden pont vizsgálatához egy új futási szálat (EngineThread osztály, amely a Java Thread osztályának leszármazottja) hozva létre. Minden kereskedési napra (a kereskedési periódus hossza paraméterként megadandó, a kezelőfelületen beállítható) az alábbi lépéseket végzi egy létrehozott futási szál: 1.
A felhasználó által megadott algoritmustól egy pontszámot kér minden
egyes részvényhez, az adott napra. Minél magasabb a pontszám, annál nagyobb valószínűséggel kerül bele a részvény a portfólióba.
24
2.
A felhasználó által megadott n legmagasabb pontszámú részvényekből
egyenlő értékben vesz, az addStocks függvényt meghívva. Mivel a rendszer nem foglalkozik a tranzakció költségeivel, ezért minden kereskedési nap eladja az összes birtokolt részvényt és újakat vásárol helyette. A tranzakciókat egy listában rögzíti.
3.3.1 Felhasználótól elvárt komponensek A felhasználó feladata a backtest algoritmus kifejlesztése, az általa fejlesztett algoritmusnak a Backtest osztály leszármazottjának kell lennie. Implementálnia kell a score() függvényt, mely paraméterként megkapja az értékelendő részvény nevét, a StockData betöltött idősort, a felhasználó által a felületen beállított paraméterek listáját és a kereskedési napot. A függvény visszatérési értéke a részvényre adott pontszám. Az implementált osztályt a felhasználónak le kell fordítania, és JAR archívumba tömörítve kell a rendszer számára elérhetővé tennie. Egy ilyen, felhasználó által fejlesztett Backtest
leszármazott osztályra
található példa a 3.2 ábrán, BacktestRandom névvel. Ez a stratégia minden kereskedési napon, minden részvénynek egy véletlenszerűen választott pontszámot ad. Ennél az egyszerű stratégiánál egy megalapozottabb, a diplomamunka fejlesztése során implementált stratégiát írok le a 6. fejezetben.
25
4 Alkalmazásfejlesztés grid rendszerekre A
diplomamunkám
során
fejlesztett
tőzsdei
backtesting
keretrendszer
különlegessége, hogy egyszerű beállítások elvégzésével a szimulációs számítást egy grid szolgáltatás igénybevételével képes elvégezni. A következőkben leírom, hogy pontosan mit takar a „grid szolgáltatás”, hogyan képest ezt a szolgáltatást az alkalmazásfejlesztő igénybe venni. A fejezet végén bemutatok egy olyan, a tanszéken fejlesztett keretrendszert, mely nagyban megkönnyíti az alkalmazásfejlesztést különböző grid rendszererekre.
4.1 A grid, mint szolgáltatás A „grid” szó az angol „electrical grid” kifejezésből származik, mely elektromos hálózatot jelent. Ennek az oka az, hogy az informatikusok egy általánosan hozzáférhető, nagy rendelkezésre állású számítási infrastruktúrát akartak létrehozni, melyet a felhasználók, hasonlóan az elektromos hálózathoz, közműként tudnak használni számítási feladataik elvégzéséhez. Ez a közmű jellegű használat köszön vissza a utility grid modellben, mely szerint a grid szolgáltatás nyújtásának a feladata kevés számú erre specializált szervezet dolga, melyek 24/7 ezzel foglalkoznak. A modellben a felhasználók száma és a használati célok és területek száma jelentősen meghaladja az erőforrást biztosító szervezetek számát. Napjaink földrészeken átnyúló gridjeit általában több tíz nemzeti szervezet együttműködése hozta létre. Egy ilyen nemzeti szervezet általában egy nagyobb számítógép-hálózatot üzemeltet, sok, a számításokat végző, egységes konfigurációval rendelkező worker node számítógépekkel (számítási csomópontokkal), nagykapacitású háttértár rendszerekkel. Ezeket a szervezeteket nagysebességű kutatói gerinchálózat köti össze (pl. a GEANT). Így egy grid hálózat több ezer számítógép számítási és tárolókapacitását képes egyesíteni, például az idén zárult EGEE projekt [18] végére 150 ezer CPU állt a Grid felhasználóinak rendelkezésére. A földrajzilag elosztott hardver réteget egy, a felhasználók számára egységes rendszert láttató szoftveres köztesréteg fogja össze, mely végrehajtja a felhasználó számítási feladatait, kezeli az erőforrásokat és adminisztrálja a felhasználásukat.
26
Ahhoz, hogy a grid, mint infrastruktúra vízió megvalósulhasson, a létrejövő grid szolgáltatásnak az alábbi öt kérdésre [19] kell kielégítő választ találnia: 1. Erőforrás-megosztás: Ahogy az elektromos hálózat felhasználói is osztozkodnak a hálózat kapacitásán, úgy kell a grid felhasználói között is megosztani a grid erőforrásait. Az erőforrások rugalmas kezeléséhez szükséges, hogy a felhasználók számára fizikailag különböző helyeken levő, eltérő hardverkonfigurációjú erőforrások egységesen jelenjenek meg. Az igazságos használat érdekében biztosítani kell, hogy minden felhasználó csak a szükséges mennyiségű erőforrást foglalhassa le. Az azonos céllal, hasonló igényekkel rendelkező felhasználók virtuális szervezeteket
(VO-kat)
alkotnak.
A
VO-k
erőforrás
kezelési
szolgáltatásokat biztosítanak, a szervezet tagjai használhatják a VO által rendelkezésre bocsátott erőforrásokat. A magyar kutatók és hallgatók az EGEE-ben a Hungrid VO alá tartoznak, , de egy felhasználó több VO tagja is lehet. 2. Biztonságos hozzáférés: Mivel a grid egy globális, szorosan integrált hálózat, több ezer felhasználóval, egy vírus vagy egy rosszindulatú felhasználó hatalmas károkat okozhat a rendszerben, tönkretehet erőforrásokat és mások munkáit. Ezért egy átgondolt biztonságpolitika létrehozása
és
alkalmazása
elengedhetetlen
a
grid
biztonságos
üzemeltetéséhez. A gridek biztonságpolitikája tanúsítvány alapú, a felhasználónak egy X.509-es szabványnak megfelelő, akármilyen elfogadott CA (Certificate Authority) által a felhasználó számára kiállított, korlátozott érvényességi idejű tanúsítvánnyal kell rendelkeznie ahhoz, hogy a VO szolgáltatásait használhassa. A tanúsítványok alkalmazásával lehetséges a felhasználók engedélyezése (authorisation), mely eldönti, hogy mely felhasználók férhetnek hozzá a rendszerhez, és a hitelesítés (authentication), mely egyértelműen és letagadhatatlanul azonosítja be a felhasználót. 3. Erőforrás-használat: Mint ahogy az áramszolgáltató díjat számláz a fogyasztónak a szolgáltatásaiért, a grid is számláz a szolgáltatás használatáért a felhasználóknak. Ez kereskedelmi gridek esetén ténylegesen fizetendő számla lehet, kutatási hálózatok esetében általában egyezmények rögzítik az engedélyezett használat mértékét. 27
4. A távolság átka: Mivel a gridben az egyes alhálózatokat akár óceánok választhatják el egymástól, és mivel a felhasználó számításai a gridben bármely számítási csomóponton futhatnak, ezért olyan esetekben előnyös gridet alkalmazni, amikor az elosztott számítás nyeresége meghaladja a az adat eljuttatásához szükséges időveszteséget. Ez a szállítási idő a grid alhálózatait
összekötő
nagysebességű
kutatói
gerinchálózatoknak
köszönhetően egyre inkább elhanyagolható lesz az feladatütemezés miatti sorbanállási időhöz és a végrehajtási időhöz viszonyítva. 5. Nyitott szabványok: A nemzeti és nemzetközi hálózatok gridbe egyesítéséhez egységes és nyitott szabványok szükségesek, hogy képesek legyenek egymás erőforrásainak megismerésére és használatára. Az egységes és szabványos köztesréteg-szoftverek a gridek felhasználói számára és alkalmazásfejlesztői számára is lehetővé teszik, hogy a globálisan szétterülő hardvert elfedve, egy nagy és több erőforrást tartalmazó szolgáltatást használhassanak. Napjaink legelterjedtebb grid köztesrétege a Globus [20], mely megvalósítja az Open Grid Forum [21] szervezet által kidolgozott Open Grid Services Architecture [22] rendszerintegrációs szabványt.
4.2 Alkalmazások „gridesítése” A következőkben megmutatom, hogy milyen főbb lépéseket kell a fejlesztőnek elvégeznie, hogy alkalmazása egy grid szolgáltatásait vehesse igénybe. A példát az EGEE Griden [18] mutatom be, mely az európai, nemzeti, akadémiai grideket egyesítve egy pán-európai, tudományos célokra használható gridet hozott létre. Dolgozatomban „Grid” néven az EGEE Grid-et fogom ezentúl érteni. Jelenleg a projekt folytatásában, a European Grid Infrastructure-ban [23] vesznek részt magyar grid hálózatok (a KFKIRMKI, a SZTAKI, a BME és az ELTE hálózata), de ennek a nemzetközi gridnek eleme a CERN LHC kísérlete is. A diplomamunkám fejlesztése során is ezt a grid hálózatot vettem igénybe, specifikusan a magyar VO szervezet, a Hungrid [24] szolgáltatásait.
4.2.1 Az EGEE Grid biztonsága Minden, a Gridet használó felhasználónak és fejlesztőnek ismernie kell a Grid biztonsági mechanizmusait, mivel ezek mindig jelen vannak a használat során. A Grid
28
tervezői nagy hangsúlyt fektettek a rendszer biztonságára, mert illetéktelen felhasználók hatalmas károkat okozhatnak a rendszerben, a projekt bukását jelenthetik. Az EGEE Grid az AAA szolgáltatásokat (authorization, authentication, accounting) egy, a nyilvános kulcsú titkosításon alapuló tanúsítványrendszerrel biztosítja. A rendszer központi elemei a Certificate Authority-k (CA-k), a tanúsító hatóságok, melyeket mindenki hitelesnek ismer el, és minden, általuk tanúsított felhasználó jogosan használja a rendszert. A tanúsítványok olyan fájlok, melyek egyértelműen és hitelesen beazonosítják a tulajdonost, és a hitelességet szavatoló CA-t, amely kiállította a tanúsítványt. Ez a gyakorlatban annyit jelent, hogy egy felhasználói tanúsítvány áll a felhasználó adataiból, publikus kulcsából és a CA digitális aláírásából, ahogy ezt a 4.2. ábra mutatja. Bárki, aki rendelkezik a tanúsítvánnyal, el tud járni a felhasználó nevében. Felmerül a kérdés, hogyan tud például a Grid erőforrás brókere a felhasználó nevében eljárni úgy, hogy ne legyen szükség az autentikációhoz a felhasználó privát kulcsának ismeretére, mivel azt a felhasználó nem szeretné megosztani. A grid felhasználója létrehozhat egy ún. proxy-t, amely egy speciális, rövid ideig érvényes tanúsítvány és egy privát kulcs pár, a tanúsítvány tartalmazza a proxy publikus kulcsát. A proxy tanúsítványát a felhasználó írja alá saját privát kulcsával, így a proxy a felhasználó jogosultságaival rendelkezhet. A proxy arra jó, hogy segítségével a felhasználó nevében korlátozottan járhatnak el a szolgáltatások, úgy, hogy a felhasználó kulcsát nem kell odaadni, mégis ellenőrizhető a proxy tanúsítvány hitelessége a kiállító láncot ellenőrizve: A proxy titkos kulcsával aláírtakat a proxy nyilvános kulcsával lehet ellenőrizni, a proxy nyilvános kulcsát tartalmazó tanúsítványt a felhasználó nyilvános kulcsával, amelyet pedig a hitelesnek tekintett CA nyilvános kulcsával. Ez lánc a gyakorlatban ennél hosszabb is lehet, a proxy-k újabb proxy-kat hozhatnak létre, ez látható a 4.1. ábrán.
4.1. ábra Tanúsítványlánc Forrás: [32]
29
4.2. ábra X.509 tanúsítvány
A Grides alkalmazásfejlesztés során nem csak a Griden való futtatás miatti technikai változtatásokra kell figyelni, hanem már a fejlesztés kezdetétől fogva figyelmbe kell venni a Grid használatának sajátosságait. Akkor célszerű egy alkalmazást felkészíteni Grid használatára, ha a végzett számítások valamilyen módon (paramétertér-felosztással, funkciók szerinti felosztással, pipeline szervezéssel) jól párhuzamosíthatóak, így kihasználható több CPU kapacitása is, és kevés kommunikáció szükséges a párhuzamosan futó szálak (grides feladatok) között. Nem érdemes viszont olyan alkalmazást Griden futtatni, mely garantált válaszidőt követel meg, mivel a Grid feladatütemezése,
biztonsági
funkciói
és
adatmozgatási
szolgáltatásai
mind
meghatározhatatlan késleltetést okoznak a beküldött számítási feladat futásában. A Gridet használni kívánó alkalmazásnak a számításait egy Grides feladat (job) formájában kell beküldenie a Grid feladatütemezőjének. Ehhez a Grid felhasználói felületét, a Grid UI-t (Grid User Interface) használhatja, amely jellemzően egy, az Internetről elérhető szerver, melyhez a VO biztosít hozzáférést a felhasználó számára. A feladatbeküldés és az eredmény megszerzésének a folyamata a következőképpen zajlik [26]:
30
2. A tanúsító hatóságtól (CA-tól) kapott
1. A felhasználó bejelentkezik a
tanúsítványa segítségével egy 12 óráig érvényes
Grid
UI
szszámítógépre.
ideiglenes tanúsítványt hoz létre, mellyel a nevében eljárhatnak a különböző szolgáltató 3.
ágensek.
A
5. A felhasználó
felhasználó
létrehoz egy új
alkalmazása létrehozza
bejegyzést
a beküldendő feladatot,
logikai
egy feladatleíró fájlban Virtual
megadja
Organization
Membership
az
Grid
8. A felhasználó
és kimeneti fájlokat,
felhasználóit azonosítja és
programja letölti
majd
kezeli
az
tanúsítványával magát
(VOMS),
a
IS-ről
a
az
(LFC)
azonosítva beküldi az
eredményét.
erőforrás brókernek.
a
nagyméretű bemeneti fájlnak,
ideiglenes
feladat
fájl
katalógusban
argumentumait és a be-
Service
a
majd
feltölti
a
tárolóba (Storage Element, SE) a fájlt.
Erőforrás bróker
4. A bróker lekérdezi az információs Információs szolgáltatás (IS)
szolgáltatást (IS), hogy milyen a feladat igényeinek megfelelő szabad erőforrások vannak. 6. A bróker elküldi a feladatot a számítást végző egységre (Computing Element, CE).
7. A feladat
8. Az eredményt regisztrálja az
letölti az SE-
IS-nél.
Computing
ről
Element (CE)
bemeneti fájlt.
ábra: Feladatkezelés EGEE Gridben. 4.3
31
az
a
nagy
Storage (SE)
Element
A feladatbeküldés folyamata, mint ahogy az ábrán is látszik, egy több lépéses, többszereplős, hosszú folyamat, ezt kell a felhasználónak automatizálnia, ha gridet használó programot fejleszt. Szerencsére megismertem a Saleve keretrendszert, mely támogatást ad a grides feladatkezelésben a fejlesztőnek, nekem nem kellett foglalkoznom azzal, hogy a számítások elvégzése tulajdonképpen hol történik. Azonban a nagyméretű adatok kezelésével a Saleve eredetileg nem foglalkozik, így továbbra is maradnak grides feladatok.
4.3 A Saleve keretrendszer A Saleve nyílt forráskódú keretrendszert [27] a BME Irányítástechnikai és Informatikai Tanszékén fejlesztették, abból a célból, hogy megkönnyítse az alkalmazásfejlesztők feladatát, amennyiben nagy teljesítményű számítási szolgáltatást akarnak felhasználni. A keretrendszert úgy tervezték, hogy elfedje a fejlesztők elől a számítást végző infrastruktúrát, a fejlesztőnek mindössze a számítások részekre bontása és a számítás implementálása a feladata, nem kell törődnie a grides feladatkezeléssel, biztonságpolitikával, elég csak egy tanúsítványt beszereznie és a keretrendszernek rendelkezésére bocsátania. A Saleve keretrendszert a leggyakrabban alkalmazott párhuzamosítási technika, a parameter study (paraméterelemzés) támogatására készítették fel, a felhasználónak a számításainak
paraméterterét
fel
kell
darabolnia,
az
így
kapott
egyes
paraméterhalmazokkal végzendő számításokból hoz létre grid feladatot a keretrendszer. A Saleve keretrendszer egy kliens-szerver architektúrát használ, a kliens feladata a paramétertér felosztása és az elvégzendő számítás definiálása:
4.4 ábra A paramétertér feldarabolása. Forrás: [28]
32
A szerver feladata pedig a számítások elvégzése az adott paraméterhalmazzal a rendelkezésre álló infrastruktúrán:
4.5 ábra A szerver végrehajtja a feladatot. Forrás: [28]
Az elvégzett feladatok eredményét a szerver összegyűjti, és elküldi a kliensnek:
4.6 ábra A szerver összegyűjti a feladatok eredményét. Forrás: [28]
Végül a kliens összegyűjti a szerver által visszaküldött részeredményeket és egyesíti őket:
4.7 ábra A kliens összeállítja a végső eredményt a részeredményekből. [28]
A Saleve rendszer jelentős előnye még, hogy többféle számítási infrastruktúrát használhat (gLite, Condor vagy SZTAKI Desktop Grid), az egyes infrastruktúrák sajátosságait becsatlakozó modulok kezelik, így a keretrendszert újabb infrastruktúrák kezelésére is fel lehet készíteni, illetve a felhasználó alkalmazása könnyen átalakítható egy másik infrastruktúra használatára. Amennyiben nem áll rendelkezésre egyetlen grid infrastruktúra sem, a kliens komponens képes a feladatok lokális gépen, több szálon való futtatására, ekkor a szerver komponensre nincs szükség. A diplomamunkám elkészítése során a gLite becsatlakozót használtam, hogy feladataimat az EGEE-n tudjam futtatni. 33
4.3.1 Fejlesztés a Saleve keretrendszer használatával Alkalmazásfejlesztői szemszögből a keretrendszer használata a keretrendszer telepítése után rendkívül egyszerű. A keretrendszer C++-ban íródott, egyelőre csak C++ alkalmazásokat lehet fejleszteni a segítségével, de már készül Java-s interfész is. A fejlesztőnek egy olyan C++ forrásfájlt kell mindössze létrehoznia, amely az alábbi elemeket tartalmazza: 1. Hivatkozást a saleve.h forrásra. 2. Egy
void
függvényt,
saleve_span()
elképzelésének
megfelelően
felbontja
mely a
a
fejlesztő
paraméterteret
paraméterhalmazokra. A függvény törzsében végig kell iterálni a paraméterhalmazokon,
átadva
egy-egy
halmaz
elemeit
egy-egy
saleve_AddInstance() hívásnak egy konstans string formájában. A saleve_AddInstance() létrehoz egy számítási szálat, mely majd elvégzi a felhasználó számításait a bemeneti argumentumban kapott
paraméterhalmazon.
Bemeneti fájlokat, melyeket minden számítási példány megkap (a végrehajtás helyén lokálisan elérhető lesz minden példány számára), a függvénnyel
saleve_AddInputFile()
lehet
megadni.
Hasonlóképpen kimeneti fájlokat, melyek a futás végén a kliensre másolódnak vissza, a saleve_AddOutputFile()függvényhívással lehet meghatározni. 3. Egy int saleve_main(int argc, char** argv)függvényt, mely hasonlóan a C/C++-os névrokonához, a program érdemi részét, a számítást
tartalmazza.
Az
argv
argumentumban
argumentumait,
saleve_AddInstance()
megkapja a
a
számítás
paraméterhalmazát. 4. Egy void saleve_sum()függvényt, mely a szervertől visszakapott részeredményeket összegzi. Érdemes megjegyezni, hogy bár ezek a függvények egy forrásfájlban lehetnek, a saleve_span()
és
a
saleve_sum()
a
kliens
számítógépen
fut,
a
saleve_main() pedig grides háttér esetén a CE egyik worker node-ján. Ezért fejlesztéskor ügyelni kell arra, hogy nem lehet globális változók használatával
34
kommunikálni a függvények között, azt csak az említett paraméterátadások alkalmazásával lehet. A forrásfájlt a keretrendszer által biztosított salevecc fordító scripttel kell lefordítani. A keletkező futtatható fájl egyben a Saleve kliens és tartalmazza a számítást is. A kliens elküldi a létrehozott számítási szálak részleteit, az adatokat, és önmagát a szervernek.
4.3.2 A Saleve keretrendszer továbbfejlesztése A diplomamunkám során elkészített backtesting keretrendszer használatához historikus részvényárfolyam idősorokra volt szükségem, ezek CSV fájlok formájában voltak elérhetőek. Egy három éves időtartam árfolyamértékei egy részvényre kb. 30 KByte-os fájlt jelentett, az S&P 500 index részvényeinek idősorai tehát kb. 15 MByte méretű állományhalmazt alkottak, ez még tömörítve is több, mint 5 MByte. Amennyiben ennél is hosszabb időintervallumra, még több részvénnyel szeretnék szimulációt végezni, az idősorok mérete 100 MByte-os nagyságrendű is lehet akár. A backtesting keretrendszer ezeket a CSV fájlokat egy ZIP fájlba tömörítve kezeli, ezt a ZIP fájlt juttatom el a szimulációs számításokat végző grid gépekre a Saleve keretrendszer saleve_AddInputFile() függvénye segítségével. Ez egy 20 MByte-nál nagyobb ZIP fájl esetén, a gLite infrastruktúra használata esetében problémát okoz, emiatt fejlesztéseket kellett, hogy végezzek a keretrendszeren, amely nem volt felkészítve nagy fájlok fogadására. A probléma okának megértéséhez azonban jobban meg kell ismerni a Saleve működését. Amikor saleve_AddInstance() hívással létrehozunk egy új számítási példányt, akkor a keretrendszer gLite modulja egy grides feladatot (job-ot) hoz létre a lefordított program futtatásakor. Ahogy az a 4.2 ábra 3. lépésében le van írva, a job beküldésekor egy feladatleírót kell készíteni, mely, mint ahogy az a 4.7 ábrán látható, tartalmazza a worker node-on végrehajtandó bináris fájl nevét (Executable), a parancssori
argumentumait
(Arguments),
a
be-
és
kimeneteli
fájlokat
(InputSandbox, OutputSandbox), valamint a feladat futtatásához szükséges erőforrás követelményeket (Requirements). Ezt a feladatleírót a Saleve gLite modulja állítja elő automatikusan.
35
[ Rank = -other.GlueCEStateEstimatedResponseTime; AllowZippedISB = true; VirtualOrganisation = "hungrid"; gLiteMyProxyServer = "grid153.kfki.hu"; Executable = "wrapper.sh"; InputSandbox = { "/home/vakond1/opt_largefile/saleve/var/saleve/2/thesis", "/home/vakond1/opt_largefile/saleve/var/saleve/2/arguments.txt", "/home/vakond1/opt_largefile/saleve/share/saleve/wrapper.sh", "/home/vakond1/opt_largefile/saleve/var/saleve/2/job1_0.zip", "/home/vakond1/opt_largefile/saleve/var/saleve/2/job1_1.zip", "/home/vakond1/opt_largefile/saleve/var/saleve/2/job1_2.zip", "/home/vakond1/opt_largefile/saleve/var/saleve/2/job1_3.zip", "/home/vakond1/opt_largefile/saleve/var/saleve/2/job1_4.zip", "/home/vakond1/opt_largefile/saleve/var/saleve/2/job1_5.zip", "/home/vakond1/opt_largefile/saleve/var/saleve/2/job1_6.zip", "/home/vakond1/opt_largefile/saleve/var/saleve/2/job1_7.zip", "/home/vakond1/opt_largefile/saleve/var/saleve/2/job1_8.zip" }; Requirements = other.GlueHostOperatingSystemRelease >= 5.0; JobType = "Parametric"; Parameters = 10; ParameterStart = 1; ParameterStep = 1; Arguments = "\"thesis\" arguments.txt _PARAM_ saleve_outputsandbox_PARAM_.tar.gz \"job1_0out.zip\" \"job1_1out.zip\" \"job1_2out.zip\" \"job1_3out.zip\" \"job1_4out.zip\" \"job1_5out.zip\" \"job1_6out.zip\" \"job1_7out.zip\" \"job1_8out.zip\""; OutputSandbox = { "stdout.thesis._PARAM_", "stderr.thesis._PARAM_", "saleve_outputsandbox_PARAM_.tar.gz", "saleve.log._PARAM_"}; ]
4.8 ábra Feladatleíró
Ez a feladatleíró, ahogy a 4.7 ábrán is látható (a _PARAM_ karaktersorozatok miatt), parametrikus, azaz az összes, a Saleve szerver által létrehozott futási szál (grid job) ezt a feladatleírót kapja, de majd futás közben helyettesítődik be a _PARAM_ helyére a job sorszáma. A gLite modul a futás környezetének beállítása után (a feladatleíró JDL fájl első 4 sora a 4.7 ábrán) a végrehajtandó parancsnak nem a felhasználó által lefordított Saleve klienst adja meg, hanem egy burkoló shell script-et (wrapper.sh), mely elvégzi az egyes feladatok felparaméterezését a sorszám szerint (a gLite helyettesíti be a _PARAM_-ot). Az InputSandbox-ba a modul megadja a Saleve kliens nevét és egy, a modul által
létrehozott,
a
saleve_AddInstance()-nak
átadott
argumentumokat
tartalmazó, arguments.txt nevű listát, a burkoló wrapper.sh scriptet, majd végül felsorolja a fájlokat,
melyek
saleve_AddInputFile()-hívásokkal megadott bemeneti egy-egy
grid
feladat
(job)
36
bemenetei
lesznek.
Mivel
a
saleve_AddInputFile()
mindegyik futási szálnak eljuttatja a bemeneti
paramétert, ezért a paraméteres feladatleíróban mindegyik feladat bemeneti állományai szerepelni fognak. Az Arguments sorban átadódik a wrapper.sh-nak az argumentumokat tartalmazó lista, a job sorszámát tartalmazó paraméter és az OutputSandbox elemei nek archívuma, illetve a saleve_addOutputFile()-al megadott kimeneti fájlok nevei. Végül az OutputSandbox-ba írja a rendszer a fájlba írt standard output és error fájl neveit, a kimeneti fájlokat tömörítő archívum nevét és a Saleve kliens által megadott kimeneti fájlok neveit. A probléma abból adódik, hogy az általam fejlesztett backtesting rendszernél a Saleve eddigi működése szerint az idősorokat tartalmazó ZIP fájl is az InputSandbox listába kerül, viszont a bemeneti és kimeneti fájlok mérete limitálva van 10 MByte-ra [29]. A problémát úgy oldottam fel, hogy mikor glite/ServiceAdapter_gLite.cpp forrásfájlban a rendszer végigiterál a kapott bemeneti fájlokon, hogy hozzáadja őket az InputSandbox-hoz, akkor ellenőrzöm, hogy nagyobb-e az input fájl, mint 1 MByte. Ha igen, akkor egy system() C++
függvényhívással (mely végrehajta az
argumentumában megadott rendszerhívást) meghívom a gLite köztesréteg lcg-cr rendszerparancsát. Az lcg-cr parancssori utasítás egy megadott fájlt feltölt az argumentumban megadott grides társzolgáltatásra (Storage Element-re), és visszaadja a fájl globálisan egyedi azonosítóját, mely alapján később visszamásolható az SE-ről a fájl. Ezt a globálisan egyedi azonosítót (guid-et) beleírom a feladatleíróba, a DataRequirements blokkba [30], egy új InputData sorba, például:
DataRequirements = { [ InputData= {"guid:437b7b23-4a6a-11d7-87e7-9c101f8c8b70"}; DataCatalogType = "DLI"; DataCatalog = "http://lfc.hpc.iit.bme.hu"; ]
};
4.9 ábra DataRequirements blokk
Az így megadott InputData fájlokat a gLite köztesréteg a feladat végrehajtása előtt automatikusan letölti a worker node-ra a SE-ből. A kimeneti fájlokkal nincs ilyen probléma,
mivel
a
szimuláció
eredménye 37
(a
portfólió
értékének
idősora)
nagyságrendekkel kisebb, mint a bemenet, azokat vissza lehet juttatni a Saleve szervernek az OutputSandbox-ban utaztatva, majd onnan visszaküldésre kerül a klienshez a Saleve saját szállítási mechanizmusaival. A Saleve keretrendszer gLite modulján elvégzett fejlesztésem után így néz ki a modul által, a kliens által beküldött feladat feldolgozása során létrehozott parametrikus JDL feladatleíró: [ Rank = -other.GlueCEStateEstimatedResponseTime; AllowZippedISB = true; VirtualOrganisation = "hungrid"; gLiteMyProxyServer = "grid153.kfki.hu"; Executable = "wrapper.sh"; InputSandbox = { "/home/vakond1/opt_largefile/saleve/var/saleve/2/thesis", "/home/vakond1/opt_largefile/saleve/var/saleve/2/arguments.txt", "/home/vakond1/opt_largefile/saleve/share/saleve/wrapper.sh"}; Requirements = other.GlueHostOperatingSystemRelease >= 5.0; JobType = "Parametric"; Parameters = 10; ParameterStart = 1; ParameterStep = 1; Arguments = "\"thesis\" arguments.txt _PARAM_ saleve_outputsandbox_PARAM_.tar.gz \"job1_0out.zip\" \"job1_1out.zip\" \"job1_2out.zip\" \"job1_3out.zip\" \"job1_4out.zip\" \"job1_5out.zip\" \"job1_6out.zip\" \"job1_7out.zip\" \"job1_8out.zip\""; OutputSandbox = { "stdout.thesis._PARAM_", "stderr.thesis._PARAM_", "saleve_outputsandbox_PARAM_.tar.gz", "saleve.log._PARAM_"}; DataRequirements = {[ InputData = "guid:b14a5bad-dc2f-c356-c1085137", "guid:8c8c503e-c42e-8f7a-32d953be", "guid:3e3edcc5-d131-3707-51397e1a", "guid:2258bada-de50-d826-7ea66414", "guid:4cf13b76-5da4-5c54-f4496bc1", "guid:6667a0d5-b9da-f102-c40c1d58", "guid:8384b991-b9e0-a1de-b19789e1", "guid:11a32228-1b4a-80f6-42a95bca", "guid:d7767cbc-9829-e50f-48d414ac"}; DataCatalogType = "DLI"; DataCatalog = "http://lfc.hpc.iit.bme.hu"; ]}; ] 4.10 ábra Módosított feladatleíró
A legfontosabb megfigyelhető különbség, hogy a bemeneti fájlok (mivel jelen esetben az archívumok tartalmazzák a nagyméretű idősorokat is) nem az InputSandbox-ba kerültek, hanem egy külön DataRequirements blokk jött létre, ahová a nagyméretű fájlok kerülnek.
38
5 . Rendszerintegráció A diplomatervezés első félévében elkészítettem a tőzsdei kereskedési stratégia szimulációs keretrendszer első, csak a felhasználó számítógépén futó változatát. A második félév kitűzött célja, hogy a szimulációs számításokat ne a felhasználó számítógépe, hanem egy grid infrastruktúra végezze, azt jelentette, hogy az első félév során megírt szimulációs motortnak a grid egy távoli, ismeretlen worker node-ján kell futnia. A 3.1 Célkitűzések c. fejezetben leírtak szerint ezt a váltás úgy kellett végrehajtani, hogy a felhasználó továbbra is könnyen, a megszokott kezelőfelülettel tudja használni a rendszert, a saját stratégia fejlesztésénél ne kelljen tekintettel lennie a szimulációt végrehajtó infrastruktúrára. A diplomamunkám során fejlesztendő rendszernek tehát adottak voltak a követelmények külvilággal érintkező „interfészek” számára, a felhasználó oldaláról a kezelőfelület formájában, a rendszer oldaláról pedig a szimulációs motor ki- és bemeneteinek formájában. A kihívást az jelentette, hogy hogyan jut el a felhasználó által a saját számítógépén futó kezelőfelületen megadott stratégia, idősor és vizsgálandó paramétertér a szimulációs motorhoz a grid rendszer számítási csomópontjaiban, illetve az, hogy a számítás eredménye hogyan kerül vissza a felhasználóhoz és végül hogyan kerül kiértékelésre a felhasználó igényeinek megfelelően. Meg kellett azt is határozni, hogyan bontja fel a rendszer a felhasználó által megadott paramétertér vizsgálatát részfeladatokra, hogy lesz ezekből a feladatokból griden futó feladat, hogy ezek a feladatok milyen be- és kimenettel rendelkeznek. A grides háttér elfedésére a 4.3 pontban már ismertettem egy alkalmas eszközt, a Saleve keretrendszert, a diplomamunkám során ezt a keretrendszert használva építettem fel az általam fejlesztett backtesting keretrendszert. A Saleve keretrendszer alkalmazható volt a felhasználó számítógépe és a grid közötti információszállításra, de ezen felül ki kellett dolgozni, hogyan lehet egy szimulációs motor futtatást Saleve feladatba csomagolni, azaz áttételesen hogyan lehet egy grides job-ot definiálni a szimulációs motor futtatásához. A Saleve keretrendszer szerepét az általam fejlesztett rendszerben a következő ábra mutatja be, mely áttekintő képet ad a backtesting keretrendszer felépítéséről: 39
5.1. ábra Rendszerterv
40
5.1 A backtesting keretrendszer elemei A rendszer tervezésekor, a Saleve keretrendszer alkalmazásának eldöntése után felmerült a kérdés, hogy a Saleve kliens hol helyezkedjen el a rendszerben, legyen a felhasználó számítógépére telepítve, vagy a Saleve szerverrel egy helyre, a Grid UI szerverre legyen installálva. Az első megoldásnak az előnye, hogy egyszerű a Java UI és a Saleve kliens közötti kommunikáció, melyre több alternatíva is adódik:
Egyszerű, de tárhely helyigényes fájl alapú kommunikáció,
Valamilyen IPC (processzek közötti kommunikáció) alkalmazása (pipeok, üzenetsorok, socket-ek, megosztott memória)
A megoldás hátránya, hogy a felhasználónak fel kell telepítenie a Saleve klienst komponenseit, mely azt jelenti, hogy a felhasználó csak olyan operációs rendszert és környezetet alkalmazhat, melyen a Saleve kliens fut, ami jelenleg a Linux operációs rendszert jelenti. A második megoldás előnye, hogy a felhasználó bármilyen operációs rendszert használhat, ha a Saleve kliens a Grid UI-n fut, akkor TCP/IP alapú kommunikáció lehetséges a Java UI-val, a felhasználónak nem kell foglalkoznia a Saleve telepítésével. A második megoldás hátránya, hogy új protokollt kell létrehozni a Java UI és a Saleve kliens között, mely képes a felhasználó utasításait kommunikálni, képes a felhasználó által megadott szimulációs argumentumokat eljuttatni a Grid UI-ra. Egy ilyen protokoll kifejlesztése önmaga diplomatéma szintű feladat, nem végezhető el reálisan a rendelkezésre álló idő alatt, ezért ez a megoldás el lett vetve. A backtesting keretrendszer a fentiek alapján három fő komponensből épül fel: 1. A Java-ban íródott felhasználói kezelőfelületből, 2. A C++ -ban íródott Saleve kliensből, mely a felhasználó számítógépén fut, 3. A Java-ban íródott szimulációs motorról. A következőkben e komponensek felépítését és működését írom le, kihangsúlyozva a közöttük levő kapcsolatokat.
41
5.1.1 A felhasználói kezelőfelület A felhasználói kezelőfelület funkciója, hogy rajta keresztül a felhasználó végre tudja hajtani a három fő use case-t (felhasználási esetet), melyet a keretrendszer biztosítani hivatott:
Új szimuláció meghatározása és elindítása: A felhasználó grafikusan, az operációs rendszer dialógusablakait használva ki tudja választani az általa fejlesztett stratégiát, mely egy JAR archívum, meg tudja adni a használandó idősort (amely egy ZIP fájl, mely a részvények árfolyamait tartalmazza CSV formátumban) és meg tudja adni a paramétereket, értéktartományukkal és az egyes értékek közötti lépésközzel. Az adatok megadása után a szimulációt egy gombra kattintva tudja indítani, a gomb lenyomása
után
nem
változtathatja
meg
lekérdezése:
Mivel
az
előbb
megadott
argumentumokat.
Szimuláció
állapotának
egy grides
feladat-
végrehajtás órákat, de rosszabb esetben akár napokat is igénybe vehet, ezért fontos, hogy a felhasználó le tudja kérdezni az elindított feladatok állapotát. Ezt az állapotinformációt a Saleve kliens szolgáltatja, mely a Saleve szervertől kérdezi le a beküldött feladatok státuszát.
Szimuláció eredményének kiértékelése: A felhasználó a stratégia megadásához hasonlóan megadhat egy kiértékelő eljárást tartalmazó JAR fájlt, mely eljárást a keretrendszer végrehajt, miután egy szimulációs feladat sikeresen lefutott és visszaérkeztek az eredmények.
A felhasználói felület három fő részre bontható (melyek az 5.1. ábrán, a rendszerterv bal felső sarkában, kékkel színezve találhatóak): Java Swing osztályokra, melyek a képernyő elemeit alkotják,
A Controller osztályra, mely a felhasználó által indukált eseményeket (új feladat beküldése, feladatok lekérdezése, szimuláció kiértékelése) figyeli, majd ezek bekövetkeztekor hívja meg a JobManager megfelelő metódusát, átadva a felhasználó által a képernyőn megadott argumentumokat. A JobManager reakciót visszaközvetíti a képernyőelemeknek. Ez az 5.1. ábrán, a rendszerterven a 2. és 14-es pontokban látható.
A JobManager osztályra, mely végrehajtja a felhasználó kéréseit a Saleve klienssel kommunikálva. 42
A JobManager egy új szimuláció futtatásánál létrehoz a feladatnak egy saját könyvtárat, ahová bemásolja egy központi helyről az előre lefordított Saleve klienst (egy thesis nevű bináris fájlt). Azért lehetséges előre lefordítani a Saleve klienst, mert mint ahogy az később részletesebben is le lesz írva, a kliens rögzített bemenetet vár, független a vizsgálandó stratégiától, az alkalmazott idősortól és a megadott szimulációs paramétertértől. A JobManager a feladat könyvtárába másolja a felhasználó által a GUI-n megadott elérési utakon található kereskedési stratégiát és historikus részvényárfolyamidősorokat. A könyvtárba másolódik még a Java szimulációs motort (engine.jar), a CSV-k betöltéséhez szükséges függvénykönytárakat tartalmazó JAR fájlokkal együtt. Felmerül a kérdés, hogy milyen módon tud a JobManager a C++-ban íródott Saleve klienssel kommunikálni, hogyan adhatja át a saleve_span() függvénynek a Saleve feladatok (grides job-ok) előállításához szükséges információt, mivel a saleve_span() függvénynek nincsen argumentuma. Az egyszerűbbik megoldás, hogy a JobManager a grides JDL fájlokhoz hasonlóan létrehoz egy rögzített nevű feladatleírót, melyben megadja a feladat azonosítóját, a futtatandó stratégiát tartalmazó JAR fájl elérési útját, a használandó idősorokat tömörítő archívum elérési útját és a paraméterteret (nem konkrét paraméter értékeket, hanem a paraméterek értelmezési tartományait). A bonyolultabbik, ugyanakkor gyorsabb megoldás, hogy valamilyen a rendszer
által
biztosított,
interprocessz
kommunikációs
csatornát
használunk.
Elvetettem ezt az ötletet, mert a leírófájlos megoldás jelentősen nem lassabb, viszont sokkal könnyebb a fejlesztés, jobban észlelhetőek és javíthatóak a hibák, mint csak egy memóriában csatolt rendszer esetén. Tehát a JobManager létrehoz egy rögzítetten job.cnf nevű feladatleíró fájlt és egy system() rendszerhívással meghívja a Saleve klienst, ez látható az 5.1 ábrán, a rendszerterv 3. pontjában. A beküldött feladatok állapotát a Controller kérésére, szintén egy system() rendszerhívással kérdezi le, a thesis
–ls
parancsot végrehajtva. A parancs hatására a Saleve kliens lekérdezi a szervertől a beküldött feladatok állapotát, és kiírja a standard kimenetre, ezt dolgozza fel és adja vissza a Controller-nek a JobManager. Ez a rendszerterv ábra 13. pontjában látható.
43
5.1.2 A Saleve kliens A Saleve kliens a 4.1.3. fejezetben leírt függvényeket tartalmazó C++ forrásfájlból fordított bináris, végrehajtható fájl. A Saleve kliens a működését az előző pontban ismertetettek szerint, a saleve_span() függvényben a job.cfg nevű feladatleíró fájl megnyitásával és értelmezésével kezdi. Ez a fájl a kliens binárisával egyező könyvtárban van, ezért elég csak a fájl nevét ismernie a kliensnek. Egy teszteléshez használt feladatleíró tartalma: jobID=job1 algPath=/home/vakond1/backtest.jar csvPath=/home/vakond1/csv.zip paramNum=4 param0Code=P1 param0Desc=Teszt1 param0Min=1 param0Max=3 param0Step=1 param1Code=P2 param1Desc=Teszt2 param1Min=4 param1Max=5 param1Step=1 param2Code=P3 param2Desc=Teszt3 param2Min=6 param2Max=8 param2Step=1 param3Code=P4 param3Desc=Teszt4 param3Min=8 param3Max=9 param3Step=0.5
5.2. ábra Feladatleíró a Saleve kliens számára
44
A feladatleíróból kiolvassa az idősorokat tartalmazó archívumnak a nevét (az archívum
szintén
a
kliens
binárisával
egy
könyvtárban
van),
majd
egy
saleve_addInputFile() hívással regisztrálja, mint bemeneti fájlt a Saleve feladathoz. Ugyanezt teszi a a szimulációs motor JAR fájlával, illetve feladatleíróban megadott, a felhasználó által létrehozott, JAR fájl formájában megtalálható kereskedési stratégiával.. A feladatleíró végén a felhasználó által megadott paraméterek vannak felsorolva, minden paraméterhez meg van adva az értelmezési tartomány minimuma, maximuma, és a lépésköz, mellyel diszkrét pontokra bontjuk a tartományt, hogy véges számú paramétertér-pontot kelljen vizsgálni a szimuláció során.
5.1.3 Saleve feladatok (jobok) létrehozása A minden Saleve job számára közös input fájlok megadása után következik a paramétertér felbontása, a Saleve jobok kialakítása. Ezek a lépések szintén a saleve_span() függvényben történnek meg. A paramétertér felbontását egy általam írt, a Saleve klienssel egy forrásfájlban található függvény végzi, melynek bemenete a felhasználó által megadott paraméterek listája, kimenete pedig a paramétertér pontjai, egy listában felsorolva. Az algoritmus C++-os implementációja a Függelék II. pontjában található. Mivel a paramétertér mérete a paraméterek számában exponenciális, ezért 3-4 paraméter és 10 elemű értékkészletek esetén már 100-1000 vizsgálandó pont van, melyre a szimulációt le kellene futtatni. Ha mindegyikhez külön-külön Saleve job jönne létre, melyekhez a Saleve gLite modulja egyenként egy új grid job-ot hozna létre, akkor az többszáz beküldött feladatot jelentene, amely hatalmas adminisztrációs terhet fektet a grid feladatkezelő rendszereire. Ezért valamilyen módon össze kell vonni a szimulációk során vizsgált paramétertér-pontokat. Erre azt a megoldást választottam, hogy a paramétertér utolsó néhány dimenzióját összevonom egy Saleve-feladatba. Tehát például ha a paramétertér 4 dimenziós: P=P1xP2xP3xP4, és a két csoport {P1, P2} és {P3, P4}, akkor ahelyett, hogy a paramétertér minden |P1xP2xP3xP4| pontjához egy 1 méretű feladatot csinálnék, csak az első két paraméternek minden kombinációjához készítek feladatokat. Így itt a részfeladatok száma |P1xP2|, és az egyes résztartományok mérete |P3xP4|. Így felsoroltam a teljes paraméterteret.
A paramétervektort kettéosztásnál egyszerűen
megfeleztem, n paraméter esetén az első n/2 paraméter kifejtett értékei hoznak létre új 45
Saleve feladatokat, a második n/2 paraméter kifejtett értékei minden feladatban szerepelnek. Ezzel a létrejövő feladatok számát is tudja a felhasználó implicit módon szabályozni. A minden Saleve job számára közös bemeneti fájlok regisztrációja után, a paramétertér felbontása és a Saleve jobok számának meghatározása után meg kellett adni az egyes jobok által elvégzendő feladatot. A jobok által végrehajtandó utasításokat a Saleve keretrendszer specifikációja szerint a saleve_main() metódusban kell megadni, ez a metódus megkapja a saleve_addInstance() metódusnak átadott argumentumokat, tehát argumentumként lehet job-specifikus információkat átadni a létrejövő grides jobnak. Ilyen job-specifikus információ a rendszeremben a jobonkénti bemeneti fájl neve. A jobonkénti bemeneti fájl tartalmaz egy, a Saleve kliensnek átadott job.cfg fájlhoz hasonló feladatleírót, mely tartalmazza, hogy milyen konkrét paraméterértékekkel kell lefuttatni az adott rész-szimulációt, illetve megadja, hogy milyen néven keresse majd a futás helyén a szimulációs motort tartalmazó JAR fájlt, a felhasználó stratégiáját és az adatsorok archívumát. Tehát
a
Saleve
kliens
saleve_span()
metódusában
minden
saleve_addInstance() hívásnak átadok egy ZIP fájl nevet, mely a jobspecifikus feladatleírót tartalmazza. A saleve_span() visszatérése után a Saleve kliens átküldi a regisztrált bemeneti fájlokat a Saleve szervernek (5.1. ábra, Rendszerterv, 5. pont), és átküldi magát a Saleve kliens binárist is (hiszen a saleve_main()már a grid worker nodejain fog futni). A Saleve szerver a 4.2. és 4.3 fejezetekben leírtak szerint létrehozza a grid jobokat. A jobok létrehozása közben, a 4.3.2 fejezetben leírt fejlesztésem hatására a gLite modul feltölti a grid SE-re a nagyméretű, közös bemeneti fájlokat (az idősorokat és a szimulációs motort).
5.1.4 A grid jobok futása, eredmények begyűjtése A Saleve szerver, mielőtt összeállítja a grides jobok a 4.3. fejezetben részletezett parametrikus feladatleíróját, a felhasználótól (klienstől) kapott proxy tanúsítványt (ez részletesebben le lett írva a Az EGEE Grid biztonsága fejezetben) felhasználva el tud járni a felhasználó nevében a feladatbeküldés során. Szükség van erre a tanúsítványra a grid SE-be való fájlfeltöltésnél is.
46
A parametrikus feladatleíró elkészülte után a Saleve szerver a grid erőforrás brókerénél beküldi a feladatokat, majd részfeladatok elkészültét periodikusan lekérdezve vár a feladatak lefutására. Eközben a grid erőforrás brókere beütemezi végrehajtásra a beküldött feladatokat, végrehajtatja őket a worker node-okon. A feladat végrehajtása során 4.3 fejezetben
leírtak
argumentumokkal
szerint a
Saleve
a
wrapper.sh kliens
meghívja
saleve_main()
a
jobnak
függvényét.
megfelelő Ennek
a
függvénynek a rendszeremben mindössze annyi a dolga, hogy egy C++-os system() rendszerhívással futtassa a szimuláció JAR fájlját, átadva neki parancssori argumentumokként a bemeneti fájlok nevét. A bemeneti fájlok worker node-ra juttatása a grid feladata. A szimulációs motor a 3.3. fejezetben leírtak szerint betölti kitömöríti a CSV fájlokat tartlamazó archívumot, és beolvassa az idősorokat memóriába. Ez után példányosítja a felhasználó algoritmus osztályát, majd lefuttatja a szimulációt. Az eredmény fájlokat az a meghatározott néven menti el, hogy mikor befejeződik a futás a grid feladatkezelője megtalálja, mint a feladatleíróban, az OutputSandbox listában szereplő kimeneti fájlt. A grides feladatok sikeres lefutása után a Saleve szerver daemon lekérdezi a grid erőforrás brókerétől a feladatok eredményeit, a kimeneti szimulációs eredmény fájlokat pedig a gridről lemásolva, visszajuttatja a felhasználó számítógépére, hogy a JobManager fel tudja dolgozni a felhasználó által megadott algoritmus segítségével.
47
6 Az implementált rendszer tesztelése, értékelése A diplomamunkám során fejlesztett keretrendszer tesztelését a tervezett felhasználás forgatókönyvét követve végeztem, azaz az itt leírtak, mint felhasználói útmutató értelmezhetőek. A tesztelés előtt fel kellett telepítenem a Saleve klienst a gépemre, a Saleve szerver a BME IIT gridjének UI szerverén futott. Ügyelnem kellett arra, hogy a CA-tól (esetemben a Nemzeti Információs Infrastruktúra Fejlesztési Intézettől, a NIIF-től) kapott, Grid hozzáféréshez szükséges tanúsítványomat elérhesse a Saleve kliens. Elsőnek a kereskedési a választott kereskedési stratégiát kell Java nyelven implementálni, egy olyan osztályt kell létrehozni, mely a Backtest ősosztály leszármazottja, azaz felülírja a score() és getRequiredParams() függvényeket. A teszteléshez egy egyszerűbb, de napjainkban is alkalmazott stratégiát választottam, a 2.2. fejezetben leírt mozgóátlag-átlépéses stratégiát, pontosabban ennek is egy egyszerűbb változatát, mikor a rövidtávú mozgóátlag időbeli hossza egy nap, tehát egy részvény pontszámának megállapításához az aktuális árfolyamot hasonlítja össze a stratégia az elmúlt WINDOW_SIZE paraméterben megadott napnyi árfolyam nyitó átlagárához. A részvény pontszáma a részvény napi nyitóárának és az átlag értékének különbsége osztva a részvény napi nyitóárával, hogy a pontszám normalizálva legyen, össze lehessen hasonlítani árban eltérő részvényeket. A Java osztályt fordítás után egy JAR archívumba kell tömöríteni. A teszteléshez általam használt, általam implementált stratégiának forráskódja a Függelék I. pontjában található. Látható, hogy egy stratégia létrehozása kevesebb, mint 1 oldal forráskód megírását kívánja. Historikus idősoroknak az S&P 500 [7] indexben 2007. március 19-e és 2010. március 19 között szereplő részvények napi alapadatokat (dátumot, nyitó- és osztalékkorrigált záróárfolyamot, napi minimum és maximum árat és napi forgalmat) tartalmazó idősorát használtam. Ezek részvényenként külön CSV fájlban szerepelnek, az alábbi formátumban (az adatok az AAPL jelű részvény adatai): 2007/03/19,90.24,91.55,89.59,91.13,24994500 2007/03/20,91.35,91.84,91.06,91.48,17171900 2007/03/21,91.99,94,91.65,93.87,23699600 2007/03/22,93.73,94.36,93,93.96,19146800 6.1. ábra Részvény idősora
48
A szorgalmi időszak végére sajnos még nem tudtam teljesen elkészülni a grafikus Java kezelőfelülettel, azonban a rendszer teljes értékű e nélkül is. A tesztelés szempontjából sem jelentős probléma, annyit jelent mindössze, hogy nem grafikus felületen kell megadni az idősort, a szimulálandó stratégiát és a vizsgálandó paraméterteret, hanem egy feladatleíró fájlban, ahogy az 5.2. ábra mutatja. Létrehoztam egy új könyvtárat, bemásoltam a könyvtárba az idősorokat tartalmazó ZIP fájlt, a tesztelendő stratégiát JAR fájlját, a szimulációs motor JAR fájlját, a Saleve klienst tartalmazó binárist és a feladatleírót, majd elindítottam a Saleve kliens binárisát. A bináris futása közben nyomon lehet követni a Saleve feladatok létrejöttét és a futás állapotát, de mivel a grides feladatok átfutási ideje általában órás nagyságrendű, ezért nem célszerű folyamatosan nyomon követni a történteket. A feladat sikeres futását a szimuláció eredményfájljainak megjelenése jelenti, ezek is ZIP archívumok és a portfólió értékének alakulását tartalmazzák az eltelt napok függvényében. A rendszer tesztelése során futtatott szimulációk eredményei az alábbi diagramokon láthatóak: 1. Ennél a szimulációnál 10000 dollár volt a kiindulási készpénz, és 2 részvény tartott mindig a portfólióban a rendszer, naponta kereskedve a részvényekkel. A kék görbe a 2 nap, a piros a 10 nap hosszú mozgóátlagablak
használatával
kapott
eredményt
mutatja:
20000 18000 16000 14000 12000 10000
WINDOW_SIZE=2
8000
WINDOW_SIZE=10
6000 4000 2000 1 36 71 106 141 176 211 246 281 316 351 386 421 456 491 526 561 596 631
0
6.2. ábra Szimuláció eredménye 1.
49
2. Ennél a szimulációnál szintén 10000 dollár volt a kiindulási tőke, de minden nap 3 részvényt vásárolt a rendszer. A piros görbe a 2 napos, a kék görbe a 10 napos mozgóátlag-ablak méret választásának eredményét mutatja: 16000 14000 12000 10000 8000
WINDOW_SIZE=2
6000
WINDOW_SIZE=10
4000 2000
1 36 71 106 141 176 211 246 281 316 351 386 421 456 491 526 561 596 631
0
6.3. ábra Szimuláció eredménye 2.
Látható a diagramokon, hogy mennyire számít egy adott stratégiánál a paraméterek optimális megválasztása, ennél a stratégiánál, 10000 dollár kiinduló tőke esetén, napi kereskedéssel a rövid mozgóátlag-ablakok alkalmazása bizonyult eredményesebbnek.
6.1 Továbbfejlesztési lehetőségek Az itt bemutatott rendszer értékelésem szerint teljesíti a diplomatervezés kezdetén kitűzött célokat, az előző pontban leírtak szerint a felhasználó könnyen tud saját stratégiát fejleszteni, bizonyos korlátok között szabadon választhatja az alkalmazandó idősort, és a szimulációs számítás is grid infrastruktúra segítségével történik. Azonban ez a rendszer még inkább egy megvalósíthatósági tanulmány, mintsem egy a valóságban értékes eredményeket produkálni képes backtesting rendszer. A diplomamunkám elkészítése közben számos egyszerűsítést tettünk, melyeket egy éles rendszerben muszáj elkerülni, hogy releváns eredményeket kapjunk. Az első ilyen egyszerűsítés az idősorok kezelésében történt, ugyanis az nem mindegyik, S&P 500 indexben szereplő részvényhez volt három évre visszamenőleg idősorom, voltak részvények, melyek csak néhány hónapnyi adattal rendelkeztek. 50
Előfordulhatott
az
is,
hogy
egyes
részvények
kereskedését
egy-egy
napra
felfüggesztették, ezért ezeknél a napoknál hiányos az idősor. A jelenlegi rendszer nem naptári dátum alapján követi az idősorokat, hanem az egyes napok értékeinek sorszámot ad, így minden részvény idősora lyuk nélküli lesz, viszont nem a valóságnak megfelelő részvényárfolyam-értékek közül lehet egy adott napon választani. Szükséges tehát egy adattisztítás, mely garantálná, hogy a valóságnak megfelelő adatokon végezzük a szimulációt. Fontos ügyelni a backesting korlátainál említett survivorship bias jelenség kiküszöbölésére, azaz nem szabad, hogy csak olyan részvényeket válasszunk be a backtest elvégzéséhez, melyekről tudjuk, hogy az idősor végén is elérhetőek voltak. Ez a diplomaterv nem a pénzügyi és matematikai modellezési oldaláról közelítette meg a backtesting-et, de egy bonyolultabb, nagyobb felbontású adatsorokat kezelő szimulációs motort érdemes lenne kifejleszteni, könnyen ki lehetne cserélni a mostan alkalmazott motorra. Jó lenne tudni megadni olyan stratégiákat, melyek nem pontozzák a részvényeket, hanem eladási és vételi utasításokat adnának, így tökéletesen szimulálhatnák egy kisbefektető tevékenységét. Technikai szempontból mindenképpen a kezelőfelület fejlesztésén lenne a hangsúly, a rendszer konfigurációját (Saleve kliens konfigurációja, tanúsítvány kezelése) is jó lenne tudni grafikusan végezni. Fontos lenne, hogy a felhasználói felületről nyomon lehessen követni a beküldött feladatok állapotát, ne kelljen ehhez parancssori utasításokat kiadni. Ez a munka véleményem szerint egy jó példája a grid infrastruktúra rugalmasságának, széles körben alkalmazhatóságának bemutatására, érdemes lenne egy ipari szintű backtesting keretrendszer kifejlesztése, mert üzletileg értékes információkat biztosíthatna.
51
7 Köszönetnyilvánítás Szeretném megköszönni konzulensemnek, Kápolnai Richárdnak a diplomaterv probléma felvetését, az egész éves munkáját és segítségét, köszönöm, hogy mindig segítőkészen rendelkezésemre állt, ha technikai kérdésem adódott. Nagyon sokat jelentett, hogy témavezetőként aktívan követte a diplomaterv alakulását és észrevételeivel segítette számomra a lehető legmagasabb szintű elkészítését.
52
Irodalomjegyzék [
Portfolio.hu. (2010, december) Meddig szárnyalunk? - Technikai elemzés.
1] [Online]. http://portfolio.hu/vallalatok/technikai_elemzes/meddig_szarnyalunk_technikai_ele mzes.142358.html [
Tradetrek.com.
Technical
Trading
Strategies.
[Online].
2] http://www.tradetrek.com/education/tech_tra/tech_trading_strategy01.asp [
Terence C. Mills, "Technical Analysis and the London Stock Exchange:
3] Testing Trading Rules Using the FT30," International Journal of Financial Economics, vol. 2., pp. 319-331., 1997. [
StockCharts.com.
Gap
Trading
Strategies.
[Online].
4] http://stockcharts.com/school/doku.php?id=chart_school:trading_strategies:gap_tra ding_strategi [
Josef Lakonishok, Blake LeBaron William Brock, "Simple Technical
5] Trading Rules and the Stochastic Properties of Stock Returns," The Journal of Finance, vol. 47., no. 5., pp. 1731-1764., December 1992. [
Sean D. Campbell, "A Review of Backtesting and Backtesting Procedures,"
6] in Finance and Economics Discussion Series, Divisions of Research & Statistics and Monetary Affairs, Federal Reserve Board , Washington, D.C., 2005. [
Standard
&
Poor's.
(2010,
december)
S&P
500.
[Online].
7] http://www.standardandpoors.com/indices/sp-500/en/us/?indexId=spusa-500-usduf-p-us-l-[
Wikipedia contributors. (2010, december) Survivorship bias. [Online].
8] http://en.wikipedia.org/wiki/Survivorship_bias [
Matlaber. (2010, április) Common Back Testing Issues. [Online].
9] http://matlaber.blogspot.com/2010/04/common-back-testing-problems.html [
Center for Research in Security Prices. (2010, november) Data Descriptions
10] Guide.
[Online].
http://www.crsp.com/documentation/product/stkind/data_descriptions_guide.pdf
53
[
Darrell Jobman. (2010, augusztus) Stocks, Futures and Options Magazine.
11] [Online].
http://www.sfomag.com/Stocks_Futures_Options-
The_Early_Days_Search_for_Systematic_Trading-ar1527i112.aspx [
(2010,
december)
Tradecision
Trading
System.
[Online].
12] http://www.tradecision.com/product/trading_systems/strategies.htm [
(2010,
december)
MultiCharts.
[Online].
13] http://www.multicharts.com/portfolio-backtesting/ [
(2010, december) AmiBroker. [Online]. http://www.amibroker.com/
[
(2010,
14] december)
Portfolio.hu
Adatletöltés
rovat.
[Online].
15] http://portfolio.hu/history/adatletoltes.tdp [
(2010., december) Yahoo Finance - S&P 500 Historical prices. [Online].
16] http://finance.yahoo.com/q/hp?s=^GSPC+Historical+Prices [
(2010.,
december)
Portfolio.hu
Adat
Előfizetés.
[Online].
17] http://portfolio.hu/users/elofizetes_info.php [
EGEE Project. (2010., december) Enabling Grids for E-Science. [Online].
18] http://www.eu-egee.hu/ [
fordította: Daróczi Bertalan, Szeberényi Ágnes és Szeberényi Imre Cristy
19] Burne. (2010., december) Grid Café: Az öt nagy gondolat a Grid hátterében. [Online]. http://gridcafe.ik.bme.hu/five-big-ideas.html [
The Globus Alliance. (2010., december) The Globus Alliance homepage.
20] [Online]. www.globus.org [
Open Grid Forum. (2010., december) Open Grid Forum homepage.
21] [Online]. http://www.gridforum.org/ [
Open Grid Forum. (2006., július) The Open Grid Services Architecture,
22] Version 1.5. [Online]. http://www.ogf.org/documents/GFD.80.pdf [
EGI, European Grid Infrastructure. (2010., december) European Grid
23] Infrastructure. [Online]. http://www.egi.eu/ [
MTA KFKI RMKI. (2010, december) Hungrid Virtuális Szervezet.
24] [Online]. http://grid.kfki.hu/hungrid/ [
Microsoft Corporation. (2003., március) How CA Certificates Work.
54
25] [Online]. http://technet.microsoft.com/en-us/library/cc737264(WS.10).aspx [
Sipos Gergely. Application development concepts on gLite. [Online].
26] http://www.lpds.sztaki.hu/teaching_materials/01_Application_development_concep ts_on_EGEE.pdf [
Saleve
Project.
(2010.,
december)
Saleve
Main
Page.
[Online].
Concepts.
[Online].
27] http://saleve.iit.bme.hu/wiki/Main_Page [
Saleve
Project.
(2010.,
december)
Saleve
28] http://saleve.iit.bme.hu/wiki/Saleve_concepts [
Bence Somogyhegyi. (2010., október) How to submit simple jobs onto the
29] Grid. [Online]. http://grid.kfki.hu/twiki/bin/view/RmkiGrid/BasicUsage [
EGEE. (2006., május) JOB DESCRIPTION LANGUAGE ATTRIBUTES
30] SPECIFICATION
(submission
through
Network
Server).
[Online].
https://edms.cern.ch/file/555796/1/EGEE-JRA1-TEC-555796-JDL-Attributes-v08.pdf [
Gautam Kaul Jennifer Conrad, "An Anatomy of Trading Strategies," The
31] Review of Financial Studies, vol. 3., pp. 489-519., 1998. [
Globus Alliance. (2010, december) GT 4.0 Security: Key Concepts.
32] [Online]. http://globus.org/toolkit/docs/4.0/security/key-index.html
55
Ábrajegyzék 2.2.1. ábra A Portfolio.hu elemzésénél használt idősor ...................................... 10 2.2. ábra Kitörés árfolyamsávból. Forrás: Tradetrek.com .................................. 11 3.1. ábra A szimuláció lépései ............................................................................ 19 3.2. ábra A motor osztálydiagramja .................................................................... 21 3.3. ábra A szimuláció futása .............................................................................. 24 4.1. ábra Tanúsítványlánc Forrás: [32] ............................................................... 29 4.2. ábra X.509 tanúsítvány ................................................................................ 30 4.3 ábra: Feladatkezelés az EGEE Gridben. ....................................................... 31 4.4 ábra A paramétertér feldarabolása. Forrás: [28] ........................................... 32 4.5 ábra A szerver végrehajtja a feladatot. Forrás: [28]..................................... 33 4.6 ábra A szerver összegyűjti a feladatok eredményét. Forrás: [28] ................ 33 4.7 ábra A kliens összeállítja a végső eredményt a részeredményekből. [28] .... 33 4.8 ábra Feladatleíró ........................................................................................... 36 4.9 ábra DataRequirements blokk ....................................................................... 37 4.10 ábra Módosított feladatleíró ........................................................................ 38 5.1. ábra Rendszerterv ........................................................................................ 40 5.2. ábra Feladatleíró a Saleve kliens számára ................................................... 44 6.1. ábra Részvény idősora ................................................................................. 48 6.2. ábra Szimuláció eredménye 1. ..................................................................... 49 6.3. ábra Szimuláció eredménye 2. ..................................................................... 50
56
Függelék I.
Egy példa a felhasználó által fejlesztett stratégiára, mely a 3.3.1-ben leírtak szerint lett implementálva, és a 6. fejezetben leírt stratégiát valósítja meg:
package hu.bme.iit.sda.backtests; import hu.bme.iit.sda.api.provide.*; import hu.bme.iit.sda.exceptions.NoSuchParameterException; import java.util.ArrayList; import java.util.List; public class BacktestMovingAvg extends Backtest { @Override public double score(int day, String ticker, StockData stockData, java.util.List<ParamValue> params) { try { int windowSize = (int)ParamValue.getValueByCode("WINDOW_SIZE", params); windowSize = (day > windowSize) ? windowSize : (day - 1); double sum = 0; if (windowSize > 0 && day > 0) { for (int i = 0; i < windowSize; i++) { sum += stockData.getStocks().get(ticker).getHistory()[day - i 1].getAdjustedClose(); } double avg = sum / windowSize; double priceToday = stockData.getStocks().get(ticker).getHistory()[day].getAdjustedClose(); return (priceToday - avg) / priceToday ; } else { return 0; } } catch (NoSuchParameterException ex) { return 0; } } @Override public List<Parameter> getRequiredParams() { ArrayList<Parameter> ret = new ArrayList<Parameter>(); ret.add(new Parameter("WINDOW_SIZE", "The size of the moving average window in days", 1, 15, 1)); return ret; } }
57
II.
A szimuláció paramétereiből a paramétertér-pontjainak listáját előállító rekurzív C++ függvény (lásd: 5.1.2. bekezdés) és a szükséges típusdefiníciók:
/* A parameter structure with identical fields to the Parameter class used by the Java UI. */ struct Parameter { string code; string description; double minValue; double maxValue; double step; }; /* A single point in the parameter space, handed to the Java engine that runs the user's algorithm. */ struct ParamValue { string code; double value; }; typedef shared_ptr
> PVArrayPtr; typedef shared_ptr<ParamValue> PVPtr; /** * Subdivides recursively a parameter space defined in params into points. * A point is a vector of ParamValues. * All points in the parameter space are returned. * @param params The parameter space. * @param prevValues The dimensions of a point already determined for the current iteration of the
recursion.
* @param allValues The points of the parameter space. */
58
Folytatva az előző oldalról: void spanParams(const vector<Parameter> ¶ms, const vector<ParamValue> &prevValues, shared_ptr<list > allValues
)
{ /* If we are processing the last parameter dimension, a new ParamValue array should be returned containing the parameter values in prevValues (from the previous parameter dimensions) and a value from the last parameter dimension */ unsigned int s = prevValues.size(); unsigned int pSize = params.size(); if (s == pSize - 1) { for( int i = 0; i <= (params[s].maxValue - params[s].minValue) / params[s].step; i++) { ParamValue pv = { params[s].code, params[s].minValue + i * params[s].step }; PVArrayPtr pvs(new vector<ParamValue>()); for ( int j = 0; j < pSize - 1; j++ ) { pvs->push_back(prevValues[j]); } pvs->push_back(pv); allValues->push_back(pvs); } } else { for( int i = 0; i <= (params[s].maxValue - params[s].minValue) / params[s].step; i++) { ParamValue pv = { params[s].code, params[s].minValue + i * params[s].step }; vector<ParamValue> newValues = vector<ParamValue>(prevValues); newValues.push_back(pv); spanParams(params, newValues, allValues ); } } }
59