当前位置:网站首页>Tradingview 使用教程
Tradingview 使用教程
2022-07-26 10:25:00 【Zheng One Dream】
进入:https://www.tradingview.com/HTML5-stock-forex-bitcoin-charting-library/
然后选择自己想要的库

第一个轻量图表
第二个技术分析图表
第三个图表&交易平台
主要对 Technical Analysis Charts(技术分析图表) 做一个教程
需要注意的是,这个库需要获取才能使用
获取步骤:
↓
↓
全部写完会出现一个这个东西,需要你下载这个文件,然后签名并上传
注意:不受理个人申请或测试用、研究用的申请;公司申请必须是受合法监管的公司,不符合规范的公司请勿申请(https://s3.amazonaws.com/tradingview/charting_library_license_agreement.pdf)
获取到库之后 我们就可以进行下一步操作了!
1. 克隆库到本地
git clone https://github.com/tradingview/charting_library charting_library_clonned_data
2. 创建一个 index.html
!DOCTYPE HTML>
<html>
<head>
<title>TradingView Charting Library example</title>
<script
type="text/javascript"
src="charting_library_clonned_data/charting_library/charting_library.js">
</script>
<!-- Custom datafeed module. -->
<script type="module" src="src/main.js"></script>
</head>
<body style="margin:0px;">
<div id="tv_chart_container">
<!-- This div will contain the Charting Library widget. -->
</div>
</body>
</html>3. 添加一个 src 目录,main.js
// 这里引入 datafeed 这个文件后边我们再说
import Datafeed from './datafeed.js';
window.tvWidget = new TradingView.widget({
symbol: 'Bitfinex:BTC/USD', // 默认symbol
interval: '1D', // 默认的数据间隔
fullscreen: true, // 是否全屏
container_id: 'tv_chart_container', // 盒子的id
datafeed: Datafeed,
library_path: '../charting_library_clonned_data/charting_library/', // 库的相对路径
});4. 创建一个 datafeed.js
export default {
onReady: (callback) => {
console.log('[onReady]: Method call');
},
searchSymbols: (userInput, exchange, symbolType, onResultReadyCallback) => {
console.log('[searchSymbols]: Method call');
},
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {
console.log('[resolveSymbol]: Method call', symbolName);
},
getBars: (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {
console.log('[getBars]: Method call', symbolInfo);
},
subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {
console.log('[subscribeBars]: Method call with subscribeUID:', subscribeUID);
},
unsubscribeBars: (subscriberUID) => {
console.log('[unsubscribeBars]: Method call with subscriberUID:', subscriberUID);
},
};5. 实现这些方法
5.1 datafeed.js 添加一个 configurationData 对象,用来配置一些参数
const configurationData = {
supported_resolutions: ['1D', '1W', '1M'],
exchanges: [
{
value: 'Bitfinex',
name: 'Bitfinex',
desc: 'Bitfinex',
},
{
// 如果用户选择该交易所,searchSymbols 方法中的 exchange 参数
value: 'Kraken', // 交易所名称
name: 'Kraken', // 过滤器名称
desc: 'Kraken bitcoin exchange', // 过滤器弹出窗口中显示的完整交易所名称
},
],
symbols_types: [
{
// 如果用户选择这个symbol,searchSymbols 方法中的 symbolType 参数
name: 'crypto',
value: 'crypto',
},
// ...
],
};5.2 实现 onReady 方法,图表库使用此方法来获取 datafeed 的配置(例如,支持的间隔(resolutions),交易所(exchange)等)。这是调用数据馈送的第一个方法。我们的 datafeed 会将此配置返回到图表库。注意,该回调必须异步调用
export default {
onReady: (callback) => {
console.log('[onReady]: Method call');
setTimeout(() => callback(configurationData));
},
...
};5.2 创建 helpers.js 文件,我们用免费的 CryptoCompare API 来模拟数据,可以在浏览器输入 https://min-api.cryptocompare.com/data/v3/all/exchanges,查看返回数据格式
// 向 CryptoCompare API 发出请求
export async function makeApiRequest(path) {
try {
const response = await fetch(`https://min-api.cryptocompare.com/${path}`);
return response.json();
} catch(error) {
throw new Error(`CryptoCompare request error: ${error.status}`);
}
}
// 从对币生成 symbol id
export function generateSymbol(exchange, fromSymbol, toSymbol) {
const short = `${fromSymbol}/${toSymbol}`;
return {
short,
full: `${exchange}:${short}`,
};
}5.3 在 datafeed.js 文件里写一个 getAllSymbols 方法用来获取所有的 symbol
import { makeApiRequest, generateSymbol } from './helpers.js';
// ...
async function getAllSymbols() {
const data = await makeApiRequest('data/v3/all/exchanges');
let allSymbols = [];
for (const exchange of configurationData.exchanges) {
const pairs = data.Data[exchange.value].pairs;
for (const leftPairPart of Object.keys(pairs)) {
const symbols = pairs[leftPairPart].map(rightPairPart => {
const symbol = generateSymbol(exchange.value, leftPairPart, rightPairPart);
return {
symbol: symbol.short,
full_name: symbol.full,
description: symbol.short,
exchange: exchange.value,
type: 'crypto',
};
});
allSymbols = [...allSymbols, ...symbols];
}
}
return allSymbols;
}5.4 实现 resolveSymbol 方法,此方法来检索有关特定交易品种的信息(交易所,价格比例,完整交易品种等)。
export default {
// ...
resolveSymbol: async (
symbolName,
onSymbolResolvedCallback,
onResolveErrorCallback
) => {
console.log('[resolveSymbol]: 方法被调用了', symbolName);
const symbols = await getAllSymbols();
const symbolItem = symbols.find(({ full_name }) => full_name === symbolName);
if (!symbolItem) {
console.log('[resolveSymbol]: 不支持的 symbol', symbolName);
onResolveErrorCallback('暂不支持该 symbol');
return;
}
const symbolInfo = {
ticker: symbolItem.full_name,
name: symbolItem.symbol,
description: symbolItem.description,
type: symbolItem.type,
session: '24x7',
timezone: 'Etc/UTC',
exchange: symbolItem.exchange,
minmov: 1,
pricescale: 100,
has_intraday: false,
has_no_volume: true,
has_weekly_and_monthly: false,
supported_resolutions: configurationData.supported_resolutions,
volume_precision: 2,
data_status: 'streaming',
};
console.log('[resolveSymbol]: symbol 已创建', symbolName);
onSymbolResolvedCallback(symbolInfo);
},
// ...
};5.5 在 helpers.js 里添加方法,它解析一个加密币对并返回该 symbol 的所有组成部分(full 是 generateSymbol 方法返回的值)
export function parseFullSymbol(fullSymbol) {
const match = fullSymbol.match(/^(\w+):(\w+)\/(\w+)$/);
if (!match) {
return null;
}
return { exchange: match[1], fromSymbol: match[2], toSymbol: match[3] };
}5.6 实现 getBars 方法,此方法用来获取 symbol 的历史数据
import { makeApiRequest, parseFullSymbol, generateSymbol } from './helpers.js';
// ...
export default {
// ...
getBars: async (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {
console.log('[getBars]: 方法被调用了', symbolInfo, resolution, from, to);
const parsedSymbol = parseFullSymbol(symbolInfo.full_name);
const urlParameters = {
e: parsedSymbol.exchange,
fsym: parsedSymbol.fromSymbol,
tsym: parsedSymbol.toSymbol,
toTs: to,
limit: 2000,
};
const query = Object.keys(urlParameters)
.map(name => `${name}=${encodeURIComponent(urlParameters[name])}`)
.join('&');
try {
const data = await makeApiRequest(`data/histoday?${query}`);
if (data.Response && data.Response === 'Error' || data.Data.length === 0) {
// 如果在请求的时间段内没有数据,则设置“noData”。
onHistoryCallback([], { noData: true });
return;
}
let bars = [];
data.Data.forEach(bar => {
if (bar.time >= from && bar.time < to) {
bars = [...bars, {
time: bar.time * 1000,
low: bar.low,
high: bar.high,
open: bar.open,
close: bar.close,
}];
}
});
console.log(`[getBars]: 返回了 ${bars.length} 个 bars`);
onHistoryCallback(bars, { noData: false });
} catch (error) {
console.log('[getBars]: 错误', error);
onErrorCallback(error);
}
},
//...
};5.7 实现 searchSymbols,每次用户在 symbol 搜索框中键入文本时,tradingview 都会使用此方法搜索 symbol。更改 symbol 也可以使用 searchSymbols。
我们将从API请求所有可用的符号,然后在 datafeed.js 中对其进行过滤。如果用户尚未选择交易所,则该exchange参数将等于一个空字符串
export default {
...
searchSymbols: async (
userInput,
exchange,
symbolType,
onResultReadyCallback
) => {
console.log('[searchSymbols]: 方法被调用');
const symbols = await getAllSymbols();
const newSymbols = symbols.filter(symbol => {
const isExchangeValid = exchange === '' || symbol.exchange === exchange;
const isFullSymbolContainsInput = symbol.full_name
.toLowerCase()
.indexOf(userInput.toLowerCase()) !== -1;
return isExchangeValid && isFullSymbolContainsInput;
});
onResultReadyCallback(newSymbols);
},
...
}现在我们已经可以搜索符号并显示历史数据,接下来我们需要显示实时的交易数据
6. Streaming 实现,在本节中,我们将通过WebSocket实现实时更新。
6.1 在 index.html 中添加 socket.io,用来创建 websocket 连接
<!DOCTYPE HTML>
<html>
<head>
<!-- ... -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.2/socket.io.js"></script>
<!-- ... -->
</body>
</html>6.2 创建 streaming.js 用来连接 websocket
// streaming.js
const socket = io('wss://streamer.cryptocompare.com');
socket.on('connect', () => {
console.log('[socket] Connected');
});
socket.on('disconnect', (reason) => {
console.log('[socket] Disconnected:', reason);
});
socket.on('error', (error) => {
console.log('[socket] Error:', error);
});
export function subscribeOnStream() {
// todo
}
export function unsubscribeFromStream() {
// todo
}6.3 实现 subscribeBars 和 unsubscribeBars 方法,用来订阅和取消订阅某个 symbol 的实时数据
// datafeed.js
import { subscribeOnStream, unsubscribeFromStream } from './streaming.js';
const lastBarsCache = new Map();
// ...
export default {
// ...
subscribeBars: (
symbolInfo,
resolution,
onRealtimeCallback,
subscribeUID,
onResetCacheNeededCallback
) => {
console.log('[subscribeBars]: Method call with subscribeUID:', subscribeUID);
subscribeOnStream(
symbolInfo,
resolution,
onRealtimeCallback,
subscribeUID,
onResetCacheNeededCallback,
lastBarsCache.get(symbolInfo.full_name)
);
},
unsubscribeBars: (subscriberUID) => {
console.log('[unsubscribeBars]: Method call with subscriberUID:', subscriberUID);
unsubscribeFromStream(subscriberUID);
},
};6.4 实现 unsubscribeFromStream 方法,取消订阅的方法实现
export function unsubscribeFromStream(subscriberUID) {
// 找到 subscriberUID 的订阅
for (const channelString of channelToSubscription.keys()) {
const subscriptionItem = channelToSubscription.get(channelString);
const handlerIndex = subscriptionItem.handlers
.findIndex(handler => handler.id === subscriberUID);
if (handlerIndex !== -1) {
// 删除它
subscriptionItem.handlers.splice(handlerIndex, 1);
if (subscriptionItem.handlers.length === 0) {
// 如果是最后一个处理程序,则取消订阅通道
console.log('[unsubscribeBars]: 从 streaming 取消订阅频道:', channelString);
socket.emit('SubRemove', { subs: [channelString] });
channelToSubscription.delete(channelString);
break;
}
}
}
}6.5 实现 websocket.onmessage 方法,用来处理 socket 发送过来的数据
// streaming.js
// ...
socket.on('m', data => {
// 响应的数据看上去是这样的: 0~Bitfinex~BTC~USD~2~335394436~1548837377~0.36~3504.1~1261.4759999999999~1f
console.log('[socket] Message:', data);
const [
eventTypeStr,
exchange,
fromSymbol,
toSymbol,
,
,
tradeTimeStr,
,
tradePriceStr,
] = data.split('~');
if (parseInt(eventTypeStr) !== 0) {
// 跳过所有 non-TRADE 事件
return;
}
const tradePrice = parseFloat(tradePriceStr);
const tradeTime = parseInt(tradeTimeStr);
const channelString = `0~${exchange}~${fromSymbol}~${toSymbol}`;
const subscriptionItem = channelToSubscription.get(channelString);
if (subscriptionItem === undefined) {
return;
}
const lastDailyBar = subscriptionItem.lastDailyBar;
let bar = {
...lastDailyBar,
high: Math.max(lastDailyBar.high, tradePrice),
low: Math.min(lastDailyBar.low, tradePrice),
close: tradePrice,
};
console.log('[socket] 按价格更新最新的 bar', tradePrice);
subscriptionItem.lastDailyBar = bar;
// 给每一个订阅的 symbol 发送数据
subscriptionItem.handlers.forEach(handler => handler.callback(bar));
});6.6 在运行项目之前,打开您的 datafeed.js 文件并调整您的 GetBars 方法以保存当前 symbol 的最后一个 bar 数据。如果我们有更准确的方法来检查新的 bar,或者我们有 bar streaming API,那么我们将不需要此服务。
//...
data.Data.forEach( ... );
if (firstDataRequest) {
lastBarsCache.set(symbolInfo.full_name, { ...bars[bars.length - 1] });
}
console.log(`[getBars]: returned ${bars.length} bar(s)`);
//...6.7 CryptoCompare 提供 刻度的流数据,但不提供 bar。因此,让我们大致检查一下新交易是否与新的每日 bar 相关。请注意,对于生产版本,您可能需要在此处进行更全面的检查。您可以在 streaming.js 中调整代码。添加正确的功能:
function getNextDailyBarTime(barTime) {
const date = new Date(barTime * 1000);
date.setDate(date.getDate() + 1);
return date.getTime() / 1000;
}6.8 调整 websocket.onmessage
socket.on('m', data => {
//...
const lastDailyBar = subscriptionItem.lastDailyBar;
const nextDailyBarTime = getNextDailyBarTime(lastDailyBar.time);
let bar;
if (tradeTime >= nextDailyBarTime) {
bar = {
time: nextDailyBarTime,
open: tradePrice,
high: tradePrice,
low: tradePrice,
close: tradePrice,
};
console.log('[socket] Generate new bar', bar);
} else {
bar = {
...lastDailyBar,
high: Math.max(lastDailyBar.high, tradePrice),
low: Math.min(lastDailyBar.low, tradePrice),
close: tradePrice,
};
console.log('[socket] Update the latest bar by price', tradePrice);
}
subscriptionItem.lastDailyBar = bar;
//...
});最后一步,运行
---------------------------------
这里有详细的教程
github 地址 https://github.com/tradingview
边栏推荐
- Common errors when starting projects in uniapp ---appid
- 抓包工具fiddler和wireshark对比
- Study on the basis of opencv
- 【Halcon视觉】图像的傅里叶变换
- 上传图片获取宽高
- 微信公众号发布提醒(微信公众号模板消息接口)
- AirTest
- Function templates and non template functions with the same name cannot be overloaded (definition of overloads)
- SAP ABAP Netweaver 容器化的一些前沿性研究工作分享
- Network related journals and conferences in CS
猜你喜欢
随机推荐
[Halcon vision] software programming ideas
[Halcon vision] image filtering
[C language] LINQ overview
The charm of SQL optimization! From 30248s to 0.001s
【Halcon视觉】形态学腐蚀
【Halcon视觉】极坐标变换
SPARK中 DS V2 push down(下推)的一些说明
上传图片获取宽高
Function template parameters (where are the function parameters)
The difference between equals and = =
数通基础-网络基础知识
Prevent XSS attacks
Network related journals and conferences in CS
Modelsim installation tutorial (application not installed)
Learning about opencv (2)
单元测试,到底什么是单元测试,为什么单测这么难写
Okaleido ecological core equity Oka, all in fusion mining mode
Strange Towers of Hanoi|汉诺塔4柱问题
Vs Code configures go locale and successfully installs go related plug-ins in vscode problem: Tools failed to install
Flask框架初学-03-模板












