alphavantagerb 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,70 @@
1
+ module Alphavantage
2
+ class Client
3
+ include HelperFunctions
4
+
5
+ def initialize key:, verbose: false
6
+ check_argument([true, false], verbose, "verbose")
7
+ @apikey = key
8
+ @base_uri = 'https://www.alphavantage.co'
9
+ @verbose = verbose
10
+ end
11
+
12
+ attr_reader :verbose
13
+
14
+ def verbose=(verbose)
15
+ check_argument([true, false], verbose, "verbose")
16
+ @verbose = verbose
17
+ end
18
+
19
+ def request(url)
20
+ send_url = "#{@base_uri}/query?#{url}&apikey=#{@apikey}"
21
+ puts "\n#{send_url}\n" if @verbose
22
+ begin
23
+ response = HTTParty.get(send_url)
24
+ rescue Exception => e
25
+ raise Alphavantage::Error.new message: "Failed request: #{e.message}"
26
+ end
27
+ data = response.body
28
+ begin
29
+ data = JSON.parse(data)
30
+ rescue Exception => e
31
+ raise Alphavantage::Error.new message: "Parsing failed",
32
+ data: data
33
+ end
34
+ if !data["Error Message"].nil?
35
+ raise Alphavantage::Error.new message: data["Error Message"], data: data
36
+ elsif !data["Information"].nil?
37
+ raise Alphavantage::Error.new message: data["Information"], data: data
38
+ end
39
+ return data
40
+ end
41
+
42
+ def download(url, file)
43
+ send_url = "#{@base_uri}/query?#{url}&datatype=csv&apikey=#{@apikey}"
44
+ begin
45
+ puts send_url if @verbose
46
+ uri = URI.parse(send_url)
47
+ uri.open{|csv| IO.copy_stream(csv, file)}
48
+ rescue Exception => e
49
+ raise Alphavantage::Error.new message: "Failed to save the CSV file: #{e.message}"
50
+ end
51
+ return "CSV saved in #{file}"
52
+ end
53
+
54
+ def stock(symbol:, datatype: "json")
55
+ Alphavantage::Stock.new symbol: symbol, key: self, datatype: datatype
56
+ end
57
+
58
+ def exchange(from:, to:)
59
+ Alphavantage::Exchange.new from: from, to: to, key: self
60
+ end
61
+
62
+ def crypto(symbol:, market:, datatype: "json")
63
+ Alphavantage::Crypto.new symbol: symbol, key: self, datatype: datatype, market: market
64
+ end
65
+
66
+ def sector
67
+ Alphavantage::Sector.new key: self
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,26 @@
1
+ module Alphavantage
2
+ class Crypto
3
+ include HelperFunctions
4
+
5
+ def initialize symbol:, datatype: "json", key:, verbose: false, market:
6
+ check_argument([true, false], verbose, "verbose")
7
+ @client = return_client(key, verbose)
8
+ @symbol = symbol
9
+ @market = market
10
+ @datatype = datatype
11
+ end
12
+
13
+ attr_accessor :symbol, :market
14
+ attr_reader :datatype
15
+
16
+ def datatype=(datatype)
17
+ check_argument(["json", "csv"], datatype, "datatype")
18
+ @datatype = datatype
19
+ end
20
+
21
+ def timeseries type: "intraday", market: @market, file: nil, datatype: @datatype
22
+ Alphavantage::Crypto_Timeseries.new type: type, market: market,
23
+ symbol: @symbol, datatype: datatype, file: file, key: @client
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,67 @@
1
+ module Alphavantage
2
+ class Crypto_Timeseries
3
+ include HelperFunctions
4
+
5
+ def initialize type: "intraday", market:, symbol:, datatype: "json", file: nil,
6
+ key:, verbose: false
7
+ check_argument([true, false], verbose, "verbose")
8
+ @client = return_client(key, verbose)
9
+ check_argument(["json", "csv"], datatype, "datatype")
10
+ if datatype == "csv" && file.nil?
11
+ raise Alphavantage::Error.new message: "No file specified where to save the CSV data"
12
+ elsif datatype != "csv" && !file.nil?
13
+ raise Alphavantage::Error.new message: "Hash error: No file necessary"
14
+ end
15
+
16
+ @selected_time_series = which_series(type)
17
+ url = "function=#{@selected_time_series}&symbol=#{symbol}&market=#{market}"
18
+ return @client.download(url, file) if datatype == "csv"
19
+ @hash = @client.request(url)
20
+ metadata = @hash.dig("Meta Data") || {}
21
+ metadata.each do |key, val|
22
+ key_sym = key.downcase.gsub(/[0-9.]/, "").lstrip.gsub(" ", "_").to_sym
23
+ define_singleton_method(key_sym) do
24
+ return val
25
+ end
26
+ end
27
+ @open = []; @high = []; @low = []; @close = []; @volume = [];
28
+ @open_usd = []; @high_usd = []; @low_usd = []; @close_usd = [];
29
+ @market_cap_usd = [];
30
+
31
+ begin
32
+ time_series = @hash.find{|key, val| key.include?("Time Series")}[1]
33
+ rescue Exception => e
34
+ raise Alphavantage::Error.new message: "No Time Series found: #{e.message}",
35
+ data: @hash
36
+ end
37
+
38
+ series = {}
39
+ convert_key = {}
40
+ time_series.values[0].keys.each do |key|
41
+ key_sym = recreate_metadata_key(key)
42
+ series[key_sym] = []
43
+ convert_key[key] = key_sym
44
+ end
45
+ time_series.each do |time, ts_hash|
46
+ ts_hash.each do |key, value|
47
+ series[convert_key[key]] << [time, value]
48
+ end
49
+ end
50
+ series.keys.each do |key_sym|
51
+ define_singleton_method(key_sym) do |*args|
52
+ args ||= []
53
+ return return_series(series[key_sym], args[0])
54
+ end
55
+ end
56
+ end
57
+
58
+ attr_reader :hash
59
+
60
+ def which_series(type)
61
+ check_argument(["intraday", "daily", "weekly", "monthly"], type, "type")
62
+ series = "DIGITAL_CURRENCY_"
63
+ series += type.upcase
64
+ return series
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,9 @@
1
+ module Alphavantage
2
+ class Error < StandardError
3
+ def initialize(message: , data: nil)
4
+ @data = data
5
+ super(message)
6
+ end
7
+ attr_reader :data
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ module Alphavantage
2
+ class Exchange
3
+ include HelperFunctions
4
+
5
+ def initialize from:, to:, key:, verbose: false
6
+ check_argument([true, false], verbose, "verbose")
7
+ @client = return_client(key, verbose)
8
+ @from = from
9
+ @to = to
10
+ @hash = @client.request("function=CURRENCY_EXCHANGE_RATE&from_currency=#{@from}&to_currency=#{@to}")
11
+ hash = @hash["Realtime Currency Exchange Rate"]
12
+ hash.each do |key, val|
13
+ key_sym = recreate_metadata_key(key)
14
+ define_singleton_method(key_sym) do
15
+ return val
16
+ end
17
+ end
18
+ end
19
+
20
+ attr_reader :hash
21
+
22
+ end
23
+ end
@@ -0,0 +1,135 @@
1
+ module Alphavantage
2
+ class Indicator
3
+ include HelperFunctions
4
+
5
+ def initialize function:, symbol:, interval: "daily", time_period: "60",
6
+ series_type: "close", fastlimit: "0.01", slowlimit: "0.01",
7
+ fastperiod: "12", slowperiod: "26", signalperiod: "9",
8
+ fastmatype: "0", slowmatype: "0", signalmatype: "0",
9
+ fastkperiod: "5", slowkperiod: "3", slowdperiod: "3",
10
+ slowkmatype: "0", slowdmatype: "0", fastdperiod: "3",
11
+ fastdmatype: "0", matype: "0", timeperiod1: "7", timeperiod2: "14",
12
+ timeperiod3: "28", nbdevup: "2", nbdevdn: "2", acceleration: "0.01",
13
+ maximum: "0.20", key:, verbose: false
14
+ check_argument([true, false], verbose, "verbose")
15
+ @client = return_client(key, verbose)
16
+ check_argument(["SMA", "EMA", "WMA", "DEMA", "TEMA", "TRIMA", "KAMA", "T3",
17
+ "RSI","MAMA", "MACD", "MACDEXT", "STOCH", "STOCHF", "STOCHRSI", "WILLR",
18
+ "ADX", "ADXR", "APO", "PPO", "MOM", "BOP", "CCI", "CMO", "ROC", "ROCR",
19
+ "AROON", "AROONOSC", "MFI", "TRIX", "ULTOSC", "DX", "MINUS_DI",
20
+ "PLUS_DI", "MINUS_DM", "PLUS_DM", "BBANDS", "MIDPOINT", "MIDPRICE",
21
+ "SAR", "TRANGE", "ATR", "NATR", "AD", "ADOSC", "OBV", "HT_SINE",
22
+ "HT_TRENDLINE", "HT_TRENDMODE", "HT_DCPERIOD", "HT_DCPHASE",
23
+ "HT_PHASOR"], function, "function")
24
+ url = "function=#{function}&symbol=#{symbol}"
25
+
26
+ if ["SMA", "EMA", "WMA", "DEMA", "TEMA", "TRIMA", "KAMA", "T3", "RSI",
27
+ "MAMA", "MACD", "MACDEXT", "STOCH", "STOCHF", "STOCHRSI", "WILLR",
28
+ "ADX", "ADXR", "APO", "PPO", "MOM", "BOP", "CCI", "CMO", "ROC", "ROCR",
29
+ "AROON", "AROONOSC", "MFI", "TRIX", "ULTOSC", "DX", "MINUS_DI",
30
+ "PLUS_DI", "MINUS_DM", "PLUS_DM", "BBANDS", "MIDPOINT", "MIDPRICE",
31
+ "SAR", "TRANGE", "ATR", "NATR", "AD", "ADOSC", "OBV", "HT_SINE",
32
+ "HT_TRENDLINE", "HT_TRENDMODE", "HT_DCPERIOD", "HT_DCPHASE",
33
+ "HT_PHASOR"].include? function
34
+ check_argument(["1min", "5min", "15min", "30min", "60min", "daily", "weekly", "monthly"], interval, "interval")
35
+ url += "&interval=#{interval}"
36
+ end
37
+ if ["SMA", "EMA", "WMA", "DEMA", "TEMA", "TRIMA", "KAMA", "T3", "RSI",
38
+ "STOCHRSI", "WILLR", "ADX", "ADXR", "MOM", "CCI", "CMO", "ROC", "ROCR",
39
+ "AROON", "AROONOSC", "MFI", "TRIX", "DX", "MINUS_DI", "PLUS_DI",
40
+ "MINUS_DM", "PLUS_DM", "BBANDS", "MIDPOINT", "MIDPRICE", "ATR",
41
+ "NATR"].include? function
42
+ url += return_int_val(time_period, "time_period", "integer")
43
+ end
44
+ if ["SMA", "EMA", "WMA", "DEMA", "TEMA", "TRIMA", "KAMA", "T3", "RSI",
45
+ "MAMA", "MACD", "MACDEXT", "STOCHRSI", "APO", "PPO", "MOM", "ROC",
46
+ "ROCR", "TRIX", "BBANDS", "MIDPOINT", "HT_SINE", "HT_TRENDLINE",
47
+ "HT_TRENDMODE", "HT_DCPERIOD", "HT_DCPHASE", "HT_PHASOR", "CMO"].include? function
48
+ check_argument(["close", "open", "high", "low"], series_type, "series_type")
49
+ url += "&series_type=#{series_type}"
50
+ end
51
+ if ["MAMA"].include? function
52
+ url += return_int_val(fastlimit, "fastlimit", "float")
53
+ url += return_int_val(slowlimit, "slowlimit", "float")
54
+ end
55
+ if ["MACD", "MACDEXT", "APO", "PPO", "ADOSC"].include? function
56
+ url += return_int_val(fastperiod, "fastperiod", "integer")
57
+ url += return_int_val(slowperiod, "slowperiod", "integer")
58
+ end
59
+ if ["MACD", "MACDEXT"].include? function
60
+ url += return_int_val(signalperiod, "signalperiod", "integer")
61
+ end
62
+ if ["MACDEXT"].include? function
63
+ url += return_matype(fastmatype, "fastmatype")
64
+ url += return_matype(slowmatype, "slowmatype")
65
+ url += return_matype(signalmatype, "signalmatype")
66
+ end
67
+ if ["STOCH", "STOCHF", "STOCHRSI"].include? function
68
+ url += return_int_val(fastkperiod, "fastkperiod", "integer")
69
+ url += return_int_val(fastdperiod, "fastdperiod", "integer")
70
+ end
71
+ if ["STOCH"].include? function
72
+ url += return_int_val(slowkperiod, "slowkperiod", "integer")
73
+ url += return_int_val(signalperiod, "signalperiod", "integer")
74
+ url += return_matype(slowkmatype, "slowkmatype")
75
+ url += return_matype(slowdmatype, "slowdmatype")
76
+ end
77
+ if ["STOCH", "STOCHF", "STOCHRSI"].include? function
78
+ url += return_matype(fastdmatype, "fastdmatype")
79
+ end
80
+ if ["APO", "PPO", "BBANDS"].include? function
81
+ url += return_matype(matype, "matype")
82
+ end
83
+ if ["ULTOSC"].include? function
84
+ url += return_int_val(timeperiod1, "timeperiod1", "integer")
85
+ url += return_int_val(timeperiod2, "timeperiod2", "integer")
86
+ url += return_int_val(timeperiod3, "timeperiod3", "integer")
87
+ end
88
+ if ["BBANDS"].include? function
89
+ url += return_int_val(nbdevup, "nbdevup", "integer")
90
+ url += return_int_val(nbdevdn, "nbdevdn", "integer")
91
+ end
92
+ if ["SAR"].include? function
93
+ url += return_int_val(acceleration, "acceleration", "float")
94
+ url += return_int_val(maximum, "maximum", "float")
95
+ end
96
+
97
+ @hash = @client.request(url)
98
+ metadata = @hash.dig("Meta Data") || {}
99
+ metadata.each do |key, val|
100
+ key_sym = recreate_metadata_key(key)
101
+ define_singleton_method(key_sym) do
102
+ return val
103
+ end
104
+ end
105
+
106
+ begin
107
+ time_series = @hash.find{|key, val| key.include?("Technical Analysis")}[1]
108
+ rescue Exception => e
109
+ raise Alphavantage::Error.new message: "No Time Series found: #{e.message}",
110
+ data: @hash
111
+ end
112
+
113
+ series = {}
114
+ convert_key = {}
115
+ time_series.values[0].keys.each do |key|
116
+ key_sym = key.downcase.gsub(/[.\/]/, "").lstrip.gsub(" ", "_").to_sym
117
+ series[key_sym] = []
118
+ convert_key[key] = key_sym
119
+ end
120
+ time_series.each do |time, ts_hash|
121
+ ts_hash.each do |key, value|
122
+ series[convert_key[key]] << [time, value]
123
+ end
124
+ end
125
+ series.keys.each do |key_sym|
126
+ define_singleton_method(key_sym) do |*args|
127
+ args ||= []
128
+ return return_series(series[key_sym], args[0])
129
+ end
130
+ end
131
+ end
132
+
133
+ attr_reader :hash
134
+ end
135
+ end
@@ -0,0 +1,34 @@
1
+ module Alphavantage
2
+ class Sector
3
+ include HelperFunctions
4
+
5
+ def initialize key:, verbose: false
6
+ check_argument([true, false], verbose, "verbose")
7
+ @client = return_client(key, verbose)
8
+ @hash = @client.request("function=SECTOR")
9
+ metadata = @hash.dig("Meta Data") || {}
10
+ metadata.each do |key, val|
11
+ key_sym = key.downcase.gsub(/[0-9.]/, "").lstrip.gsub(" ", "_").to_sym
12
+ define_singleton_method(key_sym) do
13
+ return val
14
+ end
15
+ end
16
+ @hash.each do |key, val|
17
+ next if key == "Meta Data"
18
+ key = key.split(":")[1].lstrip
19
+ key = key.split(" ")
20
+ if key[0].to_i != 0
21
+ key[0] = key[0].to_i.humanize
22
+ end
23
+ key.delete_if{|k| k.include?("(")}
24
+ key = key.join("_")
25
+ key_sym = key.downcase.gsub("-", "_").to_sym
26
+ define_singleton_method(key_sym) do
27
+ return val
28
+ end
29
+ end
30
+ end
31
+
32
+ attr_reader :hash
33
+ end
34
+ end
@@ -0,0 +1,49 @@
1
+ module Alphavantage
2
+ class Stock
3
+ include HelperFunctions
4
+
5
+ def initialize symbol:, datatype: "json", key:, verbose: false
6
+ check_argument([true, false], verbose, "verbose")
7
+ @client = return_client(key, verbose)
8
+ @symbol = symbol
9
+ @datatype = datatype
10
+ end
11
+
12
+ attr_accessor :symbol
13
+ attr_reader :datatype
14
+
15
+ def datatype=(datatype)
16
+ check_argument(["json", "csv"], datatype, "datatype")
17
+ @datatype = datatype
18
+ end
19
+
20
+ def timeseries type: "daily", interval: nil, outputsize: "compact",
21
+ file: nil, datatype: @datatype, adjusted: false
22
+ Alphavantage::Timeseries.new type: type, interval: interval,
23
+ outputsize: outputsize, symbol: @symbol, datatype: datatype, file: file,
24
+ key: @client, adjusted: adjusted
25
+ end
26
+
27
+ def indicator function:, interval: "daily", time_period: "60",
28
+ series_type: "close", fastlimit: "0.01", slowlimit: "0.01",
29
+ fastperiod: "12", slowperiod: "26", signalperiod: "9",
30
+ fastmatype: "0", slowmatype: "0", signalmatype: "0",
31
+ fastkperiod: "5", slowkperiod: "3", slowdperiod: "3",
32
+ slowkmatype: "0", slowdmatype: "0", fastdperiod: "3",
33
+ fastdmatype: "0", matype: "0", timeperiod1: "7", timeperiod2: "14",
34
+ timeperiod3: "28", nbdevup: "2", nbdevdn: "2", acceleration: "0.01",
35
+ maximum: "0.20"
36
+ Alphavantage::Indicator.new function: function, symbol: @symbol,
37
+ interval: interval, time_period: time_period, series_type: series_type,
38
+ fastlimit: fastlimit, slowlimit: slowlimit, fastperiod: fastperiod,
39
+ slowperiod: slowperiod, signalperiod: signalperiod,
40
+ fastmatype: fastmatype, slowmatype: slowmatype,
41
+ signalmatype: signalmatype, fastkperiod: fastkperiod, slowkperiod: slowkperiod,
42
+ slowdperiod: slowdperiod, slowkmatype: slowkmatype, slowdmatype: slowdmatype,
43
+ fastdperiod: fastdperiod, fastdmatype: fastdmatype, matype: matype,
44
+ timeperiod1: timeperiod1, timeperiod2: timeperiod2, timeperiod3: timeperiod3,
45
+ nbdevup: nbdevup, nbdevdn: nbdevdn, acceleration: acceleration,
46
+ maximum: maximum, key: @client
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,76 @@
1
+ module Alphavantage
2
+ class Timeseries
3
+ include HelperFunctions
4
+
5
+ def initialize type: "daily", interval: nil, outputsize: "compact",
6
+ symbol:, datatype: "json", file: nil, key:, verbose: false,
7
+ adjusted: false
8
+ check_argument([true, false], verbose, "verbose")
9
+ @client = return_client(key, verbose)
10
+ if type == "intraday"
11
+ interval ||= "1min"
12
+ check_argument(["1min", "5min", "15min", "30min", "60min"], interval, "interval")
13
+ check_argument([false], adjusted, "adjusted")
14
+ interval = "&interval=#{interval}"
15
+ else
16
+ check_argument([nil], interval, "interval")
17
+ interval = ""
18
+ end
19
+ check_argument(["compact", "full"], outputsize, "outputsize")
20
+ check_argument(["json", "csv"], datatype, "datatype")
21
+ if datatype == "csv" && file.nil?
22
+ raise Alphavantage::Error.new message: "No file specified where to save the CSV ata"
23
+ elsif datatype != "csv" && !file.nil?
24
+ raise Alphavantage::Error.new message: "Hash error: No file necessary"
25
+ end
26
+
27
+ @selected_time_series = which_series(type, adjusted)
28
+ url = "function=#{@selected_time_series}&symbol=#{symbol}#{interval}&outputsize=#{outputsize}"
29
+ return @client.download(url, file) if datatype == "csv"
30
+ @hash = @client.request(url)
31
+ metadata = @hash.dig("Meta Data") || {}
32
+ metadata.each do |key, val|
33
+ key_sym = recreate_metadata_key(key)
34
+ define_singleton_method(key_sym) do
35
+ return val
36
+ end
37
+ end
38
+
39
+ begin
40
+ time_series = @hash.find{|key, val| key.include?("Time Series")}[1]
41
+ rescue Exception => e
42
+ raise Alphavantage::Error.new message: "No Time Series found: #{e.message}",
43
+ data: @hash
44
+ end
45
+
46
+ series = {}
47
+ convert_key = {}
48
+ time_series.values[0].keys.each do |key|
49
+ key_sym = key.downcase.gsub(/[0-9.]/, "").lstrip.gsub(" ", "_").to_sym
50
+ series[key_sym] = []
51
+ convert_key[key] = key_sym
52
+ end
53
+ time_series.each do |time, ts_hash|
54
+ ts_hash.each do |key, value|
55
+ series[convert_key[key]] << [time, value]
56
+ end
57
+ end
58
+ series.keys.each do |key_sym|
59
+ define_singleton_method(key_sym) do |*args|
60
+ args ||= []
61
+ return return_series(series[key_sym], args[0])
62
+ end
63
+ end
64
+ end
65
+
66
+ attr_reader :hash
67
+
68
+ def which_series(type, adjusted)
69
+ check_argument(["intraday", "daily", "weekly", "monthly"], type, "type")
70
+ series = "TIME_SERIES_"
71
+ series += type.upcase
72
+ series += "_ADJUSTED" if adjusted
73
+ return series
74
+ end
75
+ end
76
+ end