Published on

Investing Smartly - How to Evaluate Your Investment Strategy's Vulnerability

The Essentials

Investment strategies usually involve making bets with an exit plan based on two conditions: achieving a profit or stopping losses. The interaction between these factors is best understood as a binomial process that evaluates the strategy's resilience against minor changes. In a nutshell, you want a strategy with frequent bets and high precision to increase your Sharpe ratio, a measure of risk-adjusted returns.

The formula for the annualized Sharpe ratio with symmetric payouts is given by:

θ[p,n]=2p12p(1p)n\theta[p, n] = \frac{2p - 1}{2 \sqrt{p(1-p)}} \sqrt{n}

This shows the trade-off between precision (p)(p) and frequency (n)(n) for a given Sharpe ratio (θ)(\theta). For instance, to achieve an annualized Sharpe ratio of 2 with weekly bets, you would need a precision of p=0.6336p=0.6336.

For non-symmetric payouts, the annualized Sharpe ratio is:

θ[p,n,π,π+]=(π+π)p+π(π+π)p(1p)n\theta[p, n, \pi_{-}, \pi_{+}] = \frac{( \pi_{+} - \pi_{-} ) p + \pi_{-}}{( \pi_{+} - \pi_{-} ) \sqrt{p(1-p)}} \sqrt{n}

Calculating Sharpe Ratio

strategy_risk.py
import numpy as np

def sharpe_ratio_trials(
        p: float,
        n_run: int
) -> tuple[float, float, float]:
    outcomes = np.random.binomial(n=1, p=p, size=n_run) * 2 - 1
    mean_outcome = np.mean(outcomes)
    std_outcome = np.std(outcomes)
    sharpe_ratio = mean_outcome / std_outcome

    return mean_outcome, std_outcome, sharpe_ratio

View More: Julia | Python


This functionality is available in both Python and Julia in the RiskLabAI library.

Advanced Calculations: Symbolic Operations

For those interested in deeper analysis, the equation for pp in terms of various parameters can be computed symbolically.

p=b+b24ac2ap=\frac{-b+\sqrt{b^{2}-4ac}}{2a}

Where:

  • a=(n+θ2)(π+π)2a=(n+\theta^{2})(\pi_{+}-\pi_{-})^{2}
  • b=[2nπθ2(π+π)](π+π)b=[2n\pi_{-}-\theta^{2}(\pi_{+}-\pi_{-})](\pi_{+}-\pi_{-})
  • c=nπ2c=n \pi_{-}^{2}
strategy_risk.py
from sympy import symbols, factor

def target_sharpe_ratio_symbolic() -> sympy.Add:
    p, u, d = symbols("p u d")

    m2 = p * u**2 + (1 - p) * d**2
    m1 = p * u + (1 - p) * d
    v = m2 - m1**2

    return factor(v)

View More: Julia | Python


Understanding Implied Precision

The impliedPrecision function in both Python and Julia computes the implied betting frequency, denoted as nn. It takes four parameters:

  • stopLoss: The stop loss threshold
  • profitTaking: The profit taking threshold
  • frequency: Number of bets per year
  • targetSharpeRatio: The target annual Sharpe ratio

The function deals with how varying the precision rate pp and profit/loss ratio π\pi_{-} affects the required betting frequency nn to achieve a given target Sharpe ratio θ\theta^{*}.

θ(p,n,π,π+)=Implied betting frequency\theta(p, n, \pi_{-}, \pi_{+}) = \text{Implied betting frequency}

Calculating Bin Frequency

The binFrequency function calculates the annual frequency of bets, denoted as nn, required to achieve a target Sharpe ratio θ\theta^{*}. The parameters are similar to those of impliedPrecision.

Strategy Risk

Unlike portfolio risk, which is usually well-monitored, strategy risk often goes under the radar. Strategy risk is the risk that the investment strategy will fail to meet its objective over time. The question "What is the probability that this strategy will fail?" can be represented mathematically as P[p<pθ]P[p<p_{\theta^{*}}].

To compute this, we:

  1. Estimate the profit/loss ratios π\pi_{-} and π+\pi_{+} from a time series of bet outcomes.
  2. Calculate the annual frequency nn.
  3. Bootstrap the distribution of pp.
  4. Find pθp_{\theta^{*}}, the value of pp below which the strategy will fail to achieve θ\theta^{*}.
  5. Finally, compute the strategy risk as P[p<pθ]P[p<p_{\theta^{*}}].

When is a Strategy too Risky?

Strategies with P[p<pθ]>.05P[p<p_{\theta^{*}}] > .05 are usually considered too risky, irrespective of the underlying assets' volatility. This means that even if the strategy doesn't lose much money, the probability that it will fail to achieve its target is too high.

For code implementations of these algorithms, you can refer to the RiskLabAI library. The functionalities are available in both Python and Julia.

strategy_risk.py
def implied_precision(
        stop_loss: float,
        profit_taking: float,
        frequency: float,
        target_sharpe_ratio: float
) -> float:
    a = (frequency + target_sharpe_ratio**2) * (profit_taking - stop_loss)**2

    b = (2 * frequency * stop_loss - target_sharpe_ratio**2 * (profit_taking - stop_loss)) * (profit_taking - stop_loss)

    c = frequency * stop_loss**2
    precision = (-b + (b**2 - 4 * a * c)**0.5) / (2 * a)

    return precision

View More: Julia | Python


References

  1. De Prado, M. L. (2018). Advances in financial machine learning. John Wiley & Sons.
  2. De Prado, M. M. L. (2020). Machine learning for asset managers. Cambridge University Press.