ig_markets 0.19 → 0.20

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6e6fa29281db18808e948435c5dd1dcb5da3b003
4
- data.tar.gz: ef3c666877d55b0c85236e1982b6d6d55713ad90
3
+ metadata.gz: e0873a06d085af3287d3497f41a7157710216995
4
+ data.tar.gz: 4606f5cc0084f0092ab1f53361ae3c2ff11f4804
5
5
  SHA512:
6
- metadata.gz: 01471a39066771f1bbbb4df8faff8c500072af4bd93eef58a246c2669f495a3307d136b190b67c45e27bb4774515aada15d40099caf388ee4459e2c9ec76fab9
7
- data.tar.gz: 314ec4b9d9005ae4dd5117dd2ec5380f5338a6a53a4be1d32f0a3592327dc331fa5153f97e5197565badec61dfd6c54863b7449c45f9559670ca0ccb32687179
6
+ metadata.gz: db11c11960641e5f468b5765e3e790bce4540c3e2f6e468e29ba0b80fda70e7bd3aab20cdcae5e37f3c86fd2a26a59afc39dde7d22ece0ab8abf9524c254acea
7
+ data.tar.gz: 6d27114ba6ba7811f767a022643f176bc77ad69d669c8e81b2637c82b321a611cb355bcf4b91bd3e8b0ca30fc4899705b4bb5d8902807b58e4bac96c654b9632
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # IG Markets Changelog
2
2
 
3
+ ### 0.20 — August 20, 2016
4
+
5
+ - Added `IGMarkets::DealingPlatform#streaming` which along with new classes in the `IGMarkets::Streaming` module
6
+ provides a simple interface to the IG Markets streaming API
7
+ - Added `ig_markets stream` command that shows a live display of account balances, positions and working orders, the
8
+ previous behavior of showing raw streaming output is still available using `ig_markets stream raw`
9
+ - Added new `IGMarkets::Position#deal_reference` attribute
10
+ - The `ig_markets self-test` command now runs self-tests on the streaming functionality as well
11
+ - Removed `IGMarkets::DealingPlatform#lightstreamer_session`
12
+
3
13
  ### 0.19 — August 5, 2016
4
14
 
5
15
  - Added `ig_markets stream` command that displays live streaming data for accounts, markets and trading activity
data/README.md CHANGED
@@ -22,6 +22,7 @@ Includes support for:
22
22
  - Watchlists
23
23
  - Client sentiment
24
24
  - Authentication profiles
25
+ - Live streaming of account, trade and market updates
25
26
 
26
27
  An IG Markets live or demo trading account is needed in order to use this gem.
27
28
 
@@ -100,7 +101,8 @@ commands and their subcommands is:
100
101
  - `ig_markets sentiment MARKET`
101
102
  - `ig_markets sprints [list]`
102
103
  - `ig_markets sprints create ...`
103
- - `ig_markets stream ...`
104
+ - `ig_markets stream [dashboard] [...]`
105
+ - `ig_markets stream raw ...`
104
106
  - `ig_markets transactions --days N [...]`
105
107
  - `ig_markets watchlists [list]`
106
108
  - `ig_markets watchlists create NAME [EPIC ...]`
@@ -152,8 +154,11 @@ ig_markets prices --epic CS.D.EURUSD.CFD.IP --resolution day --number 14
152
154
  # Print account dealing performance from the last 90 days, broken down by the EPICs that were traded
153
155
  ig_markets performance --days 90
154
156
 
155
- # Print streaming details of account balances, trading actions, and the live price of the EURUSD pair
156
- ig_markets stream --accounts --trades --markets CS.D.EURUSD.CFD.IP
157
+ # Print an updating live display of account balances, positions and working orders
158
+ ig_markets stream
159
+
160
+ # Print raw streaming details of account balances, trading actions, and the price of the EURUSD pair
161
+ ig_markets stream raw --accounts --trades --markets CS.D.EURUSD.CFD.IP
157
162
 
158
163
  # Log in and open a Ruby console which can be used to query the IG API, printing all REST requests
159
164
  ig_markets console --verbose
@@ -235,6 +240,23 @@ client_sentiment.reload
235
240
 
236
241
  # Miscellaneous
237
242
  ig.applications
243
+
244
+ # Streaming
245
+ queue = Queue.new
246
+
247
+ ig.streaming.connect
248
+ ig.streaming.on_error { |error| queue.push error }
249
+
250
+ subscription = ig.streaming.build_accounts_subscription
251
+ subscription.on_data { |data, _merged_data| queue.push data }
252
+ ig.streaming.start_subscriptions subscription, snapshot: true
253
+
254
+ loop do
255
+ data = queue.pop
256
+ raise data if data.is_a? Lightstreamer::LightstreamerError
257
+
258
+ puts data.inspect
259
+ end
238
260
  ```
239
261
 
240
262
  ## Contributors
data/lib/ig_markets.rb CHANGED
@@ -30,6 +30,7 @@ require 'ig_markets/dealing_platform/client_sentiment_methods'
30
30
  require 'ig_markets/dealing_platform/market_methods'
31
31
  require 'ig_markets/dealing_platform/position_methods'
32
32
  require 'ig_markets/dealing_platform/sprint_market_position_methods'
33
+ require 'ig_markets/dealing_platform/streaming_methods'
33
34
  require 'ig_markets/dealing_platform/watchlist_methods'
34
35
  require 'ig_markets/dealing_platform/working_order_methods'
35
36
  require 'ig_markets/errors'
@@ -46,6 +47,15 @@ require 'ig_markets/request_printer'
46
47
  require 'ig_markets/response_parser'
47
48
  require 'ig_markets/session'
48
49
  require 'ig_markets/sprint_market_position'
50
+ require 'ig_markets/streaming/account_state'
51
+ require 'ig_markets/streaming/account_update'
52
+ require 'ig_markets/streaming/chart_tick_update'
53
+ require 'ig_markets/streaming/consolidated_chart_data_update'
54
+ require 'ig_markets/streaming/market_subscription_manager'
55
+ require 'ig_markets/streaming/market_update'
56
+ require 'ig_markets/streaming/position_update'
57
+ require 'ig_markets/streaming/subscription'
58
+ require 'ig_markets/streaming/working_order_update'
49
59
  require 'ig_markets/transaction'
50
60
  require 'ig_markets/version'
51
61
  require 'ig_markets/watchlist'
@@ -54,9 +64,11 @@ require 'ig_markets/working_order'
54
64
  require 'ig_markets/cli/commands/orders_command'
55
65
  require 'ig_markets/cli/commands/positions_command'
56
66
  require 'ig_markets/cli/commands/sprints_command'
67
+ require 'ig_markets/cli/commands/stream_command'
57
68
  require 'ig_markets/cli/commands/watchlists_command'
58
69
  require 'ig_markets/cli/main'
59
70
  require 'ig_markets/cli/config_file'
71
+ require 'ig_markets/cli/curses_window'
60
72
  require 'ig_markets/cli/commands/account_command'
61
73
  require 'ig_markets/cli/commands/activities_command'
62
74
  require 'ig_markets/cli/commands/confirmation_command'
@@ -67,7 +79,6 @@ require 'ig_markets/cli/commands/prices_command'
67
79
  require 'ig_markets/cli/commands/search_command'
68
80
  require 'ig_markets/cli/commands/self_test_command'
69
81
  require 'ig_markets/cli/commands/sentiment_command'
70
- require 'ig_markets/cli/commands/stream_command'
71
82
  require 'ig_markets/cli/commands/transactions_command'
72
83
  require 'ig_markets/cli/tables/table'
73
84
  require 'ig_markets/cli/tables/accounts_table'
@@ -85,4 +96,8 @@ require 'ig_markets/cli/tables/working_orders_table'
85
96
  # This module contains all the code for the IG Markets gem. See `README.md` and the {DealingPlatform} class to get
86
97
  # started with using this gem.
87
98
  module IGMarkets
99
+ # This module contains classes used when streaming live data from the IG Markets API. See
100
+ # {DealingPlatform::StreamingMethods} for details.
101
+ module Streaming
102
+ end
88
103
  end
@@ -8,7 +8,8 @@ module IGMarkets
8
8
  self.class.begin_session(options) do |dealing_platform|
9
9
  raise 'Error: self-tests must be run on a demo account' unless dealing_platform.session.platform == :demo
10
10
 
11
- run_self_test dealing_platform
11
+ @dealing_platform = dealing_platform
12
+ run_self_test
12
13
 
13
14
  dealing_platform.sign_out
14
15
  end
@@ -16,36 +17,38 @@ module IGMarkets
16
17
 
17
18
  private
18
19
 
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']
20
+ def run_self_test
21
+ test_markets
22
+ test_positions
23
+ test_sprint_market_positions
24
+ test_working_orders
25
+ test_watchlists
26
+ test_client_sentiment
27
+ test_account_methods
28
+ test_applications
29
+ test_streaming
30
+ end
31
+
32
+ def test_markets
33
+ @dealing_platform.markets.hierarchy '264134' # ID of the main 'Forex' node
34
+ @dealing_platform.markets.search 'EURUSD'
35
+ @eur_usd = @dealing_platform.markets['CS.D.EURUSD.CFD.IP']
36
+ @eur_usd_sprint = @dealing_platform.markets['FM.D.EURUSD24.EURUSD24.IP']
35
37
  @eur_usd.historical_prices resolution: :hour, number: 1
36
38
  end
37
39
 
38
- def test_positions(dealing_platform)
39
- test_position_create dealing_platform
40
+ def test_positions
41
+ test_position_create
40
42
  test_position_update
41
- test_position_close dealing_platform
43
+ test_position_close
42
44
  end
43
45
 
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
46
+ def test_position_create
47
+ deal_reference = @dealing_platform.positions.create currency_code: 'USD', direction: :buy,
48
+ epic: 'CS.D.EURUSD.CFD.IP', size: 2
47
49
 
48
- @position = dealing_platform.positions[dealing_platform.deal_confirmation(deal_reference).deal_id]
50
+ deal_confirmation = @dealing_platform.deal_confirmation deal_reference
51
+ @position = @dealing_platform.positions[deal_confirmation.deal_id]
49
52
 
50
53
  raise 'Error: failed creating position' unless @position
51
54
  end
@@ -61,81 +64,97 @@ module IGMarkets
61
64
  raise 'Error: failed updating position' unless update_worked
62
65
  end
63
66
 
64
- def test_position_close(dealing_platform)
67
+ def test_position_close
65
68
  @position.close
66
69
 
67
- raise 'Error: failed closing position' if dealing_platform.positions[@position.deal_id]
70
+ raise 'Error: failed closing position' if @dealing_platform.positions[@position.deal_id]
68
71
  end
69
72
 
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
73
+ def test_sprint_market_positions
74
+ create_options = { direction: :buy, expiry_period: :sixty_minutes, epic: 'FM.D.EURUSD24.EURUSD24.IP',
75
+ size: 100 }
74
76
 
75
- deal_confirmation = dealing_platform.deal_confirmation deal_reference
76
-
77
- sprint_market_position = dealing_platform.sprint_market_positions[deal_confirmation.deal_id]
77
+ deal_reference = @dealing_platform.sprint_market_positions.create create_options
78
+ deal_confirmation = @dealing_platform.deal_confirmation deal_reference
79
+ sprint_market_position = @dealing_platform.sprint_market_positions[deal_confirmation.deal_id]
78
80
 
79
81
  raise 'Error: failed creating sprint market position' unless sprint_market_position
80
82
  end
81
83
 
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
84
+ def test_working_orders
85
+ test_working_order_create
86
+ test_working_order_update
87
+ test_working_order_delete
86
88
  end
87
89
 
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
90
+ def test_working_order_create
91
+ deal_reference = @dealing_platform.working_orders.create currency_code: 'USD', direction: :buy,
92
+ epic: 'CS.D.EURUSD.CFD.IP', type: :limit,
93
+ level: @eur_usd.snapshot.bid - 0.1, size: 1
92
94
 
93
- @working_order = dealing_platform.working_orders[dealing_platform.deal_confirmation(deal_reference).deal_id]
95
+ @working_order = @dealing_platform.working_orders[@dealing_platform.deal_confirmation(deal_reference).deal_id]
94
96
 
95
97
  raise 'Error: failed creating working order' unless @working_order
96
98
  end
97
99
 
98
- def test_working_order_update(dealing_platform)
100
+ def test_working_order_update
99
101
  new_level = @eur_usd.snapshot.bid - 1
100
102
 
101
103
  @working_order.update level: new_level
102
104
  @working_order.reload
103
105
 
104
- update_worked = (new_level - dealing_platform.working_orders[@working_order.deal_id].order_level).abs < 0.01
106
+ update_worked = (new_level - @dealing_platform.working_orders[@working_order.deal_id].order_level).abs < 0.01
105
107
 
106
108
  raise 'Error: failed updating working order' unless update_worked
107
109
  end
108
110
 
109
- def test_working_order_delete(dealing_platform)
111
+ def test_working_order_delete
110
112
  @working_order.delete
111
113
 
112
- raise 'Error: failed deleting working order' if dealing_platform.working_orders[@working_order.deal_id]
114
+ raise 'Error: failed deleting working order' if @dealing_platform.working_orders[@working_order.deal_id]
113
115
  end
114
116
 
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]
117
+ def test_watchlists
118
+ watchlist = @dealing_platform.watchlists.create SecureRandom.hex, 'UA.D.AAPL.CASH.IP'
119
+ watchlist = @dealing_platform.watchlists[watchlist.id]
118
120
  watchlist.markets
119
121
  watchlist.add_market 'CS.D.EURUSD.CFD.IP'
120
122
  watchlist.remove_market 'CS.D.EURUSD.CFD.IP'
121
123
  watchlist.delete
122
124
 
123
- raise 'Error: failed deleting watchlist' if dealing_platform.watchlists[watchlist.id]
125
+ raise 'Error: failed deleting watchlist' if @dealing_platform.watchlists[watchlist.id]
126
+ end
127
+
128
+ def test_account_methods
129
+ @dealing_platform.account.all
130
+ @dealing_platform.account.activities from: Date.today - 14
131
+ @dealing_platform.account.transactions from: Date.today - 14
124
132
  end
125
133
 
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
134
+ def test_client_sentiment
135
+ @dealing_platform.client_sentiment['EURUSD'].related_sentiments
130
136
  end
131
137
 
132
- def test_client_sentiment(dealing_platform)
133
- client_sentiment = dealing_platform.client_sentiment['EURUSD']
134
- client_sentiment.related_sentiments
138
+ def test_applications
139
+ @dealing_platform.applications
135
140
  end
136
141
 
137
- def test_applications(dealing_platform)
138
- dealing_platform.applications
142
+ def test_streaming
143
+ streaming = @dealing_platform.streaming
144
+
145
+ streaming.connect
146
+
147
+ subscriptions = [streaming.build_accounts_subscription,
148
+ streaming.build_markets_subscription(['CS.D.EURUSD.CFD.IP']),
149
+ streaming.build_trades_subscription]
150
+
151
+ streaming.start_subscriptions subscriptions, snapshot: true
152
+
153
+ queue = Queue.new
154
+ subscriptions.each { |subscription| subscription.on_data { |data| queue.push data } }
155
+ 10.times { queue.pop }
156
+
157
+ streaming.disconnect
139
158
  end
140
159
  end
141
160
  end
@@ -1,170 +1,118 @@
1
1
  module IGMarkets
2
2
  module CLI
3
3
  # Implements the `ig_markets stream` command.
4
- class Main < Thor
5
- desc 'stream', 'Displays live streaming updates of account balances, markets and trading activity'
4
+ class Stream < Thor
5
+ desc 'dashboard', 'Displays an updating live display of account balances, positions and working orders'
6
6
 
7
- option :accounts, type: :boolean, desc: 'Whether to stream changes to account balances'
8
- option :markets, type: :array, desc: 'The EPICs of the markets to stream live prices for'
9
- option :trades, type: :boolean, desc: 'Whether to stream details of any trades and position or order updates'
7
+ option :aggregate, type: :boolean, desc: 'Whether to aggregate separate positions in the same market'
10
8
 
11
- def stream
12
- self.class.begin_session(options) do |dealing_platform|
13
- @dealing_platform = dealing_platform
9
+ def dashboard
10
+ Main.begin_session(options) do |dealing_platform|
11
+ dealing_platform.streaming.connect
12
+ dealing_platform.streaming.on_error { |error| @error = error }
13
+
14
+ window = CursesWindow.new
14
15
 
15
- prepare_stream
16
+ account_state = Streaming::AccountState.new dealing_platform
17
+ account_state.start
16
18
 
17
- loop { process_new_data @queue.pop }
19
+ redraw_account_state account_state, window until @error
20
+
21
+ raise @error
18
22
  end
19
23
  end
20
24
 
21
- private
25
+ default_task :dashboard
22
26
 
23
- def process_new_data(data)
24
- raise data if data.is_a? Lightstreamer::LightstreamerError
27
+ desc 'raw', 'Displays raw live streaming updates of account balances, markets and trading activity'
25
28
 
26
- puts data
27
- end
29
+ option :accounts, type: :boolean, desc: 'Whether to stream changes to account balances'
30
+ option :markets, type: :array, desc: 'The EPICs of the markets to stream live prices for'
31
+ option :trades, type: :boolean, desc: 'Whether to stream details of any trades and position or order updates'
32
+ option :chart_ticks, type: :array, desc: 'The EPICs of the markets to stream live chart tick data for'
28
33
 
29
- def prepare_stream
30
- @queue = Queue.new
34
+ def raw
35
+ Main.begin_session(options) do |dealing_platform|
36
+ @dealing_platform = dealing_platform
37
+ @queue = Queue.new
31
38
 
32
- @lightstreamer = @dealing_platform.lightstreamer_session
33
- @lightstreamer.on_error { |error| @queue.push error }
34
- @lightstreamer.connect
39
+ @dealing_platform.streaming.on_error(&method(:on_error))
40
+ @dealing_platform.streaming.connect
41
+ start_raw_subscriptions
35
42
 
36
- subscriptions = [account_subscription, market_subscription, trade_subscription].compact
37
- @lightstreamer.bulk_subscription_start subscriptions, snapshot: true
43
+ main_loop
44
+ end
38
45
  end
39
46
 
40
- def account_subscription
41
- return unless options[:accounts]
42
-
43
- items = @dealing_platform.client_account_summary.accounts.map { |account| "ACCOUNT:#{account.account_id}" }
44
- fields = [:pnl, :deposit, :available_cash, :funds, :margin, :available_to_deal, :equity]
47
+ private
45
48
 
46
- subscription = @lightstreamer.build_subscription items: items, fields: fields, mode: :merge
49
+ def start_raw_subscriptions
50
+ subscriptions = [accounts_subscription, markets_subscription, trades_subscription,
51
+ chart_ticks_subscription].compact
47
52
 
48
- subscription.on_data do |_subscription, item_name, item_data, _new_data|
49
- @queue.push "#{item_name} - #{item_data.map { |key, value| "#{key}: #{value}" }.join ', '}"
53
+ subscriptions.each do |subscription|
54
+ subscription.on_data(&method(:on_data))
50
55
  end
51
56
 
52
- subscription
57
+ @dealing_platform.streaming.start_subscriptions subscriptions, snapshot: true
53
58
  end
54
59
 
55
- def market_subscription
56
- items = Array(options[:markets]).map { |market| "MARKET:#{market}" }
57
- fields = [:bid, :offer, :high, :low, :mid_open, :strike_price, :odds]
60
+ def accounts_subscription
61
+ return unless options[:accounts]
58
62
 
59
- subscription = @lightstreamer.build_subscription items: items, fields: fields, mode: :merge
63
+ @dealing_platform.streaming.build_accounts_subscription
64
+ end
60
65
 
61
- subscription.on_data do |_subscription, item_name, item_data, _new_data|
62
- @queue.push "#{item_name} - #{item_data.map { |key, value| "#{key}: #{value}" }.join ', '}"
63
- end
66
+ def markets_subscription
67
+ return unless options[:markets]
64
68
 
65
- subscription
69
+ @dealing_platform.streaming.build_markets_subscription options[:markets]
66
70
  end
67
71
 
68
- def trade_subscription
72
+ def trades_subscription
69
73
  return unless options[:trades]
70
74
 
71
- items = @dealing_platform.client_account_summary.accounts.map { |account| "TRADE:#{account.account_id}" }
72
- fields = [:confirms, :opu, :wou]
73
-
74
- subscription = @lightstreamer.build_subscription items: items, fields: fields, mode: :distinct
75
-
76
- subscription.on_data do |_subscription, item_name, item_data, _new_data|
77
- process_confirmation item_name, item_data[:confirms]
78
- process_position_update item_name, item_data[:opu]
79
- process_working_order_update item_name, item_data[:wou]
80
- end
81
-
82
- subscription
75
+ @dealing_platform.streaming.build_trades_subscription
83
76
  end
84
77
 
85
- def process_confirmation(item_name, json)
86
- return unless json
87
-
88
- model = DealConfirmation.new ResponseParser.parse(JSON.parse(json)).merge(affected_deals: nil)
78
+ def chart_ticks_subscription
79
+ return unless options[:chart_ticks]
89
80
 
90
- queue_item = "#{item_name} - Confirmation - id: #{model.deal_id}"
81
+ @dealing_platform.streaming.build_chart_ticks_subscription options[:chart_ticks]
82
+ end
91
83
 
92
- [:status, :deal_status, :epic, :direction, :size, :level, :stop_distance, :stop_level, :limit_distance,
93
- :limit_level].each do |attribute|
94
- value = model.send attribute
95
- queue_item << ", #{attribute}: #{value}" if value
84
+ def on_data(data, _merged_data)
85
+ if data.is_a? DealConfirmation
86
+ data.affected_deals = nil
87
+ data.date = nil
96
88
  end
97
89
 
98
- queue_item << ", profit: #{Format.currency(model.profit, model.profit_currency)}" if model.profit
90
+ summary = data.attributes.keys.sort.map { |key| "#{key}: #{data.send key}" if data.send key }
99
91
 
100
- @queue.push queue_item
92
+ @queue.push "#{data.class.name.split('::').last} - #{summary.compact.join ', '}"
101
93
  end
102
94
 
103
- def process_position_update(item_name, json)
104
- return unless json
105
-
106
- model = OpenPositionUpdate.new ResponseParser.parse(JSON.parse(json))
107
-
108
- queue_item = "#{item_name} - Position update - id: #{model.deal_id}"
109
-
110
- [:status, :deal_status, :epic, :direction, :size, :level, :stop_level, :limit_level].each do |attribute|
111
- value = model.send attribute
112
- queue_item << ", #{attribute}: #{value}" if value
113
- end
114
-
115
- @queue.push queue_item
95
+ def on_error(error)
96
+ @queue.push error
116
97
  end
117
98
 
118
- def process_working_order_update(item_name, json)
119
- return unless json
99
+ def main_loop
100
+ loop do
101
+ data = @queue.pop
102
+ raise data if data.is_a? Lightstreamer::LightstreamerError
120
103
 
121
- model = WorkingOrderUpdate.new ResponseParser.parse(JSON.parse(json))
122
-
123
- queue_item = "#{item_name} - Order update - id: #{model.deal_id}"
124
-
125
- [:status, :deal_status, :epic, :direction, :size, :level, :stop_distance, :limit_distance].each do |attribute|
126
- value = model.send attribute
127
- queue_item << ", #{attribute}: #{value}" if value
104
+ puts data
128
105
  end
129
-
130
- @queue.push queue_item
131
106
  end
132
107
 
133
- # Internal model used to parse streaming open position updates.
134
- class OpenPositionUpdate < Model
135
- attribute :channel
136
- attribute :deal_id
137
- attribute :deal_id_origin
138
- attribute :deal_reference
139
- attribute :deal_status, Symbol, allowed_values: [:accepted, :rejected]
140
- attribute :direction, Symbol, allowed_values: [:buy, :sell]
141
- attribute :epic, String, regex: Regex::EPIC
142
- attribute :expiry, Date, nil_if: %w(- DFB), format: ['%d-%b-%y', '%b-%y']
143
- attribute :guaranteed_stop, Boolean
144
- attribute :level, Float
145
- attribute :limit_level, Float
146
- attribute :size, Float
147
- attribute :status, Symbol, allowed_values: [:deleted, :open, :updated]
148
- attribute :stop_level, Float
149
- attribute :timestamp, Time, format: '%FT%T.%L'
150
- end
108
+ def redraw_account_state(account_state, window)
109
+ account_state.process_queued_data
151
110
 
152
- # Internal model used to parse streaming working order updates.
153
- class WorkingOrderUpdate < Model
154
- attribute :channel
155
- attribute :deal_id
156
- attribute :deal_reference
157
- attribute :deal_status, Symbol, allowed_values: [:accepted, :rejected]
158
- attribute :direction, Symbol, allowed_values: [:buy, :sell]
159
- attribute :epic, String, regex: Regex::EPIC
160
- attribute :expiry, Date, nil_if: %w(- DFB), format: ['%d-%b-%y', '%b-%y']
161
- attribute :guaranteed_stop, Boolean
162
- attribute :level, Float
163
- attribute :limit_distance, Fixnum
164
- attribute :size, Float
165
- attribute :status, Symbol, allowed_values: [:deleted, :open, :updated]
166
- attribute :stop_distance, Fixnum
167
- attribute :timestamp, Time, format: '%FT%T.%L'
111
+ window.clear
112
+ window.print_lines AccountsTable.new(account_state.accounts).lines, '',
113
+ PositionsTable.new(account_state.positions, aggregate: options[:aggregate]).lines, '',
114
+ WorkingOrdersTable.new(account_state.working_orders).lines, ''
115
+ window.refresh
168
116
  end
169
117
  end
170
118
  end