questrade_api 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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