@quantform/core 0.3.238 → 0.3.243
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/adapter-aggregate.js +5 -5
- package/dist/adapter/adapter-aggregate.js.map +1 -1
- package/dist/adapter/paper/paper-adapter.js +2 -2
- package/dist/adapter/paper/paper-adapter.js.map +1 -1
- package/dist/bin.d.ts +0 -1
- package/dist/bin.js +1 -7
- package/dist/bin.js.map +1 -1
- package/dist/domain/asset.d.ts +3 -3
- package/dist/domain/asset.js +8 -8
- package/dist/domain/asset.js.map +1 -1
- package/dist/domain/asset.spec.js +4 -4
- package/dist/domain/asset.spec.js.map +1 -1
- package/dist/domain/instrument.d.ts +1 -1
- package/dist/domain/instrument.js +6 -6
- package/dist/domain/instrument.js.map +1 -1
- package/dist/domain/instrument.spec.js +7 -7
- package/dist/domain/instrument.spec.js.map +1 -1
- package/dist/domain/orderbook.d.ts +0 -1
- package/dist/ipc.d.ts +10 -5
- package/dist/ipc.js +40 -26
- package/dist/ipc.js.map +1 -1
- package/dist/ipc.spec.js +45 -1
- package/dist/ipc.spec.js.map +1 -1
- package/dist/session/session.d.ts +2 -2
- package/dist/session/session.js +9 -9
- package/dist/session/session.js.map +1 -1
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +1 -0
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/task.d.ts +6 -0
- package/dist/shared/task.js +25 -0
- package/dist/shared/task.js.map +1 -0
- package/dist/store/event/store-instrument.event.js +1 -1
- package/dist/store/event/store-instrument.event.js.map +1 -1
- package/dist/store/event/store-order.event.js +0 -8
- package/dist/store/event/store-order.event.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/src/adapter/adapter-aggregate.ts +5 -5
- package/src/adapter/paper/paper-adapter.ts +2 -2
- package/src/bin.ts +0 -11
- package/src/domain/asset.spec.ts +4 -4
- package/src/domain/asset.ts +9 -9
- package/src/domain/instrument.spec.ts +7 -7
- package/src/domain/instrument.ts +6 -6
- package/src/domain/orderbook.ts +1 -1
- package/src/ipc.spec.ts +59 -4
- package/src/ipc.ts +54 -24
- package/src/session/session.ts +10 -10
- package/src/shared/index.ts +1 -0
- package/src/shared/task.ts +30 -0
- package/src/store/event/store-instrument.event.ts +1 -1
- package/src/store/event/store-order.event.ts +0 -12
|
@@ -10,9 +10,9 @@ describe('instrument tests', () => {
|
|
|
10
10
|
);
|
|
11
11
|
|
|
12
12
|
expect(sut.base.name).toEqual('abc');
|
|
13
|
-
expect(sut.base.
|
|
13
|
+
expect(sut.base.adapter).toEqual('xyz');
|
|
14
14
|
expect(sut.quote.name).toEqual('def');
|
|
15
|
-
expect(sut.quote.
|
|
15
|
+
expect(sut.quote.adapter).toEqual('xyz');
|
|
16
16
|
expect(sut.toString()).toEqual('xyz:abc-def');
|
|
17
17
|
});
|
|
18
18
|
});
|
|
@@ -22,9 +22,9 @@ describe('instrument selector tests', () => {
|
|
|
22
22
|
const sut = instrumentOf('xyz:abc-def');
|
|
23
23
|
|
|
24
24
|
expect(sut.base.name).toEqual('abc');
|
|
25
|
-
expect(sut.base.
|
|
25
|
+
expect(sut.base.adapter).toEqual('xyz');
|
|
26
26
|
expect(sut.quote.name).toEqual('def');
|
|
27
|
-
expect(sut.quote.
|
|
27
|
+
expect(sut.quote.adapter).toEqual('xyz');
|
|
28
28
|
expect(sut.toString()).toEqual('xyz:abc-def');
|
|
29
29
|
});
|
|
30
30
|
|
|
@@ -32,9 +32,9 @@ describe('instrument selector tests', () => {
|
|
|
32
32
|
const sut = instrumentOf('XYZ:ABC-DEF');
|
|
33
33
|
|
|
34
34
|
expect(sut.base.name).toEqual('abc');
|
|
35
|
-
expect(sut.base.
|
|
35
|
+
expect(sut.base.adapter).toEqual('xyz');
|
|
36
36
|
expect(sut.quote.name).toEqual('def');
|
|
37
|
-
expect(sut.quote.
|
|
37
|
+
expect(sut.quote.adapter).toEqual('xyz');
|
|
38
38
|
expect(sut.toString()).toEqual('xyz:abc-def');
|
|
39
39
|
});
|
|
40
40
|
|
|
@@ -62,7 +62,7 @@ describe('instrument selector tests', () => {
|
|
|
62
62
|
expect(fn).toThrow(Error);
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
-
test('should throw invalid format message for missing
|
|
65
|
+
test('should throw invalid format message for missing adapter name', () => {
|
|
66
66
|
const fn = () => {
|
|
67
67
|
assetOf(':abc-def');
|
|
68
68
|
};
|
package/src/domain/instrument.ts
CHANGED
|
@@ -9,9 +9,9 @@ export class InstrumentSelector {
|
|
|
9
9
|
readonly base: AssetSelector;
|
|
10
10
|
readonly quote: AssetSelector;
|
|
11
11
|
|
|
12
|
-
constructor(base: string, quote: string,
|
|
13
|
-
this.base = new AssetSelector(base.toLowerCase(),
|
|
14
|
-
this.quote = new AssetSelector(quote.toLowerCase(),
|
|
12
|
+
constructor(base: string, quote: string, adapter: string) {
|
|
13
|
+
this.base = new AssetSelector(base.toLowerCase(), adapter.toLowerCase());
|
|
14
|
+
this.quote = new AssetSelector(quote.toLowerCase(), adapter.toLowerCase());
|
|
15
15
|
|
|
16
16
|
this.id = `${this.base.toString()}-${this.quote.name}`;
|
|
17
17
|
}
|
|
@@ -31,10 +31,10 @@ export class Instrument extends InstrumentSelector implements Component {
|
|
|
31
31
|
leverage?: number = null;
|
|
32
32
|
|
|
33
33
|
constructor(readonly base: Asset, readonly quote: Asset, readonly raw: string) {
|
|
34
|
-
super(base.name, quote.name, base.
|
|
34
|
+
super(base.name, quote.name, base.adapter);
|
|
35
35
|
|
|
36
|
-
if (base.
|
|
37
|
-
throw new Error('
|
|
36
|
+
if (base.adapter != quote.adapter) {
|
|
37
|
+
throw new Error('Adapter mismatch!');
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
}
|
package/src/domain/orderbook.ts
CHANGED
package/src/ipc.spec.ts
CHANGED
|
@@ -3,14 +3,18 @@ import {
|
|
|
3
3
|
Adapter,
|
|
4
4
|
AdapterFeedCommand,
|
|
5
5
|
AdapterAwakeCommand,
|
|
6
|
-
AdapterAccountCommand
|
|
6
|
+
AdapterAccountCommand,
|
|
7
|
+
AdapterSubscribeCommand,
|
|
8
|
+
AdapterDisposeCommand
|
|
7
9
|
} from './adapter';
|
|
8
10
|
import { PaperAdapter, PaperSpotExecutor } from './adapter/paper';
|
|
9
11
|
import { PaperExecutor } from './adapter/paper/executor/paper-executor';
|
|
10
|
-
import {
|
|
12
|
+
import { run } from './ipc';
|
|
11
13
|
import { Feed, InMemoryStorage } from './storage';
|
|
12
14
|
import { instrumentOf } from './domain';
|
|
13
|
-
import { handler } from './shared';
|
|
15
|
+
import { handler, task } from './shared';
|
|
16
|
+
import { EventEmitter } from 'events';
|
|
17
|
+
import { from, of, take, tap } from 'rxjs';
|
|
14
18
|
|
|
15
19
|
class DefaultAdapter extends Adapter {
|
|
16
20
|
name = 'default';
|
|
@@ -26,6 +30,12 @@ class DefaultAdapter extends Adapter {
|
|
|
26
30
|
@handler(AdapterAwakeCommand)
|
|
27
31
|
onAwake(command: AdapterAwakeCommand) {}
|
|
28
32
|
|
|
33
|
+
@handler(AdapterDisposeCommand)
|
|
34
|
+
onDispose(command: AdapterDisposeCommand) {}
|
|
35
|
+
|
|
36
|
+
@handler(AdapterSubscribeCommand)
|
|
37
|
+
onSubscribe(command: AdapterSubscribeCommand) {}
|
|
38
|
+
|
|
29
39
|
@handler(AdapterAccountCommand)
|
|
30
40
|
onAccount(command: AdapterAccountCommand) {}
|
|
31
41
|
|
|
@@ -51,6 +61,51 @@ describe('ipc feed tests', () => {
|
|
|
51
61
|
command
|
|
52
62
|
);
|
|
53
63
|
|
|
54
|
-
expect(session.descriptor).toBeUndefined();
|
|
64
|
+
//expect(session.descriptor).toBeUndefined();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('should dispatch session started event', done => {
|
|
68
|
+
const command = {
|
|
69
|
+
type: 'paper',
|
|
70
|
+
balance: { 'default:usd': 100 }
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const ipcSub = new EventEmitter();
|
|
74
|
+
|
|
75
|
+
ipcSub.on('message', (message: any) => {
|
|
76
|
+
expect(message.type).toBe('paper:started');
|
|
77
|
+
done();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
run(
|
|
81
|
+
{
|
|
82
|
+
adapter: [new DefaultAdapter()],
|
|
83
|
+
describe: (session: Session) => session.trade(instrumentOf('default:btc-usdt')),
|
|
84
|
+
ipcSub
|
|
85
|
+
},
|
|
86
|
+
command
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('should execute user task', done => {
|
|
91
|
+
task('hello-world', session => {
|
|
92
|
+
return of(1).pipe(
|
|
93
|
+
take(1),
|
|
94
|
+
tap(() => done())
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const command = {
|
|
99
|
+
type: 'task',
|
|
100
|
+
taskName: 'hello-world'
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
run(
|
|
104
|
+
{
|
|
105
|
+
adapter: [new DefaultAdapter()],
|
|
106
|
+
describe: (session: Session) => session.trade(instrumentOf('default:btc-usdt'))
|
|
107
|
+
},
|
|
108
|
+
command
|
|
109
|
+
);
|
|
55
110
|
});
|
|
56
111
|
});
|
package/src/ipc.ts
CHANGED
|
@@ -2,10 +2,15 @@ import { AdapterFeedCommand } from './adapter';
|
|
|
2
2
|
import { Session, SessionDescriptor } from './session';
|
|
3
3
|
import { instrumentOf } from './domain';
|
|
4
4
|
import { Topic, event, handler } from './shared/topic';
|
|
5
|
-
import { Logger } from './shared';
|
|
6
|
-
import { backtest,
|
|
5
|
+
import { runTask, Logger } from './shared';
|
|
6
|
+
import { backtest, live, paper } from './bin';
|
|
7
7
|
import { BacktesterStreamer } from './adapter/backtester';
|
|
8
|
+
import { EventEmitter } from 'events';
|
|
8
9
|
import minimist = require('minimist');
|
|
10
|
+
import dotenv = require('dotenv');
|
|
11
|
+
|
|
12
|
+
// force to load environment variables from .env file if this file imported.
|
|
13
|
+
dotenv.config();
|
|
9
14
|
|
|
10
15
|
/**
|
|
11
16
|
* Base command/query interface for IPC communication.
|
|
@@ -73,12 +78,6 @@ export class IpcBacktestCommand implements IpcCommand {
|
|
|
73
78
|
balance: { [key: string]: number };
|
|
74
79
|
}
|
|
75
80
|
|
|
76
|
-
@event
|
|
77
|
-
export class IpcUniverseQuery implements IpcCommand {
|
|
78
|
-
type = 'universe';
|
|
79
|
-
exchange: string;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
81
|
/**
|
|
83
82
|
* Feeds specific session descriptor with instrument data.
|
|
84
83
|
*/
|
|
@@ -102,6 +101,19 @@ export class IpcFeedCommand implements IpcCommand {
|
|
|
102
101
|
to: number;
|
|
103
102
|
}
|
|
104
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Executes user task defined in quantform.ts file.
|
|
106
|
+
*/
|
|
107
|
+
@event
|
|
108
|
+
export class IpcTaskCommand implements IpcCommand {
|
|
109
|
+
type = 'task';
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Name of the task to execute.
|
|
113
|
+
*/
|
|
114
|
+
taskName: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
105
117
|
/**
|
|
106
118
|
* Stores current session instance.
|
|
107
119
|
*/
|
|
@@ -109,11 +121,13 @@ class IpcSessionAccessor {
|
|
|
109
121
|
session: Session;
|
|
110
122
|
}
|
|
111
123
|
|
|
124
|
+
export declare type SessionRunDescriptor = SessionDescriptor & { ipcSub?: EventEmitter };
|
|
125
|
+
|
|
112
126
|
/**
|
|
113
127
|
* Inter process communication handler.
|
|
114
128
|
*/
|
|
115
129
|
class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
116
|
-
constructor(private readonly descriptor:
|
|
130
|
+
constructor(private readonly descriptor: SessionRunDescriptor) {
|
|
117
131
|
super();
|
|
118
132
|
}
|
|
119
133
|
|
|
@@ -209,28 +223,20 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
209
223
|
});
|
|
210
224
|
}
|
|
211
225
|
|
|
212
|
-
/**
|
|
213
|
-
* @see IpcUniverseQuery
|
|
214
|
-
*/
|
|
215
|
-
@handler(IpcUniverseQuery)
|
|
216
|
-
onUniverse(query: IpcUniverseQuery, accessor: IpcSessionAccessor) {
|
|
217
|
-
accessor.session = accessor.session ?? idle(this.descriptor);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
226
|
/**
|
|
221
227
|
* @see IpcFeedCommand
|
|
222
228
|
*/
|
|
223
229
|
@handler(IpcFeedCommand)
|
|
224
230
|
async onFeed(command: IpcFeedCommand, accessor: IpcSessionAccessor) {
|
|
225
|
-
accessor.session = accessor.session ??
|
|
231
|
+
accessor.session = accessor.session ?? live(this.descriptor);
|
|
226
232
|
const instrument = instrumentOf(command.instrument);
|
|
227
233
|
|
|
228
|
-
await accessor.session.awake();
|
|
234
|
+
await accessor.session.awake(true);
|
|
229
235
|
|
|
230
236
|
this.notify({ type: 'feed:started' });
|
|
231
237
|
|
|
232
238
|
await accessor.session.aggregate.dispatch(
|
|
233
|
-
instrument.base.
|
|
239
|
+
instrument.base.adapter,
|
|
234
240
|
new AdapterFeedCommand(
|
|
235
241
|
instrument,
|
|
236
242
|
command.from,
|
|
@@ -251,15 +257,39 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
251
257
|
await accessor.session.dispose();
|
|
252
258
|
}
|
|
253
259
|
|
|
260
|
+
/**
|
|
261
|
+
* @see IpcTaskCommand
|
|
262
|
+
*/
|
|
263
|
+
@handler(IpcTaskCommand)
|
|
264
|
+
async onTask(query: IpcTaskCommand, accessor: IpcSessionAccessor) {
|
|
265
|
+
accessor.session = accessor.session ?? live(this.descriptor);
|
|
266
|
+
|
|
267
|
+
await accessor.session.awake(true);
|
|
268
|
+
|
|
269
|
+
this.notify({ type: 'task:started', taskName: query.taskName });
|
|
270
|
+
|
|
271
|
+
let result = undefined;
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
result = await runTask(query.taskName, accessor.session);
|
|
275
|
+
} catch (e) {
|
|
276
|
+
result = e;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
this.notify({ type: 'task:completed', taskName: query.taskName, result });
|
|
280
|
+
|
|
281
|
+
await accessor.session.dispose();
|
|
282
|
+
}
|
|
283
|
+
|
|
254
284
|
/**
|
|
255
285
|
* Sends a message to parent process.
|
|
256
286
|
*/
|
|
257
287
|
private notify(message: any) {
|
|
258
|
-
if (
|
|
259
|
-
|
|
288
|
+
if (process.send) {
|
|
289
|
+
process.send(message);
|
|
260
290
|
}
|
|
261
291
|
|
|
262
|
-
|
|
292
|
+
this.descriptor.ipcSub?.emit('message', message);
|
|
263
293
|
}
|
|
264
294
|
}
|
|
265
295
|
|
|
@@ -270,7 +300,7 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
270
300
|
* @returns new session.
|
|
271
301
|
*/
|
|
272
302
|
export async function run(
|
|
273
|
-
descriptor:
|
|
303
|
+
descriptor: SessionRunDescriptor,
|
|
274
304
|
...commands: IpcCommand[]
|
|
275
305
|
): Promise<Session> {
|
|
276
306
|
const handler = new IpcHandler(descriptor);
|
package/src/session/session.ts
CHANGED
|
@@ -57,7 +57,7 @@ export class Session {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
async awake(): Promise<void> {
|
|
60
|
+
async awake(idle: boolean = false): Promise<void> {
|
|
61
61
|
if (this.initialized) {
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
@@ -67,7 +67,7 @@ export class Session {
|
|
|
67
67
|
// awake all adapters and synchronize trading accounts with store.
|
|
68
68
|
await this.aggregate.awake(this.descriptor != null);
|
|
69
69
|
|
|
70
|
-
if (this.descriptor?.describe) {
|
|
70
|
+
if (!idle && this.descriptor?.describe) {
|
|
71
71
|
this.subscription = this.descriptor.describe(this).subscribe();
|
|
72
72
|
}
|
|
73
73
|
}
|
|
@@ -151,12 +151,12 @@ export class Session {
|
|
|
151
151
|
const grouped = instrument
|
|
152
152
|
.filter(it => it != null)
|
|
153
153
|
.reduce((aggregate, it) => {
|
|
154
|
-
const
|
|
154
|
+
const adapter = it.base.adapter;
|
|
155
155
|
|
|
156
|
-
if (aggregate[
|
|
157
|
-
aggregate[
|
|
156
|
+
if (aggregate[adapter]) {
|
|
157
|
+
aggregate[adapter].push(it);
|
|
158
158
|
} else {
|
|
159
|
-
aggregate[
|
|
159
|
+
aggregate[adapter] = [it];
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
return aggregate;
|
|
@@ -176,7 +176,7 @@ export class Session {
|
|
|
176
176
|
await Promise.all(
|
|
177
177
|
orders.map(it =>
|
|
178
178
|
this.aggregate.dispatch<AdapterOrderOpenCommand, void>(
|
|
179
|
-
it.instrument.base.
|
|
179
|
+
it.instrument.base.adapter,
|
|
180
180
|
new AdapterOrderOpenCommand(it)
|
|
181
181
|
)
|
|
182
182
|
)
|
|
@@ -188,7 +188,7 @@ export class Session {
|
|
|
188
188
|
*/
|
|
189
189
|
cancel(order: Order): Promise<void> {
|
|
190
190
|
return this.aggregate.dispatch(
|
|
191
|
-
order.instrument.base.
|
|
191
|
+
order.instrument.base.adapter,
|
|
192
192
|
new AdapterOrderCancelCommand(order)
|
|
193
193
|
);
|
|
194
194
|
}
|
|
@@ -352,7 +352,7 @@ export class Session {
|
|
|
352
352
|
);
|
|
353
353
|
}
|
|
354
354
|
|
|
355
|
-
balance(selector
|
|
355
|
+
balance(selector: AssetSelector): Observable<Balance> {
|
|
356
356
|
return this.store.changes$.pipe(
|
|
357
357
|
startWith(selector ? this.store.snapshot.balance[selector.toString()] : null),
|
|
358
358
|
filter(
|
|
@@ -375,7 +375,7 @@ export class Session {
|
|
|
375
375
|
switchMap(() =>
|
|
376
376
|
from(
|
|
377
377
|
this.aggregate.dispatch<AdapterHistoryQuery, Candle[]>(
|
|
378
|
-
selector.base.
|
|
378
|
+
selector.base.adapter,
|
|
379
379
|
new AdapterHistoryQuery(selector, timeframe, length)
|
|
380
380
|
)
|
|
381
381
|
)
|
package/src/shared/index.ts
CHANGED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { lastValueFrom, Observable } from 'rxjs';
|
|
2
|
+
import { Session } from './../session';
|
|
3
|
+
|
|
4
|
+
declare type Task = (session: Session) => Observable<any> | Promise<any> | any;
|
|
5
|
+
|
|
6
|
+
const tasks: Record<string, Task> = {};
|
|
7
|
+
|
|
8
|
+
export function task(name: string, fn: Task) {
|
|
9
|
+
tasks[name] = fn;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function runTask(name: string, session: Session): Promise<void> {
|
|
13
|
+
const task = tasks[name];
|
|
14
|
+
|
|
15
|
+
if (!task) {
|
|
16
|
+
throw new Error('Unknown task: ' + name);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const result = tasks[name](session);
|
|
20
|
+
|
|
21
|
+
if (result instanceof Observable) {
|
|
22
|
+
return lastValueFrom(result);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (result instanceof Promise) {
|
|
26
|
+
return await result;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
@@ -23,7 +23,7 @@ export function InstrumentPatchEventHandler(event: InstrumentPatchEvent, state:
|
|
|
23
23
|
const selector = new InstrumentSelector(
|
|
24
24
|
event.base.name,
|
|
25
25
|
event.quote.name,
|
|
26
|
-
event.base.
|
|
26
|
+
event.base.adapter
|
|
27
27
|
);
|
|
28
28
|
|
|
29
29
|
let instrument = state.universe.instrument[selector.toString()];
|
|
@@ -12,12 +12,6 @@ export class OrderLoadEvent implements StoreEvent {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export function OrderLoadEventHandler(event: OrderLoadEvent, state: State) {
|
|
15
|
-
const instrumentKey = event.order.instrument.toString();
|
|
16
|
-
|
|
17
|
-
if (!(instrumentKey in state.subscription.instrument)) {
|
|
18
|
-
throw new Error(`Trying to load order for unsubscribed instrument: ${instrumentKey}`);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
15
|
event.order.timestamp = event.timestamp;
|
|
22
16
|
|
|
23
17
|
switch (event.order.state) {
|
|
@@ -48,12 +42,6 @@ export class OrderNewEvent implements StoreEvent {
|
|
|
48
42
|
}
|
|
49
43
|
|
|
50
44
|
export function OrderNewEventHandler(event: OrderNewEvent, state: State) {
|
|
51
|
-
const instrumentKey = event.order.instrument.toString();
|
|
52
|
-
|
|
53
|
-
if (!(instrumentKey in state.subscription.instrument)) {
|
|
54
|
-
throw new Error(`Trying to order for unsubscribed instrument: ${instrumentKey}`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
45
|
if (event.order.state != 'NEW') {
|
|
58
46
|
throw new Error(`Order is not new`);
|
|
59
47
|
}
|