@quantform/core 0.3.254 → 0.3.259

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 (56) hide show
  1. package/README.md +1 -1
  2. package/dist/adapter/backtester/backtester-cursor.spec.js.map +1 -1
  3. package/dist/adapter/backtester/backtester-streamer.spec.js.map +1 -1
  4. package/dist/session/session.d.ts +6 -9
  5. package/dist/session/session.js +10 -24
  6. package/dist/session/session.js.map +1 -1
  7. package/dist/store/event/store-balance.event.d.ts +5 -6
  8. package/dist/store/event/store-balance.event.js +8 -8
  9. package/dist/store/event/store-balance.event.js.map +1 -1
  10. package/dist/store/event/store-candle.event.d.ts +2 -1
  11. package/dist/store/event/store-candle.event.js +25 -19
  12. package/dist/store/event/store-candle.event.js.map +1 -1
  13. package/dist/store/event/store-candle.event.spec.js +7 -8
  14. package/dist/store/event/store-candle.event.spec.js.map +1 -1
  15. package/dist/store/event/store-instrument.event.d.ts +6 -6
  16. package/dist/store/event/store-instrument.event.js +7 -7
  17. package/dist/store/event/store-instrument.event.js.map +1 -1
  18. package/dist/store/event/store-order.event.d.ts +9 -9
  19. package/dist/store/event/store-order.event.js +26 -47
  20. package/dist/store/event/store-order.event.js.map +1 -1
  21. package/dist/store/event/store-order.event.spec.js +7 -7
  22. package/dist/store/event/store-order.event.spec.js.map +1 -1
  23. package/dist/store/event/store-orderbook.event.d.ts +2 -3
  24. package/dist/store/event/store-orderbook.event.js +2 -2
  25. package/dist/store/event/store-orderbook.event.js.map +1 -1
  26. package/dist/store/event/store-position.event.d.ts +3 -3
  27. package/dist/store/event/store-position.event.js +6 -5
  28. package/dist/store/event/store-position.event.js.map +1 -1
  29. package/dist/store/event/store-trade.event.d.ts +2 -3
  30. package/dist/store/event/store-trade.event.js +2 -2
  31. package/dist/store/event/store-trade.event.js.map +1 -1
  32. package/dist/store/event/store-trade.event.spec.js +16 -17
  33. package/dist/store/event/store-trade.event.spec.js.map +1 -1
  34. package/dist/store/store.d.ts +23 -20
  35. package/dist/store/store.js +29 -28
  36. package/dist/store/store.js.map +1 -1
  37. package/dist/store/store.state.d.ts +6 -7
  38. package/dist/store/store.state.js +1 -6
  39. package/dist/store/store.state.js.map +1 -1
  40. package/dist/tsconfig.tsbuildinfo +1 -1
  41. package/package.json +1 -1
  42. package/src/adapter/backtester/backtester-cursor.spec.ts +2 -2
  43. package/src/adapter/backtester/backtester-streamer.spec.ts +0 -1
  44. package/src/session/session.ts +21 -56
  45. package/src/store/event/store-balance.event.ts +25 -9
  46. package/src/store/event/store-candle.event.spec.ts +8 -10
  47. package/src/store/event/store-candle.event.ts +44 -30
  48. package/src/store/event/store-instrument.event.ts +12 -7
  49. package/src/store/event/store-order.event.spec.ts +8 -8
  50. package/src/store/event/store-order.event.ts +56 -54
  51. package/src/store/event/store-orderbook.event.ts +7 -3
  52. package/src/store/event/store-position.event.ts +15 -7
  53. package/src/store/event/store-trade.event.spec.ts +18 -20
  54. package/src/store/event/store-trade.event.ts +7 -3
  55. package/src/store/store.state.ts +9 -14
  56. package/src/store/store.ts +33 -31
@@ -191,14 +191,12 @@ export class Session {
191
191
  /**
192
192
  * Subscribes to trade/ticker changes.
193
193
  */
194
- trade(selector?: InstrumentSelector): Observable<Trade> {
194
+ trade(selector: InstrumentSelector): Observable<Trade> {
195
195
  this.subscribe([selector]);
196
196
 
197
197
  return this.store.changes$.pipe(
198
198
  filter(
199
- it =>
200
- it instanceof Trade &&
201
- (!selector || it.instrument.toString() == selector.toString())
199
+ it => it instanceof Trade && it.instrument.toString() == selector.toString()
202
200
  ),
203
201
  map(it => it as Trade)
204
202
  );
@@ -208,14 +206,12 @@ export class Session {
208
206
  * Subscribes to orderbook changes.
209
207
  * Right now you can access only best bid and best ask.
210
208
  */
211
- orderbook(selector?: InstrumentSelector): Observable<Orderbook> {
209
+ orderbook(selector: InstrumentSelector): Observable<Orderbook> {
212
210
  this.subscribe([selector]);
213
211
 
214
212
  return this.store.changes$.pipe(
215
213
  filter(
216
- it =>
217
- it instanceof Orderbook &&
218
- (!selector || it.instrument.toString() == selector.toString())
214
+ it => it instanceof Orderbook && it.instrument.toString() == selector.toString()
219
215
  ),
220
216
  map(it => it as Orderbook)
221
217
  );
@@ -224,14 +220,12 @@ export class Session {
224
220
  /**
225
221
  * Subscribes to position on leveraged market.
226
222
  */
227
- position(selector?: InstrumentSelector): Observable<Position> {
223
+ position(selector: InstrumentSelector): Observable<Position> {
228
224
  this.subscribe([selector]);
229
225
 
230
226
  return this.store.changes$.pipe(
231
227
  filter(
232
- it =>
233
- it instanceof Position &&
234
- (!selector || it.instrument.toString() == selector.toString())
228
+ it => it instanceof Position && it.instrument.toString() == selector.toString()
235
229
  ),
236
230
  map(it => it as Position)
237
231
  );
@@ -256,73 +250,44 @@ export class Session {
256
250
  );
257
251
  }
258
252
 
259
- order(selector?: InstrumentSelector): Observable<Order> {
253
+ order(selector: InstrumentSelector): Observable<Order> {
260
254
  this.subscribe([selector]);
261
255
 
262
256
  return this.store.changes$.pipe(
263
257
  filter(
264
- it =>
265
- it instanceof Order &&
266
- (!selector || it.instrument.toString() == selector.toString())
258
+ it => it instanceof Order && it.instrument.toString() == selector.toString()
267
259
  ),
268
260
  map(it => it as Order)
269
261
  );
270
262
  }
271
263
 
272
- private ordersOf(
273
- orders: Order[],
274
- states: OrderState[],
275
- selector?: InstrumentSelector
276
- ): Observable<Order[]> {
264
+ orders(selector: InstrumentSelector, states?: OrderState[]): Observable<Order[]> {
277
265
  this.subscribe([selector]);
278
266
 
279
267
  return this.store.changes$.pipe(
280
268
  filter(
281
269
  it =>
282
270
  it instanceof Order &&
283
- (!selector || it.instrument.toString() == selector.toString()) &&
284
- (states.indexOf(it.state) >= 0 || states.length == 0)
271
+ it.instrument.toString() == selector.toString() &&
272
+ (!states || states.includes(it.state))
285
273
  ),
286
- map(() =>
287
- Object.values(orders)
288
- .filter(it => !selector || it.instrument.toString() == selector.toString())
289
- .sort((lhs, rhs) => rhs.createdAt - lhs.createdAt)
290
- ),
291
- startWith(
292
- Object.values(orders)
293
- .filter(it => !selector || it.instrument.toString() == selector.toString())
274
+ map(() => this.store.snapshot.order),
275
+ startWith(this.store.snapshot.order),
276
+ map(it =>
277
+ Object.values(it)
278
+ .filter(
279
+ it =>
280
+ it.instrument.toString() == selector.toString() &&
281
+ (states ? states.includes(it.state) : true)
282
+ )
294
283
  .sort((lhs, rhs) => rhs.createdAt - lhs.createdAt)
295
284
  )
296
285
  );
297
286
  }
298
287
 
299
- pending(selector?: InstrumentSelector): Observable<Order[]> {
300
- return this.ordersOf(
301
- Object.values(this.store.snapshot.order.pending),
302
- ['PENDING', 'NEW'],
303
- selector
304
- );
305
- }
306
-
307
- filled(selector?: InstrumentSelector): Observable<Order[]> {
308
- return this.ordersOf(
309
- Object.values(this.store.snapshot.order.filled),
310
- ['FILLED'],
311
- selector
312
- );
313
- }
314
-
315
- canceled(selector?: InstrumentSelector): Observable<Order[]> {
316
- return this.ordersOf(
317
- Object.values(this.store.snapshot.order.canceled),
318
- ['CANCELING', 'CANCELED'],
319
- selector
320
- );
321
- }
322
-
323
288
  balance(selector: AssetSelector): Observable<Balance> {
324
289
  return this.store.changes$.pipe(
325
- startWith(selector ? this.store.snapshot.balance[selector.toString()] : null),
290
+ startWith(this.store.snapshot.balance[selector.toString()]),
326
291
  filter(
327
292
  it =>
328
293
  it instanceof Balance &&
@@ -2,7 +2,7 @@ import { event } from '../../shared/topic';
2
2
  import { timestamp } from '../../shared';
3
3
  import { AssetSelector } from '../../domain/asset';
4
4
  import { Balance } from '../../domain/balance';
5
- import { State } from '../store.state';
5
+ import { State, StateChangeTracker } from '../store.state';
6
6
  import { StoreEvent } from './store.event';
7
7
 
8
8
  /**
@@ -23,7 +23,11 @@ export class BalancePatchEvent implements StoreEvent {
23
23
  /**
24
24
  * @see BalancePatchEvent
25
25
  */
26
- export function BalancePatchEventHandler(event: BalancePatchEvent, state: State) {
26
+ export function BalancePatchEventHandler(
27
+ event: BalancePatchEvent,
28
+ state: State,
29
+ changes: StateChangeTracker
30
+ ) {
27
31
  let balance = state.balance[event.asset.toString()];
28
32
 
29
33
  if (!balance) {
@@ -41,7 +45,7 @@ export function BalancePatchEventHandler(event: BalancePatchEvent, state: State)
41
45
 
42
46
  state.timestamp = event.timestamp;
43
47
 
44
- return balance;
48
+ changes.commit(balance);
45
49
  }
46
50
 
47
51
  /**
@@ -61,7 +65,11 @@ export class BalanceTransactEvent implements StoreEvent {
61
65
  /**
62
66
  * @see BalanceTransactEvent
63
67
  */
64
- export function BalanceTransactEventHandler(event: BalanceTransactEvent, state: State) {
68
+ export function BalanceTransactEventHandler(
69
+ event: BalanceTransactEvent,
70
+ state: State,
71
+ changes: StateChangeTracker
72
+ ) {
65
73
  let balance = state.balance[event.asset.toString()];
66
74
 
67
75
  if (!balance) {
@@ -77,7 +85,7 @@ export function BalanceTransactEventHandler(event: BalanceTransactEvent, state:
77
85
 
78
86
  state.timestamp = event.timestamp;
79
87
 
80
- return balance;
88
+ changes.commit(balance);
81
89
  }
82
90
 
83
91
  /**
@@ -97,7 +105,11 @@ export class BalanceFreezEvent implements StoreEvent {
97
105
  /**
98
106
  * @see BalanceFreezEvent
99
107
  */
100
- export function BalanceFreezEventHandler(event: BalanceFreezEvent, state: State) {
108
+ export function BalanceFreezEventHandler(
109
+ event: BalanceFreezEvent,
110
+ state: State,
111
+ changes: StateChangeTracker
112
+ ) {
101
113
  const balance = state.balance[event.asset.toString()];
102
114
 
103
115
  if (!balance) {
@@ -109,7 +121,7 @@ export function BalanceFreezEventHandler(event: BalanceFreezEvent, state: State)
109
121
 
110
122
  state.timestamp = event.timestamp;
111
123
 
112
- return balance;
124
+ changes.commit(balance);
113
125
  }
114
126
 
115
127
  /**
@@ -129,7 +141,11 @@ export class BalanceUnfreezEvent implements StoreEvent {
129
141
  /**
130
142
  * @see BalanceUnfreezEvent
131
143
  */
132
- export function BalanceUnfreezEventHandler(event: BalanceUnfreezEvent, state: State) {
144
+ export function BalanceUnfreezEventHandler(
145
+ event: BalanceUnfreezEvent,
146
+ state: State,
147
+ changes: StateChangeTracker
148
+ ) {
133
149
  const balance = state.balance[event.asset.toString()];
134
150
 
135
151
  if (!balance) {
@@ -141,5 +157,5 @@ export function BalanceUnfreezEventHandler(event: BalanceUnfreezEvent, state: St
141
157
 
142
158
  state.timestamp = event.timestamp;
143
159
 
144
- return balance;
160
+ changes.commit(balance);
145
161
  }
@@ -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).length).toEqual(1);
26
+ expect(store.snapshot.order[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,27 +11,16 @@ 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
- switch (event.order.state) {
18
- case 'NEW':
19
- case 'PENDING':
20
- state.order.pending[event.order.id] = event.order;
21
- break;
22
- case 'FILLED':
23
- state.order.filled[event.order.id] = event.order;
24
- break;
25
- case 'CANCELING':
26
- case 'CANCELED':
27
- state.order.canceled[event.order.id] = event.order;
28
- break;
29
- case 'REJECTED':
30
- state.order.rejected[event.order.id] = event.order;
31
- break;
32
- }
21
+ state.order[event.order.id] = event.order;
33
22
 
34
- return event.order;
23
+ changes.commit(event.order);
35
24
  }
36
25
 
37
26
  @event
@@ -41,7 +30,11 @@ export class OrderNewEvent implements StoreEvent {
41
30
  constructor(readonly order: Order, readonly timestamp: timestamp) {}
42
31
  }
43
32
 
44
- export function OrderNewEventHandler(event: OrderNewEvent, state: State) {
33
+ export function OrderNewEventHandler(
34
+ event: OrderNewEvent,
35
+ state: State,
36
+ changes: StateChangeTracker
37
+ ) {
45
38
  if (event.order.state != 'NEW') {
46
39
  throw new Error(`Order is not new`);
47
40
  }
@@ -49,9 +42,9 @@ export function OrderNewEventHandler(event: OrderNewEvent, state: State) {
49
42
  event.order.createdAt = event.timestamp;
50
43
  event.order.timestamp = event.timestamp;
51
44
 
52
- state.order.pending[event.order.id] = event.order;
45
+ state.order[event.order.id] = event.order;
53
46
 
54
- return event.order;
47
+ changes.commit(event.order);
55
48
  }
56
49
 
57
50
  @event
@@ -61,12 +54,16 @@ export class OrderPendingEvent implements StoreEvent {
61
54
  constructor(readonly id: string, readonly timestamp: timestamp) {}
62
55
  }
63
56
 
64
- export function OrderPendingEventHandler(event: OrderPendingEvent, state: State) {
57
+ export function OrderPendingEventHandler(
58
+ event: OrderPendingEvent,
59
+ state: State,
60
+ changes: StateChangeTracker
61
+ ) {
65
62
  if (!(event.id in state.order.pending)) {
66
63
  throw new Error(`Trying to patch unknown order: ${event.id}`);
67
64
  }
68
65
 
69
- const order = state.order.pending[event.id];
66
+ const order = state.order[event.id];
70
67
 
71
68
  if (order.state != 'NEW') {
72
69
  throw new Error(`Order is not new`);
@@ -75,7 +72,7 @@ export function OrderPendingEventHandler(event: OrderPendingEvent, state: State)
75
72
  order.state = 'PENDING';
76
73
  order.timestamp = event.timestamp;
77
74
 
78
- return order;
75
+ changes.commit(order);
79
76
  }
80
77
 
81
78
  @event
@@ -89,12 +86,16 @@ export class OrderFilledEvent implements StoreEvent {
89
86
  ) {}
90
87
  }
91
88
 
92
- export function OrderFilledEventHandler(event: OrderFilledEvent, state: State) {
93
- if (!(event.id in state.order.pending)) {
89
+ export function OrderFilledEventHandler(
90
+ event: OrderFilledEvent,
91
+ state: State,
92
+ changes: StateChangeTracker
93
+ ) {
94
+ if (!(event.id in state.order)) {
94
95
  throw new Error(`Trying to patch unknown order: ${event.id}`);
95
96
  }
96
97
 
97
- const order = state.order.pending[event.id];
98
+ const order = state.order[event.id];
98
99
 
99
100
  if (order.state != 'PENDING' && order.state != 'CANCELING') {
100
101
  throw new Error('Order is not pending');
@@ -105,11 +106,7 @@ export function OrderFilledEventHandler(event: OrderFilledEvent, state: State) {
105
106
  order.quantityExecuted = order.quantity;
106
107
  order.averageExecutionRate = event.averageExecutionRate;
107
108
 
108
- delete state.order.pending[event.id];
109
-
110
- state.order.filled[event.id] = order;
111
-
112
- return order;
109
+ changes.commit(order);
113
110
  }
114
111
 
115
112
  @event
@@ -119,12 +116,16 @@ export class OrderCancelingEvent implements StoreEvent {
119
116
  constructor(readonly id: string, readonly timestamp: timestamp) {}
120
117
  }
121
118
 
122
- export function OrderCancelingEventHandler(event: OrderCancelingEvent, state: State) {
123
- if (!(event.id in state.order.pending)) {
119
+ export function OrderCancelingEventHandler(
120
+ event: OrderCancelingEvent,
121
+ state: State,
122
+ changes: StateChangeTracker
123
+ ) {
124
+ if (!(event.id in state.order)) {
124
125
  throw new Error(`Trying to patch unknown order: ${event.id}`);
125
126
  }
126
127
 
127
- const order = state.order.pending[event.id];
128
+ const order = state.order[event.id];
128
129
 
129
130
  if (order.state == 'CANCELING' || order.state == 'CANCELED') {
130
131
  return;
@@ -137,7 +138,7 @@ export function OrderCancelingEventHandler(event: OrderCancelingEvent, state: St
137
138
  order.state = 'CANCELING';
138
139
  order.timestamp = event.timestamp;
139
140
 
140
- return order;
141
+ changes.commit(order);
141
142
  }
142
143
 
143
144
  @event
@@ -147,8 +148,12 @@ export class OrderCanceledEvent implements StoreEvent {
147
148
  constructor(readonly id: string, readonly timestamp: timestamp) {}
148
149
  }
149
150
 
150
- export function OrderCanceledEventHandler(event: OrderCanceledEvent, state: State) {
151
- const order = state.order.pending[event.id];
151
+ export function OrderCanceledEventHandler(
152
+ event: OrderCanceledEvent,
153
+ state: State,
154
+ changes: StateChangeTracker
155
+ ) {
156
+ const order = state.order[event.id];
152
157
 
153
158
  if (order.state == 'CANCELED') {
154
159
  return;
@@ -161,11 +166,7 @@ export function OrderCanceledEventHandler(event: OrderCanceledEvent, state: Stat
161
166
  order.state = 'CANCELED';
162
167
  order.timestamp = event.timestamp;
163
168
 
164
- delete state.order.pending[event.id];
165
-
166
- state.order.canceled[event.id] = order;
167
-
168
- return order;
169
+ changes.commit(order);
169
170
  }
170
171
 
171
172
  @event
@@ -177,9 +178,10 @@ export class OrderCancelFailedEvent implements StoreEvent {
177
178
 
178
179
  export function OrderCancelFailedEventHandler(
179
180
  event: OrderCancelFailedEvent,
180
- state: State
181
+ state: State,
182
+ changes: StateChangeTracker
181
183
  ) {
182
- const order = state.order.pending[event.id];
184
+ const order = state.order[event.id];
183
185
 
184
186
  if (order.state != 'CANCELING') {
185
187
  return;
@@ -188,7 +190,7 @@ export function OrderCancelFailedEventHandler(
188
190
  order.state = 'PENDING';
189
191
  order.timestamp = event.timestamp;
190
192
 
191
- return order;
193
+ changes.commit(order);
192
194
  }
193
195
 
194
196
  @event
@@ -198,8 +200,12 @@ export class OrderRejectedEvent implements StoreEvent {
198
200
  constructor(readonly id: string, readonly timestamp: timestamp) {}
199
201
  }
200
202
 
201
- export function OrderRejectedEventHandler(event: OrderRejectedEvent, state: State) {
202
- const order = state.order.pending[event.id];
203
+ export function OrderRejectedEventHandler(
204
+ event: OrderRejectedEvent,
205
+ state: State,
206
+ changes: StateChangeTracker
207
+ ) {
208
+ const order = state.order[event.id];
203
209
 
204
210
  if (order.state != 'NEW') {
205
211
  throw new Error('Order is not new.');
@@ -208,9 +214,5 @@ export function OrderRejectedEventHandler(event: OrderRejectedEvent, state: Stat
208
214
  order.state = 'REJECTED';
209
215
  order.timestamp = event.timestamp;
210
216
 
211
- delete state.order.pending[event.id];
212
-
213
- state.order.rejected[event.id] = order;
214
-
215
- return order;
217
+ changes.commit(order);
216
218
  }