Ich hab alles richtig gemacht aber pandas rechnet falsch ;)

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
TechHippie420
User
Beiträge: 11
Registriert: Montag 22. Februar 2021, 10:03

Hallo zusammen,

habe ein seltsames Problem mit der Berechnung von gleitenden Durchschnitten (moving averages).
Habe ein paar Tutorials zur Berechnung der gleitenden Durchschnitte auf Youtube verfolg und zunächst in einem ipython notebook (VS-Code) - leicht für meine Zwecke abgewandelt - Nachvollzogen. hat auch alles super geklappt.

hier der Code des IPythonNotebooks:

Code: Alles auswählen

import datetime as dt
import pandas as pd
from pandas import DataFrame
from pandas_datareader import data as pdr
import yfinance as yf
import pickle
import bs4 as bs
import requests

yf.pdr_override()

def save_DAX_tickers():

    response = requests.get('https://de.wikipedia.org/wiki/DAX')
    soup = bs.BeautifulSoup(response.text, 'lxml')
    table = soup.find('table', {'class': 'wikitable sortable'})

    tickers = []
    for row in table.findAll('tr')[1:]:
        ticker = row.findAll('td')[1].text
        if '.' in ticker:
            ticker = ticker.replace('.','-')
        tickers.append(ticker + '.DE')

    with open('DAX_tickers.pickle', 'wb') as f:
        pickle.dump(tickers, f)

    return tickers

save_DAX_tickers()

startyear = 2015
startmonth = 1
startday = 1
start = dt.datetime(startyear, startmonth, startday)

# endyear = 2020
# endmonth = 2
# endday = 1
# end = dt.datetime(endyear, endmonth, endday)

end = dt.datetime.now()

Dax_list_pickle = pd.read_pickle('DAX_tickers.pickle')
stocklist = DataFrame(Dax_list_pickle, columns=['tickers'])
exportlist = pd.DataFrame(columns=['Stock', 'RS_Rating', '50 Day MA', '150 Day MA', '200 Day MA', '52 Week Low', '52 Week High'])

# print(type(stocklist))
# print(stocklist)
# print(type(exportlist))
# print(exportlist)

# Calculation for the relative strength index (RSI) from:
# https://www.learnpythonwithrune.org/pandas-calculate-the-relative-strength-index-rsi-on-a-stock/

for i in stocklist.index:
    stock = str(stocklist['tickers'][i])

    try:
        df_RS_Rating = pdr.get_data_yahoo(stock, start, end)
        df_RS_Rating.drop(['Open', 'High', 'Low', 'Close', 'Volume'], 1, inplace=True)
        df_RS_Rating['Diff Vortag'] = df_RS_Rating.diff()

        delta = df_RS_Rating['Adj Close'].diff()
        up = delta.clip(lower=0)
        down = -1*delta.clip(upper=0)
        ema_up = up.ewm(com=13, adjust=False).mean()
        ema_down = down.ewm(com=13, adjust=False).mean()
        rs = ema_up/ema_down

        df_RS_Rating['RSI'] = 100 - (100/(1 + rs))

        # Skip first 14 days to have real values
        df_RS_Rating = df_RS_Rating.iloc[14:]

        print(df_RS_Rating.head())
    except Exception:
        print('sth. went wrong')

for i in stocklist.index:
    stock = str(stocklist['tickers'][i])
    RS_Rating = df_RS_Rating['RSI'][i]

    try:
        df = pdr.get_data_yahoo(stock, start, end)
        
        smaUsed = [50, 150, 200]

        for x in smaUsed:
            sma = x
            df['SMA_' + str(sma)] = round(df.iloc[:,4].rolling(window=sma).mean(), 2)
        
        currentClose = df['Adj Close'][-1]
        moving_average_50 = df['SMA_50'][-1]
        moving_average_150 = df['SMA_150'][-1]
        moving_average_200 = df['SMA_200'][-1]

        low_of_52week = min(df['Adj Close'][-260:])
        high_of_52week = max(df['Adj Close'][-260:])
        
        try:
            moving_average_200_20past = df['SMA_200'][-20]
        except Exception:
            moving_average_200_20past = 0

        print('Checking ' + stock + ' ...')

        # Condition 1: Current price > 150 SMA and > 200 SMA
        if (currentClose > moving_average_150 and currentClose > moving_average_200):
            cond_1 = True
            print(currentClose)
            print(moving_average_150)
            print(moving_average_200)
            print('cond_1 is True')
        else:
            cond_1 = False
            print('cond_1 is False')

        # Condition 2: 150 SMA > 200 SMA
        if (moving_average_150 > moving_average_200):
            cond_2 = True
            print('cond_2 is True')
        else:
            cond_2 = False
            print('cond_2 is False')

        # Condition3: 200 SMA trending up for at least 1 month (ideally 4-5 months)
        if (moving_average_200 > moving_average_200_20past):
            cond_3 = True
            print('cond_3 is True')
        else:
            cond_3 = False
            print('cond_3 is False')

        # Condition 4: 50 SMA > 150 SMA and 50 SMA > 200 SMA
        if (moving_average_50 > moving_average_150 and moving_average_50 > moving_average_200):
            cond_4 = True
            print('cond_4 is True')
        else:
            cond_4 = False
            print('cond_4 is False')

        # Condition 5: Current price > 50 SMA
        if (currentClose > moving_average_50):
            cond_5 = True
            print('cond_5 is True')
        else:
            cond_5 = False
            print('cond_5 is False')

        # Condition 6: Current price is at least 30% above 52 weeks low (many of the best are up to 100 - 300% above)
        if (currentClose >= (1.3*low_of_52week)):
            cond_6 = True
            print('cond_6 is True')
        else:
            cond_6 = False
            print('cond_6 is False')

        # Condition 7: Current price is within 25% of 52 week high
        if (currentClose >= (.75*high_of_52week)):
            cond_7 = True
            print('cond_7 is True')
        else:
            cond_7 = False
            print('cond_7 is False')

        # Condition 8: (IBD) RS rating > 70 and the higher the better
        if (RS_Rating > 70):
            cond_8 = True
            print('cond_8 is True')
        else:
            cond_8 = False
            print('cond_8 is False')

        if(cond_1 and cond_2 and cond_3 and cond_4 and cond_5 and cond_6 and cond_7 and cond_8):
            exportlist = exportlist.append({'Stock': stock, 'RS_Rating': RS_Rating, '50 Day MA': moving_average_50, '150 Day MA': moving_average_150, '200 Day MA': moving_average_200, '52 Week Low': low_of_52week, '52 Week High': high_of_52week}, ignore_index=True)        

    except Exception:
        print('No Data on ' + stock)

print(exportlist)
Wie gesagt, läuft einwandfrei.
Hier die entsprechende Ausgabe:

Code: Alles auswählen

[*********************100%***********************]  1 of 1 completed
Checking ADS.DE ...
286.70001220703125
274.59
264.71
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is True
cond_6 is True
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking ALV.DE ...
196.10000610351562
184.83
182.77
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking BAS.DE ...
67.58999633789062
57.58
55.4
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is True
cond_6 is True
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking BAYN.DE ...
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is True
cond_6 is True
cond_7 is False
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking BEI.DE ...
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is False
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking BMW.DE ...
69.79000091552734
66.2
63.61
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking CON.DE ...
117.55000305175781
104.46
99.35
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking 1COV.DE ...
59.70000076293945
46.5
43.08
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is True
cond_6 is True
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking DAI.DE ...
65.56999969482422
51.43
47.33
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is True
cond_6 is True
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking DHER.DE ...
cond_1 is False
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is False
cond_6 is True
cond_7 is False
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking DBK.DE ...
9.758000373840332
8.48
8.38
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is True
cond_6 is True
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking DB1.DE ...
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking DPW.DE ...
41.22999954223633
39.57
37.26
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking DTE.DE ...
cond_1 is False
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking DWNI.DE ...
cond_1 is False
cond_2 is True
cond_3 is True
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking EOAN.DE ...
cond_1 is False
cond_2 is False
cond_3 is True
cond_4 is False
cond_5 is False
cond_6 is False
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking FRE.DE ...
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is False
cond_8 is True
[*********************100%***********************]  1 of 1 completed
Checking FME.DE ...
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is False
cond_7 is False
cond_8 is True
[*********************100%***********************]  1 of 1 completed
Checking HEI.DE ...
64.77999877929688
57.19
54.71
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is True
cond_6 is True
cond_7 is True
cond_8 is True
[*********************100%***********************]  1 of 1 completed
Checking HEN3.DE ...
cond_1 is False
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is True
[*********************100%***********************]  1 of 1 completed
Checking IFX.DE ...
34.2400016784668
27.75
25.92
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is True
cond_6 is True
cond_7 is True
cond_8 is True
[*********************100%***********************]  1 of 1 completed
Checking LIN.DE ...
cond_1 is False
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is True
[*********************100%***********************]  1 of 1 completed
Checking MRK.DE ...
135.3000030517578
129.6
123.62
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is True
[*********************100%***********************]  1 of 1 completed
Checking MTX.DE ...
195.0500030517578
176.94
170.79
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is False
cond_6 is True
cond_7 is False
cond_8 is True
[*********************100%***********************]  1 of 1 completed
Checking MUV2.DE ...
236.8000030517578
231.87
229.38
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is True
cond_6 is True
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking RWE.DE ...
cond_1 is False
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is True
[*********************100%***********************]  1 of 1 completed
Checking SAP.DE ...
cond_1 is False
cond_2 is False
cond_3 is True
cond_4 is False
cond_5 is False
cond_6 is False
cond_7 is False
cond_8 is True
[*********************100%***********************]  1 of 1 completed
Checking SIE.DE ...
127.0
114.06
110.54
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is True
cond_6 is True
cond_7 is True
cond_8 is True
[*********************100%***********************]  1 of 1 completed
Checking VOW3.DE ...
171.02000427246094
144.06
140.9
cond_1 is True
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is True
cond_6 is True
cond_7 is True
cond_8 is False
[*********************100%***********************]  1 of 1 completed
Checking VNA.DE ...
cond_1 is False
cond_2 is True
cond_3 is True
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
    Stock  RS_Rating  50 Day MA  150 Day MA  200 Day MA  52 Week Low  \
0  HEI.DE  73.910121      63.32       57.19       54.71    28.293339   
1  IFX.DE  74.576581      33.25       27.75       25.92    10.678000   
2  SIE.DE  77.130666     122.41      114.06      110.54    59.313236   

   52 Week High  
0     68.360001  
1     36.599998  
2    136.160004  
Nun zum Problem:
Wollte das Ganze nochmal in einer GUI Version implementieren (tkinter)
Ich poste vorsichtshalber mal das komplette Programm:

main.py:

Code: Alles auswählen

import tkinter as tk
from tkinter import ttk
import sys

from views.pages import Disclaimer, HomePage, MyPortfolio

class PersonalBroker(tk.Tk):

    def __init__(self, *args, **kwargs):
        
        tk.Tk.__init__(self, *args, **kwargs)
        tk.Tk.wm_title(self, 'Personal Broker')

        container = tk.Frame(self)
        container.pack(side='top', fill='both', expand=True)

        container.grid_columnconfigure(0, weight=1)
        container.grid_columnconfigure(1, weight=1)
        container.grid_rowconfigure(0, weight=1)

        self.frames = {}

        pages = [Disclaimer, HomePage, MyPortfolio]

        for page in pages:
            frame = page(container, self)
            self.frames[page] = frame
            frame.grid(column=0, row=0, columnspan=2, sticky='NESW')

        self.show_frame(Disclaimer)

    def show_frame(self, cont):

        frame = self.frames[cont]
        frame.tkraise()

app = PersonalBroker()
width = '1280'
height = '720'
screenWitdh = int((app.winfo_screenwidth() - int(width)) / 2)
screenHeight = int((app.winfo_screenheight() - int(height)) / 2)
posWidth = str(screenWitdh)
posHeight = str(screenHeight)
app.geometry(f'{width}x{height}+{posWidth}+{posHeight}')
app.mainloop()
wie gesagt, soweit keine Probleme.

Weiter mit
pages.py
das Problem liegt vermutlich in der Funktion createPortfolio der Klasse MyPortfolio irgendwo zwischen Zeile 166 und 186.
Hier werden nämlich die besagten moving averages berechnet.

Code: Alles auswählen

import tkinter as tk
from tkinter import ttk
import time

import bs4 as bs
import pickle
import requests

import datetime as dt
import pandas as pd
from pandas import DataFrame
from pandas_datareader import data as pdr
import yfinance as yf

LARGE_FONT = ('Verdana', 12)

class Disclaimer(tk.Frame):

    def __init__(self, parent, controller):

        tk.Frame.__init__(self, parent)

        label = tk.Label(self, text="""
        
         - Personal Broker Haftungsausschluss -

        Bei dieser Anwendung handelt es sich um eine 'alpha-version' zu testzwecken.
        Sie sollte nicht als Anlagetool oder Ratgeber verwendet werden.
        Der Autor der Anwendung übernimmt ausdrücklich keinerlei Gewährleistung in
        Bezug auf Funktionalität und/oder Korrektheit der Ergebnisse.
        Mit klicken auf 'Zustimmen' erklären Sie sich mit diesen Bedingungen einverstanden.
        Ein Klick auf 'Ablehnen' beendet die Anwendung.
        
        """, font=LARGE_FONT)
        label.pack(pady=10, padx=10)

        button1 = ttk.Button(self, text='Zustimmen', command=lambda: controller.show_frame(HomePage))
        button1.pack()

        button2 = ttk.Button(self, text='Ablehnen', command=quit)
        button2.pack()

class HomePage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        self.grid_columnconfigure(0, weight=1)
        self.grid_columnconfigure(1, weight=3)
        self.grid_rowconfigure(0, weight=1)

        mainCanvas = tk.Canvas(self, bg='black')
        mainCanvas.grid(column=0, row=0, columnspan=2, sticky='nsew')

        navigationCanvas = tk.Canvas(self, bg='blue')
        navigationCanvas.grid_columnconfigure(0, weight=1)
        navigationCanvas.grid_rowconfigure((0,1,2,3), weight=1)
        navigationCanvas.grid(column=0, row=0, padx=5, pady=5, sticky='NSEW')

        btn_MyPortfolio = ttk.Button(navigationCanvas, text='Mein Portfolio',
                                                command=lambda: controller.show_frame(MyPortfolio))
        btn_MyPortfolio.grid(column=0, row=0, padx=5, pady=5, sticky='NESW')

        btn_FindStocks = ttk.Button(navigationCanvas, text='Aktien Finder', command=lambda: controller.show_frame(StockFinder))
        btn_FindStocks.grid(column=0, row=1, padx=5, pady=5, sticky='NESW')

        btn_HomePage = ttk.Button(navigationCanvas, text='Home Page', command=lambda: controller.show_frame(Disclaimer))
        btn_HomePage.state(['disabled'])
        btn_HomePage.grid(column=0, row=3, padx=5, pady=5, sticky='NESW')

        button4 = ttk.Button(navigationCanvas, text='Beenden', command=quit)
        button4.grid(column=0, row=4, padx=5, pady=5, sticky='NESW')

        userViewCanvas = tk.Canvas(self, bg='blue')
        userViewCanvas.grid_columnconfigure((0,1,2,3), weight=1)        
        userViewCanvas.grid_rowconfigure((0,1,2,3), weight=1)
        
        lbl_PageTitle = tk.Label(userViewCanvas, text='Personal Broker - Home', anchor='center', font=LARGE_FONT)
        lbl_PageTitle.grid(column=0, row=0, columnspan=4, rowspan=1, padx=5, pady=5, sticky='NESW')
        userViewCanvas.grid(column=1, row=0, columnspan=7, padx=5, pady=5, sticky='NSEW')

class MyPortfolio(tk.Frame):

    startyear = 2015
    startmonth = 1
    startday = 1
    start = dt.datetime(startyear, startmonth, startday)

    # endyear = 2020
    # endmonth = 2
    # endday = 1
    # end = dt.datetime(endyear, endmonth, endday)

    end = dt.datetime.now()

    def save_Dax_Tickers(self, parent, controller):

        response = requests.get('https://de.wikipedia.org/wiki/DAX')
        soup = bs.BeautifulSoup(response.text, 'lxml')
        table = soup.find('table', {'class': 'wikitable sortable'})

        tickers = []
        for row in table.findAll('tr')[1:]:
            ticker = row.findAll('td')[1].text
            if '.' in ticker:
                ticker = ticker.replace('.','-')
            tickers.append(ticker + '.DE')

        with open('Data/tickers/DAX_tickers.pickle', 'wb') as f:
            pickle.dump(tickers, f)

        return tickers

    def createPortfolio(self, parent, controller):

        try:
            Dax_list_pickle = pd.read_pickle('Data/tickers/DAX_tickers.pickle')
            stocklist = DataFrame(Dax_list_pickle, columns=['tickers'])
            exportlist = pd.DataFrame(columns=['Stock', 'RS_Rating', '50 Day MA', '150 Day MA', '200 Day MA', '52 Week Low', '52 Week High'])

            # print(type(stocklist))
            # print(stocklist)
            # print(type(exportlist))
            # print(exportlist)

        except Exception:
            MyPortfolio(parent, controller).save_Dax_Tickers(parent, controller)

        
        # Kalkulation des Relative Stärke Index (RSI) von:
        # https://www.learnpythonwithrune.org/pandas-calculate-the-relative-strength-index-rsi-on-a-stock/

        for i in stocklist.index:
            stock = str(stocklist['tickers'][i])

            try:
                df_RS_Rating = pdr.get_data_yahoo(stock, self.start, self.end)
                df_RS_Rating.drop(['Open', 'High', 'Low', 'Close', 'Volume'], 1, inplace=True)
                df_RS_Rating['Diff Vortag'] = df_RS_Rating.diff()
                
                delta = df_RS_Rating['Adj Close'].diff()
                up = delta.clip(lower=0)
                down = -1*delta.clip(upper=0)
                ema_up = up.ewm(com=13, adjust=False).mean()
                ema_down = down.ewm(com=13, adjust=False).mean()
                rs = ema_up/ema_down

                df_RS_Rating['RSI'] = 100 - (100/(1 + rs))

                # Skip first 14 days to have real values
                df_RS_Rating = df_RS_Rating.iloc[14:]

                # print(df_RS_Rating.head())
            except Exception:
                print('sth. went wrong')
                print(Exception.with_traceback())

        # Auswahl der Aktien aus dem DAX, welche Mark Minervinis Trend Template Kriterien erfüllen.
        # siehe auch: https://www.youtube.com/watch?v=hngHA9Jjbjc&list=PLPfme2mwsQ1FQhH1icKEfiYdLSUHE-Wo5&index=3


        for i in stocklist.index:
            stock = str(stocklist['tickers'][i])
            RS_Rating = df_RS_Rating['RSI'][i]

            try:
                df = pdr.get_data_yahoo(stock, self.start, self.end)                
                
                smaUsed = [50, 150, 200]

                for x in smaUsed:
                    sma = x
                    df['SMA_' + str(sma)] = round(df.iloc[:,4].rolling(window=sma).mean(), 2)
                
                currentClose = df['Adj Close'][-1]
                moving_average_50 = df['SMA_50'][-1]
                moving_average_150 = df['SMA_150'][-1]
                moving_average_200 = df['SMA_200'][-1]

                low_of_52week = min(df['Adj Close'][-260:])
                high_of_52week = max(df['Adj Close'][-260:])
                
                try:
                    moving_average_200_20past = df['SMA_200'][-20]
                except Exception:
                    moving_average_200_20past = 0

                print('Checking ' + stock + ' ...')

                # Condition 1: Current price > 150 SMA and > 200 SMA
                if (currentClose > moving_average_150 and currentClose > moving_average_200):
                    cond_1 = True
                    print(currentClose)
                    print(moving_average_150)
                    print(moving_average_200)
                    print('cond_1 is True')
                else:
                    cond_1 = False
                    print(currentClose)
                    print(moving_average_150)
                    print(moving_average_200)
                    print('cond_1 is False')

                # Condition 2: 150 SMA > 200 SMA
                if (moving_average_150 > moving_average_200):
                    cond_2 = True
                    print('cond_2 is True')
                else:
                    cond_2 = False
                    print('cond_2 is False')

                # Condition3: 200 SMA trending up for at least 1 month (ideally 4-5 months)
                if (moving_average_200 > moving_average_200_20past):
                    cond_3 = True
                    print('cond_3 is True')
                else:
                    cond_3 = False
                    print('cond_3 is False')

                # Condition 4: 50 SMA > 150 SMA and 50 SMA > 200 SMA
                if (moving_average_50 > moving_average_150 and moving_average_50 > moving_average_200):
                    cond_4 = True
                    print('cond_4 is True')
                else:
                    cond_4 = False
                    print('cond_4 is False')

                # Condition 5: Current price > 50 SMA
                if (currentClose > moving_average_50):
                    cond_5 = True
                    print('cond_5 is True')
                else:
                    cond_5 = False
                    print('cond_5 is False')

                # Condition 6: Current price is at least 30% above 52 weeks low (many of the best are up to 100 - 300% above)
                if (currentClose >= (1.3*low_of_52week)):
                    cond_6 = True
                    print('cond_6 is True')
                else:
                    cond_6 = False
                    print('cond_6 is False')

                # Condition 7: Current price is within 25% of 52 week high
                if (currentClose >= (.75*high_of_52week)):
                    cond_7 = True
                    print('cond_7 is True')
                else:
                    cond_7 = False
                    print('cond_7 is False')

                # Condition 8: (IBD) RS rating > 70 and the higher the better
                if (RS_Rating > 70):
                    cond_8 = True
                    print('cond_8 is True')
                else:
                    cond_8 = False
                    print('cond_8 is False')

                if(cond_1 and cond_2 and cond_3 and cond_4 and cond_5 and cond_6 and cond_7 and cond_8):
                    exportlist = exportlist.append({'Stock': stock, 'RS_Rating': RS_Rating, '50 Day MA': moving_average_50, '150 Day MA': moving_average_150, '200 Day MA': moving_average_200, '52 Week Low': low_of_52week, '52 Week High': high_of_52week}, ignore_index=True)        

            except Exception:
                print('No Data on ' + stock)
                print(Exception.with_traceback())

        print(exportlist)

    def getMyPortfolio(self, lbl_PortfolioOverview):

        try:
            # print(self.lbl_PortfolioOverview.configure(text = 'endlich richtig'))
            self.lbl_PortfolioOverview.configure(text = 'endlich richtig')
            print('endlich richtig')
        except Exception:
            print('\n' + 'schon wieder falsch...' + '\n')
            print(Exception.with_traceback())

    def __init__(self, parent, controller):

        tk.Frame.__init__(self, parent)

        self.grid_columnconfigure(0, weight=1)
        self.grid_columnconfigure(1, weight=3)
        self.grid_rowconfigure(0, weight=1)

        self.mainCanvas = tk.Canvas(self, bg='black')
        self.mainCanvas.grid(column=0, row=0, columnspan=2, sticky='nsew')

        self.navigationCanvas = tk.Canvas(self, bg='blue')
        self.navigationCanvas.grid_columnconfigure(0, weight=1)
        self.navigationCanvas.grid_rowconfigure((0,1,2,3), weight=1)
        self.navigationCanvas.grid(column=0, row=0, padx=5, pady=5, sticky='NSEW')

        self.btn_CheckPortfolio = ttk.Button(self.navigationCanvas, text='Check Portfolio',
                                                command=lambda: MyPortfolio.getMyPortfolio(self, self.lbl_PortfolioOverview))
        self.btn_CheckPortfolio.grid(column=0, row=0, padx=5, pady=5, sticky='NESW')

        self.btn_CreatePortfolio = ttk.Button(self.navigationCanvas, text='Portfolio erstellen', 
                                                command=lambda: MyPortfolio.createPortfolio(self, parent, controller))
        self.btn_CreatePortfolio.grid(column=0, row=1, padx=5, pady=5, sticky='NESW')

        self.btn_HomePage = ttk.Button(self.navigationCanvas, text='Home Page',
                                                command=lambda: controller.show_frame(HomePage))
        self.btn_HomePage.grid(column=0, row=3, padx=5, pady=5, sticky='NESW')

        self.btn_Quit = ttk.Button(self.navigationCanvas, text='Beenden', 
                                                command=quit)
        self.btn_Quit.grid(column=0, row=4, padx=5, pady=5, sticky='NESW')

        self.userViewCanvas = tk.Canvas(self, bg='blue')
        self.userViewCanvas.grid_columnconfigure((0,1,2,3), weight=1)        
        self.userViewCanvas.grid_rowconfigure((0,1,2,3), weight=1)        

        self.lbl_PageTitle = tk.Label(self.userViewCanvas, text='Personal Broker - Mein Portfolio', anchor='center', font=LARGE_FONT)
        self.lbl_PageTitle.grid(column=0, row=0, columnspan=4, rowspan=1, padx=5, pady=5, sticky='NESW')
        self.lbl_PortfolioOverview = tk.Label(self.userViewCanvas, text='Dummy Text', anchor='center', font=LARGE_FONT)
        self.lbl_PortfolioOverview.grid(column=0, row=1, columnspan=4, rowspan=2, padx=5, pady=5, sticky='NESW')
        self.userViewCanvas.grid(column=1, row=0, columnspan=7, padx=5, pady=5, sticky='NSEW')

allerdings anscheinend falsch, wie wir anhand der Ausgabe sehen:

Code: Alles auswählen

Checking ADS.DE ...
288.0
535440.66      
607873.62      
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True 
cond_7 is True 
cond_8 is False
Checking ALV.DE ...
196.5399932861328
1159803.12       
1315155.32       
cond_1 is False  
cond_2 is False  
cond_3 is False  
cond_4 is False  
cond_5 is False  
cond_6 is True   
cond_7 is True   
cond_8 is False
Checking BAS.DE ...
67.66000366210938
2982490.95
3345449.24
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
Checking BAYN.DE ...
53.2599983215332
3634138.83
3731980.08
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is False
cond_8 is False
Checking BEI.DE ...
85.0199966430664
377307.17
401215.46
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is False
cond_7 is True
cond_8 is False
Checking BMW.DE ...
70.05999755859375
1569148.42
1721153.95
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
Checking CON.DE ...
117.94999694824219
532076.67
599922.06
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
Checking 1COV.DE ...
59.779998779296875
1166014.69
1250094.32
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
Checking DAI.DE ...
65.48999786376953
3722272.43
4311039.59
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
Checking DHER.DE ...
108.0
643323.33
609855.44
cond_1 is False
cond_2 is True
cond_3 is True
cond_4 is True
cond_5 is False
cond_6 is True
cond_7 is False
cond_8 is False
Checking DBK.DE ...
9.826000213623047
11913438.91
13197683.3
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
Checking DB1.DE ...
136.0
563350.89
579160.34
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
Checking DPW.DE ...
41.2400016784668
3164549.91
3448306.18
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
Checking DTE.DE ...
14.649999618530273
10078708.3
10668557.27
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
Checking DWNI.DE ...
39.150001525878906
880282.37
951632.8
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
Checking EOAN.DE ...
8.473999977111816
8051564.8
8435621.31
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is True
cond_5 is False
cond_6 is False
cond_7 is True
cond_8 is False
Checking FRE.DE ...
35.43000030517578
1881489.36
1864240.1
cond_1 is False
cond_2 is True
cond_3 is True
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is False
cond_8 is True
Checking FME.DE ...
57.63999938964844
699026.12
717117.3
cond_1 is False
cond_2 is False
cond_3 is True
cond_4 is True
cond_5 is False
cond_6 is False
cond_7 is False
cond_8 is True
Checking HEI.DE ...
64.37999725341797
761808.99
860936.7
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is True
Checking HEN3.DE ...
82.9800033569336
461559.61
495325.62
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is True
Checking IFX.DE ...
34.349998474121094
5027591.27
5650442.91
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is True
Checking LIN.DE ...
204.0
813302.53
894622.71
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is True
Checking MRK.DE ...
135.3000030517578
415278.29
457396.86
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is True
Checking MTX.DE ...
196.4499969482422
271319.38
329195.08
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is False
cond_8 is True
Checking MUV2.DE ...
237.6999969482422
424143.65
467404.2
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
Checking RWE.DE ...
31.079999923706055
2449766.56
2548498.26
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is True
Checking SAP.DE ...
101.4800033569336
2980461.27
3015159.34
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is False
cond_7 is False
cond_8 is True
Checking SIE.DE ...
127.30000305175781
1828477.01
1980212.56
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is True
Checking VOW3.DE ...
171.47999572753906
1294612.0
1351866.98
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is True
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
Checking VNA.DE ...
52.47999954223633
1415093.77
1418233.78
cond_1 is False
cond_2 is False
cond_3 is False
cond_4 is False
cond_5 is False
cond_6 is True
cond_7 is True
cond_8 is False
Empty DataFrame
Columns: [Stock, RS_Rating, 50 Day MA, 150 Day MA, 200 Day MA, 52 Week Low, 52 Week High]
Index: []
Die moving averages sind viel zu hoch, wie uns ein Vergleich mit der Ausgabe des iPythonNotebooks zeigt.
Kann es sein, das dies ein Performance Problem ist und die Daten zu schnell berechnet werden müssen?

Vielen Dank im Voraus und noch einen schönen Tag alle zusammen

TechHippie420
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Warum kürzt man bs4 als bs ab? findAll ist schon lange veraltet und durch find_all ersetzt.
Generell schreibt man alle Variablennamen komplett klein.
Auf Klassenebene sollten nur Konstanten stehen, keine Variablen.
Das Exceptionhandling in createPortfolio ist falsch, da bei einer Exception stocklist gar nicht existiert.
Über einen Index (auch einen Pandas-Index) iteriert man nicht, weil man direkt über die Daten iterieren könnte.
Warum schreibst Du die Elemente von smaUsed erst in x um sie dann gleich in sma zu speichern? Das x ist nicht nur ein schlechter Variablenname sondern auch total unnötig.

pdr.get_data_yahoo liefert offensichtlich andere Werte, was die Ausgabe von moving_average_150 und moving_average_200 zeigen.
Wenn ich wetten müßte: Du machst da etwas falsch.
TechHippie420
User
Beiträge: 11
Registriert: Montag 22. Februar 2021, 10:03

Hi Sirius3,
vielen Dank für Deine schnelle Antwort.

War gerade dabei auf alle o. g. Punkte genau einzugehen, bin dann aber irgendwie abgemeldet worden und musste mich nochmal neu anmelden. Danach war dann der von mir verfasste bisherige Text weg.
Also hier nochmal in Kurzform

vieles z. B. das Abkürzen von bs4 oder auch findAll war halt einfach aus einem Tutorial (ich glaube aus 2014) übernommen
Die Variablennamen finde ich in CamelCase ehrlich gesagt lesbarer, gerade bei langen Namen. - Auch wenn das gestern dann doch mal in die Hose gegangen ist, wie Du sicher noch weißt.
Das Exceptionhandling, die Variablen auf Klassenebene habe ich geändert.
An das iterieren über den Index traue ich mich nicht ran. - Funktioniert ja
Die Nummer mit smaUsed -> x usw. - war halt auch aus nem Tutorial und läuft.

Zum eigentlichen Problem:
Die Wette hätte ich wohl verloren:) - wer hätte das gedacht.
tatsächlich waren in den beiden DataFrames (warum auch immer) die Spalten 'Adj Close' und 'Volume' vertauscht was dann auch die extrem hohen Werte erklärte.
Jetzt gibt es bei beiden die selbe Ausgabe.

Abschließend also nochmals besten Dank und noch einen schönen Tag weiterhin
Beste Grüße
TechHippie420
Antworten