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.
- opencode_pyneruntime-6.6.4.dist-info/METADATA +281 -0
- opencode_pyneruntime-6.6.4.dist-info/RECORD +261 -0
- opencode_pyneruntime-6.6.4.dist-info/WHEEL +5 -0
- opencode_pyneruntime-6.6.4.dist-info/entry_points.txt +6 -0
- opencode_pyneruntime-6.6.4.dist-info/licenses/LICENSE +201 -0
- opencode_pyneruntime-6.6.4.dist-info/licenses/NOTICE +21 -0
- opencode_pyneruntime-6.6.4.dist-info/top_level.txt +1 -0
- pynecore/__init__.py +6 -0
- pynecore/cli/__init__.py +2 -0
- pynecore/cli/app.py +238 -0
- pynecore/cli/commands/__init__.py +343 -0
- pynecore/cli/commands/benchmark.py +186 -0
- pynecore/cli/commands/compile.py +198 -0
- pynecore/cli/commands/data.py +857 -0
- pynecore/cli/commands/debug.py +63 -0
- pynecore/cli/commands/optimize.py +956 -0
- pynecore/cli/commands/plugin.py +242 -0
- pynecore/cli/commands/run.py +2006 -0
- pynecore/cli/pluggable.py +132 -0
- pynecore/cli/utils/__init__.py +0 -0
- pynecore/cli/utils/api_error_handler.py +168 -0
- pynecore/cli/utils/broker_picker.py +330 -0
- pynecore/cli/utils/error_hook.py +28 -0
- pynecore/cli/utils/keyreader.py +178 -0
- pynecore/cli/utils/provider_picker.py +19 -0
- pynecore/cli/utils/symbol_browser.py +1149 -0
- pynecore/core/__init__.py +0 -0
- pynecore/core/aggregator.py +257 -0
- pynecore/core/bar_magnifier.py +168 -0
- pynecore/core/broker/__init__.py +64 -0
- pynecore/core/broker/defaults.py +113 -0
- pynecore/core/broker/disappearance.py +927 -0
- pynecore/core/broker/emulator.py +345 -0
- pynecore/core/broker/exceptions.py +346 -0
- pynecore/core/broker/idempotency.py +401 -0
- pynecore/core/broker/intent_builder.py +334 -0
- pynecore/core/broker/journal.py +1785 -0
- pynecore/core/broker/models.py +1600 -0
- pynecore/core/broker/native_failsafe_manager.py +1436 -0
- pynecore/core/broker/one_way_emulator.py +1128 -0
- pynecore/core/broker/position.py +787 -0
- pynecore/core/broker/run_identity.py +126 -0
- pynecore/core/broker/software_entry_stop_engine.py +351 -0
- pynecore/core/broker/software_partial_bracket_engine.py +1379 -0
- pynecore/core/broker/spot_inventory.py +1327 -0
- pynecore/core/broker/storage.py +2655 -0
- pynecore/core/broker/store_helpers.py +2161 -0
- pynecore/core/broker/sync_engine.py +16070 -0
- pynecore/core/broker/validation.py +382 -0
- pynecore/core/class_property.py +7 -0
- pynecore/core/config.py +392 -0
- pynecore/core/csv_file.py +547 -0
- pynecore/core/currency.py +262 -0
- pynecore/core/data_converter.py +1002 -0
- pynecore/core/datetime.py +296 -0
- pynecore/core/download_info.py +71 -0
- pynecore/core/download_runner.py +274 -0
- pynecore/core/htf_aggregator.py +181 -0
- pynecore/core/import_hook.py +358 -0
- pynecore/core/instance_state.py +494 -0
- pynecore/core/live_ltf_collector.py +442 -0
- pynecore/core/live_ltf_window.py +189 -0
- pynecore/core/live_runner.py +1347 -0
- pynecore/core/module_property.py +26 -0
- pynecore/core/ohlcv_file.py +1888 -0
- pynecore/core/overload.py +371 -0
- pynecore/core/pine_cast.py +113 -0
- pynecore/core/pine_export.py +95 -0
- pynecore/core/pine_method.py +244 -0
- pynecore/core/pine_range.py +86 -0
- pynecore/core/pine_udt.py +69 -0
- pynecore/core/plugin/__init__.py +394 -0
- pynecore/core/plugin/broker.py +781 -0
- pynecore/core/plugin/cli.py +96 -0
- pynecore/core/plugin/live_provider.py +208 -0
- pynecore/core/plugin/provider.py +331 -0
- pynecore/core/provider_string.py +148 -0
- pynecore/core/random.py +40 -0
- pynecore/core/resampler.py +686 -0
- pynecore/core/safe_convert.py +64 -0
- pynecore/core/script.py +1011 -0
- pynecore/core/script_runner.py +3202 -0
- pynecore/core/security.py +1749 -0
- pynecore/core/security_process.py +1253 -0
- pynecore/core/security_shm.py +456 -0
- pynecore/core/series.py +417 -0
- pynecore/core/strategy_stats.py +669 -0
- pynecore/core/symbol_map.py +134 -0
- pynecore/core/syminfo.py +505 -0
- pynecore/core/viz.py +591 -0
- pynecore/lib/__init__.py +1771 -0
- pynecore/lib/_fixnan.py +32 -0
- pynecore/lib/_math_stateful.py +202 -0
- pynecore/lib/_timeframe_change.py +101 -0
- pynecore/lib/adjustment.py +6 -0
- pynecore/lib/alert.py +39 -0
- pynecore/lib/alert.pyi +14 -0
- pynecore/lib/array.py +1051 -0
- pynecore/lib/barmerge.py +60 -0
- pynecore/lib/barstate.py +30 -0
- pynecore/lib/box.py +415 -0
- pynecore/lib/chart.py +128 -0
- pynecore/lib/color.py +152 -0
- pynecore/lib/color.pyi +50 -0
- pynecore/lib/currency.py +62 -0
- pynecore/lib/dayofweek.py +36 -0
- pynecore/lib/dayofweek.pyi +18 -0
- pynecore/lib/display.py +8 -0
- pynecore/lib/dividends.py +9 -0
- pynecore/lib/earnings.py +11 -0
- pynecore/lib/extend.py +6 -0
- pynecore/lib/font.py +5 -0
- pynecore/lib/footprint.py +79 -0
- pynecore/lib/format.py +11 -0
- pynecore/lib/hline.py +67 -0
- pynecore/lib/hline.pyi +24 -0
- pynecore/lib/label.py +409 -0
- pynecore/lib/line.py +433 -0
- pynecore/lib/linefill.py +93 -0
- pynecore/lib/location.py +11 -0
- pynecore/lib/log.py +362 -0
- pynecore/lib/map.py +150 -0
- pynecore/lib/math.py +385 -0
- pynecore/lib/matrix.py +708 -0
- pynecore/lib/order.py +8 -0
- pynecore/lib/pivotpointtype.py +8 -0
- pynecore/lib/plot.py +95 -0
- pynecore/lib/plot.pyi +33 -0
- pynecore/lib/polyline.py +91 -0
- pynecore/lib/position.py +15 -0
- pynecore/lib/request.py +281 -0
- pynecore/lib/runtime.py +5 -0
- pynecore/lib/scale.py +9 -0
- pynecore/lib/session.py +267 -0
- pynecore/lib/session.pyi +12 -0
- pynecore/lib/shape.py +18 -0
- pynecore/lib/size.py +12 -0
- pynecore/lib/splits.py +4 -0
- pynecore/lib/strategy/__init__.py +4778 -0
- pynecore/lib/strategy/closedtrades.py +347 -0
- pynecore/lib/strategy/closedtrades.pyi +53 -0
- pynecore/lib/strategy/commission.py +9 -0
- pynecore/lib/strategy/direction.py +9 -0
- pynecore/lib/strategy/oca.py +13 -0
- pynecore/lib/strategy/opentrades.py +281 -0
- pynecore/lib/strategy/opentrades.pyi +49 -0
- pynecore/lib/strategy/risk.py +109 -0
- pynecore/lib/string.py +649 -0
- pynecore/lib/syminfo.py +84 -0
- pynecore/lib/ta.py +2230 -0
- pynecore/lib/table.py +290 -0
- pynecore/lib/text.py +17 -0
- pynecore/lib/ticker.py +207 -0
- pynecore/lib/timeframe.py +293 -0
- pynecore/lib/volume_row.py +67 -0
- pynecore/lib/xloc.py +4 -0
- pynecore/lib/yloc.py +5 -0
- pynecore/providers/__init__.py +0 -0
- pynecore/providers/ccxt.py +664 -0
- pynecore/providers/replay.py +187 -0
- pynecore/pynesys/__init__.py +0 -0
- pynecore/pynesys/api.py +498 -0
- pynecore/pynesys/compiler.py +112 -0
- pynecore/standalone.py +99 -0
- pynecore/testing/__init__.py +1 -0
- pynecore/testing/broker_lab/__init__.py +41 -0
- pynecore/testing/broker_lab/__main__.py +5 -0
- pynecore/testing/broker_lab/cli.py +87 -0
- pynecore/testing/broker_lab/generate.py +47 -0
- pynecore/testing/broker_lab/model.py +84 -0
- pynecore/testing/broker_lab/reference.py +645 -0
- pynecore/testing/broker_lab/runner.py +372 -0
- pynecore/testing/broker_lab/scheduler.py +50 -0
- pynecore/testing/broker_lab/subprocess.py +73 -0
- pynecore/transformers/__init__.py +0 -0
- pynecore/transformers/builtin_shadow.py +136 -0
- pynecore/transformers/closure_arguments_transformer.py +428 -0
- pynecore/transformers/display_rewrite.py +140 -0
- pynecore/transformers/dynamic_default.py +147 -0
- pynecore/transformers/function_isolation.py +757 -0
- pynecore/transformers/import_lifter.py +61 -0
- pynecore/transformers/import_normalizer.py +328 -0
- pynecore/transformers/inline_series_hoist.py +178 -0
- pynecore/transformers/input_transformer.py +175 -0
- pynecore/transformers/lib_series.py +201 -0
- pynecore/transformers/locations.py +70 -0
- pynecore/transformers/module_properties.json +3387 -0
- pynecore/transformers/module_property.py +221 -0
- pynecore/transformers/ne_guard.py +70 -0
- pynecore/transformers/persistent.py +320 -0
- pynecore/transformers/persistent_series.py +76 -0
- pynecore/transformers/safe_convert_transformer.py +97 -0
- pynecore/transformers/safe_division_transformer.py +95 -0
- pynecore/transformers/script_requirements.py +308 -0
- pynecore/transformers/security.py +752 -0
- pynecore/transformers/security_instantiation.py +274 -0
- pynecore/transformers/series.py +275 -0
- pynecore/transformers/slot_layout.py +381 -0
- pynecore/transformers/type_checking_stripper.py +25 -0
- pynecore/transformers/unused_series_detector.py +267 -0
- pynecore/types/__init__.py +21 -0
- pynecore/types/alert.py +5 -0
- pynecore/types/barmerge.py +5 -0
- pynecore/types/base.py +39 -0
- pynecore/types/box.py +37 -0
- pynecore/types/chart.py +17 -0
- pynecore/types/color.py +107 -0
- pynecore/types/currency.py +5 -0
- pynecore/types/datetime.py +6 -0
- pynecore/types/display.py +5 -0
- pynecore/types/dividends.py +5 -0
- pynecore/types/earnings.py +5 -0
- pynecore/types/extend.py +5 -0
- pynecore/types/font.py +5 -0
- pynecore/types/footprint.py +41 -0
- pynecore/types/format.py +5 -0
- pynecore/types/hline.py +24 -0
- pynecore/types/ib_persistent.py +8 -0
- pynecore/types/ib_persistent.pyi +10 -0
- pynecore/types/label.py +35 -0
- pynecore/types/line.py +32 -0
- pynecore/types/linefill.py +13 -0
- pynecore/types/location.py +5 -0
- pynecore/types/matrix.py +999 -0
- pynecore/types/na.py +237 -0
- pynecore/types/na.pyi +83 -0
- pynecore/types/ohlcv.py +12 -0
- pynecore/types/order.py +5 -0
- pynecore/types/persistent.py +8 -0
- pynecore/types/persistent.pyi +13 -0
- pynecore/types/pine_types.py +11 -0
- pynecore/types/pine_types.pyi +15 -0
- pynecore/types/pivotpointtype.py +5 -0
- pynecore/types/plot.py +12 -0
- pynecore/types/plot_meta.py +60 -0
- pynecore/types/polyline.py +40 -0
- pynecore/types/position.py +5 -0
- pynecore/types/scale.py +5 -0
- pynecore/types/script_type.py +15 -0
- pynecore/types/series.py +23 -0
- pynecore/types/series.pyi +19 -0
- pynecore/types/session.py +35 -0
- pynecore/types/shape.py +5 -0
- pynecore/types/size.py +5 -0
- pynecore/types/source.py +33 -0
- pynecore/types/splits.py +5 -0
- pynecore/types/strategy.py +45 -0
- pynecore/types/table.py +87 -0
- pynecore/types/text.py +13 -0
- pynecore/types/type_checker.py +7 -0
- pynecore/types/type_checker.pyi +48 -0
- pynecore/types/volume_row.py +36 -0
- pynecore/types/weekdays.py +11 -0
- pynecore/types/xloc.py +5 -0
- pynecore/types/yloc.py +5 -0
- pynecore/utils/__init__.py +0 -0
- pynecore/utils/file_utils.py +50 -0
- pynecore/utils/rich/__init__.py +0 -0
- pynecore/utils/rich/date_column.py +25 -0
- pynecore/utils/sequence_view.py +92 -0
- 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
|
+
...
|
pynecore/types/table.py
ADDED
|
@@ -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,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")
|
pynecore/types/xloc.py
ADDED
pynecore/types/yloc.py
ADDED
|
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
|