openalgo-script 0.4.0 → 0.6.0

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 (359) hide show
  1. package/CHANGELOG.md +1050 -0
  2. package/README.md +111 -27
  3. package/dist/adapters/charts/driving.d.ts +50 -0
  4. package/dist/adapters/charts/driving.d.ts.map +1 -0
  5. package/dist/adapters/charts/driving.js +57 -0
  6. package/dist/adapters/charts/driving.js.map +1 -0
  7. package/dist/adapters/charts/run.d.ts +20 -0
  8. package/dist/adapters/charts/run.d.ts.map +1 -1
  9. package/dist/adapters/charts/run.js +89 -16
  10. package/dist/adapters/charts/run.js.map +1 -1
  11. package/dist/adapters/charts/tables.d.ts +6 -19
  12. package/dist/adapters/charts/tables.d.ts.map +1 -1
  13. package/dist/adapters/charts/tables.js.map +1 -1
  14. package/dist/adapters/charts/undrawable.d.ts +4 -0
  15. package/dist/adapters/charts/undrawable.d.ts.map +1 -0
  16. package/dist/adapters/charts/undrawable.js +47 -0
  17. package/dist/adapters/charts/undrawable.js.map +1 -0
  18. package/dist/adapters/charts/venue.d.ts +73 -0
  19. package/dist/adapters/charts/venue.d.ts.map +1 -0
  20. package/dist/adapters/charts/venue.js +104 -0
  21. package/dist/adapters/charts/venue.js.map +1 -0
  22. package/dist/core/accounting/analysis.d.ts +111 -0
  23. package/dist/core/accounting/analysis.d.ts.map +1 -0
  24. package/dist/core/accounting/analysis.js +123 -0
  25. package/dist/core/accounting/analysis.js.map +1 -0
  26. package/dist/core/accounting/equity.d.ts +33 -0
  27. package/dist/core/accounting/equity.d.ts.map +1 -1
  28. package/dist/core/accounting/equity.js +12 -0
  29. package/dist/core/accounting/equity.js.map +1 -1
  30. package/dist/core/accounting/index.d.ts +2 -0
  31. package/dist/core/accounting/index.d.ts.map +1 -1
  32. package/dist/core/accounting/index.js +1 -0
  33. package/dist/core/accounting/index.js.map +1 -1
  34. package/dist/core/accounting/report.d.ts +3 -0
  35. package/dist/core/accounting/report.d.ts.map +1 -1
  36. package/dist/core/accounting/report.js +2 -0
  37. package/dist/core/accounting/report.js.map +1 -1
  38. package/dist/core/accounting/statistics.d.ts +12 -0
  39. package/dist/core/accounting/statistics.d.ts.map +1 -1
  40. package/dist/core/accounting/statistics.js +23 -1
  41. package/dist/core/accounting/statistics.js.map +1 -1
  42. package/dist/core/backtest/case.d.ts +60 -0
  43. package/dist/core/backtest/case.d.ts.map +1 -0
  44. package/dist/core/backtest/case.js +319 -0
  45. package/dist/core/backtest/case.js.map +1 -0
  46. package/dist/core/backtest/compare.d.ts.map +1 -1
  47. package/dist/core/backtest/compare.js +2 -0
  48. package/dist/core/backtest/compare.js.map +1 -1
  49. package/dist/core/backtest/deliver.d.ts +93 -0
  50. package/dist/core/backtest/deliver.d.ts.map +1 -0
  51. package/dist/core/backtest/deliver.js +94 -0
  52. package/dist/core/backtest/deliver.js.map +1 -0
  53. package/dist/core/backtest/drive.d.ts +101 -8
  54. package/dist/core/backtest/drive.d.ts.map +1 -1
  55. package/dist/core/backtest/drive.js +114 -158
  56. package/dist/core/backtest/drive.js.map +1 -1
  57. package/dist/core/backtest/index.d.ts +26 -12
  58. package/dist/core/backtest/index.d.ts.map +1 -1
  59. package/dist/core/backtest/index.js +21 -10
  60. package/dist/core/backtest/index.js.map +1 -1
  61. package/dist/core/backtest/record.d.ts +63 -2
  62. package/dist/core/backtest/record.d.ts.map +1 -1
  63. package/dist/core/backtest/record.js +71 -4
  64. package/dist/core/backtest/record.js.map +1 -1
  65. package/dist/core/backtest/replay.d.ts.map +1 -1
  66. package/dist/core/backtest/replay.js +11 -1
  67. package/dist/core/backtest/replay.js.map +1 -1
  68. package/dist/core/backtest/simulate.d.ts +113 -1
  69. package/dist/core/backtest/simulate.d.ts.map +1 -1
  70. package/dist/core/backtest/simulate.js +123 -5
  71. package/dist/core/backtest/simulate.js.map +1 -1
  72. package/dist/core/backtest/walk.d.ts +39 -0
  73. package/dist/core/backtest/walk.d.ts.map +1 -0
  74. package/dist/core/backtest/walk.js +125 -0
  75. package/dist/core/backtest/walk.js.map +1 -0
  76. package/dist/core/catalogue/catalogue.generated.d.ts +179 -2
  77. package/dist/core/catalogue/catalogue.generated.d.ts.map +1 -1
  78. package/dist/core/catalogue/catalogue.generated.js +19 -2
  79. package/dist/core/catalogue/catalogue.generated.js.map +1 -1
  80. package/dist/core/catalogue/types.d.ts +8 -2
  81. package/dist/core/catalogue/types.d.ts.map +1 -1
  82. package/dist/core/catalogue/values.generated.d.ts +51 -0
  83. package/dist/core/catalogue/values.generated.d.ts.map +1 -1
  84. package/dist/core/check/assigned.d.ts +19 -0
  85. package/dist/core/check/assigned.d.ts.map +1 -0
  86. package/dist/core/check/assigned.js +14 -0
  87. package/dist/core/check/assigned.js.map +1 -0
  88. package/dist/core/check/call-sites.d.ts.map +1 -1
  89. package/dist/core/check/call-sites.js +9 -4
  90. package/dist/core/check/call-sites.js.map +1 -1
  91. package/dist/core/check/calls.d.ts.map +1 -1
  92. package/dist/core/check/calls.js +12 -4
  93. package/dist/core/check/calls.js.map +1 -1
  94. package/dist/core/check/check.d.ts.map +1 -1
  95. package/dist/core/check/check.js +15 -2
  96. package/dist/core/check/check.js.map +1 -1
  97. package/dist/core/check/checker.d.ts +26 -0
  98. package/dist/core/check/checker.d.ts.map +1 -1
  99. package/dist/core/check/checker.js +38 -2
  100. package/dist/core/check/checker.js.map +1 -1
  101. package/dist/core/check/constant.d.ts +16 -0
  102. package/dist/core/check/constant.d.ts.map +1 -1
  103. package/dist/core/check/constant.js +52 -0
  104. package/dist/core/check/constant.js.map +1 -1
  105. package/dist/core/check/deleted.d.ts +3 -0
  106. package/dist/core/check/deleted.d.ts.map +1 -0
  107. package/dist/core/check/deleted.js +109 -0
  108. package/dist/core/check/deleted.js.map +1 -0
  109. package/dist/core/check/expressions.js +1 -1
  110. package/dist/core/check/expressions.js.map +1 -1
  111. package/dist/core/check/library-orders.js +2 -2
  112. package/dist/core/check/library-orders.js.map +1 -1
  113. package/dist/core/check/library-output.d.ts.map +1 -1
  114. package/dist/core/check/library-output.js +1 -0
  115. package/dist/core/check/library-output.js.map +1 -1
  116. package/dist/core/check/library-prose.generated.js +12 -12
  117. package/dist/core/check/library-prose.generated.js.map +1 -1
  118. package/dist/core/check/library.d.ts +7 -0
  119. package/dist/core/check/library.d.ts.map +1 -1
  120. package/dist/core/check/library.js +1 -0
  121. package/dist/core/check/library.js.map +1 -1
  122. package/dist/core/check/surface.d.ts +9 -0
  123. package/dist/core/check/surface.d.ts.map +1 -1
  124. package/dist/core/check/surface.js +13 -0
  125. package/dist/core/check/surface.js.map +1 -1
  126. package/dist/core/emit/canonical.d.ts +22 -8
  127. package/dist/core/emit/canonical.d.ts.map +1 -1
  128. package/dist/core/emit/canonical.js +67 -6
  129. package/dist/core/emit/canonical.js.map +1 -1
  130. package/dist/core/engine/arithmetic.d.ts +6 -25
  131. package/dist/core/engine/arithmetic.d.ts.map +1 -1
  132. package/dist/core/engine/arithmetic.js +48 -3
  133. package/dist/core/engine/arithmetic.js.map +1 -1
  134. package/dist/core/engine/bar-source.d.ts +65 -0
  135. package/dist/core/engine/bar-source.d.ts.map +1 -0
  136. package/dist/core/engine/bar-source.js +58 -0
  137. package/dist/core/engine/bar-source.js.map +1 -0
  138. package/dist/core/engine/engine.d.ts +9 -11
  139. package/dist/core/engine/engine.d.ts.map +1 -1
  140. package/dist/core/engine/engine.js +24 -24
  141. package/dist/core/engine/engine.js.map +1 -1
  142. package/dist/core/engine/guard.d.ts.map +1 -1
  143. package/dist/core/engine/guard.js +10 -0
  144. package/dist/core/engine/guard.js.map +1 -1
  145. package/dist/core/engine/host.d.ts +4 -2
  146. package/dist/core/engine/host.d.ts.map +1 -1
  147. package/dist/core/engine/host.js.map +1 -1
  148. package/dist/core/engine/index.d.ts +2 -1
  149. package/dist/core/engine/index.d.ts.map +1 -1
  150. package/dist/core/engine/index.js +1 -1
  151. package/dist/core/engine/index.js.map +1 -1
  152. package/dist/core/engine/library/arrays.d.ts.map +1 -1
  153. package/dist/core/engine/library/arrays.js +8 -2
  154. package/dist/core/engine/library/arrays.js.map +1 -1
  155. package/dist/core/engine/library/binding.d.ts +2 -0
  156. package/dist/core/engine/library/binding.d.ts.map +1 -1
  157. package/dist/core/engine/library/binding.js.map +1 -1
  158. package/dist/core/engine/library/code-points.d.ts +40 -0
  159. package/dist/core/engine/library/code-points.d.ts.map +1 -0
  160. package/dist/core/engine/library/code-points.js +74 -0
  161. package/dist/core/engine/library/code-points.js.map +1 -0
  162. package/dist/core/engine/library/index.d.ts +13 -0
  163. package/dist/core/engine/library/index.d.ts.map +1 -1
  164. package/dist/core/engine/library/index.js +15 -0
  165. package/dist/core/engine/library/index.js.map +1 -1
  166. package/dist/core/engine/library/objects.d.ts.map +1 -1
  167. package/dist/core/engine/library/objects.js +1 -1
  168. package/dist/core/engine/library/objects.js.map +1 -1
  169. package/dist/core/engine/library/text.d.ts.map +1 -1
  170. package/dist/core/engine/library/text.js +51 -34
  171. package/dist/core/engine/library/text.js.map +1 -1
  172. package/dist/core/engine/load.d.ts +20 -0
  173. package/dist/core/engine/load.d.ts.map +1 -1
  174. package/dist/core/engine/load.js +62 -0
  175. package/dist/core/engine/load.js.map +1 -1
  176. package/dist/core/engine/request-body.d.ts +3 -1
  177. package/dist/core/engine/request-body.d.ts.map +1 -1
  178. package/dist/core/engine/request-body.js +3 -1
  179. package/dist/core/engine/request-body.js.map +1 -1
  180. package/dist/core/engine/request-plan.d.ts +3 -3
  181. package/dist/core/engine/request-plan.js +3 -3
  182. package/dist/core/engine/requests.d.ts +2 -2
  183. package/dist/core/engine/requests.d.ts.map +1 -1
  184. package/dist/core/engine/requests.js +5 -4
  185. package/dist/core/engine/requests.js.map +1 -1
  186. package/dist/core/engine/series.d.ts +18 -6
  187. package/dist/core/engine/series.d.ts.map +1 -1
  188. package/dist/core/engine/series.js +24 -5
  189. package/dist/core/engine/series.js.map +1 -1
  190. package/dist/core/engine/session/record.d.ts +4 -4
  191. package/dist/core/engine/session/record.js +4 -4
  192. package/dist/core/engine/verify-tables.d.ts.map +1 -1
  193. package/dist/core/engine/verify-tables.js +41 -0
  194. package/dist/core/engine/verify-tables.js.map +1 -1
  195. package/dist/core/importer/calls.d.ts +29 -0
  196. package/dist/core/importer/calls.d.ts.map +1 -0
  197. package/dist/core/importer/calls.js +267 -0
  198. package/dist/core/importer/calls.js.map +1 -0
  199. package/dist/core/importer/context.d.ts +118 -0
  200. package/dist/core/importer/context.d.ts.map +1 -0
  201. package/dist/core/importer/context.js +120 -0
  202. package/dist/core/importer/context.js.map +1 -0
  203. package/dist/core/importer/expressions.d.ts +44 -0
  204. package/dist/core/importer/expressions.d.ts.map +1 -0
  205. package/dist/core/importer/expressions.js +223 -0
  206. package/dist/core/importer/expressions.js.map +1 -0
  207. package/dist/core/importer/importer.d.ts +13 -0
  208. package/dist/core/importer/importer.d.ts.map +1 -0
  209. package/dist/core/importer/importer.js +220 -0
  210. package/dist/core/importer/importer.js.map +1 -0
  211. package/dist/core/importer/index.d.ts +20 -0
  212. package/dist/core/importer/index.d.ts.map +1 -0
  213. package/dist/core/importer/index.js +18 -0
  214. package/dist/core/importer/index.js.map +1 -0
  215. package/dist/core/importer/lexer.d.ts +68 -0
  216. package/dist/core/importer/lexer.d.ts.map +1 -0
  217. package/dist/core/importer/lexer.js +207 -0
  218. package/dist/core/importer/lexer.js.map +1 -0
  219. package/dist/core/importer/names.d.ts +41 -0
  220. package/dist/core/importer/names.d.ts.map +1 -0
  221. package/dist/core/importer/names.js +78 -0
  222. package/dist/core/importer/names.js.map +1 -0
  223. package/dist/core/importer/orders.d.ts +8 -0
  224. package/dist/core/importer/orders.d.ts.map +1 -0
  225. package/dist/core/importer/orders.js +332 -0
  226. package/dist/core/importer/orders.js.map +1 -0
  227. package/dist/core/importer/outputs.d.ts +19 -0
  228. package/dist/core/importer/outputs.d.ts.map +1 -0
  229. package/dist/core/importer/outputs.js +266 -0
  230. package/dist/core/importer/outputs.js.map +1 -0
  231. package/dist/core/importer/parser.d.ts +5 -0
  232. package/dist/core/importer/parser.d.ts.map +1 -0
  233. package/dist/core/importer/parser.js +439 -0
  234. package/dist/core/importer/parser.js.map +1 -0
  235. package/dist/core/importer/presence.d.ts +32 -0
  236. package/dist/core/importer/presence.d.ts.map +1 -0
  237. package/dist/core/importer/presence.js +146 -0
  238. package/dist/core/importer/presence.js.map +1 -0
  239. package/dist/core/importer/settle.d.ts +23 -0
  240. package/dist/core/importer/settle.d.ts.map +1 -0
  241. package/dist/core/importer/settle.js +135 -0
  242. package/dist/core/importer/settle.js.map +1 -0
  243. package/dist/core/importer/statements.d.ts +4 -0
  244. package/dist/core/importer/statements.d.ts.map +1 -0
  245. package/dist/core/importer/statements.js +339 -0
  246. package/dist/core/importer/statements.js.map +1 -0
  247. package/dist/core/importer/syntax.d.ts +182 -0
  248. package/dist/core/importer/syntax.d.ts.map +1 -0
  249. package/dist/core/importer/syntax.js +14 -0
  250. package/dist/core/importer/syntax.js.map +1 -0
  251. package/dist/core/importer/table.d.ts +52 -0
  252. package/dist/core/importer/table.d.ts.map +1 -0
  253. package/dist/core/importer/table.js +156 -0
  254. package/dist/core/importer/table.js.map +1 -0
  255. package/dist/core/importer/values.d.ts +27 -0
  256. package/dist/core/importer/values.d.ts.map +1 -0
  257. package/dist/core/importer/values.js +236 -0
  258. package/dist/core/importer/values.js.map +1 -0
  259. package/dist/core/index.d.ts +22 -5
  260. package/dist/core/index.d.ts.map +1 -1
  261. package/dist/core/index.js +19 -3
  262. package/dist/core/index.js.map +1 -1
  263. package/dist/core/stdlib/calendar/civil.d.ts.map +1 -1
  264. package/dist/core/stdlib/calendar/civil.js +5 -2
  265. package/dist/core/stdlib/calendar/civil.js.map +1 -1
  266. package/dist/core/stdlib/index.d.ts +1 -1
  267. package/dist/core/stdlib/index.d.ts.map +1 -1
  268. package/dist/core/stdlib/index.js +1 -1
  269. package/dist/core/stdlib/index.js.map +1 -1
  270. package/dist/core/stdlib/maths/index.d.ts +1 -1
  271. package/dist/core/stdlib/maths/index.d.ts.map +1 -1
  272. package/dist/core/stdlib/maths/index.js +1 -1
  273. package/dist/core/stdlib/maths/index.js.map +1 -1
  274. package/dist/core/stdlib/maths/rounding.d.ts +5 -0
  275. package/dist/core/stdlib/maths/rounding.d.ts.map +1 -1
  276. package/dist/core/stdlib/maths/rounding.js +19 -1
  277. package/dist/core/stdlib/maths/rounding.js.map +1 -1
  278. package/dist/core/version/version.generated.d.ts +1 -1
  279. package/dist/core/version/version.generated.js +1 -1
  280. package/package.json +17 -2
  281. package/spec/README.md +2 -1
  282. package/spec/errors.json +383 -23
  283. package/src/adapters/charts/driving.ts +109 -0
  284. package/src/adapters/charts/run.ts +126 -28
  285. package/src/adapters/charts/tables.ts +6 -19
  286. package/src/adapters/charts/undrawable.ts +51 -0
  287. package/src/adapters/charts/venue.ts +132 -0
  288. package/src/core/accounting/analysis.ts +188 -0
  289. package/src/core/accounting/equity.ts +38 -0
  290. package/src/core/accounting/index.ts +2 -0
  291. package/src/core/accounting/report.ts +5 -0
  292. package/src/core/accounting/statistics.ts +38 -1
  293. package/src/core/backtest/case.ts +395 -0
  294. package/src/core/backtest/compare.ts +2 -0
  295. package/src/core/backtest/deliver.ts +161 -0
  296. package/src/core/backtest/drive.ts +233 -217
  297. package/src/core/backtest/index.ts +26 -12
  298. package/src/core/backtest/record.ts +134 -5
  299. package/src/core/backtest/replay.ts +11 -1
  300. package/src/core/backtest/simulate.ts +201 -6
  301. package/src/core/backtest/walk.ts +182 -0
  302. package/src/core/catalogue/catalogue.generated.ts +19 -2
  303. package/src/core/catalogue/types.ts +8 -2
  304. package/src/core/catalogue/values.generated.ts +16 -0
  305. package/src/core/check/assigned.ts +31 -0
  306. package/src/core/check/call-sites.ts +11 -4
  307. package/src/core/check/calls.ts +13 -4
  308. package/src/core/check/check.ts +14 -2
  309. package/src/core/check/checker.ts +39 -2
  310. package/src/core/check/constant.ts +57 -0
  311. package/src/core/check/deleted.ts +135 -0
  312. package/src/core/check/expressions.ts +1 -1
  313. package/src/core/check/library-orders.ts +2 -2
  314. package/src/core/check/library-output.ts +1 -0
  315. package/src/core/check/library-prose.generated.ts +12 -12
  316. package/src/core/check/library.ts +8 -0
  317. package/src/core/check/surface.ts +16 -0
  318. package/src/core/emit/canonical.ts +67 -9
  319. package/src/core/engine/arithmetic.ts +23 -3
  320. package/src/core/engine/bar-source.ts +113 -0
  321. package/src/core/engine/engine.ts +26 -25
  322. package/src/core/engine/guard.ts +12 -1
  323. package/src/core/engine/host.ts +4 -2
  324. package/src/core/engine/index.ts +2 -1
  325. package/src/core/engine/library/arrays.ts +8 -2
  326. package/src/core/engine/library/binding.ts +2 -0
  327. package/src/core/engine/library/code-points.ts +73 -0
  328. package/src/core/engine/library/index.ts +17 -0
  329. package/src/core/engine/library/objects.ts +1 -6
  330. package/src/core/engine/library/text.ts +53 -35
  331. package/src/core/engine/load.ts +68 -0
  332. package/src/core/engine/request-body.ts +5 -7
  333. package/src/core/engine/request-plan.ts +3 -3
  334. package/src/core/engine/requests.ts +11 -8
  335. package/src/core/engine/series.ts +30 -6
  336. package/src/core/engine/session/record.ts +4 -4
  337. package/src/core/engine/verify-tables.ts +43 -0
  338. package/src/core/importer/calls.ts +274 -0
  339. package/src/core/importer/context.ts +197 -0
  340. package/src/core/importer/expressions.ts +247 -0
  341. package/src/core/importer/importer.ts +226 -0
  342. package/src/core/importer/index.ts +19 -0
  343. package/src/core/importer/lexer.ts +285 -0
  344. package/src/core/importer/names.ts +104 -0
  345. package/src/core/importer/orders.ts +307 -0
  346. package/src/core/importer/outputs.ts +245 -0
  347. package/src/core/importer/parser.ts +436 -0
  348. package/src/core/importer/presence.ts +164 -0
  349. package/src/core/importer/settle.ts +141 -0
  350. package/src/core/importer/statements.ts +331 -0
  351. package/src/core/importer/syntax.ts +144 -0
  352. package/src/core/importer/table.ts +191 -0
  353. package/src/core/importer/values.ts +241 -0
  354. package/src/core/index.ts +29 -2
  355. package/src/core/stdlib/calendar/civil.ts +5 -2
  356. package/src/core/stdlib/index.ts +1 -0
  357. package/src/core/stdlib/maths/index.ts +1 -0
  358. package/src/core/stdlib/maths/rounding.ts +23 -1
  359. package/src/core/version/version.generated.ts +1 -1
@@ -25,51 +25,195 @@
25
25
  * is reported on bar k + 1. A frame answered after the last bar has no boundary
26
26
  * left to fold at: it is not delivered, it is not recorded as delivered, and
27
27
  * the order it was about is in the ledger at whatever it last said.
28
+ *
29
+ * **Two drivers, and the only difference between them is where the frames come
30
+ * from.** `backtest` runs against the simulated destination, which decides a
31
+ * fill from the bars and answers frames of its own; `backtestSupplied` is
32
+ * handed the frames and delivers those. Everything else about the two is one
33
+ * function below: the same window, the same load, the same refusals, the same
34
+ * loop and the same record.
28
35
  */
29
36
  import { reportOf, scheduleFromDeclaration } from '../accounting/index.js';
30
- import type { ChargeSchedule, RecordedFill } from '../accounting/index.js';
37
+ import type { ChargeSchedule, Contract } from '../accounting/index.js';
31
38
  import type { Diagnostic } from '../diagnostics/index.js';
32
39
  import type { CompiledProgram } from '../emit/index.js';
33
40
  import { load } from '../engine/index.js';
34
41
  import type {
35
- BarResult,
36
- Engine,
42
+ Drawing,
37
43
  EngineHost,
44
+ Grid,
38
45
  Instrument,
39
46
  LedgerRow,
40
- OrderFrame,
41
47
  OrderIntent,
48
+ RequestProvider,
42
49
  RoutedEffect,
50
+ Value,
43
51
  } from '../engine/index.js';
44
52
  import { declarationOf } from './declaration.js';
45
53
  import type { RunDeclaration } from './declaration.js';
54
+ import { Delivery, framedAs, ordinalsOf } from './deliver.js';
55
+ import type { Destination } from './deliver.js';
46
56
  import { marksFor, windowFor } from './range.js';
47
- import type { ReportWindow } from './range.js';
48
- import { diagnosticIn, orderIn, recordOf } from './record.js';
49
- import type {
50
- RecordedBar,
51
- RecordedDiagnostic,
52
- RecordedFrame,
53
- RecordedOrder,
54
- RunRecord,
55
- } from './record.js';
57
+ import { orderIn, recordOf } from './record.js';
58
+ import type { RecordedBar, RecordedFrame, RecordedOrder, RunRecord } from './record.js';
56
59
  import { Simulator } from './simulate.js';
57
60
  import { checkSettings } from './settings.js';
61
+ import { walk } from './walk.js';
62
+ import type { LogLine } from './walk.js';
58
63
  import type { BacktestSettings } from './settings.js';
59
64
 
60
65
  /** What a run came to, or why it could not be carried out at all. */
61
66
  export type BacktestResult =
62
- | { readonly ok: true; readonly record: RunRecord }
67
+ | {
68
+ readonly ok: true;
69
+ readonly record: RunRecord;
70
+ readonly rows?: readonly (readonly Value[])[];
71
+ readonly log?: readonly LogLine[];
72
+ readonly surface?: Surface;
73
+ }
63
74
  | { readonly ok: false; readonly diagnostic: Diagnostic };
64
75
 
76
+ /** The drawing objects and the grids the last bar left, `conformance.md` section 4. */
77
+ export interface Surface {
78
+ readonly drawings: readonly Drawing[];
79
+ readonly tables: readonly Grid[];
80
+ }
81
+
82
+ /**
83
+ * The facts of `host-interface.md` 4.1 that the contract does not hold.
84
+ *
85
+ * The contract already states six of the twelve, the ones the money is priced
86
+ * under, and a fact stated in two places is a fact that can disagree with
87
+ * itself: a tick size the engine rounds to and a different one the venue
88
+ * worsens a fill by is a run under two instruments. So the other six are
89
+ * stated here and the six the contract holds cannot be, which the compiler
90
+ * enforces rather than a check at run time.
91
+ */
92
+ export type InstrumentFacts = Omit<
93
+ Instrument,
94
+ 'symbol' | 'exchange' | 'tickSize' | 'lotSize' | 'pointValue' | 'currency'
95
+ >;
96
+
65
97
  /** The few choices a driver has that are not settings of the run itself. */
66
98
  export interface DriveOptions {
67
99
  /** Whether the bars travel in the record. Inline is the conformance form. */
68
100
  readonly form?: 'inline' | 'referenced';
101
+ /**
102
+ * What the host states about the instrument beside the contract, so the
103
+ * record it produces is a conformance case.
104
+ *
105
+ * A case holds `instrument.json`, which `conformance.md` section 2 says is
106
+ * the record of `host-interface.md` 4.1, and that page requires one fact of
107
+ * every host: `hasVolume`, because no derivation recovers it (4.2). The
108
+ * engine reads the record and does not refuse a run without it, so a caller
109
+ * that leaves this out gets a record that replays and reruns like any other
110
+ * and cannot become a case, exactly as one without `sourceText` cannot.
111
+ *
112
+ * A session stated without a timezone is refused at load, OS6012, by the
113
+ * same rule that refuses it for any host.
114
+ */
115
+ readonly instrument?: InstrumentFacts;
116
+ /**
117
+ * The script's own text, so the record it produces is a conformance case.
118
+ *
119
+ * A compiled program identifies its source and cannot reproduce it, and a
120
+ * case has to hold `script.os`. A caller holding only a program leaves this
121
+ * out and gets a record that replays and reruns like any other; the one
122
+ * thing it cannot do is be handed to somebody else's engine as a case.
123
+ *
124
+ * It is checked against the program's own source hash, so text from a
125
+ * different revision than the one that was compiled is refused rather than
126
+ * written into a case that could never make its own expected output.
127
+ */
128
+ readonly sourceText?: string;
129
+ /**
130
+ * Whether to hand back every channel's value on every bar that ran, beside
131
+ * the record rather than inside it.
132
+ *
133
+ * A conformance case that asserts `values` compares one value per bar per
134
+ * plot, and the record holds none of them: it is the reproducible run, and a
135
+ * curve per plot is bytes it would carry for every run to serve the few cases
136
+ * that ask. So the rows are asked for, and a run that does not ask pays
137
+ * nothing. A bar that failed has no row, as in the second engine.
138
+ */
139
+ readonly rows?: boolean;
140
+ /** Whether to hand back every line `print` wrote, beside the record, for the same reason. */
141
+ readonly log?: boolean;
142
+ /** Whether to hand back the drawing objects and grids the last bar left, for the same reason. */
143
+ readonly surface?: boolean;
144
+ /**
145
+ * Bars for another instrument, `host-interface.md` 5, for a run whose host
146
+ * serves them.
147
+ *
148
+ * Left out, the run holds the chart's own bars and nothing else: a read of
149
+ * the chart's instrument at a coarser interval is folded from them, and a
150
+ * program that reads another instrument declares a capability this host does
151
+ * not have and is refused at load by name. Given, the host serves duty 3 and
152
+ * the engine asks it once per read, before bar 0.
153
+ */
154
+ readonly requestBars?: RequestProvider;
69
155
  }
70
156
 
157
+
71
158
  /**
72
- * One run, from a compiled program to a record of it.
159
+ * One run against a simulated destination, from a compiled program to a record.
160
+ *
161
+ * The frames are the destination's own: it is handed the orders, it reads the
162
+ * bars, and what it answers is what the engine folds. A run whose frames
163
+ * somebody else is supplying is `backtestSupplied` below.
164
+ */
165
+ export function backtest(
166
+ program: CompiledProgram,
167
+ bars: readonly RecordedBar[],
168
+ settings: BacktestSettings,
169
+ options: DriveOptions = {},
170
+ ): BacktestResult {
171
+ return drive(program, bars, settings, options, (declared, schedule) =>
172
+ simulated(
173
+ new Simulator({
174
+ bars,
175
+ contract: settings.contract,
176
+ fill: settings.fill,
177
+ slippageTicks: schedule.slippageTicks,
178
+ fillOn: declared.fillOn,
179
+ qtyType: declared.qtyType,
180
+ }),
181
+ ),
182
+ );
183
+ }
184
+
185
+ /**
186
+ * One run over the frames somebody else supplied, which this engine does not
187
+ * choose and does not add to.
188
+ *
189
+ * `conformance.md` section 3 gives a case a `frames.csv` that supplies order
190
+ * frames the way `bars.csv` supplies bars, so that a case asserts the fold
191
+ * against input the engine did not choose. Every other argument is `backtest`'s
192
+ * and means there what it means here. A row is delivered at the boundary it
193
+ * names and folded before the next bar, and the record carries the rows it was
194
+ * handed rather than a second spelling of them.
195
+ *
196
+ * **Nothing is invented.** No fill is priced off a bar, no order rests and no
197
+ * schedule is read, so an order the frames say nothing about stays where its
198
+ * placement left it, which is what a case saying nothing about it means.
199
+ *
200
+ * **A record made here is a record of this run and not of a simulated one.**
201
+ * `rerun` puts a record's program back on a simulated destination, because a
202
+ * record does not say which of the two answered it, so a rerun of one of these
203
+ * reproduces it only where that destination would answer these same frames.
204
+ */
205
+ export function backtestSupplied(
206
+ program: CompiledProgram,
207
+ bars: readonly RecordedBar[],
208
+ settings: BacktestSettings,
209
+ frames: readonly RecordedFrame[],
210
+ options: DriveOptions = {},
211
+ ): BacktestResult {
212
+ return drive(program, bars, settings, options, () => new Delivery(frames));
213
+ }
214
+
215
+ /**
216
+ * The run both drivers are, and the one place a record is made.
73
217
  *
74
218
  * A refusal before the first bar comes back as a refusal and not as a record:
75
219
  * a program that would not load, a setting that cannot be applied and a window
@@ -77,24 +221,33 @@ export interface DriveOptions {
77
221
  * be a document asserting figures nothing computed. A failure during a bar is
78
222
  * the other way round: the run happened, it stopped, and the record carries
79
223
  * both what it did and the diagnostic that stopped it.
224
+ *
225
+ * **The destination is chosen after the program is loaded**, which is why it
226
+ * arrives as a function of the declaration and the schedule: the bar a market
227
+ * order is priced at is the declaration's, and the declaration is resolved at
228
+ * load. The route is wired first and reaches whatever is chosen through the
229
+ * binding below, which is what lets one host serve both halves.
80
230
  */
81
- export function backtest(
231
+ function drive(
82
232
  program: CompiledProgram,
83
233
  bars: readonly RecordedBar[],
84
234
  settings: BacktestSettings,
85
- options: DriveOptions = {},
235
+ options: DriveOptions,
236
+ choose: (declared: RunDeclaration, schedule: ChargeSchedule) => Destination,
86
237
  ): BacktestResult {
87
238
  const framed = windowFor(bars, settings.range);
88
239
  if (!framed.ok) return { ok: false, diagnostic: framed.diagnostic };
89
240
 
90
- // The venue is built after the program is loaded, because the bar a market
91
- // order is priced at is the declaration's and the declaration is resolved at
92
- // load. The route is wired first and reaches it through this binding, which
93
- // is what lets one host serve both halves.
94
- let venue: Simulator | undefined;
241
+ let sending: Destination | undefined;
242
+ const instrument = instrumentFor(settings.contract, options.instrument ?? {});
95
243
  const loaded = load(program, {
96
244
  settings: settings.inputs,
97
- host: hostFor(settings, (effect, bar) => venue?.route(effect, bar)),
245
+ host: hostFor(
246
+ instrument,
247
+ settings.now,
248
+ (effect, bar) => sending?.route(effect, bar),
249
+ options.requestBars,
250
+ ),
98
251
  });
99
252
  if (!loaded.ok) return { ok: false, diagnostic: loaded.diagnostic };
100
253
 
@@ -104,204 +257,44 @@ export function backtest(
104
257
  if (problem !== null) return { ok: false, diagnostic: problem };
105
258
 
106
259
  const schedule = scheduleFor(settings, declared);
107
- venue = new Simulator({
108
- bars,
109
- contract: settings.contract,
110
- fill: settings.fill,
111
- slippageTicks: schedule.slippageTicks,
112
- fillOn: declared.fillOn,
113
- qtyType: declared.qtyType,
114
- });
260
+ const destination = choose(declared, schedule);
261
+ sending = destination;
115
262
 
116
- const run = walk(engine, venue, bars, framed.covered);
117
- const ordinals = ordinalsOf(venue.intents);
263
+ const run = walk(engine, destination, bars, framed.covered, options);
264
+ const ordinals = ordinalsOf(destination.intents);
118
265
  const marks = marksFor(bars, framed.covered);
119
266
 
120
267
  return {
121
268
  ok: true,
269
+ ...(options.rows === true ? { rows: run.rows } : {}),
270
+ ...(options.log === true ? { log: run.log } : {}),
271
+ ...(options.surface === true ? { surface: { drawings: engine.drawings(), tables: engine.tables() } } : {}),
122
272
  record: recordOf({
123
273
  program: engine.program,
274
+ ...(options.sourceText === undefined ? {} : { sourceText: options.sourceText }),
124
275
  settings,
276
+ instrument,
125
277
  bars,
126
278
  form: options.form ?? 'inline',
127
- frames: run.frames.map((one) => framedAs(one.frame, one.afterBar, ordinals)),
279
+ // The row where a case supplied one, because that row is the input and a
280
+ // record of a run over it says what it was given rather than what it
281
+ // would have written down had it decided the frame itself.
282
+ frames: run.frames.map((one) => one.row ?? framedAs(one.frame, one.afterBar, ordinals)),
128
283
  fills: run.fills,
129
- orders: ordersOf(engine.orders(), venue.intents, ordinals),
284
+ orders: ordersOf(engine.orders(), destination.intents, ordinals),
130
285
  diagnostics: run.diagnostics,
131
286
  report: reportOf(run.fills, marks, schedule, settings.contract, declared.capital),
132
287
  }),
133
288
  };
134
289
  }
135
290
 
136
- /** A frame, and the boundary it was handed over at. */
137
- interface Delivered {
138
- readonly frame: OrderFrame;
139
- readonly afterBar: number;
140
- }
141
-
142
- /** What one walk of the bars produced. */
143
- interface Walked {
144
- readonly fills: readonly RecordedFill[];
145
- readonly frames: readonly Delivered[];
146
- readonly diagnostics: readonly RecordedDiagnostic[];
147
- }
148
-
149
- /**
150
- * The bars, in order, with the venue answering between them.
151
- *
152
- * The one ordering rule: deliver, then append, then collect what the append
153
- * reported, then ask the venue what this bar did. A driver that asked the venue
154
- * before appending would price a fill against a bar the strategy had not seen.
155
- */
156
- function walk(
157
- engine: Engine,
158
- venue: Simulator,
159
- bars: readonly RecordedBar[],
160
- covered: ReportWindow,
161
- ): Walked {
162
- const fills: RecordedFill[] = [];
163
- const frames: Delivered[] = [];
164
- const diagnostics: RecordedDiagnostic[] = [];
165
- const intents = new Map<number, OrderIntent>();
166
- const refs = new Map<number, string>();
167
- const sizes = new Map<number, number>();
168
-
169
- let pending: readonly Delivered[] = [];
170
- let seq = 0;
171
-
172
- for (let index = 0; index < covered.total; index += 1) {
173
- const bar = bars[index];
174
- if (bar === undefined) continue;
175
-
176
- for (const one of pending) {
177
- const ref = one.frame.orderRef;
178
- if (typeof ref === 'string') refs.set(one.frame.intentId, ref);
179
- engine.deliver(one.frame);
180
- frames.push(one);
181
- }
182
- pending = [];
183
-
184
- const result = engine.append(
185
- { time: bar.time, open: bar.open, high: bar.high, low: bar.low, close: bar.close,
186
- volume: bar.volume, oi: bar.oi },
187
- { isConfirmed: true, isRealtime: false },
188
- covered.total,
189
- );
190
-
191
- for (const intent of intentsIn(result)) intents.set(intent.intentId, intent);
192
- seq = settle(result, index, bar, { intents, refs, sizes }, fills, seq);
193
-
194
- if (result.diagnostic !== undefined) {
195
- diagnostics.push(diagnosticIn(result.diagnostic, index));
196
- break;
197
- }
198
-
199
- pending = venue.framesFor(index).map((frame) => ({ frame, afterBar: index }));
200
- }
201
-
202
- return { fills, frames, diagnostics };
203
- }
204
-
205
- /** What the run is holding while it folds one bar's frames into fills. */
206
- interface Books {
207
- readonly intents: ReadonlyMap<number, OrderIntent>;
208
- readonly refs: ReadonlyMap<number, string>;
209
- readonly sizes: Map<number, number>;
210
- }
211
-
212
- /**
213
- * The fills one bar's fold settled.
214
- *
215
- * **The position sizes either side of step 6 are kept here and not read back
216
- * from the engine**, because the engine reports a leg's net and a fill settles
217
- * against one position reference: the two are different numbers whenever a leg
218
- * holds more than one position, which is every flip. They are folded in the
219
- * order the frames were folded in, from the same deltas, so they are the same
220
- * arithmetic the position book did rather than a second reading of its result.
221
- * When `FrameOutcome` carries them, these two lines come from the engine and
222
- * this fold keeps only the sequence number.
223
- *
224
- * A refused frame settles nothing and is not a fill. Today the fold reports the
225
- * refusal as a word rather than a code, so nothing here can write it into the
226
- * record as a diagnostic; that is OS7018 and OS7019, and both are deferred.
227
- */
228
- function settle(
229
- result: BarResult,
230
- index: number,
231
- bar: RecordedBar,
232
- books: Books,
233
- fills: RecordedFill[],
234
- from: number,
235
- ): number {
236
- let seq = from;
237
- for (const outcome of result.frames) {
238
- if (outcome.refused !== undefined) continue;
239
- if (outcome.delta <= 0 || outcome.price === null) continue;
240
- const intent = books.intents.get(outcome.intentId);
241
- if (intent === undefined || intent.side === null) continue;
242
-
243
- const before = books.sizes.get(intent.positionRef) ?? 0;
244
- const after = before + (intent.side === 'sell' ? -outcome.delta : outcome.delta);
245
- books.sizes.set(intent.positionRef, after);
246
- seq += 1;
247
-
248
- fills.push({
249
- seq,
250
- intentId: outcome.intentId,
251
- orderRef: books.refs.get(outcome.intentId) ?? '',
252
- tag: intent.tag,
253
- positionRef: intent.positionRef,
254
- side: intent.side,
255
- units: outcome.delta,
256
- price: outcome.price,
257
- // The bar the fold happened at, which is the bar the position exists
258
- // from. Where the fill itself traded is the bar before it or this bar's
259
- // own open, and neither is a bar the strategy could have acted on it in.
260
- barIndex: index,
261
- barTime: bar.time,
262
- refSizeBefore: before,
263
- refSizeAfter: after,
264
- });
265
- }
266
- return seq;
267
- }
268
-
269
- /** Every intent one bar handed over, in the order the bar applied them. */
270
- function intentsIn(result: BarResult): readonly OrderIntent[] {
271
- const out: OrderIntent[] = [];
272
- for (const effect of result.effects) for (const intent of effect.intents) out.push(intent);
273
- return out;
274
- }
275
-
276
- /**
277
- * The ordinal of every intent, which is how a case names one.
278
- *
279
- * One, two, three in the order the run placed them, because no engine can know
280
- * the id another minted and a case that named one would only ever be readable
281
- * by the engine that wrote it.
282
- */
283
- function ordinalsOf(intents: readonly OrderIntent[]): ReadonlyMap<number, number> {
284
- const out = new Map<number, number>();
285
- for (const intent of intents) {
286
- if (!out.has(intent.intentId)) out.set(intent.intentId, out.size + 1);
287
- }
288
- return out;
289
- }
290
-
291
- /** One delivered frame, in the columns a case file prints. */
292
- function framedAs(
293
- frame: OrderFrame,
294
- afterBar: number,
295
- ordinals: ReadonlyMap<number, number>,
296
- ): RecordedFrame {
291
+ /** The simulated destination, as a destination the loop below can drive. */
292
+ function simulated(venue: Simulator): Destination {
297
293
  return {
298
- afterBar,
299
- intent: ordinals.get(frame.intentId) ?? 0,
300
- status: frame.status,
301
- filledQty: frame.filledQty,
302
- avgFillPrice: frame.avgFillPrice ?? null,
303
- orderRef: frame.orderRef ?? null,
304
- text: frame.text ?? null,
294
+ route: (effect, barIndex) => venue.route(effect, barIndex),
295
+ answers: (barIndex) =>
296
+ venue.framesFor(barIndex).map((frame) => ({ frame, afterBar: barIndex, row: null })),
297
+ intents: venue.intents,
305
298
  };
306
299
  }
307
300
 
@@ -336,29 +329,52 @@ function scheduleFor(settings: BacktestSettings, declared: RunDeclaration): Char
336
329
  );
337
330
  }
338
331
 
332
+ /**
333
+ * The instrument record of `host-interface.md` 4.1 the engine is handed, and
334
+ * the record carries verbatim.
335
+ *
336
+ * Composed once, here, from the contract's six facts and the six stated beside
337
+ * it, so the engine and the record read one document and there is no second
338
+ * composition for the two to disagree by. A fact nobody stated is left out
339
+ * rather than written as undefined: the record travels as JSON, which drops an
340
+ * undefined member, and a document that changes shape in transit is not the
341
+ * document the engine read.
342
+ */
343
+ function instrumentFor(contract: Contract, facts: InstrumentFacts): Instrument {
344
+ return {
345
+ ...(contract.symbol === null ? {} : { symbol: contract.symbol }),
346
+ ...(contract.exchange === null ? {} : { exchange: contract.exchange }),
347
+ ...(facts.interval === undefined ? {} : { interval: facts.interval }),
348
+ ...(facts.timezone === undefined ? {} : { timezone: facts.timezone }),
349
+ ...(contract.tickSize === null ? {} : { tickSize: contract.tickSize }),
350
+ ...(contract.lotSize === null ? {} : { lotSize: contract.lotSize }),
351
+ pointValue: contract.pointValue,
352
+ currency: contract.currency,
353
+ ...(facts.instrumentType === undefined ? {} : { instrumentType: facts.instrumentType }),
354
+ ...(facts.hasVolume === undefined ? {} : { hasVolume: facts.hasVolume }),
355
+ ...(facts.hasOpenInterest === undefined ? {} : { hasOpenInterest: facts.hasOpenInterest }),
356
+ ...(facts.session === undefined ? {} : { session: facts.session }),
357
+ };
358
+ }
359
+
339
360
  /**
340
361
  * The host a backtest is: an instrument record, a clock and a destination.
341
362
  *
342
- * Duty 3 is not served. A backtest holds the chart's own bars and nothing else,
343
- * so a program that reads another instrument declares a capability this host
344
- * does not have and is refused at load, by name, rather than drawing a line
345
- * with nothing in it.
363
+ * Duty 3 is served only when the caller supplied bars for it. A backtest with
364
+ * none holds the chart's own bars and nothing else, so a program that reads
365
+ * another instrument declares a capability this host does not have and is
366
+ * refused at load, by name, rather than drawing a line with nothing in it.
346
367
  */
347
368
  function hostFor(
348
- settings: BacktestSettings,
369
+ instrument: Instrument,
370
+ now: number | null,
349
371
  route: (effect: RoutedEffect, bar: number) => void,
372
+ requestBars: RequestProvider | undefined,
350
373
  ): EngineHost {
351
- const instrument: Instrument = {
352
- ...(settings.contract.symbol === null ? {} : { symbol: settings.contract.symbol }),
353
- ...(settings.contract.exchange === null ? {} : { exchange: settings.contract.exchange }),
354
- ...(settings.contract.tickSize === null ? {} : { tickSize: settings.contract.tickSize }),
355
- ...(settings.contract.lotSize === null ? {} : { lotSize: settings.contract.lotSize }),
356
- pointValue: settings.contract.pointValue,
357
- currency: settings.contract.currency,
358
- };
359
374
  return {
360
375
  instrument,
361
- ...(settings.now === null ? {} : { now: settings.now }),
376
+ ...(now === null ? {} : { now }),
362
377
  route,
378
+ ...(requestBars === undefined ? {} : { requestBars }),
363
379
  };
364
380
  }
@@ -14,18 +14,30 @@
14
14
  * worsened by a tick and a fill is charged. The engine never adjusts a price and
15
15
  * this module never folds one.
16
16
  *
17
- * `backtest` drives one, `replay` folds a stored one's money again from its own
18
- * fills, and `rerun` executes a stored one again and is held to producing the
19
- * same bytes. `recordToJson` and `recordFromJson` are the document itself.
20
- * `compareRuns` puts two records beside each other and says whether the gap
21
- * between them clears the noise. `caseFilesFrom` is named by the design and is
22
- * not here yet: it will return text and write nothing, because core does no
23
- * I/O, and it needs a channel the record does not carry today. `conformance.md`
24
- * section 2 requires a case to hold `script.os`, the source text, and a record
25
- * carries only the source's hash, its line count and its file name.
17
+ * `backtest` drives one against a simulated destination and `backtestSupplied`
18
+ * drives one over frames somebody else supplied, which is what `conformance.md`
19
+ * section 3 asks of an engine running a case. `replay` folds a stored one's
20
+ * money again from its own fills, and `rerun` executes a stored one again and
21
+ * is held to producing the same bytes. `recordToJson` and `recordFromJson` are
22
+ * the document itself. `compareRuns` puts two records beside each other and
23
+ * says whether the gap between them clears the noise. `caseFilesFrom` turns a
24
+ * record into the files of a conformance case, returning text and writing
25
+ * nothing because core does no I/O. It needed three channels the record did not
26
+ * carry. `conformance.md` section 2 requires a case to hold `script.os`, the
27
+ * source text, and a record carried only the source's hash, its line count and
28
+ * its file name: record version 2 carries the text, checked against that hash.
29
+ * The same section says `instrument.json` is the record of `host-interface.md`
30
+ * 4.1, and a record carried the money layer's contract, which holds six of its
31
+ * twelve facts: record version 3 carries the record the engine was handed,
32
+ * whole. And a case is handed frames, which `stdlib.md` 17.7 folds one ledger
33
+ * field from an instant of: a record carried a frame without the instant it
34
+ * arrived at, so a case projected from it asserted a field its own input could
35
+ * not reproduce. Record version 4 carries a frame's time.
26
36
  */
27
- export { backtest } from './drive.js';
28
- export type { BacktestResult, DriveOptions } from './drive.js';
37
+ export { backtest, backtestSupplied } from './drive.js';
38
+ export type { BacktestResult, DriveOptions, InstrumentFacts } from './drive.js';
39
+ export type { LogLine } from './walk.js';
40
+ export type { Surface } from './drive.js';
29
41
  export { declarationOf } from './declaration.js';
30
42
  export type { RunDeclaration } from './declaration.js';
31
43
  export { marksFor, windowFor } from './range.js';
@@ -35,8 +47,10 @@ export type { ReplayResult } from './replay.js';
35
47
  export { testResting } from './resting.js';
36
48
  export type { RestOutcome, RestingOrder } from './resting.js';
37
49
  export { Simulator } from './simulate.js';
38
- export type { SimulatorOptions } from './simulate.js';
50
+ export type { SimulatorOptions, VenueAct, VenueDoes, VenuePolicy } from './simulate.js';
39
51
  export { DEFAULT_FILL, EXACT, WHOLE_RANGE, checkSettings, settingsFor } from './settings.js';
52
+ export { caseFilesFrom } from './case.js';
53
+ export type { CaseFiles, CaseIdentity, CaseResult } from './case.js';
40
54
  export { RECORD_VERSION, barsHash, recordFromJson, recordOf, recordToJson, runBytes } from './record.js';
41
55
  export type { RecordParts } from './record.js';
42
56
  export type { BacktestSettings, DateRange, FillPolicy, Tolerance } from './settings.js';