Beispiel #1
0
 def insert_quotes(self):
     print( "Insert new quotes" )
     mdb_query = Query()
     iex = Iex()
     #Get all symbols in MongoDB
     mdb_symbols_full = mdb_query.get_active_companies()
     #Get current date
     currDate = datetime.datetime.now().strftime("%Y-%m-%d")
     #Initial call to print 0% progress
     printProgressBar(0, len(mdb_symbols_full.index), prefix = 'Progress:', suffix = '', length = 50)
     idx_min = 0
     query_num = 100
     while idx_min < len(mdb_symbols_full.index):
         idx_max = idx_min + query_num
         if idx_max > len(mdb_symbols_full.index):
             idx_max = len(mdb_symbols_full.index)
         mdb_symbols = mdb_symbols_full.iloc[ idx_min:idx_max ]
         mdb_symbols.reset_index(drop=True, inplace=True)
         #Get latest price in MongoDB for each symbol up to 50 days ago
         mdb_quotes = mdb_query.get_quotes( mdb_symbols.tolist(), currDate, "latest" )
         #Loop through symbols
         iex_quotes = pandas.DataFrame()
         for index, mdb_symbol in mdb_symbols.iteritems():
             #Get matching quote in MongoDB
             if not mdb_quotes.empty:
                 mdb_quote = mdb_quotes[ mdb_quotes['symbol'] == mdb_symbol ]
             else:
                 mdb_quote = mdb_quotes
             #continue if already up to date
             if not mdb_quote.empty and (mdb_quote['date'].iloc[0] == currDate):
                 #Update progress bar
                 printProgressBar(idx_min+index+1, len(mdb_symbols_full.index), prefix = 'Progress:', suffix = "No new data for " + mdb_symbol + "      ", length = 50)
                 continue
             #Get quote from IEX
             iex_quote = iex.get_quote( mdb_symbol )
             #Select quotes more recent than MongoDB
             if not iex_quote.empty and not mdb_quote.empty:
                 mask = iex_quote['date'] > mdb_quote['date'].iloc[0]
                 iex_quote = iex_quote.loc[mask]
             #Insert if quotes exist
             if not iex_quote.empty:
                 #Update progress bar
                 printProgressBar(idx_min+index+1, len(mdb_symbols_full.index), prefix = 'Progress:', suffix = "Inserting quote for " + mdb_symbol + "      ", length = 50)
                 #Append quote
                 iex_quotes = iex_quotes.append(iex_quote, ignore_index=True, sort=False)
             else:
                 #Update progress bar
                 printProgressBar(idx_min+index+1, len(mdb_symbols_full.index), prefix = 'Progress:', suffix = "No new data for " + mdb_symbol + "      ", length = 50)
         #Bulk insert quotes
         if not iex_quotes.empty:
             self.db.iex_quotes.insert_many( iex_quotes.to_dict('records') )
         idx_min = idx_min + query_num
Beispiel #2
0
    def calculate_top_stocks(self, ref_date):
        """
        Calculate ranked list of stocks
        @params:
            ref_date    - Required  : date YYYY-MM-DD (Str)
        """

        mdb_query = Query()
        #Get ranked stock list for given date
        symbols = mdb_query.get_active_companies().tolist()
        print("Query balance sheets")
        balancesheets = mdb_query.get_balancesheets(symbols, ref_date,
                                                    "latest")
        #earnings = earnings[["EPSReportDate","actualEPS","fiscalEndDate","fiscalPeriod","symbol"]]
        #print( earnings )
        #Get financials within 6 months
        #print( "Query financials" )
        sixMonthsBeforeDate = (
            pandas.Timestamp(ref_date) +
            pandas.DateOffset(months=-6)).strftime('%Y-%m-%d')
        #financials = mdb_query.get_financials(symbols, sixMonthsBeforeDate, "after")
        balancesheets = balancesheets[
            balancesheets['reportDate'] >= sixMonthsBeforeDate]
        #financials = financials[["symbol","reportDate","netIncome","shareholderEquity"]]
        #print( financials )
        #Get prices for inception date
        print("Query prices")
        idx_min = 0
        query_num = 100
        prices = pandas.DataFrame()
        while idx_min < len(symbols):
            idx_max = idx_min + query_num
            if idx_max > len(symbols):
                idx_max = len(symbols)
            symbols_split = symbols[idx_min:idx_max]
            prices_split = mdb_query.get_quotes(symbols_split, ref_date,
                                                "latest")
            prices = prices.append(prices_split, ignore_index=True, sort=False)
            idx_min = idx_min + query_num
        #Get prices within 7 days
        fiveDaysBeforeDate = (pandas.Timestamp(ref_date) +
                              pandas.DateOffset(days=-7)).strftime('%Y-%m-%d')
        prices = prices[prices['date'] >= fiveDaysBeforeDate]
        prices.reset_index(drop=True, inplace=True)
        #print( prices )
        #Get company data
        company = mdb_query.get_company(symbols)
        company = company[['symbol', 'companyName']]
        #Merge dataframes together
        print("Merge dataframes")
        #merged = pandas.merge(earnings,financials,how='inner',left_on=["symbol","fiscalEndDate"],right_on=["symbol","reportDate"],sort=False)
        merged = pandas.merge(balancesheets,
                              prices,
                              how='inner',
                              on="symbol",
                              sort=False)
        merged = pandas.merge(merged,
                              company,
                              how='inner',
                              on='symbol',
                              sort=False)
        #Remove any rows with missing values
        merged = merged.dropna(
            axis=0,
            subset=['shareholderEquity', 'close', 'marketCap', 'peRatio'])
        #Calculate ROE
        #close / peRatio = EPS
        #marketCap / close = sharesOutstanding
        #sharesOutstanding * EPS = netIncome
        #netIncome / shareholderEquity = returnOnEquity
        merged = merged[merged.peRatio != 0]
        merged["EPS"] = merged.close / merged.peRatio
        merged = merged[merged.close != 0]
        merged["sharesOutstanding"] = merged.marketCap / merged.close
        merged["netIncome"] = merged.sharesOutstanding * merged.EPS
        merged = merged[merged.shareholderEquity != 0]
        merged["returnOnEquity"] = merged.netIncome / merged.shareholderEquity
        merged = merged[merged.returnOnEquity != 0]
        merged["peROERatio"] = merged.peRatio / merged.returnOnEquity
        #Count number of stocks above mcap value
        # A useful indicator of how universe compares to S&P500
        print("Universe before cuts...")
        print("mcap > 50M: " +
              str(merged[merged["marketCap"] > 50000000].count()["marketCap"]))
        print(
            "mcap > 100M: " +
            str(merged[merged["marketCap"] > 100000000].count()["marketCap"]))
        print(
            "mcap > 500M: " +
            str(merged[merged["marketCap"] > 500000000].count()["marketCap"]))
        print(
            "mcap > 1B: " +
            str(merged[merged["marketCap"] > 1000000000].count()["marketCap"]))
        print(
            "mcap > 5B: " +
            str(merged[merged["marketCap"] > 5000000000].count()["marketCap"]))
        print("mcap > 10B: " + str(merged[
            merged["marketCap"] > 10000000000].count()["marketCap"]))
        print("mcap > 50B: " + str(merged[
            merged["marketCap"] > 50000000000].count()["marketCap"]))
        print("mcap > 100B: " + str(merged[
            merged["marketCap"] > 100000000000].count()["marketCap"]))
        #Rank stocks
        #Cut negative PE and ROE
        merged = merged[(merged.peRatio > 0) & (merged.returnOnEquity > 0)]
        #Remove invalid stock symbols, and different voting options
        # Do the different voting options affect marketCap?
        #forbidden = [ "#", ".", "-" ]
        #merged = merged[ merged.apply( lambda x: not any( s in x['symbol'] for s in forbidden ), axis=1 ) ]
        #Remove American Depositary Shares
        #ads_str = 'American Depositary Shares'
        #merged = merged[ merged.apply( lambda x: ads_str not in x['companyName'], axis=1 ) ]
        #Remove industries that do not compare well
        # e.g. Companies that have investments as assets
        #forbidden_industry = ['Brokers & Exchanges','REITs','Asset Management','Banks']
        #merged = merged[ ~merged.industry.isin( forbidden_industry ) ]
        #Count number of stocks after cuts
        print("Universe after cuts...")
        print("mcap > 50M: " +
              str(merged[merged["marketCap"] > 50000000].count()["marketCap"]))
        print(
            "mcap > 100M: " +
            str(merged[merged["marketCap"] > 100000000].count()["marketCap"]))
        print(
            "mcap > 500M: " +
            str(merged[merged["marketCap"] > 500000000].count()["marketCap"]))
        print(
            "mcap > 1B: " +
            str(merged[merged["marketCap"] > 1000000000].count()["marketCap"]))
        print(
            "mcap > 5B: " +
            str(merged[merged["marketCap"] > 5000000000].count()["marketCap"]))
        print("mcap > 10B: " + str(merged[
            merged["marketCap"] > 10000000000].count()["marketCap"]))
        print("mcap > 50B: " + str(merged[
            merged["marketCap"] > 50000000000].count()["marketCap"]))
        print("mcap > 100B: " + str(merged[
            merged["marketCap"] > 100000000000].count()["marketCap"]))
        #Order by peROERatio
        merged = merged.sort_values(by="peROERatio",
                                    ascending=True,
                                    axis="index")

        return merged
Beispiel #3
0
 def insert_performance(self):
     print( "Insert portfolio performance tables" )
     mdb_query = Query()
     #Get current date
     currDate = datetime.datetime.now().strftime("%Y-%m-%d")
     #currDate = "2019-12-27"
     #Get existing portfolios
     portfolios = mdb_query.get_portfolios(currDate)[["portfolioID","inceptionDate"]]
     #Loop through portfolios
     for portfolio_index, portfolio_row in portfolios.iterrows():
         #Get portfolioID and inceptionDate
         portfolio = portfolio_row.portfolioID
         inceptionDate = portfolio_row.inceptionDate
         print( 'Inserting performance tables for ' + portfolio )
         #Get holdings tables from inception
         holdings = mdb_query.get_holdings(portfolio, inceptionDate, "after").sort_values(by="lastUpdated", ascending=False, axis="index")
         #print( holdings )
         #Default to calculating performance from inception
         date = inceptionDate
         #Get list of symbols in holdings table
         symbols = holdings["symbol"].unique().tolist()
         #Get existing performance table for portfolio sorted by date
         performance = mdb_query.get_performance([portfolio], inceptionDate)
         if not performance.empty:
             performance.sort_values(by="date", ascending=False, axis="index", inplace=True)
         #Get close value from last date and increment the date
         perf_tables = []
         prevCloseValue = 0
         adjPrevCloseValue = 0
         if not performance.empty:
             date = performance.iloc[0]["date"]
             date = (pandas.Timestamp(date) + pandas.DateOffset(days=1)).strftime('%Y-%m-%d')
             adjPrevCloseValue = performance.iloc[0]["closeValue"]
             prevCloseValue = performance.iloc[0]["closeValue"]
         #print( date )
         #Get prices for symbols in portfolio after date
         prices = mdb_query.get_quotes(symbols, date, "after")
         #print( prices )
         #If there are no prices then can't calculate performance
         if prices.empty:
             print( "No prices!" )
             continue
         #Get any transactions after date
         transactions = mdb_query.get_transactions(portfolio, date, "after")
         #print( transactions )
         #Loop through dates
         while date <= currDate:
             #print( date )
             #Initialize portfolio close of day values
             closeValue = 0
             adjCloseValue = 0
             #Get latest holding for each symbol on date
             holdings_date = holdings[holdings.lastUpdated <= date]
             holdings_date = holdings_date[holdings_date.groupby(['symbol'], sort=False)['lastUpdated'].transform(max) == holdings_date['lastUpdated']]
             #Merge with stock prices
             holdings_date = pandas.merge(holdings_date,prices[prices.date == date],how='left',left_on=["symbol"],right_on=["symbol"],sort=False)
             #Remove stocks no longer held
             holdings_date = holdings_date[ holdings_date['endOfDayQuantity'] != 0 ]
             #print( holdings_date )
             #Skip if only USD in holdings
             if holdings_date[holdings_date.symbol != "USD"].empty:
                 date = (pandas.Timestamp(date) + pandas.DateOffset(days=1)).strftime('%Y-%m-%d')
                 continue
             #Skip any day where there aren't prices for all stocks
             if holdings_date[holdings_date.symbol != "USD"]['close'].isnull().values.any():
                 date = (pandas.Timestamp(date) + pandas.DateOffset(days=1)).strftime('%Y-%m-%d')
                 continue
             #Calculate portfolio close of day value from close of day stock prices
             if not holdings_date.empty:
                 for index, holding in holdings_date.iterrows():
                     if holding.symbol == "USD":
                         closeValue = closeValue + (holding.endOfDayQuantity)
                     else:
                         closeValue = closeValue + (holding.endOfDayQuantity * holding.close)
             #Get any deposits or withdrawals
             deposits = pandas.DataFrame()
             withdrawals = pandas.DataFrame()
             if not transactions.empty:
                 deposits = transactions[(transactions.date == date) & (transactions.type == "deposit")]
                 withdrawals = transactions[(transactions.date == date) & (transactions.type == "withdrawal")]
             #print( deposits )
             #print( withdrawals )
             #Adjust close or previous close for withdrawals/deposits
             adjPrevCloseValue = prevCloseValue
             adjCloseValue = closeValue
             if not deposits.empty:
                 for index, deposit in deposits.iterrows():
                     adjPrevCloseValue = adjPrevCloseValue + (deposit.volume * deposit.price)
             if not withdrawals.empty:
                 for index, withdrawal in withdrawals.iterrows():
                     adjCloseValue = adjCloseValue + (withdrawal.volume * withdrawal.price)
             #If portfolio has no holdings or deposits yet then continue
             if adjPrevCloseValue == 0:
                 date = (pandas.Timestamp(date) + pandas.DateOffset(days=1)).strftime('%Y-%m-%d')
                 continue
             #Build portfolio performance table
             perf_table = { "portfolioID": portfolio,
                             "date": date,
                             "prevCloseValue": prevCloseValue,
                             "closeValue": closeValue,
                             "adjPrevCloseValue": adjPrevCloseValue,
                             "adjCloseValue": adjCloseValue,
                             "percentReturn": 100.*((adjCloseValue-adjPrevCloseValue)/adjPrevCloseValue) }
             perf_tables.append( perf_table )
             #Reset previous close values
             prevCloseValue = closeValue
             adjPrevCloseValue = closeValue
             #Increment date
             date = (pandas.Timestamp(date) + pandas.DateOffset(days=1)).strftime('%Y-%m-%d')
         #Insert performance table
         insert_pf_performance = True
         #print( perf_tables )
         if insert_pf_performance and len(perf_tables)>0:
             #print( perf_tables )
             self.db.pf_performance.insert_many( perf_tables )