ig_markets 0.16 → 0.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/ig_markets.rb +7 -5
- data/lib/ig_markets/api_versions.rb +6 -0
- data/lib/ig_markets/cli/main.rb +14 -20
- data/lib/ig_markets/dealing_platform.rb +28 -10
- data/lib/ig_markets/errors.rb +323 -0
- data/lib/ig_markets/format.rb +2 -0
- data/lib/ig_markets/model.rb +9 -3
- data/lib/ig_markets/password_encryptor.rb +8 -2
- data/lib/ig_markets/payload_formatter.rb +2 -0
- data/lib/ig_markets/regex.rb +2 -0
- data/lib/ig_markets/request_printer.rb +5 -1
- data/lib/ig_markets/response_parser.rb +5 -14
- data/lib/ig_markets/session.rb +82 -83
- data/lib/ig_markets/version.rb +1 -1
- metadata +12 -13
- data/lib/ig_markets/request_failed_error.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c696f25e6b960d65896474cf519c7492f8ad195
|
4
|
+
data.tar.gz: 54dcc2e3caa92373344c3faf7c3a1ea8f916dcf2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b0052a80212495c796d6ab5c75188690f259d640fa96982b7c0cb7f7b636014bc43cea9e5102a4bb17e8c07cb0f671d634db469165ab83b002d66d7bdde53b6
|
7
|
+
data.tar.gz: 588dd121edd94b04546afa353802f39ccdde3c972684f17d297d6d2d649baa2cce25968dfc82a6876e06ce7e0e86093236ba4a13720d9db98531a437c057cb17
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# IG Markets Changelog
|
2
2
|
|
3
|
+
### 0.17 — July 27, 2016
|
4
|
+
|
5
|
+
- Switched to the `excon` HTTP library
|
6
|
+
- Replaced `IGMarkets::RequestFailedError` with a new `IGMarkets::IGMarketsError` class which is used as a base class
|
7
|
+
for all errors raised by this gem
|
8
|
+
- Added a full set of error subclassses to give more accurate reporting of errors generated by the IG Markets API
|
9
|
+
- Documentation improvements
|
10
|
+
|
3
11
|
### 0.16 — July 20, 2016
|
4
12
|
|
5
13
|
- Switched to YAML for the `.ig_markets` config files and added support for storing multiple authentication profiles in
|
data/lib/ig_markets.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
require 'base64'
|
2
|
-
require 'colorize'
|
3
2
|
require 'date'
|
4
3
|
require 'json'
|
5
|
-
require 'pry'
|
6
|
-
require 'rest-client'
|
7
4
|
require 'securerandom'
|
5
|
+
require 'time'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
require 'colorize'
|
9
|
+
require 'excon'
|
10
|
+
require 'pry'
|
8
11
|
require 'terminal-table'
|
9
12
|
require 'thor'
|
10
|
-
require 'yaml'
|
11
13
|
|
12
14
|
require 'ig_markets/boolean'
|
13
15
|
require 'ig_markets/model'
|
@@ -29,6 +31,7 @@ require 'ig_markets/dealing_platform/position_methods'
|
|
29
31
|
require 'ig_markets/dealing_platform/sprint_market_position_methods'
|
30
32
|
require 'ig_markets/dealing_platform/watchlist_methods'
|
31
33
|
require 'ig_markets/dealing_platform/working_order_methods'
|
34
|
+
require 'ig_markets/errors'
|
32
35
|
require 'ig_markets/format'
|
33
36
|
require 'ig_markets/instrument'
|
34
37
|
require 'ig_markets/historical_price_result'
|
@@ -38,7 +41,6 @@ require 'ig_markets/market_hierarchy_result'
|
|
38
41
|
require 'ig_markets/password_encryptor'
|
39
42
|
require 'ig_markets/payload_formatter'
|
40
43
|
require 'ig_markets/position'
|
41
|
-
require 'ig_markets/request_failed_error'
|
42
44
|
require 'ig_markets/request_printer'
|
43
45
|
require 'ig_markets/response_parser'
|
44
46
|
require 'ig_markets/session'
|
@@ -1,10 +1,16 @@
|
|
1
1
|
module IGMarkets
|
2
2
|
# Named constant used to target version 1 of the IG Markets API.
|
3
|
+
#
|
4
|
+
# @private
|
3
5
|
API_V1 = 1
|
4
6
|
|
5
7
|
# Named constant used to target version 2 of the IG Markets API.
|
8
|
+
#
|
9
|
+
# @private
|
6
10
|
API_V2 = 2
|
7
11
|
|
8
12
|
# Named constant used to target version 3 of the IG Markets API.
|
13
|
+
#
|
14
|
+
# @private
|
9
15
|
API_V3 = 3
|
10
16
|
end
|
data/lib/ig_markets/cli/main.rb
CHANGED
@@ -26,8 +26,6 @@ module IGMarkets
|
|
26
26
|
|
27
27
|
# Turns the `:days` and `:from` options into a hash with `:from` and `:to` keys that can be passed to
|
28
28
|
# {AccountMethods#activities} and {AccountMethods#transactions}.
|
29
|
-
#
|
30
|
-
# @return [Hash]
|
31
29
|
def history_options
|
32
30
|
if options[:from]
|
33
31
|
from = Date.strptime options[:from], '%F'
|
@@ -68,10 +66,8 @@ module IGMarkets
|
|
68
66
|
@dealing_platform.sign_in options[:username], options[:password], options[:api_key], platform
|
69
67
|
|
70
68
|
yield @dealing_platform
|
71
|
-
rescue
|
72
|
-
|
73
|
-
rescue ArgumentError => argument_error
|
74
|
-
error "Argument error: #{argument_error}"
|
69
|
+
rescue IGMarketsError => error
|
70
|
+
warn_and_exit error
|
75
71
|
end
|
76
72
|
|
77
73
|
# Requests and displays the deal confirmation for the passed deal reference. If the request for the deal
|
@@ -86,8 +82,8 @@ module IGMarkets
|
|
86
82
|
5.times do |index|
|
87
83
|
begin
|
88
84
|
return print_deal_confirmation @dealing_platform.deal_confirmation(deal_reference)
|
89
|
-
rescue
|
90
|
-
raise if
|
85
|
+
rescue Errors::DealNotFoundError
|
86
|
+
raise if index == 4
|
91
87
|
|
92
88
|
puts 'Deal not found, retrying ...'
|
93
89
|
sleep 2
|
@@ -130,30 +126,30 @@ module IGMarkets
|
|
130
126
|
options.each_with_object({}) do |(key, value), new_hash|
|
131
127
|
next unless whitelist.include? key.to_sym
|
132
128
|
|
133
|
-
new_hash[key.to_sym] =
|
129
|
+
new_hash[key.to_sym] = value == key ? nil : value
|
134
130
|
end
|
135
131
|
end
|
136
132
|
|
137
133
|
private
|
138
134
|
|
139
|
-
#
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
135
|
+
# Prints the passed error to `stderr` and then exits the application.
|
136
|
+
def warn_and_exit(error)
|
137
|
+
class_name = error.class.name.split('::').last
|
138
|
+
|
139
|
+
message = error.message.to_s
|
140
|
+
message = nil if message.empty? || message == error.class.to_s
|
141
|
+
|
142
|
+
warn ["IG Markets: #{class_name}", message].compact.join(', ')
|
143
|
+
|
144
144
|
exit 1
|
145
145
|
end
|
146
146
|
|
147
147
|
# Returns the config file to use for this invocation.
|
148
|
-
#
|
149
|
-
# @return [ConfigFile]
|
150
148
|
def config_file
|
151
149
|
ConfigFile.find "#{Dir.pwd}/.ig_markets.yml", "#{Dir.home}/.ig_markets.yml"
|
152
150
|
end
|
153
151
|
|
154
152
|
# Prints out details of the passed deal confirmation.
|
155
|
-
#
|
156
|
-
# @param [DealConfirmation] deal_confirmation The deal confirmation to print out.
|
157
153
|
def print_deal_confirmation(deal_confirmation)
|
158
154
|
puts <<-END
|
159
155
|
Deal ID: #{deal_confirmation.deal_id}
|
@@ -167,8 +163,6 @@ END
|
|
167
163
|
end
|
168
164
|
|
169
165
|
# Prints out the profit/loss for the passed deal confirmation if applicable.
|
170
|
-
#
|
171
|
-
# @param [DealConfirmation] deal_confirmation The deal confirmation to print out the profit/loss for.
|
172
166
|
def print_deal_confirmation_profit_loss(deal_confirmation)
|
173
167
|
return unless deal_confirmation.profit
|
174
168
|
|
@@ -12,33 +12,51 @@ module IGMarkets
|
|
12
12
|
#
|
13
13
|
# See `README.md` for examples.
|
14
14
|
#
|
15
|
-
# If any errors occur while executing requests to the IG Markets API then {
|
15
|
+
# If any errors occur while executing requests to the IG Markets API then an {IGMarketsError} will be raised.
|
16
16
|
class DealingPlatform
|
17
|
-
#
|
17
|
+
# The session used by this dealing platform.
|
18
|
+
#
|
19
|
+
# @return [Session]
|
18
20
|
attr_reader :session
|
19
21
|
|
20
|
-
#
|
22
|
+
# The summary of the client account that is returned as part of a successful sign in.
|
23
|
+
#
|
24
|
+
# @return [ClientAccountSummary]
|
21
25
|
attr_reader :client_account_summary
|
22
26
|
|
23
|
-
#
|
27
|
+
# Methods for working with the logged in account.
|
28
|
+
#
|
29
|
+
# @return [AccountMethods]
|
24
30
|
attr_reader :account
|
25
31
|
|
26
|
-
#
|
32
|
+
# Methods for working with client sentiment.
|
33
|
+
#
|
34
|
+
# @return [ClientSentimentMethods]
|
27
35
|
attr_reader :client_sentiment
|
28
36
|
|
29
|
-
#
|
37
|
+
# Methods for working with markets.
|
38
|
+
#
|
39
|
+
# @return [MarketMethods]
|
30
40
|
attr_reader :markets
|
31
41
|
|
32
|
-
#
|
42
|
+
# Methods for working with positions.
|
43
|
+
#
|
44
|
+
# @return [PositionMethods]
|
33
45
|
attr_reader :positions
|
34
46
|
|
35
|
-
#
|
47
|
+
# Methods for working with sprint market positions.
|
48
|
+
#
|
49
|
+
# @return [SprintMarketPositionMethods]
|
36
50
|
attr_reader :sprint_market_positions
|
37
51
|
|
38
|
-
#
|
52
|
+
# Methods for working with watchlists.
|
53
|
+
#
|
54
|
+
# @return [WatchlistMethods]
|
39
55
|
attr_reader :watchlists
|
40
56
|
|
41
|
-
#
|
57
|
+
# Methods for working with working orders.
|
58
|
+
#
|
59
|
+
# @return [WorkingOrderMethods]
|
42
60
|
attr_reader :working_orders
|
43
61
|
|
44
62
|
def initialize
|
@@ -0,0 +1,323 @@
|
|
1
|
+
module IGMarkets
|
2
|
+
# Base class for all errors raised by this gem.
|
3
|
+
class IGMarketsError < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
# This module contains all the error classes for this gem. They all subclass {IGMarketsError}.
|
7
|
+
module Errors
|
8
|
+
# This error is raised when the specified account is invalid.
|
9
|
+
class InvalidClientAccountError < IGMarketsError
|
10
|
+
end
|
11
|
+
|
12
|
+
# This error is raised when the API key can't be used for this endpoint.
|
13
|
+
class APIKeyRejectedError < IGMarketsError
|
14
|
+
end
|
15
|
+
|
16
|
+
# This error is raised when a specified deal can't be found.
|
17
|
+
class DealNotFoundError < IGMarketsError
|
18
|
+
end
|
19
|
+
|
20
|
+
# This error is raised when an invalid date range is specified.
|
21
|
+
class InvalidDateRangeError < IGMarketsError
|
22
|
+
end
|
23
|
+
|
24
|
+
# This error is raised when an invalid watchlist name is specified.
|
25
|
+
class InvalidWatchlistError < IGMarketsError
|
26
|
+
end
|
27
|
+
|
28
|
+
# This error is raised when a malformed date is specified.
|
29
|
+
class MalformedDateError < IGMarketsError
|
30
|
+
end
|
31
|
+
|
32
|
+
# This error is raised when a specified position can't be found.
|
33
|
+
class PositionNotFoundError < IGMarketsError
|
34
|
+
end
|
35
|
+
|
36
|
+
# This error is raised when a generic position error occurs.
|
37
|
+
class PositionError < IGMarketsError
|
38
|
+
end
|
39
|
+
|
40
|
+
# This error is raised when a specified EPIC can't be found.
|
41
|
+
class EPICNotFoundError < IGMarketsError
|
42
|
+
end
|
43
|
+
|
44
|
+
# This error is raised when the account's traffic allowance is exceeded.
|
45
|
+
class ExceededAccountAllowanceError < IGMarketsError
|
46
|
+
end
|
47
|
+
|
48
|
+
# This error is raised when the account's historical data allowance is exceeded.
|
49
|
+
class ExceededAccountHistoricalDataAllowanceError < IGMarketsError
|
50
|
+
end
|
51
|
+
|
52
|
+
# This error is raised when the account's trading allowance is exceeded.
|
53
|
+
class ExceededAccountTradingAllowanceError < IGMarketsError
|
54
|
+
end
|
55
|
+
|
56
|
+
# This error is raised when the API key's allowance is exceeded.
|
57
|
+
class ExceededAPIKeyAllowanceError < IGMarketsError
|
58
|
+
end
|
59
|
+
|
60
|
+
# This error is raised when trying to login with an unencrypted password to a server that requires encryption.
|
61
|
+
class EncryptionRequiredError < IGMarketsError
|
62
|
+
end
|
63
|
+
|
64
|
+
# This error is raised when required KYC (Know Your Client) authorization for this account is incomplete.
|
65
|
+
class KYCRequiredForAccountError < IGMarketsError
|
66
|
+
end
|
67
|
+
|
68
|
+
# This error is raised when relevant credentials are not supplied.
|
69
|
+
class MissingCredentialsError < IGMarketsError
|
70
|
+
end
|
71
|
+
|
72
|
+
# This error is raised when the account has pending agreements that must be agreed to before using the account.
|
73
|
+
class PendingAgreementsError < IGMarketsError
|
74
|
+
end
|
75
|
+
|
76
|
+
# This error is raised when the preferred account is disabled.
|
77
|
+
class PreferredAccountDisabledError < IGMarketsError
|
78
|
+
end
|
79
|
+
|
80
|
+
# This error is raised when the preferred account is not set.
|
81
|
+
class PreferredAccountNotSetError < IGMarketsError
|
82
|
+
end
|
83
|
+
|
84
|
+
# This error is raised when stockbroking is not supported.
|
85
|
+
class StockbrokingNotSupportedError < IGMarketsError
|
86
|
+
end
|
87
|
+
|
88
|
+
# This error is raised when too many EPICs are specified for a request.
|
89
|
+
class TooManyEPICSError < IGMarketsError
|
90
|
+
end
|
91
|
+
|
92
|
+
# This error is raised when the account has been denied login privileges.
|
93
|
+
class AccountAccessDeniedError < IGMarketsError
|
94
|
+
end
|
95
|
+
|
96
|
+
# This error is raised when the account has been migrated to the client-account model and should be authenticated
|
97
|
+
# with the relevant client credentials.
|
98
|
+
class AccountMigratedError < IGMarketsError
|
99
|
+
end
|
100
|
+
|
101
|
+
# This error is raised when the account has not yet been activated.
|
102
|
+
class AccountNotYetActivatedError < IGMarketsError
|
103
|
+
end
|
104
|
+
|
105
|
+
# This error is raised when the the account has been suspended.
|
106
|
+
class AccountSuspendedError < IGMarketsError
|
107
|
+
end
|
108
|
+
|
109
|
+
# This error is raised when the service requires an account token but the one given was invalid.
|
110
|
+
class AccountTokenInvalidError < IGMarketsError
|
111
|
+
end
|
112
|
+
|
113
|
+
# This error is raised when the service requires an account token but none was specified.
|
114
|
+
class AccountTokenMissingError < IGMarketsError
|
115
|
+
end
|
116
|
+
|
117
|
+
# This error is raised when all accounts are in the 'pending' state.
|
118
|
+
class AllAccountsPendingError < IGMarketsError
|
119
|
+
end
|
120
|
+
|
121
|
+
# This error is raised when all accounts are in the 'suspended' state.
|
122
|
+
class AllAccountsSuspendedError < IGMarketsError
|
123
|
+
end
|
124
|
+
|
125
|
+
# This error is raised when the specified API key is not enabled.
|
126
|
+
class APIKeyDisabledError < IGMarketsError
|
127
|
+
end
|
128
|
+
|
129
|
+
# This error is raised when the specified API key is invalid.
|
130
|
+
class APIKeyInvalidError < IGMarketsError
|
131
|
+
end
|
132
|
+
|
133
|
+
# This error is raised when no API key was specified.
|
134
|
+
class APIKeyMissingError < IGMarketsError
|
135
|
+
end
|
136
|
+
|
137
|
+
# This error is raised when the specified API key is not valid for the requested account.
|
138
|
+
class APIKeyRestrictedError < IGMarketsError
|
139
|
+
end
|
140
|
+
|
141
|
+
# This error is raised when the specified API key has been revoked.
|
142
|
+
class APIKeyRevokedError < IGMarketsError
|
143
|
+
end
|
144
|
+
|
145
|
+
# This error is raised when the client has been suspended from using the platform.
|
146
|
+
class ClientSuspendedError < IGMarketsError
|
147
|
+
end
|
148
|
+
|
149
|
+
# This error is raised when the specified client token is invalid.
|
150
|
+
class ClientTokenInvalidError < IGMarketsError
|
151
|
+
end
|
152
|
+
|
153
|
+
# This error is raised when no client token was specified.
|
154
|
+
class ClientTokenMissingError < IGMarketsError
|
155
|
+
end
|
156
|
+
|
157
|
+
# This error is raised when there is a generic security error.
|
158
|
+
class SecurityError < IGMarketsError
|
159
|
+
end
|
160
|
+
|
161
|
+
# This error is raised when the provided user agent string is not valid.
|
162
|
+
class InvalidApplicationError < IGMarketsError
|
163
|
+
end
|
164
|
+
|
165
|
+
# This error is raised when the specified user credentials are not valid.
|
166
|
+
class InvalidCredentialsError < IGMarketsError
|
167
|
+
end
|
168
|
+
|
169
|
+
# This error is raised when the requested site is not accessible through the API.
|
170
|
+
class InvalidWebsiteError < IGMarketsError
|
171
|
+
end
|
172
|
+
|
173
|
+
# This error is raised when there have been too many failed login attempts.
|
174
|
+
class TooManyFailedLoginAttemptsError < IGMarketsError
|
175
|
+
end
|
176
|
+
|
177
|
+
# This error is raised when an invalid EPIC was used when interacting with a watchlist.
|
178
|
+
class WatchlistInvalidEPICError < IGMarketsError
|
179
|
+
end
|
180
|
+
|
181
|
+
# This error is raised when trying to set the current account to the current account.
|
182
|
+
class AccountAlreadyCurrentError < IGMarketsError
|
183
|
+
end
|
184
|
+
|
185
|
+
# This error is raised when setting the default account is not allowed.
|
186
|
+
class CannotSetDefaultAccountError < IGMarketsError
|
187
|
+
end
|
188
|
+
|
189
|
+
# This error is raised when an invalid account ID was specified.
|
190
|
+
class InvalidAccountIDError < IGMarketsError
|
191
|
+
end
|
192
|
+
|
193
|
+
# This error is raised when an unsupported EPIC was specified.
|
194
|
+
class UnsupportedEPICError < IGMarketsError
|
195
|
+
end
|
196
|
+
|
197
|
+
# This error is raised when trying to delete a watchlist that can't be deleted.
|
198
|
+
class CannotDeleteWatchlistError < IGMarketsError
|
199
|
+
end
|
200
|
+
|
201
|
+
# This error is raised when trying to set two watchlists to have the same name.
|
202
|
+
class DuplicateWatchlistNameError < IGMarketsError
|
203
|
+
end
|
204
|
+
|
205
|
+
# This error is raised when a generic watchlist error occurs.
|
206
|
+
class WatchlistError < IGMarketsError
|
207
|
+
end
|
208
|
+
|
209
|
+
# This error is raised when the specified watchlist could not be found.
|
210
|
+
class WatchlistNotFoundError < IGMarketsError
|
211
|
+
end
|
212
|
+
|
213
|
+
# This error is raised when invalid input was supplied.
|
214
|
+
class InvalidInputError < IGMarketsError
|
215
|
+
end
|
216
|
+
|
217
|
+
# This error is raised when an invalid URL was specified.
|
218
|
+
class InvalidURLError < IGMarketsError
|
219
|
+
end
|
220
|
+
|
221
|
+
# This error is raised when a generic system error occurs.
|
222
|
+
class SystemError < IGMarketsError
|
223
|
+
end
|
224
|
+
|
225
|
+
# This error is raised when trying attempting unauthorised access to an equity.
|
226
|
+
class UnauthorisedAccessToEquityError < IGMarketsError
|
227
|
+
end
|
228
|
+
|
229
|
+
# This error is raised when the specified API key is not valid for the client.
|
230
|
+
class InvalidAPIKeyForClientError < IGMarketsError
|
231
|
+
end
|
232
|
+
|
233
|
+
# This error is raised when invalid JSON is returned by the IG Markets API.
|
234
|
+
class InvalidJSONError < IGMarketsError
|
235
|
+
end
|
236
|
+
|
237
|
+
# This error is raised when an HTTP connection error occurs.
|
238
|
+
class ConnectionError < IGMarketsError
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# Base class for all errors raised by this gem.
|
243
|
+
class IGMarketsError
|
244
|
+
# Takes an IG Markets error code and returns an instance of the relevant error class that should be raised in
|
245
|
+
# response to the error.
|
246
|
+
#
|
247
|
+
# @param [String] error_code The error code.
|
248
|
+
#
|
249
|
+
# @return [LightstreamerError]
|
250
|
+
#
|
251
|
+
# @private
|
252
|
+
def self.build(error_code)
|
253
|
+
if API_ERROR_CODE_TO_CLASS.key? error_code
|
254
|
+
API_ERROR_CODE_TO_CLASS[error_code].new ''
|
255
|
+
else
|
256
|
+
new error_code
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
API_ERROR_CODE_TO_CLASS = {
|
261
|
+
'authentication.failure.not-a-client-account' => Errors::InvalidClientAccountError,
|
262
|
+
'endpoint.unavailable.for.api-key' => Errors::APIKeyRejectedError,
|
263
|
+
'error.confirms.deal-not-found' => Errors::DealNotFoundError,
|
264
|
+
'error.invalid.daterange' => Errors::InvalidDateRangeError,
|
265
|
+
'error.invalid.watchlist' => Errors::InvalidWatchlistError,
|
266
|
+
'error.malformed.date' => Errors::MalformedDateError,
|
267
|
+
'error.position.notfound' => Errors::PositionNotFoundError,
|
268
|
+
'error.positions.generic' => Errors::PositionError,
|
269
|
+
'error.public-api.epic-not-found' => Errors::EPICNotFoundError,
|
270
|
+
'error.public-api.exceeded-account-allowance' => Errors::ExceededAccountAllowanceError,
|
271
|
+
'error.public-api.exceeded-account-historical-data-allowance' =>
|
272
|
+
Errors::ExceededAccountHistoricalDataAllowanceError,
|
273
|
+
'error.public-api.exceeded-account-trading-allowance' => Errors::ExceededAccountTradingAllowanceError,
|
274
|
+
'error.public-api.exceeded-api-key-allowance' => Errors::ExceededAPIKeyAllowanceError,
|
275
|
+
'error.public-api.failure.encryption.required' => Errors::EncryptionRequiredError,
|
276
|
+
'error.public-api.failure.kyc.required' => Errors::KYCRequiredForAccountError,
|
277
|
+
'error.public-api.failure.missing.credentials' => Errors::MissingCredentialsError,
|
278
|
+
'error.public-api.failure.pending.agreements.required' => Errors::PendingAgreementsError,
|
279
|
+
'error.public-api.failure.preferred.account.disabled' => Errors::PreferredAccountDisabledError,
|
280
|
+
'error.public-api.failure.preferred.account.not.set' => Errors::PreferredAccountNotSetError,
|
281
|
+
'error.public-api.failure.stockbroking-not-supported' => Errors::StockbrokingNotSupportedError,
|
282
|
+
'error.public-api.too-many-epics' => Errors::TooManyEPICSError,
|
283
|
+
'error.security.account-access-denied' => Errors::AccountAccessDeniedError,
|
284
|
+
'error.security.account-migrated' => Errors::AccountMigratedError,
|
285
|
+
'error.security.account-not-yet-activated' => Errors::AccountNotYetActivatedError,
|
286
|
+
'error.security.account-suspended' => Errors::AccountSuspendedError,
|
287
|
+
'error.security.account-token-invalid' => Errors::AccountTokenInvalidError,
|
288
|
+
'error.security.account-token-missing' => Errors::AccountTokenMissingError,
|
289
|
+
'error.security.all-accounts-pending' => Errors::AllAccountsPendingError,
|
290
|
+
'error.security.all-accounts-suspended' => Errors::AllAccountsSuspendedError,
|
291
|
+
'error.security.api-key-disabled' => Errors::APIKeyDisabledError,
|
292
|
+
'error.security.api-key-invalid' => Errors::APIKeyInvalidError,
|
293
|
+
'error.security.api-key-missing' => Errors::APIKeyMissingError,
|
294
|
+
'error.security.api-key-restricted' => Errors::APIKeyRestrictedError,
|
295
|
+
'error.security.api-key-revoked' => Errors::APIKeyRevokedError,
|
296
|
+
'error.security.client-suspended' => Errors::ClientSuspendedError,
|
297
|
+
'error.security.client-token-invalid' => Errors::ClientTokenInvalidError,
|
298
|
+
'error.security.client-token-missing' => Errors::ClientTokenMissingError,
|
299
|
+
'error.security.generic' => Errors::SecurityError,
|
300
|
+
'error.security.invalid-application' => Errors::InvalidApplicationError,
|
301
|
+
'error.security.invalid-details' => Errors::InvalidCredentialsError,
|
302
|
+
'error.security.invalid-website' => Errors::InvalidWebsiteError,
|
303
|
+
'error.security.too-many-failed-attempts' => Errors::TooManyFailedLoginAttemptsError,
|
304
|
+
'error.service.watchlists.add-instrument.invalid-epic' => Errors::WatchlistInvalidEPICError,
|
305
|
+
'error.switch.accountId-must-be-different' => Errors::AccountAlreadyCurrentError,
|
306
|
+
'error.switch.cannot-set-default-account' => Errors::CannotSetDefaultAccountError,
|
307
|
+
'error.switch.invalid-accountId' => Errors::InvalidAccountIDError,
|
308
|
+
'error.unsupported.epic' => Errors::UnsupportedEPICError,
|
309
|
+
'error.watchlists.management.cannot-delete-watchlist' => Errors::CannotDeleteWatchlistError,
|
310
|
+
'error.watchlists.management.duplicate-name' => Errors::DuplicateWatchlistNameError,
|
311
|
+
'error.watchlists.management.error' => Errors::WatchlistError,
|
312
|
+
'error.watchlists.management.watchlist-not-found' => Errors::WatchlistNotFoundError,
|
313
|
+
'invalid.input' => Errors::InvalidInputError,
|
314
|
+
'invalid.url' => Errors::InvalidURLError,
|
315
|
+
'system.error' => Errors::SystemError,
|
316
|
+
'unauthorised.access.to.equity.exception' => Errors::UnauthorisedAccessToEquityError,
|
317
|
+
'unauthorised.api-key.revoked' => Errors::APIKeyRevokedError,
|
318
|
+
'unauthorised.clientId.api-key.mismatch' => Errors::InvalidAPIKeyForClientError
|
319
|
+
}.freeze
|
320
|
+
|
321
|
+
private_constant :API_ERROR_CODE_TO_CLASS
|
322
|
+
end
|
323
|
+
end
|
data/lib/ig_markets/format.rb
CHANGED
data/lib/ig_markets/model.rb
CHANGED
@@ -3,7 +3,9 @@ module IGMarkets
|
|
3
3
|
# attribute is defined by a call to {attribute}. Attributes have standard getter and setter methods and can also
|
4
4
|
# be subject to a variety of constraints and validations, see {attribute} for further details.
|
5
5
|
class Model
|
6
|
-
#
|
6
|
+
# The current attribute values set on this model.
|
7
|
+
#
|
8
|
+
# @return [Hash]
|
7
9
|
attr_reader :attributes
|
8
10
|
|
9
11
|
# Initializes this new model with the given attribute values. Attributes not known to this model will raise
|
@@ -74,10 +76,14 @@ module IGMarkets
|
|
74
76
|
end
|
75
77
|
|
76
78
|
class << self
|
77
|
-
#
|
79
|
+
# A hash containing details of all attributes that have been defined on this model.
|
80
|
+
#
|
81
|
+
# @return [Hash]
|
78
82
|
attr_accessor :defined_attributes
|
79
83
|
|
80
|
-
#
|
84
|
+
# The names of the deprecated attributes on this model.
|
85
|
+
#
|
86
|
+
# @return [Array]
|
81
87
|
attr_accessor :deprecated_attributes
|
82
88
|
|
83
89
|
# Returns the names of all currently defined attributes for this model.
|
@@ -1,10 +1,16 @@
|
|
1
1
|
module IGMarkets
|
2
2
|
# Encrypts account passwords in the manner required for authentication with the IG Markets API.
|
3
|
+
#
|
4
|
+
# @private
|
3
5
|
class PasswordEncryptor
|
4
|
-
#
|
6
|
+
# The public key used by {#encrypt}, can also be set using {#encoded_public_key=}.
|
7
|
+
#
|
8
|
+
# @return [OpenSSL::PKey::RSA]
|
5
9
|
attr_accessor :public_key
|
6
10
|
|
7
|
-
#
|
11
|
+
# The time stamp used by {#encrypt}.
|
12
|
+
#
|
13
|
+
# @return [String]
|
8
14
|
attr_accessor :time_stamp
|
9
15
|
|
10
16
|
# Initializes this password encryptor with the specified encoded public key and timestamp.
|
data/lib/ig_markets/regex.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
module IGMarkets
|
2
2
|
# This class contains methods for printing a REST request and its JSON response for inspection and debugging.
|
3
3
|
# Request printing is enabled by setting {enabled} to `true`.
|
4
|
+
#
|
5
|
+
# @private
|
4
6
|
class RequestPrinter
|
5
7
|
class << self
|
6
|
-
#
|
8
|
+
# Whether the request printer is enabled.
|
9
|
+
#
|
10
|
+
# @return [Boolean]
|
7
11
|
attr_accessor :enabled
|
8
12
|
|
9
13
|
# Prints out an options hash that is ready to be passed to `RestClient::Request.execute`.
|
@@ -1,25 +1,16 @@
|
|
1
1
|
module IGMarkets
|
2
2
|
# Contains methods for parsing responses received from the IG Markets API.
|
3
|
+
#
|
4
|
+
# @private
|
3
5
|
module ResponseParser
|
4
6
|
module_function
|
5
7
|
|
6
|
-
# Parses the passed JSON string and then passes it on to {parse}. If `json` is not valid JSON then `{}` is returned.
|
7
|
-
#
|
8
|
-
# @param [String] json The JSON string.
|
9
|
-
#
|
10
|
-
# @return [Hash]
|
11
|
-
def parse_json(json)
|
12
|
-
parse JSON.parse(json)
|
13
|
-
rescue JSON::ParserError
|
14
|
-
{}
|
15
|
-
end
|
16
|
-
|
17
8
|
# Parses the specified value that was returned from a call to the IG Markets API.
|
18
9
|
#
|
19
|
-
# @param [Hash, Array, Object] response The response or part of a
|
10
|
+
# @param [Hash, Array, Object] response The response or part of a response that should be parsed. If this is of type
|
20
11
|
# `Hash` then all hash keys will converted from camel case into snake case and their values each to parsed
|
21
|
-
# individually by a recursive call. If this is of type `Array` then each item will be parsed
|
22
|
-
# recursive call. All other types are passed through unchanged.
|
12
|
+
# individually by a recursive call. If this is of type `Array` then each item will be parsed individually by
|
13
|
+
# a recursive call. All other types are passed through unchanged.
|
23
14
|
#
|
24
15
|
# @return [Hash, Array, Object] The parsed object, the type depends on the type of the `response` parameter.
|
25
16
|
def parse(response)
|
data/lib/ig_markets/session.rb
CHANGED
@@ -3,45 +3,55 @@ module IGMarkets
|
|
3
3
|
# In order to sign in, {#username}, {#password}, {#api_key} and {#platform} must be set. {#platform} must be
|
4
4
|
# either `:demo` or `:live` depending on which platform is being targeted.
|
5
5
|
class Session
|
6
|
-
#
|
6
|
+
# The username to use to authenticate this session.
|
7
|
+
#
|
8
|
+
# @return [String]
|
7
9
|
attr_accessor :username
|
8
10
|
|
9
|
-
#
|
11
|
+
# The password to use to authenticate this session.
|
12
|
+
#
|
13
|
+
# @return [String]
|
10
14
|
attr_accessor :password
|
11
15
|
|
12
|
-
#
|
16
|
+
# The API key to use to authenticate this session.
|
17
|
+
#
|
18
|
+
# @return [String]
|
13
19
|
attr_accessor :api_key
|
14
20
|
|
15
|
-
#
|
21
|
+
# The platform variant to log into for this session.
|
22
|
+
#
|
23
|
+
# @return [:demo, :live]
|
16
24
|
attr_accessor :platform
|
17
25
|
|
18
|
-
#
|
19
|
-
#
|
26
|
+
# The client session security access token for the currently logged in session, or `nil` if there is no active
|
27
|
+
# session.
|
28
|
+
#
|
29
|
+
# @return [String]
|
20
30
|
attr_reader :client_security_token
|
21
31
|
|
22
|
-
#
|
23
|
-
#
|
32
|
+
# The account session security access token for the currently logged in session, or `nil` if there is no active
|
33
|
+
# session.
|
34
|
+
#
|
35
|
+
# @return [String]
|
24
36
|
attr_reader :x_security_token
|
25
37
|
|
26
38
|
# Signs in to IG Markets using the values of {#username}, {#password}, {#api_key} and {#platform}. If an error
|
27
|
-
# occurs then {
|
39
|
+
# occurs then an {IGMarketsError} will be raised.
|
28
40
|
#
|
29
41
|
# @return [Hash] The data returned in the body of the sign in request.
|
30
42
|
def sign_in
|
31
|
-
|
43
|
+
body = { identifier: username, password: password_encryptor.encrypt(password), encryptedPassword: true }
|
32
44
|
|
33
|
-
|
34
|
-
|
35
|
-
sign_in_result = request method: :post, url: 'session', payload: payload, api_version: API_V2
|
45
|
+
sign_in_result = request method: :post, url: 'session', body: body, api_version: API_V2
|
36
46
|
|
37
47
|
headers = sign_in_result.fetch(:response).headers
|
38
|
-
@client_security_token = headers.fetch
|
39
|
-
@x_security_token = headers.fetch
|
48
|
+
@client_security_token = headers.fetch 'CST'
|
49
|
+
@x_security_token = headers.fetch 'X-SECURITY-TOKEN'
|
40
50
|
|
41
|
-
sign_in_result.fetch :
|
51
|
+
sign_in_result.fetch :body
|
42
52
|
end
|
43
53
|
|
44
|
-
# Signs out of IG Markets, ending the current session (if any). If an error occurs then {
|
54
|
+
# Signs out of IG Markets, ending the current session (if any). If an error occurs then an {IGMarketsError} will be
|
45
55
|
# raised.
|
46
56
|
def sign_out
|
47
57
|
delete 'session' if alive?
|
@@ -56,61 +66,53 @@ module IGMarkets
|
|
56
66
|
!client_security_token.nil? && !x_security_token.nil?
|
57
67
|
end
|
58
68
|
|
59
|
-
# Sends a POST request to the IG Markets API. If an error occurs then {
|
69
|
+
# Sends a POST request to the IG Markets API. If an error occurs then an {IGMarketsError} will be raised.
|
60
70
|
#
|
61
71
|
# @param [String] url The URL to send the POST request to.
|
62
|
-
# @param [
|
72
|
+
# @param [Hash, nil] body The body to include with the POST request, this will be encoded as JSON.
|
63
73
|
# @param [Fixnum] api_version The API version to target.
|
64
74
|
#
|
65
75
|
# @return [Hash] The response from the IG Markets API.
|
66
|
-
def post(url,
|
67
|
-
request(method: :post, url: url,
|
76
|
+
def post(url, body, api_version = API_V1)
|
77
|
+
request(method: :post, url: url, body: body, api_version: api_version).fetch :body
|
68
78
|
end
|
69
79
|
|
70
|
-
# Sends a GET request to the IG Markets API. If an error occurs then {
|
80
|
+
# Sends a GET request to the IG Markets API. If an error occurs then an {IGMarketsError} will be raised.
|
71
81
|
#
|
72
82
|
# @param [String] url The URL to send the GET request to.
|
73
83
|
# @param [Fixnum] api_version The API version to target.
|
74
84
|
#
|
75
85
|
# @return [Hash] The response from the IG Markets API.
|
76
86
|
def get(url, api_version = API_V1)
|
77
|
-
request(method: :get, url: url, api_version: api_version).fetch :
|
87
|
+
request(method: :get, url: url, api_version: api_version).fetch :body
|
78
88
|
end
|
79
89
|
|
80
|
-
# Sends a PUT request to the IG Markets API. If an error occurs then {
|
90
|
+
# Sends a PUT request to the IG Markets API. If an error occurs then an {IGMarketsError} will be raised.
|
81
91
|
#
|
82
92
|
# @param [String] url The URL to send the PUT request to.
|
83
|
-
# @param [
|
93
|
+
# @param [Hash, nil] body The body to include with the PUT request, this will be encoded as JSON.
|
84
94
|
# @param [Fixnum] api_version The API version to target.
|
85
95
|
#
|
86
96
|
# @return [Hash] The response from the IG Markets API.
|
87
|
-
def put(url,
|
88
|
-
request(method: :put, url: url,
|
97
|
+
def put(url, body = nil, api_version = API_V1)
|
98
|
+
request(method: :put, url: url, body: body, api_version: api_version).fetch :body
|
89
99
|
end
|
90
100
|
|
91
|
-
# Sends a DELETE request to the IG Markets API. If an error occurs then {
|
101
|
+
# Sends a DELETE request to the IG Markets API. If an error occurs then an {IGMarketsError} will be raised.
|
92
102
|
#
|
93
103
|
# @param [String] url The URL to send the DELETE request to.
|
94
|
-
# @param [
|
104
|
+
# @param [Hash, nil] body The body to include with the DELETE request, this will be encoded as JSON.
|
95
105
|
# @param [Fixnum] api_version The API version to target.
|
96
106
|
#
|
97
107
|
# @return [Hash] The response from the IG Markets API.
|
98
|
-
def delete(url,
|
99
|
-
request(method: :delete, url: url,
|
108
|
+
def delete(url, body = nil, api_version = API_V1)
|
109
|
+
request(method: :delete, url: url, body: body, api_version: api_version).fetch :body
|
100
110
|
end
|
101
111
|
|
102
112
|
private
|
103
113
|
|
104
114
|
HOST_URLS = { demo: 'https://demo-api.ig.com/gateway/deal/', live: 'https://api.ig.com/gateway/deal/' }.freeze
|
105
115
|
|
106
|
-
def validate_authentication
|
107
|
-
%i(username password api_key).each do |attribute|
|
108
|
-
raise ArgumentError, "#{attribute} is not set" if send(attribute).to_s.empty?
|
109
|
-
end
|
110
|
-
|
111
|
-
raise ArgumentError, 'platform is invalid' unless HOST_URLS.key? platform
|
112
|
-
end
|
113
|
-
|
114
116
|
def password_encryptor
|
115
117
|
result = get 'session/encryptionKey'
|
116
118
|
|
@@ -120,76 +122,73 @@ module IGMarkets
|
|
120
122
|
def request(options)
|
121
123
|
options[:url] = "#{HOST_URLS.fetch(platform)}#{URI.escape(options[:url])}"
|
122
124
|
options[:headers] = request_headers(options)
|
123
|
-
options[:payload] = options[:payload] && options[:payload].to_json
|
124
|
-
|
125
|
-
RequestPrinter.print_options options
|
126
|
-
|
127
|
-
response = execute_request options
|
128
125
|
|
129
|
-
|
126
|
+
# The IG Markets API requires that DELETE requests with a body are sent as POST requests with a special header
|
127
|
+
if options[:method] == :delete && options[:body]
|
128
|
+
options[:headers]['_method'] = 'DELETE'
|
129
|
+
options[:method] = :post
|
130
|
+
end
|
130
131
|
|
131
|
-
|
132
|
+
options[:body] = options[:body] && options[:body].to_json
|
132
133
|
|
133
|
-
|
134
|
+
execute_request options
|
134
135
|
end
|
135
136
|
|
136
137
|
def request_headers(options)
|
137
138
|
headers = {}
|
138
139
|
|
139
|
-
headers[
|
140
|
-
headers[
|
141
|
-
headers[
|
140
|
+
headers['Content-Type'] = headers['Accept'] = 'application/json; charset=UTF-8'
|
141
|
+
headers['X-IG-API-KEY'] = api_key
|
142
|
+
headers['Version'] = options.delete :api_version
|
142
143
|
|
143
|
-
headers[
|
144
|
-
headers[
|
144
|
+
headers['CST'] = client_security_token if client_security_token
|
145
|
+
headers['X-SECURITY-TOKEN'] = x_security_token if x_security_token
|
145
146
|
|
146
147
|
headers
|
147
148
|
end
|
148
149
|
|
149
|
-
def use_post_for_delete_with_payload(options)
|
150
|
-
if options[:method] == :delete && options[:payload]
|
151
|
-
options[:headers]['_method'] = :delete
|
152
|
-
options[:method] = :post
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
150
|
def execute_request(options)
|
157
|
-
|
151
|
+
RequestPrinter.print_options options
|
158
152
|
|
159
|
-
|
160
|
-
rescue RestClient::Exception => exception
|
161
|
-
raise RequestFailedError, exception.message unless exception.response
|
153
|
+
response = Excon.send options[:method], options[:url], headers: options[:headers], body: options[:body]
|
162
154
|
|
163
|
-
|
155
|
+
RequestPrinter.print_response_body response.body
|
164
156
|
|
165
|
-
|
166
|
-
rescue
|
167
|
-
raise
|
157
|
+
process_response response, options
|
158
|
+
rescue Excon::Error => error
|
159
|
+
raise Errors::ConnectionError, error.message
|
168
160
|
end
|
169
161
|
|
170
|
-
def
|
171
|
-
|
162
|
+
def process_response(response, options)
|
163
|
+
body = parse_body response
|
172
164
|
|
173
|
-
if
|
174
|
-
|
175
|
-
return true
|
176
|
-
end
|
165
|
+
if body.key? :error_code
|
166
|
+
error = IGMarketsError.build body[:error_code]
|
177
167
|
|
178
|
-
|
179
|
-
sleep 5
|
180
|
-
return true
|
181
|
-
end
|
168
|
+
raise error unless should_retry_request? error, options
|
182
169
|
|
183
|
-
|
170
|
+
execute_request options.merge(retry: true)
|
171
|
+
else
|
172
|
+
{ response: response, body: body }
|
173
|
+
end
|
184
174
|
end
|
185
175
|
|
186
|
-
def
|
187
|
-
|
188
|
-
http_code = response.code
|
176
|
+
def parse_body(response)
|
177
|
+
return {} if response.body == ''
|
189
178
|
|
190
|
-
|
179
|
+
ResponseParser.parse JSON.parse(response.body)
|
180
|
+
rescue JSON::ParserError
|
181
|
+
raise Errors::InvalidJSONError, response.body
|
182
|
+
end
|
191
183
|
|
192
|
-
|
184
|
+
def should_retry_request?(error, options)
|
185
|
+
if error.is_a?(Errors::ClientTokenInvalidError) && !options[:retry]
|
186
|
+
sign_in
|
187
|
+
true
|
188
|
+
elsif error.is_a?(Errors::ExceededAPIKeyAllowanceError) || error.is_a?(Errors::ExceededAccountAllowanceError)
|
189
|
+
sleep 5
|
190
|
+
true
|
191
|
+
end
|
193
192
|
end
|
194
193
|
end
|
195
194
|
end
|
data/lib/ig_markets/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ig_markets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.17'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Viney
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-07-
|
11
|
+
date: 2016-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -25,33 +25,33 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0.8'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: excon
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: '0.51'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
40
|
+
version: '0.51'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: pry
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 0.10.4
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 0.10.4
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: terminal-table
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -184,14 +184,14 @@ dependencies:
|
|
184
184
|
requirements:
|
185
185
|
- - "~>"
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version: '0.
|
187
|
+
version: '0.42'
|
188
188
|
type: :development
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
192
|
- - "~>"
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version: '0.
|
194
|
+
version: '0.42'
|
195
195
|
- !ruby/object:Gem::Dependency
|
196
196
|
name: yard
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -263,6 +263,7 @@ files:
|
|
263
263
|
- lib/ig_markets/dealing_platform/sprint_market_position_methods.rb
|
264
264
|
- lib/ig_markets/dealing_platform/watchlist_methods.rb
|
265
265
|
- lib/ig_markets/dealing_platform/working_order_methods.rb
|
266
|
+
- lib/ig_markets/errors.rb
|
266
267
|
- lib/ig_markets/format.rb
|
267
268
|
- lib/ig_markets/historical_price_result.rb
|
268
269
|
- lib/ig_markets/instrument.rb
|
@@ -275,7 +276,6 @@ files:
|
|
275
276
|
- lib/ig_markets/payload_formatter.rb
|
276
277
|
- lib/ig_markets/position.rb
|
277
278
|
- lib/ig_markets/regex.rb
|
278
|
-
- lib/ig_markets/request_failed_error.rb
|
279
279
|
- lib/ig_markets/request_printer.rb
|
280
280
|
- lib/ig_markets/response_parser.rb
|
281
281
|
- lib/ig_markets/session.rb
|
@@ -307,6 +307,5 @@ rubyforge_project:
|
|
307
307
|
rubygems_version: 2.5.1
|
308
308
|
signing_key:
|
309
309
|
specification_version: 4
|
310
|
-
summary:
|
311
|
-
platform.
|
310
|
+
summary: Library and command-line client for accessing the IG Markets dealing platform.
|
312
311
|
test_files: []
|
@@ -1,21 +0,0 @@
|
|
1
|
-
module IGMarkets
|
2
|
-
# This error class is raised by {Session} when a request to the IG Markets API fails.
|
3
|
-
class RequestFailedError < StandardError
|
4
|
-
# @return [String] A description of the error that occurred when the request was attempted.
|
5
|
-
attr_reader :error
|
6
|
-
|
7
|
-
# @return [Fixnum] The HTTP code that was returned, or `nil` if unknown.
|
8
|
-
attr_reader :http_code
|
9
|
-
|
10
|
-
# Initializes this request failure error with a message and an HTTP code.
|
11
|
-
#
|
12
|
-
# @param [String] error The error description.
|
13
|
-
# @param [Integer] http_code The HTTP code for the request failure, if known.
|
14
|
-
def initialize(error, http_code = nil)
|
15
|
-
@error = error.to_s
|
16
|
-
@http_code = http_code ? http_code.to_i : nil
|
17
|
-
|
18
|
-
super "#<#{self.class.name} error: #{@error}#{http_code ? ", http_code: #{http_code}" : ''}>"
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|