def get_holdings_stats(self, fund_symbol): """ Gets the top 25 companies in their portfolio, as well as the following stats: 1. Name 2. % portfolio weight 3. YTD return 4. Shares owned 5. Shares changed 6. P/E 7. Price 8. G/L % (gain/loss percent for the day) First get the first 25 most weighted companies from portfolio (desc) For each: 1. Equity view tab -Name -% portfolio weight -Shares owned -Shares changed -YTD return (could be positive, negative, float, or blank (-) ) -P/E (could be positive, negative, float, or blank (-) ) 2. Equity prices tab -Price -G/L % (gain/loss percent) Each tab is represented as a table -equity view tab: id = equity_holding_tab -get <tbody> with id holding_epage0 -equity prices tab: id = equityPrice_holding_tab Comparisons between 2+ mutual funds will compare Name and % portfolio weight only """ fund_symbol = fund_symbol.upper() response = {} try: Util.validate_format(fund_symbol) url = Util.build_url(Section.HOLDINGS_PAGE_TOP_25, fund_symbol) response = self.extractHoldings(url, fund_symbol) except FundException.ImproperSymbolFormatError as e: raise FundException.ImproperSymbolFormatError(e) except FundException.SymbolDoesNotExistError as e: raise FundException.SymbolDoesNotExistError(e) except FundException.UIChangedError as e: raise FundException.UIChangedError(e) except FundException.SourceEndpointChangedError as e: raise FundException.SourceEndpointChangedError(e) return response
def get_risk_stats(self, fund_symbol): """ Grabs risk stats. Grabs 8 things, for 4 time periods (3 year, 5 year, 10 year, 15 year): 1. Alpha 2. Beta 3. R-squared 4. Standard deviation 5. Sharpe ratio 6. Sortino ratio 7. Treynor ratio 8. Capture ratios Return in a JsonResponse encoded object """ #Add data from capture ratios first. We can get all data in capture ratios in 1 GET request, but need multiple GET requests for mpt and volatility fund_symbol = fund_symbol.upper() response = {} try: Util.validate_format(fund_symbol) response = self.get_capture_ratios(fund_symbol) timespans = ["3-Year", "5-Year", "10-Year", "15-Year"] for timespan in timespans: #Extract and aggregate data for MPT stats and Volatility stats mpt_and_volatility = self.get_mpt_and_volatility_data( fund_symbol, timespan) #Add these values into the current timespan dict along with the capture ratios response[timespan] = { **response[timespan], **mpt_and_volatility } except FundException.ImproperSymbolFormatError as e: raise FundException.ImproperSymbolFormatError(e) except FundException.SymbolDoesNotExistError as e: raise FundException.SymbolDoesNotExistError(e) except FundException.UIChangedError as e: raise FundException.UIChangedError(e) except FundException.SourceEndpointChangedError as e: raise FundException.SourceEndpointChangedError(e) return response
def get_performance_stats(self, fund_symbol): fund_symbol = fund_symbol.upper() stats = {} try: Util.validate_format(fund_symbol) stats["trailing_returns"] = self.get_trailing_returns(fund_symbol) stats["historical_returns"] = self.get_fund_historical_returns( fund_symbol) stats["10000_growth_data"] = self.get_10000_growth(fund_symbol) except FundException.ImproperSymbolFormatError as e: raise FundException.ImproperSymbolFormatError(e) except FundException.SymbolDoesNotExistError as e: raise FundException.SymbolDoesNotExistError(e) except FundException.UIChangedError as e: raise FundException.UIChangedError(e) except FundException.SourceEndpointChangedError as e: raise FundException.SourceEndpointChangedError(e) return stats
def get_general_stats(self, fund_symbol): """ Grabs general stats of the mutual fund. Grabs things: 1. Price (NAV) 2. Min. initial investment 3. Expense ratio 4. Asset allocation pie chart data(Morningstar's pie chart: Cash, US stock, Non-US stock, bonds, etc)Asset allocation pie chart data(Morningstar's pie chart: Cash, US stock, Non-US stock, bonds, etc) 5. Morningstar overall rating 6. Morningstar risk vs category 7. Morningstar return vs category 8. Morningstar category 9. Turnover ratio Source = Morningstar, quotes page """ fund_symbol = fund_symbol.upper() response = {} try: Util.validate_format(fund_symbol) sections = [ Section.GENERAL_STATS, Section.ASSET_ALLOCATION, Section.RISK_RETURN_VS_CATEGORY, Section.OVERALL_RATING ] for section in sections: response[str(section)] = self.get_section_data( section, fund_symbol) except FundException.ImproperSymbolFormatError as e: raise FundException.ImproperSymbolFormatError(e) except FundException.SymbolDoesNotExistError as e: raise FundException.SymbolDoesNotExistError(e) except FundException.UIChangedError as e: raise FundException.UIChangedError(e) except FundException.SourceEndpointChangedError as e: raise FundException.SourceEndpointChangedError(e) return response
def validate_format(fund_symbol): if len(fund_symbol) != 5 or re.match('^[A-Z]{5}$', fund_symbol) is None: raise FundException.ImproperSymbolFormatError(f"Fund symbol is not in the proper format (needs to be 5 characters, capitalized, no spaces, A-Z): {fund_symbol}")