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
@@ -0,0 +1,45 @@
1
+ from .base import StrLiteral
2
+
3
+ ADOPTED_STARTUP_ENTRY_ID = "__adopted_startup__"
4
+ """Synthetic FIFO parent-trade id seeded by startup adoption.
5
+
6
+ When a fresh process restarts over an existing broker position and the real
7
+ Pine parent entry id cannot be recovered (no bracket, or a pyramided
8
+ multi-parent position), the sync engine seeds the adopted size under this
9
+ synthetic id. The id deliberately does NOT match any real ``strategy.entry``
10
+ id, so both the close-quantity clamp and the ``strategy.close(id)`` binding
11
+ must treat an open FIFO that carries it as untracked exposure: a keyed
12
+ ``strategy.close(id)`` that misses every faithful id must still be allowed to
13
+ flatten the adopted position rather than be dropped.
14
+ """
15
+
16
+ ADOPTED_STARTUP_EXTRA_KEY = "adopted_startup"
17
+ """``OrderRow.extras`` flag marking a store row a plugin synthesized at startup
18
+ for an *untracked* live venue leg (one this run has no durable journal for).
19
+
20
+ Such rows exist purely so the normal close/exit paths have a confirmed
21
+ ``position`` row to route a DELETE/opposite-close against — they are NOT a
22
+ product of THIS run's own orders. Startup run-ownership reconstruction
23
+ (:meth:`OrderSyncEngine._durable_owned_signed_size`) must therefore exclude
24
+ them: on a one-way (netting) account two runs share one venue net, and a leg
25
+ this run merely adopted for bookkeeping belongs to another run. Counting it as
26
+ owned would re-inflate the ownership clamp and let the run copy a foreign
27
+ run's exposure into ``_position`` — the very cross-run double count the clamp
28
+ exists to prevent.
29
+ """
30
+
31
+
32
+ class QtyType(StrLiteral):
33
+ ...
34
+
35
+
36
+ class Direction(StrLiteral):
37
+ ...
38
+
39
+
40
+ class Commission(StrLiteral):
41
+ ...
42
+
43
+
44
+ class Oca(StrLiteral):
45
+ ...
@@ -0,0 +1,87 @@
1
+ from typing import Optional, Dict, Tuple
2
+ from dataclasses import dataclass, field
3
+
4
+ from ..lib import (color as _color, position as _position, size as _size, text as _text, font as _font)
5
+
6
+
7
+ @dataclass(slots=True)
8
+ class TableCell:
9
+ """Represents a single cell in a table."""
10
+ text: str = ""
11
+ width: int | float = 0
12
+ height: int | float = 0
13
+ text_color: Optional[_color.Color] = None
14
+ text_halign: Optional[_text.AlignEnum] = None
15
+ text_valign: Optional[_text.AlignEnum] = None
16
+ text_size: int | str = _size.normal
17
+ bgcolor: Optional[_color.Color] = None
18
+ tooltip: str = ""
19
+ text_font_family: Optional[_font.FontFamilyEnum] = None
20
+ text_formatting: Optional[_text.FormatEnum] = None
21
+
22
+ # Merge information
23
+ is_merged: bool = False
24
+ merge_start_col: int = -1
25
+ merge_start_row: int = -1
26
+ merge_end_col: int = -1
27
+ merge_end_row: int = -1
28
+
29
+
30
+ @dataclass(slots=True, eq=False)
31
+ class Table:
32
+ # Required parameters
33
+ position: _position.Position # Position of the table
34
+ columns: int # Number of columns
35
+ rows: int # Number of rows
36
+
37
+ # Optional parameters with defaults
38
+ bgcolor: Optional[_color.Color] = None
39
+ frame_color: Optional[_color.Color] = None
40
+ frame_width: int = 0
41
+ border_color: Optional[_color.Color] = None
42
+ border_width: int = 0
43
+ force_overlay: bool = False
44
+
45
+ # Cell data storage - using (column, row) as key
46
+ cells: Dict[Tuple[int, int], TableCell] = field(default_factory=dict)
47
+
48
+ vid: int = -1
49
+
50
+ def get_cell(self, column: int, row: int) -> TableCell:
51
+ """Get or create a cell at the specified position."""
52
+ if (column, row) not in self.cells:
53
+ self.cells[(column, row)] = TableCell()
54
+ return self.cells[(column, row)]
55
+
56
+ def set_cell(self, column: int, row: int, cell: TableCell) -> None:
57
+ """Set a cell at the specified position."""
58
+ self.cells[(column, row)] = cell
59
+
60
+ def clear_cell(self, column: int, row: int) -> None:
61
+ """Clear a cell at the specified position."""
62
+ if (column, row) in self.cells:
63
+ del self.cells[(column, row)]
64
+
65
+ def clear_cells(self, start_column: int, start_row: int, end_column: int, end_row: int) -> None:
66
+ """Clear a range of cells."""
67
+ for col in range(start_column, end_column + 1):
68
+ for row in range(start_row, end_row + 1):
69
+ self.clear_cell(col, row)
70
+
71
+ def merge_cells(self, start_column: int, start_row: int, end_column: int, end_row: int) -> None:
72
+ """Merge a range of cells."""
73
+ # Create or get the main cell (top-left)
74
+ main_cell = self.get_cell(start_column, start_row)
75
+
76
+ # Mark cells in the range as merged
77
+ for col in range(start_column, end_column + 1):
78
+ for row in range(start_row, end_row + 1):
79
+ cell = self.get_cell(col, row)
80
+ cell.is_merged = True
81
+ cell.merge_start_col = start_column
82
+ cell.merge_start_row = start_row
83
+ cell.merge_end_col = end_column
84
+ cell.merge_end_row = end_row
85
+
86
+ # The main cell retains its content, others are effectively hidden
87
+ main_cell.is_merged = True
pynecore/types/text.py ADDED
@@ -0,0 +1,13 @@
1
+ from .base import StrLiteral
2
+
3
+
4
+ class AlignEnum(StrLiteral):
5
+ ...
6
+
7
+
8
+ class FormatEnum(StrLiteral):
9
+ ...
10
+
11
+
12
+ class WrapEnum(StrLiteral):
13
+ ...
@@ -0,0 +1,7 @@
1
+ from builtins import float, int, bool # noqa
2
+
3
+ __all__ = [
4
+ "float",
5
+ "int",
6
+ "bool"
7
+ ]
@@ -0,0 +1,48 @@
1
+ """
2
+ Pine Script type checker compatibility layer.
3
+
4
+ In Pine Script (and PyneCore), every variable is implicitly a Series — meaning even a plain
5
+ ``float`` supports historical indexing like ``close[1]`` (the previous bar's value). At runtime
6
+ the AST transformer handles this, but IDEs (PyCharm, etc.) only see the static types. Since
7
+ ``Series[float]`` is a transparent alias for ``float`` (see series.pyi), strict type checkers
8
+ complain that ``float`` has no ``__getitem__``.
9
+
10
+ This module solves it by re-exporting ``float``, ``int``, and ``bool`` as enhanced subclasses
11
+ **only under TYPE_CHECKING** (i.e., only visible to the IDE, zero runtime cost). The enhanced
12
+ versions inherit from their builtins and add ``__getitem__``, so every member of the Series union
13
+ becomes indexable in the IDE's eyes.
14
+
15
+ Usage in @pyne files (via the TypeCheckingStripperTransformer, these are removed at runtime)::
16
+
17
+ from typing import TYPE_CHECKING
18
+ if TYPE_CHECKING:
19
+ from pynecore.types.type_checker import *
20
+
21
+ Or import via ``pine_types`` which re-exports these automatically::
22
+
23
+ from pynecore.types import PyneFloat # already includes the enhanced float
24
+
25
+ Pyright/basedpyright: set ``"defineConstant": {"TYPECHECKER": "pyright"}`` in pyrightconfig.json
26
+ PyCharm: set ``TYPECHECKER=pycharm`` environment variable
27
+ """
28
+ import builtins
29
+
30
+ TYPECHECKER: str
31
+
32
+ if TYPECHECKER == "pycharm":
33
+ # noinspection PyPep8Naming,PyRedeclaration,PyShadowingBuiltins
34
+ class float(builtins.float):
35
+ def __getitem__(self, index: builtins.int) -> builtins.float: ...
36
+
37
+ # noinspection PyPep8Naming,PyRedeclaration,PyShadowingBuiltins
38
+ class int(builtins.int):
39
+ def __getitem__(self, index: builtins.int) -> builtins.int: ...
40
+
41
+ # noinspection PyPep8Naming,PyRedeclaration,PyShadowingBuiltins
42
+ class bool(builtins.bool): # type: ignore
43
+ def __getitem__(self, index: builtins.int) -> builtins.bool: ...
44
+
45
+ else:
46
+ float = builtins.float
47
+ int = builtins.int
48
+ bool = builtins.bool
@@ -0,0 +1,36 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass(slots=True)
5
+ class VolumeRow:
6
+ """
7
+ Represents a single price row within a footprint bar. Contains volume data
8
+ for a specific price level, including buy/sell volume and price boundaries.
9
+
10
+ Returned by footprint methods such as ``footprint.vah()``, ``footprint.val()``,
11
+ and ``footprint.poc()``.
12
+ """
13
+
14
+ def up_price(self) -> float:
15
+ """Upper price boundary of the row."""
16
+ raise NotImplementedError("VolumeRow.up_price() is not yet implemented in PyneCore")
17
+
18
+ def down_price(self) -> float:
19
+ """Lower price boundary of the row."""
20
+ raise NotImplementedError("VolumeRow.down_price() is not yet implemented in PyneCore")
21
+
22
+ def buy_volume(self) -> float:
23
+ """Buy volume for this row."""
24
+ raise NotImplementedError("VolumeRow.buy_volume() is not yet implemented in PyneCore")
25
+
26
+ def sell_volume(self) -> float:
27
+ """Sell volume for this row."""
28
+ raise NotImplementedError("VolumeRow.sell_volume() is not yet implemented in PyneCore")
29
+
30
+ def delta(self) -> float:
31
+ """Volume delta (buy - sell) for this row."""
32
+ raise NotImplementedError("VolumeRow.delta() is not yet implemented in PyneCore")
33
+
34
+ def total_volume(self) -> float:
35
+ """Total volume for this row."""
36
+ raise NotImplementedError("VolumeRow.total_volume() is not yet implemented in PyneCore")
@@ -0,0 +1,11 @@
1
+ from enum import IntEnum
2
+
3
+
4
+ class Weekdays(IntEnum):
5
+ Sun = 6
6
+ Mon = 0
7
+ Tue = 1
8
+ Wed = 2
9
+ Thu = 3
10
+ Fri = 4
11
+ Sat = 5
pynecore/types/xloc.py ADDED
@@ -0,0 +1,5 @@
1
+ from .base import StrLiteral
2
+
3
+
4
+ class XLoc(StrLiteral):
5
+ ...
pynecore/types/yloc.py ADDED
@@ -0,0 +1,5 @@
1
+ from .base import StrLiteral
2
+
3
+
4
+ class YLoc(StrLiteral):
5
+ ...
File without changes
@@ -0,0 +1,50 @@
1
+ """
2
+ File utilities
3
+ """
4
+ import os
5
+ from pathlib import Path
6
+
7
+
8
+ def copy_mtime(source_path: Path, target_path: Path) -> bool:
9
+ """Copy modification time from source to target file.
10
+
11
+ :param source_path: Source file to copy mtime from
12
+ :param target_path: Target file to set mtime on
13
+ :return: True if successful, False otherwise
14
+ """
15
+ try:
16
+ source_mtime = source_path.stat().st_mtime
17
+ except (OSError, FileNotFoundError):
18
+ return False
19
+
20
+ try:
21
+ os.utime(target_path, (source_mtime, source_mtime))
22
+ return True
23
+ except (OSError, FileNotFoundError):
24
+ return False
25
+
26
+
27
+ def is_updated(src_path: Path, dest_path: Path) -> bool:
28
+ """
29
+ Check if a file is updated using modification time comparison.
30
+
31
+ :param src_path: Path to the .pine file
32
+ :param dest_path: Path to the compiled .py file
33
+ :return: True if compilation is needed, False otherwise
34
+ :raises FileNotFoundError: If pine file doesn't exist
35
+ :raises OSError: If we can't get modification times
36
+ """
37
+
38
+ # If output file doesn't exist, compilation is needed
39
+ if not dest_path.exists():
40
+ return True
41
+ # If source file doesn't exist, assume compilation is needed
42
+ if not src_path.exists():
43
+ raise FileNotFoundError(f"Source file not found: {src_path}")
44
+
45
+ # Get modification times
46
+ src_mtime = os.path.getmtime(src_path)
47
+ dst_mtime = os.path.getmtime(dest_path)
48
+
49
+ # If source is newer than output, compilation is needed
50
+ return src_mtime > dst_mtime
File without changes
@@ -0,0 +1,25 @@
1
+ from datetime import datetime, timedelta
2
+
3
+ from rich.text import Text
4
+ from rich.progress import ProgressColumn
5
+
6
+
7
+ class DateColumn(ProgressColumn):
8
+ """Custom progress column showing the current date being processed.
9
+
10
+ The start time can come from the constructor (when the task spans a
11
+ single fixed range) or from a per-task ``start_time`` field — useful
12
+ for retry loops that re-anchor the start as they extend the request
13
+ window without spawning a new spinner each time.
14
+ """
15
+
16
+ def __init__(self, start_time: datetime | None = None):
17
+ super().__init__()
18
+ self.start_time = start_time
19
+
20
+ def render(self, task) -> Text:
21
+ start_time = task.fields.get('start_time', self.start_time)
22
+ if start_time is None:
23
+ return Text("")
24
+ current_date = start_time + timedelta(seconds=task.completed)
25
+ return Text(current_date.strftime("%Y-%m-%d %H:%M"), style="magenta")
@@ -0,0 +1,92 @@
1
+ from __future__ import annotations
2
+ from collections.abc import MutableSequence
3
+ from typing import TypeVar, Iterator, cast, overload
4
+
5
+ T = TypeVar('T')
6
+
7
+
8
+ class SequenceView(MutableSequence[T]):
9
+ """
10
+ A view for list slice
11
+
12
+ Useful for creating a slice of list but modifying the slice will modify the original list.
13
+ And vice versa.
14
+
15
+ Mutating operations (append/insert/pop/remove/etc. — provided by the
16
+ ``MutableSequence`` mixin on top of ``insert`` and ``__delitem__``) write
17
+ through to the parent sequence, matching Pine's ``array.slice`` semantics
18
+ where pushing to or removing from a slice also grows or shrinks the original
19
+ array. ``array.slice`` always builds a contiguous, forward (step 1) range.
20
+ """
21
+
22
+ __slots__ = ('sequence', 'range')
23
+
24
+ def __init__(self, sequence: MutableSequence[T], range_object: range | None = None) -> None:
25
+ self.range: range = range_object if range_object is not None else range(len(sequence))
26
+ self.sequence = sequence
27
+
28
+ @overload
29
+ def __getitem__(self, key: int) -> T: ...
30
+
31
+ @overload
32
+ def __getitem__(self, key: slice) -> SequenceView[T]: ...
33
+
34
+ def __getitem__(self, key: int | slice) -> T | SequenceView[T]:
35
+ if isinstance(key, slice):
36
+ return SequenceView(self.sequence, self.range[key])
37
+ else:
38
+ return self.sequence[self.range[key]]
39
+
40
+ def __setitem__(self, key: int | slice, value: T) -> None:
41
+ if isinstance(key, slice):
42
+ for i in self.range[key]:
43
+ self.sequence[i] = value
44
+ else:
45
+ self.sequence[self.range[key]] = value
46
+
47
+ def __delitem__(self, key: int | slice) -> None:
48
+ if isinstance(key, slice):
49
+ # Delete from the parent at the mapped indices, highest first so the
50
+ # earlier indices stay valid; then shrink this view's range.
51
+ removed = 0
52
+ for i in sorted(self.range[key], reverse=True):
53
+ del self.sequence[i]
54
+ removed += 1
55
+ self.range = range(self.range.start, self.range.stop - removed)
56
+ else:
57
+ n = len(self.range)
58
+ if key < 0:
59
+ key += n
60
+ if not 0 <= key < n:
61
+ raise IndexError("SequenceView index out of range")
62
+ del self.sequence[self.range[key]]
63
+ self.range = range(self.range.start, self.range.stop - 1)
64
+
65
+ def insert(self, index: int, value: T) -> None:
66
+ # Insert into the parent at the mapped position and extend this view's
67
+ # range by one. Index is clamped like list.insert (append maps to the
68
+ # slice end, i.e. parent index range.stop — Pine's array.push on a slice).
69
+ n = len(self.range)
70
+ if index < 0:
71
+ index += n
72
+ index = max(0, min(index, n))
73
+ self.sequence.insert(self.range.start + index, value)
74
+ self.range = range(self.range.start, self.range.stop + 1)
75
+
76
+ def __len__(self) -> int:
77
+ return len(self.range)
78
+
79
+ def __iter__(self) -> Iterator[T]:
80
+ for i in self.range:
81
+ yield self.sequence[i]
82
+
83
+ def __repr__(self) -> str:
84
+ return f"SequenceView({self.sequence!r}, {self.range!r})"
85
+
86
+ def __str__(self) -> str:
87
+ if isinstance(self.sequence, str):
88
+ return ''.join(cast('Iterator[str]', self))
89
+ elif isinstance(self.sequence, (list, tuple)):
90
+ return str(type(self.sequence)(self))
91
+ else:
92
+ return repr(self)
@@ -0,0 +1,17 @@
1
+ import sys
2
+
3
+
4
+ def is_stdlib(module_name: str) -> bool:
5
+ """
6
+ Check whether a module belongs to Python's standard library.
7
+
8
+ Resolution is name-based via ``sys.stdlib_module_names`` (a frozenset of
9
+ every stdlib top-level module name on Python 3.10+; PyneCore requires
10
+ 3.11+). This is authoritative and independent of the install layout: a
11
+ path-based check misclassifies packages under
12
+ ``<prefix>/lib/pythonX.Y/site-packages`` as stdlib.
13
+
14
+ :param module_name: Full module path (e.g. ``os.path``).
15
+ :return: True if the module's top-level package is part of the stdlib.
16
+ """
17
+ return module_name.split('.', 1)[0] in sys.stdlib_module_names