UNPKG

@azteam/candlestick-chart

Version:

N/A

935 lines (929 loc) 48.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _lodash = _interopRequireDefault(require("lodash")); var _momentTimezone = _interopRequireDefault(require("moment-timezone")); var _util = require("@azteam/util"); var _constant = require("./constant"); var _util2 = require("./util"); var _excluded = ["symbol", "openAt", "openID", "openPrice", "closePrice", "rate", "stopLossPercent", "takeProfitPercent", "algo"], _excluded2 = ["symbol", "openAt", "openID", "openPrice", "closePrice", "rate", "stopLossPercent", "takeProfitPercent", "algo"]; function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; } function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function roundDown(m, downTo, timeType) { var newMoment = m; if (downTo > 1) { var diff = 0; if (['day', 'days'].includes(timeType)) { diff = newMoment.date() % downTo; } else if (['hour', 'hours'].includes(timeType)) { diff = newMoment.hours() % downTo; } else if (['minute', 'minutes'].includes(timeType)) { diff = newMoment.minutes() % downTo; } else if (['second', 'seconds'].includes(timeType)) { diff = newMoment.seconds() % downTo; } newMoment = newMoment.subtract(diff, timeType); } return newMoment.startOf(timeType); } function groupBlockTimeByTimeChart(ts, timeChart) { if (timeChart === _constant.TIME_CHART._1_DAY.name) { var period = 14400; return [0, 1, 2, 3, 4, 5].map(function (x) { return ts + period * x; }); } if (timeChart === _constant.TIME_CHART._4_HOUR.name) { var _period = 3600; return [0, 1, 2, 3].map(function (x) { return ts + _period * x; }); } if (timeChart === _constant.TIME_CHART._60_MIN.name) { var _period2 = 1800; return [0, 1].map(function (x) { return ts + _period2 * x; }); } if (timeChart === _constant.TIME_CHART._30_MIN.name) { var _period3 = 900; return [0, 1].map(function (x) { return ts + _period3 * x; }); } if (timeChart === _constant.TIME_CHART._15_MIN.name) { var _period4 = 300; return [0, 1, 2].map(function (x) { return ts + _period4 * x; }); } if (timeChart === _constant.TIME_CHART._5_MIN.name) { var _period5 = 60; return [0, 1, 2, 3, 4].map(function (x) { return ts + _period5 * x; }); } return [ts]; } var CandlestickChart = /*#__PURE__*/function () { function CandlestickChart() { var timezone = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'Asia/Ho_Chi_Minh'; var pricePrecision = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; _classCallCheck(this, CandlestickChart); this.timezone = timezone; this.isInitChart = false; this.chart = _lodash["default"].reduce(_constant.TIME_CHART, function (result, value) { // eslint-disable-next-line no-param-reassign result[value.name] = []; return result; }, {}); this.pricePrecision = pricePrecision; } return _createClass(CandlestickChart, [{ key: "init", value: function init() { this.isInitChart = true; } }, { key: "convertTickId", value: function convertTickId(tick1minId) { var m = _momentTimezone["default"].unix(tick1minId).tz(this.timezone); return { tick1minId: roundDown(m, 1, 'minutes').unix(), tick5minId: roundDown(m, 5, 'minutes').unix(), tick15minId: roundDown(m, 15, 'minutes').unix(), tick30minId: roundDown(m, 30, 'minutes').unix(), tick60minId: roundDown(m, 1, 'hours').unix(), tick4hourId: roundDown(m, 4, 'hours').unix(), tick1dayId: roundDown(m, 1, 'days').unix() }; } }, { key: "generateOpenId", value: function generateOpenId(tickId, index) { return "".concat(this.serial).concat(index).concat(tickId); } }, { key: "generateLongEntry", value: function generateLongEntry(entry) { var symbol = entry.symbol, openAt = entry.openAt, openID = entry.openID, openPrice = entry.openPrice, closePrice = entry.closePrice, rate = entry.rate, stopLossPercent = entry.stopLossPercent, takeProfitPercent = entry.takeProfitPercent, algo = entry.algo, info = _objectWithoutProperties(entry, _excluded); var orderPrice = (0, _util.increasePercent)(closePrice, 0.02); var takeProfitPrice = (0, _util.increasePercent)(openPrice, takeProfitPercent); var stopLossPrice = (0, _util.decreasePercent)(openPrice, stopLossPercent); return _objectSpread({ symbol: symbol, open_at: openAt, open_type: _constant.TREND.LONG, open_id: openID, open_price: _lodash["default"].floor(openPrice, this.pricePrecision), order_price: _lodash["default"].floor(orderPrice, this.pricePrecision), stop_loss_price: _lodash["default"].floor(stopLossPrice, this.pricePrecision), stop_loss_percent: stopLossPercent, take_profit_price: _lodash["default"].floor(takeProfitPrice, this.pricePrecision), take_profit_percent: takeProfitPercent, rate: rate, algo: algo }, info); } }, { key: "generateShortEntry", value: function generateShortEntry(entry) { var symbol = entry.symbol, openAt = entry.openAt, openID = entry.openID, openPrice = entry.openPrice, closePrice = entry.closePrice, rate = entry.rate, stopLossPercent = entry.stopLossPercent, takeProfitPercent = entry.takeProfitPercent, algo = entry.algo, info = _objectWithoutProperties(entry, _excluded2); var orderPrice = (0, _util.decreasePercent)(closePrice, 0.02); var takeProfitPrice = (0, _util.decreasePercent)(openPrice, takeProfitPercent); var stopLossPrice = (0, _util.increasePercent)(openPrice, stopLossPercent); return _objectSpread({ symbol: symbol, open_type: _constant.TREND.SHORT, open_at: openAt, open_id: openID, open_price: _lodash["default"].floor(openPrice, this.pricePrecision), order_price: _lodash["default"].floor(orderPrice, this.pricePrecision), stop_loss_price: _lodash["default"].floor(stopLossPrice, this.pricePrecision), stop_loss_percent: stopLossPercent, take_profit_price: _lodash["default"].floor(takeProfitPrice, this.pricePrecision), take_profit_percent: takeProfitPercent, algo: algo, rate: rate }, info); } }, { key: "convertAlgorithm", value: function convertAlgorithm(ticks) { var algo = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var index = arguments.length > 2 ? arguments[2] : undefined; var symbol = algo.symbol, detectFunc = algo.detectFunc, trend = algo.trend, name = algo.name; var cacheTick = ticks.tick1min; var _detectFunc = detectFunc(ticks), status = _detectFunc.status, indicators = _detectFunc.indicators, rate = _detectFunc.rate; if (status) { var tick1min = ticks.tick1min; var entryInfo = { symbol: symbol, openAt: tick1min.id, openPrice: tick1min.close, closePrice: tick1min.close, openID: this.generateOpenId(cacheTick.id, index), stopLossPercent: rate, takeProfitPercent: rate, rate: rate, algo: name, indicators: indicators }; if (trend === _constant.TREND.LONG) { return this.generateLongEntry(entryInfo); } if (trend === _constant.TREND.SHORT) { return this.generateShortEntry(entryInfo); } } return null; } }, { key: "getTicks", value: function getTicks() { var position = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var ticks = {}; var chart1minName = _constant.TIME_CHART._1_MIN.name; ticks.tick1min = this.chart[chart1minName][position]; ticks.prevTick1min = this.chart[chart1minName][position + 1]; ticks.prev2Tick1min = this.chart[chart1minName][position + 2]; ticks.prev3Tick1min = this.chart[chart1minName][position + 3]; var _this$convertTickId = this.convertTickId(ticks.tick1min.id), tick5minId = _this$convertTickId.tick5minId, tick15minId = _this$convertTickId.tick15minId, tick30minId = _this$convertTickId.tick30minId, tick60minId = _this$convertTickId.tick60minId, tick4hourId = _this$convertTickId.tick4hourId, tick1dayId = _this$convertTickId.tick1dayId; var chart5minName = _constant.TIME_CHART._5_MIN.name; var indexTick5min = this.chart[chart5minName].findIndex(function (obj) { return obj.id === tick5minId; }); ticks.tick5min = this.chart[chart5minName][indexTick5min]; ticks.prevTick5min = this.chart[chart5minName][indexTick5min + 1]; ticks.prev2Tick5min = this.chart[chart5minName][indexTick5min + 2]; ticks.prev3Tick5min = this.chart[chart5minName][indexTick5min + 3]; var chart15minName = _constant.TIME_CHART._15_MIN.name; var indexTick15min = this.chart[chart15minName].findIndex(function (obj) { return obj.id === tick15minId; }); ticks.tick15min = this.chart[chart15minName][indexTick15min]; ticks.prevTick15min = this.chart[chart15minName][indexTick15min + 1]; ticks.prev2Tick15min = this.chart[chart15minName][indexTick15min + 2]; ticks.prev3Tick15min = this.chart[chart15minName][indexTick15min + 3]; var chart30minName = _constant.TIME_CHART._30_MIN.name; var indexTick30min = this.chart[chart30minName].findIndex(function (obj) { return obj.id === tick30minId; }); ticks.tick30min = this.chart[chart30minName][indexTick30min]; ticks.prevTick30min = this.chart[chart30minName][indexTick30min + 1]; ticks.prev2Tick30min = this.chart[chart30minName][indexTick30min + 2]; ticks.prev3Tick30min = this.chart[chart30minName][indexTick30min + 3]; var chart60minName = _constant.TIME_CHART._60_MIN.name; var indexTick60min = this.chart[chart60minName].findIndex(function (obj) { return obj.id === tick60minId; }); ticks.tick60min = this.chart[chart60minName][indexTick60min]; ticks.prevTick60min = this.chart[chart60minName][indexTick60min + 1]; ticks.prev2Tick60min = this.chart[chart60minName][indexTick60min + 2]; ticks.prev3Tick60min = this.chart[chart60minName][indexTick60min + 3]; var chart4hourName = _constant.TIME_CHART._4_HOUR.name; var indexTick4hour = this.chart[chart4hourName].findIndex(function (obj) { return obj.id === tick4hourId; }); ticks.tick4hour = this.chart[chart4hourName][indexTick4hour]; ticks.prevTick4hour = this.chart[chart4hourName][indexTick4hour + 1]; ticks.prev2Tick4hour = this.chart[chart4hourName][indexTick4hour + 2]; ticks.prev3Tick4hour = this.chart[chart4hourName][indexTick4hour + 3]; var chart1dayName = _constant.TIME_CHART._1_DAY.name; var indexTick1day = this.chart[chart1dayName].findIndex(function (obj) { return obj.id === tick1dayId; }); ticks.tick1day = this.chart[chart1dayName][indexTick1day]; ticks.prevTick1day = this.chart[chart1dayName][indexTick1day + 1]; ticks.prev2Tick1day = this.chart[chart1dayName][indexTick1day + 2]; ticks.prev3Tick1day = this.chart[chart1dayName][indexTick1day + 3]; return ticks; } }, { key: "getChart", value: function getChart() { return this.chart; } /* eslint-disable no-param-reassign */ }, { key: "calculateTickMA", value: function calculateTickMA(data, index) { var bbSMA = 0; var closeSMA5 = 0; var closeSMA10 = 0; var closeSMA20 = 0; data[index].max5 = data[index].high; data[index].max10 = data[index].high; data[index].max20 = data[index].high; data[index].min5 = data[index].low; data[index].min10 = data[index].low; data[index].min20 = data[index].low; for (var i = index; i < _constant.BB_DEVIATION + index; i += 1) { var tick = data[i]; if (i < _constant.BB_DEVIATION + index) { bbSMA += tick.close; } if (i < 5 + index) { closeSMA5 += tick.close; data[index].max5 = Math.max(data[index].max5, tick.high); data[index].min5 = Math.min(data[index].min5, tick.low); } if (i < 10 + index) { closeSMA10 += tick.close; data[index].max10 = Math.max(data[index].max10, tick.high); data[index].min10 = Math.min(data[index].min10, tick.low); } if (i < 20 + index) { closeSMA20 += tick.close; data[index].max20 = Math.max(data[index].max20, tick.high); data[index].min20 = Math.min(data[index].min20, tick.low); } } data[index].bb_sma = _lodash["default"].round(bbSMA / _constant.BB_DEVIATION, this.pricePrecision); data[index].close_sma_5 = _lodash["default"].round(closeSMA5 / 5, this.pricePrecision); data[index].close_sma_10 = _lodash["default"].round(closeSMA10 / 10, this.pricePrecision); data[index].close_sma_20 = _lodash["default"].round(closeSMA20 / 20, this.pricePrecision); data[index].trend5 = _constant.TREND.SIDEWAY; data[index].trend10 = _constant.TREND.SIDEWAY; data[index].trend20 = _constant.TREND.SIDEWAY; var prev2 = data[index + 2]; var prev1 = data[index + 1]; var current = data[index]; if (prev2) { if (prev2.close_sma_5 < prev1.close_sma_5 && prev1.close_sma_5 < current.close_sma_5) { data[index].trend5 = _constant.TREND.LONG; } else if (prev2.close_sma_5 > prev1.close_sma_5 && prev1.close_sma_5 > current.close_sma_5) { data[index].trend5 = _constant.TREND.SHORT; } if (prev2.close_sma_10 < prev1.close_sma_10 && prev1.close_sma_10 < current.close_sma_10) { data[index].trend10 = _constant.TREND.LONG; } else if (prev2.close_sma_10 > prev1.close_sma_10 && prev1.close_sma_10 > current.close_sma_10) { data[index].trend10 = _constant.TREND.SHORT; } if (prev2.close_sma_20 < prev1.close_sma_20 && prev1.close_sma_20 < current.close_sma_20) { data[index].trend20 = _constant.TREND.LONG; } else if (prev2.close_sma_20 > prev1.close_sma_20 && prev1.close_sma_20 > current.close_sma_20) { data[index].trend20 = _constant.TREND.SHORT; } } data[index].straight = "".concat(_lodash["default"].map(_lodash["default"].orderBy([{ key: 5, value: data[index].close_sma_5 }, { key: 10, value: data[index].close_sma_10 }, { key: 20, value: data[index].close_sma_20 }], ['value'], ['desc']), 'key').join('_')); data[index].above_sma5 = 0; data[index].above_sma10 = 0; data[index].above_sma20 = 0; data[index].below_sma5 = 0; data[index].below_sma10 = 0; data[index].below_sma20 = 0; var isNextAbove5 = true; var isNextAbove10 = true; var isNextAbove20 = true; var isNextBelow5 = true; var isNextBelow10 = true; var isNextBelow20 = true; for (var _i = index + 1; _i < _constant.BB_DEVIATION + index; _i += 1) { var _tick = data[_i]; if (isNextAbove5) { if (_tick.low > _tick.close_sma_5) { data[index].above_sma5 += 1; } else { isNextAbove5 = false; } } if (isNextBelow5) { if (_tick.high < _tick.close_sma_5) { data[index].below_sma5 += 1; } else { isNextBelow5 = false; } } if (isNextAbove10) { if (_tick.low > _tick.close_sma_10) { data[index].above_sma10 += 1; } else { isNextAbove10 = false; } } if (isNextBelow10) { if (_tick.high < _tick.close_sma_10) { data[index].below_sma10 += 1; } else { isNextBelow10 = false; } } if (isNextAbove20) { if (_tick.low > _tick.close_sma_20) { data[index].above_sma20 += 1; } else { isNextAbove20 = false; } } if (isNextBelow20) { if (_tick.high < _tick.close_sma_20) { data[index].below_sma20 += 1; } else { isNextBelow20 = false; } } if (!isNextAbove5 && !isNextAbove10 && !isNextAbove20 && !isNextBelow5 && !isNextBelow10 && !isNextBelow20) { break; } } } /* eslint-enable */ }, { key: "calculateProfitAndTimeTick", value: function calculateProfitAndTimeTick(data, index) { var tick = data[index]; tick.profit = _lodash["default"].round(tick.close - tick.open, 2); tick.profit_percent = (0, _util.getPercentDifference)(tick.close, tick.open); tick.max_profit_percent = (0, _util.getPercentDifference)(tick.high, tick.open); tick.max_loss_percent = (0, _util.getPercentDifference)(tick.low, tick.open); tick.candle_size = (0, _util.getPercentDifference)(tick.high, tick.low); tick.lower_wick_percent = (0, _util.getPercentDifference)(tick.close, tick.low); tick.upper_wick_percent = (0, _util.getPercentDifference)(tick.high, tick.close); tick.center_price = _lodash["default"].mean([tick.high, tick.low]); tick.color = tick.open < tick.close ? _constant.CANDLE_COLOR.GREEN : _constant.CANDLE_COLOR.RED; tick.time = _momentTimezone["default"].unix(tick.id).tz('Asia/Ho_Chi_Minh').format('HH:mm:ss DD-MM-YYYY UTCZ'); } }, { key: "calculateBollingerBandsForTick", value: function calculateBollingerBandsForTick(data, index) { var tick = data[index]; var variance = 0; for (var j = index; j < index + _constant.BB_DEVIATION; j += 1) { variance += Math.pow(data[j].close - tick.bb_sma, 2); } variance /= _constant.BB_DEVIATION; var standardDeviation = Math.sqrt(variance); tick.bb_upper_band = _lodash["default"].round(tick.bb_sma + 2 * standardDeviation, this.pricePrecision); tick.bb_lower_band = _lodash["default"].round(tick.bb_sma - 2 * standardDeviation, this.pricePrecision); tick.bb_size = (0, _util.getPercentDifference)(tick.bb_upper_band, tick.bb_lower_band); tick.bb_width = _lodash["default"].round((tick.bb_upper_band - tick.bb_lower_band) / tick.bb_sma, 4); tick.bb_percent = _lodash["default"].round((tick.close - tick.bb_lower_band) / (tick.bb_upper_band - tick.bb_lower_band), 4) || 0; tick.pos = _constant.BB_POSITION.MIDDLE; if (tick.bb_size > 5) { if (tick.close > tick.bb_upper_band) { tick.pos = _constant.BB_POSITION.OUT_TOP; } else if (tick.close < tick.bb_lower_band) { tick.pos = _constant.BB_POSITION.OUT_BOTTOM; } else if (tick.close > (tick.bb_upper_band + tick.bb_sma) / 2) { tick.pos = _constant.BB_POSITION.TOP; } else if (tick.close < (tick.bb_lower_band + tick.bb_sma) / 2) { tick.pos = _constant.BB_POSITION.BOTTOM; } else if (tick.close > tick.bb_sma) { tick.pos = _constant.BB_POSITION.UPPER_MIDDLE; } else if (tick.close < tick.bb_sma) { tick.pos = _constant.BB_POSITION.LOWER_MIDDLE; } } tick.time_at = tick.id; tick.tick_id = tick.id; tick.is_bb_tick = true; } }, { key: "reverseAndClearSAR", value: function reverseAndClearSAR(data) { var reversed = []; for (var i = data.length - 1; i >= 0; i -= 1) { var item = _objectSpread({}, data[i]); reversed.push(item); } return reversed; } }, { key: "calculateSAR", value: function calculateSAR(data) { var afStep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.02; var afMax = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0.2; if (data.length < 2) return; var reversed = this.reverseAndClearSAR(data); var isUp = reversed[1].close > reversed[0].close; var ep = isUp ? reversed[1].high : reversed[1].low; var sar = isUp ? reversed[0].low : reversed[0].high; var af = afStep; reversed[1].sar = sar; for (var i = 2; i < reversed.length; i += 1) { var curr = reversed[i]; var prev = reversed[i - 1]; var prev2 = reversed[i - 2]; sar += af * (ep - sar); if (isUp) { var prev2Low = prev2 && prev2.low != null ? prev2.low : prev.low; sar = Math.min(sar, prev.low, prev2Low); } else { var prev2High = prev2 && prev2.high != null ? prev2.high : prev.high; sar = Math.max(sar, prev.high, prev2High); } if (isUp && curr.low < sar) { isUp = false; sar = ep; ep = curr.low; af = afStep; } else if (!isUp && curr.high > sar) { isUp = true; sar = ep; ep = curr.high; af = afStep; } else { if (isUp && curr.high > ep) { ep = curr.high; af = Math.min(af + afStep, afMax); } if (!isUp && curr.low < ep) { ep = curr.low; af = Math.min(af + afStep, afMax); } } curr.sar = sar; } // Gán lại kết quả vào data gốc for (var _i2 = 0; _i2 < data.length; _i2 += 1) { data[_i2].sar = _lodash["default"].floor(reversed[data.length - 1 - _i2].sar, this.pricePrecision); data[_i2].sar_trend = data[_i2].close > data[_i2].sar ? _constant.TREND.LONG : _constant.TREND.SHORT; } } }, { key: "convertBBTick", value: function convertBBTick(data, index) { if (data.length >= _constant.CHART_SIZE) { this.calculateProfitAndTimeTick(data, index); this.calculateTickMA(data, index); this.calculateBollingerBandsForTick(data, index); } return data; } }, { key: "convertBBFirstTick", value: function convertBBFirstTick(data) { return this.convertBBTick(data, 0); } }, { key: "convertBollingerBands", value: function convertBollingerBands(data) { if (data.length < _constant.BB_DEVIATION + _constant.CHART_SIZE) { return []; } for (var i = 0; i <= _constant.CHART_SIZE; i += 1) { this.calculateProfitAndTimeTick(data, i); this.calculateTickMA(data, i); } for (var _i3 = 0; _i3 <= _constant.CHART_SIZE; _i3 += 1) { this.calculateBollingerBandsForTick(data, _i3); } return data; } }, { key: "sumVolume", value: function sumVolume(ts, timeChart) { var blockTimes = groupBlockTimeByTimeChart(ts, timeChart); var ticks = []; var findChartName = ''; if (timeChart === _constant.TIME_CHART._1_DAY.name) { findChartName = _constant.TIME_CHART._4_HOUR.name; } if (timeChart === _constant.TIME_CHART._4_HOUR.name) { findChartName = _constant.TIME_CHART._60_MIN.name; } if (timeChart === _constant.TIME_CHART._60_MIN.name) { findChartName = _constant.TIME_CHART._30_MIN.name; } if (timeChart === _constant.TIME_CHART._30_MIN.name) { findChartName = _constant.TIME_CHART._15_MIN.name; } if (timeChart === _constant.TIME_CHART._15_MIN.name) { findChartName = _constant.TIME_CHART._5_MIN.name; } if (timeChart === _constant.TIME_CHART._5_MIN.name) { findChartName = _constant.TIME_CHART._1_MIN.name; } ticks = this.chart[findChartName].filter(function (t) { return blockTimes.includes(t.time_at); }); return { vol: _lodash["default"].sumBy(ticks, 'vol'), amount: _lodash["default"].sumBy(ticks, 'amount') }; } }, { key: "addTickToChart", value: function addTickToChart(tick) { var timeChart = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _constant.TIME_CHART._1_MIN.name; var isInitialized = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; // eslint-disable-next-line no-param-reassign tick.debug_time = _momentTimezone["default"].unix(tick.id).tz('Asia/Ho_Chi_Minh').format('HH:mm:ss DD-MM-YYYY UTCZ'); tick.isInitialized = isInitialized; var chart = this.chart[timeChart]; var chart1minName = _constant.TIME_CHART._1_MIN.name; var tickIds = this.convertTickId(tick.id); var currentTickIds = this.convertTickId((0, _momentTimezone["default"])().unix()); var _$find = _lodash["default"].find(_constant.TIME_CHART, function (tc) { if (tc.name === timeChart) { // eslint-disable-next-line no-param-reassign tc.tickId = tickIds["tick".concat(tc.name, "Id")]; // eslint-disable-next-line no-param-reassign tc.currentTickId = currentTickIds["tick".concat(tc.name, "Id")]; return tc; } }), tickId = _$find.tickId, currentTickId = _$find.currentTickId, period = _$find.period; if (timeChart !== chart1minName && !tick.isInitialized) { var _this$sumVolume = this.sumVolume(tickId, timeChart), vol = _this$sumVolume.vol, amount = _this$sumVolume.amount; } if (chart.length === 0) { chart.unshift(_objectSpread(_objectSpread({}, tick), {}, { id: tickId, // required chart_type: timeChart })); } if (chart[0].id === tickId) { chart[0].debug_time = tick.debug_time; if (timeChart === chart1minName) { chart[0].open = tick.open; } chart[0].close = tick.close; if (chart[0].high < tick.high) { chart[0].high = tick.high; } if (chart[0].low > tick.low) { chart[0].low = tick.low; } if (timeChart !== chart1minName && !tick.isInitialized) { var _this$sumVolume2 = this.sumVolume(tickId, timeChart), _vol = _this$sumVolume2.vol, _amount = _this$sumVolume2.amount; chart[0].vol = _vol; chart[0].amount = _amount; } this.convertBBFirstTick(chart); } else if (tickId - chart[0].id === period) { chart.unshift(_objectSpread(_objectSpread({}, tick), {}, { chart_type: timeChart })); this.convertBBFirstTick(chart); } else if (!chart.findIndex(function (t) { return t.id === tickId; })) { throw new Error("Add wrong tick ts [".concat(timeChart, ", ").concat(tickId, ", ").concat(chart[0].id, "]")); } else if (timeChart === chart1minName) { if (chart[0].id - chart[1].id !== period) { throw new Error("Add wrong tick ts [".concat(timeChart, ", ").concat(tickId, ", ").concat(chart[0].id, "]")); } } if (timeChart === chart1minName) { var _this$getTicks = this.getTicks(), tick5min = _this$getTicks.tick5min, tick15min = _this$getTicks.tick15min, tick30min = _this$getTicks.tick30min, tick60min = _this$getTicks.tick60min, tick4hour = _this$getTicks.tick4hour, tick1day = _this$getTicks.tick1day; chart[0].ticks = { tick5min: _lodash["default"].clone(tick5min), tick15min: _lodash["default"].clone(tick15min), tick30min: _lodash["default"].clone(tick30min), tick60min: _lodash["default"].clone(tick60min), tick4hour: _lodash["default"].clone(tick4hour), tick1day: _lodash["default"].clone(tick1day) }; } if (chart.length > _constant.CHART_SIZE) { chart.pop(); } // this.calculateSAR(chart); return this.getCurrentTick(timeChart); } }, { key: "addTickToAllChart", value: function addTickToAllChart(tick) { this.addTickToChart(tick, _constant.TIME_CHART._1_MIN.name); this.addTickToChart(tick, _constant.TIME_CHART._5_MIN.name); this.addTickToChart(tick, _constant.TIME_CHART._15_MIN.name); this.addTickToChart(tick, _constant.TIME_CHART._30_MIN.name); this.addTickToChart(tick, _constant.TIME_CHART._60_MIN.name); this.addTickToChart(tick, _constant.TIME_CHART._4_HOUR.name); this.addTickToChart(tick, _constant.TIME_CHART._1_DAY.name); } }, { key: "getCurrentTick", value: function getCurrentTick() { var timeChart = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constant.TIME_CHART._1_MIN.name; var chart = this.chart[timeChart]; return chart[0]; } }, { key: "getPreviousTick", value: function getPreviousTick() { var timeChart = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constant.TIME_CHART._1_MIN.name; var chart = this.chart[timeChart]; return chart[1]; } }], [{ key: "generateTickIndicator", value: function generateTickIndicator(tickName, current, prev1, prev2) { return [].concat(_toConsumableArray((0, _util2.generateTickCompare)("".concat(tickName), prev2, prev1, current)), _toConsumableArray((0, _util2.generateTickSMACompareBB)("".concat(tickName, "_current"), 'close', current)), _toConsumableArray((0, _util2.generateTickSMACompareBB)("".concat(tickName, "_prev1"), 'close', prev1)), _toConsumableArray((0, _util2.generateTickSMACompareBB)("".concat(tickName, "_prev2"), 'close', prev2)), [(0, _util2.generateTickColor)("".concat(tickName), prev2, prev1, current), (0, _util2.generateTickBBPercentRange)("".concat(tickName, "_current"), current), (0, _util2.generateTickBBPercentRange)("".concat(tickName, "_prev1"), prev1), (0, _util2.generateTickBBPercentRange)("".concat(tickName, "_prev2"), prev2), (0, _util2.generateTickProfitPercentRange)("".concat(tickName, "_current"), current, current), (0, _util2.generateTickProfitPercentRange)("".concat(tickName, "_prev1"), prev1, current), (0, _util2.generateTickProfitPercentRange)("".concat(tickName, "_prev2"), prev2, current), (0, _util2.generateTickCandleSizeRange)("".concat(tickName, "_current"), current, current), (0, _util2.generateTickCandleSizeRange)("".concat(tickName, "_prev1"), prev1, current), (0, _util2.generateTickCandleSizeRange)("".concat(tickName, "_prev2"), prev2, current), (0, _util2.generateTickSMACompare51020)("".concat(tickName, "_current"), 'close', current), (0, _util2.generateTickSMACompare51020)("".concat(tickName, "_prev1"), 'close', prev1), (0, _util2.generateTickSMACompare51020)("".concat(tickName, "_prev2"), 'close', prev2)]); } }, { key: "generateTickIndicators", value: function generateTickIndicators(ticks) { var tick5minCurrent = ticks.tick5minCurrent, tick5minPrev1 = ticks.tick5minPrev1, tick5minPrev2 = ticks.tick5minPrev2, tick15minCurrent = ticks.tick15minCurrent, tick15minPrev1 = ticks.tick15minPrev1, tick15minPrev2 = ticks.tick15minPrev2, tick30minCurrent = ticks.tick30minCurrent, tick30minPrev1 = ticks.tick30minPrev1, tick30minPrev2 = ticks.tick30minPrev2, tick60minCurrent = ticks.tick60minCurrent, tick60minPrev1 = ticks.tick60minPrev1, tick60minPrev2 = ticks.tick60minPrev2, tick4hourCurrent = ticks.tick4hourCurrent, tick4hourPrev1 = ticks.tick4hourPrev1, tick4hourPrev2 = ticks.tick4hourPrev2, tick1dayCurrent = ticks.tick1dayCurrent, tick1dayPrev1 = ticks.tick1dayPrev1, tick1dayPrev2 = ticks.tick1dayPrev2; return [].concat(_toConsumableArray(CandlestickChart.generateTickIndicator('tick_5min', tick5minCurrent, tick5minPrev1, tick5minPrev2)), _toConsumableArray(CandlestickChart.generateTickIndicator('tick_15min', tick15minCurrent, tick15minPrev1, tick15minPrev2)), _toConsumableArray(CandlestickChart.generateTickIndicator('tick_30min', tick30minCurrent, tick30minPrev1, tick30minPrev2)), _toConsumableArray(CandlestickChart.generateTickIndicator('tick_60min', tick60minCurrent, tick60minPrev1, tick60minPrev2)), _toConsumableArray(CandlestickChart.generateTickIndicator('tick_4hour', tick4hourCurrent, tick4hourPrev1, tick4hourPrev2)), _toConsumableArray(CandlestickChart.generateTickIndicator('tick_1day', tick1dayCurrent, tick1dayPrev1, tick1dayPrev2))); } }, { key: "convertIndicatorToAlgo", value: function convertIndicatorToAlgo(index) { var matches = index.match(/tic[k\u212A]_((?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*?)_((?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*?)_((?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)/i); if (matches) { var _matches = _slicedToArray(matches, 4), tickName = _matches[1], tickType = _matches[2], tickArg = _matches[3]; if (tickType === 'color') { var _tickArg$match = tickArg.match(/((?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*?)_((?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*?)_((?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)/i), _tickArg$match2 = _slicedToArray(_tickArg$match, 4), prev2Color = _tickArg$match2[1], prev1Color = _tickArg$match2[2], color = _tickArg$match2[3]; return "prev2Tick".concat(tickName, ".color === '").concat(prev2Color, "' && prevTick").concat(tickName, ".color === '").concat(prev1Color, "' && tick").concat(tickName, ".color === '").concat(color, "'"); } if (tickType === 'straight') { var _tickArg$match3 = tickArg.match(/((?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*?)_([0-9]+)_([0-9]+)_([0-9]+)/i), _tickArg$match4 = _slicedToArray(_tickArg$match3, 5), type = _tickArg$match4[1], i2 = _tickArg$match4[2], i1 = _tickArg$match4[3], i = _tickArg$match4[4]; var ticks = { 0: 'tick', 1: 'prevTick', 2: 'prev2Tick' }; return "".concat(ticks[i2]).concat(tickName, ".").concat(type, " > ").concat(ticks[i1]).concat(tickName, ".").concat(type, " && ").concat(ticks[i1]).concat(tickName, ".").concat(type, " > ").concat(ticks[i]).concat(tickName, ".").concat(type); } if (['prev2', 'prev1', 'current'].includes(tickType)) { var tickTypes = { current: function current(name) { return "tick".concat(name); }, prev1: function prev1(name) { return "prevTick".concat(name); }, prev2: function prev2(name) { return "prev2Tick".concat(name); } }; var newTickName = tickTypes[tickType](tickName); if (tickArg.startsWith('bbp_range')) { var _tickArg$match5 = tickArg.match(/bbp_range_([0-9]+)/i), _tickArg$match6 = _slicedToArray(_tickArg$match5, 2), range = _tickArg$match6[1]; var tickRange = { 0: function _(name) { return "".concat(name, ".bb_percent <= 0"); }, 1: function _(name) { return "".concat(name, ".bb_percent <= 0.2 && ").concat(name, ".bb_percent > 0"); }, 2: function _(name) { return "".concat(name, ".bb_percent <= 0.4 && ").concat(name, ".bb_percent > 0.2"); }, 3: function _(name) { return "".concat(name, ".bb_percent <= 0.6 && ").concat(name, ".bb_percent > 0.4"); }, 4: function _(name) { return "".concat(name, ".bb_percent <= 0.8 && ").concat(name, ".bb_percent > 0.6"); }, 5: function _(name) { return "".concat(name, ".bb_percent <= 1 && ").concat(name, ".bb_percent > 0.8"); }, 6: function _(name) { return "".concat(name, ".bb_percent > 1"); } }; return tickRange[range](newTickName); } if (tickArg.startsWith('profit_per_range')) { var _tickArg$match7 = tickArg.match(/profit_per_range_(-?[0-9]*\.?[0-9]+)_(-?[0-9]*\.?[0-9]+)/i), _tickArg$match8 = _slicedToArray(_tickArg$match7, 3), _range = _tickArg$match8[1], currentRange = _tickArg$match8[2]; _range = Number(_range); currentRange = Number(currentRange); var condition1; var condition2; if (_range <= 0) { condition1 = "Math.floor(".concat(newTickName, ".profit_percent / 0.5) === ").concat(_range); if (_range <= -10) { condition1 = "Math.floor(".concat(newTickName, ".profit_percent / 0.5) <= -10"); } } else { condition1 = "Math.ceil(".concat(newTickName, ".profit_percent / 0.5) === ").concat(_range); if (_range >= 10) { condition1 = "Math.ceil(".concat(newTickName, ".profit_percent / 0.5) >= 10"); } } if (currentRange <= 0) { condition2 = "Math.floor(tick".concat(tickName, ".profit_percent / 0.5) === ").concat(currentRange); if (currentRange <= -10) { condition2 = "Math.floor(tick".concat(tickName, ".profit_percent / 0.5) <= -10"); } } else { condition2 = "Math.ceil(tick".concat(tickName, ".profit_percent / 0.5) === ").concat(currentRange); if (currentRange >= 10) { condition2 = "Math.ceil(tick".concat(tickName, ".profit_percent / 0.5) >= 10"); } } return "".concat(condition1, " && ").concat(condition2); } if (tickArg.startsWith('candle_size_range')) { var _tickArg$match9 = tickArg.match(/candle_[s\u017F]ize_range_(-?[0-9]*\.?[0-9]+)_(-?[0-9]*\.?[0-9]+)/i), _tickArg$match0 = _slicedToArray(_tickArg$match9, 3), _range2 = _tickArg$match0[1], _currentRange = _tickArg$match0[2]; _range2 = Number(_range2); _currentRange = Number(_currentRange); var _condition; var _condition2; if (_range2 <= 0) { _condition = "".concat(newTickName, ".color === 'RED' && Math.floor(").concat(newTickName, ".candle_size / 0.5) === ").concat(_range2); if (_range2 <= -10) { _condition = "".concat(newTickName, ".color === 'RED' && Math.floor(").concat(newTickName, ".candle_size / 0.5) <= -10"); } } else { _condition = "".concat(newTickName, ".color === 'GREEN' && Math.ceil(").concat(newTickName, ".candle_size / 0.5) === ").concat(_range2); if (_range2 >= 10) { _condition = "".concat(newTickName, ".color === 'GREEN' && Math.ceil(").concat(newTickName, ".candle_size / 0.5) >= 10"); } } if (_currentRange <= 0) { _condition2 = "tick".concat(tickName, ".color === 'RED' && Math.floor(tick").concat(tickName, ".candle_size / 0.5) === ").concat(_currentRange); if (_currentRange <= -10) { _condition2 = "tick".concat(tickName, ".color === 'RED' && Math.floor(tick").concat(tickName, ".candle_size / 0.5) <= -10"); } } else { _condition2 = "tick".concat(tickName, ".color === 'GREEN' && Math.ceil(tick").concat(tickName, ".candle_size / 0.5) === ").concat(_currentRange); if (_currentRange >= 10) { _condition2 = "tick".concat(tickName, ".color === 'GREEN' && Math.ceil(tick").concat(tickName, ".candle_size / 0.5) >= 10"); } } return "".concat(_condition, " && ").concat(_condition2); } if (tickArg.includes('sma_straight')) { var _tickArg$match1 = tickArg.match(/((?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*?)_[s\u017F]traight_([0-9]+)_([0-9]+)_([0-9]+)/i), _tickArg$match10 = _slicedToArray(_tickArg$match1, 5), _type = _tickArg$match10[1], ma1 = _tickArg$match10[2], ma2 = _tickArg$match10[3], ma3 = _tickArg$match10[4]; return "".concat(newTickName, ".").concat(_type, "_").concat(ma1, " > ").concat(newTickName, ".").concat(_type, "_").concat(ma2, " && ").concat(newTickName, ".").concat(_type, "_").concat(ma2, " > ").concat(newTickName, ".").concat(_type, "_").concat(ma3); } if (tickArg.includes('_bb_')) { var _tickArg$match11 = tickArg.match(/((?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*?)_bb_((?:[\0-\t\x0B\f\x0E-\u2027\u202A-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)/i), _tickArg$match12 = _slicedToArray(_tickArg$match11, 3), t = _tickArg$match12[1], p = _tickArg$match12[2]; var tickPositions = { TOP: function TOP(name, type) { return "".concat(name, ".").concat(type, " > ").concat(name, ".bb_upper_band"); }, ABOVE: function ABOVE(name, type) { return "".concat(name, ".").concat(type, " < ").concat(name, ".bb_upper_band && ").concat(name, ".").concat(type, " > ").concat(name, ".bb_sma"); }, BELOW: function BELOW(name, type) { return "".concat(name, ".").concat(type, " > ").concat(name, ".bb_lower_band && ").concat(name, ".").concat(type, " < ").concat(name, ".bb_sma"); }, BOTTOM: function BOTTOM(name, type) { return "".concat(name, ".").concat(type, " < ").concat(name, ".bb_lower_band"); } }; return tickPositions[p](newTickName, t); } } } return 'fail'; } }]); }(); var _default = exports["default"] = CandlestickChart;