stock-markit 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/stock-markit.rb +50 -0
- data/lib/stock-markit/api_exception.rb +22 -0
- data/lib/stock-markit/chart.rb +159 -0
- data/lib/stock-markit/chart_result.rb +47 -0
- data/lib/stock-markit/element.rb +37 -0
- data/lib/stock-markit/lookup.rb +52 -0
- data/lib/stock-markit/quote.rb +95 -0
- data/lib/stock-markit/stock.rb +26 -0
- data/lib/stock-markit/version.rb +9 -0
- data/spec/lib/stock-markit/lookup_spec.rb +35 -0
- data/spec/lib/stock-markit/quote_spec.rb +49 -0
- data/spec/lib/stock-markit/version_spec.rb +7 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/support/vcr.rb +6 -0
- data/spec/vcr/lookup/twtr.yml +50 -0
- data/spec/vcr/quote/twtr.yml +50 -0
- data/spec/vcr/quote/twtr_update.yml +97 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 41eb5980e6189fac8d4739c449b2eb2ac5a82401
|
4
|
+
data.tar.gz: 12d67a6a27900fe624b553e7d02b06b070c128e8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: da557ef3702ad11d5cb3bb9cc1029e22bcc44e3c5dd335483543f2737f5e8478bc3e29ac2e68dd7b13462feb2d83f3200ffcf898d7c9a9be8f13cd10a23a0b15
|
7
|
+
data.tar.gz: 547aa5837ec339ad15ba87026722c362b216d683b69cf98cb70ab1615bc3abe2f39f2c8df2c33388aaedbed7768581f6139f17ed3b2051bd29a88d067fa71db5
|
data/lib/stock-markit.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# This library allows you to persist objects with meta data
|
2
|
+
# StockMarkit supports data expiry and is designed with thread safety
|
3
|
+
#
|
4
|
+
# Author:: Michael Heijmans (mailto:parabuzzle@gmail.com)
|
5
|
+
# Copyright:: Copyright (c) 2016 Michael Heijmans
|
6
|
+
# License:: MIT
|
7
|
+
|
8
|
+
require 'httparty'
|
9
|
+
require 'oj'
|
10
|
+
|
11
|
+
module StockMarkit
|
12
|
+
|
13
|
+
# require library file that was passed
|
14
|
+
# @param [String] lib Library path to require
|
15
|
+
def self.require_lib(lib)
|
16
|
+
require lib
|
17
|
+
end
|
18
|
+
|
19
|
+
# Iterates through the passed in array of
|
20
|
+
# library paths and requires each of them
|
21
|
+
# @param [Array] libs Array of libraries to require
|
22
|
+
def self.require_libs(libs)
|
23
|
+
libs.each do |lib|
|
24
|
+
self.require_lib(lib)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Uses the lookup service to find stocks with the given symbol
|
29
|
+
# @param [String, Symbol] symbol The ticker symbol to lookup
|
30
|
+
# @return [Array<StockMarkit::Stock>] An Array of Stock Objects that match the given symbol
|
31
|
+
# @see StockMarkit::Lookup
|
32
|
+
def self.lookup(symbol)
|
33
|
+
Lookup.new(symbol).fetch
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
# Uses the quote service to get a quote for the given symbol
|
38
|
+
# @param [String, Symbol] symbol The ticker symbol to lookup
|
39
|
+
# @return [StockMarkit::Quote] A populated quote object
|
40
|
+
# @see StockMarkit::Quote
|
41
|
+
def self.quote(symbol)
|
42
|
+
Quote.new(symbol).fetch
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
$:.concat [File.expand_path('../', __FILE__),File.expand_path('../stock-markit', __FILE__)]
|
48
|
+
|
49
|
+
# Require all ruby files in the stock-markit directory
|
50
|
+
StockMarkit.require_libs Dir.glob(File.expand_path('../stock-markit', __FILE__) + '/*.rb')
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module StockMarkit
|
2
|
+
|
3
|
+
# Api Exception Object
|
4
|
+
#
|
5
|
+
# @attr_reader [String] message The Error Message
|
6
|
+
# @attr_reader [String] api_results The httparty object for inspecting
|
7
|
+
#
|
8
|
+
# @author Michael Heijmans (mailto:parabuzzle@gmail.com)
|
9
|
+
#
|
10
|
+
# Copyright:: Copyright (c) 2016 Michael Heijmans
|
11
|
+
# License:: MIT
|
12
|
+
class ApiException < Exception
|
13
|
+
|
14
|
+
attr_reader :api_results
|
15
|
+
|
16
|
+
def initialize(message="Api Error", api_results=nil)
|
17
|
+
@api_results = api_results
|
18
|
+
super(message)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'active_support/time'
|
2
|
+
|
3
|
+
module StockMarkit
|
4
|
+
|
5
|
+
# Stock Chart Object
|
6
|
+
#
|
7
|
+
# @attr_reader [StockMarkit::ChartResult] results The chart results
|
8
|
+
#
|
9
|
+
# @author Michael Heijmans (mailto:parabuzzle@gmail.com)
|
10
|
+
#
|
11
|
+
# Copyright:: Copyright (c) 2016 Michael Heijmans
|
12
|
+
# License:: MIT
|
13
|
+
class Chart
|
14
|
+
include ::HTTParty
|
15
|
+
base_uri 'dev.markitondemand.com'
|
16
|
+
|
17
|
+
attr_reader :results
|
18
|
+
|
19
|
+
# @option opts [Boolean] :normalized Show data in price units (false) or percentages (true)
|
20
|
+
# @option opts [Time] :start_date The beginning date for the chart
|
21
|
+
# @option opts [Time] :end_date The end date of the chart
|
22
|
+
# @option opts [Integer] :offset Number of days back that chart should end. Defaults to 0 if not specified. May be used instead of :end_date for interday requests.
|
23
|
+
# @option opts [Integer] :number_of_days Number of days that should be shown on the chart. Required for intraday requests. May be used instead of :start_date for interday requests.
|
24
|
+
# @option opts [Symbol] :data_period The type of data requested. :Minute, :Hour, :Day, :Week, :Month, :Quarter, :Year
|
25
|
+
# @option opts [Integer] :data_interval For intraday data, specifies the number of periods between data points. e.g. if DataPeriod is Minute and DataInterval is 5, you will get a chart with five minute intervals. Must be 0 or null for interday charts
|
26
|
+
# @option opts [Symbol] :label_period The TimePeriod over which to create labels. Control how often you want labels by setting LabelInterval. :Minute, :Hour, :Day, :Week, :Month, :Quarter, :Year
|
27
|
+
# @option opts [Integer] :label_interval How many LabelPeriods to skip between labels
|
28
|
+
# @option opts [Array<StockMarkit::Element>] :elements An Array of 1 or more Elements.
|
29
|
+
def initialize(opts)
|
30
|
+
@opts = opts
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [Boolean] value of the passed normalized parameter on instantiation
|
34
|
+
def normalized?
|
35
|
+
return true if @opts[:normalized].nil?
|
36
|
+
@opts[:normalized]
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [String] value of passed start_time parameter in ISO8601 formatted Eastern Time
|
40
|
+
def start_date
|
41
|
+
format_time(@opts[:start_date])
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [String] value of passed end_time parameter in ISO8601 formatted Eastern Time
|
45
|
+
def end_date
|
46
|
+
format_time(@opts[:end_date])
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Integer] value of passed offset parameter on instantiation
|
50
|
+
def offset
|
51
|
+
@opts[:offset]
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [Integer] value of passed number_of_days parameter on instantiation
|
55
|
+
def number_of_days
|
56
|
+
@opts[:number_of_days]
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [Symbol] value of passed data_period parameter on instantiation
|
60
|
+
def data_period
|
61
|
+
raise "valid data_periods are #{allowed_periods.join(", ")}" unless allowed_periods.include? @opts[:data_period]
|
62
|
+
@opts[:data_period].to_s.capitalize
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Integer] value of passed data_interval parameter on instantiation
|
66
|
+
def data_interval
|
67
|
+
@opts[:data_interval]
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [Symbol] value of passed label_period parameter on instantiation
|
71
|
+
def label_period
|
72
|
+
return nil unless @opts[:label_period]
|
73
|
+
raise "valid label_periods are #{allowed_periods.join(", ")}" unless allowed_periods.include? @opts[:label_period]
|
74
|
+
@opts[:label_period].to_s.capitalize
|
75
|
+
end
|
76
|
+
|
77
|
+
# @return [Integer] value of passed label_interval parameter on instantiation
|
78
|
+
def label_interval
|
79
|
+
@opts[:label_interval]
|
80
|
+
end
|
81
|
+
|
82
|
+
# @return [Array] List of normalized elements passed on instantiation
|
83
|
+
def elements
|
84
|
+
@opts[:elements].map{ |element| {"Symbol" => element.symbol, "Type" => element.type, "Params" => [element.params]} }
|
85
|
+
end
|
86
|
+
|
87
|
+
# loads the @results on first call or returns results on subsequent calls
|
88
|
+
#
|
89
|
+
# @return [StockMarkit::ChartResults] results object
|
90
|
+
def fetch
|
91
|
+
@results || update
|
92
|
+
end
|
93
|
+
|
94
|
+
# updates the data from the api
|
95
|
+
#
|
96
|
+
# @return [StockMarkit::ChartResult] results object
|
97
|
+
def update
|
98
|
+
@results = lookup_with_api
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def allowed_periods
|
104
|
+
[
|
105
|
+
:minute,
|
106
|
+
:hour,
|
107
|
+
:day,
|
108
|
+
:week,
|
109
|
+
:month,
|
110
|
+
:quarter,
|
111
|
+
:year,
|
112
|
+
]
|
113
|
+
end
|
114
|
+
|
115
|
+
def format_time(time)
|
116
|
+
return nil unless time
|
117
|
+
time.in_time_zone('Eastern Time (US & Canada)').iso8601
|
118
|
+
end
|
119
|
+
|
120
|
+
def options
|
121
|
+
{
|
122
|
+
query: {
|
123
|
+
parameters: encoded_parameters
|
124
|
+
}
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
def encoded_parameters
|
129
|
+
parameters.to_json
|
130
|
+
end
|
131
|
+
|
132
|
+
def parameters
|
133
|
+
params = {}
|
134
|
+
|
135
|
+
params.store("Normalized", normalized?)
|
136
|
+
params.store("StartDate", start_date) if start_date
|
137
|
+
params.store("EndDate", end_date) if end_date
|
138
|
+
params.store("EndOffsetDays", offset) if offset
|
139
|
+
params.store("NumberOfDays", number_of_days) if number_of_days
|
140
|
+
params.store("DataPeriod", data_period) if data_period
|
141
|
+
params.store("DataInterval", data_interval) if data_interval
|
142
|
+
params.store("LabelPeriod", label_period) if label_period
|
143
|
+
params.store("LabelInterval", label_interval) if label_interval
|
144
|
+
|
145
|
+
params.store("Elements", elements)
|
146
|
+
|
147
|
+
return params
|
148
|
+
end
|
149
|
+
|
150
|
+
def lookup_with_api
|
151
|
+
results = self.class.get("/MODApis/Api/v2/InteractiveChart/json", options)
|
152
|
+
if results.code != 200
|
153
|
+
raise ApiException.new("An error occured while attempting to communicate with the api", results)
|
154
|
+
end
|
155
|
+
StockMarkit::ChartResult.new( Oj.load( results.body ) )
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'active_support/time'
|
2
|
+
|
3
|
+
module StockMarkit
|
4
|
+
|
5
|
+
# Stock Chart Result Object
|
6
|
+
#
|
7
|
+
# @author Michael Heijmans (mailto:parabuzzle@gmail.com)
|
8
|
+
#
|
9
|
+
# Copyright:: Copyright (c) 2016 Michael Heijmans
|
10
|
+
# License:: MIT
|
11
|
+
class ChartResult
|
12
|
+
|
13
|
+
# @param [Hash] the parsed json result from the chart api
|
14
|
+
def initialize(json)
|
15
|
+
@json = json
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [Hash] X Axis label position, text, and dates. The "dates" are in Microsoft "OA Date" format. The "text" is an ISO timestamp.
|
19
|
+
def labels
|
20
|
+
@json["Labels"]
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Array] List of X coordinate positions for each data point returned, between 0 and 1.
|
24
|
+
def positions
|
25
|
+
@json["Positions"]
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [Array] Timestamps corresponding to each position in UTC
|
29
|
+
def dates
|
30
|
+
@json["Dates"].map { |date| parse_date(date) }
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [Array] requested element data
|
34
|
+
def elements
|
35
|
+
@json["Elements"]
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def parse_date(date)
|
42
|
+
timezone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
|
43
|
+
timezone.parse(date).utc
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module StockMarkit
|
2
|
+
|
3
|
+
# Stock Chart Element Object
|
4
|
+
#
|
5
|
+
# @attr_reader [String] symbol The Stock Symbol
|
6
|
+
# @attr_reader [String] type The type of element. Must be one of :price, :volume, or :sma
|
7
|
+
# @attr_reader [String] params Params vary for each Type. The following Types accept Params. For the other types, Params should be null or an empty array. "sma": [period], "price": ["ohlc"] for open/high/low/close, ["c"] for close only.
|
8
|
+
#
|
9
|
+
# @author Michael Heijmans (mailto:parabuzzle@gmail.com)
|
10
|
+
#
|
11
|
+
# Copyright:: Copyright (c) 2016 Michael Heijmans
|
12
|
+
# License:: MIT
|
13
|
+
class Element
|
14
|
+
attr_reader :symbol, :type, :params
|
15
|
+
|
16
|
+
# @param [String] symbol The stock's ticker symbol
|
17
|
+
# @param [Symbol] type The type of element. Must be one of :price, :volume, or :sma
|
18
|
+
# @param [Array] params Params vary for each Type. The following Types accept Params. For the other types, Params should be null or an empty array. "sma": [period], "price": ["ohlc"] for open/high/low/close, ["c"] for close only.
|
19
|
+
def initialize(symbol, type, params=nil)
|
20
|
+
@symbol = symbol.to_s.upcase
|
21
|
+
@type = type.to_s
|
22
|
+
@params = params || default_params
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def default_params
|
28
|
+
case @type
|
29
|
+
when "price"
|
30
|
+
"c"
|
31
|
+
when "sma"
|
32
|
+
:week
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module StockMarkit
|
2
|
+
|
3
|
+
# Lookup a Stock by Symbol
|
4
|
+
#
|
5
|
+
# @attr_reader [String,Symbol] symbol The symbol of the stock to lookup
|
6
|
+
# @attr_reader [Hash] options Options hash for httparty
|
7
|
+
# @attr_reader [Array<StockMarkit::Stock>] results The stocks that match the symbol. This is populated on the first call of <#fetch>
|
8
|
+
#
|
9
|
+
# @author Michael Heijmans (mailto:parabuzzle@gmail.com)
|
10
|
+
#
|
11
|
+
# Copyright:: Copyright (c) 2016 Michael Heijmans
|
12
|
+
# License:: MIT
|
13
|
+
class Lookup
|
14
|
+
include ::HTTParty
|
15
|
+
base_uri 'dev.markitondemand.com'
|
16
|
+
|
17
|
+
attr_reader :symbol, :results
|
18
|
+
|
19
|
+
# @param [String, Symbol] symbol The stock's ticker symbol
|
20
|
+
def initialize(symbol)
|
21
|
+
@symbol = symbol.to_sym.upcase
|
22
|
+
@options = { query: {input: @symbol} }
|
23
|
+
end
|
24
|
+
|
25
|
+
# Fetch stocks matching @symbol from the api
|
26
|
+
#
|
27
|
+
# This method memoizes the results and returns the contents
|
28
|
+
# of the results variable instead of asking the api again
|
29
|
+
# @return [Array<StockMarkit::Stock>]
|
30
|
+
def fetch
|
31
|
+
@results ||= lookup_with_api
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def lookup_with_api
|
37
|
+
results = self.class.get("/MODApis/Api/v2/Lookup/json", @options)
|
38
|
+
unless results.code == 200
|
39
|
+
raise ApiException.new("An error occured while attempting to communicate with the api", results)
|
40
|
+
end
|
41
|
+
map_stocks( Oj.load( results.body ) )
|
42
|
+
end
|
43
|
+
|
44
|
+
def map_stocks(stocks)
|
45
|
+
stocks.map do |stock|
|
46
|
+
Stock.new(stock["Symbol"], stock['Name'], stock["Exchange"])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'active_support/time'
|
2
|
+
|
3
|
+
module StockMarkit
|
4
|
+
|
5
|
+
# Stock Quote
|
6
|
+
#
|
7
|
+
# @attr_reader [String] status The status from the api call
|
8
|
+
# @attr_reader [String] name The company name
|
9
|
+
# @attr_reader [String, Symbol] symbol The ticker symbol of the company
|
10
|
+
# @attr_reader [Float] last_price The last price of the company's stock
|
11
|
+
# @attr_reader [Float] change The change in price of the company's stock since the previous trading day's close
|
12
|
+
# @attr_reader [Float] change_percent The change percent in price of the company's stock since the previous trading day's close
|
13
|
+
# @attr_reader [Time] timestamp The last time the company's stock was traded
|
14
|
+
# @attr_reader [Float] ms_date The last time the company's stock was traded in exchange-local timezone. Represented as an OLE Automation date.
|
15
|
+
# @attr_reader [Integer] market_cap The company's market cap
|
16
|
+
# @attr_reader [Integer] volume The trade volume of the company's stock
|
17
|
+
# @attr_reader [Float] change_ytd The change in price of the company's stock since the start of the year
|
18
|
+
# @attr_reader [Float] change_percent_ytd The change percent in price of the company's stock since the start of the year
|
19
|
+
# @attr_reader [Float] high The high price of the company's stock in the trading session
|
20
|
+
# @attr_reader [Float] low The low price of the company's stock in the trading session
|
21
|
+
# @attr_reader [Float] open The opening price of the company's stock at the start of the trading session
|
22
|
+
#
|
23
|
+
# @author Michael Heijmans (mailto:parabuzzle@gmail.com)
|
24
|
+
#
|
25
|
+
# Copyright:: Copyright (c) 2016 Michael Heijmans
|
26
|
+
# License:: MIT
|
27
|
+
class Quote
|
28
|
+
include ::HTTParty
|
29
|
+
base_uri 'dev.markitondemand.com'
|
30
|
+
|
31
|
+
attr_reader :status, :name, :symbol, :last_price,
|
32
|
+
:change, :change_percent, :timestamp,
|
33
|
+
:ms_date, :market_cap, :volume,
|
34
|
+
:change_ytd, :change_percent_ytd,
|
35
|
+
:high, :low, :open
|
36
|
+
|
37
|
+
# @param [String, Symbol] symbol The stock's ticker symbol
|
38
|
+
def initialize(symbol)
|
39
|
+
@symbol = symbol.to_sym.upcase
|
40
|
+
@options = { query: {symbol: @symbol} }
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return <self> on successful api call
|
44
|
+
# @return <False> on failed api call - check #message for failure message
|
45
|
+
# @see #update
|
46
|
+
def fetch
|
47
|
+
update
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return <self> on successful api call
|
51
|
+
# @return <False> on failed api call - check #message for failure message
|
52
|
+
# @see #fetch
|
53
|
+
def update
|
54
|
+
lookup_with_api
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def lookup_with_api
|
60
|
+
results = self.class.get("/MODApis/Api/v2/Quote/json", @options)
|
61
|
+
unless results.code == 200
|
62
|
+
raise ApiException.new("An error occured while attempting to communicate with the api", results)
|
63
|
+
end
|
64
|
+
map_stock( Oj.load( results.body ) )
|
65
|
+
end
|
66
|
+
|
67
|
+
def map_stock(stock)
|
68
|
+
if stock["Message"]
|
69
|
+
@status = stock["Message"]
|
70
|
+
return false
|
71
|
+
end
|
72
|
+
@status = stock["Status"]
|
73
|
+
@name = stock["Name"]
|
74
|
+
@last_price = stock["LastPrice"]
|
75
|
+
@change = stock["Change"]
|
76
|
+
@change_percent = stock["ChangePercent"]
|
77
|
+
@timestamp = parse_time(stock["Timestamp"])
|
78
|
+
@ms_date = stock["MSDate"]
|
79
|
+
@market_cap = stock["MarketCap"]
|
80
|
+
@volume = stock["Volume"]
|
81
|
+
@change_ytd = stock["ChangeYTD"]
|
82
|
+
@change_percent_ytd = stock["ChangePercentYTD"]
|
83
|
+
@high = stock["High"]
|
84
|
+
@low = stock["Low"]
|
85
|
+
@open = stock["Open"]
|
86
|
+
return self
|
87
|
+
end
|
88
|
+
|
89
|
+
def parse_time(stamp)
|
90
|
+
timezone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
|
91
|
+
timezone.parse(stamp).utc
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module StockMarkit
|
2
|
+
|
3
|
+
# Stock Object
|
4
|
+
#
|
5
|
+
# @attr_reader [String] symbol The Stock Symbol
|
6
|
+
# @attr_reader [String] name The company name
|
7
|
+
# @attr_reader [String] exchange The exchange the stock is traded on
|
8
|
+
#
|
9
|
+
# @author Michael Heijmans (mailto:parabuzzle@gmail.com)
|
10
|
+
#
|
11
|
+
# Copyright:: Copyright (c) 2016 Michael Heijmans
|
12
|
+
# License:: MIT
|
13
|
+
class Stock
|
14
|
+
attr_reader :symbol, :name, :exchange
|
15
|
+
|
16
|
+
# @param [String] symbol The stock's ticker symbol
|
17
|
+
# @param [String] name The name of the company
|
18
|
+
# @param [String] exchange Optional exchange string
|
19
|
+
def initialize(symbol, name, exchange=nil)
|
20
|
+
@symbol = symbol
|
21
|
+
@name = name
|
22
|
+
@exchange = exchange
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe 'StockMarkit::Lookup' do
|
4
|
+
describe '#initialize' do
|
5
|
+
it 'sets the instance symbol as an upcased symbol' do
|
6
|
+
lookup = StockMarkit::Lookup.new(:twtr)
|
7
|
+
expect( lookup.symbol ).to eq(:TWTR)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'accepts a string and converts to symbol internally' do
|
11
|
+
lookup = StockMarkit::Lookup.new('twtr')
|
12
|
+
expect( lookup.symbol ).to eq(:TWTR)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#fetch' do
|
17
|
+
it 'fetches the stock data from the api' do
|
18
|
+
VCR.use_cassette 'lookup/twtr' do
|
19
|
+
lookup = StockMarkit::Lookup.new(:twtr)
|
20
|
+
lookup.fetch
|
21
|
+
expect( lookup.results ).to be_a(Array)
|
22
|
+
expect( lookup.results.first ).to be_a(StockMarkit::Stock)
|
23
|
+
expect( lookup.results.first.name ).to eq("Twitter Inc")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'memoizes the results' do
|
28
|
+
VCR.use_cassette 'lookup/twtr' do
|
29
|
+
lookup = StockMarkit::Lookup.new(:twtr)
|
30
|
+
results = lookup.fetch
|
31
|
+
expect( lookup.fetch.equal?(results) ).to eq(true)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe 'StockMarkit::Quote' do
|
4
|
+
describe '#initialize' do
|
5
|
+
it 'sets the instance symbol as an upcased symbol' do
|
6
|
+
quote = StockMarkit::Quote.new(:twtr)
|
7
|
+
expect( quote.symbol ).to eq(:TWTR)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'accepts a string and converts to symbol internally' do
|
11
|
+
quote = StockMarkit::Quote.new('twtr')
|
12
|
+
expect( quote.symbol ).to eq(:TWTR)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#fetch' do
|
17
|
+
let(:quote) {StockMarkit::Quote.new(:twtr)}
|
18
|
+
|
19
|
+
it 'fetches the stock quote data from the api' do
|
20
|
+
VCR.use_cassette 'quote/twtr' do
|
21
|
+
expect( quote.name ).to be_nil
|
22
|
+
quote.fetch
|
23
|
+
expect( quote.name ).not_to be_nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'sets the timestamp as a utc time' do
|
28
|
+
VCR.use_cassette 'quote/twtr' do
|
29
|
+
quote.fetch
|
30
|
+
expect( quote.timestamp.zone ).to eq('UTC')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#update' do
|
36
|
+
let(:quote) {StockMarkit::Quote.new(:twtr)}
|
37
|
+
|
38
|
+
it 'updates quote from the api' do
|
39
|
+
VCR.use_cassette 'quote/twtr_update' do
|
40
|
+
quote.fetch
|
41
|
+
expect( quote.name ).not_to be_nil
|
42
|
+
quote.instance_eval('@name = nil')
|
43
|
+
expect( quote.name ).to be_nil
|
44
|
+
quote.update
|
45
|
+
expect( quote.name ).not_to be_nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# This file is loaded before rspec tests are run
|
2
|
+
require 'simplecov'
|
3
|
+
require 'simplecov-rcov'
|
4
|
+
require 'coveralls'
|
5
|
+
require 'pry'
|
6
|
+
|
7
|
+
require_relative './support/vcr.rb'
|
8
|
+
|
9
|
+
require 'stock-markit'
|
10
|
+
|
11
|
+
SimpleCov.start do
|
12
|
+
add_filter '/spec/'
|
13
|
+
add_group 'lib', 'lib'
|
14
|
+
#SimpleCov.minimum_coverage 75
|
15
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
16
|
+
SimpleCov::Formatter::HTMLFormatter,
|
17
|
+
SimpleCov::Formatter::RcovFormatter
|
18
|
+
]
|
19
|
+
end if ENV["COVERAGE"]
|
20
|
+
|
21
|
+
Coveralls.wear!
|
data/spec/support/vcr.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://dev.markitondemand.com/MODApis/Api/v2/Lookup/json?input=TWTR
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- "*/*"
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Cache-Control:
|
22
|
+
- private
|
23
|
+
Content-Type:
|
24
|
+
- text/javascript; charset=UTF-8
|
25
|
+
Vary:
|
26
|
+
- Accept-Encoding
|
27
|
+
Server:
|
28
|
+
- ''
|
29
|
+
X-Aspnet-Version:
|
30
|
+
- ''
|
31
|
+
P3p:
|
32
|
+
- CP="NON PHY ONL UNI PUR FIN COM NAV INT DEM STA HEA CUR ADM DEV OUR IND",
|
33
|
+
policyref="/w3c/p3p.xml"
|
34
|
+
Set-Cookie:
|
35
|
+
- 3481%5F0=F4818F874E6B510347577EE44860372EBD4802692B02483A4BDC4E27ACCC5F05;
|
36
|
+
path=/; HttpOnly
|
37
|
+
- GZIP=1; expires=Sat, 04-Sep-2021 18:58:55 GMT; path=/
|
38
|
+
X-Powered-By:
|
39
|
+
- ASP.NET
|
40
|
+
Date:
|
41
|
+
- Mon, 05 Sep 2016 18:58:55 GMT
|
42
|
+
Content-Length:
|
43
|
+
- '191'
|
44
|
+
body:
|
45
|
+
encoding: ASCII-8BIT
|
46
|
+
string: '[{"Symbol":"TWTR","Name":"Twitter Inc","Exchange":"NYSE"},{"Symbol":"TWTR","Name":"Twitter
|
47
|
+
Inc","Exchange":"BATS Trading Inc"}]'
|
48
|
+
http_version:
|
49
|
+
recorded_at: Mon, 05 Sep 2016 18:58:55 GMT
|
50
|
+
recorded_with: VCR 3.0.3
|
@@ -0,0 +1,50 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://dev.markitondemand.com/MODApis/Api/v2/Quote/json?symbol=TWTR
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- "*/*"
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Cache-Control:
|
22
|
+
- private
|
23
|
+
Content-Type:
|
24
|
+
- text/javascript; charset=UTF-8
|
25
|
+
Vary:
|
26
|
+
- Accept-Encoding
|
27
|
+
Server:
|
28
|
+
- ''
|
29
|
+
X-Aspnet-Version:
|
30
|
+
- ''
|
31
|
+
P3p:
|
32
|
+
- CP="NON PHY ONL UNI PUR FIN COM NAV INT DEM STA HEA CUR ADM DEV OUR IND",
|
33
|
+
policyref="/w3c/p3p.xml"
|
34
|
+
Set-Cookie:
|
35
|
+
- 3481%5F0=73B343DA043278F396CBECA8FB707A1EA9971FED219369C125A5957958B2C927;
|
36
|
+
path=/; HttpOnly
|
37
|
+
- GZIP=1; expires=Sat, 04-Sep-2021 19:10:49 GMT; path=/
|
38
|
+
X-Powered-By:
|
39
|
+
- ASP.NET
|
40
|
+
Date:
|
41
|
+
- Mon, 05 Sep 2016 19:10:48 GMT
|
42
|
+
Content-Length:
|
43
|
+
- '378'
|
44
|
+
body:
|
45
|
+
encoding: ASCII-8BIT
|
46
|
+
string: '{"Status":"SUCCESS","Name":"Twitter Inc","Symbol":"TWTR","LastPrice":19.54,"Change":0.0399999999999991,"ChangePercent":0.205128205128201,"Timestamp":"Fri
|
47
|
+
Sep 2 15:59:00 UTC-04:00 2016","MSDate":42615.6659722222,"MarketCap":13828985580,"Volume":949554,"ChangeYTD":23.14,"ChangePercentYTD":-15.5574762316335,"High":19.87,"Low":19.355,"Open":19.61}'
|
48
|
+
http_version:
|
49
|
+
recorded_at: Mon, 05 Sep 2016 19:10:49 GMT
|
50
|
+
recorded_with: VCR 3.0.3
|
@@ -0,0 +1,97 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://dev.markitondemand.com/MODApis/Api/v2/Quote/json?symbol=TWTR
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- "*/*"
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Cache-Control:
|
22
|
+
- private
|
23
|
+
Content-Type:
|
24
|
+
- text/javascript; charset=UTF-8
|
25
|
+
Vary:
|
26
|
+
- Accept-Encoding
|
27
|
+
Server:
|
28
|
+
- ''
|
29
|
+
X-Aspnet-Version:
|
30
|
+
- ''
|
31
|
+
P3p:
|
32
|
+
- CP="NON PHY ONL UNI PUR FIN COM NAV INT DEM STA HEA CUR ADM DEV OUR IND",
|
33
|
+
policyref="/w3c/p3p.xml"
|
34
|
+
Set-Cookie:
|
35
|
+
- 3481%5F0=3341EF7F0399B17CB017F9EBD7F5F1BD5091D0BC6FB4A567CA792985822FFD10;
|
36
|
+
path=/; HttpOnly
|
37
|
+
- GZIP=1; expires=Sat, 04-Sep-2021 19:18:44 GMT; path=/
|
38
|
+
X-Powered-By:
|
39
|
+
- ASP.NET
|
40
|
+
Date:
|
41
|
+
- Mon, 05 Sep 2016 19:18:43 GMT
|
42
|
+
Content-Length:
|
43
|
+
- '378'
|
44
|
+
body:
|
45
|
+
encoding: ASCII-8BIT
|
46
|
+
string: '{"Status":"SUCCESS","Name":"Twitter Inc","Symbol":"TWTR","LastPrice":19.54,"Change":0.0399999999999991,"ChangePercent":0.205128205128201,"Timestamp":"Fri
|
47
|
+
Sep 2 15:59:00 UTC-04:00 2016","MSDate":42615.6659722222,"MarketCap":13828985580,"Volume":949554,"ChangeYTD":23.14,"ChangePercentYTD":-15.5574762316335,"High":19.87,"Low":19.355,"Open":19.61}'
|
48
|
+
http_version:
|
49
|
+
recorded_at: Mon, 05 Sep 2016 19:18:44 GMT
|
50
|
+
- request:
|
51
|
+
method: get
|
52
|
+
uri: http://dev.markitondemand.com/MODApis/Api/v2/Quote/json?symbol=TWTR
|
53
|
+
body:
|
54
|
+
encoding: US-ASCII
|
55
|
+
string: ''
|
56
|
+
headers:
|
57
|
+
Accept-Encoding:
|
58
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
59
|
+
Accept:
|
60
|
+
- "*/*"
|
61
|
+
User-Agent:
|
62
|
+
- Ruby
|
63
|
+
response:
|
64
|
+
status:
|
65
|
+
code: 200
|
66
|
+
message: OK
|
67
|
+
headers:
|
68
|
+
Cache-Control:
|
69
|
+
- private
|
70
|
+
Content-Type:
|
71
|
+
- text/javascript; charset=UTF-8
|
72
|
+
Vary:
|
73
|
+
- Accept-Encoding
|
74
|
+
Server:
|
75
|
+
- ''
|
76
|
+
X-Aspnet-Version:
|
77
|
+
- ''
|
78
|
+
P3p:
|
79
|
+
- CP="NON PHY ONL UNI PUR FIN COM NAV INT DEM STA HEA CUR ADM DEV OUR IND",
|
80
|
+
policyref="/w3c/p3p.xml"
|
81
|
+
Set-Cookie:
|
82
|
+
- 3481%5F0=C4D853D2672331B8914DC4512337700963C25A602B0C546F69C622EF7562EA04;
|
83
|
+
path=/; HttpOnly
|
84
|
+
- GZIP=1; expires=Sat, 04-Sep-2021 19:18:44 GMT; path=/
|
85
|
+
X-Powered-By:
|
86
|
+
- ASP.NET
|
87
|
+
Date:
|
88
|
+
- Mon, 05 Sep 2016 19:18:43 GMT
|
89
|
+
Content-Length:
|
90
|
+
- '378'
|
91
|
+
body:
|
92
|
+
encoding: ASCII-8BIT
|
93
|
+
string: '{"Status":"SUCCESS","Name":"Twitter Inc","Symbol":"TWTR","LastPrice":19.54,"Change":0.0399999999999991,"ChangePercent":0.205128205128201,"Timestamp":"Fri
|
94
|
+
Sep 2 15:59:00 UTC-04:00 2016","MSDate":42615.6659722222,"MarketCap":13828985580,"Volume":949554,"ChangeYTD":23.14,"ChangePercentYTD":-15.5574762316335,"High":19.87,"Low":19.355,"Open":19.61}'
|
95
|
+
http_version:
|
96
|
+
recorded_at: Mon, 05 Sep 2016 19:18:44 GMT
|
97
|
+
recorded_with: VCR 3.0.3
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stock-markit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Heijmans
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: httparty
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.14'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: oj
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.17'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.17'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activesupport
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
description: the stock-markit gem brings all the great information from Markit on
|
70
|
+
Demand to your ruby project (http://dev.markitondemand.com/)
|
71
|
+
email: parabuzzle@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- lib/stock-markit.rb
|
77
|
+
- lib/stock-markit/api_exception.rb
|
78
|
+
- lib/stock-markit/chart.rb
|
79
|
+
- lib/stock-markit/chart_result.rb
|
80
|
+
- lib/stock-markit/element.rb
|
81
|
+
- lib/stock-markit/lookup.rb
|
82
|
+
- lib/stock-markit/quote.rb
|
83
|
+
- lib/stock-markit/stock.rb
|
84
|
+
- lib/stock-markit/version.rb
|
85
|
+
- spec/lib/stock-markit/lookup_spec.rb
|
86
|
+
- spec/lib/stock-markit/quote_spec.rb
|
87
|
+
- spec/lib/stock-markit/version_spec.rb
|
88
|
+
- spec/spec_helper.rb
|
89
|
+
- spec/support/vcr.rb
|
90
|
+
- spec/vcr/lookup/twtr.yml
|
91
|
+
- spec/vcr/quote/twtr.yml
|
92
|
+
- spec/vcr/quote/twtr_update.yml
|
93
|
+
homepage: https://github.com/parabuzzle/stock-markit
|
94
|
+
licenses:
|
95
|
+
- MIT
|
96
|
+
metadata: {}
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 2.5.1
|
114
|
+
signing_key:
|
115
|
+
specification_version: 4
|
116
|
+
summary: stock-markit is the ruby interface for Markit on Demand.
|
117
|
+
test_files:
|
118
|
+
- spec/lib/stock-markit/lookup_spec.rb
|
119
|
+
- spec/lib/stock-markit/quote_spec.rb
|
120
|
+
- spec/lib/stock-markit/version_spec.rb
|
121
|
+
- spec/spec_helper.rb
|
122
|
+
- spec/support/vcr.rb
|
123
|
+
- spec/vcr/lookup/twtr.yml
|
124
|
+
- spec/vcr/quote/twtr.yml
|
125
|
+
- spec/vcr/quote/twtr_update.yml
|