@tranding-custom-chart/financial 0.0.0-stage → 2.1.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 +351 -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 +74 -4
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/supertrend.ts
|
|
3
|
+
* Algorithmic Supertrend calculation engine.
|
|
4
|
+
* Computes ATR-based dynamic trailing stop bands and trend direction (1 = Bullish, -1 = Bearish).
|
|
5
|
+
*/
|
|
6
|
+
import { computeATR } from './atr.js';
|
|
7
|
+
export function computeSupertrend(bars, options = {}) {
|
|
8
|
+
const { period = 10, multiplier = 3.0 } = options;
|
|
9
|
+
if (bars.length === 0) {
|
|
10
|
+
return { points: [], period, multiplier };
|
|
11
|
+
}
|
|
12
|
+
const atrPoints = computeATR(bars, period);
|
|
13
|
+
const points = [];
|
|
14
|
+
let prevFinalUpper = 0;
|
|
15
|
+
let prevFinalLower = 0;
|
|
16
|
+
let prevDirection = 1;
|
|
17
|
+
for (let i = 0; i < bars.length; i++) {
|
|
18
|
+
const bar = bars[i];
|
|
19
|
+
const atr = atrPoints[i]?.atr ?? 0;
|
|
20
|
+
const hl2 = (bar.high + bar.low) / 2;
|
|
21
|
+
const basicUpper = hl2 + multiplier * atr;
|
|
22
|
+
const basicLower = hl2 - multiplier * atr;
|
|
23
|
+
let finalUpper = basicUpper;
|
|
24
|
+
let finalLower = basicLower;
|
|
25
|
+
if (i > 0) {
|
|
26
|
+
const prevBar = bars[i - 1];
|
|
27
|
+
// Final Upper Band
|
|
28
|
+
if (basicUpper < prevFinalUpper || prevBar.close > prevFinalUpper) {
|
|
29
|
+
finalUpper = basicUpper;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
finalUpper = prevFinalUpper;
|
|
33
|
+
}
|
|
34
|
+
// Final Lower Band
|
|
35
|
+
if (basicLower > prevFinalLower || prevBar.close < prevFinalLower) {
|
|
36
|
+
finalLower = basicLower;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
finalLower = prevFinalLower;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
prevFinalUpper = basicUpper;
|
|
44
|
+
prevFinalLower = basicLower;
|
|
45
|
+
}
|
|
46
|
+
// Determine Direction
|
|
47
|
+
let direction = prevDirection;
|
|
48
|
+
if (i === 0) {
|
|
49
|
+
direction = bar.close >= hl2 ? 1 : -1;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
if (prevDirection === 1) {
|
|
53
|
+
if (bar.close < finalLower) {
|
|
54
|
+
direction = -1;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
direction = 1;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
if (bar.close > finalUpper) {
|
|
62
|
+
direction = 1;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
direction = -1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const isReversal = i > 0 && direction !== prevDirection;
|
|
70
|
+
const supertrendVal = direction === 1 ? finalLower : finalUpper;
|
|
71
|
+
points.push({
|
|
72
|
+
time: bar.time,
|
|
73
|
+
supertrend: supertrendVal,
|
|
74
|
+
direction,
|
|
75
|
+
upperBand: finalUpper,
|
|
76
|
+
lowerBand: finalLower,
|
|
77
|
+
isReversal,
|
|
78
|
+
});
|
|
79
|
+
prevFinalUpper = finalUpper;
|
|
80
|
+
prevFinalLower = finalLower;
|
|
81
|
+
prevDirection = direction;
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
points,
|
|
85
|
+
period,
|
|
86
|
+
multiplier,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/volume-profile.ts
|
|
3
|
+
* Algorithmic Visible Range Volume Profile (VRVP) calculation.
|
|
4
|
+
* Distributes traded volume into discrete price bins, identifying Point of Control (POC)
|
|
5
|
+
* and the 70% Value Area (VAH and VAL).
|
|
6
|
+
*/
|
|
7
|
+
import type { OHLCVBar, VolumeProfileBin, VolumeProfileResult, VolumeProfileOptions } from '@tranding-custom-chart/core';
|
|
8
|
+
export type { VolumeProfileBin, VolumeProfileResult, VolumeProfileOptions };
|
|
9
|
+
export declare function computeVolumeProfile(bars: readonly OHLCVBar[], options?: VolumeProfileOptions): VolumeProfileResult;
|
|
10
|
+
//# sourceMappingURL=volume-profile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"volume-profile.d.ts","sourceRoot":"","sources":["../../src/indicators/volume-profile.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,QAAQ,EACR,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,6BAA6B,CAAC;AAErC,YAAY,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,CAAC;AAE5E,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,SAAS,QAAQ,EAAE,EACzB,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CAmJrB"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/volume-profile.ts
|
|
3
|
+
* Algorithmic Visible Range Volume Profile (VRVP) calculation.
|
|
4
|
+
* Distributes traded volume into discrete price bins, identifying Point of Control (POC)
|
|
5
|
+
* and the 70% Value Area (VAH and VAL).
|
|
6
|
+
*/
|
|
7
|
+
export function computeVolumeProfile(bars, options = {}) {
|
|
8
|
+
if (bars.length === 0) {
|
|
9
|
+
return {
|
|
10
|
+
bins: [],
|
|
11
|
+
pocPrice: 0,
|
|
12
|
+
pocVolume: 0,
|
|
13
|
+
vahPrice: 0,
|
|
14
|
+
valPrice: 0,
|
|
15
|
+
totalVolume: 0,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const { binCount = 24, valueAreaRatio = 0.7 } = options;
|
|
19
|
+
let minPrice = Infinity;
|
|
20
|
+
let maxPrice = -Infinity;
|
|
21
|
+
let overallVolume = 0;
|
|
22
|
+
for (const b of bars) {
|
|
23
|
+
if (b.low < minPrice)
|
|
24
|
+
minPrice = b.low;
|
|
25
|
+
if (b.high > maxPrice)
|
|
26
|
+
maxPrice = b.high;
|
|
27
|
+
overallVolume += b.volume ?? 0;
|
|
28
|
+
}
|
|
29
|
+
if (maxPrice <= minPrice || overallVolume === 0) {
|
|
30
|
+
return {
|
|
31
|
+
bins: [],
|
|
32
|
+
pocPrice: minPrice,
|
|
33
|
+
pocVolume: 0,
|
|
34
|
+
vahPrice: maxPrice,
|
|
35
|
+
valPrice: minPrice,
|
|
36
|
+
totalVolume: overallVolume,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const priceSpan = maxPrice - minPrice;
|
|
40
|
+
const binStep = priceSpan / binCount;
|
|
41
|
+
// Initialize bins
|
|
42
|
+
const rawBins = [];
|
|
43
|
+
for (let k = 0; k < binCount; k++) {
|
|
44
|
+
const low = minPrice + k * binStep;
|
|
45
|
+
const high = low + binStep;
|
|
46
|
+
rawBins.push({
|
|
47
|
+
priceLow: low,
|
|
48
|
+
priceHigh: high,
|
|
49
|
+
priceMid: (low + high) / 2,
|
|
50
|
+
buyVolume: 0,
|
|
51
|
+
sellVolume: 0,
|
|
52
|
+
totalVolume: 0,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
// Allocate bar volume across bins
|
|
56
|
+
for (const b of bars) {
|
|
57
|
+
const vol = b.volume ?? 0;
|
|
58
|
+
if (vol <= 0)
|
|
59
|
+
continue;
|
|
60
|
+
const isUp = b.close >= b.open;
|
|
61
|
+
const barLow = b.low;
|
|
62
|
+
const barHigh = b.high;
|
|
63
|
+
// Find overlapping bins
|
|
64
|
+
const startBin = Math.max(0, Math.min(binCount - 1, Math.floor((barLow - minPrice) / binStep)));
|
|
65
|
+
const endBin = Math.max(0, Math.min(binCount - 1, Math.floor((barHigh - minPrice) / binStep)));
|
|
66
|
+
const binsTouched = endBin - startBin + 1;
|
|
67
|
+
const volPerBin = vol / binsTouched;
|
|
68
|
+
for (let idx = startBin; idx <= endBin; idx++) {
|
|
69
|
+
const target = rawBins[idx];
|
|
70
|
+
if (isUp) {
|
|
71
|
+
target.buyVolume += volPerBin;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
target.sellVolume += volPerBin;
|
|
75
|
+
}
|
|
76
|
+
target.totalVolume += volPerBin;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Find Point of Control (POC)
|
|
80
|
+
let pocIdx = 0;
|
|
81
|
+
let maxBinVol = -1;
|
|
82
|
+
for (let k = 0; k < binCount; k++) {
|
|
83
|
+
if (rawBins[k].totalVolume > maxBinVol) {
|
|
84
|
+
maxBinVol = rawBins[k].totalVolume;
|
|
85
|
+
pocIdx = k;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const pocPrice = rawBins[pocIdx].priceMid;
|
|
89
|
+
const pocVolume = rawBins[pocIdx].totalVolume;
|
|
90
|
+
// Determine Value Area (70% total volume radiating outward from POC)
|
|
91
|
+
const targetVAVolume = overallVolume * valueAreaRatio;
|
|
92
|
+
let currentVAVolume = pocVolume;
|
|
93
|
+
let upIdx = pocIdx;
|
|
94
|
+
let downIdx = pocIdx;
|
|
95
|
+
while (currentVAVolume < targetVAVolume && (upIdx < binCount - 1 || downIdx > 0)) {
|
|
96
|
+
const nextUpVol = upIdx < binCount - 1 ? rawBins[upIdx + 1].totalVolume : -1;
|
|
97
|
+
const nextDownVol = downIdx > 0 ? rawBins[downIdx - 1].totalVolume : -1;
|
|
98
|
+
if (nextUpVol >= nextDownVol && upIdx < binCount - 1) {
|
|
99
|
+
upIdx++;
|
|
100
|
+
currentVAVolume += nextUpVol;
|
|
101
|
+
}
|
|
102
|
+
else if (downIdx > 0) {
|
|
103
|
+
downIdx--;
|
|
104
|
+
currentVAVolume += nextDownVol;
|
|
105
|
+
}
|
|
106
|
+
else if (upIdx < binCount - 1) {
|
|
107
|
+
upIdx++;
|
|
108
|
+
currentVAVolume += nextUpVol;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const valPrice = rawBins[downIdx].priceLow;
|
|
115
|
+
const vahPrice = rawBins[upIdx].priceHigh;
|
|
116
|
+
const resultBins = rawBins.map((rb, idx) => ({
|
|
117
|
+
priceLow: Number(rb.priceLow.toFixed(2)),
|
|
118
|
+
priceHigh: Number(rb.priceHigh.toFixed(2)),
|
|
119
|
+
priceMid: Number(rb.priceMid.toFixed(2)),
|
|
120
|
+
buyVolume: Math.round(rb.buyVolume),
|
|
121
|
+
sellVolume: Math.round(rb.sellVolume),
|
|
122
|
+
totalVolume: Math.round(rb.totalVolume),
|
|
123
|
+
isValueArea: idx >= downIdx && idx <= upIdx,
|
|
124
|
+
isPOC: idx === pocIdx,
|
|
125
|
+
}));
|
|
126
|
+
return {
|
|
127
|
+
bins: resultBins,
|
|
128
|
+
pocPrice: Number(pocPrice.toFixed(2)),
|
|
129
|
+
pocVolume: Math.round(pocVolume),
|
|
130
|
+
vahPrice: Number(vahPrice.toFixed(2)),
|
|
131
|
+
valPrice: Number(valPrice.toFixed(2)),
|
|
132
|
+
totalVolume: Math.round(overallVolume),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/vwap.ts
|
|
3
|
+
* Volume Weighted Average Price (VWAP) calculation with daily intraday session resets.
|
|
4
|
+
*/
|
|
5
|
+
import type { OHLCVBar } from '@tranding-custom-chart/core';
|
|
6
|
+
export declare function computeVWAP(bars: readonly OHLCVBar[]): readonly (number | null)[];
|
|
7
|
+
//# sourceMappingURL=vwap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vwap.d.ts","sourceRoot":"","sources":["../../src/indicators/vwap.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,GAAG,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAgCjF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/vwap.ts
|
|
3
|
+
* Volume Weighted Average Price (VWAP) calculation with daily intraday session resets.
|
|
4
|
+
*/
|
|
5
|
+
export function computeVWAP(bars) {
|
|
6
|
+
if (bars.length === 0)
|
|
7
|
+
return [];
|
|
8
|
+
const result = [];
|
|
9
|
+
let cumVolume = 0;
|
|
10
|
+
let cumTypicalPriceVolume = 0;
|
|
11
|
+
let lastSessionKey = '';
|
|
12
|
+
for (let i = 0; i < bars.length; i++) {
|
|
13
|
+
const bar = bars[i];
|
|
14
|
+
const vol = bar.volume ?? 0;
|
|
15
|
+
// Detect session reset by calendar day
|
|
16
|
+
const sessionKey = new Date(bar.time * 1000).toDateString();
|
|
17
|
+
if (sessionKey !== lastSessionKey) {
|
|
18
|
+
cumVolume = 0;
|
|
19
|
+
cumTypicalPriceVolume = 0;
|
|
20
|
+
lastSessionKey = sessionKey;
|
|
21
|
+
}
|
|
22
|
+
const typicalPrice = (bar.high + bar.low + bar.close) / 3;
|
|
23
|
+
cumVolume += vol;
|
|
24
|
+
cumTypicalPriceVolume += typicalPrice * vol;
|
|
25
|
+
if (cumVolume > 0) {
|
|
26
|
+
result.push(cumTypicalPriceVolume / cumVolume);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
result.push(typicalPrice);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/wma.ts
|
|
3
|
+
* Weighted Moving Average (WMA) computation with linear weights.
|
|
4
|
+
*/
|
|
5
|
+
import type { OHLCVBar } from '@tranding-custom-chart/core';
|
|
6
|
+
export declare function computeWMA(bars: readonly OHLCVBar[], period: number): readonly (number | null)[];
|
|
7
|
+
//# sourceMappingURL=wma.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wma.d.ts","sourceRoot":"","sources":["../../src/indicators/wma.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,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAmB5B"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/indicators/wma.ts
|
|
3
|
+
* Weighted Moving Average (WMA) computation with linear weights.
|
|
4
|
+
*/
|
|
5
|
+
export function computeWMA(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 weightDenominator = (period * (period + 1)) / 2;
|
|
11
|
+
for (let i = period - 1; i < bars.length; i++) {
|
|
12
|
+
let weightedSum = 0;
|
|
13
|
+
for (let k = 0; k < period; k++) {
|
|
14
|
+
const weight = period - k;
|
|
15
|
+
const barIndex = i - k;
|
|
16
|
+
weightedSum += bars[barIndex].close * weight;
|
|
17
|
+
}
|
|
18
|
+
result[i] = weightedSum / weightDenominator;
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/layout/pane-layout.ts
|
|
3
|
+
* Multi-pane vertical split layout manager (Price, Volume, Indicators).
|
|
4
|
+
*/
|
|
5
|
+
import type { Dimension, Padding } from '@tranding-custom-chart/core';
|
|
6
|
+
export interface PaneDefinition {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly heightRatio: number;
|
|
9
|
+
readonly minHeight?: number | undefined;
|
|
10
|
+
}
|
|
11
|
+
export interface ComputedPaneLayout {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly top: number;
|
|
14
|
+
readonly bottom: number;
|
|
15
|
+
readonly height: number;
|
|
16
|
+
readonly padding: Padding;
|
|
17
|
+
}
|
|
18
|
+
export declare function computePaneLayouts(totalBounds: Dimension, padding: Padding, panes: readonly PaneDefinition[], paneGap?: number): readonly ComputedPaneLayout[];
|
|
19
|
+
//# sourceMappingURL=pane-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pane-layout.d.ts","sourceRoot":"","sources":["../../src/layout/pane-layout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAEtE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,SAAS,EACtB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,SAAS,cAAc,EAAE,EAChC,OAAO,SAAI,GACV,SAAS,kBAAkB,EAAE,CA0C/B"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-financial/src/layout/pane-layout.ts
|
|
3
|
+
* Multi-pane vertical split layout manager (Price, Volume, Indicators).
|
|
4
|
+
*/
|
|
5
|
+
export function computePaneLayouts(totalBounds, padding, panes, paneGap = 8) {
|
|
6
|
+
if (panes.length === 0)
|
|
7
|
+
return [];
|
|
8
|
+
const availableHeight = totalBounds.height - padding.top - padding.bottom;
|
|
9
|
+
const totalGaps = (panes.length - 1) * paneGap;
|
|
10
|
+
const netHeight = Math.max(10, availableHeight - totalGaps);
|
|
11
|
+
const totalRatio = panes.reduce((sum, p) => sum + p.heightRatio, 0) || 1;
|
|
12
|
+
const computed = [];
|
|
13
|
+
let currentY = padding.top;
|
|
14
|
+
for (let i = 0; i < panes.length; i++) {
|
|
15
|
+
const pane = panes[i];
|
|
16
|
+
const isLast = i === panes.length - 1;
|
|
17
|
+
const isFirst = i === 0;
|
|
18
|
+
let paneHeight = Math.round((pane.heightRatio / totalRatio) * netHeight);
|
|
19
|
+
if (pane.minHeight && paneHeight < pane.minHeight) {
|
|
20
|
+
paneHeight = pane.minHeight;
|
|
21
|
+
}
|
|
22
|
+
const paneTop = currentY;
|
|
23
|
+
const paneBottom = paneTop + paneHeight;
|
|
24
|
+
computed.push({
|
|
25
|
+
id: pane.id,
|
|
26
|
+
top: paneTop,
|
|
27
|
+
bottom: paneBottom,
|
|
28
|
+
height: paneHeight,
|
|
29
|
+
padding: {
|
|
30
|
+
top: isFirst ? padding.top : 2,
|
|
31
|
+
bottom: isLast ? padding.bottom : 2,
|
|
32
|
+
left: padding.left,
|
|
33
|
+
right: padding.right,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
currentY = paneBottom + paneGap;
|
|
37
|
+
}
|
|
38
|
+
return computed;
|
|
39
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,76 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tranding-custom-chart/financial",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "Production-grade financial technical indicators and chart algorithms — SMA, EMA, WMA, RSI, MACD, Bollinger Bands, ATR, VWAP, Supertrend, Volume Profile (VRVP), Renko, Heikin-Ashi, Kagi, Line Break, and multi-pane layout engine.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "The Creator Studio <thecreatorstudio97@gmail.com>",
|
|
8
|
+
"homepage": "https://www.npmjs.com/package/@tranding-custom-chart/financial",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"financial",
|
|
11
|
+
"finance",
|
|
12
|
+
"trading",
|
|
13
|
+
"stock",
|
|
14
|
+
"crypto",
|
|
15
|
+
"forex",
|
|
16
|
+
"fx",
|
|
17
|
+
"fintech",
|
|
18
|
+
"technical-analysis",
|
|
19
|
+
"indicators",
|
|
20
|
+
"technical-indicators",
|
|
21
|
+
"sma",
|
|
22
|
+
"ema",
|
|
23
|
+
"rsi",
|
|
24
|
+
"macd",
|
|
25
|
+
"bollinger-bands",
|
|
26
|
+
"atr",
|
|
27
|
+
"vwap",
|
|
28
|
+
"supertrend",
|
|
29
|
+
"volume-profile",
|
|
30
|
+
"vrvp",
|
|
31
|
+
"renko",
|
|
32
|
+
"heikin-ashi",
|
|
33
|
+
"kagi",
|
|
34
|
+
"line-break",
|
|
35
|
+
"candlestick",
|
|
36
|
+
"ohlc",
|
|
37
|
+
"ohlcv",
|
|
38
|
+
"moving-average",
|
|
39
|
+
"momentum",
|
|
40
|
+
"oscillator",
|
|
41
|
+
"chart",
|
|
42
|
+
"charts",
|
|
43
|
+
"visualization",
|
|
44
|
+
"typescript",
|
|
45
|
+
"zero-dependency",
|
|
46
|
+
"framework-agnostic"
|
|
47
|
+
],
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "git+https://github.com/thecreatorstudio97/trend-chart.git",
|
|
51
|
+
"directory": "packages/chart-financial"
|
|
52
|
+
},
|
|
53
|
+
"main": "./dist/index.js",
|
|
54
|
+
"types": "./dist/index.d.ts",
|
|
55
|
+
"exports": {
|
|
56
|
+
".": {
|
|
57
|
+
"types": "./dist/index.d.ts",
|
|
58
|
+
"import": "./dist/index.js"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"@tranding-custom-chart/core": "^2.1.0"
|
|
63
|
+
},
|
|
64
|
+
"files": [
|
|
65
|
+
"dist",
|
|
66
|
+
"README.md"
|
|
67
|
+
],
|
|
68
|
+
"publishConfig": {
|
|
69
|
+
"access": "public"
|
|
70
|
+
},
|
|
71
|
+
"scripts": {
|
|
72
|
+
"build": "tsc -p tsconfig.build.json",
|
|
73
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
74
|
+
"test": "vitest run --config vitest.config.ts"
|
|
75
|
+
}
|
|
76
|
+
}
|