UNPKG

@dickyindra/klinecharts

Version:

Lightweight k-line chart built with html5 canvas

1,876 lines (1,674 loc) 558 kB
/** * @license * KLineChart v8.3.6-7 * Copyright (c) 2019 lihu. * Licensed under Apache License 2.0 https://www.apache.org/licenses/LICENSE-2.0 */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.klinecharts = {})); })(this, (function (exports) { 'use strict'; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * 成交均线 */ var averagePrice = { name: 'AVP', shortName: 'AVP', series: 'price', precision: 2, plots: [{ key: 'avp', title: 'AVP: ', type: 'line' }], calcTechnicalIndicator: function calcTechnicalIndicator(dataList) { var totalTurnover = 0; var totalVolume = 0; return dataList.map(function (kLineData) { var avp = {}; var turnover = kLineData.turnover || 0; var volume = kLineData.volume || 0; totalTurnover += turnover; totalVolume += volume; if (totalVolume !== 0) { avp.avp = totalTurnover / totalVolume; } return avp; }); } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * 多空指标 * 公式: BBI = (MA(CLOSE, M) + MA(CLOSE, N) + MA(CLOSE, O) + MA(CLOSE, P)) / 4 * */ var bullAndBearIndex = { name: 'BBI', shortName: 'BBI', series: 'price', precision: 2, calcParams: [3, 6, 12, 24], shouldCheckParamCount: true, shouldOhlc: true, plots: [{ key: 'bbi', title: 'BBI: ', type: 'line' }], calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params; var maxPeriod = Math.max.apply(null, params); var closeSums = []; var mas = []; return dataList.map(function (kLineData, i) { var bbi = {}; var close = kLineData.close; params.forEach(function (p, index) { closeSums[index] = (closeSums[index] || 0) + close; if (i >= p - 1) { mas[index] = closeSums[index] / p; closeSums[index] -= dataList[i - (p - 1)].close; } }); if (i >= maxPeriod - 1) { var maSum = 0; mas.forEach(function (ma) { maSum += ma; }); bbi.bbi = maSum / 4; } return bbi; }); } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * DMA * 公式:DIF:MA(CLOSE,N1)-MA(CLOSE,N2);DIFMA:MA(DIF,M) */ var differentOfMovingAverage = { name: 'DMA', shortName: 'DMA', calcParams: [10, 50, 10], plots: [{ key: 'dma', title: 'DMA: ', type: 'line' }, { key: 'ama', title: 'AMA: ', type: 'line' }], calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params; var maxPeriod = Math.max(params[0], params[1]); var closeSum1 = 0; var closeSum2 = 0; var dmaSum = 0; var result = []; dataList.forEach(function (kLineData, i) { var dma = {}; var close = kLineData.close; closeSum1 += close; closeSum2 += close; var ma1; var ma2; if (i >= params[0] - 1) { ma1 = closeSum1 / params[0]; closeSum1 -= dataList[i - (params[0] - 1)].close; } if (i >= params[1] - 1) { ma2 = closeSum2 / params[1]; closeSum2 -= dataList[i - (params[1] - 1)].close; } if (i >= maxPeriod - 1) { var dif = ma1 - ma2; dma.dma = dif; dmaSum += dif; if (i >= maxPeriod + params[2] - 2) { dma.ama = dmaSum / params[2]; dmaSum -= result[i - (params[2] - 1)].dma; } } result.push(dma); }); return result; } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * DMI * * MTR:=EXPMEMA(MAX(MAX(HIGH-LOW,ABS(HIGH-REF(CLOSE,1))),ABS(REF(CLOSE,1)-LOW)),N) * HD :=HIGH-REF(HIGH,1); * LD :=REF(LOW,1)-LOW; * DMP:=EXPMEMA(IF(HD>0&&HD>LD,HD,0),N); * DMM:=EXPMEMA(IF(LD>0&&LD>HD,LD,0),N); * * PDI: DMP*100/MTR; * MDI: DMM*100/MTR; * ADX: EXPMEMA(ABS(MDI-PDI)/(MDI+PDI)*100,MM); * ADXR:EXPMEMA(ADX,MM); * 公式含义: * MTR赋值:最高价-最低价和最高价-昨收的绝对值的较大值和昨收-最低价的绝对值的较大值的N日指数平滑移动平均 * HD赋值:最高价-昨日最高价 * LD赋值:昨日最低价-最低价 * DMP赋值:如果HD>0并且HD>LD,返回HD,否则返回0的N日指数平滑移动平均 * DMM赋值:如果LD>0并且LD>HD,返回LD,否则返回0的N日指数平滑移动平均 * 输出PDI:DMP*100/MTR * 输出MDI:DMM*100/MTR * 输出ADX:MDI-PDI的绝对值/(MDI+PDI)*100的MM日指数平滑移动平均 * 输出ADXR:ADX的MM日指数平滑移动平均 * */ var directionalMovementIndex = { name: 'DMI', shortName: 'DMI', calcParams: [14, 6], plots: [{ key: 'pdi', title: 'PDI: ', type: 'line' }, { key: 'mdi', title: 'MDI: ', type: 'line' }, { key: 'adx', title: 'ADX: ', type: 'line' }, { key: 'adxr', title: 'ADXR: ', type: 'line' }], calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params; var trSum = 0; var hSum = 0; var lSum = 0; var mtr = 0; var dmp = 0; var dmm = 0; var dxSum = 0; var adx = 0; var result = []; dataList.forEach(function (kLineData, i) { var dmi = {}; var preKLineData = dataList[i - 1] || kLineData; var preClose = preKLineData.close; var high = kLineData.high; var low = kLineData.low; var hl = high - low; var hcy = Math.abs(high - preClose); var lcy = Math.abs(preClose - low); var hhy = high - preKLineData.high; var lyl = preKLineData.low - low; var tr = Math.max(Math.max(hl, hcy), lcy); var h = hhy > 0 && hhy > lyl ? hhy : 0; var l = lyl > 0 && lyl > hhy ? lyl : 0; trSum += tr; hSum += h; lSum += l; if (i >= params[0] - 1) { if (i > params[0] - 1) { mtr = mtr - mtr / params[0] + tr; dmp = dmp - dmp / params[0] + h; dmm = dmm - dmm / params[0] + l; } else { mtr = trSum; dmp = hSum; dmm = lSum; } var pdi = 0; var mdi = 0; if (mtr !== 0) { pdi = dmp * 100 / mtr; mdi = dmm * 100 / mtr; } dmi.pdi = pdi; dmi.mdi = mdi; var dx = 0; if (mdi + pdi !== 0) { dx = Math.abs(mdi - pdi) / (mdi + pdi) * 100; } dxSum += dx; if (i >= params[0] * 2 - 2) { if (i > params[0] * 2 - 2) { adx = (adx * (params[0] - 1) + dx) / params[0]; } else { adx = dxSum / params[0]; } dmi.adx = adx; if (i >= params[0] * 2 + params[1] - 3) { dmi.adxr = (result[i - (params[1] - 1)].adx + adx) / 2; } } } result.push(dmi); }); return result; } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * * EMV 简易波动指标 * 公式: * A=(今日最高+今日最低)/2 * B=(前日最高+前日最低)/2 * C=今日最高-今日最低 * EM=(A-B)*C/今日成交额 * EMV=N日内EM的累和 * MAEMV=EMV的M日的简单移动平均 * */ var easeOfMovementValue = { name: 'EMV', shortName: 'EMV', calcParams: [14, 9], plots: [{ key: 'emv', title: 'EMV: ', type: 'line' }, { key: 'maEmv', title: 'MAEMV: ', type: 'line' }], calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params; var emSum = 0; var emvSum = 0; var emList = []; var result = []; dataList.forEach(function (kLineData, i) { var emv = {}; var preKLineData = dataList[i - 1] || kLineData; var high = kLineData.high; var low = kLineData.low; var turnover = kLineData.turnover || 0; var halfHl = (high + low) / 2; var preHalfHl = (preKLineData.high + preKLineData.low) / 2; var hl = high - low; var em = 0; if (turnover !== 0) { em = (halfHl - preHalfHl) * hl / turnover; } emList.push(em); emSum += em; if (i >= params[0] - 1) { emv.emv = emSum; emSum -= emList[i - (params[0] - 1)]; emvSum += emv.emv; if (i >= params[0] + params[1] - 2) { emv.maEmv = emvSum / params[1]; emvSum -= result[i - (params[1] - 1)].emv; } } result.push(emv); }); return result; } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * EMA 指数移动平均 */ var exponentialMovingAverage = { name: 'EMA', shortName: 'EMA', series: 'price', calcParams: [6, 12, 20], precision: 2, shouldCheckParamCount: false, shouldOhlc: true, plots: [{ key: 'ema6', title: 'EMA6: ', type: 'line' }, { key: 'ema12', title: 'EMA12: ', type: 'line' }, { key: 'ema20', title: 'EMA20: ', type: 'line' }], regeneratePlots: function regeneratePlots(params) { return params.map(function (p) { return { key: "ema".concat(p), title: "EMA".concat(p, ": "), type: 'line' }; }); }, calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params, plots = _ref.plots; var closeSum = 0; var emaValues = []; return dataList.map(function (kLineData, i) { var ema = {}; var close = kLineData.close; closeSum += close; params.forEach(function (p, index) { if (i >= p - 1) { if (i > p - 1) { emaValues[index] = (2 * close + (p - 1) * emaValues[index]) / (p + 1); } else { emaValues[index] = closeSum / p; } ema[plots[index].key] = emaValues[index]; } }); return ema; }); } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * MA 移动平均 */ var movingAverage = { name: 'MA', shortName: 'MA', series: 'price', calcParams: [5, 10, 30, 60], precision: 2, shouldCheckParamCount: false, shouldOhlc: true, plots: [{ key: 'ma5', title: 'MA5: ', type: 'line' }, { key: 'ma10', title: 'MA10: ', type: 'line' }, { key: 'ma30', title: 'MA30: ', type: 'line' }, { key: 'ma60', title: 'MA60: ', type: 'line' }], regeneratePlots: function regeneratePlots(params) { return params.map(function (p) { return { key: "ma".concat(p), title: "MA".concat(p, ": "), type: 'line' }; }); }, calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params, plots = _ref.plots; var closeSums = []; return dataList.map(function (kLineData, i) { var ma = {}; var close = kLineData.close; params.forEach(function (p, index) { closeSums[index] = (closeSums[index] || 0) + close; if (i >= p - 1) { ma[plots[index].key] = closeSums[index] / p; closeSums[index] -= dataList[i - (p - 1)].close; } }); return ma; }); } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * MACD:参数快线移动平均、慢线移动平均、移动平均, * 默认参数值12、26、9。 * 公式:⒈首先分别计算出收盘价12日指数平滑移动平均线与26日指数平滑移动平均线,分别记为EMA(12)与EMA(26)。 * ⒉求这两条指数平滑移动平均线的差,即:DIFF = EMA(SHORT) - EMA(LONG)。 * ⒊再计算DIFF的M日的平均的指数平滑移动平均线,记为DEA。 * ⒋最后用DIFF减DEA,得MACD。MACD通常绘制成围绕零轴线波动的柱形图。MACD柱状大于0涨颜色,小于0跌颜色。 */ var movingAverageConvergenceDivergence = { name: 'MACD', shortName: 'MACD', calcParams: [12, 26, 9], plots: [{ key: 'dif', title: 'DIF: ', type: 'line' }, { key: 'dea', title: 'DEA: ', type: 'line' }, { key: 'macd', title: 'MACD: ', type: 'bar', baseValue: 0, color: function color(data, options) { var current = data.current; var macd = (current.technicalIndicatorData || {}).macd; if (macd > 0) { return options.bar.upColor; } else if (macd < 0) { return options.bar.downColor; } else { return options.bar.noChangeColor; } }, isStroke: function isStroke(data) { var prev = data.prev, current = data.current; var macd = (current.technicalIndicatorData || {}).macd; var preMacd = (prev.technicalIndicatorData || {}).macd; return preMacd < macd; } }], calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params; var closeSum = 0; var emaShort; var emaLong; var dif = 0; var difSum = 0; var dea = 0; var maxPeriod = Math.max(params[0], params[1]); return dataList.map(function (kLineData, i) { var macd = {}; var close = kLineData.close; closeSum += close; if (i >= params[0] - 1) { if (i > params[0] - 1) { emaShort = (2 * close + (params[0] - 1) * emaShort) / (params[0] + 1); } else { emaShort = closeSum / params[0]; } } if (i >= params[1] - 1) { if (i > params[1] - 1) { emaLong = (2 * close + (params[1] - 1) * emaLong) / (params[1] + 1); } else { emaLong = closeSum / params[1]; } } if (i >= maxPeriod - 1) { dif = emaShort - emaLong; macd.dif = dif; difSum += dif; if (i >= maxPeriod + params[2] - 2) { if (i > maxPeriod + params[2] - 2) { dea = (dif * 2 + dea * (params[2] - 1)) / (params[2] + 1); } else { dea = difSum / params[2]; } macd.macd = (dif - dea) * 2; macd.dea = dea; } } return macd; }); } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * sma */ var simpleMovingAverage = { name: 'SMA', shortName: 'SMA', series: 'price', calcParams: [12, 2], precision: 2, plots: [{ key: 'sma', title: 'SMA: ', type: 'line' }], shouldCheckParamCount: true, shouldOhlc: true, calcTechnicalIndicator: function calcTechnicalIndicator(kLineDataList, _ref) { var params = _ref.params; var closeSum = 0; var smaValue = 0; return kLineDataList.map(function (kLineData, i) { var sma = {}; var close = kLineData.close; closeSum += close; if (i >= params[0] - 1) { if (i > params[0] - 1) { smaValue = (close * params[1] + smaValue * (params[0] - params[1] + 1)) / (params[0] + 1); } else { smaValue = closeSum / params[0]; } sma.sma = smaValue; } return sma; }); } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http:*www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * trix * * TR=收盘价的N日指数移动平均的N日指数移动平均的N日指数移动平均; * TRIX=(TR-昨日TR)/昨日TR*100; * MATRIX=TRIX的M日简单移动平均; * 默认参数N设为12,默认参数M设为9; * 默认参数12、9 * 公式:MTR:=EMA(EMA(EMA(CLOSE,N),N),N) * TRIX:(MTR-REF(MTR,1))/REF(MTR,1)*100; * TRMA:MA(TRIX,M) * */ var tripleExponentiallySmoothedAverage = { name: 'TRIX', shortName: 'TRIX', calcParams: [12, 9], plots: [{ key: 'trix', title: 'TRIX: ', type: 'line' }, { key: 'maTrix', title: 'MATRIX: ', type: 'line' }], calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params; var closeSum = 0; var ema1; var ema2; var oldTr; var ema1Sum = 0; var ema2Sum = 0; var trixSum = 0; var result = []; dataList.forEach(function (kLineData, i) { var trix = {}; var close = kLineData.close; closeSum += close; if (i >= params[0] - 1) { if (i > params[0] - 1) { ema1 = (2 * close + (params[0] - 1) * ema1) / (params[0] + 1); } else { ema1 = closeSum / params[0]; } ema1Sum += ema1; if (i >= params[0] * 2 - 2) { if (i > params[0] * 2 - 2) { ema2 = (2 * ema1 + (params[0] - 1) * ema2) / (params[0] + 1); } else { ema2 = ema1Sum / params[0]; } ema2Sum += ema2; if (i >= params[0] * 3 - 3) { var tr; var trixValue = 0; if (i > params[0] * 3 - 3) { tr = (2 * ema2 + (params[0] - 1) * oldTr) / (params[0] + 1); trixValue = (tr - oldTr) / oldTr * 100; } else { tr = ema2Sum / params[0]; } oldTr = tr; trix.trix = trixValue; trixSum += trixValue; if (i >= params[0] * 3 + params[1] - 4) { trix.maTrix = trixSum / params[1]; trixSum -= result[i - (params[1] - 1)].trix; } } } } result.push(trix); }); return result; } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * BRAR * 默认参数是26。 * 公式N日BR=N日内(H-CY)之和除以N日内(CY-L)之和*100, * 其中,H为当日最高价,L为当日最低价,CY为前一交易日的收盘价,N为设定的时间参数。 * N日AR=(N日内(H-O)之和除以N日内(O-L)之和)*100, * 其中,H为当日最高价,L为当日最低价,O为当日开盘价,N为设定的时间参数 * */ var brar = { name: 'BRAR', shortName: 'BRAR', calcParams: [26], plots: [{ key: 'br', title: 'BR: ', type: 'line' }, { key: 'ar', title: 'AR: ', type: 'line' }], calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params; var hcy = 0; var cyl = 0; var ho = 0; var ol = 0; return dataList.map(function (kLineData, i) { var brar = {}; var high = kLineData.high; var low = kLineData.low; var open = kLineData.open; var preClose = (dataList[i - 1] || kLineData).close; ho += high - open; ol += open - low; hcy += high - preClose; cyl += preClose - low; if (i >= params[0] - 1) { if (ol !== 0) { brar.ar = ho / ol * 100; } else { brar.ar = 0; } if (cyl !== 0) { brar.br = hcy / cyl * 100; } else { brar.br = 0; } var agoKLineData = dataList[i - (params[0] - 1)]; var agoHigh = agoKLineData.high; var agoLow = agoKLineData.low; var agoOpen = agoKLineData.open; var agoPreClose = (dataList[i - params[0]] || dataList[i - (params[0] - 1)]).close; hcy -= agoHigh - agoPreClose; cyl -= agoPreClose - agoLow; ho -= agoHigh - agoOpen; ol -= agoOpen - agoLow; } return brar; }); } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http:*www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * MID:=REF(HIGH+LOW,1)/2; * CR:SUM(MAX(0,HIGH-MID),N)/SUM(MAX(0,MID-LOW),N)*100; * MA1:REF(MA(CR,M1),M1/2.5+1); * MA2:REF(MA(CR,M2),M2/2.5+1); * MA3:REF(MA(CR,M3),M3/2.5+1); * MA4:REF(MA(CR,M4),M4/2.5+1); * MID赋值:(昨日最高价+昨日最低价)/2 * 输出带状能量线:0和最高价-MID的较大值的N日累和/0和MID-最低价的较大值的N日累和*100 * 输出MA1:M1(5)/2.5+1日前的CR的M1(5)日简单移动平均 * 输出MA2:M2(10)/2.5+1日前的CR的M2(10)日简单移动平均 * 输出MA3:M3(20)/2.5+1日前的CR的M3(20)日简单移动平均 * 输出MA4:M4/2.5+1日前的CR的M4日简单移动平均 * */ var currentRatio = { name: 'CR', shortName: 'CR', calcParams: [26, 10, 20, 40, 60], plots: [{ key: 'cr', title: 'CR: ', type: 'line' }, { key: 'ma1', title: 'MA1: ', type: 'line' }, { key: 'ma2', title: 'MA2: ', type: 'line' }, { key: 'ma3', title: 'MA3: ', type: 'line' }, { key: 'ma4', title: 'MA4: ', type: 'line' }], calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params; var ma1ForwardPeriod = Math.ceil(params[1] / 2.5 + 1); var ma2ForwardPeriod = Math.ceil(params[2] / 2.5 + 1); var ma3ForwardPeriod = Math.ceil(params[3] / 2.5 + 1); var ma4ForwardPeriod = Math.ceil(params[4] / 2.5 + 1); var ma1Sum = 0; var ma1List = []; var ma2Sum = 0; var ma2List = []; var ma3Sum = 0; var ma3List = []; var ma4Sum = 0; var ma4List = []; var result = []; dataList.forEach(function (kLineData, i) { var cr = {}; var preData = dataList[i - 1] || kLineData; var preMid = (preData.high + preData.close + preData.low + preData.open) / 4; var highSubPreMid = Math.max(0, kLineData.high - preMid); var preMidSubLow = Math.max(0, preMid - kLineData.low); if (i >= params[0] - 1) { if (preMidSubLow !== 0) { cr.cr = highSubPreMid / preMidSubLow * 100; } else { cr.cr = 0; } ma1Sum += cr.cr; ma2Sum += cr.cr; ma3Sum += cr.cr; ma4Sum += cr.cr; if (i >= params[0] + params[1] - 2) { ma1List.push(ma1Sum / params[1]); if (i >= params[0] + params[1] + ma1ForwardPeriod - 3) { cr.ma1 = ma1List[ma1List.length - 1 - ma1ForwardPeriod]; } ma1Sum -= result[i - (params[1] - 1)].cr; } if (i >= params[0] + params[2] - 2) { ma2List.push(ma2Sum / params[2]); if (i >= params[0] + params[2] + ma2ForwardPeriod - 3) { cr.ma2 = ma2List[ma2List.length - 1 - ma2ForwardPeriod]; } ma2Sum -= result[i - (params[2] - 1)].cr; } if (i >= params[0] + params[3] - 2) { ma3List.push(ma3Sum / params[3]); if (i >= params[0] + params[3] + ma3ForwardPeriod - 3) { cr.ma3 = ma3List[ma3List.length - 1 - ma3ForwardPeriod]; } ma3Sum -= result[i - (params[3] - 1)].cr; } if (i >= params[0] + params[4] - 2) { ma4List.push(ma4Sum / params[4]); if (i >= params[0] + params[4] + ma4ForwardPeriod - 3) { cr.ma4 = ma4List[ma4List.length - 1 - ma4ForwardPeriod]; } ma4Sum -= result[i - (params[4] - 1)].cr; } } result.push(cr); }); return result; } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * mtm * 公式 MTM(N日)=C-CN */ var momentum = { name: 'MTM', shortName: 'MTM', calcParams: [12, 6], plots: [{ key: 'mtm', title: 'MTM: ', type: 'line' }, { key: 'maMtm', title: 'MAMTM: ', type: 'line' }], calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params; var mtmSum = 0; var result = []; dataList.forEach(function (kLineData, i) { var mtm = {}; if (i >= params[0]) { var close = kLineData.close; var agoClose = dataList[i - params[0]].close; mtm.mtm = close - agoClose; mtmSum += mtm.mtm; if (i >= params[0] + params[1] - 1) { mtm.maMtm = mtmSum / params[1]; mtmSum -= result[i - (params[1] - 1)].mtm; } } result.push(mtm); }); return result; } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * PSY * 公式:PSY=N日内的上涨天数/N×100%。 */ var psychologicalLine = { name: 'PSY', shortName: 'PSY', calcParams: [12, 6], plots: [{ key: 'psy', title: 'PSY: ', type: 'line' }, { key: 'maPsy', title: 'MAPSY: ', type: 'line' }], calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params; var upCount = 0; var psySum = 0; var upList = []; var result = []; dataList.forEach(function (kLineData, i) { var psy = {}; var preClose = (dataList[i - 1] || kLineData).close; var upFlag = kLineData.close - preClose > 0 ? 1 : 0; upList.push(upFlag); upCount += upFlag; if (i >= params[0] - 1) { psy.psy = upCount / params[0] * 100; psySum += psy.psy; if (i >= params[0] + params[1] - 2) { psy.maPsy = psySum / params[1]; psySum -= result[i - (params[1] - 1)].psy; } upCount -= upList[i - (params[0] - 1)]; } result.push(psy); }); return result; } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * 变动率指标 * 公式:ROC = (CLOSE - REF(CLOSE, N)) / REF(CLOSE, N) */ var rateOfChange = { name: 'ROC', shortName: 'ROC', calcParams: [12, 6], shouldCheckParamCount: true, plots: [{ key: 'roc', title: 'ROC: ', type: 'line' }, { key: 'maRoc', title: 'MAROC: ', type: 'line' }], calcTechnicalIndicator: function calcTechnicalIndicator(kLineDataList, _ref) { var params = _ref.params; var result = []; var rocSum = 0; kLineDataList.forEach(function (kLineData, i) { var roc = {}; if (i >= params[0] - 1) { var close = kLineData.close; var agoClose = (kLineDataList[i - params[0]] || kLineDataList[i - (params[0] - 1)]).close; if (agoClose !== 0) { roc.roc = (close - agoClose) / agoClose * 100; } else { roc.roc = 0; } rocSum += roc.roc; if (i >= params[0] - 1 + params[1] - 1) { roc.maRoc = rocSum / params[1]; rocSum -= result[i - (params[1] - 1)].roc; } } result.push(roc); }); return result; } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * VR * VR=(UVS+1/2PVS)/(DVS+1/2PVS) * 24天以来凡是股价上涨那一天的成交量都称为AV,将24天内的AV总和相加后称为UVS * 24天以来凡是股价下跌那一天的成交量都称为BV,将24天内的BV总和相加后称为DVS * 24天以来凡是股价不涨不跌,则那一天的成交量都称为CV,将24天内的CV总和相加后称为PVS * */ var volumeRatio = { name: 'VR', shortName: 'VR', calcParams: [26, 6], plots: [{ key: 'vr', title: 'VR: ', type: 'line' }, { key: 'maVr', title: 'MAVR: ', type: 'line' }], calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params; var uvs = 0; var dvs = 0; var pvs = 0; var vrSum = 0; var result = []; dataList.forEach(function (kLineData, i) { var vr = {}; var close = kLineData.close; var preClose = (dataList[i - 1] || kLineData).close; var volume = kLineData.volume; if (close > preClose) { uvs += volume; } else if (close < preClose) { dvs += volume; } else { pvs += volume; } if (i >= params[0] - 1) { var halfPvs = pvs / 2; if (dvs + halfPvs === 0) { vr.vr = 0; } else { vr.vr = (uvs + halfPvs) / (dvs + halfPvs) * 100; } vrSum += vr.vr; if (i >= params[0] + params[1] - 2) { vr.maVr = vrSum / params[1]; vrSum -= result[i - (params[1] - 1)].vr; } var agoData = dataList[i - (params[0] - 1)]; var agoPreData = dataList[i - params[0]] || agoData; var agoClose = agoData.close; var agoVolume = agoData.volume; if (agoClose > agoPreData.close) { uvs -= agoVolume; } else if (agoClose < agoPreData.close) { dvs -= agoVolume; } else { pvs -= agoVolume; } } result.push(vr); }); return result; } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var awesomeOscillator = { name: 'AO', shortName: 'AO', calcParams: [5, 34], shouldCheckParamCount: true, plots: [{ key: 'ao', title: 'AO: ', type: 'bar', baseValue: 0, color: function color(data, options) { var prev = data.prev, current = data.current; var preAo = (prev.technicalIndicatorData || {}).ao; var ao = (current.technicalIndicatorData || {}).ao; if (ao > preAo) { return options.bar.upColor; } else { return options.bar.downColor; } }, isStroke: function isStroke(data) { var prev = data.prev, current = data.current; var preAo = (prev.technicalIndicatorData || {}).ao; var ao = (current.technicalIndicatorData || {}).ao; return ao > preAo; } }], calcTechnicalIndicator: function calcTechnicalIndicator(kLineDataList, _ref) { var params = _ref.params; var maxPeriod = Math.max(params[0], params[1]); var shortSum = 0; var longSum = 0; var short = 0; var long = 0; return kLineDataList.map(function (kLineData, i) { var ao = {}; var middle = (kLineData.low + kLineData.high) / 2; shortSum += middle; longSum += middle; if (i >= params[0] - 1) { short = shortSum / params[0]; var agoKLineData = kLineDataList[i - (params[0] - 1)]; shortSum -= (agoKLineData.low + agoKLineData.high) / 2; } if (i >= params[1] - 1) { long = longSum / params[1]; var _agoKLineData = kLineDataList[i - (params[1] - 1)]; longSum -= (_agoKLineData.low + _agoKLineData.high) / 2; } if (i >= maxPeriod - 1) { ao.ao = short - long; } return ao; }); } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * BIAS * 乖离率=[(当日收盘价-N日平均价)/N日平均价]*100% */ var bias = { name: 'BIAS', shortName: 'BIAS', calcParams: [6, 12, 24], shouldCheckParamCount: false, plots: [{ key: 'bias6', title: 'BIAS6: ', type: 'line' }, { key: 'bias12', title: 'BIAS12: ', type: 'line' }, { key: 'bias24', title: 'BIAS24: ', type: 'line' }], regeneratePlots: function regeneratePlots(params) { return params.map(function (p) { return { key: "bias".concat(p), title: "BIAS".concat(p, ": "), type: 'line' }; }); }, calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params, plots = _ref.plots; var closeSums = []; return dataList.map(function (kLineData, i) { var bias = {}; var close = kLineData.close; params.forEach(function (p, index) { closeSums[index] = (closeSums[index] || 0) + close; if (i >= p - 1) { var mean = closeSums[index] / params[index]; bias[plots[index].key] = (close - mean) / mean * 100; closeSums[index] -= dataList[i - (p - 1)].close; } }); return bias; }); } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * CCI * CCI(N日)=(TP-MA)÷MD÷0.015 * 其中,TP=(最高价+最低价+收盘价)÷3 * MA=近N日TP价的累计之和÷N * MD=近N日TP - 当前MA绝对值的累计之和÷N * */ var commodityChannelIndex = { name: 'CCI', shortName: 'CCI', calcParams: [20], plots: [{ key: 'cci', title: 'CCI: ', type: 'line' }], calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params; var p = params[0] - 1; var tpSum = 0; var tpList = []; return dataList.map(function (kLineData, i) { var cci = {}; var tp = (kLineData.high + kLineData.low + kLineData.close) / 3; tpSum += tp; tpList.push(tp); if (i >= p) { var maTp = tpSum / params[0]; var sliceTpList = tpList.slice(i - p, i + 1); var sum = 0; sliceTpList.forEach(function (tp) { sum += Math.abs(tp - maTp); }); var md = sum / params[0]; cci.cci = md !== 0 ? (tp - maTp) / md / 0.015 : 0; var agoTp = (dataList[i - p].high + dataList[i - p].low + dataList[i - p].close) / 3; tpSum -= agoTp; } return cci; }); } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * RSI * RSI = SUM(MAX(CLOSE - REF(CLOSE,1),0),N) / SUM(ABS(CLOSE - REF(CLOSE,1)),N) × 100 */ var relativeStrengthIndex = { name: 'RSI', shortName: 'RSI', calcParams: [6, 12, 24], shouldCheckParamCount: false, plots: [{ key: 'rsi1', title: 'RSI1: ', type: 'line' }, { key: 'rsi2', title: 'RSI2: ', type: 'line' }, { key: 'rsi3', title: 'RSI3: ', type: 'line' }], regeneratePlots: function regeneratePlots(params) { return params.map(function (_, index) { var num = index + 1; return { key: "rsi".concat(num), title: "RSI".concat(num, ": "), type: 'line' }; }); }, calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params, plots = _ref.plots; var sumCloseAs = []; var sumCloseBs = []; return dataList.map(function (kLineData, i) { var rsi = {}; var preClose = (dataList[i - 1] || kLineData).close; var tmp = kLineData.close - preClose; params.forEach(function (p, index) { if (tmp > 0) { sumCloseAs[index] = (sumCloseAs[index] || 0) + tmp; } else { sumCloseBs[index] = (sumCloseBs[index] || 0) + Math.abs(tmp); } if (i >= p - 1) { if (sumCloseBs[index] !== 0) { rsi[plots[index].key] = 100 - 100.0 / (1 + sumCloseAs[index] / sumCloseBs[index]); } else { rsi[plots[index].key] = 0; } var agoData = dataList[i - (p - 1)]; var agoPreData = dataList[i - p] || agoData; var agoTmp = agoData.close - agoPreData.close; if (agoTmp > 0) { sumCloseAs[index] -= agoTmp; } else { sumCloseBs[index] -= Math.abs(agoTmp); } } }); return rsi; }); } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * 计算n周期内最高和最低 * @param dataList * @returns {{ln: number, hn: number}} */ function calcHnLn() { var dataList = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; var hn = Number.MIN_SAFE_INTEGER; var ln = Number.MAX_SAFE_INTEGER; dataList.forEach(function (data) { hn = Math.max(data.high, hn); ln = Math.min(data.low, ln); }); return { hn: hn, ln: ln }; } /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * KDJ * * 当日K值=2/3×前一日K值+1/3×当日RSV * 当日D值=2/3×前一日D值+1/3×当日K值 * 若无前一日K 值与D值,则可分别用50来代替。 * J值=3*当日K值-2*当日D值 */ var stockIndicatorKDJ = { name: 'KDJ', shortName: 'KDJ', calcParams: [9, 3, 3], plots: [{ key: 'k', title: 'K: ', type: 'line' }, { key: 'd', title: 'D: ', type: 'line' }, { key: 'j', title: 'J: ', type: 'line' }], calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params; var result = []; dataList.forEach(function (kLineData, i) { var kdj = {}; var close = kLineData.close; if (i >= params[0] - 1) { var lhn = calcHnLn(dataList.slice(i - (params[0] - 1), i + 1)); var ln = lhn.ln; var hn = lhn.hn; var hnSubLn = hn - ln; var rsv = (close - ln) / (hnSubLn === 0 ? 1 : hnSubLn) * 100; kdj.k = ((params[1] - 1) * (result[i - 1].k || 50) + rsv) / params[1]; kdj.d = ((params[2] - 1) * (result[i - 1].d || 50) + kdj.k) / params[2]; kdj.j = 3.0 * kdj.k - 2.0 * kdj.d; } result.push(kdj); }); return result; } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * WR * 公式 WR(N) = 100 * [ C - HIGH(N) ] / [ HIGH(N)-LOW(N) ] */ var williamsR = { name: 'WR', shortName: 'WR', calcParams: [6, 10, 14], shouldCheckParamCount: false, plots: [{ key: 'wr1', title: 'WR1: ', type: 'line' }, { key: 'wr2', title: 'WR2: ', type: 'line' }, { key: 'wr3', title: 'WR3: ', type: 'line' }], regeneratePlots: function regeneratePlots(params) { return params.map(function (_, i) { return { key: "wr".concat(i + 1), title: "WR".concat(i + 1, ": "), type: 'line' }; }); }, calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params, plots = _ref.plots; return dataList.map(function (kLineData, i) { var wr = {}; var close = kLineData.close; params.forEach(function (param, index) { var p = param - 1; if (i >= p) { var hln = calcHnLn(dataList.slice(i - p, i + 1)); var hn = hln.hn; var ln = hln.ln; var hnSubLn = hn - ln; wr[plots[index].key] = hnSubLn === 0 ? 0 : (close - hn) / hnSubLn * 100; } }); return wr; }); } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * 计算布林指标中的标准差 * @param dataList * @param ma * @return {number} */ function getBollMd(dataList, ma) { var dataSize = dataList.length; var sum = 0; dataList.forEach(function (data) { var closeMa = data.close - ma; sum += closeMa * closeMa; }); var b = sum > 0; sum = Math.abs(sum); var md = Math.sqrt(sum / dataSize); return b ? md : -1 * md; } /** * BOLL */ var bollingerBands = { name: 'BOLL', shortName: 'BOLL', calcParams: [20, { value: 2, allowDecimal: true }], precision: 2, shouldOhlc: true, plots: [{ key: 'up', title: 'UP: ', type: 'line' }, { key: 'mid', title: 'MID: ', type: 'line' }, { key: 'dn', title: 'DN: ', type: 'line' }], calcTechnicalIndicator: function calcTechnicalIndicator(dataList, _ref) { var params = _ref.params; var p = params[0] - 1; var closeSum = 0; return dataList.map(function (kLineData, i) { var close = kLineData.close; var boll = {}; closeSum += close; if (i >= p) { boll.mid = closeSum / params[0]; var md = getBollMd(dataList.slice(i - p, i + 1), boll.mid); boll.up = boll.mid + params[1] * md; boll.dn = boll.mid - params[1] * md; closeSum -= dataList[i - p].close; } return boll; }); } }; /** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var stopAndReverse = { name: 'SAR', shortName: 'SAR', series: 'price', calcParams: [2, 2, 20], precision: 2, shouldOhlc: true, plots: [{ key: 'sar', title: 'SAR: ', type: 'circle', color: function color(data, options) { var current = data.current; var kLineData = current.kLineData || {}; var technicalIndicatorData = current.technicalIndicatorData || {}; var halfHL = (kLineData.high + kLineData.low) / 2; if (technicalIndicatorData.sar < halfHL) { return optio