diff --git a/src/chart/components/chart/candle.functions.ts b/src/chart/components/chart/candle.functions.ts index 836b8a8f..733ec013 100644 --- a/src/chart/components/chart/candle.functions.ts +++ b/src/chart/components/chart/candle.functions.ts @@ -12,28 +12,33 @@ import { PartialCandle } from './chart.component'; * so there is not enough information to build a candle: only Open/Close value available. * In this case Daily candle, which we receive, must be completed to full OHLC with equal values. */ -export const prepareCandle = (candle: PartialCandle): Candle => { - const settlementPrice = finite(candle.close, candle.open, candle.hi, candle.lo); - if (!isFinite(settlementPrice)) { - throw new Error('Received candle without any price'); +export const prepareCandle = (candle: PartialCandle): Candle | undefined => { + try { + const settlementPrice = finite(candle.close, candle.open, candle.hi, candle.lo); + if (!isFinite(settlementPrice)) { + throw new Error('Received candle without any price'); + } + // @ts-ignore + const preparedCandleHi = finite(candle.hi, Math.max(candle.open, candle.close), settlementPrice); + // @ts-ignore + const preparedCandleLo = finite(candle.lo, Math.min(candle.open, candle.close), settlementPrice); + const preparedCandleOpen = finite(candle.open, candle.lo, settlementPrice); + const preparedCandleClose = finite(candle.close, candle.hi, settlementPrice); + return { + hi: preparedCandleHi, + lo: preparedCandleLo, + open: preparedCandleOpen, + close: preparedCandleClose, + timestamp: candle.timestamp, + volume: candle.volume ?? 0, + expansion: candle.expansion, + idx: candle.idx, + impVolatility: candle.impVolatility, + }; + } catch (e) { + console.warn(e); + return; } - // @ts-ignore - const preparedCandleHi = finite(candle.hi, Math.max(candle.open, candle.close), settlementPrice); - // @ts-ignore - const preparedCandleLo = finite(candle.lo, Math.min(candle.open, candle.close), settlementPrice); - const preparedCandleOpen = finite(candle.open, candle.lo, settlementPrice); - const preparedCandleClose = finite(candle.close, candle.hi, settlementPrice); - return { - hi: preparedCandleHi, - lo: preparedCandleLo, - open: preparedCandleOpen, - close: preparedCandleClose, - timestamp: candle.timestamp, - volume: candle.volume ?? 0, - expansion: candle.expansion, - idx: candle.idx, - impVolatility: candle.impVolatility, - }; }; /** @@ -51,3 +56,5 @@ export const deleteCandlesIndex = (candles: Array) => { candle.idx = undefined; }); }; + +export const isCandle = (value: Candle | undefined): value is Candle => value !== undefined; diff --git a/src/chart/components/chart/chart.model.ts b/src/chart/components/chart/chart.model.ts index 75ff9ba3..9fa6ca63 100755 --- a/src/chart/components/chart/chart.model.ts +++ b/src/chart/components/chart/chart.model.ts @@ -33,7 +33,7 @@ import { PaneComponent } from '../pane/pane.component'; import { LabelGroup } from '../y_axis/price_labels/y-axis-labels.model'; import { createBasicScaleViewportTransformer, createTimeFrameViewportTransformer } from './basic-scale'; import { calculateCandleWidth } from './candle-width-calculator.functions'; -import { deleteCandlesIndex, prepareCandle, reindexCandles } from './candle.functions'; +import { deleteCandlesIndex, isCandle, prepareCandle, reindexCandles } from './candle.functions'; import { ChartBaseModel } from './chart-base.model'; import { CandleSeries, ChartInstrument, PartialCandle } from './chart.component'; import { fakeCandle } from './fake-candles'; @@ -230,9 +230,9 @@ export class ChartModel extends ChartBaseElement { instrument: ChartInstrument = this.mainCandleSeries.instrument, recalculateAndUpdate = true, ): CandleSeriesModel | undefined { - const prepareCandleCandles = sortCandles(candles.map(prepareCandle)); + const preparedCandles = prepareCandles(candles); // set correct indexes based on main candles timestamp - const reindexCandles = this.reindexCandlesBasedOnSeries(this.mainCandleSeries.dataPoints, prepareCandleCandles); + const reindexCandles = this.reindexCandlesBasedOnSeries(this.mainCandleSeries.dataPoints, preparedCandles); // ensure there are no gaps in new candles const secondaryCandles = this.secondarySeriesAdjustments(this.mainCandleSeries.dataPoints, reindexCandles); // create a new secondary series model if it doesn't already exist @@ -267,10 +267,10 @@ export class ChartModel extends ChartBaseElement { this.mainInstrumentChangedSubject.next(mainSeries.instrument); } this.rememberCurrentTimeframe(); - const prepareCandleCandles = sortCandles(mainSeries.candles.map(prepareCandle)); + const preparedCandles = prepareCandles(mainSeries.candles); this.mainCandleSeries.clearData(); - reindexCandles(prepareCandleCandles); - this.mainCandleSeries.dataPoints = prepareCandleCandles; + reindexCandles(preparedCandles); + this.mainCandleSeries.dataPoints = preparedCandles; // deactivate deleted series this.secondaryCandleSeries .filter(series => { @@ -359,7 +359,7 @@ export class ChartModel extends ChartBaseElement { return; } - const preparedCandles = sortCandles(mainSeries.candles.map(prepareCandle)); + const preparedCandles = prepareCandles(mainSeries.candles); const updateResult = updateCandles(this.mainCandleSeries.dataPoints, preparedCandles); const updatedCandles = updateResult.candles; reindexCandles(updatedCandles); @@ -367,7 +367,7 @@ export class ChartModel extends ChartBaseElement { // re-create series secondarySeries.map(series => { - const preparedCandles = sortCandles(series.candles.map(prepareCandle)); + const preparedCandles = prepareCandles(series.candles); const updatedCandles = updateCandles( this.findSecondarySeriesBySymbol(series.instrument?.symbol ?? '')?.dataPoints ?? [], preparedCandles, @@ -1117,6 +1117,8 @@ export interface UpdateCandlesResult { const sortCandles = (candles: Candle[]): Candle[] => candles.slice().sort((a, b) => (a.timestamp === b.timestamp ? 0 : a.timestamp > b.timestamp ? 1 : -1)); +const prepareCandles = (candles: PartialCandle[]): Candle[] => sortCandles(candles.map(prepareCandle).filter(isCandle)); + const findFirstNotEmptyCandle = (candles: Array, startIdx: number, iterateStep: number): Candle | undefined => { if (startIdx >= candles.length) { return candles[candles.length - 1];