@aetherwealth/mcp 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -105,7 +105,7 @@ data:
|
|
|
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.",PX,"","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 ${f4} rather than attempting it over MCP.`].join(`
|
|
106
106
|
`)}}]}]}function y5(){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:qZ()})}]}function r2($){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 p2($){return{name:$.name,...r2($)}}function SZ($){return $.trading.accounts.list.query()}function kZ($,v){return $.trading.accounts.create.mutate(p2(v))}function n5($){return{triggerType:$.triggerType??"close",isPersistent:$.isPersistent??!1,notifyEmail:$.notifyEmail??!0,notifyPush:$.notifyPush??!0,...$.message===void 0?{}:{message:$.message},...$.expiresAt===void 0?{}:{expiresAt:$.expiresAt}}}function EZ($){return{...$.includeArchived===void 0?{}:{includeArchived:$.includeArchived},...$.pair===void 0?{}:{pair:$.pair}}}function t2($){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 o2($){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 TZ($,v){return $.alerts.list.query(EZ(v))}function RZ($,v){let D={pair:v.pair,timeframe:v.timeframe,price:v.price,condition:v.condition,...n5(v)};return $.alerts.createPrice.mutate(D)}function gZ($,v){let D={pair:v.pair,timeframe:v.timeframe,price1:v.price1,time1:v.time1,price2:v.price2,time2:v.time2,condition:v.condition,...n5(v)};return $.alerts.createTrendline.mutate(D)}function CZ($,v){return $.alerts.update.mutate(t2(v))}function uZ($,v){return $.alerts.delete.mutate({id:v.id})}function xZ($,v){let D=EZ(v);return $.alerts.indicator.list.query(D)}function fZ($,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",...n5(v)};return $.alerts.indicator.create.mutate(D)}function _Z($,v){return $.alerts.indicator.update.mutate(o2(v))}function iZ($,v){return $.alerts.indicator.delete.mutate({id:v.id})}function a2($){if($.provider==="mt5_executor")return{accountId:$.accountId,provider:$.provider,baseUrl:$.baseUrl,providerAccountRef:$.providerAccountRef,providerToken:$.providerToken,...$.approvalMode===void 0?{}:{approvalMode:$.approvalMode}};return{accountId:$.accountId,region:$.region,providerAccountRef:$.providerAccountRef,providerToken:$.providerToken,...$.provider===void 0?{}:{provider:$.provider},...$.approvalMode===void 0?{}:{approvalMode:$.approvalMode}}}function bX($){return{accountId:$.accountId}}function e2($){return{accountId:$.accountId,approvalMode:$.approvalMode,...$.totpCode===void 0?{}:{totpCode:$.totpCode}}}function s2($){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 $R($){return{intentId:$.intentId,...$.code===void 0?{}:{code:$.code}}}function vR($){return{intentId:$.intentId}}function UR($){return{intentId:$.intentId}}function DR($){return{accountId:$.accountId,positionId:$.positionId,...$.volume===void 0?{}:{volume:$.volume}}}function XR($){return{accountId:$.accountId,positionId:$.positionId,...$.stopLoss===void 0?{}:{stopLoss:$.stopLoss},...$.takeProfit===void 0?{}:{takeProfit:$.takeProfit}}}function yZ($,v){return $.execution.connect.mutate(a2(v))}function nZ($,v){return $.execution.status.query(bX(v))}function lZ($,v){return $.execution.disconnect.mutate(bX(v))}function hZ($,v){return $.execution.setApprovalMode.mutate(e2(v))}function mZ($,v){return $.execution.account.query(bX(v))}function cZ($,v){return $.execution.positions.query(bX(v))}function dZ($,v){return $.execution.propose.mutate(s2(v))}function rZ($,v){return $.execution.execute.mutate($R(v))}function pZ($,v){return $.execution.cancel.mutate(vR(v))}function tZ($,v){return $.execution.intentStatus.query(UR(v))}function oZ($,v){return $.execution.closePosition.mutate(DR(v))}function aZ($,v){return $.execution.modifyPosition.mutate(XR(v))}function GR($){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 eZ($,v){return $.technicalIndicators.get.query(GR(v))}var sZ=["3m","6m","12m","24m","all"];function JR($){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 QR($){return{currency:$.currency,indicator:$.indicator,...$.from===void 0?{}:{from:$.from},...$.to===void 0?{}:{to:$.to},...$.limit===void 0?{}:{limit:$.limit}}}function WR($){return{currency:$.currency,indicator:$.indicator,...$.range===void 0?{}:{range:$.range}}}function zR($){return{pair:$.pair,timeframe:$.timeframe,...$.limit===void 0?{}:{limit:$.limit},...$.offset===void 0?{}:{offset:$.offset},...$.cursor===void 0?{}:{cursor:$.cursor}}}function YR($){return{...zR($),...$.sourceId===void 0?{}:{sourceId:$.sourceId}}}function qX($,v){return $.marketData.mcpCandles.query(YR(v))}function $O($,v){return $.marketData.listCalendar.query(JR(v))}function vO($,v){return $.marketData.listIndicatorSeries.query(QR(v))}function UO($,v){return $.macroIndicator.list.query(WR(v))}function DO($){return $.marketData.getConfig.query()}function IR($){return{...$.accountId===void 0?{}:{accountId:$.accountId},...$.pair===void 0?{}:{pair:$.pair},...$.from===void 0?{}:{from:$.from},...$.to===void 0?{}:{to:$.to}}}function XO($,v){return $.trading.analytics.stats.query(IR(v))}function VR($){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 GO($){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 KR($){return{accountId:$.accountId,pair:$.pair,direction:$.direction,entryPrice:$.entryPrice,entryTime:$.entryTime,...GO($)}}function LR($){return{id:$.id,...$.pair===void 0?{}:{pair:$.pair},...$.direction===void 0?{}:{direction:$.direction},...$.entryPrice===void 0?{}:{entryPrice:$.entryPrice},...$.entryTime===void 0?{}:{entryTime:$.entryTime},...GO($)}}function BR($){return{id:$.id,exitPrice:$.exitPrice,exitTime:$.exitTime,...$.fees===void 0?{}:{fees:$.fees},...$.swap===void 0?{}:{swap:$.swap},...$.notes===void 0?{}:{notes:$.notes}}}function NR($){return{accountId:$.accountId,status:$.status}}function ZR($){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 OR($){return{accountId:$.accountId,trades:$.trades.map(ZR)}}function JO($,v){return $.trading.trades.list.query(VR(v))}function QO($,v){return $.trading.trades.get.query({id:v.id})}function WO($,v){return $.trading.trades.create.mutate(KR(v))}function zO($,v){return $.trading.trades.update.mutate(LR(v))}function YO($,v){return $.trading.trades.close.mutate(BR(v))}function IO($,v){return $.trading.trades.delete.mutate({id:v.id})}function VO($,v){return $.trading.trades.deleteMany.mutate(NR(v))}function KO($,v){return $.trading.trades.importMany.mutate(OR(v))}function E($){return $}var l5='Not signed in to Aether Wealth. Call the "login" tool to authenticate, then retry.';async function R($){if(!await $.session.getAccessToken())throw Error(l5)}var LO={type:"integer",minimum:1,maximum:200,description:"Max rows to return"},BO={type:"integer",minimum:1,description:"Page number (1-indexed)"};function SX($,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=HR($,D)??FR($,D);return X?{ok:!1,reason:X}:{ok:!0,args:D}}function HR($,v){for(let D of $.required??[])if(!(D in v)||v[D]===void 0||v[D]===null)return`missing required: ${D}`;return null}function FR($,v){if($.additionalProperties!==!1)return null;for(let D of Object.keys(v))if(!(D in $.properties))return`unknown property: ${D}`;return null}var h5={type:"string",enum:["above","below","crosses"]},w0={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"}},kX=[E({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 R(v),TZ(v.trpc,$)}}),E({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:h5,...w0},required:["pair","timeframe","price","condition"],additionalProperties:!1},handler:async($,v)=>{return await R(v),RZ(v.trpc,$)}}),E({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:h5,...w0},required:["pair","timeframe","price1","time1","price2","time2","condition"],additionalProperties:!1},handler:async($,v)=>{return await R(v),gZ(v.trpc,$)}}),E({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:h5,timeframe:{type:"string"},isActive:{type:"boolean"},isArchived:{type:"boolean"},...w0},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await R(v),CZ(v.trpc,$)}}),E({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 R(v),uZ(v.trpc,$)}}),E({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 R(v),xZ(v.trpc,$)}}),E({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"},...w0},required:["pair","timeframe","indicatorType","indicatorParams","outputSeries","condition"],additionalProperties:!1},handler:async($,v)=>{return await R(v),fZ(v.trpc,$)}}),E({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"},...w0},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await R(v),_Z(v.trpc,$)}}),E({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 R(v),iZ(v.trpc,$)}})];var EX=[E({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."}}}),E({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 B$=($,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}}},jR=[B$("AUDUSD","AUD/USD","Forex Majors"),B$("EURUSD","EUR/USD","Forex Majors"),B$("GBPUSD","GBP/USD","Forex Majors"),B$("USDCAD","USD/CAD","Forex Majors"),B$("USDCHF","USD/CHF","Forex Majors"),B$("USDJPY","USD/JPY","Forex Majors",{pipSize:0.01,priceDecimals:3}),B$("AUDCAD","AUD/CAD","Forex Minors"),B$("AUDCHF","AUD/CHF","Forex Minors"),B$("AUDJPY","AUD/JPY","Forex Minors",{pipSize:0.01,priceDecimals:3}),B$("AUDNZD","AUD/NZD","Forex Minors"),B$("EURAUD","EUR/AUD","Forex Minors"),B$("EURCAD","EUR/CAD","Forex Minors"),B$("EURCHF","EUR/CHF","Forex Minors"),B$("EURGBP","EUR/GBP","Forex Minors"),B$("EURJPY","EUR/JPY","Forex Minors",{pipSize:0.01,priceDecimals:3}),B$("EURNZD","EUR/NZD","Forex Minors"),B$("GBPAUD","GBP/AUD","Forex Minors"),B$("GBPCAD","GBP/CAD","Forex Minors"),B$("GBPCHF","GBP/CHF","Forex Minors"),B$("GBPJPY","GBP/JPY","Forex Minors",{pipSize:0.01,priceDecimals:3}),B$("GBPNZD","GBP/NZD","Forex Minors")],AR=[{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 R$($,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 wR=[R$("BTCUSD","BTC/USD"),R$("ETHUSD","ETH/USD"),R$("SOLUSD","SOL/USD"),R$("BNBUSD","BNB/USD"),R$("AVAXUSD","AVAX/USD"),R$("LINKUSD","LINK/USD"),R$("LTCUSD","LTC/USD"),R$("BCHUSD","BCH/USD"),R$("ATOMUSD","ATOM/USD"),R$("TONUSD","TON/USD"),R$("DOTUSD","DOT/USD"),R$("XRPUSD","XRP/USD",!0),R$("ADAUSD","ADA/USD",!0),R$("DOGEUSD","DOGE/USD",!0),R$("TRXUSD","TRX/USD",!0),R$("POLUSD","POL/USD",!0)],MR=[{id:"NAS100",displayName:"Nasdaq 100",kind:"index",exchange:"NASDAQ",region:"US",category:"Indices",pipSize:0.01,priceDecimals:2,contractSize:20,providers:{twelvedata:"QQQ"}}],PR=[{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 bR=[{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")],TX=Object.freeze([...jR,...AR,...wR,...MR,...PR,...bR]);class M0{byKey;instruments;providerNames;constructor($){this.instruments=Object.freeze([...$]);let v=new Map,D=new Set;for(let X of $){if(m5(v,X.id,X,"id"),X.displayName!==X.id)m5(v,X.displayName,X,"displayName");for(let[U,G]of Object.entries(X.providers))if(D.add(U),m5(v,NO(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(NO($,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 NO($,v){return`${$}:${v}`}function m5($,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 SR=["forex","metal","crypto","index","commodity","stock","bond"],kR=l.object({kind:l.enum(SR),displayName:l.string().min(1).optional(),exchange:l.string().min(1).optional(),region:l.string().min(1).optional(),category:l.string().min(1).optional(),pipSize:l.number().positive().optional(),priceDecimals:l.number().int().min(0).max(12).optional(),contractSize:l.number().positive().optional(),providers:l.record(l.string().min(1),l.string().min(1))}),gp=l.record(l.string().min(1),kR).refine(($)=>Object.keys($).length>0,{message:"INSTRUMENTS must contain at least one entry"});var ER=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 c5($,v){return Number(v.toFixed($.priceDecimals))}var g$="-apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', Roboto, sans-serif",d5=11,r5=15,p5=11,t5=13,ZO=12,RX=17,OO=26,HO=0.85,FO=20,jO=8,AO=64,wO=26,f1=18,gX=16,MO=20,PO=300,o5=120,bO=1280,qO=720,SO=2,kO=!0,EO=320,TO=2560,RO=240,gO=1440,CO=1,uO=3,CX={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"}},a5=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function xO($,v){if(!Number.isFinite(v))return"0.00000";if(!$)return v.toFixed(5);return c5($,v).toFixed($.priceDecimals)}function fO($,v,D){let X=new Date(v*1000);if(CR($)){if(D===void 0||_R(D,v))return xR(X);return uR(X)}return fR(X)}function CR($){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 P0($,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 uR($){return`${uX($.getUTCHours())}:${uX($.getUTCMinutes())}`}function xR($){return`${uX($.getUTCDate())} ${a5[$.getUTCMonth()]}`}function fR($){return`${uX($.getUTCDate())} ${a5[$.getUTCMonth()]} '${String($.getUTCFullYear()).slice(-2)}`}function _R($,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 uX($){return String($).padStart(2,"0")}var _O="data:image/png;base64,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";function iO($){return $.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}function I$($){return`<line${i1($)} />`}function F$($){return`<rect${i1($)} />`}function p$($,v){return`<text${i1(v)}>${iO($)}</text>`}function yO($){return`<image${i1($)} />`}function nO($,v){let D=$.map((X)=>`${e5(X.x)},${e5(X.y)}`).join(" ");return`<polygon${i1({...v,points:D})} />`}function o($,v={}){if($.length===0)return"";return`<g${i1(v)}>${$}</g>`}function lO($,v,D){return[`<svg xmlns="http://www.w3.org/2000/svg" width="${$}" height="${v}" viewBox="0 0 ${$} ${v}" fill="none">`,D,"</svg>"].join("")}function _1($,v=11){return Math.max(10,Math.round($.length*v*0.58))}function i1($){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}="${e5(X)}"`;if(typeof X==="string")return`${D}="${iO(X)}"`;return""}).filter((D)=>D.length>0).join(" ");return v.length>0?` ${v}`:""}function e5($){let v=Math.round($*100)/100;return Number.isInteger(v)?String(v):v.toFixed(2)}var xX=16,iR=9,yR=12,nR=8,lR=8;function hO($,v){let D=[],X=$.plotLeft,U=$.instrument?.displayName??$.pair;D.push(p$(U,{x:X,y:xX,fill:v.headerText,"font-size":r5,"font-weight":700,"letter-spacing":0.2,"font-family":g$})),X+=_1(U,r5)+iR;let G=$.timeframe,J=_1(G,p5)+lR*2,Q=xX-RX+4;D.push(F$({x:X,y:Q,width:J,height:RX,rx:4,fill:v.badgeBg})),D.push(p$(G,{x:X+J/2,y:Q+RX/2+0.5,fill:v.badgeText,"font-size":p5,"font-weight":600,"text-anchor":"middle","dominant-baseline":"middle","font-family":g$})),X+=J+yR;let W=$.visibleCandles,z=W[W.length-1].close,Y=W[0].open,I=z-Y,V=Y===0?null:I/Y*100,K=I>=0?v.upCandle:v.downCandle,L=$.formatPrice(z);D.push(p$(L,{x:X,y:xX,fill:K,"font-size":t5,"font-weight":600,"font-family":g$})),X+=_1(L,t5)+nR;let N=$.instrument?.priceDecimals??5;return D.push(p$(P0(I,V,N),{x:X,y:xX,fill:K,"font-size":ZO,"font-weight":500,"font-family":g$})),o(D.join(""))}function mO($,v){if(!v)return"";let D=OO;return yO({href:_O,x:$.plotRight-D-8,y:$.plotBottom-D-8,width:D,height:D,opacity:HO})}var hR=["price","priceHigh","priceLow","price1","price2","entry","stop","target"];function dO($,v){let D=$.candles.slice(-$.bars),X=jO,U=FO,G=Math.max(X+1,$.width-AO),J=Math.max(U+1,$.height-wO),Q=G-X,W=J-U,z=Q/Math.max(1,D.length),Y=Math.min(...D.map((a)=>a.low)),I=Math.max(...D.map((a)=>a.high)),V=I-Y,K=V>0?V*0.06:Math.max(Math.abs(I)*0.006,0.000001),L=Y-K,N=I+K,Z=Math.max(N-L,0.000001),F=V>0?Math.max(Z,V/0.6):Z,S=pR($.shapes),g=S.length>0?Math.min(...S):Number.POSITIVE_INFINITY,u=S.length>0?Math.max(...S):Number.NEGATIVE_INFINITY,k=Number.isFinite(g)&&g<L?L-g:0,N$=Number.isFinite(u)&&u>N?u-N:0,j$=Math.max(0,F-Z),g4=k+N$,Q4=L,y$=N;if(g4<=j$)Q4-=k,y$+=N$;else if(k>0&&N$===0)Q4-=Math.min(k,j$);else if(N$>0&&k===0)y$+=Math.min(N$,j$);else if(g4>0){let a=j$/g4;Q4-=k*a,y$+=N$*a}let h1=Math.max(y$-Q4,0.000001),m1=eR(D),c1=D.length-1;function q0(a){return U+(y$-a)/h1*W}function SH(a){if(!Number.isFinite(a))return{y:J,clamped:!0,edge:"bottom"};if(a>y$)return{y:U,clamped:!0,edge:"top"};if(a<Q4)return{y:J,clamped:!0,edge:"bottom"};return{y:q0(a),clamped:!1,edge:null}}function eX(a){return X+(a+0.5)*z}function O7(a){return rR(D,c1,m1,a)}function H7(a){return eX(O7(a))}function F7(a){return c1-a}function kH(a,j7,RH){let A7=oR(a,j7);if(A7!==void 0)return H7(A7);let gH=aR(a,j7)??RH;return eX(F7(gH))}function EH(a=6){return mR(Q4,y$,a)}function TH(a=7){return dR(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:W,slot:z,visibleCandles:D,instrument:v,priceRange:{min:Q4,max:y$,candleMin:Y,candleMax:I},averageSpacing:m1,formatPrice(a){return xO(v,a)},priceToY:q0,projectPrice:SH,indexToX:eX,timeToIndex:O7,timeToX:H7,barsBackToIndex:F7,resolveEndpointX:kH,nicePriceTicks:EH,niceTimeTickIndices:TH}}var cO=3;function mR($,v,D=6){let X=sR($,v,D),U=Math.ceil($/X)*X,G=Math.floor(v/X)*X,J=$g(X),Q=[];if(G>=U){let W=Math.round((G-U)/X);for(let z=0;z<=W;z+=1)Q.push(Number((U+z*X).toFixed(J+2)))}if(Q.length<cO)return cR($,v,cO+2);return Q}function cR($,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 dR($,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 rR($,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 tR($,v,X)}function pR($){let v=[];for(let D of $){if(D.affectsScale===!1)continue;for(let X of hR){let U=D[X];if(typeof U==="number"&&Number.isFinite(U))v.push(U)}}return v}function tR($,v,D){let X=0,U=v;while(X<=U){let Y=Math.floor((X+U)/2),I=$[Y];if(I.time===D)return Y;if(I.time<D)X=Y+1;else U=Y-1}let G=Math.min(v,X),J=Math.max(0,G-1),Q=$[J],z=$[G].time-Q.time;if(z<=0)return J;return J+(D-Q.time)/z}function oR($,v){if(v==="start")return $.time1??$.entryTime;return $.time2}function aR($,v){if(v==="start")return $.barsBack1;return $.barsBack2}function eR($){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 sR($,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],W=U,z=Number.POSITIVE_INFINITY;for(let Y of J){let I=10**Y;for(let V of Q){let K=V*I,L=Math.ceil($/K),N=Math.floor(v/K),Z=N>=L?N-L+1:1,F=Math.abs(Z-D);if(F<z)z=F,W=K}}return W}function $g($){let v=0,D=$;while(v<10&&Math.abs(Math.round(D)-D)>0.00000001)D*=10,v+=1;return v}function Z6($){return CX[$]}function rO($,v){let D=Z6($.theme),X=vg($.nicePriceTicks(),$.formatPrice),U=$.niceTimeTickIndices(),G=[],J=[],Q=$.visibleCandles[$.visibleCandles.length-1],W=$.priceToY(Q.close),z=Q.close>=Q.open?D.upCandle:D.downCandle,Y=$.formatPrice(Q.close);for(let N of X){let Z=$.priceToY(N);G.push(I$({x1:$.plotLeft,y1:Math.round(Z)+0.5,x2:$.plotRight,y2:Math.round(Z)+0.5,stroke:D.grid,"stroke-width":1}));let F=$.formatPrice(N);if(F!==Y)J.push(p$(F,{x:$.width-6,y:Z,fill:D.text,"font-size":d5,"font-family":g$,"text-anchor":"end","dominant-baseline":"middle"}))}for(let N of U){let Z=$.visibleCandles[N];if(!Z)continue;let F=$.indexToX(N),g=(N>0?$.visibleCandles[N-1]:void 0)?.time;G.push(I$({x1:Math.round(F)+0.5,y1:$.plotTop,x2:Math.round(F)+0.5,y2:$.plotBottom,stroke:D.grid,"stroke-width":1})),J.push(p$(fO($.timeframe,Z.time,g),{x:F,y:$.height-8,fill:D.text,"font-size":d5,"font-family":g$,"text-anchor":"middle"}))}J.push(I$({x1:Math.round($.plotRight)+0.5,y1:$.plotTop,x2:Math.round($.plotRight)+0.5,y2:$.plotBottom,stroke:D.axisBorder,"stroke-width":1})),J.push(I$({x1:$.plotLeft,y1:Math.round($.plotBottom)+0.5,x2:$.width,y2:Math.round($.plotBottom)+0.5,stroke:D.axisBorder,"stroke-width":1}));let I=I$({x1:$.plotLeft,y1:Math.round(W)+0.5,x2:$.plotRight,y2:Math.round(W)+0.5,stroke:z,"stroke-width":1,"stroke-dasharray":"4 4"}),V={y:W,label:$.formatPrice(Q.close),fill:z,height:f1},K=hO($,D),L=mO($,v);return{gridSvg:o(G.join(""),{"shape-rendering":"crispEdges"}),axesSvg:J.join(""),lastPriceSvg:I,lastPriceTag:V,headerSvg:K,watermarkSvg:L}}function vg($,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 pO($){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,W=$.priceToY(U.high),z=$.priceToY(U.low),Y=$.priceToY(U.open),I=$.priceToY(U.close),V=Math.min(Y,I),K=Math.max(Y,I),L=Math.max(1,Math.round(K-V)),N=Math.round(J-v/2),Z=Math.round(V);D.push(I$({x1:Q,y1:Math.round(W)+0.5,x2:Q,y2:Math.round(z)+0.5,stroke:G,"stroke-width":1})),D.push(F$({x:N,y:Z,width:v,height:L,fill:G}))}return o(D.join(""),{"shape-rendering":"crispEdges"})}function tO($,v){if(v.length===0)return"";let D=Z6($.theme);return Ug(v,$.plotTop+2,$.plotBottom-2).map((U)=>o([F$({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>=f1?11:10,"font-family":g$,"font-weight":600,"text-anchor":"end","dominant-baseline":"middle"})].join(""),{"shape-rendering":"crispEdges"})).join("")}function Ug($,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],W=X[J],z=Q.y+(Q.height+W.height)/2;if(W.y<z)W.y=z}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],W=X[J],z=Q.y-(Q.height+W.height)/2;if(W.y>z)W.y=z}}let G=X[0];if(G.y<v)G.y=v;return X}function s5($){let v=Gg($.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:oO($.width,bO,EO,TO),height:oO($.height,qO,RO,gO),bars:Dg($.bars??o5),scale:Xg($.scale),watermark:$.watermark??kO,...$.fontFiles?{fontFiles:$.fontFiles}:{}}}function Dg($){if(!Number.isFinite($))return o5;return $7(Math.round($),MO,PO)}function Xg($){if($===void 0||!Number.isFinite($)||$<=0)return SO;return $7($,CO,uO)}function oO($,v,D,X){if($===void 0||!Number.isFinite($)||$<=0)return v;return $7(Math.round($),D,X)}function $7($,v,D){return Math.min(D,Math.max(v,$))}function Gg($){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 Jg}from"node:module";var Qg=Jg(import.meta.url);function aO($,v,D,X){let{Resvg:U}=Wg();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 Wg(){try{return Qg("@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 zg={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"},Yg={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 Ig=["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 b0($){if(typeof $!=="string")return null;let v=$.trim().toLowerCase();return zg[v]??null}function $H($){return`Unknown shape type: "${String($)}". Supported types: ${Ig.join(", ")}`}function v7($){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 Vg($){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=v7($[D]);if(X!==void 0)return X}return}function R4($,v,D){let X=$[v];if(!X||typeof X!=="object"||Array.isArray(X))return;return t$(X,D)}function Kg($){if(typeof $.type!=="string")return null;let v=$.type.trim().toLowerCase();return v.length>0?v:null}function O4($,v,D){if($[v]!==void 0||D===void 0)return;$[v]=D}function U7($,v,D){O4($,v,D===void 0?void 0:Math.trunc(D))}function Lg($,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=Vg($.side)}function Bg($){return t$($,["level","y","value","priceLevel","linePrice"])??R4($,"point1",["price","y","value"])??R4($,"from",["price","y","value"])}function eO($,v){if(v==="start")return t$($,["startPrice","fromPrice","priceA","p1"])??R4($,"point1",["price","y","value"])??R4($,"from",["price","y","value"]);return t$($,["endPrice","toPrice","priceB","p2"])??R4($,"point2",["price","y","value"])??R4($,"to",["price","y","value"])}function sO($,v){if(v==="start")return t$($,["time","startTime","fromTime","timestamp","t1"])??R4($,"point1",["time","t","timestamp"])??R4($,"from",["time","t","timestamp"]);return t$($,["endTime","toTime","t2"])??R4($,"point2",["time","t","timestamp"])??R4($,"to",["time","t","timestamp"])}function Ng($){O4($,"price",Bg($)),O4($,"priceHigh",t$($,["high","upper","top","max","priceTop","priceUpper"])),O4($,"priceLow",t$($,["low","lower","bottom","min","priceBottom","priceLower"])),O4($,"price1",eO($,"start")),O4($,"price2",eO($,"end"))}function Zg($){U7($,"time1",sO($,"start")),U7($,"time2",sO($,"end")),O4($,"barsBack1",t$($,["barsBack","barBack","lookback","bars"])),O4($,"barsBack2",t$($,["barsBackEnd","barBackEnd","lookbackEnd"]))}function Og($){O4($,"entry",t$($,["entryPrice","open","openPrice"])),O4($,"stop",t$($,["stopLoss","sl","stopPrice"])),O4($,"target",t$($,["takeProfit","tp","targetPrice","tpPrice"])),U7($,"entryTime",t$($,["entryTimestamp"]))}function Hg($){let v=v7($.priceHigh),D=v7($.priceLow);if(v!==void 0&&D!==void 0&&v<D)$.priceHigh=D,$.priceLow=v}function vH($){if(typeof $!=="object"||$===null||Array.isArray($))return $;let v={...$},D=Kg(v),X=b0(D);if(X)v.type=X;return Lg(v,D),Ng(v),Zg(v),Og(v),Hg(v),v}function UH($){return Yg[$].required}var Fg=l.object({type:l.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:l.coerce.number().optional().describe("Price level (required for horizontal_line, horizontal_ray, cross_line)"),priceHigh:l.coerce.number().optional().describe("Upper price boundary (required for zone/rectangle)"),priceLow:l.coerce.number().optional().describe("Lower price boundary (required for zone/rectangle)"),price1:l.coerce.number().optional().describe("First point price (required for trendline/ray/right_ray/left_ray/extended_line/info_line/trend_angle)"),price2:l.coerce.number().optional().describe("Second point price (required for trendline/ray/right_ray/left_ray/extended_line/info_line/trend_angle)"),time1:l.number().int().optional().describe("Absolute time (epoch seconds) of the first endpoint for trendline/rays or anchor for vertical_line. PREFERRED over barsBack1."),time2:l.number().int().optional().describe("Absolute time (epoch seconds) of the second endpoint (trendline/rays) or right edge of a zone. PREFERRED over barsBack2."),barsBack1:l.number().optional().describe("FALLBACK only — bars back from the current bar for first endpoint/anchor (trendline, rays, vertical_line). Use time1 when possible."),barsBack2:l.number().optional().describe("FALLBACK only — bars back from the current bar for second endpoint / zone right edge. Use time2 when possible."),direction:l.enum(["long","short"]).optional().describe('Position direction (required for position): "long" or "short"'),entry:l.coerce.number().optional().describe("Entry price (required for position)"),stop:l.coerce.number().optional().describe("Stop-loss price (required for position)"),target:l.coerce.number().optional().describe("Take-profit price (required for position)"),entryTime:l.number().int().optional().describe("Absolute time (epoch seconds) for the position entry anchor. Defaults to the current bar."),label:l.string().optional().describe('Label text, e.g. "Support", "Resistance", "Demand Zone", "Long EURCHF"'),color:l.string().optional().describe('Color hex, e.g. "#22c55e" green, "#ef4444" red, "#3b82f6" blue'),affectsScale:l.boolean().optional().describe("Whether this shape expands the rendered price range (default true). Set false for distant context levels that should stay labelled but not compress the setup.")}).superRefine(($,v)=>{let D=b0($.type);if(!D){v.addIssue({code:"custom",message:$H($.type),path:["type"]});return}for(let X of UH(D))if($[X.field]===void 0)v.addIssue({code:"custom",message:X.message,path:[X.field]})}),DH=l.preprocess(vH,Fg),ot=l.object({shapes:l.array(DH).min(1)});function XH($){let v=[],D=[];for(let[X,U]of $.entries()){let G=DH.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 z$($,v,D,X){let U=$.projectPrice(D);if(!U.clamped||U.edge===null)return"";let G=Z6($.theme),J=Y$(v,$.plotLeft+10,$.plotRight-10),Q=U.edge==="top"?$.plotTop+4:$.plotBottom-4,W=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}],z=U.edge==="top"?Q+16:Q-10;return o([nO(W,{fill:X}),p$($.formatPrice(D),{x:J,y:z,fill:G.markerText,"font-size":10,"font-family":g$,"text-anchor":"middle"})].join(""))}function D7($,v,D,X,U){let G=_1(D,10)+10;return o([F$({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":g$})].join(""),{"shape-rendering":"crispEdges"})}function H4($,v,D,X,U="start"){return p$(D,{x:$,y:v,fill:X,"font-size":10,"font-family":g$,"text-anchor":U})}function Y$($,v,D){return Math.min(D,Math.max(v,$))}var JH="price out of visible range (clamped)";function X7($,v){if(v.type==="zone")return jg($,v);if(v.type==="rectangle")return Ag($,v);return O$(v,`Unsupported area shape: ${v.type}`)}function jg($,v){let D=QH($,v,"zone");if(D.kind==="error")return D.fragments;let X=o$(v,"#3b82f6"),U=Y$(D.top+12,$.plotTop+12,$.plotBottom-6),G=(D.left+D.right)/2;return $4(v,{underlaySvg:o(F$({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([I$({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}),I$({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?H4(D.left+4,U,v.label,X):"",z$($,G,D.highPrice,X),z$($,G,D.lowPrice,X)].join(""),{"shape-rendering":"crispEdges"})},D.clamped?JH:void 0)}function Ag($,v){let D=QH($,v,"rectangle");if(D.kind==="error")return D.fragments;let X=o$(v,"#f59e0b"),U=Y$(D.top+12,$.plotTop+12,$.plotBottom-6),G=(D.left+D.right)/2;return $4(v,{underlaySvg:o(F$({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([F$({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?H4(D.left+4,U,v.label,X):"",z$($,G,D.highPrice,X),z$($,G,D.lowPrice,X)].join(""),{"shape-rendering":"crispEdges"})},D.clamped?JH:void 0)}function QH($,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"&&!GH(v)?$.plotLeft:Y$($.resolveEndpointX(v,"start",24),$.plotLeft,$.plotRight),W=D==="zone"&&!GH(v)?$.plotRight:Y$($.resolveEndpointX(v,"end",4),$.plotLeft,$.plotRight),z=Math.min(G.y,J.y),Y=Math.max(G.y,J.y);return{kind:"ok",left:Math.min(Q,W),right:Math.max(Q,W),top:z,bottom:Y,highPrice:X,lowPrice:U,clamped:G.clamped||J.clamped}}function GH($){return $.time1!==void 0||$.time2!==void 0||$.barsBack1!==void 0||$.barsBack2!==void 0}function fX($,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 WH($,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:fX(D,$,v)}}}function zH($,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:fX(D,$,v)}}}function YH($,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:fX(D,$,v)},end:{x:X,y:fX(X,$,v)}}}function G7($,v){return{x:($.x+v.x)/2,y:($.y+v.y)/2}}var y1="price out of visible range (clamped)";function J4($,v){switch(v.type){case"horizontal_line":return wg($,v);case"horizontal_ray":return Mg($,v);case"vertical_line":return Pg($,v);case"cross_line":return bg($,v);case"trendline":return qg($,v);case"ray":case"right_ray":return Sg($,v);case"left_ray":return kg($,v);case"extended_line":return Eg($,v);case"info_line":return Tg($,v);case"trend_angle":return Rg($,v);default:return O$(v,`Unsupported line shape: ${v.type}`)}}function wg($,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=[I$({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?H4($.plotLeft+4,Y$(U.y-4,$.plotTop+10,$.plotBottom-4),v.label,X):"",z$($,$.plotRight-12,D,X)].join("");return $4(v,{lineSvg:o(G,{"shape-rendering":"crispEdges"}),gutterTags:[{y:U.y,label:$.formatPrice(D),fill:X,height:f1}]},U.clamped?y1:void 0)}function Mg($,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=Y$(G+4,$.plotLeft+4,$.plotRight-60);return $4(v,{lineSvg:o([I$({x1:Y$(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?H4(J,Y$(U.y-4,$.plotTop+10,$.plotBottom-4),v.label,X):"",z$($,G,D,X)].join(""),{"shape-rendering":"crispEdges"})},U.clamped?y1:void 0)}function Pg($,v){let D=o$(v,"#f59e0b"),X=$.resolveEndpointX(v,"start",0),U=Y$(X,$.plotLeft,$.plotRight);return $4(v,{lineSvg:o([I$({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?H4(U+4,$.plotTop+12,v.label,D):""].join(""),{"shape-rendering":"crispEdges"})})}function bg($,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=Y$($.resolveEndpointX(v,"start",0),$.plotLeft,$.plotRight);return $4(v,{lineSvg:o([I$({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"}),I$({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?H4(G+4,Y$(U.y-4,$.plotTop+10,$.plotBottom-4),v.label,X):"",z$($,G,D,X)].join(""),{"shape-rendering":"crispEdges"})},U.clamped?y1:void 0)}function qg($,v){let D=n1($,v,"trendline");if(D.kind==="error")return D.fragments;return gg($,v,D.first,D.second,"#f59e0b","4 4")}function Sg($,v){let D=n1($,v,v.type);if(D.kind==="error")return D.fragments;let X=o$(v,"#f59e0b"),U=WH(D.first,D.second,$.plotRight);return _X($,v,U.start,U.end,X,"4 4",[z$($,D.first.x,D.price1,X),z$($,D.second.x,D.price2,X)])}function kg($,v){let D=n1($,v,"left_ray");if(D.kind==="error")return D.fragments;let X=o$(v,"#f59e0b"),U=zH(D.first,D.second,$.plotLeft);return _X($,v,U.start,U.end,X,"4 4",[z$($,D.first.x,D.price1,X),z$($,D.second.x,D.price2,X)])}function Eg($,v){let D=n1($,v,"extended_line");if(D.kind==="error")return D.fragments;let X=o$(v,"#f59e0b"),U=YH(D.first,D.second,$.plotLeft,$.plotRight,$.plotTop,$.plotBottom);return _X($,v,U.start,U.end,X,"4 4",[z$($,D.first.x,D.price1,X),z$($,D.second.x,D.price2,X)])}function Tg($,v){let D=n1($,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} · ${P0(U,G,J)}`:P0(U,G,J),W=G7(D.first,D.second);return $4(v,{lineSvg:o([I$({x1:D.first.x,y1:D.first.y,x2:D.second.x,y2:D.second.y,stroke:X,"stroke-width":1}),D7(Y$(W.x-30,$.plotLeft+2,$.plotRight-120),Y$(W.y-6,$.plotTop+12,$.plotBottom-12),Q,X,"#FFFFFF"),z$($,D.first.x,D.price1,X),z$($,D.second.x,D.price2,X)].join(""),{"shape-rendering":"crispEdges"})},D.clamped?y1:void 0)}function Rg($,v){let D=n1($,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=G7(D.first,D.second);return $4(v,{lineSvg:o([I$({x1:D.first.x,y1:D.first.y,x2:D.second.x,y2:D.second.y,stroke:X,"stroke-width":1}),D7(Y$(J.x-26,$.plotLeft+2,$.plotRight-100),Y$(J.y-6,$.plotTop+12,$.plotBottom-12),G,X,"#FFFFFF"),z$($,D.first.x,D.price1,X),z$($,D.second.x,D.price2,X)].join(""),{"shape-rendering":"crispEdges"})},D.clamped?y1:void 0)}function gg($,v,D,X,U,G){let J=o$(v,U);return _X($,v,D,X,J,G,[z$($,D.x,k$(v.price1)??0,J),z$($,X.x,k$(v.price2)??0,J)])}function _X($,v,D,X,U,G,J){let Q=Y$(X.x+4,$.plotLeft+4,$.plotRight-70),W=Y$(X.y-4,$.plotTop+12,$.plotBottom-4),z=k$(v.price1),Y=k$(v.price2),I=z!==void 0&&$.projectPrice(z).clamped||Y!==void 0&&$.projectPrice(Y).clamped;return $4(v,{lineSvg:o([I$({x1:D.x,y1:D.y,x2:X.x,y2:X.y,stroke:U,"stroke-width":1,...G?{"stroke-dasharray":G}:{}}),v.label?H4(Q,W,v.label,U):"",...J].join(""),{"shape-rendering":"crispEdges"})},I?y1:void 0)}function n1($,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:Y$($.resolveEndpointX(v,"start",50),$.plotLeft,$.plotRight),y:G.y},W={x:Y$($.resolveEndpointX(v,"end",0),$.plotLeft,$.plotRight),y:J.y};return{kind:"ok",first:Q,second:W,price1:X,price2:U,clamped:G.clamped||J.clamped}}var Cg="price out of visible range (clamped)";function IH($,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=Z6($.theme),J=Y$($.resolveEndpointX(v,"start",0),$.plotLeft,$.plotRight),Q=$.projectPrice(D),W=$.projectPrice(X),z=$.projectPrice(U),Y=Math.min(Q.y,z.y),I=Math.max(Q.y,z.y),V=Math.min(Q.y,W.y),K=Math.max(Q.y,W.y),L=Y$(Math.min(Y,V)+12,$.plotTop+12,$.plotBottom-8),N=Q.clamped||W.clamped||z.clamped;return $4(v,{positionSvg:o([F$({x:J,y:Y,width:$.plotRight-J,height:I-Y,fill:"#10b981","fill-opacity":0.12}),F$({x:J,y:V,width:$.plotRight-J,height:K-V,fill:"#ef4444","fill-opacity":0.12}),I$({x1:J,y1:Math.round(Q.y)+0.5,x2:$.plotRight,y2:Math.round(Q.y)+0.5,stroke:G.entryTag,"stroke-width":1}),I$({x1:J,y1:Math.round(W.y)+0.5,x2:$.plotRight,y2:Math.round(W.y)+0.5,stroke:"#ef4444","stroke-width":1}),I$({x1:J,y1:Math.round(z.y)+0.5,x2:$.plotRight,y2:Math.round(z.y)+0.5,stroke:"#10b981","stroke-width":1}),v.label?H4(J+4,L,v.label,G.text):"",z$($,J,D,G.entryTag),z$($,J,X,"#ef4444"),z$($,J,U,"#10b981")].join(""),{"shape-rendering":"crispEdges"}),gutterTags:[{y:Q.y,label:`Entry ${$.formatPrice(D)}`,fill:G.entryTag,height:gX},{y:W.y,label:`SL ${$.formatPrice(X)}`,fill:"#ef4444",height:gX},{y:z.y,label:`TP ${$.formatPrice(U)}`,fill:"#10b981",height:gX}]},N?Cg:void 0)}var ug={horizontal_line:J4,horizontal_ray:J4,vertical_line:J4,cross_line:J4,zone:X7,rectangle:X7,trendline:J4,ray:J4,right_ray:J4,left_ray:J4,extended_line:J4,info_line:J4,trend_angle:J4,position:IH};function VH($,v){let D=[],X=[],U=[],G=[],J=[],Q=[],W=0,z=0;for(let Y of v){let I=xg($,Y);if(D.push(I.underlaySvg),X.push(I.lineSvg),U.push(I.positionSvg),G.push(I.chromeSvg),J.push(...I.gutterTags),Q.push(I.report),I.report.ok)W+=1;else z+=1}return{underlaySvg:D.join(""),lineSvg:X.join(""),positionSvg:U.join(""),chromeSvg:G.join(""),gutterTags:J,reports:Q,drawn:W,skipped:z}}function xg($,v){let D=b0(v.type);if(!D)return O$(v,`Unknown shape type: ${String(v.type)}`);let X=ug[D];if(!X)return O$(v,`Unsupported shape type: ${D}`);let U=D===v.type?v:{...v,type:D};return X($,U)}var J7;function KH($){let v=s5($),D=fg(v.pair),X=dO(v,D),U=CX[v.theme],G=VH(X,v.shapes),J=rO(X,v.watermark),Q=`plot-clip-${yg(X)}`,W=`<defs><clipPath id="${Q}">${F$({x:X.plotLeft,y:X.plotTop,width:X.plotWidth,height:X.plotHeight})}</clipPath></defs>`,z={"clip-path":`url(#${Q})`},Y=o(J.gridSvg,z),I=o(G.underlaySvg,z),V=o(pO(X),z),K=o(G.lineSvg,z),L=o(G.positionSvg,z),N=tO(X,[...G.gutterTags,J.lastPriceTag]);return{svg:lO(X.width,X.height,[F$({x:0,y:0,width:X.width,height:X.height,fill:U.background}),W,Y,I,V,K,L,J.axesSvg,G.chromeSvg,J.lastPriceSvg,N,J.headerSvg,J.watermarkSvg,ig()].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 Q7($){let v=KH($),D=s5($);return{...v,png:aO(v.svg,v.width,D.scale,D.fontFiles)}}function fg($){return _g().resolve($)}function _g(){if(J7===void 0)J7=new M0([...TX]);return J7}function ig(){return`<style>text{font-family:${g$};white-space:pre}</style>`}function yg($){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 LH=120,W7=20,z7=200,ng=4800;function lg($,v,D){return Math.max(v,Math.min(D,$))}var hg="Render an annotated candlestick chart image (PNG) for a pair + timeframe and optional market-data sourceId. 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*.",mg="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`, `color` (hex), and `affectsScale` (false keeps a distant contextual level labelled without compressing the active setup).",iX=[E({name:"render_chart",description:hg,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)"},sourceId:{type:"string",pattern:"^[a-z][a-z0-9-]{0,62}$",description:"Market-data source from get_market_config, e.g. mt5-primary. Omit for Twelve Data."},shapes:{type:"array",description:mg,items:{type:"object"}},bars:{type:"integer",minimum:W7,maximum:z7,description:`Most-recent candles to show (${W7}-${z7}, default ${LH})`},offset:{type:"integer",minimum:0,maximum:ng,description:"Candle page offset: 0 is the latest page; larger offsets walk backward through history. Pair with bars to frame a historical setup."},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 R(v);let D=lg($.bars??LH,W7,z7),{candles:X}=await qX(v.trpc,{pair:$.pair,timeframe:$.timeframe,limit:D,...$.offset===void 0?{}:{offset:$.offset},...$.sourceId?{sourceId:$.sourceId}:{}});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}=XH($.shapes??[]),J=Q7({pair:$.pair,timeframe:$.timeframe,candles:X,shapes:U,bars:D,...$.theme?{theme:$.theme}:{},...$.width?{width:$.width}:{},...$.height?{height:$.height}:{}}),Q=J.shapes.filter((I)=>!I.ok),W=[...G.map((I)=>`shape ${I.index}: ${I.reason}`),...Q.map((I)=>`${I.type}: ${I.reason??"undrawable"}`)],z=W.length>0?` (${W.length} skipped)
|
|
107
107
|
Skipped: ${W.join("; ")}`:"",Y=`Rendered ${$.pair} ${$.timeframe} — ${X.length} candles, drew ${J.drawn} shape${J.drawn===1?"":"s"}. Price range ${J.priceRange.min}–${J.priceRange.max}.${z}`;return{content:[{type:"image",data:Buffer.from(J.png).toString("base64"),mimeType:"image/png"},{type:"text",text:Y}]}}})];async function yX($){try{return{ok:!0,value:await $}}catch(v){return{ok:!1,error:v instanceof Error?v.message:String(v)}}}function cg($){return/unauthor|forbidden|401|403|sign[ -]?in|token|credential/i.test($)}var dg="The Aether Wealth backend is unreachable right now. Try again shortly.",rg=_5.flatMap(($)=>$.dashboardOnly.map((v)=>`${$.name}: ${v}`)),nX=[E({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 R(v);let D=await Promise.all([yX(v.trpc.trading.accounts.list.query()),yX(v.trpc.trading.trades.list.query({status:"OPEN",limit:200})),yX(v.trpc.trading.analytics.stats.query({})),yX(v.trpc.alerts.list.query({}))]);if(D.every((W)=>!W.ok)){let W=D.every((z)=>!z.ok&&cg(z.error));throw Error(W?l5:dg)}let[X,U,G,J]=D,Q=(W)=>W.ok?W.value:{error:W.error};return{accounts:Q(X),openTrades:Q(U),stats:Q(G),alerts:Q(J),dashboard:{url:f4,dashboardOnly:rg,note:`These actions are not available over MCP. When the user needs one, suggest they open the dashboard at ${f4}.`}}}})];function pg(){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 u6($,v,D){let{url:X,secret:U}=pg(),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(z){throw Error(`Could not reach the Aether Wealth app at ${G}. Is the dashboard running?`,{cause:z})}if(!J.ok)throw Error(`Live-chart push rejected (HTTP ${J.status}).`);let Q=await J.json().catch(()=>({})),W=typeof Q.delivered==="number"?Q.delivered:0;return{ok:!0,tool:v,delivered:W,message:W>0?`Dispatched to ${W} open chart tab(s).`:"Dispatched, but no open Aether Wealth chart tab is listening — open the dashboard in your browser, then retry."}}function Y7($){let v=BH($),D=og(v?.approvalMethod);return{content:[{type:"text",text:[`Pending broker intent created with approval method: ${v?.approvalMethod??"unknown"}.`,D,"Use trade_intent_status to check whether it was approved, executed, expired, cancelled, or failed.","",JSON.stringify($,null,2)].join(`
|
|
108
|
-
`)}]}}function tg($){return BH($)?.approvalMethod==="push"}function og($){if($==="email_otp")return"Ask the user for the emailed confirmation code, then call execute_trade with this intentId and code. Never guess or fabricate the code.";if($==="app_otp")return"Ask the user for the current authenticator app code, then call execute_trade with this intentId and code. Never guess or fabricate the code.";if($==="push")return"Do NOT ask the user for a code. This action executes only when the user taps Approve in the Aether Wealth app.";if($==="auto")return"No code is required. Call execute_trade with this intentId to execute the action.";return"Inspect the returned proposal before taking the next step."}function BH($){if(typeof $!=="object"||$===null)return null;let v=$.proposal;if(typeof v!=="object"||v===null)return null;return v}var lX=[E({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 R(v),mZ(v.trpc,$)}}),E({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 R(v),cZ(v.trpc,$)}}),E({name:"connect_broker",description:"Attach a live execution provider to a journal account. For MetaApi, provide its account id and region. For `mt5_executor`, provide the expected MT5 login as `providerAccountRef` and its `baseUrl` under `*.aetherwealth.ai`. `providerToken` is sensitive — never expose or log it.",inputSchema:{type:"object",properties:{accountId:{type:"string"},provider:{type:"string",enum:["metaapi","mt5_executor"],description:"Defaults to 'metaapi' when omitted."},region:{type:"string",enum:["new-york","london"]},baseUrl:{type:"string",description:"Required for `mt5_executor`; the executor's HTTPS origin under `*.aetherwealth.ai`."},providerAccountRef:{type:"string",description:"The MetaApi account id, or the expected numeric MT5 login for `mt5_executor`."},providerToken:{type:"string",description:"The provider token. For `mt5_executor`, use its service bearer token. 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","providerAccountRef","providerToken"],additionalProperties:!1},handler:async($,v)=>{return await R(v),yZ(v.trpc,$)}}),E({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 R(v),nZ(v.trpc,$)}}),E({name:"disconnect_broker",description:"Disarm broker trading for a connected account instantly. Cancels pending intents, keeps executed history, and does not require confirmation because it is the kill switch. Reconnect later with connect_broker. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"}},required:["accountId"],additionalProperties:!1},handler:async($,v)=>{return await R(v),lZ(v.trpc,$)}}),E({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 R(v),hZ(v.trpc,$)}}),E({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 R(v);let D=await dZ(v.trpc,$);return tg(D)?Y7(D):D}}),E({name:"execute_trade",description:"Place a previously proposed trade. Email/app modes require the user-provided code; auto mode requires no per-trade code. Push intents cannot be executed by the agent. 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 R(v),rZ(v.trpc,$)}}),E({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 R(v),tZ(v.trpc,$)}}),E({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 R(v),pZ(v.trpc,$)}}),E({name:"close_position",description:"Propose closing an open broker position fully, or partially by passing `volume` when the provider supports it. MT5 executor Phase 1 supports full closes only. This does not close immediately; it returns a pending confirmation intent. For email_otp/app_otp ask the user for the code and call execute_trade. For push, do not ask for a code — the user taps Approve in the app.",inputSchema:{type:"object",properties:{accountId:{type:"string"},positionId:{type:"string"},volume:{type:"number"}},required:["accountId","positionId"],additionalProperties:!1},handler:async($,v)=>{return await R(v),Y7(await oZ(v.trpc,$))}}),E({name:"modify_position",description:"Propose adjusting 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. This returns a pending confirmation intent; for email_otp/app_otp ask for the code and call execute_trade, while push is approved in the app.",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 R(v),Y7(await aZ(v.trpc,$))}})],hX=[E({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 R(v);let D=await v.session.getUserId();return u6(D,"draw_chart_shape",{shapes:[{type:"position",direction:$.direction,entry:$.entry,stop:$.stopLoss,...$.takeProfit===void 0?{}:{target:$.takeProfit},...$.label===void 0?{}:{label:$.label}}]})}})];var ag=["news","press_release"];function eg($){return{pair:$.pair,...$.limit===void 0?{}:{limit:$.limit}}}function sg($){return{currency:$.currency,...$.limit===void 0?{}:{limit:$.limit}}}function $C($){return{currency:$.currency,...$.indicator===void 0?{}:{indicator:$.indicator},...$.limit===void 0?{}:{limit:$.limit}}}function vC($){return{...$.limit===void 0?{}:{limit:$.limit}}}function UC($){return{currency:$.currency,...$.documentType===void 0?{}:{documentType:$.documentType},...$.limit===void 0?{}:{limit:$.limit}}}var mX={type:"integer",minimum:1,maximum:250,description:"Max rows to return (1-250, default 120)."},cX=[E({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:mX},required:["pair"],additionalProperties:!1},handler:async($,v)=>{return await R(v),v.trpc.fxMacroData.pairContext.query(eg($))}}),E({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:mX},required:["currency"],additionalProperties:!1},handler:async($,v)=>{return await R(v),v.trpc.fxMacroData.currencyContext.query(sg($))}}),E({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:mX},required:["currency"],additionalProperties:!1},handler:async($,v)=>{return await R(v),v.trpc.fxMacroData.predictions.query($C($))}}),E({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:mX},additionalProperties:!1},handler:async($,v)=>{return await R(v),v.trpc.fxMacroData.riskSentiment.query(vC($))}}),E({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:[...ag],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 R(v),v.trpc.fxMacroData.documents.query(UC($))}}),E({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 R(v),v.trpc.fxMacroData.syncState.query()}})];var DC="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",dX=[E({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 — ${DC}. 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 R(v),eZ(v.trpc,$)}})];var XC=["horizontal_line","horizontal_ray","vertical_line","cross_line","zone","rectangle","trendline","ray","right_ray","left_ray","extended_line","info_line","trend_angle","position"],rX=[E({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 R(v);let D=await v.session.getUserId();return u6(D,"select_pair",{pair:$.pair})}}),E({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 R(v);let D=await v.session.getUserId();return u6(D,"change_timeframe",{timeframe:$.timeframe})}}),E({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:[...XC]},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 R(v);let D=await v.session.getUserId();return u6(D,"draw_chart_shape",{shapes:$.shapes})}}),E({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 R(v);let D=await v.session.getUserId();return u6(D,"remove_chart_drawings",{target:$.target??"all"})}})];var pX=[E({name:"get_candles",description:"Get OHLC candles for a pair + timeframe and optional sourceId. Omit sourceId for Twelve Data. Non-default sources return only native timeframes advertised by get_market_config; they are never re-aggregated. Returns up to 200 bars plus nextCursor. Pass nextCursor back as cursor until it is null. The legacy offset 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."},sourceId:{type:"string",pattern:"^[a-z][a-z0-9-]{0,62}$",description:"Market-data source from get_market_config, e.g. mt5-primary. Omit for Twelve Data."},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 R(v),qX(v.trpc,$)}}),E({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 R(v),$O(v.trpc,$)}}),E({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 R(v),vO(v.trpc,$)}}),E({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:[...sZ],description:"Lookback window (default 12m)"}},required:["currency","indicator"],additionalProperties:!1},handler:async($,v)=>{return await R(v),UO(v.trpc,$)}}),E({name:"get_market_config",description:"Get supported instruments, timeframes, and per-source candle/live capabilities. Use marketDataSources before selecting a non-default sourceId.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async($,v)=>{return await R(v),DO(v.trpc)}})];var NH={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"}}},GC={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"}}},tX=[E({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:BO,limit:LO},additionalProperties:!1},handler:async($,v)=>{return await R(v),JO(v.trpc,$)}}),E({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 R(v),QO(v.trpc,$)}}),E({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 R(v),SZ(v.trpc)}}),E({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 R(v),kZ(v.trpc,$)}}),E({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 R(v),XO(v.trpc,$)}}),E({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"},...NH},required:["accountId","pair","direction","entryPrice","entryTime"],additionalProperties:!1},handler:async($,v)=>{return await R(v),WO(v.trpc,$)}}),E({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"},...NH},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await R(v),zO(v.trpc,$)}}),E({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 R(v),YO(v.trpc,$)}}),E({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 R(v),IO(v.trpc,$)}}),E({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 R(v),VO(v.trpc,$)}}),E({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:GC,required:["pair","direction","entryPrice","lotSize","entryTime"],additionalProperties:!1}}},required:["accountId","trades"],additionalProperties:!1},handler:async($,v)=>{return await R(v),KO(v.trpc,$)}})];function I7($={}){let v=$.includeAuthTools??!0,D=$.includeLiveChartTools??!1,X=$.includeRenderChartTools??!Y4;return[...v?EX:[],...nX,...tX,...lX,...kX,...pX,...cX,...dX,...X?iX:[],...D?[...rX,...hX]:[]]}var JC="aether-wealth-mcp",QC="0.2.7";function ZH($,v){let D=new A0({name:JC,version:QC},{capabilities:{tools:{listChanged:!1},resources:{listChanged:!1,subscribe:!1},prompts:{listChanged:!1}}});return WC(D,$,v??$.toolContext),D}function WC($,v,D){let X=!1,U=(J)=>{let Q=v.clientGate?.nudge;if(Q&&!X)return X=!0,`${Q}
|
|
108
|
+
`)}]}}function tg($){return BH($)?.approvalMethod==="push"}function og($){if($==="email_otp")return"Ask the user for the emailed confirmation code, then call execute_trade with this intentId and code. Never guess or fabricate the code.";if($==="app_otp")return"Ask the user for the current authenticator app code, then call execute_trade with this intentId and code. Never guess or fabricate the code.";if($==="push")return"Do NOT ask the user for a code. This action executes only when the user taps Approve in the Aether Wealth app.";if($==="auto")return"No code is required. Call execute_trade with this intentId to execute the action.";return"Inspect the returned proposal before taking the next step."}function BH($){if(typeof $!=="object"||$===null)return null;let v=$.proposal;if(typeof v!=="object"||v===null)return null;return v}var lX=[E({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 R(v),mZ(v.trpc,$)}}),E({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 R(v),cZ(v.trpc,$)}}),E({name:"connect_broker",description:"Attach a live execution provider to a journal account. For MetaApi, provide its account id and region. For `mt5_executor`, provide the expected MT5 login as `providerAccountRef` and its `baseUrl` under `*.aetherwealth.ai`. `providerToken` is sensitive — never expose or log it.",inputSchema:{type:"object",properties:{accountId:{type:"string"},provider:{type:"string",enum:["metaapi","mt5_executor"],description:"Defaults to 'metaapi' when omitted."},region:{type:"string",enum:["new-york","london"]},baseUrl:{type:"string",description:"Required for `mt5_executor`; the executor's HTTPS origin under `*.aetherwealth.ai`."},providerAccountRef:{type:"string",description:"The MetaApi account id, or the expected numeric MT5 login for `mt5_executor`."},providerToken:{type:"string",description:"The provider token. For `mt5_executor`, use its service bearer token. 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","providerAccountRef","providerToken"],additionalProperties:!1},handler:async($,v)=>{return await R(v),yZ(v.trpc,$)}}),E({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 R(v),nZ(v.trpc,$)}}),E({name:"disconnect_broker",description:"Disarm broker trading for a connected account instantly. Cancels pending intents, keeps executed history, and does not require confirmation because it is the kill switch. Reconnect later with connect_broker. Requires sign-in.",inputSchema:{type:"object",properties:{accountId:{type:"string"}},required:["accountId"],additionalProperties:!1},handler:async($,v)=>{return await R(v),lZ(v.trpc,$)}}),E({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 R(v),hZ(v.trpc,$)}}),E({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 R(v);let D=await dZ(v.trpc,$);return tg(D)?Y7(D):D}}),E({name:"execute_trade",description:"Place a previously proposed trade. Email/app modes require the user-provided code; auto mode requires no per-trade code. Push intents cannot be executed by the agent. 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 R(v),rZ(v.trpc,$)}}),E({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 R(v),tZ(v.trpc,$)}}),E({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 R(v),pZ(v.trpc,$)}}),E({name:"close_position",description:"Propose closing an open broker position fully, or partially by passing `volume`. This does not close immediately; it returns a pending confirmation intent. For email_otp/app_otp ask the user for the code and call execute_trade. For push, do not ask for a code — the user taps Approve in the app.",inputSchema:{type:"object",properties:{accountId:{type:"string"},positionId:{type:"string"},volume:{type:"number"}},required:["accountId","positionId"],additionalProperties:!1},handler:async($,v)=>{return await R(v),Y7(await oZ(v.trpc,$))}}),E({name:"modify_position",description:"Propose adjusting 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. This returns a pending confirmation intent; for email_otp/app_otp ask for the code and call execute_trade, while push is approved in the app.",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 R(v),Y7(await aZ(v.trpc,$))}})],hX=[E({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 R(v);let D=await v.session.getUserId();return u6(D,"draw_chart_shape",{shapes:[{type:"position",direction:$.direction,entry:$.entry,stop:$.stopLoss,...$.takeProfit===void 0?{}:{target:$.takeProfit},...$.label===void 0?{}:{label:$.label}}]})}})];var ag=["news","press_release"];function eg($){return{pair:$.pair,...$.limit===void 0?{}:{limit:$.limit}}}function sg($){return{currency:$.currency,...$.limit===void 0?{}:{limit:$.limit}}}function $C($){return{currency:$.currency,...$.indicator===void 0?{}:{indicator:$.indicator},...$.limit===void 0?{}:{limit:$.limit}}}function vC($){return{...$.limit===void 0?{}:{limit:$.limit}}}function UC($){return{currency:$.currency,...$.documentType===void 0?{}:{documentType:$.documentType},...$.limit===void 0?{}:{limit:$.limit}}}var mX={type:"integer",minimum:1,maximum:250,description:"Max rows to return (1-250, default 120)."},cX=[E({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:mX},required:["pair"],additionalProperties:!1},handler:async($,v)=>{return await R(v),v.trpc.fxMacroData.pairContext.query(eg($))}}),E({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:mX},required:["currency"],additionalProperties:!1},handler:async($,v)=>{return await R(v),v.trpc.fxMacroData.currencyContext.query(sg($))}}),E({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:mX},required:["currency"],additionalProperties:!1},handler:async($,v)=>{return await R(v),v.trpc.fxMacroData.predictions.query($C($))}}),E({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:mX},additionalProperties:!1},handler:async($,v)=>{return await R(v),v.trpc.fxMacroData.riskSentiment.query(vC($))}}),E({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:[...ag],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 R(v),v.trpc.fxMacroData.documents.query(UC($))}}),E({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 R(v),v.trpc.fxMacroData.syncState.query()}})];var DC="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",dX=[E({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 — ${DC}. 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 R(v),eZ(v.trpc,$)}})];var XC=["horizontal_line","horizontal_ray","vertical_line","cross_line","zone","rectangle","trendline","ray","right_ray","left_ray","extended_line","info_line","trend_angle","position"],rX=[E({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 R(v);let D=await v.session.getUserId();return u6(D,"select_pair",{pair:$.pair})}}),E({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 R(v);let D=await v.session.getUserId();return u6(D,"change_timeframe",{timeframe:$.timeframe})}}),E({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:[...XC]},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 R(v);let D=await v.session.getUserId();return u6(D,"draw_chart_shape",{shapes:$.shapes})}}),E({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 R(v);let D=await v.session.getUserId();return u6(D,"remove_chart_drawings",{target:$.target??"all"})}})];var pX=[E({name:"get_candles",description:"Get OHLC candles for a pair + timeframe and optional sourceId. Omit sourceId for Twelve Data. Non-default sources return only native timeframes advertised by get_market_config; they are never re-aggregated. Returns up to 200 bars plus nextCursor. Pass nextCursor back as cursor until it is null. The legacy offset 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."},sourceId:{type:"string",pattern:"^[a-z][a-z0-9-]{0,62}$",description:"Market-data source from get_market_config, e.g. mt5-primary. Omit for Twelve Data."},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 R(v),qX(v.trpc,$)}}),E({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 R(v),$O(v.trpc,$)}}),E({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 R(v),vO(v.trpc,$)}}),E({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:[...sZ],description:"Lookback window (default 12m)"}},required:["currency","indicator"],additionalProperties:!1},handler:async($,v)=>{return await R(v),UO(v.trpc,$)}}),E({name:"get_market_config",description:"Get supported instruments, timeframes, and per-source candle/live capabilities. Use marketDataSources before selecting a non-default sourceId.",inputSchema:{type:"object",properties:{},additionalProperties:!1},handler:async($,v)=>{return await R(v),DO(v.trpc)}})];var NH={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"}}},GC={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"}}},tX=[E({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:BO,limit:LO},additionalProperties:!1},handler:async($,v)=>{return await R(v),JO(v.trpc,$)}}),E({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 R(v),QO(v.trpc,$)}}),E({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 R(v),SZ(v.trpc)}}),E({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 R(v),kZ(v.trpc,$)}}),E({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 R(v),XO(v.trpc,$)}}),E({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"},...NH},required:["accountId","pair","direction","entryPrice","entryTime"],additionalProperties:!1},handler:async($,v)=>{return await R(v),WO(v.trpc,$)}}),E({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"},...NH},required:["id"],additionalProperties:!1},handler:async($,v)=>{return await R(v),zO(v.trpc,$)}}),E({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 R(v),YO(v.trpc,$)}}),E({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 R(v),IO(v.trpc,$)}}),E({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 R(v),VO(v.trpc,$)}}),E({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:GC,required:["pair","direction","entryPrice","lotSize","entryTime"],additionalProperties:!1}}},required:["accountId","trades"],additionalProperties:!1},handler:async($,v)=>{return await R(v),KO(v.trpc,$)}})];function I7($={}){let v=$.includeAuthTools??!0,D=$.includeLiveChartTools??!1,X=$.includeRenderChartTools??!Y4;return[...v?EX:[],...nX,...tX,...lX,...kX,...pX,...cX,...dX,...X?iX:[],...D?[...rX,...hX]:[]]}var JC="aether-wealth-mcp",QC="0.2.9";function ZH($,v){let D=new A0({name:JC,version:QC},{capabilities:{tools:{listChanged:!1},resources:{listChanged:!1,subscribe:!1},prompts:{listChanged:!1}}});return WC(D,$,v??$.toolContext),D}function WC($,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 W=J.find((z)=>z.type==="text");if(W)return J.map((z)=>z===W?{type:"text",text:`${Q}
|
|
111
111
|
|
|
@@ -114,7 +114,7 @@ ${W.text}`}:z);return[{type:"text",text:Q},...J]};$.setRequestHandler(tv,async()
|
|
|
114
114
|
`),A1(500,{error:"internal error"})}finally{await G.close().catch(HH),await U.close().catch(HH)}}function BC($){let{servedPaths:v,bundle:D,log:X,oauth:U,bearerToken:G}=$,J=new Set([qz,...[...v].filter((W)=>W!==V7).map((W)=>`${qz}${W}`)]),Q=async(W)=>{let z=new URL(W.url),Y=NC(W,z,v,U,J);if(Y)return Y;if(U)return ZC(W,U,D,X);if(G&&!bC(W,G))return new Response("unauthorized",{status:401});return FH(W,D,void 0,X)};return U?async(W)=>uV(await Q(W)):Q}function NC($,v,D,X,U){if(v.pathname===LC&&$.method==="GET")return A1(200,{ok:!0});if(X){let G=gV($,v,X,U);if(G)return G}if(!D.has(v.pathname))return new Response("not found",{status:404});if($.method==="GET"&&!X)return A1(200,{ok:!0,transport:"streamable-http"});return null}async function ZC($,v,D,X){let U=CV($),G=new URL($.url).pathname,J=G===V7?"":G;for(let z of xV($,U)){let Y=v.rateLimiter.check(z);if(!Y.allowed)return new Response(JSON.stringify({error:"rate_limited"}),{status:429,headers:{"content-type":"application/json","retry-after":String(Y.retryAfterSeconds)}})}if(!U)return Sz(v,void 0,J);let Q;try{Q=await v.tokenVerifier.verify(U)}catch(z){return X(`[http] token verification unavailable: ${L7(z)}
|
|
115
115
|
`),A1(502,{error:"token verification unavailable"})}if(!Q.ok)return Sz(v,"invalid_token",J);let W=_V({token:U,userId:Q.userId,trpcUrl:v.trpcUrl,onUnauthorized:()=>v.tokenVerifier.invalidate(U)});return FH($,D,W,X)}function OC($,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 HC($,v,D){let X=VC((J,Q)=>{FC(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((W)=>{if(W)Q(W);else J()})})}}async function FC($,v,D){try{let X=await jC($),U=await D(X);await PC(U,v)}catch(X){if(!v.headersSent){v.statusCode=500,v.setHeader("content-type","application/json"),v.end(JSON.stringify({error:L7(X)}));return}v.end()}}async function jC($){let v=AC($),D=wC($),X=$.method??"GET",U={method:X,headers:D},G=await MC($,X);if(G)U.body=G,U.duplex="half";return new Request(v,U)}function AC($){let v=$.socket,D=$.headers["x-forwarded-proto"]??(v?.encrypted?"https":"http"),X=$.headers.host??"localhost";return new URL($.url??"/",`${D}://${X}`).toString()}function wC($){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 MC($,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 PC($,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 bC($,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)),OH(J,G),!1}return OH(U,G)}function L7($){if($ instanceof Error)return $.message;return String($)}function HH(){return}var qC="aether-wealth-mcp",SC=[33417,33418,33419],kC="/callback",EC=["trades:read","trades:write","accounts:read","alerts:read","alerts:write"],TC="aether-wealth-mcp",RC="AETHER_MCP_CREDENTIALS_FILE",l1={clientId:qC,redirectPorts:SC,redirectPath:kC,scopes:EC,keychainService:TC,credentialsFilePath:k0("aether-wealth-mcp"),forceFileEnvVar:RC};function jH($={}){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, and charts 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",...Y4?[]:[" • Charts: render_chart"]," • Broker execution: propose_trade, close_position, and modify_position create intents. Email/app modes need a user-provided code; auto mode needs no per-trade code. For push intents, do not ask for a code — use trade_intent_status to check the app approval outcome. disconnect_broker is the instant kill switch and requires no confirmation.","","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.",PX,"","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 ${f4} rather than attempting it over MCP.`].join(`
|
|
117
|
-
`)}}]}]}var AH="aether-wealth-mcp",B7="0.2.
|
|
117
|
+
`)}}]}]}var AH="aether-wealth-mcp",B7="0.2.9";function gC($){return{toolContext:$.toolContext,tools:new Map(($.tools??I7()).map((v)=>[v.name,v])),resources:new Map(($.resources??y5()).map((v)=>[v.uri,v])),prompts:new Map(($.prompts??i5()).map((v)=>[v.name,v])),...$.clientGate?{clientGate:$.clientGate}:{},log:$.log??((v)=>{process.stderr.write(v)})}}function CC($,v){let D=new A0({name:AH,version:B7},{capabilities:{tools:{listChanged:!1},resources:{listChanged:!1,subscribe:!1},prompts:{listChanged:!1}}});return uC(D,$,v??$.toolContext),D}class oX{server;bundle;constructor($){this.bundle=gC($),this.server=CC(this.bundle),this.server.oninitialized=()=>{this.bundle.log(`${AH} 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 uC($,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 W=J.find((z)=>z.type==="text");if(W)return J.map((z)=>z===W?{type:"text",text:`${Q}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aetherwealth/mcp",
|
|
3
3
|
"mcpName": "ai.aetherwealth/mcp",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.9",
|
|
5
5
|
"description": "Official Aether Wealth MCP server for journals, alerts, forex and crypto market context, and approval-governed broker actions.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|