openbacktesting 0.2.0__py3-none-any.whl

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 (350) hide show
  1. openbacktesting/__init__.py +85 -0
  2. openbacktesting/aggregation.py +8 -0
  3. openbacktesting/broker/__init__.py +54 -0
  4. openbacktesting/broker/commission.py +57 -0
  5. openbacktesting/broker/core.py +1122 -0
  6. openbacktesting/broker/execution.py +62 -0
  7. openbacktesting/broker/instrument.py +106 -0
  8. openbacktesting/broker/ledger.py +60 -0
  9. openbacktesting/broker/models.py +236 -0
  10. openbacktesting/broker/observations.py +99 -0
  11. openbacktesting/broker/requests.py +192 -0
  12. openbacktesting/broker/sizing.py +76 -0
  13. openbacktesting/colors.py +175 -0
  14. openbacktesting/data/__init__.py +20 -0
  15. openbacktesting/data/aggregation.py +39 -0
  16. openbacktesting/data/context.py +30 -0
  17. openbacktesting/data/core.py +218 -0
  18. openbacktesting/data/generators.py +54 -0
  19. openbacktesting/data/strategy_data.py +103 -0
  20. openbacktesting/data/timeframe.py +69 -0
  21. openbacktesting/engine.py +34 -0
  22. openbacktesting/helpers.py +77 -0
  23. openbacktesting/indicator_api.py +10 -0
  24. openbacktesting/indicator_methods.py +123 -0
  25. openbacktesting/indicator_types.py +19 -0
  26. openbacktesting/indicators/__init__.py +7 -0
  27. openbacktesting/indicators/api.py +97 -0
  28. openbacktesting/indicators/calculus.py +75 -0
  29. openbacktesting/indicators/candles/__init__.py +0 -0
  30. openbacktesting/indicators/candles/cdl_doji.py +17 -0
  31. openbacktesting/indicators/candles/cdl_engulfing.py +14 -0
  32. openbacktesting/indicators/candles/cdl_eveningstar.py +15 -0
  33. openbacktesting/indicators/candles/cdl_hammer.py +14 -0
  34. openbacktesting/indicators/candles/cdl_harami.py +14 -0
  35. openbacktesting/indicators/candles/cdl_inside.py +14 -0
  36. openbacktesting/indicators/candles/cdl_marubozu.py +14 -0
  37. openbacktesting/indicators/candles/cdl_morningstar.py +15 -0
  38. openbacktesting/indicators/candles/cdl_shootingstar.py +14 -0
  39. openbacktesting/indicators/candles/cdl_z.py +28 -0
  40. openbacktesting/indicators/candles/ha.py +19 -0
  41. openbacktesting/indicators/catalog.json +8348 -0
  42. openbacktesting/indicators/common.py +94 -0
  43. openbacktesting/indicators/cycles/__init__.py +0 -0
  44. openbacktesting/indicators/cycles/dsp.py +10 -0
  45. openbacktesting/indicators/cycles/ebsw.py +10 -0
  46. openbacktesting/indicators/cycles/ht_dcperiod.py +10 -0
  47. openbacktesting/indicators/cycles/ht_dcphase.py +10 -0
  48. openbacktesting/indicators/cycles/ht_phasor.py +17 -0
  49. openbacktesting/indicators/cycles/ht_sine.py +17 -0
  50. openbacktesting/indicators/cycles/ht_trendmode.py +10 -0
  51. openbacktesting/indicators/cycles/msw.py +19 -0
  52. openbacktesting/indicators/methods.py +5762 -0
  53. openbacktesting/indicators/momentum/__init__.py +0 -0
  54. openbacktesting/indicators/momentum/ac.py +9 -0
  55. openbacktesting/indicators/momentum/ao.py +10 -0
  56. openbacktesting/indicators/momentum/apo.py +10 -0
  57. openbacktesting/indicators/momentum/bias.py +10 -0
  58. openbacktesting/indicators/momentum/bop.py +10 -0
  59. openbacktesting/indicators/momentum/brar.py +26 -0
  60. openbacktesting/indicators/momentum/cci.py +10 -0
  61. openbacktesting/indicators/momentum/cfo.py +10 -0
  62. openbacktesting/indicators/momentum/cg.py +10 -0
  63. openbacktesting/indicators/momentum/cmo.py +10 -0
  64. openbacktesting/indicators/momentum/coppock.py +10 -0
  65. openbacktesting/indicators/momentum/crsi.py +28 -0
  66. openbacktesting/indicators/momentum/cti.py +10 -0
  67. openbacktesting/indicators/momentum/dm.py +17 -0
  68. openbacktesting/indicators/momentum/er.py +10 -0
  69. openbacktesting/indicators/momentum/eri.py +17 -0
  70. openbacktesting/indicators/momentum/fisher.py +17 -0
  71. openbacktesting/indicators/momentum/fosc.py +10 -0
  72. openbacktesting/indicators/momentum/gator.py +13 -0
  73. openbacktesting/indicators/momentum/ibs.py +7 -0
  74. openbacktesting/indicators/momentum/inertia.py +22 -0
  75. openbacktesting/indicators/momentum/kdj.py +18 -0
  76. openbacktesting/indicators/momentum/kst.py +30 -0
  77. openbacktesting/indicators/momentum/lrsi.py +10 -0
  78. openbacktesting/indicators/momentum/macd.py +27 -0
  79. openbacktesting/indicators/momentum/macdext.py +27 -0
  80. openbacktesting/indicators/momentum/macdfix.py +18 -0
  81. openbacktesting/indicators/momentum/mom.py +10 -0
  82. openbacktesting/indicators/momentum/pgo.py +10 -0
  83. openbacktesting/indicators/momentum/pmo.py +13 -0
  84. openbacktesting/indicators/momentum/po.py +10 -0
  85. openbacktesting/indicators/momentum/ppo.py +20 -0
  86. openbacktesting/indicators/momentum/psl.py +12 -0
  87. openbacktesting/indicators/momentum/pvo.py +20 -0
  88. openbacktesting/indicators/momentum/qqe.py +31 -0
  89. openbacktesting/indicators/momentum/rci.py +20 -0
  90. openbacktesting/indicators/momentum/rmi.py +7 -0
  91. openbacktesting/indicators/momentum/roc.py +10 -0
  92. openbacktesting/indicators/momentum/rocp.py +10 -0
  93. openbacktesting/indicators/momentum/rocr.py +10 -0
  94. openbacktesting/indicators/momentum/rocr100.py +10 -0
  95. openbacktesting/indicators/momentum/rsi.py +10 -0
  96. openbacktesting/indicators/momentum/rsx.py +10 -0
  97. openbacktesting/indicators/momentum/rvgi.py +26 -0
  98. openbacktesting/indicators/momentum/slope.py +17 -0
  99. openbacktesting/indicators/momentum/smc_sweep.py +18 -0
  100. openbacktesting/indicators/momentum/smi.py +21 -0
  101. openbacktesting/indicators/momentum/smi_stochastic.py +15 -0
  102. openbacktesting/indicators/momentum/squeeze.py +47 -0
  103. openbacktesting/indicators/momentum/squeeze_pro.py +53 -0
  104. openbacktesting/indicators/momentum/stc.py +20 -0
  105. openbacktesting/indicators/momentum/stoch.py +19 -0
  106. openbacktesting/indicators/momentum/stochf.py +19 -0
  107. openbacktesting/indicators/momentum/stochrsi.py +19 -0
  108. openbacktesting/indicators/momentum/td_seq.py +17 -0
  109. openbacktesting/indicators/momentum/trix.py +19 -0
  110. openbacktesting/indicators/momentum/trixh.py +20 -0
  111. openbacktesting/indicators/momentum/tsi.py +26 -0
  112. openbacktesting/indicators/momentum/uo.py +22 -0
  113. openbacktesting/indicators/momentum/vwmacd.py +20 -0
  114. openbacktesting/indicators/momentum/wavetrend.py +15 -0
  115. openbacktesting/indicators/momentum/willr.py +10 -0
  116. openbacktesting/indicators/overlap/__init__.py +0 -0
  117. openbacktesting/indicators/overlap/alligator.py +13 -0
  118. openbacktesting/indicators/overlap/alma.py +33 -0
  119. openbacktesting/indicators/overlap/anchored_vwap.py +50 -0
  120. openbacktesting/indicators/overlap/anchored_vwap_bands.py +13 -0
  121. openbacktesting/indicators/overlap/avgprice.py +10 -0
  122. openbacktesting/indicators/overlap/dema.py +10 -0
  123. openbacktesting/indicators/overlap/ema.py +12 -0
  124. openbacktesting/indicators/overlap/frama.py +29 -0
  125. openbacktesting/indicators/overlap/fwma.py +10 -0
  126. openbacktesting/indicators/overlap/hilo.py +26 -0
  127. openbacktesting/indicators/overlap/hl2.py +10 -0
  128. openbacktesting/indicators/overlap/hlc3.py +10 -0
  129. openbacktesting/indicators/overlap/hma.py +10 -0
  130. openbacktesting/indicators/overlap/ht_trendline.py +10 -0
  131. openbacktesting/indicators/overlap/hwma.py +10 -0
  132. openbacktesting/indicators/overlap/ichimoku.py +44 -0
  133. openbacktesting/indicators/overlap/jma.py +10 -0
  134. openbacktesting/indicators/overlap/kama.py +10 -0
  135. openbacktesting/indicators/overlap/linreg.py +15 -0
  136. openbacktesting/indicators/overlap/linregangle.py +10 -0
  137. openbacktesting/indicators/overlap/linregintercept.py +10 -0
  138. openbacktesting/indicators/overlap/linregslope.py +10 -0
  139. openbacktesting/indicators/overlap/ma.py +10 -0
  140. openbacktesting/indicators/overlap/ma_envelopes.py +16 -0
  141. openbacktesting/indicators/overlap/mama.py +17 -0
  142. openbacktesting/indicators/overlap/mavp.py +17 -0
  143. openbacktesting/indicators/overlap/mcgd.py +10 -0
  144. openbacktesting/indicators/overlap/medprice.py +10 -0
  145. openbacktesting/indicators/overlap/midpoint.py +10 -0
  146. openbacktesting/indicators/overlap/midprice.py +10 -0
  147. openbacktesting/indicators/overlap/mmar.py +21 -0
  148. openbacktesting/indicators/overlap/ohlc4.py +10 -0
  149. openbacktesting/indicators/overlap/pwma.py +10 -0
  150. openbacktesting/indicators/overlap/rainbow.py +25 -0
  151. openbacktesting/indicators/overlap/rma.py +10 -0
  152. openbacktesting/indicators/overlap/sinwma.py +10 -0
  153. openbacktesting/indicators/overlap/sma.py +14 -0
  154. openbacktesting/indicators/overlap/ssf.py +10 -0
  155. openbacktesting/indicators/overlap/supertrend.py +21 -0
  156. openbacktesting/indicators/overlap/swma.py +10 -0
  157. openbacktesting/indicators/overlap/t3.py +10 -0
  158. openbacktesting/indicators/overlap/tema.py +10 -0
  159. openbacktesting/indicators/overlap/trima.py +10 -0
  160. openbacktesting/indicators/overlap/tsf.py +10 -0
  161. openbacktesting/indicators/overlap/typprice.py +10 -0
  162. openbacktesting/indicators/overlap/vidya.py +10 -0
  163. openbacktesting/indicators/overlap/vwap.py +10 -0
  164. openbacktesting/indicators/overlap/vwma.py +10 -0
  165. openbacktesting/indicators/overlap/wcp.py +10 -0
  166. openbacktesting/indicators/overlap/wma.py +10 -0
  167. openbacktesting/indicators/overlap/zlma.py +10 -0
  168. openbacktesting/indicators/performance/__init__.py +0 -0
  169. openbacktesting/indicators/performance/drawdown.py +18 -0
  170. openbacktesting/indicators/performance/log_return.py +10 -0
  171. openbacktesting/indicators/performance/percent_return.py +10 -0
  172. openbacktesting/indicators/predicates.py +88 -0
  173. openbacktesting/indicators/registry.py +571 -0
  174. openbacktesting/indicators/runtime.py +290 -0
  175. openbacktesting/indicators/statistics/__init__.py +0 -0
  176. openbacktesting/indicators/statistics/beta.py +10 -0
  177. openbacktesting/indicators/statistics/correl.py +10 -0
  178. openbacktesting/indicators/statistics/entropy.py +10 -0
  179. openbacktesting/indicators/statistics/kurtosis.py +10 -0
  180. openbacktesting/indicators/statistics/mad.py +10 -0
  181. openbacktesting/indicators/statistics/md.py +10 -0
  182. openbacktesting/indicators/statistics/median.py +10 -0
  183. openbacktesting/indicators/statistics/mode.py +48 -0
  184. openbacktesting/indicators/statistics/quantile.py +10 -0
  185. openbacktesting/indicators/statistics/skew.py +10 -0
  186. openbacktesting/indicators/statistics/stderr.py +10 -0
  187. openbacktesting/indicators/statistics/stdev.py +10 -0
  188. openbacktesting/indicators/statistics/variance.py +10 -0
  189. openbacktesting/indicators/statistics/zscore.py +10 -0
  190. openbacktesting/indicators/trend/__init__.py +0 -0
  191. openbacktesting/indicators/trend/adx.py +28 -0
  192. openbacktesting/indicators/trend/adxr.py +28 -0
  193. openbacktesting/indicators/trend/amat.py +19 -0
  194. openbacktesting/indicators/trend/aroon.py +18 -0
  195. openbacktesting/indicators/trend/atr_stop.py +33 -0
  196. openbacktesting/indicators/trend/chop.py +20 -0
  197. openbacktesting/indicators/trend/cksp.py +17 -0
  198. openbacktesting/indicators/trend/cpr.py +57 -0
  199. openbacktesting/indicators/trend/decay.py +10 -0
  200. openbacktesting/indicators/trend/decreasing.py +18 -0
  201. openbacktesting/indicators/trend/dpo.py +12 -0
  202. openbacktesting/indicators/trend/dx.py +19 -0
  203. openbacktesting/indicators/trend/edecay.py +10 -0
  204. openbacktesting/indicators/trend/increasing.py +18 -0
  205. openbacktesting/indicators/trend/long_run.py +10 -0
  206. openbacktesting/indicators/trend/minus_dm.py +10 -0
  207. openbacktesting/indicators/trend/pivot_points.py +89 -0
  208. openbacktesting/indicators/trend/pivothigh.py +23 -0
  209. openbacktesting/indicators/trend/pivotlow.py +23 -0
  210. openbacktesting/indicators/trend/plus_dm.py +10 -0
  211. openbacktesting/indicators/trend/pmax.py +18 -0
  212. openbacktesting/indicators/trend/psar.py +19 -0
  213. openbacktesting/indicators/trend/qstick.py +10 -0
  214. openbacktesting/indicators/trend/sarext.py +35 -0
  215. openbacktesting/indicators/trend/short_run.py +10 -0
  216. openbacktesting/indicators/trend/tsignals.py +26 -0
  217. openbacktesting/indicators/trend/ttm_trend.py +16 -0
  218. openbacktesting/indicators/trend/vhf.py +10 -0
  219. openbacktesting/indicators/trend/volatility_stop.py +33 -0
  220. openbacktesting/indicators/trend/vortex.py +17 -0
  221. openbacktesting/indicators/trend/xsignals.py +29 -0
  222. openbacktesting/indicators/types.py +344 -0
  223. openbacktesting/indicators/utility/__init__.py +0 -0
  224. openbacktesting/indicators/utility/barssince.py +21 -0
  225. openbacktesting/indicators/utility/change.py +7 -0
  226. openbacktesting/indicators/utility/cross.py +12 -0
  227. openbacktesting/indicators/utility/crossover.py +11 -0
  228. openbacktesting/indicators/utility/crossunder.py +11 -0
  229. openbacktesting/indicators/utility/cum.py +7 -0
  230. openbacktesting/indicators/utility/falling.py +10 -0
  231. openbacktesting/indicators/utility/highest.py +7 -0
  232. openbacktesting/indicators/utility/highestbars.py +29 -0
  233. openbacktesting/indicators/utility/lowest.py +7 -0
  234. openbacktesting/indicators/utility/lowestbars.py +29 -0
  235. openbacktesting/indicators/utility/percentile_linear_interpolation.py +12 -0
  236. openbacktesting/indicators/utility/percentile_nearest_rank.py +16 -0
  237. openbacktesting/indicators/utility/percentrank.py +7 -0
  238. openbacktesting/indicators/utility/range.py +8 -0
  239. openbacktesting/indicators/utility/rising.py +10 -0
  240. openbacktesting/indicators/utility/rolling_count.py +12 -0
  241. openbacktesting/indicators/utility/rolling_sum.py +7 -0
  242. openbacktesting/indicators/utility/running_max.py +7 -0
  243. openbacktesting/indicators/utility/running_min.py +7 -0
  244. openbacktesting/indicators/utility/shift.py +7 -0
  245. openbacktesting/indicators/utility/valuewhen.py +25 -0
  246. openbacktesting/indicators/volatility/__init__.py +0 -0
  247. openbacktesting/indicators/volatility/aberration.py +21 -0
  248. openbacktesting/indicators/volatility/accbands.py +20 -0
  249. openbacktesting/indicators/volatility/adr.py +7 -0
  250. openbacktesting/indicators/volatility/atr.py +12 -0
  251. openbacktesting/indicators/volatility/avolume.py +10 -0
  252. openbacktesting/indicators/volatility/bbands.py +20 -0
  253. openbacktesting/indicators/volatility/ce.py +25 -0
  254. openbacktesting/indicators/volatility/cvi.py +10 -0
  255. openbacktesting/indicators/volatility/donchian.py +20 -0
  256. openbacktesting/indicators/volatility/hvol.py +10 -0
  257. openbacktesting/indicators/volatility/hwc.py +27 -0
  258. openbacktesting/indicators/volatility/kc.py +27 -0
  259. openbacktesting/indicators/volatility/massi.py +10 -0
  260. openbacktesting/indicators/volatility/natr.py +19 -0
  261. openbacktesting/indicators/volatility/pdist.py +10 -0
  262. openbacktesting/indicators/volatility/rvi.py +21 -0
  263. openbacktesting/indicators/volatility/starc.py +11 -0
  264. openbacktesting/indicators/volatility/thermo.py +28 -0
  265. openbacktesting/indicators/volatility/true_range.py +31 -0
  266. openbacktesting/indicators/volatility/ui.py +10 -0
  267. openbacktesting/indicators/volume/__init__.py +0 -0
  268. openbacktesting/indicators/volume/ad.py +10 -0
  269. openbacktesting/indicators/volume/adosc.py +19 -0
  270. openbacktesting/indicators/volume/aobv.py +31 -0
  271. openbacktesting/indicators/volume/cmf.py +12 -0
  272. openbacktesting/indicators/volume/efi.py +12 -0
  273. openbacktesting/indicators/volume/emv.py +10 -0
  274. openbacktesting/indicators/volume/eom.py +19 -0
  275. openbacktesting/indicators/volume/iii.py +9 -0
  276. openbacktesting/indicators/volume/kvo.py +28 -0
  277. openbacktesting/indicators/volume/marketfi.py +10 -0
  278. openbacktesting/indicators/volume/mfi.py +12 -0
  279. openbacktesting/indicators/volume/nvi.py +26 -0
  280. openbacktesting/indicators/volume/obv.py +10 -0
  281. openbacktesting/indicators/volume/pvi.py +26 -0
  282. openbacktesting/indicators/volume/pvol.py +10 -0
  283. openbacktesting/indicators/volume/pvr.py +10 -0
  284. openbacktesting/indicators/volume/pvt.py +10 -0
  285. openbacktesting/indicators/volume/rvol.py +8 -0
  286. openbacktesting/indicators/volume/vfi.py +18 -0
  287. openbacktesting/indicators/volume/vosc.py +10 -0
  288. openbacktesting/indicators/volume/wad.py +10 -0
  289. openbacktesting/indicators/volume/wvad.py +9 -0
  290. openbacktesting/inputs.py +51 -0
  291. openbacktesting/lib.py +31 -0
  292. openbacktesting/logs.py +129 -0
  293. openbacktesting/optimization.py +8 -0
  294. openbacktesting/optimizer/__init__.py +25 -0
  295. openbacktesting/optimizer/_semantics.py +155 -0
  296. openbacktesting/optimizer/identity.py +45 -0
  297. openbacktesting/optimizer/models.py +92 -0
  298. openbacktesting/optimizer/plan.py +129 -0
  299. openbacktesting/optimizer/portfolio-result.schema.json +4984 -0
  300. openbacktesting/optimizer/query.py +257 -0
  301. openbacktesting/optimizer/runner.py +98 -0
  302. openbacktesting/optimizer/storage.py +261 -0
  303. openbacktesting/optimizer/validation.py +64 -0
  304. openbacktesting/parallel.py +9 -0
  305. openbacktesting/plotting/__init__.py +23 -0
  306. openbacktesting/plotting/collector.py +509 -0
  307. openbacktesting/plotting/encoding.py +102 -0
  308. openbacktesting/plotting/types.py +92 -0
  309. openbacktesting/portfolio/__init__.py +15 -0
  310. openbacktesting/portfolio/analysis.py +245 -0
  311. openbacktesting/portfolio/builder.py +381 -0
  312. openbacktesting/portfolio/catalog.json +1404 -0
  313. openbacktesting/portfolio/helpers.py +92 -0
  314. openbacktesting/portfolio/metrics.py +186 -0
  315. openbacktesting/portfolio/models.py +63 -0
  316. openbacktesting/portfolio/periods.py +164 -0
  317. openbacktesting/portfolio/rates.py +14 -0
  318. openbacktesting/portfolio/snapshot.py +111 -0
  319. openbacktesting/portfolio/stats.py +272 -0
  320. openbacktesting/portfolio/trades.py +136 -0
  321. openbacktesting/portfolio/trading.py +215 -0
  322. openbacktesting/py.typed +0 -0
  323. openbacktesting/runtime.py +330 -0
  324. openbacktesting/simulation/__init__.py +17 -0
  325. openbacktesting/simulation/collection.py +13 -0
  326. openbacktesting/simulation/config.py +241 -0
  327. openbacktesting/simulation/core.py +528 -0
  328. openbacktesting/simulation/optimization.py +326 -0
  329. openbacktesting/simulation/parallel.py +145 -0
  330. openbacktesting/simulation/variants.py +107 -0
  331. openbacktesting/strategy/__init__.py +19 -0
  332. openbacktesting/strategy/bar_state.py +14 -0
  333. openbacktesting/strategy/base.py +810 -0
  334. openbacktesting/strategy/declaration.py +90 -0
  335. openbacktesting/strategy/helpers.py +198 -0
  336. openbacktesting/strategy/inputs.py +460 -0
  337. openbacktesting/strategy/sizing.py +80 -0
  338. openbacktesting/strategy/templates.py +160 -0
  339. openbacktesting/strategy_data.py +10 -0
  340. openbacktesting/test/BTCUSD.csv +157 -0
  341. openbacktesting/test/EURUSD.csv +5001 -0
  342. openbacktesting/test/GOOG.csv +2149 -0
  343. openbacktesting/test/__init__.py +29 -0
  344. openbacktesting/test/__main__.py +11 -0
  345. openbacktesting/test/_test.py +1312 -0
  346. openbacktesting/util.py +31 -0
  347. openbacktesting-0.2.0.dist-info/METADATA +151 -0
  348. openbacktesting-0.2.0.dist-info/RECORD +350 -0
  349. openbacktesting-0.2.0.dist-info/WHEEL +4 -0
  350. openbacktesting-0.2.0.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,218 @@
1
+ """Native market-data views, indicator arrays, and warmup helpers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import warnings
6
+ from numbers import Number
7
+ from typing import cast
8
+
9
+ import numpy as np
10
+ import pandas as pd
11
+
12
+ from openbacktesting.helpers import _set_legacy_module
13
+
14
+
15
+ def _data_period(index) -> pd.Timedelta | Number:
16
+ """Return data index period as pd.Timedelta"""
17
+ values = pd.Series(index[-100:])
18
+ return values.diff().dropna().median()
19
+
20
+
21
+ def _strategy_indicators(strategy):
22
+ return {
23
+ attr: indicator
24
+ for attr, indicator in strategy.__dict__.items()
25
+ if isinstance(indicator, _Indicator)
26
+ }.items()
27
+
28
+
29
+ def _indicator_warmup_nbars(strategy):
30
+ """Indicator-readiness diagnostic for the legacy entry point; no longer controls next scheduling or return baselines."""
31
+ if strategy is None:
32
+ return 0
33
+ if hasattr(strategy, "_indicator_cursor"):
34
+ return max((indicator.first_ready() for indicator in strategy._indicators), default=0)
35
+ nbars = max(
36
+ (
37
+ np.isnan(indicator.astype(float)).argmin(axis=-1).max()
38
+ for _, indicator in _strategy_indicators(strategy)
39
+ if indicator._opts.get("warmup", True)
40
+ ),
41
+ default=0,
42
+ )
43
+ return nbars
44
+
45
+
46
+ class _Array(np.ndarray):
47
+ """
48
+ ndarray extended to supply .name and other arbitrary properties
49
+ in ._opts dict.
50
+ """
51
+
52
+ def __new__(cls, array, *, name=None, **kwargs):
53
+ obj = np.asarray(array).view(cls)
54
+ obj.name = name or array.name
55
+ obj._opts = kwargs
56
+ return obj
57
+
58
+ def __array_finalize__(self, obj):
59
+ if obj is not None:
60
+ self.name = getattr(obj, "name", "")
61
+ self._opts = getattr(obj, "_opts", {})
62
+
63
+ # Make sure properties name and _opts are carried over
64
+ # when (un-)pickling.
65
+ def __reduce__(self):
66
+ value = super().__reduce__()
67
+ return value[:2] + (value[2] + (self.__dict__,),)
68
+
69
+ def __setstate__(self, state):
70
+ self.__dict__.update(state[-1])
71
+ super().__setstate__(state[:-1])
72
+
73
+ def __bool__(self):
74
+ try:
75
+ return bool(self[-1])
76
+ except IndexError:
77
+ return super().__bool__()
78
+
79
+ def __float__(self):
80
+ try:
81
+ return float(self[-1])
82
+ except IndexError:
83
+ return super().__float__()
84
+
85
+ def to_series(self):
86
+ warnings.warn("`.to_series()` is deprecated. For pd.Series conversion, use accessor `.s`")
87
+ return self.s
88
+
89
+ @property
90
+ def s(self) -> pd.Series:
91
+ values = np.atleast_2d(self)
92
+ index = self._opts["index"][: values.shape[1]]
93
+ return pd.Series(values[0], index=index, name=self.name)
94
+
95
+ @property
96
+ def df(self) -> pd.DataFrame:
97
+ values = np.atleast_2d(np.asarray(self))
98
+ index = self._opts["index"][: values.shape[1]]
99
+ df = pd.DataFrame(values.T, index=index, columns=[self.name] * len(values))
100
+ return df
101
+
102
+
103
+ class _Indicator(_Array):
104
+ pass
105
+
106
+
107
+ class _Data:
108
+ """
109
+ A data array accessor. Provides access to OHLCV "columns"
110
+ as a standard `pd.DataFrame` would, except it's not a DataFrame
111
+ and the returned "series" are _not_ `pd.Series` but `np.ndarray`
112
+ for performance reasons.
113
+ """
114
+
115
+ def __init__(self, df: pd.DataFrame):
116
+ self.__df = df
117
+ self.__len = len(df) # Current length
118
+ self.__pip: float | None = None
119
+ self.__cache: dict[str, _Array] = {}
120
+ self.__arrays: dict[str, _Array] = {}
121
+ self._update()
122
+
123
+ def __getitem__(self, item):
124
+ return self.__get_array(item)
125
+
126
+ def __getattr__(self, item):
127
+ try:
128
+ return self.__get_array(item)
129
+ except KeyError:
130
+ raise AttributeError(f"Column '{item}' not in data") from None
131
+
132
+ def _set_length(self, length):
133
+ self.__len = length
134
+ self.__cache.clear()
135
+
136
+ def _update(self):
137
+ index = self.__df.index.copy()
138
+ self.__arrays = {col: _Array(arr, index=index) for col, arr in self.__df.items()}
139
+ # Leave index as Series because pd.Timestamp nicer API to work with
140
+ self.__arrays["__index"] = index
141
+
142
+ def __repr__(self):
143
+ i = min(self.__len, len(self.__df)) - 1
144
+ index = self.__arrays["__index"][i]
145
+ items = ", ".join(f"{k}={v}" for k, v in self.__df.iloc[i].items())
146
+ return f"<Data i={i} ({index}) {items}>"
147
+
148
+ def __len__(self):
149
+ return self.__len
150
+
151
+ @property
152
+ def df(self) -> pd.DataFrame:
153
+ return self.__df.iloc[: self.__len] if self.__len < len(self.__df) else self.__df
154
+
155
+ def _full_frame(self) -> pd.DataFrame:
156
+ """Used for internal provenance capture without changing the visible length of public data."""
157
+ return self.__df
158
+
159
+ @property
160
+ def pip(self) -> float:
161
+ if self.__pip is None:
162
+ self.__pip = float(
163
+ 10
164
+ ** -np.median(
165
+ [len(s.partition(".")[-1]) for s in self.__arrays["Close"].astype(str)]
166
+ )
167
+ )
168
+ return self.__pip
169
+
170
+ def __get_array(self, key) -> _Array:
171
+ arr = self.__cache.get(key)
172
+ if arr is None:
173
+ arr = self.__cache[key] = cast(_Array, self.__arrays[key][: self.__len])
174
+ return arr
175
+
176
+ def _current_value(self, key: str):
177
+ # Known fast path to avoid needless __get_array reslicing
178
+ assert self.__len >= 0, self
179
+ return self.__arrays[key][self.__len - 1]
180
+
181
+ @property
182
+ def Open(self) -> _Array:
183
+ return self.__get_array("Open")
184
+
185
+ @property
186
+ def High(self) -> _Array:
187
+ return self.__get_array("High")
188
+
189
+ @property
190
+ def Low(self) -> _Array:
191
+ return self.__get_array("Low")
192
+
193
+ @property
194
+ def Close(self) -> _Array:
195
+ return self.__get_array("Close")
196
+
197
+ @property
198
+ def Volume(self) -> _Array:
199
+ return self.__get_array("Volume")
200
+
201
+ @property
202
+ def index(self) -> pd.DatetimeIndex:
203
+ return self.__get_array("__index")
204
+
205
+ # Make pickling in Backtest.optimize() work with our catch-all __getattr__
206
+ def __getstate__(self):
207
+ return self.__dict__
208
+
209
+ def __setstate__(self, state):
210
+ self.__dict__ = state
211
+
212
+
213
+ _set_legacy_module(_data_period, "openbacktesting._util")
214
+ _set_legacy_module(_strategy_indicators, "openbacktesting._util")
215
+ _set_legacy_module(_indicator_warmup_nbars, "openbacktesting._util")
216
+ _set_legacy_module(_Array, "openbacktesting._util")
217
+ _set_legacy_module(_Indicator, "openbacktesting._util")
218
+ _set_legacy_module(_Data, "openbacktesting._util")
@@ -0,0 +1,54 @@
1
+ """Existing implementation moved from lib: random_ohlc_data."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Generator
6
+
7
+ import pandas as pd
8
+
9
+ from openbacktesting.helpers import _set_legacy_module
10
+
11
+
12
+ def random_ohlc_data(
13
+ example_data: pd.DataFrame, *, frac=1.0, random_state: int | None = None
14
+ ) -> Generator[pd.DataFrame, None, None]:
15
+ """Iteratively generate random samples preserving basic market-data structure; these are not real-market forecasts.
16
+
17
+
18
+ OHLC data generator. The generated OHLC data has basic
19
+ [descriptive statistics](https://en.wikipedia.org/wiki/Descriptive_statistics)
20
+ similar to the provided `example_data`.
21
+
22
+ `frac` is a fraction of data to sample (with replacement). Values greater
23
+ than 1 result in oversampling.
24
+
25
+ Such random data can be effectively used for stress testing trading
26
+ strategy robustness, Monte Carlo simulations, significance testing, etc.
27
+
28
+ >>> from openbacktesting.test import EURUSD
29
+ >>> ohlc_generator = random_ohlc_data(EURUSD)
30
+ >>> next(ohlc_generator) # returns new random data
31
+ ...
32
+ >>> next(ohlc_generator) # returns new random data
33
+ ...
34
+ """
35
+
36
+ def shuffle(x):
37
+ return x.sample(frac=frac, replace=frac > 1, random_state=random_state)
38
+
39
+ if len(example_data.columns.intersection({"Open", "High", "Low", "Close"})) != 4:
40
+ raise ValueError(
41
+ "`data` must be a pandas.DataFrame with columns 'Open', 'High', 'Low', 'Close'"
42
+ )
43
+ while True:
44
+ df = shuffle(example_data)
45
+ df.index = example_data.index
46
+ padding = df.Close - df.Open.shift(-1)
47
+ gaps = shuffle(example_data.Open.shift(-1) - example_data.Close)
48
+ deltas = (padding + gaps).shift(1).fillna(0).cumsum()
49
+ for key in ("Open", "High", "Low", "Close"):
50
+ df[key] += deltas
51
+ yield df
52
+
53
+
54
+ _set_legacy_module(random_ohlc_data, "openbacktesting.lib")
@@ -0,0 +1,103 @@
1
+ """Per-run market-data snapshot and stable series; does not register indicators."""
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+
6
+ from openbacktesting.data.core import _Data
7
+ from openbacktesting.indicators.types import (
8
+ IndicatorCursor,
9
+ IndicatorError,
10
+ IndicatorHandle,
11
+ immutable,
12
+ )
13
+
14
+ PRICE_COLUMNS = {"open": "Open", "high": "High", "low": "Low", "close": "Close", "volume": "Volume"}
15
+ DERIVED = ("hl2", "hlc3", "hlcc4")
16
+ DATA_NAMES = frozenset((*PRICE_COLUMNS, *DERIVED, "data_index", "df", "pip"))
17
+
18
+
19
+ class StrategyData:
20
+ def __init__(self, data: _Data, cursor: IndicatorCursor):
21
+ self._data = data
22
+ self._cursor = cursor
23
+ self._baseline: pd.DataFrame | None = None
24
+ self._values: dict[str, np.ndarray] = {}
25
+ self._handles: dict[str, IndicatorHandle] = {}
26
+
27
+ def validate(self):
28
+ """Check only at the initialization boundary; do not scan all data on each bar."""
29
+ if self._baseline is None or self._cursor.phase != "init":
30
+ return
31
+ frame = self._data._full_frame()
32
+ columns = frame.columns[frame.columns.isin(PRICE_COLUMNS.values())]
33
+ current = frame.loc[:, columns]
34
+ if (
35
+ not current.equals(self._baseline)
36
+ or not current.index.identical(self._baseline.index)
37
+ or not current.columns.identical(self._baseline.columns)
38
+ ):
39
+ raise IndicatorError(
40
+ "data-source-mutated",
41
+ "strategy.data",
42
+ "OHLCV or index changed; finish market-data preprocessing before first reading a market-data series",
43
+ )
44
+
45
+ def _capture(self):
46
+ frame = self._data._full_frame()
47
+ if not frame.index.is_unique:
48
+ raise IndicatorError("invalid-data-source", "strategy.data", "Market-data index must be unique")
49
+ columns = frame.columns[frame.columns.isin(PRICE_COLUMNS.values())]
50
+ if len(columns) != 5 or set(columns) != set(PRICE_COLUMNS.values()):
51
+ raise IndicatorError("invalid-data-source", "strategy.data", "Unique OHLCV columns are required")
52
+ baseline = frame.loc[:, columns].copy(deep=True)
53
+ values = {}
54
+ for name, column in PRICE_COLUMNS.items():
55
+ series = baseline[column]
56
+ if pd.api.types.is_bool_dtype(series.dtype) or not (
57
+ pd.api.types.is_integer_dtype(series.dtype)
58
+ or pd.api.types.is_float_dtype(series.dtype)
59
+ ):
60
+ raise IndicatorError(
61
+ "invalid-data-source", "strategy.data", f"{column} must be a real-valued market-data column"
62
+ )
63
+ values[name] = immutable(series.to_numpy(dtype=np.float64, na_value=np.nan))
64
+ self._baseline = baseline
65
+ self._values = values
66
+
67
+ def _derive(self, name):
68
+ high, low, close = (self._values[key] for key in ("high", "low", "close"))
69
+ valid = np.isfinite(high) & np.isfinite(low)
70
+ with np.errstate(over="ignore", invalid="ignore"):
71
+ if name == "hl2":
72
+ values = (high + low) / 2
73
+ else:
74
+ valid &= np.isfinite(close)
75
+ if name == "hlc3":
76
+ values = ((high + low) + close) / 3
77
+ else:
78
+ values = ((high + low) + (close + close)) / 4
79
+ return np.where(valid & np.isfinite(values), values, np.nan)
80
+
81
+ def get(self, name: str) -> IndicatorHandle:
82
+ self.validate()
83
+ if self._baseline is None:
84
+ self._capture()
85
+ if name not in self._handles:
86
+ values = self._values[name] if name in PRICE_COLUMNS else self._derive(name)
87
+ self._handles[name] = IndicatorHandle(
88
+ values,
89
+ name=PRICE_COLUMNS.get(name, name),
90
+ index=self._baseline.index,
91
+ cursor=self._cursor,
92
+ metadata={"kind": "data-source", "field": name, "version": "1"},
93
+ )
94
+ return self._handles[name]
95
+
96
+ def __setstate__(self, state):
97
+ self.__dict__.update(state)
98
+ self._values = {name: immutable(value) for name, value in self._values.items()}
99
+
100
+
101
+ from openbacktesting.helpers import _set_legacy_module
102
+
103
+ _set_legacy_module(StrategyData, "openbacktesting.strategy_data")
@@ -0,0 +1,69 @@
1
+ """Chart timeframe units and immutable values; no market-data inference or resampling."""
2
+
3
+ from dataclasses import dataclass
4
+ from enum import StrEnum
5
+
6
+
7
+ class TimeframeUnit(StrEnum):
8
+ """Time-bar units; calendar units are not implicitly converted to fixed seconds."""
9
+
10
+ SECOND = "second"
11
+ MINUTE = "minute"
12
+ DAY = "day"
13
+ WEEK = "week"
14
+ MONTH = "month"
15
+
16
+
17
+ def _positive_integer(value: int) -> int:
18
+ if type(value) is not int:
19
+ raise TypeError("Timeframe multiplier must be an integer; bool and floats are not accepted")
20
+ if value <= 0:
21
+ raise ValueError("Timeframe multiplier must be a positive integer")
22
+ return value
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class Timeframe:
27
+ """Timeframe value; the host validates data-source support, and not all combinations are guaranteed to have market data."""
28
+
29
+ unit: TimeframeUnit
30
+ multiplier: int
31
+
32
+ def __post_init__(self):
33
+ if not isinstance(self.unit, TimeframeUnit):
34
+ raise TypeError("unit must be a TimeframeUnit")
35
+ _positive_integer(self.multiplier)
36
+
37
+ @classmethod
38
+ def seconds(cls, value: int) -> "Timeframe":
39
+ """Create a seconds timeframe."""
40
+ return cls(TimeframeUnit.SECOND, value)
41
+
42
+ @classmethod
43
+ def minutes(cls, value: int) -> "Timeframe":
44
+ """Create a minutes timeframe."""
45
+ return cls(TimeframeUnit.MINUTE, value)
46
+
47
+ @classmethod
48
+ def hours(cls, value: int) -> "Timeframe":
49
+ """Normalize hours to minutes; 24 hours is not a daily timeframe."""
50
+ return cls.minutes(_positive_integer(value) * 60)
51
+
52
+ @classmethod
53
+ def days(cls, value: int) -> "Timeframe":
54
+ """Create a calendar-day timeframe."""
55
+ return cls(TimeframeUnit.DAY, value)
56
+
57
+ @classmethod
58
+ def weeks(cls, value: int) -> "Timeframe":
59
+ """Create a calendar-week timeframe."""
60
+ return cls(TimeframeUnit.WEEK, value)
61
+
62
+ @classmethod
63
+ def months(cls, value: int) -> "Timeframe":
64
+ """Create a calendar-month timeframe."""
65
+ return cls(TimeframeUnit.MONTH, value)
66
+
67
+ def snapshot(self) -> dict:
68
+ """Return independent plain unit/multiplier values."""
69
+ return {"unit": self.unit.value, "multiplier": self.multiplier}
@@ -0,0 +1,34 @@
1
+ """Compatibility entry point for old native-kernel paths; definitions reside in the corresponding responsibility modules."""
2
+
3
+ from openbacktesting.broker.core import (
4
+ Order,
5
+ Position,
6
+ Trade,
7
+ __pdoc__, # noqa: F401 — preserve compatibility exports at the original path
8
+ _Broker, # noqa: F401 — preserve compatibility exports at the original path
9
+ _OutOfMoneyError, # noqa: F401 — preserve compatibility exports at the original path
10
+ )
11
+ from openbacktesting.data.core import (
12
+ _Data, # noqa: F401 — preserve compatibility exports at the original path
13
+ _Indicator, # noqa: F401 — preserve compatibility exports at the original path
14
+ _indicator_warmup_nbars, # noqa: F401 — preserve compatibility exports at the original path
15
+ _strategy_indicators, # noqa: F401 — preserve compatibility exports at the original path
16
+ )
17
+ from openbacktesting.helpers import (
18
+ _as_str, # noqa: F401 — preserve compatibility exports at the original path
19
+ patch, # noqa: F401 — preserve compatibility exports at the original path
20
+ try_, # noqa: F401 — preserve compatibility exports at the original path
21
+ )
22
+ from openbacktesting.portfolio.stats import (
23
+ compute_stats, # noqa: F401 — preserve compatibility exports at the original path
24
+ dummy_stats, # noqa: F401 — preserve compatibility exports at the original path
25
+ )
26
+ from openbacktesting.simulation.core import Backtest
27
+ from openbacktesting.simulation.parallel import (
28
+ SharedMemoryManager, # noqa: F401 — preserve compatibility exports at the original path
29
+ _batch, # noqa: F401 — preserve compatibility exports at the original path
30
+ )
31
+ from openbacktesting.strategy.base import Strategy
32
+ from openbacktesting.util import _tqdm # noqa: F401 — preserve compatibility exports at the original path
33
+
34
+ __all__ = ["Strategy", "Position", "Order", "Trade", "Backtest"] # noqa: RUF022 — preserve the original public export order
@@ -0,0 +1,77 @@
1
+ """Stateless helpers and compatibility with old object paths."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Sequence
6
+ from contextlib import contextmanager
7
+ from numbers import Number
8
+ from types import FunctionType
9
+
10
+ import pandas as pd
11
+
12
+
13
+ def _set_legacy_module(obj, module):
14
+ """Preserve old qualified names used by pickle when moving definitions; do not create replacement classes."""
15
+ original = obj.__module__
16
+ obj.__module__ = module
17
+ if isinstance(obj, type):
18
+ for member in vars(obj).values():
19
+ if isinstance(member, type) and member.__module__ == original:
20
+ _set_legacy_module(member, module)
21
+ if isinstance(member, (staticmethod, classmethod)):
22
+ functions = (member.__func__,)
23
+ elif isinstance(member, property):
24
+ functions = (member.fget, member.fset, member.fdel)
25
+ else:
26
+ functions = (member, getattr(member, "func", None))
27
+ for function in functions:
28
+ if isinstance(function, FunctionType) and function.__module__ == original:
29
+ function.__module__ = module
30
+
31
+
32
+ def try_(lazy_func, default=None, exception=Exception):
33
+ try:
34
+ return lazy_func()
35
+ except exception:
36
+ return default
37
+
38
+
39
+ @contextmanager
40
+ def patch(obj, attr, newvalue):
41
+ had_attr = hasattr(obj, attr)
42
+ orig_value = getattr(obj, attr, None)
43
+ setattr(obj, attr, newvalue)
44
+ try:
45
+ yield
46
+ finally:
47
+ if had_attr:
48
+ setattr(obj, attr, orig_value)
49
+ else:
50
+ delattr(obj, attr)
51
+
52
+
53
+ def _as_str(value) -> str:
54
+ if isinstance(value, (Number, str)):
55
+ return str(value)
56
+ if isinstance(value, pd.DataFrame):
57
+ return "df"
58
+ name = str(getattr(value, "name", "") or "")
59
+ if name in ("Open", "High", "Low", "Close", "Volume"):
60
+ return name[:1]
61
+ if callable(value):
62
+ name = getattr(value, "__name__", value.__class__.__name__).replace("<lambda>", "λ")
63
+ if len(name) > 10:
64
+ name = name[:9] + "…"
65
+ return name
66
+
67
+
68
+ def _as_list(value) -> list:
69
+ if isinstance(value, Sequence) and not isinstance(value, str):
70
+ return list(value)
71
+ return [value]
72
+
73
+
74
+ _set_legacy_module(try_, "openbacktesting._util")
75
+ _set_legacy_module(patch, "openbacktesting._util")
76
+ _set_legacy_module(_as_str, "openbacktesting._util")
77
+ _set_legacy_module(_as_list, "openbacktesting._util")
@@ -0,0 +1,10 @@
1
+ """Compatibility exports for old type paths; implemented in the indicators subpackage."""
2
+
3
+ from .indicators.api import (
4
+ IndicatorNamespace,
5
+ IndicatorResult,
6
+ Inputs,
7
+ Source,
8
+ )
9
+
10
+ __all__ = ["IndicatorNamespace", "IndicatorResult", "Inputs", "Source"]
@@ -0,0 +1,123 @@
1
+ """Compatibility exports for old type paths; implemented in the indicators subpackage."""
2
+
3
+ from .indicators.methods import (
4
+ AberrationResult,
5
+ AccbandsResult,
6
+ AdxResult,
7
+ AdxrResult,
8
+ AmatResult,
9
+ AobvResult,
10
+ AroonResult,
11
+ BbandsResult,
12
+ BrarResult,
13
+ CdlZResult,
14
+ CeResult,
15
+ CkspResult,
16
+ CprResult,
17
+ DmResult,
18
+ DonchianResult,
19
+ DrawdownResult,
20
+ EriResult,
21
+ FisherResult,
22
+ HaResult,
23
+ HiloResult,
24
+ HtPhasorResult,
25
+ HtSineResult,
26
+ HwcResult,
27
+ IchimokuResult,
28
+ KcResult,
29
+ KdjResult,
30
+ KstResult,
31
+ KvoResult,
32
+ MacdextResult,
33
+ MacdfixResult,
34
+ MacdResult,
35
+ MamaResult,
36
+ MmarResult,
37
+ MswResult,
38
+ PpoResult,
39
+ PsarResult,
40
+ PvoResult,
41
+ QqeResult,
42
+ RainbowResult,
43
+ RvgiResult,
44
+ SmiResult,
45
+ SqueezeProResult,
46
+ SqueezeResult,
47
+ StcResult,
48
+ StochfResult,
49
+ StochResult,
50
+ StochrsiResult,
51
+ SupertrendResult,
52
+ TdSeqResult,
53
+ TechnicalAnalysis,
54
+ ThermoResult,
55
+ TrixhResult,
56
+ TrixResult,
57
+ TsignalsResult,
58
+ TsiResult,
59
+ VortexResult,
60
+ VwmacdResult,
61
+ XsignalsResult,
62
+ )
63
+
64
+ __all__ = [
65
+ "AberrationResult",
66
+ "AccbandsResult",
67
+ "AdxResult",
68
+ "AdxrResult",
69
+ "AmatResult",
70
+ "AobvResult",
71
+ "AroonResult",
72
+ "BbandsResult",
73
+ "BrarResult",
74
+ "CdlZResult",
75
+ "CeResult",
76
+ "CkspResult",
77
+ "CprResult",
78
+ "DmResult",
79
+ "DonchianResult",
80
+ "DrawdownResult",
81
+ "EriResult",
82
+ "FisherResult",
83
+ "HaResult",
84
+ "HiloResult",
85
+ "HtPhasorResult",
86
+ "HtSineResult",
87
+ "HwcResult",
88
+ "IchimokuResult",
89
+ "KcResult",
90
+ "KdjResult",
91
+ "KstResult",
92
+ "KvoResult",
93
+ "MacdResult",
94
+ "MacdextResult",
95
+ "MacdfixResult",
96
+ "MamaResult",
97
+ "MmarResult",
98
+ "MswResult",
99
+ "PpoResult",
100
+ "PsarResult",
101
+ "PvoResult",
102
+ "QqeResult",
103
+ "RainbowResult",
104
+ "RvgiResult",
105
+ "SmiResult",
106
+ "SqueezeProResult",
107
+ "SqueezeResult",
108
+ "StcResult",
109
+ "StochResult",
110
+ "StochfResult",
111
+ "StochrsiResult",
112
+ "SupertrendResult",
113
+ "TdSeqResult",
114
+ "TechnicalAnalysis",
115
+ "ThermoResult",
116
+ "TrixResult",
117
+ "TrixhResult",
118
+ "TsiResult",
119
+ "TsignalsResult",
120
+ "VortexResult",
121
+ "VwmacdResult",
122
+ "XsignalsResult",
123
+ ]