@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
@@ -1,6 +1,6 @@
1
1
  import { Candle, InstrumentSelector, Order } from '../domain';
2
2
  import { now, timestamp } from '../shared';
3
- import { Feed } from '../storage';
3
+ import { Cache, Feed } from '../storage';
4
4
  import { State, Store, StoreEvent } from '../store';
5
5
  import { PaperAdapter } from './paper';
6
6
  import { PaperSimulator } from './paper/simulator/paper-simulator';
@@ -20,7 +20,11 @@ export class AdapterContext {
20
20
  return this.store.snapshot;
21
21
  }
22
22
 
23
- constructor(private readonly adapter: Adapter, private readonly store: Store) {}
23
+ constructor(
24
+ private readonly adapter: Adapter,
25
+ private readonly store: Store,
26
+ readonly cache: Cache
27
+ ) {}
24
28
 
25
29
  dispatch(...events: StoreEvent[]) {
26
30
  return this.store.dispatch(...events);
@@ -65,7 +69,9 @@ export abstract class Adapter {
65
69
  /**
66
70
  * Dispose an adapter.
67
71
  */
68
- async dispose(): Promise<void> {}
72
+ async dispose(): Promise<void> {
73
+ throw new Error('method not implemented');
74
+ }
69
75
 
70
76
  /**
71
77
  * Subscribe to collection of instruments.
@@ -1,7 +1,7 @@
1
- import { Adapter, AdapterContext } from '..';
2
1
  import { Candle, InstrumentSelector, Order } from '../../domain';
3
2
  import { timestamp } from '../../shared';
4
3
  import { InstrumentSubscriptionEvent } from '../../store';
4
+ import { Adapter, AdapterContext } from '..';
5
5
  import { FeedQuery, HistoryQuery } from '../adapter';
6
6
  import { PaperAdapter, PaperOptions } from '../paper';
7
7
  import { PaperSimulator } from '../paper/simulator/paper-simulator';
@@ -42,6 +42,8 @@ export class BacktesterAdapter extends Adapter {
42
42
  it => new InstrumentSubscriptionEvent(this.context.timestamp, it, true)
43
43
  )
44
44
  );
45
+
46
+ this.streamer.tryContinue();
45
47
  }
46
48
 
47
49
  account(): Promise<void> {
@@ -1,8 +1,9 @@
1
- import { PaperSpotSimulator } from '.';
2
- import { AdapterContext } from '..';
1
+ import { Cache, InMemoryStorage } from '../../storage';
3
2
  import { InstrumentPatchEvent, Store } from '../../store';
3
+ import { AdapterContext } from '..';
4
4
  import { Adapter } from '../adapter';
5
5
  import { Asset, Commission, instrumentOf, Order } from './../../domain';
6
+ import { PaperSpotSimulator } from '.';
6
7
  import { PaperAdapter } from './paper-adapter';
7
8
  import { PaperSimulator } from './simulator/paper-simulator';
8
9
 
@@ -52,10 +53,11 @@ describe('paper adapter tests', () => {
52
53
  test('', async () => {
53
54
  const store = new Store();
54
55
  const adapter = new DefaultAdapter();
56
+ const cache = new Cache(new InMemoryStorage());
55
57
 
56
58
  const sut = new PaperAdapter(adapter, store, options);
57
59
 
58
- await sut.awake(new AdapterContext(sut, store));
60
+ await sut.awake(new AdapterContext(sut, store, cache));
59
61
  await sut.account();
60
62
 
61
63
  const order = Order.buyMarket(instrumentOf('default:a-b'), 1.0);
@@ -1,6 +1,6 @@
1
- import { Adapter, AdapterContext } from '..';
2
1
  import { assetOf, Candle, InstrumentSelector, Order } from '../../domain';
3
2
  import { BalancePatchEvent, Store } from '../../store';
3
+ import { Adapter, AdapterContext } from '..';
4
4
  import { FeedQuery, HistoryQuery } from '../adapter';
5
5
  import { PaperSimulator } from './simulator/paper-simulator';
6
6
 
@@ -1,4 +1,3 @@
1
- import { PaperAdapter } from '..';
2
1
  import { Order } from '../../../domain';
3
2
  import { pnl, weightedMean } from '../../../shared';
4
3
  import {
@@ -10,6 +9,7 @@ import {
10
9
  OrderPendingEvent,
11
10
  PositionPatchEvent
12
11
  } from '../../../store';
12
+ import { PaperAdapter } from '..';
13
13
  import { PaperSimulator } from './paper-simulator';
14
14
 
15
15
  export class PaperMarginSimulator extends PaperSimulator {
@@ -1,7 +1,8 @@
1
1
  import { tap } from 'rxjs';
2
2
  import { Set } from 'typescript-collections';
3
- import { PaperAdapter } from '..';
3
+
4
4
  import { Component, InstrumentSelector, Order, Orderbook, Trade } from '../../../domain';
5
+ import { PaperAdapter } from '..';
5
6
 
6
7
  export abstract class PaperSimulator {
7
8
  private readonly pending: Record<string, Set<Order>> = {};
@@ -1,4 +1,3 @@
1
- import { PaperAdapter } from '..';
2
1
  import { Order } from '../../../domain';
3
2
  import { timestamp } from '../../../shared';
4
3
  import {
@@ -11,6 +10,7 @@ import {
11
10
  OrderNewEvent,
12
11
  OrderPendingEvent
13
12
  } from '../../../store';
13
+ import { PaperAdapter } from '..';
14
14
  import { PaperSimulator } from './paper-simulator';
15
15
 
16
16
  export class PaperSpotSimulator extends PaperSimulator {
@@ -111,7 +111,7 @@ export class PaperSpotSimulator extends PaperSimulator {
111
111
  switch (order.type) {
112
112
  case 'MARKET':
113
113
  return [
114
- new BalanceUnfreezEvent(order.instrument.quote, quote.freezed, timestamp)
114
+ new BalanceUnfreezEvent(order.instrument.quote, quote.locked, timestamp)
115
115
  ];
116
116
 
117
117
  case 'LIMIT':
package/src/bootstrap.ts CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  PaperAdapter
7
7
  } from './adapter';
8
8
  import { Session, SessionDescriptor } from './domain';
9
+ import { Cache, Feed, InMemoryStorage, InMemoryStorageFactory } from './storage';
9
10
  import { Store } from './store';
10
11
 
11
12
  export class Bootstrap {
@@ -29,12 +30,20 @@ export class Bootstrap {
29
30
  * @param to
30
31
  */
31
32
  useBacktestPeriod(from?: number, to?: number): Bootstrap {
33
+ if (!this.descriptor.simulation) {
34
+ this.descriptor.simulation = {
35
+ balance: {},
36
+ from: undefined,
37
+ to: undefined
38
+ };
39
+ }
40
+
32
41
  if (from) {
33
- this.descriptor.options.backtester.from = from;
42
+ this.descriptor.simulation.from = from;
34
43
  }
35
44
 
36
45
  if (to) {
37
- this.descriptor.options.backtester.to = to;
46
+ this.descriptor.simulation.to = to;
38
47
  }
39
48
 
40
49
  return this;
@@ -47,16 +56,27 @@ export class Bootstrap {
47
56
  */
48
57
  backtest(listener?: BacktesterListener): [Session, BacktesterStreamer] {
49
58
  const store = new Store();
50
- const { feed } = this.descriptor;
51
- const { backtester } = this.descriptor.options;
52
-
53
- const streamer = new BacktesterStreamer(store, feed, backtester, listener);
59
+ const { storage } = this.descriptor;
60
+ const feed = new Feed(storage.create('feed'));
61
+ const cache = new Cache(storage.create('cache'));
62
+
63
+ const streamer = new BacktesterStreamer(
64
+ store,
65
+ feed,
66
+ this.descriptor.simulation,
67
+ listener
68
+ );
54
69
 
55
70
  const aggregate = new AdapterAggregate(
56
71
  this.descriptor.adapter.map(
57
- it => new BacktesterAdapter(new PaperAdapter(it, store, backtester), streamer)
72
+ it =>
73
+ new BacktesterAdapter(
74
+ new PaperAdapter(it, store, this.descriptor.simulation),
75
+ streamer
76
+ )
58
77
  ),
59
- store
78
+ store,
79
+ cache
60
80
  );
61
81
 
62
82
  const session = new Session(store, aggregate, this.descriptor);
@@ -69,22 +89,28 @@ export class Bootstrap {
69
89
  * @returns new session object.
70
90
  */
71
91
  paper(): Session {
72
- if (!this.descriptor.options) {
73
- this.descriptor.options = {};
92
+ if (!this.descriptor.simulation) {
93
+ this.descriptor.simulation = {
94
+ balance: {},
95
+ from: undefined,
96
+ to: undefined
97
+ };
74
98
  }
75
99
 
76
- if (!this.descriptor.options.paper) {
77
- this.descriptor.options.paper = {
78
- balance: {}
79
- };
100
+ if (!this.descriptor.simulation.balance) {
101
+ this.descriptor.simulation.balance = {};
80
102
  }
81
103
 
82
104
  const store = new Store();
83
- const { paper } = this.descriptor.options;
105
+ const storage = this.descriptor.storage ?? new InMemoryStorageFactory();
106
+ const cache = new Cache(storage.create('cache'));
84
107
 
85
108
  const aggregate = new AdapterAggregate(
86
- this.descriptor.adapter.map(it => new PaperAdapter(it, store, paper)),
87
- store
109
+ this.descriptor.adapter.map(
110
+ it => new PaperAdapter(it, store, this.descriptor.simulation)
111
+ ),
112
+ store,
113
+ cache
88
114
  );
89
115
 
90
116
  return new Session(store, aggregate, this.descriptor);
@@ -96,7 +122,10 @@ export class Bootstrap {
96
122
  */
97
123
  live(): Session {
98
124
  const store = new Store();
99
- const aggregate = new AdapterAggregate(this.descriptor.adapter, store);
125
+ const storage = this.descriptor.storage ?? new InMemoryStorageFactory();
126
+ const cache = new Cache(storage.create('cache'));
127
+
128
+ const aggregate = new AdapterAggregate(this.descriptor.adapter, store, cache);
100
129
 
101
130
  return new Session(store, aggregate, this.descriptor);
102
131
  }
@@ -0,0 +1,15 @@
1
+ import { spawn } from 'child_process';
2
+
3
+ import { buildDirectory } from './internal/workspace';
4
+
5
+ export default async function (): Promise<number> {
6
+ return new Promise<number>((resolve, reject) => {
7
+ const process = spawn('swc', ['./src', '--out-dir', buildDirectory()], {
8
+ stdio: 'inherit',
9
+ shell: false
10
+ });
11
+
12
+ process.once('exit', resolve);
13
+ process.once('error', reject);
14
+ });
15
+ }
package/src/cli/dev.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { Bootstrap } from '../bootstrap';
2
+ import build from './build';
3
+ import { getModule } from './internal/workspace';
4
+
5
+ export default async function (name: string, options: any) {
6
+ if (await build()) {
7
+ return;
8
+ }
9
+
10
+ const id = options.id ? Number(options.id) : undefined;
11
+
12
+ const module = await getModule(name);
13
+
14
+ const bootstrap = new Bootstrap(module.descriptor);
15
+ const session = bootstrap.useSessionId(id).paper();
16
+
17
+ await session.awake(module.default);
18
+ }
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { ChildProcess, spawn } from 'child_process';
4
+ import { program } from 'commander';
5
+ import watch from 'node-watch';
6
+
7
+ import build from './build';
8
+ import dev from './dev';
9
+ import pull from './pull';
10
+ import run from './run';
11
+ import test from './test';
12
+
13
+ program
14
+ .command('build')
15
+ .description('builds a production version of the app')
16
+ .action(async () => {
17
+ await build();
18
+ });
19
+
20
+ program
21
+ .command('run')
22
+ .argument('<name>', 'strategy to execute')
23
+ .option('-i, --id <id>', 'session identifier')
24
+ .option('-w', 'watch mode')
25
+ .description('executes strategy in live trading mode')
26
+ .action(run);
27
+
28
+ program
29
+ .command('dev')
30
+ .argument('<name>', 'strategy to execute')
31
+ .option('-i, --id <id>', 'session identifier')
32
+ .option('-w', 'watch mode')
33
+ .description('executes strategy in paper e.g. simulation mode')
34
+ .action(dev);
35
+
36
+ program
37
+ .command('test')
38
+ .description('executes strategy in backtesting mode for specified period')
39
+ .argument('<name>', 'strategy to execute')
40
+ .option('-f, --from <from>', 'date from')
41
+ .option('-t, --to <to>', 'date to')
42
+ .option('-w', 'watch mode')
43
+ .action(test);
44
+
45
+ program
46
+ .command('pull')
47
+ .description('pulls instrument historical data to storage')
48
+ .argument('<name>', 'strategy to execute')
49
+ .argument('<instrument>', 'instrument to import')
50
+ .option('-f, --from <from>', 'date from')
51
+ .option('-t, --to <to>', 'date to')
52
+ .action(pull);
53
+
54
+ program.name('quantform').description('quantform tools');
55
+
56
+ if (process.argv.length < 3) {
57
+ program.help();
58
+ } else {
59
+ if (process.argv.every(it => it != '-w')) {
60
+ program.parse(process.argv);
61
+ } else {
62
+ const argv = process.argv.splice(1).filter(it => it != '-w');
63
+ let child: ChildProcess;
64
+
65
+ const spawnChildProcess = () => {
66
+ console.clear();
67
+
68
+ if (child) {
69
+ child.kill();
70
+ }
71
+
72
+ child = spawn('node', argv, {
73
+ stdio: ['inherit', 'inherit', 'inherit', 'ipc']
74
+ });
75
+ };
76
+
77
+ spawnChildProcess();
78
+
79
+ watch(process.cwd() + '/src', { recursive: true }, () => spawnChildProcess());
80
+ }
81
+ }
@@ -0,0 +1,18 @@
1
+ import { join } from 'path';
2
+ import { Observable } from 'rxjs';
3
+
4
+ import { Session, SessionDescriptor } from './../../domain';
5
+ import { workingDirectory } from './../../shared';
6
+
7
+ export type StrategyModule = {
8
+ descriptor: SessionDescriptor;
9
+ default: (session: Session) => Observable<any>;
10
+ };
11
+
12
+ export function buildDirectory() {
13
+ return join(process.cwd(), workingDirectory(), 'build');
14
+ }
15
+
16
+ export async function getModule(name: string): Promise<StrategyModule> {
17
+ return await import(join(buildDirectory(), name));
18
+ }
@@ -0,0 +1,67 @@
1
+ import { Presets, SingleBar } from 'cli-progress';
2
+
3
+ import { Bootstrap } from '../bootstrap';
4
+ import { instrumentOf } from '../domain';
5
+ import { Feed } from '../storage';
6
+ import build from './build';
7
+ import { getModule } from './internal/workspace';
8
+
9
+ export default async function (name: string, instrument: string, options: any) {
10
+ if (await build()) {
11
+ return;
12
+ }
13
+
14
+ const id = options.id ? Number(options.id) : undefined;
15
+
16
+ const module = await getModule(name);
17
+
18
+ const bootstrap = new Bootstrap(module.descriptor);
19
+ const session = bootstrap.useSessionId(id).paper();
20
+
21
+ if (!module.descriptor.storage) {
22
+ throw new Error('Please provide a "storage" property in session descriptor.');
23
+ }
24
+
25
+ const from = options.from
26
+ ? Date.parse(options.from)
27
+ : module.descriptor.simulation.from;
28
+
29
+ if (!from) {
30
+ throw new Error(
31
+ 'Please set a "from" date in session descriptor or provide the date as parameter.'
32
+ );
33
+ }
34
+
35
+ const to = options.to ? Date.parse(options.to) : module.descriptor.simulation.to;
36
+
37
+ if (!to) {
38
+ throw new Error(
39
+ 'Please set a "to" date in session descriptor or provide the date as parameter.'
40
+ );
41
+ }
42
+
43
+ await session.awake(undefined);
44
+
45
+ const bar = new SingleBar({}, Presets.shades_classic);
46
+ const feed = new Feed(module.descriptor.storage.create('feed'));
47
+
48
+ bar.start(100, 0);
49
+
50
+ await session.aggregate.feed({
51
+ instrument: instrumentOf(instrument),
52
+ from,
53
+ to,
54
+ destination: feed,
55
+ callback: timestamp => {
56
+ const duration = to - from;
57
+ const completed = timestamp - from;
58
+
59
+ bar.update(Math.floor((completed / duration) * 100));
60
+ }
61
+ });
62
+
63
+ bar.update(100);
64
+ bar.stop();
65
+
66
+ await session.dispose();
67
+ }
package/src/cli/run.ts ADDED
@@ -0,0 +1,22 @@
1
+ import * as dotenv from 'dotenv';
2
+
3
+ import { Bootstrap } from '../bootstrap';
4
+ import build from './build';
5
+ import { getModule } from './internal/workspace';
6
+
7
+ export default async function (name, options: any) {
8
+ if (await build()) {
9
+ return;
10
+ }
11
+
12
+ dotenv.config();
13
+
14
+ const id = options.id ? Number(options.id) : undefined;
15
+
16
+ const module = await getModule(name);
17
+
18
+ const bootstrap = new Bootstrap(module.descriptor);
19
+ const session = bootstrap.useSessionId(id).live();
20
+
21
+ await session.awake(module.default);
22
+ }
@@ -0,0 +1,50 @@
1
+ import { BacktesterStreamer } from '../adapter';
2
+ import { Bootstrap } from '../bootstrap';
3
+ import build from './build';
4
+ import { getModule } from './internal/workspace';
5
+
6
+ export default async function (name, options: any) {
7
+ if (await build()) {
8
+ return;
9
+ }
10
+
11
+ const module = await getModule(name);
12
+
13
+ const bootstrap = new Bootstrap(module.descriptor);
14
+
15
+ if (!module.descriptor.storage) {
16
+ throw new Error('Please provide a "storage" property in session descriptor.');
17
+ }
18
+
19
+ const from = options.from
20
+ ? Date.parse(options.from)
21
+ : module.descriptor.simulation.from;
22
+
23
+ if (!from) {
24
+ throw new Error(
25
+ 'Please set a "from" date in session descriptor or provide the date as parameter.'
26
+ );
27
+ }
28
+
29
+ const to = options.to ? Date.parse(options.to) : module.descriptor.simulation.to;
30
+
31
+ if (!to) {
32
+ throw new Error(
33
+ 'Please set a "to" date in session descriptor or provide the date as parameter.'
34
+ );
35
+ }
36
+
37
+ await new Promise<void>(async resolve => {
38
+ const [session] = bootstrap.useBacktestPeriod(from, to).backtest({
39
+ onBacktestCompleted: async () => {
40
+ await session.dispose();
41
+
42
+ console.log('backtest completed.');
43
+
44
+ resolve();
45
+ }
46
+ });
47
+
48
+ await session.awake(module.default);
49
+ });
50
+ }
@@ -7,7 +7,7 @@ describe('balance tests', () => {
7
7
 
8
8
  expect(sut.asset.toString()).toEqual('xyz:abc');
9
9
  expect(sut.free).toEqual(0);
10
- expect(sut.freezed).toEqual(0);
10
+ expect(sut.locked).toEqual(0);
11
11
  expect(Object.keys(sut.position).length).toEqual(0);
12
12
  });
13
13
 
@@ -18,7 +18,7 @@ describe('balance tests', () => {
18
18
 
19
19
  expect(sut.asset.toString()).toEqual('xyz:abc');
20
20
  expect(sut.free).toEqual(100);
21
- expect(sut.freezed).toEqual(50);
21
+ expect(sut.locked).toEqual(50);
22
22
  expect(Object.keys(sut.position).length).toEqual(0);
23
23
  });
24
24
  });
@@ -7,19 +7,20 @@ import { Position, PositionMode } from './position';
7
7
  * Represents single asset balance in your wallet.
8
8
  */
9
9
  export class Balance implements Component {
10
+ kind = 'balance';
10
11
  timestamp: timestamp;
11
12
 
12
13
  readonly maintenanceMarginRate = 1;
13
14
 
14
- private _free = 0;
15
- private _freezed = 0;
15
+ private available = 0;
16
+ private unavailable = 0;
16
17
 
17
18
  /**
18
19
  * Returns available amount to trade.
19
20
  */
20
21
  get free(): number {
21
22
  return (
22
- this._free +
23
+ this.available +
23
24
  this.getEstimatedUnrealizedPnL('CROSS') -
24
25
  this.getEstimatedMaintenanceMargin('CROSS')
25
26
  );
@@ -28,8 +29,8 @@ export class Balance implements Component {
28
29
  /**
29
30
  * Return locked amount for order.
30
31
  */
31
- get freezed(): number {
32
- return this._freezed;
32
+ get locked(): number {
33
+ return this.unavailable;
33
34
  }
34
35
 
35
36
  /**
@@ -38,7 +39,7 @@ export class Balance implements Component {
38
39
  */
39
40
  get total(): number {
40
41
  return (
41
- this._free + this._freezed + this.getEstimatedUnrealizedPnL() /* +
42
+ this.available + this.unavailable + this.getEstimatedUnrealizedPnL() /* +
42
43
  this.getEstimatedMaintenanceMargin()*/
43
44
  );
44
45
  }
@@ -51,20 +52,20 @@ export class Balance implements Component {
51
52
  constructor(public readonly asset: Asset) {}
52
53
 
53
54
  transact(amount: number) {
54
- if (this._free + amount < 0) {
55
- throw new Error(`invalid balance amount has: ${this._free} wants: ${amount}`);
55
+ if (this.available + amount < 0) {
56
+ throw new Error(`invalid balance amount has: ${this.available} wants: ${amount}`);
56
57
  }
57
58
 
58
- this._free += amount;
59
+ this.available += amount;
59
60
  }
60
61
 
61
62
  set(free: number, freezed: number) {
62
63
  if (free != null) {
63
- this._free = free;
64
+ this.available = free;
64
65
  }
65
66
 
66
67
  if (freezed != null) {
67
- this._freezed = freezed;
68
+ this.unavailable = freezed;
68
69
  }
69
70
  }
70
71
 
@@ -73,21 +74,21 @@ export class Balance implements Component {
73
74
  * If you place new pending order, you will lock your balance to fund order.
74
75
  */
75
76
  freez(amount: number) {
76
- if (this._free < amount) {
77
- throw new Error(`insufficient funds has: ${this._free} wants: ${amount}`);
77
+ if (this.available < amount) {
78
+ throw new Error(`insufficient funds has: ${this.available} wants: ${amount}`);
78
79
  }
79
80
 
80
- this._free -= amount;
81
- this._freezed += amount;
81
+ this.available -= amount;
82
+ this.unavailable += amount;
82
83
  }
83
84
 
84
85
  unfreez(amount: number) {
85
- if (this._freezed < amount) {
86
- throw new Error(`insufficient funds has: ${this._freezed} wants: ${amount}`);
86
+ if (this.unavailable < amount) {
87
+ throw new Error(`insufficient funds has: ${this.unavailable} wants: ${amount}`);
87
88
  }
88
89
 
89
- this._free += amount;
90
- this._freezed -= amount;
90
+ this.available += amount;
91
+ this.unavailable -= amount;
91
92
  }
92
93
 
93
94
  /**
@@ -1,4 +1,5 @@
1
1
  import { from, map } from 'rxjs';
2
+
2
3
  import { now } from '../shared';
3
4
  import { TradePatchEvent } from '../store';
4
5
  import { Candle, mergeCandle } from './candle';