questrade_api 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +3 -0
  5. data/.yardopts +9 -0
  6. data/Gemfile +15 -0
  7. data/Guardfile +6 -0
  8. data/{LICENSE.txt → LICENSE} +0 -0
  9. data/README.md +31 -45
  10. data/Rakefile +4 -0
  11. data/lib/questrade_api/authorization.rb +94 -0
  12. data/lib/questrade_api/client.rb +87 -0
  13. data/lib/questrade_api/modules/util.rb +22 -0
  14. data/lib/questrade_api/rest/account.rb +101 -0
  15. data/lib/questrade_api/rest/activity.rb +58 -0
  16. data/lib/questrade_api/rest/balance.rb +81 -0
  17. data/lib/questrade_api/rest/base.rb +88 -0
  18. data/lib/questrade_api/rest/execution.rb +59 -0
  19. data/lib/questrade_api/rest/market.rb +42 -0
  20. data/lib/questrade_api/rest/order.rb +58 -0
  21. data/lib/questrade_api/rest/position.rb +48 -0
  22. data/lib/questrade_api/rest/time.rb +26 -0
  23. data/lib/questrade_api/version.rb +1 -1
  24. data/questrade_api.gemspec +2 -3
  25. data/spec/fixtures/json/accounts.json +21 -0
  26. data/spec/fixtures/json/activities.json +36 -0
  27. data/spec/fixtures/json/balances.json +55 -0
  28. data/spec/fixtures/json/executions.json +46 -0
  29. data/spec/fixtures/json/markets.json +34 -0
  30. data/spec/fixtures/json/orders.json +49 -0
  31. data/spec/fixtures/json/positions.json +17 -0
  32. data/spec/fixtures/json/time.json +3 -0
  33. data/spec/questrade_api/authorization_spec.rb +74 -0
  34. data/spec/questrade_api/client_spec.rb +38 -0
  35. data/spec/questrade_api/rest/account_spec.rb +88 -0
  36. data/spec/questrade_api/rest/activity_spec.rb +70 -0
  37. data/spec/questrade_api/rest/balance_spec.rb +34 -0
  38. data/spec/questrade_api/rest/execution_spec.rb +80 -0
  39. data/spec/questrade_api/rest/market_spec.rb +63 -0
  40. data/spec/questrade_api/rest/order_spec.rb +95 -0
  41. data/spec/questrade_api/rest/position_spec.rb +47 -0
  42. data/spec/questrade_api/rest/time_spec.rb +34 -0
  43. data/spec/spec_helper.rb +107 -0
  44. data/spec/support/json_fixtures.rb +21 -0
  45. metadata +61 -47
@@ -0,0 +1,58 @@
1
+ require 'questrade_api/rest/base'
2
+
3
+ module QuestradeApi
4
+ module REST
5
+ # @author Bruno Meira <goesmeira@gmail.com>
6
+ class Activity < QuestradeApi::REST::Base
7
+ attr_accessor :account_id
8
+
9
+ def initialize(params)
10
+ @account_id = params[:account_id]
11
+
12
+ @raw_body = params[:data]
13
+ build_data(params[:data]) if @raw_body
14
+ end
15
+
16
+ #
17
+ # Fetch account activities
18
+ #
19
+ # @param authorization [QuestradeApi::Authorization] with the authorized #access_token and #url.
20
+ # @param account_number [String] with the account the activities will be fetched
21
+ # @param params [Hash] with the range of dates the activities will be fetched
22
+ # @option params [String] :startTime The start time. ex: '2011-02-16T00:00:00.000000-05:00'
23
+ # @option params [String] :endTime The end time. ex: '2011-02-16T00:00:00.000000-05:00'
24
+ def self.all(authorization, account_number, params)
25
+ response = super(access_token: authorization.access_token,
26
+ endpoint: endpoint(account_number),
27
+ url: authorization.url,
28
+ params: params)
29
+
30
+ result = OpenStruct.new(activities: [])
31
+
32
+ if response.status == 200
33
+ result.activities = parse_activities(account_number, response.body)
34
+ end
35
+
36
+ result
37
+ end
38
+
39
+ def self.endpoint(account_id)
40
+ "#{BASE_ENDPOINT}/accounts/#{account_id}/activities"
41
+ end
42
+
43
+ def self.parse_activities(account_number, body)
44
+ raw = JSON.parse(body)
45
+
46
+ activities = []
47
+
48
+ raw['activities'].each do |activity|
49
+ activities << new(account_id: account_number, data: activity)
50
+ end
51
+
52
+ activities
53
+ end
54
+
55
+ private_class_method :parse_activities
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,81 @@
1
+ require 'questrade_api/rest/base'
2
+
3
+ module QuestradeApi
4
+ module REST
5
+ # @author Bruno Meira <goesmeira@gmail.com>
6
+ class Balance < QuestradeApi::REST::Base
7
+ attr_accessor :account_id
8
+
9
+ def initialize(params)
10
+ @account_id = params[:account_id]
11
+
12
+ @raw_body = params[:data]
13
+ build_data(params[:data]) if @raw_body
14
+ end
15
+
16
+ #
17
+ # Fetch account balances
18
+ #
19
+ # @param authorization [QuestradeApi::Authorization] with the authorized #access_token and #url.
20
+ # @param account_number [String] with the account the activities will be fetched
21
+ # @return [OpenStruct(per_currency_balances, combined_balances, sod_per_currency_balances, sod_combined_balances)] If call succeeds. Each method returns an array of QuestradeApi::REST::Balance
22
+ # @return [Faraday::Response] if call fails.
23
+ def self.all(authorization, account_number)
24
+ response = super(access_token: authorization.access_token,
25
+ endpoint: endpoint(account_number),
26
+ url: authorization.url)
27
+
28
+ result = OpenStruct.new(per_currency_balances: [],
29
+ combined_balances: [],
30
+ sod_per_currency_balances: [],
31
+ sod_combined_balances: [])
32
+
33
+ if response.status == 200
34
+ parse_balances(account_number, response.body).each do |key, value|
35
+ result.send("#{key}=", value)
36
+ end
37
+ end
38
+
39
+ result
40
+ end
41
+
42
+ def self.endpoint(account_id)
43
+ "#{BASE_ENDPOINT}/accounts/#{account_id}/balances"
44
+ end
45
+
46
+ def self.parse_balances(account_number, body)
47
+ raw = JSON.parse(body)
48
+ balances = {
49
+ per_currency_balances: [],
50
+ combined_balances: [],
51
+ sod_per_currency_balances: [],
52
+ sod_combined_balances: []
53
+ }
54
+
55
+ raw['perCurrencyBalances'].each do |balance|
56
+ balances[:per_currency_balances] << new(account_id: account_number,
57
+ data: balance)
58
+ end
59
+
60
+ raw['combinedBalances'].each do |balance|
61
+ balances[:combined_balances] << new(account_id: account_number,
62
+ data: balance)
63
+ end
64
+
65
+ raw['sodPerCurrencyBalances'].each do |balance|
66
+ balances[:sod_per_currency_balances] << new(account_id: account_number,
67
+ data: balance)
68
+ end
69
+
70
+ raw['sodCombinedBalances'].each do |balance|
71
+ balances[:sod_combined_balances] << new(account_id: account_number,
72
+ data: balance)
73
+ end
74
+
75
+ balances
76
+ end
77
+
78
+ private_class_method :parse_balances
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,88 @@
1
+ require 'questrade_api/modules/util'
2
+ require 'faraday'
3
+ require 'json'
4
+
5
+ module QuestradeApi
6
+ module REST
7
+ # @author Bruno Meira <goesmeira@gmail.com>
8
+ class Base
9
+ include QuestradeApi::Util
10
+
11
+ BASE_ENDPOINT = '/v1'.freeze
12
+ attr_accessor :connection, :raw_body, :endpoint,
13
+ :authorization, :data
14
+
15
+ # Initialize an instance of QuestradeApi::REST::Base
16
+ #
17
+ # @param authorization [Object] to access API. Any object that responds to url and access_token.
18
+ def initialize(authorization)
19
+ @authorization = authorization
20
+
21
+ # TODO: Review this later
22
+ @connection =
23
+ self.class.connection(url: url,
24
+ access_token: @authorization.access_token)
25
+ end
26
+
27
+ # @return [String]
28
+ def url
29
+ authorization.url
30
+ end
31
+
32
+ # Builds a new Faraday connection to access endpoint.
33
+ #
34
+ # @param params [Hash] for connection.
35
+ # @option params [String] :url of endpoint.
36
+ # @option params [String] :access_token to call endpoint.
37
+ #
38
+ # @return [Faraday] Object with attributes set up to call proper endpoint.
39
+ def self.connection(params = {})
40
+ Faraday.new(params[:url]) do |faraday|
41
+ # faraday.response :logger
42
+ faraday.adapter Faraday.default_adapter
43
+ faraday.headers['Content-Type'] = 'application/json'
44
+ faraday.headers['Authorization'] = "Bearer #{params[:access_token]}"
45
+ end
46
+ end
47
+
48
+ protected
49
+
50
+ def build_data(data)
51
+ hash = hash_to_snakecase(data)
52
+ @data = OpenStruct.new(hash)
53
+ end
54
+
55
+ def build_attributes(response)
56
+ @raw_body = JSON.parse(response.body)
57
+ end
58
+
59
+ def get(params = {})
60
+ response = @connection.get do |req|
61
+ req.path = self.class.endpoint
62
+
63
+ params.each do |key, value|
64
+ req.params[key] = value
65
+ end
66
+ end
67
+
68
+ build_attributes(response) if response.status == 200
69
+
70
+ response
71
+ end
72
+
73
+ class << self
74
+ def all(params = {})
75
+ connection = connection(params)
76
+
77
+ connection.get do |req|
78
+ req.path = params[:endpoint]
79
+
80
+ params.fetch(:params, []).each do |key, value|
81
+ req.params[key] = value
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,59 @@
1
+ require 'questrade_api/rest/base'
2
+
3
+ module QuestradeApi
4
+ module REST
5
+ # @author Bruno Meira <goesmeira@gmail.com>
6
+ class Execution < QuestradeApi::REST::Base
7
+ attr_accessor :account_id
8
+
9
+ def initialize(params)
10
+ @account_id = params[:account_id]
11
+
12
+ @raw_body = params[:data]
13
+ build_data(params[:data]) if @raw_body
14
+ end
15
+
16
+ #
17
+ # Fetch account executions
18
+ #
19
+ # @param authorization [QuestradeApi::Authorization] with the authorized #access_token and #url.
20
+ # @param account_number [String] with the account the activities will be fetched
21
+ # @param params [Hash] with the range of dates the activities will be fetched
22
+ # @option params [String] :startTime The start time. ex: '2011-02-16T00:00:00.000000-05:00'
23
+ # @option params [String] :endTime The end time. ex: '2011-02-16T00:00:00.000000-05:00'
24
+ def self.all(authorization, account_number, params)
25
+
26
+ response = super(access_token: authorization.access_token,
27
+ endpoint: endpoint(account_number),
28
+ url: authorization.url,
29
+ params: params)
30
+
31
+ result = OpenStruct.new(executions: [])
32
+
33
+ if response.status == 200
34
+ result.executions = parse_executions(account_number, response.body)
35
+ end
36
+
37
+ result
38
+ end
39
+
40
+ def self.endpoint(account_id)
41
+ "#{BASE_ENDPOINT}/accounts/#{account_id}/executions"
42
+ end
43
+
44
+ def self.parse_executions(account_id, body)
45
+ raw = JSON.parse(body)
46
+
47
+ executions = []
48
+
49
+ raw['executions'].each do |execution|
50
+ executions << new(account_id: account_id, data: execution)
51
+ end
52
+
53
+ executions
54
+ end
55
+
56
+ private_class_method :parse_executions
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,42 @@
1
+ require 'questrade_api/rest/base'
2
+
3
+ module QuestradeApi
4
+ module REST
5
+ class Market < QuestradeApi::REST::Base
6
+ def initialize(params)
7
+ @raw_body = params[:data]
8
+ build_data(params[:data]) if @raw_body
9
+ end
10
+
11
+ def self.all(authorization)
12
+ response = super(access_token: authorization.access_token,
13
+ endpoint: endpoint,
14
+ url: authorization.url)
15
+
16
+ result = OpenStruct.new(markets: [])
17
+
18
+ result.markets = parse_markets(response.body) if response.status == 200
19
+
20
+ result
21
+ end
22
+
23
+ def self.endpoint
24
+ "#{BASE_ENDPOINT}/markets"
25
+ end
26
+
27
+ def self.parse_markets(body)
28
+ raw = JSON.parse(body)
29
+
30
+ markets = []
31
+
32
+ raw['markets'].each do |market|
33
+ markets << new(data: market)
34
+ end
35
+
36
+ markets
37
+ end
38
+
39
+ private_class_method :parse_markets
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,58 @@
1
+ require 'questrade_api/rest/base'
2
+
3
+ module QuestradeApi
4
+ module REST
5
+ class Order < QuestradeApi::REST::Base
6
+ attr_accessor :account_id, :id
7
+
8
+ def initialize(authorization, params = {})
9
+ super(authorization)
10
+
11
+ @id = params[:id]
12
+ @account_id = params[:account_id]
13
+
14
+ @raw_body = params[:data]
15
+ build_data(params[:data]) if @raw_body
16
+ end
17
+
18
+ def self.all(authorization, account_number, params)
19
+
20
+ response = super(access_token: authorization.access_token,
21
+ endpoint: endpoint(account_number),
22
+ url: authorization.url,
23
+ params: params)
24
+
25
+ result = OpenStruct.new(orders: [])
26
+
27
+ if response.status == 200
28
+ result.orders = parse_orders(authorization, account_number, response.body)
29
+ end
30
+
31
+ result
32
+ end
33
+
34
+ def endpoint
35
+ self.class.endpoint(account_id) + "/#{id}"
36
+ end
37
+
38
+ def self.endpoint(account_id)
39
+ "#{BASE_ENDPOINT}/accounts/#{account_id}/orders"
40
+ end
41
+
42
+ def self.parse_orders(authorization, account_id, body)
43
+ raw = JSON.parse(body)
44
+
45
+ orders = []
46
+
47
+ raw['orders'].each do |order|
48
+ orders << new(authorization,
49
+ account_id: account_id, id: order['id'], data: order)
50
+ end
51
+
52
+ orders
53
+ end
54
+
55
+ private_class_method :parse_orders
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,48 @@
1
+ require 'questrade_api/rest/base'
2
+
3
+ module QuestradeApi
4
+ module REST
5
+ class Position < QuestradeApi::REST::Base
6
+ attr_accessor :account_id
7
+
8
+ def initialize(params)
9
+ @account_id = params[:account_id]
10
+
11
+ @raw_body = params[:data]
12
+ build_data(params[:data]) if @raw_body
13
+ end
14
+
15
+ def self.all(authorization, account_number)
16
+ response = super(access_token: authorization.access_token,
17
+ endpoint: endpoint(account_number),
18
+ url: authorization.url)
19
+
20
+ result = OpenStruct.new(positions: [])
21
+
22
+ if response.status == 200
23
+ result.positions = parse_positions(account_number, response.body)
24
+ end
25
+
26
+ result
27
+ end
28
+
29
+ def self.endpoint(account_id)
30
+ "#{BASE_ENDPOINT}/accounts/#{account_id}/positions"
31
+ end
32
+
33
+ def self.parse_positions(account_id, body)
34
+ raw = JSON.parse(body)
35
+
36
+ positions = []
37
+
38
+ raw['positions'].each do |position|
39
+ positions << new(account_id: account_id, data: position)
40
+ end
41
+
42
+ positions
43
+ end
44
+
45
+ private_class_method :parse_positions
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,26 @@
1
+ require 'questrade_api/rest/base'
2
+
3
+ module QuestradeApi
4
+ module REST
5
+ # @author Bruno Meira <goesmeira@gmail.com>
6
+ class Time < QuestradeApi::REST::Base
7
+ attr_reader :data
8
+
9
+ def initialize(authorization)
10
+ super(authorization)
11
+ end
12
+
13
+ def get
14
+ response = super
15
+
16
+ build_data(raw_body) if raw_body
17
+
18
+ response
19
+ end
20
+
21
+ def self.endpoint
22
+ "#{BASE_ENDPOINT}/time"
23
+ end
24
+ end
25
+ end
26
+ end