本篇教程写的是tradingview图表的数据接入,关于初始化在第一篇教程

第一篇:传送门

根据官方文档,datafeed这个文件中便是一些数据处理,根据api,我对这个文件进行了一些处理,将一些一般用不到的网络请求都修改或删除了(没删干净,有冗余,哈哈哈),保留了关于数据的一部分(不影响使用,切换商品,切换周期都正常)

根据我的研究,其实关于数据和显示的基本都集中在getBars和resolveSymbol中

  • resolveSymbol是关于一些配置的

  • getbar是关于数据的

  • _send方法是关于请求的(如果想要使用axios,请先导入axios,参考axios教程,和main.js导入一样)

下面把我的datafeeed贴出来:

function parseJSONorNot(mayBeJSON) {
  if (typeof mayBeJSON === 'string') {
    return JSON.parse(mayBeJSON);
  } else {
    return mayBeJSON;
  }
}

let Datafeeds = {};

Datafeeds.UDFCompatibleDatafeed = function (updateURL, updateFrequency) {
  this._updateURL = updateURL;
  this._configuration = undefined;

  this._barsPulseUpdater = new Datafeeds.DataPulseUpdater(this, updateFrequency || 10 * 1000);

  this._enableLogging = false;
  this._initializationFinished = false;
  this._callbacks = {};

  this._initialize();
};

Datafeeds.UDFCompatibleDatafeed.prototype.defaultConfiguration = function () {
  return {
    supports_search: false,
    supports_group_request: true,
    supported_resolutions: ['1', '5', '15', '30', '60', '240', '1D', '7D', '1W', '1M'],
    supports_marks: false,
    supports_timescale_marks: false
  };
};

Datafeeds.UDFCompatibleDatafeed.prototype.on = function (event, callback) {
  if (!this._callbacks.hasOwnProperty(event)) {
    this._callbacks[event] = [];
  }

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

Datafeeds.UDFCompatibleDatafeed.prototype._fireEvent = function (event, argument) {
  if (this._callbacks.hasOwnProperty(event)) {
    let callbacksChain = this._callbacks[event];
    for (let i = 0; i < callbacksChain.length; ++i) {
      callbacksChain[i](argument);
    }

    this._callbacks[event] = [];
  }
};

Datafeeds.UDFCompatibleDatafeed.prototype.onInitialized = function () {
  this._initializationFinished = true;
  this._fireEvent('initialized');
};

Datafeeds.UDFCompatibleDatafeed.prototype._logMessage = function (message) {
  if (this._enableLogging) {
    let now = new Date();
    console.log(now.toLocaleTimeString() + '.' + now.getMilliseconds() + '> ' + message);
  }
};

Datafeeds.UDFCompatibleDatafeed.prototype._send = function (url, params, over) {
  let request = url;
  if (params) {
    for (let i = 0; i < Object.keys(params).length; ++i) {
      let key = Object.keys(params)[i];
      let value = encodeURIComponent(params[key]);
      request += (i === 0 ? '?' : '&') + key + '=' + value;
    }
  }

  this._logMessage('New request: ' + request);

    return fetch(request, {
      method: 'GET',
      mode: 'cors',
      headers: {}
    });
};

Datafeeds.UDFCompatibleDatafeed.prototype._initialize = function () {
  let that = this;
  this._send(this._datafeedURL + '/config')
    .then(function (response) {
      try {
        response.json().then(function (data) {
          let configurationData = parseJSONorNot(data);
          that._setupWithConfiguration(configurationData);
        }).catch(function (err) {
          that._setupWithConfiguration(that.defaultConfiguration(err))
        })
      } catch (err) {
        that._setupWithConfiguration(that.defaultConfiguration(err));
      }
    })
    .catch(function (reason) {
      that._setupWithConfiguration(that.defaultConfiguration());
    });
};

Datafeeds.UDFCompatibleDatafeed.prototype.onReady = function (callback) {
  let that = this;
  if (this._configuration) {
    setTimeout(function () {
      callback(that._configuration);
    }, 0);
  } else {
    this.on('configuration_ready', function () {
      callback(that._configuration);
    });
  }
};

Datafeeds.UDFCompatibleDatafeed.prototype._setupWithConfiguration = function (configurationData) {
  this._configuration = configurationData;

  if (!configurationData.exchanges) {
    configurationData.exchanges = [];
  }

  //	@obsolete; remove in 1.5
  let supportedResolutions = configurationData.supported_resolutions || configurationData.supportedResolutions;
  configurationData.supported_resolutions = supportedResolutions;

  //	@obsolete; remove in 1.5
  let symbolsTypes = configurationData.symbols_types || configurationData.symbolsTypes;
  configurationData.symbols_types = symbolsTypes;

  this._fireEvent('configuration_ready');
  this._logMessage('Initialized with ' + JSON.stringify(configurationData));
};

Datafeeds.UDFCompatibleDatafeed.prototype.resolveSymbol = function (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) {
  this._logMessage("GOWNO :: resolve symbol " + symbolName);
  Promise.resolve().then(() => {

    this._logMessage("GOWNO :: onResultReady inject " + "AAPL");
    onSymbolResolvedCallback({
      name: "AAPL",
      timezone: "Asia/Hong_Kong",//这里时区设置无效,只在初始化中有效
      pricescale:100,//保留小数,如:2位小数传100,3位传1000
      minmov: 1,
      minmov2: 0,
      ticker: symbolName,
      description: "",
      session: "24x7",
      type: "bitcoin",
      "exchange-traded": "myExchange",
      "exchange-listed": "myExchange",
      has_intraday: true,
      intraday_multipliers: ['1', '2', '5', '15', '30', '60', '240', '1D', '7D', '1W', '1M'],//所有的周期
      has_weekly_and_monthly: true,//是否有周线和月线
      has_no_volume: true,//是否将成交量独立出来
      regular_session: "24x7"
    });
  });
};

Datafeeds.UDFCompatibleDatafeed.prototype.getBars = function (symbolInfo, resolution, rangeStartDate, rangeEndDate, onDataCallback, onErrorCallback) {
  this._send(this._updateURL + '自己的数据接口', {
    给后段的参数
  }).then(function (response) {
    response.json().then((o) => {
      dataCB(o.data, onDataCallback, onErrorCallback);
    })
  }).catch(function (arg) {
    console.warn(['getBars(): HTTP error', arg]);
    if (!!onErrorCallback) {
      onErrorCallback('network error: ' + parseJSONorNot(arg));
    }
  });
};

function dataCB(response, onDataCallback, onErrorCallback) {
  let bars = [];
  for (let i = 0; i < response.length; i++) {
    将后段返回的数组处理成:
    {
        close:Number,不是number类型会出现问题
        open:Number,
        time:Number,时间戳,
        high:Number,
        low:Number,
        volume:Number
    }
    bars.push(obj);
  }
  onDataCallback(bars);
}

Datafeeds.UDFCompatibleDatafeed.prototype.subscribeBars = function (symbolInfo, resolution, onRealtimeCallback, listenerGUID, onResetCacheNeededCallback) {
  this._barsPulseUpdater.subscribeDataListener(symbolInfo, resolution, onRealtimeCallback, listenerGUID, onResetCacheNeededCallback);
};

Datafeeds.UDFCompatibleDatafeed.prototype.unsubscribeBars = function (listenerGUID) {
  this._barsPulseUpdater.unsubscribeDataListener(listenerGUID);
};

Datafeeds.UDFCompatibleDatafeed.prototype.unsubscribeAll = function () {
  this._barsPulseUpdater.unsubscribeAllListener();
};


Datafeeds.DataPulseUpdater = function (datafeed, updateFrequency) {
  this._datafeed = datafeed;
  this._subscribers = {};

  this._requestsPending = 0;
  let that = this;

  let update = function () {
    if (that._requestsPending > 0) {
      return;
    }

    for (let listenerGUID in that._subscribers) {
      let subscriptionRecord = that._subscribers[listenerGUID];
      let resolution = subscriptionRecord.resolution;
      let datesRangeRight;
      datesRangeRight = parseInt((new Date().valueOf()) / 1000);


      //	BEWARE: please note we really need 2 bars, not the only last one
      //	see the explanation below. `10` is the `large enough` value to work around holidays
      let datesRangeLeft = datesRangeRight - that.periodLengthSeconds(resolution, 10);
      that._requestsPending++;

      (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 === 0) {
            return;
          }

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

          let subscribers = _subscriptionRecord.listeners;

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

          //	Pulse updating may miss some trades data (ie, if pulse period = 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('Not enough bars in history for proper pulse update. Need at least 2.');
            }

            let previousBar = bars[bars.length - 2];
            for (let i = 0; i < subscribers.length; ++i) {
              subscribers[i](previousBar);
            }
          }

          _subscriptionRecord.lastBarTime = lastBar.time;

          for (let i = 0; i < subscribers.length; ++i) {
            subscribers[i](lastBar);
          }
        },

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

  if (typeof updateFrequency !== 'undefined' && updateFrequency > 0) {
    setInterval(update, updateFrequency);
  }
};

Datafeeds.DataPulseUpdater.prototype.unsubscribeAllListener = function () {
  this._subscribers = {};
};

Datafeeds.DataPulseUpdater.prototype.unsubscribeDataListener = function (listenerGUID) {
  this._datafeed._logMessage('Unsubscribing ' + listenerGUID);
  delete this._subscribers[listenerGUID];
};

Datafeeds.DataPulseUpdater.prototype.subscribeDataListener = function (symbolInfo, resolution, newDataCallback, listenerGUID) {
  this._datafeed._logMessage('Subscribing ' + listenerGUID);
  if (!this._subscribers.hasOwnProperty(listenerGUID)) {
    this._subscribers[listenerGUID] = {
      symbolInfo: symbolInfo,
      resolution: resolution,
      lastBarTime: NaN,
      listeners: []
    };
  }

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

Datafeeds.DataPulseUpdater.prototype.periodLengthSeconds = function (resolution, requiredPeriodsCount) {
  let daysCount = 0;

  if (resolution === 'D') {
    daysCount = requiredPeriodsCount;
  } else if (resolution === 'M') {
    daysCount = 31 * requiredPeriodsCount;
  } else if (resolution === 'W') {
    daysCount = 7 * requiredPeriodsCount;
  } else {
    daysCount = requiredPeriodsCount * resolution / (24 * 60);
  }

  return daysCount * 24 * 60 * 60;
};

export const DataFeeds = Datafeeds;
 

到这里基本就完成了tradingview的接入,将一些我写中文的地方改成自己的处理

Logo

前往低代码交流专区

更多推荐