@quantform/core 0.3.264 → 0.3.272

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 (250) hide show
  1. package/dist/adapter/adapter-aggregate.d.ts +2 -2
  2. package/dist/adapter/adapter-aggregate.js.map +1 -1
  3. package/dist/adapter/adapter.d.ts +5 -6
  4. package/dist/adapter/adapter.js.map +1 -1
  5. package/dist/adapter/backtester/backtester-adapter.d.ts +6 -6
  6. package/dist/adapter/backtester/backtester-adapter.js +5 -9
  7. package/dist/adapter/backtester/backtester-adapter.js.map +1 -1
  8. package/dist/adapter/backtester/backtester-cursor.d.ts +2 -2
  9. package/dist/adapter/backtester/backtester-cursor.spec.js +9 -9
  10. package/dist/adapter/backtester/backtester-cursor.spec.js.map +1 -1
  11. package/dist/adapter/backtester/backtester-streamer.d.ts +6 -4
  12. package/dist/adapter/backtester/backtester-streamer.js +5 -5
  13. package/dist/adapter/backtester/backtester-streamer.js.map +1 -1
  14. package/dist/adapter/backtester/backtester-streamer.spec.js +9 -11
  15. package/dist/adapter/backtester/backtester-streamer.spec.js.map +1 -1
  16. package/dist/adapter/index.d.ts +2 -0
  17. package/dist/adapter/index.js +2 -0
  18. package/dist/adapter/index.js.map +1 -1
  19. package/dist/adapter/paper/index.d.ts +2 -2
  20. package/dist/adapter/paper/index.js +2 -2
  21. package/dist/adapter/paper/index.js.map +1 -1
  22. package/dist/adapter/paper/paper-adapter.d.ts +5 -5
  23. package/dist/adapter/paper/paper-adapter.js +9 -12
  24. package/dist/adapter/paper/paper-adapter.js.map +1 -1
  25. package/dist/adapter/paper/paper-adapter.spec.js +5 -7
  26. package/dist/adapter/paper/paper-adapter.spec.js.map +1 -1
  27. package/dist/adapter/paper/{executor/paper-margin-executor.d.ts → simulator/paper-margin-simulator.d.ts} +3 -3
  28. package/dist/adapter/paper/{executor/paper-margin-executor.js → simulator/paper-margin-simulator.js} +11 -11
  29. package/dist/adapter/paper/simulator/paper-margin-simulator.js.map +1 -0
  30. package/dist/adapter/paper/{executor/paper-executor.d.ts → simulator/paper-simulator.d.ts} +2 -2
  31. package/dist/adapter/paper/{executor/paper-executor.js → simulator/paper-simulator.js} +7 -7
  32. package/dist/adapter/paper/simulator/paper-simulator.js.map +1 -0
  33. package/dist/adapter/paper/{executor/paper-spot-executor.d.ts → simulator/paper-spot-simulator.d.ts} +3 -3
  34. package/dist/adapter/paper/{executor/paper-spot-executor.js → simulator/paper-spot-simulator.js} +17 -17
  35. package/dist/adapter/paper/simulator/paper-spot-simulator.js.map +1 -0
  36. package/dist/adapter/paper/simulator/paper-spot-simulator.spec.d.ts +1 -0
  37. package/dist/adapter/paper/simulator/paper-spot-simulator.spec.js +49 -0
  38. package/dist/adapter/paper/simulator/paper-spot-simulator.spec.js.map +1 -0
  39. package/dist/bootstrap.d.ts +1 -1
  40. package/dist/bootstrap.js +3 -5
  41. package/dist/bootstrap.js.map +1 -1
  42. package/dist/domain/balance.d.ts +1 -1
  43. package/dist/domain/candle.d.ts +14 -0
  44. package/dist/domain/candle.js +65 -1
  45. package/dist/domain/candle.js.map +1 -1
  46. package/dist/domain/candle.spec.js +11 -13
  47. package/dist/domain/candle.spec.js.map +1 -1
  48. package/dist/domain/index.d.ts +6 -8
  49. package/dist/domain/index.js +6 -8
  50. package/dist/domain/index.js.map +1 -1
  51. package/dist/domain/order.d.ts +1 -1
  52. package/dist/domain/order.js.map +1 -1
  53. package/dist/domain/orderbook.d.ts +1 -1
  54. package/dist/domain/position.d.ts +2 -2
  55. package/dist/domain/position.js +3 -3
  56. package/dist/domain/position.js.map +1 -1
  57. package/dist/domain/session.d.ts +14 -3
  58. package/dist/domain/session.js +17 -18
  59. package/dist/domain/session.js.map +1 -1
  60. package/dist/domain/session.spec.js +3 -3
  61. package/dist/domain/session.spec.js.map +1 -1
  62. package/dist/domain/statement.d.ts +1 -2
  63. package/dist/domain/statement.js.map +1 -1
  64. package/dist/domain/trade.d.ts +1 -1
  65. package/dist/index.d.ts +4 -7
  66. package/dist/index.js +4 -7
  67. package/dist/index.js.map +1 -1
  68. package/dist/indicator/atr.js +3 -3
  69. package/dist/indicator/atr.js.map +1 -1
  70. package/dist/indicator/cross.js +3 -3
  71. package/dist/indicator/cross.js.map +1 -1
  72. package/dist/indicator/donchian.js +3 -4
  73. package/dist/indicator/donchian.js.map +1 -1
  74. package/dist/indicator/drawdown.js +3 -3
  75. package/dist/indicator/drawdown.js.map +1 -1
  76. package/dist/indicator/ema.js +3 -3
  77. package/dist/indicator/ema.js.map +1 -1
  78. package/dist/indicator/envelope.js +3 -3
  79. package/dist/indicator/envelope.js.map +1 -1
  80. package/dist/indicator/index.d.ts +3 -3
  81. package/dist/indicator/index.js +3 -3
  82. package/dist/indicator/index.js.map +1 -1
  83. package/dist/indicator/macd.js +2 -3
  84. package/dist/indicator/macd.js.map +1 -1
  85. package/dist/indicator/min-max.js +3 -3
  86. package/dist/indicator/min-max.js.map +1 -1
  87. package/dist/indicator/rma.js +3 -3
  88. package/dist/indicator/rma.js.map +1 -1
  89. package/dist/indicator/sma.js +2 -3
  90. package/dist/indicator/sma.js.map +1 -1
  91. package/dist/indicator/swma.js +3 -3
  92. package/dist/indicator/swma.js.map +1 -1
  93. package/dist/indicator/tma.js +3 -3
  94. package/dist/indicator/tma.js.map +1 -1
  95. package/dist/indicator/trailing.js +3 -3
  96. package/dist/indicator/trailing.js.map +1 -1
  97. package/dist/indicator/truerange.js +3 -3
  98. package/dist/indicator/truerange.js.map +1 -1
  99. package/dist/indicator/truerange.spec.js +2 -2
  100. package/dist/indicator/truerange.spec.js.map +1 -1
  101. package/dist/indicator/wma.js +3 -3
  102. package/dist/indicator/wma.js.map +1 -1
  103. package/dist/ipc.d.ts +1 -1
  104. package/dist/ipc.js +3 -3
  105. package/dist/ipc.js.map +1 -1
  106. package/dist/ipc.spec.js +4 -5
  107. package/dist/ipc.spec.js.map +1 -1
  108. package/dist/shared/index.d.ts +4 -4
  109. package/dist/shared/index.js +4 -4
  110. package/dist/shared/index.js.map +1 -1
  111. package/dist/shared/policy.js +1 -1
  112. package/dist/shared/policy.js.map +1 -1
  113. package/dist/storage/feed.d.ts +1 -1
  114. package/dist/storage/feed.js.map +1 -1
  115. package/dist/storage/index.d.ts +1 -1
  116. package/dist/storage/index.js +1 -1
  117. package/dist/storage/index.js.map +1 -1
  118. package/dist/storage/measurement.js.map +1 -1
  119. package/dist/storage/storage.js.map +1 -1
  120. package/dist/store/event/index.d.ts +4 -4
  121. package/dist/store/event/index.js +4 -4
  122. package/dist/store/event/index.js.map +1 -1
  123. package/dist/store/event/store-balance.event.d.ts +1 -1
  124. package/dist/store/event/store-balance.event.js +1 -1
  125. package/dist/store/event/store-balance.event.js.map +1 -1
  126. package/dist/store/event/store-balance.event.spec.js +3 -3
  127. package/dist/store/event/store-balance.event.spec.js.map +1 -1
  128. package/dist/store/event/store-candle.event.d.ts +2 -2
  129. package/dist/store/event/store-candle.event.js +2 -2
  130. package/dist/store/event/store-candle.event.js.map +1 -1
  131. package/dist/store/event/store-candle.event.spec.js +1 -1
  132. package/dist/store/event/store-candle.event.spec.js.map +1 -1
  133. package/dist/store/event/store-instrument.event.d.ts +1 -1
  134. package/dist/store/event/store-instrument.event.js +1 -1
  135. package/dist/store/event/store-instrument.event.js.map +1 -1
  136. package/dist/store/event/store-instrument.event.spec.js +1 -1
  137. package/dist/store/event/store-instrument.event.spec.js.map +1 -1
  138. package/dist/store/event/store-order.event.d.ts +1 -1
  139. package/dist/store/event/store-order.event.js +6 -6
  140. package/dist/store/event/store-order.event.js.map +1 -1
  141. package/dist/store/event/store-order.event.spec.js +2 -2
  142. package/dist/store/event/store-order.event.spec.js.map +1 -1
  143. package/dist/store/event/store-orderbook.event.d.ts +1 -1
  144. package/dist/store/event/store-orderbook.event.js +1 -1
  145. package/dist/store/event/store-orderbook.event.js.map +1 -1
  146. package/dist/store/event/store-position.event.d.ts +1 -1
  147. package/dist/store/event/store-position.event.js +1 -1
  148. package/dist/store/event/store-position.event.js.map +1 -1
  149. package/dist/store/event/store-trade.event.d.ts +1 -1
  150. package/dist/store/event/store-trade.event.js +1 -1
  151. package/dist/store/event/store-trade.event.js.map +1 -1
  152. package/dist/store/event/store-trade.event.spec.js +2 -2
  153. package/dist/store/event/store-trade.event.spec.js.map +1 -1
  154. package/dist/store/index.d.ts +1 -0
  155. package/dist/store/index.js +1 -0
  156. package/dist/store/index.js.map +1 -1
  157. package/dist/store/store.d.ts +2 -5
  158. package/dist/store/store.js +4 -8
  159. package/dist/store/store.js.map +1 -1
  160. package/dist/store/store.state.d.ts +1 -1
  161. package/dist/tests/backtester-adapter.spec.js +8 -15
  162. package/dist/tests/backtester-adapter.spec.js.map +1 -1
  163. package/dist/tests/session.spec.d.ts +0 -1
  164. package/dist/tests/session.spec.js +0 -2
  165. package/dist/tsconfig.tsbuildinfo +1 -1
  166. package/package.json +1 -1
  167. package/src/adapter/adapter-aggregate.ts +2 -3
  168. package/src/adapter/adapter.ts +5 -6
  169. package/src/adapter/backtester/backtester-adapter.ts +8 -8
  170. package/src/adapter/backtester/backtester-cursor.spec.ts +1 -1
  171. package/src/adapter/backtester/backtester-cursor.ts +2 -2
  172. package/src/adapter/backtester/backtester-streamer.spec.ts +1 -3
  173. package/src/adapter/backtester/backtester-streamer.ts +7 -8
  174. package/src/adapter/index.ts +2 -0
  175. package/src/adapter/paper/index.ts +2 -2
  176. package/src/adapter/paper/paper-adapter.spec.ts +6 -8
  177. package/src/adapter/paper/paper-adapter.ts +9 -11
  178. package/src/adapter/paper/{executor/paper-margin-executor.ts → simulator/paper-margin-simulator.ts} +5 -5
  179. package/src/adapter/paper/{executor/paper-executor.ts → simulator/paper-simulator.ts} +4 -4
  180. package/src/adapter/paper/simulator/paper-spot-simulator.spec.ts +87 -0
  181. package/src/adapter/paper/{executor/paper-spot-executor.ts → simulator/paper-spot-simulator.ts} +6 -6
  182. package/src/bootstrap.ts +4 -4
  183. package/src/domain/balance.ts +1 -1
  184. package/src/domain/candle.spec.ts +3 -5
  185. package/src/domain/candle.ts +103 -0
  186. package/src/domain/index.ts +6 -8
  187. package/src/domain/order.ts +2 -2
  188. package/src/domain/orderbook.ts +1 -1
  189. package/src/domain/position.ts +2 -3
  190. package/src/domain/session.spec.ts +3 -3
  191. package/src/domain/session.ts +61 -8
  192. package/src/domain/statement.ts +1 -2
  193. package/src/domain/trade.ts +1 -1
  194. package/src/index.ts +4 -7
  195. package/src/indicator/atr.ts +1 -2
  196. package/src/indicator/cross.ts +3 -4
  197. package/src/indicator/donchian.ts +2 -3
  198. package/src/indicator/drawdown.ts +2 -3
  199. package/src/indicator/ema.ts +1 -2
  200. package/src/indicator/envelope.ts +1 -2
  201. package/src/indicator/index.ts +3 -3
  202. package/src/indicator/macd.ts +1 -2
  203. package/src/indicator/min-max.ts +1 -2
  204. package/src/indicator/rma.ts +1 -2
  205. package/src/indicator/sma.ts +1 -2
  206. package/src/indicator/swma.ts +1 -2
  207. package/src/indicator/tma.ts +1 -2
  208. package/src/indicator/trailing.ts +3 -4
  209. package/src/indicator/truerange.spec.ts +2 -2
  210. package/src/indicator/truerange.ts +1 -2
  211. package/src/indicator/window.ts +1 -1
  212. package/src/indicator/wma.ts +1 -2
  213. package/src/ipc.spec.ts +6 -7
  214. package/src/ipc.ts +6 -6
  215. package/src/shared/index.ts +4 -4
  216. package/src/shared/policy.ts +1 -1
  217. package/src/shared/topic.spec.ts +1 -1
  218. package/src/storage/feed.ts +20 -1
  219. package/src/storage/index.ts +1 -1
  220. package/src/storage/measurement.ts +19 -0
  221. package/src/storage/storage.ts +37 -0
  222. package/src/store/event/index.ts +4 -4
  223. package/src/store/event/store-balance.event.spec.ts +3 -3
  224. package/src/store/event/store-balance.event.ts +2 -2
  225. package/src/store/event/store-candle.event.spec.ts +1 -1
  226. package/src/store/event/store-candle.event.ts +5 -5
  227. package/src/store/event/store-instrument.event.spec.ts +1 -1
  228. package/src/store/event/store-instrument.event.ts +2 -2
  229. package/src/store/event/store-order.event.spec.ts +2 -2
  230. package/src/store/event/store-order.event.ts +7 -7
  231. package/src/store/event/store-orderbook.event.ts +2 -2
  232. package/src/store/event/store-position.event.ts +2 -2
  233. package/src/store/event/store-trade.event.spec.ts +2 -2
  234. package/src/store/event/store-trade.event.ts +2 -2
  235. package/src/store/index.ts +1 -0
  236. package/src/store/store.state.ts +7 -7
  237. package/src/store/store.ts +6 -9
  238. package/src/tests/backtester-adapter.spec.ts +8 -15
  239. package/src/tests/session.spec.ts +0 -3
  240. package/dist/adapter/paper/executor/paper-executor.js.map +0 -1
  241. package/dist/adapter/paper/executor/paper-margin-executor.js.map +0 -1
  242. package/dist/adapter/paper/executor/paper-spot-executor.js.map +0 -1
  243. package/dist/domain/candle-builder.d.ts +0 -16
  244. package/dist/domain/candle-builder.js +0 -70
  245. package/dist/domain/candle-builder.js.map +0 -1
  246. package/dist/domain/session-descriptor.d.ts +0 -15
  247. package/dist/domain/session-descriptor.js +0 -3
  248. package/dist/domain/session-descriptor.js.map +0 -1
  249. package/src/domain/candle-builder.ts +0 -104
  250. package/src/domain/session-descriptor.ts +0 -53
@@ -1,2 +1,4 @@
1
1
  export * from './adapter';
2
2
  export * from './adapter-aggregate';
3
+ export * from './backtester';
4
+ export * from './paper';
@@ -1,3 +1,3 @@
1
1
  export * from './paper-adapter';
2
- export * from './executor/paper-spot-executor';
3
- export * from './executor/paper-margin-executor';
2
+ export * from './simulator/paper-margin-simulator';
3
+ export * from './simulator/paper-spot-simulator';
@@ -1,12 +1,10 @@
1
- import { PaperSpotExecutor } from '.';
1
+ import { PaperSpotSimulator } from '.';
2
2
  import { AdapterContext } from '..';
3
- import { Store } from '../../store';
3
+ import { InstrumentPatchEvent, Store } from '../../store';
4
4
  import { Adapter } from '../adapter';
5
- import { PaperExecutor } from './executor/paper-executor';
5
+ import { Asset, Commission, instrumentOf, Order } from './../../domain';
6
6
  import { PaperAdapter } from './paper-adapter';
7
- import { Order, Asset, Commission, assetOf } from './../../domain';
8
- import { instrumentOf } from './../../domain/instrument';
9
- import { BalancePatchEvent, InstrumentPatchEvent } from '../../store/event';
7
+ import { PaperSimulator } from './simulator/paper-simulator';
10
8
 
11
9
  class DefaultAdapter extends Adapter {
12
10
  name = 'default';
@@ -29,8 +27,8 @@ class DefaultAdapter extends Adapter {
29
27
  );
30
28
  }
31
29
 
32
- createPaperExecutor(adapter: PaperAdapter): PaperExecutor {
33
- return new PaperSpotExecutor(adapter);
30
+ createPaperSimulator(adapter: PaperAdapter): PaperSimulator {
31
+ return new PaperSpotSimulator(adapter);
34
32
  }
35
33
  }
36
34
 
@@ -1,18 +1,16 @@
1
1
  import { Adapter, AdapterContext } from '..';
2
- import { Store } from '../../store';
3
- import { PaperExecutor } from './executor/paper-executor';
4
2
  import { assetOf, Candle, InstrumentSelector, Order } from '../../domain';
5
- import { BalancePatchEvent } from '../../store/event';
6
- import { Feed } from 'src/storage';
3
+ import { BalancePatchEvent, Store } from '../../store';
7
4
  import { FeedQuery, HistoryQuery } from '../adapter';
5
+ import { PaperSimulator } from './simulator/paper-simulator';
8
6
 
9
- export class PaperOptions {
7
+ export interface PaperOptions {
10
8
  balance: { [key: string]: number };
11
9
  }
12
10
 
13
11
  export class PaperAdapter extends Adapter {
14
12
  readonly name = this.decoratedAdapter.name;
15
- readonly executor: PaperExecutor;
13
+ readonly simulator: PaperSimulator;
16
14
 
17
15
  constructor(
18
16
  readonly decoratedAdapter: Adapter,
@@ -21,7 +19,7 @@ export class PaperAdapter extends Adapter {
21
19
  ) {
22
20
  super();
23
21
 
24
- this.executor = this.createPaperExecutor(this);
22
+ this.simulator = this.createPaperSimulator(this);
25
23
  }
26
24
 
27
25
  timestamp() {
@@ -68,11 +66,11 @@ export class PaperAdapter extends Adapter {
68
66
  }
69
67
 
70
68
  async open(order: Order): Promise<void> {
71
- this.executor.open(order);
69
+ this.simulator.open(order);
72
70
  }
73
71
 
74
72
  async cancel(order: Order): Promise<void> {
75
- this.executor.cancel(order);
73
+ this.simulator.cancel(order);
76
74
  }
77
75
 
78
76
  history(query: HistoryQuery): Promise<Candle[]> {
@@ -83,7 +81,7 @@ export class PaperAdapter extends Adapter {
83
81
  return this.decoratedAdapter.feed(query);
84
82
  }
85
83
 
86
- createPaperExecutor(adapter: PaperAdapter): PaperExecutor {
87
- return this.decoratedAdapter.createPaperExecutor(adapter);
84
+ createPaperSimulator(adapter: PaperAdapter): PaperSimulator {
85
+ return this.decoratedAdapter.createPaperSimulator(adapter);
88
86
  }
89
87
  }
@@ -1,5 +1,6 @@
1
- import { pnl, weightedMean } from '../../../shared';
1
+ import { PaperAdapter } from '..';
2
2
  import { Order } from '../../../domain';
3
+ import { pnl, weightedMean } from '../../../shared';
3
4
  import {
4
5
  BalanceTransactEvent,
5
6
  OrderCanceledEvent,
@@ -8,11 +9,10 @@ import {
8
9
  OrderNewEvent,
9
10
  OrderPendingEvent,
10
11
  PositionPatchEvent
11
- } from '../../../store/event';
12
- import { PaperAdapter } from '..';
13
- import { PaperExecutor } from './paper-executor';
12
+ } from '../../../store';
13
+ import { PaperSimulator } from './paper-simulator';
14
14
 
15
- export class PaperMarginExecutor extends PaperExecutor {
15
+ export class PaperMarginSimulator extends PaperSimulator {
16
16
  leverage = 10;
17
17
 
18
18
  constructor(adapter: PaperAdapter) {
@@ -1,9 +1,9 @@
1
- import { tap } from 'rxjs/operators';
2
- import { Component, InstrumentSelector, Order, Orderbook, Trade } from '../../../domain';
3
- import { PaperAdapter } from '..';
1
+ import { tap } from 'rxjs';
4
2
  import { Set } from 'typescript-collections';
3
+ import { PaperAdapter } from '..';
4
+ import { Component, InstrumentSelector, Order, Orderbook, Trade } from '../../../domain';
5
5
 
6
- export abstract class PaperExecutor {
6
+ export abstract class PaperSimulator {
7
7
  private readonly pending: Record<string, Set<Order>> = {};
8
8
 
9
9
  constructor(readonly adapter: PaperAdapter) {
@@ -0,0 +1,87 @@
1
+ import { PaperAdapter } from '../paper-adapter';
2
+ import {
3
+ Asset,
4
+ assetOf,
5
+ Commission,
6
+ commissionPercentOf,
7
+ instrumentOf,
8
+ Order
9
+ } from './../../../domain';
10
+ import {
11
+ BalancePatchEvent,
12
+ InstrumentPatchEvent,
13
+ InstrumentSubscriptionEvent,
14
+ Store,
15
+ TradePatchEvent
16
+ } from './../../../store';
17
+ import { Adapter, AdapterContext } from './../../adapter';
18
+ import { PaperSimulator } from './paper-simulator';
19
+ import { PaperSpotSimulator } from './paper-spot-simulator';
20
+
21
+ class DefaultAdapter extends Adapter {
22
+ name = 'default';
23
+
24
+ timestamp() {
25
+ return 123;
26
+ }
27
+
28
+ async awake(context: AdapterContext): Promise<void> {
29
+ await super.awake(context);
30
+
31
+ context.dispatch(
32
+ new InstrumentPatchEvent(
33
+ context.timestamp,
34
+ new Asset('a', this.name, 8),
35
+ new Asset('b', this.name, 4),
36
+ new Commission(0.1, 0.1),
37
+ 'a-b'
38
+ )
39
+ );
40
+ }
41
+
42
+ createPaperSimulator(adapter: PaperAdapter): PaperSimulator {
43
+ return new PaperSpotSimulator(adapter);
44
+ }
45
+ }
46
+
47
+ describe('paper spot simulator tests', () => {
48
+ const options = {
49
+ balance: {
50
+ ['default:a']: 1000,
51
+ ['default:b']: 200
52
+ }
53
+ };
54
+
55
+ test('should open an market order', async () => {
56
+ const store = new Store();
57
+ const adapter = new DefaultAdapter();
58
+ const order = Order.buyMarket(instrumentOf('default:a-b'), 1);
59
+
60
+ store.dispatch(
61
+ new InstrumentPatchEvent(
62
+ 0,
63
+ new Asset('a', 'default', 8),
64
+ new Asset('b', 'default', 4),
65
+ commissionPercentOf(0.1, 0.1),
66
+ 'a-b'
67
+ ),
68
+ new BalancePatchEvent(assetOf('default:a'), 1000, 0, 1)
69
+ );
70
+ store.dispatch(new BalancePatchEvent(assetOf('default:b'), 1000, 0, 1));
71
+ store.dispatch(new InstrumentSubscriptionEvent(1, instrumentOf('default:a-b'), true));
72
+
73
+ const sut = new PaperSpotSimulator(new PaperAdapter(adapter, store, options));
74
+
75
+ await sut.open(order);
76
+
77
+ expect(store.snapshot.order[order.id].state).toBe('PENDING');
78
+
79
+ store.dispatch(new TradePatchEvent(instrumentOf('default:a-b'), 5, 1, 2));
80
+
81
+ expect(store.snapshot.order[order.id].quantity).toBe(1);
82
+ expect(store.snapshot.order[order.id].averageExecutionRate).toBe(5);
83
+ expect(store.snapshot.order[order.id].state).toBe('FILLED');
84
+ expect(store.snapshot.balance['default:b'].free).toBe(995);
85
+ expect(store.snapshot.balance['default:a'].free).toBe(1000.999);
86
+ });
87
+ });
@@ -1,4 +1,6 @@
1
- import { Order, Orderbook } from '../../../domain';
1
+ import { PaperAdapter } from '..';
2
+ import { Order } from '../../../domain';
3
+ import { timestamp } from '../../../shared';
2
4
  import {
3
5
  BalanceFreezEvent,
4
6
  BalanceTransactEvent,
@@ -8,12 +10,10 @@ import {
8
10
  OrderFilledEvent,
9
11
  OrderNewEvent,
10
12
  OrderPendingEvent
11
- } from '../../../store/event';
12
- import { PaperAdapter } from '..';
13
- import { PaperExecutor } from './paper-executor';
14
- import { timestamp } from '../../../shared';
13
+ } from '../../../store';
14
+ import { PaperSimulator } from './paper-simulator';
15
15
 
16
- export class PaperSpotExecutor extends PaperExecutor {
16
+ export class PaperSpotSimulator extends PaperSimulator {
17
17
  constructor(readonly adapter: PaperAdapter) {
18
18
  super(adapter);
19
19
  }
package/src/bootstrap.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
+ AdapterAggregate,
2
3
  BacktesterAdapter,
3
4
  BacktesterListener,
4
- BacktesterStreamer
5
- } from './adapter/backtester';
6
- import { AdapterAggregate } from './adapter';
7
- import { PaperAdapter } from './adapter/paper';
5
+ BacktesterStreamer,
6
+ PaperAdapter
7
+ } from './adapter';
8
8
  import { Session, SessionDescriptor } from './domain';
9
9
  import { Store } from './store';
10
10
 
@@ -1,7 +1,7 @@
1
1
  import { timestamp } from '../shared';
2
2
  import { Asset } from './';
3
- import { Position, PositionMode } from './position';
4
3
  import { Component } from './component';
4
+ import { Position, PositionMode } from './position';
5
5
 
6
6
  /**
7
7
  * Represents single asset balance in your wallet.
@@ -1,9 +1,7 @@
1
- import { from } from 'rxjs';
2
- import { map } from 'rxjs/operators';
3
- import { TradePatchEvent } from '../store/event';
1
+ import { from, map } from 'rxjs';
4
2
  import { now } from '../shared';
5
- import { Candle } from './candle';
6
- import { mergeCandle } from './candle-builder';
3
+ import { TradePatchEvent } from '../store';
4
+ import { Candle, mergeCandle } from './candle';
7
5
  import { instrumentOf } from './instrument';
8
6
  import { Timeframe } from './timeframe';
9
7
 
@@ -1,4 +1,16 @@
1
+ import {
2
+ concat,
3
+ filter,
4
+ last,
5
+ map,
6
+ mergeMap,
7
+ Observable,
8
+ share,
9
+ skipLast,
10
+ withLatestFrom
11
+ } from 'rxjs';
1
12
  import { timestamp } from '../shared';
13
+ import { tf } from './timeframe';
2
14
 
3
15
  export class Candle {
4
16
  constructor(
@@ -15,3 +27,94 @@ export class Candle {
15
27
  this.close = value;
16
28
  }
17
29
  }
30
+
31
+ export class CandleBuilder {
32
+ private _candle: Candle;
33
+
34
+ get candle(): Candle {
35
+ return this._candle;
36
+ }
37
+
38
+ constructor(readonly timeframe: number) {}
39
+
40
+ append(value: number, timestamp: timestamp): Candle {
41
+ const frame = tf(timestamp, this.timeframe);
42
+
43
+ if (!this._candle) {
44
+ this._candle = new Candle(frame, value, value, value, value);
45
+
46
+ return null;
47
+ }
48
+
49
+ if (this.candle.timestamp == frame) {
50
+ this.candle.apply(value);
51
+
52
+ return null;
53
+ }
54
+
55
+ const previous = this._candle;
56
+
57
+ this._candle = new Candle(frame, value, value, value, value);
58
+ return previous;
59
+ }
60
+ }
61
+
62
+ export function candle<T extends { timestamp: number }>(
63
+ timeframe: number,
64
+ fn: (x: T) => number
65
+ ) {
66
+ return function (source: Observable<T>): Observable<Candle> {
67
+ const builder = new CandleBuilder(timeframe);
68
+ let candle: Candle;
69
+
70
+ return source.pipe(
71
+ filter(it => {
72
+ return (candle = builder.append(fn(it), it.timestamp)) != null;
73
+ }),
74
+ map(_ => candle),
75
+ share()
76
+ );
77
+ };
78
+ }
79
+
80
+ export function mergeCandle<T extends { timestamp: number }>(
81
+ timeframe: number,
82
+ fn: (x: T) => number,
83
+ history$: Observable<Candle>
84
+ ) {
85
+ return function (source$: Observable<T>): Observable<Candle> {
86
+ const builder = new CandleBuilder(timeframe);
87
+ let hasMergedHistory = false;
88
+
89
+ return concat(
90
+ history$.pipe(skipLast(1)),
91
+ source$.pipe(
92
+ withLatestFrom(history$.pipe(last())),
93
+ mergeMap(([it, history]) => {
94
+ const completed = builder.append(fn(it), it.timestamp);
95
+
96
+ if (completed) {
97
+ if (completed.timestamp == history.timestamp) {
98
+ completed.open = history.open;
99
+ completed.high = Math.max(completed.high, history.high);
100
+ completed.low = Math.min(completed.low, history.low);
101
+
102
+ hasMergedHistory = true;
103
+ } else if (completed.timestamp > history.timestamp) {
104
+ if (!hasMergedHistory) {
105
+ hasMergedHistory = true;
106
+ return [history, completed];
107
+ }
108
+ } else if (completed.timestamp < history.timestamp) {
109
+ throw new Error('invalid candle sequence, input data is to old.');
110
+ }
111
+
112
+ return [completed];
113
+ }
114
+
115
+ return [];
116
+ })
117
+ )
118
+ );
119
+ };
120
+ }
@@ -1,15 +1,13 @@
1
1
  export * from './asset';
2
- export * from './instrument';
3
2
  export * from './balance';
4
- export * from './order';
5
- export * from './orderbook';
3
+ export * from './candle';
6
4
  export * from './commission';
7
5
  export * from './component';
8
- export * from './candle';
9
- export * from './candle-builder';
10
- export * from './timeframe';
6
+ export * from './instrument';
7
+ export * from './order';
8
+ export * from './orderbook';
11
9
  export * from './position';
12
- export * from './trade';
13
10
  export * from './session';
14
- export * from './session-descriptor';
15
11
  export * from './statement';
12
+ export * from './timeframe';
13
+ export * from './trade';
@@ -1,7 +1,7 @@
1
- import { Component } from './component';
2
1
  import { v4 } from 'uuid';
3
- import { InstrumentSelector } from './instrument';
4
2
  import { timestamp } from '../shared';
3
+ import { Component } from './component';
4
+ import { InstrumentSelector } from './instrument';
5
5
 
6
6
  export type OrderSide = 'SELL' | 'BUY';
7
7
  export type OrderType = 'MARKET' | 'LIMIT' | 'STOP-MARKET' | 'STOP-LIMIT';
@@ -1,5 +1,5 @@
1
- import { timestamp } from '../shared';
2
1
  import { Instrument } from '../domain';
2
+ import { timestamp } from '../shared';
3
3
  import { Component } from './component';
4
4
 
5
5
  /**
@@ -1,8 +1,7 @@
1
+ import { map, Observable, share } from 'rxjs';
1
2
  import { Instrument } from '../domain';
2
- import { Component } from './component';
3
3
  import { pnl, timestamp, weightedMean } from '../shared';
4
- import { Observable } from 'rxjs';
5
- import { map, share } from 'rxjs/operators';
4
+ import { Component } from './component';
6
5
 
7
6
  export type PositionMode = 'CROSS' | 'ISOLATED';
8
7
 
@@ -1,8 +1,8 @@
1
- import { InstrumentPatchEvent } from '../store/event';
1
+ import { Bootstrap } from '../bootstrap';
2
2
  import { Asset, Commission } from '../domain';
3
3
  import { now } from '../shared';
4
- import { SessionDescriptor } from './session-descriptor';
5
- import { Bootstrap } from '../bootstrap';
4
+ import { InstrumentPatchEvent } from '../store';
5
+ import { SessionDescriptor } from './session';
6
6
 
7
7
  describe('session tests', () => {
8
8
  const descriptor: SessionDescriptor = {
@@ -1,14 +1,21 @@
1
1
  import {
2
+ concat,
2
3
  distinctUntilChanged,
3
4
  filter,
5
+ from,
4
6
  map,
5
7
  mergeMap,
8
+ Observable,
6
9
  share,
7
10
  shareReplay,
8
11
  startWith,
12
+ Subject,
13
+ Subscription,
9
14
  switchMap,
10
15
  take
11
- } from 'rxjs/operators';
16
+ } from 'rxjs';
17
+ import { Adapter, BacktesterOptions, PaperOptions } from '../adapter';
18
+ import { AdapterAggregate } from '../adapter/adapter-aggregate';
12
19
  import {
13
20
  AssetSelector,
14
21
  Balance,
@@ -16,19 +23,65 @@ import {
16
23
  Instrument,
17
24
  InstrumentSelector,
18
25
  Order,
19
- Position,
20
26
  Orderbook,
21
- OrderState
27
+ OrderState,
28
+ Position
22
29
  } from '../domain';
23
- import { Store } from '../store';
24
- import { concat, from, Observable, Subject, Subscription } from 'rxjs';
25
- import { AdapterAggregate } from '../adapter/adapter-aggregate';
26
- import { Worker, now } from '../shared';
27
30
  import { Trade } from '../domain/trade';
28
- import { SessionDescriptor } from './session-descriptor';
31
+ import { now, Worker } from '../shared';
32
+ import { Feed, Measurement } from '../storage';
33
+ import { Store } from '../store';
29
34
 
30
35
  type Optional<T, K extends keyof T> = Omit<T, K> & Partial<T>;
31
36
 
37
+ /**
38
+ * Describes a single session.
39
+ * You can use @run function to start a new session managed by CLI.
40
+ * To start managed session you should install @quantform/cli package and run
41
+ * specific command:
42
+ * - qf paper (to paper trade strategy)
43
+ * - qf backtest (to backtest strategy based on provided feed)
44
+ * - qf live (to live trade strategy)
45
+ * or run on your own in code:
46
+ * - paper(descriptor, options)
47
+ * - backtest(descriptor, options)
48
+ * - live(descriptor)
49
+ */
50
+ export interface SessionDescriptor {
51
+ /**
52
+ * Unique session identifier, used to identify session in the storage.
53
+ * You can generate new id every time you start the new session or provide
54
+ * session id explicitly to resume previous session (in code or via CLI).
55
+ * If you don't provide session id, it will generate new one based on time.
56
+ */
57
+ id?: number;
58
+
59
+ /**
60
+ * Collection of adapters used to connect to the exchanges.
61
+ */
62
+ adapter: Adapter[];
63
+
64
+ /**
65
+ * Provides historical data for backtest, it's not required for live and paper
66
+ * sessions.
67
+ */
68
+ feed?: Feed;
69
+
70
+ /**
71
+ * Stores session variables i.e. indicators, orders, or any other type of time
72
+ * series data. You can install @quantform/editor to render this data in your browser.
73
+ */
74
+ measurement?: Measurement;
75
+
76
+ /**
77
+ * Session additional options.
78
+ */
79
+ options?: {
80
+ backtester?: BacktesterOptions;
81
+ paper?: PaperOptions;
82
+ };
83
+ }
84
+
32
85
  export class Session {
33
86
  private initialized = false;
34
87
  private subscription: Subscription;
@@ -1,6 +1,5 @@
1
- import { Session } from '.';
2
- import { InstrumentSelector } from '.';
3
1
  import { combineLatest, finalize, map, take, tap } from 'rxjs';
2
+ import { InstrumentSelector, Session } from '.';
4
3
  import { drawdown } from '../indicator';
5
4
  import { floor, precision } from '../shared';
6
5
 
@@ -1,5 +1,5 @@
1
- import { timestamp } from '../shared';
2
1
  import { Instrument } from '.';
2
+ import { timestamp } from '../shared';
3
3
  import { Component } from './component';
4
4
 
5
5
  /**
package/src/index.ts CHANGED
@@ -1,11 +1,8 @@
1
- export * from './shared';
2
- export * from './domain';
3
1
  export * from './adapter';
4
- export * from './adapter/backtester';
5
- export * from './adapter/paper';
2
+ export * from './bootstrap';
3
+ export * from './domain';
6
4
  export * from './indicator';
5
+ export * from './ipc';
6
+ export * from './shared';
7
7
  export * from './storage';
8
8
  export * from './store';
9
- export * from './store/event';
10
- export * from './bootstrap';
11
- export * from './ipc';
@@ -1,5 +1,4 @@
1
- import { Observable } from 'rxjs';
2
- import { share, map } from 'rxjs/operators';
1
+ import { map, Observable, share } from 'rxjs';
3
2
  import { Candle } from '../domain';
4
3
  import { rma } from './rma';
5
4
  import { truerange } from './truerange';
@@ -1,8 +1,7 @@
1
- import { Observable } from 'rxjs';
2
- import { filter } from 'rxjs/operators';
1
+ import { filter, Observable } from 'rxjs';
3
2
 
4
3
  export function crossunder<T>(limitFn: (it: T) => number, currentFn: (it: T) => number) {
5
- return function(source: Observable<T>): Observable<T> {
4
+ return function (source: Observable<T>): Observable<T> {
6
5
  let triggered = false;
7
6
 
8
7
  return source.pipe(
@@ -27,7 +26,7 @@ export function crossunder<T>(limitFn: (it: T) => number, currentFn: (it: T) =>
27
26
  }
28
27
 
29
28
  export function crossover<T>(limitFn: (it: T) => number, currentFn: (it: T) => number) {
30
- return function(source: Observable<T>): Observable<T> {
29
+ return function (source: Observable<T>): Observable<T> {
31
30
  let triggered = false;
32
31
 
33
32
  return source.pipe(
@@ -1,7 +1,6 @@
1
- import { Observable, withLatestFrom } from 'rxjs';
2
- import { map, share } from 'rxjs/operators';
3
- import { minMax } from './min-max';
1
+ import { map, Observable, share, withLatestFrom } from 'rxjs';
4
2
  import { Candle } from '../domain';
3
+ import { minMax } from './min-max';
5
4
 
6
5
  export function donchian<T>(length: number, fn: (it: T) => Candle) {
7
6
  return function (source: Observable<T>): Observable<
@@ -1,8 +1,7 @@
1
- import { Observable } from 'rxjs';
2
- import { map, share } from 'rxjs/operators';
1
+ import { map, Observable, share } from 'rxjs';
3
2
 
4
3
  export function drawdown<T>(fn: (it: T) => number) {
5
- return function(source: Observable<T>): Observable<number> {
4
+ return function (source: Observable<T>): Observable<number> {
6
5
  let rate;
7
6
  let max = 0;
8
7
 
@@ -1,5 +1,4 @@
1
- import { Observable } from 'rxjs';
2
- import { map, share } from 'rxjs/operators';
1
+ import { map, Observable, share } from 'rxjs';
3
2
  import { sma } from './sma';
4
3
 
5
4
  export function ema<T>(length: number, fn: (it: T) => number) {
@@ -1,5 +1,4 @@
1
- import { Observable } from 'rxjs';
2
- import { map, share } from 'rxjs/operators';
1
+ import { map, Observable, share } from 'rxjs';
3
2
  import { sma } from './sma';
4
3
 
5
4
  export function envelope<T>(length: number, percent: number, valueFn: (it: T) => number) {