本篇教程写的是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的接入,将一些我写中文的地方改成自己的处理