@quantform/core 0.5.13 → 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 (499) hide show
  1. package/dist/adapter/adapter-aggregate.d.ts +8 -5
  2. package/dist/adapter/adapter-aggregate.js +18 -20
  3. package/dist/adapter/adapter-aggregate.js.map +1 -1
  4. package/dist/adapter/adapter.d.ts +20 -32
  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 +11 -9
  8. package/dist/adapter/backtester/backtester-adapter.js +17 -16
  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 +83 -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 +19 -18
  17. package/dist/adapter/backtester/backtester-cursor.spec.js.map +1 -1
  18. package/dist/adapter/backtester/backtester-streamer.d.ts +3 -1
  19. package/dist/adapter/backtester/backtester-streamer.js +25 -14
  20. package/dist/adapter/backtester/backtester-streamer.js.map +1 -1
  21. package/dist/adapter/backtester/backtester-streamer.spec.js +17 -16
  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 +104 -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 +10 -9
  36. package/dist/adapter/paper/paper-adapter.js +26 -23
  37. package/dist/adapter/paper/paper-adapter.js.map +1 -1
  38. package/dist/adapter/paper/paper-adapter.spec.js +36 -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 +8 -11
  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 +10 -9
  47. package/dist/domain/asset.js +26 -23
  48. package/dist/domain/asset.js.map +1 -1
  49. package/dist/domain/asset.spec.js +36 -36
  50. package/dist/domain/asset.spec.js.map +1 -1
  51. package/dist/domain/balance.d.ts +13 -13
  52. package/dist/domain/balance.js +38 -32
  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/{indicator/truerange.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 +73 -12
  61. package/dist/domain/balance.spec.js.map +1 -1
  62. package/dist/domain/candle.d.ts +8 -23
  63. package/dist/domain/candle.js +6 -72
  64. package/dist/domain/candle.js.map +1 -1
  65. package/dist/domain/candle.operator.d.ts +10 -0
  66. package/dist/domain/candle.operator.js +64 -0
  67. package/dist/domain/candle.operator.js.map +1 -0
  68. package/dist/{shared/policy.spec.d.ts → domain/candle.operator.spec.d.ts} +0 -0
  69. package/dist/domain/candle.operator.spec.js +112 -0
  70. package/dist/domain/candle.operator.spec.js.map +1 -0
  71. package/dist/domain/candle.spec.js +16 -58
  72. package/dist/domain/candle.spec.js.map +1 -1
  73. package/dist/domain/commission.d.ts +12 -8
  74. package/dist/domain/commission.js +6 -6
  75. package/dist/domain/commission.js.map +1 -1
  76. package/dist/{shared/topic.spec.d.ts → domain/commission.spec.d.ts} +0 -0
  77. package/dist/domain/commission.spec.js +31 -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 +6 -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-balance.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 +16 -18
  98. package/dist/domain/order.js +39 -27
  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-candle.event.spec.d.ts → domain/order.operator.spec.d.ts} +0 -0
  104. package/dist/domain/order.operator.spec.js +65 -0
  105. package/dist/domain/order.operator.spec.js.map +1 -0
  106. package/dist/{store/event/store-instrument.event.spec.d.ts → domain/order.spec.d.ts} +0 -0
  107. package/dist/domain/order.spec.js +34 -0
  108. package/dist/domain/order.spec.js.map +1 -0
  109. package/dist/domain/orderbook.d.ts +19 -6
  110. package/dist/domain/orderbook.js +6 -4
  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-order.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/{store/event/store-trade.event.spec.d.ts → domain/orderbook.spec.d.ts} +0 -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 +9 -14
  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 +11 -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 +49 -0
  129. package/dist/domain/position.operator.spec.js.map +1 -0
  130. package/dist/domain/position.spec.js +22 -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 +2 -2
  136. package/dist/domain/session.spec.js.map +1 -1
  137. package/dist/domain/trade.d.ts +4 -3
  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/atr.d.ts +2 -1
  150. package/dist/indicator/atr.js +3 -3
  151. package/dist/indicator/atr.js.map +1 -1
  152. package/dist/indicator/cross.d.ts +3 -2
  153. package/dist/indicator/cross.js +13 -13
  154. package/dist/indicator/cross.js.map +1 -1
  155. package/dist/indicator/cross.spec.js +23 -22
  156. package/dist/indicator/cross.spec.js.map +1 -1
  157. package/dist/indicator/donchian.d.ts +3 -2
  158. package/dist/indicator/donchian.js.map +1 -1
  159. package/dist/indicator/drawdown.d.ts +2 -1
  160. package/dist/indicator/drawdown.js +3 -2
  161. package/dist/indicator/drawdown.js.map +1 -1
  162. package/dist/indicator/ema.d.ts +2 -1
  163. package/dist/indicator/ema.js +3 -2
  164. package/dist/indicator/ema.js.map +1 -1
  165. package/dist/indicator/ema.spec.js +4 -3
  166. package/dist/indicator/ema.spec.js.map +1 -1
  167. package/dist/indicator/envelope.d.ts +4 -3
  168. package/dist/indicator/envelope.js +4 -4
  169. package/dist/indicator/envelope.js.map +1 -1
  170. package/dist/indicator/index.d.ts +1 -1
  171. package/dist/indicator/index.js +1 -1
  172. package/dist/indicator/index.js.map +1 -1
  173. package/dist/indicator/macd.d.ts +2 -1
  174. package/dist/indicator/macd.js +1 -1
  175. package/dist/indicator/macd.js.map +1 -1
  176. package/dist/indicator/min-max.d.ts +4 -3
  177. package/dist/indicator/min-max.js +5 -4
  178. package/dist/indicator/min-max.js.map +1 -1
  179. package/dist/indicator/rma.d.ts +2 -1
  180. package/dist/indicator/rma.js +3 -2
  181. package/dist/indicator/rma.js.map +1 -1
  182. package/dist/indicator/sma.d.ts +2 -1
  183. package/dist/indicator/sma.js +4 -6
  184. package/dist/indicator/sma.js.map +1 -1
  185. package/dist/indicator/sma.spec.js +4 -3
  186. package/dist/indicator/sma.spec.js.map +1 -1
  187. package/dist/indicator/swma.d.ts +2 -1
  188. package/dist/indicator/swma.js +5 -1
  189. package/dist/indicator/swma.js.map +1 -1
  190. package/dist/indicator/tma.d.ts +2 -1
  191. package/dist/indicator/tma.js.map +1 -1
  192. package/dist/indicator/tma.spec.js +4 -3
  193. package/dist/indicator/tma.spec.js.map +1 -1
  194. package/dist/indicator/trailing.d.ts +8 -7
  195. package/dist/indicator/trailing.js +12 -11
  196. package/dist/indicator/trailing.js.map +1 -1
  197. package/dist/indicator/trailing.spec.js +15 -14
  198. package/dist/indicator/trailing.spec.js.map +1 -1
  199. package/dist/indicator/true-range.d.ts +4 -0
  200. package/dist/indicator/true-range.js +20 -0
  201. package/dist/indicator/true-range.js.map +1 -0
  202. package/dist/indicator/true-range.spec.d.ts +1 -0
  203. package/dist/indicator/true-range.spec.js +28 -0
  204. package/dist/indicator/true-range.spec.js.map +1 -0
  205. package/dist/indicator/window.d.ts +1 -1
  206. package/dist/indicator/window.js +1 -1
  207. package/dist/indicator/window.js.map +1 -1
  208. package/dist/indicator/wma.d.ts +2 -1
  209. package/dist/indicator/wma.js +6 -5
  210. package/dist/indicator/wma.js.map +1 -1
  211. package/dist/indicator/wma.spec.js +4 -3
  212. package/dist/indicator/wma.spec.js.map +1 -1
  213. package/dist/shared/collections.d.ts +26 -0
  214. package/dist/shared/collections.js +115 -0
  215. package/dist/shared/collections.js.map +1 -0
  216. package/dist/shared/collections.spec.d.ts +1 -0
  217. package/dist/shared/collections.spec.js +28 -0
  218. package/dist/shared/collections.spec.js.map +1 -0
  219. package/dist/shared/datetime.d.ts +0 -1
  220. package/dist/shared/datetime.js +1 -12
  221. package/dist/shared/datetime.js.map +1 -1
  222. package/dist/shared/decimals.d.ts +15 -6
  223. package/dist/shared/decimals.js +22 -36
  224. package/dist/shared/decimals.js.map +1 -1
  225. package/dist/shared/decimals.spec.js +18 -22
  226. package/dist/shared/decimals.spec.js.map +1 -1
  227. package/dist/shared/index.d.ts +2 -1
  228. package/dist/shared/index.js +2 -1
  229. package/dist/shared/index.js.map +1 -1
  230. package/dist/shared/io.js.map +1 -1
  231. package/dist/shared/pipe.d.ts +4 -0
  232. package/dist/shared/pipe.js +9 -0
  233. package/dist/shared/pipe.js.map +1 -0
  234. package/dist/shared/policy.d.ts +0 -1
  235. package/dist/shared/policy.js +1 -11
  236. package/dist/shared/policy.js.map +1 -1
  237. package/dist/storage/cache.js +1 -1
  238. package/dist/storage/cache.js.map +1 -1
  239. package/dist/storage/cache.spec.d.ts +1 -0
  240. package/dist/storage/cache.spec.js +18 -0
  241. package/dist/storage/cache.spec.js.map +1 -0
  242. package/dist/storage/feed.d.ts +7 -4
  243. package/dist/storage/feed.js +55 -8
  244. package/dist/storage/feed.js.map +1 -1
  245. package/dist/storage/storage.d.ts +2 -7
  246. package/dist/storage/storage.js +6 -11
  247. package/dist/storage/storage.js.map +1 -1
  248. package/dist/store/index.d.ts +8 -2
  249. package/dist/store/index.js +8 -2
  250. package/dist/store/index.js.map +1 -1
  251. package/dist/store/store-balance.event.d.ts +33 -0
  252. package/dist/store/store-balance.event.js +90 -0
  253. package/dist/store/store-balance.event.js.map +1 -0
  254. package/dist/store/store-balance.event.spec.d.ts +1 -0
  255. package/dist/store/{event/store-balance.event.spec.js → store-balance.event.spec.js} +10 -10
  256. package/dist/store/store-balance.event.spec.js.map +1 -0
  257. package/dist/store/{event/store-instrument.event.d.ts → store-instrument.event.d.ts} +5 -8
  258. package/dist/store/store-instrument.event.js +52 -0
  259. package/dist/store/store-instrument.event.js.map +1 -0
  260. package/dist/store/store-instrument.event.spec.d.ts +1 -0
  261. package/dist/store/store-instrument.event.spec.js +22 -0
  262. package/dist/store/store-instrument.event.spec.js.map +1 -0
  263. package/dist/store/store-order.event.d.ts +59 -0
  264. package/dist/store/store-order.event.js +181 -0
  265. package/dist/store/store-order.event.js.map +1 -0
  266. package/dist/store/store-order.event.spec.d.ts +1 -0
  267. package/dist/store/{event/store-order.event.spec.js → store-order.event.spec.js} +8 -8
  268. package/dist/store/store-order.event.spec.js.map +1 -0
  269. package/dist/store/store-orderbook.event.d.ts +12 -0
  270. package/dist/store/store-orderbook.event.js +42 -0
  271. package/dist/store/store-orderbook.event.js.map +1 -0
  272. package/dist/store/store-orderbook.event.spec.d.ts +1 -0
  273. package/dist/store/store-orderbook.event.spec.js +28 -0
  274. package/dist/store/store-orderbook.event.spec.js.map +1 -0
  275. package/dist/store/store-position.event.d.ts +21 -0
  276. package/dist/store/store-position.event.js +89 -0
  277. package/dist/store/store-position.event.js.map +1 -0
  278. package/dist/store/store-state.d.ts +27 -0
  279. package/dist/store/store-state.js +29 -0
  280. package/dist/store/store-state.js.map +1 -0
  281. package/dist/store/store-trade.event.d.ts +12 -0
  282. package/dist/store/store-trade.event.js +25 -0
  283. package/dist/store/store-trade.event.js.map +1 -0
  284. package/dist/store/store-trade.event.spec.d.ts +1 -0
  285. package/dist/store/store-trade.event.spec.js +44 -0
  286. package/dist/store/store-trade.event.spec.js.map +1 -0
  287. package/dist/store/store.d.ts +4 -25
  288. package/dist/store/store.event.d.ts +6 -0
  289. package/dist/store/{event/store.event.js → store.event.js} +0 -0
  290. package/dist/store/store.event.js.map +1 -0
  291. package/dist/store/store.js +7 -195
  292. package/dist/store/store.js.map +1 -1
  293. package/dist/store/store.spec.d.ts +1 -0
  294. package/dist/store/store.spec.js +119 -0
  295. package/dist/store/store.spec.js.map +1 -0
  296. package/dist/tsconfig.tsbuildinfo +1 -1
  297. package/{jestconfig.unit.json → jestconfig.json} +2 -2
  298. package/package.json +4 -6
  299. package/src/adapter/adapter-aggregate.ts +39 -38
  300. package/src/adapter/adapter.ts +39 -71
  301. package/src/adapter/backtester/backtester-adapter.spec.ts +133 -0
  302. package/src/adapter/backtester/backtester-adapter.ts +41 -21
  303. package/src/adapter/backtester/backtester-cursor.spec.ts +19 -18
  304. package/src/adapter/backtester/backtester-cursor.ts +7 -7
  305. package/src/adapter/backtester/backtester-streamer.spec.ts +23 -22
  306. package/src/adapter/backtester/backtester-streamer.ts +28 -15
  307. package/src/adapter/error.ts +9 -0
  308. package/src/adapter/paper/engine/paper-engine.spec.ts +99 -0
  309. package/src/adapter/paper/engine/paper-engine.ts +142 -0
  310. package/src/adapter/paper/index.ts +1 -2
  311. package/src/adapter/paper/paper-adapter.spec.ts +65 -20
  312. package/src/adapter/paper/paper-adapter.ts +42 -27
  313. package/src/bootstrap.ts +26 -19
  314. package/src/cli/pull.ts +11 -6
  315. package/src/cli/test.ts +5 -2
  316. package/src/domain/asset.spec.ts +37 -33
  317. package/src/domain/asset.ts +33 -34
  318. package/src/domain/balance.operator.spec.ts +25 -0
  319. package/src/domain/balance.operator.ts +15 -0
  320. package/src/domain/balance.spec.ts +101 -12
  321. package/src/domain/balance.ts +57 -51
  322. package/src/domain/candle.operator.spec.ts +126 -0
  323. package/src/domain/candle.operator.ts +107 -0
  324. package/src/domain/candle.spec.ts +18 -73
  325. package/src/domain/candle.ts +9 -121
  326. package/src/domain/commission.spec.ts +34 -0
  327. package/src/domain/commission.ts +13 -11
  328. package/src/domain/component.ts +1 -0
  329. package/src/domain/error.ts +27 -0
  330. package/src/domain/index.ts +8 -1
  331. package/src/domain/instrument.operator.spec.ts +28 -0
  332. package/src/domain/instrument.operator.ts +25 -0
  333. package/src/domain/instrument.spec.ts +22 -30
  334. package/src/domain/instrument.ts +20 -11
  335. package/src/domain/order.operator.spec.ts +82 -0
  336. package/src/domain/order.operator.ts +23 -0
  337. package/src/domain/order.spec.ts +44 -0
  338. package/src/domain/order.ts +55 -55
  339. package/src/domain/orderbook.operator.spec.ts +28 -0
  340. package/src/domain/orderbook.operator.ts +15 -0
  341. package/src/domain/orderbook.spec.ts +17 -0
  342. package/src/domain/orderbook.ts +18 -9
  343. package/src/domain/position.operator.spec.ts +59 -0
  344. package/src/domain/position.operator.ts +64 -0
  345. package/src/domain/position.spec.ts +28 -23
  346. package/src/domain/position.ts +17 -49
  347. package/src/domain/session.spec.ts +4 -4
  348. package/src/domain/session.ts +42 -134
  349. package/src/domain/trade.operator.spec.ts +31 -0
  350. package/src/domain/trade.operator.ts +15 -0
  351. package/src/domain/trade.spec.ts +17 -0
  352. package/src/domain/trade.ts +7 -4
  353. package/src/indicator/atr.ts +6 -5
  354. package/src/indicator/cross.spec.ts +33 -48
  355. package/src/indicator/cross.ts +18 -10
  356. package/src/indicator/donchian.ts +5 -4
  357. package/src/indicator/drawdown.ts +7 -5
  358. package/src/indicator/ema.spec.ts +5 -4
  359. package/src/indicator/ema.ts +7 -6
  360. package/src/indicator/envelope.ts +11 -6
  361. package/src/indicator/index.ts +1 -1
  362. package/src/indicator/macd.ts +5 -4
  363. package/src/indicator/min-max.ts +10 -7
  364. package/src/indicator/rma.ts +7 -6
  365. package/src/indicator/sma.spec.ts +5 -4
  366. package/src/indicator/sma.ts +9 -8
  367. package/src/indicator/swma.ts +8 -4
  368. package/src/indicator/tma.spec.ts +5 -4
  369. package/src/indicator/tma.ts +4 -3
  370. package/src/indicator/trailing.spec.ts +29 -16
  371. package/src/indicator/trailing.ts +22 -16
  372. package/src/indicator/true-range.spec.ts +32 -0
  373. package/src/indicator/true-range.ts +32 -0
  374. package/src/indicator/window.ts +3 -3
  375. package/src/indicator/wma.spec.ts +5 -4
  376. package/src/indicator/wma.ts +8 -7
  377. package/src/shared/collections.spec.ts +30 -0
  378. package/src/shared/collections.ts +141 -0
  379. package/src/shared/datetime.ts +0 -12
  380. package/src/shared/decimals.spec.ts +19 -24
  381. package/src/shared/decimals.ts +22 -55
  382. package/src/shared/index.ts +2 -1
  383. package/src/shared/io.ts +0 -2
  384. package/src/shared/pipe.ts +12 -0
  385. package/src/shared/policy.ts +0 -13
  386. package/src/storage/cache.spec.ts +18 -0
  387. package/src/storage/cache.ts +1 -1
  388. package/src/storage/feed.ts +88 -23
  389. package/src/storage/storage.ts +9 -13
  390. package/src/store/index.ts +8 -2
  391. package/src/store/{event/store-balance.event.spec.ts → store-balance.event.spec.ts} +10 -10
  392. package/src/store/store-balance.event.ts +124 -0
  393. package/src/store/store-instrument.event.spec.ts +25 -0
  394. package/src/store/store-instrument.event.ts +72 -0
  395. package/src/store/store-order.event.spec.ts +28 -0
  396. package/src/store/store-order.event.ts +214 -0
  397. package/src/store/store-orderbook.event.spec.ts +37 -0
  398. package/src/store/store-orderbook.event.ts +54 -0
  399. package/src/store/store-position.event.ts +114 -0
  400. package/src/store/store-state.ts +48 -0
  401. package/src/store/store-trade.event.spec.ts +60 -0
  402. package/src/store/store-trade.event.ts +36 -0
  403. package/src/store/store.event.ts +8 -0
  404. package/src/store/store.spec.ts +180 -0
  405. package/src/store/store.ts +10 -208
  406. package/dist/adapter/paper/simulator/paper-margin-simulator.d.ts +0 -10
  407. package/dist/adapter/paper/simulator/paper-margin-simulator.js +0 -69
  408. package/dist/adapter/paper/simulator/paper-margin-simulator.js.map +0 -1
  409. package/dist/adapter/paper/simulator/paper-simulator.d.ts +0 -16
  410. package/dist/adapter/paper/simulator/paper-simulator.js +0 -93
  411. package/dist/adapter/paper/simulator/paper-simulator.js.map +0 -1
  412. package/dist/adapter/paper/simulator/paper-spot-simulator.d.ts +0 -13
  413. package/dist/adapter/paper/simulator/paper-spot-simulator.js +0 -81
  414. package/dist/adapter/paper/simulator/paper-spot-simulator.js.map +0 -1
  415. package/dist/adapter/paper/simulator/paper-spot-simulator.spec.js +0 -49
  416. package/dist/adapter/paper/simulator/paper-spot-simulator.spec.js.map +0 -1
  417. package/dist/domain/statement.d.ts +0 -4
  418. package/dist/domain/statement.js +0 -87
  419. package/dist/domain/statement.js.map +0 -1
  420. package/dist/indicator/truerange.d.ts +0 -3
  421. package/dist/indicator/truerange.js +0 -19
  422. package/dist/indicator/truerange.js.map +0 -1
  423. package/dist/indicator/truerange.spec.js +0 -28
  424. package/dist/indicator/truerange.spec.js.map +0 -1
  425. package/dist/shared/policy.spec.js +0 -22
  426. package/dist/shared/policy.spec.js.map +0 -1
  427. package/dist/shared/topic.d.ts +0 -14
  428. package/dist/shared/topic.js +0 -40
  429. package/dist/shared/topic.js.map +0 -1
  430. package/dist/shared/topic.spec.js +0 -43
  431. package/dist/shared/topic.spec.js.map +0 -1
  432. package/dist/store/event/index.d.ts +0 -8
  433. package/dist/store/event/index.js +0 -25
  434. package/dist/store/event/index.js.map +0 -1
  435. package/dist/store/event/store-balance.event.d.ts +0 -37
  436. package/dist/store/event/store-balance.event.js +0 -119
  437. package/dist/store/event/store-balance.event.js.map +0 -1
  438. package/dist/store/event/store-balance.event.spec.js.map +0 -1
  439. package/dist/store/event/store-candle.event.d.ts +0 -18
  440. package/dist/store/event/store-candle.event.js +0 -63
  441. package/dist/store/event/store-candle.event.js.map +0 -1
  442. package/dist/store/event/store-candle.event.spec.js +0 -23
  443. package/dist/store/event/store-candle.event.spec.js.map +0 -1
  444. package/dist/store/event/store-instrument.event.js +0 -78
  445. package/dist/store/event/store-instrument.event.js.map +0 -1
  446. package/dist/store/event/store-instrument.event.spec.js +0 -21
  447. package/dist/store/event/store-instrument.event.spec.js.map +0 -1
  448. package/dist/store/event/store-order.event.d.ts +0 -61
  449. package/dist/store/event/store-order.event.js +0 -205
  450. package/dist/store/event/store-order.event.js.map +0 -1
  451. package/dist/store/event/store-order.event.spec.js.map +0 -1
  452. package/dist/store/event/store-orderbook.event.d.ts +0 -15
  453. package/dist/store/event/store-orderbook.event.js +0 -65
  454. package/dist/store/event/store-orderbook.event.js.map +0 -1
  455. package/dist/store/event/store-position.event.d.ts +0 -23
  456. package/dist/store/event/store-position.event.js +0 -97
  457. package/dist/store/event/store-position.event.js.map +0 -1
  458. package/dist/store/event/store-trade.event.d.ts +0 -13
  459. package/dist/store/event/store-trade.event.js +0 -47
  460. package/dist/store/event/store-trade.event.js.map +0 -1
  461. package/dist/store/event/store-trade.event.spec.js +0 -44
  462. package/dist/store/event/store-trade.event.spec.js.map +0 -1
  463. package/dist/store/event/store.event.d.ts +0 -5
  464. package/dist/store/event/store.event.js.map +0 -1
  465. package/dist/store/store.state.d.ts +0 -21
  466. package/dist/store/store.state.js +0 -21
  467. package/dist/store/store.state.js.map +0 -1
  468. package/dist/tests/backtester-adapter.spec.js +0 -61
  469. package/dist/tests/backtester-adapter.spec.js.map +0 -1
  470. package/dist/tests/session.spec.d.ts +0 -0
  471. package/dist/tests/session.spec.js +0 -1
  472. package/dist/tests/session.spec.js.map +0 -1
  473. package/jestconfig.integration.json +0 -12
  474. package/src/adapter/paper/simulator/paper-margin-simulator.ts +0 -108
  475. package/src/adapter/paper/simulator/paper-simulator.ts +0 -121
  476. package/src/adapter/paper/simulator/paper-spot-simulator.spec.ts +0 -87
  477. package/src/adapter/paper/simulator/paper-spot-simulator.ts +0 -134
  478. package/src/domain/statement.ts +0 -119
  479. package/src/indicator/truerange.spec.ts +0 -32
  480. package/src/indicator/truerange.ts +0 -31
  481. package/src/shared/policy.spec.ts +0 -25
  482. package/src/shared/topic.spec.ts +0 -34
  483. package/src/shared/topic.ts +0 -43
  484. package/src/store/event/index.ts +0 -8
  485. package/src/store/event/store-balance.event.ts +0 -161
  486. package/src/store/event/store-candle.event.spec.ts +0 -30
  487. package/src/store/event/store-candle.event.ts +0 -71
  488. package/src/store/event/store-instrument.event.spec.ts +0 -25
  489. package/src/store/event/store-instrument.event.ts +0 -84
  490. package/src/store/event/store-order.event.spec.ts +0 -28
  491. package/src/store/event/store-order.event.ts +0 -218
  492. package/src/store/event/store-orderbook.event.ts +0 -70
  493. package/src/store/event/store-position.event.ts +0 -109
  494. package/src/store/event/store-trade.event.spec.ts +0 -60
  495. package/src/store/event/store-trade.event.ts +0 -52
  496. package/src/store/event/store.event.ts +0 -6
  497. package/src/store/store.state.ts +0 -43
  498. package/src/tests/backtester-adapter.spec.ts +0 -88
  499. package/src/tests/session.spec.ts +0 -121
@@ -1,23 +1,32 @@
1
1
  import { Instrument } from '../domain';
2
- import { timestamp } from '../shared';
2
+ import { decimal, timestamp } from '../shared';
3
3
  import { Component } from './component';
4
4
 
5
+ export interface Liquidity {
6
+ rate: decimal;
7
+ quantity: decimal;
8
+ next: this;
9
+ }
10
+
11
+ export const LiquidityAskComparer = (lhs: { rate: decimal }, rhs: { rate: decimal }) =>
12
+ lhs.rate.comparedTo(rhs.rate);
13
+ export const LiquidityBidComparer = (lhs: { rate: decimal }, rhs: { rate: decimal }) =>
14
+ rhs.rate.comparedTo(lhs.rate);
15
+
5
16
  /**
6
17
  * Provides an access to pending buy and sell orders on the specific market.
7
18
  */
8
19
  export class Orderbook implements Component {
20
+ id: string;
9
21
  kind = 'orderbook';
10
22
  timestamp: timestamp;
11
- bestAskRate: number;
12
- bestAskQuantity: number;
13
- bestBidRate: number;
14
- bestBidQuantity: number;
15
23
 
16
- get midRate(): number {
17
- return this.instrument.quote.fixed((this.bestAskRate + this.bestBidRate) / 2);
18
- }
24
+ asks: Liquidity;
25
+ bids: Liquidity;
19
26
 
20
- constructor(public readonly instrument: Instrument) {}
27
+ constructor(public readonly instrument: Instrument) {
28
+ this.id = instrument.id;
29
+ }
21
30
 
22
31
  toString() {
23
32
  return this.instrument.toString();
@@ -0,0 +1,59 @@
1
+ import { BehaviorSubject, Subject } from 'rxjs';
2
+
3
+ import { d } from '../shared';
4
+ import { State } from '../store';
5
+ import { Asset } from './asset';
6
+ import { Balance } from './balance';
7
+ import { Component } from './component';
8
+ import { Instrument } from './instrument';
9
+ import { Position } from './position';
10
+ import { position, positions } from './position.operator';
11
+
12
+ const instrument = new Instrument(
13
+ new Asset('abc', 'xyz', 4),
14
+ new Asset('def', 'xyz', 4),
15
+ 'abc-def'
16
+ );
17
+
18
+ describe('position', () => {
19
+ test('should pipe a position', done => {
20
+ new BehaviorSubject<Component>(new Position('1', instrument, 'CROSS', d(10), d(2), 3))
21
+ .pipe(position(instrument))
22
+ .subscribe({
23
+ next: it => {
24
+ expect(it.id).toEqual('1');
25
+ done();
26
+ }
27
+ });
28
+ });
29
+
30
+ test('should skip a pipe', done => {
31
+ new BehaviorSubject<Component>(instrument).pipe(position(instrument)).subscribe({
32
+ next: () => fail(),
33
+ complete: done()
34
+ });
35
+ });
36
+ });
37
+
38
+ describe('positions', () => {
39
+ const state = new State();
40
+ const balance = new Balance(instrument.quote);
41
+ const position1 = new Position('1', instrument, 'CROSS', d(10), d(2), 3);
42
+ const position2 = new Position('2', instrument, 'CROSS', d(20), d(2), 3);
43
+
44
+ beforeEach(() => {
45
+ state.balance.upsert(balance);
46
+
47
+ balance.position['1'] = position1;
48
+ balance.position['2'] = position2;
49
+ });
50
+
51
+ test('should pipe an array of positions on subscription start', done => {
52
+ new Subject<Component>().pipe(positions(instrument, state)).subscribe({
53
+ next: it => {
54
+ expect(it.length).toEqual(2);
55
+ done();
56
+ }
57
+ });
58
+ });
59
+ });
@@ -0,0 +1,64 @@
1
+ import { filter, map, Observable, share, startWith } from 'rxjs';
2
+
3
+ import { d, decimal, weightedMean } from '../shared';
4
+ import { State } from '../store';
5
+ import { InstrumentSelector } from './instrument';
6
+ import { Position } from './position';
7
+
8
+ export function position(selector: InstrumentSelector) {
9
+ return (source: Observable<Position>) =>
10
+ source.pipe(
11
+ filter(it => it.kind == 'position' && it.instrument.id == selector.id),
12
+ map(it => it as Readonly<Position>)
13
+ );
14
+ }
15
+
16
+ export function positions(selector: InstrumentSelector, state: State) {
17
+ const getter = () =>
18
+ Object.values(state.balance.get(selector.quote.id).position).filter(
19
+ it => it.instrument.id == selector.id
20
+ );
21
+
22
+ return (source: Observable<Position>) =>
23
+ source.pipe(
24
+ position(selector),
25
+ map(() => getter()),
26
+ startWith(getter())
27
+ );
28
+ }
29
+
30
+ export function flatten() {
31
+ return function (
32
+ source: Observable<Position[]>
33
+ ): Observable<{ size: decimal; rate: decimal }> {
34
+ return source.pipe(
35
+ map(it => {
36
+ if (it.length > 1) {
37
+ return {
38
+ size: it.reduce(
39
+ (aggregate, position) => aggregate.add(position.size),
40
+ d.Zero
41
+ ),
42
+ rate: weightedMean(
43
+ it.map(x => x.averageExecutionRate),
44
+ it.map(x => x.size)
45
+ )
46
+ };
47
+ }
48
+
49
+ if (it.length == 1) {
50
+ return {
51
+ size: it[0].size,
52
+ rate: it[0].averageExecutionRate
53
+ };
54
+ }
55
+
56
+ return {
57
+ size: d.Zero,
58
+ rate: d.Zero
59
+ };
60
+ }),
61
+ share()
62
+ );
63
+ };
64
+ }
@@ -1,35 +1,40 @@
1
+ import { d } from '../shared';
1
2
  import { Asset } from './asset';
2
3
  import { Instrument } from './instrument';
3
4
  import { Position } from './position';
4
5
 
5
- const instrument = new Instrument(
6
- new Asset('abc', 'xyz', 4),
7
- new Asset('def', 'xyz', 4),
8
- 'abc-def'
9
- );
10
-
11
- describe('position tests', () => {
12
- test('should instantiate proper position', () => {
13
- const sut = new Position('123', instrument);
6
+ describe('Position', () => {
7
+ const instrument = new Instrument(
8
+ new Asset('abc', 'xyz', 4),
9
+ new Asset('def', 'xyz', 4),
10
+ 'abc-def'
11
+ );
12
+
13
+ test('should construct a position', () => {
14
+ const sut = new Position('1', instrument, 'CROSS', d(10), d(2), 3);
15
+
16
+ expect(sut.id).toEqual('1');
17
+ expect(sut.mode).toEqual('CROSS');
18
+ expect(sut.averageExecutionRate).toEqual(d(10));
19
+ expect(sut.size).toEqual(d(2));
20
+ expect(sut.leverage).toEqual(3);
21
+ expect(sut.estimatedUnrealizedPnL).toEqual(undefined);
22
+ expect(sut.id).toEqual('1');
23
+ });
14
24
 
15
- sut.size = 5;
16
- sut.averageExecutionRate = 20;
17
- sut.leverage = 20;
25
+ test('should calculate correct margin', () => {
26
+ const sut = new Position('1', instrument, 'CROSS', d(2511.81), d(10.31), 20);
18
27
 
19
- expect(sut.margin).toEqual(5);
20
- expect(sut.estimatedUnrealizedPnL).toEqual(0);
28
+ expect(sut.margin).toEqual(d(0.5155));
29
+ expect(sut.estimatedUnrealizedPnL).toEqual(undefined);
21
30
  });
22
31
 
23
- test('should calculate unrealized pnl', () => {
24
- const sut = new Position('123', instrument);
25
-
26
- sut.size = -5;
27
- sut.averageExecutionRate = 20;
28
- sut.leverage = 20;
32
+ test('should calculate correct unrealized pnl', () => {
33
+ const sut = new Position('1', instrument, 'CROSS', d(2511.81), d(10.31), 20);
29
34
 
30
- sut.calculatePnL(10);
35
+ const pnl = sut.calculateEstimatedUnrealizedPnL(d(2576.44));
31
36
 
32
- expect(sut.margin).toEqual(5);
33
- expect(sut.estimatedUnrealizedPnL).toEqual(50);
37
+ expect(pnl).toEqual(d(0.2652));
38
+ expect(sut.estimatedUnrealizedPnL).toEqual(d(0.2652));
34
39
  });
35
40
  });
@@ -1,7 +1,5 @@
1
- import { map, Observable, share } from 'rxjs';
2
-
3
1
  import { Instrument } from '../domain';
4
- import { pnl, timestamp, weightedMean } from '../shared';
2
+ import { decimal, pnl, timestamp } from '../shared';
5
3
  import { Component } from './component';
6
4
 
7
5
  export type PositionMode = 'CROSS' | 'ISOLATED';
@@ -9,22 +7,25 @@ export type PositionMode = 'CROSS' | 'ISOLATED';
9
7
  export class Position implements Component {
10
8
  kind = 'position';
11
9
  timestamp: timestamp;
12
- averageExecutionRate: number;
13
- size: number;
14
- leverage: number;
15
- mode: PositionMode = 'CROSS';
16
- estimatedUnrealizedPnL = 0;
10
+ estimatedUnrealizedPnL?: decimal;
17
11
 
18
- get margin(): number {
19
- return this.instrument.quote.ceil(
20
- (Math.abs(this.size) * this.averageExecutionRate) / this.leverage
21
- );
12
+ get margin(): decimal {
13
+ return this.instrument.quote.floor(this.size.abs().div(this.leverage));
22
14
  }
23
15
 
24
- constructor(readonly id: string, readonly instrument: Instrument) {}
25
-
26
- calculatePnL(rate: number): number {
27
- this.estimatedUnrealizedPnL = pnl(this.averageExecutionRate, rate, this.size);
16
+ constructor(
17
+ readonly id: string,
18
+ readonly instrument: Instrument,
19
+ readonly mode: PositionMode,
20
+ public averageExecutionRate: decimal,
21
+ public size: decimal,
22
+ public leverage: number
23
+ ) {}
24
+
25
+ calculateEstimatedUnrealizedPnL(rate: decimal): decimal {
26
+ this.estimatedUnrealizedPnL = this.instrument.quote.floor(
27
+ pnl(this.averageExecutionRate, rate, this.size)
28
+ );
28
29
 
29
30
  return this.estimatedUnrealizedPnL;
30
31
  }
@@ -33,36 +34,3 @@ export class Position implements Component {
33
34
  return this.id;
34
35
  }
35
36
  }
36
-
37
- export function positionsFlat() {
38
- return function (
39
- source: Observable<Position[]>
40
- ): Observable<{ size: number; rate: number }> {
41
- return source.pipe(
42
- map(it => {
43
- if (it.length > 1) {
44
- return {
45
- size: it.reduce((aggregate, position) => aggregate + position.size, 0),
46
- rate: weightedMean(
47
- it.map(x => x.averageExecutionRate),
48
- it.map(x => x.size)
49
- )
50
- };
51
- }
52
-
53
- if (it.length == 1) {
54
- return {
55
- size: it[0].size,
56
- rate: it[0].averageExecutionRate
57
- };
58
- }
59
-
60
- return {
61
- size: 0,
62
- rate: 0
63
- };
64
- }),
65
- share()
66
- );
67
- };
68
- }
@@ -1,10 +1,10 @@
1
1
  import { Bootstrap } from '../bootstrap';
2
2
  import { Asset, Commission } from '../domain';
3
- import { now } from '../shared';
3
+ import { d, now } from '../shared';
4
4
  import { InstrumentPatchEvent } from '../store';
5
5
  import { SessionDescriptor } from './session';
6
6
 
7
- describe('session tests', () => {
7
+ describe('Session', () => {
8
8
  const descriptor: SessionDescriptor = {
9
9
  id: now(),
10
10
  adapter: []
@@ -25,14 +25,14 @@ describe('session tests', () => {
25
25
  now(),
26
26
  new Asset('de30', 'cex', 2),
27
27
  new Asset('usd', 'cex', 2),
28
- new Commission(0, 0),
28
+ new Commission(d.Zero, d.Zero),
29
29
  ''
30
30
  ),
31
31
  new InstrumentPatchEvent(
32
32
  now(),
33
33
  new Asset('wig20', 'cex', 2),
34
34
  new Asset('pln', 'cex', 2),
35
- new Commission(0, 0),
35
+ new Commission(d.Zero, d.Zero),
36
36
  ''
37
37
  )
38
38
  );
@@ -1,22 +1,19 @@
1
1
  import {
2
2
  defer,
3
- distinctUntilChanged,
4
3
  filter,
5
4
  finalize,
6
5
  from,
7
6
  map,
8
- merge,
9
7
  mergeMap,
10
8
  Observable,
11
9
  shareReplay,
12
10
  startWith,
13
- Subject,
14
11
  Subscription,
15
12
  switchMap,
16
13
  take
17
14
  } from 'rxjs';
18
15
 
19
- import { Adapter, BacktesterOptions, PaperOptions } from '../adapter';
16
+ import { AdapterFactory, BacktesterOptions, PaperOptions } from '../adapter';
20
17
  import { AdapterAggregate } from '../adapter/adapter-aggregate';
21
18
  import {
22
19
  AssetSelector,
@@ -26,26 +23,21 @@ import {
26
23
  InstrumentSelector,
27
24
  Order,
28
25
  Orderbook,
29
- OrderState,
30
26
  Position,
31
27
  Trade
32
28
  } from '../domain';
33
29
  import { now } from '../shared';
34
30
  import { StorageFactory } from '../storage';
35
31
  import { Store } from '../store';
32
+ import { balance } from './balance.operator';
33
+ import { instrument, instruments } from './instrument.operator';
34
+ import { order, orders } from './order.operator';
35
+ import { orderbook } from './orderbook.operator';
36
+ import { position, positions } from './position.operator';
37
+ import { trade } from './trade.operator';
36
38
 
37
39
  /**
38
40
  * 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
41
  */
50
42
  export interface SessionDescriptor {
51
43
  /**
@@ -59,7 +51,7 @@ export interface SessionDescriptor {
59
51
  /**
60
52
  * Collection of adapters used to connect to the exchanges.
61
53
  */
62
- adapter: Adapter[];
54
+ adapter: AdapterFactory[];
63
55
 
64
56
  /**
65
57
  * Provides historical data for backtest, it's not required for live and paper
@@ -82,8 +74,6 @@ export class Session {
82
74
  return this.store.snapshot.timestamp;
83
75
  }
84
76
 
85
- readonly statement: Record<string, Record<string, any>> = {};
86
-
87
77
  constructor(
88
78
  readonly store: Store,
89
79
  readonly aggregate: AdapterAggregate,
@@ -129,19 +119,6 @@ export class Session {
129
119
  this.initialized = false;
130
120
  }
131
121
 
132
- useStatement(section: string): Record<string, any> {
133
- return this.statement[section] ?? (this.statement[section] = {});
134
- }
135
-
136
- /**
137
- * Return values for patch provided in optimization file.
138
- * Example usage:
139
- * const orderSize = session.useOptimizer('order.size');
140
- */
141
- useOptimizer(path: string): any {
142
- return undefined;
143
- }
144
-
145
122
  /**
146
123
  * Subscribes to specific instrument. Usually forces adapter to subscribe
147
124
  * for orderbook and ticker streams.
@@ -152,26 +129,21 @@ export class Session {
152
129
 
153
130
  /**
154
131
  * Opens a new order.
155
- * Example:
156
- * session.open(Order.buyMarket(instrument, 100));
132
+ * Example of buy order:
133
+ * session.open(Order.market(instrument, 100));
157
134
  */
158
- open(order: Order): Observable<Order> {
159
- const subject = new Subject<Order>();
160
-
161
- this.aggregate.open(order).catch(subject.error);
162
-
163
- return merge(
164
- subject.asObservable(),
165
- this.order(order.instrument).pipe(filter(it => it.id == order.id))
135
+ open(order: Order): Observable<Readonly<Order>> {
136
+ return from(this.aggregate.open(order)).pipe(
137
+ switchMap(() => this.order(order.instrument).pipe(filter(it => it.id == order.id)))
166
138
  );
167
139
  }
168
140
 
169
141
  /**
170
142
  * Cancels specific order.
171
143
  */
172
- cancel(order: Order): Observable<Order> {
144
+ cancel(order: Order): Observable<Readonly<Order>> {
173
145
  return defer(() => from(this.aggregate.cancel(order))).pipe(
174
- switchMap(it =>
146
+ switchMap(() =>
175
147
  this.store.changes$.pipe(filter(it => it instanceof Order && order.id == it.id))
176
148
  ),
177
149
  map(it => it as Order)
@@ -182,149 +154,85 @@ export class Session {
182
154
  * Subscribes to specific instrument changes.
183
155
  * When adapter awake then it will fetch collection of all available instruments.
184
156
  */
185
- instrument(selector: InstrumentSelector): Observable<Instrument> {
157
+ instrument(selector: InstrumentSelector): Observable<Readonly<Instrument>> {
186
158
  this.subscribe([selector]);
187
159
 
188
- return this.store.changes$.pipe(
189
- filter(it => it instanceof Instrument && it.toString() == selector.toString()),
190
- map(it => it as Instrument)
191
- );
160
+ return this.store.changes$.pipe(instrument(selector, this.store.snapshot));
192
161
  }
193
162
 
194
163
  /**
195
164
  * Subscribes to instruments changes.
196
165
  * When adapter awake then it will fetch collection of all available instruments.
197
166
  */
198
- instruments(): Observable<Instrument[]> {
199
- return this.store.changes$.pipe(
200
- filter(it => it instanceof Instrument),
201
- map(() => Object.values(this.store.snapshot.universe.instrument)),
202
- startWith(Object.values(this.store.snapshot.universe.instrument)),
203
- filter(it => it.length > 0),
204
- distinctUntilChanged((lhs, rhs) => lhs.length == rhs.length)
205
- );
167
+ instruments(): Observable<Readonly<Instrument[]>> {
168
+ return this.store.changes$.pipe(instruments(this.store.snapshot));
169
+ }
170
+
171
+ /**
172
+ * Subscribes to balance changes.
173
+ */
174
+ balance(selector: AssetSelector): Observable<Readonly<Balance>> {
175
+ return this.store.changes$.pipe(balance(selector, this.store.snapshot));
206
176
  }
207
177
 
208
178
  /**
209
179
  * Subscribes to trade/ticker changes.
210
180
  */
211
- trade(selector: InstrumentSelector): Observable<Trade> {
181
+ trade(selector: InstrumentSelector): Observable<Readonly<Trade>> {
212
182
  this.subscribe([selector]);
213
183
 
214
- return this.store.changes$.pipe(
215
- filter(
216
- it => it instanceof Trade && it.instrument.toString() == selector.toString()
217
- ),
218
- map(it => it as Trade)
219
- );
184
+ return this.store.changes$.pipe(trade(selector, this.store.snapshot));
220
185
  }
221
186
 
222
187
  /**
223
188
  * Subscribes to orderbook changes.
224
189
  * Right now you can access only best bid and best ask.
225
190
  */
226
- orderbook(selector: InstrumentSelector): Observable<Orderbook> {
191
+ orderbook(selector: InstrumentSelector): Observable<Readonly<Orderbook>> {
227
192
  this.subscribe([selector]);
228
193
 
229
- return this.store.changes$.pipe(
230
- filter(
231
- it => it instanceof Orderbook && it.instrument.toString() == selector.toString()
232
- ),
233
- map(it => it as Orderbook)
234
- );
194
+ return this.store.changes$.pipe(orderbook(selector, this.store.snapshot));
235
195
  }
236
196
 
237
197
  /**
238
198
  * Subscribes to position on leveraged market.
239
199
  */
240
- position(selector: InstrumentSelector): Observable<Position> {
200
+ position(selector: InstrumentSelector): Observable<Readonly<Position>> {
241
201
  this.subscribe([selector]);
242
202
 
243
- return this.store.changes$.pipe(
244
- filter(
245
- it => it instanceof Position && it.instrument.toString() == selector.toString()
246
- ),
247
- map(it => it as Position)
248
- );
203
+ return this.store.changes$.pipe(position(selector));
249
204
  }
250
205
 
251
206
  /**
252
207
  * Subscribes to positions on leveraged markets.
253
208
  */
254
- positions(selector: InstrumentSelector): Observable<Position[]> {
209
+ positions(selector: InstrumentSelector): Observable<Readonly<Position[]>> {
255
210
  this.subscribe([selector]);
256
211
 
257
- return this.store.changes$.pipe(
258
- filter(
259
- it => it instanceof Position && it.instrument.toString() == selector.toString()
260
- ),
261
- map(() =>
262
- Object.values(
263
- this.store.snapshot.balance[selector.quote.toString()].position
264
- ).filter(it => it.instrument.toString() == selector.toString())
265
- ),
266
- startWith([])
267
- );
212
+ return this.store.changes$.pipe(positions(selector, this.store.snapshot));
268
213
  }
269
214
 
270
- order(selector: InstrumentSelector): Observable<Order> {
215
+ order(selector: InstrumentSelector): Observable<Readonly<Order>> {
271
216
  this.subscribe([selector]);
272
217
 
273
- return this.store.changes$.pipe(
274
- filter(
275
- it => it instanceof Order && it.instrument.toString() == selector.toString()
276
- ),
277
- map(it => it as Order)
278
- );
218
+ return this.store.changes$.pipe(order(selector));
279
219
  }
280
220
 
281
- orders(selector: InstrumentSelector, states?: OrderState[]): Observable<Order[]> {
221
+ orders(selector: InstrumentSelector): Observable<Readonly<Order[]>> {
282
222
  this.subscribe([selector]);
283
223
 
284
- return this.store.changes$.pipe(
285
- filter(
286
- it =>
287
- it instanceof Order &&
288
- it.instrument.toString() == selector.toString() &&
289
- (!states || states.includes(it.state))
290
- ),
291
- map(() => this.store.snapshot.order),
292
- startWith(this.store.snapshot.order),
293
- map(it =>
294
- Object.values(it)
295
- .filter(
296
- it =>
297
- it.instrument.toString() == selector.toString() &&
298
- (states ? states.includes(it.state) : true)
299
- )
300
- .sort((lhs, rhs) => rhs.createdAt - lhs.createdAt)
301
- )
302
- );
303
- }
304
-
305
- balance(selector: AssetSelector): Observable<Balance> {
306
- return this.store.changes$.pipe(
307
- startWith(this.store.snapshot.balance[selector.toString()]),
308
- filter(
309
- it =>
310
- it instanceof Balance &&
311
- (!selector || it.asset.toString() == selector.toString())
312
- ),
313
- map(it => it as Balance)
314
- );
224
+ return this.store.changes$.pipe(orders(selector, this.store.snapshot));
315
225
  }
316
226
 
317
227
  history(
318
228
  selector: InstrumentSelector,
319
229
  timeframe: number,
320
230
  length: number
321
- ): Observable<Candle> {
231
+ ): Observable<Readonly<Candle>> {
322
232
  return this.store.changes$.pipe(
323
- startWith(this.store.snapshot.universe.instrument[selector.toString()]),
324
- filter(it => it instanceof Instrument && it.toString() == selector.toString()),
325
- switchMap(() =>
326
- from(this.aggregate.history({ instrument: selector, timeframe, length }))
327
- ),
233
+ startWith(this.store.snapshot.universe.instrument.get(selector.id)),
234
+ filter(it => it instanceof Instrument && it.id == selector.id),
235
+ switchMap(() => from(this.aggregate.history(selector, timeframe, length))),
328
236
  take(1),
329
237
  shareReplay(),
330
238
  mergeMap(it => it)
@@ -0,0 +1,31 @@
1
+ import { Subject } from 'rxjs';
2
+
3
+ import { State } from '../store';
4
+ import { Asset } from './asset';
5
+ import { Component } from './component';
6
+ import { Instrument } from './instrument';
7
+ import { Trade } from './trade';
8
+ import { trade } from './trade.operator';
9
+
10
+ describe('trade', () => {
11
+ const instrument = new Instrument(
12
+ new Asset('abc', 'xyz', 4),
13
+ new Asset('def', 'xyz', 4),
14
+ 'abc-def'
15
+ );
16
+
17
+ const state = new State();
18
+
19
+ beforeEach(() => {
20
+ state.trade.upsert(new Trade(instrument));
21
+ });
22
+
23
+ test('should pipe an orderbook on subscription', done => {
24
+ new Subject<Component>().pipe(trade(instrument, state)).subscribe({
25
+ next: it => {
26
+ expect(it.id).toEqual(instrument.id);
27
+ done();
28
+ }
29
+ });
30
+ });
31
+ });