oanda_api 0.9.3 → 0.9.4

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: a80562ee64a74c0c4ea6b5ef112ca9c94de2693a
4
- data.tar.gz: d1f343f2f83e5a157b982bf7f99eaba8b8bfd070
3
+ metadata.gz: 6bde10bb61208fec6faf667058293783ffdf6e2c
4
+ data.tar.gz: 928603f30cf2a1170b8d5ef8091d8ce4fa6222da
5
5
  SHA512:
6
- metadata.gz: 60a73b0a93284b5a2d7444e01c95e486ed4cecd16657c85a3840dce2557f850a7e1d9137999996c8dd899a94f36938148bbbf0456b8c2e0ff75d0bc3a53195c2
7
- data.tar.gz: a761bd94438f861a3da1b2546d361df47cef008d93cb025e2bffc947aa448e391985aac6b094e45769ba577830086ce4f555d3b8760adcd34062a2edc1d208fa
6
+ metadata.gz: dc10bcbe935f95419b769296860c3069d1b77f62e35a9727b53d8c01c595509ebec739d3ff1fe11800b031441317ca9449fd750742437b23d7222289c033661d
7
+ data.tar.gz: c4351ef875a10f099bc2da0bcc7a80ca9d47fbc7f0aa5888c420e10210ae762130933dac3f446624d33219ffe49062ddf9bd2b6eddd17629b4bc4ff9d1147861
data/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.9.4
4
+
5
+ * Added multi-threaded support for request throttling. Now if you've configured the API to use request throttling:
6
+
7
+ ```ruby
8
+ OandaAPI.configure do |config|
9
+ config.use_request_throttling = true
10
+ config.max_requests_per_second = 15
11
+ end
12
+ ```
13
+ and if you access a single instance of the API from multiple threads, then the request rate will be throttled correctly.
14
+
15
+ * Added a new configuration to customize the number of connections the API holds in the connection pool. Useful if your application requires multiple connections to the API, for example multiple threads issuing requests through the API. The default connection pool size is 2.
16
+
17
+ ```ruby
18
+ OandaAPI.configure do |config|
19
+ config.connection_pool_size = 5
20
+ end
21
+ ```
22
+ Thanks [Eric](https://github.com/lifeBCE).
23
+
3
24
  ## 0.9.3
4
25
 
5
26
  * Fixed support for retrieving [full account history](http://developer.oanda.com/rest-live/transaction-history/#getFullAccountHistory). Thanks [bewon](https://github.com/bewon).
data/README.md CHANGED
@@ -152,7 +152,7 @@ for detailed documentation and API usage notes.
152
152
  | client.accounts.get | GET /v1/accounts |
153
153
  | client.account(123).get | GET /v1/accounts/123 |
154
154
  | client.account.create | POST /v1/accounts |
155
- | client.instruments.get | GET /v1/instruments |
155
+ | client.instruments(account_id: 123).get | GET /v1/instruments?accountId=123 |
156
156
  | client.prices(instruments: ["EUR_USD","USD_JPY"]).get | GET /v1/prices/?instruments=EUR_USD%2CUSD_JPY |
157
157
  | client.account(123).orders.get | GET /v1/accounts/123/orders |
158
158
  | client.account(123).order(123).get | GET /v1/accounts/123/orders/123 |
@@ -14,9 +14,9 @@ module OandaAPI
14
14
  # - Uses request rate limiting if enabled (see {Configuration#use_request_throttling}).
15
15
  module Client
16
16
  include HTTParty
17
- persistent_connection_adapter idle_timeout: 10,
18
- keep_alive: 30,
19
- pool_size: 2
17
+
18
+ # Used to synchronize throttling metrics
19
+ @throttle_mutex = Mutex.new
20
20
 
21
21
  # Use a custom JSON parser
22
22
  parser OandaAPI::Client::JsonParser
@@ -46,6 +46,16 @@ module OandaAPI
46
46
  end.flatten.join("&")
47
47
  }
48
48
 
49
+ # Common initializations
50
+ # @param [Hash] options Specifies overrides to default settings.
51
+ # Overrides for the persistent connection adapter are specified
52
+ # by including an :connection_adapter_options: {} hash.
53
+ # @return [OandaAPI::Client]
54
+ def initialize(options={})
55
+ super()
56
+ load_persistent_connection_adapter options[:connection_adapter_options] || {}
57
+ end
58
+
49
59
  # Returns an absolute URI for a resource request.
50
60
  #
51
61
  # @param [String] path the path portion of the URI.
@@ -56,6 +66,23 @@ module OandaAPI
56
66
  uri.sub "[API_VERSION]", OandaAPI.configuration.rest_api_version
57
67
  end
58
68
 
69
+ # Binds a persistent connection adapter. See documentation for the
70
+ # persistent_httparty gem for configuration details.
71
+ # @param [Hash] options Specifies overrides for the connection adapter.
72
+ #
73
+ # @return [void]
74
+ def load_persistent_connection_adapter(options={})
75
+ adapter_config = {
76
+ name: "oanda_api",
77
+ idle_timeout: 10,
78
+ keep_alive: 30,
79
+ warn_timeout: 2,
80
+ pool_size: OandaAPI.configuration.connection_pool_size,
81
+ }.merge options
82
+
83
+ Client.persistent_connection_adapter adapter_config
84
+ end
85
+
59
86
  # @private
60
87
  # Executes an http request.
61
88
  #
@@ -112,6 +139,14 @@ module OandaAPI
112
139
  end
113
140
  end
114
141
 
142
+ def self.last_request_at
143
+ @throttle_mutex.synchronize { @last_request_at }
144
+ end
145
+
146
+ def self.last_request_at=(value)
147
+ @throttle_mutex.synchronize { @last_request_at = value }
148
+ end
149
+
115
150
  # @private
116
151
  # Limits the execution rate of consecutive requests. Specified by
117
152
  # {OandaAPI::Configuration#max_requests_per_second}. Only enforced
@@ -120,11 +155,10 @@ module OandaAPI
120
155
  # @return [void]
121
156
  def self.throttle_request_rate
122
157
  now = Time.now
123
- Thread.current[:oanda_api_last_request_at] ||= now
124
- delta = now - Thread.current[:oanda_api_last_request_at]
125
- _throttle(now) if delta < OandaAPI.configuration.min_request_interval &&
126
- OandaAPI.configuration.use_request_throttling?
127
- Thread.current[:oanda_api_last_request_at] = Time.now
158
+ delta = now - (last_request_at || now)
159
+ _throttle(delta, now) if delta < OandaAPI.configuration.min_request_interval &&
160
+ OandaAPI.configuration.use_request_throttling?
161
+ last_request_at = Time.now
128
162
  end
129
163
 
130
164
  # @private
@@ -135,7 +169,7 @@ module OandaAPI
135
169
  #
136
170
  # @return [nil] if a request has never been throttled.
137
171
  def self.last_throttled_at
138
- Thread.current[:oanda_api_throttled_at]
172
+ @throttle_mutex.synchronize { @throttled_at }
139
173
  end
140
174
 
141
175
  private
@@ -144,12 +178,15 @@ module OandaAPI
144
178
  # Sleeps for the minimal amount of time required to honour the
145
179
  # {OandaAPI::Configuration#max_requests_per_second} limit.
146
180
  #
181
+ # @param [Float] delta The duration in seconds since the last request.
147
182
  # @param [Time] time The time that the throttle was requested.
148
183
  #
149
184
  # @return [void]
150
- def self._throttle(time)
151
- Thread.current[:oanda_api_throttled_at] = time
152
- sleep OandaAPI.configuration.min_request_interval
185
+ def self._throttle(delta, time)
186
+ @throttle_mutex.synchronize do
187
+ @throttled_at = time
188
+ sleep OandaAPI.configuration.min_request_interval - delta
189
+ end
153
190
  end
154
191
 
155
192
  # @private
@@ -42,8 +42,8 @@ module OandaAPI
42
42
 
43
43
  # @param [Symbol] domain see {#domain}
44
44
  # @param [String] auth_token see {#auth_token}
45
- def initialize(domain, auth_token)
46
- super()
45
+ def initialize(domain, auth_token, options={})
46
+ super options
47
47
  @auth_token = auth_token
48
48
  @default_params = {}
49
49
  self.domain = domain
@@ -35,8 +35,8 @@ module OandaAPI
35
35
  attr_accessor :default_params, :headers
36
36
 
37
37
  # @param [String] username used for authentication.
38
- def initialize(username)
39
- super()
38
+ def initialize(username, options={})
39
+ super options
40
40
  @domain = :sandbox
41
41
  @username = username
42
42
  @default_params = auth
@@ -10,6 +10,20 @@ module OandaAPI
10
10
  REST_API_VERSION = "v1"
11
11
  USE_COMPRESSION = false
12
12
  USE_REQUEST_THROTTLING = false
13
+ CONNECTION_POOL_SIZE = 2
14
+
15
+ # Maximum size of the persistent connection pool.
16
+ # @return [Numeric]
17
+ def connection_pool_size
18
+ @connection_pool_size ||= CONNECTION_POOL_SIZE
19
+ end
20
+
21
+ # Define the maximum size of the persistent connection pool.
22
+ # @return [Numeric]
23
+ def connection_pool_size=(value)
24
+ fail ArgumentError, "must be a number > 0" unless value.is_a?(Numeric) && value > 0
25
+ @connection_pool_size = value
26
+ end
13
27
 
14
28
  # The format in which dates will be returned by the API (`:rfc3339` or `:unix`).
15
29
  # See the Oanda Development Guide for more details about {http://developer.oanda.com/rest-live/development-guide/#date_Time_Format DateTime formats}.
@@ -1,3 +1,3 @@
1
1
  module OandaAPI
2
- VERSION = "0.9.3"
2
+ VERSION = "0.9.4"
3
3
  end
@@ -0,0 +1,114 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ X-Accept-Datetime-Format:
11
+ - RFC3339
12
+ Connection:
13
+ - keep-alive
14
+ Keep-Alive:
15
+ - 30
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Server:
22
+ - openresty/1.7.0.1
23
+ Date:
24
+ - Fri, 11 Sep 2015 21:15:45 GMT
25
+ Content-Type:
26
+ - application/json
27
+ Content-Length:
28
+ - '139'
29
+ Connection:
30
+ - keep-alive
31
+ Etag:
32
+ - '"2e14fb3070bd124e44c7a146923c9e0cb08d7969"'
33
+ body:
34
+ encoding: UTF-8
35
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
36
+ : \"2015-09-11T21:15:23.859054Z\",\n\t\t\t\"bid\" : 1.24095,\n\t\t\t\"ask\"
37
+ : 1.24109\n\t\t}\n\t]\n}"
38
+ http_version:
39
+ recorded_at: Fri, 11 Sep 2015 21:15:45 GMT
40
+ - request:
41
+ method: get
42
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
43
+ body:
44
+ encoding: US-ASCII
45
+ string: ''
46
+ headers:
47
+ X-Accept-Datetime-Format:
48
+ - RFC3339
49
+ Connection:
50
+ - keep-alive
51
+ Keep-Alive:
52
+ - 30
53
+ response:
54
+ status:
55
+ code: 200
56
+ message: OK
57
+ headers:
58
+ Server:
59
+ - openresty/1.7.0.1
60
+ Date:
61
+ - Fri, 11 Sep 2015 21:15:46 GMT
62
+ Content-Type:
63
+ - application/json
64
+ Content-Length:
65
+ - '139'
66
+ Connection:
67
+ - keep-alive
68
+ Etag:
69
+ - '"2e14fb3070bd124e44c7a146923c9e0cb08d7969"'
70
+ body:
71
+ encoding: UTF-8
72
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
73
+ : \"2015-09-11T21:15:23.859054Z\",\n\t\t\t\"bid\" : 1.24095,\n\t\t\t\"ask\"
74
+ : 1.24109\n\t\t}\n\t]\n}"
75
+ http_version:
76
+ recorded_at: Fri, 11 Sep 2015 21:15:46 GMT
77
+ - request:
78
+ method: get
79
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
80
+ body:
81
+ encoding: US-ASCII
82
+ string: ''
83
+ headers:
84
+ X-Accept-Datetime-Format:
85
+ - RFC3339
86
+ Connection:
87
+ - keep-alive
88
+ Keep-Alive:
89
+ - 30
90
+ response:
91
+ status:
92
+ code: 200
93
+ message: OK
94
+ headers:
95
+ Server:
96
+ - openresty/1.7.0.1
97
+ Date:
98
+ - Fri, 11 Sep 2015 21:15:46 GMT
99
+ Content-Type:
100
+ - application/json
101
+ Content-Length:
102
+ - '139'
103
+ Connection:
104
+ - keep-alive
105
+ Etag:
106
+ - '"2e14fb3070bd124e44c7a146923c9e0cb08d7969"'
107
+ body:
108
+ encoding: UTF-8
109
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
110
+ : \"2015-09-11T21:15:23.859054Z\",\n\t\t\t\"bid\" : 1.24095,\n\t\t\t\"ask\"
111
+ : 1.24109\n\t\t}\n\t]\n}"
112
+ http_version:
113
+ recorded_at: Fri, 11 Sep 2015 21:15:46 GMT
114
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,225 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ X-Accept-Datetime-Format:
11
+ - RFC3339
12
+ Connection:
13
+ - keep-alive
14
+ Keep-Alive:
15
+ - 30
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Server:
22
+ - openresty/1.7.0.1
23
+ Date:
24
+ - Fri, 11 Sep 2015 20:41:33 GMT
25
+ Content-Type:
26
+ - application/json
27
+ Content-Length:
28
+ - '139'
29
+ Connection:
30
+ - keep-alive
31
+ Etag:
32
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
33
+ body:
34
+ encoding: UTF-8
35
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
36
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
37
+ : 1.24128\n\t\t}\n\t]\n}"
38
+ http_version:
39
+ recorded_at: Fri, 11 Sep 2015 20:41:33 GMT
40
+ - request:
41
+ method: get
42
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
43
+ body:
44
+ encoding: US-ASCII
45
+ string: ''
46
+ headers:
47
+ X-Accept-Datetime-Format:
48
+ - RFC3339
49
+ Connection:
50
+ - keep-alive
51
+ Keep-Alive:
52
+ - 30
53
+ response:
54
+ status:
55
+ code: 200
56
+ message: OK
57
+ headers:
58
+ Server:
59
+ - openresty/1.7.0.1
60
+ Date:
61
+ - Fri, 11 Sep 2015 20:41:34 GMT
62
+ Content-Type:
63
+ - application/json
64
+ Content-Length:
65
+ - '139'
66
+ Connection:
67
+ - keep-alive
68
+ Etag:
69
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
70
+ body:
71
+ encoding: UTF-8
72
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
73
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
74
+ : 1.24128\n\t\t}\n\t]\n}"
75
+ http_version:
76
+ recorded_at: Fri, 11 Sep 2015 20:41:34 GMT
77
+ - request:
78
+ method: get
79
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
80
+ body:
81
+ encoding: US-ASCII
82
+ string: ''
83
+ headers:
84
+ X-Accept-Datetime-Format:
85
+ - RFC3339
86
+ Connection:
87
+ - keep-alive
88
+ Keep-Alive:
89
+ - 30
90
+ response:
91
+ status:
92
+ code: 200
93
+ message: OK
94
+ headers:
95
+ Server:
96
+ - openresty/1.7.0.1
97
+ Date:
98
+ - Fri, 11 Sep 2015 20:41:34 GMT
99
+ Content-Type:
100
+ - application/json
101
+ Content-Length:
102
+ - '139'
103
+ Connection:
104
+ - keep-alive
105
+ Etag:
106
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
107
+ body:
108
+ encoding: UTF-8
109
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
110
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
111
+ : 1.24128\n\t\t}\n\t]\n}"
112
+ http_version:
113
+ recorded_at: Fri, 11 Sep 2015 20:41:34 GMT
114
+ - request:
115
+ method: get
116
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
117
+ body:
118
+ encoding: US-ASCII
119
+ string: ''
120
+ headers:
121
+ X-Accept-Datetime-Format:
122
+ - RFC3339
123
+ Connection:
124
+ - keep-alive
125
+ Keep-Alive:
126
+ - 30
127
+ response:
128
+ status:
129
+ code: 200
130
+ message: OK
131
+ headers:
132
+ Server:
133
+ - openresty/1.7.0.1
134
+ Date:
135
+ - Fri, 11 Sep 2015 20:41:34 GMT
136
+ Content-Type:
137
+ - application/json
138
+ Content-Length:
139
+ - '139'
140
+ Connection:
141
+ - keep-alive
142
+ Etag:
143
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
144
+ body:
145
+ encoding: UTF-8
146
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
147
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
148
+ : 1.24128\n\t\t}\n\t]\n}"
149
+ http_version:
150
+ recorded_at: Fri, 11 Sep 2015 20:41:34 GMT
151
+ - request:
152
+ method: get
153
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
154
+ body:
155
+ encoding: US-ASCII
156
+ string: ''
157
+ headers:
158
+ X-Accept-Datetime-Format:
159
+ - RFC3339
160
+ Connection:
161
+ - keep-alive
162
+ Keep-Alive:
163
+ - 30
164
+ response:
165
+ status:
166
+ code: 200
167
+ message: OK
168
+ headers:
169
+ Server:
170
+ - openresty/1.7.0.1
171
+ Date:
172
+ - Fri, 11 Sep 2015 20:41:35 GMT
173
+ Content-Type:
174
+ - application/json
175
+ Content-Length:
176
+ - '139'
177
+ Connection:
178
+ - keep-alive
179
+ Etag:
180
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
181
+ body:
182
+ encoding: UTF-8
183
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
184
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
185
+ : 1.24128\n\t\t}\n\t]\n}"
186
+ http_version:
187
+ recorded_at: Fri, 11 Sep 2015 20:41:35 GMT
188
+ - request:
189
+ method: get
190
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
191
+ body:
192
+ encoding: US-ASCII
193
+ string: ''
194
+ headers:
195
+ X-Accept-Datetime-Format:
196
+ - RFC3339
197
+ Connection:
198
+ - keep-alive
199
+ Keep-Alive:
200
+ - 30
201
+ response:
202
+ status:
203
+ code: 200
204
+ message: OK
205
+ headers:
206
+ Server:
207
+ - openresty/1.7.0.1
208
+ Date:
209
+ - Fri, 11 Sep 2015 20:41:35 GMT
210
+ Content-Type:
211
+ - application/json
212
+ Content-Length:
213
+ - '139'
214
+ Connection:
215
+ - keep-alive
216
+ Etag:
217
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
218
+ body:
219
+ encoding: UTF-8
220
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
221
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
222
+ : 1.24128\n\t\t}\n\t]\n}"
223
+ http_version:
224
+ recorded_at: Fri, 11 Sep 2015 20:41:35 GMT
225
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,373 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ X-Accept-Datetime-Format:
11
+ - RFC3339
12
+ Connection:
13
+ - keep-alive
14
+ Keep-Alive:
15
+ - 30
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Server:
22
+ - openresty/1.7.0.1
23
+ Date:
24
+ - Fri, 11 Sep 2015 20:41:30 GMT
25
+ Content-Type:
26
+ - application/json
27
+ Content-Length:
28
+ - '139'
29
+ Connection:
30
+ - keep-alive
31
+ Etag:
32
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
33
+ body:
34
+ encoding: UTF-8
35
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
36
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
37
+ : 1.24128\n\t\t}\n\t]\n}"
38
+ http_version:
39
+ recorded_at: Fri, 11 Sep 2015 20:41:30 GMT
40
+ - request:
41
+ method: get
42
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
43
+ body:
44
+ encoding: US-ASCII
45
+ string: ''
46
+ headers:
47
+ X-Accept-Datetime-Format:
48
+ - RFC3339
49
+ Connection:
50
+ - keep-alive
51
+ Keep-Alive:
52
+ - 30
53
+ response:
54
+ status:
55
+ code: 200
56
+ message: OK
57
+ headers:
58
+ Server:
59
+ - openresty/1.7.0.1
60
+ Date:
61
+ - Fri, 11 Sep 2015 20:41:30 GMT
62
+ Content-Type:
63
+ - application/json
64
+ Content-Length:
65
+ - '139'
66
+ Connection:
67
+ - keep-alive
68
+ Etag:
69
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
70
+ body:
71
+ encoding: UTF-8
72
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
73
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
74
+ : 1.24128\n\t\t}\n\t]\n}"
75
+ http_version:
76
+ recorded_at: Fri, 11 Sep 2015 20:41:30 GMT
77
+ - request:
78
+ method: get
79
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
80
+ body:
81
+ encoding: US-ASCII
82
+ string: ''
83
+ headers:
84
+ X-Accept-Datetime-Format:
85
+ - RFC3339
86
+ Connection:
87
+ - keep-alive
88
+ Keep-Alive:
89
+ - 30
90
+ response:
91
+ status:
92
+ code: 200
93
+ message: OK
94
+ headers:
95
+ Server:
96
+ - openresty/1.7.0.1
97
+ Date:
98
+ - Fri, 11 Sep 2015 20:41:30 GMT
99
+ Content-Type:
100
+ - application/json
101
+ Content-Length:
102
+ - '139'
103
+ Connection:
104
+ - keep-alive
105
+ Etag:
106
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
107
+ body:
108
+ encoding: UTF-8
109
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
110
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
111
+ : 1.24128\n\t\t}\n\t]\n}"
112
+ http_version:
113
+ recorded_at: Fri, 11 Sep 2015 20:41:30 GMT
114
+ - request:
115
+ method: get
116
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
117
+ body:
118
+ encoding: US-ASCII
119
+ string: ''
120
+ headers:
121
+ X-Accept-Datetime-Format:
122
+ - RFC3339
123
+ Connection:
124
+ - keep-alive
125
+ Keep-Alive:
126
+ - 30
127
+ response:
128
+ status:
129
+ code: 200
130
+ message: OK
131
+ headers:
132
+ Server:
133
+ - openresty/1.7.0.1
134
+ Date:
135
+ - Fri, 11 Sep 2015 20:41:30 GMT
136
+ Content-Type:
137
+ - application/json
138
+ Content-Length:
139
+ - '139'
140
+ Connection:
141
+ - keep-alive
142
+ Etag:
143
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
144
+ body:
145
+ encoding: UTF-8
146
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
147
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
148
+ : 1.24128\n\t\t}\n\t]\n}"
149
+ http_version:
150
+ recorded_at: Fri, 11 Sep 2015 20:41:30 GMT
151
+ - request:
152
+ method: get
153
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
154
+ body:
155
+ encoding: US-ASCII
156
+ string: ''
157
+ headers:
158
+ X-Accept-Datetime-Format:
159
+ - RFC3339
160
+ Connection:
161
+ - keep-alive
162
+ Keep-Alive:
163
+ - 30
164
+ response:
165
+ status:
166
+ code: 200
167
+ message: OK
168
+ headers:
169
+ Server:
170
+ - openresty/1.7.0.1
171
+ Date:
172
+ - Fri, 11 Sep 2015 20:41:30 GMT
173
+ Content-Type:
174
+ - application/json
175
+ Content-Length:
176
+ - '139'
177
+ Connection:
178
+ - keep-alive
179
+ Etag:
180
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
181
+ body:
182
+ encoding: UTF-8
183
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
184
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
185
+ : 1.24128\n\t\t}\n\t]\n}"
186
+ http_version:
187
+ recorded_at: Fri, 11 Sep 2015 20:41:30 GMT
188
+ - request:
189
+ method: get
190
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
191
+ body:
192
+ encoding: US-ASCII
193
+ string: ''
194
+ headers:
195
+ X-Accept-Datetime-Format:
196
+ - RFC3339
197
+ Connection:
198
+ - keep-alive
199
+ Keep-Alive:
200
+ - 30
201
+ response:
202
+ status:
203
+ code: 200
204
+ message: OK
205
+ headers:
206
+ Server:
207
+ - openresty/1.7.0.1
208
+ Date:
209
+ - Fri, 11 Sep 2015 20:41:30 GMT
210
+ Content-Type:
211
+ - application/json
212
+ Content-Length:
213
+ - '139'
214
+ Connection:
215
+ - keep-alive
216
+ Etag:
217
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
218
+ body:
219
+ encoding: UTF-8
220
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
221
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
222
+ : 1.24128\n\t\t}\n\t]\n}"
223
+ http_version:
224
+ recorded_at: Fri, 11 Sep 2015 20:41:30 GMT
225
+ - request:
226
+ method: get
227
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
228
+ body:
229
+ encoding: US-ASCII
230
+ string: ''
231
+ headers:
232
+ X-Accept-Datetime-Format:
233
+ - RFC3339
234
+ Connection:
235
+ - keep-alive
236
+ Keep-Alive:
237
+ - 30
238
+ response:
239
+ status:
240
+ code: 200
241
+ message: OK
242
+ headers:
243
+ Server:
244
+ - openresty/1.7.0.1
245
+ Date:
246
+ - Fri, 11 Sep 2015 20:41:30 GMT
247
+ Content-Type:
248
+ - application/json
249
+ Content-Length:
250
+ - '139'
251
+ Connection:
252
+ - keep-alive
253
+ Etag:
254
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
255
+ body:
256
+ encoding: UTF-8
257
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
258
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
259
+ : 1.24128\n\t\t}\n\t]\n}"
260
+ http_version:
261
+ recorded_at: Fri, 11 Sep 2015 20:41:30 GMT
262
+ - request:
263
+ method: get
264
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
265
+ body:
266
+ encoding: US-ASCII
267
+ string: ''
268
+ headers:
269
+ X-Accept-Datetime-Format:
270
+ - RFC3339
271
+ Connection:
272
+ - keep-alive
273
+ Keep-Alive:
274
+ - 30
275
+ response:
276
+ status:
277
+ code: 200
278
+ message: OK
279
+ headers:
280
+ Server:
281
+ - openresty/1.7.0.1
282
+ Date:
283
+ - Fri, 11 Sep 2015 20:41:30 GMT
284
+ Content-Type:
285
+ - application/json
286
+ Content-Length:
287
+ - '139'
288
+ Connection:
289
+ - keep-alive
290
+ Etag:
291
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
292
+ body:
293
+ encoding: UTF-8
294
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
295
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
296
+ : 1.24128\n\t\t}\n\t]\n}"
297
+ http_version:
298
+ recorded_at: Fri, 11 Sep 2015 20:41:30 GMT
299
+ - request:
300
+ method: get
301
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
302
+ body:
303
+ encoding: US-ASCII
304
+ string: ''
305
+ headers:
306
+ X-Accept-Datetime-Format:
307
+ - RFC3339
308
+ Connection:
309
+ - keep-alive
310
+ Keep-Alive:
311
+ - 30
312
+ response:
313
+ status:
314
+ code: 200
315
+ message: OK
316
+ headers:
317
+ Server:
318
+ - openresty/1.7.0.1
319
+ Date:
320
+ - Fri, 11 Sep 2015 20:41:30 GMT
321
+ Content-Type:
322
+ - application/json
323
+ Content-Length:
324
+ - '139'
325
+ Connection:
326
+ - keep-alive
327
+ Etag:
328
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
329
+ body:
330
+ encoding: UTF-8
331
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
332
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
333
+ : 1.24128\n\t\t}\n\t]\n}"
334
+ http_version:
335
+ recorded_at: Fri, 11 Sep 2015 20:41:30 GMT
336
+ - request:
337
+ method: get
338
+ uri: http://api-sandbox.oanda.com/v1/prices?instruments=EUR_USD&username=dwaymotim
339
+ body:
340
+ encoding: US-ASCII
341
+ string: ''
342
+ headers:
343
+ X-Accept-Datetime-Format:
344
+ - RFC3339
345
+ Connection:
346
+ - keep-alive
347
+ Keep-Alive:
348
+ - 30
349
+ response:
350
+ status:
351
+ code: 200
352
+ message: OK
353
+ headers:
354
+ Server:
355
+ - openresty/1.7.0.1
356
+ Date:
357
+ - Fri, 11 Sep 2015 20:41:30 GMT
358
+ Content-Type:
359
+ - application/json
360
+ Content-Length:
361
+ - '139'
362
+ Connection:
363
+ - keep-alive
364
+ Etag:
365
+ - '"f481d760a871b4f679207cd0715bd4be8271f399"'
366
+ body:
367
+ encoding: UTF-8
368
+ string: "{\n\t\"prices\" : [\n\t\t{\n\t\t\t\"instrument\" : \"EUR_USD\",\n\t\t\t\"time\"
369
+ : \"2015-09-11T20:41:29.948985Z\",\n\t\t\t\"bid\" : 1.24115,\n\t\t\t\"ask\"
370
+ : 1.24128\n\t\t}\n\t]\n}"
371
+ http_version:
372
+ recorded_at: Fri, 11 Sep 2015 20:41:30 GMT
373
+ recorded_with: VCR 2.9.3
@@ -88,7 +88,35 @@ describe "OandaAPI::Client" do
88
88
  end
89
89
  end
90
90
  end
91
+
92
+ describe "#load_persistent_connection_adapter" do
93
+ let(:client) { (Class.new { include OandaAPI::Client }).new }
94
+
95
+ it "is called by the constructor of an including class" do
96
+ OandaAPI::Client.default_options[:connection_adapter] = nil
97
+ expect(OandaAPI::Client.default_options[:connection_adapter]).to be_nil
98
+
99
+ klass = Class.new { include OandaAPI::Client }
100
+ instance = klass.new
101
+ expect(OandaAPI::Client.default_options[:connection_adapter]).to be_a HTTParty::Persistent::ConnectionAdapter
102
+
103
+ instance = klass.new( {connection_adapter_options: {keep_alive: 20}} )
104
+ expect(OandaAPI::Client.default_options[:connection_adapter_options][:keep_alive]).to eq 20
105
+ end
91
106
 
107
+ it "loads a persistent connection adapter" do
108
+ OandaAPI::Client.default_options[:connection_adapter] = nil
109
+ expect(OandaAPI::Client.default_options[:connection_adapter]).to be_nil
110
+ client.load_persistent_connection_adapter keep_alive: 30
111
+ expect(OandaAPI::Client.default_options[:connection_adapter]).to be_a HTTParty::Persistent::ConnectionAdapter
112
+ end
113
+
114
+ it "overrides a persistent connection adapter settings" do
115
+ client.load_persistent_connection_adapter pool_size: OandaAPI.configuration.connection_pool_size + 1
116
+ expect(OandaAPI::Client.default_options[:connection_adapter_options][:pool_size]).to eq OandaAPI.configuration.connection_pool_size + 1
117
+ end
118
+ end
119
+
92
120
  describe "#execute_request" do
93
121
  let(:client) { OandaAPI::Client::UsernameClient.new "spongebob" }
94
122
 
@@ -3,6 +3,29 @@ require 'spec_helper'
3
3
  describe "OandaAPI::Configuration" do
4
4
  let(:config) { OandaAPI::Configuration.new }
5
5
 
6
+ describe "#connection_pool_size" do
7
+ it "returns the default maximum connection pool size" do
8
+ expect(config.connection_pool_size).to eq OandaAPI::Configuration::CONNECTION_POOL_SIZE
9
+ end
10
+ end
11
+
12
+ describe "#connection_pool_size=" do
13
+ it "overrides the default maximum connection pool size" do
14
+ config.connection_pool_size = 10
15
+ expect(config.connection_pool_size).to eq 10
16
+ end
17
+
18
+ it "must be numeric" do
19
+ expect { config.connection_pool_size = "X" }.to raise_error(ArgumentError)
20
+ end
21
+
22
+ it "must be > 0" do
23
+ [-10, 0].each do |val|
24
+ expect { config.connection_pool_size = val }.to raise_error(ArgumentError)
25
+ end
26
+ end
27
+ end
28
+
6
29
  describe "#datetime_format" do
7
30
  it "returns the default datetime format" do
8
31
  expect(config.datetime_format).to eq OandaAPI::Configuration::DATETIME_FORMAT
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+ require 'support/client_helper'
3
+
4
+ describe "OandaAPI::Client" do
5
+ let(:client) { ClientHelper.client }
6
+
7
+ around do |example|
8
+ reset_configuration(:use_request_throttling, :max_requests_per_second) { example.call }
9
+ end
10
+
11
+ context "when NOT using request throttling" do
12
+ it "it does NOT limit the request rate of multiple sequential requests", :vcr do
13
+ OandaAPI.configuration.use_request_throttling = false
14
+ VCR.use_cassette("without_throttling") do
15
+ start_time = Time.now
16
+ 1.upto(10) { client.prices(instruments: ["EUR_USD"]).get }
17
+
18
+ # When running the test from the VCR cassette,
19
+ # the time for each request should be constant and minimal allowing a high
20
+ # request rate.
21
+ #
22
+ # This test may fail if the VCR cassette is not used because of network
23
+ # latency.
24
+ expect(Time.now - start_time).to be > 0.0 && be < 1.0
25
+ end
26
+ end
27
+ end
28
+
29
+ context "when using request throttling" do
30
+ context "with a positive value set for max_requests_per_second" do
31
+ it "it limits multiple sequential requests to the rate specified in the requests_per_second setting " do
32
+ OandaAPI.configuration.use_request_throttling = true
33
+ OandaAPI.configuration.max_requests_per_second = 2
34
+
35
+ VCR.use_cassette("with_throttling_and_max_requests_per_second") do
36
+ start_time = Time.now
37
+ 1.upto(3) { client.prices(instruments: ["EUR_USD"]).get }
38
+
39
+ # 3 requests at 2 req/second should take at least 1 second (see below).
40
+ #
41
+ # A limit of 2 requests per second is enforced by waiting 0.5 seconds bewteen requests.
42
+ #
43
+ # time: 0.0.................0.5.................1.0 (seconds)
44
+ # request: 1st [wait 0.5s] 2nd [wait 0.5s] 3rd
45
+ expect(Time.now - start_time).to be > 1.0
46
+ end
47
+ end
48
+
49
+ context "when multiple threads make synchronized requests to the same client instance" do
50
+ it "it throttles the combined requests made by all threads" do
51
+ OandaAPI.configuration.use_request_throttling = true
52
+ OandaAPI.configuration.max_requests_per_second = 3
53
+
54
+ VCR.use_cassette("with_throttling_with_multiple_threads") do
55
+
56
+ mutex = Mutex.new
57
+ threads = []
58
+ start_time = Time.now
59
+
60
+ # Start up multiple threads
61
+ 1.upto(3) do
62
+ threads << Thread.new do
63
+ # Each thread executes multiple API requests
64
+ 1.upto(2) do
65
+ # A thread has exclusive use of the API client while executing a request.
66
+ mutex.synchronize { client.prices(instruments: ["EUR_USD"]).get }
67
+ end
68
+ end
69
+ end
70
+ threads.each(&:join)
71
+
72
+ # 6 requests in total, at 3 req/second should require at least 1.66 seconds (see below).
73
+ #
74
+ # A limit of 3 requests per second is enforced by waiting 1/3 second bewteen requests.
75
+ #
76
+ # time: 0.0 0.3 0.6 1.0 1.3 1.6 2.0 2.3 2.6 (seconds)
77
+ # request: 1st 2nd 3rd 4th 5th 6th
78
+ expect(Time.now - start_time).to be > 1.6
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
data/spec/spec_helper.rb CHANGED
@@ -60,6 +60,15 @@ def simulate_no_adapters
60
60
  end
61
61
  end
62
62
 
63
+ # Allows examples to change configuration settings, and have the settings returned to their pre-example state.
64
+ def reset_configuration(*keys)
65
+ configs = {}
66
+ keys.each { |key| configs[key] = OandaAPI.configuration.send(key) }
67
+ yield
68
+ ensure
69
+ configs.each { |key, value| OandaAPI.configuration.send("#{key}=", value) }
70
+ end
71
+
63
72
  def undefine_constants(*consts)
64
73
  values = {}
65
74
  consts.each do |const|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oanda_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dean Missikowski
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-08 00:00:00.000000000 Z
11
+ date: 2015-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -188,6 +188,9 @@ files:
188
188
  - spec/fixtures/vcr_cassettes/sandbox_client.yml
189
189
  - spec/fixtures/vcr_cassettes/sandbox_client_account.yml
190
190
  - spec/fixtures/vcr_cassettes/sandbox_instrument_EUR_USD.yml
191
+ - spec/fixtures/vcr_cassettes/with_throttling_and_max_requests_per_second.yml
192
+ - spec/fixtures/vcr_cassettes/with_throttling_with_multiple_threads.yml
193
+ - spec/fixtures/vcr_cassettes/without_throttling.yml
191
194
  - spec/oanda_api/client/client_spec.rb
192
195
  - spec/oanda_api/client/json_parser_spec.rb
193
196
  - spec/oanda_api/client/namespace_proxy_spec.rb
@@ -199,6 +202,7 @@ files:
199
202
  - spec/oanda_api/examples/orders_spec.rb
200
203
  - spec/oanda_api/examples/positions_spec.rb
201
204
  - spec/oanda_api/examples/rates_spec.rb
205
+ - spec/oanda_api/examples/request_throttling_spec.rb
202
206
  - spec/oanda_api/examples/trades_spec.rb
203
207
  - spec/oanda_api/examples/transactions_spec.rb
204
208
  - spec/oanda_api/resource_base_spec.rb
@@ -234,7 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
234
238
  version: '0'
235
239
  requirements: []
236
240
  rubyforge_project:
237
- rubygems_version: 2.4.5
241
+ rubygems_version: 2.4.6
238
242
  signing_key:
239
243
  specification_version: 4
240
244
  summary: A ruby client for the Oanda REST API.
@@ -265,6 +269,9 @@ test_files:
265
269
  - spec/fixtures/vcr_cassettes/sandbox_client.yml
266
270
  - spec/fixtures/vcr_cassettes/sandbox_client_account.yml
267
271
  - spec/fixtures/vcr_cassettes/sandbox_instrument_EUR_USD.yml
272
+ - spec/fixtures/vcr_cassettes/with_throttling_and_max_requests_per_second.yml
273
+ - spec/fixtures/vcr_cassettes/with_throttling_with_multiple_threads.yml
274
+ - spec/fixtures/vcr_cassettes/without_throttling.yml
268
275
  - spec/oanda_api/client/client_spec.rb
269
276
  - spec/oanda_api/client/json_parser_spec.rb
270
277
  - spec/oanda_api/client/namespace_proxy_spec.rb
@@ -276,6 +283,7 @@ test_files:
276
283
  - spec/oanda_api/examples/orders_spec.rb
277
284
  - spec/oanda_api/examples/positions_spec.rb
278
285
  - spec/oanda_api/examples/rates_spec.rb
286
+ - spec/oanda_api/examples/request_throttling_spec.rb
279
287
  - spec/oanda_api/examples/trades_spec.rb
280
288
  - spec/oanda_api/examples/transactions_spec.rb
281
289
  - spec/oanda_api/resource_base_spec.rb