Option Pricing Using Recursion; Please Help!!

Hi guys,

Here is the code I am working with. This is supposed to price american asian options using recursion and a trinomial tree. The idea behind american asian options is that the option can be executed at any time and the value of the underlying asset is averaged over the path of the price. Therefore the price is not simply determined by its current price but by the average of the price over the entire path of the stock. This is a trinomial representation so it would look something like this:

http://www.iijournals.com/na101/home/literatum/publisher/invest/journals/content/jod/2009/jod.2009.16.4/jod.2009.16.4.072/production/images/small/fig1.gif

when drawn out.

I *think* that my issue is with the averaging of the path. I will post the code that I have currently and then the correct output as supplied by my prof.

My code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <iostream>
#include <iomanip>
#include <cmath>
#include <fstream>
#include <cstdlib>
#include <algorithm>

using namespace std;

float up_factor, uptick_prob, downtick_prob, notick_prob, risk_free_rate, strike_price;
float initial_stock_price, sum_stock_price, expiration_time, volatility, R, T,A;
int no_of_divisions;

float max(float a, float b) {
	return (b < a )? a:b;
} 

float american_asian_call_option(int k, int i, float current_stock_price, float current_avg_stock_price) {
	
	if (k == no_of_divisions)

		return max(0.0, (((current_avg_stock_price)/(k+1)) - strike_price));
	else 
		//cout << k<<"\t" << i << "\t" << current_stock_price<< "\t" << current_avg_stock_price<<"\t"<<current_avg_stock_price/(k+1) <<"\t"<< (current_avg_stock_price+current_stock_price)/(k+2)<< endl;

		return max((((current_avg_stock_price)/(k+1)) - strike_price),

				(uptick_prob*american_asian_call_option(k+1,i+1,current_stock_price*up_factor,(((current_avg_stock_price)+(current_stock_price*up_factor)))) + 

				notick_prob*american_asian_call_option(k+1,i,current_stock_price,(current_avg_stock_price+(current_stock_price))) +

				 downtick_prob*american_asian_call_option(k+1,i-1,current_stock_price/up_factor,(current_avg_stock_price + (current_stock_price/up_factor))))/R);

}

float american_asian_put_option(int k, int i, float current_stock_price, float current_avg_stock_price) {
	


	if (k == no_of_divisions)

		return max(0.0, strike_price - ((current_avg_stock_price)/(k+1)));

	else 
		//cout << k<<"\t" << i << "\t" << current_stock_price<< "\t" << current_avg_stock_price<<"\t"<< (current_avg_stock_price)/(k+1)<< endl;

		return max((strike_price - ((current_avg_stock_price)/(k+1))),

				(uptick_prob*american_asian_put_option(k+1,i+1,current_stock_price*up_factor,((current_avg_stock_price)+(current_stock_price*up_factor)))+ 

				 notick_prob*american_asian_put_option(k+1,i,current_stock_price,(current_avg_stock_price+(current_stock_price))) +

				 downtick_prob*american_asian_put_option(k+1,i-1,current_stock_price/up_factor,(current_avg_stock_price + (current_stock_price/up_factor))))/R);
}

int main (int argc, char* argv[])
{
	
//	sscanf (argv[1], "%f", &expiration_time);
//	sscanf (argv[2], "%d", &no_of_divisions);
//	sscanf (argv[3], "%f", &risk_free_rate);
//	sscanf (argv[4], "%f", &volatility);
//	sscanf (argv[5], "%f", &initial_stock_price);
//	sscanf (argv[6], "%f", &strike_price);

	cin >> no_of_divisions;
		expiration_time = .5;
		risk_free_rate = .08; 
		volatility = .3; 
		initial_stock_price= 60; 
		strike_price = 50;
	
		
	up_factor = exp(volatility*sqrt(2*(expiration_time/((float) no_of_divisions))));

	R = exp(risk_free_rate*expiration_time/((float) no_of_divisions));
	uptick_prob = pow(((sqrt(R) - (1/sqrt(up_factor)))/(sqrt(up_factor)-(1/sqrt(up_factor)))),2);
	downtick_prob = pow(((sqrt(up_factor)-sqrt(R))/(sqrt(up_factor)-(1/sqrt(up_factor)))),2);
	notick_prob = 1-uptick_prob-downtick_prob;
	cout << "Recursive Trinomial American Asian Option Pricing" << endl;
	cout << "Expiration Time (Years) = " << expiration_time << endl;
	cout << "Number of Divisions = " << no_of_divisions << endl;
	cout << "Risk Free Interest Rate = " << risk_free_rate << endl;
	cout << "Volatility (%age of stock value) = " << volatility*100 << endl;
	cout << "Initial Stock Price = " << initial_stock_price << endl;
	cout << "Strike Price = " << strike_price << endl;
	cout << "--------------------------------------" << endl;
	cout << "Up Factor = " << up_factor << endl;
	cout << "Uptick Probability = " << uptick_prob << endl;
	cout << "Notick Probability = " << notick_prob << endl;
	cout << "Downtick Probability = " << downtick_prob << endl;
	cout << "--------------------------------------" << endl;
	cout<<endl;
	double call_price = american_asian_call_option(0,0, initial_stock_price, initial_stock_price);
	cout << "Trinomial Price of an American Asian Call Option = " << call_price << endl;
	double put_price = american_asian_put_option(0, 0, initial_stock_price, initial_stock_price);
	cout << "Trinomial Price of an American Asian Put Option = " << put_price << endl;
}


The correct output when no_of_divisions =20 is:

**reiteration of inputs**
1
2
3
4
5
6
7
Up Factor = 1.06938
Uptick Probability = 0.25657
Notick Probability = 0.499915
Downtick Probability = 0.243515    //all of this is correct in my code already
--------------------------------------
Trinomial Price of an American-Asian Call option = 12.3626
Trinomial Price of an American-Asian Put option = 0.148442


I have the user inputting the no_of_divisions so that smaller number of divisions can be used to check outputs. The correct output as provided by my prof. above is after 20 divisions which takes a little while due to the recursion. If you are trying to help me but don't want to use 20 divisions then the output should be a little smaller for the call and put option something like

for no_of_divisions = 5:
price of call ~= 12.15
price of put ~= 0.125

I truly appreciate any help or suggestions that you can provide. I am BEYOND frustrated with this code. I have been tinkering with it for ages and have been unable to comeup with the same output as my prof. I believe I am very close but I don't have it quite yet.

Again I think the error is most likely in how I am averaging the price over the paths because I am not averaging it in the intermediate paths but only at the end.

Thanks for your help and suggestions!!

Last edited on
Any thoughts or suggestions at all would really help me. I really need new perspective at this point.... Don't hesitate to chime in even if you don't know for sure or haven't checked!!
I haven't stepped through the code yet, but aren't you taking the average of an average in your recursion? I'd guess that's a no-no.
I don't think I am because I have labeled the fourth spot in the recursion as "current_avg_stock_price" but it should really be named "sum_of_current_path" in order to accurately reflect what it is. If you compile the code *wink wink* and just run it with three divisions and get rid of the comments on the cout lines then you can see that that part of the code is just summing the current_stock_price.

Unfortunately I think I have found that this is not the correct way to do it. I need to actually be holding the actual average of the given stock price and its past path but I don't have any idea how to do that. I thought about something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
float american_asian_call_option(int k, int i, float current_stock_price, float current_avg_stock_price) {
	
	if (k == no_of_divisions)

		return max(0.0, (((current_avg_stock_price)) - strike_price));
	else 
//cout << k<<"\t" << i << "\t" << current_stock_price<< "\t" << current_avg_stock_price<<"\t"<<current_avg_stock_price/(k+1) <<"\t"<< (current_avg_stock_price+current_stock_price)/(k+2)<< endl;

		return max((((current_avg_stock_price)) - strike_price),

(uptick_prob*american_asian_call_option(k+1,i+1,current_stock_price*up_factor,(((current_avg_stock_price)+(current_stock_price*up_factor))/(k+1))) + 

notick_prob*american_asian_call_option(k+1,i,current_stock_price,(current_avg_stock_price+(current_stock_price))/(k+1)) +

 downtick_prob*american_asian_call_option(k+1,i-1,current_stock_price/up_factor,(current_avg_stock_price + (current_stock_price/up_factor))/(k+1)))/R);


But this does not hold the average value because I am dividing the current_avg_stock_price by k+1 way to many times throughout the function...

I was thinking that I need to pass the current_avg_stock_price by reference but I am quite lost in actually implementing this...
Last edited on
By "its past path" do you mean the history of the stock price through each iteration? If so, what about keeping it in a vector? Then you can use your position indicator (k I believe) to retrieve it.

I'm starting to tear down the code, but can't see the purpose of i. I see it passed around, but not used anywhere. Is it a relic of something else?

If the explanation of i is too lengthy, don't worry about answering. I'll ignore it for now.

After rearranging your code (I switched everything to local variables and parameters to make things easier for me to follow), I'm now ready to step through it. I'll watch the current_avg_stock_price and am sure I'll have a better understanding of what you are attempting to accomplish when done.

BTW: my non-global-variable code (if I didn't introduce any bugs):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <iostream>
#include <iomanip>
#include <cmath>
#include <fstream>
#include <cstdlib>
#include <algorithm>

using namespace std;

struct probabilities {
	float uptick_prob;
	float notick_prob;
	float downtick_prob;
};

float max(float a, float b) {
	return (b < a )? a:b;
}

float american_asian_call_option(int k, int i, float current_stock_price, float current_avg_stock_price, float up_factor, float R, probabilities probs, int no_of_divisions, float strike_price) {

	if (k == no_of_divisions)
		return max(0.0, (((current_avg_stock_price)/(k+1)) - strike_price));
	else
		return max((((current_avg_stock_price)/(k+1)) - strike_price),
				(probs.uptick_prob*american_asian_call_option(k+1,i+1,current_stock_price*up_factor,(((current_avg_stock_price)+(current_stock_price*up_factor))), up_factor, R, probs, no_of_divisions, strike_price) +
				probs.notick_prob*american_asian_call_option(k+1,i,current_stock_price,(current_avg_stock_price+(current_stock_price)), up_factor, R, probs, no_of_divisions, strike_price) +
				 probs.downtick_prob*american_asian_call_option(k+1,i-1,current_stock_price/up_factor,(current_avg_stock_price + (current_stock_price/up_factor)), up_factor, R, probs, no_of_divisions, strike_price))/R);
}

float american_asian_put_option(int k, int i, float current_stock_price, float current_avg_stock_price, float up_factor, float R, probabilities probs, int no_of_divisions, float strike_price) {

	if (k == no_of_divisions)
		return max(0.0, strike_price - ((current_avg_stock_price)/(k+1)));
	else
		return max((strike_price - ((current_avg_stock_price)/(k+1))),
				(probs.uptick_prob*american_asian_put_option(k+1,i+1,current_stock_price*up_factor,((current_avg_stock_price)+(current_stock_price*up_factor)), up_factor, R, probs, no_of_divisions, strike_price)+
				 probs.notick_prob*american_asian_put_option(k+1,i,current_stock_price,(current_avg_stock_price+(current_stock_price)), up_factor, R, probs, no_of_divisions, strike_price) +
				 probs.downtick_prob*american_asian_put_option(k+1,i-1,current_stock_price/up_factor,(current_avg_stock_price + (current_stock_price/up_factor)), up_factor, R, probs, no_of_divisions, strike_price))/R);
}

int main (int argc, char* argv[])
{
	int no_of_divisions;
	float expiration_time = .5;
	float risk_free_rate = .08;
	float volatility = .3;
	float initial_stock_price= 60;
	float strike_price = 50;
	probabilities probs;

	cin >> no_of_divisions;
	float up_factor = exp(volatility*sqrt(2*(expiration_time/((float) no_of_divisions))));
	float R = exp(risk_free_rate*expiration_time/((float) no_of_divisions));
	probs.uptick_prob = pow(((sqrt(R) - (1/sqrt(up_factor)))/(sqrt(up_factor)-(1/sqrt(up_factor)))),2);
	probs.downtick_prob = pow(((sqrt(up_factor)-sqrt(R))/(sqrt(up_factor)-(1/sqrt(up_factor)))),2);
	probs.notick_prob = 1-probs.uptick_prob-probs.downtick_prob;
	
	cout << "Recursive Trinomial American Asian Option Pricing" << endl;
	cout << "Expiration Time (Years) = " << expiration_time << endl;
	cout << "Number of Divisions = " << no_of_divisions << endl;
	cout << "Risk Free Interest Rate = " << risk_free_rate << endl;
	cout << "Volatility (%age of stock value) = " << volatility*100 << endl;
	cout << "Initial Stock Price = " << initial_stock_price << endl;
	cout << "Strike Price = " << strike_price << endl;
	cout << "--------------------------------------" << endl;
	cout << "Up Factor = " << up_factor << endl;
	cout << "Uptick Probability = " << probs.uptick_prob << endl;
	cout << "Notick Probability = " << probs.notick_prob << endl;
	cout << "Downtick Probability = " << probs.downtick_prob << endl;
	cout << "--------------------------------------" << endl;
	cout<<endl;
	
	double call_price = american_asian_call_option(0,0, initial_stock_price, initial_stock_price, up_factor, R, probs, no_of_divisions, strike_price);
	cout << "Trinomial Price of an American Asian Call Option = " << call_price << endl;
	double put_price = american_asian_put_option(0, 0, initial_stock_price, initial_stock_price, up_factor, R, probs, no_of_divisions, strike_price);
	cout << "Trinomial Price of an American Asian Put Option = " << put_price << endl;
	
	return 0;
}
To address in order:

I have to do this using recursion because that is the assignment :(

Because of the recursion requirement I am not sure how to implement building a vector as it would not follow a great path to do such a thing.

This is how the recursion path works from my understanding, using three divisions, lets say I am labeling nodes here:


' ' ' '' '3

' ' 2 '' 4

1 '' 6 ''5

' ' 8' ' '7

' ' ' ''' '9

The recursion gives you the value for
1 -> 2 ->3, 4, 5

1->6->4,5,7

1->8->5,7,9

I dont think I could build vectors with something like that that are actually correct. ( also from the way my prof talked about this code it shouldn't take much more than 1 or 2 MAX more values,outside of k, i and current_stock_price, to pass through the recursive function in order to get the right values back.

You are correct that i currently has no purpose. It can be used however to check the code because i and k together almost uniquely map out the nodes and where you were at and they give you info on the path taken. Also this is a canabilized code originally from my prof that used i but because of the complexity of the pricing of this option you cannot use i to price it...

So just to reiterate the idea of the averaging the path look at the following example of a simpler version of the code:

So with this function:

1
2
3
4
5
6
7
8
9
10
11
float recursive_function(int k, int i, float price, float avg_price){

      if(k=10)

           return max(0,50-avg_price)

      else
           return max((0, 50 - avg_price),
                   (0.53*recursive_function(k+1,i+1,price*1.1, (avg_price +price*1.1)/(k+1))+
                     0.47*recursive_function(k+1,i-1,price/1.1, (avg_price + price/1.1)/(k+1))
}


The output I want would be this: (this is NOT the output i actually get but this is what I am aiming for)
1
2
3
4
5
6
7
recursive_function(0, 0,60,60 )
	recursive_function(1, 1, 66,63)
		recursive_function(2, 2, 72.6,66.2)
		recursive_function(2, 0, 60, 62)
	recursive_function(1, -1, 54.54, 57.27)
		recursive_function(2, 0, 60, 58.18)
		recursive_function(2, -2,49.58,54.07)


This will be an example of 2 paths that go to the same place but have different averages
so setting up a bit of a chart for easy reading:

k i Current_price avg_price_over_path

0 0 60 60
1 1 66 63
2 0 60 62 (this is at node 5 from above traveling from 1->2->5)

0 0 60 60
1 -1 54.54 57.27
2 0 60 58.18 ( this is also node 5 but traveling from 1->8->5)

The code I have currently (first post) gets these values correctly but it does NOT hold the correct value in the recursive function ( it just holds a sum of the prices over any given path) as I need it to in order to get the correct return from the
(uptick*function + notick*funtion + downtick*function.

Does that explain what I mean by averaging the path? I can try to explain better if this is confusing or has a flaw or two.




Last edited on
Any new ideas?
@JMJatlanta have you had any luck by chance?
Here is my most recent attempt but it is a little bit off unfortunately:

1
2
3
4
5
6
7
8
9
10
float american_asian_call_option(int k, int i, float current_stock_price, float sum_stock_price, float current_avg_stock_price) {
	if (k == no_of_divisions)
		return max(0.0, (((current_avg_stock_price)) - strike_price));
	else 
		cout << k<<"\t" << i << "\t" << current_stock_price<< "\t" << current_avg_stock_price<<"\t" <<sum_stock_price<<"\t"<< sum_stock_price/(k+1)<< endl;
		return max((((current_avg_stock_price)) - strike_price),
		(uptick_prob*american_asian_call_option(k+1,i+1,current_stock_price*up_factor,((sum_stock_price)+(current_stock_price*up_factor)),sum_stock_price/(k+1)) + 
		 notick_prob*american_asian_call_option(k+1,i,current_stock_price,(sum_stock_price+(current_stock_price)), sum_stock_price/(k+1)) +
		 downtick_prob*american_asian_call_option(k+1,i-1,current_stock_price/up_factor,(sum_stock_price + (current_stock_price/up_factor)),sum_stock_price/(k+1)))/R);
}


Can anybody explain why my current_avg_stock_price is not the same as sum_stock_price/(k+1) when I cout those values?

From my understanding of the function every time it pass around it should insert the sum/(k+1) as the current_avg_stock_price value.

JMJatlanta come back and saving me from this misery!!!
Last edited on
Now I have this which is closer but not quite there:

1
2
3
4
5
6
7
8
9
10
11
float american_asian_call_option(int k, int i, float current_stock_price, float sum_stock_price, float current_avg_stock_price) {
	if (k == no_of_divisions)
		return max(0.0, (((current_avg_stock_price)) - strike_price));
	else 
		//cout << k<<"\t" << i << "\t" << current_stock_price<< "\t" << current_avg_stock_price<<"\t" <<sum_stock_price<<"\t"<< sum_stock_price/(k+1)<< endl;
		return max((((current_avg_stock_price)) - strike_price),

		(uptick_prob*american_asian_call_option(k+1,i+1,current_stock_price*up_factor,((sum_stock_price)+(current_stock_price*up_factor)),(initial_stock_price*up_factor+sum_stock_price/(k+1))/2) + 
		 notick_prob*american_asian_call_option(k+1,i,current_stock_price,(sum_stock_price+(current_stock_price)),(initial_stock_price+sum_stock_price/(k+1))/2) +
		 downtick_prob*american_asian_call_option(k+1,i-1,current_stock_price/up_factor,(sum_stock_price + (current_stock_price/up_factor)),((initial_stock_price/up_factor) +sum_stock_price/(k+1))/2))/R);
}


In the last spot of the recursion function I need to only have the initial_stock_price be added in once but I can't figure out how to make it add the first time with the appropriate multiple and then not be in the function.
Anyone have any interest in trying to work this B**ch of a code out with me???

Please?
Sorry to leave you hanging. I'm working on this in my free time. Unfortunately, not only does my employer expect me here on time, they expect me to work too!

I haven't stepped through your new code yet, but will try it out this morning...

Okay, I'm stepping through your code. I think we need to do this on paper first. I'm only using 3 for no_of_divisions

First call:
0, 0, 60, 60, 60
Second call:
1, 1, 71.3465958, 131.346588, 65.6732941
Third call:
2, 2, 84.8389435, 216.185532, 68.5099411

Notice on the 3rd call, if you take your 3rd parameter and divide by k+1, you get 72.0618, not 68.5099411

So lets go back to your 2nd call and see how you computed that parameter. The code said (initial_stock_price*up_factor+sum_stock_price/(k+1))/2

You took the initial stock price (60) and multiplied by the up_factor (1.18910992) to get 71.3466

You took the sum_stock_price (131.346588) and divided by k+1 (2) to get 65.6733.

Add the two and get 137.0199.

Divide by two and get 68.51 (my calculator rounds a bit so my answer is slightly off from what my debugger says).

I think where your problem lays is the fact that you are gathering a number and dividing by two. In the process of doing that, you are taking a derivative of an average and averaging it.

While I don't completely understand your pricing model, I hope I'm leading you to an answer, and not off into the weeds.

On a side note: If you haven't already found it,

http://wilmott.com/index.cfm?forumid=1

especially

http://wilmott.com/categories.cfm?catid=10
Last edited on
So I get the correct outputs at each step (as far as I can tell) from the following code but I do not get the correct final answer when I run it for 20 divisions. My prof. has an output of 12.3626 and I get 12.3492. When I run through a 3 division iteration like you have above, though, it seems like I have the correct outputs... I am beginning to wonder if my professor has put an incorrect answer out or if there may be some rounding error or something else that I am running into.

1
2
3
4
5
6
7
8
9
10
11
float american_asian_call_option(int k, int i, float current_stock_price,float sum_stock_price, float current_avg_stock_price) {
	if (k == no_of_divisions)
		return max(0.0, (current_avg_stock_price - strike_price));
	else 
		cout << k<<"\t" << i << "\t" << current_stock_price<< "\t" << current_avg_stock_price<<"\t" <<sum_stock_price<<"\t"<< sum_stock_price/(k+1)<< endl;
		return max((current_avg_stock_price - strike_price),

		(uptick_prob*american_asian_call_option(k+1,  i+1,  current_stock_price*up_factor,   (sum_stock_price + current_stock_price*up_factor), (sum_stock_price + current_stock_price*up_factor)/(k+2)) + 
		 notick_prob*american_asian_call_option(k+1,  i,    current_stock_price,             (sum_stock_price + current_stock_price),           (sum_stock_price + current_stock_price)/(k+2)) +
	       downtick_prob*american_asian_call_option(k+1,  i-1,  current_stock_price/up_factor,   (sum_stock_price + current_stock_price/up_factor), (sum_stock_price + current_stock_price/up_factor)/(k+2)))/R);
}


Last edited on
Another thing I've been considering is how the uptick_prob, notick_prob and downtick_prob are affecting the overall output value and what is a way to make sure that they are working correctly?
I have also noticed that my values for the put option (the second recursive code) is a bit further from the correct answer than the call option is. With the put option I get a value of 0.113445 when it should be 0.148442.
Thanks for all your help JMJatlanta. The code has actually been right for a while with a few incorrect changes in the middle. I realized that my professor began his averaging after the first iteration as apposed to beginning with the first iteration and of course he did not specify any of this to me but the code works fine so that's that.
Topic archived. No new replies allowed.