Ticket #3621: sage-3621-extrapart1.patch

File sage-3621-extrapart1.patch, 36.6 KB (added by cswiercz, 13 years ago)

Added Yahoo Finance as a backup to Google Finance historical requests. Additional refinements.

  • sage/finance/all.py

    # HG changeset patch
    # User Chris Swierczewski <cswiercz@gmail.com>
    # Date 1218588365 25200
    # Node ID 759492c407b722a985ed40361a3e9d499c533114
    # Parent  d3fe688b1cf71619f33d3c25562d3343caf6a1c0
    finance.Stock().historical() will now use Yahoo Finance as a backup to Google Finance. Added various refinements and features to finance.Stock.
    
    diff -r d3fe688b1cf7 -r 759492c407b7 sage/finance/all.py
    a b from stock import Stock 
    11from stock import Stock
     2
     3from datetime import date
    24
    35from markov_multifractal import MarkovSwitchingMultifractal
    46
     7from datetime import datetime
    58from time_series import TimeSeries, autoregressive_fit
    69
    710from fractal import (stationary_gaussian_simulation,
  • sage/finance/stock.py

    diff -r d3fe688b1cf7 -r 759492c407b7 sage/finance/stock.py
    a b TESTS: 
    1414
    1515import urllib
    1616from sage.structure.all import Sequence
    17 from datetime import date
     17from datetime import datetime
    1818
    1919class OHLC:
    2020    def __init__(self, timestamp, open, high, low, close, volume):
    class OHLC: 
    2828            volume -- int
    2929
    3030        EXAMPLES:
    31             sage: sage.finance.stock.OHLC('18-Aug-04', 100.01, 104.06, 95.96, 100.34, 22353092)
    32              18-Aug-04 100.01 104.06 95.96 100.34   22353092
     31            sage: sage.finance.stock.OHLC('2004-8-18', 100.01, 104.06, 95.96, 100.34, 22353092)
     32            2004-8-18 100.01 104.06 95.96 100.34   22353092
    3333        """
    3434        self.timestamp = timestamp
    3535        self.open=float(open); self.high=float(high); self.low=float(low); self.close=float(close)
    class OHLC: 
    4040        Return string representation of stock OHLC data.
    4141
    4242        EXAMPLES:
    43             sage: sage.finance.stock.OHLC('18-Aug-04', 100.01, 104.06, 95.96, 100.34, 22353092).__repr__()
    44             ' 18-Aug-04 100.01 104.06 95.96 100.34   22353092'
     43            sage: sage.finance.stock.OHLC('2004-8-18', 100.01, 104.06, 95.96, 100.34, 22353092).__repr__()
     44            '2004-8-18 100.01 104.06 95.96 100.34   22353092'
    4545        """
    46         return '%10s %4.2f %4.2f %4.2f %4.2f %10d'%(self.timestamp, self.open, self.high,
     46        return '%s %4.2f %4.2f %4.2f %4.2f %10d'%(self.timestamp, self.open, self.high,
    4747                   self.low, self.close, self.volume)
    4848
    4949    def __cmp__(self, other):
    class OHLC: 
    5151        Compare self and other.
    5252
    5353        EXAMPLES:
    54             sage: ohlc = sage.finance.stock.OHLC('18-Aug-04', 100.01, 104.06, 95.96, 100.34, 22353092)
    55             sage: ohlc2 = sage.finance.stock.OHLC('18-Aug-04', 101.01, 104.06, 95.96, 100.34, 22353092)
     54            sage: ohlc = sage.finance.stock.OHLC('2004-8-18', 100.01, 104.06, 95.96, 100.34, 22353092)
     55            sage: ohlc2 = sage.finance.stock.OHLC('2004-8-18', 101.01, 104.06, 95.96, 100.34, 22353092)
    5656            sage: cmp(ohlc, ohlc2)
    5757            -1
    5858        """
    class Stock: 
    6666    Class for retrieval of stock market information.
    6767    """
    6868    def __init__(self, symbol, cid=''):
    69         """
    70         Create a Stock object. Optional initialization by cid: an identifier
    71         for each equity used by Google Finance.
     69        r"""
     70        The \code{finance.Stock} object retrieves and stores OHLC data for
     71        a stock. \code{Stock.historical()} requests this data from Google
     72        Finance and Yahoo Finance and OHLC data is then stored internally as
     73        a \code{Sequence} object.
     74
     75        Optionally, one can initialize by cid: an identifier for each equity
     76        used by Google Finance. This is useful for obtaining information on
     77        many equities.
    7278
    7379        INPUT:
    7480            symbol -- string, a ticker symbol (with or without market)
    7581                      format: "MARKET:SYMBOL" or "SYMBOL", if you don't
    7682                              supply the market, it is assumed to be
    77                               NYSE or NASDAQ.
    78                       eg. "goog" or "OTC:NTDOY"
    79             cid    -- Integer, a Google contract ID (optional)
     83                              NASDAQ or NYSE
     84                      eg. "goog" or "BE:BMW"
     85            cid    -- (optional) Integer, a Google contract ID
    8086
    8187        LIMITATIONS:
    8288            Currently, the symbol and cid do not have to match.  When using
    8389            google(), the cid will take precedence.
    8490
    8591        EXAMPLES:
     92        One can always retrieve the current stock price for the given equity
     93        buy simply evaluating the stock object itself or by calling
     94        \code{Stock.market_value()}:
    8695            sage: S = finance.Stock('ibm')
    87             sage: S        # optional -- requires internet, and random
    88             IBM (127.48)           
     96            sage: S                # optional -- requires internet, and random
     97            IBM (127.48)
     98            sage: S.market_value() # optional -- requires internet, and random
     99            IBM (127.48)
     100
     101        To retrive hsitorical data, use the Stock.historical() command. You
     102        can specify starting and ending dates. Otherwise, Stock.historical
     103        defaults to the past year of historical data:
     104            sage: S.historical(startdate='Jan 3,2000', enddate='Jan 7,2000')    # optional -- requires internet
     105            [
     106            2000-01-03T00:00:00 112.44 116.00 111.87 116.00   10347700,
     107            2000-01-04T00:00:00 114.00 114.50 110.87 112.06    8227800,
     108            2000-01-05T00:00:00 112.94 119.75 112.12 116.00   12733200,
     109            2000-01-06T00:00:00 118.00 118.94 113.50 114.00    7971900,
     110            2000-01-07T00:00:00 117.25 117.94 110.62 113.50   11856700
     111            ]
     112
     113        The above historical data is stored in memory for further use. For
     114        example, Stock.close() returns a TimeSeries object containing the
     115        closing prices of the above data. One can also specify new dates and
     116        retreive new OHLC data in this way:
     117            sage: S.close()    # optional -- requires internet
     118            [116.0000, 112.0600, 116.0000, 114.0000, 113.5000]
     119            sage: S.close('Jan 10, 2000', 'Jan 15, 2000')    # optional -- rewuires internet
     120            [118.0000, 119.0000, 119.5000, 118.2500, 119.6200]
    89121        """
    90         self.symbol = symbol.upper()
     122        symbols = symbol.split(':')
     123        if len(symbols) == 1:
     124            self.exchange = 'NASDAQ'
     125            self.symbol = symbols[0].upper()
     126        else:
     127            self.exchange = symbols[0].upper()
     128            self.symbol = symbols[1].upper()
    91129        self.cid = cid
    92130
    93131    def __repr__(self):
    94132        """
    95         Return string representation of this stock.
     133        Return string representation of this stock. Displays the exchange,
     134        symbol, and current market value.
    96135
    97136        EXAMPLES:
    98137            sage: finance.Stock('ibm').__repr__()     # optional -- requires internet, and random
    99138            'IBM (127.47)'
    100139        """
    101         return "%s (%s)"%(self.symbol, self.market_value())
     140        return "%s:%s (%s)"%(self.exchange, self.symbol, self.market_value())
    102141   
    103142    def market_value(self):
    104143        """
    class Stock: 
    111150            sage: finance.Stock('goog').market_value()   # optional and random
    112151            575.83000000000004
    113152        """
    114         return float(self.yahoo()['price'])
     153        return float(self._yahoo()['price'])
    115154
    116     def yahoo(self):
     155    def _yahoo(self):
    117156        """
    118         Get Yahoo current price data for this stock.
     157        Get Yahoo current price data for this stock as well as historical
     158        price
    119159
    120160        OUTPUT:
    121161            dict
    122162
    123163        EXAMPLES:
    124             sage: finance.Stock('GOOG').yahoo()          # random and optional (requires internet)
     164            sage: finance.Stock('GOOG')._yahoo()          # random and optional (requires internet)
    125165            {'stock_exchange': '"NasdaqNM"', 'market_cap': '181.1B', '200day_moving_avg': '564.569', '52_week_high': '747.24', 'price_earnings_growth_ratio': '1.04', 'price_sales_ratio': '10.16', 'price': '576.48', 'earnings_per_share': '14.463', '50day_moving_avg': '549.293', 'avg_daily_volume': '6292480', 'volume': '1613507', '52_week_low': '412.11', 'short_ratio': '1.00', 'price_earnings_ratio': '40.50', 'dividend_yield': 'N/A', 'dividend_per_share': '0.00', 'price_book_ratio': '7.55', 'ebitda': '6.513B', 'change': '-9.32', 'book_value': '77.576'}
    126166        """
    127167        url = 'http://finance.yahoo.com/d/quotes.csv?s=%s&f=%s' % (self.symbol, 'l1c1va2xj1b4j4dyekjm3m4rr5p5p6s7')
    class Stock: 
    149189        data['short_ratio'] = values[19]
    150190        return data
    151191
    152     def google(self,startdate='Jan+1,+1900',enddate=date.today().strftime("%b+%d,+%Y"), histperiod='daily'):
     192    def historical(self,startdate=datetime.today().replace(year=datetime.today().year-1),enddate=datetime.today(), histperiod='daily'):
    153193        """
    154         Return an immutable sequence of historical price data
    155         for this stock, obtained from Google. OHLC data is stored
    156         internally as well. By default, returns the past year's daily
    157         OHLC data.
    158 
    159         Dates startdate and enddate should be formatted 'Mon+d,+yyyy' where
    160         'Mon' is a three character abbreviation of the month's name.
     194        Return an immutable sequence of historical OHLC data for this stock
     195        and store this data internally as well. The attributes startdate and
     196        enddate are \code{datetime.date} objects.
    161197
    162198        NOTE:
    163             Google Finance returns the past year's financial data by default
    164             when startdate is set too low from the equity's date of going
    165             public.  By default, this function only looks at the NASDAQ and
     199            By default, this function only looks at the NASDAQ and
    166200            NYSE markets.  However, if you sepcified the market during
    167             initialization of the stock (i.e. "finance.Stock("OTC:NTDOY")"),
     201            initialization of the stock (i.e. finance.Stock('OTC:NTDOY')),
    168202            Stock.google() will give correct results.
    169203
    170204        INPUT:
    171             startdate -- string, (default: 'Jan+1,+1900')
    172             enddate   -- string, (default: current date )
     205            startdate -- string representation of date (default: one year ago)
     206            enddate   -- string representation of date (default: today)
     207                         Allowed Formats:
     208                         yyyy-mm-dd
     209                         Mon dd, yyyy (three letter abbrev. of month)
    173210            histperiod -- string, ('daily' or 'weekly')
    174211
    175212        OUTPUT:
    176             Sequence
     213            Sequence -- Sequence object containing OHLC historical data
     214                        beginning from the specified start date and ending
     215                        on the specified end date
    177216
    178217        EXAMPLES:
    179         We get the first five days of VMware's stock history:
    180             sage: finance.Stock('vmw').google()[:5]   # optional -- requires internet
     218        By default, Stock.historical() will return the past year of stock data.
     219        Here, we accessed data on August 12, 2008:
     220            sage: S = finance.Stock('NYSE:HMC')
     221            sage: S.historical()    # optional -- requires internet and random
    181222            [
    182              15-Aug-07 52.11 59.87 51.50 57.71   10678500,
    183              16-Aug-07 60.99 61.49 52.71 56.99    6919500,
    184              17-Aug-07 59.00 59.00 54.45 55.55    3086100,
    185              20-Aug-07 56.05 57.50 55.61 57.33    2140900,
    186              21-Aug-07 57.25 66.59 56.50 65.99    7369700
    187             ]
    188            
    189             sage: finance.Stock('F').google('Jan+3,+1978', 'Jul+7,+2008')[:5] # optional -- requires internet
    190             [
    191               3-Jan-78 2.90 2.90 2.84 2.85    1074495,
    192               4-Jan-78 2.84 2.84 2.81 2.83    1648713,
    193               5-Jan-78 2.83 2.84 2.77 2.77    1988524,
    194               6-Jan-78 2.77 2.77 2.74 2.76    2019988,
    195               9-Jan-78 2.73 2.73 2.69 2.73    2600499
    196             ]
    197            
    198         Note that when startdate is too far prior to a stock's actual start
    199         date, Google Finance defaults to a year's worth of stock history
    200         leading up to the specified enddate.  For example, Apple's (AAPL) stock
    201         history only dates back to September 7, 1984
    202            
    203             sage: finance.Stock('AAPL').google('Sep+1,+1900', 'Jan+1,+2000')[0:5] # optional -- requires internet
    204             [
    205               4-Jan-99 10.53 10.56 10.00 10.31   34031600,
    206               5-Jan-99 10.48 10.98 10.38 10.83   50361200,
    207               6-Jan-99 11.03 11.03 10.25 10.44   48163200,
    208               7-Jan-99 10.56 11.27 10.53 11.25   51036400,
    209               8-Jan-99 11.64 11.72 11.00 11.25   24244000
    210             ]
    211            
    212         Here is an example where we create and get the history of a stock
    213         that is not in NASDAQ or NYSE
    214                
    215             sage: finance.Stock("OTC:NTDOY").google(startdate="Jan+1,+2007", enddate="Jan+1,+2008")[:5]
    216             [
    217               3-Jan-07 32.44 32.75 32.30 32.44     156300,
    218               4-Jan-07 31.70 32.40 31.20 31.70     222700,
    219               5-Jan-07 30.15 30.50 30.15 30.15      65700,
    220               8-Jan-07 30.10 30.50 30.00 30.10     130800,
    221               9-Jan-07 29.90 30.05 29.60 29.90     103400
     223            2007-08-13T00:00:00 33.81 34.07 33.78 33.81     707600,
     224            2007-08-14T00:00:00 34.06 34.16 33.61 33.68     618800,
     225            2007-08-15T00:00:00 33.43 33.61 32.92 32.93     936500,
     226            2007-08-16T00:00:00 32.10 32.51 31.33 31.95    2181100,
     227            2007-08-17T00:00:00 31.29 32.08 31.29 31.88    1792000
    222228            ]
    223229
    224        
    225         Here, we create a stock by cid, and get historical data.
    226         Note that when using historical, if a cid is specified,
    227         it will take precedence over the stock's symbol.  So, if
    228         the symbol and cid do not match, the history based on the
    229         contract id will be returned.
    230        
    231             sage: sage.finance.stock.Stock("AAPL", 22144).google(startdate='Jan+1,+1990')[:5] #optional -- requires internet
     230        You can also specify explicit starting and ending dates. By default,
     231        the ending date is today's date:
     232            sage: S.historical('Mar 3, 2008', 'Mar 7, 2008')    # optional -- requires internet
    232233            [
    233               2-Jan-90 8.81 9.38 8.75 9.31    6542800,
    234               3-Jan-90 9.50 9.50 9.38 9.38    7428400,
    235               4-Jan-90 9.56 9.69 9.31 9.41    7911200,
    236               5-Jan-90 9.44 9.56 9.25 9.44    4404000,
    237               8-Jan-90 9.38 9.50 9.25 9.50    3627600
     234            2008-03-03T00:00:00 29.95 30.20 29.90 30.16     592300,
     235            2008-03-04T00:00:00 30.00 30.00 29.40 29.65    1078700,
     236            2008-03-05T00:00:00 29.93 29.96 29.48 29.83     589100,
     237            2008-03-06T00:00:00 29.86 29.86 29.40 29.41     522200,
     238            2008-03-07T00:00:00 29.35 29.35 28.70 28.77     535600
    238239            ]
    239240
     241        One can also retreive weekly data. Here's an example from a stock
     242        belonging to a foreign exchange:
     243            sage: finance.Stock('BE:BMW').historical('Jun 1, 2008', 'Jul 1, 2008', 'weekly')    # optional -- requires internet
     244            [
     245            2008-06-02T00:00:00 37.95 37.95 34.64 34.64          0,
     246            2008-06-10T00:00:00 33.80 34.57 33.25 33.25        200,
     247            2008-06-16T00:00:00 33.72 34.01 32.50 33.02          0,
     248            2008-06-23T00:00:00 32.51 32.61 30.10 30.10        200,
     249            2008-06-30T00:00:00 30.39 30.49 29.55 29.84          0
     250            ]
    240251        """
    241252        cid = self.cid
    242253        symbol = self.symbol
     254
     255        if type(startdate) != datetime:
     256            if startdate[0].isdigit():
     257                startdate = datetime.strptime(startdate.strip(), '%Y-%m-%d')
     258            else:
     259                startdate = datetime.strptime(startdate.replace(' ',''), '%b%d,%Y')
     260
     261        if type(enddate) != datetime:
     262            if enddate[0].isdigit():
     263                enddate = datetime.strptime(enddate.strip(), '%Y-%m-%d')
     264            else:
     265                enddate = datetime.strptime(enddate.replace(' ',''), '%b%d,%Y')
     266
     267        R = self._historical_google(startdate, enddate, histperiod)
     268        if 'Bad Request' in R or 'Server Error' in R:
     269            R = self._historical_yahoo(startdate, enddate, histperiod)
     270            if 'Bad Request' in R or 'Server Error' in R:
     271                self.exchange = 'NYSE'
     272                R = self._historical_google(startdate, enddate, histperiod)
     273                if 'Bad Request' in R or 'Server Error' in R:
     274                    raise RuntimeError
    243275       
    244         if self.cid=='':
    245             if ':' in symbol:
    246                 R = self._get_data('', startdate, enddate, histperiod)
    247             else:
    248                 R = self._get_data('NASDAQ:', startdate, enddate, histperiod)
    249                 if "Bad Request" in R:
    250                      R = self._get_data("NYSE:", startdate, enddate, histperiod)
    251         else:
    252             R = self._get_data('', startdate, enddate, histperiod)
    253         if "Bad Request" in R:
    254             raise RuntimeError
    255276        self.__historical = []
    256277        self.__historical = self._load_from_csv(R)
    257278        return self.__historical
    class Stock: 
    260281        r"""
    261282        Return a TimeSeries containing historical opening prices for this
    262283        stock. If no arguments are given, will return last acquired historical
    263         data. Otherwise, data will be gotten from Google Finance.
     284        data. Otherwise, a new data request will be made to Google Finance
     285        or Yahoo Finance.
    264286
    265287        INPUT:
    266             startdate  -- string, (default: 'Jan+1,+1900')
    267             enddate    -- string, (default: current date)
     288            startdate -- string representation of date (default: one year ago)
     289            enddate   -- string representation of date (default: today)
     290                         Allowed Formats:
     291                         yyyy-mm-dd
     292                         Mon dd, yyyy (three letter abbrev. of month)
    268293            histperiod -- string, ('daily' or 'weekly')
    269294
    270295        OUTPUT:
    271             TimeSeries -- Close price data
     296            TimeSeries -- open price data
    272297
    273298        EXAMPLES:
    274         You can directly obtain Open data as so:
    275             sage: finance.Stock('vmw').open(startdate='Jan+1,+2008', enddate='Feb+1,+2008')                 # optional -- requires internet
    276             [83.0500, 85.4900, 84.9000, 82.0000, 81.2500 ... 82.0000, 58.0500, 54.4900, 55.6000, 56.9800]
     299        You can directly obtain Open data for a given equity like so:
     300            sage: finance.Stock('vmw').open('Jan 1, 2008', 'Jan 10, 2008')    # optional -- requires internet
     301            [85.4900, 84.9000, 82.0000, 81.2500, 74.0100, 76.4400, 79.2000]
    277302
    278303        Or, you can initialize stock data first and then extract the Open
    279         data:
    280             sage: c = finance.Stock('vmw')
    281             sage: c.google(startdate='Feb+1,+2008', enddate='Mar+1,+2008')[:5]    # optional -- requires internet
     304        data. If no arguments are given to Stock.open, it will use the data
     305        from the last request:
     306            sage: S = finance.Stock('vmw')
     307            sage: S.historical('Jan 10, 2008', 'Jan 20, 2008')[:5]    # optional -- requires internet
    282308            [
    283              31-Jan-08 55.60 57.35 55.52 56.67    2607800,
    284               1-Feb-08 56.98 58.14 55.06 57.85    2489400,
    285               4-Feb-08 58.00 60.47 56.91 58.05    1840300,
    286               5-Feb-08 57.60 59.30 57.17 59.30    1711700,
    287               6-Feb-08 60.32 62.00 59.50 61.52    2209700
     309            2008-01-10T00:00:00 79.20 82.43 77.64 80.30    1800700,
     310            2008-01-11T00:00:00 78.38 79.80 75.83 77.53    2109900,
     311            2008-01-14T00:00:00 79.99 83.26 78.34 82.24    1923500,
     312            2008-01-15T00:00:00 81.53 84.40 78.85 79.93    2408500,
     313            2008-01-16T00:00:00 78.34 83.70 77.00 83.50    2611600
    288314            ]
    289             sage: c.open()    # optional -- requires internet
    290             [55.6000, 56.9800, 58.0000, 57.6000, 60.3200 ... 56.5500, 59.3000, 60.0000, 59.7900, 59.2600]
     315            sage: S.open()    # optional -- requires internet
     316            [79.2000, 78.3800, 79.9900, 81.5300, 78.3400, 84.4500, 81.6000]
    291317
    292         Otherwise, \code{self.google()} will be called with the default
    293         arguements returning a year's worth of data:
    294             sage: finance.Stock('vmw').open()   # optional and random -- requires internet and depends on day
    295             [52.1100, 60.9900, 59.0000, 56.0500, 57.2500 ... 83.0500, 85.4900, 84.9000, 82.0000, 81.2500]
    296 
     318        If no request was made before calling Stock.open, the default
     319        is to return the past year of Open data. This particular call was
     320        made on 12 August, 2008:
     321            sage: finance.Stock('amd').open()[:5]    # optional -- requires internet and random
     322            [13.2200, 12.8700, 12.4500, 11.8600, 12.0400]
    297323        """
    298324       
    299325        from time_series import TimeSeries
    300        
     326
     327        # Obtain new data only if the user specifies new start or end dates.
     328        # Otherwise, use the cached data.
    301329        if len(args) != 0:
    302             return TimeSeries([x.open for x in self.google(*args, **kwds)])
     330            return TimeSeries([x.open for x in self.historical(*args,**kwds)])
    303331           
    304332        try:
    305333            return TimeSeries([x.open for x in self.__historical])
    306334        except AttributeError:
    307335            pass
    308336       
    309         return TimeSeries([x.open for x in self.google(*args, **kwds)])
     337        return TimeSeries([x.open for x in self.historical(*args,**kwds)])
    310338   
    311339    def close(self, *args, **kwds):
    312340        r"""
    class Stock: 
    315343        Otherwise, data will be gotten from Google Finance.
    316344
    317345        INPUT:
    318             startdate  -- string, (default: 'Jan+1,+1900')
    319             enddate    -- string, (default: current date)
     346            startdate -- string representation of date (default: one year ago)
     347            enddate   -- string representation of date (default: today)
     348                         Allowed Formats:
     349                         yyyy-mm-dd
     350                         Mon dd, yyyy (three letter abbrev. of month)
    320351            histperiod -- string, ('daily' or 'weekly')
    321352
    322353        OUTPUT:
    323354            TimeSeries -- Close price data
    324355
    325356        EXAMPLES:
    326         You can directly obtain close data as so:
    327             sage: finance.Stock('vmw').close(startdate='Jan+1,+2008', enddate='Feb+1,+2008')                 # optional -- requires internet
    328             [84.9900, 84.6000, 83.9500, 80.4900, 72.9900 ... 83.0000, 54.8700, 56.4200, 56.6700, 57.8500]
     357        You can directly obtain Close data for a given equity like so:
     358            sage: finance.Stock('vmw').close('Jan 1, 2008', 'Jan 10, 2008')    # optional -- requires internet
     359            [84.6000, 83.9500, 80.4900, 72.9900, 74.5000, 79.8900, 80.3000]
    329360
    330361        Or, you can initialize stock data first and then extract the Close
    331         data:
    332             sage: c = finance.Stock('vmw')
    333             sage: c.google(startdate='Feb+1,+2008', enddate='Mar+1,+2008')[:5]    # optional -- requires internet
     362        data. If no arguments are given to Stock.close, it will use the data
     363        from the last request:
     364            sage: S = finance.Stock('vmw')
     365            sage: S.historical('Jan 10, 2008', 'Jan 20, 2008')[:5]    # optional -- requires internet
    334366            [
    335              31-Jan-08 55.60 57.35 55.52 56.67    2607800,
    336               1-Feb-08 56.98 58.14 55.06 57.85    2489400,
    337               4-Feb-08 58.00 60.47 56.91 58.05    1840300,
    338               5-Feb-08 57.60 59.30 57.17 59.30    1711700,
    339               6-Feb-08 60.32 62.00 59.50 61.52    2209700
     367            2008-01-10T00:00:00 79.20 82.43 77.64 80.30    1800700,
     368            2008-01-11T00:00:00 78.38 79.80 75.83 77.53    2109900,
     369            2008-01-14T00:00:00 79.99 83.26 78.34 82.24    1923500,
     370            2008-01-15T00:00:00 81.53 84.40 78.85 79.93    2408500,
     371            2008-01-16T00:00:00 78.34 83.70 77.00 83.50    2611600
    340372            ]
    341             sage: c.close()    # optional -- requires internet
    342             [56.6700, 57.8500, 58.0500, 59.3000, 61.5200 ... 58.2900, 60.1800, 59.8600, 59.9500, 58.6700]
     373            sage: S.close()    # optional -- requires internet
     374            [80.3000, 77.5300, 82.2400, 79.9300, 83.5000, 80.7400, 81.2700]
    343375
    344 
    345 
    346         Otherwise, \code{self.google()} will be called with the default
    347         arguements returning a year's worh of data:
    348             sage: finance.Stock('vmw').close()   # optional and random -- requires internet and depends on day
    349             [57.7100, 56.9900, 55.5500, 57.3300, 65.9900 ... 84.9900, 84.6000, 83.9500, 80.4900, 72.9900]
     376        If no request was made before calling Stock.close, the default
     377        is to return the past year of Close data. This particular call was
     378        made on 12 August, 2008:
     379            sage: finance.Stock('amd').close()[:5]    # optional -- requires internet and random
     380            [12.8400, 12.5400, 11.9500, 11.6400, 11.8900]
    350381        """
    351382               
    352383        from time_series import TimeSeries
    353        
     384
     385        # Obtain new data only if the user specifies new start or end dates.
     386        # Otherwise, use the cached data.
    354387        if len(args) != 0:
    355             return TimeSeries([x.close for x in self.google(*args, **kwds)])
     388            return TimeSeries([x.close for x in self.historical(*args,**kwds)])
    356389           
    357390        try:
    358391            return TimeSeries([x.close for x in self.__historical])
    359392        except AttributeError:
    360393            pass
    361394       
    362         return TimeSeries([x.close for x in self.google(*args, **kwds)])
     395        return TimeSeries([x.close for x in self.historical(*args,**kwds)])
    363396       
    364397    def load_from_file(self, file):
    365398        """
    366399        Load historical data from a local csv formatted data file. Note
    367400        that no symbol data is included in Google Finance's csv data.
    368         The csv file must be formatted in the following way, just as
    369         on Google Finance:
     401        The csv file must be formatted in either of the two following ways:
    370402
    371403        Timestamp,Open,High,Low,Close,Volume
     404        Timestamp,Open,High,Low,Close,Volume,Adj.Close
    372405
    373406        INPUT:
    374             file -- local file with Google Finance formatted OHLC data
     407            file -- local file with csv formatted OHLC data
    375408
    376409        OUTPUTS:
    377410            Sequence -- OHLC data
    class Stock: 
    381414        OHLC data, such as that from Google Finance, called AAPL-minutely.csv.
    382415        One can load this information into a Stock object like so. Note that
    383416        the path must be explicit:
    384             sage: finance.Stock('aapl').load_from_file(SAGE_ROOT + '/examples/finance/AAPL-minutely.csv')[:5]
     417            sage: finance.Stock('aapl').load_from_file(SAGE_ROOT + '/examples/finance/AAPL-minutely.csv')
    385418            [
    386             1212408060 188.00 188.00 188.00 188.00        687,
    387             1212408000 188.00 188.11 188.00 188.00       2877,
    388             1212407700 188.00 188.00 188.00 188.00       1000,
    389             1212407640 187.75 188.00 187.75 188.00       2000,
    390             1212405780 187.80 187.80 187.80 187.80        100
     419            2008-06-02T05:01:00 188.00 188.00 188.00 188.00        687,
     420            2008-06-02T05:00:00 188.00 188.11 188.00 188.00       2877,
     421            2008-06-02T04:55:00 188.00 188.00 188.00 188.00       1000,
     422            2008-06-02T04:54:00 187.75 188.00 187.75 188.00       2000,
     423            2008-06-02T04:23:00 187.80 187.80 187.80 187.80        100
    391424            ]
    392 
    393425
    394426        Note that since the source file doesn't contain information on which
    395427        equity the information comes from, the symbol designated at
    396428        initialization of Stock need not match the source of the data. For
    397429        example, we can initialize a Stock object with the symbol 'goog',
    398430        but load data from 'aapl' stock prices:
    399             sage: finance.Stock('goog').load_from_file(SAGE_ROOT + '/examples/finance/AAPL-minutely.csv')[:5]
     431            sage: finance.Stock('goog').load_from_file(SAGE_ROOT + '/examples/finance/AAPL-minutely.csv')
    400432            [
    401             1212408060 188.00 188.00 188.00 188.00        687,
    402             1212408000 188.00 188.11 188.00 188.00       2877,
    403             1212407700 188.00 188.00 188.00 188.00       1000,
    404             1212407640 187.75 188.00 187.75 188.00       2000,
    405             1212405780 187.80 187.80 187.80 187.80        100
     433            2008-06-02T05:01:00 188.00 188.00 188.00 188.00        687,
     434            2008-06-02T05:00:00 188.00 188.11 188.00 188.00       2877,
     435            2008-06-02T04:55:00 188.00 188.00 188.00 188.00       1000,
     436            2008-06-02T04:54:00 187.75 188.00 187.75 188.00       2000,
     437            2008-06-02T04:23:00 187.80 187.80 187.80 187.80        100
    406438            ]
    407439
    408440        This tests a file that doesn't exist:
    409             sage: finance.Stock("AAPL").load_from_file("I am not a file")
     441            sage: finance.Stock('AAPL').load_from_file('I am not a file')
    410442            Bad path or file name
    411 
    412443        """
    413444        try:
    414445            file_obj = open(file, 'r')
    class Stock: 
    418449            return self.__historical
    419450        except IOError, msg:
    420451            print "Bad path or file name"
    421        
     452
    422453    def _load_from_csv(self, R):
    423454        """
     455        This function is used internally. Parses OHLC data from Google
     456        Finance and Yahoo Finance (or any OHLC csv formatted data file) and
     457        returns a Sequence containing the OHLC data.
     458
    424459        EXAMPLES:
    425         This indirectly tests _load_from_csv():
    426             sage: finance.Stock('aapl').load_from_file(SAGE_ROOT + "/examples/finance/AAPL-minutely.csv")
     460        The following implicity tests this function:
     461            sage: S = finance.Stock('NYSE:HMC')
     462            sage: S.historical()    # optional -- requires internet and random
    427463            [
    428             1212408060 188.00 188.00 188.00 188.00        687,
    429             1212408000 188.00 188.11 188.00 188.00       2877,
    430             1212407700 188.00 188.00 188.00 188.00       1000,
    431             1212407640 187.75 188.00 187.75 188.00       2000,
    432             1212405780 187.80 187.80 187.80 187.80        100
     464            2007-08-13T00:00:00 33.81 34.07 33.78 33.81     707600,
     465            2007-08-14T00:00:00 34.06 34.16 33.61 33.68     618800,
     466            2007-08-15T00:00:00 33.43 33.61 32.92 32.93     936500,
     467            2007-08-16T00:00:00 32.10 32.51 31.33 31.95    2181100,
     468            2007-08-17T00:00:00 31.29 32.08 31.29 31.88    1792000
    433469            ]
    434 
    435        
    436470        """
    437471        R = R.splitlines()
     472        numheadings = R[0].count(',')
    438473        headings = R[0].split(',')
    439474        hist_data = []
    440475        for x in reversed(R[1:]):
    441476            try:
    442                 timestamp, opn, high, low, close, volume = x.split(',')
     477                if numheadings == 5:
     478                    timestamp, opn, high, low, close, volume = x.split(',')
     479                else:
     480                    timestamp, opn, high, low, close, volume, cl = x.split(',')
     481               
     482                if timestamp.isdigit():
     483                    # assume POSIX timestamp. used in opentick historical
     484                    # queries. otherwise, assume one of the formats found
     485                    # in Google Finance or Yahoo Finance. Store in ISO
     486                    # format so we can recover later.
     487                    timestamp = datetime.fromtimestamp(int(timestamp)).isoformat()
     488                else:
     489                    if timestamp.find('-') == 4:
     490                        # Yahoo Finance formatting
     491                        timestamp = datetime.strptime(timestamp, '%Y-%m-%d').isoformat()
     492                    else:
     493                        # Google Finance formatting
     494                        timestamp = datetime.strptime(timestamp, '%d-%b-%y').isoformat()
     495
    443496                ohlc = OHLC(timestamp, opn,high,low,close,volume)
    444497                hist_data.append(ohlc)
    445498            except ValueError:
    class Stock: 
    447500        hist_data = Sequence(hist_data,cr=True,universe=lambda x:x, immutable=True)
    448501        return hist_data
    449502       
    450     def _get_data(self, exchange='', startdate='Jan+1,+1900', enddate=date.today().strftime("%b+%d,+%Y"), histperiod='daily'):
     503    def _historical_google(self, startdate, enddate, histperiod):
    451504        """       
    452         This function is used internally.
     505        This function is used internally. Takes the startdate, enddate,
     506        histperiod, exchange and symbol and creates a url that links to
     507        a csv file on Google Finance containing the desired data.
     508
     509        INPUT:
     510            startdate -- string representation of date (default: one year ago)
     511            enddate   -- string representation of date (default: today)
     512                         Allowed Formats:
     513                         yyyy-mm-dd
     514                         Mon dd, yyyy (three letter abbrev. of month)
     515            histperiod -- string, ('daily' or 'weekly')
     516
     517        OUTPUT:
     518            string -- read-in data from OHLC csv data file
    453519
    454520        EXAMPLES:
    455         This indirectly tests the use of get_data.
    456             sage: finance.Stock('aapl').google(startdate='Jan+1,+1990')[:2]    # optional -- requires internet
     521        The following implicity tests this function:
     522            sage: S = finance.Stock('NYSE:HMC')
     523            sage: S.historical()    # optional -- requires internet and random
    457524            [
    458               2-Jan-90 8.81 9.38 8.75 9.31    6542800,
    459               3-Jan-90 9.50 9.50 9.38 9.38    7428400
     525            2007-08-13T00:00:00 33.81 34.07 33.78 33.81     707600,
     526            2007-08-14T00:00:00 34.06 34.16 33.61 33.68     618800,
     527            2007-08-15T00:00:00 33.43 33.61 32.92 32.93     936500,
     528            2007-08-16T00:00:00 32.10 32.51 31.33 31.95    2181100,
     529            2007-08-17T00:00:00 31.29 32.08 31.29 31.88    1792000
    460530            ]
    461531        """
    462         symbol = self.symbol
    463         cid = self.cid
    464         if cid == '':
    465             url = 'http://finance.google.com/finance/historical?q=%s%s&startdate=%s&enddate=%s&histperiod=%s&output=csv'%(exchange, symbol.upper(), startdate, enddate, histperiod)
     532        if self.cid == '':
     533            url = 'http://finance.google.com/finance/historical?q=%s:%s&startdate=%s&enddate=%s&histperiod=%s&output=csv'%(self.exchange, self.symbol, startdate.strftime('%b+%d,+%Y'), enddate.strftime('%b+%d,+%Y'), histperiod)
    466534        else:
    467             url = 'http://finance.google.com/finance/historical?cid=%s&startdate=%s&enddate=%s&histperiod=%s&output=csv'%(cid, startdate, enddate, histperiod)
     535            url = 'http://finance.google.com/finance/historical?cid=%s&startdate=%s&enddate=%s&histperiod=%s&output=csv'%(self.cid, startdate.strftime('%b+%d,+%Y'), enddate.strftime('%b+%d,+%Y'), histperiod)
     536
    468537        return urllib.urlopen(url).read()
     538       
     539    def _historical_yahoo(self, startdate, enddate, histperiod):
     540        """
     541        This function is used internally. Takes the startdate, enddate,
     542        histperiod, exchange and symbol and creates a url that links to
     543        a csv file on Yahoo Finance containing the desired data.
     544
     545        INPUT:
     546            startdate -- string representation of date (default: one year ago)
     547            enddate   -- string representation of date (default: today)
     548                         Allowed Formats:
     549                         yyyy-mm-dd
     550                         Mon dd, yyyy (three letter abbrev. of month)
     551            histperiod -- string, ('daily' or 'weekly')
     552
     553        OUTPUT:
     554            string -- read-in data from OHLC csv data file
     555
     556        EXAMPLES:
     557        The following implicity tests this function:
     558            sage: S = finance.Stock('NYSE:HMC')
     559            sage: S.historical()    # optional -- requires internet and random
     560            [
     561            2007-08-13T00:00:00 33.81 34.07 33.78 33.81     707600,
     562            2007-08-14T00:00:00 34.06 34.16 33.61 33.68     618800,
     563            2007-08-15T00:00:00 33.43 33.61 32.92 32.93     936500,
     564            2007-08-16T00:00:00 32.10 32.51 31.33 31.95    2181100,
     565            2007-08-17T00:00:00 31.29 32.08 31.29 31.88    1792000
     566            ]
     567        """
     568        included_exchanges = ['NASDAQ', 'NYSE']
     569        hist_periods = {'daily':'d', 'weekly':'w', 'monthly':'m'}
     570        startmonth = '%.2i'%(startdate.month-1)
     571        endmonth = '%.2i'%(enddate.month-1)
     572        if self.exchange in included_exchanges:
     573            url = 'http://ichart.finance.yahoo.com/table.csv?s=%s&a=%s&b=%s&c=%s&d=%s&e=%s&f=%s&g=%s&ignore=.csv'%(self.symbol, startmonth, startdate.day, startdate.year, endmonth, enddate.day, enddate.year, hist_periods[histperiod])
     574        else:
     575            url = 'http://ichart.finance.yahoo.com/table.csv?s=%s.%s&a=%s&b=%s&c=%s&d=%s&e=%s&f=%s&g=%s&ignore=.csv'%(self.symbol, self.exchange[:2], startmonth, startdate.day, startdate.year, endmonth, enddate.day, enddate.year, hist_periods[histperiod])
     576
     577        return urllib.urlopen(url).read()