ig_markets 0.33 → 0.35

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +7 -16
  5. data/lib/ig_markets/boolean.rb +1 -1
  6. data/lib/ig_markets/cli/commands/console_command.rb +1 -1
  7. data/lib/ig_markets/cli/commands/performance_command.rb +8 -8
  8. data/lib/ig_markets/cli/commands/positions_command.rb +1 -1
  9. data/lib/ig_markets/cli/commands/prices_command.rb +5 -5
  10. data/lib/ig_markets/cli/commands/stream_command.rb +2 -2
  11. data/lib/ig_markets/cli/commands/watchlists_command.rb +1 -1
  12. data/lib/ig_markets/cli/config_file.rb +2 -2
  13. data/lib/ig_markets/cli/curses_window.rb +1 -1
  14. data/lib/ig_markets/cli/main.rb +16 -18
  15. data/lib/ig_markets/cli/tables/accounts_table.rb +1 -1
  16. data/lib/ig_markets/cli/tables/market_overviews_table.rb +2 -2
  17. data/lib/ig_markets/cli/tables/performances_table.rb +1 -1
  18. data/lib/ig_markets/cli/tables/positions_table.rb +4 -4
  19. data/lib/ig_markets/cli/tables/sprint_market_positions_table.rb +2 -2
  20. data/lib/ig_markets/cli/tables/table.rb +1 -1
  21. data/lib/ig_markets/cli/tables/transactions_table.rb +1 -1
  22. data/lib/ig_markets/dealing_platform/market_methods.rb +1 -1
  23. data/lib/ig_markets/dealing_platform/streaming_methods.rb +2 -2
  24. data/lib/ig_markets/dealing_platform.rb +4 -3
  25. data/lib/ig_markets/format.rb +2 -2
  26. data/lib/ig_markets/model/typecasters.rb +13 -17
  27. data/lib/ig_markets/model.rb +13 -12
  28. data/lib/ig_markets/position.rb +3 -2
  29. data/lib/ig_markets/regex.rb +2 -2
  30. data/lib/ig_markets/request_body_formatter.rb +1 -1
  31. data/lib/ig_markets/request_formatter.rb +3 -3
  32. data/lib/ig_markets/response_parser.rb +3 -2
  33. data/lib/ig_markets/session.rb +3 -3
  34. data/lib/ig_markets/streaming/account_state.rb +3 -1
  35. data/lib/ig_markets/streaming/market_subscription_manager.rb +1 -1
  36. data/lib/ig_markets/streaming/subscription.rb +9 -7
  37. data/lib/ig_markets/transaction.rb +1 -1
  38. data/lib/ig_markets/version.rb +1 -1
  39. metadata +45 -45
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de92f7363906f7bb64fe6d258c8975cb4b506f6b029e888122038a6677911394
4
- data.tar.gz: 90abc4b017ba8b6a107917b9fdf0573f713d2330cd31e57fd6a1e0426fc2694f
3
+ metadata.gz: 04e98ad7849a63ce3005fd84aa7ae03a9ff3f560efbcc302ba2b68cecbef4023
4
+ data.tar.gz: 91df31e0fe72ff4ab68384191e59b70a7456d09ab164d73fae0321d6bac53d0b
5
5
  SHA512:
6
- metadata.gz: dd929726e98a24eb65e9c293e2e86348ab51db440cf878cf4e9f9778ff930de22b66ddcafc8d43b6b485a61415aa207adac9ca9dea5062af67f77ff91cda7eaa
7
- data.tar.gz: 220263722e82b7dd44c8aca7a5e1821e61481454ee997b7506599d398ea4ca65926204f1e6cb4521758865bdfdd48bbbf41f6ddb4fdc2342e2def9e07694c503
6
+ metadata.gz: fd774702efad7e59a4e724b2dfc826bb11fdb8f1c6e1d9ac8197a14af0d28f3fd3be0d8658f0a4fd5f09b468898b9743e131e50befe3442eab6441c57eccf909
7
+ data.tar.gz: 31404cd38fc63edac4f4d35e3afeb21778e9a1f125f510096ad53e7b3d6bea86d9c36fe3d4a69e4a7457967d00b3f166dec3f74e883d274f0b22f96ee64e8acd
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # IG Markets Changelog
2
2
 
3
+ ### 0.35 — March 26, 2023
4
+
5
+ - Updated supported Ruby version range to 2.7 - 3.2.
6
+ - Updated dependency versions.
7
+
8
+ ### 0.34 — April 29, 2020
9
+
10
+ - Updated supported Ruby version range to 2.5 - 2.7.
11
+ - Updated dependency versions.
12
+ - Switched from Travis CI to GitHub Actions.
13
+ - Removed CodeClimate.
14
+
3
15
  ### 0.33 — December 30, 2017
4
16
 
5
17
  - Added `DealingPlatform::ClientSentimentMethods#find` for retrieving multiple client sentiments in one request
data/LICENSE.md CHANGED
@@ -1,7 +1,7 @@
1
1
  The MIT License (MIT)
2
2
  =====================
3
3
 
4
- Copyright © 2015-2017 Richard Viney
4
+ Copyright © 2015-2020 Richard Viney
5
5
 
6
6
  Permission is hereby granted, free of charge, to any person
7
7
  obtaining a copy of this software and associated documentation
data/README.md CHANGED
@@ -1,10 +1,7 @@
1
1
  # Ruby IG Markets Dealing Platform Gem
2
2
 
3
3
  [![Gem][gem-badge]][gem-link]
4
- [![Build Status][travis-ci-badge]][travis-ci-link]
5
- [![Test Coverage][test-coverage-badge]][test-coverage-link]
6
- [![Code Climate][code-climate-badge]][code-climate-link]
7
- [![Dependencies][dependencies-badge]][dependencies-link]
4
+ [![Build Status][ci-badge]][ci-link]
8
5
  [![Documentation][documentation-badge]][documentation-link]
9
6
  [![License][license-badge]][license-link]
10
7
 
@@ -168,7 +165,7 @@ ig_markets console --verbose
168
165
 
169
166
  #### Documentation
170
167
 
171
- API documentation is available [here](http://www.rubydoc.info/github/richard-viney/ig_markets/master).
168
+ API documentation is available [here](http://www.rubydoc.info/github/richard-viney/ig_markets/main).
172
169
 
173
170
  #### Examples
174
171
 
@@ -268,15 +265,9 @@ Gem created by Richard Viney. All contributions welcome.
268
265
 
269
266
  [gem-link]: https://rubygems.org/gems/ig_markets
270
267
  [gem-badge]: https://badge.fury.io/rb/ig_markets.svg
271
- [travis-ci-link]: http://travis-ci.org/richard-viney/ig_markets
272
- [travis-ci-badge]: https://travis-ci.org/richard-viney/ig_markets.svg?branch=master
273
- [test-coverage-link]: https://codeclimate.com/github/richard-viney/ig_markets/coverage
274
- [test-coverage-badge]: https://codeclimate.com/github/richard-viney/ig_markets/badges/coverage.svg
275
- [code-climate-link]: https://codeclimate.com/github/richard-viney/ig_markets
276
- [code-climate-badge]: https://codeclimate.com/github/richard-viney/ig_markets/badges/gpa.svg
277
- [dependencies-link]: https://gemnasium.com/richard-viney/ig_markets
278
- [dependencies-badge]: https://gemnasium.com/richard-viney/ig_markets.svg
279
- [documentation-link]: https://inch-ci.org/github/richard-viney/ig_markets
280
- [documentation-badge]: https://inch-ci.org/github/richard-viney/ig_markets.svg?branch=master
281
- [license-link]: https://github.com/richard-viney/ig_markets/blob/master/LICENSE.md
268
+ [ci-link]: https://github.com/richard-viney/ig_markets/actions
269
+ [ci-badge]: https://github.com/richard-viney/ig_markets/workflows/ci/badge.svg?branch=main
270
+ [documentation-link]: https://inch-ci.org/github/richard-viney/ig_markets?branch=main
271
+ [documentation-badge]: https://inch-ci.org/github/richard-viney/ig_markets.svg?branch=main
272
+ [license-link]: https://github.com/richard-viney/ig_markets/blob/main/LICENSE.md
282
273
  [license-badge]: https://img.shields.io/badge/license-MIT-blue.svg
@@ -1,5 +1,5 @@
1
1
  module IGMarkets
2
2
  # Placeholder class for specifying a boolean type.
3
- class Boolean
3
+ class Boolean # rubocop:disable Lint/EmptyClass
4
4
  end
5
5
  end
@@ -8,7 +8,7 @@ module IGMarkets
8
8
  self.class.begin_session(options) do |dealing_platform|
9
9
  ig = dealing_platform
10
10
 
11
- pry binding
11
+ pry binding # rubocop:disable Lint/Debugger
12
12
  end
13
13
  end
14
14
  end
@@ -25,7 +25,7 @@ module IGMarkets
25
25
 
26
26
  def gather_performances(dealing_platform)
27
27
  performances = deal_transactions_by_epic(dealing_platform).map do |epic, transactions|
28
- profit_loss = transactions.map(&:profit_and_loss_amount).inject(&:+)
28
+ profit_loss = transactions.sum(&:profit_and_loss_amount)
29
29
 
30
30
  { epic: epic, transactions: transactions, profit_loss: profit_loss }
31
31
  end
@@ -38,7 +38,7 @@ module IGMarkets
38
38
 
39
39
  deal_transactions(dealing_platform).group_by do |transaction|
40
40
  activities.detect do |activity|
41
- Regexp.new("^Position(\/s| partially) closed:.*#{transaction.reference}").match activity.description
41
+ Regexp.new("^Position(/s| partially) closed:.*#{transaction.reference}").match activity.description
42
42
  end.epic
43
43
  end
44
44
  end
@@ -58,16 +58,16 @@ module IGMarkets
58
58
  end
59
59
 
60
60
  def print_summary(performances)
61
- profit_loss = performances.map { |h| h[:profit_loss] }.inject(:+)
61
+ profit_loss = performances.sum { |h| h[:profit_loss] }
62
62
  currency = performances.first[:transactions].first.currency
63
63
 
64
- puts <<-MSG
64
+ puts <<~MSG
65
65
 
66
- Note: this table only shows the profit/loss made from dealing, it does not include interest payments,
67
- dividends, or other adjustments that may have occurred over this period.
66
+ Note: this table only shows the profit/loss made from dealing, it does not include interest payments,
67
+ dividends, or other adjustments that may have occurred over this period.
68
68
 
69
- Total: #{Format.colored_currency profit_loss, currency}
70
- MSG
69
+ Total: #{Format.colored_currency profit_loss, currency}
70
+ MSG
71
71
  end
72
72
  end
73
73
  end
@@ -130,7 +130,7 @@ module IGMarkets
130
130
 
131
131
  def print_position_totals(positions)
132
132
  currency_totals = positions.group_by(&:currency).map do |currency, subset|
133
- total = subset.map(&:profit_loss).reduce :+
133
+ total = subset.sum(&:profit_loss)
134
134
 
135
135
  Format.colored_currency total, currency
136
136
  end
@@ -21,12 +21,12 @@ module IGMarkets
21
21
 
22
22
  table = Tables::HistoricalPriceResultSnapshotsTable.new result.prices, title: "Prices for #{options[:epic]}"
23
23
 
24
- puts <<-MSG
25
- #{table}
24
+ puts <<~MSG
25
+ #{table}
26
26
 
27
- Allowance: #{allowance.total_allowance}
28
- Remaining: #{allowance.remaining_allowance}
29
- MSG
27
+ Allowance: #{allowance.total_allowance}
28
+ Remaining: #{allowance.remaining_allowance}
29
+ MSG
30
30
  end
31
31
  end
32
32
 
@@ -36,7 +36,7 @@ module IGMarkets
36
36
  @dealing_platform = dealing_platform
37
37
  @queue = Queue.new
38
38
 
39
- @dealing_platform.streaming.on_error(&method(:on_error))
39
+ @dealing_platform.streaming.on_error { |error| on_error error }
40
40
  @dealing_platform.streaming.connect
41
41
  start_raw_subscriptions
42
42
 
@@ -51,7 +51,7 @@ module IGMarkets
51
51
  chart_ticks_subscription].compact
52
52
 
53
53
  subscriptions.each do |subscription|
54
- subscription.on_data(&method(:on_data))
54
+ subscription.on_data { |data, merged_data| on_data data, merged_data }
55
55
  end
56
56
 
57
57
  @dealing_platform.streaming.start_subscriptions subscriptions, snapshot: true
@@ -9,7 +9,7 @@ module IGMarkets
9
9
  dealing_platform.watchlists.all.each_with_index do |watchlist, index|
10
10
  table = Tables::MarketOverviewsTable.new watchlist.markets, title: table_title(watchlist)
11
11
 
12
- puts '' if index > 0
12
+ puts '' if index.positive?
13
13
  puts table
14
14
  end
15
15
  end
@@ -13,8 +13,8 @@ module IGMarkets
13
13
  def initialize(content = {})
14
14
  @content = content || {}
15
15
 
16
- @profiles = (@content['profiles'] || {}).each_with_object({}) do |(profile_name, profile_arguments), result|
17
- result[profile_name] = profile_arguments.map do |argument, value|
16
+ @profiles = (@content['profiles'] || {}).transform_values do |profile_arguments|
17
+ profile_arguments.map do |argument, value|
18
18
  "--#{argument}=#{value}"
19
19
  end
20
20
  end
@@ -66,7 +66,7 @@ module IGMarkets
66
66
  end
67
67
  end
68
68
 
69
- COLORIZE_REGEXP = /^\e\[0(?:;(\d+);49)?m/
69
+ COLORIZE_REGEXP = /^\e\[0(?:;(\d+);49)?m/.freeze
70
70
 
71
71
  def print_next_line_segment(line)
72
72
  match = line.match COLORIZE_REGEXP
@@ -36,7 +36,7 @@ module IGMarkets
36
36
  to: history_options_parse_time(options[:to])
37
37
  }
38
38
  else
39
- { from: Time.now.utc - options[:days] * 86_400 }
39
+ { from: Time.now.utc - (options[:days] * 86_400) }
40
40
  end
41
41
  end
42
42
 
@@ -73,8 +73,8 @@ module IGMarkets
73
73
  @dealing_platform.sign_in options[:username], options[:password], options[:api_key], platform
74
74
 
75
75
  yield @dealing_platform
76
- rescue IGMarketsError => error
77
- warn_and_exit error
76
+ rescue IGMarketsError => e
77
+ warn_and_exit e
78
78
  end
79
79
 
80
80
  # Requests and displays the deal confirmation for the passed deal reference. If the request for the deal
@@ -87,14 +87,12 @@ module IGMarkets
87
87
  puts "Deal reference: #{deal_reference}"
88
88
 
89
89
  5.times do |index|
90
- begin
91
- return print_deal_confirmation @dealing_platform.deal_confirmation(deal_reference)
92
- rescue Errors::DealNotFoundError
93
- raise if index == 4
90
+ return print_deal_confirmation @dealing_platform.deal_confirmation(deal_reference)
91
+ rescue Errors::DealNotFoundError
92
+ raise if index == 4
94
93
 
95
- puts 'Deal not found, retrying ...'
96
- sleep 2
97
- end
94
+ puts 'Deal not found, retrying ...'
95
+ sleep 2
98
96
  end
99
97
  end
100
98
 
@@ -110,14 +108,14 @@ module IGMarkets
110
108
  def parse_date_time(attributes, attribute, klass, format, display_format)
111
109
  return unless attributes.key? attribute
112
110
 
113
- if !['', attribute.to_s].include? attributes[attribute].to_s
111
+ if ['', attribute.to_s].include? attributes[attribute].to_s
112
+ attributes[attribute] = nil
113
+ else
114
114
  begin
115
115
  attributes[attribute] = klass.strptime attributes[attribute], format
116
116
  rescue ArgumentError
117
117
  raise ArgumentError, %(invalid #{attribute}, use format "#{display_format}")
118
118
  end
119
- else
120
- attributes[attribute] = nil
121
119
  end
122
120
  end
123
121
 
@@ -159,11 +157,11 @@ module IGMarkets
159
157
 
160
158
  # Prints out details of the passed deal confirmation.
161
159
  def print_deal_confirmation(deal_confirmation)
162
- puts <<-MSG
163
- Deal ID: #{deal_confirmation.deal_id}
164
- Status: #{Format.symbol deal_confirmation.deal_status}
165
- Result: #{Format.symbol deal_confirmation.status}
166
- MSG
160
+ puts <<~MSG
161
+ Deal ID: #{deal_confirmation.deal_id}
162
+ Status: #{Format.symbol deal_confirmation.deal_status}
163
+ Result: #{Format.symbol deal_confirmation.status}
164
+ MSG
167
165
 
168
166
  print_deal_confirmation_profit_loss deal_confirmation
169
167
 
@@ -33,7 +33,7 @@ module IGMarkets
33
33
  def cell_color(value, _model, _row_index, column_index)
34
34
  return unless headings[column_index] == 'Profit/loss'
35
35
 
36
- if value =~ /-/
36
+ if value.include?('-')
37
37
  :red
38
38
  else
39
39
  :green
@@ -24,9 +24,9 @@ module IGMarkets
24
24
  end
25
25
 
26
26
  def cell_color(value, _model, _row_index, column_index)
27
- return unless headings[column_index] =~ /Change/
27
+ return unless headings[column_index].include?('Change')
28
28
 
29
- if value =~ /-/
29
+ if value.include?('-')
30
30
  :red
31
31
  else
32
32
  :green
@@ -27,7 +27,7 @@ module IGMarkets
27
27
  def cell_color(value, _transaction, _row_index, column_index)
28
28
  return unless headings[column_index] == 'Profit/loss'
29
29
 
30
- if value =~ /-/
30
+ if value.include?('-')
31
31
  :red
32
32
  else
33
33
  :green
@@ -33,7 +33,7 @@ module IGMarkets
33
33
  def cell_color(value, _model, _row_index, column_index)
34
34
  return unless headings[column_index] == 'Profit/loss'
35
35
 
36
- if value =~ /-/
36
+ if value.include?('-')
37
37
  :red
38
38
  else
39
39
  :green
@@ -73,15 +73,15 @@ module IGMarkets
73
73
  Position.new(contract_size: first.contract_size, currency: first.currency,
74
74
  deal_id: combine_position_deal_ids(positions), direction: first.direction,
75
75
  level: combine_position_levels(positions), market: first.market,
76
- size: positions.map(&:size).reduce(:+)).tap do |combined|
76
+ size: positions.sum(&:size)).tap do |combined|
77
77
  combined.level /= combined.size
78
78
  end
79
79
  end
80
80
 
81
81
  def combine_position_levels(positions)
82
- positions.map do |position|
82
+ positions.sum do |position|
83
83
  position.level * position.size
84
- end.reduce :+
84
+ end
85
85
  end
86
86
 
87
87
  def combine_position_deal_ids(positions)
@@ -32,8 +32,8 @@ module IGMarkets
32
32
  def cell_color(_value, sprint, _row_index, column_index)
33
33
  return unless headings[column_index] == 'Payout'
34
34
 
35
- if current_level(sprint) > sprint.strike_level && sprint.direction == :buy ||
36
- current_level(sprint) < sprint.strike_level && sprint.direction == :sell
35
+ if (current_level(sprint) > sprint.strike_level && sprint.direction == :buy) ||
36
+ (current_level(sprint) < sprint.strike_level && sprint.direction == :sell)
37
37
  :green
38
38
  else
39
39
  :red
@@ -95,7 +95,7 @@ module IGMarkets
95
95
 
96
96
  return '' if value.empty?
97
97
 
98
- value[0].upcase + value[1..-1]
98
+ value[0].upcase + value[1..]
99
99
  end
100
100
  end
101
101
  end
@@ -27,7 +27,7 @@ module IGMarkets
27
27
  def cell_color(value, _transaction, _row_index, column_index)
28
28
  return unless headings[column_index] == 'Profit/loss'
29
29
 
30
- if value =~ /-/
30
+ if value.include?('-')
31
31
  :red
32
32
  else
33
33
  :green
@@ -34,7 +34,7 @@ module IGMarkets
34
34
  return [] if epics.empty?
35
35
 
36
36
  epics.each do |epic|
37
- raise ArgumentError, "invalid EPIC: #{epic}" unless epic.to_s =~ Regex::EPIC
37
+ raise ArgumentError, "invalid EPIC: #{epic}" unless Regex::EPIC.match?(epic.to_s)
38
38
  end
39
39
 
40
40
  # The API imposes a maximum of 50 EPICs per request
@@ -12,7 +12,7 @@ module IGMarkets
12
12
 
13
13
  # Connects the streaming session. Raises a `Lightstreamer::LightstreamerError` if an error occurs.
14
14
  def connect
15
- @lightstreamer.disconnect if @lightstreamer
15
+ @lightstreamer&.disconnect
16
16
 
17
17
  @lightstreamer = Lightstreamer::Session.new username: username, password: password, server_url: server_url
18
18
  @lightstreamer.on_error { |error| @on_error_callbacks.each { |callback| callback.call error } }
@@ -21,7 +21,7 @@ module IGMarkets
21
21
 
22
22
  # Disconnects the streaming session.
23
23
  def disconnect
24
- @lightstreamer.disconnect if @lightstreamer
24
+ @lightstreamer&.disconnect
25
25
  @lightstreamer = nil
26
26
  end
27
27
 
@@ -147,9 +147,10 @@ module IGMarkets
147
147
 
148
148
  source = prepare_source model_class, source
149
149
 
150
- if source.is_a? Array
150
+ case source
151
+ when Array
151
152
  source.map { |entry| instantiate_models model_class, entry }
152
- elsif source.is_a? Hash
153
+ when Hash
153
154
  instantiate_model_from_attributes_hash model_class, source
154
155
  else
155
156
  raise ArgumentError, "#{model_class}: can't instantiate from a source of type #{source.class}"
@@ -211,7 +212,7 @@ module IGMarkets
211
212
  model.send "#{attribute}=", value
212
213
  else
213
214
  unless Array(@reported_unrecognized_values).include? [model.class, attribute, value]
214
- warn "ig_markets: received unrecognized value for #{model.class}##{attribute}: #{value}"
215
+ warn "ig_markets: received unrecognized value for #{model.class.name}##{attribute}: #{value}"
215
216
  (@reported_unrecognized_values ||= []) << [model.class, attribute, value]
216
217
  end
217
218
  end
@@ -43,7 +43,7 @@ module IGMarkets
43
43
  def colored_currency(amount, currency_name)
44
44
  return '' unless amount
45
45
 
46
- color = amount < 0 ? :red : :green
46
+ color = amount.negative? ? :red : :green
47
47
 
48
48
  ColorizedString[currency(amount, currency_name)].colorize color
49
49
  end
@@ -60,7 +60,7 @@ module IGMarkets
60
60
  (value / 60).to_s
61
61
  end
62
62
 
63
- result + ':' + Kernel.format('%02i', value % 60)
63
+ "#{result}:#{Kernel.format('%02i', value % 60)}"
64
64
  end
65
65
 
66
66
  # Formats the passed symbol into a human-readable string, replacing underscores with spaces and capitalizing the
@@ -6,11 +6,11 @@ module IGMarkets
6
6
 
7
7
  def typecaster_for(type)
8
8
  if [Boolean, String, Integer, Float, Symbol, Date, Time].include? type
9
- method "typecaster_#{type.to_s.gsub(/\AIGMarkets::/, '').downcase}"
9
+ method "typecaster_#{type.to_s.delete_prefix('IGMarkets::').downcase}"
10
10
  elsif type
11
11
  lambda do |value, _options, name|
12
12
  if Array(value).any? { |entry| !entry.is_a? type }
13
- raise ArgumentError, "incorrect type set on #{self}##{name}: #{value.inspect}"
13
+ raise ArgumentError, "incorrect type set on #{self.name}##{name}: #{value.inspect}"
14
14
  end
15
15
 
16
16
  value
@@ -22,14 +22,14 @@ module IGMarkets
22
22
  return value if [nil, true, false].include? value
23
23
  return value == '1' if %w[0 1].include? value
24
24
 
25
- raise ArgumentError, "#{self}##{name}: invalid boolean value: #{value}"
25
+ raise ArgumentError, "#{self.name}##{name}: invalid boolean value: #{value}"
26
26
  end
27
27
 
28
28
  def typecaster_string(value, options, name)
29
29
  return nil if value.nil?
30
30
 
31
31
  if options.key?(:regex) && !options[:regex].match(value.to_s)
32
- raise ArgumentError, "#{self}##{name}: invalid string value: #{value}"
32
+ raise ArgumentError, "#{self.name}##{name}: invalid string value: #{value}"
33
33
  end
34
34
 
35
35
  value.to_s
@@ -46,7 +46,7 @@ module IGMarkets
46
46
 
47
47
  Float(value)
48
48
  rescue ArgumentError
49
- raise ArgumentError, "#{self}##{name}: invalid float value: #{value}"
49
+ raise ArgumentError, "#{self.name}##{name}: invalid float value: #{value}"
50
50
  end
51
51
 
52
52
  def typecaster_symbol(value, _options, _name)
@@ -65,14 +65,12 @@ module IGMarkets
65
65
 
66
66
  def parse_formatted_date_value(value, options, name)
67
67
  Array(options[:format]).each do |format|
68
- begin
69
- return Date.strptime value, format
70
- rescue ArgumentError
71
- next
72
- end
68
+ return Date.strptime value, format
69
+ rescue ArgumentError
70
+ next
73
71
  end
74
72
 
75
- raise ArgumentError, "#{self}##{name}: failed parsing date: #{value}"
73
+ raise ArgumentError, "#{self.name}##{name}: failed parsing date: #{value}"
76
74
  end
77
75
 
78
76
  def typecaster_time(value, options, name)
@@ -85,14 +83,12 @@ module IGMarkets
85
83
 
86
84
  def parse_formatted_time_value(value, options, name)
87
85
  Array(options[:format]).each do |format|
88
- begin
89
- return parse_time_using_format value, format
90
- rescue ArgumentError
91
- next
92
- end
86
+ return parse_time_using_format value, format
87
+ rescue ArgumentError
88
+ next
93
89
  end
94
90
 
95
- raise ArgumentError, "#{self}##{name}: failed parsing time: #{value}"
91
+ raise ArgumentError, "#{self.name}##{name}: failed parsing time: #{value}"
96
92
  end
97
93
 
98
94
  def parse_time_using_format(value, format)
@@ -47,12 +47,12 @@ module IGMarkets
47
47
  #
48
48
  # @return [Hash]
49
49
  def to_h
50
- attributes.each_with_object({}) do |(key, value), hash|
51
- hash[key] = if value.is_a? Model
52
- value.to_h
53
- else
54
- value
55
- end
50
+ attributes.transform_values do |value|
51
+ if value.is_a? Model
52
+ value.to_h
53
+ else
54
+ value
55
+ end
56
56
  end
57
57
  end
58
58
 
@@ -80,9 +80,10 @@ module IGMarkets
80
80
 
81
81
  # Returns the {#inspect} string for the given value.
82
82
  def inspect_value(value)
83
- if value.is_a? Time
83
+ case value
84
+ when Time
84
85
  value.localtime.strftime '%F %T %Z'
85
- elsif value.is_a? Date
86
+ when Date
86
87
  value.strftime '%F'
87
88
  else
88
89
  value.inspect
@@ -113,7 +114,7 @@ module IGMarkets
113
114
  return true if defined_attribute_names.include?(name) || Array(deprecated_attributes).include?(name)
114
115
 
115
116
  unless Array(@reported_invalid_attributes).include? name
116
- warn "ig_markets: unrecognized attribute #{self}##{name}"
117
+ warn "ig_markets: unrecognized attribute #{self.name}##{name}"
117
118
  (@reported_invalid_attributes ||= []) << name
118
119
  end
119
120
 
@@ -183,8 +184,8 @@ module IGMarkets
183
184
  # @param [Array<Symbol>] names The names of the deprecated attributes.
184
185
  def deprecated_attribute(*names)
185
186
  names.each do |name|
186
- define_method(name) {}
187
- define_method("#{name}=") { |_value| }
187
+ define_method(name) {} # rubocop:disable Lint/EmptyBlock
188
+ define_method("#{name}=") { |_value| } # rubocop:disable Lint/EmptyBlock
188
189
  define_singleton_method("sanitize_#{name}_value") { |value| value }
189
190
 
190
191
  (@deprecated_attributes ||= []) << name
@@ -202,7 +203,7 @@ module IGMarkets
202
203
  value = self.class.send "sanitize_#{name}_value", value
203
204
 
204
205
  unless self.class.attribute_value_allowed? name, value
205
- raise ArgumentError, "#{self.class}##{name}: invalid value: #{value.inspect}"
206
+ raise ArgumentError, "#{self.class.name}##{name}: invalid value: #{value.inspect}"
206
207
  end
207
208
 
208
209
  (@attributes ||= {})[name] = value
@@ -39,9 +39,10 @@ module IGMarkets
39
39
  #
40
40
  # @return [Float]
41
41
  def price_delta
42
- if direction == :buy
42
+ case direction
43
+ when :buy
43
44
  close_level - level
44
- elsif direction == :sell
45
+ when :sell
45
46
  level - close_level
46
47
  end
47
48
  end
@@ -4,9 +4,9 @@ module IGMarkets
4
4
  # @private
5
5
  module Regex
6
6
  # Regex used to validate an ISO currency code.
7
- CURRENCY = /\A[A-Z]{3}\Z/
7
+ CURRENCY = /\A[A-Z]{3}\Z/.freeze
8
8
 
9
9
  # Regex used to validate an EPIC.
10
- EPIC = /\A[A-Z,a-z,0-9,.,_]{6,30}\Z/
10
+ EPIC = /\A[A-Za-z0-9.,_]{6,30}\Z/.freeze
11
11
  end
12
12
  end
@@ -48,7 +48,7 @@ module IGMarkets
48
48
  def snake_case_to_camel_case(value)
49
49
  pieces = value.to_s.split '_'
50
50
 
51
- (pieces.first + pieces[1..-1].map(&:capitalize).join).to_sym
51
+ (pieces.first + pieces[1..].map(&:capitalize).join).to_sym
52
52
  end
53
53
  end
54
54
  end
@@ -50,7 +50,7 @@ module IGMarkets
50
50
  result = " Body:\n "
51
51
  result += JSON.pretty_generate(JSON.parse(body)).gsub("\n", "\n ")
52
52
 
53
- result + "\n"
53
+ "#{result}\n"
54
54
  end
55
55
 
56
56
  def format_response_headers(headers)
@@ -66,9 +66,9 @@ module IGMarkets
66
66
  def format_response_body(body)
67
67
  result = " Body:\n "
68
68
  result += JSON.pretty_generate(JSON.parse(body)).gsub "\n", "\n "
69
- result + "\n"
69
+ "#{result}\n"
70
70
  rescue JSON::ParserError
71
- result + body + "\n"
71
+ "#{result}#{body}\n"
72
72
  end
73
73
  end
74
74
  end
@@ -14,11 +14,12 @@ module IGMarkets
14
14
  #
15
15
  # @return [Hash, Array, Object] The parsed object, the type depends on the type of the `response` parameter.
16
16
  def parse(response)
17
- if response.is_a? Hash
17
+ case response
18
+ when Hash
18
19
  response.each_with_object({}) do |(key, value), new_hash|
19
20
  new_hash[camel_case_to_snake_case(key).to_sym] = parse(value)
20
21
  end
21
- elsif response.is_a? Array
22
+ when Array
22
23
  response.map { |item| parse item }
23
24
  else
24
25
  response
@@ -122,7 +122,7 @@ module IGMarkets
122
122
  options[:method] = :post
123
123
  end
124
124
 
125
- options[:body] = options[:body] && options[:body].to_json
125
+ options[:body] = options[:body]&.to_json
126
126
 
127
127
  execute_request options
128
128
  end
@@ -148,8 +148,8 @@ module IGMarkets
148
148
  write_to_log_sinks { RequestFormatter.format_response response }
149
149
 
150
150
  process_response response, options
151
- rescue Excon::Error => error
152
- raise Errors::ConnectionError, error.message
151
+ rescue Excon::Error => e
152
+ raise Errors::ConnectionError, e.message
153
153
  end
154
154
 
155
155
  def write_to_log_sinks
@@ -170,13 +170,15 @@ module IGMarkets
170
170
  end
171
171
 
172
172
  def on_working_order_updated(working_order_update)
173
+ working_order_attributes = %i[good_till_date limit_distance order_type stop_distance time_in_force]
174
+
173
175
  @working_orders.each do |working_order|
174
176
  next unless working_order.deal_id == working_order_update.deal_id
175
177
 
176
178
  working_order.currency_code = working_order_update.currency
177
179
  working_order.order_level = working_order_update.level
178
180
 
179
- %i[good_till_date limit_distance order_type stop_distance time_in_force].each do |attribute|
181
+ working_order_attributes.each do |attribute|
180
182
  working_order.send "#{attribute}=", working_order_update.send(attribute)
181
183
  end
182
184
  end
@@ -54,7 +54,7 @@ module IGMarkets
54
54
  next if @subscriptions.key? epic
55
55
 
56
56
  subscription = @dealing_platform.streaming.build_markets_subscription epic
57
- subscription.on_data(&method(:run_callbacks))
57
+ subscription.on_data { |data, merged_data| run_callbacks data, merged_data }
58
58
 
59
59
  @subscriptions[epic] = subscription
60
60
 
@@ -19,7 +19,9 @@ module IGMarkets
19
19
  @dealing_platform = dealing_platform
20
20
 
21
21
  @lightstreamer_subscription = lightstreamer_subscription
22
- @lightstreamer_subscription.on_data(&method(:on_raw_data))
22
+ @lightstreamer_subscription.on_data do |subscription, item_name, item_data, new_data|
23
+ on_raw_data subscription, item_name, item_data, new_data
24
+ end
23
25
 
24
26
  @on_data_callbacks = []
25
27
  end
@@ -44,11 +46,11 @@ module IGMarkets
44
46
 
45
47
  private
46
48
 
47
- ACCOUNT_DATA_REGEX = /^ACCOUNT:(.*)$/
48
- MARKET_DATA_REGEX = /^MARKET:(.*)$/
49
- TRADE_DATA_REGEX = /^TRADE:(.*)$/
50
- CHART_TICK_DATA_REGEX = /^CHART:(.*):TICK$/
51
- CONSOLIDATED_CHART_DATA_REGEX = /^CHART:(.*):(SECOND|1MINUTE|5MINUTE|HOUR)$/
49
+ ACCOUNT_DATA_REGEX = /^ACCOUNT:(.*)$/.freeze
50
+ MARKET_DATA_REGEX = /^MARKET:(.*)$/.freeze
51
+ TRADE_DATA_REGEX = /^TRADE:(.*)$/.freeze
52
+ CHART_TICK_DATA_REGEX = /^CHART:(.*):TICK$/.freeze
53
+ CONSOLIDATED_CHART_DATA_REGEX = /^CHART:(.*):(SECOND|1MINUTE|5MINUTE|HOUR)$/.freeze
52
54
 
53
55
  def on_raw_data(_subscription, item_name, item_data, new_data)
54
56
  {
@@ -58,7 +60,7 @@ module IGMarkets
58
60
  CHART_TICK_DATA_REGEX => :on_chart_tick_data,
59
61
  CONSOLIDATED_CHART_DATA_REGEX => :on_consolidated_chart_data
60
62
  }.each do |regex, handler|
61
- send handler, item_name, item_data, new_data if item_name =~ regex
63
+ send handler, item_name, item_data, new_data if item_name&.match?(regex)
62
64
  end
63
65
  end
64
66
 
@@ -32,7 +32,7 @@ module IGMarkets
32
32
  def profit_and_loss_amount
33
33
  raise 'profit_and_loss does not start with the expected currency' unless profit_and_loss.start_with? currency
34
34
 
35
- profit_and_loss[currency.length..-1].delete(',').to_f
35
+ profit_and_loss[currency.length..].delete(',').to_f
36
36
  end
37
37
  end
38
38
  end
@@ -1,4 +1,4 @@
1
1
  module IGMarkets
2
2
  # The version of this gem.
3
- VERSION = '0.33'.freeze
3
+ VERSION = '0.35'.freeze
4
4
  end
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.33'
4
+ version: '0.35'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Viney
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-30 00:00:00.000000000 Z
11
+ date: 2023-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -30,196 +30,196 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.51'
33
+ version: '0.99'
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.51'
40
+ version: '0.99'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: lightstreamer
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0.14'
47
+ version: '0.16'
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: '0.14'
54
+ version: '0.16'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: pry
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0.10'
61
+ version: '0.14'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0.10'
68
+ version: '0.14'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: terminal-table
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '1.6'
75
+ version: '3.0'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '1.6'
82
+ version: '3.0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: thor
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.19'
89
+ version: '1.0'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0.19'
96
+ version: '1.0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: codeclimate-test-reporter
98
+ name: factory_bot
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '1.0'
103
+ version: '6.2'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '1.0'
110
+ version: '6.2'
111
111
  - !ruby/object:Gem::Dependency
112
- name: factory_bot
112
+ name: github-markup
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '4.8'
117
+ version: '4.0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '4.8'
124
+ version: '4.0'
125
125
  - !ruby/object:Gem::Dependency
126
- name: github-markup
126
+ name: redcarpet
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: '1.4'
131
+ version: '3.6'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: '1.4'
138
+ version: '3.6'
139
139
  - !ruby/object:Gem::Dependency
140
- name: redcarpet
140
+ name: rspec
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '3.3'
145
+ version: '3.12'
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '3.3'
152
+ version: '3.12'
153
153
  - !ruby/object:Gem::Dependency
154
- name: rspec
154
+ name: rspec-mocks
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
157
  - - "~>"
158
158
  - !ruby/object:Gem::Version
159
- version: '3.5'
159
+ version: '3.12'
160
160
  type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
- version: '3.5'
166
+ version: '3.12'
167
167
  - !ruby/object:Gem::Dependency
168
- name: rspec-mocks
168
+ name: rubocop
169
169
  requirement: !ruby/object:Gem::Requirement
170
170
  requirements:
171
171
  - - "~>"
172
172
  - !ruby/object:Gem::Version
173
- version: '3.5'
173
+ version: '1.48'
174
174
  type: :development
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
178
  - - "~>"
179
179
  - !ruby/object:Gem::Version
180
- version: '3.5'
180
+ version: '1.48'
181
181
  - !ruby/object:Gem::Dependency
182
- name: rubocop
182
+ name: rubocop-performance
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
185
  - - "~>"
186
186
  - !ruby/object:Gem::Version
187
- version: 0.52.1
187
+ version: '1.16'
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.52.1
194
+ version: '1.16'
195
195
  - !ruby/object:Gem::Dependency
196
196
  name: rubocop-rspec
197
197
  requirement: !ruby/object:Gem::Requirement
198
198
  requirements:
199
199
  - - "~>"
200
200
  - !ruby/object:Gem::Version
201
- version: '1.21'
201
+ version: '2.19'
202
202
  type: :development
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
206
  - - "~>"
207
207
  - !ruby/object:Gem::Version
208
- version: '1.21'
208
+ version: '2.19'
209
209
  - !ruby/object:Gem::Dependency
210
210
  name: simplecov
211
211
  requirement: !ruby/object:Gem::Requirement
212
212
  requirements:
213
213
  - - "~>"
214
214
  - !ruby/object:Gem::Version
215
- version: '0.12'
215
+ version: '0.21'
216
216
  type: :development
217
217
  prerelease: false
218
218
  version_requirements: !ruby/object:Gem::Requirement
219
219
  requirements:
220
220
  - - "~>"
221
221
  - !ruby/object:Gem::Version
222
- version: '0.12'
222
+ version: '0.21'
223
223
  - !ruby/object:Gem::Dependency
224
224
  name: yard
225
225
  requirement: !ruby/object:Gem::Requirement
@@ -234,7 +234,7 @@ dependencies:
234
234
  - - "~>"
235
235
  - !ruby/object:Gem::Version
236
236
  version: '0.9'
237
- description:
237
+ description:
238
238
  email: richard.viney@gmail.com
239
239
  executables:
240
240
  - ig_markets
@@ -330,8 +330,9 @@ files:
330
330
  homepage: https://github.com/richard-viney/ig_markets
331
331
  licenses:
332
332
  - MIT
333
- metadata: {}
334
- post_install_message:
333
+ metadata:
334
+ rubygems_mfa_required: 'true'
335
+ post_install_message:
335
336
  rdoc_options: []
336
337
  require_paths:
337
338
  - lib
@@ -339,16 +340,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
339
340
  requirements:
340
341
  - - ">="
341
342
  - !ruby/object:Gem::Version
342
- version: 2.2.2
343
+ version: '2.7'
343
344
  required_rubygems_version: !ruby/object:Gem::Requirement
344
345
  requirements:
345
346
  - - ">="
346
347
  - !ruby/object:Gem::Version
347
348
  version: '0'
348
349
  requirements: []
349
- rubyforge_project:
350
- rubygems_version: 2.7.3
351
- signing_key:
350
+ rubygems_version: 3.4.6
351
+ signing_key:
352
352
  specification_version: 4
353
353
  summary: Library and command-line client for accessing the IG Markets dealing platform.
354
354
  test_files: []