Class: SQA::Stock
Overview
SMELL: SQA::Stock is now pretty coupled to the Alpha Vantage
API service. Should that stuff be extracted into a
separate class and injected by the requiring program?
Constant Summary collapse
- CONNECTION =
Faraday.new(url: "https://www.alphavantage.co")
- @@top =
nil
Instance Attribute Summary collapse
-
#data ⇒ Object
General Info – SQA::DataFrame::Data.
-
#df ⇒ Object
Historical Prices – SQA::DataFrame::Data.
-
#klass ⇒ Object
class of historical and current prices.
-
#strategy ⇒ Object
Holds the SQA::Strategy class name which seems to work the best for this stock.
-
#transformers ⇒ Object
procs for changing column values from String to Numeric.
Class Method Summary collapse
-
.top ⇒ Object
Top Gainers, Losers and Most Active for most recent closed trading day.
Instance Method Summary collapse
- #associate_best_strategy(strategies) ⇒ Object
- #create ⇒ Object
- #evaluate_strategy(strategy) ⇒ Object
-
#initialize(ticker:, source: :alpha_vantage) ⇒ Stock
constructor
A new instance of Stock.
- #load ⇒ Object
- #merge_overview ⇒ Object
- #save ⇒ Object
- #to_s ⇒ Object (also: #inspect)
- #update ⇒ Object
- #update_the_dataframe ⇒ Object
Constructor Details
#initialize(ticker:, source: :alpha_vantage) ⇒ Stock
Returns a new instance of Stock.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/sqa/stock.rb', line 24 def initialize( ticker:, source: :alpha_vantage ) @ticker = ticker.downcase @source = source raise "Invalid Ticker #{ticker}" unless SQA::Ticker.valid?(ticker) @data_path = SQA.data_dir + "#{@ticker}.json" @df_path = SQA.data_dir + "#{@ticker}.csv" @klass = "SQA::DataFrame::#{@source.to_s.camelize}".constantize @transformers = "SQA::DataFrame::#{@source.to_s.camelize}::TRANSFORMERS".constantize if @data_path.exist? load else create update save end update_the_dataframe end |
Instance Attribute Details
#data ⇒ Object
General Info – SQA::DataFrame::Data
13 14 15 |
# File 'lib/sqa/stock.rb', line 13 def data @data end |
#df ⇒ Object
Historical Prices – SQA::DataFrame::Data
14 15 16 |
# File 'lib/sqa/stock.rb', line 14 def df @df end |
#klass ⇒ Object
class of historical and current prices
16 17 18 |
# File 'lib/sqa/stock.rb', line 16 def klass @klass end |
#strategy ⇒ Object
Holds the SQA::Strategy class name which seems to work the best for this stock.
21 22 23 |
# File 'lib/sqa/stock.rb', line 21 def strategy @strategy end |
#transformers ⇒ Object
procs for changing column values from String to Numeric
17 18 19 |
# File 'lib/sqa/stock.rb', line 17 def transformers @transformers end |
Class Method Details
.top ⇒ Object
Top Gainers, Losers and Most Active for most recent closed trading day.
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/sqa/stock.rb', line 187 def top return @@top unless @@top.nil? a_hash = JSON.parse( CONNECTION.get( "/query?function=TOP_GAINERS_LOSERS&apikey=#{SQA.av.key}" ).to_hash[:body] ) mash = Hashie::Mash.new(a_hash) keys = mash.top_gainers.first.keys %w[top_gainers top_losers most_actively_traded].each do |collection| mash.send(collection).each do |e| keys.each do |k| case k when 'ticker' # Leave it as a String when 'volume' e[k] = e[k].to_i else e[k] = e[k].to_f end end end end @@top = mash end |
Instance Method Details
#associate_best_strategy(strategies) ⇒ Object
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/sqa/stock.rb', line 154 def associate_best_strategy(strategies) best_strategy = nil best_accuracy = 0 strategies.each do |strategy| accuracy = evaluate_strategy(strategy) if accuracy > best_accuracy best_strategy = strategy best_accuracy = accuracy end end self.strategy = best_strategy end |
#create ⇒ Object
59 60 61 62 63 64 65 66 67 68 |
# File 'lib/sqa/stock.rb', line 59 def create @data = SQA::DataFrame::Data.new( { ticker: @ticker, source: @source, indicators: { xyzzy: "Magic" }, } ) end |
#evaluate_strategy(strategy) ⇒ Object
171 172 173 174 |
# File 'lib/sqa/stock.rb', line 171 def evaluate_strategy(strategy) # TODO: Implement this method to evaluate the accuracy of the strategy # on the historical data of this stock. end |
#load ⇒ Object
52 53 54 55 56 |
# File 'lib/sqa/stock.rb', line 52 def load @data = SQA::DataFrame::Data.new( JSON.parse(@data_path.read) ) end |
#merge_overview ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/sqa/stock.rb', line 123 def merge_overview temp = JSON.parse( CONNECTION.get("/query?function=OVERVIEW&symbol=#{ticker.upcase}&apikey=#{SQA.av.key}") .to_hash[:body] ) if temp.has_key? "Information" ApiError.raise(temp["Information"]) end # TODO: CamelCase hash keys look common in Alpha Vantage # JSON; look at making a special Hashie-based class # to convert the keys to normal Ruby standards. temp2 = {} string_values = %w[ address asset_type cik country currency description dividend_date ex_dividend_date exchange fiscal_year_end industry latest_quarter name sector symbol ] temp.keys.each do |k| new_k = k.underscore temp2[new_k] = string_values.include?(new_k) ? temp[k] : temp[k].to_f end @data.overview = temp2 end |
#save ⇒ Object
76 77 78 |
# File 'lib/sqa/stock.rb', line 76 def save @data_path.write @data.to_json end |
#to_s ⇒ Object Also known as: inspect
117 118 119 |
# File 'lib/sqa/stock.rb', line 117 def to_s "#{ticker} with #{@df.size} data points from #{@df..first} to #{@df..last}" end |
#update ⇒ Object
71 72 73 |
# File 'lib/sqa/stock.rb', line 71 def update merge_overview end |
#update_the_dataframe ⇒ Object
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/sqa/stock.rb', line 91 def update_the_dataframe if @df_path.exist? @df = SQA::DataFrame.load( source: @df_path, transformers: @transformers ) else @df = klass.recent(@ticker, full: true) @df.to_csv(@df_path) return end from_date = Date.parse(@df..last) + 1 df2 = klass.recent(@ticker, from_date: from_date) return if df2.nil? # CSV file is up to date. df_nrows = @df.nrows @df.append!(df2) if @df.nrows > df_nrows @df.to_csv(@df_path) end end |