@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.
- package/README.md +1 -1
- package/dist/adapter/backtester/backtester-cursor.spec.js.map +1 -1
- package/dist/adapter/backtester/backtester-streamer.spec.js.map +1 -1
- package/dist/session/session.d.ts +6 -9
- package/dist/session/session.js +10 -24
- package/dist/session/session.js.map +1 -1
- package/dist/store/event/store-balance.event.d.ts +5 -6
- package/dist/store/event/store-balance.event.js +8 -8
- package/dist/store/event/store-balance.event.js.map +1 -1
- package/dist/store/event/store-candle.event.d.ts +2 -1
- package/dist/store/event/store-candle.event.js +25 -19
- package/dist/store/event/store-candle.event.js.map +1 -1
- package/dist/store/event/store-candle.event.spec.js +7 -8
- package/dist/store/event/store-candle.event.spec.js.map +1 -1
- package/dist/store/event/store-instrument.event.d.ts +6 -6
- package/dist/store/event/store-instrument.event.js +7 -7
- package/dist/store/event/store-instrument.event.js.map +1 -1
- package/dist/store/event/store-order.event.d.ts +9 -9
- package/dist/store/event/store-order.event.js +26 -47
- package/dist/store/event/store-order.event.js.map +1 -1
- package/dist/store/event/store-order.event.spec.js +7 -7
- package/dist/store/event/store-order.event.spec.js.map +1 -1
- package/dist/store/event/store-orderbook.event.d.ts +2 -3
- package/dist/store/event/store-orderbook.event.js +2 -2
- package/dist/store/event/store-orderbook.event.js.map +1 -1
- package/dist/store/event/store-position.event.d.ts +3 -3
- package/dist/store/event/store-position.event.js +6 -5
- package/dist/store/event/store-position.event.js.map +1 -1
- package/dist/store/event/store-trade.event.d.ts +2 -3
- package/dist/store/event/store-trade.event.js +2 -2
- package/dist/store/event/store-trade.event.js.map +1 -1
- package/dist/store/event/store-trade.event.spec.js +16 -17
- package/dist/store/event/store-trade.event.spec.js.map +1 -1
- package/dist/store/store.d.ts +23 -20
- package/dist/store/store.js +29 -28
- package/dist/store/store.js.map +1 -1
- package/dist/store/store.state.d.ts +6 -7
- package/dist/store/store.state.js +1 -6
- package/dist/store/store.state.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/adapter/backtester/backtester-cursor.spec.ts +2 -2
- package/src/adapter/backtester/backtester-streamer.spec.ts +0 -1
- package/src/session/session.ts +21 -56
- package/src/store/event/store-balance.event.ts +25 -9
- package/src/store/event/store-candle.event.spec.ts +8 -10
- package/src/store/event/store-candle.event.ts +44 -30
- package/src/store/event/store-instrument.event.ts +12 -7
- package/src/store/event/store-order.event.spec.ts +8 -8
- package/src/store/event/store-order.event.ts +56 -54
- package/src/store/event/store-orderbook.event.ts +7 -3
- package/src/store/event/store-position.event.ts +15 -7
- package/src/store/event/store-trade.event.spec.ts +18 -20
- package/src/store/event/store-trade.event.ts +7 -3
- package/src/store/store.state.ts +9 -14
- package/src/store/store.ts +33 -31
package/src/session/session.ts
CHANGED
|
@@ -191,14 +191,12 @@ export class Session {
|
|
|
191
191
|
/**
|
|
192
192
|
* Subscribes to trade/ticker changes.
|
|
193
193
|
*/
|
|
194
|
-
trade(selector
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
284
|
-
(states.
|
|
271
|
+
it.instrument.toString() == selector.toString() &&
|
|
272
|
+
(!states || states.includes(it.state))
|
|
285
273
|
),
|
|
286
|
-
map(() =>
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
160
|
+
changes.commit(balance);
|
|
145
161
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Asset, Instrument } from '../../domain';
|
|
2
|
-
import { CandleEvent
|
|
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
|
|
15
|
+
const store = new Store();
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
store.snapshot.universe.instrument[instrument.toString()] = instrument;
|
|
18
|
+
store.snapshot.subscription.instrument[instrument.toString()] = instrument;
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
store.dispatch(new CandleEvent(instrument, 1, 1, 1, 1, 1, 1, timestamp));
|
|
21
21
|
|
|
22
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
|
16
|
+
readonly commission: Commission,
|
|
17
17
|
readonly raw: string,
|
|
18
18
|
readonly leverage?: number
|
|
19
19
|
) {}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export function InstrumentPatchEventHandler(
|
|
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.
|
|
44
|
+
instrument.commission = event.commission;
|
|
41
45
|
|
|
42
46
|
if (event.leverage) {
|
|
43
47
|
instrument.leverage = event.leverage;
|
|
44
48
|
}
|
|
45
49
|
|
|
46
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
15
|
+
const store = new Store();
|
|
16
16
|
const order = Order.buyMarket(instrument, 1.0);
|
|
17
17
|
|
|
18
18
|
order.state = 'PENDING';
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
store.snapshot.universe.instrument[instrument.toString()] = instrument;
|
|
21
|
+
store.snapshot.subscription.instrument[instrument.toString()] = instrument;
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
store.dispatch(new OrderLoadEvent(order, timestamp));
|
|
24
24
|
|
|
25
|
-
expect(Object.keys(
|
|
26
|
-
expect(
|
|
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(
|
|
14
|
+
export function OrderLoadEventHandler(
|
|
15
|
+
event: OrderLoadEvent,
|
|
16
|
+
state: State,
|
|
17
|
+
changes: StateChangeTracker
|
|
18
|
+
) {
|
|
15
19
|
event.order.timestamp = event.timestamp;
|
|
16
20
|
|
|
17
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
45
|
+
state.order[event.order.id] = event.order;
|
|
53
46
|
|
|
54
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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(
|
|
93
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
123
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
151
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
202
|
-
|
|
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
|
-
|
|
212
|
-
|
|
213
|
-
state.order.rejected[event.id] = order;
|
|
214
|
-
|
|
215
|
-
return order;
|
|
217
|
+
changes.commit(order);
|
|
216
218
|
}
|