NAME
Finance::StockAccount - Analyze past transactions in a personal stock account.
VERSION
Version 0.01
SYNOPSIS
Analyze past transactions in a personal stock account. Find out your total profit, annual profit, quarterly profit, monthly profit, or profit for any other arbitrary date/time range. Discover what the most cash you had invested in stocks at once was, over the course of your account from when it opened to the present, or for any period. Or get the total cash you spent on all stock purchases, call that your totalOutlays and learn how the ratio of profit to that totalOutlays changed from period to period. Find out how much you spent on commissions. Match up the results with your experience by looking at profit for each stock symbol separately.
use Finance::StockAccount;
# Object-oriented, so instantiate your object
my $sa = Finance::StockAccount->new();
# Now add your trades
# One (fake/fantasy) trade a day for a week in January...
$sa->stockTransaction({ # total outlay: 1000
symbol => 'AAA',
dateString => '20140106T150500Z', # This is a Time::Moment string, more on that below
action => 'buy', # in the 'Required: date' section
quantity => 198,
price => 5,
commission => 10,
});
$sa->stockTransaction({ # total outlay: 1000
symbol => 'BBB',
dateString => '20140107T150500Z',
action => 'buy',
quantity => 99,
price => 10,
commission => 10,
});
$sa->stockTransaction({ # total revenue: 600
symbol => 'AAA',
dateString => '20140108T150500Z',
action => 'sell',
quantity => 100,
price => 6.10,
commission => 10,
});
$sa->stockTransaction({ # total revenue: 1070
symbol => 'BBB',
dateString => '20140109T150500Z',
action => 'sell',
quantity => 99,
price => 11,
commission => 19,
});
$sa->stockTransaction({ # total revenue: 670
symbol => 'AAA',
dateString => '20140110T150500Z',
action => 'sell',
quantity => 98,
price => 7,
commission => 16,
});
# How much did you make (or lose)?
$sa->profit(); # 340
# What was the most cash you had invested in stocks at once?
$sa->maxCashInvested(); # 2000
# How much profit did you make as a share of the max you invested?
$sa->profitOverMaxCashInvested(); # 0.17
# Prefer just profit over outlays? No problem. It happens to be the same in this case.
$sa->profitOverOutlays(); # 0.17
# If you kept up that rate of profit over a year how much would you make?
$sa->profitOverYears(); # 31046.25 (Wish I were that lucky.)
# How much did you pay your broker?
$sa->commissions(); # 65
# How many transactions were counted in these statistics?
$sa->numberOfTrades(); # 5
# Get a list of statistics you can loop through
my $stats = $sa->stats();
# or get it broken down by date period
$sa->annualStats();
$sa->quarterlyStats();
$sa->monthlyStats();
# Want me to iterate through it and make it a string for you?
print $sa->statsString();
# Want that by date too?
print $sa->annualStatsString();
print $sa->quarterlyStatsString();
print $sa->monthlyStatsString();
# Get a simple one-stock-per-line breakdown of how you did
print $sa->summaryByStock();
# Need to exclude a couple stocks from analysis?
$sa->skipStocks(qw(AAA BBB));
# Include AAA and BBB again
$sa->resetSkipStocks();
# Curious how the module is doing its accounting?
# Print the realizations (matches of acquisitions to divestment):
print $sa->realizationsString();
My online brokerage account does not allow me to easily see how my stock account is performing. With a little research, I found this was common practice with both online and offline brokerages, as well as financial advisers. So I wrote this software to find out my actual account performance, and shared these modules so others could find out theirs.
This is a pure stock-transaction based set of modules. Currently understood transaction types include buy, sell, short, and cover. This version (version 0.01) does not consider cash or dividends, but I would like to add those features in future releases. Because of that limitation, calculations cannot be based purely on cash -- but rather on appreciation and depreciation of stocks, and timing of transactions -- which gives an interesting (and I think useful) perspective on account performance.
Looking at the "Analyze" tools in my OptionsXpress online brokerage account, I saw it always used a "Last In, First Out" accounting method, which, frankly, is ridiculous in terms of evaluating my stock trading performance.
So in these modules, accounting is done by what I call the Greatest Realized Benefit (GRB) method: divestments (sales and covers) are processed from oldest to newest, and one or more prior acquisitions (buys and shorts) are matched with the sale by availability (meaning not all acquisition shares are already tied to another divestment) and lowest cost of the acquisition. Future releases may add alternative accounting methods that could be selected by the user, and I welcome your suggestions for those.
Along the way I tried to create a pure stock transaction class and a pure stock class. If you need such a thing, please look at
Finance::StockAccount::Transaction
Finance::StockAccount::Stock
which are included in the Finance::StockAccount installation.
If you happen to have an OptionsXpress online brokerage account you can import the whole thing in one go with Finance::StockAccount::Import::OptionsXpress. I would like to add more formats, so, if you can, please donate an export from a brokerage account to help this along.
Dates are stored as Time::Moment objects, and may be specified either as a Time::Moment object (using the 'tm' property) or one of the string formats natively understood by Time::Moment (using the 'dateString' property).
EXPLANATION
This set of modules is intended to give the lay investor (as opposed to the high finance Wall Street type who already has a bunch of expensive tools available to him) a meaningful sense of how his or her personal stock account is doing. It turns out a lot of both online and offline brokerages and financial advisers and institutions obscure that information from their users on the theory that if you knew how you were really doing, you would take your money elsewhere, or bug them with questions and demands for improvement. So to get the information from them, you have to get the data, make a plan, and do some accounting and some math. It's one more thing on the to-do list so many people don't get to it with any frequency.
With these modules you can get a better understanding of the performance of your personal stock account. Here's what you do: Create a new stock account object, add your past stock transactions to it, and get statistics and information from it. You can set arbitrary date limits, to constrain that information to a certain period, or use built in methods for yearly, quarterly, or monthly data.
This set of modules deals purely in stock transactions. There is no concept of cash transactions. Currently there is not even a concept of dividends, though I intend to add that in a future release. So far it is purely concerned with acquisitions and divestments: their timing, absolute value, and relative value.
Terminology
Acquisition
A stock transaction of the type 'buy' or 'short'. This is where the consumer (or user) spends cash to gain an interest in some number of shares of a stock, buying it if she expects it to go up, shorting it if she expects it to go down.
An acquisition, or part of an acquisition, becomes the cost basis for a later divestment.
Divestment
A stock transaction of the type 'sell' or 'cover'. This is where the consumer sells her interest in a stock in return for cash, terminating the interest gained in an earlier acquisition for some number of shares and gaining cash as a result.
Realization
These modules attempt to match each divestment against one or more prior acquisition(s), and use that match to calculate profit and other statistics useful for evaluating stock account performance. A successful match between a divestment and one or more acquisitions is called a "realization" because it represents the consummation or realization of the totalOutlays.
Set
The collection of all realizations for a particular stock.
Outlay
How much cash was spent on an acquisition transaction, including commissions and fees.
Revenue
How much cash was received in a divestment, after commissions and fees have been subtracted.
Statistics, or "Why does that number look wrong?"
Unmatched transactions are not included in statistics: an acquisition that cannot be paired with a divestment, or a divestment that cannot be paired with an acquisition, is simply left out or ignored. Here's an example to illustrate why this is necessary: Suppose you bought $5,000 worth of stock 'FOO', but you haven't sold it yet. There is no way to evaluate whether that was a profitable choice or not. It could end up making you a millionaire, or its value could drop to $0.
So when you see some statistics that look different from what you expected, one of the things you might consider is whether any transactions were left out of the analysis. You can check that with the numberOfTrades and numberExcluded methods (see below). If you want more granular information, you might consider diving down to the Finance::StockAccount::Set level, which provides more tools for looking at the accounting of all trades in a specific stock.
Another area that might appear off at first inspection is the periodic stats. This module handles date range limitations by figuring out what portion of a given realization to attribute to the date range. Imagine, for example, you purchase a stock at d1 and sell it at d2. Then you set a date range limit starting at s1 and ending at s2 on this time line:
s1 s2
|---|----------------------------------------------------|---|
d1 d2
Trades on d1 and d2 are outside the date range limit set by s1 and s2. So a simple evaluation would attribute no value to that realization within this time line. But the reality is that most of the value of that realization likely accrued during this time. It's also a simplification, since I don't look up the stock price for that stock every day during that time, but this module assumes a linear change in value and attributes to date range s1 to s2 a value for this realization in proportion to the time it overlaps with the range d1 to d2. So $sa->profit() with this date range limit would return the profit for the entire realization times (s2-s1)/(d2-d1). Commissions, outlays, revenues, etc., are all divided up the same way.
Perhaps the most practical application for this rule is the periodic look at your stock performance. So when you look at annualStats, quarterlyStats, or monthlyStats, you will see what I would consider more accurate divisions of value. And a month where you did no trades would not necessarily mean a month with no stats, as acquisitions would likely be gaining or losing value.
This can have the odd-looking side effect, however, of showing you a number of trades considered in the statistics gathering that is larger than the number of trades actually made within that date range. And it means the purported "number of trades" for each period adds up to more than the total number of trades in the account. I may try to remove this side effect in a future version, so let me know if you find it too problematic or confusing...
METHODS
new
Constructor, instantiates and returns a new Finance::StockAccount object. Typically called with no arguments:
my $sa = Finance::StockAccount->new();
Currently there is only one StockAccount option/setting, which may be passed to new if desired. By default, attempts to add a stock transaction with a zero price to a StockAccount object will be treated as suspect and fail. I realize that is personal preference, so it may optionally be overcome by setting allowZeroPrice, like so:
my $sa = Finance::StockAccount->new({allowZeroPrice => 1});
This option can also be set via method (see allowZeroPrice method below).
stockTransaction
This is the intended means of adding transactions to a StockAccount object. An instantiation hash is passed in. Here is an example, me buying fifty shares of stock in Twitter:
$sa->stockTransaction({
symbol => 'TWTR',
dateString => '20140708T185304Z',
action => 'buy',
quantity => 50,
price => 37.33,
commission => 8.95,
});
Several pieces of information are required.
Required: stock
For one, there must be a stock. It may be specified as a symbol string, as above. An optional exchange string may be passed in as well:
symbol => 'TWTR',
exchange => 'NYSE', # optional
Alternatively, a stock object can be created using Finance::StockAccount::Stock and passed in with the stock key:
use Finance::StockAccount;
my $stock = Finance::StockAccount::Stock->new({
symbol => 'TWTR',
exchange => 'NYSE', # optional
});
$sa->stockTransaction({
stock => $stock,
...
});
The same $stock object could then be used over and over to pass in transactions on that stock. But even if you use a symbol string each time, they will be treated as the same stock. An exchange modifies a stock, so you could have two stocks with the same symbol traded on two different exchanges and they would be kept separate in StockAccount accounting.
Required: date
Second, there must be a date for the transaction. Dates are necessary for matching a sale to its prior purchase, or for calculating the mean annual profit (or loss), for example. Finance::StockAccount uses the CPAN module Time::Moment to handle dates. A date can either be passed in as a string using the dateString key:
dateString => '20140708T185304Z',
or a Time::Moment object can be passed in using the tm key:
my $tm = Time::Moment->new({ # the same date as the string above
year => 2014,
month => 7,
day => 8,
hour => 18,
minute => 53,
second => 4,
offset => 0,
});
$sa->stockTransaction({
symbol => 'TWTR',
tm => $tm,
...
});
If using a string passed in with the dateString key, any string acceptable to the Time::Moment->from_string method without using the 'lenient' flag will work. Please see the perldoc for Time::Moment for more information.
I chose to use Time::Moment over other Perl time modules because of its efficiency in benchmark tests and its ease of use. It seemed to do everything I needed, to do it correctly, and to do it faster than any of the alternatives. Please give it a chance, but also please do let me know if you run into any problems using it in the context of this module.
Required: action
A value for the 'action' key is required and must be one of the following strings: 'buy', 'sell', 'short', or 'cover'. E.g.:
$sa->stockTransaction({
...
action => 'sell',
...
});
Required: quantity
A numeric value for quantity greater than zero is required:
$sa->stockTransaction({
...
quantity => 60,
...
});
Required: price
A numeric value for price is also required:
$sa->stockTransaction({
...
price => 4.55,
...
});
By default, the price is required to be greater than zero, but see the 'allowZeroPrice' section below.
Additional information is not required, but can optionally be set when adding a stock transaction:
Optional: commission
$sa->stockTransaction({
...
commission => 8.95,
...
});
Optional: regulatoryFees
In the United States the Securities and Exchange Commission imposes regulatory fees on stock brokers or dealers. Instead of paying these with their profits, these for-profit companies often pass these fees on to their customers directly. The regulatoryFees
property could be used for similar purposes in other jurisdictions.
See http://www.sec.gov/answers/sec31.htm for more information.
$sa->stockTransaction({
...
regulatoryFees => 0.04,
...
});
Optional: otherFees
Any other fees that your jurisdiction, exchange, or broker adds in addition to commission and regulatory fees.
$sa->stockTransaction({
...
otherFees => 8.95,
...
});
profit
Returns the numeric total profit (or loss) for all realizations in the stock account.
my $profit = $sa->profit();
commissions
Returns the numeric total commissions paid on all included transactions.
my $commissions = $sa->commissions();
totalCommissions
Same as commissions above.
maxCashInvested
Returns the maximum cash value invested in stocks at once. Uses transaction dates and outlays to find this value.
my $maxCashInvested = $sa->maxCashInvested();
profitOverOutlays
my $profitOverOutlays = $sa->profitOverOutlays();
Returns the ratio of profit to outlays. In other words, the profit divided by the outlays.
profitOverYears
my $profitOverYears = $sa->profitOverYears();
Returns the ratio of profit to years. So if you took the seconds between the first transaction date and the last transaction date, and divided by the number of seconds in a year to get time t, this returns profit divided by time t.
regulatoryFees
my $regulatoryFees = $sa->regulatoryFees();
Returns the total of all regulatory fees paid in all transactions.
otherFees
my $otherFees = $sa->otherFees();
Returns the total of all other fees paid in all transactions.
summaryByStock
Returns a string showing how you did for each stock. It begins with a header, and then a line for each stock with the following information:
Symbol ROI Outlays Revenues Profit
with a row of dashes between each line as a visual cue for which values belong together.
print $sa->summaryByStock();
stats
Returns a reference to an array of statistics. Every other position, starting with zero, contains the name of the value stored at the next position. Here is each name prefixed by its location index:
0 startDate
2 endDate
4 maxCashInvested
6 totalOutlays
8 totalRevenues
10 profit
12 profitOverYears
14 profitOverOutlays
16 profitOverMaxCashInvested
18 pomciOverYears
20 commissions
22 regulatoryFees
24 otherFees
26 numberOfTrades
28 numberExcluded
where "pomci" is short for "Profit Over Max Cash Invested". As shown above, there is an $sa->profit() method. But if you wished to get the profit from stats instead, you could. Perl arrays are zero-indexed, and each of the above names is followed by the value, so to get the profit name and value:
my $stats = $sa->stats();
my $profitIndex = 10;
my $profitName = $stats->[$profitIndex];
my $profitValue = $stats->[$profitIndex+1];
Of course all that seems like a lot of work compared to calling $sa->profit(). But if for some reason you want to grab all the stats in one go in a reference and process them somehow, stats is the method for you.
If you are doing much of this work, I suggest looking at the code I've implemented in StockAccount.pm for methods stats() and statsString(), which might provide you with some useful guides for how to more conveniently access and traverse such information. For example:
for (my $x=0; $x<scalar(@$statsLinesArray); $x+=3) {
my ($name, $key, $valPattern) = @$statsLinesArray[$x .. $x+2];
$statsString .= sprintf("%30s $valPattern\n", $name, $stats->{$key});
}
You have access to the $statsLinesArray structure through the method of the same name:
my $statsLinesArray = $sa->statsLinesArray();
In version 0.01, it looked something like this:
my $statsLinesArray = [
'First Trade Date' => 'startDate' => '%35s',
'Last Trade Date' => 'endDate' => '%35s',
'Maximum Cash Invested at Once' => 'maxCashInvested' => '%35.2f',
'Sum Outlays' => 'totalOutlays' => '%35.2f',
'Sum Revenues' => 'totalRevenues' => '%35.2f',
'Total Profit' => 'profit' => '%35.2f',
'Profit Over Years' => 'profitOverYears' => '%35.2f',
'Profit Over Sum Outlays' => 'profitOverOutlays' => '%35.2f',
'Profit Over Max Cash Invested' => 'profitOverMaxCashInvested' => '%35.2f',
'The Above (^) Over Years' => 'pomciOverYears' => '%35.2f',
'Total Commissions' => 'commissions' => '%35.2f',
'Total Regulatory Fees' => 'regulatoryFees' => '%35.2f',
'Total Other Fees' => 'otherFees' => '%35.2f',
'Num Trades Included in Stats' => 'numberOfTrades' => '%35d',
'Num Trades Excluded from Stats' => 'numberExcluded' => '%35d',
];
I imagine this structure may change in future versions.
statsString
Many users will likely just want to print out the stats for display instead of looping through the values. This method loops through them all and creates readable formatted text you can print.
print $sa->statsString();
Note that it's only formatted up to a point. I did not add a currency notation or do much formatting on the numbers. This is partly because I don't know what currency you're using, and partly because there are good modules already written to format currency and numbers. It is a job best left to modules designed specifically for those purposes, such as Number::Format, and I suggest you grab values using other Finance::StockAccount methods and use such modules if you need good currency symbol and number formatting.
statsForPeriod
This method returns a reference to a hash of account statistics for an arbitrary date range you provide. The return value takes the following form:
{
totalOutlays => $totalOutlays,
totalRevenues => $totalRevenues,
maxCashInvested => $maxCashInvested,
profit => $profit,
profitOverOutlays => $profit / $totalOutlays,
profitOverMaxCashInvested => $profit / $maxCashInvested,
commissions => $commissions,
regulatoryFees => $regulatoryFees,
otherFees => $otherFees,
numberOfTrades => $transactionCount,
}
The date range must be provided as two Time::Moment objects:
my $statsForPeriod = $sa->statsForPeriod($tm1, $tm2);
where $tm2 should represent a time that came after $tm1. Time::Moment provides several methods instantiating new objects with date/time information. When doing so by hand, I find the most convenient one is usually the Time::Moment->from_string method:
# Create a new Time::Moment object for 2:00 PM, January 31, 2014 GMT
my $tm1 = Time::Moment->from_string("20140131T140000Z")
Please see Time::Moment's documentation for more information.
annualStats
This method basically returns a reference to an array of "statsForPeriod" hashes above, one for each year in chronological order.
annualStatsString
Iterates through annualStats and returns a string of information in columns and rows. It looks something like this:
Year Outlays Revenues MaxInvested Profit OverOut OverInvested Commiss RegFees OthFees NumTrades
2012 14454.48 15219.04 15989.18 764.56 0.05 0.05 229.99 0.37 0.00 80
2013 59995.61 65866.67 16421.24 5871.07 0.10 0.36 508.56 1.27 0.00 116
2014 28838.24 32162.69 12364.62 3324.46 0.12 0.27 237.51 0.75 0.00 73
------------------------------------------------------------------------------------------------------------------------
COL SUMS 103288.33 113248.41 44775.05 9960.08 0.27 0.67 976.05 2.38 0.00 269
------------------------------------------------------------------------------------------------------------------------
ACCT TOTAL 103288.34 113248.42 15989.18 9960.08 0.10 0.62 976.05 2.38 0.00 130
The columns explained further:
- Outlays - acquisition costs, including commissions and fees
- Revenues - divestment gains, reduced by commissions and fees
- Maximum Cash Invested - total acquisition cost at the moment of maximum simultaneous unrealized investment. Put another way: the most cash you had invested in stocks at once.
- Total Profit - revenues less outlays
- Profit Over Outlays - profit divided by outlays
- Profit Over Max Cash Invested - profit divided by max cash invested
- Total Commissions
- Total Regulatory Fees
- Total Other Fees
- Num Trades - number of trades examined that contributed to these stats values
In COL SUMS row, the columns are summed (even for columns where that doesn't make much sense), and then in the ACCT TOTAL row, total account statistics are presented.
Notice how "off" the NumTrades values look when summed compared to the account total. This is because it counts the trades in all realizations that overlap the time period, so many trades are counted twice. See "Why does that number look wrong?" above.
quarterlyStats
Like annualStats but per quarter. Here a quarter is defined by dividing up the year into four three-month periods, starting in January and ending in December.
quarterlyStatsString
Like annualStatsString but for quarter.
monthlyStats
Like annualStats but per month.
monthlyStatsString
Like annualStatsString but per month.
getSet
my $set = $sa->getSet($hashKey);
Returns the Finance::StockAccount::Set object specified by $hashKey, or undef if not found.
If you want to get into the details of the accounting for a particular set, accessing the set is the way to go. You can retrieve the set using a hashKey made up of the stock symbol and exchange in the form:
symbol:exchange
So for example, if I added stock transactions for Apple stock using the symbol AAPL and the exchange NASDAQ, my hashKey would be
AAPL:NASDAQ
The set can be returned with the getSet method passing in the hashKey as a string:
my $appleSet = $sa->getSet('AAPL:NASDAQ');
If you didn't set an exchange, which is optional for stock objects, just use the symbol:
my $appleSet = $sa->getSet('AAPL');
That will give you a Finance::StockAccount::Set object. Finance::StockAccount::Set is installed with the Finance::StockAccount module. To learn more about sets, run
perldoc Finance::StockAccount::Set
from the command line.
getSetFiltered
my $set = $sa->getSetFiltered($hashKey);
Same as getSet except it filters out all sets that are ruled out by skipStocks (see skipStocks method below) or for which there are no realizations -- no pairings of acquisition and divestment. Returns undef if no set is found matching the hashKey, containing realizations, and not on the skipStocks list.
getFilteredSets
my $sets = $sa->getFilteredSets();
Returns a reference to the array of all sets in the account that match the getSetFiltered criteria above.
realizationsString
print $sa->realizationsString();
If you want to get even further down into the weeds than Finance::StockAccount::Set objects, you can look at Finance::StockAccount::Realization objects. Sets are made up of them, so you can access them through the Set object. But for a quick overview/printout, you can use this method to retrieve a string showing each realization. The method loops through each set, and each realization within the set, retrieving a string for each one that is combined into the return value.
availableAcquisitionsString
print $sa->availableAcquisitionsString('WFM');
Returns the string showing all acquisitions not yet paired with a divestment, which one could use to evaluate cost basis for a potential sale or cover. With $hashKey passed in, it will be limited to the Set object matching $hashKey (a string in the form '<symbol>:<exchange>', e.g. 'TWTR:NYSE', or just '<symbol>', e.g. 'TWTR', if no exchange was specified on the stock).
With no arguments, loops through all sets and aggregates the data into one string.
skipStocks
After adding a bunch of transactions, or importing an entire account history, you may wish to exclude certain stocks from calculations, at least temporarily. You can do this using the skipStocks method. Pass it a string list of the stock symbols you would like to skip. If the optional exchange parameter was set, you must join the exchange string to the symbol string with a colon. For example:
$sa->skipStocks(qw(AMD TWTR:NYSE));
my $profit = $sa->profit();
...
Now any calculations, such as profit, will exclude the stock specified as symbol => 'AMD' with no exchange, and the stock specified as symbol => 'TWTR', exchange => 'NYSE'.
New calls to the method are additive, so you can add skip stocks one at a time or all at once or anywhere in between.
If you'd like to see the current set of skipStocks, you can call the method with no arguments and it will return an alphabetically sorted list of strings:
print join(', ', $sa->skipStocks()), "\n"; # prints "AMD, TWTR:NYSE\n"
If there are no skip stocks to return, it will return undef.
resetSkipStocks
Use this method to reset the skipStocks list to an empty list.
allowZeroPrice
Transactions where the price is zero are treated as suspect by default, and stockTransaction will not add them to the StockAccount object. However, there are some legitimate use cases where one might want them to be included, so you can set the allowZeroPrice option on the StockAccount object to do that:
$sa->allowZeroPrice(1); # allow transactions with price == 0
$sa->allowZeroPrice(0); # disallow transactions with price == 0
or check the value with the same method and no arguments:
if ($sa->allowZeroPrice()) {
... do something ...
}
As mentioned above, it can also be set using the new method, described above.
INSTALLATION
A classic and still great means of installing a Perl module is basically as follows. Download the tarball, extract it somewhere, and then in that directory run these commands:
perl Makefile.PL
make
make test
make install
Of course there are lots of options and alternatives. For example, say you were on unix or linux and you created a "plib" directory in your home directory and configured Perl to look there, and you wanted to install there instead. You could change that first line to do that:
perl Makefile.PL INSTALL_BASE=~/plib
And there are lots of other things you can do. I recommend looking at
perldoc ExtUtils::MakeMaker
(or just view it on cpan or metacpan) for more information.
Also, there are several tools for installing Perl modules, such as cpanm. Many of them will install dependencies for you. I did not test my distribution with all such tools, so please let me know if you have problems installing this module with any of them.
This is by no means meant as an authoritative guide for how to install Perl modules: there is a lot of good material on that subject online and in perldoc pages, so please look for those sources.
MORE EXAMPLES
If you download this module as a tarball from cpan or metacpan and extract it somewhere, you should see a
t/
directory. In there are tests written for this module, providing more examples of code that makes use of this module. Note that much of this code was written specifically to test features and methods of this module, and may not represent typical or ideal usage. Note that several of these tests require the files in
t/data/
to work.
AUTHOR
John Everett Refior, <jrefior at gmail.com>
BUGS
Please report any bugs or feature requests to bug-finance-stockaccount at rt.cpan.org
, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Finance-StockAccount. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
SUPPORT
You can find documentation for this module with the perldoc command.
perldoc Finance::StockAccount
You can also look for information at:
RT: CPAN's request tracker (report bugs here)
http://rt.cpan.org/NoAuth/Bugs.html?Dist=Finance-StockAccount
AnnoCPAN: Annotated CPAN documentation
CPAN Ratings
Search CPAN
ACKNOWLEDGEMENTS
I would like to thank the Perl Monks for contributing their wisdom when I posted questions about how to handle date/time and whether there was already a module capable of doing what I planned.
LICENSE AND COPYRIGHT
Copyright 2014 John Everett Refior.
This program is free software; you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at:
http://www.perlfoundation.org/artistic_license_2_0
Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license.
If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license.
This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder.
This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed.
Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.