added security type models, improved cashflow, bug- and layout fixes along the way
[smr.git] / gui / lib / smr / asset.rb
blob4cbcc0d979e27d94c3e593a6a8e1b9faac9a8058
2 # This file is part of SMR.
4 # SMR is free software: you can redistribute it and/or modify it under the
5 # terms of the GNU General Public License as published by the Free Software
6 # Foundation, either version 3 of the License, or (at your option) any later
7 # version.
9 # SMR is distributed in the hope that it will be useful, but WITHOUT ANY
10 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License along with
14 # SMR.  If not, see <http://www.gnu.org/licenses/>.
16 require 'asset_position'
18 module Smr  #:nodoc:
19   ##
20   # Total assets of current user at some point in time.
21   #
22   # Use #open_positions to access Smr::AssetPosition objects of all positions
23   # held. Then each knows more details about itself.
24   class Asset
25       # collection of Smr::AssetPosition objects of currently open positions
26       attr_reader :open_positions
28       # currently invested amount of money
29       attr_reader :invested
31       # current market value of all assets
32       attr_reader :market_value
34       # current profit/loss on all assets
35       attr_reader :profit_loss
37       # current collateral_coverage_value of all assets
38       attr_reader :collateral_coverage_value
40       ##
41       # age of +Quote+ data before its considered old
42       QUOTE_OUTDATED_DAYS = 4
43   
44       ## 
45       # date defines the point of Time this object sits at
46       def initialize(id_user, date, options={:id_portfolio=>false, :skip_cash_positions=>false})
47           raise 'date must be of Time' unless date.is_a?(Time)
50           @id_user = id_user
51           @date = date
53           limit_portfolio = if options[:id_portfolio] then 'AND po.id=%i' % options[:id_portfolio] else '' end
54           skip_cash_positions = if options[:skip_cash_positions] then 'AND s.id != %i' % Smr::ID_CASH_SECURITY else '' end
55   
56           @invested = 0.0
57           @market_value = 0.0
58           @profit_loss = 0.0
59           @collateral_coverage_value = 0.0
60   
61           @_have_old_quotes = false
62           @_have_missing_quotes = false
63   
64           @open_positions = Array.new
66           # ATTENTION: not portable!
67           # - thats not the preferred way to do a query.
68           # - this one is just too complex for ActiveRecord at the moment
69           open_positions = Smr::AssetPositions.new(@date, '
70           SELECT
71               p.id
72          /*   p.id_security,
73               p.id_portfolio,   # if those values could be used
74               pr.id_order,      # things would be much faster since
75               pr.id_position,   # subsequent SmrPosition objects query
76               pr.date,          # these again... too many queries...
77               pr.shares,
78               pr.invested */
79           FROM
80               position p,
81               position_revision pr,
82               security s,
83               portfolio po,
84               (SELECT
85                   MAX(pr1.date) AS LASTDATE,
86                   pr1.id_position AS LASTPOSITION
87                   FROM
88                       position_revision pr1
89                   WHERE
90                       pr1.date<=%i
91                   GROUP BY pr1.id_position
92               ) AS blah
93           WHERE
94               p.id=pr.id_position
95               %s
96               %s
97               AND p.id_portfolio=po.id
98               AND s.id=p.id_security
99               AND po.id_user=%i
100               AND (p.closed=0 OR p.closed>%i)
101               AND pr.date=LASTDATE
102               AND pr.id_position=LASTPOSITION
103               AND po.name NOT LIKE "watchlist:%%"   /* HACK for speed on old DBs */
104           GROUP BY p.id
105           ORDER BY pr.date' % [@date, limit_portfolio, skip_cash_positions, @id_user, @date]).get_all
106   
107           # turn Position objects into SmrPosition
108           # - for the sake of performance we calculate totals right here
109           open_positions.each do |p|
110               sp = Smr::AssetPosition.new(p.id, id_user, @date)
111               @open_positions << sp
112   
113               @invested += sp.invested
114               @market_value += sp.market_value if sp.market_value
115               @profit_loss += sp.profit_loss if sp.profit_loss
116               @collateral_coverage_value += sp.collateral_coverage_value
117   
118               if not sp.market_value then @_have_missing_quotes = true end
119               if sp.quote_time and  sp.quote_time < QUOTE_OUTDATED_DAYS.days.ago then
120                   @_have_old_quotes = true
121               end 
122           end
123       end
124   
125       public
127       # tell whether this Asset report includes outdated quotes
128       def have_old_quotes?
129           @_have_old_quotes
130       end
131   
132       # tell whether this Asset report is lacking quote data
133       def have_missing_quotes?
134           @_have_missing_quotes
135       end
136   end
138 end # module