当前位置:网站首页>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
边栏推荐
猜你喜欢
随机推荐
[Halcon vision] array
[Halcon vision] morphological expansion
Analyze the hybrid construction objects in JS in detail (construction plus attributes, prototype plus methods)
Learning about tensorflow (II)
Use spiel expressions in custom annotations to dynamically obtain method parameters or execute methods
【Halcon视觉】形态学腐蚀
Listening freely, the next stop of online text traffic competition?
algorithm
【Halcon视觉】阈值分割
Closure of go (cumulative sum)
微信公众号发布提醒(微信公众号模板消息接口)
equals与==的区别
C language course design Tetris (Part 2)
软件打不开了
C语言回调函数
Employee information management system based on Web
Structure of [Halcon vision] operator
QRcode二维码(C语言)遇到的问题
数据分析入门 | kaggle泰坦尼克任务(一)—>数据加载和初步观察
Cause: couldn‘t make a guess for 解决方法