canvas-trading
Version:
Interactive HTML5 Canvas Trading Chart
228 lines (227 loc) • 8.92 kB
JavaScript
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
import { candleColors, tradeColors } from '../config';
export function drawCurveLine(ctx, points, color, lineWidth, lineCap) {
ctx.beginPath();
if (lineCap) {
ctx.lineCap = lineCap;
}
ctx.lineWidth = lineWidth;
ctx.strokeStyle = color;
for (var _i = 0, points_1 = points; _i < points_1.length; _i++) {
var point = points_1[_i];
var xMid = (point.x + point.x) / 2;
var yMid = (point.y + point.y) / 2;
var cpX1 = (xMid + point.x) / 2;
var cpX2 = (xMid + point.x) / 2;
ctx.quadraticCurveTo(cpX1, point.y, xMid, yMid);
ctx.quadraticCurveTo(cpX2, point.y, point.x, point.y);
}
ctx.stroke();
if (lineCap) {
// initial value
ctx.lineCap = 'butt';
}
ctx.closePath();
}
export function drawMountedIndicators(ctx, candle, x, candleWidth, drawRevBar, drawFractal) {
var arr = __spreadArray(__spreadArray([], candle.mountPoints.above, true), candle.mountPoints.below, true);
arr.forEach(function (indicator) {
var indicatorIsInAboveArray = candle.mountPoints.above.includes(indicator);
if (indicator === null)
return;
if (indicator.type === 'revBar' && drawRevBar) {
revBar(ctx, x, indicator.yPos, indicator.value, candleWidth);
return;
}
if (indicator.type === 'fractal' && drawFractal) {
fractal(ctx, x, indicator.yPos, indicator.value, candleWidth);
}
function indicatorIsTrade(indicator) {
return 'tradeType' in indicator;
}
if (indicator.type === 'trade' && indicatorIsTrade(indicator)) {
var candleAboveMin = !indicatorIsInAboveArray;
tradeLetter(ctx, { x: x + candleWidth / 2, y: indicator.yPos }, candleWidth, indicator.tradeType === 'long', indicator.profitable, candleAboveMin, indicator.yPos);
arrowWithHead(ctx, {
x: x + candleWidth / 2,
y: candleAboveMin
? indicator.yPos + candleWidth * 3
: indicator.yPos - candleWidth * 3,
}, {
x: x + candleWidth / 2,
y: candleAboveMin
? indicator.yPos + candleWidth
: indicator.yPos - candleWidth,
}, tradeColors.arrow, candleWidth);
}
});
}
export function revBar(ctx, x, y, type, candleWidth) {
ctx.beginPath();
ctx.arc(x + candleWidth / 2, y, Math.max(candleWidth / 3, 3), 0, 2 * Math.PI);
ctx.fillStyle = type === 'buy' ? candleColors.green : candleColors.red;
ctx.fill();
ctx.closePath();
}
export function fractal(ctx, x, y, type, candleWidth) {
ctx.beginPath();
/** It also adds to the height a little bit, proportionally */
var triangleAdditionalWidthMultiplier = 0.1;
var triangleWidthShrinker = 1 / triangleAdditionalWidthMultiplier;
var triangleWidthMultiplier = 1 + triangleAdditionalWidthMultiplier;
// const triangleWidth = candleWidth * triangleWidthMultiplier;
var triangleWidth = Math.max(candleWidth * triangleWidthMultiplier, 10);
// ctx.moveTo(x - candleWidth / triangleWidthShrinker, y);
ctx.moveTo(x - triangleWidth / 2 + candleWidth / 2, y);
var toY = type === 'up' ? y - triangleWidth : y + triangleWidth;
ctx.lineTo(x + candleWidth / 2, toY);
// ctx.lineTo(x + triangleWidth, y);
ctx.lineTo(x + triangleWidth / 2 + candleWidth / 2, y);
ctx.fillStyle = type === 'up' ? candleColors.green : candleColors.red;
ctx.fill();
// ctx.strokeStyle = type === 'up' ? candleColors.green : candleColors.red;
// ctx.stroke();
ctx.closePath();
}
export function rect(ctx, x, y, width, height, fillColor, opacity) {
if (fillColor === void 0) { fillColor = candleColors.green; }
if (opacity === void 0) { opacity = 1; }
ctx.beginPath();
ctx.rect(x, y, width, height);
ctx.fillStyle = fillColor;
ctx.globalAlpha = opacity;
ctx.fill();
ctx.closePath();
ctx.globalAlpha = 1;
}
export function line(ctx, start, end, color, width, opacity, dash, lineCap) {
if (width === void 0) { width = 1; }
if (opacity === void 0) { opacity = 1; }
if (dash === void 0) { dash = []; }
ctx.beginPath();
ctx.moveTo(start.x, start.y);
ctx.lineTo(end.x, end.y);
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.globalAlpha = opacity;
if (lineCap) {
ctx.lineCap = lineCap;
}
ctx.setLineDash(dash);
ctx.stroke();
ctx.closePath();
ctx.setLineDash([]);
ctx.globalAlpha = 1;
if (lineCap) {
// initial value
ctx.lineCap = 'butt';
}
}
export function roundedRect(ctx, x, y, width, height, radius, fillColor) {
if (fillColor === void 0) { fillColor = 'white'; }
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.fillStyle = fillColor;
ctx.fill();
ctx.closePath();
}
export function findCandleWithTrade(candles, id, end) {
if (end === void 0) { end = false; }
var foundObj = {
candle: false,
index: 0,
innerIndex: 0,
};
candles.forEach(function (candle, index) {
var _a;
(_a = candle.trades) === null || _a === void 0 ? void 0 : _a.forEach(function (candleTrade, innerIndex) {
var rightType = !end
? candleTrade.isThisCandleStart && !candleTrade.isThisCandleEnd
: !candleTrade.isThisCandleStart && candleTrade.isThisCandleEnd;
if (candleTrade.tradeID === id && rightType) {
foundObj.candle = candle;
foundObj.index = index;
foundObj.innerIndex = innerIndex;
return foundObj;
}
});
});
return foundObj;
}
export function findCandleByDate(candles, date) {
var foundObj = {
candle: false,
index: 0,
innerIndex: 0,
};
candles.forEach(function (candle, index) {
var openDate = new Date(candle['openTime']);
if (openDate.getTime() === date.getTime()) {
foundObj.candle = candle;
foundObj.index = index;
return foundObj;
}
});
return foundObj;
}
export var tradeLetter = function (ctx, cords, gap, isTradeLong, isProfit, candleAboveMidLine, yPoint) {
ctx.font = "".concat(gap * 1.3, "px -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Open Sans\", \"Helvetica Neue\", sans-serif");
ctx.fillStyle = isProfit
? tradeColors.positiveArrow
: tradeColors.negativeArrow;
ctx.textAlign = 'center';
ctx.shadowColor = 'white';
ctx.shadowBlur = 2;
ctx.fillText(isTradeLong ? 'L' : 'S', cords.x, candleAboveMidLine ? yPoint + gap * 5 : yPoint - gap * 4);
//reset shadow
ctx.shadowColor = 'transparent';
ctx.shadowBlur = 0;
// reset text center
ctx.textAlign = 'left';
};
export function arrowWithHead(ctx, start, end, color, candleWidth) {
line(ctx, start, end, color, Math.sqrt(candleWidth), 0.8, [
candleWidth * 0.7,
candleWidth * 0.7,
]);
// arrow head
var angle = Math.atan2(end.y - start.y, end.x - start.x);
ctx.beginPath();
ctx.moveTo(end.x, end.y);
var size = candleWidth + Math.sqrt(candleWidth) * 1.5;
ctx.lineTo(end.x - size * Math.cos(angle - Math.PI / 6), end.y - size * Math.sin(angle - Math.PI / 6));
ctx.lineTo(end.x - size * Math.cos(angle + Math.PI / 6), end.y - size * Math.sin(angle + Math.PI / 6));
ctx.lineTo(end.x, end.y);
ctx.fillStyle = color;
ctx.fill();
ctx.closePath();
}
export var fibonacciReference = [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1];
export var fibonacciNumbers = function (priceA, priceB) {
var fibonacciPrices = [
priceA,
priceA + (priceB - priceA) * fibonacciReference[1],
priceA + (priceB - priceA) * fibonacciReference[2],
priceA + (priceB - priceA) * fibonacciReference[3],
priceA + (priceB - priceA) * fibonacciReference[4],
priceA + (priceB - priceA) * fibonacciReference[5],
priceB,
];
return fibonacciPrices;
};