NAME
Finance::Shares::Model - Apply tests to stock quotes
SYNOPSIS
Most usage requires at least one Sample with some function lines calculated on it's data. The functions and data are compared to produce a test line and possibly trigger signals.
use Finance::Shares::Model;
use Finance::Shares::Sample;
use Finance::Shares::Bands;
use Finance::Shares::Chart;
my $fsm = new Finance::Shares::Model;
my $fss = new Finance::Shares::Sample(...);
$fsm->add_sample( $fss );
$fsm->add_signal('mark_buy', undef, {
graph => 'volumes',
line => 'volume',
key => 'above envelope',
style => {
point => {
color => [1, 0, 0],
shape => 'circle',
size => 15,
},
},
});
my ($high, $low) = $fss->envelope(
graph => 'prices', line => 'close',
percent => 3,
);
$fsm->test(
graph1 => 'prices', line1 => $high,
graph2 => 'prices', line2 => 'high',
test => 'ge',
graph => 'signals',
signal => [ 'mark_buy' ],
);
my $fsc = new Finance::Shares::Chart(
sample => $fss,
);
$fsc->output($filename);
This pseudo-example draws a circle around the volume where a day's highest price is more than 3% above the previous closing price.
DESCRIPTION
This module provides the testing enviroment for the Finance::Shares suite. The 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 usually seen using Finance::Shares::Chart.
Unusually, the Finance::Shares::Model constructor does nothing. However, nothing will happen until add_sample has been called at least once. The 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 three 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 currently available are:
gt 1st line moves above 2nd
lt moves below
ge moves above or touches
le moves below or touches
eq touches
ne doesn't touch
The tests produce data lines in the standard format. This means that data, functions and tests can be used interchangeably. They can all be graphed (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.
These results lines are analog in that they can take a range of values. Indeed they can be made to fade over time. But they represent a state or level at any particular time. 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_buy
-
Places a mark on a graph.
- mark_sell
-
Places a mark on a graph.
- print_value
-
Write signal results to a file.
-
Print a message on the console.
- custom
-
Invoke a user defined callback.
CONSTRUCTOR
new
There are no options. All settings are given using add_sample, add_signal, test and output.
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( signal, [ object [, args ]] )
Register a callback function which will be invoked when some test evaluates 'true'.
- 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
are passed as key => value pairs, with the following as known keys.
- graph1
-
The graph holding
line1
. Must be one of 'prices', 'volumes', 'cycles' or 'signals'. - 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 'signals'. Defaults tograph1
. - 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.
- 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 'signals'.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. - line
-
An optional string identifying the results data in case you wish to refer to them in another test. Provided for completeness, but it is much better to use the internal one returned by this method.
- key
-
The string which will appear in the Key panel identifying the test results.
- 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 signal line. This amount is added to the signal value with each period.
- signal
-
This should be one or more of the signals registered with this model. It can either be a single name or an array ref holding a list of names.
The results line would typically be shown on the 'signals' 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 makes handling CGI requests easier.
Examples
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.
$fsm->output('myfile');
The default A4 landscape page(s) is/are saved as myfile.ps.
my $pf = new PostScript::File(...);
my $file = $fsm->output($pf);
PostScript is returned for printing using CGI.pm for example. The pages are formatted according to the PostScript::File parameters. The same result would have been obtained had $pf been a hash ref.
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 this 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 of the signal is also passed to the handler.
mark_buy
A 'buy' 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('mark_buy', undef, {
graph => 'prices',
value => 440,
});
- graph
-
One of prices, volumes, cycles or signals.
- value
-
If present, this should be a suitable Y coordinate. No bounds checking is done.
- line
-
If no
value
is given, the value may be obtained from the line identified by this string. - 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 and bar make no sense). (Default: blue arrow).
- shown
-
Optional flag, true if the mark is to be shown (Default: 1)
mark_sell
Draws a 'sell point'. See mark_buy.
print_value
This is the heavy duty print signal. See "print" for a lighter weight one.
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.
Example 1
$fsm->add_signal('print_value', undef, {
message => 'Volume is $value at $date',
graph => 'volumes', line => 'volume',
});
- message
-
This is the string that is output. It may include
$date
and$value
, which will be replaced with the date and value for that signal. Note that this should be given in single quotes or with the '$' signs escaped. $date and $value look like variables but are actually just placeholders. - graph
-
One of prices, volumes, cycles or signals.
- value
-
If present, this should be a suitable Y coordinate. No bounds checking is done.
- line
-
If no
value
is given, the value may be obtained from the line identified by this string. - file
-
If given, this should be an already open file handle. It defaults to
\*STDOUT
.
Example 2
my $fsm = new Finance::Shares::Model;
my $sfile;
open $sfile, '>>', 'signals.txt';
$fsm->add_signal('print_value', undef, {
message => '$date',
file => $sfile,
});
$fsm->test(
graph1 => 'prices', line1 => 'close',
graph1 => 'prices', line2 => 'open',
test => 'gt',
signal => 'print_value',
);
close $sfile;
Here a list of dates are written to the file 'signals.txt' instead.
This is the lightweight print signal. See "print_value" for a fuller featured one.
It prints a string to STDOUT when the test evaluates 'true'.
Register the signal like this:
my $fsm = new Finance::Shares::Model;
$fsm->add_signal('print', 'Some message');
or even
$fsm->add_signal('print');
Note that this is slighty different from all the others - there is no undef
(the object placeholder).
custom
Use this to register your own callbacks. When your function is called, date
will always be the first parameter, followed by any args
given here. The format is as follows:
$fsm->add_signal( 'custom', <coderef>, @args );
Example
my $fss = new Finance::Shares::Sample(...);
my $fsm = new Finance::Shares::Model;
my $level = $fss->value(
graph => 'volumes', value => 250000
);
sub some_func {
my ($date, @args) = @_;
...
}
$fsm->add_signal( 'custom', \&some_func,
3, 'blind', $mice );
$fsm->test(
graph1 => 'volumes', line1 => 'volume',
graph1 => 'volumes', line2 => $level,
test => 'gt',
signal => 'custom',
);
Here &some_func will be be called with four parameters whenever the volume moves above 250000.
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
Please report those you find to the author.
AUTHOR
Chris Willmot, chris@willmot.org.uk
SEE ALSO
Finance::Shares::Sample, Finance::Shares::Chart.
There is also an introduction, Finance::Shares::Overview and a tutorial beginning with Finance::Shares::Lesson1.