class StockMess(): def __init__(self): self.db = Database() self.ss = SectorStats() self.last_date = None self.financials = None self.earnings = None self.sentiment = None self.spy = None self.stocks = None self.in_day_stocks = None self.trend_data = None async def mail_stats(self, data, subject, last_date=None, spy=None): # print(data) if spy is None: spy = sdf.retype( self.db.load_data(TableName.DAY, ["spy"], time_from="-60d", time_to="0d")) for key, value in data.iterrows(): if "flpd" in value: subject_flpd = subject + " " + str(round(value.flpd, 2)) + "% | " try: sym = value.sym except AttributeError: sym = key self.set_fundamentals(sym=sym) self.set_prices(sym=sym) self.mail_sym_stats(sym, subject_flpd, last_date=last_date) def a_mail_sym_stats(self, sym, subject, last_date=None): self.mail_sym_stats(sym, subject, last_date=None) def mail_sym_stats(self, sym, subject, last_date=None): # self.db.last_date = last_date # if self.spy is None: # self.spy = sdf.retype(self.db.load_data( # TableName.DAY, ["spy"], time_from="-60d", time_to="0d")) # self.stocks = sdf.retype(self.db.load_data(TableName.DAY, sym, time_from="-60d", time_to = "0d")) # self.stocks = FinI.add_indicators(self.stocks) # time_to = last_date # self.earnings, self.sentiment, self.financials = self.db.get_fundamentals(self.stocks.iloc[-1]["sym"], # tf={"e": "-5d", # "s": "-20d", # "f": "-14d"}, # tt={"e": "30d", "s": "0d", "f": "0d"}) mess, curr_price, days_to_earnings = self.get_subj_mess(subject, sym=sym) details = self.get_fund_mess(self.financials, curr_price, self.earnings, self.sentiment, days_to_earnings, self.stocks) plt = self.show_sym_stats(sym, True) Utils.send_mm_mail(mess, details, plt) def get_subj_mess(self, subject, sym=None): mess = "" if self.stocks is None or sym != self.stocks.iloc[0].sym: self.stocks = self.ss.get_trend_slice(table_name=None, time_from="-120d", time_to="0d", symbol=sym) curr_price = self.stocks.iloc[-1].close # print(self.stocks) days_to_earnings = FinI.days_to_earnings(self.earnings) sector_mess, spy_mess, vol_mess = self.get_common_mess(self.stocks) mess = subject + " " + str(sym) + \ self.subject_fund_info(self.financials, self.sentiment, self.earnings, days_to_earnings = days_to_earnings) mess += str(sector_mess) mess += str(spy_mess) mess += str(vol_mess) self.stocks = FinI.add_levels(self.stocks) # hl = FinI.get_fib_hl(self.stocks, self.stocks.iloc[-1].close) pl = self.stocks.price_level.dropna() low, high = FinI.get_nearest_values(pl, curr_price) mess += " Price: " + str(curr_price) mess += " | Loss: " + str(Utils.calc_perc( curr_price, low[0])) + "%, " if low is not None and len(low) > 0 else "" mess += " " + "Prof.: " + str(Utils.calc_perc( curr_price, high[0])) + "% " if high is not None and len(high) > 0 else " | " print("get_subj_mess() - done") return mess, curr_price, days_to_earnings @staticmethod def get_fib_mess(df, close_price): mess = "" last_fib = -1 for col in df: if col.startswith('fb'): if close_price > last_fib and close_price < df.iloc[-1][col]: mess += str(Utils.calc_perc(close_price, last_fib)) + "% | " \ "Price: " + str(close_price) + \ " | " + str(Utils.calc_perc(close_price, df.iloc[-1][col])) + "% \n\r" mess += str(col) + ": " + str(round(df.iloc[0][col], 2)) + "\n\r" last_fib = df.iloc[-1][col] return mess def show_sym_stats(self, sym, save_img=False): # last financials if self.financials is not None and len(self.financials) > 0: self.financials = self.financials.tail(5) days_to_earnings = FinI.days_to_earnings(self.earnings) # print(earnings) if days_to_earnings is None: self.earnings = None plots_num = 4 if save_img else 5 fig, axs = plt.subplots(plots_num, 1, figsize=(16, 18)) PlotI.set_margins(plt) if self.spy is not None: PlotI.plot_spy( axs[0], self.spy.loc[self.spy.index.isin(self.stocks.index)]) axsp = PlotI.plot_stock_prices(axs[0].twinx(), self.stocks, sym, alpha=0.3) axsp = PlotI.plot_sma(axsp, self.stocks, ["sma9", "sma50"]) axsp = PlotI.plot_candles(self.stocks, axsp, body_w=0.5, shadow_w=0.1, alpha=0.5) axsp = PlotI.plot_fib(self.stocks, axsp, alpha=0.4) axsp = PlotI.plot_fib(self.stocks, axsp, alpha=0.4, fib_name="fb_mid") axsp = PlotI.plot_fib(self.stocks, axsp, alpha=0.4, fib_name="fb_bot") PlotI.plot_boll(axsp, self.stocks, sym) PlotI.plot_weeks(axsp, self.stocks) PlotI.plot_rsi(axs[1], self.stocks) ax_macd = PlotI.plot_macd_boll(axs[1].twinx(), self.stocks) # ax_macd = PlotI.plot_macd(ax_macd,dfp) PlotI.plot_volume_bars(axs[1].twinx(), self.stocks) if self.in_day_stocks is None: self.in_day_stocks = sdf.retype( self.db.load_data(TableName.MIN15, sym, time_from="-1d", time_to="0d")) if len(self.in_day_stocks) < 1: self.in_day_stocks = sdf.retype( self.db.load_data(TableName.MIN15, sym, limit=20)) # self.plot_volume(axs[2], last_prices) ax = PlotI.plot_candlesticks2(axs[2], self.in_day_stocks) self.in_day_stocks = FinI.add_fib_from_day_df(self.in_day_stocks, self.stocks) ax = PlotI.plot_fib(self.in_day_stocks, axs[2], alpha=0.4, fib_name="fb_mid") # PlotI.plot_boll(ax, last_prices, sym) sectors = self.ss.sectors_day_stats() PlotI.plot_sector_stats(axs[3], sectors, self.stocks.iloc[0].sector) if (save_img): return plt # self.plot_spy(axs[2], self.spy) #self.plot_yahoo_candles(last_prices) # self.plot_volume(axs[2], last_prices) # set rotation of tick labels axs[3].text(0.02, 0.9, str(self.financials.beta.name) + ' | ' + str(self.financials.beta.to_list()), fontsize=8) axs[3].text( 0.02, 0.8, str(self.financials.priceToSalesTrailing12Months.name) + ' | ' + str(self.financials.priceToSalesTrailing12Months.to_list()), fontsize=8) axs[3].text(0.02, 0.7, str(self.financials.enterpriseToRevenue.name) + ' | ' + str(self.financials.enterpriseToRevenue.to_list()), fontsize=8) axs[3].text(0.02, 0.6, str(self.financials.profitMargins.name) + ' | ' + str(self.financials.profitMargins.to_list()), fontsize=8) axs[3].text(0.02, 0.5, str(self.financials.enterpriseToEbitda.name) + ' | ' + str(self.financials.enterpriseToEbitda.to_list()), fontsize=8) axs[3].text(0.02, 0.4, str(self.financials.trailingEps.name) + ' | ' + str(self.financials.trailingEps.to_list()), fontsize=8) axs[3].text(0.02, 0.3, str(self.financials.forwardEps.name) + ' | ' + str(self.financials.forwardEps.to_list()), fontsize=8) axs[3].text(0.02, 0.2, str(self.financials.priceToBook.name) + ' | ' + str(self.financials.priceToBook.to_list()), fontsize=8) axs[3].text(0.02, 0.1, str(self.financials.bookValue.name) + ' | ' + str(self.financials.bookValue.to_list()), fontsize=8) axs[3].text(0.4, 0.9, str(self.financials.shortRatio.name) + ' | ' + str(self.financials.shortRatio.to_list()), fontsize=8) axs[3].text(0.4, 0.8, str(self.financials.sharesShortPriorMonth.name) + ' | ' + str(self.financials.sharesShortPriorMonth.to_list()), fontsize=8) axs[3].text(0.4, 0.7, str(self.financials.pegRatio.name) + ' | ' + str(self.financials.pegRatio.to_list()), fontsize=8) axs[3].text(0.4, 0.6, str(self.financials.earningsQuarterlyGrowth.name) + ' | ' + str(self.financials.earningsQuarterlyGrowth.to_list()), fontsize=8) axs[3].text(0.4, 0.5, str(self.financials.bid.name) + ' | ' + str(self.financials.bid.to_list()), fontsize=8) axs[3].text(0.4, 0.4, str(self.financials.trailingPE.name) + ' | ' + str(self.financials.trailingPE.to_list()), fontsize=8) axs[3].text(0.4, 0.3, str(self.financials.forwardPE.name) + ' | ' + str(self.financials.forwardPE.to_list()), fontsize=8) axs[3].text(0.4, 0.2, str(self.financials.industry.to_list()) + ' | ' + str(self.financials.sector.to_list()), fontsize=8) axs[3].text(0.4, 0.1, str(self.financials.heldPercentInstitutions.name) + ' | ' + str(self.financials.heldPercentInstitutions.to_list()) + ' ||| ' + str(self.financials.heldPercentInsiders.name) + ' | ' + str(self.financials.heldPercentInsiders.to_list()), fontsize=8) axs[3].text(0.6, 0.9, str(self.financials.fiftyDayAverage.name) + ' | ' + str(self.financials.fiftyDayAverage.to_list()), fontsize=8) axs[3].text(0.6, 0.7, str("Last CLose Price: ") + ' | ' + str(self.in_day_stocks.iloc[-1].close), fontsize=8) axs[3].text( 0.6, 0.5, str("Days to earn.: ") + ' | ' + str(days_to_earnings.days) + " D" if self.earnings is not None else str("Days to earn.: NaN "), fontsize=8) axs[3].text(0.6, 0.4, str("Earn. est. | act. | surp.: ") + str(self.earnings.iloc[-1].epsestimate) + ' | ' + str(self.earnings.iloc[-1].epsactual) + ' | ' + str(self.earnings.iloc[-1].epssurprisepct) if self.earnings is not None else str("Earn est.: NaN "), fontsize=8) axs[3].text(0.6, 0.3, str(" Sentiment article/title: ") + str(self.sentiment.sentiment_summary_avg.to_list()) + '/' + str(self.sentiment.sentiment_title_avg.to_list()) if self.sentiment is not None and len(self.sentiment) > 0 else str(" Sentiment: NaN "), fontsize=8) axs[3].text(0.02, 0.01, str(self.financials.longBusinessSummary.to_list()), fontsize=8) # self.plot_candlesticks(last_prices) # axs[3].plot([2], [1], 'o') # plt.text() # plt.show() return plt def subject_fund_info(self, financials, sentiment, earnings, days_to_earnings=None): mess = "" if len(financials) > 0: eps, pe = chi.eps_pe(financials) mess += ''.join([ " | ShortR: ", str(financials.iloc[-1].shortRatio), " | TrEps/FwdEps: ", str(eps) + "%", " | TrPE/FwdPE: ", str(pe) + "%", " | 50_DA_move: ", str( Utils.calc_perc(financials.iloc[0].fiftyDayAverage, financials.iloc[-1].fiftyDayAverage)) + "%", " | Beta: ", str(financials.iloc[0].beta), " | PriceToBook: ", str(financials.iloc[0].priceToBook), " | DividRate: ", str(financials.iloc[0].dividendRate) ]) if earnings is not None and len(earnings) > 0: mess += ''.join([ str(" | Earn. est./act./surp.: "), str(earnings.iloc[-1].epsestimate), '/', str(earnings.iloc[-1].epsactual) + '/', str(earnings.iloc[-1].epssurprisepct), "" ]) if days_to_earnings is not None: days_to_earnings = str(days_to_earnings).split(",") mess += ''.join([" | Earn :", str(days_to_earnings[0])]) if sentiment is not None and len(sentiment) > 0: mess += ''.join([ str(" | Sentiment article/title: "), str(sentiment.iloc[-1].sentiment_summary_avg), '/', str(sentiment.iloc[-1].sentiment_title_avg) if sentiment is not None and len(sentiment) > 0 else str("Sentiment: NaN ") ]) return mess # def plot_sectors(self, plt): # data = self.sectors_uptrend_by_month(yf=2021,yt=2021, show_chart = False) # plt = self.sector_stats_to_plt(self,plt, data) # return plt # def classify_sectors(self, time_from = "7d", table_name = "p_day", loosers = False): # stocks = self.classify_sectors_uptrend(table_name) # stocks = stocks.sort_values(by='flpd', ascending=loosers) # return stocks def create_sectors_trend_mess(self, sector): sector_mess = "" # if self.sectors_trend is None and len(self.sectors_trend) < 1: self.ss.set_spy_sectors_trend() sector0 = self.ss.sectors_trend[0][self.ss.sectors_trend[0].index == sector] sector1 = self.ss.sectors_trend[1][self.ss.sectors_trend[1].index == sector] if len(sector0) > 0 and len(sector1) > 0: sector_mess = " | " + str(sector) + ": " + str( round(sector0.iloc[0].flpd, 1)) + "% -> " + str( round(sector1.iloc[0].flpd, 1)) + "%" print("create_sectors_trend_mess() - done") return sector_mess def create_spy_trend_mess(self): spy_mess = "" if self.ss.spy_trend is not None and \ self.ss.spy_trend[0] is not None and \ len(self.ss.spy_trend) > 2 and \ len(self.ss.spy_trend[0]) > 0 and \ len(self.ss.spy_trend[1]) > 0: print(self.ss.spy_trend[0]) spy_mess = " | SPY: " + str( round(self.ss.spy_trend[0].flpd.mean(), 2)) + "% -> " + str( round(self.ss.spy_trend[1].flpd.mean(), 2)) + "%" else: spy_mess = "No Data" return spy_mess def get_common_mess(self, stocks): # print(stocks.iloc[0].sector) vol_mess = vol_perc = spy_mess = sector_mess = "" if stocks is not None and len(stocks) > 0: sector_mess = self.create_sectors_trend_mess(stocks.iloc[0].sector) if stocks is not None and "boll" in stocks: vol_perc = Utils.calc_perc(stocks.iloc[-1].boll, stocks.iloc[-1].boll_ub) vol_mess = " | Vlt: " + str(vol_perc) + "% " else: vol_perc = 0 spy_mess = self.create_spy_trend_mess() print("get_common_mess() - done") return sector_mess, spy_mess, vol_mess def get_fund_mess(self, financials, curr_price, earnings, sentiment, days_to_earnings, day_stocks=None): mess = "" mess += ''.join("Detail | ") financials.sort_values(by=["date"], inplace=True, ascending=True) if len(financials) > 0: cols = [ "date", "shortRatio", "sharesShortPriorMonth", "fiftyDayAverage", "beta", "dividendRate", "exDividendDate", "priceToSalesTrailing12Months", "enterpriseToRevenue", "profitMargins", "enterpriseToEbitda", "trailingEps", "forwardEps", "priceToBook", "bookValue", "pegRatio", "earningsQuarterlyGrowth", "bid", "volume", "trailingPE", "forwardPE", "heldPercentInstitutions", "heldPercentInsiders" ] mess += ''.join([ "T_EPS->F_EPS: ", str( Utils.calc_perc(financials.iloc[0].trailingEps, financials.iloc[0].forwardEps)), "%\n\r", "T_PE->F_PE: ", str( Utils.calc_perc(financials.iloc[0].trailingPE, financials.iloc[0].forwardPE)) + "%\n\r" ]) for item in cols: # financials[item].dropna(inplace=True) first = financials.iloc[0][item] last = financials.iloc[-1][item] mess += ''.join([ item + ": ", str(Utils.human_format(first)), " -> ", str(Utils.human_format(last)), " | ", str(Utils.calc_perc(first, last)), "%\n\r", ]) mess += ''.join([ str(financials.iloc[0].sector), ' | ', str(financials.iloc[0].industry), "\n\r", str("Current Price: "), ' | ', str(curr_price), "\n\r", str("Days to earn.: "), ' | ', str(days_to_earnings), " D", "\n\r" ]) if earnings is not None and len(earnings) > 0: mess += str("Earn. est. | act. | surp.: ") + str(earnings.iloc[-1].epsestimate) + \ ' | ' + str(earnings.iloc[-1].epsactual) + \ ' | ' + str(earnings.iloc[-1].epssurprisepct) + "\n\r" if sentiment is not None and len(sentiment) > 0: mess += str("Sentiment article/title: ") + str(sentiment.sentiment_summary_avg.to_list()) + \ '/' + str(sentiment.sentiment_title_avg.to_list()) if sentiment is not None and len(sentiment)>0 else str("Sentiment: NaN ") + "\n\r" if financials is not None and len(financials) > 0: mess += str(financials.iloc[0].longBusinessSummary) + "\n\r" sector_mess, spy_mess, vol_mess = self.get_common_mess(self.stocks) mess += "\n\r" + sector_mess mess += "\n\r" + spy_mess mess += "\n\r" + vol_mess hl = FinI.get_fib_hl(self.stocks, curr_price) mess += "\n\r" + "Loss: " + str(Utils.calc_perc(curr_price, hl["l"])) + "% " + " " + str(hl['l']) +" | "+\ " Price: " + str(curr_price) + \ " | " + "Profit: " + str(hl['h']) + \ " " + str(Utils.calc_perc(curr_price, hl["h"])) + "% \n\r" mess += self.get_fib_mess(self.stocks, curr_price) + "\n\r" print("get_fund_mess() - done") return mess def set_fundamentals(self, sym, last_date=None, tf={ "e": "-5d", "s": "-20d", "f": "-30d" }, tt={ "e": "14d", "s": "2d", "f": "0d" }): if last_date: self.db.last_date = last_date print("set_fund_mess() - done") self.earnings, self.sentiment, self.financials = self.db.get_fundamentals( sym=sym, tf=tf, tt=tt) def set_prices(self, sym=None, last_date=None, time_from="-90d", time_to="0d"): if last_date: self.db.last_date = last_date self.in_day_stocks = sdf.retype(self.db.get_last_n_days(sym)) self.stocks = sdf.retype( self.db.load_data(TableName.DAY, sym, time_from=time_from, time_to=time_to)) self.stocks = FinI.add_indicators(sdf.retype(self.stocks)) self.stocks = FinI.add_fib(self.stocks, last_rows=10) self.spy = sdf.retype( self.db.load_data(TableName.DAY, ["SPY"], time_from=time_from, time_to=time_to)) print("set_prices() - done")
class getData(): def __init__(self): self.engine = create_engine('postgresql://*****:*****@localhost:5432/nyse_financials') self.api = al.alpaca2Login().getApi() self.fin_db = "financials" self.earnings_db = "earning_dates" self.sentiment_db = "sentiment" self.nothingToGet = True self.db = Database() # df = pd.DataFrame() def get_bars(self, symbol, interval, limit, after): # print(after.isoformat()) data = self.api.get_barset(symbol, interval, limit, after=after.isoformat()) data = data.df[symbol] print(data) return data def get_sentiment(self, days_before=0, days_after=30): from stocknews import StockNews self.get_sentiment_from_csv() symbols = self.db.get_symbols() # print(symbols) sn = StockNews(symbols, wt_key='0d57e2849d73713e95f395c7440380ff') df_sum, r_count = sn.summarize() print("rows: " + str(r_count)) self.save_sentiment(df_sum) print("get sentiment ends") # print(df_new) return df_sum def get_sentiment_from_csv(self): df = pd.read_csv("./data/data.csv", sep=";") print(df) self.save_sentiment(df) def save_sentiment(self, df_sum): """[summary] !!!! WARNING this method ends with exiting whole script Args: df_sum ([type]): [description] """ try: dfdb = pd.read_sql(self.sentiment_db, con=self.engine) df_new = df_sum.append(dfdb, ignore_index=True) except: df_new = df_sum print("Database sentiment doesnt exists") try: df_new.drop(columns=['index','open','close','high','low','volume','change'], inplace=True) except KeyError : print("some columns to drop hasnt been found") df_new.drop_duplicates( subset=["id","stock", "news_dt"], inplace=True, keep="first") df_new.to_sql(self.sentiment_db, con=self.engine, if_exists='replace', index=True) print("Sentiment saved") exit() # return df_new def get_earnings(self, days_before = 0, days_after = 30): from yahoo_earnings_calendar import YahooEarningsCalendar dfdb = pd.read_sql(self.earnings_db, con=self.engine) yec = YahooEarningsCalendar() dfd = pd.DataFrame(yec.earnings_between( datetime.now() - timedelta(days=days_before), datetime.now() + timedelta(days=days_after))) df_new = dfd.append(dfdb, ignore_index=True) df_new.drop_duplicates(subset=["ticker","startdatetime","startdatetimetype"], inplace=True, keep="first") #save DATAFRAME to database df_new.to_sql(self.earnings_db, con=self.engine, if_exists='replace', index=False) print(df_new) return df_new # def convertUnixTimeToDate(columns,df): # for col in columns: # df[col] = pd.to_datetime(df[col],unit="s") # return df def fill_database(self, dfs,interval, limit, table_name, after): self.nothingToGet = True for row in dfs['Symbol']: if row: row = str.strip(row) print(row) # check last date for specific symbol dfp = pd.read_sql('select MAX("index") as last_time from '+ table_name + ' where sym = \'' + row + '\' ', con=self.engine) if dfp.iloc[0].last_time is not None: after = dfp.iloc[0].last_time # get data from ALPACA df = self.get_bars(row, interval, limit, after) if len(df) > 0: self.nothingToGet = False # add symbol df["sym"] = row #add sector # dff = pd.read_sql('select sector from '+ self.fin_db + ' where symbol = \'' + row + '\' and sector is not null limit 1', con=self.engine) # if len(dff) > 0 and dff.iloc[0].sector: # df["sector"] = dff.iloc[0].sector df.index.rename('index', inplace = True) #save DATAFRAME to database df.to_sql(table_name, con=self.engine, if_exists='append', index = True) if table_name == TableName.MIN15: self.save_bar_as_last_in_day(df) def get_last_working_day(self): offset = max(0, (datetime.today().weekday() + 6) % 7 - 3) timedelta2 = timedelta(offset) # most_recent = datetime.today().replace(hour=0, minute=0, second=0, microsecond=0) - timedelta2 most_recent = datetime.today() - timedelta2 return most_recent def save_bar_as_last_in_day(self,last_bar:pd.DataFrame): last_day = self.db.get_last_n_days( sym=last_bar.iloc[-1].sym, n_days_back=1, table=TableName.DAY) last_day.iloc[-1].close = last_bar.iloc[-1].close last_day.iloc[-1].high = last_day.iloc[-1].high if last_day.iloc[-1].high > last_bar.iloc[-1].high else last_bar.iloc[-1].high last_day.iloc[-1].low = last_day.iloc[-1].low if last_day.iloc[-1].low < last_bar.iloc[-1].low else last_bar.iloc[-1].low last_day.to_sql(TableName.DAY, con=self.engine, if_exists='replace', index=False) # param interval could be 1,5,15, 0 - for day def start_download(self, min_interval, start_date, infinity = False): dfs = pd.read_csv("./datasets/RevolutStock.csv", delimiter="|") print(start_date) min_interval = int(min_interval) if min_interval > 0: db_name = 'p_'+ str(min_interval) +'min' else: db_name = 'p_day' while True: try: if min_interval > 0: self.fill_database(dfs,str(min_interval) + "Min",1000, 'p_'+ str(min_interval) +'min', start_date) else: self.fill_database(dfs,"day",1000, 'p_day', start_date) if infinity and self.nothingToGet: break Utils.countdown(60) except KeyboardInterrupt: print("END by keybord interruption") exit() except: print("Unexpected error:", sys.exc_info()[0]) print("Waiting 3 minutes and try it again") Utils.countdown(60) print("DONE")
class RunData(): selected_stock = None timetick = None time_from = None time_to = None selected = {} action_type = None types = ["sector-stats", "stock-detail", "stocks-stats"] sw = StockWhisperer() inday_days = 2 def __init__(self): self.db = Database() self.symbols = self.db.get_symbols(TableName.DAY) self.sectors = self.db.get_sectors(TableName.DAY) self.sm = StockMess() self.ss = SectorStats() self.app = self.get_home_page() self.submit = None # self.fig = None # print(self.df) # def load_data(self, option, time_from = "-180d", time_to = None): # df = self.db.load_data( # "p_day", symbols=option, time_from=time_from, time_to = time_to) # df = FinI.add_indicators(sdf.retype(df)) # return df def testing_mess(self): self.sm.stocks = self.db.load_data( table_name=TableName.DAY, symbols=["PLUG"], time_from=self.time_from, time_to=self.time_to, ) self.sm.get_subj_mess("Base Fund: ", "PLUG") def get_home_page(self): query_params = st.experimental_get_query_params() if len(query_params) > 0 and query_params.get("type")[0] == "detail": st.set_page_config(initial_sidebar_state="collapsed", page_title=query_params.get("sym")[0], layout="wide") else: st.set_page_config(layout="wide") self.hide_footer() self.left_menu() # self.testing_mess() self.action_router(query_params) async def prepare_detail_tasks(self, sym=None): tasks = [] tasks.append(asyncio.ensure_future(self.get_price_detail(sym=sym))) tasks.append(asyncio.ensure_future( self.get_inday_price_graph(sym=sym))) tasks.append(asyncio.ensure_future(self.get_fund_detail(sym=sym))) await asyncio.gather(*tasks, return_exceptions=True) def left_menu(self): self.time_from = st.sidebar.text_input("Time from now -1m, -1h, -1d,", value="-120d") self.time_to = st.sidebar.text_input("Time to 1m, 1h, 1d,") self.selected_sector = st.sidebar.selectbox('Select sector', self.sectors) self.selected_stock = st.sidebar.selectbox('Select stock', self.symbols) self.inday_days = st.sidebar.number_input('inday chart days', value=2) if self.selected_stock == 0: self.selected_stock = "TSLA" # loop = asyncio.get_event_loop() # task = None # try: # task = loop.create_task(self.watch()) # except KeyboardInterrupt: # task.cancel() # print('after async') # st.sidebar.text_area("websocket",self.timetick) # self.action_type = st.sidebar.selectbox( # 'Seeect Type', # self.types) # self.submit = st.sidebar.button("Submit", "submit") def action_router(self, query_params=None): if st.sidebar.button('stock-detail') or ( len(query_params) > 0 and query_params.get("type")[0] == "detail"): asyncio.new_event_loop().run_until_complete( self.prepare_detail_tasks(sym=query_params.get("sym")[0] if len(query_params) > 0 else None)) if st.sidebar.button('top-sectors'): self.top_sectors(time_from=self.time_from, time_to=self.time_to) if st.sidebar.button('top-industries'): self.top_sectors(time_from=self.time_from, time_to=self.time_to, is_industries=True) if st.sidebar.button('top-stocks'): self.top_stocks(time_from=self.time_from, time_to=self.time_to) if st.sidebar.button('bottom-stocks'): self.top_stocks(time_from=self.time_from, time_to=self.time_to, ascending=True) if st.sidebar.button("find-stocks-to-buy"): self.find_stocks_to_buy() if st.sidebar.button("Last-Financials"): self.last_financials() def last_financials(self): df = self.db.get_last_financials() df.dropna(inplace=True, axis='columns', how="all") df.drop(columns=['zip','city','phone','longBusinessSummary','companyOfficers','maxAge','address1','previousClose', \ 'regularMarketOpen','regularMarketDayHigh','navPrice','totalAssets','regularMarketPreviousClose','open','yield', \ 'priceHint', 'currency', 'dayLow', 'ask', 'askSize','website','longName', \ 'exchange'], inplace=True) df.set_index(df.symbol, inplace=True) st.dataframe(df, height=2000) def find_stocks_to_buy(self): st.title("Stocks to buy") self.sw.time_from = self.time_from if self.sectors is not None: self.sw.sectors = [self.sectors] self.sw = StockWhisperer() try: output = self.sw.find_stocks(TableName.DAY, False) except KeyboardInterrupt: st.write("stopped by keyboard") stocks = output[[ "close", "open", "high", "low", "volume", "amount", "flpd", "sym" ]] # print(stocks) self.print_stocks_list(stocks, True, from_top=0, show_stocks_num=50) def show_sectors(self, stocks, is_industries=False): fig = px.bar(stocks, y='flpd', x=stocks.index) # fig.update_traces(texttemplate=stocks.sector, textposition='inside') fig.update_layout(uniformtext_minsize=8, uniformtext_mode='hide', barmode='group') st.plotly_chart( fig, use_container_width=True, use_container_height=True, template="plotly_dark", ) # st.bar_chart(stocks) def top_sectors(self, ascending=False, time_from=None, time_to=None, is_industries=False): # st.write(time_to) # st.write(time_from) title = "Top industries" if is_industries else "Top sectors" separator = " | " st.title(title + str(time_from)) if not time_from: time_from = "-7d" table = TableName.DAY if time_from.find("m") > -1 or time_from.find("m") > -1: table = TableName.MIN15 stocks = self.ss.classify_sectors_uptrend(table_name=table, time_from=time_from, time_to=time_to, from_db=True, is_industries=is_industries, separator=separator) if stocks is not None and len(stocks) > 0: stocks = stocks.sort_values(by='flpd', ascending=ascending) stocks.drop( columns=["close", "open", "high", "low", "volume", "amount"], inplace=True) self.show_sectors(stocks, is_industries=is_industries) for idx, row in stocks.iterrows(): st.write(str(idx) + ": " + str(round(row.flpd, 2)) + "%") self.top_stocks(group=idx, ascending=ascending, time_from=time_from, time_to=time_to, table=table, is_industries=is_industries, separator=separator) else: st.write("No data") def top_stocks(self, group=None, ascending=False, time_from=None, time_to=None, table=None, from_top=0, show_stocks_num=20, is_industries=False, separator=None): st.empty() table = TableName.DAY if time_from.find("m") > -1: table = TableName.MIN15 subject = "Loosers: " if ascending else "Gainers: " if isinstance(group, str): industry = str.split(group, separator) group = industry[1] if len(industry) > 1 else industry[0] group = [group] if is_industries: stocks = self.db.load_data( table_name=table, industries=group, time_from=time_from, time_to=time_to, ) else: stocks = self.db.load_data( table_name=table, sectors=group, time_from=time_from, time_to=time_to, ) # self.stocks = FinI.add_change(self.stocks) stocks = Utils.add_first_last_perc_diff(stocks) self.print_stocks_list(stocks, ascending, from_top=from_top, show_stocks_num=show_stocks_num) def print_stocks_list(self, stocks, ascending, from_top=0, show_stocks_num=20): if stocks is not None and len(stocks) > 0: stocks = stocks.groupby(by="sym").mean() stocks = stocks.sort_values(by='flpd', ascending=ascending) top_stocks = stocks.iloc[from_top:(from_top + show_stocks_num)] top_stocks = self.fill_with_mess(top_stocks) reduced_top_stocks = top_stocks.drop( columns=["open", "high", "low", "amount"]) reduced_top_stocks["detail"] = '<a href="/?type=detail&sym=' + \ reduced_top_stocks.index + '" target="_blank"> ' + \ reduced_top_stocks.index + '</a>' reduced_top_stocks["news"] = '<a href="https://finance.yahoo.com/quote/' + \ reduced_top_stocks.index + '" target="_blank"> yahoo </a>' reduced_top_stocks["rating"] = '<a href="https://zacks.com/stock/quote/' + \ reduced_top_stocks.index + '" target="_blank"> zacks </a>' st.write(reduced_top_stocks.to_html(escape=False, index=False), unsafe_allow_html=True) # selected_indices = st.multiselect('Select rows:', stocks.index) # selected_rows = stocks.loc[selected_indices] # self.top_stocks_list = top_stocks.index.tolist() # self.draw_chart_values(top_stocks) #send_mails # asyncio.run(self.sm.mail_stats(top_stocks, subject)) else: print('No stocks has been found') def fill_with_mess(self, stocks): mess_block = [] for index, row in stocks.iterrows(): self.sm.set_fundamentals(index) # st.write(index) mess, curr_price, days_to_earnings = self.sm.get_subj_mess( "", index) mess_block.append(mess) # print(stocks.loc[index]) stocks["fund"] = mess_block return stocks def set_time_to(self): if self.time_from is None: time_from = "-180d" else: time_from = self.time_from return time_from async def get_inday_price_graph(self, sym=None): if sym is None: sym = self.selected_stock inday_df = self.db.get_last_n_days(sym, n_days_back=self.inday_days, table=TableName.MIN15) inday_df = FinI.add_indicators(sdf.retype(inday_df)) await self.inday_price_graph(sym, inday_df) async def get_price_detail(self, sym=None): if sym is None: sym = self.selected_stock time_from = self.set_time_to() df = self.db.load_data( table_name=TableName.DAY, symbols=sym, time_from=time_from, time_to=self.time_to, ) m_df_spy = self.db.load_data(table_name=TableName.DAY, time_from=time_from, time_to=self.time_to, symbols=["SPY"]) m_df_spy["oc_mean"] = (m_df_spy.close + m_df_spy.open) / 2 # self.stocks = FinI.add_change(self.stocks) df = FinI.add_indicators(sdf.retype(df)) await self.price_graph(sym, df, m_df_spy=m_df_spy) # self.macd_rsi_graph(option, df) self._max_width_() # await asyncio.sleep(0.001) async def get_fund_detail(self, sym=None): if sym is None: sym = self.selected_stock self.sm.set_fundamentals(sym) time_from = self.set_time_to() self.sm.stocks = self.db.load_data( table_name=TableName.DAY, symbols=sym, time_from=time_from, time_to=self.time_to, ) mess, curr_price, days_to_earnings = self.sm.get_subj_mess( "Base Fund: ", sym) st.write(mess) await st.write( self.sm.get_fund_mess(self.sm.financials, curr_price, self.sm.earnings, self.sm.sentiment, days_to_earnings, self.sm.stocks)) def macd_rsi_graph(self, option, df): data = PlotP.plot_rsi(df, ax="y") data += PlotP.plot_macd_boll(df=df, ax="y2") fig = go.Figure(data=data) fig.update_layout(autosize=True, height=400, yaxis=dict(title="RSI", titlefont=dict(color="green"), tickfont=dict(color="green")), yaxis2=dict(title="macd", titlefont=dict(color="#8888ff"), tickfont=dict(color="#8888ff"), anchor="free", overlaying="y", side="left", position=0)) # Create figure with secondary y-axis st.plotly_chart(fig, use_container_width=True) def gainers(self): pass def hide_footer(self): hide_streamlit_style = """ <style> #MainMenu {visibility: visible;} footer {visibility: hidden;} </style> """ st.markdown(hide_streamlit_style, unsafe_allow_html=True) # def sector_stats(self, time_from, time_to, loosers): # stocks = self.ss.classify_sectors_uptrend(table_name =TableName.DAY) # stocks = stocks.sort_values(by='flpd', ascending=loosers) # if False: # self.sw.sectors = [self.sw.stocks.iloc[:-1].index[0]] # self.sw.top_stocks(table_name=None, top_losers=loosers) def inday_price_graph(self, option, df, ax="y2"): st.write("In day chart: -" + str(self.inday_days) + "d") sets = [{ 'x': df["index"], 'open': df.open, 'close': df.close, 'high': df.high, 'low': df.low, 'yaxis': ax, "hovertext": "", 'type': 'candlestick' }] sets += [{ 'x': df["index"], 'y': df.boll, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 1, 'color': 'green' }, 'name': 'Boll' }] sets += [{ 'x': df["index"], 'y': df.boll + df.boll_2, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 0.3, 'color': 'green', "dash": "dot" }, 'name': '-' }] sets += [{ 'x': df["index"], 'y': df.boll + df.boll_3, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 0.3, 'color': 'green', "dash": "dot" }, 'name': '-' }] # sets += [{'x': df["index"], 'y': df.boll + df.boll_5, 'yaxis': ax, 'type': 'scatter', # 'mode': 'lines', 'line': {'width': 0.3, 'color': 'green'}, 'name': '-'}] sets += [{ 'x': df["index"], 'y': df.boll + df.boll_6, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 0.3, 'color': 'green', "dash": "dot" }, 'name': '-' }] sets += [{ 'x': df["index"], 'y': df.boll - df.boll_2, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 0.3, 'color': 'green', "dash": "dot" }, 'name': '-' }] sets += [{ 'x': df["index"], 'y': df.boll - df.boll_3, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 0.3, 'color': 'green', "dash": "dot" }, 'name': '-' }] # sets += [{'x': df["index"], 'y': df.boll - df.boll_5, 'yaxis': ax, 'type': 'scatter', # 'mode': 'lines', 'line': {'width': 0.3, 'color': 'green'}, 'name': '-'}] sets += [{ 'x': df["index"], 'y': df.boll - df.boll_6, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 0.3, 'color': 'green', "dash": "dot" }, 'name': '-' }] sets += [{ 'x': df["index"], 'y': df.boll_ub, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 1, 'color': 'green' }, 'name': 'Boll UP' }] sets += [{ 'x': df["index"], 'y': df.boll, 'yaxis': ax, 'type': 'scatter', "fill": 'tonexty', 'line': { 'width': 0, }, "fillcolor": 'rgba(128, 255, 128,0.2)' }] sets += [{ 'x': df["index"], 'y': df.boll_lb, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 1, 'color': 'green' }, 'name': 'Boll Down' }] sets += [{ 'x': df["index"], 'y': df.boll, 'yaxis': ax, 'type': 'scatter', "fill": 'tonexty', 'line': { 'width': 0, }, "fillcolor": 'rgba(128, 255, 128,0.2)' }] sets += [{ 'x': df["index"], 'y': df.sma9, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 1, 'color': 'blue' }, 'name': 'sma9' }] sets += [{ 'x': df["index"], 'y': df.sma50, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 1, 'color': 'darkblue' }, 'name': 'sma50' }] sets += [{ 'x': df["index"], 'y': df.sma100, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 1, 'color': 'orange' }, 'name': 'sma100' }] df = FinI.add_levels(df) for i, r in df.iterrows(): if r.price_level is not None: sets += [{ 'x': [r["index"], df.iloc[-1]["index"]], 'y': [r.price_level, r.price_level], 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 1, 'color': 'brown', "dash": "dot" }, 'name': '' }] # print(levels) # sets += [{'x': df["index"], 'y': df.price_level, 'yaxis': ax, 'type': 'scatter', # 'mode': 'lines', 'line': {'width': 1, 'color': 'orange'}, 'name': 'sma100'}] # data += PlotP.plot_rsi(df, ax="y2") # data += PlotP.plot_macd_boll(df=df, ax="y3") # st.area(df, x=df["index"], y=df.boll, color="continent", # line_group="country") # fig = go.Figure(data=sets) fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.009, horizontal_spacing=0.009, row_width=[0.1, 0.5], specs=[[{ "secondary_y": True }], [{ "secondary_y": True }]]) fig.add_traces(data=sets, cols=1, rows=1) # data = PlotP.plot_rsi(df, ax="y") # fig.add_traces(data, 3, 1) # data = PlotP.plot_macd_boll(df=df, ax="y2") # fig.add_traces(data, 3, 1) df.loc[df.open > df.close, "vol_color"] = "red" df.loc[df.open <= df.close, "vol_color"] = "green" # print(df.vol_color) fig.add_trace( { 'x': df["index"], 'y': df.volume, 'type': 'bar', 'name': 'Volume', 'marker_color': df.vol_color }, 2, 1, secondary_y=False, ) # fig['layout']['margin'] = {'l': 30, 'r': 10, 'b': 50, 't': 25} fig.update_yaxes(showgrid=True, zeroline=False, showticklabels=True, showspikes=True, spikemode='across', spikesnap='cursor', showline=True, spikedash='dash', spikethickness=0.5) fig.update_xaxes(showgrid=True, zeroline=False, rangeslider_visible=False, showticklabels=True, showspikes=True, showline=True, spikemode='across', spikesnap='cursor', spikedash='dash', spikethickness=0.5) fig.update_layout(autosize=True, height=600, hoverdistance=1, hovermode='y', spikedistance=10000) st.plotly_chart( fig, use_container_width=True, use_container_height=True, template="plotly_dark", ) # st.line_chart(df.close) def price_graph(self, option, df, m_df_spy=None, ax="y2"): st.write("Days chart: " + str(self.time_from)) sets = [{ 'x': df.index, 'open': df.open, 'close': df.close, 'high': df.high, 'low': df.low, 'yaxis': ax, "hovertext": "", 'type': 'candlestick' }] sets += [{ 'x': df.index, 'y': df.boll, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 1, 'color': 'green' }, 'name': 'Boll' }] sets += [{ 'x': df.index, 'y': df.boll + df.boll_2, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 0.3, 'color': 'green', "dash": "dot" }, 'name': '-' }] sets += [{ 'x': df.index, 'y': df.boll + df.boll_3, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 0.3, 'color': 'green', "dash": "dot" }, 'name': '-' }] # sets += [{'x': df.index, 'y': df.boll + df.boll_5, 'yaxis': ax, 'type': 'scatter', # 'mode': 'lines', 'line': {'width': 0.3, 'color': 'green'}, 'name': '-'}] sets += [{ 'x': df.index, 'y': df.boll + df.boll_6, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 0.3, 'color': 'green', "dash": "dot" }, 'name': '-' }] sets += [{ 'x': df.index, 'y': df.boll - df.boll_2, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 0.3, 'color': 'green', "dash": "dot" }, 'name': '-' }] sets += [{ 'x': df.index, 'y': df.boll - df.boll_3, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 0.3, 'color': 'green', "dash": "dot" }, 'name': '-' }] # sets += [{'x': df.index, 'y': df.boll - df.boll_5, 'yaxis': ax, 'type': 'scatter', # 'mode': 'lines', 'line': {'width': 0.3, 'color': 'green'}, 'name': '-'}] sets += [{ 'x': df.index, 'y': df.boll - df.boll_6, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 0.3, 'color': 'green', "dash": "dot" }, 'name': '-' }] sets += [{ 'x': df.index, 'y': df.boll_ub, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 1, 'color': 'green' }, 'name': 'Boll UP' }] sets += [{ 'x': df.index, 'y': df.boll, 'yaxis': ax, 'type': 'scatter', "fill": 'tonexty', 'line': { 'width': 0, }, "fillcolor": 'rgba(128, 255, 128,0.2)' }] sets += [{ 'x': df.index, 'y': df.boll_lb, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 1, 'color': 'green' }, 'name': 'Boll Down' }] sets += [{ 'x': df.index, 'y': df.boll, 'yaxis': ax, 'type': 'scatter', "fill": 'tonexty', 'line': { 'width': 0, }, "fillcolor": 'rgba(255, 128, 128,0.2)' }] sets += [{ 'x': df.index, 'y': df.sma9, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 1, 'color': 'blue' }, 'name': 'sma9' }] sets += [{ 'x': df.index, 'y': df.sma50, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 1, 'color': 'darkblue' }, 'name': 'sma50' }] sets += [{ 'x': df.index, 'y': df.sma100, 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 1, 'color': 'orange' }, 'name': 'sma100' }] df = FinI.add_levels(df) for i, r in df.iterrows(): if r.price_level is not None: sets += [{ 'x': [i, df.iloc[-1].name], 'y': [r.price_level, r.price_level], 'yaxis': ax, 'type': 'scatter', 'mode': 'lines', 'line': { 'width': 1, 'color': 'brown', "dash": "dot" }, 'name': '' }] # print(levels) # sets += [{'x': df.index, 'y': df.price_level, 'yaxis': ax, 'type': 'scatter', # 'mode': 'lines', 'line': {'width': 1, 'color': 'orange'}, 'name': 'sma100'}] # data += PlotP.plot_rsi(df, ax="y2") # data += PlotP.plot_macd_boll(df=df, ax="y3") # st.area(df, x=df.index, y=df.boll, color="continent", # line_group="country") # fig = go.Figure(data=sets) fig = make_subplots(rows=3, cols=1, shared_xaxes=True, vertical_spacing=0.009, horizontal_spacing=0.009, row_width=[0.2, 0.1, 0.5], specs=[[{ "secondary_y": True }], [{ "secondary_y": True }], [{ "secondary_y": True }]]) fig.add_traces(data=sets, cols=1, rows=1) if m_df_spy is not None: fig.add_trace( { 'x': m_df_spy.index, 'y': m_df_spy.oc_mean, 'type': 'scatter', 'yaxis': "y", 'mode': 'lines', 'line': { 'width': 1, 'color': 'red' }, 'name': 'SPY' }, 1, 1, secondary_y=True, ) # data = PlotP.plot_rsi(df, ax="y") # fig.add_traces(data, 3, 1) mb = PlotP.plot_macd_boll(df=df, ax="y") fig.add_traces( data=mb, rows=3, cols=1, ) rsi = PlotP.plot_rsi(df=df, ax="y3") fig.add_traces(data=rsi, rows=3, cols=1, secondary_ys=[True, True, True, True, True]) df.loc[df.open > df.close, "vol_color"] = "red" df.loc[df.open <= df.close, "vol_color"] = "green" # print(df.vol_color) fig.add_trace( { 'x': df.index, 'y': df.volume, 'type': 'bar', 'name': 'Volume', 'marker_color': df.vol_color }, 2, 1, secondary_y=False, ) # fig['layout']['margin'] = {'l': 30, 'r': 10, 'b': 50, 't': 25} fig.update_yaxes(showgrid=True, zeroline=False, showticklabels=True, showspikes=True, spikemode='across', spikesnap='cursor', showline=True, spikedash='dash', spikethickness=0.5) fig.update_xaxes(showgrid=True, zeroline=False, rangeslider_visible=False, showticklabels=True, showspikes=True, showline=True, spikemode='across', spikesnap='cursor', spikedash='dash', spikethickness=0.5) fig.update_layout( autosize=True, height=600, hoverdistance=1, hovermode='y', spikedistance=10000, ) st.plotly_chart( fig, use_container_width=True, use_container_height=True, template="plotly_dark", ) # st.line_chart(df.close) def _max_width_(self): max_width_str = f"max-width: 2000px;max-height:1000px;" st.markdown( f""" <style> .reportview-container .main .block-container{{ {max_width_str} }} </style> """, unsafe_allow_html=True, )