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.
- 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
|