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