ig_markets 0.19 → 0.20

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: 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