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 SecurityStock < ActiveRecord::Base
22 include Smr::Extensions::HelperMethods
23 include Smr::Extensions::SecurityTypemodelMandatoryMethods
24 include Smr::Extensions::DateTimeWrapper
26 after_initialize :build_cf_stream
28 self.inheritance_column = :none
29 has_one :Security, :foreign_key=>:id_security_stock, :inverse_of=>:SecurityStock
32 # types of stock supported (may alter behaviour of some methods)
33 # see http://api.rubyonrails.org/v4.1.0/classes/ActiveRecord/Enum.html
34 # NOTE: do NOT change the relations! just ADD!
35 enum type: { :common=>0, :preferred=>1, :bearer=>2, :registered=>3, :vinculum=>4, :ADR=>5, }
38 #validates :id_security, numericality: { greater_than: 0 }
41 # Returns human readable String describing :type. It may be given as
42 # symbol, as string or as numerical index.
43 def SecurityStock.describe_type(lookup)
45 :common => 'Common Stock',
46 :preferred => 'Preferred Stock',
47 :bearer => 'Bearer Share',
48 :registered => 'Registered Share',
49 :vinculum => 'Registered Share with restricted transferability',
50 :ADR => 'American Depositary Receipt',
53 if lookup.is_a?(Numeric) then
54 lookup = self.types.key(lookup) || ''
56 descriptions[lookup.to_sym]
60 # Describes type of the instance object.
62 SecurityStock.describe_type(type)
66 # Returns humanreadable String describing the model itself.
67 def SecurityStock.describe
71 SecurityStock.describe
75 # Returns a collection of all types in their described form.
77 # Useful for Select boxes in forms, also see SecurityStock#describe_type. The
78 # :as_number option toggles whether symbols or integers are retured as
80 def self.types_for_form(options={ :as_number=>false })
81 SecurityStock.types.map { |t|
83 SecurityStock.describe_type(t.first),
84 options[:as_number] ? SecurityStock.types[t.first] : t.first
90 # Human readable String composed of essential properties known by a
91 # SecurityStock on its own. Useful as part to compose the name of a
94 SecurityStock.describe_type(type)
98 # mandatory method: result based on :dividend declared, :dividend_interval
100 def current_yield(quote=false)
101 quote = self.Security.last_quote unless quote
102 raise ':quote must be of Quote' if quote and not quote.is_a?(Quote)
103 if quote.last.zero? then return false end
105 dividend * 12 / dividend_interval
106 ).to_s ).as_percentage_of(quote.last)
110 # mandatory method: equity never expires but we expire it
111 # artificially if the last available quotation is older than 3
112 # years. New Quote data will automatically unexpire it.
113 def is_expired?(date=Time.now)
114 quote = self.Security.last_quote(date)
115 quote.time_last < date - 3.years
119 # mandatory method: constructs :dividend payments
121 # Its based on :dividend_exdate and :dividend_interval. Since equity never
122 # expires, the steam of cashflow is limited to 10 years from :start_date.
124 # The :type option allows to filter what is returned. This model supports
125 # :none and :dividend_booking. Also see PositionRevision#types to have all
126 # types of cashflow known to SMR.
128 # :start_date is Time.now unless given.
129 def cashflow(options={:start_date=>false, :end_date=>false, :amount=>false, :type=>:none, :item_link=>false})
130 start_date = options[:start_date] || Time.now
131 end_date = options[:end_date] || (start_date + 10.years).end_of_year
132 shares = options[:amount] || 1
136 :start=>start_date, :end=>end_date,
137 :filter=>(options[:type] || :none),
138 :item_link=>options[:item_link]
143 # mandatory method: inspects :dividend_interval for happening multiple times a year
144 def has_subannual_payments?
145 dividend_interval < 12
151 # create Smr::CashflowStream from SecurityStock attributes
153 @cf_stream = Smr::CashflowStream.new(
154 dividend, time_dividend_exdate,
155 :payment_interval=>dividend_interval,
156 :item_description=>self.Security.to_s,
157 :id_for_caching=>('%s%i' % [self.class, (id || 0)]).to_sym