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.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/.yardopts +9 -0
- data/Gemfile +15 -0
- data/Guardfile +6 -0
- data/{LICENSE.txt → LICENSE} +0 -0
- data/README.md +31 -45
- data/Rakefile +4 -0
- data/lib/questrade_api/authorization.rb +94 -0
- data/lib/questrade_api/client.rb +87 -0
- data/lib/questrade_api/modules/util.rb +22 -0
- data/lib/questrade_api/rest/account.rb +101 -0
- data/lib/questrade_api/rest/activity.rb +58 -0
- data/lib/questrade_api/rest/balance.rb +81 -0
- data/lib/questrade_api/rest/base.rb +88 -0
- data/lib/questrade_api/rest/execution.rb +59 -0
- data/lib/questrade_api/rest/market.rb +42 -0
- data/lib/questrade_api/rest/order.rb +58 -0
- data/lib/questrade_api/rest/position.rb +48 -0
- data/lib/questrade_api/rest/time.rb +26 -0
- data/lib/questrade_api/version.rb +1 -1
- data/questrade_api.gemspec +2 -3
- data/spec/fixtures/json/accounts.json +21 -0
- data/spec/fixtures/json/activities.json +36 -0
- data/spec/fixtures/json/balances.json +55 -0
- data/spec/fixtures/json/executions.json +46 -0
- data/spec/fixtures/json/markets.json +34 -0
- data/spec/fixtures/json/orders.json +49 -0
- data/spec/fixtures/json/positions.json +17 -0
- data/spec/fixtures/json/time.json +3 -0
- data/spec/questrade_api/authorization_spec.rb +74 -0
- data/spec/questrade_api/client_spec.rb +38 -0
- data/spec/questrade_api/rest/account_spec.rb +88 -0
- data/spec/questrade_api/rest/activity_spec.rb +70 -0
- data/spec/questrade_api/rest/balance_spec.rb +34 -0
- data/spec/questrade_api/rest/execution_spec.rb +80 -0
- data/spec/questrade_api/rest/market_spec.rb +63 -0
- data/spec/questrade_api/rest/order_spec.rb +95 -0
- data/spec/questrade_api/rest/position_spec.rb +47 -0
- data/spec/questrade_api/rest/time_spec.rb +34 -0
- data/spec/spec_helper.rb +107 -0
- data/spec/support/json_fixtures.rb +21 -0
- 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
|