ohlcv-indicators 1.2.5 → 1.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ohlcv-indicators.min.js +1 -2
- package/index.js +7 -4
- package/package.json +2 -2
- package/src/moving-averages/bollingerBands.js +33 -25
- package/src/moving-averages/ema.js +19 -7
- package/src/moving-averages/macd.js +34 -13
- package/src/moving-averages/relativeVolume.js +18 -0
- package/src/moving-averages/sma.js +19 -7
- package/src/oscillators/rsi.js +18 -6
- package/src/studies/chart.js +110 -112
- package/src/utilities.js +47 -33
|
@@ -1,2 +1 @@
|
|
|
1
|
-
/*! For license information please see ohlcv-indicators.min.js.LICENSE.txt */
|
|
2
|
-
var OHLCV_INDICATORS;(()=>{var t={978:function(t,i){!function(t){"use strict";var i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,i){t.__proto__=i}||function(t,i){for(var e in i)Object.prototype.hasOwnProperty.call(i,e)&&(t[e]=i[e])})(t,e)},e=function(){return(e=Object.assign||function(t){for(var i,e=arguments,s=1,n=arguments.length;s<n;s++)for(var o in i=e[s])Object.prototype.hasOwnProperty.call(i,o)&&(t[o]=i[o]);return t}).apply(this,arguments)};function s(){for(var t=arguments,i=0,e=0,s=arguments.length;e<s;e++)i+=t[e].length;var n=Array(i),o=0;for(e=0;e<s;e++)for(var r=arguments[e],h=0,l=r.length;h<l;h++,o++)n[o]=r[h];return n}var n=function(){function t(t,i,e,s,n,o){void 0===o&&(o=null),this.forked=!1,this.forkedAt=0,this.lastForkY=null,this.step=s,this.index=n,this.length=0,this.startPoint=o?{y:t?o.h:o.l,x:o.x}:{y:t||i,x:e},this.init(t,i,e),this.thisPoint=this.startPoint}return t.prototype.init=function(t,i,e){this.type||(this.type=t?"h":"l"),this.candlePoint={y:"h"==this.type?t:i,x:e},this.thisPoint&&(this.prevPoint=this.thisPoint,this.nextPoint&&(this.thisPoint=this.nextPoint),this.nextPoint={y:this.k*(this.candlePoint.x+this.step)+this.b,x:this.candlePoint.x+this.step})},t.prototype.update=function(t,i,e){var s=null;if(this.length++,this.init(t,i,e),this.k&&!isNaN(this.k)||(this.k=(this.candlePoint.y-this.startPoint.y)/(this.candlePoint.x-this.startPoint.x),this.b=this.candlePoint.y-this.k*this.candlePoint.x,this.prevPoint=this.startPoint,this.thisPoint=this.candlePoint,this.nextPoint={y:this.k*(this.candlePoint.x+this.step)+this.b,x:this.candlePoint.x+this.step},s={condition:"h"==this.type?"lt":"gt",value:this.nextPoint.y,action:"fork",lineIndex:this.index}),"h"==this.type&&this.thisPoint.y<=this.candlePoint.y||"l"==this.type&&this.thisPoint.y>=this.candlePoint.y){this.k=(this.candlePoint.y-this.startPoint.y)/(this.candlePoint.x-this.startPoint.x),this.b=this.candlePoint.y-this.k*this.candlePoint.x,this.thisPoint=this.candlePoint,this.length=0,this.nextPoint={y:this.k*(this.candlePoint.x+this.step)+this.b,x:this.candlePoint.x+this.step};var n=this.rollback?this.rollback.length:0,o=this.candlePoint.y-this.prevPoint.y;("h"==this.type?o>0:o<0)?(this.rollback={k:o,b:this.candlePoint.y-o*this.candlePoint.x,length:n+1,lastForkTime:this.forkedAt||(this.rollback?this.rollback.lastForkTime:0),lastForkValue:this.forkedValue||(this.rollback?this.rollback.lastForkValue:0)},this.forked=!1,this.forkedAt=null,this.forkedValue=null):(this.forkedAt=this.candlePoint.x,this.forkedValue=this.candlePoint.y,this.forked=!0,this.rollback=null),s={condition:"h"==this.type?"lt":"gt",value:this.nextPoint.y,action:"fork",lineIndex:this.index}}else this.rollback=null;return s},t.prototype.updateStep=function(t){this.step=t},t}(),o=function(){function t(t){this.lineIndex=0,this.forkDiffH=null,this.forkDiffL=null,this.step=t,this.list=[[],[]],this.id={}}return t.prototype.add=function(t,i,e,s,o){void 0===s&&(s=null),void 0===o&&(o=null);var r,h,l,a=null;if(null==o?(r=this.lineIndex,this.lineIndex++,null!=t?this.list[0].push(r):this.list[1].push(r)):(r=o,a=this.id[r].lastForkY||(null!=t?s.h:s.l)),this.id[r]=new n(t,i,e,this.step,r,s),a&&(this.id[r].lastForkY=a),r>1||null!=o&&null!=this.id[o]){h=null!=o?o:this.list["h"==this.id[r].type?0:1][this.list["h"==this.id[r].type?0:1].indexOf(r)-1],l=null!=o?o:this.list["h"==this.id[r].type?0:1][this.list["h"==this.id[r].type?0:1].indexOf(r)-2];var u=this.id[h].lastForkY;l&&!u&&(u=this.id[l].lastForkY);var c=null!=t?s.h:s.l;u&&(t?this.forkDiffH=u>=c?-h-1:h+1:this.forkDiffL=u>=c?-h-1:h+1),this.id[h].lastForkY=c}return r},t.prototype.update=function(t,i,e,s){return this.id[t].update(i,e,s)},t.prototype.delete=function(t){this.id[t]&&("h"==this.id[t].type?this.list[0].splice(this.list[0].indexOf(t),1):this.list[1].splice(this.list[1].indexOf(t),1),delete this.id[t])},t}(),r=function(){function t(t,i){this.kdiff=[],this.env=i,this.lines=t,this.in={state:null,lineIndex:null,line:null},this.is={state:null,lineIndex:null,line:null,start:null,size:0},this.was={state:null,lineIndex:null,line:null,size:null},this.width=0,this.speed=0,this.at=0}return t.prototype.update=function(t,i){var s=this;if(t.length>1?this.hlMaxDuration=t.map((function(t){return s.lines.id[t]})).filter((function(t){return!s.is.line||(t.forkedAt?t.forkedAt>s.is.line.startPoint.x:!!t.rollback&&t.rollback.lastForkTime>s.is.line.startPoint.x)})).reduce((function(t,i){return t.length>i.length?t:i}),this.lines.id[t[0]]):this.hlMaxDuration=this.lines.id[t[0]],i.length>1?this.llMaxDuration=i.map((function(t){return s.lines.id[t]})).filter((function(t){return!s.is.line||(t.forkedAt?t.forkedAt>s.is.line.startPoint.x:!!t.rollback&&t.rollback.lastForkTime>s.is.line.startPoint.x)})).reduce((function(t,i){return t.length>i.length?t:i}),this.lines.id[i[0]]):this.llMaxDuration=this.lines.id[i[0]],null==this.is.state&&null==this.was.state&&(this.is.line=this.llMaxDuration&&this.llMaxDuration.length>this.env.minLength&&this.hlMaxDuration.length<this.env.minLength?this.llMaxDuration:this.hlMaxDuration&&this.hlMaxDuration.length>this.env.minLength&&this.llMaxDuration.length<this.env.minLength?this.hlMaxDuration:null,this.is.line&&(this.is.lineIndex=this.is.line.index,this.is.state="h"==this.is.line.type?"fall":"rise",this.is.start=this.is.line.candlePoint)),this.is.state){this.is.size=Math.max(this.is.size,Math.abs(this.is.start.y-this.is.line.candlePoint.y));var n,o=this.lines.id[this.is.lineIndex]||this.lines.id["h"==this.is.line.type?0:1],r=null,h=null,l=this.lines.list["h"==o.type?1:0].filter((function(t){return s.lines.id[t].forked&&s.lines.id[t].thisPoint.x-s.lines.id[t].forkedAt>12}));l.length>1?l[1]:l.length>0&&l[0];var a=l.filter((function(t){return s.lines.id[t].forkedAt>s.is.start.x}));if(o&&this.lines.list["h"==o.type?0:1].forEach((function(t,i){var e=s.lines.id[t];if(t>=o.index&&null!=e.rollback){n=s.lines.list["h"==o.type?0:1][i-1];var l=1==s.env.deltaModel&&i>1&&n&&s.lines.id[n]?i>1&&n&&s.lines.id[n].lastForkY:s.lines.id[t>0?t-1:0];h=l?s.lines.id[t>1?n:"h"==o.type?0:1].lastForkY-e.candlePoint.y:e.rollback?e.rollback.lastForkValue-e.candlePoint.y:0,e.rollback.lastForkValue>0&&e.thisPoint.x-e.rollback.lastForkTime>s.env.minRightLeg&&("fall"==s.is.state?s.llMaxDuration.length>1:s.hlMaxDuration.length>1)&&(("h"==o.type?h<0:h>0)||e.rollback.length>s.env.rollbackLength||2*s.is.size/3>Math.abs(s.is.start.y-s.is.line.candlePoint.y)&&s.is.size>s.is.line.candlePoint.y*s.env.minIsSizeOnRollback&&a.length>1||("h"==o.type?e.candlePoint.y>s.is.start.y&&1==s.lines.list[0].length:e.candlePoint.y<s.is.start.y&&1==s.lines.list[1].length))&&(e.candlePoint.x-e.rollback.lastForkTime>s.env.forkDurationMin&&e.candlePoint.x-e.rollback.lastForkTime<s.env.forkDurationMax||("h"==o.type?e.candlePoint.y>e.startPoint.y:e.candlePoint.y<e.startPoint.y)||("h"==o.type?e.candlePoint.y>s.is.start.y&&1==s.lines.list[0].length:e.candlePoint.y<s.is.start.y&&1==s.lines.list[1].length))&&(r=t+1)}})),r){this.in.size=(this.was.size||0)+this.is.size;var u=this.lines.id[0].candlePoint.y-this.is.start.y,c="rise"==this.is.state?u>=0:u<0;this.was.size&&(this.in.state=this.was.size>this.is.size?this.was.state:this.is.state),this.was=e({},this.is),this.was.success=c,this.is.line="fall"==this.is.state?this.llMaxDuration:this.hlMaxDuration,this.is.state="h"==this.is.line.type?"fall":"rise",this.is.lineIndex=this.is.line.index,this.is.start=this.lines.id[0].candlePoint,this.is.size=0}}},t}(),h=function(){function t(t){this.hLineDirectives=[],this.lLineDirectives=[],this.step=1,this.i=0,this.localCounter=0,this.prevPoint=null,this.env=Object.assign({step:1,minLength:5,minRightLeg:3,maxForks:500,minLog:0,maxLog:0,rollbackLength:3,deltaModel:1,minIsSizeOnRollback:.05},t),this.env.minLength=Math.round(this.env.minLength/this.env.step)||1,this.env.minRightLeg=Math.round(this.env.minRightLeg/this.env.step)||1,this.env.rollbackLength=Math.round(this.env.rollbackLength/this.env.step)||1,this.env.forkDurationMin=Math.round(this.env.forkDurationMin/this.env.step)||1,this.env.forkDurationMax=Math.round(this.env.forkDurationMax/this.env.step)||1,this.lines=new o(this.step),this.trend=new r(this.lines,this.env)}return t.prototype.log=function(t){for(var i=arguments,e=[],n=1;n<arguments.length;n++)e[n-1]=i[n];this.consoleWindow=this.env.minLog<this.localCounter&&this.localCounter<this.env.maxLog,this.consoleWindow&&console.log.apply(console,s([t],e))},t.prototype.nextValue=function(t,i,e,s){var n,o=this;this.localCounter++,this.lLineDirectives.length>0&&this.lLineDirectives.forEach((function(t,i){var e=o.lines.id[t.lineIndex];"gt"==t.condition&&s>t.value&&"fork"==t.action&&e&&(null!=t.lineIndex&&null!=e&&e.k<0?o.lines.add(null,s,o.i-1,o.prevPoint,t.lineIndex):(e.forked=!0,e.forkedAt=e.thisPoint.x,e.forkedValue=e.thisPoint.y,o.lines.add(null,s,o.i-1,o.prevPoint)))})),this.hLineDirectives.length>0&&this.hLineDirectives.forEach((function(t,i){var s=o.lines.id[t.lineIndex];"lt"==t.condition&&e<t.value&&"fork"==t.action&&s&&(s.k>0?o.lines.add(e,null,o.i-1,o.prevPoint,t.lineIndex):(s.forked=!0,s.forkedAt=s.thisPoint.x,s.forkedValue=s.thisPoint.y,o.lines.add(e,null,o.i-1,o.prevPoint)))})),this.hLineDirectives.length=0,this.lLineDirectives.length=0,this.lines.list[0].length<1?(this.lines.add(e,null,this.i),this.lines.add(null,s,this.i)):this.lines.list.forEach((function(t){return t.forEach((function(t){var i=o.lines.id[t];if(i&&i.type){n=null,i&&i.startPoint.x<o.i&&(n=o.lines.update(t,e,s,o.i));var r=i.type;n&&("h"==r?o.hLineDirectives.push(n):o.lLineDirectives.push(n))}}))}));var r=[];return this.lines.list.forEach((function(t){t&&(r=[],t.forEach((function(i,e){var s=o.lines.id[t[e]],n=o.lines.id[t[e-1]];(e>0&&s&&n&&"h"==s.type&&s.thisPoint&&n.thisPoint.y<=s.thisPoint.y||e>o.env.maxForks||e>0&&s&&n&&"l"==s.type&&s.thisPoint&&n.thisPoint.y>=s.thisPoint.y||e>o.env.maxForks)&&r.push(i)})),r.forEach((function(t){return o.lines.delete(t)})))})),this.prevPoint={x:this.i,h:e,l:s},this.trend.update(this.lines.list[0],this.lines.list[1]),this.i++,this.lines},t}(),l=Object.freeze({__proto__:null,Indicator:h}),a=function(){function t(t){this.length=t,this.filled=!1,this.pointer=0,this.buffer=new Array(t),this.maxIndex=t-1}return t.prototype.push=function(t){var i=this.buffer[this.pointer];return this.buffer[this.pointer]=t,this.iteratorNext(),i},t.prototype.pushback=function(t){this.iteratorPrev();var i=this.buffer[this.pointer];return this.buffer[this.pointer]=t,i},t.prototype.peek=function(){return this.buffer[this.pointer]},t.prototype.forEach=function(t){for(var i=this.pointer,e=0;e!==this.length;)t(this.buffer[i],e),i=(this.length+i+1)%this.length,e++},t.prototype.forEachRight=function(t){for(var i=(this.length+this.pointer-1)%this.length,e=this.length-1;e!==this.length;)t(this.buffer[i],e),i=(this.length+i-1)%this.length,e--},t.prototype.fill=function(t){this.buffer.fill(t),this.filled=!0},t.prototype.toArray=function(){return this.buffer},t.prototype.iteratorNext=function(){this.pointer++,this.pointer>this.maxIndex&&(this.pointer=0,this.filled=!0)},t.prototype.iteratorPrev=function(){this.pointer--,this.pointer<0&&(this.pointer=this.maxIndex)},t}(),u=function(t){function e(i,e){void 0===i&&(i=100);var s=t.call(this,i)||this;return s.period=i,s.mode=e,s.comparator="max"===e?s.maxComporator:s.mminComporator,s}return function(t,e){function s(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(s.prototype=e.prototype,new s)}(e,t),e.prototype.nextValue=function(t){return this.push(t),this.getExtremum()},e.prototype.momentValue=function(t){var i=this.push(t),e=this.getExtremum();return this.pushback(i),e},e.prototype.maxComporator=function(t,i){return t>i},e.prototype.mminComporator=function(t,i){return t<i},e.prototype.getExtremum=function(t){var i=(this.length+this.pointer-2)%this.length,e="max"===this.mode?-1/0:1/0;if(!this.filled)return 0;for(;i!==this.pointer;){var s=this.buffer[(this.length+i-1)%this.length],n=this.buffer[(this.length+i+1)%this.length],o=this.buffer[i];if(this.comparator(o,e)&&this.comparator(o,s)&&this.comparator(o,n)){if(e=o,this.prevIx===i)return null;if(this.prevIx=i,t)return e}i=(this.length+i-1)%this.length}return isFinite(e)?e:(this.prevIx=null,null)},e}(a),c=function(){function t(t){this.period=t,this.sum=0,this.circular=new a(t)}return t.prototype.nextValue=function(t){var i=this;if(this.circular.push(t),this.sum+=t,this.circular.filled)return this.nextValue=function(t){return i.sum=i.sum-i.circular.push(t)+t,i.sum/i.period},this.momentValue=function(t){return(i.sum-i.circular.peek()+t)/i.period},this.sum/this.period},t.prototype.momentValue=function(t){},t}(),p=function(){function t(t){this.period=t,this.smooth=1/this.period,this.sma=new c(this.period)}return t.prototype.nextValue=function(t){return this.wema?this.wema=(t-this.wema)*this.smooth+this.wema:this.wema=this.sma.nextValue(t)},t.prototype.momentValue=function(t){return this.wema?(t-this.wema)*this.smooth+this.wema:this.sma.momentValue(t)},t}(),d=function(){function t(t){this.period=t,this.smooth=2/(this.period+1),this.sma=new c(this.period)}return t.prototype.nextValue=function(t){var i=this,e=this.sma.nextValue(t);return e&&(this.ema=e,this.nextValue=function(t){return i.ema=(t-i.ema)*i.smooth+i.ema},this.momentValue=function(t){return(t-i.ema)*i.smooth+i.ema}),e},t.prototype.momentValue=function(t){},t}(),f=function(){function t(t,i){this.indicator=t,this.samples=i,this._indicators=[]}return t.prototype.create=function(){for(var t,i=arguments,e=[],n=0;n<arguments.length;n++)e[n]=i[n];for(var o=0;o<this.samples;o++)this._indicators.push(new((t=this.indicator).bind.apply(t,s([void 0],e))))},t.prototype.nextValue=function(t){for(var i=0;i<this.samples;i++)if(void 0===(t=this._indicators[i].nextValue(t)))return t;return t},t.prototype.momentValue=function(t){for(var i=0;i<this.samples;i++)if(null==(t=this._indicators[i].momentValue(t)))return t;return t},t}(),m=function(){function t(t,i,e,s,n){void 0===t&&(t=.85),void 0===s&&(s=1),void 0===n&&(n=1),this.redunant=t,this.multiplier=s,this.offset=n,this.prevValue=0,this.lastUpperValue=0,this.lastLowerValue=0,this.samplerUp=new f(i,e),this.samplerLow=new f(i,e)}return t.prototype.create=function(){for(var t,i,e=arguments,s=[],n=0;n<arguments.length;n++)s[n]=e[n];(t=this.samplerUp).create.apply(t,s),(i=this.samplerLow).create.apply(i,s)},t.prototype.nextValue=function(t){this.lastUpperValue=t>0?Math.max(t,this.prevValue):Math.max(0,this.lastUpperValue)*this.redunant,this.lastLowerValue=t<=0?Math.min(t,this.prevValue):Math.min(0,this.lastLowerValue)*this.redunant;var i=(t<=0?t:this.lastLowerValue)*this.multiplier,e=(t>=0?t:this.lastUpperValue)*this.multiplier;return[this.samplerUp.nextValue(e)+this.offset,this.samplerLow.nextValue(i)-this.offset]},t}(),v=function(){function t(t,i,e,s){void 0===e&&(e=.85),void 0===s&&(s="WEMA"),this.period=t,this.samples=i,this.redunant=e,this.type=s,this.upper=0,this.lower=0,this.lastUpperValue=0,this.lastLowerValue=0,this.sample1Up=this.createSample(),this.sample2Up=this.createSample(),this.sample3Up=this.createSample(),this.sample1Low=this.createSample(),this.sample2Low=this.createSample(),this.sample3Low=this.createSample()}return t.prototype.nextValue=function(t){return t>0?(this.upper=this.getUp(t),this.lastLowerValue*=this.redunant,this.lower=this.getDown(this.lastLowerValue),this.lastUpperValue=t):t<0&&(this.lower=this.getDown(t),this.lastUpperValue*=this.redunant,this.upper=this.getUp(this.lastUpperValue),this.lastLowerValue=t),{upper:this.upper,lower:this.lower}},t.prototype.getUp=function(t){var i=this.sample1Up.nextValue(t),e=null;return 1===this.samples?i:(i&&(e=this.sample2Up.nextValue(i)),2===this.samples?e:e?this.sample3Up.nextValue(e):null)},t.prototype.getDown=function(t){var i=this.sample1Low.nextValue(t),e=null;return 1===this.samples?i:(i&&(e=this.sample2Low.nextValue(i)),2===this.samples?e:e?this.sample3Low.nextValue(e):null)},t.prototype.createSample=function(){switch(this.type){case"EMA":return new d(this.period);case"WEMA":return new p(this.period);case"SMA":return new c(this.period)}},t}(),g=function(){function t(t){this.period=t,this.SMAx=new c(this.period),this.SMAy=new c(this.period),this.pricesX=new a(this.period),this.pricesY=new a(this.period)}return t.prototype.nextValue=function(t,i){this.pricesX.push(t),this.pricesY.push(i),this.SMAxValue=this.SMAx.nextValue(t),this.SMAyValue=this.SMAy.nextValue(i);for(var e=0,s=0,n=0,o=0;o<this.period;o++){var r=this.pricesX.toArray()[o],h=this.pricesY.toArray()[o];e+=(r-this.SMAxValue)*(h-this.SMAyValue),s+=Math.pow(r-this.SMAxValue,2),n+=Math.pow(h-this.SMAyValue,2)}return e/Math.sqrt(s*n)},t}(),w=function(){function t(t){this.period=t,this.denominator=t*(t+1)/2,this.buffer=new a(t),this.values=[]}return t.prototype.nextValue=function(t){var i=this;if(this.buffer.push(t),this.buffer.filled){var e=0;return this.buffer.forEach((function(t,s){e+=t*(s+1)/i.denominator})),e}},t.prototype.momentValue=function(t){var i=this,e=this.buffer.push(t);if(this.buffer.filled){var s=0;return this.buffer.forEach((function(t,e){s+=t*(e+1)/i.denominator})),this.buffer.pushback(e),s}this.buffer.pushback(e)},t}(),x=function(){function t(t){void 0===t&&(t=.2),this.alpha=t,this.filled=!1}return t.prototype.nextValue=function(t){var i=this.alpha*t+(1-this.alpha)*(this.prevValue||1);if(this.filled=this.filled||void 0!==this.prevValue,this.prevValue=i,this.filled)return i},t.prototype.momentValue=function(t){if(this.filled)return this.alpha*t+(1-this.alpha)*(this.prevValue||1)},t}(),V=function(){function t(t){this.period=t,this.sum=0,this.avg=0,this.filled=!1,this.fill=0}return t.prototype.nextValue=function(t){var i=this;return this.filled?(this.nextValue=function(t){return i.avg=(i.avg*(i.period-1)+t)/i.period},this.nextValue(t)):(this.sum+=t,this.fill++,this.fill===this.period?(this.filled=!0,this.avg=this.sum/this.period,this.avg):void 0)},t.prototype.momentValue=function(t){if(this.filled)return(this.avg*(this.period-1)+t)/this.period},t}(),y=function(){function t(t){void 0===t&&(t=14),this.period=t,this.alpha=1/t,this.sma=new c(this.period)}return t.prototype.nextValue=function(t){var i=this;return this.prevValue?(this.prevValue=this.alpha*t+(1-this.alpha)*this.prevValue,this.nextValue=function(t){return i.prevValue=i.alpha*t+(1-i.alpha)*i.prevValue,i.prevValue}):this.prevValue=this.sma.nextValue(t),this.prevValue},t.prototype.momentValue=function(t){if(this.prevValue)return this.alpha*t+(1-this.alpha)*this.prevValue},t}(),M=function(){function t(t,i){void 0===t&&(t=5),void 0===i&&(i=34),this.smaSlow=new c(i),this.smaFast=new c(t)}return t.prototype.nextValue=function(t,i){var e=this;if(this.smaSlowValue=this.smaSlow.nextValue((t+i)/2),this.smaFastValue=this.smaFast.nextValue((t+i)/2),void 0!==this.smaSlowValue&&void 0!==this.smaFastValue)return this.nextValue=function(t,i){return e.smaSlowValue=e.smaSlow.nextValue((t+i)/2),e.smaFastValue=e.smaFast.nextValue((t+i)/2),e.smaFastValue-e.smaSlowValue},this.momentValue=function(t,i){return e.smaFast.momentValue((t+i)/2)-e.smaSlow.momentValue((t+i)/2)},this.smaFastValue-this.smaSlowValue},t.prototype.momentValue=function(t,i){},t}(),P=function(){function t(){this.sma=new c(5),this.ao=new M}return t.prototype.nextValue=function(t,i){var e=this;if(this.aoValue=this.ao.nextValue(t,i),void 0!==this.aoValue&&(this.smaValue=this.sma.nextValue(this.aoValue),void 0!==this.smaValue))return this.nextValue=function(t,i){return e.aoValue=e.ao.nextValue(t,i),e.smaValue=e.sma.nextValue(e.aoValue),e.aoValue-e.smaValue},this.momentValue=function(t,i){return e.ao.momentValue(t,i)-e.sma.momentValue(e.aoValue)},this.aoValue-this.smaValue},t.prototype.momentValue=function(t,i){},t}(),k=function(t,i){return(t-i)/i*100},b=function(){function t(t){this.period=t,this.value=0,this.changes=new a(t)}return t.prototype.nextValue=function(t){if(this.prevPrice){var i=k(t,this.prevPrice);return this.calculate(i),this.prevPrice=t,this.value}this.prevPrice=t},t.prototype.calculate=function(t){return this.value+=t,this.value-=this.changes.push(t),this.value},t}();function A(t){return t.consolidate=0,t.power=0,t.streak=0,t.diff=0,t.startPrice=0,t.prevPeak=0,t}var S=function(){function t(){this.up={consolidate:0,power:0,streak:0,startPrice:0,diff:0,prevPeak:0},this.down={consolidate:0,power:0,streak:0,startPrice:0,diff:0,prevPeak:0}}return t.prototype.nextValue=function(t,i,s,n){if(t<i||this.up.streak&&this.up.prevPeak<n){this.up.startPrice||(this.up.startPrice=t),this.down.streak&&A(this.down);var o=i-t;this.up.streak++,this.up.prevPeak=n,this.up.diff>o?this.up.consolidate++:this.up.consolidate=0,this.up.diff=o,this.up.power=k(i,this.up.startPrice)}return(t>i||this.down.streak&&this.down.prevPeak>s)&&(this.down.startPrice||(this.down.startPrice=t),this.up.streak&&A(this.up),o=t-i,this.down.streak++,this.down.prevPeak=s,this.down.diff>o?this.down.consolidate++:this.down.consolidate=0,this.down.diff=o,this.down.power=k(i,this.down.startPrice)),t===i&&(this.up.streak++,this.down.streak++,this.up.diff=this.down.diff=0),this.up.streak>this.down.streak?e({},this.up):e({},this.down)},t}(),L=function(){function t(t){this.max=-1/0,this.highest=new a(t)}return t.prototype.filled=function(){return this.highest.filled},t.prototype.nextValue=function(t){return this.max<t&&(this.max=t),this.highest.push(t)===this.max&&t!==this.max&&(this.max=function(t){for(var i=-1/0,e=t.length-1;e>=0;e--){var s=t[e];i<s&&(i=s)}return i}(this.highest.toArray())),this.max},t.prototype.momentValue=function(t){return this.max>t?this.max:t},t}(),D=function(){function t(t){this.min=1/0,this.lowest=new a(t)}return t.prototype.filled=function(){return this.lowest.filled},t.prototype.nextValue=function(t){return this.min>t&&(this.min=t),this.lowest.push(t)===this.min&&t!==this.min&&(this.min=function(t){for(var i=1/0,e=t.length-1;e>=0;e--){var s=t[e];i>s&&(i=s)}return i}(this.lowest.toArray())),this.min},t.prototype.momentValue=function(t){return this.min<t?this.min:t},t}(),C=function(){function t(t,i){void 0===t&&(t=14),void 0===i&&(i=3),this.period=t,this.smaPeriod=i,this.sma=new c(this.smaPeriod),this.max=new L(t),this.min=new D(t)}return t.prototype.nextValue=function(t,i,e){var s=this.max.nextValue(t),n=this.min.nextValue(i);if(this.max.filled()){var o=(e-n)/(s-n)*100;return{k:o,d:this.sma.nextValue(o)}}},t.prototype.momentValue=function(t,i,e){if(this.max.filled()){var s=this.max.momentValue(t),n=this.min.momentValue(i),o=(e-n)/(s-n)*100;return{k:o,d:this.sma.momentValue(o)}}},t}(),F=function(){function t(t){this.avgGain=new V(t),this.avgLoss=new V(t)}return t.prototype.nextValue=function(t){var i=t-this.prev;if(this.prev){var e=i>0?i:0,s=i<0?i:0,n=this.avgGain.nextValue(e),o=this.avgLoss.nextValue(s);return this.prev=t,{upAvg:n,downAvg:o}}this.prev=t},t.prototype.momentValue=function(t){var i=t-this.prev,e=i>0?i:0,s=i<0?i:0;return{upAvg:this.avgGain.momentValue(e),downAvg:this.avgLoss.momentValue(s)}},t}(),_=function(){function t(t){void 0===t&&(t=14),this.period=t,this.change=new F(this.period)}return t.prototype.nextValue=function(t){var i=this.change.nextValue(t)||{},e=i.downAvg,s=i.upAvg;if(void 0!==s&&void 0!==e)return 100-100/(1+s/-e)},t.prototype.momentValue=function(t){var i=this.change.momentValue(t)||{},e=i.downAvg,s=i.upAvg;if(void 0!==s&&void 0!==e)return 100-100/(1+s/-e)},t}(),B=function(){function t(t,i,e,s){void 0===t&&(t=14),void 0===i&&(i=3),void 0===e&&(e=3),void 0===s&&(s=14),this.rsi=new _(t),this.sma1=new c(i),this.sma2=new c(e),this.max=new L(s),this.min=new D(s)}return t.prototype.nextValue=function(t){var i=this.rsi.nextValue(t);if(void 0!==i){var e=this.max.nextValue(i),s=this.min.nextValue(i);if(this.max.filled()){var n=(i-s)/(e-s)*100,o=this.sma1.nextValue(n);if(void 0!==o)return{k:o,d:this.sma2.nextValue(o),stochRsi:n}}}},t.prototype.momentValue=function(t){if(this.max.filled()){var i=this.rsi.momentValue(t),e=this.max.momentValue(i),s=this.min.momentValue(i),n=(i-s)/(e-s)*100,o=this.sma1.momentValue(n);return{k:o,d:this.sma2.momentValue(o),stochRsi:n}}},t}(),I=function(){function t(t){this.period=t,this.values=new a(t)}return t.prototype.nextValue=function(t,i){if(i)return this.nextValue=this.pureNextValue,this.momentValue=this.pureMomentValue,this.pureNextValue(t,i);this.values.push(t)},t.prototype.momentValue=function(t,i){},t.prototype.pureNextValue=function(t,i){var e=this;return this.values.push(t),this.values.toArray().reduce((function(t,s){return t+e.positiveDelta(i,s)}),0)/this.period},t.prototype.pureMomentValue=function(t,i){var e=this,s=this.values.push(t),n=this.values.toArray().reduce((function(t,s){return t+e.positiveDelta(i,s)}),0);return this.values.pushback(s),n/this.period},t.prototype.positiveDelta=function(t,i){return t>i?t-i:i-t},t}(),T=function(){function t(t){void 0===t&&(t=20),this.md=new I(t),this.sma=new c(t)}return t.prototype.nextValue=function(t,i,e){var s=(t+i+e)/3,n=this.sma.nextValue(s),o=this.md.nextValue(s,n);return o&&(s-n)/(.015*o)},t.prototype.momentValue=function(t,i,e){var s=(t+i+e)/3,n=this.sma.momentValue(s),o=this.md.momentValue(s,n);return o&&(s-n)/(.015*o)},t}(),E=function(){function t(t){this.period=t,this.arr=[],this.filled=!1,this.devider=0,this.lastSum=0,this.devider=function(t){for(var i=0,e=t.length;e>0;)i+=t[--e];return i}(Array.from(Array(this.period).keys()).map((function(t){return t+1})))}return t.prototype.nextValue=function(t){if(this.filled=this.filled||this.arr.length===this.period,this.arr.push(t),this.filled)return this.arr.shift(),this.arr.reduce((function(t,i,e){return t+i*(e+1)}),0)/this.devider},t.prototype.momentValue=function(t){if(this.filled){var i=this.arr.slice(1);return i.push(t),i.reduce((function(t,i,e){return t+i*(e+1)}),0)/this.devider}},t}();function O(t,i,e){if(e){var s=t-i,n=t>e?t-e:e-t,o=i>e?i-e:e-i;return s>=n&&s>=o?s:n>=s&&n>=o?n:o}}var R=function(){function t(t,i){switch(void 0===t&&(t=14),void 0===i&&(i="WEMA"),i){case"SMA":this.avg=new c(t);break;case"EMA":this.avg=new d(t);break;case"SMMA":this.avg=new V(t);break;case"WEMA":this.avg=new p(t);break;case"LWMA":this.avg=new E(t);break;case"EWMA":this.avg=new x(.2);break;case"RMA":this.avg=new y(t)}this.prevClose=0}return t.prototype.nextValue=function(t,i,e){var s=O(t,i,this.prevClose);if(this.prevClose=e,void 0!==s)return this.avg.nextValue(s)},t.prototype.momentValue=function(t,i){var e=O(t,i,this.prevClose);if(void 0!==e)return this.avg.momentValue(e)},t}(),U=function(){function t(t){void 0===t&&(t=5),this.values=new a(t)}return t.prototype.nextValue=function(t){var i=this.values.push(t);if(i)return(t-i)/i*100},t.prototype.momentValue=function(t){var i=this.values.peek();if(i)return(t-i)/i*100},t}(),N=function(){function t(t){void 0===t&&(t=20),this.maxProvider=new L(t),this.minProvider=new D(t)}return t.prototype.nextValue=function(t,i){var e=this.maxProvider.nextValue(t),s=this.minProvider.nextValue(i);return{upper:e,middle:(e+s)/2,lower:s}},t.prototype.momentValue=function(t,i){var e=this.maxProvider.momentValue(t),s=this.minProvider.momentValue(i);return{upper:e,middle:(e+s)/2,lower:s}},t}(),W=function(){function t(t){this.period=t,this.fill=0,this.values=new a(t)}return t.prototype.nextValue=function(t){var i=this;if(this.values.push(t),this.fill++,this.fill===this.period)return this.nextValue=function(t){var e=i.calc(t);return i.values.push(t),e},this.momentValue=this.calc,this.calc(t)},t.prototype.momentValue=function(t){},t.prototype.calc=function(t){var i=0;return this.values.toArray().forEach((function(e){e<=t&&i++})),i/this.period*100},t}(),H=function(){function t(t,i,e){void 0===t&&(t=3),void 0===i&&(i=2),void 0===e&&(e=100),this.period=t,this.rsi=new _(this.period),this.updownRsi=new _(i),this.roc=new U(1),this.percentRank=new W(e),this.updownPeriod=0,this.prevClose=0}return t.prototype.nextValue=function(t){var i=this.rsi.nextValue(t),e=this.percentRank.nextValue(this.roc.nextValue(t));if(this.updownPeriod=this.getUpdownPeriod(t),this.prevClose=t,this.updownValue=this.updownRsi.nextValue(this.updownPeriod),this.updownValue)return(i+this.updownValue+e)/3},t.prototype.momentValue=function(t){var i=this.rsi.momentValue(t),e=this.percentRank.momentValue(this.roc.momentValue(t)),s=this.getUpdownPeriod(t),n=this.updownRsi.momentValue(s);if(void 0!==n)return(i+n+e)/3},t.prototype.getUpdownPeriod=function(t){var i=this.updownPeriod;return t>this.prevClose?(this.updownPeriod<0&&(i=0),i++):t<this.prevClose?(this.updownPeriod>0&&(i=0),i--):i=0,i},t}(),j=function(){function t(t){this.period=t,this.values=new a(t)}return t.prototype.nextValue=function(t,i){return this.values.push(t),Math.sqrt(this.values.toArray().reduce((function(t,e){return t+Math.pow(e-i,2)}),0)/this.period)},t.prototype.momentValue=function(t,i){var e=this.values.push(t),s=Math.sqrt(this.values.toArray().reduce((function(t,e){return t+Math.pow(e-i,2)}),0)/this.period);return this.values.pushback(e),s},t}(),z=function(){function t(t,i){void 0===t&&(t=20),void 0===i&&(i=2),this.period=t,this.stdDev=i,this.fill=0,this.sma=new c(t),this.sd=new j(t)}return t.prototype.nextValue=function(t){var i=this,e=this.sma.nextValue(t),s=this.sd.nextValue(t,e);if(this.fill++,this.fill===this.period){var n=e-this.stdDev*s,o=e+this.stdDev*s;return this.nextValue=function(t){var e=i.sma.nextValue(t),s=i.sd.nextValue(t,e);return{lower:e-i.stdDev*s,middle:e,upper:e+i.stdDev*s}},{lower:n,middle:e,upper:o}}},t.prototype.momentValue=function(t){var i=this.sma.momentValue(t),e=this.sd.momentValue(t,i);return{lower:i-this.stdDev*e,middle:i,upper:i+this.stdDev*e}},t}(),$=function(){function t(t,i,e){void 0===t&&(t=12),void 0===i&&(i=26),void 0===e&&(e=9),this.periodEmaFast=t,this.periodEmaSlow=i,this.periodSignal=e,this.emaFastIndicator=new d(t),this.emaSlowIndicator=new d(i),this.emaSignalIndicator=new d(e)}return t.prototype.nextValue=function(t){var i=this.emaFastIndicator.nextValue(t),e=this.emaSlowIndicator.nextValue(t),s=i-e,n=s&&this.emaSignalIndicator.nextValue(s)||void 0,o=s-n||void 0;if(!isNaN(s))return{macd:s,emaFast:i,emaSlow:e,signal:n,histogram:o}},t.prototype.momentValue=function(t){var i=this.emaFastIndicator.momentValue(t),e=this.emaSlowIndicator.momentValue(t),s=i-e,n=s&&this.emaSignalIndicator.momentValue(s);return{macd:s,emaFast:i,emaSlow:e,signal:n,histogram:s-n}},t}(),Y=function(){function t(){this.prevOpen=0,this.prevClose=0}return t.prototype.nextValue=function(t,i,e,s){var n=this.calculate(t,i,e,s);return this.prevClose=n.c,this.prevOpen=n.o,n},t.prototype.momentValue=function(t,i,e,s){return this.calculate(t,i,e,s)},t.prototype.calculate=function(t,i,e,s){return s=(t+i+e+s)/4,this.prevOpen&&(t=(this.prevOpen+this.prevClose)/2),{o:t,h:i=Math.max(i,t,s),l:e=Math.min(e,t,s),c:s}},t}(),q=function(){function t(t){switch(void 0===t&&(t="classic"),this.mode=t,this.mode){case"classic":this.calculator=this.classic;break;case"camarilla":this.calculator=this.camarilla;break;case"woodie":this.calculator=this.woodie;break;case"fibonacci":this.calculator=this.fibonacci}}return t.prototype.nextValue=function(t,i,e){return this.calculator(t,i,e)},t.prototype.classic=function(t,i,e){var s=(t+i+e)/3;return{r3:t+2*(s-i),r2:s+(t-i),r1:2*s-i,pp:s,s1:2*s-t,s2:s-(t-i),s3:i-2*(t-s)}},t.prototype.woodie=function(t,i,e){var s=(t+i+2*e)/4;return{r2:s+t-i,r1:2*s-i,pp:s,s1:2*s-t,s2:s-t+i}},t.prototype.camarilla=function(t,i,e){var s=1.1*(t-i),n=t/i*e,o=e+s/2,r=n+1.168*(n-o);return{r6:r,r5:n,r4:o,r3:e+s/4,r2:e+s/6,r1:e+s/12,pp:(t+i+e)/3,s1:e-s/12,s2:e-s/6,s3:e-s/4,s4:e-s/2,s5:e-(n-e),s6:e-(r-e)}},t.prototype.fibonacci=function(t,i,e){var s=t-i,n=(t+i+e)/3;return{r3:n+s,r2:n+.618*s,r1:n+.382*s,pp:n,s1:n-.382*s,s2:n-.618*s,s3:n-s}},t}(),X=function(){function t(t,i,e){void 0===t&&(t=.02),void 0===i&&(i=.02),void 0===e&&(e=.2),this.start=t,this.acceleration=i,this.max=e,this.result=0,this.isBullTrend=!0}return t.prototype.nextValue=function(t,i,e){if(!this.result)return this.result=e,this.low1=i,this.high1=t,this.low2=i,this.high2=t,this.highest=t,this.lowest=i,this.accelerationFactor=this.start,i;if(this.isBullTrend?this.psar=this.result+this.accelerationFactor*(this.highest-this.result):this.psar=this.result+this.accelerationFactor*(this.lowest-this.result),this.isBullTrend)if(i<this.psar)this.isBullTrend=!1,this.psar=this.highest,this.lowest=i,this.accelerationFactor=this.start;else{if(t>this.highest){this.highest=t;var s=this.accelerationFactor+this.acceleration;this.accelerationFactor=s>this.max?this.max:s}this.low1<this.psar&&(this.psar=this.low1),this.low2<this.psar&&(this.psar=this.low2)}else t>this.psar?(this.isBullTrend=!0,this.psar=this.lowest,this.highest=t,this.accelerationFactor=this.start):(i<this.lowest&&(this.lowest=i,s=this.accelerationFactor+this.acceleration,this.accelerationFactor=s>this.max?this.max:s),this.high1>this.psar&&(this.psar=this.high1),this.high2>this.psar&&(this.psar=this.high2));return this.low2=this.low1,this.low1=i,this.high2=this.high1,this.high1=t,this.result=this.psar,this.result},t.prototype.momentValue=function(t,i){if(!this.result)return i;var e,s=this.isBullTrend,n=this.result,o=this.low1,r=this.high1,h=this.low2,l=this.high2,a=this.highest,u=this.lowest,c=this.accelerationFactor;return e=s?n+c*(a-n):n+c*(u-n),s?i<e?e=a:(o<e&&(e=o),h<e&&(e=h)):t>e?e=u:(r>e&&(e=r),l>e&&(e=l)),e},t}(),G=function(){function t(t){this.period=t,this.prevValue=0,this.sumCount=1}return t.prototype.nextValue=function(t){var i=this;return this.sumCount<this.period?(this.prevValue+=t,void this.sumCount++):this.sumCount===this.period?(this.prevValue+=t,this.sumCount++,this.nextValue=function(t){return i.prevValue=i.prevValue-i.prevValue/i.period+t},this.prevValue):void 0},t.prototype.momentValue=function(t){if(!(this.sumCount<this.period))return this.prevValue-this.prevValue/this.period+t},t}(),K=function(){function t(t){void 0===t&&(t=14),this.period=t,this.wma1=new G(t),this.wma2=new G(t),this.wma3=new G(t),this.wema=new p(t)}return t.prototype.nextValue=function(t,i,e){if(!this.prevClose)return this.prevHigh=t,this.prevLow=i,void(this.prevClose=e);var s=0,n=0,o=t-this.prevHigh,r=this.prevLow-i;o>r&&o>0&&(s=o),r>o&&r>0&&(n=r),(s>n||n<0)&&(n=0);var h=this.wma1.nextValue(O(t,i,this.prevClose)),l=this.wma2.nextValue(s),a=this.wma3.nextValue(n);if(this.prevHigh=t,this.prevLow=i,this.prevClose=e,void 0!==l&&void 0!==a){var u=100*l/h,c=100*a/h,p=u>c?u-c:c-u;return{adx:this.wema.nextValue(p/(u+c)*100),pdi:u,mdi:c}}},t.prototype.momentValue=function(t,i,e){if(this.prevClose){var s=0,n=0,o=t-this.prevHigh,r=this.prevLow-i;o>r&&o>0&&(s=o),r>o&&r>0&&(n=r),(s>n||n<0)&&(n=0);var h=this.wma1.momentValue(O(t,i,this.prevClose)),l=this.wma2.momentValue(s),a=this.wma3.momentValue(n);if(void 0!==l&&void 0!==a){var u=100*l/h,c=100*a/h,p=u>c?u-c:c-u;return{adx:this.wema.momentValue(p/(u+c)*100),pdi:u,mdi:c}}}},t}(),J=function(){function t(t,i,e){void 0===t&&(t=10),void 0===i&&(i=3),void 0===e&&(e="WEMA"),this.multiplier=i,this.atr=new R(t,e)}return t.prototype.nextValue=function(t,i,e){var s=this.atr.nextValue(t,i,e);if(s){var n=(t+i)/2,o=n+this.multiplier*s,r=n-this.multiplier*s;this.prevLower&&(r=r>this.prevLower||this.prevClose<this.prevLower?r:this.prevLower,o=o<this.prevUpper||this.prevClose>this.prevUpper?o:this.prevUpper);var h,l=(h=this.prevSuper===this.prevUpper?e>o?r:o:e<r?o:r)===o?1:-1;return this.prevUpper=o,this.prevLower=r,this.prevSuper=h,this.prevClose=e,{upper:o,lower:r,superTrend:h,direction:l}}},t.prototype.momentValue=function(t,i,e){var s=this.atr.momentValue(t,i),n=(t+i)/2,o=n+this.multiplier*s,r=n-this.multiplier*s;this.prevLower&&(r=r>this.prevLower||this.prevClose<this.prevLower?r:this.prevLower,o=o<this.prevSuper||this.prevClose>this.prevUpper?o:this.prevUpper);var h;return{upper:o,lower:r,superTrend:h=this.prevSuper===this.prevUpper?e>o?r:o:e<r?o:r,direction:h===o?1:-1}},t}(),Q=function(t){return(t.o+t.h+t.l+t.c)/4},Z=function(){function t(t,i){void 0===t&&(t=4),void 0===i&&(i=Q),this.sum=0,this.sessionPricesLookup=new Set,this.sessionVolumes={},this.prevCandle=null,this.source=i,this.precision=t,this.valueToRoundWith=Math.pow(10,this.precision)}return t.prototype.getSession=function(t,i){var e=this;void 0===i&&(i=15);var s=this.source(t),n=1/0,o=s;this.sessionPricesLookup.forEach((function(t){var r=e.diffPercent(t,s);r>i?(e.sessionPricesLookup.delete(t),delete e.sessionVolumes[t]):r<n&&(n=r,o=t)}));var r=Array.from(this.sessionPricesLookup).sort(),h=r.indexOf(o),l=new Map;if(-1===h)return l;for(var a=Math.round(r.length/4),u=0,c=0;c<4;c++){for(var p=c*a,d=p+a,f=0,m=0,v=p;v<d;v++){var g=r[p],w=this.sessionVolumes[g];f<w&&(f=w,m=g)}this.diffPercent(u,m)<1&&(f=l.get(u)+f,m=this.roundPrice((m+u)/2),l.delete(u)),l.set(m,f),u=m}return l},t.prototype.getSessionAvg=function(){return this.sum/this.sessionPricesLookup.size},t.prototype.getRawSession=function(){return this.sessionVolumes},t.prototype.nextValue=function(t){var i,e=this.roundPrice(this.source(t)),s=(null===(i=this.prevCandle)||void 0===i?void 0:i.time)===t.time?t.v-this.prevCandle.v:t.v;this.addToSession(e,s),this.sum+=s,this.lastPrice=e,this.prevCandle=t},t.prototype.roundPrice=function(t){return Math.round((t+Number.EPSILON)*this.valueToRoundWith)/this.valueToRoundWith},t.prototype.addToSession=function(t,i){this.sessionPricesLookup.has(t)?this.sessionVolumes[t]+=i:(this.sessionPricesLookup.add(t),this.sessionVolumes[t]=i)},t.prototype.diffPercent=function(t,i){return t<i?100*(i-t)/t:100*(t-i)/i},t}(),tt=function(){function t(t,i){void 0===t&&(t=3),void 0===i&&(i=10),this.accDistribution=0,this.emaFast=new d(t),this.emaSlow=new d(i)}return t.prototype.nextValue=function(t,i,e,s){return this.accDistribution+=e===t&&e===i||t===i?0:(2*e-i-t)/(t-i)*s,this.emaFast.nextValue(this.accDistribution)-this.emaSlow.nextValue(this.accDistribution)},t.prototype.momentValue=function(t,i,e,s){var n=this.accDistribution+(e===t&&e===i||t===i?0:(2*e-i-t)/(t-i)*s);return this.emaFast.momentValue(n)-this.emaSlow.momentValue(n)},t}();t.AC=P,t.ADX=K,t.AO=M,t.ATR=R,t.BollingerBands=z,t.CCI=T,t.ChaikinOscillator=tt,t.CircularBuffer=a,t.Correlation=g,t.DC=N,t.EMA=d,t.EWMA=x,t.Extremums=u,t.HeikenAshi=Y,t.LWMA=E,t.Level=v,t.MACD=$,t.Move=b,t.PSAR=X,t.Pivot=q,t.RMA=y,t.ROC=U,t.RSI=_,t.SMA=c,t.SMMA=V,t.Sampler=f,t.StandardDeviation=j,t.Stochastic=C,t.StochasticRSI=B,t.SuperTrend=J,t.TrendLines=l,t.UniLevel=m,t.VolumeProfile=Z,t.WEMA=p,t.WMA=w,t.WWS=G,t.Wave=S,t.cRSI=H,Object.defineProperty(t,"__esModule",{value:!0})}(i)}},i={};function e(s){var n=i[s];if(void 0!==n)return n.exports;var o=i[s]={exports:{}};return t[s].call(o.exports,o,o.exports,e),o.exports}e.d=(t,i)=>{for(var s in i)e.o(i,s)&&!e.o(t,s)&&Object.defineProperty(t,s,{enumerable:!0,get:i[s]})},e.o=(t,i)=>Object.prototype.hasOwnProperty.call(t,i),e.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var s={};(()=>{"use strict";e.r(s),e.d(s,{default:()=>u});var t=e(978);const i=(i,e)=>{const s=[],n=new t.EMA(e);return i.forEach((t=>{s.push(n.nextValue(t))})),s},n=(i,e)=>{const s=[],n=new t.SMA(e);return i.forEach((t=>{s.push(n.nextValue(t))})),s},o=(t,i)=>{var e;return(0===(e=t.map(((t,e)=>t>i[e]?"up":t<i[e]?"down":"neutral")).reverse()).length?[]:e.reduce(((t,i,e,s)=>{if(0===e)t.push([i]);else{const n=s[e-1],o=t[t.length-1];i!==n?t.push([i]):o.push(i)}return t}),[])).map((t=>{const i=t.length;return t.map(((t,e)=>{let s=i-e;return"down"===t?-s:"up"===t?s:0}))})).flat().reverse()},r=(t,i)=>{let{upper:e,lower:s}=i;const n=e.map(((t,i)=>t-s[i]));return t.map(((t,i)=>(t-s[i])/n[i]*100))},h={getSMA:n,getEMA:i},l=t=>{if(!t||0===t.length)throw new Error("Bins array is empty or not provided");let i=t[0],e=t[0];return t.forEach((t=>{t.grossVolume>i.grossVolume&&(i=t),t.grossVolume<e.grossVolume&&(e=t)})),{high:i,low:e}};class a{constructor(t,i=100){const e=["open","high","low","close"];for(let[s,n]of Object.entries(t))e.includes(s)&&(this[s]=n.splice(-i))}init(){if(this.close.length<50)return console.log("PatternRecognizer requires at least 50 datapoints"),{chart_pattern:"Neutral",chart_score:0};const t=[{name:"Bullish Flag",condition:this.isBullishFlag.bind(this),score:2},{name:"Bearish Flag",condition:this.isBearishFlag.bind(this),score:-2},{name:"Bullish Pennant",condition:this.isBullishPennant.bind(this),score:2},{name:"Bearish Pennant",condition:this.isBearishPennant.bind(this),score:-2},{name:"Bearish Double Top",condition:this.isDoubleTop.bind(this),score:-1},{name:"Bullish Double Bottom",condition:this.isDoubleBottom.bind(this),score:1},{name:"Bearish Triple Top",condition:this.isTripleTop.bind(this),score:-1},{name:"Bullish Triple Bottom",condition:this.isTripleBottom.bind(this),score:1},{name:"Bearish Head And Shoulders",condition:this.isHeadAndShoulders.bind(this),score:-1},{name:"Bullish Inverse Head And Shoulders",condition:this.isInverseHeadAndShoulders.bind(this),score:1},{name:"Bearish Rising Wedge",condition:this.isRisingWedge.bind(this),score:-1},{name:"Bullish Falling Wedge",condition:this.isFallingWedge.bind(this),score:1},{name:"Bullish Triangle",condition:this.isBullishTriangle.bind(this),score:1},{name:"Bearish Triangle",condition:this.isBearishTriangle.bind(this),score:-1},{name:"Bullish Rectangle",condition:this.isBullishRectangle.bind(this),score:1},{name:"Bearish Rectangle",condition:this.isBearishRectangle.bind(this),score:-1}];for(const{name:i,condition:e,score:s}of t)if(e())return{chart_pattern:i,chart_score:s};return{chart_pattern:"Neutral",chart_score:0}}isBullishFlag(){const t=this.close.length,i=Math.floor(t/3),e=(Math.floor(i/2),this.close[t-2*i]);if((this.close[t-i]-e)/e<.15)return!1;const s=this.close[t-i];if((s-this.close[t-1])/s>.05)return!1;for(let e=t-i;e<t-1;e++)if(this.high[e]>this.high[e+1]||this.low[e]>this.low[e+1])return!1;return!0}isBearishFlag(){const t=this.close.length,i=Math.floor(t/3),e=(Math.floor(i/2),this.close[t-2*i]);if((e-this.close[t-i])/e<.15)return!1;const s=this.close[t-i];if((this.close[t-1]-s)/s>.05)return!1;for(let e=t-i;e<t-1;e++)if(this.high[e]<this.high[e+1]||this.low[e]<this.low[e+1])return!1;return!0}isBullishPennant(){const t=this.close.length,i=Math.floor(t/3),e=Math.floor(i/2),s=this.close[t-2*i];if((this.close[t-i]-s)/s<.15)return!1;const n=this.close[t-i];if((n-this.close[t-1])/n>.05)return!1;for(let i=t-e;i<t-1;i++)if(this.high[i]<this.high[i+1]&&this.low[i]<this.low[i+1]||this.high[i]>this.high[i+1]&&this.low[i]>this.low[i+1])return!1;return!0}isBearishPennant(){const t=this.close.length,i=Math.floor(t/3),e=Math.floor(i/2),s=this.close[t-2*i];if((s-this.close[t-i])/s<.15)return!1;const n=this.close[t-i];if((this.close[t-1]-n)/n>.05)return!1;for(let i=t-e;i<t-1;i++)if(this.high[i]>this.high[i+1]&&this.low[i]>this.low[i+1]||this.high[i]<this.high[i+1]&&this.low[i]<this.low[i+1])return!1;return!0}isDoubleTop(){const t=this.close.length,i=Math.floor(t/2),e=Math.max(...this.close.slice(0,i)),s=Math.max(...this.close.slice(i));if(e<=0||s<=0)return!1;const n=Math.min(...this.close.slice(0,i)),o=Math.min(...this.close.slice(i));return!((e-n)/e<.1||(s-o)/s<.1)&&Math.abs(e-s)/e<.03}isDoubleBottom(){const t=this.close.length,i=Math.floor(t/2),e=Math.min(...this.close.slice(0,i)),s=Math.min(...this.close.slice(i));if(e<=0||s<=0)return!1;const n=Math.max(...this.close.slice(0,i)),o=Math.max(...this.close.slice(i));return!((n-e)/e<.1||(o-s)/s<.1)&&Math.abs(e-s)/e<.03}isTripleTop(){const t=this.close.length,i=Math.floor(t/3),e=Math.max(...this.close.slice(0,i)),s=Math.max(...this.close.slice(i,2*i)),n=Math.max(...this.close.slice(2*i));if(e<=0||s<=0||n<=0)return!1;const o=(e-Math.min(...this.close.slice(0,i)))/e,r=(s-Math.min(...this.close.slice(i,2*i)))/s,h=(n-Math.min(...this.close.slice(2*i)))/n;return!(o<.1||r<.1||h<.1)&&Math.abs(e-s)/e<.03&&Math.abs(e-n)/e<.03}isTripleBottom(){const t=this.close.length,i=Math.floor(t/3),e=Math.min(...this.close.slice(0,i)),s=Math.min(...this.close.slice(i,2*i)),n=Math.min(...this.close.slice(2*i));if(e<=0||s<=0||n<=0)return!1;const o=(Math.max(...this.close.slice(0,i))-e)/e,r=(Math.max(...this.close.slice(i,2*i))-s)/s,h=(Math.max(...this.close.slice(2*i))-n)/n;return!(o<.1||r<.1||h<.1)&&Math.abs(e-s)/e<.03&&Math.abs(e-n)/e<.03}isHeadAndShoulders(){const t=this.close.length,i=Math.floor(t/3),e=Math.max(...this.close.slice(0,i)),s=Math.max(...this.close.slice(i,2*i)),n=Math.max(...this.close.slice(2*i));if(e<=0||s<=0||n<=0)return!1;const o=Math.min(...this.close.slice(0,i)),r=Math.min(...this.close.slice(i,2*i)),h=Math.min(...this.close.slice(2*i)),l=(s-r)/s,a=(Math.max(o,h)-Math.min(o,h))/Math.min(o,h);return l>.15&&a<.03}isInverseHeadAndShoulders(){const t=this.close.length,i=Math.floor(t/3),e=Math.min(...this.close.slice(0,i)),s=Math.min(...this.close.slice(i,2*i)),n=Math.min(...this.close.slice(2*i));if(e<=0||s<=0||n<=0)return!1;const o=Math.max(...this.close.slice(0,i)),r=Math.max(...this.close.slice(i,2*i)),h=Math.max(...this.close.slice(2*i)),l=(r-s)/s,a=(Math.min(o,h)-Math.max(o,h))/Math.max(o,h);return l>.15&&a<.03}isRisingWedge(){const t=this.close.length,i=Math.floor(t/3),e=Math.max(...this.close.slice(0,i)),s=Math.max(...this.close.slice(i,2*i)),n=Math.max(...this.close.slice(2*i)),o=Math.min(...this.close.slice(0,i)),r=Math.min(...this.close.slice(i,2*i)),h=Math.min(...this.close.slice(2*i));return e<s&&s<n&&o<r&&r<h}isFallingWedge(){const t=this.close.length,i=Math.floor(t/3),e=Math.max(...this.close.slice(0,i)),s=Math.max(...this.close.slice(i,2*i)),n=Math.max(...this.close.slice(2*i)),o=Math.min(...this.close.slice(0,i)),r=Math.min(...this.close.slice(i,2*i)),h=Math.min(...this.close.slice(2*i));return e>s&&s>n&&o>r&&r>h}isBullishTriangle(){const t=this.close.length,i=Math.floor(t/2),e=Math.max(...this.high.slice(0,i)),s=Math.max(...this.high.slice(i)),n=Math.min(...this.low.slice(0,i)),o=Math.min(...this.low.slice(i));return e>s&&n<o}isBearishTriangle(){const t=this.close.length,i=Math.floor(t/2),e=Math.max(...this.high.slice(0,i)),s=Math.max(...this.high.slice(i));return Math.min(...this.low.slice(0,i))<Math.min(...this.low.slice(i))&&e>s}isBullishRectangle(){const t=this.close.length,i=Math.floor(t/3),e=Math.max(...this.high.slice(0,i)),s=Math.max(...this.high.slice(i,2*i)),n=Math.max(...this.high.slice(2*i)),o=Math.min(...this.low.slice(0,i)),r=Math.min(...this.low.slice(i,2*i)),h=Math.min(...this.low.slice(2*i)),l=Math.abs(e-s)/e<.03&&Math.abs(s-n)/s<.03,a=Math.abs(o-r)/o<.03&&Math.abs(r-h)/r<.03;return l&&a}isBearishRectangle(){const t=this.close.length,i=Math.floor(t/3),e=Math.max(...this.high.slice(0,i)),s=Math.max(...this.high.slice(i,2*i)),n=Math.max(...this.high.slice(2*i)),o=Math.min(...this.low.slice(0,i)),r=Math.min(...this.low.slice(i,2*i)),h=Math.min(...this.low.slice(2*i)),l=Math.abs(e-s)/e<.03&&Math.abs(s-n)/s<.03,a=Math.abs(o-r)/o<.03&&Math.abs(r-h)/r<.03;return l&&a}}class u{constructor(){this.ChartPatterns=t=>new a(t).init()}init(t){return this.rawOhlcv=t,this.ohlcv=t.reduce(((t,{open:i,high:e,low:s,close:n,volume:o,...r})=>{t.open.push(i),t.high.push(e),t.low.push(s),t.close.push(n),t.volume.push(o);for(const i of Object.keys(r))t[i]||(t[i]=[]),t[i].push(r[i]);return t}),{open:[],high:[],low:[],close:[],volume:[]}),this}getHeaders(){return Object.keys(this.ohlcv)}getData(){const{ohlcv:t}=this,i=Object.keys(t),e=i.length;return t.open.map(((s,n)=>{const o={};for(let s=0;s<e;s++){const e=i[s];o[e]=t[e][n]}return o}))}getLastValues(){const t={};for(const[i,e]of Object.entries(this.ohlcv)){let s=e[e.length-1];t[i]=s}return t}addColumn(t,i){const e=this.ohlcv.open.length;if(i.length>e)throw new Error("Invalid column data: The length of the new column exceeds the length of the OHLCV data");i=[...new Array(e-i.length).fill(null),...i],this.ohlcv[t]=i}crossPairs(t){const i=this.ohlcv,e={},s=t=>{if(!i.hasOwnProperty(t)&&"string"==typeof t){const[i,...e]=t.split("_");this[i]&&e.length>0&&this[i](...e)}};for(const{fast:n,slow:r}of t)if(n&&r)if(s(n),s(r),"number"!=typeof r||e[r]||(e[r]=i.close.map((()=>r))),i[n]&&i[r]){const t=o(i[n],i[r]);this.addColumn(`${n}_x_${r}`,t)}else if(i[n]&&e[r]){const t=o(i[n],e[r]);this.addColumn(`${n}_x_${r}`,t)}else console.error(`Missing ohlcv properties for ${n} or ${r}`)}ema(t){return((t,e)=>{const{ohlcv:s}=t,n=s.close,o=i(n,e);t.addColumn(`ema_${e}`,o)})(this,t),this}sma(t){return((t,i)=>{const{ohlcv:e}=t,s=e.close,o=n(s,i);t.addColumn(`sma_${i}`,o)})(this,t),this}macd(t,e,s){return((t,e=12,s=26,n=9)=>{const{ohlcv:r}=t,h=((t,e=12,s=26,n=9)=>{const r=i(t,e),h=i(t,s),l=r.map(((t,i)=>isNaN(t)||isNaN(h[i])?null:t-h[i])),a=i(l,n),u=l.map(((t,i)=>t-a[i])),c=o(l,a);return{macd_diff:l,macd_dea:a,macd_histogram:u,macd_diff_x_macd_dea:c}})(r.close,e,s,n);for(let i in h)t.addColumn(i,h[i])})(this,t,e,s),this}bollingerBands(i,e,s){return((i,e,s)=>{const{ohlcv:n}=i,o=((i,e=20,s=2)=>{const n={lower:[],middle:[],upper:[]},o=new t.BollingerBands(e,s);i.forEach((t=>{const i=o.nextValue(t);if("object"==typeof i){const{lower:t,middle:e,upper:s}=i;n.lower.push(t),n.middle.push(e),n.upper.push(s)}else n.lower.push(null),n.middle.push(null),n.upper.push(null)}));const h=r(i,{upper:n.upper,lower:n.lower});return{...n,range:h}})(n.close,e,s);for(let t in o)i.addColumn(`bollinger_bands_${t}`,o[t])})(this,i,e),this}rsi(i,e,s){return((i,e,s,n)=>{const{ohlcv:r}=i;"number"==typeof e&&void 0===n&&(n=e);const l=((i,e=14,s="SMA",n=14)=>{if(i.length<e)return[];let r=[];e=parseInt(e),n=parseInt(n);const l=new t.RSI(e);i.forEach((t=>{r.push(l.nextValue(t))})),r=r.filter((t=>t));let a={[`rsi_${e}`]:r};if("string"==typeof s&&"number"==typeof n&&h.hasOwnProperty(`get${s}`)){const t=h[`get${s}`](r,n);a[`rsi_${s}_${n}`]=t,a[`rsi_${e}_x_rsi_${s}_${n}`]=o(r,t)}return a})(r.close,e,s,n);for(let t in l)i.addColumn(`${t}`.toLowerCase(),l[t])})(this,i,e,s),this}candles(){return(t=>{const{ohlcv:i}=t,e=(t=>{const{open:i,high:e,low:s,close:n}=t,o=i.length;if(![i,e,s,n].every((t=>Array.isArray(t)&&t.length>1&&t.length===o)))return{pattern:Array(o).fill("Neutral"),name:Array(o).fill("No Pattern"),score:Array(o).fill(0)};const r=(t,i,e=1e-4)=>Math.abs(t-i)<e,h={bullish:[{name:"Marubozu",condition:(t,i)=>r(i.open,i.low)&&r(i.close,i.high),score:2},{name:"Engulfing",condition:(t,i)=>i.open<t.close&&i.close>t.open&&i.low<t.low&&i.high>t.high,score:2},{name:"Kicker",condition:(t,i)=>i.open<t.open&&i.close>i.open&&t.close<t.open,score:2},{name:"Morning Star",condition:(t,i)=>i.close>t.close&&i.open<t.open&&t.close<t.open,score:2},{name:"Piercing Line",condition:(t,i)=>i.close>t.close&&i.open<t.open&&i.close>(t.open+t.close)/2,score:1},{name:"Belt Hold",condition:(t,i)=>i.open>t.open&&r(i.close,i.high)&&r(t.close,t.low),score:1},{name:"Harami",condition:(t,i)=>i.open>t.close&&i.close<t.open&&i.open<t.open&&i.close>t.close,score:1},{name:"Doji",condition:(t,i)=>r(i.close,i.open)&&i.high-i.low>Math.abs(i.close-i.open),score:0}],bearish:[{name:"Marubozu",condition:(t,i)=>r(i.open,i.high)&&r(i.close,i.low),score:-2},{name:"Engulfing",condition:(t,i)=>i.open>t.close&&i.close<t.open&&i.high>t.high&&i.low<t.low,score:-2},{name:"Kicker",condition:(t,i)=>i.open>t.open&&i.close<i.open&&t.close>t.open,score:-2},{name:"Evening Star",condition:(t,i)=>i.close<t.close&&i.open>t.open&&t.close<t.open,score:-2},{name:"Dark Cloud Cover",condition:(t,i)=>i.close<t.close&&i.open>t.open&&i.close<(t.open+t.close)/2,score:-1},{name:"Belt Hold",condition:(t,i)=>i.open<t.open&&r(i.close,i.low)&&r(t.close,t.high),score:-1},{name:"Harami",condition:(t,i)=>i.open<t.close&&i.close>t.open&&i.open>t.open&&i.close<t.close,score:-1},{name:"Doji",condition:(t,i)=>r(i.close,i.open)&&i.high-i.low>Math.abs(i.close-i.open),score:0}]},l=(t,i,e)=>{for(const{name:s,condition:n,score:o}of e)if(n(t,i))return{name:s,score:o};return null},a=["Neutral"],u=["No Pattern"],c=[0];for(let t=1;t<o;t++){const o={open:i[t-1],high:e[t-1],low:s[t-1],close:n[t-1]},r={open:i[t],high:e[t],low:s[t],close:n[t]},p=l(o,r,h.bullish)||l(o,r,h.bearish);p?(a.push(p.score>0?"Bullish":"Bearish"),u.push(p.name),c.push(p.score)):(a.push("Neutral"),u.push("No Pattern"),c.push(0))}return{pattern:a,name:u,score:c}})(i);for(let i in e)t.addColumn(`candle_${i}`.toLowerCase(),e[i])})(this),this}volumeProfile(t,i,e){return((t,i,e=1,s)=>{let{ohlcv:n}=t;const o=((t,i,e)=>{const s=new Date(t[e][t[e].length-1]),n=new Date(s);n.setDate(n.getDate()-i),n.setHours(0,0,0,0);const o={open:[],high:[],low:[],close:[],volume:[],[e]:[]};for(let i=0;i<t[e].length;i++)new Date(t[e][i])>=n&&(o.open.push(t.open[i]),o.high.push(t.high[i]),o.low.push(t.low[i]),o.close.push(t.close[i]),o.volume.push(t.volume[i]),o[e].push(t[e][i]));return o})(n,e,s),r=((t,i=5)=>{const{open:e,high:s,low:n,close:o,volume:r}=t,h=Math.min(...n),a=(Math.max(...s)-h)/i,u={upVolume:0,downVolume:0,grossVolume:0},c=Array.from({length:i},((t,i)=>({price:h+a*i,upVolume:0,downVolume:0,grossVolume:0}))),p=1/a;for(let t=0;t<o.length;t++){const l=o[t],a=e[t],u=s[t],d=n[t],f=r[t],m=l>=a?f:0,v=l<a?f:0,g=Math.max(0,Math.floor((d-h)*p)),w=Math.min(i,Math.ceil((u-h)*p));for(let t=g;t<w;t++)c[t].upVolume+=m,c[t].downVolume+=v,c[t].grossVolume+=m+v}for(const{upVolume:t,downVolume:i,grossVolume:e}of c)u.upVolume+=t,u.downVolume+=i,u.grossVolume+=e;return{bins:c,nodes:l(c)}})(o,i),h=r.nodes.high.price,a=r.nodes.low.price;t.addColumn("volume_profile_high",[h]),t.addColumn("volume_profile_low",[a])})(this,t,i,e),this}}})(),OHLCV_INDICATORS=s})();
|
|
1
|
+
var OHLCV_INDICATORS;(()=>{"use strict";var t={d:(e,s)=>{for(var i in s)t.o(s,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:s[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};(()=>{t.r(e),t.d(e,{default:()=>V});var s=1e6,i="[big.js] ",o=i+"Invalid ",h=o+"decimal places",r=o+"rounding mode",n=i+"Division by zero",l={},c=void 0,a=/^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i;function u(t,e,s,i){var o=t.c;if(s===c&&(s=t.constructor.RM),0!==s&&1!==s&&2!==s&&3!==s)throw Error(r);if(e<1)i=3===s&&(i||!!o[0])||0===e&&(1===s&&o[0]>=5||2===s&&(o[0]>5||5===o[0]&&(i||o[1]!==c))),o.length=1,i?(t.e=t.e-e+1,o[0]=1):o[0]=t.e=0;else if(e<o.length){if(i=1===s&&o[e]>=5||2===s&&(o[e]>5||5===o[e]&&(i||o[e+1]!==c||1&o[e-1]))||3===s&&(i||!!o[0]),o.length=e,i)for(;++o[--e]>9;)if(o[e]=0,0===e){++t.e,o.unshift(1);break}for(e=o.length;!o[--e];)o.pop()}return t}function p(t,e,s){var i=t.e,o=t.c.join(""),h=o.length;if(e)o=o.charAt(0)+(h>1?"."+o.slice(1):"")+(i<0?"e":"e+")+i;else if(i<0){for(;++i;)o="0"+o;o="0."+o}else if(i>0)if(++i>h)for(i-=h;i--;)o+="0";else i<h&&(o=o.slice(0,i)+"."+o.slice(i));else h>1&&(o=o.charAt(0)+"."+o.slice(1));return t.s<0&&s?"-"+o:o}l.abs=function(){var t=new this.constructor(this);return t.s=1,t},l.cmp=function(t){var e,s=this,i=s.c,o=(t=new s.constructor(t)).c,h=s.s,r=t.s,n=s.e,l=t.e;if(!i[0]||!o[0])return i[0]?h:o[0]?-r:0;if(h!=r)return h;if(e=h<0,n!=l)return n>l^e?1:-1;for(r=(n=i.length)<(l=o.length)?n:l,h=-1;++h<r;)if(i[h]!=o[h])return i[h]>o[h]^e?1:-1;return n==l?0:n>l^e?1:-1},l.div=function(t){var e=this,i=e.constructor,o=e.c,r=(t=new i(t)).c,l=e.s==t.s?1:-1,a=i.DP;if(a!==~~a||a<0||a>s)throw Error(h);if(!r[0])throw Error(n);if(!o[0])return t.s=l,t.c=[t.e=0],t;var p,g,v,f,d,m=r.slice(),w=p=r.length,M=o.length,b=o.slice(0,p),x=b.length,R=t,B=R.c=[],y=0,P=a+(R.e=e.e-t.e)+1;for(R.s=l,l=P<0?0:P,m.unshift(0);x++<p;)b.push(0);do{for(v=0;v<10;v++){if(p!=(x=b.length))f=p>x?1:-1;else for(d=-1,f=0;++d<p;)if(r[d]!=b[d]){f=r[d]>b[d]?1:-1;break}if(!(f<0))break;for(g=x==p?r:m;x;){if(b[--x]<g[x]){for(d=x;d&&!b[--d];)b[d]=9;--b[d],b[x]+=10}b[x]-=g[x]}for(;!b[0];)b.shift()}B[y++]=f?v:++v,b[0]&&f?b[x]=o[w]||0:b=[o[w]]}while((w++<M||b[0]!==c)&&l--);return B[0]||1==y||(B.shift(),R.e--,P--),y>P&&u(R,P,i.RM,b[0]!==c),R},l.eq=function(t){return 0===this.cmp(t)},l.gt=function(t){return this.cmp(t)>0},l.gte=function(t){return this.cmp(t)>-1},l.lt=function(t){return this.cmp(t)<0},l.lte=function(t){return this.cmp(t)<1},l.minus=l.sub=function(t){var e,s,i,o,h=this,r=h.constructor,n=h.s,l=(t=new r(t)).s;if(n!=l)return t.s=-l,h.plus(t);var c=h.c.slice(),a=h.e,u=t.c,p=t.e;if(!c[0]||!u[0])return u[0]?t.s=-l:c[0]?t=new r(h):t.s=1,t;if(n=a-p){for((o=n<0)?(n=-n,i=c):(p=a,i=u),i.reverse(),l=n;l--;)i.push(0);i.reverse()}else for(s=((o=c.length<u.length)?c:u).length,n=l=0;l<s;l++)if(c[l]!=u[l]){o=c[l]<u[l];break}if(o&&(i=c,c=u,u=i,t.s=-t.s),(l=(s=u.length)-(e=c.length))>0)for(;l--;)c[e++]=0;for(l=e;s>n;){if(c[--s]<u[s]){for(e=s;e&&!c[--e];)c[e]=9;--c[e],c[s]+=10}c[s]-=u[s]}for(;0===c[--l];)c.pop();for(;0===c[0];)c.shift(),--p;return c[0]||(t.s=1,c=[p=0]),t.c=c,t.e=p,t},l.mod=function(t){var e,s=this,i=s.constructor,o=s.s,h=(t=new i(t)).s;if(!t.c[0])throw Error(n);return s.s=t.s=1,e=1==t.cmp(s),s.s=o,t.s=h,e?new i(s):(o=i.DP,h=i.RM,i.DP=i.RM=0,s=s.div(t),i.DP=o,i.RM=h,this.minus(s.times(t)))},l.neg=function(){var t=new this.constructor(this);return t.s=-t.s,t},l.plus=l.add=function(t){var e,s,i,o=this,h=o.constructor;if(t=new h(t),o.s!=t.s)return t.s=-t.s,o.minus(t);var r=o.e,n=o.c,l=t.e,c=t.c;if(!n[0]||!c[0])return c[0]||(n[0]?t=new h(o):t.s=o.s),t;if(n=n.slice(),e=r-l){for(e>0?(l=r,i=c):(e=-e,i=n),i.reverse();e--;)i.push(0);i.reverse()}for(n.length-c.length<0&&(i=c,c=n,n=i),e=c.length,s=0;e;n[e]%=10)s=(n[--e]=n[e]+c[e]+s)/10|0;for(s&&(n.unshift(s),++l),e=n.length;0===n[--e];)n.pop();return t.c=n,t.e=l,t},l.pow=function(t){var e=this,s=new e.constructor("1"),i=s,h=t<0;if(t!==~~t||t<-1e6||t>1e6)throw Error(o+"exponent");for(h&&(t=-t);1&t&&(i=i.times(e)),t>>=1;)e=e.times(e);return h?s.div(i):i},l.prec=function(t,e){if(t!==~~t||t<1||t>s)throw Error(o+"precision");return u(new this.constructor(this),t,e)},l.round=function(t,e){if(t===c)t=0;else if(t!==~~t||t<-s||t>s)throw Error(h);return u(new this.constructor(this),t+this.e+1,e)},l.sqrt=function(){var t,e,s,o=this,h=o.constructor,r=o.s,n=o.e,l=new h("0.5");if(!o.c[0])return new h(o);if(r<0)throw Error(i+"No square root");0===(r=Math.sqrt(o+""))||r===1/0?((e=o.c.join("")).length+n&1||(e+="0"),n=((n+1)/2|0)-(n<0||1&n),t=new h(((r=Math.sqrt(e))==1/0?"5e":(r=r.toExponential()).slice(0,r.indexOf("e")+1))+n)):t=new h(r+""),n=t.e+(h.DP+=4);do{s=t,t=l.times(s.plus(o.div(s)))}while(s.c.slice(0,n).join("")!==t.c.slice(0,n).join(""));return u(t,(h.DP-=4)+t.e+1,h.RM)},l.times=l.mul=function(t){var e,s=this,i=s.constructor,o=s.c,h=(t=new i(t)).c,r=o.length,n=h.length,l=s.e,c=t.e;if(t.s=s.s==t.s?1:-1,!o[0]||!h[0])return t.c=[t.e=0],t;for(t.e=l+c,r<n&&(e=o,o=h,h=e,c=r,r=n,n=c),e=new Array(c=r+n);c--;)e[c]=0;for(l=n;l--;){for(n=0,c=r+l;c>l;)n=e[c]+h[l]*o[c-l-1]+n,e[c--]=n%10,n=n/10|0;e[c]=n}for(n?++t.e:e.shift(),l=e.length;!e[--l];)e.pop();return t.c=e,t},l.toExponential=function(t,e){var i=this,o=i.c[0];if(t!==c){if(t!==~~t||t<0||t>s)throw Error(h);for(i=u(new i.constructor(i),++t,e);i.c.length<t;)i.c.push(0)}return p(i,!0,!!o)},l.toFixed=function(t,e){var i=this,o=i.c[0];if(t!==c){if(t!==~~t||t<0||t>s)throw Error(h);for(t=t+(i=u(new i.constructor(i),t+i.e+1,e)).e+1;i.c.length<t;)i.c.push(0)}return p(i,!1,!!o)},l[Symbol.for("nodejs.util.inspect.custom")]=l.toJSON=l.toString=function(){var t=this,e=t.constructor;return p(t,t.e<=e.NE||t.e>=e.PE,!!t.c[0])},l.toNumber=function(){var t=Number(p(this,!0,!0));if(!0===this.constructor.strict&&!this.eq(t.toString()))throw Error(i+"Imprecise conversion");return t},l.toPrecision=function(t,e){var i=this,h=i.constructor,r=i.c[0];if(t!==c){if(t!==~~t||t<1||t>s)throw Error(o+"precision");for(i=u(new h(i),t,e);i.c.length<t;)i.c.push(0)}return p(i,t<=i.e||i.e<=h.NE||i.e>=h.PE,!!r)},l.valueOf=function(){var t=this,e=t.constructor;if(!0===e.strict)throw Error(i+"valueOf disallowed");return p(t,t.e<=e.NE||t.e>=e.PE,!0)};const g=function t(){function e(s){var i=this;if(!(i instanceof e))return s===c?t():new e(s);if(s instanceof e)i.s=s.s,i.e=s.e,i.c=s.c.slice();else{if("string"!=typeof s){if(!0===e.strict&&"bigint"!=typeof s)throw TypeError(o+"value");s=0===s&&1/s<0?"-0":String(s)}!function(t,e){var s,i,h;if(!a.test(e))throw Error(o+"number");for(t.s="-"==e.charAt(0)?(e=e.slice(1),-1):1,(s=e.indexOf("."))>-1&&(e=e.replace(".","")),(i=e.search(/e/i))>0?(s<0&&(s=i),s+=+e.slice(i+1),e=e.substring(0,i)):s<0&&(s=e.length),h=e.length,i=0;i<h&&"0"==e.charAt(i);)++i;if(i==h)t.c=[t.e=0];else{for(;h>0&&"0"==e.charAt(--h););for(t.e=s-i-1,t.c=[],s=0;i<=h;)t.c[s++]=+e.charAt(i++)}}(i,s)}i.constructor=e}return e.prototype=l,e.DP=20,e.RM=1,e.NE=-7,e.PE=21,e.strict=!1,e.roundDown=0,e.roundHalfUp=1,e.roundHalfEven=2,e.roundUp=3,e}();class v extends Error{constructor(t="Not enough data"){super(t),Object.setPrototypeOf(this,new.target.prototype),this.name="NotEnoughDataError"}}class f{previousHighest;highest;previousLowest;lowest;previousResult;result;get isStable(){return void 0!==this.result}getResult(){if(void 0===this.result)throw new v;return this.result}setResult(t,e){return e&&(this.highest=this.previousHighest,this.lowest=this.previousLowest,this.result=this.previousResult),void 0===this.highest?this.highest=t:t.gt(this.highest)?(this.previousHighest=this.highest,this.highest=t):this.previousHighest=this.highest,void 0===this.lowest?this.lowest=t:t.lt(this.lowest)?(this.previousLowest=this.lowest,this.lowest=t):this.previousLowest=this.lowest,this.previousResult=this.result,this.result=t}replace(t){return this.update(t,!0)}}class d extends f{interval;constructor(t){super(),this.interval=t}updates(t){return t.forEach((t=>this.update(t))),this.result}replace(t){return this.update(t,!0)}}class m extends d{prices=[];update(t,e=!1){if(this.prices.length&&e?this.prices[this.prices.length-1]=t:this.prices.push(t),this.prices.length>this.interval&&this.prices.shift(),this.prices.length===this.interval)return this.setResult(m.getResultFromBatch(this.prices),e)}static getResultFromBatch(t){return t.reduce(((t,e)=>t.plus(e)),new g("0")).div(t.length||1)}}class w extends d{interval;indicator;smoothingFactor;constructor(t){super(t),this.interval=t,this.indicator=new m(t),this.smoothingFactor=new g(1).div(this.interval)}updates(t){return t.forEach((t=>this.update(t))),this.result}update(t,e=!1){const s=this.indicator.update(t,e);if(e&&this.previousResult){const s=new g(t).minus(this.previousResult).mul(this.smoothingFactor);return this.setResult(s.plus(this.previousResult),e)}if(!e&&this.result){const s=new g(t).minus(this.result).mul(this.smoothingFactor);return this.setResult(s.plus(this.result),e)}if(void 0===this.result&&s)return this.setResult(s,e)}}function M(t){return t.reduce(((t,e)=>t.add(e)),new g(0)).div(t.length||1)}class b{interval;deviationMultiplier;prices=[];result;constructor(t,e=2){this.interval=t,this.deviationMultiplier=e}get isStable(){return void 0!==this.result}update(t){if(this.prices.push(new g(t)),this.prices.length>this.interval){this.prices.shift();const t=m.getResultFromBatch(this.prices),e=function(t,e){const s=e||M(t);return M(t.map((t=>new g(t).sub(s).pow(2)))).sqrt()}(this.prices,t);return this.result={lower:t.sub(e.times(this.deviationMultiplier)),middle:t,upper:t.add(e.times(this.deviationMultiplier))}}}getResult(){if(void 0===this.result)throw new v;return this.result}}class x extends d{interval;pricesCounter=0;weightFactor;constructor(t){super(t),this.interval=t,this.weightFactor=2/(this.interval+1)}update(t,e=!1){e?e&&0===this.pricesCounter&&this.pricesCounter++:this.pricesCounter++;const s=new g(t);return e&&this.previousResult?this.setResult(s.times(this.weightFactor).add(this.previousResult.times(1-this.weightFactor)),e):this.setResult(s.times(this.weightFactor).add((this.result??s).times(1-this.weightFactor)),e)}getResult(){if(this.pricesCounter<this.interval)throw new v;return this.result}get isStable(){try{return this.getResult(),!0}catch{return!1}}}class R{prices=[];long;short;signal;result;constructor(t){this.long=new t.indicator(t.longInterval),this.short=new t.indicator(t.shortInterval),this.signal=new t.indicator(t.signalInterval)}get isStable(){return void 0!==this.result}update(t,e=!1){const s=new g(t);this.prices.length&&e?this.prices[this.prices.length-1]=s:this.prices.push(s);const i=this.short.update(s,e),o=this.long.update(s,e);if(this.prices.length>this.long.interval&&this.prices.shift(),this.prices.length===this.long.interval){const t=i.sub(o),e=this.signal.update(t);return this.result={histogram:t.sub(e),macd:t,signal:e}}}getResult(){if(!this.isStable||void 0===this.result)throw new v;return this.result}}class B extends f{interval;previousPrices=[];avgGain;avgLoss;maxValue=new g(100);constructor(t,e=w){super(),this.interval=t,this.avgGain=new e(this.interval),this.avgLoss=new e(this.interval)}update(t,e=!1){if(this.previousPrices.length&&e?this.previousPrices[this.previousPrices.length-1]=t:this.previousPrices.push(t),this.previousPrices.length<2)return;const s=new g(t),i=new g(this.previousPrices[this.previousPrices.length-2]);if(s.gt(i)?(this.avgLoss.update(new g(0),e),this.avgGain.update(s.sub(i),e)):(this.avgLoss.update(i.sub(s),e),this.avgGain.update(new g(0),e)),this.avgGain.isStable){const t=this.avgLoss.getResult();if(t.eq(0))return this.setResult(new g(100),e);const s=this.avgGain.getResult().div(t);return this.setResult(this.maxValue.minus(this.maxValue.div(s.add(1))),e)}}}const y=(t,e)=>{const s=[],i=new x(e),o=t.length;for(let e=0;e<o;e++){let o=null;i.update(t[e]);try{o=i.getResult()}catch(t){o=null}s.push(o)}return s},P=(t,e)=>{const s=[],i=new m(e),o=t.length;for(let e=0;e<o;e++){let o=null;i.update(t[e]);try{o=i.getResult()}catch(t){o=null}s.push(o)}return s},E=(t,e)=>{t=t.filter((t=>t instanceof g)),e=e.filter((t=>t instanceof g));const s=Math.min(t.length,e.length);t=t.slice(-s),e=e.slice(-s);let i=t.map(((t,s)=>{if(t.eq(e[s]))return"neutral";if(t.gt(e[s]))return"up";if(t.lt(e[s]))return"down";throw Error("undefined error in findCrosses")}));const o=_(i),h=o.map((t=>t.length));return o.map(((t,e)=>{let s=h[e];return t.map(((t,e)=>{let i=s-e;return"neutral"===t&&(i=0),"up"===t&&(i*=1),"down"===t&&(i*=-1),i})).reverse()})).flat()},_=t=>0===t.length?[]:t.reduce(((t,e,s,i)=>{if(0===s)t.push([e]);else{const o=i[s-1],h=t[t.length-1];e!==o?t.push([e]):h.push(e)}return t}),[]),S=(t,e)=>{const{upper:s,lower:i}=e,o=new Array(t.length);for(let e=0;e<t.length;e++)if(null!=s[e]&&null!=i[e]&&null!=t[e]){const h=new g(s[e]),r=new g(i[e]),n=new g(t[e]),l=h.minus(r);o[e]=n.minus(r).div(l).times(100).toNumber()}else o[e]=null;return o},C={getSMA:P,getEMA:y},D=t=>{if(!t||0===t.length)throw new Error("Bins array is empty or not provided");let e=t[0],s=t[0];return t.forEach((t=>{t.grossVolume>e.grossVolume&&(e=t),t.grossVolume<s.grossVolume&&(s=t)})),{high:e,low:s}};class A{constructor(t,e=100){const s=["open","high","low","close"];this.ohlcv={};for(let i of Object.keys(t))s.includes(i)&&(this.ohlcv[i]=t[i].slice(-e))}init(){if(this.ohlcv.close.length<50)return console.log("PatternRecognizer requires at least 50 datapoints"),{chart_pattern:"Neutral",chart_score:0};const t=[{name:"Bullish Flag",condition:this.isBullishFlag.bind(this),score:2},{name:"Bearish Flag",condition:this.isBearishFlag.bind(this),score:-2},{name:"Bullish Pennant",condition:this.isBullishPennant.bind(this),score:2},{name:"Bearish Pennant",condition:this.isBearishPennant.bind(this),score:-2},{name:"Bearish Double Top",condition:this.isDoubleTop.bind(this),score:-1},{name:"Bullish Double Bottom",condition:this.isDoubleBottom.bind(this),score:1},{name:"Bearish Triple Top",condition:this.isTripleTop.bind(this),score:-1},{name:"Bullish Triple Bottom",condition:this.isTripleBottom.bind(this),score:1},{name:"Bearish Head And Shoulders",condition:this.isHeadAndShoulders.bind(this),score:-1},{name:"Bullish Inverse Head And Shoulders",condition:this.isInverseHeadAndShoulders.bind(this),score:1},{name:"Bearish Rising Wedge",condition:this.isRisingWedge.bind(this),score:-1},{name:"Bullish Falling Wedge",condition:this.isFallingWedge.bind(this),score:1},{name:"Bullish Triangle",condition:this.isBullishTriangle.bind(this),score:1},{name:"Bearish Triangle",condition:this.isBearishTriangle.bind(this),score:-1},{name:"Bullish Rectangle",condition:this.isBullishRectangle.bind(this),score:1},{name:"Bearish Rectangle",condition:this.isBearishRectangle.bind(this),score:-1}];for(const{name:e,condition:s,score:i}of t)if(s())return{chart_pattern:e,chart_score:i};return{chart_pattern:"Neutral",chart_score:0}}isBullishFlag(){const t=this.ohlcv.close.length,e=Math.floor(t/3),s=(Math.floor(e/2),this.ohlcv.close[t-2*e]);if((this.ohlcv.close[t-e]-s)/s<.15)return!1;const i=this.ohlcv.close[t-e];if((i-this.ohlcv.close[t-1])/i>.05)return!1;for(let s=t-e;s<t-1;s++)if(this.ohlcv.high[s]>this.ohlcv.high[s+1]||this.ohlcv.low[s]>this.ohlcv.low[s+1])return!1;return!0}isBearishFlag(){const t=this.ohlcv.close.length,e=Math.floor(t/3),s=(Math.floor(e/2),this.ohlcv.close[t-2*e]);if((s-this.ohlcv.close[t-e])/s<.15)return!1;const i=this.ohlcv.close[t-e];if((this.ohlcv.close[t-1]-i)/i>.05)return!1;for(let s=t-e;s<t-1;s++)if(this.ohlcv.high[s]<this.ohlcv.high[s+1]||this.ohlcv.low[s]<this.ohlcv.low[s+1])return!1;return!0}isBullishPennant(){const t=this.ohlcv.close.length,e=Math.floor(t/3),s=Math.floor(e/2),i=this.ohlcv.close[t-2*e];if((this.ohlcv.close[t-e]-i)/i<.15)return!1;const o=this.ohlcv.close[t-e];if((o-this.ohlcv.close[t-1])/o>.05)return!1;for(let e=t-s;e<t-1;e++)if(this.ohlcv.high[e]<this.ohlcv.high[e+1]&&this.ohlcv.low[e]<this.ohlcv.low[e+1]||this.ohlcv.high[e]>this.ohlcv.high[e+1]&&this.ohlcv.low[e]>this.ohlcv.low[e+1])return!1;return!0}isBearishPennant(){const t=this.ohlcv.close.length,e=Math.floor(t/3),s=Math.floor(e/2),i=this.ohlcv.close[t-2*e];if((i-this.ohlcv.close[t-e])/i<.15)return!1;const o=this.ohlcv.close[t-e];if((this.ohlcv.close[t-1]-o)/o>.05)return!1;for(let e=t-s;e<t-1;e++)if(this.ohlcv.high[e]>this.ohlcv.high[e+1]&&this.ohlcv.low[e]>this.ohlcv.low[e+1]||this.ohlcv.high[e]<this.ohlcv.high[e+1]&&this.ohlcv.low[e]<this.ohlcv.low[e+1])return!1;return!0}isDoubleTop(){const t=this.ohlcv.close.length,e=Math.floor(t/2),s=Math.max(...this.ohlcv.close.slice(0,e)),i=Math.max(...this.ohlcv.close.slice(e));if(s<=0||i<=0)return!1;const o=Math.min(...this.ohlcv.close.slice(0,e)),h=Math.min(...this.ohlcv.close.slice(e));return!((s-o)/s<.1||(i-h)/i<.1)&&Math.abs(s-i)/s<.03}isDoubleBottom(){const t=this.ohlcv.close.length,e=Math.floor(t/2),s=Math.min(...this.ohlcv.close.slice(0,e)),i=Math.min(...this.ohlcv.close.slice(e));if(s<=0||i<=0)return!1;const o=Math.max(...this.ohlcv.close.slice(0,e)),h=Math.max(...this.ohlcv.close.slice(e));return!((o-s)/s<.1||(h-i)/i<.1)&&Math.abs(s-i)/s<.03}isTripleTop(){const t=this.ohlcv.close.length,e=Math.floor(t/3),s=Math.max(...this.ohlcv.close.slice(0,e)),i=Math.max(...this.ohlcv.close.slice(e,2*e)),o=Math.max(...this.ohlcv.close.slice(2*e));if(s<=0||i<=0||o<=0)return!1;const h=(s-Math.min(...this.ohlcv.close.slice(0,e)))/s,r=(i-Math.min(...this.ohlcv.close.slice(e,2*e)))/i,n=(o-Math.min(...this.ohlcv.close.slice(2*e)))/o;return!(h<.1||r<.1||n<.1)&&Math.abs(s-i)/s<.03&&Math.abs(s-o)/s<.03}isTripleBottom(){const t=this.ohlcv.close.length,e=Math.floor(t/3),s=Math.min(...this.ohlcv.close.slice(0,e)),i=Math.min(...this.ohlcv.close.slice(e,2*e)),o=Math.min(...this.ohlcv.close.slice(2*e));if(s<=0||i<=0||o<=0)return!1;const h=(Math.max(...this.ohlcv.close.slice(0,e))-s)/s,r=(Math.max(...this.ohlcv.close.slice(e,2*e))-i)/i,n=(Math.max(...this.ohlcv.close.slice(2*e))-o)/o;return!(h<.1||r<.1||n<.1)&&Math.abs(s-i)/s<.03&&Math.abs(s-o)/s<.03}isHeadAndShoulders(){const t=this.ohlcv.close.length,e=Math.floor(t/3),s=Math.max(...this.ohlcv.close.slice(0,e)),i=Math.max(...this.ohlcv.close.slice(e,2*e)),o=Math.max(...this.ohlcv.close.slice(2*e));if(s<=0||i<=0||o<=0)return!1;const h=Math.min(...this.ohlcv.close.slice(0,e)),r=Math.min(...this.ohlcv.close.slice(e,2*e)),n=Math.min(...this.ohlcv.close.slice(2*e)),l=(i-r)/i,c=(Math.max(h,n)-Math.min(h,n))/Math.min(h,n);return l>.15&&c<.03}isInverseHeadAndShoulders(){const t=this.ohlcv.close.length,e=Math.floor(t/3),s=Math.min(...this.ohlcv.close.slice(0,e)),i=Math.min(...this.ohlcv.close.slice(e,2*e)),o=Math.min(...this.ohlcv.close.slice(2*e));if(s<=0||i<=0||o<=0)return!1;const h=Math.max(...this.ohlcv.close.slice(0,e)),r=Math.max(...this.ohlcv.close.slice(e,2*e)),n=Math.max(...this.ohlcv.close.slice(2*e)),l=(r-i)/i,c=(Math.min(h,n)-Math.max(h,n))/Math.max(h,n);return l>.15&&c<.03}isRisingWedge(){const t=this.ohlcv.close.length,e=Math.floor(t/3),s=Math.max(...this.ohlcv.close.slice(0,e)),i=Math.max(...this.ohlcv.close.slice(e,2*e)),o=Math.max(...this.ohlcv.close.slice(2*e)),h=Math.min(...this.ohlcv.close.slice(0,e)),r=Math.min(...this.ohlcv.close.slice(e,2*e)),n=Math.min(...this.ohlcv.close.slice(2*e));return s<i&&i<o&&h<r&&r<n}isFallingWedge(){const t=this.ohlcv.close.length,e=Math.floor(t/3),s=Math.max(...this.ohlcv.close.slice(0,e)),i=Math.max(...this.ohlcv.close.slice(e,2*e)),o=Math.max(...this.ohlcv.close.slice(2*e)),h=Math.min(...this.ohlcv.close.slice(0,e)),r=Math.min(...this.ohlcv.close.slice(e,2*e)),n=Math.min(...this.ohlcv.close.slice(2*e));return s>i&&i>o&&h>r&&r>n}isBullishTriangle(){const t=this.ohlcv.close.length,e=Math.floor(t/2),s=Math.max(...this.ohlcv.high.slice(0,e)),i=Math.max(...this.ohlcv.high.slice(e)),o=Math.min(...this.ohlcv.low.slice(0,e)),h=Math.min(...this.ohlcv.low.slice(e));return s>i&&o<h}isBearishTriangle(){const t=this.ohlcv.close.length,e=Math.floor(t/2),s=Math.max(...this.ohlcv.high.slice(0,e)),i=Math.max(...this.ohlcv.high.slice(e));return Math.min(...this.ohlcv.low.slice(0,e))<Math.min(...this.ohlcv.low.slice(e))&&s>i}isBullishRectangle(){const t=this.ohlcv.close.length,e=Math.floor(t/3),s=Math.max(...this.ohlcv.high.slice(0,e)),i=Math.max(...this.ohlcv.high.slice(e,2*e)),o=Math.max(...this.ohlcv.high.slice(2*e)),h=Math.min(...this.ohlcv.low.slice(0,e)),r=Math.min(...this.ohlcv.low.slice(e,2*e)),n=Math.min(...this.ohlcv.low.slice(2*e)),l=Math.abs(s-i)/s<.03&&Math.abs(i-o)/i<.03,c=Math.abs(h-r)/h<.03&&Math.abs(r-n)/r<.03;return l&&c}isBearishRectangle(){const t=this.ohlcv.close.length,e=Math.floor(t/3),s=Math.max(...this.ohlcv.high.slice(0,e)),i=Math.max(...this.ohlcv.high.slice(e,2*e)),o=Math.max(...this.ohlcv.high.slice(2*e)),h=Math.min(...this.ohlcv.low.slice(0,e)),r=Math.min(...this.ohlcv.low.slice(e,2*e)),n=Math.min(...this.ohlcv.low.slice(2*e)),l=Math.abs(s-i)/s<.03&&Math.abs(i-o)/i<.03,c=Math.abs(h-r)/h<.03&&Math.abs(r-n)/r<.03;return l&&c}}class V{constructor(){this.ChartPatterns=t=>new A(t).init()}init(t){return this.ohlcv=t.reduce(((t,{open:e,high:s,low:i,close:o,volume:h,...r})=>{t.open.push(e),t.high.push(s),t.low.push(i),t.close.push(o),t.volume.push(h);for(const e of Object.keys(r))t[e]||(t[e]=[]),t[e].push(r[e]);return t}),{open:[],high:[],low:[],close:[],volume:[]}),this}getHeaders(){return Object.keys(this.ohlcv)}getData(){const{ohlcv:t}=this,e=Object.keys(t),s=e.length;return t.open.map(((i,o)=>{const h={};for(let i=0;i<s;i++){const s=e[i],r=t[s][o];h[s]=r instanceof g?r.toNumber():r}return h}))}getLastValues(){const t={};for(const[e,s]of Object.entries(this.ohlcv)){let i=s[s.length-1];t[e]=i instanceof g?i.toNumber():i}return t}addColumn(t,e){const s=this.ohlcv.open.length;if(e.length>s)throw new Error("Invalid column data: The length of the new column exceeds the length of the OHLCV data");e=[...new Array(s-e.length).fill(null),...e],this.ohlcv[t]=e}crossPairs(t){const e=this.ohlcv,s={},i=t=>{if(!e.hasOwnProperty(t)&&"string"==typeof t){const[e,...s]=t.split("_");this[e]&&s.length>0&&this[e](...s)}};for(const{fast:o,slow:h}of t)if(o&&h)if(i(o),i(h),"number"!=typeof h||s[h]||(s[h]=e.close.map((()=>h))),e[o]&&e[h]){const t=E(e[o],e[h]);this.addColumn(`${o}_x_${h}`,t)}else if(e[o]&&s[h]){const t=E(e[o],s[h]);this.addColumn(`${o}_x_${h}`,t)}else console.error(`Missing ohlcv properties for ${o} or ${h}`)}ema(t){return((t,e)=>{const{ohlcv:s}=t,i=s.close,o=y(i,e);t.addColumn(`ema_${e}`,o)})(this,t),this}sma(t){return((t,e)=>{const{ohlcv:s}=t,i=s.close,o=P(i,e);t.addColumn(`sma_${e}`,o)})(this,t),this}macd(t,e,s){return((t,e=12,s=26,i=9)=>{const{ohlcv:o}=t,h=((t,e=12,s=26,i=9)=>{const o=[],h=[],r=[],n=new R({indicator:x,shortInterval:e,longInterval:s,signalInterval:i}),l=t.length;for(let e=0;e<l;e++){let s={};n.update(t[e]);try{s=n.getResult()}catch(t){s={macd:null,signal:null,histogram:null}}o.push(s.macd),h.push(s.signal),r.push(s.histogram)}return{macd_diff:o,macd_dea:h,macd_histogram:r,macd_diff_x_macd_dea:E(o,h)}})(o.close,e,s,i);for(let e in h)t.addColumn(e,h[e])})(this,t,e,s),this}bollingerBands(t,e,s){return((t,e,s)=>{const{ohlcv:i}=t,o=((t,e=20,s=2)=>{const i=t.length,o={upper:[],middle:[],lower:[]},h=new b(e,s);for(let e=0;e<i;e++){let s={};h.update(t[e]);try{s=h.getResult()}catch(t){s={upper:null,middle:null,lower:null}}o.upper.push(s.upper),o.middle.push(s.middle),o.lower.push(s.lower)}const r=S(t,{upper:o.upper,lower:o.lower});return{...o,range:r}})(i.close,e,s);for(let e in o)t.addColumn(`bollinger_bands_${e}`,o[e])})(this,t,e),this}rsi(t,e,s){return((t,e,s,i)=>{const{ohlcv:o}=t;"number"==typeof e&&void 0===i&&(i=e);const h=((t,e=14,s="SMA",i=14)=>{if(t.length<e)return[];let o=[];e=parseInt(e),i=parseInt(i);const h=new B(e),r=t.length;for(let e=0;e<r;e++){let s=null;h.update(t[e]);try{s=h.getResult()}catch(t){s=null}o.push(s)}o=o.filter((t=>t));let n={[`rsi_${e}`]:o};if("string"==typeof s&&"number"==typeof i&&C.hasOwnProperty(`get${s}`)){const t=C[`get${s}`](o,i);n[`rsi_${s}_${i}`]=t,n[`rsi_${e}_x_rsi_${s}_${i}`]=E(o,t)}return n})(o.close,e,s,i);for(let e in h)t.addColumn(`${e}`.toLowerCase(),h[e])})(this,t,e,s),this}candles(){return(t=>{const{ohlcv:e}=t,s=(t=>{const{open:e,high:s,low:i,close:o}=t,h=e.length;if(![e,s,i,o].every((t=>Array.isArray(t)&&t.length>1&&t.length===h)))return{pattern:Array(h).fill("Neutral"),name:Array(h).fill("No Pattern"),score:Array(h).fill(0)};const r=(t,e,s=1e-4)=>Math.abs(t-e)<s,n={bullish:[{name:"Marubozu",condition:(t,e)=>r(e.open,e.low)&&r(e.close,e.high),score:2},{name:"Engulfing",condition:(t,e)=>e.open<t.close&&e.close>t.open&&e.low<t.low&&e.high>t.high,score:2},{name:"Kicker",condition:(t,e)=>e.open<t.open&&e.close>e.open&&t.close<t.open,score:2},{name:"Morning Star",condition:(t,e)=>e.close>t.close&&e.open<t.open&&t.close<t.open,score:2},{name:"Piercing Line",condition:(t,e)=>e.close>t.close&&e.open<t.open&&e.close>(t.open+t.close)/2,score:1},{name:"Belt Hold",condition:(t,e)=>e.open>t.open&&r(e.close,e.high)&&r(t.close,t.low),score:1},{name:"Harami",condition:(t,e)=>e.open>t.close&&e.close<t.open&&e.open<t.open&&e.close>t.close,score:1},{name:"Doji",condition:(t,e)=>r(e.close,e.open)&&e.high-e.low>Math.abs(e.close-e.open),score:0}],bearish:[{name:"Marubozu",condition:(t,e)=>r(e.open,e.high)&&r(e.close,e.low),score:-2},{name:"Engulfing",condition:(t,e)=>e.open>t.close&&e.close<t.open&&e.high>t.high&&e.low<t.low,score:-2},{name:"Kicker",condition:(t,e)=>e.open>t.open&&e.close<e.open&&t.close>t.open,score:-2},{name:"Evening Star",condition:(t,e)=>e.close<t.close&&e.open>t.open&&t.close<t.open,score:-2},{name:"Dark Cloud Cover",condition:(t,e)=>e.close<t.close&&e.open>t.open&&e.close<(t.open+t.close)/2,score:-1},{name:"Belt Hold",condition:(t,e)=>e.open<t.open&&r(e.close,e.low)&&r(t.close,t.high),score:-1},{name:"Harami",condition:(t,e)=>e.open<t.close&&e.close>t.open&&e.open>t.open&&e.close<t.close,score:-1},{name:"Doji",condition:(t,e)=>r(e.close,e.open)&&e.high-e.low>Math.abs(e.close-e.open),score:0}]},l=(t,e,s)=>{for(const{name:i,condition:o,score:h}of s)if(o(t,e))return{name:i,score:h};return null},c=["Neutral"],a=["No Pattern"],u=[0];for(let t=1;t<h;t++){const h={open:e[t-1],high:s[t-1],low:i[t-1],close:o[t-1]},r={open:e[t],high:s[t],low:i[t],close:o[t]},p=l(h,r,n.bullish)||l(h,r,n.bearish);p?(c.push(p.score>0?"Bullish":"Bearish"),a.push(p.name),u.push(p.score)):(c.push("Neutral"),a.push("No Pattern"),u.push(0))}return{pattern:c,name:a,score:u}})(e);for(let e in s)t.addColumn(`candle_${e}`.toLowerCase(),s[e])})(this),this}volumeProfile(t,e,s){return((t,e,s=1,i)=>{let{ohlcv:o}=t;const h=((t,e,s)=>{const i=new Date(t[s][t[s].length-1]),o=new Date(i);o.setDate(o.getDate()-e),o.setHours(0,0,0,0);const h={open:[],high:[],low:[],close:[],volume:[],[s]:[]};for(let e=0;e<t[s].length;e++)new Date(t[s][e])>=o&&(h.open.push(t.open[e]),h.high.push(t.high[e]),h.low.push(t.low[e]),h.close.push(t.close[e]),h.volume.push(t.volume[e]),h[s].push(t[s][e]));return h})(o,s,i),r=((t,e=5)=>{const{open:s,high:i,low:o,close:h,volume:r}=t,n=Math.min(...o),l=(Math.max(...i)-n)/e,c={upVolume:0,downVolume:0,grossVolume:0},a=Array.from({length:e},((t,e)=>({price:n+l*e,upVolume:0,downVolume:0,grossVolume:0}))),u=1/l;for(let t=0;t<h.length;t++){const l=h[t],c=s[t],p=i[t],g=o[t],v=r[t],f=l>=c?v:0,d=l<c?v:0,m=Math.max(0,Math.floor((g-n)*u)),w=Math.min(e,Math.ceil((p-n)*u));for(let t=m;t<w;t++)a[t].upVolume+=f,a[t].downVolume+=d,a[t].grossVolume+=f+d}for(const{upVolume:t,downVolume:e,grossVolume:s}of a)c.upVolume+=t,c.downVolume+=e,c.grossVolume+=s;return{bins:a,nodes:D(a)}})(h,e),n=r.nodes.high.price,l=r.nodes.low.price;t.addColumn("volume_profile_high",[n]),t.addColumn("volume_profile_low",[l])})(this,t,e,s),this}}})(),OHLCV_INDICATORS=e})();
|
package/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { volumeProfile } from './src/studies/volumeProfile.js'
|
|
|
7
7
|
import {findCrosses} from './src/utilities.js'
|
|
8
8
|
import { candles } from './src/studies/candles.js'
|
|
9
9
|
import ChartPatterns from './src/studies/chart.js'
|
|
10
|
+
import {Big} from 'trading-signals';
|
|
10
11
|
|
|
11
12
|
export default class OHLCV_INDICATORS {
|
|
12
13
|
constructor() {
|
|
@@ -15,7 +16,6 @@ export default class OHLCV_INDICATORS {
|
|
|
15
16
|
|
|
16
17
|
init(ohlcv) {
|
|
17
18
|
|
|
18
|
-
this.rawOhlcv = ohlcv
|
|
19
19
|
this.ohlcv = ohlcv.reduce((acc, { open, high, low, close, volume, ...rest }) => {
|
|
20
20
|
acc.open.push(open)
|
|
21
21
|
acc.high.push(high)
|
|
@@ -49,7 +49,10 @@ export default class OHLCV_INDICATORS {
|
|
|
49
49
|
for(let x = 0; x < keysLength; x++)
|
|
50
50
|
{
|
|
51
51
|
const header = keys[x]
|
|
52
|
-
|
|
52
|
+
const value = ohlcv[header][i]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
row[header] = (value instanceof Big) ? value.toNumber() : value
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
return row
|
|
@@ -59,8 +62,8 @@ export default class OHLCV_INDICATORS {
|
|
|
59
62
|
const output = {}
|
|
60
63
|
|
|
61
64
|
for (const [k, arr] of Object.entries(this.ohlcv)) {
|
|
62
|
-
let value = arr[arr.length - 1]
|
|
63
|
-
output[k] = value;
|
|
65
|
+
let value = arr[arr.length - 1]
|
|
66
|
+
output[k] = (value instanceof Big) ? value.toNumber(): value;
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
return output
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ohlcv-indicators",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.7",
|
|
4
4
|
"description": "A JavaScript library featuring optimized trading indicators for OHLCV arrays [{open, high, low, close, value}]. This library is optimized for backtesting and trading bot development.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"author": "https://jaimelias.com/",
|
|
12
12
|
"license": "ISC",
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"
|
|
14
|
+
"trading-signals": "^5.0.4"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"dotenv": "^16.4.5",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
import {BollingerBands, Big} from 'trading-signals';
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
export const bollingerBands = (main, size, times) => {
|
|
@@ -16,46 +17,53 @@ export const bollingerBands = (main, size, times) => {
|
|
|
16
17
|
|
|
17
18
|
export const getBollingerBands = (data, size = 20, times = 2) => {
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
const output = {
|
|
20
|
+
const dataLength = data.length
|
|
21
|
+
const output = {upper: [], middle: [], lower: []}
|
|
21
22
|
const instance = new BollingerBands(size, times)
|
|
22
23
|
|
|
23
|
-
data.forEach(c => {
|
|
24
24
|
|
|
25
|
+
for(let x = 0; x < dataLength; x++) {
|
|
26
|
+
let obj = {}
|
|
27
|
+
instance.update(data[x])
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if(typeof bb === 'object')
|
|
29
|
+
try
|
|
29
30
|
{
|
|
30
|
-
|
|
31
|
-
output.lower.push(lower)
|
|
32
|
-
output.middle.push(middle)
|
|
33
|
-
output.upper.push(upper)
|
|
34
|
-
|
|
31
|
+
obj = instance.getResult()
|
|
35
32
|
}
|
|
36
|
-
|
|
33
|
+
catch(err)
|
|
37
34
|
{
|
|
38
|
-
|
|
39
|
-
output.middle.push(null)
|
|
40
|
-
output.upper.push(null)
|
|
35
|
+
obj = {upper: null, middle: null, lower: null}
|
|
41
36
|
}
|
|
42
|
-
})
|
|
43
37
|
|
|
44
|
-
|
|
38
|
+
output.upper.push(obj.upper)
|
|
39
|
+
output.middle.push(obj.middle)
|
|
40
|
+
output.lower.push(obj.lower)
|
|
45
41
|
|
|
42
|
+
}
|
|
46
43
|
|
|
47
|
-
|
|
44
|
+
const range = bollingerBandsRange(data, {upper: output.upper, lower: output.lower})
|
|
48
45
|
|
|
46
|
+
return {...output, range}
|
|
49
47
|
}
|
|
50
48
|
|
|
51
49
|
|
|
52
50
|
|
|
53
51
|
const bollingerBandsRange = (data, bollingerBands) => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
const { upper, lower } = bollingerBands;
|
|
53
|
+
const output = new Array(data.length);
|
|
54
|
+
|
|
55
|
+
for (let i = 0; i < data.length; i++) {
|
|
56
|
+
if (upper[i] != null && lower[i] != null && data[i] != null) {
|
|
57
|
+
const upperBig = new Big(upper[i]);
|
|
58
|
+
const lowerBig = new Big(lower[i]);
|
|
59
|
+
const dataBig = new Big(data[i]);
|
|
60
|
+
|
|
61
|
+
const range = upperBig.minus(lowerBig);
|
|
62
|
+
output[i] = dataBig.minus(lowerBig).div(range).times(100).toNumber();
|
|
63
|
+
} else {
|
|
64
|
+
output[i] = null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
59
67
|
|
|
60
68
|
return output;
|
|
61
|
-
}
|
|
69
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
2
|
+
import {EMA} from 'trading-signals';
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
export const ema = (main, size) => {
|
|
@@ -11,15 +11,27 @@ export const ema = (main, size) => {
|
|
|
11
11
|
|
|
12
12
|
export const getEMA = (data, size) => {
|
|
13
13
|
|
|
14
|
-
|
|
15
14
|
const output = []
|
|
16
15
|
const instance = new EMA(size)
|
|
16
|
+
const dataLength = data.length
|
|
17
|
+
|
|
18
|
+
for(let x = 0; x < dataLength; x++)
|
|
19
|
+
{
|
|
20
|
+
let value = null
|
|
21
|
+
instance.update(data[x])
|
|
22
|
+
|
|
23
|
+
try
|
|
24
|
+
{
|
|
25
|
+
value = instance.getResult()
|
|
26
|
+
}
|
|
27
|
+
catch(err)
|
|
28
|
+
{
|
|
29
|
+
value = null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
output.push(value)
|
|
33
|
+
}
|
|
17
34
|
|
|
18
|
-
data.forEach(c => {
|
|
19
|
-
|
|
20
|
-
output.push(instance.nextValue(c))
|
|
21
|
-
|
|
22
|
-
})
|
|
23
35
|
|
|
24
36
|
return output
|
|
25
37
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { findCrosses } from "../utilities.js";
|
|
2
|
-
import {
|
|
2
|
+
import {EMA, MACD} from 'trading-signals';
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
export const macd = (main, fastLine = 12, slowLine = 26, signalLine = 9) => {
|
|
@@ -15,23 +15,44 @@ export const macd = (main, fastLine = 12, slowLine = 26, signalLine = 9) => {
|
|
|
15
15
|
|
|
16
16
|
export const getMACD = (data, fastLine = 12, slowLine = 26, signalLine = 9) => {
|
|
17
17
|
|
|
18
|
-
const
|
|
19
|
-
const
|
|
18
|
+
const diff = []
|
|
19
|
+
const dea = []
|
|
20
|
+
const histogram = []
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
const instance = new MACD({
|
|
23
|
+
indicator: EMA,
|
|
24
|
+
shortInterval: fastLine,
|
|
25
|
+
longInterval: slowLine,
|
|
26
|
+
signalInterval: signalLine
|
|
27
|
+
})
|
|
23
28
|
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
const dataLength = data.length
|
|
30
|
+
|
|
31
|
+
for(let x = 0; x < dataLength; x++)
|
|
32
|
+
{
|
|
33
|
+
let obj = {}
|
|
34
|
+
instance.update(data[x])
|
|
35
|
+
|
|
36
|
+
try
|
|
37
|
+
{
|
|
38
|
+
obj = instance.getResult()
|
|
39
|
+
}
|
|
40
|
+
catch(err)
|
|
41
|
+
{
|
|
42
|
+
obj = {macd: null, signal: null, histogram: null}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
diff.push(obj.macd)
|
|
46
|
+
dea.push(obj.signal)
|
|
47
|
+
histogram.push(obj.histogram)
|
|
48
|
+
}
|
|
26
49
|
|
|
27
|
-
// Calculate the MACD line (histogram)
|
|
28
|
-
const histogram = diff.map((d, i) => d - dea[i])
|
|
29
50
|
const x = findCrosses(diff, dea)
|
|
30
51
|
|
|
31
52
|
return {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
53
|
+
macd_diff: diff,
|
|
54
|
+
macd_dea: dea,
|
|
55
|
+
macd_histogram: histogram,
|
|
56
|
+
macd_diff_x_macd_dea: x
|
|
36
57
|
}
|
|
37
58
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { getSMA } from './sma.js'
|
|
2
|
+
|
|
3
|
+
export const RelativeVolume = (main, size) => {
|
|
4
|
+
const {ohlcv} = main
|
|
5
|
+
const data = ohlcv['volume']
|
|
6
|
+
const relVolume = getRelativeVolume(main.BigNumber, data, size)
|
|
7
|
+
main.addColumn(`relative_volume_${size}`, relVolume)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const getRelativeVolume = (BigNumber, data, size = 10) => {
|
|
11
|
+
const sma = getSMA(BigNumber, data, size)
|
|
12
|
+
|
|
13
|
+
return data.map((v, i) => {
|
|
14
|
+
const prevSma = sma[i - 1]
|
|
15
|
+
if (i === 0 || !prevSma || prevSma.isZero()) return null
|
|
16
|
+
return v.dividedBy(prevSma)
|
|
17
|
+
}).filter(v => !Number.isNaN(v))
|
|
18
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import {
|
|
2
|
+
import {SMA, Big} from 'trading-signals';
|
|
3
3
|
|
|
4
4
|
export const sma = (main, size) => {
|
|
5
5
|
const {ohlcv} = main
|
|
@@ -10,16 +10,28 @@ export const sma = (main, size) => {
|
|
|
10
10
|
|
|
11
11
|
export const getSMA = (data, size) => {
|
|
12
12
|
|
|
13
|
-
|
|
14
13
|
const output = []
|
|
15
14
|
const instance = new SMA(size)
|
|
15
|
+
const dataLength = data.length
|
|
16
16
|
|
|
17
|
-
data.forEach(c => {
|
|
18
|
-
|
|
19
|
-
output.push(instance.nextValue(c))
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
|
|
19
|
+
for(let x = 0; x < dataLength; x++)
|
|
20
|
+
{
|
|
21
|
+
let value = null
|
|
22
|
+
instance.update(data[x])
|
|
23
|
+
|
|
24
|
+
try
|
|
25
|
+
{
|
|
26
|
+
value = instance.getResult()
|
|
27
|
+
}
|
|
28
|
+
catch(err)
|
|
29
|
+
{
|
|
30
|
+
value = null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
output.push(value)
|
|
34
|
+
}
|
|
22
35
|
|
|
23
36
|
return output
|
|
24
|
-
|
|
25
37
|
}
|
package/src/oscillators/rsi.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getSMA } from "../moving-averages/sma.js";
|
|
2
2
|
import { getEMA } from "../moving-averages/ema.js";
|
|
3
3
|
import { findCrosses } from "../utilities.js";
|
|
4
|
-
import {
|
|
4
|
+
import {RSI} from 'trading-signals';
|
|
5
5
|
|
|
6
6
|
const ma = {getSMA, getEMA}
|
|
7
7
|
|
|
@@ -34,12 +34,24 @@ export const getRSI = (data, period = 14, movingAverage = 'SMA', movingAveragePe
|
|
|
34
34
|
period = parseInt(period)
|
|
35
35
|
movingAveragePeriod = parseInt(movingAveragePeriod)
|
|
36
36
|
const instance = new RSI(period)
|
|
37
|
+
const dataLength = data.length
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
for(let x = 0; x < dataLength; x++)
|
|
40
|
+
{
|
|
41
|
+
let value = null
|
|
42
|
+
instance.update(data[x])
|
|
43
|
+
|
|
44
|
+
try
|
|
45
|
+
{
|
|
46
|
+
value = instance.getResult()
|
|
47
|
+
}
|
|
48
|
+
catch(err)
|
|
49
|
+
{
|
|
50
|
+
value = null
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
rsi.push(value)
|
|
54
|
+
}
|
|
43
55
|
|
|
44
56
|
rsi = rsi.filter(v => v)
|
|
45
57
|
|
package/src/studies/chart.js
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
export default class ChartPatterns {
|
|
2
|
+
|
|
2
3
|
constructor(ohlcv, period = 100) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
for(let
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
{
|
|
10
|
-
this[key] = arr.splice(-period)
|
|
4
|
+
const validProps = ['open', 'high', 'low', 'close'];
|
|
5
|
+
this.ohlcv = {};
|
|
6
|
+
|
|
7
|
+
for (let key of Object.keys(ohlcv)) {
|
|
8
|
+
if (validProps.includes(key)) {
|
|
9
|
+
this.ohlcv[key] = ohlcv[key].slice(-period);
|
|
11
10
|
}
|
|
12
|
-
|
|
13
11
|
}
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
init() {
|
|
17
|
-
const length = this.close.length;
|
|
15
|
+
const length = this.ohlcv.close.length;
|
|
18
16
|
if (length < 50) {
|
|
19
17
|
console.log('PatternRecognizer requires at least 50 datapoints')
|
|
20
18
|
return { chart_pattern: 'Neutral', chart_score: 0 };
|
|
@@ -55,13 +53,13 @@ export default class ChartPatterns {
|
|
|
55
53
|
isBullishFlag() {
|
|
56
54
|
|
|
57
55
|
// A Bullish Flag is characterized by a sharp price rise followed by a period of consolidation that has a downward slant.
|
|
58
|
-
const length = this.close.length;
|
|
56
|
+
const length = this.ohlcv.close.length;
|
|
59
57
|
const flagpoleLength = Math.floor(length / 3); // Roughly the first third of the data
|
|
60
58
|
const consolidationLength = Math.floor(flagpoleLength / 2); // Roughly half the length of the flagpole
|
|
61
59
|
|
|
62
60
|
// Sharp price rise (flagpole)
|
|
63
|
-
const flagpoleStart = this.close[length - flagpoleLength * 2];
|
|
64
|
-
const flagpoleEnd = this.close[length - flagpoleLength];
|
|
61
|
+
const flagpoleStart = this.ohlcv.close[length - flagpoleLength * 2];
|
|
62
|
+
const flagpoleEnd = this.ohlcv.close[length - flagpoleLength];
|
|
65
63
|
const flagpoleGain = (flagpoleEnd - flagpoleStart) / flagpoleStart;
|
|
66
64
|
|
|
67
65
|
if (flagpoleGain < 0.15) { // A significant gain, at least 15%
|
|
@@ -69,8 +67,8 @@ export default class ChartPatterns {
|
|
|
69
67
|
}
|
|
70
68
|
|
|
71
69
|
// Consolidation period
|
|
72
|
-
const consolidationStart = this.close[length - flagpoleLength];
|
|
73
|
-
const consolidationEnd = this.close[length - 1];
|
|
70
|
+
const consolidationStart = this.ohlcv.close[length - flagpoleLength];
|
|
71
|
+
const consolidationEnd = this.ohlcv.close[length - 1];
|
|
74
72
|
const consolidationDrop = (consolidationStart - consolidationEnd) / consolidationStart;
|
|
75
73
|
|
|
76
74
|
if (consolidationDrop > 0.05) { // A downward slant, less than 5%
|
|
@@ -79,7 +77,7 @@ export default class ChartPatterns {
|
|
|
79
77
|
|
|
80
78
|
// Ensure that the consolidation period has lower highs and lower lows
|
|
81
79
|
for (let i = length - flagpoleLength; i < length - 1; i++) {
|
|
82
|
-
if (this.high[i] > this.high[i + 1] || this.low[i] > this.low[i + 1]) {
|
|
80
|
+
if (this.ohlcv.high[i] > this.ohlcv.high[i + 1] || this.ohlcv.low[i] > this.ohlcv.low[i + 1]) {
|
|
83
81
|
return false;
|
|
84
82
|
}
|
|
85
83
|
}
|
|
@@ -91,13 +89,13 @@ export default class ChartPatterns {
|
|
|
91
89
|
// https://www.tradingview.com/support/solutions/43000653209-chart-pattern-bullish-flag/
|
|
92
90
|
isBearishFlag() {
|
|
93
91
|
// A Bearish Flag is characterized by a sharp price decline followed by a period of consolidation that has an upward slant.
|
|
94
|
-
const length = this.close.length;
|
|
92
|
+
const length = this.ohlcv.close.length;
|
|
95
93
|
const flagpoleLength = Math.floor(length / 3); // Roughly the first third of the data
|
|
96
94
|
const consolidationLength = Math.floor(flagpoleLength / 2); // Roughly half the length of the flagpole
|
|
97
95
|
|
|
98
96
|
// Sharp price decline (flagpole)
|
|
99
|
-
const flagpoleStart = this.close[length - flagpoleLength * 2];
|
|
100
|
-
const flagpoleEnd = this.close[length - flagpoleLength];
|
|
97
|
+
const flagpoleStart = this.ohlcv.close[length - flagpoleLength * 2];
|
|
98
|
+
const flagpoleEnd = this.ohlcv.close[length - flagpoleLength];
|
|
101
99
|
const flagpoleDrop = (flagpoleStart - flagpoleEnd) / flagpoleStart;
|
|
102
100
|
|
|
103
101
|
if (flagpoleDrop < 0.15) { // A significant drop, at least 15%
|
|
@@ -105,8 +103,8 @@ export default class ChartPatterns {
|
|
|
105
103
|
}
|
|
106
104
|
|
|
107
105
|
// Consolidation period
|
|
108
|
-
const consolidationStart = this.close[length - flagpoleLength];
|
|
109
|
-
const consolidationEnd = this.close[length - 1];
|
|
106
|
+
const consolidationStart = this.ohlcv.close[length - flagpoleLength];
|
|
107
|
+
const consolidationEnd = this.ohlcv.close[length - 1];
|
|
110
108
|
const consolidationGain = (consolidationEnd - consolidationStart) / consolidationStart;
|
|
111
109
|
|
|
112
110
|
if (consolidationGain > 0.05) { // An upward slant, less than 5%
|
|
@@ -115,7 +113,7 @@ export default class ChartPatterns {
|
|
|
115
113
|
|
|
116
114
|
// Ensure that the consolidation period has higher lows and higher highs
|
|
117
115
|
for (let i = length - flagpoleLength; i < length - 1; i++) {
|
|
118
|
-
if (this.high[i] < this.high[i + 1] || this.low[i] < this.low[i + 1]) {
|
|
116
|
+
if (this.ohlcv.high[i] < this.ohlcv.high[i + 1] || this.ohlcv.low[i] < this.ohlcv.low[i + 1]) {
|
|
119
117
|
return false;
|
|
120
118
|
}
|
|
121
119
|
}
|
|
@@ -127,13 +125,13 @@ export default class ChartPatterns {
|
|
|
127
125
|
// https://www.tradingview.com/support/solutions/43000653215-chart-pattern-bullish-pennant/
|
|
128
126
|
isBullishPennant() {
|
|
129
127
|
// A Bullish Pennant is characterized by a sharp price rise followed by a small symmetrical triangle consolidation.
|
|
130
|
-
const length = this.close.length;
|
|
128
|
+
const length = this.ohlcv.close.length;
|
|
131
129
|
const flagpoleLength = Math.floor(length / 3); // Roughly the first third of the data
|
|
132
130
|
const pennantLength = Math.floor(flagpoleLength / 2); // Roughly half the length of the flagpole
|
|
133
131
|
|
|
134
132
|
// Sharp price rise (flagpole)
|
|
135
|
-
const flagpoleStart = this.close[length - flagpoleLength * 2];
|
|
136
|
-
const flagpoleEnd = this.close[length - flagpoleLength];
|
|
133
|
+
const flagpoleStart = this.ohlcv.close[length - flagpoleLength * 2];
|
|
134
|
+
const flagpoleEnd = this.ohlcv.close[length - flagpoleLength];
|
|
137
135
|
const flagpoleGain = (flagpoleEnd - flagpoleStart) / flagpoleStart;
|
|
138
136
|
|
|
139
137
|
if (flagpoleGain < 0.15) { // A significant gain, at least 15%
|
|
@@ -141,8 +139,8 @@ export default class ChartPatterns {
|
|
|
141
139
|
}
|
|
142
140
|
|
|
143
141
|
// Small symmetrical triangle consolidation
|
|
144
|
-
const pennantStart = this.close[length - flagpoleLength];
|
|
145
|
-
const pennantEnd = this.close[length - 1];
|
|
142
|
+
const pennantStart = this.ohlcv.close[length - flagpoleLength];
|
|
143
|
+
const pennantEnd = this.ohlcv.close[length - 1];
|
|
146
144
|
const pennantDrop = (pennantStart - pennantEnd) / pennantStart;
|
|
147
145
|
|
|
148
146
|
if (pennantDrop > 0.05) { // A downward slant, less than 5%
|
|
@@ -151,8 +149,8 @@ export default class ChartPatterns {
|
|
|
151
149
|
|
|
152
150
|
// Ensure the consolidation period forms a small symmetrical triangle
|
|
153
151
|
for (let i = length - pennantLength; i < length - 1; i++) {
|
|
154
|
-
if ((this.high[i] < this.high[i + 1] && this.low[i] < this.low[i + 1]) ||
|
|
155
|
-
(this.high[i] > this.high[i + 1] && this.low[i] > this.low[i + 1])) {
|
|
152
|
+
if ((this.ohlcv.high[i] < this.ohlcv.high[i + 1] && this.ohlcv.low[i] < this.ohlcv.low[i + 1]) ||
|
|
153
|
+
(this.ohlcv.high[i] > this.ohlcv.high[i + 1] && this.ohlcv.low[i] > this.ohlcv.low[i + 1])) {
|
|
156
154
|
return false;
|
|
157
155
|
}
|
|
158
156
|
}
|
|
@@ -163,13 +161,13 @@ export default class ChartPatterns {
|
|
|
163
161
|
// Implementation of Bearish Pennant
|
|
164
162
|
// https://www.tradingview.com/support/solutions/43000697937-chart-pattern-bearish-pennant/
|
|
165
163
|
isBearishPennant() {
|
|
166
|
-
const length = this.close.length;
|
|
164
|
+
const length = this.ohlcv.close.length;
|
|
167
165
|
const flagpoleLength = Math.floor(length / 3); // Roughly the first third of the data
|
|
168
166
|
const pennantLength = Math.floor(flagpoleLength / 2); // Roughly half the length of the flagpole
|
|
169
167
|
|
|
170
168
|
// Sharp price decline (flagpole)
|
|
171
|
-
const flagpoleStart = this.close[length - flagpoleLength * 2];
|
|
172
|
-
const flagpoleEnd = this.close[length - flagpoleLength];
|
|
169
|
+
const flagpoleStart = this.ohlcv.close[length - flagpoleLength * 2];
|
|
170
|
+
const flagpoleEnd = this.ohlcv.close[length - flagpoleLength];
|
|
173
171
|
const flagpoleDrop = (flagpoleStart - flagpoleEnd) / flagpoleStart;
|
|
174
172
|
|
|
175
173
|
if (flagpoleDrop < 0.15) { // A significant drop, at least 15%
|
|
@@ -177,8 +175,8 @@ export default class ChartPatterns {
|
|
|
177
175
|
}
|
|
178
176
|
|
|
179
177
|
// Small symmetrical triangle consolidation
|
|
180
|
-
const pennantStart = this.close[length - flagpoleLength];
|
|
181
|
-
const pennantEnd = this.close[length - 1];
|
|
178
|
+
const pennantStart = this.ohlcv.close[length - flagpoleLength];
|
|
179
|
+
const pennantEnd = this.ohlcv.close[length - 1];
|
|
182
180
|
const pennantGain = (pennantEnd - pennantStart) / pennantStart;
|
|
183
181
|
|
|
184
182
|
if (pennantGain > 0.05) { // An upward slant, less than 5%
|
|
@@ -187,8 +185,8 @@ export default class ChartPatterns {
|
|
|
187
185
|
|
|
188
186
|
// Ensure the consolidation period forms a small symmetrical triangle
|
|
189
187
|
for (let i = length - pennantLength; i < length - 1; i++) {
|
|
190
|
-
if ((this.high[i] > this.high[i + 1] && this.low[i] > this.low[i + 1]) ||
|
|
191
|
-
(this.high[i] < this.high[i + 1] && this.low[i] < this.low[i + 1])) {
|
|
188
|
+
if ((this.ohlcv.high[i] > this.ohlcv.high[i + 1] && this.ohlcv.low[i] > this.ohlcv.low[i + 1]) ||
|
|
189
|
+
(this.ohlcv.high[i] < this.ohlcv.high[i + 1] && this.ohlcv.low[i] < this.ohlcv.low[i + 1])) {
|
|
192
190
|
return false;
|
|
193
191
|
}
|
|
194
192
|
}
|
|
@@ -199,18 +197,18 @@ export default class ChartPatterns {
|
|
|
199
197
|
// Implementation of Double Top
|
|
200
198
|
// https://www.tradingview.com/support/solutions/43000653211-chart-pattern-double-top/
|
|
201
199
|
isDoubleTop() {
|
|
202
|
-
const length = this.close.length;
|
|
200
|
+
const length = this.ohlcv.close.length;
|
|
203
201
|
const midpoint = Math.floor(length / 2);
|
|
204
202
|
|
|
205
|
-
const firstPeak = Math.max(...this.close.slice(0, midpoint));
|
|
206
|
-
const secondPeak = Math.max(...this.close.slice(midpoint));
|
|
203
|
+
const firstPeak = Math.max(...this.ohlcv.close.slice(0, midpoint));
|
|
204
|
+
const secondPeak = Math.max(...this.ohlcv.close.slice(midpoint));
|
|
207
205
|
|
|
208
206
|
if (firstPeak <= 0 || secondPeak <= 0) {
|
|
209
207
|
return false;
|
|
210
208
|
}
|
|
211
209
|
|
|
212
|
-
const firstValley = Math.min(...this.close.slice(0, midpoint));
|
|
213
|
-
const secondValley = Math.min(...this.close.slice(midpoint));
|
|
210
|
+
const firstValley = Math.min(...this.ohlcv.close.slice(0, midpoint));
|
|
211
|
+
const secondValley = Math.min(...this.ohlcv.close.slice(midpoint));
|
|
214
212
|
|
|
215
213
|
const dropFromFirstPeak = (firstPeak - firstValley) / firstPeak;
|
|
216
214
|
const dropFromSecondPeak = (secondPeak - secondValley) / secondPeak;
|
|
@@ -225,18 +223,18 @@ export default class ChartPatterns {
|
|
|
225
223
|
// Implementation of Double Bottom
|
|
226
224
|
// https://www.tradingview.com/support/solutions/43000690659-chart-pattern-double-bottom/
|
|
227
225
|
isDoubleBottom() {
|
|
228
|
-
const length = this.close.length;
|
|
226
|
+
const length = this.ohlcv.close.length;
|
|
229
227
|
const midpoint = Math.floor(length / 2);
|
|
230
228
|
|
|
231
|
-
const firstValley = Math.min(...this.close.slice(0, midpoint));
|
|
232
|
-
const secondValley = Math.min(...this.close.slice(midpoint));
|
|
229
|
+
const firstValley = Math.min(...this.ohlcv.close.slice(0, midpoint));
|
|
230
|
+
const secondValley = Math.min(...this.ohlcv.close.slice(midpoint));
|
|
233
231
|
|
|
234
232
|
if (firstValley <= 0 || secondValley <= 0) {
|
|
235
233
|
return false;
|
|
236
234
|
}
|
|
237
235
|
|
|
238
|
-
const firstPeak = Math.max(...this.close.slice(0, midpoint));
|
|
239
|
-
const secondPeak = Math.max(...this.close.slice(midpoint));
|
|
236
|
+
const firstPeak = Math.max(...this.ohlcv.close.slice(0, midpoint));
|
|
237
|
+
const secondPeak = Math.max(...this.ohlcv.close.slice(midpoint));
|
|
240
238
|
|
|
241
239
|
const riseFromFirstValley = (firstPeak - firstValley) / firstValley;
|
|
242
240
|
const riseFromSecondValley = (secondPeak - secondValley) / secondValley;
|
|
@@ -251,20 +249,20 @@ export default class ChartPatterns {
|
|
|
251
249
|
// Implementation of Triple Top
|
|
252
250
|
// https://www.tradingview.com/support/solutions/43000653218-chart-pattern-triple-top/
|
|
253
251
|
isTripleTop() {
|
|
254
|
-
const length = this.close.length;
|
|
252
|
+
const length = this.ohlcv.close.length;
|
|
255
253
|
const third = Math.floor(length / 3);
|
|
256
254
|
|
|
257
|
-
const firstPeak = Math.max(...this.close.slice(0, third));
|
|
258
|
-
const secondPeak = Math.max(...this.close.slice(third, third * 2));
|
|
259
|
-
const thirdPeak = Math.max(...this.close.slice(third * 2));
|
|
255
|
+
const firstPeak = Math.max(...this.ohlcv.close.slice(0, third));
|
|
256
|
+
const secondPeak = Math.max(...this.ohlcv.close.slice(third, third * 2));
|
|
257
|
+
const thirdPeak = Math.max(...this.ohlcv.close.slice(third * 2));
|
|
260
258
|
|
|
261
259
|
if (firstPeak <= 0 || secondPeak <= 0 || thirdPeak <= 0) {
|
|
262
260
|
return false;
|
|
263
261
|
}
|
|
264
262
|
|
|
265
|
-
const dropFromFirstPeak = (firstPeak - Math.min(...this.close.slice(0, third))) / firstPeak;
|
|
266
|
-
const dropFromSecondPeak = (secondPeak - Math.min(...this.close.slice(third, third * 2))) / secondPeak;
|
|
267
|
-
const dropFromThirdPeak = (thirdPeak - Math.min(...this.close.slice(third * 2))) / thirdPeak;
|
|
263
|
+
const dropFromFirstPeak = (firstPeak - Math.min(...this.ohlcv.close.slice(0, third))) / firstPeak;
|
|
264
|
+
const dropFromSecondPeak = (secondPeak - Math.min(...this.ohlcv.close.slice(third, third * 2))) / secondPeak;
|
|
265
|
+
const dropFromThirdPeak = (thirdPeak - Math.min(...this.ohlcv.close.slice(third * 2))) / thirdPeak;
|
|
268
266
|
|
|
269
267
|
if (dropFromFirstPeak < 0.1 || dropFromSecondPeak < 0.1 || dropFromThirdPeak < 0.1) {
|
|
270
268
|
return false;
|
|
@@ -276,20 +274,20 @@ export default class ChartPatterns {
|
|
|
276
274
|
// Implementation of Triple Bottom
|
|
277
275
|
// https://www.tradingview.com/support/solutions/43000690660-chart-pattern-triple-bottom/
|
|
278
276
|
isTripleBottom() {
|
|
279
|
-
const length = this.close.length;
|
|
277
|
+
const length = this.ohlcv.close.length;
|
|
280
278
|
const third = Math.floor(length / 3);
|
|
281
279
|
|
|
282
|
-
const firstValley = Math.min(...this.close.slice(0, third));
|
|
283
|
-
const secondValley = Math.min(...this.close.slice(third, third * 2));
|
|
284
|
-
const thirdValley = Math.min(...this.close.slice(third * 2));
|
|
280
|
+
const firstValley = Math.min(...this.ohlcv.close.slice(0, third));
|
|
281
|
+
const secondValley = Math.min(...this.ohlcv.close.slice(third, third * 2));
|
|
282
|
+
const thirdValley = Math.min(...this.ohlcv.close.slice(third * 2));
|
|
285
283
|
|
|
286
284
|
if (firstValley <= 0 || secondValley <= 0 || thirdValley <= 0) {
|
|
287
285
|
return false;
|
|
288
286
|
}
|
|
289
287
|
|
|
290
|
-
const riseFromFirstValley = (Math.max(...this.close.slice(0, third)) - firstValley) / firstValley;
|
|
291
|
-
const riseFromSecondValley = (Math.max(...this.close.slice(third, third * 2)) - secondValley) / secondValley;
|
|
292
|
-
const riseFromThirdValley = (Math.max(...this.close.slice(third * 2)) - thirdValley) / thirdValley;
|
|
288
|
+
const riseFromFirstValley = (Math.max(...this.ohlcv.close.slice(0, third)) - firstValley) / firstValley;
|
|
289
|
+
const riseFromSecondValley = (Math.max(...this.ohlcv.close.slice(third, third * 2)) - secondValley) / secondValley;
|
|
290
|
+
const riseFromThirdValley = (Math.max(...this.ohlcv.close.slice(third * 2)) - thirdValley) / thirdValley;
|
|
293
291
|
|
|
294
292
|
if (riseFromFirstValley < 0.1 || riseFromSecondValley < 0.1 || riseFromThirdValley < 0.1) {
|
|
295
293
|
return false;
|
|
@@ -301,20 +299,20 @@ export default class ChartPatterns {
|
|
|
301
299
|
// Implementation of Head and Shoulders
|
|
302
300
|
// https://www.tradingview.com/support/solutions/43000653213-chart-pattern-head-and-shoulders/
|
|
303
301
|
isHeadAndShoulders() {
|
|
304
|
-
const length = this.close.length;
|
|
302
|
+
const length = this.ohlcv.close.length;
|
|
305
303
|
const third = Math.floor(length / 3);
|
|
306
304
|
|
|
307
|
-
const leftShoulder = Math.max(...this.close.slice(0, third));
|
|
308
|
-
const head = Math.max(...this.close.slice(third, third * 2));
|
|
309
|
-
const rightShoulder = Math.max(...this.close.slice(third * 2));
|
|
305
|
+
const leftShoulder = Math.max(...this.ohlcv.close.slice(0, third));
|
|
306
|
+
const head = Math.max(...this.ohlcv.close.slice(third, third * 2));
|
|
307
|
+
const rightShoulder = Math.max(...this.ohlcv.close.slice(third * 2));
|
|
310
308
|
|
|
311
309
|
if (leftShoulder <= 0 || head <= 0 || rightShoulder <= 0) {
|
|
312
310
|
return false;
|
|
313
311
|
}
|
|
314
312
|
|
|
315
|
-
const leftValley = Math.min(...this.close.slice(0, third));
|
|
316
|
-
const middleValley = Math.min(...this.close.slice(third, third * 2));
|
|
317
|
-
const rightValley = Math.min(...this.close.slice(third * 2));
|
|
313
|
+
const leftValley = Math.min(...this.ohlcv.close.slice(0, third));
|
|
314
|
+
const middleValley = Math.min(...this.ohlcv.close.slice(third, third * 2));
|
|
315
|
+
const rightValley = Math.min(...this.ohlcv.close.slice(third * 2));
|
|
318
316
|
|
|
319
317
|
const dropFromHead = (head - middleValley) / head;
|
|
320
318
|
const riseFromValleys = (Math.max(leftValley, rightValley) - Math.min(leftValley, rightValley)) / Math.min(leftValley, rightValley);
|
|
@@ -325,20 +323,20 @@ export default class ChartPatterns {
|
|
|
325
323
|
// Implementation of Inverse Head and Shoulders
|
|
326
324
|
// https://www.tradingview.com/support/solutions/43000690666-chart-pattern-inverse-head-and-shoulders/
|
|
327
325
|
isInverseHeadAndShoulders() {
|
|
328
|
-
const length = this.close.length;
|
|
326
|
+
const length = this.ohlcv.close.length;
|
|
329
327
|
const third = Math.floor(length / 3);
|
|
330
328
|
|
|
331
|
-
const leftShoulder = Math.min(...this.close.slice(0, third));
|
|
332
|
-
const head = Math.min(...this.close.slice(third, third * 2));
|
|
333
|
-
const rightShoulder = Math.min(...this.close.slice(third * 2));
|
|
329
|
+
const leftShoulder = Math.min(...this.ohlcv.close.slice(0, third));
|
|
330
|
+
const head = Math.min(...this.ohlcv.close.slice(third, third * 2));
|
|
331
|
+
const rightShoulder = Math.min(...this.ohlcv.close.slice(third * 2));
|
|
334
332
|
|
|
335
333
|
if (leftShoulder <= 0 || head <= 0 || rightShoulder <= 0) {
|
|
336
334
|
return false;
|
|
337
335
|
}
|
|
338
336
|
|
|
339
|
-
const leftPeak = Math.max(...this.close.slice(0, third));
|
|
340
|
-
const middlePeak = Math.max(...this.close.slice(third, third * 2));
|
|
341
|
-
const rightPeak = Math.max(...this.close.slice(third * 2));
|
|
337
|
+
const leftPeak = Math.max(...this.ohlcv.close.slice(0, third));
|
|
338
|
+
const middlePeak = Math.max(...this.ohlcv.close.slice(third, third * 2));
|
|
339
|
+
const rightPeak = Math.max(...this.ohlcv.close.slice(third * 2));
|
|
342
340
|
|
|
343
341
|
const riseFromHead = (middlePeak - head) / head;
|
|
344
342
|
const dropFromPeaks = (Math.min(leftPeak, rightPeak) - Math.max(leftPeak, rightPeak)) / Math.max(leftPeak, rightPeak);
|
|
@@ -349,16 +347,16 @@ export default class ChartPatterns {
|
|
|
349
347
|
// Implementation of Rising Wedge
|
|
350
348
|
// https://www.tradingview.com/support/solutions/43000653219-chart-pattern-rising-wedge/
|
|
351
349
|
isRisingWedge() {
|
|
352
|
-
const length = this.close.length;
|
|
350
|
+
const length = this.ohlcv.close.length;
|
|
353
351
|
const third = Math.floor(length / 3);
|
|
354
352
|
|
|
355
|
-
const firstPeak = Math.max(...this.close.slice(0, third));
|
|
356
|
-
const secondPeak = Math.max(...this.close.slice(third, third * 2));
|
|
357
|
-
const thirdPeak = Math.max(...this.close.slice(third * 2));
|
|
353
|
+
const firstPeak = Math.max(...this.ohlcv.close.slice(0, third));
|
|
354
|
+
const secondPeak = Math.max(...this.ohlcv.close.slice(third, third * 2));
|
|
355
|
+
const thirdPeak = Math.max(...this.ohlcv.close.slice(third * 2));
|
|
358
356
|
|
|
359
|
-
const firstValley = Math.min(...this.close.slice(0, third));
|
|
360
|
-
const secondValley = Math.min(...this.close.slice(third, third * 2));
|
|
361
|
-
const thirdValley = Math.min(...this.close.slice(third * 2));
|
|
357
|
+
const firstValley = Math.min(...this.ohlcv.close.slice(0, third));
|
|
358
|
+
const secondValley = Math.min(...this.ohlcv.close.slice(third, third * 2));
|
|
359
|
+
const thirdValley = Math.min(...this.ohlcv.close.slice(third * 2));
|
|
362
360
|
|
|
363
361
|
const risingPeaks = firstPeak < secondPeak && secondPeak < thirdPeak;
|
|
364
362
|
const risingValleys = firstValley < secondValley && secondValley < thirdValley;
|
|
@@ -369,16 +367,16 @@ export default class ChartPatterns {
|
|
|
369
367
|
// Implementation of Falling Wedge
|
|
370
368
|
// https://www.tradingview.com/support/solutions/43000697938-chart-pattern-falling-wedge/
|
|
371
369
|
isFallingWedge() {
|
|
372
|
-
const length = this.close.length;
|
|
370
|
+
const length = this.ohlcv.close.length;
|
|
373
371
|
const third = Math.floor(length / 3);
|
|
374
372
|
|
|
375
|
-
const firstPeak = Math.max(...this.close.slice(0, third));
|
|
376
|
-
const secondPeak = Math.max(...this.close.slice(third, third * 2));
|
|
377
|
-
const thirdPeak = Math.max(...this.close.slice(third * 2));
|
|
373
|
+
const firstPeak = Math.max(...this.ohlcv.close.slice(0, third));
|
|
374
|
+
const secondPeak = Math.max(...this.ohlcv.close.slice(third, third * 2));
|
|
375
|
+
const thirdPeak = Math.max(...this.ohlcv.close.slice(third * 2));
|
|
378
376
|
|
|
379
|
-
const firstValley = Math.min(...this.close.slice(0, third));
|
|
380
|
-
const secondValley = Math.min(...this.close.slice(third, third * 2));
|
|
381
|
-
const thirdValley = Math.min(...this.close.slice(third * 2));
|
|
377
|
+
const firstValley = Math.min(...this.ohlcv.close.slice(0, third));
|
|
378
|
+
const secondValley = Math.min(...this.ohlcv.close.slice(third, third * 2));
|
|
379
|
+
const thirdValley = Math.min(...this.ohlcv.close.slice(third * 2));
|
|
382
380
|
|
|
383
381
|
const fallingPeaks = firstPeak > secondPeak && secondPeak > thirdPeak;
|
|
384
382
|
const fallingValleys = firstValley > secondValley && secondValley > thirdValley;
|
|
@@ -389,14 +387,14 @@ export default class ChartPatterns {
|
|
|
389
387
|
// Implementation of Bullish Triangle
|
|
390
388
|
// https://www.tradingview.com/support/solutions/43000653217/
|
|
391
389
|
isBullishTriangle() {
|
|
392
|
-
const length = this.close.length;
|
|
390
|
+
const length = this.ohlcv.close.length;
|
|
393
391
|
const half = Math.floor(length / 2);
|
|
394
392
|
|
|
395
|
-
const firstHalfHigh = Math.max(...this.high.slice(0, half));
|
|
396
|
-
const secondHalfHigh = Math.max(...this.high.slice(half));
|
|
393
|
+
const firstHalfHigh = Math.max(...this.ohlcv.high.slice(0, half));
|
|
394
|
+
const secondHalfHigh = Math.max(...this.ohlcv.high.slice(half));
|
|
397
395
|
|
|
398
|
-
const firstHalfLow = Math.min(...this.low.slice(0, half));
|
|
399
|
-
const secondHalfLow = Math.min(...this.low.slice(half));
|
|
396
|
+
const firstHalfLow = Math.min(...this.ohlcv.low.slice(0, half));
|
|
397
|
+
const secondHalfLow = Math.min(...this.ohlcv.low.slice(half));
|
|
400
398
|
|
|
401
399
|
const contractingHighs = firstHalfHigh > secondHalfHigh;
|
|
402
400
|
const risingLows = firstHalfLow < secondHalfLow;
|
|
@@ -407,14 +405,14 @@ export default class ChartPatterns {
|
|
|
407
405
|
// Implementation of Bearish Triangle
|
|
408
406
|
// https://www.tradingview.com/support/solutions/43000653217/
|
|
409
407
|
isBearishTriangle() {
|
|
410
|
-
const length = this.close.length;
|
|
408
|
+
const length = this.ohlcv.close.length;
|
|
411
409
|
const half = Math.floor(length / 2);
|
|
412
410
|
|
|
413
|
-
const firstHalfHigh = Math.max(...this.high.slice(0, half));
|
|
414
|
-
const secondHalfHigh = Math.max(...this.high.slice(half));
|
|
411
|
+
const firstHalfHigh = Math.max(...this.ohlcv.high.slice(0, half));
|
|
412
|
+
const secondHalfHigh = Math.max(...this.ohlcv.high.slice(half));
|
|
415
413
|
|
|
416
|
-
const firstHalfLow = Math.min(...this.low.slice(0, half));
|
|
417
|
-
const secondHalfLow = Math.min(...this.low.slice(half));
|
|
414
|
+
const firstHalfLow = Math.min(...this.ohlcv.low.slice(0, half));
|
|
415
|
+
const secondHalfLow = Math.min(...this.ohlcv.low.slice(half));
|
|
418
416
|
|
|
419
417
|
const contractingLows = firstHalfLow < secondHalfLow;
|
|
420
418
|
const fallingHighs = firstHalfHigh > secondHalfHigh;
|
|
@@ -425,16 +423,16 @@ export default class ChartPatterns {
|
|
|
425
423
|
// Implementation of Bullish Rectangle
|
|
426
424
|
// https://www.tradingview.com/support/solutions/43000653216/
|
|
427
425
|
isBullishRectangle() {
|
|
428
|
-
const length = this.close.length;
|
|
426
|
+
const length = this.ohlcv.close.length;
|
|
429
427
|
const third = Math.floor(length / 3);
|
|
430
428
|
|
|
431
|
-
const firstSectionHigh = Math.max(...this.high.slice(0, third));
|
|
432
|
-
const secondSectionHigh = Math.max(...this.high.slice(third, third * 2));
|
|
433
|
-
const thirdSectionHigh = Math.max(...this.high.slice(third * 2));
|
|
429
|
+
const firstSectionHigh = Math.max(...this.ohlcv.high.slice(0, third));
|
|
430
|
+
const secondSectionHigh = Math.max(...this.ohlcv.high.slice(third, third * 2));
|
|
431
|
+
const thirdSectionHigh = Math.max(...this.ohlcv.high.slice(third * 2));
|
|
434
432
|
|
|
435
|
-
const firstSectionLow = Math.min(...this.low.slice(0, third));
|
|
436
|
-
const secondSectionLow = Math.min(...this.low.slice(third, third * 2));
|
|
437
|
-
const thirdSectionLow = Math.min(...this.low.slice(third * 2));
|
|
433
|
+
const firstSectionLow = Math.min(...this.ohlcv.low.slice(0, third));
|
|
434
|
+
const secondSectionLow = Math.min(...this.ohlcv.low.slice(third, third * 2));
|
|
435
|
+
const thirdSectionLow = Math.min(...this.ohlcv.low.slice(third * 2));
|
|
438
436
|
|
|
439
437
|
const stableHighs = Math.abs(firstSectionHigh - secondSectionHigh) / firstSectionHigh < 0.03 &&
|
|
440
438
|
Math.abs(secondSectionHigh - thirdSectionHigh) / secondSectionHigh < 0.03;
|
|
@@ -447,16 +445,16 @@ export default class ChartPatterns {
|
|
|
447
445
|
// Implementation of Bearish Rectangle
|
|
448
446
|
// https://www.tradingview.com/support/solutions/43000653216/
|
|
449
447
|
isBearishRectangle() {
|
|
450
|
-
const length = this.close.length;
|
|
448
|
+
const length = this.ohlcv.close.length;
|
|
451
449
|
const third = Math.floor(length / 3);
|
|
452
450
|
|
|
453
|
-
const firstSectionHigh = Math.max(...this.high.slice(0, third));
|
|
454
|
-
const secondSectionHigh = Math.max(...this.high.slice(third, third * 2));
|
|
455
|
-
const thirdSectionHigh = Math.max(...this.high.slice(third * 2));
|
|
451
|
+
const firstSectionHigh = Math.max(...this.ohlcv.high.slice(0, third));
|
|
452
|
+
const secondSectionHigh = Math.max(...this.ohlcv.high.slice(third, third * 2));
|
|
453
|
+
const thirdSectionHigh = Math.max(...this.ohlcv.high.slice(third * 2));
|
|
456
454
|
|
|
457
|
-
const firstSectionLow = Math.min(...this.low.slice(0, third));
|
|
458
|
-
const secondSectionLow = Math.min(...this.low.slice(third, third * 2));
|
|
459
|
-
const thirdSectionLow = Math.min(...this.low.slice(third * 2));
|
|
455
|
+
const firstSectionLow = Math.min(...this.ohlcv.low.slice(0, third));
|
|
456
|
+
const secondSectionLow = Math.min(...this.ohlcv.low.slice(third, third * 2));
|
|
457
|
+
const thirdSectionLow = Math.min(...this.ohlcv.low.slice(third * 2));
|
|
460
458
|
|
|
461
459
|
const stableHighs = Math.abs(firstSectionHigh - secondSectionHigh) / firstSectionHigh < 0.03 &&
|
|
462
460
|
Math.abs(secondSectionHigh - thirdSectionHigh) / secondSectionHigh < 0.03;
|
package/src/utilities.js
CHANGED
|
@@ -1,50 +1,64 @@
|
|
|
1
|
+
import {Big} from 'trading-signals';
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
// Function to find crosses between two arrays: fast and slow
|
|
2
5
|
export const findCrosses = (fast, slow) => {
|
|
3
6
|
// Map states based on comparison of fast and slow arrays
|
|
4
|
-
const states = fast.map((f, i) => {
|
|
5
|
-
if (f > slow[i]) {
|
|
6
|
-
return 'up';
|
|
7
|
-
} else if (f < slow[i]) {
|
|
8
|
-
return 'down';
|
|
9
|
-
} else {
|
|
10
|
-
return 'neutral';
|
|
11
|
-
}
|
|
12
|
-
}).reverse(); // Reverse for processing from the end
|
|
13
7
|
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
fast = fast.filter(o => o instanceof Big)
|
|
9
|
+
slow = slow.filter(o => o instanceof Big)
|
|
10
|
+
const min = Math.min(fast.length, slow.length)
|
|
16
11
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const chunkLength = chunk.length;
|
|
20
|
-
return chunk.map((state, index) => {
|
|
21
|
-
let value = chunkLength - index;
|
|
12
|
+
fast = fast.slice(-min);
|
|
13
|
+
slow = slow.slice(-min);
|
|
22
14
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
15
|
+
let state = fast.map((f, i) => {
|
|
16
|
+
if(f.eq(slow[i])) return 'neutral'
|
|
17
|
+
else if(f.gt(slow[i])) return 'up'
|
|
18
|
+
else if(f.lt(slow[i])) return 'down'
|
|
19
|
+
else throw Error('undefined error in findCrosses')
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const groups = groupConsecutiveValues(state)
|
|
23
|
+
const groupLengths = groups.map(g => g.length)
|
|
24
|
+
|
|
25
|
+
return groups.map((group, gIndex) => {
|
|
26
|
+
let initialValue = groupLengths[gIndex]
|
|
27
|
+
|
|
28
|
+
return group.map((s, i) => {
|
|
29
|
+
let v = initialValue - i
|
|
30
|
+
|
|
31
|
+
if(s === 'neutral')
|
|
32
|
+
{
|
|
33
|
+
v = 0
|
|
34
|
+
}
|
|
35
|
+
if(s === 'up')
|
|
36
|
+
{
|
|
37
|
+
v = v * 1
|
|
29
38
|
}
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
if(s === 'down')
|
|
40
|
+
{
|
|
41
|
+
v = v * -1
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return v
|
|
45
|
+
}).reverse()
|
|
46
|
+
}).flat()
|
|
32
47
|
|
|
33
|
-
|
|
34
|
-
};
|
|
48
|
+
}
|
|
35
49
|
|
|
36
50
|
// Helper function to group consecutive values
|
|
37
|
-
|
|
38
|
-
if (arr.length === 0) return []
|
|
51
|
+
const groupConsecutiveValues = arr => {
|
|
52
|
+
if (arr.length === 0) return []
|
|
39
53
|
|
|
40
54
|
return arr.reduce((acc, currentValue, index, array) => {
|
|
41
55
|
if (index === 0) {
|
|
42
56
|
// Start the first group with the first element
|
|
43
|
-
acc.push([currentValue])
|
|
57
|
+
acc.push([currentValue])
|
|
44
58
|
} else {
|
|
45
59
|
// Get the previous value
|
|
46
|
-
const prevValue = array[index - 1]
|
|
47
|
-
const currentGroup = acc[acc.length - 1]
|
|
60
|
+
const prevValue = array[index - 1]
|
|
61
|
+
const currentGroup = acc[acc.length - 1]
|
|
48
62
|
|
|
49
63
|
// Check the direction of the previous and current values
|
|
50
64
|
if (currentValue !== prevValue) {
|
|
@@ -55,6 +69,6 @@ function groupConsecutiveValues(arr) {
|
|
|
55
69
|
currentGroup.push(currentValue);
|
|
56
70
|
}
|
|
57
71
|
}
|
|
58
|
-
return acc
|
|
59
|
-
}, [])
|
|
72
|
+
return acc
|
|
73
|
+
}, [])
|
|
60
74
|
}
|