oakscriptjs 0.7.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -85,6 +85,40 @@ __export(ta_exports, {
85
85
  wvad: () => wvad,
86
86
  zigzag: () => zigzag
87
87
  });
88
+
89
+ // src/compare/index.ts
90
+ var compare_exports = {};
91
+ __export(compare_exports, {
92
+ EPSILON: () => EPSILON,
93
+ eq: () => eq,
94
+ ge: () => ge,
95
+ gt: () => gt,
96
+ le: () => le,
97
+ lt: () => lt,
98
+ ne: () => ne
99
+ });
100
+ var EPSILON = 1e-10;
101
+ var valid = (a, b2) => !Number.isNaN(a) && !Number.isNaN(b2);
102
+ function eq(a, b2) {
103
+ return valid(a, b2) && Math.abs(a - b2) <= EPSILON;
104
+ }
105
+ function ne(a, b2) {
106
+ return valid(a, b2) && Math.abs(a - b2) > EPSILON;
107
+ }
108
+ function lt(a, b2) {
109
+ return valid(a, b2) && b2 - a > EPSILON;
110
+ }
111
+ function le(a, b2) {
112
+ return valid(a, b2) && a - b2 <= EPSILON;
113
+ }
114
+ function gt(a, b2) {
115
+ return valid(a, b2) && a - b2 > EPSILON;
116
+ }
117
+ function ge(a, b2) {
118
+ return valid(a, b2) && b2 - a <= EPSILON;
119
+ }
120
+
121
+ // src/ta/index.ts
88
122
  function sma(source, length2) {
89
123
  const result = [];
90
124
  const len = Math.floor(length2);
@@ -276,7 +310,7 @@ function tr(handle_na = false, high, low, close) {
276
310
  const result = [];
277
311
  for (let i = 0; i < high.length; i++) {
278
312
  if (i === 0) {
279
- result.push(high[i] - low[i]);
313
+ result.push(handle_na ? high[i] - low[i] : NaN);
280
314
  } else {
281
315
  const prevClose = close[i - 1];
282
316
  if (isNaN(prevClose)) {
@@ -303,7 +337,7 @@ function atr(length2, high, low, close) {
303
337
  "ta.atr() requires high, low, and close series. Either pass them explicitly or use createContext({ chart: { high, low, close } }) for implicit data."
304
338
  );
305
339
  }
306
- const trueRange = tr(false, high, low, close);
340
+ const trueRange = tr(true, high, low, close);
307
341
  return rma(trueRange, length2);
308
342
  }
309
343
  function supertrend(factor, atrPeriod, high, low, close, wicks = false) {
@@ -780,48 +814,26 @@ function mfi(source, length2, volume) {
780
814
  "ta.mfi() requires volume series. Either pass it explicitly or use createContext({ chart: { ..., volume } }) for implicit data."
781
815
  );
782
816
  }
783
- const result = [];
784
- const changes = [NaN];
785
- for (let i = 1; i < source.length; i++) {
786
- changes.push(source[i] - source[i - 1]);
787
- }
788
- const positiveFlow = [];
789
- const negativeFlow = [];
790
- for (let i = 0; i < source.length; i++) {
791
- if (i === 0 || isNaN(changes[i])) {
792
- positiveFlow.push(0);
793
- negativeFlow.push(0);
794
- } else if (changes[i] > 0) {
795
- positiveFlow.push(volume[i] * source[i]);
796
- negativeFlow.push(0);
797
- } else if (changes[i] < 0) {
798
- positiveFlow.push(0);
799
- negativeFlow.push(volume[i] * source[i]);
800
- } else {
801
- positiveFlow.push(0);
802
- negativeFlow.push(0);
803
- }
804
- }
817
+ const upperFlow = [];
818
+ const lowerFlow = [];
805
819
  for (let i = 0; i < source.length; i++) {
806
- if (i < length2) {
807
- result.push(NaN);
808
- } else {
809
- let posSum = 0;
810
- let negSum = 0;
811
- for (let j = 0; j < length2; j++) {
812
- posSum += positiveFlow[i - j];
813
- negSum += negativeFlow[i - j];
814
- }
815
- if (negSum === 0) {
816
- result.push(100);
817
- } else {
818
- const moneyRatio = posSum / negSum;
819
- const mfiValue = 100 - 100 / (1 + moneyRatio);
820
- result.push(mfiValue);
821
- }
822
- }
823
- }
824
- return result;
820
+ const change3 = i === 0 ? NaN : source[i] - source[i - 1];
821
+ const flow = volume[i] * source[i];
822
+ upperFlow.push(le(change3, 0) ? 0 : flow);
823
+ lowerFlow.push(ge(change3, 0) ? 0 : flow);
824
+ }
825
+ const sumAt = (flow, i) => {
826
+ const values2 = lastValues(flow, i, Math.floor(length2));
827
+ return values2 ? values2.reduce((a, b2) => a + b2, 0) : NaN;
828
+ };
829
+ const upper2 = upperFlow.map((_, i) => sumAt(upperFlow, i));
830
+ const lower2 = lowerFlow.map((_, i) => sumAt(lowerFlow, i));
831
+ return upper2.map((u, i) => {
832
+ const l = lower2[i];
833
+ if (Number.isNaN(u) || Number.isNaN(l)) return NaN;
834
+ if (l === 0) return 100;
835
+ return 100 - 100 / (1 + u / l);
836
+ });
825
837
  }
826
838
  function hma(source, length2) {
827
839
  const halfLength = Math.floor(length2 / 2);
@@ -985,50 +997,32 @@ function dmi(diLength, adxSmoothing, high, low, close) {
985
997
  const len = Math.max(high.length, low.length, close.length);
986
998
  const plusDM = [];
987
999
  const minusDM = [];
988
- const trueRangeValues = tr(false, high, low, close);
989
- for (let i = 0; i < len; i++) {
990
- if (i === 0) {
991
- plusDM.push(0);
992
- minusDM.push(0);
993
- } else {
994
- const upMove = high[i] - high[i - 1];
995
- const downMove = low[i - 1] - low[i];
996
- let plusDMVal = 0;
997
- let minusDMVal = 0;
998
- if (upMove > downMove && upMove > 0) {
999
- plusDMVal = upMove;
1000
- }
1001
- if (downMove > upMove && downMove > 0) {
1002
- minusDMVal = downMove;
1003
- }
1004
- plusDM.push(plusDMVal);
1005
- minusDM.push(minusDMVal);
1006
- }
1007
- }
1008
- const smoothedPlusDM = rma(plusDM, diLength);
1009
- const smoothedMinusDM = rma(minusDM, diLength);
1010
- const smoothedTR = rma(trueRangeValues, diLength);
1011
- const plusDI = [];
1012
- const minusDI = [];
1013
- for (let i = 0; i < len; i++) {
1014
- if (smoothedTR[i] === 0) {
1015
- plusDI.push(0);
1016
- minusDI.push(0);
1017
- } else {
1018
- plusDI.push(smoothedPlusDM[i] / smoothedTR[i] * 100);
1019
- minusDI.push(smoothedMinusDM[i] / smoothedTR[i] * 100);
1020
- }
1021
- }
1022
- const dx = [];
1023
1000
  for (let i = 0; i < len; i++) {
1024
- const sum4 = plusDI[i] + minusDI[i];
1025
- if (sum4 === 0) {
1026
- dx.push(0);
1027
- } else {
1028
- dx.push(Math.abs(plusDI[i] - minusDI[i]) / sum4 * 100);
1029
- }
1030
- }
1031
- const adx = rma(dx, adxSmoothing);
1001
+ const up = i === 0 ? NaN : high[i] - high[i - 1];
1002
+ const down = i === 0 ? NaN : low[i - 1] - low[i];
1003
+ plusDM.push(Number.isNaN(up) ? NaN : gt(up, down) && gt(up, 0) ? up : 0);
1004
+ minusDM.push(Number.isNaN(down) ? NaN : gt(down, up) && gt(down, 0) ? down : 0);
1005
+ }
1006
+ const trur = rma(tr(false, high, low, close), diLength);
1007
+ const smoothedPlus = rma(plusDM, diLength);
1008
+ const smoothedMinus = rma(minusDM, diLength);
1009
+ const directional = (smoothed) => {
1010
+ let last2 = NaN;
1011
+ return smoothed.map((v, i) => {
1012
+ const t2 = trur[i];
1013
+ const value = t2 === 0 ? NaN : 100 * v / t2;
1014
+ if (!Number.isNaN(value)) last2 = value;
1015
+ return last2;
1016
+ });
1017
+ };
1018
+ const plusDI = directional(smoothedPlus);
1019
+ const minusDI = directional(smoothedMinus);
1020
+ const dx = plusDI.map((plus, i) => {
1021
+ const minus = minusDI[i];
1022
+ const sum4 = plus + minus;
1023
+ return Math.abs(plus - minus) / (eq(sum4, 0) ? 1 : sum4);
1024
+ });
1025
+ const adx = rma(dx, adxSmoothing).map((v) => 100 * v);
1032
1026
  return [plusDI, minusDI, adx];
1033
1027
  }
1034
1028
  function tsi(source, shortLength, longLength) {
@@ -1855,38 +1849,6 @@ __export(math_exports, {
1855
1849
  toradians: () => toradians
1856
1850
  });
1857
1851
 
1858
- // src/compare/index.ts
1859
- var compare_exports = {};
1860
- __export(compare_exports, {
1861
- EPSILON: () => EPSILON,
1862
- eq: () => eq,
1863
- ge: () => ge,
1864
- gt: () => gt,
1865
- le: () => le,
1866
- lt: () => lt,
1867
- ne: () => ne
1868
- });
1869
- var EPSILON = 1e-10;
1870
- var valid = (a, b2) => !Number.isNaN(a) && !Number.isNaN(b2);
1871
- function eq(a, b2) {
1872
- return valid(a, b2) && Math.abs(a - b2) <= EPSILON;
1873
- }
1874
- function ne(a, b2) {
1875
- return valid(a, b2) && Math.abs(a - b2) > EPSILON;
1876
- }
1877
- function lt(a, b2) {
1878
- return valid(a, b2) && b2 - a > EPSILON;
1879
- }
1880
- function le(a, b2) {
1881
- return valid(a, b2) && a - b2 <= EPSILON;
1882
- }
1883
- function gt(a, b2) {
1884
- return valid(a, b2) && a - b2 > EPSILON;
1885
- }
1886
- function ge(a, b2) {
1887
- return valid(a, b2) && b2 - a <= EPSILON;
1888
- }
1889
-
1890
1852
  // src/runtime/series.ts
1891
1853
  var BarData = class _BarData {
1892
1854
  _bars;
@@ -6134,6 +6096,44 @@ var format_none = 0;
6134
6096
  var format_bold = 1;
6135
6097
  var format_italic = 2;
6136
6098
 
6099
+ // src/callsite/index.ts
6100
+ var callsite_exports = {};
6101
+ __export(callsite_exports, {
6102
+ cross: () => cross2,
6103
+ crossover: () => crossover2,
6104
+ crossunder: () => crossunder2,
6105
+ whenCalled: () => whenCalled
6106
+ });
6107
+ function whenCalled(called, fn, ...sources) {
6108
+ const bars = [];
6109
+ for (let i = 0; i < called.length; i++) if (called[i]) bars.push(i);
6110
+ const result = fn(...sources.map((s) => bars.map((i) => s[i] ?? NaN)));
6111
+ const out = new Array(called.length).fill(NaN);
6112
+ bars.forEach((bar, k) => {
6113
+ out[bar] = result[k];
6114
+ });
6115
+ return out;
6116
+ }
6117
+ function twoSeriesSite(test) {
6118
+ let prevA = NaN;
6119
+ let prevB = NaN;
6120
+ return (a, b2) => {
6121
+ const result = test(a, b2, prevA, prevB);
6122
+ prevA = a;
6123
+ prevB = b2;
6124
+ return result;
6125
+ };
6126
+ }
6127
+ function crossover2() {
6128
+ return twoSeriesSite((a, b2, pa, pb) => a > b2 && pa <= pb);
6129
+ }
6130
+ function crossunder2() {
6131
+ return twoSeriesSite((a, b2, pa, pb) => a < b2 && pa >= pb);
6132
+ }
6133
+ function cross2() {
6134
+ return twoSeriesSite((a, b2, pa, pb) => a > b2 && pa <= pb || a < b2 && pa >= pb);
6135
+ }
6136
+
6137
6137
  // src/ta-series.ts
6138
6138
  var ta_series_exports = {};
6139
6139
  __export(ta_series_exports, {
@@ -6148,9 +6148,9 @@ __export(ta_series_exports, {
6148
6148
  cmo: () => cmo2,
6149
6149
  cog: () => cog2,
6150
6150
  correlation: () => correlation2,
6151
- cross: () => cross2,
6152
- crossover: () => crossover2,
6153
- crossunder: () => crossunder2,
6151
+ cross: () => cross3,
6152
+ crossover: () => crossover3,
6153
+ crossunder: () => crossunder3,
6154
6154
  cum: () => cum2,
6155
6155
  dev: () => dev2,
6156
6156
  dmi: () => dmi2,
@@ -6316,7 +6316,7 @@ function stoch2(source, high, low, length2) {
6316
6316
  const result = stoch(sourceValues, highValues, lowValues, length2);
6317
6317
  return Series.fromArray(bars, result);
6318
6318
  }
6319
- function crossover2(source1, source2) {
6319
+ function crossover3(source1, source2) {
6320
6320
  const bars = source1.bars;
6321
6321
  const vals1 = source1.toArray();
6322
6322
  const vals2 = typeof source2 === "number" ? Array(bars.length).fill(source2) : source2.toArray();
@@ -6324,7 +6324,7 @@ function crossover2(source1, source2) {
6324
6324
  const numResult = result.map((b2) => b2 ? 1 : 0);
6325
6325
  return Series.fromArray(bars, numResult);
6326
6326
  }
6327
- function crossunder2(source1, source2) {
6327
+ function crossunder3(source1, source2) {
6328
6328
  const bars = source1.bars;
6329
6329
  const vals1 = source1.toArray();
6330
6330
  const vals2 = typeof source2 === "number" ? Array(bars.length).fill(source2) : source2.toArray();
@@ -6332,7 +6332,7 @@ function crossunder2(source1, source2) {
6332
6332
  const numResult = result.map((b2) => b2 ? 1 : 0);
6333
6333
  return Series.fromArray(bars, numResult);
6334
6334
  }
6335
- function cross2(source1, source2) {
6335
+ function cross3(source1, source2) {
6336
6336
  const bars = source1.bars;
6337
6337
  const vals1 = source1.toArray();
6338
6338
  const vals2 = typeof source2 === "number" ? Array(bars.length).fill(source2) : source2.toArray();
@@ -6651,9 +6651,9 @@ var ta = {
6651
6651
  atr: atr2,
6652
6652
  tr: tr2,
6653
6653
  stoch: stoch2,
6654
- crossover: crossover2,
6655
- crossunder: crossunder2,
6656
- cross: cross2,
6654
+ crossover: crossover3,
6655
+ crossunder: crossunder3,
6656
+ cross: cross3,
6657
6657
  change: change2,
6658
6658
  mom: mom2,
6659
6659
  roc: roc2,
@@ -6729,6 +6729,16 @@ function fixnan(source) {
6729
6729
  return seen ? last2 : v;
6730
6730
  });
6731
6731
  }
6732
+ function at(source, i, offset = 0) {
6733
+ if (offset < 0) {
6734
+ throw new RangeError(`at(): the offset must be >= 0 (got ${offset}); a negative offset reads a later bar.`);
6735
+ }
6736
+ const j = i - offset;
6737
+ return j >= 0 && j < source.length ? source[j] ?? NaN : NaN;
6738
+ }
6739
+ function div(a, b2) {
6740
+ return b2 === 0 ? NaN : a / b2;
6741
+ }
6732
6742
  function ohlcFromBars(bars) {
6733
6743
  return {
6734
6744
  open: bars.map((b2) => b2.open),
@@ -6749,6 +6759,50 @@ function getLow(ohlc) {
6749
6759
  function getOpen(ohlc) {
6750
6760
  return ohlc.open;
6751
6761
  }
6762
+ function getSource(data, source = "close") {
6763
+ const isOHLC = "open" in data && Array.isArray(data.open);
6764
+ if (isOHLC) {
6765
+ const ohlc = data;
6766
+ switch (source) {
6767
+ case "close":
6768
+ return ohlc.close;
6769
+ case "open":
6770
+ return ohlc.open;
6771
+ case "high":
6772
+ return ohlc.high;
6773
+ case "low":
6774
+ return ohlc.low;
6775
+ case "hl2":
6776
+ return ohlc.high.map((h, i) => (h + ohlc.low[i]) / 2);
6777
+ case "hlc3":
6778
+ return ohlc.high.map((h, i) => (h + ohlc.low[i] + ohlc.close[i]) / 3);
6779
+ case "ohlc4":
6780
+ return ohlc.open.map((o, i) => (o + ohlc.high[i] + ohlc.low[i] + ohlc.close[i]) / 4);
6781
+ case "hlcc4":
6782
+ return ohlc.high.map((h, i) => (h + ohlc.low[i] + ohlc.close[i] + ohlc.close[i]) / 4);
6783
+ }
6784
+ } else {
6785
+ const bars = data;
6786
+ switch (source) {
6787
+ case "close":
6788
+ return bars.map((b2) => b2.close);
6789
+ case "open":
6790
+ return bars.map((b2) => b2.open);
6791
+ case "high":
6792
+ return bars.map((b2) => b2.high);
6793
+ case "low":
6794
+ return bars.map((b2) => b2.low);
6795
+ case "hl2":
6796
+ return bars.map((b2) => (b2.high + b2.low) / 2);
6797
+ case "hlc3":
6798
+ return bars.map((b2) => (b2.high + b2.low + b2.close) / 3);
6799
+ case "ohlc4":
6800
+ return bars.map((b2) => (b2.open + b2.high + b2.low + b2.close) / 4);
6801
+ case "hlcc4":
6802
+ return bars.map((b2) => (b2.high + b2.low + b2.close + b2.close) / 4);
6803
+ }
6804
+ }
6805
+ }
6752
6806
  function getSourceSeries(bars, source = "close") {
6753
6807
  const open = new Series(bars, (bar) => bar.open);
6754
6808
  const high = new Series(bars, (bar) => bar.high);
@@ -7548,6 +7602,72 @@ function getSourceData(ohlcv, sourceName) {
7548
7602
  }
7549
7603
  }
7550
7604
 
7605
+ // src/strategy/index.ts
7606
+ var STRATEGY_CONSTANTS = {
7607
+ long: "long",
7608
+ short: "short",
7609
+ fixed: "fixed",
7610
+ cash: "cash",
7611
+ percent_of_equity: "percent_of_equity",
7612
+ commission: { percent: "percent", cash_per_contract: "cash_per_contract", cash_per_order: "cash_per_order" },
7613
+ direction: { all: "all", long: "long", short: "short" },
7614
+ oca: { none: "none", cancel: "cancel", reduce: "reduce" }
7615
+ };
7616
+ var STRATEGY_DEFAULTS = {
7617
+ pyramiding: 0,
7618
+ calc_on_order_fills: false,
7619
+ calc_on_every_tick: false,
7620
+ backtest_fill_limits_assumption: 0,
7621
+ default_qty_type: "fixed",
7622
+ default_qty_value: 1,
7623
+ initial_capital: 1e6,
7624
+ slippage: 0,
7625
+ commission_type: "percent",
7626
+ commission_value: 0,
7627
+ process_orders_on_close: false,
7628
+ close_entries_rule: "FIFO",
7629
+ margin_long: 100,
7630
+ margin_short: 100,
7631
+ calc_bars_count: 0,
7632
+ risk_free_rate: 2,
7633
+ use_bar_magnifier: false,
7634
+ fill_orders_on_standard_ohlc: false
7635
+ };
7636
+ var STRATEGY_NUMBER_VARIABLES = [
7637
+ "position_size",
7638
+ "position_avg_price",
7639
+ "equity",
7640
+ "initial_capital",
7641
+ "netprofit",
7642
+ "netprofit_percent",
7643
+ "openprofit",
7644
+ "openprofit_percent",
7645
+ "grossprofit",
7646
+ "grossprofit_percent",
7647
+ "grossloss",
7648
+ "grossloss_percent",
7649
+ "opentrades",
7650
+ "closedtrades",
7651
+ "wintrades",
7652
+ "losstrades",
7653
+ "eventrades",
7654
+ "avg_trade",
7655
+ "avg_trade_percent",
7656
+ "avg_winning_trade",
7657
+ "avg_winning_trade_percent",
7658
+ "avg_losing_trade",
7659
+ "avg_losing_trade_percent",
7660
+ "max_drawdown",
7661
+ "max_drawdown_percent",
7662
+ "max_runup",
7663
+ "max_runup_percent",
7664
+ "max_contracts_held_all",
7665
+ "max_contracts_held_long",
7666
+ "max_contracts_held_short",
7667
+ "margin_liquidation_price"
7668
+ ];
7669
+ var STRATEGY_TEXT_VARIABLES = ["position_entry_name", "account_currency"];
7670
+
7551
7671
  // src/runtime/adapters/LightweightChartsAdapter.ts
7552
7672
  var LightweightChartsAdapter = class {
7553
7673
  chart;
@@ -7756,7 +7876,7 @@ var SimpleInputAdapter = class {
7756
7876
  };
7757
7877
 
7758
7878
  // src/index.ts
7759
- var VERSION = "0.7.2";
7879
+ var VERSION = "0.8.0";
7760
7880
  var info2 = {
7761
7881
  name: "OakScriptJS",
7762
7882
  version: VERSION,
@@ -7781,6 +7901,10 @@ function alertcondition(_condition, _title, _message) {
7781
7901
  export {
7782
7902
  BarData,
7783
7903
  LightweightChartsAdapter,
7904
+ STRATEGY_CONSTANTS,
7905
+ STRATEGY_DEFAULTS,
7906
+ STRATEGY_NUMBER_VARIABLES,
7907
+ STRATEGY_TEXT_VARIABLES,
7784
7908
  Series,
7785
7909
  SimpleInputAdapter,
7786
7910
  VERSION,
@@ -7788,11 +7912,13 @@ export {
7788
7912
  abs,
7789
7913
  alertcondition,
7790
7914
  array_exports as array,
7915
+ at,
7791
7916
  atr2 as atr,
7792
7917
  avg,
7793
7918
  bb2 as bb,
7794
7919
  box_exports as box,
7795
7920
  calculateZigZag,
7921
+ callsite_exports as callsite,
7796
7922
  ceil,
7797
7923
  change2 as change,
7798
7924
  chartpoint_exports as chartPoint,
@@ -7803,9 +7929,10 @@ export {
7803
7929
  compare_exports as compare,
7804
7930
  cos,
7805
7931
  createPlot,
7806
- crossover2 as crossover,
7807
- crossunder2 as crossunder,
7932
+ crossover3 as crossover,
7933
+ crossunder3 as crossunder,
7808
7934
  cum2 as cum,
7935
+ div,
7809
7936
  ema2 as ema,
7810
7937
  exp,
7811
7938
  fixnan,
@@ -7815,6 +7942,7 @@ export {
7815
7942
  getHigh,
7816
7943
  getLow,
7817
7944
  getOpen,
7945
+ getSource,
7818
7946
  getSourceSeries,
7819
7947
  hline,
7820
7948
  indicator,