ig_markets 0.31 → 0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -4
  3. data/lib/ig_markets/account.rb +2 -2
  4. data/lib/ig_markets/activity.rb +12 -12
  5. data/lib/ig_markets/application.rb +1 -1
  6. data/lib/ig_markets/cli/commands/activities_command.rb +4 -3
  7. data/lib/ig_markets/cli/commands/orders_command.rb +6 -6
  8. data/lib/ig_markets/cli/commands/performance_command.rb +4 -3
  9. data/lib/ig_markets/cli/commands/positions_command.rb +13 -11
  10. data/lib/ig_markets/cli/commands/prices_command.rb +4 -4
  11. data/lib/ig_markets/cli/commands/sprints_command.rb +2 -2
  12. data/lib/ig_markets/cli/commands/transactions_command.rb +4 -3
  13. data/lib/ig_markets/cli/main.rb +12 -10
  14. data/lib/ig_markets/cli/tables/accounts_table.rb +6 -4
  15. data/lib/ig_markets/cli/tables/activities_table.rb +1 -1
  16. data/lib/ig_markets/cli/tables/historical_price_result_snapshots_table.rb +1 -1
  17. data/lib/ig_markets/cli/tables/market_overviews_table.rb +1 -1
  18. data/lib/ig_markets/client_account_summary.rb +8 -8
  19. data/lib/ig_markets/deal_confirmation.rb +25 -25
  20. data/lib/ig_markets/dealing_platform/account_methods.rb +2 -2
  21. data/lib/ig_markets/dealing_platform/position_methods.rb +13 -6
  22. data/lib/ig_markets/dealing_platform/sprint_market_position_methods.rb +3 -3
  23. data/lib/ig_markets/dealing_platform/streaming_methods.rb +10 -10
  24. data/lib/ig_markets/dealing_platform/working_order_methods.rb +6 -6
  25. data/lib/ig_markets/instrument.rb +7 -7
  26. data/lib/ig_markets/limited_risk_premium.rb +1 -1
  27. data/lib/ig_markets/market.rb +9 -9
  28. data/lib/ig_markets/market_overview.rb +1 -1
  29. data/lib/ig_markets/model.rb +16 -2
  30. data/lib/ig_markets/model/typecasters.rb +1 -1
  31. data/lib/ig_markets/position.rb +6 -6
  32. data/lib/ig_markets/sprint_market_position.rb +1 -1
  33. data/lib/ig_markets/streaming/account_state.rb +1 -1
  34. data/lib/ig_markets/streaming/consolidated_chart_data_update.rb +1 -1
  35. data/lib/ig_markets/streaming/market_update.rb +2 -2
  36. data/lib/ig_markets/streaming/position_update.rb +4 -4
  37. data/lib/ig_markets/streaming/working_order_update.rb +6 -6
  38. data/lib/ig_markets/transaction.rb +5 -5
  39. data/lib/ig_markets/version.rb +1 -1
  40. data/lib/ig_markets/working_order.rb +5 -5
  41. metadata +5 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d43d7d776df76a8ac237f866ea55d5006e1f87c5
4
- data.tar.gz: d4ec2f9f14cb68aeb9b2942bc5e4c5a54f6d59f8
3
+ metadata.gz: 33c3ae06269ac129ea8042da743d2638e9d103a7
4
+ data.tar.gz: 5dc8bdd1bc5f32b58b845f6bec1040eeb2c21e92
5
5
  SHA512:
6
- metadata.gz: 7ebcba64fce12c9f276811d0df4e6588d484de43c5673cfbf7afd8c448f9d6cd94bf396847890d188e5cd2d53326652783e5ef19f24f210e0e2ae08901377c8b
7
- data.tar.gz: 5f3a03a7c45f0d973303fb37284b67ab5ba14e83a73917f540a4054b271b4812227a8afa826c11586fee6378d81c1be933bd8e450e8d74b5c874300e532d41bc
6
+ metadata.gz: 91d9892ccc49bdf29b5143c8ddb7f3e80d8aa7da64e89fb340da98b2fdbc8425c03178f87202a71efe8ec544319961d9c49acf7d6af73b1a86837bcd5caeaf5e
7
+ data.tar.gz: bbb4cdf0f2472244ad059372276520f043d521667218189b2d670f7de5ca6d54efe332224ee920737e1edc07ab5f71b6b3ef9bc7926921b0dbe028e9b6132be3
data/CHANGELOG.md CHANGED
@@ -1,12 +1,25 @@
1
1
  # IG Markets Changelog
2
2
 
3
+ ### 0.32 — May 27, 2017
4
+
5
+ - The `force_open` option now defaults to true for working orders, and is automatically set to true when creating a
6
+ position that specifies a limit distance, limit level, stop distance, or stop level
7
+ - Added `--to` option to the `ig_markets activities`, `ig_markets transactions`, and `ig_markets performance`
8
+ commands
9
+ - All timestamps provided to the `ig_markets activities`, `ig_markets transactions`, and `ig_markets performance`
10
+ commands must now specify an explicit time zone
11
+ - Support the `unavailable` state on `IGMarkets::Streaming::MarketUpdate#market_state`
12
+ - Fix exception in the `ig_markets performance` command when no performance data is found
13
+ - Fixed `IGMarkets::AccountMethods#activities` and `IGMarkets::AccountMethods#transactions` sometimes returning
14
+ duplicate entries
15
+
3
16
  ### 0.31 — March 26, 2017
4
17
 
5
- - Added `IGMarkets::Streaming::PositionUpdate#currency` attribute.
6
- - Added proper detection of an invalid deal ID passed to `ig_markets orders update`.
18
+ - Added `IGMarkets::Streaming::PositionUpdate#currency` attribute
19
+ - Added proper detection of an invalid deal ID passed to `ig_markets orders update`
7
20
  - Limited the update rate of `ig_markets stream` to 2Hz to avoid flickering caused by large numbers of simultaneous
8
- updates.
9
- - Fixed errors caused by a missing millisecond component on certain timestamps.
21
+ updates
22
+ - Fixed errors caused by a missing millisecond component on certain timestamps
10
23
 
11
24
  ### 0.30 — March 10, 2017
12
25
 
@@ -12,13 +12,13 @@ module IGMarkets
12
12
  attribute :account_alias
13
13
  attribute :account_id
14
14
  attribute :account_name
15
- attribute :account_type, Symbol, allowed_values: [:cfd, :physical, :spreadbet]
15
+ attribute :account_type, Symbol, allowed_values: %i[cfd physical spreadbet]
16
16
  attribute :balance, Balance
17
17
  attribute :can_transfer_from, Boolean
18
18
  attribute :can_transfer_to, Boolean
19
19
  attribute :currency, String, regex: Regex::CURRENCY
20
20
  attribute :preferred, Boolean
21
- attribute :status, Symbol, allowed_values: [:disabled, :enabled, :suspended_from_dealing]
21
+ attribute :status, Symbol, allowed_values: %i[disabled enabled suspended_from_dealing]
22
22
 
23
23
  # Reloads this account's attributes by re-querying the IG Markets API.
24
24
  def reload
@@ -6,20 +6,20 @@ module IGMarkets
6
6
  class Details < Model
7
7
  # Contains details on the actions that were performed by an activity. Returned by {#actions}.
8
8
  class Action < Model
9
- attribute :action_type, Symbol, allowed_values: [:limit_order_amended, :limit_order_deleted,
10
- :limit_order_filled, :limit_order_opened, :limit_order_rolled,
11
- :position_closed, :position_deleted, :position_opened,
12
- :position_partially_closed, :position_rolled,
13
- :stop_limit_amended, :stop_order_amended, :stop_order_deleted,
14
- :stop_order_filled, :stop_order_opened, :stop_order_rolled,
15
- :unknown, :working_order_deleted]
9
+ attribute :action_type, Symbol, allowed_values: %i[limit_order_amended limit_order_deleted
10
+ limit_order_filled limit_order_opened limit_order_rolled
11
+ position_closed position_deleted position_opened
12
+ position_partially_closed position_rolled
13
+ stop_limit_amended stop_order_amended stop_order_deleted
14
+ stop_order_filled stop_order_opened stop_order_rolled
15
+ unknown working_order_deleted]
16
16
  attribute :affected_deal_id
17
17
  end
18
18
 
19
19
  attribute :actions, Action
20
20
  attribute :currency
21
21
  attribute :deal_reference
22
- attribute :direction, Symbol, allowed_values: [:buy, :sell]
22
+ attribute :direction, Symbol, allowed_values: %i[buy sell]
23
23
  attribute :good_till_date
24
24
  attribute :guaranteed_stop, Boolean
25
25
  attribute :level, Float
@@ -33,14 +33,14 @@ module IGMarkets
33
33
  attribute :trailing_stop_distance, Integer
34
34
  end
35
35
 
36
- attribute :channel, Symbol, allowed_values: [:dealer, :mobile, :public_fix_api, :public_web_api, :system, :web]
36
+ attribute :channel, Symbol, allowed_values: %i[dealer mobile public_fix_api public_web_api system web]
37
37
  attribute :date, Time, format: '%FT%T'
38
38
  attribute :deal_id
39
39
  attribute :description
40
40
  attribute :details, Details
41
41
  attribute :epic, String, regex: Regex::EPIC
42
- attribute :period, Time, nil_if: %w(- DFB), format: ['%FT%T', '%d-%b-%y', '%b-%y']
43
- attribute :status, Symbol, allowed_values: [:accepted, :rejected, :unknown]
44
- attribute :type, Symbol, allowed_values: [:edit_stop_and_limit, :position, :system, :working_order]
42
+ attribute :period, Time, nil_if: %w[- DFB], format: ['%FT%T', '%d-%b-%y', '%b-%y']
43
+ attribute :status, Symbol, allowed_values: %i[accepted rejected unknown]
44
+ attribute :type, Symbol, allowed_values: %i[edit_stop_and_limit position system working_order]
45
45
  end
46
46
  end
@@ -15,7 +15,7 @@ module IGMarkets
15
15
  attribute :id
16
16
  attribute :name
17
17
  attribute :restricted_to_self, Boolean
18
- attribute :status, Symbol, allowed_values: [:disabled, :enabled, :revoked]
18
+ attribute :status, Symbol, allowed_values: %i[disabled enabled revoked]
19
19
  attribute :terms_accepted_date, Time, format: '%Q'
20
20
  attribute :tier
21
21
  end
@@ -4,10 +4,11 @@ module IGMarkets
4
4
  class Main
5
5
  desc 'activities', 'Prints account activities'
6
6
 
7
- option :days, type: :numeric, required: true, desc: 'The number of days to print account activities for'
8
- option :from, desc: 'The date and time to print account activities from, format: yyyy-mm-ddThh:mm:ss'
7
+ option :days, type: :numeric, desc: 'The number of days to print account activities for'
8
+ option :from, desc: 'The date and time to print account activities from, format: yyyy-mm-ddThh:mm:ss(+|-)zz:zz'
9
+ option :to, desc: 'The end date and time to print account transactions for, format: yyyy-mm-ddThh:mm:ss(+|-)zz:zz'
9
10
  option :epic, desc: 'Regex for filtering activities based on their EPIC'
10
- option :sort_by, enum: %w(channel date epic type), default: 'date', desc: 'The attribute to sort activities by'
11
+ option :sort_by, enum: %w[channel date epic type], default: 'date', desc: 'The attribute to sort activities by'
11
12
 
12
13
  def activities
13
14
  self.class.begin_session(options) do |dealing_platform|
@@ -20,10 +20,10 @@ module IGMarkets
20
20
 
21
21
  option :currency_code, required: true, desc: "The 3 character currency code, must be one of the instrument's " \
22
22
  'currencies'
23
- option :direction, enum: %w(buy sell), required: true, desc: 'The trade direction'
23
+ option :direction, enum: %w[buy sell], required: true, desc: 'The trade direction'
24
24
  option :epic, required: true, desc: 'The EPIC of the market to trade'
25
25
  option :expiry, desc: 'The expiry date of the instrument (if applicable), format: yyyy-mm-dd'
26
- option :force_open, type: :boolean, default: false, desc: 'Whether a force open is required'
26
+ option :force_open, type: :boolean, default: true, desc: 'Whether a force open is required'
27
27
  option :good_till_date, desc: 'The date that the order will live till, format: yyyy-mm-ddThh:mm(+|-)zz:zz'
28
28
  option :guaranteed_stop, type: :boolean, default: false, desc: 'Whether a guaranteed stop is required'
29
29
  option :level, type: :numeric, required: true, desc: 'The level at which the order will be triggered'
@@ -32,7 +32,7 @@ module IGMarkets
32
32
  option :size, type: :numeric, required: true, desc: 'The size of the order'
33
33
  option :stop_distance, type: :numeric, desc: 'The distance away in pips to place the stop'
34
34
  option :stop_level, type: :numeric, desc: 'The level at which to place the stop'
35
- option :type, enum: %w(limit stop), required: true, desc: 'The order type'
35
+ option :type, enum: %w[limit stop], required: true, desc: 'The order type'
36
36
 
37
37
  def create
38
38
  Main.begin_session(options) do |dealing_platform|
@@ -50,7 +50,7 @@ module IGMarkets
50
50
  option :limit_level, type: :numeric, desc: 'The level at which to place the limit'
51
51
  option :stop_distance, desc: 'The distance away in pips to place the stop'
52
52
  option :stop_level, type: :numeric, desc: 'The level at which to place the stop'
53
- option :type, enum: %w(limit stop), desc: 'The order type'
53
+ option :type, enum: %w[limit stop], desc: 'The order type'
54
54
 
55
55
  def update(deal_id)
56
56
  Main.begin_session(options) do |dealing_platform|
@@ -92,8 +92,8 @@ module IGMarkets
92
92
 
93
93
  private
94
94
 
95
- ATTRIBUTES = [:currency_code, :direction, :epic, :expiry, :force_open, :good_till_date, :guaranteed_stop, :level,
96
- :limit_distance, :limit_level, :size, :stop_distance, :stop_level, :type].freeze
95
+ ATTRIBUTES = %i[currency_code direction epic expiry force_open good_till_date guaranteed_stop level
96
+ limit_distance limit_level size stop_distance stop_level type].freeze
97
97
 
98
98
  def working_order_attributes
99
99
  attributes = Main.filter_options options, ATTRIBUTES
@@ -4,8 +4,9 @@ module IGMarkets
4
4
  class Main
5
5
  desc 'performance', 'Prints a summary of trading performance over a period'
6
6
 
7
- option :days, type: :numeric, required: true, desc: 'The number of days to print performance for'
8
- option :from, desc: 'The date and time to show performance from, format: yyyy-mm-ddThh:mm:ss'
7
+ option :days, type: :numeric, desc: 'The number of days to print performance for'
8
+ option :from, desc: 'The date and time to show performance from, format: yyyy-mm-ddThh:mm:ss(+|-)zz:zz'
9
+ option :to, desc: 'The end date and time to show transactions for, format: yyyy-mm-ddThh:mm:ss(+|-)zz:zz'
9
10
 
10
11
  def performance
11
12
  self.class.begin_session(options) do |dealing_platform|
@@ -16,7 +17,7 @@ module IGMarkets
16
17
 
17
18
  puts table
18
19
 
19
- print_summary performances
20
+ print_summary performances if performances.any?
20
21
  end
21
22
  end
22
23
 
@@ -26,22 +26,24 @@ module IGMarkets
26
26
 
27
27
  option :currency_code, required: true, desc: "The 3 character currency code, must be one of the instrument's " \
28
28
  'currencies'
29
- option :direction, required: true, enum: %w(buy sell), desc: 'The trade direction'
29
+ option :direction, required: true, enum: %w[buy sell], desc: 'The trade direction'
30
30
  option :epic, required: true, desc: 'The EPIC of the market to trade'
31
31
  option :expiry, desc: 'The expiry date of the instrument (if applicable), format: yyyy-mm-dd'
32
- option :force_open, type: :boolean, default: false, desc: 'Whether a force open is required'
32
+ option :force_open, type: :boolean, desc: 'Whether a force open is required, defaults to true if ' \
33
+ '--limit-distance, --limit-level, --stop-distance or --stop-level ' \
34
+ 'are specified'
33
35
  option :guaranteed_stop, type: :boolean, default: false, desc: 'Whether a guaranteed stop is required'
34
36
  option :level, type: :numeric, desc: "Required if and only if --order-type is 'limit' or 'quote'"
35
37
  option :limit_distance, type: :numeric, desc: 'The distance away in pips to place the limit, if set then ' \
36
38
  '--limit-level must not be used'
37
39
  option :limit_level, type: :numeric, desc: 'The limit level, if set then --limit-distance must not be used'
38
- option :order_type, enum: %w(limit market quote), default: 'market', desc: 'The order type'
40
+ option :order_type, enum: %w[limit market quote], default: 'market', desc: 'The order type'
39
41
  option :quote_id, desc: 'The Lightstreamer quote ID, required when using --order-type=quote'
40
42
  option :size, type: :numeric, required: true, desc: 'The size of the position'
41
43
  option :stop_distance, type: :numeric, desc: 'The distance away in pips to place the stop, if set then ' \
42
44
  '--stop-level must not be used'
43
45
  option :stop_level, type: :numeric, desc: 'The stop level, if set then --stop-distance must not be used'
44
- option :time_in_force, enum: %w(execute-and-eliminate fill-or-kill), desc: 'The order fill strategy'
46
+ option :time_in_force, enum: %w[execute-and-eliminate fill-or-kill], desc: 'The order fill strategy'
45
47
  option :trailing_stop, type: :boolean, desc: 'Whether to use a trailing stop, defaults to false'
46
48
  option :trailing_stop_increment, type: :numeric, desc: 'The increment step in pips for the trailing stop, ' \
47
49
  'required when --trailing-stop is specified'
@@ -71,11 +73,11 @@ module IGMarkets
71
73
  desc 'close DEAL-ID', 'Closes or partially closes a position'
72
74
 
73
75
  option :level, type: :numeric, desc: "Required if and only if --order-type is 'limit' or 'quote'"
74
- option :order_type, enum: %w(limit market quote), default: 'market', desc: 'The order type'
76
+ option :order_type, enum: %w[limit market quote], default: 'market', desc: 'The order type'
75
77
  option :quote_id, desc: 'The Lightstreamer quote ID, required when using --order-type=quote'
76
78
  option :size, type: :numeric, desc: 'The size of the position to close, if not specified then the entire ' \
77
79
  'position will be closed'
78
- option :time_in_force, enum: %w(execute-and-eliminate fill-or-kill), desc: 'The order fill strategy'
80
+ option :time_in_force, enum: %w[execute-and-eliminate fill-or-kill], desc: 'The order fill strategy'
79
81
 
80
82
  def close(deal_id)
81
83
  with_position(deal_id) do |position|
@@ -85,8 +87,8 @@ module IGMarkets
85
87
 
86
88
  desc 'close-all', 'Closes all open positions'
87
89
 
88
- option :order_type, enum: %w(limit market quote), default: 'market', desc: 'The order type'
89
- option :time_in_force, enum: %w(execute-and-eliminate fill-or-kill), desc: 'The order fill strategy'
90
+ option :order_type, enum: %w[limit market quote], default: 'market', desc: 'The order type'
91
+ option :time_in_force, enum: %w[execute-and-eliminate fill-or-kill], desc: 'The order fill strategy'
90
92
 
91
93
  def close_all
92
94
  Main.begin_session(options) do |dealing_platform|
@@ -100,9 +102,9 @@ module IGMarkets
100
102
 
101
103
  private
102
104
 
103
- ATTRIBUTES = [:currency_code, :direction, :epic, :expiry, :force_open, :guaranteed_stop, :level, :limit_distance,
104
- :limit_level, :order_type, :quote_id, :size, :stop_distance, :stop_level, :time_in_force,
105
- :trailing_stop, :trailing_stop_increment].freeze
105
+ ATTRIBUTES = %i[currency_code direction epic expiry force_open guaranteed_stop level limit_distance
106
+ limit_level order_type quote_id size stop_distance stop_level time_in_force
107
+ trailing_stop trailing_stop_increment].freeze
106
108
 
107
109
  def position_attributes
108
110
  attributes = Main.filter_options options, ATTRIBUTES
@@ -5,8 +5,8 @@ module IGMarkets
5
5
  desc 'prices', 'Prints historical prices for a market'
6
6
 
7
7
  option :epic, required: true, desc: 'The EPIC of the market to print historical prices for'
8
- option :resolution, enum: %w(second minute minute-2 minute-3 minute-5 minute-10 minute-15 minute-30 hour hour-2
9
- hour-3 hour-4 day week month), required: true, desc: 'The price resolution'
8
+ option :resolution, enum: %w[second minute minute-2 minute-3 minute-5 minute-10 minute-15 minute-30 hour hour-2
9
+ hour-3 hour-4 day week month], required: true, desc: 'The price resolution'
10
10
  option :number, type: :numeric, desc: 'The number of historical prices to return, if this is specified then ' \
11
11
  '--from and --to are ignored, otherwise they are required'
12
12
  option :from, desc: 'The start of the period to return prices for, required unless --number is specified, ' \
@@ -55,9 +55,9 @@ END
55
55
  end
56
56
 
57
57
  def historical_price_result_from_date_range(market)
58
- filtered_options = self.class.filter_options options, [:from, :to]
58
+ filtered_options = self.class.filter_options options, %i[from to]
59
59
 
60
- [:from, :to].each do |attribute|
60
+ %i[from to].each do |attribute|
61
61
  self.class.parse_date_time filtered_options, attribute, Time, '%FT%T%z', 'yyyy-mm-ddThh:mm:ss(+|-)zz:zz'
62
62
  end
63
63
 
@@ -20,9 +20,9 @@ module IGMarkets
20
20
 
21
21
  desc 'create', 'Creates a new sprint market position'
22
22
 
23
- option :direction, enum: %w(buy sell), required: true, desc: 'The trade direction'
23
+ option :direction, enum: %w[buy sell], required: true, desc: 'The trade direction'
24
24
  option :epic, required: true, desc: 'The EPIC of the market to trade'
25
- option :expiry_period, enum: %w(1 2 5 20 60), required: true, desc: 'The expiry period in seconds'
25
+ option :expiry_period, enum: %w[1 2 5 20 60], required: true, desc: 'The expiry period in seconds'
26
26
  option :size, required: true, desc: 'The position size'
27
27
 
28
28
  def create
@@ -4,11 +4,12 @@ module IGMarkets
4
4
  class Main
5
5
  desc 'transactions', 'Prints account transactions'
6
6
 
7
- option :days, type: :numeric, required: true, desc: 'The number of days to print account transactions for'
8
- option :from, desc: 'The date and time to print account transactions from, format: yyyy-mm-ddThh:mm:ss'
7
+ option :days, type: :numeric, desc: 'The number of days to print account transactions for'
8
+ option :from, desc: 'The date and time to print account transactions from, format: yyyy-mm-ddThh:mm:ss(+|-)zz:zz'
9
+ option :to, desc: 'The end date and time to print account transactions for, format: yyyy-mm-ddThh:mm:ss(+|-)zz:zz'
9
10
  option :instrument, desc: 'Regex for filtering transactions based on their instrument'
10
11
  option :interest, type: :boolean, default: true, desc: 'Whether to show interest deposits and withdrawals'
11
- option :sort_by, enum: %w(date instrument profit-loss type), default: 'date', desc: 'The attribute to sort ' \
12
+ option :sort_by, enum: %w[date instrument profit-loss type], default: 'date', desc: 'The attribute to sort ' \
12
13
  'transactions by'
13
14
 
14
15
  def transactions
@@ -27,21 +27,23 @@ module IGMarkets
27
27
 
28
28
  private
29
29
 
30
- # Turns the `:days` and `:from` options into a hash with `:from` and `:to` keys that can be passed to
31
- # {AccountMethods#activities} and {AccountMethods#transactions}.
30
+ # Turns the `:days` or `:from` options into a hash that can be passed to {AccountMethods#activities} and
31
+ # {AccountMethods#transactions}.
32
32
  def history_options
33
- days_in_seconds = options[:days] * 24 * 60 * 60
34
-
35
33
  if options[:from]
36
- from = Time.strptime options[:from], '%FT%T'
37
- to = from + days_in_seconds
38
-
39
- { from: from, to: to }
34
+ {
35
+ from: history_options_parse_time(options[:from]),
36
+ to: history_options_parse_time(options[:to])
37
+ }
40
38
  else
41
- { from: Time.now - days_in_seconds }
39
+ { from: Time.now.utc - options[:days] * 86_400 }
42
40
  end
43
41
  end
44
42
 
43
+ def history_options_parse_time(input)
44
+ input && Time.strptime(input, '%FT%T%z')
45
+ end
46
+
45
47
  class << self
46
48
  # This is the initial entry point for the execution of the command-line client. It is responsible for reading
47
49
  # any config files, implementing the --version/-v options, and then invoking the main application.
@@ -97,7 +99,7 @@ module IGMarkets
97
99
  end
98
100
 
99
101
  # Parses and validates a `Date` or `Time` option received as a command-line argument. Raises `ArgumentError` if
100
- # it is been specified in an invalid format.
102
+ # it has been specified in an invalid format.
101
103
  #
102
104
  # @param [Hash] attributes The attributes hash.
103
105
  # @param [Symbol] attribute The name of the date or time attribute to parse and validate.
@@ -22,10 +22,12 @@ module IGMarkets
22
22
  status = { disabled: 'Disabled', enabled: 'Enabled',
23
23
  suspended_from_dealing: 'Suspended' }.fetch account.status
24
24
 
25
- [account.account_name, account.account_id, type, account.currency, status, account.preferred] +
26
- [:available, :balance, :deposit, :profit_loss].map do |attribute|
27
- Format.currency account.balance.send(attribute), account.currency
28
- end
25
+ currency_values = %i[available balance deposit profit_loss].map do |attribute|
26
+ Format.currency account.balance.send(attribute), account.currency
27
+ end
28
+
29
+ [account.account_name, account.account_id, type, account.currency, status,
30
+ account.preferred] + currency_values
29
31
  end
30
32
 
31
33
  def cell_color(value, _model, _row_index, column_index)
@@ -10,7 +10,7 @@ module IGMarkets
10
10
  end
11
11
 
12
12
  def headings
13
- %w(Date Channel Type Status EPIC Market Size Level Limit Stop Result)
13
+ %w[Date Channel Type Status EPIC Market Size Level Limit Stop Result]
14
14
  end
15
15
 
16
16
  def right_aligned_columns
@@ -6,7 +6,7 @@ module IGMarkets
6
6
  private
7
7
 
8
8
  def headings
9
- %w(Date Open Close Low High)
9
+ %w[Date Open Close Low High]
10
10
  end
11
11
 
12
12
  def right_aligned_columns
@@ -34,7 +34,7 @@ module IGMarkets
34
34
  end
35
35
 
36
36
  def levels(market_overview)
37
- [:bid, :offer, :high, :low, :net_change, :percentage_change].map do |attribute|
37
+ %i[bid offer high low net_change percentage_change].map do |attribute|
38
38
  Format.level market_overview.send(attribute)
39
39
  end
40
40
  end
@@ -5,7 +5,7 @@ module IGMarkets
5
5
  class FormDetails < Model
6
6
  attribute :form_dismissable, Boolean
7
7
  attribute :form_title
8
- attribute :form_type, Symbol, allowed_values: [:bca, :kyc]
8
+ attribute :form_type, Symbol, allowed_values: %i[bca kyc]
9
9
  attribute :form_url
10
10
  end
11
11
 
@@ -13,17 +13,17 @@ module IGMarkets
13
13
  class AccountDetails < Model
14
14
  attribute :account_id
15
15
  attribute :account_name
16
- attribute :account_type, Symbol, allowed_values: [:cfd, :physical, :spreadbet]
16
+ attribute :account_type, Symbol, allowed_values: %i[cfd physical spreadbet]
17
17
  attribute :preferred, Boolean
18
18
  end
19
19
 
20
20
  attribute :account_info, Account::Balance
21
- attribute :account_type, Symbol, allowed_values: [:cfd, :physical, :spreadbet]
21
+ attribute :account_type, Symbol, allowed_values: %i[cfd physical spreadbet]
22
22
  attribute :accounts, AccountDetails
23
- attribute :authentication_status, Symbol, allowed_values: [:authenticated, :authenticated_missing_credentials,
24
- :change_environment, :disabled_preferred_account,
25
- :missing_preferred_account,
26
- :rejected_invalid_client_version]
23
+ attribute :authentication_status, Symbol, allowed_values: %i[authenticated authenticated_missing_credentials
24
+ change_environment disabled_preferred_account
25
+ missing_preferred_account
26
+ rejected_invalid_client_version]
27
27
  attribute :client_id
28
28
  attribute :currency_iso_code, String, regex: Regex::CURRENCY
29
29
  attribute :currency_symbol
@@ -35,7 +35,7 @@ module IGMarkets
35
35
  attribute :has_active_live_accounts, Boolean
36
36
  attribute :ig_company
37
37
  attribute :lightstreamer_endpoint
38
- attribute :rerouting_environment, Symbol, allowed_values: [:demo, :live, :test, :uat]
38
+ attribute :rerouting_environment, Symbol, allowed_values: %i[demo live test uat]
39
39
  attribute :timezone_offset, Float
40
40
  attribute :trailing_stops_enabled, Boolean
41
41
  end
@@ -4,7 +4,7 @@ module IGMarkets
4
4
  # Contains details on a specific deal that was affected by a dealing event. Returned by {#affected_deals}.
5
5
  class AffectedDeal < Model
6
6
  attribute :deal_id
7
- attribute :status, Symbol, allowed_values: [:amended, :deleted, :fully_closed, :opened, :partially_closed]
7
+ attribute :status, Symbol, allowed_values: %i[amended deleted fully_closed opened partially_closed]
8
8
  end
9
9
 
10
10
  attribute :account_id
@@ -13,38 +13,38 @@ module IGMarkets
13
13
  attribute :date, Time, format: ['%FT%T.%L', '%FT%T']
14
14
  attribute :deal_id
15
15
  attribute :deal_reference
16
- attribute :deal_status, Symbol, allowed_values: [:accepted, :fund_account, :rejected]
17
- attribute :direction, Symbol, allowed_values: [:buy, :sell]
16
+ attribute :deal_status, Symbol, allowed_values: %i[accepted fund_account rejected]
17
+ attribute :direction, Symbol, allowed_values: %i[buy sell]
18
18
  attribute :epic, String, regex: Regex::EPIC
19
- attribute :expiry, Date, nil_if: %w(- DFB), format: ['%d-%b-%y', '%b-%y']
19
+ attribute :expiry, Date, nil_if: %w[- DFB], format: ['%d-%b-%y', '%b-%y']
20
20
  attribute :guaranteed_stop, Boolean
21
21
  attribute :level, Float
22
22
  attribute :limit_distance, Integer
23
23
  attribute :limit_level, Float
24
24
  attribute :profit, Float
25
25
  attribute :profit_currency, String, regex: Regex::CURRENCY
26
- attribute :reason, Symbol, allowed_values: [:account_not_enabled_to_trading, :attached_order_level_error,
27
- :attached_order_trailing_stop_error, :cannot_change_stop_type,
28
- :cannot_remove_stop, :closing_only_trades_accepted_on_this_market,
29
- :conflicting_order, :contact_support_instrument_error, :cr_spacing,
30
- :duplicate_order_error, :exchange_manual_override,
31
- :finance_repeat_dealing, :force_open_on_same_market_different_currency,
32
- :general_error, :good_till_date_in_the_past, :instrument_not_found,
33
- :insufficient_funds, :level_tolerance_error, :manual_order_timeout,
34
- :market_closed, :market_closed_with_edits, :market_closing,
35
- :market_not_borrowable, :market_offline, :market_phone_only,
36
- :market_rolled, :market_unavailable_to_client, :max_auto_size_exceeded,
37
- :minimum_order_size_error, :move_away_only_limit, :move_away_only_stop,
38
- :move_away_only_trigger_level, :opposing_direction_orders_not_allowed,
39
- :opposing_positions_not_allowed, :order_locked, :order_not_found,
40
- :over_normal_market_size, :partially_closed_position_not_deleted,
41
- :position_not_available_to_close, :position_not_found,
42
- :reject_spreadbet_order_on_cfd_account, :size_increment,
43
- :sprint_market_expiry_after_market_close, :stop_or_limit_not_allowed,
44
- :stop_required_error, :strike_level_tolerance, :success,
45
- :trailing_stop_not_allowed, :unknown, :wrong_side_of_market]
26
+ attribute :reason, Symbol, allowed_values: %i[account_not_enabled_to_trading attached_order_level_error
27
+ attached_order_trailing_stop_error cannot_change_stop_type
28
+ cannot_remove_stop closing_only_trades_accepted_on_this_market
29
+ conflicting_order contact_support_instrument_error cr_spacing
30
+ duplicate_order_error exchange_manual_override
31
+ finance_repeat_dealing force_open_on_same_market_different_currency
32
+ general_error good_till_date_in_the_past instrument_not_found
33
+ insufficient_funds level_tolerance_error manual_order_timeout
34
+ market_closed market_closed_with_edits market_closing
35
+ market_not_borrowable market_offline market_phone_only
36
+ market_rolled market_unavailable_to_client max_auto_size_exceeded
37
+ minimum_order_size_error move_away_only_limit move_away_only_stop
38
+ move_away_only_trigger_level opposing_direction_orders_not_allowed
39
+ opposing_positions_not_allowed order_locked order_not_found
40
+ over_normal_market_size partially_closed_position_not_deleted
41
+ position_not_available_to_close position_not_found
42
+ reject_spreadbet_order_on_cfd_account size_increment
43
+ sprint_market_expiry_after_market_close stop_or_limit_not_allowed
44
+ stop_required_error strike_level_tolerance success
45
+ trailing_stop_not_allowed unknown wrong_side_of_market]
46
46
  attribute :size, Float
47
- attribute :status, Symbol, allowed_values: [:amended, :closed, :deleted, :open, :partially_closed]
47
+ attribute :status, Symbol, allowed_values: %i[amended closed deleted open partially_closed]
48
48
  attribute :stop_distance, Integer
49
49
  attribute :stop_level, Float
50
50
  attribute :trailing_stop, Boolean
@@ -45,7 +45,7 @@ module IGMarkets
45
45
  def transactions(options)
46
46
  options[:type] ||= :all
47
47
 
48
- unless [:all, :all_deal, :deposit, :withdrawal].include? options[:type]
48
+ unless %i[all all_deal deposit withdrawal].include? options[:type]
49
49
  raise ArgumentError, "invalid transaction type: #{options[:type]}"
50
50
  end
51
51
 
@@ -85,7 +85,7 @@ module IGMarkets
85
85
  options[:url_parameters][:to] = request_result.last.send(options[:date_attribute]).utc.strftime('%FT%T')
86
86
  end
87
87
 
88
- models.uniq
88
+ models.uniq(&:to_h)
89
89
  end
90
90
 
91
91
  # Parses and formats options shared by {#activities} and {#transactions} into a set of URL parameters.
@@ -80,7 +80,7 @@ module IGMarkets
80
80
  # Internal model used by {#create}
81
81
  class PositionCreateAttributes < Model
82
82
  attribute :currency_code, String, regex: Regex::CURRENCY
83
- attribute :direction, Symbol, allowed_values: [:buy, :sell]
83
+ attribute :direction, Symbol, allowed_values: %i[buy sell]
84
84
  attribute :epic, String, regex: Regex::EPIC
85
85
  attribute :expiry, Date, format: '%d-%b-%y'
86
86
  attribute :force_open, Boolean
@@ -88,12 +88,12 @@ module IGMarkets
88
88
  attribute :level, Float
89
89
  attribute :limit_distance, Integer
90
90
  attribute :limit_level, Float
91
- attribute :order_type, Symbol, allowed_values: [:limit, :market, :quote]
91
+ attribute :order_type, Symbol, allowed_values: %i[limit market quote]
92
92
  attribute :quote_id
93
93
  attribute :size, Float
94
94
  attribute :stop_distance, Integer
95
95
  attribute :stop_level, Float
96
- attribute :time_in_force, Symbol, allowed_values: [:execute_and_eliminate, :fill_or_kill]
96
+ attribute :time_in_force, Symbol, allowed_values: %i[execute_and_eliminate fill_or_kill]
97
97
  attribute :trailing_stop, Boolean
98
98
  attribute :trailing_stop_increment, Integer
99
99
 
@@ -106,12 +106,19 @@ module IGMarkets
106
106
  private
107
107
 
108
108
  def set_defaults
109
- self.force_open = false if force_open.nil?
109
+ set_default_force_open
110
+
110
111
  self.guaranteed_stop = false if guaranteed_stop.nil?
111
112
  self.order_type ||= :market
112
113
  self.time_in_force = :execute_and_eliminate if order_type == :market
113
114
  end
114
115
 
116
+ def set_default_force_open
117
+ self.force_open = false if force_open.nil?
118
+ self.force_open = true if attributes[:limit_distance] || attributes[:limit_level] ||
119
+ attributes[:stop_distance] || attributes[:stop_level]
120
+ end
121
+
115
122
  # Runs a series of validations on this model's attributes to check whether it is ready to be sent to the IG
116
123
  # Markets API.
117
124
  def validate
@@ -124,8 +131,8 @@ module IGMarkets
124
131
 
125
132
  # Checks that all required attributes for position creation are present.
126
133
  def validate_required_attributes
127
- required = [:currency_code, :direction, :epic, :force_open, :guaranteed_stop, :order_type, :size,
128
- :time_in_force]
134
+ required = %i[currency_code direction epic force_open guaranteed_stop order_type size
135
+ time_in_force]
129
136
 
130
137
  required.each do |attribute|
131
138
  raise ArgumentError, "#{attribute} attribute must be set" if attributes[attribute].nil?
@@ -49,10 +49,10 @@ module IGMarkets
49
49
 
50
50
  # Internal model used by {#create}
51
51
  class SprintMarketPositionCreateAttributes < Model
52
- attribute :direction, Symbol, allowed_values: [:buy, :sell]
52
+ attribute :direction, Symbol, allowed_values: %i[buy sell]
53
53
  attribute :epic, String, regex: Regex::EPIC
54
- attribute :expiry_period, Symbol, allowed_values: [:one_minute, :two_minutes, :five_minutes, :twenty_minutes,
55
- :sixty_minutes]
54
+ attribute :expiry_period, Symbol, allowed_values: %i[one_minute two_minutes five_minutes twenty_minutes
55
+ sixty_minutes]
56
56
  attribute :size, Float
57
57
  end
58
58
 
@@ -49,8 +49,8 @@ module IGMarkets
49
49
  accounts ||= @dealing_platform.client_account_summary.accounts
50
50
 
51
51
  items = Array(accounts).map { |account| "ACCOUNT:#{account.account_id}" }
52
- fields = [:available_cash, :available_to_deal, :deposit, :equity, :equity_used, :funds, :margin, :margin_lr,
53
- :margin_nlr, :pnl, :pnl_lr, :pnl_nlr]
52
+ fields = %i[available_cash available_to_deal deposit equity equity_used funds margin margin_lr
53
+ margin_nlr pnl pnl_lr pnl_nlr]
54
54
 
55
55
  build_subscription items: items, fields: fields, mode: :merge
56
56
  end
@@ -64,8 +64,8 @@ module IGMarkets
64
64
  # @return [Streaming::Subscription]
65
65
  def build_markets_subscription(epics)
66
66
  items = Array(epics).map { |epic| "MARKET:#{epic}" }
67
- fields = [:bid, :change, :change_pct, :high, :low, :market_delay, :market_state, :mid_open, :odds, :offer,
68
- :strike_price, :update_time]
67
+ fields = %i[bid change change_pct high low market_delay market_state mid_open odds offer
68
+ strike_price update_time]
69
69
 
70
70
  build_subscription items: items, fields: fields, mode: :merge
71
71
  end
@@ -82,7 +82,7 @@ module IGMarkets
82
82
  accounts ||= @dealing_platform.client_account_summary.accounts
83
83
 
84
84
  items = Array(accounts).map { |account| "TRADE:#{account.account_id}" }
85
- fields = [:confirms, :opu, :wou]
85
+ fields = %i[confirms opu wou]
86
86
 
87
87
  build_subscription items: items, fields: fields, mode: :distinct
88
88
  end
@@ -96,8 +96,8 @@ module IGMarkets
96
96
  # @return [Streaming::Subscription]
97
97
  def build_chart_ticks_subscription(epics)
98
98
  items = Array(epics).map { |epic| "CHART:#{epic}:TICK" }
99
- fields = [:bid, :day_high, :day_low, :day_net_chg_mid, :day_open_mid, :day_perc_chg_mid, :ltp, :ltv, :ofr, :ttv,
100
- :utm]
99
+ fields = %i[bid day_high day_low day_net_chg_mid day_open_mid day_perc_chg_mid ltp ltv ofr ttv
100
+ utm]
101
101
 
102
102
  build_subscription items: items, fields: fields, mode: :distinct
103
103
  end
@@ -114,9 +114,9 @@ module IGMarkets
114
114
  scale = { one_second: 'SECOND', one_minute: '1MINUTE', five_minutes: '5MINUTE', one_hour: 'HOUR' }.fetch scale
115
115
  items = ["CHART:#{epic}:#{scale}"]
116
116
 
117
- fields = [:bid_close, :bid_high, :bid_low, :bid_open, :cons_end, :cons_tick_count, :day_high, :day_low,
118
- :day_net_chg_mid, :day_open_mid, :day_perc_chg_mid, :ltp_close, :ltp_high, :ltp_low, :ltp_open, :ltv,
119
- :ofr_close, :ofr_high, :ofr_low, :ofr_open, :ttv, :utm]
117
+ fields = %i[bid_close bid_high bid_low bid_open cons_end cons_tick_count day_high day_low
118
+ day_net_chg_mid day_open_mid day_perc_chg_mid ltp_close ltp_high ltp_low ltp_open ltv
119
+ ofr_close ofr_high ofr_low ofr_open ttv utm]
120
120
 
121
121
  build_subscription items: items, fields: fields, mode: :merge
122
122
  end
@@ -39,7 +39,7 @@ module IGMarkets
39
39
  # @option attributes [:buy, :sell] :direction Order direction. Required.
40
40
  # @option attributes [String] :epic The EPIC of the instrument for the order. Required.
41
41
  # @option attributes [Date] :expiry The expiry date of the instrument (if applicable). Optional.
42
- # @option attributes [Boolean] :force_open Whether a force open is required. Defaults to `false`.
42
+ # @option attributes [Boolean] :force_open Whether a force open is required. Defaults to `true`.
43
43
  # @option attributes [Time] :good_till_date The date that the working order will live till. If not specified then
44
44
  # the working order will remain until it is cancelled.
45
45
  # @option attributes [Boolean] :guaranteed_stop Whether a guaranteed stop is required. Defaults to `false`.
@@ -72,7 +72,7 @@ module IGMarkets
72
72
  # Internal model used by {#create}.
73
73
  class WorkingOrderCreateAttributes < Model
74
74
  attribute :currency_code, String, regex: Regex::CURRENCY
75
- attribute :direction, Symbol, allowed_values: [:buy, :sell]
75
+ attribute :direction, Symbol, allowed_values: %i[buy sell]
76
76
  attribute :epic, String, regex: Regex::EPIC
77
77
  attribute :expiry, Date, format: '%d-%b-%y'
78
78
  attribute :force_open, Boolean
@@ -84,8 +84,8 @@ module IGMarkets
84
84
  attribute :size, Float
85
85
  attribute :stop_distance, Integer
86
86
  attribute :stop_level, Float
87
- attribute :time_in_force, Symbol, allowed_values: [:good_till_cancelled, :good_till_date]
88
- attribute :type, Symbol, allowed_values: [:limit, :stop]
87
+ attribute :time_in_force, Symbol, allowed_values: %i[good_till_cancelled good_till_date]
88
+ attribute :type, Symbol, allowed_values: %i[limit stop]
89
89
 
90
90
  def initialize(attributes)
91
91
  super
@@ -96,7 +96,7 @@ module IGMarkets
96
96
  private
97
97
 
98
98
  def set_defaults
99
- self.force_open = false if force_open.nil?
99
+ self.force_open = true if force_open.nil?
100
100
  self.guaranteed_stop = false if guaranteed_stop.nil?
101
101
  self.time_in_force = good_till_date ? :good_till_date : :good_till_cancelled
102
102
  end
@@ -104,7 +104,7 @@ module IGMarkets
104
104
  # Runs a series of validations on this model's attributes to check whether it is ready to be sent to the IG
105
105
  # Markets API.
106
106
  def validate
107
- required = [:currency_code, :direction, :epic, :guaranteed_stop, :level, :size, :time_in_force, :type]
107
+ required = %i[currency_code direction epic guaranteed_stop level size time_in_force type]
108
108
  required.each do |attribute|
109
109
  raise ArgumentError, "#{attribute} attribute must be set" if send(attribute).nil?
110
110
  end
@@ -62,14 +62,14 @@ module IGMarkets
62
62
  attribute :country
63
63
  attribute :currencies, Currency
64
64
  attribute :epic, String, regex: Regex::EPIC
65
- attribute :expiry, Date, nil_if: %w(- DFB), format: ['%d-%b-%y', '%b-%y']
65
+ attribute :expiry, Date, nil_if: %w[- DFB], format: ['%d-%b-%y', '%b-%y']
66
66
  attribute :expiry_details, ExpiryDetails
67
67
  attribute :force_open_allowed, Boolean
68
68
  attribute :limited_risk_premium, LimitedRiskPremium
69
69
  attribute :lot_size, Float
70
70
  attribute :margin_deposit_bands, MarginDepositBand
71
71
  attribute :margin_factor, Float
72
- attribute :margin_factor_unit, Symbol, allowed_values: [:percentage, :points]
72
+ attribute :margin_factor_unit, Symbol, allowed_values: %i[percentage points]
73
73
  attribute :market_id
74
74
  attribute :name
75
75
  attribute :news_code
@@ -82,11 +82,11 @@ module IGMarkets
82
82
  attribute :sprint_markets_minimum_expiry_time, Float
83
83
  attribute :stops_limits_allowed, Boolean
84
84
  attribute :streaming_prices_available, Boolean
85
- attribute :type, Symbol, allowed_values: [:binary, :bungee_capped, :bungee_commodities, :bungee_currencies,
86
- :bungee_indices, :commodities, :currencies, :indices, :opt_commodities,
87
- :opt_currencies, :opt_indices, :opt_rates, :opt_shares, :rates, :sectors,
88
- :shares, :sprint_market, :test_market, :unknown]
89
- attribute :unit, Symbol, allowed_values: [:amount, :contracts, :shares]
85
+ attribute :type, Symbol, allowed_values: %i[binary bungee_capped bungee_commodities bungee_currencies
86
+ bungee_indices commodities currencies indices opt_commodities
87
+ opt_currencies opt_indices opt_rates opt_shares rates sectors
88
+ shares sprint_market test_market unknown]
89
+ attribute :unit, Symbol, allowed_values: %i[amount contracts shares]
90
90
  attribute :value_of_one_pip
91
91
  end
92
92
  end
@@ -2,7 +2,7 @@ module IGMarkets
2
2
  # Contains details on a limited risk premium. Returned by {Instrument#limited_risk_premium},
3
3
  # {Position#limited_risk_premium} and {WorkingOrder#limited_risk_premium}.
4
4
  class LimitedRiskPremium < Model
5
- attribute :unit, Symbol, allowed_values: [:percentage, :points]
5
+ attribute :unit, Symbol, allowed_values: %i[percentage points]
6
6
  attribute :value, Float
7
7
  end
8
8
  end
@@ -7,18 +7,18 @@ module IGMarkets
7
7
  class DealingRules < Model
8
8
  # Contains specfics for a single dealing rule.
9
9
  class RuleDetails < Model
10
- attribute :unit, Symbol, allowed_values: [:percentage, :points]
10
+ attribute :unit, Symbol, allowed_values: %i[percentage points]
11
11
  attribute :value, Float
12
12
  end
13
13
 
14
- attribute :market_order_preference, Symbol, allowed_values: [:available_default_off, :available_default_on,
15
- :not_available]
14
+ attribute :market_order_preference, Symbol, allowed_values: %i[available_default_off available_default_on
15
+ not_available]
16
16
  attribute :max_stop_or_limit_distance, RuleDetails
17
17
  attribute :min_controlled_risk_stop_distance, RuleDetails
18
18
  attribute :min_deal_size, RuleDetails
19
19
  attribute :min_normal_stop_or_limit_distance, RuleDetails
20
20
  attribute :min_step_distance, RuleDetails
21
- attribute :trailing_stops_preference, Symbol, allowed_values: [:available, :not_available]
21
+ attribute :trailing_stops_preference, Symbol, allowed_values: %i[available not_available]
22
22
  end
23
23
 
24
24
  # Contains details on a snapshot of a market. Returned by {#snapshot}.
@@ -30,8 +30,8 @@ module IGMarkets
30
30
  attribute :delay_time, Float
31
31
  attribute :high, Float
32
32
  attribute :low, Float
33
- attribute :market_status, Symbol, allowed_values: [:closed, :edits_only, :offline, :on_auction,
34
- :on_auction_no_edits, :suspended, :tradeable]
33
+ attribute :market_status, Symbol, allowed_values: %i[closed edits_only offline on_auction
34
+ on_auction_no_edits suspended tradeable]
35
35
  attribute :net_change, Float
36
36
  attribute :offer, Float
37
37
  attribute :percentage_change, Float
@@ -75,12 +75,12 @@ module IGMarkets
75
75
 
76
76
  # Validates the options passed to {#historical_prices}.
77
77
  def validate_historical_prices_options(options)
78
- resolutions = [:second, :minute, :minute_2, :minute_3, :minute_5, :minute_10, :minute_15, :minute_30, :hour,
79
- :hour_2, :hour_3, :hour_4, :day, :week, :month]
78
+ resolutions = %i[second minute minute_2 minute_3 minute_5 minute_10 minute_15 minute_30 hour
79
+ hour_2 hour_3 hour_4 day week month]
80
80
 
81
81
  raise ArgumentError, 'resolution is invalid' unless resolutions.include? options[:resolution]
82
82
 
83
- return if options.keys == [:resolution, :from, :to] || options.keys == [:resolution, :number]
83
+ return if options.keys == %i[resolution from to] || options.keys == %i[resolution number]
84
84
 
85
85
  raise ArgumentError, 'options must specify either :number or :from and :to'
86
86
  end
@@ -5,7 +5,7 @@ module IGMarkets
5
5
  attribute :delay_time, Float
6
6
  attribute :epic, String, regex: Regex::EPIC
7
7
  attribute :exchange_id
8
- attribute :expiry, String, nil_if: %w(- DFB)
8
+ attribute :expiry, String, nil_if: %w[- DFB]
9
9
  attribute :high, Float
10
10
  attribute :instrument_name
11
11
  attribute :instrument_type, Symbol, allowed_values: Instrument.allowed_values(:type)
@@ -35,11 +35,25 @@ module IGMarkets
35
35
 
36
36
  # Compares this model to another, the attributes and class must match for them to be considered equal.
37
37
  #
38
- # @param [#class, #attributes] other The other model to compare to.
38
+ # @param [Model] other The other model to compare to.
39
39
  #
40
40
  # @return [Boolean]
41
41
  def ==(other)
42
- self.class == other.class && attributes == other.attributes
42
+ self.class == other.class && to_h == other.to_h
43
+ end
44
+
45
+ # Converts this model into a nested hash of attributes. This is simlar to just calling {#attributes}, but in this
46
+ # case any attributes that are instances of {Model} will also be transformed into a hash in the return value.
47
+ #
48
+ # @return [Hash]
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
56
+ end
43
57
  end
44
58
 
45
59
  # Returns a human-readable string containing this model's type and all its current attribute values.
@@ -20,7 +20,7 @@ module IGMarkets
20
20
 
21
21
  def typecaster_boolean(value, _options, name)
22
22
  return value if [nil, true, false].include? value
23
- return value == '1' if %w(0 1).include? value
23
+ return value == '1' if %w[0 1].include? value
24
24
 
25
25
  raise ArgumentError, "#{self}##{name}: invalid boolean value: #{value}"
26
26
  end
@@ -8,7 +8,7 @@ module IGMarkets
8
8
  attribute :currency, String, regex: Regex::CURRENCY
9
9
  attribute :deal_id
10
10
  attribute :deal_reference
11
- attribute :direction, Symbol, allowed_values: [:buy, :sell]
11
+ attribute :direction, Symbol, allowed_values: %i[buy sell]
12
12
  attribute :level, Float
13
13
  attribute :limit_level, Float
14
14
  attribute :limited_risk_premium, LimitedRiskPremium
@@ -134,7 +134,7 @@ module IGMarkets
134
134
  raise ArgumentError, 'set quote_id if and only if order_type is :quote'
135
135
  end
136
136
 
137
- return unless [:limit, :quote].include?(attributes[:order_type]) == attributes[:level].nil?
137
+ return unless %i[limit quote].include?(attributes[:order_type]) == attributes[:level].nil?
138
138
 
139
139
  raise ArgumentError, 'set level if and only if order_type is :limit or :quote'
140
140
  end
@@ -142,17 +142,17 @@ module IGMarkets
142
142
  # Internal model used by {#close}.
143
143
  class PositionCloseAttributes < Model
144
144
  attribute :deal_id
145
- attribute :direction, Symbol, allowed_values: [:buy, :sell]
145
+ attribute :direction, Symbol, allowed_values: %i[buy sell]
146
146
  attribute :level, Float
147
- attribute :order_type, Symbol, allowed_values: [:limit, :market, :quote]
147
+ attribute :order_type, Symbol, allowed_values: %i[limit market quote]
148
148
  attribute :quote_id
149
149
  attribute :size, Float
150
- attribute :time_in_force, Symbol, allowed_values: [:execute_and_eliminate, :fill_or_kill]
150
+ attribute :time_in_force, Symbol, allowed_values: %i[execute_and_eliminate fill_or_kill]
151
151
 
152
152
  # Runs a series of validations on this model's attributes to check whether it is ready to be sent to the IG
153
153
  # Markets API.
154
154
  def validate
155
- [:deal_id, :direction, :order_type, :size, :time_in_force].each do |attribute|
155
+ %i[deal_id direction order_type size time_in_force].each do |attribute|
156
156
  raise ArgumentError, "#{attribute} attribute must be set" if attributes[attribute].nil?
157
157
  end
158
158
 
@@ -5,7 +5,7 @@ module IGMarkets
5
5
  attribute :currency, String, regex: Regex::CURRENCY
6
6
  attribute :deal_id
7
7
  attribute :description
8
- attribute :direction, Symbol, allowed_values: [:buy, :sell]
8
+ attribute :direction, Symbol, allowed_values: %i[buy sell]
9
9
  attribute :epic, String, regex: Regex::EPIC
10
10
  attribute :expiry_time, Time, format: '%FT%T'
11
11
  attribute :instrument_name
@@ -174,7 +174,7 @@ module IGMarkets
174
174
  working_order.currency_code = working_order_update.currency
175
175
  working_order.order_level = working_order_update.level
176
176
 
177
- %i(good_till_date limit_distance order_type stop_distance time_in_force).each do |attribute|
177
+ %i[good_till_date limit_distance order_type stop_distance time_in_force].each do |attribute|
178
178
  working_order.send "#{attribute}=", working_order_update.send(attribute)
179
179
  end
180
180
  end
@@ -24,7 +24,7 @@ module IGMarkets
24
24
  attribute :ofr_high, Float
25
25
  attribute :ofr_low, Float
26
26
  attribute :ofr_open, Float
27
- attribute :scale, Symbol, allowed_values: [:one_second, :one_minute, :five_minutes, :one_hour]
27
+ attribute :scale, Symbol, allowed_values: %i[one_second one_minute five_minutes one_hour]
28
28
  attribute :ttv, Float
29
29
  attribute :utm, Time, format: '%Q'
30
30
  end
@@ -9,8 +9,8 @@ module IGMarkets
9
9
  attribute :high, Float
10
10
  attribute :low, Float
11
11
  attribute :market_delay, Boolean
12
- attribute :market_state, Symbol, allowed_values: [:closed, :offline, :tradeable, :edit, :auction,
13
- :auction_no_edit, :suspended]
12
+ attribute :market_state, Symbol, allowed_values: %i[closed offline tradeable edit auction
13
+ auction_no_edit suspended unavailable]
14
14
  attribute :mid_open, Float
15
15
  attribute :odds, Float
16
16
  attribute :offer, Float
@@ -8,15 +8,15 @@ module IGMarkets
8
8
  attribute :deal_id
9
9
  attribute :deal_id_origin
10
10
  attribute :deal_reference
11
- attribute :deal_status, Symbol, allowed_values: [:accepted, :rejected]
12
- attribute :direction, Symbol, allowed_values: [:buy, :sell]
11
+ attribute :deal_status, Symbol, allowed_values: %i[accepted rejected]
12
+ attribute :direction, Symbol, allowed_values: %i[buy sell]
13
13
  attribute :epic, String, regex: Regex::EPIC
14
- attribute :expiry, Date, nil_if: %w(- DFB), format: ['%d-%b-%y', '%b-%y']
14
+ attribute :expiry, Date, nil_if: %w[- DFB], format: ['%d-%b-%y', '%b-%y']
15
15
  attribute :guaranteed_stop, Boolean
16
16
  attribute :level, Float
17
17
  attribute :limit_level, Float
18
18
  attribute :size, Float
19
- attribute :status, Symbol, allowed_values: [:deleted, :open, :updated]
19
+ attribute :status, Symbol, allowed_values: %i[deleted open updated]
20
20
  attribute :stop_level, Float
21
21
  attribute :timestamp, Time, format: ['%FT%T.%L', '%FT%T']
22
22
  end
@@ -8,19 +8,19 @@ module IGMarkets
8
8
  attribute :currency, String, regex: Regex::CURRENCY
9
9
  attribute :deal_id
10
10
  attribute :deal_reference
11
- attribute :deal_status, Symbol, allowed_values: [:accepted, :rejected]
12
- attribute :direction, Symbol, allowed_values: [:buy, :sell]
11
+ attribute :deal_status, Symbol, allowed_values: %i[accepted rejected]
12
+ attribute :direction, Symbol, allowed_values: %i[buy sell]
13
13
  attribute :epic, String, regex: Regex::EPIC
14
- attribute :expiry, Date, nil_if: %w(- DFB), format: ['%d-%b-%y', '%b-%y']
14
+ attribute :expiry, Date, nil_if: %w[- DFB], format: ['%d-%b-%y', '%b-%y']
15
15
  attribute :good_till_date, Time, format: '%FT%T'
16
16
  attribute :guaranteed_stop, Boolean
17
17
  attribute :level, Float
18
18
  attribute :limit_distance, Integer
19
- attribute :order_type, Symbol, allowed_values: [:limit, :stop]
19
+ attribute :order_type, Symbol, allowed_values: %i[limit stop]
20
20
  attribute :size, Float
21
- attribute :status, Symbol, allowed_values: [:deleted, :open, :updated]
21
+ attribute :status, Symbol, allowed_values: %i[deleted open updated]
22
22
  attribute :stop_distance, Integer
23
- attribute :time_in_force, Symbol, allowed_values: [:good_till_cancelled, :good_till_date]
23
+ attribute :time_in_force, Symbol, allowed_values: %i[good_till_cancelled good_till_date]
24
24
  attribute :timestamp, Time, format: ['%FT%T.%L', '%FT%T']
25
25
  end
26
26
  end
@@ -3,17 +3,17 @@ module IGMarkets
3
3
  # {DealingPlatform::AccountMethods#transactions}.
4
4
  class Transaction < Model
5
5
  attribute :cash_transaction, Boolean
6
- attribute :close_level, String, nil_if: %w(- 0)
6
+ attribute :close_level, String, nil_if: %w[- 0]
7
7
  attribute :currency
8
8
  attribute :date_utc, Time, format: '%FT%T'
9
9
  attribute :instrument_name
10
10
  attribute :open_date_utc, Time, format: '%FT%T'
11
- attribute :open_level, String, nil_if: %w(- 0)
12
- attribute :period, Time, nil_if: %w(- DFB), format: ['%FT%T', '%d-%b-%y', '%b-%y']
11
+ attribute :open_level, String, nil_if: %w[- 0]
12
+ attribute :period, Time, nil_if: %w[- DFB], format: ['%FT%T', '%d-%b-%y', '%b-%y']
13
13
  attribute :profit_and_loss
14
14
  attribute :reference
15
15
  attribute :size, String, nil_if: '-'
16
- attribute :transaction_type, Symbol, allowed_values: [:chart, :deal, :depo, :dividend, :exchange, :trade, :with]
16
+ attribute :transaction_type, Symbol, allowed_values: %i[chart deal depo dividend exchange trade with]
17
17
 
18
18
  deprecated_attribute :date
19
19
 
@@ -23,7 +23,7 @@ module IGMarkets
23
23
  #
24
24
  # @return [Boolean]
25
25
  def interest?
26
- [:depo, :with].include?(transaction_type) && !(instrument_name.downcase =~ /(^|[^a-z])interest([^a-z]|$)/).nil?
26
+ %i[depo with].include?(transaction_type) && !(instrument_name.downcase =~ /(^|[^a-z])interest([^a-z]|$)/).nil?
27
27
  end
28
28
 
29
29
  # Returns this transaction's {#profit_and_loss} as a `Float`, denominated in this transaction's {#currency}.
@@ -1,4 +1,4 @@
1
1
  module IGMarkets
2
2
  # The version of this gem.
3
- VERSION = '0.31'.freeze
3
+ VERSION = '0.32'.freeze
4
4
  end
@@ -5,7 +5,7 @@ module IGMarkets
5
5
  attribute :created_date_utc, Time, format: '%FT%T'
6
6
  attribute :currency_code, String, regex: Regex::CURRENCY
7
7
  attribute :deal_id
8
- attribute :direction, Symbol, allowed_values: [:buy, :sell]
8
+ attribute :direction, Symbol, allowed_values: %i[buy sell]
9
9
  attribute :dma, Boolean
10
10
  attribute :epic, String, regex: Regex::EPIC
11
11
  attribute :good_till_date, Time, format: '%Y/%m/%d %R'
@@ -14,9 +14,9 @@ module IGMarkets
14
14
  attribute :limited_risk_premium, LimitedRiskPremium
15
15
  attribute :order_level, Float
16
16
  attribute :order_size, Float
17
- attribute :order_type, Symbol, allowed_values: [:limit, :stop]
17
+ attribute :order_type, Symbol, allowed_values: %i[limit stop]
18
18
  attribute :stop_distance, Integer
19
- attribute :time_in_force, Symbol, allowed_values: [:good_till_cancelled, :good_till_date]
19
+ attribute :time_in_force, Symbol, allowed_values: %i[good_till_cancelled good_till_date]
20
20
 
21
21
  attribute :market, MarketOverview
22
22
 
@@ -70,8 +70,8 @@ module IGMarkets
70
70
  attribute :limit_level, Float
71
71
  attribute :stop_distance, Integer
72
72
  attribute :stop_level, Float
73
- attribute :time_in_force, Symbol, allowed_values: [:good_till_cancelled, :good_till_date]
74
- attribute :type, Symbol, allowed_values: [:limit, :stop]
73
+ attribute :time_in_force, Symbol, allowed_values: %i[good_till_cancelled good_till_date]
74
+ attribute :type, Symbol, allowed_values: %i[limit stop]
75
75
 
76
76
  def initialize(existing_attributes, new_attributes)
77
77
  existing_attributes.delete :limit_distance if new_attributes.key? :limit_level
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.31'
4
+ version: '0.32'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Viney
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-26 00:00:00.000000000 Z
11
+ date: 2017-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -66,20 +66,6 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.10.4
69
- - !ruby/object:Gem::Dependency
70
- name: rainbow
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: 2.1.0
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: 2.1.0
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: terminal-table
85
71
  requirement: !ruby/object:Gem::Requirement
@@ -198,14 +184,14 @@ dependencies:
198
184
  requirements:
199
185
  - - "~>"
200
186
  - !ruby/object:Gem::Version
201
- version: '0.47'
187
+ version: '0.48'
202
188
  type: :development
203
189
  prerelease: false
204
190
  version_requirements: !ruby/object:Gem::Requirement
205
191
  requirements:
206
192
  - - "~>"
207
193
  - !ruby/object:Gem::Version
208
- version: '0.47'
194
+ version: '0.48'
209
195
  - !ruby/object:Gem::Dependency
210
196
  name: rubocop-rspec
211
197
  requirement: !ruby/object:Gem::Requirement
@@ -361,7 +347,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
361
347
  version: '0'
362
348
  requirements: []
363
349
  rubyforge_project:
364
- rubygems_version: 2.5.2
350
+ rubygems_version: 2.6.11
365
351
  signing_key:
366
352
  specification_version: 4
367
353
  summary: Library and command-line client for accessing the IG Markets dealing platform.