Assignment 7
Objective and Overview
Objective: Learn to use the numpy numerical programming toolkit and Monte Carlo simulation. Additional practice with object-oriented programming, class definintions, inheritance, and polymorphism.
Overview: In this assignment, you will implement some classes to simulate stock returns and price movements (task 1) to assist with pricing path-dependent options (task 2). In the first task, you will implement a base class to encapsulate the fundamental data members and common calculations used to simulate stock returns using Monte Carlo simulation. In the second task, you will create subclasses to implement several option pricing algorithms.
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 file that are similar to the ones that we gave you at the top of
a1task1.py
. -
Your functions must have the exact names that we have specified, or we won’t 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., inconvert_from_inches
). -
Each of your functions should include a docstring that describes what your function does and what its inputs are.
-
If a function takes more than one input, you must keep the inputs in the order that we have specified.
-
You should not use any Python features that we have not discussed in class or read about in the textbook.
-
Unless expressly stated, your functions do not need to handle bad inputs – inputs with a type or value that doesn’t correspond to the description of the inputs provided in the problem.
-
Make sure that your functions return the specified 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:
-
You must test each function after you write it. Here are two ways to do so:
- Run your file after you finish 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 file, 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 file, which will save you from having to enter the tests yourself. We have given you an example of one such test in the starter file.
-
You must not leave any
print
statements in the global scope. This will cause an error with the Gradescope autograder. Make sure all of yourprint
statements are inside a function scope or insude theif __name__ == '__main__'
control struture.
NumPy Programming Toolkit
This assignment will require the (free) NumPy toolkit of numeric programming tools.
If you are using Anaconda/Spyder, this package is already installed for you.
If you not using Spyder, you will need to install it yourself. The easiest way
to install this is by running the pip
command at the shell (i.e., the Terminal on Mac).
pip3 install numpy scipy matplotlib pandas
For alternative installation instructions, see: https://scipy.org/install.html
Task 1: Simulating Stock Returns
50 points; individual-only
Monte Carlo Simulation is a mathematical technique in which we use data generated at random to help understand what might occur in some real scenario. It is used in a wide variety of domains to simulate outcomes that follow some known (or assumed) probability distribution. In finance, Monte Carlo methods are used to simulate stock returns, and can be instrumental in pricing some assets for which an analytical pricing formula does not exist.
In this task, you will write a definition for the class MCStockSimulator
, which
encapsulates the data and methods required to simulate stock returns and values. This
class will serve as a base class for option pricing classes (in part 2).
Do this entire task in a file called a7task1.py
.
-
Create the
__init__
and__repr__
methods for the classMCStockSimulator
, such that you can create and print out an object like this:Example:
>>> # initial stock price = $100; 1 year time frame >>> # expected rate of return = 10%; standard deviation = 30%; >>> # 250 discrete time periods per year >>> sim = MCStockSimulator(100, 1, 0.1, 0.3, 250) >>> print(sim) StockSimulator (s=$100.00, t=1.00 (years), r=0.10, sigma=0.30, nper_per_year=250
The data required include:
s
(the current stock price in dollars),
t
(the option maturity time in years),
r
(the annualized rate of return on this stock),
sigma
(the annualized standard deviation of returns),
nper_per_year
(the number of discrete time periods per year) -
Write a method
generate_simulated_stock_returns(self)
on your classMCStockOption
, which will generate and return anp.array
(numpy array) containing a sequence of simulated stock returns over the time periodt
.For example, here is a
MCStockSimulator
for a 1-year time horizon, with 2 discrete periods per year:>>> sim = MCStockSimulator(100, 1, 0.10, 0.30, 2) >>> sim.generate_simulated_stock_returns() array([ 0.10370361, 0.04763965])
Here is a
MCStockSimulator
for a 1-year time horizon, with 4 discrete periods per year:>>> sim = MCStockSimulator(100, 1, 0.10, 0.30, 4) >>> sim.generate_simulated_stock_returns() array([ 0.06111529, -0.03161354, 0.01123988, -0.02747573])
Here is a
MCStockSimulator
for a 0.5-year time horizon, with 2 discrete periods per year:>>> sim = MCStockSimulator(100, 0.5, 0.10, 0.30, 2) >>> sim.generate_simulated_stock_returns() array([ 0.01746703])
Notice that in 0.5 years, it only generates one simulated return (i.e, 2 periods per for 0.5 years is one periodic return).
Finally, here is a 5-year simulation with 250 discrete time periods per year (i.e., 250 stock market trading days per year).
>>> sim = MCStockSimulator(100, 5, 0.10, 0.30, 250) >>> returns = sim.generate_simulated_stock_returns() >>> len(returns) 1250
Algorithm to generate simulated stock returns
One method for creating simulated stock returns is to assume that future returns will follow the same probability distribution as historical returns. Let’s assume that stock returns have historically been approximately normally distributed with a mean
mu
and standard deviationsigma
. We can simiulate the annual rate of return as:where
Z
is a randomly-drawn number from the standard normal distribution. You can draw such a number using the functionnp.random.normal()
.To find a simulated rate of return for an arbitrary discrete time period
dt
, we can use this formula:Where
mu
is the mean historical rate of return on the stock, andsigma
is the historical standard deviation on the stock.Notes/Hints:
-
Each run of
generate_simulated_stock_returns()
will return a new, independent sequence of simulated stock returns. You should not expect to get the same result twice! -
The returns in this sequence represent a simluated run through
t
years, withnper_per_year
discrete steps per year. It might be helpful to create a variabledt = 1/nper_per_year
to represent the length of each discrete time period.
-
-
Write a method
generate_simulated_stock_values(self)
on your classMCStockOption
, which will generate and return anp.array
(numpy array) containing a sequence of stock values, corresponding to a random sequence of stock return.The sequence of stock values is created as follows:
We refer to this sequence of prices as the price path of the stock, i.e., the price of the stock at each discrete time period from now until the end of the simulation. There are
t * nper_per_year
discrete time periods.For example, here is a 1-year simulation with the stock value in each of 4 discrete time periods:
>>> sim = MCStockSimulator(100, 1, 0.10, 0.30, 4) >>> sim.generate_simulated_stock_values() array([ 100., 106.21081853, 99.06516915, 106.82487454, 111.7185901 ])
For example, here is a 2-year simulation with the stock value in each of 24 discrete time periods:
>>> sim = MCStockSimulator(100, 2, 0.10, 0.30, 24) >>> sim.generate_simulated_stock_values() array([ 100. , 98.43464757, 89.06787115, 89.45335537, 98.10990421, 95.47948379, 98.58499305, 102.60564175, 110.89048152, 109.14211213, 101.505116 , 102.75341162, 94.28467862, 95.64829725, 106.66955089, 116.07599088, 108.20518856, 103.25591899, 117.17127503, 101.43353659, 97.12297512, 100.56849565, 98.02435776, 103.12016945, 105.77297333, 110.350575 , 112.5208508 , 121.42911882, 122.11935187, 125.16098769, 129.47382744, 149.55685873, 147.32158875, 153.70553074, 160.91099803, 166.92453169, 161.94170337, 159.82663272, 158.93655807, 144.25364641, 137.70097581, 140.1791159 , 139.74213887, 143.07955822, 134.06674212, 127.83268835, 121.31988325, 131.96440002, 136.10952943])
Notes/Hints:
- You should re-use your
generate_simulated_stock_returns()
to obtain the sequence of returns for the simulation. Next, you will use the returns to create the stock values for the simulation, beginning with the initial stock prices
.
- You should re-use your
-
Write the method
plot_simulated_stock_values(self, num_trials = 1)
, that will generate a plot of ofnum_trials
series of simulated stock returns.num_trials
is an optional parameter; if it is not supplied, the default value of1
will be used.For example, consider this sequence of operations:
>>> sim = MCStockSimulator(100, 2, 0.10, 0.30, 24) >>> sim.plot_simulated_stock_values()
which generates this plot:
We can also generate multiple simulations on a single plot, by passing in the parameter
num_trials
. For example:>>> sim = MCStockSimulator(100, 2, 0.10, 0.30, 250) >>> sim.plot_simulated_stock_values(5)
which generates this plot:
In the above plot, each line represents one simulated price-path over a period of 5 years, with 250 discrete time periods per year.
Notes/Hints:
-
Each run of
plot_simulated_stock_values()
will return a new, independent plot of simulated stock values. You should not expect to get the same result twice! -
You should re-use your
generate_simulated_stock_values()
method to obtain a sequence of stock values for each ofnum_trials
trials. -
Use the
matplotlib
library to generate the plots. -
The
matplotlib plot
method accepts parameters that are of typenumpy.array
.
We can pass in a 2-dimensionalnumpy.array
of y-values, where each y-value corresponds to one x-value. -
The
matplotlib
library will automatically assign colors to each plot line, so you don’t need to.
-
Take a screen shot of your graphs!
The Gradescope autograder cannot display/test your graphs. Instead, we will attempt to run your code manually to test the graphing.
As a backup, please take screen shots of your graphs and save as a single .pdf
file called a8graphs.pdf
and attach this file to Gradescope.
To take a screen shot:
-
On Mac: use the keyboard sequence
Command-Shift-4
, and then drag the cross-hairs to include the region you want to include. The image will be saved to your desktop. Create a Word document and drag your images into the document, then save as.pdf
. -
On Windows: use the keyboard sequence
Ctrl-PrintScreen
, and then paste Create a Word document and paste your images into the document, then save as.pdf
.
Task 2: Pricing Path-Dependent Options
50 points; individual-only
The Black-Scholes method provides the most efficient way to value standard options, such as the European call or put options. However, there exist many exotic options types for which the payoff depends on the price path of the underlying assets, and thus require a technique to simulate the path of a stock price (or other underlying asset) through time.
We will use object-oriented techniques to implement a hierarchy of option classes, extensible to many different kinds of optoins with similar fundamental characteristics such as the underlying stock’s mean rate of return and standard deviation of returns, but with different payoff algorithms (e.g., European, average price, or no-regret options).
Do this task in a file called a7task2.py
. You will need to import the class
MCStockSimulator
from your a7task1.py
file, as well as importing the numpy
module, i.e.,
from a7task1 import MCStockSimulator import numpy as np
-
Write a class definition for the class
MCStockOption
, which inherits fromMCStockSimulator
. This class will encapsulate the idea of a Monte Carlo stock option, and will contain some additional data members( that are not part of classMCStockSimulator
and are required to run stock-price simulations and calculate the option’s payoff. However, this class will not be a concrete option type, and thus will not implement the option’s value algorithm, which differs for each concrete option type.a. Write an
__init__
method that takes the following parameters:
s
, which is the initial stock price
x
, which is the option’s exercise price
t
, which is the time to maturity (in years) for the option
r
, which is the (expected) mean annual rate of return on the underlying stock
sigma
, which is the annual standard deviation of returns on the underlying stock
nper_per_year
, which is the number of discrete time periods per year with which to evaluate the option, and
num_trials
, which is the number of trials to run when calculating the value of this optionThe constructor for
MCStockOption
will need to explicitly call the super class’s constructor to initialize the data attributes of the super class. Only two new data attributes are created in this subclass.b. Write a
__repr__
method to create a nicely formatted printout of theMCStockOption
object, which will be useful for debugging your work.>>> option = MCStockOption(90, 100, 1.0, 0.1, 0.3, 250, 10) >>> print(option) MCStockOption, s=90.00, x=100.00, t=1.00, r=0.10, sigma=0.30, nper_per_year=250, num_trials=10
-
Add the following methods to your class
MCStockOption
:a. the method
value(self)
, which will return the value of the option. This method cannot be concretely implemented in this base class, but will be overridden in each subclass (see below). For now, the methods should print out a message and return 0.Example:
>>> option = MCStockOption(90, 100, 1.0, 0.1, 0.3, 250, 10) >>> option.value() Base class MCStockOption has no concrete implementation of .value(). # print statement 0 # this is the return value
b. the method
stderr(self)
, which will return the standard error of this option’s value. The standard error is calculated asstdev / sqrt(num_trials)
, wherestdev
is the standard deviation of the values obtained from many trials.The standard error can only be calculated after running some trials, and as such it cannot be calculated until we implement the
value(self)
method in the concrete subclasses (explained below). For now, you should use the following method definition in classMCStockOption
:def stderr(self): if 'stdev' in dir(self): return self.stdev / math.sqrt(self.num_trials) return 0
The following notes apply to all remaining parts of this task:
-
For each option type that follows, you will create a separate class definition. If the parameter list to create an object of the sub class is the same as the the parameter list for the super class constructor, it will work automatically for the sub class, i.e., you should not need to implement the constructor (
__init__
), unless you accept additional parameters. -
You will need to implement a new version of the
__repr__
for each subclass (see samples below). -
For each option type that follows, you will implement the option pricing algorithm by overriding the
value(self)
method, with the specific algorithm/formula required by that option type. -
Monte Carlo option pricing is achieved by running many random trials (sepcified by the data attribute `num_trials). The value of the option is the mean result from many trials.
In each trial, you will generate a sequence of simulated stock returns by calling
thegenerate_simulated_stock_values()
method, and use those prices to find the value of the option.Your will also calculate the standard deviation of the results from all trials, and store this value in the data member
self.stdev
. It might be helpful to have these lines of code near the end of yourvalue(self)
method:self.mean = np.mean(trials) self.stdev = np.std(trials)
-
Write a class definition for the class
MCEuroCallOption
which inherits from the base classMCStockOption
.For example:
>>> call = MCEuroCallOption(90, 100, 1, 0.1, 0.3, 100, 1000) >>> print(call) MCEuroCallOption, s=90.00, x=100.00, t=1.00, r=0.10, sigma=0.30, nper_per_year=100, num_trials=1000 >>> call.value() 10.164874441384734 ## your value WILL be different but should be relatively close
Calculating the option value:
The value of the European call option is calculated by:
where St is the value of the underlying stock in the last discrete time period.
Note that each time your execute the
.value()
method, you will get a different result to to the nature of the random trials:>>> call.value() 11.322180528696247 >>> call.value() 10.748354948112402 >>> call.value() 10.695278628009447
The standard error of the option’s value describes how good or bad this estimate is. In this case for a call option value calculated with 1000 random trials, the standard error is quite large:
>>> call.stderr() 0.5787576231663906
We can obtain a better estimate of the option value (i.e., with lower standard error) by increasing the number of trials:
>>> call = MCEuroCallOption(90, 100, 1.0, 0.1, 0.3, 100, 1000) >>> print(call) MCEuroCallOption, s=90.00, x=100.00, t=1.00, r=0.10, sigma=0.30, nper_per_year=100, num_trials=1000 >>> call.value() 11.000330304756181 >>> call.stderr() 0.6023949256312296 >>> # change num_trials from 1,000 to 100,000 >>> call.num_trials = 100000 >>> call.value() # note: this took about 8 seconds to run on my computer 10.512108280184108 >>> call.stderr() 0.05937301178540991
The value of this option given by Black-Scholes is:
>>> bs_call = BSEuroCallOption(100, 100, 1.0, 0.3, 0.10) >>> bs_call.value() 10.51985812604488 # the MC option value was pretty close
We can obtain a closer estimate by further increasing the number of trials, i.e.,
>>> # change num_trials from 1,000 to 1,000,000 >>> call.num_trials = 1000000 >>> call.value() # this calculation took about 1 minutes on my computer. 10.537749946259456 >>> call.stderr() 0.01878190454494842
Notice that using Monte Carlo simulation to calculate the value is very inefficient for European call/put options. However, pricing European call options via our Monte Carlo simulation is a good way to check that our simulation is working correctly, i.e., we can check the value obtained for these options against the values from Black-Scholes.
Here is one more example against which you can test your work:
>>> bs_call = BSEuroCallOption(40, 40, 0.25, 0.3, 0.08) >>> bs_call.value() 2.7847366578216608 >>> call = MCEuroCallOption(40, 40, 0.25, 0.08, 0.30, 100, 100000) >>> print(call) MCEuroCallOption, s=40.00, x=40.00, t=0.25, r=0.08, sigma=0.30, nper_per_year=100, num_trials=100000 >>> call.value() 2.7946173763090427 >>> call.stderr() 0.012950161471655414
-
Write a class definition for the class
MCEuroPutOption
which inherits from the base classMCStockOption
.For example:
>>> put = MCEuroPutOption(100, 100, 1.0, 0.1, 0.3, 100, 1000) >>> print(put) MCEuroPutOption, s=100.00, x=100.00, t=1.00, r=0.10, sigma=0.30, nper_per_year=100, num_trials=1000 >>> put.value() 7.2857299607715076
Calculating the option value:
The value of the European put option is calculated by:
where St is the value of the underlying stock in the last discrete time period.
Note that each time your execute the
.value()
method, you will get a different result to to the nature of the random trials:>>> put.value() 7.1295404189273102 >>> put.value() 6.8666625992759549 >>> put.value() 7.140392750931456 >>> put.value() 7.1207833023244609
The standard error of the option’s value describes how good or bad this estimate is. In this case for a call option value calculated with 1000 random trials, the standard error is quite large:
>>> put.stderr() 0.360437099279606
We can obtain a better estimate of the option value (i.e., with lower standard error) by increasing the number of trials:
>>> put = MCEuroPutOption(100, 100, 1.0, 0.1, 0.3, 100, 100000) >>> print(put) MCEuroPutOption, s=100.00, x=100.00, t=1.00, r=0.10, sigma=0.30, nper_per_year=100, num_trials=100000 >>> put.value() ## this took about 8 seconds on my computer 7.2195765228911499 >>> put.stderr() 0.03564371182285262
The value of this option given by Black-Scholes is:
>>> bs_put = BSEuroPutOption(100, 100, 1.0, 0.3, 0.10) >>> bs_put.value() 7.2178753859826088
Again, we note that Monte Carlo simulation to calculate the value is very inefficient for European call/put options. However, pricing European put options via our Monte Carlo simulation is a good way to check that our simulation is working correctly, i.e., we can check the values obtained for these options against the values from Black-Scholes.
Valuing path-dependent options
-
For a little background reading about path-dependent options, read this page from Wikipedia on Exotic options.
-
For the option types below, there is no precise pricing formula such as Black-Scholes. The prices of these options depend on the price-path through time. These options can be priced exactly using historical data, i.e., at maturity. At any time before maturity, we can only estimate the value of these options by simulating the path of future stock prices.
-
Write a class definition for the class
MCAsianCallOption
which inherits from the base classMCStockOption
. The Asian call option’s payoff the amount by which the average stock price exceeds the option’s exercise price during the option’s lifetime.(The “Asian” or average price option was developed by two British bankers, who just happened to be in Tokyo when “they developed the first commercially used pricing formula for options linked to the average price of crude oil.” - Wikipedia)
Calculating the option value:
The value of the Asian call option (in a single trial) is calculated by:
where S is price-path of the of the underlying stock form now until time
t
.For example:
>>> acall = MCAsianCallOption(100, 100, 1.0, 0.10, 0.30, 100, 1000) >>> print(acall) MCAsianCallOption, s=100.00, x=100.00, t=1.00, r=0.10, sigma=0.30, nper_per_year=100, num_trials=1000 >>> acall.value() 8.7286677639144141 >>> acall.stderr() 0.37251965838780865
We can obtain a better estimate of the option value (i.e., with lower standard error) by increasing the number of trials:
>>> # change num_trials to reduce the standard error: >>> acall.num_trials = 100000 >>> acall.value() 9.082241249588852 >>> acall.stderr() 0.039660682189637385
There is no “exact” right answer, but we can increase the number of trials until the standard error is sufficiently small (e.g., maybe a standard error of $0.01 is “good enough”.)
Here are some additional examples of Asian call options with different parameters:
>>> acall = MCAsianCallOption(35, 30, 1.0, 0.08, 0.25, 100, 100000) >>> acall.value() 6.10676499229242 >>> acall.stderr() 0.014791094213907266 >>> acall = MCAsianCallOption(35, 40, 1.0, 0.08, 0.40, 100, 100000) >>> acall.value() 1.9336597090613712 >>> acall.stderr() 0.013909777807322249
-
Write a class definition for the class
MCAsianPutOption
which inherits from the base classMCStockOption
. The Asian put option’s payoff the amount by which the option’s exercise price exceeds average stock price during the option’s lifetime.Calculating the option value:
The value of the Asian put option (in a single trial) is calculated by:
where S is price-path of the of the underlying stock form now until time
t
.For example:
>>> aput = MCAsianPutOption(100, 100, 1.0, 0.10, 0.30, 100, 1000) >>> print(aput) MCAsianPutOption, s=100.00, x=100.00, t=1.00, r=0.10, sigma=0.30, nper_per_year=100, num_trials=1000 >>> aput.value() 4.3344210537230685 >>> aput.stderr() 0.2126994125989547
We can obtain a better estimate of the option value (i.e., with lower standard error) by increasing the number of trials:
>>> # change num_trials to reduce the standard error: >>> aput.num_trials = 100000 >>> aput.value() 4.3828743625359667 >>> aput.stderr() 0.022065988231296036
There is no “exact” correct value, but we can increase the number of trials until the standard error is sufficiently small (e.g., maybe a standard error of $0.01 is “good enough”.)
Here are some additional examples of Asian put options with different parameters:
>>> aput = MCAsianPutOption(35, 30, 1.0, 0.08, 0.25, 100, 100000) >>> aput.value() 0.17081451092121083 >>> aput.stderr() 0.0021427462876315935 >>> aput = MCAsianPutOption(35, 40, 1.0, 0.08, 0.40, 100, 100000) >>> aput.value() 5.202096070272916 >>> aput.stderr() 0.01579490624224986
-
Write a class definition for the class
MCLookbackCallOption
which inherits from the base classMCStockOption
. The look-back call option’s payoff the amount by which the option’s exercise price exceeds maximum stock price during the option’s lifetime.Calculating the option value:
The value of the look-back call option (in a single trial) is calculated by:
where S is price-path of the of the underlying stock form now until time
t
.For example:
>>> lcall = MCLookbackCallOption(100, 100, 1.0, 0.10, 0.30, 100, 1000) >>> print(lcall) MCLookbackCallOption, s=100.00, x=100.00, t=1.00, r=0.10, sigma=0.30, nper_per_year=100, num_trials=1000 >>> lcall.value() 27.623315806983594 >>> lcall.stderr() 0.7849042509114783
We can obtain a better estimate of the option value (i.e., with lower standard error) by increasing the number of trials:
>>> # change num_trials to reduce the standard error: >>> lcall.num_trials = 100000 >>> lcall.value() 28.25988421663273 >>> lcall.stderr() 0.07978179212787108
There is no “exact” right answer, but we can increase the number of trials until the standard error is sufficiently small (e.g., maybe a standard error of $0.01 is “good enough”.)
Here are some additional examples of look-back call options with different parameters:
>>> lcall = MCLookbackCallOption(35, 30, 1.0, 0.08, 0.25, 100, 100000) >>> lcall.value() 12.77950317693695 >>> lcall.stderr() 0.022307140359480636 >>> lcall = MCLookbackCallOption(35, 40, 1.0, 0.08, 0.40, 100, 100000) >>> lcall.value() 8.794892213218377 >>> lcall.stderr() 0.03689429324794948
-
Write a class definition for the class
MCLookbackPutOption
which inherits from the base classMCStockOption
. The look-back put option’s payoff the amount by which the option’s exercise price exceeds minimum stock price during the option’s lifetime.Calculating the option value:
The value of the look-back call option (in a single trial) is calculated by:
where S is price-path of the of the underlying stock form now until time
t
.For example:
>>> lput = >>> print(lput) MCLookbackPutOption, s=100.00, x=100.00, t=1.00, r=0.10, sigma=0.30, nper_per_year=100, num_trials=1000 >>> lput.value() 14.968295917890794 >>> lput.stderr() 0.3669254592774948
We can obtain a better estimate of the option value (i.e., with lower standard error) by increasing the number of trials:
>>> # change num_trials to reduce the standard error: >>> lput.num_trials = 100000 >>> lput.value() 15.173249621749418 >>> lput.stderr() 0.03691269486451156
There is no “exact” right answer, but we can increase the number of trials until the standard error is sufficiently small (e.g., maybe a standard error of $0.01 is “good enough”.)
Here are some additional examples of look-back put options with different parameters:
>>> lput = MCLookbackPutOption(35, 30, 1.0, 0.08, 0.25, 100, 100000) >>> lput.value() 1.473450162184218 >>> lput.stderr() 0.007596162700364556 >>> lput = MCLookbackPutOption(35, 40, 1.0, 0.08, 0.40, 100, 100000) >>> lput.value() 12.28338712431232 >>> lput.stderr() 0.016902847424762495
Submitting Your Work
Use the link to GradeScope (left) to submit your work.
Be sure to name your files correctly!
Under the heading for Assignment 7, attach these 3 required files:
a7task1.py
, a7task2.py
and a8graphs.pdf
When you upload the files, the autograder will test your program.
Notes:
- You may resubmit multiple times, but only the last submission will be graded.
Warnings about Submissions
-
Make sure to use these exact file names, or Gradescope will not accept your files. If Gradescope reports that a file does not have the correct name, you should rename the file using the name listed in the assignment page.
-
If you make any last-minute changes to one of your Python files (e.g., adding additional comments), you should run the file in Spyder after you make the changes to ensure that it still runs correctly. Even seemingly minor changes can cause your code to become unrunnable.
-
If you submit an unrunnable file, Gradescope will accept your file, but it will not be able to auto-grade it. If time permits, you are strongly encouraged to fix your file and resubmit. Otherwise, your code will fail most if not all of our tests.
Important note regarding test cases and Gradescope:
-
You must test each function after you write it. Here are two ways to do so:
- Run your file after you finish 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 file, inside the
if __name__ == '__main__'
control structure. For example:if __name__ == '__main__': print("mystery(6,7) returned", mystery(6,7))
These tests will be called every time that you run the file, which will save you from having to enter the tests yourself. We have given you an example of one such test in the starter file.
-
You must not leave any
print
statements in the global scope. This will cause an error with the Gradescope autograder. Make sure all of yourprint
statements are inside a function scope or insude theif __name__ == '__main__'
control structure.