@quantform/core 0.3.242 → 0.3.248
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 +64 -54
- 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 +2 -2
- 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/store/event/store-order.event.js +0 -8
- package/dist/store/event/store-order.event.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 +2 -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 +90 -89
- package/src/session/session-descriptor.ts +7 -4
- package/src/session/session.spec.ts +1 -5
- package/src/session/session.ts +10 -49
- package/src/store/event/store-order.event.ts +0 -12
- 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,12 +1,17 @@
|
|
|
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');
|
|
11
|
+
import dotenv = require('dotenv');
|
|
12
|
+
|
|
13
|
+
// force to load environment variables from .env file if this file imported.
|
|
14
|
+
dotenv.config();
|
|
10
15
|
|
|
11
16
|
/**
|
|
12
17
|
* Base command/query interface for IPC communication.
|
|
@@ -42,12 +47,6 @@ export class IpcPaperCommand implements IpcCommand {
|
|
|
42
47
|
* The optional session identifier.
|
|
43
48
|
*/
|
|
44
49
|
id?: number;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Specifies trading balance, for example:
|
|
48
|
-
* { "binance:usdt": 1000 }
|
|
49
|
-
*/
|
|
50
|
-
balance: { [key: string]: number };
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
/**
|
|
@@ -58,20 +57,14 @@ export class IpcBacktestCommand implements IpcCommand {
|
|
|
58
57
|
type = 'backtest';
|
|
59
58
|
|
|
60
59
|
/**
|
|
61
|
-
* Start date of the
|
|
62
|
-
*/
|
|
63
|
-
from: number;
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Due date of the backtest in unix timestamp.
|
|
60
|
+
* Start date of the feed in unix timestamp.
|
|
67
61
|
*/
|
|
68
|
-
|
|
62
|
+
from?: number;
|
|
69
63
|
|
|
70
64
|
/**
|
|
71
|
-
*
|
|
72
|
-
* { "binance:usdt": 1000 }
|
|
65
|
+
* Due date of the feed in unix timestamp.
|
|
73
66
|
*/
|
|
74
|
-
|
|
67
|
+
to?: number;
|
|
75
68
|
}
|
|
76
69
|
|
|
77
70
|
/**
|
|
@@ -89,12 +82,12 @@ export class IpcFeedCommand implements IpcCommand {
|
|
|
89
82
|
/**
|
|
90
83
|
* Start date of the feed in unix timestamp.
|
|
91
84
|
*/
|
|
92
|
-
from
|
|
85
|
+
from?: number;
|
|
93
86
|
|
|
94
87
|
/**
|
|
95
88
|
* Due date of the feed in unix timestamp.
|
|
96
89
|
*/
|
|
97
|
-
to
|
|
90
|
+
to?: number;
|
|
98
91
|
}
|
|
99
92
|
|
|
100
93
|
/**
|
|
@@ -117,13 +110,13 @@ class IpcSessionAccessor {
|
|
|
117
110
|
session: Session;
|
|
118
111
|
}
|
|
119
112
|
|
|
120
|
-
export declare type
|
|
113
|
+
export declare type IpcSessionDescriptor = SessionDescriptor & { ipcSub?: EventEmitter };
|
|
121
114
|
|
|
122
115
|
/**
|
|
123
116
|
* Inter process communication handler.
|
|
124
117
|
*/
|
|
125
118
|
class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
126
|
-
constructor(private readonly descriptor:
|
|
119
|
+
constructor(private readonly descriptor: IpcSessionDescriptor) {
|
|
127
120
|
super();
|
|
128
121
|
}
|
|
129
122
|
|
|
@@ -138,12 +131,12 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
138
131
|
|
|
139
132
|
accessor.session = live(this.descriptor);
|
|
140
133
|
|
|
141
|
-
this.
|
|
134
|
+
this.emit({
|
|
142
135
|
type: 'live:started',
|
|
143
136
|
session: accessor.session.descriptor?.id
|
|
144
137
|
});
|
|
145
138
|
|
|
146
|
-
await accessor.session.awake();
|
|
139
|
+
await accessor.session.awake(this.describe());
|
|
147
140
|
}
|
|
148
141
|
|
|
149
142
|
/**
|
|
@@ -155,16 +148,14 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
155
148
|
this.descriptor.id = command.id;
|
|
156
149
|
}
|
|
157
150
|
|
|
158
|
-
accessor.session = paper(this.descriptor
|
|
159
|
-
balance: command.balance
|
|
160
|
-
});
|
|
151
|
+
accessor.session = paper(this.descriptor);
|
|
161
152
|
|
|
162
|
-
this.
|
|
153
|
+
this.emit({
|
|
163
154
|
type: 'paper:started',
|
|
164
155
|
session: accessor.session.descriptor?.id
|
|
165
156
|
});
|
|
166
157
|
|
|
167
|
-
await accessor.session.awake();
|
|
158
|
+
await accessor.session.awake(this.describe());
|
|
168
159
|
}
|
|
169
160
|
|
|
170
161
|
/**
|
|
@@ -172,49 +163,51 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
172
163
|
*/
|
|
173
164
|
@handler(IpcBacktestCommand)
|
|
174
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
|
+
|
|
175
173
|
return new Promise<void>(async resolve => {
|
|
176
174
|
const [session, streamer] = backtest(this.descriptor, {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
this.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
this.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
this.
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
to: command.to
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
resolve();
|
|
211
|
-
}
|
|
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();
|
|
212
205
|
}
|
|
213
206
|
});
|
|
214
207
|
|
|
215
208
|
accessor.session = session;
|
|
216
209
|
|
|
217
|
-
await accessor.session.awake();
|
|
210
|
+
await accessor.session.awake(this.describe());
|
|
218
211
|
await streamer.tryContinue().catch(it => Logger.error(it));
|
|
219
212
|
});
|
|
220
213
|
}
|
|
@@ -227,28 +220,25 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
227
220
|
accessor.session = accessor.session ?? live(this.descriptor);
|
|
228
221
|
const instrument = instrumentOf(command.instrument);
|
|
229
222
|
|
|
230
|
-
await accessor.session.awake(
|
|
231
|
-
|
|
232
|
-
this.
|
|
233
|
-
|
|
234
|
-
await accessor.session.aggregate.
|
|
235
|
-
instrument
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
this.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
to: command.to
|
|
247
|
-
})
|
|
248
|
-
)
|
|
223
|
+
await accessor.session.awake(undefined);
|
|
224
|
+
|
|
225
|
+
this.emit({ type: 'feed:started' });
|
|
226
|
+
|
|
227
|
+
await accessor.session.aggregate.feed(
|
|
228
|
+
instrument,
|
|
229
|
+
command.from,
|
|
230
|
+
command.to,
|
|
231
|
+
this.descriptor.feed,
|
|
232
|
+
timestamp =>
|
|
233
|
+
this.emit({
|
|
234
|
+
type: 'feed:updated',
|
|
235
|
+
timestamp,
|
|
236
|
+
from: command.from,
|
|
237
|
+
to: command.to
|
|
238
|
+
})
|
|
249
239
|
);
|
|
250
240
|
|
|
251
|
-
this.
|
|
241
|
+
this.emit({ type: 'feed:completed' });
|
|
252
242
|
|
|
253
243
|
await accessor.session.dispose();
|
|
254
244
|
}
|
|
@@ -260,9 +250,9 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
260
250
|
async onTask(query: IpcTaskCommand, accessor: IpcSessionAccessor) {
|
|
261
251
|
accessor.session = accessor.session ?? live(this.descriptor);
|
|
262
252
|
|
|
263
|
-
await accessor.session.awake(
|
|
253
|
+
await accessor.session.awake(undefined);
|
|
264
254
|
|
|
265
|
-
this.
|
|
255
|
+
this.emit({ type: 'task:started', taskName: query.taskName });
|
|
266
256
|
|
|
267
257
|
let result = undefined;
|
|
268
258
|
|
|
@@ -272,15 +262,26 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
272
262
|
result = e;
|
|
273
263
|
}
|
|
274
264
|
|
|
275
|
-
this.
|
|
265
|
+
this.emit({ type: 'task:completed', taskName: query.taskName, result });
|
|
276
266
|
|
|
277
267
|
await accessor.session.dispose();
|
|
278
268
|
}
|
|
279
269
|
|
|
270
|
+
describe(): (session: Session) => Observable<any> {
|
|
271
|
+
const pkg = require(join(process.cwd(), 'package.json'));
|
|
272
|
+
const describe = require(join(process.cwd(), pkg.main))?.default;
|
|
273
|
+
|
|
274
|
+
if (describe instanceof Function) {
|
|
275
|
+
return describe;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return undefined;
|
|
279
|
+
}
|
|
280
|
+
|
|
280
281
|
/**
|
|
281
282
|
* Sends a message to parent process.
|
|
282
283
|
*/
|
|
283
|
-
private
|
|
284
|
+
private emit(message: any) {
|
|
284
285
|
if (process.send) {
|
|
285
286
|
process.send(message);
|
|
286
287
|
}
|
|
@@ -296,7 +297,7 @@ class IpcHandler extends Topic<{ type: string }, IpcSessionAccessor> {
|
|
|
296
297
|
* @returns new session.
|
|
297
298
|
*/
|
|
298
299
|
export async function run(
|
|
299
|
-
descriptor:
|
|
300
|
+
descriptor: IpcSessionDescriptor,
|
|
300
301
|
...commands: IpcCommand[]
|
|
301
302
|
): Promise<Session> {
|
|
302
303
|
const handler = new IpcHandler(descriptor);
|