Edit file File name : Tiaacref.pm Content :#!/usr/bin/perl -w # # Copyright (C) 1998, Dj Padzensky <djpadz@padz.net> # Copyright (C) 1998, 1999 Linas Vepstas <linas@linas.org> # Copyright (C) 2000, Yannick LE NY <y-le-ny@ifrance.com> # Copyright (C) 2000, Paul Fenwick <pjf@cpan.org> # Copyright (C) 2000, Brent Neal <brentn@users.sourceforge.net> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA # # # This code derived from Padzensky's work on package Finance::YahooQuote, # but extends its capabilites to encompas a greater number of data sources. # # This code was developed as part of GnuCash <http://www.gnucash.org/> package Finance::Quote::Tiaacref; require 5.005; use strict; use Encode qw/decode/; use Time::Piece; use Time::Seconds; use Try::Tiny; our $VERSION = '1.51'; # VERSION # URLs of where to obtain information. my $TIAA_MAIN_URL = 'https://www.tiaa.org/public/investment-performance'; my $TIAA_DATA_URL = 'https://www.tiaa.markitondemand.com/Research/Public/Export/Details'; sub methods { return (tiaacref=>\&tiaacref); } sub labels { return (tiaacref => [qw/ method symbol exchange name date isodate nav price currency /]); } # ======================================================================= # TIAA-CREF Annuities are not listed on any exchange, unlike their mutual funds # TIAA-CREF provides unit values via a cgi on their website. The cgi returns # a csv file in the format # description,price1,date1 # description,price2,date2 # ..etc. # As of 11-Oct-2020, the following securities are found in their lookup # service. Data for some of these are available elsewhere and some are not: # QCBMIX QCBMPX QCBMRX QCEQIX QCEQPX QCEQRX QCGLIX QCGLPX QCGLRX # QCGRIX QCGRPX QCGRRX QCILIX QCILPX QCILRX QCMMIX QCMMPX QCMMRX # QCSCIX QCSCPX QCSCRX QCSTIX QCSTPX QCSTRX QREARX TAISX TAIWX # TBBWX TBIAX TBIIX TBILX TBIPX TBIRX TBIWX TBPPX TCBHX # TCBPX TCBRX TCBWX TCCHX TCEPX TCFPX TCHHX TCHPX TCIEX # TCIHX TCIIX TCILX TCIWX TCIXX TCLCX TCLEX TCLFX TCLHX # TCLIX TCLNX TCLOX TCLPX TCLRX TCLTX TCMGX TCMHX TCMVX # TCNHX TCNIX TCOIX TCQHX TCQPX TCREX TCRIX TCSEX TCSIX # TCTHX TCTIX TCTPX TCTRX TCTWX TCWHX TCWIX TCWPX TCYHX # TCYIX TCYPX TCZHX TCZPX TECGX TECWX TEDHX TEDLX TEDNX # TEDPX TEDTX TEDVX TEIEX TEIHX TEIWX TELCX TELWX TEMHX # TEMLX TEMPX TEMRX TEMSX TEMVX TENWX TEQHX TEQKX TEQLX # TEQPX TEQSX TEQWX TESHX TEVIX TEWCX TFIHX TFIIX TFIPX # TFIRX TFITX TFTHX TFTIX TGIHX TGIWX TGRKX TGRLX TGRMX # TGRNX TGROX THCVX THCWX TIBDX TIBEX TIBFX TIBHX TIBLX # TIBNX TIBUX TIBVX TIBWX TICHX TICRX TIDPX TIDRX TIEHX # TIEIX TIERX TIEWX TIEXX TIGRX TIHHX TIHPX TIHRX TIHWX # TIHYX TIIEX TIIHX TIILX TIIRX TIISX TIIWX TIKPX TIKRX # TILGX TILHX TILIX TILPX TILRX TILVX TILWX TIMIX TIMRX # TIMVX TINRX TIOHX TIOIX TIOPX TIORX TIOSX TIOTX TIOVX # TIQRX TIREX TIRHX TIRTX TIRXX TISAX TISBX TISCX TISEX # TISIX TISPX TISRX TISWX TITIX TITRX TIXHX TIXRX TIYRX # TLFAX TLFIX TLFPX TLFRX TLGRX TLHHX TLHIX TLHPX TLHRX # TLIHX TLIIX TLIPX TLIRX TLISX TLLHX TLLIX TLLPX TLLRX # TLMHX TLMPX TLMRX TLPRX TLQHX TLQIX TLQRX TLRHX TLRIX # TLRRX TLSHX TLSPX TLSRX TLTHX TLTIX TLTPX TLTRX TLVPX # TLWCX TLWHX TLWIX TLWPX TLWRX TLXHX TLXIX TLXNX TLXPX # TLXRX TLYHX TLYIX TLYPX TLYRX TLZHX TLZIX TLZRX TMHXX # TNSHX TNWCX TPILX TPISX TPPXX TPSHX TPWCX TRBIX TRCIX # TRCPX TRCVX TREPX TRERX TRGIX TRGMX TRGPX TRHBX TRIEX # TRIHX TRILX TRIPX TRIRX TRIWX TRLCX TRLHX TRLIX TRLWX # TRPGX TRPSX TRPWX TRRPX TRRSX TRSCX TRSEX TRSHX TRSPX # TRVHX TRVPX TRVRX TSAHX TSAIX TSALX TSAPX TSARX TSBBX # TSBHX TSBIX TSBPX TSBRX TSCHX TSCLX TSCTX TSCWX TSDBX # TSDDX TSDFX TSDHX TSDJX TSFHX TSFPX TSFRX TSFTX TSGGX # TSGHX TSGLX TSGPX TSGRX TSIHX TSILX TSIMX TSIPX TSITX # TSMEX TSMHX TSMLX TSMMX TSMNX TSMOX TSMPX TSMTX TSMUX # TSMWX TSOEX TSOHX TSONX TSOPX TSORX TSRPX TSTPX TTBHX # TTBWX TTFHX TTFIX TTFPX TTFRX TTIHX TTIIX TTIPX TTIRX # TTISX TTRHX TTRIX TTRLX TTRPX TVIHX TVIIX TVIPX TVITX # W111# W113# W114# W115# W116# W117# W118# W119# W120# # W121# W122# W123# W128# W130# W131# W132# W133# W134# # W135# W136# W137# W138# W139# W140# W141# W142# W143# # W144# W145# W146# W147# W148# W149# W150# W151# W152# # W153# W154# W155# W156# W157# W158# W159# W160# W161# # W162# W163# W164# W165# W166# W167# W168# W169# W170# # W171# W172# W173# W174# W175# W176# W177# W178# W179# # W180# W211# W213# W214# W215# W216# W217# W218# W219# # W220# W221# W222# W223# W228# W230# W231# W232# W233# # W234# W235# W236# W237# W238# W239# W240# W241# W242# # W243# W244# W245# W246# W247# W248# W249# W250# W251# # W252# W253# W254# W255# W256# W257# W258# W259# W260# # W261# W262# W263# W264# W265# W266# W267# W268# W269# # W270# W271# W272# W273# W274# W275# W276# W277# W278# # W279# W280# W311# W313# W314# W315# W316# W317# W318# # W319# W320# W321# W322# W323# W328# W330# W331# W332# # W333# W334# W335# W336# W337# W338# W339# W340# W341# # W342# W343# W344# W345# W346# W347# W348# W349# W350# # W351# W352# W353# W354# W355# W356# W357# W358# W359# # W360# W361# W362# W363# W364# W365# W366# W367# W368# # W369# W370# W371# W372# W373# W374# W375# W376# W377# # W378# W379# W380# W411# W413# W414# W415# W416# W417# # W418# W419# W420# W421# W422# W423# W428# W430# W431# # W432# W433# W434# W435# W436# W437# W438# W439# W440# # W441# W442# W443# W444# W445# W446# W447# W448# W449# # W450# W451# W452# W453# W454# W455# W456# W457# W458# # W459# W460# W461# W462# W463# W464# W465# W466# W467# # W468# W469# W470# W471# W472# W473# W474# W475# W476# # W477# W478# W479# W480# W511# W512# W514# W515# W516# # W517# W518# W519# W520# W521# W522# W523# W524# W525# # W526# W527# W528# W529# W530# W531# W532# W533# W534# # W535# W536# W537# W538# W539# W540# W541# W543# W544# # W545# W546# W547# W548# W549# W550# W611# W612# W614# # W615# W616# W617# W618# W619# W620# W621# W622# W623# # W624# W625# W626# W627# W628# W629# W630# W631# W632# # W633# W634# W635# W636# W637# W638# W639# W640# W641# # W643# W644# W645# W646# W647# W648# W649# W650# W711# # W712# W714# W715# W716# W717# W718# W719# W720# W721# # W722# W723# W724# W725# W726# W727# W728# W729# W730# # W731# W732# W733# W734# W735# W736# W737# W738# W739# # W740# W741# W743# W744# W745# W746# W747# W748# W749# # W750# W811# W812# W814# W815# W816# W817# W818# W819# # W820# W821# W822# W823# W824# W825# W826# W827# W828# # W829# W830# W831# W832# W833# W834# W835# W836# W837# # W838# W839# W840# W841# W843# W844# W845# W846# W847# # W848# W849# W850# # # This subroutine was written by Brent Neal <brentn@users.sourceforge.net> # Modified to support new TIAA-CREF webpages by Kevin Foss <kfoss@maine.edu> and Brent Neal # Modified to support new 2012 TIAA-CREF webpages by Carl LaCombe <calcisme@gmail.com> # Modified to support new 2020 TIAA webpages by Jeremy Volkening # # TODO: # # The TIAA-CREF cgi allows you to specify the exact dates for which to retrieve # price data. That functionality could be worked into this subroutine. # Currently, we only grab the most recent price data. # sub tiaacref { my $quoter = shift; my @symbols = @_; return unless scalar @symbols; my %info; my $ua = $quoter->user_agent; # The TIAA data service wants a start and end date. To guarantee data, # ask for 7 days of quotes, and only take the first (most recent) one. my $end = localtime; my $start = $end - ONE_WEEK; #Need to fetch a session key first my $session_key; my $fail_msg; my $res = $ua->get( $TIAA_MAIN_URL ); if (! $res->is_success) { $fail_msg = "Failed to fetch TIAA page from $TIAA_MAIN_URL. It may be" . " that the link has changed. HTTP status returned: " . $res->status_line; } else { if ($res->content =~ /\bMODKey=\'([^']+)'/) { $session_key = $1; } else { $fail_msg = "Failed to fetch session key from TIAA site. Please" . " contact the developers for further assistance." } } if (defined $fail_msg) { for my $symbol (@symbols) { $info{ $symbol, "success" } = 0; $info{ $symbol, "errormsg" } = $fail_msg; } return %info if wantarray; return \%info; } SYMBOL: for my $symbol (@symbols) { my $payload = { xids => [$symbol], exportType => 'CSV', startDate => $start->mdy, endDate => $end->mdy, selectedDetails => '', }; my $url = join '?', $TIAA_DATA_URL, $session_key, ; my $res = $ua->post($url, $payload); if (! $res->is_success) { $info{ $symbol, "success" } = 0; $info{ $symbol, "errormsg" } = "There was an error fetching data" . " for $symbol. HTTP status returned: " . $res->status_line; next SYMBOL; } # Data returned is in UTF-16-encoded CSV. As we asked for a week of # data, successful queries will likely return multiple lines, but they # are sorted in descending chronological order so we can just take # the first one. my $csv = decode( 'UTF-16LE', $res->content ); open my $stream, '<', \$csv; while (my $line = <$stream>) { chomp $line; my ($description, $price, $date) = split ',', $line; # if no data is found for the given symbol, no error is thrown # but the content returned contains a textual error message. In # this case, the latter fields will not be defined. if (! defined $date) { $info{ $symbol, "success" } = 0; $info{ $symbol, "errormsg" } = "Error retrieving quote for $symbol - no listing for this" . " name found. Please check symbol and the two letter" . " extension (if any)"; next SYMBOL; } try { $date = Time::Piece->strptime($date, "%m/%d/%Y"); } catch { $info{ $symbol, "success" } = 0; $info{ $symbol, "errormsg" } = "Error parsing date ($date) for $symbol. Please" . " contact the developers for further assistance."; next SYMBOL; }; $info{ $symbol, "success" } = 1; $info{ $symbol, "symbol" } = $symbol; $info{ $symbol, "exchange" } = "TIAA"; $info{ $symbol, "name" } = $description; $info{ $symbol, "nav" } = $price; $info{ $symbol, "price" } = $info{$symbol, "nav"}; $info{ $symbol, "currency" } = "USD"; $info{ $symbol, "method" } = "tiaacref"; $info{ $symbol, "isodate" } = $date->ymd; $info{ $symbol, "date" } = $date->mdy('/'); $quoter->store_date( \%info, $symbol, {isodate => $date->ymd} ); last; # IMPORTANT: don't parse older data! } } return %info if wantarray; return \%info; } 1; =head1 NAME Finance::Quote::Tiaacref - Obtain quote from TIAA (formerly TIAA-CREF) =head1 SYNOPSIS use Finance::Quote; $q = Finance::Quote->new; %stockinfo = $q->fetch("tiaacref","TIAAreal"); =head1 DESCRIPTION This module obtains information about TIAA-CREF managed funds. This module is loaded by default on a Finance::Quote object. It's also possible to load it explicitly by passing "Tiaacref" in to the argument list of Finance::Quote->new(). Information returned by this module is governed by TIAA's terms and conditions. =head1 LABELS RETURNED The following labels may be returned by Finance::Quote::Tiaacref: symbol, exchange, name, date, nav, price. =head1 SEE ALSO TIAA, L<http://www.tiaa.org> =cut Save