opencode-pyneruntime 6.6.4__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 (261) hide show
  1. opencode_pyneruntime-6.6.4.dist-info/METADATA +281 -0
  2. opencode_pyneruntime-6.6.4.dist-info/RECORD +261 -0
  3. opencode_pyneruntime-6.6.4.dist-info/WHEEL +5 -0
  4. opencode_pyneruntime-6.6.4.dist-info/entry_points.txt +6 -0
  5. opencode_pyneruntime-6.6.4.dist-info/licenses/LICENSE +201 -0
  6. opencode_pyneruntime-6.6.4.dist-info/licenses/NOTICE +21 -0
  7. opencode_pyneruntime-6.6.4.dist-info/top_level.txt +1 -0
  8. pynecore/__init__.py +6 -0
  9. pynecore/cli/__init__.py +2 -0
  10. pynecore/cli/app.py +238 -0
  11. pynecore/cli/commands/__init__.py +343 -0
  12. pynecore/cli/commands/benchmark.py +186 -0
  13. pynecore/cli/commands/compile.py +198 -0
  14. pynecore/cli/commands/data.py +857 -0
  15. pynecore/cli/commands/debug.py +63 -0
  16. pynecore/cli/commands/optimize.py +956 -0
  17. pynecore/cli/commands/plugin.py +242 -0
  18. pynecore/cli/commands/run.py +2006 -0
  19. pynecore/cli/pluggable.py +132 -0
  20. pynecore/cli/utils/__init__.py +0 -0
  21. pynecore/cli/utils/api_error_handler.py +168 -0
  22. pynecore/cli/utils/broker_picker.py +330 -0
  23. pynecore/cli/utils/error_hook.py +28 -0
  24. pynecore/cli/utils/keyreader.py +178 -0
  25. pynecore/cli/utils/provider_picker.py +19 -0
  26. pynecore/cli/utils/symbol_browser.py +1149 -0
  27. pynecore/core/__init__.py +0 -0
  28. pynecore/core/aggregator.py +257 -0
  29. pynecore/core/bar_magnifier.py +168 -0
  30. pynecore/core/broker/__init__.py +64 -0
  31. pynecore/core/broker/defaults.py +113 -0
  32. pynecore/core/broker/disappearance.py +927 -0
  33. pynecore/core/broker/emulator.py +345 -0
  34. pynecore/core/broker/exceptions.py +346 -0
  35. pynecore/core/broker/idempotency.py +401 -0
  36. pynecore/core/broker/intent_builder.py +334 -0
  37. pynecore/core/broker/journal.py +1785 -0
  38. pynecore/core/broker/models.py +1600 -0
  39. pynecore/core/broker/native_failsafe_manager.py +1436 -0
  40. pynecore/core/broker/one_way_emulator.py +1128 -0
  41. pynecore/core/broker/position.py +787 -0
  42. pynecore/core/broker/run_identity.py +126 -0
  43. pynecore/core/broker/software_entry_stop_engine.py +351 -0
  44. pynecore/core/broker/software_partial_bracket_engine.py +1379 -0
  45. pynecore/core/broker/spot_inventory.py +1327 -0
  46. pynecore/core/broker/storage.py +2655 -0
  47. pynecore/core/broker/store_helpers.py +2161 -0
  48. pynecore/core/broker/sync_engine.py +16070 -0
  49. pynecore/core/broker/validation.py +382 -0
  50. pynecore/core/class_property.py +7 -0
  51. pynecore/core/config.py +392 -0
  52. pynecore/core/csv_file.py +547 -0
  53. pynecore/core/currency.py +262 -0
  54. pynecore/core/data_converter.py +1002 -0
  55. pynecore/core/datetime.py +296 -0
  56. pynecore/core/download_info.py +71 -0
  57. pynecore/core/download_runner.py +274 -0
  58. pynecore/core/htf_aggregator.py +181 -0
  59. pynecore/core/import_hook.py +358 -0
  60. pynecore/core/instance_state.py +494 -0
  61. pynecore/core/live_ltf_collector.py +442 -0
  62. pynecore/core/live_ltf_window.py +189 -0
  63. pynecore/core/live_runner.py +1347 -0
  64. pynecore/core/module_property.py +26 -0
  65. pynecore/core/ohlcv_file.py +1888 -0
  66. pynecore/core/overload.py +371 -0
  67. pynecore/core/pine_cast.py +113 -0
  68. pynecore/core/pine_export.py +95 -0
  69. pynecore/core/pine_method.py +244 -0
  70. pynecore/core/pine_range.py +86 -0
  71. pynecore/core/pine_udt.py +69 -0
  72. pynecore/core/plugin/__init__.py +394 -0
  73. pynecore/core/plugin/broker.py +781 -0
  74. pynecore/core/plugin/cli.py +96 -0
  75. pynecore/core/plugin/live_provider.py +208 -0
  76. pynecore/core/plugin/provider.py +331 -0
  77. pynecore/core/provider_string.py +148 -0
  78. pynecore/core/random.py +40 -0
  79. pynecore/core/resampler.py +686 -0
  80. pynecore/core/safe_convert.py +64 -0
  81. pynecore/core/script.py +1011 -0
  82. pynecore/core/script_runner.py +3202 -0
  83. pynecore/core/security.py +1749 -0
  84. pynecore/core/security_process.py +1253 -0
  85. pynecore/core/security_shm.py +456 -0
  86. pynecore/core/series.py +417 -0
  87. pynecore/core/strategy_stats.py +669 -0
  88. pynecore/core/symbol_map.py +134 -0
  89. pynecore/core/syminfo.py +505 -0
  90. pynecore/core/viz.py +591 -0
  91. pynecore/lib/__init__.py +1771 -0
  92. pynecore/lib/_fixnan.py +32 -0
  93. pynecore/lib/_math_stateful.py +202 -0
  94. pynecore/lib/_timeframe_change.py +101 -0
  95. pynecore/lib/adjustment.py +6 -0
  96. pynecore/lib/alert.py +39 -0
  97. pynecore/lib/alert.pyi +14 -0
  98. pynecore/lib/array.py +1051 -0
  99. pynecore/lib/barmerge.py +60 -0
  100. pynecore/lib/barstate.py +30 -0
  101. pynecore/lib/box.py +415 -0
  102. pynecore/lib/chart.py +128 -0
  103. pynecore/lib/color.py +152 -0
  104. pynecore/lib/color.pyi +50 -0
  105. pynecore/lib/currency.py +62 -0
  106. pynecore/lib/dayofweek.py +36 -0
  107. pynecore/lib/dayofweek.pyi +18 -0
  108. pynecore/lib/display.py +8 -0
  109. pynecore/lib/dividends.py +9 -0
  110. pynecore/lib/earnings.py +11 -0
  111. pynecore/lib/extend.py +6 -0
  112. pynecore/lib/font.py +5 -0
  113. pynecore/lib/footprint.py +79 -0
  114. pynecore/lib/format.py +11 -0
  115. pynecore/lib/hline.py +67 -0
  116. pynecore/lib/hline.pyi +24 -0
  117. pynecore/lib/label.py +409 -0
  118. pynecore/lib/line.py +433 -0
  119. pynecore/lib/linefill.py +93 -0
  120. pynecore/lib/location.py +11 -0
  121. pynecore/lib/log.py +362 -0
  122. pynecore/lib/map.py +150 -0
  123. pynecore/lib/math.py +385 -0
  124. pynecore/lib/matrix.py +708 -0
  125. pynecore/lib/order.py +8 -0
  126. pynecore/lib/pivotpointtype.py +8 -0
  127. pynecore/lib/plot.py +95 -0
  128. pynecore/lib/plot.pyi +33 -0
  129. pynecore/lib/polyline.py +91 -0
  130. pynecore/lib/position.py +15 -0
  131. pynecore/lib/request.py +281 -0
  132. pynecore/lib/runtime.py +5 -0
  133. pynecore/lib/scale.py +9 -0
  134. pynecore/lib/session.py +267 -0
  135. pynecore/lib/session.pyi +12 -0
  136. pynecore/lib/shape.py +18 -0
  137. pynecore/lib/size.py +12 -0
  138. pynecore/lib/splits.py +4 -0
  139. pynecore/lib/strategy/__init__.py +4778 -0
  140. pynecore/lib/strategy/closedtrades.py +347 -0
  141. pynecore/lib/strategy/closedtrades.pyi +53 -0
  142. pynecore/lib/strategy/commission.py +9 -0
  143. pynecore/lib/strategy/direction.py +9 -0
  144. pynecore/lib/strategy/oca.py +13 -0
  145. pynecore/lib/strategy/opentrades.py +281 -0
  146. pynecore/lib/strategy/opentrades.pyi +49 -0
  147. pynecore/lib/strategy/risk.py +109 -0
  148. pynecore/lib/string.py +649 -0
  149. pynecore/lib/syminfo.py +84 -0
  150. pynecore/lib/ta.py +2230 -0
  151. pynecore/lib/table.py +290 -0
  152. pynecore/lib/text.py +17 -0
  153. pynecore/lib/ticker.py +207 -0
  154. pynecore/lib/timeframe.py +293 -0
  155. pynecore/lib/volume_row.py +67 -0
  156. pynecore/lib/xloc.py +4 -0
  157. pynecore/lib/yloc.py +5 -0
  158. pynecore/providers/__init__.py +0 -0
  159. pynecore/providers/ccxt.py +664 -0
  160. pynecore/providers/replay.py +187 -0
  161. pynecore/pynesys/__init__.py +0 -0
  162. pynecore/pynesys/api.py +498 -0
  163. pynecore/pynesys/compiler.py +112 -0
  164. pynecore/standalone.py +99 -0
  165. pynecore/testing/__init__.py +1 -0
  166. pynecore/testing/broker_lab/__init__.py +41 -0
  167. pynecore/testing/broker_lab/__main__.py +5 -0
  168. pynecore/testing/broker_lab/cli.py +87 -0
  169. pynecore/testing/broker_lab/generate.py +47 -0
  170. pynecore/testing/broker_lab/model.py +84 -0
  171. pynecore/testing/broker_lab/reference.py +645 -0
  172. pynecore/testing/broker_lab/runner.py +372 -0
  173. pynecore/testing/broker_lab/scheduler.py +50 -0
  174. pynecore/testing/broker_lab/subprocess.py +73 -0
  175. pynecore/transformers/__init__.py +0 -0
  176. pynecore/transformers/builtin_shadow.py +136 -0
  177. pynecore/transformers/closure_arguments_transformer.py +428 -0
  178. pynecore/transformers/display_rewrite.py +140 -0
  179. pynecore/transformers/dynamic_default.py +147 -0
  180. pynecore/transformers/function_isolation.py +757 -0
  181. pynecore/transformers/import_lifter.py +61 -0
  182. pynecore/transformers/import_normalizer.py +328 -0
  183. pynecore/transformers/inline_series_hoist.py +178 -0
  184. pynecore/transformers/input_transformer.py +175 -0
  185. pynecore/transformers/lib_series.py +201 -0
  186. pynecore/transformers/locations.py +70 -0
  187. pynecore/transformers/module_properties.json +3387 -0
  188. pynecore/transformers/module_property.py +221 -0
  189. pynecore/transformers/ne_guard.py +70 -0
  190. pynecore/transformers/persistent.py +320 -0
  191. pynecore/transformers/persistent_series.py +76 -0
  192. pynecore/transformers/safe_convert_transformer.py +97 -0
  193. pynecore/transformers/safe_division_transformer.py +95 -0
  194. pynecore/transformers/script_requirements.py +308 -0
  195. pynecore/transformers/security.py +752 -0
  196. pynecore/transformers/security_instantiation.py +274 -0
  197. pynecore/transformers/series.py +275 -0
  198. pynecore/transformers/slot_layout.py +381 -0
  199. pynecore/transformers/type_checking_stripper.py +25 -0
  200. pynecore/transformers/unused_series_detector.py +267 -0
  201. pynecore/types/__init__.py +21 -0
  202. pynecore/types/alert.py +5 -0
  203. pynecore/types/barmerge.py +5 -0
  204. pynecore/types/base.py +39 -0
  205. pynecore/types/box.py +37 -0
  206. pynecore/types/chart.py +17 -0
  207. pynecore/types/color.py +107 -0
  208. pynecore/types/currency.py +5 -0
  209. pynecore/types/datetime.py +6 -0
  210. pynecore/types/display.py +5 -0
  211. pynecore/types/dividends.py +5 -0
  212. pynecore/types/earnings.py +5 -0
  213. pynecore/types/extend.py +5 -0
  214. pynecore/types/font.py +5 -0
  215. pynecore/types/footprint.py +41 -0
  216. pynecore/types/format.py +5 -0
  217. pynecore/types/hline.py +24 -0
  218. pynecore/types/ib_persistent.py +8 -0
  219. pynecore/types/ib_persistent.pyi +10 -0
  220. pynecore/types/label.py +35 -0
  221. pynecore/types/line.py +32 -0
  222. pynecore/types/linefill.py +13 -0
  223. pynecore/types/location.py +5 -0
  224. pynecore/types/matrix.py +999 -0
  225. pynecore/types/na.py +237 -0
  226. pynecore/types/na.pyi +83 -0
  227. pynecore/types/ohlcv.py +12 -0
  228. pynecore/types/order.py +5 -0
  229. pynecore/types/persistent.py +8 -0
  230. pynecore/types/persistent.pyi +13 -0
  231. pynecore/types/pine_types.py +11 -0
  232. pynecore/types/pine_types.pyi +15 -0
  233. pynecore/types/pivotpointtype.py +5 -0
  234. pynecore/types/plot.py +12 -0
  235. pynecore/types/plot_meta.py +60 -0
  236. pynecore/types/polyline.py +40 -0
  237. pynecore/types/position.py +5 -0
  238. pynecore/types/scale.py +5 -0
  239. pynecore/types/script_type.py +15 -0
  240. pynecore/types/series.py +23 -0
  241. pynecore/types/series.pyi +19 -0
  242. pynecore/types/session.py +35 -0
  243. pynecore/types/shape.py +5 -0
  244. pynecore/types/size.py +5 -0
  245. pynecore/types/source.py +33 -0
  246. pynecore/types/splits.py +5 -0
  247. pynecore/types/strategy.py +45 -0
  248. pynecore/types/table.py +87 -0
  249. pynecore/types/text.py +13 -0
  250. pynecore/types/type_checker.py +7 -0
  251. pynecore/types/type_checker.pyi +48 -0
  252. pynecore/types/volume_row.py +36 -0
  253. pynecore/types/weekdays.py +11 -0
  254. pynecore/types/xloc.py +5 -0
  255. pynecore/types/yloc.py +5 -0
  256. pynecore/utils/__init__.py +0 -0
  257. pynecore/utils/file_utils.py +50 -0
  258. pynecore/utils/rich/__init__.py +0 -0
  259. pynecore/utils/rich/date_column.py +25 -0
  260. pynecore/utils/sequence_view.py +92 -0
  261. pynecore/utils/stdlib_checker.py +17 -0
pynecore/lib/array.py ADDED
@@ -0,0 +1,1051 @@
1
+ from typing import TypeVar, Any, cast
2
+
3
+ import builtins
4
+
5
+ import math
6
+ import statistics
7
+
8
+ from ..utils.sequence_view import SequenceView
9
+
10
+ from ..types.na import NA, na_float
11
+ from ..types.color import Color
12
+ from ..types.box import Box
13
+ from ..types.line import Line
14
+ from ..types.label import Label
15
+ from ..types.linefill import LineFill
16
+ from ..types.table import Table
17
+ from . import order as _order
18
+
19
+ T = TypeVar('T')
20
+ Number = TypeVar('Number', int, float)
21
+
22
+ __all__ = [
23
+ 'abs',
24
+ 'avg',
25
+ 'binary_search',
26
+ 'binary_search_leftmost',
27
+ 'binary_search_rightmost',
28
+ 'clear',
29
+ 'concat',
30
+ 'copy',
31
+ 'covariance',
32
+ 'every',
33
+ 'fill',
34
+ 'first',
35
+ 'from_items',
36
+ 'get',
37
+ 'includes',
38
+ 'indexof',
39
+ 'insert',
40
+ 'join',
41
+ 'last',
42
+ 'lastindexof',
43
+ 'max',
44
+ 'median',
45
+ 'min',
46
+ 'mode',
47
+ 'new',
48
+ 'new_bool',
49
+ 'new_box',
50
+ 'new_color',
51
+ 'new_float',
52
+ 'new_int',
53
+ 'new_label',
54
+ 'new_line',
55
+ 'new_linefill',
56
+ 'new_string',
57
+ 'new_table',
58
+ 'percentile_linear_interpolation',
59
+ 'percentile_nearest_rank',
60
+ 'percentrank',
61
+ 'pop',
62
+ 'push',
63
+ 'range',
64
+ 'remove',
65
+ 'reverse',
66
+ 'set',
67
+ 'shift',
68
+ 'size',
69
+ 'slice',
70
+ 'some',
71
+ 'sort',
72
+ 'sort_indices',
73
+ 'standardize',
74
+ 'stdev',
75
+ 'sum',
76
+ 'unshift',
77
+ 'variance',
78
+ ]
79
+
80
+
81
+ # noinspection PyShadowingBuiltins
82
+ def _non_na(id: list[T]) -> list[T]:
83
+ """
84
+ Return the array's elements with na values removed.
85
+
86
+ TradingView's array math and statistics reductions ignore na elements and
87
+ reduce over the remaining values only, yielding na when none remain. Every
88
+ such reduction filters its input through this helper so their na handling
89
+ stays consistent with Pine.
90
+
91
+ :param id: Input array, possibly containing na elements
92
+ :return: New list containing only the non-na elements, in original order
93
+ """
94
+ return [i for i in id if not (isinstance(i, NA) or i != i)]
95
+
96
+
97
+ # noinspection PyShadowingBuiltins
98
+ def abs(id: list[int | float]) -> list[int | float]:
99
+ """
100
+ Returns an array containing the absolute value of each element in the original array.
101
+
102
+ :param id: Input array
103
+ :return: Array containing the absolute value of each element in the original array
104
+ """
105
+ return [builtins.abs(v) for v in id]
106
+
107
+
108
+ # noinspection PyShadowingBuiltins
109
+ def avg(id: list[Number]) -> float:
110
+ """
111
+ Returns the average value of the elements in the array.
112
+
113
+ :param id: Input array
114
+ :return: Average value of the elements in the array, or na if the array is empty
115
+ """
116
+ a = _non_na(id)
117
+ if not a:
118
+ return na_float
119
+ return builtins.sum(a) / len(a)
120
+
121
+
122
+ # noinspection PyShadowingBuiltins
123
+ def binary_search(id: list[Any], val: Any) -> int:
124
+ """
125
+ Returns the index of the specified value in the sorted array using binary search.
126
+ If the value is not found, returns -1.
127
+ The array to search must be sorted in ascending order.
128
+
129
+ :param id: Input array
130
+ :param val: Value to search for
131
+ :return: Index of the specified value in the sorted array, or -1 if not found
132
+ """
133
+ low = 0
134
+ high = len(id) - 1
135
+ while low <= high:
136
+ mid = (low + high) // 2
137
+ if id[mid] == val:
138
+ return mid
139
+ else:
140
+ if val < id[mid]:
141
+ high = mid - 1
142
+ else:
143
+ low = mid + 1
144
+ return -1
145
+
146
+
147
+ # noinspection PyShadowingBuiltins
148
+ def binary_search_leftmost(id: list[Any], val: Any) -> int:
149
+ """
150
+ Returns the index of the specified value in the sorted array using binary search.
151
+ If the value is not found, returns the index of the leftmost element greater than the value.
152
+ The array to search must be sorted in ascending order.
153
+
154
+ :param id: Input array
155
+ :param val: Value to search for
156
+ :return: Index of the specified value in the sorted array, or the index of the leftmost element
157
+ greater than the value
158
+ """
159
+ low = 0
160
+ high = len(id) - 1
161
+ while low <= high:
162
+ mid = (low + high) // 2
163
+ if id[mid] == val:
164
+ return mid
165
+ else:
166
+ if val < id[mid]:
167
+ high = mid - 1
168
+ else:
169
+ low = mid + 1
170
+ return low - 1
171
+
172
+
173
+ # noinspection PyShadowingBuiltins
174
+ def binary_search_rightmost(id: list[Any], val: Any) -> int:
175
+ """
176
+ Returns the index of the specified value in the sorted array using binary search.
177
+ If the value is not found, returns the index of the rightmost element less than the value.
178
+ The array to search must be sorted in ascending order.
179
+
180
+ :param id: Input array
181
+ :param val: Value to search for
182
+ :return: Index of the specified value in the sorted array, or the index of the rightmost element less than the value
183
+ """
184
+ low = 0
185
+ high = len(id) - 1
186
+ while low <= high:
187
+ mid = (low + high) // 2
188
+ if id[mid] == val:
189
+ return mid
190
+ else:
191
+ if val < id[mid]:
192
+ high = mid - 1
193
+ else:
194
+ low = mid + 1
195
+ return high + 1
196
+
197
+
198
+ # noinspection PyShadowingBuiltins
199
+ def clear(id: list[Any]) -> None:
200
+ """
201
+ Removes all elements from the array.
202
+
203
+ :param id: Input array
204
+ """
205
+ id.clear()
206
+
207
+
208
+ # noinspection PyShadowingBuiltins
209
+ def concat(id1: list[T], id2: list[T]) -> list[T]:
210
+ """
211
+ Concatenates two arrays into a single array.
212
+
213
+ :param id1: First array
214
+ :param id2: Second array
215
+ :return: Array containing the elements of both input arrays
216
+ """
217
+ id1.extend(id2)
218
+ return id1
219
+
220
+
221
+ # noinspection PyShadowingBuiltins
222
+ def copy(id: list[T]) -> list[T]:
223
+ """
224
+ Returns a shallow copy of the array.
225
+
226
+ :param id: Input array
227
+ :return: Shallow copy of the array
228
+ """
229
+ return list(id)
230
+
231
+
232
+ # noinspection PyShadowingBuiltins
233
+ def covariance(id1: list[Number], id2: list[Number], biased: bool = True) -> float:
234
+ """
235
+ Returns the covariance between the elements in the two arrays.
236
+
237
+ :param id1: First input array
238
+ :param id2: Second input array
239
+ :param biased: If True, calculates the biased covariance. If False, calculates the unbiased covariance.
240
+ :return: Covariance between the elements in the two arrays, or na if the arrays are empty
241
+ """
242
+ assert len(id1) == len(id2), "Input arrays must have the same length!"
243
+ pairs = [(v1, v2) for v1, v2 in zip(id1, id2)
244
+ if not (isinstance(v1, NA) or v1 != v1 or isinstance(v2, NA) or v2 != v2)]
245
+ if not pairs:
246
+ return na_float
247
+ # Online (Welford) co-moment — matches TradingView bit-for-bit for both
248
+ # the biased and unbiased result, where the classic two-pass
249
+ # ``sum((x-mx)*(y-my)) / divisor`` lands a couple of ulps off on the
250
+ # unbiased path (TV-verified in test_003_array_functions_float).
251
+ length = 0
252
+ mean1 = 0.0
253
+ mean2 = 0.0
254
+ comoment = 0.0
255
+ for v1, v2 in pairs:
256
+ length += 1
257
+ d1 = v1 - mean1
258
+ mean1 += d1 / length
259
+ mean2 += (v2 - mean2) / length
260
+ comoment += d1 * (v2 - mean2)
261
+ divisor = (length - 1) if not biased else length
262
+ if divisor == 0:
263
+ return 0.0
264
+ return comoment / divisor
265
+
266
+
267
+ # noinspection PyShadowingBuiltins
268
+ def every(id: list[Any]) -> bool:
269
+ """
270
+ Returns true if all elements of the id array are true, false otherwise.
271
+
272
+ :param id: Input array
273
+ :return: True if all elements of the id array are true, false otherwise
274
+ """
275
+ return all(id)
276
+
277
+
278
+ # noinspection PyShadowingBuiltins
279
+ def fill(id: list[T], value: T, index_from: int = 0, index_to: int | NA = NA(int)) -> None:
280
+ """
281
+ Fills the elements in the array with the specified value.
282
+
283
+ :param id: Input array
284
+ :param value: Value to fill
285
+ :param index_from: Index to start filling from
286
+ :param index_to: Index to stop filling at
287
+ """
288
+ if isinstance(index_to, NA):
289
+ index_to = len(id)
290
+ id[index_from:index_to] = [value] * (index_to - index_from)
291
+
292
+
293
+ # noinspection PyShadowingBuiltins
294
+ def first(id: list[T]) -> T:
295
+ """
296
+ Returns the first element in the array.
297
+
298
+ :param id: Input array
299
+ :return: First element in the array
300
+ """
301
+ if len(id) == 0:
302
+ raise RuntimeError("Cannot get first element of an empty array!")
303
+ return id[0]
304
+
305
+
306
+ # noinspection PyShadowingBuiltins
307
+ def from_items(*items: T) -> list[T]:
308
+ """
309
+ Returns an array containing the specified elements.
310
+ NOTE: this is `array.from()` in Pine Script, but `from` is a reserved keyword in Python
311
+
312
+ :param items: Elements to include in the array
313
+ :return: Array containing the specified elements
314
+ """
315
+ return list(items)
316
+
317
+
318
+ # noinspection PyShadowingBuiltins
319
+ def get(id: list[T] | SequenceView[T], index: int) -> T:
320
+ """
321
+ Returns the element at the specified index in the array.
322
+
323
+ :param id: Input array
324
+ :param index: Index of the element to return
325
+ :return: Element at the specified index in the array
326
+ """
327
+ # A na index (e.g. an index derived from a warmup ta.* value) yields na
328
+ # rather than crashing, matching Pine's na-propagation.
329
+ if isinstance(index, NA) or (isinstance(index, float) and math.isnan(index)):
330
+ return NA(None) # type: ignore[return-value]
331
+ # Pine floors a float index (documented: `array.get()` uses floor(index)),
332
+ # whereas Python cannot index a list with a float.
333
+ return id[int(index)]
334
+
335
+
336
+ # noinspection PyShadowingBuiltins
337
+ def includes(id: list[T], value: T) -> bool:
338
+ """
339
+ Returns true if the array contains the specified value, false otherwise.
340
+
341
+ :param id: Input array
342
+ :param value: Value to search for
343
+ :return: True if the array contains the specified value, false otherwise
344
+ """
345
+ return value in id
346
+
347
+
348
+ # noinspection PyShadowingBuiltins
349
+ def indexof(id: list[T], value: T) -> int:
350
+ """
351
+ Returns the index of the first occurrence of the specified value in the array.
352
+
353
+ :param id: Input array
354
+ :param value: Value to search for
355
+ :return: Index of the first occurrence of the specified value in the array
356
+ """
357
+ try:
358
+ return id.index(value)
359
+ except ValueError:
360
+ return -1
361
+
362
+
363
+ # noinspection PyShadowingBuiltins
364
+ def insert(id: list[T], index: int, value: T) -> None:
365
+ """
366
+ Inserts the specified value at the specified index in the array.
367
+
368
+ :param id: Input array
369
+ :param index: Index to insert the value at
370
+ :param value: Value to insert
371
+ """
372
+ id.insert(index, value)
373
+
374
+
375
+ # noinspection PyShadowingBuiltins
376
+ def join(id: list, separator: str) -> str:
377
+ """
378
+ Concatenates the elements in the array into a single string, separated by the specified separator.
379
+
380
+ :param id: Input array
381
+ :param separator: Separator to use
382
+ :return: String containing the concatenated elements
383
+ """
384
+ sa = [str(i) for i in id] # Ensure all elements are strings
385
+ return separator.join(sa)
386
+
387
+
388
+ # noinspection PyShadowingBuiltins
389
+ def last(id: list[T]) -> T:
390
+ """
391
+ Returns the last element in the array.
392
+
393
+ :param id: Input array
394
+ :return: Last element in the array
395
+ """
396
+ if len(id) == 0:
397
+ raise RuntimeError("Cannot get last element of an empty array!")
398
+ return id[-1]
399
+
400
+
401
+ # noinspection PyShadowingBuiltins
402
+ def lastindexof(id: list[T], value: T) -> int:
403
+ """
404
+ Returns the index of the last occurrence of the specified value in the array.
405
+
406
+ :param id: Input array
407
+ :param value: Value to search for
408
+ :return: Index of the last occurrence of the specified value in the array
409
+ """
410
+ try:
411
+ return len(id) - 1 - id[::-1].index(value)
412
+ except ValueError:
413
+ return -1
414
+
415
+
416
+ # noinspection PyShadowingBuiltins
417
+ def max(id: list[Number], nth: int = 0) -> Number:
418
+ """
419
+ Returns the maximum value in the array, or the nth largest value.
420
+
421
+ na elements are ignored. ``nth`` is 0-based: 0 is the maximum, 1 the second
422
+ largest, and so on. Returns na if the array holds no non-na values or ``nth``
423
+ is out of range.
424
+
425
+ :param id: Input array
426
+ :param nth: Rank of the maximum to return (0 = maximum)
427
+ :return: The nth largest value in the array, or na
428
+ """
429
+ a = _non_na(id)
430
+ if not a:
431
+ return id[0] if id else NA(None)
432
+ if nth == 0:
433
+ return builtins.max(a)
434
+ if nth < 0 or nth >= len(a):
435
+ return cast(Number, NA(builtins.type(a[0])))
436
+ return sorted(a, reverse=True)[nth]
437
+
438
+
439
+ # noinspection PyShadowingBuiltins
440
+ def median(id: list[Number]) -> float:
441
+ """
442
+ Returns the median value of the elements in the array.
443
+
444
+ :param id: Input array
445
+ :return: Median value of the elements in the array, or na if the array is empty
446
+ """
447
+ a = _non_na(id)
448
+ if not a:
449
+ return na_float
450
+ return statistics.median(a)
451
+
452
+
453
+ # noinspection PyShadowingBuiltins
454
+ def min(id: list[Number], nth: int = 0) -> Number:
455
+ """
456
+ Returns the minimum value in the array, or the nth smallest value.
457
+
458
+ na elements are ignored. ``nth`` is 0-based: 0 is the minimum, 1 the second
459
+ smallest, and so on. Returns na if the array holds no non-na values or ``nth``
460
+ is out of range.
461
+
462
+ :param id: Input array
463
+ :param nth: Rank of the minimum to return (0 = minimum)
464
+ :return: The nth smallest value in the array, or na
465
+ """
466
+ a = _non_na(id)
467
+ if not a:
468
+ return id[0] if id else NA(None)
469
+ if nth == 0:
470
+ return builtins.min(a)
471
+ if nth < 0 or nth >= len(a):
472
+ return cast(Number, NA(builtins.type(a[0])))
473
+ return sorted(a)[nth]
474
+
475
+
476
+ # noinspection PyShadowingBuiltins
477
+ def mode(id: list[T]) -> T:
478
+ """
479
+ Returns the most frequently occurring element in the array.
480
+
481
+ :param id: Input array
482
+ :return: Most frequently occurring element in the array, or na if the array is empty
483
+ """
484
+ a = _non_na(id)
485
+ if not a:
486
+ # An all-na array still knows its element type through its na elements;
487
+ # a truly empty one does not, so it gets a typeless na
488
+ return id[0] if id else NA(None)
489
+ return statistics.mode(a)
490
+
491
+
492
+ # noinspection PyShadowingNames
493
+ def _na_size(size: int | NA) -> int:
494
+ """
495
+ Normalize an array constructor ``size`` argument.
496
+
497
+ TradingView treats an ``na`` size (e.g. ``array.new<line>(na)``) as 0,
498
+ producing an empty array, so mirror that instead of failing. A genuinely
499
+ negative size is still rejected.
500
+
501
+ :param size: Requested array size, possibly ``na``
502
+ :return: Non-negative integer size
503
+ """
504
+ if isinstance(size, NA) or size != size:
505
+ return 0
506
+ assert size >= 0, "Size must be >=0!"
507
+ return size
508
+
509
+
510
+ # noinspection PyShadowingNames
511
+ def new_box(size: int | NA = 0, initial_value: Box = NA(Box)) -> list[Box]:
512
+ """
513
+ Creates a new array of box objects of the specified size, with each element initialized
514
+ to the specified value.
515
+
516
+ :param size: Size of the new array
517
+ :param initial_value: Initial value to set for each element in the array
518
+ :return: New array of box objects
519
+ """
520
+ size = _na_size(size)
521
+ assert isinstance(initial_value, (Box, NA)), "Initial value must be Box!"
522
+ return [initial_value] * size
523
+
524
+
525
+ # noinspection PyShadowingNames
526
+ def new_line(size: int | NA = 0, initial_value: Line = NA(Line)) -> list[Line]:
527
+ """
528
+ Creates a new array of line objects of the specified size, with each element initialized
529
+ to the specified value.
530
+
531
+ :param size: Size of the new array
532
+ :param initial_value: Initial value to set for each element in the array
533
+ :return: New array of line objects
534
+ """
535
+ size = _na_size(size)
536
+ assert isinstance(initial_value, (Line, NA)), "Initial value must be Line!"
537
+ return [initial_value] * size
538
+
539
+
540
+ # noinspection PyShadowingNames
541
+ def new_label(size: int | NA = 0, initial_value: Label = NA(Label)) -> list[Label]:
542
+ """
543
+ Creates a new array of label objects of the specified size, with each element initialized
544
+ to the specified value.
545
+
546
+ :param size: Size of the new array
547
+ :param initial_value: Initial value to set for each element in the array
548
+ :return: New array of label objects
549
+ """
550
+ size = _na_size(size)
551
+ assert isinstance(initial_value, (Label, NA)), "Initial value must be Label!"
552
+ return [initial_value] * size
553
+
554
+
555
+ # noinspection PyShadowingNames
556
+ def new_linefill(size: int | NA = 0,
557
+ initial_value: LineFill = NA(LineFill)) -> list[LineFill]:
558
+ """
559
+ Creates a new array of linefill objects of the specified size, with each element initialized
560
+ to the specified value.
561
+
562
+ :param size: Size of the new array
563
+ :param initial_value: Initial value to set for each element in the array
564
+ :return: New array of linefill objects
565
+ """
566
+ size = _na_size(size)
567
+ assert isinstance(initial_value, (LineFill, NA)), "Initial value must be LineFill!"
568
+ return [initial_value] * size
569
+
570
+
571
+ # noinspection PyShadowingNames
572
+ def new_table(size: int | NA = 0, initial_value: Table = NA(Table)) -> list[Table]:
573
+ """
574
+ Creates a new array of table objects of the specified size, with each element initialized
575
+ to the specified value.
576
+
577
+ :param size: Size of the new array
578
+ :param initial_value: Initial value to set for each element in the array
579
+ :return: New array of table objects
580
+ """
581
+ size = _na_size(size)
582
+ assert isinstance(initial_value, (Table, NA)), "Initial value must be Table!"
583
+ return [initial_value] * size
584
+
585
+
586
+ # noinspection PyShadowingNames
587
+ def new(size: int | NA = 0, initial_value: T = NA(T)) -> list[T]:
588
+ """
589
+ Creates a new array of the specified size, with each element initialized to the specified value.
590
+
591
+ :param size: Size of the new array
592
+ :param initial_value: Initial value to set for each element in the array
593
+ :return: New array of the specified size
594
+ """
595
+ size = _na_size(size)
596
+ return [initial_value] * size
597
+
598
+
599
+ # noinspection PyShadowingNames
600
+ def new_bool(size: int | NA = 0, initial_value: bool = NA(bool)) -> list[bool]:
601
+ """
602
+ Creates a new array of the specified size, with each element initialized to the specified value.
603
+
604
+ :param size: Size of the new array
605
+ :param initial_value: Initial value to set for each element in the array
606
+ :return: New array of the specified size
607
+ """
608
+ size = _na_size(size)
609
+ assert isinstance(initial_value, (bool, NA)), "Initial value must be bool!"
610
+ return [initial_value] * size
611
+
612
+
613
+ # noinspection PyShadowingNames
614
+ def new_color(size: int | NA = 0, initial_value: Color = NA(Color)) -> list[Color]:
615
+ """
616
+ Creates a new array of the specified size, with each element initialized to the specified value.
617
+
618
+ :param size: Size of the new array
619
+ :param initial_value: Initial value to set for each element in the array
620
+ :return: New array of the specified size
621
+ """
622
+ size = _na_size(size)
623
+ assert isinstance(initial_value, (Color, NA)), "Initial value must be Color!"
624
+ return [initial_value] * size
625
+
626
+
627
+ # noinspection PyShadowingNames
628
+ def new_float(size: int | NA = 0, initial_value: float | int = na_float) -> list[float]:
629
+ """
630
+ Creates a new array of the specified size, with each element initialized to the specified value.
631
+
632
+ :param size: Size of the new array
633
+ :param initial_value: Initial value to set for each element in the array
634
+ :return: New array of the specified size
635
+ """
636
+ size = _na_size(size)
637
+ assert isinstance(initial_value, (float, int, NA)), "Initial value must be float!"
638
+ if isinstance(initial_value, int):
639
+ initial_value = float(initial_value)
640
+ return [initial_value] * size
641
+
642
+
643
+ # noinspection PyShadowingNames
644
+ def new_int(size: int | NA = 0, initial_value: int = NA(int)) -> list[int]:
645
+ """
646
+ Creates a new array of the specified size, with each element initialized to the specified value.
647
+
648
+ :param size: Size of the new array
649
+ :param initial_value: Initial value to set for each element in the array
650
+ :return: New array of the specified size
651
+ """
652
+ size = _na_size(size)
653
+ assert isinstance(initial_value, (int, NA)), "Initial value must be int!"
654
+ return [initial_value] * size
655
+
656
+
657
+ # noinspection PyShadowingNames
658
+ def new_string(size: int | NA = 0, initial_value: str = NA(str)) -> list[str]:
659
+ """
660
+ Creates a new array of the specified size, with each element initialized to the specified value.
661
+
662
+ :param size: Size of the new array
663
+ :param initial_value: Initial value to set for each element in the array
664
+ :return: New array of the specified size
665
+ """
666
+ size = _na_size(size)
667
+ assert isinstance(initial_value, (str, NA)), "Initial value must be str!"
668
+ return [initial_value] * size
669
+
670
+
671
+ # noinspection PyShadowingBuiltins,PyShadowingNames
672
+ def percentile_linear_interpolation(id: list[float], percentage: float) -> float:
673
+ """
674
+ Calculate the percentile value using linear interpolation, following TradingView's logic.
675
+
676
+ Values are sorted ascending with na elements pushed to the end (as if they
677
+ were the largest values). The interpolation position is 1-based over the full
678
+ array length, ``pos = n * percentage / 100 + 0.5``, clamped to the array
679
+ bounds.
680
+
681
+ Without na the value is interpolated linearly between the two ranks
682
+ straddling ``pos``. TradingView diverges once the array holds any na element:
683
+ it then yields a value only for the low-end clamp or for a ``pos`` that lands
684
+ exactly on an integer rank, and returns na for every fractional position --
685
+ even when both neighbouring values are numeric. An exact rank falling in the
686
+ sorted-to-end na tail likewise yields na.
687
+
688
+ :param id: List of numeric values, possibly containing na elements
689
+ :param percentage: Percentile (0-100, not 0-1)
690
+ :return: Interpolated value at the given percentile, or na (see above)
691
+ :raises ValueError: If arr is empty or percentage is not in [0, 100]
692
+ """
693
+ if not id:
694
+ raise ValueError("Input array is empty")
695
+ if not (0 <= percentage <= 100):
696
+ raise ValueError("Percentage must be between 0 and 100")
697
+
698
+ has_na = any(isinstance(v, NA) or v != v for v in id)
699
+ # filter() instead of a comprehension: PyCharm mis-narrows `not isinstance`
700
+ # inside comprehension conditions (elements would type as NA, not float)
701
+ non_na = sorted(filter(lambda v: not (isinstance(v, NA) or v != v), id))
702
+ sorted_arr = non_na + [na_float] * (len(id) - len(non_na))
703
+ n = len(id)
704
+
705
+ # 1-based interpolation position over the full length
706
+ pos = n * percentage / 100.0 + 0.5
707
+ # Snap to an exact integer rank when floating-point noise leaves us just shy
708
+ nearest = round(pos)
709
+ if builtins.abs(pos - nearest) < 1e-9:
710
+ pos = float(nearest)
711
+
712
+ if pos <= 1:
713
+ return sorted_arr[0]
714
+ if pos >= n:
715
+ return sorted_arr[-1]
716
+
717
+ lower = math.floor(pos) # 1-based lower rank
718
+ frac = pos - lower
719
+ if frac == 0:
720
+ return sorted_arr[lower - 1]
721
+ if has_na:
722
+ return na_float
723
+ return sorted_arr[lower - 1] + frac * (sorted_arr[lower] - sorted_arr[lower - 1])
724
+
725
+
726
+ # noinspection PyShadowingBuiltins,PyShadowingNames
727
+ def percentile_nearest_rank(id: list[float], percentage: float) -> float:
728
+ """
729
+ Calculate the nearest rank percentile without interpolation.
730
+
731
+ Matches TradingView: na elements are kept and sort to the end (as if they
732
+ were the largest values), so the full array length (na included) drives the
733
+ rank. A rank that lands on a na element yields na.
734
+
735
+ :param id: List of numeric values
736
+ :param percentage: Percentile (0-100)
737
+ :return: The value at the nearest rank for the specified percentile, or na
738
+ if that rank falls on a na element
739
+ :raises ValueError: If arr is empty or percentage is not between 0 and 100
740
+ """
741
+ if not id:
742
+ raise ValueError("Input array is empty")
743
+ if not (0 <= percentage <= 100):
744
+ raise ValueError("Percentage must be between 0 and 100")
745
+
746
+ # filter() instead of a comprehension: see percentile_linear_interpolation
747
+ non_na = sorted(filter(lambda v: not (isinstance(v, NA) or v != v), id))
748
+ sorted_arr = non_na + [na_float] * (len(id) - len(non_na))
749
+ n = len(id)
750
+ if percentage == 0:
751
+ return sorted_arr[0]
752
+
753
+ # Calculate the rank using the ceiling function as per the nearest rank method
754
+ rank = math.ceil(percentage * n / 100)
755
+ # Clamp rank to be within the valid range [1, n]
756
+ rank = builtins.max(1, builtins.min(rank, n))
757
+ # Adjust for 0-indexed array: return the (rank-1)th element
758
+ return sorted_arr[rank - 1]
759
+
760
+
761
+ # noinspection PyShadowingBuiltins,PyShadowingNames
762
+ def percentrank(id: list[Number], index: int) -> float:
763
+ """
764
+ Returns the percentile rank of the element at the specified index.
765
+ The percentile rank is the percentage of values less than or equal to the value at index.
766
+
767
+ Matches TradingView: na elements are ignored when counting values at or below
768
+ the target, but still count toward the array length. If the element at
769
+ ``index`` is itself na, the rank is na.
770
+
771
+ :param id: Input array
772
+ :param index: Index of the element to calculate rank for
773
+ :return: Percentile rank (0-100), or na if the element at index is na
774
+ :raises ValueError: If input array is empty or index is out of range
775
+ """
776
+ if not id:
777
+ raise ValueError("Input array is empty")
778
+
779
+ if not 0 <= index < len(id):
780
+ raise ValueError("Index out of range")
781
+
782
+ # Get value at index
783
+ value = id[index]
784
+ if isinstance(value, NA) or value != value:
785
+ return na_float
786
+
787
+ # Count non-na elements less than or equal to the target value
788
+ count = builtins.sum(1 for x in id if not (isinstance(x, NA) or x != x) and x <= value)
789
+
790
+ # Calculate percentage
791
+ return (count - 1) * 100 / (len(id) - 1)
792
+
793
+
794
+ # noinspection PyShadowingBuiltins
795
+ def pop(id: list[T]) -> T:
796
+ """
797
+ Removes the last element from the array and returns it.
798
+
799
+ :param id: Input array
800
+ :return: Last element from the array
801
+ """
802
+ return id.pop()
803
+
804
+
805
+ # noinspection PyShadowingBuiltins
806
+ def push(id: list[T], value: T) -> None:
807
+ """
808
+ Appends the specified value to the end of the array.
809
+
810
+ :param id: Input array
811
+ :param value: Value to append
812
+ """
813
+ id.append(value)
814
+
815
+
816
+ # noinspection PyShadowingBuiltins
817
+ def range(id: list[Number]) -> Number:
818
+ """
819
+ Returns the range of the elements in the array.
820
+
821
+ :param id: Input array
822
+ :return: Range of the elements in the array, or na if the array is empty
823
+ """
824
+ a = _non_na(id)
825
+ if not a:
826
+ return id[0] if id else NA(None)
827
+ return builtins.max(a) - builtins.min(a)
828
+
829
+
830
+ # noinspection PyShadowingBuiltins
831
+ def remove(id: list[T], index: int) -> T:
832
+ """
833
+ Removes the element at the specified index from the array.
834
+
835
+ :param id: Input array
836
+ :param index: Index of the element to remove
837
+ :return: The removed element
838
+ """
839
+ return id.pop(index)
840
+
841
+
842
+ # noinspection PyShadowingBuiltins
843
+ def reverse(id: list[T]) -> None:
844
+ """
845
+ Reverses the order of the elements in the array.
846
+
847
+ :param id: Input array
848
+ """
849
+ id.reverse()
850
+
851
+
852
+ # noinspection PyShadowingBuiltins
853
+ def set(id: list[T] | SequenceView[T], index: int, value: T) -> None:
854
+ """
855
+ Sets the value of the element at the specified index in the array.
856
+
857
+ :param id: Input array
858
+ :param index: Index of the element to set
859
+ :param value: Value to set
860
+ """
861
+ id[index] = value
862
+
863
+
864
+ # noinspection PyShadowingBuiltins
865
+ def shift(id: list[T]) -> T:
866
+ """
867
+ Removes the first element from the array and returns it.
868
+
869
+ :param id: Input array
870
+ :return: First element from the array
871
+ """
872
+ return id.pop(0)
873
+
874
+
875
+ # noinspection PyShadowingBuiltins
876
+ def size(id: list[Any] | SequenceView[Any]) -> int:
877
+ """
878
+ Returns the number of elements in the array.
879
+
880
+ :param id: Input array
881
+ :return: Number of elements in the array
882
+ """
883
+ return len(id)
884
+
885
+
886
+ # noinspection PyShadowingBuiltins
887
+ def slice(id: list[T], index_from: int, index_to: int) -> SequenceView[T]:
888
+ """
889
+ The function creates a slice from an existing array. If an object from the slice changes, the
890
+ changes are applied to both the new and the original arrays.
891
+
892
+ :param id: Input array
893
+ :param index_from: Index to start the sub-array from
894
+ :param index_to: Index to end the sub-array at
895
+ :return: Slice view of the original array
896
+ """
897
+ return SequenceView(id)[int(index_from):int(index_to)] # type: ignore
898
+
899
+
900
+ # noinspection PyShadowingBuiltins
901
+ def some(id: list[Any]) -> bool:
902
+ """
903
+ Returns true if at least one element of the id array is true, false otherwise.
904
+
905
+ :param id: Input array
906
+ :return: True if at least one element of the id array is true, false otherwise
907
+ """
908
+ return any(id)
909
+
910
+
911
+ # noinspection PyShadowingBuiltins
912
+ def sort(id: list[int | float | str], order: _order.Order = _order.ascending) -> None:
913
+ """
914
+ Sorts the elements in the array in ascending or descending order.
915
+
916
+ :param id: Input array
917
+ :param order: Order to sort the elements in
918
+ """
919
+ id.sort(reverse=order == _order.descending)
920
+
921
+
922
+ # noinspection PyShadowingBuiltins
923
+ def sort_indices(id: list[T], order: _order.Order = _order.ascending) -> list[int]:
924
+ """
925
+ Returns an array of indices which, when used to index the original array, will access its elements
926
+ in their sorted order. It does not modify the original array.
927
+
928
+ :param id: Input array
929
+ :param order: Order to sort the elements in
930
+ :return: Array of indices to access the elements in their sorted order
931
+ """
932
+ indices: list[int] = sorted(builtins.range(len(id)), key=id.__getitem__) # type: ignore
933
+ if order == _order.descending:
934
+ indices.reverse()
935
+ return indices
936
+
937
+
938
+ # noinspection PyShadowingBuiltins,PyShadowingNames
939
+ def standardize(id: list[float | int]) -> list[float | int]:
940
+ """
941
+ Standardizes the input array in a Pine Script-like manner:
942
+ 1) Uses a left-to-right summation for the mean (population mean).
943
+ 2) Uses a second pass for summing squared differences (population variance).
944
+ 3) Computes the population standard deviation (divisor = N).
945
+ 4) Returns the z-score for each element.
946
+ - If all input elements are integers, it applies thresholding:
947
+ z < -1 -> -1,
948
+ z > 1 -> 1,
949
+ otherwise 0
950
+ - If any element is float, the result is the continuous z-score value.
951
+ This version is bit-by-bit compatible with Pine Script's `standardize()` function.
952
+
953
+ :param id: A list of numeric values (int or float).
954
+ :return: A list containing the standardized values.
955
+ """
956
+ n = len(id)
957
+ if n == 0:
958
+ # You can decide how you want to handle the empty list.
959
+ return []
960
+
961
+ mean = statistics.mean(id)
962
+ stdev = math.sqrt(statistics.mean([(v - mean) ** 2 for v in id]))
963
+ if stdev == 0:
964
+ # All elements are equal: TV's standardize() yields 1.0 for every element.
965
+ z_scores = [1.0 for _ in id]
966
+ else:
967
+ z_scores = [(v - mean) / stdev for v in id]
968
+
969
+ # If all values are integers, apply the thresholding to get -1, 0, or 1.
970
+ if all(isinstance(v, int) for v in id):
971
+ # Pine Script-style integer thresholding
972
+ return [
973
+ -1 if z < -1 else
974
+ 1 if z > 1 else
975
+ 0
976
+ for z in z_scores
977
+ ]
978
+
979
+ # Otherwise, return the continuous z-score values.
980
+ return z_scores
981
+
982
+
983
+ # noinspection PyShadowingBuiltins
984
+ def stdev(id: list[Number], biased: bool = True) -> float:
985
+ """
986
+ Returns the standard deviation of the elements in the array.
987
+
988
+ :param id: Input array
989
+ :param biased: If True, calculates the biased standard deviation. If False, calculates the
990
+ unbiased standard deviation.
991
+ :return: Standard deviation of the elements in the array, or na if the array is empty
992
+ """
993
+ a = _non_na(id)
994
+ if not a:
995
+ return na_float
996
+ if len(a) < 2:
997
+ return 0.0
998
+ if not biased:
999
+ return statistics.stdev(a)
1000
+ mean = statistics.mean(a)
1001
+ return math.sqrt(statistics.mean([(v - mean) ** 2 for v in a]))
1002
+
1003
+
1004
+ # noinspection PyShadowingBuiltins
1005
+ def sum(id: list[float | int]) -> float | int:
1006
+ """
1007
+ Returns the sum of the elements in the array.
1008
+
1009
+ :param id: Input array
1010
+ :return: Sum of the elements in the array, or na if the array is empty
1011
+ """
1012
+ a = _non_na(id)
1013
+ if not a:
1014
+ return na_float
1015
+ return builtins.sum(a)
1016
+
1017
+
1018
+ # noinspection PyShadowingBuiltins
1019
+ def unshift(id: list[T], value: T) -> None:
1020
+ """
1021
+ Prepends the specified value to the beginning of the array.
1022
+
1023
+ :param id: Input array
1024
+ :param value: Value to prepend
1025
+ """
1026
+ id.insert(0, value)
1027
+
1028
+
1029
+ # noinspection PyShadowingBuiltins
1030
+ def variance(id: list[Number], biased: bool = True) -> float:
1031
+ """
1032
+ Returns the variance of the elements in the array.
1033
+
1034
+ :param id: Input array
1035
+ :param biased: If True, calculates the biased variance. If False, calculates the unbiased variance.
1036
+ :return: Variance of the elements in the array, or na if the array is empty
1037
+ """
1038
+ a = _non_na(id)
1039
+ if not a:
1040
+ return na_float
1041
+ if len(a) < 2:
1042
+ return 0.0
1043
+ if not biased:
1044
+ return statistics.variance(a)
1045
+
1046
+ length = len(a)
1047
+ mean = statistics.mean(a)
1048
+ summ = 0.0
1049
+ for v in a:
1050
+ summ += (v - mean) ** 2
1051
+ return summ / length