[QUIZ] Stock Portfolios (#41)

R

Ruby Quiz

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

I'm a member of a local stock club. For those of you not familiar with such
clubs, they're just a group of people who pool resources (primarily knowledge,
research time, and finances) to purchase stocks.

My particular club makes use of a lot of technology for information and
communication. A recent request was a tool to practice investing. This is
especially helpful to inexperienced members. The idea is that they can pretend
to purchase a few stocks (preferably after studying their choices!) and then see
how they do over time.

This week's Ruby Quiz is to build this simple tool.

Here's a sample run to get the ideas flowing:

$ ./portfolio
Buy (symbol shares/dollars): PIXR $1000
You purchased 23 shares of PIXR for $991.53.
Buy (symbol shares/dollars): GOOG 3
You purchased 3 shares of GOOG for $887.55.
Buy (symbol shares/dollars):
+--------+--------+-----------+----------------+---------------+-----------+
| Symbol | Shares | Buy Price | Buy Date | Current Price | Gain/Loss |
+--------+--------+-----------+----------------+---------------+-----------+
| GOOG | 3 | $ 295.85 | 07/25/05 19:53 | $ 295.85 | $ 0.00 |
+--------+--------+-----------+----------------+---------------+-----------+
| PIXR | 23 | $ 43.11 | 07/25/05 19:53 | $ 43.11 | $ 0.00 |
+--------+--------+-----------+----------------+---------------+-----------+

Later, I can see how my shares are doing:

$ ./portfolio
+--------+--------+-----------+----------------+---------------+-----------+
| Symbol | Shares | Buy Price | Buy Date | Current Price | Gain/Loss |
+--------+--------+-----------+----------------+---------------+-----------+
| GOOG | 3 | $ 295.85 | 07/25/05 19:53 | $ 293.29 | $ -7.68 |
+--------+--------+-----------+----------------+---------------+-----------+
| PIXR | 23 | $ 43.11 | 07/25/05 19:53 | $ 43.44 | $ 7.59 |
+--------+--------+-----------+----------------+---------------+-----------+

Don't feel tied to this exact display or interface. Some interesting ideas
might be to show historical data before asking a user to confirm their choice,
or plot changes over regular intervals instead of just showing the initial and
current prices. If you think of something else, go for it.

I think this is a great quiz for beginners wanting to learn more about Ruby's
standard library. If that describes you, I encourage you to give it a try.
(Hint: Many web sites offer stock data, all you need do is figure out how to
get it...)
 
J

James Edward Gray II

Possible "spoiler", but Yahoo makes it easy to get the stock data,
see:
http://www.gummy-stuff.org/Yahoo-data.htm

Thanks for sharing. I wasn't aware of that service and it is trivial
to wrap:

$ ./stock_data -s -n -d1 -l1 -y -r AAPL GOOG PIXR RHAT
"AAPL","APPLE COMPUTER","8/9/2005",43.55,N/A,35.54
"GOOG","GOOGLE","8/9/2005",289.969,N/A,85.34
"PIXR","PIXAR","8/9/2005",43.65,N/A,26.73
"RHAT","RED HAT INC","8/9/2005",14.24,N/A,57.87
$ cat stock_data
#!/usr/local/bin/ruby -w

# Stock data via: http://www.gummy-stuff.org/Yahoo-data.htm

require "open-uri"

# parse options and symbols requested
data, stocks = ARGV.partition { |e| e[0] == ?- }
data = data.map { |tag| tag[/\w+/] }.join
stocks = stocks.join("+")

# fetch and print data
open "http://finance.yahoo.com/d/quotes.csv?s=#{stocks}&f=#{data}" do
|csv|
csv.each { |line| puts line }
end

__END__

James Edward Gray II
 
J

James Edward Gray II

This week's Ruby Quiz is to build this simple tool.

Here's the code used to create the quiz:

#!/usr/local/bin/ruby

require "yaml"
require "soap/rpc/driver"

server = SOAP::RPC::Driver.new( "http://services.xmethods.com/soap",
"urn:xmethods-delayed-quotes" )
server.add_method( "getQuote", "symbol" )

Struct.new("Shares", :symbol, :shares, :price, :date)

file_name = File.join(ENV["HOME"], ".portfolio.yaml")
portfolio = if File.exist? file_name
File.open(file_name) { |file| YAML.load(file) }
else
Hash.new
end

if portfolio.empty? or not ARGV.empty? and ARGV.first == "-p"
loop do
print "Buy (symbol shares/dollars): "
line = $stdin.gets.strip
break if line.empty?

ticker, amount = line.split
price = server.getQuote(ticker)
if price <= 0
puts "Unable to fetch a price for that ticker symbol."
next
end

if amount =~ /^\$(\d+)$/
dollars = Integer($1)
shares = (dollars / price).to_i
elsif amount =~ /^[1-9]\d*$/
shares = Integer(amount)
else
puts "Unknown amount format."
next
end

if shares.zero?
puts "You can't purchase any shares for that amount."
next
else
date = Time.now.strftime("%m/%d/%y %H:%M")
buy = Struct::Shares.new(ticker, shares, price, date)
portfolio[buy.symbol] = buy

puts "You purchased #{buy.shares} shares of #
{buy.symbol} " +
"for $#{"%.2f" % (buy.shares * price)}."
end
end

File.open(file_name, "w") { |file| YAML.dump(portfolio, file) }
end

output = [%w{Symbol Shares Buy\ Price Buy\ Date Current\ Price Gain/
Loss}]
portfolio.each do |ticker, details|
current = server.getQuote(ticker)
output << [ ticker, details.shares, details.price, details.date,
current,
details.shares * current - details.shares *
details.price ]
end

widths = Array.new(output.first.size, 0)
output.each do |row|
row.each_index do |index|
width = if row[index].is_a? Float
("%.2f" % row[index]).length + 1
else
row[index].to_s.length
end
widths[index] = width if width > widths[index]
end
end

border = "+-" + widths.map { |width| "-" * width }.join("-+-") + "-+"
template = ("| " + output.last.map do |column|
case column
when Float
"$%#{widths.shift - 1}.2f"
when Integer
"%#{widths.shift}d"
else
"%#{widths.shift}s"
end
end.join(" | ") + " |").sub(/\A\| %/, "| %-")
puts border
puts template.gsub(/ \| \$?%(\d+)(?:\.\d+)?[sdf]/, " | %\\1s") %
output.first
output[1..-1].sort.each do |row|
puts border
puts template % row
end
puts border

__END__

James Edward Gray II
 
J

Jeffrey Moss

I use a web service that uses yahoo, I always thought this was dirty though,
I wanted a web service but not one that ripped it off some website.

require 'soap/rpc/driver'

driver = SOAP::RPC::Driver.new( 'http://services.xmethods.com/soap',
'urn:xmethods-delayed-quotes' )
driver.add_method( 'getQuote', 'a_string' )
driver.getQuote('GOOG')

-Jeff

----- Original Message -----
From: "James Edward Gray II" <[email protected]>
To: "ruby-talk ML" <[email protected]>
Sent: Tuesday, August 09, 2005 9:50 AM
Subject: Re: [SOLUTION] Stock Portfolios (#41)

Possible "spoiler", but Yahoo makes it easy to get the stock data, see:
http://www.gummy-stuff.org/Yahoo-data.htm

Thanks for sharing. I wasn't aware of that service and it is trivial to
wrap:

$ ./stock_data -s -n -d1 -l1 -y -r AAPL GOOG PIXR RHAT
"AAPL","APPLE COMPUTER","8/9/2005",43.55,N/A,35.54
"GOOG","GOOGLE","8/9/2005",289.969,N/A,85.34
"PIXR","PIXAR","8/9/2005",43.65,N/A,26.73
"RHAT","RED HAT INC","8/9/2005",14.24,N/A,57.87
$ cat stock_data
#!/usr/local/bin/ruby -w

# Stock data via: http://www.gummy-stuff.org/Yahoo-data.htm

require "open-uri"

# parse options and symbols requested
data, stocks = ARGV.partition { |e| e[0] == ?- }
data = data.map { |tag| tag[/\w+/] }.join
stocks = stocks.join("+")

# fetch and print data
open "http://finance.yahoo.com/d/quotes.csv?s=#{stocks}&f=#{data}" do
|csv|
csv.each { |line| puts line }
end

__END__

James Edward Gray II
 
A

Adam Sanderson

Here's my solution:
http://staff.washington.edu/netghost/stocks.rb

The application bit is a little unpolished, but it has some neat
features:
-Lookup stocks:
view goog, msft
-Buy/Sell multiple stocks:
buy 10 goog, 20 msft
-Get a history of transactions:
history goog

Anyways, this was pretty fun, and I even found a compelling use for
OpenStruct, neat.
.adam
 
E

email55555

James said:
if portfolio.empty? or not ARGV.empty? and ARGV.first == "-p"

Typo error ?

The way you wrote:
if portfolio.empty? or not ARGV.empty? and ARGV.first == "-p"
Will treat like:
if (portfolio.empty? or not ARGV.empty?) and ARGV.first == "-p"

I guess you would like to say:
if portfolio.empty? or (not ARGV.empty? and ARGV.first == "-p")

Note:
&& has higher precedence than ||
but "or" "and" both are the same precedence.
 
J

James Edward Gray II

Typo error ?

The way you wrote:
if portfolio.empty? or not ARGV.empty? and ARGV.first == "-p"
Will treat like:
if (portfolio.empty? or not ARGV.empty?) and ARGV.first == "-p"

I guess you would like to say:
if portfolio.empty? or (not ARGV.empty? and ARGV.first == "-p")

Note:
&& has higher precedence than ||
but "or" "and" both are the same precedence.

You're right and I should know better. Thanks!

James Edward Gray II
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,173
Latest member
GeraldReund
Top