UNPKG

openalgo-charts

Version:

From-scratch, dependency-free canvas charting engine for OpenAlgo: professional-grade interactive rendering, advanced on-chart trading, and a one-call widget tier that adds the toolbar, drawing rail, dialogs and shortcuts.

3 lines (2 loc) • 21.8 kB
import{registerSeriesTransform as e,registerChartType as t}from"./openalgo-charts.mjs";function i(e,t,i){const s=e.boxSize;return"number"==typeof s&&s>0?s:void 0!==t.boxSize&&t.boxSize>0?t.boxSize:i}function s(e,t,s,r,o,n,l=1/0){if(0===t.length)return;const h=function(e){let t=1/0;for(const{bar:i}of e){const e=i.high-i.low;e>0&&e<t&&(t=e)}return Number.isFinite(t)?t:0}(t),a=Math.max(3,Math.floor(r*o*.7))/2,u=l===1/0?1/0:l*o;e.save(),e.lineWidth=Math.max(1,Math.floor(o));for(const{x:r,bar:l}of t){const t=i(l,n,h);if(!(t>0))continue;const c=Math.round(l.low/t),b=Math.round(l.high/t)-1;if(b<c)continue;if(b-c+1>4e3)continue;const _=l.close>=l.open;e.strokeStyle=_?n.upColor??"#26a69a":n.downColor??"#ef5350";const f=r*o;for(let i=c;i<=b;i++){const r=s((i+1)*t)*o,n=s(i*t)*o;n<0||r>u||(e.beginPath(),_?(e.moveTo(f-a,r),e.lineTo(f+a,n),e.moveTo(f+a,r),e.lineTo(f-a,n)):e.ellipse(f,(r+n)/2,a,Math.abs(n-r)/2,0,0,2*Math.PI),e.stroke())}}e.restore()}function r(e){return Object.assign(Object.create(Object.getPrototypeOf(e)),e)}function o(e){let t=-1/0;const i=[];for(const s of e){let e=s.time;e<=t&&(e=t+1),t=e,i.push(e===s.time?s:{...s,time:e})}return i}function n(e,t){e.reset();const i=[];for(const s of t)i.push(...e.push(s));return e.flush&&i.push(...e.flush()),o(i)}class l{constructor(){Object.defineProperty(this,"_prevOpen",{enumerable:!0,configurable:!0,writable:!0,value:NaN}),Object.defineProperty(this,"_prevClose",{enumerable:!0,configurable:!0,writable:!0,value:NaN})}reset(){this._prevOpen=NaN,this._prevClose=NaN}clone(){return r(this)}push(e){const t=(e.open+e.high+e.low+e.close)/4,i=Number.isNaN(this._prevOpen)?(e.open+e.close)/2:(this._prevOpen+this._prevClose)/2,s=Math.max(e.high,i,t),r=Math.min(e.low,i,t);return this._prevOpen=i,this._prevClose=t,[{time:e.time,open:i,high:s,low:r,close:t,volume:e.volume,oi:e.oi}]}}class h{constructor(e){if(Object.defineProperty(this,"_box",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_edge",{enumerable:!0,configurable:!0,writable:!0,value:NaN}),e.boxSize<=0)throw new Error("openalgo-charts: Renko boxSize must be > 0");this._box=e.boxSize}reset(){this._edge=NaN}clone(){return r(this)}push(e){const t=e.close,i=[];if(Number.isNaN(this._edge))return this._edge=Math.floor(t/this._box)*this._box,i;for(;t>=this._edge+this._box;){const t=this._edge,s=this._edge+this._box;i.push({time:e.time,open:t,high:s,low:t,close:s}),this._edge=s}for(;t<=this._edge-this._box;){const t=this._edge,s=this._edge-this._box;i.push({time:e.time,open:t,high:t,low:s,close:s}),this._edge=s}return i}}class a{constructor(e){if(Object.defineProperty(this,"_range",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_cur",{enumerable:!0,configurable:!0,writable:!0,value:null}),e.range<=0)throw new Error("openalgo-charts: range must be > 0");this._range=e.range}reset(){this._cur=null}clone(){const e=r(this);return e._cur=null===this._cur?null:{...this._cur},e}push(e){const t=e.close,i=[];return null===this._cur?this._cur={time:e.time,open:t,high:t,low:t,close:t}:(this._cur.high=Math.max(this._cur.high,t),this._cur.low=Math.min(this._cur.low,t),this._cur.close=t,this._cur.time=e.time),this._cur.high-this._cur.low>=this._range&&(i.push(this._cur),this._cur=null),i}flush(){if(null===this._cur)return[];const e=this._cur;return this._cur=null,[e]}}class u{constructor(e={lines:3}){Object.defineProperty(this,"_n",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_lines",{enumerable:!0,configurable:!0,writable:!0,value:[]}),this._n=Math.max(1,e.lines)}reset(){this._lines=[]}clone(){const e=r(this);return e._lines=this._lines.slice(),e}push(e){const t=e.close;if(0===this._lines.length)return this._lines.push({open:t,close:t}),[];const i=this._lines.slice(-this._n);let s=-1/0,r=1/0;for(const e of i)s=Math.max(s,e.open,e.close),r=Math.min(r,e.open,e.close);const o=this._lines[this._lines.length-1];let n=null;return(t>s||t<r)&&(n={open:o.close,close:t}),null===n?[]:(this._lines.push(n),this._lines.length>this._n&&this._lines.splice(0,this._lines.length-this._n),[{time:e.time,open:n.open,high:Math.max(n.open,n.close),low:Math.min(n.open,n.close),close:n.close}])}}class c{constructor(e){Object.defineProperty(this,"_period",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_prevClose",{enumerable:!0,configurable:!0,writable:!0,value:NaN}),Object.defineProperty(this,"_sum",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_n",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_atr",{enumerable:!0,configurable:!0,writable:!0,value:NaN}),this._period=Math.max(1,Math.floor(e))}reset(){this._prevClose=NaN,this._sum=0,this._n=0,this._atr=NaN}push(e){const t=Number.isNaN(this._prevClose)?e.high-e.low:Math.max(e.high-e.low,Math.abs(e.high-this._prevClose),Math.abs(e.low-this._prevClose));this._prevClose=e.close,this._n<this._period?(this._sum+=t,this._n+=1,this._atr=this._sum/this._n):this._atr=(this._atr*(this._period-1)+t)/this._period}value(){return this._atr}}class b{constructor(e){Object.defineProperty(this,"_reversal",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_method",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_mode",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_fixedBox",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_percent",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_atrMult",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_atr",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_box",{enumerable:!0,configurable:!0,writable:!0,value:NaN}),Object.defineProperty(this,"_dir",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_top",{enumerable:!0,configurable:!0,writable:!0,value:NaN}),Object.defineProperty(this,"_bot",{enumerable:!0,configurable:!0,writable:!0,value:NaN}),Object.defineProperty(this,"_time",{enumerable:!0,configurable:!0,writable:!0,value:0});const t=e.mode??"fixed";if(this._mode=t,this._reversal=Math.max(1,Math.floor(e.reversal??3)),this._method=e.method??"hl",this._fixedBox=e.boxSize??NaN,this._percent=e.percent??NaN,this._atrMult=e.atrMultiplier??1,this._atr=new c(e.atrPeriod??14),"fixed"===t&&!(this._fixedBox>0))throw new Error("openalgo-charts: P&F boxSize must be > 0");if("percent"===t&&!(this._percent>0))throw new Error("openalgo-charts: P&F percent must be > 0")}get boxSize(){return this._fixedBox}reset(){this._box=NaN,this._dir=0,this._top=NaN,this._bot=NaN,this._time=0,this._atr.reset()}clone(){const e=r(this);return Object.assign(e,{_atr:r(this._atr)}),e}_resolveBox(e){let t=NaN;if(t="fixed"===this._mode?this._fixedBox:"percent"===this._mode?Math.abs(e)*this._percent/100:this._atr.value()*this._atrMult,t>0&&Number.isFinite(t))return t;if(this._box>0)return this._box;const i=.01*Math.abs(e);return i>0?i:1}_column(){const e=this._box,t=this._bot*e,i=(this._top+1)*e,s=this._dir>=0;return{time:this._time,open:s?t:i,close:s?i:t,high:i,low:t,boxSize:e,boxes:this._top-this._bot+1}}push(e){"atr"===this._mode&&this._atr.push(e);const t="hl"===this._method,i=t?e.high:e.close,s=t?e.low:e.close;if(Number.isNaN(this._top)){this._box=this._resolveBox(e.close);const t=Math.floor(e.close/this._box);return this._top=t,this._bot=t,this._dir=0,this._time=e.time,[]}const r=Math.floor(i/this._box),o=Math.floor(s/this._box);if(0===this._dir){const t=r-this._top,i=this._bot-o;return t<=0&&i<=0||(t>=i?(this._top=r,this._dir=1):(this._bot=o,this._dir=-1),this._time=e.time),[]}const n=[];if(this._dir>0){if(r>this._top)this._top=r;else if(this._top-o>=this._reversal){const t=this._top*this._box;n.push(this._column()),this._box=this._resolveBox(s),this._top=Math.ceil(t/this._box)-1,this._bot=Math.floor(s/this._box),this._dir=-1,this._time=e.time}}else if(o<this._bot)this._bot=o;else if(r-this._bot>=this._reversal){const t=(this._bot+1)*this._box;n.push(this._column()),this._box=this._resolveBox(i),this._bot=Math.floor(t/this._box),this._top=Math.floor(i/this._box),this._dir=1,this._time=e.time}return n}flush(){return 0===this._dir||Number.isNaN(this._top)?[]:[this._column()]}}function _(e,t,i){return{time:e,open:t,high:t,low:t,close:t,volume:i?1:0}}class f{constructor(e){if(Object.defineProperty(this,"_reversal",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_dir",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_ext",{enumerable:!0,configurable:!0,writable:!0,value:NaN}),Object.defineProperty(this,"_prevShoulder",{enumerable:!0,configurable:!0,writable:!0,value:-1/0}),Object.defineProperty(this,"_prevWaist",{enumerable:!0,configurable:!0,writable:!0,value:1/0}),Object.defineProperty(this,"_thick",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"_time",{enumerable:!0,configurable:!0,writable:!0,value:0}),e.reversal<=0)throw new Error("openalgo-charts: Kagi reversal must be > 0");this._reversal=e.reversal}reset(){this._dir=0,this._ext=NaN,this._prevShoulder=-1/0,this._prevWaist=1/0,this._thick=!1,this._time=0}clone(){return r(this)}push(e){const t=e.close;if(this._time=e.time,Number.isNaN(this._ext))return this._ext=t,[];const i=[];return this._dir>=0?t>this._ext?(this._ext=t,t>this._prevShoulder&&(this._thick=!0)):this._ext-t>=this._reversal&&(i.push(_(e.time,this._ext,this._thick)),this._prevShoulder=this._ext,this._dir=-1,this._ext=t):t<this._ext?(this._ext=t,t<this._prevWaist&&(this._thick=!1)):t-this._ext>=this._reversal&&(i.push(_(e.time,this._ext,this._thick)),this._prevWaist=this._ext,this._dir=1,this._ext=t),i}flush(){return Number.isNaN(this._ext)?[]:[_(this._time,this._ext,this._thick)]}}function m(e){const t=new Map;for(const i of e)t.set(i.time,i);return Array.from(t.values()).sort((e,t)=>e.time-t.time)}function p(e){let t=-1/0,i=1/0;for(const s of e)s.high>t&&(t=s.high),s.low<i&&(i=s.low);const s=Math.max((t-i)/40,Math.abs(e[e.length-1]?.close??0)/1e3);return s>0&&Number.isFinite(s)?Number(s.toPrecision(2)):1}const d=(e,t)=>"number"==typeof e&&e>0?e:t();class v{constructor(e,t,i,s){Object.defineProperty(this,"_given",{enumerable:!0,configurable:!0,writable:!0,value:e}),Object.defineProperty(this,"_resolve",{enumerable:!0,configurable:!0,writable:!0,value:t}),Object.defineProperty(this,"_make",{enumerable:!0,configurable:!0,writable:!0,value:i}),Object.defineProperty(this,"_oneToOne",{enumerable:!0,configurable:!0,writable:!0,value:s}),Object.defineProperty(this,"_source",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"_state",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"_elements",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"_index",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"_committed",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_resolved",{enumerable:!0,configurable:!0,writable:!0,value:null})}setData(e){this._source=m(e),this._resolved=null,this._rebuild()}prepend(e){this._source=m([...this._source,...e]),this._rebuild()}update(e){const t=this._source.length,i=this._source[t-1];if(void 0===i||e.time<i.time)return this._source=m([...this._source,e]),this._rebuild(),0;const s=this._committed;return e.time>i.time?(this._commit(t-1),this._source.push(e)):this._source[t-1]=e,this._formTail(),s}source(){return this._source}elements(){return this._elements}sourceIndex(){return this._oneToOne?null:this._index}_rebuild(){this._elements.length=0,this._index.length=0,this._committed=0;const e=this._source.length;if(0!==e){this._resolved??(this._resolved=this._resolve(this._given,this._source)),this._state=this._make(this._resolved);for(let t=0;t<e-1;t++)this._commit(t);this._formTail()}else this._state=null}_commit(e){this._elements.length=this._committed,this._index.length=this._committed;for(const t of this._state.push(this._source[e]))this._append(t,e);this._committed=this._elements.length}_formTail(){this._elements.length=this._committed,this._index.length=this._committed;const e=this._source.length;if(0===e||null===this._state)return;const t=this._state.clone();for(const i of t.push(this._source[e-1]))this._append(i,e-1);for(const i of t.flush?.()??[])this._append(i,e-1)}_append(e,t){const i=this._elements[this._elements.length-1]?.time??-1/0;this._elements.push(e.time>i?e:{...e,time:i+1}),this._index.push(t)}}const g=(e,t)=>({key:e,type:"number",label:`${t} (0 = from history)`,default:0,min:0});function x(t,i,s,r,o,n,l=!1){e(t,{name:i,renderer:s,inputs:r,create:e=>new v(function(e,t,i){const s=e=>{throw new TypeError(`openalgo-charts: invalid series transform: ${e}`)};(null===i||"object"!=typeof i||Array.isArray(i))&&s("options must be an object");const r={};for(const[o,n]of Object.entries(i)){const i=t.find(e=>e.key===o);void 0===i&&s(`${e} option "${o}" is not one it takes`),("number"===i.type?"number"==typeof n&&Number.isFinite(n)&&(void 0===i.min||n>=i.min)&&(void 0===i.max||n<=i.max)&&(1!==i.step||Number.isInteger(n)):"select"===i.type&&i.options.some(e=>e.value===n))||s(`${e} option "${o}" cannot be ${String(n)}`),r[o]=n}return r}(t,r,e),o,n,l)})}const w=(e,t)=>e[t];const y={abs:1,sqrt:1,ln:1,log:1,log10:1,exp:1,min:2,max:2,pow:2};class N extends Error{constructor(e,t){super(`openalgo-charts: ${e}`),Object.defineProperty(this,"position",{enumerable:!0,configurable:!0,writable:!0,value:t}),this.name="ExpressionError"}}const M=/[A-Za-z_]/,k=/[A-Za-z0-9_.:!#&]/;const P={"+":1,"-":1,"*":2,"/":2,"^":3};function O(e,t){let i=0;const s=()=>e[i];function r(){const e=s();if(void 0===e)throw new N("expression ended early",t.length);if("num"===e.t)return i++,{k:"num",v:e.v};if("sym"===e.t){i++;const r=e.v.toLowerCase();if(r in y&&"op"===s()?.t&&"("===s()?.v){i++;const o=[];if("op"!==s()?.t||")"!==s()?.v)for(;o.push(n(0)),"op"===s()?.t&&","===s()?.v;)i++;if("op"!==s()?.t||")"!==s()?.v)throw new N(`${r}( is not closed`,s()?.i??t.length);i++;const l=y[r];if(o.length!==l)throw new N(`${r}() takes ${l} argument${1===l?"":"s"}, got ${o.length}`,e.i);return{k:"fn",name:r,args:o}}return{k:"sym",name:e.v}}if("("===e.v){i++;const t=n(0);if("op"!==s()?.t||")"!==s()?.v)throw new N("( is not closed",e.i);return i++,t}if("-"===e.v)return i++,{k:"neg",a:o()};if("+"===e.v)return i++,o();throw new N(`unexpected "${e.v}"`,e.i)}function o(){return r()}function n(e){let t=o();for(;;){const r=s();if(void 0===r||"op"!==r.t||!(r.v in P))break;const o=P[r.v];if(o<e)break;i++;const l=n("^"===r.v?o:o+1);t={k:"bin",op:r.v,a:t,b:l}}return t}const l=n(0),h=e[i];if(void 0!==h)throw new N(`unexpected "${h.v}"`,h.i);return l}function j(e,t){if("sym"!==e.k)if("neg"!==e.k){if("bin"===e.k)return j(e.a,t),void j(e.b,t);if("fn"===e.k)for(const i of e.args)j(i,t)}else j(e.a,t);else t.includes(e.name)||t.push(e.name)}function S(e){const t=function(e){const t=[];let i=0;for(;i<e.length;){const s=e[i];if(" "!==s&&"\t"!==s&&"\n"!==s&&"\r"!==s){if("'"===s||'"'===s){const r=e.indexOf(s,i+1);if(-1===r)throw new N(`unclosed ${s} in expression`,i);const o=e.slice(i+1,r);if(""===o)throw new N("empty quoted symbol",i);t.push({t:"sym",v:o,i:i}),i=r+1;continue}if(/[0-9]/.test(s)||"."===s&&/[0-9]/.test(e[i+1]??"")){let s=i;for(;s<e.length&&/[0-9.]/.test(e[s]);)s++;const r=e.slice(i,s),o=Number(r);if(!Number.isFinite(o))throw new N(`"${r}" is not a number`,i);t.push({t:"num",v:o,i:i}),i=s;continue}if(M.test(s)){let s=i;for(;s<e.length&&k.test(e[s]);)s++;let r=e.slice(i,s);for(;r.endsWith(":");)r=r.slice(0,-1),s--;t.push({t:"sym",v:r,i:i}),i=s;continue}if("+-*/^(),".includes(s))t.push({t:"op",v:s,i:i}),i++;else if("×"!==s)if("÷"!==s){if("−"!==s)throw new N(`unexpected "${s}" in expression`,i);t.push({t:"op",v:"-",i:i}),i++}else t.push({t:"op",v:"/",i:i}),i++;else t.push({t:"op",v:"*",i:i}),i++}else i++}return t}(e);if(0===t.length)throw new N("expression is empty",0);const i=O(t,e),s=[];if(j(i,s),0===s.length)throw new N("expression names no symbol",0);return{source:e,symbols:s,ast:i}}function z(e){try{return"sym"===S(e).ast.k}catch{return!1}}const C={lo:NaN,hi:NaN},$=e=>!Number.isFinite(e.lo)||!Number.isFinite(e.hi),T=e=>({lo:Math.min(...e),hi:Math.max(...e)});function B(e,t){if(t.lo!==t.hi)return C;const i=t.lo,s=[Math.pow(e.lo,i),Math.pow(e.hi,i)];return e.lo<0&&e.hi>0&&Number.isInteger(i)&&i%2==0&&s.push(0),T(s)}function F(e,t){return T([t(e.lo),t(e.hi)])}function W(e,t){switch(e.k){case"num":return{lo:e.v,hi:e.v};case"sym":return t(e.name)??C;case"neg":{const i=W(e.a,t);return $(i)?C:{lo:-i.hi,hi:-i.lo}}case"bin":{const i=W(e.a,t),s=W(e.b,t);if($(i)||$(s))return C;switch(e.op){case"+":return{lo:i.lo+s.lo,hi:i.hi+s.hi};case"-":return{lo:i.lo-s.hi,hi:i.hi-s.lo};case"*":return function(e,t){return T([e.lo*t.lo,e.lo*t.hi,e.hi*t.lo,e.hi*t.hi])}(i,s);case"/":return function(e,t){return t.lo<=0&&t.hi>=0?C:T([e.lo/t.lo,e.lo/t.hi,e.hi/t.lo,e.hi/t.hi])}(i,s);case"^":return B(i,s)}return C}case"fn":{const i=e.args.map(e=>W(e,t));if(i.some($))return C;const[s,r]=i;switch(e.name){case"abs":return function(e){return e.lo>=0?e:e.hi<=0?{lo:-e.hi,hi:-e.lo}:{lo:0,hi:Math.max(-e.lo,e.hi)}}(s);case"sqrt":return s.lo<0?C:F(s,Math.sqrt);case"ln":case"log":return s.lo<=0?C:F(s,Math.log);case"log10":return s.lo<=0?C:F(s,Math.log10);case"exp":return F(s,Math.exp);case"min":return{lo:Math.min(s.lo,r.lo),hi:Math.min(s.hi,r.hi)};case"max":return{lo:Math.max(s.lo,r.lo),hi:Math.max(s.hi,r.hi)};case"pow":return B(s,r)}return C}}}function A(e,t,i={}){const s="interval"===i.ohlc,r=i.primary??e.symbols[0],o=t[r];if(void 0===o||0===o.length)return[];const n=new Map;for(const i of e.symbols){if(i===r)continue;const e=t[i];if(void 0===e)return[];const s=new Map;for(const t of e)s.set(t.time,t);n.set(i,s)}const l=[],h=new Map;for(const t of o){h.clear(),h.set(r,t);let o=!0;for(const[e,i]of n){const s=i.get(t.time);if(void 0===s){o=!1;break}h.set(e,s)}if(!o)continue;const a=e=>t=>{const i=h.get(t);return void 0===i?null:{lo:i[e],hi:i[e]}},u=W(e.ast,a("open")),c=W(e.ast,a("close"));if($(u)||$(c))continue;let b=Math.max(u.hi,c.hi),_=Math.min(u.lo,c.lo);if(s){const t=W(e.ast,e=>{const t=h.get(e);return void 0===t?null:{lo:t.low,hi:t.high}});if($(t))continue;b=Math.max(b,t.hi),_=Math.min(_,t.lo)}const f={time:t.time,open:u.lo,high:b,low:_,close:c.lo};if("sum"===i.volume){let t=0;for(const i of e.symbols){const e=h.get(i)?.volume;if(void 0===e||!Number.isFinite(e)||e<0){t=NaN;break}t+=e}Number.isFinite(t)&&(f.volume=t)}l.push(f)}return l}const E="transform";let R=!1;function q(){R||(R=!0,function(){x("heikin-ashi","Heikin Ashi","candlestick",[],()=>({}),()=>new l,!0),x("renko","Renko","candlestick",[g("boxSize","Box size")],(e,t)=>({boxSize:d(e.boxSize,()=>p(t))}),e=>new h({boxSize:w(e,"boxSize")})),x("range-bars","Range bars","candlestick",[g("range","Range")],(e,t)=>({range:d(e.range,()=>2*p(t))}),e=>new a({range:w(e,"range")})),x("line-break","Line break","candlestick",[{key:"lines",type:"number",label:"Lines to break",default:3,min:1,step:1}],e=>({lines:e.lines??3}),e=>new u({lines:w(e,"lines")}));const e={key:"mode",is:"atr"};x("point-figure","Point and figure","point-figure",[{key:"mode",type:"select",label:"Box size from",default:"fixed",options:[{label:"Fixed size",value:"fixed"},{label:"Percent of price",value:"percent"},{label:"ATR",value:"atr"}]},{...g("boxSize","Box size"),visibleWhen:{key:"mode",is:"fixed"}},{key:"percent",type:"number",label:"Box percent",default:1,min:0,visibleWhen:{key:"mode",is:"percent"}},{key:"atrPeriod",type:"number",label:"ATR length",default:14,min:1,step:1,visibleWhen:e},{key:"atrMultiplier",type:"number",label:"ATR multiplier",default:1,min:0,visibleWhen:e},{key:"reversal",type:"number",label:"Reversal boxes",default:3,min:1,step:1},{key:"method",type:"select",label:"Prices",default:"hl",options:[{label:"High and low",value:"hl"},{label:"Close",value:"close"}]}],(e,t)=>{const i=e.mode??"fixed";return{...e,mode:i,..."fixed"===i?{boxSize:d(e.boxSize,()=>p(t))}:{},..."percent"===i?{percent:d(e.percent,()=>1)}:{}}},e=>new b({mode:e.mode,boxSize:e.boxSize,percent:e.percent,atrPeriod:e.atrPeriod,atrMultiplier:e.atrMultiplier,reversal:e.reversal,method:e.method})),x("kagi","Kagi","kagi",[g("reversal","Reversal")],(e,t)=>({reversal:d(e.reversal,()=>2*p(t))}),e=>new f({reversal:w(e,"reversal")}))}(),t("point-figure",{defaultStyle:{},isPriceSeries:!0,draw:(e,t,i,r,o,n,l)=>s(e,t,i,r,o,n,l.plotHeight),extents:e=>({min:e.low,max:e.high})}),t("kagi",{defaultStyle:{thickColor:"#26a69a",thinColor:"#ef5350"},isPriceSeries:!0,connectsBars:!0,draw:(e,t,i,s,r,o)=>function(e,t,i,s,r){if(t.length<2)return;const o=r.thickColor??"#26a69a",n=r.thinColor??"#ef5350",l=Math.max(2,Math.round(2.5*s)),h=Math.max(1,Math.round(s)),a=t[0].edgeX,u=t[t.length-1].edgeX,c=void 0===a?-1/0:a-8,b=void 0===u?1/0:u+8;e.save();for(let r=1;r<t.length;r++){const a=t[r-1],u=t[r],_=(u.bar.volume??0)>=1;e.strokeStyle=_?o:n,e.lineWidth=_?l:h;const f=Math.max(a.x,c)*s,m=Math.min(u.x,b)*s,p=i(a.bar.close)*s,d=i(u.bar.close)*s;e.beginPath(),e.moveTo(f,p),e.lineTo(m,p),u.x<=b&&e.lineTo(m,d),e.stroke()}e.restore()}(e,t,i,r,o),extents:e=>({min:e.close,max:e.close})}))}q();export{N as ExpressionError,l as HeikinAshiTransform,f as KagiTransform,u as LineBreakTransform,b as PointFigureTransform,a as RangeBarsTransform,h as RenkoTransform,E as TRANSFORM_TIER,o as ensureIncreasingTimes,A as evaluateExpression,z as isPlainSymbol,S as parseExpression,q as registerTransformChartTypes,n as runTransform}; //# sourceMappingURL=openalgo-charts.transform.mjs.map