Back to Stocks

Mathematical Formulas & Methodology

Understanding the advanced calculations behind our stock analysis

1. Compound Annual Growth Rate (CAGR)

CAGR measures the mean annual growth rate of an investment over a specified time period longer than one year.

CAGR = (Ending Value/Beginning Value) 1/n - 1

where n = number of years

Implementation

def compute_cagr(series):
    if len(series) < 2:
        return None
    first_val = series[0]
    last_val = series[-1]
    years = last_year - first_year
    
    if first_val <= 0:
        return None
    
    return (last_val / first_val) ** (1 / years) - 1

Use Cases

  • Revenue CAGR (3Y, 5Y): Measures consistent revenue growth over multiple years
  • Net Profit CAGR: Evaluates profitability growth trajectory
  • Price CAGR: Calculates stock price appreciation over 1, 3, and 5 years

2. Robust Scaling (Percentile-Based Normalization)

Robust scaling uses percentiles to reduce the impact of outliers, making the scoring system more stable.

Scaled Value = (Value - P5)/(P95 - P5) × Weight

P5 = 5th percentile, P95 = 95th percentile

Implementation

def robust_scale(series, weight, higher_is_better=True):
    # Clip values to 5th-95th percentile range
    low = np.nanpercentile(series, 5)
    high = np.nanpercentile(series, 95)
    clipped = series.clip(lower=low, upper=high)
    
    # Normalize to 0-1 range
    if higher_is_better:
        normalized = (clipped - low) / (high - low)
    else:
        normalized = (high - clipped) / (high - low)
    
    return normalized * weight

Advantages

  • Reduces impact of extreme outliers
  • More stable scoring across different market conditions
  • Handles skewed distributions better than min-max scaling

3. Financial Health Metrics

3.1 Debt-to-Equity Ratio

Debt-to-Equity = Total Borrowings/Shareholders' Equity

Lower values indicate less financial risk. Equity = Equity Capital + Reserves

3.2 Interest Coverage Ratio

Interest Coverage = Operating Profit/Interest Expense

Measures ability to pay interest. Higher values (>3) indicate better financial health.

3.3 Cash Flow Coverage

Cash Flow Coverage = Cash from Operating Activities/Net Profit

Ratio > 1 indicates strong cash generation relative to reported profits.

4. Profitability Metrics

4.1 Net Profit Margin

Net Profit Margin = Net Profit/Sales × 100%

4.2 Operating Margin

Operating Margin = Operating Profit/Sales × 100%

4.3 Return on Equity (ROE)

ROE = Net Profit/Shareholders' Equity × 100%

Measures return generated on shareholders' investment. Higher is better (typically >15%).

4.4 Return on Capital Employed (ROCE)

ROCE = EBIT/Capital Employed × 100%

Capital Employed = Equity + Long-term Debt. Measures efficiency of capital usage.

5. Volatility & Risk Metrics

5.1 Profit Volatility

Standard deviation of sequential growth rates in profit over the last 4 quarters.

def compute_volatility(values):
    # Calculate growth rates
    growth_rates = []
    for i in range(1, len(values)):
        if values[i-1] != 0:
            growth = (values[i] - values[i-1]) / values[i-1]
            growth_rates.append(growth)
    
    # Return standard deviation of recent growth rates
    window = growth_rates[-4:] if len(growth_rates) >= 4 else growth_rates
    return np.std(window)

Lower volatility indicates more consistent profitability.

5.2 Price Volatility (1Y)

Volatility = Standard Deviation of Daily Returns × √252

Annualized volatility using 252 trading days per year.

5.3 Sharpe Ratio

Sharpe Ratio = (Return - Risk-free Rate)/Volatility

Measures risk-adjusted returns. Higher values indicate better risk-adjusted performance.

5.4 Maximum Drawdown

Largest peak-to-trough decline in stock price over the period.

def calculate_max_drawdown(prices):
    peak = prices.expanding().max()
    drawdown = (prices - peak) / peak
    return drawdown.min()

6. Technical Indicators

6.1 Moving Averages

MA(n) = Sum of Last n Prices/n

We use MA50 (50-day) and MA200 (200-day) to identify trends.

6.2 Relative Strength Index (RSI)

RSI measures the speed and magnitude of price changes.

def calculate_rsi(prices, period=14):
    delta = prices.diff()
    gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
    
    rs = gain / loss
    rsi = 100 - (100 / (1 + rs))
    return rsi

RSI > 70 indicates overbought, RSI < 30 indicates oversold.

6.3 MACD (Moving Average Convergence Divergence)

MACD = EMA(12) - EMA(26)

Signal Line = EMA(9) of MACD. Histogram = MACD - Signal Line.

7. Trend Analysis

7.1 Linear Regression Trend (90-day)

Fits a linear trend to the last 90 days of price data.

from sklearn.linear_model import LinearRegression

def calculate_trend_slope(prices, days=90):
    recent_prices = prices.tail(days)
    X = np.arange(len(recent_prices)).reshape(-1, 1)
    y = recent_prices.values
    
    model = LinearRegression()
    model.fit(X, y)
    
    slope = model.coef_[0]
    r_squared = model.score(X, y)
    
    # Convert to percentage
    slope_pct = (slope / recent_prices.iloc[0]) * 100
    
    return slope_pct, r_squared

Positive slope indicates upward trend. R² measures trend strength (0-1).

8. Composite Scoring System

8.1 Financial Score Components (100 points)

  • Growth Score (0-25): Revenue CAGR, Profit CAGR, YoY Growth
  • Profitability Score (0-25): ROE, ROCE, OPM, Net Profit Margin
  • Financial Health Score (0-20): Debt-to-Equity, Interest Coverage, Cash Flow
  • Consistency Score (0-15): Profit Volatility, Years Positive Profit
  • Valuation Score (0-15): P/E Ratio, Market Cap

8.2 Price Score Components (40 points)

  • Price Momentum Score (0-35): 1M/3M/6M changes, CAGRs, Trend Slope
  • Volume/Liquidity Score (0-20): Average Volume, Volume Trends
  • Technical Score (0-25): Price vs MA50/MA200, RSI, MACD, 52W High/Low
  • Risk-Adjusted Score (0-20): Volatility, Max Drawdown, Sharpe Ratio

8.3 Overall Composite Score

Overall Score = (Financial Score × 0.6) + (Price Score × 0.4)

Weighted combination with 60% weight on financials and 40% on price momentum.

9. Year-to-Date (YTD) Calculations

For quarterly periods, we calculate cumulative results within the fiscal year:

  • Jun 2024: Jun 2024 only
  • Sep 2024: Jun 2024 + Sep 2024
  • Dec 2024: Jun 2024 + Sep 2024 + Dec 2024
  • Mar 2025: Jun 2024 + Sep 2024 + Dec 2024 + Mar 2025

This provides a "Financial_result_so_far" view for incomplete fiscal years.

10. Fiscal Year Logic

Indian companies typically follow April-March fiscal year. For quarterly periods:

  • Jun, Sep, Dec quarters: Use previous year's annual data (e.g., Jun 2024 → Mar 2024 annual)
  • Mar quarter: Use current year's annual data (e.g., Mar 2025 → Mar 2025 annual)

This ensures we're not using future data for current quarter analysis.

Conclusion

Our comprehensive scoring system combines multiple financial and technical metrics using robust statistical methods. The percentile-based scaling ensures fair comparison across different market sectors, while the weighted composite score provides a balanced view of both fundamental strength and price momentum.

All calculations are performed using Python with NumPy and Pandas for accuracy and efficiency, processing thousands of stocks in real-time.