app.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. const graph = new Vue({
  2. el: "#graph",
  3. data: {
  4. candles: [],
  5. latest: undefined
  6. },
  7. methods: {
  8. addCandle: (candle) => {
  9. graph.candles.push({
  10. date: candle[0],
  11. value: candle[2]
  12. });
  13. graph.latest = new Date(candle[0]);
  14. }
  15. },
  16. watch: {
  17. candles: (values) => {
  18. sorted = values.slice();
  19. sorted.sort((a, b) => {
  20. if (a.date < b.date) return -1;
  21. if (a.date > b.date) return 1;
  22. return 0;
  23. });
  24. dates = sorted.map((d) => d.date);
  25. for (let i=0; i<30; i++) {
  26. last = dates[dates.length - 1];
  27. dates.push(last + 60000);
  28. }
  29. d3.select("#data").select("g").remove();
  30. element = document.querySelector("#chart-space");
  31. margin = {
  32. top: 10,
  33. right: 30,
  34. bottom: 100,
  35. left: 60
  36. }
  37. height = element.clientHeight - margin.top - margin.bottom;
  38. width = element.clientWidth - margin.left - margin.right;
  39. svg = d3.select("#data")
  40. .append("g")
  41. .attr("transform", `translate(${margin.left}, ${margin.top})`);
  42. x = d3.scaleTime()
  43. .domain(d3.extent(dates, (d) => { return d }))
  44. .range([ 0, width ]);
  45. svg.append("g")
  46. .attr("transform", `translate(0, ${height})`)
  47. .call(d3.axisBottom(x));
  48. y = d3.scaleLinear()
  49. .domain([0, d3.max(sorted, (d) => { return +d.value })])
  50. .range([ height, 0 ]);
  51. svg.append("g")
  52. .call(d3.axisLeft(y));
  53. regression = ss.linearRegression(sorted.map((d) => { return [+d.date, d.value] }));
  54. line = ss.linearRegressionLine(regression);
  55. trendline = x.domain().map((x) => {
  56. return {
  57. date: x,
  58. value: line(+x)
  59. }
  60. });
  61. svg.append("path")
  62. .datum(trendline)
  63. .attr("fill", "none")
  64. .attr("stroke", "red")
  65. .attr("stroke-width", 1)
  66. .attr("d", d3.line().x((d) => {
  67. return x(d.date);
  68. }).y((d) => {
  69. return y(d.value);
  70. }));
  71. svg.append("path")
  72. .datum(sorted)
  73. .attr("fill", "none")
  74. .attr("stroke", "black")
  75. .attr("stroke-width", 2)
  76. .attr("d", d3.line().x((d) => {
  77. return x(d.date);
  78. }).y((d) => {
  79. return y(d.value);
  80. }));
  81. }
  82. }
  83. });
  84. const websocket = new Vue({
  85. el: "#websocket",
  86. created: () => {
  87. this.socket = new WebSocket("wss://api-pub.bitfinex.com/ws/2")
  88. this.socket.onopen = () => {
  89. websocket.connected = true
  90. };
  91. this.socket.onclose = () => {
  92. websocket.info = "";
  93. websocket.connected = false;
  94. };
  95. this.socket.onmessage = (message) => {
  96. json = JSON.parse(message.data);
  97. if (json.event == "info") websocket.info = `Server ${json.serverId} v${json.version}`;
  98. if (Array.isArray(json) && json[1] !== "hb") websocket.processValues(json);
  99. };
  100. },
  101. data: {
  102. connected: false,
  103. info: "",
  104. socket: undefined
  105. },
  106. methods: {
  107. processCandle: (candle) => {
  108. graph.addCandle(candle);
  109. },
  110. processValues: (json) => {
  111. if (Array.isArray(json[1][0])) {
  112. json[1].forEach((data) => websocket.processCandle(data));
  113. } else {
  114. websocket.processCandle(json[1]);
  115. }
  116. }
  117. },
  118. watch: {
  119. connected: (connected) => {
  120. if (connected === true) this.socket.send('{"event":"subscribe","channel":"candles","key":"trade:1m:tBTCUSD"}');
  121. }
  122. }
  123. });