Skip to content

Commit

Permalink
fixing formatting, market status, bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
poitch committed Apr 9, 2012
1 parent 7b78295 commit 082311d
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 28 deletions.
9 changes: 1 addition & 8 deletions Gemfile
@@ -1,10 +1,3 @@
source :rubygems
gemspec

gem "boson"
gem "hirb"
gem "data_mapper"
gem "dm-sqlite-adapter"
gem "dm-migrations"
gem "json"
gem "uri"
gem "gems"
4 changes: 3 additions & 1 deletion bin/stockfolio
@@ -1,8 +1,10 @@
#!/usr/bin/env ruby

$LOAD_PATH << './lib'
$: << File.dirname($0) + "/../lib"

require 'rubygems'
require 'stockfolio'

begin
StockFolio::Runner.start
rescue Boson::OptionParser::Error => e
Expand Down
6 changes: 6 additions & 0 deletions lib/stockfolio.rb
Expand Up @@ -5,9 +5,12 @@
require_relative 'stockfolio/transaction'
require_relative 'stockfolio/watchlist'

require_relative 'stockfolio/formatters'

module StockFolio
autoload :Runner, 'stockfolio/runner'
autoload :Web, 'stockfolio/web'
autoload :ConsoleGraph, 'stockfolio/consolegraph'
end

#DataMapper::Logger.new($stdout, :debug)
Expand All @@ -17,6 +20,9 @@ module StockFolio
if File.exists?(rcfile)
config = YAML::load(File.open(rcfile))
ENV['STOCKFOLIO_DB'] = config['db'] || nil
if (config[:database])
ENV['STOCKFOLIO_DB'] = config[:database][:location] || nil
end
end

dbfile = ENV['STOCKFOLIO_DB'] || Dir.home + '/.stockfolio.db'
Expand Down
21 changes: 21 additions & 0 deletions lib/stockfolio/formatters.rb
@@ -0,0 +1,21 @@
require 'hirb'

module Hirb::Helpers::Table::Filters
def to_dollars(amount)
if amount
amount = amount.to_f
if amount < 0
sprintf('($%0.2f)',0-amount).gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,")
else
sprintf('$%0.2f',amount).gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,")
end
end
end

def to_percent(value)
if value
"#{(100.0 * value).round(1)}%"
end
end
end

110 changes: 93 additions & 17 deletions lib/stockfolio/runner.rb
Expand Up @@ -31,6 +31,22 @@ def quote(symbol)
def historical(symbol,start_date,end_date)
history = StockFolio::Web.historical(symbol, DateTime.parse(start_date), DateTime.parse(end_date))
puts Hirb::Helpers::Table.render(history, :fields => [:date, :open, :close, :low, :high, :volume])
# http://tagaholic.me/hirb/doc/classes/Hirb/Helpers/Table.html#M000008
# :headers => { :date => "Date", ... }
# :description => false
# :filters => { :date => lambda { |f} }}
# https://github.com/change/method_profiler/blob/master/lib/method_profiler/hirb.rb
end

def graph_historical(symbol,start_date,end_date)
history = StockFolio::Web.historical(symbol, DateTime.parse(start_date), DateTime.parse(end_date))

values = []
history.each do |row|
values << row[:close]
end
values.reverse!
StockFolio::ConsoleGraph.new(values)
end

desc "Search symbol"
Expand Down Expand Up @@ -71,8 +87,16 @@ def positions(name = nil)
portfolios = []
if nil == name
portfolios = Portfolio.all
if portfolios.size == 0
puts "No portfolio found"
exit
end
else
portfolios = Portfolio.all(:name => name)
if portfolios.size == 0
puts "Portfolio #{name} not found"
exit
end
end

positions = {}
Expand Down Expand Up @@ -108,28 +132,54 @@ def positions(name = nil)
end

pos = []

total = {}
total[:symbol] = "Total"
total[:daygain] = 0
total[:cost] = 0
total[:value] = 0
total[:gain] = 0

positions.each do |symbol,position|
p = {}
p["Symbol"] = symbol.split(":")[1]
p["Last Price"] = "$#{position[:l].to_f.round(2)}"
p["Change"] = "#{position[:c]} (#{position[:cp]}%)"
p[:symbol] = symbol.split(":")[1]
p[:last_price] = position[:l].to_f
p[:change] = "#{position[:c]} (#{position[:cp]}%)"

if position[:quantity] > 0
p["Day's Gain"] = (position[:quantity] * position[:c].to_f).round(2)
p["Shares"] = position[:quantity]
p["Cost Basis"] = "$#{position[:cost].round(2)}"
p["Market Value"] = "$#{position[:value].round(2)}"
p["Gain"] = "$#{(position[:value] - position[:cost]).round(2)}"
p["Gain %"] = "#{(100.0 * (position[:value] - position[:cost]) / position[:cost]).round(1)}%"
p[:daygain] = position[:quantity] * position[:c].to_f
p[:quantity] = position[:quantity]
p[:cost] = position[:cost].to_f
p[:value] = position[:value].to_f
p[:gain] = position[:value] - position[:cost]
p[:gain_p] = (position[:value] - position[:cost]) / position[:cost]

total[:daygain] = total[:daygain] + p[:daygain]
total[:cost] = total[:cost] + position[:cost]
total[:value] = total[:value] + position[:value]
total[:gain] = total[:gain] + position[:value] - position[:cost]
else
p["Gain"] = "$#{(0 - position[:balance]).round(2)}"
p["Gain %"] = "#{(100.0 * (0 - position[:balance]) / position[:cost]).round(1)}%"
p[:gain] = (0 - position[:balance])
p[:gain_p] = (0 - position[:balance]) / position[:cost]

end
pos << p
end

puts Hirb::Helpers::Table.render(pos, :fields => ["Symbol", "Last Price", "Change", "Day's Gain", "Shares", "Cost Basis", "Market Value", "Gain", "Gain %"])

pos.sort! { |a,b| a[:symbol] <=> b[:symbol] }

total[:gain_p] = (total[:value] - total[:cost]) / total[:cost]

pos << total

puts Hirb::Helpers::Table.render(pos,
:fields => [:symbol, :last_price, :change, :daygain, :quantity, :cost, :value, :gain, :gain_p],
:headers => {:symbol => "Symbol", :last_price => "Last Price", :change => "Change", :daygain => "Day's Gain", :quantity => "Shares", :cost => "Cost Basis", :value => "Market Value", :gain => "Gain", :gain_p => "Gain %"},
:filters => { :last_price => :to_dollars, :daygain => :to_dollars, :cost => :to_dollars, :value => :to_dollars, :gain => :to_dollars, :gain_p => :to_percent },
:description => false

)
puts "Market is #{StockFolio::Web.market_status}"
end

common_transaction_options
Expand Down Expand Up @@ -298,12 +348,38 @@ def transaction_from_options(options={})
def print_quotes(quote)
if nil != quote
# Beautify those
extended = false
quote.sort! { |a,b| a["t"] <=> b["t"] }
quote.each do |q|
q["Symbol"] = q["t"]
q["Last Price"] = "$#{q["l"]}"
q["Change"] = "#{q["c"]} (#{q["cp"]}%)"
#q["Symbol"] = q["t"]
#q["Last Price"] = "$#{q["l"]}"

#q["t"] = "#{q["e"]}:#{q["t"]}"
q[:change] = "#{q["c"]} (#{q["cp"]}%)"
if q["el"]
q[:echange] = "#{q["ec"]} (#{q["ecp"]}%)"
extended = true
else
q["elt"] = q["lt"]
end
end
puts Hirb::Helpers::Table.render(quote, fields: ["Symbol", "Last Price", "Change"])
headers = { "t" => "Symbol", "l" => "Last Price", :change => "Change", "lt" => "Last Updated" }

fields = ["t", "l", :change, "lt"]
filters = { "l" => :to_dollars }

if extended
fields = ["t", "l", :change, "el", :echange, "elt"]
headers = { "t" => "Symbol", "l" => "Close Price", :change => "Change", "el" => "After Hours Price", :echange => "After Hours Change", "elt" => "Last Updated" }
filters = { "l" => :to_dollars, "el" => :to_dollars }
end

puts Hirb::Helpers::Table.render(quote,
:fields => fields,
:headers => headers,
:filters => filters,
:description => false
)
end

end
Expand Down
27 changes: 26 additions & 1 deletion lib/stockfolio/web.rb
Expand Up @@ -12,7 +12,9 @@ def self.quote(symbol)
if data.empty?
return nil
end
JSON.parse(data.slice(3, data.length).strip)
r = JSON.parse(data.slice(3, data.length).strip)
#puts r
r
end

def self.historical(symbol, startDate, endDate)
Expand Down Expand Up @@ -59,4 +61,27 @@ def self.search(term)
result["matches"]
end

def self.market_status()
url = "http://www.nasdaq.com/dynamic_includes/marketstatus.js"
resp = Net::HTTP.get_response(URI.parse(url))
data = resp.body
if data.empty?
return false
end

parts = data.split('=')
status = parts[1].gsub('"', '').gsub(';', '').strip
if status == "O"
return "Opened"
elsif status == "A"
return "After hours"
elsif status == "C"
return "Closed"
else
return nil
end

end

end

1 change: 0 additions & 1 deletion stockfolio.gemspec
Expand Up @@ -15,7 +15,6 @@ Gem::Specification.new do |spec|
spec.add_dependency 'dm-migrations'
spec.add_dependency 'dm-sqlite-adapter'
spec.add_dependency 'json'
spec.add_dependency 'uri'
spec.add_dependency 'gems'
spec.files = Dir.glob(%w[{lib}/**/*.rb bin/*])
spec.require_paths << "lib"
Expand Down

0 comments on commit 082311d

Please sign in to comment.