Over the last Christmas I was thinking about investing so I developed a small tool which I was using to analyse stock market data. I was interested in checking what the rate of return on various stocks actually was if you use the Dollar Cost Averaging method of investment.
I retrieved the data from Google Finance – you can download daily stock prices for any stock you’d like. I then imported that data into a MySQL database so I could write simple queries for the data from php. Finally I wrote a single little php script that took the value in Euros which you wanted to invest per month and calculated how much your money would grow (or decline) in value over the time you chose.
For the moment, both the stock you invest in and historic period over which you invest in are hard-coded in the php code. These could be both made into fields for the users of the tool to change later.
However, as I made progress the PHP was growing larger and longer without much redesign. So I thought it was perfect piece of code to practise refactoring on! The code as it is today is pasted below. As you can see there is no clear structure to the code, just variables, constants and a loop that echos out the response. There are no tests so I have to re-load the page and examine it manually every time I make a change to make sure I haven’t broken it.
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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
<h1>Dollar Cost Average Calculator</h1> <form method="get" action="index.php"> <label>Euro per month: </label> <input name="euro_per_month" type="text"/> <input type="submit" value="Dollar Cost Average"/> </form> <?php /// ------------------------------------------ $euro_per_month = 500; $cost_per_month = 3; $dividend_per_quarter = 0.005; $USA_DIVIDEND_WITHHOLDING_TAX = 0.15; $IRISH_INCOME_TAX_ON_US_DIVIDENDS = 0.41 - $USA_DIVIDEND_WITHHOLDING_TAX; $IRISH_TAX_PAYMENT_MONTH = 1; if (isset($_GET['euro_per_month'])) { $euro_per_month = $_GET['euro_per_month']; } /// ------------------------------------------ $mysqli = new mysqli("127.0.0.1", "invest_data_user", "1234qwer", "investing_data"); $result = $mysqli->query("SELECT * FROM import_test_2 " . "WHERE date BETWEEN '2005-12-01' AND '2012-12-31' " . "ORDER BY date ASC"); echo '<table border="1" cellpadding="5">'; echo '<tr>'; echo '<th>Date</th>'; echo '<th>Price</th>'; echo '<th> </th>'; echo '<th>Cash to Invest</th>'; echo '<th>Shares Bought</th>'; echo '<th>Shares Owned</th>'; echo '<th>Cash Invested</th>'; echo '<th>Stock Worth</th>'; echo '<th>Dividends Paid</th>'; echo '<th>Gross Dividends YTD</th>'; echo '<th>Cash Balance</th>'; echo '<th> </th>'; echo '<th>Return</th>'; echo '</tr>'; $current_month = 2; $day = 1; /// ------------------------------------------ $euro_invested = 0; $cash_balance = 0; $shares_purchased = 0; $day_of_month_to_buy_on = 1; $gross_dividends_this_year = 0; /// ------------------------------------------ while($row = $result->fetch_assoc()) { $date = DateTime::createFromFormat('Y-m-d', $row['date']); $month = $date->format('n'); if ($month == $current_month) { /// ------------------------------------------ /// filter out 0 values if ($row['high'] == 0) { continue; } /// ------------------------------------------ if ($day < $day_of_month_to_buy_on) { $day++; continue; } echo '<tr>'; echo '<td>' . $row['date'] . '</td>'; echo '<td>€' . $row['high'] . '</td>'; echo '<td> </td>'; /// ------------------------------------------ $euro_invested += $euro_per_month; $cash_balance += $euro_per_month; $cash_at_start_of_month = $cash_balance; $cash_balance -= $cost_per_month; $price_per_share = $row['high']; $num_shares_can_buy = intval($cash_balance / $price_per_share); $shares_purchased += $num_shares_can_buy; $stock_worth = $shares_purchased * $price_per_share; $cash_balance -= $num_shares_can_buy * $price_per_share; $dividend_this_month = ($current_month==3 or $current_month==6 or$current_month==9 or$current_month==12) ? 1 : 0; $dividends_paid = $shares_purchased * $price_per_share * $dividend_per_quarter * $dividend_this_month; $gross_dividends_this_year += $dividends_paid; $dividend_this_month -= $USA_DIVIDEND_WITHHOLDING_TAX * $dividends_paid; $cash_balance += $dividends_paid; if ($current_month == $IRISH_TAX_PAYMENT_MONTH) { $tax_payable_to_revenue_on_us_dividends = $IRISH_INCOME_TAX_ON_US_DIVIDENDS * $gross_dividends_this_year; $cash_balance -= $tax_payable_to_revenue_on_us_dividends; // reset dividend aggregate $gross_dividends_this_year = 0; } $percentage_return = intval(($cash_balance+$stock_worth) * 100 / $euro_invested) - 100; /// ------------------------------------------ echo '<td>€' . $cash_at_start_of_month . '</td>'; echo '<td>x' . $num_shares_can_buy . '</td>'; echo '<td>x' . $shares_purchased . '</td>'; echo '<td>€' . $euro_invested . '</td>'; echo '<td>€' . $stock_worth . '</td>'; echo '<td>€' . $dividends_paid . '</td>'; echo '<td>€' . $gross_dividends_this_year . '</td>'; echo '<td>€' . $cash_balance . '</td>'; echo '<td> </td>'; echo '<td>' . $percentage_return . '%</td>'; echo '</tr>'; /// ------------------------------------------ /// ------------------------------------------ $current_month++; if ($current_month == 13) { $current_month = 1; } } } echo '</table>'; ?> |
Clearly I need to clean this code up! The first step will be to write a test around it – I’m going to try writing a characterisation test for this. Then I can begin refactoring. Once I’m happy with the refactor I can go back and refactor my tests so they aren’t so fragile and tied to the response output.
Leave a comment