ig_markets 0.16 → 0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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
|