ig_markets 0.10 → 0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 443589ca4b1af7f2e0de04ba1ca8be7f9b1450ec
4
- data.tar.gz: 875b689e9ed88ec0b594b4dac26b43ff669366b4
3
+ metadata.gz: 3ffcc67e15b995a577e2a546e9c3167194422eeb
4
+ data.tar.gz: 6f2bbe2ba36c50719b1cb17de93a5bd3f3dfe037
5
5
  SHA512:
6
- metadata.gz: 0402b33e23f7fd885d74382b50057242e9cd17fe53322e065180e09784f5a530a046a29bdecb88376e1ef7022eb9e21c26eac2db23752676795ba0783a6d29d4
7
- data.tar.gz: f26909d155efbb51262d8fddabc0f6c1a72a2de743da7f6aa6ce09518e8c8834e500f087d285e8357980ab72a7319b69c38fd10609226aa9688eacffb05c0b65
6
+ metadata.gz: a11539879eeb53bb9027be01f626e276ceb522cbbaf51f45686155070612914ab218f8adb5d395087095c77af61fcb0e43916252562bda8c0803d2330072732d
7
+ data.tar.gz: ff1647ed07d0c563fae8956ec4b8a4c0591e7ecc3f45817ca732bb38cf58ca4c3d3df31e36908c14cfaa11ff33a9c8a77907be438d7afd1b575cdf3645870864
data/CHANGELOG.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # IG Markets Changelog
2
2
 
3
- ### 0.10 — May 9, 2016
3
+ ### 0.11 — May 23, 2016
4
+
5
+ - `IGMarkets::DealingPlatform::AccountMethods#activities` and `IGMarkets::DealingPlatform::AccountMethods#transactions`
6
+ now send as many requests as necessary in order to get around the fact that the IG Markets API caps the maximum number
7
+ of results returned by a single request at 500
8
+ - `IGMarkets::DealingPlatform::AccountMethods#activities` and `IGMarkets::DealingPlatform::AccountMethods#transactions`
9
+ no longer take a `:days` option, and their `:to` option defaults to today's date if it is omitted
10
+ - Accept "`DFB`" (Daily Funded Bet) on instrument expiries, it is silently converted to `nil`
11
+ - Instrument high and low is now shown in the `ig_markets positions list` command
12
+
13
+ ### 0.10 — May 10, 2016
4
14
 
5
15
  - Added `--epic` option to the `ig_markets activities` command
6
16
  - Added `--sort-by` option to the `ig_markets activities` and `ig_markets transactions` commands
@@ -94,7 +104,7 @@
94
104
  `Time` attributes that have a known time zone. Previous uses of `DateTime` should be replaced with either `Date` or
95
105
  `Time`.
96
106
  - Changed `size` attribute to always be of type `Float` on all models.
97
- - Changed `limit_distance` and `stop_distance` attributes to always be of type `Fixnum` on all models.
107
+ - Changed `limit_distance` and `stop_distance` attributes to always be of type `Fixnum` on all models
98
108
  - Added `IGMarkets::Format` module
99
109
  - Added `#expired?` and `#seconds_till_expiry` to `IGMarkets::SprintMarketPosition`
100
110
  - Fixed `IGMarkets::RequestFailedError#message`
data/README.md CHANGED
@@ -151,10 +151,11 @@ ig.sign_out
151
151
 
152
152
  # Account
153
153
  ig.account.all
154
- ig.account.activities days: 30
154
+ ig.account.activities from: Date.today - 7
155
155
  ig.account.activities from: Date.today - 14, to: Date.today - 7
156
- ig.account.transactions days: 30
156
+ ig.account.transactions from: Date.today - 7
157
157
  ig.account.transactions from: Date.today - 14, to: Date.today - 7
158
+ ig.account.transactions from: Date.today - 14, to: Date.today - 7, type: :deal
158
159
 
159
160
  # Dealing
160
161
  ig.deal_confirmation 'deal_reference'
@@ -11,6 +11,8 @@ module IGMarkets
11
11
 
12
12
  def activities
13
13
  self.class.begin_session(options) do |dealing_platform|
14
+ @epic_regex = Regexp.new options.fetch('epic', ''), Regexp::IGNORECASE
15
+
14
16
  activities = gather_activities dealing_platform
15
17
 
16
18
  table = ActivitiesTable.new activities
@@ -22,8 +24,6 @@ module IGMarkets
22
24
  private
23
25
 
24
26
  def gather_activities(dealing_platform)
25
- @epic_regex = Regexp.new options.fetch('epic', ''), Regexp::IGNORECASE
26
-
27
27
  result = gather_account_history(:activities, dealing_platform).select do |activity|
28
28
  activity_filter activity
29
29
  end
@@ -53,7 +53,7 @@ module IGMarkets
53
53
 
54
54
  { from: from, to: to }
55
55
  else
56
- { days: options[:days] }
56
+ { from: Date.today - options[:days] }
57
57
  end
58
58
 
59
59
  dealing_platform.account.send method_name, history_options
@@ -13,6 +13,8 @@ module IGMarkets
13
13
 
14
14
  def transactions
15
15
  self.class.begin_session(options) do |dealing_platform|
16
+ @instrument_regex = Regexp.new options.fetch('instrument', ''), Regexp::IGNORECASE
17
+
16
18
  transactions = gather_transactions dealing_platform
17
19
 
18
20
  table = TransactionsTable.new transactions
@@ -29,8 +31,6 @@ module IGMarkets
29
31
  private
30
32
 
31
33
  def gather_transactions(dealing_platform)
32
- @instrument_regex = Regexp.new options.fetch('instrument', ''), Regexp::IGNORECASE
33
-
34
34
  result = gather_account_history(:transactions, dealing_platform).select do |transaction|
35
35
  transaction_filter transaction
36
36
  end
@@ -50,28 +50,31 @@ module IGMarkets
50
50
  @dealing_platform.sign_in options[:username], options[:password], options[:api_key], platform
51
51
 
52
52
  yield @dealing_platform
53
- rescue IGMarkets::RequestFailedError => error
54
- error "Request error: #{error.error}"
55
- rescue ArgumentError => error
56
- error "Argument error: #{error}"
53
+ rescue IGMarkets::RequestFailedError => request_failed_error
54
+ error "Request error: #{request_failed_error.error}"
55
+ rescue ArgumentError => argument_error
56
+ error "Argument error: #{argument_error}"
57
57
  end
58
58
 
59
- # Requests and displays the deal confirmation for the passed deal reference. If the first request for the deal
60
- # confirmation returns a 'deal not found' error then the request is attempted again after a five second pause.
61
- # This is done because sometimes there is a delay in the processing of the deal by IG Markets.
59
+ # Requests and displays the deal confirmation for the passed deal reference. If the request for the deal
60
+ # confirmation returns a 'deal not found' error then the request is attempted again after a two second pause.
61
+ # This is done because sometimes there is a delay in the processing of the deal by IG Markets. A maximum of
62
+ # five attempts wil be made before failing outright.
62
63
  #
63
64
  # @param [String] deal_reference The deal reference.
64
65
  def report_deal_confirmation(deal_reference)
65
66
  puts "Deal reference: #{deal_reference}"
66
67
 
67
- print_deal_confirmation @dealing_platform.deal_confirmation(deal_reference)
68
- rescue RequestFailedError => request_failed_error
69
- raise unless request_failed_error.error == 'error.confirms.deal-not-found'
70
-
71
- puts 'Deal confirmation not found, pausing for five seconds before retrying ...'
68
+ 5.times do |index|
69
+ begin
70
+ return print_deal_confirmation @dealing_platform.deal_confirmation(deal_reference)
71
+ rescue IGMarkets::RequestFailedError => request_failed_error
72
+ raise if request_failed_error.error != 'error.confirms.deal-not-found' || index == 4
72
73
 
73
- sleep 5
74
- print_deal_confirmation @dealing_platform.deal_confirmation(deal_reference)
74
+ puts 'Deal not found, retrying ...'
75
+ sleep 2
76
+ end
77
+ end
75
78
  end
76
79
 
77
80
  # Parses and validates a `Date` or `Time` option received as a command-line argument. Raises `ArgumentError` if
@@ -16,11 +16,12 @@ module IGMarkets
16
16
  end
17
17
 
18
18
  def headings
19
- ['Date', 'EPIC', 'Type', 'Direction', 'Size', 'Level', 'Current', 'Limit', 'Stop', 'Profit/loss', 'Deal IDs']
19
+ ['Date', 'EPIC', 'Type', 'Direction', 'Size', 'Level', 'Current', 'High', 'Low', 'Limit', 'Stop', 'Profit/loss',
20
+ 'Deal IDs']
20
21
  end
21
22
 
22
23
  def right_aligned_columns
23
- [4, 5, 6, 7, 8, 9]
24
+ [4, 5, 6, 7, 8, 9, 10, 11]
24
25
  end
25
26
 
26
27
  def row(position)
@@ -39,8 +40,15 @@ module IGMarkets
39
40
  end
40
41
 
41
42
  def position_prices(position)
42
- [:level, :close_level, :limit_level, :stop_level].map do |attribute|
43
- Format.level position.send(attribute)
43
+ [
44
+ position.level,
45
+ position.close_level,
46
+ position.market.high,
47
+ position.market.low,
48
+ position.limit_level,
49
+ position.stop_level
50
+ ].map do |value|
51
+ Format.level value
44
52
  end
45
53
  end
46
54
 
@@ -13,7 +13,7 @@ module IGMarkets
13
13
  attribute :deal_status, Symbol, allowed_values: [:accepted, :fund_account, :rejected]
14
14
  attribute :direction, Symbol, allowed_values: [:buy, :sell]
15
15
  attribute :epic
16
- attribute :expiry, Date, nil_if: '-', format: '%d-%b-%y'
16
+ attribute :expiry, Date, nil_if: %w(- DFB), format: '%d-%b-%y'
17
17
  attribute :guaranteed_stop, Boolean
18
18
  attribute :level, Float
19
19
  attribute :limit_distance, Fixnum
@@ -18,68 +18,78 @@ module IGMarkets
18
18
  @dealing_platform.instantiate_models Account, result
19
19
  end
20
20
 
21
- # Returns activities for this account, either the most recent activities by specifying the `:days` option, or
22
- # those from a date range by specifying the `:from` and `:to` options.
21
+ # Returns activities for this account in the specified date range.
23
22
  #
24
23
  # @param [Hash] options The options hash.
25
- # @option options [Float] :days The number of recent days to return activities for. If this is specified then the
26
- # `:from` and `:to` options must not be specified.
27
- # @option options [Date] :from The start of the period to return activities for.
28
- # @option options [Date] :to The end of the period to return activities for.
24
+ # @option options [Date] :from The start of the period to return activities for. Required.
25
+ # @option options [Date] :to The end of the period to return activities for. Defaults to today.
29
26
  #
30
27
  # @return [Array<Activity>]
31
28
  def activities(options)
32
- parse_history_options options
33
-
34
- result = history_request('history/activity', options)
35
-
36
- @dealing_platform.instantiate_models Activity, result.fetch(:activities)
29
+ history_request_complete url: 'history/activity', url_parameters: prepare_history_options(options),
30
+ collection_name: :activities, model_class: Activity, date_attribute: :date
37
31
  end
38
32
 
39
- # Returns transactions for this account, either the most recent transactions by specifying the `:days` option, or
40
- # those from a date range by specifying the `:from` and `:to` options.
33
+ # Returns transactions for this account in the specified date range.
41
34
  #
42
35
  # @param [Hash] options The options hash.
43
36
  # @option options [:all, :all_deal, :deposit, :withdrawal] :type The type of transactions to return. Defaults to
44
37
  # `:all`.
45
- # @option options [Float] :days The number of recent days to return transactions for. If this is specified then
46
- # the `:from` and `:to` options must not be specified.
47
- # @option options [Date] :from The start of the period to return transactions for.
48
- # @option options [Date] :to The end of the period to return transactions for.
38
+ # @option options [Date] :from The start of the period to return transactions for. Required.
39
+ # @option options [Date] :to The end of the period to return transactions for. Defaults to today.
49
40
  #
50
- # @return [Array<Activity>]
41
+ # @return [Array<Transaction>]
51
42
  def transactions(options)
52
43
  options[:type] ||= :all
53
44
 
54
- parse_history_options options
45
+ history_request_complete url: 'history/transactions', url_parameters: prepare_history_options(options),
46
+ collection_name: :transactions, model_class: Transaction, date_attribute: :date_utc
47
+ end
55
48
 
56
- result = history_request('history/transactions', options)
49
+ private
57
50
 
58
- @dealing_platform.instantiate_models Transaction, result.fetch(:transactions)
51
+ # The maximum number of results the IG Markets API will return in one request.
52
+ MAXIMUM_PAGE_SIZE = 500
53
+
54
+ # Retrieves historical data for this account (either activities or transactions) in the specified date range. This
55
+ # methods sends a single GET request with the passed URL parameters and returns the response. The maximum number
56
+ # of items this method can return is capped at 500 {MAXIMUM_PAGE_SIZE}.
57
+ def history_request(options)
58
+ url = "#{options[:url]}?#{options[:url_parameters].map { |key, value| "#{key}=#{value.to_s.upcase}" }.join '&'}"
59
+
60
+ get_result = @dealing_platform.session.get url, API_V2
61
+
62
+ @dealing_platform.instantiate_models options[:model_class], get_result.fetch(options[:collection_name])
59
63
  end
60
64
 
61
- private
65
+ # This method is the same as {#history_request} except it will send as many GET requests as are needed in order
66
+ # to circumvent the maximum number of results that can be returned per request.
67
+ def history_request_complete(options)
68
+ models = []
62
69
 
63
- # Sends a GET request to the specified URL with the passed options and returns the response.
64
- #
65
- # @param [String] url The base URL.
66
- # @param [Hash] options The options to put with the URL.
67
- #
68
- # @return [Hash]
69
- def history_request(url, options)
70
- url = "#{url}?#{options.map { |key, value| "#{key}=#{value.to_s.upcase}" }.join '&'}"
70
+ loop do
71
+ request_result = history_request options
72
+ models += request_result
73
+
74
+ break if request_result.size < MAXIMUM_PAGE_SIZE
75
+
76
+ # Update the :to parameter so the next GET request returns older results
77
+ options[:url_parameters][:to] = request_result.last.send(options[:date_attribute]).utc.to_date + 1
78
+ end
71
79
 
72
- @dealing_platform.session.get url, API_V2
80
+ models.uniq
73
81
  end
74
82
 
75
83
  # Parses and formats the history options shared by {#activities} and {#transactions}.
76
- #
77
- # @param [Hash] options
78
- def parse_history_options(options)
79
- options[:maxSpanSeconds] = (options.delete(:days).to_f * 24 * 60 * 60).to_i if options.key? :days
80
- options[:from] = options[:from].strftime('%F') if options.key? :from
81
- options[:to] = options[:to].strftime('%F') if options.key? :to
82
- options[:pageSize] = 0
84
+ def prepare_history_options(options)
85
+ options[:to] ||= Date.today + 1
86
+
87
+ options[:from] = options[:from].strftime('%F')
88
+ options[:to] = options[:to].strftime('%F')
89
+
90
+ options[:pageSize] = MAXIMUM_PAGE_SIZE
91
+
92
+ options
83
93
  end
84
94
  end
85
95
  end
@@ -60,7 +60,7 @@ module IGMarkets
60
60
  attribute :country
61
61
  attribute :currencies, Currency
62
62
  attribute :epic, String, regex: Regex::EPIC
63
- attribute :expiry, Date, nil_if: '-', format: '%d-%b-%y'
63
+ attribute :expiry, Date, nil_if: %w(- DFB), format: '%d-%b-%y'
64
64
  attribute :expiry_details, ExpiryDetails
65
65
  attribute :force_open_allowed, Boolean
66
66
  attribute :lot_size, Float
@@ -63,7 +63,7 @@ module IGMarkets
63
63
  options[:from] = options[:from].utc.strftime '%FT%T' if options.key? :from
64
64
  options[:to] = options[:to].utc.strftime '%FT%T' if options.key? :to
65
65
 
66
- @dealing_platform.instantiate_models HistoricalPriceResult, historical_prices_response(options)
66
+ @dealing_platform.instantiate_models HistoricalPriceResult, historical_prices_request(options)
67
67
  end
68
68
 
69
69
  private
@@ -81,7 +81,7 @@ module IGMarkets
81
81
  end
82
82
 
83
83
  # Returns the API response to a request for historical prices.
84
- def historical_prices_response(options)
84
+ def historical_prices_request(options)
85
85
  url = "prices/#{instrument.epic}?#{options.map { |key, value| "#{key}=#{value.to_s.upcase}" }.join '&'}"
86
86
 
87
87
  @dealing_platform.session.get url, API_V3
@@ -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: '-'
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)
@@ -1,4 +1,4 @@
1
1
  module IGMarkets
2
2
  # The version of this gem.
3
- VERSION = '0.10'.freeze
3
+ VERSION = '0.11'.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.10'
4
+ version: '0.11'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Viney
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-10 00:00:00.000000000 Z
11
+ date: 2016-05-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize