oanda_api_v20 1.5.0 → 2.0.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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +1 -1
- data/CHANGELOG.md +11 -0
- data/README.md +19 -9
- data/lib/oanda_api_v20/accounts.rb +1 -1
- data/lib/oanda_api_v20/api.rb +78 -1
- data/lib/oanda_api_v20/client.rb +27 -94
- data/lib/oanda_api_v20/exceptions.rb +1 -0
- data/lib/oanda_api_v20/instruments.rb +1 -1
- data/lib/oanda_api_v20/version.rb +1 -1
- data/oanda_api_v20.gemspec +1 -1
- data/spec/oanda_api_v20/api_spec.rb +439 -260
- data/spec/oanda_api_v20/client_spec.rb +105 -114
- data/spec/oanda_api_v20/oanda_api_v20_spec.rb +2 -2
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2e44f2d12b3c6e2fafe20137218ecfec9d8f4678
|
4
|
+
data.tar.gz: cec80bbcce9fe58398319d715a2d7a50cc1f37f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b4439bf716d67a9117036009817ea19caa302b610b234832b7f7294116df3ab6b5ee6763967c6f4932a0630143367bcf498132f0b689e0c7627f9afdeff6a4e
|
7
|
+
data.tar.gz: 984932b04c7095c02af46a3000a6b2c8935f8062e707d235a45d07afcc43a4f94d719744d83b7277ab64e90525f1e3086982134b6e2ea58c001714bc717d694b
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 2.0.0
|
4
|
+
#### 2018-04-24
|
5
|
+
* Fixed issues when trying to reuse a Client object to make HTTP requests to Oanda.
|
6
|
+
* Moved instance variables last_action, last_arguments, instrument and account_id from the Client class to the Api class. They should not be part of a Client object.
|
7
|
+
* Removed last_transaction_id instance variable.
|
8
|
+
* RubyVM::Logger changed to ::Logger.
|
9
|
+
* Added a connection_pool_size option to allow persistent HTTP connection control on the Client object.
|
10
|
+
* Added a max_requests_per_second option to allow customized control on the Client max requests per second allowed to Oanda API.
|
11
|
+
* Added multithreading support for HTTP request governing. HTTP requests will be correctly allocated across multiple client threads.
|
12
|
+
* Raises an OandaApiV20::ApiError exception when no client object was supplied when instantiating an OandaApiV20::Api instance.
|
13
|
+
|
3
14
|
## 1.5.0
|
4
15
|
#### 2017-07-07
|
5
16
|
* Updated the orders method to allow query options to be passed along.
|
data/README.md
CHANGED
@@ -37,6 +37,14 @@ If you need your requests to go through a proxy:
|
|
37
37
|
|
38
38
|
client = OandaApiV20.new(access_token: 'my_access_token', proxy_url: 'https://user:pass@proxy.com:80')
|
39
39
|
|
40
|
+
You can adjust the persistend connection pool size, the default is 2:
|
41
|
+
|
42
|
+
client = OandaApiV20.new(access_token: 'my_access_token', connection_pool_size: 10)
|
43
|
+
|
44
|
+
You can adjust the number of requests per second allowed to Oanda API, the default is 100:
|
45
|
+
|
46
|
+
client = OandaApiV20.new(access_token: 'my_access_token', max_requests_per_second: 10)
|
47
|
+
|
40
48
|
## Examples
|
41
49
|
|
42
50
|
### Accounts
|
@@ -63,10 +71,6 @@ client.account('account_id').instruments.show
|
|
63
71
|
client.account('account_id').instruments('EUR_USD,EUR_CAD').show
|
64
72
|
```
|
65
73
|
|
66
|
-
```ruby
|
67
|
-
client.account('account_id').changes.show
|
68
|
-
```
|
69
|
-
|
70
74
|
```ruby
|
71
75
|
options = { 'sinceTransactionID' => '6358' }
|
72
76
|
|
@@ -103,6 +107,10 @@ options = { 'instrument' => 'USD_CAD' }
|
|
103
107
|
client.account('account_id').orders(options).show
|
104
108
|
```
|
105
109
|
|
110
|
+
```ruby
|
111
|
+
client.account('account_id').pending_orders.show
|
112
|
+
```
|
113
|
+
|
106
114
|
```ruby
|
107
115
|
id = client.account('account_id').orders.show['orders'][0]['id']
|
108
116
|
|
@@ -128,10 +136,12 @@ id = client.account('account_id').orders.show['orders'][0]['id']
|
|
128
136
|
|
129
137
|
options = {
|
130
138
|
'order' => {
|
139
|
+
'instrument' => 'EUR_CAD',
|
140
|
+
'price' => '1.6000',
|
131
141
|
'timeInForce' => 'GTC',
|
132
|
-
'
|
133
|
-
'
|
134
|
-
'
|
142
|
+
'type' => 'MARKET_IF_TOUCHED',
|
143
|
+
'units' => '200',
|
144
|
+
'positionFill' => 'DEFAULT'
|
135
145
|
}
|
136
146
|
}
|
137
147
|
|
@@ -182,11 +192,11 @@ id = client.account('account_id').open_trades.show['trades'][0]['id']
|
|
182
192
|
options = {
|
183
193
|
'takeProfit' => {
|
184
194
|
'timeInForce' => 'GTC',
|
185
|
-
'price' => '
|
195
|
+
'price' => '2.5'
|
186
196
|
},
|
187
197
|
'stopLoss' => {
|
188
198
|
'timeInForce' => 'GTC',
|
189
|
-
'price' => '
|
199
|
+
'price' => '0.5'
|
190
200
|
}
|
191
201
|
}
|
192
202
|
|
@@ -25,7 +25,7 @@ module OandaApiV20
|
|
25
25
|
|
26
26
|
# GET /v3/accounts/:account_id/changes
|
27
27
|
def changes(options = {})
|
28
|
-
options = { 'sinceTransactionID' =>
|
28
|
+
options = { 'sinceTransactionID' => nil } unless options['sinceTransactionID']
|
29
29
|
Client.send(http_verb, "#{base_uri}/accounts/#{account_id}/changes", headers: headers, query: options)
|
30
30
|
end
|
31
31
|
|
data/lib/oanda_api_v20/api.rb
CHANGED
@@ -8,12 +8,89 @@ module OandaApiV20
|
|
8
8
|
include Transactions
|
9
9
|
include Pricing
|
10
10
|
|
11
|
-
attr_accessor :
|
11
|
+
attr_accessor :client, :base_uri, :headers, :account_id, :last_action, :last_arguments
|
12
|
+
attr_writer :instrument
|
12
13
|
|
13
14
|
def initialize(options = {})
|
14
15
|
options.each do |key, value|
|
15
16
|
self.send("#{key}=", value) if self.respond_to?("#{key}=")
|
16
17
|
end
|
18
|
+
|
19
|
+
raise OandaApiV20::ApiError, 'No client object was supplid.' unless client
|
20
|
+
@base_uri ||= client.base_uri
|
21
|
+
@headers ||= client.headers
|
22
|
+
end
|
23
|
+
|
24
|
+
class << self
|
25
|
+
def api_methods
|
26
|
+
Accounts.instance_methods + Instruments.instance_methods + Orders.instance_methods + Trades.instance_methods + Positions.instance_methods + Transactions.instance_methods + Pricing.instance_methods
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
self.api_methods.each do |method_name|
|
31
|
+
original_method = instance_method(method_name)
|
32
|
+
|
33
|
+
define_method(method_name) do |*args, &block|
|
34
|
+
# Add the block below before each of the api_methods to set the last_action and last_arguments.
|
35
|
+
# Return the OandaApiV20::Api object to allow for method chaining when any of the api_methods have been called.
|
36
|
+
# Only make an HTTP request to Oanda API When an action method like show, update, cancel, close or create was called.
|
37
|
+
set_last_action_and_arguments(method_name, *args)
|
38
|
+
return self unless http_verb
|
39
|
+
|
40
|
+
original_method.bind(self).call(*args, &block)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def method_missing(name, *args, &block)
|
45
|
+
case name
|
46
|
+
when :show, :create, :update, :cancel, :close
|
47
|
+
set_http_verb(name, last_action)
|
48
|
+
|
49
|
+
if respond_to?(last_action)
|
50
|
+
api_result = {}
|
51
|
+
client.update_last_api_request_at
|
52
|
+
client.govern_api_request_rate
|
53
|
+
|
54
|
+
begin
|
55
|
+
response = Http::Exceptions.wrap_and_check do
|
56
|
+
last_arguments.nil? || last_arguments.empty? ? send(last_action, &block) : send(last_action, *last_arguments, &block)
|
57
|
+
end
|
58
|
+
rescue Http::Exceptions::HttpException => e
|
59
|
+
raise OandaApiV20::RequestError, e.message
|
60
|
+
end
|
61
|
+
|
62
|
+
if response.body && !response.body.empty?
|
63
|
+
api_result.merge!(JSON.parse(response.body))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
self.http_verb = nil
|
68
|
+
api_result
|
69
|
+
else
|
70
|
+
super
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
attr_accessor :http_verb
|
77
|
+
|
78
|
+
def set_last_action_and_arguments(action, *args)
|
79
|
+
self.last_action = action.to_sym
|
80
|
+
self.last_arguments = args
|
81
|
+
end
|
82
|
+
|
83
|
+
def set_http_verb(action, last_action)
|
84
|
+
case action
|
85
|
+
when :show
|
86
|
+
self.http_verb = :get
|
87
|
+
when :update, :cancel, :close
|
88
|
+
[:configuration].include?(last_action) ? self.http_verb = :patch : self.http_verb = :put
|
89
|
+
when :create
|
90
|
+
self.http_verb = :post
|
91
|
+
else
|
92
|
+
self.http_verb = nil
|
93
|
+
end
|
17
94
|
end
|
18
95
|
end
|
19
96
|
end
|
data/lib/oanda_api_v20/client.rb
CHANGED
@@ -2,14 +2,12 @@ module OandaApiV20
|
|
2
2
|
class Client
|
3
3
|
include HTTParty
|
4
4
|
|
5
|
-
MAX_REQUESTS_PER_SECOND_ALLOWED = 30
|
6
|
-
|
7
5
|
BASE_URI = {
|
8
6
|
live: 'https://api-fxtrade.oanda.com/v3',
|
9
7
|
practice: 'https://api-fxpractice.oanda.com/v3'
|
10
8
|
}
|
11
9
|
|
12
|
-
attr_accessor :access_token, :proxy_url
|
10
|
+
attr_accessor :access_token, :proxy_url, :max_requests_per_second, :connection_pool_size, :debug
|
13
11
|
attr_reader :base_uri, :headers
|
14
12
|
|
15
13
|
def initialize(options = {})
|
@@ -17,11 +15,14 @@ module OandaApiV20
|
|
17
15
|
self.send("#{key}=", value) if self.respond_to?("#{key}=")
|
18
16
|
end
|
19
17
|
|
20
|
-
@
|
21
|
-
@
|
22
|
-
@
|
18
|
+
@mutex = Mutex.new
|
19
|
+
@debug ||= false
|
20
|
+
@connection_pool_size ||= 2
|
21
|
+
@max_requests_per_second ||= 100
|
22
|
+
@last_api_request_at = Array.new(max_requests_per_second)
|
23
|
+
@base_uri = options[:practice] == true ? BASE_URI[:practice] : BASE_URI[:live]
|
23
24
|
|
24
|
-
@headers
|
25
|
+
@headers = {}
|
25
26
|
@headers['Authorization'] = "Bearer #{access_token}"
|
26
27
|
@headers['X-Accept-Datetime-Format'] = 'RFC3339'
|
27
28
|
@headers['Content-Type'] = 'application/json'
|
@@ -35,113 +36,45 @@ module OandaApiV20
|
|
35
36
|
keep_alive: 30,
|
36
37
|
idle_timeout: 10,
|
37
38
|
warn_timeout: 2,
|
38
|
-
pool_size:
|
39
|
+
pool_size: connection_pool_size
|
39
40
|
}
|
40
|
-
|
41
|
+
|
42
|
+
persistent_connection_adapter_options.merge!(logger: ::Logger.new(STDOUT)) if debug
|
41
43
|
Client.persistent_connection_adapter(persistent_connection_adapter_options)
|
42
44
|
end
|
43
45
|
|
44
46
|
def method_missing(name, *args, &block)
|
45
47
|
case name
|
46
|
-
when
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
set_last_api_request_at
|
53
|
-
govern_api_request_rate
|
54
|
-
|
55
|
-
begin
|
56
|
-
response = Http::Exceptions.wrap_and_check do
|
57
|
-
last_arguments.nil? || last_arguments.empty? ? api.send(last_action, &block) : api.send(last_action, *last_arguments, &block)
|
58
|
-
end
|
59
|
-
rescue Http::Exceptions::HttpException => e
|
60
|
-
raise OandaApiV20::RequestError, e.message
|
61
|
-
end
|
48
|
+
when *Api.api_methods
|
49
|
+
api_attributes = {
|
50
|
+
client: self,
|
51
|
+
last_action: name,
|
52
|
+
last_arguments: args
|
53
|
+
}
|
62
54
|
|
63
|
-
|
64
|
-
|
65
|
-
set_last_transaction_id(api_result['lastTransactionID']) if api_result['lastTransactionID']
|
66
|
-
end
|
67
|
-
end
|
55
|
+
api_attributes.merge!(account_id: args.first) if name == :account
|
56
|
+
api_attributes.merge!(instrument: args.first) if name == :instrument
|
68
57
|
|
69
|
-
|
70
|
-
when *api_methods
|
71
|
-
set_last_action_and_arguments(name, args)
|
72
|
-
set_account_id(args.first) if name == :account
|
73
|
-
set_instrument(args.first) if name == :instrument
|
74
|
-
self
|
58
|
+
Api.new(api_attributes)
|
75
59
|
else
|
76
60
|
super
|
77
61
|
end
|
78
62
|
end
|
79
63
|
|
80
|
-
private
|
81
|
-
|
82
|
-
attr_accessor :http_verb, :account_id, :instrument, :last_transaction_id, :last_action, :last_arguments, :last_api_request_at
|
83
|
-
|
84
|
-
def api_methods
|
85
|
-
Accounts.instance_methods + Instruments.instance_methods + Orders.instance_methods + Trades.instance_methods + Positions.instance_methods + Transactions.instance_methods + Pricing.instance_methods
|
86
|
-
end
|
87
|
-
|
88
64
|
def govern_api_request_rate
|
89
65
|
return unless last_api_request_at[0]
|
90
|
-
halt = 1 - (last_api_request_at[
|
66
|
+
halt = 1 - (last_api_request_at[max_requests_per_second - 1] - last_api_request_at[0])
|
91
67
|
sleep halt if halt > 0
|
92
68
|
end
|
93
69
|
|
94
|
-
def
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
def set_last_action_and_arguments(action, args)
|
99
|
-
set_last_action(action)
|
100
|
-
set_last_arguments(args)
|
101
|
-
end
|
102
|
-
|
103
|
-
def set_last_action(action)
|
104
|
-
self.last_action = action
|
105
|
-
end
|
106
|
-
|
107
|
-
def set_last_arguments(args)
|
108
|
-
self.last_arguments = args.nil? || args.empty? ? nil : args.flatten
|
109
|
-
end
|
110
|
-
|
111
|
-
def set_account_id(id)
|
112
|
-
self.account_id = id
|
113
|
-
end
|
114
|
-
|
115
|
-
def set_instrument(instrument)
|
116
|
-
self.instrument = instrument
|
117
|
-
end
|
118
|
-
|
119
|
-
def set_last_transaction_id(id)
|
120
|
-
self.last_transaction_id = id
|
121
|
-
end
|
122
|
-
|
123
|
-
def set_http_verb(action, last_action)
|
124
|
-
case action
|
125
|
-
when :show
|
126
|
-
self.http_verb = :get
|
127
|
-
when :update, :cancel, :close
|
128
|
-
[:configuration].include?(last_action) ? self.http_verb = :patch : self.http_verb = :put
|
129
|
-
when :create
|
130
|
-
self.http_verb = :post
|
131
|
-
else
|
132
|
-
self.http_verb = nil
|
70
|
+
def update_last_api_request_at
|
71
|
+
@mutex.synchronize do
|
72
|
+
last_api_request_at.push(Time.now.utc).shift
|
133
73
|
end
|
134
74
|
end
|
135
75
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
base_uri: base_uri,
|
140
|
-
headers: headers,
|
141
|
-
account_id: account_id,
|
142
|
-
instrument: instrument,
|
143
|
-
last_transaction_id: last_transaction_id
|
144
|
-
}
|
145
|
-
end
|
76
|
+
private
|
77
|
+
|
78
|
+
attr_accessor :last_api_request_at
|
146
79
|
end
|
147
80
|
end
|
data/oanda_api_v20.gemspec
CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_development_dependency 'rspec', '~> 3.4'
|
24
24
|
s.add_development_dependency 'webmock', '~> 2.1'
|
25
25
|
s.add_development_dependency 'timecop', '~> 0.8'
|
26
|
-
s.add_development_dependency 'rake'
|
26
|
+
s.add_development_dependency 'rake', '~> 10.5'
|
27
27
|
|
28
28
|
s.files = `git ls-files`.split("\n")
|
29
29
|
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
@@ -2,326 +2,505 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe OandaApiV20::Api do
|
4
4
|
describe '#initialize' do
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
let!(:client) { OandaApiV20::Client.new(access_token: 'my_access_token') }
|
6
|
+
|
7
|
+
it 'sets the client attribute when supplied' do
|
8
|
+
api = OandaApiV20::Api.new(client: client)
|
9
|
+
expect(api.client).to eq(client)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'raises an OandaApiV20::ApiError exception when no client object was supplied' do
|
13
|
+
expect{ OandaApiV20::Api.new }.to raise_error(OandaApiV20::ApiError)
|
8
14
|
end
|
9
15
|
|
10
16
|
it 'sets the base_uri attribute when supplied' do
|
11
17
|
url = 'https://api-fxpractice.oanda.com/v3'
|
12
|
-
api = OandaApiV20::Api.new(base_uri: url)
|
18
|
+
api = OandaApiV20::Api.new(client: client, base_uri: url)
|
13
19
|
expect(api.base_uri).to eq(url)
|
14
20
|
end
|
15
21
|
|
22
|
+
it 'sets the default base_uri attribute when not supplied' do
|
23
|
+
api = OandaApiV20::Api.new(client: client)
|
24
|
+
expect(api.base_uri).to eq('https://api-fxtrade.oanda.com/v3')
|
25
|
+
end
|
26
|
+
|
16
27
|
it 'sets the headers attribute when supplied' do
|
17
28
|
headers = { 'Content-Type' => 'application/json', 'Connection' => 'keep-alive', 'Keep-Alive' => '30' }
|
18
|
-
api = OandaApiV20::Api.new(headers: headers)
|
29
|
+
api = OandaApiV20::Api.new(client: client, headers: headers)
|
19
30
|
expect(api.headers).to eq(headers)
|
20
31
|
end
|
21
32
|
|
33
|
+
it 'sets the default headers attribute when not supplied' do
|
34
|
+
api = OandaApiV20::Api.new(client: client)
|
35
|
+
expect(api.headers).to eq({ 'Authorization' => 'Bearer my_access_token', 'X-Accept-Datetime-Format' => 'RFC3339', 'Content-Type' => 'application/json' })
|
36
|
+
end
|
37
|
+
|
22
38
|
it 'sets the account_id attribute when supplied' do
|
23
39
|
account_id = '100-100-100'
|
24
|
-
api = OandaApiV20::Api.new(account_id: account_id)
|
40
|
+
api = OandaApiV20::Api.new(client: client, account_id: account_id)
|
25
41
|
expect(api.account_id).to eq(account_id)
|
26
42
|
end
|
27
43
|
|
28
|
-
it 'sets the
|
29
|
-
|
30
|
-
api = OandaApiV20::Api.new(
|
31
|
-
expect(api.
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
describe '#public_methods' do
|
36
|
-
let!(:api) { OandaApiV20::Api.new }
|
37
|
-
let(:public_methods) { [
|
38
|
-
:account, :accounts, :summary, :instruments, :changes, :configuration,
|
39
|
-
:order, :orders, :pending_orders,
|
40
|
-
:trade, :trades, :open_trades,
|
41
|
-
:position, :positions, :open_positions,
|
42
|
-
:transaction, :transactions, :transactions_id_range, :transactions_since_id,
|
43
|
-
:pricing
|
44
|
-
] }
|
45
|
-
|
46
|
-
it 'responds to all public methods' do
|
47
|
-
public_methods.each do |public_method|
|
48
|
-
expect(api.respond_to?(public_method)).to be_truthy
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
describe 'constructs the correct API URL under' do
|
54
|
-
let!(:api) { OandaApiV20::Api.new(base_uri: 'https://api-fxtrade.oanda.com/v3', account_id: '100-100-100', headers: {}) }
|
55
|
-
|
56
|
-
before(:each) do
|
57
|
-
stub_request(:any, /https:\/\/api-fxtrade\.oanda\.com\/v3.*/)
|
58
|
-
api.http_verb = :get
|
44
|
+
it 'sets the instrument variable when supplied' do
|
45
|
+
instrument = 'EUR_USD'
|
46
|
+
api = OandaApiV20::Api.new(client: client, instrument: instrument)
|
47
|
+
expect(api.instance_variable_get(:@instrument)).to eq(instrument)
|
59
48
|
end
|
60
49
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100')).to have_been_made.once
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'retrieving all accounts' do
|
68
|
-
api.accounts
|
69
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts')).to have_been_made.once
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'retrieving a summary' do
|
73
|
-
api.summary
|
74
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/summary')).to have_been_made.once
|
75
|
-
end
|
76
|
-
|
77
|
-
it 'retrieving all instruments' do
|
78
|
-
api.instruments
|
79
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/instruments')).to have_been_made.once
|
80
|
-
end
|
81
|
-
|
82
|
-
it 'retrieving an instrument' do
|
83
|
-
api.instruments('EUR_USD')
|
84
|
-
options = { 'instruments' => 'EUR_USD' }
|
85
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/instruments').with(query: options)).to have_been_made.once
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'retrieving all changes' do
|
89
|
-
api.last_transaction_id = '1'
|
90
|
-
api.changes
|
91
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/changes').with(query: { 'sinceTransactionID' => '1' })).to have_been_made.once
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'retrieving all changes since a transaction id' do
|
95
|
-
options = {
|
96
|
-
'sinceTransactionID' => '1'
|
97
|
-
}
|
98
|
-
api.changes(options)
|
99
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/changes').with(query: options)).to have_been_made.once
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'updating a configuration' do
|
103
|
-
api.http_verb = :patch
|
104
|
-
options = { 'alias' => 'Timmy!' }
|
105
|
-
api.configuration(options)
|
106
|
-
expect(a_request(:patch, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/configuration').with(body: options.to_json))
|
107
|
-
end
|
50
|
+
it 'sets the last_action when supplied' do
|
51
|
+
api = OandaApiV20::Api.new(client: client, last_action: 'accounts')
|
52
|
+
expect(api.last_action).to eq('accounts')
|
108
53
|
end
|
109
54
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
options = { 'count' => '10' }
|
115
|
-
api.candles(options)
|
116
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/instruments/EUR_USD/candles').with(query: options)).to have_been_made.once
|
117
|
-
end
|
55
|
+
it 'sets the last_arguments when supplied' do
|
56
|
+
api = OandaApiV20::Api.new(client: client, last_action: 'account', last_arguments: ['100-100-100'])
|
57
|
+
expect(api.last_action).to eq('account')
|
58
|
+
expect(api.last_arguments).to eq(['100-100-100'])
|
118
59
|
end
|
60
|
+
end
|
119
61
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
62
|
+
describe '#method_missing' do
|
63
|
+
describe 'constructs the correct API URL under' do
|
64
|
+
let!(:client) { OandaApiV20::Client.new(access_token: 'my_access_token', base_uri: 'https://api-fxtrade.oanda.com/v3', headers: {}) }
|
65
|
+
let!(:api) { OandaApiV20::Api.new(client: client, account_id: '100-100-100') }
|
66
|
+
|
67
|
+
before(:each) do
|
68
|
+
stub_request(:get, /https:\/\/api-fxtrade\.oanda\.com\/v3.*/)
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'accounts for' do
|
72
|
+
it 'retrieving an account' do
|
73
|
+
api.account('100-100-100').show
|
74
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100')).to have_been_made.once
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'retrieving all accounts' do
|
78
|
+
api.accounts.show
|
79
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts')).to have_been_made.once
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'retrieving a summary' do
|
83
|
+
api.summary.show
|
84
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/summary')).to have_been_made.once
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'retrieving all instruments' do
|
88
|
+
api.instruments.show
|
89
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/instruments')).to have_been_made.once
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'retrieving an instrument' do
|
93
|
+
api.instruments('EUR_USD').show
|
94
|
+
options = { 'instruments' => 'EUR_USD' }
|
95
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/instruments').with(query: options)).to have_been_made.once
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'retrieving no changes' do
|
99
|
+
options = {}
|
100
|
+
api.changes(options).show
|
101
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/changes').with(query: { 'sinceTransactionID' => '' })).to have_been_made.once
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'retrieving all changes since a transaction ID' do
|
105
|
+
options = { 'sinceTransactionID' => '1' }
|
106
|
+
api.changes(options).show
|
107
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/changes').with(query: options)).to have_been_made.once
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'updating a configuration' do
|
111
|
+
options = { 'alias' => 'Timmy!' }
|
112
|
+
request = stub_request(:patch, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/configuration').with(body: options)
|
113
|
+
api.configuration(options).update
|
114
|
+
expect(request).to have_been_requested.once
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'instruments for' do
|
119
|
+
let!(:api) { OandaApiV20::Api.new(client: client, account_id: '100-100-100', instrument: 'EUR_USD') }
|
120
|
+
|
121
|
+
it 'retrieving candlestick data' do
|
122
|
+
options = { 'count' => '10' }
|
123
|
+
api.candles(options).show
|
124
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/instruments/EUR_USD/candles').with(query: options)).to have_been_made.once
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'orders for' do
|
129
|
+
it 'retrieving an order' do
|
130
|
+
api.order('1').show
|
131
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/orders/1')).to have_been_made.once
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'creating an order' do
|
135
|
+
options = {
|
136
|
+
'order' => {
|
137
|
+
'units' => '100',
|
138
|
+
'instrument' => 'EUR_CAD',
|
139
|
+
'timeInForce' => 'FOK',
|
140
|
+
'type' => 'MARKET',
|
141
|
+
'positionFill' => 'DEFAULT'
|
142
|
+
}
|
135
143
|
}
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
144
|
+
request = stub_request(:post, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/orders').with(body: options)
|
145
|
+
api.order(options).create
|
146
|
+
expect(request).to have_been_requested.once
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'updating an order' do
|
150
|
+
options = {
|
151
|
+
'order' => {
|
152
|
+
'timeInForce' => 'GTC',
|
153
|
+
'price' => '1.7000',
|
154
|
+
'type' => 'TAKE_PROFIT',
|
155
|
+
'tradeID' => '1'
|
156
|
+
}
|
157
|
+
}
|
158
|
+
request = stub_request(:put, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/orders/1').with(body: options)
|
159
|
+
api.order('1', options).update
|
160
|
+
expect(request).to have_been_requested.once
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'updating an order client extensions' do
|
164
|
+
options = {
|
165
|
+
'clientExtensions' => {
|
166
|
+
'comment' => 'New comment for my limit order'
|
167
|
+
}
|
168
|
+
}
|
169
|
+
request = stub_request(:put, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/orders/1/clientExtensions').with(body: options)
|
170
|
+
api.order('1', options).update
|
171
|
+
expect(request).to have_been_requested.once
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'cancelling an order' do
|
175
|
+
request = stub_request(:put,'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/orders/1/cancel')
|
176
|
+
api.order('1').cancel
|
177
|
+
expect(request).to have_been_requested.once
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'retrieving all orders' do
|
181
|
+
api.orders.show
|
182
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/orders')).to have_been_made.once
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'retrieving all orders' do
|
186
|
+
options = { 'instrument' => 'USD_CAD' }
|
187
|
+
api.orders(options).show
|
188
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/orders').with(query: options)).to have_been_made.once
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'retrieving all pending orders' do
|
192
|
+
api.pending_orders.show
|
193
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/pendingOrders')).to have_been_made.once
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
context 'trades for' do
|
198
|
+
it 'retrieving a trade' do
|
199
|
+
api.trade('1').show
|
200
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/trades/1')).to have_been_made.once
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'updating a trade' do
|
204
|
+
options = {
|
205
|
+
'takeProfit' => {
|
206
|
+
'timeInForce' => 'GTC',
|
207
|
+
'price' => '0.5'
|
208
|
+
},
|
209
|
+
'stopLoss' => {
|
210
|
+
'timeInForce' => 'GTC',
|
211
|
+
'price' => '2.5'
|
212
|
+
}
|
213
|
+
}
|
214
|
+
request = stub_request(:put, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/trades/1/orders').with(body: options)
|
215
|
+
api.trade('1', options).update
|
216
|
+
expect(request).to have_been_requested.once
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'updating a trade client extensions' do
|
220
|
+
options = {
|
221
|
+
'clientExtensions' => {
|
222
|
+
'comment' => 'This is a USD/CAD trade',
|
223
|
+
'tag' => 'trade tag',
|
224
|
+
'id' => 'my_usd_cad_trade'
|
225
|
+
}
|
226
|
+
}
|
227
|
+
request = stub_request(:put, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/trades/1/clientExtensions').with(body: options)
|
228
|
+
api.trade('1', options).update
|
229
|
+
expect(request).to have_been_requested.once
|
230
|
+
end
|
231
|
+
|
232
|
+
it 'closing a trade' do
|
233
|
+
request = stub_request(:put, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/trades/1/close')
|
234
|
+
api.trade('1').close
|
235
|
+
expect(request).to have_been_requested.once
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'closing a trade partially' do
|
239
|
+
options = { 'units' => '10' }
|
240
|
+
request = stub_request(:put, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/trades/1/close')
|
241
|
+
api.trade('1', options).close
|
242
|
+
expect(request).to have_been_requested.once
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'retrieving all trades' do
|
246
|
+
options = { 'instrument' => 'USD_CAD' }
|
247
|
+
api.trades(options).show
|
248
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/trades').with(query: options)).to have_been_made.once
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'retrieving all open trades' do
|
252
|
+
api.open_trades.show
|
253
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/openTrades')).to have_been_made.once
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
context 'positions for' do
|
258
|
+
it 'retrieving a position' do
|
259
|
+
api.position('EUR_USD').show
|
260
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/positions/EUR_USD')).to have_been_made.once
|
261
|
+
end
|
262
|
+
|
263
|
+
it 'retrieving all positions' do
|
264
|
+
api.positions.show
|
265
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/positions')).to have_been_made.once
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'retrieving all open positions' do
|
269
|
+
api.open_positions.show
|
270
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/openPositions')).to have_been_made.once
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'closing a position' do
|
274
|
+
options = { 'longUnits' => 'ALL' }
|
275
|
+
request = stub_request(:put, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/positions/EUR_CAD/close').with(body: options)
|
276
|
+
api.position('EUR_CAD', options).close
|
277
|
+
expect(request).to have_been_requested.once
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'closing a position partially' do
|
281
|
+
options = { 'longUnits' => '99' }
|
282
|
+
request = stub_request(:put, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/positions/EUR_CAD/close').with(body: options)
|
283
|
+
api.position('EUR_CAD', options).close
|
284
|
+
expect(request).to have_been_requested.once
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
context 'transactions for' do
|
289
|
+
it 'retrieving a transaction' do
|
290
|
+
api.transaction('1').show
|
291
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/transactions/1')).to have_been_made.once
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'retrieving all transactions' do
|
295
|
+
api.transactions.show
|
296
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/transactions')).to have_been_made.once
|
297
|
+
end
|
298
|
+
|
299
|
+
it 'retrieving all transactions in date range' do
|
300
|
+
options = {
|
301
|
+
'from' => '2016-08-01T02:00:00Z',
|
302
|
+
'to' => '2016-08-15T02:00:00Z'
|
303
|
+
}
|
304
|
+
api.transactions(options).show
|
305
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/transactions').with(query: options)).to have_been_made.once
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'retrieving all transactions in an ID range' do
|
309
|
+
options = {
|
310
|
+
'from' => '6409',
|
311
|
+
'to' => '6412'
|
312
|
+
}
|
313
|
+
api.transactions_id_range(options).show
|
314
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/transactions/idrange').with(query: options)).to have_been_made.once
|
315
|
+
end
|
140
316
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
'order' => {
|
145
|
-
'timeInForce' => 'GTC',
|
146
|
-
'price' => '1.7000',
|
147
|
-
'type' => 'TAKE_PROFIT',
|
148
|
-
'tradeID' => '1'
|
317
|
+
it 'retrieving all transactions since an ID' do
|
318
|
+
options = {
|
319
|
+
'id' => '6411'
|
149
320
|
}
|
150
|
-
|
151
|
-
|
152
|
-
|
321
|
+
api.transactions_since_id(options).show
|
322
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/transactions/sinceid').with(query: options)).to have_been_made.once
|
323
|
+
end
|
153
324
|
end
|
154
325
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
'comment' => 'New comment for my limit order'
|
326
|
+
context 'pricing for' do
|
327
|
+
it 'retrieving all pricing' do
|
328
|
+
options = {
|
329
|
+
'instruments' => 'EUR_USD,USD_CAD'
|
160
330
|
}
|
161
|
-
|
162
|
-
|
163
|
-
|
331
|
+
api.pricing(options).show
|
332
|
+
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/pricing').with(query: options)).to have_been_made.once
|
333
|
+
end
|
164
334
|
end
|
335
|
+
end
|
165
336
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
expect(a_request(:put, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/orders/1/cancel')).to have_been_made.once
|
170
|
-
end
|
337
|
+
describe 'network' do
|
338
|
+
let!(:client) { OandaApiV20::Client.new(access_token: 'my_access_token', base_uri: 'https://api-fxtrade.oanda.com/v3', headers: {}) }
|
339
|
+
let!(:api) { OandaApiV20::Api.new(client: client) }
|
171
340
|
|
172
|
-
|
173
|
-
|
174
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/orders')).to have_been_made.once
|
175
|
-
end
|
341
|
+
let(:response_account) { '{"account":{"id":"100-100-100","NAV":"100000.0000","balance":"100000.0000","lastTransactionID":"99","orders":[],"positions":[],"trades":[],"pendingOrderCount":0},"lastTransactionID":"99"}' }
|
342
|
+
let!(:request_account) { stub_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100').to_return(status: 200, body: response_account, headers: {}) }
|
176
343
|
|
177
|
-
|
178
|
-
|
179
|
-
api.orders(options)
|
180
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/orders').with(query: options)).to have_been_made.once
|
181
|
-
end
|
344
|
+
let(:response_accounts) { '{"accounts":[{"id":"100-100-100","tags":[]}]}' }
|
345
|
+
let!(:request_accounts) { stub_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts').to_return(status: 200, body: response_accounts, headers: {}) }
|
182
346
|
|
183
|
-
it '
|
184
|
-
api.
|
185
|
-
expect(
|
347
|
+
it 'makes a request to Oanda API' do
|
348
|
+
api.accounts.show
|
349
|
+
expect(request_accounts).to have_been_requested
|
350
|
+
expect(request_accounts).to have_been_requested.at_most_once
|
186
351
|
end
|
187
|
-
end
|
188
352
|
|
189
|
-
|
190
|
-
|
191
|
-
api.
|
192
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/trades/1')).to have_been_made.once
|
353
|
+
it 'returns the response from Oanda API' do
|
354
|
+
expect(api.accounts.show).to eq(JSON.parse(response_accounts))
|
355
|
+
expect(api.account('100-100-100').show).to eq(JSON.parse(response_account))
|
193
356
|
end
|
357
|
+
end
|
194
358
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
359
|
+
describe 'sets the correct HTTP verb' do
|
360
|
+
let!(:client) { OandaApiV20::Client.new(access_token: 'my_access_token', base_uri: 'https://api-fxtrade.oanda.com/v3', headers: {}) }
|
361
|
+
let!(:api) { OandaApiV20::Api.new(client: client, account_id: '100-100-100') }
|
362
|
+
|
363
|
+
context 'for GET' do
|
364
|
+
let!(:request) { stub_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts') }
|
365
|
+
|
366
|
+
it 'uses the correct HTTP verb' do
|
367
|
+
api.accounts.show
|
368
|
+
expect(request).to have_been_requested.once
|
369
|
+
end
|
370
|
+
|
371
|
+
it 'clears the HTTP verb attribute after use' do
|
372
|
+
api.accounts.show
|
373
|
+
expect(api.send(:http_verb)).to be_nil
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
context 'for POST' do
|
378
|
+
let!(:options) {
|
379
|
+
{
|
380
|
+
'order' => {
|
381
|
+
'units' => '100',
|
382
|
+
'instrument' => 'EUR_CAD',
|
383
|
+
'timeInForce' => 'FOK',
|
384
|
+
'type' => 'MARKET',
|
385
|
+
'positionFill' => 'DEFAULT'
|
386
|
+
}
|
205
387
|
}
|
206
388
|
}
|
207
|
-
api.
|
208
|
-
expect(a_request(:put, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/trades/1/orders').with(body: options.to_json)).to have_been_made.once
|
209
|
-
end
|
389
|
+
let!(:request) { stub_request(:post, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/orders').with(body: options) }
|
210
390
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
'comment' => 'This is a USD/CAD trade',
|
216
|
-
'tag' => 'trade tag',
|
217
|
-
'id' => 'my_usd_cad_trade'
|
218
|
-
}
|
219
|
-
}
|
220
|
-
api.trade('1', options)
|
221
|
-
expect(a_request(:put, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/trades/1/clientExtensions').with(body: options.to_json)).to have_been_made.once
|
222
|
-
end
|
391
|
+
it 'uses the correct HTTP verb' do
|
392
|
+
api.order(options).create
|
393
|
+
expect(request).to have_been_requested.once
|
394
|
+
end
|
223
395
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
396
|
+
it 'clears the HTTP verb attribute after use' do
|
397
|
+
api.order(options).create
|
398
|
+
expect(api.send(:http_verb)).to be_nil
|
399
|
+
end
|
228
400
|
end
|
229
401
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
api.trade('1', options)
|
234
|
-
expect(a_request(:put, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/trades/1/close')).to have_been_made.once
|
235
|
-
end
|
402
|
+
context 'for PATCH' do
|
403
|
+
let!(:options) { { 'alias' => 'Timmy!' } }
|
404
|
+
let!(:request) { stub_request(:patch, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/configuration').with(body: options) }
|
236
405
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
end
|
406
|
+
it 'uses the correct HTTP verb' do
|
407
|
+
api.configuration(options).update
|
408
|
+
expect(request).to have_been_requested.once
|
409
|
+
end
|
242
410
|
|
243
|
-
|
244
|
-
|
245
|
-
|
411
|
+
it 'clears the HTTP verb attribute after use' do
|
412
|
+
api.configuration(options).update
|
413
|
+
expect(api.send(:http_verb)).to be_nil
|
414
|
+
end
|
246
415
|
end
|
247
416
|
end
|
417
|
+
end
|
248
418
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
api.open_positions
|
262
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/openPositions')).to have_been_made.once
|
263
|
-
end
|
264
|
-
|
265
|
-
it 'closing a position' do
|
266
|
-
api.http_verb = :put
|
267
|
-
options = { 'longUnits' => 'ALL' }
|
268
|
-
api.position('EUR_CAD', options)
|
269
|
-
expect(a_request(:put, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/positions/EUR_CAD/close').with(body: options.to_json)).to have_been_made.once
|
270
|
-
end
|
419
|
+
describe 'public methods' do
|
420
|
+
let!(:client) { OandaApiV20::Client.new(access_token: 'my_access_token') }
|
421
|
+
let!(:api) { OandaApiV20::Api.new(client: client) }
|
422
|
+
let(:public_methods) { [
|
423
|
+
:account, :accounts, :summary, :instruments, :changes, :configuration,
|
424
|
+
:order, :orders, :pending_orders,
|
425
|
+
:trade, :trades, :open_trades,
|
426
|
+
:position, :positions, :open_positions,
|
427
|
+
:transaction, :transactions, :transactions_id_range, :transactions_since_id,
|
428
|
+
:pricing,
|
429
|
+
:candles
|
430
|
+
] }
|
271
431
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
api.position('EUR_CAD', options)
|
276
|
-
expect(a_request(:put, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/positions/EUR_CAD/close').with(body: options.to_json)).to have_been_made.once
|
432
|
+
it 'responds to all public methods' do
|
433
|
+
public_methods.each do |public_method|
|
434
|
+
expect(api.respond_to?(public_method)).to be_truthy
|
277
435
|
end
|
278
436
|
end
|
279
437
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/transactions/1')).to have_been_made.once
|
284
|
-
end
|
438
|
+
it 'returns an OandaApiV20::Api instance when calling any of the public methods' do
|
439
|
+
expect(api.accounts).to be_an_instance_of(OandaApiV20::Api)
|
440
|
+
end
|
285
441
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
442
|
+
it 'makes a request to Oanda API when calling any of the action methods' do
|
443
|
+
request = stub_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts')
|
444
|
+
api.accounts.show
|
445
|
+
expect(request).to have_been_requested.once
|
446
|
+
end
|
447
|
+
end
|
290
448
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
449
|
+
describe 'private methods' do
|
450
|
+
describe '#set_http_verb' do
|
451
|
+
let!(:client) { OandaApiV20::Client.new(access_token: 'my_access_token', base_uri: 'https://api-fxtrade.oanda.com/v3', headers: {}) }
|
452
|
+
let!(:api) { OandaApiV20::Api.new(client: client) }
|
453
|
+
|
454
|
+
describe 'sets the correct HTTP verb' do
|
455
|
+
it 'for GET' do
|
456
|
+
api.send(:set_http_verb, :show, nil)
|
457
|
+
expect(api.send(:http_verb)).to eq(:get)
|
458
|
+
end
|
459
|
+
|
460
|
+
it 'for POST' do
|
461
|
+
api.send(:set_http_verb, :create, nil)
|
462
|
+
expect(api.send(:http_verb)).to eq(:post)
|
463
|
+
end
|
464
|
+
|
465
|
+
it 'for PUT' do
|
466
|
+
api.send(:set_http_verb, :update, nil)
|
467
|
+
expect(api.send(:http_verb)).to eq(:put)
|
468
|
+
end
|
469
|
+
|
470
|
+
it 'for PUT' do
|
471
|
+
api.send(:set_http_verb, :cancel, nil)
|
472
|
+
expect(api.send(:http_verb)).to eq(:put)
|
473
|
+
end
|
474
|
+
|
475
|
+
it 'for PUT' do
|
476
|
+
api.send(:set_http_verb, :close, nil)
|
477
|
+
expect(api.send(:http_verb)).to eq(:put)
|
478
|
+
end
|
479
|
+
|
480
|
+
it 'for PATCH' do
|
481
|
+
api.send(:set_http_verb, :update, :configuration)
|
482
|
+
expect(api.send(:http_verb)).to eq(:patch)
|
483
|
+
end
|
484
|
+
|
485
|
+
it 'for POST' do
|
486
|
+
api.send(:set_http_verb, :create, nil)
|
487
|
+
expect(api.send(:http_verb)).to eq(:post)
|
488
|
+
end
|
298
489
|
end
|
490
|
+
end
|
299
491
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
'to' => '6412'
|
304
|
-
}
|
305
|
-
api.transactions_id_range(options)
|
306
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/transactions/idrange').with(query: options)).to have_been_made.once
|
307
|
-
end
|
492
|
+
describe '#set_last_action_and_arguments' do
|
493
|
+
let!(:client) { OandaApiV20::Client.new(access_token: 'my_access_token', base_uri: 'https://api-fxtrade.oanda.com/v3', headers: {}) }
|
494
|
+
let!(:api) { OandaApiV20::Api.new(client: client) }
|
308
495
|
|
309
|
-
it '
|
310
|
-
|
311
|
-
|
312
|
-
}
|
313
|
-
api.transactions_since_id(options)
|
314
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/transactions/sinceid').with(query: options)).to have_been_made.once
|
496
|
+
it 'sets the last_action attribute' do
|
497
|
+
api.send(:set_last_action_and_arguments, :accounts)
|
498
|
+
expect(api.send(:last_action)).to eq(:accounts)
|
315
499
|
end
|
316
|
-
end
|
317
500
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
'instruments' => 'EUR_USD,USD_CAD'
|
322
|
-
}
|
323
|
-
api.pricing(options)
|
324
|
-
expect(a_request(:get, 'https://api-fxtrade.oanda.com/v3/accounts/100-100-100/pricing').with(query: options)).to have_been_made.once
|
501
|
+
it 'sets the last_arguments attribute' do
|
502
|
+
api.send(:set_last_action_and_arguments, :account, '100-100-100')
|
503
|
+
expect(api.send(:last_arguments)).to eq(['100-100-100'])
|
325
504
|
end
|
326
505
|
end
|
327
506
|
end
|