def ohlson_o_score(stock: str, date: datetime = datetime.now(), lookback_period: timedelta = timedelta(days=0),
                   period: str = 'TTM'):
    TA = financials.total_assets(stock=stock, date=date, lookback_period=lookback_period, period=period)
    GNP = macroeconomic_analysis.gross_national_product_price_index(date)
    TL = financials.total_liabilities(stock=stock, date=date, lookback_period=lookback_period, period=period)
    WC = metrics.net_working_capital(stock=stock, date=date, lookback_period=lookback_period, period=period)
    CL = financials.total_current_liabilities(stock=stock, date=date, lookback_period=lookback_period, period=period)
    CA = financials.total_current_assets(stock=stock, date=date, lookback_period=lookback_period, period=period)
    X = 1 if TL > TA else 0
    NI = financials.net_income(stock=stock, date=date, lookback_period=lookback_period, period=period)
    NI_prev = financials.net_income(stock=stock, date=date, lookback_period=lookback_period, period=period)
    FFO = financials.cash_flow_operating_activities(stock=stock, date=date, lookback_period=lookback_period,
                                                    period=period)
    Y = 1 if (NI < 0 and NI_prev < 0) else 0
    return -1.32 - 0.407 * np.log(TA / GNP) + 6.03 * (TL / TA) - 1.43 * (WC / TA) + 0.0757 * (CL / CA) - 1.72 * X \
           - 2.37 * (NI / TA) - 1.83 * (FFO / TL) + 0.285 * Y - 0.521 * ((NI - NI_prev) / (abs(NI) + abs(NI_prev)))
예제 #2
0
def capital_employed(stock: str, date: datetime = datetime.now(), lookback_period: timedelta = timedelta(days=0),
                     period: str = ''):
    return fi.total_assets(stock=stock, date=date, lookback_period=lookback_period, period=period) \
           - fi.current_total_liabilities(stock=stock, date=date, lookback_period=lookback_period, period=period)
def altman_z_score(stock: str,
                   date: datetime = datetime.now(),
                   lookback_period: timedelta = timedelta(days=0),
                   period: str = 'TTM'):
    A = metrics.net_working_capital(stock=stock, date=date, lookback_period=lookback_period, period=period) \
        / financials.total_assets(stock=stock, date=date, lookback_period=lookback_period, period=period)
    B = financials.retained_earnings(stock=stock, date=date, lookback_period=lookback_period, period=period) \
        / financials.total_assets(stock=stock, date=date, lookback_period=lookback_period, period=period)
    C = metrics.earnings_before_interest_and_taxes(stock=stock, date=date, lookback_period=lookback_period,
                                                   period=period) \
        / financials.total_assets(stock=stock, date=date, lookback_period=lookback_period, period=period)
    D = financials.total_shareholders_equity(stock=stock, date=date, lookback_period=lookback_period, period=period) \
        / financials.total_liabilities(stock=stock, date=date, lookback_period=lookback_period, period=period)
    E = financials.net_sales(stock=stock, date=date, lookback_period=lookback_period, period=period) \
        / financials.total_assets(stock=stock, date=date, lookback_period=lookback_period, period=period)

    with open(
            os.path.join(config.ROOT_DIR, config.DATA_DIR_NAME,
                         config.MARKET_TICKERS_DIR_NAME, "nasdaq_df.pickle"),
            "rb") as f:
        nasdaq_tickers = pickle.load(f).index

    # for private manufacturing companies
    if stock not in nasdaq_tickers and 'Manufacturing' not in metrics.get_stock_sector(
            stock):
        z_plus_score = 0.717 * A + 0.847 * B + 3.107 * C + 0.420 * D + 0.998 * E
        if z_plus_score > 2.9:
            return z_plus_score, 'safe zone'
        elif z_plus_score < 1.23:
            return z_plus_score, 'distress zone'
        else:
            return z_plus_score, 'grey zone'

    # for foreign firms (i.e. all but US and Canada) and for non-manufacturing firms, both public and private
    elif ('Other Countries' in metrics.get_stock_location(stock)) \
            or ('Manufacturing' not in metrics.get_stock_sector(stock)):

        if 'Other Countries' in metrics.get_stock_location(stock):
            z_plus_plus_score = 3.25 + 6.56 * A + 3.26 * B + 6.72 * C + 1.05 * D

        else:
            z_plus_plus_score = 6.56 * A + 3.26 * B + 6.72 * C + 1.05 * D

        if z_plus_plus_score > 2.6:
            return z_plus_plus_score, 'safe zone'
        elif z_plus_plus_score < 1.1:
            return z_plus_plus_score, 'distress zone'
        else:
            return z_plus_plus_score, 'grey zone'

    else:  # for public manufacturing firms, original score
        D = metrics.market_capitalization(
            stock=stock,
            date=date,
            lookback_period=lookback_period,
            period=period) / financials.total_liabilities(
                stock=stock,
                date=date,
                lookback_period=lookback_period,
                period=period)
        z_score = 1.2 * A + 1.4 * B + 3.3 * C + 0.6 * D + 1.0 * E
        if z_score > 2.99:
            return z_score, 'safe zone'
        elif z_score < 1.81:
            return z_score, 'distress zone'
        else:
            return z_score, 'grey zone'
def piotroski_f_score(stock: str,
                      date: datetime = datetime.now(),
                      lookback_period: timedelta = timedelta(days=0),
                      period: str = 'TTM',
                      diluted_shares=True):
    piotroski_dictio = {
        'Profitability': {},
        'Financial Leverage, Liquidity, and Source of Funds': {},
        'Operating Efficiency': {},
        'Piotroski F-Score': {
            ' ': {
                ' ': {0}
            }
        }
    }

    # Return on Assets (1 point if it is positive in the current year, 0 otherwise)
    return_on_assets_current_year = ratios.return_on_assets(
        stock=stock, date=date, lookback_period=lookback_period, period=period)
    piotroski_dictio['Profitability']['Return on Assets'] = {
        'Return on Assets Current Year':
        '{:.4f}'.format(return_on_assets_current_year),
        'ROA Positive in the Current Year ?':
        return_on_assets_current_year > 0
    }

    # Operating Cash Flow (1 point if it is positive in the current year, 0 otherwise)
    operating_cash_flow_current_year = financials.cash_flow_operating_activities(
        stock=stock, date=date, lookback_period=lookback_period, period=period)
    piotroski_dictio['Profitability']['Operating Cash Flow'] = {
        'Operating Cash Flow Current Year':
        '{:.2f}'.format(operating_cash_flow_current_year),
        'OCF Positive in the Current Year ?':
        operating_cash_flow_current_year > 0
    }

    # Change in Return of Assets (ROA) (1 point if ROA is higher in the current year compared to the previous one,
    # 0 otherwise)
    return_on_assets_previous_year = ratios.return_on_assets(
        stock=stock,
        date=date,
        lookback_period=timedelta(days=365),
        period=period)
    piotroski_dictio['Profitability']['Change in Return of Assets'] = {
        'Return on Assets Current Year':
        '{:.4f}'.format(return_on_assets_current_year),
        'Return on Assets Previous Year':
        '{:.4f}'.format(return_on_assets_previous_year),
        'ROA Current Year > ROA Previous Year ?':
        return_on_assets_current_year > return_on_assets_previous_year
    }

    # Accruals (1 point if Operating Cash Flow/Total Assets is higher than ROA in the current year, 0 otherwise)
    total_assets_current_year = financials.total_assets(
        stock=stock, date=date, lookback_period=lookback_period, period=period)
    accruals = operating_cash_flow_current_year / total_assets_current_year
    piotroski_dictio['Profitability']['Accruals'] = {
        'Operating Cash Flow Current Year':
        '{}'.format(operating_cash_flow_current_year),
        'Total Assets Current Year':
        '{}'.format(total_assets_current_year),
        'Accruals Current Year':
        '{:.4f}'.format(accruals),
        'ROA Current Year':
        '{:.4f}'.format(return_on_assets_current_year),
        'Accruals Current Year > ROA Current Year ?':
        accruals > return_on_assets_current_year
    }

    # Change in Leverage (long-term) ratio (1 point if the ratio is lower this year compared to the previous one,
    # 0 otherwise)
    debt_to_assets_current_year = ratios.debt_ratio(
        stock=stock, date=date, lookback_period=lookback_period, period=period)
    debt_to_assets_previous_year = ratios.debt_ratio(
        stock=stock,
        date=date,
        lookback_period=timedelta(days=365),
        period=period)
    piotroski_dictio['Financial Leverage, Liquidity, and Source of Funds'][
        'Change in Leverage Ratio'] = {
            'Debt to Assets Current Year':
            '{:.4f}'.format(debt_to_assets_current_year),
            'Debt to Assets Previous Year':
            '{:.4f}'.format(debt_to_assets_current_year),
            'D/A Current Year < D/A Previous Year ?':
            debt_to_assets_current_year < debt_to_assets_previous_year
        }

    # Change in Current ratio (1 point if it is higher in the current year compared to the previous one, 0 otherwise)
    current_ratio_current_year = ratios.current_ratio(
        stock=stock, date=date, lookback_period=lookback_period, period=period)
    current_ratio_previous_year = ratios.current_ratio(
        stock=stock,
        date=date,
        lookback_period=timedelta(days=365),
        period=period)
    piotroski_dictio['Financial Leverage, Liquidity, and Source of Funds'][
        'Change in Current Ratio'] = {
            'Current Ratio Current Year':
            '{:.4f}'.format(current_ratio_current_year),
            'Current Ratio Previous Year':
            '{:.4f}'.format(current_ratio_previous_year),
            'CR Current Year > CR Previous Year ?':
            current_ratio_current_year > current_ratio_previous_year
        }

    shares_current_year = financials.total_shares_outstanding(
        stock=stock,
        date=date,
        lookback_period=lookback_period,
        diluted_shares=diluted_shares,
        period=period)
    shares_previous_year = financials.total_shares_outstanding(
        stock=stock,
        date=date,
        lookback_period=timedelta(days=365),
        diluted_shares=diluted_shares,
        period=period)
    # Change in the number of shares (1 point if no new shares were issued during the last year)
    piotroski_dictio['Financial Leverage, Liquidity, and Source of Funds'][
        'Change in Number of Shares'] = {
            'Shares Outstanding Current Year': shares_current_year,
            'Shares Outstanding Previous Year': shares_previous_year,
            'No New Shares Issued ?':
            shares_current_year <= shares_previous_year
        }

    # Change in Gross Margin (1 point if it is higher in the current year compared to the previous one, 0 otherwise)
    gross_margin_current_year = ratios.gross_profit_margin(
        stock=stock, date=date, lookback_period=lookback_period, period=period)
    gross_margin_previous_year = ratios.gross_profit_margin(
        stock=stock,
        date=date,
        lookback_period=timedelta(days=365),
        period=period)

    piotroski_dictio['Operating Efficiency']['Gross Margin'] = {
        'Gross Margin Current Year':
        '{:.4f}'.format(gross_margin_current_year),
        'Gross Margin Previous Year':
        '{:.4f}'.format(gross_margin_previous_year),
        'GM Current Year > GM Previous Year ?':
        gross_margin_current_year > gross_margin_previous_year
    }

    # Change in Asset Turnover ratio (1 point if it is higher in the current year compared to the previous one,
    # 0 otherwise)
    asset_turnover_current_year = ratios.asset_turnover_ratio(
        stock=stock, date=date, lookback_period=lookback_period, period=period)
    asset_turnover_previous_year = ratios.asset_turnover_ratio(
        stock=stock,
        date=date,
        lookback_period=timedelta(days=365),
        period=period)
    piotroski_dictio['Operating Efficiency']['Asset Turnover Ratio'] = {
        'Asset Turnover Ratio Current Year':
        '{:.4f}'.format(asset_turnover_current_year),
        'Asset Turnover Ratio Previous Year':
        '{:.4f}'.format(asset_turnover_previous_year),
        'ATO Current Year > ATO Previous Year ?':
        asset_turnover_current_year > asset_turnover_previous_year
    }

    number_of_trues = 0
    for k, v in piotroski_dictio.items():
        for kk, vv in v.items():
            for kkk, vvv in vv.items():
                if isinstance(vvv, np.bool_) and vvv:
                    number_of_trues = number_of_trues + 1

    piotroski_dictio['Piotroski F-Score'][' '][' '] = number_of_trues

    return piotroski_dictio
예제 #5
0
def beneish_m_score(stock: str,
                    date: datetime = datetime.now(),
                    lookback_period: timedelta = timedelta(days=0),
                    period: str = 'TTM',
                    describe=False):
    current_net_accounts_receivable = fi.net_accounts_receivable(
        stock=stock, date=date, lookback_period=lookback_period, period=period)
    current_net_sales = fi.net_sales(stock=stock,
                                     date=date,
                                     lookback_period=lookback_period,
                                     period=period)
    current_receivables_to_sales = current_net_accounts_receivable / current_net_sales

    previous_net_accounts_receivable = fi.net_accounts_receivable(
        stock=stock,
        date=date - timedelta(days=365 if period == 'FY' else 90),
        lookback_period=lookback_period,
        period=period)
    previous_net_sales = fi.net_sales(
        stock=stock,
        date=date - timedelta(days=365 if period == 'FY' else 90),
        lookback_period=lookback_period,
        period=period)
    previous_receivables_to_sales = previous_net_accounts_receivable / previous_net_sales

    DSRI = current_receivables_to_sales / previous_receivables_to_sales

    previous_gross_profit_margin = ratios.gross_profit_margin(
        stock=stock,
        date=date - timedelta(days=365 if period == 'FY' else 90),
        lookback_period=lookback_period,
        period=period)
    current_gross_profit_margin = ratios.gross_profit_margin(
        stock=stock, date=date, lookback_period=lookback_period, period=period)

    GMI = previous_gross_profit_margin / current_gross_profit_margin

    current_asset_quality = 1 - (fi.total_current_assets(
        stock=stock, date=date, lookback_period=lookback_period, period=period
    ) + fi.net_property_plant_equipment(
        stock=stock, date=date, lookback_period=lookback_period, period=period
    ) + fi.current_marketable_securities(
        stock=stock, date=date, lookback_period=lookback_period,
        period=period))
    previous_asset_quality = 1 - (fi.total_current_assets(
        stock=stock,
        date=date - timedelta(days=365 if period == 'FY' else 90),
        lookback_period=lookback_period,
        period=period) + fi.net_property_plant_equipment(
            stock=stock,
            date=date - timedelta(days=365 if period == 'FY' else 90),
            lookback_period=lookback_period,
            period=period) + fi.current_marketable_securities(
                stock=stock,
                date=date - timedelta(days=365 if period == 'FY' else 90),
                lookback_period=lookback_period,
                period=period))
    AQI = current_asset_quality / previous_asset_quality

    SGI = fi.net_sales(stock=stock, date=date, lookback_period=lookback_period, period=period) \
          / fi.net_sales(stock=stock, date=date - timedelta(days=365 if period == 'FY' else 90),
                         lookback_period=lookback_period, period=period)

    current_depreciation = fi.accumulated_depreciation_amortization(stock=stock, date=date,
                                                                    lookback_period=lookback_period, period=period) \
                           / (fi.net_property_plant_equipment(stock=stock, date=date, lookback_period=lookback_period,
                                                              period=period)
                              + fi.accumulated_depreciation_amortization(stock=stock, date=date,
                                                                         lookback_period=lookback_period,
                                                                         period=period))
    previous_depreciation = fi.accumulated_depreciation_amortization(stock=stock,
                                                                     date=date - timedelta(
                                                                         days=365 if period == 'FY' else 90),
                                                                     lookback_period=lookback_period, period=period) \
                            / (fi.net_property_plant_equipment(stock=stock,
                                                               date=date - timedelta(
                                                                   days=365 if period == 'FY' else 90),
                                                               lookback_period=lookback_period, period=period)
                               + fi.accumulated_depreciation_amortization(stock=stock, date=date - timedelta(
                days=365 if period == 'FY' else 90), lookback_period=lookback_period, period=period))

    DEPI = previous_depreciation / current_depreciation

    SGAI = (fi.selling_general_administrative(stock=stock, date=date, lookback_period=lookback_period, period=period)
            / fi.net_sales(stock=stock, date=date, lookback_period=lookback_period, period=period)) \
           / (fi.selling_general_administrative(stock=stock, date=date - timedelta(days=365 if period == 'FY' else 90),
                                                lookback_period=lookback_period, period=period)
              / fi.net_sales(stock=stock, date=date - timedelta(days=365 if period == 'FY' else 90),
                             lookback_period=lookback_period, period=period))

    previous_leverage = (fi.total_current_liabilities(stock=stock,
                                                      date=date - timedelta(days=365 if period == 'FY' else 90),
                                                      lookback_period=lookback_period, period=period) +
                         fi.total_long_term_debt(stock=stock, date=date - timedelta(days=365 if period == 'FY' else 90),
                                                 lookback_period=lookback_period, period=period)) \
                        / fi.total_assets(stock=stock, date=date - timedelta(days=365 if period == 'FY' else 90),
                                          lookback_period=lookback_period, period=period)
    current_leverage = (fi.total_current_liabilities(stock=stock, date=date, lookback_period=lookback_period,
                                                     period=period)
                        + fi.total_long_term_debt(stock=stock, date=date, lookback_period=lookback_period,
                                                  period=period)) \
                       / fi.total_assets(stock=stock, date=date, lookback_period=lookback_period, period=period)
    LVGI = current_leverage / previous_leverage

    TATA = (fi.operating_income(stock=stock, date=date, lookback_period=lookback_period, period=period)
            - fi.cash_flow_operating_activities(stock=stock, date=date, lookback_period=lookback_period, period=period)) \
           / fi.total_assets(stock=stock, date=date, lookback_period=lookback_period, period=period)

    if not describe:
        return -4.84 + 0.92 * DSRI + 0.528 * GMI + 0.404 * AQI + 0.892 * SGI + 0.115 * DEPI - 0.172 * SGAI + 4.679 * TATA - 0.327 * LVGI
    else:
        return {'Inputs': {}}
def altman_z_score(stock, date, lookback_period: timedelta = timedelta(days=0), period: str = 'TTM'):
    """

    :param stock:
    :param date:
    :param lookback_period:
    :param period:
    :return:

    * For **private manufacturing companies**, a Z-score > 2.9 indicates *safe zone*, while < 1.23 indicates *distress zone*,
    and what's in between is the *grey zone*.

    For foreign firms (i.e. all but US and Canada) and for non-manufacturing firms (both public and private),
    a Z-score

    +------------------------+------------+----------+----------+
    |                        | Safe Zone   | Grey Zone | Distress Zone|
    +========================+============+==========+==========+
    | Public, Manufacturing |   > 2.99     |            |  < 1.81        |
    +-------------------------+-------------+---------+----------|
    | Private, Manufacturing   | column 2   | column 3 | column 4 |
    +------------------------+------------+----------+----------+
    | Non-Manufacturing, Foreign |            |           |         |
    +------------------------+------------+----------+----------+

    """
    A = metrics.net_working_capital(stock=stock, date=date, lookback_period=lookback_period, period=period) \
        / financials.total_assets(stock=stock, date=date, lookback_period=lookback_period, period=period)
    B = financials.retained_earnings(stock=stock, date=date, lookback_period=lookback_period, period=period) \
        / financials.total_assets(stock=stock, date=date, lookback_period=lookback_period, period=period)
    C = metrics.earnings_before_interest_and_taxes(stock=stock, date=date, lookback_period=lookback_period,
                                                   period=period) \
        / financials.total_assets(stock=stock, date=date, lookback_period=lookback_period, period=period)
    D = financials.total_shareholders_equity(stock=stock, date=date, lookback_period=lookback_period, period=period) \
        / financials.total_liabilities(stock=stock, date=date, lookback_period=lookback_period, period=period)
    E = financials.net_sales(stock=stock, date=date, lookback_period=lookback_period, period=period) \
        / financials.total_assets(stock=stock, date=date, lookback_period=lookback_period, period=period)

    public_tickers = object_model.Company.objects(exchange__in=['NASDAQ', 'NYSE', 'AMEX']).values_list('name')
    manufacturing_tickers = object_model.Company.objects(sic_sector='MANUFACTURING').values_list('name')
    # for private manufacturing companies
    if stock not in public_tickers and 'Manufacturing' not in metrics.get_stock_sector(stock):
        z_plus_score = 0.717 * A + 0.847 * B + 3.107 * C + 0.420 * D + 0.998 * E
        if z_plus_score > 2.9:
            return z_plus_score, 'safe zone'
        elif z_plus_score < 1.23:
            return z_plus_score, 'distress zone'
        else:
            return z_plus_score, 'grey zone'

    # for foreign firms (i.e. all but US and Canada) and for non-manufacturing firms, both public and private
    elif ('Other Countries' in metrics.get_stock_location(stock)) \
            or ('Manufacturing' not in metrics.get_stock_sector(stock)):

        if 'Other Countries' in metrics.get_stock_location(stock):
            z_plus_plus_score = 3.25 + 6.56 * A + 3.26 * B + 6.72 * C + 1.05 * D

        else:
            z_plus_plus_score = 6.56 * A + 3.26 * B + 6.72 * C + 1.05 * D

        if z_plus_plus_score > 2.6:
            return z_plus_plus_score, 'safe zone'
        elif z_plus_plus_score < 1.1:
            return z_plus_plus_score, 'distress zone'
        else:
            return z_plus_plus_score, 'grey zone'

    else:  # for public manufacturing firms, original score
        D = metrics.market_capitalization(stock=stock, date=date, lookback_period=lookback_period,
                                          period=period) / financials.total_liabilities(stock=stock, date=date,
                                                                                        lookback_period=lookback_period,
                                                                                        period=period)
        z_score = 1.2 * A + 1.4 * B + 3.3 * C + 0.6 * D + 1.0 * E
        if z_score > 2.99:
            return z_score, 'safe zone'
        elif z_score < 1.81:
            return z_score, 'distress zone'
        else:
            return z_score, 'grey zone'