@quantform/core 0.3.251 → 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.
- package/dist/adapter/backtester/backtester-cursor.spec.js.map +1 -1
- package/dist/adapter/backtester/backtester-streamer.js +3 -0
- package/dist/adapter/backtester/backtester-streamer.js.map +1 -1
- package/dist/bootstrap.d.ts +11 -0
- package/dist/bootstrap.js +58 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/ipc.js +21 -37
- package/dist/ipc.js.map +1 -1
- package/dist/session/session.spec.js +2 -2
- package/dist/session/session.spec.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 +16 -16
- 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 +5 -1
- 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.ts +5 -1
- package/src/bootstrap.ts +103 -0
- package/src/index.ts +1 -1
- package/src/ipc.ts +22 -40
- package/src/session/session.spec.ts +2 -4
- 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 +46 -17
- 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 +8 -2
- package/src/store/store.ts +33 -31
- package/dist/bin.d.ts +0 -5
- package/dist/bin.js +0 -28
- package/dist/bin.js.map +0 -1
- package/src/bin.ts +0 -71
package/src/ipc.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Session, SessionDescriptor } from './session';
|
|
|
2
2
|
import { instrumentOf } from './domain';
|
|
3
3
|
import { Topic, event, handler } from './shared/topic';
|
|
4
4
|
import { runTask, Logger } from './shared';
|
|
5
|
-
import {
|
|
5
|
+
import { Bootstrap } from './bootstrap';
|
|
6
6
|
import { BacktesterStreamer } from './adapter/backtester';
|
|
7
7
|
import { Observable } from 'rxjs';
|
|
8
8
|
import { EventEmitter } from 'events';
|
|
@@ -116,7 +116,10 @@ export declare type IpcSessionDescriptor = SessionDescriptor & { ipcSub?: EventE
|
|
|
116
116
|
* Inter process communication handler.
|
|
117
117
|
*/
|
|
118
118
|
class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
119
|
-
constructor(
|
|
119
|
+
constructor(
|
|
120
|
+
private readonly bootstrap: Bootstrap,
|
|
121
|
+
private readonly ipcSub?: EventEmitter
|
|
122
|
+
) {
|
|
120
123
|
super();
|
|
121
124
|
}
|
|
122
125
|
|
|
@@ -125,11 +128,7 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
125
128
|
*/
|
|
126
129
|
@handler(IpcLiveCommand)
|
|
127
130
|
async onLiveMode(command: IpcLiveCommand, accessor: IpcSessionAccessor) {
|
|
128
|
-
|
|
129
|
-
this.descriptor.id = command.id;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
accessor.session = live(this.descriptor);
|
|
131
|
+
accessor.session = this.bootstrap.useSessionId(command.id).live();
|
|
133
132
|
|
|
134
133
|
this.emit({
|
|
135
134
|
type: 'live:started',
|
|
@@ -144,11 +143,7 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
144
143
|
*/
|
|
145
144
|
@handler(IpcPaperCommand)
|
|
146
145
|
async onPaperMode(command: IpcPaperCommand, accessor: IpcSessionAccessor) {
|
|
147
|
-
|
|
148
|
-
this.descriptor.id = command.id;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
accessor.session = paper(this.descriptor);
|
|
146
|
+
accessor.session = this.bootstrap.useSessionId(command.id).paper();
|
|
152
147
|
|
|
153
148
|
this.emit({
|
|
154
149
|
type: 'paper:started',
|
|
@@ -163,22 +158,18 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
163
158
|
*/
|
|
164
159
|
@handler(IpcBacktestCommand)
|
|
165
160
|
onBacktestMode(command: IpcBacktestCommand, accessor: IpcSessionAccessor) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
if (command.to) {
|
|
170
|
-
this.descriptor.options.backtester.to = command.to;
|
|
171
|
-
}
|
|
161
|
+
this.bootstrap.useBacktestPeriod(command.from, command.to).backtest();
|
|
162
|
+
const { from, to } = this.bootstrap.descriptor.options.backtester;
|
|
172
163
|
|
|
173
164
|
return new Promise<void>(async resolve => {
|
|
174
|
-
const [session, streamer] = backtest(
|
|
165
|
+
const [session, streamer] = this.bootstrap.backtest({
|
|
175
166
|
onBacktestStarted: (streamer: BacktesterStreamer) => {
|
|
176
167
|
this.emit({
|
|
177
168
|
type: 'backtest:started',
|
|
178
169
|
session: session.descriptor?.id,
|
|
179
170
|
timestamp: streamer.timestamp,
|
|
180
|
-
from
|
|
181
|
-
to
|
|
171
|
+
from,
|
|
172
|
+
to
|
|
182
173
|
});
|
|
183
174
|
},
|
|
184
175
|
onBacktestUpdated: (streamer: BacktesterStreamer) => {
|
|
@@ -186,8 +177,8 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
186
177
|
type: 'backtest:updated',
|
|
187
178
|
session: session.descriptor?.id,
|
|
188
179
|
timestamp: streamer.timestamp,
|
|
189
|
-
from
|
|
190
|
-
to
|
|
180
|
+
from,
|
|
181
|
+
to
|
|
191
182
|
});
|
|
192
183
|
},
|
|
193
184
|
onBacktestCompleted: async (streamer: BacktesterStreamer) => {
|
|
@@ -197,8 +188,8 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
197
188
|
type: 'backtest:completed',
|
|
198
189
|
session: session.descriptor?.id,
|
|
199
190
|
timestamp: streamer.timestamp,
|
|
200
|
-
from
|
|
201
|
-
to
|
|
191
|
+
from,
|
|
192
|
+
to
|
|
202
193
|
});
|
|
203
194
|
|
|
204
195
|
resolve();
|
|
@@ -217,18 +208,9 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
217
208
|
*/
|
|
218
209
|
@handler(IpcFeedCommand)
|
|
219
210
|
async onFeed(command: IpcFeedCommand, accessor: IpcSessionAccessor) {
|
|
220
|
-
|
|
221
|
-
this.descriptor.options = {};
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (!this.descriptor.options.paper) {
|
|
225
|
-
this.descriptor.options.paper = {
|
|
226
|
-
balance: {}
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
accessor.session = accessor.session ?? paper(this.descriptor);
|
|
211
|
+
accessor.session = accessor.session ?? this.bootstrap.paper();
|
|
231
212
|
const instrument = instrumentOf(command.instrument);
|
|
213
|
+
const { feed } = accessor.session.descriptor;
|
|
232
214
|
|
|
233
215
|
await accessor.session.awake(undefined);
|
|
234
216
|
|
|
@@ -238,7 +220,7 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
238
220
|
instrument,
|
|
239
221
|
command.from,
|
|
240
222
|
command.to,
|
|
241
|
-
|
|
223
|
+
feed,
|
|
242
224
|
timestamp =>
|
|
243
225
|
this.emit({
|
|
244
226
|
type: 'feed:updated',
|
|
@@ -258,7 +240,7 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
258
240
|
*/
|
|
259
241
|
@handler(IpcTaskCommand)
|
|
260
242
|
async onTask(query: IpcTaskCommand, accessor: IpcSessionAccessor) {
|
|
261
|
-
accessor.session = accessor.session ?? live(
|
|
243
|
+
accessor.session = accessor.session ?? this.bootstrap.live();
|
|
262
244
|
|
|
263
245
|
await accessor.session.awake(undefined);
|
|
264
246
|
|
|
@@ -296,7 +278,7 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
296
278
|
process.send(message);
|
|
297
279
|
}
|
|
298
280
|
|
|
299
|
-
this.
|
|
281
|
+
this.ipcSub?.emit('message', message);
|
|
300
282
|
}
|
|
301
283
|
}
|
|
302
284
|
|
|
@@ -310,7 +292,7 @@ export async function run(
|
|
|
310
292
|
descriptor: IpcSessionDescriptor,
|
|
311
293
|
...commands: IpcCommand[]
|
|
312
294
|
): Promise<Session> {
|
|
313
|
-
const handler = new IpcHandler(descriptor);
|
|
295
|
+
const handler = new IpcHandler(new Bootstrap(descriptor), descriptor.ipcSub);
|
|
314
296
|
const accessor = new IpcSessionAccessor();
|
|
315
297
|
const argv = minimist(process.argv.slice(2));
|
|
316
298
|
|
|
@@ -2,9 +2,7 @@ import { InstrumentPatchEvent } from '../store/event';
|
|
|
2
2
|
import { Asset, Commission } from '../domain';
|
|
3
3
|
import { now } from '../shared';
|
|
4
4
|
import { SessionDescriptor } from './session-descriptor';
|
|
5
|
-
import {
|
|
6
|
-
import { Session } from './session';
|
|
7
|
-
import { of } from 'rxjs';
|
|
5
|
+
import { Bootstrap } from '../bootstrap';
|
|
8
6
|
|
|
9
7
|
describe('session tests', () => {
|
|
10
8
|
const descriptor: SessionDescriptor = {
|
|
@@ -13,7 +11,7 @@ describe('session tests', () => {
|
|
|
13
11
|
};
|
|
14
12
|
|
|
15
13
|
test('should trigger once', done => {
|
|
16
|
-
const session =
|
|
14
|
+
const session = new Bootstrap(descriptor).paper();
|
|
17
15
|
|
|
18
16
|
session.instruments().subscribe({
|
|
19
17
|
next: it => {
|
|
@@ -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.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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
69
|
+
changes.commit(orderbook);
|
|
66
70
|
}
|