include Math require 'business_time' ## ## https://www.macrotrends.net/stocks/charts/META/meta-platforms/stock-price-history ## class Iro::Stock include Mongoid::Document include Mongoid::Timestamps include Mongoid::Paranoia store_in collection: 'iro_stocks' STATUS_ACTIVE = 'active' STATUS_INACTIVE = 'inactive' STATUSES = [ nil, 'active', 'inactive' ] def self.active where( status: STATUS_ACTIVE ) end field :status, default: STATUS_ACTIVE field :ticker validates :ticker, uniqueness: true, presence: true index({ ticker: -1 }, { unique: true }) def symbol; ticker; end def symbol= a; ticker = a; end field :last, type: :float field :options_price_increment, type: :float field :stdev, type: :float has_many :positions, class_name: 'Iro::Position', inverse_of: :stock has_many :strategies, class_name: 'Iro::Strategy', inverse_of: :stock has_many :purses, class_name: 'Iro::Purse', inverse_of: :stock has_many :options, class_name: 'Iro::Option', inverse_of: :stock has_many :priceitems, inverse_of: :stock default_scope { order_by({ ticker: :asc }) } ## my_find def self.f ticker self.find_by ticker: ticker end def to_s ticker end def self.list [[nil,nil]] + all.map { |sss| [ sss.ticker, sss.id ] } end def self.tickers_list [[nil,nil]] + all.map { |sss| [ sss.ticker, sss.ticker ] } end =begin stock = Iro::Stock.find_by( ticker: 'NVDA' ) duration = 1.month stock.volatility_from_mo duration = 1.year stock.volatility_from_yr =end field :volatility, type: :float def volatility duration: 1.year, recompute: false if self[:volatility] if !recompute return self[:volatility] end end stock = self begin_on = Time.now - duration - 1.day points = Iro::Datapoint.where( kind: 'STOCK', symbol: stock.ticker, :date.gte => begin_on, ).order_by( date: :asc ) puts! [points.first.date, points.last.date], "from,to" points_p = [] points.each_with_index do |p, idx| next if idx == 0 prev = points[idx-1] out = p.value / prev.value - 1 points_p.push out end n = points_p.length avg = points_p.reduce(&:+) / n _sum_of_sq = [] points_p.map do |p| _sum_of_sq.push( ( p - avg )*( p - avg ) ) end sum_of_sq = _sum_of_sq.reduce( &:+ ) / n # n_periods = begin_on.to_date.business_days_until( Date.today ) out = Math.sqrt( sum_of_sq )*sqrt( n ) adjustment = 2.0 out = out * adjustment puts! out, 'volatility (adjusted)' self.update volatility: out return out end def volatility_from_mo volatility( duration: 1.month ) end def volatility_from_yr volatility( duration: 1.year ) end def stdev recompute: nil if !self[:stdev] || recompute out = volatility_from_yr self[:stdev] = out save( validate: false ) return out else self[:stdev] end end ## stdev ## From: https://stackoverflow.com/questions/19484891/how-do-i-find-the-standard-deviation-in-ruby # contents = [1,2,3,4,5,6,7,8,9] # n = contents.size # => 9 # contents.map!(&:to_f) # => [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] # mean = contents.reduce(&:+)/n # => 5.0 # sum_sqr = contents.map {|x| x * x}.reduce(&:+) # => 285.0 # std_dev = Math.sqrt((sum_sqr - n * mean * mean)/(n-1)) # => 2.7386127875258306 end