@quantform/core 0.5.15 → 0.5.23

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 (282) hide show
  1. package/dist/adapter/adapter-aggregate.d.ts +5 -4
  2. package/dist/adapter/adapter-aggregate.js +4 -4
  3. package/dist/adapter/adapter-aggregate.js.map +1 -1
  4. package/dist/adapter/adapter.d.ts +4 -15
  5. package/dist/adapter/adapter.js.map +1 -1
  6. package/dist/adapter/backtester/backtester-adapter.d.ts +3 -3
  7. package/dist/adapter/backtester/backtester-adapter.js +4 -4
  8. package/dist/adapter/backtester/backtester-adapter.js.map +1 -1
  9. package/dist/adapter/backtester/backtester-adapter.spec.js +7 -6
  10. package/dist/adapter/backtester/backtester-adapter.spec.js.map +1 -1
  11. package/dist/adapter/backtester/backtester-cursor.d.ts +4 -4
  12. package/dist/adapter/backtester/backtester-cursor.js.map +1 -1
  13. package/dist/adapter/backtester/backtester-cursor.spec.js +19 -17
  14. package/dist/adapter/backtester/backtester-cursor.spec.js.map +1 -1
  15. package/dist/adapter/backtester/backtester-streamer.d.ts +0 -1
  16. package/dist/adapter/backtester/backtester-streamer.js +4 -14
  17. package/dist/adapter/backtester/backtester-streamer.js.map +1 -1
  18. package/dist/adapter/backtester/backtester-streamer.spec.js +12 -11
  19. package/dist/adapter/backtester/backtester-streamer.spec.js.map +1 -1
  20. package/dist/adapter/paper/engine/paper-engine.js +20 -19
  21. package/dist/adapter/paper/engine/paper-engine.js.map +1 -1
  22. package/dist/adapter/paper/engine/paper-engine.spec.js +19 -19
  23. package/dist/adapter/paper/engine/paper-engine.spec.js.map +1 -1
  24. package/dist/adapter/paper/paper-adapter.d.ts +4 -3
  25. package/dist/adapter/paper/paper-adapter.js +8 -7
  26. package/dist/adapter/paper/paper-adapter.js.map +1 -1
  27. package/dist/adapter/paper/paper-adapter.spec.js +5 -4
  28. package/dist/adapter/paper/paper-adapter.spec.js.map +1 -1
  29. package/dist/cli/pull.js +5 -10
  30. package/dist/cli/pull.js.map +1 -1
  31. package/dist/domain/asset.d.ts +4 -4
  32. package/dist/domain/asset.js +4 -7
  33. package/dist/domain/asset.js.map +1 -1
  34. package/dist/domain/asset.spec.js +4 -4
  35. package/dist/domain/asset.spec.js.map +1 -1
  36. package/dist/domain/balance.d.ts +9 -9
  37. package/dist/domain/balance.js +16 -15
  38. package/dist/domain/balance.js.map +1 -1
  39. package/dist/domain/balance.spec.js +37 -36
  40. package/dist/domain/balance.spec.js.map +1 -1
  41. package/dist/domain/candle.d.ts +8 -8
  42. package/dist/domain/candle.js +3 -2
  43. package/dist/domain/candle.js.map +1 -1
  44. package/dist/domain/candle.operator.d.ts +3 -2
  45. package/dist/domain/candle.operator.js.map +1 -1
  46. package/dist/domain/candle.operator.spec.js +43 -42
  47. package/dist/domain/candle.operator.spec.js.map +1 -1
  48. package/dist/domain/candle.spec.js +11 -11
  49. package/dist/domain/candle.spec.js.map +1 -1
  50. package/dist/domain/commission.d.ts +10 -9
  51. package/dist/domain/commission.js +5 -5
  52. package/dist/domain/commission.js.map +1 -1
  53. package/dist/domain/commission.spec.js +13 -12
  54. package/dist/domain/commission.spec.js.map +1 -1
  55. package/dist/domain/error.d.ts +2 -1
  56. package/dist/domain/error.js +1 -1
  57. package/dist/domain/error.js.map +1 -1
  58. package/dist/domain/order.d.ts +13 -13
  59. package/dist/domain/order.js +10 -9
  60. package/dist/domain/order.js.map +1 -1
  61. package/dist/domain/order.operator.spec.js +6 -5
  62. package/dist/domain/order.operator.spec.js.map +1 -1
  63. package/dist/domain/order.spec.js +11 -10
  64. package/dist/domain/order.spec.js.map +1 -1
  65. package/dist/domain/orderbook.d.ts +18 -6
  66. package/dist/domain/orderbook.js +5 -4
  67. package/dist/domain/orderbook.js.map +1 -1
  68. package/dist/domain/position.d.ts +7 -7
  69. package/dist/domain/position.js +2 -2
  70. package/dist/domain/position.js.map +1 -1
  71. package/dist/domain/position.operator.d.ts +3 -2
  72. package/dist/domain/position.operator.js +3 -3
  73. package/dist/domain/position.operator.js.map +1 -1
  74. package/dist/domain/position.operator.spec.js +4 -3
  75. package/dist/domain/position.operator.spec.js.map +1 -1
  76. package/dist/domain/position.spec.js +10 -9
  77. package/dist/domain/position.spec.js.map +1 -1
  78. package/dist/domain/session.js +1 -1
  79. package/dist/domain/session.js.map +1 -1
  80. package/dist/domain/session.spec.js +1 -1
  81. package/dist/domain/session.spec.js.map +1 -1
  82. package/dist/domain/trade.d.ts +3 -3
  83. package/dist/indicator/atr.d.ts +2 -1
  84. package/dist/indicator/atr.js +3 -3
  85. package/dist/indicator/atr.js.map +1 -1
  86. package/dist/indicator/cross.d.ts +3 -2
  87. package/dist/indicator/cross.js +13 -13
  88. package/dist/indicator/cross.js.map +1 -1
  89. package/dist/indicator/cross.spec.js +22 -21
  90. package/dist/indicator/cross.spec.js.map +1 -1
  91. package/dist/indicator/donchian.d.ts +3 -2
  92. package/dist/indicator/donchian.js.map +1 -1
  93. package/dist/indicator/drawdown.d.ts +2 -1
  94. package/dist/indicator/drawdown.js +3 -2
  95. package/dist/indicator/drawdown.js.map +1 -1
  96. package/dist/indicator/ema.d.ts +2 -1
  97. package/dist/indicator/ema.js +3 -2
  98. package/dist/indicator/ema.js.map +1 -1
  99. package/dist/indicator/ema.spec.js +3 -2
  100. package/dist/indicator/ema.spec.js.map +1 -1
  101. package/dist/indicator/envelope.d.ts +4 -3
  102. package/dist/indicator/envelope.js +4 -4
  103. package/dist/indicator/envelope.js.map +1 -1
  104. package/dist/indicator/index.d.ts +1 -1
  105. package/dist/indicator/index.js +1 -1
  106. package/dist/indicator/index.js.map +1 -1
  107. package/dist/indicator/macd.d.ts +2 -1
  108. package/dist/indicator/macd.js +1 -1
  109. package/dist/indicator/macd.js.map +1 -1
  110. package/dist/indicator/min-max.d.ts +4 -3
  111. package/dist/indicator/min-max.js +5 -4
  112. package/dist/indicator/min-max.js.map +1 -1
  113. package/dist/indicator/rma.d.ts +2 -1
  114. package/dist/indicator/rma.js +3 -2
  115. package/dist/indicator/rma.js.map +1 -1
  116. package/dist/indicator/sma.d.ts +2 -1
  117. package/dist/indicator/sma.js +4 -6
  118. package/dist/indicator/sma.js.map +1 -1
  119. package/dist/indicator/sma.spec.js +3 -2
  120. package/dist/indicator/sma.spec.js.map +1 -1
  121. package/dist/indicator/swma.d.ts +2 -1
  122. package/dist/indicator/swma.js +5 -1
  123. package/dist/indicator/swma.js.map +1 -1
  124. package/dist/indicator/tma.d.ts +2 -1
  125. package/dist/indicator/tma.js.map +1 -1
  126. package/dist/indicator/tma.spec.js +3 -2
  127. package/dist/indicator/tma.spec.js.map +1 -1
  128. package/dist/indicator/trailing.d.ts +8 -7
  129. package/dist/indicator/trailing.js +12 -11
  130. package/dist/indicator/trailing.js.map +1 -1
  131. package/dist/indicator/trailing.spec.js +15 -14
  132. package/dist/indicator/trailing.spec.js.map +1 -1
  133. package/dist/indicator/true-range.d.ts +4 -0
  134. package/dist/indicator/true-range.js +20 -0
  135. package/dist/indicator/true-range.js.map +1 -0
  136. package/dist/indicator/{truerange.spec.d.ts → true-range.spec.d.ts} +0 -0
  137. package/dist/indicator/true-range.spec.js +28 -0
  138. package/dist/indicator/true-range.spec.js.map +1 -0
  139. package/dist/indicator/window.d.ts +1 -1
  140. package/dist/indicator/window.js +1 -1
  141. package/dist/indicator/window.js.map +1 -1
  142. package/dist/indicator/wma.d.ts +2 -1
  143. package/dist/indicator/wma.js +6 -5
  144. package/dist/indicator/wma.js.map +1 -1
  145. package/dist/indicator/wma.spec.js +3 -2
  146. package/dist/indicator/wma.spec.js.map +1 -1
  147. package/dist/shared/collections.d.ts +16 -0
  148. package/dist/shared/collections.js +83 -1
  149. package/dist/shared/collections.js.map +1 -1
  150. package/dist/shared/collections.spec.d.ts +1 -0
  151. package/dist/shared/collections.spec.js +28 -0
  152. package/dist/shared/collections.spec.js.map +1 -0
  153. package/dist/shared/decimals.d.ts +15 -6
  154. package/dist/shared/decimals.js +21 -34
  155. package/dist/shared/decimals.js.map +1 -1
  156. package/dist/shared/decimals.spec.js +17 -22
  157. package/dist/shared/decimals.spec.js.map +1 -1
  158. package/dist/shared/index.d.ts +1 -0
  159. package/dist/shared/index.js +1 -0
  160. package/dist/shared/index.js.map +1 -1
  161. package/dist/shared/pipe.d.ts +4 -0
  162. package/dist/shared/pipe.js +9 -0
  163. package/dist/shared/pipe.js.map +1 -0
  164. package/dist/storage/feed.d.ts +8 -4
  165. package/dist/storage/feed.js +55 -18
  166. package/dist/storage/feed.js.map +1 -1
  167. package/dist/store/store-balance.event.d.ts +6 -6
  168. package/dist/store/store-balance.event.js +2 -2
  169. package/dist/store/store-balance.event.js.map +1 -1
  170. package/dist/store/store-balance.event.spec.js +4 -4
  171. package/dist/store/store-balance.event.spec.js.map +1 -1
  172. package/dist/store/store-instrument.event.js.map +1 -1
  173. package/dist/store/store-instrument.event.spec.js +1 -1
  174. package/dist/store/store-instrument.event.spec.js.map +1 -1
  175. package/dist/store/store-order.event.d.ts +3 -3
  176. package/dist/store/store-order.event.js.map +1 -1
  177. package/dist/store/store-order.event.spec.js +1 -1
  178. package/dist/store/store-order.event.spec.js.map +1 -1
  179. package/dist/store/store-orderbook.event.d.ts +4 -6
  180. package/dist/store/store-orderbook.event.js +13 -13
  181. package/dist/store/store-orderbook.event.js.map +1 -1
  182. package/dist/store/store-orderbook.event.spec.d.ts +1 -0
  183. package/dist/store/store-orderbook.event.spec.js +28 -0
  184. package/dist/store/store-orderbook.event.spec.js.map +1 -0
  185. package/dist/store/store-position.event.d.ts +4 -4
  186. package/dist/store/store-position.event.js +23 -11
  187. package/dist/store/store-position.event.js.map +1 -1
  188. package/dist/store/store-trade.event.d.ts +4 -4
  189. package/dist/store/store-trade.event.js +2 -2
  190. package/dist/store/store-trade.event.js.map +1 -1
  191. package/dist/store/store-trade.event.spec.js +8 -8
  192. package/dist/store/store-trade.event.spec.js.map +1 -1
  193. package/dist/store/store.spec.js +15 -15
  194. package/dist/store/store.spec.js.map +1 -1
  195. package/dist/tsconfig.tsbuildinfo +1 -1
  196. package/jestconfig.json +1 -0
  197. package/package.json +3 -1
  198. package/src/adapter/adapter-aggregate.ts +16 -7
  199. package/src/adapter/adapter.ts +15 -18
  200. package/src/adapter/backtester/backtester-adapter.spec.ts +18 -9
  201. package/src/adapter/backtester/backtester-adapter.ts +14 -5
  202. package/src/adapter/backtester/backtester-cursor.spec.ts +20 -18
  203. package/src/adapter/backtester/backtester-cursor.ts +5 -5
  204. package/src/adapter/backtester/backtester-streamer.spec.ts +14 -13
  205. package/src/adapter/backtester/backtester-streamer.ts +5 -22
  206. package/src/adapter/paper/engine/paper-engine.spec.ts +30 -23
  207. package/src/adapter/paper/engine/paper-engine.ts +28 -21
  208. package/src/adapter/paper/paper-adapter.spec.ts +15 -6
  209. package/src/adapter/paper/paper-adapter.ts +20 -8
  210. package/src/cli/pull.ts +6 -5
  211. package/src/domain/asset.spec.ts +4 -4
  212. package/src/domain/asset.ts +7 -14
  213. package/src/domain/balance.spec.ts +37 -36
  214. package/src/domain/balance.ts +29 -29
  215. package/src/domain/candle.operator.spec.ts +43 -42
  216. package/src/domain/candle.operator.ts +4 -3
  217. package/src/domain/candle.spec.ts +13 -12
  218. package/src/domain/candle.ts +9 -9
  219. package/src/domain/commission.spec.ts +13 -12
  220. package/src/domain/commission.ts +13 -11
  221. package/src/domain/error.ts +5 -3
  222. package/src/domain/order.operator.spec.ts +6 -5
  223. package/src/domain/order.spec.ts +11 -10
  224. package/src/domain/order.ts +25 -22
  225. package/src/domain/orderbook.ts +14 -8
  226. package/src/domain/position.operator.spec.ts +5 -4
  227. package/src/domain/position.operator.ts +8 -5
  228. package/src/domain/position.spec.ts +10 -9
  229. package/src/domain/position.ts +8 -8
  230. package/src/domain/session.spec.ts +3 -3
  231. package/src/domain/session.ts +1 -3
  232. package/src/domain/trade.ts +3 -3
  233. package/src/indicator/atr.ts +6 -5
  234. package/src/indicator/cross.spec.ts +32 -47
  235. package/src/indicator/cross.ts +18 -10
  236. package/src/indicator/donchian.ts +5 -4
  237. package/src/indicator/drawdown.ts +7 -5
  238. package/src/indicator/ema.spec.ts +4 -3
  239. package/src/indicator/ema.ts +7 -6
  240. package/src/indicator/envelope.ts +11 -6
  241. package/src/indicator/index.ts +1 -1
  242. package/src/indicator/macd.ts +5 -4
  243. package/src/indicator/min-max.ts +10 -7
  244. package/src/indicator/rma.ts +7 -6
  245. package/src/indicator/sma.spec.ts +4 -3
  246. package/src/indicator/sma.ts +9 -8
  247. package/src/indicator/swma.ts +8 -4
  248. package/src/indicator/tma.spec.ts +4 -3
  249. package/src/indicator/tma.ts +4 -3
  250. package/src/indicator/trailing.spec.ts +29 -16
  251. package/src/indicator/trailing.ts +22 -16
  252. package/src/indicator/true-range.spec.ts +32 -0
  253. package/src/indicator/true-range.ts +32 -0
  254. package/src/indicator/window.ts +3 -3
  255. package/src/indicator/wma.spec.ts +4 -3
  256. package/src/indicator/wma.ts +8 -7
  257. package/src/shared/collections.spec.ts +30 -0
  258. package/src/shared/collections.ts +106 -0
  259. package/src/shared/decimals.spec.ts +18 -24
  260. package/src/shared/decimals.ts +22 -55
  261. package/src/shared/index.ts +1 -0
  262. package/src/shared/pipe.ts +12 -0
  263. package/src/storage/feed.ts +89 -34
  264. package/src/store/store-balance.event.spec.ts +5 -5
  265. package/src/store/store-balance.event.ts +6 -6
  266. package/src/store/store-instrument.event.spec.ts +2 -2
  267. package/src/store/store-instrument.event.ts +2 -2
  268. package/src/store/store-order.event.spec.ts +2 -2
  269. package/src/store/store-order.event.ts +2 -2
  270. package/src/store/store-orderbook.event.spec.ts +37 -0
  271. package/src/store/store-orderbook.event.ts +13 -13
  272. package/src/store/store-position.event.ts +27 -15
  273. package/src/store/store-trade.event.spec.ts +9 -9
  274. package/src/store/store-trade.event.ts +5 -5
  275. package/src/store/store.spec.ts +16 -16
  276. package/dist/indicator/truerange.d.ts +0 -3
  277. package/dist/indicator/truerange.js +0 -19
  278. package/dist/indicator/truerange.js.map +0 -1
  279. package/dist/indicator/truerange.spec.js +0 -28
  280. package/dist/indicator/truerange.spec.js.map +0 -1
  281. package/src/indicator/truerange.spec.ts +0 -32
  282. package/src/indicator/truerange.ts +0 -31
package/src/cli/pull.ts CHANGED
@@ -49,18 +49,19 @@ export default async function (name: string, instrument: string, options: any) {
49
49
 
50
50
  bar.start(100, 0);
51
51
 
52
- await session.aggregate.feed({
53
- instrument: instrumentOf(instrument),
52
+ await session.aggregate.feed(
53
+ instrumentOf(instrument),
54
54
  from,
55
55
  to,
56
- destination: feed,
57
- callback: timestamp => {
56
+ async (timestamp, events) => {
58
57
  const duration = to - from;
59
58
  const completed = timestamp - from;
60
59
 
60
+ await feed.save(events);
61
+
61
62
  bar.update(Math.floor((completed / duration) * 100));
62
63
  }
63
- });
64
+ );
64
65
 
65
66
  bar.update(100);
66
67
  bar.stop();
@@ -1,3 +1,4 @@
1
+ import { d } from '../shared';
1
2
  import { Asset, assetOf } from './asset';
2
3
 
3
4
  describe('Asset', () => {
@@ -7,10 +8,9 @@ describe('Asset', () => {
7
8
  expect(sut.name).toEqual('abc');
8
9
  expect(sut.adapterName).toEqual('xyz');
9
10
  expect(sut.scale).toEqual(4);
10
- expect(sut.tickSize).toEqual(0.0001);
11
- expect(sut.fixed(1.1234567)).toEqual(1.1234);
12
- expect(sut.floor(1.1234567)).toEqual(1.1234);
13
- expect(sut.ceil(1.1234567)).toEqual(1.1235);
11
+ expect(sut.tickSize).toEqual(d(0.0001));
12
+ expect(sut.floor(d(1.1234567))).toEqual(d(1.1234));
13
+ expect(sut.ceil(d(1.1234567))).toEqual(d(1.1235));
14
14
  expect(sut.id).toEqual('xyz:abc');
15
15
  });
16
16
 
@@ -1,4 +1,4 @@
1
- import { ceil, fixed, floor } from '../shared/decimals';
1
+ import { d, decimal } from './../shared/decimals';
2
2
  import { invalidArgumentError, invalidAssetSelectorError } from './error';
3
3
 
4
4
  export const AssetSelectorSeparator = ':';
@@ -51,7 +51,7 @@ export function assetOf(selector: string): AssetSelector {
51
51
  * For example, you can combine two trading assets to create a trading instrument.
52
52
  */
53
53
  export class Asset extends AssetSelector {
54
- readonly tickSize: number;
54
+ readonly tickSize: decimal;
55
55
 
56
56
  constructor(name: string, adapterName: string, public readonly scale: number) {
57
57
  super(name, adapterName);
@@ -60,27 +60,20 @@ export class Asset extends AssetSelector {
60
60
  throw invalidArgumentError(scale);
61
61
  }
62
62
 
63
- this.tickSize = 1.0 / Math.pow(10, this.scale);
64
- }
65
-
66
- /**
67
- * Trims a number to the asset precision.
68
- */
69
- fixed(number: number): number {
70
- return fixed(number, this.scale);
63
+ this.tickSize = d(1.0).div(Math.pow(10, this.scale));
71
64
  }
72
65
 
73
66
  /**
74
67
  * Rounds down a number to the asset precision.
75
68
  */
76
- floor(number: number): number {
77
- return floor(number, this.scale);
69
+ floor(number: decimal): decimal {
70
+ return number.toFloor(this.scale);
78
71
  }
79
72
 
80
73
  /**
81
74
  * Rounds up a number to the asset precision.
82
75
  */
83
- ceil(number: number): number {
84
- return ceil(number, this.scale);
76
+ ceil(number: decimal): decimal {
77
+ return number.toCeil(this.scale);
85
78
  }
86
79
  }
@@ -1,3 +1,4 @@
1
+ import { d } from '../shared';
1
2
  import { Asset } from './asset';
2
3
  import { Balance } from './balance';
3
4
  import { Instrument } from './instrument';
@@ -15,50 +16,50 @@ describe('Balance', () => {
15
16
  const sut = new Balance(asset);
16
17
 
17
18
  expect(sut.asset.id).toEqual('xyz:abc');
18
- expect(sut.free).toEqual(0);
19
- expect(sut.locked).toEqual(0);
19
+ expect(sut.free).toEqual(d.Zero);
20
+ expect(sut.locked).toEqual(d.Zero);
20
21
  expect(Object.keys(sut.position).length).toEqual(0);
21
22
  });
22
23
 
23
24
  test('should construct balance', () => {
24
25
  const sut = new Balance(asset);
25
26
 
26
- sut.set(100, 50);
27
+ sut.set(d(100), d(50));
27
28
 
28
29
  expect(sut.asset.id).toEqual('xyz:abc');
29
- expect(sut.free).toEqual(100);
30
- expect(sut.locked).toEqual(50);
31
- expect(sut.total).toEqual(150);
30
+ expect(sut.free).toEqual(d(100));
31
+ expect(sut.locked).toEqual(d(50));
32
+ expect(sut.total).toEqual(d(150));
32
33
  expect(Object.keys(sut.position).length).toEqual(0);
33
34
  });
34
35
 
35
36
  test('should account positive amount', () => {
36
37
  const sut = new Balance(asset);
37
38
 
38
- sut.set(100, 0);
39
- sut.account(10);
39
+ sut.set(d(100), d.Zero);
40
+ sut.account(d(10));
40
41
 
41
- expect(sut.free).toEqual(110);
42
- expect(sut.locked).toEqual(0);
43
- expect(sut.total).toEqual(110);
42
+ expect(sut.free).toEqual(d(110));
43
+ expect(sut.locked).toEqual(d.Zero);
44
+ expect(sut.total).toEqual(d(110));
44
45
  });
45
46
 
46
47
  test('should account negative amount', () => {
47
48
  const sut = new Balance(asset);
48
49
 
49
- sut.set(100, 0);
50
- sut.account(-10);
50
+ sut.set(d(100), d.Zero);
51
+ sut.account(d(-10));
51
52
 
52
- expect(sut.free).toEqual(90);
53
- expect(sut.locked).toEqual(0);
54
- expect(sut.total).toEqual(90);
53
+ expect(sut.free).toEqual(d(90));
54
+ expect(sut.locked).toEqual(d.Zero);
55
+ expect(sut.total).toEqual(d(90));
55
56
  });
56
57
 
57
58
  test('should throw for insufficient balance account amount', () => {
58
59
  const sut = new Balance(asset);
59
60
 
60
- sut.set(100, 0);
61
- const fn = () => sut.account(-120);
61
+ sut.set(d(100), d.Zero);
62
+ const fn = () => sut.account(d(-120));
62
63
 
63
64
  expect(fn).toThrowError();
64
65
  });
@@ -66,19 +67,19 @@ describe('Balance', () => {
66
67
  test('should lock specific amount of available balance', () => {
67
68
  const sut = new Balance(asset);
68
69
 
69
- sut.set(100, 0);
70
- sut.lock('key', 10);
70
+ sut.set(d(100), d.Zero);
71
+ sut.lock('key', d(10));
71
72
 
72
- expect(sut.free).toEqual(90);
73
- expect(sut.locked).toEqual(10);
74
- expect(sut.total).toEqual(100);
73
+ expect(sut.free).toEqual(d(90));
74
+ expect(sut.locked).toEqual(d(10));
75
+ expect(sut.total).toEqual(d(100));
75
76
  });
76
77
 
77
78
  test('should throw for lock insufficient amount of available balance', () => {
78
79
  const sut = new Balance(asset);
79
80
 
80
- sut.set(30, 50);
81
- const fn = () => sut.lock('key', 100);
81
+ sut.set(d(30), d(50));
82
+ const fn = () => sut.lock('key', d(100));
82
83
 
83
84
  expect(fn).toThrowError();
84
85
  });
@@ -86,27 +87,27 @@ describe('Balance', () => {
86
87
  test('should lock an unlock specific amount of available balance', () => {
87
88
  const sut = new Balance(asset);
88
89
 
89
- sut.set(100, 0);
90
- sut.lock('key', 40);
90
+ sut.set(d(100), d.Zero);
91
+ sut.lock('key', d(40));
91
92
  sut.tryUnlock('key');
92
93
 
93
- expect(sut.free).toEqual(100);
94
- expect(sut.locked).toEqual(0);
95
- expect(sut.total).toEqual(100);
94
+ expect(sut.free).toEqual(d(100));
95
+ expect(sut.locked).toEqual(d.Zero);
96
+ expect(sut.total).toEqual(d(100));
96
97
  });
97
98
 
98
99
  test('should return correct estimated unrealized pnl', () => {
99
- const position = new Position('1', instrument, 'CROSS', 2511.81, 10.31, 20);
100
+ const position = new Position('1', instrument, 'CROSS', d(2511.81), d(10.31), 20);
100
101
 
101
- position.calculateEstimatedUnrealizedPnL(2576.44);
102
+ position.calculateEstimatedUnrealizedPnL(d(2576.44));
102
103
 
103
104
  const sut = new Balance(asset);
104
105
 
105
- sut.set(100, 0);
106
+ sut.set(d(100), d.Zero);
106
107
  sut.position['1'] = position;
107
108
 
108
- expect(sut.getEstimatedUnrealizedPnL()).toEqual(0.2652);
109
- expect(sut.free).toEqual(100 + 0.2652);
110
- expect(sut.total).toEqual(100 + 0.2652);
109
+ expect(sut.getEstimatedUnrealizedPnL()).toEqual(d(0.2652));
110
+ expect(sut.free).toEqual(d(100).add(d(0.2652)));
111
+ expect(sut.total).toEqual(d(100).add(d(0.2652)));
111
112
  });
112
113
  });
@@ -1,4 +1,4 @@
1
- import { timestamp } from '../shared';
1
+ import { d, decimal, timestamp } from '../shared';
2
2
  import { Asset } from './';
3
3
  import { Component } from './component';
4
4
  import { insufficientFundsError, invalidArgumentError } from './error';
@@ -12,21 +12,21 @@ export class Balance implements Component {
12
12
  kind = 'balance';
13
13
  timestamp: timestamp;
14
14
 
15
- private locker: Record<string, number> = {};
16
- private available = 0;
17
- private unavailable = 0;
15
+ private locker: Record<string, decimal> = {};
16
+ private available = d.Zero;
17
+ private unavailable = d.Zero;
18
18
 
19
19
  /**
20
20
  * Returns available amount to trade.
21
21
  */
22
- get free(): number {
23
- return this.asset.fixed(this.available) + this.getEstimatedUnrealizedPnL('CROSS');
22
+ get free(): decimal {
23
+ return this.asset.floor(this.available).add(this.getEstimatedUnrealizedPnL('CROSS'));
24
24
  }
25
25
 
26
26
  /**
27
27
  * Return locked amount for order.
28
28
  */
29
- get locked(): number {
29
+ get locked(): decimal {
30
30
  return this.unavailable;
31
31
  }
32
32
 
@@ -34,11 +34,10 @@ export class Balance implements Component {
34
34
  * Return total amount of asset in wallet.
35
35
  * Represents a sum of free, locked and opened positions.
36
36
  */
37
- get total(): number {
38
- return (
39
- this.asset.fixed(this.available + this.unavailable) +
40
- this.getEstimatedUnrealizedPnL()
41
- );
37
+ get total(): decimal {
38
+ return this.asset
39
+ .floor(this.available.add(this.unavailable))
40
+ .add(this.getEstimatedUnrealizedPnL());
42
41
  }
43
42
 
44
43
  /**
@@ -50,15 +49,15 @@ export class Balance implements Component {
50
49
  this.id = asset.id;
51
50
  }
52
51
 
53
- account(amount: number) {
54
- if (this.available + amount < 0) {
52
+ account(amount: decimal) {
53
+ if (this.available.add(amount).lessThan(0)) {
55
54
  throw insufficientFundsError(this.id, amount, this.available);
56
55
  }
57
56
 
58
- this.available += amount;
57
+ this.available = this.available.add(amount);
59
58
  }
60
59
 
61
- set(free: number, locked: number) {
60
+ set(free: decimal, locked: decimal) {
62
61
  this.available = free;
63
62
  this.unavailable = locked;
64
63
  this.locker = {};
@@ -68,8 +67,8 @@ export class Balance implements Component {
68
67
  * Lock specific amount of asset.
69
68
  * If you place new pending order, you will lock your balance to fund order.
70
69
  */
71
- lock(id: string, amount: number) {
72
- if (this.available < amount) {
70
+ lock(id: string, amount: decimal) {
71
+ if (this.available.lessThan(amount)) {
73
72
  throw insufficientFundsError(this.id, amount, this.available);
74
73
  }
75
74
 
@@ -78,8 +77,8 @@ export class Balance implements Component {
78
77
  }
79
78
 
80
79
  this.locker[id] = amount;
81
- this.available -= amount;
82
- this.unavailable += amount;
80
+ this.available = this.available.minus(amount);
81
+ this.unavailable = this.unavailable.plus(amount);
83
82
  }
84
83
 
85
84
  tryUnlock(id: string): boolean {
@@ -95,8 +94,8 @@ export class Balance implements Component {
95
94
  throw insufficientFundsError(this.id, amount, this.unavailable);
96
95
  }
97
96
 
98
- this.available += amount;
99
- this.unavailable -= amount;
97
+ this.available = this.available.add(amount);
98
+ this.unavailable = this.unavailable.minus(amount);
100
99
 
101
100
  return true;
102
101
  }
@@ -104,20 +103,21 @@ export class Balance implements Component {
104
103
  /**
105
104
  * Returns unrealized profit and loss for all positions backed by this balance.
106
105
  */
107
- getEstimatedUnrealizedPnL(mode?: PositionMode) {
106
+ getEstimatedUnrealizedPnL(mode?: PositionMode): decimal {
108
107
  return Object.values(this.position).reduce(
109
108
  (aggregate, position) =>
110
- (aggregate +=
111
- mode && mode != position.mode ? 0 : position.estimatedUnrealizedPnL),
112
- 0
109
+ (aggregate = aggregate.add(
110
+ mode && mode != position.mode ? 0 : position.estimatedUnrealizedPnL
111
+ )),
112
+ d.Zero
113
113
  );
114
114
  }
115
115
 
116
- getEstimatedMargin(mode?: PositionMode): number {
116
+ getEstimatedMargin(mode?: PositionMode): decimal {
117
117
  return Object.values(this.position).reduce(
118
118
  (aggregate, position) =>
119
- (aggregate += mode && mode != position.mode ? 0 : position.margin),
120
- 0
119
+ (aggregate = aggregate.add(mode && mode != position.mode ? 0 : position.margin)),
120
+ d.Zero
121
121
  );
122
122
  }
123
123
 
@@ -1,26 +1,27 @@
1
1
  import { from } from 'rxjs';
2
2
 
3
+ import { d } from '../shared';
3
4
  import { Candle } from './candle';
4
5
  import { candle, candleCompleted, mergeCandle } from './candle.operator';
5
6
 
6
7
  describe('candle', () => {
7
8
  test('should aggregate and pipe candle updates', done => {
8
9
  const input$ = from([
9
- { timestamp: 1, rate: 1 },
10
- { timestamp: 2, rate: 2 },
11
- { timestamp: 3, rate: 3 },
12
- { timestamp: 4, rate: 0 },
13
- { timestamp: 5, rate: 7 },
14
- { timestamp: 6, rate: 8 }
10
+ { timestamp: 1, rate: d(1) },
11
+ { timestamp: 2, rate: d(2) },
12
+ { timestamp: 3, rate: d(3) },
13
+ { timestamp: 4, rate: d.Zero },
14
+ { timestamp: 5, rate: d(7) },
15
+ { timestamp: 6, rate: d(8) }
15
16
  ]);
16
17
 
17
18
  const output = [
18
- { timestamp: 0, open: 1, high: 1, low: 1, close: 1 },
19
- { timestamp: 0, open: 1, high: 2, low: 1, close: 2 },
20
- { timestamp: 0, open: 1, high: 3, low: 1, close: 3 },
21
- { timestamp: 0, open: 1, high: 3, low: 0, close: 0 },
22
- { timestamp: 5, open: 0, high: 7, low: 7, close: 7 },
23
- { timestamp: 5, open: 0, high: 8, low: 7, close: 8 }
19
+ new Candle(0, d(1), d(1), d(1), d(1)),
20
+ new Candle(0, d(1), d(2), d(1), d(2)),
21
+ new Candle(0, d(1), d(3), d(1), d(3)),
22
+ new Candle(0, d(1), d(3), d.Zero, d.Zero),
23
+ new Candle(5, d.Zero, d(7), d(7), d(7)),
24
+ new Candle(5, d.Zero, d(8), d(7), d(8))
24
25
  ].reverse();
25
26
 
26
27
  input$.pipe(candle(5, it => it.rate)).subscribe({
@@ -37,12 +38,12 @@ describe('candle', () => {
37
38
  describe('candleCompleted', () => {
38
39
  test('should aggregate and pipe distinct completed candles', done => {
39
40
  const input$ = from([
40
- { timestamp: 1, rate: 1 },
41
- { timestamp: 2, rate: 2 },
42
- { timestamp: 3, rate: 3 },
43
- { timestamp: 4, rate: 0 },
44
- { timestamp: 5, rate: 7 },
45
- { timestamp: 6, rate: 8 }
41
+ { timestamp: 1, rate: d(1) },
42
+ { timestamp: 2, rate: d(2) },
43
+ { timestamp: 3, rate: d(3) },
44
+ { timestamp: 4, rate: d.Zero },
45
+ { timestamp: 5, rate: d(7) },
46
+ { timestamp: 6, rate: d(8) }
46
47
  ]);
47
48
 
48
49
  input$
@@ -52,7 +53,7 @@ describe('candleCompleted', () => {
52
53
  )
53
54
  .subscribe({
54
55
  next: it => {
55
- expect(it).toEqual({ timestamp: 0, open: 1, high: 3, low: 0, close: 0 });
56
+ expect(it).toEqual(new Candle(0, d(1), d(3), d.Zero, d.Zero));
56
57
  done();
57
58
  }
58
59
  });
@@ -62,23 +63,23 @@ describe('candleCompleted', () => {
62
63
  describe('mergeCandle', () => {
63
64
  test('should pipe and merge candle from history', done => {
64
65
  const history$ = from([
65
- new Candle(1, 1, 1.5, 0.5, 2),
66
- new Candle(2, 2, 2.5, 1.5, 3),
67
- new Candle(3, 3, 3.5, 2.5, 4)
66
+ new Candle(1, d(1), d(1.5), d(0.5), d(2)),
67
+ new Candle(2, d(2), d(2.5), d(1.5), d(3)),
68
+ new Candle(3, d(3), d(3.5), d(2.5), d(4))
68
69
  ]);
69
70
 
70
71
  const input$ = from([
71
- { timestamp: 3, rate: 5 },
72
- { timestamp: 4, rate: 3 },
73
- { timestamp: 5, rate: 4 }
72
+ { timestamp: 3, rate: d(5) },
73
+ { timestamp: 4, rate: d(3) },
74
+ { timestamp: 5, rate: d(4) }
74
75
  ]);
75
76
 
76
77
  const output = [
77
- { timestamp: 1, open: 1, high: 1.5, low: 0.5, close: 2 },
78
- { timestamp: 2, open: 2, high: 2.5, low: 1.5, close: 3 },
79
- { timestamp: 3, open: 3, high: 5, low: 2.5, close: 5 },
80
- { timestamp: 4, open: 5, high: 3, low: 3, close: 3 },
81
- { timestamp: 5, open: 3, high: 4, low: 4, close: 4 }
78
+ new Candle(1, d(1), d(1.5), d(0.5), d(2)),
79
+ new Candle(2, d(2), d(2.5), d(1.5), d(3)),
80
+ new Candle(3, d(3), d(5), d(2.5), d(5)),
81
+ new Candle(4, d(5), d(3), d(3), d(3)),
82
+ new Candle(5, d(3), d(4), d(4), d(4))
82
83
  ].reverse();
83
84
 
84
85
  input$.pipe(mergeCandle(1, it => it.rate, history$)).subscribe({
@@ -93,24 +94,24 @@ describe('mergeCandle', () => {
93
94
 
94
95
  test('should pipe and not merge candle from history', done => {
95
96
  const history$ = from([
96
- new Candle(1, 1, 1.5, 0.5, 2),
97
- new Candle(2, 2, 2.5, 1.5, 3),
98
- new Candle(3, 3, 3.5, 2.5, 4)
97
+ new Candle(1, d(1), d(1.5), d(0.5), d(2)),
98
+ new Candle(2, d(2), d(2.5), d(1.5), d(3)),
99
+ new Candle(3, d(3), d(3.5), d(2.5), d(4))
99
100
  ]);
100
101
 
101
102
  const input$ = from([
102
- { timestamp: 4, rate: 5 },
103
- { timestamp: 5, rate: 3 },
104
- { timestamp: 6, rate: 4 }
103
+ { timestamp: 4, rate: d(5) },
104
+ { timestamp: 5, rate: d(3) },
105
+ { timestamp: 6, rate: d(4) }
105
106
  ]);
106
107
 
107
108
  const output = [
108
- { timestamp: 1, open: 1, high: 1.5, low: 0.5, close: 2 },
109
- { timestamp: 2, open: 2, high: 2.5, low: 1.5, close: 3 },
110
- { timestamp: 3, open: 3, high: 3.5, low: 2.5, close: 4 },
111
- { timestamp: 4, open: 4, high: 5, low: 5, close: 5 },
112
- { timestamp: 5, open: 5, high: 3, low: 3, close: 3 },
113
- { timestamp: 6, open: 3, high: 4, low: 4, close: 4 }
109
+ new Candle(1, d(1), d(1.5), d(0.5), d(2)),
110
+ new Candle(2, d(2), d(2.5), d(1.5), d(3)),
111
+ new Candle(3, d(3), d(3.5), d(2.5), d(4)),
112
+ new Candle(4, d(4), d(5), d(5), d(5)),
113
+ new Candle(5, d(5), d(3), d(3), d(3)),
114
+ new Candle(6, d(3), d(4), d(4), d(4))
114
115
  ].reverse();
115
116
 
116
117
  input$.pipe(mergeCandle(1, it => it.rate, history$)).subscribe({
@@ -10,10 +10,11 @@ import {
10
10
  switchMap
11
11
  } from 'rxjs';
12
12
 
13
+ import { decimal } from '../shared';
13
14
  import { Candle } from './candle';
14
15
  import { tf } from './timeframe';
15
16
 
16
- function aggregate(candle: Candle, timeframe: number, value: number, timestamp: number) {
17
+ function aggregate(candle: Candle, timeframe: number, value: decimal, timestamp: number) {
17
18
  const frame = tf(timestamp, timeframe);
18
19
 
19
20
  if (!candle) {
@@ -29,7 +30,7 @@ function aggregate(candle: Candle, timeframe: number, value: number, timestamp:
29
30
 
30
31
  export function candle<T extends { timestamp: number }>(
31
32
  timeframe: number,
32
- fn: (x: T) => number,
33
+ fn: (x: T) => decimal,
33
34
  candleToStartWith: Candle = undefined
34
35
  ) {
35
36
  return function (source: Observable<T>): Observable<Candle> {
@@ -62,7 +63,7 @@ export function candle<T extends { timestamp: number }>(
62
63
 
63
64
  export function mergeCandle<T extends { timestamp: number }>(
64
65
  timeframe: number,
65
- fn: (x: T) => number,
66
+ fn: (x: T) => decimal,
66
67
  history$: Observable<Candle>
67
68
  ) {
68
69
  return function (source$: Observable<T>): Observable<Candle> {
@@ -1,29 +1,30 @@
1
- import { now } from '../shared';
1
+ import { d, now } from '../shared';
2
2
  import { Candle } from './candle';
3
3
 
4
4
  describe('Candle', () => {
5
5
  test('should construct a candle', () => {
6
6
  const timestamp = now();
7
7
 
8
- const sut = new Candle(timestamp, 2, 4, 1, 3);
8
+ const sut = new Candle(timestamp, d(2), d(4), d(1), d(3));
9
9
 
10
10
  expect(sut.timestamp).toEqual(timestamp);
11
- expect(sut.open).toEqual(2);
12
- expect(sut.high).toEqual(4);
13
- expect(sut.low).toEqual(1);
14
- expect(sut.close).toEqual(3);
11
+ expect(sut.open).toEqual(d(2));
12
+ expect(sut.high).toEqual(d(4));
13
+ expect(sut.low).toEqual(d(1));
14
+ expect(sut.close).toEqual(d(3));
15
15
  });
16
16
 
17
17
  test('should modify a candle', () => {
18
18
  const timestamp = now();
19
19
 
20
- const sut = new Candle(timestamp, 2, 4, 1, 3);
21
- sut.apply(10);
20
+ const sut = new Candle(timestamp, d(2), d(4), d(1), d(3));
21
+
22
+ sut.apply(d(10));
22
23
 
23
24
  expect(sut.timestamp).toEqual(timestamp);
24
- expect(sut.open).toEqual(2);
25
- expect(sut.high).toEqual(10);
26
- expect(sut.low).toEqual(1);
27
- expect(sut.close).toEqual(10);
25
+ expect(sut.open).toEqual(d(2));
26
+ expect(sut.high).toEqual(d(10));
27
+ expect(sut.low).toEqual(d(1));
28
+ expect(sut.close).toEqual(d(10));
28
29
  });
29
30
  });
@@ -1,18 +1,18 @@
1
- import { timestamp } from '../shared';
1
+ import { decimal, timestamp } from '../shared';
2
2
 
3
3
  export class Candle {
4
4
  constructor(
5
5
  public timestamp: timestamp,
6
- public open: number,
7
- public high: number,
8
- public low: number,
9
- public close: number,
10
- public volume?: number
6
+ public open: decimal,
7
+ public high: decimal,
8
+ public low: decimal,
9
+ public close: decimal,
10
+ public volume?: decimal
11
11
  ) {}
12
12
 
13
- apply(value: number) {
14
- this.high = Math.max(this.high, value);
15
- this.low = Math.min(this.low, value);
13
+ apply(value: decimal) {
14
+ this.high = decimal.max(this.high, value);
15
+ this.low = decimal.min(this.low, value);
16
16
  this.close = value;
17
17
  }
18
18
  }
@@ -1,33 +1,34 @@
1
+ import { d } from '../shared';
1
2
  import { commissionPercentOf } from './commission';
2
3
 
3
4
  describe('Commission', () => {
4
5
  test('should construct a Commission', () => {
5
6
  const sut = commissionPercentOf({
6
- maker: 0.1,
7
- taker: 0.2
7
+ maker: d(0.1),
8
+ taker: d(0.2)
8
9
  });
9
10
 
10
- expect(sut.makerRate).toEqual(0.001);
11
- expect(sut.takerRate).toEqual(0.002);
11
+ expect(sut.makerRate).toEqual(d(0.001));
12
+ expect(sut.takerRate).toEqual(d(0.002));
12
13
  });
13
14
 
14
15
  test('should calculate a maker fee', () => {
15
16
  const sut = commissionPercentOf({
16
- maker: 0.1,
17
- taker: 0.2
17
+ maker: d(0.1),
18
+ taker: d(0.2)
18
19
  });
19
20
 
20
- expect(sut.calculateMakerFee(2000)).toEqual(2);
21
- expect(sut.applyMakerFee(2000)).toEqual(1998);
21
+ expect(sut.calculateMakerFee(d(2000))).toEqual(d(2));
22
+ expect(sut.applyMakerFee(d(2000))).toEqual(d(1998));
22
23
  });
23
24
 
24
25
  test('should calculate a taker fee', () => {
25
26
  const sut = commissionPercentOf({
26
- maker: 0.1,
27
- taker: 0.2
27
+ maker: d(0.1),
28
+ taker: d(0.2)
28
29
  });
29
30
 
30
- expect(sut.calculateTakerFee(2000)).toEqual(4);
31
- expect(sut.applyTakerFee(2000)).toEqual(1996);
31
+ expect(sut.calculateTakerFee(d(2000))).toEqual(d(4));
32
+ expect(sut.applyTakerFee(d(2000))).toEqual(d(1996));
32
33
  });
33
34
  });