def get(self, request, *args, **kwargs): """ Hier werden alle benötigten Daten für das Konfigurieren einer Simulation geholt. Dazu gehören alle verfügbaren Strategien und alle verfügbaren finanziellen Instrumente, auf denen eine Simulation laufen kann. Diese werden an das Template über den Context weitergegeben. Die getroffene Wahl wird über JavaScript in das entsprechende Formular Feld geschrieben """ Simulation.objects.all().delete() # Alle erstellten Objekte löschen. Diese werden temporär erstellt um verlustfreies Anzeigen von Daten zu garantieren self.object = None # CreateView braucht irgendein Object, None ist dabei ein valider Wert context = super().get_context_data(**kwargs) # Hier werden alle Strategie-Daten bezogen. serverAntwort = datenAnBackendSenden( hauptPfad = "strategie/", unterPfad = "getalle", daten = { "benutzer_id" : request.user.username, } ) # Wenn Fehler enthalten, auf FehlerSeite weiterleiten, ansonsten Strategie Daten im Context speichern. if(allgemeineFehlerPruefung(serverAntwort,request)): return redirect(reverse('simulation:simulation-fehler')) context['strategien'] = serverAntwort["strategien"] # ------------------------ # Hier werden alle ISIN-Daten bezogen. serverAntwort = datenAnBackendSenden( hauptPfad = "isin/", unterPfad = "getalle", daten = { "benutzer_id": request.user.username, } ) if(allgemeineFehlerPruefung(serverAntwort,self.request)): return redirect(reverse('simulation:simulation-fehler')) alleIsins = [] """ Die ISINs können Indizes und Währungen enthalten. Indices können anhand zwei verschiedener Attribute (ist_index == True und einheit == "Punkte") identifiziert werden Währungen können anhand der Einheit identifiziert werden (einheit == "undefiniert") Alle ISINs die nicht diese Attribute haben, werden in eine separate Liste gespeichert und schließlich im Context gespeichert """ for isin in serverAntwort["isins"]: if(not isin["ist_index"] and isin["einheit"] != "Punkte" and isin["einheit"] != "undefiniert"): alleIsins.append(isin) serverAntwort["isins"] = alleIsins context['isins'] = serverAntwort["isins"] # ------------------------ return self.render_to_response(context)
def get(self, request, *args, **kwargs): """ Holt alle verfügbaren Regeln für die Darstellung. Hier wird die get_context_data-Funktion der CreateView-Klasse überschrieben. Es wird mit datenAnBackendSenden versucht die Daten zu holen. Auf die dabei potentiell entstandenen Fehler wird in allgemeineFehlerPruefung geprüft. Bei vorhandenen Fehlern wird von der Funktion ein True zurückgegeben was zu einem Redirect auf die FehlerView führt. Bei False wird die serverAntwort im Context gespeichert, um eine Darstellung der Regeln zu ermöglichen""" serverAntwort = datenAnBackendSenden(hauptPfad="regel/", unterPfad="getalle", daten={ "benutzer_id": self.request.user.username, }) if (allgemeineFehlerPruefung(serverAntwort, self.request)): return redirect(reverse("strategie:strategie-fehler")) self.object = Strategie() context = self.get_context_data(object=self.object) context["regeln"] = serverAntwort["regeln"] context["appName"] = appName return self.render_to_response(context)
def form_valid(self, form): """ Hier werden die Eingabedaten des Nutzers an das Backend gesendet. Wenn dabei Fehler entstanden sind, wird auf die Fehlerseite weitergeleitet. Ansonsten wird mit dem return von super.form_valid automatisch ein Simulations-Objekt erstellt, get_absolute_url des Objekts aufgerufen und somit auf die Simulations-Ergebnis-Ansicht weitergeleitet. """ simulationsDaten = datenAnBackendSenden( hauptPfad = globalerHauptPfad, unterPfad = "", daten = { "benutzer_id" : self.request.user.username, "strategie_id" : int(form.cleaned_data["strategie"]), "isin" : form.cleaned_data["isin"], "start_kapital" : int(form.cleaned_data["startkapital"]), "start_datum" : str(form.cleaned_data["von_datum"]), "end_datum" : str(form.cleaned_data["bis_datum"]) } ) if(allgemeineFehlerPruefung(simulationsDaten, self.request)): return redirect(reverse('simulation:simulation-fehler')) else: self.request.session["simulationsDaten"] = simulationsDaten return super().form_valid(form)
def pruefeObEigeneSkala(ID, callerSelf): """ Funktion zum Prüfen ob ein Indikator mit der angegebenen ID eine eigene Skala hat. Hierbei werden die Indikatordaten geholt und, wenn kein Fehler aufgetreten ist, der Wert für eigene_skala zurückgegeben """ serverAntwort = datenAnBackendSenden(hauptPfad="indikator/", unterPfad="get", daten={ "id": int(ID), "benutzer_id": callerSelf.request.user.username, }) if (allgemeineFehlerPruefung(serverAntwort, callerSelf.request)): return redirect(reverse('simulation:simulation-fehler')) return serverAntwort["indikator"]["eigene_skala"]
def get_context_data(self, *args, **kwargs): """ Holt die Daten aller Regeln. Die Daten der verwendeten Regel werden in eine eigene Liste gespeichert. """ context = super().get_context_data(**kwargs) # Daten an Backend senden. serverAntwort = datenAnBackendSenden( hauptPfad="regel/", unterPfad="getalle", daten={"benutzer_id": self.request.user.username}) # ServerAntwort auf Fehler prüfen. Bei gefundenen Fehler auf FehlerSeite leiten. if (allgemeineFehlerPruefung(serverAntwort, self.request)): return redirect(reverse("strategie:strategie-fehler")) verwendeteRegelListe = [] # Liste mit verwendeten Regeln erstellen. for verwendeteRegel in self.request.session["verwendete-regeln"]: for regel in serverAntwort["regeln"]: if (regel["id"] == verwendeteRegel): verwendeteRegelListe.append(regel) for i in verwendeteRegelListe: print(i["id"]) # Alle Regeln im Context speichern context["regeln"] = serverAntwort["regeln"] # Alle verwendeten Regeln im Context speichern context["verwendeteRegeln"] = verwendeteRegelListe # Den bearbeitbar-Wert in Context speichern. Wichtig für DetailAnsicht context["bearbeitbar"] = self.request.session["bearbeitbar"] return context
def get(self, request): """ Diese Funktion holt sich alle Daten die benötigt werden für das Darstellen der Simulations-Ergebnisse. Dazu gehören die Aktienkurs Daten der zum simulieren verwendeten ISIN und die Simulationsergebnisse. """ if ("konfigDaten" not in request.session): request.session[ "fehler"] = "Keine Simulationsdaten vorhanden. Versuchen Sie es nochmal..." return redirect(reverse('simulation:simulation-fehler')) # Zuletzt erstelltes Objekt holen # Prüfen ob es existiert, wenn nicht, auf FehlerSeite weiterleiten und entsprechende Fehlermeldung in session speichern. konfigDaten = request.session["konfigDaten"] strategie_id = konfigDaten["strategie_id"] isin = konfigDaten["isin"] start_kapital = konfigDaten["start_kapital"] start_datum = konfigDaten["start_datum"] end_datum = konfigDaten["end_datum"] # Hier werden die Simulation-Konfigurations-Daten an das Backend geschickt. simulationsDaten = datenAnBackendSenden(hauptPfad=globalerHauptPfad, unterPfad="", daten={ "benutzer_id": self.request.user.username, "strategie_id": strategie_id, "isin": isin, "start_kapital": start_kapital, "start_datum": start_datum, "end_datum": end_datum, }) # Bei Fehlern auf Fehlerseite weiterleiten if (allgemeineFehlerPruefung(simulationsDaten, request)): return redirect(reverse('simulation:simulation-fehler')) #------------------ self.request.session[ "simulationsDaten"] = simulationsDaten # Simulationsdaten in Session speichern um für die Funktion downloadCSV zugänglich zu machen #Von- und Bis-Datum in passendes Format TT.MM.JJJJ umwandeln vonDatumAnzeigeFormat = datetime.strptime( start_datum, '%Y-%m-%d').strftime('%d.%m.%Y') bisDatumAnzeigeFormat = datetime.strptime( end_datum, '%Y-%m-%d').strftime('%d.%m.%Y') # AnzeigeDaten Dict für Template zusammenbauen anzeigeDaten = { "strategie_id": strategie_id, "strategie_name": simulationsDaten["strategie"]["name"], "isin": simulationsDaten["wertpapier"]["isin"], "name": simulationsDaten["wertpapier"]["name"], "start_kapital": start_kapital, "start_datum": start_datum, "end_datum": end_datum, "statistik": simulationsDaten["strategie_statistik"], } # Statistischen Werte auf 3 Nachkommestellen kürzen anzeigeDaten["statistik"]["performance_gesamt"] = '%.3f' % (float( anzeigeDaten["statistik"]["performance_gesamt"])) anzeigeDaten["statistik"]["performance_pro_jahr"] = '%.3f' % (float( anzeigeDaten["statistik"]["performance_pro_jahr"])) anzeigeDaten["statistik"]["hoch_gesamt"] = '%.3f' % (float( anzeigeDaten["statistik"]["hoch_gesamt"])) anzeigeDaten["statistik"]["tief_gesamt"] = '%.3f' % (float( anzeigeDaten["statistik"]["tief_gesamt"])) anzeigeDaten["statistik"]["maximum_drawdown"] = '%.3f' % (float( anzeigeDaten["statistik"]["maximum_drawdown"])) # Alle Koordinatensysteme erstellen p1 = figure( # p1 ist Koordinatensystem mit Aktienkurs als Candlesticks plot_width=1000, plot_height=700, x_axis_type="datetime", tools="pan, wheel_zoom, box_zoom, reset, save" # verfügbaren Tools ) p2 = figure( # p2 ist Koordinatensystem mit Aktienkurs als Linie plot_width=1000, plot_height=700, x_axis_type="datetime", tools="pan, wheel_zoom, box_zoom, reset, save", x_range=p1. x_range, # Verschiebungen entlang der X-Achse von p1 übernehmen y_range=p1. y_range # Verschiebungen entlang der Y-Achse von p1 übernehmen ) p3 = figure( # p3 ist Koordinatensystem für Performance-Entwicklung plot_width=1000, plot_height=700, x_axis_type="datetime", tools="pan, wheel_zoom, box_zoom, reset, save", x_range=p1. x_range # Verschiebungen entlang der X-Achse von p1 übernehmen # Verschiebung entlang der Y-Achse wird nicht übernommen, da es keinen Sinn ergibt. ) plotListe = [p1, p2, p3] # Alle Koordinatensyteme in eine Liste indikatoren = simulationsDaten[ "indikator_zeitreihe"] # Alle indikatordaten werden in einem eigenen Objekt gespeichert keyList = [] listenDict = {} # Jeder einzelne Key wird in die Key-Liste gespeichert und für jeden Key wird im ListenDict eine leere Liste erstellt. # Der erste key ist immer der Zeitstempel, die darauf folgenden sind die keys der Indikatoren for key in indikatoren[0]: keyList.append(key) listenDict[key] = [] # daten im indikatoren-Objekt werden aufgeteilt und abhängig vom key an die entsprechende Liste im listenDict angefügt. for daten in indikatoren: for key in keyList: listenDict[key].append(daten[key]) # Farb-Palette für das Darstellen der Graphen in verschiedenen Farben colors = itertools.cycle(palette) # Alle benötigten DataFrames generieren und deren Zeitstempel entsprechend formatieren zeitstempelDataFrame = pd.DataFrame(listenDict["zeitstempel"], columns=['zeitstempel']) zeitstempelDataFrame["zeitstempel"] = pd.to_datetime( zeitstempelDataFrame["zeitstempel"]) kursZeitreiheDF = pd.DataFrame(simulationsDaten["kurs_zeitreihe"]) kursZeitreiheDF["zeitstempel"] = pd.to_datetime( kursZeitreiheDF["zeitstempel"]) stratZeitreiheDF = pd.DataFrame( simulationsDaten["strategie_kurs_zeitreihe"]) stratZeitreiheDF["zeitstempel"] = pd.to_datetime( stratZeitreiheDF["zeitstempel"]) kaufVerkaufDF = pd.DataFrame( simulationsDaten["strategie_kaeufe_verkaeufe_zeitreihe"]) inc = kursZeitreiheDF.close > kursZeitreiheDF.open # inc ist ein boolean, welcher True zurückgibt wenn Close > Open dec = kursZeitreiheDF.open > kursZeitreiheDF.close # dec ist ein boolean, welcher True zurückgibt wenn Open > Close w = 12 * 60 * 60 * 1000 # halber Tag in ms, für die Breite der Kerzen # Hier werden die einzelnen Elemente der Kerze zum Koordinatensystem p1 hinzugefügt p1.segment( # Hier werden die High und Lows für jeden Tag erstellt, dargestellt durch zwei verbunde Punkte kursZeitreiheDF.zeitstempel, # X Werte für Punkt 1 kursZeitreiheDF.high, # Y Werte für Punkt 1 kursZeitreiheDF.zeitstempel, # X Werte für Punkt 2 kursZeitreiheDF.low, # Y Werte für Punkt 2 color="black", legend_label=simulationsDaten["wertpapier"]["name"] + " - High-Low") p1.vbar( # Hier werden die grünen Kerzen "Torsos" erstellt, dargestellt durch Balken je einem X-Wert, zwei Y-Werten und einer Breite kursZeitreiheDF.zeitstempel[inc], # X Werte der Balken w, # Breite kursZeitreiheDF.open[inc], # Y1 Werte der Balken kursZeitreiheDF.close[inc], # Y2 Werte der Balken fill_color="green", line_color="black", legend_label=simulationsDaten["wertpapier"]["name"] + " - Grüne Kerzen") p1.vbar( # Hier werden die roten Kerzen "Torsos" erstellt, dargestellt durch Balken je einem X-Wert, zwei Y-Werten und einer Breite kursZeitreiheDF.zeitstempel[dec], # X Werte der Balken w, # Breite kursZeitreiheDF.open[dec], # Y1 Werte der Balken kursZeitreiheDF.close[dec], # Y2 Werte der Balken fill_color="red", line_color="black", legend_label=simulationsDaten["wertpapier"]["name"] + " - Rote Kerzen") # --------------------------------- p2.line( # Hier wird der Aktienkurs als Linie zu dem Koordinatensystem p2 hinzugefügt kursZeitreiheDF.zeitstempel, # X Werte der Linie kursZeitreiheDF.close, # Y Werte der Linie line_width=3, color="red", alpha=0.5, legend_label=simulationsDaten["wertpapier"]["name"]) p3.line( # Hier wird die Performance als Linie zu dem Koordinatensystem p3 hinzugefügt stratZeitreiheDF.zeitstempel, stratZeitreiheDF.kurs_prozentual, line_width=3, color="black", alpha=0.5, legend_label="Kapital in Prozent") # Für jeden Key in der KeyListe for key in keyList: # Der nicht gleich zeitstempel, also für jeden Indikator if (key != "zeitstempel"): # wird ein eigenes DataFrame angelegt mit den entsprechenden Daten aus listenDict elementDataFrame = pd.DataFrame(listenDict[key]) # Wenn Indikator eine eigene Skala braucht, wird ein neues Koordinatensystem erstellt inEigenesKoord = False if (pruefeObEigeneSkala(key, self)): newPlot = figure( plot_width=1000, plot_height=700, x_axis_type="datetime", tools= "pan, wheel_zoom, box_zoom, reset, save, crosshair", x_range=p1. x_range # Verschiebungen entlang der X-Achse von p1 übernehmen ) inEigenesKoord = True # für jeden key in diesem DataFrame, also für jeden Graph des Indikators for graph in listenDict[key][0].keys(): # wird eine eigene Linie erstellt mit den entsprechenden Y-Werten. Die X-Werte werden dabei vom ZeitstempelDataFrame übernommen, # um es einheitlich zu halten line = pd.concat( [zeitstempelDataFrame, elementDataFrame[graph]], axis=1) # Wenn eigenes Koordianten System erstellt wurde, an dieses Koordinatensystem fügen if (inEigenesKoord): newPlot.line(zeitstempelDataFrame["zeitstempel"], line[graph], line_width=3, color=next(colors), alpha=1, legend_label="ID " + key + " - " + graph) # Ansonsten in beide Koordinatensystemen p1 und p2 else: for plot in [p1, p2]: plot.line( zeitstempelDataFrame["zeitstempel"], line[graph], line_width=3, color=next(colors), alpha=1, legend_label="ID " + key + " - " + graph, ) # Wenn eigenes Koordinatensystem erstellt wurde, dann dieses zur KoordinatenSystem Liste hinzufügen if (inEigenesKoord): plotListe.append(newPlot) # Wenn das KaufVerkaufDataFrame nicht leer ist if (not kaufVerkaufDF.empty): # boolischen Ausdrücke generieren kauf = kaufVerkaufDF.typ == "Kauf" verkauf = kaufVerkaufDF.typ == "Verkauf" # In beide Koordinatensystemen p1 und p2 werden die Markierungen für Käufe und Verkäufe eingefügt hauptPlotListe = [p1, p2] for plot in hauptPlotListe: plot.circle( # Punkte für Käufe pd.to_datetime( kaufVerkaufDF.zeitstempel[kauf] ), # X-Werte, Zeitstempel der Daten wenn TransaktionsTyp = Kauf # Für die Y-Werte wird der Kaufpreis der Aktie berechnet. Also die Menge an ausgegebenem Kapital durch die Anzahl der gekauften Aktien (-1) * (kaufVerkaufDF.kapital_bestand_aenderung[kauf] / kaufVerkaufDF.stueck_bestand_aenderung[kauf]), size=20, color="blue", alpha=0.5, legend_label="Käufe") plot.circle( # Punkte für Verkäufe pd.to_datetime( kaufVerkaufDF.zeitstempel[verkauf] ), # X-Werte Zeitstempel der Daten wenn TransaktionsTyp = Verkauf # Für die Y-Werte wird der Verkaufspreis der Aktie berechnet. Also die Menge an erhaltenem Kapital durch die Anzahl der verkauften Aktien (-1) * (kaufVerkaufDF.kapital_bestand_aenderung[verkauf] / kaufVerkaufDF.stueck_bestand_aenderung[verkauf]), size=20, color="yellow", alpha=0.5, legend_label="Verkäufe") # Hier werden alle Legenden Einstellungen und allg. Koordinaten System Einstellungen gemacht for plot in plotListe: plot.legend.location = "top_left" plot.legend.title = 'Graphen' plot.legend.title_text_font_style = "bold" plot.legend.title_text_font_size = "20px" plot.legend.click_policy = "hide" plot.output_backend = "svg" plot.background_fill_color = "#f5f5f5" plot.grid.grid_line_color = "white" plot.axis.axis_line_color = None plot.xaxis.major_label_orientation = pi / 4 # script, div = components(Tabs(tabs=[tab1, tab2])) script, div = components(column(plotListe)) return render( request, 'modulViews/generisch_ansicht_plotErgebnis.html', { 'script': script, 'div': div, 'daten': anzeigeDaten, "appName": "simulation" })
def get(self, request, *args, **kwargs): """ Hier werden die benötigten Indikator- und Kursdaten geholt und in die entsprechenden Graphiken eingefügt. Es werden mit der Bibliothek "bokeh" für die Kursdaten als Referenzwert und die Daten des Indikators die entsprechenden Graphen generiert. Es werden insgesamt 2 Koordinaten-Systeme generiert. Im ersten sind die Aktienkurse-Daten des DAX als Candles dargestellt sowie alle Graphen des ausgewählten Indikators. Im zweiten sind die Aktienkurse-Daten des DAX als Linie dargestellt sowie alle Graphen des ausgewählten Indikators. Bei beiden Koordinaten-Systemen wird der Zeitraum vom 01.0.1.2019 bis 31.12.2020 dargestellt. """ daten = { "id": self.kwargs.get("id"), "benutzer_id": self.request.user.username, "isin": "DE0008469008", "start_datum": "2019-01-01", "end_datum": "2020-12-31" } # Kurs daten werden hier geholt -------------- aktienkursDaten = datenAnBackendSenden(hauptPfad="kurs", unterPfad="/get", daten=daten) # Prüfen ob kein Fehler entstanden ist # Wenn ja auf FehlerSeite leiten if (allgemeineFehlerPruefung(serverAntwort=aktienkursDaten, request=request)): return redirect(reverse('indikator:indikator-fehler')) # ----------------------- # Indikatorgraph-Daten werden hier geholt, angewandt auf der oben festgelegten ISIN serverAntwort = datenAnBackendSenden(hauptPfad="indikator", unterPfad="/auswerten", daten=daten) # Prüfen ob kein Fehler entstanden ist # Wenn ja auf FehlerSeite leiten if (allgemeineFehlerPruefung(serverAntwort=serverAntwort, request=request)): return redirect(reverse('indikator:indikator-fehler')) # ----------------------- indikatorenDaten = serverAntwort[ "indikator_zeitreihe"] # Die Indikatordaten werden für eine einfachere Verarbeitung in ein eigenes Objekt kopiert. keyListe = indikatorenDaten[0].keys() listenDict = {} # ersetze alle Leerzeichen mit der Leerzeichen Entity serverAntwort["indikator"]["berechnung_pseudo_code"] = serverAntwort[ "indikator"]["berechnung_pseudo_code"].replace(" ", " ") # ersetze vier aufeinander folgende Leerzeichen durch zu 4 Leerzeichen Entity serverAntwort["indikator"]["berechnung_pseudo_code"] = serverAntwort[ "indikator"]["berechnung_pseudo_code"].replace( " ", "    ") # Für jeden key wird eine Leere Liste im listenDict angelegt for key in keyListe: listenDict[key] = [] # Jeder Datensatz in den IndikatorDaten wird an die entsprechende Liste im ListenDict Dictionary angehängt for datensatz in indikatorenDaten: for key in keyListe: listenDict[key].append(datensatz[key]) p1 = figure( # Koordinaten-System Deklaration plot_width=1000, plot_height=700, x_axis_type="datetime", tools="pan,wheel_zoom,box_zoom,reset,save") p2 = figure( # Koordinaten-System Deklaration plot_width=1000, plot_height=700, x_axis_type="datetime", tools="pan,wheel_zoom,box_zoom,reset,save", x_range=p1.x_range, y_range=p1.y_range) plotListe = [p1, p2] # Wandelt die zeitstempel Daten in ein DataFrame um zeitstempelDataFrame = pd.DataFrame(listenDict["zeitstempel"], columns=['zeitstempel']) # Die Daten in der Spalte "zeitstempel" müssen in das entsprechende Format umgewandelt werden zeitstempelDataFrame["zeitstempel"] = pd.to_datetime( zeitstempelDataFrame["zeitstempel"]) #Wandelt die kurs_zeitreihe Daten in ein DataFrame um aktienKursDataFrame = pd.DataFrame(aktienkursDaten["kurs_zeitreihe"]) # Die Daten in der Spalte "zeitstempel" müssen in das entsprechende Format umgewandelt werden aktienKursDataFrame["zeitstempel"] = pd.to_datetime( aktienKursDataFrame["zeitstempel"]) # Boolean der prüft, ob aktienKursDataFrame.close größer aktienKursDataFrame.open inc = aktienKursDataFrame.close > aktienKursDataFrame.open # Boolean der prüft, ob aktienKursDataFrame.close kleiner aktienKursDataFrame.open dec = aktienKursDataFrame.close < aktienKursDataFrame.open kerzenBreite = 12 * 60 * 60 * 1000 # halber Tag in ms, für die Breite der Kerzen #Jeder "Punkt" eines segment ist eine Linie die aus zwei Koordinaten-Paaren besteht. p1.segment( # Hier werden die High und Lows für jeden Tag erstellt aktienKursDataFrame.zeitstempel, # Paar-1 Werte für x-Achse aktienKursDataFrame.high, # Paar-1 Werte für y-Achse aktienKursDataFrame.zeitstempel, # Paar-2 Werte für x-Achse aktienKursDataFrame.low, # Paar-2 Werte für y-Achse color="black", legend_label="High-Low-Linien") # Jedes "Punkt" einer vbar ist ein Rechteck mit einem x-Wert, einer Breite, und zwei Werten für die y-Achse (Rechteck-Höhe) p1.vbar( # Hier werden die grünen Kerzen "Torsos" erstellt aktienKursDataFrame.zeitstempel[inc], # Werte für x-Achse kerzenBreite, aktienKursDataFrame.open[inc], # Teil 1 Werte für y-Achse aktienKursDataFrame.close[inc], # Teil 2 Werte für y-Achse fill_color="green", line_color="black", legend_label="Grüne Candlesticks") p1.vbar( # Hier werden die roten Kerzen "Torsos" erstellt aktienKursDataFrame.zeitstempel[dec], # Werte für x-Achse kerzenBreite, aktienKursDataFrame.open[dec], # Teil 1 Werte für y-Achse aktienKursDataFrame.close[dec], # Teil 2 Werte für y-Achse fill_color="red", line_color="black", legend_label="Rote Candlesticks", ) #Jeder Punkt einer line braucht ein Koordinaten-Paar p2.line( # Hier wird der Aktienkurs als Linie erstellt aktienKursDataFrame.zeitstempel, # Werte für x-Achse aktienKursDataFrame.close, # Werte für y-Achse line_width=3, color="red", alpha=0.5, legend_label="DAX") farben = itertools.cycle(palette) # Farbenauswahl for key in keyListe: if (key != "zeitstempel"): # Jede einzelne Liste im ListenDict wird in ein DataFrame umgewandelt, außer die Liste mit dem key "zeitstempel" elementDataFrame = pd.DataFrame(listenDict[key]) for graph in listenDict[key][0].keys(): # für eine korrekte Darstellung müssen alle Graphen das selbe Zeitstempel DataFrame verwenden # hier werden die Graphen-Werte der einzelnen Graphen mit den Zeitstempeln des zeitstempelDataFrame zu einen einzigen DataFrame vereinigt angepassteDatenPunkte = pd.concat( [zeitstempelDataFrame, elementDataFrame[graph]], axis=1) farbe = next(farben) # und in beide Koordinatensysteme eingefügt if (serverAntwort["indikator"]["eigene_skala"]): p3 = figure( # Koordinaten-System Deklaration plot_width=1000, plot_height=700, x_axis_type="datetime", tools="pan,wheel_zoom,box_zoom,reset,save", x_range=p1.x_range) p3.line( # zeitstempelDataFrame["zeitstempel"], angepassteDatenPunkte[graph], line_width=3, color=farbe, alpha=1, legend_label="ID " + key + " - " + graph, ) plotListe.append(p3) else: for plot in plotListe: plot.line( zeitstempelDataFrame["zeitstempel"], angepassteDatenPunkte[graph], line_width=3, color=farbe, alpha=1, legend_label="ID " + key + " - " + graph, ) # An beide Koordinaten-Systeme werden die gleichen Legenden Einstellungen sowie Stylingattribute vergeben for plot in plotListe: #Legenden Einstellung plot.legend.location = "top_left" plot.legend.title = 'Graphen' plot.legend.title_text_font_style = "bold" plot.legend.title_text_font_size = "20px" plot.legend.click_policy = "hide" #Koordinaten-System Styling plot.background_fill_color = "#f5f5f5" plot.grid.grid_line_color = "white" plot.axis.axis_line_color = None plot.xaxis.major_label_orientation = pi / 4 tab1 = Panel(child=p1, title="Candlesticks") tab2 = Panel(child=p2, title="Linie") if (len(plotListe) == 2): script, div = components(Tabs(tabs=[tab1, tab2])) else: script, div = components(column(Tabs(tabs=[tab1, tab2]), p3)) return render( request, 'indikator/indikator_graph.html', { 'script': script, 'div': div, 'daten': serverAntwort["indikator"], 'bearbeitbar': self.request.session["bearbeitbar"] })