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/core/script.py
ADDED
|
@@ -0,0 +1,1011 @@
|
|
|
1
|
+
from typing import Any, Callable, TypeVar, overload
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from enum import StrEnum
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import pynecore.lib.format as _format
|
|
10
|
+
import pynecore.lib.scale as _scale
|
|
11
|
+
import pynecore.lib.strategy as _strategy
|
|
12
|
+
import pynecore.lib.currency as _currency
|
|
13
|
+
import pynecore.lib.display as _display
|
|
14
|
+
|
|
15
|
+
from pynecore.core.broker.models import ScriptRequirements
|
|
16
|
+
|
|
17
|
+
from pynecore.types import script_type as _script_type
|
|
18
|
+
from pynecore.types.color import Color
|
|
19
|
+
from pynecore.types import PyneFloat, PyneInt
|
|
20
|
+
|
|
21
|
+
__all__ = ['script', 'input']
|
|
22
|
+
|
|
23
|
+
from pynecore.types.source import Source
|
|
24
|
+
from . import safe_convert
|
|
25
|
+
|
|
26
|
+
# Global registry for library main functions
|
|
27
|
+
_registered_libraries: list[tuple[str, Callable]] = []
|
|
28
|
+
|
|
29
|
+
# TypeVar for enum type preservation
|
|
30
|
+
TEnum = TypeVar('TEnum', bound=StrEnum)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass(kw_only=True, slots=True)
|
|
34
|
+
class InputData:
|
|
35
|
+
"""
|
|
36
|
+
Input dataclass
|
|
37
|
+
"""
|
|
38
|
+
id: str | None = None
|
|
39
|
+
input_type: str | None = None
|
|
40
|
+
defval: int | bool | Color | float | str | None = None
|
|
41
|
+
title: str | None = None
|
|
42
|
+
minval: int | float | None = None
|
|
43
|
+
maxval: int | float | None = None
|
|
44
|
+
step: int | float | None = None
|
|
45
|
+
tooltip: str | None = None
|
|
46
|
+
inline: str | None = None
|
|
47
|
+
group: str | None = None
|
|
48
|
+
confirm: bool | None = False
|
|
49
|
+
options: tuple[int | float | str, ...] | None = None
|
|
50
|
+
display: _display.Display | None = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
_old_input_values: dict[str, Any] = {}
|
|
54
|
+
_programmatic_inputs: dict[str, Any] = {}
|
|
55
|
+
inputs: dict[str, InputData] = {}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# noinspection PyShadowingBuiltins,PyShadowingNames,PyDunderSlots,PyUnresolvedReferences
|
|
59
|
+
@dataclass(kw_only=True, slots=True)
|
|
60
|
+
class Script:
|
|
61
|
+
"""
|
|
62
|
+
Script parameters dataclass
|
|
63
|
+
"""
|
|
64
|
+
# These fields will be skipped when saving to toml
|
|
65
|
+
_SKIP_FIELDS = {'script_type', 'inputs', 'title', 'shorttitle', 'position'}
|
|
66
|
+
|
|
67
|
+
script_type: _script_type.ScriptType | None = None
|
|
68
|
+
inputs: dict[str, InputData] = field(default_factory=dict)
|
|
69
|
+
|
|
70
|
+
title: str | None = None
|
|
71
|
+
shorttitle: str | None = None
|
|
72
|
+
|
|
73
|
+
overlay: bool = False
|
|
74
|
+
format: _format.Format = _format.inherit
|
|
75
|
+
precision: int | None = None
|
|
76
|
+
scale: _scale.Scale | None = None
|
|
77
|
+
pyramiding: int = 1
|
|
78
|
+
calc_on_order_fills: bool = False
|
|
79
|
+
calc_on_every_tick: bool = False
|
|
80
|
+
max_bars_back: int = 0
|
|
81
|
+
timeframe: str | None = None
|
|
82
|
+
timeframe_gaps: bool = True
|
|
83
|
+
explicit_plot_zorder: bool = False
|
|
84
|
+
max_lines_count: int = 50
|
|
85
|
+
max_labels_count: int = 50
|
|
86
|
+
max_boxes_count: int = 50
|
|
87
|
+
calc_bars_count: int = 0
|
|
88
|
+
max_polylines_count: int = 50
|
|
89
|
+
dynamic_requests: bool = False
|
|
90
|
+
behind_chart: bool = True
|
|
91
|
+
|
|
92
|
+
backtest_fill_limits_assumption: int = 0
|
|
93
|
+
default_qty_type: _strategy.QtyType = _strategy.cash
|
|
94
|
+
default_qty_value: float = 1
|
|
95
|
+
initial_capital: float | int = 1000000
|
|
96
|
+
currency: _currency.Currency = _currency.NONE
|
|
97
|
+
slippage: int = 0
|
|
98
|
+
commission_type: _strategy.commission.Commission = _strategy.commission.percent # type: ignore
|
|
99
|
+
commission_value: int | float = 0.0
|
|
100
|
+
process_orders_on_close: bool = False
|
|
101
|
+
close_entries_rule: str = 'FIFO'
|
|
102
|
+
margin_long: int | float = 100.0 # Defaulted to 100.0 in Pine Script v6
|
|
103
|
+
margin_short: int | float = 100.0 # Defaulted to 100.0 in Pine Script v6
|
|
104
|
+
risk_free_rate: float = 2.0
|
|
105
|
+
use_bar_magnifier: bool = True
|
|
106
|
+
fill_orders_on_standard_ohlc: bool = False
|
|
107
|
+
|
|
108
|
+
position: _strategy.PositionBase = None # type: ignore[assignment]
|
|
109
|
+
|
|
110
|
+
_broker_requirements: ScriptRequirements | None = None
|
|
111
|
+
|
|
112
|
+
_modified: set[str] = field(default_factory=set)
|
|
113
|
+
|
|
114
|
+
def save(self, path: Path):
|
|
115
|
+
"""
|
|
116
|
+
Save script settings to TOML-like format.
|
|
117
|
+
Non-settable fields are commented out with '#'.
|
|
118
|
+
None values are also commented out.
|
|
119
|
+
Input values are saved with their metadata as comments.
|
|
120
|
+
|
|
121
|
+
:param path: Path to save the file
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
def _format_value(value) -> str:
|
|
125
|
+
"""Format value according to its type"""
|
|
126
|
+
if isinstance(value, bool):
|
|
127
|
+
return str(value).lower()
|
|
128
|
+
if isinstance(value, (int, float)):
|
|
129
|
+
return str(value)
|
|
130
|
+
if isinstance(value, Color):
|
|
131
|
+
value = str(value)
|
|
132
|
+
if isinstance(value, str):
|
|
133
|
+
# Escape newlines and backslashes for valid TOML
|
|
134
|
+
escaped = value.replace('\\', '\\\\').replace('\n', '\\n').replace('\r', '\\r')
|
|
135
|
+
return f'"{escaped}"'
|
|
136
|
+
return str(value)
|
|
137
|
+
|
|
138
|
+
lines = [
|
|
139
|
+
"# Indicator / Strategy / Library Settings",
|
|
140
|
+
"",
|
|
141
|
+
"[script]"
|
|
142
|
+
]
|
|
143
|
+
|
|
144
|
+
# Save general settings
|
|
145
|
+
from dataclasses import fields
|
|
146
|
+
for field in fields(self):
|
|
147
|
+
key = field.name
|
|
148
|
+
value = getattr(self, key)
|
|
149
|
+
if key.startswith('_') or key in self._SKIP_FIELDS:
|
|
150
|
+
continue
|
|
151
|
+
if value is None:
|
|
152
|
+
line = f"#{key} ="
|
|
153
|
+
else:
|
|
154
|
+
line = "#" if key not in self._modified else ""
|
|
155
|
+
line += f"{key} = {_format_value(value)}"
|
|
156
|
+
lines.append(line)
|
|
157
|
+
|
|
158
|
+
# Add an empty line before inputs
|
|
159
|
+
lines.append("")
|
|
160
|
+
lines.append("# Input Settings")
|
|
161
|
+
|
|
162
|
+
# Save inputs
|
|
163
|
+
for arg_name, input_data in self.inputs.items():
|
|
164
|
+
if not arg_name:
|
|
165
|
+
continue
|
|
166
|
+
lines.append(f"\n[inputs.{arg_name.removesuffix('__global__')}]")
|
|
167
|
+
lines.append("# Input metadata, cannot be modified")
|
|
168
|
+
|
|
169
|
+
# Add all metadata as comments
|
|
170
|
+
from dataclasses import fields as input_fields
|
|
171
|
+
for field in input_fields(input_data):
|
|
172
|
+
key = field.name
|
|
173
|
+
value = getattr(input_data, key)
|
|
174
|
+
if key == 'id':
|
|
175
|
+
continue
|
|
176
|
+
if value is not None:
|
|
177
|
+
# We use ':` to not confuse with real values
|
|
178
|
+
lines.append(f"# {key.rjust(10)}: {_format_value(value)}")
|
|
179
|
+
|
|
180
|
+
lines.append("# Change here to modify the input value")
|
|
181
|
+
|
|
182
|
+
# Add the actual value
|
|
183
|
+
if input_data.defval is not None and arg_name in _old_input_values:
|
|
184
|
+
lines.append(f"value = {_format_value(_old_input_values[arg_name])}")
|
|
185
|
+
else:
|
|
186
|
+
lines.append("#value =")
|
|
187
|
+
|
|
188
|
+
# Write to file
|
|
189
|
+
with open(path, 'w', encoding='utf-8') as f:
|
|
190
|
+
f.write('\n'.join(lines) + '\n')
|
|
191
|
+
|
|
192
|
+
def load(self, path: str | Path) -> None:
|
|
193
|
+
"""
|
|
194
|
+
Load script settings from TOML file and update this script instance.
|
|
195
|
+
Only loads settable fields and input values, preserving the original script structure.
|
|
196
|
+
|
|
197
|
+
:param path: Path to load the file from
|
|
198
|
+
"""
|
|
199
|
+
import tomllib
|
|
200
|
+
|
|
201
|
+
with open(path, 'rb') as f:
|
|
202
|
+
data = tomllib.load(f)
|
|
203
|
+
|
|
204
|
+
if 'script' not in data:
|
|
205
|
+
raise ValueError("Invalid TOML: missing [script] section!")
|
|
206
|
+
|
|
207
|
+
script_data = data['script']
|
|
208
|
+
|
|
209
|
+
for key, value in script_data.items():
|
|
210
|
+
if key not in self._SKIP_FIELDS and hasattr(self, key):
|
|
211
|
+
if value != getattr(self, key):
|
|
212
|
+
setattr(self, key, value)
|
|
213
|
+
# We just save the modified fields
|
|
214
|
+
self._modified.add(key)
|
|
215
|
+
|
|
216
|
+
if 'inputs' not in data:
|
|
217
|
+
return
|
|
218
|
+
|
|
219
|
+
# Fill old_input_values
|
|
220
|
+
for arg_name, arg_data in data['inputs'].items():
|
|
221
|
+
if 'value' not in arg_data:
|
|
222
|
+
continue
|
|
223
|
+
_old_input_values[arg_name] = arg_data['value']
|
|
224
|
+
_old_input_values[arg_name + '__global__'] = arg_data['value'] # For strict mode
|
|
225
|
+
|
|
226
|
+
#
|
|
227
|
+
# decorators
|
|
228
|
+
#
|
|
229
|
+
|
|
230
|
+
def _decorate(self):
|
|
231
|
+
# Get the script path from the caller frame
|
|
232
|
+
script_path = Path(sys._getframe(2).f_globals['__file__']).resolve() # noqa F821
|
|
233
|
+
toml_path = script_path.with_suffix('.toml')
|
|
234
|
+
|
|
235
|
+
# Load settings from toml file if exists
|
|
236
|
+
if toml_path.exists():
|
|
237
|
+
self.load(toml_path)
|
|
238
|
+
|
|
239
|
+
# Apply programmatic inputs (override .toml values)
|
|
240
|
+
if _programmatic_inputs:
|
|
241
|
+
for key, value in _programmatic_inputs.items():
|
|
242
|
+
_old_input_values[key] = value
|
|
243
|
+
_old_input_values[key + '__global__'] = value
|
|
244
|
+
_programmatic_inputs.clear()
|
|
245
|
+
|
|
246
|
+
# Pyramiding must be at least 1
|
|
247
|
+
if self.pyramiding <= 0:
|
|
248
|
+
self.pyramiding = 1
|
|
249
|
+
|
|
250
|
+
def decorator(func):
|
|
251
|
+
# Save inputs to script instance then clear inputs (for next script)
|
|
252
|
+
self.inputs = inputs.copy() # type: ignore
|
|
253
|
+
inputs.clear()
|
|
254
|
+
|
|
255
|
+
# Set script attribute to the main function to be able to access script properties
|
|
256
|
+
setattr(func, 'script', self)
|
|
257
|
+
|
|
258
|
+
if self.script_type in (_script_type.indicator, _script_type.strategy):
|
|
259
|
+
# Save toml file if not in pytest and not disabled by env var PYNE_SAVE_SCRIPT_TOML = 0
|
|
260
|
+
if os.environ.get('PYNE_SAVE_SCRIPT_TOML', '1') == '1' and 'pytest' not in sys.modules:
|
|
261
|
+
self.save(toml_path)
|
|
262
|
+
|
|
263
|
+
_old_input_values.clear()
|
|
264
|
+
return func
|
|
265
|
+
|
|
266
|
+
return decorator
|
|
267
|
+
|
|
268
|
+
# noinspection DuplicatedCode
|
|
269
|
+
@classmethod
|
|
270
|
+
def indicator(
|
|
271
|
+
cls,
|
|
272
|
+
title='', shorttitle='',
|
|
273
|
+
overlay=False,
|
|
274
|
+
format: _format.Format = _format.inherit,
|
|
275
|
+
precision: int | None = None,
|
|
276
|
+
scale: _scale.Scale | None = None,
|
|
277
|
+
max_bars_back=0,
|
|
278
|
+
timeframe: str | None = None,
|
|
279
|
+
timeframe_gaps=True,
|
|
280
|
+
explicit_plot_zorder=False,
|
|
281
|
+
max_lines_count=50,
|
|
282
|
+
max_labels_count=50,
|
|
283
|
+
max_boxes_count=50,
|
|
284
|
+
calc_bars_count=0,
|
|
285
|
+
max_polylines_count=50,
|
|
286
|
+
dynamic_requests=False,
|
|
287
|
+
behind_chart=True,
|
|
288
|
+
*_, **__
|
|
289
|
+
) -> Callable[..., Any]:
|
|
290
|
+
"""
|
|
291
|
+
Decorator for indicator script. You should deocrate `main` function with this decorator if
|
|
292
|
+
your script is an indicator script.
|
|
293
|
+
|
|
294
|
+
:param title: The title of the script
|
|
295
|
+
:param shorttitle: The script's display name
|
|
296
|
+
:param overlay: If True, the script will be displayed on the price chart as an overlay,
|
|
297
|
+
otherwise it will be displayed in a separate pane
|
|
298
|
+
:param format: Specifies the formatting of the script's displayed values
|
|
299
|
+
:param precision: Specifies the number of digits after the floating point of the script's displayed values
|
|
300
|
+
:param scale: The price scale used
|
|
301
|
+
:param max_bars_back: The length of the historical buffer the script keeps for every
|
|
302
|
+
Series variables which determines how many past values can be
|
|
303
|
+
referenced by Series objects
|
|
304
|
+
:param timeframe: Adds multi-timeframe functionality to simple scripts
|
|
305
|
+
:param timeframe_gaps: Specifies how the indicator's values are displayed on chart bars
|
|
306
|
+
when the `timeframe` is higher than the chart's timeframe.
|
|
307
|
+
:param explicit_plot_zorder: Specifies the order in which the script's plots, fills, and hlines are rendered
|
|
308
|
+
:param max_lines_count: The number of last line drawings displayed on the chart
|
|
309
|
+
:param max_labels_count: The number of last label drawings displayed
|
|
310
|
+
:param max_boxes_count: The number of last box drawings displayed
|
|
311
|
+
:param calc_bars_count: Limits the initial calculation of a script to the last number of bars specified
|
|
312
|
+
:param max_polylines_count: The number of last polyline drawings displayed
|
|
313
|
+
:param dynamic_requests: Specifies whether the script can dynamically call functions from
|
|
314
|
+
the `request.*()` namespace
|
|
315
|
+
:param behind_chart: Controls whether the script's plots and drawings in the main chart pane
|
|
316
|
+
appear behind the chart display
|
|
317
|
+
"""
|
|
318
|
+
script = cls()
|
|
319
|
+
script.script_type = _script_type.indicator
|
|
320
|
+
script.title = title
|
|
321
|
+
script.shorttitle = shorttitle
|
|
322
|
+
|
|
323
|
+
script.overlay = overlay
|
|
324
|
+
script.format = format
|
|
325
|
+
script.precision = precision
|
|
326
|
+
script.scale = scale
|
|
327
|
+
script.max_bars_back = max_bars_back
|
|
328
|
+
script.timeframe = timeframe
|
|
329
|
+
script.timeframe_gaps = timeframe_gaps
|
|
330
|
+
script.explicit_plot_zorder = explicit_plot_zorder
|
|
331
|
+
script.max_lines_count = max_lines_count
|
|
332
|
+
script.max_labels_count = max_labels_count
|
|
333
|
+
script.max_boxes_count = max_boxes_count
|
|
334
|
+
script.calc_bars_count = calc_bars_count
|
|
335
|
+
script.max_polylines_count = max_polylines_count
|
|
336
|
+
script.dynamic_requests = dynamic_requests
|
|
337
|
+
script.behind_chart = behind_chart
|
|
338
|
+
|
|
339
|
+
return script._decorate()
|
|
340
|
+
|
|
341
|
+
# noinspection DuplicatedCode
|
|
342
|
+
@classmethod
|
|
343
|
+
def strategy(
|
|
344
|
+
cls,
|
|
345
|
+
title='', shorttitle='',
|
|
346
|
+
overlay=False,
|
|
347
|
+
format: _format.Format = _format.inherit,
|
|
348
|
+
precision: int | None = None,
|
|
349
|
+
scale: _scale.Scale | None = None,
|
|
350
|
+
|
|
351
|
+
pyramiding: int = 0,
|
|
352
|
+
calc_on_order_fills=False,
|
|
353
|
+
calc_on_every_tick=False,
|
|
354
|
+
|
|
355
|
+
max_bars_back=0,
|
|
356
|
+
|
|
357
|
+
backtest_fill_limits_assumption=0,
|
|
358
|
+
default_qty_type: _strategy.QtyType = _strategy.fixed,
|
|
359
|
+
default_qty_value: float = 1,
|
|
360
|
+
initial_capital: float | int = 1000000,
|
|
361
|
+
currency: _currency.Currency = _currency.NONE,
|
|
362
|
+
slippage: int = 0,
|
|
363
|
+
commission_type: _strategy.commission.Commission = _strategy.commission.percent, # type: ignore
|
|
364
|
+
commission_value: int | float = 0.0,
|
|
365
|
+
process_orders_on_close=False,
|
|
366
|
+
close_entries_rule='FIFO',
|
|
367
|
+
margin_long: int | float = 100.0,
|
|
368
|
+
margin_short: int | float = 100.0,
|
|
369
|
+
|
|
370
|
+
explicit_plot_zorder=False,
|
|
371
|
+
max_lines_count=50,
|
|
372
|
+
max_labels_count=50,
|
|
373
|
+
max_boxes_count=50,
|
|
374
|
+
calc_bars_count=0,
|
|
375
|
+
|
|
376
|
+
risk_free_rate=2.0,
|
|
377
|
+
use_bar_magnifier=True,
|
|
378
|
+
fill_orders_on_standard_ohlc=False,
|
|
379
|
+
|
|
380
|
+
max_polylines_count=50,
|
|
381
|
+
dynamic_requests=False,
|
|
382
|
+
|
|
383
|
+
behind_chart=True,
|
|
384
|
+
|
|
385
|
+
_broker_requirements: ScriptRequirements | None = None,
|
|
386
|
+
|
|
387
|
+
*_, **__
|
|
388
|
+
) -> Callable[..., Any]:
|
|
389
|
+
"""
|
|
390
|
+
Decorator for strategy script. You should deocrate `main` function with this decorator if
|
|
391
|
+
your script is a strategy script.
|
|
392
|
+
|
|
393
|
+
:param title: The title of the script
|
|
394
|
+
:param shorttitle: The script's display name
|
|
395
|
+
:param overlay: If True, the script will be displayed on the price chart as an overlay,
|
|
396
|
+
:param format: Specifies the formatting of the script's displayed values
|
|
397
|
+
:param precision: Specifies the number of digits after the floating point of the script's displayed values
|
|
398
|
+
:param scale: The price scale used
|
|
399
|
+
:param pyramiding: The maximum number of entries allowed in the same direction
|
|
400
|
+
:param calc_on_order_fills: Specifies whether the strategy should be recalculated after an order is filled
|
|
401
|
+
:param calc_on_every_tick: Specifies whether the strategy should be recalculated on each realtime tick
|
|
402
|
+
:param max_bars_back: The length of the historical buffer the script keeps for every
|
|
403
|
+
:param backtest_fill_limits_assumption: Limit order execution threshold in ticks
|
|
404
|
+
:param default_qty_type: Specifies the units used for `default_qty_value`
|
|
405
|
+
:param default_qty_value: The default quantity to trade, in units determined by the argument
|
|
406
|
+
used with the `default_qty_type` parameter
|
|
407
|
+
:param initial_capital: The amount of funds initially available for the strategy to trade,
|
|
408
|
+
in units of `currency`
|
|
409
|
+
:param currency: Currency used by the strategy in currency-related calculations
|
|
410
|
+
:param slippage: Slippage expressed in ticks
|
|
411
|
+
:param commission_type: Determines what the number passed to the `commission_value`
|
|
412
|
+
:param commission_value: Commission applied to the strategy's orders in units determined by
|
|
413
|
+
the argument passed to the `commission_type` parameter
|
|
414
|
+
:param process_orders_on_close: When set to true, generates an additional attempt to execute
|
|
415
|
+
orders after a bar closes and strategy calculations are completed.
|
|
416
|
+
:param close_entries_rule: Determines the order in which trades are closed
|
|
417
|
+
:param margin_long: Margin long is the percentage of the purchase price of a security that
|
|
418
|
+
must be covered by cash or collateral for long positions
|
|
419
|
+
:param margin_short: Margin short is the percentage of the purchase price of a security that
|
|
420
|
+
must be covered by cash or collateral for short positions
|
|
421
|
+
:param explicit_plot_zorder: Specifies the order in which the script's plots, fills, and hlines are rendered
|
|
422
|
+
:param max_lines_count: The number of last line drawings displayed on the chart
|
|
423
|
+
:param max_labels_count: The number of last label drawings displayed
|
|
424
|
+
:param max_boxes_count: The number of last box drawings displayed
|
|
425
|
+
:param calc_bars_count: Limits the initial calculation of a script to the last number of bars specified
|
|
426
|
+
:param risk_free_rate: The risk-free rate of return is the annual percentage change in the
|
|
427
|
+
value of an investment with minimal or zero risk
|
|
428
|
+
:param use_bar_magnifier: When true, the Broker Emulator uses lower timeframe data during
|
|
429
|
+
history backtesting to achieve more realistic results
|
|
430
|
+
:param fill_orders_on_standard_ohlc: When true, forces strategies running on Heikin Ashi
|
|
431
|
+
charts to fill orders using actual OHLC prices, for more
|
|
432
|
+
realistic results.
|
|
433
|
+
:param max_polylines_count: The number of last polyline drawings displayed
|
|
434
|
+
:param dynamic_requests: Specifies whether the script can dynamically call functions from
|
|
435
|
+
:param behind_chart: Controls whether the script's plots and drawings in the main chart pane
|
|
436
|
+
:param _broker_requirements: Broker capability requirements of the script, internal use only
|
|
437
|
+
"""
|
|
438
|
+
script = cls()
|
|
439
|
+
script.script_type = _script_type.strategy
|
|
440
|
+
script.title = title
|
|
441
|
+
script.shorttitle = shorttitle
|
|
442
|
+
|
|
443
|
+
script.overlay = overlay
|
|
444
|
+
script.format = format
|
|
445
|
+
script.precision = precision
|
|
446
|
+
script.scale = scale
|
|
447
|
+
|
|
448
|
+
script.pyramiding = pyramiding
|
|
449
|
+
script.calc_on_order_fills = calc_on_order_fills
|
|
450
|
+
script.calc_on_every_tick = calc_on_every_tick
|
|
451
|
+
|
|
452
|
+
script.max_bars_back = max_bars_back
|
|
453
|
+
|
|
454
|
+
script.backtest_fill_limits_assumption = backtest_fill_limits_assumption
|
|
455
|
+
script.default_qty_type = default_qty_type
|
|
456
|
+
script.default_qty_value = default_qty_value
|
|
457
|
+
script.initial_capital = initial_capital
|
|
458
|
+
script.currency = currency
|
|
459
|
+
script.slippage = slippage
|
|
460
|
+
script.commission_type = commission_type
|
|
461
|
+
script.commission_value = commission_value
|
|
462
|
+
script.process_orders_on_close = process_orders_on_close
|
|
463
|
+
script.close_entries_rule = close_entries_rule
|
|
464
|
+
script.margin_long = margin_long
|
|
465
|
+
script.margin_short = margin_short
|
|
466
|
+
script.explicit_plot_zorder = explicit_plot_zorder
|
|
467
|
+
|
|
468
|
+
script.max_lines_count = max_lines_count
|
|
469
|
+
script.max_labels_count = max_labels_count
|
|
470
|
+
script.max_boxes_count = max_boxes_count
|
|
471
|
+
script.calc_bars_count = calc_bars_count
|
|
472
|
+
|
|
473
|
+
script.risk_free_rate = risk_free_rate
|
|
474
|
+
script.use_bar_magnifier = use_bar_magnifier
|
|
475
|
+
script.fill_orders_on_standard_ohlc = fill_orders_on_standard_ohlc
|
|
476
|
+
|
|
477
|
+
script.max_polylines_count = max_polylines_count
|
|
478
|
+
script.dynamic_requests = dynamic_requests
|
|
479
|
+
script.behind_chart = behind_chart
|
|
480
|
+
|
|
481
|
+
script.position = _strategy.SimPosition()
|
|
482
|
+
|
|
483
|
+
script._broker_requirements = _broker_requirements
|
|
484
|
+
|
|
485
|
+
return script._decorate()
|
|
486
|
+
|
|
487
|
+
@classmethod
|
|
488
|
+
def library(
|
|
489
|
+
cls,
|
|
490
|
+
title='',
|
|
491
|
+
overlay=False,
|
|
492
|
+
dynamic_requests=False,
|
|
493
|
+
*_, **__
|
|
494
|
+
) -> Callable[..., Any]:
|
|
495
|
+
"""
|
|
496
|
+
Decorator for library script. You should deocrate `main` function with this decorator if
|
|
497
|
+
your script is a library script.
|
|
498
|
+
|
|
499
|
+
:param title: The title of the script
|
|
500
|
+
:param overlay: If True, the script will be displayed on the price chart as an overlay,
|
|
501
|
+
:param dynamic_requests: Specifies whether the script can dynamically call functions from
|
|
502
|
+
"""
|
|
503
|
+
script = cls()
|
|
504
|
+
script.script_type = _script_type.library
|
|
505
|
+
script.title = title
|
|
506
|
+
script.shorttitle = title
|
|
507
|
+
|
|
508
|
+
script.overlay = overlay
|
|
509
|
+
script.dynamic_requests = dynamic_requests
|
|
510
|
+
|
|
511
|
+
def decorator(func):
|
|
512
|
+
# Register library main function if not already registered
|
|
513
|
+
lib_entry = (script.title or 'Untitled Library', func)
|
|
514
|
+
if lib_entry not in _registered_libraries:
|
|
515
|
+
_registered_libraries.append(lib_entry)
|
|
516
|
+
return script._decorate()(func)
|
|
517
|
+
|
|
518
|
+
return decorator
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
script = Script
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
class _Input:
|
|
525
|
+
"""
|
|
526
|
+
Input functions
|
|
527
|
+
"""
|
|
528
|
+
|
|
529
|
+
def __call__(self, defval: Any, title: str | None = None,
|
|
530
|
+
tooltip: str | None = None, inline: str | None = None, group: str | None = None,
|
|
531
|
+
display: _display.Display | None = None, active: bool | None = None,
|
|
532
|
+
*, _id: str = "", **__) -> Any:
|
|
533
|
+
"""
|
|
534
|
+
Adds an input to your script's settings, which allows you to provide configuration options
|
|
535
|
+
|
|
536
|
+
:param defval: The default value of the input
|
|
537
|
+
:param title: The title of the input
|
|
538
|
+
:param tooltip: The tooltip of the input
|
|
539
|
+
:param inline: Inputs with the same inline string are displayed on one line
|
|
540
|
+
:param group: The group of the input
|
|
541
|
+
:param display: Controls where the script will display the input's information
|
|
542
|
+
:param active: UI-only in Pine (greys out the field); accepted for parity, ignored
|
|
543
|
+
:param _id: The unique identifier of the input, it is filled by the InputTransformer
|
|
544
|
+
:return: The input value from toml file or the default
|
|
545
|
+
"""
|
|
546
|
+
input_type = type(defval).__name__.lower()
|
|
547
|
+
if input_type == 'source':
|
|
548
|
+
defval = str(defval)
|
|
549
|
+
inputs[_id] = InputData(
|
|
550
|
+
id=_id,
|
|
551
|
+
input_type=input_type,
|
|
552
|
+
defval=defval,
|
|
553
|
+
title=title,
|
|
554
|
+
tooltip=tooltip,
|
|
555
|
+
inline=inline,
|
|
556
|
+
group=group,
|
|
557
|
+
display=display,
|
|
558
|
+
)
|
|
559
|
+
return defval if _id not in _old_input_values else _old_input_values[_id]
|
|
560
|
+
|
|
561
|
+
# Pine's numeric inputs have TWO positional overloads after ``title``: the
|
|
562
|
+
# minval/maxval/step form and the options form. A single Python parameter
|
|
563
|
+
# list cannot bind both, so the implementations take ``*args`` and bind the
|
|
564
|
+
# tail by inspecting the third argument (a tuple/list selects the options
|
|
565
|
+
# form) — mirroring what the v6 reference publishes.
|
|
566
|
+
_NUMERIC_RANGE_TAIL = ('minval', 'maxval', 'step', 'tooltip', 'inline', 'group',
|
|
567
|
+
'confirm', 'display', 'active')
|
|
568
|
+
_NUMERIC_OPTIONS_TAIL = ('options', 'tooltip', 'inline', 'group',
|
|
569
|
+
'confirm', 'display', 'active')
|
|
570
|
+
|
|
571
|
+
@classmethod
|
|
572
|
+
def _bind_numeric_tail(cls, args: tuple, kwargs: dict) -> None:
|
|
573
|
+
"""
|
|
574
|
+
Bind positional arguments after ``title`` into ``kwargs`` following
|
|
575
|
+
Pine's two numeric input overloads.
|
|
576
|
+
|
|
577
|
+
:param args: Positional arguments after ``defval`` and ``title``
|
|
578
|
+
:param kwargs: Keyword arguments; bound names are added in place
|
|
579
|
+
:raises TypeError: On too many positionals or a positional/keyword clash
|
|
580
|
+
"""
|
|
581
|
+
if not args:
|
|
582
|
+
return
|
|
583
|
+
names = (cls._NUMERIC_OPTIONS_TAIL if isinstance(args[0], (tuple, list))
|
|
584
|
+
else cls._NUMERIC_RANGE_TAIL)
|
|
585
|
+
if len(args) > len(names):
|
|
586
|
+
raise TypeError("too many positional arguments for input")
|
|
587
|
+
for name, value in zip(names, args):
|
|
588
|
+
if name in kwargs:
|
|
589
|
+
raise TypeError(f"input got multiple values for argument '{name}'")
|
|
590
|
+
kwargs[name] = value
|
|
591
|
+
|
|
592
|
+
# noinspection PyMethodOverriding
|
|
593
|
+
@overload
|
|
594
|
+
@classmethod
|
|
595
|
+
def _int(cls, defval: int, title: str | None = None,
|
|
596
|
+
minval: int | None = None, maxval: int | None = None, step: int | None = None,
|
|
597
|
+
tooltip: str | None = None, inline: str | None = None, group: str | None = None,
|
|
598
|
+
confirm: bool | None = False, display: _display.Display | None = None,
|
|
599
|
+
active: bool | None = None, *, _id: str = "") -> PyneInt: ...
|
|
600
|
+
|
|
601
|
+
# noinspection PyMethodOverriding
|
|
602
|
+
@overload
|
|
603
|
+
@classmethod
|
|
604
|
+
def _int(cls, defval: int, title: str | None = None,
|
|
605
|
+
options: tuple[int, ...] | None = None,
|
|
606
|
+
tooltip: str | None = None, inline: str | None = None, group: str | None = None,
|
|
607
|
+
confirm: bool | None = False, display: _display.Display | None = None,
|
|
608
|
+
active: bool | None = None, *, _id: str = "") -> PyneInt: ...
|
|
609
|
+
|
|
610
|
+
@classmethod
|
|
611
|
+
def _int(cls, defval: int, title: str | None = None, *args,
|
|
612
|
+
_id: str = "", **kwargs) -> PyneInt:
|
|
613
|
+
"""
|
|
614
|
+
Adds an input to your script's settings, which allows you to provide configuration options
|
|
615
|
+
to script users. This function adds a field for an integer input to the script's inputs.
|
|
616
|
+
|
|
617
|
+
Positional arguments after ``title`` follow Pine v6's two overloads
|
|
618
|
+
(``minval, maxval, step, ...`` or ``options, ...``); ``active`` is
|
|
619
|
+
UI-only in Pine and is accepted but ignored.
|
|
620
|
+
|
|
621
|
+
:param defval: The default value of the input
|
|
622
|
+
:param title: The title of the input
|
|
623
|
+
:param _id: The unique identifier of the input, it is filled by the InputTransformer
|
|
624
|
+
:return: The input value from toml file or the default
|
|
625
|
+
"""
|
|
626
|
+
cls._bind_numeric_tail(args, kwargs)
|
|
627
|
+
inputs[_id] = InputData(
|
|
628
|
+
id=_id,
|
|
629
|
+
input_type='int',
|
|
630
|
+
defval=defval,
|
|
631
|
+
title=title,
|
|
632
|
+
minval=kwargs.get('minval'),
|
|
633
|
+
maxval=kwargs.get('maxval'),
|
|
634
|
+
step=kwargs.get('step'),
|
|
635
|
+
tooltip=kwargs.get('tooltip'),
|
|
636
|
+
inline=kwargs.get('inline'),
|
|
637
|
+
group=kwargs.get('group'),
|
|
638
|
+
confirm=kwargs.get('confirm', False),
|
|
639
|
+
options=kwargs.get('options'),
|
|
640
|
+
display=kwargs.get('display'),
|
|
641
|
+
)
|
|
642
|
+
return defval if _id not in _old_input_values else safe_convert.safe_int(_old_input_values[_id])
|
|
643
|
+
|
|
644
|
+
# noinspection PyUnusedLocal
|
|
645
|
+
@classmethod
|
|
646
|
+
def _bool(cls, defval: bool, title: str | None = None,
|
|
647
|
+
tooltip: str | None = None, inline: str | None = None, group: str | None = None,
|
|
648
|
+
confirm: bool | None = False, display: _display.Display | None = None,
|
|
649
|
+
active: bool | None = None,
|
|
650
|
+
*, _id: str = "", **__) -> bool:
|
|
651
|
+
"""
|
|
652
|
+
Adds an input to your script's settings, which allows you to provide configuration options
|
|
653
|
+
to script users. This function adds a field for a boolean input to the script's inputs.
|
|
654
|
+
|
|
655
|
+
:param defval: The default value of the input
|
|
656
|
+
:param title: The title of the input
|
|
657
|
+
:param tooltip: The tooltip of the input
|
|
658
|
+
:param inline: Inputs with the same inline string are displayed on one line
|
|
659
|
+
:param group: The group of the input
|
|
660
|
+
:param confirm: If True, the user will be asked to confirm the input
|
|
661
|
+
:param display: Controls where the script will display the input's information
|
|
662
|
+
:param active: UI-only in Pine (greys out the field); accepted for parity, ignored
|
|
663
|
+
:param _id: The unique identifier of the input, it is filled by the InputTransformer
|
|
664
|
+
:return: The input value from toml file or the default
|
|
665
|
+
"""
|
|
666
|
+
inputs[_id] = InputData(
|
|
667
|
+
id=_id,
|
|
668
|
+
input_type='bool',
|
|
669
|
+
defval=defval,
|
|
670
|
+
title=title,
|
|
671
|
+
tooltip=tooltip,
|
|
672
|
+
inline=inline,
|
|
673
|
+
group=group,
|
|
674
|
+
confirm=confirm,
|
|
675
|
+
display=display,
|
|
676
|
+
)
|
|
677
|
+
return defval if _id not in _old_input_values else bool(_old_input_values[_id])
|
|
678
|
+
|
|
679
|
+
# noinspection PyMethodOverriding
|
|
680
|
+
@overload
|
|
681
|
+
@classmethod
|
|
682
|
+
def _float(cls, defval: float, title: str | None = None,
|
|
683
|
+
minval: float | None = None, maxval: float | None = None,
|
|
684
|
+
step: float | None = None,
|
|
685
|
+
tooltip: str | None = None, inline: str | None = None, group: str | None = None,
|
|
686
|
+
confirm: bool | None = False, display: _display.Display | None = None,
|
|
687
|
+
active: bool | None = None, *, _id: str = "") -> PyneFloat: ...
|
|
688
|
+
|
|
689
|
+
# noinspection PyMethodOverriding
|
|
690
|
+
@overload
|
|
691
|
+
@classmethod
|
|
692
|
+
def _float(cls, defval: float, title: str | None = None,
|
|
693
|
+
options: tuple[int | float, ...] | None = None,
|
|
694
|
+
tooltip: str | None = None, inline: str | None = None, group: str | None = None,
|
|
695
|
+
confirm: bool | None = False, display: _display.Display | None = None,
|
|
696
|
+
active: bool | None = None, *, _id: str = "") -> PyneFloat: ...
|
|
697
|
+
|
|
698
|
+
@classmethod
|
|
699
|
+
def _float(cls, defval: float, title: str | None = None, *args,
|
|
700
|
+
_id: str = "", **kwargs) -> PyneFloat:
|
|
701
|
+
"""
|
|
702
|
+
Adds an input to your script's settings, which allows you to provide configuration options
|
|
703
|
+
to script users. This function adds a field for a float input to the script's inputs.
|
|
704
|
+
|
|
705
|
+
Positional arguments after ``title`` follow Pine v6's two overloads
|
|
706
|
+
(``minval, maxval, step, ...`` or ``options, ...``); ``active`` is
|
|
707
|
+
UI-only in Pine and is accepted but ignored.
|
|
708
|
+
|
|
709
|
+
:param defval: The default value of the input
|
|
710
|
+
:param title: The title of the input
|
|
711
|
+
:param _id: The unique identifier of the input, it is filled by the InputTransformer
|
|
712
|
+
:return: The input value from toml file or the default
|
|
713
|
+
"""
|
|
714
|
+
cls._bind_numeric_tail(args, kwargs)
|
|
715
|
+
inputs[_id] = InputData(
|
|
716
|
+
id=_id,
|
|
717
|
+
input_type='float',
|
|
718
|
+
defval=defval,
|
|
719
|
+
title=title,
|
|
720
|
+
minval=kwargs.get('minval'),
|
|
721
|
+
maxval=kwargs.get('maxval'),
|
|
722
|
+
step=kwargs.get('step'),
|
|
723
|
+
tooltip=kwargs.get('tooltip'),
|
|
724
|
+
inline=kwargs.get('inline'),
|
|
725
|
+
group=kwargs.get('group'),
|
|
726
|
+
confirm=kwargs.get('confirm', False),
|
|
727
|
+
options=kwargs.get('options'),
|
|
728
|
+
display=kwargs.get('display'),
|
|
729
|
+
)
|
|
730
|
+
return defval if _id not in _old_input_values else safe_convert.safe_float(_old_input_values[_id])
|
|
731
|
+
|
|
732
|
+
# noinspection PyUnusedLocal
|
|
733
|
+
@classmethod
|
|
734
|
+
def string(cls, defval: str, title: str | None = None,
|
|
735
|
+
options: tuple[str, ...] | None = None,
|
|
736
|
+
tooltip: str | None = None, inline: str | None = None, group: str | None = None,
|
|
737
|
+
confirm: bool | None = False,
|
|
738
|
+
display: _display.Display | None = None, active: bool | None = None,
|
|
739
|
+
*, _id: str = "", **__) -> str:
|
|
740
|
+
"""
|
|
741
|
+
Adds an input to your script's settings, which allows you to provide configuration options
|
|
742
|
+
to script users. This function adds a field for a string input to the script's inputs.
|
|
743
|
+
|
|
744
|
+
:param defval: The default value of the input
|
|
745
|
+
:param title: The title of the input
|
|
746
|
+
:param tooltip: The tooltip of the input
|
|
747
|
+
:param inline: Inputs with the same inline string are displayed on one line
|
|
748
|
+
:param group: The group of the input
|
|
749
|
+
:param confirm: If True, the user will be asked to confirm the input
|
|
750
|
+
:param display: Controls where the script will display the input's information
|
|
751
|
+
:param active: UI-only in Pine (greys out the field); accepted for parity, ignored
|
|
752
|
+
:param options: A tuple of strings that the user can select from
|
|
753
|
+
:param _id: The unique identifier of the input, it is filled by the InputTransformer
|
|
754
|
+
:return: The input value from toml file or the default
|
|
755
|
+
"""
|
|
756
|
+
inputs[_id] = InputData(
|
|
757
|
+
id=_id,
|
|
758
|
+
input_type='string',
|
|
759
|
+
defval=defval,
|
|
760
|
+
title=title,
|
|
761
|
+
tooltip=tooltip,
|
|
762
|
+
inline=inline,
|
|
763
|
+
group=group,
|
|
764
|
+
confirm=confirm,
|
|
765
|
+
display=display,
|
|
766
|
+
options=options,
|
|
767
|
+
)
|
|
768
|
+
return defval if _id not in _old_input_values else str(_old_input_values[_id])
|
|
769
|
+
|
|
770
|
+
# noinspection PyUnusedLocal
|
|
771
|
+
@classmethod
|
|
772
|
+
def color(cls, defval: Color, title: str | None = None,
|
|
773
|
+
tooltip: str | None = None, inline: str | None = None, group: str | None = None,
|
|
774
|
+
confirm: bool | None = False, display: _display.Display | None = None,
|
|
775
|
+
active: bool | None = None,
|
|
776
|
+
*, _id: str = "", **__) -> Color:
|
|
777
|
+
"""
|
|
778
|
+
Adds an input to your script's settings, which allows you to provide configuration options
|
|
779
|
+
to script users. This function adds a field for a color input to the script's inputs.
|
|
780
|
+
|
|
781
|
+
:param defval: The default value of the input
|
|
782
|
+
:param title: The title of the input
|
|
783
|
+
:param tooltip: The tooltip of the input
|
|
784
|
+
:param inline: Inputs with the same inline string are displayed on one line
|
|
785
|
+
:param group: The group of the input
|
|
786
|
+
:param confirm: If True, the user will be asked to confirm the input
|
|
787
|
+
:param display: Controls where the script will display the input's information
|
|
788
|
+
:param active: UI-only in Pine (greys out the field); accepted for parity, ignored
|
|
789
|
+
:param _id: The unique identifier of the input, it is filled by the InputTransformer
|
|
790
|
+
:return: The input value from toml file or the default
|
|
791
|
+
"""
|
|
792
|
+
inputs[_id] = InputData(
|
|
793
|
+
id=_id,
|
|
794
|
+
input_type='color',
|
|
795
|
+
defval=defval,
|
|
796
|
+
title=title,
|
|
797
|
+
tooltip=tooltip,
|
|
798
|
+
inline=inline,
|
|
799
|
+
group=group,
|
|
800
|
+
confirm=confirm,
|
|
801
|
+
display=display,
|
|
802
|
+
)
|
|
803
|
+
return defval if _id not in _old_input_values else Color(_old_input_values[_id])
|
|
804
|
+
|
|
805
|
+
# noinspection PyUnusedLocal
|
|
806
|
+
@classmethod
|
|
807
|
+
def source(cls, defval: str | Source | float, title: str | None = None,
|
|
808
|
+
tooltip: str | None = None, inline: str | None = None, group: str | None = None,
|
|
809
|
+
display: _display.Display | None = None, active: bool | None = None,
|
|
810
|
+
confirm: bool | None = False,
|
|
811
|
+
*, _id: str = "", **__) -> PyneFloat:
|
|
812
|
+
"""
|
|
813
|
+
Adds an input to your script's settings, which allows you to provide configuration options
|
|
814
|
+
to script users. This function adds a field for a source input to the script's inputs.
|
|
815
|
+
|
|
816
|
+
Pine v6 positional order — uniquely among inputs, ``confirm`` comes LAST,
|
|
817
|
+
after ``display`` and ``active``.
|
|
818
|
+
|
|
819
|
+
:param defval: The name of the "source" registered in lib module,
|
|
820
|
+
like "open", "high", "low", "close", "hl2", "hlc3", "ohlc4"
|
|
821
|
+
:param title: The title of the input
|
|
822
|
+
:param tooltip: The tooltip of the input
|
|
823
|
+
:param inline: Inputs with the same inline string are displayed on one line
|
|
824
|
+
:param group: The group of the input
|
|
825
|
+
:param display: Controls where the script will display the input's information
|
|
826
|
+
:param active: UI-only in Pine (greys out the field); accepted for parity, ignored
|
|
827
|
+
:param confirm: If True, the user will be asked to confirm the input
|
|
828
|
+
:param _id: The unique identifier of the input, it is filled by the InputTransformer
|
|
829
|
+
:return: The input value from toml file or the default
|
|
830
|
+
"""
|
|
831
|
+
defval = str(defval)
|
|
832
|
+
inputs[_id] = InputData(
|
|
833
|
+
id=_id,
|
|
834
|
+
input_type='source',
|
|
835
|
+
defval=defval,
|
|
836
|
+
title=title,
|
|
837
|
+
tooltip=tooltip,
|
|
838
|
+
inline=inline,
|
|
839
|
+
group=group,
|
|
840
|
+
confirm=confirm,
|
|
841
|
+
display=display,
|
|
842
|
+
)
|
|
843
|
+
# We actually return a string here, but the InputTransformer will add a `getattr()` call to get the
|
|
844
|
+
return defval if _id not in _old_input_values else _old_input_values[_id] # type: ignore[return-value]
|
|
845
|
+
|
|
846
|
+
# noinspection PyUnusedLocal
|
|
847
|
+
@classmethod
|
|
848
|
+
def enum(cls, defval: TEnum, title: str | None = None,
|
|
849
|
+
options: tuple[str, ...] | None = None,
|
|
850
|
+
tooltip: str | None = None, inline: str | None = None, group: str | None = None,
|
|
851
|
+
confirm: bool | None = False,
|
|
852
|
+
display: _display.Display | None = None, active: bool | None = None,
|
|
853
|
+
*, _id: str = "", **__) -> TEnum:
|
|
854
|
+
"""
|
|
855
|
+
Adds an input to your script's settings, which allows you to provide configuration options
|
|
856
|
+
to script users. This function adds a field for a enum input to the script's inputs.
|
|
857
|
+
|
|
858
|
+
:param defval: The default value of the input
|
|
859
|
+
:param title: The title of the input
|
|
860
|
+
:param tooltip: The tooltip of the input
|
|
861
|
+
:param inline: Inputs with the same inline string are displayed on one line
|
|
862
|
+
:param group: The group of the input
|
|
863
|
+
:param confirm: If True, the user will be asked to confirm the input
|
|
864
|
+
:param display: Controls where the script will display the input's information
|
|
865
|
+
:param active: UI-only in Pine (greys out the field); accepted for parity, ignored
|
|
866
|
+
:param options: A tuple of strings that the user can select from
|
|
867
|
+
:param _id: The unique identifier of the input, it is filled by the InputTransformer
|
|
868
|
+
:return: The input value from toml file or the default
|
|
869
|
+
"""
|
|
870
|
+
inputs[_id] = InputData(
|
|
871
|
+
id=_id,
|
|
872
|
+
input_type='enum',
|
|
873
|
+
defval=defval,
|
|
874
|
+
title=title,
|
|
875
|
+
tooltip=tooltip,
|
|
876
|
+
inline=inline,
|
|
877
|
+
group=group,
|
|
878
|
+
confirm=confirm,
|
|
879
|
+
display=display,
|
|
880
|
+
options=options,
|
|
881
|
+
)
|
|
882
|
+
if _id not in _old_input_values:
|
|
883
|
+
return defval
|
|
884
|
+
else:
|
|
885
|
+
# Convert string value back to the specific enum type
|
|
886
|
+
value = _old_input_values[_id]
|
|
887
|
+
if isinstance(value, str):
|
|
888
|
+
try:
|
|
889
|
+
return defval.__class__(value)
|
|
890
|
+
except ValueError:
|
|
891
|
+
return defval
|
|
892
|
+
return defval
|
|
893
|
+
|
|
894
|
+
# We don't have interactive inputs, so price is stored as a float input; its
|
|
895
|
+
# Pine positional order has no minval/maxval/step, so it cannot alias _float
|
|
896
|
+
# noinspection PyUnusedLocal
|
|
897
|
+
@classmethod
|
|
898
|
+
def price(cls, defval: float, title: str | None = None,
|
|
899
|
+
tooltip: str | None = None, inline: str | None = None, group: str | None = None,
|
|
900
|
+
confirm: bool | None = False, display: _display.Display | None = None,
|
|
901
|
+
active: bool | None = None,
|
|
902
|
+
*, _id: str = "", **__) -> PyneFloat:
|
|
903
|
+
"""
|
|
904
|
+
Adds an input to your script's settings, which allows you to provide configuration options
|
|
905
|
+
to script users. This function adds a field for a price input to the script's inputs.
|
|
906
|
+
|
|
907
|
+
:param defval: The default value of the input
|
|
908
|
+
:param title: The title of the input
|
|
909
|
+
:param tooltip: The tooltip of the input
|
|
910
|
+
:param inline: Inputs with the same inline string are displayed on one line
|
|
911
|
+
:param group: The group of the input
|
|
912
|
+
:param confirm: If True, the user will be asked to confirm the input
|
|
913
|
+
:param display: Controls where the script will display the input's information
|
|
914
|
+
:param active: UI-only in Pine (greys out the field); accepted for parity, ignored
|
|
915
|
+
:param _id: The unique identifier of the input, it is filled by the InputTransformer
|
|
916
|
+
:return: The input value from toml file or the default
|
|
917
|
+
"""
|
|
918
|
+
return cls._float(defval, title, tooltip=tooltip, inline=inline, group=group,
|
|
919
|
+
confirm=confirm, display=display, _id=_id)
|
|
920
|
+
|
|
921
|
+
# Pine's input.symbol has NO options: its third positional is tooltip, so it
|
|
922
|
+
# cannot alias string (whose third positional is options)
|
|
923
|
+
# noinspection PyUnusedLocal
|
|
924
|
+
@classmethod
|
|
925
|
+
def symbol(cls, defval: str, title: str | None = None,
|
|
926
|
+
tooltip: str | None = None, inline: str | None = None, group: str | None = None,
|
|
927
|
+
confirm: bool | None = False, display: _display.Display | None = None,
|
|
928
|
+
active: bool | None = None,
|
|
929
|
+
*, _id: str = "", **__) -> str:
|
|
930
|
+
"""
|
|
931
|
+
Adds an input to your script's settings, which allows you to provide configuration options
|
|
932
|
+
to script users. This function adds a field for a symbol input to the script's inputs.
|
|
933
|
+
|
|
934
|
+
:param defval: The default value of the input
|
|
935
|
+
:param title: The title of the input
|
|
936
|
+
:param tooltip: The tooltip of the input
|
|
937
|
+
:param inline: Inputs with the same inline string are displayed on one line
|
|
938
|
+
:param group: The group of the input
|
|
939
|
+
:param confirm: If True, the user will be asked to confirm the input
|
|
940
|
+
:param display: Controls where the script will display the input's information
|
|
941
|
+
:param active: UI-only in Pine (greys out the field); accepted for parity, ignored
|
|
942
|
+
:param _id: The unique identifier of the input, it is filled by the InputTransformer
|
|
943
|
+
:return: The input value from toml file or the default
|
|
944
|
+
"""
|
|
945
|
+
return cls.string(defval, title, tooltip=tooltip, inline=inline, group=group,
|
|
946
|
+
confirm=confirm, display=display, _id=_id)
|
|
947
|
+
|
|
948
|
+
# Pine's input.text_area has neither options nor inline: its positional
|
|
949
|
+
# order is defval, title, tooltip, group, confirm, display, active
|
|
950
|
+
# noinspection PyUnusedLocal
|
|
951
|
+
@classmethod
|
|
952
|
+
def text_area(cls, defval: str, title: str | None = None,
|
|
953
|
+
tooltip: str | None = None, group: str | None = None,
|
|
954
|
+
confirm: bool | None = False, display: _display.Display | None = None,
|
|
955
|
+
active: bool | None = None,
|
|
956
|
+
*, _id: str = "", **__) -> str:
|
|
957
|
+
"""
|
|
958
|
+
Adds an input to your script's settings, which allows you to provide configuration options
|
|
959
|
+
to script users. This function adds a field for a text area input to the script's inputs.
|
|
960
|
+
|
|
961
|
+
:param defval: The default value of the input
|
|
962
|
+
:param title: The title of the input
|
|
963
|
+
:param tooltip: The tooltip of the input
|
|
964
|
+
:param group: The group of the input
|
|
965
|
+
:param confirm: If True, the user will be asked to confirm the input
|
|
966
|
+
:param display: Controls where the script will display the input's information
|
|
967
|
+
:param active: UI-only in Pine (greys out the field); accepted for parity, ignored
|
|
968
|
+
:param _id: The unique identifier of the input, it is filled by the InputTransformer
|
|
969
|
+
:return: The input value from toml file or the default
|
|
970
|
+
"""
|
|
971
|
+
return cls.string(defval, title, tooltip=tooltip, group=group,
|
|
972
|
+
confirm=confirm, display=display, _id=_id)
|
|
973
|
+
|
|
974
|
+
# time() returns UNIX timestamp in milliseconds (int); its Pine positional
|
|
975
|
+
# order has no minval/maxval/step, so it cannot alias _int
|
|
976
|
+
# noinspection PyUnusedLocal
|
|
977
|
+
@classmethod
|
|
978
|
+
def time(cls, defval: int, title: str | None = None,
|
|
979
|
+
tooltip: str | None = None, inline: str | None = None, group: str | None = None,
|
|
980
|
+
confirm: bool | None = False, display: _display.Display | None = None,
|
|
981
|
+
active: bool | None = None,
|
|
982
|
+
*, _id: str = "", **__) -> PyneInt:
|
|
983
|
+
"""
|
|
984
|
+
Adds an input to your script's settings, which allows you to provide configuration options
|
|
985
|
+
to script users. This function adds a field for a time input to the script's inputs.
|
|
986
|
+
|
|
987
|
+
:param defval: The default value of the input (UNIX timestamp in milliseconds)
|
|
988
|
+
:param title: The title of the input
|
|
989
|
+
:param tooltip: The tooltip of the input
|
|
990
|
+
:param inline: Inputs with the same inline string are displayed on one line
|
|
991
|
+
:param group: The group of the input
|
|
992
|
+
:param confirm: If True, the user will be asked to confirm the input
|
|
993
|
+
:param display: Controls where the script will display the input's information
|
|
994
|
+
:param active: UI-only in Pine (greys out the field); accepted for parity, ignored
|
|
995
|
+
:param _id: The unique identifier of the input, it is filled by the InputTransformer
|
|
996
|
+
:return: The input value from toml file or the default
|
|
997
|
+
"""
|
|
998
|
+
return cls._int(defval, title, tooltip=tooltip, inline=inline, group=group,
|
|
999
|
+
confirm=confirm, display=display, _id=_id)
|
|
1000
|
+
|
|
1001
|
+
int = _int
|
|
1002
|
+
bool = _bool
|
|
1003
|
+
float = _float
|
|
1004
|
+
|
|
1005
|
+
# These are incomplete, but good workaround
|
|
1006
|
+
session = string
|
|
1007
|
+
timeframe = string
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
# noinspection PyShadowingBuiltins
|
|
1011
|
+
input = _Input()
|