Passed
Push — master ( 5dee5a...729c4d )
by
unknown
20:09 queued 09:33
created

Price::priceAtMaturity()   B

Complexity

Conditions 7
Paths 24

Size

Total Lines 55
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 32
CRAP Score 7.0671

Importance

Changes 0
Metric Value
cc 7
eloc 36
c 0
b 0
f 0
nc 24
nop 6
dl 0
loc 55
ccs 32
cts 36
cp 0.8889
crap 7.0671
rs 8.4106

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities;
4
5
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
6
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
7
use PhpOffice\PhpSpreadsheet\Calculation\Financial\Constants as FinancialConstants;
8
use PhpOffice\PhpSpreadsheet\Calculation\Financial\Coupons;
9
use PhpOffice\PhpSpreadsheet\Calculation\Financial\Helpers;
10
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
11
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
12
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
13
14
class Price
15
{
16
    /**
17
     * PRICE.
18
     *
19
     * Returns the price per $100 face value of a security that pays periodic interest.
20
     *
21
     * @param mixed $settlement The security's settlement date.
22
     *                              The security settlement date is the date after the issue date when the security
23
     *                              is traded to the buyer.
24
     * @param mixed $maturity The security's maturity date.
25
     *                                The maturity date is the date when the security expires.
26
     * @param mixed $rate the security's annual coupon rate
27
     * @param mixed $yield the security's annual yield
28
     * @param mixed $redemption The number of coupon payments per year.
29
     *                              For annual payments, frequency = 1;
30
     *                              for semiannual, frequency = 2;
31
     *                              for quarterly, frequency = 4.
32
     * @param mixed $basis The type of day count to use.
33
     *                         0 or omitted    US (NASD) 30/360
34
     *                         1               Actual/actual
35
     *                         2               Actual/360
36
     *                         3               Actual/365
37
     *                         4               European 30/360
38
     *
39
     * @return float|string Result, or a string containing an error
40
     */
41 28
    public static function price(
42
        mixed $settlement,
43
        mixed $maturity,
44
        mixed $rate,
45
        mixed $yield,
46
        mixed $redemption,
47
        mixed $frequency,
48
        mixed $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
49
    ): string|float {
50 28
        $settlement = Functions::flattenSingleValue($settlement);
51 28
        $maturity = Functions::flattenSingleValue($maturity);
52 28
        $rate = Functions::flattenSingleValue($rate);
53 28
        $yield = Functions::flattenSingleValue($yield);
54 28
        $redemption = Functions::flattenSingleValue($redemption);
55 28
        $frequency = Functions::flattenSingleValue($frequency);
56 28
        $basis = ($basis === null)
57 1
            ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
58 27
            : Functions::flattenSingleValue($basis);
59
60
        try {
61 28
            $settlement = SecurityValidations::validateSettlementDate($settlement);
62 27
            $maturity = SecurityValidations::validateMaturityDate($maturity);
63 26
            SecurityValidations::validateSecurityPeriod($settlement, $maturity);
64 25
            $rate = SecurityValidations::validateRate($rate);
65 24
            $yield = SecurityValidations::validateYield($yield);
66 23
            $redemption = SecurityValidations::validateRedemption($redemption);
67 22
            $frequency = SecurityValidations::validateFrequency($frequency);
68 18
            $basis = SecurityValidations::validateBasis($basis);
69 13
        } catch (Exception $e) {
70 13
            return $e->getMessage();
71
        }
72
73 15
        $dsc = (float) Coupons::COUPDAYSNC($settlement, $maturity, $frequency, $basis);
74 15
        $e = (float) Coupons::COUPDAYS($settlement, $maturity, $frequency, $basis);
75 15
        $n = (int) Coupons::COUPNUM($settlement, $maturity, $frequency, $basis);
76 15
        $a = (float) Coupons::COUPDAYBS($settlement, $maturity, $frequency, $basis);
77
78 15
        $baseYF = 1.0 + ($yield / $frequency);
79 15
        $rfp = 100 * ($rate / $frequency);
80 15
        $de = $dsc / $e;
81
82 15
        $result = $redemption / $baseYF ** (--$n + $de);
83 15
        for ($k = 0; $k <= $n; ++$k) {
84 15
            $result += $rfp / ($baseYF ** ($k + $de));
85
        }
86 15
        $result -= $rfp * ($a / $e);
87
88 15
        return $result;
89
    }
90
91
    /**
92
     * PRICEDISC.
93
     *
94
     * Returns the price per $100 face value of a discounted security.
95
     *
96
     * @param mixed $settlement The security's settlement date.
97
     *                              The security settlement date is the date after the issue date when the security
98
     *                              is traded to the buyer.
99
     * @param mixed $maturity The security's maturity date.
100
     *                                The maturity date is the date when the security expires.
101
     * @param mixed $discount The security's discount rate
102
     * @param mixed $redemption The security's redemption value per $100 face value
103
     * @param mixed $basis The type of day count to use.
104
     *                         0 or omitted    US (NASD) 30/360
105
     *                         1               Actual/actual
106
     *                         2               Actual/360
107
     *                         3               Actual/365
108
     *                         4               European 30/360
109
     *
110
     * @return float|string Result, or a string containing an error
111
     */
112 11
    public static function priceDiscounted(
113
        mixed $settlement,
114
        mixed $maturity,
115
        mixed $discount,
116
        mixed $redemption,
117
        mixed $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
118
    ) {
119 11
        $settlement = Functions::flattenSingleValue($settlement);
120 11
        $maturity = Functions::flattenSingleValue($maturity);
121 11
        $discount = Functions::flattenSingleValue($discount);
122 11
        $redemption = Functions::flattenSingleValue($redemption);
123 11
        $basis = ($basis === null)
124 1
            ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
125 10
            : Functions::flattenSingleValue($basis);
126
127
        try {
128 11
            $settlement = SecurityValidations::validateSettlementDate($settlement);
129 10
            $maturity = SecurityValidations::validateMaturityDate($maturity);
130 9
            SecurityValidations::validateSecurityPeriod($settlement, $maturity);
131 9
            $discount = SecurityValidations::validateDiscount($discount);
132 7
            $redemption = SecurityValidations::validateRedemption($redemption);
133 5
            $basis = SecurityValidations::validateBasis($basis);
134 8
        } catch (Exception $e) {
135 8
            return $e->getMessage();
136
        }
137
138 3
        $daysBetweenSettlementAndMaturity = Functions::scalar(DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis));
139 3
        if (!is_numeric($daysBetweenSettlementAndMaturity)) {
140
            //    return date error
141
            return StringHelper::convertToString($daysBetweenSettlementAndMaturity);
142
        }
143
144 3
        return $redemption * (1 - $discount * $daysBetweenSettlementAndMaturity);
145
    }
146
147
    /**
148
     * PRICEMAT.
149
     *
150
     * Returns the price per $100 face value of a security that pays interest at maturity.
151
     *
152
     * @param mixed $settlement The security's settlement date.
153
     *                              The security's settlement date is the date after the issue date when the
154
     *                              security is traded to the buyer.
155
     * @param mixed $maturity The security's maturity date.
156
     *                                The maturity date is the date when the security expires.
157
     * @param mixed $issue The security's issue date
158
     * @param mixed $rate The security's interest rate at date of issue
159
     * @param mixed $yield The security's annual yield
160
     * @param mixed $basis The type of day count to use.
161
     *                         0 or omitted    US (NASD) 30/360
162
     *                         1               Actual/actual
163
     *                         2               Actual/360
164
     *                         3               Actual/365
165
     *                         4               European 30/360
166
     *
167
     * @return float|string Result, or a string containing an error
168
     */
169 11
    public static function priceAtMaturity(
170
        mixed $settlement,
171
        mixed $maturity,
172
        mixed $issue,
173
        mixed $rate,
174
        mixed $yield,
175
        mixed $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
176
    ) {
177 11
        $settlement = Functions::flattenSingleValue($settlement);
178 11
        $maturity = Functions::flattenSingleValue($maturity);
179 11
        $issue = Functions::flattenSingleValue($issue);
180 11
        $rate = Functions::flattenSingleValue($rate);
181 11
        $yield = Functions::flattenSingleValue($yield);
182 11
        $basis = ($basis === null)
183 1
            ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
184 10
            : Functions::flattenSingleValue($basis);
185
186
        try {
187 11
            $settlement = SecurityValidations::validateSettlementDate($settlement);
188 10
            $maturity = SecurityValidations::validateMaturityDate($maturity);
189 9
            SecurityValidations::validateSecurityPeriod($settlement, $maturity);
190 9
            $issue = SecurityValidations::validateIssueDate($issue);
191 8
            $rate = SecurityValidations::validateRate($rate);
192 6
            $yield = SecurityValidations::validateYield($yield);
193 4
            $basis = SecurityValidations::validateBasis($basis);
194 7
        } catch (Exception $e) {
195 7
            return $e->getMessage();
196
        }
197
198 4
        $daysPerYear = Helpers::daysPerYear(Functions::scalar(DateTimeExcel\DateParts::year($settlement)), $basis);
199 4
        if (!is_numeric($daysPerYear)) {
200
            return $daysPerYear;
201
        }
202 4
        $daysBetweenIssueAndSettlement = Functions::scalar(DateTimeExcel\YearFrac::fraction($issue, $settlement, $basis));
203 4
        if (!is_numeric($daysBetweenIssueAndSettlement)) {
204
            //    return date error
205
            return StringHelper::convertToString($daysBetweenIssueAndSettlement);
206
        }
207 4
        $daysBetweenIssueAndSettlement *= $daysPerYear;
208 4
        $daysBetweenIssueAndMaturity = Functions::scalar(DateTimeExcel\YearFrac::fraction($issue, $maturity, $basis));
209 4
        if (!is_numeric($daysBetweenIssueAndMaturity)) {
210
            //    return date error
211
            return StringHelper::convertToString($daysBetweenIssueAndMaturity);
212
        }
213 4
        $daysBetweenIssueAndMaturity *= $daysPerYear;
214 4
        $daysBetweenSettlementAndMaturity = Functions::scalar(DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis));
215 4
        if (!is_numeric($daysBetweenSettlementAndMaturity)) {
216
            //    return date error
217
            return StringHelper::convertToString($daysBetweenSettlementAndMaturity);
218
        }
219 4
        $daysBetweenSettlementAndMaturity *= $daysPerYear;
220
221 4
        return (100 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate * 100))
222 4
            / (1 + (($daysBetweenSettlementAndMaturity / $daysPerYear) * $yield))
223 4
            - (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate * 100);
224
    }
225
226
    /**
227
     * RECEIVED.
228
     *
229
     * Returns the amount received at maturity for a fully invested Security.
230
     *
231
     * @param mixed $settlement The security's settlement date.
232
     *                              The security settlement date is the date after the issue date when the security
233
     *                                  is traded to the buyer.
234
     * @param mixed $maturity The security's maturity date.
235
     *                            The maturity date is the date when the security expires.
236
     * @param mixed $investment The amount invested in the security
237
     * @param mixed $discount The security's discount rate
238
     * @param mixed $basis The type of day count to use.
239
     *                         0 or omitted    US (NASD) 30/360
240
     *                         1               Actual/actual
241
     *                         2               Actual/360
242
     *                         3               Actual/365
243
     *                         4               European 30/360
244
     *
245
     * @return float|string Result, or a string containing an error
246
     */
247 10
    public static function received(
248
        mixed $settlement,
249
        mixed $maturity,
250
        mixed $investment,
251
        mixed $discount,
252
        mixed $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
253
    ) {
254 10
        $settlement = Functions::flattenSingleValue($settlement);
255 10
        $maturity = Functions::flattenSingleValue($maturity);
256 10
        $investment = Functions::flattenSingleValue($investment);
257 10
        $discount = Functions::flattenSingleValue($discount);
258 10
        $basis = ($basis === null)
259 1
            ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD
260 9
            : Functions::flattenSingleValue($basis);
261
262
        try {
263 10
            $settlement = SecurityValidations::validateSettlementDate($settlement);
264 9
            $maturity = SecurityValidations::validateMaturityDate($maturity);
265 8
            SecurityValidations::validateSecurityPeriod($settlement, $maturity);
266 8
            $investment = SecurityValidations::validateFloat($investment);
267 7
            $discount = SecurityValidations::validateDiscount($discount);
268 6
            $basis = SecurityValidations::validateBasis($basis);
269 5
        } catch (Exception $e) {
270 5
            return $e->getMessage();
271
        }
272
273 5
        if ($investment <= 0) {
274 1
            return ExcelError::NAN();
275
        }
276 4
        $daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::fraction($settlement, $maturity, $basis);
277 4
        if (!is_numeric($daysBetweenSettlementAndMaturity)) {
278
            //    return date error
279
            return StringHelper::convertToString(Functions::scalar($daysBetweenSettlementAndMaturity));
280
        }
281
282 4
        return $investment / (1 - ($discount * $daysBetweenSettlementAndMaturity));
283
    }
284
}
285