snaptrade 3.0.45 → 3.0.46

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +54 -2
  3. data/lib/snaptrade/api/experimental_endpoints_api.rb +145 -0
  4. data/lib/snaptrade/models/account_order.rb +438 -0
  5. data/lib/snaptrade/models/account_order_group.rb +241 -0
  6. data/lib/snaptrade/models/account_order_leg.rb +302 -0
  7. data/lib/snaptrade/models/account_order_record_v2.rb +35 -1
  8. data/lib/snaptrade/models/account_order_time_in_force.rb +44 -0
  9. data/lib/snaptrade/models/all_account_orders_response.rb +239 -0
  10. data/lib/snaptrade/models/all_account_orders_response_data_freshness.rb +223 -0
  11. data/lib/snaptrade/models/limit_order_type.rb +237 -0
  12. data/lib/snaptrade/models/limit_order_type_kind.rb +36 -0
  13. data/lib/snaptrade/models/market_order_type.rb +222 -0
  14. data/lib/snaptrade/models/market_order_type_kind.rb +36 -0
  15. data/lib/snaptrade/models/order_type_configuration.rb +63 -0
  16. data/lib/snaptrade/models/other_order_type.rb +257 -0
  17. data/lib/snaptrade/models/other_order_type_kind.rb +36 -0
  18. data/lib/snaptrade/models/stop_limit_order_type.rb +252 -0
  19. data/lib/snaptrade/models/stop_limit_order_type_kind.rb +36 -0
  20. data/lib/snaptrade/models/stop_order_type.rb +237 -0
  21. data/lib/snaptrade/models/stop_order_type_kind.rb +36 -0
  22. data/lib/snaptrade/models/trailing_stop_limit_order_type.rb +262 -0
  23. data/lib/snaptrade/models/trailing_stop_limit_order_type_kind.rb +36 -0
  24. data/lib/snaptrade/models/trailing_stop_order_type.rb +247 -0
  25. data/lib/snaptrade/models/trailing_stop_order_type_kind.rb +36 -0
  26. data/lib/snaptrade/version.rb +1 -1
  27. data/lib/snaptrade.rb +21 -0
  28. data/spec/api/experimental_endpoints_api_spec.rb +16 -0
  29. data/spec/models/account_order_group_spec.rb +35 -0
  30. data/spec/models/account_order_leg_spec.rb +71 -0
  31. data/spec/models/account_order_record_v2_spec.rb +4 -0
  32. data/spec/models/account_order_spec.rb +125 -0
  33. data/spec/models/account_order_time_in_force_spec.rb +23 -0
  34. data/spec/models/all_account_orders_response_data_freshness_spec.rb +29 -0
  35. data/spec/models/all_account_orders_response_spec.rb +35 -0
  36. data/spec/models/limit_order_type_kind_spec.rb +23 -0
  37. data/spec/models/limit_order_type_spec.rb +35 -0
  38. data/spec/models/market_order_type_kind_spec.rb +23 -0
  39. data/spec/models/market_order_type_spec.rb +29 -0
  40. data/spec/models/order_type_configuration_spec.rb +38 -0
  41. data/spec/models/other_order_type_kind_spec.rb +23 -0
  42. data/spec/models/other_order_type_spec.rb +47 -0
  43. data/spec/models/stop_limit_order_type_kind_spec.rb +23 -0
  44. data/spec/models/stop_limit_order_type_spec.rb +41 -0
  45. data/spec/models/stop_order_type_kind_spec.rb +23 -0
  46. data/spec/models/stop_order_type_spec.rb +35 -0
  47. data/spec/models/trailing_stop_limit_order_type_kind_spec.rb +23 -0
  48. data/spec/models/trailing_stop_limit_order_type_spec.rb +47 -0
  49. data/spec/models/trailing_stop_order_type_kind_spec.rb +23 -0
  50. data/spec/models/trailing_stop_order_type_spec.rb +41 -0
  51. metadata +313 -250
@@ -0,0 +1,438 @@
1
+ =begin
2
+ #SnapTrade
3
+
4
+ #Connect brokerage accounts to your app for live positions and trading. ## Rate limiting Two limits apply to requests signed with your `clientId`. The stricter one wins, and exceeding either returns `429 Too Many Requests`. - **Customer-level** — 250 requests/minute by default, scoped to your `clientId` and applied across all endpoints. Reported in `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. - **Account-level** — 10 requests/minute per account, scoped to (`clientId`, `accountId`). All covered operations for one account draw on the same bucket — reading balances and reading positions share it — and enforcement does not depend on the HTTP method, so updating an account consumes the same bucket as reading it. Only enforced for Personal users, and only for integrations it has been rolled out to — it is not yet in force for every Personal integration. It also does not apply on every operation that documents a 429 below. Where it applies it is reported in `X-RateLimit-Account-Limit`, `X-RateLimit-Account-Remaining` and `X-RateLimit-Account-Reset`. Do not read the absence of those headers as proof the limit is off — some configurations omit the rate limit headers while still enforcing the limit, so header absence tells you nothing about your allowance. On a 429, `X-RateLimit-Remaining: 0` means you hit the customer-level limit and `X-RateLimit-Account-Remaining: 0` means the account-level one. Wait for the corresponding `*-Reset` value (seconds) before retrying, or fall back to exponential backoff with jitter. Not every 429 is explained by those headers. A separate per-authenticated-user limit, reported in no `X-RateLimit-*` header, covers OAuth-authenticated requests and signed requests in configurations where the customer-level limit is not in effect — on the operations that use the default throttles. A few operations override those and are governed by the customer-level limit alone. The two do not stack: a signed request governed by the customer-level limit above is not additionally subject to the per-user one. If a 429 arrives with no header at zero — or with no `X-RateLimit-*` headers at all — honour `Retry-After` and back off. Treat the remaining counts as a hint, not a guarantee that the next request will succeed. Because the customer-level limit applies everywhere, any signed request can return 429. **OAuth-authenticated requests are an exception.** They are not subject to the customer-level limit and do not receive `X-RateLimit-Limit`, `X-RateLimit-Remaining` or `X-RateLimit-Reset` — do not wait on those headers or design around a customer-level allowance on this path. The account-level limit still applies to them on the account-data endpoints above, reported in the `X-RateLimit-Account-*` headers. On operations using the default throttles the per-user limit above applies to them as well, so an OAuth request can be rejected while the account headers still show capacity; on the few operations that override those throttles, OAuth callers have no per-user ceiling at all. Drive retries from `Retry-After` and exponential backoff with jitter rather than from the headers. See https://docs.snaptrade.com/docs/ratelimiting.
5
+
6
+ The version of the OpenAPI document: 1.0.0
7
+ Contact: api@snaptrade.com
8
+ =end
9
+
10
+ require 'date'
11
+ require 'time'
12
+
13
+ module SnapTrade
14
+ # A single order. Single-leg orders have exactly one entry in `legs`; multi-leg orders (spreads, strangles, covered calls) have one entry per leg.
15
+ class AccountOrder
16
+ # Order ID returned by brokerage. This is the unique identifier for the order in the brokerage system.
17
+ attr_accessor :brokerage_order_id
18
+
19
+ # Indicates the status of an order. SnapTrade does a best effort to map brokerage statuses to statuses in this enum.
20
+ attr_accessor :status
21
+
22
+ attr_accessor :order_type
23
+
24
+ # How long the order remains active. Brokerage values that cannot be mapped to this list are returned as `OTHER`. - `DAY` - valid only for the trading day on which it is placed. - `GTC` - Good Til Canceled. - `FOK` - Fill Or Kill. - `IOC` - Immediate Or Cancel. - `GTD` - Good Til Date; see `expiry_date`. - `MOO` - Market On Open. - `EHP` - Extended Hours P.M. - `EHA` - Extended Hours A.M. - `OTHER` - the brokerage reported a value outside this list.
25
+ attr_accessor :time_in_force
26
+
27
+ # When the order expires, for orders with a `time_in_force` of `GTD`.
28
+ attr_accessor :expiry_date
29
+
30
+ # ISO-4217 currency code the order prices are denominated in. For crypto pairs this is the quote asset (for example `USDC` for `ETH-USDC`).
31
+ attr_accessor :price_currency
32
+
33
+ # Direction of the net order price. CREDIT means cash is received, DEBIT means cash is paid, EVEN means the net price is zero, and UNKNOWN means the direction could not be determined.
34
+ attr_accessor :price_effect
35
+
36
+ # Total quantity requested. For multi-leg orders this is the number of spreads, not the sum of leg quantities.
37
+ attr_accessor :total_quantity
38
+
39
+ # Quantity filled so far.
40
+ attr_accessor :filled_quantity
41
+
42
+ # Quantity canceled.
43
+ attr_accessor :canceled_quantity
44
+
45
+ # Quantity still open (not yet filled or canceled).
46
+ attr_accessor :open_quantity
47
+
48
+ # Average execution price. Per unit for single-leg orders; net price per spread for multi-leg orders.
49
+ attr_accessor :execution_price
50
+
51
+ # The time the order was submitted to the brokerage, when the brokerage reports it.
52
+ attr_accessor :time_placed
53
+
54
+ # The time the order was last updated at the brokerage, when available.
55
+ attr_accessor :time_updated
56
+
57
+ # The time the order was executed, when available.
58
+ attr_accessor :time_executed
59
+
60
+ attr_accessor :group
61
+
62
+ # The legs that make up the order. Always has at least one entry.
63
+ attr_accessor :legs
64
+
65
+ # Attribute mapping from ruby-style variable name to JSON key.
66
+ def self.attribute_map
67
+ {
68
+ :'brokerage_order_id' => :'brokerage_order_id',
69
+ :'status' => :'status',
70
+ :'order_type' => :'order_type',
71
+ :'time_in_force' => :'time_in_force',
72
+ :'expiry_date' => :'expiry_date',
73
+ :'price_currency' => :'price_currency',
74
+ :'price_effect' => :'price_effect',
75
+ :'total_quantity' => :'total_quantity',
76
+ :'filled_quantity' => :'filled_quantity',
77
+ :'canceled_quantity' => :'canceled_quantity',
78
+ :'open_quantity' => :'open_quantity',
79
+ :'execution_price' => :'execution_price',
80
+ :'time_placed' => :'time_placed',
81
+ :'time_updated' => :'time_updated',
82
+ :'time_executed' => :'time_executed',
83
+ :'group' => :'group',
84
+ :'legs' => :'legs'
85
+ }
86
+ end
87
+
88
+ # Returns all the JSON keys this model knows about
89
+ def self.acceptable_attributes
90
+ attribute_map.values
91
+ end
92
+
93
+ # Attribute type mapping.
94
+ def self.openapi_types
95
+ {
96
+ :'brokerage_order_id' => :'String',
97
+ :'status' => :'AccountOrderRecordStatusV2',
98
+ :'order_type' => :'OrderTypeConfiguration',
99
+ :'time_in_force' => :'AccountOrderTimeInForce',
100
+ :'expiry_date' => :'Time',
101
+ :'price_currency' => :'String',
102
+ :'price_effect' => :'PriceEffect',
103
+ :'total_quantity' => :'Float',
104
+ :'filled_quantity' => :'Float',
105
+ :'canceled_quantity' => :'Float',
106
+ :'open_quantity' => :'Float',
107
+ :'execution_price' => :'Float',
108
+ :'time_placed' => :'Time',
109
+ :'time_updated' => :'Time',
110
+ :'time_executed' => :'Time',
111
+ :'group' => :'AccountOrderGroup',
112
+ :'legs' => :'Array<AccountOrderLeg>'
113
+ }
114
+ end
115
+
116
+ # List of attributes with nullable: true
117
+ def self.openapi_nullable
118
+ Set.new([
119
+ :'expiry_date',
120
+ :'price_currency',
121
+ :'total_quantity',
122
+ :'filled_quantity',
123
+ :'canceled_quantity',
124
+ :'open_quantity',
125
+ :'execution_price',
126
+ :'time_placed',
127
+ :'time_updated',
128
+ :'time_executed',
129
+ :'group',
130
+ ])
131
+ end
132
+
133
+ # Initializes the object
134
+ # @param [Hash] attributes Model attributes in the form of hash
135
+ def initialize(attributes = {})
136
+ if (!attributes.is_a?(Hash))
137
+ fail ArgumentError, "The input argument (attributes) must be a hash in `SnapTrade::AccountOrder` initialize method"
138
+ end
139
+
140
+ # check to see if the attribute exists and convert string to symbol for hash key
141
+ attributes = attributes.each_with_object({}) { |(k, v), h|
142
+ if (!self.class.attribute_map.key?(k.to_sym))
143
+ fail ArgumentError, "`#{k}` is not a valid attribute in `SnapTrade::AccountOrder`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect
144
+ end
145
+ h[k.to_sym] = v
146
+ }
147
+
148
+ if attributes.key?(:'brokerage_order_id')
149
+ self.brokerage_order_id = attributes[:'brokerage_order_id']
150
+ end
151
+
152
+ if attributes.key?(:'status')
153
+ self.status = attributes[:'status']
154
+ end
155
+
156
+ if attributes.key?(:'order_type')
157
+ self.order_type = attributes[:'order_type']
158
+ end
159
+
160
+ if attributes.key?(:'time_in_force')
161
+ self.time_in_force = attributes[:'time_in_force']
162
+ end
163
+
164
+ if attributes.key?(:'expiry_date')
165
+ self.expiry_date = attributes[:'expiry_date']
166
+ end
167
+
168
+ if attributes.key?(:'price_currency')
169
+ self.price_currency = attributes[:'price_currency']
170
+ end
171
+
172
+ if attributes.key?(:'price_effect')
173
+ self.price_effect = attributes[:'price_effect']
174
+ end
175
+
176
+ if attributes.key?(:'total_quantity')
177
+ self.total_quantity = attributes[:'total_quantity']
178
+ end
179
+
180
+ if attributes.key?(:'filled_quantity')
181
+ self.filled_quantity = attributes[:'filled_quantity']
182
+ end
183
+
184
+ if attributes.key?(:'canceled_quantity')
185
+ self.canceled_quantity = attributes[:'canceled_quantity']
186
+ end
187
+
188
+ if attributes.key?(:'open_quantity')
189
+ self.open_quantity = attributes[:'open_quantity']
190
+ end
191
+
192
+ if attributes.key?(:'execution_price')
193
+ self.execution_price = attributes[:'execution_price']
194
+ end
195
+
196
+ if attributes.key?(:'time_placed')
197
+ self.time_placed = attributes[:'time_placed']
198
+ end
199
+
200
+ if attributes.key?(:'time_updated')
201
+ self.time_updated = attributes[:'time_updated']
202
+ end
203
+
204
+ if attributes.key?(:'time_executed')
205
+ self.time_executed = attributes[:'time_executed']
206
+ end
207
+
208
+ if attributes.key?(:'group')
209
+ self.group = attributes[:'group']
210
+ end
211
+
212
+ if attributes.key?(:'legs')
213
+ if (value = attributes[:'legs']).is_a?(Array)
214
+ self.legs = value
215
+ end
216
+ end
217
+ end
218
+
219
+ # Show invalid properties with the reasons. Usually used together with valid?
220
+ # @return Array for valid properties with the reasons
221
+ def list_invalid_properties
222
+ invalid_properties = Array.new
223
+ if @brokerage_order_id.nil?
224
+ invalid_properties.push('invalid value for "brokerage_order_id", brokerage_order_id cannot be nil.')
225
+ end
226
+
227
+ if @status.nil?
228
+ invalid_properties.push('invalid value for "status", status cannot be nil.')
229
+ end
230
+
231
+ if @order_type.nil?
232
+ invalid_properties.push('invalid value for "order_type", order_type cannot be nil.')
233
+ end
234
+
235
+ if @time_in_force.nil?
236
+ invalid_properties.push('invalid value for "time_in_force", time_in_force cannot be nil.')
237
+ end
238
+
239
+ if @price_effect.nil?
240
+ invalid_properties.push('invalid value for "price_effect", price_effect cannot be nil.')
241
+ end
242
+
243
+ if @legs.nil?
244
+ invalid_properties.push('invalid value for "legs", legs cannot be nil.')
245
+ end
246
+
247
+ if @legs.length < 1
248
+ invalid_properties.push('invalid value for "legs", number of items must be greater than or equal to 1.')
249
+ end
250
+
251
+ invalid_properties
252
+ end
253
+
254
+ # Check to see if the all the properties in the model are valid
255
+ # @return true if the model is valid
256
+ def valid?
257
+ return false if @brokerage_order_id.nil?
258
+ return false if @status.nil?
259
+ return false if @order_type.nil?
260
+ return false if @time_in_force.nil?
261
+ return false if @price_effect.nil?
262
+ return false if @legs.nil?
263
+ return false if @legs.length < 1
264
+ true
265
+ end
266
+
267
+ # Custom attribute writer method with validation
268
+ # @param [Object] legs Value to be assigned
269
+ def legs=(legs)
270
+ if legs.nil?
271
+ fail ArgumentError, 'legs cannot be nil'
272
+ end
273
+
274
+ if legs.length < 1
275
+ fail ArgumentError, 'invalid value for "legs", number of items must be greater than or equal to 1.'
276
+ end
277
+
278
+ @legs = legs
279
+ end
280
+
281
+ # Checks equality by comparing each attribute.
282
+ # @param [Object] Object to be compared
283
+ def ==(o)
284
+ return true if self.equal?(o)
285
+ self.class == o.class &&
286
+ brokerage_order_id == o.brokerage_order_id &&
287
+ status == o.status &&
288
+ order_type == o.order_type &&
289
+ time_in_force == o.time_in_force &&
290
+ expiry_date == o.expiry_date &&
291
+ price_currency == o.price_currency &&
292
+ price_effect == o.price_effect &&
293
+ total_quantity == o.total_quantity &&
294
+ filled_quantity == o.filled_quantity &&
295
+ canceled_quantity == o.canceled_quantity &&
296
+ open_quantity == o.open_quantity &&
297
+ execution_price == o.execution_price &&
298
+ time_placed == o.time_placed &&
299
+ time_updated == o.time_updated &&
300
+ time_executed == o.time_executed &&
301
+ group == o.group &&
302
+ legs == o.legs
303
+ end
304
+
305
+ # @see the `==` method
306
+ # @param [Object] Object to be compared
307
+ def eql?(o)
308
+ self == o
309
+ end
310
+
311
+ # Calculates hash code according to all attributes.
312
+ # @return [Integer] Hash code
313
+ def hash
314
+ [brokerage_order_id, status, order_type, time_in_force, expiry_date, price_currency, price_effect, total_quantity, filled_quantity, canceled_quantity, open_quantity, execution_price, time_placed, time_updated, time_executed, group, legs].hash
315
+ end
316
+
317
+ # Builds the object from hash
318
+ # @param [Hash] attributes Model attributes in the form of hash
319
+ # @return [Object] Returns the model itself
320
+ def self.build_from_hash(attributes)
321
+ new.build_from_hash(attributes)
322
+ end
323
+
324
+ # Builds the object from hash
325
+ # @param [Hash] attributes Model attributes in the form of hash
326
+ # @return [Object] Returns the model itself
327
+ def build_from_hash(attributes)
328
+ return nil unless attributes.is_a?(Hash)
329
+ attributes = attributes.transform_keys(&:to_sym)
330
+ self.class.openapi_types.each_pair do |key, type|
331
+ if attributes[self.class.attribute_map[key]].nil? && self.class.openapi_nullable.include?(key)
332
+ self.send("#{key}=", nil)
333
+ elsif type =~ /\AArray<(.*)>/i
334
+ # check to ensure the input is an array given that the attribute
335
+ # is documented as an array but the input is not
336
+ if attributes[self.class.attribute_map[key]].is_a?(Array)
337
+ self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) })
338
+ end
339
+ elsif !attributes[self.class.attribute_map[key]].nil?
340
+ self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]]))
341
+ end
342
+ end
343
+
344
+ self
345
+ end
346
+
347
+ # Deserializes the data based on type
348
+ # @param string type Data type
349
+ # @param string value Value to be deserialized
350
+ # @return [Object] Deserialized data
351
+ def _deserialize(type, value)
352
+ case type.to_sym
353
+ when :Time
354
+ Time.parse(value)
355
+ when :Date
356
+ Date.parse(value)
357
+ when :String
358
+ value.to_s
359
+ when :Integer
360
+ value.to_i
361
+ when :Float
362
+ value.to_f
363
+ when :Boolean
364
+ if value.to_s =~ /\A(true|t|yes|y|1)\z/i
365
+ true
366
+ else
367
+ false
368
+ end
369
+ when :Object
370
+ # generic object (usually a Hash), return directly
371
+ value
372
+ when /\AArray<(?<inner_type>.+)>\z/
373
+ inner_type = Regexp.last_match[:inner_type]
374
+ value.map { |v| _deserialize(inner_type, v) }
375
+ when /\AHash<(?<k_type>.+?), (?<v_type>.+)>\z/
376
+ k_type = Regexp.last_match[:k_type]
377
+ v_type = Regexp.last_match[:v_type]
378
+ {}.tap do |hash|
379
+ value.each do |k, v|
380
+ hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
381
+ end
382
+ end
383
+ else # model
384
+ # models (e.g. Pet) or oneOf
385
+ klass = SnapTrade.const_get(type)
386
+ klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value)
387
+ end
388
+ end
389
+
390
+ # Returns the string representation of the object
391
+ # @return [String] String presentation of the object
392
+ def to_s
393
+ to_hash.to_s
394
+ end
395
+
396
+ # to_body is an alias to to_hash (backward compatibility)
397
+ # @return [Hash] Returns the object in the form of hash
398
+ def to_body
399
+ to_hash
400
+ end
401
+
402
+ # Returns the object in the form of hash
403
+ # @return [Hash] Returns the object in the form of hash
404
+ def to_hash
405
+ hash = {}
406
+ self.class.attribute_map.each_pair do |attr, param|
407
+ value = self.send(attr)
408
+ if value.nil?
409
+ is_nullable = self.class.openapi_nullable.include?(attr)
410
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
411
+ end
412
+
413
+ hash[param] = _to_hash(value)
414
+ end
415
+ hash
416
+ end
417
+
418
+ # Outputs non-array value in the form of hash
419
+ # For object, use to_hash. Otherwise, just return the value
420
+ # @param [Object] value Any valid value
421
+ # @return [Hash] Returns the value in the form of hash
422
+ def _to_hash(value)
423
+ if value.is_a?(Array)
424
+ value.compact.map { |v| _to_hash(v) }
425
+ elsif value.is_a?(Hash)
426
+ {}.tap do |hash|
427
+ value.each { |k, v| hash[k] = _to_hash(v) }
428
+ end
429
+ elsif value.respond_to? :to_hash
430
+ value.to_hash
431
+ else
432
+ value
433
+ end
434
+ end
435
+
436
+ end
437
+
438
+ end
@@ -0,0 +1,241 @@
1
+ =begin
2
+ #SnapTrade
3
+
4
+ #Connect brokerage accounts to your app for live positions and trading. ## Rate limiting Two limits apply to requests signed with your `clientId`. The stricter one wins, and exceeding either returns `429 Too Many Requests`. - **Customer-level** — 250 requests/minute by default, scoped to your `clientId` and applied across all endpoints. Reported in `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. - **Account-level** — 10 requests/minute per account, scoped to (`clientId`, `accountId`). All covered operations for one account draw on the same bucket — reading balances and reading positions share it — and enforcement does not depend on the HTTP method, so updating an account consumes the same bucket as reading it. Only enforced for Personal users, and only for integrations it has been rolled out to — it is not yet in force for every Personal integration. It also does not apply on every operation that documents a 429 below. Where it applies it is reported in `X-RateLimit-Account-Limit`, `X-RateLimit-Account-Remaining` and `X-RateLimit-Account-Reset`. Do not read the absence of those headers as proof the limit is off — some configurations omit the rate limit headers while still enforcing the limit, so header absence tells you nothing about your allowance. On a 429, `X-RateLimit-Remaining: 0` means you hit the customer-level limit and `X-RateLimit-Account-Remaining: 0` means the account-level one. Wait for the corresponding `*-Reset` value (seconds) before retrying, or fall back to exponential backoff with jitter. Not every 429 is explained by those headers. A separate per-authenticated-user limit, reported in no `X-RateLimit-*` header, covers OAuth-authenticated requests and signed requests in configurations where the customer-level limit is not in effect — on the operations that use the default throttles. A few operations override those and are governed by the customer-level limit alone. The two do not stack: a signed request governed by the customer-level limit above is not additionally subject to the per-user one. If a 429 arrives with no header at zero — or with no `X-RateLimit-*` headers at all — honour `Retry-After` and back off. Treat the remaining counts as a hint, not a guarantee that the next request will succeed. Because the customer-level limit applies everywhere, any signed request can return 429. **OAuth-authenticated requests are an exception.** They are not subject to the customer-level limit and do not receive `X-RateLimit-Limit`, `X-RateLimit-Remaining` or `X-RateLimit-Reset` — do not wait on those headers or design around a customer-level allowance on this path. The account-level limit still applies to them on the account-data endpoints above, reported in the `X-RateLimit-Account-*` headers. On operations using the default throttles the per-user limit above applies to them as well, so an OAuth request can be rejected while the account headers still show capacity; on the few operations that override those throttles, OAuth callers have no per-user ceiling at all. Drive retries from `Retry-After` and exponential backoff with jitter rather than from the headers. See https://docs.snaptrade.com/docs/ratelimiting.
5
+
6
+ The version of the OpenAPI document: 1.0.0
7
+ Contact: api@snaptrade.com
8
+ =end
9
+
10
+ require 'date'
11
+ require 'time'
12
+
13
+ module SnapTrade
14
+ # Set when this order belongs to a complex order group (OCO, OTO, OTOCO). Null otherwise.
15
+ class AccountOrderGroup
16
+ # Brokerage-assigned identifier shared by every order in the group.
17
+ attr_accessor :id
18
+
19
+ # This order's role within the group, when the brokerage reports it.
20
+ attr_accessor :role
21
+
22
+ # Attribute mapping from ruby-style variable name to JSON key.
23
+ def self.attribute_map
24
+ {
25
+ :'id' => :'id',
26
+ :'role' => :'role'
27
+ }
28
+ end
29
+
30
+ # Returns all the JSON keys this model knows about
31
+ def self.acceptable_attributes
32
+ attribute_map.values
33
+ end
34
+
35
+ # Attribute type mapping.
36
+ def self.openapi_types
37
+ {
38
+ :'id' => :'String',
39
+ :'role' => :'AccountOrderRecordV2OrderRole'
40
+ }
41
+ end
42
+
43
+ # List of attributes with nullable: true
44
+ def self.openapi_nullable
45
+ Set.new([
46
+ :'role'
47
+ ])
48
+ end
49
+
50
+ # List of class defined in allOf (OpenAPI v3)
51
+ def self.openapi_all_of
52
+ [
53
+ :'AccountOrderGroup'
54
+ ]
55
+ end
56
+
57
+ # Initializes the object
58
+ # @param [Hash] attributes Model attributes in the form of hash
59
+ def initialize(attributes = {})
60
+ if (!attributes.is_a?(Hash))
61
+ fail ArgumentError, "The input argument (attributes) must be a hash in `SnapTrade::AccountOrderGroup` initialize method"
62
+ end
63
+
64
+ # check to see if the attribute exists and convert string to symbol for hash key
65
+ attributes = attributes.each_with_object({}) { |(k, v), h|
66
+ if (!self.class.attribute_map.key?(k.to_sym))
67
+ fail ArgumentError, "`#{k}` is not a valid attribute in `SnapTrade::AccountOrderGroup`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect
68
+ end
69
+ h[k.to_sym] = v
70
+ }
71
+
72
+ if attributes.key?(:'id')
73
+ self.id = attributes[:'id']
74
+ end
75
+
76
+ if attributes.key?(:'role')
77
+ self.role = attributes[:'role']
78
+ end
79
+ end
80
+
81
+ # Show invalid properties with the reasons. Usually used together with valid?
82
+ # @return Array for valid properties with the reasons
83
+ def list_invalid_properties
84
+ invalid_properties = Array.new
85
+ if @id.nil?
86
+ invalid_properties.push('invalid value for "id", id cannot be nil.')
87
+ end
88
+
89
+ invalid_properties
90
+ end
91
+
92
+ # Check to see if the all the properties in the model are valid
93
+ # @return true if the model is valid
94
+ def valid?
95
+ return false if @id.nil?
96
+ true
97
+ end
98
+
99
+ # Checks equality by comparing each attribute.
100
+ # @param [Object] Object to be compared
101
+ def ==(o)
102
+ return true if self.equal?(o)
103
+ self.class == o.class &&
104
+ id == o.id &&
105
+ role == o.role
106
+ end
107
+
108
+ # @see the `==` method
109
+ # @param [Object] Object to be compared
110
+ def eql?(o)
111
+ self == o
112
+ end
113
+
114
+ # Calculates hash code according to all attributes.
115
+ # @return [Integer] Hash code
116
+ def hash
117
+ [id, role].hash
118
+ end
119
+
120
+ # Builds the object from hash
121
+ # @param [Hash] attributes Model attributes in the form of hash
122
+ # @return [Object] Returns the model itself
123
+ def self.build_from_hash(attributes)
124
+ new.build_from_hash(attributes)
125
+ end
126
+
127
+ # Builds the object from hash
128
+ # @param [Hash] attributes Model attributes in the form of hash
129
+ # @return [Object] Returns the model itself
130
+ def build_from_hash(attributes)
131
+ return nil unless attributes.is_a?(Hash)
132
+ attributes = attributes.transform_keys(&:to_sym)
133
+ self.class.openapi_types.each_pair do |key, type|
134
+ if attributes[self.class.attribute_map[key]].nil? && self.class.openapi_nullable.include?(key)
135
+ self.send("#{key}=", nil)
136
+ elsif type =~ /\AArray<(.*)>/i
137
+ # check to ensure the input is an array given that the attribute
138
+ # is documented as an array but the input is not
139
+ if attributes[self.class.attribute_map[key]].is_a?(Array)
140
+ self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) })
141
+ end
142
+ elsif !attributes[self.class.attribute_map[key]].nil?
143
+ self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]]))
144
+ end
145
+ end
146
+
147
+ self
148
+ end
149
+
150
+ # Deserializes the data based on type
151
+ # @param string type Data type
152
+ # @param string value Value to be deserialized
153
+ # @return [Object] Deserialized data
154
+ def _deserialize(type, value)
155
+ case type.to_sym
156
+ when :Time
157
+ Time.parse(value)
158
+ when :Date
159
+ Date.parse(value)
160
+ when :String
161
+ value.to_s
162
+ when :Integer
163
+ value.to_i
164
+ when :Float
165
+ value.to_f
166
+ when :Boolean
167
+ if value.to_s =~ /\A(true|t|yes|y|1)\z/i
168
+ true
169
+ else
170
+ false
171
+ end
172
+ when :Object
173
+ # generic object (usually a Hash), return directly
174
+ value
175
+ when /\AArray<(?<inner_type>.+)>\z/
176
+ inner_type = Regexp.last_match[:inner_type]
177
+ value.map { |v| _deserialize(inner_type, v) }
178
+ when /\AHash<(?<k_type>.+?), (?<v_type>.+)>\z/
179
+ k_type = Regexp.last_match[:k_type]
180
+ v_type = Regexp.last_match[:v_type]
181
+ {}.tap do |hash|
182
+ value.each do |k, v|
183
+ hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
184
+ end
185
+ end
186
+ else # model
187
+ # models (e.g. Pet) or oneOf
188
+ klass = SnapTrade.const_get(type)
189
+ klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value)
190
+ end
191
+ end
192
+
193
+ # Returns the string representation of the object
194
+ # @return [String] String presentation of the object
195
+ def to_s
196
+ to_hash.to_s
197
+ end
198
+
199
+ # to_body is an alias to to_hash (backward compatibility)
200
+ # @return [Hash] Returns the object in the form of hash
201
+ def to_body
202
+ to_hash
203
+ end
204
+
205
+ # Returns the object in the form of hash
206
+ # @return [Hash] Returns the object in the form of hash
207
+ def to_hash
208
+ hash = {}
209
+ self.class.attribute_map.each_pair do |attr, param|
210
+ value = self.send(attr)
211
+ if value.nil?
212
+ is_nullable = self.class.openapi_nullable.include?(attr)
213
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
214
+ end
215
+
216
+ hash[param] = _to_hash(value)
217
+ end
218
+ hash
219
+ end
220
+
221
+ # Outputs non-array value in the form of hash
222
+ # For object, use to_hash. Otherwise, just return the value
223
+ # @param [Object] value Any valid value
224
+ # @return [Hash] Returns the value in the form of hash
225
+ def _to_hash(value)
226
+ if value.is_a?(Array)
227
+ value.compact.map { |v| _to_hash(v) }
228
+ elsif value.is_a?(Hash)
229
+ {}.tap do |hash|
230
+ value.each { |k, v| hash[k] = _to_hash(v) }
231
+ end
232
+ elsif value.respond_to? :to_hash
233
+ value.to_hash
234
+ else
235
+ value
236
+ end
237
+ end
238
+
239
+ end
240
+
241
+ end