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 +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +25 -3
- data/lib/ig_markets.rb +16 -1
- data/lib/ig_markets/cli/commands/self_test_command.rb +78 -59
- data/lib/ig_markets/cli/commands/stream_command.rb +69 -121
- data/lib/ig_markets/cli/curses_window.rb +96 -0
- data/lib/ig_markets/cli/main.rb +3 -0
- data/lib/ig_markets/cli/tables/table.rb +7 -0
- data/lib/ig_markets/deal_confirmation.rb +2 -1
- data/lib/ig_markets/dealing_platform.rb +20 -13
- data/lib/ig_markets/dealing_platform/streaming_methods.rb +173 -0
- data/lib/ig_markets/model/typecasters.rb +1 -0
- data/lib/ig_markets/position.rb +1 -0
- data/lib/ig_markets/streaming/account_state.rb +190 -0
- data/lib/ig_markets/streaming/account_update.rb +20 -0
- data/lib/ig_markets/streaming/chart_tick_update.rb +19 -0
- data/lib/ig_markets/streaming/consolidated_chart_data_update.rb +32 -0
- data/lib/ig_markets/streaming/market_subscription_manager.rb +86 -0
- data/lib/ig_markets/streaming/market_update.rb +21 -0
- data/lib/ig_markets/streaming/position_update.rb +23 -0
- data/lib/ig_markets/streaming/subscription.rb +122 -0
- data/lib/ig_markets/streaming/working_order_update.rb +23 -0
- data/lib/ig_markets/version.rb +1 -1
- data/lib/ig_markets/watchlist.rb +1 -1
- metadata +29 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0873a06d085af3287d3497f41a7157710216995
|
4
|
+
data.tar.gz: 4606f5cc0084f0092ab1f53361ae3c2ff11f4804
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
156
|
-
ig_markets stream
|
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
|
-
|
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
|
20
|
-
test_markets
|
21
|
-
test_positions
|
22
|
-
test_sprint_market_positions
|
23
|
-
test_working_orders
|
24
|
-
test_watchlists
|
25
|
-
test_client_sentiment
|
26
|
-
test_account_methods
|
27
|
-
test_applications
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
dealing_platform.markets.
|
33
|
-
@
|
34
|
-
@
|
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
|
39
|
-
test_position_create
|
40
|
+
def test_positions
|
41
|
+
test_position_create
|
40
42
|
test_position_update
|
41
|
-
test_position_close
|
43
|
+
test_position_close
|
42
44
|
end
|
43
45
|
|
44
|
-
def test_position_create
|
45
|
-
deal_reference = dealing_platform.positions.create currency_code: 'USD', direction: :buy,
|
46
|
-
|
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
|
-
|
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
|
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
|
71
|
-
|
72
|
-
|
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
|
-
|
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
|
83
|
-
test_working_order_create
|
84
|
-
test_working_order_update
|
85
|
-
test_working_order_delete
|
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
|
89
|
-
deal_reference = dealing_platform.working_orders.create currency_code: 'USD', direction: :buy,
|
90
|
-
|
91
|
-
|
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
|
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
|
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
|
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
|
127
|
-
dealing_platform.
|
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
|
133
|
-
|
134
|
-
client_sentiment.related_sentiments
|
138
|
+
def test_applications
|
139
|
+
@dealing_platform.applications
|
135
140
|
end
|
136
141
|
|
137
|
-
def
|
138
|
-
dealing_platform.
|
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
|
5
|
-
desc '
|
4
|
+
class Stream < Thor
|
5
|
+
desc 'dashboard', 'Displays an updating live display of account balances, positions and working orders'
|
6
6
|
|
7
|
-
option :
|
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
|
12
|
-
|
13
|
-
|
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
|
-
|
16
|
+
account_state = Streaming::AccountState.new dealing_platform
|
17
|
+
account_state.start
|
16
18
|
|
17
|
-
|
19
|
+
redraw_account_state account_state, window until @error
|
20
|
+
|
21
|
+
raise @error
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
21
|
-
|
25
|
+
default_task :dashboard
|
22
26
|
|
23
|
-
|
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
|
-
|
27
|
-
|
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
|
30
|
-
|
34
|
+
def raw
|
35
|
+
Main.begin_session(options) do |dealing_platform|
|
36
|
+
@dealing_platform = dealing_platform
|
37
|
+
@queue = Queue.new
|
31
38
|
|
32
|
-
|
33
|
-
|
34
|
-
|
39
|
+
@dealing_platform.streaming.on_error(&method(:on_error))
|
40
|
+
@dealing_platform.streaming.connect
|
41
|
+
start_raw_subscriptions
|
35
42
|
|
36
|
-
|
37
|
-
|
43
|
+
main_loop
|
44
|
+
end
|
38
45
|
end
|
39
46
|
|
40
|
-
|
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
|
-
|
49
|
+
def start_raw_subscriptions
|
50
|
+
subscriptions = [accounts_subscription, markets_subscription, trades_subscription,
|
51
|
+
chart_ticks_subscription].compact
|
47
52
|
|
48
|
-
|
49
|
-
|
53
|
+
subscriptions.each do |subscription|
|
54
|
+
subscription.on_data(&method(:on_data))
|
50
55
|
end
|
51
56
|
|
52
|
-
|
57
|
+
@dealing_platform.streaming.start_subscriptions subscriptions, snapshot: true
|
53
58
|
end
|
54
59
|
|
55
|
-
def
|
56
|
-
|
57
|
-
fields = [:bid, :offer, :high, :low, :mid_open, :strike_price, :odds]
|
60
|
+
def accounts_subscription
|
61
|
+
return unless options[:accounts]
|
58
62
|
|
59
|
-
|
63
|
+
@dealing_platform.streaming.build_accounts_subscription
|
64
|
+
end
|
60
65
|
|
61
|
-
|
62
|
-
|
63
|
-
end
|
66
|
+
def markets_subscription
|
67
|
+
return unless options[:markets]
|
64
68
|
|
65
|
-
|
69
|
+
@dealing_platform.streaming.build_markets_subscription options[:markets]
|
66
70
|
end
|
67
71
|
|
68
|
-
def
|
72
|
+
def trades_subscription
|
69
73
|
return unless options[:trades]
|
70
74
|
|
71
|
-
|
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
|
86
|
-
return unless
|
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
|
-
|
81
|
+
@dealing_platform.streaming.build_chart_ticks_subscription options[:chart_ticks]
|
82
|
+
end
|
91
83
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
-
|
90
|
+
summary = data.attributes.keys.sort.map { |key| "#{key}: #{data.send key}" if data.send key }
|
99
91
|
|
100
|
-
@queue.push
|
92
|
+
@queue.push "#{data.class.name.split('::').last} - #{summary.compact.join ', '}"
|
101
93
|
end
|
102
94
|
|
103
|
-
def
|
104
|
-
|
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
|
119
|
-
|
99
|
+
def main_loop
|
100
|
+
loop do
|
101
|
+
data = @queue.pop
|
102
|
+
raise data if data.is_a? Lightstreamer::LightstreamerError
|
120
103
|
|
121
|
-
|
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
|
-
|
134
|
-
|
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
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
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
|