Пример #1
0
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")
Пример #2
0
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")    
Пример #3
0
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,
        )