pineforge-codegen 0.6.5__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.
- pineforge_codegen/__init__.py +53 -0
- pineforge_codegen/analyzer/__init__.py +60 -0
- pineforge_codegen/analyzer/base.py +1563 -0
- pineforge_codegen/analyzer/call_handlers.py +895 -0
- pineforge_codegen/analyzer/contracts.py +163 -0
- pineforge_codegen/analyzer/diagnostics.py +118 -0
- pineforge_codegen/analyzer/tables.py +204 -0
- pineforge_codegen/analyzer/types.py +250 -0
- pineforge_codegen/ast_nodes.py +293 -0
- pineforge_codegen/codegen/__init__.py +78 -0
- pineforge_codegen/codegen/base.py +1381 -0
- pineforge_codegen/codegen/emit_top.py +875 -0
- pineforge_codegen/codegen/helpers.py +163 -0
- pineforge_codegen/codegen/helpers_syminfo.py +134 -0
- pineforge_codegen/codegen/input.py +189 -0
- pineforge_codegen/codegen/security.py +1564 -0
- pineforge_codegen/codegen/ta.py +298 -0
- pineforge_codegen/codegen/tables.py +613 -0
- pineforge_codegen/codegen/types.py +573 -0
- pineforge_codegen/codegen/visit_call.py +1305 -0
- pineforge_codegen/codegen/visit_expr.py +701 -0
- pineforge_codegen/codegen/visit_stmt.py +729 -0
- pineforge_codegen/errors.py +98 -0
- pineforge_codegen/lexer.py +531 -0
- pineforge_codegen/parser.py +1198 -0
- pineforge_codegen/pragmas.py +117 -0
- pineforge_codegen/signatures.py +808 -0
- pineforge_codegen/support_checker.py +1111 -0
- pineforge_codegen/symbols.py +118 -0
- pineforge_codegen/tokens.py +406 -0
- pineforge_codegen/tv_input_choices.py +86 -0
- pineforge_codegen-0.6.5.dist-info/METADATA +462 -0
- pineforge_codegen-0.6.5.dist-info/RECORD +35 -0
- pineforge_codegen-0.6.5.dist-info/WHEEL +4 -0
- pineforge_codegen-0.6.5.dist-info/licenses/LICENSE +197 -0
|
@@ -0,0 +1,808 @@
|
|
|
1
|
+
"""Complete PineScript v6 intrinsic function signatures.
|
|
2
|
+
|
|
3
|
+
Single source of truth for all TradingView built-in function signatures.
|
|
4
|
+
Used by both analyzer (type inference, kwargs resolution) and codegen
|
|
5
|
+
(correct C++ emission).
|
|
6
|
+
|
|
7
|
+
Each signature specifies:
|
|
8
|
+
- params: ordered list of (name, type, default_value_or_None)
|
|
9
|
+
- return_type: PineType
|
|
10
|
+
- overloads: list of alternative param lists (if function is overloaded)
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
from .symbols import PineType
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class Param:
|
|
22
|
+
"""One function parameter."""
|
|
23
|
+
name: str
|
|
24
|
+
pine_type: PineType = PineType.FLOAT
|
|
25
|
+
default: Any = None # None = required, else default value
|
|
26
|
+
is_series: bool = True # series vs simple/const
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class FuncSig:
|
|
31
|
+
"""One function signature (one overload)."""
|
|
32
|
+
params: list[Param] = field(default_factory=list)
|
|
33
|
+
return_type: PineType = PineType.FLOAT
|
|
34
|
+
returns_tuple: bool = False
|
|
35
|
+
tuple_count: int = 0 # number of tuple elements
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class IntrinsicFunc:
|
|
40
|
+
"""Complete intrinsic function definition with all overloads."""
|
|
41
|
+
name: str # e.g. "ta.sma" or "math.abs"
|
|
42
|
+
signatures: list[FuncSig] = field(default_factory=list)
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def primary(self) -> FuncSig:
|
|
46
|
+
return self.signatures[0]
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def param_names(self) -> list[str]:
|
|
50
|
+
"""Param names from the widest overload (for kwargs resolution).
|
|
51
|
+
|
|
52
|
+
Uses the overload with the most params so all possible kwargs
|
|
53
|
+
can be resolved to positional positions.
|
|
54
|
+
"""
|
|
55
|
+
widest = max(self.signatures, key=lambda s: len(s.params))
|
|
56
|
+
return [p.name for p in widest.params]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# ---------------------------------------------------------------------------
|
|
60
|
+
# Helper constructors
|
|
61
|
+
# ---------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
def _sig(params: list[tuple], ret: PineType = PineType.FLOAT,
|
|
64
|
+
returns_tuple: bool = False, tuple_count: int = 0) -> FuncSig:
|
|
65
|
+
"""Shorthand to build a FuncSig from tuples of (name, type, default)."""
|
|
66
|
+
plist = []
|
|
67
|
+
for p in params:
|
|
68
|
+
name = p[0]
|
|
69
|
+
ptype = p[1] if len(p) > 1 else PineType.FLOAT
|
|
70
|
+
default = p[2] if len(p) > 2 else None
|
|
71
|
+
plist.append(Param(name=name, pine_type=ptype, default=default))
|
|
72
|
+
return FuncSig(params=plist, return_type=ret,
|
|
73
|
+
returns_tuple=returns_tuple, tuple_count=tuple_count)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _func(name: str, *sigs: FuncSig) -> IntrinsicFunc:
|
|
77
|
+
return IntrinsicFunc(name=name, signatures=list(sigs))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# Shortcuts for common param types
|
|
81
|
+
F = PineType.FLOAT
|
|
82
|
+
I = PineType.INT
|
|
83
|
+
B = PineType.BOOL
|
|
84
|
+
S = PineType.STRING
|
|
85
|
+
NA = PineType.NA
|
|
86
|
+
VOID = PineType.VOID
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# ============================================================================
|
|
90
|
+
# ta.* functions
|
|
91
|
+
# ============================================================================
|
|
92
|
+
|
|
93
|
+
TA_FUNCTIONS: dict[str, IntrinsicFunc] = {}
|
|
94
|
+
|
|
95
|
+
def _ta(short_name: str, *sigs: FuncSig) -> None:
|
|
96
|
+
TA_FUNCTIONS[short_name] = _func(f"ta.{short_name}", *sigs)
|
|
97
|
+
|
|
98
|
+
# --- Moving Averages ---
|
|
99
|
+
_ta("sma", _sig([("source", F), ("length", I)]))
|
|
100
|
+
_ta("ema", _sig([("source", F), ("length", I)]))
|
|
101
|
+
_ta("rma", _sig([("source", F), ("length", I)]))
|
|
102
|
+
_ta("wma", _sig([("source", F), ("length", I)]))
|
|
103
|
+
_ta("hma", _sig([("source", F), ("length", I)]))
|
|
104
|
+
_ta("vwma", _sig([("source", F), ("length", I)]))
|
|
105
|
+
_ta("alma", _sig([("source", F), ("length", I), ("offset", F, 0.85), ("sigma", F, 6.0)]))
|
|
106
|
+
_ta("swma", _sig([("source", F)]))
|
|
107
|
+
_ta("linreg", _sig([("source", F), ("length", I), ("offset", I, 0)]))
|
|
108
|
+
|
|
109
|
+
# --- Oscillators ---
|
|
110
|
+
_ta("rsi", _sig([("source", F), ("length", I)]))
|
|
111
|
+
_ta("stoch", _sig([("source", F), ("high", F), ("low", F), ("length", I)]))
|
|
112
|
+
_ta("cci", _sig([("source", F), ("length", I)]))
|
|
113
|
+
_ta("mfi", _sig([("series", F), ("length", I)]))
|
|
114
|
+
_ta("mom", _sig([("source", F), ("length", I)]))
|
|
115
|
+
_ta("roc", _sig([("source", F), ("length", I)]))
|
|
116
|
+
_ta("cmo", _sig([("source", F), ("length", I)]))
|
|
117
|
+
_ta("tsi", _sig([("source", F), ("short_length", I), ("long_length", I)]))
|
|
118
|
+
_ta("wpr", _sig([("length", I)]))
|
|
119
|
+
_ta("cog", _sig([("source", F), ("length", I)]))
|
|
120
|
+
|
|
121
|
+
# --- MACD ---
|
|
122
|
+
_ta("macd", _sig([("source", F), ("fastlen", I), ("slowlen", I), ("siglen", I)],
|
|
123
|
+
returns_tuple=True, tuple_count=3))
|
|
124
|
+
|
|
125
|
+
# --- Bollinger Bands / Keltner ---
|
|
126
|
+
_ta("bb", _sig([("source", F), ("length", I), ("mult", F, 2.0)],
|
|
127
|
+
returns_tuple=True, tuple_count=3))
|
|
128
|
+
_ta("kc", _sig([("source", F), ("length", I), ("mult", F, 1.5)],
|
|
129
|
+
returns_tuple=True, tuple_count=3))
|
|
130
|
+
_ta("bbw", _sig([("source", F), ("length", I), ("mult", F, 2.0)]))
|
|
131
|
+
_ta("kcw", _sig([("source", F), ("length", I), ("mult", F, 1.5)]))
|
|
132
|
+
|
|
133
|
+
# --- Volatility & Range ---
|
|
134
|
+
_ta("atr", _sig([("length", I)]))
|
|
135
|
+
_ta("tr", _sig([("handle_na", B, False)]))
|
|
136
|
+
_ta("stdev", _sig([("source", F), ("length", I)]))
|
|
137
|
+
_ta("variance",_sig([("source", F), ("length", I)]))
|
|
138
|
+
|
|
139
|
+
# --- Trend ---
|
|
140
|
+
_ta("supertrend", _sig([("factor", F), ("atrPeriod", I)],
|
|
141
|
+
returns_tuple=True, tuple_count=2))
|
|
142
|
+
_ta("dmi", _sig([("diLength", I), ("adxSmoothing", I)],
|
|
143
|
+
returns_tuple=True, tuple_count=3))
|
|
144
|
+
_ta("sar", _sig([("start", F, 0.02), ("inc", F, 0.02), ("max", F, 0.2)]))
|
|
145
|
+
|
|
146
|
+
# --- Crossover / State ---
|
|
147
|
+
_ta("crossover", _sig([("source1", F), ("source2", F)], ret=B))
|
|
148
|
+
_ta("crossunder", _sig([("source1", F), ("source2", F)], ret=B))
|
|
149
|
+
_ta("cross", _sig([("source1", F), ("source2", F)], ret=B))
|
|
150
|
+
_ta("rising", _sig([("source", F), ("length", I)], ret=B))
|
|
151
|
+
_ta("falling", _sig([("source", F), ("length", I)], ret=B))
|
|
152
|
+
_ta("change", _sig([("source", F), ("length", I, 1)]))
|
|
153
|
+
|
|
154
|
+
# --- Extremes & Lookback ---
|
|
155
|
+
# ta.highest / ta.lowest have TWO overloads:
|
|
156
|
+
# ta.highest(source, length) — full form
|
|
157
|
+
# ta.highest(length) — source defaults to high/low
|
|
158
|
+
_ta("highest",
|
|
159
|
+
_sig([("source", F), ("length", I)]),
|
|
160
|
+
_sig([("length", I)]))
|
|
161
|
+
_ta("lowest",
|
|
162
|
+
_sig([("source", F), ("length", I)]),
|
|
163
|
+
_sig([("length", I)]))
|
|
164
|
+
_ta("highestbars", _sig([("source", F), ("length", I)], ret=I))
|
|
165
|
+
_ta("lowestbars", _sig([("source", F), ("length", I)], ret=I))
|
|
166
|
+
_ta("median", _sig([("source", F), ("length", I)]))
|
|
167
|
+
_ta("percentrank", _sig([("source", F), ("length", I)]))
|
|
168
|
+
_ta("percentile_nearest_rank", _sig([("source", F), ("length", I), ("percentage", F)]))
|
|
169
|
+
_ta("percentile_linear_interpolation", _sig([("source", F), ("length", I), ("percentage", F)]))
|
|
170
|
+
|
|
171
|
+
# --- Pivots ---
|
|
172
|
+
# ta.pivothigh/pivotlow have TWO overloads:
|
|
173
|
+
# ta.pivothigh(source, leftbars, rightbars)
|
|
174
|
+
# ta.pivothigh(leftbars, rightbars) — source defaults to high/low
|
|
175
|
+
_ta("pivothigh",
|
|
176
|
+
_sig([("source", F), ("leftbars", I), ("rightbars", I)]),
|
|
177
|
+
_sig([("leftbars", I), ("rightbars", I)]))
|
|
178
|
+
_ta("pivotlow",
|
|
179
|
+
_sig([("source", F), ("leftbars", I), ("rightbars", I)]),
|
|
180
|
+
_sig([("leftbars", I), ("rightbars", I)]))
|
|
181
|
+
|
|
182
|
+
# --- Volume indicators ---
|
|
183
|
+
# ta.vwap has TWO overloads:
|
|
184
|
+
# ta.vwap(source, anchor, stdev_mult) — 3-arg bands form (primary), returns [vwap, upper, lower]
|
|
185
|
+
# ta.vwap(source) — scalar 1-arg form (daily anchor)
|
|
186
|
+
# Note: primary is the 3-arg form so param_names covers all kwargs; the
|
|
187
|
+
# analyzer remaps 3-arg calls to the internal "vwap_bands" dispatch key.
|
|
188
|
+
_ta("vwap", _sig([("source", F), ("anchor", B), ("stdev_mult", F)],
|
|
189
|
+
returns_tuple=True, tuple_count=3),
|
|
190
|
+
_sig([("source", F)]))
|
|
191
|
+
|
|
192
|
+
# --- Statistical (additional) ---
|
|
193
|
+
_ta("mode", _sig([("source", F), ("length", I)]))
|
|
194
|
+
_ta("range", _sig([("source", F), ("length", I)]))
|
|
195
|
+
_ta("dev", _sig([("source", F), ("length", I)]))
|
|
196
|
+
|
|
197
|
+
# --- Cumulative & Historical ---
|
|
198
|
+
_ta("cum", _sig([("source", F)]))
|
|
199
|
+
_ta("barssince", _sig([("condition", B)], ret=I))
|
|
200
|
+
_ta("valuewhen", _sig([("condition", B), ("source", F), ("occurrence", I)]))
|
|
201
|
+
_ta("correlation", _sig([("source1", F), ("source2", F), ("length", I)]))
|
|
202
|
+
|
|
203
|
+
# --- Chart all-time extremes (single series) ---
|
|
204
|
+
_ta("max", _sig([("source", F)]))
|
|
205
|
+
_ta("min", _sig([("source", F)]))
|
|
206
|
+
|
|
207
|
+
# --- Rank Correlation Index ---
|
|
208
|
+
_ta("rci", _sig([("source", F), ("length", I)]))
|
|
209
|
+
|
|
210
|
+
# --- Pivot levels ---
|
|
211
|
+
_ta("pivot_point_levels",
|
|
212
|
+
_sig([("type", S), ("anchor", B), ("developing", B, False)]))
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
# ============================================================================
|
|
216
|
+
# math.* functions
|
|
217
|
+
# ============================================================================
|
|
218
|
+
|
|
219
|
+
MATH_FUNCTIONS: dict[str, IntrinsicFunc] = {}
|
|
220
|
+
|
|
221
|
+
def _math(short_name: str, *sigs: FuncSig) -> None:
|
|
222
|
+
MATH_FUNCTIONS[short_name] = _func(f"math.{short_name}", *sigs)
|
|
223
|
+
|
|
224
|
+
# Arithmetic
|
|
225
|
+
_math("abs", _sig([("x", F)]))
|
|
226
|
+
_math("ceil", _sig([("x", F)], ret=I))
|
|
227
|
+
_math("floor", _sig([("x", F)], ret=I))
|
|
228
|
+
_math("round",
|
|
229
|
+
_sig([("x", F)], ret=I), # round(x) → int
|
|
230
|
+
_sig([("x", F), ("precision", I)])) # round(x, n) → float
|
|
231
|
+
_math("round_to_mintick", _sig([("x", F)]))
|
|
232
|
+
_math("sign", _sig([("x", F)], ret=I))
|
|
233
|
+
_math("max",
|
|
234
|
+
_sig([("x", F), ("y", F)]), # 2-arg
|
|
235
|
+
_sig([("x", F), ("y", F), ("z", F)]), # 3-arg
|
|
236
|
+
_sig([("x", F), ("y", F), ("z", F), ("w", F)])) # 4-arg
|
|
237
|
+
_math("min",
|
|
238
|
+
_sig([("x", F), ("y", F)]),
|
|
239
|
+
_sig([("x", F), ("y", F), ("z", F)]),
|
|
240
|
+
_sig([("x", F), ("y", F), ("z", F), ("w", F)]))
|
|
241
|
+
_math("avg",
|
|
242
|
+
_sig([("x", F), ("y", F)]),
|
|
243
|
+
_sig([("x", F), ("y", F), ("z", F)]),
|
|
244
|
+
_sig([("x", F), ("y", F), ("z", F), ("w", F)]),
|
|
245
|
+
_sig([("x", F), ("y", F), ("z", F), ("w", F), ("u", F)]),
|
|
246
|
+
_sig([("x", F), ("y", F), ("z", F), ("w", F), ("u", F), ("v", F)]))
|
|
247
|
+
_math("sum", _sig([("source", F), ("length", I)])) # rolling sum → math::Sum in runtime
|
|
248
|
+
_math("pow", _sig([("base", F), ("exp", F)]))
|
|
249
|
+
_math("sqrt", _sig([("x", F)]))
|
|
250
|
+
_math("exp", _sig([("x", F)]))
|
|
251
|
+
_math("log", _sig([("x", F)]))
|
|
252
|
+
_math("log10", _sig([("x", F)]))
|
|
253
|
+
_math("random", _sig([("min", F, 0.0), ("max", F, 1.0), ("seed", I, None)]))
|
|
254
|
+
|
|
255
|
+
# Trigonometry
|
|
256
|
+
_math("sin", _sig([("x", F)]))
|
|
257
|
+
_math("cos", _sig([("x", F)]))
|
|
258
|
+
_math("tan", _sig([("x", F)]))
|
|
259
|
+
_math("asin", _sig([("x", F)]))
|
|
260
|
+
_math("acos", _sig([("x", F)]))
|
|
261
|
+
_math("atan", _sig([("x", F)]))
|
|
262
|
+
_math("atan2", _sig([("y", F), ("x", F)]))
|
|
263
|
+
_math("todegrees", _sig([("x", F)]))
|
|
264
|
+
_math("toradians", _sig([("x", F)]))
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
# ============================================================================
|
|
268
|
+
# strategy.* functions
|
|
269
|
+
# ============================================================================
|
|
270
|
+
|
|
271
|
+
STRATEGY_FUNCTIONS: dict[str, IntrinsicFunc] = {}
|
|
272
|
+
|
|
273
|
+
def _strat(short_name: str, *sigs: FuncSig) -> None:
|
|
274
|
+
STRATEGY_FUNCTIONS[short_name] = _func(f"strategy.{short_name}", *sigs)
|
|
275
|
+
|
|
276
|
+
_strat("entry", _sig([
|
|
277
|
+
("id", S), ("direction", B), ("qty", F, None),
|
|
278
|
+
("limit", F, None), ("stop", F, None),
|
|
279
|
+
("oca_name", S, None), ("oca_type", I, None),
|
|
280
|
+
("comment", S, None), ("alert_message", S, None),
|
|
281
|
+
("disable_alert", B, None), ("qty_type", I, None),
|
|
282
|
+
], ret=VOID))
|
|
283
|
+
|
|
284
|
+
_strat("order", _sig([
|
|
285
|
+
("id", S), ("direction", B), ("qty", F, None),
|
|
286
|
+
("limit", F, None), ("stop", F, None),
|
|
287
|
+
("oca_name", S, None), ("oca_type", I, None),
|
|
288
|
+
("comment", S, None), ("alert_message", S, None),
|
|
289
|
+
("disable_alert", B, None), ("qty_type", I, None),
|
|
290
|
+
], ret=VOID))
|
|
291
|
+
|
|
292
|
+
_strat("exit", _sig([
|
|
293
|
+
("id", S), ("from_entry", S, ""),
|
|
294
|
+
("qty", F, None), ("qty_percent", F, None),
|
|
295
|
+
("profit", F, None), ("loss", F, None),
|
|
296
|
+
("limit", F, None), ("stop", F, None),
|
|
297
|
+
("trail_price", F, None), ("trail_points", F, None),
|
|
298
|
+
("trail_offset", F, None),
|
|
299
|
+
("oca_name", S, None),
|
|
300
|
+
("comment", S, None), ("comment_profit", S, None),
|
|
301
|
+
("comment_loss", S, None), ("comment_trailing", S, None),
|
|
302
|
+
("alert_message", S, None),
|
|
303
|
+
("alert_profit", S, None), ("alert_loss", S, None), ("alert_trailing", S, None),
|
|
304
|
+
("disable_alert", B, None),
|
|
305
|
+
], ret=VOID))
|
|
306
|
+
|
|
307
|
+
_strat("close", _sig([
|
|
308
|
+
("id", S), ("comment", S, None),
|
|
309
|
+
("qty", F, None), ("qty_percent", F, None),
|
|
310
|
+
("alert_message", S, None), ("disable_alert", B, None),
|
|
311
|
+
("immediately", B, False),
|
|
312
|
+
], ret=VOID))
|
|
313
|
+
|
|
314
|
+
_strat("close_all", _sig([
|
|
315
|
+
("comment", S, None), ("alert_message", S, None),
|
|
316
|
+
("disable_alert", B, None), ("immediately", B, False),
|
|
317
|
+
], ret=VOID))
|
|
318
|
+
|
|
319
|
+
_strat("cancel", _sig([("id", S)], ret=VOID))
|
|
320
|
+
_strat("cancel_all", _sig([], ret=VOID))
|
|
321
|
+
|
|
322
|
+
_strat("convert_to_account", _sig([("value", F)], ret=F))
|
|
323
|
+
_strat("convert_to_symbol", _sig([("value", F)], ret=F))
|
|
324
|
+
_strat("default_entry_qty", _sig([("fill_price", F)], ret=F))
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
# ============================================================================
|
|
328
|
+
# str.* functions
|
|
329
|
+
# ============================================================================
|
|
330
|
+
|
|
331
|
+
STR_FUNCTIONS: dict[str, IntrinsicFunc] = {}
|
|
332
|
+
|
|
333
|
+
def _str(short_name: str, *sigs: FuncSig) -> None:
|
|
334
|
+
STR_FUNCTIONS[short_name] = _func(f"str.{short_name}", *sigs)
|
|
335
|
+
|
|
336
|
+
_str("tostring",
|
|
337
|
+
_sig([("value", F)], ret=S),
|
|
338
|
+
_sig([("value", F), ("format", S)], ret=S))
|
|
339
|
+
_str("tonumber", _sig([("string", S)], ret=F))
|
|
340
|
+
_str("format", _sig([("formatStr", S)], ret=S)) # variadic
|
|
341
|
+
_str("format_time", _sig([("time", I), ("format", S), ("timezone", S, "")], ret=S))
|
|
342
|
+
_str("length", _sig([("string", S)], ret=I))
|
|
343
|
+
_str("contains", _sig([("source", S), ("str", S)], ret=B))
|
|
344
|
+
_str("startswith", _sig([("source", S), ("str", S)], ret=B))
|
|
345
|
+
_str("endswith", _sig([("source", S), ("str", S)], ret=B))
|
|
346
|
+
_str("pos", _sig([("source", S), ("str", S)], ret=I))
|
|
347
|
+
_str("substring",
|
|
348
|
+
_sig([("source", S), ("begin_pos", I)], ret=S),
|
|
349
|
+
_sig([("source", S), ("begin_pos", I), ("end_pos", I)], ret=S))
|
|
350
|
+
_str("replace", _sig([("source", S), ("target", S), ("replacement", S), ("occurrence", I, 0)], ret=S))
|
|
351
|
+
_str("replace_all", _sig([("source", S), ("target", S), ("replacement", S)], ret=S))
|
|
352
|
+
_str("lower", _sig([("source", S)], ret=S))
|
|
353
|
+
_str("upper", _sig([("source", S)], ret=S))
|
|
354
|
+
_str("trim", _sig([("source", S)], ret=S))
|
|
355
|
+
_str("repeat", _sig([("source", S), ("count", I)], ret=S))
|
|
356
|
+
_str("match", _sig([("source", S), ("regex", S)], ret=S))
|
|
357
|
+
_str("split", _sig([("string", S), ("separator", S)], ret=S)) # returns array<string>
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
# ============================================================================
|
|
361
|
+
# map.* functions
|
|
362
|
+
# ============================================================================
|
|
363
|
+
|
|
364
|
+
MAP_FUNCTIONS: dict[str, IntrinsicFunc] = {}
|
|
365
|
+
|
|
366
|
+
def _map(short_name: str, *sigs: FuncSig) -> None:
|
|
367
|
+
MAP_FUNCTIONS[short_name] = _func(f"map.{short_name}", *sigs)
|
|
368
|
+
|
|
369
|
+
_map("new", _sig([], ret=F))
|
|
370
|
+
_map("put", _sig([("id", F), ("key", S), ("value", F)], ret=F))
|
|
371
|
+
_map("get", _sig([("id", F), ("key", S)], ret=F))
|
|
372
|
+
_map("remove", _sig([("id", F), ("key", S)], ret=F))
|
|
373
|
+
_map("contains", _sig([("id", F), ("key", S)], ret=B))
|
|
374
|
+
_map("size", _sig([("id", F)], ret=I))
|
|
375
|
+
_map("clear", _sig([("id", F)], ret=VOID))
|
|
376
|
+
_map("keys", _sig([("id", F)], ret=F)) # returns array
|
|
377
|
+
_map("values", _sig([("id", F)], ret=F)) # returns array
|
|
378
|
+
_map("copy", _sig([("id", F)], ret=F))
|
|
379
|
+
_map("put_all", _sig([("id", F), ("id2", F)], ret=VOID))
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
# ============================================================================
|
|
383
|
+
# syminfo.* functions
|
|
384
|
+
# ============================================================================
|
|
385
|
+
|
|
386
|
+
SYMINFO_FUNCTIONS: dict[str, IntrinsicFunc] = {}
|
|
387
|
+
|
|
388
|
+
def _syminfo_fn(short_name: str, *sigs: FuncSig) -> None:
|
|
389
|
+
SYMINFO_FUNCTIONS[short_name] = _func(f"syminfo.{short_name}", *sigs)
|
|
390
|
+
|
|
391
|
+
_syminfo_fn("prefix", _sig([], ret=S))
|
|
392
|
+
_syminfo_fn("ticker", _sig([], ret=S))
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
# ============================================================================
|
|
396
|
+
# Standalone built-in functions (no namespace)
|
|
397
|
+
# ============================================================================
|
|
398
|
+
|
|
399
|
+
BUILTIN_FUNCTIONS: dict[str, IntrinsicFunc] = {}
|
|
400
|
+
|
|
401
|
+
def _builtin(name: str, *sigs: FuncSig) -> None:
|
|
402
|
+
BUILTIN_FUNCTIONS[name] = _func(name, *sigs)
|
|
403
|
+
|
|
404
|
+
_builtin("na", _sig([("x", F)], ret=B))
|
|
405
|
+
_builtin("nz",
|
|
406
|
+
_sig([("x", F)], ret=F),
|
|
407
|
+
_sig([("x", F), ("y", F)], ret=F))
|
|
408
|
+
_builtin("fixnan", _sig([("x", F)], ret=F))
|
|
409
|
+
_builtin("timestamp",
|
|
410
|
+
_sig([("year", I), ("month", I), ("day", I),
|
|
411
|
+
("hour", I, 0), ("minute", I, 0), ("second", I, 0)], ret=I))
|
|
412
|
+
_builtin("time",
|
|
413
|
+
_sig([("timeframe", S), ("session", S), ("timezone", S, "")], ret=I),
|
|
414
|
+
_sig([("timeframe", S)], ret=I))
|
|
415
|
+
_builtin("time_close",
|
|
416
|
+
_sig([("timeframe", S), ("session", S), ("timezone", S, "")], ret=I),
|
|
417
|
+
_sig([("timeframe", S)], ret=I))
|
|
418
|
+
_builtin("year", _sig([("time", I, None), ("timezone", S, "")], ret=I))
|
|
419
|
+
_builtin("month", _sig([("time", I, None), ("timezone", S, "")], ret=I))
|
|
420
|
+
_builtin("dayofmonth", _sig([("time", I, None), ("timezone", S, "")], ret=I))
|
|
421
|
+
_builtin("dayofweek", _sig([("time", I, None), ("timezone", S, "")], ret=I))
|
|
422
|
+
_builtin("hour", _sig([("time", I, None), ("timezone", S, "")], ret=I))
|
|
423
|
+
_builtin("minute", _sig([("time", I, None), ("timezone", S, "")], ret=I))
|
|
424
|
+
_builtin("second", _sig([("time", I, None), ("timezone", S, "")], ret=I))
|
|
425
|
+
_builtin("weekofyear", _sig([("time", I, None), ("timezone", S, "")], ret=I))
|
|
426
|
+
_builtin("max_bars_back", _sig([("var", F), ("num", I)], ret=VOID))
|
|
427
|
+
|
|
428
|
+
# Type casts
|
|
429
|
+
_builtin("int", _sig([("x", F)], ret=I))
|
|
430
|
+
_builtin("float", _sig([("x", I)], ret=F))
|
|
431
|
+
_builtin("bool", _sig([("x", F)], ret=B))
|
|
432
|
+
_builtin("string", _sig([("x", F)], ret=S))
|
|
433
|
+
|
|
434
|
+
# Timeframe
|
|
435
|
+
_builtin("timeframe.change", _sig([("timeframe", S)], ret=B))
|
|
436
|
+
_builtin("timeframe.in_seconds", _sig([("timeframe", S)], ret=F))
|
|
437
|
+
|
|
438
|
+
# Plain input() — overloaded on type of defval (PineScript v6)
|
|
439
|
+
_builtin("input",
|
|
440
|
+
_sig([("defval", F), ("title", S, "")], ret=F),
|
|
441
|
+
_sig([("defval", I), ("title", S, "")], ret=I),
|
|
442
|
+
_sig([("defval", B), ("title", S, "")], ret=B),
|
|
443
|
+
_sig([("defval", S), ("title", S, "")], ret=S))
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
# ============================================================================
|
|
447
|
+
# input.* functions
|
|
448
|
+
# ============================================================================
|
|
449
|
+
|
|
450
|
+
INPUT_FUNCTIONS: dict[str, IntrinsicFunc] = {}
|
|
451
|
+
|
|
452
|
+
def _input(short_name: str, *sigs: FuncSig) -> None:
|
|
453
|
+
INPUT_FUNCTIONS[short_name] = _func(f"input.{short_name}", *sigs)
|
|
454
|
+
|
|
455
|
+
# Common trailing: tooltip, inline, group, display (plot_display), confirm
|
|
456
|
+
_C = [("tooltip", S, None), ("inline", S, None), ("group", S, None),
|
|
457
|
+
("display", I, None), ("confirm", B, None)]
|
|
458
|
+
|
|
459
|
+
_input("int", _sig([("defval", I), ("title", S, ""), ("minval", I, None),
|
|
460
|
+
("maxval", I, None), ("step", I, 1)] + _C, ret=I))
|
|
461
|
+
_input("float", _sig([("defval", F), ("title", S, ""), ("minval", F, None),
|
|
462
|
+
("maxval", F, None), ("step", F, None)] + _C, ret=F))
|
|
463
|
+
_input("bool", _sig([("defval", B), ("title", S, "")] + _C, ret=B))
|
|
464
|
+
_input("string", _sig([("defval", S), ("title", S, ""), ("options", S, None)] + _C, ret=S))
|
|
465
|
+
_input("source", _sig([("defval", F), ("title", S, "")] + _C, ret=F))
|
|
466
|
+
_input("color", _sig([("defval", I), ("title", S, "")] + _C, ret=I))
|
|
467
|
+
_input("timeframe", _sig([("defval", S, ""), ("title", S, "")] + _C, ret=S))
|
|
468
|
+
_input("session", _sig([("defval", S, ""), ("title", S, "")] + _C, ret=S))
|
|
469
|
+
_input("symbol", _sig([("defval", S, ""), ("title", S, "")] + _C, ret=S))
|
|
470
|
+
_input("price", _sig([("defval", F), ("title", S, "")] + _C, ret=F))
|
|
471
|
+
_input("time", _sig([("defval", I), ("title", S, "")] + _C, ret=I))
|
|
472
|
+
_input("text_area", _sig([("defval", S), ("title", S, "")] + _C, ret=S))
|
|
473
|
+
# defval is an enum member (typed as float in Pine's overloads; value is int index)
|
|
474
|
+
_input("enum", _sig([("defval", F), ("title", S, "")] + _C, ret=I))
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
# ============================================================================
|
|
478
|
+
# Math constants
|
|
479
|
+
# ============================================================================
|
|
480
|
+
|
|
481
|
+
MATH_CONSTANTS = {
|
|
482
|
+
"pi": 3.141592653589793,
|
|
483
|
+
"e": 2.718281828459045,
|
|
484
|
+
"phi": 1.618033988749895,
|
|
485
|
+
"rphi": 0.6180339887498949,
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
# ============================================================================
|
|
490
|
+
# Built-in variables (not functions)
|
|
491
|
+
# ============================================================================
|
|
492
|
+
|
|
493
|
+
BUILTIN_VARIABLES: dict[str, PineType] = {
|
|
494
|
+
# Price series
|
|
495
|
+
"open": F, "high": F, "low": F, "close": F, "volume": F,
|
|
496
|
+
# Derived price
|
|
497
|
+
"hl2": F, "hlc3": F, "hlcc4": F, "ohlc4": F,
|
|
498
|
+
# Bar info
|
|
499
|
+
"bar_index": I, "time": I, "time_close": I,
|
|
500
|
+
"last_bar_index": I, "last_bar_time": I, "timenow": I, "time_tradingday": I,
|
|
501
|
+
# Time/date (when used as variables, NOT function calls)
|
|
502
|
+
"hour": I, "minute": I, "second": I,
|
|
503
|
+
"dayofmonth": I, "dayofweek": I,
|
|
504
|
+
"month": I, "year": I, "weekofyear": I,
|
|
505
|
+
# Special
|
|
506
|
+
"na": NA,
|
|
507
|
+
# ta.tr as a variable
|
|
508
|
+
"ta.tr": F,
|
|
509
|
+
# Official no-call ta.* series variables.
|
|
510
|
+
"ta.obv": F, "ta.accdist": F, "ta.nvi": F, "ta.pvi": F,
|
|
511
|
+
"ta.pvt": F, "ta.wad": F, "ta.wvad": F, "ta.iii": F,
|
|
512
|
+
# chart.is_* chart-type predicates (batch engine is always standard chart)
|
|
513
|
+
"chart.is_standard": B,
|
|
514
|
+
"chart.is_heikinashi": B,
|
|
515
|
+
"chart.is_kagi": B,
|
|
516
|
+
"chart.is_linebreak": B,
|
|
517
|
+
"chart.is_pnf": B,
|
|
518
|
+
"chart.is_range": B,
|
|
519
|
+
"chart.is_renko": B,
|
|
520
|
+
# Session predicates (Pine v6 HIGH — backed by pine_session_is* engine fns)
|
|
521
|
+
"session.ismarket": B, "session.ispremarket": B, "session.ispostmarket": B,
|
|
522
|
+
"session.isfirstbar": B, "session.isfirstbar_regular": B,
|
|
523
|
+
"session.islastbar": B, "session.islastbar_regular": B,
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
# Strategy variables (read-only properties, not function calls)
|
|
527
|
+
STRATEGY_VARIABLES: dict[str, PineType] = {
|
|
528
|
+
"strategy.position_size": F,
|
|
529
|
+
"strategy.position_avg_price": F,
|
|
530
|
+
"strategy.position_entry_name": S,
|
|
531
|
+
"strategy.equity": F,
|
|
532
|
+
"strategy.initial_capital": F,
|
|
533
|
+
"strategy.netprofit": F,
|
|
534
|
+
"strategy.netprofit_percent": F,
|
|
535
|
+
"strategy.openprofit": F,
|
|
536
|
+
"strategy.openprofit_percent": F,
|
|
537
|
+
"strategy.grossprofit": F,
|
|
538
|
+
"strategy.grossloss": F,
|
|
539
|
+
"strategy.closedtrades": I,
|
|
540
|
+
"strategy.opentrades": I,
|
|
541
|
+
"strategy.wintrades": I,
|
|
542
|
+
"strategy.losstrades": I,
|
|
543
|
+
"strategy.eventrades": I,
|
|
544
|
+
"strategy.max_contracts_held_all": F,
|
|
545
|
+
"strategy.max_contracts_held_long": F,
|
|
546
|
+
"strategy.max_contracts_held_short": F,
|
|
547
|
+
"strategy.max_drawdown": F,
|
|
548
|
+
"strategy.max_drawdown_percent": F,
|
|
549
|
+
"strategy.max_runup": F,
|
|
550
|
+
"strategy.max_runup_percent": F,
|
|
551
|
+
"strategy.avg_trade": F,
|
|
552
|
+
"strategy.avg_trade_percent": F,
|
|
553
|
+
"strategy.avg_winning_trade": F,
|
|
554
|
+
"strategy.avg_losing_trade": F,
|
|
555
|
+
"strategy.avg_winning_trade_percent": F,
|
|
556
|
+
"strategy.avg_losing_trade_percent": F,
|
|
557
|
+
"strategy.margin_liquidation_price": F,
|
|
558
|
+
"strategy.grossprofit_percent": F,
|
|
559
|
+
"strategy.grossloss_percent": F,
|
|
560
|
+
"strategy.account_currency": S,
|
|
561
|
+
"strategy.opentrades.capital_held": F,
|
|
562
|
+
# Direction constants
|
|
563
|
+
"strategy.long": B,
|
|
564
|
+
"strategy.short": B,
|
|
565
|
+
# Qty type constants
|
|
566
|
+
"strategy.fixed": I,
|
|
567
|
+
"strategy.cash": I,
|
|
568
|
+
"strategy.percent_of_equity": I,
|
|
569
|
+
# Commission type constants
|
|
570
|
+
"strategy.commission.percent": I,
|
|
571
|
+
"strategy.commission.cash_per_contract": I,
|
|
572
|
+
"strategy.commission.cash_per_order": I,
|
|
573
|
+
# OCA constants
|
|
574
|
+
"strategy.oca.cancel": I,
|
|
575
|
+
"strategy.oca.reduce": I,
|
|
576
|
+
"strategy.oca.none": I,
|
|
577
|
+
# Direction constants
|
|
578
|
+
"strategy.direction.all": I,
|
|
579
|
+
"strategy.direction.long": I,
|
|
580
|
+
"strategy.direction.short": I,
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
# Barstate variables
|
|
584
|
+
BARSTATE_VARIABLES: dict[str, PineType] = {
|
|
585
|
+
"barstate.isfirst": B,
|
|
586
|
+
"barstate.islast": B,
|
|
587
|
+
"barstate.ishistory": B,
|
|
588
|
+
"barstate.isrealtime": B,
|
|
589
|
+
"barstate.isnew": B,
|
|
590
|
+
"barstate.isconfirmed": B,
|
|
591
|
+
"barstate.islastconfirmedhistory": B,
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
# Syminfo variables
|
|
595
|
+
SYMINFO_VARIABLES: dict[str, PineType] = {
|
|
596
|
+
"syminfo.ticker": S,
|
|
597
|
+
"syminfo.tickerid": S,
|
|
598
|
+
"syminfo.basecurrency": S,
|
|
599
|
+
"syminfo.currency": S,
|
|
600
|
+
"syminfo.description": S,
|
|
601
|
+
"syminfo.mintick": F,
|
|
602
|
+
"syminfo.pointvalue": F,
|
|
603
|
+
"syminfo.type": S,
|
|
604
|
+
"syminfo.timezone": S,
|
|
605
|
+
"syminfo.session": S,
|
|
606
|
+
"syminfo.volumetype": S,
|
|
607
|
+
# --- Critical fix: were silently emitting 0; now na-accept ---
|
|
608
|
+
"syminfo.prefix": S,
|
|
609
|
+
"syminfo.root": S,
|
|
610
|
+
"syminfo.pricescale": F,
|
|
611
|
+
"syminfo.minmove": F,
|
|
612
|
+
# --- External-data fields: na-accept so scripts compile ---
|
|
613
|
+
"syminfo.mincontract": F,
|
|
614
|
+
"syminfo.current_contract": S,
|
|
615
|
+
"syminfo.expiration_date": I,
|
|
616
|
+
"syminfo.isin": S,
|
|
617
|
+
"syminfo.sector": S,
|
|
618
|
+
"syminfo.industry": S,
|
|
619
|
+
# --- LOW-tier na-accepts: financial/fundamental data ---
|
|
620
|
+
"syminfo.employees": F,
|
|
621
|
+
"syminfo.shareholders": F,
|
|
622
|
+
"syminfo.shares_outstanding_float": F,
|
|
623
|
+
"syminfo.shares_outstanding_total": F,
|
|
624
|
+
"syminfo.recommendations_buy": F,
|
|
625
|
+
"syminfo.recommendations_strong_buy": F,
|
|
626
|
+
"syminfo.recommendations_hold": F,
|
|
627
|
+
"syminfo.recommendations_sell": F,
|
|
628
|
+
"syminfo.recommendations_strong_sell": F,
|
|
629
|
+
"syminfo.recommendations_total": F,
|
|
630
|
+
"syminfo.recommendations_date": F,
|
|
631
|
+
"syminfo.target_price_average": F,
|
|
632
|
+
"syminfo.target_price_high": F,
|
|
633
|
+
"syminfo.target_price_low": F,
|
|
634
|
+
"syminfo.target_price_median": F,
|
|
635
|
+
"syminfo.target_price_date": F,
|
|
636
|
+
"syminfo.target_price_analysts_count": F,
|
|
637
|
+
# --- Syminfo derivations ---
|
|
638
|
+
"syminfo.main_tickerid": S,
|
|
639
|
+
"syminfo.country": S,
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
# Timeframe variables
|
|
643
|
+
TIMEFRAME_VARIABLES: dict[str, PineType] = {
|
|
644
|
+
"timeframe.period": S,
|
|
645
|
+
"timeframe.multiplier": I,
|
|
646
|
+
"timeframe.isintraday": B,
|
|
647
|
+
"timeframe.isdaily": B,
|
|
648
|
+
"timeframe.isweekly": B,
|
|
649
|
+
"timeframe.ismonthly": B,
|
|
650
|
+
"timeframe.isdwm": B,
|
|
651
|
+
"timeframe.main_period": S,
|
|
652
|
+
"timeframe.isticks": B,
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
# display.* plot_display constants (PineScript v6 — values for C++ codegen)
|
|
656
|
+
DISPLAY_VARIABLES: dict[str, PineType] = {
|
|
657
|
+
"display.all": I,
|
|
658
|
+
"display.none": I,
|
|
659
|
+
"display.pane": I,
|
|
660
|
+
"display.data_window": I,
|
|
661
|
+
"display.status_line": I,
|
|
662
|
+
"display.price_scale": I,
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
# ============================================================================
|
|
669
|
+
# TA functions that have implicit default source (1-arg overload)
|
|
670
|
+
# When called with fewer args than the primary signature, the source
|
|
671
|
+
# is implicitly `high` (for highest/pivothigh) or `low` (for lowest/pivotlow).
|
|
672
|
+
# ============================================================================
|
|
673
|
+
|
|
674
|
+
TA_DEFAULT_SOURCE = {
|
|
675
|
+
"highest": "high",
|
|
676
|
+
"lowest": "low",
|
|
677
|
+
"pivothigh": "high",
|
|
678
|
+
"pivotlow": "low",
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
# ============================================================================
|
|
683
|
+
# Lookup helpers
|
|
684
|
+
# ============================================================================
|
|
685
|
+
|
|
686
|
+
def resolve_overload(func: IntrinsicFunc, num_args: int) -> FuncSig:
|
|
687
|
+
"""Pick the best matching overload for a given argument count."""
|
|
688
|
+
# Try exact match first
|
|
689
|
+
for sig in func.signatures:
|
|
690
|
+
required = sum(1 for p in sig.params if p.default is None)
|
|
691
|
+
total = len(sig.params)
|
|
692
|
+
if required <= num_args <= total:
|
|
693
|
+
return sig
|
|
694
|
+
# Fallback to primary
|
|
695
|
+
return func.primary
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
def merge_kwargs_to_positional(
|
|
699
|
+
sig: FuncSig,
|
|
700
|
+
args: list,
|
|
701
|
+
kwargs: dict,
|
|
702
|
+
) -> list:
|
|
703
|
+
"""Merge positional args and kwargs into a unified positional arg list
|
|
704
|
+
using the function signature's parameter names.
|
|
705
|
+
|
|
706
|
+
Returns a list of AST nodes in positional order.
|
|
707
|
+
"""
|
|
708
|
+
merged = list(args)
|
|
709
|
+
for i, param in enumerate(sig.params):
|
|
710
|
+
if param.name in kwargs:
|
|
711
|
+
while len(merged) <= i:
|
|
712
|
+
merged.append(None)
|
|
713
|
+
if i >= len(args) or merged[i] is None:
|
|
714
|
+
merged[i] = kwargs[param.name]
|
|
715
|
+
# Trim trailing Nones
|
|
716
|
+
while merged and merged[-1] is None:
|
|
717
|
+
merged.pop()
|
|
718
|
+
return merged
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
def get_param_names(namespace: str | None, func_name: str) -> list[str] | None:
|
|
722
|
+
"""Get parameter names for a function (for kwargs resolution).
|
|
723
|
+
|
|
724
|
+
Returns None if the function is not a known intrinsic.
|
|
725
|
+
"""
|
|
726
|
+
if namespace == "ta" and func_name in TA_FUNCTIONS:
|
|
727
|
+
return TA_FUNCTIONS[func_name].param_names
|
|
728
|
+
if namespace == "math" and func_name in MATH_FUNCTIONS:
|
|
729
|
+
return MATH_FUNCTIONS[func_name].param_names
|
|
730
|
+
if namespace == "strategy" and func_name in STRATEGY_FUNCTIONS:
|
|
731
|
+
return STRATEGY_FUNCTIONS[func_name].param_names
|
|
732
|
+
if namespace == "str" and func_name in STR_FUNCTIONS:
|
|
733
|
+
return STR_FUNCTIONS[func_name].param_names
|
|
734
|
+
if namespace == "input" and func_name in INPUT_FUNCTIONS:
|
|
735
|
+
return INPUT_FUNCTIONS[func_name].param_names
|
|
736
|
+
if namespace == "map" and func_name in MAP_FUNCTIONS:
|
|
737
|
+
return MAP_FUNCTIONS[func_name].param_names
|
|
738
|
+
if namespace == "syminfo" and func_name in SYMINFO_FUNCTIONS:
|
|
739
|
+
return SYMINFO_FUNCTIONS[func_name].param_names
|
|
740
|
+
if namespace is None and func_name in BUILTIN_FUNCTIONS:
|
|
741
|
+
return BUILTIN_FUNCTIONS[func_name].param_names
|
|
742
|
+
return None
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
def get_return_type(namespace: str | None, func_name: str,
|
|
746
|
+
num_args: int = 0) -> PineType:
|
|
747
|
+
"""Get return type for a function call."""
|
|
748
|
+
func = None
|
|
749
|
+
if namespace == "ta":
|
|
750
|
+
func = TA_FUNCTIONS.get(func_name)
|
|
751
|
+
elif namespace == "math":
|
|
752
|
+
func = MATH_FUNCTIONS.get(func_name)
|
|
753
|
+
elif namespace == "strategy":
|
|
754
|
+
func = STRATEGY_FUNCTIONS.get(func_name)
|
|
755
|
+
elif namespace == "str":
|
|
756
|
+
func = STR_FUNCTIONS.get(func_name)
|
|
757
|
+
elif namespace == "input":
|
|
758
|
+
func = INPUT_FUNCTIONS.get(func_name)
|
|
759
|
+
elif namespace == "map":
|
|
760
|
+
func = MAP_FUNCTIONS.get(func_name)
|
|
761
|
+
elif namespace == "syminfo":
|
|
762
|
+
func = SYMINFO_FUNCTIONS.get(func_name)
|
|
763
|
+
elif namespace is None:
|
|
764
|
+
func = BUILTIN_FUNCTIONS.get(func_name)
|
|
765
|
+
|
|
766
|
+
if func is None:
|
|
767
|
+
return PineType.UNKNOWN
|
|
768
|
+
sig = resolve_overload(func, num_args)
|
|
769
|
+
return sig.return_type
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
def is_intrinsic_function(namespace: str | None, func_name: str) -> bool:
|
|
773
|
+
"""Check if a function is a known TradingView intrinsic."""
|
|
774
|
+
if namespace == "ta":
|
|
775
|
+
return func_name in TA_FUNCTIONS
|
|
776
|
+
if namespace == "math":
|
|
777
|
+
return func_name in MATH_FUNCTIONS
|
|
778
|
+
if namespace == "strategy":
|
|
779
|
+
return func_name in STRATEGY_FUNCTIONS
|
|
780
|
+
if namespace == "str":
|
|
781
|
+
return func_name in STR_FUNCTIONS
|
|
782
|
+
if namespace == "input":
|
|
783
|
+
return func_name in INPUT_FUNCTIONS
|
|
784
|
+
if namespace == "map":
|
|
785
|
+
return func_name in MAP_FUNCTIONS
|
|
786
|
+
if namespace == "syminfo":
|
|
787
|
+
return func_name in SYMINFO_FUNCTIONS
|
|
788
|
+
if namespace is None:
|
|
789
|
+
return func_name in BUILTIN_FUNCTIONS
|
|
790
|
+
return False
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
def is_intrinsic_variable(namespace: str | None, name: str) -> bool:
|
|
794
|
+
"""Check if a name is a known TradingView built-in variable."""
|
|
795
|
+
if namespace is None:
|
|
796
|
+
return name in BUILTIN_VARIABLES
|
|
797
|
+
full = f"{namespace}.{name}"
|
|
798
|
+
if (full in STRATEGY_VARIABLES
|
|
799
|
+
or full in BARSTATE_VARIABLES
|
|
800
|
+
or full in SYMINFO_VARIABLES
|
|
801
|
+
or full in TIMEFRAME_VARIABLES
|
|
802
|
+
or full in BUILTIN_VARIABLES
|
|
803
|
+
or full in DISPLAY_VARIABLES):
|
|
804
|
+
return True
|
|
805
|
+
# e.g. strategy + "opentrades.capital_held" -> strategy.opentrades.capital_held
|
|
806
|
+
if namespace == "strategy" and "." in name:
|
|
807
|
+
return f"strategy.{name}" in STRATEGY_VARIABLES
|
|
808
|
+
return False
|