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
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/>.
19 # Total assets of current user at some point in time.
21 # Use #open_positions to access Smr::AssetPosition objects of all positions
22 # held. Then each knows more details about itself.
25 # Ransack Gem query object, ie for use in controllers or views.
29 # Makes the watchlist with Quote information at :date. The given User
30 # should be authenticated!
32 # By default a set of 15 randomly selected securities is shown. To see
33 # more, provide a :ransack_query.
34 # This is for the sake of speed at the first look. There might be
35 # hundrets to throusands of Security records in the database. Its no good
36 # to select all of them at once.
38 # Option :ransack_query is the query produced by Ransack's #search_form
39 # helper method. It will be used to select Security records.
41 # Optional :exclude_securities may give a collection if Security.id
42 # numbers that should not be shown in the watchlist.
45 # Note: if the :ransack_query contains #sorts, only the first (!) one
46 # will actually be used and passed on to Smr::WatchlistItem as
48 def initialize(user, date,
50 :exclude_securities=>false,
51 :provides_collateral=>false, :provides_cashflow=>false,
52 :provides_huge_coupon=>false, :provides_subannual_payments=>false,
53 :matures_within_year=>false,
57 raise ':user must be of User' unless user.is_a?(User)
58 raise ':date must be of Time' unless date.is_a?(Time)
63 exclude_securities = [ Smr::ID_CASH_SECURITY ]
64 exclude_securities += options[:exclude_securities] if options[:exclude_securities]
65 @filters = options[:filters] if options[:filters]
68 if options[:ransack_query]
69 @query = Security.ransack(options[:ransack_query])
72 @query = Security.where(:id=>Array.new(15).map{|e| rand(c)}).ransack
75 @query.result.includes(:Organization,:SecurityBond,:SecurityStock).to_a.uniq.each do |s|
77 next if exclude_securities.include?(s.id)
78 next if s.is_expired?(date) or s.has_trading_ceased?(date)
79 next if options[:provides_collateral] and s.collateral_coverage_ratio == 0
80 next if options[:provides_cashflow] and (s.cashflow_this_year == false or s.cashflow_this_year == 0)
81 next if options[:provides_subannual_payments] and not s.has_subannual_payments?
83 next if options[:matures_within_year] and not s.get_type.time_maturity.between?(@date, @date + 1.year)
84 next if options[:provides_huge_coupon] and s.get_type.coupon < 9
85 elsif options[:matures_within_year] or options[:provides_huge_coupon]
86 next # skip securities that can be filtered with these options
90 @items << Smr::WatchlistItem.new(
92 :compare_by=>(if not @query.sorts.empty? then @query.sorts.first.name.to_sym else :date end)
96 @items.reverse! if not @query.sorts.empty? and @query.sorts.first.dir == 'desc'
102 # loops over WatchlistItem collection
108 @items.collect(&block)
117 # Represents a single item of a watchlist, suitable for easy
118 # rendering in template.
122 # unique identifier for this item, right now wrapped to Security#id
128 # Quote of last trade known before :date, may be "old", wrapped to Security#last_quote.
131 # underlying Security
132 attr_reader :security
135 # A WatchlistItem is basically a Security shown at a :date.
137 # Use the :compare_by option to tune how a collection of these items
138 # should be ordered. Default is #date, possible are all attributes of
140 def initialize(security, date, options={:compare_by=>:date})
141 raise ':security must be of type Security' unless security.is_a?(Security)
142 raise ':date must be of type Time' unless date.is_a?(Time)
144 @security = security; @date=date
145 @quote = @security.last_quote(@date)
147 @compare_by = options[:compare_by] || :date
151 # Evaluates :compare_by option, see #new.
153 if @compare_by != :date
154 mine = @security.send(@compare_by)
155 the_other = other.security.send(@compare_by)
157 retval = if mine==false or the_other==false then # probably from Security.method_missing
158 if mine or the_other then 1
160 elsif mine > the_other then 1
161 elsif mine < the_other then -1
164 retval = if date > other.date then 1
165 elsif date < other.date then -1