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

NAME

Finance::Shares::Chart - Draw stock quotes on a PostScript graph

SYNOPSIS

    use Finance::Shares::Chart;
    use Finance::Shares::Chart 'deep_copy';

    # ensure quotes data exists
    my $fss = new Finance::Shares::Sample(...);
    
    # add data lines with e.g.
    $fss->add_line('prices', $id, $data, $key, $style);
    
    # optional support objects
    my $psf = new PostScript::File(...);
    my $seq = new PostScript::Graph::Sequence;
    $seq->setup(...);
    $seq->auto(...);
    
    # create the Chart object
    my $fsc = new Finance::Shares::Chart(
        file    => $psf,
        sample  => $fss,
                
        dots_per_inch => 72,
        background    => [1, 1, 0.9],
        bgnd_outline  => 1,
        reverse       => 1,
        heading       => 'Results chart',

        heading_font => {
            font => 'Times-Bold',
            size => 12,
            color => [0, 0, 0.7],
        },
        
        normal_font => {
            # as heading_font
        },
        
        key         => {
            # see PostScript::Graph::Key
        },
        
        x_axis      => {
            show_lines  => 1,
            show_weekday=> 1,
            show_day    => 1,
            show_month  => 1,
            show_year   => 1,
            changes_only=> 0,
            # see PostScript::Graph::Paper
        },

        prices  => {
            sequence    => $seq,
            show_dates  => 1,
            percent     => 25,
            layout      => {
                # see PostScript::Graph::Paper
            },
            y_axis      => {
                smallest    => 4,
                # see PostScript::Graph::Paper
            },
            points => {
                # style settings
            },
        },
        
        volumes => {
            # as prices, but with 'bars'
            # instead of 'points'
        },
        
        cycles  => {
            # as prices, but without 'points'
        },
        
        tests   => {
            # as prices, but without 'points'
        },
    );

    # draw the chart and output it
    $fsc->build_chart();
    $fsc->output($filename);

DESCRIPTION

The chart produced by this module is about A4 size by default and has up to four graphs stacked vertically, with key panels to the right of each one.

prices

This panel must always be present. It shows the share prices, usually showing opening and closing prices on a high-low range. Lines drawn on this are usually functions acting on the price data.

volumes

If volume data exists, it is placed on this chart. Lines drawn here are usually functions acting on the volume data.

cycles

This axis has a negative as well as a positive range, designed for graphing functions describing how the prices change.

tests

Tests applied to functions from the other graphs would typically place their results here. By default, the axis ranges from 0 to 100 to indicate a confidence percentage.

Specifications are given to the constructor, the most important being the Finance::Shares::Sample holding the data and function and test lines. Lines can be added to the sample until build_chart is invoked, typically by calling the output method.

As can be seen from the "SYNOPSIS" there are a number of top-level parameters which apply to all visible graphs, followed by a sub-group controlling each graph independently. Of particular interest are the graph parameters percent and show_dates which control how the vertical space is allocated. Horizontal space is allocated automatically, with the key panels taking up as much space as needed to describe the superimposed lines.

Each graph also has its own sequence. This tries to make sure that the lines on that graph all have different characteristics in terms of colour, point shape, dash pattern and so on.

If no PostScript::File is given to the constructor, one is generated. However, passing an existing PostScript::File object means that several charts can be placed on the one file. See "build_chart".

CONSTRUCTOR

new( options )

options can be a hash ref or a list of hash keys and values. The top level keys are as follows.

background

The background colour for all the graphs. This can be a shade of grey (0.0 for black, 1.0 for brightest) or an array ref holding similar decimals for red, green and blue, e.g. [ 0.6, 0.4, 0 ] for a red-orange. (Default: 1.0)

bgnd_outline

By default the price and volume marks are drawn with a contrasting outline. Setting this to 1 makes this outline the same colour as the background. (Default: 0)

changes_only

The dates can be shown with every part (day, month etc) shown on every label, or with these parts only shown when they change. (Default: 1)

cycles

A hash ref controlling the appearance of the cycles graph. See "'Individual graphs'" for details.

dots_per_inch

One of the advantages of PostScript output is that it can make the best use of each medium. Setting this to 72 produces output suitable for most computer monitors. Use a higher figure for hard copy, depending on you printer's capabilities. (Default: 300)

file

This can be either a PostScript::File object or a hash ref holding parameters suitable for creating one. The default is to set up a landscape A4 page with half inch margins.

glyph_ratio

Generating PostScript is a one-way process. It is not possible to find out how much space will be taken up by a string using a proportional spaced font, so guesses are made. This allows that guess to be fine tuned. (Default: 0.5)

heading_font

A hash ref holding font settings for the main heading. See normal_font for details.

reverse

If true, the order in which lines are drawn is reversed.

key

A hash ref controlling the appearance of the key panels. The following keys are recognized. See PostScript::Graph::Key for details.

    background      outline_color       outline_width
    title           title_font          text_font
    spacing         horz_spacing        vert_spacing
    text_width      icon_height         icon_width
    glyph_ratio
normal_font

A hash ref holding font settings for the text used for axis labels etc. It may contain these keys:

font

The font family name which should be one of the following. (Default: 'Helvetica')

    Courier
    Courier-Bold
    Courier-BoldOblique
    Courier-Oblique
    Helvetica
    Helvetica-Bold
    Helvetica-BoldOblique
    Helvetica-Oblique
    Times-Roman
    Times-Bold
    Times-BoldItalic
    Times-Italic
    Symbol
size

Point size to use. (Default: 10)

color

The normal colour format: either a grey value or an array ref holding [<red>,<green>,<blue>]. (Default: 1.0)

page

An optional string used as the PostScript page 'number'. Although this may be anything many programs expect this to be short like a page number, with no spaces.

prices

A hash ref controlling the appearance of the prices graph. See "'Individual graphs'" for details.

sample

The Finance::Shares::Sample object holding the data to be displayed. Required - no default.

tests

A hash ref controlling the appearance of the prices graph. See "'Individual graphs'" for details.

smallest

The underlying PostScript::Graph::Paper module will sometimes generate more subdivisions and axis lines than needed, especially at high resolutions. smallest provides some control over this for the Y axes. It specifies the size of the smallest gap between lines; giving a larger number means fewer lines. The default produces 3 dots at the resolution given to dots_per_inch.

Note that the only way to control the line density on the X axis is to plot fewer dates. One way of doing this is to set the Finance::Shares::Sample contructor option dates_by to 'weeks' or 'months'.

volumes

A hash ref controlling the appearance of the volumes graph. See "'Individual graphs'" for details.

x_axis

A hash ref controlling the appearance of the dates axis and the vertical grid lines. These keys are defined in this module:

show_lines

True means that vertical lines are to be shown on all the graphs. This can get a little crowded if a lot of dates are shown. (Default: 1)

show_weekday

True means the day of the week is to be shown on the date axis. (Default: 0)

show_day

True means the day of the month is to be shown on the date axis. The default depends on the timescale of the sample.

show_month

True means the month abbreviation is to be shown on the date axis. The default depends on the timescale of the sample.

show_year

True means the year is to be shown on the date axis. The default depends on the timescale of the sample.

changes_only

The date labels can either show all parts (day, month etc.) on every date or only show them as they change. (Default: 1)

These keys are also recognized within x_axis. See PostScript::Graph::Paper for details.

    title           color
    heavy_color     mid_color
    heavy_width     mid_width
    mark_min        mark_max

'heavy' vertical lines are those marked with a date lablel. Date positions whose labels have been omitted are marked with 'mid' lines. Although there is no way to stop these from being drawn, the chart can be made visually simpler by setting mid_width to 0 and/or mid_color to the background color.

Individual graphs

prices, volumes, cycles and tests all use extensive hash refs. More or less, these are passed on to PostScript::Graph::Paper and friends. To make them more manageable, they are broken down into sub-hashes. Here are the top level keys within each graph.

bars

A hash ref controlling how the volume data is to be displayed. Only relevant for the volume graph. These are the recognized keys; see PostScript::Graph::Style for details.

    color       inner_color     outer_color
    width       inner_width     outer_width
layout

A hash ref controlling some general aspects of the graph. The following keys are recognized. See PostScript::Graph::Paper for details.

    spacing     top_margin  right_margin
percent

This is the proportion of space allocated to the graph. Specifying 0 hides it. It is not a strict percentage in that they don't all have to add up to 100, but it does give an idea of the sort of numbers to put here. There may be problems if the value is less than 10, or so small the graph cannot physically be drawn in the space.

Some graphs will become visible automatically (provided their percent is not 0) if data or lines should be shown there. They take a default value of 20.

points

A hash ref controlling how the price data is to be displayed. Only relevant for the price graph. These are the recognized keys; see PostScript::Graph::Style for details.

    size        shape*      color       width
    inner_color outer_color inner_width outer_width

*The allowed values for shape are 'stock', 'stock2', 'close' and 'close2' and NOT as listed under "shape" in PostScript::Graph::Style.

sequence

Lines added to a graph are shown by default with slightly differing styles controlled by a PostScript::Graph::Sequence object. Each graph has a default sequence which can be accessed by the sequence() method. Alternatively, you can set up your own sequence and declare it here. See PostScript::Graph::Style for details.

show_dates

True if the dates axis is to be shown under this chart. By default the dates are placed under the first graph that hasn't specified show_dates => 0.

y_axis

These keys are recognized within y_axis. See PostScript::Graph::Paper for details.

    color       heavy_color mid_color   light_color
    smallest    heavy_width mid_width   light_width
    title       mark_min    mark_max    label_gap
    si_shift

MAIN METHODS

sequence( graph )

This provides access to the PostScript::Graph::Sequence object which by default controls the styles of lines placed on each of the graphs. graph is one of 'prices', 'volumes', 'cycles', 'tests'.

Example

Here, a number of lines (moving averages) are drawn on a chart. Each line will be given a different colour even though they are all have the same style options.

    my $fss = Finance::Shares::Sample(
        ... );
    my $fsc = Finance::Shares::Chart(
        sample   => $fss, ... );

    my $pseq = $fsc->sequence( 'prices' );
    $pseq->auto( qw(color dashes shape) );
    
    my $style = {
        sequence => $pseq,
        width    => 2,
    };
    
    $fss->simple_average(
        period   => 5,
        style    => $style,
    );

    $fss->simple_average(
        period   => 15,
        style    => $style,
    );

    $fss->simple_average(
        period   => 30,
        style    => $style,
    );

See PostScript::Graph::Style for details concerning sequences and styles.

output( [filename [, directory]] )

The graphs are constructed and written out to a PostScript file. A suitable suffix (.ps, .epsi or .epsf) will be appended to the file name.

If no filename is given, the PostScript text is returned. This makes handling CGI requests easier.

SUPPORT METHODS

build_chart( [file] )

If given, file should be a PostScript::File object or a hash ref suitable for creating one.

This writes the appropriate PostScript to either the file given or one created internally. This is normally called by output() and should only need calling directly if several charts are to be placed on the same file.

Example

    # Create the file
    my $pf = new PostScript::File(...);

    # Create the necessary samples
    my $s1 = new Finance::Shares::Sample(...);
    my $s2 = new Finance::Shares::Sample(...);
    my $s3 = new Finance::Shares::Sample(...);
    
    # add lines as required
    $s1->add_line(...);
    $s2->add_line(...);
    ...
    
    # Create a chart object for each sample
    my $ch1 = new Finance::Shares::Chart(
        file   => $pf,
        sample => $s1,
        ... );
    my $ch2 = new Finance::Shares::Chart(
        file   => $pf,
        sample => $s2,
        ... );
    my $ch3 = new Finance::Shares::Chart(
        file   => $pf,
        sample => $s3,
        ... );

    # add more lines if required
    $s3->add_line(...);
    
    # Build the charts on seperate pages
    $ch1->build_chart();
    $pf->newpage();
    
    $ch2->build_chart();
    $pf->newpage();
    
    $ch3->build_chart();
    $pf->newpage();

    # Output the file
    $pf->output($filename);

visible( graph [, entry ] )

Returns true if the graph or line is visible. graph must be one of the graph names. If entry is given it should be a ref to the line's data structure, as stored in Sample.

sample()

Return the Finance::Shares::Sample holding the data for this chart.

title()

Return the heading printed at the top of the chart.

page( [id] )

Return the page identifier, if any.

If id is given this replaces the returned value.

CLASS METHODS

The PostScript code is a class method so that it may be available to other classes that don't need a Stock object.

The useful functions in the 'gstockdict' dictionary draw a stock chart mark and a close mark in either one or two colours.

   make_stock
   make_stock2
   make_close
   make_close2

The all consume 5 numbers from the stack (even if they aren't all used):

    x yopen ylow yhigh yclose
   

gstockdict

A few functions are defined in the gstockdict dictionary. These provide the code for the shapes drawn as price marks. These dictionary entries are defined:

    make_stock  Draw single price mark
    make_stock2 Draw double price mark
    make_close  Draw single closing price mark
    make_close2 Draw double closing price mark
    yclose      parameter
    ylow        parameter
    yhigh       parameter
    yopen       parameter
    x           parameter
    dx          working value

A postscript function suitable for passing to the shape option to new must have 'make_' preprended to the name. It should take 5 parameters similar to the code for shape = 'stock'> which is called as follows.

    x yopen ylow yhigh yclose make_stock
    

EXPORTED FUNCTIONS

deep_copy( var )

var is returned unless it is, or contains, a hash ref or an array ref. These are copied recursively and the copy is returned.

BUGS

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::Sample, PostScript::Graph::Style and Finance::Shares::Model.

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