vue 使用TradingView制作K线图(模仿火币)详解

特斯比特 2021-11-18 10:27:26

前言
项目需求要写K线图echarts图表实现不了里面的功能所以要用到TradingView这个真心让人头疼百度的东西也很少花了很久才实现出来了。
效果图
k线是实时更新的可以正常根据数据跳动
在这里插入图片描述

index.html 引入js和css文件

我这里是vue-cli4 vue-cli4和vue-cli2文件夹不一样
如果你是vue-cli4 里面的css和js 记得放在public文件夹里面 vue-cli2的话就是正常使用
在这里插入图片描述

创建容器

先建立一个div用来保存k线图 样式根据自己项目修改

<template>
  <div class&#61;&#34;tvContent&#34;>
    <div id&#61;&#34;tv_chart_container&#34;></div>
  </div></template><style scoped>.tvContent {
  width: 100%;
  height: 800px;
  background: #061f46;
  border: 1px solid #4390e4;
  border-radius: 5px;
  padding: 20px;
  box-sizing: border-box;}#tv_chart_container {
  width: 100%;
  height: 100%;}</style>

父组件截图

引入组件 并将需要的参数传给子组件

在这里插入图片描述

剩下的都是子组件

props希望父组件穿的值

props: {
    symbol: {
      type: String,
      required: true,
      default: &#34;BTC/USDT&#34;, //币种类型
    },
    currency_id: {
      type: Number,
      required: true,  //id
    },
  },

监听父组件传过来的类型

watch: {
    listenState: function (a, b) {
      //监听交易对
      if (a !&#61; b && b !&#61; &#34;&#34;) {
        this.widget.setSymbol(
          a,
          localStorage.getItem(&#34;tim&#34;),
          function onReadyCallback() {}
        ); //切换币种
      }
    },
    symbol: {
      handler(n) {
      //  这个地方是socket的用法 不会的请看socket那篇文章
        this.$socket.on(&#34;reconnect&#34;);
      },
      deep: true, // 深度监听父组件传过来对象变化
      immediate: true,
    },
  },

data() 里面的数据

      widget: null, //创建的实例
      symbolInfo: null, //信息
      priceScale: 100000, //价格精度
      aa: null,
      time1: null,  

创建 createWidget 函数

createWidget() {
      let _this &#61; this;
      this.$nextTick(function () {
        let widget &#61; (_this.widget &#61; new TradingView.widget({
          symbol: _this.symbol,
          interval: 1,
          debug: false,
          fullscreen: false,
          autosize: true,
          container_id: &#34;tv_chart_container&#34;,
          datafeed: _this.createFeed(),
          library_path: &#34;static/tradeview/charting_library/&#34;,
          custom_css_url: &#34;bundles/new.css&#34;,
          locale: &#34;zh&#34;,
          width: &#34;100%&#34;,
          allow_symbol_change: true,
          drawings_access: {
            type: &#34;black&#34;,
            // tools: [{name: &#34;Regression Trend&#34;}]//todo: moje
            tools: [
              { name: &#34;Trend Line&#34;, grayed: true },
              { name: &#34;Trend Angle&#34;, grayed: true },
            ], //todo: bb
          },
          disabled_features: [
            //  禁用的功能
            &#34;left_toolbar&#34;, //左侧菜单栏
            &#34;widget_logo&#34;, //底部logo
            &#34;header_saveload&#34;, //头部保存功能
            &#34;compare_symbol&#34;,
            &#34;display_market_status&#34;,
            &#34;go_to_date&#34;,
            &#34;header_chart_type&#34;, //头部类型 下面有自定义
            &#34;header_compare&#34;,
            &#34;header_interval_dialog_button&#34;,
            &#34;header_resolutions&#34;,
            &#34;header_screenshot&#34;, //图片上传
            &#34;header_symbol_search&#34;,
            &#34;header_undo_redo&#34;,
            // &#34;legend_context_menu&#34;, //显示币种名称
            &#34;show_hide_button_in_legend&#34;,
            &#34;show_interval_dialog_on_key_press&#34;,
            // &#34;symbol_info&#34;,
            &#34;timeframes_toolbar&#34;, //底部时间信息
            &#34;use_localstorage_for_settings&#34;,
            &#34;volume_force_overlay&#34;,
          ],
          enabled_features: [
            //  启用的功能备注disable_resolution_rebuild 功能用于控制当时间范围为1个月时日期刻度是否都是每个月1号
            &#34;dont_show_boolean_study_arguments&#34;,
            &#34;use_localstorage_for_settings&#34;,
            &#34;remove_library_container_border&#34;,
            &#34;save_chart_properties_to_local_storage&#34;,
            &#34;side_toolbar_in_fullscreen_mode&#34;,
            &#34;hide_last_na_study_output&#34;,
            &#34;constraint_dialogs_movement&#34;,
            &#34;legend_widget&#34;,
          ],
          charts_storage_url: &#34;http://saveload.tradingview.com&#34;,
          charts_storage_api_version: &#34;1.1&#34;,
          toolbar_bg: &#34;transparent&#34;,
          timezone: &#34;Asia/Shanghai&#34;,
          studies_overrides: {
            &#34;volume.precision&#34;: &#34;1000&#34;,
          },
          overrides: _this.overrides(),
        }));

        widget.MAStudies &#61; [];
        widget.selectedIntervalButton &#61; null;
        widget.onChartReady(function () {
          let buttonArr &#61; [
            {
              value: &#34;5&#34;,
              period: &#34;5min&#34;,
              text: &#34;5分&#34;,
              chartType: 1,
              type: &#34;5min&#34;,
            },
            {
              value: &#34;15&#34;,
              period: &#34;15min&#34;,
              text: &#34;15分&#34;,
              chartType: 1,
              type: &#34;15min&#34;,
            },
            {
              value: &#34;30&#34;,
              period: &#34;30min&#34;,
              text: &#34;30分&#34;,
              chartType: 1,
              type: &#34;30min&#34;,
            },
            {
              value: &#34;60&#34;,
              period: &#34;60min&#34;,
              text: &#34;60分&#34;,
              chartType: 1,
              type: &#34;60min&#34;,
            },
            {
              value: &#34;1D&#34;,
              period: &#34;1D&#34;,
              text: &#34;1天&#34;,
              chartType: 1,
              type: &#34;1day&#34;,
            },
            {
              value: &#34;1W&#34;,
              period: &#34;1W&#34;,
              text: &#34;1周&#34;,
              chartType: 1,
              type: &#34;1week&#34;,
            },
            {
              value: &#34;1M&#34;,
              period: &#34;1mon&#34;,
              text: &#34;1月&#34;,
              chartType: 1,
              type: &#34;1mon&#34;,
            },
          ];
          let btn &#61; {};
          let nowTime &#61; &#34;&#34;;

          buttonArr.forEach((v, i) &#61;> {
            let button &#61; widget.createButton();
            button.attr(&#34;title&#34;, v.text).addClass(&#34;my2&#34;).text(v.text);
            if (v.text &#61;&#61;&#61; &#34;5分&#34;) {
              button.css({
                color: &#34;#5786d2&#34;,
                &#34;border-bottom&#34;: &#34;1px solid #5786d2&#34;,
              });
              localStorage.setItem(&#34;tim&#34;, &#34;5&#34;);
            }
            btn &#61; button.on(&#34;click&#34;, function (e) {
              $(this).parents(&#34;.left&#34;).children().find(&#34;.my2&#34;).removeAttr(&#34;style&#34;);
              handleClick(e, v.value, v.type);
              button.css({
                color: &#34;#5786d2&#34;,
                &#34;border-bottom&#34;: &#34;1px solid #5786d2&#34;,
              });
              _this.$store.commit(&#34;upType&#34;, v.type);
              widget.chart().setChartType(v.chartType); //改变K线类型
            });
          });
          let handleClick &#61; (e, value, type) &#61;> {
            _this.setSymbol &#61; function (symbol, value) {
              gh.chart().setSymbol(symbol, value);
            };
            widget.chart().setResolution(value, function onReadyCallback() {}); //改变分辨率
            $(e.target)
              .addClass(&#34;mydate&#34;)
              .closest(&#34;div.space-single&#34;)
              .siblings(&#34;div.space-single&#34;)
              .find(&#34;div.button&#34;)
              .removeClass(&#34;mydate&#34;);
          };
        });

        _this.widget &#61; widget;
      });
    },

createWidget 函数 里面的注意事项

1. 如果你是vue-cli4 的话 library_pathcustom_css_url 的路径必须要和我的一样如果用相对路径会报错vue-cli2的话就是正常使用

在这里插入图片描述
2. 禁用的功能和启用的功能的选择 代码中用到的是一部分功能 根据我的备注 可自行删减 没有的可去文档中寻找

TradingView 中文开发文档 

在这里插入图片描述

3. 自定义导航栏周期

在这里插入图片描述
设置默认时间样式以及切换
在这里插入图片描述
创建 createFeed 函数

createFeed() {
      let this_vue &#61; this;
      let Datafeed &#61; {};

      Datafeed.DataPulseUpdater &#61; function (datafeed, updateFrequency) {
        this._datafeed &#61; datafeed;
        this._subscribers &#61; {};

        this._requestsPending &#61; 0;
        var that &#61; this;

        var update &#61; function () {
          if (that._requestsPending > 0) {
            return;
          }

          for (var listenerGUID in that._subscribers) {
            var subscriptionRecord &#61; that._subscribers[listenerGUID];
            var resolution &#61; subscriptionRecord.resolution;

            var datesRangeRight &#61; parseInt(new Date().valueOf() / 1000);

            //	BEWARE: please note we really need 2 bars, not the only last one
            //	see the explanation below. &#96;10&#96; is the &#96;large enough&#96; value to work around holidays
            var datesRangeLeft &#61;
              datesRangeRight - that.periodLengthSeconds(resolution, 10);

            that._requestsPending&#43;&#43;;

            (function (_subscriptionRecord) {
              // eslint-disable-line
              that._datafeed.getBars(
                _subscriptionRecord.symbolInfo,
                resolution,
                datesRangeLeft,
                datesRangeRight,
                function (bars) {
                  that._requestsPending--;

                  //	means the subscription was cancelled while waiting for data
                  if (!that._subscribers.hasOwnProperty(listenerGUID)) {
                    return;
                  }

                  if (bars.length &#61;&#61;&#61; 0) {
                    return;
                  }

                  var lastBar &#61; bars[bars.length - 1];
                  if (
                    !isNaN(_subscriptionRecord.lastBarTime) &&
                    lastBar.time < _subscriptionRecord.lastBarTime                  ) {
                    return;
                  }

                  var subscribers &#61; _subscriptionRecord.listeners;

                  //	BEWARE: this one isn't working when first update comes and this update makes a new bar. In this case
                  //	_subscriptionRecord.lastBarTime &#61; NaN
                  var isNewBar &#61;
                    !isNaN(_subscriptionRecord.lastBarTime) &&
                    lastBar.time > _subscriptionRecord.lastBarTime;

                  //	Pulse updating may miss some trades data (ie, if pulse period &#61; 10 secods and new bar is started 5 seconds later after the last update, the
                  //	old bar's last 5 seconds trades will be lost). Thus, at fist we should broadcast old bar updates when it's ready.
                  if (isNewBar) {
                    if (bars.length < 2) {
                      throw new Error(
                        &#34;Not enough bars in history for proper pulse update. Need at least 2.&#34;
                      );
                    }

                    var previousBar &#61; bars[bars.length - 2];
                    for (var i &#61; 0; i < subscribers.length; &#43;&#43;i) {
                      subscribers[i](previousBar);
                    }
                  }

                  _subscriptionRecord.lastBarTime &#61; lastBar.time;

                  for (var i &#61; 0; i < subscribers.length; &#43;&#43;i) {
                    subscribers[i](lastBar);
                  }
                },

                //	on error
                function () {
                  that._requestsPending--;
                }
              );
            })(subscriptionRecord);
          }
        };

        if (typeof updateFrequency !&#61; &#34;undefined&#34; && updateFrequency > 0) {
          setInterval(update, updateFrequency);
        }
      };

      Datafeed.DataPulseUpdater.prototype.periodLengthSeconds &#61; function (
        resolution,
        requiredPeriodsCount
      ) {
        var daysCount &#61; 0;
        if (resolution &#61;&#61;&#61; &#34;D&#34;) {
          daysCount &#61; requiredPeriodsCount;
        } else if (resolution &#61;&#61;&#61; &#34;M&#34;) {
          daysCount &#61; 31 * requiredPeriodsCount;
        } else if (resolution &#61;&#61;&#61; &#34;W&#34;) {
          daysCount &#61; 7 * requiredPeriodsCount;
        } else {
          daysCount &#61; (requiredPeriodsCount * resolution) / (24 * 60);
        }

        return daysCount * 24 * 60 * 60;
      };

      Datafeed.DataPulseUpdater.prototype.subscribeDataListener &#61; function (
        symbolInfo,
        resolution,
        newDataCallback,
        listenerGUID
      ) {
        this._datafeed._logMessage(&#34;Subscribing &#34; &#43; listenerGUID);

        if (!this._subscribers.hasOwnProperty(listenerGUID)) {
          this._subscribers[listenerGUID] &#61; {
            symbolInfo: symbolInfo,
            resolution: resolution,
            lastBarTime: NaN,
            listeners: [],
          };
        }

        this._subscribers[listenerGUID].listeners.push(newDataCallback);
      };

      Datafeed.DataPulseUpdater.prototype.unsubscribeDataListener &#61; function (
        listenerGUID
      ) {
        this._datafeed._logMessage(&#34;Unsubscribing &#34; &#43; listenerGUID);
        delete this._subscribers[listenerGUID];
      };

      Datafeed.Container &#61; function (updateFrequency) {
        this._configuration &#61; {
          supports_search: false,
          supports_group_request: false,
          supported_resolutions: [&#34;5&#34;, &#34;15&#34;, &#34;30&#34;, &#34;60&#34;, &#34;1D&#34;, &#34;1W&#34;, &#34;1M&#34;],
          supports_marks: true,
          supports_timescale_marks: true,
          exchanges: [&#34;gh&#34;],
        };

        this._barsPulseUpdater &#61; new Datafeed.DataPulseUpdater(
          this,
          updateFrequency || 10 * 1000
        );
        // this._quotesPulseUpdater &#61; new Datafeed.QuotesPulseUpdater(this);

        this._enableLogging &#61; true;
        this._callbacks &#61; {};

        this._initializationFinished &#61; true;
        this._fireEvent(&#34;initialized&#34;);
        this._fireEvent(&#34;configuration_ready&#34;);
      };

      Datafeed.Container.prototype._fireEvent &#61; function (event, argument) {
        if (this._callbacks.hasOwnProperty(event)) {
          var callbacksChain &#61; this._callbacks[event];
          for (var i &#61; 0; i < callbacksChain.length; &#43;&#43;i) {
            callbacksChain[i](argument);
          }

          this._callbacks[event] &#61; [];
        }
      };

      Datafeed.Container.prototype._logMessage &#61; function (message) {
        if (this._enableLogging) {
          var now &#61; new Date();
        }
      };

      Datafeed.Container.prototype.on &#61; function (event, callback) {
        if (!this._callbacks.hasOwnProperty(event)) {
          this._callbacks[event] &#61; [];
        }

        this._callbacks[event].push(callback);
        return this;
      };

      Datafeed.Container.prototype.onReady &#61; function (callback) {
        let that &#61; this;
        if (that._configuration) {
          setTimeout(function () {
            callback(that._configuration);
          }, 0);
        } else {
          this.on(&#34;configuration_ready&#34;, function () {
            callback(that._configuration);
          });
        }
      };

      Datafeed.Container.prototype.resolveSymbol &#61; function (
        symbolName,
        onSymbolResolvedCallback,
        onResolveErrorCallback
      ) {
        this._logMessage(&#34;GOWNO :: resolve symbol &#34; &#43; symbolName);
        Promise.resolve().then(() &#61;> {
          onSymbolResolvedCallback({
            name: this_vue.symbol,
            timezone: &#34;Asia/Shanghai&#34;,
            pricescale: this_vue.priceScale,
            minmov: 1, //minmov(最小波动), pricescale(价格精度), minmove2, fractional(分数)
            minmov2: 0, //这是一个神奇的数字来格式化复杂情况下的价格。
            ticker: this_vue.symbol,
            description: &#34;&#34;,
            type: &#34;bitcoin&#34;,
            volume_precision: 8,
            // &#34;exchange-traded&#34;: &#34;sdt&#34;,
            // &#34;exchange-listed&#34;: &#34;sdt&#34;,
            //现在这两个字段都为某个交易所的略称。将被显示在图表的图例中以表示此商品。目前此字段不用于其他目的。
            has_intraday: true,
            has_weekly_and_monthly: true,
            has_no_volume: false, //布尔表示商品是否拥有成交量数据。
            session: &#34;24x7&#34;,
            supported_resolutions: [&#34;5&#34;, &#34;15&#34;, &#34;30&#34;, &#34;60&#34;, &#34;1D&#34;, &#34;1W&#34;, &#34;1M&#34;],
          });
        });
      };

      //初始化数据
      Datafeed.Container.prototype.getBars &#61; async function (
        symbolInfo,
        resolution,
        rangeStartDate,
        rangeEndDate,
        onHistoryCallback,
        onErrorCallback
      ) {
        if (
          resolution.indexOf(&#34;D&#34;) &#61;&#61; -1 &&
          resolution.indexOf(&#34;W&#34;) &#61;&#61; -1 &&
          resolution.indexOf(&#34;M&#34;) &#61;&#61; -1
        ) {
          resolution &#61; resolution &#43; &#34;min&#34;;
        } else if (resolution.indexOf(&#34;W&#34;) !&#61; -1 || resolution.indexOf(&#34;M&#34;) !&#61; -1) {
          resolution &#61; resolution;
        }
        //this_vue.newTimeshar  我请求历史数据的封装方法 换成自己的
        const res &#61; await this_vue.newTimeshar({
          from: rangeStartDate,
          to: rangeEndDate,
          symbol: symbolInfo.name,
          period: resolution,
          currency_id: this_vue.currency_id,
        });

        if (res.code &#61;&#61; 1 && res.data.length > 0) {
          this_vue.$store.commit(&#34;upSma1&#34;, res.data[res.data.length - 2].sma1);
          this_vue.$store.commit(&#34;upSma2&#34;, res.data[res.data.length - 2].sma2);
          //我是实时传送数据到后台 如果用不到自己删除
          this_vue.time1 &#61; setInterval(function () {
            this_vue.$socket.emit(&#34;sub&#34;, this_vue.emitData); //触发socket连接
          }, 1000);
          //清楚计时器
          this_vue.$once(&#34;hook:beforeDestroy&#34;, () &#61;> {
            clearInterval(this_vue.time1);
          });
          res.data.forEach((item, i) &#61;> {
            item.open &#61; Number(item.open);
            item.close &#61; Number(item.close);
            item.high &#61; Number(item.high);
            item.low &#61; Number(item.low);
          });
          onHistoryCallback(res.data, { noData: false });
          onHistoryCallback([], { noData: true });
        }
        if (!res.data || res.code &#61;&#61; -1) {
          onHistoryCallback([], { noData: true });
        }
        if (res.data && res.data.length &#61;&#61; 0) {
          onHistoryCallback([], { noData: true });
        }
      };
      //实时数据
      Datafeed.Container.prototype.subscribeBars &#61; function (
        symbolInfo,
        resolution,
        onRealtimeCallback,
        listenerGUID,
        onResetCacheNeededCallback
      ) {
        this_vue.connect(onRealtimeCallback);

        //this._barsPulseUpdater.subscribeDataListener(symbolInfo, resolution, onRealtimeCallback, listenerGUID, onResetCacheNeededCallback);
      };

      Datafeed.Container.prototype.unsubscribeBars &#61; function (listenerGUID) {
        this._barsPulseUpdater.unsubscribeDataListener(listenerGUID);
      };

      return new Datafeed.Container();
    },

createFeed 函数 里面的注意事项

1. 获取历史数据

this_vue.newTimeshar是我封装的获取数据的接口 换成你自己的就可
在这里插入图片描述
在这里插入图片描述
2. 实时更新数据
this_vue.connect实时回调在这里插入图片描述

创建 overrides 函数

overrides() {
      let style &#61; {
        up: &#34;#12b886&#34;, //升
        down: &#34;#fa5252&#34;, //降
        bg: &#34;#061f46&#34;,  //背景
        grid: &#34;rgba(122, 152, 247, .2)&#34;,
        cross: &#34;#fff&#34;, //十字线
        border: &#34;rgba(122, 152, 247, .2)&#34;,
        text: &#34;rgba(122, 152, 247, .6)&#34;, //文字
        areatop: &#34;rgba(122, 152, 247, .2)&#34;,
        areadown: &#34;rgba(122, 152, 247, .2)&#34;,
        line: &#34;rgba(122, 152, 247, .2)&#34;,
      };
      return {
        volumePaneSize: &#34;medium&#34;, //large, medium, small, tiny
        &#34;paneProperties.topMargin&#34;: &#34;20&#34;,
        &#34;scalesProperties.lineColor&#34;: style.text,
        &#34;scalesProperties.textColor&#34;: style.text,
        &#34;paneProperties.background&#34;: style.bg, //改变背景色的重要代码
        &#34;paneProperties.vertGridProperties.color&#34;: style.grid,
        &#34;paneProperties.horzGridProperties.color&#34;: style.grid,
        &#34;paneProperties.crossHairProperties.color&#34;: style.cross,
        &#34;paneProperties.crossHairProperties.lineType&#34;: 2,
        &#34;paneProperties.legendProperties.showLegend&#34;: true,
        &#34;paneProperties.legendProperties.showStudyArguments&#34;: true,
        &#34;paneProperties.legendProperties.showStudyTitles&#34;: true,
        &#34;paneProperties.legendProperties.showStudyValues&#34;: true,
        &#34;paneProperties.legendProperties.showSeriesTitle&#34;: true,
        &#34;paneProperties.legendProperties.showSeriesOHLC&#34;: true,
        &#34;mainSeriesProperties.candleStyle.upColor&#34;: style.up,
        &#34;mainSeriesProperties.candleStyle.downColor&#34;: style.down,
        &#34;mainSeriesProperties.candleStyle.drawWick&#34;: true,
        &#34;mainSeriesProperties.candleStyle.drawBorder&#34;: true,
        &#34;mainSeriesProperties.candleStyle.borderColor&#34;: style.border,
        &#34;mainSeriesProperties.candleStyle.borderUpColor&#34;: style.up,
        &#34;mainSeriesProperties.candleStyle.borderDownColor&#34;: style.down,
        &#34;mainSeriesProperties.candleStyle.wickUpColor&#34;: style.up,
        &#34;mainSeriesProperties.candleStyle.wickDownColor&#34;: style.down,
        &#34;mainSeriesProperties.candleStyle.barColorsOnPrevClose&#34;: false,
        &#34;mainSeriesProperties.hollowCandleStyle.upColor&#34;: style.up,
        &#34;mainSeriesProperties.hollowCandleStyle.downColor&#34;: style.down,

        &#34;mainSeriesProperties.hollowCandleStyle.drawWick&#34;: true,
        &#34;mainSeriesProperties.hollowCandleStyle.drawBorder&#34;: true,
        &#34;mainSeriesProperties.hollowCandleStyle.borderColor&#34;: style.border,
        &#34;mainSeriesProperties.hollowCandleStyle.borderUpColor&#34;: style.up,
        &#34;mainSeriesProperties.hollowCandleStyle.borderDownColor&#34;: style.down,
        &#34;mainSeriesProperties.hollowCandleStyle.wickColor&#34;: style.line,
        &#34;mainSeriesProperties.haStyle.upColor&#34;: style.up,
        &#34;mainSeriesProperties.haStyle.downColor&#34;: style.down,
        &#34;mainSeriesProperties.haStyle.drawWick&#34;: true,
        &#34;mainSeriesProperties.haStyle.drawBorder&#34;: true,
        &#34;mainSeriesProperties.haStyle.borderColor&#34;: style.border,
        &#34;mainSeriesProperties.haStyle.borderUpColor&#34;: style.up,
        &#34;mainSeriesProperties.haStyle.borderDownColor&#34;: style.down,
        &#34;mainSeriesProperties.haStyle.wickColor&#34;: style.border,
        &#34;mainSeriesProperties.haStyle.barColorsOnPrevClose&#34;: false,
        &#34;mainSeriesProperties.barStyle.upColor&#34;: style.up,
        &#34;mainSeriesProperties.barStyle.downColor&#34;: style.down,
        &#34;mainSeriesProperties.barStyle.barColorsOnPrevClose&#34;: false,
        &#34;mainSeriesProperties.barStyle.dontDrawOpen&#34;: false,
        &#34;mainSeriesProperties.lineStyle.color&#34;: style.border,
        &#34;mainSeriesProperties.lineStyle.linewidth&#34;: 2,
        &#34;mainSeriesProperties.lineStyle.styleType&#34;: 2,
        &#34;mainSeriesProperties.lineStyle.linestyle&#34;: 2,
        &#34;mainSeriesProperties.lineStyle.priceSource&#34;: &#34;close&#34;,
        &#34;mainSeriesProperties.areaStyle.color1&#34;: style.areatop,
        &#34;mainSeriesProperties.areaStyle.color2&#34;: style.areadown,
        &#34;mainSeriesProperties.areaStyle.linecolor&#34;: style.border,
        &#34;mainSeriesProperties.areaStyle.linewidth&#34;: 2,
        &#34;mainSeriesProperties.areaStyle.linestyle&#34;: 2,
        &#34;mainSeriesProperties.areaStyle.priceSource&#34;: &#34;close&#34;,
      };
    },

overrides 函数 里面的注意事项

颜色根据自己的项目进行修改 其他样式参考中文文档


在这里插入图片描述

tv全部完整代码
我里面用的是socket.io连接的后台进行的实时对接数据
如果你是用的其他方法直接把socket.io里面的东西替换就行

<template>
  <div class&#61;&#34;tvContent&#34;>
    <div id&#61;&#34;tv_chart_container&#34;></div>
  </div></template><style scoped>.tvContent {
  width: 100%;
  height: 800px;
  background: #061f46;
  border: 1px solid #4390e4;
  border-radius: 5px;
  padding: 20px;
  box-sizing: border-box;}#tv_chart_container {
  width: 100%;
  height: 100%;}</style><script>import { mapActions } from &#34;vuex&#34;;export default {
  name: &#34;tv&#34;,
  props: {
    symbol: {
      type: String,
      required: true,
      default: &#34;BTC/USDT&#34;,
    },
    currency_id: {
      type: Number,
      required: true,
    },
  },
  data() {
    return {
      widget: null, //创建的实例
      symbolInfo: null, //信息
      priceScale: 100000, //价格精度
      aa: null,
      time1: null, 
    };
  },
  // 我使用的socket
  sockets: {
    //查看socket是否渲染成功
    connect() {},
    disconnect() {
      console.log(&#34;断开链接&#34;);
    }, //检测socket断开链接
    reconnect() {
      console.log(&#34;重新链接&#34;);
      // this.$socket.emit(&#34;connection&#34;, 1);
      this.$socket.open();
    },
    //客户端接收后台传输的socket事件
    kline: function (msg) {
      let obj &#61; {};
      var that &#61; this;
      let type &#61; that.$store.state.type;

      if (that.symbol &#61;&#61; msg.symbol && msg.period &#61;&#61; type) {
        obj.open &#61; Number(msg.open);
        obj.low &#61; Number(msg.low);
        obj.high &#61; Number(msg.high);
        obj.close &#61; Number(msg.close);
        obj.volume &#61; Number(msg.volume);
        obj.time &#61; Number(msg.time);
        if (that.$store.state.nextId !&#61; msg.id) {
          that.$store.commit(&#34;upId&#34;, msg.id);
          that.$store.commit(&#34;upSma1&#34;, msg.sma1);
          that.$store.commit(&#34;upSma2&#34;, msg.sma2);
        }

        this.aa && this.aa(obj);
      }
    },
  },
  computed: {
    listenState() {
      //监听交易对
      return this.symbol;
    },
    kind() {
      return this.symbol.split(&#34;/&#34;)[0].toLowerCase();
    },
    // 我传给后台的东西 自己进行删减
    emitData() {
      return (
        this.kind &#43;
        &#34;-&#34; &#43;
        this.$store.state.type &#43;
        &#34;-&#34; &#43;
        this.$store.state.sma1 &#43;
        &#34;-&#34; &#43;
        this.$store.state.sma2      );
    },
  },
  watch: {
    listenState: function (a, b) {
      //监听交易对
      if (a !&#61; b && b !&#61; &#34;&#34;) {
        this.widget.setSymbol(
          a,
          localStorage.getItem(&#34;tim&#34;),
          function onReadyCallback() {}
        ); //切换币种
      }
    },
    symbol: {
      handler(n) {
        this.$socket.on(&#34;reconnect&#34;);
      },
      deep: true, // 深度监听父组件传过来对象变化
      immediate: true,
    },
  },
  mounted() {
    this.createWidget();
  },
  destroyed() {
    this.removeWidget();
  },

  methods: {
    ...mapActions({
      newTimeshar: &#34;home/newTimeshar&#34;,
    }),
    connect(real) {
      this.aa &#61; real;
      let that &#61; this;
      //实时数据进行回调链接socket
      this.$socket.on(&#34;connect&#34;, function () {
        this.$socket.on(&#34;kline&#34;, (msg) &#61;> {
          let obj &#61; {};
          let type &#61; that.$store.state.type;
          if (that.symbol &#61;&#61; msg.symbol && msg.period &#61;&#61; type) {
            obj.open &#61; Number(msg.open);
            obj.low &#61; Number(msg.low);
            obj.high &#61; Number(msg.high);
            obj.close &#61; Number(msg.close);
            obj.volume &#61; Number(msg.volume);
            obj.time &#61; Number(msg.time);
            if (that.$store.state.nextId !&#61; msg.id) {
              that.$store.commit(&#34;upId&#34;, msg.id);
              that.$store.commit(&#34;upSma1&#34;, msg.sma1);
              that.$store.commit(&#34;upSma2&#34;, msg.sma2);
            }

            real(obj);
          }
        });
      });
    },
    createWidget() {
      let _this &#61; this;
      this.$nextTick(function () {
        let widget &#61; (_this.widget &#61; new TradingView.widget({
          symbol: _this.symbol,
          interval: 1,
          debug: false,
          fullscreen: false,
          autosize: true,
          container_id: &#34;tv_chart_container&#34;,
          // datafeed: new Datafeeds.UDFCompatibleDatafeed(
          //   &#34;http://demo_feed.tradingview.com&#34;
          // ),
          datafeed: _this.createFeed(),
          library_path: &#34;static/tradeview/charting_library/&#34;,
          custom_css_url: &#34;bundles/new.css&#34;,
          locale: &#34;zh&#34;,
          width: &#34;100%&#34;,
          allow_symbol_change: true,
          drawings_access: {
            type: &#34;black&#34;,
            // tools: [{name: &#34;Regression Trend&#34;}]//todo: moje
            tools: [
              { name: &#34;Trend Line&#34;, grayed: true },
              { name: &#34;Trend Angle&#34;, grayed: true },
            ], //todo: bb
          },
          disabled_features: [
            //  禁用的功能
            // &#34;left_toolbar&#34;, //左侧菜单栏
            &#34;widget_logo&#34;, //底部logo
            &#34;header_saveload&#34;, //头部保存功能
            &#34;compare_symbol&#34;,
            &#34;display_market_status&#34;,
            &#34;go_to_date&#34;,
            &#34;header_chart_type&#34;, //头部类型 下面有自定义
            &#34;header_compare&#34;,
            &#34;header_interval_dialog_button&#34;,
            &#34;header_resolutions&#34;,
            &#34;header_screenshot&#34;, //图片上传
            &#34;header_symbol_search&#34;,
            &#34;header_undo_redo&#34;,
            // &#34;legend_context_menu&#34;, //显示币种名称
            &#34;show_hide_button_in_legend&#34;,
            &#34;show_interval_dialog_on_key_press&#34;,
            // &#34;symbol_info&#34;,
            &#34;timeframes_toolbar&#34;, //底部时间信息
            &#34;use_localstorage_for_settings&#34;,
            &#34;volume_force_overlay&#34;,
          ],
          enabled_features: [
            //  启用的功能备注disable_resolution_rebuild 功能用于控制当时间范围为1个月时日期刻度是否都是每个月1号
            &#34;dont_show_boolean_study_arguments&#34;,
            &#34;use_localstorage_for_settings&#34;,
            &#34;remove_library_container_border&#34;,
            &#34;save_chart_properties_to_local_storage&#34;,
            &#34;side_toolbar_in_fullscreen_mode&#34;,
            &#34;hide_last_na_study_output&#34;,
            &#34;constraint_dialogs_movement&#34;,
            &#34;legend_widget&#34;,
          ],
          charts_storage_url: &#34;http://saveload.tradingview.com&#34;,
          charts_storage_api_version: &#34;1.1&#34;,
          toolbar_bg: &#34;transparent&#34;,
          timezone: &#34;Asia/Shanghai&#34;,
          studies_overrides: {
            &#34;volume.precision&#34;: &#34;1000&#34;,
          },
          overrides: _this.overrides(),
        }));

        widget.MAStudies &#61; [];
        widget.selectedIntervalButton &#61; null;
        widget.onChartReady(function () {
          let buttonArr &#61; [
            {
              value: &#34;1&#34;,
              period: &#34;1min&#34;,
              text: &#34;1分&#34;,
              chartType: 1,
              type: &#34;1min&#34;,
            },
            {
              value: &#34;5&#34;,
              period: &#34;5min&#34;,
              text: &#34;5分&#34;,
              chartType: 1,
              type: &#34;5min&#34;,
            },
            {
              value: &#34;30&#34;,
              period: &#34;30min&#34;,
              text: &#34;30分&#34;,
              chartType: 1,
              type: &#34;30min&#34;,
            },
            {
              value: &#34;60&#34;,
              period: &#34;60min&#34;,
              text: &#34;60分&#34;,
              chartType: 1,
              type: &#34;60min&#34;,
            },
            {
              value: &#34;1D&#34;,
              period: &#34;1D&#34;,
              text: &#34;1天&#34;,
              chartType: 1,
              type: &#34;1day&#34;,
            },
            {
              value: &#34;1W&#34;,
              period: &#34;1W&#34;,
              text: &#34;1周&#34;,
              chartType: 1,
              type: &#34;1week&#34;,
            },
            {
              value: &#34;1M&#34;,
              period: &#34;1mon&#34;,
              text: &#34;1月&#34;,
              chartType: 1,
              type: &#34;1mon&#34;,
            },
          ];
          let btn &#61; {};
          let nowTime &#61; &#34;&#34;;

          buttonArr.forEach((v, i) &#61;> {
            let button &#61; widget.createButton();
            button.attr(&#34;title&#34;, v.text).addClass(&#34;my2&#34;).text(v.text);
            if (v.text &#61;&#61;&#61; &#34;5分&#34;) {
              button.css({
                color: &#34;#5786d2&#34;,
                &#34;border-bottom&#34;: &#34;1px solid #5786d2&#34;,
              });
              localStorage.setItem(&#34;tim&#34;, &#34;5&#34;);
            }
            btn &#61; button.on(&#34;click&#34;, function (e) {
              $(this).parents(&#34;.left&#34;).children().find(&#34;.my2&#34;).removeAttr(&#34;style&#34;);
              handleClick(e, v.value, v.type);
              button.css({
                color: &#34;#5786d2&#34;,
                &#34;border-bottom&#34;: &#34;1px solid #5786d2&#34;,
              });
              _this.$store.commit(&#34;upType&#34;, v.type);
              widget.chart().setChartType(v.chartType); //改变K线类型
            });
          });
          let handleClick &#61; (e, value, type) &#61;> {
            _this.setSymbol &#61; function (symbol, value) {
              gh.chart().setSymbol(symbol, value);
            };
            widget.chart().setResolution(value, function onReadyCallback() {}); //改变分辨率
            $(e.target)
              .addClass(&#34;mydate&#34;)
              .closest(&#34;div.space-single&#34;)
              .siblings(&#34;div.space-single&#34;)
              .find(&#34;div.button&#34;)
              .removeClass(&#34;mydate&#34;);
          };
        });

        _this.widget &#61; widget;
      });
    },
    createFeed() {
      let this_vue &#61; this;
      let Datafeed &#61; {};

      Datafeed.DataPulseUpdater &#61; function (datafeed, updateFrequency) {
        this._datafeed &#61; datafeed;
        this._subscribers &#61; {};

        this._requestsPending &#61; 0;
        var that &#61; this;

        var update &#61; function () {
          if (that._requestsPending > 0) {
            return;
          }

          for (var listenerGUID in that._subscribers) {
            var subscriptionRecord &#61; that._subscribers[listenerGUID];
            var resolution &#61; subscriptionRecord.resolution;

            var datesRangeRight &#61; parseInt(new Date().valueOf() / 1000);

            //	BEWARE: please note we really need 2 bars, not the only last one
            //	see the explanation below. &#96;10&#96; is the &#96;large enough&#96; value to work around holidays
            var datesRangeLeft &#61;
              datesRangeRight - that.periodLengthSeconds(resolution, 10);

            that._requestsPending&#43;&#43;;

            (function (_subscriptionRecord) {
              // eslint-disable-line
              that._datafeed.getBars(
                _subscriptionRecord.symbolInfo,
                resolution,
                datesRangeLeft,
                datesRangeRight,
                function (bars) {
                  that._requestsPending--;

                  //	means the subscription was cancelled while waiting for data
                  if (!that._subscribers.hasOwnProperty(listenerGUID)) {
                    return;
                  }

                  if (bars.length &#61;&#61;&#61; 0) {
                    return;
                  }

                  var lastBar &#61; bars[bars.length - 1];
                  if (
                    !isNaN(_subscriptionRecord.lastBarTime) &&
                    lastBar.time < _subscriptionRecord.lastBarTime                  ) {
                    return;
                  }

                  var subscribers &#61; _subscriptionRecord.listeners;

                  //	BEWARE: this one isn't working when first update comes and this update makes a new bar. In this case
                  //	_subscriptionRecord.lastBarTime &#61; NaN
                  var isNewBar &#61;
                    !isNaN(_subscriptionRecord.lastBarTime) &&
                    lastBar.time > _subscriptionRecord.lastBarTime;

                  //	Pulse updating may miss some trades data (ie, if pulse period &#61; 10 secods and new bar is started 5 seconds later after the last update, the
                  //	old bar's last 5 seconds trades will be lost). Thus, at fist we should broadcast old bar updates when it's ready.
                  if (isNewBar) {
                    if (bars.length < 2) {
                      throw new Error(
                        &#34;Not enough bars in history for proper pulse update. Need at least 2.&#34;
                      );
                    }

                    var previousBar &#61; bars[bars.length - 2];
                    for (var i &#61; 0; i < subscribers.length; &#43;&#43;i) {
                      subscribers[i](previousBar);
                    }
                  }

                  _subscriptionRecord.lastBarTime &#61; lastBar.time;

                  for (var i &#61; 0; i < subscribers.length; &#43;&#43;i) {
                    subscribers[i](lastBar);
                  }
                },

                //	on error
                function () {
                  that._requestsPending--;
                }
              );
            })(subscriptionRecord);
          }
        };

        if (typeof updateFrequency !&#61; &#34;undefined&#34; && updateFrequency > 0) {
          setInterval(update, updateFrequency);
        }
      };

      Datafeed.DataPulseUpdater.prototype.periodLengthSeconds &#61; function (
        resolution,
        requiredPeriodsCount
      ) {
        var daysCount &#61; 0;
        if (resolution &#61;&#61;&#61; &#34;D&#34;) {
          daysCount &#61; requiredPeriodsCount;
        } else if (resolution &#61;&#61;&#61; &#34;M&#34;) {
          daysCount &#61; 31 * requiredPeriodsCount;
        } else if (resolution &#61;&#61;&#61; &#34;W&#34;) {
          daysCount &#61; 7 * requiredPeriodsCount;
        } else {
          daysCount &#61; (requiredPeriodsCount * resolution) / (24 * 60);
        }

        return daysCount * 24 * 60 * 60;
      };

      Datafeed.DataPulseUpdater.prototype.subscribeDataListener &#61; function (
        symbolInfo,
        resolution,
        newDataCallback,
        listenerGUID
      ) {
        this._datafeed._logMessage(&#34;Subscribing &#34; &#43; listenerGUID);

        if (!this._subscribers.hasOwnProperty(listenerGUID)) {
          this._subscribers[listenerGUID] &#61; {
            symbolInfo: symbolInfo,
            resolution: resolution,
            lastBarTime: NaN,
            listeners: [],
          };
        }

        this._subscribers[listenerGUID].listeners.push(newDataCallback);
      };

      Datafeed.DataPulseUpdater.prototype.unsubscribeDataListener &#61; function (
        listenerGUID
      ) {
        this._datafeed._logMessage(&#34;Unsubscribing &#34; &#43; listenerGUID);
        delete this._subscribers[listenerGUID];
      };

      Datafeed.Container &#61; function (updateFrequency) {
        this._configuration &#61; {
          supports_search: false,
          supports_group_request: false,
          supported_resolutions: [&#34;5&#34;, &#34;15&#34;, &#34;30&#34;, &#34;60&#34;, &#34;1D&#34;, &#34;1W&#34;, &#34;1M&#34;],
          supports_marks: true,
          supports_timescale_marks: true,
          exchanges: [&#34;gh&#34;],
        };

        this._barsPulseUpdater &#61; new Datafeed.DataPulseUpdater(
          this,
          updateFrequency || 10 * 1000
        );
        // this._quotesPulseUpdater &#61; new Datafeed.QuotesPulseUpdater(this);

        this._enableLogging &#61; true;
        this._callbacks &#61; {};

        this._initializationFinished &#61; true;
        this._fireEvent(&#34;initialized&#34;);
        this._fireEvent(&#34;configuration_ready&#34;);
      };

      Datafeed.Container.prototype._fireEvent &#61; function (event, argument) {
        if (this._callbacks.hasOwnProperty(event)) {
          var callbacksChain &#61; this._callbacks[event];
          for (var i &#61; 0; i < callbacksChain.length; &#43;&#43;i) {
            callbacksChain[i](argument);
          }

          this._callbacks[event] &#61; [];
        }
      };

      Datafeed.Container.prototype._logMessage &#61; function (message) {
        if (this._enableLogging) {
          var now &#61; new Date();
        }
      };

      Datafeed.Container.prototype.on &#61; function (event, callback) {
        if (!this._callbacks.hasOwnProperty(event)) {
          this._callbacks[event] &#61; [];
        }

        this._callbacks[event].push(callback);
        return this;
      };

      Datafeed.Container.prototype.onReady &#61; function (callback) {
        let that &#61; this;
        if (that._configuration) {
          setTimeout(function () {
            callback(that._configuration);
          }, 0);
        } else {
          this.on(&#34;configuration_ready&#34;, function () {
            callback(that._configuration);
          });
        }
      };

      Datafeed.Container.prototype.resolveSymbol &#61; function (
        symbolName,
        onSymbolResolvedCallback,
        onResolveErrorCallback
      ) {
        this._logMessage(&#34;GOWNO :: resolve symbol &#34; &#43; symbolName);
        Promise.resolve().then(() &#61;> {
          onSymbolResolvedCallback({
            name: this_vue.symbol,
            timezone: &#34;Asia/Shanghai&#34;,
            pricescale: this_vue.priceScale,
            minmov: 1, //minmov(最小波动), pricescale(价格精度), minmove2, fractional(分数)
            minmov2: 0, //这是一个神奇的数字来格式化复杂情况下的价格。
            ticker: this_vue.symbol,
            description: &#34;&#34;,
            type: &#34;bitcoin&#34;,
            volume_precision: 8,
            // &#34;exchange-traded&#34;: &#34;sdt&#34;,
            // &#34;exchange-listed&#34;: &#34;sdt&#34;,
            //现在这两个字段都为某个交易所的略称。将被显示在图表的图例中以表示此商品。目前此字段不用于其他目的。
            has_intraday: true,
            has_weekly_and_monthly: true,
            has_no_volume: false, //布尔表示商品是否拥有成交量数据。
            session: &#34;24x7&#34;,
            supported_resolutions: [&#34;5&#34;, &#34;15&#34;, &#34;30&#34;, &#34;60&#34;, &#34;1D&#34;, &#34;1W&#34;, &#34;1M&#34;],
          });
        });
      };

      //初始化数据
      Datafeed.Container.prototype.getBars &#61; async function (
        symbolInfo,
        resolution,
        rangeStartDate,
        rangeEndDate,
        onHistoryCallback,
        onErrorCallback
      ) {
        if (
          resolution.indexOf(&#34;D&#34;) &#61;&#61; -1 &&
          resolution.indexOf(&#34;W&#34;) &#61;&#61; -1 &&
          resolution.indexOf(&#34;M&#34;) &#61;&#61; -1
        ) {
          resolution &#61; resolution &#43; &#34;min&#34;;
        } else if (resolution.indexOf(&#34;W&#34;) !&#61; -1 || resolution.indexOf(&#34;M&#34;) !&#61; -1) {
          resolution &#61; resolution;
        }

        //this_vue.newTimeshar  我请求历史数据的封装方法 换成自己的
        const res &#61; await this_vue.newTimeshar({
          from: rangeStartDate,
          to: rangeEndDate,
          symbol: symbolInfo.name,
          period: resolution,
          currency_id: this_vue.currency_id,
        });

        if (res.code &#61;&#61; 1 && res.data.length > 0) {
          this_vue.$store.commit(&#34;upSma1&#34;, res.data[res.data.length - 2].sma1);
          this_vue.$store.commit(&#34;upSma2&#34;, res.data[res.data.length - 2].sma2);
          //我是实时传送数据到后台 如果用不到自己删除
          this_vue.time1 &#61; setInterval(function () {
            this_vue.$socket.emit(&#34;sub&#34;, this_vue.emitData); //触发socket连接
          }, 1000);
          //清楚计时器
          this_vue.$once(&#34;hook:beforeDestroy&#34;, () &#61;> {
            clearInterval(this_vue.time1);
          });
          res.data.forEach((item, i) &#61;> {
            item.open &#61; Number(item.open);
            item.close &#61; Number(item.close);
            item.high &#61; Number(item.high);
            item.low &#61; Number(item.low);
          });
          onHistoryCallback(res.data, { noData: false });
          onHistoryCallback([], { noData: true });
        }
        if (!res.data || res.code &#61;&#61; -1) {
          onHistoryCallback([], { noData: true });
        }
        if (res.data && res.data.length &#61;&#61; 0) {
          onHistoryCallback([], { noData: true });
        }
      };
      //实时数据
      Datafeed.Container.prototype.subscribeBars &#61; function (
        symbolInfo,
        resolution,
        onRealtimeCallback,
        listenerGUID,
        onResetCacheNeededCallback
      ) {
        this_vue.connect(onRealtimeCallback);

        //this._barsPulseUpdater.subscribeDataListener(symbolInfo, resolution, onRealtimeCallback, listenerGUID, onResetCacheNeededCallback);
      };

      Datafeed.Container.prototype.unsubscribeBars &#61; function (listenerGUID) {
        this._barsPulseUpdater.unsubscribeDataListener(listenerGUID);
      };

      return new Datafeed.Container();
    },

    updateData(data) {
      if (data) {
        this.$emit(&#34;real-time&#34;, data);
      }
    },

    updateWidget(item) {
      this.symbolInfo &#61; {
        name: item,
        ticker: item,
        description: &#34;&#34;,
        session: &#34;24x7&#34;,
        supported_resolutions: [&#34;5&#34;, &#34;15&#34;, &#34;30&#34;, &#34;60&#34;, &#34;1D&#34;, &#34;1W&#34;, &#34;1M&#34;],
        has_intraday: true,
        has_daily: true,
        has_weekly_and_monthly: true,
        timezone: &#34;UTC&#34;,
      };

      this.removeWidget();
      this.createWidget();
    },
    removeWidget() {
      if (this.widget) {
        this.widget.remove();
        this.widget &#61; null;
      }
    },
    overrides() {
      let style &#61; {
        up: &#34;#12b886&#34;, //升
        down: &#34;#fa5252&#34;, //降
        bg: &#34;#061f46&#34;,  //背景
        grid: &#34;rgba(122, 152, 247, .2)&#34;,
        cross: &#34;#fff&#34;, //十字线
        border: &#34;rgba(122, 152, 247, .2)&#34;,
        text: &#34;rgba(122, 152, 247, .6)&#34;, //文字
        areatop: &#34;rgba(122, 152, 247, .2)&#34;,
        areadown: &#34;rgba(122, 152, 247, .2)&#34;,
        line: &#34;rgba(122, 152, 247, .2)&#34;,
      };
      return {
        volumePaneSize: &#34;medium&#34;, //large, medium, small, tiny
        &#34;paneProperties.topMargin&#34;: &#34;20&#34;,
        &#34;scalesProperties.lineColor&#34;: style.text,
        &#34;scalesProperties.textColor&#34;: style.text,
        &#34;paneProperties.background&#34;: style.bg, //改变背景色的重要代码
        &#34;paneProperties.vertGridProperties.color&#34;: style.grid,
        &#34;paneProperties.horzGridProperties.color&#34;: style.grid,
        &#34;paneProperties.crossHairProperties.color&#34;: style.cross,
        &#34;paneProperties.crossHairProperties.lineType&#34;: 2,
        &#34;paneProperties.legendProperties.showLegend&#34;: true,
        &#34;paneProperties.legendProperties.showStudyArguments&#34;: true,
        &#34;paneProperties.legendProperties.showStudyTitles&#34;: true,
        &#34;paneProperties.legendProperties.showStudyValues&#34;: true,
        &#34;paneProperties.legendProperties.showSeriesTitle&#34;: true,
        &#34;paneProperties.legendProperties.showSeriesOHLC&#34;: true,
        &#34;mainSeriesProperties.candleStyle.upColor&#34;: style.up,
        &#34;mainSeriesProperties.candleStyle.downColor&#34;: style.down,
        &#34;mainSeriesProperties.candleStyle.drawWick&#34;: true,
        &#34;mainSeriesProperties.candleStyle.drawBorder&#34;: true,
        &#34;mainSeriesProperties.candleStyle.borderColor&#34;: style.border,
        &#34;mainSeriesProperties.candleStyle.borderUpColor&#34;: style.up,
        &#34;mainSeriesProperties.candleStyle.borderDownColor&#34;: style.down,
        &#34;mainSeriesProperties.candleStyle.wickUpColor&#34;: style.up,
        &#34;mainSeriesProperties.candleStyle.wickDownColor&#34;: style.down,
        &#34;mainSeriesProperties.candleStyle.barColorsOnPrevClose&#34;: false,
        &#34;mainSeriesProperties.hollowCandleStyle.upColor&#34;: style.up,
        &#34;mainSeriesProperties.hollowCandleStyle.downColor&#34;: style.down,

        &#34;mainSeriesProperties.hollowCandleStyle.drawWick&#34;: true,
        &#34;mainSeriesProperties.hollowCandleStyle.drawBorder&#34;: true,
        &#34;mainSeriesProperties.hollowCandleStyle.borderColor&#34;: style.border,
        &#34;mainSeriesProperties.hollowCandleStyle.borderUpColor&#34;: style.up,
        &#34;mainSeriesProperties.hollowCandleStyle.borderDownColor&#34;: style.down,
        &#34;mainSeriesProperties.hollowCandleStyle.wickColor&#34;: style.line,
        &#34;mainSeriesProperties.haStyle.upColor&#34;: style.up,
        &#34;mainSeriesProperties.haStyle.downColor&#34;: style.down,
        &#34;mainSeriesProperties.haStyle.drawWick&#34;: true,
        &#34;mainSeriesProperties.haStyle.drawBorder&#34;: true,
        &#34;mainSeriesProperties.haStyle.borderColor&#34;: style.border,
        &#34;mainSeriesProperties.haStyle.borderUpColor&#34;: style.up,
        &#34;mainSeriesProperties.haStyle.borderDownColor&#34;: style.down,
        &#34;mainSeriesProperties.haStyle.wickColor&#34;: style.border,
        &#34;mainSeriesProperties.haStyle.barColorsOnPrevClose&#34;: false,
        &#34;mainSeriesProperties.barStyle.upColor&#34;: style.up,
        &#34;mainSeriesProperties.barStyle.downColor&#34;: style.down,
        &#34;mainSeriesProperties.barStyle.barColorsOnPrevClose&#34;: false,
        &#34;mainSeriesProperties.barStyle.dontDrawOpen&#34;: false,
        &#34;mainSeriesProperties.lineStyle.color&#34;: style.border,
        &#34;mainSeriesProperties.lineStyle.linewidth&#34;: 2,
        &#34;mainSeriesProperties.lineStyle.styleType&#34;: 2,
        &#34;mainSeriesProperties.lineStyle.linestyle&#34;: 2,
        &#34;mainSeriesProperties.lineStyle.priceSource&#34;: &#34;close&#34;,
        &#34;mainSeriesProperties.areaStyle.color1&#34;: style.areatop,
        &#34;mainSeriesProperties.areaStyle.color2&#34;: style.areadown,
        &#34;mainSeriesProperties.areaStyle.linecolor&#34;: style.border,
        &#34;mainSeriesProperties.areaStyle.linewidth&#34;: 2,
        &#34;mainSeriesProperties.areaStyle.linestyle&#34;: 2,
        &#34;mainSeriesProperties.areaStyle.priceSource&#34;: &#34;close&#34;,
      };
    },
  },};</script>
声明:本文内容不代表斑马投诉网站观点,内容仅供参考,不构成投资建议。投资有风险,选择需谨慎! 如涉及内容、版权等问题,请联系我们,我们会在第一时间作出调整!

相关文章