当前位置:网站首页>Tradingview tutorial
Tradingview tutorial
2022-07-26 10:31:00 【Zheng One Dream】
Get into :https://www.tradingview.com/HTML5-stock-forex-bitcoin-charting-library/
Then choose the library you want

The first lightweight chart
The second technical analysis chart
The third chart & trading platform
Mainly for Technical Analysis Charts( Technical analysis chart ) Do a tutorial
It should be noted that , This library needs to be acquired before it can be used
Get steps :
↓
↓
After writing it all, there will be this thing , You need to download this file , Then sign and upload
Be careful : Do not accept personal applications or tests 、 Application for research ; The company application must be a legally regulated company , Companies that do not meet the specifications should not apply (https://s3.amazonaws.com/tradingview/charting_library_license_agreement.pdf)
After getting the Library We can then proceed to the next step !
1. Clone the library locally
git clone https://github.com/tradingview/charting_library charting_library_clonned_data
2. Create a 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. Add one src Catalog ,main.js
// Introduce here datafeed We'll talk about this document later
import Datafeed from './datafeed.js';
window.tvWidget = new TradingView.widget({
symbol: 'Bitfinex:BTC/USD', // Default symbol
interval: '1D', // Default data interval
fullscreen: true, // Is it full screen
container_id: 'tv_chart_container', // Box id
datafeed: Datafeed,
library_path: '../charting_library_clonned_data/charting_library/', // The relative path of the Library
});4. Create a 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. Implement these methods
5.1 datafeed.js Add one configurationData object , Used to configure some parameters
const configurationData = {
supported_resolutions: ['1D', '1W', '1M'],
exchanges: [
{
value: 'Bitfinex',
name: 'Bitfinex',
desc: 'Bitfinex',
},
{
// If the user selects this Exchange ,searchSymbols Methods exchange Parameters
value: 'Kraken', // Name of exchange
name: 'Kraken', // Filter name
desc: 'Kraken bitcoin exchange', // The full transaction name displayed in the filter pop-up window
},
],
symbols_types: [
{
// If the user selects this symbol,searchSymbols Methods symbolType Parameters
name: 'crypto',
value: 'crypto',
},
// ...
],
};5.2 Realization onReady Method , Chart library uses this method to get datafeed Configuration of ( for example , Supported intervals (resolutions), exchange (exchange) etc. ). This is the first method to invoke the data feed . our datafeed This configuration will be returned to the chart Library . Be careful , The callback must be called asynchronously
export default {
onReady: (callback) => {
console.log('[onReady]: Method call');
setTimeout(() => callback(configurationData));
},
...
};5.2 establish helpers.js file , We use free CryptoCompare API To simulate data , Can be entered in the browser https://min-api.cryptocompare.com/data/v3/all/exchanges, View the return data format
// towards CryptoCompare API Request
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}`);
}
}
// Generate from currency symbol id
export function generateSymbol(exchange, fromSymbol, toSymbol) {
const short = `${fromSymbol}/${toSymbol}`;
return {
short,
full: `${exchange}:${short}`,
};
}5.3 stay datafeed.js Write one in the file getAllSymbols Method is used to get all 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 Realization resolveSymbol Method , This method is used to retrieve information about specific transaction varieties ( exchange , Price ratio , Complete trading varieties, etc ).
export default {
// ...
resolveSymbol: async (
symbolName,
onSymbolResolvedCallback,
onResolveErrorCallback
) => {
console.log('[resolveSymbol]: Method is called ', symbolName);
const symbols = await getAllSymbols();
const symbolItem = symbols.find(({ full_name }) => full_name === symbolName);
if (!symbolItem) {
console.log('[resolveSymbol]: Don't support symbol', symbolName);
onResolveErrorCallback(' This is not supported temporarily 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 Created ', symbolName);
onSymbolResolvedCallback(symbolInfo);
},
// ...
};5.5 stay helpers.js Add method to , It parses a cryptocurrency pair and returns the symbol All components of (full yes generateSymbol Method The value returned )
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 Realization getBars Method , This method is used to get symbol Historical data of
import { makeApiRequest, parseFullSymbol, generateSymbol } from './helpers.js';
// ...
export default {
// ...
getBars: async (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {
console.log('[getBars]: Method is called ', 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) {
// If there is no data within the requested time period , Is set “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]: Back to ${bars.length} individual bars`);
onHistoryCallback(bars, { noData: false });
} catch (error) {
console.log('[getBars]: error ', error);
onErrorCallback(error);
}
},
//...
};5.7 Realization searchSymbols, Every time a user is in symbol When typing text in the search box ,tradingview Will use this method to search symbol. change symbol You can also use searchSymbols.
We will start from API Request all available symbols , And then in datafeed.js Filter it in . If the user has not selected an exchange , Then exchange The parameter will be equal to an empty string
export default {
...
searchSymbols: async (
userInput,
exchange,
symbolType,
onResultReadyCallback
) => {
console.log('[searchSymbols]: Method is called ');
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);
},
...
}Now we can search for symbols and display historical data , Next, we need to display real-time transaction data
6. Streaming Realization , In this section , We will pass WebSocket Real time update .
6.1 stay index.html Add socket.io, Used to create websocket Connect
<!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 establish streaming.js Used to connect 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 Realization subscribeBars and unsubscribeBars Method , Used to subscribe and unsubscribe to a symbol Real-time data
// 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 Realization unsubscribeFromStream Method , The method of unsubscribing is implemented
export function unsubscribeFromStream(subscriberUID) {
// find subscriberUID The subscription
for (const channelString of channelToSubscription.keys()) {
const subscriptionItem = channelToSubscription.get(channelString);
const handlerIndex = subscriptionItem.handlers
.findIndex(handler => handler.id === subscriberUID);
if (handlerIndex !== -1) {
// Delete it
subscriptionItem.handlers.splice(handlerIndex, 1);
if (subscriptionItem.handlers.length === 0) {
// If it is the last handler , Then cancel the subscription channel
console.log('[unsubscribeBars]: from streaming Unsubscribe channel :', channelString);
socket.emit('SubRemove', { subs: [channelString] });
channelToSubscription.delete(channelString);
break;
}
}
}
}6.5 Realization websocket.onmessage Method , Used for processing socket Data sent
// streaming.js
// ...
socket.on('m', data => {
// The response data looks like this : 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) {
// Skip all non-TRADE event
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] Update the latest according to the price bar', tradePrice);
subscriptionItem.lastDailyBar = bar;
// For everyone who subscribes symbol send data
subscriptionItem.handlers.forEach(handler => handler.callback(bar));
});6.6 Before running the project , Open your datafeed.js File and adjust your GetBars Method to save the current symbol The last bar data . If we have a more accurate way to check the new bar, Or we have bar streaming API, Then we will not need this service .
//...
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 Provide Scaled stream data , But do not provide bar. therefore , Let's roughly check whether the new transaction is related to the new daily bar relevant . Please note that , For production version , You may need to do a more comprehensive inspection here . You can go to streaming.js Adjust the code . Add the right function :
function getNextDailyBarTime(barTime) {
const date = new Date(barTime * 1000);
date.setDate(date.getDate() + 1);
return date.getTime() / 1000;
}6.8 adjustment 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;
//...
});The last step , function
---------------------------------
Here is a detailed tutorial
github Address https://github.com/tradingview
Chinese document preface - TradingView Chinese development documents
边栏推荐
- The problem of incomplete or partial display of the last recyclerview is solved
- datav漂亮数据屏制作体验
- [Halcon vision] morphological expansion
- C语言计算日期间隔天数
- videojs转canvas暂停、播放、切换视频
- Learning about opencv (3)
- Prevent XSS attacks
- cavans实现静态滚动弹幕
- Inheritance method of simplified constructor (I) - combined inheritance
- canvas上传图片base64-有裁剪功能-Jcrop.js
猜你喜欢
随机推荐
The software cannot be opened
图片随手机水平移动-陀螺仪。360度设置条件
数据分析入门 | kaggle泰坦尼克任务(一)—>数据加载和初步观察
数据库的复习--1.概述
C语言计算日期间隔天数
cavans实现静态滚动弹幕
Comparison of packet capturing tools fiddler and Wireshark
Wechat official account release reminder (wechat official account template message interface)
Google与Pixar开发Draco支持USD格式 加速3D对象传输&lt;转发&gt;
【Halcon视觉】软件编程思路
PTA class a 1002
关于函数模板描述错误的是(链接格式错误怎么解决)
About the declaration and definition of template functions [easy to understand]
记给esp8266烧录刷固件
原生JS-获取transform值 x y z及rotate旋转角度
hx711 数据波动大的问题
MLX90640 红外热成像仪测温传感器模块开发笔记(六)
抓包工具fiddler和wireshark对比
[Halcon vision] array
【socket】三次握手是在listen中完成,accept只从完成连接的队列中拿出一个连接





![[Halcon vision] image gray change](/img/62/426713becba851f034e6008f28bdb0.png)

![[Halcon vision] threshold segmentation](/img/1c/e2463a796f99804a55680b69e714a6.png)

![[Halcon vision] morphological expansion](/img/ce/abaca036fce5b67dfe6ac361aecfea.png)


