ig_markets 0.14 → 0.15

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: 4a9c0f861710bf880c830d2826c3e4ece9c2ef35
4
- data.tar.gz: 4c2f4dbd5d336489e2a343ac0015ff34c0910e2b
3
+ metadata.gz: 4205e8e7a404222272416344c5f21e912de43256
4
+ data.tar.gz: 55595208ec8a08d8941d68387c6c61e19c436d5d
5
5
  SHA512:
6
- metadata.gz: fa7dc0e4c01816d95e5b6dfec934c3a52e66b9b82ed27f5b777c19a89fa7bda5915b8f9bdba02ae6a3b8b42c251622ffa91c2c1a41e6c032ca4ae7300b611ca8
7
- data.tar.gz: 9ca3b4fe730001d4ed3d8900ec5483e3a10e386e9b772f4057e0696b9c3f8019889318faf6abda047735046dade967bcaf537a1a157b95e90e5eb751928feb23
6
+ metadata.gz: 230f8eb850b639d3a6fa479cd42101ecd89c901382951adaa5a69d064029623a30c042cbe9bc44ee16d11b0e1cf50c034dc99e0aa43f3081063b27cda4a797ec
7
+ data.tar.gz: 20991fd83b740be9a1bcc36ce2c112a7a63b2070adc9cf736617a130350b9810abe33663214b1b45889b3e53bda3741cc37f633068f1284cab30a09088d36d9b
data/CHANGELOG.md CHANGED
@@ -1,10 +1,21 @@
1
1
  # IG Markets Changelog
2
2
 
3
+ ### 0.15 — July 11, 2016
4
+
5
+ - Added `ig_markets self-test` command that can be run under a demo account in order to test the library against the
6
+ live IG Markets API
7
+ - If the API key or account's traffic allowance is exceeded then `IGMarkets::Session` now automatically retries the
8
+ request after a five second pause
9
+ - Added `IGMarkets::MarketHierarchyResult::HierarchyNode#markets` and
10
+ `IGMarkets::MarketHierarchyResult::HierarchyNode#nodes` methods
11
+
3
12
  ### 0.14 — July 2, 2016
4
13
 
5
14
  - Added `delete-all` subcommand to `ig_markets orders`
6
15
  - Added a `#reload` method that reloads a model's attributes in-place to `IGMarkets::Account`,
7
16
  `IGMarkets::ClientSentiment`, `IGMarkets::Market`, `IGMarkets::Position` and `IGMarkets::WorkingOrder`
17
+ - Support mass assignment of attributes on models
18
+ - Fixed a compatibility issue with recent IG API changes
8
19
 
9
20
  ### 0.13 — June 22, 2016
10
21
 
data/README.md CHANGED
@@ -85,6 +85,7 @@ commands and their subcommands is:
85
85
  - `ig_markets positions close-all [...]`
86
86
  - `ig_markets prices --epic EPIC --resolution RESOLUTION ...`
87
87
  - `ig_markets search QUERY [--type TYPE]`
88
+ - `ig_markets self-test`
88
89
  - `ig_markets sentiment MARKET`
89
90
  - `ig_markets sprints [list]`
90
91
  - `ig_markets sprints create ...`
@@ -0,0 +1,142 @@
1
+ module IGMarkets
2
+ module CLI
3
+ # Implements the `ig_markets self-test` command.
4
+ class Main < Thor
5
+ desc 'self-test', 'Runs a self-test of this application against the live IG Markets API (demo accounts only)'
6
+
7
+ def self_test
8
+ self.class.begin_session(options) do |dealing_platform|
9
+ raise 'Error: self-tests must be run on a demo account' unless dealing_platform.session.platform == :demo
10
+
11
+ run_self_test dealing_platform
12
+
13
+ dealing_platform.sign_out
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def run_self_test(dealing_platform)
20
+ test_markets dealing_platform
21
+ test_positions dealing_platform
22
+ test_sprint_market_positions dealing_platform
23
+ test_working_orders dealing_platform
24
+ test_watchlists dealing_platform
25
+ test_client_sentiment dealing_platform
26
+ test_account_methods dealing_platform
27
+ test_applications dealing_platform
28
+ end
29
+
30
+ def test_markets(dealing_platform)
31
+ dealing_platform.markets.hierarchy '264134' # ID of the main 'Forex' node
32
+ dealing_platform.markets.search 'EURUSD'
33
+ @eur_usd = dealing_platform.markets['CS.D.EURUSD.CFD.IP']
34
+ @eur_usd_sprint = dealing_platform.markets['FM.D.EURUSD24.EURUSD24.IP']
35
+ @eur_usd.historical_prices resolution: :hour, number: 1
36
+ end
37
+
38
+ def test_positions(dealing_platform)
39
+ test_position_create dealing_platform
40
+ test_position_update
41
+ test_position_close dealing_platform
42
+ end
43
+
44
+ def test_position_create(dealing_platform)
45
+ deal_reference = dealing_platform.positions.create currency_code: 'USD', direction: :buy,
46
+ epic: 'CS.D.EURUSD.CFD.IP', size: 2
47
+
48
+ @position = dealing_platform.positions[dealing_platform.deal_confirmation(deal_reference).deal_id]
49
+
50
+ raise 'Error: failed creating position' unless @position
51
+ end
52
+
53
+ def test_position_update
54
+ stop_level = @position.level - 0.01
55
+
56
+ @position.update stop_level: stop_level
57
+ @position.reload
58
+
59
+ update_worked = (@position.stop_level - stop_level).abs < 0.001
60
+
61
+ raise 'Error: failed updating position' unless update_worked
62
+ end
63
+
64
+ def test_position_close(dealing_platform)
65
+ @position.close
66
+
67
+ raise 'Error: failed closing position' if dealing_platform.positions[@position.deal_id]
68
+ end
69
+
70
+ def test_sprint_market_positions(dealing_platform)
71
+ deal_reference = dealing_platform.sprint_market_positions.create direction: :buy,
72
+ epic: 'FM.D.EURUSD24.EURUSD24.IP',
73
+ expiry_period: :twenty_minutes, size: 100
74
+
75
+ deal_confirmation = dealing_platform.deal_confirmation deal_reference
76
+
77
+ sprint_market_position = dealing_platform.sprint_market_positions[deal_confirmation.deal_id]
78
+
79
+ raise 'Error: failed creating sprint market position' unless sprint_market_position
80
+ end
81
+
82
+ def test_working_orders(dealing_platform)
83
+ test_working_order_create dealing_platform
84
+ test_working_order_update dealing_platform
85
+ test_working_order_delete dealing_platform
86
+ end
87
+
88
+ def test_working_order_create(dealing_platform)
89
+ deal_reference = dealing_platform.working_orders.create currency_code: 'USD', direction: :buy,
90
+ epic: 'CS.D.EURUSD.CFD.IP', type: :limit,
91
+ level: @eur_usd.snapshot.bid - 0.1, size: 1
92
+
93
+ @working_order = dealing_platform.working_orders[dealing_platform.deal_confirmation(deal_reference).deal_id]
94
+
95
+ raise 'Error: failed creating working order' unless @working_order
96
+ end
97
+
98
+ def test_working_order_update(dealing_platform)
99
+ new_level = @eur_usd.snapshot.bid - 1
100
+
101
+ @working_order.update level: new_level
102
+ @working_order.reload
103
+
104
+ update_worked = (new_level - dealing_platform.working_orders[@working_order.deal_id].order_level).abs < 0.01
105
+
106
+ raise 'Error: failed updating working order' unless update_worked
107
+ end
108
+
109
+ def test_working_order_delete(dealing_platform)
110
+ @working_order.delete
111
+
112
+ raise 'Error: failed deleting working order' if dealing_platform.working_orders[@working_order.deal_id]
113
+ end
114
+
115
+ def test_watchlists(dealing_platform)
116
+ watchlist = dealing_platform.watchlists.create SecureRandom.hex, 'UA.D.AAPL.CASH.IP'
117
+ watchlist = dealing_platform.watchlists[watchlist.id]
118
+ watchlist.markets
119
+ watchlist.add_market 'CS.D.EURUSD.CFD.IP'
120
+ watchlist.remove_market 'CS.D.EURUSD.CFD.IP'
121
+ watchlist.delete
122
+
123
+ raise 'Error: failed deleting watchlist' if dealing_platform.watchlists[watchlist.id]
124
+ end
125
+
126
+ def test_account_methods(dealing_platform)
127
+ dealing_platform.account.all
128
+ dealing_platform.account.activities from: Date.today - 14
129
+ dealing_platform.account.transactions from: Date.today - 14
130
+ end
131
+
132
+ def test_client_sentiment(dealing_platform)
133
+ client_sentiment = dealing_platform.client_sentiment['EURUSD']
134
+ client_sentiment.related_sentiments
135
+ end
136
+
137
+ def test_applications(dealing_platform)
138
+ dealing_platform.applications
139
+ end
140
+ end
141
+ end
142
+ end
@@ -5,6 +5,20 @@ module IGMarkets
5
5
  class HierarchyNode < Model
6
6
  attribute :id
7
7
  attribute :name
8
+
9
+ # Returns an array of the markets under this node in the market hierarchy.
10
+ #
11
+ # @return [Array<MarketOverview>]
12
+ def markets
13
+ @dealing_platform.markets.hierarchy(id).markets
14
+ end
15
+
16
+ # Returns an array of the child nodes under this node in the market hierarchy.
17
+ #
18
+ # @return [Array<HierarchyNode>]
19
+ def nodes
20
+ @nodes ||= @dealing_platform.markets.hierarchy(id).nodes
21
+ end
8
22
  end
9
23
 
10
24
  attribute :markets, MarketOverview
@@ -101,10 +101,7 @@ module IGMarkets
101
101
 
102
102
  private
103
103
 
104
- HOST_URLS = {
105
- demo: 'https://demo-api.ig.com/gateway/deal/',
106
- live: 'https://api.ig.com/gateway/deal/'
107
- }.freeze
104
+ HOST_URLS = { demo: 'https://demo-api.ig.com/gateway/deal/', live: 'https://api.ig.com/gateway/deal/' }.freeze
108
105
 
109
106
  def validate_authentication
110
107
  %i(username password api_key).each do |attribute|
@@ -163,24 +160,34 @@ module IGMarkets
163
160
  rescue RestClient::Exception => exception
164
161
  raise RequestFailedError, exception.message unless exception.response
165
162
 
166
- return exception.response unless !options[:retry] && client_token_invalid?(exception.response)
163
+ return exception.response unless should_retry_request? exception.response, options
167
164
 
168
- sign_in
169
165
  execute_request options.merge(retry: true)
170
166
  rescue SocketError => socket_error
171
167
  raise RequestFailedError, socket_error
172
168
  end
173
169
 
174
- def client_token_invalid?(response)
175
- ResponseParser.parse_json(response.body)[:error_code] == 'error.security.client-token-invalid'
170
+ def should_retry_request?(response, options)
171
+ error_code = ResponseParser.parse_json(response.body)[:error_code]
172
+
173
+ if error_code == 'error.security.client-token-invalid' && !options[:retry]
174
+ sign_in
175
+ return true
176
+ end
177
+
178
+ if error_code =~ /^error\.public-api\.exceeded-(api-key|account)-allowance/
179
+ sleep 5
180
+ return true
181
+ end
182
+
183
+ false
176
184
  end
177
185
 
178
186
  def process_response(response)
179
187
  result = ResponseParser.parse_json response.body
188
+ http_code = response.code
180
189
 
181
- unless response.code >= 200 && response.code < 300
182
- raise RequestFailedError.new(result[:error_code], response.code)
183
- end
190
+ raise RequestFailedError.new(result[:error_code], http_code) unless http_code >= 200 && http_code < 300
184
191
 
185
192
  result
186
193
  end
@@ -1,4 +1,4 @@
1
1
  module IGMarkets
2
2
  # The version of this gem.
3
- VERSION = '0.14'.freeze
3
+ VERSION = '0.15'.freeze
4
4
  end
data/lib/ig_markets.rb CHANGED
@@ -4,6 +4,7 @@ require 'date'
4
4
  require 'json'
5
5
  require 'pry'
6
6
  require 'rest-client'
7
+ require 'securerandom'
7
8
  require 'terminal-table'
8
9
  require 'thor'
9
10
 
@@ -60,6 +61,7 @@ require 'ig_markets/cli/commands/markets_command'
60
61
  require 'ig_markets/cli/commands/performance_command'
61
62
  require 'ig_markets/cli/commands/prices_command'
62
63
  require 'ig_markets/cli/commands/search_command'
64
+ require 'ig_markets/cli/commands/self_test_command'
63
65
  require 'ig_markets/cli/commands/sentiment_command'
64
66
  require 'ig_markets/cli/commands/transactions_command'
65
67
  require 'ig_markets/cli/tables/table'
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.14'
4
+ version: '0.15'
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-07-02 00:00:00.000000000 Z
11
+ date: 2016-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -233,6 +233,7 @@ files:
233
233
  - lib/ig_markets/cli/commands/positions_command.rb
234
234
  - lib/ig_markets/cli/commands/prices_command.rb
235
235
  - lib/ig_markets/cli/commands/search_command.rb
236
+ - lib/ig_markets/cli/commands/self_test_command.rb
236
237
  - lib/ig_markets/cli/commands/sentiment_command.rb
237
238
  - lib/ig_markets/cli/commands/sprints_command.rb
238
239
  - lib/ig_markets/cli/commands/transactions_command.rb