@quantform/core 0.7.0-beta.47 → 0.7.0-beta.49

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.
Files changed (49) hide show
  1. package/dist/cli/internal/script.d.ts +2 -2
  2. package/dist/cli/internal/script.d.ts.map +1 -1
  3. package/dist/cli/internal/script.js +9 -6
  4. package/dist/replay/index.d.ts +2 -2
  5. package/dist/replay/index.d.ts.map +1 -1
  6. package/dist/replay/index.js +2 -2
  7. package/dist/replay/{use-replay-storage-buffer.d.ts → storage/use-replay-storage-buffer.d.ts} +2 -2
  8. package/dist/replay/storage/use-replay-storage-buffer.d.ts.map +1 -0
  9. package/dist/replay/{use-replay-storage-buffer.js → storage/use-replay-storage-buffer.js} +10 -4
  10. package/dist/replay/storage/use-replay-storage-cursor.d.ts +30 -0
  11. package/dist/replay/storage/use-replay-storage-cursor.d.ts.map +1 -0
  12. package/dist/replay/storage/use-replay-storage-cursor.js +49 -0
  13. package/dist/replay/{use-replay-storage.d.ts → storage/use-replay-storage.d.ts} +2 -2
  14. package/dist/replay/storage/use-replay-storage.d.ts.map +1 -0
  15. package/dist/replay/{use-replay-storage.js → storage/use-replay-storage.js} +2 -2
  16. package/dist/replay/storage/use-replay-storage.spec.d.ts.map +1 -0
  17. package/dist/replay/{use-replay-storage.spec.js → storage/use-replay-storage.spec.js} +2 -2
  18. package/dist/replay/use-replay-breakpoint.js +3 -3
  19. package/dist/replay/use-replay-manager.d.ts +2 -2
  20. package/dist/replay/use-replay-manager.d.ts.map +1 -1
  21. package/dist/replay/use-replay-manager.js +9 -30
  22. package/dist/replay/use-replay.js +3 -3
  23. package/dist/shared/decimals.d.ts +0 -16
  24. package/dist/shared/decimals.d.ts.map +1 -1
  25. package/dist/shared/decimals.js +1 -44
  26. package/dist/strategy.d.ts.map +1 -1
  27. package/dist/strategy.js +7 -0
  28. package/dist/use-execution-mode.js +7 -7
  29. package/dist/use-socket.d.ts +19 -0
  30. package/dist/use-socket.d.ts.map +1 -0
  31. package/dist/use-socket.js +69 -0
  32. package/package.json +1 -1
  33. package/src/cli/internal/script.ts +14 -7
  34. package/src/replay/index.ts +2 -2
  35. package/src/replay/{use-replay-storage-buffer.ts → storage/use-replay-storage-buffer.ts} +9 -2
  36. package/src/replay/storage/use-replay-storage-cursor.ts +44 -0
  37. package/src/replay/{use-replay-storage.spec.ts → storage/use-replay-storage.spec.ts} +0 -1
  38. package/src/replay/use-replay-breakpoint.ts +3 -3
  39. package/src/replay/use-replay-manager.ts +11 -35
  40. package/src/replay/use-replay.ts +3 -3
  41. package/src/shared/decimals.ts +0 -45
  42. package/src/strategy.ts +9 -1
  43. package/src/use-execution-mode.ts +7 -7
  44. package/src/use-socket.ts +78 -0
  45. package/dist/replay/use-replay-storage-buffer.d.ts.map +0 -1
  46. package/dist/replay/use-replay-storage.d.ts.map +0 -1
  47. package/dist/replay/use-replay-storage.spec.d.ts.map +0 -1
  48. /package/dist/replay/{use-replay-storage.spec.d.ts → storage/use-replay-storage.spec.d.ts} +0 -0
  49. /package/src/replay/{use-replay-storage.ts → storage/use-replay-storage.ts} +0 -0
@@ -1,8 +1,8 @@
1
1
  import { Dependency } from '../../module';
2
2
  export declare class Script {
3
- private readonly name;
3
+ private readonly filename;
4
4
  private readonly dependencies;
5
- constructor(name: string, dependencies: Dependency[]);
5
+ constructor(filename: string, dependencies: Dependency[]);
6
6
  run(): Promise<unknown[]>;
7
7
  }
8
8
  //# sourceMappingURL=script.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"script.d.ts","sourceRoot":"","sources":["../../../src/cli/internal/script.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,UAAU,EAAU,MAAM,aAAa,CAAC;AAMjD,qBAAa,MAAM;IAEf,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,YAAY;gBADZ,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,UAAU,EAAE;IAGvC,GAAG;CAmCV"}
1
+ {"version":3,"file":"script.d.ts","sourceRoot":"","sources":["../../../src/cli/internal/script.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,UAAU,EAAU,MAAM,aAAa,CAAC;AAMjD,qBAAa,MAAM;IAEf,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,YAAY;gBADZ,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,UAAU,EAAE;IAGvC,GAAG;CA0CV"}
@@ -40,21 +40,24 @@ const module_1 = require("../../module");
40
40
  const replay_1 = require("../../replay");
41
41
  const workspace_1 = require("./workspace");
42
42
  class Script {
43
- constructor(name, dependencies) {
44
- this.name = name;
43
+ constructor(filename, dependencies) {
44
+ this.filename = filename;
45
45
  this.dependencies = dependencies;
46
46
  }
47
47
  run() {
48
48
  return __awaiter(this, void 0, void 0, function* () {
49
- const script = yield Promise.resolve(`${(0, path_1.join)((0, workspace_1.buildDirectory)(), this.name)}`).then(s => __importStar(require(s)));
49
+ const script = yield Promise.resolve(`${(0, path_1.join)((0, workspace_1.buildDirectory)(), this.filename)}`).then(s => __importStar(require(s)));
50
50
  const { dependencies, description } = script.default;
51
51
  const module = new module_1.Module([...(0, core_1.core)(), ...dependencies, ...this.dependencies]);
52
52
  const { act } = yield module.awake();
53
53
  return yield act(() => {
54
54
  process.stdin.resume();
55
- return (0, rxjs_1.firstValueFrom)((0, rxjs_1.merge)((0, rxjs_1.forkJoin)(description.before.map(it => it()))
56
- .pipe((0, rxjs_1.switchMap)(() => (0, rxjs_1.forkJoin)(description.behavior.map(it => it())).pipe((0, rxjs_1.last)())))
57
- .pipe((0, rxjs_1.last)()), (0, replay_1.whenReplayFinished)().pipe((0, rxjs_1.last)()), (0, rxjs_1.fromEvent)(process, 'exit'), (0, rxjs_1.fromEvent)(process, 'SIGINT'), (0, rxjs_1.fromEvent)(process, 'SIGUSR1'), (0, rxjs_1.fromEvent)(process, 'SIGUSR2'), (0, rxjs_1.fromEvent)(process, 'uncaughtException')).pipe((0, rxjs_1.take)(1), (0, rxjs_1.switchMap)(it => { var _a; return (_a = (0, rxjs_1.forkJoin)(description.after.map(it => it())).pipe((0, rxjs_1.last)())) !== null && _a !== void 0 ? _a : (0, rxjs_1.of)(it); }), (0, rxjs_1.finalize)(() => process.exit(0))));
55
+ return (0, rxjs_1.firstValueFrom)((0, rxjs_1.merge)((0, rxjs_1.forkJoin)(description.before.map(before => before()))
56
+ .pipe((0, rxjs_1.switchMap)(() => (0, rxjs_1.forkJoin)(description.behavior.map(behavior => behavior())).pipe((0, rxjs_1.last)())))
57
+ .pipe((0, rxjs_1.last)()), (0, replay_1.whenReplayFinished)().pipe((0, rxjs_1.last)()), (0, rxjs_1.fromEvent)(process, 'exit'), (0, rxjs_1.fromEvent)(process, 'SIGINT'), (0, rxjs_1.fromEvent)(process, 'SIGUSR1'), (0, rxjs_1.fromEvent)(process, 'SIGUSR2'), (0, rxjs_1.fromEvent)(process, 'uncaughtException')).pipe((0, rxjs_1.catchError)(e => {
58
+ console.error(e);
59
+ return (0, rxjs_1.of)(e);
60
+ }), (0, rxjs_1.take)(1), (0, rxjs_1.switchMap)(it => { var _a; return (_a = (0, rxjs_1.forkJoin)(description.after.map(after => after())).pipe((0, rxjs_1.last)())) !== null && _a !== void 0 ? _a : (0, rxjs_1.of)(it); }), (0, rxjs_1.finalize)(() => process.exit(0))));
58
61
  });
59
62
  });
60
63
  }
@@ -1,8 +1,8 @@
1
1
  export * from './use-replay';
2
2
  export * from './use-replay-breakpoint';
3
3
  export * from './use-replay-options';
4
- export * from './use-replay-storage';
5
- export * from './use-replay-storage-buffer';
4
+ export * from './storage/use-replay-storage';
5
+ export * from './storage/use-replay-storage-buffer';
6
6
  export * from './use-replay-manager';
7
7
  export * from './when-replay-finished';
8
8
  export * from './replay';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/replay/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/replay/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qCAAqC,CAAC;AACpD,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC"}
@@ -17,8 +17,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./use-replay"), exports);
18
18
  __exportStar(require("./use-replay-breakpoint"), exports);
19
19
  __exportStar(require("./use-replay-options"), exports);
20
- __exportStar(require("./use-replay-storage"), exports);
21
- __exportStar(require("./use-replay-storage-buffer"), exports);
20
+ __exportStar(require("./storage/use-replay-storage"), exports);
21
+ __exportStar(require("./storage/use-replay-storage-buffer"), exports);
22
22
  __exportStar(require("./use-replay-manager"), exports);
23
23
  __exportStar(require("./when-replay-finished"), exports);
24
24
  __exportStar(require("./replay"), exports);
@@ -1,4 +1,4 @@
1
- import { dependency } from '../use-hash';
1
+ import { dependency } from '../../use-hash';
2
2
  export declare const useReplayStorageBuffer: <T>(dependencies: dependency[]) => {
3
3
  size(): number;
4
4
  peek(): {
@@ -10,6 +10,6 @@ export declare const useReplayStorageBuffer: <T>(dependencies: dependency[]) =>
10
10
  payload: T;
11
11
  };
12
12
  completed(): boolean;
13
- fetchNextPage(from: number, to: number): Promise<void>;
13
+ fetchNextPage(): Promise<void>;
14
14
  };
15
15
  //# sourceMappingURL=use-replay-storage-buffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-replay-storage-buffer.d.ts","sourceRoot":"","sources":["../../../src/replay/storage/use-replay-storage-buffer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAK3C,eAAO,MAAM,sBAAsB;;;mBAIC,MAAM;;;;mBAAN,MAAM;;;;;CAsCxC,CAAC"}
@@ -10,14 +10,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.useReplayStorageBuffer = void 0;
13
- const storage_1 = require("../storage");
14
- const with_memo_1 = require("../with-memo");
13
+ const use_replay_options_1 = require("../../replay/use-replay-options");
14
+ const storage_1 = require("../../storage");
15
+ const with_memo_1 = require("../../with-memo");
15
16
  const use_replay_storage_1 = require("./use-replay-storage");
16
17
  exports.useReplayStorageBuffer = (0, with_memo_1.withMemo)((dependencies) => {
17
18
  const { query } = (0, use_replay_storage_1.useReplayStorage)(dependencies);
19
+ const { from, to } = (0, use_replay_options_1.useReplayOptions)();
18
20
  let page = new Array();
19
21
  let index = 0;
20
22
  let completed = false;
23
+ let count = 0;
21
24
  return {
22
25
  size() {
23
26
  return page.length - index;
@@ -31,7 +34,7 @@ exports.useReplayStorageBuffer = (0, with_memo_1.withMemo)((dependencies) => {
31
34
  completed() {
32
35
  return completed;
33
36
  },
34
- fetchNextPage(from, to) {
37
+ fetchNextPage() {
35
38
  return __awaiter(this, void 0, void 0, function* () {
36
39
  if (completed) {
37
40
  return;
@@ -41,8 +44,11 @@ exports.useReplayStorageBuffer = (0, with_memo_1.withMemo)((dependencies) => {
41
44
  where: {
42
45
  timestamp: (0, storage_1.between)(from, to)
43
46
  },
44
- limit: 10000
47
+ limit: 10000,
48
+ offset: count,
49
+ orderBy: 'ASC'
45
50
  });
51
+ count += page.length;
46
52
  completed = page.length == 0;
47
53
  });
48
54
  }
@@ -0,0 +1,30 @@
1
+ import { dependency } from '../../use-hash';
2
+ export declare const useReplayStorageCursor: () => {
3
+ get<T>(dependencies: dependency[]): {
4
+ size(): number;
5
+ peek(): {
6
+ timestamp: number;
7
+ payload: T;
8
+ };
9
+ dequeue(): {
10
+ timestamp: number;
11
+ payload: T;
12
+ };
13
+ completed(): boolean;
14
+ fetchNextPage(): Promise<void>;
15
+ };
16
+ cursor(): Promise<{
17
+ size(): number;
18
+ peek(): {
19
+ timestamp: number;
20
+ payload: any;
21
+ };
22
+ dequeue(): {
23
+ timestamp: number;
24
+ payload: any;
25
+ };
26
+ completed(): boolean;
27
+ fetchNextPage(): Promise<void>;
28
+ } | undefined>;
29
+ };
30
+ //# sourceMappingURL=use-replay-storage-cursor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-replay-storage-cursor.d.ts","sourceRoot":"","sources":["../../../src/replay/storage/use-replay-storage-cursor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAW,MAAM,eAAe,CAAC;AAMpD,eAAO,MAAM,sBAAsB;yBAKV,UAAU,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCnC,CAAC"}
@@ -0,0 +1,49 @@
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,5 +1,5 @@
1
- import { Query, QueryObject } from '../storage';
2
- import { dependency } from '../use-hash';
1
+ import { Query, QueryObject } from '../../storage';
2
+ import { dependency } from '../../use-hash';
3
3
  export declare function useReplayStorage<T>(dependencies: dependency[]): {
4
4
  query(query: Query<QueryObject>): Promise<{
5
5
  timestamp: number;
@@ -0,0 +1 @@
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"}
@@ -10,8 +10,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.useReplayStorage = void 0;
13
- const storage_1 = require("../storage");
14
- const use_hash_1 = require("../use-hash");
13
+ const storage_1 = require("../../storage");
14
+ const use_hash_1 = require("../../use-hash");
15
15
  function useReplayStorage(dependencies) {
16
16
  const storage = (0, storage_1.useStorage)(['replay']);
17
17
  const storageObjectKey = (0, use_hash_1.useHash)(dependencies);
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-replay-storage.spec.d.ts","sourceRoot":"","sources":["../../../src/replay/storage/use-replay-storage.spec.ts"],"names":[],"mappings":""}
@@ -9,8 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- const make_test_module_1 = require("../make-test-module");
13
- const storage_1 = require("../storage");
12
+ const make_test_module_1 = require("../../make-test-module");
13
+ const storage_1 = require("../../storage");
14
14
  const use_replay_storage_1 = require("./use-replay-storage");
15
15
  jest.mock('@lib/storage', () => (Object.assign(Object.assign({}, jest.requireActual('@lib/storage')), { useStorage: jest.fn() })));
16
16
  describe(use_replay_storage_1.useReplayStorage.name, () => {
@@ -10,12 +10,12 @@ function useReplayBreakpoint(input) {
10
10
  if (!isReplay) {
11
11
  return input;
12
12
  }
13
- const { info } = (0, use_logger_1.useLogger)('useReplayBreakpoint');
13
+ const { info } = (0, use_logger_1.useLogger)('replay');
14
14
  const { stop, tryContinue } = (0, use_replay_manager_1.useReplayManager)();
15
- info('locking resource...');
15
+ info('breakpoint acquired');
16
16
  stop();
17
17
  return input.pipe((0, rxjs_1.finalize)(() => {
18
- info('unlocking resource');
18
+ info('breakpoint released');
19
19
  tryContinue();
20
20
  }));
21
21
  }
@@ -12,7 +12,7 @@ export declare const useReplayManager: () => {
12
12
  payload: any;
13
13
  };
14
14
  completed(): boolean;
15
- fetchNextPage(from: number, to: number): Promise<void>;
15
+ fetchNextPage(): Promise<void>;
16
16
  }, {
17
17
  timestamp: number;
18
18
  payload: any;
@@ -20,7 +20,7 @@ export declare const useReplayManager: () => {
20
20
  timestamp(): number;
21
21
  stop(): void;
22
22
  tryContinue: () => void;
23
- when<T>(dependencies: dependency[]): Observable<{
23
+ watch<T>(dependencies: dependency[]): Observable<{
24
24
  timestamp: number;
25
25
  payload: T;
26
26
  }>;
@@ -1 +1 @@
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,EAAW,MAAM,eAAe,CAAC;AAOpD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;mBASqC,MAAM;iBAAW,GAAG;;;;;0BAsE5D,UAAU,EAAE;mBAA2B,MAAM;;;CAkBrE,CAAC"}
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"}
@@ -11,41 +11,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.useReplayManager = void 0;
13
13
  const rxjs_1 = require("rxjs");
14
- const use_hash_1 = require("../use-hash");
15
- const use_logger_1 = require("../use-logger");
16
14
  const with_memo_1 = require("../with-memo");
15
+ const use_replay_storage_cursor_1 = require("./storage/use-replay-storage-cursor");
17
16
  const use_replay_options_1 = require("./use-replay-options");
18
- const use_replay_storage_buffer_1 = require("./use-replay-storage-buffer");
19
17
  exports.useReplayManager = (0, with_memo_1.withMemo)(() => {
20
- const { from, to } = (0, use_replay_options_1.useReplayOptions)();
21
- const { info } = (0, use_logger_1.useLogger)('useReplayManager');
18
+ const { from } = (0, use_replay_options_1.useReplayOptions)();
19
+ const { get, cursor } = (0, use_replay_storage_cursor_1.useReplayStorageCursor)();
22
20
  let timestamp = from;
23
21
  let stopAcquire = 1;
24
- const subscriptions = Array.of();
25
22
  const stream$ = new rxjs_1.Subject();
26
- const getNextStorage = () => __awaiter(void 0, void 0, void 0, function* () {
27
- let next;
28
- for (const cursor of subscriptions) {
29
- if (cursor.size() == 0 && !cursor.completed()) {
30
- yield cursor.fetchNextPage(timestamp, to + 1);
31
- }
32
- if (cursor.peek()) {
33
- if (!next || next.peek().timestamp > cursor.peek().timestamp) {
34
- next = cursor;
35
- }
36
- }
37
- }
38
- return next;
39
- });
40
23
  const processNext = () => __awaiter(void 0, void 0, void 0, function* () {
41
- const cursor = yield getNextStorage();
42
- if (!cursor || !cursor.peek()) {
24
+ const storage = yield cursor();
25
+ if (!storage || !storage.peek()) {
43
26
  stream$.complete();
44
27
  return false;
45
28
  }
46
- const sample = cursor.dequeue();
29
+ const sample = storage.dequeue();
47
30
  timestamp = sample.timestamp;
48
- stream$.next([cursor, sample]);
31
+ stream$.next([storage, sample]);
49
32
  return true;
50
33
  });
51
34
  const next = () => __awaiter(void 0, void 0, void 0, function* () {
@@ -74,12 +57,8 @@ exports.useReplayManager = (0, with_memo_1.withMemo)(() => {
74
57
  stopAcquire++;
75
58
  },
76
59
  tryContinue,
77
- when(dependencies) {
78
- const storage = (0, use_replay_storage_buffer_1.useReplayStorageBuffer)(dependencies);
79
- if (!subscriptions.includes(storage)) {
80
- info('subscribing to replay', (0, use_hash_1.useHash)(dependencies));
81
- subscriptions.push(storage);
82
- }
60
+ watch(dependencies) {
61
+ const storage = get(dependencies);
83
62
  return (0, rxjs_1.defer)(() => {
84
63
  tryContinue();
85
64
  return stream$.pipe((0, rxjs_1.filter)(([cur]) => cur === storage), (0, rxjs_1.map)(([, it]) => ({ timestamp: it.timestamp, payload: it.payload })));
@@ -3,13 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useReplay = void 0;
4
4
  const rxjs_1 = require("rxjs");
5
5
  const use_execution_mode_1 = require("../use-execution-mode");
6
+ const use_replay_storage_1 = require("./storage/use-replay-storage");
6
7
  const use_replay_manager_1 = require("./use-replay-manager");
7
- const use_replay_storage_1 = require("./use-replay-storage");
8
8
  function useReplay(input, dependencies) {
9
9
  const { isReplay, recording } = (0, use_execution_mode_1.useExecutionMode)();
10
10
  if (isReplay) {
11
- const { when } = (0, use_replay_manager_1.useReplayManager)();
12
- return when(dependencies);
11
+ const { watch } = (0, use_replay_manager_1.useReplayManager)();
12
+ return watch(dependencies);
13
13
  }
14
14
  if (recording) {
15
15
  const { save } = (0, use_replay_storage_1.useReplayStorage)(dependencies);
@@ -11,20 +11,4 @@ export declare function d(value: Decimal.Value): decimal;
11
11
  export declare namespace d {
12
12
  var Zero: decimal;
13
13
  }
14
- export declare function weightedMean(values: decimal[], weights: decimal[]): decimal;
15
- export declare function pnl(entryRate: decimal, exitRate: decimal, amount: decimal): Decimal;
16
- /**
17
- *
18
- * @param timestamp
19
- * @param timeframe
20
- * @returns nearest timestamp to the given timeframe
21
- */
22
- export declare function candledown(timestamp: number, timeframe: number): number;
23
- /**
24
- *
25
- * @param timestamp
26
- * @param timeframe
27
- * @returns nearest timestamp to the given timeframe
28
- */
29
- export declare function candleup(timestamp: number, timeframe: number): number;
30
14
  //# sourceMappingURL=decimals.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decimals.d.ts","sourceRoot":"","sources":["../../src/shared/decimals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,OAAO,QAAQ,YAAY,CAAC;IAC1B,UAAU,OAAO;QACf,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC;QACxC,MAAM,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC;KACxC;CACF;AAUD,qBAAa,OAAQ,SAAQ,OAAO;CAAG;AAOvC,wBAAgB,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,WAErC;yBAFe,CAAC;;;AAMjB,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAc3E;AAED,wBAAgB,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,WAEzE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAErE"}
1
+ {"version":3,"file":"decimals.d.ts","sourceRoot":"","sources":["../../src/shared/decimals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,OAAO,QAAQ,YAAY,CAAC;IAC1B,UAAU,OAAO;QACf,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC;QACxC,MAAM,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC;KACxC;CACF;AAUD,qBAAa,OAAQ,SAAQ,OAAO;CAAG;AAEvC,wBAAgB,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,WAErC;yBAFe,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.candleup = exports.candledown = exports.pnl = exports.weightedMean = exports.d = exports.decimal = void 0;
3
+ exports.d = exports.decimal = void 0;
4
4
  const decimal_js_1 = require("decimal.js");
5
5
  decimal_js_1.Decimal.prototype.toFloor = function (decimalPlaces) {
6
6
  return this.toDecimalPlaces(decimalPlaces, decimal_js_1.Decimal.ROUND_FLOOR);
@@ -11,51 +11,8 @@ decimal_js_1.Decimal.prototype.toCeil = function (decimalPlaces) {
11
11
  class decimal extends decimal_js_1.Decimal {
12
12
  }
13
13
  exports.decimal = decimal;
14
- /*
15
- decimal.prototype.toJSON = function () {
16
- return '444';
17
- };
18
- */
19
14
  function d(value) {
20
15
  return new decimal(value);
21
16
  }
22
17
  exports.d = d;
23
18
  d.Zero = new decimal(0);
24
- function weightedMean(values, weights) {
25
- const result = values
26
- .map((value, i) => {
27
- const weight = weights[i];
28
- const sum = value.mul(weight);
29
- return [sum, weight];
30
- })
31
- .reduce((p, c) => [p[0].add(c[0]), p[1].add(c[1])], [d.Zero, d.Zero]);
32
- if (!result[1]) {
33
- return d.Zero;
34
- }
35
- return result[0].div(result[1]);
36
- }
37
- exports.weightedMean = weightedMean;
38
- function pnl(entryRate, exitRate, amount) {
39
- return exitRate.div(entryRate).minus(1).mul(amount);
40
- }
41
- exports.pnl = pnl;
42
- /**
43
- *
44
- * @param timestamp
45
- * @param timeframe
46
- * @returns nearest timestamp to the given timeframe
47
- */
48
- function candledown(timestamp, timeframe) {
49
- return timestamp - (timestamp % timeframe);
50
- }
51
- exports.candledown = candledown;
52
- /**
53
- *
54
- * @param timestamp
55
- * @param timeframe
56
- * @returns nearest timestamp to the given timeframe
57
- */
58
- function candleup(timestamp, timeframe) {
59
- return candledown(timestamp, timeframe) + timeframe;
60
- }
61
- exports.candleup = candleup;
@@ -1 +1 @@
1
- {"version":3,"file":"strategy.d.ts","sourceRoot":"","sources":["../src/strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAElC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,MAAM,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;AAEnD,eAAO,IAAI,MAAM,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;AACpD,eAAO,IAAI,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;AACtD,eAAO,IAAI,KAAK,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;AAEnD,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,UAAU,EAAE;;;;;;;EAiBtD"}
1
+ {"version":3,"file":"strategy.d.ts","sourceRoot":"","sources":["../src/strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAM,MAAM,MAAM,CAAC;AAEtC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,MAAM,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;AAEnD,eAAO,IAAI,MAAM,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;AACpD,eAAO,IAAI,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;AACtD,eAAO,IAAI,KAAK,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;AAEnD,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,UAAU,EAAE;;;;;;;EAyBtD"}
package/dist/strategy.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.strategy = exports.after = exports.behavior = exports.before = void 0;
4
+ const rxjs_1 = require("rxjs");
4
5
  function strategy(descriptor) {
5
6
  const description = {
6
7
  before: Array.of(),
@@ -11,6 +12,12 @@ function strategy(descriptor) {
11
12
  exports.behavior = descriptor => description.behavior.push(descriptor);
12
13
  exports.after = descriptor => description.after.push(descriptor);
13
14
  const dependencies = descriptor();
15
+ if (!description.before.length) {
16
+ description.before.push(() => (0, rxjs_1.of)(true));
17
+ }
18
+ if (!description.after.length) {
19
+ description.after.push(() => (0, rxjs_1.of)(true));
20
+ }
14
21
  return {
15
22
  dependencies,
16
23
  description
@@ -32,14 +32,14 @@ function idleExecutionMode() {
32
32
  }
33
33
  exports.idleExecutionMode = idleExecutionMode;
34
34
  const useExecutionMode = () => {
35
- const mode = (0, module_1.useContext)(injectionToken);
35
+ const { mode, recording } = (0, module_1.useContext)(injectionToken);
36
36
  return {
37
- isReplay: mode.mode === 'replay',
38
- isPaper: mode.mode === 'paper',
39
- isLive: mode.mode === 'live',
40
- isIdle: mode.mode === 'idle',
41
- isSimulation: mode.mode !== 'live',
42
- recording: mode.recording
37
+ isReplay: mode === 'replay',
38
+ isPaper: mode === 'paper',
39
+ isLive: mode === 'live',
40
+ isIdle: mode === 'idle',
41
+ isSimulation: mode !== 'live',
42
+ recording
43
43
  };
44
44
  };
45
45
  exports.useExecutionMode = useExecutionMode;
@@ -0,0 +1,19 @@
1
+ import { Observable } from 'rxjs';
2
+ export declare function useSocket(url: string, options?: {
3
+ pingInterval?: number;
4
+ }): {
5
+ /**
6
+ * Observes socket events and handles connection health monitoring via ping/pong
7
+ * @returns observable emitting message events with timestamps and parsed payloads
8
+ */
9
+ watch(): Observable<{
10
+ timestamp: number;
11
+ payload: unknown;
12
+ }>;
13
+ send(message: {
14
+ payload: unknown;
15
+ }): Observable<{
16
+ timestamp: number;
17
+ }>;
18
+ };
19
+ //# sourceMappingURL=use-socket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-socket.d.ts","sourceRoot":"","sources":["../src/use-socket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,UAAU,EAAM,MAAM,MAAM,CAAC;AAM7C,wBAAgB,SAAS,CACvB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAA2B;IAMzD;;;OAGG;aACM,WAAW;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;kBAmD9C;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,WAAW;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;EAQzE"}
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useSocket = void 0;
4
+ const rxjs_1 = require("rxjs");
5
+ const ws_1 = require("ws");
6
+ const use_logger_1 = require("./use-logger");
7
+ const use_timestamp_1 = require("./use-timestamp");
8
+ function useSocket(url, options = { pingInterval: 5000 }) {
9
+ const { debug } = (0, use_logger_1.useLogger)('useSocket');
10
+ const socket = new ws_1.WebSocket(url);
11
+ return {
12
+ /**
13
+ * Observes socket events and handles connection health monitoring via ping/pong
14
+ * @returns observable emitting message events with timestamps and parsed payloads
15
+ */
16
+ watch() {
17
+ let isAlive = false;
18
+ let interval;
19
+ return new rxjs_1.Observable(stream => {
20
+ socket.onmessage = it => stream.next({
21
+ timestamp: (0, use_timestamp_1.useTimestamp)(),
22
+ payload: JSON.parse(it.data)
23
+ });
24
+ socket.onerror = it => {
25
+ clearInterval(interval);
26
+ debug('errored', url);
27
+ stream.error(it);
28
+ };
29
+ socket.onclose = () => {
30
+ debug('closed', url);
31
+ clearInterval(interval);
32
+ stream.error();
33
+ };
34
+ socket.onopen = () => {
35
+ debug('opened', url);
36
+ isAlive = true;
37
+ interval = setInterval(() => {
38
+ if (isAlive) {
39
+ isAlive = false;
40
+ socket.ping();
41
+ }
42
+ else {
43
+ socket.terminate();
44
+ clearInterval(interval);
45
+ }
46
+ }, options.pingInterval);
47
+ socket.on('pong', () => {
48
+ isAlive = true;
49
+ });
50
+ socket.on('ping', () => {
51
+ isAlive = true;
52
+ socket.pong();
53
+ });
54
+ };
55
+ return () => {
56
+ clearInterval(interval);
57
+ socket.terminate();
58
+ };
59
+ });
60
+ },
61
+ send(message) {
62
+ return (0, rxjs_1.defer)(() => {
63
+ socket.send(JSON.stringify(message.payload));
64
+ return (0, rxjs_1.of)({ timestamp: (0, use_timestamp_1.useTimestamp)() });
65
+ });
66
+ }
67
+ };
68
+ }
69
+ exports.useSocket = useSocket;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantform/core",
3
- "version": "0.7.0-beta.47",
3
+ "version": "0.7.0-beta.49",
4
4
  "license": "MIT",
5
5
  "author": "Mateusz Majchrzak",
6
6
  "description": "Node.js library for building systematic trading strategies in reactive way.",
@@ -1,5 +1,6 @@
1
1
  import { join } from 'path';
2
2
  import {
3
+ catchError,
3
4
  finalize,
4
5
  firstValueFrom,
5
6
  forkJoin,
@@ -8,8 +9,7 @@ import {
8
9
  merge,
9
10
  of,
10
11
  switchMap,
11
- take,
12
- tap
12
+ take
13
13
  } from 'rxjs';
14
14
 
15
15
  import { core } from '@lib/core';
@@ -21,12 +21,12 @@ import { buildDirectory } from './workspace';
21
21
 
22
22
  export class Script {
23
23
  constructor(
24
- private readonly name: string,
24
+ private readonly filename: string,
25
25
  private readonly dependencies: Dependency[]
26
26
  ) {}
27
27
 
28
28
  async run() {
29
- const script = await import(join(buildDirectory(), this.name));
29
+ const script = await import(join(buildDirectory(), this.filename));
30
30
 
31
31
  const { dependencies, description } = script.default as ReturnType<typeof strategy>;
32
32
 
@@ -39,9 +39,11 @@ export class Script {
39
39
 
40
40
  return firstValueFrom(
41
41
  merge(
42
- forkJoin(description.before.map(it => it()))
42
+ forkJoin(description.before.map(before => before()))
43
43
  .pipe(
44
- switchMap(() => forkJoin(description.behavior.map(it => it())).pipe(last()))
44
+ switchMap(() =>
45
+ forkJoin(description.behavior.map(behavior => behavior())).pipe(last())
46
+ )
45
47
  )
46
48
  .pipe(last()),
47
49
  whenReplayFinished().pipe(last()),
@@ -51,9 +53,14 @@ export class Script {
51
53
  fromEvent(process, 'SIGUSR2'),
52
54
  fromEvent(process, 'uncaughtException')
53
55
  ).pipe(
56
+ catchError(e => {
57
+ console.error(e);
58
+
59
+ return of(e);
60
+ }),
54
61
  take(1),
55
62
  switchMap(
56
- it => forkJoin(description.after.map(it => it())).pipe(last()) ?? of(it)
63
+ it => forkJoin(description.after.map(after => after())).pipe(last()) ?? of(it)
57
64
  ),
58
65
  finalize(() => process.exit(0))
59
66
  )
@@ -1,8 +1,8 @@
1
1
  export * from './use-replay';
2
2
  export * from './use-replay-breakpoint';
3
3
  export * from './use-replay-options';
4
- export * from './use-replay-storage';
5
- export * from './use-replay-storage-buffer';
4
+ export * from './storage/use-replay-storage';
5
+ export * from './storage/use-replay-storage-buffer';
6
6
  export * from './use-replay-manager';
7
7
  export * from './when-replay-finished';
8
8
  export * from './replay';
@@ -1,3 +1,4 @@
1
+ import { useReplayOptions } from '@lib/replay/use-replay-options';
1
2
  import { between } from '@lib/storage';
2
3
  import { dependency } from '@lib/use-hash';
3
4
  import { withMemo } from '@lib/with-memo';
@@ -6,10 +7,12 @@ import { useReplayStorage } from './use-replay-storage';
6
7
 
7
8
  export const useReplayStorageBuffer = withMemo(<T>(dependencies: dependency[]) => {
8
9
  const { query } = useReplayStorage<T>(dependencies);
10
+ const { from, to } = useReplayOptions();
9
11
 
10
12
  let page = new Array<{ timestamp: number; payload: T }>();
11
13
  let index = 0;
12
14
  let completed = false;
15
+ let count = 0;
13
16
 
14
17
  return {
15
18
  size() {
@@ -24,7 +27,7 @@ export const useReplayStorageBuffer = withMemo(<T>(dependencies: dependency[]) =
24
27
  completed() {
25
28
  return completed;
26
29
  },
27
- async fetchNextPage(from: number, to: number) {
30
+ async fetchNextPage() {
28
31
  if (completed) {
29
32
  return;
30
33
  }
@@ -35,8 +38,12 @@ export const useReplayStorageBuffer = withMemo(<T>(dependencies: dependency[]) =
35
38
  where: {
36
39
  timestamp: between(from, to)
37
40
  },
38
- limit: 10000
41
+ limit: 10000,
42
+ offset: count,
43
+ orderBy: 'ASC'
39
44
  });
45
+
46
+ count += page.length;
40
47
  completed = page.length == 0;
41
48
  }
42
49
  };
@@ -0,0 +1,44 @@
1
+ import { dependency, useHash } from '@lib/use-hash';
2
+ import { useLogger } from '@lib/use-logger';
3
+ import { withMemo } from '@lib/with-memo';
4
+
5
+ import { useReplayStorageBuffer } from './use-replay-storage-buffer';
6
+
7
+ export const useReplayStorageCursor = withMemo(() => {
8
+ const { info } = useLogger('useReplayStorageCursor');
9
+ const storages = Array.of<ReturnType<typeof useReplayStorageBuffer<any>>>();
10
+
11
+ return {
12
+ get<T>(dependencies: dependency[]) {
13
+ const storage = useReplayStorageBuffer<T>(dependencies);
14
+
15
+ if (!storages.includes(storage)) {
16
+ info('opening a new replay buffer', useHash(dependencies));
17
+ storages.push(storage);
18
+ }
19
+
20
+ return storage;
21
+ },
22
+ async cursor() {
23
+ let current: ReturnType<typeof useReplayStorageBuffer<any>> | undefined;
24
+
25
+ for (const storage of storages) {
26
+ if (storage.completed()) {
27
+ continue;
28
+ }
29
+
30
+ if (storage.size() == 0) {
31
+ await storage.fetchNextPage();
32
+ }
33
+
34
+ if (storage.peek()) {
35
+ if (!current || current.peek().timestamp > storage.peek().timestamp) {
36
+ current = storage;
37
+ }
38
+ }
39
+ }
40
+
41
+ return current;
42
+ }
43
+ };
44
+ });
@@ -69,7 +69,6 @@ async function getFixtures() {
69
69
  return act(() => useReplayStorage<T>(dependencies).query(query));
70
70
  }
71
71
  },
72
-
73
72
  then: {
74
73
  stored<T>(sample: { timestamp: number; payload: T }[]) {
75
74
  expect(save).toHaveBeenCalledWith(
@@ -12,16 +12,16 @@ export function useReplayBreakpoint<T>(input: Observable<T>): Observable<T> {
12
12
  return input;
13
13
  }
14
14
 
15
- const { info } = useLogger('useReplayBreakpoint');
15
+ const { info } = useLogger('replay');
16
16
  const { stop, tryContinue } = useReplayManager();
17
17
 
18
- info('locking resource...');
18
+ info('breakpoint acquired');
19
19
 
20
20
  stop();
21
21
 
22
22
  return input.pipe(
23
23
  finalize(() => {
24
- info('unlocking resource');
24
+ info('breakpoint released');
25
25
 
26
26
  tryContinue();
27
27
  })
@@ -1,56 +1,37 @@
1
1
  import { defer, filter, map, Observable, Subject } from 'rxjs';
2
2
 
3
- import { dependency, useHash } from '@lib/use-hash';
4
- import { useLogger } from '@lib/use-logger';
3
+ import { dependency } from '@lib/use-hash';
5
4
  import { withMemo } from '@lib/with-memo';
6
5
 
6
+ import { useReplayStorageBuffer } from './storage/use-replay-storage-buffer';
7
+ import { useReplayStorageCursor } from './storage/use-replay-storage-cursor';
7
8
  import { useReplayOptions } from './use-replay-options';
8
- import { useReplayStorageBuffer } from './use-replay-storage-buffer';
9
9
 
10
10
  export const useReplayManager = withMemo(() => {
11
- const { from, to } = useReplayOptions();
12
- const { info } = useLogger('useReplayManager');
11
+ const { from } = useReplayOptions();
12
+ const { get, cursor } = useReplayStorageCursor();
13
13
 
14
14
  let timestamp = from;
15
15
  let stopAcquire = 1;
16
- const subscriptions = Array.of<ReturnType<typeof useReplayStorageBuffer<any>>>();
17
16
 
18
17
  const stream$ = new Subject<
19
18
  [ReturnType<typeof useReplayStorageBuffer<any>>, { timestamp: number; payload: any }]
20
19
  >();
21
20
 
22
- const getNextStorage = async () => {
23
- let next: ReturnType<typeof useReplayStorageBuffer<any>> | undefined;
24
-
25
- for (const cursor of subscriptions) {
26
- if (cursor.size() == 0 && !cursor.completed()) {
27
- await cursor.fetchNextPage(timestamp, to + 1);
28
- }
29
-
30
- if (cursor.peek()) {
31
- if (!next || next.peek().timestamp > cursor.peek().timestamp) {
32
- next = cursor;
33
- }
34
- }
35
- }
36
-
37
- return next;
38
- };
39
-
40
21
  const processNext = async () => {
41
- const cursor = await getNextStorage();
22
+ const storage = await cursor();
42
23
 
43
- if (!cursor || !cursor.peek()) {
24
+ if (!storage || !storage.peek()) {
44
25
  stream$.complete();
45
26
 
46
27
  return false;
47
28
  }
48
29
 
49
- const sample = cursor.dequeue();
30
+ const sample = storage.dequeue();
50
31
 
51
32
  timestamp = sample.timestamp;
52
33
 
53
- stream$.next([cursor, sample]);
34
+ stream$.next([storage, sample]);
54
35
 
55
36
  return true;
56
37
  };
@@ -86,13 +67,8 @@ export const useReplayManager = withMemo(() => {
86
67
  stopAcquire++;
87
68
  },
88
69
  tryContinue,
89
- when<T>(dependencies: dependency[]): Observable<{ timestamp: number; payload: T }> {
90
- const storage = useReplayStorageBuffer<T>(dependencies);
91
-
92
- if (!subscriptions.includes(storage)) {
93
- info('subscribing to replay', useHash(dependencies));
94
- subscriptions.push(storage);
95
- }
70
+ watch<T>(dependencies: dependency[]): Observable<{ timestamp: number; payload: T }> {
71
+ const storage = get<T>(dependencies);
96
72
 
97
73
  return defer(() => {
98
74
  tryContinue();
@@ -3,8 +3,8 @@ import { Observable, tap } from 'rxjs';
3
3
  import { useExecutionMode } from '@lib/use-execution-mode';
4
4
  import { dependency } from '@lib/use-hash';
5
5
 
6
+ import { useReplayStorage } from './storage/use-replay-storage';
6
7
  import { useReplayManager } from './use-replay-manager';
7
- import { useReplayStorage } from './use-replay-storage';
8
8
 
9
9
  export function useReplay<T>(
10
10
  input: Observable<{ timestamp: number; payload: T }>,
@@ -13,9 +13,9 @@ export function useReplay<T>(
13
13
  const { isReplay, recording } = useExecutionMode();
14
14
 
15
15
  if (isReplay) {
16
- const { when } = useReplayManager();
16
+ const { watch } = useReplayManager();
17
17
 
18
- return when<T>(dependencies);
18
+ return watch<T>(dependencies);
19
19
  }
20
20
 
21
21
  if (recording) {
@@ -16,54 +16,9 @@ Decimal.prototype.toCeil = function (decimalPlaces: number) {
16
16
  };
17
17
 
18
18
  export class decimal extends Decimal {}
19
- /*
20
- decimal.prototype.toJSON = function () {
21
- return '444';
22
- };
23
- */
24
19
 
25
20
  export function d(value: Decimal.Value) {
26
21
  return new decimal(value);
27
22
  }
28
23
 
29
24
  d.Zero = new decimal(0);
30
-
31
- export function weightedMean(values: decimal[], weights: decimal[]): decimal {
32
- const result = values
33
- .map((value, i) => {
34
- const weight = weights[i];
35
- const sum = value.mul(weight);
36
- return [sum, weight];
37
- })
38
- .reduce((p, c) => [p[0].add(c[0]), p[1].add(c[1])], [d.Zero, d.Zero]);
39
-
40
- if (!result[1]) {
41
- return d.Zero;
42
- }
43
-
44
- return result[0].div(result[1]);
45
- }
46
-
47
- export function pnl(entryRate: decimal, exitRate: decimal, amount: decimal) {
48
- return exitRate.div(entryRate).minus(1).mul(amount);
49
- }
50
-
51
- /**
52
- *
53
- * @param timestamp
54
- * @param timeframe
55
- * @returns nearest timestamp to the given timeframe
56
- */
57
- export function candledown(timestamp: number, timeframe: number): number {
58
- return timestamp - (timestamp % timeframe);
59
- }
60
-
61
- /**
62
- *
63
- * @param timestamp
64
- * @param timeframe
65
- * @returns nearest timestamp to the given timeframe
66
- */
67
- export function candleup(timestamp: number, timeframe: number): number {
68
- return candledown(timestamp, timeframe) + timeframe;
69
- }
package/src/strategy.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Observable } from 'rxjs';
1
+ import { Observable, of } from 'rxjs';
2
2
 
3
3
  import { Dependency } from './module';
4
4
 
@@ -21,6 +21,14 @@ export function strategy(descriptor: () => Dependency[]) {
21
21
 
22
22
  const dependencies = descriptor();
23
23
 
24
+ if (!description.before.length) {
25
+ description.before.push(() => of(true));
26
+ }
27
+
28
+ if (!description.after.length) {
29
+ description.after.push(() => of(true));
30
+ }
31
+
24
32
  return {
25
33
  dependencies,
26
34
  description
@@ -36,14 +36,14 @@ export function idleExecutionMode() {
36
36
  }
37
37
 
38
38
  export const useExecutionMode = () => {
39
- const mode = useContext<ExecutionMode>(injectionToken);
39
+ const { mode, recording } = useContext<ExecutionMode>(injectionToken);
40
40
 
41
41
  return {
42
- isReplay: mode.mode === 'replay',
43
- isPaper: mode.mode === 'paper',
44
- isLive: mode.mode === 'live',
45
- isIdle: mode.mode === 'idle',
46
- isSimulation: mode.mode !== 'live',
47
- recording: mode.recording
42
+ isReplay: mode === 'replay',
43
+ isPaper: mode === 'paper',
44
+ isLive: mode === 'live',
45
+ isIdle: mode === 'idle',
46
+ isSimulation: mode !== 'live',
47
+ recording
48
48
  };
49
49
  };
@@ -0,0 +1,78 @@
1
+ import { defer, Observable, of } from 'rxjs';
2
+ import { WebSocket } from 'ws';
3
+
4
+ import { useLogger } from './use-logger';
5
+ import { useTimestamp } from './use-timestamp';
6
+
7
+ export function useSocket(
8
+ url: string,
9
+ options: { pingInterval?: number } = { pingInterval: 5000 }
10
+ ) {
11
+ const { debug } = useLogger('useSocket');
12
+ const socket = new WebSocket(url);
13
+
14
+ return {
15
+ /**
16
+ * Observes socket events and handles connection health monitoring via ping/pong
17
+ * @returns observable emitting message events with timestamps and parsed payloads
18
+ */
19
+ watch(): Observable<{ timestamp: number; payload: unknown }> {
20
+ let isAlive = false;
21
+ let interval: NodeJS.Timeout | undefined;
22
+
23
+ return new Observable(stream => {
24
+ socket.onmessage = it =>
25
+ stream.next({
26
+ timestamp: useTimestamp(),
27
+ payload: JSON.parse(it.data as string)
28
+ });
29
+ socket.onerror = it => {
30
+ clearInterval(interval);
31
+ debug('errored', url);
32
+ stream.error(it);
33
+ };
34
+ socket.onclose = () => {
35
+ debug('closed', url);
36
+ clearInterval(interval);
37
+ stream.error();
38
+ };
39
+ socket.onopen = () => {
40
+ debug('opened', url);
41
+ isAlive = true;
42
+ interval = setInterval(() => {
43
+ if (isAlive) {
44
+ isAlive = false;
45
+
46
+ socket.ping();
47
+ } else {
48
+ socket.terminate();
49
+ clearInterval(interval);
50
+ }
51
+ }, options.pingInterval);
52
+
53
+ socket.on('pong', () => {
54
+ isAlive = true;
55
+ });
56
+
57
+ socket.on('ping', () => {
58
+ isAlive = true;
59
+ socket.pong();
60
+ });
61
+ };
62
+
63
+ return () => {
64
+ clearInterval(interval);
65
+ socket.terminate();
66
+ };
67
+ });
68
+ },
69
+
70
+ send(message: { payload: unknown }): Observable<{ timestamp: number }> {
71
+ return defer(() => {
72
+ socket.send(JSON.stringify(message.payload));
73
+
74
+ return of({ timestamp: useTimestamp() });
75
+ });
76
+ }
77
+ };
78
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-replay-storage-buffer.d.ts","sourceRoot":"","sources":["../../src/replay/use-replay-storage-buffer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAK3C,eAAO,MAAM,sBAAsB;;;mBAGC,MAAM;;;;mBAAN,MAAM;;;;wBAiBZ,MAAM,MAAM,MAAM;CAgB9C,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-replay-storage.d.ts","sourceRoot":"","sources":["../../src/replay/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 +0,0 @@
1
- {"version":3,"file":"use-replay-storage.spec.d.ts","sourceRoot":"","sources":["../../src/replay/use-replay-storage.spec.ts"],"names":[],"mappings":""}