@aicoin/opendata-mcp 1.0.29 → 2.0.0

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 (3) hide show
  1. package/README.md +153 -165
  2. package/build/index.js +978 -2249
  3. package/package.json +1 -1
package/build/index.js CHANGED
@@ -44,7 +44,7 @@ Endpoint: ${path}`;
44
44
  }
45
45
  throw new Error(msg);
46
46
  }
47
- var BIZ_AUTH_CODES = /* @__PURE__ */ new Set([403, 401]);
47
+ var BIZ_AUTH_CODES = /* @__PURE__ */ new Set([403, 401, 304]);
48
48
  function checkBizError(data, path) {
49
49
  if (!data || typeof data !== "object") return;
50
50
  const obj = data;
@@ -329,2410 +329,1225 @@ function err(e) {
329
329
  // src/tools/coins.ts
330
330
  function registerCoinTools(server2) {
331
331
  server2.tool(
332
- "get_coin_list",
333
- "Get supported coins list (returns top 100 by default, use get_coin_ticker for specific coins)",
334
- { ...maxItemsParam },
335
- async ({ _max_items }) => {
336
- try {
337
- return okList(
338
- await apiGet("/api/v2/coin"),
339
- parseMax(_max_items, 100)
340
- );
341
- } catch (e) {
342
- return err(e);
343
- }
344
- }
345
- );
346
- server2.tool(
347
- "get_coin_ticker",
348
- "Get real-time ticker data for coins (price, change, volume)",
349
- {
350
- coin_list: z2.string().describe("Coin keys, comma-separated, e.g. bitcoin,ethereum")
351
- },
352
- async ({ coin_list }) => {
353
- try {
354
- return ok(
355
- await apiGet("/api/v2/coin/ticker", { coin_list })
356
- );
357
- } catch (e) {
358
- return err(e);
359
- }
360
- }
361
- );
362
- server2.tool(
363
- "get_coin_config",
364
- "Get coin profile/description data",
365
- {
366
- coin_list: z2.string().describe(
367
- "Coin keys, comma-separated, max 100, e.g. bitcoin,ethereum"
368
- )
369
- },
370
- async ({ coin_list }) => {
371
- try {
372
- return ok(
373
- await apiGet("/api/v2/coin/config", { coin_list })
374
- );
375
- } catch (e) {
376
- return err(e);
377
- }
378
- }
379
- );
380
- server2.tool(
381
- "get_ai_coin_analysis",
382
- "Get AI interpretation and prediction for coins",
383
- {
384
- coin_keys: z2.string().describe('Coin keys JSON array, e.g. ["bitcoin","ethereum"]'),
385
- language: z2.enum(["CN", "EN", "TC"]).optional().describe("Language: CN/EN/TC, default CN")
386
- },
387
- async ({ coin_keys, language }) => {
388
- try {
389
- const body = {
390
- coinKeys: JSON.parse(coin_keys)
391
- };
392
- if (language) body.language = language;
393
- return ok(
394
- await apiPost("/api/v2/content/ai-coins", body)
395
- );
396
- } catch (e) {
397
- return err(e);
398
- }
399
- }
400
- );
401
- server2.tool(
402
- "get_funding_rate_history",
403
- "Get funding rate history",
404
- {
405
- symbol: z2.string().describe(
406
- "Trading pair, e.g. btcswapusdt:okcoinfutures"
407
- ),
408
- interval: z2.string().describe(
409
- "Interval: 5m,15m,30m,8h (recommended). 1h,4h,1d may return empty data"
410
- ),
411
- limit: z2.string().optional().describe("Number of records, default 100"),
412
- start_time: z2.string().optional().describe("Start time in ms"),
413
- end_time: z2.string().optional().describe("End time in ms")
414
- },
415
- async ({ symbol, interval, limit, start_time, end_time }) => {
416
- try {
417
- const params = {
418
- symbol,
419
- interval
420
- };
421
- params.limit = limit ?? "100";
422
- if (start_time) params.start_time = start_time;
423
- if (end_time) params.end_time = end_time;
424
- return ok(
425
- await apiGet(
426
- "/api/upgrade/v2/futures/funding-rate/history",
427
- params
428
- )
429
- );
430
- } catch (e) {
431
- return err(e);
432
- }
433
- }
434
- );
435
- server2.tool(
436
- "get_liquidation_map",
437
- "Get liquidation heatmap data",
332
+ "coin_info",
333
+ "Coin data.\n\u2022 list \u2014 all coins, no params needed\n\u2022 ticker \u2014 real-time prices. Requires: coin_list\n\u2022 config \u2014 coin profiles. Requires: coin_list\n\u2022 ai_analysis \u2014 AI predictions. Requires: coin_keys (JSON array string)",
438
334
  {
439
- dbkey: z2.string().describe(
440
- "Trading pair key, e.g. btcswapusdt:binance"
441
- ),
442
- cycle: z2.string().describe("Cycle: 24h or 7d"),
443
- leverage: z2.string().optional().describe(
444
- "Leverage filter: 10,25,50,100 (empty=all)"
335
+ action: z2.enum(["list", "ticker", "config", "ai_analysis"]).describe(
336
+ "list: top coins; ticker: real-time prices; config: coin profiles; ai_analysis: AI predictions"
445
337
  ),
338
+ coin_list: z2.string().optional().describe('REQUIRED for ticker, config. Comma-separated coin keys, e.g. "bitcoin,ethereum". NOT used by ai_analysis'),
339
+ coin_keys: z2.string().optional().describe(`REQUIRED for ai_analysis. JSON array string, e.g. '["bitcoin","ethereum"]'. NOT used by ticker/config`),
340
+ language: z2.enum(["CN", "EN", "TC"]).optional().describe("Optional for ai_analysis: response language, default CN"),
446
341
  ...maxItemsParam
447
342
  },
448
- async ({ dbkey, cycle, leverage, _max_items }) => {
449
- try {
450
- const params = {
451
- dbkey,
452
- cycle
453
- };
454
- if (leverage) params.leverage = leverage;
455
- return okList(
456
- await apiGet(
457
- "/api/upgrade/v2/futures/liquidation/map",
458
- params
459
- ),
460
- parseMax(_max_items, 50)
461
- );
462
- } catch (e) {
463
- return err(e);
464
- }
465
- }
466
- );
467
- server2.tool(
468
- "get_weighted_funding_rate_history",
469
- "Get volume-weighted funding rate history",
470
- {
471
- symbol: z2.string().describe("Symbol, e.g. btcswapusdt"),
472
- interval: z2.string().describe(
473
- "Interval: 5m,15m,30m,8h (recommended). 1h,4h,1d may return empty data"
474
- ),
475
- limit: z2.string().optional().describe("Number of records, default 100"),
476
- start_time: z2.string().optional().describe("Start time in ms"),
477
- end_time: z2.string().optional().describe("End time in ms")
478
- },
479
- async ({ symbol, interval, limit, start_time, end_time }) => {
480
- try {
481
- const params = {
482
- symbol,
483
- interval
484
- };
485
- params.limit = limit ?? "100";
486
- if (start_time) params.start_time = start_time;
487
- if (end_time) params.end_time = end_time;
488
- return ok(
489
- await apiGet(
490
- "/api/upgrade/v2/futures/funding-rate/vol-weight-history",
491
- params
492
- )
493
- );
494
- } catch (e) {
495
- return err(e);
496
- }
497
- }
498
- );
499
- server2.tool(
500
- "get_aggregated_stablecoin_oi_history",
501
- "Get aggregated stablecoin-margined open interest history",
502
- {
503
- symbol: z2.string().describe("Coin symbol, e.g. BTC"),
504
- interval: z2.string().describe("Interval: 1m,2m,15m,30m"),
505
- limit: z2.string().optional().describe("Number of records, default 100"),
506
- start_time: z2.string().optional().describe("Start time in ms"),
507
- end_time: z2.string().optional().describe("End time in ms")
508
- },
509
- async ({ symbol, interval, limit, start_time, end_time }) => {
343
+ async ({ action, coin_list, coin_keys, language, _max_items }) => {
510
344
  try {
511
- const params = {
512
- symbol,
513
- interval
514
- };
515
- params.limit = limit ?? "100";
516
- if (start_time) params.start_time = start_time;
517
- if (end_time) params.end_time = end_time;
518
- return ok(
519
- await apiGet(
520
- "/api/upgrade/v2/futures/open-interest/aggregated-stablecoin-history",
521
- params
522
- )
523
- );
345
+ switch (action) {
346
+ case "list":
347
+ return okList(await apiGet("/api/v2/coin"), parseMax(_max_items, 100));
348
+ case "ticker": {
349
+ if (!coin_list) return err("coin_list is required for ticker action");
350
+ return ok(await apiGet("/api/v2/coin/ticker", { coin_list }));
351
+ }
352
+ case "config": {
353
+ if (!coin_list) return err("coin_list is required for config action");
354
+ return ok(await apiGet("/api/v2/coin/config", { coin_list }));
355
+ }
356
+ case "ai_analysis": {
357
+ if (!coin_keys) return err("coin_keys is required for ai_analysis action");
358
+ const body = { coinKeys: JSON.parse(coin_keys) };
359
+ if (language) body.language = language;
360
+ return ok(await apiPost("/api/v2/content/ai-coins", body));
361
+ }
362
+ }
524
363
  } catch (e) {
525
364
  return err(e);
526
365
  }
527
366
  }
528
367
  );
529
368
  server2.tool(
530
- "get_aggregated_coin_margin_oi_history",
531
- "Get aggregated coin-margined open interest history",
369
+ "coin_funding_rate",
370
+ "Funding rate history.\n\u2022 Default: per-exchange rate. Requires symbol with exchange suffix, e.g. btcswapusdt:binance\n\u2022 weighted=true: volume-weighted rate across exchanges. Symbol WITHOUT exchange suffix, e.g. btcswapusdt",
532
371
  {
533
- symbol: z2.string().describe("Coin symbol, e.g. BTC"),
534
- interval: z2.string().describe("Interval: 1m,2m,15m,30m"),
372
+ symbol: z2.string().describe("REQUIRED. Trading pair. With exchange suffix for normal (e.g. btcswapusdt:binance), WITHOUT suffix for weighted (e.g. btcswapusdt)"),
373
+ interval: z2.string().describe("REQUIRED. Candle interval: 5m, 15m, 30m, 8h (recommended). 1h, 4h, 1d may return empty"),
374
+ weighted: z2.boolean().optional().default(false).describe("Use volume-weighted funding rate"),
535
375
  limit: z2.string().optional().describe("Number of records, default 100"),
536
376
  start_time: z2.string().optional().describe("Start time in ms"),
537
377
  end_time: z2.string().optional().describe("End time in ms")
538
378
  },
539
- async ({ symbol, interval, limit, start_time, end_time }) => {
540
- try {
541
- const params = {
542
- symbol,
543
- interval
544
- };
545
- params.limit = limit ?? "100";
546
- if (start_time) params.start_time = start_time;
547
- if (end_time) params.end_time = end_time;
548
- return ok(
549
- await apiGet(
550
- "/api/upgrade/v2/futures/open-interest/aggregated-coin-margin-history",
551
- params
552
- )
553
- );
554
- } catch (e) {
555
- return err(e);
556
- }
557
- }
558
- );
559
- server2.tool(
560
- "get_liquidation_history",
561
- "Get liquidation order history",
562
- {
563
- symbol: z2.string().describe(
564
- "Trading pair, e.g. btcswapusdt:binance"
565
- ),
566
- interval: z2.string().describe("Interval: 1m,2m,15m,30m"),
567
- limit: z2.string().optional().describe("Number of records, default 10"),
568
- start_time: z2.string().optional().describe("Start time in ms"),
569
- end_time: z2.string().optional().describe("End time in ms")
570
- },
571
- async ({ symbol, interval, limit, start_time, end_time }) => {
379
+ async ({ symbol, interval, weighted, limit, start_time, end_time }) => {
572
380
  try {
573
- const params = {
574
- symbol,
575
- interval
576
- };
381
+ const params = { symbol, interval };
577
382
  params.limit = limit ?? "100";
578
383
  if (start_time) params.start_time = start_time;
579
384
  if (end_time) params.end_time = end_time;
580
- return ok(
581
- await apiGet(
582
- "/api/upgrade/v2/futures/liquidation/history",
583
- params
584
- )
585
- );
385
+ const path = weighted ? "/api/upgrade/v2/futures/funding-rate/vol-weight-history" : "/api/upgrade/v2/futures/funding-rate/history";
386
+ return ok(await apiGet(path, params));
586
387
  } catch (e) {
587
388
  return err(e);
588
389
  }
589
390
  }
590
391
  );
591
392
  server2.tool(
592
- "get_estimated_liquidation_history",
593
- "Get historical estimated liquidation chart data",
393
+ "coin_liquidation",
394
+ "Liquidation data.\n\u2022 history \u2014 liquidation orders. Requires: symbol + interval\n\u2022 map \u2014 liquidation heatmap. Requires: dbkey + cycle\n\u2022 estimated \u2014 estimated liquidation chart. Requires: dbkey + cycle",
594
395
  {
595
- dbkey: z2.string().describe(
596
- "Trading pair key, e.g. btcswapusdt:binance"
597
- ),
598
- cycle: z2.string().describe("Cycle: 24h or 7d"),
599
- leverage: z2.string().optional().describe(
600
- "Leverage filter: 10,25,50,100 (empty=all)"
396
+ action: z2.enum(["map", "history", "estimated"]).describe(
397
+ "map: liquidation heatmap; history: liquidation orders; estimated: estimated liquidation chart"
601
398
  ),
602
- limit: z2.string().optional().describe("Number of records, default 100"),
399
+ symbol: z2.string().optional().describe("REQUIRED for history. Trading pair with exchange, e.g. btcswapusdt:binance. NOT used by map/estimated"),
400
+ dbkey: z2.string().optional().describe("REQUIRED for map, estimated. Trading pair key, e.g. btcswapusdt:binance. NOT used by history"),
401
+ cycle: z2.string().optional().describe('REQUIRED for map, estimated. Time cycle: "24h" or "7d"'),
402
+ leverage: z2.string().optional().describe("Optional for map, estimated. Leverage filter: 10, 25, 50, 100"),
403
+ interval: z2.string().optional().describe("REQUIRED for history. Candle interval: 1m, 2m, 15m, 30m"),
404
+ limit: z2.string().optional().describe("Number of records"),
603
405
  start_time: z2.string().optional().describe("Start time in ms"),
604
406
  end_time: z2.string().optional().describe("End time in ms"),
605
407
  ...maxItemsParam
606
408
  },
607
- async ({ dbkey, cycle, leverage, limit, start_time, end_time, _max_items }) => {
608
- try {
609
- const params = {
610
- dbkey,
611
- cycle
612
- };
613
- if (leverage) params.leverage = leverage;
614
- params.limit = limit ?? "5";
615
- if (start_time) params.start_time = start_time;
616
- if (end_time) params.end_time = end_time;
617
- return okListDeep(
618
- await apiGet(
619
- "/api/upgrade/v2/futures/estimated-liquidation/history",
620
- params
621
- ),
622
- parseMax(_max_items, 5),
623
- 20
624
- );
625
- } catch (e) {
626
- return err(e);
627
- }
628
- }
629
- );
630
- server2.tool(
631
- "get_historical_depth",
632
- "Get historical order book depth data",
633
- {
634
- key: z2.string().describe(
635
- "Trading pair key, e.g. btcswapusdt:okcoinfutures"
636
- ),
637
- limit: z2.string().optional().describe("Number of records, max 1000"),
638
- start_time: z2.string().optional().describe("Start time in ms"),
639
- end_time: z2.string().optional().describe("End time in ms")
640
- },
641
- async ({ key, limit, start_time, end_time }) => {
642
- try {
643
- const params = { key };
644
- params.limit = limit ?? "100";
645
- if (start_time) params.start_time = start_time;
646
- if (end_time) params.end_time = end_time;
647
- return ok(
648
- await apiGet(
649
- "/api/upgrade/v2/futures/historical-depth",
650
- params
651
- )
652
- );
653
- } catch (e) {
654
- return err(e);
655
- }
656
- }
657
- );
658
- server2.tool(
659
- "get_super_depth_history",
660
- "Get large order depth history",
661
- {
662
- key: z2.string().describe(
663
- "Trading pair key, e.g. btcswapusdt:okcoinfutures"
664
- ),
665
- amount: z2.string().optional().describe("USD threshold, default 10000"),
666
- limit: z2.string().optional().describe("Number of records, max 1000"),
667
- start_time: z2.string().optional().describe("Start time in ms"),
668
- end_time: z2.string().optional().describe("End time in ms")
669
- },
670
- async ({ key, amount, limit, start_time, end_time }) => {
671
- try {
672
- const params = { key };
673
- params.amount = amount ?? "10000";
674
- params.limit = limit ?? "100";
675
- if (start_time) params.start_time = start_time;
676
- if (end_time) params.end_time = end_time;
677
- return ok(
678
- await apiGet(
679
- "/api/upgrade/v2/futures/super-depth/history",
680
- params
681
- )
682
- );
683
- } catch (e) {
684
- return err(e);
685
- }
686
- }
687
- );
688
- server2.tool(
689
- "get_trade_data",
690
- "Get latest trade data for futures",
691
- {
692
- dbkey: z2.string().describe(
693
- "Trading pair key, e.g. btcswapusdt:okcoinfutures"
694
- ),
695
- limit: z2.string().optional().describe("Number of records, max 1000"),
696
- start_time: z2.string().optional().describe("Start time in ms"),
697
- end_time: z2.string().optional().describe("End time in ms")
698
- },
699
- async ({ dbkey, limit, start_time, end_time }) => {
700
- try {
701
- const params = { dbkey };
702
- params.limit = limit ?? "100";
703
- if (start_time) params.start_time = start_time;
704
- if (end_time) params.end_time = end_time;
705
- return ok(
706
- await apiGet(
707
- "/api/upgrade/v2/futures/trade-data",
708
- params
709
- )
710
- );
711
- } catch (e) {
712
- return err(e);
713
- }
714
- }
715
- );
716
- }
717
-
718
- // src/tools/contents.ts
719
- import { z as z3 } from "zod";
720
- function registerContentTools(server2) {
721
- server2.tool(
722
- "get_newsflash",
723
- "Get latest crypto flash news by AiCoin only",
724
- {
725
- language: z3.string().optional().describe("Language: cn, tc, en")
726
- },
727
- async ({ language }) => {
728
- try {
729
- const params = {};
730
- if (language) params.language = language;
731
- return ok(
732
- await apiGet("/api/v2/content/newsflash", params)
733
- );
734
- } catch (e) {
735
- return err(e);
736
- }
737
- }
738
- );
739
- server2.tool(
740
- "get_news_list",
741
- "Get news article list",
742
- {
743
- page: z3.string().optional().describe("Page number, default 1"),
744
- pageSize: z3.string().optional().describe("Page size, max 20")
745
- },
746
- async ({ page, pageSize }) => {
747
- try {
748
- const params = {};
749
- if (page) params.page = page;
750
- params.pageSize = pageSize ?? "20";
751
- return ok(
752
- await apiGet("/api/v2/content/news-list", params)
753
- );
754
- } catch (e) {
755
- return err(e);
756
- }
757
- }
758
- );
759
- server2.tool(
760
- "get_news_detail",
761
- "Get full content of a news article",
762
- {
763
- id: z3.string().describe("News article ID")
764
- },
765
- async ({ id }) => {
766
- try {
767
- return ok(
768
- await apiGet("/api/v2/content/news-detail", { id })
769
- );
770
- } catch (e) {
771
- return err(e);
772
- }
773
- }
774
- );
775
- server2.tool(
776
- "get_rss_news_list",
777
- "Get RSS news list (dedicated RSS feed)",
778
- {
779
- page: z3.string().optional().describe("Page number"),
780
- pageSize: z3.string().optional().describe("Page size, max 20")
781
- },
782
- async ({ page, pageSize }) => {
783
- try {
784
- const params = {};
785
- if (page) params.page = page;
786
- params.pageSize = pageSize ?? "20";
787
- return ok(
788
- await apiGet(
789
- "/api/v2/content/square/market/news-list",
790
- params
791
- )
792
- );
793
- } catch (e) {
794
- return err(e);
795
- }
796
- }
797
- );
798
- server2.tool(
799
- "get_flash_list",
800
- "Get industry flash news (with flash type classification)",
801
- {
802
- language: z3.string().optional().describe("Language: cn, tc, en"),
803
- createtime: z3.string().optional().describe("Filter by create time"),
804
- ...maxItemsParam
805
- },
806
- async ({ language, createtime, _max_items }) => {
807
- try {
808
- const params = {};
809
- if (language) params.language = language;
810
- if (createtime) params.createtime = createtime;
811
- return okList(
812
- await apiGet(
813
- "/api/v2/content/flashList",
814
- params
815
- ),
816
- parseMax(_max_items, 30)
817
- );
818
- } catch (e) {
819
- return err(e);
820
- }
821
- }
822
- );
823
- server2.tool(
824
- "get_exchange_listing_flash",
825
- "Get exchange coin listing/delisting news",
826
- {
827
- language: z3.string().optional().describe("Language: cn, tc, en"),
828
- memberIds: z3.string().optional().describe(
829
- "Exchange member IDs, comma-separated. 477=Binance, 1509=Bitget. Default: 477,1509"
830
- ),
831
- pageSize: z3.string().optional().describe("Page size, default 20")
832
- },
833
- async ({ language, memberIds, pageSize }) => {
834
- try {
835
- const params = {};
836
- if (language) params.language = language;
837
- if (memberIds) params.memberIds = memberIds;
838
- if (pageSize) params.pageSize = pageSize;
839
- return ok(
840
- await apiGet(
841
- "/api/v2/content/exchange-listing-flash",
842
- params
843
- )
844
- );
409
+ async ({ action, symbol, dbkey, cycle, leverage, interval, limit, start_time, end_time, _max_items }) => {
410
+ try {
411
+ switch (action) {
412
+ case "map": {
413
+ if (!dbkey || !cycle) return err("dbkey and cycle are required for map action");
414
+ const params = { dbkey, cycle };
415
+ if (leverage) params.leverage = leverage;
416
+ return okList(
417
+ await apiGet("/api/upgrade/v2/futures/liquidation/map", params),
418
+ parseMax(_max_items, 50)
419
+ );
420
+ }
421
+ case "history": {
422
+ if (!symbol || !interval) return err("symbol and interval are required for history action");
423
+ const params = { symbol, interval };
424
+ params.limit = limit ?? "100";
425
+ if (start_time) params.start_time = start_time;
426
+ if (end_time) params.end_time = end_time;
427
+ return ok(await apiGet("/api/upgrade/v2/futures/liquidation/history", params));
428
+ }
429
+ case "estimated": {
430
+ if (!dbkey || !cycle) return err("dbkey and cycle are required for estimated action");
431
+ const params = { dbkey, cycle };
432
+ if (leverage) params.leverage = leverage;
433
+ params.limit = limit ?? "5";
434
+ if (start_time) params.start_time = start_time;
435
+ if (end_time) params.end_time = end_time;
436
+ return okListDeep(
437
+ await apiGet("/api/upgrade/v2/futures/estimated-liquidation/history", params),
438
+ parseMax(_max_items, 5),
439
+ 20
440
+ );
441
+ }
442
+ }
845
443
  } catch (e) {
846
444
  return err(e);
847
445
  }
848
446
  }
849
447
  );
850
- }
851
-
852
- // src/tools/markets.ts
853
- import { z as z4 } from "zod";
854
- function registerMarketTools(server2) {
855
448
  server2.tool(
856
- "get_kline_data",
857
- "Get K-line (candlestick) data for a trading pair",
449
+ "coin_open_interest",
450
+ "Aggregated open interest history. Requires: symbol + interval.\n\u2022 margin_type=stablecoin: stablecoin-margined OI (default)\n\u2022 margin_type=coin: coin-margined OI",
858
451
  {
859
- symbol: z4.string().describe(
860
- "Symbol, e.g. btcusdt:okex or i:ixic:nasdaq"
861
- ),
862
- period: z4.string().optional().describe(
863
- "Period in seconds: 900=15min, 3600=1h, 14400=4h, 86400=1d"
864
- ),
865
- size: z4.string().optional().describe("Number of candles, 1-500"),
866
- since: z4.string().optional().describe("Start timestamp"),
867
- open_time: z4.string().optional().describe("Open time offset: 0 or 8")
868
- },
869
- async ({ symbol, period, size, since, open_time }) => {
870
- try {
871
- const params = {
872
- symbol
873
- };
874
- if (period) params.period = period;
875
- params.size = size ?? "100";
876
- if (since) params.since = since;
877
- if (open_time) params.open_time = open_time;
878
- return ok(
879
- await apiGet(
880
- "/api/v2/commonKline/dataRecords",
881
- params
882
- )
883
- );
884
- } catch (e) {
885
- return err(e);
886
- }
887
- }
888
- );
889
- server2.tool(
890
- "get_market_ticker",
891
- "Get ticker data for exchange platforms",
892
- {
893
- market_list: z4.string().describe(
894
- "Comma-separated exchange keys, max 100, e.g. okex,binance"
895
- )
896
- },
897
- async ({ market_list }) => {
898
- try {
899
- return ok(
900
- await apiGet("/api/v2/market/ticker", {
901
- market_list
902
- })
903
- );
904
- } catch (e) {
905
- return err(e);
906
- }
907
- }
908
- );
909
- server2.tool(
910
- "get_markets",
911
- "Get list of all supported exchange platforms",
912
- {},
913
- async () => {
914
- try {
915
- return ok(await apiGet("/api/v2/market"));
916
- } catch (e) {
917
- return err(e);
918
- }
919
- }
920
- );
921
- server2.tool(
922
- "get_futures_interest",
923
- "Get futures open interest data",
924
- {
925
- lan: z4.string().optional().describe("Language: cn or en"),
926
- page: z4.string().optional().describe("Page number"),
927
- pageSize: z4.string().optional().describe("Page size, max 20"),
928
- currency: z4.string().optional().describe("Currency: cny or usd")
929
- },
930
- async ({ lan, page, pageSize, currency }) => {
931
- try {
932
- const params = {};
933
- if (lan) params.lan = lan;
934
- if (page) params.page = page;
935
- if (pageSize) params.pageSize = pageSize;
936
- if (currency) params.currency = currency;
937
- return ok(
938
- await apiGet(
939
- "/api/v2/futures/interest",
940
- params
941
- )
942
- );
943
- } catch (e) {
944
- return err(e);
945
- }
946
- }
947
- );
948
- server2.tool(
949
- "get_crypto_stock_quotes",
950
- "Get crypto-related stock quotes (MSTR, COIN, etc.)",
951
- {
952
- tickers: z4.string().optional().describe(
953
- "Stock tickers, e.g. i:mstr:nasdaq,i:coin:nasdaq"
954
- )
955
- },
956
- async ({ tickers }) => {
957
- try {
958
- const params = {};
959
- if (tickers) params.tickers = tickers;
960
- return ok(
961
- await apiGet(
962
- "/api/upgrade/v2/crypto_stock/quotes",
963
- params
964
- )
965
- );
966
- } catch (e) {
967
- return err(e);
968
- }
969
- }
970
- );
971
- server2.tool(
972
- "get_crypto_stock_top_gainer",
973
- "Get top gaining crypto-related stocks (US and/or HK market)",
974
- {
975
- us_stock: z4.boolean().optional().describe("Include US stocks (default false)"),
976
- hk_stock: z4.boolean().optional().describe("Include HK stocks (default false)"),
977
- limit: z4.number().optional().describe("Number of results (default 50)")
978
- },
979
- async ({ us_stock, hk_stock, limit }) => {
980
- try {
981
- const params = {};
982
- if (us_stock != null)
983
- params.us_stock = String(us_stock);
984
- if (hk_stock != null)
985
- params.hk_stock = String(hk_stock);
986
- params.limit = String(limit ?? 30);
987
- return ok(
988
- await apiGet(
989
- "/api/upgrade/v2/crypto_stock/top-gainer",
990
- params
991
- )
992
- );
993
- } catch (e) {
994
- return err(e);
995
- }
996
- }
997
- );
998
- server2.tool(
999
- "get_index_price",
1000
- "Get index price data",
1001
- {
1002
- key: z4.string().describe("Index key, e.g. i:diniw:ice"),
1003
- currency: z4.string().optional().describe("Currency: cny or usd")
1004
- },
1005
- async ({ key, currency }) => {
1006
- try {
1007
- const params = { key };
1008
- if (currency) params.currency = currency;
1009
- return ok(
1010
- await apiGet("/api/v2/index/indexPrice", params)
1011
- );
1012
- } catch (e) {
1013
- return err(e);
1014
- }
1015
- }
1016
- );
1017
- server2.tool(
1018
- "get_hot_tab_coins",
1019
- "Get trending/hot coins list by category",
1020
- {
1021
- key: z4.string().describe(
1022
- "Category key: gamefi,anonymous,market,web,newcoin,stable,defi"
1023
- ),
1024
- currency: z4.string().optional().describe("Currency: cny or usd"),
1025
- ...maxItemsParam
1026
- },
1027
- async ({ key, currency, _max_items }) => {
1028
- try {
1029
- const params = { key };
1030
- if (currency) params.currency = currency;
1031
- return okList(
1032
- await apiGet(
1033
- "/api/v2/market/hotTabCoins",
1034
- params
1035
- ),
1036
- parseMax(_max_items, 20)
1037
- );
1038
- } catch (e) {
1039
- return err(e);
1040
- }
1041
- }
1042
- );
1043
- server2.tool(
1044
- "get_crypto_company_info",
1045
- "Get crypto-related company details by stock symbol",
1046
- {
1047
- symbol: z4.string().describe(
1048
- "Symbol in i:ticker:market format, e.g. i:mstr:nasdaq"
1049
- )
1050
- },
1051
- async ({ symbol }) => {
1052
- try {
1053
- return ok(
1054
- await apiGet(
1055
- `/api/upgrade/v2/crypto_stock/company/${symbol}`
1056
- )
1057
- );
1058
- } catch (e) {
1059
- return err(e);
1060
- }
1061
- }
1062
- );
1063
- server2.tool(
1064
- "get_index_info",
1065
- "Get index detail information",
1066
- {
1067
- key: z4.string().describe("Index key, e.g. i:diniw:ice"),
1068
- lan: z4.string().optional().describe("Language: en or cn")
1069
- },
1070
- async ({ key, lan }) => {
1071
- try {
1072
- const params = { key };
1073
- if (lan) params.lan = lan;
1074
- return ok(
1075
- await apiGet("/api/v2/index/indexInfo", params)
1076
- );
1077
- } catch (e) {
1078
- return err(e);
1079
- }
1080
- }
1081
- );
1082
- server2.tool(
1083
- "get_index_list",
1084
- "Get list of all available indexes",
1085
- { ...maxItemsParam },
1086
- async ({ _max_items }) => {
1087
- try {
1088
- return okList(
1089
- await apiGet("/api/v2/index/getIndex"),
1090
- parseMax(_max_items, 20)
1091
- );
1092
- } catch (e) {
1093
- return err(e);
1094
- }
1095
- }
1096
- );
1097
- server2.tool(
1098
- "get_indicator_kline_trading_pair",
1099
- "Get trading pairs for indicator K-line",
1100
- {
1101
- coinType: z4.string().optional().describe("Coin type, e.g. bitcoin"),
1102
- indicator_key: z4.string().optional().describe(
1103
- "Indicator key: fundflow,aiaggtrade,fr,etc."
1104
- )
1105
- },
1106
- async ({ coinType, indicator_key }) => {
1107
- try {
1108
- const params = {};
1109
- if (coinType) params.coinType = coinType;
1110
- if (indicator_key)
1111
- params.indicator_key = indicator_key;
1112
- return ok(
1113
- await apiGet(
1114
- "/api/v2/indicatorKline/getTradingPair",
1115
- params
1116
- )
1117
- );
1118
- } catch (e) {
1119
- return err(e);
1120
- }
1121
- }
1122
- );
1123
- server2.tool(
1124
- "get_indicator_kline_data",
1125
- "Get indicator K-line data records",
1126
- {
1127
- symbol: z4.string().describe(
1128
- "Trading pair, e.g. btcswapusdt:binance"
1129
- ),
1130
- indicator_key: z4.string().describe(
1131
- "Indicator key: fundflow, aiaggtrade, fr, etc."
1132
- ),
1133
- period: z4.string().optional().describe(
1134
- "Period in seconds: 900=15min, 3600=1h, 14400=4h, 86400=1d"
1135
- ),
1136
- size: z4.string().optional().describe("Number of records, 1-500"),
1137
- since: z4.string().optional().describe("Start timestamp"),
1138
- open_time: z4.string().optional().describe("Open time offset: 0 or 8")
1139
- },
1140
- async ({
1141
- symbol,
1142
- indicator_key,
1143
- period,
1144
- size,
1145
- since,
1146
- open_time
1147
- }) => {
1148
- try {
1149
- const params = {
1150
- symbol,
1151
- indicator_key
1152
- };
1153
- if (period) params.period = period;
1154
- params.size = size ?? "100";
1155
- if (since) params.since = since;
1156
- if (open_time) params.open_time = open_time;
1157
- return ok(
1158
- await apiGet(
1159
- "/api/v2/indicatorKline/dataRecords",
1160
- params
1161
- )
1162
- );
1163
- } catch (e) {
1164
- return err(e);
1165
- }
1166
- }
1167
- );
1168
- server2.tool(
1169
- "get_coin_treasury_entities",
1170
- "Get coin treasury entity data (e.g. MicroStrategy BTC holdings)",
1171
- {
1172
- coin: z4.string().describe("Coin ticker, e.g. BTC, ETH"),
1173
- entity_type: z4.string().optional().describe(
1174
- "Entity type: public-companies, eth-treasuries, etc."
1175
- ),
1176
- name: z4.string().optional().describe("Entity name fuzzy search"),
1177
- ticker: z4.string().optional().describe("Stock ticker filter"),
1178
- start_date: z4.string().optional().describe("Start date, ISO 8601"),
1179
- end_date: z4.string().optional().describe("End date, ISO 8601"),
1180
- page: z4.string().optional().describe("Page number, default 1"),
1181
- page_size: z4.string().optional().describe("Page size, default 20, max 100"),
1182
- sort_order: z4.string().optional().describe("Sort: asc or desc, default desc")
1183
- },
1184
- async ({
1185
- coin,
1186
- entity_type,
1187
- name,
1188
- ticker,
1189
- start_date,
1190
- end_date,
1191
- page,
1192
- page_size,
1193
- sort_order
1194
- }) => {
1195
- try {
1196
- const body = { coin };
1197
- if (entity_type) body.entity_type = entity_type;
1198
- if (name) body.name = name;
1199
- if (ticker) body.ticker = ticker;
1200
- if (start_date) body.start_date = start_date;
1201
- if (end_date) body.end_date = end_date;
1202
- if (page) body.page = Number(page);
1203
- if (page_size)
1204
- body.page_size = Number(page_size);
1205
- if (sort_order) body.sort_order = sort_order;
1206
- return ok(
1207
- await apiPost(
1208
- "/api/upgrade/v2/coin-treasuries/entities",
1209
- body
1210
- )
1211
- );
1212
- } catch (e) {
1213
- return err(e);
1214
- }
1215
- }
1216
- );
1217
- server2.tool(
1218
- "get_coin_treasury_history",
1219
- "Get coin treasury historical data",
1220
- {
1221
- coin: z4.string().describe("Coin ticker, e.g. BTC, ETH"),
1222
- name: z4.string().optional().describe("Entity name filter"),
1223
- type: z4.string().optional().describe("Trade type: Buy or Sell"),
1224
- start_date: z4.string().optional().describe("Start date, ISO 8601"),
1225
- end_date: z4.string().optional().describe("End date, ISO 8601"),
1226
- page: z4.string().optional().describe("Page number, default 1"),
1227
- page_size: z4.string().optional().describe("Page size, default 20"),
1228
- sort_by: z4.string().optional().describe("Sort field, default date"),
1229
- sort_order: z4.string().optional().describe("Sort: asc or desc, default desc")
1230
- },
1231
- async ({
1232
- coin,
1233
- name,
1234
- type,
1235
- start_date,
1236
- end_date,
1237
- page,
1238
- page_size,
1239
- sort_by,
1240
- sort_order
1241
- }) => {
1242
- try {
1243
- const body = { coin };
1244
- if (name) body.name = name;
1245
- if (type) body.type = type;
1246
- if (start_date) body.start_date = start_date;
1247
- if (end_date) body.end_date = end_date;
1248
- if (page) body.page = Number(page);
1249
- if (page_size)
1250
- body.page_size = Number(page_size);
1251
- if (sort_by) body.sort_by = sort_by;
1252
- if (sort_order) body.sort_order = sort_order;
1253
- return ok(
1254
- await apiPost(
1255
- "/api/upgrade/v2/coin-treasuries/history",
1256
- body
1257
- )
1258
- );
1259
- } catch (e) {
1260
- return err(e);
1261
- }
1262
- }
1263
- );
1264
- server2.tool(
1265
- "get_coin_treasury_accumulated",
1266
- "Get accumulated coin treasury historical data",
1267
- {
1268
- coin: z4.string().describe("Coin ticker, e.g. BTC, ETH"),
1269
- entity_type: z4.string().optional().describe("Entity type filter"),
1270
- start_date: z4.string().optional().describe("Start date, ISO 8601"),
1271
- end_date: z4.string().optional().describe("End date, ISO 8601"),
1272
- interval: z4.string().optional().describe(
1273
- "Interval: daily, weekly, or monthly"
1274
- )
1275
- },
1276
- async ({
1277
- coin,
1278
- entity_type,
1279
- start_date,
1280
- end_date,
1281
- interval
1282
- }) => {
1283
- try {
1284
- const body = { coin };
1285
- if (entity_type)
1286
- body.entity_type = entity_type;
1287
- if (start_date)
1288
- body.start_date = start_date;
1289
- if (end_date) body.end_date = end_date;
1290
- if (interval) body.interval = interval;
1291
- return ok(
1292
- await apiPost(
1293
- "/api/upgrade/v2/coin-treasuries/history/accumulated",
1294
- body
1295
- )
1296
- );
1297
- } catch (e) {
1298
- return err(e);
1299
- }
1300
- }
1301
- );
1302
- server2.tool(
1303
- "get_latest_coin_treasury_entities",
1304
- "Get latest coin treasury entity data",
1305
- {
1306
- coin: z4.string().describe("Coin ticker, e.g. BTC, ETH"),
1307
- ...maxItemsParam
1308
- },
1309
- async ({ coin, _max_items }) => {
1310
- try {
1311
- return okList(
1312
- await apiGet(
1313
- "/api/upgrade/v2/coin-treasuries/latest/entities",
1314
- { coin }
1315
- ),
1316
- parseMax(_max_items, 20)
1317
- );
1318
- } catch (e) {
1319
- return err(e);
1320
- }
1321
- }
1322
- );
1323
- server2.tool(
1324
- "get_latest_coin_treasury_history",
1325
- "Get latest coin treasury history data",
1326
- {
1327
- coin: z4.string().describe("Coin ticker, e.g. BTC, ETH"),
1328
- ...maxItemsParam
1329
- },
1330
- async ({ coin, _max_items }) => {
1331
- try {
1332
- return okList(
1333
- await apiGet(
1334
- "/api/upgrade/v2/coin-treasuries/latest/history",
1335
- { coin }
1336
- ),
1337
- parseMax(_max_items, 20)
1338
- );
1339
- } catch (e) {
1340
- return err(e);
1341
- }
1342
- }
1343
- );
1344
- server2.tool(
1345
- "get_coin_treasury_summary",
1346
- "Get coin treasury data summary",
1347
- {
1348
- coin: z4.string().describe("Coin ticker, e.g. BTC, ETH")
1349
- },
1350
- async ({ coin }) => {
1351
- try {
1352
- return ok(
1353
- await apiGet(
1354
- "/api/upgrade/v2/coin-treasuries/summary",
1355
- { coin }
1356
- )
1357
- );
1358
- } catch (e) {
1359
- return err(e);
1360
- }
1361
- }
1362
- );
1363
- server2.tool(
1364
- "get_latest_depth",
1365
- "Get latest order book depth snapshot from Redis",
1366
- {
1367
- dbKey: z4.string().describe(
1368
- "Trading pair key, e.g. btcusdt:binance, ethusdt:okex"
1369
- ),
1370
- size: z4.string().optional().describe(
1371
- "Number of depth levels, 1-500, default 50"
1372
- )
1373
- },
1374
- async ({ dbKey, size }) => {
1375
- try {
1376
- const params = {
1377
- dbKey
1378
- };
1379
- if (size) params.size = size;
1380
- return ok(
1381
- await apiGet(
1382
- "/api/upgrade/v2/futures/latest-depth",
1383
- params
1384
- )
1385
- );
1386
- } catch (e) {
1387
- return err(e);
1388
- }
1389
- }
1390
- );
1391
- server2.tool(
1392
- "get_full_depth",
1393
- "Get full order book depth data for futures",
1394
- {
1395
- dbKey: z4.string().describe(
1396
- "Trading pair key, e.g. btcswapusd:hbdm, btcswapusdt:binance"
1397
- ),
1398
- ...maxItemsParam
1399
- },
1400
- async ({ dbKey, _max_items }) => {
1401
- try {
1402
- return okDepth(
1403
- await apiGet(
1404
- "/api/upgrade/v2/futures/full-depth",
1405
- { dbKey }
1406
- ),
1407
- parseMax(_max_items, 50)
1408
- );
1409
- } catch (e) {
1410
- return err(e);
1411
- }
1412
- }
1413
- );
1414
- server2.tool(
1415
- "get_full_depth_grouped",
1416
- "Get full depth data grouped by price interval",
1417
- {
1418
- dbKey: z4.string().describe(
1419
- "Trading pair key, e.g. btcswapusd:hbdm, btcswapusdt:binance"
1420
- ),
1421
- groupSize: z4.string().describe(
1422
- "Price grouping interval, e.g. 100, 500, 1000"
1423
- ),
1424
- ...maxItemsParam
1425
- },
1426
- async ({ dbKey, groupSize, _max_items }) => {
1427
- try {
1428
- return okDepth(
1429
- await apiGet(
1430
- "/api/upgrade/v2/futures/full-depth/grouped",
1431
- { dbKey, groupSize }
1432
- ),
1433
- parseMax(_max_items, 50)
1434
- );
1435
- } catch (e) {
1436
- return err(e);
1437
- }
1438
- }
1439
- );
1440
- }
1441
-
1442
- // src/tools/features.ts
1443
- import { z as z5 } from "zod";
1444
- function registerFeatureTools(server2) {
1445
- server2.tool(
1446
- "get_ls_ratio",
1447
- "Get long/short ratio data",
1448
- {},
1449
- async () => {
1450
- try {
1451
- return ok(
1452
- await apiGet("/api/v2/mix/ls-ratio")
1453
- );
1454
- } catch (e) {
1455
- return err(e);
1456
- }
1457
- }
1458
- );
1459
- server2.tool(
1460
- "get_liquidation_data",
1461
- "Get liquidation/forced-close data",
1462
- {
1463
- currency: z5.string().optional().describe("Currency: cny or usd, default cny"),
1464
- type: z5.string().optional().describe(
1465
- "Query type: 1=by coin, 2=by platform"
1466
- ),
1467
- coinKey: z5.string().optional().describe("Coin key, used when type=1"),
1468
- marketKey: z5.string().optional().describe("Market key, used when type=2")
1469
- },
1470
- async ({ currency, type, coinKey, marketKey }) => {
1471
- try {
1472
- const params = {};
1473
- if (currency) params.currency = currency;
1474
- if (type) params.type = type;
1475
- if (coinKey) params.coinKey = coinKey;
1476
- if (marketKey) params.marketKey = marketKey;
1477
- return ok(
1478
- await apiGet("/api/v2/mix/liq", params)
1479
- );
1480
- } catch (e) {
1481
- return err(e);
1482
- }
1483
- }
1484
- );
1485
- server2.tool(
1486
- "get_big_orders",
1487
- "Get whale/large order tracking data",
1488
- {
1489
- symbol: z5.string().describe(
1490
- "Trading pair, e.g. btcusdt:okex"
1491
- ),
1492
- ...maxItemsParam
1493
- },
1494
- async ({ symbol, _max_items }) => {
1495
- try {
1496
- return okList(
1497
- await apiGet("/api/v2/order/bigOrder", {
1498
- symbol
1499
- }),
1500
- parseMax(_max_items, 20)
1501
- );
1502
- } catch (e) {
1503
- return err(e);
1504
- }
1505
- }
1506
- );
1507
- server2.tool(
1508
- "get_agg_trades",
1509
- "Get aggregated large trades data",
1510
- {
1511
- symbol: z5.string().describe(
1512
- "Trading pair, e.g. btcusdt:okex"
1513
- ),
1514
- ...maxItemsParam
1515
- },
1516
- async ({ symbol, _max_items }) => {
1517
- try {
1518
- return okList(
1519
- await apiGet("/api/v2/order/aggTrade", {
1520
- symbol
1521
- }),
1522
- parseMax(_max_items, 30)
1523
- );
1524
- } catch (e) {
1525
- return err(e);
1526
- }
1527
- }
1528
- );
1529
- server2.tool(
1530
- "get_trading_pair_ticker",
1531
- "Get ticker data for specific trading pairs",
1532
- {
1533
- key_list: z5.string().describe(
1534
- "Trading pair keys, comma-separated, max 100, e.g. btcusdt:okex,btcusdt:huobipro"
1535
- )
1536
- },
1537
- async ({ key_list }) => {
1538
- try {
1539
- return ok(
1540
- await apiGet("/api/v2/trading-pair/ticker", {
1541
- key_list
1542
- })
1543
- );
1544
- } catch (e) {
1545
- return err(e);
1546
- }
1547
- }
1548
- );
1549
- server2.tool(
1550
- "get_strategy_signal",
1551
- "Get indicator win-rate signal data",
1552
- {
1553
- coin_type: z5.string().optional().describe("Coin type, e.g. bitcoin"),
1554
- signal_key: z5.string().optional().describe(
1555
- "Signal key: depth_win_one,depth_win_two,depth_buy_one,order_buy_one,td_buy_one,lsur_one"
1556
- ),
1557
- latest_time: z5.string().optional().describe("Latest time in ms timestamp"),
1558
- ...maxItemsParam
1559
- },
1560
- async ({ coin_type, signal_key, latest_time, _max_items }) => {
1561
- try {
1562
- const params = {};
1563
- if (coin_type) params.coin_type = coin_type;
1564
- if (signal_key) params.signal_key = signal_key;
1565
- if (latest_time)
1566
- params.latest_time = latest_time;
1567
- return okList(
1568
- await apiGet(
1569
- "/api/v2/signal/strategySignal",
1570
- params
1571
- ),
1572
- parseMax(_max_items, 20)
1573
- );
1574
- } catch (e) {
1575
- return err(e);
1576
- }
1577
- }
1578
- );
1579
- server2.tool(
1580
- "get_nav",
1581
- "Get navigation bar data (market overview)",
1582
- {
1583
- lan: z5.string().optional().describe("Language: cn or en")
1584
- },
1585
- async ({ lan }) => {
1586
- try {
1587
- const params = {};
1588
- if (lan) params.lan = lan;
1589
- return ok(
1590
- await apiGet("/api/v2/mix/nav", params)
1591
- );
1592
- } catch (e) {
1593
- return err(e);
1594
- }
1595
- }
1596
- );
1597
- server2.tool(
1598
- "get_grayscale_trust",
1599
- "Get Grayscale trust fund data",
1600
- {},
1601
- async () => {
1602
- try {
1603
- return ok(
1604
- await apiGet("/api/v2/mix/grayscale-trust")
1605
- );
1606
- } catch (e) {
1607
- return err(e);
1608
- }
1609
- }
1610
- );
1611
- server2.tool(
1612
- "get_gray_scale",
1613
- "Get Grayscale holdings data",
1614
- {
1615
- coins: z5.string().describe(
1616
- "Coin list, comma-separated: btc,ltc,eth,bch,xrp,xlm,zec,zen,etc"
1617
- )
1618
- },
1619
- async ({ coins }) => {
1620
- try {
1621
- return ok(
1622
- await apiGet("/api/v2/mix/gray-scale", {
1623
- coins
1624
- })
1625
- );
1626
- } catch (e) {
1627
- return err(e);
1628
- }
1629
- }
1630
- );
1631
- server2.tool(
1632
- "get_stock_market",
1633
- "Get stock market data (crypto-related)",
1634
- { ...maxItemsParam },
1635
- async ({ _max_items }) => {
1636
- try {
1637
- return okList(
1638
- await apiGet("/api/v2/mix/stock-market"),
1639
- parseMax(_max_items, 50)
1640
- );
1641
- } catch (e) {
1642
- return err(e);
1643
- }
1644
- }
1645
- );
1646
- server2.tool(
1647
- "get_signal_alert",
1648
- "Get signal alert data",
1649
- { ...maxItemsParam },
1650
- async ({ _max_items }) => {
1651
- try {
1652
- return okList(
1653
- await apiGet(
1654
- "/api/v2/signal/signalAlert"
1655
- ),
1656
- parseMax(_max_items, 20)
1657
- );
1658
- } catch (e) {
1659
- return err(e);
1660
- }
1661
- }
1662
- );
1663
- server2.tool(
1664
- "get_signal_alert_config",
1665
- "Get signal alert configuration options",
1666
- {
1667
- lan: z5.string().optional().describe("Language: cn or en"),
1668
- ...maxItemsParam
1669
- },
1670
- async ({ lan, _max_items }) => {
1671
- try {
1672
- const params = {};
1673
- if (lan) params.lan = lan;
1674
- return okList(
1675
- await apiGet(
1676
- "/api/v2/signal/signalAlertConf",
1677
- params
1678
- ),
1679
- parseMax(_max_items, 20)
1680
- );
1681
- } catch (e) {
1682
- return err(e);
1683
- }
1684
- }
1685
- );
1686
- server2.tool(
1687
- "delete_signal_alert",
1688
- "Delete a signal alert by ID",
1689
- {
1690
- id: z5.string().describe("Signal alert ID")
1691
- },
1692
- async ({ id }) => {
1693
- try {
1694
- return ok(
1695
- await apiGet(
1696
- "/api/v2/signal/delSignalAlert",
1697
- { id }
1698
- )
1699
- );
1700
- } catch (e) {
1701
- return err(e);
1702
- }
1703
- }
1704
- );
1705
- server2.tool(
1706
- "add_signal_alert",
1707
- "Add a new signal alert",
1708
- {
1709
- subType: z5.string().describe("Alert sub type"),
1710
- symbol: z5.string().describe("Trading pair symbol"),
1711
- remark: z5.string().optional().describe("Alert remark/note")
1712
- },
1713
- async ({ subType, symbol, remark }) => {
1714
- try {
1715
- const params = {
1716
- subType,
1717
- symbol
1718
- };
1719
- if (remark) params.remark = remark;
1720
- return ok(
1721
- await apiGet(
1722
- "/api/v2/signal/addSignalAlert",
1723
- params
1724
- )
1725
- );
1726
- } catch (e) {
1727
- return err(e);
1728
- }
1729
- }
1730
- );
1731
- server2.tool(
1732
- "get_signal_alert_list",
1733
- "Get signal alert settings list",
1734
- {},
1735
- async () => {
1736
- try {
1737
- return ok(
1738
- await apiGet(
1739
- "/api/v2/signal/getSignalAlertSetList"
1740
- )
1741
- );
1742
- } catch (e) {
1743
- return err(e);
1744
- }
1745
- }
1746
- );
1747
- server2.tool(
1748
- "get_change_signal",
1749
- "Get abnormal movement signal data",
1750
- {
1751
- type: z5.string().optional().describe(
1752
- "Signal type: 1-12, 17, 18, 23, 24"
1753
- ),
1754
- currency: z5.string().optional().describe("Currency: usd (default) or cny"),
1755
- ...maxItemsParam
1756
- },
1757
- async ({ type, currency, _max_items }) => {
1758
- try {
1759
- const params = {};
1760
- if (type) params.type = type;
1761
- if (currency) params.currency = currency;
1762
- return okList(
1763
- await apiGet(
1764
- "/api/v2/signal/changeSignal",
1765
- params
1766
- ),
1767
- parseMax(_max_items, 50)
1768
- );
1769
- } catch (e) {
1770
- return err(e);
1771
- }
1772
- }
1773
- );
1774
- server2.tool(
1775
- "get_trading_pair",
1776
- "Get trading pair info for a platform",
1777
- {
1778
- market: z5.string().describe(
1779
- "Platform key (from get_markets), e.g. okex, binance"
1780
- ),
1781
- ...maxItemsParam
1782
- },
1783
- async ({ market, _max_items }) => {
1784
- try {
1785
- return okList(
1786
- await apiGet(
1787
- "/api/v2/trading-pair/getTradingPair",
1788
- { market }
1789
- ),
1790
- parseMax(_max_items, 50)
1791
- );
1792
- } catch (e) {
1793
- return err(e);
1794
- }
1795
- }
1796
- );
1797
- server2.tool(
1798
- "get_trading_pairs",
1799
- "Get trading pair list for a platform",
1800
- {
1801
- market: z5.string().describe(
1802
- "Platform key (from /v2/market), e.g. okex, binance"
1803
- ),
1804
- currency: z5.string().optional().describe("Quote currency filter"),
1805
- show: z5.string().optional().describe("Coin symbol filter"),
1806
- ...maxItemsParam
1807
- },
1808
- async ({ market, currency, show, _max_items }) => {
1809
- try {
1810
- const params = {
1811
- market
1812
- };
1813
- if (currency) params.currency = currency;
1814
- if (show) params.show = show;
1815
- return okList(
1816
- await apiGet("/api/v2/trading-pair", params),
1817
- parseMax(_max_items, 100)
1818
- );
1819
- } catch (e) {
1820
- return err(e);
1821
- }
1822
- }
1823
- );
1824
- }
1825
-
1826
- // src/tools/hyperliquid.ts
1827
- import { z as z6 } from "zod";
1828
- function registerHyperliquidTools(server2) {
1829
- server2.tool(
1830
- "hl_get_tickers",
1831
- "Get Hyperliquid ticker data (truncated to top 50, use hl_get_ticker_by_coin for specific coin)",
1832
- { ...maxItemsParam },
1833
- async ({ _max_items }) => {
1834
- try {
1835
- return okList(
1836
- await apiGet("/api/upgrade/v2/hl/tickers"),
1837
- parseMax(_max_items, 50)
1838
- );
1839
- } catch (e) {
1840
- return err(e);
1841
- }
1842
- }
1843
- );
1844
- server2.tool(
1845
- "hl_get_ticker_by_coin",
1846
- "Get Hyperliquid ticker for a specific coin",
1847
- {
1848
- coin: z6.string().describe("Coin symbol, e.g. BTC, ETH")
1849
- },
1850
- async ({ coin }) => {
1851
- try {
1852
- return ok(
1853
- await apiGet(`/api/upgrade/v2/hl/tickers/coin/${coin}`)
1854
- );
1855
- } catch (e) {
1856
- return err(e);
1857
- }
1858
- }
1859
- );
1860
- server2.tool(
1861
- "hl_get_whale_positions",
1862
- "Get Hyperliquid whale open positions",
1863
- {
1864
- coin: z6.string().optional().describe("Coin filter, e.g. BTC"),
1865
- min_usd: z6.string().optional().describe("Min position size in USD"),
1866
- ...maxItemsParam
1867
- },
1868
- async ({ coin, min_usd, _max_items }) => {
1869
- try {
1870
- const params = {};
1871
- if (coin) params.coin = coin;
1872
- if (min_usd) params.min_usd = min_usd;
1873
- return okList(
1874
- await apiGet(
1875
- "/api/upgrade/v2/hl/whales/open-positions",
1876
- params
1877
- ),
1878
- parseMax(_max_items, 50)
1879
- );
1880
- } catch (e) {
1881
- return err(e);
1882
- }
1883
- }
1884
- );
1885
- server2.tool(
1886
- "hl_get_liquidations",
1887
- "Get Hyperliquid liquidation history",
1888
- {
1889
- coin: z6.string().optional().describe("Coin filter"),
1890
- ...maxItemsParam
1891
- },
1892
- async ({ coin, _max_items }) => {
1893
- try {
1894
- const params = {};
1895
- if (coin) params.coin = coin;
1896
- return okList(
1897
- await apiGet(
1898
- "/api/upgrade/v2/hl/liquidations/history",
1899
- params
1900
- ),
1901
- parseMax(_max_items, 50)
1902
- );
1903
- } catch (e) {
1904
- return err(e);
1905
- }
1906
- }
1907
- );
1908
- server2.tool(
1909
- "hl_get_trader_stats",
1910
- "Get Hyperliquid trader statistics by address",
1911
- {
1912
- address: z6.string().describe("Wallet address, e.g. 0x..."),
1913
- period: z6.string().optional().describe("Period in days, e.g. 7, 30")
1914
- },
1915
- async ({ address, period }) => {
1916
- try {
1917
- const params = {};
1918
- if (period) params.period = period;
1919
- return ok(
1920
- await apiGet(
1921
- `/api/upgrade/v2/hl/traders/${address}/addr-stat`,
1922
- params
1923
- )
1924
- );
1925
- } catch (e) {
1926
- return err(e);
1927
- }
1928
- }
1929
- );
1930
- server2.tool(
1931
- "hl_info",
1932
- "Generic Hyperliquid Info API (supports all info types)",
1933
- {
1934
- type: z6.string().describe(
1935
- "Info type, e.g. metaAndAssetCtxs, clearinghouseState, spotMeta, allMids, l2Book, openOrders, userFills, candleSnapshot"
1936
- ),
1937
- user: z6.string().optional().describe("User wallet address (for user-specific queries)"),
1938
- extra_params: z6.string().optional().describe('Extra params as JSON string, e.g. {"coin":"BTC"}'),
1939
- ...maxItemsParam
1940
- },
1941
- async ({ type, user, extra_params, _max_items }) => {
1942
- try {
1943
- const body = { type };
1944
- if (user) body.user = user;
1945
- if (extra_params) {
1946
- Object.assign(body, JSON.parse(extra_params));
1947
- }
1948
- return okList(
1949
- await apiPost("/api/upgrade/v2/hl/info", body),
1950
- parseMax(_max_items, 20)
1951
- );
1952
- } catch (e) {
1953
- return err(e);
1954
- }
1955
- }
1956
- );
1957
- server2.tool(
1958
- "hl_get_fills_by_address",
1959
- "Get Hyperliquid user trade fills by wallet address",
1960
- {
1961
- address: z6.string().describe("Wallet address, e.g. 0x..."),
1962
- coin: z6.string().optional().describe("Coin filter, e.g. BTC"),
1963
- limit: z6.string().optional().describe("Max results"),
1964
- ...maxItemsParam
1965
- },
1966
- async ({ address, coin, limit, _max_items }) => {
1967
- try {
1968
- const params = {};
1969
- if (coin) params.coin = coin;
1970
- if (limit) params.limit = limit;
1971
- return okList(
1972
- await apiGet(
1973
- `/api/upgrade/v2/hl/fills/${address}`,
1974
- params
1975
- ),
1976
- parseMax(_max_items, 50)
1977
- );
1978
- } catch (e) {
1979
- return err(e);
1980
- }
1981
- }
1982
- );
1983
- server2.tool(
1984
- "hl_get_fills_by_oid",
1985
- "Get Hyperliquid trade fills by order ID",
1986
- {
1987
- oid: z6.string().describe("Order ID")
1988
- },
1989
- async ({ oid }) => {
1990
- try {
1991
- return ok(
1992
- await apiGet(`/api/upgrade/v2/hl/fills/oid/${oid}`)
1993
- );
1994
- } catch (e) {
1995
- return err(e);
1996
- }
1997
- }
1998
- );
1999
- server2.tool(
2000
- "hl_get_fills_by_twapid",
2001
- "Get Hyperliquid trade fills by TWAP ID",
2002
- {
2003
- twapid: z6.string().describe("TWAP ID")
2004
- },
2005
- async ({ twapid }) => {
2006
- try {
2007
- return ok(
2008
- await apiGet(
2009
- `/api/upgrade/v2/hl/fills/twapid/${twapid}`
2010
- )
2011
- );
2012
- } catch (e) {
2013
- return err(e);
2014
- }
2015
- }
2016
- );
2017
- server2.tool(
2018
- "hl_get_top_trades",
2019
- "Get Hyperliquid top trades",
2020
- {
2021
- coin: z6.string().optional().describe("Coin filter, e.g. BTC"),
2022
- interval: z6.string().optional().describe("Interval, e.g. 4h, 1d"),
2023
- limit: z6.string().optional().describe("Max results"),
2024
- ...maxItemsParam
2025
- },
2026
- async ({ coin, interval, limit, _max_items }) => {
2027
- try {
2028
- const params = {};
2029
- if (coin) params.coin = coin;
2030
- if (interval) params.interval = interval;
2031
- if (limit) params.limit = limit;
2032
- return okList(
2033
- await apiGet(
2034
- "/api/upgrade/v2/hl/fills/top-trades",
2035
- params
2036
- ),
2037
- parseMax(_max_items, 50)
2038
- );
2039
- } catch (e) {
2040
- return err(e);
2041
- }
2042
- }
2043
- );
2044
- server2.tool(
2045
- "hl_get_filled_orders",
2046
- "Get filled orders by wallet address",
2047
- {
2048
- address: z6.string().describe("Wallet address"),
2049
- coin: z6.string().optional().describe("Coin filter, e.g. BTC"),
2050
- limit: z6.string().optional().describe("Max results, default 1000"),
2051
- ...maxItemsParam
2052
- },
2053
- async ({ address, coin, limit, _max_items }) => {
2054
- try {
2055
- const params = {};
2056
- if (coin) params.coin = coin;
2057
- if (limit) params.limit = limit;
2058
- return okList(
2059
- await apiGet(
2060
- `/api/upgrade/v2/hl/filled-orders/${address}/latest`,
2061
- params
2062
- ),
2063
- parseMax(_max_items, 50)
2064
- );
2065
- } catch (e) {
2066
- return err(e);
2067
- }
2068
- }
2069
- );
2070
- server2.tool(
2071
- "hl_get_filled_order_by_oid",
2072
- "Get filled order by order ID",
2073
- {
2074
- oid: z6.string().describe("Order ID")
2075
- },
2076
- async ({ oid }) => {
2077
- try {
2078
- return ok(
2079
- await apiGet(
2080
- `/api/upgrade/v2/hl/filled-orders/oid/${oid}`
2081
- )
2082
- );
2083
- } catch (e) {
2084
- return err(e);
2085
- }
2086
- }
2087
- );
2088
- server2.tool(
2089
- "hl_get_orders",
2090
- "Get latest orders by wallet address",
2091
- {
2092
- address: z6.string().describe("Wallet address"),
2093
- coin: z6.string().optional().describe("Coin filter, e.g. BTC"),
2094
- limit: z6.string().optional().describe("Max results, default 2000"),
2095
- ...maxItemsParam
2096
- },
2097
- async ({ address, coin, limit, _max_items }) => {
2098
- try {
2099
- const params = {};
2100
- if (coin) params.coin = coin;
2101
- if (limit) params.limit = limit;
2102
- return okList(
2103
- await apiGet(
2104
- `/api/upgrade/v2/hl/orders/${address}/latest`,
2105
- params
2106
- ),
2107
- parseMax(_max_items, 50)
2108
- );
2109
- } catch (e) {
2110
- return err(e);
2111
- }
2112
- }
2113
- );
2114
- server2.tool(
2115
- "hl_get_order_by_oid",
2116
- "Get order by order ID",
2117
- {
2118
- oid: z6.string().describe("Order ID")
2119
- },
2120
- async ({ oid }) => {
2121
- try {
2122
- return ok(
2123
- await apiGet(`/api/upgrade/v2/hl/orders/oid/${oid}`)
2124
- );
2125
- } catch (e) {
2126
- return err(e);
2127
- }
2128
- }
2129
- );
2130
- server2.tool(
2131
- "hl_get_top_open_orders",
2132
- "Get top open orders on Hyperliquid",
2133
- {
2134
- coin: z6.string().optional().describe("Coin filter"),
2135
- min_val: z6.string().optional().describe("Min order value filter"),
2136
- limit: z6.string().optional().describe("Max results"),
2137
- ...maxItemsParam
452
+ symbol: z2.string().describe("REQUIRED. Coin symbol in uppercase, e.g. BTC, ETH"),
453
+ interval: z2.string().describe("REQUIRED. Candle interval: 1m, 2m, 15m, 30m"),
454
+ margin_type: z2.enum(["stablecoin", "coin"]).default("stablecoin").describe(
455
+ "stablecoin: stablecoin-margined OI; coin: coin-margined OI"
456
+ ),
457
+ limit: z2.string().optional().describe("Number of records, default 100"),
458
+ start_time: z2.string().optional().describe("Start time in ms"),
459
+ end_time: z2.string().optional().describe("End time in ms")
2138
460
  },
2139
- async ({ coin, min_val, limit, _max_items }) => {
461
+ async ({ symbol, interval, margin_type, limit, start_time, end_time }) => {
2140
462
  try {
2141
- const params = {};
2142
- if (coin) params.coin = coin;
2143
- if (min_val) params.min_val = min_val;
2144
- if (limit) params.limit = limit;
2145
- return okList(
2146
- await apiGet(
2147
- "/api/upgrade/v2/hl/orders/top-open-orders",
2148
- params
2149
- ),
2150
- parseMax(_max_items, 50)
2151
- );
463
+ const params = { symbol, interval };
464
+ params.limit = limit ?? "100";
465
+ if (start_time) params.start_time = start_time;
466
+ if (end_time) params.end_time = end_time;
467
+ const path = margin_type === "coin" ? "/api/upgrade/v2/futures/open-interest/aggregated-coin-margin-history" : "/api/upgrade/v2/futures/open-interest/aggregated-stablecoin-history";
468
+ return ok(await apiGet(path, params));
2152
469
  } catch (e) {
2153
470
  return err(e);
2154
471
  }
2155
472
  }
2156
473
  );
2157
474
  server2.tool(
2158
- "hl_get_active_stats",
2159
- "Get active order statistics",
475
+ "coin_futures_data",
476
+ "Futures depth & trade data.\n\u2022 historical_depth \u2014 order book history. Requires: key\n\u2022 super_depth \u2014 large orders >$10k. Requires: key\n\u2022 trade_data \u2014 latest trades. Requires: dbkey (NOT key)",
2160
477
  {
2161
- coin: z6.string().optional().describe("Coin filter"),
2162
- whale_threshold: z6.string().optional().describe(
2163
- "Whale threshold (order value limitPx * sz)"
2164
- )
478
+ action: z2.enum(["historical_depth", "super_depth", "trade_data"]).describe(
479
+ "historical_depth: order book history; super_depth: large order depth; trade_data: latest trade data"
480
+ ),
481
+ key: z2.string().optional().describe("REQUIRED for historical_depth, super_depth. Trading pair key, e.g. btcswapusdt:okcoinfutures. NOT used by trade_data"),
482
+ dbkey: z2.string().optional().describe("REQUIRED for trade_data. Trading pair key, e.g. btcswapusdt:okcoinfutures. NOT used by historical_depth/super_depth"),
483
+ amount: z2.string().optional().describe("For super_depth: USD threshold, default 10000"),
484
+ limit: z2.string().optional().describe("Number of records, max 1000"),
485
+ start_time: z2.string().optional().describe("Start time in ms"),
486
+ end_time: z2.string().optional().describe("End time in ms")
2165
487
  },
2166
- async ({ coin, whale_threshold }) => {
488
+ async ({ action, key, dbkey, amount, limit, start_time, end_time }) => {
2167
489
  try {
2168
- const params = {};
2169
- if (coin) params.coin = coin;
2170
- if (whale_threshold)
2171
- params.whale_threshold = whale_threshold;
2172
- return ok(
2173
- await apiGet(
2174
- "/api/upgrade/v2/hl/orders/active-stats",
2175
- params
2176
- )
2177
- );
490
+ switch (action) {
491
+ case "historical_depth": {
492
+ if (!key) return err("key is required for historical_depth action");
493
+ const params = { key };
494
+ params.limit = limit ?? "100";
495
+ if (start_time) params.start_time = start_time;
496
+ if (end_time) params.end_time = end_time;
497
+ return ok(await apiGet("/api/upgrade/v2/futures/historical-depth", params));
498
+ }
499
+ case "super_depth": {
500
+ if (!key) return err("key is required for super_depth action");
501
+ const params = { key };
502
+ params.amount = amount ?? "10000";
503
+ params.limit = limit ?? "100";
504
+ if (start_time) params.start_time = start_time;
505
+ if (end_time) params.end_time = end_time;
506
+ return ok(await apiGet("/api/upgrade/v2/futures/super-depth/history", params));
507
+ }
508
+ case "trade_data": {
509
+ if (!dbkey) return err("dbkey is required for trade_data action");
510
+ const params = { dbkey };
511
+ params.limit = limit ?? "100";
512
+ if (start_time) params.start_time = start_time;
513
+ if (end_time) params.end_time = end_time;
514
+ return ok(await apiGet("/api/upgrade/v2/futures/trade-data", params));
515
+ }
516
+ }
2178
517
  } catch (e) {
2179
518
  return err(e);
2180
519
  }
2181
520
  }
2182
521
  );
522
+ }
523
+
524
+ // src/tools/contents.ts
525
+ import { z as z3 } from "zod";
526
+ function registerContentTools(server2) {
2183
527
  server2.tool(
2184
- "hl_get_portfolio",
2185
- "Get account value and PNL curves",
528
+ "news",
529
+ "News articles.\n\u2022 list \u2014 paginated news articles\n\u2022 detail \u2014 full article content. Requires: id\n\u2022 rss \u2014 RSS news feed",
2186
530
  {
2187
- address: z6.string().describe("Wallet address"),
2188
- window: z6.string().describe(
2189
- "Time window: day, week, month, allTime"
531
+ action: z3.enum(["list", "detail", "rss"]).describe(
532
+ "list: paginated news articles; detail: full article content; rss: RSS news feed"
2190
533
  ),
2191
- ...maxItemsParam
2192
- },
2193
- async ({ address, window: win, _max_items }) => {
2194
- try {
2195
- return okList(
2196
- await apiGet(
2197
- `/api/upgrade/v2/hl/portfolio/${address}/${win}`
2198
- ),
2199
- parseMax(_max_items, 30)
2200
- );
534
+ id: z3.string().optional().describe("REQUIRED for detail. News article ID"),
535
+ page: z3.string().optional().describe("For list/rss: page number, default 1"),
536
+ pageSize: z3.string().optional().describe("For list/rss: page size, max 20")
537
+ },
538
+ async ({ action, id, page, pageSize }) => {
539
+ try {
540
+ switch (action) {
541
+ case "list": {
542
+ const params = {};
543
+ if (page) params.page = page;
544
+ params.pageSize = pageSize ?? "20";
545
+ return ok(await apiGet("/api/v2/content/news-list", params));
546
+ }
547
+ case "detail": {
548
+ if (!id) return err("id is required for detail action");
549
+ return ok(await apiGet("/api/v2/content/news-detail", { id }));
550
+ }
551
+ case "rss": {
552
+ const params = {};
553
+ if (page) params.page = page;
554
+ params.pageSize = pageSize ?? "20";
555
+ return ok(await apiGet("/api/v2/content/square/market/news-list", params));
556
+ }
557
+ }
2201
558
  } catch (e) {
2202
559
  return err(e);
2203
560
  }
2204
561
  }
2205
562
  );
2206
563
  server2.tool(
2207
- "hl_get_pnls",
2208
- "Get PNL curve data by address",
564
+ "flash",
565
+ "Flash news.\n\u2022 newsflash \u2014 AiCoin flash news\n\u2022 list \u2014 industry flash with classification\n\u2022 exchange_listing \u2014 coin listing/delisting announcements",
2209
566
  {
2210
- address: z6.string().describe("Wallet address"),
2211
- period: z6.string().optional().describe(
2212
- "Period in days: 0(allTime), 1, 7, 30"
567
+ action: z3.enum(["newsflash", "list", "exchange_listing"]).describe(
568
+ "newsflash: AiCoin flash news; list: industry flash with types; exchange_listing: coin listing/delisting"
569
+ ),
570
+ language: z3.string().optional().describe("Language: cn, tc, en"),
571
+ createtime: z3.string().optional().describe("For list: filter by create time"),
572
+ memberIds: z3.string().optional().describe(
573
+ "For exchange_listing: exchange member IDs, comma-separated. 477=Binance, 1509=Bitget. Default: 477,1509"
2213
574
  ),
575
+ pageSize: z3.string().optional().describe("For exchange_listing: page size, default 20"),
2214
576
  ...maxItemsParam
2215
577
  },
2216
- async ({ address, period, _max_items }) => {
578
+ async ({ action, language, createtime, memberIds, pageSize, _max_items }) => {
2217
579
  try {
2218
- const params = {};
2219
- if (period) params.period = period;
2220
- return okList(
2221
- await apiGet(
2222
- `/api/upgrade/v2/hl/pnls/${address}`,
2223
- params
2224
- ),
2225
- parseMax(_max_items, 100)
2226
- );
580
+ switch (action) {
581
+ case "newsflash": {
582
+ const params = {};
583
+ if (language) params.language = language;
584
+ return ok(await apiGet("/api/v2/content/newsflash", params));
585
+ }
586
+ case "list": {
587
+ const params = {};
588
+ if (language) params.language = language;
589
+ if (createtime) params.createtime = createtime;
590
+ return okList(
591
+ await apiGet("/api/v2/content/flashList", params),
592
+ parseMax(_max_items, 30)
593
+ );
594
+ }
595
+ case "exchange_listing": {
596
+ const params = {};
597
+ if (language) params.language = language;
598
+ if (memberIds) params.memberIds = memberIds;
599
+ if (pageSize) params.pageSize = pageSize;
600
+ return ok(await apiGet("/api/v2/content/exchange-listing-flash", params));
601
+ }
602
+ }
2227
603
  } catch (e) {
2228
604
  return err(e);
2229
605
  }
2230
606
  }
2231
607
  );
608
+ }
609
+
610
+ // src/tools/markets.ts
611
+ import { z as z4 } from "zod";
612
+ function registerMarketTools(server2) {
2232
613
  server2.tool(
2233
- "hl_get_best_trades",
2234
- "Get most profitable trades by address",
614
+ "market_info",
615
+ "Exchange/market data.\n\u2022 exchanges \u2014 all platforms, no params needed\n\u2022 ticker \u2014 platform tickers. Requires: market_list (NOT key)\n\u2022 hot_coins \u2014 trending by category. Requires: key (category key, NOT exchange name)\n\u2022 futures_interest \u2014 futures OI rankings, no required params",
2235
616
  {
2236
- address: z6.string().describe("Wallet address"),
2237
- period: z6.string().describe("Period in days, e.g. 7, 30, 90"),
2238
- limit: z6.string().optional().describe("Max results, default 10")
617
+ action: z4.enum(["exchanges", "ticker", "hot_coins", "futures_interest"]).describe(
618
+ "exchanges: all supported platforms; ticker: platform ticker data; hot_coins: trending coins; futures_interest: futures open interest"
619
+ ),
620
+ market_list: z4.string().optional().describe('REQUIRED for ticker. Comma-separated exchange keys, e.g. "okex,binance". NOT used by hot_coins'),
621
+ key: z4.string().optional().describe("REQUIRED for hot_coins. Category key: gamefi, anonymous, market, web, newcoin, stable, defi. This is a category key, NOT an exchange name"),
622
+ currency: z4.string().optional().describe("Currency: cny or usd"),
623
+ lan: z4.string().optional().describe("For futures_interest: language cn or en"),
624
+ page: z4.string().optional().describe("For futures_interest: page number"),
625
+ pageSize: z4.string().optional().describe("For futures_interest: page size, max 20"),
626
+ ...maxItemsParam
2239
627
  },
2240
- async ({ address, period, limit }) => {
628
+ async ({ action, market_list, key, currency, lan, page, pageSize, _max_items }) => {
2241
629
  try {
2242
- const params = {
2243
- period
2244
- };
2245
- if (limit) params.limit = limit;
2246
- return ok(
2247
- await apiGet(
2248
- `/api/upgrade/v2/hl/traders/${address}/best-trades`,
2249
- params
2250
- )
2251
- );
630
+ switch (action) {
631
+ case "exchanges":
632
+ return ok(await apiGet("/api/v2/market"));
633
+ case "ticker": {
634
+ if (!market_list) return err("market_list is required for ticker action");
635
+ return ok(await apiGet("/api/v2/market/ticker", { market_list }));
636
+ }
637
+ case "hot_coins": {
638
+ if (!key) return err("key is required for hot_coins action");
639
+ const params = { key };
640
+ if (currency) params.currency = currency;
641
+ return okList(await apiGet("/api/v2/market/hotTabCoins", params), parseMax(_max_items, 20));
642
+ }
643
+ case "futures_interest": {
644
+ const params = {};
645
+ if (lan) params.lan = lan;
646
+ if (page) params.page = page;
647
+ if (pageSize) params.pageSize = pageSize;
648
+ if (currency) params.currency = currency;
649
+ return ok(await apiGet("/api/v2/futures/interest", params));
650
+ }
651
+ }
2252
652
  } catch (e) {
2253
653
  return err(e);
2254
654
  }
2255
655
  }
2256
656
  );
2257
657
  server2.tool(
2258
- "hl_get_performance_by_coin",
2259
- "Get per-coin trading performance stats",
658
+ "kline",
659
+ "K-line (candlestick) data.\n\u2022 data \u2014 standard K-line. Requires: symbol\n\u2022 indicator \u2014 indicator K-line. Requires: symbol + indicator_key\n\u2022 trading_pair \u2014 available pairs for indicator. Optional: coinType, indicator_key",
2260
660
  {
2261
- address: z6.string().describe("Wallet address"),
2262
- period: z6.string().describe("Period in days, e.g. 7, 30, 90"),
2263
- limit: z6.string().optional().describe("Max results, default 10")
661
+ action: z4.enum(["data", "indicator", "trading_pair"]).describe(
662
+ "data: standard K-line data; indicator: indicator K-line data; trading_pair: available pairs for indicator K-line"
663
+ ),
664
+ symbol: z4.string().optional().describe("REQUIRED for data, indicator. Trading pair with exchange, e.g. btcusdt:okex or btcswapusdt:binance"),
665
+ indicator_key: z4.string().optional().describe("REQUIRED for indicator. Optional for trading_pair. Indicator key: fundflow, aiaggtrade, fr, etc."),
666
+ coinType: z4.string().optional().describe("Optional for trading_pair. Coin type, e.g. bitcoin"),
667
+ period: z4.string().optional().describe("Period in seconds: 900=15min, 3600=1h, 14400=4h, 86400=1d"),
668
+ size: z4.string().optional().describe("Number of candles, 1-500"),
669
+ since: z4.string().optional().describe("Start timestamp"),
670
+ open_time: z4.string().optional().describe("Open time offset: 0 or 8")
2264
671
  },
2265
- async ({ address, period, limit }) => {
2266
- try {
2267
- const params = {
2268
- period
2269
- };
2270
- if (limit) params.limit = limit;
2271
- return ok(
2272
- await apiGet(
2273
- `/api/upgrade/v2/hl/traders/${address}/performance-by-coin`,
2274
- params
2275
- )
2276
- );
672
+ async ({ action, symbol, indicator_key, coinType, period, size, since, open_time }) => {
673
+ try {
674
+ switch (action) {
675
+ case "data": {
676
+ if (!symbol) return err("symbol is required for data action");
677
+ const params = { symbol };
678
+ if (period) params.period = period;
679
+ params.size = size ?? "100";
680
+ if (since) params.since = since;
681
+ if (open_time) params.open_time = open_time;
682
+ return ok(await apiGet("/api/v2/commonKline/dataRecords", params));
683
+ }
684
+ case "indicator": {
685
+ if (!symbol || !indicator_key) return err("symbol and indicator_key are required for indicator action");
686
+ const params = { symbol, indicator_key };
687
+ if (period) params.period = period;
688
+ params.size = size ?? "100";
689
+ if (since) params.since = since;
690
+ if (open_time) params.open_time = open_time;
691
+ return ok(await apiGet("/api/v2/indicatorKline/dataRecords", params));
692
+ }
693
+ case "trading_pair": {
694
+ const params = {};
695
+ if (coinType) params.coinType = coinType;
696
+ if (indicator_key) params.indicator_key = indicator_key;
697
+ return ok(await apiGet("/api/v2/indicatorKline/getTradingPair", params));
698
+ }
699
+ }
2277
700
  } catch (e) {
2278
701
  return err(e);
2279
702
  }
2280
703
  }
2281
704
  );
2282
705
  server2.tool(
2283
- "hl_get_completed_trades",
2284
- "Get completed trades list by address",
706
+ "index_data",
707
+ "Index data.\n\u2022 price \u2014 index price. Requires: key\n\u2022 info \u2014 index detail. Requires: key\n\u2022 list \u2014 all available indexes, no params needed",
2285
708
  {
2286
- address: z6.string().describe("Wallet address"),
2287
- coin: z6.string().optional().describe("Coin filter, e.g. BTC"),
2288
- limit: z6.string().optional().describe("Max results, default 100"),
709
+ action: z4.enum(["price", "info", "list"]).describe(
710
+ "price: index price data; info: index detail; list: all available indexes"
711
+ ),
712
+ key: z4.string().optional().describe('REQUIRED for price, info. Index key in "i:symbol:exchange" format, e.g. "i:diniw:ice". Use list action to discover available keys'),
713
+ currency: z4.string().optional().describe("For price: currency cny or usd"),
714
+ lan: z4.string().optional().describe("For info: language en or cn"),
2289
715
  ...maxItemsParam
2290
716
  },
2291
- async ({ address, coin, limit, _max_items }) => {
717
+ async ({ action, key, currency, lan, _max_items }) => {
2292
718
  try {
2293
- const params = {};
2294
- if (coin) params.coin = coin;
2295
- if (limit) params.limit = limit;
2296
- return okList(
2297
- await apiGet(
2298
- `/api/upgrade/v2/hl/traders/${address}/completed-trades`,
2299
- params
2300
- ),
2301
- parseMax(_max_items, 50)
2302
- );
719
+ switch (action) {
720
+ case "price": {
721
+ if (!key) return err("key is required for price action");
722
+ const params = { key };
723
+ if (currency) params.currency = currency;
724
+ return ok(await apiGet("/api/v2/index/indexPrice", params));
725
+ }
726
+ case "info": {
727
+ if (!key) return err("key is required for info action");
728
+ const params = { key };
729
+ if (lan) params.lan = lan;
730
+ return ok(await apiGet("/api/v2/index/indexInfo", params));
731
+ }
732
+ case "list":
733
+ return okList(await apiGet("/api/v2/index/getIndex"), parseMax(_max_items, 20));
734
+ }
2303
735
  } catch (e) {
2304
736
  return err(e);
2305
737
  }
2306
738
  }
2307
739
  );
2308
740
  server2.tool(
2309
- "hl_get_current_position_history",
2310
- "Get current position history for a coin",
741
+ "crypto_stock",
742
+ 'Crypto-related stocks.\n\u2022 quotes \u2014 stock prices. Optional: tickers\n\u2022 top_gainer \u2014 top gainers. Optional: us_stock, hk_stock\n\u2022 company \u2014 company details. Requires: symbol (in "i:ticker:market" format)',
2311
743
  {
2312
- address: z6.string().describe("Wallet address"),
2313
- coin: z6.string().describe("Coin, e.g. BTC")
2314
- },
2315
- async ({ address, coin }) => {
2316
- try {
2317
- return ok(
2318
- await apiGet(
2319
- `/api/upgrade/v2/hl/traders/${address}/current-position-history/${coin}`
2320
- )
2321
- );
744
+ action: z4.enum(["quotes", "top_gainer", "company"]).describe(
745
+ "quotes: stock quotes (MSTR,COIN); top_gainer: top gaining stocks; company: company details"
746
+ ),
747
+ tickers: z4.string().optional().describe('Optional for quotes. Comma-separated stock tickers in "i:ticker:market" format, e.g. "i:mstr:nasdaq,i:coin:nasdaq"'),
748
+ symbol: z4.string().optional().describe('REQUIRED for company. Stock symbol in "i:ticker:market" format, e.g. "i:mstr:nasdaq"'),
749
+ us_stock: z4.boolean().optional().describe("For top_gainer: include US stocks"),
750
+ hk_stock: z4.boolean().optional().describe("For top_gainer: include HK stocks"),
751
+ limit: z4.number().optional().describe("For top_gainer: number of results, default 30")
752
+ },
753
+ async ({ action, tickers, symbol, us_stock, hk_stock, limit }) => {
754
+ try {
755
+ switch (action) {
756
+ case "quotes": {
757
+ const params = {};
758
+ if (tickers) params.tickers = tickers;
759
+ return ok(await apiGet("/api/upgrade/v2/crypto_stock/quotes", params));
760
+ }
761
+ case "top_gainer": {
762
+ const params = {};
763
+ if (us_stock != null) params.us_stock = String(us_stock);
764
+ if (hk_stock != null) params.hk_stock = String(hk_stock);
765
+ params.limit = String(limit ?? 30);
766
+ return ok(await apiGet("/api/upgrade/v2/crypto_stock/top-gainer", params));
767
+ }
768
+ case "company": {
769
+ if (!symbol) return err("symbol is required for company action");
770
+ return ok(await apiGet(`/api/upgrade/v2/crypto_stock/company/${symbol}`));
771
+ }
772
+ }
2322
773
  } catch (e) {
2323
774
  return err(e);
2324
775
  }
2325
776
  }
2326
777
  );
2327
778
  server2.tool(
2328
- "hl_get_completed_position_history",
2329
- "Get completed position history for a coin",
779
+ "coin_treasury",
780
+ "Coin treasury data (corporate holdings). Requires: coin for all actions.\n\u2022 entities \u2014 treasury entities\n\u2022 history \u2014 trade history\n\u2022 accumulated \u2014 accumulated holdings over time\n\u2022 latest_entities / latest_history \u2014 latest data\n\u2022 summary \u2014 overview stats",
2330
781
  {
2331
- address: z6.string().describe("Wallet address"),
2332
- coin: z6.string().describe("Coin, e.g. BTC"),
2333
- startTime: z6.string().optional().describe(
2334
- "Start time in ms, at least one of startTime/endTime required"
782
+ action: z4.enum(["entities", "history", "accumulated", "latest_entities", "latest_history", "summary"]).describe(
783
+ "entities: treasury entity data; history: trade history; accumulated: accumulated data; latest_entities/latest_history: latest data; summary: overview"
2335
784
  ),
2336
- endTime: z6.string().optional().describe(
2337
- "End time in ms, at least one of startTime/endTime required"
2338
- )
785
+ coin: z4.string().describe("REQUIRED for all actions. Coin ticker in uppercase, e.g. BTC, ETH"),
786
+ entity_type: z4.string().optional().describe("Entity type filter"),
787
+ name: z4.string().optional().describe("Entity name filter"),
788
+ ticker: z4.string().optional().describe("For entities: stock ticker filter"),
789
+ type: z4.string().optional().describe("For history: trade type Buy or Sell"),
790
+ start_date: z4.string().optional().describe("Start date, ISO 8601"),
791
+ end_date: z4.string().optional().describe("End date, ISO 8601"),
792
+ interval: z4.string().optional().describe("For accumulated: daily, weekly, or monthly"),
793
+ page: z4.string().optional().describe("Page number, default 1"),
794
+ page_size: z4.string().optional().describe("Page size, default 20"),
795
+ sort_by: z4.string().optional().describe("For history: sort field, default date"),
796
+ sort_order: z4.string().optional().describe("Sort: asc or desc, default desc"),
797
+ ...maxItemsParam
2339
798
  },
2340
- async ({ address, coin, startTime, endTime }) => {
2341
- try {
2342
- const params = {};
2343
- if (startTime) params.startTime = startTime;
2344
- if (endTime) params.endTime = endTime;
2345
- return ok(
2346
- await apiGet(
2347
- `/api/upgrade/v2/hl/traders/${address}/completed-position-history/${coin}`,
2348
- params
2349
- )
2350
- );
799
+ async ({ action, coin, entity_type, name, ticker, type, start_date, end_date, interval, page, page_size, sort_by, sort_order, _max_items }) => {
800
+ try {
801
+ switch (action) {
802
+ case "entities": {
803
+ const body = { coin };
804
+ if (entity_type) body.entity_type = entity_type;
805
+ if (name) body.name = name;
806
+ if (ticker) body.ticker = ticker;
807
+ if (start_date) body.start_date = start_date;
808
+ if (end_date) body.end_date = end_date;
809
+ if (page) body.page = Number(page);
810
+ if (page_size) body.page_size = Number(page_size);
811
+ if (sort_order) body.sort_order = sort_order;
812
+ return ok(await apiPost("/api/upgrade/v2/coin-treasuries/entities", body));
813
+ }
814
+ case "history": {
815
+ const body = { coin };
816
+ if (name) body.name = name;
817
+ if (type) body.type = type;
818
+ if (start_date) body.start_date = start_date;
819
+ if (end_date) body.end_date = end_date;
820
+ if (page) body.page = Number(page);
821
+ if (page_size) body.page_size = Number(page_size);
822
+ if (sort_by) body.sort_by = sort_by;
823
+ if (sort_order) body.sort_order = sort_order;
824
+ return ok(await apiPost("/api/upgrade/v2/coin-treasuries/history", body));
825
+ }
826
+ case "accumulated": {
827
+ const body = { coin };
828
+ if (entity_type) body.entity_type = entity_type;
829
+ if (start_date) body.start_date = start_date;
830
+ if (end_date) body.end_date = end_date;
831
+ if (interval) body.interval = interval;
832
+ return ok(await apiPost("/api/upgrade/v2/coin-treasuries/history/accumulated", body));
833
+ }
834
+ case "latest_entities":
835
+ return okList(
836
+ await apiGet("/api/upgrade/v2/coin-treasuries/latest/entities", { coin }),
837
+ parseMax(_max_items, 20)
838
+ );
839
+ case "latest_history":
840
+ return okList(
841
+ await apiGet("/api/upgrade/v2/coin-treasuries/latest/history", { coin }),
842
+ parseMax(_max_items, 20)
843
+ );
844
+ case "summary":
845
+ return ok(await apiGet("/api/upgrade/v2/coin-treasuries/summary", { coin }));
846
+ }
2351
847
  } catch (e) {
2352
848
  return err(e);
2353
849
  }
2354
850
  }
2355
851
  );
2356
852
  server2.tool(
2357
- "hl_get_current_position_pnl",
2358
- "Get current position PnL for a coin",
853
+ "depth",
854
+ "Order book depth. Requires: dbKey for all actions.\n\u2022 latest \u2014 real-time snapshot\n\u2022 full \u2014 complete order book\n\u2022 grouped \u2014 grouped by price interval. Requires: groupSize",
2359
855
  {
2360
- address: z6.string().describe("Wallet address"),
2361
- coin: z6.string().describe("Coin, e.g. BTC"),
2362
- interval: z6.string().describe("Interval, e.g. 1h, 4h, 1d")
856
+ action: z4.enum(["latest", "full", "grouped"]).describe(
857
+ "latest: real-time snapshot; full: complete order book; grouped: grouped by price interval"
858
+ ),
859
+ dbKey: z4.string().describe("REQUIRED for all actions. Trading pair key, e.g. btcswapusdt:binance"),
860
+ size: z4.string().optional().describe("Optional for latest. Depth levels 1-500, default 50"),
861
+ groupSize: z4.string().optional().describe('REQUIRED for grouped. Price grouping interval, e.g. "100", "500", "1000"'),
862
+ ...maxItemsParam
2363
863
  },
2364
- async ({ address, coin, interval }) => {
864
+ async ({ action, dbKey, size, groupSize, _max_items }) => {
2365
865
  try {
2366
- return ok(
2367
- await apiGet(
2368
- `/api/upgrade/v2/hl/traders/${address}/current-position-pnl/${coin}`,
2369
- { interval }
2370
- )
2371
- );
866
+ switch (action) {
867
+ case "latest": {
868
+ const params = { dbKey };
869
+ if (size) params.size = size;
870
+ return ok(await apiGet("/api/upgrade/v2/futures/latest-depth", params));
871
+ }
872
+ case "full":
873
+ return okDepth(
874
+ await apiGet("/api/upgrade/v2/futures/full-depth", { dbKey }),
875
+ parseMax(_max_items, 50)
876
+ );
877
+ case "grouped": {
878
+ if (!groupSize) return err("groupSize is required for grouped action");
879
+ return okDepth(
880
+ await apiGet("/api/upgrade/v2/futures/full-depth/grouped", { dbKey, groupSize }),
881
+ parseMax(_max_items, 50)
882
+ );
883
+ }
884
+ }
2372
885
  } catch (e) {
2373
886
  return err(e);
2374
887
  }
2375
888
  }
2376
889
  );
890
+ }
891
+
892
+ // src/tools/features.ts
893
+ import { z as z5 } from "zod";
894
+ function registerFeatureTools(server2) {
2377
895
  server2.tool(
2378
- "hl_get_completed_position_pnl",
2379
- "Get completed position PnL for a coin",
896
+ "market_overview",
897
+ "Market overview data.\n\u2022 nav \u2014 market overview/navigation\n\u2022 ls_ratio \u2014 long/short ratio, no params needed\n\u2022 liquidation \u2014 forced-close data\n\u2022 grayscale_trust \u2014 trust fund, no params needed\n\u2022 gray_scale \u2014 grayscale holdings. Requires: coins\n\u2022 stock_market \u2014 crypto stocks, no params needed",
2380
898
  {
2381
- address: z6.string().describe("Wallet address"),
2382
- coin: z6.string().describe("Coin, e.g. BTC"),
2383
- interval: z6.string().describe("Interval, e.g. 1h, 4h, 1d"),
2384
- startTime: z6.string().optional().describe(
2385
- "Start time in ms, at least one of startTime/endTime required"
899
+ action: z5.enum(["nav", "ls_ratio", "liquidation", "grayscale_trust", "gray_scale", "stock_market"]).describe(
900
+ "nav: market overview; ls_ratio: long/short ratio; liquidation: forced-close data; grayscale_trust: trust fund; gray_scale: holdings; stock_market: crypto stocks"
2386
901
  ),
2387
- endTime: z6.string().optional().describe(
2388
- "End time in ms, at least one of startTime/endTime required"
2389
- )
902
+ lan: z5.string().optional().describe('Optional for nav. Language: "cn" or "en"'),
903
+ currency: z5.string().optional().describe('Optional for liquidation. Currency: "cny" or "usd"'),
904
+ type: z5.string().optional().describe('Optional for liquidation. Group by: "1"=by coin, "2"=by platform'),
905
+ coinKey: z5.string().optional().describe('Optional for liquidation. Coin key filter (when type="1")'),
906
+ marketKey: z5.string().optional().describe('Optional for liquidation. Market key filter (when type="2")'),
907
+ coins: z5.string().optional().describe('REQUIRED for gray_scale. Comma-separated coin symbols in lowercase, e.g. "btc,eth"'),
908
+ ...maxItemsParam
2390
909
  },
2391
- async ({ address, coin, interval, startTime, endTime }) => {
910
+ async ({ action, lan, currency, type, coinKey, marketKey, coins, _max_items }) => {
2392
911
  try {
2393
- const params = { interval };
2394
- if (startTime) params.startTime = startTime;
2395
- if (endTime) params.endTime = endTime;
2396
- return ok(
2397
- await apiGet(
2398
- `/api/upgrade/v2/hl/traders/${address}/completed-position-pnl/${coin}`,
2399
- params
2400
- )
2401
- );
912
+ switch (action) {
913
+ case "nav": {
914
+ const params = {};
915
+ if (lan) params.lan = lan;
916
+ return ok(await apiGet("/api/v2/mix/nav", params));
917
+ }
918
+ case "ls_ratio":
919
+ return ok(await apiGet("/api/v2/mix/ls-ratio"));
920
+ case "liquidation": {
921
+ const params = {};
922
+ if (currency) params.currency = currency;
923
+ if (type) params.type = type;
924
+ if (coinKey) params.coinKey = coinKey;
925
+ if (marketKey) params.marketKey = marketKey;
926
+ return ok(await apiGet("/api/v2/mix/liq", params));
927
+ }
928
+ case "grayscale_trust":
929
+ return ok(await apiGet("/api/v2/mix/grayscale-trust"));
930
+ case "gray_scale": {
931
+ if (!coins) return err("coins is required for gray_scale action");
932
+ return ok(await apiGet("/api/v2/mix/gray-scale", { coins }));
933
+ }
934
+ case "stock_market":
935
+ return okList(await apiGet("/api/v2/mix/stock-market"), parseMax(_max_items, 50));
936
+ }
2402
937
  } catch (e) {
2403
938
  return err(e);
2404
939
  }
2405
940
  }
2406
941
  );
2407
942
  server2.tool(
2408
- "hl_get_current_position_executions",
2409
- "Get current position execution trace",
943
+ "order_flow",
944
+ "Order flow data. Requires: symbol for all actions.\n\u2022 big_orders \u2014 whale/large order tracking\n\u2022 agg_trades \u2014 aggregated large trades",
2410
945
  {
2411
- address: z6.string().describe("Wallet address"),
2412
- coin: z6.string().describe("Coin, e.g. BTC"),
2413
- interval: z6.string().describe("Interval, e.g. 1h, 4h, 1d")
946
+ action: z5.enum(["big_orders", "agg_trades"]).describe(
947
+ "big_orders: whale/large order tracking; agg_trades: aggregated large trades"
948
+ ),
949
+ symbol: z5.string().describe("REQUIRED. Trading pair with exchange, e.g. btcswapusdt:binance"),
950
+ ...maxItemsParam
2414
951
  },
2415
- async ({ address, coin, interval }) => {
952
+ async ({ action, symbol, _max_items }) => {
2416
953
  try {
2417
- return ok(
2418
- await apiGet(
2419
- `/api/upgrade/v2/hl/traders/${address}/current-position-executions/${coin}`,
2420
- { interval }
2421
- )
2422
- );
954
+ switch (action) {
955
+ case "big_orders":
956
+ return okList(await apiGet("/api/v2/order/bigOrder", { symbol }), parseMax(_max_items, 20));
957
+ case "agg_trades":
958
+ return okList(await apiGet("/api/v2/order/aggTrade", { symbol }), parseMax(_max_items, 30));
959
+ }
2423
960
  } catch (e) {
2424
961
  return err(e);
2425
962
  }
2426
963
  }
2427
964
  );
2428
965
  server2.tool(
2429
- "hl_get_completed_position_executions",
2430
- "Get completed position execution trace",
966
+ "trading_pair",
967
+ "Trading pair data.\n\u2022 ticker \u2014 specific pair tickers. Requires: key_list\n\u2022 by_market \u2014 all pairs for a platform. Requires: market\n\u2022 list \u2014 pairs with filters. Requires: market",
2431
968
  {
2432
- address: z6.string().describe("Wallet address"),
2433
- coin: z6.string().describe("Coin, e.g. BTC"),
2434
- interval: z6.string().describe("Interval, e.g. 1h, 4h, 1d"),
2435
- startTime: z6.string().optional().describe(
2436
- "Start time in ms, at least one of startTime/endTime required"
969
+ action: z5.enum(["ticker", "by_market", "list"]).describe(
970
+ "ticker: specific pair tickers; by_market: pairs for a platform; list: pairs with filters"
2437
971
  ),
2438
- endTime: z6.string().optional().describe(
2439
- "End time in ms, at least one of startTime/endTime required"
2440
- )
972
+ key_list: z5.string().optional().describe('REQUIRED for ticker. Comma-separated pair keys, e.g. "btcusdt:okex,btcusdt:huobipro"'),
973
+ market: z5.string().optional().describe("REQUIRED for by_market, list. Platform/exchange key, e.g. okex, binance"),
974
+ currency: z5.string().optional().describe("For list: quote currency filter"),
975
+ show: z5.string().optional().describe("For list: coin symbol filter"),
976
+ ...maxItemsParam
2441
977
  },
2442
- async ({ address, coin, interval, startTime, endTime }) => {
978
+ async ({ action, key_list, market, currency, show, _max_items }) => {
2443
979
  try {
2444
- const params = { interval };
2445
- if (startTime) params.startTime = startTime;
2446
- if (endTime) params.endTime = endTime;
2447
- return ok(
2448
- await apiGet(
2449
- `/api/upgrade/v2/hl/traders/${address}/completed-position-executions/${coin}`,
2450
- params
2451
- )
2452
- );
980
+ switch (action) {
981
+ case "ticker": {
982
+ if (!key_list) return err("key_list is required for ticker action");
983
+ return ok(await apiGet("/api/v2/trading-pair/ticker", { key_list }));
984
+ }
985
+ case "by_market": {
986
+ if (!market) return err("market is required for by_market action");
987
+ return okList(
988
+ await apiGet("/api/v2/trading-pair/getTradingPair", { market }),
989
+ parseMax(_max_items, 50)
990
+ );
991
+ }
992
+ case "list": {
993
+ if (!market) return err("market is required for list action");
994
+ const params = { market };
995
+ if (currency) params.currency = currency;
996
+ if (show) params.show = show;
997
+ return okList(await apiGet("/api/v2/trading-pair", params), parseMax(_max_items, 100));
998
+ }
999
+ }
2453
1000
  } catch (e) {
2454
1001
  return err(e);
2455
1002
  }
2456
1003
  }
2457
1004
  );
2458
1005
  server2.tool(
2459
- "hl_get_traders_accounts",
2460
- "Batch query trader account info",
1006
+ "signal_data",
1007
+ "Signal data.\n\u2022 strategy \u2014 indicator win-rate signals\n\u2022 alert \u2014 current signal alerts\n\u2022 config \u2014 alert configurations\n\u2022 alert_list \u2014 user alert settings\n\u2022 change \u2014 abnormal price movements",
2461
1008
  {
2462
- addresses: z6.string().describe("Addresses as JSON array string")
1009
+ action: z5.enum(["strategy", "alert", "config", "alert_list", "change"]).describe(
1010
+ "strategy: indicator win-rate signals; alert: signal alert data; config: alert configurations; alert_list: alert settings; change: abnormal movement"
1011
+ ),
1012
+ coin_type: z5.string().optional().describe("Optional for strategy. Coin type, e.g. bitcoin"),
1013
+ signal_key: z5.string().optional().describe("Optional for strategy. Signal key: depth_win_one, td_buy_one, etc."),
1014
+ latest_time: z5.string().optional().describe("Optional for strategy. Latest time filter in ms"),
1015
+ lan: z5.string().optional().describe('Optional for config. Language: "cn" or "en"'),
1016
+ type: z5.string().optional().describe("Optional for change. Signal type: 1-12, 17, 18, 23, 24"),
1017
+ currency: z5.string().optional().describe('Optional for change. Currency: "usd" or "cny"'),
1018
+ ...maxItemsParam
2463
1019
  },
2464
- async ({ addresses }) => {
1020
+ async ({ action, coin_type, signal_key, latest_time, lan, type, currency, _max_items }) => {
2465
1021
  try {
2466
- return ok(
2467
- await apiPost("/api/upgrade/v2/hl/traders/accounts", {
2468
- addresses: JSON.parse(addresses)
2469
- })
2470
- );
1022
+ switch (action) {
1023
+ case "strategy": {
1024
+ const params = {};
1025
+ if (coin_type) params.coin_type = coin_type;
1026
+ if (signal_key) params.signal_key = signal_key;
1027
+ if (latest_time) params.latest_time = latest_time;
1028
+ return okList(await apiGet("/api/v2/signal/strategySignal", params), parseMax(_max_items, 20));
1029
+ }
1030
+ case "alert":
1031
+ return okList(await apiGet("/api/v2/signal/signalAlert"), parseMax(_max_items, 20));
1032
+ case "config": {
1033
+ const params = {};
1034
+ if (lan) params.lan = lan;
1035
+ return okList(await apiGet("/api/v2/signal/signalAlertConf", params), parseMax(_max_items, 20));
1036
+ }
1037
+ case "alert_list":
1038
+ return ok(await apiGet("/api/v2/signal/getSignalAlertSetList"));
1039
+ case "change": {
1040
+ const params = {};
1041
+ if (type) params.type = type;
1042
+ if (currency) params.currency = currency;
1043
+ return okList(await apiGet("/api/v2/signal/changeSignal", params), parseMax(_max_items, 50));
1044
+ }
1045
+ }
2471
1046
  } catch (e) {
2472
1047
  return err(e);
2473
1048
  }
2474
1049
  }
2475
1050
  );
2476
1051
  server2.tool(
2477
- "hl_get_traders_statistics",
2478
- "Batch query trader statistics",
1052
+ "signal_manage",
1053
+ "Delete a signal alert. Requires: id",
2479
1054
  {
2480
- addresses: z6.string().describe("Addresses as JSON array string")
1055
+ id: z5.string().describe("REQUIRED. Signal alert ID to delete")
2481
1056
  },
2482
- async ({ addresses }) => {
1057
+ async ({ id }) => {
2483
1058
  try {
2484
- return ok(
2485
- await apiPost(
2486
- "/api/upgrade/v2/hl/traders/statistics",
2487
- { addresses: JSON.parse(addresses) }
2488
- )
2489
- );
1059
+ return ok(await apiGet("/api/v2/signal/delSignalAlert", { id }));
2490
1060
  } catch (e) {
2491
1061
  return err(e);
2492
1062
  }
2493
1063
  }
2494
1064
  );
1065
+ }
1066
+
1067
+ // src/tools/hyperliquid.ts
1068
+ import { z as z6 } from "zod";
1069
+ function registerHyperliquidTools(server2) {
2495
1070
  server2.tool(
2496
- "hl_get_whale_events",
2497
- "Get latest whale position events",
1071
+ "hl_ticker",
1072
+ "Hyperliquid tickers. If coin provided, returns single ticker; otherwise returns all tickers.",
2498
1073
  {
2499
- coin: z6.string().optional().describe("Coin filter"),
1074
+ coin: z6.string().optional().describe("Optional. Coin symbol in uppercase, e.g. BTC, ETH. Omit to get all tickers"),
2500
1075
  ...maxItemsParam
2501
1076
  },
2502
1077
  async ({ coin, _max_items }) => {
2503
1078
  try {
2504
- const params = {};
2505
- if (coin) params.coin = coin;
2506
- return okList(
2507
- await apiGet(
2508
- "/api/upgrade/v2/hl/whales/latest-events",
2509
- params
2510
- ),
2511
- parseMax(_max_items, 50)
2512
- );
1079
+ if (coin) {
1080
+ return ok(await apiGet(`/api/upgrade/v2/hl/tickers/coin/${coin}`));
1081
+ }
1082
+ return okList(await apiGet("/api/upgrade/v2/hl/tickers"), parseMax(_max_items, 50));
2513
1083
  } catch (e) {
2514
1084
  return err(e);
2515
1085
  }
2516
1086
  }
2517
1087
  );
2518
1088
  server2.tool(
2519
- "hl_get_whale_directions",
2520
- "Get whale position long/short counts",
1089
+ "hl_whale",
1090
+ "Hyperliquid whale data. All actions support optional coin filter.\n\u2022 positions \u2014 whale open positions\n\u2022 events \u2014 latest whale events\n\u2022 directions \u2014 long/short counts\n\u2022 history_ratio \u2014 historical long ratio",
2521
1091
  {
2522
- coin: z6.string().optional().describe("Coin filter")
1092
+ action: z6.enum(["positions", "events", "directions", "history_ratio"]).describe(
1093
+ "positions: whale open positions; events: latest whale events; directions: long/short counts; history_ratio: historical long ratio"
1094
+ ),
1095
+ coin: z6.string().optional().describe("Optional. Coin filter in uppercase, e.g. BTC"),
1096
+ min_usd: z6.string().optional().describe("Optional for positions. Min position size in USD"),
1097
+ ...maxItemsParam
2523
1098
  },
2524
- async ({ coin }) => {
1099
+ async ({ action, coin, min_usd, _max_items }) => {
2525
1100
  try {
2526
1101
  const params = {};
2527
1102
  if (coin) params.coin = coin;
2528
- return ok(
2529
- await apiGet(
2530
- "/api/upgrade/v2/hl/whales/directions",
2531
- params
2532
- )
2533
- );
1103
+ switch (action) {
1104
+ case "positions": {
1105
+ if (min_usd) params.min_usd = min_usd;
1106
+ return okList(
1107
+ await apiGet("/api/upgrade/v2/hl/whales/open-positions", params),
1108
+ parseMax(_max_items, 50)
1109
+ );
1110
+ }
1111
+ case "events":
1112
+ return okList(
1113
+ await apiGet("/api/upgrade/v2/hl/whales/latest-events", params),
1114
+ parseMax(_max_items, 50)
1115
+ );
1116
+ case "directions":
1117
+ return ok(await apiGet("/api/upgrade/v2/hl/whales/directions", params));
1118
+ case "history_ratio":
1119
+ return okList(
1120
+ await apiGet("/api/upgrade/v2/hl/whales/history-long-ratio", params),
1121
+ parseMax(_max_items, 30)
1122
+ );
1123
+ }
2534
1124
  } catch (e) {
2535
1125
  return err(e);
2536
1126
  }
2537
1127
  }
2538
1128
  );
2539
1129
  server2.tool(
2540
- "hl_get_whale_history_long_ratio",
2541
- "Get historical whale long/short ratio",
1130
+ "hl_liquidation",
1131
+ "Hyperliquid liquidation data. All actions support optional coin filter.\n\u2022 history \u2014 liquidation history\n\u2022 stats \u2014 aggregate stats\n\u2022 stats_by_coin \u2014 per-coin stats\n\u2022 top_positions \u2014 top liquidated positions",
2542
1132
  {
2543
- coin: z6.string().optional().describe("Coin filter"),
1133
+ action: z6.enum(["history", "stats", "stats_by_coin", "top_positions"]).describe(
1134
+ "history: liquidation history; stats: aggregate stats; stats_by_coin: per-coin stats; top_positions: top liquidated"
1135
+ ),
1136
+ coin: z6.string().optional().describe("Optional. Coin filter in uppercase, e.g. BTC"),
2544
1137
  ...maxItemsParam
2545
1138
  },
2546
- async ({ coin, _max_items }) => {
1139
+ async ({ action, coin, _max_items }) => {
2547
1140
  try {
2548
1141
  const params = {};
2549
1142
  if (coin) params.coin = coin;
2550
- return okList(
2551
- await apiGet(
2552
- "/api/upgrade/v2/hl/whales/history-long-ratio",
2553
- params
2554
- ),
2555
- parseMax(_max_items, 30)
2556
- );
2557
- } catch (e) {
2558
- return err(e);
2559
- }
2560
- }
2561
- );
2562
- server2.tool(
2563
- "hl_get_liquidation_stats",
2564
- "Get Hyperliquid liquidation statistics",
2565
- {},
2566
- async () => {
2567
- try {
2568
- return ok(
2569
- await apiGet("/api/upgrade/v2/hl/liquidations/stat")
2570
- );
1143
+ switch (action) {
1144
+ case "history":
1145
+ return okList(
1146
+ await apiGet("/api/upgrade/v2/hl/liquidations/history", params),
1147
+ parseMax(_max_items, 50)
1148
+ );
1149
+ case "stats":
1150
+ return ok(await apiGet("/api/upgrade/v2/hl/liquidations/stat"));
1151
+ case "stats_by_coin":
1152
+ return ok(await apiGet("/api/upgrade/v2/hl/liquidations/stat-by-coin", params));
1153
+ case "top_positions":
1154
+ return okList(
1155
+ await apiGet("/api/upgrade/v2/hl/liquidations/top-positions", params),
1156
+ parseMax(_max_items, 50)
1157
+ );
1158
+ }
2571
1159
  } catch (e) {
2572
1160
  return err(e);
2573
1161
  }
2574
1162
  }
2575
1163
  );
2576
1164
  server2.tool(
2577
- "hl_get_liquidation_stats_by_coin",
2578
- "Get liquidation statistics by coin",
1165
+ "hl_open_interest",
1166
+ "Hyperliquid open interest.\n\u2022 summary \u2014 overall OI summary, no params needed\n\u2022 top_coins \u2014 top coins ranked by OI\n\u2022 history \u2014 per-coin OI history. Requires: coin",
2579
1167
  {
2580
- coin: z6.string().optional().describe("Coin filter")
1168
+ action: z6.enum(["summary", "top_coins", "history"]).describe(
1169
+ "summary: overall OI summary; top_coins: top coins by OI; history: per-coin OI history"
1170
+ ),
1171
+ coin: z6.string().optional().describe("REQUIRED for history. Coin in uppercase, e.g. BTC"),
1172
+ interval: z6.string().optional().describe("Optional for history. Time window: 4h, 1d, etc."),
1173
+ limit: z6.string().optional().describe("Optional for top_coins. Number of coins to return"),
1174
+ ...maxItemsParam
2581
1175
  },
2582
- async ({ coin }) => {
2583
- try {
2584
- const params = {};
2585
- if (coin) params.coin = coin;
2586
- return ok(
2587
- await apiGet(
2588
- "/api/upgrade/v2/hl/liquidations/stat-by-coin",
2589
- params
2590
- )
2591
- );
1176
+ async ({ action, coin, interval, limit, _max_items }) => {
1177
+ try {
1178
+ switch (action) {
1179
+ case "summary":
1180
+ return ok(await apiGet("/api/upgrade/v2/hl/open-interest/summary"));
1181
+ case "top_coins": {
1182
+ const params = {};
1183
+ if (limit) params.limit = limit;
1184
+ return okList(
1185
+ await apiGet("/api/upgrade/v2/hl/open-interest/top-coins", params),
1186
+ parseMax(_max_items, 50)
1187
+ );
1188
+ }
1189
+ case "history": {
1190
+ if (!coin) return err("coin is required for history action");
1191
+ const params = {};
1192
+ if (interval) params.interval = interval;
1193
+ return okList(
1194
+ await apiGet(`/api/upgrade/v2/hl/open-interest/history/${coin}`, params),
1195
+ parseMax(_max_items, 50)
1196
+ );
1197
+ }
1198
+ }
2592
1199
  } catch (e) {
2593
1200
  return err(e);
2594
1201
  }
2595
1202
  }
2596
1203
  );
2597
1204
  server2.tool(
2598
- "hl_get_liquidation_top_positions",
2599
- "Get top liquidated positions",
1205
+ "hl_taker",
1206
+ "Hyperliquid taker data. Requires: coin for all actions.\n\u2022 delta \u2014 accumulated taker buy/sell delta\n\u2022 klines \u2014 K-lines with taker volume",
2600
1207
  {
2601
- coin: z6.string().optional().describe("Coin filter"),
1208
+ action: z6.enum(["delta", "klines"]).describe(
1209
+ "delta: accumulated taker buy/sell delta; klines: K-lines with taker volume"
1210
+ ),
1211
+ coin: z6.string().describe("REQUIRED. Coin in uppercase, e.g. BTC, ETH"),
1212
+ interval: z6.string().optional().describe("Optional. Time window: 15m, 4h, 1d. Default 4h for klines"),
2602
1213
  ...maxItemsParam
2603
1214
  },
2604
- async ({ coin, _max_items }) => {
1215
+ async ({ action, coin, interval, _max_items }) => {
2605
1216
  try {
2606
1217
  const params = {};
2607
- if (coin) params.coin = coin;
2608
- return okList(
2609
- await apiGet(
2610
- "/api/upgrade/v2/hl/liquidations/top-positions",
2611
- params
2612
- ),
2613
- parseMax(_max_items, 50)
2614
- );
1218
+ if (interval) params.interval = interval;
1219
+ switch (action) {
1220
+ case "delta":
1221
+ return ok(await apiGet(`/api/upgrade/v2/hl/accumulated-taker-delta/${coin}`, params));
1222
+ case "klines":
1223
+ return okList(
1224
+ await apiGet(`/api/upgrade/v2/hl/klines-with-taker-vol/${coin}/${interval || "4h"}`),
1225
+ parseMax(_max_items, 30)
1226
+ );
1227
+ }
2615
1228
  } catch (e) {
2616
1229
  return err(e);
2617
1230
  }
2618
1231
  }
2619
1232
  );
2620
1233
  server2.tool(
2621
- "hl_smart_find",
2622
- "Discover smart money addresses on Hyperliquid",
1234
+ "hl_trader",
1235
+ "Hyperliquid trader analytics.\n\u2022 stats \u2014 trader stats. Requires: address\n\u2022 best_trades \u2014 most profitable trades. Requires: address + period\n\u2022 performance \u2014 per-coin performance. Requires: address + period\n\u2022 completed_trades \u2014 completed trade list. Requires: address\n\u2022 accounts \u2014 batch account info. Requires: addresses (JSON array string)\n\u2022 statistics \u2014 batch stats. Requires: addresses (JSON array string)",
2623
1236
  {
2624
- params_json: z6.string().describe("Search params as JSON string"),
1237
+ action: z6.enum(["stats", "best_trades", "performance", "completed_trades", "accounts", "statistics"]).describe(
1238
+ "stats: trader stats; best_trades: most profitable; performance: per-coin performance; completed_trades: completed list; accounts: batch account info; statistics: batch stats"
1239
+ ),
1240
+ address: z6.string().optional().describe("REQUIRED for stats, best_trades, performance, completed_trades. Single wallet address (0x...)"),
1241
+ addresses: z6.string().optional().describe(`REQUIRED for accounts, statistics. Must be a JSON array string, e.g. '["0xabc...","0xdef..."]'. NOT comma-separated`),
1242
+ period: z6.string().optional().describe("REQUIRED for best_trades, performance. Optional for stats. Period in days: 7, 30, 90"),
1243
+ coin: z6.string().optional().describe("Optional for completed_trades. Coin filter in uppercase, e.g. BTC"),
1244
+ limit: z6.string().optional().describe("Max results"),
2625
1245
  ...maxItemsParam
2626
1246
  },
2627
- async ({ params_json, _max_items }) => {
1247
+ async ({ action, address, addresses, period, coin, limit, _max_items }) => {
2628
1248
  try {
2629
- return okList(
2630
- await apiPost(
2631
- "/api/upgrade/v2/hl/smart/find",
2632
- JSON.parse(params_json)
2633
- ),
2634
- parseMax(_max_items, 20)
2635
- );
1249
+ switch (action) {
1250
+ case "stats": {
1251
+ if (!address) return err("address is required for stats action");
1252
+ const params = {};
1253
+ if (period) params.period = period;
1254
+ return ok(await apiGet(`/api/upgrade/v2/hl/traders/${address}/addr-stat`, params));
1255
+ }
1256
+ case "best_trades": {
1257
+ if (!address || !period) return err("address and period are required for best_trades action");
1258
+ const params = { period };
1259
+ if (limit) params.limit = limit;
1260
+ return ok(await apiGet(`/api/upgrade/v2/hl/traders/${address}/best-trades`, params));
1261
+ }
1262
+ case "performance": {
1263
+ if (!address || !period) return err("address and period are required for performance action");
1264
+ const params = { period };
1265
+ if (limit) params.limit = limit;
1266
+ return ok(await apiGet(`/api/upgrade/v2/hl/traders/${address}/performance-by-coin`, params));
1267
+ }
1268
+ case "completed_trades": {
1269
+ if (!address) return err("address is required for completed_trades action");
1270
+ const params = {};
1271
+ if (coin) params.coin = coin;
1272
+ if (limit) params.limit = limit;
1273
+ return okList(
1274
+ await apiGet(`/api/upgrade/v2/hl/traders/${address}/completed-trades`, params),
1275
+ parseMax(_max_items, 50)
1276
+ );
1277
+ }
1278
+ case "accounts": {
1279
+ if (!addresses) return err("addresses is required for accounts action");
1280
+ return ok(await apiPost("/api/upgrade/v2/hl/traders/accounts", {
1281
+ addresses: JSON.parse(addresses)
1282
+ }));
1283
+ }
1284
+ case "statistics": {
1285
+ if (!addresses) return err("addresses is required for statistics action");
1286
+ return ok(await apiPost("/api/upgrade/v2/hl/traders/statistics", {
1287
+ addresses: JSON.parse(addresses)
1288
+ }));
1289
+ }
1290
+ }
2636
1291
  } catch (e) {
2637
1292
  return err(e);
2638
1293
  }
2639
1294
  }
2640
1295
  );
2641
1296
  server2.tool(
2642
- "hl_discover_traders",
2643
- "Discover traders by criteria",
1297
+ "hl_fills",
1298
+ "Hyperliquid trade fills.\n\u2022 by_address \u2014 fills by wallet. Requires: address\n\u2022 by_oid \u2014 fills by order ID. Requires: oid\n\u2022 by_twapid \u2014 fills by TWAP ID. Requires: twapid\n\u2022 top_trades \u2014 top trades, no required params",
2644
1299
  {
2645
- params_json: z6.string().describe("Discovery params as JSON string"),
1300
+ action: z6.enum(["by_address", "by_oid", "by_twapid", "top_trades"]).describe(
1301
+ "by_address: fills by wallet; by_oid: fills by order ID; by_twapid: fills by TWAP ID; top_trades: top trades"
1302
+ ),
1303
+ address: z6.string().optional().describe("REQUIRED for by_address. Wallet address (0x...)"),
1304
+ oid: z6.string().optional().describe("REQUIRED for by_oid. Order ID"),
1305
+ twapid: z6.string().optional().describe("REQUIRED for by_twapid. TWAP ID"),
1306
+ coin: z6.string().optional().describe("Optional. Coin filter in uppercase, e.g. BTC"),
1307
+ interval: z6.string().optional().describe("Optional for top_trades. Interval: 4h, 1d"),
1308
+ limit: z6.string().optional().describe("Max results"),
2646
1309
  ...maxItemsParam
2647
1310
  },
2648
- async ({ params_json, _max_items }) => {
2649
- try {
2650
- return okList(
2651
- await apiPost(
2652
- "/api/upgrade/v2/hl/traders/discover",
2653
- JSON.parse(params_json)
2654
- ),
2655
- parseMax(_max_items, 20)
2656
- );
1311
+ async ({ action, address, oid, twapid, coin, interval, limit, _max_items }) => {
1312
+ try {
1313
+ switch (action) {
1314
+ case "by_address": {
1315
+ if (!address) return err("address is required for by_address action");
1316
+ const params = {};
1317
+ if (coin) params.coin = coin;
1318
+ if (limit) params.limit = limit;
1319
+ return okList(
1320
+ await apiGet(`/api/upgrade/v2/hl/fills/${address}`, params),
1321
+ parseMax(_max_items, 50)
1322
+ );
1323
+ }
1324
+ case "by_oid": {
1325
+ if (!oid) return err("oid is required for by_oid action");
1326
+ return ok(await apiGet(`/api/upgrade/v2/hl/fills/oid/${oid}`));
1327
+ }
1328
+ case "by_twapid": {
1329
+ if (!twapid) return err("twapid is required for by_twapid action");
1330
+ return ok(await apiGet(`/api/upgrade/v2/hl/fills/twapid/${twapid}`));
1331
+ }
1332
+ case "top_trades": {
1333
+ const params = {};
1334
+ if (coin) params.coin = coin;
1335
+ if (interval) params.interval = interval;
1336
+ if (limit) params.limit = limit;
1337
+ return okList(
1338
+ await apiGet("/api/upgrade/v2/hl/fills/top-trades", params),
1339
+ parseMax(_max_items, 50)
1340
+ );
1341
+ }
1342
+ }
2657
1343
  } catch (e) {
2658
1344
  return err(e);
2659
1345
  }
2660
1346
  }
2661
1347
  );
2662
1348
  server2.tool(
2663
- "hl_get_twap_states",
2664
- "Get TWAP order states by address",
1349
+ "hl_orders",
1350
+ "Hyperliquid orders.\n\u2022 latest \u2014 latest orders. Requires: address\n\u2022 by_oid \u2014 single order. Requires: oid\n\u2022 filled \u2014 filled orders. Requires: address\n\u2022 filled_by_oid \u2014 filled order. Requires: oid\n\u2022 top_open \u2014 top open orders\n\u2022 active_stats \u2014 active order stats\n\u2022 twap_states \u2014 TWAP states. Requires: address",
2665
1351
  {
2666
- address: z6.string().describe("Wallet address")
1352
+ action: z6.enum(["latest", "by_oid", "filled", "filled_by_oid", "top_open", "active_stats", "twap_states"]).describe(
1353
+ "latest: latest orders by address; by_oid: order by ID; filled: filled orders; filled_by_oid: filled order by ID; top_open: top open orders; active_stats: active order stats; twap_states: TWAP states"
1354
+ ),
1355
+ address: z6.string().optional().describe("REQUIRED for latest, filled, twap_states. Wallet address (0x...)"),
1356
+ oid: z6.string().optional().describe("REQUIRED for by_oid, filled_by_oid. Order ID"),
1357
+ coin: z6.string().optional().describe("Optional. Coin filter in uppercase"),
1358
+ min_val: z6.string().optional().describe("Optional for top_open. Min order value in USD"),
1359
+ whale_threshold: z6.string().optional().describe("Optional for active_stats. Whale threshold in USD"),
1360
+ limit: z6.string().optional().describe("Max results"),
1361
+ ...maxItemsParam
2667
1362
  },
2668
- async ({ address }) => {
2669
- try {
2670
- return ok(
2671
- await apiGet(
2672
- `/api/upgrade/v2/hl/twap-states/${address}/latest`
2673
- )
2674
- );
1363
+ async ({ action, address, oid, coin, min_val, whale_threshold, limit, _max_items }) => {
1364
+ try {
1365
+ switch (action) {
1366
+ case "latest": {
1367
+ if (!address) return err("address is required for latest action");
1368
+ const params = {};
1369
+ if (coin) params.coin = coin;
1370
+ if (limit) params.limit = limit;
1371
+ return okList(
1372
+ await apiGet(`/api/upgrade/v2/hl/orders/${address}/latest`, params),
1373
+ parseMax(_max_items, 50)
1374
+ );
1375
+ }
1376
+ case "by_oid": {
1377
+ if (!oid) return err("oid is required for by_oid action");
1378
+ return ok(await apiGet(`/api/upgrade/v2/hl/orders/oid/${oid}`));
1379
+ }
1380
+ case "filled": {
1381
+ if (!address) return err("address is required for filled action");
1382
+ const params = {};
1383
+ if (coin) params.coin = coin;
1384
+ if (limit) params.limit = limit;
1385
+ return okList(
1386
+ await apiGet(`/api/upgrade/v2/hl/filled-orders/${address}/latest`, params),
1387
+ parseMax(_max_items, 50)
1388
+ );
1389
+ }
1390
+ case "filled_by_oid": {
1391
+ if (!oid) return err("oid is required for filled_by_oid action");
1392
+ return ok(await apiGet(`/api/upgrade/v2/hl/filled-orders/oid/${oid}`));
1393
+ }
1394
+ case "top_open": {
1395
+ const params = {};
1396
+ if (coin) params.coin = coin;
1397
+ if (min_val) params.min_val = min_val;
1398
+ if (limit) params.limit = limit;
1399
+ return okList(
1400
+ await apiGet("/api/upgrade/v2/hl/orders/top-open-orders", params),
1401
+ parseMax(_max_items, 50)
1402
+ );
1403
+ }
1404
+ case "active_stats": {
1405
+ const params = {};
1406
+ if (coin) params.coin = coin;
1407
+ if (whale_threshold) params.whale_threshold = whale_threshold;
1408
+ return ok(await apiGet("/api/upgrade/v2/hl/orders/active-stats", params));
1409
+ }
1410
+ case "twap_states": {
1411
+ if (!address) return err("address is required for twap_states action");
1412
+ return ok(await apiGet(`/api/upgrade/v2/hl/twap-states/${address}/latest`));
1413
+ }
1414
+ }
2675
1415
  } catch (e) {
2676
1416
  return err(e);
2677
1417
  }
2678
1418
  }
2679
1419
  );
2680
1420
  server2.tool(
2681
- "hl_get_max_drawdown",
2682
- "Get max drawdown data by address",
1421
+ "hl_position",
1422
+ "Hyperliquid position data. Requires: address + coin for all actions.\n\u2022 current_history \u2014 current position history\n\u2022 completed_history \u2014 closed position history. Optional: startTime, endTime\n\u2022 current_pnl \u2014 current PnL. Requires: interval\n\u2022 completed_pnl \u2014 closed PnL. Requires: interval. Optional: startTime, endTime\n\u2022 current_executions \u2014 current execution trace. Requires: interval\n\u2022 completed_executions \u2014 closed execution trace. Requires: interval. Optional: startTime, endTime",
2683
1423
  {
2684
- address: z6.string().describe("Wallet address"),
2685
- days: z6.string().describe("Number of days, e.g. 7, 30, 90")
2686
- },
2687
- async ({ address, days }) => {
2688
- try {
2689
- return ok(
2690
- await apiGet(
2691
- `/api/upgrade/v2/hl/max-drawdown/${address}`,
2692
- { days }
2693
- )
2694
- );
1424
+ action: z6.enum(["current_history", "completed_history", "current_pnl", "completed_pnl", "current_executions", "completed_executions"]).describe(
1425
+ "current_history: current position history; completed_history: closed position history; current_pnl/completed_pnl: PnL data; current_executions/completed_executions: execution trace"
1426
+ ),
1427
+ address: z6.string().describe("REQUIRED. Wallet address (0x...)"),
1428
+ coin: z6.string().describe("REQUIRED. Coin in uppercase, e.g. BTC"),
1429
+ interval: z6.string().optional().describe("REQUIRED for current_pnl, completed_pnl, current_executions, completed_executions. Interval: 1h, 4h, 1d"),
1430
+ startTime: z6.string().optional().describe("Optional for completed_* actions. Start time in ms"),
1431
+ endTime: z6.string().optional().describe("Optional for completed_* actions. End time in ms")
1432
+ },
1433
+ async ({ action, address, coin, interval, startTime, endTime }) => {
1434
+ try {
1435
+ switch (action) {
1436
+ case "current_history":
1437
+ return ok(await apiGet(`/api/upgrade/v2/hl/traders/${address}/current-position-history/${coin}`));
1438
+ case "completed_history": {
1439
+ const params = {};
1440
+ if (startTime) params.startTime = startTime;
1441
+ if (endTime) params.endTime = endTime;
1442
+ return ok(await apiGet(`/api/upgrade/v2/hl/traders/${address}/completed-position-history/${coin}`, params));
1443
+ }
1444
+ case "current_pnl": {
1445
+ if (!interval) return err("interval is required for current_pnl action");
1446
+ return ok(await apiGet(`/api/upgrade/v2/hl/traders/${address}/current-position-pnl/${coin}`, { interval }));
1447
+ }
1448
+ case "completed_pnl": {
1449
+ if (!interval) return err("interval is required for completed_pnl action");
1450
+ const params = { interval };
1451
+ if (startTime) params.startTime = startTime;
1452
+ if (endTime) params.endTime = endTime;
1453
+ return ok(await apiGet(`/api/upgrade/v2/hl/traders/${address}/completed-position-pnl/${coin}`, params));
1454
+ }
1455
+ case "current_executions": {
1456
+ if (!interval) return err("interval is required for current_executions action");
1457
+ return ok(await apiGet(`/api/upgrade/v2/hl/traders/${address}/current-position-executions/${coin}`, { interval }));
1458
+ }
1459
+ case "completed_executions": {
1460
+ if (!interval) return err("interval is required for completed_executions action");
1461
+ const params = { interval };
1462
+ if (startTime) params.startTime = startTime;
1463
+ if (endTime) params.endTime = endTime;
1464
+ return ok(await apiGet(`/api/upgrade/v2/hl/traders/${address}/completed-position-executions/${coin}`, params));
1465
+ }
1466
+ }
2695
1467
  } catch (e) {
2696
1468
  return err(e);
2697
1469
  }
2698
1470
  }
2699
1471
  );
2700
1472
  server2.tool(
2701
- "hl_get_net_flow",
2702
- "Get ledger net flow by address",
1473
+ "hl_portfolio",
1474
+ "Hyperliquid portfolio data. Requires: address for all actions.\n\u2022 portfolio \u2014 account value curve. Requires: window (NOT days)\n\u2022 pnls \u2014 PNL curve. Optional: period\n\u2022 max_drawdown \u2014 max drawdown. Requires: days (NOT window)\n\u2022 net_flow \u2014 ledger net flow. Requires: days (NOT window)",
2703
1475
  {
2704
- address: z6.string().describe("Wallet address"),
2705
- days: z6.string().describe("Number of days, e.g. 7, 30, 90")
1476
+ action: z6.enum(["portfolio", "pnls", "max_drawdown", "net_flow"]).describe(
1477
+ "portfolio: account value curve; pnls: PNL curve; max_drawdown: max drawdown; net_flow: ledger net flow"
1478
+ ),
1479
+ address: z6.string().describe("REQUIRED. Wallet address (0x...)"),
1480
+ window: z6.string().optional().describe('REQUIRED for portfolio ONLY. Time window: "day", "week", "month", "allTime". NOT used by max_drawdown/net_flow'),
1481
+ period: z6.string().optional().describe("Optional for pnls. Period in days: 0=allTime, 1, 7, 30"),
1482
+ days: z6.string().optional().describe("REQUIRED for max_drawdown, net_flow. Number of days: 7, 30, 90. NOT used by portfolio"),
1483
+ ...maxItemsParam
2706
1484
  },
2707
- async ({ address, days }) => {
1485
+ async ({ action, address, window: win, period, days, _max_items }) => {
2708
1486
  try {
2709
- return ok(
2710
- await apiGet(
2711
- `/api/upgrade/v2/hl/ledger-updates/net-flow/${address}`,
2712
- { days }
2713
- )
2714
- );
1487
+ switch (action) {
1488
+ case "portfolio": {
1489
+ if (!win) return err("window is required for portfolio action");
1490
+ return okList(
1491
+ await apiGet(`/api/upgrade/v2/hl/portfolio/${address}/${win}`),
1492
+ parseMax(_max_items, 30)
1493
+ );
1494
+ }
1495
+ case "pnls": {
1496
+ const params = {};
1497
+ if (period) params.period = period;
1498
+ return okList(
1499
+ await apiGet(`/api/upgrade/v2/hl/pnls/${address}`, params),
1500
+ parseMax(_max_items, 100)
1501
+ );
1502
+ }
1503
+ case "max_drawdown": {
1504
+ if (!days) return err("days is required for max_drawdown action");
1505
+ return ok(await apiGet(`/api/upgrade/v2/hl/max-drawdown/${address}`, { days }));
1506
+ }
1507
+ case "net_flow": {
1508
+ if (!days) return err("days is required for net_flow action");
1509
+ return ok(await apiGet(`/api/upgrade/v2/hl/ledger-updates/net-flow/${address}`, { days }));
1510
+ }
1511
+ }
2715
1512
  } catch (e) {
2716
1513
  return err(e);
2717
1514
  }
2718
1515
  }
2719
1516
  );
2720
1517
  server2.tool(
2721
- "hl_get_klines_with_taker_vol",
2722
- "Get K-line data with taker volume",
1518
+ "hl_advanced",
1519
+ "Hyperliquid advanced.\n\u2022 info \u2014 generic Hyperliquid Info API. Requires: type\n\u2022 smart_find \u2014 smart money discovery. Optional: params_json\n\u2022 discover \u2014 trader discovery. Optional: params_json",
2723
1520
  {
2724
- coin: z6.string().describe("Coin, e.g. BTC"),
2725
- interval: z6.string().describe("Interval, e.g. 1h, 4h, 1d"),
1521
+ action: z6.enum(["info", "smart_find", "discover"]).describe(
1522
+ "info: generic Hyperliquid Info API; smart_find: smart money addresses; discover: trader discovery"
1523
+ ),
1524
+ type: z6.string().optional().describe("REQUIRED for info. Info type: metaAndAssetCtxs, clearinghouseState, allMids, etc."),
1525
+ user: z6.string().optional().describe("Optional for info. User wallet address (0x...)"),
1526
+ extra_params: z6.string().optional().describe("Optional for info. Extra params as JSON string"),
1527
+ params_json: z6.string().optional().describe("Optional for smart_find, discover. Search params as JSON string"),
2726
1528
  ...maxItemsParam
2727
1529
  },
2728
- async ({ coin, interval, _max_items }) => {
1530
+ async ({ action, type, user, extra_params, params_json, _max_items }) => {
2729
1531
  try {
2730
- return okList(
2731
- await apiGet(
2732
- `/api/upgrade/v2/hl/klines-with-taker-vol/${coin}/${interval}`
2733
- ),
2734
- parseMax(_max_items, 30)
2735
- );
1532
+ switch (action) {
1533
+ case "info": {
1534
+ if (!type) return err("type is required for info action");
1535
+ const body = { type };
1536
+ if (user) body.user = user;
1537
+ if (extra_params) Object.assign(body, JSON.parse(extra_params));
1538
+ return okList(await apiPost("/api/upgrade/v2/hl/info", body), parseMax(_max_items, 20));
1539
+ }
1540
+ case "smart_find":
1541
+ return okList(
1542
+ await apiPost("/api/upgrade/v2/hl/smart/find", JSON.parse(params_json || "{}")),
1543
+ parseMax(_max_items, 20)
1544
+ );
1545
+ case "discover":
1546
+ return okList(
1547
+ await apiPost("/api/upgrade/v2/hl/traders/discover", JSON.parse(params_json || "{}")),
1548
+ parseMax(_max_items, 20)
1549
+ );
1550
+ }
2736
1551
  } catch (e) {
2737
1552
  return err(e);
2738
1553
  }
@@ -2744,11 +1559,27 @@ function registerHyperliquidTools(server2) {
2744
1559
  import { z as z7 } from "zod";
2745
1560
  function registerGuideTools(server2) {
2746
1561
  server2.tool(
2747
- "guide_get_api_key",
2748
- "Guide user to register AiCoin account and generate OpenAPI key. Call this when API returns 401/403 or credentials are missing.",
2749
- {},
2750
- async () => {
2751
- const guide = `# AiCoin OpenAPI Key Setup Guide
1562
+ "guide",
1563
+ "Setup guides. Actions: api_key (get AiCoin API key), upgrade (tier comparison)",
1564
+ {
1565
+ action: z7.enum(["api_key", "upgrade"]).describe(
1566
+ "api_key: register & get API key; upgrade: tier comparison & upgrade"
1567
+ ),
1568
+ current_error: z7.string().optional().describe("For upgrade: the error message received"),
1569
+ endpoint: z7.string().optional().describe("For upgrade: the endpoint that returned 403")
1570
+ },
1571
+ async ({ action, current_error, endpoint }) => {
1572
+ switch (action) {
1573
+ case "api_key":
1574
+ return { content: [{ type: "text", text: getApiKeyGuide() }] };
1575
+ case "upgrade":
1576
+ return { content: [{ type: "text", text: getUpgradeGuide(current_error, endpoint) }] };
1577
+ }
1578
+ }
1579
+ );
1580
+ }
1581
+ function getApiKeyGuide() {
1582
+ return `# AiCoin OpenAPI Key Setup Guide
2752
1583
 
2753
1584
  ## Step 1: Register / Login
2754
1585
  Visit https://www.aicoin.com and create an account (or log in).
@@ -2788,24 +1619,19 @@ Add them to your MCP client config:
2788
1619
  }
2789
1620
  \`\`\`
2790
1621
 
2791
- After updating the config, restart your MCP client to apply.`;
2792
- return {
2793
- content: [{ type: "text", text: guide }]
2794
- };
2795
- }
2796
- );
2797
- server2.tool(
2798
- "guide_upgrade_tier",
2799
- "Guide user to upgrade API tier when current tier lacks permission for certain endpoints. Call this when API returns 403 or feature is tier-restricted.",
2800
- {
2801
- current_error: z7.string().optional().describe("The error message received"),
2802
- endpoint: z7.string().optional().describe("The endpoint that returned 403")
2803
- },
2804
- async ({ current_error, endpoint }) => {
2805
- const guide = `# AiCoin API Tier Upgrade Guide
1622
+ After updating the config, restart your MCP client to apply.
1623
+
1624
+ ## Want Trading Features?
1625
+ For exchange trading (place orders, check balances), use the full AiCoin MCP:
1626
+ \`\`\`
1627
+ npx -y @aicoin/aicoin-mcp
1628
+ \`\`\``;
1629
+ }
1630
+ function getUpgradeGuide(currentError, endpoint) {
1631
+ return `# AiCoin API Tier Upgrade Guide
2806
1632
 
2807
1633
  ## Current Issue
2808
- ${current_error ? `Error: ${current_error}` : "Your current API tier does not have permission for this endpoint."}
1634
+ ${currentError ? `Error: ${currentError}` : "Your current API tier does not have permission for this endpoint."}
2809
1635
  ${endpoint ? `Endpoint: ${endpoint}` : ""}
2810
1636
 
2811
1637
  ## API Tier Comparison
@@ -2831,103 +1657,6 @@ ${endpoint ? `Endpoint: ${endpoint}` : ""}
2831
1657
  5. Complete payment
2832
1658
 
2833
1659
  After upgrading, your existing key will be automatically upgraded. No config changes needed.`;
2834
- return {
2835
- content: [{ type: "text", text: guide }]
2836
- };
2837
- }
2838
- );
2839
- server2.tool(
2840
- "guide_setup_ccxt_trade",
2841
- "Guide user to set up the AiCoin Trade MCP server (CCXT-based) for executing trades. Includes exchange API key setup and local proxy configuration.",
2842
- {
2843
- exchange: z7.string().optional().describe(
2844
- "Target exchange: binance, okx, bybit, bitget, gate, huobi, pionex, hyperliquid"
2845
- )
2846
- },
2847
- async ({ exchange }) => {
2848
- const ex = exchange?.toLowerCase() || "binance";
2849
- const needsPass = ex === "okx" || ex === "bitget";
2850
- const EX = ex.toUpperCase();
2851
- let keyBlock = `${EX}_API_KEY=your_api_key
2852
- ${EX}_SECRET=your_secret`;
2853
- if (needsPass) keyBlock += `
2854
- ${EX}_PASSPHRASE=your_passphrase`;
2855
- let envJson = ` "${EX}_API_KEY": "<your_api_key>",
2856
- "${EX}_SECRET": "<your_secret>"`;
2857
- if (needsPass) {
2858
- envJson += `,
2859
- "${EX}_PASSPHRASE": "<your_passphrase>"`;
2860
- }
2861
- const guide = getTradeGuide(ex, EX, keyBlock, envJson);
2862
- return {
2863
- content: [{ type: "text", text: guide }]
2864
- };
2865
- }
2866
- );
2867
- }
2868
- function getExchangeGuide(ex) {
2869
- const guides = {
2870
- binance: '1. Log in to https://www.binance.com\n2. Go to Account \u2192 API Management\n3. Create API key, enable "Spot Trading" permission\n4. Recommended: set IP whitelist',
2871
- okx: '1. Log in to https://www.okx.com\n2. Go to Account \u2192 API \u2192 Create API Key\n3. Set passphrase, enable "Trade" permission\n4. Note: OKX requires a passphrase in addition to key/secret',
2872
- bybit: '1. Log in to https://www.bybit.com\n2. Go to Account \u2192 API Management\n3. Create API key with "Trade" permission',
2873
- bitget: '1. Log in to https://www.bitget.com\n2. Go to Account \u2192 API Management\n3. Create API key with passphrase, enable "Trade"\n4. Note: Bitget requires a passphrase',
2874
- gate: '1. Log in to https://www.gate.io\n2. Go to Account \u2192 API Management\n3. Create API key with "Spot Trade" permission',
2875
- huobi: '1. Log in to https://www.huobi.com\n2. Go to Account \u2192 API Management\n3. Create API key with "Trade" permission',
2876
- pionex: "1. Log in to https://www.pionex.com\n2. Go to Account \u2192 API Management\n3. Create API key",
2877
- hyperliquid: "1. Visit https://app.hyperliquid.xyz\n2. Connect your wallet\n3. Go to API \u2192 Generate API Key"
2878
- };
2879
- return guides[ex] || guides.binance;
2880
- }
2881
- function getTradeGuide(ex, EX, keyBlock, envJson) {
2882
- return `# AiCoin Trade MCP Setup Guide (CCXT)
2883
-
2884
- > All API keys are stored locally only. They are never sent to AiCoin servers.
2885
-
2886
- ## Step 1: Get Exchange API Key
2887
-
2888
- ${getExchangeGuide(ex)}
2889
-
2890
- \`\`\`
2891
- ${keyBlock}
2892
- \`\`\`
2893
-
2894
- ## Step 2: Proxy Configuration
2895
-
2896
- Many exchanges require proxy access in certain regions.
2897
- If you are in mainland China or behind a firewall, you likely need a local proxy.
2898
-
2899
- - If YES: set \`USE_PROXY=true\` and \`PROXY_URL\` (default: \`http://127.0.0.1:7890\`)
2900
- - If NO: set \`USE_PROXY=false\` or leave it unset
2901
-
2902
- Common proxy ports:
2903
- - Clash: 7890
2904
- - V2Ray: 10808
2905
- - Shadowsocks: 1080
2906
-
2907
- ## Step 3: Configure MCP Client
2908
-
2909
- \`\`\`json
2910
- {
2911
- "mcpServers": {
2912
- "aicoin-trade": {
2913
- "command": "npx",
2914
- "args": ["-y", "@aicoin/trade-mcp"],
2915
- "env": {
2916
- "DEFAULT_EXCHANGE": "${ex}",
2917
- ${envJson},
2918
- "USE_PROXY": "true",
2919
- "PROXY_URL": "http://127.0.0.1:7890"
2920
- }
2921
- }
2922
- }
2923
- }
2924
- \`\`\`
2925
-
2926
- ## Security Notes
2927
- - API keys are stored in your local MCP config only
2928
- - Never share your secret key with anyone
2929
- - Enable IP whitelist on the exchange if possible
2930
- - For trading, enable "Trade" permission; disable "Withdraw"`;
2931
1660
  }
2932
1661
 
2933
1662
  // src/tools/index.ts