marketmyna 0.2.0__py3-none-any.whl

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.
Files changed (344) hide show
  1. marketmyna/__init__.py +14 -0
  2. marketmyna/agent/__init__.py +8 -0
  3. marketmyna/agent/agents.py +543 -0
  4. marketmyna/agent/context.py +69 -0
  5. marketmyna/agent/dashboard.py +55 -0
  6. marketmyna/agent/orchestrator.py +153 -0
  7. marketmyna/agent/sentiment.py +150 -0
  8. marketmyna/agent/skills.py +119 -0
  9. marketmyna/ai/__init__.py +1 -0
  10. marketmyna/ai/portfolio_optimizer.py +330 -0
  11. marketmyna/analysis/__init__.py +6 -0
  12. marketmyna/analysis/fundamental.py +329 -0
  13. marketmyna/analysis/sip_optimizer.py +81 -0
  14. marketmyna/analysis/technical.py +321 -0
  15. marketmyna/api/__init__.py +1 -0
  16. marketmyna/api/app.py +209 -0
  17. marketmyna/api/deps.py +63 -0
  18. marketmyna/api/middlewares/__init__.py +0 -0
  19. marketmyna/api/middlewares/auth.py +116 -0
  20. marketmyna/api/middlewares/csrf.py +66 -0
  21. marketmyna/api/middlewares/error_handler.py +38 -0
  22. marketmyna/api/middlewares/slashes.py +27 -0
  23. marketmyna/api/v1/__init__.py +0 -0
  24. marketmyna/api/v1/endpoints/__init__.py +0 -0
  25. marketmyna/api/v1/endpoints/account.py +166 -0
  26. marketmyna/api/v1/endpoints/agent.py +114 -0
  27. marketmyna/api/v1/endpoints/bot.py +38 -0
  28. marketmyna/api/v1/endpoints/calendar.py +269 -0
  29. marketmyna/api/v1/endpoints/data_sources.py +174 -0
  30. marketmyna/api/v1/endpoints/health.py +10 -0
  31. marketmyna/api/v1/endpoints/listings.py +564 -0
  32. marketmyna/api/v1/endpoints/macro.py +163 -0
  33. marketmyna/api/v1/endpoints/portfolio.py +530 -0
  34. marketmyna/api/v1/endpoints/push.py +119 -0
  35. marketmyna/api/v1/endpoints/reports.py +49 -0
  36. marketmyna/api/v1/endpoints/scheduler.py +219 -0
  37. marketmyna/api/v1/endpoints/stocks.py +400 -0
  38. marketmyna/api/v1/endpoints/system_config.py +157 -0
  39. marketmyna/api/v1/endpoints/thesis.py +112 -0
  40. marketmyna/api/v1/endpoints/trade.py +709 -0
  41. marketmyna/api/v1/endpoints/updates.py +394 -0
  42. marketmyna/api/v1/endpoints/watchlists.py +179 -0
  43. marketmyna/api/v1/router.py +43 -0
  44. marketmyna/bot/__init__.py +14 -0
  45. marketmyna/bot/commands/__init__.py +0 -0
  46. marketmyna/bot/commands/analyze.py +40 -0
  47. marketmyna/bot/commands/ask.py +51 -0
  48. marketmyna/bot/commands/base.py +35 -0
  49. marketmyna/bot/commands/batch.py +53 -0
  50. marketmyna/bot/commands/common.py +84 -0
  51. marketmyna/bot/commands/help.py +43 -0
  52. marketmyna/bot/commands/markets.py +153 -0
  53. marketmyna/bot/commands/portfolio.py +145 -0
  54. marketmyna/bot/commands/research.py +323 -0
  55. marketmyna/bot/commands/status.py +48 -0
  56. marketmyna/bot/commands/trade.py +176 -0
  57. marketmyna/bot/dispatcher.py +95 -0
  58. marketmyna/bot/formatting.py +25 -0
  59. marketmyna/bot/models.py +27 -0
  60. marketmyna/bot/registry.py +50 -0
  61. marketmyna/bot/telegram_listener.py +227 -0
  62. marketmyna/cli/__init__.py +1 -0
  63. marketmyna/cli/scheduled_run.py +292 -0
  64. marketmyna/core/__init__.py +6 -0
  65. marketmyna/core/compliance.py +53 -0
  66. marketmyna/core/config.py +377 -0
  67. marketmyna/core/constants.py +69 -0
  68. marketmyna/core/home.py +22 -0
  69. marketmyna/core/numbers.py +28 -0
  70. marketmyna/core/secret_store.py +104 -0
  71. marketmyna/core/tenant.py +130 -0
  72. marketmyna/data/__init__.py +8 -0
  73. marketmyna/data/base.py +36 -0
  74. marketmyna/data/categories.py +272 -0
  75. marketmyna/data/china.py +360 -0
  76. marketmyna/data/crypto.py +200 -0
  77. marketmyna/data/ecb_fx.py +131 -0
  78. marketmyna/data/extra_sources.py +569 -0
  79. marketmyna/data/india.py +241 -0
  80. marketmyna/data/india_filings.py +343 -0
  81. marketmyna/data/listings.py +1314 -0
  82. marketmyna/data/mutual_funds.py +34 -0
  83. marketmyna/data/news.py +98 -0
  84. marketmyna/data/news_search.py +346 -0
  85. marketmyna/data/nse_deals.py +138 -0
  86. marketmyna/data/resilience.py +173 -0
  87. marketmyna/data/sec_facts.py +252 -0
  88. marketmyna/data/shariah.py +283 -0
  89. marketmyna/data/social/__init__.py +9 -0
  90. marketmyna/data/social/base.py +100 -0
  91. marketmyna/data/social/browser.py +92 -0
  92. marketmyna/data/social/hackernews.py +53 -0
  93. marketmyna/data/social/reddit.py +397 -0
  94. marketmyna/data/social/stocktwits.py +63 -0
  95. marketmyna/data/social/valuepickr.py +53 -0
  96. marketmyna/data/stocks.py +197 -0
  97. marketmyna/data/yahoo_price.py +48 -0
  98. marketmyna/launcher.py +71 -0
  99. marketmyna/llm/__init__.py +33 -0
  100. marketmyna/llm/backend_factory.py +51 -0
  101. marketmyna/llm/backend_registry.py +19 -0
  102. marketmyna/llm/channels.py +447 -0
  103. marketmyna/llm/json_reply.py +63 -0
  104. marketmyna/llm/litellm_backend.py +197 -0
  105. marketmyna/llm/model_catalog.py +166 -0
  106. marketmyna/llm/model_health.py +193 -0
  107. marketmyna/llm/protocol.py +111 -0
  108. marketmyna/llm/providers.py +128 -0
  109. marketmyna/llm/store.py +128 -0
  110. marketmyna/notifiers/__init__.py +35 -0
  111. marketmyna/notifiers/apprise_sender.py +43 -0
  112. marketmyna/notifiers/astrbot.py +47 -0
  113. marketmyna/notifiers/bark.py +24 -0
  114. marketmyna/notifiers/base.py +80 -0
  115. marketmyna/notifiers/dingtalk.py +54 -0
  116. marketmyna/notifiers/discord.py +39 -0
  117. marketmyna/notifiers/dispatcher.py +153 -0
  118. marketmyna/notifiers/email.py +99 -0
  119. marketmyna/notifiers/feishu.py +57 -0
  120. marketmyna/notifiers/googlechat.py +24 -0
  121. marketmyna/notifiers/gotify.py +36 -0
  122. marketmyna/notifiers/matrix.py +28 -0
  123. marketmyna/notifiers/ntfy.py +36 -0
  124. marketmyna/notifiers/pushbullet.py +24 -0
  125. marketmyna/notifiers/pushover.py +41 -0
  126. marketmyna/notifiers/pushplus.py +41 -0
  127. marketmyna/notifiers/serverchan3.py +40 -0
  128. marketmyna/notifiers/settings_schema.py +119 -0
  129. marketmyna/notifiers/signal_messenger.py +25 -0
  130. marketmyna/notifiers/slack.py +36 -0
  131. marketmyna/notifiers/teams.py +37 -0
  132. marketmyna/notifiers/telegram.py +81 -0
  133. marketmyna/notifiers/twilio.py +33 -0
  134. marketmyna/notifiers/webhook.py +44 -0
  135. marketmyna/notifiers/webpush.py +222 -0
  136. marketmyna/notifiers/wechat.py +40 -0
  137. marketmyna/notifiers/whatsapp.py +27 -0
  138. marketmyna/portfolio/__init__.py +6 -0
  139. marketmyna/portfolio/analytics.py +336 -0
  140. marketmyna/portfolio/manager.py +383 -0
  141. marketmyna/portfolio/models.py +155 -0
  142. marketmyna/portfolio/optimizers.py +88 -0
  143. marketmyna/portfolio/review.py +411 -0
  144. marketmyna/services/__init__.py +1 -0
  145. marketmyna/services/accounts.py +278 -0
  146. marketmyna/services/ai_access.py +94 -0
  147. marketmyna/services/analysis_run.py +491 -0
  148. marketmyna/services/big_trades.py +335 -0
  149. marketmyna/services/brokers/__init__.py +0 -0
  150. marketmyna/services/brokers/angel.py +271 -0
  151. marketmyna/services/brokers/finnhub.py +209 -0
  152. marketmyna/services/byok_detect.py +196 -0
  153. marketmyna/services/calendar.py +748 -0
  154. marketmyna/services/central_banks.py +202 -0
  155. marketmyna/services/commodities.py +134 -0
  156. marketmyna/services/compare.py +307 -0
  157. marketmyna/services/cot.py +148 -0
  158. marketmyna/services/country_macro.py +135 -0
  159. marketmyna/services/crude_sensitivity.py +239 -0
  160. marketmyna/services/crypto_mood.py +135 -0
  161. marketmyna/services/crypto_screens.py +226 -0
  162. marketmyna/services/data_export.py +91 -0
  163. marketmyna/services/dcf.py +220 -0
  164. marketmyna/services/dcf_model.py +194 -0
  165. marketmyna/services/delivery.py +142 -0
  166. marketmyna/services/discovery.py +146 -0
  167. marketmyna/services/dividends.py +95 -0
  168. marketmyna/services/earnings.py +305 -0
  169. marketmyna/services/econ_calendar.py +495 -0
  170. marketmyna/services/eia_stocks.py +115 -0
  171. marketmyna/services/estimates.py +109 -0
  172. marketmyna/services/etf.py +236 -0
  173. marketmyna/services/etf_rotation.py +193 -0
  174. marketmyna/services/etf_screens.py +196 -0
  175. marketmyna/services/financials.py +639 -0
  176. marketmyna/services/fund_ai.py +181 -0
  177. marketmyna/services/fund_analytics.py +371 -0
  178. marketmyna/services/fund_cost.py +147 -0
  179. marketmyna/services/fund_holdings.py +664 -0
  180. marketmyna/services/fund_peers.py +247 -0
  181. marketmyna/services/fund_rotation.py +206 -0
  182. marketmyna/services/fund_style.py +179 -0
  183. marketmyna/services/funds.py +70 -0
  184. marketmyna/services/hot_stocks.py +358 -0
  185. marketmyna/services/india_flows.py +263 -0
  186. marketmyna/services/india_rates.py +258 -0
  187. marketmyna/services/investor_lenses.py +271 -0
  188. marketmyna/services/leadership.py +165 -0
  189. marketmyna/services/live_market.py +497 -0
  190. marketmyna/services/live_quotes.py +295 -0
  191. marketmyna/services/macro.py +182 -0
  192. marketmyna/services/market_calendar.py +399 -0
  193. marketmyna/services/market_mood.py +168 -0
  194. marketmyna/services/market_valuation.py +231 -0
  195. marketmyna/services/mf_holdings.py +199 -0
  196. marketmyna/services/mf_insights.py +132 -0
  197. marketmyna/services/mf_lumpsum.py +587 -0
  198. marketmyna/services/mf_portfolio_ai.py +195 -0
  199. marketmyna/services/nse_events.py +98 -0
  200. marketmyna/services/overview.py +366 -0
  201. marketmyna/services/ownership.py +143 -0
  202. marketmyna/services/quality_scores.py +199 -0
  203. marketmyna/services/rates.py +335 -0
  204. marketmyna/services/reconcile.py +343 -0
  205. marketmyna/services/report.py +584 -0
  206. marketmyna/services/report_i18n.py +678 -0
  207. marketmyna/services/rotation.py +224 -0
  208. marketmyna/services/runtime_scheduler.py +548 -0
  209. marketmyna/services/schedule_config.py +251 -0
  210. marketmyna/services/schedule_time.py +39 -0
  211. marketmyna/services/screens.py +398 -0
  212. marketmyna/services/sec_mdna.py +173 -0
  213. marketmyna/services/shariah.py +246 -0
  214. marketmyna/services/sip.py +148 -0
  215. marketmyna/services/sip_days.py +362 -0
  216. marketmyna/services/smart_file.py +595 -0
  217. marketmyna/services/smart_pdf.py +425 -0
  218. marketmyna/services/smart_report.py +370 -0
  219. marketmyna/services/social_sentiment.py +511 -0
  220. marketmyna/services/thesis.py +328 -0
  221. marketmyna/services/translate.py +146 -0
  222. marketmyna/services/valuation.py +173 -0
  223. marketmyna/services/worker_pool.py +149 -0
  224. marketmyna/services/world_markets.py +208 -0
  225. marketmyna/storage.py +722 -0
  226. marketmyna/strategies/README.md +51 -0
  227. marketmyna/strategies/bottom_volume.yaml +49 -0
  228. marketmyna/strategies/box_oscillation.yaml +69 -0
  229. marketmyna/strategies/bull_trend.yaml +49 -0
  230. marketmyna/strategies/chan_theory.yaml +58 -0
  231. marketmyna/strategies/dragon_head.yaml +44 -0
  232. marketmyna/strategies/emotion_cycle.yaml +79 -0
  233. marketmyna/strategies/event_driven.yaml +54 -0
  234. marketmyna/strategies/expectation_repricing.yaml +54 -0
  235. marketmyna/strategies/growth_quality.yaml +54 -0
  236. marketmyna/strategies/hot_theme.yaml +54 -0
  237. marketmyna/strategies/ma_golden_cross.yaml +46 -0
  238. marketmyna/strategies/one_yang_three_yin.yaml +37 -0
  239. marketmyna/strategies/shrink_pullback.yaml +46 -0
  240. marketmyna/strategies/volume_breakout.yaml +47 -0
  241. marketmyna/strategies/wave_theory.yaml +64 -0
  242. marketmyna/trading/__init__.py +2 -0
  243. marketmyna/trading/alerts.py +356 -0
  244. marketmyna/trading/backtest.py +317 -0
  245. marketmyna/trading/charges.py +82 -0
  246. marketmyna/trading/chart.py +197 -0
  247. marketmyna/trading/indicators.py +303 -0
  248. marketmyna/trading/journal.py +74 -0
  249. marketmyna/trading/knn.py +164 -0
  250. marketmyna/trading/lots.py +109 -0
  251. marketmyna/trading/market_hours.py +66 -0
  252. marketmyna/trading/options.py +554 -0
  253. marketmyna/trading/pairs.py +94 -0
  254. marketmyna/trading/risk.py +170 -0
  255. marketmyna/trading/scanner.py +500 -0
  256. marketmyna/trading/volatility.py +163 -0
  257. marketmyna/utils/__init__.py +1 -0
  258. marketmyna/utils/deadline.py +36 -0
  259. marketmyna/utils/log_redact.py +52 -0
  260. marketmyna/utils/yahoo_gate.py +183 -0
  261. marketmyna/utils/yf_lock.py +12 -0
  262. marketmyna/web/apple-touch-icon.png +0 -0
  263. marketmyna/web/assets/Account-CA9NFDKO.js +1 -0
  264. marketmyna/web/assets/Analyze-uM0srB_U.js +7 -0
  265. marketmyna/web/assets/AreaChart-2i67V6Jf.js +1 -0
  266. marketmyna/web/assets/BarChart-_yngarVl.js +3 -0
  267. marketmyna/web/assets/Bot-E4gpf1qZ.js +1 -0
  268. marketmyna/web/assets/CandleChart-CioqTqMV.js +1 -0
  269. marketmyna/web/assets/Compare-D6_2CPl4.js +1 -0
  270. marketmyna/web/assets/ExportMenu-DaZ1xVmW.js +1 -0
  271. marketmyna/web/assets/LineChart-BaOkD1Ta.js +57 -0
  272. marketmyna/web/assets/Markets-BMw_M1sJ.js +1 -0
  273. marketmyna/web/assets/Portfolio-DQEdHVc2.js +1 -0
  274. marketmyna/web/assets/ReportView-BzhdcqSh.js +1 -0
  275. marketmyna/web/assets/Scheduler-I9PDKxTd.js +1 -0
  276. marketmyna/web/assets/Settings-DpXfHolW.js +3 -0
  277. marketmyna/web/assets/SipDays-C9q3bNSx.js +1 -0
  278. marketmyna/web/assets/SymbolSearch-CBOVPEk1.js +1 -0
  279. marketmyna/web/assets/Trade-_CM7HC4H.js +2 -0
  280. marketmyna/web/assets/TradeChart-ZjsycacC.js +1 -0
  281. marketmyna/web/assets/WatchButton-ComYW56_.js +1 -0
  282. marketmyna/web/assets/Watchlist-DAjLb0jd.js +1 -0
  283. marketmyna/web/assets/app-BP1o7WZS.js +1 -0
  284. marketmyna/web/assets/app-BkIUKdld.js +1 -0
  285. marketmyna/web/assets/app-CKeSYhEt.js +1 -0
  286. marketmyna/web/assets/app-CN1OERYX.js +1 -0
  287. marketmyna/web/assets/app-DIQllha5.js +1 -0
  288. marketmyna/web/assets/app-DeiAW0tX.js +1 -0
  289. marketmyna/web/assets/br-Cu5YU29T.svg +45 -0
  290. marketmyna/web/assets/browser-CR-ks2Fp.js +19 -0
  291. marketmyna/web/assets/browser-D5K_K_gj.js +1 -0
  292. marketmyna/web/assets/common-0wvpAVpd.js +1 -0
  293. marketmyna/web/assets/common-3ghy53Us.js +1 -0
  294. marketmyna/web/assets/common-Bib2unjX.js +1 -0
  295. marketmyna/web/assets/common-BvSJP0w_.js +1 -0
  296. marketmyna/web/assets/common-CSfyC0Sp.js +1 -0
  297. marketmyna/web/assets/common-C_t-iZPf.js +1 -0
  298. marketmyna/web/assets/compare-DMcsx70H.js +1 -0
  299. marketmyna/web/assets/es-d5m8M5h8.svg +544 -0
  300. marketmyna/web/assets/exporter-DiMg2O5d.js +3 -0
  301. marketmyna/web/assets/files-CpgiZRbN.js +1 -0
  302. marketmyna/web/assets/format-d8InM0Zw.js +9 -0
  303. marketmyna/web/assets/html2canvas-Bw0OShmD.js +5 -0
  304. marketmyna/web/assets/index-CKAnq-Or.js +12 -0
  305. marketmyna/web/assets/index-D4U8E6LH.css +2 -0
  306. marketmyna/web/assets/index.es-iBEw7jOv.js +5 -0
  307. marketmyna/web/assets/ir-cCIgaNf6.svg +219 -0
  308. marketmyna/web/assets/jspdf.es.min-C4285IdL.js +79 -0
  309. marketmyna/web/assets/jspdf.plugin.autotable-2eOJeXl-.js +2 -0
  310. marketmyna/web/assets/lightweight-charts.production-BF2noug5.js +1 -0
  311. marketmyna/web/assets/listings-BefgXpb1.js +1 -0
  312. marketmyna/web/assets/liveQuotes-CtSmCUFA.js +1 -0
  313. marketmyna/web/assets/markets-BI4AhI9W.js +1 -0
  314. marketmyna/web/assets/markets-BUHUdYpT.js +1 -0
  315. marketmyna/web/assets/markets-BqvN1Bvf.js +1 -0
  316. marketmyna/web/assets/markets-DPO40TTe.js +1 -0
  317. marketmyna/web/assets/markets-bsiPo-Tk.js +1 -0
  318. marketmyna/web/assets/markets-ff1e792u.js +1 -0
  319. marketmyna/web/assets/montecarlo-BsNlH2qe.js +1 -0
  320. marketmyna/web/assets/options-BYAZnwzW.js +1 -0
  321. marketmyna/web/assets/preload-helper-BLdHbfdN.js +1 -0
  322. marketmyna/web/assets/purify.es-Dqk5qvad.js +3 -0
  323. marketmyna/web/assets/rolldown-runtime-XKyaHtl9.js +1 -0
  324. marketmyna/web/assets/sa-Dh79zbT9.svg +25 -0
  325. marketmyna/web/assets/toast-DDradTZw.js +1 -0
  326. marketmyna/web/assets/trade-fndw1Ql3.js +1 -0
  327. marketmyna/web/assets/ui-gsFb8B2m.js +1 -0
  328. marketmyna/web/assets/watchlists-B6YqwUIk.js +1 -0
  329. marketmyna/web/brand/logo-mark.webp +0 -0
  330. marketmyna/web/favicon.png +0 -0
  331. marketmyna/web/icon-192.png +0 -0
  332. marketmyna/web/icon-512.png +0 -0
  333. marketmyna/web/index.html +34 -0
  334. marketmyna/web/manifest.webmanifest +28 -0
  335. marketmyna/web/robots.txt +2 -0
  336. marketmyna/web/sw.js +40 -0
  337. marketmyna/web/theme-init.js +37 -0
  338. marketmyna-0.2.0.dist-info/METADATA +345 -0
  339. marketmyna-0.2.0.dist-info/RECORD +344 -0
  340. marketmyna-0.2.0.dist-info/WHEEL +5 -0
  341. marketmyna-0.2.0.dist-info/entry_points.txt +2 -0
  342. marketmyna-0.2.0.dist-info/licenses/LICENSE +202 -0
  343. marketmyna-0.2.0.dist-info/licenses/NOTICE +22 -0
  344. marketmyna-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1 @@
1
+ import{r as e}from"./rolldown-runtime-XKyaHtl9.js";import{b as t,n,p as r}from"./format-d8InM0Zw.js";import{D as i,O as a,b as o,f as s,i as c,l,o as u,p as d,r as f,y as p}from"./ui-gsFb8B2m.js";var m=e(t(),1);async function h(e){return(await a.post(`/bot/command`,{text:e,platform:`http`,chat_id:`http`})).data}async function g(){return(await a.get(`/bot/commands`)).data}var _=r(),v=0;function y(e,t){let n=t.toLowerCase();if(!n)return e;let r=e.filter(e=>e.name.startsWith(n)||e.aliases.some(e=>e.startsWith(n))),i=e.filter(e=>!r.includes(e)&&`${e.description} ${e.group}`.toLowerCase().includes(n));return[...r,...i]}function b(e,t){let n=t.trim().split(/\s+/)[0]?.replace(/^\//,``).toLowerCase();if(n&&t.includes(` `))return e.find(e=>e.name===n||e.aliases.includes(n))}function x(){let[e,t]=(0,m.useState)([]),[r,a]=(0,m.useState)(``),[x,S]=(0,m.useState)(!1),[C,w]=(0,m.useState)([]),[T,E]=(0,m.useState)(null),[D,O]=(0,m.useState)(null),[k,A]=(0,m.useState)(null),[j,M]=(0,m.useState)(0),[N,P]=(0,m.useState)(!1),F=(0,m.useRef)(null),I=(0,m.useRef)(null),L=(0,m.useRef)(null);(0,m.useEffect)(()=>{g().then(O).catch(e=>A(n(e)))},[]),(0,m.useEffect)(()=>{F.current?.scrollTo({top:F.current.scrollHeight,behavior:`smooth`})},[e,x]);let R=/^\/\S*$/.test(r)?r.slice(1):null,z=(0,m.useMemo)(()=>D&&R!=null&&!N?y(D,R):[],[D,R,N]),B=z.length>0,V=b(D??[],r);(0,m.useEffect)(()=>M(0),[R]),(0,m.useEffect)(()=>{L.current?.querySelector(`[data-index="${j}"]`)?.scrollIntoView({block:`nearest`})},[j]);let H=(0,m.useMemo)(()=>{let e=new Map;for(let t of D??[])e.set(t.group,[...e.get(t.group)??[],t]);return[...e.entries()]},[D]);function U(e){t(t=>[...t,{...e,id:v++,at:new Date}])}async function W(e=r){let t=e.trim();if(t&&!x){U({role:`user`,text:t}),w(e=>[t,...e.filter(e=>e!==t)].slice(0,50)),E(null),a(``),S(!0);try{let e=await h(t);U({role:`bot`,text:e.text,success:e.success})}catch(e){U({role:`bot`,text:n(e),success:!1})}finally{S(!1),I.current?.focus()}}}function G(e,t){let n=e.usage.trim().includes(` `);t&&!n?W(`/${e.name}`):(a(`/${e.name}${n?` `:``}`),P(!0),I.current?.focus())}function K(e){if(B){if(e.key===`ArrowDown`||e.key===`ArrowUp`){e.preventDefault();let t=e.key===`ArrowDown`?1:-1;M(e=>(e+t+z.length)%z.length);return}if(e.key===`Tab`||e.key===`Enter`){e.preventDefault(),G(z[j],e.key===`Enter`);return}if(e.key===`Escape`){e.preventDefault(),P(!0);return}}if(e.key===`ArrowUp`&&C.length){e.preventDefault();let t=T==null?0:Math.min(T+1,C.length-1);E(t),a(C[t])}else if(e.key===`ArrowDown`&&T!=null){e.preventDefault();let t=T-1;E(t<0?null:t),a(t<0?``:C[t])}}return(0,_.jsxs)(`div`,{children:[(0,_.jsx)(d,{title:`Bot console`,description:`Every MarketMyna tool as a chat command - the same commands the Telegram bot answers.`,actions:e.length>0&&(0,_.jsx)(f,{variant:`ghost`,icon:`trash`,onClick:()=>t([]),children:`Clear`})}),(0,_.jsxs)(`div`,{className:`grid gap-6 lg:grid-cols-[minmax(0,1fr)_320px]`,children:[(0,_.jsxs)(c,{className:`flex h-[calc(100dvh-19rem-env(safe-area-inset-bottom))] min-h-[360px] flex-col md:h-[calc(100dvh-13rem)] md:min-h-[420px]`,children:[(0,_.jsxs)(`div`,{ref:F,className:`flex-1 space-y-4 overflow-y-auto p-5`,children:[e.length===0&&(0,_.jsx)(`div`,{className:`grid h-full place-items-center text-center text-xs text-muted`,children:(0,_.jsxs)(`div`,{children:[(0,_.jsx)(l,{name:`chat`,className:`mx-auto mb-2 h-5 w-5`}),`Type `,(0,_.jsx)(`kbd`,{className:`rounded bg-raised px-1 font-mono`,children:`/`}),` to see every command, or pick one from the list.`,(0,_.jsx)(`br`,{}),(0,_.jsx)(`span`,{className:`text-faint`,children:`↑ / ↓ recalls previous commands · Tab completes`})]})}),e.map(e=>(0,_.jsx)(`div`,{className:i(`flex`,e.role===`user`?`justify-end`:`justify-start`),children:(0,_.jsxs)(`div`,{className:`max-w-[85%]`,children:[(0,_.jsx)(`pre`,{className:i(`rounded-xl px-4 py-2.5 font-sans text-sm leading-relaxed whitespace-pre-wrap`,e.role===`user`?`rounded-ee-sm bg-accent font-mono text-white`:e.success===!1?`rounded-es-sm bg-down-soft text-down ring-1 ring-down/30`:`rounded-es-sm bg-raised`),children:e.text}),(0,_.jsx)(`div`,{className:i(`mt-1 text-xs text-faint`,e.role===`user`&&`text-end`),children:e.at.toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`,second:`2-digit`})})]})},e.id)),x&&(0,_.jsxs)(`div`,{className:`flex items-center gap-2 text-xs text-muted`,children:[(0,_.jsx)(o,{className:`h-3.5 w-3.5`}),` Working… AI analysis commands can take a minute.`]})]}),(0,_.jsxs)(`div`,{className:`relative border-t border-line`,children:[B&&(0,_.jsx)(`ul`,{ref:L,role:`listbox`,"aria-label":`Commands`,className:`absolute end-3 bottom-full start-3 z-20 mb-1 max-h-80 overflow-y-auto rounded-lg border border-line-strong bg-surface py-1 shadow-card`,children:z.map((e,t)=>(0,_.jsx)(`li`,{role:`option`,"aria-selected":t===j,"data-index":t,children:(0,_.jsxs)(`button`,{type:`button`,onMouseDown:e=>e.preventDefault(),onMouseEnter:()=>M(t),onClick:()=>G(e,!1),className:i(`flex w-full items-baseline gap-3 px-3 py-1.5 text-start`,t===j&&`bg-accent-soft`),children:[(0,_.jsx)(`code`,{className:`shrink-0 font-mono text-xs text-accent-fg`,children:e.usage}),(0,_.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-xs text-muted`,children:e.description}),(0,_.jsx)(`span`,{className:`hidden shrink-0 text-[11px] text-faint sm:inline`,children:e.group})]})},e.name))}),V&&!B&&(0,_.jsxs)(`div`,{className:`px-3 pt-2 text-xs text-muted`,children:[(0,_.jsx)(`code`,{className:`font-mono text-accent-fg`,children:V.usage}),(0,_.jsx)(`span`,{className:`text-faint`,children:` · e.g. `}),(0,_.jsx)(`button`,{type:`button`,className:`font-mono text-faint hover:text-fg`,onClick:()=>a(V.example),children:V.example})]}),(0,_.jsxs)(`form`,{className:`flex gap-2 p-3`,onSubmit:e=>{e.preventDefault(),W()},children:[(0,_.jsx)(s,{ref:I,value:r,onChange:e=>{a(e.target.value),E(null),P(!1)},onKeyDown:K,placeholder:`Type / for commands, e.g. /quote RELIANCE`,className:`font-mono`,role:`combobox`,"aria-expanded":B,"aria-autocomplete":`list`,autoComplete:`off`,spellCheck:!1,autoFocus:!0}),(0,_.jsx)(f,{type:`submit`,icon:`send`,loading:x,disabled:!r.trim(),children:`Send`})]})]})]}),(0,_.jsxs)(c,{className:`h-fit lg:sticky lg:top-8 lg:max-h-[calc(100vh-4rem)] lg:overflow-y-auto`,children:[(0,_.jsx)(u,{title:`Commands`,description:D?`${D.length} commands · click to fill, double-click to run`:`Click to fill, double-click to run`}),k?(0,_.jsx)(`p`,{className:`px-5 py-4 text-xs text-down`,children:k}):D?H.map(([e,t])=>(0,_.jsxs)(`div`,{children:[(0,_.jsx)(`div`,{className:`border-y border-line bg-canvas px-5 py-1.5 text-[11px] font-semibold tracking-wide text-faint uppercase`,children:e}),(0,_.jsx)(`ul`,{className:`divide-y divide-line`,children:t.map(e=>(0,_.jsx)(`li`,{children:(0,_.jsxs)(`button`,{type:`button`,title:`e.g. ${e.example}`,onClick:()=>{a(e.example),P(!0),I.current?.focus()},onDoubleClick:()=>W(e.example),className:`w-full px-5 py-2.5 text-start hover:bg-raised/40`,children:[(0,_.jsx)(`code`,{className:`block font-mono text-xs text-accent-fg`,children:e.usage}),(0,_.jsx)(`span`,{className:`mt-0.5 block text-xs text-muted`,children:e.description})]})},e.name))})]},e)):(0,_.jsxs)(`div`,{className:`space-y-2 p-5`,children:[(0,_.jsx)(p,{className:`h-10 w-full`}),(0,_.jsx)(p,{className:`h-10 w-full`}),(0,_.jsx)(p,{className:`h-10 w-full`})]})]})]})]})}export{x as default};
@@ -0,0 +1 @@
1
+ import{r as e}from"./rolldown-runtime-XKyaHtl9.js";import{b as t,o as n,p as r,s as i,t as a}from"./format-d8InM0Zw.js";import{r as o}from"./index-CKAnq-Or.js";import{c as s,i as c,n as l,o as u,s as d,t as f}from"./lightweight-charts.production-BF2noug5.js";var p=e(t(),1),m=r(),h={20:`#f5b942`,50:`#6d8cff`,200:`#c77dff`};function g(e,t){return getComputedStyle(document.documentElement).getPropertyValue(e).trim()||t}function _(e,t){let n=[],r=0;return e.forEach((i,a)=>{r+=i.close,a>=t&&(r-=e[a-t].close),a>=t-1&&n.push({time:i.time,value:r/t})}),n}function v({candles:e,averages:t,intraday:r}){let v=(0,p.useRef)(null),y=(0,p.useRef)(null),[b,x]=(0,p.useState)(null),S=o();(0,p.useEffect)(()=>{let n=v.current;if(!n||e.length===0)return;let i=g(`--color-up`,`#34d399`),a=g(`--color-down`,`#fb8a8a`),o=g(`--color-faint`,`#8c95aa`),p=g(`--color-line`,`#2a3142`),m=u(n,{autoSize:!0,layout:{background:{type:f.Solid,color:`transparent`},textColor:o,fontSize:11},grid:{vertLines:{visible:!1},horzLines:{color:p}},rightPriceScale:{borderVisible:!1},timeScale:{borderVisible:!1,timeVisible:r,secondsVisible:!1},crosshair:{mode:l.Normal}});y.current=m;let b=m.addSeries(c,{upColor:i,downColor:a,borderUpColor:i,borderDownColor:a,wickUpColor:i,wickDownColor:a});if(b.setData(e.map(e=>({time:e.time,open:e.open,high:e.high,low:e.low,close:e.close}))),e.some(e=>e.volume)){let t=m.addSeries(d,{priceFormat:{type:`volume`},priceScaleId:``});t.priceScale().applyOptions({scaleMargins:{top:.8,bottom:0}}),b.priceScale().applyOptions({scaleMargins:{top:.05,bottom:.25}}),t.setData(e.map(e=>({time:e.time,value:e.volume??0,color:`${e.close>=e.open?i:a}55`})))}for(let n of t)e.length<=n||m.addSeries(s,{color:h[n]??o,lineWidth:1,priceLineVisible:!1,lastValueVisible:!1,crosshairMarkerVisible:!1}).setData(_(e,n));m.timeScale().fitContent();let S=new Map(e.map(e=>[e.time,e]));return m.subscribeCrosshairMove(e=>{x(e.time==null?null:S.get(e.time)??null)}),()=>{m.remove(),y.current=null}},[e,t,r,S]);let C=b??e[e.length-1],w=C?(C.close-C.open)/C.open*100:null,T=C?new Date(C.time*1e3).toLocaleString(void 0,r?{dateStyle:`medium`,timeStyle:`short`}:{dateStyle:`medium`}):``;return(0,m.jsxs)(`div`,{className:`relative h-full w-full`,children:[C&&(0,m.jsxs)(`div`,{className:`tabular pointer-events-none absolute top-1 start-1 z-10 flex flex-wrap gap-x-3 rounded-md bg-surface/80 px-2 py-1 text-[12px] text-muted backdrop-blur-sm`,children:[(0,m.jsx)(`span`,{children:T}),(0,m.jsxs)(`span`,{children:[`O `,(0,m.jsx)(`b`,{className:`text-fg`,children:n(C.open)})]}),(0,m.jsxs)(`span`,{children:[`H `,(0,m.jsx)(`b`,{className:`text-fg`,children:n(C.high)})]}),(0,m.jsxs)(`span`,{children:[`L `,(0,m.jsx)(`b`,{className:`text-fg`,children:n(C.low)})]}),(0,m.jsxs)(`span`,{children:[`C `,(0,m.jsx)(`b`,{className:`text-fg`,children:n(C.close)})]}),(0,m.jsx)(`span`,{className:w!=null&&w>=0?`text-up`:`text-down`,children:i(w)}),C.volume!=null&&(0,m.jsxs)(`span`,{children:[`Vol `,a(C.volume)]})]}),(0,m.jsx)(`div`,{ref:v,className:`h-full w-full`})]})}export{v as default};
@@ -0,0 +1 @@
1
+ import{r as e}from"./rolldown-runtime-XKyaHtl9.js";import{b as t,f as n,n as r,o as i,p as a,s as o,t as s}from"./format-d8InM0Zw.js";import{D as c,a as l,g as u,i as d,l as f,o as p,p as m,s as h,t as g,y as _}from"./ui-gsFb8B2m.js";import{O as v,j as y}from"./index-CKAnq-Or.js";import{R as b,a as ee,d as te,i as x,pt as S,r as C,t as w,u as T,yt as E}from"./LineChart-BaOkD1Ta.js";import{a as D,n as O}from"./options-BYAZnwzW.js";import{n as k,s as A}from"./compare-DMcsx70H.js";import{t as j}from"./SymbolSearch-CBOVPEk1.js";import{t as M}from"./ExportMenu-DaZ1xVmW.js";var N=e(t(),1),P=a(),F=[`#6d8cff`,`#34d399`,`#fbbf24`,`#f472b6`,`#22d3ee`],I=[{value:`6mo`,label:`6M`},{value:`1y`,label:`1Y`},{value:`3y`,label:`3Y`},{value:`5y`,label:`5Y`}],L=5;function R(e){return e?e.split(`,`).map(e=>{let[t,n]=e.split(`:`);return{symbol:(t??``).trim().toUpperCase(),market:(n||`us`).trim().toLowerCase()}}).filter(e=>e.symbol).slice(0,L):[]}function z(e,t,n){return t==null?`—`:e.kind===`pct`?`${i(t,1)}%`:e.kind===`money`?`${n?`${n} `:``}${s(t)}`:e.kind===`count`?i(t,0):i(t,2)}function B(){let[e,t]=y(),a=(0,N.useMemo)(()=>R(e.get(`s`)),[e]),s=e.get(`period`)??`1y`,[v,A]=(0,N.useState)(``),[B,K]=(0,N.useState)(null),[q,J]=(0,N.useState)(null),[Y,X]=(0,N.useState)(!1);function Z(e,n=s){let r={};e.length&&(r.s=e.map(e=>`${e.symbol}:${e.market}`).join(`,`)),n!==`1y`&&(r.period=n),t(r,{replace:!0})}(0,N.useEffect)(()=>{if(a.length<2){K(null);return}let e=!1;return X(!0),J(null),k(a,s).then(t=>!e&&K(t)).catch(t=>!e&&(J(r(t)),K(null))).finally(()=>!e&&X(!1)),()=>{e=!0}},[a,s]);let Q=e=>F[Math.max(0,a.findIndex(t=>t.symbol===e))%F.length],$=B?.items??[],ne=e=>$.find(t=>t.symbol===e)?.currency??null;return(0,P.jsxs)(`div`,{children:[(0,P.jsx)(m,{title:`Compare`,description:`Put up to five stocks, ETFs or coins side by side: performance, risk and fundamentals.`,actions:B&&(0,P.jsx)(M,{title:`Compare ${$.map(e=>e.symbol).join(` vs `)}`,subtitle:`Period ${s}`,tables:()=>G(B)})}),(0,P.jsx)(d,{className:`mb-6`,children:(0,P.jsxs)(l,{className:`space-y-3`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[a.map((e,t)=>(0,P.jsxs)(`span`,{className:`inline-flex items-center gap-1.5 rounded-full border border-line bg-canvas py-1 pe-1 ps-3 text-sm`,children:[(0,P.jsx)(`span`,{className:`h-2 w-2 rounded-full`,style:{background:F[t%F.length]}}),(0,P.jsx)(`span`,{className:`font-mono font-medium`,children:e.symbol}),(0,P.jsx)(`span`,{className:`text-xs text-faint`,children:D(O,e.market)}),(0,P.jsx)(`button`,{type:`button`,className:`rounded-full p-1 text-muted hover:bg-raised hover:text-fg`,"aria-label":`Remove ${e.symbol}`,onClick:()=>Z(a.filter(t=>t!==e)),children:(0,P.jsx)(f,{name:`x`,className:`h-3.5 w-3.5`})})]},`${e.symbol}:${e.market}`)),a.length===0&&(0,P.jsx)(`span`,{className:`text-sm text-muted`,children:`Add at least two symbols.`})]}),(0,P.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3`,children:[a.length<L&&(0,P.jsx)(`div`,{className:`min-w-0 basis-full sm:max-w-sm sm:flex-1 sm:basis-auto`,children:(0,P.jsx)(j,{value:v,onChange:A,placeholder:`Add a symbol (${a.length}/${L})`,exclude:a.map(e=>e.symbol),onSelect:e=>{A(``),a.some(t=>t.symbol===e.symbol.toUpperCase()&&t.market===e.market)||Z([...a,{symbol:e.symbol.toUpperCase(),market:e.market}])}})}),(0,P.jsx)(u,{options:I,value:s,onChange:e=>Z(a,e),size:`sm`})]})]})}),a.length<2?(0,P.jsx)(d,{children:(0,P.jsx)(h,{icon:`compare`,title:`Pick two to five instruments`,description:`Mix markets if you like (say HDFCBANK vs ICICIBANK, or AAPL vs MSFT vs NVDA). Tip: open a stock in Analyze and use its Peers card to fill this in.`})}):q?(0,P.jsx)(g,{tone:`down`,children:q}):B?(0,P.jsxs)(`div`,{className:c(`space-y-6 transition-opacity`,Y&&`opacity-60`),children:[B.warnings.length>0&&(0,P.jsx)(`div`,{className:`space-y-1`,children:B.warnings.map(e=>(0,P.jsx)(`p`,{className:`rounded-md bg-warn-soft px-3 py-2 text-xs text-warn`,children:e},e))}),(0,P.jsxs)(d,{children:[(0,P.jsx)(p,{title:`Performance`,description:`Growth of 100 invested at the start of the period (dividends included)`,icon:`analyze`}),(0,P.jsx)(l,{children:(0,P.jsx)(`div`,{className:`h-72`,children:(0,P.jsx)(E,{width:`100%`,height:`100%`,children:(0,P.jsxs)(w,{data:B.chart,margin:{top:4,right:8,bottom:0,left:0},children:[(0,P.jsx)(T,{stroke:`var(--color-line)`,vertical:!1}),(0,P.jsx)(x,{dataKey:`time`,tick:{fill:`var(--color-faint)`,fontSize:11},axisLine:!1,tickLine:!1,minTickGap:50,tickFormatter:e=>new Date(e).toLocaleDateString(void 0,{month:`short`,year:`2-digit`})}),(0,P.jsx)(C,{width:40,domain:[`auto`,`auto`],tick:{fill:`var(--color-faint)`,fontSize:11},axisLine:!1,tickLine:!1}),(0,P.jsx)(b,{contentStyle:{background:`var(--color-raised)`,border:`1px solid var(--color-line-strong)`,borderRadius:8,fontSize:12},labelFormatter:e=>new Date(String(e)).toLocaleDateString(),formatter:(e,t)=>[i(Number(e),1),t]}),(0,P.jsx)(te,{y:100,stroke:`var(--color-line-strong)`}),(0,P.jsx)(S,{wrapperStyle:{fontSize:12}}),$.map(e=>(0,P.jsx)(ee,{dataKey:e.symbol,stroke:Q(e.symbol),strokeWidth:1.75,dot:!1,connectNulls:!0,isAnimationActive:!1},e.symbol))]})})})})]}),(0,P.jsxs)(d,{children:[(0,P.jsx)(p,{title:`Returns & risk`,description:`Total return per window; risk over the selected period`}),(0,P.jsx)(`div`,{className:`overflow-x-auto`,children:(0,P.jsx)(U,{items:$,colorOf:Q,rows:[...B.returns.map(e=>({label:`${e.window} return`,values:e.values,fmt:e=>(0,P.jsx)(`span`,{className:n(e),children:o(e,1)}),best:H(e.values,!0)})),{label:`Volatility (annual)`,values:V(B.risk,`volatility`),fmt:e=>e==null?`—`:`${i(e,1)}%`,best:H(V(B.risk,`volatility`),!1)},{label:`Max drawdown`,values:V(B.risk,`max_drawdown`),fmt:e=>(0,P.jsx)(`span`,{className:`text-down`,children:e==null?`—`:`${i(e,1)}%`}),best:H(V(B.risk,`max_drawdown`),!0)},{label:`Return per unit of risk`,values:V(B.risk,`sharpe_like`),fmt:e=>i(e,2),best:H(V(B.risk,`sharpe_like`),!0)},{label:`Beta vs home index`,values:V(B.risk,`beta`),fmt:(e,t)=>(0,P.jsx)(`span`,{title:t?`vs ${B.risk[t]?.benchmark}`:void 0,children:i(e,2)}),best:null}]})})]}),B.metrics.length>0&&(0,P.jsxs)(d,{children:[(0,P.jsx)(p,{title:`Fundamentals`,description:`Highlighted = best in the row. Latest reported figures.`}),(0,P.jsx)(`div`,{className:`overflow-x-auto`,children:(0,P.jsx)(U,{items:$,colorOf:Q,rows:B.metrics.map((e,t)=>({label:e.label,section:t===0||B.metrics[t-1].group!==e.group?e.group:void 0,values:e.values,fmt:(t,n)=>z(e,t,n?ne(n):null),best:e.best}))})})]}),B.correlation&&B.correlation.symbols.length>1&&(0,P.jsxs)(d,{children:[(0,P.jsx)(p,{title:`How they move together`,description:`Correlation of daily returns over the period. Near 1 = move as one; near 0 = independent.`}),(0,P.jsx)(l,{className:`overflow-x-auto`,children:(0,P.jsxs)(`table`,{className:`tabular text-sm`,children:[(0,P.jsx)(`thead`,{children:(0,P.jsxs)(`tr`,{children:[(0,P.jsx)(`th`,{}),B.correlation.symbols.map(e=>(0,P.jsx)(`th`,{className:`px-3 py-1.5 text-end font-mono text-xs font-medium text-muted`,children:e},e))]})}),(0,P.jsx)(`tbody`,{children:B.correlation.matrix.map((e,t)=>(0,P.jsxs)(`tr`,{children:[(0,P.jsx)(`th`,{className:`py-1.5 pe-3 text-start font-mono text-xs font-medium text-muted`,children:B.correlation.symbols[t]}),e.map((e,n)=>(0,P.jsx)(`td`,{className:`px-3 py-1.5 text-end`,style:t===n||e==null?void 0:{background:`rgba(109, 140, 255, ${Math.max(0,e)*.45})`},children:t===n?`—`:i(e,2)},n))]},t))})]})})]}),(0,P.jsx)(W,{picks:a}),(0,P.jsx)(`p`,{className:`text-xs text-faint`,children:`Data: market data feed, delayed. Past performance does not predict future returns. Not investment advice.`})]}):(0,P.jsx)(_,{className:`h-96 w-full`})]})}function V(e,t){return Object.fromEntries(Object.entries(e).map(([e,n])=>[e,n[t]??null]))}function H(e,t){let n=Object.entries(e).filter(([,e])=>e!=null);return n.length<2?null:n.reduce((e,n)=>(t?n[1]>e[1]:n[1]<e[1])?n:e)[0]}function U({items:e,rows:t,colorOf:n}){return(0,P.jsxs)(`table`,{className:`tabular w-full min-w-[34rem] text-sm`,children:[(0,P.jsx)(`thead`,{children:(0,P.jsxs)(`tr`,{className:`border-b border-line text-xs text-muted`,children:[(0,P.jsx)(`th`,{className:`sticky start-0 bg-surface px-5 py-2 text-start font-medium`}),e.map(e=>(0,P.jsx)(`th`,{className:`px-3 py-2 text-end font-medium`,children:(0,P.jsxs)(v,{to:`/analyze?symbol=${encodeURIComponent(e.symbol)}&market=${e.market}`,className:`inline-flex items-center gap-1.5 hover:text-fg`,title:e.name,children:[(0,P.jsx)(`span`,{className:`h-2 w-2 rounded-full`,style:{background:n(e.symbol)}}),(0,P.jsx)(`span`,{className:`font-mono`,children:e.symbol})]})},e.symbol))]})}),(0,P.jsx)(`tbody`,{className:`divide-y divide-line`,children:t.map(t=>[t.section&&(0,P.jsx)(`tr`,{className:`bg-canvas`,children:(0,P.jsx)(`td`,{colSpan:e.length+1,className:`px-5 py-1.5 text-xs font-medium text-muted`,children:t.section})},`s-${t.section}`),(0,P.jsxs)(`tr`,{children:[(0,P.jsx)(`td`,{className:`sticky start-0 bg-surface px-5 py-2 text-muted sm:whitespace-nowrap`,children:t.label}),e.map(e=>(0,P.jsx)(`td`,{className:c(`px-3 py-2 text-end`,t.best===e.symbol&&`bg-accent/10 font-semibold`),children:t.fmt(t.values[e.symbol]??null,e.symbol)},e.symbol))]},t.label)])})]})}function W({picks:e}){let[t,n]=(0,N.useState)(null),r=e.map(e=>`${e.symbol}:${e.market}`).join(`,`);return(0,N.useEffect)(()=>{let t=!1;n(null);let r=[];for(let t=0;t<e.length;t++)for(let n=t+1;n<e.length;n++)r.push([e[t],e[n]]);return Promise.all(r.map(([e,t])=>A(e,t).catch(()=>null))).then(e=>!t&&n(e.filter(e=>!!e&&e.available))),()=>{t=!0}},[r]),!t||t.length===0?null:(0,P.jsxs)(d,{children:[(0,P.jsx)(p,{title:`ETF holdings overlap`,description:`Share of each fund's weight sitting in the same stocks. High overlap = little extra diversification.`}),(0,P.jsx)(l,{className:`space-y-3`,children:t.map(e=>(0,P.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap items-baseline justify-between gap-2 text-sm`,children:[(0,P.jsxs)(`span`,{children:[(0,P.jsx)(`span`,{className:`font-mono`,children:e.a}),` & `,(0,P.jsx)(`span`,{className:`font-mono`,children:e.b})]}),(0,P.jsxs)(`span`,{className:`tabular font-semibold`,children:[i((e.overlap??0)*100,1),`% overlap · `,e.shared_count,` shared`]})]}),(0,P.jsx)(`div`,{className:`h-2 rounded-full bg-raised`,children:(0,P.jsx)(`div`,{className:`h-2 rounded-full bg-accent`,style:{width:`${Math.min((e.overlap??0)*100,100)}%`}})}),e.shared&&e.shared.length>0&&(0,P.jsxs)(`p`,{className:`text-xs text-muted`,children:[`Biggest shared: `,e.shared.slice(0,6).map(e=>`${e.symbol} (${i(Math.min(e.weight_a,e.weight_b)*100,1)}%)`).join(`, `)]}),e.note&&(0,P.jsx)(`p`,{className:`text-xs text-faint`,children:e.note})]},`${e.a}-${e.b}`))})]})}function G(e){let t=e.items.map(e=>e.symbol),n=e=>t.map(t=>({key:t,label:t,kind:e}));return[{title:`Overview`,columns:[{key:`symbol`,label:`Symbol`},{key:`name`,label:`Name`},{key:`market`,label:`Market`},{key:`currency`,label:`Currency`},{key:`sector`,label:`Sector`},{key:`industry`,label:`Industry`},{key:`price`,label:`Price`,kind:`number`}],rows:e.items},{title:`Returns`,columns:[{key:`label`,label:`Window`},...n(`pct`)],rows:e.returns.map(e=>({label:`${e.window} return`,...e.values}))},{title:`Risk`,columns:[{key:`symbol`,label:`Symbol`},{key:`return_period`,label:`Return over period %`,kind:`pct`},{key:`volatility`,label:`Volatility (annual) %`,kind:`pct`},{key:`max_drawdown`,label:`Max drawdown %`,kind:`pct`},{key:`sharpe_like`,label:`Return per unit of risk`,kind:`number`},{key:`beta`,label:`Beta`,kind:`number`},{key:`benchmark`,label:`Beta vs`}],rows:Object.entries(e.risk).map(([e,t])=>({symbol:e,...t}))},{title:`Fundamentals`,columns:[{key:`group`,label:`Group`},{key:`label`,label:`Metric`},...n(`number`),{key:`best`,label:`Best`}],rows:e.metrics.map(e=>({group:e.group,label:e.kind===`pct`?`${e.label} %`:e.label,...e.values,best:e.best,_kind:e.kind===`money`?`money`:e.kind===`pct`?`pct`:`number`})),note:`Latest reported figures. Money values are in each company's own currency.`},...e.correlation?[{title:`Correlation of daily returns`,columns:[{key:`symbol`,label:``},...e.correlation.symbols.map(e=>({key:e,label:e,kind:`number`}))],rows:e.correlation.matrix.map((t,n)=>({symbol:e.correlation.symbols[n],...Object.fromEntries(t.map((t,n)=>[e.correlation.symbols[n],t]))}))}]:[],{title:`Performance (rebased to 100)`,columns:[{key:`time`,label:`Date`,kind:`date`},...n(`number`)],rows:e.chart,pdf:!1}]}export{B as default};
@@ -0,0 +1 @@
1
+ import{r as e}from"./rolldown-runtime-XKyaHtl9.js";import{b as t,n,p as r}from"./format-d8InM0Zw.js";import{t as i}from"./toast-DDradTZw.js";import{b as a}from"./ui-gsFb8B2m.js";import{M as o}from"./index-CKAnq-Or.js";import{t as s}from"./exporter-DiMg2O5d.js";var c=e(t(),1),l=r(),u=[{value:`xlsx`,label:`Excel (.xlsx)`},{value:`csv`,label:`CSV`},{value:`pdf`,label:`PDF`}];function d({title:e,subtitle:t,tables:r,disabled:d}){let{t:f}=o(`app`),[p,m]=(0,c.useState)(!1),[h,g]=(0,c.useState)(null),_=(0,c.useRef)(null);(0,c.useEffect)(()=>{if(!p)return;let e=e=>{(e instanceof KeyboardEvent?e.key===`Escape`:!_.current?.contains(e.target))&&m(!1)};return document.addEventListener(`mousedown`,e),document.addEventListener(`keydown`,e),()=>{document.removeEventListener(`mousedown`,e),document.removeEventListener(`keydown`,e)}},[p]);async function v(a){g(a);try{let n=await r();if(!n.some(e=>e.rows.length)){i.info(f(`export.nothing`));return}await s(a,e,n,t),m(!1)}catch(e){i.error(f(`export.failed`,{error:n(e)}))}finally{g(null)}}return(0,l.jsxs)(`div`,{ref:_,className:`relative inline-block`,children:[(0,l.jsxs)(`button`,{type:`button`,disabled:d,onClick:()=>m(e=>!e),"aria-haspopup":`menu`,"aria-expanded":p,className:`inline-flex items-center gap-1.5 whitespace-nowrap rounded-md border border-line px-2.5 py-1 text-xs text-muted hover:border-line-strong hover:text-fg disabled:opacity-50`,children:[(0,l.jsx)(`svg`,{viewBox:`0 0 24 24`,className:`h-3.5 w-3.5`,fill:`none`,stroke:`currentColor`,strokeWidth:2,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,children:(0,l.jsx)(`path`,{d:`M12 3v12M7 10l5 5 5-5M5 21h14`})}),f(`export.button`)]}),p&&(0,l.jsx)(`div`,{role:`menu`,className:`absolute end-0 z-30 mt-1 w-56 rounded-lg border border-line bg-surface p-1 shadow-xl`,children:u.map(e=>(0,l.jsxs)(`button`,{type:`button`,role:`menuitem`,disabled:h!=null,onClick:()=>v(e.value),className:`flex w-full items-center justify-between gap-2 rounded-md px-3 py-2 text-start hover:bg-raised disabled:opacity-60`,children:[(0,l.jsxs)(`span`,{children:[(0,l.jsx)(`span`,{className:`block text-sm`,children:e.label}),(0,l.jsx)(`span`,{className:`block text-xs text-faint`,children:f(`export.hint.${e.value}`)})]}),h===e.value&&(0,l.jsx)(a,{})]},e.value))})]})}export{d as t};