@tranding-custom-chart/financial 0.0.0-stage → 2.0.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/README.md +40 -2
- package/dist/adapter.d.ts +24 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +47 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/indicators/atr.d.ts +13 -0
- package/dist/indicators/atr.d.ts.map +1 -0
- package/dist/indicators/atr.js +40 -0
- package/dist/indicators/bollinger.d.ts +12 -0
- package/dist/indicators/bollinger.d.ts.map +1 -0
- package/dist/indicators/bollinger.js +34 -0
- package/dist/indicators/ema.d.ts +7 -0
- package/dist/indicators/ema.d.ts.map +1 -0
- package/dist/indicators/ema.js +26 -0
- package/dist/indicators/heikin-ashi.d.ts +14 -0
- package/dist/indicators/heikin-ashi.d.ts.map +1 -0
- package/dist/indicators/heikin-ashi.js +36 -0
- package/dist/indicators/kagi.d.ts +20 -0
- package/dist/indicators/kagi.d.ts.map +1 -0
- package/dist/indicators/kagi.js +122 -0
- package/dist/indicators/line-break.d.ts +18 -0
- package/dist/indicators/line-break.d.ts.map +1 -0
- package/dist/indicators/line-break.js +73 -0
- package/dist/indicators/macd.d.ts +13 -0
- package/dist/indicators/macd.d.ts.map +1 -0
- package/dist/indicators/macd.js +60 -0
- package/dist/indicators/renko.d.ts +19 -0
- package/dist/indicators/renko.d.ts.map +1 -0
- package/dist/indicators/renko.js +84 -0
- package/dist/indicators/rsi.d.ts +7 -0
- package/dist/indicators/rsi.d.ts.map +1 -0
- package/dist/indicators/rsi.js +47 -0
- package/dist/indicators/sma.d.ts +15 -0
- package/dist/indicators/sma.d.ts.map +1 -0
- package/dist/indicators/sma.js +37 -0
- package/dist/indicators/supertrend.d.ts +8 -0
- package/dist/indicators/supertrend.d.ts.map +1 -0
- package/dist/indicators/supertrend.js +88 -0
- package/dist/indicators/volume-profile.d.ts +10 -0
- package/dist/indicators/volume-profile.d.ts.map +1 -0
- package/dist/indicators/volume-profile.js +134 -0
- package/dist/indicators/vwap.d.ts +7 -0
- package/dist/indicators/vwap.d.ts.map +1 -0
- package/dist/indicators/vwap.js +33 -0
- package/dist/indicators/wma.d.ts +7 -0
- package/dist/indicators/wma.d.ts.map +1 -0
- package/dist/indicators/wma.js +21 -0
- package/dist/layout/pane-layout.d.ts +19 -0
- package/dist/layout/pane-layout.d.ts.map +1 -0
- package/dist/layout/pane-layout.js +39 -0
- package/package.json +33 -4
package/README.md
CHANGED
|
@@ -1,3 +1,41 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @tranding-custom-chart/financial
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> High-throughput financial indicators, market data adapters, multi-pane geometry, and time-independent series engines.
|
|
4
|
+
|
|
5
|
+
[](https://semver.org)
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
- **Technical Indicators**:
|
|
9
|
+
- `computeSMA`: Simple Moving Average.
|
|
10
|
+
- `computeEMA`: Exponential Moving Average.
|
|
11
|
+
- `computeWMA`: Weighted Moving Average.
|
|
12
|
+
- `computeVWAP`: Session-anchored Volume Weighted Average Price.
|
|
13
|
+
- `computeBollingerBands`: Volatility envelope with standard deviation multiplier.
|
|
14
|
+
- `computeRSI`: Relative Strength Index with Wilder's smoothing.
|
|
15
|
+
- `computeMACD`: MACD Line, Signal Line, and Divergence Histogram.
|
|
16
|
+
- `computeATR`: Average True Range volatility measure.
|
|
17
|
+
- `computeSupertrend`: ATR-based dynamic trailing stop bands with direction and reversal tracking.
|
|
18
|
+
- `computeVolumeProfile`: Visible Range Volume Profile (VRVP) binned volume with POC and 70% Value Area bounds.
|
|
19
|
+
- **Time-Independent Series**:
|
|
20
|
+
- `computeRenko`: Price movement bricks eliminating market noise.
|
|
21
|
+
- `computeHeikinAshi`: Mathematical synthetic trend smoothing.
|
|
22
|
+
- **Multi-Pane Layout Calculator**:
|
|
23
|
+
- `computePaneLayouts`: Splits vertical chart height proportionally across Price, Volume, and Oscillator panes.
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
```bash
|
|
27
|
+
npm install @tranding-custom-chart/financial @tranding-custom-chart/core
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
```ts
|
|
32
|
+
import { computeSupertrend, computeVolumeProfile } from '@tranding-custom-chart/financial';
|
|
33
|
+
|
|
34
|
+
const supertrend = computeSupertrend(bars, { period: 10, multiplier: 3.0 });
|
|
35
|
+
const profile = computeVolumeProfile(bars, { binCount: 24, valueAreaRatio: 0.7 });
|
|
36
|
+
|
|
37
|
+
console.log('POC Price:', profile.pocPrice);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## License
|
|
41
|
+
UNLICENSED (Internal / In-House Use)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/adapter.ts
|
|
3
|
+
* Adapter converting raw market contracts (e.g. StoredCandleDto) into canonical OHLCVBar objects.
|
|
4
|
+
* Truthfulness guarantee: never fabricates artificial candles.
|
|
5
|
+
*/
|
|
6
|
+
import { type OHLCVBar } from '@tranding-custom-chart/core';
|
|
7
|
+
export interface RawCandleInput {
|
|
8
|
+
readonly id?: string | undefined;
|
|
9
|
+
readonly entityKey?: string | undefined;
|
|
10
|
+
readonly interval?: string | undefined;
|
|
11
|
+
readonly candleStart: string;
|
|
12
|
+
readonly open: string | number;
|
|
13
|
+
readonly high: string | number;
|
|
14
|
+
readonly low: string | number;
|
|
15
|
+
readonly close: string | number;
|
|
16
|
+
readonly volume?: string | number | null | undefined;
|
|
17
|
+
readonly qualityFlags?: readonly string[] | undefined;
|
|
18
|
+
readonly timezoneInterpretation?: string | undefined;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Normalizes an array of raw candle inputs into strictly validated, sorted OHLCV bars.
|
|
22
|
+
*/
|
|
23
|
+
export declare function normalizeCandleDtos(candles: readonly RawCandleInput[]): readonly OHLCVBar[];
|
|
24
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,QAAQ,EAGd,MAAM,6BAA6B,CAAC;AAErC,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACrD,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACtD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,SAAS,cAAc,EAAE,GACjC,SAAS,QAAQ,EAAE,CA0CrB"}
|
package/dist/adapter.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/adapter.ts
|
|
3
|
+
* Adapter converting raw market contracts (e.g. StoredCandleDto) into canonical OHLCVBar objects.
|
|
4
|
+
* Truthfulness guarantee: never fabricates artificial candles.
|
|
5
|
+
*/
|
|
6
|
+
import { normalizeTimeSeries, validateOHLCVBar, } from '@tranding-custom-chart/core';
|
|
7
|
+
/**
|
|
8
|
+
* Normalizes an array of raw candle inputs into strictly validated, sorted OHLCV bars.
|
|
9
|
+
*/
|
|
10
|
+
export function normalizeCandleDtos(candles) {
|
|
11
|
+
if (!candles || candles.length === 0)
|
|
12
|
+
return [];
|
|
13
|
+
const rawBars = [];
|
|
14
|
+
for (const c of candles) {
|
|
15
|
+
const timeMs = Date.parse(c.candleStart);
|
|
16
|
+
if (!Number.isFinite(timeMs) || timeMs <= 0)
|
|
17
|
+
continue;
|
|
18
|
+
const time = Math.floor(timeMs / 1000); // Unix timestamp in seconds
|
|
19
|
+
const open = typeof c.open === 'number' ? c.open : Number.parseFloat(c.open);
|
|
20
|
+
const high = typeof c.high === 'number' ? c.high : Number.parseFloat(c.high);
|
|
21
|
+
const low = typeof c.low === 'number' ? c.low : Number.parseFloat(c.low);
|
|
22
|
+
const close = typeof c.close === 'number' ? c.close : Number.parseFloat(c.close);
|
|
23
|
+
let volume = null;
|
|
24
|
+
if (c.volume !== null && c.volume !== undefined) {
|
|
25
|
+
const parsedVol = typeof c.volume === 'number' ? c.volume : Number.parseFloat(c.volume);
|
|
26
|
+
if (Number.isFinite(parsedVol) && parsedVol >= 0) {
|
|
27
|
+
volume = parsedVol;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const candidate = {
|
|
31
|
+
time,
|
|
32
|
+
dateStr: c.candleStart,
|
|
33
|
+
open,
|
|
34
|
+
high,
|
|
35
|
+
low,
|
|
36
|
+
close,
|
|
37
|
+
volume,
|
|
38
|
+
qualityFlags: c.qualityFlags ?? [],
|
|
39
|
+
};
|
|
40
|
+
const validation = validateOHLCVBar(candidate);
|
|
41
|
+
if (validation.valid) {
|
|
42
|
+
rawBars.push(candidate);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Deduplicate by timestamp and sort ascending
|
|
46
|
+
return normalizeTimeSeries(rawBars, (b) => b.time);
|
|
47
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/index.ts
|
|
3
|
+
* Main entry point for @tranding-custom-chart/financial.
|
|
4
|
+
*/
|
|
5
|
+
export * from './adapter.js';
|
|
6
|
+
export * from './indicators/sma.js';
|
|
7
|
+
export * from './indicators/ema.js';
|
|
8
|
+
export * from './indicators/rsi.js';
|
|
9
|
+
export * from './indicators/bollinger.js';
|
|
10
|
+
export * from './indicators/heikin-ashi.js';
|
|
11
|
+
export * from './indicators/vwap.js';
|
|
12
|
+
export * from './indicators/macd.js';
|
|
13
|
+
export * from './indicators/wma.js';
|
|
14
|
+
export * from './indicators/renko.js';
|
|
15
|
+
export * from './indicators/kagi.js';
|
|
16
|
+
export * from './indicators/line-break.js';
|
|
17
|
+
export * from './indicators/volume-profile.js';
|
|
18
|
+
export * from './indicators/atr.js';
|
|
19
|
+
export * from './indicators/supertrend.js';
|
|
20
|
+
export * from './layout/pane-layout.js';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/index.ts
|
|
3
|
+
* Main entry point for @tranding-custom-chart/financial.
|
|
4
|
+
*/
|
|
5
|
+
export * from './adapter.js';
|
|
6
|
+
export * from './indicators/sma.js';
|
|
7
|
+
export * from './indicators/ema.js';
|
|
8
|
+
export * from './indicators/rsi.js';
|
|
9
|
+
export * from './indicators/bollinger.js';
|
|
10
|
+
export * from './indicators/heikin-ashi.js';
|
|
11
|
+
export * from './indicators/vwap.js';
|
|
12
|
+
export * from './indicators/macd.js';
|
|
13
|
+
export * from './indicators/wma.js';
|
|
14
|
+
export * from './indicators/renko.js';
|
|
15
|
+
export * from './indicators/kagi.js';
|
|
16
|
+
export * from './indicators/line-break.js';
|
|
17
|
+
export * from './indicators/volume-profile.js';
|
|
18
|
+
export * from './indicators/atr.js';
|
|
19
|
+
export * from './indicators/supertrend.js';
|
|
20
|
+
export * from './layout/pane-layout.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/atr.ts
|
|
3
|
+
* Average True Range (ATR) calculation engine.
|
|
4
|
+
*/
|
|
5
|
+
import type { OHLCVBar, ATRPoint } from '@tranding-custom-chart/core';
|
|
6
|
+
export interface ATROptions {
|
|
7
|
+
readonly period?: number | undefined;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Computes True Range and smoothed Average True Range (ATR).
|
|
11
|
+
*/
|
|
12
|
+
export declare function computeATR(bars: readonly OHLCVBar[], period?: number): readonly ATRPoint[];
|
|
13
|
+
//# sourceMappingURL=atr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atr.d.ts","sourceRoot":"","sources":["../../src/indicators/atr.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAEtE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,MAAM,GAAE,MAAW,GAClB,SAAS,QAAQ,EAAE,CAqCrB"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/atr.ts
|
|
3
|
+
* Average True Range (ATR) calculation engine.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Computes True Range and smoothed Average True Range (ATR).
|
|
7
|
+
*/
|
|
8
|
+
export function computeATR(bars, period = 14) {
|
|
9
|
+
if (bars.length === 0)
|
|
10
|
+
return [];
|
|
11
|
+
const results = [];
|
|
12
|
+
const p = Math.max(1, period);
|
|
13
|
+
let prevClose = bars[0].open;
|
|
14
|
+
let trSum = 0;
|
|
15
|
+
let prevATR = 0;
|
|
16
|
+
for (let i = 0; i < bars.length; i++) {
|
|
17
|
+
const bar = bars[i];
|
|
18
|
+
const hl = bar.high - bar.low;
|
|
19
|
+
const hc = Math.abs(bar.high - prevClose);
|
|
20
|
+
const lc = Math.abs(bar.low - prevClose);
|
|
21
|
+
const tr = Math.max(hl, hc, lc);
|
|
22
|
+
let atr = 0;
|
|
23
|
+
if (i < p) {
|
|
24
|
+
trSum += tr;
|
|
25
|
+
atr = trSum / (i + 1);
|
|
26
|
+
prevATR = atr;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
atr = (prevATR * (p - 1) + tr) / p;
|
|
30
|
+
prevATR = atr;
|
|
31
|
+
}
|
|
32
|
+
results.push({
|
|
33
|
+
time: bar.time,
|
|
34
|
+
tr,
|
|
35
|
+
atr,
|
|
36
|
+
});
|
|
37
|
+
prevClose = bar.close;
|
|
38
|
+
}
|
|
39
|
+
return results;
|
|
40
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/bollinger.ts
|
|
3
|
+
* Bollinger Bands calculation (Middle SMA, Upper Band, Lower Band).
|
|
4
|
+
*/
|
|
5
|
+
import type { OHLCVBar } from '@tranding-custom-chart/core';
|
|
6
|
+
export interface BollingerBandsResult {
|
|
7
|
+
readonly middle: (number | null)[];
|
|
8
|
+
readonly upper: (number | null)[];
|
|
9
|
+
readonly lower: (number | null)[];
|
|
10
|
+
}
|
|
11
|
+
export declare function computeBollingerBands(bars: readonly OHLCVBar[], period?: number, multiplier?: number): BollingerBandsResult;
|
|
12
|
+
//# sourceMappingURL=bollinger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bollinger.d.ts","sourceRoot":"","sources":["../../src/indicators/bollinger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;CACnC;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,MAAM,SAAK,EACX,UAAU,SAAI,GACb,oBAAoB,CAqCtB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/bollinger.ts
|
|
3
|
+
* Bollinger Bands calculation (Middle SMA, Upper Band, Lower Band).
|
|
4
|
+
*/
|
|
5
|
+
export function computeBollingerBands(bars, period = 20, multiplier = 2) {
|
|
6
|
+
const length = bars.length;
|
|
7
|
+
const middle = new Array(length).fill(null);
|
|
8
|
+
const upper = new Array(length).fill(null);
|
|
9
|
+
const lower = new Array(length).fill(null);
|
|
10
|
+
if (period <= 0 || length < period) {
|
|
11
|
+
return { middle, upper, lower };
|
|
12
|
+
}
|
|
13
|
+
let windowSum = 0;
|
|
14
|
+
for (let i = 0; i < length; i++) {
|
|
15
|
+
windowSum += bars[i].close;
|
|
16
|
+
if (i >= period) {
|
|
17
|
+
windowSum -= bars[i - period].close;
|
|
18
|
+
}
|
|
19
|
+
if (i >= period - 1) {
|
|
20
|
+
const mean = windowSum / period;
|
|
21
|
+
middle[i] = mean;
|
|
22
|
+
// Calculate population variance over the window
|
|
23
|
+
let varianceSum = 0;
|
|
24
|
+
for (let j = i - period + 1; j <= i; j++) {
|
|
25
|
+
const diff = bars[j].close - mean;
|
|
26
|
+
varianceSum += diff * diff;
|
|
27
|
+
}
|
|
28
|
+
const stdDev = Math.sqrt(varianceSum / period);
|
|
29
|
+
upper[i] = mean + multiplier * stdDev;
|
|
30
|
+
lower[i] = mean - multiplier * stdDev;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { middle, upper, lower };
|
|
34
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/ema.ts
|
|
3
|
+
* Exponential Moving Average (EMA) computation with formal initial smoothing.
|
|
4
|
+
*/
|
|
5
|
+
import type { OHLCVBar } from '@tranding-custom-chart/core';
|
|
6
|
+
export declare function computeEMA(bars: readonly OHLCVBar[], period: number): (number | null)[];
|
|
7
|
+
//# sourceMappingURL=ema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ema.d.ts","sourceRoot":"","sources":["../../src/indicators/ema.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D,wBAAgB,UAAU,CACxB,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,MAAM,EAAE,MAAM,GACb,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAyBnB"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/ema.ts
|
|
3
|
+
* Exponential Moving Average (EMA) computation with formal initial smoothing.
|
|
4
|
+
*/
|
|
5
|
+
export function computeEMA(bars, period) {
|
|
6
|
+
if (period <= 0 || bars.length < period) {
|
|
7
|
+
return bars.map(() => null);
|
|
8
|
+
}
|
|
9
|
+
const result = new Array(bars.length).fill(null);
|
|
10
|
+
const alpha = 2 / (period + 1);
|
|
11
|
+
// Initialize first EMA value at (period - 1) as simple average
|
|
12
|
+
let initialSum = 0;
|
|
13
|
+
for (let i = 0; i < period; i++) {
|
|
14
|
+
initialSum += bars[i].close;
|
|
15
|
+
}
|
|
16
|
+
let prevEma = initialSum / period;
|
|
17
|
+
result[period - 1] = prevEma;
|
|
18
|
+
// Compute subsequent EMA values
|
|
19
|
+
for (let i = period; i < bars.length; i++) {
|
|
20
|
+
const currentClose = bars[i].close;
|
|
21
|
+
const currentEma = alpha * currentClose + (1 - alpha) * prevEma;
|
|
22
|
+
result[i] = currentEma;
|
|
23
|
+
prevEma = currentEma;
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/heikin-ashi.ts
|
|
3
|
+
* Transforms standard OHLCV candlesticks into smoothed Heikin-Ashi candles.
|
|
4
|
+
*
|
|
5
|
+
* Formulas:
|
|
6
|
+
* - Close_HA = (Open + High + Low + Close) / 4
|
|
7
|
+
* - Open_HA[0] = (Open[0] + Close[0]) / 2
|
|
8
|
+
* - Open_HA[i] = (Open_HA[i-1] + Close_HA[i-1]) / 2
|
|
9
|
+
* - High_HA = max(High, Open_HA, Close_HA)
|
|
10
|
+
* - Low_HA = min(Low, Open_HA, Close_HA)
|
|
11
|
+
*/
|
|
12
|
+
import type { OHLCVBar } from '@tranding-custom-chart/core';
|
|
13
|
+
export declare function computeHeikinAshi(bars: readonly OHLCVBar[]): readonly OHLCVBar[];
|
|
14
|
+
//# sourceMappingURL=heikin-ashi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heikin-ashi.d.ts","sourceRoot":"","sources":["../../src/indicators/heikin-ashi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,GAAG,SAAS,QAAQ,EAAE,CA8BhF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/heikin-ashi.ts
|
|
3
|
+
* Transforms standard OHLCV candlesticks into smoothed Heikin-Ashi candles.
|
|
4
|
+
*
|
|
5
|
+
* Formulas:
|
|
6
|
+
* - Close_HA = (Open + High + Low + Close) / 4
|
|
7
|
+
* - Open_HA[0] = (Open[0] + Close[0]) / 2
|
|
8
|
+
* - Open_HA[i] = (Open_HA[i-1] + Close_HA[i-1]) / 2
|
|
9
|
+
* - High_HA = max(High, Open_HA, Close_HA)
|
|
10
|
+
* - Low_HA = min(Low, Open_HA, Close_HA)
|
|
11
|
+
*/
|
|
12
|
+
export function computeHeikinAshi(bars) {
|
|
13
|
+
if (bars.length === 0)
|
|
14
|
+
return [];
|
|
15
|
+
const result = [];
|
|
16
|
+
for (let i = 0; i < bars.length; i++) {
|
|
17
|
+
const bar = bars[i];
|
|
18
|
+
const haClose = (bar.open + bar.high + bar.low + bar.close) / 4;
|
|
19
|
+
const haOpen = i === 0
|
|
20
|
+
? (bar.open + bar.close) / 2
|
|
21
|
+
: (result[i - 1].open + result[i - 1].close) / 2;
|
|
22
|
+
const haHigh = Math.max(bar.high, haOpen, haClose);
|
|
23
|
+
const haLow = Math.min(bar.low, haOpen, haClose);
|
|
24
|
+
result.push({
|
|
25
|
+
time: bar.time,
|
|
26
|
+
open: haOpen,
|
|
27
|
+
high: haHigh,
|
|
28
|
+
low: haLow,
|
|
29
|
+
close: haClose,
|
|
30
|
+
volume: bar.volume,
|
|
31
|
+
dateStr: bar.dateStr,
|
|
32
|
+
qualityFlags: bar.qualityFlags,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/kagi.ts
|
|
3
|
+
* Algorithmic Kagi line generation from sequential OHLCV bars.
|
|
4
|
+
* Kagi charts filter time and noise, indicating trend reversals and Yang (bullish) / Yin (bearish) inflections.
|
|
5
|
+
*/
|
|
6
|
+
import type { OHLCVBar } from '@tranding-custom-chart/core';
|
|
7
|
+
export interface KagiSegment extends OHLCVBar {
|
|
8
|
+
readonly isYang: boolean;
|
|
9
|
+
readonly isUp: boolean;
|
|
10
|
+
readonly originalIndex: number;
|
|
11
|
+
}
|
|
12
|
+
export interface KagiOptions {
|
|
13
|
+
readonly reversalAmount?: number | undefined;
|
|
14
|
+
readonly reversalPercent?: number | undefined;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Computes Kagi trend segments from standard OHLCV bars.
|
|
18
|
+
*/
|
|
19
|
+
export declare function computeKagi(bars: readonly OHLCVBar[], options?: KagiOptions): readonly KagiSegment[];
|
|
20
|
+
//# sourceMappingURL=kagi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kagi.d.ts","sourceRoot":"","sources":["../../src/indicators/kagi.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D,MAAM,WAAW,WAAY,SAAQ,QAAQ;IAC3C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/C;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,OAAO,GAAE,WAAgB,GACxB,SAAS,WAAW,EAAE,CAsHxB"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/kagi.ts
|
|
3
|
+
* Algorithmic Kagi line generation from sequential OHLCV bars.
|
|
4
|
+
* Kagi charts filter time and noise, indicating trend reversals and Yang (bullish) / Yin (bearish) inflections.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Computes Kagi trend segments from standard OHLCV bars.
|
|
8
|
+
*/
|
|
9
|
+
export function computeKagi(bars, options = {}) {
|
|
10
|
+
if (bars.length === 0)
|
|
11
|
+
return [];
|
|
12
|
+
const firstClose = bars[0].close;
|
|
13
|
+
const reversalPct = options.reversalPercent ?? 0.01;
|
|
14
|
+
const reversalThreshold = options.reversalAmount && options.reversalAmount > 0
|
|
15
|
+
? options.reversalAmount
|
|
16
|
+
: Math.max(0.1, Number((firstClose * reversalPct).toFixed(2)));
|
|
17
|
+
const segments = [];
|
|
18
|
+
let currentStartPrice = firstClose;
|
|
19
|
+
let currentEndPrice = firstClose;
|
|
20
|
+
let currentDirection = null;
|
|
21
|
+
let isYang = true;
|
|
22
|
+
let lastShoulder = firstClose; // Previous peak
|
|
23
|
+
let lastWaist = firstClose; // Previous trough
|
|
24
|
+
for (let i = 1; i < bars.length; i++) {
|
|
25
|
+
const bar = bars[i];
|
|
26
|
+
const price = bar.close;
|
|
27
|
+
if (currentDirection === null) {
|
|
28
|
+
if (price >= currentStartPrice + reversalThreshold) {
|
|
29
|
+
currentDirection = 'up';
|
|
30
|
+
currentEndPrice = price;
|
|
31
|
+
lastShoulder = price;
|
|
32
|
+
}
|
|
33
|
+
else if (price <= currentStartPrice - reversalThreshold) {
|
|
34
|
+
currentDirection = 'down';
|
|
35
|
+
currentEndPrice = price;
|
|
36
|
+
lastWaist = price;
|
|
37
|
+
isYang = false;
|
|
38
|
+
}
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (currentDirection === 'up') {
|
|
42
|
+
if (price > currentEndPrice) {
|
|
43
|
+
// Continue upward trend
|
|
44
|
+
currentEndPrice = price;
|
|
45
|
+
if (!isYang && price > lastShoulder) {
|
|
46
|
+
isYang = true; // Breakout above shoulder turns Yang
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else if (price <= currentEndPrice - reversalThreshold) {
|
|
50
|
+
// Reversal downwards
|
|
51
|
+
segments.push({
|
|
52
|
+
time: bar.time,
|
|
53
|
+
open: currentStartPrice,
|
|
54
|
+
high: currentEndPrice,
|
|
55
|
+
low: currentStartPrice,
|
|
56
|
+
close: currentEndPrice,
|
|
57
|
+
volume: bar.volume ?? 0,
|
|
58
|
+
isYang,
|
|
59
|
+
isUp: true,
|
|
60
|
+
originalIndex: i - 1,
|
|
61
|
+
dateStr: bar.dateStr,
|
|
62
|
+
});
|
|
63
|
+
lastShoulder = currentEndPrice;
|
|
64
|
+
currentStartPrice = currentEndPrice;
|
|
65
|
+
currentEndPrice = price;
|
|
66
|
+
currentDirection = 'down';
|
|
67
|
+
if (isYang && price < lastWaist) {
|
|
68
|
+
isYang = false; // Breakdown below waist turns Yin
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// currentDirection === 'down'
|
|
74
|
+
if (price < currentEndPrice) {
|
|
75
|
+
// Continue downward trend
|
|
76
|
+
currentEndPrice = price;
|
|
77
|
+
if (isYang && price < lastWaist) {
|
|
78
|
+
isYang = false; // Breakdown below waist turns Yin
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else if (price >= currentEndPrice + reversalThreshold) {
|
|
82
|
+
// Reversal upwards
|
|
83
|
+
segments.push({
|
|
84
|
+
time: bar.time,
|
|
85
|
+
open: currentStartPrice,
|
|
86
|
+
high: currentStartPrice,
|
|
87
|
+
low: currentEndPrice,
|
|
88
|
+
close: currentEndPrice,
|
|
89
|
+
volume: bar.volume ?? 0,
|
|
90
|
+
isYang,
|
|
91
|
+
isUp: false,
|
|
92
|
+
originalIndex: i - 1,
|
|
93
|
+
dateStr: bar.dateStr,
|
|
94
|
+
});
|
|
95
|
+
lastWaist = currentEndPrice;
|
|
96
|
+
currentStartPrice = currentEndPrice;
|
|
97
|
+
currentEndPrice = price;
|
|
98
|
+
currentDirection = 'up';
|
|
99
|
+
if (!isYang && price > lastShoulder) {
|
|
100
|
+
isYang = true; // Breakout above shoulder turns Yang
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Push terminal active segment
|
|
106
|
+
if (currentDirection !== null) {
|
|
107
|
+
const lastBar = bars[bars.length - 1];
|
|
108
|
+
segments.push({
|
|
109
|
+
time: lastBar.time,
|
|
110
|
+
open: currentStartPrice,
|
|
111
|
+
high: Math.max(currentStartPrice, currentEndPrice),
|
|
112
|
+
low: Math.min(currentStartPrice, currentEndPrice),
|
|
113
|
+
close: currentEndPrice,
|
|
114
|
+
volume: lastBar.volume ?? 0,
|
|
115
|
+
isYang,
|
|
116
|
+
isUp: currentEndPrice >= currentStartPrice,
|
|
117
|
+
originalIndex: bars.length - 1,
|
|
118
|
+
dateStr: lastBar.dateStr,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return segments;
|
|
122
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/line-break.ts
|
|
3
|
+
* Algorithmic Three-Line Break (TLB) chart generation.
|
|
4
|
+
* Filters minor oscillations, adding new blocks only when price exceeds the extreme of the prior N lines.
|
|
5
|
+
*/
|
|
6
|
+
import type { OHLCVBar } from '@tranding-custom-chart/core';
|
|
7
|
+
export interface LineBreakBar extends OHLCVBar {
|
|
8
|
+
readonly isUp: boolean;
|
|
9
|
+
readonly originalIndex: number;
|
|
10
|
+
}
|
|
11
|
+
export interface LineBreakOptions {
|
|
12
|
+
readonly lineCount?: number | undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Computes Three-Line Break (TLB) bars from sequential OHLCV bars.
|
|
16
|
+
*/
|
|
17
|
+
export declare function computeLineBreak(bars: readonly OHLCVBar[], options?: LineBreakOptions): readonly LineBreakBar[];
|
|
18
|
+
//# sourceMappingURL=line-break.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"line-break.d.ts","sourceRoot":"","sources":["../../src/indicators/line-break.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC5C,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,OAAO,GAAE,gBAAqB,GAC7B,SAAS,YAAY,EAAE,CAoEzB"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/line-break.ts
|
|
3
|
+
* Algorithmic Three-Line Break (TLB) chart generation.
|
|
4
|
+
* Filters minor oscillations, adding new blocks only when price exceeds the extreme of the prior N lines.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Computes Three-Line Break (TLB) bars from sequential OHLCV bars.
|
|
8
|
+
*/
|
|
9
|
+
export function computeLineBreak(bars, options = {}) {
|
|
10
|
+
if (bars.length === 0)
|
|
11
|
+
return [];
|
|
12
|
+
const lineCount = Math.max(1, options.lineCount ?? 3);
|
|
13
|
+
const result = [];
|
|
14
|
+
// Seed with initial bar
|
|
15
|
+
const first = bars[0];
|
|
16
|
+
result.push({
|
|
17
|
+
time: first.time,
|
|
18
|
+
open: first.open,
|
|
19
|
+
high: Math.max(first.open, first.close),
|
|
20
|
+
low: Math.min(first.open, first.close),
|
|
21
|
+
close: first.close,
|
|
22
|
+
volume: first.volume ?? 0,
|
|
23
|
+
isUp: first.close >= first.open,
|
|
24
|
+
originalIndex: 0,
|
|
25
|
+
dateStr: first.dateStr,
|
|
26
|
+
});
|
|
27
|
+
for (let i = 1; i < bars.length; i++) {
|
|
28
|
+
const bar = bars[i];
|
|
29
|
+
const price = bar.close;
|
|
30
|
+
// Check extremes of recent N lines
|
|
31
|
+
const recent = result.slice(-lineCount);
|
|
32
|
+
let highestHigh = -Infinity;
|
|
33
|
+
let lowestLow = Infinity;
|
|
34
|
+
for (const line of recent) {
|
|
35
|
+
const top = Math.max(line.open, line.close);
|
|
36
|
+
const bottom = Math.min(line.open, line.close);
|
|
37
|
+
if (top > highestHigh)
|
|
38
|
+
highestHigh = top;
|
|
39
|
+
if (bottom < lowestLow)
|
|
40
|
+
lowestLow = bottom;
|
|
41
|
+
}
|
|
42
|
+
const lastLine = result[result.length - 1];
|
|
43
|
+
if (price > highestHigh) {
|
|
44
|
+
// New up line
|
|
45
|
+
result.push({
|
|
46
|
+
time: bar.time,
|
|
47
|
+
open: lastLine.isUp ? lastLine.close : lastLine.open,
|
|
48
|
+
high: price,
|
|
49
|
+
low: lastLine.isUp ? lastLine.close : lastLine.open,
|
|
50
|
+
close: price,
|
|
51
|
+
volume: bar.volume ?? 0,
|
|
52
|
+
isUp: true,
|
|
53
|
+
originalIndex: i,
|
|
54
|
+
dateStr: bar.dateStr,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
else if (price < lowestLow) {
|
|
58
|
+
// New down line
|
|
59
|
+
result.push({
|
|
60
|
+
time: bar.time,
|
|
61
|
+
open: !lastLine.isUp ? lastLine.close : lastLine.open,
|
|
62
|
+
high: !lastLine.isUp ? lastLine.close : lastLine.open,
|
|
63
|
+
low: price,
|
|
64
|
+
close: price,
|
|
65
|
+
volume: bar.volume ?? 0,
|
|
66
|
+
isUp: false,
|
|
67
|
+
originalIndex: i,
|
|
68
|
+
dateStr: bar.dateStr,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/macd.ts
|
|
3
|
+
* Moving Average Convergence Divergence (MACD) calculation.
|
|
4
|
+
* Outputs MACD Line, Signal Line, and Histogram oscillator.
|
|
5
|
+
*/
|
|
6
|
+
import type { OHLCVBar } from '@tranding-custom-chart/core';
|
|
7
|
+
export interface MACDResult {
|
|
8
|
+
readonly macd: readonly (number | null)[];
|
|
9
|
+
readonly signal: readonly (number | null)[];
|
|
10
|
+
readonly histogram: readonly (number | null)[];
|
|
11
|
+
}
|
|
12
|
+
export declare function computeMACD(bars: readonly OHLCVBar[], fastPeriod?: number, slowPeriod?: number, signalPeriod?: number): MACDResult;
|
|
13
|
+
//# sourceMappingURL=macd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"macd.d.ts","sourceRoot":"","sources":["../../src/indicators/macd.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAG5D,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAC1C,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAC5C,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;CAChD;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,UAAU,SAAK,EACf,UAAU,SAAK,EACf,YAAY,SAAI,GACf,UAAU,CA4DZ"}
|