@quantform/core 0.4.9 → 0.5.14

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 (222) hide show
  1. package/dist/adapter/adapter-aggregate.d.ts +4 -2
  2. package/dist/adapter/adapter-aggregate.js +4 -3
  3. package/dist/adapter/adapter-aggregate.js.map +1 -1
  4. package/dist/adapter/adapter.d.ts +3 -2
  5. package/dist/adapter/adapter.js +5 -2
  6. package/dist/adapter/adapter.js.map +1 -1
  7. package/dist/adapter/backtester/backtester-adapter.d.ts +1 -1
  8. package/dist/adapter/backtester/backtester-adapter.js +2 -1
  9. package/dist/adapter/backtester/backtester-adapter.js.map +1 -1
  10. package/dist/adapter/backtester/index.js +5 -1
  11. package/dist/adapter/backtester/index.js.map +1 -1
  12. package/dist/adapter/index.js +5 -1
  13. package/dist/adapter/index.js.map +1 -1
  14. package/dist/adapter/paper/index.js +5 -1
  15. package/dist/adapter/paper/index.js.map +1 -1
  16. package/dist/adapter/paper/paper-adapter.d.ts +1 -1
  17. package/dist/adapter/paper/paper-adapter.js +1 -1
  18. package/dist/adapter/paper/paper-adapter.js.map +1 -1
  19. package/dist/adapter/paper/paper-adapter.spec.js +5 -3
  20. package/dist/adapter/paper/paper-adapter.spec.js.map +1 -1
  21. package/dist/adapter/paper/simulator/paper-margin-simulator.d.ts +1 -1
  22. package/dist/adapter/paper/simulator/paper-margin-simulator.js.map +1 -1
  23. package/dist/adapter/paper/simulator/paper-simulator.d.ts +1 -1
  24. package/dist/adapter/paper/simulator/paper-simulator.js.map +1 -1
  25. package/dist/adapter/paper/simulator/paper-spot-simulator.d.ts +1 -1
  26. package/dist/adapter/paper/simulator/paper-spot-simulator.js +1 -1
  27. package/dist/adapter/paper/simulator/paper-spot-simulator.js.map +1 -1
  28. package/dist/bootstrap.js +31 -15
  29. package/dist/bootstrap.js.map +1 -1
  30. package/dist/cli/build.d.ts +1 -0
  31. package/dist/cli/build.js +16 -0
  32. package/dist/cli/build.js.map +1 -0
  33. package/dist/cli/dev.d.ts +1 -0
  34. package/dist/cli/dev.js +17 -0
  35. package/dist/cli/dev.js.map +1 -0
  36. package/dist/cli/index.d.ts +2 -0
  37. package/dist/cli/index.js +72 -0
  38. package/dist/cli/index.js.map +1 -0
  39. package/dist/cli/internal/workspace.d.ts +8 -0
  40. package/dist/cli/internal/workspace.js +14 -0
  41. package/dist/cli/internal/workspace.js.map +1 -0
  42. package/dist/cli/pull.d.ts +1 -0
  43. package/dist/cli/pull.js +50 -0
  44. package/dist/cli/pull.js.map +1 -0
  45. package/dist/cli/run.d.ts +1 -0
  46. package/dist/cli/run.js +19 -0
  47. package/dist/cli/run.js.map +1 -0
  48. package/dist/cli/test.d.ts +1 -0
  49. package/dist/cli/test.js +37 -0
  50. package/dist/cli/test.js.map +1 -0
  51. package/dist/domain/balance.d.ts +4 -3
  52. package/dist/domain/balance.js +20 -19
  53. package/dist/domain/balance.js.map +1 -1
  54. package/dist/domain/balance.spec.js +2 -2
  55. package/dist/domain/balance.spec.js.map +1 -1
  56. package/dist/domain/candle.d.ts +4 -2
  57. package/dist/domain/candle.js +13 -9
  58. package/dist/domain/candle.js.map +1 -1
  59. package/dist/domain/candle.spec.js.map +1 -1
  60. package/dist/domain/component.d.ts +1 -0
  61. package/dist/domain/index.js +5 -1
  62. package/dist/domain/index.js.map +1 -1
  63. package/dist/domain/instrument.d.ts +1 -0
  64. package/dist/domain/instrument.js +1 -0
  65. package/dist/domain/instrument.js.map +1 -1
  66. package/dist/domain/order.d.ts +3 -2
  67. package/dist/domain/order.js +2 -0
  68. package/dist/domain/order.js.map +1 -1
  69. package/dist/domain/orderbook.d.ts +1 -0
  70. package/dist/domain/orderbook.js +1 -0
  71. package/dist/domain/orderbook.js.map +1 -1
  72. package/dist/domain/position.d.ts +1 -0
  73. package/dist/domain/position.js +1 -0
  74. package/dist/domain/position.js.map +1 -1
  75. package/dist/domain/session.d.ts +4 -18
  76. package/dist/domain/session.js +7 -23
  77. package/dist/domain/session.js.map +1 -1
  78. package/dist/domain/statement.js +11 -11
  79. package/dist/domain/statement.js.map +1 -1
  80. package/dist/domain/trade.d.ts +2 -1
  81. package/dist/domain/trade.js +1 -0
  82. package/dist/domain/trade.js.map +1 -1
  83. package/dist/index.d.ts +0 -1
  84. package/dist/index.js +5 -2
  85. package/dist/index.js.map +1 -1
  86. package/dist/indicator/atr.js.map +1 -1
  87. package/dist/indicator/cross.spec.js.map +1 -1
  88. package/dist/indicator/donchian.js.map +1 -1
  89. package/dist/indicator/ema.js.map +1 -1
  90. package/dist/indicator/ema.spec.js.map +1 -1
  91. package/dist/indicator/envelope.js.map +1 -1
  92. package/dist/indicator/index.js +5 -1
  93. package/dist/indicator/index.js.map +1 -1
  94. package/dist/indicator/macd.js.map +1 -1
  95. package/dist/indicator/min-max.js.map +1 -1
  96. package/dist/indicator/rma.js.map +1 -1
  97. package/dist/indicator/sma.js.map +1 -1
  98. package/dist/indicator/sma.spec.js.map +1 -1
  99. package/dist/indicator/swma.js.map +1 -1
  100. package/dist/indicator/tma.js.map +1 -1
  101. package/dist/indicator/tma.spec.js.map +1 -1
  102. package/dist/indicator/trailing.spec.js.map +1 -1
  103. package/dist/indicator/truerange.js.map +1 -1
  104. package/dist/indicator/truerange.spec.js.map +1 -1
  105. package/dist/indicator/window.js.map +1 -1
  106. package/dist/indicator/wma.js.map +1 -1
  107. package/dist/indicator/wma.spec.js.map +1 -1
  108. package/dist/shared/index.d.ts +0 -2
  109. package/dist/shared/index.js +5 -3
  110. package/dist/shared/index.js.map +1 -1
  111. package/dist/shared/policy.spec.js +2 -6
  112. package/dist/shared/policy.spec.js.map +1 -1
  113. package/dist/storage/cache.d.ts +9 -0
  114. package/dist/storage/cache.js +32 -0
  115. package/dist/storage/cache.js.map +1 -0
  116. package/dist/storage/index.d.ts +1 -0
  117. package/dist/storage/index.js +6 -1
  118. package/dist/storage/index.js.map +1 -1
  119. package/dist/storage/storage.d.ts +7 -0
  120. package/dist/storage/storage.js +11 -1
  121. package/dist/storage/storage.js.map +1 -1
  122. package/dist/store/event/index.js +5 -1
  123. package/dist/store/event/index.js.map +1 -1
  124. package/dist/store/event/store-balance.event.spec.js +3 -3
  125. package/dist/store/event/store-balance.event.spec.js.map +1 -1
  126. package/dist/store/event/store-candle.event.d.ts +1 -1
  127. package/dist/store/event/store-candle.event.js.map +1 -1
  128. package/dist/store/event/store-candle.event.spec.js +1 -1
  129. package/dist/store/event/store-candle.event.spec.js.map +1 -1
  130. package/dist/store/event/store-instrument.event.spec.js +1 -1
  131. package/dist/store/event/store-instrument.event.spec.js.map +1 -1
  132. package/dist/store/event/store-trade.event.spec.js +2 -2
  133. package/dist/store/event/store-trade.event.spec.js.map +1 -1
  134. package/dist/store/index.js +5 -1
  135. package/dist/store/index.js.map +1 -1
  136. package/dist/store/store.js.map +1 -1
  137. package/dist/tests/backtester-adapter.spec.js +2 -1
  138. package/dist/tests/backtester-adapter.spec.js.map +1 -1
  139. package/dist/tsconfig.tsbuildinfo +1 -1
  140. package/package.json +24 -21
  141. package/src/adapter/adapter-aggregate.ts +8 -3
  142. package/src/adapter/adapter.ts +9 -3
  143. package/src/adapter/backtester/backtester-adapter.ts +3 -1
  144. package/src/adapter/paper/paper-adapter.spec.ts +5 -3
  145. package/src/adapter/paper/paper-adapter.ts +1 -1
  146. package/src/adapter/paper/simulator/paper-margin-simulator.ts +1 -1
  147. package/src/adapter/paper/simulator/paper-simulator.ts +2 -1
  148. package/src/adapter/paper/simulator/paper-spot-simulator.ts +2 -2
  149. package/src/bootstrap.ts +47 -18
  150. package/src/cli/build.ts +15 -0
  151. package/src/cli/dev.ts +18 -0
  152. package/src/cli/index.ts +81 -0
  153. package/src/cli/internal/workspace.ts +18 -0
  154. package/src/cli/pull.ts +67 -0
  155. package/src/cli/run.ts +22 -0
  156. package/src/cli/test.ts +50 -0
  157. package/src/domain/balance.spec.ts +2 -2
  158. package/src/domain/balance.ts +20 -19
  159. package/src/domain/candle.spec.ts +1 -0
  160. package/src/domain/candle.ts +20 -10
  161. package/src/domain/component.ts +1 -0
  162. package/src/domain/instrument.ts +1 -0
  163. package/src/domain/order.ts +3 -1
  164. package/src/domain/orderbook.ts +1 -0
  165. package/src/domain/position.ts +2 -0
  166. package/src/domain/session.ts +17 -67
  167. package/src/domain/statement.ts +13 -12
  168. package/src/domain/trade.ts +2 -1
  169. package/src/index.ts +0 -1
  170. package/src/indicator/atr.ts +1 -0
  171. package/src/indicator/cross.spec.ts +1 -0
  172. package/src/indicator/donchian.ts +1 -0
  173. package/src/indicator/ema.spec.ts +1 -0
  174. package/src/indicator/ema.ts +1 -0
  175. package/src/indicator/envelope.ts +1 -0
  176. package/src/indicator/macd.ts +1 -0
  177. package/src/indicator/min-max.ts +1 -0
  178. package/src/indicator/rma.ts +1 -0
  179. package/src/indicator/sma.spec.ts +1 -0
  180. package/src/indicator/sma.ts +1 -0
  181. package/src/indicator/swma.ts +1 -0
  182. package/src/indicator/tma.spec.ts +1 -0
  183. package/src/indicator/tma.ts +1 -0
  184. package/src/indicator/trailing.spec.ts +1 -0
  185. package/src/indicator/truerange.spec.ts +1 -0
  186. package/src/indicator/truerange.ts +1 -0
  187. package/src/indicator/window.ts +1 -0
  188. package/src/indicator/wma.spec.ts +1 -0
  189. package/src/indicator/wma.ts +1 -0
  190. package/src/shared/index.ts +0 -2
  191. package/src/shared/policy.spec.ts +2 -6
  192. package/src/storage/cache.ts +35 -0
  193. package/src/storage/index.ts +1 -0
  194. package/src/storage/storage.ts +15 -0
  195. package/src/store/event/store-balance.event.spec.ts +3 -3
  196. package/src/store/event/store-candle.event.spec.ts +1 -1
  197. package/src/store/event/store-candle.event.ts +2 -2
  198. package/src/store/event/store-instrument.event.spec.ts +1 -1
  199. package/src/store/event/store-trade.event.spec.ts +2 -2
  200. package/src/store/store.ts +1 -0
  201. package/src/tests/backtester-adapter.spec.ts +3 -2
  202. package/tsconfig.json +2 -2
  203. package/dist/ipc.d.ts +0 -33
  204. package/dist/ipc.js +0 -244
  205. package/dist/ipc.js.map +0 -1
  206. package/dist/ipc.spec.d.ts +0 -1
  207. package/dist/ipc.spec.js +0 -57
  208. package/dist/ipc.spec.js.map +0 -1
  209. package/dist/shared/task.d.ts +0 -6
  210. package/dist/shared/task.js +0 -25
  211. package/dist/shared/task.js.map +0 -1
  212. package/dist/shared/worker.d.ts +0 -10
  213. package/dist/shared/worker.js +0 -46
  214. package/dist/shared/worker.js.map +0 -1
  215. package/dist/shared/worker.spec.d.ts +0 -1
  216. package/dist/shared/worker.spec.js +0 -18
  217. package/dist/shared/worker.spec.js.map +0 -1
  218. package/src/ipc.spec.ts +0 -73
  219. package/src/ipc.ts +0 -321
  220. package/src/shared/task.ts +0 -30
  221. package/src/shared/worker.spec.ts +0 -25
  222. package/src/shared/worker.ts +0 -55
@@ -9,6 +9,7 @@ import {
9
9
  skipLast,
10
10
  withLatestFrom
11
11
  } from 'rxjs';
12
+
12
13
  import { timestamp } from '../shared';
13
14
  import { tf } from './timeframe';
14
15
 
@@ -29,10 +30,10 @@ export class Candle {
29
30
  }
30
31
 
31
32
  export class CandleBuilder {
32
- private _candle: Candle;
33
+ private current: Candle;
33
34
 
34
35
  get candle(): Candle {
35
- return this._candle;
36
+ return this.current;
36
37
  }
37
38
 
38
39
  constructor(readonly timeframe: number) {}
@@ -40,8 +41,8 @@ export class CandleBuilder {
40
41
  append(value: number, timestamp: timestamp): Candle {
41
42
  const frame = tf(timestamp, this.timeframe);
42
43
 
43
- if (!this._candle) {
44
- this._candle = new Candle(frame, value, value, value, value);
44
+ if (!this.current) {
45
+ this.current = new Candle(frame, value, value, value, value);
45
46
 
46
47
  return null;
47
48
  }
@@ -52,25 +53,34 @@ export class CandleBuilder {
52
53
  return null;
53
54
  }
54
55
 
55
- const previous = this._candle;
56
+ const previous = this.current;
56
57
 
57
- this._candle = new Candle(frame, value, value, value, value);
58
+ this.current = new Candle(frame, value, value, value, value);
58
59
  return previous;
59
60
  }
60
61
  }
61
62
 
62
63
  export function candle<T extends { timestamp: number }>(
63
64
  timeframe: number,
64
- fn: (x: T) => number
65
+ fn: (x: T) => number,
66
+ options: { passThru: boolean } = { passThru: false }
65
67
  ) {
66
68
  return function (source: Observable<T>): Observable<Candle> {
67
69
  const builder = new CandleBuilder(timeframe);
68
70
  let candle: Candle;
69
71
 
72
+ if (options.passThru) {
73
+ return source.pipe(
74
+ map(it => {
75
+ builder.append(fn(it), it.timestamp);
76
+ return builder.candle;
77
+ }),
78
+ share()
79
+ );
80
+ }
81
+
70
82
  return source.pipe(
71
- filter(it => {
72
- return (candle = builder.append(fn(it), it.timestamp)) != null;
73
- }),
83
+ filter(it => (candle = builder.append(fn(it), it.timestamp)) != null),
74
84
  map(_ => candle),
75
85
  share()
76
86
  );
@@ -1,5 +1,6 @@
1
1
  import { timestamp } from '../shared';
2
2
 
3
3
  export interface Component {
4
+ kind: string;
4
5
  timestamp: timestamp;
5
6
  }
@@ -25,6 +25,7 @@ export class InstrumentSelector {
25
25
  * Represents trading market which is made up by two trading assets (base and quoted).
26
26
  */
27
27
  export class Instrument extends InstrumentSelector implements Component {
28
+ kind = 'instrument';
28
29
  timestamp: timestamp;
29
30
  commission: Commission;
30
31
  cross: Instrument;
@@ -1,4 +1,5 @@
1
1
  import { v4 } from 'uuid';
2
+
2
3
  import { timestamp } from '../shared';
3
4
  import { Component } from './component';
4
5
  import { InstrumentSelector } from './instrument';
@@ -14,12 +15,13 @@ export type OrderState =
14
15
  | 'REJECTED';
15
16
 
16
17
  export class Order implements Component {
18
+ kind = 'order';
17
19
  timestamp: timestamp;
18
20
  id = v4();
19
21
  externalId: string;
20
22
  state: OrderState = 'NEW';
21
23
 
22
- quantityExecuted: number;
24
+ quantityExecuted = 0;
23
25
  averageExecutionRate: number;
24
26
  createdAt: timestamp;
25
27
  comment: string;
@@ -6,6 +6,7 @@ import { Component } from './component';
6
6
  * Provides an access to pending buy and sell orders on the specific market.
7
7
  */
8
8
  export class Orderbook implements Component {
9
+ kind = 'orderbook';
9
10
  timestamp: timestamp;
10
11
  bestAskRate: number;
11
12
  bestAskQuantity: number;
@@ -1,4 +1,5 @@
1
1
  import { map, Observable, share } from 'rxjs';
2
+
2
3
  import { Instrument } from '../domain';
3
4
  import { pnl, timestamp, weightedMean } from '../shared';
4
5
  import { Component } from './component';
@@ -6,6 +7,7 @@ import { Component } from './component';
6
7
  export type PositionMode = 'CROSS' | 'ISOLATED';
7
8
 
8
9
  export class Position implements Component {
10
+ kind = 'position';
9
11
  timestamp: timestamp;
10
12
  averageExecutionRate: number;
11
13
  size: number;
@@ -1,14 +1,13 @@
1
1
  import {
2
- concat,
3
2
  defer,
4
3
  distinctUntilChanged,
5
4
  filter,
5
+ finalize,
6
6
  from,
7
7
  map,
8
8
  merge,
9
9
  mergeMap,
10
10
  Observable,
11
- share,
12
11
  shareReplay,
13
12
  startWith,
14
13
  Subject,
@@ -16,6 +15,7 @@ import {
16
15
  switchMap,
17
16
  take
18
17
  } from 'rxjs';
18
+
19
19
  import { Adapter, BacktesterOptions, PaperOptions } from '../adapter';
20
20
  import { AdapterAggregate } from '../adapter/adapter-aggregate';
21
21
  import {
@@ -27,15 +27,13 @@ import {
27
27
  Order,
28
28
  Orderbook,
29
29
  OrderState,
30
- Position
30
+ Position,
31
+ Trade
31
32
  } from '../domain';
32
- import { Trade } from '../domain/trade';
33
- import { now, Worker } from '../shared';
34
- import { Feed, Measurement } from '../storage';
33
+ import { now } from '../shared';
34
+ import { StorageFactory } from '../storage';
35
35
  import { Store } from '../store';
36
36
 
37
- type Optional<T, K extends keyof T> = Omit<T, K> & Partial<T>;
38
-
39
37
  /**
40
38
  * Describes a single session.
41
39
  * You can use @run function to start a new session managed by CLI.
@@ -65,29 +63,20 @@ export interface SessionDescriptor {
65
63
 
66
64
  /**
67
65
  * Provides historical data for backtest, it's not required for live and paper
68
- * sessions.
69
- */
70
- feed?: Feed;
71
-
72
- /**
73
- * Stores session variables i.e. indicators, orders, or any other type of time
66
+ * sessions. Stores session variables i.e. indicators, orders, or any other type of time
74
67
  * series data. You can install @quantform/editor to render this data in your browser.
75
68
  */
76
- measurement?: Measurement;
69
+ storage?: StorageFactory;
77
70
 
78
71
  /**
79
72
  * Session additional options.
80
73
  */
81
- options?: {
82
- backtester?: BacktesterOptions;
83
- paper?: PaperOptions;
84
- };
74
+ simulation?: PaperOptions & BacktesterOptions;
85
75
  }
86
76
 
87
77
  export class Session {
88
78
  private initialized = false;
89
79
  private subscription: Subscription;
90
- private worker = new Worker();
91
80
 
92
81
  get timestamp(): number {
93
82
  return this.store.snapshot.timestamp;
@@ -117,7 +106,9 @@ export class Session {
117
106
  await this.aggregate.awake();
118
107
 
119
108
  if (describe) {
120
- this.subscription = describe(this).subscribe();
109
+ this.subscription = describe(this)
110
+ .pipe(finalize(() => this.dispose()))
111
+ .subscribe();
121
112
  }
122
113
  }
123
114
 
@@ -126,63 +117,22 @@ export class Session {
126
117
  return;
127
118
  }
128
119
 
129
- this.store.dispose();
130
-
131
120
  if (this.subscription) {
132
121
  this.subscription.unsubscribe();
122
+ this.subscription = undefined;
133
123
  }
134
124
 
125
+ this.store.dispose();
126
+
135
127
  await this.aggregate.dispose();
136
- await this.worker.wait();
128
+
129
+ this.initialized = false;
137
130
  }
138
131
 
139
132
  useStatement(section: string): Record<string, any> {
140
133
  return this.statement[section] ?? (this.statement[section] = {});
141
134
  }
142
135
 
143
- /**
144
- * Returns last stored measurement and setter for it in session.
145
- * For example you can save and restore variables in same session between runs.
146
- * Example usage:
147
- * const [order$, setOrder] = session.measurement<Order>('order');
148
- *
149
- * order.pipe(tap(it => console.log(`your last order was: ${it}`)));
150
- *
151
- * setOrder(order);
152
- */
153
- useMeasure<T extends { timestamp: number }>(
154
- params: { kind: string; timestamp?: number },
155
- defaultValue: T = undefined
156
- ): [Observable<T>, (value: Optional<T, 'timestamp'>) => void] {
157
- const stored$ = from(
158
- this.descriptor.measurement.query(this.descriptor.id, {
159
- to: params.timestamp ?? this.timestamp,
160
- kind: params.kind,
161
- count: 1
162
- })
163
- ).pipe(
164
- map(it =>
165
- it.length ? { timestamp: it[0].timestamp, ...it[0].payload } : defaultValue
166
- ),
167
- share()
168
- );
169
-
170
- const subject$ = new Subject<T>();
171
-
172
- const setter = (value: T) => {
173
- const timestamp = value.timestamp ?? this.timestamp;
174
- const measure = { timestamp, kind: params.kind, payload: value };
175
-
176
- this.worker.enqueue(() =>
177
- this.descriptor.measurement.save(this.descriptor.id, [measure])
178
- );
179
-
180
- subject$.next({ ...value, timestamp });
181
- };
182
-
183
- return [concat(stored$, subject$.asObservable()), setter];
184
- }
185
-
186
136
  /**
187
137
  * Return values for patch provided in optimization file.
188
138
  * Example usage:
@@ -1,7 +1,8 @@
1
1
  import { combineLatest, finalize, map, take, tap } from 'rxjs';
2
- import { InstrumentSelector, Session } from '.';
2
+
3
3
  import { drawdown } from '../indicator';
4
4
  import { floor, precision } from '../shared';
5
+ import { InstrumentSelector, Session } from '.';
5
6
 
6
7
  export function period() {
7
8
  return (session: Session) => {
@@ -46,11 +47,11 @@ export function benchmark(instrument: InstrumentSelector) {
46
47
  finalize(() => {
47
48
  const pnl = exit / entry - 1;
48
49
 
49
- statement['benchmark_entry'] = entry;
50
- statement['benchmark_exit'] = exit;
51
- statement['benchmark_pnl'] = floor(balance * pnl, precision(entry));
52
- statement['benchmark_pnl_pp'] = floor(pnl * 100, 2);
53
- statement['benchmark_drawdown_pp'] = floor(dd * 100, 2);
50
+ statement.benchmark_entry = entry;
51
+ statement.benchmark_exit = exit;
52
+ statement.benchmark_pnl = floor(balance * pnl, precision(entry));
53
+ statement.benchmark_pnl_pp = floor(pnl * 100, 2);
54
+ statement.benchmark_drawdown_pp = floor(dd * 100, 2);
54
55
  })
55
56
  );
56
57
  };
@@ -106,12 +107,12 @@ export function equity(instrument: InstrumentSelector) {
106
107
  const pnl = equity / balance - 1;
107
108
  const scale = precision(equity);
108
109
 
109
- statement['equity'] = equity;
110
- statement['equity_min'] = min;
111
- statement['equity_max'] = max;
112
- statement['equity_pnl'] = floor(balance * pnl, scale);
113
- statement['equity_pnl_pp'] = floor(pnl * 100, 2);
114
- statement['equity_drawdown_pp'] = floor(dd * 100, 2);
110
+ statement.equity = equity;
111
+ statement.equity_min = min;
112
+ statement.equity_max = max;
113
+ statement.equity_pnl = floor(balance * pnl, scale);
114
+ statement.equity_pnl_pp = floor(pnl * 100, 2);
115
+ statement.equity_drawdown_pp = floor(dd * 100, 2);
115
116
  })
116
117
  );
117
118
  };
@@ -1,5 +1,5 @@
1
- import { Instrument } from '.';
2
1
  import { timestamp } from '../shared';
2
+ import { Instrument } from '.';
3
3
  import { Component } from './component';
4
4
 
5
5
  /**
@@ -7,6 +7,7 @@ import { Component } from './component';
7
7
  * and seller of the same asset.
8
8
  */
9
9
  export class Trade implements Component {
10
+ kind = 'trade';
10
11
  timestamp: timestamp;
11
12
  rate: number;
12
13
  quantity: number;
package/src/index.ts CHANGED
@@ -2,7 +2,6 @@ export * from './adapter';
2
2
  export * from './bootstrap';
3
3
  export * from './domain';
4
4
  export * from './indicator';
5
- export * from './ipc';
6
5
  export * from './shared';
7
6
  export * from './storage';
8
7
  export * from './store';
@@ -1,4 +1,5 @@
1
1
  import { map, Observable, share } from 'rxjs';
2
+
2
3
  import { Candle } from '../domain';
3
4
  import { rma } from './rma';
4
5
  import { truerange } from './truerange';
@@ -1,4 +1,5 @@
1
1
  import { from } from 'rxjs';
2
+
2
3
  import { crossover, crossunder } from './cross';
3
4
 
4
5
  describe('crossunder tests', () => {
@@ -1,4 +1,5 @@
1
1
  import { map, Observable, share, withLatestFrom } from 'rxjs';
2
+
2
3
  import { Candle } from '../domain';
3
4
  import { minMax } from './min-max';
4
5
 
@@ -1,4 +1,5 @@
1
1
  import { from } from 'rxjs';
2
+
2
3
  import { ema } from './ema';
3
4
 
4
5
  describe('ema tests', () => {
@@ -1,4 +1,5 @@
1
1
  import { map, Observable, share } from 'rxjs';
2
+
2
3
  import { sma } from './sma';
3
4
 
4
5
  export function ema<T>(length: number, fn: (it: T) => number) {
@@ -1,4 +1,5 @@
1
1
  import { map, Observable, share } from 'rxjs';
2
+
2
3
  import { sma } from './sma';
3
4
 
4
5
  export function envelope<T>(length: number, percent: number, valueFn: (it: T) => number) {
@@ -1,4 +1,5 @@
1
1
  import { map, Observable, share, withLatestFrom } from 'rxjs';
2
+
2
3
  import { ema } from './ema';
3
4
 
4
5
  export function macd<T>(
@@ -1,4 +1,5 @@
1
1
  import { filter, map, Observable, share } from 'rxjs';
2
+
2
3
  import { window } from './window';
3
4
 
4
5
  export function minMax<T>(length: number, fn: (it: T) => number) {
@@ -1,4 +1,5 @@
1
1
  import { map, Observable, share } from 'rxjs';
2
+
2
3
  import { sma } from '.';
3
4
 
4
5
  export function rma<T>(length: number, fn: (it: T) => number) {
@@ -1,4 +1,5 @@
1
1
  import { from } from 'rxjs';
2
+
2
3
  import { sma } from './sma';
3
4
 
4
5
  describe('sma tests', () => {
@@ -1,4 +1,5 @@
1
1
  import { filter, map, Observable, share, tap } from 'rxjs';
2
+
2
3
  import { window } from './window';
3
4
 
4
5
  export function sma<T>(length: number, fn: (it: T) => number) {
@@ -1,4 +1,5 @@
1
1
  import { filter, map, Observable, share } from 'rxjs';
2
+
2
3
  import { window } from './window';
3
4
 
4
5
  export function swma<T>(fn: (it: T) => number) {
@@ -1,4 +1,5 @@
1
1
  import { from } from 'rxjs';
2
+
2
3
  import { tma } from './tma';
3
4
 
4
5
  describe('tma tests', () => {
@@ -1,4 +1,5 @@
1
1
  import { map, Observable, share } from 'rxjs';
2
+
2
3
  import { swma } from './swma';
3
4
  import { wma } from './wma';
4
5
 
@@ -1,4 +1,5 @@
1
1
  import { from } from 'rxjs';
2
+
2
3
  import { trailingdown, trailingup } from './trailing';
3
4
 
4
5
  describe('trailing up tests', () => {
@@ -1,4 +1,5 @@
1
1
  import { from } from 'rxjs';
2
+
2
3
  import { Candle } from '../domain';
3
4
  import { now } from '../shared';
4
5
  import { sma } from './sma';
@@ -1,4 +1,5 @@
1
1
  import { map, Observable, share } from 'rxjs';
2
+
2
3
  import { Candle } from '../domain';
3
4
 
4
5
  export function truerange<T>(fn: (it: T) => Candle) {
@@ -1,4 +1,5 @@
1
1
  import { map, Observable, share } from 'rxjs';
2
+
2
3
  import { RingBuffer } from './ring-buffer';
3
4
 
4
5
  export function window<T, Y>(length: number, fn: (value: T) => Y) {
@@ -1,4 +1,5 @@
1
1
  import { from } from 'rxjs';
2
+
2
3
  import { wma } from './wma';
3
4
 
4
5
  describe('wma tests', () => {
@@ -1,4 +1,5 @@
1
1
  import { filter, map, Observable, share } from 'rxjs';
2
+
2
3
  import { window } from './window';
3
4
 
4
5
  export function wma<T>(length: number, fn: (it: T) => number) {
@@ -3,6 +3,4 @@ export * from './decimals';
3
3
  export * from './io';
4
4
  export * from './logger';
5
5
  export * from './policy';
6
- export * from './task';
7
6
  export * from './topic';
8
- export * from './worker';
@@ -4,9 +4,7 @@ describe('cache policy tests', () => {
4
4
  test('string as key cache', async () => {
5
5
  let counter = 0;
6
6
 
7
- const request = async () => {
8
- return ++counter;
9
- };
7
+ const request = async () => ++counter;
10
8
 
11
9
  expect(await cache('abc', request)).toBe(1);
12
10
  expect(await cache('abc', request)).toBe(1);
@@ -17,9 +15,7 @@ describe('cache policy tests', () => {
17
15
  test('object as key cache', async () => {
18
16
  let counter = 0;
19
17
 
20
- const request = async () => {
21
- return ++counter;
22
- };
18
+ const request = async () => ++counter;
23
19
 
24
20
  expect(await cache({ from: 1, to: 2, content: 'abc' }, request)).toBe(1);
25
21
  expect(await cache({ from: 1, to: 2, content: 'abc' }, request)).toBe(1);
@@ -0,0 +1,35 @@
1
+ import { now } from '../shared';
2
+ import { Storage } from './storage';
3
+
4
+ export class Cache {
5
+ constructor(private readonly storage: Storage) {}
6
+
7
+ async tryGet<T>(
8
+ getter: () => Promise<T>,
9
+ options: { key: string; ttl?: number }
10
+ ): Promise<T> {
11
+ const time = now();
12
+
13
+ const payload = await this.storage.query(options.key, {
14
+ kind: 'cache',
15
+ count: 1,
16
+ to: time
17
+ });
18
+
19
+ if ((!payload.length || payload[0].timestamp < time - options.ttl) ?? 60 * 60 * 24) {
20
+ const value = await getter();
21
+
22
+ await this.storage.save(options.key, [
23
+ {
24
+ timestamp: time,
25
+ kind: 'cache',
26
+ json: JSON.stringify(value)
27
+ }
28
+ ]);
29
+
30
+ return value;
31
+ }
32
+
33
+ return JSON.parse(payload[0].json);
34
+ }
35
+ }
@@ -1,3 +1,4 @@
1
1
  export * from './feed';
2
2
  export * from './measurement';
3
3
  export * from './storage';
4
+ export * from './cache';
@@ -35,6 +35,13 @@ export interface Storage {
35
35
  query(library: string, options: StorageQueryOptions): Promise<StorageDocument[]>;
36
36
  }
37
37
 
38
+ /**
39
+ *
40
+ */
41
+ export interface StorageFactory {
42
+ create(type: string): Storage;
43
+ }
44
+
38
45
  /**
39
46
  *
40
47
  */
@@ -111,3 +118,11 @@ export class InMemoryStorage implements Storage {
111
118
  this.tables = {};
112
119
  }
113
120
  }
121
+
122
+ export class InMemoryStorageFactory implements StorageFactory {
123
+ private readonly storage: Record<string, Storage> = {};
124
+
125
+ create(type: string): Storage {
126
+ return this.storage[type] ?? (this.storage[type] = new InMemoryStorage());
127
+ }
128
+ }
@@ -1,7 +1,7 @@
1
- import { BalancePatchEvent } from '.';
2
- import { Store } from '..';
3
1
  import { Asset, Commission } from '../../domain';
4
2
  import { now } from '../../shared';
3
+ import { Store } from '..';
4
+ import { BalancePatchEvent } from '.';
5
5
  import { InstrumentPatchEvent } from './store-instrument.event';
6
6
 
7
7
  describe('balance event tests', () => {
@@ -23,7 +23,7 @@ describe('balance event tests', () => {
23
23
 
24
24
  expect(balance).toEqual(component);
25
25
  expect(balance.free).toEqual(100);
26
- expect(balance.freezed).toEqual(0);
26
+ expect(balance.locked).toEqual(0);
27
27
  expect(balance.timestamp).toEqual(timestamp);
28
28
  expect(store.snapshot.timestamp).toEqual(timestamp);
29
29
  });
@@ -1,7 +1,7 @@
1
- import { CandleEvent } from '.';
2
1
  import { Asset, Instrument } from '../../domain';
3
2
  import { now } from '../../shared';
4
3
  import { Store } from '../store';
4
+ import { CandleEvent } from '.';
5
5
 
6
6
  const instrument = new Instrument(
7
7
  new Asset('btc', 'binance', 8),
@@ -1,11 +1,11 @@
1
- import { StateChangeTracker } from '..';
2
1
  import { InstrumentSelector } from '../../domain';
3
2
  import { timestamp } from '../../shared/datetime';
4
3
  import { event } from '../../shared/topic';
4
+ import { StateChangeTracker } from '..';
5
5
  import { State } from '../store.state';
6
+ import { StoreEvent } from './store.event';
6
7
  import { OrderbookPatchEventHandler } from './store-orderbook.event';
7
8
  import { TradePatchEventHandler } from './store-trade.event';
8
- import { StoreEvent } from './store.event';
9
9
 
10
10
  @event
11
11
  export class CandleEvent implements StoreEvent {
@@ -1,6 +1,6 @@
1
- import { Store } from '..';
2
1
  import { Asset, Commission } from '../../domain';
3
2
  import { now } from '../../shared';
3
+ import { Store } from '..';
4
4
  import { InstrumentPatchEvent } from './store-instrument.event';
5
5
 
6
6
  describe('instrument patch event tests', () => {
@@ -1,7 +1,7 @@
1
- import { TradePatchEvent } from '.';
2
- import { Store } from '..';
3
1
  import { Asset, Instrument } from '../../domain';
4
2
  import { now } from '../../shared';
3
+ import { Store } from '..';
4
+ import { TradePatchEvent } from '.';
5
5
 
6
6
  const instrument = new Instrument(
7
7
  new Asset('btc', 'binance', 8),