Workshop 1 Solution, Algorithms and Data Analysis

Author

Alberto Dorantes

Published

September 22, 2025

Abstract
This is an INDIVIDUAL workshop. In this workshop we learn about Algirithmic thinking and foundations of programming. We practice writing pseudo-code for simple finance-related problems

1 Introduction to Algorithmic thinking

What is an Algorithm? It is a set of logical, structured and sequential set of steps that takes input information, process it and creates a desired output.

How to design an algorithm?

  • Write the problem with your words and with clear and short sentences.

  • Identify what inputs are needed to solve the problem

  • Identify what is the output or the final expected result

  • What is the general approach to solve the problem? Here you specify general steps you will follow in a sequential order.

  • What is the specific steps for each general step specified above

Pseudo-code vs programming code

When we design

How can we use LLM’s (such as ChatGPT) to learn how think algorithmically ?

2 Introduction to programming code

What is a programming language? A programming language is a set of commands or instructions that are executed by the computer usually to automate repetitive tasks or functions that usually require intensive data processing. Programming languages are also used to develop computer applications. In Economics and Finance, we use programming languages mainly to do the following:

  1. data input and/or data collection,
  2. data cleaning,
  3. data management including data transformation and data merging,
  4. data storing,
  5. data processing that includes descriptive analytics and predictive models, and finally
  6. information delivery that includes reports or documents usually with summary tables and graphs.

You can effectively perform these programming processes in Python or R.
Python is a free open source language. Nowadays, both Python and R are the two more popular programming languages for Data Science around the world.

2.1 Elements of a programming language

Any programming language has the following elements used to automate any pseudocode to solve any business or technical problem:

  • Variables and variable types

  • Conditionals using comparison operators

  • Loops to do repetitive tasks

  • Data structures - objects

    • Data frames

    • Objetcs

  • Functions

    A function is a method that receives an input (1 or more parameters, which can be variables), do specific steps to process the input, and at the end, return an output which can be one number, one variable with numbers, a data frame, or a complete data structure such as an object.

3 What is an Objet-Programming Language?

  • Objects:

    • Classes: Specification of a data structure that contains both properties or variables, other objects, and methods

    • Object as an instance of a Class

    • Each object contains data as attributes or properties, and methods (functions) that operate into on the data. The methods are usually functions

4 CHALLENGE 1

You have to write pseudocode and corresponding Python code to calculate the number of months needed to finish paying a mortgage loan. The information about the loan is the following:

Loan amount = $3,000,000.00 pesos

APR (Annual % rate) = 11% (compounded monthly)

Monthly Fixed Payment = $40,000.00 (includes interests and capital)

Your program has to provide 2 results: the number of months needed to finish paying the loan, and the amount of the last payment if the payment is less than the fixed payment amount. Your program has to be able to run with any change in any of the values of the above variables.

Once you wrote your Algorithm as a Text CHUHK, use it as a prompt (or series of prompts) for Gemini to generate Python code.

You have to run the Python code and check whether your results are correct.

Pay attention in class about the syntax and logic of Python computer language.

This is a quite challenging exercise!

Hint: if you are familiar with Excel, start solving the problem in Excel, and then try to write your logical steps as pseudocode. # CHALLENGE 1 SOLUTION - Approach 1

My general approach was the following. The inputs of the problem are

  • Loan amount (LOAN)
  • Annual percentage rate (APR)
  • Fixed payment per month (PAYMENT)

The outputs are:

  • Number of months needed to fully pay the loan
  • Amount of the last payment

My approach is to write a while loop that will end when the balance ($ owned) is zero or less than zero. Each iteration will simulate each month of the loan period where interest, principal and balance for the the month will be calculated.

Before I do the iterations for the loop, I initialize:

  • BALANCE to be equal to the LOAN amount, and
  • A variable N to zero for the # of months.

For each iteration of this loop I will do the following:

  1. Add 1 to N
  2. Calculate the interests for the month using a monthly interest rate
  3. Calculate the principal amount of the payment
  4. Subtract the principal of the payment from the BALANCE
  5. If BALANCE is zero or negative, then calculate the last payment amount and display N as the # of months needed to pay the loan

Here is my code and its documentation:

# Parámetros iniciales
LOAN = 3_000_000       # Monto del préstamo
BALANCE = LOAN
APR = 0.11             # Tasa anual (12%)
PAYMENT = 40_000       # Pago mensual
N = 0                  # Contador de meses

# Bucle hasta que el saldo llegue a 0 o menos
while BALANCE > 0:
    # Incrementar contador de meses
    N += 1

    # Intereses mensuales
    INTERESTS = BALANCE * (APR / 12)

    # Parte del pago que corresponde al principal
    PRINCIPAL = PAYMENT - INTERESTS

    # Actualizar saldo
    BALANCE -= PRINCIPAL

    # Verificar si el saldo llegó a cero o negativo
    if BALANCE <= 0:
        # El último pago será menor que el pago regular
        LASTPAYMENT = PAYMENT + BALANCE
        print(f"The last payment will be less than the rest, and will be {LASTPAYMENT:,.2f} in period {N}")

# Resultado final
print(f"The number of periods (months) to finish paying the loan is {N}")
The last payment will be less than the rest, and will be 18,840.27 in period 128
The number of periods (months) to finish paying the loan is 128

4.1 CHALLENGE 1 Solution - Approach 2

Another approach to solve this problem is to look at the Annuity formula and try to see if there is an analytic way to calculate the N, the number of periods. You can see my Note Basics of Return and Risk to review basic formulas of Time value of Money.

This mortgage problem can be solved using the formula for the Annuity. An annuity is a fixed cash flow that is payed each period (monthly or annual) and the interest rate is the same for all periods

The formula to get the present value (PV) of fixed payments C in N periods with a period rate R is the following:

PV=\frac{C}{R}*\left[1-\frac{1}{(1+R)^{N}}\right]

I will do basic algebra to get N, the number of periods:

I multiply both sides times \frac{R}{C}:

PV*\frac{R}{C}=1-\frac{1}{(1+R)^{N}} I try to leave (1+R)^N in the left side of the equation:

\frac{1}{(1+R)^{N}}=1-PV*\frac{R}{C}

(1+R)^{N}=\frac{1}{\left[1-\frac{PV(R)}{C}\right]} Now I can apply natural logs to both sides of the equation, so that I can leave N alone:

ln(1+R)^{N}=ln\left(\frac{1}{\left[1-\frac{PV(R)}{C}\right]}\right) Following basic rules of logarithms:

N*ln(1+R)=ln(1)-ln\left(1-\frac{PV(R)}{C}\right)

Note that ln(1)=0. Then, finally I got N as:

N=\frac{-ln\left(1-\frac{PV(R)}{C}\right)}{ln(1+R)}

Now I can easily implement this formula in Python as follows:

import math

# Parámetros iniciales
BALANCE = 3_000_000
PAYMENT = 40_000
APR = 0.11

# Fórmula: N = (-ln(1 - (PV * r / C))) / ln(1 + r)
# Donde PV = saldo (principal), r = tasa por periodo, C = pago periódico
r = APR / 12  # tasa mensual

N2 = (-math.log(1 - (BALANCE * r / PAYMENT))) / math.log(1 + r)

print("The number of months (in decimal) I need to finish paying my mortgage is:")
print(N2)

# Obtener la parte entera del número de meses
Nmonths = math.trunc(N2)

# Si hay una parte decimal, implica un pago final parcial
if Nmonths < N2:
    lastpayment = (N2 - Nmonths) * PAYMENT
    Nmonths += 1
else:
    lastpayment = 0

print(f"In other words, I need {Nmonths} months to pay the mortgage.")
print(f"The last payment must be = ${lastpayment:,.2f}")
The number of months (in decimal) I need to finish paying my mortgage is:
127.46987018733515
In other words, I need 128 months to pay the mortgage.
The last payment must be = $18,794.81

5 CHALLENGE 2

Write pseudo-code and corresponding Python code to calculate the price of the following bond issued by the company ABC. ABC needs to finance an important project to develop a new technological device. To get the money, ABC issued a bond with the following characteristics:

  • Principal: $3,000,000
  • Time to maturity: 20 years
  • Coupon rate: 11% (annual)
  • coupons are payed semi annually

Calculate the price of this bond if the stated annual interest rate is:

  1. 8%
  2. 11%
  3. 13%

As in the previous challenge, do the same to generate Python code.

5.1 CHALLENGE 2 Solution - Approach 1

Since I have to calculate the price bond for 3 different interest rates, it is a good idea to write a function that receives the principal, time to maturity, coupon rate and interest rate.

In this approach I will use a vector with the cash flows, calculate the present values of each cash flow, and then I add them all to get the bond price. I will solve this problem using vectorization instead of a loop.

import numpy as np

def bondprice(principal, ttm, coupon_rate, interest_rate, periods):
    """
    Calculates the price of a bond given its parameters.

    Parameters:
        principal (float): Face value of the bond
        ttm (int): Time to maturity (in years)
        coupon_rate (float): Annual coupon rate (e.g., 0.06 for 6%)
        interest_rate (float): Annual market interest rate (yield)
        periods (int): Number of compounding periods per year

    Returns:
        float: Present value (price) of the bond
    """
    # Coupon payment per period
    coupon = (coupon_rate / periods) * principal
    
    # Cash flow vector: all coupons, with the last payment including principal
    cf = np.repeat(coupon, ttm * periods)
    cf[-1] += principal  # add principal to the last payment
    
    # Discount factors
    exponents = np.arange(1, ttm * periods + 1)
    discount_factors = 1 / (1 + interest_rate / periods) ** exponents
    
    # Present value (bond price)
    present_value = np.sum(cf * discount_factors)
    
    return present_value

# Once I have my function, I just call my function with the parameters specified 
#  in the problem. 
# I run my function 3 times for the 3 interest rates: 

# Run the function for three different interest rates:

# 8% annual interest rate:
bond1 = bondprice(principal=3_000_000, ttm=20, coupon_rate=0.11, interest_rate=0.08, periods=2)
print("The bond price when interest rate is 8% is")
print(f"$ {bond1:,.2f}")

# 11% annual interest rate:
bond2 = bondprice(3_000_000, 20, 0.11, 0.11, 2)
print("The bond price when interest rate is 11% is")
print(f"$ {bond2:,.2f}")

# 13% annual interest rate:
bond3 = bondprice(3_000_000, 20, 0.11, 0.13, 2)
print("The bond price when interest rate is 13% is")
print(f"$ {bond3:,.2f}")
The bond price when interest rate is 8% is
$ 3,890,674.82
The bond price when interest rate is 11% is
$ 3,000,000.00
The bond price when interest rate is 13% is
$ 2,575,634.19

5.2 CHALLENGE 2 Solution - Approach 2

In this approach I use the annuity formula and the present value formula to calculate the bond price. I also use a function since I will be calculating bond price three times for 3 interest rates.

def bondprice2(principal, ttm, coupon_rate, interest_rate, periods):
    """
    Calculates the bond price using the annuity formula for coupon PV and 
    the present value of the principal.

    Parameters:
        principal (float): Face value of the bond
        ttm (int): Time to maturity (years)
        coupon_rate (float): Annual coupon rate (e.g., 0.11 for 11%)
        interest_rate (float): Annual market interest rate (yield)
        periods (int): Number of compounding periods per year

    Returns:
        float: Present value (price) of the bond
    """
    # Coupon payment per period
    coupon = (coupon_rate / periods) * principal

    # Present value of coupons (ordinary annuity)
    PV_coupons = coupon / (interest_rate / periods) * (
        1 - 1 / (1 + interest_rate / periods) ** (ttm * periods)
    )

    # Present value of the principal
    PV_principal = principal / (1 + interest_rate / periods) ** (ttm * periods)

    # Bond price
    return PV_coupons + PV_principal


# Run the function for three different interest rates
bond1 = bondprice2(3_000_000, 20, 0.11, 0.08, 2)
print("The bond price when interest rate is 8% is")
print(f"$ {bond1:,.2f}")

bond2 = bondprice2(3_000_000, 20, 0.11, 0.11, 2)
print("The bond price when interest rate is 11% is")
print(f"$ {bond2:,.2f}")

bond3 = bondprice2(3_000_000, 20, 0.11, 0.13, 2)
print("The bond price when interest rate is 13% is")
print(f"$ {bond3:,.2f}")
The bond price when interest rate is 8% is
$ 3,890,674.82
The bond price when interest rate is 11% is
$ 3,000,000.00
The bond price when interest rate is 13% is
$ 2,575,634.19

I got the same results in both approaches!