| 59 | | [TestClass()] |
|---|
| 60 | | class T_AmericanOption |
|---|
| 61 | | { |
|---|
| 62 | | public static YieldTermStructure flatRate(Date today, Quote forward, DayCounter dc) |
|---|
| 63 | | { |
|---|
| 64 | | //return new YieldTermStructure(new FlatForward(today, new Handle<Quote>(forward), dc)); |
|---|
| 65 | | return null; |
|---|
| 66 | | } |
|---|
| 67 | | |
|---|
| 68 | | public static YieldTermStructure flatRate(Date today, double forward, DayCounter dc) |
|---|
| 69 | | { |
|---|
| 70 | | //return flatRate(today, boost.shared_ptr<Quote>(new SimpleQuote(forward)), dc); |
|---|
| 71 | | return null; |
|---|
| 72 | | } |
|---|
| 73 | | |
|---|
| 74 | | [TestMethod()] |
|---|
| 75 | | public void testBaroneAdesiWhaleyValues() |
|---|
| 76 | | { |
|---|
| 77 | | AmericanOptionData[] values = { |
|---|
| 78 | | new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.10, 0.15, 0.0206) , |
|---|
| 79 | | new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.15, 1.8771) , |
|---|
| 80 | | new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.15, 10.0089) , |
|---|
| 81 | | new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.10, 0.25, 0.3159) , |
|---|
| 82 | | new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.25, 3.1280) , |
|---|
| 83 | | new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.25, 10.3919) , |
|---|
| 84 | | new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.10, 0.35, 0.9495) , |
|---|
| 85 | | new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.35, 4.3777) , |
|---|
| 86 | | new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.35, 11.1679) , |
|---|
| 87 | | new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.50, 0.15, 0.8208) , |
|---|
| 88 | | new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.15, 4.0842) , |
|---|
| 89 | | new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.15, 10.8087) , |
|---|
| 90 | | new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.50, 0.25, 2.7437) , |
|---|
| 91 | | new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.25, 6.8015) , |
|---|
| 92 | | new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.25, 13.0170) , |
|---|
| 93 | | new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.50, 0.35, 5.0063) , |
|---|
| 94 | | new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.35, 9.5106) , |
|---|
| 95 | | new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.35, 15.5689) , |
|---|
| 96 | | new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.10, 0.15, 10.0000) , |
|---|
| 97 | | new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.10, 0.15, 1.8770) , |
|---|
| 98 | | new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.10, 0.15, 0.0410) , |
|---|
| 99 | | new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.10, 0.25, 10.2533) , |
|---|
| 100 | | new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.10, 0.25, 3.1277) , |
|---|
| 101 | | new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.10, 0.25, 0.4562) , |
|---|
| 102 | | new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.10, 0.35, 10.8787) , |
|---|
| 103 | | new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.10, 0.35, 4.3777) , |
|---|
| 104 | | new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.10, 0.35, 1.2402) , |
|---|
| 105 | | new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.50, 0.15, 10.5595) , |
|---|
| 106 | | new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.50, 0.15, 4.0842) , |
|---|
| 107 | | new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.50, 0.15, 1.0822) , |
|---|
| 108 | | new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.50, 0.25, 12.4419) , |
|---|
| 109 | | new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.50, 0.25, 6.8014) , |
|---|
| 110 | | new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.50, 0.25, 3.3226) , |
|---|
| 111 | | new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.50, 0.35, 14.6945) , |
|---|
| 112 | | new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.50, 0.35, 9.5104) , |
|---|
| 113 | | new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.50, 0.35, 5.8823)}; |
|---|
| 114 | | |
|---|
| 115 | | Date today = Date.Today; |
|---|
| 116 | | DayCounter dc = new Actual360(); |
|---|
| 117 | | SimpleQuote spot = new SimpleQuote(0.0); |
|---|
| 118 | | SimpleQuote qRate = new SimpleQuote(0.0); |
|---|
| 119 | | YieldTermStructure qTS = flatRate(today, qRate, dc); |
|---|
| 120 | | |
|---|
| 121 | | |
|---|
| 122 | | |
|---|
| 123 | | } |
|---|
| | 58 | [TestClass()] |
|---|
| | 59 | public class T_AmericanOption { |
|---|
| | 60 | |
|---|
| | 61 | /* The data below are from |
|---|
| | 62 | An Approximate Formula for Pricing American Options |
|---|
| | 63 | Journal of Derivatives Winter 1999 |
|---|
| | 64 | Ju, N. |
|---|
| | 65 | */ |
|---|
| | 66 | AmericanOptionData[] juValues = new AmericanOptionData[] { |
|---|
| | 67 | // type, strike, spot, q, r, t, vol, value, tol |
|---|
| | 68 | // These values are from Exhibit 3 - Short dated Put Options |
|---|
| | 69 | new AmericanOptionData( Option.Type.Put, 35.00, 40.00, 0.0, 0.0488, 0.0833, 0.2, 0.006 ), |
|---|
| | 70 | new AmericanOptionData( Option.Type.Put, 35.00, 40.00, 0.0, 0.0488, 0.3333, 0.2, 0.201 ), |
|---|
| | 71 | new AmericanOptionData( Option.Type.Put, 35.00, 40.00, 0.0, 0.0488, 0.5833, 0.2, 0.433 ), |
|---|
| | 72 | |
|---|
| | 73 | new AmericanOptionData( Option.Type.Put, 40.00, 40.00, 0.0, 0.0488, 0.0833, 0.2, 0.851 ), |
|---|
| | 74 | new AmericanOptionData( Option.Type.Put, 40.00, 40.00, 0.0, 0.0488, 0.3333, 0.2, 1.576 ), |
|---|
| | 75 | new AmericanOptionData( Option.Type.Put, 40.00, 40.00, 0.0, 0.0488, 0.5833, 0.2, 1.984 ), |
|---|
| | 76 | |
|---|
| | 77 | new AmericanOptionData( Option.Type.Put, 45.00, 40.00, 0.0, 0.0488, 0.0833, 0.2, 5.000 ), |
|---|
| | 78 | new AmericanOptionData( Option.Type.Put, 45.00, 40.00, 0.0, 0.0488, 0.3333, 0.2, 5.084 ), |
|---|
| | 79 | new AmericanOptionData( Option.Type.Put, 45.00, 40.00, 0.0, 0.0488, 0.5833, 0.2, 5.260 ), |
|---|
| | 80 | |
|---|
| | 81 | new AmericanOptionData( Option.Type.Put, 35.00, 40.00, 0.0, 0.0488, 0.0833, 0.3, 0.078 ), |
|---|
| | 82 | new AmericanOptionData( Option.Type.Put, 35.00, 40.00, 0.0, 0.0488, 0.3333, 0.3, 0.697 ), |
|---|
| | 83 | new AmericanOptionData( Option.Type.Put, 35.00, 40.00, 0.0, 0.0488, 0.5833, 0.3, 1.218 ), |
|---|
| | 84 | |
|---|
| | 85 | new AmericanOptionData( Option.Type.Put, 40.00, 40.00, 0.0, 0.0488, 0.0833, 0.3, 1.309 ), |
|---|
| | 86 | new AmericanOptionData( Option.Type.Put, 40.00, 40.00, 0.0, 0.0488, 0.3333, 0.3, 2.477 ), |
|---|
| | 87 | new AmericanOptionData( Option.Type.Put, 40.00, 40.00, 0.0, 0.0488, 0.5833, 0.3, 3.161 ), |
|---|
| | 88 | |
|---|
| | 89 | new AmericanOptionData( Option.Type.Put, 45.00, 40.00, 0.0, 0.0488, 0.0833, 0.3, 5.059 ), |
|---|
| | 90 | new AmericanOptionData( Option.Type.Put, 45.00, 40.00, 0.0, 0.0488, 0.3333, 0.3, 5.699 ), |
|---|
| | 91 | new AmericanOptionData( Option.Type.Put, 45.00, 40.00, 0.0, 0.0488, 0.5833, 0.3, 6.231 ), |
|---|
| | 92 | |
|---|
| | 93 | new AmericanOptionData( Option.Type.Put, 35.00, 40.00, 0.0, 0.0488, 0.0833, 0.4, 0.247 ), |
|---|
| | 94 | new AmericanOptionData( Option.Type.Put, 35.00, 40.00, 0.0, 0.0488, 0.3333, 0.4, 1.344 ), |
|---|
| | 95 | new AmericanOptionData( Option.Type.Put, 35.00, 40.00, 0.0, 0.0488, 0.5833, 0.4, 2.150 ), |
|---|
| | 96 | |
|---|
| | 97 | new AmericanOptionData( Option.Type.Put, 40.00, 40.00, 0.0, 0.0488, 0.0833, 0.4, 1.767 ), |
|---|
| | 98 | new AmericanOptionData( Option.Type.Put, 40.00, 40.00, 0.0, 0.0488, 0.3333, 0.4, 3.381 ), |
|---|
| | 99 | new AmericanOptionData( Option.Type.Put, 40.00, 40.00, 0.0, 0.0488, 0.5833, 0.4, 4.342 ), |
|---|
| | 100 | |
|---|
| | 101 | new AmericanOptionData( Option.Type.Put, 45.00, 40.00, 0.0, 0.0488, 0.0833, 0.4, 5.288 ), |
|---|
| | 102 | new AmericanOptionData( Option.Type.Put, 45.00, 40.00, 0.0, 0.0488, 0.3333, 0.4, 6.501 ), |
|---|
| | 103 | new AmericanOptionData( Option.Type.Put, 45.00, 40.00, 0.0, 0.0488, 0.5833, 0.4, 7.367 ), |
|---|
| | 104 | |
|---|
| | 105 | // Type in Exhibits 4 and 5 if you have some spare time ;-) |
|---|
| | 106 | |
|---|
| | 107 | // type, strike, spot, q, r, t, vol, value, tol |
|---|
| | 108 | // values from Exhibit 6 - Long dated Call Options with dividends |
|---|
| | 109 | new AmericanOptionData( Option.Type.Call, 100.00, 80.00, 0.07, 0.03, 3.0, 0.2, 2.605 ), |
|---|
| | 110 | new AmericanOptionData( Option.Type.Call, 100.00, 90.00, 0.07, 0.03, 3.0, 0.2, 5.182 ), |
|---|
| | 111 | new AmericanOptionData( Option.Type.Call, 100.00, 100.00, 0.07, 0.03, 3.0, 0.2, 9.065 ), |
|---|
| | 112 | new AmericanOptionData( Option.Type.Call, 100.00, 110.00, 0.07, 0.03, 3.0, 0.2, 14.430 ), |
|---|
| | 113 | new AmericanOptionData( Option.Type.Call, 100.00, 120.00, 0.07, 0.03, 3.0, 0.2, 21.398 ), |
|---|
| | 114 | |
|---|
| | 115 | new AmericanOptionData( Option.Type.Call, 100.00, 80.00, 0.07, 0.03, 3.0, 0.4, 11.336 ), |
|---|
| | 116 | new AmericanOptionData( Option.Type.Call, 100.00, 90.00, 0.07, 0.03, 3.0, 0.4, 15.711 ), |
|---|
| | 117 | new AmericanOptionData( Option.Type.Call, 100.00, 100.00, 0.07, 0.03, 3.0, 0.4, 20.760 ), |
|---|
| | 118 | new AmericanOptionData( Option.Type.Call, 100.00, 110.00, 0.07, 0.03, 3.0, 0.4, 26.440 ), |
|---|
| | 119 | new AmericanOptionData( Option.Type.Call, 100.00, 120.00, 0.07, 0.03, 3.0, 0.4, 32.709 ), |
|---|
| | 120 | |
|---|
| | 121 | new AmericanOptionData( Option.Type.Call, 100.00, 80.00, 0.07, 0.00001, 3.0, 0.3, 5.552 ), |
|---|
| | 122 | new AmericanOptionData( Option.Type.Call, 100.00, 90.00, 0.07, 0.00001, 3.0, 0.3, 8.868 ), |
|---|
| | 123 | new AmericanOptionData( Option.Type.Call, 100.00, 100.00, 0.07, 0.00001, 3.0, 0.3, 13.158 ), |
|---|
| | 124 | new AmericanOptionData( Option.Type.Call, 100.00, 110.00, 0.07, 0.00001, 3.0, 0.3, 18.458 ), |
|---|
| | 125 | new AmericanOptionData( Option.Type.Call, 100.00, 120.00, 0.07, 0.00001, 3.0, 0.3, 24.786 ), |
|---|
| | 126 | |
|---|
| | 127 | new AmericanOptionData( Option.Type.Call, 100.00, 80.00, 0.03, 0.07, 3.0, 0.3, 12.177 ), |
|---|
| | 128 | new AmericanOptionData( Option.Type.Call, 100.00, 90.00, 0.03, 0.07, 3.0, 0.3, 17.411 ), |
|---|
| | 129 | new AmericanOptionData( Option.Type.Call, 100.00, 100.00, 0.03, 0.07, 3.0, 0.3, 23.402 ), |
|---|
| | 130 | new AmericanOptionData( Option.Type.Call, 100.00, 110.00, 0.03, 0.07, 3.0, 0.3, 30.028 ), |
|---|
| | 131 | new AmericanOptionData( Option.Type.Call, 100.00, 120.00, 0.03, 0.07, 3.0, 0.3, 37.177 ) |
|---|
| | 132 | }; |
|---|
| | 133 | |
|---|
| | 134 | [TestMethod()] |
|---|
| | 135 | public void testBaroneAdesiWhaleyValues() { |
|---|
| | 136 | // ("Testing Barone-Adesi and Whaley approximation for American options..."); |
|---|
| | 137 | |
|---|
| | 138 | /* The data below are from |
|---|
| | 139 | "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 pag 24 |
|---|
| | 140 | |
|---|
| | 141 | The following values were replicated only up to the second digit |
|---|
| | 142 | by the VB code provided by Haug, which was used as base for the |
|---|
| | 143 | C++ implementation |
|---|
| | 144 | |
|---|
| | 145 | */ |
|---|
| | 146 | AmericanOptionData[] values = { |
|---|
| | 147 | new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.10, 0.15, 0.0206) , |
|---|
| | 148 | new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.15, 1.8771) , |
|---|
| | 149 | new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.15, 10.0089) , |
|---|
| | 150 | new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.10, 0.25, 0.3159) , |
|---|
| | 151 | new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.25, 3.1280) , |
|---|
| | 152 | new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.25, 10.3919) , |
|---|
| | 153 | new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.10, 0.35, 0.9495) , |
|---|
| | 154 | new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.35, 4.3777) , |
|---|
| | 155 | new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.35, 11.1679) , |
|---|
| | 156 | new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.50, 0.15, 0.8208) , |
|---|
| | 157 | new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.15, 4.0842) , |
|---|
| | 158 | new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.15, 10.8087) , |
|---|
| | 159 | new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.50, 0.25, 2.7437) , |
|---|
| | 160 | new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.25, 6.8015) , |
|---|
| | 161 | new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.25, 13.0170) , |
|---|
| | 162 | new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.50, 0.35, 5.0063) , |
|---|
| | 163 | new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.35, 9.5106) , |
|---|
| | 164 | new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.35, 15.5689) , |
|---|
| | 165 | new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.10, 0.15, 10.0000) , |
|---|
| | 166 | new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.10, 0.15, 1.8770) , |
|---|
| | 167 | new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.10, 0.15, 0.0410) , |
|---|
| | 168 | new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.10, 0.25, 10.2533) , |
|---|
| | 169 | new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.10, 0.25, 3.1277) , |
|---|
| | 170 | new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.10, 0.25, 0.4562) , |
|---|
| | 171 | new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.10, 0.35, 10.8787) , |
|---|
| | 172 | new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.10, 0.35, 4.3777) , |
|---|
| | 173 | new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.10, 0.35, 1.2402) , |
|---|
| | 174 | new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.50, 0.15, 10.5595) , |
|---|
| | 175 | new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.50, 0.15, 4.0842) , |
|---|
| | 176 | new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.50, 0.15, 1.0822) , |
|---|
| | 177 | new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.50, 0.25, 12.4419) , |
|---|
| | 178 | new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.50, 0.25, 6.8014) , |
|---|
| | 179 | new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.50, 0.25, 3.3226) , |
|---|
| | 180 | new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.50, 0.35, 14.6945) , |
|---|
| | 181 | new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.50, 0.35, 9.5104) , |
|---|
| | 182 | new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.50, 0.35, 5.8823)}; |
|---|
| | 183 | |
|---|
| | 184 | Date today = Date.Today; |
|---|
| | 185 | DayCounter dc = new Actual360(); |
|---|
| | 186 | SimpleQuote spot = new SimpleQuote(0.0); |
|---|
| | 187 | SimpleQuote qRate = new SimpleQuote(0.0); |
|---|
| | 188 | YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); |
|---|
| | 189 | |
|---|
| | 190 | SimpleQuote rRate = new SimpleQuote(0.0); |
|---|
| | 191 | YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); |
|---|
| | 192 | SimpleQuote vol = new SimpleQuote(0.0); |
|---|
| | 193 | BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); |
|---|
| | 194 | |
|---|
| | 195 | double tolerance = 3.0e-3; |
|---|
| | 196 | |
|---|
| | 197 | for (int i=0; i<values.Length; i++) { |
|---|
| | 198 | |
|---|
| | 199 | StrikedTypePayoff payoff = new PlainVanillaPayoff(values[i].type, values[i].strike); |
|---|
| | 200 | Date exDate = today + Convert.ToInt32(values[i].t*360+0.5); |
|---|
| | 201 | Exercise exercise = new AmericanExercise(today, exDate); |
|---|
| | 202 | |
|---|
| | 203 | spot .setValue(values[i].s); |
|---|
| | 204 | qRate.setValue(values[i].q); |
|---|
| | 205 | rRate.setValue(values[i].r); |
|---|
| | 206 | vol .setValue(values[i].v); |
|---|
| | 207 | |
|---|
| | 208 | BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle<Quote>(spot), |
|---|
| | 209 | new Handle<YieldTermStructure>(qTS), |
|---|
| | 210 | new Handle<YieldTermStructure>(rTS), |
|---|
| | 211 | new Handle<BlackVolTermStructure>(volTS)); |
|---|
| | 212 | |
|---|
| | 213 | IPricingEngine engine = new BaroneAdesiWhaleyApproximationEngine(stochProcess); |
|---|
| | 214 | |
|---|
| | 215 | VanillaOption option = new VanillaOption(payoff, exercise); |
|---|
| | 216 | option.setPricingEngine(engine); |
|---|
| | 217 | |
|---|
| | 218 | double calculated = option.NPV(); |
|---|
| | 219 | double error = Math.Abs(calculated-values[i].result); |
|---|
| | 220 | if (error > tolerance) { |
|---|
| | 221 | REPORT_FAILURE("value", payoff, exercise, values[i].s, values[i].q, |
|---|
| | 222 | values[i].r, today, values[i].v, values[i].result, |
|---|
| | 223 | calculated, error, tolerance); |
|---|
| | 224 | } |
|---|
| | 225 | } |
|---|
| | 226 | } |
|---|
| | 227 | |
|---|
| | 228 | [TestMethod()] |
|---|
| | 229 | public void testBjerksundStenslandValues() { |
|---|
| | 230 | // ("Testing Bjerksund and Stensland approximation for American options..."); |
|---|
| | 231 | |
|---|
| | 232 | AmericanOptionData[] values = new AmericanOptionData[] { |
|---|
| | 233 | // type, strike, spot, q, r, t, vol, value, tol |
|---|
| | 234 | // from "Option pricing formulas", Haug, McGraw-Hill 1998, pag 27 |
|---|
| | 235 | new AmericanOptionData(Option.Type.Call, 40.00, 42.00, 0.08, 0.04, 0.75, 0.35, 5.2704), |
|---|
| | 236 | // from "Option pricing formulas", Haug, McGraw-Hill 1998, VBA code |
|---|
| | 237 | new AmericanOptionData(Option.Type.Put, 40.00, 36.00, 0.00, 0.06, 1.00, 0.20, 4.4531) |
|---|
| | 238 | }; |
|---|
| | 239 | |
|---|
| | 240 | Date today = Date.Today; |
|---|
| | 241 | DayCounter dc = new Actual360(); |
|---|
| | 242 | SimpleQuote spot = new SimpleQuote(0.0); |
|---|
| | 243 | SimpleQuote qRate = new SimpleQuote(0.0); |
|---|
| | 244 | YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); |
|---|
| | 245 | |
|---|
| | 246 | SimpleQuote rRate = new SimpleQuote(0.0); |
|---|
| | 247 | YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); |
|---|
| | 248 | SimpleQuote vol = new SimpleQuote(0.0); |
|---|
| | 249 | BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); |
|---|
| | 250 | |
|---|
| | 251 | double tolerance = 3.0e-3; |
|---|
| | 252 | |
|---|
| | 253 | for (int i=0; i<values.Length; i++) { |
|---|
| | 254 | |
|---|
| | 255 | StrikedTypePayoff payoff = new PlainVanillaPayoff(values[i].type, values[i].strike); |
|---|
| | 256 | Date exDate = today + Convert.ToInt32(values[i].t*360+0.5); |
|---|
| | 257 | Exercise exercise = new AmericanExercise(today, exDate); |
|---|
| | 258 | |
|---|
| | 259 | spot .setValue(values[i].s); |
|---|
| | 260 | qRate.setValue(values[i].q); |
|---|
| | 261 | rRate.setValue(values[i].r); |
|---|
| | 262 | vol .setValue(values[i].v); |
|---|
| | 263 | |
|---|
| | 264 | BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle<Quote>(spot), |
|---|
| | 265 | new Handle<YieldTermStructure>(qTS), |
|---|
| | 266 | new Handle<YieldTermStructure>(rTS), |
|---|
| | 267 | new Handle<BlackVolTermStructure>(volTS)); |
|---|
| | 268 | |
|---|
| | 269 | IPricingEngine engine = new BjerksundStenslandApproximationEngine(stochProcess); |
|---|
| | 270 | |
|---|
| | 271 | VanillaOption option = new VanillaOption(payoff, exercise); |
|---|
| | 272 | option.setPricingEngine(engine); |
|---|
| | 273 | |
|---|
| | 274 | double calculated = option.NPV(); |
|---|
| | 275 | double error = Math.Abs(calculated-values[i].result); |
|---|
| | 276 | if (error > tolerance) { |
|---|
| | 277 | REPORT_FAILURE("value", payoff, exercise, values[i].s, values[i].q, |
|---|
| | 278 | values[i].r, today, values[i].v, values[i].result, |
|---|
| | 279 | calculated, error, tolerance); |
|---|
| | 280 | } |
|---|
| | 281 | } |
|---|
| | 282 | } |
|---|
| | 283 | |
|---|
| | 284 | [TestMethod()] |
|---|
| | 285 | public void testJuValues() { |
|---|
| | 286 | |
|---|
| | 287 | // ("Testing Ju approximation for American options..."); |
|---|
| | 288 | |
|---|
| | 289 | Date today = Date.Today; |
|---|
| | 290 | DayCounter dc = new Actual360(); |
|---|
| | 291 | SimpleQuote spot = new SimpleQuote(0.0); |
|---|
| | 292 | SimpleQuote qRate = new SimpleQuote(0.0); |
|---|
| | 293 | YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); |
|---|
| | 294 | |
|---|
| | 295 | SimpleQuote rRate = new SimpleQuote(0.0); |
|---|
| | 296 | YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); |
|---|
| | 297 | SimpleQuote vol = new SimpleQuote(0.0); |
|---|
| | 298 | BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); |
|---|
| | 299 | |
|---|
| | 300 | double tolerance = 1.0e-3; |
|---|
| | 301 | |
|---|
| | 302 | for (int i = 0; i < juValues.Length; i++) { |
|---|
| | 303 | |
|---|
| | 304 | StrikedTypePayoff payoff = new PlainVanillaPayoff(juValues[i].type, juValues[i].strike); |
|---|
| | 305 | Date exDate = today + Convert.ToInt32(juValues[i].t*360+0.5); |
|---|
| | 306 | Exercise exercise = new AmericanExercise(today, exDate); |
|---|
| | 307 | |
|---|
| | 308 | spot .setValue(juValues[i].s); |
|---|
| | 309 | qRate.setValue(juValues[i].q); |
|---|
| | 310 | rRate.setValue(juValues[i].r); |
|---|
| | 311 | vol .setValue(juValues[i].v); |
|---|
| | 312 | |
|---|
| | 313 | BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle<Quote>(spot), |
|---|
| | 314 | new Handle<YieldTermStructure>(qTS), |
|---|
| | 315 | new Handle<YieldTermStructure>(rTS), |
|---|
| | 316 | new Handle<BlackVolTermStructure>(volTS)); |
|---|
| | 317 | |
|---|
| | 318 | IPricingEngine engine = new JuQuadraticApproximationEngine(stochProcess); |
|---|
| | 319 | |
|---|
| | 320 | VanillaOption option = new VanillaOption(payoff, exercise); |
|---|
| | 321 | option.setPricingEngine(engine); |
|---|
| | 322 | |
|---|
| | 323 | double calculated = option.NPV(); |
|---|
| | 324 | double error = Math.Abs(calculated - juValues[i].result); |
|---|
| | 325 | if (error > tolerance) { |
|---|
| | 326 | REPORT_FAILURE("value", payoff, exercise, juValues[i].s, juValues[i].q, |
|---|
| | 327 | juValues[i].r, today, juValues[i].v, juValues[i].result, |
|---|
| | 328 | calculated, error, tolerance); |
|---|
| | 329 | } |
|---|
| | 330 | } |
|---|
| | 331 | } |
|---|
| | 332 | |
|---|
| | 333 | [TestMethod()] |
|---|
| | 334 | public void testFdValues() { |
|---|
| | 335 | |
|---|
| | 336 | //("Testing finite-difference engine for American options..."); |
|---|
| | 337 | |
|---|
| | 338 | Date today = Date.Today; |
|---|
| | 339 | DayCounter dc = new Actual360(); |
|---|
| | 340 | SimpleQuote spot = new SimpleQuote(0.0); |
|---|
| | 341 | SimpleQuote qRate = new SimpleQuote(0.0); |
|---|
| | 342 | YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); |
|---|
| | 343 | |
|---|
| | 344 | SimpleQuote rRate = new SimpleQuote(0.0); |
|---|
| | 345 | YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); |
|---|
| | 346 | SimpleQuote vol = new SimpleQuote(0.0); |
|---|
| | 347 | BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); |
|---|
| | 348 | |
|---|
| | 349 | double tolerance = 8.0e-2; |
|---|
| | 350 | |
|---|
| | 351 | for (int i = 0; i < juValues.Length; i++) { |
|---|
| | 352 | |
|---|
| | 353 | StrikedTypePayoff payoff = new PlainVanillaPayoff(juValues[i].type, juValues[i].strike); |
|---|
| | 354 | Date exDate = today + Convert.ToInt32(juValues[i].t*360+0.5); |
|---|
| | 355 | Exercise exercise = new AmericanExercise(today, exDate); |
|---|
| | 356 | |
|---|
| | 357 | spot .setValue(juValues[i].s); |
|---|
| | 358 | qRate.setValue(juValues[i].q); |
|---|
| | 359 | rRate.setValue(juValues[i].r); |
|---|
| | 360 | vol .setValue(juValues[i].v); |
|---|
| | 361 | |
|---|
| | 362 | BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle<Quote>(spot), |
|---|
| | 363 | new Handle<YieldTermStructure>(qTS), |
|---|
| | 364 | new Handle<YieldTermStructure>(rTS), |
|---|
| | 365 | new Handle<BlackVolTermStructure>(volTS)); |
|---|
| | 366 | |
|---|
| | 367 | IPricingEngine engine = new FDAmericanEngine(stochProcess, 100,100); |
|---|
| | 368 | |
|---|
| | 369 | VanillaOption option = new VanillaOption(payoff, exercise); |
|---|
| | 370 | option.setPricingEngine(engine); |
|---|
| | 371 | |
|---|
| | 372 | double calculated = option.NPV(); |
|---|
| | 373 | double error = Math.Abs(calculated - juValues[i].result); |
|---|
| | 374 | if (error > tolerance) { |
|---|
| | 375 | REPORT_FAILURE("value", payoff, exercise, juValues[i].s, juValues[i].q, |
|---|
| | 376 | juValues[i].r, today, juValues[i].v, juValues[i].result, |
|---|
| | 377 | calculated, error, tolerance); |
|---|
| | 378 | } |
|---|
| | 379 | } |
|---|
| | 380 | } |
|---|
| | 381 | |
|---|
| | 382 | public void testFdGreeks<Engine>() where Engine : IFDEngine, new() { |
|---|
| | 383 | |
|---|
| | 384 | //SavedSettings backup; |
|---|
| | 385 | |
|---|
| | 386 | Dictionary<string, double> calculated = new Dictionary<string,double>(), |
|---|
| | 387 | expected = new Dictionary<string,double>(), |
|---|
| | 388 | tolerance = new Dictionary<string,double>(); |
|---|
| | 389 | |
|---|
| | 390 | tolerance.Add("delta", 7.0e-4); |
|---|
| | 391 | tolerance.Add("gamma", 2.0e-4); |
|---|
| | 392 | //tolerance["theta"] = 1.0e-4; |
|---|
| | 393 | |
|---|
| | 394 | Option.Type[] types = new Option.Type[] { Option.Type.Call, Option.Type.Put }; |
|---|
| | 395 | double[] strikes = { 50.0, 99.5, 100.0, 100.5, 150.0 }; |
|---|
| | 396 | double[] underlyings = { 100.0 }; |
|---|
| | 397 | double[] qRates = { 0.04, 0.05, 0.06 }; |
|---|
| | 398 | double[] rRates = { 0.01, 0.05, 0.15 }; |
|---|
| | 399 | int[] years = { 1, 2 }; |
|---|
| | 400 | double[] vols = { 0.11, 0.50, 1.20 }; |
|---|
| | 401 | |
|---|
| | 402 | Date today = Date.Today; |
|---|
| | 403 | Settings.setEvaluationDate(today); |
|---|
| | 404 | |
|---|
| | 405 | DayCounter dc = new Actual360(); |
|---|
| | 406 | SimpleQuote spot = new SimpleQuote(0.0); |
|---|
| | 407 | SimpleQuote qRate = new SimpleQuote(0.0); |
|---|
| | 408 | YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); |
|---|
| | 409 | |
|---|
| | 410 | SimpleQuote rRate = new SimpleQuote(0.0); |
|---|
| | 411 | YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); |
|---|
| | 412 | SimpleQuote vol = new SimpleQuote(0.0); |
|---|
| | 413 | BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); |
|---|
| | 414 | |
|---|
| | 415 | for (int i=0; i<types.Length; i++) { |
|---|
| | 416 | for (int j=0; j<strikes.Length; j++) { |
|---|
| | 417 | for (int k=0; k<years.Length; k++) { |
|---|
| | 418 | Date exDate = today + new Period(years[k], TimeUnit.Years); |
|---|
| | 419 | Exercise exercise = new AmericanExercise(today, exDate); |
|---|
| | 420 | StrikedTypePayoff payoff = new PlainVanillaPayoff(types[i], strikes[j]); |
|---|
| | 421 | BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle<Quote>(spot), |
|---|
| | 422 | new Handle<YieldTermStructure>(qTS), |
|---|
| | 423 | new Handle<YieldTermStructure>(rTS), |
|---|
| | 424 | new Handle<BlackVolTermStructure>(volTS)); |
|---|
| | 425 | |
|---|
| | 426 | IPricingEngine engine = new Engine().factory(stochProcess); |
|---|
| | 427 | |
|---|
| | 428 | VanillaOption option = new VanillaOption(payoff, exercise); |
|---|
| | 429 | option.setPricingEngine(engine); |
|---|
| | 430 | |
|---|
| | 431 | for (int l=0; l<underlyings.Length; l++) { |
|---|
| | 432 | for (int m=0; m<qRates.Length; m++) { |
|---|
| | 433 | for (int n=0; n<rRates.Length; n++) { |
|---|
| | 434 | for (int p=0; p<vols.Length; p++) { |
|---|
| | 435 | double u = underlyings[l]; |
|---|
| | 436 | double q = qRates[m], |
|---|
| | 437 | r = rRates[n]; |
|---|
| | 438 | double v = vols[p]; |
|---|
| | 439 | spot.setValue(u); |
|---|
| | 440 | qRate.setValue(q); |
|---|
| | 441 | rRate.setValue(r); |
|---|
| | 442 | vol.setValue(v); |
|---|
| | 443 | |
|---|
| | 444 | double value = option.NPV(); |
|---|
| | 445 | calculated.Add("delta", option.delta()); |
|---|
| | 446 | calculated.Add("gamma", option.gamma()); |
|---|
| | 447 | //calculated["theta"] = option.theta(); |
|---|
| | 448 | |
|---|
| | 449 | if (value > spot.value()*1.0e-5) { |
|---|
| | 450 | // perturb spot and get delta and gamma |
|---|
| | 451 | double du = u*1.0e-4; |
|---|
| | 452 | spot.setValue(u+du); |
|---|
| | 453 | double value_p = option.NPV(), |
|---|
| | 454 | delta_p = option.delta(); |
|---|
| | 455 | spot.setValue(u-du); |
|---|
| | 456 | double value_m = option.NPV(), |
|---|
| | 457 | delta_m = option.delta(); |
|---|
| | 458 | spot.setValue(u); |
|---|
| | 459 | expected.Add("delta", (value_p - value_m)/(2*du)); |
|---|
| | 460 | expected.Add("gamma", (delta_p - delta_m)/(2*du)); |
|---|
| | 461 | |
|---|
| | 462 | /* |
|---|
| | 463 | // perturb date and get theta |
|---|
| | 464 | Time dT = dc.yearFraction(today-1, today+1); |
|---|
| | 465 | Settings::instance().setEvaluationDate(today-1); |
|---|
| | 466 | value_m = option.NPV(); |
|---|
| | 467 | Settings::instance().setEvaluationDate(today+1); |
|---|
| | 468 | value_p = option.NPV(); |
|---|
| | 469 | Settings::instance().setEvaluationDate(today); |
|---|
| | 470 | expected["theta"] = (value_p - value_m)/dT; |
|---|
| | 471 | */ |
|---|
| | 472 | |
|---|
| | 473 | // compare |
|---|
| | 474 | foreach (string greek in calculated.Keys) { |
|---|
| | 475 | double expct = expected [greek], |
|---|
| | 476 | calcl = calculated[greek], |
|---|
| | 477 | tol = tolerance [greek]; |
|---|
| | 478 | double error = Utilities.relativeError(expct,calcl,u); |
|---|
| | 479 | if (error>tol) { |
|---|
| | 480 | REPORT_FAILURE(greek, payoff, exercise, |
|---|
| | 481 | u, q, r, today, v, |
|---|
| | 482 | expct, calcl, error, tol); |
|---|
| | 483 | } |
|---|
| | 484 | } |
|---|
| | 485 | } |
|---|
| | 486 | calculated.Clear(); |
|---|
| | 487 | expected.Clear(); |
|---|
| | 488 | } |
|---|
| | 489 | } |
|---|
| | 490 | } |
|---|
| | 491 | } |
|---|
| | 492 | } |
|---|
| | 493 | } |
|---|
| | 494 | } |
|---|
| | 495 | } |
|---|
| | 496 | |
|---|
| | 497 | [TestMethod()] |
|---|
| | 498 | public void testFdAmericanGreeks() { |
|---|
| | 499 | //("Testing finite-differences American option greeks..."); |
|---|
| | 500 | testFdGreeks<FDAmericanEngine>(); |
|---|
| | 501 | } |
|---|
| | 502 | |
|---|
| | 503 | [TestMethod()] |
|---|
| | 504 | public void testFdShoutGreeks() { |
|---|
| | 505 | // ("Testing finite-differences shout option greeks..."); |
|---|
| | 506 | testFdGreeks<FDShoutEngine>(); |
|---|
| | 507 | } |
|---|
| | 508 | |
|---|
| | 509 | void REPORT_FAILURE(string greekName, StrikedTypePayoff payoff, Exercise exercise, double s, double q, double r, |
|---|
| | 510 | Date today, double v, double expected, double calculated, double error, double tolerance) { |
|---|
| | 511 | Assert.Fail(exercise + " " |
|---|
| | 512 | + payoff.optionType() + " option with " |
|---|
| | 513 | + payoff + " payoff:\n" |
|---|
| | 514 | + " spot value: " + s + "\n" |
|---|
| | 515 | + " strike: " + payoff.strike() + "\n" |
|---|
| | 516 | + " dividend yield: " + q + "\n" |
|---|
| | 517 | + " risk-free rate: " + r + "\n" |
|---|
| | 518 | + " reference date: " + today + "\n" |
|---|
| | 519 | + " maturity: " + exercise.lastDate() + "\n" |
|---|
| | 520 | + " volatility: " + v + "\n\n" |
|---|
| | 521 | + " expected " + greekName + ": " + expected + "\n" |
|---|
| | 522 | + " calculated " + greekName + ": " + calculated + "\n" |
|---|
| | 523 | + " error: " + error + "\n" |
|---|
| | 524 | + " tolerance: " + tolerance); |
|---|
| | 525 | } |
|---|