@quantform/core 0.7.19 → 0.7.21
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/lib/cli/replay.d.ts +1 -0
- package/lib/cli/replay.d.ts.map +1 -1
- package/lib/cli/replay.js +4 -3
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/replay/index.d.ts +3 -6
- package/lib/replay/index.d.ts.map +1 -1
- package/lib/replay/index.js +3 -6
- package/lib/replay/use-replay-options.d.ts +6 -1
- package/lib/replay/use-replay-options.d.ts.map +1 -1
- package/lib/replay/use-replay-options.js +1 -1
- package/lib/{backtest/use-backtest-scheduler.d.ts → replay/use-replay-scheduler.d.ts} +4 -4
- package/lib/replay/use-replay-scheduler.d.ts.map +1 -0
- package/lib/{backtest/use-backtest-scheduler.js → replay/use-replay-scheduler.js} +6 -6
- package/lib/replay/{storage/use-replay-storage-buffer.d.ts → use-replay-storage-buffer.d.ts} +2 -2
- package/lib/replay/use-replay-storage-buffer.d.ts.map +1 -0
- package/lib/{backtest/use-backtest-query-buffer.js → replay/use-replay-storage-buffer.js} +6 -6
- package/lib/replay/{storage/use-replay-storage-cursor.d.ts → use-replay-storage-cursor.d.ts} +16 -2
- package/lib/replay/use-replay-storage-cursor.d.ts.map +1 -0
- package/lib/{backtest/use-backtest-query-cursor.js → replay/use-replay-storage-cursor.js} +4 -4
- package/lib/{backtest/use-backtest-storage.d.ts → replay/use-replay-storage.d.ts} +8 -4
- package/lib/replay/use-replay-storage.d.ts.map +1 -0
- package/lib/replay/use-replay-storage.js +77 -0
- package/lib/replay/use-replay-sync.d.ts +3 -0
- package/lib/replay/use-replay-sync.d.ts.map +1 -0
- package/lib/{backtest/use-backtest-sync.js → replay/use-replay-sync.js} +5 -5
- package/lib/replay/use-replay.d.ts +1 -9
- package/lib/replay/use-replay.d.ts.map +1 -1
- package/lib/replay/use-replay.js +3 -14
- package/lib/replay/when-replay-finished.js +2 -2
- package/lib/use-timestamp.js +2 -2
- package/package.json +1 -1
- package/src/cli/replay.ts +3 -2
- package/src/index.ts +1 -1
- package/src/replay/index.ts +3 -6
- package/src/replay/use-replay-options.ts +10 -2
- package/src/{backtest/use-backtest-scheduler.ts → replay/use-replay-scheduler.ts} +8 -9
- package/src/{backtest/use-backtest-query-buffer.ts → replay/use-replay-storage-buffer.ts} +5 -5
- package/src/replay/use-replay-storage-cursor.ts +48 -0
- package/src/replay/use-replay-storage.ts +101 -0
- package/src/{backtest/use-backtest-sync.ts → replay/use-replay-sync.ts} +3 -3
- package/src/replay/use-replay.ts +3 -24
- package/src/replay/when-replay-finished.ts +2 -2
- package/src/use-timestamp.ts +2 -2
- package/lib/backtest/index.d.ts +0 -7
- package/lib/backtest/index.d.ts.map +0 -1
- package/lib/backtest/index.js +0 -22
- package/lib/backtest/use-backtest-options.d.ts +0 -15
- package/lib/backtest/use-backtest-options.d.ts.map +0 -1
- package/lib/backtest/use-backtest-options.js +0 -20
- package/lib/backtest/use-backtest-query-buffer.d.ts +0 -15
- package/lib/backtest/use-backtest-query-buffer.d.ts.map +0 -1
- package/lib/backtest/use-backtest-query-cursor.d.ts +0 -30
- package/lib/backtest/use-backtest-query-cursor.d.ts.map +0 -1
- package/lib/backtest/use-backtest-scheduler.d.ts.map +0 -1
- package/lib/backtest/use-backtest-storage.d.ts.map +0 -1
- package/lib/backtest/use-backtest-storage.js +0 -65
- package/lib/backtest/use-backtest-sync.d.ts +0 -3
- package/lib/backtest/use-backtest-sync.d.ts.map +0 -1
- package/lib/backtest/use-backtest.d.ts +0 -24
- package/lib/backtest/use-backtest.d.ts.map +0 -1
- package/lib/backtest/use-backtest.js +0 -14
- package/lib/backtest/when-backtest-finished.d.ts +0 -2
- package/lib/backtest/when-backtest-finished.d.ts.map +0 -1
- package/lib/backtest/when-backtest-finished.js +0 -15
- package/lib/replay/replay-guard.d.ts +0 -10
- package/lib/replay/replay-guard.d.ts.map +0 -1
- package/lib/replay/replay-guard.js +0 -8
- package/lib/replay/replay.d.ts +0 -10
- package/lib/replay/replay.d.ts.map +0 -1
- package/lib/replay/replay.js +0 -9
- package/lib/replay/storage/use-replay-storage-buffer.d.ts.map +0 -1
- package/lib/replay/storage/use-replay-storage-buffer.js +0 -57
- package/lib/replay/storage/use-replay-storage-cursor.d.ts.map +0 -1
- package/lib/replay/storage/use-replay-storage-cursor.js +0 -49
- package/lib/replay/storage/use-replay-storage.d.ts +0 -13
- package/lib/replay/storage/use-replay-storage.d.ts.map +0 -1
- package/lib/replay/storage/use-replay-storage.js +0 -39
- package/lib/replay/storage/use-replay-storage.spec.d.ts +0 -2
- package/lib/replay/storage/use-replay-storage.spec.d.ts.map +0 -1
- package/lib/replay/storage/use-replay-storage.spec.js +0 -74
- package/lib/replay/use-replay-lock.d.ts +0 -3
- package/lib/replay/use-replay-lock.d.ts.map +0 -1
- package/lib/replay/use-replay-lock.js +0 -22
- package/lib/replay/use-replay-manager.d.ts +0 -28
- package/lib/replay/use-replay-manager.d.ts.map +0 -1
- package/lib/replay/use-replay-manager.js +0 -68
- package/lib/replay/use-replay.spec.d.ts +0 -2
- package/lib/replay/use-replay.spec.d.ts.map +0 -1
- package/lib/replay/use-replay.spec.js +0 -130
- package/src/backtest/index.ts +0 -6
- package/src/backtest/use-backtest-options.ts +0 -23
- package/src/backtest/use-backtest-query-cursor.ts +0 -40
- package/src/backtest/use-backtest-storage.ts +0 -82
- package/src/backtest/use-backtest.ts +0 -28
- package/src/backtest/when-backtest-finished.ts +0 -20
- package/src/replay/replay-guard.ts +0 -11
- package/src/replay/replay.ts +0 -13
- package/src/replay/storage/use-replay-storage-buffer.ts +0 -52
- package/src/replay/storage/use-replay-storage-cursor.ts +0 -44
- package/src/replay/storage/use-replay-storage.spec.ts +0 -84
- package/src/replay/storage/use-replay-storage.ts +0 -29
- package/src/replay/use-replay-lock.ts +0 -29
- package/src/replay/use-replay-manager.ts +0 -83
- package/src/replay/use-replay.spec.ts +0 -138
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.useReplayStorageCursor = void 0;
|
|
13
|
-
const use_hash_1 = require("../../use-hash");
|
|
14
|
-
const use_logger_1 = require("../../use-logger");
|
|
15
|
-
const with_memo_1 = require("../../with-memo");
|
|
16
|
-
const use_replay_storage_buffer_1 = require("./use-replay-storage-buffer");
|
|
17
|
-
exports.useReplayStorageCursor = (0, with_memo_1.withMemo)(() => {
|
|
18
|
-
const { info } = (0, use_logger_1.useLogger)('useReplayStorageCursor');
|
|
19
|
-
const storages = Array.of();
|
|
20
|
-
return {
|
|
21
|
-
get(dependencies) {
|
|
22
|
-
const storage = (0, use_replay_storage_buffer_1.useReplayStorageBuffer)(dependencies);
|
|
23
|
-
if (!storages.includes(storage)) {
|
|
24
|
-
info('opening a new replay buffer', (0, use_hash_1.useHash)(dependencies));
|
|
25
|
-
storages.push(storage);
|
|
26
|
-
}
|
|
27
|
-
return storage;
|
|
28
|
-
},
|
|
29
|
-
cursor() {
|
|
30
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
-
let current;
|
|
32
|
-
for (const storage of storages) {
|
|
33
|
-
if (storage.completed()) {
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
if (storage.size() == 0) {
|
|
37
|
-
yield storage.fetchNextPage();
|
|
38
|
-
}
|
|
39
|
-
if (storage.peek()) {
|
|
40
|
-
if (!current || current.peek().timestamp > storage.peek().timestamp) {
|
|
41
|
-
current = storage;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return current;
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Query, QueryObject } from '../../storage';
|
|
2
|
-
import { dependency } from '../../use-hash';
|
|
3
|
-
export declare function useReplayStorage<T>(dependencies: dependency[]): {
|
|
4
|
-
query(query: Query<QueryObject>): Promise<{
|
|
5
|
-
timestamp: number;
|
|
6
|
-
payload: T;
|
|
7
|
-
}[]>;
|
|
8
|
-
save(objects: {
|
|
9
|
-
timestamp: number;
|
|
10
|
-
payload: T;
|
|
11
|
-
}[]): Promise<void>;
|
|
12
|
-
};
|
|
13
|
-
//# sourceMappingURL=use-replay-storage.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-replay-storage.d.ts","sourceRoot":"","sources":["../../../src/replay/storage/use-replay-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,WAAW,EAAuB,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,UAAU,EAAW,MAAM,eAAe,CAAC;AAEpD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE;iBASvC,MAAM,WAAW,CAAC;;;;kBAMvB;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,CAAC,CAAA;KAAE,EAAE;EAUpD"}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.useReplayStorage = void 0;
|
|
13
|
-
const storage_1 = require("../../storage");
|
|
14
|
-
const use_hash_1 = require("../../use-hash");
|
|
15
|
-
function useReplayStorage(dependencies) {
|
|
16
|
-
const storage = (0, storage_1.useStorage)(['replay']);
|
|
17
|
-
const storageObjectKey = (0, use_hash_1.useHash)(dependencies);
|
|
18
|
-
const storageObject = storage_1.Storage.createObject(storageObjectKey, {
|
|
19
|
-
timestamp: 'number',
|
|
20
|
-
payload: 'string'
|
|
21
|
-
});
|
|
22
|
-
return {
|
|
23
|
-
query(query) {
|
|
24
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
-
return (yield storage.query(storageObject, query)).map(it => ({
|
|
26
|
-
timestamp: it.timestamp,
|
|
27
|
-
payload: JSON.parse(it.payload)
|
|
28
|
-
}));
|
|
29
|
-
});
|
|
30
|
-
},
|
|
31
|
-
save(objects) {
|
|
32
|
-
return storage.save(storageObject, objects.map(it => ({
|
|
33
|
-
timestamp: it.timestamp,
|
|
34
|
-
payload: JSON.stringify(it.payload)
|
|
35
|
-
})));
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
exports.useReplayStorage = useReplayStorage;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-replay-storage.spec.d.ts","sourceRoot":"","sources":["../../../src/replay/storage/use-replay-storage.spec.ts"],"names":[],"mappings":""}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
const make_test_module_1 = require("../../make-test-module");
|
|
13
|
-
const storage_1 = require("../../storage");
|
|
14
|
-
const use_replay_storage_1 = require("./use-replay-storage");
|
|
15
|
-
jest.mock('@lib/storage', () => (Object.assign(Object.assign({}, jest.requireActual('@lib/storage')), { useStorage: jest.fn() })));
|
|
16
|
-
describe(use_replay_storage_1.useReplayStorage.name, () => {
|
|
17
|
-
let fixtures;
|
|
18
|
-
beforeEach(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
19
|
-
fixtures = yield getFixtures();
|
|
20
|
-
}));
|
|
21
|
-
describe('query', () => {
|
|
22
|
-
test('happy path', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
23
|
-
yield fixtures.given.stored(fixtures.sample);
|
|
24
|
-
const sample = yield fixtures.when.queried({});
|
|
25
|
-
expect(sample).toEqual(fixtures.sample);
|
|
26
|
-
}));
|
|
27
|
-
});
|
|
28
|
-
describe('save', () => {
|
|
29
|
-
test('happy path', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
30
|
-
yield fixtures.when.saved(fixtures.sample);
|
|
31
|
-
yield fixtures.then.stored(fixtures.sample);
|
|
32
|
-
}));
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
function getFixtures() {
|
|
36
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
-
const { act } = yield (0, make_test_module_1.makeTestModule)([]);
|
|
38
|
-
const dependencies = ['binance:btc-usdt', 'candle', 'h1'];
|
|
39
|
-
const save = jest.fn();
|
|
40
|
-
const query = jest.fn();
|
|
41
|
-
(0, make_test_module_1.mockedFunc)(storage_1.useStorage).mockReturnValue({ save, query });
|
|
42
|
-
return {
|
|
43
|
-
sample: [
|
|
44
|
-
{ timestamp: 1, payload: { o: 1.1, h: 1.1, l: 1.1, c: 1.1 } },
|
|
45
|
-
{ timestamp: 2, payload: { o: 1.1, h: 2.2, l: 1.1, c: 2.2 } },
|
|
46
|
-
{ timestamp: 3, payload: { o: 1.1, h: 3.3, l: 1.1, c: 3.3 } }
|
|
47
|
-
],
|
|
48
|
-
given: {
|
|
49
|
-
stored(sample) {
|
|
50
|
-
return query.mockReturnValue(Promise.resolve(sample.map(it => ({
|
|
51
|
-
timestamp: it.timestamp,
|
|
52
|
-
payload: JSON.stringify(it.payload)
|
|
53
|
-
}))));
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
when: {
|
|
57
|
-
saved(sample) {
|
|
58
|
-
return act(() => (0, use_replay_storage_1.useReplayStorage)(dependencies).save(sample));
|
|
59
|
-
},
|
|
60
|
-
queried(query) {
|
|
61
|
-
return act(() => (0, use_replay_storage_1.useReplayStorage)(dependencies).query(query));
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
then: {
|
|
65
|
-
stored(sample) {
|
|
66
|
-
expect(save).toHaveBeenCalledWith(expect.anything(), sample.map(it => ({
|
|
67
|
-
timestamp: it.timestamp,
|
|
68
|
-
payload: JSON.stringify(it.payload)
|
|
69
|
-
})));
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
});
|
|
74
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-replay-lock.d.ts","sourceRoot":"","sources":["../../src/replay/use-replay-lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,UAAU,EAAE,MAAM,MAAM,CAAC;AAO5C,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAqBpE"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.useReplayLock = void 0;
|
|
4
|
-
const rxjs_1 = require("rxjs");
|
|
5
|
-
const use_execution_mode_1 = require("../use-execution-mode");
|
|
6
|
-
const use_logger_1 = require("../use-logger");
|
|
7
|
-
const use_replay_manager_1 = require("./use-replay-manager");
|
|
8
|
-
function useReplayLock(input) {
|
|
9
|
-
const { isReplay } = (0, use_execution_mode_1.useExecutionMode)();
|
|
10
|
-
if (!isReplay) {
|
|
11
|
-
return input;
|
|
12
|
-
}
|
|
13
|
-
const { info } = (0, use_logger_1.useLogger)('replay');
|
|
14
|
-
const { stop, tryContinue } = (0, use_replay_manager_1.useReplayManager)();
|
|
15
|
-
info('lock acquired');
|
|
16
|
-
stop();
|
|
17
|
-
return input.pipe((0, rxjs_1.finalize)(() => {
|
|
18
|
-
info('lock released');
|
|
19
|
-
tryContinue();
|
|
20
|
-
}));
|
|
21
|
-
}
|
|
22
|
-
exports.useReplayLock = useReplayLock;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { Observable } from 'rxjs';
|
|
2
|
-
import { dependency } from '../use-hash';
|
|
3
|
-
export declare const useReplayManager: () => {
|
|
4
|
-
stream: Observable<[{
|
|
5
|
-
size(): number;
|
|
6
|
-
peek(): {
|
|
7
|
-
timestamp: number;
|
|
8
|
-
payload: any;
|
|
9
|
-
};
|
|
10
|
-
dequeue(): {
|
|
11
|
-
timestamp: number;
|
|
12
|
-
payload: any;
|
|
13
|
-
};
|
|
14
|
-
completed(): boolean;
|
|
15
|
-
fetchNextPage(): Promise<void>;
|
|
16
|
-
}, {
|
|
17
|
-
timestamp: number;
|
|
18
|
-
payload: any;
|
|
19
|
-
}]>;
|
|
20
|
-
timestamp(): number;
|
|
21
|
-
stop(): void;
|
|
22
|
-
tryContinue: () => void;
|
|
23
|
-
watch<T>(dependencies: dependency[]): Observable<{
|
|
24
|
-
timestamp: number;
|
|
25
|
-
payload: T;
|
|
26
|
-
}>;
|
|
27
|
-
};
|
|
28
|
-
//# sourceMappingURL=use-replay-manager.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-replay-manager.d.ts","sourceRoot":"","sources":["../../src/replay/use-replay-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,UAAU,EAAW,MAAM,MAAM,CAAC;AAE/D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAO3C,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;mBAQqC,MAAM;iBAAW,GAAG;;;;;2BAoD3D,UAAU,EAAE;mBAA2B,MAAM;;;CAatE,CAAC"}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.useReplayManager = void 0;
|
|
13
|
-
const rxjs_1 = require("rxjs");
|
|
14
|
-
const with_memo_1 = require("../with-memo");
|
|
15
|
-
const use_replay_storage_cursor_1 = require("./storage/use-replay-storage-cursor");
|
|
16
|
-
const use_replay_options_1 = require("./use-replay-options");
|
|
17
|
-
exports.useReplayManager = (0, with_memo_1.withMemo)(() => {
|
|
18
|
-
const { from } = (0, use_replay_options_1.useReplayOptions)();
|
|
19
|
-
const { get, cursor } = (0, use_replay_storage_cursor_1.useReplayStorageCursor)();
|
|
20
|
-
let timestamp = from;
|
|
21
|
-
let stopAcquire = 1;
|
|
22
|
-
const stream$ = new rxjs_1.Subject();
|
|
23
|
-
const processNext = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
|
-
const storage = yield cursor();
|
|
25
|
-
if (!storage || !storage.peek()) {
|
|
26
|
-
stream$.complete();
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
const sample = storage.dequeue();
|
|
30
|
-
timestamp = sample.timestamp;
|
|
31
|
-
stream$.next([storage, sample]);
|
|
32
|
-
return true;
|
|
33
|
-
});
|
|
34
|
-
const next = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
35
|
-
if (yield processNext()) {
|
|
36
|
-
if (stopAcquire === 0) {
|
|
37
|
-
setImmediate(next);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
const tryContinue = () => {
|
|
42
|
-
if (stopAcquire == 0) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
stopAcquire = Math.max(0, stopAcquire - 1);
|
|
46
|
-
if (stopAcquire != 0) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
next();
|
|
50
|
-
};
|
|
51
|
-
return {
|
|
52
|
-
stream: stream$.asObservable(),
|
|
53
|
-
timestamp() {
|
|
54
|
-
return timestamp;
|
|
55
|
-
},
|
|
56
|
-
stop() {
|
|
57
|
-
stopAcquire++;
|
|
58
|
-
},
|
|
59
|
-
tryContinue,
|
|
60
|
-
watch(dependencies) {
|
|
61
|
-
const storage = get(dependencies);
|
|
62
|
-
return (0, rxjs_1.defer)(() => {
|
|
63
|
-
tryContinue();
|
|
64
|
-
return stream$.pipe((0, rxjs_1.filter)(([cur]) => cur === storage), (0, rxjs_1.map)(([, it]) => ({ timestamp: it.timestamp, payload: it.payload })));
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-replay.spec.d.ts","sourceRoot":"","sources":["../../src/replay/use-replay.spec.ts"],"names":[],"mappings":""}
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const use_replay_1 = require("./use-replay");
|
|
4
|
-
describe(use_replay_1.useReplay.name, () => {
|
|
5
|
-
test('happy path', () => {
|
|
6
|
-
expect(true).toBe(true);
|
|
7
|
-
});
|
|
8
|
-
});
|
|
9
|
-
/*
|
|
10
|
-
|
|
11
|
-
describe.skip(useReplayCoordinator.name, () => {
|
|
12
|
-
let fixtures: Awaited<ReturnType<typeof getFixtures>>;
|
|
13
|
-
|
|
14
|
-
beforeEach(async () => {
|
|
15
|
-
fixtures = await getFixtures();
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test('return single data stream for single data source', async () => {
|
|
19
|
-
fixtures.givenRecordingEnabled(false);
|
|
20
|
-
await fixtures.givenSampleStored(fixtures.sample1, ['sample1']);
|
|
21
|
-
|
|
22
|
-
const sample1 = fixtures.whenUseReplayCalled(fixtures.sample1, ['sample']);
|
|
23
|
-
await fixtures.whenUseSampleStreamerStarted();
|
|
24
|
-
|
|
25
|
-
expect(await sample1).toEqual(fixtures.sample1);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test('return combined data stream for multiple data sources', async () => {
|
|
29
|
-
fixtures.givenRecordingEnabled(false);
|
|
30
|
-
await fixtures.givenSampleStored(fixtures.sample1, ['sample1']);
|
|
31
|
-
await fixtures.givenSampleStored(fixtures.sample2, ['sample2']);
|
|
32
|
-
|
|
33
|
-
const sample1 = fixtures.whenUseReplayCalled(fixtures.sample1, ['sample1']);
|
|
34
|
-
const sample2 = fixtures.whenUseReplayCalled(fixtures.sample2, ['sample2']);
|
|
35
|
-
await fixtures.whenUseSampleStreamerStarted();
|
|
36
|
-
|
|
37
|
-
expect(await sample1).toEqual(fixtures.sample1);
|
|
38
|
-
expect(await sample2).toEqual(fixtures.sample2);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test('record and write data stream into storage', async () => {
|
|
42
|
-
fixtures.givenRecordingEnabled(true);
|
|
43
|
-
const sample1 = await fixtures.whenUseReplayCalled(fixtures.sample1, ['sample1x']);
|
|
44
|
-
const sample2 = await fixtures.whenUseReplayCalled(fixtures.sample2, ['sample2x']);
|
|
45
|
-
|
|
46
|
-
fixtures.thenReplaySampleStored(sample1, ['sample1x']);
|
|
47
|
-
fixtures.thenReplaySampleStored(sample2, ['sample2x']);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
async function getFixtures() {
|
|
52
|
-
const executionMode = replayExecutionMode();
|
|
53
|
-
|
|
54
|
-
const { act } = await makeTestModule([
|
|
55
|
-
executionMode,
|
|
56
|
-
replayOptions({ from: 0, to: Number.MAX_VALUE })
|
|
57
|
-
]);
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
sample1: [
|
|
61
|
-
{ timestamp: 1, payload: { o: 111, h: 112, l: 113, c: 114 } },
|
|
62
|
-
{ timestamp: 2, payload: { o: 121, h: 122, l: 123, c: 124 } },
|
|
63
|
-
{ timestamp: 3, payload: { o: 131, h: 132, l: 133, c: 134 } }
|
|
64
|
-
],
|
|
65
|
-
sample2: [
|
|
66
|
-
{ timestamp: 1, payload: { o: 211, h: 212, l: 213, c: 214 } },
|
|
67
|
-
{ timestamp: 2, payload: { o: 221, h: 222, l: 223, c: 224 } },
|
|
68
|
-
{ timestamp: 3, payload: { o: 231, h: 232, l: 233, c: 234 } }
|
|
69
|
-
],
|
|
70
|
-
|
|
71
|
-
givenRecordingEnabled(recording: boolean) {
|
|
72
|
-
executionMode.useValue.recording = recording;
|
|
73
|
-
},
|
|
74
|
-
|
|
75
|
-
givenSampleStored<T>(
|
|
76
|
-
sample: { timestamp: number; payload: T }[],
|
|
77
|
-
dependencies: dependency[]
|
|
78
|
-
) {
|
|
79
|
-
return act(() => {
|
|
80
|
-
const writer = useReplayWriter(dependencies);
|
|
81
|
-
|
|
82
|
-
return writer(sample);
|
|
83
|
-
});
|
|
84
|
-
},
|
|
85
|
-
|
|
86
|
-
async whenUseReplayCalled<T>(
|
|
87
|
-
input: { timestamp: number; payload: T }[],
|
|
88
|
-
dependencies: dependency[]
|
|
89
|
-
) {
|
|
90
|
-
const sample = Array.of<{ timestamp: number; payload: T }>();
|
|
91
|
-
|
|
92
|
-
await act(() =>
|
|
93
|
-
lastValueFrom(
|
|
94
|
-
useReplay<T>(from(input), dependencies).pipe(tap(it => sample.push(it)))
|
|
95
|
-
)
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
return sample;
|
|
99
|
-
},
|
|
100
|
-
|
|
101
|
-
whenUseSampleStreamerStarted() {
|
|
102
|
-
act(() => {
|
|
103
|
-
const { tryContinue } = useReplayCoordinator();
|
|
104
|
-
|
|
105
|
-
tryContinue();
|
|
106
|
-
});
|
|
107
|
-
},
|
|
108
|
-
|
|
109
|
-
async thenReplaySampleStored<T extends { timestamp: number }>(
|
|
110
|
-
sample: T[],
|
|
111
|
-
dependencies: dependency[]
|
|
112
|
-
) {
|
|
113
|
-
const stored = await act(() => {
|
|
114
|
-
const reader = useReplayReader(dependencies);
|
|
115
|
-
|
|
116
|
-
return reader({
|
|
117
|
-
where: {
|
|
118
|
-
timestamp: between(
|
|
119
|
-
sample[0].timestamp,
|
|
120
|
-
sample[sample.length - 1].timestamp + 1
|
|
121
|
-
)
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
expect(stored).toEqual(sample);
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
*/
|
package/src/backtest/index.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Dependency, useContext } from '@lib/module';
|
|
2
|
-
|
|
3
|
-
const injectionToken = Symbol('backtest-options');
|
|
4
|
-
|
|
5
|
-
type BacktestOptions = {
|
|
6
|
-
from: number;
|
|
7
|
-
to: number;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
*
|
|
12
|
-
*/
|
|
13
|
-
export function backtestOptions(options: BacktestOptions): Dependency {
|
|
14
|
-
return {
|
|
15
|
-
provide: injectionToken,
|
|
16
|
-
useValue: options
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Will return current backtest execution options.
|
|
22
|
-
*/
|
|
23
|
-
export const useBacktestOptions = () => useContext<BacktestOptions>(injectionToken);
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { withMemo } from '@lib/with-memo';
|
|
2
|
-
|
|
3
|
-
import { BacktestStorage } from './use-backtest';
|
|
4
|
-
import { useBacktestQueryBuffer } from './use-backtest-query-buffer';
|
|
5
|
-
|
|
6
|
-
export const useBacktestQueryCursor = withMemo(() => {
|
|
7
|
-
const cursors = Array.of<ReturnType<typeof useBacktestQueryBuffer<any>>>();
|
|
8
|
-
|
|
9
|
-
return {
|
|
10
|
-
get<T>(query: BacktestStorage<T>) {
|
|
11
|
-
const buffer = useBacktestQueryBuffer<T>(query);
|
|
12
|
-
|
|
13
|
-
cursors.push(buffer);
|
|
14
|
-
|
|
15
|
-
return buffer;
|
|
16
|
-
},
|
|
17
|
-
|
|
18
|
-
async cursor() {
|
|
19
|
-
let current: ReturnType<typeof useBacktestQueryBuffer<any>> | undefined;
|
|
20
|
-
|
|
21
|
-
for (const cursor of cursors) {
|
|
22
|
-
if (cursor.completed()) {
|
|
23
|
-
continue;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (cursor.size() == 0) {
|
|
27
|
-
await cursor.fetchNextPage();
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (cursor.peek()) {
|
|
31
|
-
if (!current || current.peek().timestamp > cursor.peek().timestamp) {
|
|
32
|
-
current = cursor;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return current;
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
});
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { hashCode } from '@lib/hash-code';
|
|
2
|
-
import {
|
|
3
|
-
eq,
|
|
4
|
-
InferQueryObject,
|
|
5
|
-
Query,
|
|
6
|
-
QueryObject,
|
|
7
|
-
QueryObjectType,
|
|
8
|
-
Storage,
|
|
9
|
-
useStorage
|
|
10
|
-
} from '@lib/storage';
|
|
11
|
-
import { Uri } from '@lib/uri';
|
|
12
|
-
|
|
13
|
-
import { BacktestStorage } from './use-backtest';
|
|
14
|
-
|
|
15
|
-
export type BacktestStorageQuery<V> = {
|
|
16
|
-
sync: <T extends QueryObjectType<K>, K extends QueryObject>(
|
|
17
|
-
query: Query<InferQueryObject<T>> & {
|
|
18
|
-
where: { timestamp: { type: 'between'; min: number; max: number } };
|
|
19
|
-
},
|
|
20
|
-
storage: { save: (objects: { timestamp: number; payload: V }[]) => Promise<void> }
|
|
21
|
-
) => Promise<void>;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const storageIndexObject = Storage.createObject('index://range', {
|
|
25
|
-
timestamp: 'number',
|
|
26
|
-
uri: 'string',
|
|
27
|
-
min: 'number',
|
|
28
|
-
max: 'number'
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
export function useBacktestStorage<V, P extends Record<string, string | number>>(
|
|
32
|
-
uri: Uri<P>,
|
|
33
|
-
{ sync }: BacktestStorageQuery<V>
|
|
34
|
-
): BacktestStorage<V> {
|
|
35
|
-
const storage = useStorage(['backtest']);
|
|
36
|
-
const storageObjectKey = uri.query;
|
|
37
|
-
const storageObject = Storage.createObject(storageObjectKey, {
|
|
38
|
-
timestamp: 'number',
|
|
39
|
-
payload: 'string'
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
const id = hashCode(storageObjectKey);
|
|
43
|
-
|
|
44
|
-
return {
|
|
45
|
-
async query(query) {
|
|
46
|
-
const [index] = await storage.query(storageIndexObject, {
|
|
47
|
-
limit: 1,
|
|
48
|
-
where: { timestamp: eq(id) }
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const { min, max } = query.where.timestamp;
|
|
52
|
-
|
|
53
|
-
if (!index || min < index.min || max > index.max) {
|
|
54
|
-
await sync(query, {
|
|
55
|
-
async save(objects) {
|
|
56
|
-
await storage.save(
|
|
57
|
-
storageObject,
|
|
58
|
-
objects.map(it => ({
|
|
59
|
-
timestamp: it.timestamp,
|
|
60
|
-
payload: JSON.stringify(it.payload)
|
|
61
|
-
}))
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
await storage.save(storageIndexObject, [
|
|
67
|
-
{
|
|
68
|
-
timestamp: id,
|
|
69
|
-
max,
|
|
70
|
-
min,
|
|
71
|
-
uri: storageObjectKey
|
|
72
|
-
}
|
|
73
|
-
]);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return (await storage.query(storageObject, query)).map(it => ({
|
|
77
|
-
timestamp: it.timestamp,
|
|
78
|
-
payload: JSON.parse(it.payload) as V
|
|
79
|
-
}));
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { Observable } from 'rxjs';
|
|
2
|
-
|
|
3
|
-
import { Query, QueryObject } from '@lib/storage';
|
|
4
|
-
import { useExecutionMode } from '@lib/use-execution-mode';
|
|
5
|
-
|
|
6
|
-
import { useBacktestScheduler } from './use-backtest-scheduler';
|
|
7
|
-
|
|
8
|
-
export interface BacktestStorage<V> {
|
|
9
|
-
query(
|
|
10
|
-
query: Query<QueryObject> & {
|
|
11
|
-
where: { timestamp: { type: 'between'; min: number; max: number } };
|
|
12
|
-
}
|
|
13
|
-
): Promise<{ timestamp: number; payload: V }[]>;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function useBacktest<T>(
|
|
17
|
-
input: Observable<{ timestamp: number; payload: T }>,
|
|
18
|
-
query: BacktestStorage<T>
|
|
19
|
-
) {
|
|
20
|
-
const { isReplay } = useExecutionMode();
|
|
21
|
-
|
|
22
|
-
if (isReplay) {
|
|
23
|
-
const { watch } = useBacktestScheduler();
|
|
24
|
-
return watch<T>(query);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return input;
|
|
28
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { from, last, map, Subject } from 'rxjs';
|
|
2
|
-
|
|
3
|
-
import { useExecutionMode } from '@lib/use-execution-mode';
|
|
4
|
-
|
|
5
|
-
import { useBacktestScheduler } from './use-backtest-scheduler';
|
|
6
|
-
|
|
7
|
-
export function whenBacktestFinished() {
|
|
8
|
-
const { isReplay } = useExecutionMode();
|
|
9
|
-
|
|
10
|
-
if (!isReplay) {
|
|
11
|
-
return new Subject<boolean>().asObservable();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const { stream } = useBacktestScheduler();
|
|
15
|
-
|
|
16
|
-
return from(stream).pipe(
|
|
17
|
-
last(),
|
|
18
|
-
map(() => true)
|
|
19
|
-
);
|
|
20
|
-
}
|