@quantform/core 0.3.230 → 0.3.231
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.js.map +1 -1
- package/dist/bin.d.ts +0 -33
- package/dist/bin.js +1 -188
- package/dist/bin.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/ipc.d.ts +34 -0
- package/dist/ipc.js +193 -0
- package/dist/ipc.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/adapter/adapter.ts +10 -0
- package/src/bin.ts +22 -189
- package/src/index.ts +1 -0
- package/src/ipc.ts +277 -0
package/src/bin.ts
CHANGED
|
@@ -3,199 +3,17 @@ import {
|
|
|
3
3
|
BacktesterOptions,
|
|
4
4
|
BacktesterStreamer
|
|
5
5
|
} from './adapter/backtester';
|
|
6
|
-
import { AdapterAggregate
|
|
6
|
+
import { AdapterAggregate } from './adapter';
|
|
7
7
|
import { PaperAdapter, PaperOptions } from './adapter/paper';
|
|
8
8
|
import { Session, SessionDescriptor } from './session';
|
|
9
9
|
import { Store } from './store';
|
|
10
|
-
import { instrumentOf } from './domain';
|
|
11
|
-
import { Topic, event, handler } from './shared/topic';
|
|
12
|
-
import minimist = require('minimist');
|
|
13
|
-
import { Logger } from './shared';
|
|
14
|
-
|
|
15
|
-
export interface IpcCommand {
|
|
16
|
-
type;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
@event
|
|
20
|
-
export class IpcPaperModeCommand implements IpcCommand {
|
|
21
|
-
type = 'paper';
|
|
22
|
-
id?: number;
|
|
23
|
-
balance: { [key: string]: number };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
@event
|
|
27
|
-
export class IpcBacktestModeCommand implements IpcCommand {
|
|
28
|
-
type = 'backtest';
|
|
29
|
-
from: number;
|
|
30
|
-
to: number;
|
|
31
|
-
balance: { [key: string]: number };
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
@event
|
|
35
|
-
export class IpcLiveModeCommand implements IpcCommand {
|
|
36
|
-
id?: number;
|
|
37
|
-
type = 'live';
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
@event
|
|
41
|
-
export class IpcUniverseQuery implements IpcCommand {
|
|
42
|
-
type = 'universe';
|
|
43
|
-
exchange: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
@event
|
|
47
|
-
export class IpcFeedCommand implements IpcCommand {
|
|
48
|
-
type = 'feed';
|
|
49
|
-
instrument: string;
|
|
50
|
-
from: number;
|
|
51
|
-
to: number;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
class ExecutionAccessor {
|
|
55
|
-
session: Session;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
class ExecutionHandler extends Topic<{ type: string }, ExecutionAccessor> {
|
|
59
|
-
constructor(private readonly descriptor: SessionDescriptor) {
|
|
60
|
-
super();
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
@handler(IpcLiveModeCommand)
|
|
64
|
-
async onLiveMode(command: IpcLiveModeCommand, accessor: ExecutionAccessor) {
|
|
65
|
-
if (command.id) {
|
|
66
|
-
this.descriptor.id = command.id;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
accessor.session = live(this.descriptor);
|
|
70
|
-
|
|
71
|
-
await accessor.session.awake();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
@handler(IpcPaperModeCommand)
|
|
75
|
-
async onPaperMode(command: IpcPaperModeCommand, accessor: ExecutionAccessor) {
|
|
76
|
-
if (command.id) {
|
|
77
|
-
this.descriptor.id = command.id;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
accessor.session = paper(this.descriptor, {
|
|
81
|
-
balance: command.balance
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
await accessor.session.awake();
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
@handler(IpcBacktestModeCommand)
|
|
88
|
-
onBacktestMode(command: IpcBacktestModeCommand, accessor: ExecutionAccessor) {
|
|
89
|
-
return new Promise<void>(async resolve => {
|
|
90
|
-
const [session, streamer] = backtest(this.descriptor, {
|
|
91
|
-
from: command.from,
|
|
92
|
-
to: command.to,
|
|
93
|
-
balance: command.balance,
|
|
94
|
-
progress: timestamp =>
|
|
95
|
-
this.notify({
|
|
96
|
-
type: 'backtest:updated',
|
|
97
|
-
timestamp,
|
|
98
|
-
from: command.from,
|
|
99
|
-
to: command.to
|
|
100
|
-
}),
|
|
101
|
-
completed: async () => {
|
|
102
|
-
const statement = {};
|
|
103
|
-
|
|
104
|
-
await accessor.session.dispose();
|
|
105
|
-
|
|
106
|
-
this.notify({ type: 'backtest:completed', statement });
|
|
107
|
-
|
|
108
|
-
resolve();
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
accessor.session = session;
|
|
113
|
-
|
|
114
|
-
this.notify({ type: 'backtest:started' });
|
|
115
|
-
|
|
116
|
-
await accessor.session.awake();
|
|
117
|
-
await streamer.tryContinue().catch(it => Logger.error(it));
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
@handler(IpcUniverseQuery)
|
|
122
|
-
onUniverse(query: IpcUniverseQuery, accessor: ExecutionAccessor) {
|
|
123
|
-
accessor.session = accessor.session ?? idle(this.descriptor);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
@handler(IpcFeedCommand)
|
|
127
|
-
async onFeed(command: IpcFeedCommand, accessor: ExecutionAccessor) {
|
|
128
|
-
accessor.session = accessor.session ?? idle(this.descriptor);
|
|
129
|
-
const instrument = instrumentOf(command.instrument);
|
|
130
|
-
|
|
131
|
-
await accessor.session.awake();
|
|
132
|
-
|
|
133
|
-
this.notify({ type: 'feed:started' });
|
|
134
|
-
|
|
135
|
-
await accessor.session.aggregate.dispatch(
|
|
136
|
-
instrument.base.exchange,
|
|
137
|
-
new AdapterFeedCommand(
|
|
138
|
-
instrument,
|
|
139
|
-
command.from,
|
|
140
|
-
command.to,
|
|
141
|
-
this.descriptor.feed,
|
|
142
|
-
timestamp =>
|
|
143
|
-
this.notify({
|
|
144
|
-
type: 'feed:updated',
|
|
145
|
-
timestamp,
|
|
146
|
-
from: command.from,
|
|
147
|
-
to: command.to
|
|
148
|
-
})
|
|
149
|
-
)
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
this.notify({ type: 'feed:completed' });
|
|
153
|
-
|
|
154
|
-
await accessor.session.dispose();
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
private notify(message: any) {
|
|
158
|
-
if (!process.send) {
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
process.send(message);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export async function run(
|
|
167
|
-
descriptor: SessionDescriptor,
|
|
168
|
-
...commands: IpcCommand[]
|
|
169
|
-
): Promise<Session> {
|
|
170
|
-
const handler = new ExecutionHandler(descriptor);
|
|
171
|
-
const accessor = new ExecutionAccessor();
|
|
172
|
-
const argv = minimist(process.argv.slice(2));
|
|
173
|
-
|
|
174
|
-
if (argv.command) {
|
|
175
|
-
const json = Buffer.from(argv.command, 'base64').toString('utf-8');
|
|
176
|
-
|
|
177
|
-
commands.push(JSON.parse(json));
|
|
178
|
-
} else {
|
|
179
|
-
if (!commands.length) {
|
|
180
|
-
commands.push(new IpcPaperModeCommand());
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
for (const command of commands) {
|
|
185
|
-
await handler.dispatch(command, accessor);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
process.on('message', async (request: any) => {
|
|
189
|
-
const response = await handler.dispatch(request, accessor);
|
|
190
|
-
|
|
191
|
-
if (response) {
|
|
192
|
-
process.send(response);
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
return accessor.session;
|
|
197
|
-
}
|
|
198
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Starts a new backtest session.
|
|
13
|
+
* @param descriptor session descriptor.
|
|
14
|
+
* @param options backtest options.
|
|
15
|
+
* @returns new session object.
|
|
16
|
+
*/
|
|
199
17
|
export function backtest(
|
|
200
18
|
descriptor: SessionDescriptor,
|
|
201
19
|
options: BacktesterOptions
|
|
@@ -213,6 +31,12 @@ export function backtest(
|
|
|
213
31
|
return [new Session(store, aggregate, descriptor), streamer];
|
|
214
32
|
}
|
|
215
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Starts a new paper session.
|
|
36
|
+
* @param descriptor session descriptor.
|
|
37
|
+
* @param options backtest options.
|
|
38
|
+
* @returns new session object.
|
|
39
|
+
*/
|
|
216
40
|
export function paper(descriptor: SessionDescriptor, options: PaperOptions): Session {
|
|
217
41
|
const store = new Store();
|
|
218
42
|
|
|
@@ -224,6 +48,11 @@ export function paper(descriptor: SessionDescriptor, options: PaperOptions): Ses
|
|
|
224
48
|
return new Session(store, aggregate, descriptor);
|
|
225
49
|
}
|
|
226
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Starts a new live session.
|
|
53
|
+
* @param descriptor session descriptor.
|
|
54
|
+
* @returns new session object.
|
|
55
|
+
*/
|
|
227
56
|
export function live(descriptor: SessionDescriptor): Session {
|
|
228
57
|
const store = new Store();
|
|
229
58
|
const aggregate = new AdapterAggregate(store, descriptor.adapter);
|
|
@@ -231,6 +60,10 @@ export function live(descriptor: SessionDescriptor): Session {
|
|
|
231
60
|
return new Session(store, aggregate, descriptor);
|
|
232
61
|
}
|
|
233
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Starts a new idle session.
|
|
65
|
+
* @param descriptor session descriptor.
|
|
66
|
+
*/
|
|
234
67
|
export function idle(descriptor: SessionDescriptor): Session {
|
|
235
68
|
const store = new Store();
|
|
236
69
|
const aggregate = new AdapterAggregate(store, descriptor.adapter);
|
package/src/index.ts
CHANGED
package/src/ipc.ts
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { AdapterFeedCommand } from './adapter';
|
|
2
|
+
import { Session, SessionDescriptor } from './session';
|
|
3
|
+
import { instrumentOf } from './domain';
|
|
4
|
+
import { Topic, event, handler } from './shared/topic';
|
|
5
|
+
import { Logger } from './shared';
|
|
6
|
+
import { backtest, idle, live, paper } from './bin';
|
|
7
|
+
import minimist = require('minimist');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Base command/query interface for IPC communication.
|
|
11
|
+
*/
|
|
12
|
+
export interface IpcCommand {
|
|
13
|
+
/**
|
|
14
|
+
* The command name to handle.
|
|
15
|
+
*/
|
|
16
|
+
type;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Command to start a new live session.
|
|
21
|
+
*/
|
|
22
|
+
@event
|
|
23
|
+
export class IpcLiveCommand implements IpcCommand {
|
|
24
|
+
type = 'live';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The optional session identifier.
|
|
28
|
+
*/
|
|
29
|
+
id?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Command to start a new paper session.
|
|
34
|
+
*/
|
|
35
|
+
@event
|
|
36
|
+
export class IpcPaperCommand implements IpcCommand {
|
|
37
|
+
type = 'paper';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The optional session identifier.
|
|
41
|
+
*/
|
|
42
|
+
id?: number;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Specifies trading balance, for example:
|
|
46
|
+
* { "binance:usdt": 1000 }
|
|
47
|
+
*/
|
|
48
|
+
balance: { [key: string]: number };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Command to start a new backtest session.
|
|
53
|
+
*/
|
|
54
|
+
@event
|
|
55
|
+
export class IpcBacktestCommand implements IpcCommand {
|
|
56
|
+
type = 'backtest';
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Start date of the backtest in unix timestamp.
|
|
60
|
+
*/
|
|
61
|
+
from: number;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Due date of the backtest in unix timestamp.
|
|
65
|
+
*/
|
|
66
|
+
to: number;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Specifies trading balance, for example:
|
|
70
|
+
* { "binance:usdt": 1000 }
|
|
71
|
+
*/
|
|
72
|
+
balance: { [key: string]: number };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@event
|
|
76
|
+
export class IpcUniverseQuery implements IpcCommand {
|
|
77
|
+
type = 'universe';
|
|
78
|
+
exchange: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Feeds specific session descriptor with instrument data.
|
|
83
|
+
*/
|
|
84
|
+
@event
|
|
85
|
+
export class IpcFeedCommand implements IpcCommand {
|
|
86
|
+
type = 'feed';
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Instrument to feed.
|
|
90
|
+
*/
|
|
91
|
+
instrument: string;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Start date of the feed in unix timestamp.
|
|
95
|
+
*/
|
|
96
|
+
from: number;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Due date of the feed in unix timestamp.
|
|
100
|
+
*/
|
|
101
|
+
to: number;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Stores current session instance.
|
|
106
|
+
*/
|
|
107
|
+
class IpcSessionAccessor {
|
|
108
|
+
session: Session;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Inter process communication handler.
|
|
113
|
+
*/
|
|
114
|
+
class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
115
|
+
constructor(private readonly descriptor: SessionDescriptor) {
|
|
116
|
+
super();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @see IpcLiveCommand
|
|
121
|
+
*/
|
|
122
|
+
@handler(IpcLiveCommand)
|
|
123
|
+
async onLiveMode(command: IpcLiveCommand, accessor: IpcSessionAccessor) {
|
|
124
|
+
if (command.id) {
|
|
125
|
+
this.descriptor.id = command.id;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
accessor.session = live(this.descriptor);
|
|
129
|
+
|
|
130
|
+
await accessor.session.awake();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @see IpcPaperCommand
|
|
135
|
+
*/
|
|
136
|
+
@handler(IpcPaperCommand)
|
|
137
|
+
async onPaperMode(command: IpcPaperCommand, accessor: IpcSessionAccessor) {
|
|
138
|
+
if (command.id) {
|
|
139
|
+
this.descriptor.id = command.id;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
accessor.session = paper(this.descriptor, {
|
|
143
|
+
balance: command.balance
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
await accessor.session.awake();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @see IpcBacktestCommand
|
|
151
|
+
*/
|
|
152
|
+
@handler(IpcBacktestCommand)
|
|
153
|
+
onBacktestMode(command: IpcBacktestCommand, accessor: IpcSessionAccessor) {
|
|
154
|
+
return new Promise<void>(async resolve => {
|
|
155
|
+
const [session, streamer] = backtest(this.descriptor, {
|
|
156
|
+
from: command.from,
|
|
157
|
+
to: command.to,
|
|
158
|
+
balance: command.balance,
|
|
159
|
+
progress: timestamp =>
|
|
160
|
+
this.notify({
|
|
161
|
+
type: 'backtest:updated',
|
|
162
|
+
timestamp,
|
|
163
|
+
from: command.from,
|
|
164
|
+
to: command.to
|
|
165
|
+
}),
|
|
166
|
+
completed: async () => {
|
|
167
|
+
const statement = {};
|
|
168
|
+
|
|
169
|
+
await accessor.session.dispose();
|
|
170
|
+
|
|
171
|
+
this.notify({ type: 'backtest:completed', statement });
|
|
172
|
+
|
|
173
|
+
resolve();
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
accessor.session = session;
|
|
178
|
+
|
|
179
|
+
this.notify({ type: 'backtest:started' });
|
|
180
|
+
|
|
181
|
+
await accessor.session.awake();
|
|
182
|
+
await streamer.tryContinue().catch(it => Logger.error(it));
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @see IpcUniverseQuery
|
|
188
|
+
*/
|
|
189
|
+
@handler(IpcUniverseQuery)
|
|
190
|
+
onUniverse(query: IpcUniverseQuery, accessor: IpcSessionAccessor) {
|
|
191
|
+
accessor.session = accessor.session ?? idle(this.descriptor);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* @see IpcFeedCommand
|
|
196
|
+
*/
|
|
197
|
+
@handler(IpcFeedCommand)
|
|
198
|
+
async onFeed(command: IpcFeedCommand, accessor: IpcSessionAccessor) {
|
|
199
|
+
accessor.session = accessor.session ?? idle(this.descriptor);
|
|
200
|
+
const instrument = instrumentOf(command.instrument);
|
|
201
|
+
|
|
202
|
+
await accessor.session.awake();
|
|
203
|
+
|
|
204
|
+
this.notify({ type: 'feed:started' });
|
|
205
|
+
|
|
206
|
+
await accessor.session.aggregate.dispatch(
|
|
207
|
+
instrument.base.exchange,
|
|
208
|
+
new AdapterFeedCommand(
|
|
209
|
+
instrument,
|
|
210
|
+
command.from,
|
|
211
|
+
command.to,
|
|
212
|
+
this.descriptor.feed,
|
|
213
|
+
timestamp =>
|
|
214
|
+
this.notify({
|
|
215
|
+
type: 'feed:updated',
|
|
216
|
+
timestamp,
|
|
217
|
+
from: command.from,
|
|
218
|
+
to: command.to
|
|
219
|
+
})
|
|
220
|
+
)
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
this.notify({ type: 'feed:completed' });
|
|
224
|
+
|
|
225
|
+
await accessor.session.dispose();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Sends a message to parent process.
|
|
230
|
+
*/
|
|
231
|
+
private notify(message: any) {
|
|
232
|
+
if (!process.send) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
process.send(message);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Starts new managed session and subscribes to parent process messages.
|
|
242
|
+
* @param descriptor session descriptor.
|
|
243
|
+
* @param commands collection of commands to execute before session is started.
|
|
244
|
+
* @returns new session.
|
|
245
|
+
*/
|
|
246
|
+
export async function run(
|
|
247
|
+
descriptor: SessionDescriptor,
|
|
248
|
+
...commands: IpcCommand[]
|
|
249
|
+
): Promise<Session> {
|
|
250
|
+
const handler = new IpcHandler(descriptor);
|
|
251
|
+
const accessor = new IpcSessionAccessor();
|
|
252
|
+
const argv = minimist(process.argv.slice(2));
|
|
253
|
+
|
|
254
|
+
if (argv.command) {
|
|
255
|
+
const json = Buffer.from(argv.command, 'base64').toString('utf-8');
|
|
256
|
+
|
|
257
|
+
commands.push(JSON.parse(json));
|
|
258
|
+
} else {
|
|
259
|
+
if (!commands.length) {
|
|
260
|
+
commands.push(new IpcPaperCommand());
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
for (const command of commands) {
|
|
265
|
+
await handler.dispatch(command, accessor);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
process.on('message', async (request: any) => {
|
|
269
|
+
const response = await handler.dispatch(request, accessor);
|
|
270
|
+
|
|
271
|
+
if (response) {
|
|
272
|
+
process.send(response);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
return accessor.session;
|
|
277
|
+
}
|