@chartspire/chartspire-chart 10.0.0-alpha2 → 10.0.0-alpha3
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.d.ts +6 -0
- package/dist/index.esm.js +165 -9
- package/dist/umd/klinecharts.js +165 -9
- package/dist/umd/klinecharts.js.map +1 -1
- package/dist/umd/klinecharts.min.js +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -201,6 +201,11 @@ export interface CandleTooltipStyle extends TooltipStyle, Offset {
|
|
|
201
201
|
custom: CandleTooltipCustomCallback | TooltipLegend[];
|
|
202
202
|
rect: CandleTooltipRectStyle;
|
|
203
203
|
}
|
|
204
|
+
export interface RenkoStyle {
|
|
205
|
+
brick: {
|
|
206
|
+
size: number;
|
|
207
|
+
};
|
|
208
|
+
}
|
|
204
209
|
export declare enum CandleType {
|
|
205
210
|
HeikinAshi = "heikin_ashi",
|
|
206
211
|
CandleSolid = "candle_solid",
|
|
@@ -224,6 +229,7 @@ export interface CandleStyle {
|
|
|
224
229
|
area: CandleAreaStyle;
|
|
225
230
|
priceMark: CandlePriceMarkStyle;
|
|
226
231
|
tooltip: CandleTooltipStyle;
|
|
232
|
+
renko?: RenkoStyle;
|
|
227
233
|
}
|
|
228
234
|
export type IndicatorPolygonStyle = Omit<PolygonStyle, "color" | "borderColor"> & ChangeColor;
|
|
229
235
|
export interface IndicatorLastValueMarkStyle {
|
package/dist/index.esm.js
CHANGED
|
@@ -351,6 +351,11 @@ function getDefaultCandleStyle() {
|
|
|
351
351
|
marginBottom: 4
|
|
352
352
|
},
|
|
353
353
|
icons: []
|
|
354
|
+
},
|
|
355
|
+
renko: {
|
|
356
|
+
brick: {
|
|
357
|
+
size: 10
|
|
358
|
+
}
|
|
354
359
|
}
|
|
355
360
|
};
|
|
356
361
|
}
|
|
@@ -7501,10 +7506,14 @@ var ChildrenView = /** @class */ (function (_super) {
|
|
|
7501
7506
|
* See the License for the specific language governing permissions and
|
|
7502
7507
|
* limitations under the License.
|
|
7503
7508
|
*/
|
|
7509
|
+
// Small epsilon value to handle floating point comparison
|
|
7510
|
+
var EPSILON = 0.000001;
|
|
7504
7511
|
var CandleBarView = /** @class */ (function (_super) {
|
|
7505
7512
|
__extends(CandleBarView, _super);
|
|
7506
7513
|
function CandleBarView() {
|
|
7507
7514
|
var _this = _super.apply(this, __spreadArray([], __read(arguments), false)) || this;
|
|
7515
|
+
// Cache for Heikin-Ashi calculations
|
|
7516
|
+
_this._heikinAshiCache = new Map();
|
|
7508
7517
|
_this._boundCandleBarClickEvent = function (data) { return function () {
|
|
7509
7518
|
_this.getWidget().getPane().getChart().getChartStore().executeAction(ActionType.OnCandleBarClick, data);
|
|
7510
7519
|
return false;
|
|
@@ -7528,6 +7537,10 @@ var CandleBarView = /** @class */ (function (_super) {
|
|
|
7528
7537
|
}
|
|
7529
7538
|
halfOhlcSize_1 = Math.floor(halfOhlcSize_1 / 2);
|
|
7530
7539
|
}
|
|
7540
|
+
// Clear Heikin-Ashi cache when changing to a different chart type
|
|
7541
|
+
if (candleBarOptions.type !== CandleType.HeikinAshi) {
|
|
7542
|
+
this._heikinAshiCache.clear();
|
|
7543
|
+
}
|
|
7531
7544
|
var yAxis_1 = pane.getAxisComponent();
|
|
7532
7545
|
this.eachChildren(function (data, barSpace) {
|
|
7533
7546
|
var kLineData = data.data, x = data.x;
|
|
@@ -7618,6 +7631,8 @@ var CandleBarView = /** @class */ (function (_super) {
|
|
|
7618
7631
|
}
|
|
7619
7632
|
case CandleType.HeikinAshi: {
|
|
7620
7633
|
var heikinAshiData = _this._calculateHeikinAshi(data);
|
|
7634
|
+
// Determine colors based on Heikin-Ashi data and original candle
|
|
7635
|
+
colors = _this._getHeikinAshiColors(heikinAshiData.haValues.open, heikinAshiData.haValues.close, open_1, close_1, styles);
|
|
7621
7636
|
rects = _this._createSolidBar(x, heikinAshiData.priceY, barSpace, colors, correction);
|
|
7622
7637
|
break;
|
|
7623
7638
|
}
|
|
@@ -7710,9 +7725,9 @@ var CandleBarView = /** @class */ (function (_super) {
|
|
|
7710
7725
|
* Calculate Heikin Ashi candle data
|
|
7711
7726
|
* Calculation method is based on the following formula:
|
|
7712
7727
|
* - Close = (Open + High + Low + Close) / 4
|
|
7713
|
-
* - Open = (Previous Open + Previous Close) / 2
|
|
7714
|
-
* - High = Max(High, Open, Close)
|
|
7715
|
-
* - Low = Min(Low, Open, Close)
|
|
7728
|
+
* - Open = (Previous HA Open + Previous HA Close) / 2
|
|
7729
|
+
* - High = Max(High, HA Open, HA Close)
|
|
7730
|
+
* - Low = Min(Low, HA Open, HA Close)
|
|
7716
7731
|
*
|
|
7717
7732
|
* To read more please read - https://www.investopedia.com/trading/heikin-ashi-better-candlestick/
|
|
7718
7733
|
*
|
|
@@ -7722,13 +7737,58 @@ var CandleBarView = /** @class */ (function (_super) {
|
|
|
7722
7737
|
CandleBarView.prototype._calculateHeikinAshi = function (data) {
|
|
7723
7738
|
var kLineData = data.data, dataIndex = data.dataIndex;
|
|
7724
7739
|
var _a = kLineData, open = _a.open, high = _a.high, low = _a.low, close = _a.close;
|
|
7725
|
-
|
|
7726
|
-
var
|
|
7727
|
-
|
|
7740
|
+
// Check if this candle's HA values are already calculated
|
|
7741
|
+
var cachedHeikinAshi = this._heikinAshiCache.get(dataIndex);
|
|
7742
|
+
if (cachedHeikinAshi !== undefined) {
|
|
7743
|
+
var yAxis_2 = this.getWidget().getPane().getAxisComponent();
|
|
7744
|
+
var priceY_1 = [
|
|
7745
|
+
yAxis_2.convertToPixel(cachedHeikinAshi.open),
|
|
7746
|
+
yAxis_2.convertToPixel(cachedHeikinAshi.close),
|
|
7747
|
+
yAxis_2.convertToPixel(cachedHeikinAshi.high),
|
|
7748
|
+
yAxis_2.convertToPixel(cachedHeikinAshi.low)
|
|
7749
|
+
];
|
|
7750
|
+
priceY_1.sort(function (a, b) { return a - b; });
|
|
7751
|
+
return { priceY: priceY_1, haValues: cachedHeikinAshi };
|
|
7752
|
+
}
|
|
7753
|
+
// Calculate Heikin-Ashi values
|
|
7754
|
+
// First, calculate the close which is always the same formula
|
|
7728
7755
|
var haClose = (open + high + low + close) / 4;
|
|
7729
|
-
var haOpen =
|
|
7756
|
+
var haOpen = 0;
|
|
7757
|
+
// Get the previous HA data if available, otherwise use regular OHLC
|
|
7758
|
+
if (dataIndex > 0) {
|
|
7759
|
+
var previousHA = this._getHeikinAshiValues(dataIndex - 1);
|
|
7760
|
+
if (previousHA !== null) {
|
|
7761
|
+
// Use previous HA values to calculate current HA open
|
|
7762
|
+
haOpen = (previousHA.open + previousHA.close) / 2;
|
|
7763
|
+
}
|
|
7764
|
+
else {
|
|
7765
|
+
// Fallback if previous HA values aren't available
|
|
7766
|
+
var previousData = this.getPreviousData(dataIndex);
|
|
7767
|
+
if (previousData !== null) {
|
|
7768
|
+
haOpen = (previousData.open + previousData.close) / 2;
|
|
7769
|
+
}
|
|
7770
|
+
else {
|
|
7771
|
+
haOpen = open; // First candle
|
|
7772
|
+
}
|
|
7773
|
+
}
|
|
7774
|
+
}
|
|
7775
|
+
else {
|
|
7776
|
+
// First candle in the series
|
|
7777
|
+
haOpen = (open + close) / 2;
|
|
7778
|
+
}
|
|
7779
|
+
// Calculate high and low based on HA values
|
|
7730
7780
|
var haHigh = Math.max(high, haOpen, haClose);
|
|
7731
7781
|
var haLow = Math.min(low, haOpen, haClose);
|
|
7782
|
+
// Create HA data object
|
|
7783
|
+
var haValues = {
|
|
7784
|
+
open: haOpen,
|
|
7785
|
+
high: haHigh,
|
|
7786
|
+
low: haLow,
|
|
7787
|
+
close: haClose
|
|
7788
|
+
};
|
|
7789
|
+
// Cache the calculated values
|
|
7790
|
+
this._heikinAshiCache.set(dataIndex, haValues);
|
|
7791
|
+
// Convert to pixel coordinates for display
|
|
7732
7792
|
var yAxis = this.getWidget().getPane().getAxisComponent();
|
|
7733
7793
|
var priceY = [
|
|
7734
7794
|
yAxis.convertToPixel(haOpen),
|
|
@@ -7737,7 +7797,52 @@ var CandleBarView = /** @class */ (function (_super) {
|
|
|
7737
7797
|
yAxis.convertToPixel(haLow)
|
|
7738
7798
|
];
|
|
7739
7799
|
priceY.sort(function (a, b) { return a - b; });
|
|
7740
|
-
return { priceY: priceY };
|
|
7800
|
+
return { priceY: priceY, haValues: haValues };
|
|
7801
|
+
};
|
|
7802
|
+
/**
|
|
7803
|
+
* Get Heikin-Ashi values for a specific candle, calculating them if necessary
|
|
7804
|
+
* @param dataIndex - The index of the data point in the data list
|
|
7805
|
+
* @private
|
|
7806
|
+
*/
|
|
7807
|
+
CandleBarView.prototype._getHeikinAshiValues = function (dataIndex) {
|
|
7808
|
+
// Check if already calculated
|
|
7809
|
+
var cachedValues = this._heikinAshiCache.get(dataIndex);
|
|
7810
|
+
if (cachedValues !== undefined) {
|
|
7811
|
+
return cachedValues;
|
|
7812
|
+
}
|
|
7813
|
+
// Not calculated yet, need to calculate
|
|
7814
|
+
var dataList = this.getWidget().getPane().getChart().getChartStore().getDataList();
|
|
7815
|
+
if (dataIndex < 0 || dataIndex >= dataList.length) {
|
|
7816
|
+
return null;
|
|
7817
|
+
}
|
|
7818
|
+
var kLineData = dataList[dataIndex];
|
|
7819
|
+
// Get the previous candle's HA values, recursively calculate if necessary
|
|
7820
|
+
var previousHA = null;
|
|
7821
|
+
if (dataIndex > 0) {
|
|
7822
|
+
previousHA = this._getHeikinAshiValues(dataIndex - 1);
|
|
7823
|
+
}
|
|
7824
|
+
var open = kLineData.open, high = kLineData.high, low = kLineData.low, close = kLineData.close;
|
|
7825
|
+
// Calculate HA values
|
|
7826
|
+
var haClose = (open + high + low + close) / 4;
|
|
7827
|
+
var haOpen = 0;
|
|
7828
|
+
if (previousHA !== null) {
|
|
7829
|
+
haOpen = (previousHA.open + previousHA.close) / 2;
|
|
7830
|
+
}
|
|
7831
|
+
else {
|
|
7832
|
+
// For the first candle
|
|
7833
|
+
haOpen = (open + close) / 2;
|
|
7834
|
+
}
|
|
7835
|
+
var haHigh = Math.max(high, haOpen, haClose);
|
|
7836
|
+
var haLow = Math.min(low, haOpen, haClose);
|
|
7837
|
+
var haValues = {
|
|
7838
|
+
open: haOpen,
|
|
7839
|
+
high: haHigh,
|
|
7840
|
+
low: haLow,
|
|
7841
|
+
close: haClose
|
|
7842
|
+
};
|
|
7843
|
+
// Cache the values
|
|
7844
|
+
this._heikinAshiCache.set(dataIndex, haValues);
|
|
7845
|
+
return haValues;
|
|
7741
7846
|
};
|
|
7742
7847
|
/**
|
|
7743
7848
|
* Retrieves the previous KLineData from the data list based on the given index.
|
|
@@ -7757,6 +7862,57 @@ var CandleBarView = /** @class */ (function (_super) {
|
|
|
7757
7862
|
}
|
|
7758
7863
|
return null;
|
|
7759
7864
|
};
|
|
7865
|
+
/**
|
|
7866
|
+
* Determine appropriate colors for Heikin-Ashi candles based on their open and close values
|
|
7867
|
+
* @param haOpen - Heikin-Ashi open price
|
|
7868
|
+
* @param haClose - Heikin-Ashi close price
|
|
7869
|
+
* @param originalOpen - Original candle open price
|
|
7870
|
+
* @param originalClose - Original candle close price
|
|
7871
|
+
* @param styles - Candle bar color styles
|
|
7872
|
+
* @returns Array of colors [bodyColor, borderColor, wickColor]
|
|
7873
|
+
* @private
|
|
7874
|
+
*/
|
|
7875
|
+
CandleBarView.prototype._getHeikinAshiColors = function (haOpen, haClose, originalOpen, originalClose, styles) {
|
|
7876
|
+
var colors = [];
|
|
7877
|
+
// Fixed comparison logic with epsilon to avoid floating point precision issues
|
|
7878
|
+
var diff = haClose - haOpen;
|
|
7879
|
+
// Determine candle color based on the relationship between HA open and close
|
|
7880
|
+
if (diff > EPSILON) {
|
|
7881
|
+
// Clearly higher close - green candle
|
|
7882
|
+
colors[0] = styles.upColor;
|
|
7883
|
+
colors[1] = styles.upBorderColor;
|
|
7884
|
+
colors[2] = styles.upWickColor;
|
|
7885
|
+
}
|
|
7886
|
+
else if (diff < -1e-6) {
|
|
7887
|
+
// Clearly lower close - red candle
|
|
7888
|
+
colors[0] = styles.downColor;
|
|
7889
|
+
colors[1] = styles.downBorderColor;
|
|
7890
|
+
colors[2] = styles.downWickColor;
|
|
7891
|
+
}
|
|
7892
|
+
else {
|
|
7893
|
+
// Essentially equal - use neutral color
|
|
7894
|
+
// But check the trend direction from original candle for tie-breaking
|
|
7895
|
+
if (originalClose > originalOpen) {
|
|
7896
|
+
// Rising trend in original candle, prefer showing as up
|
|
7897
|
+
colors[0] = styles.upColor;
|
|
7898
|
+
colors[1] = styles.upBorderColor;
|
|
7899
|
+
colors[2] = styles.upWickColor;
|
|
7900
|
+
}
|
|
7901
|
+
else if (originalClose < originalOpen) {
|
|
7902
|
+
// Falling trend in original candle, prefer showing as down
|
|
7903
|
+
colors[0] = styles.downColor;
|
|
7904
|
+
colors[1] = styles.downBorderColor;
|
|
7905
|
+
colors[2] = styles.downWickColor;
|
|
7906
|
+
}
|
|
7907
|
+
else {
|
|
7908
|
+
// Truly neutral
|
|
7909
|
+
colors[0] = styles.noChangeColor;
|
|
7910
|
+
colors[1] = styles.noChangeBorderColor;
|
|
7911
|
+
colors[2] = styles.noChangeWickColor;
|
|
7912
|
+
}
|
|
7913
|
+
}
|
|
7914
|
+
return colors;
|
|
7915
|
+
};
|
|
7760
7916
|
return CandleBarView;
|
|
7761
7917
|
}(ChildrenView));
|
|
7762
7918
|
|
|
@@ -13243,7 +13399,7 @@ var ChartImp = /** @class */ (function () {
|
|
|
13243
13399
|
}
|
|
13244
13400
|
}
|
|
13245
13401
|
});
|
|
13246
|
-
createCandlePane({
|
|
13402
|
+
createCandlePane({ });
|
|
13247
13403
|
createXAxisPane({ order: Number.MAX_SAFE_INTEGER });
|
|
13248
13404
|
};
|
|
13249
13405
|
ChartImp.prototype._createPane = function (DrawPaneClass, id, options) {
|
package/dist/umd/klinecharts.js
CHANGED
|
@@ -357,6 +357,11 @@ function getDefaultCandleStyle() {
|
|
|
357
357
|
marginBottom: 4
|
|
358
358
|
},
|
|
359
359
|
icons: []
|
|
360
|
+
},
|
|
361
|
+
renko: {
|
|
362
|
+
brick: {
|
|
363
|
+
size: 10
|
|
364
|
+
}
|
|
360
365
|
}
|
|
361
366
|
};
|
|
362
367
|
}
|
|
@@ -7506,10 +7511,14 @@ var ChildrenView = /** @class */ (function (_super) {
|
|
|
7506
7511
|
* See the License for the specific language governing permissions and
|
|
7507
7512
|
* limitations under the License.
|
|
7508
7513
|
*/
|
|
7514
|
+
// Small epsilon value to handle floating point comparison
|
|
7515
|
+
var EPSILON = 0.000001;
|
|
7509
7516
|
var CandleBarView = /** @class */ (function (_super) {
|
|
7510
7517
|
__extends(CandleBarView, _super);
|
|
7511
7518
|
function CandleBarView() {
|
|
7512
7519
|
var _this = _super.apply(this, __spreadArray([], __read(arguments), false)) || this;
|
|
7520
|
+
// Cache for Heikin-Ashi calculations
|
|
7521
|
+
_this._heikinAshiCache = new Map();
|
|
7513
7522
|
_this._boundCandleBarClickEvent = function (data) { return function () {
|
|
7514
7523
|
_this.getWidget().getPane().getChart().getChartStore().executeAction(exports.ActionType.OnCandleBarClick, data);
|
|
7515
7524
|
return false;
|
|
@@ -7533,6 +7542,10 @@ var CandleBarView = /** @class */ (function (_super) {
|
|
|
7533
7542
|
}
|
|
7534
7543
|
halfOhlcSize_1 = Math.floor(halfOhlcSize_1 / 2);
|
|
7535
7544
|
}
|
|
7545
|
+
// Clear Heikin-Ashi cache when changing to a different chart type
|
|
7546
|
+
if (candleBarOptions.type !== exports.CandleType.HeikinAshi) {
|
|
7547
|
+
this._heikinAshiCache.clear();
|
|
7548
|
+
}
|
|
7536
7549
|
var yAxis_1 = pane.getAxisComponent();
|
|
7537
7550
|
this.eachChildren(function (data, barSpace) {
|
|
7538
7551
|
var kLineData = data.data, x = data.x;
|
|
@@ -7623,6 +7636,8 @@ var CandleBarView = /** @class */ (function (_super) {
|
|
|
7623
7636
|
}
|
|
7624
7637
|
case exports.CandleType.HeikinAshi: {
|
|
7625
7638
|
var heikinAshiData = _this._calculateHeikinAshi(data);
|
|
7639
|
+
// Determine colors based on Heikin-Ashi data and original candle
|
|
7640
|
+
colors = _this._getHeikinAshiColors(heikinAshiData.haValues.open, heikinAshiData.haValues.close, open_1, close_1, styles);
|
|
7626
7641
|
rects = _this._createSolidBar(x, heikinAshiData.priceY, barSpace, colors, correction);
|
|
7627
7642
|
break;
|
|
7628
7643
|
}
|
|
@@ -7715,9 +7730,9 @@ var CandleBarView = /** @class */ (function (_super) {
|
|
|
7715
7730
|
* Calculate Heikin Ashi candle data
|
|
7716
7731
|
* Calculation method is based on the following formula:
|
|
7717
7732
|
* - Close = (Open + High + Low + Close) / 4
|
|
7718
|
-
* - Open = (Previous Open + Previous Close) / 2
|
|
7719
|
-
* - High = Max(High, Open, Close)
|
|
7720
|
-
* - Low = Min(Low, Open, Close)
|
|
7733
|
+
* - Open = (Previous HA Open + Previous HA Close) / 2
|
|
7734
|
+
* - High = Max(High, HA Open, HA Close)
|
|
7735
|
+
* - Low = Min(Low, HA Open, HA Close)
|
|
7721
7736
|
*
|
|
7722
7737
|
* To read more please read - https://www.investopedia.com/trading/heikin-ashi-better-candlestick/
|
|
7723
7738
|
*
|
|
@@ -7727,13 +7742,58 @@ var CandleBarView = /** @class */ (function (_super) {
|
|
|
7727
7742
|
CandleBarView.prototype._calculateHeikinAshi = function (data) {
|
|
7728
7743
|
var kLineData = data.data, dataIndex = data.dataIndex;
|
|
7729
7744
|
var _a = kLineData, open = _a.open, high = _a.high, low = _a.low, close = _a.close;
|
|
7730
|
-
|
|
7731
|
-
var
|
|
7732
|
-
|
|
7745
|
+
// Check if this candle's HA values are already calculated
|
|
7746
|
+
var cachedHeikinAshi = this._heikinAshiCache.get(dataIndex);
|
|
7747
|
+
if (cachedHeikinAshi !== undefined) {
|
|
7748
|
+
var yAxis_2 = this.getWidget().getPane().getAxisComponent();
|
|
7749
|
+
var priceY_1 = [
|
|
7750
|
+
yAxis_2.convertToPixel(cachedHeikinAshi.open),
|
|
7751
|
+
yAxis_2.convertToPixel(cachedHeikinAshi.close),
|
|
7752
|
+
yAxis_2.convertToPixel(cachedHeikinAshi.high),
|
|
7753
|
+
yAxis_2.convertToPixel(cachedHeikinAshi.low)
|
|
7754
|
+
];
|
|
7755
|
+
priceY_1.sort(function (a, b) { return a - b; });
|
|
7756
|
+
return { priceY: priceY_1, haValues: cachedHeikinAshi };
|
|
7757
|
+
}
|
|
7758
|
+
// Calculate Heikin-Ashi values
|
|
7759
|
+
// First, calculate the close which is always the same formula
|
|
7733
7760
|
var haClose = (open + high + low + close) / 4;
|
|
7734
|
-
var haOpen =
|
|
7761
|
+
var haOpen = 0;
|
|
7762
|
+
// Get the previous HA data if available, otherwise use regular OHLC
|
|
7763
|
+
if (dataIndex > 0) {
|
|
7764
|
+
var previousHA = this._getHeikinAshiValues(dataIndex - 1);
|
|
7765
|
+
if (previousHA !== null) {
|
|
7766
|
+
// Use previous HA values to calculate current HA open
|
|
7767
|
+
haOpen = (previousHA.open + previousHA.close) / 2;
|
|
7768
|
+
}
|
|
7769
|
+
else {
|
|
7770
|
+
// Fallback if previous HA values aren't available
|
|
7771
|
+
var previousData = this.getPreviousData(dataIndex);
|
|
7772
|
+
if (previousData !== null) {
|
|
7773
|
+
haOpen = (previousData.open + previousData.close) / 2;
|
|
7774
|
+
}
|
|
7775
|
+
else {
|
|
7776
|
+
haOpen = open; // First candle
|
|
7777
|
+
}
|
|
7778
|
+
}
|
|
7779
|
+
}
|
|
7780
|
+
else {
|
|
7781
|
+
// First candle in the series
|
|
7782
|
+
haOpen = (open + close) / 2;
|
|
7783
|
+
}
|
|
7784
|
+
// Calculate high and low based on HA values
|
|
7735
7785
|
var haHigh = Math.max(high, haOpen, haClose);
|
|
7736
7786
|
var haLow = Math.min(low, haOpen, haClose);
|
|
7787
|
+
// Create HA data object
|
|
7788
|
+
var haValues = {
|
|
7789
|
+
open: haOpen,
|
|
7790
|
+
high: haHigh,
|
|
7791
|
+
low: haLow,
|
|
7792
|
+
close: haClose
|
|
7793
|
+
};
|
|
7794
|
+
// Cache the calculated values
|
|
7795
|
+
this._heikinAshiCache.set(dataIndex, haValues);
|
|
7796
|
+
// Convert to pixel coordinates for display
|
|
7737
7797
|
var yAxis = this.getWidget().getPane().getAxisComponent();
|
|
7738
7798
|
var priceY = [
|
|
7739
7799
|
yAxis.convertToPixel(haOpen),
|
|
@@ -7742,7 +7802,52 @@ var CandleBarView = /** @class */ (function (_super) {
|
|
|
7742
7802
|
yAxis.convertToPixel(haLow)
|
|
7743
7803
|
];
|
|
7744
7804
|
priceY.sort(function (a, b) { return a - b; });
|
|
7745
|
-
return { priceY: priceY };
|
|
7805
|
+
return { priceY: priceY, haValues: haValues };
|
|
7806
|
+
};
|
|
7807
|
+
/**
|
|
7808
|
+
* Get Heikin-Ashi values for a specific candle, calculating them if necessary
|
|
7809
|
+
* @param dataIndex - The index of the data point in the data list
|
|
7810
|
+
* @private
|
|
7811
|
+
*/
|
|
7812
|
+
CandleBarView.prototype._getHeikinAshiValues = function (dataIndex) {
|
|
7813
|
+
// Check if already calculated
|
|
7814
|
+
var cachedValues = this._heikinAshiCache.get(dataIndex);
|
|
7815
|
+
if (cachedValues !== undefined) {
|
|
7816
|
+
return cachedValues;
|
|
7817
|
+
}
|
|
7818
|
+
// Not calculated yet, need to calculate
|
|
7819
|
+
var dataList = this.getWidget().getPane().getChart().getChartStore().getDataList();
|
|
7820
|
+
if (dataIndex < 0 || dataIndex >= dataList.length) {
|
|
7821
|
+
return null;
|
|
7822
|
+
}
|
|
7823
|
+
var kLineData = dataList[dataIndex];
|
|
7824
|
+
// Get the previous candle's HA values, recursively calculate if necessary
|
|
7825
|
+
var previousHA = null;
|
|
7826
|
+
if (dataIndex > 0) {
|
|
7827
|
+
previousHA = this._getHeikinAshiValues(dataIndex - 1);
|
|
7828
|
+
}
|
|
7829
|
+
var open = kLineData.open, high = kLineData.high, low = kLineData.low, close = kLineData.close;
|
|
7830
|
+
// Calculate HA values
|
|
7831
|
+
var haClose = (open + high + low + close) / 4;
|
|
7832
|
+
var haOpen = 0;
|
|
7833
|
+
if (previousHA !== null) {
|
|
7834
|
+
haOpen = (previousHA.open + previousHA.close) / 2;
|
|
7835
|
+
}
|
|
7836
|
+
else {
|
|
7837
|
+
// For the first candle
|
|
7838
|
+
haOpen = (open + close) / 2;
|
|
7839
|
+
}
|
|
7840
|
+
var haHigh = Math.max(high, haOpen, haClose);
|
|
7841
|
+
var haLow = Math.min(low, haOpen, haClose);
|
|
7842
|
+
var haValues = {
|
|
7843
|
+
open: haOpen,
|
|
7844
|
+
high: haHigh,
|
|
7845
|
+
low: haLow,
|
|
7846
|
+
close: haClose
|
|
7847
|
+
};
|
|
7848
|
+
// Cache the values
|
|
7849
|
+
this._heikinAshiCache.set(dataIndex, haValues);
|
|
7850
|
+
return haValues;
|
|
7746
7851
|
};
|
|
7747
7852
|
/**
|
|
7748
7853
|
* Retrieves the previous KLineData from the data list based on the given index.
|
|
@@ -7762,6 +7867,57 @@ var CandleBarView = /** @class */ (function (_super) {
|
|
|
7762
7867
|
}
|
|
7763
7868
|
return null;
|
|
7764
7869
|
};
|
|
7870
|
+
/**
|
|
7871
|
+
* Determine appropriate colors for Heikin-Ashi candles based on their open and close values
|
|
7872
|
+
* @param haOpen - Heikin-Ashi open price
|
|
7873
|
+
* @param haClose - Heikin-Ashi close price
|
|
7874
|
+
* @param originalOpen - Original candle open price
|
|
7875
|
+
* @param originalClose - Original candle close price
|
|
7876
|
+
* @param styles - Candle bar color styles
|
|
7877
|
+
* @returns Array of colors [bodyColor, borderColor, wickColor]
|
|
7878
|
+
* @private
|
|
7879
|
+
*/
|
|
7880
|
+
CandleBarView.prototype._getHeikinAshiColors = function (haOpen, haClose, originalOpen, originalClose, styles) {
|
|
7881
|
+
var colors = [];
|
|
7882
|
+
// Fixed comparison logic with epsilon to avoid floating point precision issues
|
|
7883
|
+
var diff = haClose - haOpen;
|
|
7884
|
+
// Determine candle color based on the relationship between HA open and close
|
|
7885
|
+
if (diff > EPSILON) {
|
|
7886
|
+
// Clearly higher close - green candle
|
|
7887
|
+
colors[0] = styles.upColor;
|
|
7888
|
+
colors[1] = styles.upBorderColor;
|
|
7889
|
+
colors[2] = styles.upWickColor;
|
|
7890
|
+
}
|
|
7891
|
+
else if (diff < -1e-6) {
|
|
7892
|
+
// Clearly lower close - red candle
|
|
7893
|
+
colors[0] = styles.downColor;
|
|
7894
|
+
colors[1] = styles.downBorderColor;
|
|
7895
|
+
colors[2] = styles.downWickColor;
|
|
7896
|
+
}
|
|
7897
|
+
else {
|
|
7898
|
+
// Essentially equal - use neutral color
|
|
7899
|
+
// But check the trend direction from original candle for tie-breaking
|
|
7900
|
+
if (originalClose > originalOpen) {
|
|
7901
|
+
// Rising trend in original candle, prefer showing as up
|
|
7902
|
+
colors[0] = styles.upColor;
|
|
7903
|
+
colors[1] = styles.upBorderColor;
|
|
7904
|
+
colors[2] = styles.upWickColor;
|
|
7905
|
+
}
|
|
7906
|
+
else if (originalClose < originalOpen) {
|
|
7907
|
+
// Falling trend in original candle, prefer showing as down
|
|
7908
|
+
colors[0] = styles.downColor;
|
|
7909
|
+
colors[1] = styles.downBorderColor;
|
|
7910
|
+
colors[2] = styles.downWickColor;
|
|
7911
|
+
}
|
|
7912
|
+
else {
|
|
7913
|
+
// Truly neutral
|
|
7914
|
+
colors[0] = styles.noChangeColor;
|
|
7915
|
+
colors[1] = styles.noChangeBorderColor;
|
|
7916
|
+
colors[2] = styles.noChangeWickColor;
|
|
7917
|
+
}
|
|
7918
|
+
}
|
|
7919
|
+
return colors;
|
|
7920
|
+
};
|
|
7765
7921
|
return CandleBarView;
|
|
7766
7922
|
}(ChildrenView));
|
|
7767
7923
|
|
|
@@ -13248,7 +13404,7 @@ var ChartImp = /** @class */ (function () {
|
|
|
13248
13404
|
}
|
|
13249
13405
|
}
|
|
13250
13406
|
});
|
|
13251
|
-
createCandlePane({
|
|
13407
|
+
createCandlePane({ });
|
|
13252
13408
|
createXAxisPane({ order: Number.MAX_SAFE_INTEGER });
|
|
13253
13409
|
};
|
|
13254
13410
|
ChartImp.prototype._createPane = function (DrawPaneClass, id, options) {
|