UPDATE
– 8< –
Nach den heldenhaften Ideen des ebenso heldenhaften Stefan twittert nun mein Portfolio wochentags um 15:00 die aktuelle Entwicklung: crashportfolio@twitter
– 8< –
Anfang der Woche habe ich mein fiktives Krisenportfolio gepostet – damit war’s plötzlich höchste Zeit, Kursentwicklungen aktuell zu halten. Zwei Stunden und ein paar Zeilen Python später ist nun alles automatisiert.
Natürlich ist die Verwaltung eines Portfolios etwas, was Yahoo!, Google und zig andere Dienste gratis anbieten. Außerdem sehe ich die Positionen ohnehin auf meinem Konto bei brokerjet, aber dennoch: Nichts macht so viel Spaß wie eine selbst gebastelte Lösung, nichts ist so flexibel verwendbar, und nichts geht abzüglich der anfänglichen Programmierzeit danach so schnell.
Erfassen
Zunächst war es wichtig, die fiktiven Investments strukturiert zu erfassen. Ich hasse zwar Tabellenkalkulation, aber CSV scheint dennoch ein brauchbares Austauschformat zu sein. Kurzum: Name, Einstiegskurs, Menge, Datum, sowie eine ID (=Symbol) und ein Pointer auf den jeweiligen data provider sind wichtig.
Commodity ETF,etf/RBS_Market_Access_Jim_Rogers_International_Commodity_Index_ETF,26.50,900,08.07.2012,finanzen.net Altria,PHM7.F,28.51,300,08.07.2012,yahoo BP,BPE5.DE,5.40,1400,08.07.2012,yahoo Fuchs Petrolub,FPE.DE,40.80,180,08.07.2012,yahoo Nestle,NESR.DE,48.64,150,08.07.2012,yahoo Novo Nordisk,NOVA.DE,118.32,65,08.07.2012,yahoo Pfizer,PFE.DE,18.21,400,08.07.2012,yahoo Shoprite,HY7.F,15.64,480,08.07.2012,yahoo Umicore,UMI.BR,35.32,200,08.07.2012,yahoo
Absaugen
Das CSV-File wird mittels Python eingelesen, die Klasse Paper wird pro Position instanziiert. Yahoo! bietet ein unerschöpfliches API für Aktienkurse, die Python-Library ystockquote macht das Ganze sehr einfach zu verwenden.
class Paper():
"""Any bond, etf or stock"""
def __init__(self, data_provider, name, symbol, quant, purchase_price, date):
self.data_provider = data_provider
self.name = name
self.symbol = symbol
self.quant = int(quant)
self.purchase_price = float(purchase_price)
self.date = date
self._price = None
def __repr__(self):
return "%20s %7.2f %7.2f %7.2f%% %5d" % (self.name, self.purchase_price, self.price, self.change, self.totalgain)
@property
def price(self):
if not self._price:
if self.data_provider == 'yahoo':
self._price = float(ystockquote.get_price(self.symbol))
elif self.data_provider == 'finanzen.net':
self._price = FinanzenNetParser.get_price(self.symbol)
else:
raise NoDataProvider
return self._price
@property
def change(self):
return ((self.price / self.purchase_price ) - 1) * 100
@property
def totalgain(self):
return self.change / 100.0 * (self.purchase_price * self.quant)
Für den Kurs des ETF benötige ich einen HTML-Parser, da Yahoo! dessen Kurs nicht anbietet. Mit BeautifulSoup habe ich einen neuen Lieblings-Parser ins Herz geschlossen – in Kürze war also der Kurs von finanzen.net eingebunden. (Python-Tipp: Webscraping with Python and beautifulsoup)
Natürlich muss ich das auch noch für die Goldmünzen und die Uhr machen, die sich ebenso in meinem Portfolio befinden.
class FinanzenNetParser():
@classmethod
def get_price(self, path):
"""Ok, tricky: price is the first th in a table.header_height"""
url = 'http://www.finanzen.net/%s' % (path,)
content = urllib2.urlopen(url).read()
soup = BeautifulSoup(content)
for table in soup.find_all('table'):
if table.get('class') == ['header_height']:
return float(table.th.text.replace('EUR','').replace(',','.'))
Ausgeben
Der Output ist derzeit noch etwas mager, mit Jinja2 sind die Daten aber schnell in HTML gegossen und auf meinem Mobiltelefon verfügbar.
name purchase current change total
Commodity ETF 26.50 26.57 0.26% 62
Altria 28.51 28.79 0.98% 84
BP 5.40 5.48 1.50% 113
Fuchs Petrolub 40.80 40.65 -0.37% -26
Nestle 48.64 48.86 0.45% 32
Novo Nordisk 118.32 120.15 1.55% 118
Pfizer 18.21 18.52 1.67% 121
Shoprite 15.64 15.89 1.62% 121
Umicore 35.32 34.65 -1.91% -134





About