예제 #1
0
    def calculate_earnings_score(organized_data):
        increase_percentage = Utils.safe_cast(organized_data['earnings_increase_percentage'], float, 0)
        strict_increase_percentage = Utils.safe_cast(organized_data['earnings_strict_increase_percentage'], float, 0)
        positive_percentage = Utils.safe_cast(organized_data['earnings_positive_percentage'], float, 0)
        num_years = Utils.safe_cast(organized_data['num_years'], int, 0)

        max_years = max(num_years, 10)

        values = [
            increase_percentage,
            strict_increase_percentage,
            positive_percentage,
            num_years / float(max_years)
        ]

        return Utils.average(values) * 100
예제 #2
0
    def analyze_ticker(ticker, time_to_live=30 * 24 * 60 * 60):
        try:
            analyzed_data = FileStorageDAO.get_analyzed_data(ticker)
            if time.time() - float(analyzed_data.get('last_updated_date', 0)) < time_to_live:
                return
        except FileNotFoundError:
            # do nothing if no file exists
            pass

        organized_data = FileStorageDAO.get_organized_data(ticker)
        earnings_score = DataAnalyzer.calculate_earnings_score(organized_data)
        revenue_score = DataAnalyzer.calculate_revenue_score(organized_data)
        earnings_growth_score = DataAnalyzer.calculate_earnings_growth_score(organized_data)
        revenue_growth_score = DataAnalyzer.calculate_revenue_growth_score(organized_data)
        overall_score = Utils.average([earnings_score, revenue_score, earnings_growth_score, revenue_growth_score])

        analyzed_data = {
            'price_target': DataAnalyzer.calculate_price_target(organized_data),
            'earnings_score': earnings_score,
            'earnings_growth_score': earnings_growth_score,
            'revenue_score': revenue_score,
            'revenue_growth_score': revenue_growth_score,
            'overall_score': overall_score,
            'organized_data': organized_data,
            'last_updated_date': time.time(),
        }

        FileStorageDAO.save_analyzed_data(ticker, analyzed_data)
예제 #3
0
    def organize_ticker(ticker, time_to_live=30 * 24 * 60 * 60):

        try:
            info = FileStorageDAO.get_organized_data(ticker)
            if time.time() - float(info.get('last_updated_date',
                                            0)) < time_to_live:
                return
        except FileNotFoundError:
            # do nothing
            pass

        income_statement = FileStorageDAO.get_income_statement(ticker)
        # balance_sheet = FileStorageDAO.get_balance_sheet(ticker)
        # cash_flow_statement = FileStorageDAO.get_cash_flow_statement(ticker)

        earnings = IncomeStatementUtilities.get_earnings(income_statement)
        revenue = IncomeStatementUtilities.get_revenue(income_statement)
        num_years = IncomeStatementUtilities.get_num_years(income_statement)

        organized_data = {
            # earnings attributes
            'average_earnings':
            Utils.average(earnings),
            'earnings':
            earnings,
            'earnings_positive_percentage':
            Utils.calculate_percent_positive(earnings),
            'earnings_increase_percentage':
            Utils.calculate_increase_percentage(earnings),
            'earnings_strict_increase_percentage':
            Utils.calculate_strict_increase_percentage(earnings),
            'earnings_growth':
            DataOrganizer.get_growth(earnings, num_years - 1),

            # revenue attributes
            'average_revenue':
            Utils.average(revenue),
            'revenue':
            revenue,
            'revenue_positive_percentage':
            Utils.calculate_percent_positive(revenue),
            'revenue_increase_percentage':
            Utils.calculate_increase_percentage(revenue),
            'revenue_strict_increase_percentage':
            Utils.calculate_strict_increase_percentage(revenue),
            'revenue_growth':
            DataOrganizer.get_growth(revenue, num_years - 1),
            'num_years':
            num_years,
            'last_updated_date':
            time.time(),
        }

        FileStorageDAO.save_organized_data(ticker, organized_data)
예제 #4
0
 def get_growth(statements, num_years, attr):
     if len(statements) < num_years or len(statements) == 0:
         return 'no data'
     try:
         starting_value = float(statements[num_years].get(attr))
         ending_value = float(statements[0].get(attr))
         return Utils.calculate_yoy_return(starting_value, ending_value,
                                           num_years)
     except:
         return 'error'
예제 #5
0
from scripts.utilities.utils import Utils
from scripts.report_generator import ReportGenerator

print(Utils.calculate_yoy_return(375, 1800))
print(Utils.calculate_yoy_return(1800, 375))
print(Utils.calculate_yoy_return(375, -1800))
print(Utils.calculate_yoy_return(-375, -1800))
print(Utils.calculate_yoy_return(-375, 1800))

ReportGenerator.generate_report('AMZN')
예제 #6
0
 def get_growth(values, num_years):
     if len(values) <= 1:
         return 0
     return Utils.calculate_yoy_return(values[0], values[-1], num_years)
예제 #7
0
class FinancialModelingPrepClient:

    API_KEY = Utils.get_api_key()
    INCOME_STATEMENT = 'income_statement'
    BALANCE_SHEET = 'balance_sheet'
    CASH_FLOW_STATEMENT = 'cash_flow_statement'

    @staticmethod
    def get_financial_ratios(ticker):
        url = 'https://financialmodelingprep.com/api/v3/key-metrics/' + ticker + '?apikey=' + FinancialModelingPrepClient.API_KEY
        return FinancialModelingPrepClient.json_get(url)

    @staticmethod
    def get_financial_ratios_ttm(ticker):
        url = 'https://financialmodelingprep.com/api/v3/ratios-ttm/' + ticker + '?apikey=' + FinancialModelingPrepClient.API_KEY
        return FinancialModelingPrepClient.json_get(url)

    @staticmethod
    def get_company_key_metrics_ttm(ticker):
        url = 'https://financialmodelingprep.com/api/v3/key-metrics-ttm/' + ticker + '?apikey=' + FinancialModelingPrepClient.API_KEY
        return FinancialModelingPrepClient.json_get(url)

    @staticmethod
    def get_company_quote_batch(tickers):
        tickers_str = ''
        for ticker in tickers:
            tickers_str += str(ticker) + ','
        url = 'https://financialmodelingprep.com/api/v3/quote/' + tickers_str + '?apikey=' + FinancialModelingPrepClient.API_KEY
        return FinancialModelingPrepClient.json_get(url)

    @staticmethod
    def get_financial_ratios_batch(tickers):
        """
        Financial Modeling Prep doesn't have a batch API, so just loop through and use the single API
        :param tickers: stock symbols to fetch for
        :return: a list of json that contains financial ratios
        """
        ret = []
        for ticker in tickers:
            ret.append(
                FinancialModelingPrepClient.get_financial_ratios(ticker))
        return ret

    @staticmethod
    def get_financial_ratios_ttm_batch(tickers):
        """
        Financial Modeling Prep doesn't have a batch API, so just loop through and use the single API
        :param tickers: stock symbols to fetch for
        :return: a list of json that contains financial ratios
        """
        ret = []
        for ticker in tickers:
            try:
                ret.append(
                    FinancialModelingPrepClient.get_financial_ratios_ttm(
                        ticker))
            except:
                ret.append({})
        return ret

    @staticmethod
    def get_company_key_metrics_ttm_batch(tickers):
        """
        Financial Modeling Prep doesn't have a batch API, so just loop through and use the single API
        :param tickers: stock symbols to fetch for
        :return: a list of json that contains financial ratios
        """
        ret = []
        for ticker in tickers:
            try:
                ret.append(
                    FinancialModelingPrepClient.get_company_key_metrics_ttm(
                        ticker))
            except:
                ret.append({})
        return ret

    @staticmethod
    def get_income_statement(ticker):
        return FinancialModelingPrepClient.get_income_statements_batch(
            [ticker])

    @staticmethod
    def get_income_statements_batch(tickers):
        return FinancialModelingPrepClient.get_batch(
            tickers, FinancialModelingPrepClient.INCOME_STATEMENT)

    @staticmethod
    def get_balance_sheet(ticker):
        return FinancialModelingPrepClient.get_balance_sheets_batch([ticker])

    @staticmethod
    def get_balance_sheets_batch(tickers):
        return FinancialModelingPrepClient.get_batch(
            tickers, FinancialModelingPrepClient.BALANCE_SHEET)

    @staticmethod
    def get_batch(tickers, statement_type):
        # TODO: See if the batch API is fixed..
        ret = []
        for ticker in tickers:
            # time.sleep(1)
            ret.append(
                FinancialModelingPrepClient.
                json_get_single_financial_statement(ticker, statement_type))
        return ret

    @staticmethod
    def get_cash_flow_sheet(ticker):
        return FinancialModelingPrepClient.get_cash_flow_sheets_batch([ticker])

    @staticmethod
    def get_cash_flow_statements_batch(tickers):
        return FinancialModelingPrepClient.get_batch(
            tickers, FinancialModelingPrepClient.CASH_FLOW_STATEMENT)

    @staticmethod
    def get_tickers():
        url = 'https://financialmodelingprep.com/api/v3/company/stock/list?apikey=' + FinancialModelingPrepClient.API_KEY
        return FinancialModelingPrepClient.json_get(url)

    @staticmethod
    def json_get(url, retries=3):
        # print('url: ' + url)
        num_tries = 0
        while num_tries < retries:
            try:
                response = urlopen(url)
                data = response.read().decode("utf-8")
                return json.loads(data)
            except Exception as err:
                num_tries += 1
                print("Error calling FinancialModelingPrep: {0}".format(err))
                print("Unexpected error:", sys.exc_info()[0])
                print("url: " + url)
                print('Retrying ' + str(num_tries))

        raise Exception('Error retrieving data from FinancialModelingPrep')

    @staticmethod
    def json_get_single_financial_statement(ticker, statement_type):
        if statement_type == 'income_statement':
            url = 'https://financialmodelingprep.com/api/v3/income-statement/'
        elif statement_type == FinancialModelingPrepClient.BALANCE_SHEET:
            url = 'https://financialmodelingprep.com/api/v3/balance-sheet-statement/'
        elif statement_type == 'cash_flow_statement':
            url = 'https://financialmodelingprep.com/api/v3/cash-flow-statement/'

        url = url + ticker + '?apikey=' + FinancialModelingPrepClient.API_KEY
        data = FinancialModelingPrepClient.json_get(url)

        return data

    @staticmethod
    def json_get_financial_statement(tickers, url):
        if len(tickers) <= 0:
            return

        arguments = tickers[len(tickers) - 1]
        for i in range(len(tickers) - 2, -1, -1):
            arguments += ',' + tickers[i]

        url = url + arguments + '?apikey=' + FinancialModelingPrepClient.API_KEY
        print('url ' + url)
        data = FinancialModelingPrepClient.json_get(url)

        try:
            data = data['financialStatementList']
        except KeyError:
            data = [data]
        return data
예제 #8
0
    def generate_report(ticker, time_to_live=0):
        try:
            info = FileStorageDAO.get_company_report(ticker)
            if time.time() - float(info.get('last_updated_date',
                                            0)) < time_to_live:
                return
        except (FileNotFoundError, json.decoder.JSONDecodeError):
            # continue on
            pass
        except BaseException as e:
            print("Unexpected exception when trying to generate report: " +
                  str(e))
            return

        income_statements = FinancialStatementConverter.convert_income_statement_data(
            ticker)
        balance_sheets = FinancialStatementConverter.convert_balance_statement_data(
            ticker)
        cash_flow_statements = FinancialStatementConverter.convert_cash_flow_statement_data(
            ticker)
        key_ratios = FinancialStatementConverter.convert_key_ratio_data(ticker)
        company_key_metrics_ttm = FinancialStatementConverter.convert_company_key_metrics_ttm_data(
            ticker)
        company_quote = FinancialStatementConverter.convert_company_quote_data(
            ticker)

        # Part 1 - Growth rates
        equity_growth = ReportGenerator.get_growth_list(
            balance_sheets, BalanceSheet.SHAREHOLDERS_EQUITY)
        revenue_growth = ReportGenerator.get_growth_list(
            income_statements, IncomeStatement.REVENUE)
        earnings_growth = ReportGenerator.get_growth_list(
            income_statements, IncomeStatement.NET_INCOME)
        operating_cash_growth = ReportGenerator.get_growth_list(
            cash_flow_statements, CashFlowStatement.OPERATING_CASH_FLOW)

        try:
            relevant_growth_rates = [
                equity_growth[2], equity_growth[9], revenue_growth[2],
                revenue_growth[9], earnings_growth[2], earnings_growth[9],
                operating_cash_growth[2], operating_cash_growth[9]
            ]

            # filter out any None values
            lowest_growth_rate = min(rate for rate in relevant_growth_rates
                                     if rate is not None)
            conservative_growth_rate = min(.15, lowest_growth_rate)
        except:
            lowest_growth_rate = 0
            conservative_growth_rate = 0

        # Part 2 - P/E and EPS
        pe_ratios = ReportGenerator.get_list(key_ratios, KeyRatios.PE_RATIO)

        positive_pe_ratios = Utils.remove_negative_numbers(pe_ratios)

        estimated_future_pe = max(
            min(lowest_growth_rate * 2 * 100,
                Utils.average(positive_pe_ratios)), 0)
        conservative_future_pe = 15

        if len(income_statements) > 0:
            eps = income_statements[0].get(IncomeStatement.EPS)
            eps_diluted = income_statements[0].get(IncomeStatement.EPS_DILUTED)
        else:
            eps = 0
            eps_diluted = 0

        if company_key_metrics_ttm is None:
            eps_ttm = 0
        else:
            eps_ttm = company_key_metrics_ttm.get(CompanyKeyMetricsTTM.EPS)

        if company_quote is None:
            shares_outstanding = 0
        else:
            shares_outstanding = company_quote.get(
                CompanyQuote.SHARES_OUTSTANDING)

        # Part 3 - Intrinsic value calculation
        intrinsic_value = Utils.calculate_intrinsic_value(
            eps, lowest_growth_rate, estimated_future_pe)
        conservative_intrinsic_value = Utils.calculate_intrinsic_value(
            eps_diluted, conservative_growth_rate, conservative_future_pe)

        intrinsic_value_ttm = Utils.calculate_intrinsic_value(
            eps_ttm, lowest_growth_rate, estimated_future_pe)
        conservative_intrinsic_value_ttm = Utils.calculate_intrinsic_value(
            eps_ttm, conservative_growth_rate, conservative_future_pe)

        # Part 4 - Create and populate the company report
        company_report = CompanyReport()
        company_report.set_attr(
            CompanyReport.DATES,
            ReportGenerator.get_list(income_statements, IncomeStatement.DATE))

        # Set growth rates
        company_report.set_attr(CompanyReport.EQUITY_GROWTH, equity_growth)
        company_report.set_attr(CompanyReport.REVENUE_GROWTH, revenue_growth)
        company_report.set_attr(CompanyReport.EARNINGS_GROWTH, earnings_growth)
        company_report.set_attr(CompanyReport.OPERATING_CASH_GROWTH,
                                operating_cash_growth)

        # Debt, Revenue, Earnings, Equity, ROIC, Return on Equity, Debt to Earnings, Shares Outstanding
        company_report.set_attr(
            CompanyReport.RETURN_ON_INVESTED_CAPITAL,
            ReportGenerator.get_list(key_ratios, KeyRatios.ROIC))
        company_report.set_attr(
            CompanyReport.RETURN_ON_EQUITY,
            ReportGenerator.get_list(key_ratios, KeyRatios.ROE))
        company_report.set_attr(
            CompanyReport.TOTAL_DEBT,
            ReportGenerator.get_list(balance_sheets, BalanceSheet.TOTAL_DEBT))
        company_report.set_attr(
            CompanyReport.REVENUE,
            ReportGenerator.get_list(income_statements,
                                     IncomeStatement.REVENUE))
        company_report.set_attr(
            CompanyReport.EARNINGS,
            ReportGenerator.get_list(income_statements,
                                     IncomeStatement.NET_INCOME))
        company_report.set_attr(CompanyReport.EPS_TTM, eps_ttm)
        company_report.set_attr(
            CompanyReport.EQUITY,
            ReportGenerator.get_list(balance_sheets,
                                     BalanceSheet.SHAREHOLDERS_EQUITY))

        # other
        company_report.set_attr(CompanyReport.TICKER, ticker)
        company_report.set_attr(CompanyReport.NUM_INCOME_STATEMENTS,
                                len(income_statements))
        company_report.set_attr(CompanyReport.NUM_BALANCE_SHEETS,
                                len(balance_sheets))
        company_report.set_attr(CompanyReport.NUM_CASH_FLOW_STATEMENTS,
                                len(cash_flow_statements))

        company_report.set_attr(CompanyReport.EPS, eps)
        company_report.set_attr(CompanyReport.EPS_DILUTED, eps_diluted)
        company_report.set_attr(CompanyReport.PE_RATIOS, pe_ratios)
        company_report.set_attr(CompanyReport.AVERAGE_PE_RATIO,
                                estimated_future_pe)
        company_report.set_attr(CompanyReport.SHARES_OUTSTANDING,
                                shares_outstanding)
        company_report.set_attr(
            CompanyReport.DEBT_TO_EARNINGS,
            ReportGenerator.get_list(key_ratios, KeyRatios.DEBT_TO_EARNINGS))

        company_report.set_attr(CompanyReport.INTRINSIC_VALUE, intrinsic_value)
        company_report.set_attr(CompanyReport.INTRINSIC_VALUE_GROWTH_RATE,
                                lowest_growth_rate)
        company_report.set_attr(CompanyReport.CONSERVATIVE_INTRINSIC_VALUE,
                                conservative_intrinsic_value)
        company_report.set_attr(
            CompanyReport.CONSERVATIVE_INTRINSIC_VALUE_GROWTH_RATE,
            conservative_growth_rate)

        company_report.set_attr(CompanyReport.INTRINSIC_VALUE_USING_TTM_EPS,
                                intrinsic_value_ttm)
        company_report.set_attr(
            CompanyReport.CONSERVATIVE_INTRINSIC_VALUE_USING_TTM_EPS,
            conservative_intrinsic_value_ttm)

        FileStorageDAO.save_report(company_report)

        # Part 5 - create and save the json version of the company report
        company_report_json = {
            CompanyReport.DATES:
            ReportGenerator.get_list(income_statements, IncomeStatement.DATE),
            CompanyReport.EQUITY_GROWTH:
            equity_growth,
            CompanyReport.REVENUE_GROWTH:
            revenue_growth,
            CompanyReport.EARNINGS_GROWTH:
            earnings_growth,
            CompanyReport.OPERATING_CASH_GROWTH:
            operating_cash_growth,
            CompanyReport.RETURN_ON_INVESTED_CAPITAL:
            ReportGenerator.get_list(key_ratios, KeyRatios.ROIC),
            CompanyReport.RETURN_ON_EQUITY:
            ReportGenerator.get_list(key_ratios, KeyRatios.ROE),
            CompanyReport.TOTAL_DEBT:
            ReportGenerator.get_list(balance_sheets, BalanceSheet.TOTAL_DEBT),
            CompanyReport.REVENUE:
            ReportGenerator.get_list(income_statements,
                                     IncomeStatement.REVENUE),
            CompanyReport.EARNINGS:
            ReportGenerator.get_list(income_statements,
                                     IncomeStatement.NET_INCOME),
            CompanyReport.EPS_TTM:
            eps_ttm,
            CompanyReport.EQUITY:
            ReportGenerator.get_list(balance_sheets,
                                     BalanceSheet.SHAREHOLDERS_EQUITY),
            CompanyReport.TICKER:
            ticker,
            CompanyReport.NUM_INCOME_STATEMENTS:
            len(income_statements),
            CompanyReport.NUM_BALANCE_SHEETS:
            len(balance_sheets),
            CompanyReport.NUM_CASH_FLOW_STATEMENTS:
            len(cash_flow_statements),
            CompanyReport.EPS:
            eps,
            CompanyReport.EPS_DILUTED:
            eps_diluted,
            CompanyReport.PE_RATIOS:
            pe_ratios,
            CompanyReport.AVERAGE_PE_RATIO:
            estimated_future_pe,
            CompanyReport.SHARES_OUTSTANDING:
            shares_outstanding,
            CompanyReport.DEBT_TO_EARNINGS:
            ReportGenerator.get_list(key_ratios, KeyRatios.DEBT_TO_EARNINGS),
            CompanyReport.INTRINSIC_VALUE:
            intrinsic_value,
            CompanyReport.INTRINSIC_VALUE_GROWTH_RATE:
            lowest_growth_rate,
            CompanyReport.CONSERVATIVE_INTRINSIC_VALUE:
            conservative_intrinsic_value,
            CompanyReport.CONSERVATIVE_INTRINSIC_VALUE_GROWTH_RATE:
            conservative_growth_rate,
            CompanyReport.INTRINSIC_VALUE_USING_TTM_EPS:
            intrinsic_value_ttm,
            CompanyReport.CONSERVATIVE_INTRINSIC_VALUE_USING_TTM_EPS:
            conservative_intrinsic_value_ttm,
            'last_updated_date':
            time.time(),
            'last_updated_date_human':
            str(datetime.datetime.now())
        }

        FileStorageDAO.save_company_report_json(ticker, company_report_json)