The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Finance::Shares::Sample - Price data on a single share

SYNOPSIS

    use Finance::Shares::Simple;

Simplest

Obtain a series of stock quotes from a CSV file.

    my $ss = new Finance::Shares::Sample(
                source  => 'gsk,csv',
                symbol  => 'GSK.L',
            );

Typical

Get a series of stock quotes and graph them using specific settings. Calculate some trend lines from the Finance::Shares::Sample data and superimpose them on the graph.

    my $s = new Finance::Shares::Sample(
            source => {
                user     => 'guest',
                password => 'a94Hq',
                database => 'London',
            },
            
            dates_by   => 'weeks',
            symbol     => 'GSK.L',
            start_date => '2001-09-01',
            end_date   => '2002-08-31'
        );

    # construct data for lines, and then...
    $s->add_line( 'prices', 'one', $line1, 'Support' );
    $s->add_line( 'volumes', 'two', 'Average' );
    $s->add_line( 'cycles', 'three', $line3, 'RSI' );
        
    

DESCRIPTION

This module is principally a data structure holding stock quotes. Price and volume data are held for a particular share over a specified period. This data can be read from a CSV file or from an array, but more usually it is fetched from Finance::Shares::MySQL which in turn handles getting the data from the internet.

The Data

This object is used as a data structure common to a number of modules. Therefore, unusually, most of the internal data is made available directly. Those documented here can be relied upon to exist as soon as the object has been constructed.

open, high, low, close, volume

These hashes are indexed by date and return the appropriate value for that date. The volume hash is not used when dates_by is set to months.

lx

This hash, indexed by date, returns the logical x coordinate for that date.

dates

This array is a list of known dates indexed by the logical x coordinate. It is the inverse to lx, where

    $x    = $s->{lx}{$date};
    $date = $s->{dates}[$x];
    

lines

Function data is stored in this hash, first keyed by the chart where the function belongs - one of prices, volumes, cycles or tests. Each of these are in turn sub-hashes keyed by a line id. See <add_line> for details of the data stored.

Example

A function line with two points on the prices graph would be entered thus.

    my $s = new Finance::Shares::Sample(...);
    
    my $data = { 
        '2002-01-11' => 850,
        '2002-03-28' => 991,
    };
    $s->add_line('prices', 'my_trend', $data, 'My Trend');

It would be held within the Sample object thus.

    $s->{lines}{prices}{my_trend}{data}{2002-01-11} = 850;
                                       {2002-03-28} = 991;

Functions

A number of other modules provide functions which work on the data held here. The 'functions' provided in this module are principally the source data, but they can be identified with the following text names when building model specifications.

    open
    close
    high
    low
    volume
    value

CONSTRUCTOR

new( [options] )

options can be a hash ref or a list of hash keys and values.

source and symbol must be specified, with start_date and end_date also required if the source is a mysql database.

Recognized keys are:

source

This can be a Finances::Shares::MySQL object or a hash ref holding options suitable for creating one. Alternatively it may be the name of a CSV file or an array ref holding similar data.

Example 1

Using an existing MySQL object.

    my $db = new Finance::Shares::MySQL;            
    my $ss = new Finance::Shares::Sample (
                source => $db,
            );

Example 2

Creating our own MySQL connection.

    my $ss = new Finance::Shares::Sample (
                source => {
                    user     => 'wally',
                    password => '123jiM',
                    database => 'London',
                },
            );

Several attempts (see tries below) are made to fetch the data from the internet. Then the data is extracted from the MySQL database, filtered according to dates_by and stored as date, price and volume data.

The CSV file is read and converted to price and/or volume data, as appropriate. Files downloaded from !Yahoo Finance need filtering to change the dates into the YYYY-MM-DD format. Alternatively, a script, fetch_csv is provided in the Finance::Shares directory. The comma seperated values are interpreted by Text::CSV_XS and so are currently unable to tolerate white space. See the array option for how the field contents are handled. Optionally, the directory may be specified seperately.

Example 3

    my $ss = new Finance::Shares::Sample (
                source => 'quotes.csv',
                directory => '~/shares',
            );

If source is an array ref it should point to a list of arrays with fields date, open, high, low, close and volume.

Example 4

    my $data = [
    ['2002-08-01',645.13,645.13,586.00,606.36,33606236],
    ['2002-08-02',574.75,620.88,558.00,573.00,59618288],
    ['2002-08-05',589.88,589.88,560.11,572.42,20300730],
    ['2002-08-06',571.89,599.00,545.30,585.92,26890880],
    ['2002-08-07',565.11,611.00,560.11,567.11,24977940] ];
    
    my $ss = new Finance::Shares::Sample ( 
                source => $data,
            );

Three formats are recognized:

    Date, Open, High, Low, Close, Volume
    Date, Open, High, Low, Close
    Date, Volume

Examples

    [2001-04-26,345,400,300,321,12345678],
    [2001-04-27,234.56,240.00,230.00,239.99],
    [2001-04-28, 987654],

The four price values are typically decimals and the volume is usually an integer in the millions.

dates_by

Control how the data are stored and displayed on a chart. Suitable values:

quotes

By default, the prices are displayed just as they are received.

days

Every day is recognized, though only trading days (Monday to Friday) will have quotes, and some of those may be missing.

weekdays

Entries are made for every day except weekends. So the data mostly appears as for quotes except that missing data is visible.

weeks

One entry shows the average data for each week. Holes in the data are visible as blank weeks.

months

Entries show the average data for each month.

end_date

The last day of price data, in YYYY-MM-DD format. Only used if the data is fetched using Finance::Shares::MySQL. See fetch.

symbol

The market abbreviation for the stock as used by Yahoo. Non-US codes should have a suffix indicating the stock exchange (e.g. BSY.L for BSkyB on the London Stock Exchange).

mode

Determines how the stock quotes are obtained if Finance::Shares::MySQL is used. Suitable values are 'online', 'offline', 'fetch' and 'cache'. (Default: 'cache')

start_date

The first day of price data, in YYYY-MM-DD format. Only used if the data is fetched using Finance::Shares::MySQL. See fetch.

add_line( graph, lineid, data, key [, style [, shown ]] )

graph

The graph where the line should appear, one of 'prices', 'volumes', 'cycles' or 'tests'.

lineid

A string uniquely identifying the line.

data

A hash ref of values indexed by date.

key

The text to be shown next with the style in the Price Key box to the right of the chart.

style

This can either be a PostScript::Graph::Style object or a hash ref holding options for one.

shown

True if to be drawn, false otherwise.

Add a line to the price chart to be drawn in the style specified identified by some key text. The data is stored as a hash with the following keys:

    data    A hash of numbers keyed by YYYY-MM-DD dates.
    shown   True if the line is to be drawn on a chart.
    style   A hash or PostScript::Graph::Style object.
    key     A string associated with the style in the Key.
    id      Unique internal identifier
    order   Integer indicating when the line was added.
    min     The lowest data value
    max     The highest data value

Example

    my $s = new Finance::Shares::Sample(...);
    $s->add_line('cycles', 'my_line', $data, 'My Line');

then

    $s->{lines}{cycles}{my_line}{key} == 'My Line';
    

value( options )

Produce a comparison line for a fixed y value.

options are in key/value format using the following keys.

strict

If 1, return undef if the average period is incomplete. If 0, return the best value so far. (Default: 0)

shown

A flag controlling whether the function is graphed. 0 to not show it, 1 to add the line to the named graph. (Default: 1)

graph

A string indicating the graph for display: one of prices, volumes, cycles or tests. (Default: 'prices')

value

The Y value indicating the line.

Like all function methods, this returns the line identifier.

ACCESS METHODS

See DESCRIPTION for the data items that are directly available.

id()

Return a string used to identify the sample.

start_date()

Returns date of first quote in YYYY-MM-DD format.

symbol()

Returns the !Yahoo stock code as given to new().

end_date()

Returns date of last quote in YYYY-MM0DD format.

dates_by()

Return a string indicating how the dates are spread. One of 'data', 'days', 'workdays', 'weeks', 'months'.

chart( [chart] )

Either set or get the Finance::Shares::Chart displaying this data.

line_order( graph )

Return an array ref holding the ids of all the lines known to the sample so that the display order can be changed. Reassigning the new order to the returned array ref has the effect of altering the order displayed.

The lines will be displayed by Finance::Shares::Chart in this order (as they were added) unless shuffling this array moves lines forward or backward. See add_lines for the structure of the line data.

Note that changing this does not affect the key order, which will still show the order they were added.

SUPPORT METHODS

known_lines( [ graph(s) ] )

Returns a list of line identifiers valid for the specified graphs, zero or more of prices, volumes, cycles or tests. If none are specified, all known lines are returned.

line_by_key( identifier )

identifier must be a concatention of the graph name, '::' and the line key (the visible one, NOT the line id), as given to add_line.

Returns the internal data structure for that line. See "add_line" for details.

min_value( graph )

Return the lowest value used on the given graph, which should be one of prices, volumes, cycles or tests.

max_value( graph )

Return the highest value used on the given graph, which should be one of prices, volumes, cycles or tests.

choose_line( graph, line [, nocopy ] )

Return the data for the identified line. The data may be checked and any missing values interpolated.

graph

One of prices, volumes, cycles or tests.

line

A string identifying the line.

nocopy

If true, interpolation is prevented.

Returns undef if there is no such line. choose_line therefore indicates whether the line exists or not (best called with original=1 for this).

SUPPORT FUNCTIONS

line_id( arg1, arg2, ... )

Builds an identifier from the list of strings passed as arguments.

Note that this is NOT a method.

call_function ( hashref, name, args... )

Call a known function by name. The hashref must map names to coderefs like \%function here or Finance::Shares::Model's \%testfunc. name must be one of the names recognised by that hash. args is the argument list passed to the function. If a method is being called, an object must be the first argument in the args list.

Example

    use Finance::Shares::Sample
                    qw(call_function %function);
    use Finance::Shares::Averages;

    my $fss = new Finance::Shares::Sample(...);

    my $res = call_function( \%function, 'simple_a', 
        $fss, period => 3, key => 'Simple average' );

Note this is NOT a method.

DATE FUNCTIONS

There are three types of dates here. A 'days' value is the number of days from some arbitrary day zero. A 'date' is a string in YYYY-MM-DD format while 'ymd' refers to an array holding a year, month and day such as (2002, 12, 31). See SYNOPSIS for all the functions.

today_as_string

Return today's date in YYYY-MM-DD format.

string_from_ymd( year, month, day )

Convert the numeric representation of year, month and day into a YYYY-MM-DD date.

ymd_from_string( date )

Convert a YYYY-MM-DD date into an array of numeric values in the form:

    (year, month, day)

increment_days( year, month, day, inc_days )

Add inc_days to the date and return as a year-month-day array.

increment_date( date, days )

Add the number of days given to the YYYY-MM-DD date and return the new date in YYYY-MM-DD format.

days_difference( year1, month1, day1, year2, month2, day2 )

Return the number of days between the two dates

day_of_week( year, month, day )

Returns 1=Monday, ... 7=Sunday.

BUGS

Where data is missing from a function or test, it is filled by interpolating. I don't think this is the right behaviour, but haven't got around to changing it yet. If something looks a bit odd and you suspect this, a work-round would be to use 'quotes' for the Sample dates_by value.

The complexity of this software has seriously outstripped the testing, so there will be unfortunate interactions. Please do let me know when you suspect something isn't right. A short script working from a CSV file demonstrating the problem would be very helpful.

AUTHOR

Chris Willmot, chris@willmot.org.uk

SEE ALSO

Finance::Shares::MySQL, Finance::Shares::Chart and Finance::Shares::Model.

There is also an introduction, Finance::Shares::Overview and a tutorial beginning with Finance::Shares::Lesson1.