TradingView的简单应用

在开发公司交易所项目的过程中,页面中需要集成专业的K线图功能。经过对多个类似网站的调研和参考,最终决定采用TradingView这一专业的股票交易所类图表库。结合之前的相关项目经验和TradingView的详细文档,我们成功实现了K线图的开发工作。现将整个开发过程进行整理,记录下心得体会,以便分享给大家作为参考。

一:Tradingview介绍

Tradingview 是一个价格图表和分析软件,提供免费和付费选项,由一群交易员和软件开发商在 2011 年 9 月推出。投资者可以通过 Tradingview 查看各种不同金融市场和资产类别的价格图表,包括股票、货币对、债券、期货以及加密货币。除此之外,投资者还可以通过该平台查看多个交易品种,比如股指期货、欧美货币对、黄金、原油、比特币等等。

  TradingView 可以说是全球在网页 K 线图上最专业的网站了,凡是在网页上提供 K 线图的,大部分使用的都是 TradingView 的技术,比如说火币、币安……

  简而言之,这是一个图表插件,刨除外观 UI 的设置,它的功能就是:获得数据——数据可视化——响应用户操作——获得数据——数据可视化——……

有兴趣可以看下在线demo

二:申请图表

1. 申请核心图表库

  Tradingview 图表库是开源免费的,GitHub 上有官网 demo 可以下载。

  该图表库支持多种语言及框架(如 Vue/React/Angular 等),其实下载了 demo 并不能直接运行,其中缺少关键的核心库(charting-library),这个需要到官网申请获得,申请步骤比较麻烦,需要下载它的一份协议,签名盖章之后扫描上传上去,然后填写一堆表单(邮箱公司地址等等),如果填写没问题的话,会在一两天之内回复你的邮箱,是 github 的链接(已授权过的,不然会报 404)。

获取 github 授权之后,就可以将核心库(charting-library)下载到本地了。

2. 参考文档

  因为开发文档写的可能不怎么友好,在此罗列一下自己的一些参考文档及一些实现的 demo

文档

这是个很不错的文档,作者很用心,文档也很详尽,只是小白可能看着有点绕。

 3. 运行demo

        我图了一个方便,直接在github上下载了别人写好的demo

  前面写到的下载好demo之后第一个坑就来了

        node-sass!!!

这东西真的很坑,我不是专业的前端并不知道怎么解决兼容问题于是我果断

npm uninstall node-sass
npm install sass

小样,拿捏不了你,既然咱们不合适,那就拜拜

在我不断的祈祷中,嘿嘿,跑起来了,Perfect

等等!!!TypeScript,天塌了,我只是一个普普通通的java后端啊,为啥要这么对我,抽支烟冷静下,区区ts就能拦住我?我可是java后端,java才是世界上最好的语言!

三:改造Demo

重振java雄风,我辈义不容辞

我们先创建一个Vue2项目,这里就不赘述了

还记得前文中的那个文件吗?需要到官网申请的

    +/charting_library
        + /static
        - charting_library.min.js
        - charting_library.min.d.ts
        - datafeed-api.d.ts
    + /datafeeds
        + /udf
    - index.html
    - mobile_black.html
    - mobile_white.html
    - test.html

最重要的其实是charting_library这个文件夹

1:我们将这个文件夹复制到我们的项目中,我这里选择了复制到public下

2:在index.html下引入这个js

<script type="text/javascript" src='<%= BASE_URL %>custom_scripts/chart_main/charting_library.min.js'></script>

3:创建TradingView组件

话不多说直接贴代码,话不多说,都哥们直接用

<template>
	<div>
		<div id="chart_container"></div>
	</div>

</template>

<script>
	import axios from 'axios';
	export default {
		name: "TradingViewChart",
		props: {
			coin: {
				type: String,
				required: true
			}
		},
		data() {
			return {
				chart: null,
				dataonRealtimeCallback: null,
				yuanshiArray:[]
			};
		},
		created() {
			
		},
		mounted() {
			this.getList();
			this.initView();
		},
		methods: {
			getList() {
				this.yuanshiArray = [];
				axios.get('获取历史数据的接口')
					.then(response => {
						let list = response.data
						list.forEach((item, index) => {
							let datata = {
								time: item.time*1000,
								close: item.close,
								open: item.open,
								high: item.high,
								low: item.low,
								volume: Number(item.volume)
							};
							this.yuanshiArray.push(datata);
					});
				});
			},
			createData() {
				setInterval(() => {
					axios.get('最新数据接口')
						.then(response => {
							let datata = {
								time: response.data.time*1000,
								close: response.data.close,
								open: response.data.open,
								high: response.data.high,
								low: response.data.low,
								volume: Number(response.data.volume)
							};
							this.dataonRealtimeCallback(datata);
						})
				}, 1000);
			},
			initView() {
				let Tdata = this.createFeed();
				this.chart = new TradingView.widget({
					fullscreen: false,
					autosize: true,
					symbol: this.coin,
					container_id: "chart_container",
					datafeed: Tdata,
					library_path: "/custom_scripts/chart_main/",
					locale: "zh",
					debug: false,
					// loading_screen:{ backgroundColor: "#00ff00",foregroundColor: "#000000", }, //todo:do it
					interval: '1',
					style: '1',
					// timeframe:'',//todo: na koncu
					toolbar_bg: "#20334d",
					// saved_data: this.savedData,
					allow_symbol_change: true,
					time_frames: [{
							text: "1y",
							resolution: "1W"
						},
						{
							text: "6m",
							resolution: "3D"
						},
						{
							text: "3m",
							resolution: "1D"
						},
						{
							text: "1m",
							resolution: "1D"
						},
						{
							text: "1w",
							resolution: "30"
						},
						{
							text: "3d",
							resolution: "30"
						},
						{
							text: "1d",
							resolution: "30"
						},
						{
							text: "6h",
							resolution: "15"
						},
						{
							text: "1h",
							resolution: "1"
						}
					],
					drawings_access: {
						type: 'black',
						// tools: [{name: "Regression Trend"}]//todo: moje
						tools: [{
							name: "Trend Line",
							grayed: true
						}, {
							name: "Trend Angle",
							grayed: true
						}] //todo: bb
					},
					disabled_features: [
						"header_symbol_search",
						"header_interval_dialog_button",
						"show_interval_dialog_on_key_press",
						"symbol_search_hot_key",
						"study_dialog_search_control",
						"display_market_status",
						"header_compare",
						"edit_buttons_in_legend",
						"symbol_info",
						"border_around_the_chart",
						"main_series_scale_menu",
						"star_some_intervals_by_default",
						"datasource_copypaste",
						"right_bar_stays_on_scroll",
						"context_menus",
						"go_to_date",
						"compare_symbol",
						"border_around_the_chart",
						"timezone_menu",
						"control_bar", //todo: przetestowac
						"edit_buttons_in_legend", //todo: przetestowac
						"remove_library_container_border",
					],
					enabled_features: [
						"dont_show_boolean_study_arguments",
						"use_localstorage_for_settings",
						"remove_library_container_border",
						"save_chart_properties_to_local_storage",
						"side_toolbar_in_fullscreen_mode",
						"hide_last_na_study_output",
						"constraint_dialogs_movement", //todo: nie do końca jestem pewien
					],
					studies_overrides: {
						"volume.volume.color.0": "#fe4761",
						"volume.volume.color.1": "#3fcfb4",
						"volume.volume.transparency": 75,
					},
					overrides: {
						"symbolWatermarkProperties.color": "rgba(0,0,0, 0)",
						"paneProperties.background": "#20334d",
						"paneProperties.vertGridProperties.color": "#344568",
						"paneProperties.horzGridProperties.color": "#344568",
						"paneProperties.crossHairProperties.color": "#58637a",
						"paneProperties.crossHairProperties.style": 2,
						"mainSeriesProperties.style": 9,
						"mainSeriesProperties.showCountdown": false,
						"scalesProperties.showSeriesLastValue": true,
						"mainSeriesProperties.visible": false,
						"mainSeriesProperties.showPriceLine": false,
						"mainSeriesProperties.priceLineWidth": 1,
						"mainSeriesProperties.lockScale": false,
						"mainSeriesProperties.minTick": "default",
						"mainSeriesProperties.extendedHours": false,
						"volumePaneSize": "tiny",
						editorFontsList: ["Lato", "Arial", "Verdana", "Courier New", "Times New Roman"],
						"paneProperties.topMargin": 5,
						"paneProperties.bottomMargin": 5,
						"paneProperties.leftAxisProperties.autoScale": true,
						"paneProperties.leftAxisProperties.autoScaleDisabled": false,
						"paneProperties.leftAxisProperties.percentage": false,
						"paneProperties.leftAxisProperties.percentageDisabled": false,
						"paneProperties.leftAxisProperties.log": false,
						"paneProperties.leftAxisProperties.logDisabled": false,
						"paneProperties.leftAxisProperties.alignLabels": true,
						// "paneProperties.legendProperties.showStudyArguments": true,
						"paneProperties.legendProperties.showStudyTitles": true,
						"paneProperties.legendProperties.showStudyValues": true,
						"paneProperties.legendProperties.showSeriesTitle": true,
						"paneProperties.legendProperties.showSeriesOHLC": true,
						"scalesProperties.showLeftScale": false,
						"scalesProperties.showRightScale": true,
						"scalesProperties.backgroundColor": "#20334d",
						"scalesProperties.lineColor": "#46587b",
						"scalesProperties.textColor": "#8f98ad",
						"scalesProperties.scaleSeriesOnly": false,
						"mainSeriesProperties.priceAxisProperties.autoScale": true,
						"mainSeriesProperties.priceAxisProperties.autoScaleDisabled": false,
						"mainSeriesProperties.priceAxisProperties.percentage": false,
						"mainSeriesProperties.priceAxisProperties.percentageDisabled": false,
						"mainSeriesProperties.priceAxisProperties.log": false,
						"mainSeriesProperties.priceAxisProperties.logDisabled": false,
						"mainSeriesProperties.candleStyle.upColor": "#3fcfb4",
						"mainSeriesProperties.candleStyle.downColor": "#fe4761",
						"mainSeriesProperties.candleStyle.drawWick": true,
						"mainSeriesProperties.candleStyle.drawBorder": true,
						"mainSeriesProperties.candleStyle.borderColor": "#3fcfb4",
						"mainSeriesProperties.candleStyle.borderUpColor": "#3fcfb4",
						"mainSeriesProperties.candleStyle.borderDownColor": "#fe4761",
						"mainSeriesProperties.candleStyle.wickColor": "#737375",
						"mainSeriesProperties.candleStyle.wickUpColor": "#3fcfb4",
						"mainSeriesProperties.candleStyle.wickDownColor": "#fe4761",
						"mainSeriesProperties.candleStyle.barColorsOnPrevClose": false,
						"mainSeriesProperties.hollowCandleStyle.upColor": "#3fcfb4",
						"mainSeriesProperties.hollowCandleStyle.downColor": "#fe4761",
						"mainSeriesProperties.hollowCandleStyle.drawWick": true,
						"mainSeriesProperties.hollowCandleStyle.drawBorder": true,
						"mainSeriesProperties.hollowCandleStyle.borderColor": "#3fcfb4",
						"mainSeriesProperties.hollowCandleStyle.borderUpColor": "#3fcfb4",
						"mainSeriesProperties.hollowCandleStyle.borderDownColor": "#fe4761",
						"mainSeriesProperties.hollowCandleStyle.wickColor": "#737375",
						"mainSeriesProperties.hollowCandleStyle.wickUpColor": "#3fcfb4",
						"mainSeriesProperties.hollowCandleStyle.wickDownColor": "#fe4761",
						"mainSeriesProperties.haStyle.upColor": "#3fcfb4",
						"mainSeriesProperties.haStyle.downColor": "#fe4761",
						"mainSeriesProperties.haStyle.drawWick": true,
						"mainSeriesProperties.haStyle.drawBorder": true,
						"mainSeriesProperties.haStyle.borderColor": "#3fcfb4",
						"mainSeriesProperties.haStyle.borderUpColor": "#3fcfb4",
						"mainSeriesProperties.haStyle.borderDownColor": "#fe4761",
						"mainSeriesProperties.haStyle.wickColor": "#737375",
						"mainSeriesProperties.haStyle.wickUpColor": "#3fcfb4",
						"mainSeriesProperties.haStyle.wickDownColor": "#fe4761",
						"mainSeriesProperties.haStyle.barColorsOnPrevClose": false,
						"mainSeriesProperties.barStyle.upColor": "#3fcfb4",
						"mainSeriesProperties.barStyle.downColor": "#fe4761",
						"mainSeriesProperties.barStyle.barColorsOnPrevClose": false,
						"mainSeriesProperties.barStyle.dontDrawOpen": false,
						"mainSeriesProperties.lineStyle.color": "#0cbef3",
						"mainSeriesProperties.lineStyle.linestyle": 0,
						"mainSeriesProperties.lineStyle.linewidth": 1,
						"mainSeriesProperties.lineStyle.priceSource": "close",
						"mainSeriesProperties.areaStyle.color1": "#0cbef3",
						"mainSeriesProperties.areaStyle.color2": "#0098c4",
						"mainSeriesProperties.areaStyle.linecolor": "#0cbef3",
						"mainSeriesProperties.areaStyle.linestyle": 0,
						"mainSeriesProperties.areaStyle.linewidth": 1,
						"mainSeriesProperties.areaStyle.priceSource": "close",
						"mainSeriesProperties.areaStyle.transparency": 80
					},
					custom_css_url: 'chart.css'
				})
			},
			// 创建k线配置
			// 创建k线配置
			createFeed() {
				let that = this
				let Datafeed = {}
				Datafeed.Container = function(updateFrequency) {
					this._configuration = {
						supports_search: false,
						supports_group_request: false,
						supported_resolutions: [ //支持的周期数组
							'1',
							'5',
							'15',
							'60',
							'120',
							'1D',
							'1W'
						],
						supports_marks: true, //来标识您的 datafeed 是否支持在K线上显示标记。
						supports_timescale_marks: true, //标识您的 datafeed 是否支持时间刻度标记。
						exchanges: ['myExchange1'] //交易所对象数组
					}
				}
				// onReady在图表Widget初始化之后立即调用,此方法可以设置图表库支持的图表配置
				Datafeed.Container.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)
						})
					}
				}
				// 通过商品名称解析商品信息(SymbolInfo),可以在此配置单个商品
				Datafeed.Container.prototype.resolveSymbol = function(
					symbolName,
					onSymbolResolvedCallback,
					onResolveErrorCallback
				) {
					Promise.resolve().then(() => {
						onSymbolResolvedCallback({
							name: that.coin,
							ticker: symbolName, //商品体系中此商品的唯一标识符
							description: '', //商品说明
							session: '24x7', //商品交易时间
							timezone: 'Asia/Shanghai', // 这个商品的交易所时区
							pricescale: 1000, // 价格精度
							minmov: 100, //最小波动
							minmov2: 0,
							// 'exchange-traded': 'myExchange2',
							// 'exchange-listed': productName,
							has_intraday: true, // 显示商品是否具有日内(分钟)历史数据
							intraday_multipliers: ['1', '5', '15', '15', '60', '120'], //日内周期(分钟单位)的数组
							has_weekly_and_monthly: true, // 显示商品是否具有以W和M为单位的历史数据
							has_daily: true, //显示商品是否具有以日为单位的历史数据
							// has_empty_bars: true,
							force_session_rebuild: true, //是否会随着当前交易而过滤K柱
							has_no_volume: false, //表示商品是否拥有成交量数据。
							regular_session: '24x7'
						})
					})
				}
				// 从我们的API源获取图表数据并将其交给TradingView。
				Datafeed.Container.prototype.getBars = async function(
					symbolInfo, // 商品信息对象
					resolution, //(string (周期)
					rangeStartDate, // unix 时间戳, 最左边请求的K线时间
					rangeEndDate, // unix 时间戳, 最右边请求的K线时间
					onDataCallback, // 历史数据的回调函数。每次请求只应被调用一次。
					onErrorCallback, // 错误的回调函数。
					firstDataRequest //布尔值,以标识是否第一次调用此商品/周期的历史记录。
				) {
					that.localresolution = resolution
					if (firstDataRequest) {
						console.log(symbolInfo.name);
						console.log(resolution)
						let bars = that.yuanshiArray;
						if (bars.length) {
							onDataCallback(bars)
						} else {
							onDataCallback([], {
								noData: true
							})
							// onErrorCallback([], { noData: true })
						}
					} else {
						onDataCallback([], {
							noData: true
						})
						// onErrorCallback([], { noData: true })
					}
				}
				// 订阅K线数据。图表库将调用onRealtimeCallback方法以更新实时数据。
				Datafeed.Container.prototype.subscribeBars = function(
					symbolInfo, // ObjectsymbolInfo对象
					resolution, // StringK线周期
					onRealtimeCallback, // Function将我们更新的K线传递给此回调以更新图表
					listenerGUID, // String此交易对的唯一ID和表示订阅的分辨率,生成规则:ticker+'_'+周期
					onResetCacheNeededCallback // Function调用次回调让图表再次请求历史K线数据
				) {
					that.callbacks = []
					that.callbacks.push(onRealtimeCallback)
					that.dataonRealtimeCallback = onRealtimeCallback
					that.createData()
					// 更改线型
					//that.chart.activeChart().setChartType(1);
				}
				// 取消订阅K线数据
				Datafeed.Container.prototype.unsubscribeBars = function(listenerGUID) {}
				return new Datafeed.Container()
			}

		}
	};
</script>
<style scoped lang="scss">
	#chart_container {
		height: calc(100vh - 100px);
	}
</style>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值