Permalink
Browse files

fixing formatting, market status, bug fixes

  • Loading branch information...
1 parent 7b78295 commit 082311d1bf229d19e62e5c9139b4c8624dc295c2 @poitch committed Apr 9, 2012
Showing with 150 additions and 28 deletions.
  1. +1 −8 Gemfile
  2. +3 −1 bin/stockfolio
  3. +6 −0 lib/stockfolio.rb
  4. +21 −0 lib/stockfolio/formatters.rb
  5. +93 −17 lib/stockfolio/runner.rb
  6. +26 −1 lib/stockfolio/web.rb
  7. +0 −1 stockfolio.gemspec
View
@@ -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"
View
@@ -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
View
@@ -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)
@@ -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'
@@ -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
+
View
@@ -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"
@@ -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 = {}
@@ -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
@@ -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
View
@@ -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)
@@ -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
+
View
@@ -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"

0 comments on commit 082311d

Please sign in to comment.