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

NAME

Finance::Shares::Model - Apply tests to stock quotes

SYNOPSIS

    use Finance::Shares::Model;

Two ways to use this module. Either all the data can be given to the constructor, with the model run immediately, or tests can be administered piece by piece in a script.

These two approaches are illustrated here. Both draw circles around the volume where a day's highest price is more than 3% above the previous closing price.

Packaged model

    use Finance::Shares::Model;
    use Finance::Shares::Bands;

    my $fsm = new Finance::Shares::Model(
        sources => [
            db => {
                # Finance::Shares::MySQL options
            },
        ],
    
        charts => [
            main => {
                # Finance::Shares::Chart options
            },
        ],

        files => [
            myfile => {
                # PostScript::File options
            },
        ],

        functions => [
            env => {
                function => 'envelope',
                percent  => 3,
            },
        ],

        tests => [
            good_vol => {
                graph1 => 'prices', line1 => 'env_high',
                graph2 => 'prices', line2 => 'high',
                test   => 'ge',
                graph  => 'tests',
                signal => [ 'highlight_volume' ],
            },
        ],

        signals => [
            highlight_volume => [ 'mark', {
                graph => 'volumes',
                line  => 'volume',
                key   => 'price above envelope',
                style => {
                    point => {
                        color => [1, 0, 0],
                        shape => 'circle',
                        size  => 15,
                    },
                },
            }],
        ],

        groups => [
            main => {
                source    => 'db',
                functions => ['env'],
                tests     => ['good_vol'],
                chart     => 'main',
                file      => 'myfile',
            },
        ],

        samples => [
            stock1 => {
                # Finance::Shares::Sample options
            },
        ],
    );
    
    $fsm->output();
    

Low level control

    use Finance::Shares::Model;
    use Finance::Shares::MySQL;
    use PostScript::File;
    use Finance::Shares::Sample;
    use Finance::Shares::Chart;

    use Finance::Shares::Bands;
    
    my $sql = new Finance::Shares::MySQL(...);
    my $psf = new PostScript::File(...);
    my $fss = new Finance::Shares::Sample(
        source     => $sql,
        file       => $psf,
        ...
    );
    
    my $fsm = new Finance::Shares::Model;
    $fsm->add_sample( $fss );
    $fsm->add_signal('highlight_volume', 'mark', undef, {
        graph => 'volumes',
        line  => 'volume',
        key   => 'price above envelope',
        style => {
            point => {
                color => [1, 0, 0],
                shape => 'circle',
                size  => 15,
            },
        },
    });

    my ($high, $low) = $fss->envelope( percent => 3 );
    $fsm->test(
        graph1 => 'prices', line1 => $high,
        graph2 => 'prices', line2 => 'high',
        test   => 'ge',
        graph  => 'tests',
        signal => [ 'highlight_volume' ],
    );

    my $fsc = new Finance::Shares::Chart(
        sample => $fss,
        ...
    );
    $fsc->output('myfile');       
        

DESCRIPTION

This module provides the testing enviroment for the Finance::Shares suite. A model brings a group of Finance::Shares::Samples together and applies tests to them all. The tests usually rely on functions from other modules such as Finance::Shares::Averages, and the results are displayed on a Finance::Shares::Chart.

Either the Finance::Shares::Model constructor is passed no options or it is passed details of the whole model. The latter format is covered under the CONSTRUCTOR options.

If the constructor has no options, nothing will happen until add_sample has been called at least once (and add_signals if signals are used in the tests). Tests are applied to all samples, which don't need to have anything in common with each other. However, if the date ranges are completely different it would probably be better to run seperate models. This is because the Model's date range covered by each of the tests is made from all dates in all samples.

The tests

The tests currently available are:

    gt      1st line moves above 2nd
    lt      1st moves below 2nd
    ge      1st moves above or touches 2nd
    le      1st moves below or touches 2nd
    eq      1st touches 2nd
    ne      1st doesn't touch 2nd
    min     Smallest of 1st and 2nd
    max     Largest of 1st and 2nd
    sum     1st + 2nd
    diff    1st - 2nd
    and     Logical 1st AND 2nd
    or      Logical 1st OR 2nd
    not     Logical NOT 1st
    test    Logical value of 1st

Tests produce data lines in the standard format. This means that data, functions and tests can be used interchangeably. Tests can all be shown on any graph (or hidden). Wherever a 'line' is expected, it can be a data, function or test line. I think a circular reference is not possible because of the declaration order, but it would be a Very Bad Thing (TM) so be aware of the possibility.

not and test are unary, only working on the first line given. The line values are converted to digital form, taking one of two values. On the tests graph, these are 0 and the weight given to the test (up to 100). Other graphs have suitable minimum and maximum values depending on the Y axis scale.

test might be considered as not(not(...)). It uses a divide value to convert the source line to 'on' or 'off'. This can be further conditioned by having this value decay over time. Another use of test is to trigger signals on pseudo-test functions like rising or undersold.

All the logical tests (and, or, not and test) can be performed for their signals only if the noline option is set.

The signals

The results lines are analog in that they can take a range of values. Indeed they can be made to decrease over time. But at any particular time they have a level or state. Signals, on the other hand, are a form of output that is inherently digital - either it has been invoked or it hasn't. All tests can have zero or more signals associated with them which are invoked when some critical change of state happens, like when one line crosses over another. Currently the following signals are available:

    mark            Places a mark on a graph
    mark_buy        Draws a blue up arrow
    mark_sell       Draws a red down arrow
    print_values    Write function/test values to a file
    print           Print a message on the console
    custom          Invoke a user defined callback

CONSTRUCTOR

A model can be specified completely in the option hash given to new(), so the whole process is very simple:

    my $fsm = new Finance::Shares::Model(
            # model specified here
        );
    $fsm->output();

The specification consists of eight resources: sources, files, charts, functions, tests, signals, groups and samples. If the name is plural, it should refer to an array holding several named hashes each describing one of them.

Example 1

    functions => [
        slow => {...},
        g    => {...},
        vol5 => {...},
    ],

new() will accept either a list of key/value pairs or a hash ref containing them, so each specification would normally be terminated by a comma.

The key/value pairs are a named group of settings, typically used to constuct an object. The name can be used anywhere else in the model specification; whenever that object needs referred to.

Example 2

    files => [
        stock1 => { ... },
        stock2 => { ... },
    ],

    charts => [
        chart1 => {
            file => 'stock2',
            ...
        }
    ],

In an array, the first entry is treated as the default and is used where that resource is not specified. Alternatively, the resource can be singular, in which case those are the default settings used throughout and given the name 'default'.

Example 3

    file => {
        paper => 'A4',
        landscape => 1,
    },

Here, the file takes on the name 'default', so would be saved as default.ps.

Notice that the singular resource name must refer to a hash. There is no singular item 'signal' as individual signals are specified as arrays and not hashes.

Sources

A source entry is anything that can be passed to the Finance::Shares::Sample option of the same name. So this could be one of the following.

array

The array ref should point to quotes data held in sub-arrays.

string

This should be the name of a CSV file holding quotes data.

hash

A hash ref holding options for creating a new Finance::Shares::MySQL object.

object

A Finance::Shares::MySQL object created elsewhere.

There must be at least one source, and the hash ref is probably the most useful. See Finance::Shares::MySQL for full details, but the top level keys that can be used here include:

    hostname        port
    user            password
    database        exchange
    start_date      end_date
    mode            tries

Example 4

    sources => [
        database => {
            user     => 'me',
            password => 'Gu355',
            database => 'mystocks',
        },
        test => 'test_file.csv',
    ],

Files

Each hash ref holds options for creating a PostScript::File object. It will be created once and any charts using it will be added on a new page.

If the files (plural) resource has been declared, it contains one or more named hash refs. These key names become the name of the file, with '.ps' appended. Any chart resource using this name as it's file entry specifies (one of) the layout(s) that will appear there. Each sample using that chart specification is therefore put in that chart's file.

See PostScript::File for full details but these are the more useful sub-hash keys:

    paper           eps
    height          width
    bottom          top
    left            right
    clip_command    clipping
    dir             file
    landscape       headings
    reencode

Example 5

    files => [
        retail => { ... },
    ],

    samples => [
        sample1 => {
            symbol => 'TSCO.L',
            file   => 'retail',
            ...
        },
    ],

Here the Tesco sample will appear as a page in the file retail.ps.

On the other hand, the specification may be held in a file (singular) hash. In this case the sample specification holds no file entry, so every chart will appear in the default file. Where the files (plural) resource is used, the default will be the first entry in the array (unless another entry has the key name 'default', when it is used instead).

The way to put all samples' charts into the same file is to have only one file, as in the example above (under 'named'). Each sample's chart will find its way there either because it was specified or because it is the default (and it happens to have a name).

Where the default has been declared as a file (singular) resource hash, it has no explicit name, so will be stored in a file called default.ps.

Charts

These are Finance::Shares::Chart options. It is probably a good idea to pre-define repeated elements (e.g. colours, styles) and use the perl variables as values in the hash or sub-hashes. See Finance::Shares::Chart for full details, but these top level sub-hash keys may be used in a chart resource:

    prices          volumes
    cycles          tests
    x_axis          key
    dots_per_inch   reverse
    bgnd_outline    background
    heading_font    normal_font
    heading

Each graph sub-hash may contain the following keys, as well as 'points' for prices and 'bars' for volumes.

    percent         show_dates
    layout          y_axis
    

When the model is run, three keys are filled internally and should NOT be specified here:

sample

The Finance::Shares::Sample object created from the samples resource is assigned to this.

file

This is specified in the samples resource. Where this is not named explicitly, the default name is assumed. The name should be a key from the files resource. The corresponding PostScript::File object will be assigned in its place.

page

The samples hashes may have a field, 'page' which is assigned here.

Functions

This array ref lists all the functions known to the model. Like the other resources, they may or may not be used. However, unlike the others, the sub-hashes are not all the same format. The only requirement is that they have an additional key, function which holds the name of the method. However, these keys are common:

    graph           line
    period          percent
    strict          shown
    style           key

Example 6

    functions => {
        grad1    => {
            function => 'gradient',
            period   => 1,
            style    => $fn_style,
        },
        grad_env => {
            function => 'envelope',
            percent  => 5,
            graph    => 'cycles',
            line     => 'grad1',
            style    => $fn_style,
        },
        expo     => {
            function => 'exponential_average',
        },
    },

Here grad1 is constructed from the Finance::Shares::Momentum method, gradient which uses closing prices by default and puts its results on the cycles graph. The Finance::Shares::Bands method envelope uses this to add lines 5% above and below the grad1 line. Another function expo uses all default values when evaluating the exponential_average method from Finance::Shares::Averages. $fn_style would probably be a hash ref holding PostScript::Graph::Style options.

If the function (singular) version is used, the function defined there takes on the name 'default'.

Tests

See "test" for details of the keys allowed in these named sub-hashes:

    graph1          line1
    graph2          line2
    test            signals
    shown           style
    graph           key
    decay           ramp
    weight

Example 7

    tests => [
        high_vol => {
            graph1 => 'volumes',
            line1  => 'v250000',
            test   => 'ge',
            signal => ['good_vol', 'record'],
            graph2 => 'volumes',
            line2  => 'volume',
            key    => 'high volume',
        },
    ],

    functions => [
        v250000 => {
            function => 'value',
            graph    => 'volumes',
            value    => 250000,
            shown    => 0,
        },
        ...
    ],
    

This will produce a line on the tests graph in the default style. The software generates keys describing each line, but they can get very long. It is often best to declare your own. See Example 8 for the signal definitions.

The function v250000 uses the value method from Finance::Shares::Sample and is not visible because the signal 'good_vol' will show where it is relevent. There would be no problem giving the same name to different resources, but calling the signal 'good_vol' and the test 'high_vol' makes the example clearer.

If the test (singular) version is used, the test defined there takes on the name 'default'.

Signals

Only the plural signals version is available. The named entries are array refs and not hash refs like all the others. They list the parameters for the add_signal method. See "add_signal".

Example 8

    signals => [
        good_vol => [ 'mark', undef, { 
            graph   => 'volumes',
            line    => 'volume',
            key     => 'volume over 250000',
        }],
        record   => [ 'print_values', {
            message => '$date: vv between hh and ll',
            lines   => {
                vv      => 'volumes::volume',
                hh      => 'prices::highest price',
                ll      => 'prices::lowest price',
            },
            masks   => {
                vv      => '%d',
                hh      => '%7.2f',
                ll      => '%7.2f',
            },
        }],
    ],

The good_vol signal rings all volumes above 250000 and record prints out the volume and price range for that day. It is even more important to provide a key to 'mark' type signals. Using the default keys quickly leads to half the page being taken up with the Key panels.

Like functions, the specifications vary according to the type of signal used - the first entry in the array ref. The second entry may be omitted if it would be undef. The third is often a hash ref passed to the signal handler, although this may be different for custom signals. See "print_values" for an explanation of the record signal entries.

Samples

A model may run tests and evaluate functions for several samples. This is where the individual samples are specified, and there must be at least one. The order is significant in that it affects how the charts are added to the file(s). The sub-hash entries include options for creating a Finance::Shares::Sample object:

    start_date      end_date
    symbol          dates_by
    mode

There are, however, some significant additions.

source

This should be the name of the sources resource to use. That value then becomes the source entry for the Finance::Shares::Sample constructor.

file

The name of the files resource specifying where the chart will go.

chart

One chart is created per sample, and this should be the name of the charts resource holding the Finance::Shares::Chart constructor options to use.

page

As mentioned under "Charts", it is possible to specify a page identifier for every chart here. Bear in mind, though, that this becomes the PostScript page 'number' and as such should be short and have no embedded spaces. The stock symbol is ideal.

functions

(Note the plural.) This should be an array ref holding the names of all the function lines to be evaluated for the sample. There is no 'default' - omitting this key means no functions are evaluated. The functions will be evaluated in the order they appear.

tests

(Note the plural.) This should be an array ref holding the names of all the tests to be performed on the sample. There is no 'default' - omitting this key means no tests are done. They will be evaluated in the order they appear.

groups

(Note the plural.) If present, this should be an array ref holding names of zero or more groups of settings. The settings are added in the order the group names are given, so later groups can override earlier settings. These can always be overridden by specifying the key directly. Notice that subsequent keys override previous ones, so if two groups both have lists of functions only the second list will be used.

If no 'groups' entry is present, the default group is assumed. To prevent this, set to '[]'.

Although it is possible to specify different dates for each sample, this should be used with care. The date range includes every date needed for every sample and an attempt is made to calculate functions and tests for them all. If there is no reason for the overlap it would be better to run seperate models only differing by stock symbol and price.

As with other resources, sample (singlular) may be used if only one is required.

Example 9

    samples => [
        1 => { symbol => MSFT, dates_by => 'weekdays', },
        2 => { symbol => MSFT, dates_by => 'weeks', },
        3 => { symbol => HPQ,  dates_by => 'weekdays', },
    ],

Note that the sample names are ignored.

It is possible to use sample (singular) to specify just one sample.

Example 10

    sample => {
        symbol     => 'BSY.L',
        start_date => '2002-10-01',
        end_date   => '2002-12-31',
        dates_by   => 'days',
        functions  => [ 'simple3', 'expo20' ],
        tests      => [ 'simple_above_expo' ],
    },

The default source, file and chart entries are assumed.

Groups

To avoid repetition it is possible to name a collection of samples settings which are used together. If a groups (or group) resource exists, the default group will be used in every sample that doesn't have a 'group' entry.

Example 11

    groups [
        basic => {
            file       => 'file1',
            chart      => 'price_only',
            start_date => '2002-01-01',
            end_date   => '2002-12-31',
            dates_by   => 'weeks',
        },
        gradient => {
            chart      => 'inc_cycles',
            functions  => [qw(simple3 grad1 chan10)],
        },
        vol_tests => {
            chart      => 'inc_signals',
            functions  => [qw(v250000 expo5 expo20)],
            tests      => [qw(high_vol move_up and)],
        },
    ],

    samples [
        1 => {
            symbol   => 'BSY.L',
            page     => 'BSY',
        },
        2 => {
            symbol   => 'BSY.L',
            page     => 'BSYm',
            dates_by => 'months',
            groups   => [qw(basic gradient)],
        },
        3 => {
            symbol   => 'PSON.L',
            file     => 'file2',
            groups   => ['vol_tests'],
        },
    ],

Assume the named references are all defined in their appropriate resource arrays. Both BSkyB samples will appear on file1.ps, but only the 'months' chart will have any lines on it. The Pearson sample will use the same dates but the chart using the 'inc_signals' specification will be written to file2.ps.

new( [ options ] )

options can be a hash ref or a list of hash keys and values. Most of the top level keys are outlined above. However, there are a few general ones controlling how this module behaves.

cgi_file

Specify the name of the file or files hash to be printed to STDOUT rather than to a file with that name. (Default: 'STDOUT')

directory

If the file names are not absolute paths, they will be placed in this directory. (Default: undef)

run

Setting this to 0 prevents the constructor from running the model. A model is assumed if there are ANY parameters: if no parameters are given, this defaults to 0, otherwise the default is 1.

verbose

Gives some control over the number of messages sent to STDERR during the process.

    0   Only fatal messages
    1   Minimal
    2   Report each process
    3+  Debugging

MAIN METHODS

add_sample( sample )

This adds stock quote data to the model. sample must be a Finance::Shares::Sample object. The results of the tests are written back to the sample which would typically be displayed on a Finance::Shares::Chart.

Multiple samples can be added. These might be for the same stock sampled over days, weeks and months, or for different stocks and different dates. Bear in mind that all tests are conducted on all dates, so it makes sense to keep the date ranges as similar as possible.

add_signal( id, signal, [ object [, args ]] )

Register a callback function which will be invoked when some test evaluates 'true'.

id

A string identifying the signal. This must be unique.

signal

This must be a known signal name, see "SIGNALS".

object

Use 'undef' here for those signals that need to use the Finance::Shares::Sample, such as 'mark_buy'. When registering print, this is the message to print and when registering a custom function, this is the function reference.

args

Any arguments that will be passed to the signal function.

See the individual signal handling methods for the arguments that signal requires.

test( options )

A test is added to the model and the resulting line added to each Sample. Signals are invoked when a date is encountered that passes the test. Tests may be binary (working on two lines) or unary (just working on one).

The method returns the identifier string for the resulting data line.

options may be either a list or a hash ref. Either way it should contain parameters passed as key => value pairs, with the following as known keys.

graph1

The graph holding line1. Must be one of 'prices', 'volumes', 'cycles' or 'tests'.

line1

A string identifying the only line for a unary test or the first line for a binary test.

graph2

The graph holding line2. Must be one of 'prices', 'volumes', 'cycles' or 'tests'. Defaults to graph1.

line2

A string identifying the second line for a binary test. For a unary test this must be undefined.

test

The name of the test to be applied, e.g 'gt' or 'lt'. Note this is a string and not a function reference.

noline

[Only logical tests and, or, not and test.] When '1', the results line is not generated. Only useful when signals are triggered and the line is not needed for other tests. (Default: 0)

shown

True if the results should be shown on a graph.

style

If present, this should be either a PostScript::Graph::File object or a hash ref holding options for creating one.

graph

The destination graph, where line will be displayed. Must be one of 'prices', 'volumes', 'cycles' or 'tests'.

If not specified, graph1 is used. This is a little odd as the scales are usually meaningless. However, as mostly the result is an on-or-off function, the line is suitably scaled so the shape is clear enough.

key

The string which will appear in the Key panel identifying the test results.

divide

[Only for not and test tests.] This sets the point dividing 'true' from 'false' and should be a value within the range of line1 values. (Default: 0)

weight

How important the test should appear. Most tests implement this as the height of the results line.

decay

If the condition is met over a continuous period, the results line can be made to decay. This factor is multiplied by the previous line value, so 0.95 would produce a slow decay while 0 signals only the first date in the period.

ramp

An alternative method for conditioning the test line. This amount is added to the test value with each period.

signals

This should be an array ref holding one or more of the signals registered with this model.

The results line would typically be shown on the 'tests' graph. Most tests are either true or false, so the line is flat by default. The line can be conditioned, however, so its value changes over time. Here are some examples of how the relevant parameters interact.

Example 1

    decay   => 0.5,
    ramp    => 0,

An exponential decay, halving with each period.

    decay   => 0.95,
    ramp    => 0,

A much shallower decaying curve.

    weight => 100,
    decay  => 1,
    ramp   => -20,

A straight line decline which disappears after five days.

    weight => 100,
    decay  => 1.983,
    ramp   => -99,

An inverted curve with the first 5 days scoring more than 85 then dropping rapidly to 0 after 7 days.

output( [psfile,] [filename [, directory]] )

psfile can either be a PostScript::File object, a hash ref suitable for constructing one or undefined.

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

If no filename is given, the PostScript text is returned. This can then be piped to gs for conversion into other formats, or output directly from a cgi script.

Example 1

    my $file = $fsm->output();

The PostScript is returned as a string. The PostScript::File object has been constructed using defaults which produce a landscape A4 page.

Example 2

    $fsm->output('myfile');

The default A4 landscape page(s) is/are saved as myfile.ps.

Example 3

    my $pf = new PostScript::File(...);
    my $file = $fsm->output($pf);

The pages are formatted according to the PostScript::File parameters. The same result would have been obtained had $pf been a hash ref.

Example 4

    my $pf = new PostScript::File(...);
    $fsm->output($pf, 'shares/myfile', $dir);

The specially tailored page(s) is/are written to $dir/shares/myfile.ps.

Note that it is not possible to print the charts individually once output() has been called. However, it is possible to output them seperately to their own files, then call this to output a file showing them all.

SIGNALS

Before they can be used signals must have been registered with the Model using add_signal. The name must then be given to test as (part of) the signal value.

Most parameters are given when it is registered, but the date and Y value of the signal is also passed to the handler.

mark

A point is drawn on a graph when the test evaluates 'true'. The following parameters may be passed to add_signal within a hash ref.

Example

    $fsm->add_signal('note_price', 'mark', undef, {
        graph => 'prices', 
        line  => 'high',
    });
    
graph

One of prices, volumes, cycles or tests. If you have specified a particular graph for the test, you probably want to set this to the same.

value

If present, this should be a suitable Y coordinate. No bounds checking is done.

line

The Y coordinate may be obtained from the line identified by this string. By default, the test line value is used. graph should be set if this is given.

key

Optional string appearing in the Key panel.

style

An optional hash ref containing options for a PostScript::Graph::Style, or a PostScript::Graph::Style object. It should only have a point group defined (line makes no sense). (Default: green circle).

shown

Optional flag, true if the mark is to be shown (Default: 1)

mark_buy

A convenience form of 'mark' providing a blue up arrow as the default style. See the signal "mark" for details.

Example

    $fsm->add_signal('buy01', 'mark_buy', undef, {
        graph => 'prices', 
        value => 440,
    });
    

mark_sell

A convenience form of 'mark' providing a red down arrow as the default style. See the signal "mark" for details.

Example

    $fsm->add_signal('sell01', 'mark_sell', undef, {
        graph => 'prices', 
        line  => 'high',
    });
    

print

This is the lightweight print signal. See "print_values" for another which can show 'live' values.

It prints a string to STDOUT when the test evaluates 'true'.

Register the signal like this:

    $fsm->add_signal('msg1', 'print', 'Some message');

or even

    $fsm->add_signal('msg2', 'print');

Note that this is slighty different from all the others - there is no undef (the object placeholder).

This is the heavy duty print signal. See "print" for a lighter weight one.

This signal is intended for constructing data files from significant events. There is a message template which can include line identifiers. When the message is output for a particular date, the line values are substituted for their identifiers.

It prints a string to a file or to STDOUT when the test evaluates 'true'. The following parameters may be passed to add_signal within a hash ref.

message

This is the string that is output. It may include $date and any number of identifiers, which will be replaced with suitable values. Note that message should be given in single quotes or with the '$' sign escaped. $date looks like a variable but is just a placeholder for the signal's date.

mask

If given this should be a printf format string specifying the format of $value, e.g. '%6.2f'.

masks

If given, this provides a mask for each of the line values. In the same format as lines.

lines

If a string or a reference to an array of strings, these are line identifiers, formed by concatenating the graph, '::' and the line key. If a hash ref is given, the line identifiers are the values associated with keys used in message. The default line identifiers are as follows, not that spaces are allowed within the string.

    prices::opening price
    prices::closing price
    prices::lowest price
    prices::highest price
    volumes::volume

Note that a case insensitive regex match is used to pick out the identifier (or hash key) within message. So avoid special characters as the results will not be what you expect.

[Future releases may change the graph::user_key identifiers to text identifiers as used in the model specification.]

file

If given, this should be an already open file handle. It defaults to \*STDOUT.

Example 1

    my $fsm = new Finance::Shares::Model;

    $fsm->add_signal('value', 'print_value', undef, {
            message => 'Signal is $value at $date', 
        });

Output the value of the test line.

Example 2

    my $fss = Finance::Shares::Sample;

    my $avgline = $fss->simple_average(
        graph => 'prices',
        period => 3,
        key => 'simple 3 day average',
    );
    
    $fsm->add_signal('note_vol', 'print_value', undef, {
        message => '$date: Volume=vv, average=avg', 
        lines   => {
            avg => 'prices::simple 3 day average',
            vv  => 'volumes::volume',
        },
    });

Show the value of other lines.

Example 3

    my $sfile;
    open $sfile, '>', 'signals.txt';
    
    $fsm->add_signal('csv', 'print_value', undef, {
        message => '$date,open,high,low,close,volume', 
        lines => {
            open   => 'prices::opening price',
            high   => 'prices::highest price',
            low    => 'prices::lowest price',
            close  => 'prices::closing price',
            volume => 'volumes::volume',
        },
        masks   => {
            open   => '%6.2f',
            high   => '%6.2f',
            low    => '%6.2f',
            close  => '%6.2f',
            volume => '10d',
        },
        file    => $sfile,
    });

    $fsm->test(
        graph1 => 'prices', line1 => 'close',
        graph1 => 'prices', line2 => $avgline,
        test   => 'gt',
        signal => 'csv',
    );

    close $sfile;

Construct a CSV file 'signals.txt' holding quotes for all the dates when the signal fires.

custom

Use this to register your own callbacks which should look like this:

    sub custom_func {
        my ($id, $date, $value, @args) = @_;
        ...
    }

where the parameters are:

    $id     The identifier given to add_signal()
    $date   The date of the signal
    $value  The value of the test invoking the signal
    @args   Optional arguments given to add_signal()
    

You would register your function with a call to add_signal with 'custom' as the signal type:

    $fsm->add_signal( 'myFunc', 'custom', \&custom_func,
                      @args );
        

Example

    my $fss = new Finance::Shares::Sample(...);
    my $fsm = new Finance::Shares::Model;
    
    # A comparison line
    my $level = $fss->value(
        graph => 'volumes', value => 250000
    );

    # The callback function
    sub some_func {
        my ($id, $date, $value, @args) = @_;
        ...
    }
    
    # Registering the callback
    $fsm->add_signal( 'MySignal', 'custom', \&some_func, 
        3, 'blind', $mice );

    # Do the test which may invoke the callback
    $fsm->test(
        graph1 => 'volumes', line1 => 'volume',
        graph1 => 'volumes', line2 => $level,
        test   => 'gt',
        signal => 'custom',
    );

Here &some_func will be be called with a parameter list like this when the volume moves above 250000:

    ('MySignal', '2002-07-30', 250064, 3, 'blind', $mice)

SUPPORT METHODS

signal( signal [, object [, param ]] )

All callbacks of the type indicated by signal will be invoked.

signal

This can be either a single signal name, or an array ref containing signal names. Allowed names include:

    mark_buy
    mark_sell
    print
    custom
object

An object may be given when the signal was registered with add_signal. But if it was not, this will be the first parameter passed instead.

param

The second parameter passed to the callback function. Any number of arguments may be passed here as an array ref.

Any other registered parameters are passed after param.

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::MySQL, Finance::Shares::Sample, Finance::Shares::Chart.

Most models use functions from one or more of Finance::Shares::Averages, Finance::Shares::Bands and Finance::Shares::Momentum as well.

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