0% found this document useful (0 votes)
21 views76 pages

Python Basics Sep 11 2025

The document provides an overview of Python basics, covering data types such as integers, floats, booleans, strings, lists, dictionaries, tuples, and sets, along with their characteristics like ordering and mutability. It includes examples of variable assignment, string manipulation, and basic operations, as well as practical exercises for applying these concepts in finance and stock data contexts. Additionally, it discusses string methods, formatting, and the use of lists for managing collections of items.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views76 pages

Python Basics Sep 11 2025

The document provides an overview of Python basics, covering data types such as integers, floats, booleans, strings, lists, dictionaries, tuples, and sets, along with their characteristics like ordering and mutability. It includes examples of variable assignment, string manipulation, and basic operations, as well as practical exercises for applying these concepts in finance and stock data contexts. Additionally, it discusses string methods, formatting, and the use of lists for managing collections of items.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 76

Python Basics: ________________

by Dr. K. S. Parmar
Mea
ning
Na /
m Ty Exa
e pe mple Ordering Mutability
Int int -20, NA NA
eg 100,
ers 950
Fl flo - NA NA
oa at 20.0,
ts 100.
55,
950.
75
Bo bo Logic NA NA
ole ol al
an value
s indic
ating
True
or
False
Str str A Ordered Sequence Immutable
ing sequ
s ence
("Hel
lo",
"100
Mea
ning
Na /
m Ty Exa
e pe mple Ordering Mutability
0")
Lis list Sequ Ordered Sequence Mutable
ts ence
of
Obje
cts,
[10,
10.5,
"Hell
o",
10]
Di dic Unor Unordered Collection Mutable
cti t eder
on d
ari map
es ping
of
obje
cts,
{"Ke
y":
Valu
e}
Pairs
Tu tu Sequ Ordered Sequence Immutable
ple ple ence
s of
Obje
cts,
(20,
20.5
1,
"Hell
o")
Se set Colle Unordered Collection Mutable
ts ction
of
Uniq
ue
Obje
cts,
{"a",
Mea
ning
Na /
m Ty Exa
e pe mple Ordering Mutability
"b",
"10"}

_____________________________________________________________

### Types of Data with Meaning:

1. Integers: are whole numbers

2. Floats: are numbers with fractional values

3. Booleans: A boolean value is either True or False. Variables with boolean values are
often used to keep track of certain conditions within a program

4. Strings: A string is a series of characters, surrounded by single or double quotes.


These are immutable

5. Lists: A list stores a series of items in a particuar order. Index or loop can be used to
access them. Unlike strtings, mutation is possible through indexation

6. Dictionaries: Dictionaries store connections between pieces of information. Each


item in a dictionary is a key-value pair

7. Tuples: Tuples are similar to lists, but the items in a tuple can't be modified, that is
like strings, they are immutable. These are in brackets

8. **Sets:* Sets are unordered collections of unique elements


My First Program

# this is a comm
print ('Hello World!')
Hello World!

print ("Hello Guido Van Rossum")

"Hello"

pwd

'C:\\Users\\Kanaiyalal Parmar'

Using Python as Calc


55+99

95*10

15/8

Modulo or "Mod" Operator

15 % 2

100 % 10

5**5

5+3 * 2 -1

(5+3) * 2 -1

0.1+0.2-0.3

Assignment Vs Equality
6 == 5

False

diksha_jogi = ["Mera Road", 80, "BMS"]

diksha_jogi[2]

'BMS'

type(diksha_jogi)

list

diksha_jogi.append(5)

diksha_jogi

['Mera Road', 80, 'BMS', 5, 5, 5]


diksha_jogi.pop()

diksha_jogi1 = {"Add": "Meera_Road", "CET": 80, "Fam_Mem": 5, "Grad":


"BMS"}

diksha_jogi1

{'Add': 'Meera_Road', 'CET': 80, 'Fam_Mem': 5, 'Grad': 'BMS'}

diksha_jogi2= {"Add": "Meera_Road", "CET": 80, "Fam_Mem": ["Sunita",


"Timmappa", "Diksha"], "Grad": "BMS"}

diksha_jogi2["Grad"]

'BMS'

diksha_jogi2.keys()

Variable Assignment
• Can not start with a number
• No spaces in the name, use _ instead
• No special characters
• PEP8 (Python Enhancement Proposal) suggests to use names in lower case
• Avoid using reserved words, highlighted in different color

Python uses Dynamic Typing, therefore reassignment of variable to a different


datatype is possible
sales = 2

type(sales)

sales

sales = 4

sales

sales + sales

Python also allows the reassignment with reference to the same object
sales

sales = sales + sales + sales

sales
Calculate Income tax, if tax rate is 30% and income is 5000000
Calculate FV if PV = 1000, IR = 9% and t = 5 years
Calculate PV if FV = 10000, IR = 8.5% and t = 10 years

my_income = 5000000
tax_rate = 0.3
my_tax = my_income * tax_rate
my_tax

pv = 1000
ir = 0.09
t = 5

fv = pv * (1+ir)**t
fv

fv1 = 10000
ir1 = 0.085
t1 = 10
pv1 = fv1 / (1+ir1)**t1
pv1

Working with Strings: A string is a series of characters, surrounded by


single or double quotes. These are immutable
Agenda is to learn
• slicing

• .format method

• f method
"hello"

"hello 1"
"hello 2"

The above code returns only the second line, therefore print command is used which will not
show output but show the result

print("hello 1")
print ("hello 2")

Escape Sequence: backslash is an escape sequence, n stands for new line, t stands
for tab
print("hello world")

print("hello \nworld")

print("hello \nworld")

print("Hello World")

print("hello \tworld")

print("hello \tworld")

Length function
len("hello")

len("I am")

mystring = "Hello World"

mystring
Indexing and Slicing
• White or blank space in a string is counted as a character
mystring[0]

mystring[5]

mystring[-1]

mystring[-2]

mystring = "abcdefghijklmn"

mystring

Slicing Syntax
[start:stop:step]
mystring[4:]

mystring[2:8]

mystring[4:5]

mystring[4:8]

mystring[:4]

mystring[:-5]

mystring[-5:]

mystring[-5:-1]

mystring[:]

mystring[::]

mystring[::3]

mystring[2::3]

mystring[2:9:2]

Reverse string
mystring[::-1]

mystring[::-2]

mystring[::-4]

mystring[-3::-1]
"Hello World" [-3]

String Properties and Methods

Immutability
• Immutability of strings means that we can not change letters or individual elements from
string using indexing.

• However, we can concatenate.


• If we want to change name from TATASTEEL to TATAMOTORS then...
name = "TATASTEEL"

name

#To change name to TATAMOTORS, we can not use the following code
name[4:9] = "MOTORS"
name
# Instead we need to concatenate or merge

first_letters = name[:4]
first_letters

name = first_letters + "MOTORS"

name

X = "Is TATAMOTRS"
Y = X + " undervalued?"

Z = "No, its overvalued"


Z

print(X)

print(Y)

X = "Is TATAMOTORS"
X = X + " undervalued?"

A = "No."
A

A = A + " Its overvalued"

A
letter = "TATAMOTORS"

letter * 10

5 + 7

"5" + "7"

String Methods: Methods are functions that are inside the python objects
• .upper

• .lower

• .split, based on white space or based on a letter you pass in

Later on we'll study to create our own methods and fuctions


pwd

x = "Hello World"
x

Hit tab after x. to see a list of methods available on this string object
Hit shift tab in parenthesis to see docstring

x.upper()

.upper method is not in place, so the original string is not affected

to affect the original string, reassign

x1 = x.upper()

x1

x.lower

x.lower()

x = x.lower()
x

to create list of the string

x.split()

Split on any other sequence of character, for ex, split on sequence of i


Finance Use Case
x = "NIFTY50 NIFTYNEXT50 NIFTYMIDCAPSELECT NIFTYBANK
NIFTYFINANCIALSERVICES"

len(x)

x.split()

x.split('Y')

Two other methods


1. .format() method

2. f-string (formatted string literals) method

Formating with .format() method


Syntax: 'String here {} then also {}'.format('something1', 'something2')

print("This is a string {}" .format("INSERTED"))

X = "This is a string"
Y = " INSERTED"
X+Y

print(X+Y)

Finance Use Case


Strings can be inserted based on index position

Passing positional arguement


print("TATA{} {} {}" .format ("MOTORS", "=" , "Rs. 850.55"))

print("TATA {2} {1} {0}".format ("MOTORS", "=" , "Rs.


850.55"))

print("TATA {1} {1} {1}".format ("MOTORS", "=" , "Rs.


850.55"))

print("I {0} {1} {2}".format ( "am", "teaching", "basic Python"))

Better way is by Assigning Key Words or Variable Assignment

Passing keyword arguement


print("TATAMOTORS {e} {f} {c} {p}".format ( e = "Equity Price =
855.55,",
f = "Futures Price =
859.35,", c = "850CE = 35.75 AND,",
p = "850PE = 31.65"))

Float formatting "{value:width.precisionf}"


result = 70/570*100

result

print("The NPM was {}".format(result))

print("The result was {r}".format(r=result))

print("The result was {r:1.2f}".format(r=result))

print("The result was {r:25.2f}".format(r=result))

print("The result was {r:-25.2f}".format(r=result))

f string method
name = "Spoorthi"
name

print (f"Hello, my name is {name}")

name = "Deepak"
age = 7

print (f"{name} is {age} years old")

Practice the following:


Combining strings to create meaningful output such as stock details or messages
# Stock data as strings
company_name = "Apple Inc."
ticker_symbol = "AAPL"
price = 223.25

# Concatenating strings
stock_info = company_name + " (" + ticker_symbol + ") is trading at $"
+ str(price)
print(stock_info)

# Using f-strings (a cleaner approach in Python)


stock_info_fstring = f'{company_name} ({ticker_symbol}) is trading at
${price}'
print(stock_info_fstring)
Practice Exercise:
Create strings for three different companies (name, ticker, and price), concatenate them, and
print the output.
Use f-strings to format the output in a similar way.

Practice the following:


Slicing to Extract Substrings
# Ticker symbol slicing
ticker = "GOOG"
ticker

# Get the first two characters


first_two_chars = ticker[:2]
print(f"First two characters of ticker: {first_two_chars}")

# Get the last two characters


last_two_chars = ticker[-2:]
print(f"Last two characters of ticker: {last_two_chars}")

# Get the first three characters from company name


company = "Microsoft Corporation"
short_company_name = company[:3]
print(f"Shortened company name: {short_company_name}")

Practice Exercise:
Slice the first three letters of a company name.
Slice the last three characters of a stock ticker.
Extract the middle part of a string and print it.

Practice the following:


String Methods in Stock Market Context
# Check if a ticker symbol is uppercase (important for standardizing
ticker formats)
ticker = "aapl"
is_upper = ticker.isupper()
is_upper
print(f"Is the ticker symbol uppercase? {is_upper}")

# Convert to uppercase
ticker_upper = ticker.upper()
print(f"Uppercase ticker: {ticker_upper}")

ticker_upper

# Replace spaces with underscores in company names (useful for file


naming or URLs)
company_name = "Microsoft Corporation"
company_url = company_name.replace(" ", "_")
print(f"Company URL-friendly name: {company_url}")

# Split company names (useful when analyzing components of the name)


split_name = company_name.split(" ")
print(f"Split company name: {split_name}")

Practice Exercise:
Convert a stock ticker to uppercase.
Replace spaces in company names with underscores for a URL-friendly format.
Split the company name into individual words and print each.

# Company description
company_description = "Apple Inc. is a leading tech company. Inc.
represents incorporation."

# Find if the substring "Inc." exists in the string


exists = "Inc." in company_description
print(f"Does 'Inc.' exist in the description? {exists}")

# Count how many times "Inc." appears


count = company_description.count("Inc.")
print(f"'Inc.' appears {count} times in the description")

Practice Exercise:
Search for a specific word (like "Corporation" or "Inc.") in a company description.
Count how many times a certain word appears in a text.

Practice the following:


Formatting Stock Prices and Financial Data to Create a Commentary
# Stock price data
ticker = "TATAM"
price = 1010.56789
volume = 1000000

# Formatting price to 2 decimal places


formatted_price = f"Rs.{price:.2f}"
print(f"Price of {ticker}: {formatted_price}")

# Formatting large numbers with commas (volume)


formatted_volume = f"{volume:,}"
print(f"Trading volume: {formatted_volume} shares")

# Including financial data in a sentence


fin_statement = f"{ticker} closed at {formatted_price} with a trading
volume of {formatted_volume} shares."
print(fin_statement)

Practice Exercise:
Format stock prices to two decimal places and print them in a sentence.
Format large numbers (like trading volume) with commas and include them in a formatted
string.

Splitting and Joining Stock Data


# Example stock data as a comma-separated string
stock_data = "AAPL,250.2537,1000000"

# Split the string into separate components


stock_info = stock_data.split(",")
print(f"Stock Info: {stock_info}")

# Accessing individual components


ticker = stock_info[0]
price = float(stock_info[1])
volume = int(stock_info[2])
print(f"Ticker: {ticker}, Price: ${price:.2f}, Volume: {volume:,}")

# Joining components into a single string


joined_stock_info = ",".join(stock_info)
print(f"Joined Stock Info: {joined_stock_info}")

Practice Exercise:
Split a string containing stock data into its components (ticker, price, volume).
Join the split components back into a single string.

Lists: A list stores a series of items in a particuar order. Index or loop


can be used to access them
# creating a list
stocks = ["TM","REL","TS"]

stocks

['TM', 'REL', 'TS']

len(stocks)

type(stocks)

list
Indexing, slicing and concatenating of lists works just like strings
stocks[1]

'REL'

stocks[1:]

['REL', 'TS']

anotherstocks = ["ONGC", 'PFC', "TS"]

stocks + anotherstocks

['TM', 'REL', 'TS', 'ONGC', 'PFC', 'TS']

However, the above result is not saved

stocks

['TM', 'REL', 'TS']

anotherstocks

['ONGC', 'PFC', 'TS']

If need to save, I need to assign it to some name

newstocks = stocks + anotherstocks

newstocks

['TM', 'REL', 'TS', 'ONGC', 'PFC', 'TS']

Unlike strings, mutation or change is possible in lists through indexation


newstocks[1] = "BHEL"

newstocks

['TM', 'BHEL', 'TS', 'ONGC', 'PFC', 'TS']

newstocks.append(7)

newstocks

['TM', 'BHEL', 'TS', 'ONGC', 'PFC', 'TS', 7, 7]

##### To remove an item, use pop, which pops out last item in parenthesis is empty

newstocks.pop()

7
newstocks

['TM', 'BHEL', 'TS', 'ONGC', 'PFC', 'TS']

newstocks.count("TS")

newstocks.pop(2)

'TS'

newstocks

['TM', 'BHEL', 'ONGC', 'PFC', 'TS']

newstocks.sort()

newstocks

['ONGC', 'PFC', 'REL', 'TM', 'TS', 'TS']

pwd

'C:\\Users\\Kanaiyalal Parmar'

newstocks.reverse()

newstocks

['TS', 'PFC', 'ONGC', 'BHEL', 'TM']

Finance Use Cases:


# List of daily closing prices
closing_prices = [152.50,
153.20, 150.80, 154.10,
156.00]
print(f"Closing prices: {closing_prices}")

Closing prices: [152.5, 153.2, 150.8, 154.1, 156.0]

# Accessing list elements


print(f"First day closing price:
{closing_prices[0]}")

closing_prices[4]

# Modify the third element in the list


closing_prices[2] = 151.00
print(f"Updated closing prices: {closing_prices}")

Updated closing prices: [152.5, 153.2, 151.0, 154.1, 156.0]


Practice Exercise:
Create a list of 5 stock prices for a week.
Print the first and last prices from the list.
Modify one of the prices and print the updated list.

Dictionaries
These are unordered mapping of objects allowing users to get the objects without
knowing index locations. These can not be sorted

Syntax: {"key1":value1,"key2":value2}

Dictionaries Vs Lists
my_dict = {'reliance': 2500,
'BPCL': 400,
'PFC': 200}

my_dict["BPCL"]

400

Dictionaries can have list


my_dict = {'reliance': 2500,
'BPCL':
[401, "BSE", 402, "NSE"]
, 'PFC': 200}

my_dict["BPCL"]

[401, 'BSE', 402, 'NSE']

my_dict["BPCL"][2]

402

Dictionary and list within a dictionary


my_dict={'reliance': 2500,
'BPCL': [401, "BSE", 402, "NSE"]
, 'PFC': 200,
"MCX": {"Gold": 70000,
"Silver": 90000}}

my_dict["MCX"]

my_dict["MCX"]["Gold"]

my_dict["MCX"]["Gold"] = 101500

my_dict
{'reliance': 2500,
'BPCL': [401, 'BSE', 402, 'NSE'],
'PFC': 200,
'MCX': {'Gold': 101500, 'Silver': 90000}}

Add elements to dictionaries


my_dict["TM"]= 800
my_dict

Overwrite
my_dict["TM"]=650
my_dict

See elements of dictionaries


my_dict.keys()

my_dict.values()

my_dict.items()

Finance Use Cases


# Stock dictionary
stock_data = {
"ticker": "AAPL",
"price": 153.25,
"volume": 1000000}
# Accessing values
#print(f"Stock:{stock_data['ticker']},
#Price: ${stock_data['price']}")

# Modify the stock price


stock_data['price'] = 155.50
print(f"Updated stock price: ${stock_data['price']}")

Updated stock price: $155.5

Practice Exercise:
Create a dictionary to store stock data like ticker, price, and volume.
Access and print individual dictionary values (e.g., the price).
Modify the stock price and print the updated value.

Tuples
t = (1,2,3)
t
(1, 2, 3)

type(t)

tuple

len(t)

#Overwrite
t = ("one", 2)

('one', 2)

t[0]

'one'

t[-1]

Only 2 basic built in methods for a tuple, count and index


t = ("a", "a", "b")

t.count("a")

When does "a" occur first time in Tuple

t.index("a")

t.index("b")

Unlike Lists, Tuples are immutable in the sense that once an element is assigned to
an index position inside of a tuple, we can not grab that element and reassign it to
something else.
t

('a', 'a', 'b')

mylist

[1, 2, 3]

mylist[0] = "New"

mylist

['New', 2, 3]
t[0] = "New"

----------------------------------------------------------------------
-----
TypeError Traceback (most recent call
last)
Cell In[39], line 1
----> 1 t[0] = "New"

TypeError: 'tuple' object does not support item assignment

Finance Use Cases:


# Tuple containing stock ticker and price
reliance_data = ("RELIANCE", 1300.30)
tcs_data = ("TCS", 3530.75)
infy_data = ("INFY", 1440.50)

# Print stock data using tuples


print(f"{reliance_data[0]} stock price: ₹{reliance_data[1]}")
print(f"{tcs_data[0]} stock price: ₹{tcs_data[1]}")
print(f"{infy_data[0]} stock price: ₹{infy_data[1]}")

RELIANCE stock price: ₹1300.3


TCS stock price: ₹3530.75
INFY stock price: ₹1440.5

Practice:
Create tuples for three Indian stocks (ticker, price) and print the details.

Sets: These are unordered collections of unique variables


myset = {9, 2, "2", 2,2,2,2,2,9,9,9,9,9}

myset

{2, '2', 9}

myset.add(10)

myset

{10, 2, '2', 9}

Only Unique values are added

myset.add(2)

myset

{10, 2, '2', 9}
mylist = [7,7,7,1,1,1,1,2,2,2,2,5,5,5,5]

mylist

[7, 7, 7, 1, 1, 1, 1, 2, 2, 2, 2, 5, 5, 5, 5]

set = {7,7,7,7,1,1,1,1,10}
set

{1, 7, 10}

Finance Use Cases:


# Set example
portfolio = {"AAPL", "GOOG", "MSFT", "AAPL"} # Duplicate "AAPL" is
ignored
print(f"Unique stocks in portfolio: {portfolio}")

portfolio_a = {'RELIANCE', 'TCS', 'HDFCBANK', 'INFY', 'ICICIBANK'}


portfolio_b = {'TCS', 'BAJFINANCE', 'HINDUNILVR', 'RELIANCE',
'AXISBANK'}

# Unique stocks in Portfolio A


unique_in_a = portfolio_a - portfolio_b
unique_in_a

# Unique stocks in Portfolio B


unique_in_b = portfolio_b - portfolio_a
print(f"Unique stocks in Portfolio B: {unique_in_b}")

# Common stocks between Portfolio A and Portfolio B


common_stocks = portfolio_a & portfolio_b
print(f"Common stocks between both portfolios: {common_stocks}")

# All unique stocks across both portfolios


all_unique_stocks = portfolio_a | portfolio_b
print(f"All unique stocks across both portfolios:
{all_unique_stocks}")

Practice Exercise:
Create two sets representing portfolios of different stocks.
Find and print the common stocks in both portfolios.

None keyword: It is a placeholder


None keyword as a placeholder for an object which we don't want to assign yet. Later on I want
to assign "b" to something in my code, but right now I just need to have a placeholder. Without
this, we'll get an error
b

----------------------------------------------------------------------
-----
NameError Traceback (most recent call
last)
Cell In[215], line 1
----> 1 b

NameError: name 'b' is not defined

b = None

type(b)

NoneType

Booleans and Comparision with Logical Operators


True

True

False

False

type(True)

bool

1>2

False

10 == 10

True

5 == 7

False

"Bye" == "bye"

False

"Bye" == "Bye"

True

2.0 == 2
Use != to represent inequality
7!=7

False

9!=10

True

2>1

True

1<0

False

2>=1

True

7>=8

False

7>=6

1 < 2 < 3 < 4 > 2

True

1 < 2 > 3

False

Logical Operators:
• and

• or

• not
1 < 2 and 2 > 3

False

1 < 2 or 2 > 3

True

"h" == "h" and 2 == 2

True
To make the above code readable () can be used
("h" == "h") and (2 == 2)

True

1 == 1 and 2 != 22

10000 == 1 or 2 == 2

10000 == 1 or 2 == 2000

1 == 1

not (1==1)

not 1==10

#### not is asking for opposite boolean

not 200 > 500

Finance Use Case


# Boolean example
price_today = 1560.00
price_yesterday = 1530.25

# Check if the price increased


price_increased = price_today > price_yesterday
price_increased

True

print(f"Did the stock price increase? {price_increased}, therefore


BUY")

Did the stock price increase? True, therefore BUY

Practice Exercise:
Create two variables representing today’s and yesterday’s stock prices.
Use a boolean expression to check if the price has increased and print the result.

Python Statements
if, else statements
• Keywords are if, elif, else
• Indentation is important
• Syntax:
if some_condition:
execute some code
else:
execute some another code
if True:
print("Its crect")

Its crect

if False:
print("Its crect")

if False:
print("Its true!")
else:
print ("Its wrong!")

Its wrong!

5>4

True

if 5>4:
print("BUY!")

BUY!

if 55<22:
print("its true!")
else:
print("pagal hai kya?")

pagal hai kya?

x = 25
if 4<x:
print ("True")

True

x = 22
if 44<x:
print (True)
else:
print ("Fals")

Fals

x = 25
y = 25
if x>y:
print ("x is higher")
elif x < y:
print ("y is higher")
else:
print ("both are equal")

both are equal

Use case in Finance


Calculate RRR using CAPM if risk free rate is 7%, market return is 15% and beta is 1.5
Required Rate of Return (RRR) is calculated with capital asset pricing model (CAPM) rf = risk free
rate
rm = market return
b = beta
er expected return rrr = Ke (cost of equity) = rf + b * (rm-rf)

er > rrr, undervalued and buy


er < rrr, overvalued and sell
er = rrr, properly valued, no trade

rm = 0.15
b = 1.5
rf = 0.07
er = 0.2

rrr = rf + b * (rm-rf)
rrr

0.19

er = 0.19

if er > rrr:
print("undervalued and BUY")
elif er < rrr:
print ("overvalued and SELL")
else :
print ("properly valued and NO TRADE")

properly valued and NO TRADE

Define vaiables, pat and equity. Create an if statement which prints


if pat / equity is < 0 then "Loss making firm"
if pat / equity is = 0 then "BEP firm"
if pat / equity is above 0, but below 8% then "Low profit making firm"
if pat / equity is 8% and above but below 15% then "Moderately profit making firm"
if pat / equity is equal to or more than 15% then "High profit making firm"

pat = 4
equity = 100
if pat / equity <0:
print("Loss making firm")
elif pat / equity == 0:
print("BEP firm")
elif pat / equity > 0 and pat / equity < 0.08:
print("Low profit making firm")
elif pat / equity == 0.08 or pat / equity < 0.15:
print("Moderately profit making firm")
else:
print("High profit making firm")

# List of Indian stock tickers


stock_tickers = ["RELIANCE", "TCS", "INFY", "HDFCBANK", "ICICIBANK"]

# Search for a specific stock ticker


search_ticker = "PFC"

if search_ticker in stock_tickers:
print(f"{search_ticker} is in the list of tickers.")
else:
print(f"{search_ticker} is not in the list of tickers.")

for loop
• Many objects in python are iterable
• As an example, we can iterate through lists, strings or dictionaries etc

Syntax
my_iterable = [1,2,3,4,5]

for item_name in my_iterable:


print(item_name)

• item_name is a variable name you can choose which is a placeholder for each item in the
iterable object
• In this case, the item name represents the numbers of the list, 1,2,3,4 and 5
• for and in are keywords

Looping through a list (From cheat sheet):


cashflow = [100, 10, 20, 50, 30, 25]

for i in cashflow:
print(i)
100
10
20
50
30
25

for e in cashflow:
print(e)

for _ in cashflow:
print(_)

How many Cashflows do we have (count)?

count = 0
for i in cashflow:
# count = count + 1
count +=1
print(count)

total = 0
for i in cashflow:
total +=i
print(total)

235
count = 0
for i in cashflow:
count +=1
print(count)

total = 0
for i in cashflow:
total += i
print(total)

total = 0
for i in cf:
total += i
print(total)

sum(cashflow)

tm = ["913.55", "915.95", "10000000"]


tm

for abc in tm:


print(abc)

Finance Use Cases:


Using for loop for DDM

for loop in tuple


tup = (1,2,3)

for item in tup:


print(item)

mylist = [(1,2),(3,4),(5,6),(7,8)]

len(mylist)

for item in mylist:


print(item)
Tuple unpacking
for (a,b) in mylist:
print(a,b)

for (a,b) in mylist:


print(b)

for (a,b) in mylist:


print(b)

for a,b in mylist:


print(b,a)

mylist = [(1,2,3),(4,5,6),(7,8,9)]

for item in mylist:


print(item)

for a,b,c in mylist:


print(b)

for loop in Dictionary


d = {"K1":1, "K2": 2, "K3": 3}

for item in d:
print(item)

d = {"K1":1, "K2": 2, "K3": 3}

for item in d.items():


print(item)

d = {"K1":1, "K2": 2, "K3": 3}

for key,value in d.items():


print(value)

d = {"K1":1, "K2": 2, "K3": 3}

for key,value in d.items():


print(key)

d = {"K1":1, "K2": 2, "K3": 3}

for value in d.values():


print(value)
Finance use case
for loop in list of stock prices for Reliance Industries over 5 days

reliance_stock_prices = [2550.30005689, 2560.50, 2540.75, 2575.20,


2580.60]

# Loop through stock prices and print each price


for price in reliance_stock_prices:
print(f"Reliance Industries stock price: ₹{price:.2f}")

#### for loop mixed with a math operation and f string literals

# Calculate total and average stock price


total_price = 0
for price in reliance_stock_prices:
total_price += price

average_price = total_price / len(reliance_stock_prices)


print(f"Average Reliance Industries stock price over 5 days: ₹
{average_price:.2f}")

for loop in dictionary with formula and f string literals


# Define a dictionary of stocks with their prices and earnings per
share (EPS)
stocks_data = {
'RELIANCE': {'Price': 2500, 'EPS': 60},
'TCS': {'Price': 3300, 'EPS': 150},
'HDFCBANK': {'Price': 1600, 'EPS': 45},
'INFY': {'Price': 1450, 'EPS': 52}
}

# Calculate the P/E ratio for each stock


for stock, data in stocks_data.items():
pe_ratio = data['Price'] / data['EPS']
print(f"{stock}: P/E Ratio = {pe_ratio:.2f}")

while loop
• while loop will continue to execute a code while some condition is true
• for example, while my profit is less than Rs. 1lac, continue to trade
• or while the market is on, continue to trade

Syntax
while some_condition:
do something
else:
do something different

x = 0
while x<6: # while True, run it for eg. 5<6 for infinite loop
print (f"The current value of x is {x}")
x = x + 1
# instead of above, we can also write: x +=1

The current value of x is 0


The current value of x is 1
The current value of x is 2
The current value of x is 3
The current value of x is 4
The current value of x is 5

x = 0
while x<5:
print (f"The current value of x is {x}")
x = x + 1
# instead of above, we can also write: x +=1

The current value of x is 0


The current value of x is 1
The current value of x is 2
The current value of x is 3
The current value of x is 4

x = 0
while x <5:
x +=1
print (f"The current value of x is {x}")

x = 0
while x<5:
print (f"The current value of x is {x}")
x +=1
else:
print ("X is not less than 5")

x = 50
while x<5:
print (f"The current value of x is {x}")
x +=1
else:
print ("X is not less than 5")

X is not less than 5

pass, continue, break:


• pass; Does nothing at all
• continue: Goes back to the top of the closest enclosing loop
• break: Breaks out of the current closest enclosing loop
# To avoid the following error, pass is used

x = [1,2,3]

for item in x:
pass
#comment

x = [1,2,3]

for item in x:
# I will complete the code once I get the data
pass

print("Hello")

Hello

x = [1,2,3]

for item in x:
#comment
pass

print("end of my script, lets continue with another")

nifty50 = ("ADA", "AD",


"AP", "AS","AXISBANK","BA","BAJF")

print(nifty50)

('ADA', 'AD', 'AP', 'AS', 'AXISBANK', 'BA', 'BAJF')

for stocks in nifty50:


print(stocks)

# For eg, we don't want to print AXISBANK, use continue


for stocks in nifty50:
if stocks == "AXISBANK":
continue

print(stocks)

ADA
AD
AP
AS
BA
BAJF
# To stop printing from AXISBANK onwards, use break
for stocks in nifty50:
if stocks == "AXISBANK":
break
print(stocks)

Useful Operators in Python


(start,stop,step) for range operator
mylist = [0,1,2,3,4,5,6,7,8,9]
mylist

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

list(range(0,1000000,100000))

[0, 100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000,


900000]

Enumerate Function:
To understand enumerate function, lets do the following excercise
index_count = 0
for letter in "abcde":
index_count +=1
print(index_count)

index_count = 0
a = "abcde"
for letter in a:
index_count +=1
print(index_count)

index_count = 0
for let in "abcde":
print("At index {} the letter is {}".format(index_count,let))
index_count +=1

At index 0 the letterrrrrrrr is a


At index 0 the letterrrrrrrr is b
At index 0 the letterrrrrrrr is c
At index 0 the letterrrrrrrr is d
At index 0 the letterrrrrrrr is e

The following returns the same result in tuple


ab = "abcde"
for i in enumerate(ab):
print(i)

(0, 'a')
(1, 'b')
(2, 'c')
(3, 'd')
(4, 'e')

Random library
from random import shuffle

mylist = [1,2,3,4,5,6,7,8,9]

See docstring
shuffle(mylist)

mylist

To generate a random integer


from random import randint

randint(600,700)

mynum = randint(0,100)

mynum

Generate a list of random integers


import finlatics as fa

fa.

import random
ran_int = [random.randint(0,100)
for _ in range(20)]

ran_int

[68, 97, 71, 20, 72, 74, 3, 47, 99, 45, 11, 85, 40, 65, 20, 81, 40,
25, 24, 98]

#num_int = 10 # Number of integers


#min_val_int = 1 # Minimum value for integers
#max_val_int = 100 # Maximum value for integers
ran_int = [random.randint(5, 50) for _ in range(10)]
ran_int

# import random

num_int = 20 # Number of integers


min_val_int = 1300 # Minimum value for integers
max_val_int = 1500 # Maximum value for integers
ran_int = [random.randint(min_val_int, max_val_int)
for _ in range(num_int)]

ran_int

Generate a list of random floats rounded to 2 decimal places


import random

ran_fl = [round(random.uniform(4,8), 2)
for _ in range(10)]
ran_fl

num_fl = 10 # Number of floats


min_val_fl = 0.0 # Minimum value for floats
max_val_fl = 10.0 # Maximum value for floats
ran_fl = [round(random.uniform(min_val_fl,
max_val_fl), 2)
for _ in range(num_fl)]

# Print the results


print(ran_fl)

The above help is also available by typing shifttab with a curser at the end of insert
For more documentation:
https://docs.python.org/3.11/

Importantly, explore librarary and tutorial references among other things in the
above link

def keyword to create a function


mylist.

def j_alpha(rp, rm, rf, b):


"""
Calculate Jensen's Alpha and give trading signal.

Parameters:
rp : float - security / portfolio return
rm : float - market return
rf : float - risk-free rate
b : float - portfolio beta

Returns:
alpha : float
Jensen's Alpha
signal : str
Trading decision (BUY/SELL/HOLD)
"""
exp_ret = rf + b * (rm - rf) # CAPM expected return
alpha = rp - exp_ret # Jensen's alpha

# Trading decision
if alpha > 0:
signal = "BUY (Alpha > 0)"
elif alpha < 0:
signal = "SELL (Alpha < 0)"
else:
signal = "HOLD (Alpha = 0)"

# Print results
print("Jensen's Alpha:", round(alpha, 4))
print("Decision:", signal)

# return alpha, signal

j_alpha()

rp = 0.12
rm = 0.12
rf = 0.07
b = 1.25

j_alpha(rp, rm, rf, b) # will auto print

Jensen's Alpha: -0.0125


Decision: SELL (Alpha < 0)

import finlatics as fa

fa.black_scholes_price(S0 = 24530, X = 25550,


T = 8/365, r = 0.12,
sigma = 0.3229,
option_type='call')

144.35337051738043
fa.implied_volatility(S0 = 24530, X = 25500, T = 8/365, r = 0.12,
market_price = 155,
option_type='call',
tol=1e-05,
max_iterations=100,)

def say_hello():
"This is docstring which can be used to explain a function"
print("hello")
print("how are")
print("you?")

say_hello()

hello
how are
you?

#Using f string literal in a function


def say_hello(n ):
print(f"Helloooooo {n}")

say_hello ()

say_hello ("Arya")

Hello Arya

def say_hello(n = "Default"):


print(f"Hello {n}")

say_hello()

Hello Default

say_hello()

Hello Default

say_hello ("Kartik")

Hello Kartik

If we forget to passin the parameter (put a name), it will show an error, to avoid the
error,
def say_hello(name = "Default"):
print(f"Hi {name}")
say_hello ()

Hi Default

say_hello ("KP")

def mult_num(num1 = 0,num2 = 0,num3= 0):


return (num1*num2*num3)

mult_num(5, 5,10)

250

def add_num(num1 = 0,num2 = 0,num3= 0):


return (num1+num2+num3)

add_num(234,345)

579

def mult_num(num1 = 0,num2 = 0,num3= 0):


return (num1*num2*num3)

res = mult_num(100,2000,2)

res

type(res)

def print_result(a,b):
print(a+b)

def return_result(a,b):
return a+b

# Result of print cannot be assigned to any variable


result = print_result(10,20)

30

result

type(result)

NoneType

# Result of print can be assigned to any variable


result1 = return_result(10,20)

result1
type(result1)

def sum_numbers(num1,num2):
return num1+num2

sum_numbers(10,20)

sum_numbers("10","20")

Logic with Python Functions


Use Cases in Finance:
Calculate Profit or Loss using if statement
if SP > CP then it should print "Profit of ₹..."

if SP < CP then it should print "Loss of ₹..."

if SP = CP then it should print "No Profit, No Loss"

sp = 100
cp = 100
if sp>cp:
print(f'Profit of ₹ {sp-cp}')
elif sp < cp:
print(f"Loss of ₹ {cp-sp}")
else:
print(f"No Profit, No Loss")

def porl(sp,cp):
"""
Calculate Profit or Loss using if statement
if SP > CP then it should print "Profit of ₹..."
if SP < CP then it should print "Loss of ₹..."
if SP = CP then it should print "No Profit, No Loss"

"""
if sp>cp:
print(f'Profit of ₹ {sp-cp}')
elif sp < cp:
print(f"Loss of ₹ {cp-sp}")
else:
print(f"No Profit, No Loss")

porl(sp = 81389653478,cp = 20947656790)

Profit of ₹ 60441996688

mylist = [1,2,3]

porl()

def porl(sp,cp):
"""if SP > CP then it should print "Profit of ₹..."
if SP < CP then it should print "Loss of ₹..."
if SP = CP then it should print "No Profit, No Loss"""

if sp>cp:
print(f"Profit of ₹ {sp-cp}")
elif sp<cp:
print(f"Loss of ₹ {cp-sp}")
else:
print("No Profit, No Loss")

porl(2376259086205,2309690257625)

sp = 100
cp = 100

if sp>cp:
print(f'Profit of ₹ {sp-cp}')
elif sp < cp:
print(f"Loss of ₹ {cp-sp}")
else:
print(f"No Profit, No Loss")

No Profit, No Loss

def porl(sp,cp):
"""Calculate Profit or Loss using if statement
if SP > CP then it should print "Profit of ₹..."
if SP < CP then it should print "Loss of ₹..."
if SP = CP then it should print "No Profit, No Loss"""
if sp>cp:
print(f'Profit of ₹ {sp-cp}')
elif sp < cp:
print(f"Loss of ₹ {cp-sp}")
else:
print(f"No Profit, No Loss")

porl(2314,1314)

porl

def porl(sp,cp):

"""Calculate Profit or Loss using if statement


if SP > CP then it should print "Profit of ₹..."
if SP < CP then it should print "Loss of ₹..."
if SP = CP then it should print "No Profit, No Loss"
"""
if sp>cp:
print (f"Profit of {sp-cp}")
elif sp < cp:
print (f"Loss of {cp-sp}")
else:
print ("No Profit, No Loss")

porl(234572389467589, 923848123570349)

Loss of 689275734102760

selling_price = 25
cost_price = 25
if selling_price>cost_price:
print (f"Profit of ₹ {selling_price - cost_price}")
elif selling_price<cost_price:
print(f"Loss of ₹ {cost_price - selling_price}")
else:
print ("No Profit, No Loss")

def calculate_profit_or_loss(cost_price, selling_price):


"""
Determines if there is a profit or loss based on cost and selling
price.
if SP > CP then it should print "Profit of ₹..."
if SP < CP then it should print "Loss of ₹..."
if SP = CP then it should print "No Profit, No Loss"
"""
if selling_price > cost_price:
return f"Profit: ₹{selling_price - cost_price:.2f}"
elif selling_price < cost_price:
return f"Loss: ₹{cost_price - selling_price:.2f}"
else:
return "No Profit, No Loss"

# Example usage
print(calculate_profit_or_loss(100, 120)) # Profit

PorL = calculate_profit_or_loss(100, 100) # Loss


PorL

PorL

Calculate NPV using a function and for loop


Calculate the Net Present Value (NPV) given cash flows and a discount rate.
""" Parameters:
cf (list): List of cash flows where the first element is the initial
investment.
discount_rate (float): The discount rate as a decimal (e.g., 0.10 for
10%).

Returns:
float: The calculated NPV.
"""

pwd

def calculate_npv(cf, discount_rate):


"""
Calculate the Net Present Value (NPV) given cash flows and a discount
rate.
cf (list): List of cash flows where the first element is the
initial investment.
discount_rate (float): The discount rate as a decimal (e.g., 0.10
for 10%).
Returns:
float: The calculated NPV."""
npv = 0 # Initialize NPV to zero
t = 0 # Start time period at 0
for cash_flow in cf:
# Calculate the present value of the cash flow for year t
present_value = cash_flow / (1 + discount_rate) ** t
npv += present_value # Add present value to NPV
t += 1 # Increment time period
return npv

# Example usage
cash_flows = [-100000, 200232, 3003, 400, 500, 700,
200,324,4135,324534,5234,5234,5234,534,534]
discount_rate = 0.18 # 10% discount rate

npv = calculate_npv(cash_flows, discount_rate)


npv

149776.63847691353

cash_flows = [-1000, 300,200,344,470,570,47,78,6]


discount_rate = 0.16
npv = calculate_npv(cash_flows, discount_rate)
npv

def calculate_npv(cash_flows, discount_rate):


"""
Calculate the Net Present Value (NPV) given cash flows and a
discount rate.

Parameters:
cash_flows (list): List of cash flows where the first element is
the initial investment.
discount_rate (float): The discount rate as a decimal (e.g., 0.10
for 10%).

Returns:
float: The calculated NPV.
"""
npv = sum(cf / (1 + discount_rate) ** t for t, cf in
enumerate(cash_flows))
return npv

# Define the cash flows and discount rate


cash_flows = [-1000, 200, 300, 400, 500]
discount_rate = 0.10

# Calculate NPV
npv = calculate_npv(cash_flows, discount_rate)
#npv
# Print the NPV
print(f"The calculated NPV @ {discount_rate*100}% Discount Rate is ₹
{npv:.2f}")
Calculate Mean using a function

def mean(data):
"""
Calculate the arithmetic mean.
Formula: sum(x) / n
Data: List of floats or integers
"""
n = len(data)
return sum(data) / n

mean(data = [2134,12341,543,5])

3755.75

Calculate Standard Deviation

Project
import math
def std2(data):
"""Calculate the sample standard deviation.
Data: List of floats or integers"""
n = len(data)
if n < 2:
return None
# Step 1: compute mean
n = len(data)
m = sum(data) / n
# Step 2: compute squared deviations
sq_diff_sum = 0
for val in data:
sq_diff_sum += (val - m) ** 2
variance = sq_diff_sum / (n - 1)
return math.sqrt(variance)

std21 = std2([234, 32432])

std21

22767.424140644456

type(std21)

float

std21.

import math

def std(data):
"""
Calculate the sample standard deviation.
Formula: sqrt( Σ (x - mean)^2 / (n-1) )
Data: List of floats or integers
"""
n = len(data)
if n < 2:
return None

# Step 1: compute mean


total = 0
for val in data:
total += val
mean = total / n

# Step 2: compute squared deviations


sq_diff_sum = 0
for val in data:
sq_diff_sum += (val - mean) ** 2
variance = sq_diff_sum / (n - 1)
return math.sqrt(variance)

std([234,345,345, 0.001,625,625])

239.30872365489176

import math

def std1(data):
"""
Calculate the sample standard deviation.
Formula: sqrt( Σ (x - mean)^2 / (n-1) )
data: List of floats or integers
"""
n = len(data)
if n < 2:
return None
m = sum(data) / n
variance = sum((x - m) ** 2 for x in data) / (n - 1)
return math.sqrt(variance)

std1([234,345,345, 0.00001,625,625])

239.30872365489174

Function with a Loop: Sum of Dividends


dividends = [3,5,3]
total = 0

for div in dividends:


total += div
print (total)

3
8
11

def total_dividends(dividends):
"""
Calculate the total sum of dividends received.
"""
total = 0
for div in dividends:
total += div
return total

total_dividends([3245,456,5367,567,458,5678,67,456,356,35636356,356,36
7])

35653729

# Example usage
divids = [2.5, 3.0, 2.8, 3.5, 50.5, 100, 150]
div = total_dividends(divids)
#div
print(f"Total Dividend = {div}")

Total Dividend = 312.3

DDM
def three_stage_ddm(d0, g1, n1, g2, n2, g3, r1, r2, r3):
"""
Three-stage Dividend Discount Model (concise).

Stages:
- Stage 1: dividend grows at g1 for n1 years
- Stage 2: dividend grows at g2 for n2 years
- Stage 3: perpetual growth at g3 thereafter (Gordon growth)

Inputs (decimals):
d0 : last dividend just paid (D0)
g1 : growth in stage 1, years 1..n1
n1 : years in stage 1 (int >= 0)
g2 : growth in stage 2, years n1+1..n1+n2
n2 : years in stage 2 (int >= 0)
g3 : perpetual growth in stage 3 (must be < r)
r : required return (cost of equity)

Returns:
Intrinsic value (float): PV of all explicit dividends + PV of
terminal value

Notes:
- Requires r > g3 and (n1 + n2) >= 1
"""
if r1 <= g1:
raise ValueError("r1 must be greater than g2 for the terminal
leg.")
if r2 <= g2:
raise ValueError("r2 must be greater than g2 for the terminal
leg.")
if r3 <= g3:
raise ValueError("r3 must be greater than g3 for the terminal
leg.")
N = n1 + n2
if N < 1:
raise ValueError("Total forecast years (n1 + n2) must be at
least 1.")

div = d0
pv = 0.0

# Stage 1: grow at g1 for n1 years


for t in range(1, n1 + 1):
div *= (1 + g1)
pv += div / ((1 + r1) ** t)

# Stage 2: grow at g2 for next n2 years


for t in range(n1 + 1, N + 1):
div *= (1 + g2)
pv += div / ((1 + r2) ** t)

# Terminal value at year N, then discount back


tv_N = (div * (1 + g3)) / (r3 - g3)
return pv + tv_N / ((1 + r3) ** N)

# Inputs:
# D0 = 5.00
# Stage 1: g1=12% for n1=3 years
# Stage 2: g2=7% for n2=2 years
# Stage 3: g3=4% perpetual
# r = 10%

p0 = three_stage_ddm(d0=5.0, g1=0.12, n1=3, g2=0.07, n2=2, g3=0.04,


r1=0.15, r2 = 0.12, r3 = 0.1)
print(round(p0, 2))

110.13

Function with Multiple Parameters: EMI Calculation


pwd

'E:\\Teaching at NLD\\Subjects Taught\\AI in Finance\\Content\\NB'

def calculate_emi(principal, rate_of_interest, tenure_years):


"""
Calculate Equated Monthly Installment (EMI).
"""
monthly_rate = rate_of_interest / 12 / 100
total_months = tenure_years * 12
emi = principal * monthly_rate * ((1 + monthly_rate)
** total_months) / (((1 + monthly_rate) ** total_months) - 1)
return f"EMI: ₹{emi:.2f}"

# Example usage
calculate_emi(10000000, 10, 25) # Output: EMI for the given
parameters

'EMI: ₹90870.07'

Function with if-elif-else Statement


Classify an investment based on ROI (Return on Investment)
def classify_investment(roi):
"""
Classifies investment based on ROI.
"""
if roi > 15:
return "High Growth Investment"
elif 10 <= roi <= 15:
return "Moderate Growth Investment"
elif 5 <= roi < 10:
return "Low Growth Investment"
else:
return "Unprofitable Investment"

# Example usage
print(classify_investment(18)) # High Growth Investment
print(classify_investment(12)) # Moderate Growth Investment
print(classify_investment(8)) # Low Growth Investment
print(classify_investment(3)) # Unprofitable Investment

High Growth Investment


Moderate Growth Investment
Low Growth Investment
Unprofitable Investment

Function with while Loop


Determine how many years it will take to double an investment
def years_to_double_investment(principal, rate):
"""
Calculates the years required to double the investment.
"""
target = 2 * principal
years = 0
while principal < target:
principal *= (1 + rate / 100)
years += 1
return years

# Example usage
print(years_to_double_investment(10000, 9))

*args and **kwargs


def myfunc (a,b,c):
return sum((a,b,c))*0.10

myfunc(900,100,500)

150.0

def myfunc(a = 0, b = 0, c = 0, d = 0):


return sum((a,b,c,d))* 0.10

myfunc(400,200,400)

*args
which is an arbitrary word, which creates a tuple of values
def myfunc(*args):
print(args)
return sum(args)* 0.1

myfunc(55,550,200,100,150,25,35,500)

(55, 550, 200, 100, 150, 25, 35, 500)

161.5

Finance Use Case:


**kwargs
which is an arbitrary word, which creates a dictionary of key:value pairs
mydict = {"Rel": "RELAINCE", "Price": 1300, "Vol": 100}
mydict["Price"]

1300

def stock_info(**kwargs):
#print(kwargs)

if "stock_name" in kwargs:
print (f"Stock: {kwargs["stock_name"]}")
if "sector" in kwargs:
print(f"Sector: {kwargs['sector']}")
if 'market_cap' in kwargs:
print(f"Market Cap: {kwargs['market_cap']}")
if 'pe_ratio' in kwargs:
print(f"P/E Ratio: {kwargs['pe_ratio']}")
if "ps_ratio" in kwargs:
print(f"P/S Ratio: {kwargs['ps_ratio']}")

# Example Usage
stock_info(stock_name = "Reliance Industries", sector="Energy",
market_cap="₹16.2 Trillion",
pe_ratio=30.5, ps_ratio = 14.5)

Stock: Reliance Industries


Sector: Energy
Market Cap: ₹16.2 Trillion
P/E Ratio: 30.5
P/S Ratio: 14.5

pip install numpy-financial

Defaulting to user installation because normal site-packages is not


writeable
Collecting numpy-financial
Downloading numpy_financial-1.0.0-py3-none-any.whl.metadata (2.2 kB)
Requirement already satisfied: numpy>=1.15 in c:\programdata\
anaconda3\lib\site-packages (from numpy-financial) (1.26.4)
Downloading numpy_financial-1.0.0-py3-none-any.whl (14 kB)
Installing collected packages: numpy-financial
Successfully installed numpy-financial-1.0.0
Note: you may need to restart the kernel to use updated packages.
Project

OOP: Object Oriented Programming


stu_present = [10,22,35,11,24,56]

stu_present

[10, 22, 35, 11, 24, 56]

type(stu_present)

list
type(list)

type

#.tab
stu_present.

• Functions are not enough for automation when you scale-up the Python sripts and do
more meaningful work
• Commonly repeated tasks and objects can be defined with OOP to create code that is
more usable
• OOP allows you to create your own objects that have methods and attributes
• Recall that after defining a variable or datatype; or after creating instance of the objects,
like; list, string, dictionary etc. you were able to call methods with the .method_name()
or .function_name syntax
• These methods act as functions which use information about the object you create to
return results, or edit the object, for example, .sort, .upper methods

Syntax
class NameOfClass():
def _init_(self,param1,param2):
self.param1 = param1
self.param2 = param2

def some_method1 (self):


# perform some action
print(self.param1)

• class is a keyword for user defined objects.


• Objects are also called classes
• class is a blue print that defines the nature of objects you create.
• Pascal case or Upper Camel casing, as opposed to snake casing
• Dunder init method allows to create instance of the object and attach attributes
• Instance is a specific object created for a particular class
class Smpl():
pass

my_sample = Smpl()

type(my_sample)

If you ask for type of a class called Smpl, it just returns type (datatype) as no instance is created
yet

type(Smpl)

my_sample.
# Creating class with attributes
# ind as a parameter
class Company():
def __init__(self,ind):
self.industry = ind

mycompany = Company(ind = "Auto")

mycompany.industry

type(Company)

type(mycompany)

#Creating class with attributes


# Industry as parameter
class Company():
def __init__(self,industry):
self.industry = industry

mycom = Company(industry = "Auto")

mycom.industry

# mycom.attribute

class Company():
def __init__(self, industry, name, profit):
#init is construction for
self.industry = industry
self.name = name

# Expect boolean True / False


self.profit = profit

class Company():
def __init__(self, industry, name, profit):
self.industry = industry
self.name = name
self.profit = profit

mycomp = Company("OIL", "RELIANCE", True)

mycomp.name

mycomp.profit

class Company():
def __init__(self, industry, name, profit):
#init is construction for
self.industry = industry
self.name = name
# Expect boolean True / False
self.profit = profit

def porl(self,rev,cost):
print(f"Profit = {rev-cost}")

myco = Company("oil", "REL", True)

myco.porl(832454,693234)

class Company():
""" This class / object is created for company analysis"""
def __init__(self, industry, name, profit):
""" This is dunder init method to add attributes"""
#init is construction for
self.industry = industry
self.name = name
# Expect boolean True / False
self.profit = profit

def porl(self,sp,cp):

"""Calculate Profit or Loss using if statement


if sp > cp then it should print "Profit of ₹..."
if sp < cp then it should print "Loss of ₹..."
if sp = cp then it should print "No Profit, No Loss"
"""
if sp>cp:
print (f"Profit of {sp-cp}")
elif sp < cp:
print (f"Loss of {cp-sp}")
else:
print ("No Profit, No Loss")

mycomp = Company("Oil", "Reliance", True)

mycomp.porl(10,10)

Prompt Engineering
class Company():
""" This class / object is created for company analysis"""
def __init__(self, industry, name, profit):
""" This is dunder init method"""
self.industry = industry
self.name = name
# Expect boolean True / False
self.profit = profit

def porl(self,sp,cp):

"""Calculate Profit or Loss using if statement


if sp > cp then it should print "Profit of ₹..."
if sp < cp then it should print "Loss of ₹..."
if sp = cp then it should print "No Profit, No Loss"
"""
if sp>cp:
print (f"Profit of {sp-cp}")
elif sp < cp:
print (f"Loss of {cp-sp}")
else:
print ("No Profit, No Loss")

def j_alpha(self, rp, rm, rf, b):


"""
Calculate Jensen's Alpha and give trading signal.
Parameters:
rp : float - security / portfolio return
rm : float - market return
rf : float - risk-free rate
b : float - portfolio beta
Returns:
alpha : float
Jensen's Alpha
signal : str
Trading decision (BUY/SELL/HOLD)
"""
exp_ret = rf + b * (rm - rf) # CAPM expected return
alpha = rp - exp_ret # Jensen's alpha

# Trading decision
if alpha > 0:
signal = "BUY (Alpha > 0)"
elif alpha < 0:
signal = "SELL (Alpha < 0)"
else:
signal = "HOLD (Alpha = 0)"
# Print results
print("Jensen's Alpha:", round(alpha, 4))
print("Decision:", signal)

myco = Company("Oil", "Reliance", True)

myco.j_alpha(rp = 0.22, rm = 0.18, rf = 0.07, b = 1.25)

class Company():
""" This class / object is created for company analysis"""
def __init__(self, industry, name, profit):
""" This is dunder init method"""
self.industry = industry
self.name = name
# Expect boolean True / False
self.profit = profit

def porl(self,sp,cp):

"""Calculate Profit or Loss using if statement


if sp > cp then it should print "Profit of ₹..."
if sp < cp then it should print "Loss of ₹..."
if sp = cp then it should print "No Profit, No Loss"
"""
if sp>cp:
print (f"Profit of {sp-cp}")
elif sp < cp:
print (f"Loss of {cp-sp}")
else:
print ("No Profit, No Loss")

def j_alpha(self, rp, rm, rf, b):


"""
Calculate Jensen's Alpha and give trading signal.

Parameters:
rp : float - security / portfolio return
rm : float - market return
rf : float - risk-free rate
b : float - portfolio beta

Returns:
alpha : float
Jensen's Alpha
signal : str
Trading decision (BUY/SELL/HOLD)
"""
exp_ret = rf + b * (rm - rf) # CAPM expected return
alpha = rp - exp_ret # Jensen's alpha
# Trading decision
if alpha > 0:
signal = "BUY (Alpha > 0)"
elif alpha < 0:
signal = "SELL (Alpha < 0)"
else:
signal = "HOLD (Alpha = 0)"

# Print results
print("Jensen's Alpha:", round(alpha, 4))
print("Decision:", signal)

def calculate_npv(self, cash_flows, discount_rate):


"""
Calculate the Net Present Value (NPV) given cash flows and a
discount rate.

Parameters:
cash_flows (list): List of cash flows where the first element
is the initial investment.
discount_rate (float): The discount rate as a decimal (e.g.,
0.10 for 10%).

Returns:
float: The calculated NPV.
"""
npv = sum(cf / (1 + discount_rate) ** t for t, cf in
enumerate(cash_flows))
return round(npv,2)

myco1 = Company("Oil", "Reliance", True)

myco1.calculate_npv([-100,25,40,60,100,10], 0.20)

class Company():
def __init__(self, industry, name, profit):
#init is construction for
self.industry = industry
self.name = name
# Expect boolean True / False
self.profit = profit

def porl(self,sp,cp):

"""Calculate Profit or Loss using if statement


if sp > cp then it should print "Profit of ₹..."
if sp < cp then it should print "Loss of ₹..."
if sp = cp then it should print "No Profit, No Loss"
"""
if sp>cp:
print (f"Profit of {sp-cp}")
elif sp < cp:
print (f"Loss of {cp-sp}")
else:
print ("No Profit, No Loss")

def j_alpha(self, rp, rm, rf, b):


"""
Calculate Jensen's Alpha and give trading signal.

Parameters:
rp : float - security / portfolio return
rm : float - market return
rf : float - risk-free rate
b : float - portfolio beta

Returns:
alpha : float
Jensen's Alpha
signal : str
Trading decision (BUY/SELL/HOLD)
"""
exp_ret = rf + b * (rm - rf) # CAPM expected return
alpha = rp - exp_ret # Jensen's alpha

# Trading decision
if alpha > 0:
signal = "BUY (Alpha > 0)"
elif alpha < 0:
signal = "SELL (Alpha < 0)"
else:
signal = "HOLD (Alpha = 0)"

# Print results
print("Jensen's Alpha:", round(alpha, 4))
print("Decision:", signal)

def calculate_npv(self, cash_flows, discount_rate):


"""
Calculate the Net Present Value (NPV) given cash flows and a
discount rate.

Parameters:
cash_flows (list): List of cash flows where the first element
is the initial investment.
discount_rate (float): The discount rate as a decimal (e.g.,
0.10 for 10%).

Returns:
float: The calculated NPV.
"""
npv = sum(cf / (1 + discount_rate) ** t for t, cf in
enumerate(cash_flows))
return round(npv,2)
def three_stage_ddm(self, d0, g1, n1, g2, n2, g3, r1, r2, r3):
"""
Three-stage Dividend Discount Model (concise).

Stages:
- Stage 1: dividend grows at g1 for n1 years
- Stage 2: dividend grows at g2 for n2 years
- Stage 3: perpetual growth at g3 thereafter (Gordon growth)

Inputs (decimals):
d0 : last dividend just paid (D0)
g1 : growth in stage 1, years 1..n1
n1 : years in stage 1 (int >= 0)
g2 : growth in stage 2, years n1+1..n1+n2
n2 : years in stage 2 (int >= 0)
g3 : perpetual growth in stage 3 (must be < r)
r : required return (cost of equity)

Returns:
Intrinsic value (float): PV of all explicit dividends + PV
of terminal value

Notes:
- Requires r > g3 and (n1 + n2) >= 1
"""
if r1 <= g1:
raise ValueError("r1 must be greater than g2 for the
terminal leg.")
if r2 <= g2:
raise ValueError("r2 must be greater than g2 for the
terminal leg.")
if r3 <= g3:
raise ValueError("r3 must be greater than g3 for the
terminal leg.")
N = n1 + n2
if N < 1:
raise ValueError("Total forecast years (n1 + n2) must be
at least 1.")

div = d0
pv = 0.0

# Stage 1: grow at g1 for n1 years


for t in range(1, n1 + 1):
div *= (1 + g1)
pv += div / ((1 + r1) ** t)

# Stage 2: grow at g2 for next n2 years


for t in range(n1 + 1, N + 1):
div *= (1 + g2)
pv += div / ((1 + r2) ** t)

# Terminal value at year N, then discount back


tv_N = (div * (1 + g3)) / (r3 - g3)
return pv + tv_N / ((1 + r3) ** N)

mycom1 = Company("oil", "REL", True)

mycom1.three_stage_ddm(d0 = 25, g1 = 0.15, n1 = 3, g2 = 0.12, n2 = 20,


g3 = 0.05, r1 = 0.2, r2 = 0.15, r3 = 0.1)

mycom1.calculate_npv([-10000,3000,5000,7000], 0.16)

mycom1.calculate_npv([-1000,300,400,800],0.1)

class Company():
def __init__(self, industry, name, profit):
#init is construction for
self.industry = industry
self.name = name
# Expect boolean True / False
self.profit = profit
def porl(self,sales,cost):
print(f"Profit = {sales-cost}")

def calculate_npv(self, cash_flows, discount_rate):


"""
Calculate the Net Present Value (NPV) given cash flows and a
discount rate.

Parameters:
cash_flows (list): List of cash flows where the first element
is the initial investment.
discount_rate (float): The discount rate as a decimal (e.g.,
0.10 for 10%).

Returns:
float: The calculated NPV.
"""
npv = sum(cf / (1 + discount_rate) ** t for t, cf in
enumerate(cash_flows))
return npv
def three_stage_ddm(self, d0, g1, n1, g2, n2, g3, r1, r2, r3):
"""
Three-stage Dividend Discount Model (concise).

Stages:
- Stage 1: dividend grows at g1 for n1 years
- Stage 2: dividend grows at g2 for n2 years
- Stage 3: perpetual growth at g3 thereafter (Gordon growth)

Inputs (decimals):
d0 : last dividend just paid (D0)
g1 : growth in stage 1, years 1..n1
n1 : years in stage 1 (int >= 0)
g2 : growth in stage 2, years n1+1..n1+n2
n2 : years in stage 2 (int >= 0)
g3 : perpetual growth in stage 3 (must be < r)
r1 : required return (cost of equity) during stage 1
r2 : required return (cost of equity) during stage 2
r3 : required return (cost of equity) during stage 3

Returns:
Intrinsic value (float): PV of all explicit dividends + PV
of terminal value

Notes:
- Requires r > g3 and (n1 + n2) >= 1
"""
if r1 <= g1:
raise ValueError("r1 must be greater than g2 for the
terminal leg.")
if r2 <= g2:
raise ValueError("r2 must be greater than g2 for the
terminal leg.")
if r3 <= g3:
raise ValueError("r3 must be greater than g3 for the
terminal leg.")
N = n1 + n2
if N < 1:
raise ValueError("Total forecast years (n1 + n2) must be
at least 1.")

div = d0
pv = 0.0

# Stage 1: grow at g1 for n1 years


for t in range(1, n1 + 1):
div *= (1 + g1)
pv += div / ((1 + r1) ** t)

# Stage 2: grow at g2 for next n2 years


for t in range(n1 + 1, N + 1):
div *= (1 + g2)
pv += div / ((1 + r2) ** t)

# Terminal value at year N, then discount back


tv_N = (div * (1 + g3)) / (r3 - g3)
return pv + tv_N / ((1 + r3) ** N)

mycom2 = Company('OIL', "TM", True)

mycom2.three_stage_ddm(d0 = 5, g1 = 0.14, n1 = 3, g2 = 0.1, n2 = 2, g3 = 0.04, r1 = 0.18, r2 =


0.15, r3 = 0.08)

def ddm_three_stage_taper(d0, g1, n1, g2_start, g2_end, n2, g3, r1, r2, r3): """ Three-stage DDM
with linear taper in Stage-2 and different discount rates per stage.

Stage-1: n1 years at growth g1, discounted at r1


Stage-2: n2 years, growth tapers linearly g2_start -> g2_end,
discounted at r2
Stage-3: perpetual growth g3 (Gordon), terminal leg priced with r3

Constraints:
- n1 + n2 >= 1
- r3 > g3 (only perpetual leg needs this)
- r1, r2, r3 > -1 and g1, g2_start, g2_end, g3 > -1 (to keep 1+r
and 1+g positive)
"""
N = n1 + n2
if N < 1: raise ValueError("n1 + n2 must be >= 1.")
if r3 <= g3: raise ValueError("Require r3 > g3 for the terminal leg.")
if min(r1, r2, r3) <= -1: raise ValueError("All discount rates must be
> -1.")
if min(g1, g2_start, g2_end, g3) <= -1: raise ValueError("All growth
rates must be > -1.")
if d0 < 0: raise ValueError("d0 must be non-negative.")

div, pv, df = d0, 0.0, 1.0 # last dividend, PV accumulator,


cumulative discount factor (df)

# Stage-1: constant growth g1, discount at r1


for _ in range(n1):
div *= (1 + g1) # move to next year's dividend
df *= (1 + r1) # apply stage-1 discount one more year
pv += div / df # add discounted dividend

# Stage-2: tapered growth from g2_start to g2_end (linear), discount


at r2
if n2 > 0:
step = 0.0 if n2 == 1 else (g2_end - g2_start) / (n2 - 1)
for i in range(n2):
g2_t = g2_start + i * step
div *= (1 + g2_t)
df *= (1 + r2)
pv += div / df

# Terminal at year N (Gordon at r3, g3), discounted by df built


through Stage-1&2
terminal = (div * (1 + g3)) / (r3 - g3)
return pv + terminal / df

ddm_three_stage_taper(d0 = 5, g1 = 0.14, n1 = 3, g2_start = 0.14, g2_end = 0.04, n2 = 5, g3 =


0.04, r1 = 0.18, r2 = 0.15, r3 = 0.08)

===== PYTHON STATS TOOLKIT =====


import math # standard library only

class BasicStats:
"""
Minimal class for basic statistics and z-based inference (intro
MBA analytics).
Only __init__ is used as a dunder; all other capabilities are
plain methods.

What it provides
----------------
Descriptives:
mean(xs), sample_variance(xs), sample_sd(xs)
Distribution helpers:
phi(z) : standard normal CDF via math.erf
z_crit(conf) : two-sided critical values for {0.90, 0.95,
0.99}
Hypothesis tests:
one_sample_mean_ztest(data, mu0, alternative)
two_sample_mean_ztest(a, b, alternative) # Welch-style SE
one_sample_prop_ztest(successes, n, p0, alternative)
two_sample_prop_ztest(s1, n1, s2, n2, alternative)
Confidence intervals:
ci_mean(data, confidence) # z-based
ci_proportion(successes, n, confidence,
method='wilson'|'wald')

Notes
-----
- z-based methods are exact if population sigma is known;
otherwise good for large n.
- For small samples with unknown sigma, use t criticals from a
table (same formulas with t*).
"""

def __init__(self):
# store constants, lookups, and small helpers as attributes
(added only via __init__)
self.Z_TWO_SIDED = {0.90: 1.6448536269514722, 0.95:
1.959963984540054, 0.99: 2.5758293035489004}

# ---------- Descriptives ----------


def mean(self, xs):
"""Return arithmetic mean."""
xs = list(xs) # ensure we can iterate
multiple times
return sum(xs) / len(xs)

def sample_variance(self, xs):


"""Unbiased sample variance (ddof=1)."""
xs = list(xs)
n = len(xs)
if n < 2:
raise ValueError("Need at least two observations.")
m = self.mean(xs)
ssd = sum((x - m) ** 2 for x in xs)
return ssd / (n - 1)

def sample_sd(self, xs):


"""Sample standard deviation (unbiased)."""
return math.sqrt(self.sample_variance(xs))

# ---------- Distribution helpers ----------


def phi(self, z):
"""Standard normal CDF Φ(z) via the error function:
Φ(z)=0.5*[1+erf(z/√2)]."""
return 0.5 * (1.0 + math.erf(z / math.sqrt(2.0)))

def z_crit(self, confidence):


"""Return two-sided z* critical value for common levels."""
if confidence not in self.Z_TWO_SIDED:
raise ValueError("Use confidence in {0.90, 0.95, 0.99}.")
return self.Z_TWO_SIDED[confidence]

# ---------- Hypothesis tests ----------


def one_sample_mean_ztest(self, data, mu0, alternative="two-
sided"):
"""
One-sample mean z-test using sample sd as sigma estimate
(large n).
H0: μ = mu0; H1: two-sided/larger/smaller.

Returns dict: {'z','p','mean','sd','n'}


"""
data = list(data)
n = len(data) # sample
size
xbar = self.mean(data) # sample
mean
s = self.sample_sd(data) # sample
SD
se = s / math.sqrt(n) #
standard error of mean
z = (xbar - mu0) / se # test
statistic

if alternative == "two-sided":
p = 2.0 * (1.0 - self.phi(abs(z)))
elif alternative == "larger":
p = 1.0 - self.phi(z)
elif alternative == "smaller":
p = self.phi(z)
else:
raise ValueError("alternative ∈ {'two-
sided','larger','smaller'}")

return {"z": z, "p": p, "mean": xbar, "sd": s, "n": n}

def two_sample_mean_ztest(self, a, b, alternative="two-sided"):


"""
Two-sample mean z-test (Welch-style SE).
H0: μ_a - μ_b = 0; H1: two-sided/larger/smaller.

Returns dict:
{'z','p','mean_a','mean_b','sd_a','sd_b','n_a','n_b'}
"""
a, b = list(a), list(b)
n_a, n_b = len(a), len(b)
m_a, m_b = self.mean(a), self.mean(b)
s_a, s_b = self.sample_sd(a), self.sample_sd(b)
se = math.sqrt((s_a**2)/n_a + (s_b**2)/n_b)
z = (m_a - m_b) / se

if alternative == "two-sided":
p = 2.0 * (1.0 - self.phi(abs(z)))
elif alternative == "larger":
p = 1.0 - self.phi(z)
elif alternative == "smaller":
p = self.phi(z)
else:
raise ValueError("alternative ∈ {'two-
sided','larger','smaller'}")

return {"z": z, "p": p, "mean_a": m_a, "mean_b": m_b,


"sd_a": s_a, "sd_b": s_b, "n_a": n_a, "n_b": n_b}

def one_sample_prop_ztest(self, successes, n, p0,


alternative="two-sided"):
"""
One-sample proportion z-test.
H0: p = p0; H1: two-sided/larger/smaller.

Returns dict: {'z','p','phat','n'}


"""
phat = successes / n
se0 = math.sqrt(p0 * (1 - p0) / n)
z = (phat - p0) / se0

if alternative == "two-sided":
p = 2.0 * (1.0 - self.phi(abs(z)))
elif alternative == "larger":
p = 1.0 - self.phi(z)
elif alternative == "smaller":
p = self.phi(z)
else:
raise ValueError("alternative ∈ {'two-
sided','larger','smaller'}")

return {"z": z, "p": p, "phat": phat, "n": n}

def two_sample_prop_ztest(self, s1, n1, s2, n2, alternative="two-


sided"):
"""
Two-sample proportion z-test with pooled SE under H0: p1 - p2
= 0.
Returns dict: {'z','p','p1','p2','ppool','n1','n2'}
"""
p1, p2 = s1 / n1, s2 / n2
ppool = (s1 + s2) / (n1 + n2)
se = math.sqrt(ppool * (1 - ppool) * (1/n1 + 1/n2))
z = (p1 - p2) / se

if alternative == "two-sided":
p = 2.0 * (1.0 - self.phi(abs(z)))
elif alternative == "larger":
p = 1.0 - self.phi(z)
elif alternative == "smaller":
p = self.phi(z)
else:
raise ValueError("alternative ∈ {'two-
sided','larger','smaller'}")

return {"z": z, "p": p, "p1": p1, "p2": p2, "ppool": ppool,


"n1": n1, "n2": n2}

# ---------- Confidence intervals ----------


def ci_mean(self, data, confidence=0.95):
"""
z-based CI for population mean using sample sd (good for large
n).
Returns dict: {'lower','upper','mean','n','zcrit'}
"""
data = list(data)
n = len(data)
m = self.mean(data)
s = self.sample_sd(data)
z = self.z_crit(confidence)
margin = z * (s / math.sqrt(n))
return {"lower": m - margin, "upper": m + margin, "mean": m,
"n": n, "zcrit": z}

def ci_proportion(self, successes, n, confidence=0.95,


method="wilson"):
"""
CI for a binomial proportion. 'wilson' recommended over naive
'wald' for coverage.
Returns dict: {'lower','upper','phat','n','method','zcrit'}
"""
phat = successes / n
z = self.z_crit(confidence)

if method == "wald":
se = math.sqrt(phat * (1 - phat) / n)
lower, upper = phat - z * se, phat + z * se
elif method == "wilson":
denom = 1 + (z*z)/n
center = (phat + (z*z)/(2*n)) / denom
adj = z * math.sqrt((phat*(1 - phat)/n) + (z*z)/(4*n*n)) /
denom
lower, upper = center - adj, center + adj
else:
raise ValueError("method ∈ {'wilson','wald'}")

# truncate to [0,1]
lower = max(0.0, lower)
upper = min(1.0, upper)
return {"lower": lower, "upper": upper, "phat": phat, "n": n,
"method": method, "zcrit": z}

Basic Finance Module


# ======================= SIMPLIFIED FINANCIAL MANAGEMENT TOOLKIT
=======================
import math

class FinancialBasics():
"""
Finance toolkit covering:
- Liquidity Ratios
- Efficiency / Activity Ratios
- Leverage / Solvency Ratios
- Profitability Ratios
- Market Ratios
- DuPont Analysis
- Break-even & Leverage
- WACC
- Time Value of Money (PV, FV, NPV, IRR)
"""

def __init__(self):
# For IRR calculations
self.eps = 1e-9
self.max_iter = 10000
self.irr_low = -0.999
self.irr_high = 10.0

# ========== 1) LIQUIDITY ==========


def current_ratio(self, current_assets, current_liabilities):
return current_assets / current_liabilities

def quick_ratio(self, current_assets, inventory,


current_liabilities):
return (current_assets - inventory) / current_liabilities

def cash_ratio(self, cash_and_equiv, current_liabilities):


return cash_and_equiv / current_liabilities

# ========== 2) EFFICIENCY ==========


def inventory_turnover(self, cogs, avg_inventory):
return cogs / avg_inventory

def dio(self, cogs, avg_inventory, days=365):


return days / self.inventory_turnover(cogs, avg_inventory)

def receivables_turnover(self, net_credit_sales, avg_ar):


return net_credit_sales / avg_ar

def dso(self, net_credit_sales, avg_ar, days=365):


return days / self.receivables_turnover(net_credit_sales,
avg_ar)

def payables_turnover(self, cogs, avg_ap):


return cogs / avg_ap

def dpo(self, cogs, avg_ap, days=365):


return days / self.payables_turnover(cogs, avg_ap)

def total_asset_turnover(self, sales, avg_total_assets):


return sales / avg_total_assets

def fixed_asset_turnover(self, sales, avg_net_fixed_assets):


return sales / avg_net_fixed_assets

def cash_conversion_cycle(self, cogs, net_credit_sales, avg_inv,


avg_ar, avg_ap, days=365):
return self.dio(cogs, avg_inv, days) +
self.dso(net_credit_sales, avg_ar, days) - self.dpo(cogs, avg_ap,
days)

# ========== 3) LEVERAGE ==========


def debt_ratio(self, total_debt, total_assets):
return total_debt / total_assets

def debt_to_equity(self, total_debt, total_equity):


return total_debt / total_equity

def interest_coverage(self, ebit, interest_expense):


return ebit / interest_expense

def fixed_charge_coverage(self, ebit, lease_or_fixed,


interest_expense):
return (ebit + lease_or_fixed) / (interest_expense +
lease_or_fixed)

# ========== 4) PROFITABILITY ==========


def gross_margin_pct(self, sales, cogs):
return (sales - cogs) / sales

def operating_margin_pct(self, ebit, sales):


return ebit / sales

def net_margin_pct(self, net_income, sales):


return net_income / sales

def roa(self, net_income, avg_total_assets):


return net_income / avg_total_assets

def roe(self, net_income, avg_equity):


return net_income / avg_equity

def roic(self, ebit, tax_rate, invested_capital):


nopat = ebit * (1 - tax_rate)
return nopat / invested_capital

# ========== 5) MARKET ==========


def epss(self, net_income, shares_outstanding):
return net_income / shares_outstanding

def dps(self, total_dividends, shares_outstanding):


return total_dividends / shares_outstanding

def pe(self, price_per_share, eps_value):


return price_per_share / eps_value

def pb(self, price_per_share, book_value_per_share):


return price_per_share / book_value_per_share

def dividend_payout_ratio(self, total_dividends, net_income):


return total_dividends / net_income

def retention_ratio(self, total_dividends, net_income):


return 1 - (total_dividends / net_income)

def sustainable_growth_rate(self, roe_value, retention):


return roe_value * retention

# ========== 6) DUPONT ==========


def dupont_3step(self, net_income, sales, avg_total_assets,
avg_equity):
margin = net_income / sales
turnover = sales / avg_total_assets
em = avg_total_assets / avg_equity
return {
"net_margin": margin,
"asset_turnover": turnover,
"equity_multiplier": em,
"roe": margin * turnover * em
}

# ========== 7) BREAK-EVEN & LEVERAGE ==========


def contribution_margin_per_unit(self, price, variable_cost):
return price - variable_cost

def cm_ratio(self, price, variable_cost):


return (price - variable_cost) / price

def break_even_units(self, fixed_cost, price, variable_cost):


return fixed_cost / (price - variable_cost)

def margin_of_safety_units(self, actual_units, fixed_cost, price,


variable_cost):
return actual_units - self.break_even_units(fixed_cost, price,
variable_cost)

def dol(self, sales, variable_cost_total, fixed_cost):


cm = sales - variable_cost_total
ebit = cm - fixed_cost
return cm / ebit

def dfl(self, ebit, interest_expense):


return ebit / (ebit - interest_expense)

def dcl(self, sales, vc_total, fixed_cost, interest_expense):


dol_val = self.dol(sales, vc_total, fixed_cost)
dfl_val = self.dfl(sales - vc_total - fixed_cost,
interest_expense)
return dol_val * dfl_val
# ========== 8) WACC ==========
def wacc(self, cost_of_equity, cost_of_debt, market_equity,
market_debt, tax_rate):
V = market_equity + market_debt
we = market_equity / V
wd = market_debt / V
return cost_of_equity * we + cost_of_debt * (1 - tax_rate) *
wd

# ========== 9) TIME VALUE OF MONEY ==========


def pv(self, rate, nper, pmt=0, fv=0, when='end'):
if abs(rate) < self.eps:
return -pmt * nper - fv
factor = 1 if when == 'end' else (1 + rate)
pv_ann = -pmt * factor * (1 - (1 + rate) ** (-nper)) / rate
pv_fv = -fv * (1 + rate) ** (-nper)
return pv_ann + pv_fv

def fv(self, rate, nper, pmt=0, pv=0, when='end'):


factor = 1 if when == 'end' else (1 + rate)
if abs(rate) < self.eps:
return -pv - pmt * nper * factor
return -(pv * (1 + rate) ** nper + pmt * factor * ((1 + rate)
** nper - 1) / rate)

def npv(self, rate, cash_flows):


return sum(cf / ((1 + rate) ** t) for t, cf in
enumerate(cash_flows))

def irr(self, cash_flows):


lo, hi = self.irr_low, self.irr_high
npv_lo = self.npv(lo, cash_flows)
npv_hi = self.npv(hi, cash_flows)
if npv_lo * npv_hi > 0:
return None
for _ in range(self.max_iter):
mid = (lo + hi) / 2
npv_mid = self.npv(mid, cash_flows)
if abs(npv_mid) < self.eps:
return mid
if npv_lo * npv_mid < 0:
hi, npv_hi = mid, npv_mid
else:
lo, npv_lo = mid, npv_mid
return (lo + hi) / 2

f = FinancialBasics()

f.dupont_3step(net_income = 100, sales = 1000, avg_total_assets =


1500, avg_equity=500)
{'net_margin': 0.1,
'asset_turnover': 0.6666666666666666,
'equity_multiplier': 3.0,
'roe': 0.2}

f.epss(150, 100)

1.5

f.dps(1000, 100)

10.0

You might also like