@quantform/core 0.5.14 → 0.5.15

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 (408) hide show
  1. package/dist/adapter/adapter-aggregate.d.ts +4 -2
  2. package/dist/adapter/adapter-aggregate.js +16 -18
  3. package/dist/adapter/adapter-aggregate.js.map +1 -1
  4. package/dist/adapter/adapter.d.ts +20 -21
  5. package/dist/adapter/adapter.js +8 -43
  6. package/dist/adapter/adapter.js.map +1 -1
  7. package/dist/adapter/backtester/backtester-adapter.d.ts +9 -7
  8. package/dist/adapter/backtester/backtester-adapter.js +13 -12
  9. package/dist/adapter/backtester/backtester-adapter.js.map +1 -1
  10. package/dist/{tests → adapter/backtester}/backtester-adapter.spec.d.ts +0 -0
  11. package/dist/adapter/backtester/backtester-adapter.spec.js +82 -0
  12. package/dist/adapter/backtester/backtester-adapter.spec.js.map +1 -0
  13. package/dist/adapter/backtester/backtester-cursor.d.ts +3 -4
  14. package/dist/adapter/backtester/backtester-cursor.js +2 -1
  15. package/dist/adapter/backtester/backtester-cursor.js.map +1 -1
  16. package/dist/adapter/backtester/backtester-cursor.spec.js +17 -18
  17. package/dist/adapter/backtester/backtester-cursor.spec.js.map +1 -1
  18. package/dist/adapter/backtester/backtester-streamer.d.ts +4 -1
  19. package/dist/adapter/backtester/backtester-streamer.js +39 -18
  20. package/dist/adapter/backtester/backtester-streamer.js.map +1 -1
  21. package/dist/adapter/backtester/backtester-streamer.spec.js +13 -13
  22. package/dist/adapter/backtester/backtester-streamer.spec.js.map +1 -1
  23. package/dist/adapter/error.d.ts +2 -0
  24. package/dist/adapter/error.js +12 -0
  25. package/dist/adapter/error.js.map +1 -0
  26. package/dist/adapter/paper/engine/paper-engine.d.ts +11 -0
  27. package/dist/adapter/paper/engine/paper-engine.js +103 -0
  28. package/dist/adapter/paper/engine/paper-engine.js.map +1 -0
  29. package/dist/adapter/paper/{simulator/paper-spot-simulator.spec.d.ts → engine/paper-engine.spec.d.ts} +0 -0
  30. package/dist/adapter/paper/engine/paper-engine.spec.js +54 -0
  31. package/dist/adapter/paper/engine/paper-engine.spec.js.map +1 -0
  32. package/dist/adapter/paper/index.d.ts +1 -2
  33. package/dist/adapter/paper/index.js +1 -2
  34. package/dist/adapter/paper/index.js.map +1 -1
  35. package/dist/adapter/paper/paper-adapter.d.ts +7 -7
  36. package/dist/adapter/paper/paper-adapter.js +20 -18
  37. package/dist/adapter/paper/paper-adapter.js.map +1 -1
  38. package/dist/adapter/paper/paper-adapter.spec.js +35 -17
  39. package/dist/adapter/paper/paper-adapter.spec.js.map +1 -1
  40. package/dist/bootstrap.js +11 -10
  41. package/dist/bootstrap.js.map +1 -1
  42. package/dist/cli/pull.js +3 -1
  43. package/dist/cli/pull.js.map +1 -1
  44. package/dist/cli/test.js +5 -1
  45. package/dist/cli/test.js.map +1 -1
  46. package/dist/domain/asset.d.ts +6 -5
  47. package/dist/domain/asset.js +22 -16
  48. package/dist/domain/asset.js.map +1 -1
  49. package/dist/domain/asset.spec.js +32 -32
  50. package/dist/domain/asset.spec.js.map +1 -1
  51. package/dist/domain/balance.d.ts +7 -7
  52. package/dist/domain/balance.js +26 -21
  53. package/dist/domain/balance.js.map +1 -1
  54. package/dist/domain/balance.operator.d.ts +6 -0
  55. package/dist/domain/balance.operator.js +10 -0
  56. package/dist/domain/balance.operator.js.map +1 -0
  57. package/dist/{shared/policy.spec.d.ts → domain/balance.operator.spec.d.ts} +0 -0
  58. package/dist/domain/balance.operator.spec.js +23 -0
  59. package/dist/domain/balance.operator.spec.js.map +1 -0
  60. package/dist/domain/balance.spec.js +67 -7
  61. package/dist/domain/balance.spec.js.map +1 -1
  62. package/dist/domain/candle.d.ts +2 -17
  63. package/dist/domain/candle.js +3 -70
  64. package/dist/domain/candle.js.map +1 -1
  65. package/dist/domain/candle.operator.d.ts +9 -0
  66. package/dist/domain/candle.operator.js +64 -0
  67. package/dist/domain/candle.operator.js.map +1 -0
  68. package/dist/{shared/topic.spec.d.ts → domain/candle.operator.spec.d.ts} +0 -0
  69. package/dist/domain/candle.operator.spec.js +111 -0
  70. package/dist/domain/candle.operator.spec.js.map +1 -0
  71. package/dist/domain/candle.spec.js +11 -53
  72. package/dist/domain/candle.spec.js.map +1 -1
  73. package/dist/domain/commission.d.ts +4 -1
  74. package/dist/domain/commission.js +2 -2
  75. package/dist/domain/commission.js.map +1 -1
  76. package/dist/{store/event/store-balance.event.spec.d.ts → domain/commission.spec.d.ts} +0 -0
  77. package/dist/domain/commission.spec.js +30 -0
  78. package/dist/domain/commission.spec.js.map +1 -0
  79. package/dist/domain/component.d.ts +1 -0
  80. package/dist/domain/error.d.ts +5 -0
  81. package/dist/domain/error.js +24 -0
  82. package/dist/domain/error.js.map +1 -0
  83. package/dist/domain/index.d.ts +8 -1
  84. package/dist/domain/index.js +8 -1
  85. package/dist/domain/index.js.map +1 -1
  86. package/dist/domain/instrument.d.ts +3 -2
  87. package/dist/domain/instrument.js +17 -9
  88. package/dist/domain/instrument.js.map +1 -1
  89. package/dist/domain/instrument.operator.d.ts +6 -0
  90. package/dist/domain/instrument.operator.js +14 -0
  91. package/dist/domain/instrument.operator.js.map +1 -0
  92. package/dist/{store/event/store-candle.event.spec.d.ts → domain/instrument.operator.spec.d.ts} +0 -0
  93. package/dist/domain/instrument.operator.spec.js +24 -0
  94. package/dist/domain/instrument.operator.spec.js.map +1 -0
  95. package/dist/domain/instrument.spec.js +22 -30
  96. package/dist/domain/instrument.spec.js.map +1 -1
  97. package/dist/domain/order.d.ts +12 -14
  98. package/dist/domain/order.js +37 -26
  99. package/dist/domain/order.js.map +1 -1
  100. package/dist/domain/order.operator.d.ts +7 -0
  101. package/dist/domain/order.operator.js +14 -0
  102. package/dist/domain/order.operator.js.map +1 -0
  103. package/dist/{store/event/store-instrument.event.spec.d.ts → domain/order.operator.spec.d.ts} +0 -0
  104. package/dist/domain/order.operator.spec.js +64 -0
  105. package/dist/domain/order.operator.spec.js.map +1 -0
  106. package/dist/{store/event/store-order.event.spec.d.ts → domain/order.spec.d.ts} +0 -0
  107. package/dist/domain/order.spec.js +33 -0
  108. package/dist/domain/order.spec.js.map +1 -0
  109. package/dist/domain/orderbook.d.ts +1 -0
  110. package/dist/domain/orderbook.js +1 -0
  111. package/dist/domain/orderbook.js.map +1 -1
  112. package/dist/domain/orderbook.operator.d.ts +6 -0
  113. package/dist/domain/orderbook.operator.js +10 -0
  114. package/dist/domain/orderbook.operator.js.map +1 -0
  115. package/dist/{store/event/store-trade.event.spec.d.ts → domain/orderbook.operator.spec.d.ts} +0 -0
  116. package/dist/domain/orderbook.operator.spec.js +22 -0
  117. package/dist/domain/orderbook.operator.spec.js.map +1 -0
  118. package/dist/domain/orderbook.spec.d.ts +1 -0
  119. package/dist/domain/orderbook.spec.js +13 -0
  120. package/dist/domain/orderbook.spec.js.map +1 -0
  121. package/dist/domain/position.d.ts +6 -11
  122. package/dist/domain/position.js +9 -31
  123. package/dist/domain/position.js.map +1 -1
  124. package/dist/domain/position.operator.d.ts +10 -0
  125. package/dist/domain/position.operator.js +38 -0
  126. package/dist/domain/position.operator.js.map +1 -0
  127. package/dist/domain/position.operator.spec.d.ts +1 -0
  128. package/dist/domain/position.operator.spec.js +48 -0
  129. package/dist/domain/position.operator.spec.js.map +1 -0
  130. package/dist/domain/position.spec.js +21 -17
  131. package/dist/domain/position.spec.js.map +1 -1
  132. package/dist/domain/session.d.ts +15 -18
  133. package/dist/domain/session.js +21 -31
  134. package/dist/domain/session.js.map +1 -1
  135. package/dist/domain/session.spec.js +1 -1
  136. package/dist/domain/session.spec.js.map +1 -1
  137. package/dist/domain/trade.d.ts +1 -0
  138. package/dist/domain/trade.js +1 -0
  139. package/dist/domain/trade.js.map +1 -1
  140. package/dist/domain/trade.operator.d.ts +6 -0
  141. package/dist/domain/trade.operator.js +10 -0
  142. package/dist/domain/trade.operator.js.map +1 -0
  143. package/dist/domain/trade.operator.spec.d.ts +1 -0
  144. package/dist/domain/trade.operator.spec.js +24 -0
  145. package/dist/domain/trade.operator.spec.js.map +1 -0
  146. package/dist/domain/trade.spec.d.ts +1 -0
  147. package/dist/domain/trade.spec.js +13 -0
  148. package/dist/domain/trade.spec.js.map +1 -0
  149. package/dist/indicator/cross.spec.js +2 -2
  150. package/dist/indicator/cross.spec.js.map +1 -1
  151. package/dist/indicator/ema.spec.js +1 -1
  152. package/dist/indicator/ema.spec.js.map +1 -1
  153. package/dist/indicator/sma.spec.js +1 -1
  154. package/dist/indicator/sma.spec.js.map +1 -1
  155. package/dist/indicator/tma.spec.js +1 -1
  156. package/dist/indicator/tma.spec.js.map +1 -1
  157. package/dist/indicator/trailing.spec.js +2 -2
  158. package/dist/indicator/trailing.spec.js.map +1 -1
  159. package/dist/indicator/truerange.spec.js +1 -1
  160. package/dist/indicator/truerange.spec.js.map +1 -1
  161. package/dist/indicator/wma.spec.js +1 -1
  162. package/dist/indicator/wma.spec.js.map +1 -1
  163. package/dist/shared/collections.d.ts +10 -0
  164. package/dist/shared/collections.js +33 -0
  165. package/dist/shared/collections.js.map +1 -0
  166. package/dist/shared/datetime.d.ts +0 -1
  167. package/dist/shared/datetime.js +1 -12
  168. package/dist/shared/datetime.js.map +1 -1
  169. package/dist/shared/decimals.d.ts +1 -1
  170. package/dist/shared/decimals.js +4 -5
  171. package/dist/shared/decimals.js.map +1 -1
  172. package/dist/shared/decimals.spec.js +2 -1
  173. package/dist/shared/decimals.spec.js.map +1 -1
  174. package/dist/shared/index.d.ts +1 -1
  175. package/dist/shared/index.js +1 -1
  176. package/dist/shared/index.js.map +1 -1
  177. package/dist/shared/io.js.map +1 -1
  178. package/dist/shared/policy.d.ts +0 -1
  179. package/dist/shared/policy.js +1 -11
  180. package/dist/shared/policy.js.map +1 -1
  181. package/dist/storage/cache.js +1 -1
  182. package/dist/storage/cache.js.map +1 -1
  183. package/dist/storage/cache.spec.d.ts +1 -0
  184. package/dist/storage/cache.spec.js +18 -0
  185. package/dist/storage/cache.spec.js.map +1 -0
  186. package/dist/storage/feed.d.ts +3 -4
  187. package/dist/storage/feed.js +16 -6
  188. package/dist/storage/feed.js.map +1 -1
  189. package/dist/storage/storage.d.ts +2 -7
  190. package/dist/storage/storage.js +6 -11
  191. package/dist/storage/storage.js.map +1 -1
  192. package/dist/store/index.d.ts +8 -2
  193. package/dist/store/index.js +8 -2
  194. package/dist/store/index.js.map +1 -1
  195. package/dist/store/store-balance.event.d.ts +33 -0
  196. package/dist/store/store-balance.event.js +90 -0
  197. package/dist/store/store-balance.event.js.map +1 -0
  198. package/dist/store/store-balance.event.spec.d.ts +1 -0
  199. package/dist/store/{event/store-balance.event.spec.js → store-balance.event.spec.js} +7 -7
  200. package/dist/store/store-balance.event.spec.js.map +1 -0
  201. package/dist/store/{event/store-instrument.event.d.ts → store-instrument.event.d.ts} +5 -8
  202. package/dist/store/store-instrument.event.js +52 -0
  203. package/dist/store/store-instrument.event.js.map +1 -0
  204. package/dist/store/store-instrument.event.spec.d.ts +1 -0
  205. package/dist/store/store-instrument.event.spec.js +22 -0
  206. package/dist/store/store-instrument.event.spec.js.map +1 -0
  207. package/dist/store/store-order.event.d.ts +59 -0
  208. package/dist/store/store-order.event.js +181 -0
  209. package/dist/store/store-order.event.js.map +1 -0
  210. package/dist/store/store-order.event.spec.d.ts +1 -0
  211. package/dist/store/{event/store-order.event.spec.js → store-order.event.spec.js} +8 -8
  212. package/dist/store/store-order.event.spec.js.map +1 -0
  213. package/dist/store/{event/store-orderbook.event.d.ts → store-orderbook.event.d.ts} +4 -5
  214. package/dist/store/store-orderbook.event.js +42 -0
  215. package/dist/store/store-orderbook.event.js.map +1 -0
  216. package/dist/store/{event/store-position.event.d.ts → store-position.event.d.ts} +5 -7
  217. package/dist/store/store-position.event.js +77 -0
  218. package/dist/store/store-position.event.js.map +1 -0
  219. package/dist/store/store-state.d.ts +27 -0
  220. package/dist/store/store-state.js +29 -0
  221. package/dist/store/store-state.js.map +1 -0
  222. package/dist/store/{event/store-trade.event.d.ts → store-trade.event.d.ts} +4 -5
  223. package/dist/store/store-trade.event.js +25 -0
  224. package/dist/store/store-trade.event.js.map +1 -0
  225. package/dist/store/store-trade.event.spec.d.ts +1 -0
  226. package/dist/store/{event/store-trade.event.spec.js → store-trade.event.spec.js} +13 -13
  227. package/dist/store/store-trade.event.spec.js.map +1 -0
  228. package/dist/store/store.d.ts +4 -25
  229. package/dist/store/store.event.d.ts +6 -0
  230. package/dist/store/{event/store.event.js → store.event.js} +0 -0
  231. package/dist/store/store.event.js.map +1 -0
  232. package/dist/store/store.js +7 -195
  233. package/dist/store/store.js.map +1 -1
  234. package/dist/store/store.spec.d.ts +1 -0
  235. package/dist/store/store.spec.js +119 -0
  236. package/dist/store/store.spec.js.map +1 -0
  237. package/dist/tsconfig.tsbuildinfo +1 -1
  238. package/{jestconfig.unit.json → jestconfig.json} +1 -2
  239. package/package.json +2 -6
  240. package/src/adapter/adapter-aggregate.ts +27 -35
  241. package/src/adapter/adapter.ts +25 -54
  242. package/src/adapter/backtester/backtester-adapter.spec.ts +124 -0
  243. package/src/adapter/backtester/backtester-adapter.ts +28 -17
  244. package/src/adapter/backtester/backtester-cursor.spec.ts +18 -19
  245. package/src/adapter/backtester/backtester-cursor.ts +7 -7
  246. package/src/adapter/backtester/backtester-streamer.spec.ts +19 -19
  247. package/src/adapter/backtester/backtester-streamer.ts +50 -20
  248. package/src/adapter/error.ts +9 -0
  249. package/src/adapter/paper/engine/paper-engine.spec.ts +92 -0
  250. package/src/adapter/paper/engine/paper-engine.ts +135 -0
  251. package/src/adapter/paper/index.ts +1 -2
  252. package/src/adapter/paper/paper-adapter.spec.ts +55 -19
  253. package/src/adapter/paper/paper-adapter.ts +27 -24
  254. package/src/bootstrap.ts +26 -19
  255. package/src/cli/pull.ts +5 -1
  256. package/src/cli/test.ts +5 -2
  257. package/src/domain/asset.spec.ts +33 -29
  258. package/src/domain/asset.ts +27 -21
  259. package/src/domain/balance.operator.spec.ts +25 -0
  260. package/src/domain/balance.operator.ts +15 -0
  261. package/src/domain/balance.spec.ts +95 -7
  262. package/src/domain/balance.ts +35 -29
  263. package/src/domain/candle.operator.spec.ts +125 -0
  264. package/src/domain/candle.operator.ts +106 -0
  265. package/src/domain/candle.spec.ts +12 -68
  266. package/src/domain/candle.ts +2 -114
  267. package/src/domain/commission.spec.ts +33 -0
  268. package/src/domain/commission.ts +2 -2
  269. package/src/domain/component.ts +1 -0
  270. package/src/domain/error.ts +25 -0
  271. package/src/domain/index.ts +8 -1
  272. package/src/domain/instrument.operator.spec.ts +28 -0
  273. package/src/domain/instrument.operator.ts +25 -0
  274. package/src/domain/instrument.spec.ts +22 -30
  275. package/src/domain/instrument.ts +20 -11
  276. package/src/domain/order.operator.spec.ts +81 -0
  277. package/src/domain/order.operator.ts +23 -0
  278. package/src/domain/order.spec.ts +43 -0
  279. package/src/domain/order.ts +43 -46
  280. package/src/domain/orderbook.operator.spec.ts +28 -0
  281. package/src/domain/orderbook.operator.ts +15 -0
  282. package/src/domain/orderbook.spec.ts +17 -0
  283. package/src/domain/orderbook.ts +4 -1
  284. package/src/domain/position.operator.spec.ts +58 -0
  285. package/src/domain/position.operator.ts +61 -0
  286. package/src/domain/position.spec.ts +28 -24
  287. package/src/domain/position.ts +16 -48
  288. package/src/domain/session.spec.ts +1 -1
  289. package/src/domain/session.ts +41 -131
  290. package/src/domain/trade.operator.spec.ts +31 -0
  291. package/src/domain/trade.operator.ts +15 -0
  292. package/src/domain/trade.spec.ts +17 -0
  293. package/src/domain/trade.ts +4 -1
  294. package/src/indicator/cross.spec.ts +2 -2
  295. package/src/indicator/ema.spec.ts +1 -1
  296. package/src/indicator/sma.spec.ts +1 -1
  297. package/src/indicator/tma.spec.ts +1 -1
  298. package/src/indicator/trailing.spec.ts +2 -2
  299. package/src/indicator/truerange.spec.ts +1 -1
  300. package/src/indicator/wma.spec.ts +1 -1
  301. package/src/shared/collections.ts +35 -0
  302. package/src/shared/datetime.ts +0 -12
  303. package/src/shared/decimals.spec.ts +2 -1
  304. package/src/shared/decimals.ts +6 -6
  305. package/src/shared/index.ts +1 -1
  306. package/src/shared/io.ts +0 -2
  307. package/src/shared/policy.ts +0 -13
  308. package/src/storage/cache.spec.ts +18 -0
  309. package/src/storage/cache.ts +1 -1
  310. package/src/storage/feed.ts +26 -16
  311. package/src/storage/storage.ts +9 -13
  312. package/src/store/index.ts +8 -2
  313. package/src/store/{event/store-balance.event.spec.ts → store-balance.event.spec.ts} +6 -6
  314. package/src/store/store-balance.event.ts +124 -0
  315. package/src/store/store-instrument.event.spec.ts +25 -0
  316. package/src/store/store-instrument.event.ts +72 -0
  317. package/src/store/store-order.event.spec.ts +28 -0
  318. package/src/store/store-order.event.ts +214 -0
  319. package/src/store/store-orderbook.event.ts +54 -0
  320. package/src/store/store-position.event.ts +102 -0
  321. package/src/store/store-state.ts +48 -0
  322. package/src/store/{event/store-trade.event.spec.ts → store-trade.event.spec.ts} +14 -14
  323. package/src/store/store-trade.event.ts +36 -0
  324. package/src/store/store.event.ts +8 -0
  325. package/src/store/store.spec.ts +180 -0
  326. package/src/store/store.ts +10 -208
  327. package/dist/adapter/paper/simulator/paper-margin-simulator.d.ts +0 -10
  328. package/dist/adapter/paper/simulator/paper-margin-simulator.js +0 -69
  329. package/dist/adapter/paper/simulator/paper-margin-simulator.js.map +0 -1
  330. package/dist/adapter/paper/simulator/paper-simulator.d.ts +0 -16
  331. package/dist/adapter/paper/simulator/paper-simulator.js +0 -93
  332. package/dist/adapter/paper/simulator/paper-simulator.js.map +0 -1
  333. package/dist/adapter/paper/simulator/paper-spot-simulator.d.ts +0 -13
  334. package/dist/adapter/paper/simulator/paper-spot-simulator.js +0 -81
  335. package/dist/adapter/paper/simulator/paper-spot-simulator.js.map +0 -1
  336. package/dist/adapter/paper/simulator/paper-spot-simulator.spec.js +0 -49
  337. package/dist/adapter/paper/simulator/paper-spot-simulator.spec.js.map +0 -1
  338. package/dist/domain/statement.d.ts +0 -4
  339. package/dist/domain/statement.js +0 -87
  340. package/dist/domain/statement.js.map +0 -1
  341. package/dist/shared/policy.spec.js +0 -22
  342. package/dist/shared/policy.spec.js.map +0 -1
  343. package/dist/shared/topic.d.ts +0 -14
  344. package/dist/shared/topic.js +0 -40
  345. package/dist/shared/topic.js.map +0 -1
  346. package/dist/shared/topic.spec.js +0 -43
  347. package/dist/shared/topic.spec.js.map +0 -1
  348. package/dist/store/event/index.d.ts +0 -8
  349. package/dist/store/event/index.js +0 -25
  350. package/dist/store/event/index.js.map +0 -1
  351. package/dist/store/event/store-balance.event.d.ts +0 -37
  352. package/dist/store/event/store-balance.event.js +0 -119
  353. package/dist/store/event/store-balance.event.js.map +0 -1
  354. package/dist/store/event/store-balance.event.spec.js.map +0 -1
  355. package/dist/store/event/store-candle.event.d.ts +0 -18
  356. package/dist/store/event/store-candle.event.js +0 -63
  357. package/dist/store/event/store-candle.event.js.map +0 -1
  358. package/dist/store/event/store-candle.event.spec.js +0 -23
  359. package/dist/store/event/store-candle.event.spec.js.map +0 -1
  360. package/dist/store/event/store-instrument.event.js +0 -78
  361. package/dist/store/event/store-instrument.event.js.map +0 -1
  362. package/dist/store/event/store-instrument.event.spec.js +0 -21
  363. package/dist/store/event/store-instrument.event.spec.js.map +0 -1
  364. package/dist/store/event/store-order.event.d.ts +0 -61
  365. package/dist/store/event/store-order.event.js +0 -205
  366. package/dist/store/event/store-order.event.js.map +0 -1
  367. package/dist/store/event/store-order.event.spec.js.map +0 -1
  368. package/dist/store/event/store-orderbook.event.js +0 -65
  369. package/dist/store/event/store-orderbook.event.js.map +0 -1
  370. package/dist/store/event/store-position.event.js +0 -97
  371. package/dist/store/event/store-position.event.js.map +0 -1
  372. package/dist/store/event/store-trade.event.js +0 -47
  373. package/dist/store/event/store-trade.event.js.map +0 -1
  374. package/dist/store/event/store-trade.event.spec.js.map +0 -1
  375. package/dist/store/event/store.event.d.ts +0 -5
  376. package/dist/store/event/store.event.js.map +0 -1
  377. package/dist/store/store.state.d.ts +0 -21
  378. package/dist/store/store.state.js +0 -21
  379. package/dist/store/store.state.js.map +0 -1
  380. package/dist/tests/backtester-adapter.spec.js +0 -61
  381. package/dist/tests/backtester-adapter.spec.js.map +0 -1
  382. package/dist/tests/session.spec.d.ts +0 -0
  383. package/dist/tests/session.spec.js +0 -1
  384. package/dist/tests/session.spec.js.map +0 -1
  385. package/jestconfig.integration.json +0 -12
  386. package/src/adapter/paper/simulator/paper-margin-simulator.ts +0 -108
  387. package/src/adapter/paper/simulator/paper-simulator.ts +0 -121
  388. package/src/adapter/paper/simulator/paper-spot-simulator.spec.ts +0 -87
  389. package/src/adapter/paper/simulator/paper-spot-simulator.ts +0 -134
  390. package/src/domain/statement.ts +0 -119
  391. package/src/shared/policy.spec.ts +0 -25
  392. package/src/shared/topic.spec.ts +0 -34
  393. package/src/shared/topic.ts +0 -43
  394. package/src/store/event/index.ts +0 -8
  395. package/src/store/event/store-balance.event.ts +0 -161
  396. package/src/store/event/store-candle.event.spec.ts +0 -30
  397. package/src/store/event/store-candle.event.ts +0 -71
  398. package/src/store/event/store-instrument.event.spec.ts +0 -25
  399. package/src/store/event/store-instrument.event.ts +0 -84
  400. package/src/store/event/store-order.event.spec.ts +0 -28
  401. package/src/store/event/store-order.event.ts +0 -218
  402. package/src/store/event/store-orderbook.event.ts +0 -70
  403. package/src/store/event/store-position.event.ts +0 -109
  404. package/src/store/event/store-trade.event.ts +0 -52
  405. package/src/store/event/store.event.ts +0 -6
  406. package/src/store/store.state.ts +0 -43
  407. package/src/tests/backtester-adapter.spec.ts +0 -88
  408. package/src/tests/session.spec.ts +0 -121
package/src/cli/pull.ts CHANGED
@@ -40,10 +40,12 @@ export default async function (name: string, instrument: string, options: any) {
40
40
  );
41
41
  }
42
42
 
43
+ console.time('Pulling completed in');
44
+
43
45
  await session.awake(undefined);
44
46
 
45
47
  const bar = new SingleBar({}, Presets.shades_classic);
46
- const feed = new Feed(module.descriptor.storage.create('feed'));
48
+ const feed = new Feed(module.descriptor.storage('feed'));
47
49
 
48
50
  bar.start(100, 0);
49
51
 
@@ -64,4 +66,6 @@ export default async function (name: string, instrument: string, options: any) {
64
66
  bar.stop();
65
67
 
66
68
  await session.dispose();
69
+
70
+ console.timeLog('Pulling completed in');
67
71
  }
package/src/cli/test.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { BacktesterStreamer } from '../adapter';
2
1
  import { Bootstrap } from '../bootstrap';
3
2
  import build from './build';
4
3
  import { getModule } from './internal/workspace';
@@ -36,10 +35,14 @@ export default async function (name, options: any) {
36
35
 
37
36
  await new Promise<void>(async resolve => {
38
37
  const [session] = bootstrap.useBacktestPeriod(from, to).backtest({
38
+ onBacktestStarted: () => {
39
+ console.log('backtest started');
40
+ console.time('backtest completed');
41
+ },
39
42
  onBacktestCompleted: async () => {
40
43
  await session.dispose();
41
44
 
42
- console.log('backtest completed.');
45
+ console.timeEnd('backtest completed');
43
46
 
44
47
  resolve();
45
48
  }
@@ -1,66 +1,70 @@
1
1
  import { Asset, assetOf } from './asset';
2
2
 
3
- describe('asset tests', () => {
4
- test('should instantiate proper asset', () => {
3
+ describe('Asset', () => {
4
+ test('should construct a new asset', () => {
5
5
  const sut = new Asset('abc', 'xyz', 4);
6
6
 
7
7
  expect(sut.name).toEqual('abc');
8
- expect(sut.adapter).toEqual('xyz');
8
+ expect(sut.adapterName).toEqual('xyz');
9
9
  expect(sut.scale).toEqual(4);
10
10
  expect(sut.tickSize).toEqual(0.0001);
11
11
  expect(sut.fixed(1.1234567)).toEqual(1.1234);
12
12
  expect(sut.floor(1.1234567)).toEqual(1.1234);
13
13
  expect(sut.ceil(1.1234567)).toEqual(1.1235);
14
- expect(sut.toString()).toEqual('xyz:abc');
14
+ expect(sut.id).toEqual('xyz:abc');
15
+ });
16
+
17
+ test('should throw for missing asset name', () => {
18
+ const fn = () => new Asset('xyz', '', 5);
19
+
20
+ expect(fn).toThrowError();
21
+ });
22
+
23
+ test('should throw for missing adapter name', () => {
24
+ const fn = () => new Asset('', 'xyz', 5);
25
+
26
+ expect(fn).toThrowError();
15
27
  });
16
28
  });
17
29
 
18
- describe('asset selector tests', () => {
19
- test('should instantiate proper asset selector', () => {
30
+ describe('AssetSelector', () => {
31
+ test('should construct a new asset selector from unified string', () => {
20
32
  const sut = assetOf('xyz:abc');
21
33
 
22
34
  expect(sut.name).toEqual('abc');
23
- expect(sut.adapter).toEqual('xyz');
24
- expect(sut.toString()).toEqual('xyz:abc');
35
+ expect(sut.adapterName).toEqual('xyz');
36
+ expect(sut.id).toEqual('xyz:abc');
25
37
  });
26
38
 
27
39
  test('should instantiate proper asset selector capital case', () => {
28
40
  const sut = assetOf('XYZ:ABC');
29
41
 
30
42
  expect(sut.name).toEqual('abc');
31
- expect(sut.adapter).toEqual('xyz');
32
- expect(sut.toString()).toEqual('xyz:abc');
43
+ expect(sut.adapterName).toEqual('xyz');
44
+ expect(sut.id).toEqual('xyz:abc');
33
45
  });
34
46
 
35
47
  test('should throw invalid format message for missing separator', () => {
36
- const fn = () => {
37
- assetOf('xyzabc');
38
- };
48
+ const fn = () => assetOf('xyzabc');
39
49
 
40
- expect(fn).toThrow(Error);
50
+ expect(fn).toThrowError();
41
51
  });
42
52
 
43
- test('should throw invalid format message for multiple separators', () => {
44
- const fn = () => {
45
- assetOf('xyz:abc:');
46
- };
53
+ test('should throw for multiple separators', () => {
54
+ const fn = () => assetOf('xyz:abc:');
47
55
 
48
- expect(fn).toThrow(Error);
56
+ expect(fn).toThrowError();
49
57
  });
50
58
 
51
- test('should throw invalid format message for missing asset name', () => {
52
- const fn = () => {
53
- assetOf('xyz:');
54
- };
59
+ test('should throw for missing asset name', () => {
60
+ const fn = () => assetOf('xyz:');
55
61
 
56
- expect(fn).toThrow(Error);
62
+ expect(fn).toThrowError();
57
63
  });
58
64
 
59
- test('should throw invalid format message for missing adapter name', () => {
60
- const fn = () => {
61
- assetOf(':abc');
62
- };
65
+ test('should throw for missing adapter name', () => {
66
+ const fn = () => assetOf(':abc');
63
67
 
64
- expect(fn).toThrow(Error);
68
+ expect(fn).toThrowError();
65
69
  });
66
70
  });
@@ -1,19 +1,28 @@
1
1
  import { ceil, fixed, floor } from '../shared/decimals';
2
+ import { invalidArgumentError, invalidAssetSelectorError } from './error';
3
+
4
+ export const AssetSelectorSeparator = ':';
2
5
 
3
6
  /**
4
7
  * Supposed to query specific @see Asset from based on string notation.
5
8
  */
6
9
  export class AssetSelector {
7
- private readonly id: string;
8
-
10
+ readonly id: string;
9
11
  readonly name: string;
10
- readonly adapter: string;
12
+ readonly adapterName: string;
11
13
 
12
- constructor(name: string, adapter: string) {
13
- this.name = name.toLowerCase();
14
- this.adapter = adapter.toLowerCase();
14
+ constructor(name: string, adapterName: string) {
15
+ if (!name?.length) {
16
+ throw invalidArgumentError(name);
17
+ }
15
18
 
16
- this.id = `${this.adapter}:${this.name}`;
19
+ if (!adapterName?.length) {
20
+ throw invalidArgumentError(adapterName);
21
+ }
22
+
23
+ this.name = name.toLowerCase();
24
+ this.adapterName = adapterName.toLowerCase();
25
+ this.id = `${this.adapterName}${AssetSelectorSeparator}${this.name}`;
17
26
  }
18
27
 
19
28
  /**
@@ -27,21 +36,14 @@ export class AssetSelector {
27
36
  /**
28
37
  * Creates @see AssetSelector based on unified string notation.
29
38
  */
30
- export function assetOf(asset: string): AssetSelector {
31
- const section = asset.split(':');
39
+ export function assetOf(selector: string): AssetSelector {
40
+ const [adapterName, name, ...rest] = selector.split(AssetSelectorSeparator);
32
41
 
33
- if (section.length != 2) {
34
- throw Error('invalid asset format');
42
+ if (!adapterName || !name || rest.length) {
43
+ throw invalidAssetSelectorError(selector);
35
44
  }
36
45
 
37
- const assetName = section[1];
38
- const adapterName = section[0];
39
-
40
- if (assetName.length == 0 || adapterName.length == 0) {
41
- throw Error('invalid asset format');
42
- }
43
-
44
- return new AssetSelector(assetName, adapterName);
46
+ return new AssetSelector(name, adapterName);
45
47
  }
46
48
 
47
49
  /**
@@ -51,8 +53,12 @@ export function assetOf(asset: string): AssetSelector {
51
53
  export class Asset extends AssetSelector {
52
54
  readonly tickSize: number;
53
55
 
54
- constructor(name: string, adapter: string, public readonly scale: number) {
55
- super(name, adapter);
56
+ constructor(name: string, adapterName: string, public readonly scale: number) {
57
+ super(name, adapterName);
58
+
59
+ if (scale && (scale < 0 || Number.isNaN(scale))) {
60
+ throw invalidArgumentError(scale);
61
+ }
56
62
 
57
63
  this.tickSize = 1.0 / Math.pow(10, this.scale);
58
64
  }
@@ -0,0 +1,25 @@
1
+ import { Subject } from 'rxjs';
2
+
3
+ import { State } from '../store';
4
+ import { Asset } from './asset';
5
+ import { Balance } from './balance';
6
+ import { balance } from './balance.operator';
7
+ import { Component } from './component';
8
+
9
+ describe('balance', () => {
10
+ const asset = new Asset('abc', 'xyz', 4);
11
+ const state = new State();
12
+
13
+ beforeEach(() => {
14
+ state.balance.upsert(new Balance(asset));
15
+ });
16
+
17
+ test('should pipe a balance on subscription', done => {
18
+ new Subject<Component>().pipe(balance(asset, state)).subscribe({
19
+ next: it => {
20
+ expect(it.asset).toEqual(asset);
21
+ done();
22
+ }
23
+ });
24
+ });
25
+ });
@@ -0,0 +1,15 @@
1
+ import { filter, map, Observable, startWith } from 'rxjs';
2
+
3
+ import { State } from '../store';
4
+ import { AssetSelector } from './asset';
5
+ import { Balance } from './balance';
6
+ import { Component } from './component';
7
+
8
+ export function balance(selector: AssetSelector, state: State) {
9
+ return (source$: Observable<Component>) =>
10
+ source$.pipe(
11
+ startWith(state.balance.get(selector.id)),
12
+ filter(it => it instanceof Balance && (!selector || it.asset.id == selector.id)),
13
+ map(it => it as Balance)
14
+ );
15
+ }
@@ -1,24 +1,112 @@
1
1
  import { Asset } from './asset';
2
2
  import { Balance } from './balance';
3
+ import { Instrument } from './instrument';
4
+ import { Position } from './position';
3
5
 
4
- describe('balance tests', () => {
5
- test('should instantiate empty balance', () => {
6
- const sut = new Balance(new Asset('abc', 'xyz', 4));
6
+ describe('Balance', () => {
7
+ const asset = new Asset('abc', 'xyz', 4);
8
+ const instrument = new Instrument(
9
+ new Asset('abc', 'xyz', 4),
10
+ new Asset('def', 'xyz', 4),
11
+ 'abc-def'
12
+ );
7
13
 
8
- expect(sut.asset.toString()).toEqual('xyz:abc');
14
+ test('should construct empty balance', () => {
15
+ const sut = new Balance(asset);
16
+
17
+ expect(sut.asset.id).toEqual('xyz:abc');
9
18
  expect(sut.free).toEqual(0);
10
19
  expect(sut.locked).toEqual(0);
11
20
  expect(Object.keys(sut.position).length).toEqual(0);
12
21
  });
13
22
 
14
- test('should instantiate balance', () => {
15
- const sut = new Balance(new Asset('abc', 'xyz', 4));
23
+ test('should construct balance', () => {
24
+ const sut = new Balance(asset);
16
25
 
17
26
  sut.set(100, 50);
18
27
 
19
- expect(sut.asset.toString()).toEqual('xyz:abc');
28
+ expect(sut.asset.id).toEqual('xyz:abc');
20
29
  expect(sut.free).toEqual(100);
21
30
  expect(sut.locked).toEqual(50);
31
+ expect(sut.total).toEqual(150);
22
32
  expect(Object.keys(sut.position).length).toEqual(0);
23
33
  });
34
+
35
+ test('should account positive amount', () => {
36
+ const sut = new Balance(asset);
37
+
38
+ sut.set(100, 0);
39
+ sut.account(10);
40
+
41
+ expect(sut.free).toEqual(110);
42
+ expect(sut.locked).toEqual(0);
43
+ expect(sut.total).toEqual(110);
44
+ });
45
+
46
+ test('should account negative amount', () => {
47
+ const sut = new Balance(asset);
48
+
49
+ sut.set(100, 0);
50
+ sut.account(-10);
51
+
52
+ expect(sut.free).toEqual(90);
53
+ expect(sut.locked).toEqual(0);
54
+ expect(sut.total).toEqual(90);
55
+ });
56
+
57
+ test('should throw for insufficient balance account amount', () => {
58
+ const sut = new Balance(asset);
59
+
60
+ sut.set(100, 0);
61
+ const fn = () => sut.account(-120);
62
+
63
+ expect(fn).toThrowError();
64
+ });
65
+
66
+ test('should lock specific amount of available balance', () => {
67
+ const sut = new Balance(asset);
68
+
69
+ sut.set(100, 0);
70
+ sut.lock('key', 10);
71
+
72
+ expect(sut.free).toEqual(90);
73
+ expect(sut.locked).toEqual(10);
74
+ expect(sut.total).toEqual(100);
75
+ });
76
+
77
+ test('should throw for lock insufficient amount of available balance', () => {
78
+ const sut = new Balance(asset);
79
+
80
+ sut.set(30, 50);
81
+ const fn = () => sut.lock('key', 100);
82
+
83
+ expect(fn).toThrowError();
84
+ });
85
+
86
+ test('should lock an unlock specific amount of available balance', () => {
87
+ const sut = new Balance(asset);
88
+
89
+ sut.set(100, 0);
90
+ sut.lock('key', 40);
91
+ sut.tryUnlock('key');
92
+
93
+ expect(sut.free).toEqual(100);
94
+ expect(sut.locked).toEqual(0);
95
+ expect(sut.total).toEqual(100);
96
+ });
97
+
98
+ test('should return correct estimated unrealized pnl', () => {
99
+ const position = new Position('1', instrument, 'CROSS', 2511.81, 10.31, 20);
100
+
101
+ position.calculateEstimatedUnrealizedPnL(2576.44);
102
+
103
+ const sut = new Balance(asset);
104
+
105
+ sut.set(100, 0);
106
+ sut.position['1'] = position;
107
+
108
+ expect(sut.getEstimatedUnrealizedPnL()).toEqual(0.2652);
109
+ expect(sut.free).toEqual(100 + 0.2652);
110
+ expect(sut.total).toEqual(100 + 0.2652);
111
+ });
24
112
  });
@@ -1,17 +1,18 @@
1
1
  import { timestamp } from '../shared';
2
2
  import { Asset } from './';
3
3
  import { Component } from './component';
4
+ import { insufficientFundsError, invalidArgumentError } from './error';
4
5
  import { Position, PositionMode } from './position';
5
6
 
6
7
  /**
7
8
  * Represents single asset balance in your wallet.
8
9
  */
9
10
  export class Balance implements Component {
11
+ id: string;
10
12
  kind = 'balance';
11
13
  timestamp: timestamp;
12
14
 
13
- readonly maintenanceMarginRate = 1;
14
-
15
+ private locker: Record<string, number> = {};
15
16
  private available = 0;
16
17
  private unavailable = 0;
17
18
 
@@ -19,11 +20,7 @@ export class Balance implements Component {
19
20
  * Returns available amount to trade.
20
21
  */
21
22
  get free(): number {
22
- return (
23
- this.available +
24
- this.getEstimatedUnrealizedPnL('CROSS') -
25
- this.getEstimatedMaintenanceMargin('CROSS')
26
- );
23
+ return this.asset.fixed(this.available) + this.getEstimatedUnrealizedPnL('CROSS');
27
24
  }
28
25
 
29
26
  /**
@@ -39,56 +36,69 @@ export class Balance implements Component {
39
36
  */
40
37
  get total(): number {
41
38
  return (
42
- this.available + this.unavailable + this.getEstimatedUnrealizedPnL() /* +
43
- this.getEstimatedMaintenanceMargin()*/
39
+ this.asset.fixed(this.available + this.unavailable) +
40
+ this.getEstimatedUnrealizedPnL()
44
41
  );
45
42
  }
46
43
 
47
44
  /**
48
45
  * Collection of opened positions backed by this balance.
49
46
  */
50
- position: Record<string, Position> = {};
47
+ readonly position: Record<string, Position> = {};
51
48
 
52
- constructor(public readonly asset: Asset) {}
49
+ constructor(public readonly asset: Asset) {
50
+ this.id = asset.id;
51
+ }
53
52
 
54
- transact(amount: number) {
53
+ account(amount: number) {
55
54
  if (this.available + amount < 0) {
56
- throw new Error(`invalid balance amount has: ${this.available} wants: ${amount}`);
55
+ throw insufficientFundsError(this.id, amount, this.available);
57
56
  }
58
57
 
59
58
  this.available += amount;
60
59
  }
61
60
 
62
- set(free: number, freezed: number) {
63
- if (free != null) {
64
- this.available = free;
65
- }
66
-
67
- if (freezed != null) {
68
- this.unavailable = freezed;
69
- }
61
+ set(free: number, locked: number) {
62
+ this.available = free;
63
+ this.unavailable = locked;
64
+ this.locker = {};
70
65
  }
71
66
 
72
67
  /**
73
68
  * Lock specific amount of asset.
74
69
  * If you place new pending order, you will lock your balance to fund order.
75
70
  */
76
- freez(amount: number) {
71
+ lock(id: string, amount: number) {
77
72
  if (this.available < amount) {
78
- throw new Error(`insufficient funds has: ${this.available} wants: ${amount}`);
73
+ throw insufficientFundsError(this.id, amount, this.available);
74
+ }
75
+
76
+ if (this.locker[id]) {
77
+ throw invalidArgumentError(id);
79
78
  }
80
79
 
80
+ this.locker[id] = amount;
81
81
  this.available -= amount;
82
82
  this.unavailable += amount;
83
83
  }
84
84
 
85
- unfreez(amount: number) {
85
+ tryUnlock(id: string): boolean {
86
+ if (!this.locker[id]) {
87
+ return false;
88
+ }
89
+
90
+ const amount = this.locker[id];
91
+
92
+ delete this.locker[id];
93
+
86
94
  if (this.unavailable < amount) {
87
- throw new Error(`insufficient funds has: ${this.unavailable} wants: ${amount}`);
95
+ throw insufficientFundsError(this.id, amount, this.unavailable);
88
96
  }
89
97
 
90
98
  this.available += amount;
91
99
  this.unavailable -= amount;
100
+
101
+ return true;
92
102
  }
93
103
 
94
104
  /**
@@ -111,10 +121,6 @@ export class Balance implements Component {
111
121
  );
112
122
  }
113
123
 
114
- getEstimatedMaintenanceMargin(mode?: PositionMode): number {
115
- return this.getEstimatedMargin(mode) * this.maintenanceMarginRate;
116
- }
117
-
118
124
  toString() {
119
125
  return this.asset.toString();
120
126
  }
@@ -0,0 +1,125 @@
1
+ import { from } from 'rxjs';
2
+
3
+ import { Candle } from './candle';
4
+ import { candle, candleCompleted, mergeCandle } from './candle.operator';
5
+
6
+ describe('candle', () => {
7
+ test('should aggregate and pipe candle updates', done => {
8
+ 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 }
15
+ ]);
16
+
17
+ 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 }
24
+ ].reverse();
25
+
26
+ input$.pipe(candle(5, it => it.rate)).subscribe({
27
+ next: it => {
28
+ expect(it).toEqual(output.pop());
29
+ if (output.length === 0) {
30
+ done();
31
+ }
32
+ }
33
+ });
34
+ });
35
+ });
36
+
37
+ describe('candleCompleted', () => {
38
+ test('should aggregate and pipe distinct completed candles', done => {
39
+ 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 }
46
+ ]);
47
+
48
+ input$
49
+ .pipe(
50
+ candle(5, it => it.rate),
51
+ candleCompleted()
52
+ )
53
+ .subscribe({
54
+ next: it => {
55
+ expect(it).toEqual({ timestamp: 0, open: 1, high: 3, low: 0, close: 0 });
56
+ done();
57
+ }
58
+ });
59
+ });
60
+ });
61
+
62
+ describe('mergeCandle', () => {
63
+ test('should pipe and merge candle from history', done => {
64
+ 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)
68
+ ]);
69
+
70
+ const input$ = from([
71
+ { timestamp: 3, rate: 5 },
72
+ { timestamp: 4, rate: 3 },
73
+ { timestamp: 5, rate: 4 }
74
+ ]);
75
+
76
+ 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 }
82
+ ].reverse();
83
+
84
+ input$.pipe(mergeCandle(1, it => it.rate, history$)).subscribe({
85
+ next: it => {
86
+ expect(it).toEqual(output.pop());
87
+ if (output.length === 0) {
88
+ done();
89
+ }
90
+ }
91
+ });
92
+ });
93
+
94
+ test('should pipe and not merge candle from history', done => {
95
+ 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)
99
+ ]);
100
+
101
+ const input$ = from([
102
+ { timestamp: 4, rate: 5 },
103
+ { timestamp: 5, rate: 3 },
104
+ { timestamp: 6, rate: 4 }
105
+ ]);
106
+
107
+ 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 }
114
+ ].reverse();
115
+
116
+ input$.pipe(mergeCandle(1, it => it.rate, history$)).subscribe({
117
+ next: it => {
118
+ expect(it).toEqual(output.pop());
119
+ if (output.length === 0) {
120
+ done();
121
+ }
122
+ }
123
+ });
124
+ });
125
+ });