@quantform/core 0.3.243 → 0.3.251
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.d.ts +11 -5
- package/dist/adapter/adapter-aggregate.js +38 -8
- package/dist/adapter/adapter-aggregate.js.map +1 -1
- package/dist/adapter/backtester/backtester-adapter.d.ts +1 -2
- package/dist/adapter/backtester/backtester-adapter.js.map +1 -1
- package/dist/adapter/backtester/backtester-streamer.d.ts +2 -1
- package/dist/adapter/backtester/backtester-streamer.js +8 -7
- package/dist/adapter/backtester/backtester-streamer.js.map +1 -1
- package/dist/adapter/backtester/backtester-streamer.spec.js +9 -10
- package/dist/adapter/backtester/backtester-streamer.spec.js.map +1 -1
- package/dist/bin.d.ts +3 -4
- package/dist/bin.js +6 -6
- package/dist/bin.js.map +1 -1
- package/dist/ipc.d.ts +6 -12
- package/dist/ipc.js +71 -55
- package/dist/ipc.js.map +1 -1
- package/dist/ipc.spec.js +9 -9
- package/dist/ipc.spec.js.map +1 -1
- package/dist/session/session-descriptor.d.ts +6 -3
- package/dist/session/session.d.ts +1 -1
- package/dist/session/session.js +9 -25
- package/dist/session/session.js.map +1 -1
- package/dist/session/session.spec.js +1 -5
- package/dist/session/session.spec.js.map +1 -1
- package/dist/tests/backtester-adapter.spec.js +7 -8
- package/dist/tests/backtester-adapter.spec.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/adapter/adapter-aggregate.ts +110 -13
- package/src/adapter/backtester/backtester-adapter.ts +2 -3
- package/src/adapter/backtester/backtester-streamer.spec.ts +10 -6
- package/src/adapter/backtester/backtester-streamer.ts +8 -7
- package/src/bin.ts +21 -11
- package/src/ipc.spec.ts +9 -8
- package/src/ipc.ts +97 -90
- package/src/session/session-descriptor.ts +7 -4
- package/src/session/session.spec.ts +1 -5
- package/src/session/session.ts +9 -48
- package/src/tests/backtester-adapter.spec.ts +11 -7
|
@@ -4,8 +4,15 @@ import { Logger } from '../shared';
|
|
|
4
4
|
import {
|
|
5
5
|
AdapterAccountCommand,
|
|
6
6
|
AdapterAwakeCommand,
|
|
7
|
-
AdapterDisposeCommand
|
|
7
|
+
AdapterDisposeCommand,
|
|
8
|
+
AdapterFeedCommand,
|
|
9
|
+
AdapterHistoryQuery,
|
|
10
|
+
AdapterOrderCancelCommand,
|
|
11
|
+
AdapterOrderOpenCommand,
|
|
12
|
+
AdapterSubscribeCommand
|
|
8
13
|
} from './adapter.event';
|
|
14
|
+
import { InstrumentSelector, Order, Candle } from '../domain';
|
|
15
|
+
import { Feed } from './../storage';
|
|
9
16
|
|
|
10
17
|
/**
|
|
11
18
|
* Manages instances of all adapters provided in session descriptor.
|
|
@@ -14,21 +21,26 @@ import {
|
|
|
14
21
|
export class AdapterAggregate {
|
|
15
22
|
private readonly adapter: Record<string, Adapter> = {};
|
|
16
23
|
|
|
17
|
-
constructor(private readonly store: Store
|
|
24
|
+
constructor(adapters: Adapter[], private readonly store: Store) {
|
|
18
25
|
adapters.forEach(it => (this.adapter[it.name] = it));
|
|
19
26
|
}
|
|
20
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Returns adapter by name.
|
|
30
|
+
* @param adapterName adapter name.
|
|
31
|
+
* @returns
|
|
32
|
+
*/
|
|
33
|
+
get(adapterName: string): Adapter {
|
|
34
|
+
return this.adapter[adapterName];
|
|
35
|
+
}
|
|
36
|
+
|
|
21
37
|
/**
|
|
22
38
|
* Sets up all adapters.
|
|
23
|
-
* @param usePrivateScope use private api (api keys needed).
|
|
24
39
|
*/
|
|
25
|
-
async awake(
|
|
40
|
+
async awake(): Promise<void> {
|
|
26
41
|
for (const adapter in this.adapter) {
|
|
27
42
|
await this.dispatch(adapter, new AdapterAwakeCommand());
|
|
28
|
-
|
|
29
|
-
if (usePrivateScope) {
|
|
30
|
-
await this.dispatch(adapter, new AdapterAccountCommand());
|
|
31
|
-
}
|
|
43
|
+
await this.dispatch(adapter, new AdapterAccountCommand());
|
|
32
44
|
}
|
|
33
45
|
}
|
|
34
46
|
|
|
@@ -41,17 +53,102 @@ export class AdapterAggregate {
|
|
|
41
53
|
}
|
|
42
54
|
}
|
|
43
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Subscribe to collection of instruments.
|
|
58
|
+
* @param selectors
|
|
59
|
+
*/
|
|
60
|
+
async subscribe(selectors: InstrumentSelector[]): Promise<void> {
|
|
61
|
+
const grouped = selectors
|
|
62
|
+
.filter(it => it != null)
|
|
63
|
+
.reduce((aggregate, it) => {
|
|
64
|
+
const adapter = it.base.adapter;
|
|
65
|
+
|
|
66
|
+
if (aggregate[adapter]) {
|
|
67
|
+
aggregate[adapter].push(it);
|
|
68
|
+
} else {
|
|
69
|
+
aggregate[adapter] = [it];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return aggregate;
|
|
73
|
+
}, {});
|
|
74
|
+
|
|
75
|
+
for (const adapterName in grouped) {
|
|
76
|
+
await this.dispatch(adapterName, new AdapterSubscribeCommand(grouped[adapterName]));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Opens new order.
|
|
82
|
+
* @param order an order to open.
|
|
83
|
+
*/
|
|
84
|
+
open(order: Order): Promise<void> {
|
|
85
|
+
return this.dispatch<AdapterOrderOpenCommand, void>(
|
|
86
|
+
order.instrument.base.adapter,
|
|
87
|
+
new AdapterOrderOpenCommand(order)
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Cancels specific order.
|
|
93
|
+
*/
|
|
94
|
+
cancel(order: Order): Promise<void> {
|
|
95
|
+
return this.dispatch(
|
|
96
|
+
order.instrument.base.adapter,
|
|
97
|
+
new AdapterOrderCancelCommand(order)
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
*
|
|
103
|
+
* @param selector Returns collection of candles for specific history.
|
|
104
|
+
* @param timeframe
|
|
105
|
+
* @param length
|
|
106
|
+
* @returns
|
|
107
|
+
*/
|
|
108
|
+
history(
|
|
109
|
+
selector: InstrumentSelector,
|
|
110
|
+
timeframe: number,
|
|
111
|
+
length: number
|
|
112
|
+
): Promise<Candle[]> {
|
|
113
|
+
return this.dispatch<AdapterHistoryQuery, Candle[]>(
|
|
114
|
+
selector.base.adapter,
|
|
115
|
+
new AdapterHistoryQuery(selector, timeframe, length)
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Feeds a storage with historical instrument data.
|
|
121
|
+
* @param selector
|
|
122
|
+
* @param from
|
|
123
|
+
* @param to
|
|
124
|
+
* @param destination
|
|
125
|
+
* @param callback
|
|
126
|
+
* @returns
|
|
127
|
+
*/
|
|
128
|
+
feed(
|
|
129
|
+
selector: InstrumentSelector,
|
|
130
|
+
from: number,
|
|
131
|
+
to: number,
|
|
132
|
+
destination: Feed,
|
|
133
|
+
callback: (timestamp: number) => void
|
|
134
|
+
): Promise<void> {
|
|
135
|
+
return this.dispatch(
|
|
136
|
+
selector.base.adapter,
|
|
137
|
+
new AdapterFeedCommand(selector, from, to, destination, callback)
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
44
141
|
/**
|
|
45
142
|
* Routes and executes command to a specific adapter.
|
|
46
143
|
* @param adapterName name of adapter
|
|
47
|
-
* @param
|
|
144
|
+
* @param command
|
|
48
145
|
* @returns
|
|
49
146
|
*/
|
|
50
|
-
dispatch<
|
|
147
|
+
private dispatch<TCommand extends { type: string }, TResponse>(
|
|
51
148
|
adapterName: string,
|
|
52
|
-
|
|
149
|
+
command: TCommand
|
|
53
150
|
): Promise<TResponse> {
|
|
54
|
-
const adapter = this.
|
|
151
|
+
const adapter = this.get(adapterName);
|
|
55
152
|
|
|
56
153
|
if (!adapter) {
|
|
57
154
|
throw new Error(
|
|
@@ -60,7 +157,7 @@ export class AdapterAggregate {
|
|
|
60
157
|
}
|
|
61
158
|
|
|
62
159
|
try {
|
|
63
|
-
return adapter.dispatch(
|
|
160
|
+
return adapter.dispatch(command, new AdapterContext(adapter, this.store));
|
|
64
161
|
} catch (e) {
|
|
65
162
|
Logger.error(e);
|
|
66
163
|
}
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { Adapter, AdapterContext } from '..';
|
|
2
|
-
import {
|
|
2
|
+
import { BacktesterStreamer } from './backtester-streamer';
|
|
3
3
|
import { PaperAdapter, PaperOptions } from '../paper';
|
|
4
4
|
import { handler } from '../../shared/topic';
|
|
5
|
-
import {
|
|
5
|
+
import { timestamp } from '../../shared';
|
|
6
6
|
import { AdapterSubscribeCommand, AdapterHistoryQuery } from '../adapter.event';
|
|
7
7
|
import { InstrumentSubscriptionEvent } from '../../store/event';
|
|
8
8
|
|
|
9
9
|
export class BacktesterOptions extends PaperOptions {
|
|
10
10
|
from: timestamp;
|
|
11
11
|
to: timestamp;
|
|
12
|
-
listener?: BacktesterListener;
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
export class BacktesterAdapter extends Adapter {
|
|
@@ -18,11 +18,15 @@ describe('backtester streamer tests', () => {
|
|
|
18
18
|
store.snapshot.universe.instrument[instrument.toString()] = instrument;
|
|
19
19
|
store.snapshot.subscription.instrument[instrument.toString()] = instrument;
|
|
20
20
|
|
|
21
|
-
const streamer = new BacktesterStreamer(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
const streamer = new BacktesterStreamer(
|
|
22
|
+
store,
|
|
23
|
+
feed,
|
|
24
|
+
{
|
|
25
|
+
balance: {},
|
|
26
|
+
from: 0,
|
|
27
|
+
to: 10
|
|
28
|
+
},
|
|
29
|
+
{
|
|
26
30
|
onBacktestCompleted: () => {
|
|
27
31
|
const trade = store.snapshot.trade[instrument.toString()];
|
|
28
32
|
|
|
@@ -34,7 +38,7 @@ describe('backtester streamer tests', () => {
|
|
|
34
38
|
done();
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
|
-
|
|
41
|
+
);
|
|
38
42
|
|
|
39
43
|
feed
|
|
40
44
|
.save(instrument, [
|
|
@@ -36,7 +36,8 @@ export class BacktesterStreamer {
|
|
|
36
36
|
constructor(
|
|
37
37
|
private readonly store: Store,
|
|
38
38
|
private readonly feed: Feed,
|
|
39
|
-
private readonly options: BacktesterOptions
|
|
39
|
+
private readonly options: BacktesterOptions,
|
|
40
|
+
private readonly listener?: BacktesterListener
|
|
40
41
|
) {
|
|
41
42
|
this.timestamp = this.options.from;
|
|
42
43
|
}
|
|
@@ -73,15 +74,15 @@ export class BacktesterStreamer {
|
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
if (this.sequence == 0) {
|
|
76
|
-
if (this.
|
|
77
|
-
this.
|
|
77
|
+
if (this.listener.onBacktestStarted) {
|
|
78
|
+
this.listener.onBacktestStarted(this);
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
while (await this.processNext()) {
|
|
82
83
|
if (this.sequence % this.sequenceUpdateBatch == 0) {
|
|
83
|
-
if (this.
|
|
84
|
-
this.
|
|
84
|
+
if (this.listener.onBacktestUpdated) {
|
|
85
|
+
this.listener.onBacktestUpdated(this);
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
88
|
|
|
@@ -90,8 +91,8 @@ export class BacktesterStreamer {
|
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
if (this.
|
|
94
|
-
this.
|
|
94
|
+
if (this.listener.onBacktestCompleted) {
|
|
95
|
+
this.listener.onBacktestCompleted(this);
|
|
95
96
|
}
|
|
96
97
|
}
|
|
97
98
|
|
package/src/bin.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BacktesterAdapter,
|
|
3
|
-
|
|
3
|
+
BacktesterListener,
|
|
4
4
|
BacktesterStreamer
|
|
5
5
|
} from './adapter/backtester';
|
|
6
6
|
import { AdapterAggregate } from './adapter';
|
|
7
|
-
import { PaperAdapter
|
|
7
|
+
import { PaperAdapter } from './adapter/paper';
|
|
8
8
|
import { Session, SessionDescriptor } from './session';
|
|
9
9
|
import { Store } from './store';
|
|
10
10
|
|
|
@@ -16,16 +16,26 @@ import { Store } from './store';
|
|
|
16
16
|
*/
|
|
17
17
|
export function backtest(
|
|
18
18
|
descriptor: SessionDescriptor,
|
|
19
|
-
|
|
19
|
+
listener?: BacktesterListener
|
|
20
20
|
): [Session, BacktesterStreamer] {
|
|
21
21
|
const store = new Store();
|
|
22
22
|
|
|
23
|
-
const streamer = new BacktesterStreamer(
|
|
24
|
-
const aggregate = new AdapterAggregate(
|
|
23
|
+
const streamer = new BacktesterStreamer(
|
|
25
24
|
store,
|
|
25
|
+
descriptor.feed,
|
|
26
|
+
descriptor.options.backtester,
|
|
27
|
+
listener
|
|
28
|
+
);
|
|
29
|
+
const aggregate = new AdapterAggregate(
|
|
26
30
|
descriptor.adapter.map(
|
|
27
|
-
it =>
|
|
28
|
-
|
|
31
|
+
it =>
|
|
32
|
+
new PaperAdapter(
|
|
33
|
+
new BacktesterAdapter(it, streamer),
|
|
34
|
+
store,
|
|
35
|
+
descriptor.options.backtester
|
|
36
|
+
)
|
|
37
|
+
),
|
|
38
|
+
store
|
|
29
39
|
);
|
|
30
40
|
|
|
31
41
|
return [new Session(store, aggregate, descriptor), streamer];
|
|
@@ -37,12 +47,12 @@ export function backtest(
|
|
|
37
47
|
* @param options backtest options.
|
|
38
48
|
* @returns new session object.
|
|
39
49
|
*/
|
|
40
|
-
export function paper(descriptor: SessionDescriptor
|
|
50
|
+
export function paper(descriptor: SessionDescriptor): Session {
|
|
41
51
|
const store = new Store();
|
|
42
52
|
|
|
43
53
|
const aggregate = new AdapterAggregate(
|
|
44
|
-
store,
|
|
45
|
-
|
|
54
|
+
descriptor.adapter.map(it => new PaperAdapter(it, store, descriptor.options.paper)),
|
|
55
|
+
store
|
|
46
56
|
);
|
|
47
57
|
|
|
48
58
|
return new Session(store, aggregate, descriptor);
|
|
@@ -55,7 +65,7 @@ export function paper(descriptor: SessionDescriptor, options: PaperOptions): Ses
|
|
|
55
65
|
*/
|
|
56
66
|
export function live(descriptor: SessionDescriptor): Session {
|
|
57
67
|
const store = new Store();
|
|
58
|
-
const aggregate = new AdapterAggregate(
|
|
68
|
+
const aggregate = new AdapterAggregate(descriptor.adapter, store);
|
|
59
69
|
|
|
60
70
|
return new Session(store, aggregate, descriptor);
|
|
61
71
|
}
|
package/src/ipc.spec.ts
CHANGED
|
@@ -55,8 +55,7 @@ describe('ipc feed tests', () => {
|
|
|
55
55
|
const session = await run(
|
|
56
56
|
{
|
|
57
57
|
adapter: [new DefaultAdapter()],
|
|
58
|
-
feed: new Feed(new InMemoryStorage())
|
|
59
|
-
describe: (session: Session) => session.trade(instrumentOf('default:btc-usdt'))
|
|
58
|
+
feed: new Feed(new InMemoryStorage())
|
|
60
59
|
},
|
|
61
60
|
command
|
|
62
61
|
);
|
|
@@ -66,8 +65,7 @@ describe('ipc feed tests', () => {
|
|
|
66
65
|
|
|
67
66
|
test('should dispatch session started event', done => {
|
|
68
67
|
const command = {
|
|
69
|
-
type: 'paper'
|
|
70
|
-
balance: { 'default:usd': 100 }
|
|
68
|
+
type: 'paper'
|
|
71
69
|
};
|
|
72
70
|
|
|
73
71
|
const ipcSub = new EventEmitter();
|
|
@@ -80,8 +78,12 @@ describe('ipc feed tests', () => {
|
|
|
80
78
|
run(
|
|
81
79
|
{
|
|
82
80
|
adapter: [new DefaultAdapter()],
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
ipcSub,
|
|
82
|
+
options: {
|
|
83
|
+
paper: {
|
|
84
|
+
balance: { 'default:usd': 100 }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
85
87
|
},
|
|
86
88
|
command
|
|
87
89
|
);
|
|
@@ -102,8 +104,7 @@ describe('ipc feed tests', () => {
|
|
|
102
104
|
|
|
103
105
|
run(
|
|
104
106
|
{
|
|
105
|
-
adapter: [new DefaultAdapter()]
|
|
106
|
-
describe: (session: Session) => session.trade(instrumentOf('default:btc-usdt'))
|
|
107
|
+
adapter: [new DefaultAdapter()]
|
|
107
108
|
},
|
|
108
109
|
command
|
|
109
110
|
);
|
package/src/ipc.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { AdapterFeedCommand } from './adapter';
|
|
2
1
|
import { Session, SessionDescriptor } from './session';
|
|
3
2
|
import { instrumentOf } from './domain';
|
|
4
3
|
import { Topic, event, handler } from './shared/topic';
|
|
5
4
|
import { runTask, Logger } from './shared';
|
|
6
5
|
import { backtest, live, paper } from './bin';
|
|
7
6
|
import { BacktesterStreamer } from './adapter/backtester';
|
|
7
|
+
import { Observable } from 'rxjs';
|
|
8
8
|
import { EventEmitter } from 'events';
|
|
9
|
+
import { join } from 'path';
|
|
9
10
|
import minimist = require('minimist');
|
|
10
11
|
import dotenv = require('dotenv');
|
|
11
12
|
|
|
@@ -46,12 +47,6 @@ export class IpcPaperCommand implements IpcCommand {
|
|
|
46
47
|
* The optional session identifier.
|
|
47
48
|
*/
|
|
48
49
|
id?: number;
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Specifies trading balance, for example:
|
|
52
|
-
* { "binance:usdt": 1000 }
|
|
53
|
-
*/
|
|
54
|
-
balance: { [key: string]: number };
|
|
55
50
|
}
|
|
56
51
|
|
|
57
52
|
/**
|
|
@@ -62,20 +57,14 @@ export class IpcBacktestCommand implements IpcCommand {
|
|
|
62
57
|
type = 'backtest';
|
|
63
58
|
|
|
64
59
|
/**
|
|
65
|
-
* Start date of the
|
|
66
|
-
*/
|
|
67
|
-
from: number;
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Due date of the backtest in unix timestamp.
|
|
60
|
+
* Start date of the feed in unix timestamp.
|
|
71
61
|
*/
|
|
72
|
-
|
|
62
|
+
from?: number;
|
|
73
63
|
|
|
74
64
|
/**
|
|
75
|
-
*
|
|
76
|
-
* { "binance:usdt": 1000 }
|
|
65
|
+
* Due date of the feed in unix timestamp.
|
|
77
66
|
*/
|
|
78
|
-
|
|
67
|
+
to?: number;
|
|
79
68
|
}
|
|
80
69
|
|
|
81
70
|
/**
|
|
@@ -93,12 +82,12 @@ export class IpcFeedCommand implements IpcCommand {
|
|
|
93
82
|
/**
|
|
94
83
|
* Start date of the feed in unix timestamp.
|
|
95
84
|
*/
|
|
96
|
-
from
|
|
85
|
+
from?: number;
|
|
97
86
|
|
|
98
87
|
/**
|
|
99
88
|
* Due date of the feed in unix timestamp.
|
|
100
89
|
*/
|
|
101
|
-
to
|
|
90
|
+
to?: number;
|
|
102
91
|
}
|
|
103
92
|
|
|
104
93
|
/**
|
|
@@ -121,13 +110,13 @@ class IpcSessionAccessor {
|
|
|
121
110
|
session: Session;
|
|
122
111
|
}
|
|
123
112
|
|
|
124
|
-
export declare type
|
|
113
|
+
export declare type IpcSessionDescriptor = SessionDescriptor & { ipcSub?: EventEmitter };
|
|
125
114
|
|
|
126
115
|
/**
|
|
127
116
|
* Inter process communication handler.
|
|
128
117
|
*/
|
|
129
118
|
class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
130
|
-
constructor(private readonly descriptor:
|
|
119
|
+
constructor(private readonly descriptor: IpcSessionDescriptor) {
|
|
131
120
|
super();
|
|
132
121
|
}
|
|
133
122
|
|
|
@@ -142,12 +131,12 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
142
131
|
|
|
143
132
|
accessor.session = live(this.descriptor);
|
|
144
133
|
|
|
145
|
-
this.
|
|
134
|
+
this.emit({
|
|
146
135
|
type: 'live:started',
|
|
147
136
|
session: accessor.session.descriptor?.id
|
|
148
137
|
});
|
|
149
138
|
|
|
150
|
-
await accessor.session.awake();
|
|
139
|
+
await accessor.session.awake(this.describe());
|
|
151
140
|
}
|
|
152
141
|
|
|
153
142
|
/**
|
|
@@ -159,16 +148,14 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
159
148
|
this.descriptor.id = command.id;
|
|
160
149
|
}
|
|
161
150
|
|
|
162
|
-
accessor.session = paper(this.descriptor
|
|
163
|
-
balance: command.balance
|
|
164
|
-
});
|
|
151
|
+
accessor.session = paper(this.descriptor);
|
|
165
152
|
|
|
166
|
-
this.
|
|
153
|
+
this.emit({
|
|
167
154
|
type: 'paper:started',
|
|
168
155
|
session: accessor.session.descriptor?.id
|
|
169
156
|
});
|
|
170
157
|
|
|
171
|
-
await accessor.session.awake();
|
|
158
|
+
await accessor.session.awake(this.describe());
|
|
172
159
|
}
|
|
173
160
|
|
|
174
161
|
/**
|
|
@@ -176,49 +163,51 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
176
163
|
*/
|
|
177
164
|
@handler(IpcBacktestCommand)
|
|
178
165
|
onBacktestMode(command: IpcBacktestCommand, accessor: IpcSessionAccessor) {
|
|
166
|
+
if (command.from) {
|
|
167
|
+
this.descriptor.options.backtester.from = command.from;
|
|
168
|
+
}
|
|
169
|
+
if (command.to) {
|
|
170
|
+
this.descriptor.options.backtester.to = command.to;
|
|
171
|
+
}
|
|
172
|
+
|
|
179
173
|
return new Promise<void>(async resolve => {
|
|
180
174
|
const [session, streamer] = backtest(this.descriptor, {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
this.
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
this.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
this.
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
to: command.to
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
resolve();
|
|
215
|
-
}
|
|
175
|
+
onBacktestStarted: (streamer: BacktesterStreamer) => {
|
|
176
|
+
this.emit({
|
|
177
|
+
type: 'backtest:started',
|
|
178
|
+
session: session.descriptor?.id,
|
|
179
|
+
timestamp: streamer.timestamp,
|
|
180
|
+
from: this.descriptor.options.backtester.from,
|
|
181
|
+
to: this.descriptor.options.backtester.to
|
|
182
|
+
});
|
|
183
|
+
},
|
|
184
|
+
onBacktestUpdated: (streamer: BacktesterStreamer) => {
|
|
185
|
+
this.emit({
|
|
186
|
+
type: 'backtest:updated',
|
|
187
|
+
session: session.descriptor?.id,
|
|
188
|
+
timestamp: streamer.timestamp,
|
|
189
|
+
from: this.descriptor.options.backtester.from,
|
|
190
|
+
to: this.descriptor.options.backtester.to
|
|
191
|
+
});
|
|
192
|
+
},
|
|
193
|
+
onBacktestCompleted: async (streamer: BacktesterStreamer) => {
|
|
194
|
+
await accessor.session.dispose();
|
|
195
|
+
|
|
196
|
+
this.emit({
|
|
197
|
+
type: 'backtest:completed',
|
|
198
|
+
session: session.descriptor?.id,
|
|
199
|
+
timestamp: streamer.timestamp,
|
|
200
|
+
from: this.descriptor.options.backtester.from,
|
|
201
|
+
to: this.descriptor.options.backtester.to
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
resolve();
|
|
216
205
|
}
|
|
217
206
|
});
|
|
218
207
|
|
|
219
208
|
accessor.session = session;
|
|
220
209
|
|
|
221
|
-
await accessor.session.awake();
|
|
210
|
+
await accessor.session.awake(this.describe());
|
|
222
211
|
await streamer.tryContinue().catch(it => Logger.error(it));
|
|
223
212
|
});
|
|
224
213
|
}
|
|
@@ -228,31 +217,38 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
228
217
|
*/
|
|
229
218
|
@handler(IpcFeedCommand)
|
|
230
219
|
async onFeed(command: IpcFeedCommand, accessor: IpcSessionAccessor) {
|
|
231
|
-
|
|
220
|
+
if (!this.descriptor.options) {
|
|
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);
|
|
232
231
|
const instrument = instrumentOf(command.instrument);
|
|
233
232
|
|
|
234
|
-
await accessor.session.awake(
|
|
235
|
-
|
|
236
|
-
this.
|
|
237
|
-
|
|
238
|
-
await accessor.session.aggregate.
|
|
239
|
-
instrument
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
this.
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
to: command.to
|
|
251
|
-
})
|
|
252
|
-
)
|
|
233
|
+
await accessor.session.awake(undefined);
|
|
234
|
+
|
|
235
|
+
this.emit({ type: 'feed:started' });
|
|
236
|
+
|
|
237
|
+
await accessor.session.aggregate.feed(
|
|
238
|
+
instrument,
|
|
239
|
+
command.from,
|
|
240
|
+
command.to,
|
|
241
|
+
this.descriptor.feed,
|
|
242
|
+
timestamp =>
|
|
243
|
+
this.emit({
|
|
244
|
+
type: 'feed:updated',
|
|
245
|
+
timestamp,
|
|
246
|
+
from: command.from,
|
|
247
|
+
to: command.to
|
|
248
|
+
})
|
|
253
249
|
);
|
|
254
250
|
|
|
255
|
-
this.
|
|
251
|
+
this.emit({ type: 'feed:completed' });
|
|
256
252
|
|
|
257
253
|
await accessor.session.dispose();
|
|
258
254
|
}
|
|
@@ -264,9 +260,9 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
264
260
|
async onTask(query: IpcTaskCommand, accessor: IpcSessionAccessor) {
|
|
265
261
|
accessor.session = accessor.session ?? live(this.descriptor);
|
|
266
262
|
|
|
267
|
-
await accessor.session.awake(
|
|
263
|
+
await accessor.session.awake(undefined);
|
|
268
264
|
|
|
269
|
-
this.
|
|
265
|
+
this.emit({ type: 'task:started', taskName: query.taskName });
|
|
270
266
|
|
|
271
267
|
let result = undefined;
|
|
272
268
|
|
|
@@ -276,15 +272,26 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
276
272
|
result = e;
|
|
277
273
|
}
|
|
278
274
|
|
|
279
|
-
this.
|
|
275
|
+
this.emit({ type: 'task:completed', taskName: query.taskName, result });
|
|
280
276
|
|
|
281
277
|
await accessor.session.dispose();
|
|
282
278
|
}
|
|
283
279
|
|
|
280
|
+
describe(): (session: Session) => Observable<any> {
|
|
281
|
+
const pkg = require(join(process.cwd(), 'package.json'));
|
|
282
|
+
const describe = require(join(process.cwd(), pkg.main))?.default;
|
|
283
|
+
|
|
284
|
+
if (describe instanceof Function) {
|
|
285
|
+
return describe;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return undefined;
|
|
289
|
+
}
|
|
290
|
+
|
|
284
291
|
/**
|
|
285
292
|
* Sends a message to parent process.
|
|
286
293
|
*/
|
|
287
|
-
private
|
|
294
|
+
private emit(message: any) {
|
|
288
295
|
if (process.send) {
|
|
289
296
|
process.send(message);
|
|
290
297
|
}
|
|
@@ -300,7 +307,7 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
300
307
|
* @returns new session.
|
|
301
308
|
*/
|
|
302
309
|
export async function run(
|
|
303
|
-
descriptor:
|
|
310
|
+
descriptor: IpcSessionDescriptor,
|
|
304
311
|
...commands: IpcCommand[]
|
|
305
312
|
): Promise<Session> {
|
|
306
313
|
const handler = new IpcHandler(descriptor);
|