@quantform/core 0.4.8 → 0.5.13

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 (223) 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 +10 -24
  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 +26 -24
  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 +25 -72
  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/jestconfig.json +0 -11
  219. package/src/ipc.spec.ts +0 -73
  220. package/src/ipc.ts +0 -321
  221. package/src/shared/task.ts +0 -30
  222. package/src/shared/worker.spec.ts +0 -25
  223. 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,13 +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
+ merge,
8
9
  mergeMap,
9
10
  Observable,
10
- share,
11
11
  shareReplay,
12
12
  startWith,
13
13
  Subject,
@@ -15,6 +15,7 @@ import {
15
15
  switchMap,
16
16
  take
17
17
  } from 'rxjs';
18
+
18
19
  import { Adapter, BacktesterOptions, PaperOptions } from '../adapter';
19
20
  import { AdapterAggregate } from '../adapter/adapter-aggregate';
20
21
  import {
@@ -26,15 +27,13 @@ import {
26
27
  Order,
27
28
  Orderbook,
28
29
  OrderState,
29
- Position
30
+ Position,
31
+ Trade
30
32
  } from '../domain';
31
- import { Trade } from '../domain/trade';
32
- import { now, Worker } from '../shared';
33
- import { Feed, Measurement } from '../storage';
33
+ import { now } from '../shared';
34
+ import { StorageFactory } from '../storage';
34
35
  import { Store } from '../store';
35
36
 
36
- type Optional<T, K extends keyof T> = Omit<T, K> & Partial<T>;
37
-
38
37
  /**
39
38
  * Describes a single session.
40
39
  * You can use @run function to start a new session managed by CLI.
@@ -64,29 +63,20 @@ export interface SessionDescriptor {
64
63
 
65
64
  /**
66
65
  * Provides historical data for backtest, it's not required for live and paper
67
- * sessions.
68
- */
69
- feed?: Feed;
70
-
71
- /**
72
- * 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
73
67
  * series data. You can install @quantform/editor to render this data in your browser.
74
68
  */
75
- measurement?: Measurement;
69
+ storage?: StorageFactory;
76
70
 
77
71
  /**
78
72
  * Session additional options.
79
73
  */
80
- options?: {
81
- backtester?: BacktesterOptions;
82
- paper?: PaperOptions;
83
- };
74
+ simulation?: PaperOptions & BacktesterOptions;
84
75
  }
85
76
 
86
77
  export class Session {
87
78
  private initialized = false;
88
79
  private subscription: Subscription;
89
- private worker = new Worker();
90
80
 
91
81
  get timestamp(): number {
92
82
  return this.store.snapshot.timestamp;
@@ -116,7 +106,9 @@ export class Session {
116
106
  await this.aggregate.awake();
117
107
 
118
108
  if (describe) {
119
- this.subscription = describe(this).subscribe();
109
+ this.subscription = describe(this)
110
+ .pipe(finalize(() => this.dispose()))
111
+ .subscribe();
120
112
  }
121
113
  }
122
114
 
@@ -125,63 +117,22 @@ export class Session {
125
117
  return;
126
118
  }
127
119
 
128
- this.store.dispose();
129
-
130
120
  if (this.subscription) {
131
121
  this.subscription.unsubscribe();
122
+ this.subscription = undefined;
132
123
  }
133
124
 
125
+ this.store.dispose();
126
+
134
127
  await this.aggregate.dispose();
135
- await this.worker.wait();
128
+
129
+ this.initialized = false;
136
130
  }
137
131
 
138
132
  useStatement(section: string): Record<string, any> {
139
133
  return this.statement[section] ?? (this.statement[section] = {});
140
134
  }
141
135
 
142
- /**
143
- * Returns last stored measurement and setter for it in session.
144
- * For example you can save and restore variables in same session between runs.
145
- * Example usage:
146
- * const [order$, setOrder] = session.measurement<Order>('order');
147
- *
148
- * order.pipe(tap(it => console.log(`your last order was: ${it}`)));
149
- *
150
- * setOrder(order);
151
- */
152
- useMeasure<T extends { timestamp: number }>(
153
- params: { kind: string; timestamp?: number },
154
- defaultValue: T = undefined
155
- ): [Observable<T>, (value: Optional<T, 'timestamp'>) => void] {
156
- const stored$ = from(
157
- this.descriptor.measurement.query(this.descriptor.id, {
158
- to: params.timestamp ?? this.timestamp,
159
- kind: params.kind,
160
- count: 1
161
- })
162
- ).pipe(
163
- map(it =>
164
- it.length ? { timestamp: it[0].timestamp, ...it[0].payload } : defaultValue
165
- ),
166
- share()
167
- );
168
-
169
- const subject$ = new Subject<T>();
170
-
171
- const setter = (value: T) => {
172
- const timestamp = value.timestamp ?? this.timestamp;
173
- const measure = { timestamp, kind: params.kind, payload: value };
174
-
175
- this.worker.enqueue(() =>
176
- this.descriptor.measurement.save(this.descriptor.id, [measure])
177
- );
178
-
179
- subject$.next({ ...value, timestamp });
180
- };
181
-
182
- return [concat(stored$, subject$.asObservable()), setter];
183
- }
184
-
185
136
  /**
186
137
  * Return values for patch provided in optimization file.
187
138
  * Example usage:
@@ -205,11 +156,13 @@ export class Session {
205
156
  * session.open(Order.buyMarket(instrument, 100));
206
157
  */
207
158
  open(order: Order): Observable<Order> {
208
- return defer(() => from(this.aggregate.open(order))).pipe(
209
- switchMap(it =>
210
- this.store.changes$.pipe(filter(it => it instanceof Order && order.id == it.id))
211
- ),
212
- map(it => it as Order)
159
+ const subject = new Subject<Order>();
160
+
161
+ this.aggregate.open(order).catch(subject.error);
162
+
163
+ return merge(
164
+ subject.asObservable(),
165
+ this.order(order.instrument).pipe(filter(it => it.id == order.id))
213
166
  );
214
167
  }
215
168
 
@@ -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 {