questrade_api 1.1.0 → 1.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b4ce5fe5a4b01f8455e79cb80476d4426c1e9530
4
- data.tar.gz: 747bd6e4053f03cc36ead638ceecd27baf5cc80e
3
+ metadata.gz: e8141f3ee50e781f3ea23d1701d46e77c6ce6201
4
+ data.tar.gz: 3002e00f9d7ab48cc1a0c575c1a54ff7ae4f30ee
5
5
  SHA512:
6
- metadata.gz: 4cea9d006d79006b2af8c8f2093d480e347118c79243ab295705bd9ed3eb9983bebdc59c53e4398db2c5507d9d1f1efc95ee3222d2bf149d8faad688d7fd05da
7
- data.tar.gz: beaa6a59a7f869a3a38daa96dc2b7ed81a239b26dfb97f9c82a5e7aff71bb77d6b5493aae686ceb3eb1b1c18611287375b1aa6c4c88342ba453de9f1b9aaffd2
6
+ metadata.gz: 4d711919248d827c1d06287dfc53995c158f463e612d1d64d1a1c798bbbec8f388724eb8b89435c6640276e85acea3280938ceba6c96888be2a180965a16a1be
7
+ data.tar.gz: c9cba6dd7b09f80af88519766594862a118cd64bf5bdc6f4bc2d14a9111c1add1125caf4a8adc808e1e7b10f3c973f2d3142a2e3f5c7e5a1eff8bf8899a82998
@@ -1,4 +1,8 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.0
4
+ * Add ability to fetch quote details by id
5
+ * Add extra tests
6
+
3
7
  ## 1.0.0
4
8
  * Initial version. Disregard the previous versions
data/README.md CHANGED
@@ -83,9 +83,9 @@ client.candles('123', startTime: DateTime.yesterday.to_s, endTime: DateTime.now.
83
83
  # In case you already have a valid access token and its respective URL, you can use the QuestradeApi::REST objects. Example:
84
84
  # authorization can be any object that responds to url and access_token
85
85
  authorization = QuestradeApi::Authorization.new(access_token: 'access_token', api_server: 'url')
86
- accounts = QuestradeApi::REST::Account.fetch(accounts)
86
+ accounts = QuestradeApi::REST::Account.fetch(authorization)
87
87
  ```
88
- For more advanced options, check out our [documentation](http://www.rubydoc.info/gems/questrade_api/1.0.0).
88
+ For more advanced options, check out our [documentation](http://www.rubydoc.info/gems/questrade_api/1.1.0).
89
89
 
90
90
  ## Current Status
91
91
 
@@ -109,14 +109,14 @@ Check the tables below for more details.
109
109
  | Endpoint | Development | Documentation |
110
110
  | --- | --- | --- |
111
111
  | /symbols/ | DONE | |
112
- | /symbols/:id | | |
112
+ | /symbols/:id | DONE | |
113
113
  | /symbols/search | DONE | |
114
114
  | /symbols/:id/options | DONE | |
115
115
  | /markets | DONE | |
116
116
  | /markets/quotes/ | DONE | |
117
117
  | /markets/quotes/:id | DONE | |
118
- | /markets/quotes/options | | |
119
- | /markets/quotes/strategies | | |
118
+ | /markets/quotes/options | DONE | |
119
+ | /markets/quotes/strategies | DONE | |
120
120
  | /markets/candles/:id | DONE | |
121
121
 
122
122
  ### Order Calls
@@ -2,12 +2,14 @@ require 'questrade_api/authorization'
2
2
 
3
3
  require 'questrade_api/modules/account_call'
4
4
  require 'questrade_api/modules/market_call'
5
+ require 'questrade_api/modules/order_call'
5
6
 
6
7
  module QuestradeApi
7
8
  # @author Bruno Meira <goesmeira@gmail.com>
8
9
  class Client
9
10
  include QuestradeApi::AccountCall
10
11
  include QuestradeApi::MarketCall
12
+ include QuestradeApi::OrderCall
11
13
 
12
14
  attr_accessor :authorization
13
15
 
@@ -3,6 +3,8 @@ require 'questrade_api/rest/symbol'
3
3
  require 'questrade_api/rest/quote'
4
4
  require 'questrade_api/rest/candle'
5
5
  require 'questrade_api/rest/option'
6
+ require 'questrade_api/rest/option_quote'
7
+ require 'questrade_api/rest/strategy_quote'
6
8
 
7
9
  module QuestradeApi
8
10
  module MarketCall
@@ -38,6 +40,17 @@ module QuestradeApi
38
40
  quote
39
41
  end
40
42
 
43
+ def quote_options(filters, option_ids)
44
+ QuestradeApi::REST::OptionQuote.fetch(authorization,
45
+ filters: filters,
46
+ optionIds: option_ids)
47
+ end
48
+
49
+ def quote_strategies(variants)
50
+ QuestradeApi::REST::StrategyQuote.fetch(authorization,
51
+ variants: variants)
52
+ end
53
+
41
54
  def candles(symbol_id, params)
42
55
  QuestradeApi::REST::Candle.fetch(authorization, symbol_id, params)
43
56
  end
@@ -0,0 +1,9 @@
1
+ require 'questrade_api/rest/order'
2
+
3
+ module QuestradeApi
4
+ module OrderCall
5
+ def create_order(account_id, params = {})
6
+ QuestradeApi::REST::Order.create(authorization, account_id, params)
7
+ end
8
+ end
9
+ end
@@ -10,7 +10,7 @@ module QuestradeApi
10
10
  module REST
11
11
  # @author Bruno Meira <goesmeira@gmail.com>
12
12
  class Account < QuestradeApi::REST::Base
13
- attr_accessor :id, :user_id
13
+ attr_accessor :user_id
14
14
 
15
15
  def initialize(authorization, params)
16
16
  super(authorization)
@@ -10,7 +10,8 @@ module QuestradeApi
10
10
 
11
11
  BASE_ENDPOINT = '/v1'.freeze
12
12
  attr_accessor :connection, :raw_body, :endpoint,
13
- :authorization, :data
13
+ :authorization, :data, :account_id, :id
14
+
14
15
 
15
16
  # Initialize an instance of QuestradeApi::REST::Base
16
17
  #
@@ -41,6 +42,7 @@ module QuestradeApi
41
42
  # faraday.response :logger
42
43
  faraday.adapter Faraday.default_adapter
43
44
  faraday.headers['Content-Type'] = 'application/json'
45
+ faraday.headers['User-Agent'] = "QuestradeApi v#{QuestradeApi::VERSION}"
44
46
  faraday.headers['Authorization'] = "Bearer #{params[:access_token]}"
45
47
  end
46
48
  end
@@ -82,6 +84,15 @@ module QuestradeApi
82
84
  end
83
85
  end
84
86
  end
87
+
88
+ def post(params = {})
89
+ connection = connection(params)
90
+
91
+ connection.post do |req|
92
+ req.path = params[:endpoint]
93
+ req.body = params[:body] if params[:body]
94
+ end
95
+ end
85
96
  end
86
97
  end
87
98
  end
@@ -4,8 +4,6 @@ module QuestradeApi
4
4
  module REST
5
5
  # @author Bruno Meira <goesmeira@gmail.com>
6
6
  class Execution < QuestradeApi::REST::Base
7
- attr_accessor :account_id
8
-
9
7
  def initialize(params)
10
8
  @account_id = params[:account_id]
11
9
 
@@ -0,0 +1,45 @@
1
+ require 'questrade_api/rest/base'
2
+
3
+ module QuestradeApi
4
+ module REST
5
+ class OptionQuote < 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.fetch(authorization, params)
12
+ response = post(access_token: authorization.access_token,
13
+ endpoint: endpoint,
14
+ url: authorization.url,
15
+ body: params.to_json)
16
+
17
+ if response.status == 200
18
+ result = OpenStruct.new(optionQuotes: [])
19
+ result.optionQuotes = parse_option_quotes(response.body)
20
+ response = result
21
+ end
22
+
23
+ response
24
+ end
25
+
26
+ def self.endpoint
27
+ "#{BASE_ENDPOINT}/markets/quotes/options"
28
+ end
29
+
30
+ def self.parse_option_quotes(body)
31
+ raw = JSON.parse(body)
32
+
33
+ options = []
34
+
35
+ raw['optionQuotes'].each do |option|
36
+ options << new(data: option)
37
+ end
38
+
39
+ options
40
+ end
41
+
42
+ private_class_method :parse_option_quotes
43
+ end
44
+ end
45
+ end
@@ -3,8 +3,6 @@ require 'questrade_api/rest/base'
3
3
  module QuestradeApi
4
4
  module REST
5
5
  class Order < QuestradeApi::REST::Base
6
- attr_accessor :account_id, :id
7
-
8
6
  def initialize(authorization, params = {})
9
7
  super(authorization)
10
8
 
@@ -15,20 +13,37 @@ module QuestradeApi
15
13
  build_data(params[:data]) if @raw_body
16
14
  end
17
15
 
18
- def self.fetch(authorization, account_number, params)
16
+ def update(params = {})
17
+ params[:accountNumber] = account_id
18
+
19
+ response = self.class.post(access_token: authorization.access_token,
20
+ endpoint: endpoint,
21
+ url: authorization.url,
22
+ body: params.to_json)
23
+
24
+ parse_order(response.body) if response.status == 200
25
+
26
+ response
27
+ end
28
+
29
+ def self.create(authorization, account_number, params = {})
30
+ params[:accountNumber] = account_number
31
+
32
+ response = post(access_token: authorization.access_token,
33
+ endpoint: endpoint(account_number),
34
+ url: authorization.url,
35
+ body: params.to_json)
19
36
 
37
+ build_orders(authorization, account_number, response)
38
+ end
39
+
40
+ def self.fetch(authorization, account_number, params)
20
41
  response = super(access_token: authorization.access_token,
21
42
  endpoint: endpoint(account_number),
22
43
  url: authorization.url,
23
44
  params: params)
24
45
 
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
46
+ build_orders(authorization, account_number, response)
32
47
  end
33
48
 
34
49
  def endpoint
@@ -39,6 +54,13 @@ module QuestradeApi
39
54
  "#{BASE_ENDPOINT}/accounts/#{account_id}/orders"
40
55
  end
41
56
 
57
+ private
58
+
59
+ def parse_order(body)
60
+ raw = JSON.parse(body)
61
+ build_data(raw['orders'].first) if raw['orders'].size > 0
62
+ end
63
+
42
64
  def self.parse_orders(authorization, account_id, body)
43
65
  raw = JSON.parse(body)
44
66
 
@@ -52,7 +74,18 @@ module QuestradeApi
52
74
  orders
53
75
  end
54
76
 
55
- private_class_method :parse_orders
77
+ def self.build_orders(authorization, account_number, response)
78
+ result = response
79
+
80
+ if response.status == 200
81
+ result = OpenStruct.new(orders: [])
82
+ result.orders = parse_orders(authorization, account_number, response.body)
83
+ end
84
+
85
+ result
86
+ end
87
+
88
+ private_class_method :parse_orders, :build_orders
56
89
  end
57
90
  end
58
91
  end
@@ -3,8 +3,6 @@ require 'questrade_api/rest/base'
3
3
  module QuestradeApi
4
4
  module REST
5
5
  class Position < QuestradeApi::REST::Base
6
- attr_accessor :account_id
7
-
8
6
  def initialize(params)
9
7
  @account_id = params[:account_id]
10
8
 
@@ -3,8 +3,6 @@ require 'questrade_api/rest/base'
3
3
  module QuestradeApi
4
4
  module REST
5
5
  class Quote < QuestradeApi::REST::Base
6
- attr_accessor :id
7
-
8
6
  def initialize(params)
9
7
  super(params[:authorization])
10
8
  @id = params[:id]
@@ -0,0 +1,45 @@
1
+ require 'questrade_api/rest/base'
2
+
3
+ module QuestradeApi
4
+ module REST
5
+ class StrategyQuote < 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.fetch(authorization, params)
12
+ response = post(access_token: authorization.access_token,
13
+ endpoint: endpoint,
14
+ url: authorization.url,
15
+ body: params.to_json)
16
+
17
+ if response.status == 200
18
+ result = OpenStruct.new(strategyQuotes: [])
19
+ result.strategyQuotes = parse_strategy_quotes(response.body)
20
+ response = result
21
+ end
22
+
23
+ response
24
+ end
25
+
26
+ def self.endpoint
27
+ "#{BASE_ENDPOINT}/markets/quotes/strategies"
28
+ end
29
+
30
+ def self.parse_strategy_quotes(body)
31
+ raw = JSON.parse(body)
32
+
33
+ strategies = []
34
+
35
+ raw['strategyQuotes'].each do |strategy|
36
+ strategies << new(data: strategy)
37
+ end
38
+
39
+ strategies
40
+ end
41
+
42
+ private_class_method :parse_strategy_quotes
43
+ end
44
+ end
45
+ end
@@ -3,8 +3,6 @@ require 'questrade_api/rest/base'
3
3
  module QuestradeApi
4
4
  module REST
5
5
  class Symbol < QuestradeApi::REST::Base
6
- attr_accessor :id
7
-
8
6
  def initialize(authorization, params = {})
9
7
  super(authorization)
10
8
 
@@ -38,13 +36,7 @@ module QuestradeApi
38
36
  url: authorization.url,
39
37
  params: params)
40
38
 
41
- if response.status == 200
42
- result = OpenStruct.new(symbols: [])
43
- result.symbols = parse_symbols(authorization, response.body)
44
- response = result
45
- end
46
-
47
- response
39
+ build_symbols(authorization, response)
48
40
  end
49
41
 
50
42
  def self.fetch(authorization, params = {})
@@ -56,29 +48,39 @@ module QuestradeApi
56
48
  url: authorization.url,
57
49
  params: params)
58
50
 
51
+ build_symbols(authorization, response)
52
+ end
53
+
54
+ private
55
+
56
+ def parse_symbols(body)
57
+ raw = JSON.parse(body)
58
+
59
+ raw['symbols'].each do |symbol|
60
+ build_data(symbol)
61
+ end
62
+ end
63
+
64
+ def self.build_symbols(authorization, response)
65
+ result = response
66
+
59
67
  if response.status == 200
60
68
  result = OpenStruct.new(symbols: [])
61
69
  result.symbols = parse_symbols(authorization, response.body)
62
- response = result
63
70
  end
64
71
 
65
- response
72
+ result
66
73
  end
67
74
 
68
- # TODO: Review this later
69
75
  def self.parse_symbols(authorization, body)
70
76
  raw = JSON.parse(body)
71
77
 
72
78
  symbols = []
73
79
 
74
- if raw['symbols']
75
- raw['symbols'].each do |symbol|
76
- symbols << new(authorization, id: symbol['symbolId'], data: symbol)
77
- end
78
- end
80
+ results = raw['symbols'] || raw['symbol']
79
81
 
80
- if raw['symbol']
81
- raw['symbol'].each do |symbol|
82
+ if results
83
+ results.each do |symbol|
82
84
  symbols << new(authorization, id: symbol['symbolId'], data: symbol)
83
85
  end
84
86
  end
@@ -86,17 +88,7 @@ module QuestradeApi
86
88
  symbols
87
89
  end
88
90
 
89
- private_class_method :parse_symbols
90
-
91
- private
92
-
93
- def parse_symbols(body)
94
- raw = JSON.parse(body)
95
-
96
- raw['symbols'].each do |symbol|
97
- build_data(symbol)
98
- end
99
- end
91
+ private_class_method :parse_symbols, :build_symbols
100
92
  end
101
93
  end
102
94
  end
@@ -4,8 +4,6 @@ module QuestradeApi
4
4
  module REST
5
5
  # @author Bruno Meira <goesmeira@gmail.com>
6
6
  class Time < QuestradeApi::REST::Base
7
- attr_reader :data
8
-
9
7
  def initialize(authorization)
10
8
  super(authorization)
11
9
  end
@@ -1,3 +1,3 @@
1
1
  module QuestradeApi
2
- VERSION = '1.1.0'.freeze
2
+ VERSION = '1.2.0'.freeze
3
3
  end
@@ -0,0 +1,50 @@
1
+ {
2
+ "orderId": 177106005,
3
+ "orders": [
4
+ {
5
+ "id": 177106005,
6
+ "symbol": "AAPL",
7
+ "symbolId": 8049,
8
+ "totalQuantity": 10,
9
+ "openQuantity": 10,
10
+ "filledQuantity": 0,
11
+ "canceledQuantity": 0,
12
+ "side": "Buy",
13
+ "orderType": "Limit",
14
+ "limitPrice": 537,
15
+ "stopPrice": null,
16
+ "isAllOrNone": true,
17
+ "isAnonymous": false,
18
+ "icebergQty": 1,
19
+ "minQuantity": null,
20
+ "avgExecPrice": null,
21
+ "lastExecPrice": null,
22
+ "source": "TradingAPI",
23
+ "timeInForce": "GoodTillCanceled",
24
+ "gtdDate": null,
25
+ "state": "Pending",
26
+ "clientReasonStr": "",
27
+ "chainId": 177106005,
28
+ "creationTime": "2014-10-24T17:48:20.546000-04:00",
29
+ "updateTime": "2014-10-24T17:48:20.876000-04:00",
30
+ "notes": "",
31
+ "primaryRoute": "LAMP",
32
+ "secondaryRoute": "AUTO",
33
+ "orderRoute": "LAMP",
34
+ "venueHoldingOrder": "",
35
+ "comissionCharged": 0,
36
+ "exchangeOrderId": "",
37
+ "isSignificantShareHolder": false,
38
+ "isInsider": false,
39
+ "isLimitOffsetInDollar": false,
40
+ "userId": 3000124,
41
+ "placementCommission": null,
42
+ "legs": [],
43
+ "strategyType": "SingleLeg",
44
+ "triggerStopPrice": null,
45
+ "orderGroupId": 0,
46
+ "orderClass": null,
47
+ "mainChainId": 0
48
+ }
49
+ ]
50
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "optionQuotes": [
3
+ {
4
+ "underlying": "MSFT",
5
+ "underlyingId": 27426,
6
+ "symbol": "MSFT20Jan17C70.00",
7
+ "symbolId": 7413503,
8
+ "bidPrice": 4.90,
9
+ "bidSize": 0,
10
+ "askPrice": 4.95,
11
+ "askSize": 0,
12
+ "lastTradePriceTrHrs": 4.93,
13
+ "lastTradePrice": 4.93,
14
+ "lastTradeSize": 0,
15
+ "lastTradeTick": "Equal",
16
+ "lastTradeTime": "2015-08-17T00:00:00.000000-04:00",
17
+ "volume": 0,
18
+ "openPrice": 0,
19
+ "highPrice": 4.93,
20
+ "lowPrice": 0,
21
+ "volatility": 52.374257,
22
+ "delta": 0.06985,
23
+ "gamma": 0.01038,
24
+ "theta": -0.001406,
25
+ "vega": 0.074554,
26
+ "rho": 0.04153,
27
+ "openInterest": 2292,
28
+ "delay": 0,
29
+ "isHalted": false,
30
+ "VWAP": 0
31
+ }
32
+ ]
33
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "strategyQuotes": [
3
+ {
4
+ "variantId": 1,
5
+ "bidPrice": 27.2,
6
+ "askPrice": 27.23,
7
+ "underlying": "MSFT",
8
+ "underlyingId": 27426,
9
+ "openPrice": null,
10
+ "volatility": 0,
11
+ "delta": 1,
12
+ "gamma": 0,
13
+ "theta": 0,
14
+ "vega": 0,
15
+ "rho": 0,
16
+ "isRealTime": true
17
+ }
18
+ ]
19
+ }
@@ -59,6 +59,20 @@ describe QuestradeApi::MarketCall do
59
59
  end
60
60
  end
61
61
 
62
+ context '.quote_options' do
63
+ it 'calls proper endpoint' do
64
+ expect(QuestradeApi::REST::OptionQuote).to receive(:fetch).and_return([])
65
+ expect(subject.quote_options([], [])).to eq([])
66
+ end
67
+ end
68
+
69
+ context '.quote_strategies' do
70
+ it 'calls proper endpoint' do
71
+ expect(QuestradeApi::REST::StrategyQuote).to receive(:fetch).and_return([])
72
+ expect(subject.quote_strategies([])).to eq([])
73
+ end
74
+ end
75
+
62
76
  context '.candles' do
63
77
  it 'calls proper endpoint' do
64
78
  expect(QuestradeApi::REST::Candle).to receive(:fetch).and_return([])
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+ require 'questrade_api/rest/option_quote'
3
+
4
+ describe QuestradeApi::REST::OptionQuote do
5
+ include JSONFixtures
6
+
7
+ let(:access_token) { 'XXXX' }
8
+ let(:url) { 'http://test.com'}
9
+ let(:authorization) { OpenStruct.new(access_token: access_token, url: url) }
10
+
11
+ context '.fetch' do
12
+ it 'fetches option chain for an specific symbol' do
13
+ params = {
14
+ filters: [
15
+ {
16
+ optionType: "Call",
17
+ underlyingId: 27426,
18
+ expiryDate: "2017-01-20T00:00:00.000000-05:00",
19
+ minstrikePrice: 70,
20
+ maxstrikePrice: 80
21
+ }
22
+ ],
23
+ optionIds: [ 9907637, 9907638 ]
24
+ }
25
+
26
+ headers = { 'Accept' => '*/*',
27
+ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
28
+ 'Authorization' => 'Bearer XXXX',
29
+ 'Content-Type' => 'application/json',
30
+ 'User-Agent' => "QuestradeApi v#{QuestradeApi::VERSION}" }
31
+
32
+ stub_request(:post, 'http://test.com/v1/markets/quotes/options')
33
+ .with(body: params.to_json, headers: headers)
34
+ .to_return(status: 200, body: json_string('option_quotes.json'))
35
+
36
+ response = QuestradeApi::REST::OptionQuote.fetch(authorization, params)
37
+
38
+ expect(response.optionQuotes.size).to be(1)
39
+
40
+ first_option = response.optionQuotes.first
41
+ expect(first_option.data.to_h).to eq(
42
+ {
43
+ underlying: "MSFT",
44
+ underlying_id: 27426,
45
+ symbol: "MSFT20Jan17C70.00",
46
+ symbol_id: 7413503,
47
+ bid_price: 4.90,
48
+ bid_size: 0,
49
+ ask_price: 4.95,
50
+ ask_size: 0,
51
+ last_trade_price_tr_hrs: 4.93,
52
+ last_trade_price: 4.93,
53
+ last_trade_size: 0,
54
+ last_trade_tick: "Equal",
55
+ last_trade_time: "2015-08-17T00:00:00.000000-04:00",
56
+ volume: 0,
57
+ open_price: 0,
58
+ high_price: 4.93,
59
+ low_price: 0,
60
+ volatility: 52.374257,
61
+ delta: 0.06985,
62
+ gamma: 0.01038,
63
+ theta: -0.001406,
64
+ vega: 0.074554,
65
+ rho: 0.04153,
66
+ open_interest: 2292,
67
+ delay: 0,
68
+ is_halted: false,
69
+ vwap: 0
70
+ }
71
+ )
72
+ end
73
+ end
74
+
75
+ context '.endpoint' do
76
+ it 'returns the right endpoint' do
77
+ url = "/v1/markets/quotes/options"
78
+ expect(QuestradeApi::REST::OptionQuote.endpoint).to eq(url)
79
+ end
80
+ end
81
+ end
@@ -9,6 +9,152 @@ describe QuestradeApi::REST::Order do
9
9
  let(:account_id) { '123456' }
10
10
  let(:url) { 'http://test.com'}
11
11
  let(:authorization) { OpenStruct.new(access_token: access_token, url: url) }
12
+ let(:params) {
13
+ {
14
+ accountNumber: account_id,
15
+ symbolId: 8049,
16
+ quantity: 10,
17
+ icebergQuantity: 1,
18
+ limitPrice: 537,
19
+ isAllOrNone: true,
20
+ isAnonymous: false,
21
+ orderType: "Limit",
22
+ timeInForce: "GoodTillCanceled",
23
+ action: "Buy",
24
+ primaryRoute: "AUTO",
25
+ secondaryRoute: "AUTO"
26
+ }
27
+ }
28
+
29
+ let(:headers) {
30
+ { 'Accept' => '*/*',
31
+ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
32
+ 'Authorization' => 'Bearer XXXX',
33
+ 'Content-Type' => 'application/json',
34
+ 'User-Agent' => "QuestradeApi v#{QuestradeApi::VERSION}" }
35
+ }
36
+
37
+ context '#update' do
38
+ let(:id) { 177106005 }
39
+ subject { QuestradeApi::REST::Order.new(authorization,
40
+ id: id, account_id: account_id ) }
41
+
42
+ it 'updates an existing order' do
43
+ url = "http://test.com/v1/accounts/#{account_id}/orders/#{id}"
44
+ stub_request(:post, url)
45
+ .with(body: params.to_json, headers: headers)
46
+ .to_return(status: 200, body: json_string('create_update_order.json'))
47
+
48
+ subject.update(params)
49
+
50
+ expect(subject.data.to_h).to eq(
51
+ id: 177106005,
52
+ symbol: "AAPL",
53
+ symbol_id: 8049,
54
+ total_quantity: 10,
55
+ open_quantity: 10,
56
+ filled_quantity: 0,
57
+ canceled_quantity: 0,
58
+ side: "Buy",
59
+ order_type: "Limit",
60
+ limit_price: 537,
61
+ stop_price: nil,
62
+ is_all_or_none: true,
63
+ is_anonymous: false,
64
+ iceberg_qty: 1,
65
+ min_quantity: nil,
66
+ avg_exec_price: nil,
67
+ last_exec_price: nil,
68
+ source: "TradingAPI",
69
+ time_in_force: "GoodTillCanceled",
70
+ gtd_date: nil,
71
+ state: "Pending",
72
+ client_reason_str: "",
73
+ chain_id: 177106005,
74
+ creation_time: "2014-10-24T17:48:20.546000-04:00",
75
+ update_time: "2014-10-24T17:48:20.876000-04:00",
76
+ notes: "",
77
+ primary_route: "LAMP",
78
+ secondary_route: "AUTO",
79
+ order_route: "LAMP",
80
+ venue_holding_order: "",
81
+ comission_charged: 0,
82
+ exchange_order_id: "",
83
+ is_significant_share_holder: false,
84
+ is_insider: false,
85
+ is_limit_offset_in_dollar: false,
86
+ user_id: 3000124,
87
+ placement_commission: nil,
88
+ legs: [],
89
+ strategy_type: "SingleLeg",
90
+ trigger_stop_price: nil,
91
+ order_group_id: 0,
92
+ order_class: nil,
93
+ main_chain_id: 0
94
+ )
95
+ end
96
+ end
97
+
98
+ context '.create' do
99
+ it "places an order" do
100
+ url = "http://test.com/v1/accounts/#{account_id}/orders"
101
+ stub_request(:post, url)
102
+ .with(body: params.to_json, headers: headers)
103
+ .to_return(status: 200, body: json_string('create_update_order.json'))
104
+
105
+ response = QuestradeApi::REST::Order.create(authorization, account_id, params)
106
+
107
+ expect(response.orders.size).to be(1)
108
+
109
+ first_order = response.orders.first
110
+ expect(first_order.account_id).to eq(account_id)
111
+ expect(first_order.data.to_h).to eq(
112
+ id: 177106005,
113
+ symbol: "AAPL",
114
+ symbol_id: 8049,
115
+ total_quantity: 10,
116
+ open_quantity: 10,
117
+ filled_quantity: 0,
118
+ canceled_quantity: 0,
119
+ side: "Buy",
120
+ order_type: "Limit",
121
+ limit_price: 537,
122
+ stop_price: nil,
123
+ is_all_or_none: true,
124
+ is_anonymous: false,
125
+ iceberg_qty: 1,
126
+ min_quantity: nil,
127
+ avg_exec_price: nil,
128
+ last_exec_price: nil,
129
+ source: "TradingAPI",
130
+ time_in_force: "GoodTillCanceled",
131
+ gtd_date: nil,
132
+ state: "Pending",
133
+ client_reason_str: "",
134
+ chain_id: 177106005,
135
+ creation_time: "2014-10-24T17:48:20.546000-04:00",
136
+ update_time: "2014-10-24T17:48:20.876000-04:00",
137
+ notes: "",
138
+ primary_route: "LAMP",
139
+ secondary_route: "AUTO",
140
+ order_route: "LAMP",
141
+ venue_holding_order: "",
142
+ comission_charged: 0,
143
+ exchange_order_id: "",
144
+ is_significant_share_holder: false,
145
+ is_insider: false,
146
+ is_limit_offset_in_dollar: false,
147
+ user_id: 3000124,
148
+ placement_commission: nil,
149
+ legs: [],
150
+ strategy_type: "SingleLeg",
151
+ trigger_stop_price: nil,
152
+ order_group_id: 0,
153
+ order_class: nil,
154
+ main_chain_id: 0
155
+ )
156
+ end
157
+ end
12
158
 
13
159
  context '.fetch' do
14
160
  it "returns an object that contains a list of all user's orders" do
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+ require 'questrade_api/rest/strategy_quote'
3
+
4
+ describe QuestradeApi::REST::StrategyQuote do
5
+ include JSONFixtures
6
+
7
+ let(:access_token) { 'XXXX' }
8
+ let(:url) { 'http://test.com'}
9
+ let(:authorization) { OpenStruct.new(access_token: access_token, url: url) }
10
+
11
+ context '.fetch' do
12
+ it 'fetches strategy chain for an specific symbol' do
13
+ params = {
14
+ variants: [
15
+ {
16
+ variantId: 1,
17
+ strategy: "Custom",
18
+ legs: [
19
+ {
20
+ symbolId: 27426,
21
+ ratio: 1000,
22
+ action: "Buy"
23
+ },
24
+ {
25
+ symbolId: 10550014,
26
+ ratio: 10,
27
+ action: "Sell"
28
+ }
29
+ ]
30
+ }
31
+ ]
32
+ }
33
+
34
+ headers = { 'Accept' => '*/*',
35
+ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
36
+ 'Authorization' => 'Bearer XXXX',
37
+ 'Content-Type' => 'application/json',
38
+ 'User-Agent' => "QuestradeApi v#{QuestradeApi::VERSION}" }
39
+
40
+ stub_request(:post, 'http://test.com/v1/markets/quotes/strategies')
41
+ .with(body: params.to_json, headers: headers)
42
+ .to_return(status: 200, body: json_string('strategy_quotes.json'))
43
+
44
+ response = QuestradeApi::REST::StrategyQuote.fetch(authorization, params)
45
+
46
+ expect(response.strategyQuotes.size).to be(1)
47
+
48
+ first_strategy = response.strategyQuotes.first
49
+ expect(first_strategy.data.to_h).to eq(
50
+ {
51
+ variant_id: 1,
52
+ bid_price: 27.2,
53
+ ask_price: 27.23,
54
+ underlying: "MSFT",
55
+ underlying_id: 27426,
56
+ open_price: nil,
57
+ volatility: 0,
58
+ delta: 1,
59
+ gamma: 0,
60
+ theta: 0,
61
+ vega: 0,
62
+ rho: 0,
63
+ is_real_time: true
64
+ }
65
+ )
66
+ end
67
+ end
68
+
69
+ context '.endpoint' do
70
+ it 'returns the right endpoint' do
71
+ url = "/v1/markets/quotes/strategies"
72
+ expect(QuestradeApi::REST::StrategyQuote.endpoint).to eq(url)
73
+ end
74
+ end
75
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: questrade_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bruno Meira
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-13 00:00:00.000000000 Z
11
+ date: 2017-03-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -88,6 +88,7 @@ files:
88
88
  - lib/questrade_api/client.rb
89
89
  - lib/questrade_api/modules/account_call.rb
90
90
  - lib/questrade_api/modules/market_call.rb
91
+ - lib/questrade_api/modules/order_call.rb
91
92
  - lib/questrade_api/modules/util.rb
92
93
  - lib/questrade_api/rest/account.rb
93
94
  - lib/questrade_api/rest/activity.rb
@@ -97,9 +98,11 @@ files:
97
98
  - lib/questrade_api/rest/execution.rb
98
99
  - lib/questrade_api/rest/market.rb
99
100
  - lib/questrade_api/rest/option.rb
101
+ - lib/questrade_api/rest/option_quote.rb
100
102
  - lib/questrade_api/rest/order.rb
101
103
  - lib/questrade_api/rest/position.rb
102
104
  - lib/questrade_api/rest/quote.rb
105
+ - lib/questrade_api/rest/strategy_quote.rb
103
106
  - lib/questrade_api/rest/symbol.rb
104
107
  - lib/questrade_api/rest/time.rb
105
108
  - lib/questrade_api/version.rb
@@ -108,13 +111,16 @@ files:
108
111
  - spec/fixtures/json/activities.json
109
112
  - spec/fixtures/json/balances.json
110
113
  - spec/fixtures/json/candles.json
114
+ - spec/fixtures/json/create_update_order.json
111
115
  - spec/fixtures/json/executions.json
112
116
  - spec/fixtures/json/markets.json
117
+ - spec/fixtures/json/option_quotes.json
113
118
  - spec/fixtures/json/options.json
114
119
  - spec/fixtures/json/orders.json
115
120
  - spec/fixtures/json/positions.json
116
121
  - spec/fixtures/json/quote_01.json
117
122
  - spec/fixtures/json/quotes.json
123
+ - spec/fixtures/json/strategy_quotes.json
118
124
  - spec/fixtures/json/symbol_01.json
119
125
  - spec/fixtures/json/symbols.json
120
126
  - spec/fixtures/json/symbols_search.json
@@ -129,10 +135,12 @@ files:
129
135
  - spec/questrade_api/rest/candle_spec.rb
130
136
  - spec/questrade_api/rest/execution_spec.rb
131
137
  - spec/questrade_api/rest/market_spec.rb
138
+ - spec/questrade_api/rest/option_quote_spec.rb
132
139
  - spec/questrade_api/rest/option_spec.rb
133
140
  - spec/questrade_api/rest/order_spec.rb
134
141
  - spec/questrade_api/rest/position_spec.rb
135
142
  - spec/questrade_api/rest/quote_spec.rb
143
+ - spec/questrade_api/rest/strategy_quote_spec.rb
136
144
  - spec/questrade_api/rest/symbol_spec.rb
137
145
  - spec/questrade_api/rest/time_spec.rb
138
146
  - spec/spec_helper.rb
@@ -166,13 +174,16 @@ test_files:
166
174
  - spec/fixtures/json/activities.json
167
175
  - spec/fixtures/json/balances.json
168
176
  - spec/fixtures/json/candles.json
177
+ - spec/fixtures/json/create_update_order.json
169
178
  - spec/fixtures/json/executions.json
170
179
  - spec/fixtures/json/markets.json
180
+ - spec/fixtures/json/option_quotes.json
171
181
  - spec/fixtures/json/options.json
172
182
  - spec/fixtures/json/orders.json
173
183
  - spec/fixtures/json/positions.json
174
184
  - spec/fixtures/json/quote_01.json
175
185
  - spec/fixtures/json/quotes.json
186
+ - spec/fixtures/json/strategy_quotes.json
176
187
  - spec/fixtures/json/symbol_01.json
177
188
  - spec/fixtures/json/symbols.json
178
189
  - spec/fixtures/json/symbols_search.json
@@ -187,10 +198,12 @@ test_files:
187
198
  - spec/questrade_api/rest/candle_spec.rb
188
199
  - spec/questrade_api/rest/execution_spec.rb
189
200
  - spec/questrade_api/rest/market_spec.rb
201
+ - spec/questrade_api/rest/option_quote_spec.rb
190
202
  - spec/questrade_api/rest/option_spec.rb
191
203
  - spec/questrade_api/rest/order_spec.rb
192
204
  - spec/questrade_api/rest/position_spec.rb
193
205
  - spec/questrade_api/rest/quote_spec.rb
206
+ - spec/questrade_api/rest/strategy_quote_spec.rb
194
207
  - spec/questrade_api/rest/symbol_spec.rb
195
208
  - spec/questrade_api/rest/time_spec.rb
196
209
  - spec/spec_helper.rb