oakscriptjs 0.9.0 → 0.9.2
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/cjs/array/index.d.ts +1 -1
- package/dist/cjs/array/index.d.ts.map +1 -1
- package/dist/cjs/array/index.js +2 -1
- package/dist/cjs/array/index.js.map +2 -2
- package/dist/cjs/callsite/index.d.ts +27 -0
- package/dist/cjs/callsite/index.d.ts.map +1 -1
- package/dist/cjs/callsite/index.js +47 -0
- package/dist/cjs/callsite/index.js.map +2 -2
- package/dist/cjs/color/index.d.ts +1 -0
- package/dist/cjs/color/index.d.ts.map +1 -1
- package/dist/cjs/color/index.js +9 -30
- package/dist/cjs/color/index.js.map +2 -2
- package/dist/cjs/color/parse.d.ts +29 -0
- package/dist/cjs/color/parse.d.ts.map +1 -0
- package/dist/cjs/color/parse.js +57 -0
- package/dist/cjs/color/parse.js.map +7 -0
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/script/index.d.ts +4 -0
- package/dist/cjs/script/index.d.ts.map +1 -1
- package/dist/cjs/script/index.js +6 -1
- package/dist/cjs/script/index.js.map +2 -2
- package/dist/cjs/ta/index.d.ts +5 -0
- package/dist/cjs/ta/index.d.ts.map +1 -1
- package/dist/cjs/ta/index.js +19 -19
- package/dist/cjs/ta/index.js.map +2 -2
- package/dist/esm/array/index.d.ts +1 -1
- package/dist/esm/array/index.d.ts.map +1 -1
- package/dist/esm/array/index.js +3 -2
- package/dist/esm/array/index.js.map +1 -1
- package/dist/esm/callsite/index.d.ts +27 -0
- package/dist/esm/callsite/index.d.ts.map +1 -1
- package/dist/esm/callsite/index.js +79 -0
- package/dist/esm/callsite/index.js.map +1 -1
- package/dist/esm/color/index.d.ts +1 -0
- package/dist/esm/color/index.d.ts.map +1 -1
- package/dist/esm/color/index.js +13 -36
- package/dist/esm/color/index.js.map +1 -1
- package/dist/esm/color/parse.d.ts +29 -0
- package/dist/esm/color/parse.d.ts.map +1 -0
- package/dist/esm/color/parse.js +55 -0
- package/dist/esm/color/parse.js.map +1 -0
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/script/index.d.ts +4 -0
- package/dist/esm/script/index.d.ts.map +1 -1
- package/dist/esm/script/index.js +6 -1
- package/dist/esm/script/index.js.map +1 -1
- package/dist/esm/ta/index.d.ts +5 -0
- package/dist/esm/ta/index.d.ts.map +1 -1
- package/dist/esm/ta/index.js +34 -28
- package/dist/esm/ta/index.js.map +1 -1
- package/package.json +1 -1
- package/src/array/index.ts +3 -2
- package/src/callsite/index.ts +74 -0
- package/src/color/index.ts +14 -36
- package/src/color/parse.ts +56 -0
- package/src/index.ts +1 -1
- package/src/script/index.ts +6 -1
- package/src/ta/index.ts +32 -31
package/src/index.ts
CHANGED
|
@@ -164,7 +164,7 @@ export type { LightweightSeriesDefinitions } from './runtime/adapters/Lightweigh
|
|
|
164
164
|
export { SimpleInputAdapter } from './runtime/adapters/SimpleInputAdapter.js';
|
|
165
165
|
|
|
166
166
|
// Version
|
|
167
|
-
export const VERSION = '0.9.
|
|
167
|
+
export const VERSION = '0.9.2';
|
|
168
168
|
|
|
169
169
|
/**
|
|
170
170
|
* Library information
|
package/src/script/index.ts
CHANGED
|
@@ -58,6 +58,7 @@ import type {
|
|
|
58
58
|
import { BarData, Series } from '../runtime/series.js';
|
|
59
59
|
import * as taSeries from '../ta-series.js';
|
|
60
60
|
import * as colorCore from '../color/index.js';
|
|
61
|
+
import { inputColorDefault } from '../color/parse.js';
|
|
61
62
|
import { fixnan as fixnanValues, isNA, nz } from '../utils/index.js';
|
|
62
63
|
import * as lineCore from '../line/index.js';
|
|
63
64
|
import * as labelCore from '../label/index.js';
|
|
@@ -404,8 +405,12 @@ export const input = {
|
|
|
404
405
|
string(defval: string, title?: string, opts: StringInputOptions = {}): string {
|
|
405
406
|
return registerInput<string>({ type: 'string', defval, title, options: opts.options, ...common(opts) }, 'input_string');
|
|
406
407
|
},
|
|
408
|
+
/**
|
|
409
|
+
* Declares a colour input. As in PineScript, the default keeps an alpha of 2 decimals: an input default
|
|
410
|
+
* `color.new(c, 90)` has the alpha byte 26 (25 in the script). A value given by the host is not changed.
|
|
411
|
+
*/
|
|
407
412
|
color(defval: string, title?: string, opts: InputOptions = {}): string {
|
|
408
|
-
return registerInput<string>({ type: 'color', defval, title, ...common(opts) }, 'input_color');
|
|
413
|
+
return registerInput<string>({ type: 'color', defval: inputColorDefault(defval), title, ...common(opts) }, 'input_color');
|
|
409
414
|
},
|
|
410
415
|
/** Declares a source input and returns it as a Series. */
|
|
411
416
|
source(defval: string = 'close', title?: string, opts: InputOptions = {}): Series {
|
package/src/ta/index.ts
CHANGED
|
@@ -127,6 +127,8 @@ export function ema(source: Source, length: simple_int): series_float {
|
|
|
127
127
|
* - RSI values below 30 typically indicate oversold conditions
|
|
128
128
|
* - Uses `ta.rma()` (Relative Moving Average) for smoothing, matching PineScript v6
|
|
129
129
|
* - Formula: RSI = 100 - (100 / (1 + RS)), where RS = Average Gain / Average Loss
|
|
130
|
+
* - As in PineScript (`down == 0 ? 100 : up == 0 ? 0 : ...`): 100 when the average loss is 0, else 0 when the
|
|
131
|
+
* average gain is 0, both with the 1e-10 tolerance of the comparison operators
|
|
130
132
|
* - Average Gain and Average Loss are calculated using RMA (alpha = 1 / length)
|
|
131
133
|
* - `na` values in the source series are ignored
|
|
132
134
|
*
|
|
@@ -158,8 +160,10 @@ export function rsi(source: Source, length: simple_int): series_float {
|
|
|
158
160
|
result.push(NaN); // First value is NaN
|
|
159
161
|
|
|
160
162
|
for (let i = 0; i < avgGains.length; i++) {
|
|
161
|
-
if (avgLosses[i]
|
|
163
|
+
if (eq(avgLosses[i]!, 0)) {
|
|
162
164
|
result.push(100);
|
|
165
|
+
} else if (eq(avgGains[i]!, 0)) {
|
|
166
|
+
result.push(0);
|
|
163
167
|
} else {
|
|
164
168
|
const rs = avgGains[i]! / avgLosses[i]!;
|
|
165
169
|
result.push(100 - (100 / (1 + rs)));
|
|
@@ -569,6 +573,7 @@ export function atr(length: simple_int, high?: Source, low?: Source, close?: Sou
|
|
|
569
573
|
* - Direction: 1 = downtrend (red), -1 = uptrend (green)
|
|
570
574
|
* - Uses hl2 (average of high and low) as the source
|
|
571
575
|
* - SuperTrend helps identify the current market trend and potential reversal points
|
|
576
|
+
* - As in PineScript (`nz` of the previous bands): 0 on bar 0, na on the next bars while the ATR is na
|
|
572
577
|
*
|
|
573
578
|
* @example
|
|
574
579
|
* ```typescript
|
|
@@ -608,41 +613,35 @@ export function supertrend(
|
|
|
608
613
|
// Calculate ATR
|
|
609
614
|
const atrValues = atr(atrPeriod, high, low, close);
|
|
610
615
|
|
|
611
|
-
//
|
|
612
|
-
|
|
613
|
-
|
|
616
|
+
// PineScript reference implementation (bar by bar):
|
|
617
|
+
// prevLowerBand = nz(lowerBand[1]), prevUpperBand = nz(upperBand[1])
|
|
618
|
+
// lowerBand := lowerBand > prevLowerBand or close[1] < prevLowerBand ? lowerBand : prevLowerBand
|
|
619
|
+
// upperBand := upperBand < prevUpperBand or close[1] > prevUpperBand ? upperBand : prevUpperBand
|
|
620
|
+
// direction = na(atr[1]) ? 1 : prevSuperTrend == prevUpperBand ? (close > upperBand ? -1 : 1) : (close < lowerBand ? 1 : -1)
|
|
621
|
+
// A comparison with na is false: on bar 0 (close[1] na) both bands take nz(na) = 0, so the supertrend is 0.
|
|
622
|
+
const nz = (v: number) => (isNaN(v) ? 0 : v);
|
|
623
|
+
let lastLowerBand = NaN;
|
|
624
|
+
let lastUpperBand = NaN;
|
|
614
625
|
let prevSuperTrend = NaN;
|
|
615
626
|
|
|
616
627
|
for (let i = 0; i < source.length; i++) {
|
|
617
628
|
const atrValue = atrValues[i]! * factor;
|
|
618
|
-
|
|
619
|
-
// Skip calculation if ATR is not available yet
|
|
620
|
-
if (isNaN(atrValue)) {
|
|
621
|
-
supertrendValues.push(NaN);
|
|
622
|
-
directions.push(1);
|
|
623
|
-
continue;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
// Calculate initial bands
|
|
627
629
|
let upperBand = source[i]! + atrValue;
|
|
628
630
|
let lowerBand = source[i]! - atrValue;
|
|
631
|
+
const prevLowerBand = nz(lastLowerBand);
|
|
632
|
+
const prevUpperBand = nz(lastUpperBand);
|
|
629
633
|
|
|
630
|
-
//
|
|
634
|
+
// Price compared with the bands: close, or low / high with wicks
|
|
631
635
|
const highPrice = wicks ? high[i]! : close[i]!;
|
|
632
636
|
const lowPrice = wicks ? low[i]! : close[i]!;
|
|
633
|
-
const prevLowPrice = i > 0 ? (wicks ? low[i - 1]! : close[i - 1]!) :
|
|
634
|
-
const prevHighPrice = i > 0 ? (wicks ? high[i - 1]! : close[i - 1]!) :
|
|
637
|
+
const prevLowPrice = i > 0 ? (wicks ? low[i - 1]! : close[i - 1]!) : NaN;
|
|
638
|
+
const prevHighPrice = i > 0 ? (wicks ? high[i - 1]! : close[i - 1]!) : NaN;
|
|
635
639
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
lowerBand = (lowerBand > prevLowerBand || prevLowPrice < prevLowerBand) ? lowerBand : prevLowerBand;
|
|
639
|
-
upperBand = (upperBand < prevUpperBand || prevHighPrice > prevUpperBand) ? upperBand : prevUpperBand;
|
|
640
|
-
}
|
|
640
|
+
lowerBand = lowerBand > prevLowerBand || prevLowPrice < prevLowerBand ? lowerBand : prevLowerBand;
|
|
641
|
+
upperBand = upperBand < prevUpperBand || prevHighPrice > prevUpperBand ? upperBand : prevUpperBand;
|
|
641
642
|
|
|
642
|
-
// Determine trend direction
|
|
643
643
|
let currentDirection: int;
|
|
644
|
-
if (isNaN(
|
|
645
|
-
// Initial direction when we don't have previous supertrend
|
|
644
|
+
if (i === 0 || isNaN(atrValues[i - 1]!)) {
|
|
646
645
|
currentDirection = 1;
|
|
647
646
|
} else if (prevSuperTrend === prevUpperBand) {
|
|
648
647
|
// Was in downtrend (following upper band)
|
|
@@ -652,15 +651,12 @@ export function supertrend(
|
|
|
652
651
|
currentDirection = lowPrice < lowerBand ? 1 : -1;
|
|
653
652
|
}
|
|
654
653
|
|
|
655
|
-
// Calculate supertrend value based on direction
|
|
656
654
|
const superTrendValue = currentDirection === -1 ? lowerBand : upperBand;
|
|
657
|
-
|
|
658
655
|
supertrendValues.push(superTrendValue);
|
|
659
656
|
directions.push(currentDirection);
|
|
660
657
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
prevUpperBand = upperBand;
|
|
658
|
+
lastLowerBand = lowerBand;
|
|
659
|
+
lastUpperBand = upperBand;
|
|
664
660
|
prevSuperTrend = superTrendValue;
|
|
665
661
|
}
|
|
666
662
|
|
|
@@ -1476,6 +1472,7 @@ export function percentrank(source: Source, length: simple_int): series_float {
|
|
|
1476
1472
|
* - Typical Price = (High + Low + Close) / 3
|
|
1477
1473
|
* - Mean Deviation = Average of absolute differences from mean
|
|
1478
1474
|
* - Scaled by 0.015 to provide more readable numbers
|
|
1475
|
+
* - As in PineScript: when the mean deviation is 0 (1e-10 tolerance, a flat window), the CCI of the previous bar
|
|
1479
1476
|
* - Values above +100 indicate overbought conditions
|
|
1480
1477
|
* - Values below -100 indicate oversold conditions
|
|
1481
1478
|
* - \`na\` values in the source series are ignored
|
|
@@ -1493,8 +1490,10 @@ export function cci(source: Source, length: simple_int): series_float {
|
|
|
1493
1490
|
const devValues = dev(source, length);
|
|
1494
1491
|
|
|
1495
1492
|
for (let i = 0; i < source.length; i++) {
|
|
1496
|
-
if (isNaN(smaValues[i]!) || isNaN(devValues[i]!)
|
|
1493
|
+
if (isNaN(smaValues[i]!) || isNaN(devValues[i]!)) {
|
|
1497
1494
|
result.push(NaN);
|
|
1495
|
+
} else if (eq(devValues[i]!, 0)) {
|
|
1496
|
+
result.push(i > 0 ? result[i - 1]! : NaN);
|
|
1498
1497
|
} else {
|
|
1499
1498
|
const cci = (source[i]! - smaValues[i]!) / (0.015 * devValues[i]!);
|
|
1500
1499
|
result.push(cci);
|
|
@@ -2079,6 +2078,7 @@ export function tsi(source: Source, shortLength: simple_int, longLength: simple_
|
|
|
2079
2078
|
* - CMO > +50: overbought conditions
|
|
2080
2079
|
* - CMO < -50: oversold conditions
|
|
2081
2080
|
* - Unlike RSI, CMO uses sum of gains/losses instead of averages
|
|
2081
|
+
* - na on a flat window (every change 0), as in PineScript
|
|
2082
2082
|
* - More volatile than RSI
|
|
2083
2083
|
*
|
|
2084
2084
|
* @example
|
|
@@ -2109,9 +2109,10 @@ export function cmo(source: Source, length: simple_int): series_float {
|
|
|
2109
2109
|
}
|
|
2110
2110
|
}
|
|
2111
2111
|
|
|
2112
|
+
// PineScript: 100 * (sm1 - sm2) / (sm1 + sm2), so a flat window (0 / 0) is na
|
|
2112
2113
|
const totalMovement = sumGains + sumLosses;
|
|
2113
2114
|
if (totalMovement === 0) {
|
|
2114
|
-
result.push(
|
|
2115
|
+
result.push(NaN);
|
|
2115
2116
|
} else {
|
|
2116
2117
|
const cmoValue = ((sumGains - sumLosses) / totalMovement) * 100;
|
|
2117
2118
|
result.push(cmoValue);
|