Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

Assignment 4 — MF 602

Objective and Overview

Objective: The objective of this assignment is to practice building lists with list                comprehensions, work with list data using list comprehensions, and be introduced to the indefinite loop.

Overview:You will write several functions to aid in pricing xed-income securities (bonds), and calculate the yield-to-maturity for a bond investment. Finally, you will implement a function to  simulate the sale of new bonds via an auction process.

Preliminaries

In your work on this assignment, make sure to abide by the collaboration policies of the course.

If you have questions while working on this assignment, please post them on Piazza! This is the best way to get a quick response from your classmates and the course staff.

General Guidelines

Refer to the class Coding Standards for important style guidelines. The grader will be awarding/deducting points for writing code that comforms to these standards.

Include comments at the top of the le that are similar to the ones that we gave you at

the top of a1task1.py.

Your functions musthave the exact names that we have specied, or we wont be able

to test them. Note in particular that the case of the letters matters (all of them should be lowercase), and that you should use an underscore character (_) wherever we have specified one (e.g., in convert_from_inches).

Each of your functions should include a docstring that describes whatyourfunction

doesandwhatitsinputsare.

If a function takes more than one input, you mustkeep the inputs in the order that we

have specied.

You should notuse any Python features that we have not discussed in class or read

about in the textbook.

Unless expressly stated, your functions do notneed to handle bad inputs inputs with

a type or value that doesnt correspond to the description of the inputs provided in the

problem.

Make sure that your functions returnthe specied value, rather than printing it. Unless it

is expressly stated in the problem, none of these functions should use a print statement.

Important note regarding test cases and Gradescope:

Youmusttesteachfunctionafteryouwriteit. Here are two ways to do so:

Run your le after you nish a given function. Doing so will bring you to the Shell,

where you can call the function using different inputs and check to see that you obtain the correct outputs.

Add test calls to the bottom of your le, inside the if __name__ == '__main__'

control struture. For example:

if __name__ == '__main__':

print("mystery(6,7) returned", mystery(6,7))

These tests will be called every time that you run the le, which will save you from   having to enter the tests yourself. We have given you an example of one such test in the starter le.

You mustnotleave any print statements in the global scope. This will cause an error

with the Gradescope autograder. Make sure all of your print statements are inside a function scope or insude the if __name__ == '__main__' control struture.

Warm-up Problems

Work on these practice problems before class. We will discuss solutions in class and answer your questions.

1. Practice LC Puzzles – Fill in the Blanks:

>>> [__________ for x in range(4)]

[0, 14, 28, 42]

>>> [__________ for s in ['boston', 'university', 'cs']

['bos', 'uni', 'cs']

>>> [__________ for c in 'compsci']

['cc', 'oo', 'mm', 'pp', 'ss', 'cc', 'ii']

>>> [__________ for x in range(20, 30) if ____________]

[20, 22, 24, 26, 28]

>>> [__________ for w in ['I', 'like', 'ice', 'cream']]

[1, 4, 3, 5]

2. Write the function divisors(n, values), that returns a list of all values for which n is a divisor without remainder. Use a list comprehension.

>>> divisors(4,[4,5,6,7,8])

[4, 8]

Hint: use an if clause in your list comprehension.

3. Write the function perfect_squares(values), that returns a list of all values that are perfect squares. Use a list comprehension.

>>> perfect_squares([4,5,6,7,8,9,10])

[4, 9]

Hint: use an if clause in your list comprehension.

4. Write the function generate_primes(n), that returns a list of all prime numbers up to and including n.

For example: >>> generate_primes(10) [2, 3, 5, 7]

Hint: use an if clause in your list comprehension.

You will need to first write a helper function: is_prime(x), which returns True if x is a prime number and False otherwise.

For example:

>>> is_prime(10)

False

>>> is_prime(11)

True

The is_prime function may use a for loop or recursion.

5. Write the function guessing_game(low, high), that asks a user to guess a secret number in the range of low to high.

The secret number can be chosen at random:

import random

secret = random.randint(low, high)

Prompt the user for a guess:

guess = int(input(f'Guess a number between {low} and {high}: '))

Use an indefinite loop to stop the loop when guess is correct. Inside the loop, give               feedback, i.e., “too high” or too low” and prompt for another guess. After the loop, print out “All done!” The function does not need to return any value.

Task 1: Discounted Cashows and Bond Pricing

60points;individual-only

Do this entire task in a le called a4task1.py.

1. Write the function cashflow_times(n, m) to develop the list of the times at which a bond makes coupon payments, with n years and m coupon payments per year.

For example:

>>> cashflow_times(5,2) # 5-year bond with 2 coupons/year

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

>>> cashflow_times(3,4) # 3-year bond with 4 coupons/year

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

>>> cashflow_times(2,12) # 2-year bond with monthly coupons

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 2 >>>

Notes:

Your function must use a list comprehension (no loops or recursion), and requires no

if-elif-else logic.

2. Write the function discount_factors(r, n, m) to calculate and return a list of discount factors for a given annualized interest rate r, for n years, and m discounting periods per     year.

Your function must use a list comprehension (no loops or recursion).

For example:

>>> # 3% rate, 1 years, 2 payments/year

>>> discount_factors(0.03, 1, 2)

[0.9852216748768474, 0.9706617486471405]

>>> # 5% rate, 5 years, 2 payments/year

>>> discount_factors(0.05, 5, 2)

[0.9756097560975611, 0.9518143961927424, 0.928599410919749, 0.90595064479

Notes:

Your function must use a list comprehension (no loops or recursion), and requires no

if-elif-else logic.

You may assume that m and n are integers.

3. Write the function bond_cashflows(fv, c, n, m) to calculate and return a list of      cashflows for a bond specified by the parameters. The parameters are: fv is the future (maturity) value of the bond;

c is the annualcoupon rate expressed as percentage per year;

n is the number of yearsuntil maturity;

m is the number of coupon payments per year.

In general, the coupon payment is given by:

The nal payment of the bond is a coupon payment plus the maturity value (fv) of the bond.

For example:

>>> bond_cashflows(1000, 0.08, 5, 2) # 5 year bond with 2 coupons/year   [40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 40.0, 1040.0]           >>> bond_cashflows(10000, 0.0575, 2, 2) # 2 year bond with 2 coupons/year [287.5, 287.5, 287.5, 10287.5]

>>> bond_cashflows(5000, 0.09, 2, 4) # 2 year bond with 4 coupons/year [112.5, 112.5, 112.5, 112.5, 112.5, 112.5, 112.5, 5112.5]

Notes:

Your function must use a list comprehension (no loops or recursion), and requires no

if-elif-else logic.

Re-use your cashflow_times(n, m) function to obtain the list of the times of the

cashows for this bond this will give you the correct number of cashows.

Notice that the last period’s casflow includes the maturity vale (fv) of the bond as well as the last coupon payment.

4. Write the function bond_price(fv, c, n, m, r) to calculate and return the price of a bond. The parameters are: fv is the future (maturity) value of the bond;

c is the annualcoupon rate expressed as percentage per year;

n is the number of yearsuntil maturity;

m is the number of coupon payments per year;

and r, the annualized yield to maturity of the bond

The price of the bond is the sum of the present values of the cashows of that bond.

For example:

>>> # 3-year, 4% coupon bond, semi-annual coupons, priced at 4% annualize >>> bond_price(100, 0.04, 3, 2, 0.04)

100.0 # sells at par

>>> # 3-year, 4% coupon bond, semi-annual coupons, priced at 3% annualize

>>> bond_price(100, 0.04, 3, 2, 0.03)

102.84859358273769 # sells at a premium

>>> # 3-year, 4% coupon bond, semi-annual coupons, priced at 5% annualize >>> bond_price(100, 0.04, 3, 2, 0.05)

97.24593731921014 # sells at a discount

Important Implementation Notes:

Your function must use a list comprehension (no loop with an accumulator pattern or

recursion) and requires no if-elif-else logic. Consider the equation above, and how you could use a list comprehension to build this result.

Re-use your cashflow_times(n,m) function from above to nd the cashow times for

this bond.

Re-use your bond_cashflows(fv, c, n,m) function from above to find the cashflows associated with this bond.

Re-use your discount_factors(r, n, m) function from above to calculate the relevant discount factors.

5. Write the function bond_yield_to_maturity(fv, c, n, m, price): to calculate the annualized yield to maturityon a bond. The parameters are: fv is the future (maturity) value of the bond;

c is the annualcoupon rate expressed as percentage per year;

n is the number of yearsuntil maturity;

m is the number of coupon payments per year;

and price is the current market price of the bond

For example, consider a 3-year bond with a 4% coupon rate, with coupons paid semi-     annually. We observe the bond is selling for $101.75. The yield to maturity is the implied interest rate for this bond, in this case is 3.38% per year:

>>> bond_yield_to_maturity(100, 0.04, 3, 2, 101.75)

0.03381660580635071

As a second example, consider a 5-year bond with an 8% coupon rate, with coupons paid annually. We observe the bond is selling for $950. The yield to maturity is the implied      interest rate for this bond, in this case 9.29% per year:

>>> bond_yield_to_maturity(1000, 0.08, 5, 1, 950)

0.09295327519066632

This function will use a while loop to find the appropriate yield by iteration, i.e., trying many values (for the yield) until it the correct yield (within an acceptable margin of error).

Notes:

Refer to the example from class in which we continue a guessing game until we nd a

solution. Create variables for the upper and lower bounds for the interest rate and use the average of these as a test rate. Calculate the bond price using the test rate.

If the calculated price is below the parameter price, you need to try a higherbond price – by lowering the interest rate. Set the upper bound of the interest rate to be the test     rate, so that you pick a rate that is between the lower bound and the previous test rate .

If the calculated price is above the parameter price, you need try a lowerbond price – by increasing the interest rate.

You should continue your iteration until the calculated bond price is closeenoughto

the actual bond price, i.e., within an acceptable margin of error. Declare a variable to hold the required degree of accuracy, i.e.,

ACCURACY = 0.0001 # iterate until the error is less than $0.0001

and continue iterating until the basolute value of the difference in bond price is less    than this amount of accuracy. Note: the example below uses an accuracy of 0.001, so your results will differ.

Be sure to consider and test for cases where bond prices are above the maturity value,

i.e., where r < 0.

Hints:

When you rst write your function, include a print statement inside your loop to show

the test interest rate and the value of the bond at each iteration of the loop. For example:

>>> bond_yield_to_maturity(100, 0.04, 3, 2, 101.75)

Iteration 0, test_rate = 0.50000000, price = $32.117248 diff = $-69.63 Iteration 1, test_rate = 0.25000000, price = $57.434695 diff = $-44.31 Iteration 2, test_rate = 0.12500000, price = $79.264523 diff = $-22.48 Iteration 3, test_rate = 0.06250000, price = $93.930828 diff = $-7.819 Iteration 4, test_rate = 0.03125000, price = $102.487223 diff = $0.737 Iteration 5, test_rate = 0.04687500, price = $98.096648 diff = $-3.653 Iteration 6, test_rate = 0.03906250, price = $100.262983 diff = $-1.48 Iteration 7, test_rate = 0.03515625, price = $101.367754 diff = $-0.38 Iteration 8, test_rate = 0.03320312, price = $101.925637 diff = $0.175 Iteration 9, test_rate = 0.03417969, price = $101.646235 diff = $-0.10 Iteration 10, test_rate = 0.03369141, price = $101.785821 diff = $0.03 Iteration 11, test_rate = 0.03393555, price = $101.715999 diff = $-0.0 Iteration 12, test_rate = 0.03381348, price = $101.750903 diff = $0.00 Iteration 13, test_rate = 0.03387451, price = $101.733449 diff = $-0.0 Iteration 14, test_rate = 0.03384399, price = $101.742175 diff = $-0.0 Iteration 15, test_rate = 0.03382874, price = $101.746539 diff = $-0.0 Iteration 16, test_rate = 0.03382111, price = $101.748721 diff = $-0.0 Iteration 17, test_rate = 0.03381729, price = $101.749812 diff = $-0.0 Iteration 18, test_rate = 0.03381538, price = $101.750357 diff = $0.00

Iteration 19, test_rate = 0.03381634, price = $101.750084 diff = $0.00 Iteration 20, test_rate = 0.03381681, price = $101.749948 diff = $-0.0 Iteration 21, test_rate = 0.03381658, price = $101.750016 diff = $0.00 Iteration 22, test_rate = 0.03381670, price = $101.749982 diff = $-0.0 Iteration 23, test_rate = 0.03381664, price = $101.749999 diff = $-0.0 0.03381660580635071

This will help you verify that your algorithm is working correctly. Remove the print statement when you are done.

Task 2: Simulating a Bond Auction

40points;individual-only

The US Treasury sells new bonds to investors by offering an auction. Interested investors must submit their bids in advance of a deadline, and the Treasury sells the bonds to investors at the highest possible prices (i.e., lowest yield to maturity) and thus the least interest cost.

The auction announcement specifies the type of security to be sold (e.g., 5-year bonds with a 3% annual coupon rate), and the amount the Treasury is planning to sell (e.g., $500,000 of     maturity value). The potential investors bids must specify the price they are willing to pay per $100 of maturity value (e.g., paying $99.50 per $100 bond in this example would give an        annualized yield-to-maturity of about 3.1088%).

In this task, you will write some functions to create a simple bond auction. To begin, you should download this sample.csv le containing a list of investor’s bids. You will process this le to    determine which bids will be accepted (i.e., those with the highest prices), and the minimum     price that is successful in the auction. The design you should follow includes 3 functions,         described below. You may write additional helper function if you find that useful, but they will    not be graded. Do this entire task in a file called a4task2.py.

1. Write the function collect_bids(filename) to process the data le containing the bids. The data le will be in this format:

bid_id, bid_amount, bid_price

1, 100000, 101.50

2, 100000, 101.25

3, 200000, 100.75

in which the rst row contains the column headers, and each additional row contains three fields: the bid_id which identifies the bidder, the bid_amount (dollar value) of bonds the   this investor would like to buy, and the bid_price that the investor is willing to pay.

Your task in this function is to process the le and return a list containing the bids (i.e., a

list of lists). For example:

For example:

>>> # call the function

>>> bids = collect_bids('./bond_bids.csv')

>>> print(bids) # show the data that was returned

[[1, 100000, 101.5],

[2, 100000, 101.25],

[3, 200000, 100.75],

# ...]

2. Write the function print_bids(bids) to process the a of bids, and produce a beautifully-  formatted table of the bids. In your function, you will process a list containing bids one line at a time.

For each bid (a list of 3 fields), you will separate the elds into separate variables and print with appropriate formatting, i.e., with dollar signs, clean spacing, nicely lined up, etc. For    example:

>>> bids = collect_bids('./bond_bids.csv')

>>> print_bids(bids)

Bid ID

1

2

3

Bid Amount

100000

100000

200000

$

$

$

Price

101.500

101.250

100.750

3. Write the function find_winning_bids(bids, total_offering_fv, c, n, m) that processes a list of bids and determine which are successful in the auction. The         parameters are:

bids, where each bid is a sublist in the form of [bid_id, bid_amount, bid_price], total_offering_fv is the total amount of bonds being sold,

c is the annualized coupon rate,

n is the number of years to maturity for the bonds, and

m is the number of coupon payments per year.

The function must do the following tasks:

sort the bids by bid_price (in descending order).

determine which bids will be accepted, including any partial amounts lled.

nd the auctions clearing_price, which is lowest price at which the auction amount

(total_offering_fv) is sold out.

print out the table showing all bids and the amount sold to each bidder. The amount

sold might be the full bid_amount’, a fraction bid_amount if the entire bid was not filled, or 0 if the bid was unsuccessful.

print out the auction clearing bond price (i.e., the price at which the offering sells out)

and the yield to maturity.

return the list of bids, with the actual amonut sold to each bidder.

Example 1:

This test code:

if __name__ == '__main__':

# read in the bids

bids = collect_bids('./bond_bids.csv')

print("Here are all the bids:")

print_bids(bids)

print()

# process the bids in an auction of $500,000 of 5-year 3% semi-annual

processed_bids = find_winning_bids(bids, 500000, 0.03, 5, 2)

Produces this output:

Here are all Bid ID

1

2

3

4

5

6

7

8

9

10

Here are all Bid ID

9

1

2

4

8

the bids:

Bid Amount           Price

$      100000   $     101.500

$      100000   $     101.250

$      200000   $     100.750

$      400000   $     101.200

$      250000   $     100.900

$      300000   $     100.700

$      120000   $     101.000

$      150000   $     101.200

$      100000   $     101.750

$      350000   $     100.500

of the bids, sorted by price descending:

Bid Amount           Price

$      100000   $     101.750

$      100000   $     101.500

$      100000   $     101.250

$      400000   $     101.200

$      150000   $     101.200

7

5

3

6

10

The auction

4 bids were The auction

$

$

$

$

$

is for $500000.00 of bonds.

successful in the auction.

clearing price was $101.200, i.e., YTM is 0.027415 per year.