@aetherwealth/mcp 0.1.35 → 0.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -133,7 +133,7 @@ local process. Set `MCP_TRANSPORT=http`, `MCP_HTTP_AUTH=oauth`, and
|
|
|
133
133
|
|
|
134
134
|
| Tool | Purpose |
|
|
135
135
|
| --- | --- |
|
|
136
|
-
| `get_candles` | Fetch
|
|
136
|
+
| `get_candles` | Fetch OHLC candles for a pair and timeframe. Returns up to 200 plus `nextCursor`; pass it back as `cursor` until null to cover the complete stored history, including server-derived timeframes such as `3m`. |
|
|
137
137
|
| `list_economic_calendar` | List economic calendar events by currency, release, date, or impact. |
|
|
138
138
|
| `get_macro_series` | Fetch macro indicator time series such as CPI or interest-rate data. |
|
|
139
139
|
| `get_macro_indicator` | Fetch curated FXMacroData indicator series with unit and target metadata. |
|
package/dist/index.js
CHANGED
|
@@ -103,9 +103,9 @@ data:
|
|
|
103
103
|
`,$.enqueue(v.encode(U)),!0}catch(U){return this.onerror?.(U),!1}}handleUnsupportedRequest(){return this.onerror?.(Error("Method not allowed.")),new Response(JSON.stringify({jsonrpc:"2.0",error:{code:-32000,message:"Method not allowed."},id:null}),{status:405,headers:{Allow:"GET, POST, DELETE","Content-Type":"application/json"}})}async handlePostRequest($,v){try{let D=$.headers.get("accept");if(!D?.includes("application/json")||!D.includes("text/event-stream"))return this.onerror?.(Error("Not Acceptable: Client must accept both application/json and text/event-stream")),this.createJsonErrorResponse(406,-32000,"Not Acceptable: Client must accept both application/json and text/event-stream");let X=$.headers.get("content-type");if(!X||!X.includes("application/json"))return this.onerror?.(Error("Unsupported Media Type: Content-Type must be application/json")),this.createJsonErrorResponse(415,-32000,"Unsupported Media Type: Content-Type must be application/json");let U={headers:Object.fromEntries($.headers.entries()),url:new URL($.url)},G;if(v?.parsedBody!==void 0)G=v.parsedBody;else try{G=await $.json()}catch{return this.onerror?.(Error("Parse error: Invalid JSON")),this.createJsonErrorResponse(400,-32700,"Parse error: Invalid JSON")}let J;try{if(Array.isArray(G))J=G.map((Z)=>iv.parse(Z));else J=[iv.parse(G)]}catch{return this.onerror?.(Error("Parse error: Invalid JSON-RPC message")),this.createJsonErrorResponse(400,-32700,"Parse error: Invalid JSON-RPC message")}let Q=J.some(VW);if(Q){if(this._initialized&&this.sessionId!==void 0)return this.onerror?.(Error("Invalid Request: Server already initialized")),this.createJsonErrorResponse(400,-32600,"Invalid Request: Server already initialized");if(J.length>1)return this.onerror?.(Error("Invalid Request: Only one initialization request is allowed")),this.createJsonErrorResponse(400,-32600,"Invalid Request: Only one initialization request is allowed");if(this.sessionId=this.sessionIdGenerator?.(),this._initialized=!0,this.sessionId&&this._onsessioninitialized)await Promise.resolve(this._onsessioninitialized(this.sessionId))}if(!Q){let Z=this.validateSession($);if(Z)return Z;let H=this.validateProtocolVersion($);if(H)return H}if(!J.some(J6)){for(let Z of J)this.onmessage?.(Z,{authInfo:v?.authInfo,requestInfo:U});return new Response(null,{status:202})}let W=crypto.randomUUID(),z=J.find((Z)=>VW(Z)),Y=z?z.params.protocolVersion:$.headers.get("mcp-protocol-version")??KB;if(this._enableJsonResponse)return new Promise((Z)=>{this._streamMapping.set(W,{resolveJson:Z,cleanup:()=>{this._streamMapping.delete(W)}});for(let H of J)if(J6(H))this._requestToStreamMapping.set(H.id,W);for(let H of J)this.onmessage?.(H,{authInfo:v?.authInfo,requestInfo:U})});let B=new TextEncoder,V,L=new ReadableStream({start:(Z)=>{V=Z},cancel:()=>{this._streamMapping.delete(W)}}),N={"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"};if(this.sessionId!==void 0)N["mcp-session-id"]=this.sessionId;for(let Z of J)if(J6(Z))this._streamMapping.set(W,{controller:V,encoder:B,cleanup:()=>{this._streamMapping.delete(W);try{V.close()}catch{}}}),this._requestToStreamMapping.set(Z.id,W);await this.writePrimingEvent(V,B,W,Y);for(let Z of J){let H,S;if(J6(Z)&&this._eventStore&&Y>="2025-11-25")H=()=>{this.closeSSEStream(Z.id)},S=()=>{this.closeStandaloneSSEStream()};this.onmessage?.(Z,{authInfo:v?.authInfo,requestInfo:U,closeSSEStream:H,closeStandaloneSSEStream:S})}return new Response(L,{status:200,headers:N})}catch(D){return this.onerror?.(D),this.createJsonErrorResponse(400,-32700,"Parse error",{data:String(D)})}}async handleDeleteRequest($){let v=this.validateSession($);if(v)return v;let D=this.validateProtocolVersion($);if(D)return D;return await Promise.resolve(this._onsessionclosed?.(this.sessionId)),await this.close(),new Response(null,{status:200})}validateSession($){if(this.sessionIdGenerator===void 0)return;if(!this._initialized)return this.onerror?.(Error("Bad Request: Server not initialized")),this.createJsonErrorResponse(400,-32000,"Bad Request: Server not initialized");let v=$.headers.get("mcp-session-id");if(!v)return this.onerror?.(Error("Bad Request: Mcp-Session-Id header is required")),this.createJsonErrorResponse(400,-32000,"Bad Request: Mcp-Session-Id header is required");if(v!==this.sessionId)return this.onerror?.(Error("Session not found")),this.createJsonErrorResponse(404,-32001,"Session not found");return}validateProtocolVersion($){let v=$.headers.get("mcp-protocol-version");if(v!==null&&!N1.includes(v))return this.onerror?.(Error(`Bad Request: Unsupported protocol version: ${v} (supported versions: ${N1.join(", ")})`)),this.createJsonErrorResponse(400,-32000,`Bad Request: Unsupported protocol version: ${v} (supported versions: ${N1.join(", ")})`);return}async close(){this._streamMapping.forEach(({cleanup:$})=>{$()}),this._streamMapping.clear(),this._requestResponseMap.clear(),this.onclose?.()}closeSSEStream($){let v=this._requestToStreamMapping.get($);if(!v)return;let D=this._streamMapping.get(v);if(D)D.cleanup()}closeStandaloneSSEStream(){let $=this._streamMapping.get(this._standaloneSseStreamId);if($)$.cleanup()}async send($,v){let D=v?.relatedRequestId;if(_4($)||Z1($))D=$.id;if(D===void 0){if(_4($)||Z1($))throw Error("Cannot send a response on a standalone SSE stream unless resuming a previous client request");let G;if(this._eventStore)G=await this._eventStore.storeEvent(this._standaloneSseStreamId,$);let J=this._streamMapping.get(this._standaloneSseStreamId);if(J===void 0)return;if(J.controller&&J.encoder)this.writeSSEEvent(J.controller,J.encoder,$,G);return}let X=this._requestToStreamMapping.get(D);if(!X)throw Error(`No connection established for request ID: ${String(D)}`);let U=this._streamMapping.get(X);if(!this._enableJsonResponse&&U?.controller&&U?.encoder){let G;if(this._eventStore)G=await this._eventStore.storeEvent(X,$);this.writeSSEEvent(U.controller,U.encoder,$,G)}if(_4($)||Z1($)){this._requestResponseMap.set(D,$);let G=Array.from(this._requestToStreamMapping.entries()).filter(([Q,I])=>I===X).map(([Q])=>Q);if(G.every((Q)=>this._requestResponseMap.has(Q))){if(!U)throw Error(`No connection established for request ID: ${String(D)}`);if(this._enableJsonResponse&&U.resolveJson){let Q={"Content-Type":"application/json"};if(this.sessionId!==void 0)Q["mcp-session-id"]=this.sessionId;let I=G.map((W)=>this._requestResponseMap.get(W));if(I.length===1)U.resolveJson(new Response(JSON.stringify(I[0]),{status:200,headers:Q}));else U.resolveJson(new Response(JSON.stringify(I),{status:200,headers:Q}))}else U.cleanup();for(let Q of G)this._requestResponseMap.delete(Q),this._requestToStreamMapping.delete(Q)}}}}var PW="/.well-known/oauth-protected-resource",VM={"access-control-allow-origin":"*","access-control-allow-methods":"GET, POST, DELETE, OPTIONS","access-control-allow-headers":"authorization, content-type, accept, mcp-protocol-version, mcp-session-id, last-event-id","access-control-expose-headers":"mcp-session-id, www-authenticate, retry-after","access-control-max-age":"86400"};function TB($,v,D,X){if($.method==="OPTIONS")return new Response(null,{status:204});if($.method==="GET"&&X.has(v.pathname)){let U=v.pathname.slice(37);return F1(200,{resource:`${D.publicOrigin}${U}`,authorization_servers:[D.authorizationServerIssuer],bearer_methods_supported:["header"]})}return null}function bW($,v,D=""){let X=[...v?[`error="${v}"`]:[],`resource_metadata="${$.publicOrigin}/.well-known/oauth-protected-resource${D}"`];return new Response(JSON.stringify({error:v??"unauthorized"}),{status:401,headers:{"www-authenticate":`Bearer ${X.join(", ")}`,"content-type":"application/json"}})}function EB($){let v=$.headers.get("authorization");if(!v?.startsWith("Bearer "))return null;let D=v.slice(7).trim();return D.length>0?D:null}function F1($,v){return new Response(JSON.stringify(v),{status:$,headers:{"content-type":"application/json"}})}function uB($){let v=new Headers($.headers);for(let[D,X]of Object.entries(VM))v.set(D,X);return new Response($.body,{status:$.status,statusText:$.statusText,headers:v})}function RB($,v){let D=$.headers.get("cf-connecting-ip")??$.headers.get("x-forwarded-for")??"unknown";return v?[`ip:${D}`,`tok:${v}`]:[`ip:${D}`]}class gB{token;userId;constructor($,v){this.token=$;this.userId=v}async getAccessToken(){return this.token}async getUserId(){return this.userId}async login(){throw Error("In hosted mode, sign-in is handled by your MCP client, not a tool.")}async logout(){throw Error("In hosted mode, sign-out is handled by your MCP client, not a tool.")}}function CB($){let v=async(D,X)=>{let U=await fetch(D,X);if(U.status===401)$.onUnauthorized?.();return U};return{session:new gB($.token,$.userId),trpc:p4($.trpcUrl,async()=>$.token,{fetch:v})}}function j1($){return!!$._zod}function Q6($,v){if(j1($))return h6($,v);return $.safeParse(v)}function yD($){if(!$)return;let v;if(j1($))v=$._zod?.def?.shape;else v=$.shape;if(!v)return;if(typeof v==="function")try{return v()}catch{return}return v}function xB($){if(j1($)){let G=$._zod?.def;if(G){if(G.value!==void 0)return G.value;if(Array.isArray(G.values)&&G.values.length>0)return G.values[0]}}let D=$._def;if(D){if(D.value!==void 0)return D.value;if(Array.isArray(D.values)&&D.values.length>0)return D.values[0]}let X=$.value;if(X!==void 0)return X;return}function I6($){return $==="completed"||$==="failed"||$==="cancelled"}var LM=Symbol("Let zodToJsonSchema decide on which parser to use");var hl=new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789");function qW($){let D=yD($)?.method;if(!D)throw Error("Schema is missing a method literal");let X=xB(D);if(typeof X!=="string")throw Error("Schema method literal must be a string");return X}function SW($,v){let D=Q6($,v);if(!D.success)throw D.error;return D.data}var HM=60000;class kW{constructor($){if(this._options=$,this._requestMessageId=0,this._requestHandlers=new Map,this._requestHandlerAbortControllers=new Map,this._notificationHandlers=new Map,this._responseHandlers=new Map,this._progressHandlers=new Map,this._timeoutInfo=new Map,this._pendingDebouncedNotifications=new Set,this._taskProgressTokens=new Map,this._requestResolvers=new Map,this.setNotificationHandler(TD,(v)=>{this._oncancel(v)}),this.setNotificationHandler(RD,(v)=>{this._onprogress(v)}),this.setRequestHandler(uD,(v)=>({})),this._taskStore=$?.taskStore,this._taskMessageQueue=$?.taskMessageQueue,this._taskStore)this.setRequestHandler(gD,async(v,D)=>{let X=await this._taskStore.getTask(v.params.taskId,D.sessionId);if(!X)throw new x(i.InvalidParams,"Failed to retrieve task: Task not found");return{...X}}),this.setRequestHandler(xD,async(v,D)=>{let X=async()=>{let U=v.params.taskId;if(this._taskMessageQueue){let J;while(J=await this._taskMessageQueue.dequeue(U,D.sessionId)){if(J.type==="response"||J.type==="error"){let Q=J.message,I=Q.id,W=this._requestResolvers.get(I);if(W)if(this._requestResolvers.delete(I),J.type==="response")W(Q);else{let z=Q,Y=new x(z.error.code,z.error.message,z.error.data);W(Y)}else{let z=J.type==="response"?"Response":"Error";this._onerror(Error(`${z} handler missing for request ${I}`))}continue}await this._transport?.send(J.message,{relatedRequestId:D.requestId})}}let G=await this._taskStore.getTask(U,D.sessionId);if(!G)throw new x(i.InvalidParams,`Task not found: ${U}`);if(!I6(G.status))return await this._waitForTaskUpdate(U,D.signal),await X();if(I6(G.status)){let J=await this._taskStore.getTaskResult(U,D.sessionId);return this._clearTaskQueue(U),{...J,_meta:{...J._meta,[G6]:{taskId:U}}}}return await X()};return await X()}),this.setRequestHandler(iD,async(v,D)=>{try{let{tasks:X,nextCursor:U}=await this._taskStore.listTasks(v.params?.cursor,D.sessionId);return{tasks:X,nextCursor:U,_meta:{}}}catch(X){throw new x(i.InvalidParams,`Failed to list tasks: ${X instanceof Error?X.message:String(X)}`)}}),this.setRequestHandler(nD,async(v,D)=>{try{let X=await this._taskStore.getTask(v.params.taskId,D.sessionId);if(!X)throw new x(i.InvalidParams,`Task not found: ${v.params.taskId}`);if(I6(X.status))throw new x(i.InvalidParams,`Cannot cancel task in terminal status: ${X.status}`);await this._taskStore.updateTaskStatus(v.params.taskId,"cancelled","Client cancelled task execution.",D.sessionId),this._clearTaskQueue(v.params.taskId);let U=await this._taskStore.getTask(v.params.taskId,D.sessionId);if(!U)throw new x(i.InvalidParams,`Task not found after cancellation: ${v.params.taskId}`);return{_meta:{},...U}}catch(X){if(X instanceof x)throw X;throw new x(i.InvalidRequest,`Failed to cancel task: ${X instanceof Error?X.message:String(X)}`)}})}async _oncancel($){if(!$.params.requestId)return;this._requestHandlerAbortControllers.get($.params.requestId)?.abort($.params.reason)}_setupTimeout($,v,D,X,U=!1){this._timeoutInfo.set($,{timeoutId:setTimeout(X,v),startTime:Date.now(),timeout:v,maxTotalTimeout:D,resetTimeoutOnProgress:U,onTimeout:X})}_resetTimeout($){let v=this._timeoutInfo.get($);if(!v)return!1;let D=Date.now()-v.startTime;if(v.maxTotalTimeout&&D>=v.maxTotalTimeout)throw this._timeoutInfo.delete($),x.fromError(i.RequestTimeout,"Maximum total timeout exceeded",{maxTotalTimeout:v.maxTotalTimeout,totalElapsed:D});return clearTimeout(v.timeoutId),v.timeoutId=setTimeout(v.onTimeout,v.timeout),!0}_cleanupTimeout($){let v=this._timeoutInfo.get($);if(v)clearTimeout(v.timeoutId),this._timeoutInfo.delete($)}async connect($){if(this._transport)throw Error("Already connected to a transport. Call close() before connecting to a new transport, or use a separate Protocol instance per connection.");this._transport=$;let v=this.transport?.onclose;this._transport.onclose=()=>{v?.(),this._onclose()};let D=this.transport?.onerror;this._transport.onerror=(U)=>{D?.(U),this._onerror(U)};let X=this._transport?.onmessage;this._transport.onmessage=(U,G)=>{if(X?.(U,G),_4(U)||Z1(U))this._onresponse(U);else if(J6(U))this._onrequest(U,G);else if(FB(U))this._onnotification(U);else this._onerror(Error(`Unknown message type: ${JSON.stringify(U)}`))},await this._transport.start()}_onclose(){let $=this._responseHandlers;this._responseHandlers=new Map,this._progressHandlers.clear(),this._taskProgressTokens.clear(),this._pendingDebouncedNotifications.clear();for(let D of this._timeoutInfo.values())clearTimeout(D.timeoutId);this._timeoutInfo.clear();for(let D of this._requestHandlerAbortControllers.values())D.abort();this._requestHandlerAbortControllers.clear();let v=x.fromError(i.ConnectionClosed,"Connection closed");this._transport=void 0,this.onclose?.();for(let D of $.values())D(v)}_onerror($){this.onerror?.($)}_onnotification($){let v=this._notificationHandlers.get($.method)??this.fallbackNotificationHandler;if(v===void 0)return;Promise.resolve().then(()=>v($)).catch((D)=>this._onerror(Error(`Uncaught error in notification handler: ${D}`)))}_onrequest($,v){let D=this._requestHandlers.get($.method)??this.fallbackRequestHandler,X=this._transport,U=$.params?._meta?.[G6]?.taskId;if(D===void 0){let W={jsonrpc:"2.0",id:$.id,error:{code:i.MethodNotFound,message:"Method not found"}};if(U&&this._taskMessageQueue)this._enqueueTaskMessage(U,{type:"error",message:W,timestamp:Date.now()},X?.sessionId).catch((z)=>this._onerror(Error(`Failed to enqueue error response: ${z}`)));else X?.send(W).catch((z)=>this._onerror(Error(`Failed to send an error response: ${z}`)));return}let G=new AbortController;this._requestHandlerAbortControllers.set($.id,G);let J=OB($.params)?$.params.task:void 0,Q=this._taskStore?this.requestTaskStore($,X?.sessionId):void 0,I={signal:G.signal,sessionId:X?.sessionId,_meta:$.params?._meta,sendNotification:async(W)=>{if(G.signal.aborted)return;let z={relatedRequestId:$.id};if(U)z.relatedTask={taskId:U};await this.notification(W,z)},sendRequest:async(W,z,Y)=>{if(G.signal.aborted)throw new x(i.ConnectionClosed,"Request was cancelled");let B={...Y,relatedRequestId:$.id};if(U&&!B.relatedTask)B.relatedTask={taskId:U};let V=B.relatedTask?.taskId??U;if(V&&Q)await Q.updateTaskStatus(V,"input_required");return await this.request(W,z,B)},authInfo:v?.authInfo,requestId:$.id,requestInfo:v?.requestInfo,taskId:U,taskStore:Q,taskRequestedTtl:J?.ttl,closeSSEStream:v?.closeSSEStream,closeStandaloneSSEStream:v?.closeStandaloneSSEStream};Promise.resolve().then(()=>{if(J)this.assertTaskHandlerCapability($.method)}).then(()=>D($,I)).then(async(W)=>{if(G.signal.aborted)return;let z={result:W,jsonrpc:"2.0",id:$.id};if(U&&this._taskMessageQueue)await this._enqueueTaskMessage(U,{type:"response",message:z,timestamp:Date.now()},X?.sessionId);else await X?.send(z)},async(W)=>{if(G.signal.aborted)return;let z={jsonrpc:"2.0",id:$.id,error:{code:Number.isSafeInteger(W.code)?W.code:i.InternalError,message:W.message??"Internal error",...W.data!==void 0&&{data:W.data}}};if(U&&this._taskMessageQueue)await this._enqueueTaskMessage(U,{type:"error",message:z,timestamp:Date.now()},X?.sessionId);else await X?.send(z)}).catch((W)=>this._onerror(Error(`Failed to send response: ${W}`))).finally(()=>{if(this._requestHandlerAbortControllers.get($.id)===G)this._requestHandlerAbortControllers.delete($.id)})}_onprogress($){let{progressToken:v,...D}=$.params,X=Number(v),U=this._progressHandlers.get(X);if(!U){this._onerror(Error(`Received a progress notification for an unknown token: ${JSON.stringify($)}`));return}let G=this._responseHandlers.get(X),J=this._timeoutInfo.get(X);if(J&&G&&J.resetTimeoutOnProgress)try{this._resetTimeout(X)}catch(Q){this._responseHandlers.delete(X),this._progressHandlers.delete(X),this._cleanupTimeout(X),G(Q);return}U(D)}_onresponse($){let v=Number($.id),D=this._requestResolvers.get(v);if(D){if(this._requestResolvers.delete(v),_4($))D($);else{let G=new x($.error.code,$.error.message,$.error.data);D(G)}return}let X=this._responseHandlers.get(v);if(X===void 0){this._onerror(Error(`Received a response for an unknown message ID: ${JSON.stringify($)}`));return}this._responseHandlers.delete(v),this._cleanupTimeout(v);let U=!1;if(_4($)&&$.result&&typeof $.result==="object"){let G=$.result;if(G.task&&typeof G.task==="object"){let J=G.task;if(typeof J.taskId==="string")U=!0,this._taskProgressTokens.set(J.taskId,v)}}if(!U)this._progressHandlers.delete(v);if(_4($))X($);else{let G=x.fromError($.error.code,$.error.message,$.error.data);X(G)}}get transport(){return this._transport}async close(){await this._transport?.close()}async*requestStream($,v,D){let{task:X}=D??{};if(!X){try{yield{type:"result",result:await this.request($,v,D)}}catch(G){yield{type:"error",error:G instanceof x?G:new x(i.InternalError,String(G))}}return}let U;try{let G=await this.request($,O1,D);if(G.task)U=G.task.taskId,yield{type:"taskCreated",task:G.task};else throw new x(i.InternalError,"Task creation did not return a task");while(!0){let J=await this.getTask({taskId:U},D);if(yield{type:"taskStatus",task:J},I6(J.status)){if(J.status==="completed")yield{type:"result",result:await this.getTaskResult({taskId:U},v,D)};else if(J.status==="failed")yield{type:"error",error:new x(i.InternalError,`Task ${U} failed`)};else if(J.status==="cancelled")yield{type:"error",error:new x(i.InternalError,`Task ${U} was cancelled`)};return}if(J.status==="input_required"){yield{type:"result",result:await this.getTaskResult({taskId:U},v,D)};return}let Q=J.pollInterval??this._options?.defaultTaskPollInterval??1000;await new Promise((I)=>setTimeout(I,Q)),D?.signal?.throwIfAborted()}}catch(G){yield{type:"error",error:G instanceof x?G:new x(i.InternalError,String(G))}}}request($,v,D){let{relatedRequestId:X,resumptionToken:U,onresumptiontoken:G,task:J,relatedTask:Q}=D??{};return new Promise((I,W)=>{let z=(H)=>{W(H)};if(!this._transport){z(Error("Not connected"));return}if(this._options?.enforceStrictCapabilities===!0)try{if(this.assertCapabilityForMethod($.method),J)this.assertTaskCapability($.method)}catch(H){z(H);return}D?.signal?.throwIfAborted();let Y=this._requestMessageId++,B={...$,jsonrpc:"2.0",id:Y};if(D?.onprogress)this._progressHandlers.set(Y,D.onprogress),B.params={...$.params,_meta:{...$.params?._meta||{},progressToken:Y}};if(J)B.params={...B.params,task:J};if(Q)B.params={...B.params,_meta:{...B.params?._meta||{},[G6]:Q}};let V=(H)=>{this._responseHandlers.delete(Y),this._progressHandlers.delete(Y),this._cleanupTimeout(Y),this._transport?.send({jsonrpc:"2.0",method:"notifications/cancelled",params:{requestId:Y,reason:String(H)}},{relatedRequestId:X,resumptionToken:U,onresumptiontoken:G}).catch((R)=>this._onerror(Error(`Failed to send cancellation: ${R}`)));let S=H instanceof x?H:new x(i.RequestTimeout,String(H));W(S)};this._responseHandlers.set(Y,(H)=>{if(D?.signal?.aborted)return;if(H instanceof Error)return W(H);try{let S=Q6(v,H.result);if(!S.success)W(S.error);else I(S.data)}catch(S){W(S)}}),D?.signal?.addEventListener("abort",()=>{V(D?.signal?.reason)});let L=D?.timeout??HM,N=()=>V(x.fromError(i.RequestTimeout,"Request timed out",{timeout:L}));this._setupTimeout(Y,L,D?.maxTotalTimeout,N,D?.resetTimeoutOnProgress??!1);let Z=Q?.taskId;if(Z){let H=(S)=>{let R=this._responseHandlers.get(Y);if(R)R(S);else this._onerror(Error(`Response handler missing for side-channeled request ${Y}`))};this._requestResolvers.set(Y,H),this._enqueueTaskMessage(Z,{type:"request",message:B,timestamp:Date.now()}).catch((S)=>{this._cleanupTimeout(Y),W(S)})}else this._transport.send(B,{relatedRequestId:X,resumptionToken:U,onresumptiontoken:G}).catch((H)=>{this._cleanupTimeout(Y),W(H)})})}async getTask($,v){return this.request({method:"tasks/get",params:$},CD,v)}async getTaskResult($,v,D){return this.request({method:"tasks/result",params:$},v,D)}async listTasks($,v){return this.request({method:"tasks/list",params:$},fD,v)}async cancelTask($,v){return this.request({method:"tasks/cancel",params:$},wB,v)}async notification($,v){if(!this._transport)throw Error("Not connected");this.assertNotificationCapability($.method);let D=v?.relatedTask?.taskId;if(D){let J={...$,jsonrpc:"2.0",params:{...$.params,_meta:{...$.params?._meta||{},[G6]:v.relatedTask}}};await this._enqueueTaskMessage(D,{type:"notification",message:J,timestamp:Date.now()});return}if((this._options?.debouncedNotificationMethods??[]).includes($.method)&&!$.params&&!v?.relatedRequestId&&!v?.relatedTask){if(this._pendingDebouncedNotifications.has($.method))return;this._pendingDebouncedNotifications.add($.method),Promise.resolve().then(()=>{if(this._pendingDebouncedNotifications.delete($.method),!this._transport)return;let J={...$,jsonrpc:"2.0"};if(v?.relatedTask)J={...J,params:{...J.params,_meta:{...J.params?._meta||{},[G6]:v.relatedTask}}};this._transport?.send(J,v).catch((Q)=>this._onerror(Q))});return}let G={...$,jsonrpc:"2.0"};if(v?.relatedTask)G={...G,params:{...G.params,_meta:{...G.params?._meta||{},[G6]:v.relatedTask}}};await this._transport.send(G,v)}setRequestHandler($,v){let D=qW($);this.assertRequestHandlerCapability(D),this._requestHandlers.set(D,(X,U)=>{let G=SW($,X);return Promise.resolve(v(G,U))})}removeRequestHandler($){this._requestHandlers.delete($)}assertCanSetRequestHandler($){if(this._requestHandlers.has($))throw Error(`A request handler for ${$} already exists, which would be overridden`)}setNotificationHandler($,v){let D=qW($);this._notificationHandlers.set(D,(X)=>{let U=SW($,X);return Promise.resolve(v(U))})}removeNotificationHandler($){this._notificationHandlers.delete($)}_cleanupTaskProgressHandler($){let v=this._taskProgressTokens.get($);if(v!==void 0)this._progressHandlers.delete(v),this._taskProgressTokens.delete($)}async _enqueueTaskMessage($,v,D){if(!this._taskStore||!this._taskMessageQueue)throw Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");let X=this._options?.maxTaskQueueSize;await this._taskMessageQueue.enqueue($,v,D,X)}async _clearTaskQueue($,v){if(this._taskMessageQueue){let D=await this._taskMessageQueue.dequeueAll($,v);for(let X of D)if(X.type==="request"&&J6(X.message)){let U=X.message.id,G=this._requestResolvers.get(U);if(G)G(new x(i.InternalError,"Task cancelled or completed")),this._requestResolvers.delete(U);else this._onerror(Error(`Resolver missing for request ${U} during task ${$} cleanup`))}}}async _waitForTaskUpdate($,v){let D=this._options?.defaultTaskPollInterval??1000;try{let X=await this._taskStore?.getTask($);if(X?.pollInterval)D=X.pollInterval}catch{}return new Promise((X,U)=>{if(v.aborted){U(new x(i.InvalidRequest,"Request cancelled"));return}let G=setTimeout(X,D);v.addEventListener("abort",()=>{clearTimeout(G),U(new x(i.InvalidRequest,"Request cancelled"))},{once:!0})})}requestTaskStore($,v){let D=this._taskStore;if(!D)throw Error("No task store configured");return{createTask:async(X)=>{if(!$)throw Error("No request provided");return await D.createTask(X,$.id,{method:$.method,params:$.params},v)},getTask:async(X)=>{let U=await D.getTask(X,v);if(!U)throw new x(i.InvalidParams,"Failed to retrieve task: Task not found");return U},storeTaskResult:async(X,U,G)=>{await D.storeTaskResult(X,U,G,v);let J=await D.getTask(X,v);if(J){let Q=lv.parse({method:"notifications/tasks/status",params:J});if(await this.notification(Q),I6(J.status))this._cleanupTaskProgressHandler(X)}},getTaskResult:(X)=>{return D.getTaskResult(X,v)},updateTaskStatus:async(X,U,G)=>{let J=await D.getTask(X,v);if(!J)throw new x(i.InvalidParams,`Task "${X}" not found - it may have been cleaned up`);if(I6(J.status))throw new x(i.InvalidParams,`Cannot update task "${X}" from terminal status "${J.status}" to "${U}". Terminal states (completed, failed, cancelled) cannot transition to other states.`);await D.updateTaskStatus(X,U,G,v);let Q=await D.getTask(X,v);if(Q){let I=lv.parse({method:"notifications/tasks/status",params:Q});if(await this.notification(I),I6(Q.status))this._cleanupTaskProgressHandler(X)}},listTasks:(X)=>{return D.listTasks(X,v)}}}}function iB($){return $!==null&&typeof $==="object"&&!Array.isArray($)}function fB($,v){let D={...$};for(let X in v){let U=X,G=v[U];if(G===void 0)continue;let J=D[U];if(iB(J)&&iB(G))D[U]={...J,...G};else D[U]=G}return D}var HZ=H5(Mz(),1),FZ=H5(AZ(),1);function lu(){let $=new HZ.default({strict:!1,validateFormats:!0,validateSchema:!1,allErrors:!0});return FZ.default($),$}class gz{constructor($){this._ajv=$??lu()}getValidator($){let v="$id"in $&&typeof $.$id==="string"?this._ajv.getSchema($.$id)??this._ajv.compile($):this._ajv.compile($);return(D)=>{if(v(D))return{valid:!0,data:D,errorMessage:void 0};else return{valid:!1,data:void 0,errorMessage:this._ajv.errorsText(v.errors)}}}}class Cz{constructor($){this._server=$}requestStream($,v,D){return this._server.requestStream($,v,D)}createMessageStream($,v){let D=this._server.getClientCapabilities();if(($.tools||$.toolChoice)&&!D?.sampling?.tools)throw Error("Client does not support sampling tools capability.");if($.messages.length>0){let X=$.messages[$.messages.length-1],U=Array.isArray(X.content)?X.content:[X.content],G=U.some((W)=>W.type==="tool_result"),J=$.messages.length>1?$.messages[$.messages.length-2]:void 0,Q=J?Array.isArray(J.content)?J.content:[J.content]:[],I=Q.some((W)=>W.type==="tool_use");if(G){if(U.some((W)=>W.type!=="tool_result"))throw Error("The last message must contain only tool_result content if any is present");if(!I)throw Error("tool_result blocks are not matching any tool_use from the previous message")}if(I){let W=new Set(Q.filter((Y)=>Y.type==="tool_use").map((Y)=>Y.id)),z=new Set(U.filter((Y)=>Y.type==="tool_result").map((Y)=>Y.toolUseId));if(W.size!==z.size||![...W].every((Y)=>z.has(Y)))throw Error("ids of tool_result blocks and tool_use blocks from previous message do not match")}}return this.requestStream({method:"sampling/createMessage",params:$},ov,v)}elicitInputStream($,v){let D=this._server.getClientCapabilities(),X=$.mode??"form";switch(X){case"url":{if(!D?.elicitation?.url)throw Error("Client does not support url elicitation.");break}case"form":{if(!D?.elicitation?.form)throw Error("Client does not support form elicitation.");break}}let U=X==="form"&&$.mode===void 0?{...$,mode:"form"}:$;return this.requestStream({method:"elicitation/create",params:U},H1,v)}async getTask($,v){return this._server.getTask({taskId:$},v)}async getTaskResult($,v,D){return this._server.getTaskResult({taskId:$},v,D)}async listTasks($,v){return this._server.listTasks($?{cursor:$}:void 0,v)}async cancelTask($,v){return this._server.cancelTask({taskId:$},v)}}function jZ($,v,D){if(!$)throw Error(`${D} does not support task creation (required for ${v})`);switch(v){case"tools/call":if(!$.tools?.call)throw Error(`${D} does not support task creation for tools/call (required for ${v})`);break;default:break}}function wZ($,v,D){if(!$)throw Error(`${D} does not support task creation (required for ${v})`);switch(v){case"sampling/createMessage":if(!$.sampling?.createMessage)throw Error(`${D} does not support task creation for sampling/createMessage (required for ${v})`);break;case"elicitation/create":if(!$.elicitation?.create)throw Error(`${D} does not support task creation for elicitation/create (required for ${v})`);break;default:break}}class F0 extends kW{constructor($,v){super(v);if(this._serverInfo=$,this._loggingLevels=new Map,this.LOG_LEVEL_SEVERITY=new Map(tv.options.map((D,X)=>[D,X])),this.isMessageIgnored=(D,X)=>{let U=this._loggingLevels.get(X);return U?this.LOG_LEVEL_SEVERITY.get(D)<this.LOG_LEVEL_SEVERITY.get(U):!1},this._capabilities=v?.capabilities??{},this._instructions=v?.instructions,this._jsonSchemaValidator=v?.jsonSchemaValidator??new gz,this.setRequestHandler(ED,(D)=>this._oninitialize(D)),this.setNotificationHandler(LW,()=>this.oninitialized?.()),this._capabilities.logging)this.setRequestHandler(FW,async(D,X)=>{let U=X.sessionId||X.requestInfo?.headers["mcp-session-id"]||void 0,{level:G}=D.params,J=tv.safeParse(G);if(J.success)this._loggingLevels.set(U,J.data);return{}})}get experimental(){if(!this._experimental)this._experimental={tasks:new Cz(this)};return this._experimental}registerCapabilities($){if(this.transport)throw Error("Cannot register capabilities after connecting to transport");this._capabilities=fB(this._capabilities,$)}setRequestHandler($,v){let X=yD($)?.method;if(!X)throw Error("Schema is missing a method literal");let U;if(j1(X)){let J=X;U=J._zod?.def?.value??J.value}else{let J=X;U=J._def?.value??J.value}if(typeof U!=="string")throw Error("Schema method literal must be a string");if(U==="tools/call"){let J=async(Q,I)=>{let W=Q6(b6,Q);if(!W.success){let V=W.error instanceof Error?W.error.message:String(W.error);throw new x(i.InvalidParams,`Invalid tools/call request: ${V}`)}let{params:z}=W.data,Y=await Promise.resolve(v(Q,I));if(z.task){let V=Q6(O1,Y);if(!V.success){let L=V.error instanceof Error?V.error.message:String(V.error);throw new x(i.InvalidParams,`Invalid task creation result: ${L}`)}return V.data}let B=Q6(_D,Y);if(!B.success){let V=B.error instanceof Error?B.error.message:String(B.error);throw new x(i.InvalidParams,`Invalid tools/call result: ${V}`)}return B.data};return super.setRequestHandler($,J)}return super.setRequestHandler($,v)}assertCapabilityForMethod($){switch($){case"sampling/createMessage":if(!this._clientCapabilities?.sampling)throw Error(`Client does not support sampling (required for ${$})`);break;case"elicitation/create":if(!this._clientCapabilities?.elicitation)throw Error(`Client does not support elicitation (required for ${$})`);break;case"roots/list":if(!this._clientCapabilities?.roots)throw Error(`Client does not support listing roots (required for ${$})`);break;case"ping":break}}assertNotificationCapability($){switch($){case"notifications/message":if(!this._capabilities.logging)throw Error(`Server does not support logging (required for ${$})`);break;case"notifications/resources/updated":case"notifications/resources/list_changed":if(!this._capabilities.resources)throw Error(`Server does not support notifying about resources (required for ${$})`);break;case"notifications/tools/list_changed":if(!this._capabilities.tools)throw Error(`Server does not support notifying of tool list changes (required for ${$})`);break;case"notifications/prompts/list_changed":if(!this._capabilities.prompts)throw Error(`Server does not support notifying of prompt list changes (required for ${$})`);break;case"notifications/elicitation/complete":if(!this._clientCapabilities?.elicitation?.url)throw Error(`Client does not support URL elicitation (required for ${$})`);break;case"notifications/cancelled":break;case"notifications/progress":break}}assertRequestHandlerCapability($){if(!this._capabilities)return;switch($){case"completion/complete":if(!this._capabilities.completions)throw Error(`Server does not support completions (required for ${$})`);break;case"logging/setLevel":if(!this._capabilities.logging)throw Error(`Server does not support logging (required for ${$})`);break;case"prompts/get":case"prompts/list":if(!this._capabilities.prompts)throw Error(`Server does not support prompts (required for ${$})`);break;case"resources/list":case"resources/templates/list":case"resources/read":if(!this._capabilities.resources)throw Error(`Server does not support resources (required for ${$})`);break;case"tools/call":case"tools/list":if(!this._capabilities.tools)throw Error(`Server does not support tools (required for ${$})`);break;case"tasks/get":case"tasks/list":case"tasks/result":case"tasks/cancel":if(!this._capabilities.tasks)throw Error(`Server does not support tasks capability (required for ${$})`);break;case"ping":case"initialize":break}}assertTaskCapability($){wZ(this._clientCapabilities?.tasks?.requests,$,"Client")}assertTaskHandlerCapability($){if(!this._capabilities)return;jZ(this._capabilities.tasks?.requests,$,"Server")}async _oninitialize($){let v=$.params.protocolVersion;return this._clientCapabilities=$.params.capabilities,this._clientVersion=$.params.clientInfo,{protocolVersion:N1.includes(v)?v:WW,capabilities:this.getCapabilities(),serverInfo:this._serverInfo,...this._instructions&&{instructions:this._instructions}}}getClientCapabilities(){return this._clientCapabilities}getClientVersion(){return this._clientVersion}getCapabilities(){return this._capabilities}async ping(){return this.request({method:"ping"},kD)}async createMessage($,v){if($.tools||$.toolChoice){if(!this._clientCapabilities?.sampling?.tools)throw Error("Client does not support sampling tools capability.")}if($.messages.length>0){let D=$.messages[$.messages.length-1],X=Array.isArray(D.content)?D.content:[D.content],U=X.some((I)=>I.type==="tool_result"),G=$.messages.length>1?$.messages[$.messages.length-2]:void 0,J=G?Array.isArray(G.content)?G.content:[G.content]:[],Q=J.some((I)=>I.type==="tool_use");if(U){if(X.some((I)=>I.type!=="tool_result"))throw Error("The last message must contain only tool_result content if any is present");if(!Q)throw Error("tool_result blocks are not matching any tool_use from the previous message")}if(Q){let I=new Set(J.filter((z)=>z.type==="tool_use").map((z)=>z.id)),W=new Set(X.filter((z)=>z.type==="tool_result").map((z)=>z.toolUseId));if(I.size!==W.size||![...I].every((z)=>W.has(z)))throw Error("ids of tool_result blocks and tool_use blocks from previous message do not match")}}if($.tools)return this.request({method:"sampling/createMessage",params:$},jW,v);return this.request({method:"sampling/createMessage",params:$},ov,v)}async elicitInput($,v){switch($.mode??"form"){case"url":{if(!this._clientCapabilities?.elicitation?.url)throw Error("Client does not support url elicitation.");let X=$;return this.request({method:"elicitation/create",params:X},H1,v)}case"form":{if(!this._clientCapabilities?.elicitation?.form)throw Error("Client does not support form elicitation.");let X=$.mode==="form"?$:{...$,mode:"form"},U=await this.request({method:"elicitation/create",params:X},H1,v);if(U.action==="accept"&&U.content&&X.requestedSchema)try{let J=this._jsonSchemaValidator.getValidator(X.requestedSchema)(U.content);if(!J.valid)throw new x(i.InvalidParams,`Elicitation response content does not match requested schema: ${J.errorMessage}`)}catch(G){if(G instanceof x)throw G;throw new x(i.InternalError,`Error validating elicitation response: ${G instanceof Error?G.message:String(G)}`)}return U}}}createElicitationCompletionNotifier($,v){if(!this._clientCapabilities?.elicitation?.url)throw Error("Client does not support URL elicitation (required for notifications/elicitation/complete)");return()=>this.notification({method:"notifications/elicitation/complete",params:{elicitationId:$}},v)}async listRoots($,v){return this.request({method:"roots/list",params:$},wW,v)}async sendLoggingMessage($,v){if(this._capabilities.logging){if(!this.isMessageIgnored($.level,v))return this.notification({method:"notifications/message",params:$})}}async sendResourceUpdated($){return this.notification({method:"notifications/resources/updated",params:$})}async sendResourceListChanged(){return this.notification({method:"notifications/resources/list_changed"})}async sendToolListChanged(){return this.notification({method:"notifications/tools/list_changed"})}async sendPromptListChanged(){return this.notification({method:"notifications/prompts/list_changed"})}}var xz=[{name:"Trading journal",what:"Log, tag, and review trades across every account and market.",mcp:["list_trades","get_trade","create_trade","update_trade","close_trade","delete_trade","delete_trades","import_trades","trade_stats","list_accounts","create_account"],dashboardOnly:["the visual journal with tag and emotion analytics","per-trade chart markers and replay"]},{name:"Alerts",what:"Price, trendline, and indicator alerts that watch the market for you.",mcp:["list_alerts","create_price_alert","create_trendline_alert","create_indicator_alert","list_indicator_alerts","update_indicator_alert","delete_indicator_alert","update_alert","delete_alert"],dashboardOnly:["drawing an alert directly on the chart","the alert inbox and history"]},{name:"Market data & indicators",what:"OHLC candles, technical indicators, and instrument config across markets.",mcp:["get_candles","get_indicators","get_market_config"],dashboardOnly:["the live, interactive multi-market chart"]},{name:"Macro & economic calendar",what:"Scheduled economic events and macro time series.",mcp:["list_economic_calendar","get_macro_series","get_macro_indicator"],dashboardOnly:["the filterable calendar view with per-event alerts"]},{name:"FX macro context",what:"Per-currency and per-pair macro context — recent releases and surprises, model predictions, cross-market risk sentiment, and the source documents (news, press releases) behind them.",mcp:["get_fx_pair_context","get_fx_currency_context","get_fx_predictions","get_fx_risk_sentiment","get_fx_documents","get_fx_sync_state"],dashboardOnly:[]},{name:"Charts",what:"Render a chart image, or drive the chart the user already has open.",mcp:["render_chart","chart_select_pair","chart_change_timeframe","chart_draw_shapes","chart_remove_drawings"],dashboardOnly:["the full charting workspace with drawing tools and saved layouts"]},{name:"Pine Studio",what:"Author and backtest TradingView-style strategies on live data.",mcp:[],dashboardOnly:["the Pine editor, backtests, and turning a script into an alert"]},{name:"Aether Intelligence",what:"The in-app assistant that already sees the chart and the journal.",mcp:[],dashboardOnly:["the in-app chat that can mark up the chart as it answers"]}];function MZ(){let $=["AETHER WEALTH — capability map for assistants","","Aether Wealth is a multi-market trading workspace: charts, a trading journal,","alerts, an economic calendar, and an in-app AI assistant. You reach it two ways:","this MCP server (the tools below) and the web dashboard at",`${x4}. Call get_context first to snapshot the user's live state`,"(accounts, open trades, recent stats, active alerts) before you advise. When a",'task requires something marked "dashboard only", suggest the user open the',"dashboard rather than attempting it over MCP.",""];for(let v of xz)$.push(`## ${v.name}`),$.push(v.what),$.push(v.mcp.length>0?` MCP tools: ${v.mcp.join(", ")}`:" MCP tools: none yet"),$.push(` Dashboard only: ${v.dashboardOnly.join("; ")}`),$.push("");return $.join(`
|
|
104
104
|
`).trimEnd()}var MX=["Aether Wealth spans a trading journal, alerts, market data and indicators, a","macro calendar, charts, Pine Studio, and the Aether Intelligence assistant. Many","of these are callable over MCP; some are dashboard-only."].join(" ");function iz($={}){let v=$.hosted??!1,D=v?["Authentication is handled by the MCP connection itself — there are no sign-in tools to call. If calls fail with an authorization error, the user must re-authorize this connection in their MCP client settings."]:["Auth tools:"," • login — sign in. Opens the browser; the user authenticates and approves access. Call this first if a data tool reports the user is not signed in."," • logout — sign out on this device."],X=v?" 3. If it fails with an authorization error, tell the user to re-authorize the Aether Wealth connection in their MCP client, then retry.":' 3. If it reports "not signed in", call login, wait for the user to finish in the browser, then retry.';return[{name:"getting_started",description:"Brief the LLM on what the Aether Wealth MCP exposes and the sign-in-first flow.",handler:()=>[{role:"user",content:{type:"text",text:["You are connected to the Aether Wealth MCP — programmatic access to the user's trading journal, alerts, market data, indicators, charts, and live-chart controls, over an authenticated connection.","",...D,"","Context:"," • get_context — snapshot accounts, open trades, recent stats, and active alerts in one call. Call it first to ground your suggestions.","","Domains (partial — see the aetherwealth://capabilities resource for the full set):"," • Journal: list_trades, get_trade, list_accounts, create_account, create_trade, update_trade, close_trade, delete_trade, delete_trades, import_trades, trade_stats"," • Alerts: list_alerts, create_price_alert, create_trendline_alert, create_indicator_alert, list_indicator_alerts, update_indicator_alert, delete_indicator_alert, update_alert, delete_alert"," • Market data + indicators: get_candles, get_market_config, get_indicators"," • Macro: list_economic_calendar, get_macro_series, get_macro_indicator"," • FX macro context: get_fx_pair_context, get_fx_currency_context, get_fx_predictions, get_fx_risk_sentiment, get_fx_documents, get_fx_sync_state"," • Charts: render_chart, chart_select_pair, chart_change_timeframe, chart_draw_shapes, chart_remove_drawings"," • Broker execution: propose_trade creates a user-confirmed intent; execute_trade only applies to email_otp/app_otp/auto intents. For push intents, do not ask for a code — use trade_intent_status to check the app approval outcome.","","Deletion rule:"," • delete_trade and delete_trades are permanent and only work on demo accounts. Live-account trade deletes are blocked by the backend.","","Recommended flow:"," 1. Call get_context to load live state."," 2. Try the data tool the user asked for (e.g. list_trades).",X].join(`
|
|
105
105
|
`)}}]},{name:"dashboard_context",description:"Brief the LLM on the full Aether Wealth surface, grounding in live state, and when to suggest the dashboard.",handler:()=>[{role:"user",content:{type:"text",text:["You are connected to Aether Wealth, a multi-market trading workspace.",MX,"","Before you advise, call get_context to load the user's live state (accounts, open trades, recent stats, active alerts) so your suggestions fit what they are actually doing. The aetherwealth://capabilities resource, if your client attaches it, is the full surface map — which actions are MCP-callable vs dashboard-only.","","When the user needs something that is dashboard-only (the full charting workspace and saved layouts, the Pine editor, the full journal UI, the Aether Intelligence assistant),",`tell them to open the dashboard at ${x4} rather than attempting it over MCP.`].join(`
|
|
106
|
-
`)}}]}]}function fz(){return[{uri:"aetherwealth://capabilities",name:"Aether Wealth capabilities",description:"What Aether Wealth can do across all surfaces, and which actions are MCP-callable vs dashboard-only. Attach for product context.",mimeType:"text/markdown",handler:async()=>({text:MZ()})}]}function hu($){return{...$.broker===void 0?{}:{broker:$.broker},...$.accountType===void 0?{}:{accountType:$.accountType},...$.initialBalance===void 0?{}:{initialBalance:$.initialBalance},...$.currency===void 0?{}:{currency:$.currency},...$.notes===void 0?{}:{notes:$.notes},...$.defaultRiskAmount===void 0?{}:{defaultRiskAmount:$.defaultRiskAmount}}}function mu($){return{name:$.name,...hu($)}}function PZ($){return $.trading.accounts.list.query()}function bZ($,v){return $.trading.accounts.create.mutate(mu(v))}function nz($){return{triggerType:$.triggerType??"close",isPersistent:$.isPersistent??!1,notifyEmail:$.notifyEmail??!0,notifyPush:$.notifyPush??!0,...$.message===void 0?{}:{message:$.message},...$.expiresAt===void 0?{}:{expiresAt:$.expiresAt}}}function qZ($){return{...$.includeArchived===void 0?{}:{includeArchived:$.includeArchived},...$.pair===void 0?{}:{pair:$.pair}}}function ru($){return{id:$.id,...$.price===void 0?{}:{price:$.price},...$.price1===void 0?{}:{price1:$.price1},...$.price2===void 0?{}:{price2:$.price2},...$.time1===void 0?{}:{time1:$.time1},...$.time2===void 0?{}:{time2:$.time2},...$.condition===void 0?{}:{condition:$.condition},...$.triggerType===void 0?{}:{triggerType:$.triggerType},...$.timeframe===void 0?{}:{timeframe:$.timeframe},...$.isActive===void 0?{}:{isActive:$.isActive},...$.isArchived===void 0?{}:{isArchived:$.isArchived},...$.isPersistent===void 0?{}:{isPersistent:$.isPersistent},...$.notifyEmail===void 0?{}:{notifyEmail:$.notifyEmail},...$.notifyPush===void 0?{}:{notifyPush:$.notifyPush},...$.message===void 0?{}:{message:$.message},...$.expiresAt===void 0?{}:{expiresAt:$.expiresAt}}}function cu($){return{id:$.id,...$.condition===void 0?{}:{condition:$.condition},...$.dedupMode===void 0?{}:{dedupMode:$.dedupMode},...$.triggerType===void 0?{}:{triggerType:$.triggerType},...$.isActive===void 0?{}:{isActive:$.isActive},...$.isArchived===void 0?{}:{isArchived:$.isArchived},...$.isPersistent===void 0?{}:{isPersistent:$.isPersistent},...$.notifyEmail===void 0?{}:{notifyEmail:$.notifyEmail},...$.notifyPush===void 0?{}:{notifyPush:$.notifyPush},...$.message===void 0?{}:{message:$.message},...$.expiresAt===void 0?{}:{expiresAt:$.expiresAt}}}function SZ($,v){return $.alerts.list.query(qZ(v))}function kZ($,v){let D={pair:v.pair,timeframe:v.timeframe,price:v.price,condition:v.condition,...nz(v)};return $.alerts.createPrice.mutate(D)}function TZ($,v){let D={pair:v.pair,timeframe:v.timeframe,price1:v.price1,time1:v.time1,price2:v.price2,time2:v.time2,condition:v.condition,...nz(v)};return $.alerts.createTrendline.mutate(D)}function EZ($,v){return $.alerts.update.mutate(ru(v))}function uZ($,v){return $.alerts.delete.mutate({id:v.id})}function RZ($,v){let D=qZ(v);return $.alerts.indicator.list.query(D)}function gZ($,v){let D={pair:v.pair,timeframe:v.timeframe,indicatorType:v.indicatorType,indicatorParams:v.indicatorParams,outputSeries:v.outputSeries,condition:v.condition,dedupMode:v.dedupMode??"edge",...nz(v)};return $.alerts.indicator.create.mutate(D)}function CZ($,v){return $.alerts.indicator.update.mutate(cu(v))}function xZ($,v){return $.alerts.indicator.delete.mutate({id:v.id})}function du($){return{accountId:$.accountId,region:$.region,providerAccountRef:$.providerAccountRef,providerToken:$.providerToken,...$.provider===void 0?{}:{provider:$.provider},...$.approvalMode===void 0?{}:{approvalMode:$.approvalMode}}}function _z($){return{accountId:$.accountId}}function pu($){return{accountId:$.accountId,approvalMode:$.approvalMode,...$.totpCode===void 0?{}:{totpCode:$.totpCode}}}function tu($){return{accountId:$.accountId,symbol:$.symbol,direction:$.direction,stopLoss:$.stopLoss,...$.orderType===void 0?{}:{orderType:$.orderType},...$.entryPrice===void 0?{}:{entryPrice:$.entryPrice},...$.takeProfit===void 0?{}:{takeProfit:$.takeProfit},...$.riskPercent===void 0?{}:{riskPercent:$.riskPercent},...$.riskAmount===void 0?{}:{riskAmount:$.riskAmount}}}function ou($){return{intentId:$.intentId,...$.code===void 0?{}:{code:$.code}}}function au($){return{intentId:$.intentId}}function eu($){return{intentId:$.intentId}}function su($){return{accountId:$.accountId,positionId:$.positionId,...$.volume===void 0?{}:{volume:$.volume}}}function $R($){return{accountId:$.accountId,positionId:$.positionId,...$.stopLoss===void 0?{}:{stopLoss:$.stopLoss},...$.takeProfit===void 0?{}:{takeProfit:$.takeProfit}}}function iZ($,v){return $.execution.connect.mutate(du(v))}function fZ($,v){return $.execution.status.query(_z(v))}function nZ($,v){return $.execution.setApprovalMode.mutate(pu(v))}function _Z($,v){return $.execution.account.query(_z(v))}function yZ($,v){return $.execution.positions.query(_z(v))}function lZ($,v){return $.execution.propose.mutate(tu(v))}function hZ($,v){return $.execution.execute.mutate(ou(v))}function mZ($,v){return $.execution.cancel.mutate(au(v))}function rZ($,v){return $.execution.intentStatus.query(eu(v))}function cZ($,v){return $.execution.closePosition.mutate(su(v))}function dZ($,v){return $.execution.modifyPosition.mutate($R(v))}function vR($){return{pair:$.pair,interval:$.interval,indicators:$.indicators.map((v)=>({name:v.name,...v.params===void 0?{}:{params:v.params}})),...$.outputsize===void 0?{}:{outputsize:$.outputsize}}}function pZ($,v){return $.technicalIndicators.get.query(vR(v))}var tZ=["3m","6m","12m","24m","all"];function UR($){return{...$.currency===void 0?{}:{currency:$.currency},...$.from===void 0?{}:{from:$.from},...$.to===void 0?{}:{to:$.to},...$.indicator===void 0?{}:{indicator:$.indicator},...$.impactMin===void 0?{}:{impactMin:$.impactMin},...$.view===void 0?{}:{view:$.view}}}function DR($){return{currency:$.currency,indicator:$.indicator,...$.from===void 0?{}:{from:$.from},...$.to===void 0?{}:{to:$.to},...$.limit===void 0?{}:{limit:$.limit}}}function XR($){return{currency:$.currency,indicator:$.indicator,...$.range===void 0?{}:{range:$.range}}}function GR($){return{pair:$.pair,timeframe:$.timeframe,...$.limit===void 0?{}:{limit:$.limit},...$.offset===void 0?{}:{offset:$.offset}}}function PX($,v){return $.marketData.candles.query(GR(v))}function oZ($,v){return $.marketData.listCalendar.query(UR(v))}function aZ($,v){return $.marketData.listIndicatorSeries.query(DR(v))}function eZ($,v){return $.macroIndicator.list.query(XR(v))}function sZ($){return $.marketData.getConfig.query()}function JR($){return{...$.accountId===void 0?{}:{accountId:$.accountId},...$.pair===void 0?{}:{pair:$.pair},...$.from===void 0?{}:{from:$.from},...$.to===void 0?{}:{to:$.to}}}function $O($,v){return $.trading.analytics.stats.query(JR(v))}function QR($){return{...$.accountId===void 0?{}:{accountId:$.accountId},...$.status===void 0||$.status==="ALL"?{}:{status:$.status},...$.pair===void 0?{}:{pair:$.pair},...$.from===void 0?{}:{from:$.from},...$.to===void 0?{}:{to:$.to},...$.page===void 0?{}:{page:$.page},...$.limit===void 0?{}:{limit:$.limit}}}function vO($){return{...$.stopLoss===void 0?{}:{stopLoss:$.stopLoss},...$.takeProfit===void 0?{}:{takeProfit:$.takeProfit},...$.lotSize===void 0?{}:{lotSize:$.lotSize},...$.notes===void 0?{}:{notes:$.notes},...$.timeframe===void 0?{}:{timeframe:$.timeframe},...$.riskPercent===void 0?{}:{riskPercent:$.riskPercent},...$.tags===void 0?{}:{tags:$.tags}}}function IR($){return{accountId:$.accountId,pair:$.pair,direction:$.direction,entryPrice:$.entryPrice,entryTime:$.entryTime,...vO($)}}function WR($){return{id:$.id,...$.pair===void 0?{}:{pair:$.pair},...$.direction===void 0?{}:{direction:$.direction},...$.entryPrice===void 0?{}:{entryPrice:$.entryPrice},...$.entryTime===void 0?{}:{entryTime:$.entryTime},...vO($)}}function zR($){return{id:$.id,exitPrice:$.exitPrice,exitTime:$.exitTime,...$.fees===void 0?{}:{fees:$.fees},...$.swap===void 0?{}:{swap:$.swap},...$.notes===void 0?{}:{notes:$.notes}}}function YR($){return{accountId:$.accountId,status:$.status}}function BR($){return{pair:$.pair,direction:$.direction,entryPrice:$.entryPrice,lotSize:$.lotSize,entryTime:$.entryTime,...$.exitPrice===void 0?{}:{exitPrice:$.exitPrice},...$.stopLoss===void 0?{}:{stopLoss:$.stopLoss},...$.takeProfit===void 0?{}:{takeProfit:$.takeProfit},...$.exitTime===void 0?{}:{exitTime:$.exitTime},...$.notes===void 0?{}:{notes:$.notes},...$.timeframe===void 0?{}:{timeframe:$.timeframe},...$.emotionalTag===void 0?{}:{emotionalTag:$.emotionalTag},...$.fees===void 0?{}:{fees:$.fees},...$.swap===void 0?{}:{swap:$.swap},...$.reportedPnl===void 0?{}:{reportedPnl:$.reportedPnl},...$.tags===void 0?{}:{tags:$.tags}}}function VR($){return{accountId:$.accountId,trades:$.trades.map(BR)}}function UO($,v){return $.trading.trades.list.query(QR(v))}function DO($,v){return $.trading.trades.get.query({id:v.id})}function XO($,v){return $.trading.trades.create.mutate(IR(v))}function GO($,v){return $.trading.trades.update.mutate(WR(v))}function JO($,v){return $.trading.trades.close.mutate(zR(v))}function QO($,v){return $.trading.trades.delete.mutate({id:v.id})}function IO($,v){return $.trading.trades.deleteMany.mutate(YR(v))}function WO($,v){return $.trading.trades.importMany.mutate(VR(v))}function T($){return $}var yz='Not signed in to Aether Wealth. Call the "login" tool to authenticate, then retry.';async function u($){if(!await $.session.getAccessToken())throw Error(yz)}var zO={type:"integer",minimum:1,maximum:200,description:"Max rows to return"},YO={type:"integer",minimum:1,description:"Page number (1-indexed)"};function bX($,v){if(v===null||v===void 0){if($.required&&$.required.length>0)return{ok:!1,reason:`missing required: ${$.required.join(", ")}`};return{ok:!0,args:{}}}if(typeof v!=="object"||Array.isArray(v))return{ok:!1,reason:"args must be an object"};let D=v,X=LR($,D)??KR($,D);return X?{ok:!1,reason:X}:{ok:!0,args:D}}function LR($,v){for(let D of $.required??[])if(!(D in v)||v[D]===void 0||v[D]===null)return`missing required: ${D}`;return null}function KR($,v){if($.additionalProperties!==!1)return null;for(let D of Object.keys(v))if(!(D in $.properties))return`unknown property: ${D}`;return null}var lz={type:"string",enum:["above","below","crosses"]},j0={triggerType:{type:"string",enum:["close","wick"],description:"default: close"},isPersistent:{type:"boolean",description:"Re-arm after firing. default: false"},notifyEmail:{type:"boolean",description:"default: true"},notifyPush:{type:"boolean",description:"default: true"},message:{type:"string"},expiresAt:{type:"string",description:"ISO 8601 datetime"}},qX=[T({name:"list_alerts",description:"List your price + trendline alerts. Optionally include archived or filter by pair. Requires sign-in.",inputSchema:{type:"object",properties:{includeArchived:{type:"boolean"},pair:{type:"string"}},additionalProperties:!1},handler:async($,v)=>{return await u(v),SZ(v.trpc,$)}}),T({name:"create_price_alert",description:"Create a price-level alert (fires when price is above/below/crosses a level). Requires sign-in.",inputSchema:{type:"object",properties:{pair:{type:"string",description:"e.g. EURUSD, BTCUSD"},timeframe:{type:"string",description:"e.g. 1h, 4h, 1d"},price:{type:"number"},condition:lz,...j0},required:["pair","timeframe","price","condition"],additionalProperties:!1},handler:async($,v)=>{return await u(v),kZ(v.trpc,$)}}),T({name:"create_trendline_alert",description:"Create a trendline alert (fires when price crosses a line defined by two points). Requires sign-in.",inputSchema:{type:"object",properties:{pair:{type:"string"},timeframe:{type:"string"},price1:{type:"number"},time1:{type:"string",description:"ISO 8601 datetime of point 1"},price2:{type:"number"},time2:{type:"string",description:"ISO 8601 datetime of point 2"},condition:lz,...j0},required:["pair","timeframe","price1","time1","price2","time2","condition"],additionalProperties:!1},handler:async($,v)=>{return await u(v),TZ(v.trpc,$)}}),T({name:"update_alert",description:"Update a price/trendline alert (e.g. change level, archive, mute). Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},price:{type:"number"},price1:{type:"number"},price2:{type:"number"},time1:{type:"string"},time2:{type:"string"},condition:lz,timeframe:{type:"string"},isActive:{type:"boolean"},isArchived:{type:"boolean"},...j0},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await u(v),EZ(v.trpc,$)}}),T({name:"delete_alert",description:"Delete a price/trendline alert by id. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"}},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await u(v),uZ(v.trpc,$)}}),T({name:"list_indicator_alerts",description:"List your indicator-based alerts. Optionally include archived or filter by pair. Requires sign-in.",inputSchema:{type:"object",properties:{includeArchived:{type:"boolean"},pair:{type:"string"}},additionalProperties:!1},handler:async($,v)=>{return await u(v),RZ(v.trpc,$)}}),T({name:"create_indicator_alert",description:"Create an indicator alert (fires on an indicator output condition, e.g. RSI crosses 70). `condition` is { op, threshold } or { op, other }. Requires sign-in.",inputSchema:{type:"object",properties:{pair:{type:"string"},timeframe:{type:"string"},indicatorType:{type:"string",description:"e.g. rsi, ema, macd"},indicatorParams:{type:"object",description:"Indicator settings, e.g. { length: 14 }"},outputSeries:{type:"string",description:"Which output series to watch"},condition:{type:"object",description:"{ op: gt|gte|lt|lte|eq|crosses_above|crosses_below, threshold } or { op: *_series, other }"},dedupMode:{type:"string",enum:["edge","continuous"],description:"default: edge"},...j0},required:["pair","timeframe","indicatorType","indicatorParams","outputSeries","condition"],additionalProperties:!1},handler:async($,v)=>{return await u(v),gZ(v.trpc,$)}}),T({name:"update_indicator_alert",description:"Update an indicator alert (condition, dedup, archive, mute). Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},condition:{type:"object"},dedupMode:{type:"string",enum:["edge","continuous"]},isActive:{type:"boolean"},isArchived:{type:"boolean"},...j0},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await u(v),CZ(v.trpc,$)}}),T({name:"delete_indicator_alert",description:"Delete an indicator alert by id. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"}},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await u(v),xZ(v.trpc,$)}})];var SX=[T({name:"login",description:"Sign in to Aether Wealth. Opens your browser to authenticate; once you approve, the MCP stores a per-user token and the data tools become available.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async($,v)=>{return await v.session.login(),{status:"signed_in",message:"Signed in to Aether Wealth."}}}),T({name:"logout",description:"Sign out of Aether Wealth on this device. Clears the stored access token.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async($,v)=>{return await v.session.logout(),{status:"signed_out",message:"Signed out on this device."}}})];var K$=($,v,D,X)=>{return{id:$,displayName:`${$.slice(0,3)}/${$.slice(3)}`,kind:"forex",exchange:"FX",region:"GLOBAL",category:D,pipSize:X?.pipSize??0.0001,priceDecimals:X?.priceDecimals??5,contractSize:1e5,providers:{twelvedata:v}}},NR=[K$("AUDUSD","AUD/USD","Forex Majors"),K$("EURUSD","EUR/USD","Forex Majors"),K$("GBPUSD","GBP/USD","Forex Majors"),K$("USDCAD","USD/CAD","Forex Majors"),K$("USDCHF","USD/CHF","Forex Majors"),K$("USDJPY","USD/JPY","Forex Majors",{pipSize:0.01,priceDecimals:3}),K$("AUDCAD","AUD/CAD","Forex Minors"),K$("AUDCHF","AUD/CHF","Forex Minors"),K$("AUDJPY","AUD/JPY","Forex Minors",{pipSize:0.01,priceDecimals:3}),K$("AUDNZD","AUD/NZD","Forex Minors"),K$("EURAUD","EUR/AUD","Forex Minors"),K$("EURCAD","EUR/CAD","Forex Minors"),K$("EURCHF","EUR/CHF","Forex Minors"),K$("EURGBP","EUR/GBP","Forex Minors"),K$("EURJPY","EUR/JPY","Forex Minors",{pipSize:0.01,priceDecimals:3}),K$("EURNZD","EUR/NZD","Forex Minors"),K$("GBPAUD","GBP/AUD","Forex Minors"),K$("GBPCAD","GBP/CAD","Forex Minors"),K$("GBPCHF","GBP/CHF","Forex Minors"),K$("GBPJPY","GBP/JPY","Forex Minors",{pipSize:0.01,priceDecimals:3}),K$("GBPNZD","GBP/NZD","Forex Minors")],ZR=[{id:"XAUUSD",displayName:"Gold",kind:"metal",exchange:"OTC",region:"GLOBAL",category:"Metals",pipSize:0.01,priceDecimals:2,contractSize:100,providers:{twelvedata:"XAU/USD"}},{id:"XAGUSD",displayName:"Silver",kind:"metal",exchange:"OTC",region:"GLOBAL",category:"Metals",pipSize:0.001,priceDecimals:3,contractSize:5000,providers:{twelvedata:"XAG/USD"}}];function u$($,v,D=!1){return{id:$,displayName:`${$.slice(0,-3)}/USD`,kind:"crypto",exchange:"CRYPTO",region:"GLOBAL",category:"Crypto",pipSize:D?0.0001:0.01,priceDecimals:D?5:2,contractSize:1,providers:{twelvedata:v}}}var OR=[u$("BTCUSD","BTC/USD"),u$("ETHUSD","ETH/USD"),u$("SOLUSD","SOL/USD"),u$("BNBUSD","BNB/USD"),u$("AVAXUSD","AVAX/USD"),u$("LINKUSD","LINK/USD"),u$("LTCUSD","LTC/USD"),u$("BCHUSD","BCH/USD"),u$("ATOMUSD","ATOM/USD"),u$("TONUSD","TON/USD"),u$("DOTUSD","DOT/USD"),u$("XRPUSD","XRP/USD",!0),u$("ADAUSD","ADA/USD",!0),u$("DOGEUSD","DOGE/USD",!0),u$("TRXUSD","TRX/USD",!0),u$("POLUSD","POL/USD",!0)],AR=[{id:"NAS100",displayName:"Nasdaq 100",kind:"index",exchange:"NASDAQ",region:"US",category:"Indices",pipSize:0.01,priceDecimals:2,contractSize:20,providers:{twelvedata:"QQQ"}}],HR=[{id:"USOIL",displayName:"WTI Crude",kind:"commodity",exchange:"NYMEX",region:"US",category:"Commodities",pipSize:0.01,priceDecimals:2,contractSize:1000,providers:{twelvedata:"WTI/USD"}}];function T4($,v,D){return{id:$,displayName:D,kind:"stock",exchange:"NSE",region:"IN",category:"Indian Stocks",pipSize:0.05,priceDecimals:2,contractSize:1,providers:{twelvedata:v}}}var FR=[{id:"NIFTYBEES",displayName:"NIFTY 50 ETF",kind:"index",exchange:"BSE",region:"IN",category:"Indian Indices",pipSize:0.01,priceDecimals:2,contractSize:1,providers:{twelvedata:"NIFTYBEES:BSE"}},{id:"BANKBEES",displayName:"BANK NIFTY ETF",kind:"index",exchange:"BSE",region:"IN",category:"Indian Indices",pipSize:0.01,priceDecimals:2,contractSize:1,providers:{twelvedata:"BANKBEES:BSE"}},T4("RELIANCE","RELIANCE:NSE","Reliance Industries"),T4("TCS","TCS:NSE","Tata Consultancy Services"),T4("HDFCBANK","HDFCBANK:NSE","HDFC Bank"),T4("INFY","INFY:NSE","Infosys"),T4("ICICIBANK","ICICIBANK:NSE","ICICI Bank"),T4("BHARTIARTL","BHARTIARTL:NSE","Bharti Airtel"),T4("LT","LT:NSE","Larsen & Toubro"),T4("SBIN","SBIN:NSE","State Bank of India"),T4("AXISBANK","AXISBANK:NSE","Axis Bank"),T4("KOTAKBANK","KOTAKBANK:NSE","Kotak Mahindra Bank")],kX=Object.freeze([...NR,...ZR,...OR,...AR,...HR,...FR]);class w0{byKey;instruments;providerNames;constructor($){this.instruments=Object.freeze([...$]);let v=new Map,D=new Set;for(let X of $){if(hz(v,X.id,X,"id"),X.displayName!==X.id)hz(v,X.displayName,X,"displayName");for(let[U,G]of Object.entries(X.providers))if(D.add(U),hz(v,BO(U,G),X,"provider"),!v.has(G))v.set(G,X)}this.byKey=v,this.providerNames=D}resolve($){let v=this.byKey.get($);if(v)return v;let D=$.toUpperCase();if(D!==$){let U=this.byKey.get(D);if(U)return U}let X=$.toLowerCase();if(X!==$)return this.byKey.get(X)??null;return null}require($){let v=this.resolve($);if(!v)throw Error(`Unknown instrument: ${JSON.stringify($)}. Add it to INSTRUMENTS env var or check the key you passed in.`);return v}resolveByProvider($,v){return this.byKey.get(BO($,v))??null}list(){return this.instruments}byKind($){return this.instruments.filter((v)=>v.kind===$)}byExchange($){return this.instruments.filter((v)=>v.exchange===$)}byRegion($){return this.instruments.filter((v)=>v.region===$)}byCategory($){return this.instruments.filter((v)=>v.category===$)}groupByCategory(){let $=new Map;for(let v of this.instruments){let D=$.get(v.category);if(D)D.push(v);else $.set(v.category,[v])}return Array.from($.entries()).map(([v,D])=>({category:v,instruments:D}))}has($){return this.byKey.has($)}stats(){return{instrumentCount:this.instruments.length,providerCount:this.providerNames.size,providers:Array.from(this.providerNames).sort()}}}function BO($,v){return`${$}:${v}`}function hz($,v,D,X){if(X==="provider"){if($.has(v))throw Error(`Duplicate provider symbol ${JSON.stringify(v)} declared by multiple instruments in INSTRUMENTS`)}else if($.has(v))throw Error(`Duplicate instrument ${X} ${JSON.stringify(v)} in INSTRUMENTS (already mapped to ${$.get(v)?.id}, now also to ${D.id})`);$.set(v,D)}var wR=["forex","metal","crypto","index","commodity","stock","bond"],MR=r.object({kind:r.enum(wR),displayName:r.string().min(1).optional(),exchange:r.string().min(1).optional(),region:r.string().min(1).optional(),category:r.string().min(1).optional(),pipSize:r.number().positive().optional(),priceDecimals:r.number().int().min(0).max(12).optional(),contractSize:r.number().positive().optional(),providers:r.record(r.string().min(1),r.string().min(1))}),qp=r.record(r.string().min(1),MR).refine(($)=>Object.keys($).length>0,{message:"INSTRUMENTS must contain at least one entry"});var PR=Object.freeze({AUDUSD:{quote:"https://logo.twelvedata.com/forex/usd.png",base:"https://logo.twelvedata.com/forex/aud.png"},EURUSD:{base:"https://logo.twelvedata.com/forex/eur.png",quote:"https://logo.twelvedata.com/forex/usd.png"},GBPUSD:{quote:"https://logo.twelvedata.com/forex/usd.png",base:"https://logo.twelvedata.com/forex/gbp.png"},USDCAD:{base:"https://logo.twelvedata.com/forex/usd.png",quote:"https://logo.twelvedata.com/forex/cad.png"},USDCHF:{base:"https://logo.twelvedata.com/forex/usd.png",quote:"https://logo.twelvedata.com/forex/chf.png"},USDJPY:{base:"https://logo.twelvedata.com/forex/usd.png",quote:"https://logo.twelvedata.com/forex/jpy.png"},AUDCAD:{base:"https://logo.twelvedata.com/forex/aud.png",quote:"https://logo.twelvedata.com/forex/cad.png"},AUDCHF:{base:"https://logo.twelvedata.com/forex/aud.png",quote:"https://logo.twelvedata.com/forex/chf.png"},AUDJPY:{base:"https://logo.twelvedata.com/forex/aud.png",quote:"https://logo.twelvedata.com/forex/jpy.png"},AUDNZD:{base:"https://logo.twelvedata.com/forex/aud.png",quote:"https://logo.twelvedata.com/forex/nzd.png"},EURAUD:{base:"https://logo.twelvedata.com/forex/eur.png",quote:"https://logo.twelvedata.com/forex/aud.png"},EURCAD:{base:"https://logo.twelvedata.com/forex/eur.png",quote:"https://logo.twelvedata.com/forex/cad.png"},EURCHF:{base:"https://logo.twelvedata.com/forex/eur.png",quote:"https://logo.twelvedata.com/forex/chf.png"},EURGBP:{quote:"https://logo.twelvedata.com/forex/gbp.png",base:"https://logo.twelvedata.com/forex/eur.png"},EURJPY:{base:"https://logo.twelvedata.com/forex/eur.png",quote:"https://logo.twelvedata.com/forex/jpy.png"},EURNZD:{base:"https://logo.twelvedata.com/forex/eur.png",quote:"https://logo.twelvedata.com/forex/nzd.png"},GBPAUD:{base:"https://logo.twelvedata.com/forex/gbp.png",quote:"https://logo.twelvedata.com/forex/aud.png"},GBPCAD:{base:"https://logo.twelvedata.com/forex/gbp.png",quote:"https://logo.twelvedata.com/forex/cad.png"},GBPCHF:{quote:"https://logo.twelvedata.com/forex/chf.png",base:"https://logo.twelvedata.com/forex/gbp.png"},GBPJPY:{base:"https://logo.twelvedata.com/forex/gbp.png",quote:"https://logo.twelvedata.com/forex/jpy.png"},GBPNZD:{base:"https://logo.twelvedata.com/forex/gbp.png",quote:"https://logo.twelvedata.com/forex/nzd.png"},BTCUSD:{base:"https://logo.twelvedata.com/crypto/btc.png",quote:"https://logo.twelvedata.com/crypto/usd.png"},ETHUSD:{quote:"https://logo.twelvedata.com/crypto/usd.png",base:"https://logo.twelvedata.com/crypto/eth.png"},SOLUSD:{quote:"https://logo.twelvedata.com/crypto/usd.png",base:"https://logo.twelvedata.com/crypto/sol.png"},BNBUSD:{quote:"https://logo.twelvedata.com/crypto/usd.png",base:"https://logo.twelvedata.com/crypto/bnb.png"},AVAXUSD:{url:"https://assets.coingecko.com/coins/images/12559/large/Avalanche_Circle_RedWhite_Trans.png"},LINKUSD:{base:"https://logo.twelvedata.com/crypto/link.png",quote:"https://logo.twelvedata.com/crypto/usd.png"},LTCUSD:{base:"https://logo.twelvedata.com/crypto/ltc.png",quote:"https://logo.twelvedata.com/crypto/usd.png"},BCHUSD:{base:"https://logo.twelvedata.com/crypto/bch.png",quote:"https://logo.twelvedata.com/crypto/usd.png"},ATOMUSD:{quote:"https://logo.twelvedata.com/crypto/usd.png",base:"https://logo.twelvedata.com/crypto/atom.png"},TONUSD:{url:"https://assets.coingecko.com/coins/images/17980/large/ton_symbol.png"},DOTUSD:{quote:"https://logo.twelvedata.com/crypto/usd.png",base:"https://logo.twelvedata.com/crypto/dot.png"},XRPUSD:{base:"https://logo.twelvedata.com/crypto/xrp.png",quote:"https://logo.twelvedata.com/crypto/usd.png"},ADAUSD:{quote:"https://logo.twelvedata.com/crypto/usd.png",base:"https://logo.twelvedata.com/crypto/ada.png"},DOGEUSD:{base:"https://logo.twelvedata.com/crypto/doge.png",quote:"https://logo.twelvedata.com/crypto/usd.png"},TRXUSD:{base:"https://logo.twelvedata.com/crypto/trx.png",quote:"https://logo.twelvedata.com/crypto/usd.png"},POLUSD:{url:"https://assets.coingecko.com/coins/images/4713/large/polygon.png"},RELIANCE:{url:"https://api.twelvedata.com/logo/ril.com"},TCS:{url:"https://api.twelvedata.com/logo/tcs.com"},HDFCBANK:{url:"https://api.twelvedata.com/logo/hdfcbank.com"},INFY:{url:"https://api.twelvedata.com/logo/infosys.com"},ICICIBANK:{url:"https://api.twelvedata.com/logo/icicibank.com"},BHARTIARTL:{url:"https://api.twelvedata.com/logo/airtel.in"},LT:{url:"https://api.twelvedata.com/logo/larsentoubro.com"},SBIN:{url:"https://api.twelvedata.com/logo/sbi.co.in"},AXISBANK:{url:"https://api.twelvedata.com/logo/axisbank.com"},KOTAKBANK:{url:"https://api.twelvedata.com/logo/kotak.com"}});function mz($,v){return Number(v.toFixed($.priceDecimals))}var R$="-apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', Roboto, sans-serif",rz=11,cz=15,dz=11,pz=13,VO=12,TX=17,LO=26,KO=0.85,NO=20,ZO=8,OO=64,AO=26,x1=18,EX=16,HO=20,FO=300,tz=120,jO=1280,wO=720,MO=2,PO=!0,bO=320,qO=2560,SO=240,kO=1440,TO=1,EO=3,uX={dark:{background:"#0F0F0F",text:"#D9D9D9",mutedText:"#8A8D96",grid:"rgba(242, 242, 242, 0.06)",axisBorder:"#2B2B43",upCandle:"#10b981",downCandle:"#ef4444",markerText:"#F2F2F2",headerText:"#E8E8EA",badgeBg:"rgba(255, 255, 255, 0.08)",badgeText:"#A6AAB4",watermarkText:"#D9D9D9",tagText:"#FFFFFF",entryTag:"#363C4E"},light:{background:"#FFFFFF",text:"#191919",mutedText:"#6A6E78",grid:"rgba(0, 0, 0, 0.06)",axisBorder:"#E0E3EB",upCandle:"#10b981",downCandle:"#ef4444",markerText:"#191919",headerText:"#131722",badgeBg:"rgba(0, 0, 0, 0.06)",badgeText:"#5F6470",watermarkText:"#191919",tagText:"#FFFFFF",entryTag:"#68707F"}},oz=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function uO($,v){if(!Number.isFinite(v))return"0.00000";if(!$)return v.toFixed(5);return mz($,v).toFixed($.priceDecimals)}function RO($,v,D){let X=new Date(v*1000);if(kR($)){if(D===void 0||RR(D,v))return ER(X);return TR(X)}return uR(X)}function kR($){let v=$.trim();if(v.length===0)return!0;if(/^\d*[DWM]$/.test(v))return!1;if(/(d|w|mo|month)/i.test(v))return!1;return!0}function M0($,v,D){let U=`${$>0?"+":""}${$.toFixed(D)}`;if(v===null||!Number.isFinite(v))return U;let G=v>0?"+":"";return`${U} (${G}${v.toFixed(2)}%)`}function TR($){return`${RX($.getUTCHours())}:${RX($.getUTCMinutes())}`}function ER($){return`${RX($.getUTCDate())} ${oz[$.getUTCMonth()]}`}function uR($){return`${RX($.getUTCDate())} ${oz[$.getUTCMonth()]} '${String($.getUTCFullYear()).slice(-2)}`}function RR($,v){let D=new Date($*1000),X=new Date(v*1000);return D.getUTCFullYear()!==X.getUTCFullYear()||D.getUTCMonth()!==X.getUTCMonth()||D.getUTCDate()!==X.getUTCDate()}function RX($){return String($).padStart(2,"0")}var gO="data:image/png;base64,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";function CO($){return $.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}function Y$($){return`<line${f1($)} />`}function H$($){return`<rect${f1($)} />`}function p$($,v){return`<text${f1(v)}>${CO($)}</text>`}function xO($){return`<image${f1($)} />`}function iO($,v){let D=$.map((X)=>`${az(X.x)},${az(X.y)}`).join(" ");return`<polygon${f1({...v,points:D})} />`}function o($,v={}){if($.length===0)return"";return`<g${f1(v)}>${$}</g>`}function fO($,v,D){return[`<svg xmlns="http://www.w3.org/2000/svg" width="${$}" height="${v}" viewBox="0 0 ${$} ${v}" fill="none">`,D,"</svg>"].join("")}function i1($,v=11){return Math.max(10,Math.round($.length*v*0.58))}function f1($){let v=Object.entries($).filter(([,D])=>D!==void 0&&D!==!1).map(([D,X])=>{if(X===!0)return`${D}="true"`;if(typeof X==="number")return`${D}="${az(X)}"`;if(typeof X==="string")return`${D}="${CO(X)}"`;return""}).filter((D)=>D.length>0).join(" ");return v.length>0?` ${v}`:""}function az($){let v=Math.round($*100)/100;return Number.isInteger(v)?String(v):v.toFixed(2)}var gX=16,gR=9,CR=12,xR=8,iR=8;function nO($,v){let D=[],X=$.plotLeft,U=$.instrument?.displayName??$.pair;D.push(p$(U,{x:X,y:gX,fill:v.headerText,"font-size":cz,"font-weight":700,"letter-spacing":0.2,"font-family":R$})),X+=i1(U,cz)+gR;let G=$.timeframe,J=i1(G,dz)+iR*2,Q=gX-TX+4;D.push(H$({x:X,y:Q,width:J,height:TX,rx:4,fill:v.badgeBg})),D.push(p$(G,{x:X+J/2,y:Q+TX/2+0.5,fill:v.badgeText,"font-size":dz,"font-weight":600,"text-anchor":"middle","dominant-baseline":"middle","font-family":R$})),X+=J+CR;let I=$.visibleCandles,W=I[I.length-1].close,z=I[0].open,Y=W-z,B=z===0?null:Y/z*100,V=Y>=0?v.upCandle:v.downCandle,L=$.formatPrice(W);D.push(p$(L,{x:X,y:gX,fill:V,"font-size":pz,"font-weight":600,"font-family":R$})),X+=i1(L,pz)+xR;let N=$.instrument?.priceDecimals??5;return D.push(p$(M0(Y,B,N),{x:X,y:gX,fill:V,"font-size":VO,"font-weight":500,"font-family":R$})),o(D.join(""))}function _O($,v){if(!v)return"";let D=LO;return xO({href:gO,x:$.plotRight-D-8,y:$.plotBottom-D-8,width:D,height:D,opacity:KO})}var fR=["price","priceHigh","priceLow","price1","price2","entry","stop","target"];function lO($,v){let D=$.candles.slice(-$.bars),X=ZO,U=NO,G=Math.max(X+1,$.width-OO),J=Math.max(U+1,$.height-AO),Q=G-X,I=J-U,W=Q/Math.max(1,D.length),z=Math.min(...D.map((a)=>a.low)),Y=Math.max(...D.map((a)=>a.high)),B=Y-z,V=B>0?B*0.06:Math.max(Math.abs(Y)*0.006,0.000001),L=z-V,N=Y+V,Z=Math.max(N-L,0.000001),H=B>0?Math.max(Z,B/0.6):Z,S=hR($.shapes),R=S.length>0?Math.min(...S):Number.POSITIVE_INFINITY,C=S.length>0?Math.max(...S):Number.NEGATIVE_INFINITY,k=Number.isFinite(R)&&R<L?L-R:0,N$=Number.isFinite(C)&&C>N?C-N:0,F$=Math.max(0,H-Z),u4=k+N$,Q4=L,_$=N;if(u4<=F$)Q4-=k,_$+=N$;else if(k>0&&N$===0)Q4-=Math.min(k,F$);else if(N$>0&&k===0)_$+=Math.min(N$,F$);else if(u4>0){let a=F$/u4;Q4-=k*a,_$+=N$*a}let l1=Math.max(_$-Q4,0.000001),h1=dR(D),m1=D.length-1;function b0(a){return U+(_$-a)/l1*I}function MA(a){if(!Number.isFinite(a))return{y:J,clamped:!0,edge:"bottom"};if(a>_$)return{y:U,clamped:!0,edge:"top"};if(a<Q4)return{y:J,clamped:!0,edge:"bottom"};return{y:b0(a),clamped:!1,edge:null}}function oX(a){return X+(a+0.5)*W}function K5(a){return lR(D,m1,h1,a)}function N5(a){return oX(K5(a))}function Z5(a){return m1-a}function PA(a,O5,SA){let A5=rR(a,O5);if(A5!==void 0)return N5(A5);let kA=cR(a,O5)??SA;return oX(Z5(kA))}function bA(a=6){return nR(Q4,_$,a)}function qA(a=7){return yR(D.length,a)}return{pair:$.pair,timeframe:$.timeframe,theme:$.theme,width:$.width,height:$.height,plotLeft:X,plotTop:U,plotRight:G,plotBottom:J,plotWidth:Q,plotHeight:I,slot:W,visibleCandles:D,instrument:v,priceRange:{min:Q4,max:_$,candleMin:z,candleMax:Y},averageSpacing:h1,formatPrice(a){return uO(v,a)},priceToY:b0,projectPrice:MA,indexToX:oX,timeToIndex:K5,timeToX:N5,barsBackToIndex:Z5,resolveEndpointX:PA,nicePriceTicks:bA,niceTimeTickIndices:qA}}var yO=3;function nR($,v,D=6){let X=pR($,v,D),U=Math.ceil($/X)*X,G=Math.floor(v/X)*X,J=tR(X),Q=[];if(G>=U){let I=Math.round((G-U)/X);for(let W=0;W<=I;W+=1)Q.push(Number((U+W*X).toFixed(J+2)))}if(Q.length<yO)return _R($,v,yO+2);return Q}function _R($,v,D){if(v<=$||D<2)return[$];let X=[];for(let U=0;U<D;U+=1)X.push($+(v-$)*U/(D-1));return X}function yR($,v=7){if($<=0)return[];if($<=v)return Array.from({length:$},(U,G)=>G);let D=new Set,X=($-1)/Math.max(1,v-1);for(let U=0;U<v;U+=1)D.add(Math.round(U*X));return D.add(0),D.add($-1),Array.from(D).sort((U,G)=>U-G)}function lR($,v,D,X){if($.length===1){let J=$[0].time;return(X-J)/D}let U=$[0],G=$[v];if(X<=U.time)return(X-U.time)/D;if(X>=G.time)return v+(X-G.time)/D;return mR($,v,X)}function hR($){let v=[];for(let D of $)for(let X of fR){let U=D[X];if(typeof U==="number"&&Number.isFinite(U))v.push(U)}return v}function mR($,v,D){let X=0,U=v;while(X<=U){let z=Math.floor((X+U)/2),Y=$[z];if(Y.time===D)return z;if(Y.time<D)X=z+1;else U=z-1}let G=Math.min(v,X),J=Math.max(0,G-1),Q=$[J],W=$[G].time-Q.time;if(W<=0)return J;return J+(D-Q.time)/W}function rR($,v){if(v==="start")return $.time1??$.entryTime;return $.time2}function cR($,v){if(v==="start")return $.barsBack1;return $.barsBack2}function dR($){if($.length<2)return 1;let v=0,D=0;for(let X=1;X<$.length;X+=1){let U=$[X].time-$[X-1].time;if(U>0)v+=U,D+=1}if(D===0)return 1;return v/D}function pR($,v,D){let U=Math.max(v-$,0.000001)/Math.max(1,D-1),G=Math.floor(Math.log10(U)),J=[G-1,G,G+1],Q=[1,2,2.5,5,10],I=U,W=Number.POSITIVE_INFINITY;for(let z of J){let Y=10**z;for(let B of Q){let V=B*Y,L=Math.ceil($/V),N=Math.floor(v/V),Z=N>=L?N-L+1:1,H=Math.abs(Z-D);if(H<W)W=H,I=V}}return I}function tR($){let v=0,D=$;while(v<10&&Math.abs(Math.round(D)-D)>0.00000001)D*=10,v+=1;return v}function N6($){return uX[$]}function hO($,v){let D=N6($.theme),X=oR($.nicePriceTicks(),$.formatPrice),U=$.niceTimeTickIndices(),G=[],J=[],Q=$.visibleCandles[$.visibleCandles.length-1],I=$.priceToY(Q.close),W=Q.close>=Q.open?D.upCandle:D.downCandle,z=$.formatPrice(Q.close);for(let N of X){let Z=$.priceToY(N);G.push(Y$({x1:$.plotLeft,y1:Math.round(Z)+0.5,x2:$.plotRight,y2:Math.round(Z)+0.5,stroke:D.grid,"stroke-width":1}));let H=$.formatPrice(N);if(H!==z)J.push(p$(H,{x:$.width-6,y:Z,fill:D.text,"font-size":rz,"font-family":R$,"text-anchor":"end","dominant-baseline":"middle"}))}for(let N of U){let Z=$.visibleCandles[N];if(!Z)continue;let H=$.indexToX(N),R=(N>0?$.visibleCandles[N-1]:void 0)?.time;G.push(Y$({x1:Math.round(H)+0.5,y1:$.plotTop,x2:Math.round(H)+0.5,y2:$.plotBottom,stroke:D.grid,"stroke-width":1})),J.push(p$(RO($.timeframe,Z.time,R),{x:H,y:$.height-8,fill:D.text,"font-size":rz,"font-family":R$,"text-anchor":"middle"}))}J.push(Y$({x1:Math.round($.plotRight)+0.5,y1:$.plotTop,x2:Math.round($.plotRight)+0.5,y2:$.plotBottom,stroke:D.axisBorder,"stroke-width":1})),J.push(Y$({x1:$.plotLeft,y1:Math.round($.plotBottom)+0.5,x2:$.width,y2:Math.round($.plotBottom)+0.5,stroke:D.axisBorder,"stroke-width":1}));let Y=Y$({x1:$.plotLeft,y1:Math.round(I)+0.5,x2:$.plotRight,y2:Math.round(I)+0.5,stroke:W,"stroke-width":1,"stroke-dasharray":"4 4"}),B={y:I,label:$.formatPrice(Q.close),fill:W,height:x1},V=nO($,D),L=_O($,v);return{gridSvg:o(G.join(""),{"shape-rendering":"crispEdges"}),axesSvg:J.join(""),lastPriceSvg:Y,lastPriceTag:B,headerSvg:V,watermarkSvg:L}}function oR($,v){let D=new Set,X=[];for(let U of $){let G=v(U);if(!D.has(G))D.add(G),X.push(U)}return X}function mO($){let v=Math.max(1,Math.round($.slot*0.7)),D=[];for(let X=0;X<$.visibleCandles.length;X+=1){let U=$.visibleCandles[X];if(!U)continue;let G=U.close>=U.open?"#10b981":"#ef4444",J=$.indexToX(X),Q=Math.round(J)+0.5,I=$.priceToY(U.high),W=$.priceToY(U.low),z=$.priceToY(U.open),Y=$.priceToY(U.close),B=Math.min(z,Y),V=Math.max(z,Y),L=Math.max(1,Math.round(V-B)),N=Math.round(J-v/2),Z=Math.round(B);D.push(Y$({x1:Q,y1:Math.round(I)+0.5,x2:Q,y2:Math.round(W)+0.5,stroke:G,"stroke-width":1})),D.push(H$({x:N,y:Z,width:v,height:L,fill:G}))}return o(D.join(""),{"shape-rendering":"crispEdges"})}function rO($,v){if(v.length===0)return"";let D=N6($.theme);return aR(v,$.plotTop+2,$.plotBottom-2).map((U)=>o([H$({x:$.plotRight+1,y:Math.round(U.y-U.height/2),width:$.width-$.plotRight-1,height:U.height,fill:U.fill}),p$(U.label,{x:$.width-6,y:U.y,fill:D.tagText,"font-size":U.height>=x1?11:10,"font-family":R$,"font-weight":600,"text-anchor":"end","dominant-baseline":"middle"})].join(""),{"shape-rendering":"crispEdges"})).join("")}function aR($,v,D){let X=$.map((J)=>({...J})).sort((J,Q)=>J.y-Q.y);if(X.length===0)return X;for(let J=1;J<X.length;J+=1){let Q=X[J-1],I=X[J],W=Q.y+(Q.height+I.height)/2;if(I.y<W)I.y=W}let U=X[X.length-1];if(U.y>D){U.y=D;for(let J=X.length-2;J>=0;J-=1){let Q=X[J+1],I=X[J],W=Q.y-(Q.height+I.height)/2;if(I.y>W)I.y=W}}let G=X[0];if(G.y<v)G.y=v;return X}function ez($){let v=$2($.candles);if(v.length===0)throw Error("Cannot render chart: candles is empty");return{pair:$.pair,timeframe:$.timeframe,candles:v,shapes:$.shapes??[],theme:$.theme??"dark",width:cO($.width,jO,bO,qO),height:cO($.height,wO,SO,kO),bars:eR($.bars??tz),scale:sR($.scale),watermark:$.watermark??PO,...$.fontFiles?{fontFiles:$.fontFiles}:{}}}function eR($){if(!Number.isFinite($))return tz;return sz(Math.round($),HO,FO)}function sR($){if($===void 0||!Number.isFinite($)||$<=0)return MO;return sz($,TO,EO)}function cO($,v,D,X){if($===void 0||!Number.isFinite($)||$<=0)return v;return sz(Math.round($),D,X)}function sz($,v,D){return Math.min(D,Math.max(v,$))}function $2($){return $.filter((v)=>Number.isFinite(v.time)&&Number.isFinite(v.open)&&Number.isFinite(v.high)&&Number.isFinite(v.low)&&Number.isFinite(v.close)).sort((v,D)=>v.time-D.time)}import{createRequire as v2}from"node:module";var U2=v2(import.meta.url);function dO($,v,D,X){let{Resvg:U}=D2();return new U($,{fitTo:{mode:"width",value:Math.round(v*D)},font:{loadSystemFonts:!0,defaultFontFamily:"Inter",...X?{fontFiles:X}:{}},background:"rgba(0,0,0,0)"}).render().asPng()}function D2(){try{return U2("@resvg/resvg-js")}catch($){let v=$ instanceof Error?$.message:String($);throw Error(`chart-render: @resvg/resvg-js could not be loaded for PNG rasterization (${v})`)}}var X2={horizontal_line:"horizontal_line",line:"horizontal_line",hline:"horizontal_line",horizontal:"horizontal_line",horz_line:"horizontal_line",horizontal_ray:"horizontal_ray",hray:"horizontal_ray",horz_ray:"horizontal_ray",horizontalray:"horizontal_ray",h_ray:"horizontal_ray",vertical_line:"vertical_line",vertical:"vertical_line",vline:"vertical_line",vert_line:"vertical_line",vertline:"vertical_line",verticalline:"vertical_line",cross_line:"cross_line",crossline:"cross_line",cross:"cross_line",zone:"zone",horizontal_range:"zone",range:"zone",supply_demand_zone:"zone",rectangle:"rectangle",rect:"rectangle",box:"rectangle",trendline:"trendline",trend:"trendline",trend_line:"trendline",ray:"ray",trend_ray:"ray",right_ray:"right_ray",ray_right:"right_ray",rightray:"right_ray","right-ray":"right_ray",left_ray:"left_ray",ray_left:"left_ray",leftray:"left_ray","left-ray":"left_ray",extended_line:"extended_line",extendedline:"extended_line",extended:"extended_line",extend_line:"extended_line",info_line:"info_line",infoline:"info_line",info:"info_line",trend_angle:"trend_angle",trendangle:"trend_angle",angle:"trend_angle",position:"position",trade:"position",long:"position",short:"position",long_position:"position",short_position:"position"},G2={horizontal_line:{required:[{field:"price",message:"price is required for horizontal_line"}],describe:($)=>`Drew horizontal line at ${$.price}${$.label?` (${$.label})`:""}`},horizontal_ray:{required:[{field:"price",message:"price is required for horizontal_ray"}],describe:($)=>`Drew horizontal ray at ${$.price}${$.label?` (${$.label})`:""}`},vertical_line:{required:[],describe:($)=>{let v=$.time1??$.time2;return`Drew vertical line${v?` at ${v}`:""}${$.label?` (${$.label})`:""}`}},cross_line:{required:[{field:"price",message:"price is required for cross_line"}],describe:($)=>`Drew cross line at ${$.price}${$.label?` (${$.label})`:""}`},zone:{required:[{field:"priceHigh",message:"priceHigh is required for zone"},{field:"priceLow",message:"priceLow is required for zone"}],describe:($)=>`Drew zone from ${$.priceLow} to ${$.priceHigh}${$.label?` (${$.label})`:""}`},rectangle:{required:[{field:"priceHigh",message:"priceHigh is required for rectangle"},{field:"priceLow",message:"priceLow is required for rectangle"}],describe:($)=>`Drew rectangle from ${$.priceLow} to ${$.priceHigh}${$.label?` (${$.label})`:""}`},trendline:{required:[{field:"price1",message:"price1 is required for trendline"},{field:"price2",message:"price2 is required for trendline"}],describe:($)=>`Drew trendline from ${$.price1} to ${$.price2}${$.label?` (${$.label})`:""}`},ray:{required:[{field:"price1",message:"price1 is required for ray"},{field:"price2",message:"price2 is required for ray"}],describe:($)=>`Drew ray from ${$.price1} to ${$.price2}${$.label?` (${$.label})`:""}`},right_ray:{required:[{field:"price1",message:"price1 is required for right_ray"},{field:"price2",message:"price2 is required for right_ray"}],describe:($)=>`Drew right ray from ${$.price1} to ${$.price2}${$.label?` (${$.label})`:""}`},left_ray:{required:[{field:"price1",message:"price1 is required for left_ray"},{field:"price2",message:"price2 is required for left_ray"}],describe:($)=>`Drew left ray from ${$.price1} to ${$.price2}${$.label?` (${$.label})`:""}`},extended_line:{required:[{field:"price1",message:"price1 is required for extended_line"},{field:"price2",message:"price2 is required for extended_line"}],describe:($)=>`Drew extended line from ${$.price1} to ${$.price2}${$.label?` (${$.label})`:""}`},info_line:{required:[{field:"price1",message:"price1 is required for info_line"},{field:"price2",message:"price2 is required for info_line"}],describe:($)=>`Drew info line from ${$.price1} to ${$.price2}${$.label?` (${$.label})`:""}`},trend_angle:{required:[{field:"price1",message:"price1 is required for trend_angle"},{field:"price2",message:"price2 is required for trend_angle"}],describe:($)=>`Drew trend angle from ${$.price1} to ${$.price2}${$.label?` (${$.label})`:""}`},position:{required:[{field:"direction",message:'direction ("long" or "short") is required for position'},{field:"entry",message:"entry is required for position"},{field:"stop",message:"stop is required for position"},{field:"target",message:"target is required for position"}],describe:($)=>`Drew ${$.direction} position — entry ${$.entry}, stop ${$.stop}, target ${$.target}${$.label?` (${$.label})`:""}`}};var J2=["horizontal_line","horizontal_ray","vertical_line","cross_line","zone","rectangle","trendline","trend_line","ray","right_ray","left_ray","extended_line","info_line","trend_angle","position"];function P0($){if(typeof $!=="string")return null;let v=$.trim().toLowerCase();return X2[v]??null}function oO($){return`Unknown shape type: "${String($)}". Supported types: ${J2.join(", ")}`}function $5($){if(typeof $==="number"&&Number.isFinite($))return $;if(typeof $==="string"){let v=$.trim();if(v.length===0)return;let D=Number(v);if(Number.isFinite(D))return D}return}function Q2($){if(typeof $!=="string")return;let v=$.trim().toLowerCase();if(v==="long"||v==="buy")return"long";if(v==="short"||v==="sell")return"short";return}function t$($,v){for(let D of v){let X=$5($[D]);if(X!==void 0)return X}return}function E4($,v,D){let X=$[v];if(!X||typeof X!=="object"||Array.isArray(X))return;return t$(X,D)}function I2($){if(typeof $.type!=="string")return null;let v=$.type.trim().toLowerCase();return v.length>0?v:null}function Z4($,v,D){if($[v]!==void 0||D===void 0)return;$[v]=D}function v5($,v,D){Z4($,v,D===void 0?void 0:Math.trunc(D))}function W2($,v){if($.direction)return;if(v==="long"||v==="short"){$.direction=v;return}if(v==="long_position"||v==="short_position"){$.direction=v==="long_position"?"long":"short";return}$.direction=Q2($.side)}function z2($){return t$($,["level","y","value","priceLevel","linePrice"])??E4($,"point1",["price","y","value"])??E4($,"from",["price","y","value"])}function pO($,v){if(v==="start")return t$($,["startPrice","fromPrice","priceA","p1"])??E4($,"point1",["price","y","value"])??E4($,"from",["price","y","value"]);return t$($,["endPrice","toPrice","priceB","p2"])??E4($,"point2",["price","y","value"])??E4($,"to",["price","y","value"])}function tO($,v){if(v==="start")return t$($,["time","startTime","fromTime","timestamp","t1"])??E4($,"point1",["time","t","timestamp"])??E4($,"from",["time","t","timestamp"]);return t$($,["endTime","toTime","t2"])??E4($,"point2",["time","t","timestamp"])??E4($,"to",["time","t","timestamp"])}function Y2($){Z4($,"price",z2($)),Z4($,"priceHigh",t$($,["high","upper","top","max","priceTop","priceUpper"])),Z4($,"priceLow",t$($,["low","lower","bottom","min","priceBottom","priceLower"])),Z4($,"price1",pO($,"start")),Z4($,"price2",pO($,"end"))}function B2($){v5($,"time1",tO($,"start")),v5($,"time2",tO($,"end")),Z4($,"barsBack1",t$($,["barsBack","barBack","lookback","bars"])),Z4($,"barsBack2",t$($,["barsBackEnd","barBackEnd","lookbackEnd"]))}function V2($){Z4($,"entry",t$($,["entryPrice","open","openPrice"])),Z4($,"stop",t$($,["stopLoss","sl","stopPrice"])),Z4($,"target",t$($,["takeProfit","tp","targetPrice","tpPrice"])),v5($,"entryTime",t$($,["entryTimestamp"]))}function L2($){let v=$5($.priceHigh),D=$5($.priceLow);if(v!==void 0&&D!==void 0&&v<D)$.priceHigh=D,$.priceLow=v}function aO($){if(typeof $!=="object"||$===null||Array.isArray($))return $;let v={...$},D=I2(v),X=P0(D);if(X)v.type=X;return W2(v,D),Y2(v),B2(v),V2(v),L2(v),v}function eO($){return G2[$].required}var K2=r.object({type:r.string().describe('Shape type: "horizontal_line", "horizontal_ray", "vertical_line", "cross_line", "zone", "rectangle", "trendline", "ray", "right_ray", "left_ray", "extended_line", "info_line", "trend_angle", or "position"'),price:r.coerce.number().optional().describe("Price level (required for horizontal_line, horizontal_ray, cross_line)"),priceHigh:r.coerce.number().optional().describe("Upper price boundary (required for zone/rectangle)"),priceLow:r.coerce.number().optional().describe("Lower price boundary (required for zone/rectangle)"),price1:r.coerce.number().optional().describe("First point price (required for trendline/ray/right_ray/left_ray/extended_line/info_line/trend_angle)"),price2:r.coerce.number().optional().describe("Second point price (required for trendline/ray/right_ray/left_ray/extended_line/info_line/trend_angle)"),time1:r.number().int().optional().describe("Absolute time (epoch seconds) of the first endpoint for trendline/rays or anchor for vertical_line. PREFERRED over barsBack1."),time2:r.number().int().optional().describe("Absolute time (epoch seconds) of the second endpoint (trendline/rays) or right edge of a zone. PREFERRED over barsBack2."),barsBack1:r.number().optional().describe("FALLBACK only — bars back from the current bar for first endpoint/anchor (trendline, rays, vertical_line). Use time1 when possible."),barsBack2:r.number().optional().describe("FALLBACK only — bars back from the current bar for second endpoint / zone right edge. Use time2 when possible."),direction:r.enum(["long","short"]).optional().describe('Position direction (required for position): "long" or "short"'),entry:r.coerce.number().optional().describe("Entry price (required for position)"),stop:r.coerce.number().optional().describe("Stop-loss price (required for position)"),target:r.coerce.number().optional().describe("Take-profit price (required for position)"),entryTime:r.number().int().optional().describe("Absolute time (epoch seconds) for the position entry anchor. Defaults to the current bar."),label:r.string().optional().describe('Label text, e.g. "Support", "Resistance", "Demand Zone", "Long EURCHF"'),color:r.string().optional().describe('Color hex, e.g. "#22c55e" green, "#ef4444" red, "#3b82f6" blue')}).superRefine(($,v)=>{let D=P0($.type);if(!D){v.addIssue({code:"custom",message:oO($.type),path:["type"]});return}for(let X of eO(D))if($[X.field]===void 0)v.addIssue({code:"custom",message:X.message,path:[X.field]})}),sO=r.preprocess(aO,K2),mt=r.object({shapes:r.array(sO).min(1)});function $A($){let v=[],D=[];for(let[X,U]of $.entries()){let G=sO.safeParse(U);if(G.success)v.push(G.data);else D.push({index:X,reason:G.error.issues[0]?.message??"invalid shape"})}return{valid:v,invalid:D}}function $4($,v,D){let X={type:$.type,ok:!0,...D?{reason:D}:{},...$.label?{label:$.label}:{}};return{underlaySvg:v.underlaySvg??"",lineSvg:v.lineSvg??"",positionSvg:v.positionSvg??"",chromeSvg:v.chromeSvg??"",gutterTags:v.gutterTags??[],report:X}}function O$($,v){let D={type:$.type,ok:!1,reason:v,...$.label?{label:$.label}:{}};return{underlaySvg:"",lineSvg:"",positionSvg:"",chromeSvg:"",gutterTags:[],report:D}}function k$($){return typeof $==="number"&&Number.isFinite($)?$:void 0}function o$($,v){return $.color&&$.color.trim().length>0?$.color:v}function W$($,v,D,X){let U=$.projectPrice(D);if(!U.clamped||U.edge===null)return"";let G=N6($.theme),J=z$(v,$.plotLeft+10,$.plotRight-10),Q=U.edge==="top"?$.plotTop+4:$.plotBottom-4,I=U.edge==="top"?[{x:J,y:Q},{x:J-5,y:Q+7},{x:J+5,y:Q+7}]:[{x:J,y:Q},{x:J-5,y:Q-7},{x:J+5,y:Q-7}],W=U.edge==="top"?Q+16:Q-10;return o([iO(I,{fill:X}),p$($.formatPrice(D),{x:J,y:W,fill:G.markerText,"font-size":10,"font-family":R$,"text-anchor":"middle"})].join(""))}function U5($,v,D,X,U){let G=i1(D,10)+10;return o([H$({x:$,y:v-10,width:G,height:16,fill:X,"fill-opacity":0.85}),p$(D,{x:$+5,y:v+1,fill:U,"font-size":10,"font-family":R$})].join(""),{"shape-rendering":"crispEdges"})}function O4($,v,D,X,U="start"){return p$(D,{x:$,y:v,fill:X,"font-size":10,"font-family":R$,"text-anchor":U})}function z$($,v,D){return Math.min(D,Math.max(v,$))}var UA="price out of visible range (clamped)";function D5($,v){if(v.type==="zone")return N2($,v);if(v.type==="rectangle")return Z2($,v);return O$(v,`Unsupported area shape: ${v.type}`)}function N2($,v){let D=DA($,v,"zone");if(D.kind==="error")return D.fragments;let X=o$(v,"#3b82f6"),U=z$(D.top+12,$.plotTop+12,$.plotBottom-6),G=(D.left+D.right)/2;return $4(v,{underlaySvg:o(H$({x:D.left,y:D.top,width:D.right-D.left,height:D.bottom-D.top,fill:X,"fill-opacity":0.12}),{"shape-rendering":"crispEdges"}),lineSvg:o([Y$({x1:D.left,y1:Math.round(D.top)+0.5,x2:D.right,y2:Math.round(D.top)+0.5,stroke:X,"stroke-width":1}),Y$({x1:D.left,y1:Math.round(D.bottom)+0.5,x2:D.right,y2:Math.round(D.bottom)+0.5,stroke:X,"stroke-width":1}),v.label?O4(D.left+4,U,v.label,X):"",W$($,G,D.highPrice,X),W$($,G,D.lowPrice,X)].join(""),{"shape-rendering":"crispEdges"})},D.clamped?UA:void 0)}function Z2($,v){let D=DA($,v,"rectangle");if(D.kind==="error")return D.fragments;let X=o$(v,"#f59e0b"),U=z$(D.top+12,$.plotTop+12,$.plotBottom-6),G=(D.left+D.right)/2;return $4(v,{underlaySvg:o(H$({x:D.left,y:D.top,width:D.right-D.left,height:D.bottom-D.top,fill:X,"fill-opacity":0.12}),{"shape-rendering":"crispEdges"}),lineSvg:o([H$({x:D.left,y:D.top,width:D.right-D.left,height:D.bottom-D.top,fill:"none",stroke:X,"stroke-width":1}),v.label?O4(D.left+4,U,v.label,X):"",W$($,G,D.highPrice,X),W$($,G,D.lowPrice,X)].join(""),{"shape-rendering":"crispEdges"})},D.clamped?UA:void 0)}function DA($,v,D){let X=k$(v.priceHigh),U=k$(v.priceLow);if(X===void 0)return{kind:"error",fragments:O$(v,`priceHigh is required for ${D}`)};if(U===void 0)return{kind:"error",fragments:O$(v,`priceLow is required for ${D}`)};let G=$.projectPrice(X),J=$.projectPrice(U),Q=D==="zone"&&!vA(v)?$.plotLeft:z$($.resolveEndpointX(v,"start",24),$.plotLeft,$.plotRight),I=D==="zone"&&!vA(v)?$.plotRight:z$($.resolveEndpointX(v,"end",4),$.plotLeft,$.plotRight),W=Math.min(G.y,J.y),z=Math.max(G.y,J.y);return{kind:"ok",left:Math.min(Q,I),right:Math.max(Q,I),top:W,bottom:z,highPrice:X,lowPrice:U,clamped:G.clamped||J.clamped}}function vA($){return $.time1!==void 0||$.time2!==void 0||$.barsBack1!==void 0||$.barsBack2!==void 0}function CX($,v,D){if(Math.abs(D.x-v.x)<0.000001)return v.y;let X=(D.y-v.y)/(D.x-v.x);return v.y+($-v.x)*X}function XA($,v,D){if(Math.abs(v.x-$.x)<0.000001)return{start:{x:$.x,y:$.y},end:{x:$.x,y:v.y}};return{start:{x:$.x,y:$.y},end:{x:D,y:CX(D,$,v)}}}function GA($,v,D){if(Math.abs(v.x-$.x)<0.000001)return{start:{x:$.x,y:$.y},end:{x:$.x,y:v.y}};return{start:{x:$.x,y:$.y},end:{x:D,y:CX(D,$,v)}}}function JA($,v,D,X,U,G){if(Math.abs(v.x-$.x)<0.000001)return{start:{x:$.x,y:U},end:{x:$.x,y:G}};return{start:{x:D,y:CX(D,$,v)},end:{x:X,y:CX(X,$,v)}}}function X5($,v){return{x:($.x+v.x)/2,y:($.y+v.y)/2}}var n1="price out of visible range (clamped)";function J4($,v){switch(v.type){case"horizontal_line":return O2($,v);case"horizontal_ray":return A2($,v);case"vertical_line":return H2($,v);case"cross_line":return F2($,v);case"trendline":return j2($,v);case"ray":case"right_ray":return w2($,v);case"left_ray":return M2($,v);case"extended_line":return P2($,v);case"info_line":return b2($,v);case"trend_angle":return q2($,v);default:return O$(v,`Unsupported line shape: ${v.type}`)}}function O2($,v){let D=k$(v.price);if(D===void 0)return O$(v,"price is required for horizontal_line");let X=o$(v,"#3b82f6"),U=$.projectPrice(D),G=[Y$({x1:$.plotLeft,y1:Math.round(U.y)+0.5,x2:$.plotRight,y2:Math.round(U.y)+0.5,stroke:X,"stroke-width":1}),v.label?O4($.plotLeft+4,z$(U.y-4,$.plotTop+10,$.plotBottom-4),v.label,X):"",W$($,$.plotRight-12,D,X)].join("");return $4(v,{lineSvg:o(G,{"shape-rendering":"crispEdges"}),gutterTags:[{y:U.y,label:$.formatPrice(D),fill:X,height:x1}]},U.clamped?n1:void 0)}function A2($,v){let D=k$(v.price);if(D===void 0)return O$(v,"price is required for horizontal_ray");let X=o$(v,"#3b82f6"),U=$.projectPrice(D),G=$.resolveEndpointX(v,"start",0),J=z$(G+4,$.plotLeft+4,$.plotRight-60);return $4(v,{lineSvg:o([Y$({x1:z$(G,$.plotLeft,$.plotRight),y1:Math.round(U.y)+0.5,x2:$.plotRight,y2:Math.round(U.y)+0.5,stroke:X,"stroke-width":1}),v.label?O4(J,z$(U.y-4,$.plotTop+10,$.plotBottom-4),v.label,X):"",W$($,G,D,X)].join(""),{"shape-rendering":"crispEdges"})},U.clamped?n1:void 0)}function H2($,v){let D=o$(v,"#f59e0b"),X=$.resolveEndpointX(v,"start",0),U=z$(X,$.plotLeft,$.plotRight);return $4(v,{lineSvg:o([Y$({x1:Math.round(U)+0.5,y1:$.plotTop,x2:Math.round(U)+0.5,y2:$.plotBottom,stroke:D,"stroke-width":1,"stroke-dasharray":"4 4"}),v.label?O4(U+4,$.plotTop+12,v.label,D):""].join(""),{"shape-rendering":"crispEdges"})})}function F2($,v){let D=k$(v.price);if(D===void 0)return O$(v,"price is required for cross_line");let X=o$(v,"#38bdf8"),U=$.projectPrice(D),G=z$($.resolveEndpointX(v,"start",0),$.plotLeft,$.plotRight);return $4(v,{lineSvg:o([Y$({x1:$.plotLeft,y1:Math.round(U.y)+0.5,x2:$.plotRight,y2:Math.round(U.y)+0.5,stroke:X,"stroke-width":1,"stroke-dasharray":"4 4"}),Y$({x1:Math.round(G)+0.5,y1:$.plotTop,x2:Math.round(G)+0.5,y2:$.plotBottom,stroke:X,"stroke-width":1,"stroke-dasharray":"4 4"}),v.label?O4(G+4,z$(U.y-4,$.plotTop+10,$.plotBottom-4),v.label,X):"",W$($,G,D,X)].join(""),{"shape-rendering":"crispEdges"})},U.clamped?n1:void 0)}function j2($,v){let D=_1($,v,"trendline");if(D.kind==="error")return D.fragments;return S2($,v,D.first,D.second,"#f59e0b","4 4")}function w2($,v){let D=_1($,v,v.type);if(D.kind==="error")return D.fragments;let X=o$(v,"#f59e0b"),U=XA(D.first,D.second,$.plotRight);return xX($,v,U.start,U.end,X,"4 4",[W$($,D.first.x,D.price1,X),W$($,D.second.x,D.price2,X)])}function M2($,v){let D=_1($,v,"left_ray");if(D.kind==="error")return D.fragments;let X=o$(v,"#f59e0b"),U=GA(D.first,D.second,$.plotLeft);return xX($,v,U.start,U.end,X,"4 4",[W$($,D.first.x,D.price1,X),W$($,D.second.x,D.price2,X)])}function P2($,v){let D=_1($,v,"extended_line");if(D.kind==="error")return D.fragments;let X=o$(v,"#f59e0b"),U=JA(D.first,D.second,$.plotLeft,$.plotRight,$.plotTop,$.plotBottom);return xX($,v,U.start,U.end,X,"4 4",[W$($,D.first.x,D.price1,X),W$($,D.second.x,D.price2,X)])}function b2($,v){let D=_1($,v,"info_line");if(D.kind==="error")return D.fragments;let X=o$(v,"#22c55e"),U=D.price2-D.price1,G=D.price1===0?null:U/D.price1*100,J=$.instrument?.priceDecimals??5,Q=v.label?`${v.label} · ${M0(U,G,J)}`:M0(U,G,J),I=X5(D.first,D.second);return $4(v,{lineSvg:o([Y$({x1:D.first.x,y1:D.first.y,x2:D.second.x,y2:D.second.y,stroke:X,"stroke-width":1}),U5(z$(I.x-30,$.plotLeft+2,$.plotRight-120),z$(I.y-6,$.plotTop+12,$.plotBottom-12),Q,X,"#FFFFFF"),W$($,D.first.x,D.price1,X),W$($,D.second.x,D.price2,X)].join(""),{"shape-rendering":"crispEdges"})},D.clamped?n1:void 0)}function q2($,v){let D=_1($,v,"trend_angle");if(D.kind==="error")return D.fragments;let X=o$(v,"#a855f7"),U=Math.atan2(D.first.y-D.second.y,D.second.x-D.first.x)*180/Math.PI,G=v.label?`${v.label} · ${U.toFixed(1)}°`:`${U.toFixed(1)}°`,J=X5(D.first,D.second);return $4(v,{lineSvg:o([Y$({x1:D.first.x,y1:D.first.y,x2:D.second.x,y2:D.second.y,stroke:X,"stroke-width":1}),U5(z$(J.x-26,$.plotLeft+2,$.plotRight-100),z$(J.y-6,$.plotTop+12,$.plotBottom-12),G,X,"#FFFFFF"),W$($,D.first.x,D.price1,X),W$($,D.second.x,D.price2,X)].join(""),{"shape-rendering":"crispEdges"})},D.clamped?n1:void 0)}function S2($,v,D,X,U,G){let J=o$(v,U);return xX($,v,D,X,J,G,[W$($,D.x,k$(v.price1)??0,J),W$($,X.x,k$(v.price2)??0,J)])}function xX($,v,D,X,U,G,J){let Q=z$(X.x+4,$.plotLeft+4,$.plotRight-70),I=z$(X.y-4,$.plotTop+12,$.plotBottom-4),W=k$(v.price1),z=k$(v.price2),Y=W!==void 0&&$.projectPrice(W).clamped||z!==void 0&&$.projectPrice(z).clamped;return $4(v,{lineSvg:o([Y$({x1:D.x,y1:D.y,x2:X.x,y2:X.y,stroke:U,"stroke-width":1,...G?{"stroke-dasharray":G}:{}}),v.label?O4(Q,I,v.label,U):"",...J].join(""),{"shape-rendering":"crispEdges"})},Y?n1:void 0)}function _1($,v,D){let X=k$(v.price1),U=k$(v.price2);if(X===void 0)return{kind:"error",fragments:O$(v,`price1 is required for ${D}`)};if(U===void 0)return{kind:"error",fragments:O$(v,`price2 is required for ${D}`)};let G=$.projectPrice(X),J=$.projectPrice(U),Q={x:z$($.resolveEndpointX(v,"start",50),$.plotLeft,$.plotRight),y:G.y},I={x:z$($.resolveEndpointX(v,"end",0),$.plotLeft,$.plotRight),y:J.y};return{kind:"ok",first:Q,second:I,price1:X,price2:U,clamped:G.clamped||J.clamped}}var k2="price out of visible range (clamped)";function QA($,v){if(v.direction!=="long"&&v.direction!=="short")return O$(v,'direction ("long" or "short") is required for position');let D=k$(v.entry),X=k$(v.stop),U=k$(v.target);if(D===void 0)return O$(v,"entry is required for position");if(X===void 0)return O$(v,"stop is required for position");if(U===void 0)return O$(v,"target is required for position");let G=N6($.theme),J=z$($.resolveEndpointX(v,"start",0),$.plotLeft,$.plotRight),Q=$.projectPrice(D),I=$.projectPrice(X),W=$.projectPrice(U),z=Math.min(Q.y,W.y),Y=Math.max(Q.y,W.y),B=Math.min(Q.y,I.y),V=Math.max(Q.y,I.y),L=z$(Math.min(z,B)+12,$.plotTop+12,$.plotBottom-8),N=Q.clamped||I.clamped||W.clamped;return $4(v,{positionSvg:o([H$({x:J,y:z,width:$.plotRight-J,height:Y-z,fill:"#10b981","fill-opacity":0.12}),H$({x:J,y:B,width:$.plotRight-J,height:V-B,fill:"#ef4444","fill-opacity":0.12}),Y$({x1:J,y1:Math.round(Q.y)+0.5,x2:$.plotRight,y2:Math.round(Q.y)+0.5,stroke:G.entryTag,"stroke-width":1}),Y$({x1:J,y1:Math.round(I.y)+0.5,x2:$.plotRight,y2:Math.round(I.y)+0.5,stroke:"#ef4444","stroke-width":1}),Y$({x1:J,y1:Math.round(W.y)+0.5,x2:$.plotRight,y2:Math.round(W.y)+0.5,stroke:"#10b981","stroke-width":1}),v.label?O4(J+4,L,v.label,G.text):"",W$($,J,D,G.entryTag),W$($,J,X,"#ef4444"),W$($,J,U,"#10b981")].join(""),{"shape-rendering":"crispEdges"}),gutterTags:[{y:Q.y,label:`Entry ${$.formatPrice(D)}`,fill:G.entryTag,height:EX},{y:I.y,label:`SL ${$.formatPrice(X)}`,fill:"#ef4444",height:EX},{y:W.y,label:`TP ${$.formatPrice(U)}`,fill:"#10b981",height:EX}]},N?k2:void 0)}var T2={horizontal_line:J4,horizontal_ray:J4,vertical_line:J4,cross_line:J4,zone:D5,rectangle:D5,trendline:J4,ray:J4,right_ray:J4,left_ray:J4,extended_line:J4,info_line:J4,trend_angle:J4,position:QA};function IA($,v){let D=[],X=[],U=[],G=[],J=[],Q=[],I=0,W=0;for(let z of v){let Y=E2($,z);if(D.push(Y.underlaySvg),X.push(Y.lineSvg),U.push(Y.positionSvg),G.push(Y.chromeSvg),J.push(...Y.gutterTags),Q.push(Y.report),Y.report.ok)I+=1;else W+=1}return{underlaySvg:D.join(""),lineSvg:X.join(""),positionSvg:U.join(""),chromeSvg:G.join(""),gutterTags:J,reports:Q,drawn:I,skipped:W}}function E2($,v){let D=P0(v.type);if(!D)return O$(v,`Unknown shape type: ${String(v.type)}`);let X=T2[D];if(!X)return O$(v,`Unsupported shape type: ${D}`);let U=D===v.type?v:{...v,type:D};return X($,U)}var G5;function WA($){let v=ez($),D=u2(v.pair),X=lO(v,D),U=uX[v.theme],G=IA(X,v.shapes),J=hO(X,v.watermark),Q=`plot-clip-${C2(X)}`,I=`<defs><clipPath id="${Q}">${H$({x:X.plotLeft,y:X.plotTop,width:X.plotWidth,height:X.plotHeight})}</clipPath></defs>`,W={"clip-path":`url(#${Q})`},z=o(J.gridSvg,W),Y=o(G.underlaySvg,W),B=o(mO(X),W),V=o(G.lineSvg,W),L=o(G.positionSvg,W),N=rO(X,[...G.gutterTags,J.lastPriceTag]);return{svg:fO(X.width,X.height,[H$({x:0,y:0,width:X.width,height:X.height,fill:U.background}),I,z,Y,B,V,L,J.axesSvg,G.chromeSvg,J.lastPriceSvg,N,J.headerSvg,J.watermarkSvg,g2()].join("")),width:X.width,height:X.height,drawn:G.drawn,skipped:G.skipped,shapes:G.reports,priceRange:{min:X.priceRange.min,max:X.priceRange.max}}}function J5($){let v=WA($),D=ez($);return{...v,png:dO(v.svg,v.width,D.scale,D.fontFiles)}}function u2($){return R2().resolve($)}function R2(){if(G5===void 0)G5=new w0([...kX]);return G5}function g2(){return`<style>text{font-family:${R$};white-space:pre}</style>`}function C2($){let v=$.visibleCandles,D=v[0]?.time??0,X=v[v.length-1]?.time??0,U=`${$.pair}|${$.timeframe}|${$.width}x${$.height}|${v.length}|${D}|${X}`,G=2166136261;for(let J=0;J<U.length;J+=1)G^=U.charCodeAt(J),G=Math.imul(G,16777619);return(G>>>0).toString(36)}var zA=120,Q5=20,I5=200;function x2($,v,D){return Math.max(v,Math.min(D,$))}var i2="Render an annotated candlestick chart image (PNG) for a pair + timeframe. Fetches recent candles and draws optional shapes (support/resistance lines, zones, trendlines, a long/short position) using the same vocabulary as draw_chart_shape. Returns the chart as an image plus a text summary. PREFER absolute time anchors (time1/time2/entryTime, epoch seconds from get_candles) over barsBack*.",f2="Optional annotations. Each item is {type, ...}: horizontal_line/horizontal_ray/cross_line need `price`; zone/rectangle need `priceHigh`+`priceLow`; trendline/ray/right_ray/left_ray/extended_line/info_line/trend_angle need `price1`+`price2` (prefer `time1`+`time2` epoch seconds); position needs `direction` (long/short)+`entry`+`stop`+`target`. Optional `label` and `color` (hex).",iX=[T({name:"render_chart",description:i2,inputSchema:{type:"object",properties:{pair:{type:"string",description:"Canonical instrument id, e.g. EURUSD (case-insensitive)"},timeframe:{type:"string",description:"e.g. 1m, 5m, 15m, 30m, 1h, 4h, 1d (or an integer multiple)"},shapes:{type:"array",description:f2,items:{type:"object"}},bars:{type:"integer",minimum:Q5,maximum:I5,description:`Most-recent candles to show (${Q5}-${I5}, default ${zA})`},theme:{type:"string",enum:["dark","light"],description:"Color theme (default dark)"},width:{type:"integer",minimum:320,maximum:2560,description:"Image width in px (320-2560, default 1280)"},height:{type:"integer",minimum:240,maximum:1440,description:"Image height in px (240-1440, default 720)"}},required:["pair","timeframe"],additionalProperties:!1},handler:async($,v)=>{await u(v);let D=x2($.bars??zA,Q5,I5),{candles:X}=await PX(v.trpc,{pair:$.pair,timeframe:$.timeframe,limit:D});if(X.length===0)throw Error(`No candles available for ${$.pair} ${$.timeframe}. Check the pair/timeframe with get_market_config.`);let{valid:U,invalid:G}=$A($.shapes??[]),J=J5({pair:$.pair,timeframe:$.timeframe,candles:X,shapes:U,bars:D,...$.theme?{theme:$.theme}:{},...$.width?{width:$.width}:{},...$.height?{height:$.height}:{}}),Q=J.shapes.filter((Y)=>!Y.ok),I=[...G.map((Y)=>`shape ${Y.index}: ${Y.reason}`),...Q.map((Y)=>`${Y.type}: ${Y.reason??"undrawable"}`)],W=I.length>0?` (${I.length} skipped)
|
|
106
|
+
`)}}]}]}function fz(){return[{uri:"aetherwealth://capabilities",name:"Aether Wealth capabilities",description:"What Aether Wealth can do across all surfaces, and which actions are MCP-callable vs dashboard-only. Attach for product context.",mimeType:"text/markdown",handler:async()=>({text:MZ()})}]}function hu($){return{...$.broker===void 0?{}:{broker:$.broker},...$.accountType===void 0?{}:{accountType:$.accountType},...$.initialBalance===void 0?{}:{initialBalance:$.initialBalance},...$.currency===void 0?{}:{currency:$.currency},...$.notes===void 0?{}:{notes:$.notes},...$.defaultRiskAmount===void 0?{}:{defaultRiskAmount:$.defaultRiskAmount}}}function mu($){return{name:$.name,...hu($)}}function PZ($){return $.trading.accounts.list.query()}function bZ($,v){return $.trading.accounts.create.mutate(mu(v))}function nz($){return{triggerType:$.triggerType??"close",isPersistent:$.isPersistent??!1,notifyEmail:$.notifyEmail??!0,notifyPush:$.notifyPush??!0,...$.message===void 0?{}:{message:$.message},...$.expiresAt===void 0?{}:{expiresAt:$.expiresAt}}}function qZ($){return{...$.includeArchived===void 0?{}:{includeArchived:$.includeArchived},...$.pair===void 0?{}:{pair:$.pair}}}function ru($){return{id:$.id,...$.price===void 0?{}:{price:$.price},...$.price1===void 0?{}:{price1:$.price1},...$.price2===void 0?{}:{price2:$.price2},...$.time1===void 0?{}:{time1:$.time1},...$.time2===void 0?{}:{time2:$.time2},...$.condition===void 0?{}:{condition:$.condition},...$.triggerType===void 0?{}:{triggerType:$.triggerType},...$.timeframe===void 0?{}:{timeframe:$.timeframe},...$.isActive===void 0?{}:{isActive:$.isActive},...$.isArchived===void 0?{}:{isArchived:$.isArchived},...$.isPersistent===void 0?{}:{isPersistent:$.isPersistent},...$.notifyEmail===void 0?{}:{notifyEmail:$.notifyEmail},...$.notifyPush===void 0?{}:{notifyPush:$.notifyPush},...$.message===void 0?{}:{message:$.message},...$.expiresAt===void 0?{}:{expiresAt:$.expiresAt}}}function cu($){return{id:$.id,...$.condition===void 0?{}:{condition:$.condition},...$.dedupMode===void 0?{}:{dedupMode:$.dedupMode},...$.triggerType===void 0?{}:{triggerType:$.triggerType},...$.isActive===void 0?{}:{isActive:$.isActive},...$.isArchived===void 0?{}:{isArchived:$.isArchived},...$.isPersistent===void 0?{}:{isPersistent:$.isPersistent},...$.notifyEmail===void 0?{}:{notifyEmail:$.notifyEmail},...$.notifyPush===void 0?{}:{notifyPush:$.notifyPush},...$.message===void 0?{}:{message:$.message},...$.expiresAt===void 0?{}:{expiresAt:$.expiresAt}}}function SZ($,v){return $.alerts.list.query(qZ(v))}function kZ($,v){let D={pair:v.pair,timeframe:v.timeframe,price:v.price,condition:v.condition,...nz(v)};return $.alerts.createPrice.mutate(D)}function TZ($,v){let D={pair:v.pair,timeframe:v.timeframe,price1:v.price1,time1:v.time1,price2:v.price2,time2:v.time2,condition:v.condition,...nz(v)};return $.alerts.createTrendline.mutate(D)}function EZ($,v){return $.alerts.update.mutate(ru(v))}function uZ($,v){return $.alerts.delete.mutate({id:v.id})}function RZ($,v){let D=qZ(v);return $.alerts.indicator.list.query(D)}function gZ($,v){let D={pair:v.pair,timeframe:v.timeframe,indicatorType:v.indicatorType,indicatorParams:v.indicatorParams,outputSeries:v.outputSeries,condition:v.condition,dedupMode:v.dedupMode??"edge",...nz(v)};return $.alerts.indicator.create.mutate(D)}function CZ($,v){return $.alerts.indicator.update.mutate(cu(v))}function xZ($,v){return $.alerts.indicator.delete.mutate({id:v.id})}function du($){return{accountId:$.accountId,region:$.region,providerAccountRef:$.providerAccountRef,providerToken:$.providerToken,...$.provider===void 0?{}:{provider:$.provider},...$.approvalMode===void 0?{}:{approvalMode:$.approvalMode}}}function _z($){return{accountId:$.accountId}}function pu($){return{accountId:$.accountId,approvalMode:$.approvalMode,...$.totpCode===void 0?{}:{totpCode:$.totpCode}}}function tu($){return{accountId:$.accountId,symbol:$.symbol,direction:$.direction,stopLoss:$.stopLoss,...$.orderType===void 0?{}:{orderType:$.orderType},...$.entryPrice===void 0?{}:{entryPrice:$.entryPrice},...$.takeProfit===void 0?{}:{takeProfit:$.takeProfit},...$.riskPercent===void 0?{}:{riskPercent:$.riskPercent},...$.riskAmount===void 0?{}:{riskAmount:$.riskAmount}}}function ou($){return{intentId:$.intentId,...$.code===void 0?{}:{code:$.code}}}function au($){return{intentId:$.intentId}}function eu($){return{intentId:$.intentId}}function su($){return{accountId:$.accountId,positionId:$.positionId,...$.volume===void 0?{}:{volume:$.volume}}}function $R($){return{accountId:$.accountId,positionId:$.positionId,...$.stopLoss===void 0?{}:{stopLoss:$.stopLoss},...$.takeProfit===void 0?{}:{takeProfit:$.takeProfit}}}function iZ($,v){return $.execution.connect.mutate(du(v))}function fZ($,v){return $.execution.status.query(_z(v))}function nZ($,v){return $.execution.setApprovalMode.mutate(pu(v))}function _Z($,v){return $.execution.account.query(_z(v))}function yZ($,v){return $.execution.positions.query(_z(v))}function lZ($,v){return $.execution.propose.mutate(tu(v))}function hZ($,v){return $.execution.execute.mutate(ou(v))}function mZ($,v){return $.execution.cancel.mutate(au(v))}function rZ($,v){return $.execution.intentStatus.query(eu(v))}function cZ($,v){return $.execution.closePosition.mutate(su(v))}function dZ($,v){return $.execution.modifyPosition.mutate($R(v))}function vR($){return{pair:$.pair,interval:$.interval,indicators:$.indicators.map((v)=>({name:v.name,...v.params===void 0?{}:{params:v.params}})),...$.outputsize===void 0?{}:{outputsize:$.outputsize}}}function pZ($,v){return $.technicalIndicators.get.query(vR(v))}var tZ=["3m","6m","12m","24m","all"];function UR($){return{...$.currency===void 0?{}:{currency:$.currency},...$.from===void 0?{}:{from:$.from},...$.to===void 0?{}:{to:$.to},...$.indicator===void 0?{}:{indicator:$.indicator},...$.impactMin===void 0?{}:{impactMin:$.impactMin},...$.view===void 0?{}:{view:$.view}}}function DR($){return{currency:$.currency,indicator:$.indicator,...$.from===void 0?{}:{from:$.from},...$.to===void 0?{}:{to:$.to},...$.limit===void 0?{}:{limit:$.limit}}}function XR($){return{currency:$.currency,indicator:$.indicator,...$.range===void 0?{}:{range:$.range}}}function GR($){return{pair:$.pair,timeframe:$.timeframe,...$.limit===void 0?{}:{limit:$.limit},...$.offset===void 0?{}:{offset:$.offset},...$.cursor===void 0?{}:{cursor:$.cursor}}}function PX($,v){return $.marketData.mcpCandles.query(GR(v))}function oZ($,v){return $.marketData.listCalendar.query(UR(v))}function aZ($,v){return $.marketData.listIndicatorSeries.query(DR(v))}function eZ($,v){return $.macroIndicator.list.query(XR(v))}function sZ($){return $.marketData.getConfig.query()}function JR($){return{...$.accountId===void 0?{}:{accountId:$.accountId},...$.pair===void 0?{}:{pair:$.pair},...$.from===void 0?{}:{from:$.from},...$.to===void 0?{}:{to:$.to}}}function $O($,v){return $.trading.analytics.stats.query(JR(v))}function QR($){return{...$.accountId===void 0?{}:{accountId:$.accountId},...$.status===void 0||$.status==="ALL"?{}:{status:$.status},...$.pair===void 0?{}:{pair:$.pair},...$.from===void 0?{}:{from:$.from},...$.to===void 0?{}:{to:$.to},...$.page===void 0?{}:{page:$.page},...$.limit===void 0?{}:{limit:$.limit}}}function vO($){return{...$.stopLoss===void 0?{}:{stopLoss:$.stopLoss},...$.takeProfit===void 0?{}:{takeProfit:$.takeProfit},...$.lotSize===void 0?{}:{lotSize:$.lotSize},...$.notes===void 0?{}:{notes:$.notes},...$.timeframe===void 0?{}:{timeframe:$.timeframe},...$.riskPercent===void 0?{}:{riskPercent:$.riskPercent},...$.tags===void 0?{}:{tags:$.tags}}}function IR($){return{accountId:$.accountId,pair:$.pair,direction:$.direction,entryPrice:$.entryPrice,entryTime:$.entryTime,...vO($)}}function WR($){return{id:$.id,...$.pair===void 0?{}:{pair:$.pair},...$.direction===void 0?{}:{direction:$.direction},...$.entryPrice===void 0?{}:{entryPrice:$.entryPrice},...$.entryTime===void 0?{}:{entryTime:$.entryTime},...vO($)}}function zR($){return{id:$.id,exitPrice:$.exitPrice,exitTime:$.exitTime,...$.fees===void 0?{}:{fees:$.fees},...$.swap===void 0?{}:{swap:$.swap},...$.notes===void 0?{}:{notes:$.notes}}}function YR($){return{accountId:$.accountId,status:$.status}}function BR($){return{pair:$.pair,direction:$.direction,entryPrice:$.entryPrice,lotSize:$.lotSize,entryTime:$.entryTime,...$.exitPrice===void 0?{}:{exitPrice:$.exitPrice},...$.stopLoss===void 0?{}:{stopLoss:$.stopLoss},...$.takeProfit===void 0?{}:{takeProfit:$.takeProfit},...$.exitTime===void 0?{}:{exitTime:$.exitTime},...$.notes===void 0?{}:{notes:$.notes},...$.timeframe===void 0?{}:{timeframe:$.timeframe},...$.emotionalTag===void 0?{}:{emotionalTag:$.emotionalTag},...$.fees===void 0?{}:{fees:$.fees},...$.swap===void 0?{}:{swap:$.swap},...$.reportedPnl===void 0?{}:{reportedPnl:$.reportedPnl},...$.tags===void 0?{}:{tags:$.tags}}}function VR($){return{accountId:$.accountId,trades:$.trades.map(BR)}}function UO($,v){return $.trading.trades.list.query(QR(v))}function DO($,v){return $.trading.trades.get.query({id:v.id})}function XO($,v){return $.trading.trades.create.mutate(IR(v))}function GO($,v){return $.trading.trades.update.mutate(WR(v))}function JO($,v){return $.trading.trades.close.mutate(zR(v))}function QO($,v){return $.trading.trades.delete.mutate({id:v.id})}function IO($,v){return $.trading.trades.deleteMany.mutate(YR(v))}function WO($,v){return $.trading.trades.importMany.mutate(VR(v))}function T($){return $}var yz='Not signed in to Aether Wealth. Call the "login" tool to authenticate, then retry.';async function u($){if(!await $.session.getAccessToken())throw Error(yz)}var zO={type:"integer",minimum:1,maximum:200,description:"Max rows to return"},YO={type:"integer",minimum:1,description:"Page number (1-indexed)"};function bX($,v){if(v===null||v===void 0){if($.required&&$.required.length>0)return{ok:!1,reason:`missing required: ${$.required.join(", ")}`};return{ok:!0,args:{}}}if(typeof v!=="object"||Array.isArray(v))return{ok:!1,reason:"args must be an object"};let D=v,X=LR($,D)??KR($,D);return X?{ok:!1,reason:X}:{ok:!0,args:D}}function LR($,v){for(let D of $.required??[])if(!(D in v)||v[D]===void 0||v[D]===null)return`missing required: ${D}`;return null}function KR($,v){if($.additionalProperties!==!1)return null;for(let D of Object.keys(v))if(!(D in $.properties))return`unknown property: ${D}`;return null}var lz={type:"string",enum:["above","below","crosses"]},j0={triggerType:{type:"string",enum:["close","wick"],description:"default: close"},isPersistent:{type:"boolean",description:"Re-arm after firing. default: false"},notifyEmail:{type:"boolean",description:"default: true"},notifyPush:{type:"boolean",description:"default: true"},message:{type:"string"},expiresAt:{type:"string",description:"ISO 8601 datetime"}},qX=[T({name:"list_alerts",description:"List your price + trendline alerts. Optionally include archived or filter by pair. Requires sign-in.",inputSchema:{type:"object",properties:{includeArchived:{type:"boolean"},pair:{type:"string"}},additionalProperties:!1},handler:async($,v)=>{return await u(v),SZ(v.trpc,$)}}),T({name:"create_price_alert",description:"Create a price-level alert (fires when price is above/below/crosses a level). Requires sign-in.",inputSchema:{type:"object",properties:{pair:{type:"string",description:"e.g. EURUSD, BTCUSD"},timeframe:{type:"string",description:"e.g. 1h, 4h, 1d"},price:{type:"number"},condition:lz,...j0},required:["pair","timeframe","price","condition"],additionalProperties:!1},handler:async($,v)=>{return await u(v),kZ(v.trpc,$)}}),T({name:"create_trendline_alert",description:"Create a trendline alert (fires when price crosses a line defined by two points). Requires sign-in.",inputSchema:{type:"object",properties:{pair:{type:"string"},timeframe:{type:"string"},price1:{type:"number"},time1:{type:"string",description:"ISO 8601 datetime of point 1"},price2:{type:"number"},time2:{type:"string",description:"ISO 8601 datetime of point 2"},condition:lz,...j0},required:["pair","timeframe","price1","time1","price2","time2","condition"],additionalProperties:!1},handler:async($,v)=>{return await u(v),TZ(v.trpc,$)}}),T({name:"update_alert",description:"Update a price/trendline alert (e.g. change level, archive, mute). Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},price:{type:"number"},price1:{type:"number"},price2:{type:"number"},time1:{type:"string"},time2:{type:"string"},condition:lz,timeframe:{type:"string"},isActive:{type:"boolean"},isArchived:{type:"boolean"},...j0},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await u(v),EZ(v.trpc,$)}}),T({name:"delete_alert",description:"Delete a price/trendline alert by id. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"}},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await u(v),uZ(v.trpc,$)}}),T({name:"list_indicator_alerts",description:"List your indicator-based alerts. Optionally include archived or filter by pair. Requires sign-in.",inputSchema:{type:"object",properties:{includeArchived:{type:"boolean"},pair:{type:"string"}},additionalProperties:!1},handler:async($,v)=>{return await u(v),RZ(v.trpc,$)}}),T({name:"create_indicator_alert",description:"Create an indicator alert (fires on an indicator output condition, e.g. RSI crosses 70). `condition` is { op, threshold } or { op, other }. Requires sign-in.",inputSchema:{type:"object",properties:{pair:{type:"string"},timeframe:{type:"string"},indicatorType:{type:"string",description:"e.g. rsi, ema, macd"},indicatorParams:{type:"object",description:"Indicator settings, e.g. { length: 14 }"},outputSeries:{type:"string",description:"Which output series to watch"},condition:{type:"object",description:"{ op: gt|gte|lt|lte|eq|crosses_above|crosses_below, threshold } or { op: *_series, other }"},dedupMode:{type:"string",enum:["edge","continuous"],description:"default: edge"},...j0},required:["pair","timeframe","indicatorType","indicatorParams","outputSeries","condition"],additionalProperties:!1},handler:async($,v)=>{return await u(v),gZ(v.trpc,$)}}),T({name:"update_indicator_alert",description:"Update an indicator alert (condition, dedup, archive, mute). Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},condition:{type:"object"},dedupMode:{type:"string",enum:["edge","continuous"]},isActive:{type:"boolean"},isArchived:{type:"boolean"},...j0},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await u(v),CZ(v.trpc,$)}}),T({name:"delete_indicator_alert",description:"Delete an indicator alert by id. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"}},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await u(v),xZ(v.trpc,$)}})];var SX=[T({name:"login",description:"Sign in to Aether Wealth. Opens your browser to authenticate; once you approve, the MCP stores a per-user token and the data tools become available.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async($,v)=>{return await v.session.login(),{status:"signed_in",message:"Signed in to Aether Wealth."}}}),T({name:"logout",description:"Sign out of Aether Wealth on this device. Clears the stored access token.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async($,v)=>{return await v.session.logout(),{status:"signed_out",message:"Signed out on this device."}}})];var K$=($,v,D,X)=>{return{id:$,displayName:`${$.slice(0,3)}/${$.slice(3)}`,kind:"forex",exchange:"FX",region:"GLOBAL",category:D,pipSize:X?.pipSize??0.0001,priceDecimals:X?.priceDecimals??5,contractSize:1e5,providers:{twelvedata:v}}},NR=[K$("AUDUSD","AUD/USD","Forex Majors"),K$("EURUSD","EUR/USD","Forex Majors"),K$("GBPUSD","GBP/USD","Forex Majors"),K$("USDCAD","USD/CAD","Forex Majors"),K$("USDCHF","USD/CHF","Forex Majors"),K$("USDJPY","USD/JPY","Forex Majors",{pipSize:0.01,priceDecimals:3}),K$("AUDCAD","AUD/CAD","Forex Minors"),K$("AUDCHF","AUD/CHF","Forex Minors"),K$("AUDJPY","AUD/JPY","Forex Minors",{pipSize:0.01,priceDecimals:3}),K$("AUDNZD","AUD/NZD","Forex Minors"),K$("EURAUD","EUR/AUD","Forex Minors"),K$("EURCAD","EUR/CAD","Forex Minors"),K$("EURCHF","EUR/CHF","Forex Minors"),K$("EURGBP","EUR/GBP","Forex Minors"),K$("EURJPY","EUR/JPY","Forex Minors",{pipSize:0.01,priceDecimals:3}),K$("EURNZD","EUR/NZD","Forex Minors"),K$("GBPAUD","GBP/AUD","Forex Minors"),K$("GBPCAD","GBP/CAD","Forex Minors"),K$("GBPCHF","GBP/CHF","Forex Minors"),K$("GBPJPY","GBP/JPY","Forex Minors",{pipSize:0.01,priceDecimals:3}),K$("GBPNZD","GBP/NZD","Forex Minors")],ZR=[{id:"XAUUSD",displayName:"Gold",kind:"metal",exchange:"OTC",region:"GLOBAL",category:"Metals",pipSize:0.01,priceDecimals:2,contractSize:100,providers:{twelvedata:"XAU/USD"}},{id:"XAGUSD",displayName:"Silver",kind:"metal",exchange:"OTC",region:"GLOBAL",category:"Metals",pipSize:0.001,priceDecimals:3,contractSize:5000,providers:{twelvedata:"XAG/USD"}}];function u$($,v,D=!1){return{id:$,displayName:`${$.slice(0,-3)}/USD`,kind:"crypto",exchange:"CRYPTO",region:"GLOBAL",category:"Crypto",pipSize:D?0.0001:0.01,priceDecimals:D?5:2,contractSize:1,providers:{twelvedata:v}}}var OR=[u$("BTCUSD","BTC/USD"),u$("ETHUSD","ETH/USD"),u$("SOLUSD","SOL/USD"),u$("BNBUSD","BNB/USD"),u$("AVAXUSD","AVAX/USD"),u$("LINKUSD","LINK/USD"),u$("LTCUSD","LTC/USD"),u$("BCHUSD","BCH/USD"),u$("ATOMUSD","ATOM/USD"),u$("TONUSD","TON/USD"),u$("DOTUSD","DOT/USD"),u$("XRPUSD","XRP/USD",!0),u$("ADAUSD","ADA/USD",!0),u$("DOGEUSD","DOGE/USD",!0),u$("TRXUSD","TRX/USD",!0),u$("POLUSD","POL/USD",!0)],AR=[{id:"NAS100",displayName:"Nasdaq 100",kind:"index",exchange:"NASDAQ",region:"US",category:"Indices",pipSize:0.01,priceDecimals:2,contractSize:20,providers:{twelvedata:"QQQ"}}],HR=[{id:"USOIL",displayName:"WTI Crude",kind:"commodity",exchange:"NYMEX",region:"US",category:"Commodities",pipSize:0.01,priceDecimals:2,contractSize:1000,providers:{twelvedata:"WTI/USD"}}];function T4($,v,D){return{id:$,displayName:D,kind:"stock",exchange:"NSE",region:"IN",category:"Indian Stocks",pipSize:0.05,priceDecimals:2,contractSize:1,providers:{twelvedata:v}}}var FR=[{id:"NIFTYBEES",displayName:"NIFTY 50 ETF",kind:"index",exchange:"BSE",region:"IN",category:"Indian Indices",pipSize:0.01,priceDecimals:2,contractSize:1,providers:{twelvedata:"NIFTYBEES:BSE"}},{id:"BANKBEES",displayName:"BANK NIFTY ETF",kind:"index",exchange:"BSE",region:"IN",category:"Indian Indices",pipSize:0.01,priceDecimals:2,contractSize:1,providers:{twelvedata:"BANKBEES:BSE"}},T4("RELIANCE","RELIANCE:NSE","Reliance Industries"),T4("TCS","TCS:NSE","Tata Consultancy Services"),T4("HDFCBANK","HDFCBANK:NSE","HDFC Bank"),T4("INFY","INFY:NSE","Infosys"),T4("ICICIBANK","ICICIBANK:NSE","ICICI Bank"),T4("BHARTIARTL","BHARTIARTL:NSE","Bharti Airtel"),T4("LT","LT:NSE","Larsen & Toubro"),T4("SBIN","SBIN:NSE","State Bank of India"),T4("AXISBANK","AXISBANK:NSE","Axis Bank"),T4("KOTAKBANK","KOTAKBANK:NSE","Kotak Mahindra Bank")],kX=Object.freeze([...NR,...ZR,...OR,...AR,...HR,...FR]);class w0{byKey;instruments;providerNames;constructor($){this.instruments=Object.freeze([...$]);let v=new Map,D=new Set;for(let X of $){if(hz(v,X.id,X,"id"),X.displayName!==X.id)hz(v,X.displayName,X,"displayName");for(let[U,G]of Object.entries(X.providers))if(D.add(U),hz(v,BO(U,G),X,"provider"),!v.has(G))v.set(G,X)}this.byKey=v,this.providerNames=D}resolve($){let v=this.byKey.get($);if(v)return v;let D=$.toUpperCase();if(D!==$){let U=this.byKey.get(D);if(U)return U}let X=$.toLowerCase();if(X!==$)return this.byKey.get(X)??null;return null}require($){let v=this.resolve($);if(!v)throw Error(`Unknown instrument: ${JSON.stringify($)}. Add it to INSTRUMENTS env var or check the key you passed in.`);return v}resolveByProvider($,v){return this.byKey.get(BO($,v))??null}list(){return this.instruments}byKind($){return this.instruments.filter((v)=>v.kind===$)}byExchange($){return this.instruments.filter((v)=>v.exchange===$)}byRegion($){return this.instruments.filter((v)=>v.region===$)}byCategory($){return this.instruments.filter((v)=>v.category===$)}groupByCategory(){let $=new Map;for(let v of this.instruments){let D=$.get(v.category);if(D)D.push(v);else $.set(v.category,[v])}return Array.from($.entries()).map(([v,D])=>({category:v,instruments:D}))}has($){return this.byKey.has($)}stats(){return{instrumentCount:this.instruments.length,providerCount:this.providerNames.size,providers:Array.from(this.providerNames).sort()}}}function BO($,v){return`${$}:${v}`}function hz($,v,D,X){if(X==="provider"){if($.has(v))throw Error(`Duplicate provider symbol ${JSON.stringify(v)} declared by multiple instruments in INSTRUMENTS`)}else if($.has(v))throw Error(`Duplicate instrument ${X} ${JSON.stringify(v)} in INSTRUMENTS (already mapped to ${$.get(v)?.id}, now also to ${D.id})`);$.set(v,D)}var wR=["forex","metal","crypto","index","commodity","stock","bond"],MR=r.object({kind:r.enum(wR),displayName:r.string().min(1).optional(),exchange:r.string().min(1).optional(),region:r.string().min(1).optional(),category:r.string().min(1).optional(),pipSize:r.number().positive().optional(),priceDecimals:r.number().int().min(0).max(12).optional(),contractSize:r.number().positive().optional(),providers:r.record(r.string().min(1),r.string().min(1))}),qp=r.record(r.string().min(1),MR).refine(($)=>Object.keys($).length>0,{message:"INSTRUMENTS must contain at least one entry"});var PR=Object.freeze({AUDUSD:{quote:"https://logo.twelvedata.com/forex/usd.png",base:"https://logo.twelvedata.com/forex/aud.png"},EURUSD:{base:"https://logo.twelvedata.com/forex/eur.png",quote:"https://logo.twelvedata.com/forex/usd.png"},GBPUSD:{quote:"https://logo.twelvedata.com/forex/usd.png",base:"https://logo.twelvedata.com/forex/gbp.png"},USDCAD:{base:"https://logo.twelvedata.com/forex/usd.png",quote:"https://logo.twelvedata.com/forex/cad.png"},USDCHF:{base:"https://logo.twelvedata.com/forex/usd.png",quote:"https://logo.twelvedata.com/forex/chf.png"},USDJPY:{base:"https://logo.twelvedata.com/forex/usd.png",quote:"https://logo.twelvedata.com/forex/jpy.png"},AUDCAD:{base:"https://logo.twelvedata.com/forex/aud.png",quote:"https://logo.twelvedata.com/forex/cad.png"},AUDCHF:{base:"https://logo.twelvedata.com/forex/aud.png",quote:"https://logo.twelvedata.com/forex/chf.png"},AUDJPY:{base:"https://logo.twelvedata.com/forex/aud.png",quote:"https://logo.twelvedata.com/forex/jpy.png"},AUDNZD:{base:"https://logo.twelvedata.com/forex/aud.png",quote:"https://logo.twelvedata.com/forex/nzd.png"},EURAUD:{base:"https://logo.twelvedata.com/forex/eur.png",quote:"https://logo.twelvedata.com/forex/aud.png"},EURCAD:{base:"https://logo.twelvedata.com/forex/eur.png",quote:"https://logo.twelvedata.com/forex/cad.png"},EURCHF:{base:"https://logo.twelvedata.com/forex/eur.png",quote:"https://logo.twelvedata.com/forex/chf.png"},EURGBP:{quote:"https://logo.twelvedata.com/forex/gbp.png",base:"https://logo.twelvedata.com/forex/eur.png"},EURJPY:{base:"https://logo.twelvedata.com/forex/eur.png",quote:"https://logo.twelvedata.com/forex/jpy.png"},EURNZD:{base:"https://logo.twelvedata.com/forex/eur.png",quote:"https://logo.twelvedata.com/forex/nzd.png"},GBPAUD:{base:"https://logo.twelvedata.com/forex/gbp.png",quote:"https://logo.twelvedata.com/forex/aud.png"},GBPCAD:{base:"https://logo.twelvedata.com/forex/gbp.png",quote:"https://logo.twelvedata.com/forex/cad.png"},GBPCHF:{quote:"https://logo.twelvedata.com/forex/chf.png",base:"https://logo.twelvedata.com/forex/gbp.png"},GBPJPY:{base:"https://logo.twelvedata.com/forex/gbp.png",quote:"https://logo.twelvedata.com/forex/jpy.png"},GBPNZD:{base:"https://logo.twelvedata.com/forex/gbp.png",quote:"https://logo.twelvedata.com/forex/nzd.png"},BTCUSD:{base:"https://logo.twelvedata.com/crypto/btc.png",quote:"https://logo.twelvedata.com/crypto/usd.png"},ETHUSD:{quote:"https://logo.twelvedata.com/crypto/usd.png",base:"https://logo.twelvedata.com/crypto/eth.png"},SOLUSD:{quote:"https://logo.twelvedata.com/crypto/usd.png",base:"https://logo.twelvedata.com/crypto/sol.png"},BNBUSD:{quote:"https://logo.twelvedata.com/crypto/usd.png",base:"https://logo.twelvedata.com/crypto/bnb.png"},AVAXUSD:{url:"https://assets.coingecko.com/coins/images/12559/large/Avalanche_Circle_RedWhite_Trans.png"},LINKUSD:{base:"https://logo.twelvedata.com/crypto/link.png",quote:"https://logo.twelvedata.com/crypto/usd.png"},LTCUSD:{base:"https://logo.twelvedata.com/crypto/ltc.png",quote:"https://logo.twelvedata.com/crypto/usd.png"},BCHUSD:{base:"https://logo.twelvedata.com/crypto/bch.png",quote:"https://logo.twelvedata.com/crypto/usd.png"},ATOMUSD:{quote:"https://logo.twelvedata.com/crypto/usd.png",base:"https://logo.twelvedata.com/crypto/atom.png"},TONUSD:{url:"https://assets.coingecko.com/coins/images/17980/large/ton_symbol.png"},DOTUSD:{quote:"https://logo.twelvedata.com/crypto/usd.png",base:"https://logo.twelvedata.com/crypto/dot.png"},XRPUSD:{base:"https://logo.twelvedata.com/crypto/xrp.png",quote:"https://logo.twelvedata.com/crypto/usd.png"},ADAUSD:{quote:"https://logo.twelvedata.com/crypto/usd.png",base:"https://logo.twelvedata.com/crypto/ada.png"},DOGEUSD:{base:"https://logo.twelvedata.com/crypto/doge.png",quote:"https://logo.twelvedata.com/crypto/usd.png"},TRXUSD:{base:"https://logo.twelvedata.com/crypto/trx.png",quote:"https://logo.twelvedata.com/crypto/usd.png"},POLUSD:{url:"https://assets.coingecko.com/coins/images/4713/large/polygon.png"},RELIANCE:{url:"https://api.twelvedata.com/logo/ril.com"},TCS:{url:"https://api.twelvedata.com/logo/tcs.com"},HDFCBANK:{url:"https://api.twelvedata.com/logo/hdfcbank.com"},INFY:{url:"https://api.twelvedata.com/logo/infosys.com"},ICICIBANK:{url:"https://api.twelvedata.com/logo/icicibank.com"},BHARTIARTL:{url:"https://api.twelvedata.com/logo/airtel.in"},LT:{url:"https://api.twelvedata.com/logo/larsentoubro.com"},SBIN:{url:"https://api.twelvedata.com/logo/sbi.co.in"},AXISBANK:{url:"https://api.twelvedata.com/logo/axisbank.com"},KOTAKBANK:{url:"https://api.twelvedata.com/logo/kotak.com"}});function mz($,v){return Number(v.toFixed($.priceDecimals))}var R$="-apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', Roboto, sans-serif",rz=11,cz=15,dz=11,pz=13,VO=12,TX=17,LO=26,KO=0.85,NO=20,ZO=8,OO=64,AO=26,x1=18,EX=16,HO=20,FO=300,tz=120,jO=1280,wO=720,MO=2,PO=!0,bO=320,qO=2560,SO=240,kO=1440,TO=1,EO=3,uX={dark:{background:"#0F0F0F",text:"#D9D9D9",mutedText:"#8A8D96",grid:"rgba(242, 242, 242, 0.06)",axisBorder:"#2B2B43",upCandle:"#10b981",downCandle:"#ef4444",markerText:"#F2F2F2",headerText:"#E8E8EA",badgeBg:"rgba(255, 255, 255, 0.08)",badgeText:"#A6AAB4",watermarkText:"#D9D9D9",tagText:"#FFFFFF",entryTag:"#363C4E"},light:{background:"#FFFFFF",text:"#191919",mutedText:"#6A6E78",grid:"rgba(0, 0, 0, 0.06)",axisBorder:"#E0E3EB",upCandle:"#10b981",downCandle:"#ef4444",markerText:"#191919",headerText:"#131722",badgeBg:"rgba(0, 0, 0, 0.06)",badgeText:"#5F6470",watermarkText:"#191919",tagText:"#FFFFFF",entryTag:"#68707F"}},oz=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function uO($,v){if(!Number.isFinite(v))return"0.00000";if(!$)return v.toFixed(5);return mz($,v).toFixed($.priceDecimals)}function RO($,v,D){let X=new Date(v*1000);if(kR($)){if(D===void 0||RR(D,v))return ER(X);return TR(X)}return uR(X)}function kR($){let v=$.trim();if(v.length===0)return!0;if(/^\d*[DWM]$/.test(v))return!1;if(/(d|w|mo|month)/i.test(v))return!1;return!0}function M0($,v,D){let U=`${$>0?"+":""}${$.toFixed(D)}`;if(v===null||!Number.isFinite(v))return U;let G=v>0?"+":"";return`${U} (${G}${v.toFixed(2)}%)`}function TR($){return`${RX($.getUTCHours())}:${RX($.getUTCMinutes())}`}function ER($){return`${RX($.getUTCDate())} ${oz[$.getUTCMonth()]}`}function uR($){return`${RX($.getUTCDate())} ${oz[$.getUTCMonth()]} '${String($.getUTCFullYear()).slice(-2)}`}function RR($,v){let D=new Date($*1000),X=new Date(v*1000);return D.getUTCFullYear()!==X.getUTCFullYear()||D.getUTCMonth()!==X.getUTCMonth()||D.getUTCDate()!==X.getUTCDate()}function RX($){return String($).padStart(2,"0")}var gO="data:image/png;base64,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";function CO($){return $.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}function Y$($){return`<line${f1($)} />`}function H$($){return`<rect${f1($)} />`}function p$($,v){return`<text${f1(v)}>${CO($)}</text>`}function xO($){return`<image${f1($)} />`}function iO($,v){let D=$.map((X)=>`${az(X.x)},${az(X.y)}`).join(" ");return`<polygon${f1({...v,points:D})} />`}function o($,v={}){if($.length===0)return"";return`<g${f1(v)}>${$}</g>`}function fO($,v,D){return[`<svg xmlns="http://www.w3.org/2000/svg" width="${$}" height="${v}" viewBox="0 0 ${$} ${v}" fill="none">`,D,"</svg>"].join("")}function i1($,v=11){return Math.max(10,Math.round($.length*v*0.58))}function f1($){let v=Object.entries($).filter(([,D])=>D!==void 0&&D!==!1).map(([D,X])=>{if(X===!0)return`${D}="true"`;if(typeof X==="number")return`${D}="${az(X)}"`;if(typeof X==="string")return`${D}="${CO(X)}"`;return""}).filter((D)=>D.length>0).join(" ");return v.length>0?` ${v}`:""}function az($){let v=Math.round($*100)/100;return Number.isInteger(v)?String(v):v.toFixed(2)}var gX=16,gR=9,CR=12,xR=8,iR=8;function nO($,v){let D=[],X=$.plotLeft,U=$.instrument?.displayName??$.pair;D.push(p$(U,{x:X,y:gX,fill:v.headerText,"font-size":cz,"font-weight":700,"letter-spacing":0.2,"font-family":R$})),X+=i1(U,cz)+gR;let G=$.timeframe,J=i1(G,dz)+iR*2,Q=gX-TX+4;D.push(H$({x:X,y:Q,width:J,height:TX,rx:4,fill:v.badgeBg})),D.push(p$(G,{x:X+J/2,y:Q+TX/2+0.5,fill:v.badgeText,"font-size":dz,"font-weight":600,"text-anchor":"middle","dominant-baseline":"middle","font-family":R$})),X+=J+CR;let I=$.visibleCandles,W=I[I.length-1].close,z=I[0].open,Y=W-z,B=z===0?null:Y/z*100,V=Y>=0?v.upCandle:v.downCandle,L=$.formatPrice(W);D.push(p$(L,{x:X,y:gX,fill:V,"font-size":pz,"font-weight":600,"font-family":R$})),X+=i1(L,pz)+xR;let N=$.instrument?.priceDecimals??5;return D.push(p$(M0(Y,B,N),{x:X,y:gX,fill:V,"font-size":VO,"font-weight":500,"font-family":R$})),o(D.join(""))}function _O($,v){if(!v)return"";let D=LO;return xO({href:gO,x:$.plotRight-D-8,y:$.plotBottom-D-8,width:D,height:D,opacity:KO})}var fR=["price","priceHigh","priceLow","price1","price2","entry","stop","target"];function lO($,v){let D=$.candles.slice(-$.bars),X=ZO,U=NO,G=Math.max(X+1,$.width-OO),J=Math.max(U+1,$.height-AO),Q=G-X,I=J-U,W=Q/Math.max(1,D.length),z=Math.min(...D.map((a)=>a.low)),Y=Math.max(...D.map((a)=>a.high)),B=Y-z,V=B>0?B*0.06:Math.max(Math.abs(Y)*0.006,0.000001),L=z-V,N=Y+V,Z=Math.max(N-L,0.000001),H=B>0?Math.max(Z,B/0.6):Z,S=hR($.shapes),R=S.length>0?Math.min(...S):Number.POSITIVE_INFINITY,C=S.length>0?Math.max(...S):Number.NEGATIVE_INFINITY,k=Number.isFinite(R)&&R<L?L-R:0,N$=Number.isFinite(C)&&C>N?C-N:0,F$=Math.max(0,H-Z),u4=k+N$,Q4=L,_$=N;if(u4<=F$)Q4-=k,_$+=N$;else if(k>0&&N$===0)Q4-=Math.min(k,F$);else if(N$>0&&k===0)_$+=Math.min(N$,F$);else if(u4>0){let a=F$/u4;Q4-=k*a,_$+=N$*a}let l1=Math.max(_$-Q4,0.000001),h1=dR(D),m1=D.length-1;function b0(a){return U+(_$-a)/l1*I}function MA(a){if(!Number.isFinite(a))return{y:J,clamped:!0,edge:"bottom"};if(a>_$)return{y:U,clamped:!0,edge:"top"};if(a<Q4)return{y:J,clamped:!0,edge:"bottom"};return{y:b0(a),clamped:!1,edge:null}}function oX(a){return X+(a+0.5)*W}function K5(a){return lR(D,m1,h1,a)}function N5(a){return oX(K5(a))}function Z5(a){return m1-a}function PA(a,O5,SA){let A5=rR(a,O5);if(A5!==void 0)return N5(A5);let kA=cR(a,O5)??SA;return oX(Z5(kA))}function bA(a=6){return nR(Q4,_$,a)}function qA(a=7){return yR(D.length,a)}return{pair:$.pair,timeframe:$.timeframe,theme:$.theme,width:$.width,height:$.height,plotLeft:X,plotTop:U,plotRight:G,plotBottom:J,plotWidth:Q,plotHeight:I,slot:W,visibleCandles:D,instrument:v,priceRange:{min:Q4,max:_$,candleMin:z,candleMax:Y},averageSpacing:h1,formatPrice(a){return uO(v,a)},priceToY:b0,projectPrice:MA,indexToX:oX,timeToIndex:K5,timeToX:N5,barsBackToIndex:Z5,resolveEndpointX:PA,nicePriceTicks:bA,niceTimeTickIndices:qA}}var yO=3;function nR($,v,D=6){let X=pR($,v,D),U=Math.ceil($/X)*X,G=Math.floor(v/X)*X,J=tR(X),Q=[];if(G>=U){let I=Math.round((G-U)/X);for(let W=0;W<=I;W+=1)Q.push(Number((U+W*X).toFixed(J+2)))}if(Q.length<yO)return _R($,v,yO+2);return Q}function _R($,v,D){if(v<=$||D<2)return[$];let X=[];for(let U=0;U<D;U+=1)X.push($+(v-$)*U/(D-1));return X}function yR($,v=7){if($<=0)return[];if($<=v)return Array.from({length:$},(U,G)=>G);let D=new Set,X=($-1)/Math.max(1,v-1);for(let U=0;U<v;U+=1)D.add(Math.round(U*X));return D.add(0),D.add($-1),Array.from(D).sort((U,G)=>U-G)}function lR($,v,D,X){if($.length===1){let J=$[0].time;return(X-J)/D}let U=$[0],G=$[v];if(X<=U.time)return(X-U.time)/D;if(X>=G.time)return v+(X-G.time)/D;return mR($,v,X)}function hR($){let v=[];for(let D of $)for(let X of fR){let U=D[X];if(typeof U==="number"&&Number.isFinite(U))v.push(U)}return v}function mR($,v,D){let X=0,U=v;while(X<=U){let z=Math.floor((X+U)/2),Y=$[z];if(Y.time===D)return z;if(Y.time<D)X=z+1;else U=z-1}let G=Math.min(v,X),J=Math.max(0,G-1),Q=$[J],W=$[G].time-Q.time;if(W<=0)return J;return J+(D-Q.time)/W}function rR($,v){if(v==="start")return $.time1??$.entryTime;return $.time2}function cR($,v){if(v==="start")return $.barsBack1;return $.barsBack2}function dR($){if($.length<2)return 1;let v=0,D=0;for(let X=1;X<$.length;X+=1){let U=$[X].time-$[X-1].time;if(U>0)v+=U,D+=1}if(D===0)return 1;return v/D}function pR($,v,D){let U=Math.max(v-$,0.000001)/Math.max(1,D-1),G=Math.floor(Math.log10(U)),J=[G-1,G,G+1],Q=[1,2,2.5,5,10],I=U,W=Number.POSITIVE_INFINITY;for(let z of J){let Y=10**z;for(let B of Q){let V=B*Y,L=Math.ceil($/V),N=Math.floor(v/V),Z=N>=L?N-L+1:1,H=Math.abs(Z-D);if(H<W)W=H,I=V}}return I}function tR($){let v=0,D=$;while(v<10&&Math.abs(Math.round(D)-D)>0.00000001)D*=10,v+=1;return v}function N6($){return uX[$]}function hO($,v){let D=N6($.theme),X=oR($.nicePriceTicks(),$.formatPrice),U=$.niceTimeTickIndices(),G=[],J=[],Q=$.visibleCandles[$.visibleCandles.length-1],I=$.priceToY(Q.close),W=Q.close>=Q.open?D.upCandle:D.downCandle,z=$.formatPrice(Q.close);for(let N of X){let Z=$.priceToY(N);G.push(Y$({x1:$.plotLeft,y1:Math.round(Z)+0.5,x2:$.plotRight,y2:Math.round(Z)+0.5,stroke:D.grid,"stroke-width":1}));let H=$.formatPrice(N);if(H!==z)J.push(p$(H,{x:$.width-6,y:Z,fill:D.text,"font-size":rz,"font-family":R$,"text-anchor":"end","dominant-baseline":"middle"}))}for(let N of U){let Z=$.visibleCandles[N];if(!Z)continue;let H=$.indexToX(N),R=(N>0?$.visibleCandles[N-1]:void 0)?.time;G.push(Y$({x1:Math.round(H)+0.5,y1:$.plotTop,x2:Math.round(H)+0.5,y2:$.plotBottom,stroke:D.grid,"stroke-width":1})),J.push(p$(RO($.timeframe,Z.time,R),{x:H,y:$.height-8,fill:D.text,"font-size":rz,"font-family":R$,"text-anchor":"middle"}))}J.push(Y$({x1:Math.round($.plotRight)+0.5,y1:$.plotTop,x2:Math.round($.plotRight)+0.5,y2:$.plotBottom,stroke:D.axisBorder,"stroke-width":1})),J.push(Y$({x1:$.plotLeft,y1:Math.round($.plotBottom)+0.5,x2:$.width,y2:Math.round($.plotBottom)+0.5,stroke:D.axisBorder,"stroke-width":1}));let Y=Y$({x1:$.plotLeft,y1:Math.round(I)+0.5,x2:$.plotRight,y2:Math.round(I)+0.5,stroke:W,"stroke-width":1,"stroke-dasharray":"4 4"}),B={y:I,label:$.formatPrice(Q.close),fill:W,height:x1},V=nO($,D),L=_O($,v);return{gridSvg:o(G.join(""),{"shape-rendering":"crispEdges"}),axesSvg:J.join(""),lastPriceSvg:Y,lastPriceTag:B,headerSvg:V,watermarkSvg:L}}function oR($,v){let D=new Set,X=[];for(let U of $){let G=v(U);if(!D.has(G))D.add(G),X.push(U)}return X}function mO($){let v=Math.max(1,Math.round($.slot*0.7)),D=[];for(let X=0;X<$.visibleCandles.length;X+=1){let U=$.visibleCandles[X];if(!U)continue;let G=U.close>=U.open?"#10b981":"#ef4444",J=$.indexToX(X),Q=Math.round(J)+0.5,I=$.priceToY(U.high),W=$.priceToY(U.low),z=$.priceToY(U.open),Y=$.priceToY(U.close),B=Math.min(z,Y),V=Math.max(z,Y),L=Math.max(1,Math.round(V-B)),N=Math.round(J-v/2),Z=Math.round(B);D.push(Y$({x1:Q,y1:Math.round(I)+0.5,x2:Q,y2:Math.round(W)+0.5,stroke:G,"stroke-width":1})),D.push(H$({x:N,y:Z,width:v,height:L,fill:G}))}return o(D.join(""),{"shape-rendering":"crispEdges"})}function rO($,v){if(v.length===0)return"";let D=N6($.theme);return aR(v,$.plotTop+2,$.plotBottom-2).map((U)=>o([H$({x:$.plotRight+1,y:Math.round(U.y-U.height/2),width:$.width-$.plotRight-1,height:U.height,fill:U.fill}),p$(U.label,{x:$.width-6,y:U.y,fill:D.tagText,"font-size":U.height>=x1?11:10,"font-family":R$,"font-weight":600,"text-anchor":"end","dominant-baseline":"middle"})].join(""),{"shape-rendering":"crispEdges"})).join("")}function aR($,v,D){let X=$.map((J)=>({...J})).sort((J,Q)=>J.y-Q.y);if(X.length===0)return X;for(let J=1;J<X.length;J+=1){let Q=X[J-1],I=X[J],W=Q.y+(Q.height+I.height)/2;if(I.y<W)I.y=W}let U=X[X.length-1];if(U.y>D){U.y=D;for(let J=X.length-2;J>=0;J-=1){let Q=X[J+1],I=X[J],W=Q.y-(Q.height+I.height)/2;if(I.y>W)I.y=W}}let G=X[0];if(G.y<v)G.y=v;return X}function ez($){let v=$2($.candles);if(v.length===0)throw Error("Cannot render chart: candles is empty");return{pair:$.pair,timeframe:$.timeframe,candles:v,shapes:$.shapes??[],theme:$.theme??"dark",width:cO($.width,jO,bO,qO),height:cO($.height,wO,SO,kO),bars:eR($.bars??tz),scale:sR($.scale),watermark:$.watermark??PO,...$.fontFiles?{fontFiles:$.fontFiles}:{}}}function eR($){if(!Number.isFinite($))return tz;return sz(Math.round($),HO,FO)}function sR($){if($===void 0||!Number.isFinite($)||$<=0)return MO;return sz($,TO,EO)}function cO($,v,D,X){if($===void 0||!Number.isFinite($)||$<=0)return v;return sz(Math.round($),D,X)}function sz($,v,D){return Math.min(D,Math.max(v,$))}function $2($){return $.filter((v)=>Number.isFinite(v.time)&&Number.isFinite(v.open)&&Number.isFinite(v.high)&&Number.isFinite(v.low)&&Number.isFinite(v.close)).sort((v,D)=>v.time-D.time)}import{createRequire as v2}from"node:module";var U2=v2(import.meta.url);function dO($,v,D,X){let{Resvg:U}=D2();return new U($,{fitTo:{mode:"width",value:Math.round(v*D)},font:{loadSystemFonts:!0,defaultFontFamily:"Inter",...X?{fontFiles:X}:{}},background:"rgba(0,0,0,0)"}).render().asPng()}function D2(){try{return U2("@resvg/resvg-js")}catch($){let v=$ instanceof Error?$.message:String($);throw Error(`chart-render: @resvg/resvg-js could not be loaded for PNG rasterization (${v})`)}}var X2={horizontal_line:"horizontal_line",line:"horizontal_line",hline:"horizontal_line",horizontal:"horizontal_line",horz_line:"horizontal_line",horizontal_ray:"horizontal_ray",hray:"horizontal_ray",horz_ray:"horizontal_ray",horizontalray:"horizontal_ray",h_ray:"horizontal_ray",vertical_line:"vertical_line",vertical:"vertical_line",vline:"vertical_line",vert_line:"vertical_line",vertline:"vertical_line",verticalline:"vertical_line",cross_line:"cross_line",crossline:"cross_line",cross:"cross_line",zone:"zone",horizontal_range:"zone",range:"zone",supply_demand_zone:"zone",rectangle:"rectangle",rect:"rectangle",box:"rectangle",trendline:"trendline",trend:"trendline",trend_line:"trendline",ray:"ray",trend_ray:"ray",right_ray:"right_ray",ray_right:"right_ray",rightray:"right_ray","right-ray":"right_ray",left_ray:"left_ray",ray_left:"left_ray",leftray:"left_ray","left-ray":"left_ray",extended_line:"extended_line",extendedline:"extended_line",extended:"extended_line",extend_line:"extended_line",info_line:"info_line",infoline:"info_line",info:"info_line",trend_angle:"trend_angle",trendangle:"trend_angle",angle:"trend_angle",position:"position",trade:"position",long:"position",short:"position",long_position:"position",short_position:"position"},G2={horizontal_line:{required:[{field:"price",message:"price is required for horizontal_line"}],describe:($)=>`Drew horizontal line at ${$.price}${$.label?` (${$.label})`:""}`},horizontal_ray:{required:[{field:"price",message:"price is required for horizontal_ray"}],describe:($)=>`Drew horizontal ray at ${$.price}${$.label?` (${$.label})`:""}`},vertical_line:{required:[],describe:($)=>{let v=$.time1??$.time2;return`Drew vertical line${v?` at ${v}`:""}${$.label?` (${$.label})`:""}`}},cross_line:{required:[{field:"price",message:"price is required for cross_line"}],describe:($)=>`Drew cross line at ${$.price}${$.label?` (${$.label})`:""}`},zone:{required:[{field:"priceHigh",message:"priceHigh is required for zone"},{field:"priceLow",message:"priceLow is required for zone"}],describe:($)=>`Drew zone from ${$.priceLow} to ${$.priceHigh}${$.label?` (${$.label})`:""}`},rectangle:{required:[{field:"priceHigh",message:"priceHigh is required for rectangle"},{field:"priceLow",message:"priceLow is required for rectangle"}],describe:($)=>`Drew rectangle from ${$.priceLow} to ${$.priceHigh}${$.label?` (${$.label})`:""}`},trendline:{required:[{field:"price1",message:"price1 is required for trendline"},{field:"price2",message:"price2 is required for trendline"}],describe:($)=>`Drew trendline from ${$.price1} to ${$.price2}${$.label?` (${$.label})`:""}`},ray:{required:[{field:"price1",message:"price1 is required for ray"},{field:"price2",message:"price2 is required for ray"}],describe:($)=>`Drew ray from ${$.price1} to ${$.price2}${$.label?` (${$.label})`:""}`},right_ray:{required:[{field:"price1",message:"price1 is required for right_ray"},{field:"price2",message:"price2 is required for right_ray"}],describe:($)=>`Drew right ray from ${$.price1} to ${$.price2}${$.label?` (${$.label})`:""}`},left_ray:{required:[{field:"price1",message:"price1 is required for left_ray"},{field:"price2",message:"price2 is required for left_ray"}],describe:($)=>`Drew left ray from ${$.price1} to ${$.price2}${$.label?` (${$.label})`:""}`},extended_line:{required:[{field:"price1",message:"price1 is required for extended_line"},{field:"price2",message:"price2 is required for extended_line"}],describe:($)=>`Drew extended line from ${$.price1} to ${$.price2}${$.label?` (${$.label})`:""}`},info_line:{required:[{field:"price1",message:"price1 is required for info_line"},{field:"price2",message:"price2 is required for info_line"}],describe:($)=>`Drew info line from ${$.price1} to ${$.price2}${$.label?` (${$.label})`:""}`},trend_angle:{required:[{field:"price1",message:"price1 is required for trend_angle"},{field:"price2",message:"price2 is required for trend_angle"}],describe:($)=>`Drew trend angle from ${$.price1} to ${$.price2}${$.label?` (${$.label})`:""}`},position:{required:[{field:"direction",message:'direction ("long" or "short") is required for position'},{field:"entry",message:"entry is required for position"},{field:"stop",message:"stop is required for position"},{field:"target",message:"target is required for position"}],describe:($)=>`Drew ${$.direction} position — entry ${$.entry}, stop ${$.stop}, target ${$.target}${$.label?` (${$.label})`:""}`}};var J2=["horizontal_line","horizontal_ray","vertical_line","cross_line","zone","rectangle","trendline","trend_line","ray","right_ray","left_ray","extended_line","info_line","trend_angle","position"];function P0($){if(typeof $!=="string")return null;let v=$.trim().toLowerCase();return X2[v]??null}function oO($){return`Unknown shape type: "${String($)}". Supported types: ${J2.join(", ")}`}function $5($){if(typeof $==="number"&&Number.isFinite($))return $;if(typeof $==="string"){let v=$.trim();if(v.length===0)return;let D=Number(v);if(Number.isFinite(D))return D}return}function Q2($){if(typeof $!=="string")return;let v=$.trim().toLowerCase();if(v==="long"||v==="buy")return"long";if(v==="short"||v==="sell")return"short";return}function t$($,v){for(let D of v){let X=$5($[D]);if(X!==void 0)return X}return}function E4($,v,D){let X=$[v];if(!X||typeof X!=="object"||Array.isArray(X))return;return t$(X,D)}function I2($){if(typeof $.type!=="string")return null;let v=$.type.trim().toLowerCase();return v.length>0?v:null}function Z4($,v,D){if($[v]!==void 0||D===void 0)return;$[v]=D}function v5($,v,D){Z4($,v,D===void 0?void 0:Math.trunc(D))}function W2($,v){if($.direction)return;if(v==="long"||v==="short"){$.direction=v;return}if(v==="long_position"||v==="short_position"){$.direction=v==="long_position"?"long":"short";return}$.direction=Q2($.side)}function z2($){return t$($,["level","y","value","priceLevel","linePrice"])??E4($,"point1",["price","y","value"])??E4($,"from",["price","y","value"])}function pO($,v){if(v==="start")return t$($,["startPrice","fromPrice","priceA","p1"])??E4($,"point1",["price","y","value"])??E4($,"from",["price","y","value"]);return t$($,["endPrice","toPrice","priceB","p2"])??E4($,"point2",["price","y","value"])??E4($,"to",["price","y","value"])}function tO($,v){if(v==="start")return t$($,["time","startTime","fromTime","timestamp","t1"])??E4($,"point1",["time","t","timestamp"])??E4($,"from",["time","t","timestamp"]);return t$($,["endTime","toTime","t2"])??E4($,"point2",["time","t","timestamp"])??E4($,"to",["time","t","timestamp"])}function Y2($){Z4($,"price",z2($)),Z4($,"priceHigh",t$($,["high","upper","top","max","priceTop","priceUpper"])),Z4($,"priceLow",t$($,["low","lower","bottom","min","priceBottom","priceLower"])),Z4($,"price1",pO($,"start")),Z4($,"price2",pO($,"end"))}function B2($){v5($,"time1",tO($,"start")),v5($,"time2",tO($,"end")),Z4($,"barsBack1",t$($,["barsBack","barBack","lookback","bars"])),Z4($,"barsBack2",t$($,["barsBackEnd","barBackEnd","lookbackEnd"]))}function V2($){Z4($,"entry",t$($,["entryPrice","open","openPrice"])),Z4($,"stop",t$($,["stopLoss","sl","stopPrice"])),Z4($,"target",t$($,["takeProfit","tp","targetPrice","tpPrice"])),v5($,"entryTime",t$($,["entryTimestamp"]))}function L2($){let v=$5($.priceHigh),D=$5($.priceLow);if(v!==void 0&&D!==void 0&&v<D)$.priceHigh=D,$.priceLow=v}function aO($){if(typeof $!=="object"||$===null||Array.isArray($))return $;let v={...$},D=I2(v),X=P0(D);if(X)v.type=X;return W2(v,D),Y2(v),B2(v),V2(v),L2(v),v}function eO($){return G2[$].required}var K2=r.object({type:r.string().describe('Shape type: "horizontal_line", "horizontal_ray", "vertical_line", "cross_line", "zone", "rectangle", "trendline", "ray", "right_ray", "left_ray", "extended_line", "info_line", "trend_angle", or "position"'),price:r.coerce.number().optional().describe("Price level (required for horizontal_line, horizontal_ray, cross_line)"),priceHigh:r.coerce.number().optional().describe("Upper price boundary (required for zone/rectangle)"),priceLow:r.coerce.number().optional().describe("Lower price boundary (required for zone/rectangle)"),price1:r.coerce.number().optional().describe("First point price (required for trendline/ray/right_ray/left_ray/extended_line/info_line/trend_angle)"),price2:r.coerce.number().optional().describe("Second point price (required for trendline/ray/right_ray/left_ray/extended_line/info_line/trend_angle)"),time1:r.number().int().optional().describe("Absolute time (epoch seconds) of the first endpoint for trendline/rays or anchor for vertical_line. PREFERRED over barsBack1."),time2:r.number().int().optional().describe("Absolute time (epoch seconds) of the second endpoint (trendline/rays) or right edge of a zone. PREFERRED over barsBack2."),barsBack1:r.number().optional().describe("FALLBACK only — bars back from the current bar for first endpoint/anchor (trendline, rays, vertical_line). Use time1 when possible."),barsBack2:r.number().optional().describe("FALLBACK only — bars back from the current bar for second endpoint / zone right edge. Use time2 when possible."),direction:r.enum(["long","short"]).optional().describe('Position direction (required for position): "long" or "short"'),entry:r.coerce.number().optional().describe("Entry price (required for position)"),stop:r.coerce.number().optional().describe("Stop-loss price (required for position)"),target:r.coerce.number().optional().describe("Take-profit price (required for position)"),entryTime:r.number().int().optional().describe("Absolute time (epoch seconds) for the position entry anchor. Defaults to the current bar."),label:r.string().optional().describe('Label text, e.g. "Support", "Resistance", "Demand Zone", "Long EURCHF"'),color:r.string().optional().describe('Color hex, e.g. "#22c55e" green, "#ef4444" red, "#3b82f6" blue')}).superRefine(($,v)=>{let D=P0($.type);if(!D){v.addIssue({code:"custom",message:oO($.type),path:["type"]});return}for(let X of eO(D))if($[X.field]===void 0)v.addIssue({code:"custom",message:X.message,path:[X.field]})}),sO=r.preprocess(aO,K2),mt=r.object({shapes:r.array(sO).min(1)});function $A($){let v=[],D=[];for(let[X,U]of $.entries()){let G=sO.safeParse(U);if(G.success)v.push(G.data);else D.push({index:X,reason:G.error.issues[0]?.message??"invalid shape"})}return{valid:v,invalid:D}}function $4($,v,D){let X={type:$.type,ok:!0,...D?{reason:D}:{},...$.label?{label:$.label}:{}};return{underlaySvg:v.underlaySvg??"",lineSvg:v.lineSvg??"",positionSvg:v.positionSvg??"",chromeSvg:v.chromeSvg??"",gutterTags:v.gutterTags??[],report:X}}function O$($,v){let D={type:$.type,ok:!1,reason:v,...$.label?{label:$.label}:{}};return{underlaySvg:"",lineSvg:"",positionSvg:"",chromeSvg:"",gutterTags:[],report:D}}function k$($){return typeof $==="number"&&Number.isFinite($)?$:void 0}function o$($,v){return $.color&&$.color.trim().length>0?$.color:v}function W$($,v,D,X){let U=$.projectPrice(D);if(!U.clamped||U.edge===null)return"";let G=N6($.theme),J=z$(v,$.plotLeft+10,$.plotRight-10),Q=U.edge==="top"?$.plotTop+4:$.plotBottom-4,I=U.edge==="top"?[{x:J,y:Q},{x:J-5,y:Q+7},{x:J+5,y:Q+7}]:[{x:J,y:Q},{x:J-5,y:Q-7},{x:J+5,y:Q-7}],W=U.edge==="top"?Q+16:Q-10;return o([iO(I,{fill:X}),p$($.formatPrice(D),{x:J,y:W,fill:G.markerText,"font-size":10,"font-family":R$,"text-anchor":"middle"})].join(""))}function U5($,v,D,X,U){let G=i1(D,10)+10;return o([H$({x:$,y:v-10,width:G,height:16,fill:X,"fill-opacity":0.85}),p$(D,{x:$+5,y:v+1,fill:U,"font-size":10,"font-family":R$})].join(""),{"shape-rendering":"crispEdges"})}function O4($,v,D,X,U="start"){return p$(D,{x:$,y:v,fill:X,"font-size":10,"font-family":R$,"text-anchor":U})}function z$($,v,D){return Math.min(D,Math.max(v,$))}var UA="price out of visible range (clamped)";function D5($,v){if(v.type==="zone")return N2($,v);if(v.type==="rectangle")return Z2($,v);return O$(v,`Unsupported area shape: ${v.type}`)}function N2($,v){let D=DA($,v,"zone");if(D.kind==="error")return D.fragments;let X=o$(v,"#3b82f6"),U=z$(D.top+12,$.plotTop+12,$.plotBottom-6),G=(D.left+D.right)/2;return $4(v,{underlaySvg:o(H$({x:D.left,y:D.top,width:D.right-D.left,height:D.bottom-D.top,fill:X,"fill-opacity":0.12}),{"shape-rendering":"crispEdges"}),lineSvg:o([Y$({x1:D.left,y1:Math.round(D.top)+0.5,x2:D.right,y2:Math.round(D.top)+0.5,stroke:X,"stroke-width":1}),Y$({x1:D.left,y1:Math.round(D.bottom)+0.5,x2:D.right,y2:Math.round(D.bottom)+0.5,stroke:X,"stroke-width":1}),v.label?O4(D.left+4,U,v.label,X):"",W$($,G,D.highPrice,X),W$($,G,D.lowPrice,X)].join(""),{"shape-rendering":"crispEdges"})},D.clamped?UA:void 0)}function Z2($,v){let D=DA($,v,"rectangle");if(D.kind==="error")return D.fragments;let X=o$(v,"#f59e0b"),U=z$(D.top+12,$.plotTop+12,$.plotBottom-6),G=(D.left+D.right)/2;return $4(v,{underlaySvg:o(H$({x:D.left,y:D.top,width:D.right-D.left,height:D.bottom-D.top,fill:X,"fill-opacity":0.12}),{"shape-rendering":"crispEdges"}),lineSvg:o([H$({x:D.left,y:D.top,width:D.right-D.left,height:D.bottom-D.top,fill:"none",stroke:X,"stroke-width":1}),v.label?O4(D.left+4,U,v.label,X):"",W$($,G,D.highPrice,X),W$($,G,D.lowPrice,X)].join(""),{"shape-rendering":"crispEdges"})},D.clamped?UA:void 0)}function DA($,v,D){let X=k$(v.priceHigh),U=k$(v.priceLow);if(X===void 0)return{kind:"error",fragments:O$(v,`priceHigh is required for ${D}`)};if(U===void 0)return{kind:"error",fragments:O$(v,`priceLow is required for ${D}`)};let G=$.projectPrice(X),J=$.projectPrice(U),Q=D==="zone"&&!vA(v)?$.plotLeft:z$($.resolveEndpointX(v,"start",24),$.plotLeft,$.plotRight),I=D==="zone"&&!vA(v)?$.plotRight:z$($.resolveEndpointX(v,"end",4),$.plotLeft,$.plotRight),W=Math.min(G.y,J.y),z=Math.max(G.y,J.y);return{kind:"ok",left:Math.min(Q,I),right:Math.max(Q,I),top:W,bottom:z,highPrice:X,lowPrice:U,clamped:G.clamped||J.clamped}}function vA($){return $.time1!==void 0||$.time2!==void 0||$.barsBack1!==void 0||$.barsBack2!==void 0}function CX($,v,D){if(Math.abs(D.x-v.x)<0.000001)return v.y;let X=(D.y-v.y)/(D.x-v.x);return v.y+($-v.x)*X}function XA($,v,D){if(Math.abs(v.x-$.x)<0.000001)return{start:{x:$.x,y:$.y},end:{x:$.x,y:v.y}};return{start:{x:$.x,y:$.y},end:{x:D,y:CX(D,$,v)}}}function GA($,v,D){if(Math.abs(v.x-$.x)<0.000001)return{start:{x:$.x,y:$.y},end:{x:$.x,y:v.y}};return{start:{x:$.x,y:$.y},end:{x:D,y:CX(D,$,v)}}}function JA($,v,D,X,U,G){if(Math.abs(v.x-$.x)<0.000001)return{start:{x:$.x,y:U},end:{x:$.x,y:G}};return{start:{x:D,y:CX(D,$,v)},end:{x:X,y:CX(X,$,v)}}}function X5($,v){return{x:($.x+v.x)/2,y:($.y+v.y)/2}}var n1="price out of visible range (clamped)";function J4($,v){switch(v.type){case"horizontal_line":return O2($,v);case"horizontal_ray":return A2($,v);case"vertical_line":return H2($,v);case"cross_line":return F2($,v);case"trendline":return j2($,v);case"ray":case"right_ray":return w2($,v);case"left_ray":return M2($,v);case"extended_line":return P2($,v);case"info_line":return b2($,v);case"trend_angle":return q2($,v);default:return O$(v,`Unsupported line shape: ${v.type}`)}}function O2($,v){let D=k$(v.price);if(D===void 0)return O$(v,"price is required for horizontal_line");let X=o$(v,"#3b82f6"),U=$.projectPrice(D),G=[Y$({x1:$.plotLeft,y1:Math.round(U.y)+0.5,x2:$.plotRight,y2:Math.round(U.y)+0.5,stroke:X,"stroke-width":1}),v.label?O4($.plotLeft+4,z$(U.y-4,$.plotTop+10,$.plotBottom-4),v.label,X):"",W$($,$.plotRight-12,D,X)].join("");return $4(v,{lineSvg:o(G,{"shape-rendering":"crispEdges"}),gutterTags:[{y:U.y,label:$.formatPrice(D),fill:X,height:x1}]},U.clamped?n1:void 0)}function A2($,v){let D=k$(v.price);if(D===void 0)return O$(v,"price is required for horizontal_ray");let X=o$(v,"#3b82f6"),U=$.projectPrice(D),G=$.resolveEndpointX(v,"start",0),J=z$(G+4,$.plotLeft+4,$.plotRight-60);return $4(v,{lineSvg:o([Y$({x1:z$(G,$.plotLeft,$.plotRight),y1:Math.round(U.y)+0.5,x2:$.plotRight,y2:Math.round(U.y)+0.5,stroke:X,"stroke-width":1}),v.label?O4(J,z$(U.y-4,$.plotTop+10,$.plotBottom-4),v.label,X):"",W$($,G,D,X)].join(""),{"shape-rendering":"crispEdges"})},U.clamped?n1:void 0)}function H2($,v){let D=o$(v,"#f59e0b"),X=$.resolveEndpointX(v,"start",0),U=z$(X,$.plotLeft,$.plotRight);return $4(v,{lineSvg:o([Y$({x1:Math.round(U)+0.5,y1:$.plotTop,x2:Math.round(U)+0.5,y2:$.plotBottom,stroke:D,"stroke-width":1,"stroke-dasharray":"4 4"}),v.label?O4(U+4,$.plotTop+12,v.label,D):""].join(""),{"shape-rendering":"crispEdges"})})}function F2($,v){let D=k$(v.price);if(D===void 0)return O$(v,"price is required for cross_line");let X=o$(v,"#38bdf8"),U=$.projectPrice(D),G=z$($.resolveEndpointX(v,"start",0),$.plotLeft,$.plotRight);return $4(v,{lineSvg:o([Y$({x1:$.plotLeft,y1:Math.round(U.y)+0.5,x2:$.plotRight,y2:Math.round(U.y)+0.5,stroke:X,"stroke-width":1,"stroke-dasharray":"4 4"}),Y$({x1:Math.round(G)+0.5,y1:$.plotTop,x2:Math.round(G)+0.5,y2:$.plotBottom,stroke:X,"stroke-width":1,"stroke-dasharray":"4 4"}),v.label?O4(G+4,z$(U.y-4,$.plotTop+10,$.plotBottom-4),v.label,X):"",W$($,G,D,X)].join(""),{"shape-rendering":"crispEdges"})},U.clamped?n1:void 0)}function j2($,v){let D=_1($,v,"trendline");if(D.kind==="error")return D.fragments;return S2($,v,D.first,D.second,"#f59e0b","4 4")}function w2($,v){let D=_1($,v,v.type);if(D.kind==="error")return D.fragments;let X=o$(v,"#f59e0b"),U=XA(D.first,D.second,$.plotRight);return xX($,v,U.start,U.end,X,"4 4",[W$($,D.first.x,D.price1,X),W$($,D.second.x,D.price2,X)])}function M2($,v){let D=_1($,v,"left_ray");if(D.kind==="error")return D.fragments;let X=o$(v,"#f59e0b"),U=GA(D.first,D.second,$.plotLeft);return xX($,v,U.start,U.end,X,"4 4",[W$($,D.first.x,D.price1,X),W$($,D.second.x,D.price2,X)])}function P2($,v){let D=_1($,v,"extended_line");if(D.kind==="error")return D.fragments;let X=o$(v,"#f59e0b"),U=JA(D.first,D.second,$.plotLeft,$.plotRight,$.plotTop,$.plotBottom);return xX($,v,U.start,U.end,X,"4 4",[W$($,D.first.x,D.price1,X),W$($,D.second.x,D.price2,X)])}function b2($,v){let D=_1($,v,"info_line");if(D.kind==="error")return D.fragments;let X=o$(v,"#22c55e"),U=D.price2-D.price1,G=D.price1===0?null:U/D.price1*100,J=$.instrument?.priceDecimals??5,Q=v.label?`${v.label} · ${M0(U,G,J)}`:M0(U,G,J),I=X5(D.first,D.second);return $4(v,{lineSvg:o([Y$({x1:D.first.x,y1:D.first.y,x2:D.second.x,y2:D.second.y,stroke:X,"stroke-width":1}),U5(z$(I.x-30,$.plotLeft+2,$.plotRight-120),z$(I.y-6,$.plotTop+12,$.plotBottom-12),Q,X,"#FFFFFF"),W$($,D.first.x,D.price1,X),W$($,D.second.x,D.price2,X)].join(""),{"shape-rendering":"crispEdges"})},D.clamped?n1:void 0)}function q2($,v){let D=_1($,v,"trend_angle");if(D.kind==="error")return D.fragments;let X=o$(v,"#a855f7"),U=Math.atan2(D.first.y-D.second.y,D.second.x-D.first.x)*180/Math.PI,G=v.label?`${v.label} · ${U.toFixed(1)}°`:`${U.toFixed(1)}°`,J=X5(D.first,D.second);return $4(v,{lineSvg:o([Y$({x1:D.first.x,y1:D.first.y,x2:D.second.x,y2:D.second.y,stroke:X,"stroke-width":1}),U5(z$(J.x-26,$.plotLeft+2,$.plotRight-100),z$(J.y-6,$.plotTop+12,$.plotBottom-12),G,X,"#FFFFFF"),W$($,D.first.x,D.price1,X),W$($,D.second.x,D.price2,X)].join(""),{"shape-rendering":"crispEdges"})},D.clamped?n1:void 0)}function S2($,v,D,X,U,G){let J=o$(v,U);return xX($,v,D,X,J,G,[W$($,D.x,k$(v.price1)??0,J),W$($,X.x,k$(v.price2)??0,J)])}function xX($,v,D,X,U,G,J){let Q=z$(X.x+4,$.plotLeft+4,$.plotRight-70),I=z$(X.y-4,$.plotTop+12,$.plotBottom-4),W=k$(v.price1),z=k$(v.price2),Y=W!==void 0&&$.projectPrice(W).clamped||z!==void 0&&$.projectPrice(z).clamped;return $4(v,{lineSvg:o([Y$({x1:D.x,y1:D.y,x2:X.x,y2:X.y,stroke:U,"stroke-width":1,...G?{"stroke-dasharray":G}:{}}),v.label?O4(Q,I,v.label,U):"",...J].join(""),{"shape-rendering":"crispEdges"})},Y?n1:void 0)}function _1($,v,D){let X=k$(v.price1),U=k$(v.price2);if(X===void 0)return{kind:"error",fragments:O$(v,`price1 is required for ${D}`)};if(U===void 0)return{kind:"error",fragments:O$(v,`price2 is required for ${D}`)};let G=$.projectPrice(X),J=$.projectPrice(U),Q={x:z$($.resolveEndpointX(v,"start",50),$.plotLeft,$.plotRight),y:G.y},I={x:z$($.resolveEndpointX(v,"end",0),$.plotLeft,$.plotRight),y:J.y};return{kind:"ok",first:Q,second:I,price1:X,price2:U,clamped:G.clamped||J.clamped}}var k2="price out of visible range (clamped)";function QA($,v){if(v.direction!=="long"&&v.direction!=="short")return O$(v,'direction ("long" or "short") is required for position');let D=k$(v.entry),X=k$(v.stop),U=k$(v.target);if(D===void 0)return O$(v,"entry is required for position");if(X===void 0)return O$(v,"stop is required for position");if(U===void 0)return O$(v,"target is required for position");let G=N6($.theme),J=z$($.resolveEndpointX(v,"start",0),$.plotLeft,$.plotRight),Q=$.projectPrice(D),I=$.projectPrice(X),W=$.projectPrice(U),z=Math.min(Q.y,W.y),Y=Math.max(Q.y,W.y),B=Math.min(Q.y,I.y),V=Math.max(Q.y,I.y),L=z$(Math.min(z,B)+12,$.plotTop+12,$.plotBottom-8),N=Q.clamped||I.clamped||W.clamped;return $4(v,{positionSvg:o([H$({x:J,y:z,width:$.plotRight-J,height:Y-z,fill:"#10b981","fill-opacity":0.12}),H$({x:J,y:B,width:$.plotRight-J,height:V-B,fill:"#ef4444","fill-opacity":0.12}),Y$({x1:J,y1:Math.round(Q.y)+0.5,x2:$.plotRight,y2:Math.round(Q.y)+0.5,stroke:G.entryTag,"stroke-width":1}),Y$({x1:J,y1:Math.round(I.y)+0.5,x2:$.plotRight,y2:Math.round(I.y)+0.5,stroke:"#ef4444","stroke-width":1}),Y$({x1:J,y1:Math.round(W.y)+0.5,x2:$.plotRight,y2:Math.round(W.y)+0.5,stroke:"#10b981","stroke-width":1}),v.label?O4(J+4,L,v.label,G.text):"",W$($,J,D,G.entryTag),W$($,J,X,"#ef4444"),W$($,J,U,"#10b981")].join(""),{"shape-rendering":"crispEdges"}),gutterTags:[{y:Q.y,label:`Entry ${$.formatPrice(D)}`,fill:G.entryTag,height:EX},{y:I.y,label:`SL ${$.formatPrice(X)}`,fill:"#ef4444",height:EX},{y:W.y,label:`TP ${$.formatPrice(U)}`,fill:"#10b981",height:EX}]},N?k2:void 0)}var T2={horizontal_line:J4,horizontal_ray:J4,vertical_line:J4,cross_line:J4,zone:D5,rectangle:D5,trendline:J4,ray:J4,right_ray:J4,left_ray:J4,extended_line:J4,info_line:J4,trend_angle:J4,position:QA};function IA($,v){let D=[],X=[],U=[],G=[],J=[],Q=[],I=0,W=0;for(let z of v){let Y=E2($,z);if(D.push(Y.underlaySvg),X.push(Y.lineSvg),U.push(Y.positionSvg),G.push(Y.chromeSvg),J.push(...Y.gutterTags),Q.push(Y.report),Y.report.ok)I+=1;else W+=1}return{underlaySvg:D.join(""),lineSvg:X.join(""),positionSvg:U.join(""),chromeSvg:G.join(""),gutterTags:J,reports:Q,drawn:I,skipped:W}}function E2($,v){let D=P0(v.type);if(!D)return O$(v,`Unknown shape type: ${String(v.type)}`);let X=T2[D];if(!X)return O$(v,`Unsupported shape type: ${D}`);let U=D===v.type?v:{...v,type:D};return X($,U)}var G5;function WA($){let v=ez($),D=u2(v.pair),X=lO(v,D),U=uX[v.theme],G=IA(X,v.shapes),J=hO(X,v.watermark),Q=`plot-clip-${C2(X)}`,I=`<defs><clipPath id="${Q}">${H$({x:X.plotLeft,y:X.plotTop,width:X.plotWidth,height:X.plotHeight})}</clipPath></defs>`,W={"clip-path":`url(#${Q})`},z=o(J.gridSvg,W),Y=o(G.underlaySvg,W),B=o(mO(X),W),V=o(G.lineSvg,W),L=o(G.positionSvg,W),N=rO(X,[...G.gutterTags,J.lastPriceTag]);return{svg:fO(X.width,X.height,[H$({x:0,y:0,width:X.width,height:X.height,fill:U.background}),I,z,Y,B,V,L,J.axesSvg,G.chromeSvg,J.lastPriceSvg,N,J.headerSvg,J.watermarkSvg,g2()].join("")),width:X.width,height:X.height,drawn:G.drawn,skipped:G.skipped,shapes:G.reports,priceRange:{min:X.priceRange.min,max:X.priceRange.max}}}function J5($){let v=WA($),D=ez($);return{...v,png:dO(v.svg,v.width,D.scale,D.fontFiles)}}function u2($){return R2().resolve($)}function R2(){if(G5===void 0)G5=new w0([...kX]);return G5}function g2(){return`<style>text{font-family:${R$};white-space:pre}</style>`}function C2($){let v=$.visibleCandles,D=v[0]?.time??0,X=v[v.length-1]?.time??0,U=`${$.pair}|${$.timeframe}|${$.width}x${$.height}|${v.length}|${D}|${X}`,G=2166136261;for(let J=0;J<U.length;J+=1)G^=U.charCodeAt(J),G=Math.imul(G,16777619);return(G>>>0).toString(36)}var zA=120,Q5=20,I5=200;function x2($,v,D){return Math.max(v,Math.min(D,$))}var i2="Render an annotated candlestick chart image (PNG) for a pair + timeframe. Fetches recent candles and draws optional shapes (support/resistance lines, zones, trendlines, a long/short position) using the same vocabulary as draw_chart_shape. Returns the chart as an image plus a text summary. PREFER absolute time anchors (time1/time2/entryTime, epoch seconds from get_candles) over barsBack*.",f2="Optional annotations. Each item is {type, ...}: horizontal_line/horizontal_ray/cross_line need `price`; zone/rectangle need `priceHigh`+`priceLow`; trendline/ray/right_ray/left_ray/extended_line/info_line/trend_angle need `price1`+`price2` (prefer `time1`+`time2` epoch seconds); position needs `direction` (long/short)+`entry`+`stop`+`target`. Optional `label` and `color` (hex).",iX=[T({name:"render_chart",description:i2,inputSchema:{type:"object",properties:{pair:{type:"string",description:"Canonical instrument id, e.g. EURUSD (case-insensitive)"},timeframe:{type:"string",description:"e.g. 1m, 5m, 15m, 30m, 1h, 4h, 1d (or an integer multiple)"},shapes:{type:"array",description:f2,items:{type:"object"}},bars:{type:"integer",minimum:Q5,maximum:I5,description:`Most-recent candles to show (${Q5}-${I5}, default ${zA})`},theme:{type:"string",enum:["dark","light"],description:"Color theme (default dark)"},width:{type:"integer",minimum:320,maximum:2560,description:"Image width in px (320-2560, default 1280)"},height:{type:"integer",minimum:240,maximum:1440,description:"Image height in px (240-1440, default 720)"}},required:["pair","timeframe"],additionalProperties:!1},handler:async($,v)=>{await u(v);let D=x2($.bars??zA,Q5,I5),{candles:X}=await PX(v.trpc,{pair:$.pair,timeframe:$.timeframe,limit:D});if(X.length===0)throw Error(`No candles available for ${$.pair} ${$.timeframe}. Check the pair/timeframe with get_market_config.`);let{valid:U,invalid:G}=$A($.shapes??[]),J=J5({pair:$.pair,timeframe:$.timeframe,candles:X,shapes:U,bars:D,...$.theme?{theme:$.theme}:{},...$.width?{width:$.width}:{},...$.height?{height:$.height}:{}}),Q=J.shapes.filter((Y)=>!Y.ok),I=[...G.map((Y)=>`shape ${Y.index}: ${Y.reason}`),...Q.map((Y)=>`${Y.type}: ${Y.reason??"undrawable"}`)],W=I.length>0?` (${I.length} skipped)
|
|
107
107
|
Skipped: ${I.join("; ")}`:"",z=`Rendered ${$.pair} ${$.timeframe} — ${X.length} candles, drew ${J.drawn} shape${J.drawn===1?"":"s"}. Price range ${J.priceRange.min}–${J.priceRange.max}.${W}`;return{content:[{type:"image",data:Buffer.from(J.png).toString("base64"),mimeType:"image/png"},{type:"text",text:z}]}}})];async function fX($){try{return{ok:!0,value:await $}}catch(v){return{ok:!1,error:v instanceof Error?v.message:String(v)}}}function n2($){return/unauthor|forbidden|401|403|sign[ -]?in|token|credential/i.test($)}var _2="The Aether Wealth backend is unreachable right now. Try again shortly.",y2=xz.flatMap(($)=>$.dashboardOnly.map((v)=>`${$.name}: ${v}`)),nX=[T({name:"get_context",description:"Snapshot the user's live Aether Wealth state in one call — accounts, open trades, recent performance stats, and active alerts — plus the map of dashboard-only actions. Call this first to ground suggestions in what the user is actually doing. Requires sign-in.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async($,v)=>{await u(v);let D=await Promise.all([fX(v.trpc.trading.accounts.list.query()),fX(v.trpc.trading.trades.list.query({status:"OPEN",limit:200})),fX(v.trpc.trading.analytics.stats.query({})),fX(v.trpc.alerts.list.query({}))]);if(D.every((I)=>!I.ok)){let I=D.every((W)=>!W.ok&&n2(W.error));throw Error(I?yz:_2)}let[X,U,G,J]=D,Q=(I)=>I.ok?I.value:{error:I.error};return{accounts:Q(X),openTrades:Q(U),stats:Q(G),alerts:Q(J),dashboard:{url:x4,dashboardOnly:y2,note:`These actions are not available over MCP. When the user needs one, suggest they open the dashboard at ${x4}.`}}}})];function l2(){return{url:process.env.AETHER_APP_PUSH_URL?.trim()||"http://127.0.0.1:9003",secret:process.env.AI_LIVE_PUSH_SECRET?.trim()||void 0}}async function g6($,v,D){let{url:X,secret:U}=l2(),G=`${X.replace(/\/$/,"")}/api/ai/live/push`,J;try{J=await fetch(G,{method:"POST",headers:{"content-type":"application/json",...U?{"x-live-push-secret":U}:{}},body:JSON.stringify({userId:$,tool:v,args:D})})}catch(W){throw Error(`Could not reach the Aether Wealth app at ${G}. Is the dashboard running?`,{cause:W})}if(!J.ok)throw Error(`Live-chart push rejected (HTTP ${J.status}).`);let Q=await J.json().catch(()=>({})),I=typeof Q.delivered==="number"?Q.delivered:0;return{ok:!0,tool:v,delivered:I,message:I>0?`Dispatched to ${I} open chart tab(s).`:"Dispatched, but no open Aether Wealth chart tab is listening — open the dashboard in your browser, then retry."}}function h2($){return{content:[{type:"text",text:["Push confirmation sent to the user's device.","Do NOT ask the user for a code. This trade executes only when the user taps Approve in the Aether Wealth app.","Use trade_intent_status to check whether it was approved, executed, expired, cancelled, or failed.","",JSON.stringify($,null,2)].join(`
|
|
108
|
-
`)}]}}function m2($){if(typeof $!=="object"||$===null)return!1;let v=$.proposal;return typeof v==="object"&&v!==null&&v.approvalMethod==="push"}var _X=[T({name:"get_broker_account",description:"Get the LIVE broker account balance, equity, currency, and connection status for a connected trading account (distinct from list_accounts which lists journal accounts). Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"}},required:["accountId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),_Z(v.trpc,$)}}),T({name:"list_broker_positions",description:"List open broker positions with P&L. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"}},required:["accountId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),yZ(v.trpc,$)}}),T({name:"connect_broker",description:"Attach the user's OWN already-deployed MetaApi account to a journal account. The user creates + deploys their MT5 account in MetaApi's dashboard and generates a scoped token; provide the MetaApi account id (`providerAccountRef`), its region, and the token. We adopt it (no provisioning); the account must already be DEPLOYED and CONNECTED. `providerToken` is sensitive — never expose or log it.",inputSchema:{type:"object",properties:{accountId:{type:"string"},region:{type:"string",enum:["new-york","london"]},providerAccountRef:{type:"string",description:"The MetaApi account id (from the MetaApi dashboard)."},providerToken:{type:"string",description:"The user's scoped MetaApi token for this account. Sensitive — never expose or log it."},approvalMode:{type:"string",enum:["app_otp","email_otp"],description:"Confirmation mode. 'auto' is not selectable here; 'push' is also set later via set_broker_approval_mode because it requires an active app push subscription."}},required:["accountId","region","providerAccountRef","providerToken"],additionalProperties:!1},handler:async($,v)=>{return await u(v),iZ(v.trpc,$)}}),T({name:"broker_connection_status",description:"Get the current live broker connection status. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"}},required:["accountId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),fZ(v.trpc,$)}}),T({name:"set_broker_approval_mode",description:"Change how broker trades are confirmed for a connection between `app_otp` (authenticator), `email_otp`, and `push` (tap-to-approve in the Aether Wealth app; requires an active push subscription). The agent cannot enable `auto` here.",inputSchema:{type:"object",properties:{accountId:{type:"string"},approvalMode:{type:"string",enum:["app_otp","email_otp","push"]}},required:["accountId","approvalMode"],additionalProperties:!1},handler:async($,v)=>{return await u(v),nZ(v.trpc,$)}}),T({name:"propose_trade",description:"Size and PROPOSE a broker trade (does not place it). Provide exactly one of riskPercent or riskAmount; entryPrice is required for limit/stop. Returns the intent id and confirmation method. Push-mode intents are sent to the user's device and must not be executed by the agent. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"},symbol:{type:"string"},direction:{type:"string",enum:["BUY","SELL"]},orderType:{type:"string",enum:["market","limit","stop"]},entryPrice:{type:"number"},stopLoss:{type:"number"},takeProfit:{type:"number"},riskPercent:{type:"number"},riskAmount:{type:"number"}},required:["accountId","symbol","direction","stopLoss"],additionalProperties:!1},handler:async($,v)=>{await u(v);let D=await lZ(v.trpc,$);return m2(D)?h2(D):D}}),T({name:"execute_trade",description:"Place a previously proposed email_otp, app_otp, or auto trade after the required confirmation. Push intents cannot be executed by the agent; the backend enforces this. NEVER guess or fabricate a code.",inputSchema:{type:"object",properties:{intentId:{type:"string"},code:{type:"string"}},required:["intentId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),hZ(v.trpc,$)}}),T({name:"trade_intent_status",description:"Check whether a proposed trade was approved, executed, expired, cancelled, or failed. Especially useful for push-mode intents, which the user approves on their device.",inputSchema:{type:"object",properties:{intentId:{type:"string"}},required:["intentId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),rZ(v.trpc,$)}}),T({name:"cancel_trade_intent",description:"Cancel a previously proposed broker trade. Requires sign-in.",inputSchema:{type:"object",properties:{intentId:{type:"string"}},required:["intentId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),mZ(v.trpc,$)}}),T({name:"close_position",description:"Close an open broker position fully, or partially by passing `volume`.",inputSchema:{type:"object",properties:{accountId:{type:"string"},positionId:{type:"string"},volume:{type:"number"}},required:["accountId","positionId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),cZ(v.trpc,$)}}),T({name:"modify_position",description:"Adjust stop-loss / take-profit on an open position. Stop-loss changes that INCREASE risk are rejected (use the app). Pass null to clear a level.",inputSchema:{type:"object",properties:{accountId:{type:"string"},positionId:{type:"string"},stopLoss:{type:["number","null"]},takeProfit:{type:["number","null"]}},required:["accountId","positionId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),dZ(v.trpc,$)}})],yX=[T({name:"draw_trade_on_chart",description:"Draw a proposed/open trade (entry, stop, target) on the user's OPEN Aether Wealth chart as a position shape. Switch to the intended pair/timeframe first with chart_select_pair.",inputSchema:{type:"object",properties:{direction:{type:"string",enum:["long","short"]},entry:{type:"number"},stopLoss:{type:"number"},takeProfit:{type:"number"},label:{type:"string"}},required:["direction","entry","stopLoss"],additionalProperties:!1},handler:async($,v)=>{await u(v);let D=await v.session.getUserId();return g6(D,"draw_chart_shape",{shapes:[{type:"position",direction:$.direction,entry:$.entry,stop:$.stopLoss,...$.takeProfit===void 0?{}:{target:$.takeProfit},...$.label===void 0?{}:{label:$.label}}]})}})];var r2=["news","press_release"];function c2($){return{pair:$.pair,...$.limit===void 0?{}:{limit:$.limit}}}function d2($){return{currency:$.currency,...$.limit===void 0?{}:{limit:$.limit}}}function p2($){return{currency:$.currency,...$.indicator===void 0?{}:{indicator:$.indicator},...$.limit===void 0?{}:{limit:$.limit}}}function t2($){return{...$.limit===void 0?{}:{limit:$.limit}}}function o2($){return{currency:$.currency,...$.documentType===void 0?{}:{documentType:$.documentType},...$.limit===void 0?{}:{limit:$.limit}}}var lX={type:"integer",minimum:1,maximum:250,description:"Max rows to return (1-250, default 120)."},hX=[T({name:"get_fx_pair_context",description:"Macro context for a currency PAIR (e.g. EURUSD) — the per-currency macro state for both legs (recent releases, surprises, derived trend). Use for a pair-level macro read; for one currency use get_fx_currency_context. Distinct from get_macro_series (raw calendar history) and get_macro_indicator (one curated series).",inputSchema:{type:"object",properties:{pair:{type:"string",description:"6-letter currency pair, e.g. EURUSD (case-insensitive)"},limit:lX},required:["pair"],additionalProperties:!1},handler:async($,v)=>{return await u(v),v.trpc.fxMacroData.pairContext.query(c2($))}}),T({name:"get_fx_currency_context",description:"Macro context for a single CURRENCY (e.g. USD) — recent economic releases, surprises, and the derived macro state for that currency.",inputSchema:{type:"object",properties:{currency:{type:"string",description:"ISO currency code, e.g. USD (case-insensitive)"},limit:lX},required:["currency"],additionalProperties:!1},handler:async($,v)=>{return await u(v),v.trpc.fxMacroData.currencyContext.query(d2($))}}),T({name:"get_fx_predictions",description:"Model forecasts / predictions for a currency's upcoming macro releases. Optionally filter to one indicator by release slug (e.g. cpi).",inputSchema:{type:"object",properties:{currency:{type:"string",description:"ISO currency code, e.g. USD (case-insensitive)"},indicator:{type:"string",description:"Optional release slug filter, e.g. cpi"},limit:lX},required:["currency"],additionalProperties:!1},handler:async($,v)=>{return await u(v),v.trpc.fxMacroData.predictions.query(p2($))}}),T({name:"get_fx_risk_sentiment",description:"Cross-market risk-on / risk-off sentiment series (not currency-scoped). Use to gauge broad market risk appetite.",inputSchema:{type:"object",properties:{limit:lX},additionalProperties:!1},handler:async($,v)=>{return await u(v),v.trpc.fxMacroData.riskSentiment.query(t2($))}}),T({name:"get_fx_documents",description:"Source documents behind the FX macro data for a currency — news items and press releases. Filter by documentType.",inputSchema:{type:"object",properties:{currency:{type:"string",description:"ISO currency code, e.g. USD (case-insensitive)"},documentType:{type:"string",enum:[...r2],description:"Optional filter: news or press_release"},limit:{type:"integer",minimum:1,maximum:100,description:"Max rows to return (1-100, default 50)."}},required:["currency"],additionalProperties:!1},handler:async($,v)=>{return await u(v),v.trpc.fxMacroData.documents.query(o2($))}}),T({name:"get_fx_sync_state",description:"Ingestion/sync status of the FX macro datasets (per dataset family: status, freshness, last success, next refresh). Diagnostic — check data freshness before relying on the other get_fx_* tools.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async($,v)=>{return await u(v),v.trpc.fxMacroData.syncState.query()}})];var a2="momentum: rsi, macd, stoch, stochf, stochrsi, cci, cmo, mom, roc, rocr, willr, mfi, ultosc, ppo, apo, bop, aroon, aroonosc; trend: adx, adxr, dx, plus_di, minus_di, plus_dm, minus_dm, sar, supertrend; moving averages: sma, ema, wma, dema, tema, trima, kama, t3ma, mama, vwap, midpoint, midprice; bands: bbands, keltner, percent_b; volatility: atr, natr, trange; volume: obv, ad, adosc; stats: linearreg, linearregslope, linearregangle, linearregintercept, stddev, var, tsf",mX=[T({name:"get_indicators",description:"Compute Twelve Data technical indicators for a pair + timeframe (requires sign-in). "+`Pass up to 8 indicators by name; params are optional and default sensibly. Names — ${a2}. Bad names/params return an error listing valid options. At most 2 distinct pairs per user at a time.`,inputSchema:{type:"object",properties:{pair:{type:"string",description:"Canonical id, e.g. EURUSD, XAUUSD, BTCUSD (case-insensitive)"},interval:{type:"string",description:"One of 1m, 5m, 15m, 30m, 45m, 1h, 2h, 4h, 1d"},indicators:{type:"array",minItems:1,maxItems:8,description:"Up to 8 indicators to compute on the pair",items:{type:"object",properties:{name:{type:"string",description:"Indicator name, e.g. rsi, macd, ema, bbands, atr, adx"},params:{type:"object",description:'Optional params, e.g. {"time_period": 14} or MACD {"fast_period":12,"slow_period":26}. Defaults applied when omitted.'}},required:["name"],additionalProperties:!1}},outputsize:{type:"integer",minimum:1,maximum:500,description:"Bars to return per indicator (default 30)"}},required:["pair","interval","indicators"],additionalProperties:!1},handler:async($,v)=>{return await u(v),pZ(v.trpc,$)}})];var e2=["horizontal_line","horizontal_ray","vertical_line","cross_line","zone","rectangle","trendline","ray","right_ray","left_ray","extended_line","info_line","trend_angle","position"],rX=[T({name:"chart_select_pair",description:"Switch the user's open Aether Wealth chart to a trading pair. Use the canonical id (case-insensitive), e.g. XAUUSD for gold, EURUSD, BTCUSD. Drives the live browser chart, not backend state.",inputSchema:{type:"object",properties:{pair:{type:"string",description:"Canonical pair id, e.g. XAUUSD (gold), EURUSD, BTCUSD"}},required:["pair"],additionalProperties:!1},handler:async($,v)=>{await u(v);let D=await v.session.getUserId();return g6(D,"select_pair",{pair:$.pair})}}),T({name:"chart_change_timeframe",description:"Change the timeframe/resolution of the user's open Aether Wealth chart, e.g. 1m, 5m, 15m, 30m, 1h, 4h, 1d.",inputSchema:{type:"object",properties:{timeframe:{type:"string",description:"e.g. 1m, 5m, 15m, 30m, 1h, 4h, 1d"}},required:["timeframe"],additionalProperties:!1},handler:async($,v)=>{await u(v);let D=await v.session.getUserId();return g6(D,"change_timeframe",{timeframe:$.timeframe})}}),T({name:"chart_draw_shapes",description:"Draw one or more shapes on the user's OPEN Aether Wealth chart. For key levels use multiple `horizontal_line` shapes, each with `price` and a short `label`. For a fair-value-gap / supply-demand zone use a `zone` with `priceHigh` + `priceLow`. For a trade idea use a `position` with `direction` + `entry`/`stop`/`target`. Prices are in the instrument's price units; `time1`/`time2`/`entryTime` are optional epoch seconds. Switch to the intended pair + timeframe first.",inputSchema:{type:"object",properties:{shapes:{type:"array",description:"Shapes to draw in one batch.",items:{type:"object",properties:{type:{type:"string",enum:[...e2]},label:{type:"string"},color:{type:"string",description:"hex, e.g. #22c55e"},price:{type:"number"},priceHigh:{type:"number"},priceLow:{type:"number"},price1:{type:"number"},price2:{type:"number"},time1:{type:"number",description:"epoch seconds"},time2:{type:"number",description:"epoch seconds"},direction:{type:"string",enum:["long","short"]},entry:{type:"number"},stop:{type:"number"},target:{type:"number"},entryTime:{type:"number",description:"epoch seconds"}},required:["type"],additionalProperties:!1}}},required:["shapes"],additionalProperties:!1},handler:async($,v)=>{await u(v);let D=await v.session.getUserId();return g6(D,"draw_chart_shape",{shapes:$.shapes})}}),T({name:"chart_remove_drawings",description:"Remove AI-drawn shapes from the user's open Aether Wealth chart. `target` defaults to 'all' (clear everything the assistant drew); also accepts 'last', 'focused', or a specific shape id.",inputSchema:{type:"object",properties:{target:{type:"string",description:"'all' (default), 'last', 'focused', or a shape id"}},additionalProperties:!1},handler:async($,v)=>{await u(v);let D=await v.session.getUserId();return g6(D,"remove_chart_drawings",{target:$.target??"all"})}})];var cX=[T({name:"get_candles",description:"Get OHLC candles for a pair + timeframe. Returns up to 200 bars per request (newest 200 by default). Use offset to page further back through history — the store keeps thousands of bars (e.g. limit=200 offset=200 returns bars 201-400 back from the latest). Timeframe may be a base (1m, 5m, 15m, 30m, 1h, 4h, 1d) or any integer multiple of one (e.g. 2h, 3h, 12h, 90m), aggregated server-side; invalid or unsupported timeframes return an error, not an empty list.",inputSchema:{type:"object",properties:{pair:{type:"string",description:"e.g. EURUSD, BTCUSD (canonical id; case-insensitive)"},timeframe:{type:"string",description:"A base (1m, 5m, 15m, 30m, 1h, 4h, 1d) or an integer multiple of one (e.g. 2h, 3h, 12h, 90m). No fractional (2.5h) or sub-minute values."},limit:{type:"integer",minimum:1,maximum:200,description:"Maximum candles to return (1-200). Omit for the newest 200."},offset:{type:"integer",minimum:0,maximum:4800,description:"Number of the most-recent candles to skip before applying limit — pages backward through history (0–4800). On aggregated timeframes (e.g. 2h, 3h) the reachable depth is lower (≈ 4800 ÷ the aggregation factor) since fewer bars exist; a deeper offset returns fewer or no bars."}},required:["pair","timeframe"],additionalProperties:!1},handler:async($,v)=>{return await u(v),PX(v.trpc,$)}}),T({name:"list_economic_calendar",description:'List economic calendar events. Filter by currency, date range, release, or minimum impact (1-5). Currency and indicator/release are validated against the catalog: unknown values return an error listing valid options, so an empty result always means "no events" rather than "bad input".',inputSchema:{type:"object",properties:{currency:{type:"array",items:{type:"string"},description:'ISO currency codes, e.g. ["USD","EUR"]'},from:{type:"string",description:"ISO 8601 date or datetime"},to:{type:"string",description:"ISO 8601 date or datetime"},indicator:{type:"string",description:"release slug, e.g. cpi"},impactMin:{type:"integer",minimum:1,maximum:5},view:{type:"string",enum:["minimal","rich"]}},additionalProperties:!1},handler:async($,v)=>{return await u(v),oZ(v.trpc,$)}}),T({name:"get_macro_series",description:"Get a macro indicator time series (e.g. USD cpi). Currency and indicator are validated against the catalog: unknown values return an error listing valid options (case-insensitive).",inputSchema:{type:"object",properties:{currency:{type:"string",description:"ISO currency code, e.g. USD"},indicator:{type:"string",description:"release slug, e.g. cpi"},from:{type:"string",description:"ISO 8601 date or datetime"},to:{type:"string",description:"ISO 8601 date or datetime"},limit:{type:"integer",minimum:1,maximum:1000}},required:["currency","indicator"],additionalProperties:!1},handler:async($,v)=>{return await u(v),aZ(v.trpc,$)}}),T({name:"get_macro_indicator",description:"Get a curated macro indicator series from FXMacroData (live + cached) with unit/frequency metadata and the central-bank target where available — use get_macro_series for raw historical calendar values. Range defaults to 12m; returns a null result when the macro data provider is not configured.",inputSchema:{type:"object",properties:{currency:{type:"string",description:"ISO currency code, e.g. USD"},indicator:{type:"string",description:"indicator slug in lowercase snake_case, e.g. cpi"},range:{type:"string",enum:[...tZ],description:"Lookback window (default 12m)"}},required:["currency","indicator"],additionalProperties:!1},handler:async($,v)=>{return await u(v),eZ(v.trpc,$)}}),T({name:"get_market_config",description:"Get the catalog of supported instruments + timeframes (useful before calling other tools).",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async($,v)=>{return await u(v),sZ(v.trpc)}})];var YA={stopLoss:{type:"number"},takeProfit:{type:"number"},lotSize:{type:"number"},notes:{type:"string"},timeframe:{type:"string",description:"e.g. 1h, 4h, 1d"},riskPercent:{type:"number"},tags:{type:"array",items:{type:"string"}}},s2={pair:{type:"string",description:"e.g. EURUSD, BTCUSD"},direction:{type:"string",enum:["LONG","SHORT"]},entryPrice:{type:"number"},exitPrice:{type:"number"},stopLoss:{type:"number"},takeProfit:{type:"number"},lotSize:{type:"number"},entryTime:{type:"string",description:"ISO 8601 datetime"},exitTime:{type:"string",description:"ISO 8601 datetime"},notes:{type:"string"},timeframe:{type:"string",description:"e.g. 1h, 4h, 1d"},emotionalTag:{type:"string"},fees:{type:"number"},swap:{type:"number"},reportedPnl:{type:"number",description:"Broker-reported P&L to store instead of recalculated P&L"},tags:{type:"array",items:{type:"string"}}},dX=[T({name:"list_trades",description:"List the authenticated user's trades. Filter by account, status, pair, or date range (ISO 8601). Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"},status:{type:"string",enum:["OPEN","CLOSED","CANCELLED","ALL"]},pair:{type:"string",description:"e.g. EURUSD, BTCUSD"},from:{type:"string",description:"ISO 8601 datetime (inclusive lower bound)"},to:{type:"string",description:"ISO 8601 datetime (inclusive upper bound)"},page:YO,limit:zO},additionalProperties:!1},handler:async($,v)=>{return await u(v),UO(v.trpc,$)}}),T({name:"get_trade",description:"Get a single trade by id. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"}},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await u(v),DO(v.trpc,$)}}),T({name:"list_accounts",description:"List the user's trading accounts (use an account's id when creating a trade). Requires sign-in.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async($,v)=>{return await u(v),PZ(v.trpc)}}),T({name:"create_account",description:'Create a trading account in the journal. Use accountType "demo" for paper/demo accounts and "live" for live accounts. Requires sign-in.',inputSchema:{type:"object",properties:{name:{type:"string"},broker:{type:"string"},accountType:{type:"string",description:"default: personal"},initialBalance:{type:"number",description:"default: 0"},currency:{type:"string",description:"3-letter code, default: USD"},notes:{type:"string"},defaultRiskAmount:{type:"number"}},required:["name"],additionalProperties:!1},handler:async($,v)=>{return await u(v),bZ(v.trpc,$)}}),T({name:"trade_stats",description:"Trading performance statistics (win rate, PnL, etc.). Filter by account, pair, or date range. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"},pair:{type:"string"},from:{type:"string",description:"ISO 8601 datetime"},to:{type:"string",description:"ISO 8601 datetime"}},additionalProperties:!1},handler:async($,v)=>{return await u(v),$O(v.trpc,$)}}),T({name:"create_trade",description:"Record a new trade. Requires sign-in. Use list_accounts to find the accountId.",inputSchema:{type:"object",properties:{accountId:{type:"string",description:"Trading account id (see list_accounts)"},pair:{type:"string",description:"e.g. EURUSD, BTCUSD"},direction:{type:"string",enum:["LONG","SHORT"]},entryPrice:{type:"number"},entryTime:{type:"string",description:"ISO 8601 datetime"},...YA},required:["accountId","pair","direction","entryPrice","entryTime"],additionalProperties:!1},handler:async($,v)=>{return await u(v),XO(v.trpc,$)}}),T({name:"update_trade",description:"Update fields on an existing trade. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},pair:{type:"string"},direction:{type:"string",enum:["LONG","SHORT"]},entryPrice:{type:"number"},entryTime:{type:"string",description:"ISO 8601 datetime"},...YA},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await u(v),GO(v.trpc,$)}}),T({name:"close_trade",description:"Close an open trade with an exit price + time. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},exitPrice:{type:"number"},exitTime:{type:"string",description:"ISO 8601 datetime"},fees:{type:"number"},swap:{type:"number"},notes:{type:"string"}},required:["id","exitPrice","exitTime"],additionalProperties:!1},handler:async($,v)=>{return await u(v),JO(v.trpc,$)}}),T({name:"delete_trade",description:"Permanently delete a single trade by id. Only trades on demo accounts can be deleted. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"}},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await u(v),QO(v.trpc,$)}}),T({name:"delete_trades",description:"Permanently delete trades on a specific demo account. Requires explicit status (OPEN, CLOSED, CANCELLED, or ALL). This cannot be undone. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string",description:"Trading account id to delete from"},status:{type:"string",enum:["OPEN","CLOSED","CANCELLED","ALL"]}},required:["accountId","status"],additionalProperties:!1},handler:async($,v)=>{return await u(v),IO(v.trpc,$)}}),T({name:"import_trades",description:"Import up to 500 trades into one account. Rows with both exitPrice and exitTime are imported as closed trades. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string",description:"Trading account id to import into"},trades:{type:"array",minItems:1,maxItems:500,items:{type:"object",properties:s2,required:["pair","direction","entryPrice","lotSize","entryTime"],additionalProperties:!1}}},required:["accountId","trades"],additionalProperties:!1},handler:async($,v)=>{return await u(v),WO(v.trpc,$)}})];function W5($={}){let v=$.includeAuthTools??!0,D=$.includeLiveChartTools??!0;return[...v?SX:[],...nX,...dX,..._X,...qX,...cX,...hX,...mX,...iX,...D?[...rX,...yX]:[]]}var $g="aether-wealth-mcp",vg="0.1.35";function BA($,v){let D=new F0({name:$g,version:vg},{capabilities:{tools:{listChanged:!1},resources:{listChanged:!1,subscribe:!1},prompts:{listChanged:!1}}});return Ug(D,$,v??$.toolContext),D}function Ug($,v,D){let X=!1,U=(J)=>{let Q=v.clientGate?.nudge;if(Q&&!X)return X=!0,`${Q}
|
|
108
|
+
`)}]}}function m2($){if(typeof $!=="object"||$===null)return!1;let v=$.proposal;return typeof v==="object"&&v!==null&&v.approvalMethod==="push"}var _X=[T({name:"get_broker_account",description:"Get the LIVE broker account balance, equity, currency, and connection status for a connected trading account (distinct from list_accounts which lists journal accounts). Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"}},required:["accountId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),_Z(v.trpc,$)}}),T({name:"list_broker_positions",description:"List open broker positions with P&L. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"}},required:["accountId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),yZ(v.trpc,$)}}),T({name:"connect_broker",description:"Attach the user's OWN already-deployed MetaApi account to a journal account. The user creates + deploys their MT5 account in MetaApi's dashboard and generates a scoped token; provide the MetaApi account id (`providerAccountRef`), its region, and the token. We adopt it (no provisioning); the account must already be DEPLOYED and CONNECTED. `providerToken` is sensitive — never expose or log it.",inputSchema:{type:"object",properties:{accountId:{type:"string"},region:{type:"string",enum:["new-york","london"]},providerAccountRef:{type:"string",description:"The MetaApi account id (from the MetaApi dashboard)."},providerToken:{type:"string",description:"The user's scoped MetaApi token for this account. Sensitive — never expose or log it."},approvalMode:{type:"string",enum:["app_otp","email_otp"],description:"Confirmation mode. 'auto' is not selectable here; 'push' is also set later via set_broker_approval_mode because it requires an active app push subscription."}},required:["accountId","region","providerAccountRef","providerToken"],additionalProperties:!1},handler:async($,v)=>{return await u(v),iZ(v.trpc,$)}}),T({name:"broker_connection_status",description:"Get the current live broker connection status. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"}},required:["accountId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),fZ(v.trpc,$)}}),T({name:"set_broker_approval_mode",description:"Change how broker trades are confirmed for a connection between `app_otp` (authenticator), `email_otp`, and `push` (tap-to-approve in the Aether Wealth app; requires an active push subscription). The agent cannot enable `auto` here.",inputSchema:{type:"object",properties:{accountId:{type:"string"},approvalMode:{type:"string",enum:["app_otp","email_otp","push"]}},required:["accountId","approvalMode"],additionalProperties:!1},handler:async($,v)=>{return await u(v),nZ(v.trpc,$)}}),T({name:"propose_trade",description:"Size and PROPOSE a broker trade (does not place it). Provide exactly one of riskPercent or riskAmount; entryPrice is required for limit/stop. Returns the intent id and confirmation method. Push-mode intents are sent to the user's device and must not be executed by the agent. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"},symbol:{type:"string"},direction:{type:"string",enum:["BUY","SELL"]},orderType:{type:"string",enum:["market","limit","stop"]},entryPrice:{type:"number"},stopLoss:{type:"number"},takeProfit:{type:"number"},riskPercent:{type:"number"},riskAmount:{type:"number"}},required:["accountId","symbol","direction","stopLoss"],additionalProperties:!1},handler:async($,v)=>{await u(v);let D=await lZ(v.trpc,$);return m2(D)?h2(D):D}}),T({name:"execute_trade",description:"Place a previously proposed email_otp, app_otp, or auto trade after the required confirmation. Push intents cannot be executed by the agent; the backend enforces this. NEVER guess or fabricate a code.",inputSchema:{type:"object",properties:{intentId:{type:"string"},code:{type:"string"}},required:["intentId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),hZ(v.trpc,$)}}),T({name:"trade_intent_status",description:"Check whether a proposed trade was approved, executed, expired, cancelled, or failed. Especially useful for push-mode intents, which the user approves on their device.",inputSchema:{type:"object",properties:{intentId:{type:"string"}},required:["intentId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),rZ(v.trpc,$)}}),T({name:"cancel_trade_intent",description:"Cancel a previously proposed broker trade. Requires sign-in.",inputSchema:{type:"object",properties:{intentId:{type:"string"}},required:["intentId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),mZ(v.trpc,$)}}),T({name:"close_position",description:"Close an open broker position fully, or partially by passing `volume`.",inputSchema:{type:"object",properties:{accountId:{type:"string"},positionId:{type:"string"},volume:{type:"number"}},required:["accountId","positionId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),cZ(v.trpc,$)}}),T({name:"modify_position",description:"Adjust stop-loss / take-profit on an open position. Stop-loss changes that INCREASE risk are rejected (use the app). Pass null to clear a level.",inputSchema:{type:"object",properties:{accountId:{type:"string"},positionId:{type:"string"},stopLoss:{type:["number","null"]},takeProfit:{type:["number","null"]}},required:["accountId","positionId"],additionalProperties:!1},handler:async($,v)=>{return await u(v),dZ(v.trpc,$)}})],yX=[T({name:"draw_trade_on_chart",description:"Draw a proposed/open trade (entry, stop, target) on the user's OPEN Aether Wealth chart as a position shape. Switch to the intended pair/timeframe first with chart_select_pair.",inputSchema:{type:"object",properties:{direction:{type:"string",enum:["long","short"]},entry:{type:"number"},stopLoss:{type:"number"},takeProfit:{type:"number"},label:{type:"string"}},required:["direction","entry","stopLoss"],additionalProperties:!1},handler:async($,v)=>{await u(v);let D=await v.session.getUserId();return g6(D,"draw_chart_shape",{shapes:[{type:"position",direction:$.direction,entry:$.entry,stop:$.stopLoss,...$.takeProfit===void 0?{}:{target:$.takeProfit},...$.label===void 0?{}:{label:$.label}}]})}})];var r2=["news","press_release"];function c2($){return{pair:$.pair,...$.limit===void 0?{}:{limit:$.limit}}}function d2($){return{currency:$.currency,...$.limit===void 0?{}:{limit:$.limit}}}function p2($){return{currency:$.currency,...$.indicator===void 0?{}:{indicator:$.indicator},...$.limit===void 0?{}:{limit:$.limit}}}function t2($){return{...$.limit===void 0?{}:{limit:$.limit}}}function o2($){return{currency:$.currency,...$.documentType===void 0?{}:{documentType:$.documentType},...$.limit===void 0?{}:{limit:$.limit}}}var lX={type:"integer",minimum:1,maximum:250,description:"Max rows to return (1-250, default 120)."},hX=[T({name:"get_fx_pair_context",description:"Macro context for a currency PAIR (e.g. EURUSD) — the per-currency macro state for both legs (recent releases, surprises, derived trend). Use for a pair-level macro read; for one currency use get_fx_currency_context. Distinct from get_macro_series (raw calendar history) and get_macro_indicator (one curated series).",inputSchema:{type:"object",properties:{pair:{type:"string",description:"6-letter currency pair, e.g. EURUSD (case-insensitive)"},limit:lX},required:["pair"],additionalProperties:!1},handler:async($,v)=>{return await u(v),v.trpc.fxMacroData.pairContext.query(c2($))}}),T({name:"get_fx_currency_context",description:"Macro context for a single CURRENCY (e.g. USD) — recent economic releases, surprises, and the derived macro state for that currency.",inputSchema:{type:"object",properties:{currency:{type:"string",description:"ISO currency code, e.g. USD (case-insensitive)"},limit:lX},required:["currency"],additionalProperties:!1},handler:async($,v)=>{return await u(v),v.trpc.fxMacroData.currencyContext.query(d2($))}}),T({name:"get_fx_predictions",description:"Model forecasts / predictions for a currency's upcoming macro releases. Optionally filter to one indicator by release slug (e.g. cpi).",inputSchema:{type:"object",properties:{currency:{type:"string",description:"ISO currency code, e.g. USD (case-insensitive)"},indicator:{type:"string",description:"Optional release slug filter, e.g. cpi"},limit:lX},required:["currency"],additionalProperties:!1},handler:async($,v)=>{return await u(v),v.trpc.fxMacroData.predictions.query(p2($))}}),T({name:"get_fx_risk_sentiment",description:"Cross-market risk-on / risk-off sentiment series (not currency-scoped). Use to gauge broad market risk appetite.",inputSchema:{type:"object",properties:{limit:lX},additionalProperties:!1},handler:async($,v)=>{return await u(v),v.trpc.fxMacroData.riskSentiment.query(t2($))}}),T({name:"get_fx_documents",description:"Source documents behind the FX macro data for a currency — news items and press releases. Filter by documentType.",inputSchema:{type:"object",properties:{currency:{type:"string",description:"ISO currency code, e.g. USD (case-insensitive)"},documentType:{type:"string",enum:[...r2],description:"Optional filter: news or press_release"},limit:{type:"integer",minimum:1,maximum:100,description:"Max rows to return (1-100, default 50)."}},required:["currency"],additionalProperties:!1},handler:async($,v)=>{return await u(v),v.trpc.fxMacroData.documents.query(o2($))}}),T({name:"get_fx_sync_state",description:"Ingestion/sync status of the FX macro datasets (per dataset family: status, freshness, last success, next refresh). Diagnostic — check data freshness before relying on the other get_fx_* tools.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async($,v)=>{return await u(v),v.trpc.fxMacroData.syncState.query()}})];var a2="momentum: rsi, macd, stoch, stochf, stochrsi, cci, cmo, mom, roc, rocr, willr, mfi, ultosc, ppo, apo, bop, aroon, aroonosc; trend: adx, adxr, dx, plus_di, minus_di, plus_dm, minus_dm, sar, supertrend; moving averages: sma, ema, wma, dema, tema, trima, kama, t3ma, mama, vwap, midpoint, midprice; bands: bbands, keltner, percent_b; volatility: atr, natr, trange; volume: obv, ad, adosc; stats: linearreg, linearregslope, linearregangle, linearregintercept, stddev, var, tsf",mX=[T({name:"get_indicators",description:"Compute Twelve Data technical indicators for a pair + timeframe (requires sign-in). "+`Pass up to 8 indicators by name; params are optional and default sensibly. Names — ${a2}. Bad names/params return an error listing valid options. At most 2 distinct pairs per user at a time.`,inputSchema:{type:"object",properties:{pair:{type:"string",description:"Canonical id, e.g. EURUSD, XAUUSD, BTCUSD (case-insensitive)"},interval:{type:"string",description:"One of 1m, 5m, 15m, 30m, 45m, 1h, 2h, 4h, 1d"},indicators:{type:"array",minItems:1,maxItems:8,description:"Up to 8 indicators to compute on the pair",items:{type:"object",properties:{name:{type:"string",description:"Indicator name, e.g. rsi, macd, ema, bbands, atr, adx"},params:{type:"object",description:'Optional params, e.g. {"time_period": 14} or MACD {"fast_period":12,"slow_period":26}. Defaults applied when omitted.'}},required:["name"],additionalProperties:!1}},outputsize:{type:"integer",minimum:1,maximum:500,description:"Bars to return per indicator (default 30)"}},required:["pair","interval","indicators"],additionalProperties:!1},handler:async($,v)=>{return await u(v),pZ(v.trpc,$)}})];var e2=["horizontal_line","horizontal_ray","vertical_line","cross_line","zone","rectangle","trendline","ray","right_ray","left_ray","extended_line","info_line","trend_angle","position"],rX=[T({name:"chart_select_pair",description:"Switch the user's open Aether Wealth chart to a trading pair. Use the canonical id (case-insensitive), e.g. XAUUSD for gold, EURUSD, BTCUSD. Drives the live browser chart, not backend state.",inputSchema:{type:"object",properties:{pair:{type:"string",description:"Canonical pair id, e.g. XAUUSD (gold), EURUSD, BTCUSD"}},required:["pair"],additionalProperties:!1},handler:async($,v)=>{await u(v);let D=await v.session.getUserId();return g6(D,"select_pair",{pair:$.pair})}}),T({name:"chart_change_timeframe",description:"Change the timeframe/resolution of the user's open Aether Wealth chart, e.g. 1m, 5m, 15m, 30m, 1h, 4h, 1d.",inputSchema:{type:"object",properties:{timeframe:{type:"string",description:"e.g. 1m, 5m, 15m, 30m, 1h, 4h, 1d"}},required:["timeframe"],additionalProperties:!1},handler:async($,v)=>{await u(v);let D=await v.session.getUserId();return g6(D,"change_timeframe",{timeframe:$.timeframe})}}),T({name:"chart_draw_shapes",description:"Draw one or more shapes on the user's OPEN Aether Wealth chart. For key levels use multiple `horizontal_line` shapes, each with `price` and a short `label`. For a fair-value-gap / supply-demand zone use a `zone` with `priceHigh` + `priceLow`. For a trade idea use a `position` with `direction` + `entry`/`stop`/`target`. Prices are in the instrument's price units; `time1`/`time2`/`entryTime` are optional epoch seconds. Switch to the intended pair + timeframe first.",inputSchema:{type:"object",properties:{shapes:{type:"array",description:"Shapes to draw in one batch.",items:{type:"object",properties:{type:{type:"string",enum:[...e2]},label:{type:"string"},color:{type:"string",description:"hex, e.g. #22c55e"},price:{type:"number"},priceHigh:{type:"number"},priceLow:{type:"number"},price1:{type:"number"},price2:{type:"number"},time1:{type:"number",description:"epoch seconds"},time2:{type:"number",description:"epoch seconds"},direction:{type:"string",enum:["long","short"]},entry:{type:"number"},stop:{type:"number"},target:{type:"number"},entryTime:{type:"number",description:"epoch seconds"}},required:["type"],additionalProperties:!1}}},required:["shapes"],additionalProperties:!1},handler:async($,v)=>{await u(v);let D=await v.session.getUserId();return g6(D,"draw_chart_shape",{shapes:$.shapes})}}),T({name:"chart_remove_drawings",description:"Remove AI-drawn shapes from the user's open Aether Wealth chart. `target` defaults to 'all' (clear everything the assistant drew); also accepts 'last', 'focused', or a specific shape id.",inputSchema:{type:"object",properties:{target:{type:"string",description:"'all' (default), 'last', 'focused', or a shape id"}},additionalProperties:!1},handler:async($,v)=>{await u(v);let D=await v.session.getUserId();return g6(D,"remove_chart_drawings",{target:$.target??"all"})}})];var cX=[T({name:"get_candles",description:"Get OHLC candles for a pair + timeframe. Returns up to 200 bars plus nextCursor. To page through the complete stored history, pass nextCursor back as cursor until nextCursor is null. Timeframe may be a stored base (1m, 5m, 15m, 30m, 1h, 4h, 1d) or any integer multiple of one (e.g. 3m, 2h, 12h, 90m), aggregated server-side without splitting derived candles across pages. The legacy offset parameter remains available for shallow pagination; do not combine offset and cursor.",inputSchema:{type:"object",properties:{pair:{type:"string",description:"e.g. EURUSD, BTCUSD (canonical id; case-insensitive)"},timeframe:{type:"string",description:"A base (1m, 5m, 15m, 30m, 1h, 4h, 1d) or an integer multiple of one (e.g. 2h, 3h, 12h, 90m). No fractional (2.5h) or sub-minute values."},limit:{type:"integer",minimum:1,maximum:200,description:"Maximum candles to return (1-200). Omit for the newest 200."},offset:{type:"integer",minimum:0,maximum:4800,description:"Legacy shallow pagination: number of recent candles to skip (0–4800). Use cursor instead for complete history; do not combine offset and cursor."},cursor:{type:"string",minLength:1,maxLength:2048,description:"Opaque nextCursor returned by the previous get_candles page. Omit on the first page; continue until nextCursor is null. Do not combine with offset."}},required:["pair","timeframe"],additionalProperties:!1},handler:async($,v)=>{return await u(v),PX(v.trpc,$)}}),T({name:"list_economic_calendar",description:'List economic calendar events. Filter by currency, date range, release, or minimum impact (1-5). Currency and indicator/release are validated against the catalog: unknown values return an error listing valid options, so an empty result always means "no events" rather than "bad input".',inputSchema:{type:"object",properties:{currency:{type:"array",items:{type:"string"},description:'ISO currency codes, e.g. ["USD","EUR"]'},from:{type:"string",description:"ISO 8601 date or datetime"},to:{type:"string",description:"ISO 8601 date or datetime"},indicator:{type:"string",description:"release slug, e.g. cpi"},impactMin:{type:"integer",minimum:1,maximum:5},view:{type:"string",enum:["minimal","rich"]}},additionalProperties:!1},handler:async($,v)=>{return await u(v),oZ(v.trpc,$)}}),T({name:"get_macro_series",description:"Get a macro indicator time series (e.g. USD cpi). Currency and indicator are validated against the catalog: unknown values return an error listing valid options (case-insensitive).",inputSchema:{type:"object",properties:{currency:{type:"string",description:"ISO currency code, e.g. USD"},indicator:{type:"string",description:"release slug, e.g. cpi"},from:{type:"string",description:"ISO 8601 date or datetime"},to:{type:"string",description:"ISO 8601 date or datetime"},limit:{type:"integer",minimum:1,maximum:1000}},required:["currency","indicator"],additionalProperties:!1},handler:async($,v)=>{return await u(v),aZ(v.trpc,$)}}),T({name:"get_macro_indicator",description:"Get a curated macro indicator series from FXMacroData (live + cached) with unit/frequency metadata and the central-bank target where available — use get_macro_series for raw historical calendar values. Range defaults to 12m; returns a null result when the macro data provider is not configured.",inputSchema:{type:"object",properties:{currency:{type:"string",description:"ISO currency code, e.g. USD"},indicator:{type:"string",description:"indicator slug in lowercase snake_case, e.g. cpi"},range:{type:"string",enum:[...tZ],description:"Lookback window (default 12m)"}},required:["currency","indicator"],additionalProperties:!1},handler:async($,v)=>{return await u(v),eZ(v.trpc,$)}}),T({name:"get_market_config",description:"Get the catalog of supported instruments + timeframes (useful before calling other tools).",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async($,v)=>{return await u(v),sZ(v.trpc)}})];var YA={stopLoss:{type:"number"},takeProfit:{type:"number"},lotSize:{type:"number"},notes:{type:"string"},timeframe:{type:"string",description:"e.g. 1h, 4h, 1d"},riskPercent:{type:"number"},tags:{type:"array",items:{type:"string"}}},s2={pair:{type:"string",description:"e.g. EURUSD, BTCUSD"},direction:{type:"string",enum:["LONG","SHORT"]},entryPrice:{type:"number"},exitPrice:{type:"number"},stopLoss:{type:"number"},takeProfit:{type:"number"},lotSize:{type:"number"},entryTime:{type:"string",description:"ISO 8601 datetime"},exitTime:{type:"string",description:"ISO 8601 datetime"},notes:{type:"string"},timeframe:{type:"string",description:"e.g. 1h, 4h, 1d"},emotionalTag:{type:"string"},fees:{type:"number"},swap:{type:"number"},reportedPnl:{type:"number",description:"Broker-reported P&L to store instead of recalculated P&L"},tags:{type:"array",items:{type:"string"}}},dX=[T({name:"list_trades",description:"List the authenticated user's trades. Filter by account, status, pair, or date range (ISO 8601). Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"},status:{type:"string",enum:["OPEN","CLOSED","CANCELLED","ALL"]},pair:{type:"string",description:"e.g. EURUSD, BTCUSD"},from:{type:"string",description:"ISO 8601 datetime (inclusive lower bound)"},to:{type:"string",description:"ISO 8601 datetime (inclusive upper bound)"},page:YO,limit:zO},additionalProperties:!1},handler:async($,v)=>{return await u(v),UO(v.trpc,$)}}),T({name:"get_trade",description:"Get a single trade by id. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"}},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await u(v),DO(v.trpc,$)}}),T({name:"list_accounts",description:"List the user's trading accounts (use an account's id when creating a trade). Requires sign-in.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async($,v)=>{return await u(v),PZ(v.trpc)}}),T({name:"create_account",description:'Create a trading account in the journal. Use accountType "demo" for paper/demo accounts and "live" for live accounts. Requires sign-in.',inputSchema:{type:"object",properties:{name:{type:"string"},broker:{type:"string"},accountType:{type:"string",description:"default: personal"},initialBalance:{type:"number",description:"default: 0"},currency:{type:"string",description:"3-letter code, default: USD"},notes:{type:"string"},defaultRiskAmount:{type:"number"}},required:["name"],additionalProperties:!1},handler:async($,v)=>{return await u(v),bZ(v.trpc,$)}}),T({name:"trade_stats",description:"Trading performance statistics (win rate, PnL, etc.). Filter by account, pair, or date range. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"},pair:{type:"string"},from:{type:"string",description:"ISO 8601 datetime"},to:{type:"string",description:"ISO 8601 datetime"}},additionalProperties:!1},handler:async($,v)=>{return await u(v),$O(v.trpc,$)}}),T({name:"create_trade",description:"Record a new trade. Requires sign-in. Use list_accounts to find the accountId.",inputSchema:{type:"object",properties:{accountId:{type:"string",description:"Trading account id (see list_accounts)"},pair:{type:"string",description:"e.g. EURUSD, BTCUSD"},direction:{type:"string",enum:["LONG","SHORT"]},entryPrice:{type:"number"},entryTime:{type:"string",description:"ISO 8601 datetime"},...YA},required:["accountId","pair","direction","entryPrice","entryTime"],additionalProperties:!1},handler:async($,v)=>{return await u(v),XO(v.trpc,$)}}),T({name:"update_trade",description:"Update fields on an existing trade. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},pair:{type:"string"},direction:{type:"string",enum:["LONG","SHORT"]},entryPrice:{type:"number"},entryTime:{type:"string",description:"ISO 8601 datetime"},...YA},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await u(v),GO(v.trpc,$)}}),T({name:"close_trade",description:"Close an open trade with an exit price + time. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"},exitPrice:{type:"number"},exitTime:{type:"string",description:"ISO 8601 datetime"},fees:{type:"number"},swap:{type:"number"},notes:{type:"string"}},required:["id","exitPrice","exitTime"],additionalProperties:!1},handler:async($,v)=>{return await u(v),JO(v.trpc,$)}}),T({name:"delete_trade",description:"Permanently delete a single trade by id. Only trades on demo accounts can be deleted. Requires sign-in.",inputSchema:{type:"object",properties:{id:{type:"string"}},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await u(v),QO(v.trpc,$)}}),T({name:"delete_trades",description:"Permanently delete trades on a specific demo account. Requires explicit status (OPEN, CLOSED, CANCELLED, or ALL). This cannot be undone. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string",description:"Trading account id to delete from"},status:{type:"string",enum:["OPEN","CLOSED","CANCELLED","ALL"]}},required:["accountId","status"],additionalProperties:!1},handler:async($,v)=>{return await u(v),IO(v.trpc,$)}}),T({name:"import_trades",description:"Import up to 500 trades into one account. Rows with both exitPrice and exitTime are imported as closed trades. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string",description:"Trading account id to import into"},trades:{type:"array",minItems:1,maxItems:500,items:{type:"object",properties:s2,required:["pair","direction","entryPrice","lotSize","entryTime"],additionalProperties:!1}}},required:["accountId","trades"],additionalProperties:!1},handler:async($,v)=>{return await u(v),WO(v.trpc,$)}})];function W5($={}){let v=$.includeAuthTools??!0,D=$.includeLiveChartTools??!0;return[...v?SX:[],...nX,...dX,..._X,...qX,...cX,...hX,...mX,...iX,...D?[...rX,...yX]:[]]}var $g="aether-wealth-mcp",vg="0.1.36";function BA($,v){let D=new F0({name:$g,version:vg},{capabilities:{tools:{listChanged:!1},resources:{listChanged:!1,subscribe:!1},prompts:{listChanged:!1}}});return Ug(D,$,v??$.toolContext),D}function Ug($,v,D){let X=!1,U=(J)=>{let Q=v.clientGate?.nudge;if(Q&&!X)return X=!0,`${Q}
|
|
109
109
|
|
|
110
110
|
${J}`;return J},G=(J)=>{let Q=v.clientGate?.nudge;if(!Q||X)return J;X=!0;let I=J.find((W)=>W.type==="text");if(I)return J.map((W)=>W===I?{type:"text",text:`${Q}
|
|
111
111
|
|
|
@@ -114,7 +114,7 @@ ${I.text}`}:W);return[{type:"text",text:Q},...J]};$.setRequestHandler(pv,async()
|
|
|
114
114
|
`),F1(500,{error:"internal error"})}finally{await G.close().catch(LA),await U.close().catch(LA)}}function Wg($){let{servedPaths:v,bundle:D,log:X,oauth:U,bearerToken:G}=$,J=new Set([PW,...[...v].filter((I)=>I!==z5).map((I)=>`${PW}${I}`)]),Q=async(I)=>{let W=new URL(I.url),z=zg(I,W,v,U,J);if(z)return z;if(U)return Yg(I,U,D,X);if(G&&!Hg(I,G))return new Response("unauthorized",{status:401});return KA(I,D,void 0,X)};return U?async(I)=>uB(await Q(I)):Q}function zg($,v,D,X,U){if(v.pathname===Ig&&$.method==="GET")return F1(200,{ok:!0});if(X){let G=TB($,v,X,U);if(G)return G}if(!D.has(v.pathname))return new Response("not found",{status:404});if($.method==="GET"&&!X)return F1(200,{ok:!0,transport:"streamable-http"});return null}async function Yg($,v,D,X){let U=EB($),G=new URL($.url).pathname,J=G===z5?"":G;for(let W of RB($,U)){let z=v.rateLimiter.check(W);if(!z.allowed)return new Response(JSON.stringify({error:"rate_limited"}),{status:429,headers:{"content-type":"application/json","retry-after":String(z.retryAfterSeconds)}})}if(!U)return bW(v,void 0,J);let Q;try{Q=await v.tokenVerifier.verify(U)}catch(W){return X(`[http] token verification unavailable: ${B5(W)}
|
|
115
115
|
`),F1(502,{error:"token verification unavailable"})}if(!Q.ok)return bW(v,"invalid_token",J);let I=CB({token:U,userId:Q.userId,trpcUrl:v.trpcUrl,onUnauthorized:()=>v.tokenVerifier.invalidate(U)});return KA($,D,I,X)}function Bg($,v,D){let U=globalThis.Bun.serve({port:v.port,hostname:D,fetch:$});return{port:U.port??v.port,close:async()=>{await U.stop()}}}async function Vg($,v,D){let X=Jg((J,Q)=>{Lg(J,Q,$).catch(()=>{})});return await new Promise((J,Q)=>{X.once("error",Q),X.listen(v.port,D,()=>{X.off("error",Q),J()})}),{port:X.address()?.port??v.port,close:()=>new Promise((J,Q)=>{X.close((I)=>{if(I)Q(I);else J()})})}}async function Lg($,v,D){try{let X=await Kg($),U=await D(X);await Ag(U,v)}catch(X){if(!v.headersSent){v.statusCode=500,v.setHeader("content-type","application/json"),v.end(JSON.stringify({error:B5(X)}));return}v.end()}}async function Kg($){let v=Ng($),D=Zg($),X=$.method??"GET",U={method:X,headers:D},G=await Og($,X);if(G)U.body=G,U.duplex="half";return new Request(v,U)}function Ng($){let v=$.socket,D=$.headers["x-forwarded-proto"]??(v?.encrypted?"https":"http"),X=$.headers.host??"localhost";return new URL($.url??"/",`${D}://${X}`).toString()}function Zg($){let v=new Headers;for(let[D,X]of Object.entries($.headers)){if(X===void 0)continue;if(Array.isArray(X))for(let U of X)v.append(D,U);else v.append(D,X)}return v}async function Og($,v){if(v==="GET"||v==="HEAD")return;let D=[];for await(let X of $)D.push(Buffer.isBuffer(X)?X:Buffer.from(X));return D.length>0?Buffer.concat(D):void 0}async function Ag($,v){if(v.statusCode=$.status,$.headers.forEach((X,U)=>{v.setHeader(U,X)}),!$.body){v.end();return}let D=$.body.getReader();try{while(!0){let{value:X,done:U}=await D.read();if(U)break;if(X)v.write(Buffer.from(X))}}finally{D.releaseLock(),v.end()}}function Hg($,v){let D=$.headers.get("authorization");if(!D)return!1;if(!D.startsWith("Bearer "))return!1;let X=D.slice(7),U=Buffer.from(X,"utf8"),G=Buffer.from(v,"utf8");if(U.length!==G.length){let J=Buffer.alloc(G.length);return U.copy(J,0,0,Math.min(U.length,G.length)),VA(J,G),!1}return VA(U,G)}function B5($){if($ instanceof Error)return $.message;return String($)}function LA(){return}var Fg="aether-wealth-mcp",jg=[33417,33418,33419],wg="/callback",Mg=["trades:read","trades:write","accounts:read","alerts:read","alerts:write"],Pg="aether-wealth-mcp",bg="AETHER_MCP_CREDENTIALS_FILE",y1={clientId:Fg,redirectPorts:jg,redirectPath:wg,scopes:Mg,keychainService:Pg,credentialsFilePath:S0("aether-wealth-mcp"),forceFileEnvVar:bg};function NA($={}){let v=$.hosted??!1,D=v?["Authentication is handled by the MCP connection itself — there are no sign-in tools to call. If calls fail with an authorization error, the user must re-authorize this connection in their MCP client settings."]:["Auth tools:"," • login — sign in. Opens the browser; the user authenticates and approves access. Call this first if a data tool reports the user is not signed in."," • logout — sign out on this device."],X=v?" 3. If it fails with an authorization error, tell the user to re-authorize the Aether Wealth connection in their MCP client, then retry.":' 3. If it reports "not signed in", call login, wait for the user to finish in the browser, then retry.';return[{name:"getting_started",description:"Brief the LLM on what the Aether Wealth MCP exposes and the sign-in-first flow.",handler:()=>[{role:"user",content:{type:"text",text:["You are connected to the Aether Wealth MCP — programmatic access to the user's trading journal, alerts, market data, indicators, charts, and live-chart controls, over an authenticated connection.","",...D,"","Context:"," • get_context — snapshot accounts, open trades, recent stats, and active alerts in one call. Call it first to ground your suggestions.","","Domains (partial — see the aetherwealth://capabilities resource for the full set):"," • Journal: list_trades, get_trade, list_accounts, create_account, create_trade, update_trade, close_trade, delete_trade, delete_trades, import_trades, trade_stats"," • Alerts: list_alerts, create_price_alert, create_trendline_alert, create_indicator_alert, list_indicator_alerts, update_indicator_alert, delete_indicator_alert, update_alert, delete_alert"," • Market data + indicators: get_candles, get_market_config, get_indicators"," • Macro: list_economic_calendar, get_macro_series, get_macro_indicator"," • FX macro context: get_fx_pair_context, get_fx_currency_context, get_fx_predictions, get_fx_risk_sentiment, get_fx_documents, get_fx_sync_state"," • Charts: render_chart, chart_select_pair, chart_change_timeframe, chart_draw_shapes, chart_remove_drawings"," • Broker execution: propose_trade creates a user-confirmed intent; execute_trade only applies to email_otp/app_otp/auto intents. For push intents, do not ask for a code — use trade_intent_status to check the app approval outcome.","","Deletion rule:"," • delete_trade and delete_trades are permanent and only work on demo accounts. Live-account trade deletes are blocked by the backend.","","Recommended flow:"," 1. Call get_context to load live state."," 2. Try the data tool the user asked for (e.g. list_trades).",X].join(`
|
|
116
116
|
`)}}]},{name:"dashboard_context",description:"Brief the LLM on the full Aether Wealth surface, grounding in live state, and when to suggest the dashboard.",handler:()=>[{role:"user",content:{type:"text",text:["You are connected to Aether Wealth, a multi-market trading workspace.",MX,"","Before you advise, call get_context to load the user's live state (accounts, open trades, recent stats, active alerts) so your suggestions fit what they are actually doing. The aetherwealth://capabilities resource, if your client attaches it, is the full surface map — which actions are MCP-callable vs dashboard-only.","","When the user needs something that is dashboard-only (the full charting workspace and saved layouts, the Pine editor, the full journal UI, the Aether Intelligence assistant),",`tell them to open the dashboard at ${x4} rather than attempting it over MCP.`].join(`
|
|
117
|
-
`)}}]}]}var ZA="aether-wealth-mcp",V5="0.1.
|
|
117
|
+
`)}}]}]}var ZA="aether-wealth-mcp",V5="0.1.36";function qg($){return{toolContext:$.toolContext,tools:new Map(($.tools??W5()).map((v)=>[v.name,v])),resources:new Map(($.resources??fz()).map((v)=>[v.uri,v])),prompts:new Map(($.prompts??iz()).map((v)=>[v.name,v])),...$.clientGate?{clientGate:$.clientGate}:{},log:$.log??((v)=>{process.stderr.write(v)})}}function Sg($,v){let D=new F0({name:ZA,version:V5},{capabilities:{tools:{listChanged:!1},resources:{listChanged:!1,subscribe:!1},prompts:{listChanged:!1}}});return kg(D,$,v??$.toolContext),D}class pX{server;bundle;constructor($){this.bundle=qg($),this.server=Sg(this.bundle),this.server.oninitialized=()=>{this.bundle.log(`${ZA} initialized
|
|
118
118
|
`)}}async connect($){await this.server.connect($)}async close(){await this.server.close()}isInitialized(){return this.server.getClientVersion()!==void 0}getRegistryBundle(){return this.bundle}}function kg($,v,D){let X=!1,U=(J)=>{let Q=v.clientGate?.nudge;if(Q&&!X)return X=!0,`${Q}
|
|
119
119
|
|
|
120
120
|
${J}`;return J},G=(J)=>{let Q=v.clientGate?.nudge;if(!Q||X)return J;X=!0;let I=J.find((W)=>W.type==="text");if(I)return J.map((W)=>W===I?{type:"text",text:`${Q}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aetherwealth/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.36",
|
|
4
4
|
"description": "Official Aether Wealth MCP server for AI trading assistants: OAuth access to your trading journal, alerts, market data, macro calendar, and technical indicators.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|