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; |