Track investment progress based on Yahoo Finance historical data using either the Closing or Adj Close.
<?php
// Display the progress of an investment
//
// Given initiation date and current average cost
// Plot the progress with horizontal bars at +20%, +10%, breakeven and -5%
if (empty($_POST))
{
// -----------------STEP ONE--------------------
// if nothing has been POSTed, send out the form
// ---------------------------------------------
?>
<!DOCTYPE HTML>
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
<meta charset="windows-1252" />
<title>Equity Charts: Entry</title>
<script type="text/javascript">
/**
* DHTML date validation script. Thanks to https://www.smartwebby.com/DHTML/date_validation.asp
*/
// Declaring valid date character, minimum year and maximum year
var dtCh= "/";
var minYear=1900;
var maxYear=2100;
function isInteger(s){
var I;
for (i = 0; i < s.length; i++){
// Check that current character is number.
var c = s.charAt(i);
if (((c < "0") || (c > "9"))) return false;
}
// All characters are numbers.
return true;
}
function stripCharsInBag(s, bag){
var I;
var returnString = "";
// Search through string's characters one by one.
// If character is not in bag, append to returnString.
for (i = 0; i < s.length; i++){
var c = s.charAt(i);
if (bag.indexOf(c) == -1) returnString += c;
}
return returnString;
}
function daysInFebruary (year){
// February has 29 days in any year evenly divisible by four,
// EXCEPT for centurial years which are not also divisible by 400.
return (((year % 4 == 0) && ( (!(year % 100 == 0)) || (year % 400 == 0))) ? 29 : 28 );
}
function DaysArray(n) {
for (var i = 1; i <= n; i++) {
this[i] = 31
if (i==4 || i==6 || i==9 || i==11) {this[i] = 30}
if (i==2) {this[i] = 29}
}
return this
}
function isDate(dtStr){
var daysInMonth = DaysArray(12)
var pos1=dtStr.indexOf(dtCh)
var pos2=dtStr.indexOf(dtCh,pos1+1)
var strMonth=dtStr.substring(0,pos1)
var strDay=dtStr.substring(pos1+1,pos2)
var strYear=dtStr.substring(pos2+1)
strYr=strYear
if (strDay.charAt(0)=="0" && strDay.length>1) strDay=strDay.substring(1)
if (strMonth.charAt(0)=="0" && strMonth.length>1) strMonth=strMonth.substring(1)
for (var i = 1; i <= 3; i++) {
if (strYr.charAt(0)=="0" && strYr.length>1) strYr=strYr.substring(1)
}
month=parseInt(strMonth)
day=parseInt(strDay)
year=parseInt(strYr)
if (pos1==-1 || pos2==-1){
alert("The date format should be : mm/dd/yyyy")
return false
}
if (strMonth.length<1 || month<1 || month>12){
alert("Please enter a valid month")
return false
}
if (strDay.length<1 || day<1 || day>31 || (month==2 && day>daysInFebruary(year)) || day > daysInMonth[month]){
alert("Please enter a valid day")
return false
}
if (strYear.length != 4 || year==0 || year<minYear || year>maxYear){
alert("Please enter a valid 4 digit year between "+minYear+" and "+maxYear)
return false
}
if (dtStr.indexOf(dtCh,pos2+1)!=-1 || isInteger(stripCharsInBag(dtStr, dtCh))==false){
alert("Please enter a valid date")
return false
}
return true
}
function ValidateForm(){
var dt=document.option_lookup.date
if (isDate(dt.value)==false){
dt.focus()
return false
}
return true
}
</script>
</head>
<body>
<form name="option_lookup" action="Track_Investments.php" method="post" onsubmit="return ValidateForm()" >
<table>
<tr><td>Symbol:</td><td><input type="text" name="symbol" value="VTI" /></td></tr>
<tr><td>Date Initiated:</td><td><input type="text" name="date" value="10/06/2006" /></td></tr>
<tr><td><input type="radio" name="close_type" value="Adj Close" checked /> Adj Close</td><td> </td></tr>
<tr><td><input type="radio" name="close_type" value="Close" /> Close</td><td> </td></tr>
</table>
<input type="submit" value="Generate Chart" /><br />
</form>
</body>
</html>
<?php
}
else
{
// -------------------------STEP TWO----------------------------
// -------------------------------------------------------------
// ------ pull the data from the form ------
ob_implicit_flush(true);
ob_end_flush();
header("Expires: Tue, 01 Jan 2000 00:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
include_once("$function_path/YahooStockQuote.inc");
include_once("$function_path/YahooHistoricalStockQuote.inc");
function this_or_prior_weekday($input_date)
{
$dateparts = getdate($input_date);
$return_date = $input_date;
if ($dateparts['weekday'] == "Sunday") $return_date = strtotime("-2 days", $input_date);
if ($dateparts['weekday'] == "Saturday") $return_date = strtotime("-1 day", $input_date);
if (date("M d", $return_date) == "Dec 25" || date("M d", $return_date) == "Jan 01" || date("M d", $return_date) == "Jul 04")
$return_date = this_or_prior_weekday(strtotime("-1 day", $return_date));
return $return_date;
}
function this_or_following_weekday($input_date)
{
$dateparts = getdate($input_date);
$return_date = $input_date;
if ($dateparts['weekday'] == "Sunday") $return_date = strtotime("+1 day", $input_date);
if ($dateparts['weekday'] == "Saturday") $return_date = strtotime("+2 days", $input_date);
if (date("M d", $return_date) == "Dec 25" || date("M d", $return_date) == "Jan 01" || date("M d", $return_date) == "Jul 04")
$return_date = this_or_following_weekday(strtotime("+1 day", $return_date));
return $return_date;
}
// extract $_POST values
$symbol = strtoupper($_POST['symbol']);
$start_date = strtotime($_POST['date']);
$close_type = $_POST['close_type'];
$start_dt = $_POST['date'];
$chart_title = "$symbol from $start_dt";
// ------ figure out which dates to plot -------
// how many points on the absicssa?
$num_of_points_on_xaxis = 25;
// figure out the dates to get data for
$num_days_total = floor(abs(time() - $start_date)/(60*60*24));
$date_increment = floor($num_days_total / $num_of_points_on_xaxis) + 1;
if ($date_increment == 1) $date_increment = "+" . $date_increment . " Day";
else $date_increment = "+" . $date_increment . " Days";
if ($num_days_total < $num_of_points_on_xaxis) $num_of_points_on_xaxis = $num_days_total;
$date_array[0] = this_or_prior_weekday($start_date);
for ($i = 1; $i <= $num_of_points_on_xaxis-2; $i++)
{
if (this_or_following_weekday(strtotime($date_increment, $date_array[$i-1])) > time()) break;
$date_array[$i] = this_or_following_weekday(strtotime($date_increment, $date_array[$i-1]));
}
$end_date = date('l m/d/Y',end($date_array));
$nxt_date = date('l m/d/Y',this_or_prior_weekday(time()));
if ($end_date <> $nxt_date) $date_array[$i] = strtotime($nxt_date);
for ($i = 0; $i < count($date_array) - 1; $i++)
{
$this_date = $date_array[$i];
$quote = YahooHistoricalStockQuote($symbol, $this_date);
$price_quote = $quote[$close_type];
while ($price_quote == '' || $price_quote == '0' || $price_quote == 0):
$this_date = this_or_following_weekday(strtotime("+1 day",$this_date));
$quote = YahooHistoricalStockQuote($symbol,$this_date );
$price_quote = $quote[$close_type];
endwhile;
$data[$date_array[$i]] = $price_quote;
if ($i == 0)
{
// calculated prices for chart
$first_price = $quote[$close_type];
$cost_minus_five_pct = $price_quote * 0.95;
$cost_breakeven = $price_quote * 1.00;
$cost_plus_ten_pct = $price_quote * 1.10;
$cost_plus_twenty_pct = $price_quote * 1.20;
}
}
$last_price = YahooStockQuote(array($symbol));
$data[$date_array[$i]] = $last_price[$symbol]['LastTradePriceOnly'];
foreach ($data as $date => $closing_price)
{
$dates[] = date('m-d-y',$date);
$prices[] = $closing_price;
}
/* CAT:Line chart */
/* pChart library inclusions */
include("../class/pData.class.php");
include("../class/pDraw.class.php");
include("../class/pImage.class.php");
/* Create and populate the pData object */
$MyData = new pData();
$MyData->addPoints($prices,$close_type);
$MyData->addPoints($dates,"Labels");
$MyData->setSerieDescription("Labels","Dates");
$MyData->setAbscissa("Labels");
/* Create the pChart object */
$myPicture = new pImage(700,500,$MyData);
/* Write the chart title */
$myPicture->setFontProperties(array("FontName"=>"../fonts/calibri.ttf","FontSize"=>11));
$myPicture->drawText(150,35,$chart_title,array("FontSize"=>20,"Align"=>TEXT_ALIGN_BOTTOMMIDDLE));
/* Set the default font */
$myPicture->setFontProperties(array("FontName"=>"../fonts/calibri.ttf","FontSize"=>10));
/* Define the chart area */
$myPicture->setGraphArea(60,40,650,350);
/* Draw the scale */
$myPicture->drawScale(array('LabelRotation'=>45,"AxisR"=>255,"AxisG"=>255,"AxisB"=>255,"DrawSubTicks"=>TRUE,"CycleBackground"=>TRUE));
/* Write thresholds over the chart */
$myPicture->drawThreshold($cost_breakeven,array("Ticks"=>1,"WriteCaption"=>FALSE,"Caption"=>"breakeven"));
$myPicture->drawThreshold($cost_minus_five_pct,array("WriteCaption"=>TRUE,"Caption"=>"-5%"));
$myPicture->drawThreshold($cost_plus_ten_pct,array("WriteCaption"=>TRUE,"Caption"=>"+10%"));
$myPicture->drawThreshold($cost_plus_twenty_pct,array("WriteCaption"=>TRUE,"Caption"=>"+20%"));
/* Draw the line chart */
$myPicture->drawLineChart();
/* Write the chart legend */
$myPicture->drawLegend(410,20,array("Style"=>LEGEND_NOBORDER,"Mode"=>LEGEND_HORIZONTAL));
/* Render the picture (choose the best way) */
$myPicture->Stroke();
}
?>
Originally published: Wednesday, January 02, 2013; most-recently modified: Friday, May 31, 2019