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
pynecore/types/na.py
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
from math import isfinite
|
|
2
|
+
from typing import Any, TypeVar, Generic, Type, Self
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
'NA', 'na_float', 'na_int', 'na_bool', 'na_str', 'isna_num',
|
|
6
|
+
]
|
|
7
|
+
|
|
8
|
+
T = TypeVar('T')
|
|
9
|
+
|
|
10
|
+
# The one float na: Pine's float-typed na IS a native IEEE-754 nan.
|
|
11
|
+
# Interned so identity-based fast paths (dict key lookup, ``is`` checks)
|
|
12
|
+
# always see the same object when the na came from ``NA(float)``.
|
|
13
|
+
_NAN = float('nan')
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def isna_num(x: Any) -> bool:
|
|
17
|
+
"""
|
|
18
|
+
Representation-agnostic na test for numeric (float-typed) values.
|
|
19
|
+
|
|
20
|
+
Accepts both representations of a Pine numeric na: the ``NA`` object and a
|
|
21
|
+
native non-finite float. Uses Pine's ``na()`` predicate semantics
|
|
22
|
+
(``not isfinite``), so ``inf`` and ``-inf`` count as na too — matching
|
|
23
|
+
TradingView, where ``na(inf)`` is ``true``.
|
|
24
|
+
|
|
25
|
+
Cold paths only: never call this in a per-bar hot loop. Hot loops use the
|
|
26
|
+
inline idioms ``x != x`` (nan-only) or ``isinstance(x, NA) or x != x``.
|
|
27
|
+
|
|
28
|
+
:param x: value to test
|
|
29
|
+
:return: ``True`` if ``x`` is a numeric na, ``False`` otherwise
|
|
30
|
+
"""
|
|
31
|
+
if isinstance(x, NA):
|
|
32
|
+
return True
|
|
33
|
+
try:
|
|
34
|
+
return not isfinite(x)
|
|
35
|
+
except TypeError:
|
|
36
|
+
return False
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class NA(Generic[T]):
|
|
40
|
+
"""
|
|
41
|
+
Class representing NA (Not Available) values for non-float types.
|
|
42
|
+
|
|
43
|
+
``NA(float)`` does NOT construct an instance: it returns the interned
|
|
44
|
+
native ``float('nan')`` — Pine's float na is a real IEEE-754 nan, so
|
|
45
|
+
arithmetic and comparisons on it run at native float speed. This shim in
|
|
46
|
+
``__new__`` is a permanent compatibility contract: every already-compiled
|
|
47
|
+
script calling ``NA(float)`` (and the ``na(float)`` constructor face)
|
|
48
|
+
transparently produces the native nan.
|
|
49
|
+
|
|
50
|
+
All other types (int, str, drawing objects, UDTs, ...) get interned NA
|
|
51
|
+
instances: every operation returns self, every comparison is False.
|
|
52
|
+
"""
|
|
53
|
+
__slots__ = ('type',)
|
|
54
|
+
|
|
55
|
+
_type_cache: dict[Type | None, 'NA'] = {}
|
|
56
|
+
|
|
57
|
+
# noinspection PyShadowingBuiltins
|
|
58
|
+
def __new__(cls, type: Type[T] | T | None = int) -> Self:
|
|
59
|
+
if type is float:
|
|
60
|
+
return _NAN # type: ignore[return-value]
|
|
61
|
+
try:
|
|
62
|
+
return cls._type_cache[type] # type: ignore[reportReturnType]
|
|
63
|
+
except KeyError:
|
|
64
|
+
na = super().__new__(cls)
|
|
65
|
+
cls._type_cache[type] = na
|
|
66
|
+
return na
|
|
67
|
+
|
|
68
|
+
# noinspection PyShadowingBuiltins
|
|
69
|
+
def __init__(self, type: Type[T] | T | None = int) -> None:
|
|
70
|
+
"""
|
|
71
|
+
Initialize a new NA value with an optional type parameter.
|
|
72
|
+
The default type is int.
|
|
73
|
+
"""
|
|
74
|
+
self.type = type
|
|
75
|
+
|
|
76
|
+
def __repr__(self) -> str:
|
|
77
|
+
if self.type is None:
|
|
78
|
+
return "NA"
|
|
79
|
+
return f"NA[{self.type.__name__}]" # type: ignore
|
|
80
|
+
|
|
81
|
+
def __str__(self) -> str:
|
|
82
|
+
return ""
|
|
83
|
+
|
|
84
|
+
def __format__(self, format_spec: str) -> str:
|
|
85
|
+
return "NaN"
|
|
86
|
+
|
|
87
|
+
def __hash__(self) -> int:
|
|
88
|
+
return hash(self.type)
|
|
89
|
+
|
|
90
|
+
def __int__(self) -> 'NA[int]':
|
|
91
|
+
# We solve this with an AST Transformer
|
|
92
|
+
raise TypeError("NA cannot be converted to int")
|
|
93
|
+
|
|
94
|
+
def __float__(self) -> 'NA[float]':
|
|
95
|
+
# We solve this with an AST Transformer
|
|
96
|
+
raise TypeError("NA cannot be converted to float")
|
|
97
|
+
|
|
98
|
+
def __bool__(self) -> bool:
|
|
99
|
+
return False
|
|
100
|
+
|
|
101
|
+
def __round__(self, n=None) -> Self:
|
|
102
|
+
return self
|
|
103
|
+
|
|
104
|
+
#
|
|
105
|
+
# Arithmetic operations — every operation propagates self
|
|
106
|
+
#
|
|
107
|
+
|
|
108
|
+
def __neg__(self) -> Self:
|
|
109
|
+
return self
|
|
110
|
+
|
|
111
|
+
def __add__(self, _: Any) -> Self:
|
|
112
|
+
return self
|
|
113
|
+
|
|
114
|
+
def __radd__(self, _: Any) -> Self:
|
|
115
|
+
return self
|
|
116
|
+
|
|
117
|
+
def __sub__(self, _: Any) -> Self:
|
|
118
|
+
return self
|
|
119
|
+
|
|
120
|
+
def __rsub__(self, _: Any) -> Self:
|
|
121
|
+
return self
|
|
122
|
+
|
|
123
|
+
def __mul__(self, _: Any) -> Self:
|
|
124
|
+
return self
|
|
125
|
+
|
|
126
|
+
def __rmul__(self, _: Any) -> Self:
|
|
127
|
+
return self
|
|
128
|
+
|
|
129
|
+
def __truediv__(self, _: Any) -> Self:
|
|
130
|
+
return self
|
|
131
|
+
|
|
132
|
+
def __rtruediv__(self, _: Any) -> Self:
|
|
133
|
+
return self
|
|
134
|
+
|
|
135
|
+
def __mod__(self, _: Any) -> Self:
|
|
136
|
+
return self
|
|
137
|
+
|
|
138
|
+
def __rmod__(self, _: Any) -> Self:
|
|
139
|
+
return self
|
|
140
|
+
|
|
141
|
+
def __abs__(self) -> Self:
|
|
142
|
+
return self
|
|
143
|
+
|
|
144
|
+
#
|
|
145
|
+
# Bitwise operations
|
|
146
|
+
#
|
|
147
|
+
|
|
148
|
+
def __and__(self, _: Any) -> Self:
|
|
149
|
+
return self
|
|
150
|
+
|
|
151
|
+
def __rand__(self, _: Any) -> Self:
|
|
152
|
+
return self
|
|
153
|
+
|
|
154
|
+
def __or__(self, _: Any) -> Self:
|
|
155
|
+
return self
|
|
156
|
+
|
|
157
|
+
def __ror__(self, _: Any) -> Self:
|
|
158
|
+
return self
|
|
159
|
+
|
|
160
|
+
def __xor__(self, _: Any) -> Self:
|
|
161
|
+
return self
|
|
162
|
+
|
|
163
|
+
def __rxor__(self, _: Any) -> Self:
|
|
164
|
+
return self
|
|
165
|
+
|
|
166
|
+
def __lshift__(self, _: Any) -> Self:
|
|
167
|
+
return self
|
|
168
|
+
|
|
169
|
+
def __rlshift__(self, _: Any) -> Self:
|
|
170
|
+
return self
|
|
171
|
+
|
|
172
|
+
def __rshift__(self, _: Any) -> Self:
|
|
173
|
+
return self
|
|
174
|
+
|
|
175
|
+
def __rrshift__(self, _: Any) -> Self:
|
|
176
|
+
return self
|
|
177
|
+
|
|
178
|
+
def __invert__(self) -> Self:
|
|
179
|
+
return self
|
|
180
|
+
|
|
181
|
+
#
|
|
182
|
+
# Comparisons — all False (Pine semantics)
|
|
183
|
+
#
|
|
184
|
+
|
|
185
|
+
def __eq__(self, _: Any) -> bool:
|
|
186
|
+
return False
|
|
187
|
+
|
|
188
|
+
def __ne__(self, _: Any) -> bool:
|
|
189
|
+
return False
|
|
190
|
+
|
|
191
|
+
def __gt__(self, _: Any) -> bool:
|
|
192
|
+
return False
|
|
193
|
+
|
|
194
|
+
def __lt__(self, _: Any) -> bool:
|
|
195
|
+
return False
|
|
196
|
+
|
|
197
|
+
def __le__(self, _: Any) -> bool:
|
|
198
|
+
return False
|
|
199
|
+
|
|
200
|
+
def __ge__(self, _: Any) -> bool:
|
|
201
|
+
return False
|
|
202
|
+
|
|
203
|
+
#
|
|
204
|
+
# In contexts
|
|
205
|
+
#
|
|
206
|
+
|
|
207
|
+
def __getattr__(self, name: str) -> Self:
|
|
208
|
+
# Don't return self for special attributes
|
|
209
|
+
if name.startswith('__'):
|
|
210
|
+
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
|
|
211
|
+
return self
|
|
212
|
+
|
|
213
|
+
def __getitem__(self, _: Any) -> Self:
|
|
214
|
+
return self
|
|
215
|
+
|
|
216
|
+
def __contains__(self, _: Any) -> bool:
|
|
217
|
+
# ``x in na`` must short-circuit to False: ``__getitem__`` returns self
|
|
218
|
+
# for every index and never raises IndexError, so the ``in`` operator's
|
|
219
|
+
# sequence-protocol fallback would iterate forever.
|
|
220
|
+
return False
|
|
221
|
+
|
|
222
|
+
def __iter__(self) -> Any:
|
|
223
|
+
# NA is not a sequence. Without an explicit __iter__, ``iter(na)``
|
|
224
|
+
# (e.g. ``str.join(na)``, ``list(na)``, tuple unpacking) falls back to
|
|
225
|
+
# the sequence protocol and — since ``__getitem__`` returns self for
|
|
226
|
+
# every index — spins forever while building an unbounded list.
|
|
227
|
+
# Failing loudly is the only safe behavior here.
|
|
228
|
+
raise TypeError("na is not iterable")
|
|
229
|
+
|
|
230
|
+
def __call__(self, *_, **__) -> Self:
|
|
231
|
+
return self
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
na_float: float = _NAN
|
|
235
|
+
na_int = NA(int)
|
|
236
|
+
na_str = NA(str)
|
|
237
|
+
na_bool = NA(bool)
|
pynecore/types/na.pyi
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from typing import Any, TypeVar, Generic, Type, Iterator
|
|
2
|
+
|
|
3
|
+
T = TypeVar('T')
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def isna_num(x: Any) -> bool: ...
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class NA(Generic[T]):
|
|
10
|
+
type: Type[T] | T | None
|
|
11
|
+
|
|
12
|
+
# The "plain T" lie at its root: a constructed NA value types as T, so
|
|
13
|
+
# lib functions can return NA(X) under a plain -> X annotation and na
|
|
14
|
+
# sentinels flow anywhere an X is expected (in Pine any value can be na).
|
|
15
|
+
# No __init__ here: if the stub declares one, PyCharm ignores __new__'s
|
|
16
|
+
# return type and NA(float) degrades to NA[float] again.
|
|
17
|
+
def __new__(cls, type: Type[T] | T | None = int) -> T: ... # type: ignore[misc]
|
|
18
|
+
|
|
19
|
+
def __repr__(self) -> str: ...
|
|
20
|
+
def __str__(self) -> str: ...
|
|
21
|
+
def __format__(self, format_spec: str) -> str: ...
|
|
22
|
+
def __hash__(self) -> int: ...
|
|
23
|
+
def __bool__(self) -> bool: ...
|
|
24
|
+
def __round__(self, n: int = ...) -> Any: ...
|
|
25
|
+
|
|
26
|
+
# Protocol compliance: SupportsFloat, SupportsIndex
|
|
27
|
+
def __int__(self) -> int: ...
|
|
28
|
+
def __float__(self) -> float: ...
|
|
29
|
+
def __index__(self) -> int: ...
|
|
30
|
+
|
|
31
|
+
# Protocol compliance: Sized, Iterable
|
|
32
|
+
def __len__(self) -> int: ...
|
|
33
|
+
def __iter__(self) -> Iterator[Any]: ...
|
|
34
|
+
def __reversed__(self) -> Iterator[Any]: ...
|
|
35
|
+
|
|
36
|
+
# Arithmetic — return Any so NA propagates without type conflicts
|
|
37
|
+
def __neg__(self) -> Any: ...
|
|
38
|
+
def __add__(self, _: Any) -> Any: ...
|
|
39
|
+
def __radd__(self, _: Any) -> Any: ...
|
|
40
|
+
def __sub__(self, _: Any) -> Any: ...
|
|
41
|
+
def __rsub__(self, _: Any) -> Any: ...
|
|
42
|
+
def __mul__(self, _: Any) -> Any: ...
|
|
43
|
+
def __rmul__(self, _: Any) -> Any: ...
|
|
44
|
+
def __truediv__(self, _: Any) -> Any: ...
|
|
45
|
+
def __rtruediv__(self, _: Any) -> Any: ...
|
|
46
|
+
def __mod__(self, _: Any) -> Any: ...
|
|
47
|
+
def __rmod__(self, _: Any) -> Any: ...
|
|
48
|
+
def __abs__(self) -> Any: ...
|
|
49
|
+
|
|
50
|
+
# Bitwise
|
|
51
|
+
def __and__(self, _: Any) -> Any: ...
|
|
52
|
+
def __rand__(self, _: Any) -> Any: ...
|
|
53
|
+
def __or__(self, _: Any) -> Any: ...
|
|
54
|
+
def __ror__(self, _: Any) -> Any: ...
|
|
55
|
+
def __xor__(self, _: Any) -> Any: ...
|
|
56
|
+
def __rxor__(self, _: Any) -> Any: ...
|
|
57
|
+
def __lshift__(self, _: Any) -> Any: ...
|
|
58
|
+
def __rlshift__(self, _: Any) -> Any: ...
|
|
59
|
+
def __rshift__(self, _: Any) -> Any: ...
|
|
60
|
+
def __rrshift__(self, _: Any) -> Any: ...
|
|
61
|
+
def __invert__(self) -> Any: ...
|
|
62
|
+
|
|
63
|
+
# Comparison
|
|
64
|
+
def __eq__(self, _: Any) -> bool: ...
|
|
65
|
+
def __gt__(self, _: Any) -> bool: ...
|
|
66
|
+
def __lt__(self, _: Any) -> bool: ...
|
|
67
|
+
def __le__(self, _: Any) -> bool: ...
|
|
68
|
+
def __ge__(self, _: Any) -> bool: ...
|
|
69
|
+
|
|
70
|
+
# Catch-all for attribute access and indexing
|
|
71
|
+
def __getattr__(self, name: str) -> Any: ...
|
|
72
|
+
def __getitem__(self, _: Any) -> Any: ...
|
|
73
|
+
def __call__(self, *_: Any, **__: Any) -> Any: ...
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# The singleton constants wear the same "plain T" face as __new__ above:
|
|
77
|
+
# na_float must be assignable wherever a float is, or every hot-path use of the
|
|
78
|
+
# interned constants (instead of an NA(float) call) would false-positive.
|
|
79
|
+
# (na_float genuinely IS a float now — the interned native nan.)
|
|
80
|
+
na_float: float
|
|
81
|
+
na_int: int
|
|
82
|
+
na_str: str
|
|
83
|
+
na_bool: bool
|
pynecore/types/ohlcv.py
ADDED
pynecore/types/order.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Persistent is a transparent alias for type checkers: ``Persistent[T]`` IS ``T``.
|
|
3
|
+
|
|
4
|
+
NA is deliberately dropped from the static view (the "plain T" policy): in Pine
|
|
5
|
+
semantics any value can be na, so a ``T | NA[T]`` union only produces noise on
|
|
6
|
+
every arithmetic use. Runtime (persistent.py) is unchanged — this stub exists
|
|
7
|
+
because a bare TypeVar is not subscriptable at runtime.
|
|
8
|
+
"""
|
|
9
|
+
from typing import TypeVar, TypeAlias
|
|
10
|
+
|
|
11
|
+
T = TypeVar('T')
|
|
12
|
+
|
|
13
|
+
Persistent: TypeAlias = T
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from typing import TypeAlias, TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from pynecore.types.type_checker import *
|
|
5
|
+
from pynecore.types.na import NA
|
|
6
|
+
from pynecore.types.series import Series
|
|
7
|
+
|
|
8
|
+
PyneFloat: TypeAlias = float | NA[float] | Series[float]
|
|
9
|
+
PyneInt: TypeAlias = int | NA[int] | Series[int]
|
|
10
|
+
PyneStr: TypeAlias = str | NA[str] | Series[str]
|
|
11
|
+
PyneBool: TypeAlias = bool | NA[bool] | Series[bool]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
NA-free static view of the Pyne scalar aliases (the "plain T" policy — see
|
|
3
|
+
persistent.pyi). The ``type_checker`` wildcard import swaps ``float``/``int``/
|
|
4
|
+
``bool`` for their ``[n]``-indexable subclasses under PyCharm
|
|
5
|
+
(``TYPECHECKER=pycharm``); under pyright they stay the builtins.
|
|
6
|
+
Runtime (pine_types.py) is unchanged.
|
|
7
|
+
"""
|
|
8
|
+
from typing import TypeAlias
|
|
9
|
+
|
|
10
|
+
from pynecore.types.type_checker import *
|
|
11
|
+
|
|
12
|
+
PyneFloat: TypeAlias = float
|
|
13
|
+
PyneInt: TypeAlias = int
|
|
14
|
+
PyneStr: TypeAlias = str
|
|
15
|
+
PyneBool: TypeAlias = bool
|
pynecore/types/plot.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from .color import Color
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(slots=True)
|
|
8
|
+
class PlotMeta:
|
|
9
|
+
"""
|
|
10
|
+
Static (registered-once) metadata for a plot-family output.
|
|
11
|
+
|
|
12
|
+
Covers every plot family (``plot``, ``plotshape``, ``plotchar``, ``plotarrow``,
|
|
13
|
+
``plotcandle``, ``plotbar``, ``bgcolor``, ``barcolor``, ``hline``, ``fill``); the
|
|
14
|
+
serializer drops ``None`` fields and applies kind-specific defaults. Per-bar values
|
|
15
|
+
(the series data and dynamic color channels) live elsewhere; this object only holds
|
|
16
|
+
what is fixed for the whole run.
|
|
17
|
+
"""
|
|
18
|
+
id: str
|
|
19
|
+
kind: str # 'plot'|'shape'|'char'|'arrow'|'candle'|'bar'|'bgcolor'|'barcolor'|'hline'|'fill'
|
|
20
|
+
|
|
21
|
+
title: str | None = None
|
|
22
|
+
color: Color | None = None
|
|
23
|
+
linewidth: int = 1
|
|
24
|
+
style: Any = None
|
|
25
|
+
trackprice: bool = False
|
|
26
|
+
histbase: float = 0.0
|
|
27
|
+
offset: int = 0
|
|
28
|
+
join: bool = False
|
|
29
|
+
editable: bool = True
|
|
30
|
+
show_last: int | None = None
|
|
31
|
+
display: Any = None
|
|
32
|
+
format: str | None = None
|
|
33
|
+
precision: int | None = None
|
|
34
|
+
force_overlay: bool = False
|
|
35
|
+
|
|
36
|
+
char: str | None = None
|
|
37
|
+
location: Any = None
|
|
38
|
+
size: Any = None
|
|
39
|
+
text: str | None = None
|
|
40
|
+
textcolor: Color | None = None
|
|
41
|
+
|
|
42
|
+
colorup: Color | None = None
|
|
43
|
+
colordown: Color | None = None
|
|
44
|
+
minheight: int | None = None
|
|
45
|
+
maxheight: int | None = None
|
|
46
|
+
|
|
47
|
+
wickcolor: Color | None = None
|
|
48
|
+
bordercolor: Color | None = None
|
|
49
|
+
|
|
50
|
+
price: float | None = None
|
|
51
|
+
linestyle: Any = None
|
|
52
|
+
|
|
53
|
+
plot1: str | None = None
|
|
54
|
+
plot2: str | None = None
|
|
55
|
+
hline1: str | None = None
|
|
56
|
+
hline2: str | None = None
|
|
57
|
+
|
|
58
|
+
fillgaps: bool = False
|
|
59
|
+
|
|
60
|
+
dynamic: bool = False
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import TYPE_CHECKING, Optional
|
|
3
|
+
|
|
4
|
+
from ..lib import color as _color, xloc as _xloc
|
|
5
|
+
from ..types.line import LineEnum
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from .chart import ChartPoint
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(slots=True, eq=False)
|
|
12
|
+
class Polyline:
|
|
13
|
+
# Array of chart.point objects for the drawing to sequentially connect
|
|
14
|
+
points: list["ChartPoint"]
|
|
15
|
+
|
|
16
|
+
# If true, the drawing will connect all points using curved line segments
|
|
17
|
+
curved: bool = False
|
|
18
|
+
|
|
19
|
+
# If true, the drawing will connect the first point to the last point, resulting in a closed polyline
|
|
20
|
+
closed: bool = False
|
|
21
|
+
|
|
22
|
+
# Determines the field of the chart.point objects that the polyline will use for its x-coordinates
|
|
23
|
+
xloc: Optional[_xloc.XLoc] = None
|
|
24
|
+
|
|
25
|
+
# The color of the line segments
|
|
26
|
+
line_color: Optional[_color.Color] = None
|
|
27
|
+
|
|
28
|
+
# The fill color of the polyline
|
|
29
|
+
fill_color: Optional[_color.Color] = None
|
|
30
|
+
|
|
31
|
+
# The style of the polyline
|
|
32
|
+
line_style: Optional[LineEnum] = None
|
|
33
|
+
|
|
34
|
+
# The width of the line segments, expressed in pixels
|
|
35
|
+
line_width: int = 1
|
|
36
|
+
|
|
37
|
+
# If true, the drawing will display on the main chart pane
|
|
38
|
+
force_overlay: bool = False
|
|
39
|
+
|
|
40
|
+
vid: int = -1
|
pynecore/types/scale.py
ADDED
pynecore/types/series.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import TypeVar, Generic
|
|
3
|
+
|
|
4
|
+
__all__ = (
|
|
5
|
+
'Series',
|
|
6
|
+
'PersistentSeries',
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
T = TypeVar('T')
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Series(Generic[T]):
|
|
13
|
+
"""
|
|
14
|
+
This is the runtime, do nothing implementation of the Series type. The actual Series behavior is
|
|
15
|
+
implented in AST Transformers and the SeriesImpl class.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __new__(cls, val: T) -> T:
|
|
19
|
+
return val
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# This is only for the AST transformer to mark a variable as Pine Script like persistent series
|
|
23
|
+
PersistentSeries = Series
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Series is a transparent alias: ``Series[T]`` IS ``T`` for type checkers.
|
|
3
|
+
|
|
4
|
+
The Pine dual behavior (scalar AND ``[n]``-history-indexable at once) cannot be
|
|
5
|
+
expressed in a stub — Python typing has no intersection type, and a Union means
|
|
6
|
+
"either", not "both at once". The alias makes the scalar side (arithmetic,
|
|
7
|
+
calls, assignments) fully type-correct; the history-indexing side is covered by
|
|
8
|
+
the ``type_checker`` compat layer (PyCharm) or by suppressing
|
|
9
|
+
``reportIndexIssue`` in the generated pyrightconfig (pyright/Pylance).
|
|
10
|
+
|
|
11
|
+
The old ``TypeAlias`` syntax (not PEP 695 ``type``) is kept deliberately:
|
|
12
|
+
PyCharm resolves unbound-TypeVar aliases this way.
|
|
13
|
+
"""
|
|
14
|
+
from typing import TypeVar, TypeAlias
|
|
15
|
+
|
|
16
|
+
T = TypeVar('T')
|
|
17
|
+
|
|
18
|
+
Series: TypeAlias = T
|
|
19
|
+
PersistentSeries: TypeAlias = T
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from datetime import time
|
|
3
|
+
from typing import Set
|
|
4
|
+
|
|
5
|
+
from ..types.base import StrLiteral
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class SessionInfo:
|
|
10
|
+
"""
|
|
11
|
+
Session information containing time range, valid days, and timezone.
|
|
12
|
+
|
|
13
|
+
This dataclass represents a trading session specification that can be used
|
|
14
|
+
to determine if a given timestamp falls within the session bounds.
|
|
15
|
+
"""
|
|
16
|
+
start_time: time
|
|
17
|
+
end_time: time
|
|
18
|
+
days: Set[int] # 1=Sunday, 2=Monday, ..., 7=Saturday (TradingView format)
|
|
19
|
+
timezone: str | None
|
|
20
|
+
is_overnight: bool = False
|
|
21
|
+
|
|
22
|
+
def __post_init__(self):
|
|
23
|
+
"""Validate session parameters after initialization."""
|
|
24
|
+
# Check if this is an overnight session
|
|
25
|
+
if self.start_time > self.end_time:
|
|
26
|
+
object.__setattr__(self, 'is_overnight', True)
|
|
27
|
+
|
|
28
|
+
# Validate days
|
|
29
|
+
for day in self.days:
|
|
30
|
+
if not 1 <= day <= 7:
|
|
31
|
+
raise ValueError(f"Invalid day: {day}. Days must be between 1 (Sunday) and 7 (Saturday)")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Session(StrLiteral):
|
|
35
|
+
...
|
pynecore/types/shape.py
ADDED
pynecore/types/size.py
ADDED
pynecore/types/source.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from .series import Series
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Source(Series[float]):
|
|
6
|
+
"""
|
|
7
|
+
Represents a built-in source like "open", "high", "low", "close", "hl2", etc.
|
|
8
|
+
|
|
9
|
+
DESIGN NOTES:
|
|
10
|
+
=============
|
|
11
|
+
|
|
12
|
+
This class provides type-safe source placeholders for IDE support while enabling
|
|
13
|
+
dynamic runtime resolution through AST transformation:
|
|
14
|
+
|
|
15
|
+
1. INITIALIZATION: Source objects store the source name for type hints
|
|
16
|
+
2. INPUT DETECTION: InputTransformer detects Source objects in input() calls
|
|
17
|
+
3. AST INJECTION: Adds `var = getattr(lib, var, lib.na)` at function start
|
|
18
|
+
4. RUNTIME: ScriptRunner dynamically sets lib.close = actual_price per candle
|
|
19
|
+
|
|
20
|
+
This allows `input(defval=close)` to work with proper types while being fast
|
|
21
|
+
and compatible with both Source objects and string literals in input.source().
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __new__(cls, name: str) -> Source:
|
|
25
|
+
obj = object.__new__(cls)
|
|
26
|
+
setattr(obj, "name", name)
|
|
27
|
+
return obj
|
|
28
|
+
|
|
29
|
+
def __repr__(self) -> str:
|
|
30
|
+
return f"Source({getattr(self, 'name')})"
|
|
31
|
+
|
|
32
|
+
def __str__(self) -> str:
|
|
33
|
+
return getattr(self, 'name')
|