@quantform/core 0.6.4 → 0.6.5

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 (91) hide show
  1. package/dist/adapter/adapter-aggregate.d.ts +2 -2
  2. package/dist/adapter/adapter-aggregate.d.ts.map +1 -1
  3. package/dist/adapter/adapter-aggregate.js +1 -2
  4. package/dist/adapter/adapter.d.ts +2 -2
  5. package/dist/adapter/adapter.d.ts.map +1 -1
  6. package/dist/adapter/backtester/backtester-adapter.d.ts +2 -2
  7. package/dist/adapter/backtester/backtester-adapter.d.ts.map +1 -1
  8. package/dist/adapter/paper/paper-adapter.d.ts +2 -2
  9. package/dist/adapter/paper/paper-adapter.d.ts.map +1 -1
  10. package/dist/cli/dev.js +2 -2
  11. package/dist/cli/pull.js +2 -2
  12. package/dist/cli/run.js +2 -2
  13. package/dist/cli/test.js +2 -2
  14. package/dist/domain/asset.d.ts +0 -4
  15. package/dist/domain/asset.d.ts.map +1 -1
  16. package/dist/domain/asset.js +0 -6
  17. package/dist/domain/balance.d.ts +0 -2
  18. package/dist/domain/balance.d.ts.map +1 -1
  19. package/dist/domain/balance.js +0 -4
  20. package/dist/domain/component.d.ts +0 -1
  21. package/dist/domain/component.d.ts.map +1 -1
  22. package/dist/domain/index.d.ts +2 -2
  23. package/dist/domain/index.d.ts.map +1 -1
  24. package/dist/domain/index.js +2 -2
  25. package/dist/domain/instrument.d.ts +0 -2
  26. package/dist/domain/instrument.d.ts.map +1 -1
  27. package/dist/domain/instrument.js +0 -4
  28. package/dist/domain/ohlc-operator.d.ts +11 -0
  29. package/dist/domain/ohlc-operator.d.ts.map +1 -0
  30. package/dist/domain/{candle-operator.js → ohlc-operator.js} +11 -11
  31. package/dist/domain/{candle.d.ts → ohlc.d.ts} +2 -2
  32. package/dist/domain/ohlc.d.ts.map +1 -0
  33. package/dist/domain/{candle.js → ohlc.js} +3 -3
  34. package/dist/domain/order.d.ts +0 -2
  35. package/dist/domain/order.d.ts.map +1 -1
  36. package/dist/domain/order.js +0 -4
  37. package/dist/domain/orderbook.d.ts +0 -2
  38. package/dist/domain/orderbook.d.ts.map +1 -1
  39. package/dist/domain/orderbook.js +0 -4
  40. package/dist/domain/position.d.ts +0 -2
  41. package/dist/domain/position.d.ts.map +1 -1
  42. package/dist/domain/position.js +0 -4
  43. package/dist/domain/session-builder.d.ts +1 -1
  44. package/dist/domain/session-builder.d.ts.map +1 -1
  45. package/dist/domain/session-builder.js +3 -2
  46. package/dist/domain/session.d.ts +2 -2
  47. package/dist/domain/session.d.ts.map +1 -1
  48. package/dist/domain/trade.d.ts +0 -2
  49. package/dist/domain/trade.d.ts.map +1 -1
  50. package/dist/domain/trade.js +0 -4
  51. package/dist/index.d.ts +24 -1
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +63 -1
  54. package/dist/shared/logger.d.ts +1 -0
  55. package/dist/shared/logger.d.ts.map +1 -1
  56. package/dist/shared/logger.js +7 -4
  57. package/package.json +1 -1
  58. package/src/adapter/adapter-aggregate.ts +4 -6
  59. package/src/adapter/adapter.ts +3 -3
  60. package/src/adapter/backtester/backtester-adapter.ts +2 -2
  61. package/src/adapter/backtester/backtester-cursor.ts +1 -1
  62. package/src/adapter/paper/paper-adapter.ts +2 -2
  63. package/src/cli/dev.ts +2 -2
  64. package/src/cli/pull.ts +2 -2
  65. package/src/cli/run.ts +2 -2
  66. package/src/cli/test.ts +2 -2
  67. package/src/domain/asset.ts +0 -7
  68. package/src/domain/balance.ts +0 -5
  69. package/src/domain/component.ts +0 -1
  70. package/src/domain/index.ts +2 -2
  71. package/src/domain/instrument.ts +0 -5
  72. package/src/domain/ohlc-operator.spec.ts +126 -0
  73. package/src/domain/{candle-operator.ts → ohlc-operator.ts} +15 -15
  74. package/src/domain/{candle.spec.ts → ohlc.spec.ts} +6 -6
  75. package/src/domain/{candle.ts → ohlc.ts} +2 -2
  76. package/src/domain/order.ts +0 -5
  77. package/src/domain/orderbook.ts +0 -5
  78. package/src/domain/position.ts +0 -5
  79. package/src/domain/session-builder.ts +3 -3
  80. package/src/domain/session.ts +3 -3
  81. package/src/domain/trade.ts +0 -5
  82. package/src/index.ts +75 -1
  83. package/src/shared/logger.ts +6 -4
  84. package/dist/domain/candle-operator.d.ts +0 -11
  85. package/dist/domain/candle-operator.d.ts.map +0 -1
  86. package/dist/domain/candle.d.ts.map +0 -1
  87. package/dist/strategy.d.ts +0 -8
  88. package/dist/strategy.d.ts.map +0 -1
  89. package/dist/strategy.js +0 -44
  90. package/src/domain/candle-operator.spec.ts +0 -126
  91. package/src/strategy.ts +0 -47
@@ -12,11 +12,11 @@ import {
12
12
  } from 'rxjs';
13
13
 
14
14
  import { decimal } from '../shared';
15
- import { Candle } from './candle';
15
+ import { Ohlc } from './ohlc';
16
16
  import { tf } from './timeframe';
17
17
 
18
18
  function aggregate(
19
- candle: Candle | undefined,
19
+ candle: Ohlc | undefined,
20
20
  timeframe: number,
21
21
  value: decimal,
22
22
  timestamp: number
@@ -24,23 +24,23 @@ function aggregate(
24
24
  const frame = tf(timestamp, timeframe);
25
25
 
26
26
  if (!candle) {
27
- return new Candle(frame, value, value, value, value);
27
+ return new Ohlc(frame, value, value, value, value);
28
28
  }
29
29
 
30
30
  if (candle.timestamp === frame) {
31
31
  candle.apply(value);
32
32
  return undefined;
33
33
  } else {
34
- return new Candle(frame, candle.close, value, value, value);
34
+ return new Ohlc(frame, candle.close, value, value, value);
35
35
  }
36
36
  }
37
37
 
38
- export function candle<T extends { timestamp: number }>(
38
+ export function ohlc<T extends { timestamp: number }>(
39
39
  timeframe: number,
40
40
  fn: (x: T) => decimal,
41
- candleToStartWith?: Candle
41
+ candleToStartWith?: Ohlc
42
42
  ) {
43
- return function (source: Observable<T>): Observable<Candle> {
43
+ return function (source: Observable<T>): Observable<Ohlc> {
44
44
  let candle = candleToStartWith;
45
45
 
46
46
  return source.pipe(
@@ -77,18 +77,18 @@ export function candle<T extends { timestamp: number }>(
77
77
  };
78
78
  }
79
79
 
80
- export function mergeCandle<T extends { timestamp: number }>(
80
+ export function mergeOhlc<T extends { timestamp: number }>(
81
81
  timeframe: number,
82
82
  fn: (x: T) => decimal,
83
- history$: Observable<Candle>
83
+ history$: Observable<Ohlc>
84
84
  ) {
85
- return function (source$: Observable<T>): Observable<Candle> {
85
+ return function (source$: Observable<T>): Observable<Ohlc> {
86
86
  return concat(
87
87
  history$.pipe(skipLast(1)),
88
88
  history$.pipe(
89
89
  last(),
90
90
  switchMap(lastHistoricalCandle =>
91
- source$.pipe(candle(timeframe, fn, lastHistoricalCandle))
91
+ source$.pipe(ohlc(timeframe, fn, lastHistoricalCandle))
92
92
  ),
93
93
  share()
94
94
  )
@@ -96,10 +96,10 @@ export function mergeCandle<T extends { timestamp: number }>(
96
96
  };
97
97
  }
98
98
 
99
- export function candleCompleted(): (source: Observable<Candle>) => Observable<Candle> {
100
- let currCandle: Candle;
99
+ export function ohlcCompleted(): (source: Observable<Ohlc>) => Observable<Ohlc> {
100
+ let currCandle: Ohlc;
101
101
 
102
- return (source: Observable<Candle>) =>
102
+ return (source: Observable<Ohlc>) =>
103
103
  source.pipe(
104
104
  map(it => {
105
105
  if (!currCandle) {
@@ -117,7 +117,7 @@ export function candleCompleted(): (source: Observable<Candle>) => Observable<Ca
117
117
  return undefined;
118
118
  }
119
119
  }),
120
- filter(it => it !== undefined) as OperatorFunction<Candle | undefined, Candle>,
120
+ filter(it => it !== undefined) as OperatorFunction<Ohlc | undefined, Ohlc>,
121
121
  share()
122
122
  );
123
123
  }
@@ -1,11 +1,11 @@
1
1
  import { d, now } from '../shared';
2
- import { Candle } from './candle';
2
+ import { Ohlc } from './ohlc';
3
3
 
4
- describe('Candle', () => {
5
- test('should construct a candle', () => {
4
+ describe('Ohlc', () => {
5
+ test('should construct a ohlc', () => {
6
6
  const timestamp = now();
7
7
 
8
- const sut = new Candle(timestamp, d(2), d(4), d(1), d(3));
8
+ const sut = new Ohlc(timestamp, d(2), d(4), d(1), d(3));
9
9
 
10
10
  expect(sut.timestamp).toEqual(timestamp);
11
11
  expect(sut.open).toEqual(d(2));
@@ -14,10 +14,10 @@ describe('Candle', () => {
14
14
  expect(sut.close).toEqual(d(3));
15
15
  });
16
16
 
17
- test('should modify a candle', () => {
17
+ test('should modify a ohlc', () => {
18
18
  const timestamp = now();
19
19
 
20
- const sut = new Candle(timestamp, d(2), d(4), d(1), d(3));
20
+ const sut = new Ohlc(timestamp, d(2), d(4), d(1), d(3));
21
21
 
22
22
  sut.apply(d(10));
23
23
 
@@ -1,6 +1,6 @@
1
1
  import { decimal, timestamp } from '../shared';
2
2
 
3
- export class Candle {
3
+ export class Ohlc {
4
4
  constructor(
5
5
  public timestamp: timestamp,
6
6
  public open: decimal,
@@ -8,7 +8,7 @@ export class Candle {
8
8
  public low: decimal,
9
9
  public close: decimal,
10
10
  public volume?: decimal
11
- ) {}
11
+ ) { }
12
12
 
13
13
  apply(value: decimal) {
14
14
  this.high = decimal.max(this.high, value);
@@ -13,7 +13,6 @@ export type OrderState =
13
13
  | 'REJECTED';
14
14
 
15
15
  export class Order implements Component {
16
- readonly kind = 'order';
17
16
  state: OrderState = 'NEW';
18
17
  quantityExecuted = d.Zero;
19
18
  averageExecutionRate?: decimal;
@@ -37,10 +36,6 @@ export class Order implements Component {
37
36
  }
38
37
  }
39
38
 
40
- toString() {
41
- return this.id;
42
- }
43
-
44
39
  calculateBalanceToLock(
45
40
  base: Balance,
46
41
  quote: Balance
@@ -18,7 +18,6 @@ export const LiquidityBidComparer = (lhs: { rate: decimal }, rhs: { rate: decima
18
18
  */
19
19
  export class Orderbook implements Component {
20
20
  readonly id: string;
21
- readonly kind = 'orderbook';
22
21
 
23
22
  constructor(
24
23
  public timestamp: number,
@@ -28,8 +27,4 @@ export class Orderbook implements Component {
28
27
  ) {
29
28
  this.id = instrument.id;
30
29
  }
31
-
32
- toString() {
33
- return this.instrument.toString();
34
- }
35
30
  }
@@ -5,7 +5,6 @@ import { Component } from './component';
5
5
  export type PositionMode = 'CROSS' | 'ISOLATED';
6
6
 
7
7
  export class Position implements Component {
8
- readonly kind = 'position';
9
8
  estimatedUnrealizedPnL?: decimal;
10
9
 
11
10
  get margin(): decimal {
@@ -29,8 +28,4 @@ export class Position implements Component {
29
28
 
30
29
  return this.estimatedUnrealizedPnL;
31
30
  }
32
-
33
- toString() {
34
- return this.id;
35
- }
36
31
  }
@@ -27,9 +27,9 @@ export function deposit(selector: AssetSelector, amount: decimal): SessionFeatur
27
27
  };
28
28
  }
29
29
 
30
- export function period(from: Date, to: Date): SessionFeature {
30
+ export function period(from: Date, to?: Date): SessionFeature {
31
31
  return (builder: SessionBuilder) => {
32
- builder.usePeriod(from.getTime(), to.getTime());
32
+ builder.usePeriod(from.getTime(), to?.getTime() ?? now());
33
33
  };
34
34
  }
35
35
 
@@ -76,7 +76,7 @@ export class SessionBuilder {
76
76
  }
77
77
 
78
78
  useBalance(selector: AssetSelector, amount: decimal): SessionBuilder {
79
- this.balance[selector.toString()] = amount;
79
+ this.balance[selector.id] = amount;
80
80
 
81
81
  return this;
82
82
  }
@@ -20,10 +20,10 @@ import { AdapterAggregate } from '../adapter/adapter-aggregate';
20
20
  import {
21
21
  AssetSelector,
22
22
  Balance,
23
- Candle,
24
23
  Instrument,
25
24
  InstrumentSelector,
26
25
  invalidInstrumentSelectorError,
26
+ Ohlc,
27
27
  Order,
28
28
  Orderbook,
29
29
  Position,
@@ -53,7 +53,7 @@ export class Session {
53
53
  readonly store: Store,
54
54
  readonly aggregate: AdapterAggregate,
55
55
  readonly measurement: Measurement | undefined
56
- ) { }
56
+ ) {}
57
57
 
58
58
  async awake(): Promise<void> {
59
59
  if (this.initialized) {
@@ -203,7 +203,7 @@ export class Session {
203
203
  selector: InstrumentSelector,
204
204
  timeframe: number,
205
205
  length: number
206
- ): Observable<Readonly<Candle>> {
206
+ ): Observable<Readonly<Ohlc>> {
207
207
  return this.store.changes$.pipe(
208
208
  startWith(this.store.snapshot.universe.instrument.get(selector.id)),
209
209
  filter(it => it instanceof Instrument && it.id == selector.id),
@@ -8,7 +8,6 @@ import { Component } from './component';
8
8
  */
9
9
  export class Trade implements Component {
10
10
  readonly id: string;
11
- readonly kind = 'trade';
12
11
 
13
12
  constructor(
14
13
  public timestamp: number,
@@ -18,8 +17,4 @@ export class Trade implements Component {
18
17
  ) {
19
18
  this.id = instrument.id;
20
19
  }
21
-
22
- toString() {
23
- return this.instrument.toString();
24
- }
25
20
  }
package/src/index.ts CHANGED
@@ -1,6 +1,80 @@
1
+ import chalk from 'chalk';
2
+ import { finalize, forkJoin, Observable, of, switchMap } from 'rxjs';
3
+
4
+ import { Session, SessionBuilder, SessionFeature } from './domain';
1
5
  export * from './adapter';
2
6
  export * from './domain';
3
7
  export * from './shared';
4
8
  export * from './storage';
5
9
  export * from './store';
6
- export * from './strategy';
10
+
11
+ import { Logger } from './shared';
12
+
13
+ const registry: Record<string, () => Array<SessionFeature>> = {};
14
+
15
+ export type SessionHook = (session: Session) => Observable<any>;
16
+
17
+ /**
18
+ * Describes a single strategy logic
19
+ */
20
+ export let rule: (name: string | undefined, describe: SessionHook) => void;
21
+
22
+ /**
23
+ *
24
+ */
25
+ export let beforeAll: (describe: SessionHook) => void;
26
+
27
+ /**
28
+ *
29
+ * @param name
30
+ * @param describe
31
+ */
32
+ export function describe(name: string, describe: () => Array<SessionFeature>) {
33
+ registry[name] = describe;
34
+ }
35
+
36
+ /**
37
+ *
38
+ * @param name
39
+ * @param builder
40
+ * @returns
41
+ */
42
+ export async function spawn(name: string, builder: SessionBuilder) {
43
+ const describe = registry[name];
44
+ if (!describe) {
45
+ throw new Error(`missing strategy: ${name}`);
46
+ }
47
+
48
+ const ruleHooks = new Array<SessionHook>();
49
+ const beforeAllHooks = new Array<SessionHook>();
50
+
51
+ beforeAll = (describe: SessionHook) => {
52
+ beforeAllHooks.push(describe);
53
+ };
54
+
55
+ rule = (ruleName: string | undefined, describe: SessionHook) => {
56
+ if (ruleName) {
57
+ Logger.info(name, `${chalk.italic(ruleName)} rule found`);
58
+ }
59
+
60
+ ruleHooks.push(describe);
61
+ };
62
+
63
+ for (const feature of describe()) {
64
+ feature(builder);
65
+ }
66
+
67
+ return (session: Session) => {
68
+ const beforeAll$ = beforeAllHooks.map(it => it(session));
69
+ const rule$ = ruleHooks.map(it => it(session));
70
+
71
+ if (!beforeAll$.length) {
72
+ beforeAll$.push(of(true));
73
+ }
74
+
75
+ return forkJoin(beforeAll$).pipe(
76
+ switchMap(() => forkJoin(rule$)),
77
+ finalize(() => session.dispose())
78
+ );
79
+ };
80
+ }
@@ -17,13 +17,13 @@ const time = () => chalk.gray(new Date(now()).toISOString());
17
17
 
18
18
  export class Logger {
19
19
  public static info = (context: string, message: string) =>
20
- console.info(`${time()} ${colorize(context)}: ${message}`);
20
+ console.info(`${this.prefix(context)}: ${message}`);
21
21
 
22
22
  public static debug = (context: string, message: string) =>
23
- console.debug(`${time()} ${colorize(context)}: ${message}`);
23
+ console.debug(`${this.prefix(context)}: ${message}`);
24
24
 
25
25
  public static warn = (context: string, message: string) =>
26
- console.warn(`${time()} ${colorize(context)}: ${message}`);
26
+ console.warn(`${this.prefix(context)}: ${message}`);
27
27
 
28
28
  public static error = (context: string, error: unknown) => {
29
29
  let message = 'Unknown Error';
@@ -32,6 +32,8 @@ export class Logger {
32
32
  message = error.message;
33
33
  }
34
34
 
35
- console.error(`${time()} ${colorize(context)}: ${message}`);
35
+ console.error(`${this.prefix(context)}: ${message}`);
36
36
  };
37
+
38
+ public static prefix = (context: string) => `${time()} ${colorize(context)}`;
37
39
  }
@@ -1,11 +0,0 @@
1
- import { Observable } from 'rxjs';
2
- import { decimal } from '../shared';
3
- import { Candle } from './candle';
4
- export declare function candle<T extends {
5
- timestamp: number;
6
- }>(timeframe: number, fn: (x: T) => decimal, candleToStartWith?: Candle): (source: Observable<T>) => Observable<Candle>;
7
- export declare function mergeCandle<T extends {
8
- timestamp: number;
9
- }>(timeframe: number, fn: (x: T) => decimal, history$: Observable<Candle>): (source$: Observable<T>) => Observable<Candle>;
10
- export declare function candleCompleted(): (source: Observable<Candle>) => Observable<Candle>;
11
- //# sourceMappingURL=candle-operator.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"candle-operator.d.ts","sourceRoot":"","sources":["../../src/domain/candle-operator.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,UAAU,EAKX,MAAM,MAAM,CAAC;AAEd,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAuBlC,wBAAgB,MAAM,CAAC,CAAC,SAAS;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EACpD,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,EACrB,iBAAiB,CAAC,EAAE,MAAM,YAED,WAAW,CAAC,CAAC,KAAG,WAAW,MAAM,CAAC,CAmC5D;AAED,wBAAgB,WAAW,CAAC,CAAC,SAAS;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EACzD,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,EACrB,QAAQ,EAAE,UAAU,CAAC,MAAM,CAAC,aAEF,WAAW,CAAC,CAAC,KAAG,WAAW,MAAM,CAAC,CAY7D;AAED,wBAAgB,eAAe,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,KAAK,UAAU,CAAC,MAAM,CAAC,CAwBpF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"candle.d.ts","sourceRoot":"","sources":["../../src/domain/candle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE/C,qBAAa,MAAM;IAER,SAAS,EAAE,SAAS;IACpB,IAAI,EAAE,OAAO;IACb,IAAI,EAAE,OAAO;IACb,GAAG,EAAE,OAAO;IACZ,KAAK,EAAE,OAAO;IACd,MAAM,CAAC;gBALP,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,OAAO,EACd,MAAM,CAAC,qBAAS;IAGzB,KAAK,CAAC,KAAK,EAAE,OAAO;CAKrB"}
@@ -1,8 +0,0 @@
1
- import { Observable } from 'rxjs';
2
- import { Session, SessionBuilder, SessionFeature } from './domain';
3
- export declare type SessionAction = (session: Session) => Observable<any>;
4
- export declare let rule: (name: string | undefined, describe: SessionAction) => void;
5
- export declare let beforeAll: (describe: SessionAction) => void;
6
- export declare function describe(name: string, describe: () => Array<SessionFeature>): void;
7
- export declare function prepare(name: string, builder: SessionBuilder): Promise<(session: Session) => Observable<any[]>>;
8
- //# sourceMappingURL=strategy.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"strategy.d.ts","sourceRoot":"","sources":["../src/strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,UAAU,EAAa,MAAM,MAAM,CAAC;AAEjE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAKnE,oBAAY,aAAa,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,UAAU,CAAC,GAAG,CAAC,CAAC;AAElE,eAAO,IAAI,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;AAC7E,eAAO,IAAI,SAAS,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;AAExD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC,cAAc,CAAC,QAE3E;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,qBAqBhD,OAAO,wBASzB"}
package/dist/strategy.js DELETED
@@ -1,44 +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.prepare = exports.describe = exports.beforeAll = exports.rule = void 0;
13
- const rxjs_1 = require("rxjs");
14
- const shared_1 = require("./shared");
15
- const registry = {};
16
- function describe(name, describe) {
17
- registry[name] = describe;
18
- }
19
- exports.describe = describe;
20
- function prepare(name, builder) {
21
- return __awaiter(this, void 0, void 0, function* () {
22
- const describe = registry[name];
23
- const rules = new Array();
24
- const beforeAlls = new Array();
25
- exports.beforeAll = (describe) => {
26
- beforeAlls.push(describe);
27
- };
28
- exports.rule = (ruleName, describe) => {
29
- if (ruleName) {
30
- shared_1.Logger.info(name, ruleName);
31
- }
32
- rules.push(describe);
33
- };
34
- for (const plugin of describe()) {
35
- plugin(builder);
36
- }
37
- return (session) => {
38
- const toBeforeAll = beforeAlls.map(it => it(session));
39
- const toRules = rules.map(it => it(session));
40
- return (0, rxjs_1.forkJoin)(toBeforeAll).pipe((0, rxjs_1.switchMap)(() => (0, rxjs_1.forkJoin)(toRules)), (0, rxjs_1.finalize)(() => session.dispose()));
41
- };
42
- });
43
- }
44
- exports.prepare = prepare;
@@ -1,126 +0,0 @@
1
- import { from } from 'rxjs';
2
-
3
- import { d } from '../shared';
4
- import { Candle } from './candle';
5
- import { candle, candleCompleted, mergeCandle } from './candle-operator';
6
-
7
- describe('candle', () => {
8
- test('should aggregate and pipe candle updates', done => {
9
- const input$ = from([
10
- { timestamp: 1, rate: d(1) },
11
- { timestamp: 2, rate: d(2) },
12
- { timestamp: 3, rate: d(3) },
13
- { timestamp: 4, rate: d.Zero },
14
- { timestamp: 5, rate: d(7) },
15
- { timestamp: 6, rate: d(8) }
16
- ]);
17
-
18
- const output = [
19
- new Candle(0, d(1), d(1), d(1), d(1)),
20
- new Candle(0, d(1), d(2), d(1), d(2)),
21
- new Candle(0, d(1), d(3), d(1), d(3)),
22
- new Candle(0, d(1), d(3), d.Zero, d.Zero),
23
- new Candle(5, d.Zero, d(7), d(7), d(7)),
24
- new Candle(5, d.Zero, d(8), d(7), d(8))
25
- ].reverse();
26
-
27
- input$.pipe(candle(5, it => it.rate)).subscribe({
28
- next: it => {
29
- expect(it).toEqual(output.pop());
30
- if (output.length === 0) {
31
- done();
32
- }
33
- }
34
- });
35
- });
36
- });
37
-
38
- describe('candleCompleted', () => {
39
- test('should aggregate and pipe distinct completed candles', done => {
40
- const input$ = from([
41
- { timestamp: 1, rate: d(1) },
42
- { timestamp: 2, rate: d(2) },
43
- { timestamp: 3, rate: d(3) },
44
- { timestamp: 4, rate: d.Zero },
45
- { timestamp: 5, rate: d(7) },
46
- { timestamp: 6, rate: d(8) }
47
- ]);
48
-
49
- input$
50
- .pipe(
51
- candle(5, it => it.rate),
52
- candleCompleted()
53
- )
54
- .subscribe({
55
- next: it => {
56
- expect(it).toEqual(new Candle(0, d(1), d(3), d.Zero, d.Zero));
57
- done();
58
- }
59
- });
60
- });
61
- });
62
-
63
- describe('mergeCandle', () => {
64
- test('should pipe and merge candle from history', done => {
65
- const history$ = from([
66
- new Candle(1, d(1), d(1.5), d(0.5), d(2)),
67
- new Candle(2, d(2), d(2.5), d(1.5), d(3)),
68
- new Candle(3, d(3), d(3.5), d(2.5), d(4))
69
- ]);
70
-
71
- const input$ = from([
72
- { timestamp: 3, rate: d(5) },
73
- { timestamp: 4, rate: d(3) },
74
- { timestamp: 5, rate: d(4) }
75
- ]);
76
-
77
- const output = [
78
- new Candle(1, d(1), d(1.5), d(0.5), d(2)),
79
- new Candle(2, d(2), d(2.5), d(1.5), d(3)),
80
- new Candle(3, d(3), d(5), d(2.5), d(5)),
81
- new Candle(4, d(5), d(3), d(3), d(3)),
82
- new Candle(5, d(3), d(4), d(4), d(4))
83
- ].reverse();
84
-
85
- input$.pipe(mergeCandle(1, it => it.rate, history$)).subscribe({
86
- next: it => {
87
- expect(it).toEqual(output.pop());
88
- if (output.length === 0) {
89
- done();
90
- }
91
- }
92
- });
93
- });
94
-
95
- test('should pipe and not merge candle from history', done => {
96
- const history$ = from([
97
- new Candle(1, d(1), d(1.5), d(0.5), d(2)),
98
- new Candle(2, d(2), d(2.5), d(1.5), d(3)),
99
- new Candle(3, d(3), d(3.5), d(2.5), d(4))
100
- ]);
101
-
102
- const input$ = from([
103
- { timestamp: 4, rate: d(5) },
104
- { timestamp: 5, rate: d(3) },
105
- { timestamp: 6, rate: d(4) }
106
- ]);
107
-
108
- const output = [
109
- new Candle(1, d(1), d(1.5), d(0.5), d(2)),
110
- new Candle(2, d(2), d(2.5), d(1.5), d(3)),
111
- new Candle(3, d(3), d(3.5), d(2.5), d(4)),
112
- new Candle(4, d(4), d(5), d(5), d(5)),
113
- new Candle(5, d(5), d(3), d(3), d(3)),
114
- new Candle(6, d(3), d(4), d(4), d(4))
115
- ].reverse();
116
-
117
- input$.pipe(mergeCandle(1, it => it.rate, history$)).subscribe({
118
- next: it => {
119
- expect(it).toEqual(output.pop());
120
- if (output.length === 0) {
121
- done();
122
- }
123
- }
124
- });
125
- });
126
- });
package/src/strategy.ts DELETED
@@ -1,47 +0,0 @@
1
- import { finalize, forkJoin, Observable, switchMap } from 'rxjs';
2
-
3
- import { Session, SessionBuilder, SessionFeature } from './domain';
4
- import { Logger } from './shared';
5
-
6
- const registry: Record<string, () => Array<SessionFeature>> = {};
7
-
8
- export type SessionAction = (session: Session) => Observable<any>;
9
-
10
- export let rule: (name: string | undefined, describe: SessionAction) => void;
11
- export let beforeAll: (describe: SessionAction) => void;
12
-
13
- export function describe(name: string, describe: () => Array<SessionFeature>) {
14
- registry[name] = describe;
15
- }
16
-
17
- export async function prepare(name: string, builder: SessionBuilder) {
18
- const describe = registry[name];
19
- const rules = new Array<SessionAction>();
20
- const beforeAlls = new Array<SessionAction>();
21
-
22
- beforeAll = (describe: SessionAction) => {
23
- beforeAlls.push(describe);
24
- };
25
-
26
- rule = (ruleName: string | undefined, describe: SessionAction) => {
27
- if (ruleName) {
28
- Logger.info(name, ruleName);
29
- }
30
-
31
- rules.push(describe);
32
- };
33
-
34
- for (const plugin of describe()) {
35
- plugin(builder);
36
- }
37
-
38
- return (session: Session) => {
39
- const toBeforeAll = beforeAlls.map(it => it(session));
40
- const toRules = rules.map(it => it(session));
41
-
42
- return forkJoin(toBeforeAll).pipe(
43
- switchMap(() => forkJoin(toRules)),
44
- finalize(() => session.dispose())
45
- );
46
- };
47
- }