-
-
Save marcamillion/1cc97184e33a1cc65de2b5c622f79164 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# == Schema Information | |
# | |
# Table name: port_stocks | |
# | |
# id :bigint(8) not null, primary key | |
# portfolio_id :integer | |
# stock_id :integer | |
# volume :integer | |
# transaction_price :float | |
# current_price :float | |
# percent_change :float | |
# created_at :datetime not null | |
# updated_at :datetime not null | |
# current_value :float | |
# dollar_change :float | |
# total_spend :float | |
# transaction_date :datetime | |
# action :integer | |
# position :integer default("open") | |
# ticker :string | |
# slug :string | |
# | |
class PortStock < ApplicationRecord | |
extend FriendlyId | |
friendly_id :slug_candidates, use: :slugged | |
belongs_to :portfolio | |
belongs_to :stock | |
has_many :closed_positions, dependent: :destroy | |
accepts_nested_attributes_for :closed_positions, allow_destroy: true | |
has_many :order_histories, dependent: :destroy | |
enum action: [ :buy, :sell ] | |
enum position: [ :open, :closed ] | |
before_save :calculate_percent_change | |
before_save :calculate_dollar_change | |
before_save :calculate_current_value | |
before_save :calculate_total_spend | |
after_save :calculate_portfolio_initial_dollar_value | |
after_save :calculate_portfolio_num_winners | |
after_save :calculate_portfolio_num_losers | |
after_save :update_portfolio_current_dollar_value | |
after_save :update_portfolio_initial_dollar_value, if: (:total_spend_previously_changed? || :volume_previously_changed?) | |
after_save :calculate_portfolio_percent_change | |
after_save :calculate_portfolio_dollar_change | |
after_destroy :update_portfolio_values_on_delete | |
def slug_candidates | |
[ | |
:ticker, | |
[:ticker, :volume], | |
[:ticker, :volume, :transaction_price], | |
[:ticker, :volume, :transaction_price, :created_at] | |
] | |
end | |
def calculate_percent_change | |
self.percent_change = ((self.current_price - self.transaction_price)/self.transaction_price)*100 | |
end | |
def calculate_dollar_change | |
self.dollar_change = (self.current_price - self.transaction_price) * self.volume | |
end | |
def calculate_current_value | |
self.current_value = self.current_price * self.volume | |
end | |
def calculate_total_spend | |
self.total_spend = self.transaction_price * self.volume | |
end | |
# ========= Update Associated Portfolio Values | |
def calculate_portfolio_num_winners | |
self.portfolio.num_winners = self.portfolio.port_stocks.open.where("percent_change > 0").count | |
self.portfolio.save! | |
end | |
def calculate_portfolio_num_losers | |
self.portfolio.num_losers = self.portfolio.port_stocks.open.where("percent_change < 0").count | |
self.portfolio.save! | |
end | |
def update_portfolio_current_dollar_value | |
self.portfolio.current_dollar_value = self.portfolio.port_stocks.open.map(&:current_value).sum | |
self.portfolio.save! | |
end | |
def update_portfolio_initial_dollar_value | |
self.portfolio.initial_dollar_value = self.portfolio.port_stocks.open.map { |ps| ps.volume * ps.transaction_price }.sum | |
self.portfolio.save! | |
end | |
def update_portfolio_values_on_delete | |
if self.portfolio.port_stocks.open.count > 0 | |
self.portfolio.current_dollar_value = self.portfolio.port_stocks.open.map(&:current_value).sum | |
self.portfolio.initial_dollar_value = self.portfolio.port_stocks.open.map { |ps| ps.volume * ps.transaction_price }.sum | |
self.portfolio.dollar_change = self.portfolio.current_dollar_value - self.portfolio.initial_dollar_value | |
self.portfolio.percent_change = ((self.portfolio.current_dollar_value - self.portfolio.initial_dollar_value)/self.portfolio.initial_dollar_value)*100 | |
self.portfolio.num_winners, self.portfolio.num_losers = self.portfolio.port_stocks.open.where("percent_change > 0").count, self.portfolio.port_stocks.open.where("percent_change < 0").count | |
self.portfolio.save! | |
else | |
self.portfolio.current_dollar_value, self.portfolio.initial_dollar_value, self.portfolio.dollar_change, self.portfolio.percent_change = 0.0, 0.0, 0.0, 0.0 | |
self.portfolio.num_winners, self.portfolio.num_losers = 0, 0 | |
self.portfolio.save! | |
end | |
end | |
def calculate_portfolio_initial_dollar_value | |
if self.portfolio.initial_dollar_value.nil? | |
self.portfolio.initial_dollar_value = 0.0 | |
end | |
self.portfolio.initial_dollar_value += (self.transaction_price * self.volume) | |
self.portfolio.save! | |
end | |
def calculate_portfolio_percent_change | |
self.portfolio.percent_change = ((self.portfolio.current_dollar_value - self.portfolio.initial_dollar_value)/self.portfolio.initial_dollar_value)*100 | |
self.portfolio.save! | |
end | |
def calculate_portfolio_dollar_change | |
self.portfolio.dollar_change = self.portfolio.current_dollar_value - self.portfolio.initial_dollar_value | |
self.portfolio.save! | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# == Schema Information | |
# | |
# Table name: port_stocks | |
# | |
# id :bigint(8) not null, primary key | |
# portfolio_id :integer | |
# stock_id :integer | |
# volume :integer | |
# transaction_price :float | |
# current_price :float | |
# percent_change :float | |
# created_at :datetime not null | |
# updated_at :datetime not null | |
# current_value :float | |
# dollar_change :float | |
# total_spend :float | |
# transaction_date :datetime | |
# action :integer | |
# position :integer default("open") | |
# ticker :string | |
# slug :string | |
# | |
require 'rails_helper' | |
RSpec.describe PortStock, type: :model do | |
let(:stock) { create(:stock, price: 10.00) } | |
let(:portfolio) { create(:portfolio) } | |
let(:port_stock_1) { create(:port_stock, stock: stock, portfolio: portfolio, transaction_price: stock.price, action: :buy, volume: 100) } | |
context "associations" do | |
it { should belong_to(:portfolio) } | |
it { should belong_to (:stock) } | |
end | |
context "methods" do | |
it "should accurately calculate the positive percent_change of the current PortStock" do | |
port_stock_1.current_price = 20.00 | |
expect(port_stock_1.calculate_percent_change).to eql 100.00 | |
end | |
it "should accurately calculate the negative percent_change of the current PortStock" do | |
port_stock_1.current_price = 5.00 | |
expect(port_stock_1.calculate_percent_change).to eql(-50.00) | |
end | |
it "should accurately calculate the positive dollar_change of the current PortStock" do | |
port_stock_1.current_price = 15.00 | |
port_stock_1.volume = 1000 | |
expect(port_stock_1.calculate_dollar_change).to eql 5000.00 | |
end | |
it "should accurately calculate the negative dollar_change of the current PortStock" do | |
port_stock_1.current_price = 5.00 | |
port_stock_1.volume = 1000 | |
expect(port_stock_1.calculate_dollar_change).to eql (-5000.00) | |
end | |
it "should accurately calculate the current_value of the PortStock when the price increases" do | |
port_stock_1.current_price = 15.00 | |
port_stock_1.volume = 1000 | |
expect(port_stock_1.calculate_current_value).to eql 15000.00 | |
end | |
it "should accurately calculate the negative current_value of the PortStock when the price decreases" do | |
port_stock_1.current_price = 5.00 | |
port_stock_1.volume = 1000 | |
expect(port_stock_1.calculate_current_value).to eql 5000.00 | |
end | |
it "should accurately calculate the total_spend of the current PortStock on original purchase" do | |
expect(port_stock_1.calculate_total_spend).to eql 1000.00 | |
end | |
it "should accurately calculate the portfolio's initial_dollar_value" do | |
binding.pry | |
expect(portfolio.initial_dollar_value).to eql 1000.00 | |
end | |
it "should accurately calculate the portfolio's number of winners" | |
it "should accurately calculate the portfolio's number of losers" | |
it "should accurately update the portfolio's current_dollar_value" | |
it "should accurately update the portfolio's initial_dollar_value" | |
it "should accurately calculate the portfolio's percent_change" | |
it "should accurately calculate the portfolio's dollar_change" | |
it "should accurately update all portfolio values when PortStock is deleted" | |
end | |
context "callbacks" do | |
it "should accurately calculate the percent_change of the current PortStock BEFORE SAVING" | |
it "should accurately calculate the dollar_change of the current PortStock BEFORE SAVING" | |
it "should accurately calculate the current_value of the current PortStock BEFORE SAVING" | |
it "should accurately calculate the total_spend of the current PortStock BEFORE SAVING" | |
it "should accurately calculate the portfolio's initial_dollar_value AFTER SAVING" | |
it "should accurately calculate the portfolio's number of winners AFTER SAVING" | |
it "should accurately calculate the portfolio's number of losers AFTER SAVING" | |
it "should accurately update the portfolio's current_dollar_value AFTER SAVING" | |
it "should accurately update the portfolio's initial_dollar_value AFTER SAVING" | |
it "should accurately calculate the portfolio's percent_change AFTER SAVING" | |
it "should accurately calculate the portfolio's dollar_change AFTER SAVING" | |
it "should accurately update all portfolio values when PortStock is deleted" | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment