ig_markets 0.5 → 0.6

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 +18 -8
  3. data/README.md +40 -10
  4. data/lib/ig_markets.rb +3 -1
  5. data/lib/ig_markets/cli/commands/activities_command.rb +9 -7
  6. data/lib/ig_markets/cli/commands/orders_command.rb +8 -11
  7. data/lib/ig_markets/cli/commands/positions_command.rb +9 -7
  8. data/lib/ig_markets/cli/commands/prices_command.rb +66 -0
  9. data/lib/ig_markets/cli/commands/search_command.rb +19 -2
  10. data/lib/ig_markets/cli/commands/sprints_command.rb +2 -2
  11. data/lib/ig_markets/cli/config_file.rb +1 -1
  12. data/lib/ig_markets/cli/main.rb +25 -16
  13. data/lib/ig_markets/cli/tables/accounts_table.rb +10 -0
  14. data/lib/ig_markets/cli/tables/historical_price_result_snapshots_table.rb +25 -0
  15. data/lib/ig_markets/cli/tables/table.rb +2 -2
  16. data/lib/ig_markets/client_sentiment.rb +3 -1
  17. data/lib/ig_markets/dealing_platform.rb +49 -14
  18. data/lib/ig_markets/dealing_platform/account_methods.rb +13 -5
  19. data/lib/ig_markets/dealing_platform/client_sentiment_methods.rb +2 -4
  20. data/lib/ig_markets/dealing_platform/market_methods.rb +14 -6
  21. data/lib/ig_markets/dealing_platform/position_methods.rb +7 -7
  22. data/lib/ig_markets/dealing_platform/sprint_market_position_methods.rb +16 -2
  23. data/lib/ig_markets/dealing_platform/watchlist_methods.rb +4 -2
  24. data/lib/ig_markets/dealing_platform/working_order_methods.rb +2 -4
  25. data/lib/ig_markets/format.rb +10 -0
  26. data/lib/ig_markets/historical_price_result.rb +1 -1
  27. data/lib/ig_markets/instrument.rb +10 -10
  28. data/lib/ig_markets/market.rb +3 -3
  29. data/lib/ig_markets/model.rb +17 -25
  30. data/lib/ig_markets/model/typecasters.rb +20 -13
  31. data/lib/ig_markets/payload_formatter.rb +1 -1
  32. data/lib/ig_markets/position.rb +1 -1
  33. data/lib/ig_markets/session.rb +8 -8
  34. data/lib/ig_markets/sprint_market_position.rb +2 -2
  35. data/lib/ig_markets/transaction.rb +1 -1
  36. data/lib/ig_markets/version.rb +1 -1
  37. data/lib/ig_markets/watchlist.rb +6 -4
  38. data/lib/ig_markets/working_order.rb +2 -2
  39. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ef481344a1515b0031301c4e70e17ce843f7f111
4
- data.tar.gz: f2282b07a67e0dfba0fa8e7a8936d630777663e0
3
+ metadata.gz: 589e81bb5e11e735c8dacf82cac67d784d5d705f
4
+ data.tar.gz: 2a84abcae5a0844574fdbc25cbeff2fd831624e3
5
5
  SHA512:
6
- metadata.gz: d3816a297817a2d1da84402f1a20689e2b2f271ae7bc1c76a623f19b45320674f7ca94ec39b703bbb3553f2eb364b6d08f10f3cdc1db0c615b4887859253dc28
7
- data.tar.gz: 27b911f529724f105c3d443b41fc878f78c45815f6b9b1ce94569a6e88c17d85de48e34ed087e38307f638c05af61d90c9101b50a2db9056eb76d9c939ed2aaa
6
+ metadata.gz: f2706333bf110e2b169df6769d602bda5dae0d7e14cb98b92bb73785d81f169b35286855b72367f7182b5d41994514053768d95e1991028ee39c4a7733b3f4fb
7
+ data.tar.gz: d7c015c2573702b1ac5c1be4ec83f9c5d7e4212ded0be95d80fbe15f6542d580fed02e7fa1e5cfa5fb921227e4cd6ab74b3aaa47da6a3a093776f1949b8f0d6e
data/CHANGELOG.md CHANGED
@@ -1,12 +1,22 @@
1
1
  # IG Markets Changelog
2
2
 
3
- ### 0.6 - Unreleased
3
+ ### 0.6 April 27, 2016
4
4
 
5
- -
5
+ - Added `ig_markets prices` command to print historical market prices
6
+ - Added `IGMarkets::DealingPlatform#account_time_zone` to handle the `Time` attributes that come back from the IG
7
+ Markets API not in UTC and without a specified time zone
8
+ - Added `--account-time-zone` option to the command-line client, defaults to UTC
9
+ - Times reported by the command-line client are now in the local time zone instead of UTC
10
+ - Added `--type` option to `ig_markets search` to only show instruments of specific type(s)
11
+ - Use a default currency of `USD` for `ig_markets orders create` and `ig_markets positions create`
12
+ - Improved command-line client help output for several commands
13
+ - Added `IGMarkets::DealingPlatform::SprintMarketPositionMethods#[]`
14
+ - Fixed `IGMarkets::DealingPlatform::PositionMethods#[]` raising on an unknown deal ID
15
+ - Fixed `IGMarkets::Market#prices_in_date_range`
6
16
 
7
- ### 0.5 - April 23, 2016
17
+ ### 0.5 April 23, 2016
8
18
 
9
- - Ouptut from the command-line client is now formatted using ASCII tables and contains a lot more detail
19
+ - Output from the command-line client is now formatted using ASCII tables and contains a lot more detail
10
20
  - Added `--aggregate` option to `ig_markets positions list` to aggregate together positions with the same EPIC
11
21
  - Added `--instrument` option to `ig_markets transactions` to filter by instrument name
12
22
  - Added `--no-interest` option to `ig_markets transactions` to exclude interest transactions
@@ -18,7 +28,7 @@
18
28
  - Added `IGMarkets::Position#close_level`
19
29
  - Removed `IGMarkets::Position#formatted_size` and `IGMarkets::Transaction#formatted_transaction_type`
20
30
 
21
- ### 0.4 - April 18, 2016
31
+ ### 0.4 April 18, 2016
22
32
 
23
33
  - Added `create`, `update` and `delete` subcommands to `ig_markets orders`
24
34
  - Added `create`, `update` and `close` subcommands to `ig_markets positions`
@@ -34,11 +44,11 @@
34
44
  - Fixed errors working with a working order's `#good_till_date` attribute
35
45
  - Automatically reauthenticate if the client security token has expired
36
46
 
37
- ### 0.3 - April 14, 2016
47
+ ### 0.3 April 14, 2016
38
48
 
39
49
  - Added `--version` and `-v` options to the command-line client
40
50
 
41
- ### 0.2 - April 14, 2016
51
+ ### 0.2 April 14, 2016
42
52
 
43
53
  - Added `ig_markets` command-line client
44
54
  - `IGMarkets::Model` now has separate `Date` and `Time` attribute types, and a new `:time_zone` option is used for
@@ -50,6 +60,6 @@
50
60
  - Added `#expired?` and `#seconds_till_expiry` to `IGMarkets::SprintMarketPosition`
51
61
  - Fixed `IGMarkets::RequestFailedError#message`
52
62
 
53
- ### 0.1 - April 8, 2016
63
+ ### 0.1 April 8, 2016
54
64
 
55
65
  - Initial release
data/README.md CHANGED
@@ -41,7 +41,7 @@ $ gem install ig_markets
41
41
  The general form for invoking the command-line client is:
42
42
 
43
43
  ```
44
- $ ig_markets COMMAND [SUBCOMMAND] --username=USERNAME --password=PASSWORD --api-key=API-KEY [--demo] [...]
44
+ $ ig_markets COMMAND [SUBCOMMAND] --username USERNAME --password PASSWORD --api-key API-KEY [--demo] [...]
45
45
  ```
46
46
 
47
47
  #### Config File
@@ -53,9 +53,9 @@ details with every invocation.
53
53
  To do this create a config file at `"./.ig_markets"` or `"~/.ig_markets"` with the following contents:
54
54
 
55
55
  ```shell
56
- --username=USERNAME
57
- --password=PASSWORD
58
- --api-key=API-KEY
56
+ --username USERNAME
57
+ --password PASSWORD
58
+ --api-key API-KEY
59
59
  --demo # Include only if this is a demo account
60
60
  ```
61
61
 
@@ -67,7 +67,7 @@ Use `ig_markets help` to get details on the options accepted by the commands and
67
67
  commands and their subcommands is:
68
68
 
69
69
  - `ig_markets account`
70
- - `ig_markets activities --days=N [--start-date=YYYY-MM-DD]`
70
+ - `ig_markets activities --days N [--start-date YYYY-MM-DD]`
71
71
  - `ig_markets confirmation DEAL-REFERENCE`
72
72
  - `ig_markets help [COMMAND]`
73
73
  - `ig_markets orders [list]`
@@ -78,11 +78,12 @@ commands and their subcommands is:
78
78
  - `ig_markets positions create ...`
79
79
  - `ig_markets positions update DEAL-ID ...`
80
80
  - `ig_markets positions close DEAL-ID [...]`
81
- - `ig_markets search QUERY`
81
+ - `ig_markets prices --epic EPIC --resolution RESOLUTION [...]`
82
+ - `ig_markets search QUERY [--type TYPE]`
82
83
  - `ig_markets sentiment MARKET`
83
84
  - `ig_markets sprints [list]`
84
85
  - `ig_markets sprints create ...`
85
- - `ig_markets transactions --days=N [--start-date=YYYY-MM-DD] [--instrument=INSTRUMENT] [--no-interest]`
86
+ - `ig_markets transactions --days N [--start-date YYYY-MM-DD] [--instrument INSTRUMENT] [--no-interest]`
86
87
  - `ig_markets watchlists [list]`
87
88
  - `ig_markets watchlists create NAME [EPIC EPIC ...]`
88
89
  - `ig_markets watchlists add-markets WATCHLIST-ID [EPIC EPIC ...]`
@@ -96,13 +97,16 @@ commands and their subcommands is:
96
97
  ig_markets account
97
98
 
98
99
  # Print EUR/USD transactions from the last week, excluding interest transactions
99
- ig_markets transactions --days=7 --instrument EUR/USD --no-interest
100
+ ig_markets transactions --days 7 --instrument EUR/USD --no-interest
101
+
102
+ # Search for EURUSD currency markets
103
+ ig_markets search EURUSD --type currencies
100
104
 
101
105
  # Print current positions in aggregate
102
106
  ig_markets positions --aggregate
103
107
 
104
108
  # Create a EURUSD long position of size 2
105
- ig_markets positions create --currency-code USD --direction buy --epic CS.D.EURUSD.CFD.IP --size 2
109
+ ig_markets positions create --direction buy --epic CS.D.EURUSD.CFD.IP --size 2
106
110
 
107
111
  # Change the limit and stop levels for an existing position
108
112
  ig_markets positions update DEAL-ID --limit-level 1.15 --stop-level 1.10
@@ -117,7 +121,28 @@ ig_markets positions close DEAL-ID --size 1
117
121
  ig_markets sprints create --direction sell --epic FM.D.EURUSD24.EURUSD24.IP --expiry-period 20 --size 100
118
122
 
119
123
  # Create a working order to buy 1 unit of EURUSD at the level 1.1
120
- ig_markets orders create --currency-code USD --direction buy --epic CS.D.EURUSD.CFD.IP --level 1.1 --size 1 --type limit
124
+ ig_markets orders create --direction buy --epic CS.D.EURUSD.CFD.IP --level 1.1 --size 1 --type limit
125
+
126
+ # Print daily prices for EURUSD from the last two weeks
127
+ ig_markets prices --epic CS.D.EURUSD.CFD.IP --resolution day --number 14
128
+ ```
129
+
130
+ #### Account Time Zone
131
+
132
+ Some timestamps returned by the IG Markets API are in an unspecified time zone, which can result in some times
133
+ displayed by the command-line client being incorrect. By default the unknown time zone is assumed to be UTC, but if this
134
+ is incorrect then use the `--account-time-zone` argument to specify the actual time zone these times are in.
135
+
136
+ For example, an IG Markets Australia account requires `--account-time-zone +1000`.
137
+
138
+ The `--account-time-zone` argument should be put into an `.ig_markets` config file to avoid specifying it on every
139
+ invocation.
140
+
141
+ To check that the account time zone is correct run the following command and verify that the date and time reported for
142
+ the price is the current date/time in your local time zone.
143
+
144
+ ```
145
+ ig_markets prices --epic CS.D.EURUSD.CFD.IP --resolution minute --number 1
121
146
  ```
122
147
 
123
148
  ## Usage — Library
@@ -137,6 +162,10 @@ ig = IGMarkets::DealingPlatform.new
137
162
  ig.sign_in 'username', 'password', 'api_key', :demo
138
163
  ig.sign_out
139
164
 
165
+ # Set the time zone for the account, this is applied to time attributes returned from the IG Markets API that are not
166
+ # in a known time zone such as UTC
167
+ ig.account_time_zone = '+0000'
168
+
140
169
  # Account
141
170
  ig.account.all
142
171
  ig.account.recent_activities 365
@@ -157,6 +186,7 @@ ig.positions['deal_id'].close
157
186
 
158
187
  # Sprint market positions
159
188
  ig.sprint_market_positions.all
189
+ ig.sprint_market_positions['deal_id']
160
190
  ig.sprint_market_positions.create direction: :buy, epic: 'FM.D.EURUSD24.EURUSD24.IP',
161
191
  expiry_period: :twenty_minutes, size: 100
162
192
 
data/lib/ig_markets.rb CHANGED
@@ -52,6 +52,7 @@ require 'ig_markets/cli/config_file'
52
52
  require 'ig_markets/cli/commands/account_command'
53
53
  require 'ig_markets/cli/commands/activities_command'
54
54
  require 'ig_markets/cli/commands/confirmation_command'
55
+ require 'ig_markets/cli/commands/prices_command'
55
56
  require 'ig_markets/cli/commands/search_command'
56
57
  require 'ig_markets/cli/commands/sentiment_command'
57
58
  require 'ig_markets/cli/commands/transactions_command'
@@ -59,11 +60,12 @@ require 'ig_markets/cli/tables/table'
59
60
  require 'ig_markets/cli/tables/accounts_table'
60
61
  require 'ig_markets/cli/tables/activities_table'
61
62
  require 'ig_markets/cli/tables/client_sentiments_table'
63
+ require 'ig_markets/cli/tables/historical_price_result_snapshots_table'
62
64
  require 'ig_markets/cli/tables/market_overviews_table'
63
- require 'ig_markets/cli/tables/working_orders_table'
64
65
  require 'ig_markets/cli/tables/positions_table'
65
66
  require 'ig_markets/cli/tables/sprint_market_positions_table'
66
67
  require 'ig_markets/cli/tables/transactions_table'
68
+ require 'ig_markets/cli/tables/working_orders_table'
67
69
 
68
70
  # This module contains all the code for the IG Markets gem. See `README.md` and the {DealingPlatform} class to get
69
71
  # started with using this gem.
@@ -23,14 +23,16 @@ module IGMarkets
23
23
  days = options[:days]
24
24
  start_date = options[:start_date]
25
25
 
26
- if start_date
27
- start_date = Date.strptime start_date, '%F'
28
- end_date = start_date + days.to_i
26
+ send_args = if start_date
27
+ start_date = Date.strptime start_date, '%F'
28
+ end_date = start_date + days.to_i
29
29
 
30
- Main.dealing_platform.account.send "#{type}_in_date_range", start_date, end_date
31
- else
32
- Main.dealing_platform.account.send "recent_#{type}", days
33
- end
30
+ ["#{type}_in_date_range", start_date, end_date]
31
+ else
32
+ ["recent_#{type}", days]
33
+ end
34
+
35
+ Main.dealing_platform.account.send(*send_args)
34
36
  end
35
37
  end
36
38
  end
@@ -18,21 +18,19 @@ module IGMarkets
18
18
 
19
19
  desc 'create', 'Creates a new working order'
20
20
 
21
- option :currency_code, required: true, desc: 'The 3 character currency code, must be one of the instrument\'s ' \
21
+ option :currency_code, default: 'USD', desc: 'The 3 character currency code, must be one of the instrument\'s ' \
22
22
  'currencies'
23
- option :direction, required: true, desc: 'The trade direction, must be \'buy\' or \'sell\''
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, default: false'
27
- option :good_till_date, desc: 'The date that the order will live till, if not specified then the order will ' \
28
- 'remain until it is deleted, format: yyyy-mm-ddThh:mm(+|-)zz:zz'
29
- option :guaranteed_stop, type: :boolean, default: false, desc: 'Whether a guaranteed stop is required, ' \
30
- 'default: false'
26
+ option :force_open, type: :boolean, default: false, desc: 'Whether a force open is required'
27
+ option :good_till_date, desc: 'The date that the order will live till, format: yyyy-mm-ddThh:mm(+|-)zz:zz'
28
+ option :guaranteed_stop, type: :boolean, default: false, desc: 'Whether a guaranteed stop is required'
31
29
  option :level, type: :numeric, required: true, desc: 'The level at which the order will be triggered'
32
30
  option :limit_distance, type: :numeric, desc: 'The distance away in pips to place the limit'
33
31
  option :size, type: :numeric, required: true, desc: 'The size of the order'
34
32
  option :stop_distance, type: :numeric, desc: 'The distance away in pips to place the stop'
35
- option :type, required: true, desc: 'The order type, either \'limit\' or \'stop\''
33
+ option :type, enum: %w(limit stop), required: true, desc: 'The order type'
36
34
 
37
35
  def create
38
36
  Main.begin_session(options) do |dealing_platform|
@@ -44,12 +42,11 @@ module IGMarkets
44
42
 
45
43
  desc 'update DEAL-ID', 'Updates an existing working order'
46
44
 
47
- option :good_till_date, desc: 'The date that the order will live till, if not specified then the order will ' \
48
- 'remain until it is deleted, format: yyyy-mm-ddThh:mm(+|-)zz:zz'
45
+ option :good_till_date, desc: 'The date that the order will live till, format: yyyy-mm-ddThh:mm(+|-)zz:zz'
49
46
  option :level, type: :numeric, desc: 'The level at which the order will be triggered'
50
47
  option :limit_distance, desc: 'The distance away in pips to place the limit'
51
48
  option :stop_distance, desc: 'The distance away in pips to place the stop'
52
- option :type, desc: 'The order type, either \'limit\' or \'stop\''
49
+ option :type, enum: %w(limit stop), desc: 'The order type'
53
50
 
54
51
  def update(deal_id)
55
52
  Main.begin_session(options) do |dealing_platform|
@@ -24,9 +24,9 @@ module IGMarkets
24
24
 
25
25
  desc 'create', 'Creates a new position'
26
26
 
27
- option :currency_code, required: true, desc: 'The 3 character currency code, must be one of the instrument\'s ' \
27
+ option :currency_code, default: 'USD', desc: 'The 3 character currency code, must be one of the instrument\'s ' \
28
28
  'currencies'
29
- option :direction, required: true, desc: 'The trade direction, must be \'buy\' or \'sell\''
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
32
  option :force_open, type: :boolean, default: false, desc: 'Whether a force open is required'
@@ -35,13 +35,13 @@ module IGMarkets
35
35
  option :limit_distance, type: :numeric, desc: 'The distance away in pips to place the limit, if set then ' \
36
36
  '--limit-level must not be used'
37
37
  option :limit_level, type: :numeric, desc: 'The limit level, if set then --limit-distance must not be used'
38
- option :order_type, default: 'market', desc: 'The order type, must be \'limit\', \'market\' or \'quote\''
38
+ option :order_type, enum: %w(limit market quote), default: 'market', desc: 'The order type'
39
39
  option :quote_id, desc: 'The Lightstreamer quote ID, required when using --order-type=quote'
40
40
  option :size, type: :numeric, required: true, desc: 'The size of the position'
41
41
  option :stop_distance, type: :numeric, desc: 'The distance away in pips to place the stop, if set then ' \
42
42
  '--stop-level must not be used'
43
43
  option :stop_level, type: :numeric, desc: 'The stop level, if set then --stop-distance must not be used'
44
- option :time_in_force, desc: 'The order fill strategy, either \'execute_and_eliminate\' or \'fill_or_kill\''
44
+ option :time_in_force, enum: %w(execute-and-eliminate fill-or-kill), desc: 'The order fill strategy'
45
45
  option :trailing_stop, type: :boolean, desc: 'Whether to use a trailing stop, defaults to false'
46
46
  option :trailing_stop_increment, type: :numeric, desc: 'The increment step in pips for the trailing stop, ' \
47
47
  'required when --trailing-stop is specified'
@@ -71,11 +71,11 @@ module IGMarkets
71
71
  desc 'close DEAL-ID', 'Closes or partially closes a position'
72
72
 
73
73
  option :level, type: :numeric, desc: 'Required if and only if --order-type is \'limit\' or \'quote\''
74
- option :order_type, default: 'market', desc: 'The order type, must be \'limit\', \'market\' or \'quote\''
74
+ option :order_type, enum: %w(limit market quote), default: 'market', desc: 'The order type'
75
75
  option :quote_id, desc: 'The Lightstreamer quote ID, required when using --order-type=quote'
76
76
  option :size, type: :numeric, desc: 'The size of the position to close, if not specified then the entire ' \
77
77
  'position will be closed'
78
- option :time_in_force, desc: 'The order fill strategy, either \'execute_and_eliminate\' or \'fill_or_kill\''
78
+ option :time_in_force, enum: %w(execute-and-eliminate fill-or-kill), desc: 'The order fill strategy'
79
79
 
80
80
  def close(deal_id)
81
81
  with_position(deal_id) do |position|
@@ -92,6 +92,8 @@ module IGMarkets
92
92
  def position_attributes
93
93
  attributes = Main.filter_options options, ATTRIBUTES
94
94
 
95
+ attributes[:time_in_force] = attributes[:time_in_force].tr('-', '_').to_sym if attributes.key? :time_in_force
96
+
95
97
  Main.parse_date_time attributes, :expiry, Date, '%F', 'yyyy-mm-dd'
96
98
 
97
99
  attributes
@@ -111,7 +113,7 @@ module IGMarkets
111
113
 
112
114
  def print_position_totals(positions)
113
115
  currency_totals = positions.group_by(&:currency).map do |currency, subset|
114
- total = subset.map(&:profit_loss).reduce(:+)
116
+ total = subset.map(&:profit_loss).reduce :+
115
117
 
116
118
  Format.currency(total, currency).colorize(total < 0 ? :red : :green)
117
119
  end
@@ -0,0 +1,66 @@
1
+ module IGMarkets
2
+ module CLI
3
+ # Implements the `ig_markets prices` command.
4
+ class Main
5
+ desc 'prices', 'Prints historical prices for a market'
6
+
7
+ option :epic, required: true, desc: 'The EPIC of the market to print historical prices for'
8
+ option :resolution, enum: %w(minute minute-2 minute-3 minute-5 minute-10 minute-15 minute-30 hour hour-2 hour-3
9
+ hour-4 day week month), required: true, desc: 'The price resolution'
10
+ option :number, type: :numeric, desc: 'The number of historical prices to return, if this is specified then ' \
11
+ '--start-date and --end-date are ignored, otherwise they are required'
12
+ option :start_date, desc: 'The start of the period to return prices for, required unless --number is specified' \
13
+ ', format: yyyy-mm-ddThh:mm(+|-)zz:zz'
14
+ option :end_date, desc: 'The end of the period to return prices for, required unless --number is specified' \
15
+ ', format: yyyy-mm-ddThh:mm(+|-)zz:zz'
16
+
17
+ def prices
18
+ self.class.begin_session(options) do |dealing_platform|
19
+ result = historical_price_result dealing_platform
20
+
21
+ table = HistoricalPriceResultSnapshotsTable.new result.prices, title: "Prices for #{options[:epic]}"
22
+
23
+ puts <<-END
24
+ #{table}
25
+
26
+ Allowance: #{result.allowance.total_allowance}
27
+ Remaining: #{result.allowance.remaining_allowance}
28
+ END
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def resolution
35
+ options[:resolution].to_s.tr('-', '_').to_sym
36
+ end
37
+
38
+ def historical_price_result(dealing_platform)
39
+ market = dealing_platform.markets[options[:epic]]
40
+
41
+ raise ArgumentError, 'invalid epic' unless market
42
+
43
+ if options[:number]
44
+ historical_price_result_from_number market
45
+ elsif options[:start_date] && options[:end_date]
46
+ historical_price_result_from_date_range market
47
+ else
48
+ raise ArgumentError, 'specify --number or both --start-date and --end-date'
49
+ end
50
+ end
51
+
52
+ def historical_price_result_from_number(market)
53
+ market.recent_prices resolution, options[:number]
54
+ end
55
+
56
+ def historical_price_result_from_date_range(market)
57
+ filtered = self.class.filter_options options, [:start_date, :end_date]
58
+
59
+ self.class.parse_date_time filtered, :start_date, Time, '%FT%R%z', 'yyyy-mm-ddThh:mm(+|-)zz:zz'
60
+ self.class.parse_date_time filtered, :end_date, Time, '%FT%R%z', 'yyyy-mm-ddThh:mm(+|-)zz:zz'
61
+
62
+ market.prices_in_date_range resolution, filtered[:start_date], filtered[:end_date]
63
+ end
64
+ end
65
+ end
66
+ end
@@ -2,17 +2,34 @@ module IGMarkets
2
2
  module CLI
3
3
  # Implements the `ig_markets search` command.
4
4
  class Main < Thor
5
- desc 'search QUERY', 'Searches markets based on the specified query string'
5
+ desc 'search QUERY', 'Searches for markets using the specified query'
6
+
7
+ option :type, type: :array, enum: Instrument.allowed_values(:type).map(&:to_s),
8
+ desc: 'Only match markets of the specified types'
6
9
 
7
10
  def search(query)
8
11
  self.class.begin_session(options) do |dealing_platform|
9
- market_overviews = dealing_platform.markets.search query
12
+ market_overviews = gather_market_overviews dealing_platform, query
10
13
 
11
14
  table = MarketOverviewsTable.new market_overviews
12
15
 
13
16
  puts table
14
17
  end
15
18
  end
19
+
20
+ private
21
+
22
+ def gather_market_overviews(dealing_platform, query)
23
+ market_overviews = dealing_platform.markets.search(query)
24
+
25
+ if options[:type]
26
+ market_overviews = market_overviews.select do |market_overview|
27
+ options[:type].include? market_overview.instrument_type.to_s
28
+ end
29
+ end
30
+
31
+ market_overviews
32
+ end
16
33
  end
17
34
  end
18
35
  end
@@ -20,9 +20,9 @@ module IGMarkets
20
20
 
21
21
  desc 'create', 'Creates a new sprint market position'
22
22
 
23
- option :direction, required: true, desc: 'The trade direction, must be \'buy\' or \'sell\')'
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, required: true, desc: 'The expiry period in seconds, must be 1, 2, 5, 20 or 60'
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