ig_markets 0.8 → 0.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 905ebb175a410a5b6a86f1b92c215745e642e04b
4
- data.tar.gz: 6bb5b7d2360c936c46c2380002a15f632b853b63
3
+ metadata.gz: 8dd48141e03cc58042b6b5c14ae2f7d4a1a0b55c
4
+ data.tar.gz: 4c3467cc309a493209f646665b27b48eef0daa45
5
5
  SHA512:
6
- metadata.gz: 0abc1a40d8fb0c4ef98835c40cf525c129ea5623dc23cff94792034431d2109ce164dbbea6d1097fef176b599c3ae823d88d9aa1bb78f330a7a10ce919239aa9
7
- data.tar.gz: e0a4e9984d8eb1286ef8e92547512ec1cafb94fbdfc14bb152ffba9f9ff41072d8475b54805da3e1db7191bbf7b41ee958dc1f37e0e73ced7642e6a1f945cbb8
6
+ metadata.gz: 80af908f64fe291975ad4364a4cbc6b713f3f8f37df7dc0f15e2697cc5b4f4f2ee4ebf48c09ec41064f50b687930b45680645b51ec1299f8c3b56213783c8c95
7
+ data.tar.gz: 46e5518f0bcd7371ef63799da17e1b7d189b81a6a7a477ecd0e580b87e6ce48760a6a19d4d3eedea61517e227c359a413ac105212038dbcdcf5afeaf7d231fd6
@@ -1,8 +1,16 @@
1
1
  # IG Markets Changelog
2
2
 
3
+ ### 0.9 — May 2, 2016
4
+
5
+ - `IGMarkets::DealingPlatform#sign_in` now returns an `IGMarkets::ClientAccountSummary` instance
6
+ - `IGMarkets::DealingPlatform::MarketMethods#find` can now handle being passed more than 50 EPICs at once
7
+ - Renamed `--start-date` option for `ig_markets activities` and `ig_markets transactions` commands to `--from`
8
+ - Deal confirmations reported by the command-line client are now retried after a five second pause if the initial
9
+ request returns a 'deal not found' error
10
+
3
11
  ### 0.8 — April 30, 2016
4
12
 
5
- - The `ig_markets` prices command now takes `--from` and `--to` arguments accurate to one second
13
+ - The `ig_markets prices` command now takes `--from` and `--to` arguments accurate to one second
6
14
  - Fixed incomplete data being returned by `IGMarkets::DealingPlatform::AccountMethods#activities` and
7
15
  `IGMarkets::DealingPlatform::AccountMethods#transactions`
8
16
  - Fixed errors calling `IGMarkets::DealingPlatform#instantiate_models` for models that have deprecated attributes
data/README.md CHANGED
@@ -67,7 +67,7 @@ Use `ig_markets help` to get details on the options accepted by the commands and
67
67
  commands and their subcommands is:
68
68
 
69
69
  - `ig_markets account`
70
- - `ig_markets activities --days N [--start-date YYYY-MM-DD]`
70
+ - `ig_markets activities --days N [--from YYYY-MM-DD]`
71
71
  - `ig_markets confirmation DEAL-REFERENCE`
72
72
  - `ig_markets console`
73
73
  - `ig_markets help [COMMAND]`
@@ -84,7 +84,7 @@ commands and their subcommands is:
84
84
  - `ig_markets sentiment MARKET`
85
85
  - `ig_markets sprints [list]`
86
86
  - `ig_markets sprints create ...`
87
- - `ig_markets transactions --days N [--start-date YYYY-MM-DD] [--instrument INSTRUMENT] [--no-interest]`
87
+ - `ig_markets transactions --days N [--from YYYY-MM-DD] [--instrument INSTRUMENT] [--no-interest]`
88
88
  - `ig_markets watchlists [list]`
89
89
  - `ig_markets watchlists create NAME [EPIC EPIC ...]`
90
90
  - `ig_markets watchlists add-markets WATCHLIST-ID [EPIC EPIC ...]`
@@ -127,8 +127,8 @@ ig_markets orders create --direction buy --epic CS.D.EURUSD.CFD.IP --level 1.1 -
127
127
  # Print daily prices for EURUSD from the last two weeks
128
128
  ig_markets prices --epic CS.D.EURUSD.CFD.IP --resolution day --number 14
129
129
 
130
- # Log in and then open a live Ruby console which can be used to query the IG API
131
- ig_markets console
130
+ # Log in and then open a Ruby console which can be used to query the IG API, all REST requests will be printed in full
131
+ ig_markets console --print-requests
132
132
  ```
133
133
 
134
134
  ## Usage — Library
@@ -150,9 +150,9 @@ ig.sign_out
150
150
 
151
151
  # Account
152
152
  ig.account.all
153
- ig.account.activities days: 365
153
+ ig.account.activities days: 30
154
154
  ig.account.activities from: Date.today - 14, to: Date.today - 7
155
- ig.account.transactions days: 365
155
+ ig.account.transactions days: 30
156
156
  ig.account.transactions from: Date.today - 14, to: Date.today - 7
157
157
 
158
158
  # Dealing
@@ -15,6 +15,7 @@ require 'ig_markets/account'
15
15
  require 'ig_markets/activity'
16
16
  require 'ig_markets/api_versions'
17
17
  require 'ig_markets/application'
18
+ require 'ig_markets/client_account_summary'
18
19
  require 'ig_markets/client_sentiment'
19
20
  require 'ig_markets/deal_confirmation'
20
21
  require 'ig_markets/dealing_platform'
@@ -1,7 +1,7 @@
1
1
  module IGMarkets
2
2
  # Contains details on an IG Markets account. Returned by {DealingPlatform::AccountMethods#all}.
3
3
  class Account < Model
4
- # Contains details on the balance of an {Account}, used by {Account#balance}.
4
+ # Contains details on the balance of an {Account}, used by {#balance}.
5
5
  class Balance < Model
6
6
  attribute :available, Float
7
7
  attribute :balance, Float
@@ -5,11 +5,11 @@ module IGMarkets
5
5
  desc 'activities', 'Prints account activities'
6
6
 
7
7
  option :days, type: :numeric, required: true, desc: 'The number of days to print account activities for'
8
- option :start_date, desc: 'The start date to print account activities from, format: yyyy-mm-dd'
8
+ option :from, desc: 'The start date to print account activities from, format: yyyy-mm-dd'
9
9
 
10
10
  def activities
11
- self.class.begin_session(options) do |_dealing_platform|
12
- activities = gather_account_history(:activities).sort_by(&:date)
11
+ self.class.begin_session(options) do |dealing_platform|
12
+ activities = gather_account_history(:activities, dealing_platform).sort_by(&:date)
13
13
 
14
14
  table = ActivitiesTable.new activities
15
15
 
@@ -19,17 +19,17 @@ module IGMarkets
19
19
 
20
20
  private
21
21
 
22
- def gather_account_history(method_name)
23
- history_options = if options[:start_date]
24
- from = Date.strptime options[:start_date], '%F'
25
- to = from + options[:days].to_i
22
+ def gather_account_history(method_name, dealing_platform)
23
+ history_options = if options[:from]
24
+ from = Date.strptime options[:from], '%F'
25
+ to = from + options[:days]
26
26
 
27
27
  { from: from, to: to }
28
28
  else
29
29
  { days: options[:days] }
30
30
  end
31
31
 
32
- Main.dealing_platform.account.send method_name, history_options
32
+ dealing_platform.account.send method_name, history_options
33
33
  end
34
34
  end
35
35
  end
@@ -5,13 +5,13 @@ module IGMarkets
5
5
  desc 'transactions', 'Prints account transactions'
6
6
 
7
7
  option :days, type: :numeric, required: true, desc: 'The number of days to print account transactions for'
8
- option :start_date, desc: 'The start date to print account transactions from, format: yyyy-mm-dd'
8
+ option :from, desc: 'The start date to print account transactions from, format: yyyy-mm-dd'
9
9
  option :instrument, desc: 'Regex for filtering transactions based on their instrument'
10
10
  option :interest, type: :boolean, default: true, desc: 'Whether to show interest deposits and withdrawals'
11
11
 
12
12
  def transactions
13
- self.class.begin_session(options) do |_dealing_platform|
14
- transactions = gather_transactions
13
+ self.class.begin_session(options) do |dealing_platform|
14
+ transactions = gather_transactions dealing_platform
15
15
 
16
16
  table = TransactionsTable.new transactions
17
17
 
@@ -26,10 +26,10 @@ module IGMarkets
26
26
 
27
27
  private
28
28
 
29
- def gather_transactions
29
+ def gather_transactions(dealing_platform)
30
30
  regex = Regexp.new options.fetch('instrument', '')
31
31
 
32
- gather_account_history(:transactions).sort_by(&:date_utc).select do |transaction|
32
+ gather_account_history(:transactions, dealing_platform).sort_by(&:date_utc).select do |transaction|
33
33
  regex.match(transaction.instrument_name) && (options[:interest] || !transaction.interest?)
34
34
  end
35
35
  end
@@ -22,6 +22,23 @@ module IGMarkets
22
22
  subcommand 'watchlists', Watchlists
23
23
 
24
24
  class << self
25
+ # This is the initial entry point for the execution of the command-line client. It is responsible for reading
26
+ # any config files, implementing the --version/-v options, and then invoking the main application.
27
+ #
28
+ # @param [Array<String>] argv The array of command-line arguments.
29
+ #
30
+ # @return [void]
31
+ def bootstrap(argv)
32
+ config_file.prepend_arguments_to_argv argv
33
+
34
+ if argv.index('--version') || argv.index('-v')
35
+ puts VERSION
36
+ exit
37
+ end
38
+
39
+ start argv
40
+ end
41
+
25
42
  # Signs in to IG Markets and yields back a {DealingPlatform} instance, with common error handling if exceptions
26
43
  # occur. This method is used by all of the commands in order to authenticate.
27
44
  #
@@ -33,29 +50,19 @@ module IGMarkets
33
50
 
34
51
  RequestPrinter.enabled = true if options[:print_requests]
35
52
 
36
- dealing_platform.sign_in options[:username], options[:password], options[:api_key], platform
53
+ @dealing_platform ||= DealingPlatform.new
54
+ @dealing_platform.sign_in options[:username], options[:password], options[:api_key], platform
37
55
 
38
- yield dealing_platform
56
+ yield @dealing_platform
39
57
  rescue IGMarkets::RequestFailedError => error
40
58
  error "Request error: #{error.error}"
41
59
  rescue ArgumentError => error
42
60
  error "Argument error: #{error}"
43
61
  end
44
62
 
45
- # Writes the passed message to `stderr` and then exits the application.
46
- #
47
- # @param [String] message The error message.
48
- def error(message)
49
- warn message
50
- exit 1
51
- end
52
-
53
- # The {DealingPlatform} instance used by {begin_session}.
54
- def dealing_platform
55
- @dealing_platform ||= DealingPlatform.new
56
- end
57
-
58
- # Requests and displays the deal confirmation for the passed deal reference.
63
+ # Requests and displays the deal confirmation for the passed deal reference. If the first request for the deal
64
+ # confirmation returns a 'deal not found' error then the request is attempted again after a five second pause.
65
+ # This is done because sometimes there is a delay in the processing of the deal by IG Markets.
59
66
  #
60
67
  # @param [String] deal_reference The deal reference.
61
68
  #
@@ -63,15 +70,14 @@ module IGMarkets
63
70
  def report_deal_confirmation(deal_reference)
64
71
  puts "Deal reference: #{deal_reference}"
65
72
 
66
- deal_confirmation = dealing_platform.deal_confirmation deal_reference
73
+ print_deal_confirmation @dealing_platform.deal_confirmation(deal_reference)
74
+ rescue RequestFailedError => request_failed_error
75
+ raise unless request_failed_error.error == 'error.confirms.deal-not-found'
67
76
 
68
- puts <<-END
69
- Deal ID: #{deal_confirmation.deal_id}
70
- Status: #{Format.symbol deal_confirmation.deal_status}
71
- Result: #{Format.symbol deal_confirmation.status}
72
- END
77
+ puts 'Deal confirmation not found, pausing for five seconds before retrying ...'
73
78
 
74
- puts "Reason: #{Format.symbol deal_confirmation.reason}" unless deal_confirmation.deal_status == :accepted
79
+ sleep 5
80
+ print_deal_confirmation @dealing_platform.deal_confirmation(deal_reference)
75
81
  end
76
82
 
77
83
  # Parses and validates a `Date` or `Time` option received as a command-line argument. Raises `ArgumentError` if
@@ -115,21 +121,14 @@ END
115
121
  end
116
122
  end
117
123
 
118
- # This is the initial entry point for the execution of the command-line client. It is responsible for reading
119
- # any config files, implementing the --version/-v options, and then invoking the main application.
120
- #
121
- # @param [Array<String>] argv The array of command-line arguments.
122
- #
123
- # @return [void]
124
- def bootstrap(argv)
125
- config_file.prepend_arguments_to_argv argv
124
+ private
126
125
 
127
- if argv.index('--version') || argv.index('-v')
128
- puts VERSION
129
- exit
130
- end
131
-
132
- start argv
126
+ # Writes the passed message to `stderr` and then exits the application.
127
+ #
128
+ # @param [String] message The error message.
129
+ def error(message)
130
+ warn message
131
+ exit 1
133
132
  end
134
133
 
135
134
  # Returns the config file to use for this invocation.
@@ -138,6 +137,21 @@ END
138
137
  def config_file
139
138
  ConfigFile.find "#{Dir.pwd}/.ig_markets", "#{Dir.home}/.ig_markets"
140
139
  end
140
+
141
+ # Prints out details of the passed deal confirmation.
142
+ #
143
+ # @param [DealConfirmation] deal_confirmation The deal confirmation to print out.
144
+ #
145
+ # @return [void]
146
+ def print_deal_confirmation(deal_confirmation)
147
+ puts <<-END
148
+ Deal ID: #{deal_confirmation.deal_id}
149
+ Status: #{Format.symbol deal_confirmation.deal_status}
150
+ Result: #{Format.symbol deal_confirmation.status}
151
+ END
152
+
153
+ puts "Reason: #{Format.symbol deal_confirmation.reason}" unless deal_confirmation.deal_status == :accepted
154
+ end
141
155
  end
142
156
  end
143
157
  end
@@ -0,0 +1,41 @@
1
+ module IGMarkets
2
+ # Contains details on an IG Markets client account summary. Returned by {DealingPlatform#sign_in}.
3
+ class ClientAccountSummary < Model
4
+ # Contains details on a form, used by {#form_details}.
5
+ class FormDetails < Model
6
+ attribute :form_dismissable, Boolean
7
+ attribute :form_title
8
+ attribute :form_type, Symbol, allowed_values: [:bca, :kyc]
9
+ attribute :form_url
10
+ end
11
+
12
+ # Contains details on an account, used by {#accounts}.
13
+ class AccountDetails < Model
14
+ attribute :account_id
15
+ attribute :account_name
16
+ attribute :account_type, Symbol, allowed_values: [:cfd, :physical, :spreadbet]
17
+ attribute :preferred, Boolean
18
+ end
19
+
20
+ attribute :account_info, Account::Balance
21
+ attribute :account_type, Symbol, allowed_values: [:cfd, :physical, :spreadbet]
22
+ attribute :accounts, AccountDetails
23
+ attribute :authentication_status, Symbol, allowed_values: [
24
+ :authenticated, :authenticated_missing_credentials, :change_environment, :disabled_preferred_account,
25
+ :missing_preferred_account, :rejected_invalid_client_version]
26
+ attribute :client_id
27
+ attribute :currency_iso_code, String, regex: Regex::CURRENCY
28
+ attribute :currency_symbol
29
+ attribute :current_account_id
30
+ attribute :dealing_enabled, Boolean
31
+ attribute :encrypted
32
+ attribute :form_details, FormDetails
33
+ attribute :has_active_demo_accounts, Boolean
34
+ attribute :has_active_live_accounts, Boolean
35
+ attribute :ig_company
36
+ attribute :lightstreamer_endpoint
37
+ attribute :rerouting_environment, Symbol, allowed_values: [:demo, :live, :test, :uat]
38
+ attribute :timezone_offset, Float
39
+ attribute :trailing_stops_enabled, Boolean
40
+ end
41
+ end
@@ -56,13 +56,17 @@ module IGMarkets
56
56
  # @param [String] password The account password.
57
57
  # @param [String] api_key The account API key.
58
58
  # @param [:production, :demo] platform The platform to use.
59
+ #
60
+ # @return [ClientAccountSummary] The client account summary returned by the sign in request.
59
61
  def sign_in(username, password, api_key, platform)
60
62
  session.username = username
61
63
  session.password = password
62
64
  session.api_key = api_key
63
65
  session.platform = platform
64
66
 
65
- session.sign_in
67
+ result = session.sign_in
68
+
69
+ instantiate_models ClientAccountSummary, result
66
70
  end
67
71
 
68
72
  # Signs out of the IG Markets Dealing Platform, ending any current session.
@@ -37,9 +37,12 @@ module IGMarkets
37
37
  raise ArgumentError, "invalid EPIC: #{epic}" unless epic.to_s =~ Regex::EPIC
38
38
  end
39
39
 
40
- result = @dealing_platform.session.get("markets?epics=#{epics.join(',')}", API_V2).fetch :market_details
40
+ # The API imposes a maximum of 50 EPICs per request
41
+ markets = epics.each_slice(50).map do |epics_slice|
42
+ @dealing_platform.session.get("markets?epics=#{epics_slice.join(',')}", API_V2).fetch :market_details
43
+ end
41
44
 
42
- @dealing_platform.instantiate_models Market, result
45
+ @dealing_platform.instantiate_models Market, markets.flatten
43
46
  end
44
47
 
45
48
  # Searches markets using a search term and returns an array of results.
@@ -55,6 +55,8 @@ module IGMarkets
55
55
  :one_minute, :two_minutes, :five_minutes, :twenty_minutes, :sixty_minutes]
56
56
  attribute :size, Float
57
57
  end
58
+
59
+ private_constant :SprintMarketPositionCreateAttributes
58
60
  end
59
61
  end
60
62
  end
@@ -15,26 +15,30 @@ module IGMarkets
15
15
  # @return [:demo, :production] The platform variant to log into for this session.
16
16
  attr_accessor :platform
17
17
 
18
- # @return [String] The CST for the currently logged in session, or `nil` if there is no active session.
19
- attr_reader :cst
18
+ # @return [String] The client session security access token for the currently logged in session, or `nil` if there
19
+ # is no active session.
20
+ attr_reader :client_security_token
20
21
 
21
- # @return [String] The security token for the currently logged in session, or `nil` if there is no active session.
22
+ # @return [String] The account session security access token for the currently logged in session, or `nil` if there
23
+ # is no active session.
22
24
  attr_reader :x_security_token
23
25
 
24
26
  # Signs in to IG Markets using the values of {#username}, {#password}, {#api_key} and {#platform}. If an error
25
27
  # occurs then {RequestFailedError} will be raised.
28
+ #
29
+ # @return [Hash] The data returned in the body of the sign in request.
26
30
  def sign_in
27
31
  validate_authentication
28
32
 
29
33
  payload = { identifier: username, password: password_encryptor.encrypt(password), encryptedPassword: true }
30
34
 
31
- sign_in_result = request method: :post, url: 'session', payload: payload, api_version: API_V1
35
+ sign_in_result = request method: :post, url: 'session', payload: payload, api_version: API_V2
32
36
 
33
37
  headers = sign_in_result.fetch(:response).headers
34
- @cst = headers.fetch :cst
38
+ @client_security_token = headers.fetch :cst
35
39
  @x_security_token = headers.fetch :x_security_token
36
40
 
37
- nil
41
+ sign_in_result.fetch :result
38
42
  end
39
43
 
40
44
  # Signs out of IG Markets, ending the current session (if any). If an error occurs then {RequestFailedError} will be
@@ -42,14 +46,14 @@ module IGMarkets
42
46
  def sign_out
43
47
  delete 'session' if alive?
44
48
 
45
- @cst = @x_security_token = nil
49
+ @client_security_token = @x_security_token = nil
46
50
  end
47
51
 
48
52
  # Returns whether this session is currently alive and successfully signed in.
49
53
  #
50
54
  # @return [Boolean]
51
55
  def alive?
52
- !cst.nil? && !x_security_token.nil?
56
+ !client_security_token.nil? && !x_security_token.nil?
53
57
  end
54
58
 
55
59
  # Sends a POST request to the IG Markets API. If an error occurs then {RequestFailedError} will be raised.
@@ -99,7 +103,7 @@ module IGMarkets
99
103
  #
100
104
  # @return [String]
101
105
  def inspect
102
- "#<#{self.class.name} #{cst}, #{x_security_token}>"
106
+ "#<#{self.class.name} #{client_security_token}, #{x_security_token}>"
103
107
  end
104
108
 
105
109
  private
@@ -143,7 +147,7 @@ module IGMarkets
143
147
  headers[:'X-IG-API-KEY'] = api_key
144
148
  headers[:version] = options.delete :api_version
145
149
 
146
- headers[:cst] = cst if cst
150
+ headers[:cst] = client_security_token if client_security_token
147
151
  headers[:x_security_token] = x_security_token if x_security_token
148
152
 
149
153
  headers
@@ -1,4 +1,4 @@
1
1
  module IGMarkets
2
2
  # The version of this gem.
3
- VERSION = '0.8'.freeze
3
+ VERSION = '0.9'.freeze
4
4
  end
@@ -26,11 +26,11 @@ module IGMarkets
26
26
  # @return [String] The deal reference of the deletion operation. Use {DealingPlatform#deal_confirmation} to check
27
27
  # the result of the working order deletion.
28
28
  def delete
29
- @dealing_platform.session.delete("workingorders/otc/#{deal_id}", {}).fetch(:deal_reference)
29
+ @dealing_platform.session.delete("workingorders/otc/#{deal_id}", nil, API_V2).fetch(:deal_reference)
30
30
  end
31
31
 
32
- # Updates this working order. No attributes are mandatory, and any attributes not specified will be kept at the
33
- # current value.
32
+ # Updates this working order. No attributes are mandatory, and any attributes not specified will be kept at their
33
+ # current values.
34
34
  #
35
35
  # @param [Hash] new_attributes The attributes of this working order to update. See
36
36
  # {DealingPlatform::WorkingOrderMethods#create} for a description of the attributes.
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.8'
4
+ version: '0.9'
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-04-30 00:00:00.000000000 Z
11
+ date: 2016-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -233,6 +233,7 @@ files:
233
233
  - lib/ig_markets/cli/tables/table.rb
234
234
  - lib/ig_markets/cli/tables/transactions_table.rb
235
235
  - lib/ig_markets/cli/tables/working_orders_table.rb
236
+ - lib/ig_markets/client_account_summary.rb
236
237
  - lib/ig_markets/client_sentiment.rb
237
238
  - lib/ig_markets/deal_confirmation.rb
238
239
  - lib/ig_markets/dealing_platform.rb