pinets 0.1.1 → 0.1.33

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.
@@ -1,24 +1,42 @@
1
+
2
+ /*
3
+ * Copyright (C) 2025 Alaa-eddine KADDOURI
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Affero General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU Affero General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License
16
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ */
1
18
  import * as acorn from 'acorn';
2
19
  import * as walk from 'acorn-walk';
3
20
  import * as astring from 'astring';
4
21
 
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);
22
+ var __defProp$7 = Object.defineProperty;
23
+ var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
24
+ var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
8
25
  class ScopeManager {
9
26
  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());
27
+ __publicField$7(this, "scopes", []);
28
+ __publicField$7(this, "scopeTypes", []);
29
+ __publicField$7(this, "scopeCounts", /* @__PURE__ */ new Map());
30
+ __publicField$7(this, "contextBoundVars", /* @__PURE__ */ new Set());
31
+ __publicField$7(this, "arrayPatternElements", /* @__PURE__ */ new Set());
32
+ __publicField$7(this, "rootParams", /* @__PURE__ */ new Set());
33
+ __publicField$7(this, "varKinds", /* @__PURE__ */ new Map());
34
+ __publicField$7(this, "loopVars", /* @__PURE__ */ new Set());
35
+ __publicField$7(this, "loopVarNames", /* @__PURE__ */ new Map());
19
36
  // Map original names to transformed names
20
- __publicField$5(this, "paramIdCounter", 0);
21
- __publicField$5(this, "tempVarCounter", 0);
37
+ __publicField$7(this, "paramIdCounter", 0);
38
+ __publicField$7(this, "cacheIdCounter", 0);
39
+ __publicField$7(this, "tempVarCounter", 0);
22
40
  this.pushScope("glb");
23
41
  }
24
42
  get nextParamIdArg() {
@@ -27,6 +45,12 @@ class ScopeManager {
27
45
  name: `'p${this.paramIdCounter++}'`
28
46
  };
29
47
  }
48
+ get nextCacheIdArg() {
49
+ return {
50
+ type: "Identifier",
51
+ name: `'cache_${this.cacheIdCounter++}'`
52
+ };
53
+ }
30
54
  pushScope(type) {
31
55
  this.scopes.push(/* @__PURE__ */ new Map());
32
56
  this.scopeTypes.push(type);
@@ -204,6 +228,9 @@ function transformMemberExpression(memberNode, originalParamName, scopeManager)
204
228
  }
205
229
  function transformVariableDeclaration(varNode, scopeManager) {
206
230
  varNode.declarations.forEach((decl) => {
231
+ if (decl.init.name == "na") {
232
+ decl.init.name = "NaN";
233
+ }
207
234
  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
235
  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
236
  const isArrowFunction = decl.init && decl.init.type === "ArrowFunctionExpression";
@@ -366,7 +393,28 @@ function transformVariableDeclaration(varNode, scopeManager) {
366
393
  }
367
394
  };
368
395
  if (isArrayPatternVar) {
369
- assignmentExpr.expression.right.object.property.name += "?.[0]";
396
+ assignmentExpr.expression.right.object.property.name += `?.[0][${decl.init.property.value}]`;
397
+ const obj = assignmentExpr.expression.right.object;
398
+ assignmentExpr.expression.right = {
399
+ type: "CallExpression",
400
+ callee: {
401
+ type: "MemberExpression",
402
+ object: {
403
+ type: "Identifier",
404
+ name: CONTEXT_NAME
405
+ },
406
+ property: {
407
+ type: "Identifier",
408
+ name: "init"
409
+ },
410
+ computed: false
411
+ },
412
+ arguments: [
413
+ targetVarRef,
414
+ obj
415
+ /*, decl.init.property.value*/
416
+ ]
417
+ };
370
418
  }
371
419
  if (isArrowFunction) {
372
420
  scopeManager.pushScope("fn");
@@ -519,14 +567,22 @@ function transformAssignmentExpression(node, scopeManager) {
519
567
  { parent: node.right, inNamespaceCall: false },
520
568
  {
521
569
  Identifier(node2, state, c) {
570
+ if (node2.name == "na") {
571
+ node2.name = "NaN";
572
+ }
522
573
  node2.parent = state.parent;
523
574
  transformIdentifier(node2, scopeManager);
524
575
  const isBinaryOperation = node2.parent && node2.parent.type === "BinaryExpression";
525
576
  const isConditional = node2.parent && node2.parent.type === "ConditionalExpression";
526
- if (isConditional || isBinaryOperation) {
577
+ const isContextBound = scopeManager.isContextBound(node2.name) && !scopeManager.isRootParam(node2.name);
578
+ const hasArrayAccess = node2.parent && node2.parent.type === "MemberExpression" && node2.parent.computed && node2.parent.object === node2;
579
+ const isParamCall = node2.parent && node2.parent._isParamCall;
580
+ const isMemberExpression = node2.parent && node2.parent.type === "MemberExpression";
581
+ const isReserved = node2.name === "NaN";
582
+ if (isContextBound || isConditional || isBinaryOperation) {
527
583
  if (node2.type === "MemberExpression") {
528
584
  transformArrayIndex(node2, scopeManager);
529
- } else if (node2.type === "Identifier") {
585
+ } else if (node2.type === "Identifier" && !isMemberExpression && !hasArrayAccess && !isParamCall && !isReserved) {
530
586
  addArrayAccess(node2);
531
587
  }
532
588
  }
@@ -708,6 +764,10 @@ function transformReturnStatement(node, scopeManager) {
708
764
  }
709
765
  function transformIdentifierForParam(node, scopeManager) {
710
766
  if (node.type === "Identifier") {
767
+ if (node.name === "na") {
768
+ node.name = "NaN";
769
+ return node;
770
+ }
711
771
  if (scopeManager.isLoopVariable(node.name)) {
712
772
  return node;
713
773
  }
@@ -761,40 +821,58 @@ function transformIdentifierForParam(node, scopeManager) {
761
821
  }
762
822
  return node;
763
823
  }
824
+ function getParamFromUnaryExpression(node, scopeManager, namespace) {
825
+ const transformedArgument = transformOperand(node.argument, scopeManager, namespace);
826
+ const unaryExpr = {
827
+ type: "UnaryExpression",
828
+ operator: node.operator,
829
+ prefix: node.prefix,
830
+ argument: transformedArgument,
831
+ start: node.start,
832
+ end: node.end
833
+ };
834
+ return unaryExpr;
835
+ }
764
836
  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;
837
+ switch (node.type) {
838
+ case "BinaryExpression": {
839
+ return getParamFromBinaryExpression(node, scopeManager, namespace);
779
840
  }
780
- const isMemberExprProperty = node.parent && node.parent.type === "MemberExpression" && node.parent.property === node;
781
- if (isMemberExprProperty) {
782
- return node;
841
+ case "MemberExpression": {
842
+ const transformedObject = node.object.type === "Identifier" ? transformIdentifierForParam(node.object, scopeManager) : node.object;
843
+ return {
844
+ type: "MemberExpression",
845
+ object: transformedObject,
846
+ property: node.property,
847
+ computed: node.computed
848
+ };
849
+ }
850
+ case "Identifier": {
851
+ if (scopeManager.isLoopVariable(node.name)) {
852
+ return node;
853
+ }
854
+ const isMemberExprProperty = node.parent && node.parent.type === "MemberExpression" && node.parent.property === node;
855
+ if (isMemberExprProperty) {
856
+ return node;
857
+ }
858
+ const transformedObject = transformIdentifierForParam(node, scopeManager);
859
+ return {
860
+ type: "MemberExpression",
861
+ object: transformedObject,
862
+ property: {
863
+ type: "Literal",
864
+ value: 0
865
+ },
866
+ computed: true
867
+ };
868
+ }
869
+ case "UnaryExpression": {
870
+ return getParamFromUnaryExpression(node, scopeManager, namespace);
783
871
  }
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
872
  }
795
873
  return node;
796
874
  }
797
- function transformBinaryExpression(node, scopeManager, namespace) {
875
+ function getParamFromBinaryExpression(node, scopeManager, namespace) {
798
876
  const transformedLeft = transformOperand(node.left, scopeManager, namespace);
799
877
  const transformedRight = transformOperand(node.right, scopeManager, namespace);
800
878
  const binaryExpr = {
@@ -815,28 +893,89 @@ function transformBinaryExpression(node, scopeManager, namespace) {
815
893
  transformMemberExpression(node2, "", scopeManager);
816
894
  }
817
895
  });
896
+ return binaryExpr;
897
+ }
898
+ function getParamFromLogicalExpression(node, scopeManager, namespace) {
899
+ const transformedLeft = transformOperand(node.left, scopeManager, namespace);
900
+ const transformedRight = transformOperand(node.right, scopeManager, namespace);
901
+ const logicalExpr = {
902
+ type: "LogicalExpression",
903
+ operator: node.operator,
904
+ left: transformedLeft,
905
+ right: transformedRight,
906
+ start: node.start,
907
+ end: node.end
908
+ };
909
+ walk.recursive(logicalExpr, scopeManager, {
910
+ CallExpression(node2, scopeManager2) {
911
+ if (!node2._transformed) {
912
+ transformCallExpression(node2, scopeManager2);
913
+ }
914
+ }
915
+ });
916
+ return logicalExpr;
917
+ }
918
+ function getParamFromConditionalExpression(node, scopeManager, namespace) {
919
+ walk.recursive(
920
+ node,
921
+ { parent: node, inNamespaceCall: false },
922
+ {
923
+ Identifier(node2, state, c) {
924
+ if (node2.name == "NaN") return;
925
+ if (node2.name == "na") {
926
+ node2.name = "NaN";
927
+ return;
928
+ }
929
+ node2.parent = state.parent;
930
+ transformIdentifier(node2, scopeManager);
931
+ const isBinaryOperation = node2.parent && node2.parent.type === "BinaryExpression";
932
+ const isConditional = node2.parent && node2.parent.type === "ConditionalExpression";
933
+ if (isConditional || isBinaryOperation) {
934
+ if (node2.type === "MemberExpression") {
935
+ transformArrayIndex(node2, scopeManager);
936
+ } else if (node2.type === "Identifier") {
937
+ addArrayAccess(node2);
938
+ }
939
+ }
940
+ },
941
+ MemberExpression(node2, state, c) {
942
+ transformArrayIndex(node2, scopeManager);
943
+ if (node2.object) {
944
+ c(node2.object, { parent: node2, inNamespaceCall: state.inNamespaceCall });
945
+ }
946
+ },
947
+ CallExpression(node2, state, c) {
948
+ const isNamespaceCall = node2.callee && node2.callee.type === "MemberExpression" && node2.callee.object && node2.callee.object.type === "Identifier" && scopeManager.isContextBound(node2.callee.object.name);
949
+ transformCallExpression(node2, scopeManager);
950
+ node2.arguments.forEach((arg) => c(arg, { parent: node2, inNamespaceCall: isNamespaceCall || state.inNamespaceCall }));
951
+ }
952
+ }
953
+ );
818
954
  return {
819
955
  type: "CallExpression",
820
956
  callee: {
821
957
  type: "MemberExpression",
822
- object: {
823
- type: "Identifier",
824
- name: namespace
825
- },
826
- property: {
827
- type: "Identifier",
828
- name: "param"
829
- },
830
- computed: false
958
+ object: { type: "Identifier", name: namespace },
959
+ property: { type: "Identifier", name: "param" }
831
960
  },
832
- arguments: [binaryExpr, UNDEFINED_ARG, scopeManager.nextParamIdArg],
961
+ arguments: [node, UNDEFINED_ARG, scopeManager.nextParamIdArg],
833
962
  _transformed: true,
834
963
  _isParamCall: true
835
964
  };
836
965
  }
837
966
  function transformFunctionArgument(arg, namespace, scopeManager) {
838
- if (arg.type === "BinaryExpression") {
839
- return transformBinaryExpression(arg, scopeManager, namespace);
967
+ switch (arg?.type) {
968
+ case "BinaryExpression":
969
+ arg = getParamFromBinaryExpression(arg, scopeManager, namespace);
970
+ break;
971
+ case "LogicalExpression":
972
+ arg = getParamFromLogicalExpression(arg, scopeManager, namespace);
973
+ break;
974
+ case "ConditionalExpression":
975
+ return getParamFromConditionalExpression(arg, scopeManager, namespace);
976
+ case "UnaryExpression":
977
+ arg = getParamFromUnaryExpression(arg, scopeManager, namespace);
978
+ break;
840
979
  }
841
980
  const isArrayAccess = arg.type === "MemberExpression" && arg.computed && arg.property;
842
981
  if (isArrayAccess) {
@@ -901,6 +1040,10 @@ function transformFunctionArgument(arg, namespace, scopeManager) {
901
1040
  });
902
1041
  }
903
1042
  if (arg.type === "Identifier") {
1043
+ if (arg.name === "na") {
1044
+ arg.name = "NaN";
1045
+ return arg;
1046
+ }
904
1047
  if (scopeManager.isContextBound(arg.name) && !scopeManager.isRootParam(arg.name)) {
905
1048
  return {
906
1049
  type: "CallExpression",
@@ -944,18 +1087,18 @@ function transformFunctionArgument(arg, namespace, scopeManager) {
944
1087
  _isParamCall: true
945
1088
  };
946
1089
  }
947
- function transformCallExpression(node, scopeManager) {
1090
+ function transformCallExpression(node, scopeManager, namespace) {
948
1091
  if (node._transformed) {
949
1092
  return;
950
1093
  }
951
1094
  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
1095
  if (isNamespaceCall) {
953
- const namespace = node.callee.object.name;
1096
+ const namespace2 = node.callee.object.name;
954
1097
  node.arguments = node.arguments.map((arg) => {
955
1098
  if (arg._isParamCall) {
956
1099
  return arg;
957
1100
  }
958
- return transformFunctionArgument(arg, namespace, scopeManager);
1101
+ return transformFunctionArgument(arg, namespace2, scopeManager);
959
1102
  });
960
1103
  node._transformed = true;
961
1104
  } else if (node.callee && node.callee.type === "Identifier") {
@@ -969,13 +1112,29 @@ function transformCallExpression(node, scopeManager) {
969
1112
  }
970
1113
  node.arguments.forEach((arg) => {
971
1114
  walk.recursive(arg, scopeManager, {
972
- CallExpression(node2, state) {
1115
+ Identifier(node2, state, c) {
1116
+ node2.parent = state.parent;
1117
+ transformIdentifier(node2, scopeManager);
1118
+ const isBinaryOperation = node2.parent && node2.parent.type === "BinaryExpression";
1119
+ const isConditional = node2.parent && node2.parent.type === "ConditionalExpression";
1120
+ if (isConditional || isBinaryOperation) {
1121
+ if (node2.type === "MemberExpression") {
1122
+ transformArrayIndex(node2, scopeManager);
1123
+ } else if (node2.type === "Identifier") {
1124
+ addArrayAccess(node2);
1125
+ }
1126
+ }
1127
+ },
1128
+ CallExpression(node2, state, c) {
973
1129
  if (!node2._transformed) {
974
1130
  transformCallExpression(node2, state);
975
1131
  }
976
1132
  },
977
- MemberExpression(node2) {
1133
+ MemberExpression(node2, state, c) {
978
1134
  transformMemberExpression(node2, "", scopeManager);
1135
+ if (node2.object) {
1136
+ c(node2.object, { parent: node2, inNamespaceCall: state.inNamespaceCall });
1137
+ }
979
1138
  }
980
1139
  });
981
1140
  });
@@ -1336,9 +1495,9 @@ function transpile(fn) {
1336
1495
  return _wraperFunction(this);
1337
1496
  }
1338
1497
 
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);
1498
+ var __defProp$6 = Object.defineProperty;
1499
+ var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1500
+ var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
1342
1501
  class PineTS {
1343
1502
  constructor(source, tickerId, timeframe, limit, sDate, eDate) {
1344
1503
  this.source = source;
@@ -1347,25 +1506,25 @@ class PineTS {
1347
1506
  this.limit = limit;
1348
1507
  this.sDate = sDate;
1349
1508
  this.eDate = eDate;
1350
- __publicField$4(this, "data", []);
1509
+ __publicField$6(this, "data", []);
1351
1510
  //#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", []);
1511
+ __publicField$6(this, "open", []);
1512
+ __publicField$6(this, "high", []);
1513
+ __publicField$6(this, "low", []);
1514
+ __publicField$6(this, "close", []);
1515
+ __publicField$6(this, "volume", []);
1516
+ __publicField$6(this, "hl2", []);
1517
+ __publicField$6(this, "hlc3", []);
1518
+ __publicField$6(this, "ohlc4", []);
1519
+ __publicField$6(this, "openTime", []);
1520
+ __publicField$6(this, "closeTime", []);
1362
1521
  //#endregion
1363
1522
  //#region run context
1364
- __publicField$4(this, "_periods");
1523
+ __publicField$6(this, "_periods");
1365
1524
  //#endregion
1366
1525
  //public fn: Function;
1367
- __publicField$4(this, "_readyPromise", null);
1368
- __publicField$4(this, "_ready", false);
1526
+ __publicField$6(this, "_readyPromise", null);
1527
+ __publicField$6(this, "_ready", false);
1369
1528
  this._readyPromise = new Promise((resolve) => {
1370
1529
  this.loadMarketData(source, tickerId, timeframe, limit, sDate, eDate).then((data) => {
1371
1530
  const marketData = data.reverse();
@@ -1411,13 +1570,22 @@ class PineTS {
1411
1570
  if (!this._readyPromise) throw new Error("PineTS is not ready");
1412
1571
  return this._readyPromise;
1413
1572
  }
1414
- async run(fn, n) {
1573
+ async run(pineTSCode, n, useTACache) {
1415
1574
  await this.ready();
1416
1575
  if (!n) n = this._periods;
1417
- const context = new Context(this.data);
1418
- context.timeframe = this.timeframe;
1576
+ const context = new Context({
1577
+ marketData: this.data,
1578
+ source: this.source,
1579
+ tickerId: this.tickerId,
1580
+ timeframe: this.timeframe,
1581
+ limit: this.limit,
1582
+ sDate: this.sDate,
1583
+ eDate: this.eDate
1584
+ });
1585
+ context.pineTSCode = pineTSCode;
1586
+ context.useTACache = useTACache;
1419
1587
  const transformer = transpile.bind(this);
1420
- let transformedFn = transformer(fn);
1588
+ let transpiledFn = transformer(pineTSCode);
1421
1589
  const contextVarNames = ["const", "var", "let", "params"];
1422
1590
  for (let i = this._periods - n, idx = n - 1; i < this._periods; i++, idx--) {
1423
1591
  context.idx = i;
@@ -1431,7 +1599,7 @@ class PineTS {
1431
1599
  context.data.ohlc4 = this.ohlc4.slice(idx);
1432
1600
  context.data.openTime = this.openTime.slice(idx);
1433
1601
  context.data.closeTime = this.closeTime.slice(idx);
1434
- const result = await transformedFn(context);
1602
+ const result = await transpiledFn(context);
1435
1603
  if (typeof result === "object") {
1436
1604
  if (typeof context.result !== "object") {
1437
1605
  context.result = {};
@@ -1462,13 +1630,30 @@ class PineTS {
1462
1630
  }
1463
1631
  }
1464
1632
 
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);
1633
+ var __defProp$5 = Object.defineProperty;
1634
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1635
+ var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
1468
1636
  class Core {
1469
1637
  constructor(context) {
1470
1638
  this.context = context;
1471
- __publicField$3(this, "color", {
1639
+ __publicField$5(this, "color", {
1640
+ param: (source, index = 0) => {
1641
+ if (Array.isArray(source)) {
1642
+ return source[index];
1643
+ }
1644
+ return source;
1645
+ },
1646
+ rgb: (r, g, b, a) => a ? `rgba(${r}, ${g}, ${b}, ${a})` : `rgb(${r}, ${g}, ${b})`,
1647
+ new: (color, a) => {
1648
+ if (color && color.startsWith("#")) {
1649
+ const hex = color.slice(1);
1650
+ const r = parseInt(hex.slice(0, 2), 16);
1651
+ const g = parseInt(hex.slice(2, 4), 16);
1652
+ const b = parseInt(hex.slice(4, 6), 16);
1653
+ return a ? `rgba(${r}, ${g}, ${b}, ${a})` : `rgb(${r}, ${g}, ${b})`;
1654
+ }
1655
+ return a ? `rgba(${color}, ${a})` : color;
1656
+ },
1472
1657
  white: "white",
1473
1658
  lime: "lime",
1474
1659
  green: "green",
@@ -1500,7 +1685,7 @@ class Core {
1500
1685
  this.context.plots[title].data.push({
1501
1686
  time: this.context.marketData[this.context.marketData.length - this.context.idx - 1].openTime,
1502
1687
  value: series[0],
1503
- options: this.extractPlotOptions(options)
1688
+ options: { ...this.extractPlotOptions(options), style: "char" }
1504
1689
  });
1505
1690
  }
1506
1691
  plot(series, title, options) {
@@ -1517,11 +1702,9 @@ class Core {
1517
1702
  return Array.isArray(series) ? isNaN(series[0]) : isNaN(series);
1518
1703
  }
1519
1704
  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
- }
1705
+ const val = Array.isArray(series) ? series[0] : series;
1706
+ const rep = Array.isArray(series) ? replacement[0] : replacement;
1707
+ return isNaN(val) ? rep : val;
1525
1708
  }
1526
1709
  }
1527
1710
 
@@ -1579,75 +1762,95 @@ class Input {
1579
1762
  }
1580
1763
  }
1581
1764
 
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);
1765
+ var __defProp$4 = Object.defineProperty;
1766
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1767
+ var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
1585
1768
  class PineMath {
1586
1769
  constructor(context) {
1587
1770
  this.context = context;
1588
- __publicField$2(this, "_cache", {});
1771
+ __publicField$4(this, "_cache", {});
1589
1772
  }
1590
- param(source, index = 0) {
1773
+ param(source, index, name) {
1774
+ if (!this.context.params[name]) this.context.params[name] = [];
1591
1775
  if (Array.isArray(source)) {
1592
- return source[index];
1776
+ if (index) {
1777
+ this.context.params[name] = source.slice(index);
1778
+ this.context.params[name].length = source.length;
1779
+ return this.context.params[name];
1780
+ }
1781
+ this.context.params[name] = source.slice(0);
1782
+ return this.context.params[name];
1783
+ } else {
1784
+ this.context.params[name][0] = source;
1785
+ return this.context.params[name];
1593
1786
  }
1594
- return source;
1595
1787
  }
1596
- abs(n) {
1597
- return Math.abs(n);
1788
+ abs(source) {
1789
+ return Math.abs(source[0]);
1598
1790
  }
1599
- pow(a, b) {
1600
- return Math.pow(a, b);
1791
+ pow(source, power) {
1792
+ return Math.pow(source[0], power[0]);
1601
1793
  }
1602
- sqrt(a) {
1603
- return Math.sqrt(a);
1794
+ sqrt(source) {
1795
+ return Math.sqrt(source[0]);
1604
1796
  }
1605
- log(a) {
1606
- return Math.log(a);
1797
+ log(source) {
1798
+ return Math.log(source[0]);
1607
1799
  }
1608
- ln(a) {
1609
- return Math.log(a);
1800
+ ln(source) {
1801
+ return Math.log(source[0]);
1610
1802
  }
1611
- exp(a) {
1612
- return Math.exp(a);
1803
+ exp(source) {
1804
+ return Math.exp(source[0]);
1613
1805
  }
1614
- floor(a) {
1615
- return Math.floor(a);
1806
+ floor(source) {
1807
+ return Math.floor(source[0]);
1616
1808
  }
1617
- ceil(a) {
1618
- return Math.ceil(a);
1809
+ ceil(source) {
1810
+ return Math.ceil(source[0]);
1619
1811
  }
1620
- round(a) {
1621
- return Math.round(a);
1812
+ round(source) {
1813
+ return Math.round(source[0]);
1622
1814
  }
1623
1815
  random() {
1624
1816
  return Math.random();
1625
1817
  }
1626
- max(...args) {
1627
- return Math.max(...args);
1818
+ max(...source) {
1819
+ const arg = source.map((e) => Array.isArray(e) ? e[0] : e);
1820
+ return Math.max(...arg);
1628
1821
  }
1629
- min(...args) {
1630
- return Math.min(...args);
1822
+ min(...source) {
1823
+ const arg = source.map((e) => Array.isArray(e) ? e[0] : e);
1824
+ return Math.min(...arg);
1631
1825
  }
1632
- sin(a) {
1633
- return Math.sin(a);
1826
+ //sum of last n values
1827
+ sum(source, length) {
1828
+ const len = Array.isArray(length) ? length[0] : length;
1829
+ if (Array.isArray(source)) {
1830
+ return source.slice(0, len).reduce((a, b) => a + b, 0);
1831
+ }
1832
+ return source;
1833
+ }
1834
+ sin(source) {
1835
+ return Math.sin(source[0]);
1634
1836
  }
1635
- cos(a) {
1636
- return Math.cos(a);
1837
+ cos(source) {
1838
+ return Math.cos(source[0]);
1637
1839
  }
1638
- tan(a) {
1639
- return Math.tan(a);
1840
+ tan(source) {
1841
+ return Math.tan(source[0]);
1640
1842
  }
1641
- asin(a) {
1642
- return Math.asin(a);
1843
+ acos(source) {
1844
+ return Math.acos(source[0]);
1643
1845
  }
1644
- acos(a) {
1645
- return Math.acos(a);
1846
+ asin(source) {
1847
+ return Math.asin(source[0]);
1646
1848
  }
1647
- atan(a) {
1648
- return Math.atan(a);
1849
+ atan(source) {
1850
+ return Math.atan(source[0]);
1649
1851
  }
1650
- avg(...args) {
1852
+ avg(...sources) {
1853
+ const args = sources.map((e) => Array.isArray(e) ? e[0] : e);
1651
1854
  return args.reduce((a, b) => {
1652
1855
  const aVal = Array.isArray(a) ? a[0] : a;
1653
1856
  const bVal = Array.isArray(b) ? b[0] : b;
@@ -1656,13 +1859,14 @@ class PineMath {
1656
1859
  }
1657
1860
  }
1658
1861
 
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);
1862
+ var __defProp$3 = Object.defineProperty;
1863
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1864
+ var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
1865
+ const TIMEFRAMES = ["1", "3", "5", "15", "30", "45", "60", "120", "180", "240", "D", "W", "M"];
1662
1866
  class PineRequest {
1663
1867
  constructor(context) {
1664
1868
  this.context = context;
1665
- __publicField$1(this, "_cache", {});
1869
+ __publicField$3(this, "_cache", {});
1666
1870
  }
1667
1871
  param(source, index, name) {
1668
1872
  if (!this.context.params[name]) this.context.params[name] = [];
@@ -1678,8 +1882,42 @@ class PineRequest {
1678
1882
  return [source, name];
1679
1883
  }
1680
1884
  }
1681
- async security(symbol, timeframe, expression) {
1682
- throw new Error("Not implemented");
1885
+ async security(symbol, timeframe, expression, gaps = false, lookahead = false, ignore_invalid_symbol = false, currency = null, calc_bars_count = null) {
1886
+ const _symbol = symbol[0];
1887
+ const _timeframe = timeframe[0];
1888
+ const _expression = expression[0];
1889
+ const _expression_name = expression[1];
1890
+ const ctxTimeframeIdx = TIMEFRAMES.indexOf(this.context.timeframe);
1891
+ const reqTimeframeIdx = TIMEFRAMES.indexOf(_timeframe);
1892
+ if (ctxTimeframeIdx == -1 || reqTimeframeIdx == -1) {
1893
+ throw new Error("Invalid timeframe");
1894
+ }
1895
+ if (ctxTimeframeIdx > reqTimeframeIdx) {
1896
+ throw new Error("Only higher timeframes are supported for now");
1897
+ }
1898
+ if (ctxTimeframeIdx === reqTimeframeIdx) {
1899
+ return _expression;
1900
+ }
1901
+ const myOpenTime = this.context.data.openTime[0];
1902
+ const myCloseTime = this.context.data.closeTime[0];
1903
+ if (this.context.cache[_expression_name]) {
1904
+ const secContext2 = this.context.cache[_expression_name];
1905
+ const secContextIdx2 = this._findSecContextIdx(myOpenTime, myCloseTime, secContext2.data.openTime, secContext2.data.closeTime, lookahead);
1906
+ return secContextIdx2 == -1 ? NaN : secContext2.params[_expression_name][secContextIdx2];
1907
+ }
1908
+ const pineTS = new PineTS(this.context.source, _symbol, _timeframe, this.context.limit || 1e3, this.context.sDate, this.context.eDate);
1909
+ const secContext = await pineTS.run(this.context.pineTSCode);
1910
+ this.context.cache[_expression_name] = secContext;
1911
+ const secContextIdx = this._findSecContextIdx(myOpenTime, myCloseTime, secContext.data.openTime, secContext.data.closeTime, lookahead);
1912
+ return secContextIdx == -1 ? NaN : secContext.params[_expression_name][secContextIdx];
1913
+ }
1914
+ _findSecContextIdx(myOpenTime, myCloseTime, openTime, closeTime, lookahead = false) {
1915
+ for (let i = 0; i < openTime.length; i++) {
1916
+ if (openTime[i] <= myOpenTime && myCloseTime <= closeTime[i]) {
1917
+ return i + (lookahead ? 1 : 2);
1918
+ }
1919
+ }
1920
+ return -1;
1683
1921
  }
1684
1922
  }
1685
1923
 
@@ -1700,6 +1938,7 @@ class TechnicalAnalysis {
1700
1938
  if (Array.isArray(source)) {
1701
1939
  if (index) {
1702
1940
  this.context.params[name] = source.slice(index);
1941
+ this.context.params[name].length = source.length;
1703
1942
  return this.context.params[name];
1704
1943
  }
1705
1944
  this.context.params[name] = source.slice(0);
@@ -1715,9 +1954,21 @@ class TechnicalAnalysis {
1715
1954
  const idx = this.context.idx;
1716
1955
  return this.context.precision(result[idx]);
1717
1956
  }
1718
- sma(source, _period) {
1957
+ sma(source, _period, _cacheId) {
1719
1958
  const period = Array.isArray(_period) ? _period[0] : _period;
1720
- const result = sma(source.slice(0).reverse(), period);
1959
+ const reversedSource = source.slice(0).reverse();
1960
+ if (this.context.useTACache && _cacheId) {
1961
+ if (!this.context.cache[_cacheId]) {
1962
+ this.context.cache[_cacheId] = {};
1963
+ }
1964
+ const cacheObj = this.context.cache[_cacheId];
1965
+ if (cacheObj) {
1966
+ const result2 = sma_cache(reversedSource, period, cacheObj);
1967
+ const idx2 = this.context.idx;
1968
+ return this.context.precision(result2[idx2]);
1969
+ }
1970
+ }
1971
+ const result = sma(reversedSource, period);
1721
1972
  const idx = this.context.idx;
1722
1973
  return this.context.precision(result[idx]);
1723
1974
  }
@@ -1833,6 +2084,44 @@ class TechnicalAnalysis {
1833
2084
  const idx = this.context.idx;
1834
2085
  return [[this.context.precision(supertrend[idx]), direction[idx]]];
1835
2086
  }
2087
+ crossover(source1, source2) {
2088
+ const current1 = Array.isArray(source1) ? source1[0] : source1;
2089
+ const current2 = Array.isArray(source2) ? source2[0] : source2;
2090
+ const prev1 = Array.isArray(source1) ? source1[1] : this.context.data.series[source1][1];
2091
+ const prev2 = Array.isArray(source2) ? source2[1] : this.context.data.series[source2][1];
2092
+ return prev1 < prev2 && current1 > current2;
2093
+ }
2094
+ crossunder(source1, source2) {
2095
+ const current1 = Array.isArray(source1) ? source1[0] : source1;
2096
+ const current2 = Array.isArray(source2) ? source2[0] : source2;
2097
+ const prev1 = Array.isArray(source1) ? source1[1] : this.context.data.series[source1][1];
2098
+ const prev2 = Array.isArray(source2) ? source2[1] : this.context.data.series[source2][1];
2099
+ return prev1 > prev2 && current1 < current2;
2100
+ }
2101
+ pivothigh(source, _leftbars, _rightbars) {
2102
+ if (_rightbars == void 0) {
2103
+ _rightbars = _leftbars;
2104
+ _leftbars = source;
2105
+ source = this.context.data.high;
2106
+ }
2107
+ const leftbars = Array.isArray(_leftbars) ? _leftbars[0] : _leftbars;
2108
+ const rightbars = Array.isArray(_rightbars) ? _rightbars[0] : _rightbars;
2109
+ const result = pivothigh(source.slice(0).reverse(), leftbars, rightbars);
2110
+ const idx = this.context.idx;
2111
+ return this.context.precision(result[idx]);
2112
+ }
2113
+ pivotlow(source, _leftbars, _rightbars) {
2114
+ if (_rightbars == void 0) {
2115
+ _rightbars = _leftbars;
2116
+ _leftbars = source;
2117
+ source = this.context.data.low;
2118
+ }
2119
+ const leftbars = Array.isArray(_leftbars) ? _leftbars[0] : _leftbars;
2120
+ const rightbars = Array.isArray(_rightbars) ? _rightbars[0] : _rightbars;
2121
+ const result = pivotlow(source.slice(0).reverse(), leftbars, rightbars);
2122
+ const idx = this.context.idx;
2123
+ return this.context.precision(result[idx]);
2124
+ }
1836
2125
  }
1837
2126
  function atr(high, low, close, period) {
1838
2127
  const tr = new Array(high.length);
@@ -1906,6 +2195,35 @@ function rma(source, period) {
1906
2195
  }
1907
2196
  return result;
1908
2197
  }
2198
+ function sma_cache(source, period, cacheObj) {
2199
+ const result = cacheObj.previousResult || new Array(source.length).fill(NaN);
2200
+ const lastProcessedIndex = cacheObj.lastProcessedIndex || -1;
2201
+ let previousSum = cacheObj.previousSum || 0;
2202
+ if (lastProcessedIndex === -1 || source.length !== lastProcessedIndex + 1) {
2203
+ previousSum = 0;
2204
+ for (let i = 0; i < period; i++) {
2205
+ previousSum += source[i] || 0;
2206
+ }
2207
+ result[period - 1] = previousSum / period;
2208
+ for (let i = 0; i < period - 1; i++) {
2209
+ result[i] = NaN;
2210
+ }
2211
+ for (let i = period; i < source.length; i++) {
2212
+ previousSum = previousSum - (source[i - period] || 0) + (source[i] || 0);
2213
+ result[i] = previousSum / period;
2214
+ }
2215
+ } else if (source.length === lastProcessedIndex + 2) {
2216
+ const newIndex = source.length - 1;
2217
+ previousSum = previousSum - (source[newIndex - period] || 0) + (source[newIndex] || 0);
2218
+ result[newIndex] = previousSum / period;
2219
+ } else {
2220
+ return sma(source, period);
2221
+ }
2222
+ cacheObj.previousSum = previousSum;
2223
+ cacheObj.lastProcessedIndex = source.length - 1;
2224
+ cacheObj.previousResult = result;
2225
+ return result;
2226
+ }
1909
2227
  function sma(source, period) {
1910
2228
  const result = new Array(source.length).fill(NaN);
1911
2229
  for (let i = period - 1; i < source.length; i++) {
@@ -2024,7 +2342,7 @@ function lowest(source, length) {
2024
2342
  let min = Infinity;
2025
2343
  for (let j = 0; j < length; j++) {
2026
2344
  const value = source[i - j];
2027
- if (isNaN(value)) {
2345
+ if (isNaN(value) || value === void 0) {
2028
2346
  min = min === Infinity ? NaN : min;
2029
2347
  } else {
2030
2348
  min = Math.min(min, value);
@@ -2143,14 +2461,263 @@ function calculateSupertrend(high, low, close, factor, atrPeriod) {
2143
2461
  }
2144
2462
  return [supertrend, direction];
2145
2463
  }
2464
+ function pivothigh(source, leftbars, rightbars) {
2465
+ const result = new Array(source.length).fill(NaN);
2466
+ for (let i = leftbars + rightbars; i < source.length; i++) {
2467
+ const pivot = source[i - rightbars];
2468
+ let isPivot = true;
2469
+ for (let j = 1; j <= leftbars; j++) {
2470
+ if (source[i - rightbars - j] >= pivot) {
2471
+ isPivot = false;
2472
+ break;
2473
+ }
2474
+ }
2475
+ if (isPivot) {
2476
+ for (let j = 1; j <= rightbars; j++) {
2477
+ if (source[i - rightbars + j] >= pivot) {
2478
+ isPivot = false;
2479
+ break;
2480
+ }
2481
+ }
2482
+ }
2483
+ if (isPivot) {
2484
+ result[i] = pivot;
2485
+ }
2486
+ }
2487
+ return result;
2488
+ }
2489
+ function pivotlow(source, leftbars, rightbars) {
2490
+ const result = new Array(source.length).fill(NaN);
2491
+ for (let i = leftbars + rightbars; i < source.length; i++) {
2492
+ const pivot = source[i - rightbars];
2493
+ let isPivot = true;
2494
+ for (let j = 1; j <= leftbars; j++) {
2495
+ if (source[i - rightbars - j] <= pivot) {
2496
+ isPivot = false;
2497
+ break;
2498
+ }
2499
+ }
2500
+ if (isPivot) {
2501
+ for (let j = 1; j <= rightbars; j++) {
2502
+ if (source[i - rightbars + j] <= pivot) {
2503
+ isPivot = false;
2504
+ break;
2505
+ }
2506
+ }
2507
+ }
2508
+ if (isPivot) {
2509
+ result[i] = pivot;
2510
+ }
2511
+ }
2512
+ return result;
2513
+ }
2146
2514
 
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);
2515
+ var __defProp$2 = Object.defineProperty;
2516
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2517
+ var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
2518
+ class PineArrayObject {
2519
+ constructor(array) {
2520
+ this.array = array;
2521
+ }
2522
+ }
2523
+ class PineArray {
2524
+ constructor(context) {
2525
+ this.context = context;
2526
+ __publicField$2(this, "_cache", {});
2527
+ }
2528
+ param(source, index = 0) {
2529
+ if (Array.isArray(source)) {
2530
+ return source[index];
2531
+ }
2532
+ return source;
2533
+ }
2534
+ /**
2535
+ * This function simulates PineScript's array.get() function
2536
+ * @param id - the array object to get the value from
2537
+ * @param index - the index of the value to get
2538
+ * @returns the value at the given index
2539
+ */
2540
+ get(id, index) {
2541
+ return id.array[index];
2542
+ }
2543
+ set(id, index, value) {
2544
+ id.array[index] = value;
2545
+ }
2546
+ push(id, value) {
2547
+ id.array.push(value);
2548
+ }
2549
+ // Basic statistics
2550
+ sum(id) {
2551
+ return id.array.reduce((a, b) => a + (isNaN(b) ? 0 : b), 0);
2552
+ }
2553
+ avg(id) {
2554
+ return this.sum(id) / id.array.length;
2555
+ }
2556
+ min(id, nth = 0) {
2557
+ const sorted = [...id.array].sort((a, b) => a - b);
2558
+ return sorted[nth] ?? this.context.NA;
2559
+ }
2560
+ max(id, nth = 0) {
2561
+ const sorted = [...id.array].sort((a, b) => b - a);
2562
+ return sorted[nth] ?? this.context.NA;
2563
+ }
2564
+ size(id) {
2565
+ return id.array.length;
2566
+ }
2567
+ // Array creation
2568
+ new_bool(size, initial_value = false) {
2569
+ return new PineArrayObject(Array(size).fill(initial_value));
2570
+ }
2571
+ new_float(size, initial_value = NaN) {
2572
+ return new PineArrayObject(Array(size).fill(initial_value));
2573
+ }
2574
+ new_int(size, initial_value = 0) {
2575
+ return new PineArrayObject(Array(size).fill(Math.round(initial_value)));
2576
+ }
2577
+ new_string(size, initial_value = "") {
2578
+ return new PineArrayObject(Array(size).fill(initial_value));
2579
+ }
2580
+ new(size, initial_value) {
2581
+ return new PineArrayObject(Array(size).fill(initial_value));
2582
+ }
2583
+ // Array operations
2584
+ slice(id, start, end) {
2585
+ const adjustedEnd = end !== void 0 ? end + 1 : void 0;
2586
+ return new PineArrayObject(id.array.slice(start, adjustedEnd));
2587
+ }
2588
+ reverse(id) {
2589
+ id.array.reverse();
2590
+ }
2591
+ includes(id, value) {
2592
+ return id.array.includes(value);
2593
+ }
2594
+ indexof(id, value) {
2595
+ return id.array.indexOf(value);
2596
+ }
2597
+ lastindexof(id, value) {
2598
+ return id.array.lastIndexOf(value);
2599
+ }
2600
+ // More complex functions
2601
+ stdev(id, biased = true) {
2602
+ const mean = this.avg(id);
2603
+ const deviations = id.array.map((x) => Math.pow(x - mean, 2));
2604
+ const divisor = biased ? id.array.length : id.array.length - 1;
2605
+ return Math.sqrt(this.sum(new PineArrayObject(deviations)) / divisor);
2606
+ }
2607
+ variance(id, biased = true) {
2608
+ const mean = this.avg(id);
2609
+ const deviations = id.array.map((x) => Math.pow(x - mean, 2));
2610
+ const divisor = biased ? id.array.length : id.array.length - 1;
2611
+ return this.sum(new PineArrayObject(deviations)) / divisor;
2612
+ }
2613
+ covariance(arr1, arr2, biased = true) {
2614
+ if (arr1.array.length !== arr2.array.length || arr1.array.length < 2) return NaN;
2615
+ const divisor = biased ? arr1.array.length : arr1.array.length - 1;
2616
+ const mean1 = this.avg(arr1);
2617
+ const mean2 = this.avg(arr2);
2618
+ let sum = 0;
2619
+ for (let i = 0; i < arr1.array.length; i++) {
2620
+ sum += (arr1.array[i] - mean1) * (arr2.array[i] - mean2);
2621
+ }
2622
+ return sum / divisor;
2623
+ }
2624
+ // Additional utility methods
2625
+ first(id) {
2626
+ return id.array.length > 0 ? id.array[0] : this.context.NA;
2627
+ }
2628
+ last(id) {
2629
+ return id.array.length > 0 ? id.array[id.array.length - 1] : this.context.NA;
2630
+ }
2631
+ clear(id) {
2632
+ id.array.length = 0;
2633
+ }
2634
+ join(id, separator = ",") {
2635
+ return id.array.join(separator);
2636
+ }
2637
+ /** Array Manipulation Functions */
2638
+ abs(id) {
2639
+ return new PineArrayObject(id.array.map((val) => Math.abs(val)));
2640
+ }
2641
+ concat(id, other) {
2642
+ id.array.push(...other.array);
2643
+ return id;
2644
+ }
2645
+ copy(id) {
2646
+ return new PineArrayObject([...id.array]);
2647
+ }
2648
+ every(id, callback) {
2649
+ return id.array.every(callback);
2650
+ }
2651
+ fill(id, value, start = 0, end) {
2652
+ const length = id.array.length;
2653
+ const adjustedEnd = end !== void 0 ? Math.min(end, length) : length;
2654
+ for (let i = start; i < adjustedEnd; i++) {
2655
+ id.array[i] = value;
2656
+ }
2657
+ }
2658
+ from(source) {
2659
+ return new PineArrayObject([...source]);
2660
+ }
2661
+ insert(id, index, value) {
2662
+ id.array.splice(index, 0, value);
2663
+ }
2664
+ pop(id) {
2665
+ return id.array.pop();
2666
+ }
2667
+ range(id) {
2668
+ return this.max(id) - this.min(id);
2669
+ }
2670
+ remove(id, index) {
2671
+ if (index >= 0 && index < id.array.length) {
2672
+ return id.array.splice(index, 1)[0];
2673
+ }
2674
+ return this.context.NA;
2675
+ }
2676
+ shift(id) {
2677
+ return id.array.shift();
2678
+ }
2679
+ sort(id, order = "asc") {
2680
+ id.array.sort((a, b) => order === "asc" ? a - b : b - a);
2681
+ }
2682
+ sort_indices(id, comparator) {
2683
+ const indices = id.array.map((_, index) => index);
2684
+ indices.sort((a, b) => {
2685
+ const valA = id.array[a];
2686
+ const valB = id.array[b];
2687
+ return comparator ? comparator(valA, valB) : valA - valB;
2688
+ });
2689
+ return new PineArrayObject(indices);
2690
+ }
2691
+ standardize(id) {
2692
+ const mean = this.avg(id);
2693
+ const stdev = this.stdev(id);
2694
+ if (stdev === 0) {
2695
+ return new PineArrayObject(id.array.map(() => 0));
2696
+ }
2697
+ return new PineArrayObject(id.array.map((x) => (x - mean) / stdev));
2698
+ }
2699
+ unshift(id, value) {
2700
+ id.array.unshift(value);
2701
+ }
2702
+ some(id, callback) {
2703
+ return id.array.some(callback);
2704
+ }
2705
+ }
2706
+
2707
+ var __defProp$1 = Object.defineProperty;
2708
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2709
+ var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
2150
2710
  class Context {
2151
- constructor(marketData) {
2152
- this.marketData = marketData;
2153
- __publicField(this, "data", {
2711
+ constructor({
2712
+ marketData,
2713
+ source,
2714
+ tickerId,
2715
+ timeframe,
2716
+ limit,
2717
+ sDate,
2718
+ eDate
2719
+ }) {
2720
+ __publicField$1(this, "data", {
2154
2721
  open: [],
2155
2722
  high: [],
2156
2723
  low: [],
@@ -2160,23 +2727,43 @@ class Context {
2160
2727
  hlc3: [],
2161
2728
  ohlc4: []
2162
2729
  });
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", "");
2730
+ __publicField$1(this, "cache", {});
2731
+ __publicField$1(this, "useTACache", false);
2732
+ __publicField$1(this, "NA", NaN);
2733
+ __publicField$1(this, "math");
2734
+ __publicField$1(this, "ta");
2735
+ __publicField$1(this, "input");
2736
+ __publicField$1(this, "request");
2737
+ __publicField$1(this, "array");
2738
+ __publicField$1(this, "core");
2739
+ __publicField$1(this, "lang");
2740
+ __publicField$1(this, "idx", 0);
2741
+ __publicField$1(this, "params", {});
2742
+ __publicField$1(this, "const", {});
2743
+ __publicField$1(this, "var", {});
2744
+ __publicField$1(this, "let", {});
2745
+ __publicField$1(this, "result");
2746
+ __publicField$1(this, "plots", {});
2747
+ __publicField$1(this, "marketData");
2748
+ __publicField$1(this, "source");
2749
+ __publicField$1(this, "tickerId");
2750
+ __publicField$1(this, "timeframe", "");
2751
+ __publicField$1(this, "limit");
2752
+ __publicField$1(this, "sDate");
2753
+ __publicField$1(this, "eDate");
2754
+ __publicField$1(this, "pineTSCode");
2755
+ this.marketData = marketData;
2756
+ this.source = source;
2757
+ this.tickerId = tickerId;
2758
+ this.timeframe = timeframe;
2759
+ this.limit = limit;
2760
+ this.sDate = sDate;
2761
+ this.eDate = eDate;
2176
2762
  this.math = new PineMath(this);
2177
2763
  this.ta = new TechnicalAnalysis(this);
2178
2764
  this.input = new Input(this);
2179
2765
  this.request = new PineRequest(this);
2766
+ this.array = new PineArray(this);
2180
2767
  const core = new Core(this);
2181
2768
  this.core = {
2182
2769
  plotchar: core.plotchar.bind(core),
@@ -2212,12 +2799,13 @@ class Context {
2212
2799
  return trg;
2213
2800
  }
2214
2801
  /**
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
- */
2802
+ * this function is used to set the floating point precision of a number
2803
+ * by default it is set to 10 decimals which is the same as pine script
2804
+ * @param n - the number to be precision
2805
+ * @param decimals - the number of decimals to precision to
2806
+
2807
+ * @returns the precision number
2808
+ */
2221
2809
  precision(n, decimals = 10) {
2222
2810
  if (typeof n !== "number" || isNaN(n)) return n;
2223
2811
  return Number(n.toFixed(decimals));
@@ -2236,6 +2824,7 @@ class Context {
2236
2824
  if (Array.isArray(source)) {
2237
2825
  if (index) {
2238
2826
  this.params[name] = source.slice(index);
2827
+ this.params[name].length = source.length;
2239
2828
  return this.params[name];
2240
2829
  }
2241
2830
  this.params[name] = source.slice(0);
@@ -2248,6 +2837,9 @@ class Context {
2248
2837
  //#endregion
2249
2838
  }
2250
2839
 
2840
+ var __defProp = Object.defineProperty;
2841
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2842
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
2251
2843
  const BINANCE_API_URL = "https://api.binance.com/api/v3";
2252
2844
  const timeframe_to_binance = {
2253
2845
  "1": "1m",
@@ -2270,6 +2862,8 @@ const timeframe_to_binance = {
2270
2862
  // 3 hours (not directly supported by Binance, needs custom handling)
2271
2863
  "240": "4h",
2272
2864
  // 4 hours
2865
+ "4H": "4h",
2866
+ // 4 hours
2273
2867
  "1D": "1d",
2274
2868
  // 1 day
2275
2869
  D: "1d",
@@ -2283,15 +2877,119 @@ const timeframe_to_binance = {
2283
2877
  M: "1M"
2284
2878
  // 1 month
2285
2879
  };
2880
+ class CacheManager {
2881
+ constructor(cacheDuration = 5 * 60 * 1e3) {
2882
+ __publicField(this, "cache");
2883
+ __publicField(this, "cacheDuration");
2884
+ this.cache = /* @__PURE__ */ new Map();
2885
+ this.cacheDuration = cacheDuration;
2886
+ }
2887
+ generateKey(params) {
2888
+ return Object.entries(params).filter(([_, value]) => value !== void 0).map(([key, value]) => `${key}:${value}`).join("|");
2889
+ }
2890
+ get(params) {
2891
+ const key = this.generateKey(params);
2892
+ const cached = this.cache.get(key);
2893
+ if (!cached) return null;
2894
+ if (Date.now() - cached.timestamp > this.cacheDuration) {
2895
+ this.cache.delete(key);
2896
+ return null;
2897
+ }
2898
+ return cached.data;
2899
+ }
2900
+ set(params, data) {
2901
+ const key = this.generateKey(params);
2902
+ this.cache.set(key, {
2903
+ data,
2904
+ timestamp: Date.now()
2905
+ });
2906
+ }
2907
+ clear() {
2908
+ this.cache.clear();
2909
+ }
2910
+ // Optional: method to remove expired entries
2911
+ cleanup() {
2912
+ const now = Date.now();
2913
+ for (const [key, entry] of this.cache.entries()) {
2914
+ if (now - entry.timestamp > this.cacheDuration) {
2915
+ this.cache.delete(key);
2916
+ }
2917
+ }
2918
+ }
2919
+ }
2286
2920
  class BinanceProvider {
2921
+ constructor() {
2922
+ __publicField(this, "cacheManager");
2923
+ this.cacheManager = new CacheManager(5 * 60 * 1e3);
2924
+ }
2925
+ async getMarketDataInterval(tickerId, timeframe, sDate, eDate) {
2926
+ try {
2927
+ const interval = timeframe_to_binance[timeframe.toUpperCase()];
2928
+ if (!interval) {
2929
+ console.error(`Unsupported timeframe: ${timeframe}`);
2930
+ return [];
2931
+ }
2932
+ const timeframeDurations = {
2933
+ "1m": 60 * 1e3,
2934
+ "3m": 3 * 60 * 1e3,
2935
+ "5m": 5 * 60 * 1e3,
2936
+ "15m": 15 * 60 * 1e3,
2937
+ "30m": 30 * 60 * 1e3,
2938
+ "1h": 60 * 60 * 1e3,
2939
+ "2h": 2 * 60 * 60 * 1e3,
2940
+ "4h": 4 * 60 * 60 * 1e3,
2941
+ "1d": 24 * 60 * 60 * 1e3,
2942
+ "1w": 7 * 24 * 60 * 60 * 1e3,
2943
+ "1M": 30 * 24 * 60 * 60 * 1e3
2944
+ };
2945
+ let allData = [];
2946
+ let currentStart = sDate;
2947
+ const endTime = eDate;
2948
+ const intervalDuration = timeframeDurations[interval];
2949
+ if (!intervalDuration) {
2950
+ console.error(`Duration not defined for interval: ${interval}`);
2951
+ return [];
2952
+ }
2953
+ while (currentStart < endTime) {
2954
+ const chunkEnd = Math.min(currentStart + 1e3 * intervalDuration, endTime);
2955
+ const data = await this.getMarketData(
2956
+ tickerId,
2957
+ timeframe,
2958
+ 1e3,
2959
+ // Max allowed by Binance
2960
+ currentStart,
2961
+ chunkEnd
2962
+ );
2963
+ if (data.length === 0) break;
2964
+ allData = allData.concat(data);
2965
+ currentStart = data[data.length - 1].closeTime + 1;
2966
+ if (data.length < 1e3) break;
2967
+ }
2968
+ return allData;
2969
+ } catch (error) {
2970
+ console.error("Error in getMarketDataInterval:", error);
2971
+ return [];
2972
+ }
2973
+ }
2974
+ //TODO : allow querying more than 1000 klines
2975
+ //TODO : immplement cache
2287
2976
  async getMarketData(tickerId, timeframe, limit, sDate, eDate) {
2288
2977
  try {
2978
+ const cacheParams = { tickerId, timeframe, limit, sDate, eDate };
2979
+ const cachedData = this.cacheManager.get(cacheParams);
2980
+ if (cachedData) {
2981
+ console.log("cache hit", tickerId, timeframe, limit, sDate, eDate);
2982
+ return cachedData;
2983
+ }
2289
2984
  const interval = timeframe_to_binance[timeframe.toUpperCase()];
2290
2985
  if (!interval) {
2291
2986
  console.error(`Unsupported timeframe: ${timeframe}`);
2292
2987
  return [];
2293
2988
  }
2294
2989
  let url = `${BINANCE_API_URL}/klines?symbol=${tickerId}&interval=${interval}`;
2990
+ if (!limit && sDate && eDate) {
2991
+ return this.getMarketDataInterval(tickerId, timeframe, sDate, eDate);
2992
+ }
2295
2993
  if (limit) {
2296
2994
  url += `&limit=${limit}`;
2297
2995
  }
@@ -2308,13 +3006,13 @@ class BinanceProvider {
2308
3006
  const result = await response.json();
2309
3007
  const data = result.map((item) => {
2310
3008
  return {
2311
- openTime: parseInt(item[0]) / 1e3,
3009
+ openTime: parseInt(item[0]),
2312
3010
  open: parseFloat(item[1]),
2313
3011
  high: parseFloat(item[2]),
2314
3012
  low: parseFloat(item[3]),
2315
3013
  close: parseFloat(item[4]),
2316
3014
  volume: parseFloat(item[5]),
2317
- closeTime: parseInt(item[6]) / 1e3,
3015
+ closeTime: parseInt(item[6]),
2318
3016
  quoteAssetVolume: parseFloat(item[7]),
2319
3017
  numberOfTrades: parseInt(item[8]),
2320
3018
  takerBuyBaseAssetVolume: parseFloat(item[9]),
@@ -2322,6 +3020,7 @@ class BinanceProvider {
2322
3020
  ignore: item[11]
2323
3021
  };
2324
3022
  });
3023
+ this.cacheManager.set(cacheParams, data);
2325
3024
  return data;
2326
3025
  } catch (error) {
2327
3026
  console.error("Error in binance.klines:", error);
@@ -2332,6 +3031,7 @@ class BinanceProvider {
2332
3031
 
2333
3032
  const Provider = {
2334
3033
  Binance: new BinanceProvider()
3034
+ //TODO : add other providers (polygon, etc.)
2335
3035
  };
2336
3036
 
2337
3037
  export { Context, PineTS, Provider };