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 • 71 kB
import{checkTradingCapability as e}from"./openalgo-charts.mjs";export{TradingCapabilityError,assertTradingCapability,checkTradingCapability}from"./openalgo-charts.mjs";function t(e){return"pending"===e.status||"working"===e.status||"partial"===e.status}function i(e,t){return(t-e.avgPrice)*e.netQty}function r(e,t){if(0===e.avgPrice||0===e.netQty)return 0;const i=e.netQty>0?1:-1;return(t-e.avgPrice)/e.avgPrice*100*i}function s(e,t=0){if(0===e.netQty)return e.avgPrice;const i=e.netQty>0?1:-1;return e.avgPrice+i*t}function o(e,t,i){const r=Math.abs(e-t);return 0===r?null:Math.abs(i-e)/r}function n(e,t,i,r){return"BUY"===e?i<t&&r>t:i>t&&r<t}function a(e){const t=e.trim();if(t.startsWith("#")){const e=t.slice(1);if(3===e.length||4===e.length){const[t,i,r,s]=[...e].map(e=>parseInt(e+e,16));return[t,i,r].some(Number.isNaN)?null:{r:t,g:i,b:r,a:4===e.length?s/255:1}}if(6===e.length||8===e.length){const t=parseInt(e.slice(0,6),16);if(Number.isNaN(t))return null;const i=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(i)?1:i}}return null}const i=/^rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*(?:,\s*([\d.]+)\s*)?\)$/i.exec(t);return null===i?null:{r:Number(i[1]),g:Number(i[2]),b:Number(i[3]),a:void 0===i[4]?1:Number(i[4])}}function c(e){const t=a(e);return(null!==t?function(e){return.2126*d(e.r)+.7152*d(e.g)+.0722*d(e.b)}(t):.5)>.45?"#10131a":"#ffffff"}const d=e=>{const t=e/255;return t<=.03928?t/12.92:Math.pow((t+.055)/1.055,2.4)};function l(e,t){const i=a(e);return null===i?e:`rgba(${i.r},${i.g},${i.b},${t})`}function u(e,t){const i=a(e);if(null===i)return e;const r=t>=0?255:0,s=Math.min(1,Math.abs(t)),o=e=>Math.round(e+(r-e)*s);return`rgba(${o(i.r)},${o(i.g)},${o(i.b)},${i.a})`}function h(e,t,i,r,s,o){const n=e.roundRect;"function"==typeof n?n.call(e,t,i,r,s,Math.max(0,Math.min(o,r/2,s/2))):e.rect(t,i,r,s)}function f(e,t,i,r,s,o,n){const a=e.measureText(r).width+2*o;return e.beginPath(),h(e,t,i-s/2,a,s,n.radius),void 0!==n.backplate&&(e.fillStyle=n.backplate,e.fill()),e.fillStyle=n.fill,e.fill(),void 0!==n.border&&(e.strokeStyle=n.border,e.lineWidth=1,e.stroke()),e.fillStyle=n.text,e.textAlign="left",e.textBaseline="middle",e.fillText(r,t+o,i),a}function p(e,t,i,r,s){const{height:o,padX:n,radius:a,gap:c,dpr:d}=s,l=r.map(t=>!0===t.close?20*d:e.measureText(t.text??"").width+2*n),u=l.reduce((e,t)=>e+t,0)+c*Math.max(0,r.length-1);void 0!==s.backplate&&(e.beginPath(),h(e,t,i-o/2,u,o,a),e.fillStyle=s.backplate,e.fill());let f=Number.POSITIVE_INFINITY,p=t;for(let t=0;t<r.length;t++){const s=r[t],u=l[t];if(e.beginPath(),h(e,p,i-o/2,u,o,a),e.fillStyle=s.fill,e.fill(),void 0!==s.border&&(e.strokeStyle=s.border,e.lineWidth=Math.max(1,Math.round(d)),e.stroke()),!0===s.close){f=p,e.strokeStyle=s.textColor,e.lineWidth=Math.max(1,Math.round(1.4*d));const t=p+u/2,r=3.5*d;e.beginPath(),e.moveTo(t-r,i-r),e.lineTo(t+r,i+r),e.moveTo(t+r,i-r),e.lineTo(t-r,i+r),e.stroke()}else e.fillStyle=s.textColor,e.textAlign="left",e.textBaseline="middle",e.fillText(s.text??"",p+n,i);p+=u+c}return{x0:t/d,x1:(p-c)/d,closeX0:f/d}}function _(e,t,i,r,s,o,n,a){if("hidden"===t.priceAxisSide||!(t.priceAxisWidth>0))return;const c=t.dpr,d=6*c,l="left"===t.priceAxisSide;if(l||void 0!==t.priceAxisOffset){const a=t.priceAxisOffset??0,u=Math.round(a*c),h=Math.round((a+(l?-t.priceAxisWidth:t.priceAxisWidth))*c),f=void 0!==t.priceAxisOffset,p=(f?Math.abs(h-u):Math.round(t.priceAxisWidth*c))-1,_=t.plotHeight*c;if(Number.isFinite(u)&&Number.isFinite(h)&&p>0&&_>=n){e.save(),f&&(e.beginPath(),e.rect(Math.min(u,h),0,p+1,_),e.clip());const t=Math.min(d,p/4),a=e.measureText(r).width,b=Math.min(p,a+2*t),m=l?u-1-b:u+1,g=Math.max(n/2,Math.min(_-n/2,i));e.fillStyle=s,e.fillRect(m,g-n/2,b,n),e.fillStyle=o,e.font=`500 ${11*c*(a>0?Math.min(1,(b-2*t)/a):1)}px system-ui, sans-serif`,e.fillText(r,m+t,g),e.restore(),e.font=`500 ${11*c}px system-ui, sans-serif`}}else{const a=Math.round(t.plotWidth*c);e.fillStyle=s,e.fillRect(a+1,i-n/2,e.measureText(r).width+2*d,n),e.fillStyle=o,e.fillText(r,a+1+d,i)}}class b{constructor(e,t={}){Object.defineProperty(this,"_order",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_ltp",{enumerable:!0,configurable:!0,writable:!0,value:NaN}),Object.defineProperty(this,"_host",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"_group",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"_extent",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_ghost",{enumerable:!0,configurable:!0,writable:!0,value:null}),this._order=e,this._extent=Math.max(.1,Math.min(1,t.extentFromRight??.5))}attached(e){this._host=e}detached(){this._host=null}zOrder(){return"normal"}get order(){return this._order}update(e){this._order=e,this._host?.requestUpdate()}setLtp(e){this._ltp=e,this._host?.requestUpdate()}autoscaleInfo(){const e=this._order.triggerPrice??this._order.price;return{min:e,max:e}}_price(){return this._order.triggerPrice??this._order.price}draw(e,t){this._group=null;const i=this._price(),r=t.dpr,s=Math.round(t.priceScale.priceToY(i)*r)+.5;if(s<0||s>t.plotHeight*r)return;const o="BUY"===this._order.side?t.theme.buy:t.theme.sell,n=t.hoverId===`order:${this._order.id}`||t.hoverId===`order:${this._order.id}::close`||t.dragId===`order:${this._order.id}`,a="pending"===this._order.status,d=a?l(o,.55):n?u(o,.1):o,h=Math.round(t.plotWidth*r),f=Math.round(t.plotWidth*(1-this._extent)*r),b=t.dragId===`order:${this._order.id}`;if(b&&null===this._ghost?this._ghost=i:b||null===this._ghost||(this._ghost=null),e.save(),null!==this._ghost&&Math.abs(this._ghost-i)>1e-9){const i=Math.round(t.priceScale.priceToY(this._ghost)*r)+.5;i>=0&&i<=t.plotHeight*r&&(e.strokeStyle=l(o,.35),e.lineWidth=Math.max(1,Math.round(r)),e.setLineDash([2*r,3*r]),e.beginPath(),e.moveTo(f,i),e.lineTo(h,i),e.stroke(),e.setLineDash([]))}b&&(e.strokeStyle=l(o,.18),e.lineWidth=5*r,e.beginPath(),e.moveTo(f,s),e.lineTo(h,s),e.stroke()),e.strokeStyle=d;const m=Math.max(1,Math.round(r));e.lineWidth=n?m+Math.round(r):m,e.setLineDash([6*r,4*r]),e.beginPath(),e.moveTo(f,s),e.lineTo(h,s),e.stroke(),e.setLineDash([]),e.font=`500 ${11*r}px system-ui, sans-serif`,e.textBaseline="middle",e.textAlign="left";const g=18*r,y=6*r,v=3*r,k=t.priceScale.format(i);_(e,t,s,k,a?l(o,.7):o,c(o),g);const w="transparent"===t.theme.background?l(o,.14):t.theme.background,x="transparent"===t.theme.background?t.theme.axisText:c(t.theme.background),I=l(t.theme.axisText,n?.75:.5),M=t.hoverId===`order:${this._order.id}::close`;a&&(e.globalAlpha=.75);const P=this._order.filledQty>0?`${this._order.filledQty}/${this._order.qty}`:String(this._order.qty-this._order.filledQty);let T=`${this._order.type} ${k}`;if(!Number.isNaN(this._ltp)){const e=i-this._ltp;T+=`  ${e>=0?"+":""}${t.priceScale.format(e)}`}this._group=p(e,f,s,[{text:this._order.side,fill:n?u(o,.12):o,textColor:c(o),border:u(o,-.25)},{text:P,fill:w,textColor:x,border:I},{text:T,fill:w,textColor:x,border:I},{close:!0,fill:M?o:w,textColor:M?c(o):x,border:M?o:I}],{height:g,padX:y,radius:v,gap:2*r,backplate:"transparent"===t.theme.background?void 0:t.theme.background,dpr:r}),e.restore()}hitTest(e,t,i){if(e<0||e>i.plotWidth)return null;const r=i.priceScale.priceToY(this._price()),s=Math.abs(t-r),o=this._group;return null!==o&&s<=10&&e>=o.x0&&e<=o.x1?e>=o.closeX0?{externalId:`order:${this._order.id}::close`,zOrder:"normal",distance:s,cursor:"pointer"}:{externalId:`order:${this._order.id}`,zOrder:"normal",distance:s,cursor:"ns-resize"}:s>4||e<i.plotWidth*(1-this._extent)-8?null:{externalId:`order:${this._order.id}`,zOrder:"normal",distance:s,cursor:"ns-resize"}}}class m{constructor(e,t={}){Object.defineProperty(this,"_position",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_ltp",{enumerable:!0,configurable:!0,writable:!0,value:NaN}),Object.defineProperty(this,"_host",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"_group",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"_extent",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this._position=e,this._extent=Math.max(.1,Math.min(1,t.extentFromRight??.5))}attached(e){this._host=e}detached(){this._host=null}zOrder(){return"normal"}get position(){return this._position}update(e){this._position=e,this._host?.requestUpdate()}setLtp(e){this._ltp=e,this._host?.requestUpdate()}autoscaleInfo(){return{min:this._position.avgPrice,max:this._position.avgPrice}}draw(e,t){if(this._group=null,0===this._position.netQty)return;const s=t.dpr,o=Math.round(t.priceScale.priceToY(this._position.avgPrice)*s)+.5;if(o<0||o>t.plotHeight*s)return;const n=Math.round(t.plotWidth*s),a=Number.isNaN(this._ltp)?0:i(this._position,this._ltp),d=a>=0?t.theme.profit:t.theme.loss,h=this._position.netQty>0,f=h?t.theme.buy:t.theme.sell,b=`position:${this._position.symbol}`,m=t.hoverId===b||t.hoverId===`${b}::close`,g=Math.round(t.plotWidth*(1-this._extent)*s);if(e.save(),e.strokeStyle=m?f:t.theme.axisText,e.lineWidth=Math.max(1,Math.round(s))+(m?Math.round(s):0),e.beginPath(),e.moveTo(g,o),e.lineTo(n,o),e.stroke(),!Number.isNaN(this._ltp)){const i=Math.round(t.priceScale.priceToY(this._ltp)*s);e.fillStyle=l(d,.1),e.fillRect(g,Math.min(o,i),n-g,Math.abs(i-o))}e.font=`500 ${11*s}px system-ui, sans-serif`,e.textBaseline="middle",e.textAlign="left";const y=18*s,v=6*s,k=3*s;_(e,t,o,t.priceScale.format(this._position.avgPrice),d,c(d),y);const w="transparent"===t.theme.background?l(f,.14):t.theme.background,x="transparent"===t.theme.background?t.theme.axisText:c(t.theme.background),I=l(t.theme.axisText,m?.75:.5),M=t.hoverId===`${b}::close`,P=Number.isNaN(this._ltp)?0:r(this._position,this._ltp),T=h?"LONG":"SHORT",O=String(Math.abs(this._position.netQty)),S=`${a>=0?"+":""}${a.toFixed(2)} (${P>=0?"+":""}${P.toFixed(2)}%)`;this._group=p(e,g,o,[{text:T,fill:m?u(f,.12):f,textColor:c(f),border:u(f,-.25)},{text:O,fill:w,textColor:x,border:I},{text:S,fill:w,textColor:d,border:l(d,.65)},{close:!0,fill:M?f:w,textColor:M?c(f):x,border:M?f:I}],{height:y,padX:v,radius:k,gap:2*s,backplate:"transparent"===t.theme.background?void 0:t.theme.background,dpr:s}),e.restore()}hitTest(e,t,i){if(0===this._position.netQty||e<0||e>i.plotWidth)return null;const r=i.priceScale.priceToY(this._position.avgPrice),s=Math.abs(t-r),o=`position:${this._position.symbol}`,n=this._group;return null!==n&&s<=10&&e>=n.x0&&e<=n.x1?e>=n.closeX0?{externalId:`${o}::close`,zOrder:"normal",distance:s,cursor:"pointer"}:{externalId:o,zOrder:"normal",distance:s,cursor:"pointer"}:s>4||e<i.plotWidth*(1-this._extent)-8?null:{externalId:o,zOrder:"normal",distance:s,cursor:"pointer"}}}class g{constructor(e){Object.defineProperty(this,"_state",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_host",{enumerable:!0,configurable:!0,writable:!0,value:null}),this._state=e}attached(e){this._host=e}detached(){this._host=null}zOrder(){return"bottom"}get state(){return this._state}update(e){this._state=e,this._host?.requestUpdate()}autoscaleInfo(){return{min:Math.min(this._state.stop,this._state.target,this._state.entry),max:Math.max(this._state.stop,this._state.target,this._state.entry)}}draw(e,t){const{entry:i,stop:r,target:s}=this._state,n=t.dpr,a=Math.round(t.plotWidth*n),c=t.priceScale.priceToY(i)*n,d=t.priceScale.priceToY(r)*n,u=t.priceScale.priceToY(s)*n;e.save(),e.fillStyle=l(t.theme.loss,.09),e.fillRect(0,Math.min(c,d),a,Math.abs(d-c)),e.fillStyle=l(t.theme.profit,.09),e.fillRect(0,Math.min(c,u),a,Math.abs(u-c)),e.font=`500 ${10*n}px system-ui, sans-serif`,e.textBaseline="middle";for(const[i,o,c,h,p]of[[d,t.theme.loss,"SL",r,`bracket-sl:${this._state.symbol}`],[u,t.theme.profit,"TP",s,`bracket-tp:${this._state.symbol}`]]){const r=Math.round(i)+.5,s=t.hoverId===p||t.dragId===p;e.strokeStyle=o;const d=Math.max(1,Math.round(n));e.lineWidth=s?d+Math.round(n):d,e.setLineDash([4*n,4*n]),e.beginPath(),e.moveTo(0,r),e.lineTo(a,r),e.stroke(),e.setLineDash([]),f(e,4*n,r,`${c} ${t.priceScale.format(h)}`,16*n,6*n,{fill:l(o,s?.28:.16),text:o,border:l(o,.55),radius:3*n,backplate:"transparent"===t.theme.background?void 0:t.theme.background})}const h=o(i,r,s);null!==h&&f(e,4*n,Math.round(c)-12*n,`R:R ${h.toFixed(2)}`,16*n,6*n,{fill:l(t.theme.axisText,.16),text:t.theme.axisText,radius:3*n,backplate:"transparent"===t.theme.background?void 0:t.theme.background}),e.restore()}hitTest(e,t,i){if(e<0||e>i.plotWidth)return null;const r=i.priceScale.priceToY(this._state.stop),s=i.priceScale.priceToY(this._state.target),o=Math.abs(t-r),n=Math.abs(t-s);return o<=4?{externalId:`bracket-sl:${this._state.symbol}`,zOrder:"bottom",distance:o,cursor:"ns-resize"}:n<=4?{externalId:`bracket-tp:${this._state.symbol}`,zOrder:"bottom",distance:n,cursor:"ns-resize"}:null}}class y{constructor(e){Object.defineProperty(this,"_host",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_orderLines",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"_markers",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"_brackets",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"_ltp",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),this._host=e}reconcile(e,t){const i=this._planBrackets(e,t);this._reconcileOrderLines(e,i.covered),this._reconcilePositions(t),this._applyBrackets(i.states)}_reconcileOrderLines(e,i){const r=new Set;for(const s of e){if(!t(s)||i.has(s.id))continue;r.add(s.id);const e=this._orderLines.get(s.id);if(e)e.update(s);else{const e=new b(s),t=this._ltp.get(s.symbol);void 0!==t&&e.setLtp(t),this._orderLines.set(s.id,e),this._host.addPrimitive(e)}}for(const[e,t]of this._orderLines)r.has(e)||(this._host.removePrimitive(t),this._orderLines.delete(e))}_reconcilePositions(e){const t=new Set;for(const i of e){if(0===i.netQty)continue;t.add(i.symbol);const e=this._markers.get(i.symbol);if(e)e.update(i);else{const e=new m(i),t=this._ltp.get(i.symbol);void 0!==t&&e.setLtp(t),this._markers.set(i.symbol,e),this._host.addPrimitive(e)}}for(const[e,i]of this._markers)t.has(e)||(this._host.removePrimitive(i),this._markers.delete(e))}_planBrackets(e,i){const r=new Map,s=new Map;for(const i of e)t(i)&&("sl"===i.role?r.set(i.symbol,i):"tp"===i.role&&s.set(i.symbol,i));const o=new Map(i.map(e=>[e.symbol,e])),n=new Map,a=new Set;for(const e of new Set([...r.keys(),...s.keys()])){const t=r.get(e),i=s.get(e);if(void 0===t||void 0===i)continue;const c=o.get(e);void 0!==c&&0!==c.netQty&&(n.set(e,{symbol:e,side:c.netQty>0?"BUY":"SELL",entry:c.avgPrice,stop:t.triggerPrice??t.price,target:i.price}),a.add(t.id),a.add(i.id))}return{states:n,covered:a}}_applyBrackets(e){for(const[t,i]of e){const e=this._brackets.get(t);if(e)e.update(i);else{const e=new g(i);this._brackets.set(t,e),this._host.addPrimitive(e)}}for(const[t,i]of this._brackets)e.has(t)||(this._host.removePrimitive(i),this._brackets.delete(t))}onLtp(e,t){this._ltp.set(e,t);for(const i of this._orderLines.values())i.order.symbol===e&&i.setLtp(t);const i=this._markers.get(e);i&&i.setLtp(t)}orderLineCount(){return this._orderLines.size}positionCount(){return this._markers.size}bracketCount(){return this._brackets.size}}const v=["DAY","IOC","FOK","GTC","GTD"],k={accounts:"Account data",executions:"Execution history",orderHistory:"Order history",preview:"Order preview",duration:"Order duration",leverage:"Leverage",close:"Closing a position",partialClose:"Partial close",reverse:"Reversing a position",brackets:"Bracket placement"};function w(e){return k[e]}function x(e,t){const i=k[t.feature],r={supported:!1,reason:`${i} is not declared by this provider`};if(void 0===e)return r;try{const s="function"==typeof e?e(Object.freeze({...t})):e;if(!s||"object"!=typeof s||Array.isArray(s)||"then"in s)return{supported:!1,reason:"Trading features are unavailable"};if("duration"===t.feature){const e=s.durations;return Array.isArray(e)?void 0===t.duration?{supported:!1,reason:"Order duration needs a named duration"}:e.includes(t.duration)?{supported:!0}:{supported:!1,reason:`Duration ${t.duration} is not supported`}:r}const o=s[t.feature];return!0===o?{supported:!0}:!1===o?{supported:!1,reason:`${i} is not supported`}:void 0===o?r:{supported:!1,reason:`Support for ${i.toLowerCase()} is unknown`}}catch{return{supported:!1,reason:"Trading features are unavailable"}}}const I={accounts:!0,executions:!0,orderHistory:!0,preview:!0,durations:v,leverage:!0,close:!0,partialClose:!0,reverse:!0,brackets:!0};function M(e){return Object.assign(new Error(`FakeBroker: ${e}`),{rejected:!0})}const P=e=>"analyzer"===e?"an":"a",T=e=>0===e?0:e;class O{constructor(e={}){Object.defineProperty(this,"_orders",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"_positions",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"_bookListeners",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"_ltpListeners",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"_depthListeners",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"_orderListeners",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"_idCounter",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"_execCounter",{enumerable:!0,configurable:!0,writable:!0,value:0}),Object.defineProperty(this,"rejectNextPlace",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"_ledgers",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"_meta",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"_marks",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"_accountMode",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_features",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_clock",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_latency",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_failures",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"_connected",{enumerable:!0,configurable:!0,writable:!0,value:!0}),Object.defineProperty(this,"_muted",{enumerable:!0,configurable:!0,writable:!0,value:!1}),this._accountMode=void 0!==e.accounts,this._features=e.features??(this._accountMode?I:void 0),this._clock=e.now??(()=>Date.now()/1e3),this._latency=e.latency;for(const t of e.accounts??[])this._ledgers.set(t.id,{seed:{...t},cash:t.balance,realized:0,positions:new Map,executions:[],subscribers:new Set})}get features(){return this._features}onBook(e){this._bookListeners.push(e)}onLtp(e){this._ltpListeners.push(e)}onOrderUpdate(e){this._orderListeners.push(e)}setBook(e,t){this._orders=e.map(e=>({...e})),this._positions=t.map(e=>({...e}));for(const e of this._bookListeners)e(this._orders,this._positions)}emitLtp(e,t){this.setMark(e,t);for(const i of this._ltpListeners)i(e,t)}setMark(e,t){this._marks.set(e,t);for(const t of this._ledgers.values())t.positions.has(e)&&this._push(t)}onDepth(e){this._depthListeners.push(e)}emitDepth(e,t){for(const i of this._depthListeners)i(e,t)}static makeDepth(e,t,i=.05){const r=[],s=[];for(let o=1;o<=t;o++)r.push({price:e-o*i,qty:100+37*o%900}),s.push({price:e+o*i,qty:100+53*o%900});return{bids:r,asks:s,ltp:e}}orders(){return this._orders}positions(){return this._positions}accountPositions(e){const t=this._ledgers.get(e);return void 0===t?[]:[...t.positions].map(([e,t])=>({symbol:e,netQty:t.netQty,avgPrice:t.avgPrice}))}failNext(e,t,i){this._failures.push({operation:e,failure:t,reason:i})}disconnect(){this._connected=!1;for(const e of this._ledgers.values()){const t=[...e.subscribers];e.subscribers.clear();for(const e of t)e.onError?.(new Error("FakeBroker: disconnected"))}}reconnect(){this._connected=!0}muteOrderUpdates(e){this._muted=e}async place(e){if(this._online(),null!==this.rejectNextPlace){const e=this.rejectNextPlace;throw this.rejectNextPlace=null,new Error(e)}if(!this._accountMode){if(void 0!==e.account||void 0!==e.duration||void 0!==e.expiresAt||void 0!==e.leverage)throw M("this broker has no accounts, durations or leverage configured");const t="B"+ ++this._idCounter,i={id:t,symbol:e.symbol,side:e.side,type:e.type,qty:e.qty,filledQty:0,price:e.price??0,triggerPrice:e.triggerPrice,status:"MARKET"===e.type?"filled":"working",role:void 0};return this._orders.push(i),this._emit(i),this._notify(),{orderId:t}}const t=this._ledgerFor(e.account,e.mode),i=await this._enter("place",t.seed.id),r=this._placeIn(t,e);return this._changed(t),i&&this._lost("place"),{orderId:r.id}}async modify(e,t){this._online();const i=this._meta.get(e),r=void 0!==i&&await this._enter("modify",i.accountId),s=this._orders.find(t=>t.id===e);if(void 0===s)throw new Error("FakeBroker: unknown order");void 0!==i&&this._live(s),void 0!==t.price&&(s.price=t.price),void 0!==t.triggerPrice&&(s.triggerPrice=t.triggerPrice),void 0!==t.qty&&(s.qty=t.qty),void 0!==i&&(i.time=this._clock()),this._emit(s),this._notify(),r&&this._lost("modify")}async cancel(e){this._online();const t=this._meta.get(e),i=void 0!==t&&await this._enter("cancel",t.accountId),r=this._orders.find(t=>t.id===e);if(void 0!==r&&void 0!==t&&this._live(r),this._orders=this._orders.filter(t=>t.id!==e),void 0!==r&&void 0!==t){this._close(r,"cancelled");for(const t of this._orders.filter(t=>t.parentId===e&&"pending"===t.status))this._orders=this._orders.filter(e=>e!==t),this._close(t,"cancelled")}else void 0!==r&&this._emit({...r,status:"cancelled"});this._notify(),i&&this._lost("cancel")}fill(e){const t=this._orders.find(t=>t.id===e);if(void 0===t)return;const i=this._meta.get(e);if(t.filledQty=t.qty,t.status="filled",this._orders=this._orders.filter(t=>t.id!==e),void 0!==i){const e=this._ledgers.get(i.accountId),r="SL-M"===t.type?t.triggerPrice??t.price:t.price;this._execute(e,i,t.side,t.qty,r),i.time=this._clock(),this._emit(t);for(const e of this._orders.filter(e=>void 0!==e.parentId&&(e.parentId===t.id||e.parentId===t.parentId)))e.parentId===t.id&&"pending"===e.status?(e.status="working",this._emit(e)):void 0!==t.parentId&&e.parentId===t.parentId&&e.id!==t.id&&(this._orders=this._orders.filter(t=>t!==e),this._close(e,"cancelled"));return void this._changed(e)}this._emit(t),this._notify()}async previewOrder(e){if(this._online(),!this._accountMode)throw new Error("FakeBroker: order preview needs accounts");this._require("preview",e);const t=this._ledgerFor(e.account,e.mode);await this._enter("preview",t.seed.id),this._sweep();const i=this._snapshot(t),r=this._entryPrice(e),s={accountId:t.seed.id,asOf:this._clock(),...t.seed.currency?{currency:t.seed.currency}:{}};if(void 0===r)return{...s,rejectReason:`no price for ${e.symbol}`};const o=e.leverage??t.seed.leverage??1,n=this._opening(t,e.symbol,e.side,e.qty)*r/o,a=i.marginAvailable??0;let c;try{this._schema(t,e)}catch(e){c=String(e.message).replace(/^FakeBroker: /,"")}return void 0===c&&n>a&&(c=`Insufficient margin: ${n.toFixed(2)} required, ${a.toFixed(2)} available`),{...s,estimatedPrice:r,estimatedValue:e.qty*r,marginRequired:n,marginAvailableAfter:a-n,...void 0===c?{}:{rejectReason:c}}}async closePosition(e){if(this._online(),!this._accountMode)throw M("closing a position needs accounts");this._require(void 0===e.qty?"close":"partialClose",e);const t=this._ledgerFor(e.account,e.mode),i=await this._enter("close",t.seed.id);this._sweep();const r=this._holding(t,e.symbol),s=Math.abs(r.netQty),o=e.qty??s;if(!(o>0)||o>s)throw M(`close quantity ${o} exceeds the open position of ${s}`);const n=this._command(t,e,"close",r.netQty>0?"SELL":"BUY",o,r.leverage);return i&&this._lost("close"),{commandId:n.id,orderIds:[n.id]}}async reversePosition(e){if(this._online(),!this._accountMode)throw M("reversing a position needs accounts");this._require("reverse",e);const t=this._ledgerFor(e.account,e.mode),i=await this._enter("reverse",t.seed.id);this._sweep();const r=this._holding(t,e.symbol),s=r.netQty>0?"SELL":"BUY",o=this._mark(e.symbol),n=Math.abs(r.netQty)*o/r.leverage,a=(this._snapshot(t).marginAvailable??0)+Math.abs(r.netQty)*r.avgPrice/r.leverage;if(n>a)throw M(`Insufficient margin: ${n.toFixed(2)} required, ${a.toFixed(2)} available`);const c=this._command(t,e,"reverse",s,2*Math.abs(r.netQty),r.leverage);return i&&this._lost("reverse"),{commandId:c.id,orderIds:[c.id]}}async placeBracket(e){if(this._online(),!this._accountMode)throw M("bracket placement needs accounts");this._require("brackets",e);const t=this._ledgerFor(e.account,e.mode),i=await this._enter("bracket",t.seed.id);this._sweep();const r=this._entryPrice(e);if(void 0===r)throw M(`no price for ${e.symbol}`);const[s,o]="BUY"===e.side?[e.stopLoss,e.takeProfit]:[e.takeProfit,e.stopLoss];if(!(s<r&&r<o))throw M("the stop and target are on the wrong side of the entry");const n=this._placeIn(t,e,"bracket"),a="BUY"===e.side?"SELL":"BUY",c="filled"!==n.status,d=[];for(const i of["sl","tp"]){const r="B"+ ++this._idCounter,s={id:r,symbol:e.symbol,side:a,type:"sl"===i?"SL-M":"LIMIT",qty:e.qty,filledQty:0,price:"sl"===i?0:e.takeProfit,..."sl"===i?{triggerPrice:e.stopLoss}:{},status:c?"pending":"working",parentId:n.id,role:i},o=e.legClientTokens?.["sl"===i?"stopLoss":"takeProfit"];this._meta.set(r,{accountId:t.seed.id,order:s,exchange:e.exchange,command:"bracket",leverage:this._meta.get(n.id).leverage,time:this._clock(),...void 0===o?{}:{clientToken:o}}),this._orders.push(s),this._emit(s),d.push(r)}return this._changed(t),i&&this._lost("bracket"),{orderId:n.id,stopLossId:d[0],takeProfitId:d[1]}}async listAccounts(e){return this._online(),this._accountMode?(await this._enter("accounts",void 0),[...this._ledgers.values()].map(({seed:e})=>({id:e.id,mode:e.mode,...e.name?{name:e.name}:{},...e.currency?{currency:e.currency}:{}}))):[]}async getAccountSnapshot(e,t){this._online();const i=this._account(e);return await this._enter("snapshot",e),this._sweep(),this._snapshot(i)}subscribeAccount(e,t,i){this._online();const r=this._account(e),s={onSnapshot:t,onError:i};return r.subscribers.add(s),()=>{r.subscribers.delete(s)}}async getAccountPositions(e,t){return this._online(),this._account(e),await this._enter("positions",e),this._sweep(),this.accountPositions(e).map(t=>({...t,accountId:e}))}async getExecutions(e,t){this._online();const i=this._account(e.accountId);return await this._enter("executions",e.accountId),this._window([...i.executions].reverse(),e=>e.symbol,e=>e.time,e).map(e=>({...e}))}async getOrderHistory(e,t){this._online(),this._account(e.accountId),await this._enter("history",e.accountId),this._sweep();const i=[...this._meta.values()].filter(t=>t.accountId===e.accountId).sort((e,t)=>t.time-e.time||Number(t.order.id.slice(1))-Number(e.order.id.slice(1)));return this._window(i,e=>e.order.symbol,e=>e.time,e).map(e=>({accountId:e.accountId,order:{...e.order},time:e.time,...void 0===e.clientToken?{}:{clientToken:e.clientToken},...void 0===e.duration?{}:{duration:e.duration},...void 0===e.expiresAt?{}:{expiresAt:e.expiresAt},...void 0===e.command?{}:{command:e.command}}))}_notify(){for(const e of this._bookListeners)e(this._orders,this._positions)}_emit(e){if(this._muted)return;const t=this._meta.get(e.id),i=void 0===t?{}:{accountId:t.accountId,...void 0===t.clientToken?{}:{clientToken:t.clientToken},...void 0===t.command?{}:{command:t.command}};for(const t of[...this._orderListeners])t({...e},i)}_changed(e){this._notify(),this._push(e)}_push(e){if(0===e.subscribers.size)return;const t=this._snapshot(e);for(const i of[...e.subscribers])i.onSnapshot({...t})}_online(){if(!this._connected)throw Object.assign(new Error("FakeBroker: disconnected; nothing was sent"),{preflight:!0})}async _enter(e,t){if(void 0!==this._latency&&await this._latency(e,t),!this._connected)throw new Error("FakeBroker: the connection dropped before the answer");const i=this._failures.findIndex(t=>t.operation===e),r=this._failures[i];if(void 0===r)return!1;if(this._failures.splice(i,1),"reject"===r.failure)throw M(r.reason??`${e} refused`);if("timeout"===r.failure)throw new Error(`FakeBroker: ${r.reason??`${e} timed out`}`);return!0}_live(e){if("working"!==e.status&&"pending"!==e.status&&"partial"!==e.status)throw M(`order ${e.id} is already ${e.status}`)}_lost(e){throw new Error(`FakeBroker: the ${e} answer was lost`)}_require(e,t){const i=x(this._features,{feature:e,symbol:t.symbol,account:t.account,mode:t.mode});if(!i.supported)throw M(i.reason)}_account(e){if(!this._accountMode)throw new Error("FakeBroker: no accounts are configured");const t=this._ledgers.get(e);if(void 0===t)throw M(`unknown account ${e}`);return t}_ledgerFor(e,t){const i=t??"live";void 0!==e&&this._require("accounts",{account:e,mode:i});const r=void 0===e?[...this._ledgers.values()].find(e=>e.seed.mode===i):this._ledgers.get(e);if(void 0===r)throw M(void 0===e?`no ${i} account is configured`:`unknown account ${e}`);if(r.seed.mode!==i)throw M(`${r.seed.id} is ${P(r.seed.mode)} ${r.seed.mode} account and cannot take ${P(i)} ${i} order`);return r}_mark(e){const t=this._marks.get(e);if(void 0===t)throw M(`no price for ${e}`);return t}_holding(e,t){const i=e.positions.get(t);if(void 0===i||0===i.netQty)throw M(`no open position in ${t}`);return i}_entryPrice(e){if("MARKET"===e.type)return this._marks.get(e.symbol);const t="SL-M"===e.type?e.triggerPrice:e.price;return void 0!==t&&Number.isFinite(t)?t:void 0}_opening(e,t,i,r){const s=e.positions.get(t)?.netQty??0,o=s+("BUY"===i?r:-r);return Math.max(0,Math.abs(o)-Math.abs(s))}_schema(e,t){if(void 0!==t.duration){const e=x(this._features,{feature:"duration",duration:t.duration,mode:t.mode});if(!e.supported)throw M(e.reason)}if(!("GTD"!==t.duration&&void 0===t.expiresAt||"GTD"===t.duration&&void 0!==t.expiresAt&&t.expiresAt>this._clock()))throw M("a GTD order needs an expiry in the future, and only a GTD order takes one");const i=t.leverage??e.seed.leverage??1;if(void 0!==t.leverage){this._require("leverage",t);const r=e.seed.maxLeverage??e.seed.leverage??1;if(!(i>0)||i>r)throw M(`leverage ${i} is above the account limit of ${r}`)}return i}_placeIn(e,t,i){this._sweep();const r=this._schema(e,t),s=this._entryPrice(t);if(void 0===s)throw M("MARKET"===t.type?`no price for ${t.symbol}`:"the order has no price");const o=this._opening(e,t.symbol,t.side,t.qty)*s/r,n=this._snapshot(e).marginAvailable??0;if(o>n+1e-9)throw M(`Insufficient margin: ${o.toFixed(2)} required, ${n.toFixed(2)} available`);const a="B"+ ++this._idCounter,c={id:a,symbol:t.symbol,side:t.side,type:t.type,qty:t.qty,filledQty:0,price:t.price??0,triggerPrice:t.triggerPrice,status:"working",role:void 0},d={accountId:e.seed.id,order:c,exchange:t.exchange,leverage:r,time:this._clock(),...void 0===t.clientToken?{}:{clientToken:t.clientToken},...void 0===t.duration?{}:{duration:t.duration},...void 0===t.expiresAt?{}:{expiresAt:t.expiresAt},...void 0===i?{}:{command:i}};this._meta.set(a,d);const l="IOC"===t.duration||"FOK"===t.duration,u=this._marks.get(t.symbol);if("MARKET"===t.type||l&&"LIMIT"===t.type&&void 0!==u&&("BUY"===t.side?t.price>=u:t.price<=u)){const i=u;c.price=i,c.filledQty=t.qty,c.status="filled",this._execute(e,d,t.side,t.qty,i),this._orders.push(c)}else l?c.status="cancelled":this._orders.push(c);return this._emit(c),c}_command(e,t,i,r,s,o){const n=this._mark(t.symbol),a="B"+ ++this._idCounter,c={id:a,symbol:t.symbol,side:r,type:"MARKET",qty:s,filledQty:s,price:n,status:"filled",role:void 0},d={accountId:e.seed.id,order:c,exchange:t.exchange,leverage:o,time:this._clock(),command:i,...void 0===t.clientToken?{}:{clientToken:t.clientToken}};return this._meta.set(a,d),this._execute(e,d,r,s,n),this._orders.push(c),this._emit(c),this._changed(e),c}_execute(e,t,i,r,s){const o=t.order.symbol,n=e.positions.get(o)??{netQty:0,avgPrice:0,leverage:t.leverage},a="BUY"===i?r:-r;let{netQty:c,avgPrice:d,leverage:l}=n;if(0===c||Math.sign(c)===Math.sign(a))d=(d*Math.abs(c)+s*r)/(Math.abs(c)+r),0===c&&(l=t.leverage),c+=a;else{const i=Math.min(r,Math.abs(c)),o=(s-d)*i*Math.sign(c);e.realized+=o,e.cash+=o,c+=a,r>i&&(d=s,l=t.leverage)}0===c?e.positions.delete(o):e.positions.set(o,{netQty:c,avgPrice:d,leverage:l}),e.executions.push({id:"E"+ ++this._execCounter,accountId:e.seed.id,orderId:t.order.id,symbol:o,...void 0===t.exchange?{}:{exchange:t.exchange},side:i,qty:r,price:s,time:this._clock()})}_snapshot(e){let t=0,i=0;for(const[r,s]of e.positions)t+=((this._marks.get(r)??s.avgPrice)-s.avgPrice)*s.netQty,i+=Math.abs(s.netQty)*s.avgPrice/s.leverage;const r=e.cash+t;return{accountId:e.seed.id,mode:e.seed.mode,asOf:this._clock(),...e.seed.currency?{currency:e.seed.currency}:{},balance:T(e.cash),equity:T(r),marginUsed:T(i),marginAvailable:T(r-i),unrealizedPnl:T(t),realizedPnl:T(e.realized),leverage:e.seed.leverage??1}}_close(e,t){e.status=t;const i=this._meta.get(e.id);void 0!==i&&(i.time=this._clock()),this._emit(e)}_sweep(){const e=this._clock(),t=new Set;for(const i of[...this._orders]){const r=this._meta.get(i.id);void 0===r?.expiresAt||r.expiresAt>e||"working"!==i.status&&"pending"!==i.status||(this._orders=this._orders.filter(e=>e!==i),this._close(i,"cancelled"),t.add(this._ledgers.get(r.accountId)))}for(const e of t)this._changed(e)}_window(e,t,i,r){const s=e.filter(e=>(void 0===r.symbol||t(e)===r.symbol)&&(void 0===r.from||i(e)>=r.from)&&(void 0===r.to||i(e)<=r.to));return void 0===r.limit?s:s.slice(0,Math.max(0,r.limit))}}const S=new Set(["filled","cancelled","rejected","stale"]);function $(e){return S.has(e)}const A={pending_place:{ack:"working",partialFill:"partial",fill:"filled",reject:"rejected",reconnectAbsent:"stale"},working:{partialFill:"partial",fill:"filled",reject:"rejected",submitModify:"modify_pending",submitCancel:"cancel_pending",cancelled:"cancelled",reconnectAbsent:"stale"},partial:{partialFill:"partial",fill:"filled",reject:"rejected",submitModify:"modify_pending",submitCancel:"cancel_pending",cancelled:"cancelled",reconnectAbsent:"stale"},modify_pending:{ack:"working",reject:"working",fill:"filled",partialFill:"partial",cancelled:"cancelled",reconnectAbsent:"stale"},cancel_pending:{cancelled:"cancelled",reject:"working",fill:"filled",reconnectAbsent:"stale"},filled:{},cancelled:{},rejected:{},stale:{}};function j(e,t){return void 0!==A[e][t]}function L(e,t){return A[e][t]??e}function q(e,t){return e>=t.lower&&e<=t.upper}function N(e,t){if(!Number.isFinite(e))return{ok:!1,code:"QTY_INVALID",reason:"quantity must be a finite number"};if(e<=0)return{ok:!1,code:"QTY_INVALID",reason:"quantity must be positive"};const i=t.lotSize??(!0===t.allowFractionalQty?void 0:1);return void 0!==i&&function(e,t){if(!Number.isFinite(t)||t<=0)return!1;const i=e/t,r=Math.round(i);if(!Number.isSafeInteger(r)||r<1)return!0;if(r*t===e)return!1;const s=Math.min(1e-7,8*Number.EPSILON*Math.max(1,Math.abs(i)));return Math.abs(i-r)>s}(e,i)?{ok:!1,code:"QTY_STEP",reason:void 0!==t.lotSize?`quantity ${e} is not a multiple of lot size ${t.lotSize}`:`quantity ${e} must be a whole number`}:void 0!==t.freezeQty&&e>t.freezeQty?{ok:!1,code:"QTY_FREEZE_LIMIT",reason:`quantity ${e} exceeds freeze limit ${t.freezeQty}`}:{ok:!0}}function B(e,t){if(!Number.isFinite(e))return{ok:!1,code:"PRICE_INVALID",reason:"price must be a finite number"};const i=t.tickSchedule;if(null!=i&&"function"!=typeof i.round)throw new TypeError("OrderConstraints.tickSchedule must be built with new TickSchedule(bands)");const r=i?i.round(e):(s=e,(o=t.tickSize)<=0?s:Math.round(s/o)*o);var s,o;return t.priceBand&&!q(r,t.priceBand)?{ok:!1,code:"PRICE_OUT_OF_BAND",reason:`price ${r} outside band ${t.priceBand.lower} to ${t.priceBand.upper}`}:{ok:!0,price:r}}function C(e,t,i){const r=N(t,i);return r.ok?void 0===e?{ok:!0}:B(e,i):r}const E=e=>String(e?.message??e),F=e=>"string"==typeof e&&""!==e.trim();function R(e){return"object"==typeof e&&null!==e&&!0===e.preflight}function Q(e){return"object"==typeof e&&null!==e&&!0===e.rejected}const U=["stop","target"],D={stop:"stopLoss",target:"takeProfit"},z=new Set(["SUBMITTING","SUBMITTED","AMBIGUOUS","RECONCILING"]),G=["estimatedPrice","estimatedValue","marginRequired","marginAvailableAfter","fees","asOf"];function Y(e){if(void 0===e)return;const t=e=>{if(!e||"object"!=typeof e||Array.isArray(e)||"then"in e)return e;const{orderTypes:t,...i}=e;return i};return"function"==typeof e?i=>t(e(i)):t(e)}const W={pending:void 0,working:"ack",partial:"partialFill",filled:"fill",cancelled:"cancelled",rejected:"reject"},H=new Set(["filled","cancelled","rejected"]);class K{constructor(e){Object.defineProperty(this,"_feed",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_capabilities",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_features",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_selectedAccount",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_confirmCommand",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_clock",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_constraints",{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,"_armed",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_gate",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_minModifyMs",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_now",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_idGen",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_onValidationError",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_maxSettled",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_orders",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"_byBroker",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"_sentTokens",{enumerable:!0,configurable:!0,writable:!0,value:new Set}),Object.defineProperty(this,"_lastModifyAt",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"_pendingModify",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"_settledIds",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"_heldLegs",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"_counter",{enumerable:!0,configurable:!0,writable:!0,value:0}),this._feed=e.feed,this._capabilities=e.capabilities,this._features=e.features,this._selectedAccount=e.selectedAccount,this._confirmCommand=e.confirmCommand,this._clock=e.clock??(()=>Date.now()/1e3),this._constraints=e.constraints,this._mode=e.mode??"live",this._armed=e.armed??!1,this._gate=e.gate,this._minModifyMs=e.minModifyIntervalMs??150,this._now=e.now??(()=>"undefined"!=typeof performance?performance.now():0),this._idGen=e.idGen??(()=>"c"+ ++this._counter),this._onValidationError=e.onValidationError,this._maxSettled=Math.max(0,e.maxSettledOrders??500)}get mode(){return this._mode}state(e){return this._orders.get(e)?.state}intentState(e){return this._orders.get(e)?.intent}brokerStatus(e){return this._orders.get(e)?.brokerStatus}orderKind(e){return this._orders.get(e)?.kind}orderAccount(e){return this._orders.get(e)?.req.account}bracketLegs(e){const t=this._orders.get(e)?.legs;return void 0===t?void 0:{...t}}_capability(t){const i=e(this._feed.capabilities,t);return i.supported?e(this._capabilities,t):i}_orderCapability(e,t){return this._capability({operation:e,symbol:t.req.symbol,exchange:t.req.exchange,type:t.req.type,mode:this._mode,orderId:t.brokerId})}_feature(e){const t=x(this._feed.features,e);return t.supported&&void 0!==this._features?x(this._features,e):t}_featureRequest(e,t){return{feature:e,symbol:t.symbol,exchange:t.exchange,account:t.account,mode:this._mode,type:t.type,duration:t.duration}}_account(e){if(void 0===this._selectedAccount&&void 0===e.account)return null;const t=this._feature({feature:"accounts",account:e.account,mode:this._mode});if(!t.supported)return t.reason;if(void 0!==this._selectedAccount){const t=this._selection();if(!t.ok)return t.reason;if(void 0!==e.account&&e.account!==t.id)return`The order names account ${e.account} but ${t.id} is selected`;e.account=t.id}return F(e.account)?null:"The account id must be a non-empty string"}_selection(){const e=this._selectedAccount;if("function"==typeof e){const t=e();return F(t)?{ok:!0,id:t}:{ok:!1,reason:"No account is selected"}}const t=e.getState(),i=t.selectedId;if(!F(i))return{ok:!1,reason:"No account is selected"};const r=t.mode!==this._mode?t.mode:t.accounts.find(e=>e.id===i)?.mode??t.mode;return r===this._mode?{ok:!0,id:i}:{ok:!1,reason:`The selected account ${i} is in ${r} mode, not ${this._mode}`}}_accountStill(e){if(void 0===this._selectedAccount)return null;const t=this._selection();return t.ok&&t.id===e.account?null:"The account changed before the order was sent; nothing was sent"}_schema(e){const t=e.duration;if(void 0!==t){if(!v.includes(t))return`Unknown duration ${String(t)}`;const i=this._feature(this._featureRequest("duration",e));if(!i.supported)return i.reason}if("GTD"===t&&void 0===e.expiresAt)return"A GTD order needs an expiry";if(void 0!==e.expiresAt){if("GTD"!==t)return"An expiry needs the GTD duration";if(!Number.isFinite(e.expiresAt)||e.expiresAt<=this._clock())return"The expiry is not in the future"}if(void 0!==e.leverage){if(!Number.isFinite(e.leverage)||e.leverage<=0)return"Leverage must be a positive number";const t=this._feature(this._featureRequest("leverage",e));if(!t.supported)return t.reason}return null}_permitOrder(e){const t=this._capability({operation:"place",symbol:e.symbol,exchange:e.exchange,type:e.type,mode:this._mode});return t.supported?this._schema(e):t.reason}_validate(e){const t=C(e.price,e.qty,this._constraints);if(!t.ok)return{ok:!1,reason:t.reason??"invalid order"};const i=void 0===e.price?void 0:t.price;let r=e.triggerPrice;if(void 0!==e.triggerPrice){const t=C(e.triggerPrice,e.qty,this._constraints);if(!t.ok)return{ok:!1,reason:`trigger: ${t.reason}`};r=t.price}return{ok:!0,price:i,triggerPrice:r}}_duplicate(e){if(!this._sentTokens.has(e))return null;const t=this._orders.get(e);return{ok:!1,reason:"AMBIGUOUS"===t?.intent?"duplicate clientToken: the first attempt was never confirmed and may be live":"duplicate clientToken (idempotent skip)",clientId:e,state:t?.state,intent:t?.intent}}async _confirmed(e,t){let i=!1;try{i=await(t?t():Promise.resolve(!1))}catch(t){throw this._release(e),t}return i||this._release(e),i}_release(e){for(const t of e)this._sentTokens.delete(t)}_submitted(e,t){void 0===e.brokerId&&this._bind(e,t),void 0===e.brokerStatus&&(e.state=L(e.state,"ack"),e.intent="SUBMITTED")}_failed(e,t){const i=E(t),r=R(t);return r||void 0===e.brokerStatus?!r&&Q(t)?(e.brokerStatus="rejected",e.state=L(e.state,"reject"),e.intent="SETTLED",this._settle(e),`rejected by the broker: ${i}`):(e.state=L(e.state,"reject"),e.intent=r?"BLOCKED":"AMBIGUOUS",r&&this._sentTokens.delete(e.clientId),this._settle(e),r?i:`${i} (may have reached the broker; check the order book before retrying)`):i}_writeFailed(e,t,i,r,s){R(t)?(e.intent===i&&(e.state=r,e.intent=s),this._onValidationError?.(E(t))):(e.state=L(e.state,"reject"),e.intent="AMBIGUOUS")}_outcome(e,t){return{ok:void 0===t||void 0!==e.brokerStatus&&"rejected"!==e.brokerStatus,clientId:e.clientId,state:e.state,intent:e.intent,...void 0===t?{}:{reason:t}}}async placeOrder(e){const t={...e},i=this._validate(t);if(!i.ok)return{ok:!1,reason:i.reason,intent:"BLOCKED"};const r=t.clientToken??this._idGen(),s=this._duplicate(r);if(null!==s)return s;const o=this._permitOrder(t)??this._account(t);if(null!==o)return{ok:!1,reason:o,intent:"BLOCKED"};this._sentTokens.add(r);const n=this._gate;if(!this._armed&&!await this._confirmed([r],n?()=>n({...t}):void 0))return{ok:!1,reason:"not confirmed",intent:"BLOCKED"};const a=this._permitOrder(t)??this._accountStill(t);if(null!==a)return this._sentTokens.delete(r),{ok:!1,reason:a,intent:"BLOCKED"};const c={...t,price:i.price,triggerPrice:i.triggerPrice,clientToken:r},d={clientId:r,kind:"order",state:"pending_place",intent:"SUBMITTING",req:c,writeRevision:0};this._orders.set(r,d);try{const{orderId:e}=await this._feed.place({...c,mode:this._mode});return this._submitted(d,e),this._outcome(d)}catch(e){return this._outcome(d,this._failed(d,e))}}async previewOrder(e){const t={...e},i=this._feature(this._featureRequest("preview",t));if(!i.supported)return{ok:!1,unsupported:!0,reason:i.reason};const r=this._feed.previewOrder;if(void 0===r)return{ok:!1,unsupported:!0,reason:"Order preview is not implemented by this feed"};const s=this._validate(t);if(!s.ok)return{ok:!1,reason:s.reason};const o=this._permitOrder(t)??this._account(t);if(null!==o)return{ok:!1,reason:o};const n={...t,price:s.price,triggerPrice:s.triggerPrice},a={ok:!1,stale:!0,reason:"The account changed during the preview; preview again"};let c;try{c=await r.call(this._feed,{...n,mode:this._mode})}catch(e){return null===this._accountStill(n)?{ok:!1,reason:E(e)}:a}if(null!==this._accountStill(n))return a;const d=function(e){if("object"!=typeof e||null===e)return"preview";const t=e,i={};for(const e of G)if(void 0!==t[e]){if("number"!=typeof t[e]||!Number.isFinite(t[e]))return e;i[e]=t[e]}for(const e of["accountId","currency","rejectReason"])if(void 0!==t[e]){if("string"!=typeof t[e])return e;i[e]=t[e]}if(void 0!==t.warnings){if(!Array.isArray(t.warnings)||!t.warnings.every(e=>"string"==typeof e))return"warnings";i.warnings=[...t.warnings]}return i}(c);return"string"==typeof d?{ok:!1,reason:`The preview could not be read: ${d}`}:void 0!==d.accountId&&void 0!==n.account&&d.accountId!==n.account?{ok:!1,stale:!0,reason:`The preview answered for account ${d.accountId}, not ${n.account}`}:{ok:!0,preview:d,request:n}}closePosition(e){const t=this._feed.closePosition;return this._positionCommand("close",{...e},void 0===e.qty?"close":"partialClose",void 0===t?void 0:e=>t.call(this._feed,{...e,mode:this._mode}))}reversePosition(e){const t=this._feed.reversePosition;return this._positionCommand("reverse",{...e},"reverse",void 0===t?void 0:e=>t.call(this._feed,{...e,mode:this._mode}))}static _samePosition(e,t){return e.symbol===t.symbol&&(e.account??"")===(t.account??"")&&(void 0===e.exchange||void 0===t.exchange||e.exchange===t.exchange)}_permitCommand(t,i,r,s){const o={operation:"place",symbol:i.symbol,exchange:i.exchange,mode:this._mode};for(const t of[this._feed.capabilities,this._capabilities]){const i=e(Y(t),o);if(!i.supported)return i.reason}const n=this._feature(this._featureRequest(r,i));if(!n.supported)return n.reason;if(!s)return("close"===t?"Closing a position":"Reversing a position")+" is not implemented by this feed";for(const e of this._orders.values())if(("close"===e.kind||"reverse"===e.kind)&&z.has(e.intent)&&K._samePosition(e.req,i))return`A previous close or reverse for ${i.symbol} is unresolved; reconcile it with the broker first`;return null}async _positionCommand(e,t,i,r){const s=t=>({ok:!1,kind:e,reason:t,intent:"BLOCKED"});if(!F(t.symbol))return s(`A ${e} needs a symbol`);if(void 0!==t.qty){const e=N(t.qty,this._constraints);if(!e.ok)return s(e.reason??"invalid quantity")}const o=t.clientToken??this._idGen(),n=this._duplicate(o);if(null!==n)return{...n,kind:e};const a=this._account(t)??this._permitCommand(e,t,i,void 0!==r);if(null!==a)return s(a);this._sentTokens.add(o);const c={...t,clientToken:o},d=this._confirmCommand;if(!this._armed&&!await this._confirmed([o],d?()=>d({kind:e,request:{...c}}):void 0))return s("not confirmed");const l=this._accountStill(c)??this._permitCommand(e,c,i,void 0!==r);if(null!==l)return this._sentTokens.delete(o),s(l);const u={clientId:o,kind:e,state:"pending_place",intent:"SUBMITTING",writeRevision:0,req:{symbol:c.symbol,exchange:c.exchange,qty:c.qty,account:c.account}};this._orders.set(o,u);try{const t=await r(c);return F(t?.commandId)?(this._submitted(u,t.commandId),{...this._outcome(u),kind:e}):{...this._outcome(u,this._failed(u,new Error("the broker returned no command id"))),kind:e}}catch(t){return{...this._outcome(u,this._failed(u,t)),kind:e}}}async placeBracket(e){const t={...e},i=e=>({ok:!1,kind:"bracket",reason:e,intent:"BLOCKED"}),r=this._validate(t);if(!r.ok)return i(r.reason);const s=B(t.stopLoss,this._constraints);if(!s.ok)return i(`stop: ${s.reason}`);const o=B(t.takeProfit,this._constraints);if(!o.ok)return i(`target: ${o.reason}`);const n=s.price??t.stopLoss,a=o.price??t.takeProfit,c="SL-M"===t.type?r.triggerPrice:r.price,d="BUY"===t.side,[l,u]=d?[n,a]:[a,n];if(!(l<u&&(void 0===c||l<c&&c<u)))return i("The stop and target are on the wrong side of the entry");const h=t.clientToken??this._idGen(),f={stopLoss:`${h}:stop`,takeProfit:`${h}:target`},p=[h,f.stopLoss,f.takeProfit];for(const e of p){const t=this._duplicate(e);if(null!==t)return{...t,kind:"bracket"}}const _=this._feed.placeBracket,b=()=>{const e=this._feature(this._featureRequest("brackets",t));return e.supported?void 0===_?"Bracket placement is not implemented by this feed":this._permitOrder(t):e.reason},m=this._account(t)??b();if(null!==m)return i(m);for(const e of p)this._sentTokens.add(e);const g={...t,price:r.price,triggerPrice:r.triggerPrice,stopLoss:n,takeProfit:a,clientToken:h},y=this._confirmCommand;if(!this._armed&&!await this._confirmed(p,y?()=>y({kind:"bracket",request:{...g}}):void 0))return i("not confirmed");const v=this._accountStill(g)??b();if(null!==v)return this._release(p),i(v);const k=d?"SELL":"BUY",w={symbol:t.symbol,exchange:t.exchange,side:k,qty:t.qty,account:t.account},x={clientId:h,kind:"bracket",state:"pending_place",intent:"SUBMITTING",req:g,writeRevision:0,legReqs:{stop:{...w,type:"SL-M",triggerPrice:n},target:{...w,type:"LIMIT",price:a}}};this._orders.set(h,x);const I=e=>({...this._outcome(x,e),kind:"bracket",...void 0===x.legs?{}:{legs:{...x.legs}}});let M;try{M=await _.call(this._feed,{...g,mode:this._mode,legClientTokens:f})}catch(e){const t=this._failed(x,e);return R(e)&&this._release(p),I(t)}if(!F(M?.orderId))return I(this._failed(x,new Error("the broker returned no order id")));this._submitted(x,M.orderId);for(const[e,t]of[["stop",M.stopLossId],["target",M.takeProfitId]])F(t)&&this._submitted(this._leg(x,e),t);return I()}_leg(e,t){const i=`${e.clientId}:${t}`;let r=this._orders.get(i);return void 0===r&&(r={clientId:i,kind:"stop"===t?"bracket-stop":"bracket-target",state:"pending_place",intent:"SUBMITTING",writeRevision:0,req:{...e.legReqs[t]}},this._orders.set(i,r)),e.legs={...e.legs,[D[t]]:i},r}placeMarket(e,t,i,r){return this.placeOrder({symbol:e,side:t,type:"MARKET",qty:i,exchange:r?.exchange,product:r?.product,clientToken:r?.clientToken})}linkOco(e,t){const i=this._orders.get(e),r=this._orders.get(t);i&&r&&(i.ocoPeer=t,r.ocoPeer=e)}requestModify(e,t,i){const r=i?.triggerPrice,s=this._orders.get(e);if(void 0===s||$(s.state))return;if(this._isPositionCommand(s))return;const o=this._orderCapability("modify",s);if(!o.supported)return this._pendingModify.delete(e),void this._onValidationError?.(o.reason);const n=this._buildModifyPatch(s,t,r);if(!n.ok)return void this._onValidationError?.(n.reason);this._pendingModify.set(e,n.patch);const a=this._lastModifyAt.get(e)??-1/0;this._now()-a>=this._minModifyMs&&this._flushModify(e)}commitModify(e){return this._flushModify(e)}_buildModifyPatch(e,t,i){const r=C(t,e.req.qty??Number.NaN,this._constraints);if(!r.ok)return{ok:!1,reason:r.reason??"invalid modify price"};const s=r.price??t;if("SL-M"===e.req.type){const t=i??s,r=this._validateTrigger(t,e.req.qty);return r.ok?{ok:!0,patch:{triggerPrice:r.price}}:r}if("SL"===e.req.type){const t=void 0!==e.req.triggerPrice&&void 0!==e.req.price?e.req.triggerPrice-e.req.price:0,r=i??s+t,o=this._validateTrigger(r,e.req.qty);return o.ok?{ok:!0,patch:{price:s,triggerPrice:o.price}}:o}if(void 0!==i){const t=this._validateTrigger(i,e.req.qty);return t.ok?{ok:!0,patch:{price:s,triggerPrice:t.price}}:t}return{ok:!0,patch:{price:s}}}_validateTrigger(e,t){const i=C(e,t??Number.NaN,this._constraints);return i.ok?{ok:!0,price:i.price??e}:{ok:!1,reason:`trigger: ${i.reason??"invalid"}`}}async _flushModify(e){const t=this._pendingModify.get(e),i=this._orders.get(e);if(void 0===t||void 0===i||void 0===i.brokerId)return;this._pendingModify.delete(e);const r=this._orderCapability("modify",i);if(!r.supported)return void this._onValidationError?.(r.reason);this._lastModifyAt.set(e,this._now());const s=i.state,o=i.intent,n=++i.writeRevision;i.state=L(i.state,"submitModify"),i.intent="MODIFY_SUBMITTING";try{if(await this._feed.modify(i.brokerId,{...t}),n!==i.writeRevision)return;i.state=L(i.state,"ack"),i.intent="ACKNOWLEDGED",void 0!==t.price&&(i.req={...i.req,price:t.price}),void 0!==t.triggerPrice&&(i.req={...i.req,triggerPrice:t.triggerPrice})}catch(e){n===i.writeRevision&&this._writeFailed(i,e,"MODIFY_SUBMITTING",s,o)}}async cancelOrder(e){const t=this._orders.get(e);if(void 0===t||void 0===t.brokerId||$(t.state))return;if(this._isPositionCommand(t))return;const i=this._orderCapability("cancel",t);if(!i.supported)return void this._onValidationError?.(i.reason);const r=t.state,s=t.intent,o=++t.writeRevision;t.state=L(t.state,"submitCancel"),t.intent="CANCEL_SUBMITTING";try{if(await this._feed.cancel(t.brokerId),o!==t.writeRevision)return;t.state=L(t.state,"cancelled"),t.intent="ACKNOWLEDGED",this._cancelOcoPeer(t),this._settle(t)}catch(e){o===t.writeRevision&&this._writeFailed(t,e,"CANCEL_SUBMITTING",r,s)}}onFill(e,t){this.onBrokerUpdate(e,t?"filled":"partial")}onBrokerUpdate(e,t){const i=this._byBroker.get(e);if(void 0===i)return;const r=this._orders.get(i);if(void 0===r)return;r.writeRevision++,r.brokerStatus=t,"AMBIGUOUS"===r.intent&&$(r.state)&&(r.state="pending_place"),"pending_place"===r.state&&"rejected"!==t&&(r.state=L(r.state,"ack"));const s=W[t];void 0!==s&&(r.state=L(r.state,s)),r.intent=H.has(t)?"SETTLED":"ACKNOWLEDGED","filled"===t&&this._cancelOcoPeer(r),this._settle(r)}onBrokerOrder(e){if(!this._byBroker.has(e.id)){const t=this._unbound(e);void 0===t?this._hold(e):void 0===t.brokerId&&this._bind(t,e.id)}this.onBrokerUpdate(e.id,e.status)}_bind(e,t){e.brokerId=t,this._byBroker.set(t,e.clientId);const i=this._heldLegs.get(t);if(void 0!==i&&(this._heldLegs.delete(t),void 0!==e.legReqs)){for(const e of i.values())this.onBrokerOrder(e);this._awaitingEntry()||this._heldLegs.clear()}}_hold(e){if(void 0===e.parentId||"sl"!==e.role&&"tp"!==e.role)return;if(!this._awaitingEntry())return void this._heldLegs.clear();let t=this._heldLegs.get(e.parentId);void 0===t&&(t=new Map,this._heldLegs.set(e.parentId,t),this._heldLegs.size>64&&this._heldLegs.delete(this._heldLegs.keys().next().value)),t.set(e.id,{...e})}_awaitingEntry(){for(const e of this._orders.values())if(void 0!==e.legReqs&&void 0===e.brokerId&&z.has(e.intent))return!0;return!1}_unbound(e){const t=e.clientToken;if(void 0!==t){const e=this._orders.get(t);if(void 0!==e)return e;for(const e of U){const i=t.endsWith(`:${e}`)&&this._sentTokens.has(t)?this._orders.get(t.slice(0,-e.length-1)):void 0;if(void 0!==i?.legReqs)return this._leg(i,e)}}const i="sl"===e.role?"stop":"tp"===e.role?"target":void 0,r=void 0===e.parentId?void 0:this._byBroker.get(e.parentId),s=void 0===r?void 0:this._orders.get(r);return void 0!==i&&void 0!==s?.legReqs?this._leg(s,i):void 0}releaseAmbiguous(e){const t=this._orders.get(e);if(void 0===t||"AMBIGUOUS"!==t.intent)return!1;if(this._orders.delete(e),this._sentTokens.delete(e),void 0!==t.legReqs){for(const t of U)this._orders.has(`${e}:${t}`)||this._sentTokens.delete(`${e}:${t}`);this._awaitingEntry()||this._heldLegs.clear()}return void 0!==t.brokerId&&this._byBroker.delete(t.brokerId),this._lastModifyAt.delete(e),this._pendingModify.delete(e),!0}_isPositionCommand(e){return("close"===e.kind||"reverse"===e.kind)&&(this._onValidationError?.(`A ${e.kind} command cannot be modified or cancelled`),!0)}_cancelOcoPeer(e){if(void 0===e.ocoPeer)return;const t=this._orders.get(e.ocoPeer);t&&!$(t.state)&&this.cancelOrder(t.clientId)}beginReconcile(){for(const e of this._orders.values())$(e.state)||"AMBIGUOUS"===e.intent||(e.writeRevision++,e.intent="RECONCILING")}onReconnect(e){for(const t of this._orders.values())$(t.state)||(t.writeRevision++,void 0!==t.brokerId&&e.has(t.brokerId)?t.intent="ACKNOWLEDGED":(t.state=L(t.state,"reconnectAbsent"),t.intent="AMBIGUOUS"))}_settle(e){if(!0!==e.pruned&&$(e.state)&&"AMBIGUOUS"!==e.intent&&"RECONCILING"!==e.intent)for(e.pruned=!0,this._lastModifyAt.delete(e.clientId),this._pendingModify.delete(e.clientId),this._settledIds.push(e.clientId);this._settledIds.length>this._maxSettled;){const e=this._settledIds.shift();if(void 0===e)break;const t=this._orders.get(e);void 0!==t&&!0===t.pruned&&(this._orders.delete(e),void 0!==t.brokerId&&this._byBroker.delete(t.brokerId),this._lastModifyAt.delete(e),this._pendingModify.delete(e))}}}const V="The account changed before the read finished",X="The connection dropped; account figures may be out of date",Z=["balance","equity","marginUsed","marginAvailable","unrealizedPnl","realizedPnl","leverage"],J=e=>"live"===e||"analyzer"===e;function ee(e){if("object"!=typeof e||null===e)return null;const t=e;return F(t.id)&&J(t.mode)?{id:t.id,mode:t.mode,...F(t.name)?{name:t.name}:{},...F(t.currency)?{currency:t.currency}:{}}:null}function te(e,t){if("object"!=typeof e||null===e)return null;const i=e,r=e=>"number"==typeof e&&Number.isFinite(e);return i.accountId===t&&F(i.id)&&F(i.orderId)&&F(i.symbol)?"BUY"!==i.side&&"SELL"!==i.side||!r(i.qty)||i.qty<=0||!r(i.price)||!r(i.time)?null:e:null}function ie(e,t){if("object"!=typeof e||null===e)return null;const i=e,r=i.order;return i.accountId===t&&"number"==typeof i.time&&Number.isFinite(i.time)&&"object"==typeof r&&null!==r&&F(r.id)&&F(r.symbol)?e:null}class re{constructor(e){Object.defineProperty(this,"_feed",{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,"_hostFeatures",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_initial",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_listeners",{enumerable:!0,configurable:!0,writable:!0,value:new Set}),Object.defineProperty(this,"_aborts",{enumerable:!0,configurable:!0,writable:!0,value:new Set}),Object.defineProperty(this,"_unsubscribe",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"_state",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_destroyed",{enumerable:!0,configurable:!0,writable:!0,value:!1}),this._feed=e.feed,this._mode=e.mode??"live",this._hostFeatures=e.features,this._initial=e.initialAccount;const t=this._support("accounts");this._state={status:null===t?"idle":"unsupported",...null===t?{}:{reason:t},mode:this._mode,accounts:[],selectedId:null,snapshot:null,generation:0}}get mode(){return this._mode}getState(){return this._state}selectedAccount(){return this._state.selectedId}subscribe(e){return this._listeners.add(e),()=>{this._listeners.delete(e)}}_support(e){const t={feature:e,mode:this._mode,account:this._state?.selectedId??void 0},i=x(this._feed.features,t);if(!i.supported)return i.reason;if(void 0!==this._hostFeatures){const e=x(this._hostFeatures,t);if(!e.supported)return e.reason}const r=this._feed;return("accounts"===e?void 0!==r.listAccounts&&void 0!==r.getAccountSnapshot:"executions"===e?void 0!==r.getExecutions:"orderHistory"!==e||void 0!==r.getOrderHistory)?null:("accounts"===e?"Account data":"executions"===e?"Execution history":"Order history")+" is not implemented by this feed"}_set(e){const t={...this._state,...e};void 0===e.reason&&"reason"in e&&delete t.reason;const i=t;this._state=i;for(const e of[...this._listeners])try{e(i)}catch{}}_advance(){for(const e of this._aborts)e.abort();return this._aborts=new Set,this._unsubscribe?.(),this._unsubscribe=null,this._state.generation+1}_controller(){const e=new AbortController;return this._aborts.add(e),e}async refresh(){if(this._destroyed)return{ok:!1,reason:"The account manager was destroyed"};const e=this._support("accounts");if(null!==e)return this._advance(),this._set({status:"unsupported",reason:e,accounts:[],selectedId:null,snapshot:null,generation:this._state.generation+1}),{ok:!1,reason:e};const t=this._advance(),i=this._state.status,r="stale"===i||"ready"===i?this._state.snapshot:null;this._set({status:null===r?"loading":i,generation:t,...null===r?{reason:void 0}:{}});const s=this._controller();let o;try{const e=await this._feed.listAccounts(s.signal);if(this._state.generation!==t||this._destroyed)return{ok:!1,reason:V,cancelled:!0};o=(Array.isArray(e)?e:[]).map(ee).filter(e=>null!==e&&e.mode===this._mode)}catch(e){if(this._state.generation!==t||this._destroyed)return{ok:!1,reason:V,cancelled:!0};const i=`Could not list accounts: ${E(e)}`;return this._set(null===r?{status:"error",reason:i}:{status:"stale",reason:X}),{ok:!1,reason:i}}finally{this._aborts.delete(s)}const n=this._state.selectedId,a=o.find(e=>e.id===n)??o.find(e=>e.id===this._initial)??o[0];if(void 0===a){const e=`The provider listed no ${this._mode} account`;return this._set({status:"error",reason:e,accounts:[],selectedId:null,snapshot:null}),{ok:!1,reason:e}}return this._set({accounts:o}),this._load(a.id,t,null!==r&&r.accountId===a.id?r:null)}async select(e){if(this._destroyed)return{ok:!1,reason:"The account manager was destroyed"};const t=this._support("accounts");return null!==t?{ok:!1,reason:t}:this._state.accounts.some(t=>t.id===e)?this._load(e,this._advance(),null):{ok:!1,reason:`Account ${e} is not available in ${this._mode} mode`}}async _load(e,t,i){this._set({selectedId:e,snapshot:i,generation:t,status:null===i?"loading":this._state.status});const r=this._controller();let s;try{const i=await this._feed.getAccountSnapshot(e,r.signal);if(this._state.generation!==t||this._destroyed)return{ok:!1,reason:V,cancelled:!0};const o=this._accept(i,e);if("string"==typeof o)return this._set({status:"error",reason:o,snapshot:null}),{ok:!1,reason:o};s=o}catch(r){if(this._state.generation!==t||this._destroyed)return{ok:!1,reason:V,cancelled:!0};const s=`Could not load account ${e}: ${E(r)}`;return this._set(null===i?{status:"error",reason:s}:{status:"stale",reason:X}),{ok:!1,reason:s}}finally{this._aborts.delete(r)}return this._set({status:"ready",reason:void 0,snapshot:s}),this._stream(e,t),{ok:!0,snapshot:s}}_accept(e,t){const i=function(e){if("object"!=typeof e||null===e)return"snapshot";const t=e;if(!F(t.accountId))return"accountId";if(!J(t.mode))return"mode";if("number"!=typeof t.asOf||!Number.isFinite(t.asOf))return"asOf";const i={accountId:t.accountId,mode:t.mode,asOf:t.asOf};F(t.currency)&&(i.currency=t.currency);for(const e of Z){const r=t[e];if(void 0!==r){if("number"!=typeof r||!Number.isFinite(r))return e;i[e]=r}}return i}(e);return"string"==typeof i?`The account snapshot could not be read: ${i}`:i.accountId!==t?`The provider answered for account ${i.accountId}, not ${t}`:i.mode!==this._mode?`The provider returned figures from the ${i.mode} ledger for this ${this._mode} view`:i}_stream(e,t){const i=this._feed.subscribeAccount;if(void 0===i)return;const r=()=>!this._destroyed&&this._state.generation===t&&this._state.selectedId===e;try{this._unsubscribe=i.call(this._feed,e,t=>{if(!r())return;const i=this._accept(t,e);if("string"==typeof i)return;const s=this._state.snapshot;null!==s&&i.asOf<s.asOf||this._set({status:"ready",reason:void 0,snapshot:i})},()=>{r()&&this.disconnected()})}catch{this._unsubscribe=null}}disconnected(e=X){if(this._destroyed||"unsupported"===this._state.status)return;const t=this._advance(),i=this._state.snapshot;this._set(null===i?{status:"error",reason:e,generation:t}:{status:"stale",reason:e,generation:t})}reconnect(){return this.refresh()}positions(){return this._read("accounts",(e,t)=>this._feed.getAccountPositions?.(e,t),(e,t)=>{const i=e;return null===i||"object"!=typeof i||void 0!==i.accountId&&i.accountId!==t?null:F(i.symbol)&&Number.isFinite(i.netQty)&&Number.isFinite(i.avgPrice)?e:null})}executions(e={}){return this._read("executions",(t,i)=>this._feed.getExecutions({...e,accountId:t},i),te)}orderHistory(e={}){return this._read("orderHistory",(t,i)=>this._feed.getOrderHistory({...e,accountId:t},i),ie)}async _read(e,t,i){if(this._destroyed)return{ok:!1,reason:"The account manager was destroyed",cancelled:!0};const r=this._support("accounts")??("accounts"===e?null:this._support(e));if(null!==r)return{ok:!1,reason:r,unsupported:!0};const s=this._state.selectedId;if(null===s)return{ok:!1,reason:"No account is selected"};const o=this._state.generation,n=this._controller();try{const e=t(s,n.signal);if(void 0===e)return{ok:!1,reason:"Account positions are not implemented by this feed",unsupported:!0};const r=await e;if(this._destroyed||this._state.generation!==o)return{ok:!1,reason:V,cancelled:!0};const a=[],c=Array.isArray(r)?r:[];for(const e of c){const t=i(e,s);null!==t&&a.push(t)}return{ok:!0,accountId:s,rows:a,dropped:c.length-a.length}}catch(e){return this._destroyed||this._state.generation!==o?{ok:!1,reason:V,cancelled:!0}:{ok:!1,reason:E(e)}}finally{this._aborts.delete(n)}}destroy(){this._destroyed||(this._advance(),this._destroyed=!0,this._listeners.clear())}}function se(e){const{priceTick:t,quantityStep:i}=e.metadata,r=e.tickSchedule;return{tickSize:t,lotSize:i,allowFractionalQty:!Number.isInteger(i),...r?{tickSchedule:r}:{}}}function oe(e){const t=Math.max(e.bids.length,e.asks.length);return 0===t?"none":t<=5?"compact":"deep"}function ne(e){return new TypeError(`${e} takes a tick size or a schedule built with new TickSchedule(bands)`)}function ae(e,t,i=1){let r;if(function(e){return"object"==typeof e&&null!==e}(t)){if("function"!=typeof t.round)throw ne("buildRows");s=t,o=i>1?Math.floor(i):1,r=e=>{const t=s.round(e),{bands:i}=s;if(1===o||!Number.isFinite(t))return t;let r=i.length-1;for(;r>0&&t<i[r].from;)r--;const n=i[r],a=n.tick*o,c=n.from??-1/0,d=i[r+1]?.from??1/0;return s.round(Math.min(Math.max(Math.round(t/a)*a,c),d))}}else{const e=t*Math.max(1,i);r=t=>Math.round(Math.round(t/e)*e*1e8)/1e8}var s,o;const n=new Map,a=(e,t,i)=>{const s=r(e);let o=n.get(s);void 0===o&&(o={price:s,bidQty:0,askQty:0},n.set(s,o)),"bid"===i?o.bidQty+=t:o.askQty+=t};for(const t of e.bids)a(t.price,t.qty,"bid");for(const t of e.asks)a(t.price,t.qty,"ask");return Array.from(n.values()).sort((e,t)=>t.price-e.price)}function ce(e,t,i,r,s){const o=e.filter(e=>{const s=t(e.price);return s>=-r&&s<=i+r});if(o.length<=s)return o;const n=i/2;return o.map(e=>({r:e,d:Math.abs(t(e.price)-n)})).sort((e,t)=>e.d-t.d).slice(0,s).map(e=>e.r).sort((e,t)=>t.price-e.price)}const de={tickSize:.05,width:96,groupBy:1,maxRows:60,rowHeight:14};class le{constructor(e={}){Object.defineProperty(this,"_opts",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"_depth",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"_host",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"_rowHits",{enumerable:!0,configurable:!0,writable:!0,value:[]}),this._opts={...de,...e};const t=this._opts.tickSchedule;if(null!=t&&"function"!=typeof t.round)throw ne("DomLadder tickSchedule")}attached(e){this._host=e}detached(){this._host=null}zOrder(){return"top"}setDepth(e){this._depth=e,this._host?.requestUpdate()}tier(){return null===this._depth?"none":oe(this._depth)}draw(e,t){if(this._rowHits=[],null===this._depth)return;const i=ce(ae(this._depth,this._opts.tickSchedule??this._opts.tickSize,this._opts.groupBy),e=>t.priceScale.priceToY(e),t.plotHeight,this._opts.rowHeight,this._opts.maxRows);if(0===i.length)return;const r=t.dpr,s=this._opts.width*r,o=(t.plotWidth-this._opts.width)*r,n=o+s/2,d=this._opts.rowHeight*r;let u=1;for(const e of i)u=Math.max(u,e.bidQty,e.askQty);const h=a(t.theme.buy)??{r:38,g:166,b:154},f=a(t.theme.sell)??{r:239,g:83,b:80},p=l(c("transparent"===t.theme.background?"#808080":t.theme.background),.9);e.save(),e.strokeStyle=l(t.theme.axisLine,.6),e.lineWidth=Math.max(1,Math.round(r)),e.beginPath(),e.moveTo(Math.round(o)+.5,0),e.lineTo(Math.round(o)+.5,Math.round(t.plotHeight*r)),e.stroke(),e.font=9*r+"px system-ui, sans-serif",e.textBaseline="middle";for(const a of i){const i=t.priceScale.priceToY(a.price)*r,c=t.hoverId===`ladder-bid:${a.price}`,_=t.hoverId===`ladder-ask:${a.price}`;if(a.bidQty>0){e.fillStyle=`rgba(${h.r},${h.g},${h.b},${.15+a.bidQty/u*.5+(c?.15:0)})`;const l=s/2*(a.bidQty/u);e.fillRect(n-l,i-d/2,l,d-1),e.fillStyle=p,e.textAlign="left",e.fillText(String(a.bidQty),o+2*r,i),this._rowHits.push({price:a.price,y:t.priceScale.priceToY(a.price),side:"bid"})}if(a.askQty>0){e.fillStyle=`rgba(${f.r},${f.g},${f.b},${.15+a.askQty/u*.5+(_?.15:0)})`;const c=s/2*(a.askQty/u);e.fillRect(n,i-d/2,c,d-1),e.fillStyle=p,e.textAlign="right",e.fillText(String(a.askQty),o+s-2*r,i),this._rowHits.push({price:a.price,y:t.priceScale.priceToY(a.price),side:"ask"})}(c||_)&&(e.strokeStyle=l(c?t.theme.buy:t.theme.sell,.9),e.lineWidth=Math.max(1,Math.round(r)),e.strokeRect(c?o+.5:n+.5,i-d/2+.5,s/2-1,d-2))}e.restore()}hitTest(e,t,i){if(null===this._depth)return null;if(e<i.plotWidth-this._opts.width||e>i.plotWidth)return null;let r=null;for(const e of this._rowHits){const i=Math.abs(e.y-t);i<=this._opts.rowHeight/2&&(null===r||i<r.d)&&(r={price:e.price,side:e.side,d:i})}return null===r?null:{externalId:`ladder-${r.side}:${r.price}`,zOrder:"top",distance:r.d,cursor:"pointer"}}}const ue="trade";export{re as AccountManager,g as BracketGroup,de as DEFAULT_DOM_LADDER_OPTIONS,le as DomLadder,O as FakeBroker,v as ORDER_DURATIONS,K as OrderEngine,m as PositionMarker,ue as TRADE_TIER,y as TradeController,b as WorkingOrderLine,n as bracketValid,s as breakeven,ae as buildRows,j as canTransition,x as checkTradingFeature,Q as isBrokerRejection,R as isPreflightFailure,$ as isTerminal,t as isWorking,oe as ladderCapability,se as orderConstraintsForInstrument,o as riskReward,w as tradingFeatureLabel,L as transition,i as unrealizedPnl,r as unrealizedPnlPercent,C as validateOrder,B as validatePrice,N as validateQuantity,ce as visibleRows,q as withinPriceBand};
//# sourceMappingURL=openalgo-charts.trade.mjs.map