File Coverage

blib/lib/Finance/StockAccount/Realization.pm
Criterion Covered Total %
statement 102 111 91.8
branch 14 20 70.0
condition 5 11 45.4
subroutine 24 24 100.0
pod 0 18 0.0
total 145 184 78.8


line stmt bran cond sub pod time code
1             package Finance::StockAccount::Realization;
2              
3             our $VERSION = '0.01';
4              
5 7     7   596 use strict;
  7         15  
  7         234  
6 7     7   25 use warnings;
  7         8  
  7         152  
7              
8 7     7   416 use Time::Moment;
  7         3531  
  7         119  
9 7     7   26 use Carp;
  7         8  
  7         341  
10              
11 7     7   3234 use Finance::StockAccount::AccountTransaction;
  7         12  
  7         179  
12 7     7   3213 use Finance::StockAccount::Acquisition;
  7         13  
  7         6162  
13              
14             # qw(Symbol ROI Outlays Revenues Profit)
15             my $summaryPattern = "%-6s %7.4f %12.2f %12.2f %53.2f\n";
16              
17             sub new {
18 1006     1006 0 1151 my ($class, $init) = @_;
19 1006         4308 my $self = {
20             stock => undef,
21             divestment => undef,
22             acquisitions => [],
23             costBasis => 0,
24             revenue => 0,
25             realized => 0,
26             commissions => 0,
27             regulatoryFees => 0,
28             otherFees => 0,
29             };
30 1006         2125 bless($self, $class);
31 1006 50       2320 $init and $self->set($init);
32 1006         1665 return $self;
33             }
34              
35             sub addAcquisition {
36 1504     1504 0 1389 my ($self, $acquisition, $dateLimitPortion) = @_;
37 1504 100       2234 if (!defined($dateLimitPortion)) {
38 4         5 $dateLimitPortion = 1; # Assume no date limit restriction if none specified, i.e., none by default
39             }
40 1504         2507 my $shares = $acquisition->shares();
41 1504         1689 my $divestment = $self->{divestment};
42 1504         2787 my $divQuantity = $divestment->quantity();
43 1504         1362 my $divestedPortion;
44 1504 50       1854 if ($divQuantity) {
45 1504         1518 $divestedPortion = $shares / $divQuantity;
46             }
47             else {
48 0         0 croak "No shares divested in transaction, cannot proceed with realization.";
49             }
50              
51 1504         2453 my $divCommission += $divestedPortion * $divestment->commission();
52 1504         2644 my $divRegulatoryFees += $divestedPortion * $divestment->regulatoryFees();
53 1504         2468 my $divOtherFees += $divestedPortion * $divestment->otherFees();
54              
55 1504         2763 my $costBasis = 0 - $dateLimitPortion * $acquisition->cashEffect();
56 1504         2758 my $revenue = $dateLimitPortion * $divestedPortion * $divestment->cashEffect();
57 1504         1731 $self->{costBasis} += $costBasis;
58 1504         1439 $self->{revenue} += $revenue;
59 1504         1499 $self->{realized} += $revenue - $costBasis;
60 1504         2630 $self->{commissions} += $dateLimitPortion * ($acquisition->commission() + $divCommission );
61 1504         2738 $self->{regulatoryFees} += $dateLimitPortion * ($acquisition->regulatoryFees() + $divRegulatoryFees);
62 1504         2627 $self->{otherFees} += $dateLimitPortion * ($acquisition->otherFees() + $divOtherFees );
63              
64 1504         1142 push(@{$self->{acquisitions}}, $acquisition);
  1504         2274  
65 1504         2733 return 1;
66             }
67              
68             sub set {
69 1006     1006 0 890 my ($self, $init) = @_;
70 1006         923 my $status = 1;
71 1006         783 foreach my $key (keys %{$init}) {
  1006         2282  
72 2012 50       2498 if (exists($self->{$key})) {
73 2012 100       2907 if ($key eq 'divestment') {
    50          
74 1006         853 my $divestment = $init->{$key};
75 1006 50 33     3214 if ($divestment and ref($divestment)) {
76 1006         1798 $self->{divestment} = $divestment;
77             }
78             else {
79 0         0 $status = 0;
80 0         0 warn "Invalid divestment value in Realization intialization hash.\n";
81             }
82             }
83             elsif ($key eq 'stock') {
84 1006         1612 $self->{$key} = $init->{$key};
85             }
86             else {
87 0         0 $status = 0;
88 0         0 warn "Unable to initialize Realization object with $key parameter.\n";
89             }
90             }
91             else {
92 0         0 $status = 0;
93 0         0 warn "Tried to set $key in Realization object, but that's not a known key.\n";
94             }
95             }
96 1006         1353 return $status;
97             }
98              
99             sub ROI {
100 54     54 0 49 my $self = shift;
101 54         58 my $costBasis = $self->{costBasis};
102 54 50       73 if ($costBasis) {
103 54         553 return $self->{realized} / $costBasis;
104             }
105             else {
106 0         0 warn "Realize method finds no cost basis upon which to compute ROI.\n";
107 0         0 return undef;
108             }
109             }
110              
111             sub acquisitionCount {
112 1005     1005 0 952 my $self = shift;
113 1005         742 return scalar(@{$self->{acquisitions}});
  1005         3495  
114             }
115              
116             sub startDate {
117 387     387 0 333 my $self = shift;
118 387         330 my $startDate;
119 387         338 foreach my $acquisition (@{$self->{acquisitions}}) {
  387         565  
120 667 100       1941 if (!$startDate) {
121 387         713 $startDate = $acquisition->tm();
122             }
123             else {
124 280         472 my $tm = $acquisition->tm();
125 280 100       755 if ($tm < $startDate) {
126 186         301 $startDate = $tm;
127             }
128             }
129             }
130 387         958 return $startDate;
131             }
132              
133             sub endDate {
134 387     387 0 340 my $self = shift;
135 387         387 my $divestment = $self->{divestment};
136 387         651 return $divestment->tm();
137             }
138              
139              
140 378     378 0 790 sub divestment { return shift->{divestment}; }
141 378     378 0 693 sub acquisitions { return shift->{acquisitions}; }
142 1277     1277 0 3346 sub costBasis { return shift->{costBasis}; }
143 890     890 0 2053 sub revenue { return shift->{revenue}; }
144 389     389 0 755 sub realized { return shift->{realized}; }
145 387     387 0 571 sub commissions { return shift->{commissions}; }
146 387     387 0 535 sub regulatoryFees { return shift->{regulatoryFees}; }
147 387     387 0 564 sub otherFees { return shift->{otherFees}; }
148              
149             sub headerString {
150 2     2 0 327 return Finance::StockAccount::Transaction->lineFormatHeader() . '-'x94 . "\n" .
151             sprintf("%-6s %7s %12s %12s %53s\n", qw(Symbol ROI Outlays Revenues Profit));
152             }
153              
154             sub divestmentLineFormatString {
155 54     54 0 48 my $self = shift;
156 54         58 my $divestment = $self->{divestment};
157 54         97 my $proportion = $divestment->accounted() / $divestment->quantity();
158 54         96 my $lineFormatValues = $divestment->lineFormatValues();
159 54         61 $lineFormatValues->[5] *= $proportion;
160 54         47 $lineFormatValues->[6] *= $proportion;
161 54         35 $lineFormatValues->[7] *= $proportion;
162 54         116 return sprintf(Finance::StockAccount::Transaction->lineFormatPattern(), @$lineFormatValues);
163             }
164              
165             sub string {
166 54     54 0 53 my $self = shift;
167 54         64 my $divestment = $self->{divestment};
168 54         45 my $string;
169 54         42 foreach my $acquisition (@{$self->{acquisitions}}) {
  54         90  
170 93         196 $string .= $acquisition->lineFormatString();
171             }
172 54   50     90 $string .= $self->divestmentLineFormatString . '-'x94 . "\n" .
      50        
      50        
      50        
173             sprintf($summaryPattern, $divestment->symbol(), $self->ROI() || 0, (0 - $self->{costBasis}) || 0, $self->{revenue} || 0, $self->{realized} || 0);
174 54         228 return $string;
175             }
176              
177              
178              
179              
180              
181             1;