Financial Calculations Practical Guide With Python and R
Financial Calculations Practical Guide With Python and R
Introduction
How to use and install Python and R
R console installation
Python usage
CHAPTER 1
1. Compound Interest
2. Present Value
3. Net Present Value (NPV)
4. Internal Rate of Return (IRR)
5. Capital Asset Pricing Model (CAPM)
6. Black-Scholes Option Pricing Model
7. Gordon Growth Model
8. Debt to Equity Ratio
9. Return on Equity (ROE)
10. Price-to-Earnings (P/E) Ratio
11. Earnings Before Interest and Taxes (EBIT)
12. Quick Ratio (Acid-Test Ratio)
13. Debt Coverage Ratio
14. Dividend Yield
15. Sharpe Ratio
16. Current Ratio
17. Weighted Average Cost of Capital (WACC)
18. Beta (β)
19. Duration of a Bond
20. Portfolio Variance
CHAPTER 2
1. Simple Moving Average (SMA)
2. Exponential Moving Average (EMA)
3. Relative Strength Index (RSI)
4. Moving Average Convergence Divergence (MACD)
5. Bollinger Bands
6. Average True Range (ATR)
7. Stochastic Oscillator
8. Moving Average Convergence Divergence Histogram
9. Commodity Channel Index (CCI)
10. Fibonacci Retracement Levels
11. Moving Average Convergence Divergence Signal Cross
12. MACD Histogram Cross
13. Moving Average Golden Cross and Death Cross
14. RSI and Oversold Levels
15. MACD Zero Line Cross
16. MACD Signal Line Cross
17. MACD Histogram Peak/Trough
18. MACD Zero Line Reversal
19. Moving Average Ribbon
20. Candlestick Patterns (Hammer and Shooting Star)
CHAPTER 3
1. Portfolio Returns
2. Portfolio Volatility
3. Portfolio Sharpe Ratio
4. Minimum Variance Portfolio
5. Capital Market Line (CML) Portfolio
6. Efficient Frontier
7. Risk Parity Portfolio
8. Maximum Drawdown
9. Tracking Error
10. Active Return
11. Information Ratio
12. Treynor Ratio
13. Sortino Ratio
14. Conditional Value-at-Risk (CVaR)
15. Value-at-Risk (VaR)
16. Portfolio Beta
17. Portfolio Alpha
18. Jensen's Alpha
19. Portfolio Turnover
20. Portfolio Rebalancing
CHAPTER 4
1. Net Present Value (NPV)
2. Internal Rate of Return (IRR)
3. Payback Period
4. Return on Investment (ROI)
5. Profitability Index (PI)
6. Holding Period Return (HPR)
7. Sharpe Ratio
8. Treynor Ratio
9. Sortino Ratio
10. Conditional Value-at-Risk (CVaR)
11. Value-at-Risk (VaR)
12. Maximum Drawdown
13. Capital Asset Pricing Model (CAPM) Beta
14. Jensen's Alpha
15. Modigliani Ratio
16. Information Ratio
17. Portfolio Turnover
18. Portfolio Rebalancing
19. Mean-Variance Optimization
20. Portfolio Risk and Return
CHAPTER 5
1. Future Value (FV)
2. Present Value (PV)
3. Compound Interest
4. Simple Interest
5. Annual Percentage Yield (APY)
6. Present Value of Annuity
7. Future Value of Annuity
8. Present Value of Perpetuity
9. Future Value with Continuous Compounding
10. Present Value with Continuous Compounding
11. Effective Annual Rate (EAR)
12. Present Value of Growing Perpetuity
13. Number of Periods (N)
14. Effective Interest Rate for Continuous Compounding
15. Present Value of Growing Annuity
16. Continuous Compounding for Continuous Rate
17. Loan Payment (Amortizing Loan)
18. Loan Balance (Amortizing Loan)
19. Loan Payoff Period (Amortizing Loan)
20. Loan Interest Payment (Amortizing Loan)
CHAPTER 6
1. Convert Between Currencies
2. Cross Rates
3. Forward Exchange Rate
4. Forward Points
5. FX Swap Points
6. Percentage Change in Exchange Rate
7. FX Forward Rate Agreement (FRA)
8. FX Option Premium (Black-Scholes)
9. FX Option Delta (Black-Scholes)
10. FX Option Vega (Black-Scholes)
11. FX Option Theta (Black-Scholes)
12. FX Option Gamma (Black-Scholes)
13. FX Option Rho (Black-Scholes)
14. FX Option Implied Volatility (Black-Scholes)
15. FX Option Risk Reversal and Butterflies
16. FX Option Strike from Delta (Black-Scholes)
17. FX Option Payoff
18. FX Option Break-Even Rates
19. FX Option Spread
20. FX Option Hedge Ratios (Delta Hedging)
CHAPTER 7
1. Bond Price
2. Bond YTM (Yield to Maturity)
3. Bond Accrued Interest
4. Current Yield of a Bond
5. Macaulay Duration of a Bond
6. Modified Duration of a Bond
7. Convexity of a Bond
8. Bond Duration and Convexity for Parallel Yield Shift
9. Bond Yield Based on Cash Flows
10. Yield to Call (YTC) for Callable Bonds
11. Duration for a Bond Portfolio
12. Modified Duration for a Bond Portfolio
13. Convexity for a Bond Portfolio
14. Portfolio Yield Based on Bond Yields
15. Bond Equivalent Yield for Semiannual Coupon Bonds
16. Yield to Worst (YTW) for a Callable Bond
17. Yield to Worst (YTW) for a Bond Portfolio
18. Spread to Benchmark for a Bond
CHAPTER 8
1. Dividend Discount Model (DDM) Valuation
2. Price-to-Earnings (P/E) Ratio
3. Price-to-Book (P/B) Ratio
4. Price-to-Sales (P/S) Ratio
5. Enterprise Value (EV)
6. Earnings Before Interest and Taxes (EBIT)
7. EBITDA
8. Free Cash Flow (FCF)
9. Return on Equity (ROE)
10. Return on Assets (ROA)
11. Dividend Yield
12. Capital Asset Pricing Model (CAPM) Expected Return
13. Weighted Average Cost of Capital (WACC)
14. Intrinsic Value using the Two-Stage DDM
CHAPTER 9
1. Net Present Value of an Alternative Investment
2. Internal Rate of Return of an Alternative Investment
3. Payback Period of an Alternative Investment
4. Return on Investment (ROI) of an Alternative Investment
5. Modified Duration of an Alternative Investment
6. Real Estate Capitalization Rate (Cap Rate)
7. Real Estate Cash-on-Cash Return
8. Rental Yield for Real Estate Investment
9. Private Equity Multiple (DPI, RVPI, TVPI)
11. Hedge Fund Sharpe Ratio
12. Hedge Fund Sortino Ratio
13. Cryptocurrency Volatility
14. Venture Capital Return Multiple (TVPI)
15. Infrastructure Investment Yield
16. Art Investment Return
17. Peer-to-Peer Lending ROI
18. Precious Metals Investment Return
References and Links
#R
#Python
R & Python Links
Manuals
Tutorial
R Studio
Online communities for R
R packages
R books for teaching finance
Python programing Links
The Python Tutorial
Financial Calculations Practical Guide with Python and R
All Rights Reserved
Copyright © 2023 Engin Demirel, Ph.D.
All Rights Reserved. This book may not be reproduced, transmitted,
or stored in whole or in part by means, including graphic, electronic,
or mechanical, without the publisher's express written consent
except in the case of brief quotations embodied in critical articles
and reviews.
Introduction
This book provides readers with a thorough road map for understanding
critical ideas by covering various financial computations. The book is
divided into nine sections covering essential subjects such as portfolio
optimization, risk management, and time value of money. In these parts,
readers will find a carefully chosen to set of average twenty calculations per
subject for more than two hundred examples with the financial calculations.
This guide's strength is its practical approach, which provides theoretical
understanding and valuable solutions utilizing the Python and R
programming languages.
The book also explains each computation methodically, simply expressing
the underlying financial concepts. Formulas are provided in an easily
understood format to guarantee that the theory is well understood. The real
value of this book is providing readers with ready-to-use R and Python lines
of code, making the theory-to-practice transfer effortlessly.
Financial Calculations Practical Guide with Python and R book is an
essential resource book for anybody interested in bridging the knowledge
gap between academia and business, whether a student or a financial
professional looking to expand their analytical toolset. With the help of this
carefully designed book, readers can unlock the complexity of financial
calculations and equip themselves with the knowledge and abilities needed
to negotiate the complexities of finance confidently and accurately.
In the book, each chapter begins with the definition and specification of the
necessary functions for financial calculations. Subsequently, the code lines
required for R are provided first, followed immediately by those necessary
for Python (these sections are highlighted in gray). These codes allow you
to experiment with and make the necessary adjustments. The nature and
usage of the code are then explained. Following this, an exemplary dataset
for financial calculations is presented. The solutions for both R and Python
programming languages are demonstrated using this sample data, with the
R solution showcased first and followed by the Python solution. Finally, for
comparative analysis, the outputs of the solutions are separately displayed
for both programming languages. This approach facilitates the utilization of
practical coding examples in reader endeavors in both programming
languages.
Simultaneously, readers can compare the differences in programming
languages in the sample calculations. While the examples and
demonstrations are intended for practical usage, detailed studies, code
packages, and educational materials for coding in both languages can be
accessed through the links provided at the end of the book. There is no
specific sequence of topics outside the book's chapter headings. Readers can
locate and try any example from the table of contents.
Also, one of the book's fundamental objectives is to create a practical guide
that combines financial education with coding languages.
Engin Demirel, Ph.D
How to use and install Python and R
R console installation
R is a popular software environment and programming language for
financial and statistical computation. Your experience with financial data
analysis and programming may be much improved by learning how to
navigate its primary menu and using it effectively. The primary menu items
and their functions in “R” are explained in detail below:
To install R, follow these steps:
Download R from this link
Choose the version compatible with your operating system.
Once the download is complete, open the installer.
Follow the installation wizard's instructions.
After the installation, open R to start using it.
Optionally, you can also install RStudio, an integrated development
environment (IDE) for R, from this link
Launch RStudio and configure it to suit your preferences.
File Menu: The File menu allows you to create new scripts, open existing
files, and manage your R project's directory. You can also save, export, and
import data files for analysis.
Edit Menu: This menu provides essential editing functionalities, including
copy, paste, find, and replace, and other text manipulation tools to
streamline your coding process.
View Menu: You can customize the layout of your R environment using the
View menu. It enables you to adjust the appearance of your workspace,
manage script and console layouts, and control the visibility of various
panels and tool windows.
Packages Menu: The Packages menu allows you to manage R packages
efficiently. You can install, update, and remove packages, as well as load
and unload them to access a wide range of additional functionalities and
tools.
Plots Menu: This menu is dedicated to creating and customizing
visualizations in R. You can generate various types of plots, adjust plot
properties, and export plots for presentations and reports.
Tools Menu: The Tools menu provides access to additional utilities and
functionalities that can enhance your R programming experience. It may
include features such as the R workspace, script editor, and global options,
allowing you to customize your R environment to suit your specific
requirements.
Session Menu: This menu enables you to manage your R session
effectively. You can control the R interpreter, manage working directories,
and access options to save or clear the current workspace.
Help Menu: The Help menu is a valuable resource that provides access to R
documentation, manuals, and online resources. You can find information on
functions, packages, and general R programming concepts to guide you
through your coding and analysis tasks.
Copy and paste the selected calculation code, which is highlighted in gray
in the book, to the “R console” screen and “enter” to execute the example.
To delete screen on R console shortcuts are “cmd+alt+L” for mac and
“Ctrl+L” for windows. This book serves as a practice guide. You may easily
adapt the numerical examples to your own data.
Python usage
PyCharm is a powerful integrated development environment (IDE) for
Python that offers a comprehensive set of tools and features to streamline
the process of coding and developing Python applications. This is a text
editor for Python which reader can use different options (such as: IDLE,
Jupiter Notebooks, VSCode, Spyder, Sublime text, Command Line text
editor).
To install PyCharm for Python, follow these steps:
Download PyCharm from this link
Choose the version compatible with your operating system.
Once the download is complete, open the installer.
Follow the installation wizard's instructions.
After the installation, launch PyCharm.
Configure PyCharm according to your preferences and settings.
On the welcome screen, click on "Create New Project."
Specify the location where you want to create the new project.
Click on your “Project name” at search projects screen or “open” button
right upper corner.
The main menu of PyCharm is composed of several components arranged
in an easy-to-use layout. Let's examine the main elements and features:
File Menu: The File menu allows you to create new projects, open existing
ones, import files, and manage project settings.
Edit Menu: This menu is dedicated to editing features, including copy,
paste, find, and replace, and other text manipulation tools.
View Menu: Here, you can customize the layout of your workspace,
manage tool windows, and toggle various UI elements according to your
preferences.
Navigate Menu: This menu is instrumental in navigating through your
project, providing quick access to classes, files, symbols, and specific lines
of code. It helps you efficiently move around your codebase.
Code Menu: The Code menu contains an excess of options for code
analysis, formatting, and generation. You can find tools for refactoring,
code inspections, and managing code style settings to ensure your code is
clean and follows best practices.
Run Menu: This menu is essential for running and debugging your Python
code. You can execute scripts, manage configurations, and analyze runtime
behaviors to identify and fix any issues.
Tools Menu: Here, you can access various tools integrated into PyCharm,
such as the built-in terminal, version control systems, and database
management tools, facilitating a seamless development experience.
VCS Menu: This menu is dedicated to version control systems like Git. You
can perform Git operations, manage branches, commit changes, and resolve
merge conflicts directly from PyCharm.
Window Menu: This menu allows you to manage open windows, editor
tabs, and tool windows within the PyCharm interface, enabling you to work
on multiple files or projects simultaneously.
Copy and paste the selected calculation code, which is highlighted in gray
in the book, to the “main.py” screen and click on “Run Main” or “^R” to
execute the example. This book is a practice guide purpose. Feel free to
change the numeric examples to your data.
How to install necessary packages in Pycharm:
Go to "File" > "Settings" > "Project: your_project_name" > "Python
Interpreter."
Click on the '+' icon to add a new package.
Search for the package you want and click "Install Package."
These are the required packages for this book calculation examples:
“FinancialMaths, Pillow, appdirs, certifi charset-normalizer, contourpy,
cycler, fonttools, frozendict html5lib, idna, importlib-resources, kiwisolver,
Ixml, matplotlib, multitasking, numpy, numpy-financial, packaging,
pandas, peewee, pip, pyparsing, python-dateutil, pytz, requests, scipy,
setuptools, soupsieve ta tzdata, urllibe, webencodings, wheel, yfinance,
zipp”.
CHAPTER 1
This chapter consist best-known 20 finance formulas along with their
corresponding code examples in both R and Python:
1. Compound Interest
Compound interest is the interest that is computed on the original principle
of a loan or deposit, as well as the total interest that has accrued over time.
Compound interest permits the investment or debt to expand over time, in
contrast to simple interest, which simply calculates interest on the initial
principal amount. Compound interest is characterized by the addition of
interest to the principle as time goes on. This means that future interest
computations are based on the greater principal amount. The amount owing
on a loan, or the value of an investment increases exponentially because of
this compounding effect.
Formula: A = P * (1 + r/n)^(nt)
Where:
- A = Final amount
- P = Principal amount
- r = Annual interest rate
- n = Number of times interest is compounded per year
- t = Number of years
#R
compound_interest <- function(P, r, n, t) {
A <- P * (1 + r/n)^(n*t)
return(A)
}
# Python
def compound_interest(P, r, n, t):
A = P * (1 + r/n)**(n*t)
return A
This formula calculates the future value (A) of an initial investment (P)
with compound interest, given the interest rate (r), the number of
compounding periods per year (n), and the number of years (t).
Let's walk through a numeric example to illustrate how the code works. For
this example, let's assume:
- Initial investment (P): $1000
- Annual interest rate (r): 0.05 (5%)
- Compounding periods per year (n): 12 (monthly compounding)
- Number of years (t): 3
Using the provided code, we can calculate the compound interest in both R
and Python.
#R
P <- 1000
r <- 0.05
n <- 12
t <- 3
compound_interest <- function(P, r, n, t) {
A <- P * (1 + r/n)^(n*t)
return(A)
}
result_r <- compound_interest(P, r, n, t)
print(result_r)
#Python
P = 1000
r = 0.05
n = 12
t=3
def compound_interest(P, r, n, t):
A = P * (1 + r/n)(n*t)
return A
result_python = compound_interest(P, r, n, t)
print(result_python)
In both cases, the output will be the future value (A) of the investment after
3 years with monthly compounding:
Output:
1161.472
The result represents the value of the investment after 3 years, accounting
for the compounded interest. The difference between the initial investment
and the future value is the interest earned through compounding. In this
example, an initial investment of $1000 at an annual interest rate of 5%,
compounded monthly, would grow to $ 1161.472 after 3 years.
2. Present Value
Present Value (PV) represents the current value of a sum of money or a
series of cash flows, discounted at a specific rate to reflect their current
worth. In other words, it is the current value of a future amount of money,
considering the time value of money.
Formula: PV = FV / (1 + r)^t
Where:
- PV = Present value
- FV = Future value
- r = Discount rate
- t = Number of years
#R
present_value <- function(FV, r, t) {
PV <- FV / (1 + r)^t
return(PV)
}
# Python
def present_value(FV, r, t):
PV = FV / (1 + r)**t
return PV
```
The provided code is an implementation of the present value formula in
both R and Python. This formula calculates the present value (PV) of a
future amount (FV) given a discount rate (r) and the number of years (t)
into the future.
Let's go through a numeric example to demonstrate how the code works.
For this example, let's assume:
- Future amount (FV): $1500
- Discount rate (r): 0.08 (8%)
- Number of years (t): 5
Using the given code, we can calculate the present value in both R and
Python.
R
FV <- 1500
r <- 0.08
t <- 5
present_value <- function(FV, r, t) {
PV <- FV / (1 + r)^t
return(PV)
}
result_r <- present_value(FV, r, t)
print(result_r)
```
Python
FV = 1500
r = 0.08
t=5
def present_value(FV, r, t):
PV = FV / (1 + r)**t
return PV
result_python = present_value(FV, r, t)
print(result_python)
```
In both cases, the output will be the present value (PV) of the $1500 future
amount discounted back to the present using an 8% annual discount rate
after 5 years:
Output
1020.8747955506294
The result represents the present value of the future amount. It indicates the
amount that needs to be invested today to have a value of $1500 after 5
years, considering an 8% annual discount rate. In this example, the present
value of the $1500 future amount is approximately $1020.87. This reflects
the fact that the value of money decreases over time due to factors like
inflation and the opportunity cost of not investing it elsewhere.
Python
import numpy as np
from scipy.optimize import root_scalar
cash_flows = [-100, 30, 35, 40, 45, 50]
def irr_equation(rate, cash_flows):
return sum([cf / (1 + rate)**t for t, cf in enumerate(cash_flows)])
irr_rate = root_scalar(irr_equation, args=(cash_flows,), bracket=[0, 1])
print(irr_rate.root)
Both the R and Python versions of the code do the same thing: they
calculate the IRR for a series of cash flows. The cash flows for this example
are:
- Year 0: -$100
- Year 1: $30
- Year 2: $35
- Year 3: $40
- Year 4: $45
- Year 5: $50
The provided code uses the IRR equation to find the discount rate at which
the net present value of the cash flows becomes zero. This is done by
numerically solving the equation using the `uniroot` function in R and the
`root_scalar` function in Python.
Output
R: 0.2575398
Python: 0.2575161362187582
This IRR value suggests that the series of cash flows has an internal rate of
return of approximately 25.75%. This means that, given the timing and
amounts of the cash flows, the investment could potentially yield a return
equivalent to that rate.
Python
def capm_return(Rf, beta, market_return):
expected_return = Rf + beta * (market_return - Rf)
return expected_return
Rf = 0.03 # Risk-free rate (3%)
beta = 1.2 # Asset's beta
market_return = 0.08 # Market's expected return (8%)
result_python = capm_return(Rf, beta, market_return)
print(result_python)
In both cases, the output will be the calculated expected return based on the
CAPM formula:
Output
R: 0.09
Python: 0.09
This means that, according to the CAPM model, an asset with a beta of 1.2,
a risk-free rate of 3%, and a market expected return of 8% would be
expected to have a return of approximately 9%. The CAPM formula
accounts for the asset's sensitivity to market risk (beta) and adjusts the
return accordingly relative to the risk-free rate and the market's expected
return.
Python
from scipy.stats import norm
import numpy as np
def black_scholes_call(S, X, r, T, sigma):
d1 = (np.log(S/X) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
call_price = S * norm.cdf(d1) - X * np.exp(-r * T) * norm.cdf(d2)
return call_price
# Define input parameters
S0 = 100 # Current stock price
X = 100 # Strike price
r = 0.05 # Risk-free rate
T=1 # Time to expiration in years
sigma = 0.2 # Volatility
# Calculate call option price using Black-Scholes
call_price = black_scholes_call(S0, X, r, T, sigma)
print(call_price)
Output
R: [1] 5
Python: 5.0
This means that the company's total debt is five times its total equity,
indicating a relatively high level of financial leverage.
Output
R: [1] 1.333333
Python: 1.3333333333333333
This means that for every $1 of current liabilities, the company has $1.33 in
easily liquid assets (current assets excluding inventory). A Quick Ratio
above 1 indicates that the company can cover its short-term obligations with
its most liquid assets, suggesting a relatively healthy short-term liquidity
position.
# Python
def ema(price_data, n):
ema_values = price_data.ewm(span=n, adjust=False).mean()
return ema_values
Example
# R Example
set.seed(123) # For reproducibility
price_data <- runif(20, min = 1, max = 100) # Generating random price data
n <- 5 # Window size
ema <- function(price_data, n) {
ema_values <- EMA(price_data, n = n)
return(ema_values)
}
# Defining a simple EMA function for demonstration purposes
EMA <- function(x, n) {
alpha <- 2 / (n + 1)
ema_values <- numeric(length(x))
ema_values[1] <- x[1]
for (i in 2:length(x)) {
ema_values[i] <- alpha * x[i] + (1 - alpha) * ema_values[i - 1]
}
return(ema_values)
}
result <- ema(price_data, n)
print(result)
# Python Example
import pandas as pd
import numpy as np
# Generating random price data
np.random.seed(123) # For reproducibility
price_data = pd.Series(np.random.uniform(1, 100, 20))
n = 5 # Window size
def ema(price_data, n):
ema_values = price_data.ewm(span=n, adjust=False).mean()
return ema_values
result = ema(price_data, n)
print(result)
Output
R
[1] 29.47017 45.99419 44.49236 59.13448 70.79174 49.03119 50.44828
63.41535 60.80759 55.94001 69.20217
[12] 61.42814 63.64526 61.66041 44.83679 59.91875 48.40006 33.98801
33.81339 54.37421
Python
69.950449, 56.409564, 45.425808, 48.810592, 56.616204, 52.039983,
67.391874, 67.860630, 61.444506, 54.236216, 47.815685, 56.269097,
52.318949, 37.182003, 38.256796, 50.191712, 39.816702, 32.667709,
39.653002, 44.318978
Output
R
[1] NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN,
NaN, 40.926534, 46.121784, 55.981564, 49.480965, 45.249295,
47.732551, 51.412798
Python
NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN,
NaN, 40.926534, 46.121784, 55.981564, 49.480965, 45.249295,
47.732551, 51.412798
Example
# R Example
set.seed(123) # For reproducibility
price_data <- runif(20, min = 1, max = 100) # Generating random price data
n_fast <- 12
n_slow <- 26
n_signal <- 9
macd <- function(price_data, n_fast, n_slow, n_signal) {
macd_values <- MACD(price_data, nFast = n_fast, nSlow = n_slow, nSig
= n_signal)
return(macd_values)
}
# Defining a simple MACD function for demonstration purposes
MACD <- function(x, nFast, nSlow, nSig) {
ema_fast <- EMA(x, nFast)
ema_slow <- EMA(x, nSlow)
macd_line <- ema_fast - ema_slow
signal_line <- EMA(macd_line, nSig)
macd_values <- data.frame(macd_line = macd_line, signal_line =
signal_line)
return(macd_values)
}
EMA <- function(x, n) {
alpha <- 2 / (n + 1)
ema_values <- numeric(length(x))
ema_values[1] <- x[1]
for (i in 2:length(x)) {
ema_values[i] <- alpha * x[i] + (1 - alpha) * ema_values[i - 1]
}
return(ema_values)
}
result <- macd(price_data, n_fast, n_slow, n_signal)
print(result)
# Python Example
import pandas as pd
import numpy as np
# Generating random price data
np.random.seed(123) # For reproducibility
price_data = pd.Series(np.random.uniform(1, 100, 20))
n_fast = 12
n_slow = 26
n_signal = 9
def macd(price_data, n_fast, n_slow, n_signal):
ema_fast = price_data.ewm(span=n_fast, adjust=False).mean()
ema_slow = price_data.ewm(span=n_slow, adjust=False).mean()
macd_line = ema_fast - ema_slow
signal_line = macd_line.ewm(span=n_signal, adjust=False).mean()
histogram = macd_line - signal_line
return macd_line, signal_line, histogram
result_macd, result_signal, result_histogram = macd(price_data, n_fast,
n_slow, n_signal)
print("MACD Line:")
print(result_macd)
print("\nSignal Line:")
print(result_signal)
print("\nHistogram:")
print(result_histogram)
Output Summary
R
macd_line signal_line
1 0.0000000 0.0000000 0.0000000
2 3.9544642 0.7908928 0.7908928
3 4.0119058 1.4350954 1.4350954
4 7.7548945 2.6990553 2.6990553
5 11.0527674 4.3697977 4.3697977
6 6.4431129 4.7844607 4.7844607
7 6.5690342 5.1413754 5.1413754
8 9.4699726 6.0070949 6.0070949
9 8.9419682 6.5940695 6.5940695
10 7.6775497 6.8107656 6.8107656
11 10.5498593 7.5585843 7.5585843
12 8.7036655 7.7876006 7.7876006
13 8.9289235 8.0158652 8.0158652
14 8.1749185 8.0476758 8.0476758
15 3.7815179 7.1944442 7.1944442
16 6.5897696 7.0735093 7.0735093
17 3.5520218 6.3692118 6.3692118
18 -0.4797585 4.9994178 4.9994178
19 -1.3755231 3.7244296 3.7244296
20 2.8867411 3.5568919 3.5568919
Python
MACD Line: Signal Line: Histogram:
0 0.000000 0 0.000000 0 0.000000
1 -3.240554 1 -0.648111 1 -2.592443
2 -6.210742 2 -1.760637 2 -4.450105
3 -5.904606 3 -2.589431 3 -3.315176
4 -4.269481 4 -2.925441 4 -1.344040
5 -5.280248 5 -3.396402 5 -1.883846
6 -1.607920 6 -3.038706 6 1.430786
7 -1.049540 7 -2.640873 7 1.591333
8 -2.210371 8 -2.554772 8 0.344401
9 -3.796072 9 -2.803032 9 -0.993039
10 -5.381666 10 -3.318759 10 -2.062907
11 -3.515214 11 -3.358050 11 -0.157164
12 -4.306862 12 -3.547812 12 -0.759049
13 -7.870311 13 -4.412312 13 -3.457999
14 -7.900271 14 -5.109904 14 -2.790367
15 -5.148970 15 -5.117717 15 -0.031253
16 -7.321769 16 -5.558528 16 -1.763242
17 -8.996263 17 -6.246075 17 -2.750189
18 -7.393394 18 -6.475538 18 -0.917855
19 -6.051147 19 -6.390660 19 0.339513
5. Bollinger Bands
This tool consists of a middle band, which is an N-period simple moving
average, and two outer bands that are calculated by adding and subtracting a
specified number of standard deviations from the middle band. The purpose
of Bollinger Bands is to provide a relative definition of high and low prices
of an asset price.
#R
bollinger_bands <- function(price_data, n, sd_multiplier) {
bb <- BBands(price_data, n = n, sd = sd_multiplier)
return(bb)
}
# Python
def bollinger_bands(price_data, n, sd_multiplier):
rolling_mean = price_data.rolling(window=n).mean()
rolling_std = price_data.rolling(window=n).std()
upper_band = rolling_mean + sd_multiplier * rolling_std
lower_band = rolling_mean - sd_multiplier * rolling_std
return upper_band, lower_band
Example
# R Example
set.seed(123) # For reproducibility
price_data <- runif(20, min = 1, max = 100) # Generating random price data
n <- 20 # Window size
sd_multiplier <- 2 # Standard deviation multiplier
bollinger_bands <- function(price_data, n, sd_multiplier) {
bb <- BBands(price_data, n = n, sd = sd_multiplier)
return(bb)
}
# Defining a simple BBands function for demonstration purposes
BBands <- function(x, n, sd) {
sma <- SMA(x, n = n)
std_dev <- sqrt(runSum((x - sma)^2, n = n) / n)
upper_band <- sma + sd * std_dev
lower_band <- sma - sd * std_dev
bb_values <- data.frame(upper_band = upper_band, middle_band = sma,
lower_band = lower_band)
return(bb_values)
}
SMA <- function(x, n) {
sma_values <- SMA(x, n = n)
return(sma_values)
}
result <- bollinger_bands(price_data, n, sd_multiplier)
print(result)
# Python Example
import pandas as pd
import numpy as np
# Generating random price data
np.random.seed(123) # For reproducibility
price_data = pd.Series(np.random.uniform(10, 30, 20))
n = 7 # Window size
sd_multiplier = 2 # Standard deviation multiplier
def bollinger_bands(price_data, n, sd_multiplier):
rolling_mean = price_data.rolling(window=n).mean()
rolling_std = price_data.rolling(window=n).std()
upper_band = rolling_mean + sd_multiplier * rolling_std
lower_band = rolling_mean - sd_multiplier * rolling_std
return upper_band, lower_band
upper_band, lower_band = bollinger_bands(price_data, n, sd_multiplier)
print("Upper Bollinger Band:")
print(upper_band)
print("\nLower Bollinger Band:")
print(lower_band)
Output Summary
R
macd_line 0 0.0000000 1 3.9544642 2 4.0119058 3
7.7548945 4 11.0527674 5 6.4431129 6
6.5690342 7 9.4699726 8 8.9419682 9
7.6775497 1010.549859311 8.7036655 12
8.9289235 13 8.1749185 14 3.7815179 15
6.5897696 16 3.5520218 17
0.4797585 18 -1.3755231 19 2.8867411
Signal Line 0 0.0000000 1 0.7908928 2 1.4350954 3
2.6990553 4 4.3697977 5 4.7844607 6
5.1413754 7 6.0070949 8 6.5940695 9
6.8107656 10 7.5585843 11 7.7876006 12
8.0158652 13 8.0476758 14 7.1944442 15
7.0735093 16 6.3692118 17 4.9994178 18
3.7244296 19 3.5568919
Python
Upper Bollinger Band:
NaN, NaN, NaN, NaN, NaN, NaN, 31.752242, 31.679116, 31.295640,
30.377123, 30.687927, 30.756538, 30.735017, 27.899515, 26.038009,
28.239415, 28.442307, 28.566102, 26.672172, 27.243837
Lower Bollinger Band:
NaN, NaN, NaN, NaN, NaN, NaN, 10.442698, 10.449312, 11.945889,
13.808783, 12.308626, 12.294762, 12.404659, 9.976811, 10.199543,
9.467071, 8.066317, 6.984086, 7.749454, 7.710677
6. Average True Range (ATR)
ATR is a technical analysis indicator used to measure market volatility. It is
often employed to assist traders in setting stop-loss levels, as well as to
determine the size of potential price movements.
#R
atr <- function(high_prices, low_prices, close_prices, n) {
atr_values <- ATR(High = high_prices, Low = low_prices, Close =
close_prices, n = n)
return(atr_values)
}
# Python
def atr(high_prices, low_prices, close_prices, n):
true_range = pd.DataFrame({
"TR1": high_prices - low_prices,
"TR2": abs(high_prices - close_prices.shift()),
"TR3": abs(low_prices - close_prices.shift())
}).max(axis=1)
atr_values = true_range.rolling(window=n).mean()
return atr_values
Example
# R Example
# Generating random data
set.seed(123)
high_prices <- runif(20, min = 1, max = 100)
low_prices <- runif(20, min = 1, max = 100)
close_prices <- runif(20, min = 1, max = 100)
n <- 14 # Period
atr <- function(high_prices, low_prices, close_prices, n) {
true_range <- pmax(high_prices - low_prices, abs(high_prices -
lag(close_prices)), abs(low_prices - lag(close_prices)))
atr_values <- zoo::rollmean(true_range, n, fill = NA)
return(atr_values)
}
result <- atr(high_prices, low_prices, close_prices, n)
print(result)
# Python Example
import pandas as pd
import numpy as np
# Generating random price data
np.random.seed(123) # For reproducibility
high_prices = pd.Series(np.random.uniform(1, 100, 20))
low_prices = pd.Series(np.random.uniform(1, 100, 20))
close_prices = pd.Series(np.random.uniform(1, 100, 20))
n = 14 # Period
def atr(high_prices, low_prices, close_prices, n):
true_range = pd.DataFrame({
"TR1": high_prices - low_prices,
"TR2": abs(high_prices - close_prices.shift()),
"TR3": abs(low_prices - close_prices.shift())
}).max(axis=1)
atr_values = true_range.rolling(window=n).mean()
return atr_values
result = atr(high_prices, low_prices, close_prices, n)
print(result)
```
Output summary
R
[1] NA NA NA NA NA NA 51.17120 49.68334
51.94290 54.80079 55.40769
[12] 53.91450 54.99751
R
13 44.037914 14 44.638671 15 45.260395 16 41.819392
17 43.110840 18 42.794337 19 41.594103
7. Stochastic Oscillator
This is a momentum indicator in technical analysis that compares a closing
price to its price range over a specific period. It is used to identify
overbought and oversold conditions in a market, helping traders anticipate
potential price reversals.
#R
stochastic_oscillator <- function(high_prices, low_prices, close_prices, n,
k) {
stoch <- stochasticOscillator(high_prices, low_prices, close_prices, n = n,
k = k)
return(stoch)
}
# Python
def stochastic_oscillator(high_prices, low_prices, close_prices, n, k):
lowest_low = low_prices.rolling(window=n).min()
highest_high = high_prices.rolling(window=n).max()
stoch_k = 100 * (close_prices - lowest_low) / (highest_high -
lowest_low)
stoch_d = stoch_k.rolling(window=k).mean()
return stoch_k, stoch_d
```
Example
# R Example
set.seed(123)
high_prices <- runif(20, min = 1, max = 100)
low_prices <- runif(20, min = 1, max = 100)
close_prices <- runif(20, min = 1, max = 100)
n <- 14 # Period
k <- 3 # Smoothing period
stochastic_oscillator <- function(high_prices, low_prices, close_prices, n,
k) {
stoch_k <- numeric(length(high_prices))
for (i in (n:length(high_prices))) {
highest_high <- max(high_prices[(i - (n - 1)):i])
lowest_low <- min(low_prices[(i - (n - 1)):i])
stoch_k[i] <- 100 * (close_prices[i] - lowest_low) / (highest_high -
lowest_low)
}
stoch_d <- SMA(stoch_k, n = k)
return(list(stoch_k = stoch_k, stoch_d = stoch_d))
}
SMA <- function(x, n) {
weights <- rep(1 / n, n)
sma_values <- stats::filter(x, filter = weights, method = "convolution",
sides = 1)
return(sma_values)
}
result <- stochastic_oscillator(high_prices, low_prices, close_prices, n, k)
print(result)
# Python Example
import pandas as pd
import numpy as np
# Generating random price data
np.random.seed(123) # For reproducibility
high_prices = pd.Series(np.random.uniform(1, 100, 20))
low_prices = pd.Series(np.random.uniform(1, 100, 20))
close_prices = pd.Series(np.random.uniform(1, 100, 20))
n = 14 # Period
k = 3 # Smoothing period
def stochastic_oscillator(high_prices, low_prices, close_prices, n, k):
lowest_low = low_prices.rolling(window=n).min()
highest_high = high_prices.rolling(window=n).max()
stoch_k = 100 * (close_prices - lowest_low) / (highest_high -
lowest_low)
stoch_d = stoch_k.rolling(window=k).mean()
return stoch_k, stoch_d
stoch_k, stoch_d = stochastic_oscillator(high_prices, low_prices,
close_prices, n, k)
print("Stochastic K:")
print(stoch_k)
print("\nStochastic D:")
print(stoch_d)
Output summary
R
$stoch_k [11] 0.000000 0.000000 0.000000 -3.113965 57.533039
19.514468 11.040098 78.167648 93.371950 37.528611
$stoch_d [11] 0.000000 0.000000 0.000000 -1.037988 18.139691
24.644514 29.362535 36.240738 60.859899 69.689403
Python
Stochastic K: 50.971513, 28.206412, 23.857946, 36.562638, 66.301658,
88.149861, 47.072868
Stochastic D:34.345290, 29.542332, 42.240748, 63.671386, 67.174796
#R
macd_signal_cross <- function(price_data, n_fast, n_slow, n_signal) {
macd_values <- MACD(price_data, nFast = n_fast, nSlow = n_slow, nSig
= n_signal)
signal_cross = ifelse(macd_values$macd > macd_values$signal, 1,
ifelse(macd_values$macd < macd_values$signal, -1, 0))
return(signal_cross)
}
# Python
def macd_signal_cross(price_data, n_fast, n_slow, n_signal):
ema_fast = price_data.ewm(span=n_fast, adjust=False).mean()
ema_slow = price_data.ewm(span=n_slow, adjust=False).mean()
macd_line = ema_fast - ema_slow
signal_line = macd_line.ewm(span=n_signal, adjust=False).mean()
signal_cross = np.where(macd_line > signal_line, 1, np.where(macd_line
< signal_line, -1, 0))
return signal_cross
Example
# R Example
# Generating random price data
set.seed(123) # For reproducibility
price_data <- runif(40, min = 1, max = 100)
n_fast <- 12
n_slow <- 26
n_signal <- 9
macd_signal_cross <- function(price_data, n_fast, n_slow, n_signal) {
macd_values <- MACD(price_data, nFast = n_fast, nSlow = n_slow, nSig
= n_signal)
signal_cross <- ifelse(macd_values$macd > macd_values$signal, 1,
ifelse(macd_values$macd < macd_values$signal, -1, 0))
return(signal_cross)
}
# Define a simple MACD function for demonstration purposes
MACD <- function(price_data, nFast, nSlow, nSig) {
ema_fast <- EMA(price_data, n = nFast)
ema_slow <- EMA(price_data, n = nSlow)
macd_line <- ema_fast - ema_slow
signal_line <- SMA(macd_line, n = nSig)
macd_values <- data.frame(macd = macd_line, signal = signal_line)
return(macd_values)
}
EMA <- function(price_data, n) {
ema_values <- runMean(price_data, n)
return(ema_values)
}
SMA <- function(price_data, n) {
sma_values <- runMean(price_data, n)
return(sma_values)
}
result <- macd_signal_cross(price_data, n_fast, n_slow, n_signal)
print(result)
# Python Example
import pandas as pd
import numpy as np
# Generating random price data
np.random.seed(456) # For reproducibility
price_data = pd.Series(np.random.uniform(50, 150, 50))
n_fast = 10
n_slow = 20
n_signal = 5
def macd_signal_cross(price_data, n_fast, n_slow, n_signal):
ema_fast = price_data.ewm(span=n_fast, adjust=False).mean()
ema_slow = price_data.ewm(span=n_slow, adjust=False).mean()
macd_line = ema_fast - ema_slow
signal_line = macd_line.ewm(span=n_signal, adjust=False).mean()
signal_cross = np.where(macd_line > signal_line, 1, np.where(macd_line
< signal_line, -1, 0))
return signal_cross
result = macd_signal_cross(price_data, n_fast, n_slow, n_signal)
print(result)
Output
R
[36] 1 -1 1
Python
[ 0 -1 1…]
Output
R
[36] -1 -1…
Phyton
[ 0 -1 1…
13. Moving Average Golden Cross and Death Cross
The Moving Average Golden Cross and Death Cross are significant events
in technical analysis, particularly when analyzing the relationship between
short-term and long-term moving averages. The 50-day and 200-day SMAs
are common choices, but other combinations, such as 20-day and 50-day
can also be used based on the trader's strategy.
#R
moving_average_cross <- function(price_data, n_short, n_long) {
short_ma = SMA(price_data, n = n_short)
long_ma = SMA(price_data, n = n_long)
cross = ifelse(short_ma > long_ma, 1, ifelse(short_ma < long_ma, -1, 0))
return(cross)
}
# Python
def moving_average_cross(price_data, n_short, n_long):
short_ma = price_data.rolling(window=n_short).mean()
long_ma = price_data.rolling(window=n_long).mean()
cross = np.where(short_ma > long_ma, 1, np.where(short_ma < long_ma,
-1, 0))
return cross
Example
# R Example
set.seed(123) # For reproducibility
price_data <- runif(50, min = 50, max = 150)
n_short <- 5
n_long <- 20
moving_average_cross <- function(price_data, n_short, n_long) {
short_ma <- SMA(price_data, n = n_short)
long_ma <- SMA(price_data, n = n_long)
cross <- ifelse(short_ma > long_ma, 1, ifelse(short_ma < long_ma, -1, 0))
return(cross)
}
SMA <- function(x, n) {
sma_values <- stats::filter(x, filter = rep(1/n, n), method = "convolution",
sides = 1)
return(sma_values)
}
result <- moving_average_cross(price_data, n_short, n_long)
print(result)
# Python Example
import pandas as pd
import numpy as np
# Generating random price data
np.random.seed(123) # For reproducibility
price_data = pd.Series(np.random.uniform(50, 150, 50))
n_short = 5
n_long = 20
def moving_average_cross(price_data, n_short, n_long):
short_ma = price_data.rolling(window=n_short).mean()
long_ma = price_data.rolling(window=n_long).mean()
cross = np.where(short_ma > long_ma, 1, np.where(short_ma < long_ma,
-1, 0))
return cross
result = moving_average_cross(price_data, n_short, n_long)
print(result)
Output
R [36] -1 -1…] Phyton [ 0 0 …]
1. Portfolio Returns
The total performance, gain, or loss of a portfolio a group of investments or
assets owned by an individual or an organization referred to as portfolio
return. To calculate portfolio returns, one must evaluate the changes in the
total value of each individual holding in the portfolio over a certain time.
#R
portfolio_returns <- function(weights, returns) {
portfolio_return <- sum(weights * returns)
return(portfolio_return)
}
# Python
def portfolio_returns(weights, returns):
portfolio_return = sum(weights * returns)
return portfolio_return
Example
#R
weights <- c(0.3, 0.4, 0.3)
returns <- c(0.1, 0.05, 0.12)
portfolio_returns <- function(weights, returns) {
portfolio_return <- sum(weights * returns)
return(portfolio_return)
}
result <- portfolio_returns(weights, returns)
print(result)
# Python
import numpy as np
weights = np.array([0.3, 0.4, 0.3])
returns = np.array([0.1, 0.05, 0.12])
def portfolio_returns(weights, returns):
portfolio_return = np.sum(weights * returns)
return portfolio_return
result = portfolio_returns(weights, returns)
print(result)
Output: 0.086
2. Portfolio Volatility
The level of variance in a portfolio's returns over a certain period is
measured by portfolio volatility. Investors use it as a crucial statistic for risk
assessment to comprehend possible price volatility or variations in the value
of their investment portfolio.
#R
portfolio_volatility <- function(weights, cov_matrix) {
portfolio_variance <- t(weights) %*% cov_matrix %*% weights
portfolio_volatility <- sqrt(portfolio_variance)
return(portfolio_volatility)
}
# Python
import numpy as np
def portfolio_volatility(weights, cov_matrix):
portfolio_variance = np.dot(weights.T, np.dot(cov_matrix, weights))
portfolio_volatility = np.sqrt(portfolio_variance)
return portfolio_volatility
Example
#R
weights <- c(0.3, 0.4, 0.3)
cov_matrix <- matrix(c(0.1, 0.05, 0.02, 0.05, 0.12, 0.08, 0.02, 0.08, 0.15),
nrow = 3, ncol = 3, byrow = TRUE)
portfolio_volatility <- function(weights, cov_matrix) {
portfolio_variance <- t(weights) %*% cov_matrix %*% weights
portfolio_volatility <- sqrt(portfolio_variance)
return(portfolio_volatility)
}
result <- portfolio_volatility(weights, cov_matrix)
print(result)
# Python
import numpy as np
weights = np.array([0.3, 0.4, 0.3])
cov_matrix = np.array([[0.1, 0.05, 0.02], [0.05, 0.12, 0.08], [0.02, 0.08,
0.15]])
def portfolio_volatility(weights, cov_matrix):
portfolio_variance = np.dot(weights.T, np.dot(cov_matrix, weights))
portfolio_volatility = np.sqrt(portfolio_variance)
return portfolio_volatility
result = portfolio_volatility(weights, cov_matrix)
print(result)
Output: 0.2765863
#R
weights <- c(0.3, 0.4, 0.3)
returns <- c(0.1, 0.05, 0.12)
risk_free_rate <- 0.02
cov_matrix <- matrix(c(0.1, 0.05, 0.02, 0.05, 0.12, 0.08, 0.02, 0.08, 0.15),
nrow = 3, ncol = 3, byrow = TRUE)
portfolio_sharpe_ratio <- function(weights, returns, risk_free_rate,
cov_matrix) {
portfolio_return <- sum(weights * returns)
portfolio_volatility <- sqrt(t(weights) %*% cov_matrix %*% weights)
sharpe_ratio <- (portfolio_return - risk_free_rate) / portfolio_volatility
return(sharpe_ratio)
}
result <- portfolio_sharpe_ratio(weights, returns, risk_free_rate,
cov_matrix)
print(result)
# Python
import numpy as np
weights = np.array([0.3, 0.4, 0.3])
returns = np.array([0.1, 0.05, 0.12])
risk_free_rate = 0.02
cov_matrix = np.array([[0.1, 0.05, 0.02], [0.05, 0.12, 0.08], [0.02, 0.08,
0.15]])
def portfolio_sharpe_ratio(weights, returns, risk_free_rate, cov_matrix):
portfolio_return = np.sum(weights * returns)
portfolio_volatility = np.sqrt(np.dot(weights.T, np.dot(cov_matrix,
weights)))
sharpe_ratio = (portfolio_return - risk_free_rate) / portfolio_volatility
return sharpe_ratio
result = portfolio_sharpe_ratio(weights, returns, risk_free_rate, cov_matrix)
print(result)
Output 0.2386235
6. Efficient Frontier
The Efficient Frontier is a key concept which represents the set of optimal
portfolios that offer the maximum expected return for a given level of risk
or the minimum risk for a given level of expected return. Efficient
portfolios offer the optimal balance between return and risk as they are
situated on the Efficient Frontier.
#R
efficient_frontier <- function(returns, cov_matrix, num_portfolios) {
results <- matrix(NA, ncol = 3, nrow = num_portfolios)
colnames(results) <- c("Return", "Volatility", "Sharpe Ratio")
for (i in 1:num_portfolios) {
weights <- runif(length(returns))
weights <- weights / sum(weights)
portfolio_return <- sum(weights * returns)
portfolio_volatility <- sqrt(t(weights) %*% cov_matrix %*% weights)
sharpe_ratio <- portfolio_return / portfolio_volatility
results[i, ] <- c(portfolio_return, portfolio_volatility, sharpe_ratio)
}
return(results)
}
# Python
def efficient_frontier(returns, cov_matrix, num_portfolios):
results = np.zeros((num_portfolios, 3))
for i in range(num_portfolios):
weights = np.random.random(len(returns))
weights /= np.sum(weights)
portfolio_return = np.sum(weights * returns)
portfolio_volatility = np.sqrt(np.dot(weights.T, np.dot(cov_matrix,
weights)))
sharpe_ratio = portfolio_return / portfolio_volatility
results[i, :] = [portfolio_return, portfolio_volatility, sharpe_ratio]
return results
Example
#R
num_portfolios <- 5
returns <- c(0.1, 0.05, 0.12)
cov_matrix <- matrix(c(0.1, 0.05, 0.02, 0.05, 0.12, 0.08, 0.02, 0.08, 0.15),
nrow = 3, ncol = 3, byrow = TRUE)
efficient_frontier <- function(returns, cov_matrix, num_portfolios) {
results <- matrix(NA, ncol = 3, nrow = num_portfolios)
colnames(results) <- c("Return", "Volatility", "Sharpe Ratio")
for (i in 1:num_portfolios) {
weights <- runif(length(returns))
weights <- weights / sum(weights)
portfolio_return <- sum(weights * returns)
portfolio_volatility <- sqrt(t(weights) %*% cov_matrix %*% weights)
sharpe_ratio <- portfolio_return / portfolio_volatility
results[i, ] <- c(portfolio_return, portfolio_volatility, sharpe_ratio)
}
return(results)
}
result <- efficient_frontier(returns, cov_matrix, num_portfolios)
print(result)
# Python
import numpy as np
num_portfolios = 5
returns = np.array([0.1, 0.05, 0.12])
cov_matrix = np.array([[0.1, 0.05, 0.02], [0.05, 0.12, 0.08], [0.02, 0.08,
0.15]])
def efficient_frontier(returns, cov_matrix, num_portfolios):
results = np.zeros((num_portfolios, 3))
for i in range(num_portfolios):
weights = np.random.random(len(returns))
weights /= np.sum(weights)
portfolio_return = np.sum(weights * returns)
portfolio_volatility = np.sqrt(np.dot(weights.T, np.dot(cov_matrix,
weights)))
sharpe_ratio = portfolio_return / portfolio_volatility
results[i, :] = [portfolio_return, portfolio_volatility, sharpe_ratio]
return results
result = efficient_frontier(returns, cov_matrix, num_portfolios)
print(result)
Output
R
Return Volatility Sharpe Ratio
[1,] 0.09523565 0.3291460 0.2893417
[2,] 0.07310845 0.3017558 0.2422768
[3,] 0.08887063 0.3145006 0.2825769
[4,] 0.07235681 0.2854732 0.2534627
[5,] 0.10174720 0.2897313 0.3511778
Python
[[0.08534956 0.27684869 0.30828954]
[0.10634645 0.26873524 0.39572947]
[0.08518059 0.27605724 0.30856133]
[0.08485062 0.27646624 0.30691131]
[0.09982499 0.2738654 0.36450386]]
8. Maximum Drawdown
The highest peak-to-trough decrease or loss in the value of an investment or
portfolio over a certain period is measured by a risk indicator called
maximum drawdown, or MDD. It gives insight on the largest loss an
investor would have sustained over a specific time frame for investments.
#R
max_drawdown <- function(returns) {
cum_returns <- cumprod(1 + returns)
peak <- cummax(cum_returns)
drawdown <- (cum_returns - peak) / peak
max_drawdown <- max(drawdown)
return(max_drawdown)
}
# Python
def max_drawdown(returns):
cum_returns = np.cumprod(1 + returns)
peak = np.maximum.accumulate(cum_returns)
drawdown = (cum_returns - peak) / peak
max_drawdown = np.max(drawdown)
return max_drawdown
Example
#R
returns <- c(0.1, -0.05, 0.03, -0.02, 0.04)
max_drawdown <- function(returns) {
cum_returns <- cumprod(1 + returns)
peak <- cummax(cum_returns)
drawdown <- (cum_returns - peak) / peak
max_drawdown <- max(drawdown)
return(max_drawdown)
}
result <- max_drawdown(returns)
print(result)
# Python
import numpy as np
returns = np.array([0.1, -0.05, 0.03, -0.02, 0.04])
def max_drawdown(returns):
cum_returns = np.cumprod(1 + returns)
peak = np.maximum.accumulate(cum_returns)
drawdown = (cum_returns - peak) / peak
max_drawdown = np.max(drawdown)
return max_drawdown
result = max_drawdown(returns)
print(result)
Output
R [1] 0 Python 0.0
9. Tracking Error
The standard deviation of the difference between the returns of an
investment portfolio and the returns of a benchmark index is measured
using a metric called tracking error. Investors and portfolio managers
consider it as a critical statistic to evaluate how effectively a portfolio is
following or imitating its benchmark.
#R
tracking_error <- function(portfolio_returns, benchmark_returns) {
excess_returns <- portfolio_returns - benchmark_returns
tracking_error <- sd(excess_returns)
return(tracking_error)
}
# Python
def tracking_error(portfolio_returns, benchmark_returns):
excess_returns = portfolio_returns - benchmark_returns
tracking_error = np.std(excess_returns)
return tracking_error
Example
#R
portfolio_returns <- c(0.1, 0.05, 0.12, 0.08, 0.11)
benchmark_returns <- c(0.05, 0.03, 0.11, 0.07, 0.09)
tracking_error <- function(portfolio_returns, benchmark_returns) {
excess_returns <- portfolio_returns - benchmark_returns
tracking_error <- sd(excess_returns)
return(tracking_error)
}
result <- tracking_error(portfolio_returns, benchmark_returns)
print(result)
# Python
import numpy as np
portfolio_returns = np.array([0.1, 0.05, 0.12, 0.08, 0.11])
benchmark_returns = np.array([0.05, 0.03, 0.11, 0.07, 0.09])
def tracking_error(portfolio_returns, benchmark_returns):
excess_returns = portfolio_returns - benchmark_returns
tracking_error = np.std(excess_returns)
return tracking_error
result = tracking_error(portfolio_returns, benchmark_returns)
print(result)
Output
0.01643168
Output
R
5%
-0.018
Python
-0.018000000000000002
Output
R
[,1] [,2] [,3]
[1,] 0.3 0.4 0.3
[2,] 0.3 0.4 0.3
[3,] 0.3 0.4 0.3
[4,] 0.3 0.4 0.3
[5,] 0.3 0.4 0.3
Python
[[0.3 0.4 0.3]
[0.3 0.4 0.3]
[0.3 0.4 0.3]
[0.3 0.4 0.3]
[0.3 0.4 0.3]]
CHAPTER 4
20 commonly used code examples for making investment decisions in both
R and Python:
3. Payback Period
The payback period is used to assess how long it will take an investment to
recover its initial investment. The breakeven point is the amount of time
needed for an investment's total cash inflows to equal its total cash
outflows.
#R
payback_period <- function(cash_flows) {
cumulative_cash_flows <- cumsum(cash_flows)
payback_index <- which(cumulative_cash_flows >= 0)[1]
payback_period <- ifelse(payback_index > 1, payback_index - 1 +
(cumulative_cash_flows[payback_index - 1] / cash_flows[payback_index]),
payback_index)
return(payback_period)
}
# Python
def payback_period(cash_flows):
cumulative_cash_flows = np.cumsum(cash_flows)
payback_index = np.where(cumulative_cash_flows >= 0)[0][0]
if payback_index > 0:
payback_period = payback_index - 1 +
(cumulative_cash_flows[payback_index - 1] / cash_flows[payback_index])
else:
payback_period = payback_index
return payback_period
Example
# R Example
cash_flows_r <- c(-150, 50, 60, 70, 80)
payback_period_r <- function(cash_flows) {
cumulative_cash_flows <- cumsum(cash_flows)
payback_index <- which(cumulative_cash_flows >= 0)[1]
if (payback_index == 1) {
return(payback_index)
} else {
payback_period <- payback_index - 1 +
abs(cumulative_cash_flows[payback_index - 1]) /
cash_flows[payback_index]
return(payback_period)
}
}
result_r <- payback_period_r(cash_flows_r)
print(result_r)
# Python Example
import numpy as np
cash_flows_py = np.array([-150, 50, 60, 70, 80])
def payback_period_py(cash_flows):
cumulative_cash_flows = np.cumsum(cash_flows)
payback_index = np.where(cumulative_cash_flows >= 0)[0][0]
if payback_index == 0:
return payback_index
elif cash_flows[payback_index] == 0:
return payback_index
else:
payback_period = payback_index +
(abs(cumulative_cash_flows[payback_index - 1]) /
cash_flows[payback_index])
return payback_period
result_py = payback_period_py(cash_flows_py)
print(result_py)
Output
R
[1] 3.571429
Python
3.571428571428571
7. Sharpe Ratio
The Sharpe Ratio measures the risk-adjusted performance of an investment,
portfolio, or strategy.
#R
sharpe_ratio <- function(portfolio_return, risk_free_rate,
portfolio_volatility) {
sharpe_ratio_value <- (portfolio_return - risk_free_rate) /
portfolio_volatility
return(sharpe_ratio_value)
}
# Python
def sharpe_ratio(portfolio_return, risk_free_rate, portfolio_volatility):
sharpe_ratio_value = (portfolio_return - risk_free_rate) /
portfolio_volatility
return sharpe_ratio_value
Example
# R Example
portfolio_return_r <- 0.1
risk_free_rate_r <- 0.05
portfolio_volatility_r <- 0.12
sharpe_ratio_r <- function(portfolio_return, risk_free_rate,
portfolio_volatility) {
sharpe_ratio_value <- (portfolio_return - risk_free_rate) /
portfolio_volatility
return(sharpe_ratio_value)
}
result_r <- sharpe_ratio_r(portfolio_return_r, risk_free_rate_r,
portfolio_volatility_r)
print(result_r)
# Python Example
def sharpe_ratio(portfolio_return, risk_free_rate, portfolio_volatility):
sharpe_ratio_value = (portfolio_return - risk_free_rate) /
portfolio_volatility
return sharpe_ratio_value
portfolio_return_py = 0.1
risk_free_rate_py = 0.05
portfolio_volatility_py = 0.12
result_py = sharpe_ratio(portfolio_return_py, risk_free_rate_py,
portfolio_volatility_py)
print(result_py)
Output
R
[1] 0.4166667
Python
0.4166666666666667
8. Treynor Ratio
The Sharpe Ratio measures the risk-adjusted performance of a portfolio.
#R
treynor_ratio <- function(portfolio_return, risk_free_rate, beta) {
treynor_ratio_value <- (portfolio_return - risk_free_rate) / beta
return(treynor_ratio_value)
}
# Python
def treynor_ratio(portfolio_return, risk_free_rate, beta):
treynor_ratio_value = (portfolio_return - risk_free_rate) / beta
return treynor_ratio_value
Example
# R Example
portfolio_return_r <- 0.15
risk_free_rate_r <- 0.05
beta_r <- 1.2
treynor_ratio_r <- function(portfolio_return, risk_free_rate, beta) {
treynor_ratio_value <- (portfolio_return - risk_free_rate) / beta
return(treynor_ratio_value)
}
result_r <- treynor_ratio_r(portfolio_return_r, risk_free_rate_r, beta_r)
print(result_r)
# Python Example
def treynor_ratio(portfolio_return, risk_free_rate, beta):
treynor_ratio_value = (portfolio_return - risk_free_rate) / beta
return treynor_ratio_value
portfolio_return_py = 0.15
risk_free_rate_py = 0.05
beta_py = 1.2
result_py = treynor_ratio(portfolio_return_py, risk_free_rate_py, beta_py)
print(result_py)
Output
R [1] 0.08333333
Python
0.08333333333333333
9. Sortino Ratio
The Sortino Ratio is the risk-adjusted performance of an investment by
focusing specifically on the downside risk.
#R
sortino_ratio <- function(portfolio_return, risk_free_rate,
downside_deviation) {
sortino_ratio_value <- (portfolio_return - risk_free_rate) /
downside_deviation
return(sortino_ratio_value)
}
# Python
def sortino_ratio(portfolio_return, risk_free_rate, downside_deviation):
sortino_ratio_value = (portfolio_return - risk_free_rate) /
downside_deviation
return sortino_ratio_value
Another Example
# R Example
portfolio_return_r <- 0.12
risk_free_rate_r <- 0.03
downside_deviation_r <- 0.08
sortino_ratio_r <- function(portfolio_return, risk_free_rate,
downside_deviation) {
sortino_ratio_value <- (portfolio_return - risk_free_rate) /
downside_deviation
return(sortino_ratio_value)
}
result_r <- sortino_ratio_r(portfolio_return_r, risk_free_rate_r,
downside_deviation_r)
print(result_r)
# Python Example
def sortino_ratio(portfolio_return, risk_free_rate, downside_deviation):
sortino_ratio_value = (portfolio_return - risk_free_rate) /
downside_deviation
return sortino_ratio_value
portfolio_return_py = 0.12
risk_free_rate_py = 0.03
downside_deviation_py = 0.08
result_py = sortino_ratio(portfolio_return_py, risk_free_rate_py,
downside_deviation_py)
print(result_py)
Output
R
[1] 1.125
Python
1.125
Output
R
[1] 1.5
Python
1.5000000000000002
#R
portfolio_rebalance <- function(weights_initial, returns, rebalance_period)
{
portfolio_weights <- matrix(NA, ncol = length(weights_initial), nrow =
length(returns))
for (i in 1:length(returns)) {
if (i %% rebalance_period == 1 || i == 1) {
weights_current = weights_initial
} else {
weights_current = portfolio_weights[i - 1, ] * (1 + returns[i - 1])
weights_current = weights_current / sum(weights_current)
}
portfolio_weights[i, ] = weights_current
}
return(portfolio_weights)
}
# Python
def portfolio_rebalance(weights_initial, returns, rebalance_period):
portfolio_weights = np.zeros((len(returns), len(weights_initial)))
for i in range(len(returns)):
if (i % rebalance_period == 0) or (i == 0):
weights_current = weights_initial
else:
weights_current = portfolio_weights[i - 1, :] * (1 + returns[i - 1])
weights_current /= np.sum(weights_current)
portfolio_weights[i, :] = weights_current
return portfolio_weights
Example
#R
weights_initial <- c(0.3, 0.4, 0.3)
returns <- c(0.05, 0.02, 0.03, 0.01, 0.04)
rebalance_period <- 2
portfolio_rebalance <- function(weights_initial, returns, rebalance_period)
{
portfolio_weights <- matrix(NA, ncol = length(weights_initial), nrow =
length(returns))
for (i in 1:length(returns)) {
if (i %% rebalance_period == 1 || i == 1) {
weights_current = weights_initial
} else {
weights_current = portfolio_weights[i - 1, ] * (1 + returns[i - 1])
weights_current = weights_current / sum(weights_current)
}
portfolio_weights[i, ] = weights_current
}
return(portfolio_weights)
}
result_r <- portfolio_rebalance(weights_initial, returns, rebalance_period)
print(result_r)
# Python
import numpy as np
weights_initial = np.array([0.3, 0.4, 0.3])
returns = np.array([0.05, 0.02, 0.03, 0.01, 0.04])
rebalance_period = 2
def portfolio_rebalance(weights_initial, returns, rebalance_period):
portfolio_weights = np.zeros((len(returns), len(weights_initial)))
for i in range(len(returns)):
if (i % rebalance_period == 0) or (i == 0):
weights_current = weights_initial
else:
weights_current = portfolio_weights[i - 1, :] * (1 + returns[i - 1])
weights_current /= np.sum(weights_current)
portfolio_weights[i, :] = weights_current
return portfolio_weights
result_py = portfolio_rebalance(weights_initial, returns, rebalance_period)
print(result_py)
Output
R
[,1] [,2] [,3]
[1,] 0.3 0.4 0.3
[2,] 0.3 0.4 0.3
[3,] 0.3 0.4 0.3
[4,] 0.3 0.4 0.3
[5,] 0.3 0.4 0.3
Python
[[0.3 0.4 0.3]
[0.3 0.4 0.3]
[0.3 0.4 0.3]
[0.3 0.4 0.3]
[0.3 0.4 0.3]]
Output
R
[,1] [,2] [,3]
[1,] 0.3 0.4 0.3
[2,] 0.3 0.4 0.3
[3,] 0.3 0.4 0.3
[4,] 0.3 0.4 0.3
[5,] 0.3 0.4 0.3
Python
[1.12172823e-16 1.11022302e-16 1.00000000e+00]
3. Compound Interest
Compound Interest refers to the interest earned on both the initial principal
and any accumulated interest from previous periods.
#R
compound_interest <- function(pv, rate, n) {
compound_interest_value <- pv * (1 + rate)^n - pv
return(compound_interest_value)
}
# Example in R
compound_interest_value_r <- compound_interest(1000, 0.05, 3)
print(compound_interest_value_r)
# Python
def compound_interest(pv, rate, n):
compound_interest_value = pv * (1 + rate)**n - pv
return compound_interest_value
# Example in Python
compound_interest_value_py = compound_interest(1000, 0.05, 3)
print(compound_interest_value_py)
Output
R
[1] 157.625
Python
157.62500000000023
4. Simple Interest
Simple Interest is calculating interest on a loan or investment based solely
on the initial principal amount. The key components of simple interest
include the principal amount, the interest rate, and the time for which the
interest is calculated.
#R
simple_interest <- function(pv, rate, n) {
simple_interest_value <- pv * rate * n
return(simple_interest_value)
}
# Example in R
simple_interest_value_r <- simple_interest(1000, 0.05, 3)
print(simple_interest_value_r)
# Python
def simple_interest(pv, rate, n):
simple_interest_value = pv * rate * n
return simple_interest_value
# Example in Python
simple_interest_value_py = simple_interest(1000, 0.05, 3)
print(simple_interest_value_py)
Output
R
[1] 150
Python
150.0
Output
R
[1] 0.0511619
Python
0.051161897881732976
4. Forward Points
Forward points, also known as swap points, represent the interest rate
differential between two currencies in the foreign exchange market.
#R
forward_points <- function(forward_rate, spot_rate) {
forward_points_value <- (forward_rate - spot_rate) * 10000
return(forward_points_value)
}
# Example usage
result_r <- forward_points(1.25, 1.2)
print(result_r)
# Python
def forward_points(forward_rate, spot_rate):
forward_points_value = (forward_rate - spot_rate) * 10000
return forward_points_value
# Example usage
result_py = forward_points(1.25, 1.2)
print(result_py)
Output
R
[1] 500
Python
500.00000000000045
5. FX Swap Points
FX point represents the interest rate differential between two currencies in a
foreign exchange (forex) swap. An FX swap is a simultaneous purchase and
sale of identical amounts of one currency for another with two different
value dates: a near date (spot) and a future date.
#R
swap_points <- function(domestic_interest, foreign_interest, time) {
swap_points_value <- (domestic_interest - foreign_interest) * time *
10000
return(swap_points_value)
}
# Example usage
result_r <- swap_points(0.03, 0.02, 2)
print(result_r)
# Python
def swap_points(domestic_interest, foreign_interest, time):
swap_points_value = (domestic_interest - foreign_interest) * time *
10000
return swap_points_value
# Example usage
result_py = swap_points(0.03, 0.02, 2)
print(result_py)
Output
R
[1] 200
Python
199.99999999999997
#R
option_delta <- function(spot_rate, strike_price, time, domestic_interest,
foreign_interest, volatility, option_type) {
d1 <- (log(spot_rate / strike_price) + (domestic_interest - foreign_interest
+ 0.5 * volatility^2) * time) / (volatility * sqrt(time))
if (option_type == "call") {
option_delta_value <- pnorm(d1)
} else if (option_type == "put") {
option_delta_value <- pnorm(d1) - 1
}
return(option_delta_value)
}
# Example usage
spot_rate_example <- 50
strike_price_example <- 45
time_example <- 0.5
domestic_interest_example <- 0.05
foreign_interest_example <- 0.03
volatility_example <- 0.25
option_type_example <- "call"
option_delta(spot_rate_example, strike_price_example, time_example,
domestic_interest_example, foreign_interest_example, volatility_example,
option_type_example)
Python Example:
# Python
import math
from scipy.stats import norm
def option_delta(spot_rate, strike_price, time, domestic_interest,
foreign_interest, volatility, option_type):
d1 = (math.log(spot_rate / strike_price) + (domestic_interest -
foreign_interest + 0.5 * volatility ** 2) * time) / (volatility *
math.sqrt(time))
if option_type == 'call':
option_delta_value = norm.cdf(d1)
elif option_type == 'put':
option_delta_value = norm.cdf(d1) - 1
return option_delta_value
# Example usage
spot_rate_example = 50
strike_price_example = 45
time_example = 0.5
domestic_interest_example = 0.05
foreign_interest_example = 0.03
volatility_example = 0.25
option_type_example = "call"
print(option_delta(spot_rate_example, strike_price_example,
time_example, domestic_interest_example, foreign_interest_example,
volatility_example, option_type_example))
Output
R
[1] 0.770643
Python
0.7706429632810612
# R example
strike_from_delta <- function(spot_rate, time, domestic_interest,
foreign_interest, volatility, delta, option_type) {
d1 <- qnorm(delta) + (volatility * sqrt(time)) / 2
if (option_type == "call") {
strike_from_delta_value <- spot_rate * exp((foreign_interest -
domestic_interest) * time) * pnorm(d1)
} else if (option_type == "put") {
strike_from_delta_value <- spot_rate * exp((foreign_interest -
domestic_interest) * time) * pnorm(d1) - (pnorm(d1) - 1) * spot_rate
}
return(strike_from_delta_value)
}
# Example data
spot_rate <- 1.2
time <- 0.5
domestic_interest <- 0.03
foreign_interest <- 0.02
volatility <- 0.2
delta <- 0.6
option_type <- "call"
result <- strike_from_delta(spot_rate, time, domestic_interest,
foreign_interest, volatility, delta, option_type)
print(result)
# Python
from scipy.stats import norm
def strike_from_delta(spot_rate, time, domestic_interest, foreign_interest,
volatility, delta, option_type):
d1 = norm.ppf(delta) + (volatility * (time ** 0.5)) / 2
if option_type == "call":
strike_from_delta_value = spot_rate * (foreign_interest * time) *
norm.cdf(d1)
elif option_type == "put":
strike_from_delta_value = spot_rate * (foreign_interest * time) *
norm.cdf(d1) - (norm.cdf(d1) - 1) * spot_rate
return strike_from_delta_value
# Usage
spot_rate = 1.2
time = 0.5
domestic_interest = 0.03
foreign_interest = 0.02
volatility = 0.2
delta = 0.6
option_type = "call"
result = strike_from_delta(spot_rate, time, domestic_interest,
foreign_interest, volatility, delta, option_type)
print(result)
Output
R
[1] 0.7487105
Python
0.0075246342641871414
1. Bond Price
The Bond Price refers to the current market value or the present worth of a
bond. It represents the amount an investor is willing to pay for a bond in the
open market.
R:
calculate_bond_price <- function(coupon, ytm, face_value,
years_to_maturity) {
bond_price <- (coupon * (1 - (1 + ytm)^-years_to_maturity) / ytm) +
(face_value / (1 + ytm)^years_to_maturity)
return(bond_price)
}
# Example usage
coupon <- 50
ytm <- 0.05
face_value <- 1000
years_to_maturity <- 5
bond_price <- calculate_bond_price(coupon, ytm, face_value,
years_to_maturity)
print(bond_price)
Python:
def calculate_bond_price(coupon, ytm, face_value, years_to_maturity):
bond_price = (coupon * (1 - (1 + ytm)**-years_to_maturity) / ytm) +
(face_value / (1 + ytm)**years_to_maturity)
return bond_price
# Example usage
coupon = 50
ytm = 0.05
face_value = 1000
years_to_maturity = 5
bond_price = calculate_bond_price(coupon, ytm, face_value,
years_to_maturity)
print(bond_price)
Output
R
[1] 1000
Python
999.9999999999999
R:
# Define the function to calculate YTM
calculate_bond_ytm <- function(coupon, price, face_value,
years_to_maturity) {
ytm_func <- function(ytm) {
price - (coupon * (1 - (1 + ytm)^-years_to_maturity) / ytm) - (face_value
/ (1 + ytm)^years_to_maturity)
}
ytm <- uniroot(ytm_func, interval = c(0.0001, 1), extendInt = "yes")$root
return(ytm)
}
# Example usage
coupon <- 50
price <- 950
face_value <- 1000
years_to_maturity <- 5
ytm <- calculate_bond_ytm(coupon, price, face_value, years_to_maturity)
print(ytm)
Python:
from scipy.optimize import brentq
# Define the function to calculate YTM
def calculate_bond_ytm(coupon, price, face_value, years_to_maturity):
def ytm_func(ytm):
return price - (coupon * (1 - (1 + ytm)**-years_to_maturity) / ytm) -
(face_value / (1 + ytm)**years_to_maturity)
ytm = brentq(ytm_func, 0.0001, 1)
return ytm
# Example usage
coupon = 50
price = 950
face_value = 1000
years_to_maturity = 5
ytm = calculate_bond_ytm(coupon, price, face_value, years_to_maturity)
print(ytm)
Output
R
[1] 0.06193394
Python
0.061932282681517216
7. Convexity of a Bond
Convexity is a measure of the curvature or the second-order sensitivity of a
bond's price to changes in interest rates. While duration provides a linear
approximation of a bond's price change in response to interest rate
movements, convexity takes into account the curvature of the price-yield
curve.
#R
calculate_convexity <- function(cash_flows, discount_rates, periods, ytm) {
cash_flows <- as.numeric(cash_flows)
discount_rates <- as.numeric(discount_rates)
periods <- as.numeric(periods)
ytm <- as.numeric(ytm)
present_value <- sum(cash_flows / (1 + ytm) ^ periods)
convexity <- sum(cash_flows * periods * (periods + 1) / (1 + ytm) ^
(periods + 2)) / present_value
return(convexity)
}
# Example usage
cash_flows <- c(50, 50, 50, 1050)
discount_rates <- c(0.05, 0.05, 0.05, 0.05)
periods <- 1:4
ytm <- 0.05
convexity <- calculate_convexity(cash_flows, discount_rates, periods, ytm)
convexity
# Python
import numpy as np
def calculate_convexity(cash_flows, discount_rates, periods, ytm):
cash_flows = np.array(cash_flows)
discount_rates = np.array(discount_rates)
periods = np.array(periods)
ytm = np.array(ytm)
present_value = np.sum(cash_flows / (1 + ytm) ** periods)
convexity = np.sum(cash_flows * periods * (periods + 1) / (1 + ytm) **
(periods + 2)) / present_value
return convexity
# Example usage
cash_flows = [50, 50, 50, 1050]
discount_rates = [0.05, 0.05, 0.05, 0.05]
periods = np.array([1, 2, 3, 4])
ytm = 0.05
convexity = calculate_convexity(cash_flows, discount_rates, periods, ytm)
convexity
print(convexity)
Output
R
[1] 16.47383
Python
16.47383353154097
#R
calculate_pb_ratio <- function(stock_price, book_value_per_share) {
pb_ratio <- stock_price / book_value_per_share
return(pb_ratio)
}
# Example usage
stock_price <- 60
book_value_per_share <- 10
result <- calculate_pb_ratio(stock_price, book_value_per_share)
result
# Python
def calculate_pb_ratio(stock_price, book_value_per_share):
pb_ratio = stock_price / book_value_per_share
return pb_ratio
# Example usage
stock_price = 60
book_value_per_share = 10
result = calculate_pb_ratio(stock_price, book_value_per_share)
print(result)
Output
R
[1] 6
Python
6.0
# Python
def calculate_enterprise_value(market_cap, total_debt,
cash_and_equivalents):
enterprise_value = market_cap + total_debt - cash_and_equivalents
return enterprise_value
# Example usage
market_cap = 5000000000
total_debt = 2000000000
cash_and_equivalents = 1000000000
result = calculate_enterprise_value(market_cap, total_debt,
cash_and_equivalents)
print(result)
Output
R
[1] 6e+09
Python
6000000000
7. EBITDA
Earnings Before Interest, Taxes, Depreciation, and Amortization (EBITDA)
metric represents a company's operating performance and profitability by
excluding certain non-cash and non-operating expenses. It provides a
measure of a company's ability to generate cash from its core business
operations.
#R
calculate_ebitda <- function(revenue, operating_expenses, depreciation,
amortization) {
ebitda <- revenue - operating_expenses + depreciation + amortization
return(ebitda)
}
# Example usage
revenue <- 10000000
operating_expenses <- 6000000
depreciation <- 2000000
amortization <- 1000000
result <- calculate_ebitda(revenue, operating_expenses, depreciation,
amortization)
result
# Python
def calculate_ebitda(revenue, operating_expenses, depreciation,
amortization):
ebitda = revenue - operating_expenses + depreciation + amortization
return ebitda
# Example usage
revenue = 10000000
operating_expenses = 6000000
depreciation = 2000000
amortization = 1000000
result = calculate_ebitda(revenue, operating_expenses, depreciation,
amortization)
print(result)
Output
R
[1] 7e+06
Python
7000000
8. Free Cash Flow (FCF)
FCF represents the cash generated by a company's operations that is
available for distribution to investors, creditors, and reinvestment in the
business. It is a measure of a company's ability to generate cash after
accounting for capital expenditures necessary to maintain or expand its
asset base.
#R
calculate_fcf <- function(net_income, depreciation,
changes_in_working_capital, capital_expenditure) {
fcf <- net_income + depreciation - changes_in_working_capital -
capital_expenditure
return(fcf)
}
# Example usage
net_income <- 5000000
depreciation <- 1000000
changes_in_working_capital <- 2000000
capital_expenditure <- 1500000
result <- calculate_fcf(net_income, depreciation,
changes_in_working_capital, capital_expenditure)
result
# Python
def calculate_fcf(net_income, depreciation, changes_in_working_capital,
capital_expenditure):
fcf = net_income + depreciation - changes_in_working_capital -
capital_expenditure
return fcf
# Example usage
net_income = 5000000
depreciation = 1000000
changes_in_working_capital = 2000000
capital_expenditure = 1500000
result = calculate_fcf(net_income, depreciation,
changes_in_working_capital, capital_expenditure)
print(result)
Output
R
[1] 2500000
Python
2500000
Output
R
[1] "Annualized Art Investment Return (R): 0.0472941228206267"
Python
Annualized Art Investment Return (Python): 0.04729412282062673
#R
Chan, N. H. (2011). Time series: Applications to finance with R and S-
Plus (Vol. 837). John Wiley & Sons. Book Link
Tsay, R. S. (2014). An introduction to analysis of financial data with R.
John Wiley & Sons. Book Link
Pfaff, B. (2016). Financial risk modelling and portfolio optimization with
R. John Wiley & Sons. Book Link
Crawley, M. J. (2012). The R book. John Wiley & Sons. Book Link
Tsay, R. S. (2013). Multivariate time series analysis: with R and financial
applications. John Wiley & Sons. Book Link
Arratia, A. (2014). Computational finance. An Introductory Course with R,
Atlantis Studies in Computational Finance and Financial Engineering, 1.
Book Link
Gilli, M., Maringer, D., & Schumann, E. (2019). Numerical methods and
optimization in finance. Academic Press. Book Link
Danielsson, J. (2011). Financial risk forecasting: The theory and practice of
forecasting market risk with implementation in R and Matlab. John Wiley &
Sons. Book Link
Miranda, M. J., & Fackler, P. L. (2004). Applied computational economics
and finance. MIT press. Book Link
Lindström, E., Madsen, H., & Nielsen, J. N. (2018). Statistics for finance.
CRC Press. Book Link
#Python
Hilpisch, Y. (2021). Financial Theory with Python. " O'Reilly Media, Inc.".
Book Link
Hilpisch, Y. (2018). Python for finance: mastering data-driven finance.
O'Reilly Media. Book Link
Lewinson, E. (2020). Python for Finance Cookbook: Over 50 recipes for
applying modern Python libraries to financial data analysis. Packt
Publishing Ltd. Book Link
Kelliher, C. (2022). Quantitative Finance with Python: A Practical Guide
to Investment Management, Trading, and Financial Engineering. CRC
Press. Book Link
Yan, Y. (2017). Python for Finance. Packt Publishing Ltd. Book Link
Humber, M., Humber, M., & Anglin. (2018). Personal Finance with
Python. Apress. Book Link
Fletcher, S., & Gardner, C. (2010). Financial modelling in Python. John
Wiley & Sons. Book Link
Garita, M. (2021). Applied Quantitative Finance. Springer International
Publishing. Book Link
Rogel-Salazar, J. (2018). Data science and analytics with Python. CRC
Press. Book Link
Johansson, R. (2015). Numerical Python: A Practical Techniques Approach
for Industry. Apress. Book Link
Yudin, A., & Yudin, A. (2021). Essential financial tasks done with
python. Basic Python for Data Management, Finance, and Marketing:
Advance Your Career by Learning the Most Powerful Analytical Tool, 231-
275. Book Link
Korstanje, J. (2021). Advanced forecasting with Python. United States:
Apress. Book Link
Weiming, J. M. (2015). Mastering Python for Finance. Packt Publishing
Ltd. Book Link
Alòs, E., & Merino, R. (2022). Introduction to Financial Derivatives with
Python. CRC Press. Book Link
Aldridge, I., & Avellaneda, M. (2021). Big data science in finance. John
Wiley & Sons. Book Link
Fratini, S. (2020). Financial Mathematics with Python. Link
Yan, Y. (2014). Python for finance. Packt Publishing Ltd. Book Link
Lee, J., Chang, J. R., Kao, L. J., & Lee, C. F. (2023). Essentials of Excel
VBA, Python, and R: Volume II: Financial Derivatives, Risk Management
and Machine Learning. Springer Nature. Book Link
Karasan, A. (2021). Machine Learning for Financial Risk Management
with Python. " O'Reilly Media, Inc.". Book Link
McKinney, W. (2012). Python for data analysis: Data wrangling with
Pandas, NumPy, and IPython. " O'Reilly Media, Inc.". Book Link
Manuals
https://cran.r-project.org/manuals.html
Tutorial
https://ourcodingclub.github.io/tutorials.html
R Studio
https://posit.cloud/content