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 • 52.5 kB
JavaScript
function e(e,t){return Math.round(Math.round(e/t)*t*1e8)/1e8}function t(t,o,i){const r=e(t,i),l=e(o,i),n=[];for(let t=r;t<=l+i/2;t+=i)n.push(e(t,i));return n}function o(e,o,i=.7){const r=new Map;for(const i of e){const e=t(i.low,i.high,o),l=(i.volume??0)/e.length;for(const t of e)r.set(t,(r.get(t)??0)+l)}const l=Array.from(r.entries()).map(([e,t])=>({price:e,volume:t})).sort((e,t)=>t.price-e.price);if(0===l.length)return{buckets:l,poc:0,vah:0,val:0,totalVolume:0};const n=l.reduce((e,t)=>e+t.volume,0);let s=0;for(let e=1;e<l.length;e++)l[e].volume>l[s].volume&&(s=e);let a=s,c=s,h=l[s].volume;const u=n*i;for(;h<u&&(a>0||c<l.length-1);){(a>0?l[a-1].volume:-1)>=(c<l.length-1?l[c+1].volume:-1)?(a-=1,h+=l[a].volume):(c+=1,h+=l[c].volume)}return{buckets:l,poc:l[s].price,vah:l[a].price,val:l[c].price,totalVolume:n}}const i=19800;function r(e){const t=new Date(1e3*(e+i));return{year:t.getUTCFullYear(),month:t.getUTCMonth()+1,day:t.getUTCDate(),hour:t.getUTCHours(),minute:t.getUTCMinutes(),second:t.getUTCSeconds(),weekday:t.getUTCDay()}}const l="Asia/Kolkata",n=new Map,s={Sun:0,Mon:1,Tue:2,Wed:3,Thu:4,Fri:5,Sat:6};function a(e,t){const o=function(e){let t=n.get(e);if(void 0===t){let o;try{o=new Intl.DateTimeFormat("en-US",{timeZone:e,hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",weekday:"short"})}catch{throw new Error(`openalgo-charts: unknown IANA time zone "${e}"`)}t={format:o,parts:new Map,lastSecond:Number.NaN,lastParts:null},n.set(e,t)}return t}(t);if(e===o.lastSecond&&null!==o.lastParts)return o.lastParts;let i=o.parts.get(e);return void 0===i&&(i=function(e,t){let o=1970,i=1,r=1,l=0,n=0,a=0,c=4;for(const h of e.formatToParts(new Date(1e3*t)))switch(h.type){case"year":o=Number(h.value);break;case"month":i=Number(h.value);break;case"day":r=Number(h.value);break;case"hour":l=Number(h.value)%24;break;case"minute":n=Number(h.value);break;case"second":a=Number(h.value);break;case"weekday":c=s[h.value]??0}return{year:o,month:i,day:r,hour:l,minute:n,second:a,weekday:c,dayIndex:Math.floor(Date.UTC(o,i-1,r)/864e5)}}(o.format,e),o.parts.size>=4096&&o.parts.clear(),o.parts.set(e,i)),o.lastSecond=e,o.lastParts=i,i}function c(e,t=l){const o=a(e,t);return{year:o.year,month:o.month,day:o.day,hour:o.hour,minute:o.minute,second:o.second,weekday:o.weekday}}function h(e,t=l){return a(e,t).dayIndex}function u(e,t=l){const o=a(e,t);return Math.floor(Date.UTC(o.year,o.month-1,o.day,o.hour,o.minute,o.second)/1e3)-e}const d={tickSize:.05,session:"composite",valueAreaPercent:.7,deltaFromBarDirection:!0,timezone:l};function p(e,t,o){if("composite"===t)return 0;if("month"===t){const t=o===l?r(e):c(e,o);return 12*t.year+(t.month-1)}const n=o===l?Math.floor((e+i)/86400):h(e,o);return"day"===t?n:Math.floor((n+3)/7)}function m(e,o={}){const i={...d,...o},r=i.tickSize>0?i.tickSize:d.tickSize,n=Math.min(1,Math.max(0,i.valueAreaPercent)),s=i.timezone??l,a=new Map,c=[];for(const t of e){const e=p(t.time,i.session,s);let o=a.get(e);void 0===o&&(o=[],a.set(e,o),c.push(e)),o.push(t)}const h=[];for(const e of c){const o=a.get(e);if(0===o.length)continue;const l=new Map;let s=0,c=0,u=0;for(const e of o){const o=e.volume??0;s+=o;const n=e.close>=e.open,a=i.deltaFromBarDirection&&n?o:0,h=i.deltaFromBarDirection?n?0:o:0;c+=a,u+=h;const d=t(e.low,e.high,r),p=Math.max(1,d.length),m=o/p,f=a/p,b=h/p;for(const e of d){let t=l.get(e);void 0===t&&(t={volume:0,buy:0,sell:0},l.set(e,t)),t.volume+=m,t.buy+=f,t.sell+=b}}const d=Array.from(l.entries()).map(([e,t])=>({price:e,volume:t.volume,buyVolume:t.buy,sellVolume:t.sell,delta:t.buy-t.sell})).sort((e,t)=>t.price-e.price);if(0===d.length)continue;let p=0;for(let e=1;e<d.length;e++)d[e].volume>d[p].volume&&(p=e);let m=p,f=p,b=d[p].volume;const g=s*n;for(;b<g&&(m>0||f<d.length-1);){(m>0?d[m-1].volume:-1)>=(f<d.length-1?d[f+1].volume:-1)?(m-=1,b+=d[m].volume):(f+=1,b+=d[f].volume)}h.push({startTime:o[0].time,endTime:o[o.length-1].time,levels:d,poc:d[p].price,vah:d[m].price,val:d[f].price,totalVolume:s,buyVolume:c,sellVolume:u,delta:c-u})}return{sessions:h,options:{...i,timezone:s}}}const f={displayMode:"total",side:"right",width:90,opacity:.85,barColor:"#3b5168",buyColor:"#26a69a",sellColor:"#ef5350",showPoc:!0,pocColor:"#f0a020",showPocLabel:!0,showValueArea:!0,vahColor:"#8892a6",valColor:"#8892a6",showValueAreaLabels:!0,highlightValueArea:!0,valueAreaFillColor:"#4a6fa5",valueAreaFillOpacity:.08,valueAreaOpacityDim:.4,labelSide:"right",zOrder:"bottom"};class b{constructor(e=null,t={}){Object.defineProperty(this,"_result",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_opts",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_host",{enumerable:!0,configurable:!0,writable:!0,value:null}),this._result=e,this._opts={...f,...t}}attached(e){this._host=e}detached(){this._host=null}zOrder(){return this._opts.zOrder}autoscaleInfo(){if(null===this._result)return null;let e=1/0,t=-1/0;for(const o of this._result.sessions)0!==o.levels.length&&(t=Math.max(t,o.levels[0].price),e=Math.min(e,o.levels[o.levels.length-1].price));return Number.isFinite(e)?{min:e,max:t}:null}setData(e){this._result=e,this._host?.requestUpdate()}setOptions(e){this._opts={...this._opts,...e},this._host?.requestUpdate()}draw(e,t){if(null===this._result||0===this._result.sessions.length)return;const o=this._result.options.tickSize;for(const i of this._result.sessions)this._drawSession(e,t,i,o)}_segments(e,t,o){const i=this._opts;if("delta"===i.displayMode){const r=Math.abs(e.delta)/t*o;return[{color:e.delta>=0?i.buyColor:i.sellColor,len:r}]}const r=e.volume/t*o;if("buySell"===i.displayMode&&e.volume>0){const t=r*(e.buyVolume/e.volume);return[{color:i.buyColor,len:t},{color:i.sellColor,len:r-t}]}return[{color:i.barColor,len:r}]}_drawSession(e,t,o,i){const r=this._opts,l=t.dpr,n=t.dataLayer.timeToIndex(o.startTime),s=t.dataLayer.timeToIndex(o.endTime);if(void 0===n||void 0===s)return;const a=Math.round(t.timeScale.indexToX(n)*l),c=Math.max(a+1,Math.round(t.timeScale.indexToX(s)*l)),h=e=>t.priceScale.priceToY(e)*l,u=Math.max(1,Math.abs(t.priceScale.priceToY(o.poc)-t.priceScale.priceToY(o.poc+i))*l),d=r.width*l,p="right"===r.side?c:a;let m=0;for(const e of o.levels){const t="delta"===r.displayMode?Math.abs(e.delta):e.volume;t>m&&(m=t)}if(m<=0&&(m=1),e.save(),r.highlightValueArea){const t=h(o.vah)-u/2,i=h(o.val)+u/2,l="right"===r.side?c-d:a;e.globalAlpha=r.valueAreaFillOpacity,e.fillStyle=r.valueAreaFillColor,e.fillRect(l,t,d,i-t),e.globalAlpha=1}for(const t of o.levels){const i=t.price<=o.vah&&t.price>=o.val,l=r.opacity*(i?1:r.valueAreaOpacityDim),n=h(t.price)-u/2,s=Math.max(1,u-1);let a=p;e.globalAlpha=l;for(const o of this._segments(t,m,d)){if(o.len<=0)continue;const t="right"===r.side?a-o.len:a;e.fillStyle=o.color,e.fillRect(t,n,o.len,s),a="right"===r.side?a-o.len:a+o.len}}e.globalAlpha=1;const f=(t,o,i)=>{const n=Math.round(h(t))+.5;e.strokeStyle=o,e.lineWidth=Math.max(1,Math.round(l)),e.beginPath(),e.moveTo(a,n),e.lineTo(c,n),e.stroke(),""!==i&&(e.font=9*l+"px ui-sans-serif, system-ui, sans-serif",e.textBaseline="middle",e.fillStyle=o,"right"===r.labelSide?(e.textAlign="left",e.fillText(i,c+3*l,n)):(e.textAlign="right",e.fillText(i,a-3*l,n)))};r.showValueArea&&(f(o.vah,r.vahColor,r.showValueAreaLabels?`VAH ${t.priceScale.format(o.vah)}`:""),f(o.val,r.valColor,r.showValueAreaLabels?`VAL ${t.priceScale.format(o.val)}`:"")),r.showPoc&&f(o.poc,r.pocColor,r.showPocLabel?`POC ${t.priceScale.format(o.poc)}`:""),e.restore()}}function g(e,o,i,r=.7,l=2){const n=Math.max(1,o),s=new Map;let a=-1/0,c=1/0;const h=Math.ceil(e.length/n);for(let o=0;o<h;o++){const r=e.slice(o*n,(o+1)*n);if(0===r.length)continue;let h=-1/0,u=1/0;for(const e of r)h=Math.max(h,e.high),u=Math.min(u,e.low);o<l&&(a=Math.max(a,h),c=Math.min(c,u));for(const e of t(u,h,i))s.set(e,(s.get(e)??0)+1)}const u=Array.from(s.entries()).map(([e,t])=>({price:e,count:t})).sort((e,t)=>t.price-e.price);if(0===u.length)return{buckets:u,poc:0,vah:0,val:0,ib:{high:0,low:0}};const d=u.reduce((e,t)=>e+t.count,0);let p=0;for(let e=1;e<u.length;e++)u[e].count>u[p].count&&(p=e);let m=p,f=p,b=u[p].count;const g=d*r;for(;b<g&&(m>0||f<u.length-1);){(m>0?u[m-1].count:-1)>=(f<u.length-1?u[f+1].count:-1)?(m-=1,b+=u[m].count):(f+=1,b+=u[f].count)}return{buckets:u,poc:u[p].price,vah:u[m].price,val:u[f].price,ib:{high:a,low:c}}}const v={"all-hours":{startMinute:0,endMinute:0,name:"All Hours"},india:{startMinute:555,endMinute:930,zone:"Asia/Kolkata",name:"India"},asia:{startMinute:540,endMinute:900,zone:"Asia/Tokyo",name:"Asia"},london:{startMinute:420,endMinute:780,zone:"Europe/London",name:"London"},"new-york":{startMinute:480,endMinute:930,zone:"America/New_York",name:"New York"},"us-regular":{startMinute:570,endMinute:960,zone:"America/New_York",name:"US Regular"}},w={tickSize:.05,rowTicks:1,session:"day",blockMinutes:30,valueAreaPercent:.7,initialBalancePeriods:2,compositeSessions:1,tailEdges:0,timezone:l};function M(e,t){return e>0&&t>0?Math.max(1,Math.round(e/t)):1}function _(e){const t=(e%52+52)%52;return t<26?String.fromCharCode(65+t):String.fromCharCode(t-26+97)}const x=86400;function y(e,t){return e?.zone??t}function S(e,t){return t===l?r(e):c(e,t)}function T(e,t){if(t===l){const t=((e+i)%x+x)%x;return Math.floor(t/60)}const o=c(e,t);return 60*o.hour+o.minute}function k(e,t,o=l){if(t.startMinute===t.endMinute)return!0;const i=T(e,y(t,o));return t.startMinute<t.endMinute?i>=t.startMinute&&i<t.endMinute:i>=t.startMinute||i<t.endMinute}function P(e,t,o,i){const r=S(e,o),n=new Date(Date.UTC(r.year,r.month-1,r.day+i));return function(e,t,o,i=0,r=0,n=0,s=l){const a=Math.floor(Date.UTC(e,t-1,o,i,r,n)/1e3),c=a-u(a,s);return a-u(c,s)}(n.getUTCFullYear(),n.getUTCMonth()+1,n.getUTCDate(),Math.floor(t.startMinute/60),t.startMinute%60,0,o)}function C(e,t,o,r){if("composite"===t)return 0;if("month"===t){const t=S(e,o);return 12*t.year+(t.month-1)}let n=function(e,t){return t===l?Math.floor((e+i)/x):h(e,t)}(e,o);return void 0!==r&&r.startMinute>r.endMinute&&T(e,o)<r.endMinute&&(n-=1),"day"===t?n:Math.floor((n+3)/7)}function V(e,t){const o=e.reduce((e,t)=>e+t.count,0);let i=0;for(let t=1;t<e.length;t++)e[t].count>e[i].count&&(i=t);let r=i,l=i,n=e[i].count;const s=o*t;for(;n<s&&(r>0||l<e.length-1);){(r>0?e[r-1].count:-1)>=(l<e.length-1?e[l+1].count:-1)?(r-=1,n+=e[r].count):(l+=1,n+=e[l].count)}return{poc:e[i].price,vah:e[r].price,val:e[l].price}}function A(e,t,o){let i=0;for(let r=t;r>=0&&r<e.length&&1===e[r].count;r+=o)i++;return i}function R(e,t,o,i,r,l){const n=e.high-e.low,s=t-o;if(s<=0||n<=0)return"normal";if(i.up>0&&i.down>0)return"neutral";const a=r.findIndex(e=>e.price===l);if(a>=0&&r.length>=5){const e=r[a].count;let t=1/0,o=0;for(let e=0;e<r.length;e++){const i=Math.abs(e-a);i>1&&(o=Math.max(o,r[e].count)),i>0&&i<=Math.max(2,Math.floor(r.length/4))&&(t=Math.min(t,r[e].count))}if(o>=.7*e&&t<=.35*e)return"double-distribution"}const c=s/n;return c>=2.5?"trend":c>=1.4?"normal-variation":"normal"}function F(e,t,o,i,r){if(void 0===t)return"auction";const l=i-r;if(l<=0)return"auction";const n=t.high-t.low,s=(e-r)/l;if((s>.7||s<.3)&&n<=.35*l)return"drive";if(void 0!==o){const i=t.low<e-.25*n,r=t.high>e+.25*n;if(i&&o.high>t.high||r&&o.low<t.low)return"test-drive";if(r&&o.low<e||i&&o.high>e)return"rejection-reverse"}return"auction"}function O(e,o={}){const i={...w,...o},r=i.tickSize>0?i.tickSize:w.tickSize,n=Math.max(1,Math.floor(i.rowTicks)),s=r*n,a=Math.max(1,Math.round(60*i.blockMinutes)),c=Math.min(1,Math.max(0,i.valueAreaPercent)),h=Math.max(1,Math.floor(i.initialBalancePeriods)),u=Math.max(1,Math.floor(i.compositeSessions)),d=i.window,p=i.timezone??l,m=y(d,p),f=new Map,b=[];for(const t of e){if(void 0!==d&&!k(t.time,d,p))continue;const e=C(t.time,i.session,m,d);let o=f.get(e);void 0===o&&(o=[],f.set(e,o),b.push(e)),o.push(t)}const g=[];if(u>1&&"composite"!==i.session)for(let e=0;e<b.length;e+=u){const t=[];for(let o=e;o<Math.min(e+u,b.length);o++)t.push(...f.get(b[o]));g.push(t)}else for(const e of b)g.push(f.get(e));const v=[];for(const e of g){if(0===e.length)continue;const o=e[0].time;let r=o;if(void 0!==d&&d.startMinute!==d.endMinute){const e=P(o,d,m,0);r=e<=o?e:P(o,d,m,-1)}const l=new Map,n=new Map;let u=0,p=-1/0,f=1/0,b=0,g=-1/0,w=1/0;for(const o of e){const e=Math.max(0,Math.floor((o.time-r)/a));e>u&&(u=e),e<h&&(p=Math.max(p,o.high),f=Math.min(f,o.low)),g=Math.max(g,o.high),w=Math.min(w,o.low);const i=o.volume??0;b+=i;let c=n.get(e);void 0===c&&(c={index:e,letter:_(e),startTime:o.time,endTime:o.time,high:o.high,low:o.low,volume:0},n.set(e,c)),c.endTime=o.time,c.high=Math.max(c.high,o.high),c.low=Math.min(c.low,o.low),c.volume+=i;const d=t(o.low,o.high,s),m=i/Math.max(1,d.length);for(const t of d){let o=l.get(t);void 0===o&&(o={periods:new Set,volume:0},l.set(t,o)),o.periods.add(e),o.volume+=m}}const M=Array.from(n.values()).sort((e,t)=>e.index-t.index),x=Array.from(l.entries()).map(([e,t])=>{const o=Array.from(t.periods).sort((e,t)=>e-t);return{price:e,count:o.length,periods:o,volume:t.volume,letters:o.map(_).join("")}}).sort((e,t)=>t.price-e.price);if(0===x.length)continue;const y=V(x,c),S=[];for(const e of M){const t=[];for(const o of x){let i=0;for(const t of o.periods)t<=e.index&&i++;i>0&&t.push({price:o.price,count:i})}0!==t.length&&S.push({periodIndex:e.index,time:e.endTime,...V(t,c)})}const T=[];for(let e=1;e<x.length-1;e++)1===x[e].count&&T.push(x[e].price);let k=null,C=null;if(i.tailEdges>0){const e=A(x,0,1);e>=i.tailEdges&&(C={high:x[0].price,low:x[e-1].price});const t=A(x,x.length-1,-1);t>=i.tailEdges&&(k={high:x[x.length-t].price,low:x[x.length-1].price})}const O={high:Number.isFinite(p)?p:x[0].price,low:Number.isFinite(f)?f:x[x.length-1].price},D={up:Math.max(0,g-O.high),down:Math.max(0,O.low-w)};let N=x[0].price,z=-1;for(const e of x)e.volume>z&&(z=e.volume,N=e.price);v.push({startTime:o,endTime:e[e.length-1].time,label:d?.name,levels:x,poc:y.poc,vah:y.vah,val:y.val,high:g,low:w,open:e[0].open,close:e[e.length-1].close,periods:u+1,periodDetail:M,initialBalance:O,rangeExtension:D,singlePrints:T,buyingTail:k,sellingTail:C,poorHigh:x[0].count>1,poorLow:x[x.length-1].count>1,developing:S,dayType:R(O,g,w,D,x,y.poc),openType:F(e[0].open,M[0],M[1],g,w),volumePoc:N,totalVolume:b})}return{sessions:v,options:{...i,rowTicks:n,timezone:p}}}function D(e){const t=[],o=e.sessions,i=["poc","vah","val"];for(let e=0;e<o.length;e++)for(const r of i){const i=o[e][r];let l=!1;for(let t=e+1;t<o.length&&!l;t++)i<=o[t].high&&i>=o[t].low&&(l=!0);l||t.push({time:o[e].startTime,price:i,kind:r})}return t}function N(t,o){return e(t,o.tickSize*Math.max(1,Math.floor(o.rowTicks)))}const z=["25755","65656","34443","65556","74747","74744","34553","55755","72227","11152","55655","44447","57755","57555","25552","65644","25573","65655","34216","72222","55557","55552","55775","55255","55222","71247","03137","44656","03443","11353","02743","32722","03531","44655","20223","10152","44565","62223","07755","06555","02552","06564","03511","03444","03216","27223","05553","05552","05577","05225","05531","07127","75557","26227","61247","61216","55711","74616","34752","71222","25252","25716","57575"],I=new Map(Array.from("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#",(e,t)=>{const o=[];for(let e=0;e<5;e++){const i=Number(z[t][e]);for(let t=0;t<3;t++){if(!(i&4>>t))continue;const r=t;for(;t+1<3&&i&4>>t+1;)t++;o.push([r,e,t-r+1])}}return[e,o]}));function L(e,t,o,i,r,l,n="center"){if(0===t.length||!Number.isFinite(r)||!Number.isFinite(l))return!1;const s=4*t.length-1,a=Math.floor(Math.min(r/5,l/s)+1e-7);if(a<1)return!1;const c=s*a,h=Math.round(o-("center"===n?c/2:"right"===n?c:0)),u=Math.round(i-5*a/2);for(let o=0;o<t.length;o++){const i=I.get(t[o]);if(void 0!==i)for(const[t,r,l]of i)e.fillRect(h+(4*o+t)*a,u+r*a,l*a,a)}return!0}const j=["#e05555","#e08a3c","#d9c341","#8cc44a","#3fb96b","#38b2a3","#3b9fd1","#5a7fe0","#8a68d9","#c05fc4","#d1508f","#9b7b5a"],H={blockDisplay:"auto",minLetterHeight:7,letterFade:4,letterWidth:8,font:10,colorMode:"period",periodColors:j,color:"#5a6b8c",vaColor:"#4a8f7a",opacity:.92,outsideVaOpacity:.45,zOrder:"top",split:!1,showSessionOpen:!1,sessionOpenColor:"#5ca8ff",showLastPrice:!1,lastPriceColor:"#ff6b5e",profileSpacing:4,showPoc:!0,pocColor:"#f0a020",pocThickness:2,showPocLabel:!0,showValueArea:!0,vahColor:"#8892a6",valColor:"#8892a6",showValueAreaLabels:!0,fillValueArea:!0,valueAreaFillColor:"#4a8f7a",valueAreaFillOpacity:.07,showInitialBalance:!0,ibColor:"#c8853a",showSinglePrints:!0,singlePrintColor:"#e0556b",showTails:!0,buyTailColor:"#3fb96b",sellTailColor:"#e05555",showPoorHighLow:!1,poorColor:"#ffd966",showNakedLevels:!1,nakedColor:"#b0b0b0",showDevelopingPoc:!1,developingPocColor:"#ffffff",showDevelopingVa:!1,developingVaColor:"#888888",showTpoCounts:!1,countColor:"#8892a6",showSessionLabel:!0,showDayType:!1,showOpenType:!1,labelColor:"#cccccc",showVolumeProfile:!1,volumeProfileWidth:60,volumeProfileSide:"right",volumeColor:"#3b5168",showVolumeValues:!1},W={normal:"Normal","normal-variation":"Normal Var",trend:"Trend","double-distribution":"Double Dist",neutral:"Neutral"},E={drive:"Open-Drive","test-drive":"Open-Test-Drive","rejection-reverse":"Open-Rej-Rev",auction:"Open-Auction"};class B{constructor(e=null,t={}){Object.defineProperty(this,"_result",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_opts",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_host",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"_boxes",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"_rowH",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_rc",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"_sessionSplits",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),this._result=e,this._opts={...H,...t}}attached(e){this._host=e}detached(){this._host=null}zOrder(){return this._opts.zOrder}options(){return this._opts}autoscaleInfo(){if(null===this._result)return null;let e=1/0,t=-1/0;for(const o of this._result.sessions)0!==o.levels.length&&(t=Math.max(t,o.levels[0].price),e=Math.min(e,o.levels[o.levels.length-1].price));return Number.isFinite(e)?{min:e,max:t}:null}setData(e){this._result=e,this._boxes=[],this._host?.requestUpdate()}setOptions(e){this._opts={...this._opts,...e},void 0!==e.split&&this._sessionSplits.clear(),this._host?.requestUpdate()}isSessionSplit(e){const t=this._sessionKey(e);return null!==t&&(this._sessionSplits.get(t)??this._opts.split)}setSessionSplit(e,t){const o=this._sessionKey(e);return null!==o&&(null===t?this._sessionSplits.delete(o):this._sessionSplits.set(o,t),this._host?.requestUpdate(),!0)}_sessionKey(e){if(!Number.isInteger(e)||e<0||null===this._result)return null;const t=this._result.sessions[e];return void 0===t?null:function(e,t){const o=y(t.window,t.timezone??l);return[t.session,t.compositeSessions,o,t.window?.startMinute??"",t.window?.endMinute??"",C(e,t.session,o,t.window)].join("|")}(t.startTime,this._result.options)}hitTest(e,t){const o=this._boxes.find(t=>e>=t.x0&&e<=t.x1);return void 0===o?null:{externalId:`mp:${o.index}`,zOrder:"normal",distance:0,cursor:"crosshair"}}hoverAt(e,t,o){const i=o??this._rc;if(null===i||null===this._result)return null;const r=this._boxes.find(t=>e>=t.x0&&e<=t.x1);if(void 0===r)return null;const l=this._result.sessions[r.index];if(void 0===l)return null;let n=null,s=1/0;for(const e of l.levels){const o=Math.abs(i.priceScale.priceToY(e.price)-t);o<s&&o<=Math.max(4,this._rowH)&&(s=o,n=e)}return null===n?null:{sessionIndex:r.index,price:n.price,level:n,session:l,isPoc:n.price===l.poc,inValueArea:n.price<=l.vah&&n.price>=l.val,isSinglePrint:l.singlePrints.includes(n.price)}}draw(e,t){if(this._rc=t,this._boxes=[],null===this._result||0===this._result.sessions.length)return;const o=this._result.options,i=o.tickSize*Math.max(1,Math.floor(o.rowTicks)),r="compact"===this._opts.blockDisplay;r&&(e.save(),e.beginPath(),e.rect(0,0,Math.floor(t.plotWidth*t.dpr),Math.floor(t.plotHeight*t.dpr)),e.clip());for(let o=0;o<this._result.sessions.length;o++)this._drawSession(e,t,this._result.sessions[o],i,o);this._opts.showNakedLevels&&this._drawNaked(e,t),r&&e.restore()}_letterAlpha(e){const t=this._opts;if("compact"===t.blockDisplay||"letters"===t.blockDisplay||"blocks+letters"===t.blockDisplay)return 1;if("blocks"===t.blockDisplay)return 0;const o=Math.max(1,t.letterFade);return Math.max(0,Math.min(1,(e-t.minLetterHeight)/o))}_blockColor(e,t,o){const i=this._opts;return"period"===i.colorMode?i.periodColors[t%i.periodColors.length]:"valueArea"===i.colorMode&&e.price<=o.vah&&e.price>=o.val?i.vaColor:i.color}_drawSession(e,t,o,i,r){const l=this._opts,n=t.dpr,s="compact"===l.blockDisplay,a=this.isSessionSplit(r),c=t.dataLayer.timeToIndex(o.startTime),h=t.dataLayer.timeToIndex(o.endTime);if(void 0===c||void 0===h)return;const u=l.profileSpacing*n;let d=Math.round(t.timeScale.indexToX(c)*n)+u/2;const p=Math.max(d+1,Math.round(t.timeScale.indexToX(h)*n)-u/2),m=d<=t.plotWidth*n&&p>=0;this._boxes.push({index:r,x0:d/n,x1:p/n});const f=e=>t.priceScale.priceToY(e)*n,b=Math.max(1,Math.abs(t.priceScale.priceToY(o.poc)-t.priceScale.priceToY(o.poc+i))*n);this._rowH=b/n;const g=s&&b<12*n,v=Math.floor(Math.min(b,l.font*n)+1e-7),w=g?Math.max(1,Math.min(Math.round(l.letterWidth*n),4*Math.max(1,Math.floor(v/5)))):l.letterWidth*n;l.showSessionOpen&&(d+=w+3*n);const M=l.showLastPrice&&r===this._result.sessions.length-1,_=this._letterAlpha(b/n),x=!s&&("letters"!==l.blockDisplay||_<1);if(e.save(),l.fillValueArea&&p>d){const t=f(o.vah)-b/2,i=f(o.val)+b/2;e.globalAlpha=l.valueAreaFillOpacity,e.fillStyle=l.valueAreaFillColor,e.fillRect(d,t,p-d,i-t),e.globalAlpha=1}let y=1,S=0;for(const e of o.levels)e.count>y&&(y=e.count),e.volume>S&&(S=e.volume);l.showVolumeProfile&&S>0&&this._drawVolume(e,t,o,d,p,b,S);const T=Math.min(l.font*n,.95*b);_>0&&(e.font=`${T}px ui-monospace, SFMono-Regular, Menlo, monospace`,e.textBaseline="middle",e.textAlign="center");const k=Math.max(1,b-Math.min(1.5*n,.15*b)),P="count"===l.colorMode||"volume"===l.colorMode;for(const i of o.levels){const r=f(i.price);if(s&&(r+b/2<0||r-b/2>t.plotHeight*n))continue;const c=i.price<=o.vah&&i.price>=o.val?1:l.outsideVaOpacity,h="count"===l.colorMode?i.count/y:"volume"===l.colorMode&&S>0?i.volume/S:1,u=l.opacity*c*(P?.3+.7*h:1);for(let c=0;c<i.periods.length;c++){const m=a?i.periods[c]:c,f=d+m*w;if(f>p)break;if(s&&(f+w>p||f+w<0||f>t.plotWidth*n))continue;const b=this._blockColor(i,i.periods[c],o);x&&(e.globalAlpha=u,e.fillStyle=b,e.fillRect(f,r-k/2,Math.max(1,w-Math.min(1,.12*w)),k)),_>0&&(e.globalAlpha=s?l.opacity*(P?.3+.7*h:1):_*(x?.95:u),e.fillStyle=x?"#12151c":b,g?L(e,i.letters[c]??"",f+w/2,r,v,w-1)||e.fillRect(Math.round(f),Math.round(r),Math.max(1,Math.floor(w-1)),1):e.fillText(i.letters[c]??"",s?Math.round(f+w/2):f+w/2,s?Math.round(r):r))}}if(e.globalAlpha=1,l.showTpoCounts){e.font=`${Math.min((l.font-1)*n,b)}px ui-monospace, monospace`,e.textAlign="left",e.textBaseline="middle",e.fillStyle=l.countColor;const i=d+((a?o.periods:y)+(M?1:0))*w+3*n;for(const r of o.levels){const o=f(r.price);if(g){if(o+b/2<0||o-b/2>t.plotHeight*n)continue;L(e,String(r.count),i,o,v,Math.max(0,p-i),"left")}else e.fillText(String(r.count),i,o)}}if(l.showSinglePrints&&o.singlePrints.length>0){e.strokeStyle=l.singlePrintColor,e.lineWidth=Math.max(1,Math.round(n));for(const t of o.singlePrints){const o=Math.round(f(t))+.5;e.beginPath(),e.moveTo(d,o),e.lineTo(d+6*n,o),e.stroke()}}if(l.showTails){const t=(t,o)=>{if(null===t)return;e.fillStyle=o,e.globalAlpha=.75;const i=f(t.high)-b/2,r=f(t.low)+b/2;e.fillRect(d-4*n,i,3*n,r-i),e.globalAlpha=1};t(o.sellingTail,l.sellTailColor),t(o.buyingTail,l.buyTailColor)}if(l.showInitialBalance&&Number.isFinite(o.initialBalance.high)){const t=f(o.initialBalance.high),i=f(o.initialBalance.low),r=d-2*n;e.strokeStyle=l.ibColor,e.lineWidth=Math.max(1,Math.round(1.5*n)),e.beginPath(),e.moveTo(r,t),e.lineTo(r,i),e.moveTo(r,t),e.lineTo(r+5*n,t),e.moveTo(r,i),e.lineTo(r+5*n,i),e.stroke()}const C=(t,o,i,r=1)=>{const s=Math.round(f(t))+.5;e.strokeStyle=o,e.lineWidth=Math.max(1,Math.round(r*n)),e.beginPath(),e.moveTo(d,s),e.lineTo(p,s),e.stroke(),""!==i&&(e.font=(l.font-1)*n+"px ui-sans-serif, system-ui, sans-serif",e.textBaseline="middle",e.textAlign="left",e.fillStyle=o,e.fillText(i,p+3*n,s))};l.showValueArea&&(C(o.vah,l.vahColor,l.showValueAreaLabels?`VAH ${t.priceScale.format(o.vah)}`:""),C(o.val,l.valColor,l.showValueAreaLabels?`VAL ${t.priceScale.format(o.val)}`:"")),l.showPoc&&C(o.poc,l.pocColor,l.showPocLabel?`POC ${t.priceScale.format(o.poc)}`:"",l.pocThickness),l.showPoorHighLow&&(o.poorHigh&&C(o.high,l.poorColor,"Poor High"),o.poorLow&&C(o.low,l.poorColor,"Poor Low")),l.showDevelopingPoc&&this._drawDeveloping(e,t,o,"poc",l.developingPocColor),l.showDevelopingVa&&(this._drawDeveloping(e,t,o,"vah",l.developingVaColor),this._drawDeveloping(e,t,o,"val",l.developingVaColor));const V=this._result;if(l.showSessionOpen&&this._drawPriceMarker(e,t,"o",d-w/2-3*n,f(N(o.open,V.options)),b,l.sessionOpenColor),M&&m){const i=N(o.close,V.options),r=o.levels.find(e=>e.price===i);if(void 0!==r){const o=a?(r.periods[r.periods.length-1]??0)+1:r.count,s=Math.max(2,w/2),c=Math.max(s,Math.min(d+(o+.5)*w,t.plotWidth*n-s));this._drawPriceMarker(e,t,"#",c,f(i),b,l.lastPriceColor)}}const A=[];l.showSessionLabel&&void 0!==o.label&&A.push(o.label),l.showDayType&&A.push(W[o.dayType]??o.dayType),l.showOpenType&&A.push(E[o.openType]??o.openType),A.length>0&&(e.font=(l.font-1)*n+"px ui-sans-serif, system-ui, sans-serif",e.textAlign="left",e.textBaseline="bottom",e.fillStyle=l.labelColor,e.fillText(A.join(" · "),d,f(o.high)-b)),e.restore()}_drawPriceMarker(e,t,o,i,r,l,n){const s=Math.max(5,Math.min(l,this._opts.font*t.dpr));e.save(),e.globalAlpha=this._opts.opacity,e.fillStyle=n,l<12*t.dpr?L(e,o,i,r,s,Math.max(3,s)):(e.font=`${s}px ui-monospace, SFMono-Regular, Menlo, monospace`,e.textAlign="center",e.textBaseline="middle",e.fillText(o,Math.round(i),r)),e.restore()}_drawVolume(e,t,o,i,r,l,n){const s=this._opts,a=t.dpr,c=s.volumeProfileWidth*a,h="right"===s.volumeProfileSide,u="compact"===s.blockDisplay,d=e=>!u||e+l/2>=0&&e-l/2<=t.plotHeight*a;e.globalAlpha=.55,e.fillStyle=s.volumeColor;for(const s of o.levels){if(!d(t.priceScale.priceToY(s.price)*a))continue;const o=c*(s.volume/n),u=t.priceScale.priceToY(s.price)*a-l/2;e.fillRect(h?r-o:i,u,o,Math.max(1,l-1))}if(e.globalAlpha=1,s.showVolumeValues&&l>=(u?5-1e-7:7*a)){e.font=`${Math.min(9*a,.9*l)}px ui-monospace, monospace`,e.textBaseline="middle",e.textAlign=h?"right":"left",e.fillStyle=s.countColor;for(const n of o.levels){const o=t.priceScale.priceToY(n.price)*a;if(!d(o))continue;const s=Math.round(n.volume).toString(),p=h?r-2*a:i+2*a;u&&l<12*a?L(e,s,p,o,Math.min(l,9*a),Math.max(0,c-4*a),h?"right":"left"):e.fillText(s,p,o)}}}_drawDeveloping(e,t,o,i,r){if(0===o.developing.length)return;const l=t.dpr;e.save(),e.strokeStyle=r,e.lineWidth=Math.max(1,Math.round(l)),e.beginPath();let n=!1;for(const r of o.developing){const o=t.dataLayer.timeToIndex(r.time);if(void 0===o)continue;const s=t.timeScale.indexToX(o)*l,a=Math.round(t.priceScale.priceToY(r[i])*l)+.5;n?e.lineTo(s,a):(e.moveTo(s,a),n=!0)}n&&e.stroke(),e.restore()}_drawNaked(e,t){const o=this._opts,i=t.dpr,r=D(this._result);if(0===r.length)return;e.save(),e.strokeStyle=o.nakedColor,e.lineWidth=Math.max(1,Math.round(i)),e.setLineDash([4*i,3*i]);const l=t.plotWidth*i;for(const o of r){const r=t.dataLayer.timeToIndex(o.time);if(void 0===r)continue;const n=Math.round(t.priceScale.priceToY(o.price)*i)+.5;e.beginPath(),e.moveTo(t.timeScale.indexToX(r)*i,n),e.lineTo(l,n),e.stroke()}e.setLineDash([]),e.restore()}}function Y(t,o,i,r=1){const l=U(i,r);if(!Number.isFinite(t))throw new RangeError("Footprint time must be finite");for(const e of o)$(e);const n=new Map;let s=0,a=0,c=0;for(const t of o){const o=e(t.price,l);let i=n.get(o);void 0===i&&(i={price:o,bidVol:0,askVol:0},n.set(o,i)),"bid"===t.side?(i.bidVol+=t.qty,s-=t.qty):(i.askVol+=t.qty,s+=t.qty),a=Math.min(a,s),c=Math.max(c,s)}const h={time:t,cells:Array.from(n.values()).sort((e,t)=>t.price-e.price),delta:s,minDelta:a,maxDelta:c,rowSize:l,tradeCount:o.length};if(o.length>0){h.open=o[0].price,h.close=o[o.length-1].price,h.high=h.low=o[0].price;for(const e of o)h.high=Math.max(h.high,e.price),h.low=Math.min(h.low,e.price)}return h}function U(e,t){if(!Number.isFinite(e)||e<=0)throw new RangeError("Footprint tickSize must be positive and finite");if(!Number.isSafeInteger(t)||t<1)throw new RangeError("Footprint rowTicks must be a positive integer");const o=e*t;if(!Number.isFinite(o))throw new RangeError("Footprint tickSize * rowTicks must be finite");return o}function $(e){if(!Number.isFinite(e.price))throw new RangeError("Footprint trade price must be finite");if(!Number.isFinite(e.qty)||e.qty<0)throw new RangeError("Footprint trade qty must be nonnegative and finite");if("bid"!==e.side&&"ask"!==e.side)throw new TypeError("Footprint trade side must be bid or ask")}function q(e){let t=1/0;for(let o=1;o<e.length;o++){const i=e[o-1].price-e[o].price;i>0&&(t=Math.min(t,i))}return t}function K(e,t,o){const i=Math.max(1e-7*o,Math.max(Math.abs(e),Math.abs(t))*Number.EPSILON*8);return Number.isFinite(o)&&e>t&&Math.abs(e-t-o)<=i}function X(e,t=3,o,i=0){if(!Number.isFinite(t)||t<=0)throw new RangeError("Imbalance ratio must be positive and finite");if(void 0!==o&&(!Number.isFinite(o)||o<=0))throw new RangeError("Imbalance rowSize must be positive and finite");if(!Number.isFinite(i)||i<0)throw new RangeError("Imbalance threshold must be nonnegative and finite");const r=[...e].sort((e,t)=>t.price-e.price),l=o??q(r),n=(e,o)=>e>0&&e>=i&&e>=t*o,s=[];for(let e=0;e<r.length;e++){const t=r[e],o=r[e+1],i=r[e-1];o&&K(t.price,o.price,l)&&n(t.askVol,o.bidVol)&&s.push({price:t.price,side:"buy"}),i&&K(i.price,t.price,l)&&n(t.bidVol,i.askVol)&&s.push({price:t.price,side:"sell"})}return s}function Z(e){const t=[];let o=0;for(const i of e)o+=i.delta,t.push(o);return t}function G(e,t=3,o=3,i,r=0){if(!Number.isSafeInteger(o)||o<1)throw new RangeError("Imbalance minStack must be a positive integer");const l=[...e].sort((e,t)=>t.price-e.price),n=X(l,t,i,r),s=i??q(l),a=[];for(const e of["buy","sell"]){const t=new Set(n.filter(t=>t.side===e).map(e=>e.price));let i;const r=()=>{i&&i.count>=o&&a.push(i),i=void 0};for(const o of l)t.has(o.price)?(i&&!K(i.endPrice,o.price,s)&&r(),i?(i.endPrice=o.price,i.count++):i={startPrice:o.price,endPrice:o.price,side:e,count:1}):r();r()}return a.sort((e,t)=>t.startPrice-e.startPrice)}class J{constructor(e){Object.defineProperty(this,"_opts",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_host",{enumerable:!0,configurable:!0,writable:!0,value:null}),this._opts=e}attached(e){this._host=e}detached(){this._host=null}zOrder(){return"bottom"}autoscaleInfo(){return null}setData(e){this._opts=e,this._host?.requestUpdate()}draw(e,t){const o=this._opts;if(0===o.buckets.length)return;const i=t.dpr,r=o.buckets.reduce((e,t)=>Math.max(e,t.value),0)||1,l=o.width*i,n="left"===o.side?0:t.plotWidth*i,s=Math.max(2*i,t.plotHeight*i/Math.max(1,o.buckets.length)-i);e.save();for(const a of o.buckets){const c=t.priceScale.priceToY(a.price)*i,h=l*(a.value/r),u=a.price<=o.vah&&a.price>=o.val;e.fillStyle=a.price===o.poc?"#f0a020":u?o.vaColor:o.barColor;const d="left"===o.side?n:n-h;e.fillRect(d,c-s/2,h,s)}for(const[r,l]of[[o.poc,"#f0a020"],[o.vah,"#5a6b8c"],[o.val,"#5a6b8c"]]){const o=Math.round(t.priceScale.priceToY(r)*i)+.5;e.strokeStyle=l,e.lineWidth=Math.max(1,Math.round(i)),e.beginPath(),e.moveTo(0,o),e.lineTo(t.plotWidth*i,o),e.stroke()}e.restore()}}function Q(e){const t=e.trim();if(t.startsWith("#")){const e=t.slice(1);if(3===e.length||4===e.length){const[t,o,i,r]=[...e].map(e=>parseInt(e+e,16));return[t,o,i].some(Number.isNaN)?null:{r:t,g:o,b:i,a:4===e.length?r/255:1}}if(6===e.length||8===e.length){const t=parseInt(e.slice(0,6),16);if(Number.isNaN(t))return null;const o=8===e.length?parseInt(e.slice(6,8),16)/255:1;return{r:t>>16&255,g:t>>8&255,b:255&t,a:Number.isNaN(o)?1:o}}return null}const o=/^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*(?:,\s*([\d.]+)\s*)?\)$/i.exec(t);return null===o?null:{r:Number(o[1]),g:Number(o[2]),b:Number(o[3]),a:void 0===o[4]?1:Number(o[4])}}function ee(e){return`rgb(${Math.round(e.r)},${Math.round(e.g)},${Math.round(e.b)})`}function te(e,t,o){return{r:e.r+(t.r-e.r)*o,g:e.g+(t.g-e.g)*o,b:e.b+(t.b-e.b)*o,a:1}}function oe(e){const t=e=>{const t=Math.max(0,Math.min(255,e))/255;return t<=.04045?t/12.92:((t+.055)/1.055)**2.4};return.2126*t(e.r)+.7152*t(e.g)+.0722*t(e.b)}function ie(e,t){const o=Q(t);if(!o)return e;const i=oe(o),r=e=>{const t=oe(e);return(Math.max(t,i)+.05)/(Math.min(t,i)+.05)},l=(i+.05)/.05>=1.05/(i+.05)?0:255,n={r:l,g:l,b:l},s=Q(e);if(!s)return ee(n);const a=te(o,s,Math.max(0,Math.min(1,s.a)));if(r(a)>=4.5)return e;let c=0,h=1,u=n;for(let e=0;e<10;e++){const e=(c+h)/2,t=te(a,n,e),o={r:Math.round(t.r),g:Math.round(t.g),b:Math.round(t.b),a:1};r(o)>=4.5?(h=e,u=o):c=e}return ee(u)}const re={widthFactor:.9,font:10,minTextHeight:11,textFade:4,displayMode:"bidask",volumeDivisor:1,cellStyle:"heatmap",textColorMode:"contrast",imbalanceRatio:3,imbalanceThreshold:0,stackedImbalances:3,statsRows:[],tableRows:[],tableLabelWidth:150,statsRowHeight:15,statsPosition:"bottom",cvdOffset:0,showCandle:!0,showPoc:!0,pocStyle:"marker",pocColor:"#f0a020",showValueArea:!1,valueAreaPercent:.7,radius:2};function le(e){if(!Number.isFinite(e))return"—";const t=Number(e.toPrecision(3)),o=Math.abs(t),[i,r]=o>=1e9?["B",1e9]:o>=1e6?["M",1e6]:o>=1e3?["K",1e3]:["",1];return String(Number((t/r).toPrecision(3)))+i}function ne(e,t,o){const i=Q(e),r=Q(t);if(null===i||null===r)return t;const l=Math.max(0,Math.min(1,o));return`rgb(${Math.round(i.r+(r.r-i.r)*l)},${Math.round(i.g+(r.g-i.g)*l)},${Math.round(i.b+(r.b-i.b)*l)})`}const se={volume:"Volume",bidVolume:"Bid Volume",askVolume:"Ask Volume",delta:"Delta",minDelta:"Min Delta",maxDelta:"Max Delta",deltaPct:"Delta %",cvd:"CVD",trades:"Trades"},ae={...se,volume:"Total Volume",bidVolume:"Total Bid Volume",askVolume:"Total Ask Volume",cvd:"Cumulative Delta"};class ce{constructor(e={}){Object.defineProperty(this,"_bars",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"_opts",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_host",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"_stats",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"_cols",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"_rc",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"_inferredStep",{enumerable:!0,configurable:!0,writable:!0,value:0}),this._opts={...re,...e,statsRows:[...e.statsRows??re.statsRows],tableRows:[...e.tableRows??[]]},this._validateOptions(this._opts)}attached(e){this._host=e}detached(){this._host=null,this._rc=null,this._cols=[]}zOrder(){return"normal"}_validateOptions(e){for(const t of[e.widthFactor,e.font,e.statsRowHeight,e.tableLabelWidth,e.imbalanceRatio,e.volumeDivisor])if(!Number.isFinite(t)||t<=0)throw new RangeError("Footprint dimensions and ratio must be positive and finite");for(const t of[e.radius,e.minTextHeight,e.textFade,e.imbalanceThreshold])if(!Number.isFinite(t)||t<0)throw new RangeError("Footprint thresholds and radius must be nonnegative and finite");for(const t of[e.cellWidth,e.tickSize])if(void 0!==t&&(!Number.isFinite(t)||t<=0))throw new RangeError("Footprint width and row step must be positive and finite");if(!Number.isSafeInteger(e.stackedImbalances)||e.stackedImbalances<0)throw new RangeError("Footprint stack length must be a nonnegative integer");if(!Number.isFinite(e.cvdOffset))throw new RangeError("Footprint CVD offset must be finite");if(!Number.isFinite(e.valueAreaPercent)||e.valueAreaPercent<=0||e.valueAreaPercent>1)throw new RangeError("Footprint value area must be in (0, 1]");for(const t of[e.statsRows,e.tableRows])if(t.some(e=>!Object.prototype.hasOwnProperty.call(se,e))||new Set(t).size!==t.length)throw new RangeError("Footprint statistics rows must be known and unique")}setBars(e){this._bars=e.map(e=>({...e,cells:e.cells.map(e=>({...e})).sort((e,t)=>t.price-e.price)}));let t=1/0;for(const e of this._bars){void 0!==e.rowSize&&e.rowSize>0&&(t=Math.min(t,e.rowSize));for(let o=1;o<e.cells.length;o++){const i=e.cells[o-1].price-e.cells[o].price;i>0&&(t=Math.min(t,i))}}this._inferredStep=Number.isFinite(t)?t:0,this._cols=[],this._recomputeStats(),this._host?.requestUpdate()}setOptions(e){const t={...this._opts,...e};this._validateOptions(t),this._opts={...t,statsRows:[...t.statsRows],tableRows:[...t.tableRows]},this._cols=[],void 0===e.cvdOffset&&void 0===e.valueAreaPercent||this._recomputeStats(),this._host?.requestUpdate()}options(){return{...this._opts,statsRows:[...this._opts.statsRows],tableRows:[...this._opts.tableRows]}}stats(){return this._stats}_step(e){return this._opts.tickSize??e.rowSize??this._inferredStep}autoscaleInfo(){let e=1/0,t=-1/0;for(const o of this._bars){const i=this._step(o)/2;for(const r of o.cells)e=Math.min(e,r.price-i),t=Math.max(t,r.price+i);this._opts.showCandle&&(void 0!==o.low&&(e=Math.min(e,o.low)),void 0!==o.high&&(t=Math.max(t,o.high)))}return Number.isFinite(e)?{min:e,max:t}:null}_recomputeStats(){let e=this._opts.cvdOffset;this._stats=this._bars.map(t=>{const o=t.cells.map(e=>e.bidVol+e.askVol),i=o.reduce((e,t)=>e+t,0),r=t.cells.reduce((e,t)=>e+t.bidVol,0),l=t.cells.reduce((e,t)=>e+t.askVol,0);let n=0;for(let e=1;e<o.length;e++)o[e]>o[n]&&(n=e);let s=n,a=n,c=o[n]??0;for(;c<i*this._opts.valueAreaPercent&&(s>0||a<o.length-1);)(s>0?o[s-1]:-1)>=(a<o.length-1?o[a+1]:-1)?c+=o[--s]:c+=o[++a];return e+=t.delta,{time:t.time,volume:i,bidVolume:r,askVolume:l,delta:t.delta,minDelta:t.minDelta??null,maxDelta:t.maxDelta??null,deltaPct:i>0?t.delta/i*100:0,cvd:e,trades:t.tradeCount??null,poc:t.cells[n]?.price??0,vah:t.cells[s]?.price??0,val:t.cells[a]?.price??0}})}_bounds(e,t,o){const i=o.priceScale.priceToY(e);if(!(t>0))return{top:i-8,bottom:i+8};const r=o.priceScale.priceToY(e-t/2),l=o.priceScale.priceToY(e+t/2);return{top:Math.min(r,l),bottom:Math.max(r,l)}}draw(e,t){if(this._rc=t,this._cols=[],0===this._bars.length||t.plotHeight<=0||t.plotWidth<=0)return;const o=this._opts,i=t.dpr,r=o.buyColor??t.theme.upColor,l=o.sellColor??t.theme.downColor,n=t.theme.background,s=t.timeScale.barSpacing,a=Math.max(.1,Math.min(o.cellWidth??s*o.widthFactor,.96*s)),c=o.showCandle&&a>=20?Math.min(9,.15*a):0,h=Math.max(.1,a-c),u=o.tableRows.length?o.tableRows:"bottom"===o.statsPosition?o.statsRows:[],d=Math.min(t.plotHeight,u.length*o.statsRowHeight),p=t.plotHeight-d,m=t.timeScale.visibleRange();for(let e=0;e<this._bars.length;e++){const o=this._bars[e];if(!o.cells.length)continue;const i=t.dataLayer.timeToIndex(o.time);if(void 0===i||i<m.from-1||i>m.to+1)continue;const r=t.timeScale.indexToX(i)-a/2+c;r+h<0||r>t.plotWidth||this._cols.push({bar:o,stats:this._stats[e],x:r+h/2,x0:r,width:h,rowSize:this._step(o),rows:[]})}e.save(),e.beginPath(),e.rect(0,0,t.plotWidth*i,t.plotHeight*i),e.clip(),e.textBaseline="middle",e.save(),e.beginPath(),e.rect(0,0,t.plotWidth*i,p*i),e.clip();for(const o of this._cols)this._drawColumn(e,t,o,c,r,l,n,p);if(e.restore(),o.statsRows.length&&"bar"===o.statsPosition)for(const o of this._cols)this._drawCard(e,t,o,r,l,n,p);u.length&&this._drawFooter(e,t,r,l,n,d,u),e.restore()}_drawColumn(e,t,o,i,r,l,n,s){const a=this._opts,c=t.dpr,{bar:h,stats:u}=o,d=o.width*c,p=d/2,m=o.x0*c,f=o.x*c,b=X(h.cells,a.imbalanceRatio,o.rowSize||void 0,a.imbalanceThreshold),g=new Set(b.filter(e=>"buy"===e.side).map(e=>e.price)),v=new Set(b.filter(e=>"sell"===e.side).map(e=>e.price));let w=0,M=0;for(const e of h.cells)w=Math.max(w,"volume"===a.displayMode?e.bidVol+e.askVol:"delta"===a.displayMode?Math.abs(e.askVol-e.bidVol):Math.max(e.bidVol,e.askVol)),M=Math.max(M,"bidask"===a.displayMode?Math.max(e.bidVol,e.askVol):e.bidVol+e.askVol);i>0&&this._drawCandle(e,t,o,i,r,l);for(const i of h.cells){const h=this._bounds(i.price,o.rowSize,t);if(h.bottom<=0||h.top>=s)continue;o.rows.push({cell:i,top:Math.max(0,h.top),bottom:Math.min(s,h.bottom)});const b=h.top*c,_=(h.bottom-h.top)*c,x=Math.max(0,_-Math.min(c,.1*_)),y=Math.max(0,Math.min(1,(h.bottom-h.top-a.minTextHeight)/Math.max(1,a.textFade)+1));if(e.font=a.font*c+"px ui-monospace, SFMono-Regular, Menlo, monospace","bidask"===a.displayMode){const o=Math.min(c,.08*p),s=p-o;this._cell(e,t,i,m,b,s,x,i.bidVol,w,M,l,r,l,n,v.has(i.price),y,"bid"),this._cell(e,t,i,f+o,b,s,x,i.askVol,w,M,r,r,l,n,g.has(i.price),y,"ask")}else{const o="delta"===a.displayMode?i.askVol-i.bidVol:i.bidVol+i.askVol,s=i.askVol-i.bidVol;this._cell(e,t,i,m,b,d,x,o,w,M,s>0?r:s<0?l:ne(r,l,.5),r,l,n,s>0?g.has(i.price):s<0&&v.has(i.price),y,"single")}a.showPoc&&i.price===u.poc&&("outline"===a.pocStyle?(e.strokeStyle=a.pocColor,e.lineWidth=Math.max(1,c),e.strokeRect(m,b+c/2,d,Math.max(0,x-c))):(e.fillStyle=a.pocColor,e.fillRect(m-2*c,b,2*c,x)))}if(a.showValueArea&&u.volume>0){const i=this._bounds(u.vah,o.rowSize,t),r=this._bounds(u.val,o.rowSize,t);e.strokeStyle=a.valueAreaColor??t.theme.axisText,e.lineWidth=c,e.beginPath();for(const t of[Math.min(i.top,r.top),Math.max(i.bottom,r.bottom)])e.moveTo(m,t*c),e.lineTo(m+d,t*c);e.stroke()}if(a.stackedImbalances>0&&o.width>=16){const i=G(h.cells,a.imbalanceRatio,a.stackedImbalances,o.rowSize||void 0,a.imbalanceThreshold);for(const n of i){const i=this._bounds(n.startPrice,o.rowSize,t),s=this._bounds(n.endPrice,o.rowSize,t),a=Math.min(i.top,s.top)*c,h=Math.max(i.bottom,s.bottom)*c,u=("buy"===n.side?o.x0+o.width-1:o.x0+1)*c,d=("buy"===n.side?-3:3)*c;e.strokeStyle="buy"===n.side?r:l,e.lineWidth=c,e.beginPath(),e.moveTo(u+d,a),e.lineTo(u,a),e.lineTo(u,h),e.lineTo(u+d,h),e.stroke()}}}_drawCandle(e,t,o,i,r,l){const n=o.bar,s=t.dpr,a=(o.x0-i/2)*s,c=Math.min(4,.45*i)*s,h=n.high??n.cells[0].price,u=n.low??n.cells[n.cells.length-1].price,d=t.priceScale.priceToY(h)*s,p=t.priceScale.priceToY(u)*s,m=void 0!==n.open&&void 0!==n.close,f=m?n.close>=n.open?r:l:t.theme.axisText;if(e.fillStyle=f,e.fillRect(a,Math.min(d,p),s,Math.max(s,Math.abs(p-d))),m){const o=t.priceScale.priceToY(n.open)*s,i=t.priceScale.priceToY(n.close)*s;e.fillRect(a-c/2,Math.min(o,i),c,Math.max(s,Math.abs(i-o)))}}_cell(e,t,o,i,r,l,n,s,a,c,h,u,d,p,m,f,b){if(l<=0||n<=0)return;const g=this._opts,v=t.dpr,w="profile"===g.cellStyle,M=Math.max(0,Math.min(1,a>0?Math.abs(s)/a:0)),_=m?h:ne(p,h,"ladder"===g.cellStyle?.18+.82*Math.sqrt(M):.08+.62*Math.sqrt(M)),x=w?l*M:l,y=w&&"bid"===b?i+l-x:i;if(x>0&&(e.fillStyle=_,e.beginPath(),e.roundRect(y,r,x,n,"ladder"===g.cellStyle||w?0:Math.min(g.radius*v,n/2,x/2)),e.fill()),f<=0||n<g.font*v*.6)return;const S=le(s/g.volumeDivisor),T=e.measureText(S).width;if(T+4*v>l)return;e.textAlign=w&&"single"!==b?"bid"===b?"right":"left":"center";const k=w&&"single"!==b?"bid"===b?i+l-2*v:i+2*v:i+l/2,P="right"===e.textAlign?k-T:"left"===e.textAlign?k:k-T/2,C=P+T;let V=_;w&&(0===x||C<=y||P>=y+x?V=p:(P<y||C>y+x)&&(V=p,e.fillStyle=p,e.fillRect(P-v,r,T+2*v,n)));const A=g.textColor??ie(t.theme.axisText,p),R=function(e){const{mode:t,side:o,bidVol:i,askVol:r,neutral:l,buy:n,sell:s}=e,a=r>i?n:i>r?s:l,c="ask"===o?n:"bid"===o?s:a;let h=l;switch(t){case"contrast":break;case"side":h=c;break;case"delta":h=a;break;case"dominant":("single"===o||"ask"===o&&r>i||"bid"===o&&i>r)&&(h=a);break;case"imbalance":e.hot&&(h=c);break;case"volume":{const t="ask"===o?r:"bid"===o?i:r+i,n=e.peak>0?Math.max(0,Math.min(1,t/e.peak)):0;if(n>=1)h=c;else if(n>0&&c!==l){const e=Q(l),t=Q(c);e&&t&&(h=ee(te(e,t,n)))}break}}return ie(Q(h)?h:l,e.background)}({mode:g.textColorMode,side:b,bidVol:o.bidVol,askVol:o.askVol,peak:c,hot:m,neutral:A,buy:g.buyTextColor??u,sell:g.sellTextColor??d,background:V});e.fillStyle=function(e,t){const o=Q(e);return null===o?e:`rgba(${o.r},${o.g},${o.b},${t})`}(R,f),e.fillText(S,k,r+n/2)}_drawCard(e,t,o,i,r,l,n){const s=this._opts,a=t.dpr;if(o.width<68||0===o.rows.length)return;let c=-1/0;for(const e of o.bar.cells)c=Math.max(c,this._bounds(e.price,o.rowSize,t).bottom);if(s.showCandle)for(const e of[o.bar.high,o.bar.low])void 0!==e&&(c=Math.max(c,t.priceScale.priceToY(e)));const h=c+8,u=s.statsRows.length*s.statsRowHeight+8;if(h<0||h+u>n)return;o.card={top:h,bottom:h+u};const d=ne(l,t.theme.axisText,.13);e.fillStyle=d,e.beginPath(),e.roundRect(o.x0*a,h*a,o.width*a,u*a,2*a),e.fill(),e.font=Math.max(8,s.font-1)*a+"px ui-monospace, SFMono-Regular, Menlo, monospace",s.statsRows.forEach((l,n)=>{const c=this._metric(o.stats,l),u=this._statText(c,l),p=(h+4+(n+.5)*s.statsRowHeight)*a,m=se[l];e.measureText(m).width+e.measureText(u).width+12*a>o.width*a||(e.textAlign="left",e.fillStyle=ie(s.textColor??t.theme.axisText,d),e.fillText(m,(o.x0+4)*a,p),e.textAlign="right",e.fillStyle=ie(this._statColor(l,c,s.textColor??t.theme.axisText,s.buyTextColor??i,s.sellTextColor??r),d),e.fillText(u,(o.x0+o.width-4)*a,p))})}_drawFooter(e,t,o,i,r,l,n){const s=this._opts,a=t.dpr,c=t.plotHeight-l,h=Math.min(s.tableLabelWidth,t.plotWidth);e.fillStyle=r,e.fillRect(0,c*a,t.plotWidth*a,l*a),e.font=Math.max(8,s.font-.5)*a+"px ui-monospace, SFMono-Regular, Menlo, monospace",e.textAlign="center";const u=t.timeScale.barSpacing;for(const e of this._cols){const o=t.timeScale.indexToX(t.dataLayer.timeToIndex(e.bar.time)),i=Math.max(h,o-u/2),r=Math.min(t.plotWidth,o+u/2);i<r&&(e.table={left:i,right:r,top:c,bottom:t.plotHeight})}e.save(),e.beginPath(),e.rect(h*a,c*a,(t.plotWidth-h)*a,l*a),e.clip(),n.forEach((l,n)=>{let h=1;for(const e of this._cols)e.table&&(h=Math.max(h,Math.abs(this._metric(e.stats,l)??0)));for(const d of this._cols){if(!d.table)continue;const p=this._metric(d.stats,l),m=p??0,f=ne(r,this._statColor(l,p,t.theme.axisText,o,i),.1+.4*Math.abs(m)/h),b=t.timeScale.indexToX(t.dataLayer.timeToIndex(d.bar.time)),g=(c+n*s.statsRowHeight)*a;e.fillStyle=f,e.fillRect((b-u/2)*a,g+a,Math.max(0,u*a-a),Math.max(0,s.statsRowHeight*a-a));const v=this._statText(p,l),w=e.measureText(v).width/(2*a)+2;b-w<d.table.left||b+w>d.table.right||(e.fillStyle=ie(s.textColor??t.theme.axisText,f),e.fillText(v,b*a,g+s.statsRowHeight*a/2))}}),e.restore(),e.save(),e.beginPath(),e.rect(0,c*a,h*a,l*a),e.clip();const d=ne(r,t.theme.axisText,.09);e.fillStyle=d,e.fillRect(0,c*a,h*a,l*a),e.fillStyle=ie(s.textColor??t.theme.axisText,d),e.textAlign="left",n.forEach((t,o)=>e.fillText(ae[t],6*a,(c+(o+.5)*s.statsRowHeight)*a)),e.restore(),e.strokeStyle=ne(r,t.theme.axisText,.25),e.lineWidth=a,e.beginPath();for(let o=0;o<=n.length;o++){const i=(c+o*s.statsRowHeight)*a;e.moveTo(0,i),e.lineTo(t.plotWidth*a,i)}e.moveTo(h*a,c*a),e.lineTo(h*a,t.plotHeight*a),e.stroke()}_statColor(e,t,o,i,r){return null===t||0===t||"volume"===e||"trades"===e?o:"askVolume"===e?i:"bidVolume"===e?r:t>0?i:r}_metric(e,t){return"deltaPct"===t?e.deltaPct:e[t]}_statText(e,t){if(null===e)return"—";if("deltaPct"===t)return`${e>=0?"+":""}${e.toFixed(1)}%`;const o="trades"===t?e:e/this._opts.volumeDivisor;return(e=>"volume"===e||"trades"===e||"bidVolume"===e||"askVolume"===e)(t)?le(o):((i=o)>=0?"+":"")+le(i);var i}hitTest(e,t){const o=this.hoverAt(e,t);return o?{externalId:`footprint:${o.time}`,zOrder:"normal",distance:0,cursor:"crosshair"}:null}hoverAt(e,t,o){const i=o??this._rc;if(!i||e<0||e>i.plotWidth||t<0||t>i.plotHeight)return null;const r=this._cols.find(o=>o.table&&e>=o.table.left&&e<o.table.right&&t>=o.table.top&&t<=o.table.bottom);if(r)return{time:r.bar.time,price:null,cell:null,stats:r.stats};const l=this._cols.find(t=>e>=t.x0&&e<=t.x0+t.width);if(!l)return null;const n=l.rows.find(e=>t>=e.top&&t<e.bottom);return n?{time:l.bar.time,price:n.cell.price,cell:n.cell,stats:l.stats}:l.card&&t>=l.card.top&&t<=l.card.bottom?{time:l.bar.time,price:null,cell:null,stats:l.stats}:null}}class he{constructor(e,t,o=1){if(Object.defineProperty(this,"_tf",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_tickSize",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_time",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_cells",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"_delta",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_minDelta",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_maxDelta",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_count",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_volume",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_open",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"_lastTickTime",{enumerable:!0,configurable:!0,writable:!0,value:-1/0}),Object.defineProperty(this,"_openPrice",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_high",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_low",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_close",{enumerable:!0,configurable:!0,writable:!0,value:0}),this._tickSize=U(t,o),"interval"===e.mode){if(!Number.isFinite(e.seconds)||e.seconds<=0)throw new RangeError("Footprint interval seconds must be positive and finite");if(void 0!==e.anchorSec&&!Number.isFinite(e.anchorSec))throw new RangeError("Footprint anchorSec must be finite")}else if("ticks"===e.mode){if(!Number.isSafeInteger(e.count)||e.count<1)throw new RangeError("Footprint tick count must be a positive integer")}else{if("volume"!==e.mode)throw new TypeError("Unknown footprint timeframe mode");if(!Number.isFinite(e.perBar)||e.perBar<=0)throw new RangeError("Footprint volume perBar must be positive and finite")}this._tf={...e}}_snapshot(){const e=Array.from(this._cells.values(),e=>({...e})).sort((e,t)=>t.price-e.price);return{time:this._time,cells:e,delta:this._delta,minDelta:this._minDelta,maxDelta:this._maxDelta,rowSize:this._tickSize,open:this._openPrice,high:this._high,low:this._low,close:this._close,tradeCount:this._count}}current(){return this._open?this._snapshot():null}_intervalKey(e){if("interval"!==this._tf.mode)return 0;const t=this._tf.anchorSec??0;return t+Math.floor((e-t)/this._tf.seconds)*this._tf.seconds}onTick(t){if($(t),!Number.isFinite(t.time))throw new RangeError("Footprint tick time must be finite");if(t.time<this._lastTickTime)throw new RangeError("Footprint tick timestamp is out of order");let o=!this._open;this._open&&(o="interval"===this._tf.mode?this._intervalKey(t.time)!==this._time:"ticks"===this._tf.mode?this._count>=this._tf.count&&t.time>this._time:this._volume>=this._tf.perBar&&t.time>this._time),o&&(this._cells=new Map,this._delta=0,this._minDelta=0,this._maxDelta=0,this._count=0,this._volume=0,this._open=!0,this._openPrice=this._high=this._low=t.price,this._time="interval"===this._tf.mode?this._intervalKey(t.time):t.time);const i=e(t.price,this._tickSize);let r=this._cells.get(i);return void 0===r&&(r={price:i,bidVol:0,askVol:0},this._cells.set(i,r)),"bid"===t.side?(r.bidVol+=t.qty,this._delta-=t.qty):(r.askVol+=t.qty,this._delta+=t.qty),this._minDelta=Math.min(this._minDelta,this._delta),this._maxDelta=Math.max(this._maxDelta,this._delta),this._count+=1,this._volume+=t.qty,this._high=Math.max(this._high,t.price),this._low=Math.min(this._low,t.price),this._close=t.price,this._lastTickTime=t.time,{bar:this._snapshot(),isNew:o}}}const ue="profile";export{re as DEFAULT_FOOTPRINT_OPTIONS,w as DEFAULT_MARKET_PROFILE_OPTIONS,H as DEFAULT_MARKET_PROFILE_PRIMITIVE_OPTIONS,d as DEFAULT_VOLUME_PROFILE_FAMILY_OPTIONS,f as DEFAULT_VOLUME_PROFILE_PRIMITIVE_OPTIONS,ce as Footprint,he as FootprintAggregator,J as HorizontalProfile,B as MarketProfile,ue as PROFILE_TIER,j as TPO_PERIOD_COLORS,v as TRADING_HOURS,b as VolumeProfile,e as bucketPrice,le as compactVol,Y as computeFootprint,O as computeMarketProfile,g as computeTpo,o as computeVolumeProfile,m as computeVolumeProfileSessions,Z as cumulativeDelta,X as diagonalImbalances,k as inWindow,D as nakedLevels,t as priceBuckets,N as rowOf,M as rowTicksFor,G as stackedImbalances,_ as tpoLetter};
//# sourceMappingURL=openalgo-charts.profile.mjs.map