pinets 0.1.0
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.
- package/LICENSE +661 -0
- package/README.md +158 -0
- package/dist/pinets.dev.cjs +10125 -0
- package/dist/pinets.dev.cjs.map +1 -0
- package/dist/pinets.dev.es.js +2338 -0
- package/dist/pinets.dev.es.js.map +1 -0
- package/dist/pinets.min.browser.js +33 -0
- package/dist/pinets.min.cjs +32 -0
- package/dist/pinets.min.es.js +19 -0
- package/dist/types/Context.class.d.ts +48 -0
- package/dist/types/PineTS.class.d.ts +33 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/marketData/Binance/BinanceProvider.class.d.ts +4 -0
- package/dist/types/marketData/IProvider.d.ts +3 -0
- package/dist/types/marketData/Provider.class.d.ts +4 -0
- package/dist/types/namespaces/Core.d.ts +20 -0
- package/dist/types/namespaces/Input.d.ts +24 -0
- package/dist/types/namespaces/PineMath.d.ts +26 -0
- package/dist/types/namespaces/PineRequest.d.ts +7 -0
- package/dist/types/namespaces/Syminfo.d.ts +0 -0
- package/dist/types/namespaces/TechnicalAnalysis.d.ts +26 -0
- package/dist/types/transpiler/ScopeManager.class.d.ts +31 -0
- package/dist/types/transpiler/index.d.ts +1 -0
- package/dist/types/types/PineTypes.d.ts +48 -0
- package/package.json +48 -0
|
@@ -0,0 +1,2338 @@
|
|
|
1
|
+
import * as acorn from 'acorn';
|
|
2
|
+
import * as walk from 'acorn-walk';
|
|
3
|
+
import * as astring from 'astring';
|
|
4
|
+
|
|
5
|
+
var __defProp$5 = Object.defineProperty;
|
|
6
|
+
var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
|
+
var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
8
|
+
class ScopeManager {
|
|
9
|
+
constructor() {
|
|
10
|
+
__publicField$5(this, "scopes", []);
|
|
11
|
+
__publicField$5(this, "scopeTypes", []);
|
|
12
|
+
__publicField$5(this, "scopeCounts", /* @__PURE__ */ new Map());
|
|
13
|
+
__publicField$5(this, "contextBoundVars", /* @__PURE__ */ new Set());
|
|
14
|
+
__publicField$5(this, "arrayPatternElements", /* @__PURE__ */ new Set());
|
|
15
|
+
__publicField$5(this, "rootParams", /* @__PURE__ */ new Set());
|
|
16
|
+
__publicField$5(this, "varKinds", /* @__PURE__ */ new Map());
|
|
17
|
+
__publicField$5(this, "loopVars", /* @__PURE__ */ new Set());
|
|
18
|
+
__publicField$5(this, "loopVarNames", /* @__PURE__ */ new Map());
|
|
19
|
+
// Map original names to transformed names
|
|
20
|
+
__publicField$5(this, "paramIdCounter", 0);
|
|
21
|
+
__publicField$5(this, "tempVarCounter", 0);
|
|
22
|
+
this.pushScope("glb");
|
|
23
|
+
}
|
|
24
|
+
get nextParamIdArg() {
|
|
25
|
+
return {
|
|
26
|
+
type: "Identifier",
|
|
27
|
+
name: `'p${this.paramIdCounter++}'`
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
pushScope(type) {
|
|
31
|
+
this.scopes.push(/* @__PURE__ */ new Map());
|
|
32
|
+
this.scopeTypes.push(type);
|
|
33
|
+
this.scopeCounts.set(type, (this.scopeCounts.get(type) || 0) + 1);
|
|
34
|
+
}
|
|
35
|
+
popScope() {
|
|
36
|
+
this.scopes.pop();
|
|
37
|
+
this.scopeTypes.pop();
|
|
38
|
+
}
|
|
39
|
+
getCurrentScopeType() {
|
|
40
|
+
return this.scopeTypes[this.scopeTypes.length - 1];
|
|
41
|
+
}
|
|
42
|
+
getCurrentScopeCount() {
|
|
43
|
+
return this.scopeCounts.get(this.getCurrentScopeType()) || 1;
|
|
44
|
+
}
|
|
45
|
+
addContextBoundVar(name, isRootParam = false) {
|
|
46
|
+
this.contextBoundVars.add(name);
|
|
47
|
+
if (isRootParam) {
|
|
48
|
+
this.rootParams.add(name);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
addArrayPatternElement(name) {
|
|
52
|
+
this.arrayPatternElements.add(name);
|
|
53
|
+
}
|
|
54
|
+
isContextBound(name) {
|
|
55
|
+
return this.contextBoundVars.has(name);
|
|
56
|
+
}
|
|
57
|
+
isArrayPatternElement(name) {
|
|
58
|
+
return this.arrayPatternElements.has(name);
|
|
59
|
+
}
|
|
60
|
+
isRootParam(name) {
|
|
61
|
+
return this.rootParams.has(name);
|
|
62
|
+
}
|
|
63
|
+
addLoopVariable(originalName, transformedName) {
|
|
64
|
+
this.loopVars.add(originalName);
|
|
65
|
+
this.loopVarNames.set(originalName, transformedName);
|
|
66
|
+
}
|
|
67
|
+
getLoopVariableName(name) {
|
|
68
|
+
return this.loopVarNames.get(name);
|
|
69
|
+
}
|
|
70
|
+
isLoopVariable(name) {
|
|
71
|
+
return this.loopVars.has(name);
|
|
72
|
+
}
|
|
73
|
+
addVariable(name, kind) {
|
|
74
|
+
if (this.isContextBound(name)) {
|
|
75
|
+
return name;
|
|
76
|
+
}
|
|
77
|
+
const currentScope = this.scopes[this.scopes.length - 1];
|
|
78
|
+
const scopeType = this.scopeTypes[this.scopeTypes.length - 1];
|
|
79
|
+
const scopeCount = this.scopeCounts.get(scopeType) || 1;
|
|
80
|
+
const newName = `${scopeType}${scopeCount}_${name}`;
|
|
81
|
+
currentScope.set(name, newName);
|
|
82
|
+
this.varKinds.set(newName, kind);
|
|
83
|
+
return newName;
|
|
84
|
+
}
|
|
85
|
+
getVariable(name) {
|
|
86
|
+
if (this.loopVars.has(name)) {
|
|
87
|
+
const transformedName = this.loopVarNames.get(name);
|
|
88
|
+
if (transformedName) {
|
|
89
|
+
return [transformedName, "let"];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (this.isContextBound(name)) {
|
|
93
|
+
return [name, "let"];
|
|
94
|
+
}
|
|
95
|
+
for (let i = this.scopes.length - 1; i >= 0; i--) {
|
|
96
|
+
const scope = this.scopes[i];
|
|
97
|
+
if (scope.has(name)) {
|
|
98
|
+
const scopedName = scope.get(name);
|
|
99
|
+
const kind = this.varKinds.get(scopedName) || "let";
|
|
100
|
+
return [scopedName, kind];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return [name, "let"];
|
|
104
|
+
}
|
|
105
|
+
generateTempVar() {
|
|
106
|
+
return `temp_${++this.tempVarCounter}`;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
//!!!Warning!!! this code is not clean, it was initially written as a PoC then used as transpiler for PineTS
|
|
111
|
+
const CONTEXT_NAME = "$";
|
|
112
|
+
const UNDEFINED_ARG = {
|
|
113
|
+
type: "Identifier",
|
|
114
|
+
name: "undefined"
|
|
115
|
+
};
|
|
116
|
+
function transformArrayIndex(node, scopeManager) {
|
|
117
|
+
if (node.computed && node.property.type === "Identifier") {
|
|
118
|
+
if (scopeManager.isLoopVariable(node.property.name)) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (!scopeManager.isContextBound(node.property.name)) {
|
|
122
|
+
const [scopedName, kind] = scopeManager.getVariable(node.property.name);
|
|
123
|
+
node.property = {
|
|
124
|
+
type: "MemberExpression",
|
|
125
|
+
object: {
|
|
126
|
+
type: "MemberExpression",
|
|
127
|
+
object: {
|
|
128
|
+
type: "Identifier",
|
|
129
|
+
name: CONTEXT_NAME
|
|
130
|
+
},
|
|
131
|
+
property: {
|
|
132
|
+
type: "Identifier",
|
|
133
|
+
name: kind
|
|
134
|
+
},
|
|
135
|
+
computed: false
|
|
136
|
+
},
|
|
137
|
+
property: {
|
|
138
|
+
type: "Identifier",
|
|
139
|
+
name: scopedName
|
|
140
|
+
},
|
|
141
|
+
computed: false
|
|
142
|
+
};
|
|
143
|
+
node.property = {
|
|
144
|
+
type: "MemberExpression",
|
|
145
|
+
object: node.property,
|
|
146
|
+
property: {
|
|
147
|
+
type: "Literal",
|
|
148
|
+
value: 0
|
|
149
|
+
},
|
|
150
|
+
computed: true
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (node.computed && node.object.type === "Identifier") {
|
|
155
|
+
if (scopeManager.isLoopVariable(node.object.name)) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (!scopeManager.isContextBound(node.object.name)) {
|
|
159
|
+
const [scopedName, kind] = scopeManager.getVariable(node.object.name);
|
|
160
|
+
node.object = {
|
|
161
|
+
type: "MemberExpression",
|
|
162
|
+
object: {
|
|
163
|
+
type: "MemberExpression",
|
|
164
|
+
object: {
|
|
165
|
+
type: "Identifier",
|
|
166
|
+
name: CONTEXT_NAME
|
|
167
|
+
},
|
|
168
|
+
property: {
|
|
169
|
+
type: "Identifier",
|
|
170
|
+
name: kind
|
|
171
|
+
},
|
|
172
|
+
computed: false
|
|
173
|
+
},
|
|
174
|
+
property: {
|
|
175
|
+
type: "Identifier",
|
|
176
|
+
name: scopedName
|
|
177
|
+
},
|
|
178
|
+
computed: false
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
if (node.property.type === "MemberExpression") {
|
|
182
|
+
const memberNode = node.property;
|
|
183
|
+
if (!memberNode._indexTransformed) {
|
|
184
|
+
transformArrayIndex(memberNode, scopeManager);
|
|
185
|
+
memberNode._indexTransformed = true;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function transformMemberExpression(memberNode, originalParamName, scopeManager) {
|
|
191
|
+
if (memberNode.object && memberNode.object.type === "Identifier" && memberNode.object.name === "Math") {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const isIfStatement = scopeManager.getCurrentScopeType() == "if";
|
|
195
|
+
const isElseStatement = scopeManager.getCurrentScopeType() == "els";
|
|
196
|
+
const isForStatement = scopeManager.getCurrentScopeType() == "for";
|
|
197
|
+
if (!isIfStatement && !isElseStatement && !isForStatement && memberNode.object && memberNode.object.type === "Identifier" && scopeManager.isContextBound(memberNode.object.name) && !scopeManager.isRootParam(memberNode.object.name)) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (!memberNode._indexTransformed) {
|
|
201
|
+
transformArrayIndex(memberNode, scopeManager);
|
|
202
|
+
memberNode._indexTransformed = true;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function transformVariableDeclaration(varNode, scopeManager) {
|
|
206
|
+
varNode.declarations.forEach((decl) => {
|
|
207
|
+
const isContextProperty = decl.init && decl.init.type === "MemberExpression" && decl.init.object && (decl.init.object.name === "context" || decl.init.object.name === CONTEXT_NAME || decl.init.object.name === "context2");
|
|
208
|
+
const isSubContextProperty = decl.init && decl.init.type === "MemberExpression" && decl.init.object?.object && (decl.init.object.object.name === "context" || decl.init.object.object.name === CONTEXT_NAME || decl.init.object.object.name === "context2");
|
|
209
|
+
const isArrowFunction = decl.init && decl.init.type === "ArrowFunctionExpression";
|
|
210
|
+
if (isContextProperty) {
|
|
211
|
+
if (decl.id.name) {
|
|
212
|
+
scopeManager.addContextBoundVar(decl.id.name);
|
|
213
|
+
}
|
|
214
|
+
if (decl.id.properties) {
|
|
215
|
+
decl.id.properties.forEach((property) => {
|
|
216
|
+
if (property.key.name) {
|
|
217
|
+
scopeManager.addContextBoundVar(property.key.name);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
decl.init.object.name = CONTEXT_NAME;
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (isSubContextProperty) {
|
|
225
|
+
if (decl.id.name) {
|
|
226
|
+
scopeManager.addContextBoundVar(decl.id.name);
|
|
227
|
+
}
|
|
228
|
+
if (decl.id.properties) {
|
|
229
|
+
decl.id.properties.forEach((property) => {
|
|
230
|
+
if (property.key.name) {
|
|
231
|
+
scopeManager.addContextBoundVar(property.key.name);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
decl.init.object.object.name = CONTEXT_NAME;
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (isArrowFunction) {
|
|
239
|
+
decl.init.params.forEach((param) => {
|
|
240
|
+
if (param.type === "Identifier") {
|
|
241
|
+
scopeManager.addContextBoundVar(param.name);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
const newName = scopeManager.addVariable(decl.id.name, varNode.kind);
|
|
246
|
+
const kind = varNode.kind;
|
|
247
|
+
if (decl.init && !isArrowFunction) {
|
|
248
|
+
if (decl.init.type === "CallExpression" && decl.init.callee.type === "MemberExpression" && decl.init.callee.object && decl.init.callee.object.type === "Identifier" && scopeManager.isContextBound(decl.init.callee.object.name)) {
|
|
249
|
+
transformCallExpression(decl.init, scopeManager);
|
|
250
|
+
} else {
|
|
251
|
+
walk.recursive(
|
|
252
|
+
decl.init,
|
|
253
|
+
{ parent: decl.init },
|
|
254
|
+
{
|
|
255
|
+
Identifier(node, state) {
|
|
256
|
+
node.parent = state.parent;
|
|
257
|
+
transformIdentifier(node, scopeManager);
|
|
258
|
+
const isBinaryOperation = node.parent && node.parent.type === "BinaryExpression";
|
|
259
|
+
const isConditional = node.parent && node.parent.type === "ConditionalExpression";
|
|
260
|
+
if (node.type === "Identifier" && (isBinaryOperation || isConditional)) {
|
|
261
|
+
Object.assign(node, {
|
|
262
|
+
type: "MemberExpression",
|
|
263
|
+
object: {
|
|
264
|
+
type: "Identifier",
|
|
265
|
+
name: node.name
|
|
266
|
+
},
|
|
267
|
+
property: {
|
|
268
|
+
type: "Literal",
|
|
269
|
+
value: 0
|
|
270
|
+
},
|
|
271
|
+
computed: true
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
CallExpression(node, state, c) {
|
|
276
|
+
if (node.callee.type === "Identifier") {
|
|
277
|
+
node.callee.parent = node;
|
|
278
|
+
}
|
|
279
|
+
node.arguments.forEach((arg) => {
|
|
280
|
+
if (arg.type === "Identifier") {
|
|
281
|
+
arg.parent = node;
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
transformCallExpression(node, scopeManager);
|
|
285
|
+
node.arguments.forEach((arg) => c(arg, { parent: node }));
|
|
286
|
+
},
|
|
287
|
+
BinaryExpression(node, state, c) {
|
|
288
|
+
if (node.left.type === "Identifier") {
|
|
289
|
+
node.left.parent = node;
|
|
290
|
+
}
|
|
291
|
+
if (node.right.type === "Identifier") {
|
|
292
|
+
node.right.parent = node;
|
|
293
|
+
}
|
|
294
|
+
c(node.left, { parent: node });
|
|
295
|
+
c(node.right, { parent: node });
|
|
296
|
+
},
|
|
297
|
+
MemberExpression(node, state, c) {
|
|
298
|
+
if (node.object.type === "Identifier") {
|
|
299
|
+
node.object.parent = node;
|
|
300
|
+
}
|
|
301
|
+
if (node.property.type === "Identifier") {
|
|
302
|
+
node.property.parent = node;
|
|
303
|
+
}
|
|
304
|
+
transformArrayIndex(node, scopeManager);
|
|
305
|
+
if (node.object) {
|
|
306
|
+
c(node.object, { parent: node });
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const targetVarRef = {
|
|
314
|
+
type: "MemberExpression",
|
|
315
|
+
object: {
|
|
316
|
+
type: "MemberExpression",
|
|
317
|
+
object: {
|
|
318
|
+
type: "Identifier",
|
|
319
|
+
name: CONTEXT_NAME
|
|
320
|
+
},
|
|
321
|
+
property: {
|
|
322
|
+
type: "Identifier",
|
|
323
|
+
name: kind
|
|
324
|
+
},
|
|
325
|
+
computed: false
|
|
326
|
+
},
|
|
327
|
+
property: {
|
|
328
|
+
type: "Identifier",
|
|
329
|
+
name: newName
|
|
330
|
+
},
|
|
331
|
+
computed: false
|
|
332
|
+
};
|
|
333
|
+
const isArrayPatternVar = scopeManager.isArrayPatternElement(decl.id.name);
|
|
334
|
+
const isArrayInit = !isArrayPatternVar && decl.init && decl.init.type === "MemberExpression" && decl.init.computed && decl.init.property && (decl.init.property.type === "Literal" || decl.init.property.type === "MemberExpression");
|
|
335
|
+
if (decl.init?.property?.type === "MemberExpression") {
|
|
336
|
+
if (!decl.init.property._indexTransformed) {
|
|
337
|
+
transformArrayIndex(decl.init.property, scopeManager);
|
|
338
|
+
decl.init.property._indexTransformed = true;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
const assignmentExpr = {
|
|
342
|
+
type: "ExpressionStatement",
|
|
343
|
+
expression: {
|
|
344
|
+
type: "AssignmentExpression",
|
|
345
|
+
operator: "=",
|
|
346
|
+
left: targetVarRef,
|
|
347
|
+
right: decl.init ? isArrowFunction || isArrayPatternVar ? decl.init : {
|
|
348
|
+
type: "CallExpression",
|
|
349
|
+
callee: {
|
|
350
|
+
type: "MemberExpression",
|
|
351
|
+
object: {
|
|
352
|
+
type: "Identifier",
|
|
353
|
+
name: CONTEXT_NAME
|
|
354
|
+
},
|
|
355
|
+
property: {
|
|
356
|
+
type: "Identifier",
|
|
357
|
+
name: "init"
|
|
358
|
+
},
|
|
359
|
+
computed: false
|
|
360
|
+
},
|
|
361
|
+
arguments: isArrayInit ? [targetVarRef, decl.init.object, decl.init.property] : [targetVarRef, decl.init]
|
|
362
|
+
} : {
|
|
363
|
+
type: "Identifier",
|
|
364
|
+
name: "undefined"
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
if (isArrayPatternVar) {
|
|
369
|
+
assignmentExpr.expression.right.object.property.name += "?.[0]";
|
|
370
|
+
}
|
|
371
|
+
if (isArrowFunction) {
|
|
372
|
+
scopeManager.pushScope("fn");
|
|
373
|
+
walk.recursive(decl.init.body, scopeManager, {
|
|
374
|
+
BlockStatement(node, state, c) {
|
|
375
|
+
node.body.forEach((stmt) => c(stmt, state));
|
|
376
|
+
},
|
|
377
|
+
IfStatement(node, state, c) {
|
|
378
|
+
state.pushScope("if");
|
|
379
|
+
c(node.consequent, state);
|
|
380
|
+
if (node.alternate) {
|
|
381
|
+
state.pushScope("els");
|
|
382
|
+
c(node.alternate, state);
|
|
383
|
+
state.popScope();
|
|
384
|
+
}
|
|
385
|
+
state.popScope();
|
|
386
|
+
},
|
|
387
|
+
VariableDeclaration(node, state) {
|
|
388
|
+
transformVariableDeclaration(node, state);
|
|
389
|
+
},
|
|
390
|
+
Identifier(node, state) {
|
|
391
|
+
transformIdentifier(node, state);
|
|
392
|
+
},
|
|
393
|
+
AssignmentExpression(node, state) {
|
|
394
|
+
transformAssignmentExpression(node, state);
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
scopeManager.popScope();
|
|
398
|
+
}
|
|
399
|
+
Object.assign(varNode, assignmentExpr);
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
function transformIdentifier(node, scopeManager) {
|
|
403
|
+
if (node.name !== CONTEXT_NAME) {
|
|
404
|
+
if (node.name === "Math" || node.name === "NaN" || node.name === "undefined" || node.name === "Infinity" || node.name === "null" || node.name.startsWith("'") && node.name.endsWith("'") || node.name.startsWith('"') && node.name.endsWith('"') || node.name.startsWith("`") && node.name.endsWith("`")) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
if (scopeManager.isLoopVariable(node.name)) {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
if (scopeManager.isContextBound(node.name) && !scopeManager.isRootParam(node.name)) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
const isNamespaceMember = node.parent && node.parent.type === "MemberExpression" && node.parent.object === node && scopeManager.isContextBound(node.name);
|
|
414
|
+
const isParamCall = node.parent && node.parent.type === "CallExpression" && node.parent.callee && node.parent.callee.type === "MemberExpression" && node.parent.callee.property.name === "param";
|
|
415
|
+
node.parent && node.parent.type === "AssignmentExpression" && node.parent.left === node;
|
|
416
|
+
const isNamespaceFunctionArg = node.parent && node.parent.type === "CallExpression" && node.parent.callee && node.parent.callee.type === "MemberExpression" && scopeManager.isContextBound(node.parent.callee.object.name);
|
|
417
|
+
const isArrayAccess = node.parent && node.parent.type === "MemberExpression" && node.parent.computed;
|
|
418
|
+
const isArrayIndexInNamespaceCall = node.parent && node.parent.type === "MemberExpression" && node.parent.computed && node.parent.property === node && node.parent.parent && node.parent.parent.type === "CallExpression" && node.parent.parent.callee && node.parent.parent.callee.type === "MemberExpression" && scopeManager.isContextBound(node.parent.parent.callee.object.name);
|
|
419
|
+
const isFunctionCall = node.parent && node.parent.type === "CallExpression" && node.parent.callee === node;
|
|
420
|
+
if (isNamespaceMember || isParamCall || isNamespaceFunctionArg || isArrayIndexInNamespaceCall || isFunctionCall) {
|
|
421
|
+
if (isFunctionCall) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
const [scopedName2, kind2] = scopeManager.getVariable(node.name);
|
|
425
|
+
Object.assign(node, {
|
|
426
|
+
type: "MemberExpression",
|
|
427
|
+
object: {
|
|
428
|
+
type: "MemberExpression",
|
|
429
|
+
object: {
|
|
430
|
+
type: "Identifier",
|
|
431
|
+
name: CONTEXT_NAME
|
|
432
|
+
},
|
|
433
|
+
property: {
|
|
434
|
+
type: "Identifier",
|
|
435
|
+
name: kind2
|
|
436
|
+
},
|
|
437
|
+
computed: false
|
|
438
|
+
},
|
|
439
|
+
property: {
|
|
440
|
+
type: "Identifier",
|
|
441
|
+
name: scopedName2
|
|
442
|
+
},
|
|
443
|
+
computed: false
|
|
444
|
+
});
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
const [scopedName, kind] = scopeManager.getVariable(node.name);
|
|
448
|
+
const memberExpr = {
|
|
449
|
+
type: "MemberExpression",
|
|
450
|
+
object: {
|
|
451
|
+
type: "MemberExpression",
|
|
452
|
+
object: {
|
|
453
|
+
type: "Identifier",
|
|
454
|
+
name: CONTEXT_NAME
|
|
455
|
+
},
|
|
456
|
+
property: {
|
|
457
|
+
type: "Identifier",
|
|
458
|
+
name: kind
|
|
459
|
+
},
|
|
460
|
+
computed: false
|
|
461
|
+
},
|
|
462
|
+
property: {
|
|
463
|
+
type: "Identifier",
|
|
464
|
+
name: scopedName
|
|
465
|
+
},
|
|
466
|
+
computed: false
|
|
467
|
+
};
|
|
468
|
+
const hasArrayAccess = node.parent && node.parent.type === "MemberExpression" && node.parent.computed && node.parent.object === node;
|
|
469
|
+
if (!hasArrayAccess && !isArrayAccess) {
|
|
470
|
+
Object.assign(node, {
|
|
471
|
+
type: "MemberExpression",
|
|
472
|
+
object: memberExpr,
|
|
473
|
+
property: {
|
|
474
|
+
type: "Literal",
|
|
475
|
+
value: 0
|
|
476
|
+
},
|
|
477
|
+
computed: true
|
|
478
|
+
});
|
|
479
|
+
} else {
|
|
480
|
+
Object.assign(node, memberExpr);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
function transformAssignmentExpression(node, scopeManager) {
|
|
485
|
+
if (node.left.type === "Identifier") {
|
|
486
|
+
const [varName, kind] = scopeManager.getVariable(node.left.name);
|
|
487
|
+
const memberExpr = {
|
|
488
|
+
type: "MemberExpression",
|
|
489
|
+
object: {
|
|
490
|
+
type: "MemberExpression",
|
|
491
|
+
object: {
|
|
492
|
+
type: "Identifier",
|
|
493
|
+
name: CONTEXT_NAME
|
|
494
|
+
},
|
|
495
|
+
property: {
|
|
496
|
+
type: "Identifier",
|
|
497
|
+
name: kind
|
|
498
|
+
},
|
|
499
|
+
computed: false
|
|
500
|
+
},
|
|
501
|
+
property: {
|
|
502
|
+
type: "Identifier",
|
|
503
|
+
name: varName
|
|
504
|
+
},
|
|
505
|
+
computed: false
|
|
506
|
+
};
|
|
507
|
+
node.left = {
|
|
508
|
+
type: "MemberExpression",
|
|
509
|
+
object: memberExpr,
|
|
510
|
+
property: {
|
|
511
|
+
type: "Literal",
|
|
512
|
+
value: 0
|
|
513
|
+
},
|
|
514
|
+
computed: true
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
walk.recursive(
|
|
518
|
+
node.right,
|
|
519
|
+
{ parent: node.right, inNamespaceCall: false },
|
|
520
|
+
{
|
|
521
|
+
Identifier(node2, state, c) {
|
|
522
|
+
node2.parent = state.parent;
|
|
523
|
+
transformIdentifier(node2, scopeManager);
|
|
524
|
+
const isBinaryOperation = node2.parent && node2.parent.type === "BinaryExpression";
|
|
525
|
+
const isConditional = node2.parent && node2.parent.type === "ConditionalExpression";
|
|
526
|
+
if (isConditional || isBinaryOperation) {
|
|
527
|
+
if (node2.type === "MemberExpression") {
|
|
528
|
+
transformArrayIndex(node2, scopeManager);
|
|
529
|
+
} else if (node2.type === "Identifier") {
|
|
530
|
+
addArrayAccess(node2);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
},
|
|
534
|
+
MemberExpression(node2, state, c) {
|
|
535
|
+
transformArrayIndex(node2, scopeManager);
|
|
536
|
+
if (node2.object) {
|
|
537
|
+
c(node2.object, { parent: node2, inNamespaceCall: state.inNamespaceCall });
|
|
538
|
+
}
|
|
539
|
+
},
|
|
540
|
+
CallExpression(node2, state, c) {
|
|
541
|
+
const isNamespaceCall = node2.callee && node2.callee.type === "MemberExpression" && node2.callee.object && node2.callee.object.type === "Identifier" && scopeManager.isContextBound(node2.callee.object.name);
|
|
542
|
+
transformCallExpression(node2, scopeManager);
|
|
543
|
+
node2.arguments.forEach((arg) => c(arg, { parent: node2, inNamespaceCall: isNamespaceCall || state.inNamespaceCall }));
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
function transformArrowFunctionParams(node, scopeManager, isRootFunction = false) {
|
|
549
|
+
node.params.forEach((param) => {
|
|
550
|
+
if (param.type === "Identifier") {
|
|
551
|
+
scopeManager.addContextBoundVar(param.name, isRootFunction);
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
function transformReturnStatement(node, scopeManager) {
|
|
556
|
+
const curScope = scopeManager.getCurrentScopeType();
|
|
557
|
+
if (node.argument) {
|
|
558
|
+
if (node.argument.type === "ArrayExpression") {
|
|
559
|
+
node.argument.elements = node.argument.elements.map((element) => {
|
|
560
|
+
if (element.type === "Identifier") {
|
|
561
|
+
if (scopeManager.isContextBound(element.name) && !scopeManager.isRootParam(element.name)) {
|
|
562
|
+
return {
|
|
563
|
+
type: "MemberExpression",
|
|
564
|
+
object: element,
|
|
565
|
+
property: {
|
|
566
|
+
type: "Literal",
|
|
567
|
+
value: 0
|
|
568
|
+
},
|
|
569
|
+
computed: true
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
const [scopedName, kind] = scopeManager.getVariable(element.name);
|
|
573
|
+
return {
|
|
574
|
+
type: "MemberExpression",
|
|
575
|
+
object: {
|
|
576
|
+
type: "MemberExpression",
|
|
577
|
+
object: {
|
|
578
|
+
type: "MemberExpression",
|
|
579
|
+
object: {
|
|
580
|
+
type: "Identifier",
|
|
581
|
+
name: CONTEXT_NAME
|
|
582
|
+
},
|
|
583
|
+
property: {
|
|
584
|
+
type: "Identifier",
|
|
585
|
+
name: kind
|
|
586
|
+
},
|
|
587
|
+
computed: false
|
|
588
|
+
},
|
|
589
|
+
property: {
|
|
590
|
+
type: "Identifier",
|
|
591
|
+
name: scopedName
|
|
592
|
+
},
|
|
593
|
+
computed: false
|
|
594
|
+
},
|
|
595
|
+
property: {
|
|
596
|
+
type: "Literal",
|
|
597
|
+
value: 0
|
|
598
|
+
},
|
|
599
|
+
computed: true
|
|
600
|
+
};
|
|
601
|
+
} else if (element.type === "MemberExpression") {
|
|
602
|
+
if (element.computed && element.object.type === "Identifier" && scopeManager.isContextBound(element.object.name) && !scopeManager.isRootParam(element.object.name)) {
|
|
603
|
+
return element;
|
|
604
|
+
}
|
|
605
|
+
transformMemberExpression(element, "", scopeManager);
|
|
606
|
+
return element;
|
|
607
|
+
}
|
|
608
|
+
return element;
|
|
609
|
+
});
|
|
610
|
+
node.argument = {
|
|
611
|
+
type: "ArrayExpression",
|
|
612
|
+
elements: [node.argument]
|
|
613
|
+
};
|
|
614
|
+
} else if (node.argument.type === "BinaryExpression") {
|
|
615
|
+
walk.recursive(node.argument, scopeManager, {
|
|
616
|
+
Identifier(node2, state) {
|
|
617
|
+
transformIdentifier(node2, state);
|
|
618
|
+
if (node2.type === "Identifier") {
|
|
619
|
+
addArrayAccess(node2);
|
|
620
|
+
}
|
|
621
|
+
},
|
|
622
|
+
MemberExpression(node2) {
|
|
623
|
+
transformMemberExpression(node2, "", scopeManager);
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
} else if (node.argument.type === "ObjectExpression") {
|
|
627
|
+
node.argument.properties = node.argument.properties.map((prop) => {
|
|
628
|
+
if (prop.shorthand) {
|
|
629
|
+
const [scopedName, kind] = scopeManager.getVariable(prop.value.name);
|
|
630
|
+
return {
|
|
631
|
+
type: "Property",
|
|
632
|
+
key: {
|
|
633
|
+
type: "Identifier",
|
|
634
|
+
name: prop.key.name
|
|
635
|
+
},
|
|
636
|
+
value: {
|
|
637
|
+
type: "MemberExpression",
|
|
638
|
+
object: {
|
|
639
|
+
type: "MemberExpression",
|
|
640
|
+
object: {
|
|
641
|
+
type: "Identifier",
|
|
642
|
+
name: CONTEXT_NAME
|
|
643
|
+
},
|
|
644
|
+
property: {
|
|
645
|
+
type: "Identifier",
|
|
646
|
+
name: kind
|
|
647
|
+
},
|
|
648
|
+
computed: false
|
|
649
|
+
},
|
|
650
|
+
property: {
|
|
651
|
+
type: "Identifier",
|
|
652
|
+
name: scopedName
|
|
653
|
+
},
|
|
654
|
+
computed: false
|
|
655
|
+
},
|
|
656
|
+
kind: "init",
|
|
657
|
+
method: false,
|
|
658
|
+
shorthand: false,
|
|
659
|
+
computed: false
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
return prop;
|
|
663
|
+
});
|
|
664
|
+
} else if (node.argument.type === "Identifier") {
|
|
665
|
+
const [scopedName, kind] = scopeManager.getVariable(node.argument.name);
|
|
666
|
+
node.argument = {
|
|
667
|
+
type: "MemberExpression",
|
|
668
|
+
object: {
|
|
669
|
+
type: "MemberExpression",
|
|
670
|
+
object: {
|
|
671
|
+
type: "Identifier",
|
|
672
|
+
name: CONTEXT_NAME
|
|
673
|
+
},
|
|
674
|
+
property: {
|
|
675
|
+
type: "Identifier",
|
|
676
|
+
name: kind
|
|
677
|
+
},
|
|
678
|
+
computed: false
|
|
679
|
+
},
|
|
680
|
+
property: {
|
|
681
|
+
type: "Identifier",
|
|
682
|
+
name: scopedName
|
|
683
|
+
},
|
|
684
|
+
computed: false
|
|
685
|
+
};
|
|
686
|
+
node.argument = {
|
|
687
|
+
type: "MemberExpression",
|
|
688
|
+
object: node.argument,
|
|
689
|
+
property: {
|
|
690
|
+
type: "Literal",
|
|
691
|
+
value: 0
|
|
692
|
+
},
|
|
693
|
+
computed: true
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
if (curScope === "fn") {
|
|
697
|
+
node.argument = {
|
|
698
|
+
type: "CallExpression",
|
|
699
|
+
callee: {
|
|
700
|
+
type: "MemberExpression",
|
|
701
|
+
object: { type: "Identifier", name: CONTEXT_NAME },
|
|
702
|
+
property: { type: "Identifier", name: "precision" }
|
|
703
|
+
},
|
|
704
|
+
arguments: [node.argument]
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
function transformIdentifierForParam(node, scopeManager) {
|
|
710
|
+
if (node.type === "Identifier") {
|
|
711
|
+
if (scopeManager.isLoopVariable(node.name)) {
|
|
712
|
+
return node;
|
|
713
|
+
}
|
|
714
|
+
if (scopeManager.isRootParam(node.name)) {
|
|
715
|
+
const [scopedName2, kind2] = scopeManager.getVariable(node.name);
|
|
716
|
+
return {
|
|
717
|
+
type: "MemberExpression",
|
|
718
|
+
object: {
|
|
719
|
+
type: "MemberExpression",
|
|
720
|
+
object: {
|
|
721
|
+
type: "Identifier",
|
|
722
|
+
name: CONTEXT_NAME
|
|
723
|
+
},
|
|
724
|
+
property: {
|
|
725
|
+
type: "Identifier",
|
|
726
|
+
name: kind2
|
|
727
|
+
},
|
|
728
|
+
computed: false
|
|
729
|
+
},
|
|
730
|
+
property: {
|
|
731
|
+
type: "Identifier",
|
|
732
|
+
name: scopedName2
|
|
733
|
+
},
|
|
734
|
+
computed: false
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
if (scopeManager.isContextBound(node.name)) {
|
|
738
|
+
return node;
|
|
739
|
+
}
|
|
740
|
+
const [scopedName, kind] = scopeManager.getVariable(node.name);
|
|
741
|
+
return {
|
|
742
|
+
type: "MemberExpression",
|
|
743
|
+
object: {
|
|
744
|
+
type: "MemberExpression",
|
|
745
|
+
object: {
|
|
746
|
+
type: "Identifier",
|
|
747
|
+
name: CONTEXT_NAME
|
|
748
|
+
},
|
|
749
|
+
property: {
|
|
750
|
+
type: "Identifier",
|
|
751
|
+
name: kind
|
|
752
|
+
},
|
|
753
|
+
computed: false
|
|
754
|
+
},
|
|
755
|
+
property: {
|
|
756
|
+
type: "Identifier",
|
|
757
|
+
name: scopedName
|
|
758
|
+
},
|
|
759
|
+
computed: false
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
return node;
|
|
763
|
+
}
|
|
764
|
+
function transformOperand(node, scopeManager, namespace = "") {
|
|
765
|
+
if (node.type === "BinaryExpression") {
|
|
766
|
+
return transformBinaryExpression(node, scopeManager, namespace);
|
|
767
|
+
}
|
|
768
|
+
if (node.type === "MemberExpression") {
|
|
769
|
+
const transformedObject = node.object.type === "Identifier" ? transformIdentifierForParam(node.object, scopeManager) : node.object;
|
|
770
|
+
return {
|
|
771
|
+
type: "MemberExpression",
|
|
772
|
+
object: transformedObject,
|
|
773
|
+
property: node.property,
|
|
774
|
+
computed: node.computed
|
|
775
|
+
};
|
|
776
|
+
} else if (node.type === "Identifier") {
|
|
777
|
+
if (scopeManager.isLoopVariable(node.name)) {
|
|
778
|
+
return node;
|
|
779
|
+
}
|
|
780
|
+
const isMemberExprProperty = node.parent && node.parent.type === "MemberExpression" && node.parent.property === node;
|
|
781
|
+
if (isMemberExprProperty) {
|
|
782
|
+
return node;
|
|
783
|
+
}
|
|
784
|
+
const transformedObject = transformIdentifierForParam(node, scopeManager);
|
|
785
|
+
return {
|
|
786
|
+
type: "MemberExpression",
|
|
787
|
+
object: transformedObject,
|
|
788
|
+
property: {
|
|
789
|
+
type: "Literal",
|
|
790
|
+
value: 0
|
|
791
|
+
},
|
|
792
|
+
computed: true
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
return node;
|
|
796
|
+
}
|
|
797
|
+
function transformBinaryExpression(node, scopeManager, namespace) {
|
|
798
|
+
const transformedLeft = transformOperand(node.left, scopeManager, namespace);
|
|
799
|
+
const transformedRight = transformOperand(node.right, scopeManager, namespace);
|
|
800
|
+
const binaryExpr = {
|
|
801
|
+
type: "BinaryExpression",
|
|
802
|
+
operator: node.operator,
|
|
803
|
+
left: transformedLeft,
|
|
804
|
+
right: transformedRight,
|
|
805
|
+
start: node.start,
|
|
806
|
+
end: node.end
|
|
807
|
+
};
|
|
808
|
+
walk.recursive(binaryExpr, scopeManager, {
|
|
809
|
+
CallExpression(node2, scopeManager2) {
|
|
810
|
+
if (!node2._transformed) {
|
|
811
|
+
transformCallExpression(node2, scopeManager2);
|
|
812
|
+
}
|
|
813
|
+
},
|
|
814
|
+
MemberExpression(node2) {
|
|
815
|
+
transformMemberExpression(node2, "", scopeManager);
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
return {
|
|
819
|
+
type: "CallExpression",
|
|
820
|
+
callee: {
|
|
821
|
+
type: "MemberExpression",
|
|
822
|
+
object: {
|
|
823
|
+
type: "Identifier",
|
|
824
|
+
name: namespace
|
|
825
|
+
},
|
|
826
|
+
property: {
|
|
827
|
+
type: "Identifier",
|
|
828
|
+
name: "param"
|
|
829
|
+
},
|
|
830
|
+
computed: false
|
|
831
|
+
},
|
|
832
|
+
arguments: [binaryExpr, UNDEFINED_ARG, scopeManager.nextParamIdArg],
|
|
833
|
+
_transformed: true,
|
|
834
|
+
_isParamCall: true
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
function transformFunctionArgument(arg, namespace, scopeManager) {
|
|
838
|
+
if (arg.type === "BinaryExpression") {
|
|
839
|
+
return transformBinaryExpression(arg, scopeManager, namespace);
|
|
840
|
+
}
|
|
841
|
+
const isArrayAccess = arg.type === "MemberExpression" && arg.computed && arg.property;
|
|
842
|
+
if (isArrayAccess) {
|
|
843
|
+
const transformedObject = arg.object.type === "Identifier" && scopeManager.isContextBound(arg.object.name) && !scopeManager.isRootParam(arg.object.name) ? arg.object : transformIdentifierForParam(arg.object, scopeManager);
|
|
844
|
+
const transformedProperty = arg.property.type === "Identifier" && !scopeManager.isContextBound(arg.property.name) && !scopeManager.isLoopVariable(arg.property.name) ? transformIdentifierForParam(arg.property, scopeManager) : arg.property;
|
|
845
|
+
return {
|
|
846
|
+
type: "CallExpression",
|
|
847
|
+
callee: {
|
|
848
|
+
type: "MemberExpression",
|
|
849
|
+
object: {
|
|
850
|
+
type: "Identifier",
|
|
851
|
+
name: namespace
|
|
852
|
+
},
|
|
853
|
+
property: {
|
|
854
|
+
type: "Identifier",
|
|
855
|
+
name: "param"
|
|
856
|
+
},
|
|
857
|
+
computed: false
|
|
858
|
+
},
|
|
859
|
+
arguments: [transformedObject, transformedProperty, scopeManager.nextParamIdArg],
|
|
860
|
+
_transformed: true,
|
|
861
|
+
_isParamCall: true
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
if (arg.type === "ObjectExpression") {
|
|
865
|
+
arg.properties = arg.properties.map((prop) => {
|
|
866
|
+
if (prop.value.name) {
|
|
867
|
+
const [scopedName, kind] = scopeManager.getVariable(prop.value.name);
|
|
868
|
+
return {
|
|
869
|
+
type: "Property",
|
|
870
|
+
key: {
|
|
871
|
+
type: "Identifier",
|
|
872
|
+
name: prop.key.name
|
|
873
|
+
},
|
|
874
|
+
value: {
|
|
875
|
+
type: "MemberExpression",
|
|
876
|
+
object: {
|
|
877
|
+
type: "MemberExpression",
|
|
878
|
+
object: {
|
|
879
|
+
type: "Identifier",
|
|
880
|
+
name: CONTEXT_NAME
|
|
881
|
+
},
|
|
882
|
+
property: {
|
|
883
|
+
type: "Identifier",
|
|
884
|
+
name: kind
|
|
885
|
+
},
|
|
886
|
+
computed: false
|
|
887
|
+
},
|
|
888
|
+
property: {
|
|
889
|
+
type: "Identifier",
|
|
890
|
+
name: scopedName
|
|
891
|
+
},
|
|
892
|
+
computed: false
|
|
893
|
+
},
|
|
894
|
+
kind: "init",
|
|
895
|
+
method: false,
|
|
896
|
+
shorthand: false,
|
|
897
|
+
computed: false
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
return prop;
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
if (arg.type === "Identifier") {
|
|
904
|
+
if (scopeManager.isContextBound(arg.name) && !scopeManager.isRootParam(arg.name)) {
|
|
905
|
+
return {
|
|
906
|
+
type: "CallExpression",
|
|
907
|
+
callee: {
|
|
908
|
+
type: "MemberExpression",
|
|
909
|
+
object: {
|
|
910
|
+
type: "Identifier",
|
|
911
|
+
name: namespace
|
|
912
|
+
},
|
|
913
|
+
property: {
|
|
914
|
+
type: "Identifier",
|
|
915
|
+
name: "param"
|
|
916
|
+
},
|
|
917
|
+
computed: false
|
|
918
|
+
},
|
|
919
|
+
arguments: [arg, UNDEFINED_ARG, scopeManager.nextParamIdArg],
|
|
920
|
+
_transformed: true,
|
|
921
|
+
_isParamCall: true
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
if (arg?.type === "CallExpression") {
|
|
926
|
+
transformCallExpression(arg, scopeManager);
|
|
927
|
+
}
|
|
928
|
+
return {
|
|
929
|
+
type: "CallExpression",
|
|
930
|
+
callee: {
|
|
931
|
+
type: "MemberExpression",
|
|
932
|
+
object: {
|
|
933
|
+
type: "Identifier",
|
|
934
|
+
name: namespace
|
|
935
|
+
},
|
|
936
|
+
property: {
|
|
937
|
+
type: "Identifier",
|
|
938
|
+
name: "param"
|
|
939
|
+
},
|
|
940
|
+
computed: false
|
|
941
|
+
},
|
|
942
|
+
arguments: [arg.type === "Identifier" ? transformIdentifierForParam(arg, scopeManager) : arg, UNDEFINED_ARG, scopeManager.nextParamIdArg],
|
|
943
|
+
_transformed: true,
|
|
944
|
+
_isParamCall: true
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
function transformCallExpression(node, scopeManager) {
|
|
948
|
+
if (node._transformed) {
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
const isNamespaceCall = node.callee && node.callee.type === "MemberExpression" && node.callee.object && node.callee.object.type === "Identifier" && (scopeManager.isContextBound(node.callee.object.name) || node.callee.object.name === "math" || node.callee.object.name === "ta");
|
|
952
|
+
if (isNamespaceCall) {
|
|
953
|
+
const namespace = node.callee.object.name;
|
|
954
|
+
node.arguments = node.arguments.map((arg) => {
|
|
955
|
+
if (arg._isParamCall) {
|
|
956
|
+
return arg;
|
|
957
|
+
}
|
|
958
|
+
return transformFunctionArgument(arg, namespace, scopeManager);
|
|
959
|
+
});
|
|
960
|
+
node._transformed = true;
|
|
961
|
+
} else if (node.callee && node.callee.type === "Identifier") {
|
|
962
|
+
node.arguments = node.arguments.map((arg) => {
|
|
963
|
+
if (arg._isParamCall) {
|
|
964
|
+
return arg;
|
|
965
|
+
}
|
|
966
|
+
return transformFunctionArgument(arg, CONTEXT_NAME, scopeManager);
|
|
967
|
+
});
|
|
968
|
+
node._transformed = true;
|
|
969
|
+
}
|
|
970
|
+
node.arguments.forEach((arg) => {
|
|
971
|
+
walk.recursive(arg, scopeManager, {
|
|
972
|
+
CallExpression(node2, state) {
|
|
973
|
+
if (!node2._transformed) {
|
|
974
|
+
transformCallExpression(node2, state);
|
|
975
|
+
}
|
|
976
|
+
},
|
|
977
|
+
MemberExpression(node2) {
|
|
978
|
+
transformMemberExpression(node2, "", scopeManager);
|
|
979
|
+
}
|
|
980
|
+
});
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
function transformFunctionDeclaration(node, scopeManager) {
|
|
984
|
+
node.params.forEach((param) => {
|
|
985
|
+
if (param.type === "Identifier") {
|
|
986
|
+
scopeManager.addContextBoundVar(param.name, false);
|
|
987
|
+
}
|
|
988
|
+
});
|
|
989
|
+
if (node.body && node.body.type === "BlockStatement") {
|
|
990
|
+
scopeManager.pushScope("fn");
|
|
991
|
+
walk.recursive(node.body, scopeManager, {
|
|
992
|
+
BlockStatement(node2, state, c) {
|
|
993
|
+
node2.body.forEach((stmt) => c(stmt, state));
|
|
994
|
+
},
|
|
995
|
+
ReturnStatement(node2, state) {
|
|
996
|
+
transformReturnStatement(node2, state);
|
|
997
|
+
},
|
|
998
|
+
VariableDeclaration(node2, state) {
|
|
999
|
+
transformVariableDeclaration(node2, state);
|
|
1000
|
+
},
|
|
1001
|
+
Identifier(node2, state) {
|
|
1002
|
+
transformIdentifier(node2, state);
|
|
1003
|
+
},
|
|
1004
|
+
CallExpression(node2, state) {
|
|
1005
|
+
transformCallExpression(node2, state);
|
|
1006
|
+
node2.arguments.forEach((arg) => {
|
|
1007
|
+
if (arg.type === "BinaryExpression") {
|
|
1008
|
+
walk.recursive(arg, state, {
|
|
1009
|
+
CallExpression(node3, state2) {
|
|
1010
|
+
transformCallExpression(node3, state2);
|
|
1011
|
+
},
|
|
1012
|
+
MemberExpression(node3) {
|
|
1013
|
+
transformMemberExpression(node3, "", state);
|
|
1014
|
+
}
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
});
|
|
1018
|
+
},
|
|
1019
|
+
MemberExpression(node2) {
|
|
1020
|
+
transformMemberExpression(node2, "", scopeManager);
|
|
1021
|
+
},
|
|
1022
|
+
AssignmentExpression(node2, state) {
|
|
1023
|
+
transformAssignmentExpression(node2, state);
|
|
1024
|
+
},
|
|
1025
|
+
ForStatement(node2, state, c) {
|
|
1026
|
+
transformForStatement(node2, state, c);
|
|
1027
|
+
},
|
|
1028
|
+
IfStatement(node2, state, c) {
|
|
1029
|
+
transformIfStatement(node2, state, c);
|
|
1030
|
+
},
|
|
1031
|
+
BinaryExpression(node2, state, c) {
|
|
1032
|
+
walk.recursive(node2, state, {
|
|
1033
|
+
CallExpression(node3, state2) {
|
|
1034
|
+
transformCallExpression(node3, state2);
|
|
1035
|
+
},
|
|
1036
|
+
MemberExpression(node3) {
|
|
1037
|
+
transformMemberExpression(node3, "", state);
|
|
1038
|
+
}
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
});
|
|
1042
|
+
scopeManager.popScope();
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
function addArrayAccess(node, scopeManager) {
|
|
1046
|
+
Object.assign(node, {
|
|
1047
|
+
type: "MemberExpression",
|
|
1048
|
+
object: {
|
|
1049
|
+
type: "Identifier",
|
|
1050
|
+
name: node.name,
|
|
1051
|
+
start: node.start,
|
|
1052
|
+
end: node.end
|
|
1053
|
+
},
|
|
1054
|
+
property: {
|
|
1055
|
+
type: "Literal",
|
|
1056
|
+
value: 0
|
|
1057
|
+
},
|
|
1058
|
+
computed: true,
|
|
1059
|
+
_indexTransformed: true
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
function transformForStatement(node, scopeManager, c) {
|
|
1063
|
+
if (node.init && node.init.type === "VariableDeclaration") {
|
|
1064
|
+
const decl = node.init.declarations[0];
|
|
1065
|
+
const originalName = decl.id.name;
|
|
1066
|
+
scopeManager.addLoopVariable(originalName, originalName);
|
|
1067
|
+
node.init = {
|
|
1068
|
+
type: "VariableDeclaration",
|
|
1069
|
+
kind: node.init.kind,
|
|
1070
|
+
declarations: [
|
|
1071
|
+
{
|
|
1072
|
+
type: "VariableDeclarator",
|
|
1073
|
+
id: {
|
|
1074
|
+
type: "Identifier",
|
|
1075
|
+
name: originalName
|
|
1076
|
+
},
|
|
1077
|
+
init: decl.init
|
|
1078
|
+
}
|
|
1079
|
+
]
|
|
1080
|
+
};
|
|
1081
|
+
if (decl.init) {
|
|
1082
|
+
walk.recursive(decl.init, scopeManager, {
|
|
1083
|
+
Identifier(node2, state) {
|
|
1084
|
+
if (!scopeManager.isLoopVariable(node2.name)) {
|
|
1085
|
+
scopeManager.pushScope("for");
|
|
1086
|
+
transformIdentifier(node2, state);
|
|
1087
|
+
scopeManager.popScope();
|
|
1088
|
+
}
|
|
1089
|
+
},
|
|
1090
|
+
MemberExpression(node2) {
|
|
1091
|
+
scopeManager.pushScope("for");
|
|
1092
|
+
transformMemberExpression(node2, "", scopeManager);
|
|
1093
|
+
scopeManager.popScope();
|
|
1094
|
+
}
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
if (node.test) {
|
|
1099
|
+
walk.recursive(node.test, scopeManager, {
|
|
1100
|
+
Identifier(node2, state) {
|
|
1101
|
+
if (!scopeManager.isLoopVariable(node2.name) && !node2.computed) {
|
|
1102
|
+
scopeManager.pushScope("for");
|
|
1103
|
+
transformIdentifier(node2, state);
|
|
1104
|
+
if (node2.type === "Identifier") {
|
|
1105
|
+
node2.computed = true;
|
|
1106
|
+
addArrayAccess(node2);
|
|
1107
|
+
}
|
|
1108
|
+
scopeManager.popScope();
|
|
1109
|
+
}
|
|
1110
|
+
},
|
|
1111
|
+
MemberExpression(node2) {
|
|
1112
|
+
scopeManager.pushScope("for");
|
|
1113
|
+
transformMemberExpression(node2, "", scopeManager);
|
|
1114
|
+
scopeManager.popScope();
|
|
1115
|
+
}
|
|
1116
|
+
});
|
|
1117
|
+
}
|
|
1118
|
+
if (node.update) {
|
|
1119
|
+
walk.recursive(node.update, scopeManager, {
|
|
1120
|
+
Identifier(node2, state) {
|
|
1121
|
+
if (!scopeManager.isLoopVariable(node2.name)) {
|
|
1122
|
+
scopeManager.pushScope("for");
|
|
1123
|
+
transformIdentifier(node2, state);
|
|
1124
|
+
scopeManager.popScope();
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
scopeManager.pushScope("for");
|
|
1130
|
+
c(node.body, scopeManager);
|
|
1131
|
+
scopeManager.popScope();
|
|
1132
|
+
}
|
|
1133
|
+
function transformExpression(node, scopeManager) {
|
|
1134
|
+
walk.recursive(node, scopeManager, {
|
|
1135
|
+
MemberExpression(node2) {
|
|
1136
|
+
transformMemberExpression(node2, "", scopeManager);
|
|
1137
|
+
},
|
|
1138
|
+
CallExpression(node2, state) {
|
|
1139
|
+
transformCallExpression(node2, state);
|
|
1140
|
+
},
|
|
1141
|
+
Identifier(node2, state) {
|
|
1142
|
+
transformIdentifier(node2, state);
|
|
1143
|
+
const isIfStatement = scopeManager.getCurrentScopeType() === "if";
|
|
1144
|
+
const isContextBound = scopeManager.isContextBound(node2.name) && !scopeManager.isRootParam(node2.name);
|
|
1145
|
+
if (isContextBound && isIfStatement) {
|
|
1146
|
+
addArrayAccess(node2);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
function transformIfStatement(node, scopeManager, c) {
|
|
1152
|
+
if (node.test) {
|
|
1153
|
+
scopeManager.pushScope("if");
|
|
1154
|
+
transformExpression(node.test, scopeManager);
|
|
1155
|
+
scopeManager.popScope();
|
|
1156
|
+
}
|
|
1157
|
+
scopeManager.pushScope("if");
|
|
1158
|
+
c(node.consequent, scopeManager);
|
|
1159
|
+
scopeManager.popScope();
|
|
1160
|
+
if (node.alternate) {
|
|
1161
|
+
scopeManager.pushScope("els");
|
|
1162
|
+
c(node.alternate, scopeManager);
|
|
1163
|
+
scopeManager.popScope();
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
function transformNestedArrowFunctions(ast) {
|
|
1167
|
+
walk.recursive(ast, null, {
|
|
1168
|
+
VariableDeclaration(node, state, c) {
|
|
1169
|
+
if (node.declarations && node.declarations.length > 0) {
|
|
1170
|
+
const declarations = node.declarations;
|
|
1171
|
+
declarations.forEach((decl) => {
|
|
1172
|
+
if (decl.init && decl.init.type === "ArrowFunctionExpression") {
|
|
1173
|
+
const isRootFunction = decl.init.start === 0;
|
|
1174
|
+
if (!isRootFunction) {
|
|
1175
|
+
const functionDeclaration = {
|
|
1176
|
+
type: "FunctionDeclaration",
|
|
1177
|
+
id: decl.id,
|
|
1178
|
+
// Use the variable name as function name
|
|
1179
|
+
params: decl.init.params,
|
|
1180
|
+
body: decl.init.body.type === "BlockStatement" ? decl.init.body : {
|
|
1181
|
+
type: "BlockStatement",
|
|
1182
|
+
body: [
|
|
1183
|
+
{
|
|
1184
|
+
type: "ReturnStatement",
|
|
1185
|
+
argument: decl.init.body
|
|
1186
|
+
}
|
|
1187
|
+
]
|
|
1188
|
+
},
|
|
1189
|
+
async: decl.init.async,
|
|
1190
|
+
generator: false
|
|
1191
|
+
};
|
|
1192
|
+
Object.assign(node, functionDeclaration);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
1197
|
+
if (node.body && node.body.body) {
|
|
1198
|
+
node.body.body.forEach((stmt) => c(stmt, state));
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
function preProcessContextBoundVars(ast, scopeManager) {
|
|
1204
|
+
walk.simple(ast, {
|
|
1205
|
+
VariableDeclaration(node) {
|
|
1206
|
+
node.declarations.forEach((decl) => {
|
|
1207
|
+
const isContextProperty = decl.init && decl.init.type === "MemberExpression" && decl.init.object && (decl.init.object.name === "context" || decl.init.object.name === CONTEXT_NAME || decl.init.object.name === "context2");
|
|
1208
|
+
const isSubContextProperty = decl.init && decl.init.type === "MemberExpression" && decl.init.object?.object && (decl.init.object.object.name === "context" || decl.init.object.object.name === CONTEXT_NAME || decl.init.object.object.name === "context2");
|
|
1209
|
+
if (isContextProperty || isSubContextProperty) {
|
|
1210
|
+
if (decl.id.name) {
|
|
1211
|
+
scopeManager.addContextBoundVar(decl.id.name);
|
|
1212
|
+
}
|
|
1213
|
+
if (decl.id.properties) {
|
|
1214
|
+
decl.id.properties.forEach((property) => {
|
|
1215
|
+
if (property.key.name) {
|
|
1216
|
+
scopeManager.addContextBoundVar(property.key.name);
|
|
1217
|
+
}
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
function transpile(fn) {
|
|
1226
|
+
let code = typeof fn === "function" ? fn.toString() : fn;
|
|
1227
|
+
const ast = acorn.parse(code.trim(), {
|
|
1228
|
+
ecmaVersion: "latest",
|
|
1229
|
+
sourceType: "module"
|
|
1230
|
+
});
|
|
1231
|
+
transformNestedArrowFunctions(ast);
|
|
1232
|
+
const scopeManager = new ScopeManager();
|
|
1233
|
+
let originalParamName;
|
|
1234
|
+
preProcessContextBoundVars(ast, scopeManager);
|
|
1235
|
+
walk.simple(ast, {
|
|
1236
|
+
FunctionDeclaration(node) {
|
|
1237
|
+
transformFunctionDeclaration(node, scopeManager);
|
|
1238
|
+
},
|
|
1239
|
+
ArrowFunctionExpression(node) {
|
|
1240
|
+
const isRootFunction = node.start === 0;
|
|
1241
|
+
if (isRootFunction && node.params && node.params.length > 0) {
|
|
1242
|
+
originalParamName = node.params[0].name;
|
|
1243
|
+
node.params[0].name = CONTEXT_NAME;
|
|
1244
|
+
}
|
|
1245
|
+
transformArrowFunctionParams(node, scopeManager, isRootFunction);
|
|
1246
|
+
},
|
|
1247
|
+
VariableDeclaration(node) {
|
|
1248
|
+
node.declarations.forEach((decl) => {
|
|
1249
|
+
if (decl.id.type === "ArrayPattern") {
|
|
1250
|
+
const tempVarName = scopeManager.generateTempVar();
|
|
1251
|
+
const tempVarDecl = {
|
|
1252
|
+
type: "VariableDeclaration",
|
|
1253
|
+
kind: node.kind,
|
|
1254
|
+
declarations: [
|
|
1255
|
+
{
|
|
1256
|
+
type: "VariableDeclarator",
|
|
1257
|
+
id: {
|
|
1258
|
+
type: "Identifier",
|
|
1259
|
+
name: tempVarName
|
|
1260
|
+
},
|
|
1261
|
+
init: decl.init
|
|
1262
|
+
}
|
|
1263
|
+
]
|
|
1264
|
+
};
|
|
1265
|
+
decl.id.elements?.forEach((element) => {
|
|
1266
|
+
if (element.type === "Identifier") {
|
|
1267
|
+
scopeManager.addArrayPatternElement(element.name);
|
|
1268
|
+
}
|
|
1269
|
+
});
|
|
1270
|
+
const individualDecls = decl.id.elements.map((element, index) => ({
|
|
1271
|
+
type: "VariableDeclaration",
|
|
1272
|
+
kind: node.kind,
|
|
1273
|
+
declarations: [
|
|
1274
|
+
{
|
|
1275
|
+
type: "VariableDeclarator",
|
|
1276
|
+
id: element,
|
|
1277
|
+
init: {
|
|
1278
|
+
type: "MemberExpression",
|
|
1279
|
+
object: {
|
|
1280
|
+
type: "Identifier",
|
|
1281
|
+
name: tempVarName
|
|
1282
|
+
},
|
|
1283
|
+
property: {
|
|
1284
|
+
type: "Literal",
|
|
1285
|
+
value: index
|
|
1286
|
+
},
|
|
1287
|
+
computed: true
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
]
|
|
1291
|
+
}));
|
|
1292
|
+
Object.assign(node, {
|
|
1293
|
+
type: "BlockStatement",
|
|
1294
|
+
body: [tempVarDecl, ...individualDecls]
|
|
1295
|
+
});
|
|
1296
|
+
}
|
|
1297
|
+
});
|
|
1298
|
+
},
|
|
1299
|
+
ForStatement(node) {
|
|
1300
|
+
}
|
|
1301
|
+
});
|
|
1302
|
+
walk.recursive(ast, scopeManager, {
|
|
1303
|
+
BlockStatement(node, state, c) {
|
|
1304
|
+
node.body.forEach((stmt) => c(stmt, state));
|
|
1305
|
+
},
|
|
1306
|
+
ReturnStatement(node, state) {
|
|
1307
|
+
transformReturnStatement(node, state);
|
|
1308
|
+
},
|
|
1309
|
+
VariableDeclaration(node, state) {
|
|
1310
|
+
transformVariableDeclaration(node, state);
|
|
1311
|
+
},
|
|
1312
|
+
Identifier(node, state) {
|
|
1313
|
+
transformIdentifier(node, state);
|
|
1314
|
+
},
|
|
1315
|
+
CallExpression(node, state) {
|
|
1316
|
+
transformCallExpression(node, state);
|
|
1317
|
+
},
|
|
1318
|
+
MemberExpression(node) {
|
|
1319
|
+
transformMemberExpression(node, originalParamName, scopeManager);
|
|
1320
|
+
},
|
|
1321
|
+
AssignmentExpression(node, state) {
|
|
1322
|
+
transformAssignmentExpression(node, state);
|
|
1323
|
+
},
|
|
1324
|
+
FunctionDeclaration(node, state) {
|
|
1325
|
+
return;
|
|
1326
|
+
},
|
|
1327
|
+
ForStatement(node, state, c) {
|
|
1328
|
+
transformForStatement(node, state, c);
|
|
1329
|
+
},
|
|
1330
|
+
IfStatement(node, state, c) {
|
|
1331
|
+
transformIfStatement(node, state, c);
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
const transformedCode = astring.generate(ast);
|
|
1335
|
+
const _wraperFunction = new Function("", `return ${transformedCode}`);
|
|
1336
|
+
return _wraperFunction(this);
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
var __defProp$4 = Object.defineProperty;
|
|
1340
|
+
var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1341
|
+
var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1342
|
+
class PineTS {
|
|
1343
|
+
constructor(source, tickerId, timeframe, limit, sDate, eDate) {
|
|
1344
|
+
this.source = source;
|
|
1345
|
+
this.tickerId = tickerId;
|
|
1346
|
+
this.timeframe = timeframe;
|
|
1347
|
+
this.limit = limit;
|
|
1348
|
+
this.sDate = sDate;
|
|
1349
|
+
this.eDate = eDate;
|
|
1350
|
+
__publicField$4(this, "data", []);
|
|
1351
|
+
//#region [Pine Script built-in variables]
|
|
1352
|
+
__publicField$4(this, "open", []);
|
|
1353
|
+
__publicField$4(this, "high", []);
|
|
1354
|
+
__publicField$4(this, "low", []);
|
|
1355
|
+
__publicField$4(this, "close", []);
|
|
1356
|
+
__publicField$4(this, "volume", []);
|
|
1357
|
+
__publicField$4(this, "hl2", []);
|
|
1358
|
+
__publicField$4(this, "hlc3", []);
|
|
1359
|
+
__publicField$4(this, "ohlc4", []);
|
|
1360
|
+
__publicField$4(this, "openTime", []);
|
|
1361
|
+
__publicField$4(this, "closeTime", []);
|
|
1362
|
+
//#endregion
|
|
1363
|
+
//#region run context
|
|
1364
|
+
__publicField$4(this, "_periods");
|
|
1365
|
+
//#endregion
|
|
1366
|
+
//public fn: Function;
|
|
1367
|
+
__publicField$4(this, "_readyPromise", null);
|
|
1368
|
+
__publicField$4(this, "_ready", false);
|
|
1369
|
+
this._readyPromise = new Promise((resolve) => {
|
|
1370
|
+
this.loadMarketData(source, tickerId, timeframe, limit, sDate, eDate).then((data) => {
|
|
1371
|
+
const marketData = data.reverse();
|
|
1372
|
+
this._periods = marketData.length;
|
|
1373
|
+
this.data = marketData;
|
|
1374
|
+
const _open = marketData.map((d) => d.open);
|
|
1375
|
+
const _close = marketData.map((d) => d.close);
|
|
1376
|
+
const _high = marketData.map((d) => d.high);
|
|
1377
|
+
const _low = marketData.map((d) => d.low);
|
|
1378
|
+
const _volume = marketData.map((d) => d.volume);
|
|
1379
|
+
const _hlc3 = marketData.map((d) => (d.high + d.low + d.close) / 3);
|
|
1380
|
+
const _hl2 = marketData.map((d) => (d.high + d.low) / 2);
|
|
1381
|
+
const _ohlc4 = marketData.map((d) => (d.high + d.low + d.open + d.close) / 4);
|
|
1382
|
+
const _openTime = marketData.map((d) => d.openTime);
|
|
1383
|
+
const _closeTime = marketData.map((d) => d.closeTime);
|
|
1384
|
+
this.open = _open;
|
|
1385
|
+
this.close = _close;
|
|
1386
|
+
this.high = _high;
|
|
1387
|
+
this.low = _low;
|
|
1388
|
+
this.volume = _volume;
|
|
1389
|
+
this.hl2 = _hl2;
|
|
1390
|
+
this.hlc3 = _hlc3;
|
|
1391
|
+
this.ohlc4 = _ohlc4;
|
|
1392
|
+
this.openTime = _openTime;
|
|
1393
|
+
this.closeTime = _closeTime;
|
|
1394
|
+
this._ready = true;
|
|
1395
|
+
resolve(true);
|
|
1396
|
+
});
|
|
1397
|
+
});
|
|
1398
|
+
}
|
|
1399
|
+
get periods() {
|
|
1400
|
+
return this._periods;
|
|
1401
|
+
}
|
|
1402
|
+
async loadMarketData(source, tickerId, timeframe, limit, sDate, eDate) {
|
|
1403
|
+
if (Array.isArray(source)) {
|
|
1404
|
+
return source;
|
|
1405
|
+
} else {
|
|
1406
|
+
return source.getMarketData(tickerId, timeframe, limit, sDate, eDate);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
async ready() {
|
|
1410
|
+
if (this._ready) return true;
|
|
1411
|
+
if (!this._readyPromise) throw new Error("PineTS is not ready");
|
|
1412
|
+
return this._readyPromise;
|
|
1413
|
+
}
|
|
1414
|
+
async run(fn, n) {
|
|
1415
|
+
await this.ready();
|
|
1416
|
+
if (!n) n = this._periods;
|
|
1417
|
+
const context = new Context(this.data);
|
|
1418
|
+
context.timeframe = this.timeframe;
|
|
1419
|
+
const transformer = transpile.bind(this);
|
|
1420
|
+
let transformedFn = transformer(fn);
|
|
1421
|
+
const contextVarNames = ["const", "var", "let", "params"];
|
|
1422
|
+
for (let i = this._periods - n, idx = n - 1; i < this._periods; i++, idx--) {
|
|
1423
|
+
context.idx = i;
|
|
1424
|
+
context.data.close = this.close.slice(idx);
|
|
1425
|
+
context.data.open = this.open.slice(idx);
|
|
1426
|
+
context.data.high = this.high.slice(idx);
|
|
1427
|
+
context.data.low = this.low.slice(idx);
|
|
1428
|
+
context.data.volume = this.volume.slice(idx);
|
|
1429
|
+
context.data.hl2 = this.hl2.slice(idx);
|
|
1430
|
+
context.data.hlc3 = this.hlc3.slice(idx);
|
|
1431
|
+
context.data.ohlc4 = this.ohlc4.slice(idx);
|
|
1432
|
+
context.data.openTime = this.openTime.slice(idx);
|
|
1433
|
+
context.data.closeTime = this.closeTime.slice(idx);
|
|
1434
|
+
const result = await transformedFn(context);
|
|
1435
|
+
if (typeof result === "object") {
|
|
1436
|
+
if (typeof context.result !== "object") {
|
|
1437
|
+
context.result = {};
|
|
1438
|
+
}
|
|
1439
|
+
for (let key in result) {
|
|
1440
|
+
if (context.result[key] === void 0) {
|
|
1441
|
+
context.result[key] = [];
|
|
1442
|
+
}
|
|
1443
|
+
const val = Array.isArray(result[key]) ? result[key][0] : result[key];
|
|
1444
|
+
context.result[key].push(val);
|
|
1445
|
+
}
|
|
1446
|
+
} else {
|
|
1447
|
+
if (!Array.isArray(context.result)) {
|
|
1448
|
+
context.result = [];
|
|
1449
|
+
}
|
|
1450
|
+
context.result.push(result);
|
|
1451
|
+
}
|
|
1452
|
+
for (let ctxVarName of contextVarNames) {
|
|
1453
|
+
for (let key in context[ctxVarName]) {
|
|
1454
|
+
if (Array.isArray(context[ctxVarName][key])) {
|
|
1455
|
+
const val = context[ctxVarName][key][0];
|
|
1456
|
+
context[ctxVarName][key].unshift(val);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
return context;
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
var __defProp$3 = Object.defineProperty;
|
|
1466
|
+
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1467
|
+
var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1468
|
+
class Core {
|
|
1469
|
+
constructor(context) {
|
|
1470
|
+
this.context = context;
|
|
1471
|
+
__publicField$3(this, "color", {
|
|
1472
|
+
white: "white",
|
|
1473
|
+
lime: "lime",
|
|
1474
|
+
green: "green",
|
|
1475
|
+
red: "red",
|
|
1476
|
+
maroon: "maroon",
|
|
1477
|
+
black: "black",
|
|
1478
|
+
gray: "gray",
|
|
1479
|
+
blue: "blue"
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
extractPlotOptions(options) {
|
|
1483
|
+
const _options = {};
|
|
1484
|
+
for (let key in options) {
|
|
1485
|
+
if (Array.isArray(options[key])) {
|
|
1486
|
+
_options[key] = options[key][0];
|
|
1487
|
+
} else {
|
|
1488
|
+
_options[key] = options[key];
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
return _options;
|
|
1492
|
+
}
|
|
1493
|
+
indicator(title, shorttitle, options) {
|
|
1494
|
+
}
|
|
1495
|
+
//in the current implementation, plot functions are only used to collect data for the plots array and map it to the market data
|
|
1496
|
+
plotchar(series, title, options) {
|
|
1497
|
+
if (!this.context.plots[title]) {
|
|
1498
|
+
this.context.plots[title] = { data: [], options: this.extractPlotOptions(options), title };
|
|
1499
|
+
}
|
|
1500
|
+
this.context.plots[title].data.push({
|
|
1501
|
+
time: this.context.marketData[this.context.marketData.length - this.context.idx - 1].openTime,
|
|
1502
|
+
value: series[0],
|
|
1503
|
+
options: this.extractPlotOptions(options)
|
|
1504
|
+
});
|
|
1505
|
+
}
|
|
1506
|
+
plot(series, title, options) {
|
|
1507
|
+
if (!this.context.plots[title]) {
|
|
1508
|
+
this.context.plots[title] = { data: [], options: this.extractPlotOptions(options), title };
|
|
1509
|
+
}
|
|
1510
|
+
this.context.plots[title].data.push({
|
|
1511
|
+
time: this.context.marketData[this.context.marketData.length - this.context.idx - 1].openTime,
|
|
1512
|
+
value: series[0],
|
|
1513
|
+
options: this.extractPlotOptions(options)
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
na(series) {
|
|
1517
|
+
return Array.isArray(series) ? isNaN(series[0]) : isNaN(series);
|
|
1518
|
+
}
|
|
1519
|
+
nz(series, replacement = 0) {
|
|
1520
|
+
if (Array.isArray(series)) {
|
|
1521
|
+
return isNaN(series[0]) ? replacement : series[0];
|
|
1522
|
+
} else {
|
|
1523
|
+
return isNaN(series) ? replacement : series;
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
class Input {
|
|
1529
|
+
constructor(context) {
|
|
1530
|
+
this.context = context;
|
|
1531
|
+
}
|
|
1532
|
+
param(source, index = 0) {
|
|
1533
|
+
if (Array.isArray(source)) {
|
|
1534
|
+
return [source[index]];
|
|
1535
|
+
}
|
|
1536
|
+
return [source];
|
|
1537
|
+
}
|
|
1538
|
+
any(value, { title, group } = {}) {
|
|
1539
|
+
return Array.isArray(value) ? value[0] : value;
|
|
1540
|
+
}
|
|
1541
|
+
int(value, { title, group } = {}) {
|
|
1542
|
+
return Array.isArray(value) ? value[0] : value;
|
|
1543
|
+
}
|
|
1544
|
+
float(value, { title, group } = {}) {
|
|
1545
|
+
return Array.isArray(value) ? value[0] : value;
|
|
1546
|
+
}
|
|
1547
|
+
bool(value, { title, group } = {}) {
|
|
1548
|
+
return Array.isArray(value) ? value[0] : value;
|
|
1549
|
+
}
|
|
1550
|
+
string(value, { title, group } = {}) {
|
|
1551
|
+
return Array.isArray(value) ? value[0] : value;
|
|
1552
|
+
}
|
|
1553
|
+
timeframe(value, { title, group } = {}) {
|
|
1554
|
+
return Array.isArray(value) ? value[0] : value;
|
|
1555
|
+
}
|
|
1556
|
+
time(value, { title, group } = {}) {
|
|
1557
|
+
return Array.isArray(value) ? value[0] : value;
|
|
1558
|
+
}
|
|
1559
|
+
price(value, { title, group } = {}) {
|
|
1560
|
+
return Array.isArray(value) ? value[0] : value;
|
|
1561
|
+
}
|
|
1562
|
+
session(value, { title, group } = {}) {
|
|
1563
|
+
return Array.isArray(value) ? value[0] : value;
|
|
1564
|
+
}
|
|
1565
|
+
source(value, { title, group } = {}) {
|
|
1566
|
+
return Array.isArray(value) ? value[0] : value;
|
|
1567
|
+
}
|
|
1568
|
+
symbol(value, { title, group } = {}) {
|
|
1569
|
+
return Array.isArray(value) ? value[0] : value;
|
|
1570
|
+
}
|
|
1571
|
+
text_area(value, { title, group } = {}) {
|
|
1572
|
+
return Array.isArray(value) ? value[0] : value;
|
|
1573
|
+
}
|
|
1574
|
+
enum(value, { title, group } = {}) {
|
|
1575
|
+
return Array.isArray(value) ? value[0] : value;
|
|
1576
|
+
}
|
|
1577
|
+
color(value, { title, group } = {}) {
|
|
1578
|
+
return Array.isArray(value) ? value[0] : value;
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
var __defProp$2 = Object.defineProperty;
|
|
1583
|
+
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1584
|
+
var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1585
|
+
class PineMath {
|
|
1586
|
+
constructor(context) {
|
|
1587
|
+
this.context = context;
|
|
1588
|
+
__publicField$2(this, "_cache", {});
|
|
1589
|
+
}
|
|
1590
|
+
param(source, index = 0) {
|
|
1591
|
+
if (Array.isArray(source)) {
|
|
1592
|
+
return source[index];
|
|
1593
|
+
}
|
|
1594
|
+
return source;
|
|
1595
|
+
}
|
|
1596
|
+
abs(n) {
|
|
1597
|
+
return Math.abs(n);
|
|
1598
|
+
}
|
|
1599
|
+
pow(a, b) {
|
|
1600
|
+
return Math.pow(a, b);
|
|
1601
|
+
}
|
|
1602
|
+
sqrt(a) {
|
|
1603
|
+
return Math.sqrt(a);
|
|
1604
|
+
}
|
|
1605
|
+
log(a) {
|
|
1606
|
+
return Math.log(a);
|
|
1607
|
+
}
|
|
1608
|
+
ln(a) {
|
|
1609
|
+
return Math.log(a);
|
|
1610
|
+
}
|
|
1611
|
+
exp(a) {
|
|
1612
|
+
return Math.exp(a);
|
|
1613
|
+
}
|
|
1614
|
+
floor(a) {
|
|
1615
|
+
return Math.floor(a);
|
|
1616
|
+
}
|
|
1617
|
+
ceil(a) {
|
|
1618
|
+
return Math.ceil(a);
|
|
1619
|
+
}
|
|
1620
|
+
round(a) {
|
|
1621
|
+
return Math.round(a);
|
|
1622
|
+
}
|
|
1623
|
+
random() {
|
|
1624
|
+
return Math.random();
|
|
1625
|
+
}
|
|
1626
|
+
max(...args) {
|
|
1627
|
+
return Math.max(...args);
|
|
1628
|
+
}
|
|
1629
|
+
min(...args) {
|
|
1630
|
+
return Math.min(...args);
|
|
1631
|
+
}
|
|
1632
|
+
sin(a) {
|
|
1633
|
+
return Math.sin(a);
|
|
1634
|
+
}
|
|
1635
|
+
cos(a) {
|
|
1636
|
+
return Math.cos(a);
|
|
1637
|
+
}
|
|
1638
|
+
tan(a) {
|
|
1639
|
+
return Math.tan(a);
|
|
1640
|
+
}
|
|
1641
|
+
asin(a) {
|
|
1642
|
+
return Math.asin(a);
|
|
1643
|
+
}
|
|
1644
|
+
acos(a) {
|
|
1645
|
+
return Math.acos(a);
|
|
1646
|
+
}
|
|
1647
|
+
atan(a) {
|
|
1648
|
+
return Math.atan(a);
|
|
1649
|
+
}
|
|
1650
|
+
avg(...args) {
|
|
1651
|
+
return args.reduce((a, b) => {
|
|
1652
|
+
const aVal = Array.isArray(a) ? a[0] : a;
|
|
1653
|
+
const bVal = Array.isArray(b) ? b[0] : b;
|
|
1654
|
+
return aVal + bVal;
|
|
1655
|
+
}, 0) / args.length;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
var __defProp$1 = Object.defineProperty;
|
|
1660
|
+
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1661
|
+
var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1662
|
+
class PineRequest {
|
|
1663
|
+
constructor(context) {
|
|
1664
|
+
this.context = context;
|
|
1665
|
+
__publicField$1(this, "_cache", {});
|
|
1666
|
+
}
|
|
1667
|
+
param(source, index, name) {
|
|
1668
|
+
if (!this.context.params[name]) this.context.params[name] = [];
|
|
1669
|
+
if (Array.isArray(source)) {
|
|
1670
|
+
if (index) {
|
|
1671
|
+
this.context.params[name] = source.slice(index);
|
|
1672
|
+
} else {
|
|
1673
|
+
this.context.params[name] = source.slice(0);
|
|
1674
|
+
}
|
|
1675
|
+
return [source[index], name];
|
|
1676
|
+
} else {
|
|
1677
|
+
this.context.params[name][0] = source;
|
|
1678
|
+
return [source, name];
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
async security(symbol, timeframe, expression) {
|
|
1682
|
+
throw new Error("Not implemented");
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
class TechnicalAnalysis {
|
|
1687
|
+
constructor(context) {
|
|
1688
|
+
this.context = context;
|
|
1689
|
+
}
|
|
1690
|
+
get tr() {
|
|
1691
|
+
const val = this.context.math.max(
|
|
1692
|
+
this.context.data.high[0] - this.context.data.low[0],
|
|
1693
|
+
this.context.math.abs(this.context.data.high[0] - this.context.data.close[1]),
|
|
1694
|
+
this.context.math.abs(this.context.data.low[0] - this.context.data.close[1])
|
|
1695
|
+
);
|
|
1696
|
+
return val;
|
|
1697
|
+
}
|
|
1698
|
+
param(source, index, name) {
|
|
1699
|
+
if (!this.context.params[name]) this.context.params[name] = [];
|
|
1700
|
+
if (Array.isArray(source)) {
|
|
1701
|
+
if (index) {
|
|
1702
|
+
this.context.params[name] = source.slice(index);
|
|
1703
|
+
return this.context.params[name];
|
|
1704
|
+
}
|
|
1705
|
+
this.context.params[name] = source.slice(0);
|
|
1706
|
+
return this.context.params[name];
|
|
1707
|
+
} else {
|
|
1708
|
+
this.context.params[name][0] = source;
|
|
1709
|
+
return this.context.params[name];
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
ema(source, _period) {
|
|
1713
|
+
const period = Array.isArray(_period) ? _period[0] : _period;
|
|
1714
|
+
const result = ema(source.slice(0).reverse(), period);
|
|
1715
|
+
const idx = this.context.idx;
|
|
1716
|
+
return this.context.precision(result[idx]);
|
|
1717
|
+
}
|
|
1718
|
+
sma(source, _period) {
|
|
1719
|
+
const period = Array.isArray(_period) ? _period[0] : _period;
|
|
1720
|
+
const result = sma(source.slice(0).reverse(), period);
|
|
1721
|
+
const idx = this.context.idx;
|
|
1722
|
+
return this.context.precision(result[idx]);
|
|
1723
|
+
}
|
|
1724
|
+
vwma(source, _period) {
|
|
1725
|
+
const period = Array.isArray(_period) ? _period[0] : _period;
|
|
1726
|
+
const volume = this.context.data.volume;
|
|
1727
|
+
const result = vwma(source.slice(0).reverse(), volume.slice(0).reverse(), period);
|
|
1728
|
+
const idx = this.context.idx;
|
|
1729
|
+
return this.context.precision(result[idx]);
|
|
1730
|
+
}
|
|
1731
|
+
wma(source, _period) {
|
|
1732
|
+
const period = Array.isArray(_period) ? _period[0] : _period;
|
|
1733
|
+
const result = wma(source.slice(0).reverse(), period);
|
|
1734
|
+
const idx = this.context.idx;
|
|
1735
|
+
return this.context.precision(result[idx]);
|
|
1736
|
+
}
|
|
1737
|
+
hma(source, _period) {
|
|
1738
|
+
const period = Array.isArray(_period) ? _period[0] : _period;
|
|
1739
|
+
const result = hma(source.slice(0).reverse(), period);
|
|
1740
|
+
const idx = this.context.idx;
|
|
1741
|
+
return this.context.precision(result[idx]);
|
|
1742
|
+
}
|
|
1743
|
+
rma(source, _period) {
|
|
1744
|
+
const period = Array.isArray(_period) ? _period[0] : _period;
|
|
1745
|
+
const result = rma(source.slice(0).reverse(), period);
|
|
1746
|
+
const idx = this.context.idx;
|
|
1747
|
+
return this.context.precision(result[idx]);
|
|
1748
|
+
}
|
|
1749
|
+
change(source, _length = 1) {
|
|
1750
|
+
const length = Array.isArray(_length) ? _length[0] : _length;
|
|
1751
|
+
const result = change(source.slice(0).reverse(), length);
|
|
1752
|
+
const idx = this.context.idx;
|
|
1753
|
+
return this.context.precision(result[idx]);
|
|
1754
|
+
}
|
|
1755
|
+
rsi(source, _period) {
|
|
1756
|
+
const period = Array.isArray(_period) ? _period[0] : _period;
|
|
1757
|
+
const result = rsi(source.slice(0).reverse(), period);
|
|
1758
|
+
const idx = this.context.idx;
|
|
1759
|
+
return this.context.precision(result[idx]);
|
|
1760
|
+
}
|
|
1761
|
+
atr(_period) {
|
|
1762
|
+
const period = Array.isArray(_period) ? _period[0] : _period;
|
|
1763
|
+
const high = this.context.data.high.slice().reverse();
|
|
1764
|
+
const low = this.context.data.low.slice().reverse();
|
|
1765
|
+
const close = this.context.data.close.slice().reverse();
|
|
1766
|
+
const result = atr(high, low, close, period);
|
|
1767
|
+
const idx = this.context.idx;
|
|
1768
|
+
return this.context.precision(result[idx]);
|
|
1769
|
+
}
|
|
1770
|
+
mom(source, _length) {
|
|
1771
|
+
const length = Array.isArray(_length) ? _length[0] : _length;
|
|
1772
|
+
const result = mom(source.slice(0).reverse(), length);
|
|
1773
|
+
const idx = this.context.idx;
|
|
1774
|
+
return this.context.precision(result[idx]);
|
|
1775
|
+
}
|
|
1776
|
+
roc(source, _length) {
|
|
1777
|
+
const length = Array.isArray(_length) ? _length[0] : _length;
|
|
1778
|
+
const result = roc(source.slice(0).reverse(), length);
|
|
1779
|
+
const idx = this.context.idx;
|
|
1780
|
+
return this.context.precision(result[idx]);
|
|
1781
|
+
}
|
|
1782
|
+
dev(source, _length) {
|
|
1783
|
+
const length = Array.isArray(_length) ? _length[0] : _length;
|
|
1784
|
+
const result = dev(source.slice(0).reverse(), length);
|
|
1785
|
+
const idx = this.context.idx;
|
|
1786
|
+
return this.context.precision(result[idx]);
|
|
1787
|
+
}
|
|
1788
|
+
variance(source, _length) {
|
|
1789
|
+
const length = Array.isArray(_length) ? _length[0] : _length;
|
|
1790
|
+
const result = variance(source.slice(0).reverse(), length);
|
|
1791
|
+
const idx = this.context.idx;
|
|
1792
|
+
return this.context.precision(result[idx]);
|
|
1793
|
+
}
|
|
1794
|
+
highest(source, _length) {
|
|
1795
|
+
const length = Array.isArray(_length) ? _length[0] : _length;
|
|
1796
|
+
const result = highest(source.slice(0).reverse(), length);
|
|
1797
|
+
const idx = this.context.idx;
|
|
1798
|
+
return this.context.precision(result[idx]);
|
|
1799
|
+
}
|
|
1800
|
+
lowest(source, _length) {
|
|
1801
|
+
const length = Array.isArray(_length) ? _length[0] : _length;
|
|
1802
|
+
const result = lowest(source.slice(0).reverse(), length);
|
|
1803
|
+
const idx = this.context.idx;
|
|
1804
|
+
return this.context.precision(result[idx]);
|
|
1805
|
+
}
|
|
1806
|
+
median(source, _length) {
|
|
1807
|
+
const length = Array.isArray(_length) ? _length[0] : _length;
|
|
1808
|
+
const result = median(source.slice(0).reverse(), length);
|
|
1809
|
+
const idx = this.context.idx;
|
|
1810
|
+
return this.context.precision(result[idx]);
|
|
1811
|
+
}
|
|
1812
|
+
stdev(source, _length, _bias = true) {
|
|
1813
|
+
const length = Array.isArray(_length) ? _length[0] : _length;
|
|
1814
|
+
const bias = Array.isArray(_bias) ? _bias[0] : _bias;
|
|
1815
|
+
const result = stdev(source.slice(0).reverse(), length, bias);
|
|
1816
|
+
const idx = this.context.idx;
|
|
1817
|
+
return this.context.precision(result[idx]);
|
|
1818
|
+
}
|
|
1819
|
+
linreg(source, _length, _offset) {
|
|
1820
|
+
const length = Array.isArray(_length) ? _length[0] : _length;
|
|
1821
|
+
const offset = Array.isArray(_offset) ? _offset[0] : _offset;
|
|
1822
|
+
const result = linreg(source.slice(0).reverse(), length, offset);
|
|
1823
|
+
const idx = this.context.idx;
|
|
1824
|
+
return this.context.precision(result[idx]);
|
|
1825
|
+
}
|
|
1826
|
+
supertrend(_factor, _atrPeriod) {
|
|
1827
|
+
const factor = Array.isArray(_factor) ? _factor[0] : _factor;
|
|
1828
|
+
const atrPeriod = Array.isArray(_atrPeriod) ? _atrPeriod[0] : _atrPeriod;
|
|
1829
|
+
const high = this.context.data.high.slice().reverse();
|
|
1830
|
+
const low = this.context.data.low.slice().reverse();
|
|
1831
|
+
const close = this.context.data.close.slice().reverse();
|
|
1832
|
+
const [supertrend, direction] = calculateSupertrend(high, low, close, factor, atrPeriod);
|
|
1833
|
+
const idx = this.context.idx;
|
|
1834
|
+
return [[this.context.precision(supertrend[idx]), direction[idx]]];
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
function atr(high, low, close, period) {
|
|
1838
|
+
const tr = new Array(high.length);
|
|
1839
|
+
tr[0] = high[0] - low[0];
|
|
1840
|
+
for (let i = 1; i < high.length; i++) {
|
|
1841
|
+
const hl = high[i] - low[i];
|
|
1842
|
+
const hc = Math.abs(high[i] - close[i - 1]);
|
|
1843
|
+
const lc = Math.abs(low[i] - close[i - 1]);
|
|
1844
|
+
tr[i] = Math.max(hl, hc, lc);
|
|
1845
|
+
}
|
|
1846
|
+
const atr2 = new Array(high.length).fill(NaN);
|
|
1847
|
+
let sum = 0;
|
|
1848
|
+
for (let i = 0; i < period; i++) {
|
|
1849
|
+
sum += tr[i];
|
|
1850
|
+
}
|
|
1851
|
+
atr2[period - 1] = sum / period;
|
|
1852
|
+
for (let i = period; i < tr.length; i++) {
|
|
1853
|
+
atr2[i] = (atr2[i - 1] * (period - 1) + tr[i]) / period;
|
|
1854
|
+
}
|
|
1855
|
+
return atr2;
|
|
1856
|
+
}
|
|
1857
|
+
function ema(source, period) {
|
|
1858
|
+
const result = new Array(source.length).fill(NaN);
|
|
1859
|
+
const alpha = 2 / (period + 1);
|
|
1860
|
+
let sum = 0;
|
|
1861
|
+
for (let i = 0; i < period; i++) {
|
|
1862
|
+
sum += source[i] || 0;
|
|
1863
|
+
}
|
|
1864
|
+
result[period - 1] = sum / period;
|
|
1865
|
+
for (let i = period; i < source.length; i++) {
|
|
1866
|
+
result[i] = source[i] * alpha + result[i - 1] * (1 - alpha);
|
|
1867
|
+
}
|
|
1868
|
+
return result;
|
|
1869
|
+
}
|
|
1870
|
+
function rsi(source, period) {
|
|
1871
|
+
const result = new Array(source.length).fill(NaN);
|
|
1872
|
+
const gains = new Array(source.length).fill(0);
|
|
1873
|
+
const losses = new Array(source.length).fill(0);
|
|
1874
|
+
for (let i = 1; i < source.length; i++) {
|
|
1875
|
+
const diff = source[i] - source[i - 1];
|
|
1876
|
+
gains[i] = diff > 0 ? diff : 0;
|
|
1877
|
+
losses[i] = diff < 0 ? -diff : 0;
|
|
1878
|
+
}
|
|
1879
|
+
let avgGain = 0;
|
|
1880
|
+
let avgLoss = 0;
|
|
1881
|
+
for (let i = 1; i <= period; i++) {
|
|
1882
|
+
avgGain += gains[i];
|
|
1883
|
+
avgLoss += losses[i];
|
|
1884
|
+
}
|
|
1885
|
+
avgGain /= period;
|
|
1886
|
+
avgLoss /= period;
|
|
1887
|
+
result[period] = avgLoss === 0 ? 100 : 100 - 100 / (1 + avgGain / avgLoss);
|
|
1888
|
+
for (let i = period + 1; i < source.length; i++) {
|
|
1889
|
+
avgGain = (avgGain * (period - 1) + gains[i]) / period;
|
|
1890
|
+
avgLoss = (avgLoss * (period - 1) + losses[i]) / period;
|
|
1891
|
+
result[i] = avgLoss === 0 ? 100 : 100 - 100 / (1 + avgGain / avgLoss);
|
|
1892
|
+
}
|
|
1893
|
+
return result;
|
|
1894
|
+
}
|
|
1895
|
+
function rma(source, period) {
|
|
1896
|
+
const result = new Array(source.length).fill(NaN);
|
|
1897
|
+
const alpha = 1 / period;
|
|
1898
|
+
let sum = 0;
|
|
1899
|
+
for (let i = 0; i < period; i++) {
|
|
1900
|
+
sum += source[i] || 0;
|
|
1901
|
+
}
|
|
1902
|
+
result[period - 1] = sum / period;
|
|
1903
|
+
for (let i = period; i < source.length; i++) {
|
|
1904
|
+
const currentValue = source[i] || 0;
|
|
1905
|
+
result[i] = currentValue * alpha + result[i - 1] * (1 - alpha);
|
|
1906
|
+
}
|
|
1907
|
+
return result;
|
|
1908
|
+
}
|
|
1909
|
+
function sma(source, period) {
|
|
1910
|
+
const result = new Array(source.length).fill(NaN);
|
|
1911
|
+
for (let i = period - 1; i < source.length; i++) {
|
|
1912
|
+
let sum = 0;
|
|
1913
|
+
for (let j = 0; j < period; j++) {
|
|
1914
|
+
sum += source[i - j] || 0;
|
|
1915
|
+
}
|
|
1916
|
+
result[i] = sum / period;
|
|
1917
|
+
}
|
|
1918
|
+
return result;
|
|
1919
|
+
}
|
|
1920
|
+
function vwma(source, volume, period) {
|
|
1921
|
+
const result = new Array(source.length).fill(NaN);
|
|
1922
|
+
for (let i = period - 1; i < source.length; i++) {
|
|
1923
|
+
let sumVol = 0;
|
|
1924
|
+
let sumVolPrice = 0;
|
|
1925
|
+
for (let j = 0; j < period; j++) {
|
|
1926
|
+
sumVol += volume[i - j];
|
|
1927
|
+
sumVolPrice += source[i - j] * volume[i - j];
|
|
1928
|
+
}
|
|
1929
|
+
result[i] = sumVolPrice / sumVol;
|
|
1930
|
+
}
|
|
1931
|
+
return result;
|
|
1932
|
+
}
|
|
1933
|
+
function hma(source, period) {
|
|
1934
|
+
const halfPeriod = Math.floor(period / 2);
|
|
1935
|
+
const wma1 = wma(source, halfPeriod);
|
|
1936
|
+
const wma2 = wma(source, period);
|
|
1937
|
+
const rawHma = wma1.map((value, index) => 2 * value - wma2[index]);
|
|
1938
|
+
const sqrtPeriod = Math.floor(Math.sqrt(period));
|
|
1939
|
+
const result = wma(rawHma, sqrtPeriod);
|
|
1940
|
+
return result;
|
|
1941
|
+
}
|
|
1942
|
+
function wma(source, period) {
|
|
1943
|
+
const result = new Array(source.length);
|
|
1944
|
+
for (let i = period - 1; i < source.length; i++) {
|
|
1945
|
+
let numerator = 0;
|
|
1946
|
+
let denominator = 0;
|
|
1947
|
+
for (let j = 0; j < period; j++) {
|
|
1948
|
+
numerator += source[i - j] * (period - j);
|
|
1949
|
+
denominator += period - j;
|
|
1950
|
+
}
|
|
1951
|
+
result[i] = numerator / denominator;
|
|
1952
|
+
}
|
|
1953
|
+
for (let i = 0; i < period - 1; i++) {
|
|
1954
|
+
result[i] = NaN;
|
|
1955
|
+
}
|
|
1956
|
+
return result;
|
|
1957
|
+
}
|
|
1958
|
+
function change(source, length = 1) {
|
|
1959
|
+
const result = new Array(source.length).fill(NaN);
|
|
1960
|
+
for (let i = length; i < source.length; i++) {
|
|
1961
|
+
result[i] = source[i] - source[i - length];
|
|
1962
|
+
}
|
|
1963
|
+
return result;
|
|
1964
|
+
}
|
|
1965
|
+
function mom(source, length) {
|
|
1966
|
+
const result = new Array(source.length).fill(NaN);
|
|
1967
|
+
for (let i = length; i < source.length; i++) {
|
|
1968
|
+
result[i] = source[i] - source[i - length];
|
|
1969
|
+
}
|
|
1970
|
+
return result;
|
|
1971
|
+
}
|
|
1972
|
+
function roc(source, length) {
|
|
1973
|
+
const result = new Array(source.length).fill(NaN);
|
|
1974
|
+
for (let i = length; i < source.length; i++) {
|
|
1975
|
+
result[i] = (source[i] - source[i - length]) / source[i - length] * 100;
|
|
1976
|
+
}
|
|
1977
|
+
return result;
|
|
1978
|
+
}
|
|
1979
|
+
function dev(source, length) {
|
|
1980
|
+
const result = new Array(source.length).fill(NaN);
|
|
1981
|
+
const smaValues = sma(source, length);
|
|
1982
|
+
for (let i = length - 1; i < source.length; i++) {
|
|
1983
|
+
let sumDeviation = 0;
|
|
1984
|
+
for (let j = 0; j < length; j++) {
|
|
1985
|
+
sumDeviation += Math.abs(source[i - j] - smaValues[i]);
|
|
1986
|
+
}
|
|
1987
|
+
result[i] = sumDeviation / length;
|
|
1988
|
+
}
|
|
1989
|
+
return result;
|
|
1990
|
+
}
|
|
1991
|
+
function variance(source, length) {
|
|
1992
|
+
const result = new Array(source.length).fill(NaN);
|
|
1993
|
+
for (let i = length - 1; i < source.length; i++) {
|
|
1994
|
+
let sum = 0;
|
|
1995
|
+
let sumSquares = 0;
|
|
1996
|
+
for (let j = 0; j < length; j++) {
|
|
1997
|
+
sum += source[i - j];
|
|
1998
|
+
sumSquares += source[i - j] * source[i - j];
|
|
1999
|
+
}
|
|
2000
|
+
const mean = sum / length;
|
|
2001
|
+
result[i] = sumSquares / length - mean * mean;
|
|
2002
|
+
}
|
|
2003
|
+
return result;
|
|
2004
|
+
}
|
|
2005
|
+
function highest(source, length) {
|
|
2006
|
+
const result = new Array(source.length).fill(NaN);
|
|
2007
|
+
for (let i = length - 1; i < source.length; i++) {
|
|
2008
|
+
let max = -Infinity;
|
|
2009
|
+
for (let j = 0; j < length; j++) {
|
|
2010
|
+
const value = source[i - j];
|
|
2011
|
+
if (isNaN(value)) {
|
|
2012
|
+
max = max === -Infinity ? NaN : max;
|
|
2013
|
+
} else {
|
|
2014
|
+
max = Math.max(max, value);
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
result[i] = max;
|
|
2018
|
+
}
|
|
2019
|
+
return result;
|
|
2020
|
+
}
|
|
2021
|
+
function lowest(source, length) {
|
|
2022
|
+
const result = new Array(source.length).fill(NaN);
|
|
2023
|
+
for (let i = length - 1; i < source.length; i++) {
|
|
2024
|
+
let min = Infinity;
|
|
2025
|
+
for (let j = 0; j < length; j++) {
|
|
2026
|
+
const value = source[i - j];
|
|
2027
|
+
if (isNaN(value)) {
|
|
2028
|
+
min = min === Infinity ? NaN : min;
|
|
2029
|
+
} else {
|
|
2030
|
+
min = Math.min(min, value);
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
result[i] = min;
|
|
2034
|
+
}
|
|
2035
|
+
return result;
|
|
2036
|
+
}
|
|
2037
|
+
function median(source, length) {
|
|
2038
|
+
const result = new Array(source.length).fill(NaN);
|
|
2039
|
+
for (let i = length - 1; i < source.length; i++) {
|
|
2040
|
+
const window = source.slice(i - length + 1, i + 1);
|
|
2041
|
+
const sorted = window.slice().sort((a, b) => a - b);
|
|
2042
|
+
const mid = Math.floor(length / 2);
|
|
2043
|
+
result[i] = length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
|
|
2044
|
+
}
|
|
2045
|
+
return result;
|
|
2046
|
+
}
|
|
2047
|
+
function stdev(source, length, biased = true) {
|
|
2048
|
+
const result = new Array(source.length).fill(NaN);
|
|
2049
|
+
const smaValues = sma(source, length);
|
|
2050
|
+
for (let i = length - 1; i < source.length; i++) {
|
|
2051
|
+
let sum = 0;
|
|
2052
|
+
for (let j = 0; j < length; j++) {
|
|
2053
|
+
sum += Math.pow(source[i - j] - smaValues[i], 2);
|
|
2054
|
+
}
|
|
2055
|
+
const divisor = biased ? length : length - 1;
|
|
2056
|
+
result[i] = Math.sqrt(sum / divisor);
|
|
2057
|
+
}
|
|
2058
|
+
return result;
|
|
2059
|
+
}
|
|
2060
|
+
function linreg(source, length, offset) {
|
|
2061
|
+
const size = source.length;
|
|
2062
|
+
const output = new Array(size).fill(NaN);
|
|
2063
|
+
for (let i = length - 1; i < size; i++) {
|
|
2064
|
+
let sumX = 0;
|
|
2065
|
+
let sumY = 0;
|
|
2066
|
+
let sumXY = 0;
|
|
2067
|
+
let sumXX = 0;
|
|
2068
|
+
const n = length;
|
|
2069
|
+
for (let j = 0; j < length; j++) {
|
|
2070
|
+
const x = j;
|
|
2071
|
+
const y = source[i - length + 1 + j];
|
|
2072
|
+
sumX += x;
|
|
2073
|
+
sumY += y;
|
|
2074
|
+
sumXY += x * y;
|
|
2075
|
+
sumXX += x * x;
|
|
2076
|
+
}
|
|
2077
|
+
const denominator = n * sumXX - sumX * sumX;
|
|
2078
|
+
if (denominator === 0) {
|
|
2079
|
+
output[i] = NaN;
|
|
2080
|
+
continue;
|
|
2081
|
+
}
|
|
2082
|
+
const slope = (n * sumXY - sumX * sumY) / denominator;
|
|
2083
|
+
const intercept = (sumY - slope * sumX) / n;
|
|
2084
|
+
const linRegValue = intercept + slope * (length - 1 - offset);
|
|
2085
|
+
output[i] = linRegValue;
|
|
2086
|
+
}
|
|
2087
|
+
return output;
|
|
2088
|
+
}
|
|
2089
|
+
function calculateSupertrend(high, low, close, factor, atrPeriod) {
|
|
2090
|
+
const length = high.length;
|
|
2091
|
+
const supertrend = new Array(length).fill(NaN);
|
|
2092
|
+
const direction = new Array(length).fill(0);
|
|
2093
|
+
const atrValues = atr(high, low, close, atrPeriod);
|
|
2094
|
+
const upperBand = new Array(length).fill(NaN);
|
|
2095
|
+
const lowerBand = new Array(length).fill(NaN);
|
|
2096
|
+
for (let i = 0; i < length; i++) {
|
|
2097
|
+
const hl2 = (high[i] + low[i]) / 2;
|
|
2098
|
+
const atrValue = atrValues[i];
|
|
2099
|
+
if (!isNaN(atrValue)) {
|
|
2100
|
+
upperBand[i] = hl2 + factor * atrValue;
|
|
2101
|
+
lowerBand[i] = hl2 - factor * atrValue;
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
let prevUpperBand = upperBand[atrPeriod];
|
|
2105
|
+
let prevLowerBand = lowerBand[atrPeriod];
|
|
2106
|
+
let prevSupertrend = close[atrPeriod] <= prevUpperBand ? prevUpperBand : prevLowerBand;
|
|
2107
|
+
let prevDirection = close[atrPeriod] <= prevUpperBand ? -1 : 1;
|
|
2108
|
+
supertrend[atrPeriod] = prevSupertrend;
|
|
2109
|
+
direction[atrPeriod] = prevDirection;
|
|
2110
|
+
for (let i = atrPeriod + 1; i < length; i++) {
|
|
2111
|
+
let currentUpperBand = upperBand[i];
|
|
2112
|
+
if (currentUpperBand < prevUpperBand || close[i - 1] > prevUpperBand) {
|
|
2113
|
+
upperBand[i] = currentUpperBand;
|
|
2114
|
+
} else {
|
|
2115
|
+
upperBand[i] = prevUpperBand;
|
|
2116
|
+
}
|
|
2117
|
+
let currentLowerBand = lowerBand[i];
|
|
2118
|
+
if (currentLowerBand > prevLowerBand || close[i - 1] < prevLowerBand) {
|
|
2119
|
+
lowerBand[i] = currentLowerBand;
|
|
2120
|
+
} else {
|
|
2121
|
+
lowerBand[i] = prevLowerBand;
|
|
2122
|
+
}
|
|
2123
|
+
if (prevSupertrend === prevUpperBand) {
|
|
2124
|
+
if (close[i] > upperBand[i]) {
|
|
2125
|
+
direction[i] = 1;
|
|
2126
|
+
supertrend[i] = lowerBand[i];
|
|
2127
|
+
} else {
|
|
2128
|
+
direction[i] = -1;
|
|
2129
|
+
supertrend[i] = upperBand[i];
|
|
2130
|
+
}
|
|
2131
|
+
} else {
|
|
2132
|
+
if (close[i] < lowerBand[i]) {
|
|
2133
|
+
direction[i] = -1;
|
|
2134
|
+
supertrend[i] = upperBand[i];
|
|
2135
|
+
} else {
|
|
2136
|
+
direction[i] = 1;
|
|
2137
|
+
supertrend[i] = lowerBand[i];
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
prevUpperBand = upperBand[i];
|
|
2141
|
+
prevLowerBand = lowerBand[i];
|
|
2142
|
+
prevSupertrend = supertrend[i];
|
|
2143
|
+
}
|
|
2144
|
+
return [supertrend, direction];
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
var __defProp = Object.defineProperty;
|
|
2148
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
2149
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
2150
|
+
class Context {
|
|
2151
|
+
constructor(marketData) {
|
|
2152
|
+
this.marketData = marketData;
|
|
2153
|
+
__publicField(this, "data", {
|
|
2154
|
+
open: [],
|
|
2155
|
+
high: [],
|
|
2156
|
+
low: [],
|
|
2157
|
+
close: [],
|
|
2158
|
+
volume: [],
|
|
2159
|
+
hl2: [],
|
|
2160
|
+
hlc3: [],
|
|
2161
|
+
ohlc4: []
|
|
2162
|
+
});
|
|
2163
|
+
__publicField(this, "math");
|
|
2164
|
+
__publicField(this, "ta");
|
|
2165
|
+
__publicField(this, "input");
|
|
2166
|
+
__publicField(this, "request");
|
|
2167
|
+
__publicField(this, "core");
|
|
2168
|
+
__publicField(this, "idx", 0);
|
|
2169
|
+
__publicField(this, "params", {});
|
|
2170
|
+
__publicField(this, "const", {});
|
|
2171
|
+
__publicField(this, "var", {});
|
|
2172
|
+
__publicField(this, "let", {});
|
|
2173
|
+
__publicField(this, "result");
|
|
2174
|
+
__publicField(this, "plots", {});
|
|
2175
|
+
__publicField(this, "timeframe", "");
|
|
2176
|
+
this.math = new PineMath(this);
|
|
2177
|
+
this.ta = new TechnicalAnalysis(this);
|
|
2178
|
+
this.input = new Input(this);
|
|
2179
|
+
this.request = new PineRequest(this);
|
|
2180
|
+
const core = new Core(this);
|
|
2181
|
+
this.core = {
|
|
2182
|
+
plotchar: core.plotchar.bind(core),
|
|
2183
|
+
na: core.na.bind(core),
|
|
2184
|
+
color: core.color,
|
|
2185
|
+
plot: core.plot.bind(core),
|
|
2186
|
+
nz: core.nz.bind(core)
|
|
2187
|
+
};
|
|
2188
|
+
}
|
|
2189
|
+
//#region [Runtime functions] ===========================
|
|
2190
|
+
/**
|
|
2191
|
+
* this function is used to initialize the target variable with the source array
|
|
2192
|
+
* this array will represent a time series and its values will be shifted at runtime in order to mimic Pine script behavior
|
|
2193
|
+
* @param trg - the target variable name : used internally to maintain the series in the execution context
|
|
2194
|
+
* @param src - the source data, can be an array or a single value
|
|
2195
|
+
* @param idx - the index of the source array, used to get a sub-series of the source data
|
|
2196
|
+
* @returns the target array
|
|
2197
|
+
*/
|
|
2198
|
+
init(trg, src, idx = 0) {
|
|
2199
|
+
if (!trg) {
|
|
2200
|
+
if (Array.isArray(src)) {
|
|
2201
|
+
trg = [this.precision(src[src.length - this.idx - 1 + idx])];
|
|
2202
|
+
} else {
|
|
2203
|
+
trg = [this.precision(src)];
|
|
2204
|
+
}
|
|
2205
|
+
} else {
|
|
2206
|
+
if (!Array.isArray(src) || Array.isArray(src[0])) {
|
|
2207
|
+
trg[0] = Array.isArray(src?.[0]) ? src[0] : this.precision(src);
|
|
2208
|
+
} else {
|
|
2209
|
+
trg[0] = this.precision(src[src.length - this.idx - 1 + idx]);
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
return trg;
|
|
2213
|
+
}
|
|
2214
|
+
/**
|
|
2215
|
+
* this function is used to set the floating point precision of a number
|
|
2216
|
+
* by default it is set to 10 decimals which is the same as pine script
|
|
2217
|
+
* @param n - the number to be precision
|
|
2218
|
+
* @param decimals - the number of decimals to precision to
|
|
2219
|
+
* @returns the precision number
|
|
2220
|
+
*/
|
|
2221
|
+
precision(n, decimals = 10) {
|
|
2222
|
+
if (typeof n !== "number" || isNaN(n)) return n;
|
|
2223
|
+
return Number(n.toFixed(decimals));
|
|
2224
|
+
}
|
|
2225
|
+
/**
|
|
2226
|
+
* This function is used to apply special transformation to internal PineTS parameters and handle them as time-series
|
|
2227
|
+
* @param source - the source data, can be an array or a single value
|
|
2228
|
+
* @param index - the index of the source array, used to get a sub-series of the source data
|
|
2229
|
+
* @param name - the name of the parameter, used as a unique identifier in the current execution context, this allows us to properly handle the param as a series
|
|
2230
|
+
* @returns the current value of the param
|
|
2231
|
+
*/
|
|
2232
|
+
param(source, index, name) {
|
|
2233
|
+
if (typeof source === "string") return source;
|
|
2234
|
+
if (!Array.isArray(source) && typeof source === "object") return source;
|
|
2235
|
+
if (!this.params[name]) this.params[name] = [];
|
|
2236
|
+
if (Array.isArray(source)) {
|
|
2237
|
+
if (index) {
|
|
2238
|
+
this.params[name] = source.slice(index);
|
|
2239
|
+
return this.params[name];
|
|
2240
|
+
}
|
|
2241
|
+
this.params[name] = source.slice(0);
|
|
2242
|
+
return this.params[name];
|
|
2243
|
+
} else {
|
|
2244
|
+
this.params[name][0] = source;
|
|
2245
|
+
return this.params[name];
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
//#endregion
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
const BINANCE_API_URL = "https://api.binance.com/api/v3";
|
|
2252
|
+
const timeframe_to_binance = {
|
|
2253
|
+
"1": "1m",
|
|
2254
|
+
// 1 minute
|
|
2255
|
+
"3": "3m",
|
|
2256
|
+
// 3 minutes
|
|
2257
|
+
"5": "5m",
|
|
2258
|
+
// 5 minutes
|
|
2259
|
+
"15": "15m",
|
|
2260
|
+
// 15 minutes
|
|
2261
|
+
"30": "30m",
|
|
2262
|
+
// 30 minutes
|
|
2263
|
+
"45": null,
|
|
2264
|
+
// 45 minutes (not directly supported by Binance, needs custom handling)
|
|
2265
|
+
"60": "1h",
|
|
2266
|
+
// 1 hour
|
|
2267
|
+
"120": "2h",
|
|
2268
|
+
// 2 hours
|
|
2269
|
+
"180": null,
|
|
2270
|
+
// 3 hours (not directly supported by Binance, needs custom handling)
|
|
2271
|
+
"240": "4h",
|
|
2272
|
+
// 4 hours
|
|
2273
|
+
"1D": "1d",
|
|
2274
|
+
// 1 day
|
|
2275
|
+
D: "1d",
|
|
2276
|
+
// 1 day
|
|
2277
|
+
"1W": "1w",
|
|
2278
|
+
// 1 week
|
|
2279
|
+
W: "1w",
|
|
2280
|
+
// 1 week
|
|
2281
|
+
"1M": "1M",
|
|
2282
|
+
// 1 month
|
|
2283
|
+
M: "1M"
|
|
2284
|
+
// 1 month
|
|
2285
|
+
};
|
|
2286
|
+
class BinanceProvider {
|
|
2287
|
+
async getMarketData(tickerId, timeframe, limit, sDate, eDate) {
|
|
2288
|
+
try {
|
|
2289
|
+
const interval = timeframe_to_binance[timeframe.toUpperCase()];
|
|
2290
|
+
if (!interval) {
|
|
2291
|
+
console.error(`Unsupported timeframe: ${timeframe}`);
|
|
2292
|
+
return [];
|
|
2293
|
+
}
|
|
2294
|
+
let url = `${BINANCE_API_URL}/klines?symbol=${tickerId}&interval=${interval}`;
|
|
2295
|
+
if (limit) {
|
|
2296
|
+
url += `&limit=${limit}`;
|
|
2297
|
+
}
|
|
2298
|
+
if (sDate) {
|
|
2299
|
+
url += `&startTime=${sDate}`;
|
|
2300
|
+
}
|
|
2301
|
+
if (eDate) {
|
|
2302
|
+
url += `&endTime=${eDate}`;
|
|
2303
|
+
}
|
|
2304
|
+
const response = await fetch(url);
|
|
2305
|
+
if (!response.ok) {
|
|
2306
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
2307
|
+
}
|
|
2308
|
+
const result = await response.json();
|
|
2309
|
+
const data = result.map((item) => {
|
|
2310
|
+
return {
|
|
2311
|
+
openTime: parseInt(item[0]) / 1e3,
|
|
2312
|
+
open: parseFloat(item[1]),
|
|
2313
|
+
high: parseFloat(item[2]),
|
|
2314
|
+
low: parseFloat(item[3]),
|
|
2315
|
+
close: parseFloat(item[4]),
|
|
2316
|
+
volume: parseFloat(item[5]),
|
|
2317
|
+
closeTime: parseInt(item[6]) / 1e3,
|
|
2318
|
+
quoteAssetVolume: parseFloat(item[7]),
|
|
2319
|
+
numberOfTrades: parseInt(item[8]),
|
|
2320
|
+
takerBuyBaseAssetVolume: parseFloat(item[9]),
|
|
2321
|
+
takerBuyQuoteAssetVolume: parseFloat(item[10]),
|
|
2322
|
+
ignore: item[11]
|
|
2323
|
+
};
|
|
2324
|
+
});
|
|
2325
|
+
return data;
|
|
2326
|
+
} catch (error) {
|
|
2327
|
+
console.error("Error in binance.klines:", error);
|
|
2328
|
+
return [];
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
const Provider = {
|
|
2334
|
+
Binance: new BinanceProvider()
|
|
2335
|
+
};
|
|
2336
|
+
|
|
2337
|
+
export { Context, PineTS, Provider };
|
|
2338
|
+
//# sourceMappingURL=pinets.dev.es.js.map
|