/*
Stock ticker converter by Thomas Christensen (tc@tc.dk)
Inspired by Xanadb's stock RSS : http://www.xanadb.com/archive/perl/20030617
Released under the Creative Commons Attribution-NonCommercial-ShareAlike License.
http://creativecommons.org/licenses/by-nc-sa/2.0/
The goal is to create a flexible and versatile stock RSS feed, default options should
provide a useful and
Contact me if you make any changed that you want added to the main version
Install:
1. Added stock.php to a server that support php4 or better
2. if you want to use the fulltitle option, the script needs write rights
3. That's it
Usage:
read more here: http://blog.tc.dk/item/8
http://tc.dk/stock.php?symbols=mfts:100:100+csco:200:200&total=yes&title=My%20Stock&timedif=6&link=no
symbols=mfts:100:200+csco:300:400, displays two rows of information for microsoft and cisco, calculating totals for a 100 msft stocks aquired at value 200 and 300 cisco stocks gotten at value 400. You don't have to supply the last two numbers.
total=yes, means that an extra item with total for all stocks will be added. Default=no
title=My%20Stock, changes the title of the feed. Replace all spaces with %20.
timedif=6, how many hours ahead or behind you are compared to yahoo (+6=european central)
link=no, should the items link to yahoo. Some programs (Thunderbird v1.0) uses as guid, even if the guid is there, making it impossible to get it to update, even if the guid changes. Remove the link to solv problem. default=yes
randomlink=yes, added a random part to the link, in the attempt of fooling the rss reader to think that it's a new item. Default=no
onlytotal=yes, only create the total item. Default no.
graph=[yes,1ds,1d,5d,3m,6m,1y,2y,5y,my] adds one or more links to graphs displaying [1 day small, 1 day, 5 day, 3 month, 6 month, 1 year, 2 year, 5 year or max year].It's possible to specify more that on graph by seperating them with comma or +: graph=1d+1y for the 1 day and 1 year graphs. The old option "yes" will display the 1ds (1 Day Small) graph
fulltitle=yes uses the full title of the company if possible. Defalut no.
titlenoshort=no forces fulltitle=yes and only uses the fulltitle on the headlines (makes them a bit shorter).
titlenovalue=no removed the day value from the title
titlenochange=no removed the day change value from the title
Version history:
2005-11-23 - 0.0.8:
* Added multi graph options as suggested and researched by "ttys0", this uses the bigger graphs that yahoo supplies
* you can now split symbols by either , or +
* max number of symbols is now 20
* Changed the note
2005-11-09 - 0.0.7:
* Fixed the change procentage to be based on aqusition value.
* Changed the code that get the fulltitle so that it works with the new yahoo layout.
* Fixed it so that values are only added to total if both count and aquire value is given.
* updated the header url
* added a $noteheader and a $notebody vars to the init part. Write something in the
header variable and an extra item will be written with the message. Currently
used to warn about the change in diff calculation.
* added titlenochange - which will remove the (+.23) part of the title.
I really should make at a formatting variable ...
2005-07-27 - 0.0.6:
* Added leaching blocker. A file called stock.leach.php is written that
contains the unix time (seconds since some data) since that ip address
last requested a quote. It is less than 20 minuts an error message is returned,
tell people to stop leaching...
2005-01-31 - 0.0.5:
* fixed stupid reusage of the $data variable
2005-01-21 - 0.0.4:
* fixed version number
* added time-to-live ttl 20 minuts metadata
* added graph option
* added caching of full symbol title (needs write access to server file)
* added the fulltitle option
* cleaned up the printitem function, made the disclaimer optional
* added a bit of sanity check on the symbol size and for unknown symbols
2005-01-15 - 0.0.3:
* added information for no parameters
* added more meta/header information
2005-01-14 - 0.0.2:
* added randomlink option
* added onlytotal option
* added more information to the total item (so it's useful on its own)
* fixed warning at blank title
* fixed some division by zero error (don't try to calc values when impossible)
2005-01-13 - 0.0.1:
* First version (TC)
To-Do list:
* The time stuff aren't correct, in the total local server time is used
* Some kind of caching might be nice
* More options on what to include
* Maybe somekind of expire might be a good idea
* Make a more flexible title and page formatting system
*/
$version='0.0.8';
#putenv('TZ='.$_SESSION[PROFILE_TZOFFSET]);
$noteheader='';
$notebody='It\' now possible to specify that you want more graphs graph=1d,5d,5y will give you one 1 day, 5 day and 5 year graphs. See the site for more info http://blog.tc.dk/item/8 ';
@include('stock.dat.php');
function rssheader()
{
global $version;
if (isset($_GET['title']))
$title=$_GET['title'];
else
$title='Yahoo Stock To Rss';
print ''.$title.'
http://blog.tc.dk/item/8
http://blogs.law.harvard.edu/tech/rssSaturdaySundayFinanceYStockToRSS v'.$version.'tc@tc.dken-usStock Ticker and Portfolio Watcher via RSS20
';
}
function rssfooter()
{
print '';
}
function printitem($title, $link='', $desc='no-text', $time='', $guid='', $disclaimer=true)
{
// prints one item
if ($link!='')
{
if ((isset($_GET['link'])) and ($_GET['link']=='no'))
$link='';
else
if ((isset($_GET['randomlink'])) and ($_GET['randomlink']=='yes'))
$link .= '&random='.rand(1,9999999);
}
print '';
print ''.$title.'';
if ($link!='')
print ''.$link.'';
if ($guid!='')
print ''.$link.'';
// print ''.$guid.'';
if ($time!='')
print ''.date('r',$time).'';
print ''.htmlentities($desc);
if ($disclaimer)
print htmlentities('
Delayed data gathered from finance.yahoo.com.');
print '';
print "\n";
}
function getyahoostockprice($symbol)
{
//stock quote script inspired by http://tutorials.programmingsite.co.uk/yahoocsv.php
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, "http://finance.yahoo.com/d/quotes.csv?s=".$symbol."&f=sl1d1t1c1ohgv&e=.csv");
curl_setopt ($ch, CURLOPT_HEADER, false);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 5);
$content = curl_exec($ch);
curl_close($ch);
$data = array();
$data = explode(",", $content);
$data[0] = str_replace("\"", "", $data[0]);
$data[2] = str_replace("\"", "", $data[2]);
$data[3] = str_replace("\"", "", $data[3]);
// data[0]=symbol
// data[1]=last price
// data[2]=date
// data[3]=time
// data[4]=change
// data[5]=open price
// data[6]=day high price
// data[7]=day low price
// data[8]=trade volume
return $data;
}
function isleach()
{
$visitorip = $_SERVER['REMOTE_ADDR'];
if ($visitorip=='209.217.115.86')
return true;
else
return false;
@include('stock.leach.php');
if (isset($lastvisit[$visitorip]))
{
if ($lastvisit[$visitorip]<(time()-(19*60)))
$retval= false;
else
$retval= true;
} else
{
$retval=false;
}
$lastvisit[$visitorip]=time();
$wf = fopen('stock.leach.php', 'w');
if ($wf)
{
// save the last visit times but only if they are from with in the last 24 hours
fwrite($wf, " $svalue)
if ($svalue>(time()-(24*60*60)))
fwrite($wf, ' $lastvisit[\''.$skey.'\']=\''.$svalue.'\';'."\n\r");
fwrite($wf, '?>');
}
return $retval;
}
// main part of code
if (isset($_GET['symbols'])) // any parameters we care about?
{
header('Content-Type: text/xml');
rssheader();
if ($noteheader!='')
printitem($noteheader,'http://blog.tc.dk/item/8',$notebody,'','',false);
if (isleach())
{
printitem('STOP LEACHING','',"You are getting this message because you've requested a stock quote twice within 20 minuts. DON'T DO THAT. There's a TimeToLive 20 minuts in the RSS and if you or your RSS program can't honour that you'll need to run your own server. Oh, and shame on you - somebody goes to a lot of trouble to set up a free service and you abuse it.", '','', false);
}
else
{
// initialize and do each symbol
$sym = split('[,+ ]', $_GET['symbols'],20);
$totaq=0;
$totcur=0;
$totdif=0;
$maxdate=0;
$totalstr='SYMBOL: Current - Acquisition = value ';
if ((isset($_GET['fulltitle'])) and ($_GET['fulltitle']=='yes'))
$fulltitle=true;
else
$fulltitle=false;
if ((isset($_GET['titlenoshort'])) and ($_GET['titlenoshort']=='yes'))
$titlenoshort=true;
else
$titlenoshort=false;
if ($titlenoshort)
$fulltitle=true;
if ((isset($_GET['titlenovalue'])) and ($_GET['titlenovalue']=='yes'))
$titlenovalue=true;
else
$titlenovalue=false;
if ((isset($_GET['titlenochange'])) and ($_GET['titlenochange']=='yes'))
$titlenochange=true;
else
$titlenochange=false;
foreach($sym as $key => $value)
{
$data = split('[:]', $value,3);
// Print_r($data);
if ((isset($data[0])) and (trim($data[0])!='') and (strlen($data[0])<20)) // do we have a symbol name?
{
$symbol=$data[0];
$title='';
if ($fulltitle)
{
if (!isset($symboldata[$symbol]))
{
$fp = fopen ("http://finance.yahoo.com/q?s=".$symbol,"r");
if ($fp)
{
$d='';
while (!feof($fp))
{
$d .= fread($fp, 8192);
}
$startstr='('.strtoupper($symbol).')';
$endstr=' (';
$end = strpos($d, $startstr)-1;
if ($end>0)
{
$start=$end;
while ((substr($d, $start, 1)!='>') and ($start>0)) // run until we find the first tag
$start = $start - 1;
$start = $start+1;
if (($end-$start)<100) // sanity check
$title = substr($d, $start, $end-$start);
}
}
if ($title!='')
{
$symboldata[$symbol]=$title;
$wf = fopen('stock.dat.php', 'w');
if ($wf)
{
fwrite($wf, " $svalue)
fwrite($wf, ' $symboldata[\''.$skey.'\']=\''.$svalue.'\';'."\n\r");
fwrite($wf, '?>');
}
}
} else
{
$title = $symboldata[$symbol];
}
}
if (isset($data[1])) // is there a count of stock?
$count=$data[1];
else
$count=0;
if (isset($data[2])) // is there a cost for the stock?
$cost=$data[2];
else
$cost=0;
$data=getyahoostockprice($symbol); // get from yahoo
if ($data[1]>0)
{
// calc values and totals
$aq=($cost*$count);
$cur=($data[1]*$count);
$dif=($cur-$aq);
if (($aq>0) and ($count>0))
{ // only update total if we have both aquire and count values
$totaq +=$aq;
$totcur +=$cur;
$totdif +=$dif;
}
if (($cur>0) and ($aq>0))
$totalstr .= $data[0].':'.$cur.'-'.$aq.'='.$dif.' ('.number_format((($dif/$aq)*100),2).'%) ';
if (isset($_GET['timedif']))
$dat = strtotime($data[2].' '.$data[3]) + $_GET['timedif']*3600;
else
$dat = strtotime($data[2].' '.$data[3]);
if ($dat>$maxdate) // we need the latest trade time
$maxdate=$dat;
if ((isset($_GET['totalonly'])) and ($_GET['totalonly']=='yes'))
$desc='';
else
{
// build the description sting
$desc='Today:';
if ($data[5]>0)
$desc.=' Open price:'.$data[5];
if ($data[6]>0)
$desc.=' High price:'.$data[6];
if ($data[7]>0)
$desc.=' Low price:'.$data[7];
if ($data[1]>0)
$desc.=' Last price:'.$data[1];
if ($data[8]>0)
$desc.=' Volume:'.$data[8];
if ($dat>0)
$desc .= ' Trade date: '.date('r',$dat);
if (($count>0) and ($cost>0))
$desc .= ' Value:'.
' Acquisition: '.$aq . ' ('.$count.' at '.$cost.')'.
' Current: '.$cur. ' ('.$count.' at '.$data[1].')';
if ($aq>0)
$desc .= ' Difference: '.$dif.' ('.number_format((($dif/$aq)*100),2).'%)';
if (($count>0) and ($cost>0))
$desc .= ' Count: '.$count;
$header = ' '; break;
case '1d': $graphstr .= $header.'w?b='.$symbol.'" alt="[1d Chart]" border="0" />'; break;
case '5d': $graphstr .= $header.'w?s='.$symbol.'" alt="[5d Chart]" border="0" />'; break;
case '3m': $graphstr .= $header.'c/3m/0/'.$symbol.'" alt="[3m Chart]" border="0" />'; break;
case '6m': $graphstr .= $header.'c/6m/0/'.$symbol.'" alt="[6m Chart]" border="0" />'; break;
case '1y': $graphstr .= $header.'c/1y/0/'.$symbol.'" alt="[1y Chart]" border="0" />'; break;
case '2y': $graphstr .= $header.'c/2y/0/'.$symbol.'" alt="[2y Chart]" border="0" />'; break;
case '5y': $graphstr .= $header.'c/5y/0/'.$symbol.'" alt="[5y Chart]" border="0" />'; break;
case 'my': $graphstr .= $header.'c/my/0/'.$symbol.'" alt="[my Chart]" border="0" />'; break;
}
}
if ($graphstr!='')
$desc .= $graphstr;
}
if ($title=='')
$title=$data[0];
else
if (!$titlenoshort)
$title .= ' ('.$data[0].')';
if (!$titlenovalue)
$title .= ' - '.$data[1];
if (!$titlenochange)
$title .= ' ('.$data[4].')';
printitem($title, // title= symbol - value (change)
'http://finance.yahoo.com/q?s='.$data[0], // link to yahoo
$desc,
$dat,
$data[0].$dat);
} // totalonly
} else
{
printitem($symbol.' is unknown!','','','','',false);
}
}
}
// done with the individual items
if (isset($_GET['total']) and ($_GET['total']=='yes')) // do we want a total?
{
if ($totcur>0)
$procentage=($totdif/$totaq);
else
$procentage=0;
$totalstr .= ' Total: '.$totcur.'-'.$totaq.'='.$totdif. ' ('.number_format($procentage*100,2).'%)';
if (($totcur==0) or ($totaq==0))
$totalstr='Can\'t calculate totals without stock count and acquisition price.
See: http://blog.tc.dk/2005/01/yahoo-stock-to-rss-converter.php for more information';
printitem('Total',
'',
$totalstr,
$maxdate, // build the guid as the latest trade time
'');
}
} // isleach
rssfooter();
} else
{
header('Content-Type: text/xml');
rssheader();
printitem('Yahoo Stock to RSS',
'http://blog.tc.dk/2005/01/yahoo-stock-to-rss-converter.php',
'You need to add some parameter to the address of this RSS feed, read more here: http://blog.tc.dk/2005/01/yahoo-stock-to-rss-converter.php',
'',
'',
false);
rssfooter();
}
?>