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/math.py ADDED
@@ -0,0 +1,385 @@
1
+ from typing import TypeVar, cast, overload
2
+ import builtins
3
+ import math
4
+ from decimal import Decimal, ROUND_HALF_UP, localcontext
5
+
6
+ from ..types.na import NA, na_float
7
+ from ..types import PyneFloat, PyneInt
8
+
9
+ from . import syminfo
10
+ from ._math_stateful import random, sum
11
+
12
+ TFI = TypeVar('TFI', float, int)
13
+
14
+ __all__ = [
15
+ 'e', 'pi', 'phi', 'rphi',
16
+ 'abs', 'acos', 'asin', 'atan', 'avg', 'ceil', 'cos', 'exp', 'floor',
17
+ 'log', 'log10', 'max', 'min', 'pow', 'random', 'round', 'round_to_mintick',
18
+ 'sign', 'sin', 'sqrt', 'sum', 'tan', 'todegrees', 'toradians'
19
+ ]
20
+
21
+ # Constants
22
+ e = math.e
23
+ pi = math.pi
24
+ phi = (1 + math.sqrt(5)) / 2
25
+ rphi = 1 / phi
26
+
27
+ # noinspection PyShadowingBuiltins
28
+ def abs(number: TFI | NA[TFI]) -> PyneFloat:
29
+ """
30
+ Returns the absolute value of a number.
31
+
32
+ :param number: A number.
33
+ :return: The absolute value of the number.
34
+ """
35
+ if (isinstance(number, NA) or number != number):
36
+ return na_float
37
+ return builtins.abs(number)
38
+
39
+
40
+ def acos(value: TFI | NA[TFI]) -> PyneFloat:
41
+ """
42
+ Returns the arc cosine of a value.
43
+
44
+ :param value: A value.
45
+ :return: The arc cosine of the value.
46
+ """
47
+ if (isinstance(value, NA) or value != value):
48
+ return na_float
49
+ return math.acos(value)
50
+
51
+
52
+ def asin(value: TFI | NA[TFI]) -> PyneFloat:
53
+ """
54
+ Returns the arc sine of a value.
55
+
56
+ :param value: A value.
57
+ :return: The arc sine of the value.
58
+ """
59
+ if (isinstance(value, NA) or value != value):
60
+ return na_float
61
+ return math.asin(value)
62
+
63
+
64
+ def atan(value: TFI | NA[TFI]) -> PyneFloat:
65
+ """
66
+ Returns the arc tangent of a value.
67
+
68
+ :param value: A value.
69
+ :return: The arc tangent of the value.
70
+ """
71
+ if (isinstance(value, NA) or value != value):
72
+ return na_float
73
+ return math.atan(value)
74
+
75
+
76
+ def avg(*numbers: TFI | NA[TFI]) -> PyneFloat:
77
+ """
78
+ Returns the average of the numbers.
79
+
80
+ :param numbers: Numbers.
81
+ :return: The average of the numbers.
82
+ """
83
+ assert numbers, "At least one number is necessary!"
84
+
85
+ if any((isinstance(n, NA) or n != n) for n in numbers):
86
+ return na_float
87
+
88
+ return builtins.sum(n for n in numbers) / len(numbers)
89
+
90
+
91
+ def ceil(number: TFI | NA[TFI]) -> PyneInt:
92
+ """
93
+ Returns the smallest integer greater than or equal to a number.
94
+
95
+ :param number: A number.
96
+ :return: The smallest integer greater than or equal to the number.
97
+ """
98
+ if (isinstance(number, NA) or number != number):
99
+ return NA(int)
100
+ return math.ceil(number)
101
+
102
+
103
+ def cos(angle: TFI | NA[TFI]) -> PyneFloat:
104
+ """
105
+ Returns the cosine of an angle.
106
+
107
+ :param angle: An angle in radians.
108
+ :return: The cosine of the angle.
109
+ """
110
+ if (isinstance(angle, NA) or angle != angle):
111
+ return na_float
112
+ return math.cos(angle)
113
+
114
+
115
+ def exp(number: TFI | NA[TFI]) -> PyneFloat:
116
+ """
117
+ Returns e raised to the power of a number.
118
+
119
+ :param number: A number.
120
+ :return: e raised to the power of the number.
121
+ """
122
+ if (isinstance(number, NA) or number != number):
123
+ return na_float
124
+ return math.exp(number)
125
+
126
+
127
+ def floor(number: TFI | NA[TFI]) -> PyneInt:
128
+ """
129
+ Returns the largest integer less than or equal to a number.
130
+
131
+ :param number: A number.
132
+ :return: The largest integer less than or equal to the number.
133
+ """
134
+ if (isinstance(number, NA) or number != number):
135
+ return NA(int)
136
+ # int() truncates toward zero; Pine's floor is a true floor (floor(-1.2) == -2)
137
+ return math.floor(number)
138
+
139
+
140
+ def log(number: TFI | NA[TFI]) -> PyneFloat:
141
+ """
142
+ Returns the natural logarithm of a number.
143
+
144
+ :param number: A number.
145
+ :return: The natural logarithm of the number.
146
+ """
147
+ if (isinstance(number, NA) or number != number):
148
+ return na_float
149
+ return math.log(number)
150
+
151
+
152
+ def log10(number: TFI | NA[TFI]) -> PyneFloat:
153
+ """
154
+ Returns the base-10 logarithm of a number.
155
+
156
+ :param number: A number.
157
+ :return: The base-10 logarithm of the number.
158
+ """
159
+ if (isinstance(number, NA) or number != number):
160
+ return na_float
161
+ return math.log10(number)
162
+
163
+
164
+ def _na_of_operands(numbers: tuple[TFI | NA[TFI], ...]) -> PyneFloat:
165
+ """
166
+ Return the na matching the operands' numeric contract: na_float when any
167
+ type-carrying operand is float-like, NA(int) when the type-carrying operands
168
+ are all int-like, the typeless na when no operand carries a type at all.
169
+ Typeless na operands are neutral — they must not push an int contract to float.
170
+ """
171
+ saw_typed = False
172
+ for n in numbers:
173
+ if n != n:
174
+ # A native nan is a float-typed na by definition
175
+ return na_float
176
+ if isinstance(n, NA):
177
+ if n.type is None:
178
+ continue
179
+ saw_typed = True
180
+ if n.type is not int:
181
+ return na_float
182
+ else:
183
+ saw_typed = True
184
+ if not isinstance(n, int):
185
+ return na_float
186
+ return NA(int) if saw_typed else NA(None)
187
+
188
+
189
+ # noinspection PyShadowingBuiltins
190
+ @overload
191
+ def max(*numbers: int) -> PyneInt: ...
192
+ # noinspection PyShadowingBuiltins
193
+ @overload
194
+ def max(*numbers: TFI | NA[TFI]) -> PyneFloat: ...
195
+
196
+
197
+ # noinspection PyShadowingBuiltins
198
+ def max(*numbers: TFI | NA[TFI]) -> PyneFloat:
199
+ """
200
+ Returns the largest number.
201
+
202
+ :param numbers: Numbers.
203
+ :return: The largest number.
204
+ """
205
+ assert numbers, "At least one number is necessary!"
206
+
207
+ if any((isinstance(n, NA) or n != n) for n in numbers):
208
+ return _na_of_operands(numbers)
209
+
210
+ return builtins.max(cast(list[TFI], numbers))
211
+
212
+
213
+ # noinspection PyShadowingBuiltins
214
+ @overload
215
+ def min(*numbers: int) -> PyneInt: ...
216
+ # noinspection PyShadowingBuiltins
217
+ @overload
218
+ def min(*numbers: TFI | NA[TFI]) -> PyneFloat: ...
219
+
220
+
221
+ # noinspection PyShadowingBuiltins
222
+ def min(*numbers: TFI | NA[TFI]) -> PyneFloat:
223
+ """
224
+ Returns the smallest number.
225
+
226
+ :param numbers: Numbers.
227
+ :return: The smallest number.
228
+ """
229
+ assert numbers, "At least one number is necessary!"
230
+
231
+ if any((isinstance(n, NA) or n != n) for n in numbers):
232
+ return _na_of_operands(numbers)
233
+
234
+ return builtins.min(cast(list[TFI], numbers))
235
+
236
+
237
+ # noinspection PyShadowingBuiltins
238
+ def pow(base: TFI | NA[TFI], exponent: TFI | NA[TFI]) -> PyneFloat:
239
+ """
240
+ Returns a number raised to the power of another number.
241
+
242
+ :param base: The base number.
243
+ :param exponent: The exponent number.
244
+ :return: The base number raised to the power of the exponent number.
245
+ """
246
+ if (isinstance(base, NA) or base != base) or (isinstance(exponent, NA) or exponent != exponent):
247
+ return na_float
248
+
249
+ return base ** exponent
250
+
251
+
252
+ # noinspection PyShadowingBuiltins
253
+ @overload
254
+ def round(number: TFI | NA[TFI]) -> PyneInt: ...
255
+ # noinspection PyShadowingBuiltins
256
+ @overload
257
+ def round(number: TFI | NA[TFI], precision: PyneInt) -> PyneFloat: ...
258
+
259
+
260
+ # noinspection PyShadowingBuiltins
261
+ def round(number: TFI | NA[TFI], precision: PyneInt = NA(int)) -> PyneFloat:
262
+ """
263
+ Returns a number rounded to a specified number of decimal places.
264
+
265
+ :param number: A number.
266
+ :param precision: The number of decimal places to round to.
267
+ :return: The rounded number.
268
+ """
269
+ if (isinstance(number, NA) or number != number):
270
+ # No precision means the int contract (first overload), so an int-typed na
271
+ return na_float if isinstance(precision, int) else NA(int)
272
+ # TV-measured: ties round away from zero on the decimal (shortest-repr) value,
273
+ # not half-even on the binary double (round(2.5) == 3, round(-2.5) == -3,
274
+ # round(2.675, 2) == 2.68 — builtins.round gives 2, -2 and 2.67 there)
275
+ if not math.isfinite(number):
276
+ # Pine has no non-finite values (1/0 is na); the precision overload keeps
277
+ # builtins.round() behavior (returns the float unchanged), but the
278
+ # one-argument overload must honor its int contract, so it yields an int na
279
+ return number if isinstance(precision, int) else NA(int)
280
+ decimal_number = Decimal(repr(number))
281
+ if not isinstance(precision, int):
282
+ return int(decimal_number.to_integral_value(rounding=ROUND_HALF_UP))
283
+ # quantize() fails when the result needs more digits than the context precision
284
+ # (default 28), so size a local context from the magnitude and the requested
285
+ # precision (e.g. round(1e30, 2), round(x, 100))
286
+ with localcontext() as ctx:
287
+ ctx.prec = builtins.max(1, decimal_number.adjusted() + precision + 2)
288
+ return float(decimal_number.quantize(Decimal(1).scaleb(-precision),
289
+ rounding=ROUND_HALF_UP))
290
+
291
+
292
+ @overload
293
+ def round_to_mintick(number: float | int) -> float: ...
294
+ @overload
295
+ def round_to_mintick(number: PyneFloat | PyneInt) -> PyneFloat: ...
296
+
297
+ def round_to_mintick(number: PyneFloat | PyneInt) -> PyneFloat:
298
+ """
299
+ Returns value rounded to symbol's mintick with ties rounding up.
300
+ """
301
+ if (isinstance(number, NA) or number != number):
302
+ return na_float
303
+ # `mintick = minmove / pricescale` (Pine syminfo). Reconstruct via int math so
304
+ # `minmove=1` paths stay bit-identical to the old formula, while `minmove != 1`
305
+ # symbols (e.g. QM1!: mintick=0.025, pricescale=1000, minmove=25) round correctly.
306
+ return int(number / syminfo.mintick + 0.5) * syminfo.minmove / syminfo.pricescale
307
+
308
+
309
+ def sign(number: TFI | NA[TFI]) -> PyneFloat:
310
+ """
311
+ Returns the sign of a number.
312
+
313
+ :param number: A number.
314
+ :return: The sign of the number.
315
+ """
316
+ if (isinstance(number, NA) or number != number):
317
+ return na_float
318
+ if number == 0.0:
319
+ return 0.0
320
+ if number > 0.0:
321
+ return 1.0
322
+ return -1.0
323
+
324
+
325
+ def sin(angle: float | int | NA) -> PyneFloat:
326
+ """
327
+ Returns the sine of an angle.
328
+
329
+ :param angle: An angle in radians.
330
+ :return: The sine of the angle.
331
+ """
332
+ if (isinstance(angle, NA) or angle != angle):
333
+ return na_float
334
+ return math.sin(angle)
335
+
336
+
337
+ def sqrt(number: float | int | NA) -> PyneFloat:
338
+ """
339
+ Returns the square root of a number.
340
+
341
+ :param number: A number.
342
+ :return: The square root of the number.
343
+ """
344
+ if (isinstance(number, NA) or number != number):
345
+ return na_float
346
+ try:
347
+ return math.sqrt(number)
348
+ except ValueError:
349
+ return na_float
350
+
351
+
352
+ def tan(angle: TFI | NA[TFI]) -> PyneFloat:
353
+ """
354
+ Returns the tangent of an angle.
355
+
356
+ :param angle: An angle in radians.
357
+ :return: The tangent of the angle.
358
+ """
359
+ if (isinstance(angle, NA) or angle != angle):
360
+ return na_float
361
+ return math.tan(angle)
362
+
363
+
364
+ def todegrees(angle: TFI | NA[TFI]) -> PyneFloat:
365
+ """
366
+ Converts an angle from radians to degrees.
367
+
368
+ :param angle: An angle in radians.
369
+ :return: The angle in degrees.
370
+ """
371
+ if (isinstance(angle, NA) or angle != angle):
372
+ return na_float
373
+ return math.degrees(angle)
374
+
375
+
376
+ def toradians(angle: TFI | NA[TFI]) -> PyneFloat:
377
+ """
378
+ Converts an angle from degrees to radians.
379
+
380
+ :param angle: An angle in degrees.
381
+ :return: The angle in radians.
382
+ """
383
+ if (isinstance(angle, NA) or angle != angle):
384
+ return na_float
385
+ return math.radians(angle)