My interest in financial markets began during my college years. In my second year, while studying economics, I enrolled in a financial markets course, and I was fascinated by all the data I could manipulate. It was exciting to calculate various ratios, returns, and forecast projections. That excitement lasted until I started investing myself. It’s all fun and games until you realize that you could lose your hard-earned money in the blink of an eye.
To minimize my losses and scratch the number-crunching itch, I started building a portfolio tracker in Excel. Now that I can "cry in Python," I thought, why not try this in Python instead?
I chose the Sharpe ratio for my first Python application because it’s surprisingly easy to calculate. However, the problem with the traditional approach is that you need to export data, organize it into columns, and manually apply formulas to get the results. This process is boring, and I'm learning Python to automate exactly these kinds of tasks!
Aside from being simple to calculate, the Sharpe ratio is a crucial metric in finance. It helps investors evaluate investment performance by comparing risk-adjusted returns. It answers an age-old question in investing: should I take on more risk, or should I put my money into a less risky instrument, like interest-bearing accounts? The Sharpe ratio provides a way to assess whether the returns are worth the risk.
The formula for the Sharpe ratio is:
( return of the portfolio - risk-free rate) / (the standard deviation of the portfolio's excess return)
By calculating the Sharpe ratio, we can make more informed decisions about whether the returns on an investment justify the risk involved.
Code Overview
This script uses "yfinance" to fetch stock data and calculates the Sharpe ratio along with other key statistical measures. As I said, this was the most useful part of this script as collection of the data is a real burden if you a long time frame or you want to check more than one stock.
Here is the pseudocode as always,
- Ask for user input for ticker name, risk-free instrument's gains, time frame
- Fetch data and calculate Sharpe ratio with the above formula
- Print the length of analysis, all the parameters of the calculation, standard deviation and Sharpe ratio interpretation
The Analytical Toolkit
To run this script, I used a few Python libraries:
- numpy for numerical computations and handling arrays.
- yfinance for downloading historical financial data.
- datetime for handling date and time operations.
Interpreting the Result
The thing with the Sharpe ratio is that it is used to compare two instruments or two stocks. So, by itself it has a little meaning but in general the higher the number, the better the instrument's returns have been relative to the amount of risk taken. That means, anything above 1 is considered good, while below this is considered bad. This is how my script evaluates the Sharpe ratio of the result:
if sharpe_ratio < 0: print("Negative Sharpe Ratio: The investment's return is worse than the risk-free rate.") elif sharpe_ratio < 0.5: print("Low Sharpe Ratio: Poor risk-adjusted returns.") elif sharpe_ratio < 1: print("Below-average Sharpe Ratio: Moderate risk-adjusted returns.") elif sharpe_ratio < 2: print("Good Sharpe Ratio: Good risk-adjusted returns.") else: print("Excellent Sharpe Ratio: Very good risk-adjusted returns.")
What Is the Sharpe Ratio of Tesla?
Let's calculate the Sharpe ratio of Tesla. But, I want to remind that this isn’t a fixed value. It changes over time based on the risk-free rate of return, instrument's expected rate of return, and standard deviation.
Enter stock ticker symbol: TSLA Enter annual risk-free rate (as decimal, e.g., 0.44 for 44%): 0.0425 Enter start date (YYYY-MM-DD): 2023-12-20 Enter end date (YYYY-MM-DD): 2024-12-20 Results for TSLA: How many days of data: 251 Risk-free rate (annual): 4.25% Daily average return: 0.30% Daily standard deviation: 3.96% Annual average return: 76.36% Annual standard deviation: 62.86% Sharpe Ratio: 1.15 Volatility Interpretation: The daily standard deviation of 3.96% indicates that on any given day, the stock return typically fluctuates within 7.92% of its mean return (covering about 95% of all daily movements). Sharpe Ratio Interpretation: Good Sharpe Ratio: Good risk-adjusted returns.
Potential Improvements
As always, this is a living code and I plan to include all my performance metrics to Python, for this particular script I plan to include:
- Visualization of returns distribution
- Rolling Sharpe ratio calculation
- Benchmark comparison
- Maybe more risk metrics like Sortino ratio
- Multiple ticker comparison
Let me know if this works for you!
Cheers, Berkem
Try It Out
import yfinance as yf import numpy as np from datetime import datetime def calculate_sharpe_ratio(): # get user inputs ticker = input("Enter stock ticker symbol: ") risk_free_rate = float(input("Enter annual risk-free rate (as decimal, e.g., 0.44 for 44%): ")) start_date = input("Enter start date (YYYY-MM-DD): ") end_date = input("Enter end date (YYYY-MM-DD): ") # download stock data stock = yf.Ticker(ticker) df = stock.history(start=start_date, end=end_date) # calculate daily returns daily_returns = df['Close'].pct_change().dropna() # calculate metrics daily_avg_return = daily_returns.mean() daily_std = daily_returns.std() # annualize metrics (assuming 252 trading days) annual_avg_return = daily_avg_return * 252 annual_std = daily_std * np.sqrt(252) # calculate Sharpe Ratio monthly_rf_rate = risk_free_rate / 12 sharpe_ratio = (annual_avg_return - risk_free_rate) / annual_std # print results print(f"\nResults for {ticker.upper()}:") print(f"How many days of data: {len(daily_returns)}") print(f"Risk-free rate (annual): {risk_free_rate:.2%}") print(f"Daily average return: {daily_avg_return:.2%}") print(f"Daily standard deviation: {daily_std:.2%}") print(f"Annual average return: {annual_avg_return:.2%}") print(f"Annual standard deviation: {annual_std:.2%}") print(f"Sharpe Ratio: {sharpe_ratio:.2f}") # Add standard deviation interpretation print("\nVolatility Interpretation:") print(f"The daily standard deviation of {daily_std:.2%} indicates that on any given day,") print(f"the stock's return typically fluctuates within {daily_std*2:.2%} of its mean return") print(f"(covering about 95% of all daily movements).") # Interpret Sharpe Ratio print("\nSharpe Ratio Interpretation:") if sharpe_ratio < 0: print("Negative Sharpe Ratio: The investment's return is worse than the risk-free rate.") elif sharpe_ratio < 0.5: print("Low Sharpe Ratio: Poor risk-adjusted returns.") elif sharpe_ratio < 1: print("Below-average Sharpe Ratio: Moderate risk-adjusted returns.") elif sharpe_ratio < 2: print("Good Sharpe Ratio: Good risk-adjusted returns.") else: print("Excellent Sharpe Ratio: Very good risk-adjusted returns.") if __name__ == "__main__": try: calculate_sharpe_ratio() except Exception as e: print(f"An error occurred: {e}")