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/>.
18 require 'cashflowitem'
19 require 'cashflowstream'
21 class SecurityFund < ActiveRecord::Base
22 include Smr::HelperMethods
23 include Smr::SecurityTypemodelMandatoryMethods
25 after_initialize :build_cf_stream
27 self.inheritance_column = :none
28 has_one :Security, :foreign_key=>:id_security_fund, :inverse_of=>:SecurityFund
31 # types of funds supported (may alter behaviour of some methods)
32 # NOTE: do NOT change the relations! just ADD!
33 enum type: { :equity=>0, :bond=>1, :balanced=>2, :etf=>3, :fund_of_funds=>4,
34 :hedge=>5, :real_estate=>6, :commodity=>7 }
37 #validates :id_security, numericality: { greater_than: 0 }
40 # Returns human readable String describing :type. It may be given as
41 # symbol, as string or as numerical index.
42 def SecurityFund.describe_type(lookup)
44 :equity => 'Equity Fund',
45 :bond => 'Fixed Income Fund',
46 :balanced => 'Equity/Fixed Income Fund',
47 :etf => 'Indexing Fund',
48 :fund_of_funds => 'Fund of Funds',
49 :hedge => 'Hedge Fund',
50 :real_estate => 'Real Estate Fund',
51 :commodity => 'Commodities Fund',
54 if lookup.is_a?(Numeric) then
55 lookup = self.types.key(lookup) || ''
57 descriptions[lookup.to_sym]
61 # Describes type of the instance object.
63 SecurityFund.describe_type(type)
67 # Returns humanreadable String describing the model itself.
68 def SecurityFund.describe
75 # Human readable String composed of essential properties known by a
76 # SecurityFund on its own. Useful as part to compose the name of a
81 unless tranche.blank? then '(%s)' % tranche end,
82 SecurityFund.describe_type(type),
83 unless currency.blank? and currency != Smr::DEFAULT_CURRENCY then currency end,
88 # Wrapper to convert integer date_* column to Time and vice versa.
89 # If :integer is given, the date_* field is updated first. The Time
90 # value is always returned.
91 def time_distribution=(string)
92 write_attribute(:date_distribution, string.to_time)
95 Time.at read_attribute(:date_distribution)
98 def time_inception=(string)
99 write_attribute(:date_inception, string.to_time)
102 Time.at read_attribute(:date_inception)
105 def time_fiscalyearend=(string)
106 write_attribute(:date_fiscalyearend, string.to_time)
108 def time_fiscalyearend
109 Time.at read_attribute(:date_fiscalyearend)
113 # mandatory method: result based on :distribution declared, :distribution_interval
115 def current_yield(quote=false)
116 quote = self.Security.last_quote unless quote
117 raise ':quote must be of Quote' if quote and not quote.is_a?(Quote)
118 if quote.quote.zero? then return false end
120 distribution * 12 / distribution_interval
121 ).to_s ).as_percentage_of(quote.quote)
125 # mandatory method: funds never expires but we expire it
126 # artificially if the last available quotation is older than 3
127 # years. New Quote data will automatically unexpire it.
128 def is_expired?(date=Time.now)
129 quote = self.Security.last_quote(date)
130 quote.time < date - 3.years
134 # mandatory method: constructs :distribution payments forecast
136 # Its based on :time_distribution and :distribution_interval.
137 # Since a fund never expires, the steam of cashflow is limited to
138 # 10 years from :start_date.
140 # The :type option allows to filter what is returned. This model supports
141 # :none and :dividend_booking. Also see PositionRevision#types to have all
142 # types of cashflow known to SMR.
144 # :start_date is Time.now unless given.
145 def cashflow(options={:start_date=>false, :end_date=>false, :amount=>false, :type=>:none, :item_link=>false})
146 start_date = options[:start_date] || Time.now
147 end_date = options[:end_date] || (start_date + 10.years).end_of_year
148 shares = options[:amount] || 1
152 :start=>start_date, :end=>end_date,
153 :filter=>(options[:type] || :none),
154 :item_link=>options[:item_link]
159 # mandatory method: inspects :distribution_interval for happening multiple times a year
160 def has_subannual_payments?
161 distribution_interval < 12
167 # create Smr::CashflowStream from SecurityFund attributes
169 @cf_stream = Smr::CashflowStream.new(
170 distribution, time_distribution,
171 :payment_interval=>distribution_interval,
172 :item_description=>self.Security.to_s,
173 :id_for_caching=>('%s%i' % [self.class, (id || 0)]).to_sym