Aktien in der Watchlist speichern | Python GUI mit Kivy

In den vergangenen Artikeln haben wir Aktien zur Watchlist zugefügt und auch wieder entfernt.
Wichtig ist natürlich auch, dass wir die Watchlist speichern!
Wir wollen ja nicht jedes Mal alle Aktien neu eingeben müssen.
Also lass uns gleich mal loslegen.

Kivy Serie

Aktien in der Watchlist speichern

Um Daten zu speichern, gibt uns Kivy direkt ein Mittel an die Hand.
Mit Storage gibt Kivy uns einfachen Zugang zu einem einfachen Speicher. Hier kann unsere App Daten ablegen, sie wieder laden und bei Bedarf löschen.

Für unsere App habe ich mich für einen Json Speicher entschieden. Json ist ein gängiges Format und arbeitet super mit Python zusammen.
Damit kann ich es auch außerhalb von unserer App verwenden, wenn ich das möchte.

Um einen Speicher (Storage) zu erzeugen, erzeuge ich lediglich eine neue Instanz des jeweiligen Storage:

store = JsonStore('watchlist.json')

Bei der Erzeugung übergeben wir den Namen für unseren Speicher.
Ich habe hier einfach watchlist.json gewählt.
Zum einen, weil es eine Json Datei ist und zum anderen, weil sie unsere Watchlist Daten vorhalten soll.

Einträge fügen wir in der Funktion add_ticker_row hinzu.
Hier wissen wir also, dass die Abfrage der Daten funktioniert hat und ein Eintrag in die Watchlist gespeichert werden soll.
Der perfekte Moment für unseren Storage.

Dafür fügen wir am Ende der Funktion einfach die Initialisierung des Storage an und legen das aktuelle Symbol mit rein:

def add_ticker_row(self, symbol, name, price, *args):
    self.message.text = ''
    ticker = Label(text=symbol, size_hint_x=0.2)
    self.stock_list.add_widget(ticker)
    name = Label(text=name, size_hint_x=0.4)
    self.stock_list.add_widget(name)
    price = Label(text=price, size_hint_x=0.2)
    self.stock_list.add_widget(price)
    delete = Button(text='Entfernen', size_hint_x=0.2)
    delete.bind(on_press=self.remove_ticker_row)
    self.stock_list.add_widget(delete)

    store = JsonStore('watchlist.json')
    store.put(symbol)

Über die .put() Funktion wird zuerst ein Schlüssel übergeben. Anschließend können als Schlüssel-Werte Paare weitere Werte angegeben werden, die dem Schlüssel zugeordnet werden sollen.
Uns reicht hier der Schlüssel. Wir brauchen ja schließlich nur das Ticker Symbol der Aktie.
Solltest du mal mehr Werte brauchen, kannst du hier einfach nachlesen: Kivy Storage.

Wenn du jetzt ein Ticker Symbol zufügst, wird es automatisch in deiner Watchlist gespeichert.
Damit erhältst du eine Datei an dem von dir angegebenen Pfad.
In unserem Beispiel hier ist es die watchlist.json direkt im Pfad unseres Pythonskripts.

Anmerkung:
Ich habe hier den Parameter ticker zu symbol umbenannt, um eine Namensüberschneidung mit dem Label zu verhindern.

Der Inhalt der watchlist.json ist einfaches Json Format:

{
  "RWE.DE": {},
  "MSF.DE": {}
}

Aktien aus der Watchlist laden

Die Aktien werden also jetzt nach dem Zufügen in der Watchlist gespeichert.
Der nächste Schritt ist also, sie auch wieder zu laden, wenn die App startet.

Geladen werden sollen die Aktien im StockView. Hier wird immerhin unsere Watchlist angezeigt.
Die __init__ Funktion konfiguriert den View und bereitet ihn zur Anzeige vor.
Also ist das der perfekte Ort, um auch unsere Watchlist zu laden.

Wenn du den Storage in der Hand hast, können die Keys einfach in einer Schleife iteriert werden.
Und mehr als die Keys brauchen wir ja nicht.
Also lass uns das an das Ende unserer __init__ Funktion für den StockView anfügen:

class StockView(GridLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.cols = 1
        ...
        self.stock_add.add_widget(self.ticker_add)

        store = JsonStore('watchlist.json')
        for item in store:
            self.query_stock_data(item)

Das Zufügen einer Aktie zur Watchlist ist ja bereits in eine eigene Funktion ausgelagert.
Dann können wir die direkt verwenden: query_stock_data

Das einzige Problem ist, dass sie aktuell noch kein Symbol entgegennimmt. Sie liest es selbst aus dem ticker_input Feld aus.
Das heißt, wir müssen die Funktion jetzt auch noch anpassen.

Wird eine Aktie über den Button in der App zugefügt, soll alles so bleiben wie es ist.
Wird sie aber durch das laden des Storage zugefügt, müssen wir das Symbol übergeben können.
Das schreit nach einem optionalen Parameter:

def query_stock_data(self, symbol=None):
    symbol = symbol or self.ticker_input.text.strip()
    ....

Das war’s.
Damit können wir ein Symbol übergeben, wenn wir den Storage laden.
Übergeben wir nichts, ist symbol=None.
Mit dem or sagen wir “belege die Variable symbol mit dem Wert aus symbol. Ist der None, dann nimm den Wert aus self.ticker_input.text.strip()”
Und schon kümmert sich Python um alles Weitere.

Doppelte Einträge vermeiden

Als kleinen Bonus können wir hier auch direkt die Funktion erweitern, um doppelte Einträge in der Watchlist zu verhindern.
Beim Speichern passiert das schon automatisch, da die Aktien Ticker Symbole als Schlüssel genutzt werden.
Schlüssel dürfen immer nur einmal existieren.

Wenn wir jetzt noch in der App das Zufügen verhindern wollen, können wir auch hier unseren Storage zur Hilfe nehmen.
Ist also der Parameter symbol=None, dann kommt der Aufruf aus der App.
Wenn das Aktien Ticker Symbol aus self.ticker_input.text.strip() schon in dem Storage vorhanden ist, dann wäre es ein Duplikat.
Also: “Wenn symbol=None und self.ticker_input.text.strip() schon im Storage, dann gib eine Meldung aus. Andernfalls frag die Daten ab und füge zur Watchlist hinzu”.

Und genau so können wir das auch im Code abbilden:

def query_stock_data(self, symbol=None):
    # symbol = symbol or self.ticker_input.text.strip()

    store = JsonStore('watchlist.json')
    if not symbol and self.ticker_input.text.strip().upper() in store:
        self.message.text = 'Das Symbol ist bereits in der Liste.'
    else:
        symbol = symbol or self.ticker_input.text.strip()
        stock = yfinance.Ticker(ticker=symbol)
        data = stock.info
        if 'regularMarketPrice' in data and data.get('regularMarketPrice') is not None:
            price = f'{data.get("regularMarketPrice"):.2f} {data.get("currency")}'
            Clock.schedule_once(partial(self.add_ticker_row, data.get('symbol'), data.get('longName'), price), 0.5)
        else:
            self.message.text = f'Für das angegebene Symbol {symbol} gab es kein Ergebnis.'

Fügen wir jetzt ein Aktien Ticker Symbol zur Watchlist hinzu, wird erst geprüft, ob es bereits im Storage existiert.
Wenn ja, geben wir einfach nur eine Nachricht aus und machen nichts weiter.
Wenn nein, belegen wir wieder die Variable symbol mit dem Wert aus dem Parameter, oder dem Eingabefeld.
Anschließend läuft die Logik ab, wie zuvor.

Aktien aus der Watchlist löschen

Als letzter Schritt fehlt noch, dass wir auch Aktien aus unserer Watchlist wieder herausbekommen.
In der App funktioniert das bereits über den Entfernen-Button.
Dabei muss jetzt aber auch noch unser watchlist.json angepasst werden.

Natürlich liefert der Kivy Storage auch dafür die passende Funktion mit: delete
An delete kann einfach ein Schlüssel übergeben werden, der aus dem Storage entfernt werden soll.

Alles, was wir tun müssen ist, also das delete an das Ende unserer remove_ticker_row Funktion zu hängen.
Und schon wird der jeweilige Eintrag aus dem Storage entfernt:

def remove_ticker_row(self, symbol, *args):
    row = [element for element in args[0].parent.children if element.y == args[0].y]

    for element in row:
        self.stock_list.remove_widget(element)

    store = JsonStore('watchlist.json')
    store.delete(symbol)

Das Symbol bekommen wir, in dem wir es einfach wieder als Parameter zur Funktion hinzufügen.
Und schon kann es aus dem Parameter an das delete übergeben und somit aus dem Kivy Storage gelöscht werden.

Bleibt nur noch ein Problem: Wie übergeben wir den Parameter?
Immerhin ist der Aufruf der Funktion über einen Button gebunden.
Das heißt, wir haben hier nur eine Referenz zu der Funktion und können nicht einfach einen Parameter übergeben… Oder?

Doch.
Können wir schon.
Haben wir vorher schon gemacht.
Als wir eine Funktion mit Clock für eine spätere Ausführung eingeplant haben.
Dabei ist partial unser Retter in der Not.

In der Funktion add_ticker_row wird die Funktion an den Entfernen-Button gebunden.
Hier kannst du auch einfach mit partial die Funktion zusammen mit dem Parameter übergeben:

def add_ticker_row(self, symbol, name, price, *args):
    self.message.text = ''
    ticker = Label(text=symbol, size_hint_x=0.2)
    self.stock_list.add_widget(ticker)
    name = Label(text=name, size_hint_x=0.4)
    self.stock_list.add_widget(name)
    price = Label(text=price, size_hint_x=0.2)
    self.stock_list.add_widget(price)
    delete = Button(text='Entfernen', size_hint_x=0.2)
    delete.bind(on_press=partial(self.remove_ticker_row, symbol))
    self.stock_list.add_widget(delete)

    store = JsonStore('watchlist.json')
    store.put(symbol)

Fazit

Das war alles.
Mit Kivys Storage lassen sich super einfach und schnell Daten unserer App speichern und auch wieder laden.

Über JsonStore(<Dateiname>) lässt sich direkt eine Datei erzeugen.
Mit put und delete lassen sich Werte zufügen und auch wieder entfernen.
Einfacher kann es kaum sein.

Du hast noch Fragen?
Schau gerne im Discord vorbei!
Hier tümmeln sich Anfänger und Fortgeschrittene, die sich gerne bei Ihren Programmen unterstützen.

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Scroll to Top
ANFORDERN
Anfordern
Bereit zum Ausdrucken | Mit Erklärungen
IMMER ZUR HAND
ANFORDERN
Anfordern
Bereit zum Ausdrucken | Mit Erklärungen
IMMER ZUR HAND
Trag dich schnell ein und bekomme Zugang zum Download!
Gib mir den Download!