@quantform/core 0.3.254 → 0.3.255

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.
Files changed (50) hide show
  1. package/dist/adapter/backtester/backtester-cursor.spec.js.map +1 -1
  2. package/dist/adapter/backtester/backtester-streamer.spec.js.map +1 -1
  3. package/dist/store/event/store-balance.event.d.ts +5 -6
  4. package/dist/store/event/store-balance.event.js +8 -8
  5. package/dist/store/event/store-balance.event.js.map +1 -1
  6. package/dist/store/event/store-candle.event.d.ts +2 -1
  7. package/dist/store/event/store-candle.event.js +25 -19
  8. package/dist/store/event/store-candle.event.js.map +1 -1
  9. package/dist/store/event/store-candle.event.spec.js +7 -8
  10. package/dist/store/event/store-candle.event.spec.js.map +1 -1
  11. package/dist/store/event/store-instrument.event.d.ts +6 -6
  12. package/dist/store/event/store-instrument.event.js +7 -7
  13. package/dist/store/event/store-instrument.event.js.map +1 -1
  14. package/dist/store/event/store-order.event.d.ts +9 -9
  15. package/dist/store/event/store-order.event.js +16 -16
  16. package/dist/store/event/store-order.event.js.map +1 -1
  17. package/dist/store/event/store-order.event.spec.js +7 -7
  18. package/dist/store/event/store-order.event.spec.js.map +1 -1
  19. package/dist/store/event/store-orderbook.event.d.ts +2 -3
  20. package/dist/store/event/store-orderbook.event.js +2 -2
  21. package/dist/store/event/store-orderbook.event.js.map +1 -1
  22. package/dist/store/event/store-position.event.d.ts +3 -3
  23. package/dist/store/event/store-position.event.js +6 -5
  24. package/dist/store/event/store-position.event.js.map +1 -1
  25. package/dist/store/event/store-trade.event.d.ts +2 -3
  26. package/dist/store/event/store-trade.event.js +2 -2
  27. package/dist/store/event/store-trade.event.js.map +1 -1
  28. package/dist/store/event/store-trade.event.spec.js +16 -17
  29. package/dist/store/event/store-trade.event.spec.js.map +1 -1
  30. package/dist/store/store.d.ts +23 -20
  31. package/dist/store/store.js +29 -28
  32. package/dist/store/store.js.map +1 -1
  33. package/dist/store/store.state.d.ts +5 -1
  34. package/dist/store/store.state.js.map +1 -1
  35. package/dist/tsconfig.tsbuildinfo +1 -1
  36. package/package.json +1 -1
  37. package/src/adapter/backtester/backtester-cursor.spec.ts +2 -2
  38. package/src/adapter/backtester/backtester-streamer.spec.ts +0 -1
  39. package/src/store/event/store-balance.event.ts +25 -9
  40. package/src/store/event/store-candle.event.spec.ts +8 -10
  41. package/src/store/event/store-candle.event.ts +44 -30
  42. package/src/store/event/store-instrument.event.ts +12 -7
  43. package/src/store/event/store-order.event.spec.ts +8 -8
  44. package/src/store/event/store-order.event.ts +46 -17
  45. package/src/store/event/store-orderbook.event.ts +7 -3
  46. package/src/store/event/store-position.event.ts +15 -7
  47. package/src/store/event/store-trade.event.spec.ts +18 -20
  48. package/src/store/event/store-trade.event.ts +7 -3
  49. package/src/store/store.state.ts +8 -2
  50. package/src/store/store.ts +33 -31
@@ -1,7 +1,7 @@
1
1
  import { Asset, Instrument } from '../../domain';
2
- import { CandleEvent, CandleEventHandler } from '.';
3
- import { State } from '../store.state';
2
+ import { CandleEvent } from '.';
4
3
  import { now } from '../../shared';
4
+ import { Store } from '../store';
5
5
 
6
6
  const instrument = new Instrument(
7
7
  new Asset('btc', 'binance', 8),
@@ -12,21 +12,19 @@ const instrument = new Instrument(
12
12
  describe('candle patch event tests', () => {
13
13
  test('should patch trade object', () => {
14
14
  const timestamp = now();
15
- const state = new State();
15
+ const store = new Store();
16
16
 
17
- state.universe.instrument[instrument.toString()] = instrument;
18
- state.subscription.instrument[instrument.toString()] = instrument;
17
+ store.snapshot.universe.instrument[instrument.toString()] = instrument;
18
+ store.snapshot.subscription.instrument[instrument.toString()] = instrument;
19
19
 
20
- const event = new CandleEvent(instrument, 1, 1, 1, 1, 1, 1, timestamp);
20
+ store.dispatch(new CandleEvent(instrument, 1, 1, 1, 1, 1, 1, timestamp));
21
21
 
22
- CandleEventHandler(event, state);
23
-
24
- const trade = state.trade[instrument.toString()];
22
+ const trade = store.snapshot.trade[instrument.toString()];
25
23
 
26
24
  expect(trade.timestamp).toEqual(timestamp);
27
25
  expect(trade.instrument.toString()).toEqual(instrument.toString());
28
26
  expect(trade.rate).toEqual(1);
29
27
  expect(trade.quantity).toEqual(1);
30
- expect(state.timestamp).toEqual(timestamp);
28
+ expect(store.snapshot.timestamp).toEqual(timestamp);
31
29
  });
32
30
  });
@@ -5,6 +5,7 @@ import { InstrumentSelector } from '../../domain';
5
5
  import { State } from '../store.state';
6
6
  import { StoreEvent } from './store.event';
7
7
  import { event } from '../../shared/topic';
8
+ import { StateChangeTracker } from '..';
8
9
 
9
10
  @event
10
11
  export class CandleEvent implements StoreEvent {
@@ -22,36 +23,49 @@ export class CandleEvent implements StoreEvent {
22
23
  ) {}
23
24
  }
24
25
 
25
- export function CandleEventHandler(event: CandleEvent, state: State) {
26
+ export function CandleEventHandler(
27
+ event: CandleEvent,
28
+ state: State,
29
+ changes: StateChangeTracker
30
+ ) {
26
31
  const instrument = state.universe.instrument[event.instrument.toString()];
27
32
 
28
- // patch trade object
29
- const trade = TradePatchEventHandler(
30
- {
31
- type: 'trade-patch',
32
- instrument: event.instrument,
33
- quantity: event.volume,
34
- rate: event.close,
35
- timestamp: event.timestamp
36
- },
37
- state
38
- );
39
-
40
- // patch orderbook by assuming candle close price is mid orderbook price
41
- const orderbook = OrderbookPatchEventHandler(
42
- {
43
- type: 'orderbook-patch',
44
- instrument: event.instrument,
45
- bestAskQuantity: event.volume * 0.5,
46
- bestAskRate: event.close + instrument.quote.tickSize,
47
- bestBidQuantity: event.volume * 0.5,
48
- bestBidRate: event.close - instrument.quote.tickSize,
49
- timestamp: event.timestamp
50
- },
51
- state
52
- );
53
-
54
- state.timestamp = event.timestamp;
55
-
56
- return [trade, orderbook];
33
+ const patch = (timestamp: number, rate: number) => {
34
+ // patch trade object
35
+ TradePatchEventHandler(
36
+ {
37
+ type: 'trade-patch',
38
+ instrument: event.instrument,
39
+ quantity: event.volume,
40
+ rate,
41
+ timestamp
42
+ },
43
+ state,
44
+ changes
45
+ );
46
+
47
+ // patch orderbook by assuming candle close price is mid orderbook price
48
+ OrderbookPatchEventHandler(
49
+ {
50
+ type: 'orderbook-patch',
51
+ instrument: event.instrument,
52
+ bestAskQuantity: instrument.base.fixed(event.volume * 0.5),
53
+ bestAskRate: rate,
54
+ bestBidQuantity: instrument.base.fixed(event.volume * 0.5),
55
+ bestBidRate: rate,
56
+ timestamp
57
+ },
58
+ state,
59
+ changes
60
+ );
61
+
62
+ state.timestamp = event.timestamp;
63
+
64
+ changes.commitPendingChanges();
65
+ };
66
+
67
+ patch(event.timestamp, instrument.quote.fixed(event.open));
68
+ patch(event.timestamp, instrument.quote.fixed(event.high));
69
+ patch(event.timestamp, instrument.quote.fixed(event.low));
70
+ patch(event.timestamp, instrument.quote.fixed(event.close));
57
71
  }
@@ -2,7 +2,7 @@ import { event } from '../../shared/topic';
2
2
  import { timestamp } from '../../shared';
3
3
  import { Asset, Commission } from '../../domain';
4
4
  import { Instrument, InstrumentSelector } from '../../domain/instrument';
5
- import { State } from '../../store';
5
+ import { State, StateChangeTracker } from '../../store';
6
6
  import { StoreEvent } from './store.event';
7
7
 
8
8
  @event
@@ -13,13 +13,17 @@ export class InstrumentPatchEvent implements StoreEvent {
13
13
  readonly timestamp: timestamp,
14
14
  readonly base: Asset,
15
15
  readonly quote: Asset,
16
- readonly commision: Commission,
16
+ readonly commission: Commission,
17
17
  readonly raw: string,
18
18
  readonly leverage?: number
19
19
  ) {}
20
20
  }
21
21
 
22
- export function InstrumentPatchEventHandler(event: InstrumentPatchEvent, state: State) {
22
+ export function InstrumentPatchEventHandler(
23
+ event: InstrumentPatchEvent,
24
+ state: State,
25
+ changes: StateChangeTracker
26
+ ) {
23
27
  const selector = new InstrumentSelector(
24
28
  event.base.name,
25
29
  event.quote.name,
@@ -37,13 +41,13 @@ export function InstrumentPatchEventHandler(event: InstrumentPatchEvent, state:
37
41
  }
38
42
 
39
43
  instrument.timestamp = event.timestamp;
40
- instrument.commission = event.commision;
44
+ instrument.commission = event.commission;
41
45
 
42
46
  if (event.leverage) {
43
47
  instrument.leverage = event.leverage;
44
48
  }
45
49
 
46
- return instrument;
50
+ changes.commit(instrument);
47
51
  }
48
52
 
49
53
  @event
@@ -59,7 +63,8 @@ export class InstrumentSubscriptionEvent implements StoreEvent {
59
63
 
60
64
  export function InstrumentSubscriptionEventHandler(
61
65
  event: InstrumentSubscriptionEvent,
62
- state: State
66
+ state: State,
67
+ changes: StateChangeTracker
63
68
  ) {
64
69
  const instrumentKey = event.instrument.toString();
65
70
 
@@ -75,5 +80,5 @@ export function InstrumentSubscriptionEventHandler(
75
80
  state.subscription.asset[instrument.quote.toString()] = instrument.quote;
76
81
  }
77
82
 
78
- return instrument;
83
+ changes.commit(instrument);
79
84
  }
@@ -1,7 +1,7 @@
1
- import { State } from '../';
2
1
  import { now } from '../../shared';
3
2
  import { Asset, Instrument, Order } from '../../domain';
4
- import { OrderLoadEvent, OrderLoadEventHandler } from './store-order.event';
3
+ import { OrderLoadEvent } from './store-order.event';
4
+ import { Store } from '../store';
5
5
 
6
6
  const instrument = new Instrument(
7
7
  new Asset('btc', 'binance', 8),
@@ -12,17 +12,17 @@ const instrument = new Instrument(
12
12
  describe('order load event tests', () => {
13
13
  test('should load order to store', () => {
14
14
  const timestamp = now();
15
- const state = new State();
15
+ const store = new Store();
16
16
  const order = Order.buyMarket(instrument, 1.0);
17
17
 
18
18
  order.state = 'PENDING';
19
19
 
20
- state.universe.instrument[instrument.toString()] = instrument;
21
- state.subscription.instrument[instrument.toString()] = instrument;
20
+ store.snapshot.universe.instrument[instrument.toString()] = instrument;
21
+ store.snapshot.subscription.instrument[instrument.toString()] = instrument;
22
22
 
23
- OrderLoadEventHandler(new OrderLoadEvent(order, timestamp), state);
23
+ store.dispatch(new OrderLoadEvent(order, timestamp));
24
24
 
25
- expect(Object.keys(state.order.pending).length).toEqual(1);
26
- expect(state.order.pending[order.id]).toEqual(order);
25
+ expect(Object.keys(store.snapshot.order.pending).length).toEqual(1);
26
+ expect(store.snapshot.order.pending[order.id]).toEqual(order);
27
27
  });
28
28
  });
@@ -1,7 +1,7 @@
1
1
  import { event } from '../../shared/topic';
2
2
  import { timestamp } from '../../shared';
3
3
  import { Order } from '../../domain';
4
- import { State } from '../store.state';
4
+ import { State, StateChangeTracker } from '../store.state';
5
5
  import { StoreEvent } from './store.event';
6
6
 
7
7
  @event
@@ -11,7 +11,11 @@ export class OrderLoadEvent implements StoreEvent {
11
11
  constructor(readonly order: Order, readonly timestamp: timestamp) {}
12
12
  }
13
13
 
14
- export function OrderLoadEventHandler(event: OrderLoadEvent, state: State) {
14
+ export function OrderLoadEventHandler(
15
+ event: OrderLoadEvent,
16
+ state: State,
17
+ changes: StateChangeTracker
18
+ ) {
15
19
  event.order.timestamp = event.timestamp;
16
20
 
17
21
  switch (event.order.state) {
@@ -31,7 +35,7 @@ export function OrderLoadEventHandler(event: OrderLoadEvent, state: State) {
31
35
  break;
32
36
  }
33
37
 
34
- return event.order;
38
+ changes.commit(event.order);
35
39
  }
36
40
 
37
41
  @event
@@ -41,7 +45,11 @@ export class OrderNewEvent implements StoreEvent {
41
45
  constructor(readonly order: Order, readonly timestamp: timestamp) {}
42
46
  }
43
47
 
44
- export function OrderNewEventHandler(event: OrderNewEvent, state: State) {
48
+ export function OrderNewEventHandler(
49
+ event: OrderNewEvent,
50
+ state: State,
51
+ changes: StateChangeTracker
52
+ ) {
45
53
  if (event.order.state != 'NEW') {
46
54
  throw new Error(`Order is not new`);
47
55
  }
@@ -51,7 +59,7 @@ export function OrderNewEventHandler(event: OrderNewEvent, state: State) {
51
59
 
52
60
  state.order.pending[event.order.id] = event.order;
53
61
 
54
- return event.order;
62
+ changes.commit(event.order);
55
63
  }
56
64
 
57
65
  @event
@@ -61,7 +69,11 @@ export class OrderPendingEvent implements StoreEvent {
61
69
  constructor(readonly id: string, readonly timestamp: timestamp) {}
62
70
  }
63
71
 
64
- export function OrderPendingEventHandler(event: OrderPendingEvent, state: State) {
72
+ export function OrderPendingEventHandler(
73
+ event: OrderPendingEvent,
74
+ state: State,
75
+ changes: StateChangeTracker
76
+ ) {
65
77
  if (!(event.id in state.order.pending)) {
66
78
  throw new Error(`Trying to patch unknown order: ${event.id}`);
67
79
  }
@@ -75,7 +87,7 @@ export function OrderPendingEventHandler(event: OrderPendingEvent, state: State)
75
87
  order.state = 'PENDING';
76
88
  order.timestamp = event.timestamp;
77
89
 
78
- return order;
90
+ changes.commit(order);
79
91
  }
80
92
 
81
93
  @event
@@ -89,7 +101,11 @@ export class OrderFilledEvent implements StoreEvent {
89
101
  ) {}
90
102
  }
91
103
 
92
- export function OrderFilledEventHandler(event: OrderFilledEvent, state: State) {
104
+ export function OrderFilledEventHandler(
105
+ event: OrderFilledEvent,
106
+ state: State,
107
+ changes: StateChangeTracker
108
+ ) {
93
109
  if (!(event.id in state.order.pending)) {
94
110
  throw new Error(`Trying to patch unknown order: ${event.id}`);
95
111
  }
@@ -109,7 +125,7 @@ export function OrderFilledEventHandler(event: OrderFilledEvent, state: State) {
109
125
 
110
126
  state.order.filled[event.id] = order;
111
127
 
112
- return order;
128
+ changes.commit(order);
113
129
  }
114
130
 
115
131
  @event
@@ -119,7 +135,11 @@ export class OrderCancelingEvent implements StoreEvent {
119
135
  constructor(readonly id: string, readonly timestamp: timestamp) {}
120
136
  }
121
137
 
122
- export function OrderCancelingEventHandler(event: OrderCancelingEvent, state: State) {
138
+ export function OrderCancelingEventHandler(
139
+ event: OrderCancelingEvent,
140
+ state: State,
141
+ changes: StateChangeTracker
142
+ ) {
123
143
  if (!(event.id in state.order.pending)) {
124
144
  throw new Error(`Trying to patch unknown order: ${event.id}`);
125
145
  }
@@ -137,7 +157,7 @@ export function OrderCancelingEventHandler(event: OrderCancelingEvent, state: St
137
157
  order.state = 'CANCELING';
138
158
  order.timestamp = event.timestamp;
139
159
 
140
- return order;
160
+ changes.commit(order);
141
161
  }
142
162
 
143
163
  @event
@@ -147,7 +167,11 @@ export class OrderCanceledEvent implements StoreEvent {
147
167
  constructor(readonly id: string, readonly timestamp: timestamp) {}
148
168
  }
149
169
 
150
- export function OrderCanceledEventHandler(event: OrderCanceledEvent, state: State) {
170
+ export function OrderCanceledEventHandler(
171
+ event: OrderCanceledEvent,
172
+ state: State,
173
+ changes: StateChangeTracker
174
+ ) {
151
175
  const order = state.order.pending[event.id];
152
176
 
153
177
  if (order.state == 'CANCELED') {
@@ -165,7 +189,7 @@ export function OrderCanceledEventHandler(event: OrderCanceledEvent, state: Stat
165
189
 
166
190
  state.order.canceled[event.id] = order;
167
191
 
168
- return order;
192
+ changes.commit(order);
169
193
  }
170
194
 
171
195
  @event
@@ -177,7 +201,8 @@ export class OrderCancelFailedEvent implements StoreEvent {
177
201
 
178
202
  export function OrderCancelFailedEventHandler(
179
203
  event: OrderCancelFailedEvent,
180
- state: State
204
+ state: State,
205
+ changes: StateChangeTracker
181
206
  ) {
182
207
  const order = state.order.pending[event.id];
183
208
 
@@ -188,7 +213,7 @@ export function OrderCancelFailedEventHandler(
188
213
  order.state = 'PENDING';
189
214
  order.timestamp = event.timestamp;
190
215
 
191
- return order;
216
+ changes.commit(order);
192
217
  }
193
218
 
194
219
  @event
@@ -198,7 +223,11 @@ export class OrderRejectedEvent implements StoreEvent {
198
223
  constructor(readonly id: string, readonly timestamp: timestamp) {}
199
224
  }
200
225
 
201
- export function OrderRejectedEventHandler(event: OrderRejectedEvent, state: State) {
226
+ export function OrderRejectedEventHandler(
227
+ event: OrderRejectedEvent,
228
+ state: State,
229
+ changes: StateChangeTracker
230
+ ) {
202
231
  const order = state.order.pending[event.id];
203
232
 
204
233
  if (order.state != 'NEW') {
@@ -212,5 +241,5 @@ export function OrderRejectedEventHandler(event: OrderRejectedEvent, state: Stat
212
241
 
213
242
  state.order.rejected[event.id] = order;
214
243
 
215
- return order;
244
+ changes.commit(order);
216
245
  }
@@ -2,7 +2,7 @@ import { event } from '../../shared/topic';
2
2
  import { timestamp } from '../../shared';
3
3
  import { InstrumentSelector } from '../../domain/instrument';
4
4
  import { Orderbook } from '../../domain/orderbook';
5
- import { State } from '../store.state';
5
+ import { State, StateChangeTracker } from '../store.state';
6
6
  import { StoreEvent } from './store.event';
7
7
 
8
8
  @event
@@ -19,7 +19,11 @@ export class OrderbookPatchEvent implements StoreEvent {
19
19
  ) {}
20
20
  }
21
21
 
22
- export function OrderbookPatchEventHandler(event: OrderbookPatchEvent, state: State) {
22
+ export function OrderbookPatchEventHandler(
23
+ event: OrderbookPatchEvent,
24
+ state: State,
25
+ changes: StateChangeTracker
26
+ ) {
23
27
  const instrumentKey = event.instrument.toString();
24
28
 
25
29
  if (!(instrumentKey in state.subscription.instrument)) {
@@ -62,5 +66,5 @@ export function OrderbookPatchEventHandler(event: OrderbookPatchEvent, state: St
62
66
  }
63
67
  }
64
68
 
65
- return orderbook;
69
+ changes.commit(orderbook);
66
70
  }
@@ -1,7 +1,7 @@
1
1
  import { event } from '../../shared/topic';
2
2
  import { timestamp } from '../../shared';
3
3
  import { Position, Instrument, PositionMode } from '../../domain';
4
- import { State } from '../store.state';
4
+ import { State, StateChangeTracker } from '../store.state';
5
5
  import { StoreEvent } from './store.event';
6
6
 
7
7
  @event
@@ -11,7 +11,11 @@ export class PositionLoadEvent implements StoreEvent {
11
11
  constructor(readonly position: Position, readonly timestamp: timestamp) {}
12
12
  }
13
13
 
14
- export function PositionLoadEventHandler(event: PositionLoadEvent, state: State) {
14
+ export function PositionLoadEventHandler(
15
+ event: PositionLoadEvent,
16
+ state: State,
17
+ changes: StateChangeTracker
18
+ ) {
15
19
  if (
16
20
  event.position.instrument.toString()! in state.subscription.instrument ||
17
21
  event.position.size == 0
@@ -50,7 +54,11 @@ export class PositionPatchEvent implements StoreEvent {
50
54
  ) {}
51
55
  }
52
56
 
53
- export function PositionPatchEventHandler(event: PositionPatchEvent, state: State) {
57
+ export function PositionPatchEventHandler(
58
+ event: PositionPatchEvent,
59
+ state: State,
60
+ changes: StateChangeTracker
61
+ ) {
54
62
  if (!(event.instrument.toString() in state.subscription.instrument)) {
55
63
  return;
56
64
  }
@@ -74,10 +82,9 @@ export function PositionPatchEventHandler(event: PositionPatchEvent, state: Stat
74
82
  position.calculatePnL(rate);
75
83
  }
76
84
 
77
- return [position, balance];
85
+ changes.commit(position);
86
+ changes.commit(balance);
78
87
  }
79
-
80
- return;
81
88
  }
82
89
 
83
90
  if (!position) {
@@ -97,5 +104,6 @@ export function PositionPatchEventHandler(event: PositionPatchEvent, state: Stat
97
104
  position.calculatePnL(rate);
98
105
  }
99
106
 
100
- return [position, balance];
107
+ changes.commit(position);
108
+ changes.commit(balance);
101
109
  }
@@ -1,7 +1,7 @@
1
1
  import { Asset, Instrument } from '../../domain';
2
- import { TradePatchEvent, TradePatchEventHandler } from '.';
3
- import { State } from '../store.state';
2
+ import { TradePatchEvent } from '.';
4
3
  import { now } from '../../shared';
4
+ import { Store } from '..';
5
5
 
6
6
  const instrument = new Instrument(
7
7
  new Asset('btc', 'binance', 8),
@@ -12,49 +12,47 @@ const instrument = new Instrument(
12
12
  describe('trade patch event tests', () => {
13
13
  test('should create a new trade object and patch a store', () => {
14
14
  const timestamp = now();
15
- const state = new State();
15
+ const store = new Store();
16
16
 
17
- state.universe.instrument[instrument.toString()] = instrument;
18
- state.subscription.instrument[instrument.toString()] = instrument;
17
+ store.snapshot.universe.instrument[instrument.toString()] = instrument;
18
+ store.snapshot.subscription.instrument[instrument.toString()] = instrument;
19
19
 
20
- const event = new TradePatchEvent(instrument, 1000, 0.1, timestamp);
20
+ store.dispatch(new TradePatchEvent(instrument, 1000, 0.1, timestamp));
21
21
 
22
- TradePatchEventHandler(event, state);
23
-
24
- const trade = state.trade[instrument.toString()];
22
+ const trade = store.snapshot.trade[instrument.toString()];
25
23
 
26
24
  expect(trade.timestamp).toEqual(timestamp);
27
25
  expect(trade.instrument.toString()).toEqual(trade.instrument.toString());
28
26
  expect(trade.rate).toEqual(1000);
29
27
  expect(trade.quantity).toEqual(0.1);
30
- expect(state.timestamp).toEqual(timestamp);
28
+ expect(store.snapshot.timestamp).toEqual(timestamp);
31
29
  });
32
30
 
33
31
  test('should use the existing instance of trade when patching a store', () => {
34
- const state = new State();
32
+ const store = new Store();
35
33
 
36
- state.universe.instrument[instrument.toString()] = instrument;
37
- state.subscription.instrument[instrument.toString()] = instrument;
34
+ store.snapshot.universe.instrument[instrument.toString()] = instrument;
35
+ store.snapshot.subscription.instrument[instrument.toString()] = instrument;
38
36
 
39
- TradePatchEventHandler(new TradePatchEvent(instrument, 1000, 0.1, now()), state);
37
+ store.dispatch(new TradePatchEvent(instrument, 1000, 0.1, now()));
40
38
 
41
39
  const timestamp = now();
42
- const trade = state.trade[instrument.toString()];
40
+ const trade = store.snapshot.trade[instrument.toString()];
43
41
 
44
- TradePatchEventHandler(new TradePatchEvent(instrument, 2000, 0.2, timestamp), state);
42
+ store.dispatch(new TradePatchEvent(instrument, 2000, 0.2, now()));
45
43
 
46
44
  expect(trade.timestamp).toEqual(timestamp);
47
45
  expect(trade.instrument.toString()).toEqual(instrument.toString());
48
46
  expect(trade.rate).toEqual(2000);
49
47
  expect(trade.quantity).toEqual(0.2);
50
- expect(state.timestamp).toEqual(timestamp);
48
+ expect(store.snapshot.timestamp).toEqual(timestamp);
51
49
  });
52
50
 
53
51
  test('should throw exception when patching unsubscribed instrument', () => {
54
- const fn = () => {
55
- const event = new TradePatchEvent(instrument, 1000, 0.1, now());
52
+ const store = new Store();
56
53
 
57
- TradePatchEventHandler(event, new State());
54
+ const fn = () => {
55
+ store.dispatch(new TradePatchEvent(instrument, 1000, 0.1, now()));
58
56
  };
59
57
 
60
58
  expect(fn).toThrow(Error);
@@ -2,7 +2,7 @@ import { event } from '../../shared/topic';
2
2
  import { timestamp } from '../../shared';
3
3
  import { Trade } from '../../domain';
4
4
  import { InstrumentSelector } from '../../domain/instrument';
5
- import { State } from '../store.state';
5
+ import { State, StateChangeTracker } from '../store.state';
6
6
  import { StoreEvent } from './store.event';
7
7
 
8
8
  /**
@@ -24,7 +24,11 @@ export class TradePatchEvent implements StoreEvent {
24
24
  * Patches a store with specific event @see TradePatchEvent
25
25
  * If there is no specific @see Trade in store, it will create a new one.
26
26
  */
27
- export function TradePatchEventHandler(event: TradePatchEvent, state: State) {
27
+ export function TradePatchEventHandler(
28
+ event: TradePatchEvent,
29
+ state: State,
30
+ changes: StateChangeTracker
31
+ ) {
28
32
  const instrumentKey = event.instrument.toString();
29
33
 
30
34
  if (!(instrumentKey in state.subscription.instrument)) {
@@ -44,5 +48,5 @@ export function TradePatchEventHandler(event: TradePatchEvent, state: State) {
44
48
  trade.rate = trade.instrument.quote.fixed(event.rate);
45
49
  trade.quantity = trade.instrument.base.fixed(event.quantity);
46
50
 
47
- return trade;
51
+ changes.commit(trade);
48
52
  }
@@ -7,13 +7,19 @@ import {
7
7
  Asset,
8
8
  Trade,
9
9
  AssetSelector,
10
- InstrumentSelector
10
+ InstrumentSelector,
11
+ Component
11
12
  } from '../domain';
12
13
 
14
+ export interface StateChangeTracker {
15
+ commit(component: Component);
16
+ commitPendingChanges();
17
+ }
18
+
13
19
  export class State {
14
20
  timestamp: timestamp;
15
21
 
16
- // all available trasing assets and instruments
22
+ // available trading assets and instruments
17
23
  universe: {
18
24
  asset: Record<string, Asset>;
19
25
  instrument: Record<string, Instrument>;