Python Panoráma 8: Web alapú pénzügyi ábrák készítése Bokeh-val11 perc olvasás

Adatvizualizáció és folyamatos elérhetőség. Ha ezt a két dolgot ötvözzük, akkor igencsak hasznos eredményekre juthatunk. Egy elemzés során mindig fontos szempont az adatok megfelelő ábrázolása. Fontos szerepe van, hiszen azt a célt szolgálja, hogy az elemzés lényegét egy másik, kívülálló fél is könnyedén meg tudja ragadni. Továbbá az is jelentős szempont, hogy ez az ábra akármikor rendelkezésre álljon, ezzel áthidalva az olyan kisebb technikai problémákat, amelyek lassítják az adott munkafolyamatot.

CÉL

Akik végigkövették a Python Panoráma sorozat részeit, azok észrevehették, hogy nagyon sok témakört érintettünk. Ebben a részben egyesíteni fogunk pár ilyen megtanult elemet például a Flask-et, Heroku-t és a Pandas-t is. Természetesen ezek mellett azért ismét bővíteni fogjuk tudásunkat. Főleg a Bokeh és a Pandas együttes használatát fogjuk jobban megismerni. Ha egyébként a hatodik részben a mozgásérzékelő továbfejlesztésénél alkalmazott adatvizuálizációs szekció nem volt teljesen érthető, akkor most valószínűleg tisztulni fog a kép.

Célunk a nyolcadik részben, hogy a pandas segítségével adatokat töltsünk le egy vállalat részvényeivel kapcsolatban, ezeket a Bokeh-val megfelelően ábrázoljuk, végül pedig, hogy azt egy weboldal formájában prezentáljuk a nagy világnak. Ez a rész erőteljesen támaszkodik a negyedik részben bemutatott ismeretekre, így mindképpen ajánlom annak áttekintését.

MEGVALÓSÍTÁS

Ezen alkalmazás elkészítése során is ajánlom a Jupyter Notebook használatát, mert kódunkat sokkal hatékonyabban tudjuk egyszerre ellenőrizni és szerkeszteni. Folyamatunk első lépéseként írjuk meg azt a python scriptet, amely adatokat tölt le és ábrázolja is azokat.

Ahogy az már szinte rutinból jön, kezdésként telepítenünk kell minden olyan package-et, amelyet használni szeretnénk a programunkban. A szükséges package-ek: bokeh, pandas, pandas_datareader, fix_yahoo_finance. Ezek telepítése után importáljuk is őket a scriptünkbe. A bokeh-nak három moduljára lesz szükségünk. Ebből az első a “bokeh.plotting”, amely által magát az ábrát fogjuk tudni létrehozni a figure, show és output_file class-ok segítségével. A második a “bokeh.embed”, amely a weboldalba történő beágyazáshoz lesz majd szükséges. Az utolsó pedig a “bokeh.resources”, amely a weboldalunkon megjelenítendő ábra dinamikusságához (a bokeh verziófrissítései) kell.

A package-ek importálása után folytassuk az adatokat letöltésével. Ehhez a yahoo-t fogjuk használni. A “data.get_data_yahoo” method-nek köszönhetően egyszerűen tudunk létrehozni egy táblát, amely tartalmazza a lekért árfolyamadatokat. A method csupán a vállalat tőzsdei szimbólumát, illetve a vizsgálni kívánt időszak elejét és végét meghatározó dátumokat igényli.

from pandas_datareader import data
import datetime
import fix_yahoo_finance as yf 
from bokeh.plotting import figure, show, output_file
from bokeh.embed import components
from bokeh.resources import CDN

start=datetime.datetime(2016,1,3)
end=datetime.datetime(2017,1,3)
yf.pdr_override() 
df=data.get_data_yahoo(tickers="AAPL", start=start, end=end)
print(df)

Ha ezzel megvagyunk, akkor ellenőrizzük le, hogy sikerült-e az adatokat jól letölteni. Ha sikerült, akkor valami ehhez hasonló táblázatot kell kapnunk:

Most, hogy megvan a táblázatunk kezdjünk bele az adatok ábrázolásába. Ezt bokeh-val fogjuk kivitelezni. Első lépésben hozzuk létre magát az ábra objektumot a “figure” segítségével, nevezzük el azt “p”-nek, majd adjuk meg a paramétereit (x-tengely formátuma, szélesség, magasság, cím, méretezés). Mivel egy japán gyertya ábrát szeretnénk készíteni, így több úgynevezett “glyph”-re is szükségünk lesz.

Az ábrát kétféleképpen lehet elkészíteni. Használhatunk téglalapokat vagy sávokat, ezeket a napi nyitó és záró árak határozzák meg. Mi most a téglalapos módszert nézzük meg. Téglalapokat a bokeh-ban a “p.rect” segítségével adhatunk hozzá. Argumentumként pedig, az x és y koordinátákat, a szélességet és magasságot, a kitöltés és a körvonal színét kell megadnunk.

Arra viszont figyelnünk kell, hogy az árfolyamváltozást a kitöltés színével szeretnénk jelezni. Ezt többféleképpen is megoldhatjuk. Az egyik módszer, hogy végig iterálunk a téglalapokon és egy függvényen alapján határozzuk meg az adott téglalap színét. A másik módszer, hogy két külön téglalap csoportot hozunk létre és az egyik az árfolyamnövekedéseket fogja ábrázolni, a másik pedig az árfolyamcsökkenéseket. Azt, hogy tábla melyik sora melyik csoportba kerül egy szűréssel oldhatjuk meg. Mindkét módszerhez ki kell egészítenünk a táblázatunkat egy státusz, átlag és egy magasság oszloppal, valamint a téglalapok szélességére (12 órás kereskedés) is érdemes egy változót bevezetni, ugyanis azt millimásodpercben kell megadnunk.

# Status Column
def status(c,o):
    if c>o:
        value="Increase"
    elif c<o:
        value="Decrease"
    else:
        value="Equal"
    return value
df["Status"]=[status(c,o) for c, o in zip(df.Close,df.Open)]

# Average
df["Avg"]=(df.Close+df.Open)/2

#Height
df["Height"]=abs(df.Close-df.Open)

A két módszer pedig:

1. for loop-al

p=figure(x_axis_type="datetime",width=1000, height=400, title="Candlestick Chart", sizing_mode="stretch_both")

hours_12=12*60*60*1000

def color_find():
    if df.Status[i]=="Increase":
        return "green"
    else:
        return "red"
    
for i in range(0,len(df)):     
    p.rect(df.index[i], df.Avg[i], hours_12,
    df.Height[i],fill_color=color_find(),line_color="black")

2. Két téglalap csoporttal

p=figure(x_axis_type="datetime",width=1000, height=400, title="Candlestick Chart", sizing_mode="stretch_both")

hours_12=12*60*60*1000

p.rect(df.index[df.Status=="Increase"],df.Avg[df.Status=="Increase"], hours_12,
       df.Height[df.Status=="Increase"],fill_color="green",line_color="black")

p.rect(df.index[df.Status=="Decrease"],df.Avg[df.Status=="Decrease"], hours_12,
       df.Height[df.Status=="Decrease"],fill_color="red",line_color="black")

Az ábra ellenőrzéséhez ideiglenesen írjuk a kód végére a következőket és futtassuk le:

output_file("CandleStick.html")
show(p)

Ha stimmelnek a téglalapok, akkor már csak a háttérben látszódó segédvonalakat kell eltávolítanunk és azokat az egyeneseket berajzolnunk, amelyek a napi maximum és minimum árból adódnak.

p.grid.grid_line_alpha=0
p.segment(df.index,df.High,df.index,df.Low,line_color="black")

Ezzel az ábránk el is készült. Viszont a kódunkat még ki kell egészítenünk annak érdekében, hogy azt egy weboldalba tudjuk integrálni. Ehhez szükséges a “bokeh.embed” “components” függvénye, amely egy két elemű tuple-t ad eredményül. Az első elem az ábrához tartozó javascript-et, míg a második pedig a html-t tartalmazza.

Ezek azért kellenek, mert így fogjuk tudni, beilleszteni a weboldalunk forráskódjába az ábrát. Azonban a “components” mellett a “CDN” is alkalmaznunk kell. Ez az ábránkhoz tartozó javascript és css fájlra mutató aktuális linkeket adja meg, így ha mondjuk a bokeh-t egy újabb verziójára frissítjük, akkor az a weboldalon lévő ábránkat nem fogja elrontani.

Ezzel a python scriptünk kész is van és valahogy így kell végül kinéznie:

from pandas_datareader import data
import datetime
import fix_yahoo_finance as yf
from bokeh.plotting import figure, show, output_file
from bokeh.embed import components
from bokeh.resources import CDN

start=datetime.datetime(2016,1,3)
end=datetime.datetime(2017,1,3)
yf.pdr_override()
df=data.get_data_yahoo(tickers="AAPL", start=start, end=end)

def status(c,o):
    if c>o:
        value="Increase"
    elif c<o:
        value="Decrease"
    else:
        value="Equal"
    return value

df["Status"]=[status(c,o) for c, o in zip(df.Close,df.Open)]

df["Avg"]=(df.Close+df.Open)/2

df["Height"]=abs(df.Close-df.Open)

p=figure(x_axis_type="datetime",width=1000, height=400, title="Candlestick Chart", sizing_mode="stretch_both")

p.grid.grid_line_alpha=0

hours_12=12*60*60*1000

p.segment(df.index,df.High,df.index,df.Low,line_color="black")

p.rect(df.index[df.Status=="Increase"],df.Avg[df.Status=="Increase"], hours_12,
       df.Height[df.Status=="Increase"],fill_color="green",line_color="black")

p.rect(df.index[df.Status=="Decrease"],df.Avg[df.Status=="Decrease"], hours_12,
       df.Height[df.Status=="Decrease"],fill_color="red",line_color="black")

script, div1 = components(p)

cdn_js=CDN.js_files
cdn_css=CDN.css_files

Most pedig nézzük meg, hogyan is tudnánk az ábránkat egy weboldalon megjeleníteni. A negyedik részhez hasonlóan itt is azzal kell kezdenünk, hogy létrehozunk egy virtuális környezetet a Python-unknak. Ezután egy mappában elrendezzük a szükséges fájlokat, többek között a Flask alkalmazást tartalmazó python scriptet, valamint a html és css fájlokat (templates és static mappák), továbbá a három “nevezetes” fájlunkat is (Procfile, requirements.txt, runtime.txt). A requirements.txt-nél figyeljünk, hogy minden olyan alkalmazást telepítsünk a virtuális környezetünkbe, amely szükséges az ábra és a weboldal felállításához pl.:pandas, bokeh, gunicorn stb.

Készítsünk el egy külön az ábrához tartozó html fájlt (plot.html) és ebbe illesszük be a “script” és “div1” változókban tárolt elemeket a CDN-es változókkal együtt. Ehhez a művelethez Jinja helyőrzőket kell alkalmaznunk pl.: {{script | safe}}. Ezután nyissuk meg a Flask applikációnkat tartalmazó scriptet és adjunk hozzá a webolalunkhoz egy új oldalt, majd definiáljuk az ahhoz tartozó függvényt. A definícióba az ábránkat tartalmazó scriptet másoljuk és a végére a következő sort illesszük:

return render_template("plot.html", script=script,
div1=div1, cdn_js=cdn_js, cdn_css=cdn_css)

Ez fogja végül visszaadni az URL címhez tartozó html fájlt és az abban elhelyezett helyőrzők értékét.
Ha ezzel megvagyunk, akkor hozzunk létre egy új Heroku app-et és a Git, illetve Heroku Toolbelt segítségével töltsük fel a webalkalmazásunkat a heroku szerverekre. Ennek a folyamatát részletesebben áttekintheted a negyedik cikkben.

TOVÁBBFEJLESZTÉS ÉS ÜZLETI FELHASZNÁLÁS

Alkalmazásunk továbbfejlesztésként kibővíthetjük azt más típusú ábrákkal, adhatunk az ábrákhoz widget-eket vagy még interaktívabbá tehetjük azokat mondjuk popup-ok segítségével. Mint webes alkalmazás, előrelépést jelentene az is ha dinamikussá tudnánk tenni az ábránkat és így az folyamatosan frissülni tudna.

Felhasználás szempontjából leginkább az üzleti elemzéseket említeném meg. Itt ugyanis sokszor jól jöhet, ha valamilyen modell vagy projekt köztes állapotainak eredményét egy weboldalon elhelyezett ábrával tudjunk bemutatni másoknak.

Én a közeljövőben egy ehhez hasonló webalkalmazást szeretnék kibővíteni egy adatbázissal egy SmartHome automatizációs projekt keretében azért, hogy a szenzorok által generált adatokat egy-egy ábrán tudjam demonstrálni, majd azokat elemezni. A következő részben egy ilyesmi adatbázishoz kapcsolt weboldalt fogunk elkészíteni.
A cikkhez tartozó fájlok innen érhetők el.

Köszönöm, hogy végigolvastad a posztomat és ha érdekesnek találtad, akkor nézz bele a sorozat többi részébe is.

Gulácsy Dominik

About Dominik Gulácsy

Sophomore at Corvinus University of Budapest studying International Business who is motivated to use relevant academic knowledge to solve problems through optimisation. Dedicated to fully support the development of new business solutions in close collaboration with team members by IoT and data science applications. Gained experience in SQL and VBA but looking forward to learning more. A keen supporter of the circular economy.

View all posts by Dominik Gulácsy →

Leave a Reply

Your email address will not be published. Required fields are marked *