sclass TradingCandlePainter { settable L candles; settable int w = 600; settable int h = 400; int horizontalMargin = 10; int verticalMargin = 10; int spikeWidth = 1; Color shortColor = java.awt.Color.blue; Color longColor = java.awt.Color.yellow; L positions; // how many lines are drawn to indicate percent changes settable double percentLineDistance = 0.05; BufferedImage render() { var run = new TradingRun(candles); var verticalRange = doubleRange(run.min(), run.max()); var horizontalRange = doubleRange(run.startTime().unixDate(), run.endTime().unixDate()); var xRange = doubleRange(horizontalMargin, w-horizontalMargin); var yRange = doubleRange(h-verticalMargin, verticalMargin); // Make black image var img = blackImage(w, h); var g = img.createGraphics(); // Draw percent lines double percentStep = center(verticalRange)*percentLineDistance/100; for (double y = verticalRange.start; y <= verticalRange.end; y += percentStep) { var yy = iround(transformBetweenDoubleRanges(y, verticalRange, yRange)); drawLine(g, 0, yy, w-1, yy, Color.gray); } // Draw candles var nCandles = l(candles); for i to nCandles: { var candle = candles.get(i); //x1 <- transformBetweenDoubleRanges (candle startTime) horizontalRange xRange var x1 = xRange.start()+doubleRatio(i, nCandles)*xRange.length(); var x2 = xRange.start()+doubleRatio(i+1, nCandles)*xRange.length(); x2 = blend(x1, x2, 0.75); var xCenter = avg(x1, x2); var y1 = transformBetweenDoubleRanges(candle.max(), verticalRange, yRange); var y2 = transformBetweenDoubleRanges(candle.min(), verticalRange, yRange); var yStart = transformBetweenDoubleRanges(candle.start(), verticalRange, yRange); var yEnd = transformBetweenDoubleRanges(candle.end(), verticalRange, yRange); // draw "spikes" var r = doubleRectFromPoints(xCenter, y1, xCenter+spikeWidth, y2); fillRect(g, growRectBottom(1, toRect_round(r)), candle.color()); // draw candle body r = doubleRectFromPoints(x1, min(yStart, yEnd), x2, max(yStart, yEnd)); fillRect(g, growRectBottom(1, toRect_round(r)), candle.color()); }; for (position : positions) { var time = position.openingTime(); var price = position.openingPrice(); var x = transformBetweenDoubleRanges(time, horizontalRange, xRange); var y = transformBetweenDoubleRanges(price, verticalRange, yRange); var color = colorFromHex(position.relativeValue() > 0 ? "1da2b4" : "f1493f"); // Mark opening point fillRect(g, rectAroundPt(iround(x), iround(y), 10), color); if (not(position.isOpen())) { time = position.closingTime(); price = position.closingPrice(); var x2 = transformBetweenDoubleRanges(time, horizontalRange, xRange); var y2 = transformBetweenDoubleRanges(price, verticalRange, yRange); drawArrowBetweenPoints(g, toPt_round(doublePt(x, y)), toPt_round(doublePt(x2, y2)), color); } } ret img; } }