pinets 0.1.0 → 0.1.31

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);
1821
+ }
1822
+ min(...source) {
1823
+ const arg = source.map((e) => Array.isArray(e) ? e[0] : e);
1824
+ return Math.min(...arg);
1628
1825
  }
1629
- min(...args) {
1630
- return Math.min(...args);
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;
1631
1833
  }
1632
- sin(a) {
1633
- return Math.sin(a);
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
  }
@@ -1906,6 +2157,35 @@ function rma(source, period) {
1906
2157
  }
1907
2158
  return result;
1908
2159
  }
2160
+ function sma_cache(source, period, cacheObj) {
2161
+ const result = cacheObj.previousResult || new Array(source.length).fill(NaN);
2162
+ const lastProcessedIndex = cacheObj.lastProcessedIndex || -1;
2163
+ let previousSum = cacheObj.previousSum || 0;
2164
+ if (lastProcessedIndex === -1 || source.length !== lastProcessedIndex + 1) {
2165
+ previousSum = 0;
2166
+ for (let i = 0; i < period; i++) {
2167
+ previousSum += source[i] || 0;
2168
+ }
2169
+ result[period - 1] = previousSum / period;
2170
+ for (let i = 0; i < period - 1; i++) {
2171
+ result[i] = NaN;
2172
+ }
2173
+ for (let i = period; i < source.length; i++) {
2174
+ previousSum = previousSum - (source[i - period] || 0) + (source[i] || 0);
2175
+ result[i] = previousSum / period;
2176
+ }
2177
+ } else if (source.length === lastProcessedIndex + 2) {
2178
+ const newIndex = source.length - 1;
2179
+ previousSum = previousSum - (source[newIndex - period] || 0) + (source[newIndex] || 0);
2180
+ result[newIndex] = previousSum / period;
2181
+ } else {
2182
+ return sma(source, period);
2183
+ }
2184
+ cacheObj.previousSum = previousSum;
2185
+ cacheObj.lastProcessedIndex = source.length - 1;
2186
+ cacheObj.previousResult = result;
2187
+ return result;
2188
+ }
1909
2189
  function sma(source, period) {
1910
2190
  const result = new Array(source.length).fill(NaN);
1911
2191
  for (let i = period - 1; i < source.length; i++) {
@@ -2024,7 +2304,7 @@ function lowest(source, length) {
2024
2304
  let min = Infinity;
2025
2305
  for (let j = 0; j < length; j++) {
2026
2306
  const value = source[i - j];
2027
- if (isNaN(value)) {
2307
+ if (isNaN(value) || value === void 0) {
2028
2308
  min = min === Infinity ? NaN : min;
2029
2309
  } else {
2030
2310
  min = Math.min(min, value);
@@ -2144,13 +2424,212 @@ function calculateSupertrend(high, low, close, factor, atrPeriod) {
2144
2424
  return [supertrend, direction];
2145
2425
  }
2146
2426
 
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);
2427
+ var __defProp$2 = Object.defineProperty;
2428
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2429
+ var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
2430
+ class PineArrayObject {
2431
+ constructor(array) {
2432
+ this.array = array;
2433
+ }
2434
+ }
2435
+ class PineArray {
2436
+ constructor(context) {
2437
+ this.context = context;
2438
+ __publicField$2(this, "_cache", {});
2439
+ }
2440
+ param(source, index = 0) {
2441
+ if (Array.isArray(source)) {
2442
+ return source[index];
2443
+ }
2444
+ return source;
2445
+ }
2446
+ /**
2447
+ * This function simulates PineScript's array.get() function
2448
+ * @param id - the array object to get the value from
2449
+ * @param index - the index of the value to get
2450
+ * @returns the value at the given index
2451
+ */
2452
+ get(id, index) {
2453
+ return id.array[index];
2454
+ }
2455
+ set(id, index, value) {
2456
+ id.array[index] = value;
2457
+ }
2458
+ push(id, value) {
2459
+ id.array.push(value);
2460
+ }
2461
+ // Basic statistics
2462
+ sum(id) {
2463
+ return id.array.reduce((a, b) => a + (isNaN(b) ? 0 : b), 0);
2464
+ }
2465
+ avg(id) {
2466
+ return this.sum(id) / id.array.length;
2467
+ }
2468
+ min(id, nth = 0) {
2469
+ const sorted = [...id.array].sort((a, b) => a - b);
2470
+ return sorted[nth] ?? this.context.NA;
2471
+ }
2472
+ max(id, nth = 0) {
2473
+ const sorted = [...id.array].sort((a, b) => b - a);
2474
+ return sorted[nth] ?? this.context.NA;
2475
+ }
2476
+ size(id) {
2477
+ return id.array.length;
2478
+ }
2479
+ // Array creation
2480
+ new_bool(size, initial_value = false) {
2481
+ return new PineArrayObject(Array(size).fill(initial_value));
2482
+ }
2483
+ new_float(size, initial_value = NaN) {
2484
+ return new PineArrayObject(Array(size).fill(initial_value));
2485
+ }
2486
+ new_int(size, initial_value = 0) {
2487
+ return new PineArrayObject(Array(size).fill(Math.round(initial_value)));
2488
+ }
2489
+ new_string(size, initial_value = "") {
2490
+ return new PineArrayObject(Array(size).fill(initial_value));
2491
+ }
2492
+ new(size, initial_value) {
2493
+ return new PineArrayObject(Array(size).fill(initial_value));
2494
+ }
2495
+ // Array operations
2496
+ slice(id, start, end) {
2497
+ const adjustedEnd = end !== void 0 ? end + 1 : void 0;
2498
+ return new PineArrayObject(id.array.slice(start, adjustedEnd));
2499
+ }
2500
+ reverse(id) {
2501
+ id.array.reverse();
2502
+ }
2503
+ includes(id, value) {
2504
+ return id.array.includes(value);
2505
+ }
2506
+ indexof(id, value) {
2507
+ return id.array.indexOf(value);
2508
+ }
2509
+ lastindexof(id, value) {
2510
+ return id.array.lastIndexOf(value);
2511
+ }
2512
+ // More complex functions
2513
+ stdev(id, biased = true) {
2514
+ const mean = this.avg(id);
2515
+ const deviations = id.array.map((x) => Math.pow(x - mean, 2));
2516
+ const divisor = biased ? id.array.length : id.array.length - 1;
2517
+ return Math.sqrt(this.sum(new PineArrayObject(deviations)) / divisor);
2518
+ }
2519
+ variance(id, biased = true) {
2520
+ const mean = this.avg(id);
2521
+ const deviations = id.array.map((x) => Math.pow(x - mean, 2));
2522
+ const divisor = biased ? id.array.length : id.array.length - 1;
2523
+ return this.sum(new PineArrayObject(deviations)) / divisor;
2524
+ }
2525
+ covariance(arr1, arr2, biased = true) {
2526
+ if (arr1.array.length !== arr2.array.length || arr1.array.length < 2) return NaN;
2527
+ const divisor = biased ? arr1.array.length : arr1.array.length - 1;
2528
+ const mean1 = this.avg(arr1);
2529
+ const mean2 = this.avg(arr2);
2530
+ let sum = 0;
2531
+ for (let i = 0; i < arr1.array.length; i++) {
2532
+ sum += (arr1.array[i] - mean1) * (arr2.array[i] - mean2);
2533
+ }
2534
+ return sum / divisor;
2535
+ }
2536
+ // Additional utility methods
2537
+ first(id) {
2538
+ return id.array.length > 0 ? id.array[0] : this.context.NA;
2539
+ }
2540
+ last(id) {
2541
+ return id.array.length > 0 ? id.array[id.array.length - 1] : this.context.NA;
2542
+ }
2543
+ clear(id) {
2544
+ id.array.length = 0;
2545
+ }
2546
+ join(id, separator = ",") {
2547
+ return id.array.join(separator);
2548
+ }
2549
+ /** Array Manipulation Functions */
2550
+ abs(id) {
2551
+ return new PineArrayObject(id.array.map((val) => Math.abs(val)));
2552
+ }
2553
+ concat(id, other) {
2554
+ id.array.push(...other.array);
2555
+ return id;
2556
+ }
2557
+ copy(id) {
2558
+ return new PineArrayObject([...id.array]);
2559
+ }
2560
+ every(id, callback) {
2561
+ return id.array.every(callback);
2562
+ }
2563
+ fill(id, value, start = 0, end) {
2564
+ const length = id.array.length;
2565
+ const adjustedEnd = end !== void 0 ? Math.min(end, length) : length;
2566
+ for (let i = start; i < adjustedEnd; i++) {
2567
+ id.array[i] = value;
2568
+ }
2569
+ }
2570
+ from(source) {
2571
+ return new PineArrayObject([...source]);
2572
+ }
2573
+ insert(id, index, value) {
2574
+ id.array.splice(index, 0, value);
2575
+ }
2576
+ pop(id) {
2577
+ return id.array.pop();
2578
+ }
2579
+ range(id) {
2580
+ return this.max(id) - this.min(id);
2581
+ }
2582
+ remove(id, index) {
2583
+ if (index >= 0 && index < id.array.length) {
2584
+ return id.array.splice(index, 1)[0];
2585
+ }
2586
+ return this.context.NA;
2587
+ }
2588
+ shift(id) {
2589
+ return id.array.shift();
2590
+ }
2591
+ sort(id, order = "asc") {
2592
+ id.array.sort((a, b) => order === "asc" ? a - b : b - a);
2593
+ }
2594
+ sort_indices(id, comparator) {
2595
+ const indices = id.array.map((_, index) => index);
2596
+ indices.sort((a, b) => {
2597
+ const valA = id.array[a];
2598
+ const valB = id.array[b];
2599
+ return comparator ? comparator(valA, valB) : valA - valB;
2600
+ });
2601
+ return new PineArrayObject(indices);
2602
+ }
2603
+ standardize(id) {
2604
+ const mean = this.avg(id);
2605
+ const stdev = this.stdev(id);
2606
+ if (stdev === 0) {
2607
+ return new PineArrayObject(id.array.map(() => 0));
2608
+ }
2609
+ return new PineArrayObject(id.array.map((x) => (x - mean) / stdev));
2610
+ }
2611
+ unshift(id, value) {
2612
+ id.array.unshift(value);
2613
+ }
2614
+ some(id, callback) {
2615
+ return id.array.some(callback);
2616
+ }
2617
+ }
2618
+
2619
+ var __defProp$1 = Object.defineProperty;
2620
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2621
+ var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
2150
2622
  class Context {
2151
- constructor(marketData) {
2152
- this.marketData = marketData;
2153
- __publicField(this, "data", {
2623
+ constructor({
2624
+ marketData,
2625
+ source,
2626
+ tickerId,
2627
+ timeframe,
2628
+ limit,
2629
+ sDate,
2630
+ eDate
2631
+ }) {
2632
+ __publicField$1(this, "data", {
2154
2633
  open: [],
2155
2634
  high: [],
2156
2635
  low: [],
@@ -2160,23 +2639,43 @@ class Context {
2160
2639
  hlc3: [],
2161
2640
  ohlc4: []
2162
2641
  });
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", "");
2642
+ __publicField$1(this, "cache", {});
2643
+ __publicField$1(this, "useTACache", false);
2644
+ __publicField$1(this, "NA", NaN);
2645
+ __publicField$1(this, "math");
2646
+ __publicField$1(this, "ta");
2647
+ __publicField$1(this, "input");
2648
+ __publicField$1(this, "request");
2649
+ __publicField$1(this, "array");
2650
+ __publicField$1(this, "core");
2651
+ __publicField$1(this, "lang");
2652
+ __publicField$1(this, "idx", 0);
2653
+ __publicField$1(this, "params", {});
2654
+ __publicField$1(this, "const", {});
2655
+ __publicField$1(this, "var", {});
2656
+ __publicField$1(this, "let", {});
2657
+ __publicField$1(this, "result");
2658
+ __publicField$1(this, "plots", {});
2659
+ __publicField$1(this, "marketData");
2660
+ __publicField$1(this, "source");
2661
+ __publicField$1(this, "tickerId");
2662
+ __publicField$1(this, "timeframe", "");
2663
+ __publicField$1(this, "limit");
2664
+ __publicField$1(this, "sDate");
2665
+ __publicField$1(this, "eDate");
2666
+ __publicField$1(this, "pineTSCode");
2667
+ this.marketData = marketData;
2668
+ this.source = source;
2669
+ this.tickerId = tickerId;
2670
+ this.timeframe = timeframe;
2671
+ this.limit = limit;
2672
+ this.sDate = sDate;
2673
+ this.eDate = eDate;
2176
2674
  this.math = new PineMath(this);
2177
2675
  this.ta = new TechnicalAnalysis(this);
2178
2676
  this.input = new Input(this);
2179
2677
  this.request = new PineRequest(this);
2678
+ this.array = new PineArray(this);
2180
2679
  const core = new Core(this);
2181
2680
  this.core = {
2182
2681
  plotchar: core.plotchar.bind(core),
@@ -2212,12 +2711,13 @@ class Context {
2212
2711
  return trg;
2213
2712
  }
2214
2713
  /**
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
- */
2714
+ * this function is used to set the floating point precision of a number
2715
+ * by default it is set to 10 decimals which is the same as pine script
2716
+ * @param n - the number to be precision
2717
+ * @param decimals - the number of decimals to precision to
2718
+
2719
+ * @returns the precision number
2720
+ */
2221
2721
  precision(n, decimals = 10) {
2222
2722
  if (typeof n !== "number" || isNaN(n)) return n;
2223
2723
  return Number(n.toFixed(decimals));
@@ -2236,6 +2736,7 @@ class Context {
2236
2736
  if (Array.isArray(source)) {
2237
2737
  if (index) {
2238
2738
  this.params[name] = source.slice(index);
2739
+ this.params[name].length = source.length;
2239
2740
  return this.params[name];
2240
2741
  }
2241
2742
  this.params[name] = source.slice(0);
@@ -2248,6 +2749,9 @@ class Context {
2248
2749
  //#endregion
2249
2750
  }
2250
2751
 
2752
+ var __defProp = Object.defineProperty;
2753
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2754
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
2251
2755
  const BINANCE_API_URL = "https://api.binance.com/api/v3";
2252
2756
  const timeframe_to_binance = {
2253
2757
  "1": "1m",
@@ -2270,6 +2774,8 @@ const timeframe_to_binance = {
2270
2774
  // 3 hours (not directly supported by Binance, needs custom handling)
2271
2775
  "240": "4h",
2272
2776
  // 4 hours
2777
+ "4H": "4h",
2778
+ // 4 hours
2273
2779
  "1D": "1d",
2274
2780
  // 1 day
2275
2781
  D: "1d",
@@ -2283,15 +2789,119 @@ const timeframe_to_binance = {
2283
2789
  M: "1M"
2284
2790
  // 1 month
2285
2791
  };
2792
+ class CacheManager {
2793
+ constructor(cacheDuration = 5 * 60 * 1e3) {
2794
+ __publicField(this, "cache");
2795
+ __publicField(this, "cacheDuration");
2796
+ this.cache = /* @__PURE__ */ new Map();
2797
+ this.cacheDuration = cacheDuration;
2798
+ }
2799
+ generateKey(params) {
2800
+ return Object.entries(params).filter(([_, value]) => value !== void 0).map(([key, value]) => `${key}:${value}`).join("|");
2801
+ }
2802
+ get(params) {
2803
+ const key = this.generateKey(params);
2804
+ const cached = this.cache.get(key);
2805
+ if (!cached) return null;
2806
+ if (Date.now() - cached.timestamp > this.cacheDuration) {
2807
+ this.cache.delete(key);
2808
+ return null;
2809
+ }
2810
+ return cached.data;
2811
+ }
2812
+ set(params, data) {
2813
+ const key = this.generateKey(params);
2814
+ this.cache.set(key, {
2815
+ data,
2816
+ timestamp: Date.now()
2817
+ });
2818
+ }
2819
+ clear() {
2820
+ this.cache.clear();
2821
+ }
2822
+ // Optional: method to remove expired entries
2823
+ cleanup() {
2824
+ const now = Date.now();
2825
+ for (const [key, entry] of this.cache.entries()) {
2826
+ if (now - entry.timestamp > this.cacheDuration) {
2827
+ this.cache.delete(key);
2828
+ }
2829
+ }
2830
+ }
2831
+ }
2286
2832
  class BinanceProvider {
2833
+ constructor() {
2834
+ __publicField(this, "cacheManager");
2835
+ this.cacheManager = new CacheManager(5 * 60 * 1e3);
2836
+ }
2837
+ async getMarketDataInterval(tickerId, timeframe, sDate, eDate) {
2838
+ try {
2839
+ const interval = timeframe_to_binance[timeframe.toUpperCase()];
2840
+ if (!interval) {
2841
+ console.error(`Unsupported timeframe: ${timeframe}`);
2842
+ return [];
2843
+ }
2844
+ const timeframeDurations = {
2845
+ "1m": 60 * 1e3,
2846
+ "3m": 3 * 60 * 1e3,
2847
+ "5m": 5 * 60 * 1e3,
2848
+ "15m": 15 * 60 * 1e3,
2849
+ "30m": 30 * 60 * 1e3,
2850
+ "1h": 60 * 60 * 1e3,
2851
+ "2h": 2 * 60 * 60 * 1e3,
2852
+ "4h": 4 * 60 * 60 * 1e3,
2853
+ "1d": 24 * 60 * 60 * 1e3,
2854
+ "1w": 7 * 24 * 60 * 60 * 1e3,
2855
+ "1M": 30 * 24 * 60 * 60 * 1e3
2856
+ };
2857
+ let allData = [];
2858
+ let currentStart = sDate;
2859
+ const endTime = eDate;
2860
+ const intervalDuration = timeframeDurations[interval];
2861
+ if (!intervalDuration) {
2862
+ console.error(`Duration not defined for interval: ${interval}`);
2863
+ return [];
2864
+ }
2865
+ while (currentStart < endTime) {
2866
+ const chunkEnd = Math.min(currentStart + 1e3 * intervalDuration, endTime);
2867
+ const data = await this.getMarketData(
2868
+ tickerId,
2869
+ timeframe,
2870
+ 1e3,
2871
+ // Max allowed by Binance
2872
+ currentStart,
2873
+ chunkEnd
2874
+ );
2875
+ if (data.length === 0) break;
2876
+ allData = allData.concat(data);
2877
+ currentStart = data[data.length - 1].closeTime + 1;
2878
+ if (data.length < 1e3) break;
2879
+ }
2880
+ return allData;
2881
+ } catch (error) {
2882
+ console.error("Error in getMarketDataInterval:", error);
2883
+ return [];
2884
+ }
2885
+ }
2886
+ //TODO : allow querying more than 1000 klines
2887
+ //TODO : immplement cache
2287
2888
  async getMarketData(tickerId, timeframe, limit, sDate, eDate) {
2288
2889
  try {
2890
+ const cacheParams = { tickerId, timeframe, limit, sDate, eDate };
2891
+ const cachedData = this.cacheManager.get(cacheParams);
2892
+ if (cachedData) {
2893
+ console.log("cache hit", tickerId, timeframe, limit, sDate, eDate);
2894
+ return cachedData;
2895
+ }
2289
2896
  const interval = timeframe_to_binance[timeframe.toUpperCase()];
2290
2897
  if (!interval) {
2291
2898
  console.error(`Unsupported timeframe: ${timeframe}`);
2292
2899
  return [];
2293
2900
  }
2294
2901
  let url = `${BINANCE_API_URL}/klines?symbol=${tickerId}&interval=${interval}`;
2902
+ if (!limit && sDate && eDate) {
2903
+ return this.getMarketDataInterval(tickerId, timeframe, sDate, eDate);
2904
+ }
2295
2905
  if (limit) {
2296
2906
  url += `&limit=${limit}`;
2297
2907
  }
@@ -2308,13 +2918,13 @@ class BinanceProvider {
2308
2918
  const result = await response.json();
2309
2919
  const data = result.map((item) => {
2310
2920
  return {
2311
- openTime: parseInt(item[0]) / 1e3,
2921
+ openTime: parseInt(item[0]),
2312
2922
  open: parseFloat(item[1]),
2313
2923
  high: parseFloat(item[2]),
2314
2924
  low: parseFloat(item[3]),
2315
2925
  close: parseFloat(item[4]),
2316
2926
  volume: parseFloat(item[5]),
2317
- closeTime: parseInt(item[6]) / 1e3,
2927
+ closeTime: parseInt(item[6]),
2318
2928
  quoteAssetVolume: parseFloat(item[7]),
2319
2929
  numberOfTrades: parseInt(item[8]),
2320
2930
  takerBuyBaseAssetVolume: parseFloat(item[9]),
@@ -2322,6 +2932,7 @@ class BinanceProvider {
2322
2932
  ignore: item[11]
2323
2933
  };
2324
2934
  });
2935
+ this.cacheManager.set(cacheParams, data);
2325
2936
  return data;
2326
2937
  } catch (error) {
2327
2938
  console.error("Error in binance.klines:", error);
@@ -2332,6 +2943,7 @@ class BinanceProvider {
2332
2943
 
2333
2944
  const Provider = {
2334
2945
  Binance: new BinanceProvider()
2946
+ //TODO : add other providers (polygon, etc.)
2335
2947
  };
2336
2948
 
2337
2949
  export { Context, PineTS, Provider };