Permalink
Browse files

Finished Portfolio.nav()

  • Loading branch information...
1 parent f55c9a7 commit a5fb6207ee161fabde002ef7b4762d2f60db239f @DominicHong committed Dec 23, 2012
View
2 app/models/cash.rb
@@ -11,7 +11,7 @@
# type :string(255)
#
-require './app/models/security.rb'
+require Rails.root.to_s + '/app/models/security.rb'
class Cash < Security
View
6 app/models/cash_trade.rb
@@ -1,10 +1,10 @@
-require './app/models/trade.rb'
+require Rails.root.to_s + '/app/models/trade.rb'
class CashTrade < Trade
after_initialize :default_values
def security
- Cash.first
+ CASH
end
def vol
@@ -28,7 +28,7 @@ def fee
private
def default_values
- self.security = Cash.first
+ self.security = CASH
end
end
View
4 app/models/div_trade.rb
@@ -1,5 +1,5 @@
-require './app/models/trade.rb'
-require './app/models/cash_trade.rb'
+require "#{Rails.root.to_s}/app/models/trade.rb"
+require "#{Rails.root.to_s}/app/models/cash_trade.rb"
class DivTrade < CashTrade
def dividends
View
53 app/models/portfolio.rb
@@ -1,3 +1,5 @@
+require "#{Rails.root}/lib/data_source.rb"
+
class Portfolio < ActiveRecord::Base
attr_accessible :name, :classification
@@ -29,7 +31,7 @@ def position(*from, till)
ts = select_trades(*from, till)
position = Hash.new { |hash, key| hash[key] = {:position => 0, :cost => 0} }
cash = 0
- position[Cash.first][:position] = cash
+ position[CASH][:position] = cash
return position if ts.nil?
ts.each { |t|
vol = position[t.security][:position]
@@ -40,40 +42,47 @@ def position(*from, till)
end
cash += t.cf
}
- position[Cash.first][:position] = cash
+ position[CASH][:position] = cash
position
end
def nav(*from, till)
ts = select_trades(*from, till)
return 0 if ts.nil?
position = Hash.new { |hash, key| hash[key] = {:position => 0, :cost => 0} }
- cash = 0
- position[Cash.first][:position] = cash
+ shares = cash = 0
+ nav = 1
trade_dates = ts.group_by { |t| t.trade_date.to_date}
trade_dates.keys.sort.each { |date|
- t = trade_dates[date]
- vol = position[t.security][:position]
- cost = position[t.security][:cost]
- position[t.security][:position]= (t.buy ? (vol+t.vol) : (vol-t.vol))
- if t.buy
- position[t.security][:cost]=(vol*cost + (t.amount+t.fee))/(vol+t.vol)
+ adjBalance = 0
+ for t in trade_dates[date]
+ vol = position[t.security][:position]
+ cost = position[t.security][:cost]
+ position[t.security][:position]= (t.buy ? (vol+t.vol) : (vol-t.vol))
+ if t.buy
+ position[t.security][:cost]=(vol*cost + (t.amount+t.fee))/(vol+t.vol)
+ end
+ cash += t.cf
+ adjBalance += t.adjBalance
end
- cash += t.cf
-
- }
-
+ position[CASH][:position] = cash
+ market_value = DataSource.yahoo_market_value(position, date)
+ shares = adjBalance/nav + shares
+ shares = market_value if shares == 0
+ nav = market_value/shares
+ }
+ nav
end
private
- def select_trades(*from, till)
- rails ArgumentError, "must be no more than ONE from_date" if from.length > 1
- from = from.first
- if from.nil?
- ts = self.trades.where("trade_date <= ?", till).order("trade_date")
- else
- ts = self.trades.where("trade_date >= ? AND trade_date <= ?", from, till).order("trade_date")
- end
+ def select_trades(*from, till)
+ rails ArgumentError, "must be no more than ONE from_date" if from.length > 1
+ from = from.first
+ if from.nil?
+ ts = self.trades.where("trade_date <= ?", till).order("trade_date")
+ else
+ ts = self.trades.where("trade_date >= ? AND trade_date <= ?", from, till).order("trade_date")
end
+ end
end
# == Schema Information
View
2 config/initializers/my_init/constants.rb
@@ -0,0 +1,2 @@
+require Rails.root.to_s + '/app/models/cash.rb'
+CASH = Cash.first
View
3 config/initializers/my_init/mylogger.rb
@@ -0,0 +1,3 @@
+logfile = File.open(Rails.root.to_s + "/log/mylogger.log", "a")
+logfile.sync = true
+MYLOG = Logger.new(logfile, 1)
View
23 lib/data_source.rb
@@ -0,0 +1,23 @@
+#coding: UTF-8
+require 'net/http'
+
+Dir["#{Rails.root.to_s}/lib/*.rb"].each { |rb| require rb }
+Dir["#{Rails.root.to_s}/app/models/*.rb"].each { |rb| require rb }
+
+module DataSource
+ def self.yahoo_market_value(position, val_date)
+ mv = 0
+ position.each { |sec, value|
+ next if sec == CASH
+ market = (sec.market == 'sh' ? 'ss' : sec.market)
+ sid = (sec.market == 'hk' ? sec.sid.slice(1,4) : sec.sid)
+ date = val_date
+ begin
+ quotes = YahooFinance::get_HistoricalQuotes( "#{sid}.#{market}", date, date)
+ date = date - 1
+ end until quotes.size > 0
+ quotes.each {|hq| mv += value[:position] * FxRate::rate(date, sec.market) * hq.close }
+ }
+ mv += position[CASH][:position]
+ end
+end
View
17 lib/net_data_source.rb
@@ -26,23 +26,6 @@ def initialize (interval_minutes = 1)
def self.pmClose
return @@pmClose
end
-
- def self.market_value(position, val_date)
- mv = 0
- cash = Cash.first
- position.each { |sec, value|
- next if sec == cash
- market = (sec.market == 'sh' ? 'ss' : sec.market)
- sid = (sec.market == 'hk' ? sec.sid.slice(1,4) : sec.sid)
- date = val_date
- begin
- quotes = YahooFinance::get_HistoricalQuotes( "#{sid}.#{market}", date, date)
- date = date - 1
- end until quotes.size > 0
- quotes.each {|hq| mv += value[:position] * FxRate::rate(date, sec.market) * hq.close }
- }
- mv += position[cash][:position]
- end
def checkTime
now = DateTime.now
View
21 spec/libs/data_source_spec.rb
@@ -0,0 +1,21 @@
+#coding: UTF-8
+require 'spec_helper'
+Dir["#{Rails.root.to_s}/lib/*.rb"].each { |rb| require rb }
+Dir["#{Rails.root.to_s}/vendor/*.rb"].each { |rb| require rb }
+
+describe DataSource do
+ before(:each) do
+ @cmb = Stock.where(:sid => "600036", :market => "sh").first
+ @gree = Stock.where(:sid => "000651", :market => "sz").first
+ @cnooc = Stock.where(:sid => "00883", :market => "hk").first
+ end
+
+ it "should get correct market value for a position" do
+ position = Hash.new { |hash, key| hash[key] = {:position => 0, :cost => 0} }
+ position[@cmb][:position] = 100
+ position[@gree][:position] = 200
+ position[@cnooc][:position] = 100
+ position[CASH][:position] = 100
+ DataSource.yahoo_market_value(position, Date.parse("2012-12-2")).should == 7122.40
+ end
+end
View
9 spec/libs/net_data_source_spec.rb
@@ -45,12 +45,5 @@
quote.vol.should == 27880300
}
end
- it "should get correct market value for a position" do
- position = Hash.new { |hash, key| hash[key] = {:position => 0, :cost => 0} }
- position[@cmb][:position] = 100
- position[@gree][:position] = 200
- position[@cnooc][:position] = 100
- position[Cash.first][:position] = 100
- NetDataSource::market_value(position, Date.parse("2012-12-2")).should == 7122.40
- end
+
end
View
2 spec/models/cash_trade_spec.rb
@@ -15,7 +15,7 @@
it "should return Cash as Security even if security is set otherwise" do
cash_trade.security = Stock.first
- cash_trade.security.should == Cash.first
+ cash_trade.security.should == CASH
end
it "should return correct cf() for general Trades and CashTrades" do
cash_trade.cf.should == 100
View
8 spec/models/portfolio_spec.rb
@@ -84,17 +84,17 @@
end
it "should have 0 cash at the begining" do
- @portfolio.position(DateTime.now)[Cash.first][:position].should == 0
+ @portfolio.position(DateTime.now)[CASH][:position].should == 0
end
it "should have correct cash at specific moments" do
early_date = DateTime.parse("2011-7-29")
late_date = DateTime.parse("2011-7-30")
@portfolio.change_cash(10, early_date)
@portfolio.pay_div(1,early_date)
- @portfolio.position(early_date)[Cash.first][:position].should == 11
+ @portfolio.position(early_date)[CASH][:position].should == 11
@portfolio.change_cash(-9, late_date)
- @portfolio.position(late_date)[Cash.first][:position].should == 2
+ @portfolio.position(late_date)[CASH][:position].should == 2
end
end
@@ -166,7 +166,7 @@
end
it "should have correct NAV at specific date" do
@portfolio.nav(DateTime.parse("2012-11-2 23:59")).round(4).should == 1.0462
- @portfolio.nav(DateTime.parse("2012-8-15 23:59"),DateTime.parse("2012-12-2 23:59")).round(4).should == 1.0414
+ @portfolio.nav(DateTime.parse("2012-8-15 "),DateTime.parse("2012-12-2 23:59")).round(4).should == 1.0414
@portfolio.nav(DateTime.parse("2012-12-6 23:59")).round(4).should == 1.0756
end
end

0 comments on commit a5fb620

Please sign in to comment.