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)))
Example #2
0
def free_cash_flow(stock: str,
                   date: datetime = datetime.now(),
                   lookback_period: timedelta = timedelta(days=0),
                   period: str = ''):
    """
    Free Cash Flow is the amount of cash flow available for discretionary spending by the company after the necessary capital invesment.
    It builds on CFO but takes into account (deducts) Capital Expenditures. Unlike FCFE and FCFF, it is a generic measure of cash flow.

    :param stock: ticker(s) in question. Can be a string (i.e. 'AAPL') or a list of strings (i.e. ['AAPL', 'BA']).
    :param date: Can be a datetime (i.e. datetime(2019, 1, 1)) or list of datetimes. The most recent date of reporting from that date will be used. By default, date=datetime.now().
    :param lookback_period: lookback from date (used to compare against previous year or quarter etc.) i.e. timedelta(days=90).
    :param period: 'FY' for fiscal year, 'Q' for quarter, 'YTD' for calendar year to date, 'TTM' for trailing twelve months.

    :return:
    """
    return fi.cash_flow_operating_activities(stock=stock, date=date, lookback_period=lookback_period, period=period) \
           - abs(capital_expenditures(stock=stock, date=date, lookback_period=lookback_period, period=period))
def free_cash_flow(stock: str, date: datetime = datetime.now(), lookback_period: timedelta = timedelta(days=0),
                   period: str = ''):
    return fi.cash_flow_operating_activities(stock=stock, date=date, lookback_period=lookback_period, period=period) \
           - abs(capital_expenditures(stock=stock, date=date, lookback_period=lookback_period, period=period))
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
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': {}}