questrade_api 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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