简体   繁体   中英

D3 Bollinger Band Issue

I want to generate bollinger band using D3 library. I tried following code but unfortunately its throwing following error -

VM224 d3.v3.js:670 Error: attribute d: Expected number, "M0,NaNL890,NaN"

What could be the cause of this error?

Code -

var margin = {
    top: 20,
    right: 20,
    bottom: 30,
    left: 50
  },
  width = 960 - margin.left - margin.right,
  height = 500 - margin.top - margin.bottom;

var n = 20; // n-period of moving average
var k = 2; // k times n-period standard deviation above/below moving average

var parseDate = d3.time.format("%m/%d/%Y").parse;

var x = d3.time.scale()
  .range([0, width]);
var y = d3.scale.linear()
  .range([height, 0]);
var xAxis = d3.svg.axis()
  .scale(x)
  .orient("bottom");
var yAxis = d3.svg.axis()
  .scale(y)
  .orient("left")
  .tickSize(3, 0);
var line = d3.svg.line()
  .x(function(d) {
    return x(d.date);
  })
  .y(function(d) {
    return y(d.close);
  });
var ma = d3.svg.line()
  .x(function(d) {
    return x(d.date);
  })
  .y(function(d) {
    return y(d.ma);
  });
var lowBand = d3.svg.line()
  .x(function(d) {
    return x(d.date);
  })
  .y(function(d) {
    return y(d.low);
  });
var highBand = d3.svg.line()
  .x(function(d) {
    return x(d.date);
  })
  .y(function(d) {
    return y(d.high);
  });
var bandsArea = d3.svg.area()
  .x(function(d) {
    return x(d.date);
  })
  .y0(function(d) {
    return y(d.low);
  })
  .y1(function(d) {
    return y(d.high);
  });

var svg = d3.select("body").append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var data = [
  [
    "9/9/2012",
    1000
  ],
  [
    "9/14/2013",
    100
  ]
];

data.forEach(function(d) {
  d.date = parseDate(d[0]);
  d.close = parseInt(d[1]);

  var bandsData = getBollingerBands(n, k, data);

  x.domain(d3.extent(data, function(d) {
    return d.date;
  }));
  y.domain([d3.min(bandsData, function(d) {
      return d.low;
    }),
    d3.max(bandsData, function(d) {
      return d.high;
    })
  ]);

  svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);
  svg.append("g")
    .attr("class", "y axis")
    .call(yAxis);

  svg.append("path")
    .datum(bandsData)
    .attr("class", "area bands")
    .attr("d", bandsArea);
  svg.append("path")
    .datum(bandsData)
    .attr("class", "line bands")
    .attr("d", lowBand);
  svg.append("path")
    .datum(bandsData)
    .attr("class", "line bands")
    .attr("d", highBand);
  svg.append("path")
    .datum(bandsData)
    .attr("class", "line ma bands")
    .attr("d", ma);

  svg.append("path")
    .datum(data)
    .attr("class", "line")
    .attr("d", line);
});

function getBollingerBands(n, k, data) {
  var bands = []; //{ ma: 0, low: 0, high: 0 }
  for (var i = n - 1, len = data.length; i < len; i++) {
    var slice = data.slice(i + 1 - n, i);
    var mean = d3.mean(slice, function(d) {
      return d.close;
    });
    var stdDev = Math.sqrt(d3.mean(slice.map(function(d) {
      return Math.pow(d.close - mean, 2);
    })));
    bands.push({
      date: data[i].date,
      ma: mean,
      low: mean - (k * stdDev),
      high: mean + (k * stdDev)
    });
  }
  return bands;
}

Fiddle

See working jsfiddle

First problem was, this being Bollinger Bands, that it needed more than the 2 data points you supplied it. When passing n=20 to getBollingerBands() it means it'll want to extract a mean value out of 20 consecutive data points. Since there were only 2, it yielded a blank array, which in turn caused NaN values to make it into the <path> .

I updated that data array to be a whole lot longer, as needed.

The other issue was that instead of this:

data.forEach(function(d) {
  d.date = parseDate(d[0]);
  d.close = parseInt(d[1]);
})

you had the function passed to forEach extend all the way down to include all the rendering code (eg svg.append("path") ), which meant it was trying to render the whole thing one per data point (ie potentially hundreds of times).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM