PageSourceSearch

https://indopremier.com/app/js/tradingview.js?v=20260727

js indopremier.com collected 2026-10-02 02:59:45 UTC 39,970 bytes, 1,234 lines download raw bytes

1let BARS = {};
2let SERVER_TIME;
3let LASTPRICE_DATA = {};
4
5class ChartingLibrary {
6    path = 'app/lib/tradingview';
7    settings = {
8        A: {
9            overrides: {
10                'paneProperties.topMargin': 10,
11                'paneProperties.legendProperties.showSeriesTitle': true,
12                'paneProperties.legendProperties.showSeriesOHLC': true,
13                'mainSeriesProperties.style': 1,
14                'mainSeriesProperties.highLowAvgPrice.highLowPriceLinesVisible': true,
15                'mainSeriesProperties.highLowAvgPrice.highLowPriceLabelsVisible': true
16            },
17            disabled_features: [
18                // 'header_screenshot',
19                'save_chart_properties_to_local_storage',
20            ],
21            enabled_features: [
22                'hide_last_na_study_output',
23                // 'two_character_bar_marks_labels'
24            ],
25            studies_overrides: {}
26        },
27        S: {
28            overrides: {
29                'paneProperties.topMargin': 10,
30                'paneProperties.legendProperties.showSeriesTitle': true,
31                'mainSeriesProperties.style': 3
32            },
33            disabled_features: [
34                // header_widget
35                'header_widget',
36                'left_toolbar',
37                'context_menus',
38                'border_around_the_chart',
39                'timezone_menu',
40                'chart_property_page_timezone_sessions',
41                // use_localstorage_for_settings
42                'use_localstorage_for_settings'
43            ],
44            enabled_features: [],
45            studies_overrides: {}
46        },
47        X: {
48            overrides: {
49                'paneProperties.vertGridProperties.color': 'transparent',
50                'paneProperties.horzGridProperties.color': 'transparent',
51                'paneProperties.legendProperties.showStudyArguments': false,
52                'paneProperties.legendProperties.showStudyTitles': false,
53                'paneProperties.legendProperties.showStudyValues': false,
54                'paneProperties.legendProperties.showSeriesTitle': false,
55                'paneProperties.legendProperties.showSeriesOHLC': false,
56                'paneProperties.legendProperties.showLegend': false,
57                'paneProperties.legendProperties.showBarChange': false,
58                'scalesProperties.fontSize': 10,
59                'scalesProperties.lineColor': '#191c2f',
60                'scalesProperties.textColor': '#989dd2',
61                'mainSeriesProperties.style': 3,
62                'mainSeriesProperties.areaStyle.linewidth': 2
63            },
64            disabled_features: [
65                'header_widget',
66                'left_toolbar',
67                'control_bar',
68                'timeframes_toolbar',
69                'context_menus',
70                'display_market_status',
71                'symbol_info',
72                'timezone_menu',
73                'popup_hints',
74                'use_localstorage_for_settings'
75            ],
76            enabled_features: [],
77            studies_overrides: {}
78        }
79    };
80
81    constructor() {
82        this.code;
83        this.widget;
84        this.datafeed = new TradingViewDataFeed();
85
86        appendScript(this.path + '/charting_library/charting_library.standalone.js');
87        appendScript(this.path + '/datafeeds/udf/dist/bundle.js');
88    }
89
90    applyColor(color) {
91        let color1, color2, linecolor;
92
93        if (color == 'text-color-green') {
94            linecolor = '#4FA77D';
95            color1 = 'rgba(79, 167, 125, 0.5)';
96            color2 = 'rgba(79, 167, 125, 0)';
97        } else if (color == 'text-color-red') {
98            linecolor = '#C16161';
99            color1 = 'rgba(193, 97, 97, 0.5)';
100            color2 = 'rgba(193, 97, 97, 0)'
101        } else if (color == 'text-color-yellow') {
102            linecolor = '#b18637';
103            color1 = 'rgba(203, 185, 89, 0.5)';
104            color2 = 'rgba(203, 185, 89, 0)';
105        } else {
106            linecolor = '#5189C9';
107            color1 = 'rgba(81, 137, 201, 0.5)';
108            color2 = 'rgba(81, 137, 201, 0)';
109        }
110
111        if (this.widget) {
112            this.widget.applyOverrides({
113                'mainSeriesProperties.areaStyle.color1': color1,
114                'mainSeriesProperties.areaStyle.color2': color2,
115                'mainSeriesProperties.areaStyle.linecolor': linecolor
116            });
117        }
118    }
119
120    applyColorTemp() {
121        if (this.widget) {
122            this.widget.applyOverrides({
123                'mainSeriesProperties.areaStyle.color1': 'rgba(81, 137, 201, 0.5)',
124                'mainSeriesProperties.areaStyle.color2': 'rgba(81, 137, 201, 0)',
125                'mainSeriesProperties.areaStyle.linecolor': '#5189C9'
126            });
127        }
128    }
129
130    applyColorStock(close) {
131        try {
132            let last = close || sc.PriceLast(this.code) || sc.PricePrev(this.code);
133            let prev = sc.PricePrev(this.code);
134
135            this.applyColor(getColorClassChange(last - prev));
136        } catch (error) {
137
138        }
139    }
140
141    async createWidget(param) {
142        let library_path = this.path + '/charting_library/';
143        let {
144            type,
145            symbol,
146            container_id,
147            width,
148            height,
149            interval,
150            timeframe,
151            time_frames
152        } = param;
153
154        if (!window.cl_libs) {
155            await new Promise(r => setTimeout(r, 1000)); window.cl_libs = true;
156        }
157
158        this.hilo = param.hilo;
159
160        let p = {
161            symbol, // *
162            container: container_id, // *
163            datafeed: this.datafeed, // *
164            timezone: 'Asia/Jakarta',
165            // Setting this property to true will make the chart write detailed API logs into the browser console
166            debug: false,
167            library_path,
168            width: width ? width : '100%',
169            height: height ? height : '100%',
170            // study_count_limit: study_count_limit ? study_count_limit : '5',
171            locale: 'en',
172            numeric_formatting: {
173                decimal_sign: ','
174            },
175            overrides: this.getSettings(type, 'overrides', {}),
176            disabled_features: this.getSettings(type, 'disabled_features', []),
177            enabled_features: this.getSettings(type, 'enabled_features', []),
178            studies_overrides: this.getSettings(type, 'studies_overrides', {}),
179            time_frames: time_frames ? time_frames : this.getTimeFrames(),
180            theme: 'Dark',
181            custom_css_url: 'static/css/chart.css',
182            snapshot_url: 'https://x.ipot.id/tv'
183        };
184
185        if (interval) {
186            p['interval'] = interval;
187        }
188
189        if (timeframe) {
190            p['timeframe'] = timeframe;
191        }
192
193        // * - Required
194        this.widget = new TradingView.widget(p);
195        this.stock = getSecname(symbol);
196        this.code = symbol;
197
198        return await new Promise((resolve, reject) => {
199            let ctx = this;
200
201            this.widget.onChartReady(function () {
202                let elInfo = $$('#' + container_id).next();
203
204                if (elInfo.length > 0 && elInfo.hasClass('container-info')) {
205                    elInfo.on('click', function () {
206                        app.dialog.alert("Chart yang kami gunakan disediakan oleh TradingView, sebuah platform charting bagi para trader dan investor dari seluruh penjuru dunia. Anda dapat menemukan kilasan dari berbagai instrumen seperti nilai tukar BTC USD, harga emas, saham, dan masih banyak lagi. Selain dari itu, TradingView juga menyediakan berbagai peralatan finansial gratis untuk digunakan seperti Kalender Ekonomi, Stock Screener dan juga Widget-Widget Finansial.")
207                    });
208
209                    elInfo.removeClass('display-none');
210                }
211
212                if (param.type == 'A') {
213                    ctx.widget.chart().createStudy('Moving Average', false, false, null, null);
214                    ctx.widget.chart().createStudy('Relative Strength Index', false, false, null, null);
215                }
216
217                // ctx.widget.chart().refreshMarks();
218
219                ctx.widget.applyOverrides({
220                    'paneProperties.backgroundType': 'solid',
221                    'paneProperties.background': '#05082c'
222                });
223
224                if (ctx.stock) {
225                    set();
226                } else {
227                    setTimeout(() => {
228                        ctx.stock = getSecname(symbol);
229                        set();
230                    }, 1000);
231                }
232
233                function set() {
234                    if (ctx.stock) {
235                        let entityId = {
236                            prev: '',
237                            // high: '',
238                            // low: ''
239                        };
240
241                        if (interval == 1) {
242                            entityId.prev = ctx.createShape('prev');
243                            // entityId.high = ctx.createShape('high');
244                            // entityId.low = ctx.createShape('low');
245
246                            if (ctx.hilo) {
247                                ctx.widget.applyOverrides({
248                                    'mainSeriesProperties.highLowAvgPrice.highLowPriceLinesVisible': true,
249                                    'mainSeriesProperties.highLowAvgPrice.highLowPriceLabelsVisible': true
250                                });
251                            }
252                        }
253
254                        ctx.widget.activeChart().onVisibleRangeChanged().subscribe(
255                            null, ({ from, to }) => {
256                                let resolution = ctx.widget.activeChart().resolution();
257
258                                if (resolution == '1') {
259                                    ctx.applyColorStock();
260                                } else {
261                                    ctx.applyColorTemp();
262                                }
263                            }
264                        );
265
266                        ctx.widget.activeChart().onSymbolChanged().subscribe(null, (data) => {
267                            ctx.applyColorStock();
268
269                            if (ctx.hilo) {
270                                ctx.widget.activeChart().removeEntity(entityId.prev);
271                                // ctx.widget.activeChart().removeEntity(entityId.high);
272                                // ctx.widget.activeChart().removeEntity(entityId.low);
273                            }
274
275                            setTimeout(() => {
276                                entityId.prev = ctx.createShape('prev');
277                                // entityId.high = ctx.createShape('high');
278                                // entityId.low = ctx.createShape('low');
279                            }, 1000);
280                        });
281
282                        if (interval == 1) {
283                            ctx.applyColorStock();
284                        } else if (interval != '1D') {
285                            ctx.applyColorTemp();
286                        }
287                    }
288                }
289
290                ctx.widget.subscribe('onTick', function (data) {
291                    let resolution = ctx.widget.activeChart().resolution();
292
293                    ctx.stock = getSecname(symbol);
294
295                    if (ctx.stock && resolution == '1' && data) {
296                        ctx.applyColorStock(data.close);
297                    }
298                });
299
300                resolve(true);
301            });
302        });
303    }
304
305    createShape(label) {
306        let point = {
307            price: 0
308        };
309
310        if (!this.hilo) {
311            return;
312        }
313
314        if (label == 'prev') {
315            let symbol = this.widget.activeChart().symbol();
316            let code = symbol.split(':')[1];
317            let plast = sc.PriceLast(code);
318            let pprev = sc.PricePrev(code);
319
320            if (pprev && plast != pprev) {
321                point.price = pprev;
322
323                return this.widget.chart()
324                    .createShape(point, {
325                        shape: 'horizontal_line',
326                        overrides: {
327                            linecolor: '#b18637'
328                        }
329                    });
330            }
331        }
332        // else if (label == 'high') {
333        //     let high = this.datafeed.high;
334
335        //     if (high > 0) {
336        //         point.price = high;
337
338        //         return this.widget.chart()
339        //             .createShape(point, {
340        //                 shape: 'horizontal_line',
341        //                 overrides: {
342        //                     linecolor: '#4FA77D'
343        //                 }
344        //             });
345        //     }
346        // } else if (label == 'low') {
347        //     let low = this.datafeed.low;
348
349        //     if (low > 0) {
350        //         point.price = low;
351
352        //         return this.widget.chart()
353        //             .createShape(point, {
354        //                 shape: 'horizontal_line',
355        //                 overrides: {
356        //                     linecolor: '#C16161'
357        //                 }
358        //             });
359        //     }
360        // }
361    }
362
363    getTimeFrames() {
364        return [
365            { text: '15y', resolution: '1M', description: '15 Year' },
366            { text: '10y', resolution: '1M', description: '10 Year' },
367            { text: '5y', resolution: '1W', description: '5 Year' },
368            { text: '3y', resolution: 'D', description: '3 Year' },
369            { text: '1y', resolution: 'D', description: '1 Year' },
370            { text: '6m', resolution: 'D', description: '6 Month' },
371            { text: '3m', resolution: 'D', description: '3 Month' },
372            { text: '1m', resolution: 'D', description: '1 Month' },
373            { text: '5d', resolution: 'D', description: '5 Day' },
374            { text: '1d', resolution: '1', description: '1 Day' }
375        ];
376    }
377
378    getSettings(type, prop, template) {
379        try {
380            return this.settings[type][prop] ? this.settings[type][prop] : template;
381        } catch (error) {
382            return template;
383        }
384    }
385
386    setTimeframe(resolution, timeframe, etf = false) {
387        let ctx = this;
388
389        logger('setTimeframe: ', [resolution, timeframe]);
390
391        this.widget.chart().setResolution(resolution, function () {
392            let from;
393            let to = moment().unix();
394
395            if (etf) {
396                ctx.widget.mainSeriesPriceFormatter()._priceScale = 1;
397                ctx.widget.applyOverrides({
398                    'mainSeriesProperties.highLowAvgPrice.highLowPriceLinesVisible': false,
399                    'mainSeriesProperties.highLowAvgPrice.highLowPriceLabelsVisible': false
400                });
401            }
402
403            if (timeframe == 'YTD') {
404                from = moment().startOf('year').unix();
405            } else {
406                if (timeframe[1] == 'D') {
407                    if (timeframe[0] == '1') {
408                        if (etf) {
409                            ctx.widget.mainSeriesPriceFormatter()._priceScale = 10000;
410                            ctx.widget.applyOverrides({
411                                'mainSeriesProperties.highLowAvgPrice.highLowPriceLinesVisible': true,
412                                'mainSeriesProperties.highLowAvgPrice.highLowPriceLabelsVisible': true
413                            });
414                        }
415
416                        try {
417                            let ss = ctx.datafeed.session.split(',');
418                            let hh = ss[0].split('-')[0];
419
420                            if (hh) {
421                                hh = (hh + '').slice(0, 2);
422                            }
423
424                            from = moment().set('hour', +hh).set('minute', 0).set('second', 0).unix();
425                        } catch (error) {
426                            // console.log(error);
427                        }
428                    } else {
429                        from = moment().subtract(timeframe[0], 'days').unix();
430                    }
431                } else if (timeframe[1] == 'M') {
432                    from = moment().subtract(timeframe[0], 'months').unix();
433                } else if (timeframe[1] == 'Y') {
434                    from = moment().subtract(timeframe[0], 'years').unix();
435                }
436            }
437
438            if (from) {
439                ctx.widget.chart().setVisibleRange(
440                    { from, to },
441                    { percentRightMargin: 20 }
442                ).then(() => {
443
444                });
445            }
446        });
447    }
448}
449
450class LightWeightChart {
451
452    constructor() {
453        this.hi;
454        this.lo;
455        this.hi_pl;
456        this.lo_pl;
457        this.createPriceLineHiLo = 'Y';
458
459        this.tv = new TradingViewDataFeed();
460        this.chart;
461
462        appendScript('app/lib/lightweight-charts/dist/lightweight-charts.standalone.production.js');
463    }
464
465    async createChart(param, trending = false) {
466        let {
467            code,
468            container_id,
469            parameters_custom,
470            createPriceLineHiLo
471        } = param;
472
473        if ($$('#' + container_id).length > 0) {
474            $$('#' + container_id).empty();
475        }
476
477        if (createPriceLineHiLo) {
478            this.createPriceLineHiLo = param.createPriceLineHiLo;
479        }
480
481        if (!window.lw_libs) {
482            await new Promise(r => setTimeout(r, 1000)); window.lw_libs = true;
483        }
484
485        let p = {
486            layout: {
487                backgroundColor: 'transparent',
488                textColor: '#989dd2'
489            },
490            priceScale: {
491                position: 'right'
492            },
493            timeScale: {
494                visible: false
495            },
496            crosshair: {
497                vertLine: {
498                    visible: false,
499                    labelVisible: false
500                },
501                horzLine: {
502                    visible: false,
503                    labelVisible: false
504                }
505            },
506            grid: {
507                vertLines: {
508                    visible: false
509                },
510                horzLines: {
511                    visible: false
512                }
513            },
514            handleScroll: false,
515            handleScale: false
516        };
517
518        Object.assign(p, parameters_custom);
519
520        let chart = LightweightCharts.createChart(container_id, p);
521
522        if (trending) {
523            let series = chart.addAreaSeries({
524                lineWidth: 2,
525                crosshairMarkerVisible: false,
526                priceLineVisible: false,
527                autoscaleInfoProvider: original => {
528                    let res = original();
529
530                    if (res) {
531                        let {
532                            minValue, maxValue
533                        } = res.priceRange;
534
535                        if (param.type == 'brt') {
536                            if (minValue < 50 && maxValue < 50) {
537                                res.priceRange.maxValue = 50;
538                            } else if (minValue > 50 && maxValue > 50) {
539                                res.priceRange.minValue = 50;
540                            }
541                        } else {
542                            res.priceRange.minValue = 0;
543                        }
544                    }
545
546                    return res;
547                }
548            });
549
550            series.applyOptions({
551                topColor: 'rgba(81, 137, 201, 0.5)',
552                bottomColor: 'rgba(81, 137, 201, 0)',
553                lineColor: '#5189C9'
554            });
555
556            if (param.type == 'brt') {
557                series.createPriceLine({
558                    price: 50,
559                    color: '#b18637'
560                });
561            } else {
562                series.createPriceLine({
563                    price: 0,
564                    color: '#5189C9'
565                });
566            }
567
568            return {
569                chart, series
570            };
571        } else {
572            await this.onReady();
573
574            let symbolInfo = await this.onResolveSymbol(code);
575            let time = await this.getServerTime(true);
576            let bars = await this.getBars(symbolInfo, '1', time, true);
577            let data = this.getData(bars);
578            let plast = sc.PriceLast(code);
579            let pprev = sc.PricePrev(code);
580
581            let series = chart.addAreaSeries({
582                lineWidth: 2,
583                crosshairMarkerVisible: false,
584                priceLineVisible: false,
585                autoscaleInfoProvider: original => {
586                    let res = original();
587
588                    if (res) {
589                        let {
590                            minValue, maxValue
591                        } = res.priceRange;
592
593                        if (this.hi && this.lo) {
594                            res.priceRange.minValue = this.lo;
595                            res.priceRange.maxValue = this.hi;
596                        }
597
598                        if (pprev > 0) {
599                            if (pprev < minValue) {
600                                res.priceRange.minValue = pprev;
601                            } else if (pprev > maxValue) {
602                                res.priceRange.maxValue = pprev;
603                            }
604                        }
605                    }
606
607                    return res;
608                }
609            });
610
611            if (pprev > 0) {
612                series.createPriceLine({
613                    price: pprev,
614                    color: pprev == 1 ? '#5189C9' : '#b18637'
615                });
616
617                this.updateChart(series, this.hi, this.lo, pprev, plast);
618            }
619
620            series.setData(data);
621
622            series.applyOptions({
623                priceFormat: {
624                    precision: 0,
625                    minMove: 1
626                }
627            });
628
629            chart.timeScale().fitContent();
630
631            this.onRealTime(symbolInfo, '1', function (res) {
632                res.value = res.close;
633
634                series.update(res);
635
636                // context.updateChart(series, context.hi, context.lo, price.pprev, price.plast);
637            });
638
639            return series;
640        }
641    }
642
643    async getBars(symbolInfo, resolution, time, caching = false) {
644        return await new Promise((resolve, reject) => {
645            let cache = BARS[symbolInfo.name];
646
647            if (cache && caching) {
648                resolve(cache);
649            }
650
651            let periodParams = {
652                from: null,
653                to: time,
654                firstDataRequest: true
655            };
656
657            this.tv.getBars(symbolInfo, resolution, periodParams, function cb_onHistory(res) {
658                if (caching) {
659                    BARS[symbolInfo.name] = res;
660                }
661
662                resolve(res);
663            }, function cb_onError(err) {
664                reject(err);
665            });
666        });
667    }
668
669    getData(bars) {
670        let data = [];
671        let time;
672
673        bars.forEach(el => {
674            el.value = el.close;
675
676            if (this.hi < el.high || !this.hi) {
677                this.hi = el.high;
678            }
679
680            if (this.lo > el.low || !this.lo) {
681                this.lo = el.low;
682            }
683
684            if (time != el.time) {
685                data.push(el);
686            }
687
688            time = el.time;
689        });
690
691        return data;
692    }
693
694    async getServerTime(caching = false) {
695        return await new Promise((resolve, reject) => {
696            this.tv.getServerTime((time) => {
697                if (caching && SERVER_TIME) {
698                    resolve(SERVER_TIME);
699                }
700
701                if (time) {
702                    SERVER_TIME = time;
703
704                    setTimeout(() => {
705                        SERVER_TIME = '';
706                    }, 1000);
707
708                    resolve(time);
709                } else {
710                    reject();
711                }
712            });
713        });
714    }
715
716    async onReady() {
717        return await new Promise((resolve, reject) => {
718            this.tv.onReady((res) => {
719                if (res) {
720                    resolve(res);
721                } else {
722                    reject();
723                }
724            });
725        });
726    }
727
728    onRealTime(symbolInfo, resolution, cb) {
729        let subscriberUID = symbolInfo.ticker + '_' + resolution;
730
731        this.tv.subscribeBars(symbolInfo, resolution, function cb_onRealtime(res) {
732            cb(res);
733        }, subscriberUID);
734    }
735
736    async onResolveSymbol(code) {
737        return await new Promise((resolve, reject) => {
738            this.tv.resolveSymbol(code,
739                (symbolInfo) => {
740                    resolve(symbolInfo);
741                },
742                (err) => {
743                    reject(err);
744                }
745            );
746        });
747    }
748
749    updateChart(series, phi, plo, pprev, plast) {
750        let hi_pl_param = {
751            price: phi,
752            color: '#4FA77D',
753            title: 'Hi'
754        };
755        let lo_pl_param = {
756            price: plo,
757            color: '#C16161',
758            title: 'Lo'
759        };
760        let lineColor;
761        let topColor;
762        let bottomColor;
763
764        if (plast > pprev) {
765            lineColor = '#4fa77d';
766            topColor = 'rgba(79, 167, 125, 0.5)';
767            bottomColor = 'rgba(79, 167, 125, 0)';
768        } else if (plast < pprev) {
769            lineColor = '#c16161';
770            topColor = 'rgba(193, 97, 97, 0.5)';
771            bottomColor = 'rgba(193, 97, 97, 0)'
772        } else if (plast == pprev) {
773            lineColor = '#b18637';
774            topColor = 'rgba(203, 185, 89, 0.5)';
775            bottomColor = 'rgba(203, 185, 89, 0)';
776        }
777
778        series.applyOptions({
779            topColor, bottomColor, lineColor
780        });
781
782        if (phi && plo && this.createPriceLineHiLo == 'Y') {
783            if (this.hi_pl) {
784                if (this.hi != phi) {
785                    series.removePriceLine(this.hi_pl);
786                    this.hi_pl = series.createPriceLine(hi_pl_param);
787                }
788            } else {
789                this.hi_pl = series.createPriceLine(hi_pl_param);
790            }
791
792            if (this.lo_pl) {
793                if (this.lo != plo) {
794                    series.removePriceLine(this.lo_pl);
795                    this.lo_pl = series.createPriceLine(lo_pl_param);
796                }
797            } else {
798                this.lo_pl = series.createPriceLine(lo_pl_param);
799            }
800        }
801    }
802}
803
804class TradingViewDataFeed {
805
806    constructor() {
807        this.cmd = 'tvdfeed';
808        this.high = 0;
809        this.low = 0;
810        this.session;
811
812        this.barsCache = [];
813    }
814
815    onReady(cb) {
816        let param = {
817            cmd: 'onReady'
818        };
819
820        sc.SendWait(param, this.cmd, (err, data) => {
821            if (data) {
822                data.exchanges.push(
823                    { value: 'INDICES', name: 'INDICES', desc: 'Sectoral' },
824                    { value: 'OTHER', name: 'OTHER', desc: 'Other' }
825                );
826                // data.supports_marks = true;
827                cb(data);
828            } else {
829                cb(null);
830            }
831        });
832    }
833
834    async searchSymbols(userInput, exchange = 'IDX', symbolType, cb) {
835        let results = [];
836
837        if (!userInput) {
838            cb(results);
839            return;
840        }
841
842        let pat = ";([^;]*" + userInput + "[^;]*);";
843        let re = new RegExp(pat, "gi");
844        let m, p;
845        let cacpat = sc.cache.pattern;
846
847        if (exchange == 'IDX') {
848            p = 'stock';
849        } else if (exchange == 'INDICES') {
850            p = 'indicesname';
851
852            if (cacpat.indicesname == ';;') {
853                await svc.getIndices('*');
854            }
855        } else if (exchange == 'OTHER') {
856            p = 'otherdataname';
857        } else {
858            p = '*';
859
860            if (cacpat.indicesname == ';;') {
861                await svc.getIndices('*');
862            }
863        }
864
865        if (p == '*') {
866            let o = cacpat.stock + cacpat.indicesname + cacpat.otherdataname;
867            m = o.match(re, "gi");
868        } else {
869            m = cacpat[p].match(re, "gi");
870        }
871
872        if (m) {
873            let keys = m.map((el) => el.replace(/;/g, ""));
874
875            for (let i = 0; i < keys.length; i++) {
876                let item = keys[i].split(":");
877
878                results.push({
879                    description: item[1],
880                    exchange,
881                    full_name: item[0],
882                    symbol: item[0],
883                    ticker: item[0],
884                    // type: 'stock'
885                });
886
887                if (results.length == 50) {
888                    break;
889                }
890            }
891        }
892
893        cb(results);
894    }
895
896    resolveSymbol(symbolName, cb_onSymbolResolved, cb_onResolveError) {
897        let ctx = this;
898        let param = {
899            cmd: 'resolveSymbol',
900            symbolName
901        };
902
903        sc.SendWait(param, this.cmd, (err, data) => {
904            if (data) {
905                ctx.high = 0;
906                ctx.low = 0;
907                ctx.session = data.session;
908
909                data.visible_plots_set = data.has_no_volume;
910
911                delete data.has_no_volume;;
912
913                cb_onSymbolResolved(data);
914            } else {
915                cb_onResolveError(err);
916            }
917        });
918    }
919
920    getBars(symbolInfo, resolution, periodParams, cb_onHistory, cb_onError) {
921        let ctx = this;
922        let rbars = [];
923        let {
924            from, countBack, to, firstDataRequest
925        } = periodParams;
926        let param = {
927            cmd: 'getBars',
928            symbolInfo,
929            resolution,
930            from,
931            to,
932            firstDataRequest
933        };
934        let code = symbolInfo.name;
935
936        // logger('getBars: ', param);
937
938        if (code[0] == 'I' && code.length >= 5 && resolution == '1' && !ctx.getBarsCustom) {
939            ctx.getBarsCustom = true;
940            let sec = code.slice(1);
941            let today = moment().format('yyyy-MM-DD');
942            let param = {
943                service: 'midata',
944                cmd: 'query',
945                param: {
946                    source: 'datafeed',
947                    index: 'en_qu_general_df',
948                    args: ['TTC', '&', today, today, sec, '60', '', '', '', '', '', '', '', '', '', '', '', '']
949                }
950            };
951
952            // logger('TTC')
953
954            sc.SendWait(param, function (err, data) {
955                if (err) {
956                    if (err == 'NODATA') {
957                        cb_onHistory([], { noData: true });
958                    } else {
959                        cb_onError('NODATA');
960                    }
961                } else {
962                    if (data) {
963                        // "TTC|&|2024-08-21|11:31:00|258.594|258.79|258.257|258.363"
964                        // TTC|RefId|sdate|stime|Open|High|Low|Close
965
966                        let string = data.en_qu_general_df;
967                        let arr = string.split('|');
968                        let sdate = arr[2];
969                        let stime = arr[3];
970                        let open = +arr[4];
971                        let high = +arr[5];
972                        let low = +arr[6];
973                        let close = +arr[7];
974                        let time = moment(new Date(sdate + ' ' + stime)).unix() * 1000;
975                        let bar = {
976                            close,
977                            high,
978                            isBarClosed: false,
979                            isLastBar: true,
980                            low,
981                            open,
982                            time,
983                            volume: 0
984                        };
985
986                        if (ctx.high < bar.high) {
987                            ctx.high = bar.high;
988                        }
989
990                        if (ctx.low == 0) {
991                            ctx.low = bar.low;
992                        } else if (bar.low < ctx.low) {
993                            ctx.low = bar.low;
994                        }
995
996                        rbars.push(bar);
997                    } else if (rbars.length > 0) {
998                        cb_onHistory(rbars, {
999                            noData: rbars.length == 0
1000                        });
1001                    } else {
1002                        cb_onHistory([], { noData: false });
1003                    }
1004                }
1005            });
1006        } else {
1007            let today = new Date().setHours(0, 0, 0, 0);
1008
1009            sc.SendWait(param, this.cmd, (err, data) => {
1010                if (err) {
1011                    if (err == 'NODATA') {
1012                        cb_onHistory([], { noData: true });
1013                    } else {
1014                        cb_onError('NODATA');
1015                    }
1016                } else {
1017                    if (data) {
1018                        let bar = JSON.parse(data);
1019                        let day = new Date(bar.time).setHours(0, 0, 0, 0);
1020
1021                        if (today == day) {
1022                            if (ctx.high < bar.high) {
1023                                ctx.high = bar.high;
1024                            }
1025
1026                            if (ctx.low == 0) {
1027                                ctx.low = bar.low;
1028                            } else if (bar.low < ctx.low) {
1029                                ctx.low = bar.low;
1030                            }
1031
1032                            let date = new Date();
1033                            date.setHours(9, 0, 0, 0)
1034                            let time = Math.trunc(date.getTime());
1035
1036                            if (bar.time == time && window.prevIHSG && code == 'COMPOSITE') {
1037                                bar.open = +window.prevIHSG;
1038                                bar.close = +window.prevIHSG;
1039                            }
1040                        }
1041
1042                        rbars.push(bar);
1043                    } else if (rbars.length > 0) {
1044                        logger(code, rbars)
1045
1046                        cb_onHistory(rbars, {
1047                            noData: rbars.length == 0
1048                        });
1049                    } else {
1050                        cb_onHistory([], { noData: false });
1051                    }
1052                }
1053            });
1054        }
1055    }
1056
1057    getMarks(symbolInfo, startDate, endDate, onDataCallback, resolution) {
1058        // console.log('getMarks: ', [symbolInfo, startDate, endDate, onDataCallback, resolution]);
1059        let arr = [
1060            {
1061                id: 1,
1062                time: endDate,
1063                color: 'green',
1064                text: ['This is the mark pop-up text.'],
1065                label: 'B',
1066                minSize: 14
1067            },
1068            {
1069                id: 2,
1070                time: endDate,
1071                color: 'red',
1072                text: ['This is the mark pop-up text.'],
1073                label: 'S',
1074                minSize: 14
1075            },
1076            {
1077                id: 3,
1078                time: 1684886400000 / 1000,
1079                color: 'red',
1080                text: ['This is the mark pop-up text.'],
1081                label: 'B',
1082                minSize: 14
1083            }
1084        ];
1085
1086        // 1685491200000
1087        // 2114355600
1088
1089        // for (let i = 0; i < 3; i++) {
1090        //     arr.push({
1091        //         id: i + 1,
1092        //         time: endDate,
1093        //         color: 'red',
1094        //         text: ['This is the mark pop-up text.'],
1095        //         label: 'Se',
1096        //         minSize: 14
1097        //     })
1098        // }
1099
1100        onDataCallback(
1101            arr
1102        );
1103    };
1104
1105    subscribeBars(symbolInfo, resolution, cb_onRealtime, subscriberUID, cb_onResetCacheNeeded) {
1106        let code = symbolInfo.name;
1107        let param = {
1108            cmd: 'subscribe',
1109            service: 'mi',
1110            rtype: resolution == '15' ? 'BAR15' : 'BAR1',
1111            resolution,
1112            code,
1113            subsid: subscriberUID
1114        };
1115
1116        if (code[0] == 'I' && code.length >= 5 && resolution == 1) {
1117            let sec = getRETCode(code);
1118            let param = {
1119                cmd: 'subscribe',
1120                service: 'mi',
1121                rtype: 'ETFS',
1122                code: sec,
1123                subsid: subscriberUID + '_TV_ETF'
1124            };
1125
1126            sc.Subscribe(param, (err, res) => {
1127                if (res) {
1128                    let data = res.data.line;
1129                    let string = data.split('|');
1130                    let last_price = +string[5];
1131                    let bar = {
1132                        close: last_price,
1133                        high: last_price,
1134                        isBarClosed: false,
1135                        isLastBar: true,
1136                        low: last_price,
1137                        open: last_price,
1138                        time: moment().unix() * 1000,
1139                        volume: 0
1140                    };
1141
1142                    cb_onRealtime(bar, code);
1143                }
1144            });
1145        } else {
1146            this.subscribeLastPrice = false;
1147            sc.Subscribe(param, (err, data) => {
1148                if (data) {
1149                    let json = JSON.parse(data.data);
1150
1151                    if (resolution == 1) {
1152                        cb_onRealtime(json, code);
1153                    } else if (LASTPRICE_DATA[code]) {
1154                        let {
1155                            popen, phi, plo, price
1156                        } = LASTPRICE_DATA[code];
1157
1158                        json.close = price;
1159                        json.open = popen;
1160                        json.high = phi;
1161                        json.low = plo;
1162
1163                        cb_onRealtime(json, code);
1164                    } else if (!this.subscribeLastPrice) {
1165                        let param = {
1166                            cmd: 'lastprice',
1167                            code,
1168                            subsid: subscriberUID + '_lastprice'
1169                        };
1170
1171                        this.subscribeLastPrice = true;
1172
1173                        sc.Subscribe(param, (err, data) => {
1174                            let {
1175                                popen, phi, plo, price
1176                            } = data.data
1177
1178                            if (data) {
1179                                json.close = price;
1180                                json.open = popen;
1181                                json.high = phi;
1182                                json.low = plo;
1183
1184                                cb_onRealtime(json, code);
1185
1186                                LASTPRICE_DATA[code] = data.data;
1187                            }
1188                        });
1189                    }
1190                }
1191            });
1192        }
1193    }
1194
1195    unsubscribeBars(subscriberUID) {
1196        try {
1197            let code = subscriberUID.split('_')[0].split('.')[1];
1198
1199            if (code) {
1200                delete LASTPRICE_DATA[code];
1201            }
1202        } catch (error) {
1203
1204        }
1205
1206        sc.Unsubscribe(subscriberUID);
1207        sc.Unsubscribe(subscriberUID + '_lastprice')
1208        sc.Unsubscribe(subscriberUID + '_TV_ETF');
1209    }
1210
1211    calculateHistoryDepth(resolution, resolutionBack, intervalBack) {
1212        let r = +resolution;
1213
1214        if (!isNaN(r)) {
1215            if (r == 1) return { resolutionBack: "D", intervalBack: 1 };
1216            return { resolutionBack: "D", intervalBack: 1 };
1217        }
1218
1219        if (resolution == "D") return { resolutionBack: "M", intervalBack: 1 };
1220        if (resolution == "M") return { resolutionBack: "M", intervalBack: 1 };
1221    }
1222
1223    getServerTime(cb) {
1224        let param = {
1225            cmd: 'getServerTime'
1226        };
1227
1228        sc.SendWait(param, this.cmd, (err, data) => {
1229            if (data) {
1230                cb(data);
1231            }
1232        });
1233    }
1234}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.