@pear-protocol/exchanges-sdk 0.6.7 → 0.7.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 (40) hide show
  1. package/README.md +105 -25
  2. package/dist/client/bybit/rest.js +8 -1
  3. package/dist/client/hyperliquid/rest.js +21 -1
  4. package/dist/client/lighter/rest.js +6 -12
  5. package/dist/client/okx/rest.js +5 -1
  6. package/dist/index.d.ts +1110 -74
  7. package/dist/sdk.js +9 -2
  8. package/dist/tracker/balance-core.js +89 -0
  9. package/dist/tracker/balance.js +25 -0
  10. package/dist/tracker/basket-size.js +194 -0
  11. package/dist/tracker/binance/balance.js +11 -0
  12. package/dist/tracker/binance/mapper.js +87 -42
  13. package/dist/tracker/binance/tracker.js +29 -14
  14. package/dist/tracker/binance/types.js +0 -6
  15. package/dist/tracker/bybit/balance.js +14 -0
  16. package/dist/tracker/bybit/mapper.js +109 -52
  17. package/dist/tracker/bybit/tracker.js +242 -33
  18. package/dist/tracker/bybit/types.js +0 -7
  19. package/dist/tracker/hyperliquid/account-mode.js +14 -0
  20. package/dist/tracker/hyperliquid/balance.js +184 -0
  21. package/dist/tracker/hyperliquid/basket-size.js +93 -0
  22. package/dist/tracker/hyperliquid/coin-name.js +18 -0
  23. package/dist/tracker/hyperliquid/collateral.js +48 -0
  24. package/dist/tracker/hyperliquid/decimal.js +28 -0
  25. package/dist/tracker/hyperliquid/mapper.js +399 -176
  26. package/dist/tracker/hyperliquid/spot-pricing.js +106 -0
  27. package/dist/tracker/hyperliquid/tracker.js +237 -78
  28. package/dist/tracker/hyperliquid/types.js +1 -7
  29. package/dist/tracker/index.js +9 -7
  30. package/dist/tracker/lighter/balance.js +87 -0
  31. package/dist/tracker/lighter/basket-size.js +74 -0
  32. package/dist/tracker/lighter/mapper.js +324 -145
  33. package/dist/tracker/lighter/tracker.js +228 -117
  34. package/dist/tracker/lighter/types.js +1 -7
  35. package/dist/tracker/okx/balance.js +17 -0
  36. package/dist/tracker/okx/mapper.js +156 -58
  37. package/dist/tracker/okx/tracker.js +228 -29
  38. package/dist/tracker/okx/types.js +0 -8
  39. package/dist/tracker/types.js +0 -24
  40. package/package.json +5 -7
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ import PearSDK from '@pear-protocol/core-sdk';
3
3
  import { ProxyConfig } from '@pear-protocol/utils';
4
4
  import { WebSocket } from 'partysocket';
5
5
  import { WalletClient, Transport, Chain, Account } from 'viem';
6
+ import { z } from 'zod';
6
7
 
7
8
  type SupportedCredentials = HttpTypes.ExchangeCredentialsResponse['credentials'];
8
9
  type ExchangesSDKConfig = {
@@ -809,65 +810,440 @@ declare class OkxAccountSyncer extends BaseAccountSyncer<RawFill> {
809
810
  private contractsToBase;
810
811
  }
811
812
 
812
- declare enum BinanceAccountType {
813
- MULTI_ASSET = "MULTI_ASSET",
814
- SINGLE_ASSET = "SINGLE_ASSET"
815
- }
816
-
817
- declare enum BybitAccountType {
818
- ISOLATED_MARGIN = "ISOLATED_MARGIN",
819
- REGULAR_MARGIN = "REGULAR_MARGIN",
820
- PORTFOLIO_MARGIN = "PORTFOLIO_MARGIN"
821
- }
813
+ /**
814
+ * The account balance a consumer receives, as one discriminated union over `accountMode`.
815
+ *
816
+ * Narrowing on the tag gives exactly the fields that venue and mode support and no others, and a
817
+ * newly added mode fails every exhaustive `switch` at compile time. This module sits above the
818
+ * venue variant files, which in turn sit above `./balance-core` — one direction, no cycle.
819
+ */
822
820
 
823
- declare enum HyperliquidAccountType {
824
- DEFAULT = "default",
825
- DISABLED = "disabled",
826
- PORTFOLIO_MARGIN = "portfolioMargin",
827
- UNIFIED_ACCOUNT = "unifiedAccount"
828
- }
821
+ declare const AccountBalance: z.ZodDiscriminatedUnion<[z.ZodObject<{
822
+ totalEquity: z.ZodNullable<z.ZodString>;
823
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
824
+ availableMargin: z.ZodNullable<z.ZodString>;
825
+ poolsShared: z.ZodBoolean;
826
+ perCollateral: z.ZodArray<z.ZodObject<{
827
+ asset: z.ZodString;
828
+ equity: z.ZodString;
829
+ availableMargin: z.ZodNullable<z.ZodString>;
830
+ withdrawable: z.ZodNullable<z.ZodString>;
831
+ }, z.core.$strip>>;
832
+ timestamp: z.ZodNumber;
833
+ accountMode: z.ZodLiteral<"hyperliquid:standard">;
834
+ spotEquity: z.ZodNullable<z.ZodString>;
835
+ perpsEquity: z.ZodString;
836
+ vaultEquity: z.ZodString;
837
+ stakedEquity: z.ZodNullable<z.ZodString>;
838
+ unrealizedPnl: z.ZodString;
839
+ maintenanceMargin: z.ZodString;
840
+ crossMarginRatio: z.ZodString;
841
+ crossAccountLeverage: z.ZodString;
842
+ perDexState: z.ZodArray<z.ZodObject<{
843
+ dex: z.ZodString;
844
+ collateralToken: z.ZodNullable<z.ZodNumber>;
845
+ accountValue: z.ZodString;
846
+ crossNotional: z.ZodString;
847
+ crossMaintenanceMargin: z.ZodString;
848
+ withdrawable: z.ZodString;
849
+ }, z.core.$strip>>;
850
+ }, z.core.$strip>, z.ZodObject<{
851
+ totalEquity: z.ZodNullable<z.ZodString>;
852
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
853
+ availableMargin: z.ZodNullable<z.ZodString>;
854
+ poolsShared: z.ZodBoolean;
855
+ perCollateral: z.ZodArray<z.ZodObject<{
856
+ asset: z.ZodString;
857
+ equity: z.ZodString;
858
+ availableMargin: z.ZodNullable<z.ZodString>;
859
+ withdrawable: z.ZodNullable<z.ZodString>;
860
+ }, z.core.$strip>>;
861
+ timestamp: z.ZodNumber;
862
+ accountMode: z.ZodLiteral<"hyperliquid:unified">;
863
+ tradingEquity: z.ZodNullable<z.ZodString>;
864
+ vaultEquity: z.ZodString;
865
+ stakedEquity: z.ZodNullable<z.ZodString>;
866
+ portfolioValue: z.ZodNullable<z.ZodString>;
867
+ unrealizedPnl: z.ZodString;
868
+ perpsMaintenanceMargin: z.ZodString;
869
+ unifiedAccountRatio: z.ZodString;
870
+ unifiedAccountLeverage: z.ZodNullable<z.ZodString>;
871
+ perDexState: z.ZodArray<z.ZodObject<{
872
+ dex: z.ZodString;
873
+ collateralToken: z.ZodNullable<z.ZodNumber>;
874
+ accountValue: z.ZodString;
875
+ crossNotional: z.ZodString;
876
+ crossMaintenanceMargin: z.ZodString;
877
+ withdrawable: z.ZodString;
878
+ }, z.core.$strip>>;
879
+ }, z.core.$strip>, z.ZodObject<{
880
+ totalEquity: z.ZodNullable<z.ZodString>;
881
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
882
+ availableMargin: z.ZodNullable<z.ZodString>;
883
+ poolsShared: z.ZodBoolean;
884
+ timestamp: z.ZodNumber;
885
+ accountMode: z.ZodLiteral<"hyperliquid:portfolioMargin">;
886
+ perCollateral: z.ZodArray<z.ZodObject<{
887
+ asset: z.ZodString;
888
+ equity: z.ZodString;
889
+ availableMargin: z.ZodNullable<z.ZodString>;
890
+ withdrawable: z.ZodString;
891
+ ltv: z.ZodNullable<z.ZodString>;
892
+ borrowCapUsed: z.ZodNullable<z.ZodString>;
893
+ }, z.core.$strip>>;
894
+ tradingEquity: z.ZodNullable<z.ZodString>;
895
+ vaultEquity: z.ZodString;
896
+ stakedEquity: z.ZodNullable<z.ZodString>;
897
+ portfolioValue: z.ZodNullable<z.ZodString>;
898
+ unrealizedPnl: z.ZodString;
899
+ perpsMaintenanceMargin: z.ZodString;
900
+ portfolioMarginRatio: z.ZodNullable<z.ZodString>;
901
+ portfolioAccountLeverage: z.ZodNullable<z.ZodString>;
902
+ borrowCapUsed: z.ZodNullable<z.ZodString>;
903
+ perDexState: z.ZodArray<z.ZodObject<{
904
+ dex: z.ZodString;
905
+ collateralToken: z.ZodNullable<z.ZodNumber>;
906
+ accountValue: z.ZodString;
907
+ crossNotional: z.ZodString;
908
+ crossMaintenanceMargin: z.ZodString;
909
+ withdrawable: z.ZodString;
910
+ }, z.core.$strip>>;
911
+ }, z.core.$strip>, z.ZodObject<{
912
+ totalEquity: z.ZodNullable<z.ZodString>;
913
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
914
+ availableMargin: z.ZodNullable<z.ZodString>;
915
+ poolsShared: z.ZodBoolean;
916
+ perCollateral: z.ZodArray<z.ZodObject<{
917
+ asset: z.ZodString;
918
+ equity: z.ZodString;
919
+ availableMargin: z.ZodNullable<z.ZodString>;
920
+ withdrawable: z.ZodNullable<z.ZodString>;
921
+ }, z.core.$strip>>;
922
+ timestamp: z.ZodNumber;
923
+ tradingEquity: z.ZodNullable<z.ZodString>;
924
+ perpetualsEquity: z.ZodNullable<z.ZodString>;
925
+ spotEquity: z.ZodNullable<z.ZodString>;
926
+ publicPoolsEquity: z.ZodNullable<z.ZodString>;
927
+ stakingEquity: z.ZodNullable<z.ZodString>;
928
+ creditedInLit: z.ZodNullable<z.ZodString>;
929
+ unrealizedPnl: z.ZodNullable<z.ZodString>;
930
+ crossLeverage: z.ZodNullable<z.ZodString>;
931
+ maintenanceMargin: z.ZodNullable<z.ZodString>;
932
+ crossMarginUsage: z.ZodNullable<z.ZodString>;
933
+ crossMarginRatio: z.ZodNullable<z.ZodString>;
934
+ accountMode: z.ZodLiteral<"lighter:classic">;
935
+ }, z.core.$strip>, z.ZodObject<{
936
+ totalEquity: z.ZodNullable<z.ZodString>;
937
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
938
+ availableMargin: z.ZodNullable<z.ZodString>;
939
+ poolsShared: z.ZodBoolean;
940
+ perCollateral: z.ZodArray<z.ZodObject<{
941
+ asset: z.ZodString;
942
+ equity: z.ZodString;
943
+ availableMargin: z.ZodNullable<z.ZodString>;
944
+ withdrawable: z.ZodNullable<z.ZodString>;
945
+ }, z.core.$strip>>;
946
+ timestamp: z.ZodNumber;
947
+ portfolioMargin: z.ZodNullable<z.ZodString>;
948
+ tradingEquity: z.ZodNullable<z.ZodString>;
949
+ perpetualsEquity: z.ZodNullable<z.ZodString>;
950
+ spotEquity: z.ZodNullable<z.ZodString>;
951
+ publicPoolsEquity: z.ZodNullable<z.ZodString>;
952
+ stakingEquity: z.ZodNullable<z.ZodString>;
953
+ creditedInLit: z.ZodNullable<z.ZodString>;
954
+ unrealizedPnl: z.ZodNullable<z.ZodString>;
955
+ crossLeverage: z.ZodNullable<z.ZodString>;
956
+ maintenanceMargin: z.ZodNullable<z.ZodString>;
957
+ crossMarginUsage: z.ZodNullable<z.ZodString>;
958
+ crossMarginRatio: z.ZodNullable<z.ZodString>;
959
+ accountMode: z.ZodLiteral<"lighter:unified">;
960
+ }, z.core.$strip>, z.ZodObject<{
961
+ totalEquity: z.ZodNullable<z.ZodString>;
962
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
963
+ availableMargin: z.ZodNullable<z.ZodString>;
964
+ poolsShared: z.ZodBoolean;
965
+ perCollateral: z.ZodArray<z.ZodObject<{
966
+ asset: z.ZodString;
967
+ equity: z.ZodString;
968
+ availableMargin: z.ZodNullable<z.ZodString>;
969
+ withdrawable: z.ZodNullable<z.ZodString>;
970
+ }, z.core.$strip>>;
971
+ timestamp: z.ZodNumber;
972
+ accountMode: z.ZodLiteral<"binance:singleAsset">;
973
+ }, z.core.$strip>, z.ZodObject<{
974
+ totalEquity: z.ZodNullable<z.ZodString>;
975
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
976
+ availableMargin: z.ZodNullable<z.ZodString>;
977
+ poolsShared: z.ZodBoolean;
978
+ perCollateral: z.ZodArray<z.ZodObject<{
979
+ asset: z.ZodString;
980
+ equity: z.ZodString;
981
+ availableMargin: z.ZodNullable<z.ZodString>;
982
+ withdrawable: z.ZodNullable<z.ZodString>;
983
+ }, z.core.$strip>>;
984
+ timestamp: z.ZodNumber;
985
+ accountMode: z.ZodLiteral<"binance:multiAsset">;
986
+ }, z.core.$strip>, z.ZodObject<{
987
+ totalEquity: z.ZodNullable<z.ZodString>;
988
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
989
+ availableMargin: z.ZodNullable<z.ZodString>;
990
+ poolsShared: z.ZodBoolean;
991
+ perCollateral: z.ZodArray<z.ZodObject<{
992
+ asset: z.ZodString;
993
+ equity: z.ZodString;
994
+ availableMargin: z.ZodNullable<z.ZodString>;
995
+ withdrawable: z.ZodNullable<z.ZodString>;
996
+ }, z.core.$strip>>;
997
+ timestamp: z.ZodNumber;
998
+ accountMode: z.ZodLiteral<"bybit:isolatedMargin">;
999
+ }, z.core.$strip>, z.ZodObject<{
1000
+ totalEquity: z.ZodNullable<z.ZodString>;
1001
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1002
+ availableMargin: z.ZodNullable<z.ZodString>;
1003
+ poolsShared: z.ZodBoolean;
1004
+ perCollateral: z.ZodArray<z.ZodObject<{
1005
+ asset: z.ZodString;
1006
+ equity: z.ZodString;
1007
+ availableMargin: z.ZodNullable<z.ZodString>;
1008
+ withdrawable: z.ZodNullable<z.ZodString>;
1009
+ }, z.core.$strip>>;
1010
+ timestamp: z.ZodNumber;
1011
+ accountMode: z.ZodLiteral<"bybit:regularMargin">;
1012
+ }, z.core.$strip>, z.ZodObject<{
1013
+ totalEquity: z.ZodNullable<z.ZodString>;
1014
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1015
+ availableMargin: z.ZodNullable<z.ZodString>;
1016
+ poolsShared: z.ZodBoolean;
1017
+ perCollateral: z.ZodArray<z.ZodObject<{
1018
+ asset: z.ZodString;
1019
+ equity: z.ZodString;
1020
+ availableMargin: z.ZodNullable<z.ZodString>;
1021
+ withdrawable: z.ZodNullable<z.ZodString>;
1022
+ }, z.core.$strip>>;
1023
+ timestamp: z.ZodNumber;
1024
+ accountMode: z.ZodLiteral<"bybit:portfolioMargin">;
1025
+ }, z.core.$strip>, z.ZodObject<{
1026
+ totalEquity: z.ZodNullable<z.ZodString>;
1027
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1028
+ availableMargin: z.ZodNullable<z.ZodString>;
1029
+ poolsShared: z.ZodBoolean;
1030
+ perCollateral: z.ZodArray<z.ZodObject<{
1031
+ asset: z.ZodString;
1032
+ equity: z.ZodString;
1033
+ availableMargin: z.ZodNullable<z.ZodString>;
1034
+ withdrawable: z.ZodNullable<z.ZodString>;
1035
+ }, z.core.$strip>>;
1036
+ timestamp: z.ZodNumber;
1037
+ accountMode: z.ZodLiteral<"okx:spot">;
1038
+ }, z.core.$strip>, z.ZodObject<{
1039
+ totalEquity: z.ZodNullable<z.ZodString>;
1040
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1041
+ availableMargin: z.ZodNullable<z.ZodString>;
1042
+ poolsShared: z.ZodBoolean;
1043
+ perCollateral: z.ZodArray<z.ZodObject<{
1044
+ asset: z.ZodString;
1045
+ equity: z.ZodString;
1046
+ availableMargin: z.ZodNullable<z.ZodString>;
1047
+ withdrawable: z.ZodNullable<z.ZodString>;
1048
+ }, z.core.$strip>>;
1049
+ timestamp: z.ZodNumber;
1050
+ accountMode: z.ZodLiteral<"okx:futures">;
1051
+ }, z.core.$strip>, z.ZodObject<{
1052
+ totalEquity: z.ZodNullable<z.ZodString>;
1053
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1054
+ availableMargin: z.ZodNullable<z.ZodString>;
1055
+ poolsShared: z.ZodBoolean;
1056
+ perCollateral: z.ZodArray<z.ZodObject<{
1057
+ asset: z.ZodString;
1058
+ equity: z.ZodString;
1059
+ availableMargin: z.ZodNullable<z.ZodString>;
1060
+ withdrawable: z.ZodNullable<z.ZodString>;
1061
+ }, z.core.$strip>>;
1062
+ timestamp: z.ZodNumber;
1063
+ accountMode: z.ZodLiteral<"okx:multiCurrencyMargin">;
1064
+ }, z.core.$strip>, z.ZodObject<{
1065
+ totalEquity: z.ZodNullable<z.ZodString>;
1066
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1067
+ availableMargin: z.ZodNullable<z.ZodString>;
1068
+ poolsShared: z.ZodBoolean;
1069
+ perCollateral: z.ZodArray<z.ZodObject<{
1070
+ asset: z.ZodString;
1071
+ equity: z.ZodString;
1072
+ availableMargin: z.ZodNullable<z.ZodString>;
1073
+ withdrawable: z.ZodNullable<z.ZodString>;
1074
+ }, z.core.$strip>>;
1075
+ timestamp: z.ZodNumber;
1076
+ accountMode: z.ZodLiteral<"okx:portfolioMargin">;
1077
+ }, z.core.$strip>], "accountMode">;
1078
+ type AccountBalance = z.infer<typeof AccountBalance>;
829
1079
 
830
- declare enum LighterAccountType {
831
- /** @deprecated Use `CLASSIC`; retained as a source-compatible alias. */
832
- BASIC = "classic",
833
- CLASSIC = "classic",
834
- UNIFIED = "unified"
835
- }
1080
+ /**
1081
+ * The primitives every account-balance variant is built from: decimal string formats, the
1082
+ * `accountMode` union tag, and the four core fields every venue fills in every mode.
1083
+ *
1084
+ * This module is the root of the balance schema graph — venue variant files import it, and the
1085
+ * union in `./balance` imports those. Keeping the primitives out of `./balance` is what stops
1086
+ * that graph from becoming a cycle.
1087
+ */
836
1088
 
837
- declare enum OkxAccountType {
838
- SPOT = "OKX_SPOT",
839
- SINGLE_CURRENCY_MARGIN = "OKX_SINGLE",
840
- MULTI_CURRENCY_MARGIN = "OKX_MULTI",
841
- PORTFOLIO_MARGIN = "OKX_PORTFOLIO"
842
- }
1089
+ /** Unsigned decimal, e.g. "1234.56". Never a JS number — precision is load-bearing. */
1090
+ declare const DecimalString: z.ZodString;
1091
+ /** Signed decimal, e.g. "+1234.56" / "-1234.56". BUY positive, SELL negative. */
1092
+ declare const SignedDecimalString: z.ZodString;
1093
+ declare const MarginMode: z.ZodEnum<{
1094
+ isolated: "isolated";
1095
+ cross: "cross";
1096
+ }>;
1097
+ type MarginMode = z.infer<typeof MarginMode>;
1098
+ declare const Side: z.ZodEnum<{
1099
+ BUY: "BUY";
1100
+ SELL: "SELL";
1101
+ }>;
1102
+ type Side = z.infer<typeof Side>;
1103
+ /**
1104
+ * The union tag: venue AND mode in one literal, so narrowing needs no separate venue check.
1105
+ * `hyperliquid:standard` covers the API's `default` and `disabled` — verified identical.
1106
+ */
1107
+ declare const AccountMode: z.ZodEnum<{
1108
+ "hyperliquid:standard": "hyperliquid:standard";
1109
+ "hyperliquid:unified": "hyperliquid:unified";
1110
+ "hyperliquid:portfolioMargin": "hyperliquid:portfolioMargin";
1111
+ "lighter:classic": "lighter:classic";
1112
+ "lighter:unified": "lighter:unified";
1113
+ "binance:singleAsset": "binance:singleAsset";
1114
+ "binance:multiAsset": "binance:multiAsset";
1115
+ "bybit:isolatedMargin": "bybit:isolatedMargin";
1116
+ "bybit:regularMargin": "bybit:regularMargin";
1117
+ "bybit:portfolioMargin": "bybit:portfolioMargin";
1118
+ "okx:spot": "okx:spot";
1119
+ "okx:futures": "okx:futures";
1120
+ "okx:multiCurrencyMargin": "okx:multiCurrencyMargin";
1121
+ "okx:portfolioMargin": "okx:portfolioMargin";
1122
+ }>;
1123
+ type AccountMode = z.infer<typeof AccountMode>;
1124
+ /** One collateral pool's own figures, in THAT asset's own units. Never converted. */
1125
+ declare const CollateralBalance: z.ZodObject<{
1126
+ asset: z.ZodString;
1127
+ equity: z.ZodString;
1128
+ availableMargin: z.ZodNullable<z.ZodString>;
1129
+ withdrawable: z.ZodNullable<z.ZodString>;
1130
+ }, z.core.$strip>;
1131
+ type CollateralBalance = z.infer<typeof CollateralBalance>;
1132
+ /**
1133
+ * Filled by every venue in every mode: the USD scalars a consumer reads without narrowing, plus the
1134
+ * per-collateral rows that say what is actually spendable in each currency.
1135
+ *
1136
+ * The rows are per-asset by construction, so the only USD figures in a variant are the scalars —
1137
+ * which is what makes mixing units impossible rather than merely discouraged.
1138
+ */
1139
+ declare const AccountBalanceCore: z.ZodObject<{
1140
+ totalEquity: z.ZodNullable<z.ZodString>;
1141
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1142
+ availableMargin: z.ZodNullable<z.ZodString>;
1143
+ poolsShared: z.ZodBoolean;
1144
+ perCollateral: z.ZodArray<z.ZodObject<{
1145
+ asset: z.ZodString;
1146
+ equity: z.ZodString;
1147
+ availableMargin: z.ZodNullable<z.ZodString>;
1148
+ withdrawable: z.ZodNullable<z.ZodString>;
1149
+ }, z.core.$strip>>;
1150
+ timestamp: z.ZodNumber;
1151
+ }, z.core.$strip>;
1152
+ /** Human-readable name for each mode, as the venue's own account page labels it. */
1153
+ declare const ACCOUNT_MODE_LABELS: Record<AccountMode, string>;
843
1154
 
844
- type MarginMode = 'cross' | 'isolated';
845
- type AccountType = BinanceAccountType | BybitAccountType | HyperliquidAccountType | LighterAccountType | OkxAccountType;
846
- declare const ACCOUNT_TYPE_LABELS: Record<AccountType, string>;
847
- interface AssetBalance {
1155
+ /**
1156
+ * Mirrors the shipped basket model (`BasketItem` in the frontend): unsigned `weight`
1157
+ * with `side` alongside, weights summing to 100. Sizing ignores `side` — margin
1158
+ * requirement does not depend on direction — and normalises by Σweight.
1159
+ */
1160
+ declare const BasketLeg: z.ZodObject<{
1161
+ asset: z.ZodString;
1162
+ marginMode: z.ZodEnum<{
1163
+ isolated: "isolated";
1164
+ cross: "cross";
1165
+ }>;
1166
+ leverage: z.ZodString;
1167
+ side: z.ZodEnum<{
1168
+ BUY: "BUY";
1169
+ SELL: "SELL";
1170
+ }>;
1171
+ weight: z.ZodNumber;
1172
+ }, z.core.$strip>;
1173
+ type BasketLeg = z.infer<typeof BasketLeg>;
1174
+ declare const MaxBasketSizeInput: z.ZodObject<{
1175
+ legs: z.ZodArray<z.ZodObject<{
1176
+ asset: z.ZodString;
1177
+ marginMode: z.ZodEnum<{
1178
+ isolated: "isolated";
1179
+ cross: "cross";
1180
+ }>;
1181
+ leverage: z.ZodString;
1182
+ side: z.ZodEnum<{
1183
+ BUY: "BUY";
1184
+ SELL: "SELL";
1185
+ }>;
1186
+ weight: z.ZodNumber;
1187
+ }, z.core.$strip>>;
1188
+ }, z.core.$strip>;
1189
+ type MaxBasketSizeInput = z.infer<typeof MaxBasketSizeInput>;
1190
+ declare const MaxBasketSizeResult: z.ZodObject<{
1191
+ maxNotional: z.ZodNullable<z.ZodString>;
1192
+ legs: z.ZodArray<z.ZodObject<{
1193
+ asset: z.ZodString;
1194
+ notional: z.ZodString;
1195
+ marginRequired: z.ZodString;
1196
+ }, z.core.$strip>>;
1197
+ bindingConstraint: z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
1198
+ kind: z.ZodLiteral<"cross-pool">;
1199
+ pool: z.ZodString;
1200
+ }, z.core.$strip>, z.ZodObject<{
1201
+ kind: z.ZodLiteral<"isolated-leg">;
1202
+ asset: z.ZodString;
1203
+ }, z.core.$strip>], "kind">>;
1204
+ }, z.core.$strip>;
1205
+ type MaxBasketSizeResult = z.infer<typeof MaxBasketSizeResult>;
1206
+ /**
1207
+ * One basket leg with its leverage already capped by the venue adapter.
1208
+ *
1209
+ * `marginMode` does not enter the maths: an isolated leg gets dedicated margin, but that margin is
1210
+ * still transferred out of the same free balance, so it draws on the same budget as a cross leg.
1211
+ * It is carried so the caller passes its basket through unchanged.
1212
+ */
1213
+ type CappedBasketLeg = {
848
1214
  asset: string;
849
- free: string;
850
- used: string;
851
- total: string;
852
- walletBalance: string;
853
- usdValue: string;
854
- }
855
- interface AccountBalance {
856
- accountType: AccountType;
857
- accountTier?: string;
858
- free: Record<string, string>;
859
- used: Record<string, string>;
860
- total: Record<string, string>;
861
- availableToTrade: string;
862
- totalEquity: string;
863
- walletBalance: string;
864
- unrealizedPnl: string;
865
- initialMarginUsed: string;
866
- maintenanceMargin: string;
867
- marginRatio: string;
868
- assets: AssetBalance[];
869
- timestamp: number;
870
- }
1215
+ /**
1216
+ * The collateral pool this leg's margin comes out of, as the venue adapter resolves it — a CEX
1217
+ * from the symbol's settlement currency, Hyperliquid from the dex's collateral token. Legs in
1218
+ * different pools cannot fund each other.
1219
+ */
1220
+ pool: string;
1221
+ /** Unsigned, in the caller's own scale — `computeMaxBasketSize` normalises by Σweight. */
1222
+ weight: number;
1223
+ effectiveLeverage: string;
1224
+ marginMode: MarginMode;
1225
+ /** This leg's own venue ceiling in USD notional; `null` when the venue names no cap. */
1226
+ maxNotional: string | null;
1227
+ };
1228
+ /** The margin budget behind each collateral pool, plus the legs those pools must fund at once. */
1229
+ type MaxBasketSizeCalculation = {
1230
+ /**
1231
+ * Pool id to that pool's USD-equivalent budget. A pool whose collateral is not ~1 USD supplies no
1232
+ * entry until someone adds a price source, and a leg drawing on a missing entry voids the answer.
1233
+ */
1234
+ budgets: Record<string, string>;
1235
+ legs: CappedBasketLeg[];
1236
+ };
1237
+ /**
1238
+ * The largest gross notional this basket can reach while every leg stays funded at its weight.
1239
+ *
1240
+ * Returns a null size when a pool behind the basket cannot be valued — never a zero, which a
1241
+ * consumer would read as "no collateral" rather than "not known". A basket whose own figures cannot
1242
+ * be sized (see `isSizeableInput`) gets the same null, so this call never throws and never returns a
1243
+ * result that fails `MaxBasketSizeResult`.
1244
+ */
1245
+ declare function computeMaxBasketSize(input: MaxBasketSizeCalculation): MaxBasketSizeResult;
1246
+
871
1247
  interface AccountPosition {
872
1248
  symbol: string;
873
1249
  side: 'long' | 'short' | 'both';
@@ -924,12 +1300,16 @@ interface AccountTracker {
924
1300
  disconnect(): Promise<void>;
925
1301
  snapshot(): Promise<AccountSnapshot>;
926
1302
  snapshotAssets(coins: string[]): Promise<AssetSnapshotMap>;
1303
+ /** Sizes a basket over REST alone, so it stays usable without a running socket. */
1304
+ snapshotMaxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
927
1305
  readonly isConnected: boolean;
928
1306
  readonly isInitialized: boolean;
929
1307
  readonly hasListeners: boolean;
930
1308
  trackBalance(cb: BalanceCallback): () => void;
931
1309
  trackPosition(cb: PositionsCallback): () => void;
932
1310
  trackAsset(asset: string, cb: TrackedAssetCallback): () => void;
1311
+ /** Async: a basket may name assets this tracker has not subscribed to yet. */
1312
+ maxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
933
1313
  getBalance(): AccountBalance | null;
934
1314
  getPositions(): AccountPosition[];
935
1315
  getTrackedAsset(coin: string): TrackedAssetInfo | null;
@@ -970,6 +1350,9 @@ declare abstract class BaseAccountTracker implements AccountTracker {
970
1350
  private broadcast;
971
1351
  abstract start(): Promise<void>;
972
1352
  abstract snapshot(): Promise<AccountSnapshot>;
1353
+ /** Every venue implements both sizing paths — the live one and the REST one. */
1354
+ abstract maxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
1355
+ abstract snapshotMaxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
973
1356
  protected abstract fetchAssetSnapshots(coins: string[]): Promise<AssetSnapshotMap>;
974
1357
  abstract get isConnected(): boolean;
975
1358
  protected abstract ensureAssetTracked(asset: string): void;
@@ -977,6 +1360,51 @@ declare abstract class BaseAccountTracker implements AccountTracker {
977
1360
  protected abstract cleanupConnections(): void | Promise<void>;
978
1361
  }
979
1362
 
1363
+ /**
1364
+ * Binance's two account-mode balance variants.
1365
+ *
1366
+ * Core fields only, with `null` wherever a figure cannot be derived. What differs by mode is not the
1367
+ * shape but when the core scalars go null, which follows each mode's collateral-pool model. One
1368
+ * `z.literal` per mode, because `z.discriminatedUnion` needs a single literal tag per member rather
1369
+ * than a `z.enum` shorthand.
1370
+ */
1371
+
1372
+ /**
1373
+ * Single-asset mode runs one collateral pool per settlement currency, and Binance's account-level
1374
+ * figures cover USDT only there. Once a second pool is funded no account total exists to report, so
1375
+ * `totalEquity` goes null and `perCollateral` is the whole answer.
1376
+ */
1377
+ declare const BinanceSingleAssetBalance: z.ZodObject<{
1378
+ totalEquity: z.ZodNullable<z.ZodString>;
1379
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1380
+ availableMargin: z.ZodNullable<z.ZodString>;
1381
+ poolsShared: z.ZodBoolean;
1382
+ perCollateral: z.ZodArray<z.ZodObject<{
1383
+ asset: z.ZodString;
1384
+ equity: z.ZodString;
1385
+ availableMargin: z.ZodNullable<z.ZodString>;
1386
+ withdrawable: z.ZodNullable<z.ZodString>;
1387
+ }, z.core.$strip>>;
1388
+ timestamp: z.ZodNumber;
1389
+ accountMode: z.ZodLiteral<"binance:singleAsset">;
1390
+ }, z.core.$strip>;
1391
+ type BinanceSingleAssetBalance = z.infer<typeof BinanceSingleAssetBalance>;
1392
+ declare const BinanceMultiAssetBalance: z.ZodObject<{
1393
+ totalEquity: z.ZodNullable<z.ZodString>;
1394
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1395
+ availableMargin: z.ZodNullable<z.ZodString>;
1396
+ poolsShared: z.ZodBoolean;
1397
+ perCollateral: z.ZodArray<z.ZodObject<{
1398
+ asset: z.ZodString;
1399
+ equity: z.ZodString;
1400
+ availableMargin: z.ZodNullable<z.ZodString>;
1401
+ withdrawable: z.ZodNullable<z.ZodString>;
1402
+ }, z.core.$strip>>;
1403
+ timestamp: z.ZodNumber;
1404
+ accountMode: z.ZodLiteral<"binance:multiAsset">;
1405
+ }, z.core.$strip>;
1406
+ type BinanceMultiAssetBalance = z.infer<typeof BinanceMultiAssetBalance>;
1407
+
980
1408
  type BinanceAccountTrackerConfig = AccountTrackerConfig & {
981
1409
  credentials: SupportedCredentials;
982
1410
  listenKeyRefreshMs?: number;
@@ -993,10 +1421,19 @@ declare class BinanceAccountTracker extends BaseAccountTracker {
993
1421
  private listenKeyTimer;
994
1422
  private pollTimer;
995
1423
  private currentPositions;
996
- private accountType;
1424
+ private accountMode;
997
1425
  private trackedAssetInfos;
998
1426
  constructor(config: BinanceAccountTrackerConfig);
999
1427
  snapshot(): Promise<AccountSnapshot>;
1428
+ /**
1429
+ * Binance sizes no basket in v1: the SDK reads no per-asset max leverage from it, and sizing off
1430
+ * `availableMargin` alone would ship a number no venue field backs. The missing input is
1431
+ * `/fapi/v2/positionRisk` → `maxNotionalValue` (the account's own per-symbol ceiling), with
1432
+ * `/fapi/v1/leverageBracket` behind it for the tier a larger size would fall into.
1433
+ */
1434
+ maxBasketSize(_input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
1435
+ /** The REST path answers the same way — there is no size either way, not a slower one. */
1436
+ snapshotMaxBasketSize(_input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
1000
1437
  /**
1001
1438
  * Stateless one-shot per-asset settings read: `positionRisk` with no symbol returns leverage +
1002
1439
  * margin type for every symbol (positioned or not), so any number of assets costs one call.
@@ -1017,6 +1454,64 @@ declare class BinanceAccountTracker extends BaseAccountTracker {
1017
1454
  private refreshAllPositions;
1018
1455
  }
1019
1456
 
1457
+ /**
1458
+ * Bybit's three account-mode balance variants.
1459
+ *
1460
+ * Core fields only — Bybit carries no per-mode detail yet, with `null` wherever a figure cannot
1461
+ * be derived. All three are unified-account modes sharing one margin pool, so the core scalars are
1462
+ * the whole answer and `perCollateral` only breaks them down — where Binance single-asset and OKX
1463
+ * Spot/Futures have to null those scalars once a second pool is funded. The mode still tags the
1464
+ * variant so detail can be added later without another breaking change. One `z.literal` per mode,
1465
+ * because `z.discriminatedUnion` needs a single literal tag per member rather than a `z.enum`
1466
+ * shorthand.
1467
+ */
1468
+
1469
+ declare const BybitIsolatedMarginBalance: z.ZodObject<{
1470
+ totalEquity: z.ZodNullable<z.ZodString>;
1471
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1472
+ availableMargin: z.ZodNullable<z.ZodString>;
1473
+ poolsShared: z.ZodBoolean;
1474
+ perCollateral: z.ZodArray<z.ZodObject<{
1475
+ asset: z.ZodString;
1476
+ equity: z.ZodString;
1477
+ availableMargin: z.ZodNullable<z.ZodString>;
1478
+ withdrawable: z.ZodNullable<z.ZodString>;
1479
+ }, z.core.$strip>>;
1480
+ timestamp: z.ZodNumber;
1481
+ accountMode: z.ZodLiteral<"bybit:isolatedMargin">;
1482
+ }, z.core.$strip>;
1483
+ type BybitIsolatedMarginBalance = z.infer<typeof BybitIsolatedMarginBalance>;
1484
+ declare const BybitRegularMarginBalance: z.ZodObject<{
1485
+ totalEquity: z.ZodNullable<z.ZodString>;
1486
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1487
+ availableMargin: z.ZodNullable<z.ZodString>;
1488
+ poolsShared: z.ZodBoolean;
1489
+ perCollateral: z.ZodArray<z.ZodObject<{
1490
+ asset: z.ZodString;
1491
+ equity: z.ZodString;
1492
+ availableMargin: z.ZodNullable<z.ZodString>;
1493
+ withdrawable: z.ZodNullable<z.ZodString>;
1494
+ }, z.core.$strip>>;
1495
+ timestamp: z.ZodNumber;
1496
+ accountMode: z.ZodLiteral<"bybit:regularMargin">;
1497
+ }, z.core.$strip>;
1498
+ type BybitRegularMarginBalance = z.infer<typeof BybitRegularMarginBalance>;
1499
+ declare const BybitPortfolioMarginBalance: z.ZodObject<{
1500
+ totalEquity: z.ZodNullable<z.ZodString>;
1501
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1502
+ availableMargin: z.ZodNullable<z.ZodString>;
1503
+ poolsShared: z.ZodBoolean;
1504
+ perCollateral: z.ZodArray<z.ZodObject<{
1505
+ asset: z.ZodString;
1506
+ equity: z.ZodString;
1507
+ availableMargin: z.ZodNullable<z.ZodString>;
1508
+ withdrawable: z.ZodNullable<z.ZodString>;
1509
+ }, z.core.$strip>>;
1510
+ timestamp: z.ZodNumber;
1511
+ accountMode: z.ZodLiteral<"bybit:portfolioMargin">;
1512
+ }, z.core.$strip>;
1513
+ type BybitPortfolioMarginBalance = z.infer<typeof BybitPortfolioMarginBalance>;
1514
+
1020
1515
  type BybitAccountTrackerConfig = AccountTrackerConfig & {
1021
1516
  credentials: SupportedCredentials;
1022
1517
  };
@@ -1027,10 +1522,25 @@ declare class BybitAccountTracker extends BaseAccountTracker {
1027
1522
  private openListenerId;
1028
1523
  private rawCoins;
1029
1524
  private lastWallet;
1030
- private accountType;
1525
+ private accountMode;
1526
+ private withdrawable;
1527
+ private lastWithdrawableReadAt;
1528
+ private withdrawableRefreshTimer;
1529
+ private withdrawableReadInFlight;
1530
+ private withdrawableReadPending;
1531
+ private lifecycleVersion;
1031
1532
  private trackedAssetInfos;
1032
1533
  constructor(config: BybitAccountTrackerConfig);
1033
1534
  snapshot(): Promise<AccountSnapshot>;
1535
+ /**
1536
+ * Bybit sizes no basket in v1: the SDK reads no per-asset max leverage from it, and sizing off
1537
+ * `availableMargin` alone would ship a number no venue field backs. The missing input is
1538
+ * `/v5/position/list` → `leverage` (the account's own per-symbol setting), with
1539
+ * `/v5/market/risk-limit` → `maxLeverage` behind it for the tier a larger size would fall into.
1540
+ */
1541
+ maxBasketSize(_input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
1542
+ /** The REST path answers the same way — there is no size either way, not a slower one. */
1543
+ snapshotMaxBasketSize(_input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
1034
1544
  /**
1035
1545
  * Stateless one-shot per-asset settings read. Bybit has no batch leverage endpoint, but
1036
1546
  * `position/list` by settleCoin returns every open position (with leverage) in one call, so
@@ -1044,15 +1554,232 @@ declare class BybitAccountTracker extends BaseAccountTracker {
1044
1554
  protected cleanupConnections(): Promise<void>;
1045
1555
  get isConnected(): boolean;
1046
1556
  private fetchSnapshotData;
1557
+ /**
1558
+ * Read how much can leave the trading account, for the coins the wallet payload lists.
1559
+ *
1560
+ * Best-effort on purpose: this is a second signed call that a read-only key may be refused, and
1561
+ * a refusal must cost the caller a `null` field rather than the whole balance.
1562
+ *
1563
+ * A refusal is reported as `failed` rather than as an empty answer, because only the caller knows
1564
+ * what to do with it: the snapshot path has no earlier figure and reports nothing known, while
1565
+ * the live path keeps the figure its last successful read published.
1566
+ */
1567
+ private readWithdrawable;
1047
1568
  protected ensureAssetTracked(coin: string): void;
1048
1569
  protected releaseAsset(coin: string): void;
1049
1570
  private subscribe;
1050
1571
  private handleInitialData;
1051
1572
  private routeRaw;
1052
1573
  private handleMessage;
1574
+ /**
1575
+ * Fold one wallet push into the whole account, then publish what that whole account says.
1576
+ *
1577
+ * Bybit pushes only what moved: an update names the coins whose figures changed and leaves every
1578
+ * other coin out. So the coin list is taken from the per-coin merge rather than from the push,
1579
+ * and everything read off it sees every coin the account holds — the published rows, and the
1580
+ * coin list the next transferable-amount read asks about. A push naming one of two funded coins
1581
+ * would otherwise drop the other's row and let its per-coin maximum answer for the account.
1582
+ *
1583
+ * The account-level figures inherit on `??`, never on `||`, because ABSENT and BLANK say
1584
+ * opposite things here. A field this push left out was not restated and its previous value still
1585
+ * stands; a field present as `''` is Bybit withdrawing the figure, which it does for
1586
+ * `totalAvailableBalance` among others. Inheriting a blank would republish a number the venue no
1587
+ * longer states, and it would do it BEHIND `decimalOrNull`, whose whole job is to publish a blank
1588
+ * as `null`: overwriting the blank here means that guard never sees it.
1589
+ */
1053
1590
  private handleWalletUpdate;
1591
+ /** Publish the balance built from the newest wallet payload and the cached transferable amounts. */
1592
+ private emitBalance;
1593
+ /**
1594
+ * Queue the next transferable-amount read, no sooner than the venue's own rate limit allows.
1595
+ *
1596
+ * Nothing waits on it: the wallet update is already published from the cached figure. One queued
1597
+ * read covers every wallet tick that lands before it runs, which is what stops a burst of ticks
1598
+ * becoming a burst of signed calls — and because a tick always leaves a read queued or marked
1599
+ * pending, a moved figure is still picked up within one interval rather than dropped.
1600
+ */
1601
+ private refreshWithdrawableSoon;
1602
+ /**
1603
+ * Hold one transferable-amount read open at a time, and queue the ticks that arrive during it.
1604
+ *
1605
+ * Serialising the reads is what keeps the published figure the newest one: two overlapping reads
1606
+ * can come back in either order, and the older answer landing last would publish an amount the
1607
+ * venue has already moved past.
1608
+ */
1609
+ private refreshWithdrawableBalance;
1610
+ /**
1611
+ * Re-read the transferable amount behind the live path, then re-publish only if it moved.
1612
+ *
1613
+ * Fire-and-forget: the wallet update is already published with the previous figure, so a slow
1614
+ * read delays the correction instead of blocking the balance. A read that FAILS changes nothing
1615
+ * at all — the last good figure stays published, because a refusal says Bybit did not answer,
1616
+ * not that the account has nothing to transfer. Both the read and the re-publish take the NEWEST
1617
+ * wallet rather than the one that queued them, so a wallet update that landed meanwhile is
1618
+ * neither missed nor rolled back.
1619
+ */
1620
+ private performWithdrawableRefresh;
1054
1621
  }
1055
1622
 
1623
+ /**
1624
+ * Hyperliquid's three account-mode balance variants.
1625
+ *
1626
+ * Hyperliquid has the most divergent risk model of the five venues, so each mode carries its own
1627
+ * figures rather than sharing one flat shape. HIP-3 dexes can share the main dex's collateral
1628
+ * token, so every account-level figure aggregates across dexes and the per-dex list is kept
1629
+ * alongside — the aggregate hides HIP-3 positions entirely.
1630
+ *
1631
+ * Every figure derived from a spot price is nullable, because a spot balance carries only a token
1632
+ * index and no route to USDC reaches every token. The `perCollateral` rows are not:
1633
+ * a row is a quantity of one collateral token in that token's own units, so it keeps working
1634
+ * precisely because it is never converted.
1635
+ */
1636
+
1637
+ declare const HyperliquidDexState: z.ZodObject<{
1638
+ dex: z.ZodString;
1639
+ collateralToken: z.ZodNullable<z.ZodNumber>;
1640
+ accountValue: z.ZodString;
1641
+ crossNotional: z.ZodString;
1642
+ crossMaintenanceMargin: z.ZodString;
1643
+ withdrawable: z.ZodString;
1644
+ }, z.core.$strip>;
1645
+ type HyperliquidDexState = z.infer<typeof HyperliquidDexState>;
1646
+ declare const HyperliquidStandardBalance: z.ZodObject<{
1647
+ totalEquity: z.ZodNullable<z.ZodString>;
1648
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1649
+ availableMargin: z.ZodNullable<z.ZodString>;
1650
+ poolsShared: z.ZodBoolean;
1651
+ perCollateral: z.ZodArray<z.ZodObject<{
1652
+ asset: z.ZodString;
1653
+ equity: z.ZodString;
1654
+ availableMargin: z.ZodNullable<z.ZodString>;
1655
+ withdrawable: z.ZodNullable<z.ZodString>;
1656
+ }, z.core.$strip>>;
1657
+ timestamp: z.ZodNumber;
1658
+ accountMode: z.ZodLiteral<"hyperliquid:standard">;
1659
+ spotEquity: z.ZodNullable<z.ZodString>;
1660
+ perpsEquity: z.ZodString;
1661
+ vaultEquity: z.ZodString;
1662
+ stakedEquity: z.ZodNullable<z.ZodString>;
1663
+ unrealizedPnl: z.ZodString;
1664
+ maintenanceMargin: z.ZodString;
1665
+ crossMarginRatio: z.ZodString;
1666
+ crossAccountLeverage: z.ZodString;
1667
+ perDexState: z.ZodArray<z.ZodObject<{
1668
+ dex: z.ZodString;
1669
+ collateralToken: z.ZodNullable<z.ZodNumber>;
1670
+ accountValue: z.ZodString;
1671
+ crossNotional: z.ZodString;
1672
+ crossMaintenanceMargin: z.ZodString;
1673
+ withdrawable: z.ZodString;
1674
+ }, z.core.$strip>>;
1675
+ }, z.core.$strip>;
1676
+ type HyperliquidStandardBalance = z.infer<typeof HyperliquidStandardBalance>;
1677
+ declare const HyperliquidUnifiedBalance: z.ZodObject<{
1678
+ totalEquity: z.ZodNullable<z.ZodString>;
1679
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1680
+ availableMargin: z.ZodNullable<z.ZodString>;
1681
+ poolsShared: z.ZodBoolean;
1682
+ perCollateral: z.ZodArray<z.ZodObject<{
1683
+ asset: z.ZodString;
1684
+ equity: z.ZodString;
1685
+ availableMargin: z.ZodNullable<z.ZodString>;
1686
+ withdrawable: z.ZodNullable<z.ZodString>;
1687
+ }, z.core.$strip>>;
1688
+ timestamp: z.ZodNumber;
1689
+ accountMode: z.ZodLiteral<"hyperliquid:unified">;
1690
+ tradingEquity: z.ZodNullable<z.ZodString>;
1691
+ vaultEquity: z.ZodString;
1692
+ stakedEquity: z.ZodNullable<z.ZodString>;
1693
+ portfolioValue: z.ZodNullable<z.ZodString>;
1694
+ unrealizedPnl: z.ZodString;
1695
+ perpsMaintenanceMargin: z.ZodString;
1696
+ unifiedAccountRatio: z.ZodString;
1697
+ unifiedAccountLeverage: z.ZodNullable<z.ZodString>;
1698
+ perDexState: z.ZodArray<z.ZodObject<{
1699
+ dex: z.ZodString;
1700
+ collateralToken: z.ZodNullable<z.ZodNumber>;
1701
+ accountValue: z.ZodString;
1702
+ crossNotional: z.ZodString;
1703
+ crossMaintenanceMargin: z.ZodString;
1704
+ withdrawable: z.ZodString;
1705
+ }, z.core.$strip>>;
1706
+ }, z.core.$strip>;
1707
+ type HyperliquidUnifiedBalance = z.infer<typeof HyperliquidUnifiedBalance>;
1708
+ /**
1709
+ * One Portfolio Margin spot holding, as the venue's own balances table states it.
1710
+ *
1711
+ * PM widens the shared `CollateralBalance` in two ways it cannot carry, which is why this variant
1712
+ * declares its own row type rather than reusing it:
1713
+ *
1714
+ * - **the figures are SIGNED.** A borrowed coin holds a negative `total`, and seven of the fourteen
1715
+ * accounts measured hold one — `0x0871deb3…` reports USDC at −957,802.15. An unsigned row cannot
1716
+ * state that at all, which is the defect that made a borrowed pool indistinguishable from an
1717
+ * untouched one.
1718
+ * - **two more columns.** `ltv` and `borrowCapUsed` are per-coin risk weights the venue renders
1719
+ * beside the quantities, and both are PM-only wire fields.
1720
+ *
1721
+ * The row is otherwise the shared shape: same keys, same meanings, so a consumer reading
1722
+ * `perCollateral` without narrowing still reads `asset` / `equity` / `availableMargin` /
1723
+ * `withdrawable` off every venue.
1724
+ */
1725
+ declare const HyperliquidPortfolioMarginCollateral: z.ZodObject<{
1726
+ asset: z.ZodString;
1727
+ equity: z.ZodString;
1728
+ availableMargin: z.ZodNullable<z.ZodString>;
1729
+ withdrawable: z.ZodString;
1730
+ ltv: z.ZodNullable<z.ZodString>;
1731
+ borrowCapUsed: z.ZodNullable<z.ZodString>;
1732
+ }, z.core.$strip>;
1733
+ type HyperliquidPortfolioMarginCollateral = z.infer<typeof HyperliquidPortfolioMarginCollateral>;
1734
+ declare const HyperliquidPortfolioMarginBalance: z.ZodObject<{
1735
+ totalEquity: z.ZodNullable<z.ZodString>;
1736
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1737
+ availableMargin: z.ZodNullable<z.ZodString>;
1738
+ poolsShared: z.ZodBoolean;
1739
+ timestamp: z.ZodNumber;
1740
+ accountMode: z.ZodLiteral<"hyperliquid:portfolioMargin">;
1741
+ perCollateral: z.ZodArray<z.ZodObject<{
1742
+ asset: z.ZodString;
1743
+ equity: z.ZodString;
1744
+ availableMargin: z.ZodNullable<z.ZodString>;
1745
+ withdrawable: z.ZodString;
1746
+ ltv: z.ZodNullable<z.ZodString>;
1747
+ borrowCapUsed: z.ZodNullable<z.ZodString>;
1748
+ }, z.core.$strip>>;
1749
+ tradingEquity: z.ZodNullable<z.ZodString>;
1750
+ vaultEquity: z.ZodString;
1751
+ stakedEquity: z.ZodNullable<z.ZodString>;
1752
+ portfolioValue: z.ZodNullable<z.ZodString>;
1753
+ unrealizedPnl: z.ZodString;
1754
+ perpsMaintenanceMargin: z.ZodString;
1755
+ portfolioMarginRatio: z.ZodNullable<z.ZodString>;
1756
+ portfolioAccountLeverage: z.ZodNullable<z.ZodString>;
1757
+ borrowCapUsed: z.ZodNullable<z.ZodString>;
1758
+ perDexState: z.ZodArray<z.ZodObject<{
1759
+ dex: z.ZodString;
1760
+ collateralToken: z.ZodNullable<z.ZodNumber>;
1761
+ accountValue: z.ZodString;
1762
+ crossNotional: z.ZodString;
1763
+ crossMaintenanceMargin: z.ZodString;
1764
+ withdrawable: z.ZodString;
1765
+ }, z.core.$strip>>;
1766
+ }, z.core.$strip>;
1767
+ type HyperliquidPortfolioMarginBalance = z.infer<typeof HyperliquidPortfolioMarginBalance>;
1768
+
1769
+ /**
1770
+ * Hyperliquid's two read paths: the live WebSocket tracker and the one-shot REST snapshot.
1771
+ *
1772
+ * Both fill the same `HyperliquidBalanceContext` and hand it to the same mapper, which is what
1773
+ * makes "same account state, same balance" true across two different transports. The tracker takes
1774
+ * every CHANGING value off a channel — `allDexsClearinghouseState`, `spotState`, `webData3`,
1775
+ * `allMids`, `activeAssetData` — including vault equity, which rides `webData3`. Its only REST
1776
+ * reads happen at `start()`: the static dex metadata, and the staking position, which the venue
1777
+ * publishes on no channel at all.
1778
+ *
1779
+ * The snapshot has no channels, so it reads the same figures over REST — vault equity from
1780
+ * `userVaultEquities`, which was measured equal to the `webData3` figure on ten live accounts.
1781
+ */
1782
+
1056
1783
  type HyperliquidAccountTrackerConfig = AccountTrackerConfig & {
1057
1784
  account: TradeAccount;
1058
1785
  credentials: SupportedCredentials;
@@ -1066,17 +1793,33 @@ declare class HyperliquidAccountTracker extends BaseAccountTracker {
1066
1793
  private subscribedCoins;
1067
1794
  private lastSummary;
1068
1795
  private spotCoinBalances;
1796
+ /** Portfolio Margin's own risk scalars, which ride the same `spotState` frame the balances do. */
1797
+ private portfolioMarginRatio;
1798
+ private borrowRatioByToken;
1069
1799
  private hasSpotState;
1070
1800
  private hasClearinghouseState;
1071
1801
  private accountType;
1072
- private collateralTokenMap;
1802
+ private spotMeta;
1803
+ private collateralTokenNames;
1804
+ private prices;
1805
+ private hasWebData3;
1806
+ private vaultEquity;
1807
+ private stakedHype;
1073
1808
  private dexToMeta;
1074
1809
  private trackedAssetData;
1075
1810
  constructor(config: HyperliquidAccountTrackerConfig);
1076
1811
  /**
1077
- * Reads account mode, collateral balances, per-DEX state, and positions without opening a socket.
1812
+ * Reads account mode, spot prices, collateral balances, per-DEX state, staking, vaults and
1813
+ * per-asset headroom without opening a socket.
1078
1814
  */
1079
1815
  snapshot(): Promise<AccountSnapshot>;
1816
+ /** Sizes a basket over REST alone, so the call stays usable without a running socket. */
1817
+ snapshotMaxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
1818
+ /**
1819
+ * Sizes a basket against live state, fetching per-asset data for any leg the socket has not
1820
+ * subscribed to — which is exactly why the call is asynchronous on both paths.
1821
+ */
1822
+ maxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
1080
1823
  /**
1081
1824
  * Stateless one-shot per-asset settings read via the `activeAssetData` info request (the REST
1082
1825
  * twin of the live WS subscription), one request per coin fired in parallel — the info endpoint
@@ -1100,41 +1843,120 @@ declare class HyperliquidAccountTracker extends BaseAccountTracker {
1100
1843
  private routeRaw;
1101
1844
  private handle;
1102
1845
  private loadPerpMetas;
1846
+ /** Loads the dex metadata a sizing call needs, reusing whatever `start()` already cached. */
1847
+ private loadPerpMetasOnce;
1848
+ /** Loads the token names a pool id is spelled with, reusing whatever `start()` already cached. */
1849
+ private loadCollateralTokenNamesOnce;
1850
+ /** Reads `activeAssetData` for each coin in parallel, dropping the coins the venue refuses. */
1851
+ private fetchActiveAssetEvents;
1852
+ /** The asset set `availableMargin` is the floor over: the locked coins plus every tracked one. */
1853
+ private coinsForAvailableMargin;
1103
1854
  private onClearinghouseState;
1104
1855
  private onActiveAssetData;
1856
+ private onAllMids;
1105
1857
  private onWebData3;
1106
1858
  private onSpotState;
1859
+ /**
1860
+ * Builds the live balance once every channel that feeds it has reported, or `undefined` until then.
1861
+ *
1862
+ * All four are required. Every mode now values the spot wallet, so a balance emitted before
1863
+ * `spotState` and `allMids` would report equity missing its whole spot half; and one emitted
1864
+ * before `webData3` would report vault equity as zero on an account that holds millions in a
1865
+ * vault. Partial equity is worse than no equity, so nothing is published early.
1866
+ */
1107
1867
  private buildBalance;
1868
+ /** The floor of `availableToTrade` over the tracked set; `null` when nothing is tracked. */
1869
+ private availableMargin;
1108
1870
  /** Clears both sides of the live balance join and the public account cache without emitting. */
1109
1871
  private resetLiveAccountState;
1110
1872
  private buildTrackedAssetsMap;
1111
1873
  }
1112
1874
 
1875
+ /**
1876
+ * Lighter's two account-mode balance variants.
1877
+ *
1878
+ * Classic is Unified minus `portfolioMargin`, so both modes share one field block.
1879
+ */
1880
+
1881
+ declare const LighterClassicBalance: z.ZodObject<{
1882
+ totalEquity: z.ZodNullable<z.ZodString>;
1883
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1884
+ availableMargin: z.ZodNullable<z.ZodString>;
1885
+ poolsShared: z.ZodBoolean;
1886
+ perCollateral: z.ZodArray<z.ZodObject<{
1887
+ asset: z.ZodString;
1888
+ equity: z.ZodString;
1889
+ availableMargin: z.ZodNullable<z.ZodString>;
1890
+ withdrawable: z.ZodNullable<z.ZodString>;
1891
+ }, z.core.$strip>>;
1892
+ timestamp: z.ZodNumber;
1893
+ tradingEquity: z.ZodNullable<z.ZodString>;
1894
+ perpetualsEquity: z.ZodNullable<z.ZodString>;
1895
+ spotEquity: z.ZodNullable<z.ZodString>;
1896
+ publicPoolsEquity: z.ZodNullable<z.ZodString>;
1897
+ stakingEquity: z.ZodNullable<z.ZodString>;
1898
+ creditedInLit: z.ZodNullable<z.ZodString>;
1899
+ unrealizedPnl: z.ZodNullable<z.ZodString>;
1900
+ crossLeverage: z.ZodNullable<z.ZodString>;
1901
+ maintenanceMargin: z.ZodNullable<z.ZodString>;
1902
+ crossMarginUsage: z.ZodNullable<z.ZodString>;
1903
+ crossMarginRatio: z.ZodNullable<z.ZodString>;
1904
+ accountMode: z.ZodLiteral<"lighter:classic">;
1905
+ }, z.core.$strip>;
1906
+ type LighterClassicBalance = z.infer<typeof LighterClassicBalance>;
1907
+ declare const LighterUnifiedBalance: z.ZodObject<{
1908
+ totalEquity: z.ZodNullable<z.ZodString>;
1909
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
1910
+ availableMargin: z.ZodNullable<z.ZodString>;
1911
+ poolsShared: z.ZodBoolean;
1912
+ perCollateral: z.ZodArray<z.ZodObject<{
1913
+ asset: z.ZodString;
1914
+ equity: z.ZodString;
1915
+ availableMargin: z.ZodNullable<z.ZodString>;
1916
+ withdrawable: z.ZodNullable<z.ZodString>;
1917
+ }, z.core.$strip>>;
1918
+ timestamp: z.ZodNumber;
1919
+ portfolioMargin: z.ZodNullable<z.ZodString>;
1920
+ tradingEquity: z.ZodNullable<z.ZodString>;
1921
+ perpetualsEquity: z.ZodNullable<z.ZodString>;
1922
+ spotEquity: z.ZodNullable<z.ZodString>;
1923
+ publicPoolsEquity: z.ZodNullable<z.ZodString>;
1924
+ stakingEquity: z.ZodNullable<z.ZodString>;
1925
+ creditedInLit: z.ZodNullable<z.ZodString>;
1926
+ unrealizedPnl: z.ZodNullable<z.ZodString>;
1927
+ crossLeverage: z.ZodNullable<z.ZodString>;
1928
+ maintenanceMargin: z.ZodNullable<z.ZodString>;
1929
+ crossMarginUsage: z.ZodNullable<z.ZodString>;
1930
+ crossMarginRatio: z.ZodNullable<z.ZodString>;
1931
+ accountMode: z.ZodLiteral<"lighter:unified">;
1932
+ }, z.core.$strip>;
1933
+ type LighterUnifiedBalance = z.infer<typeof LighterUnifiedBalance>;
1934
+
1113
1935
  type LighterAccountTrackerConfig = AccountTrackerConfig & {
1114
1936
  account: TradeAccount;
1115
1937
  credentials: SupportedCredentials;
1116
- sdk?: PearSDK;
1117
1938
  };
1118
1939
  declare class LighterAccountTracker extends BaseAccountTracker {
1119
1940
  private readonly accountIdentifier;
1120
- private readonly sdk;
1121
1941
  private ws;
1122
1942
  private messageListenerId;
1123
1943
  private openListenerId;
1124
- private pollTimer;
1125
- private pollInFlight;
1944
+ private positionPollTimer;
1945
+ private positionPollInFlight;
1946
+ private marketRefreshTimer;
1947
+ private marketRefreshInFlight;
1126
1948
  private startInFlight;
1127
1949
  private lifecycleVersion;
1128
1950
  private stateVersion;
1129
1951
  private assetsByAssetId;
1130
- private rawPositionsByMarketId;
1952
+ private wsPositionsByMarketId;
1131
1953
  private marketsByMarketId;
1132
- private summary;
1133
- private accountTier;
1134
- private lastAccountTierFetchAt;
1954
+ private marketsBySymbol;
1955
+ private spotPriceBySymbol;
1956
+ private stats;
1135
1957
  private hasAssets;
1136
1958
  constructor(config: LighterAccountTrackerConfig);
1137
- /** Stateless one-shot account read; tier enrichment is optional and requires SDK-backed auth. */
1959
+ /** Stateless one-shot account read — public endpoints only, and no websocket. */
1138
1960
  snapshot(): Promise<AccountSnapshot>;
1139
1961
  /**
1140
1962
  * Stateless one-shot per-asset settings read, keyed by market id (the same identifier the live
@@ -1143,6 +1965,10 @@ declare class LighterAccountTracker extends BaseAccountTracker {
1143
1965
  * supplies the exchange default for markets absent from the account payload.
1144
1966
  */
1145
1967
  protected fetchAssetSnapshots(marketIds: string[]): Promise<AssetSnapshotMap>;
1968
+ /** Sizes a basket against the live account state, falling back to REST before the socket is up. */
1969
+ maxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
1970
+ /** Sizes a basket over REST alone, so the answer needs no running socket. */
1971
+ snapshotMaxBasketSize(input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
1146
1972
  start(): Promise<void>;
1147
1973
  /** Creates one tracker lifecycle while repeated callers share the same pending start. */
1148
1974
  private performStart;
@@ -1156,15 +1982,148 @@ declare class LighterAccountTracker extends BaseAccountTracker {
1156
1982
  private routeRaw;
1157
1983
  private handle;
1158
1984
  private onAccountAll;
1985
+ /** Keeps both published scopes: cross drives every "Cross" field, total drives the account ones. */
1159
1986
  private onUserStats;
1987
+ /**
1988
+ * The account's balance, built from websocket state alone.
1989
+ *
1990
+ * Every input is websocket-sourced — `user_stats` for the two account scopes, `account_all` for
1991
+ * the assets and positions — except the market context, which is venue-wide metadata this
1992
+ * tracker re-reads on its own timer. This is the ONLY producer of the value `getBalance()`
1993
+ * returns while the tracker is running; `snapshot()` is the separate REST path and never writes
1994
+ * here.
1995
+ *
1996
+ * Null until both channels have delivered a frame, because a balance built from one of them
1997
+ * would be missing half the account.
1998
+ */
1160
1999
  private buildBalance;
2000
+ /** The market data both read paths join account state against, as the latest read left it. */
2001
+ private marketContext;
2002
+ /** The account's current per-market settings as the base tracker already holds them. */
2003
+ private liveAccountSettings;
1161
2004
  private fetchPrimaryAccount;
1162
- private fetchAccountTier;
1163
- private pollAccount;
1164
- private performAccountPoll;
1165
- private shouldRefreshAccountTier;
2005
+ private pollPositions;
2006
+ /**
2007
+ * Republishes positions and per-market settings from REST.
2008
+ *
2009
+ * Deliberately publishes NO balance. Every field of both Lighter variants comes off the two
2010
+ * websocket channels — `user_stats` carries both account scopes and `account_all` carries the
2011
+ * assets and positions behind them — so a REST balance here would only overwrite a live value
2012
+ * with an equal one, while making `getBalance()` REST-derived most of the time.
2013
+ *
2014
+ * It also leaves `wsPositionsByMarketId` alone. That store feeds the live balance's unrealized
2015
+ * PnL and maintenance margin, so writing REST rows into it would make a balance labelled live
2016
+ * partly REST-derived without any reader being able to tell.
2017
+ */
2018
+ private performPositionPoll;
2019
+ /** Shares one in-flight market read, so a slow response cannot stack requests behind the WAF. */
2020
+ private refreshMarkets;
2021
+ /**
2022
+ * Re-reads the venue's markets and republishes the balance they move.
2023
+ *
2024
+ * `spotEquity` values each holding at the last trade its own spot book printed, so an index read
2025
+ * only at `start()` values a session-long tracker at session-old prices — and every scalar built
2026
+ * on it drifts with it.
2027
+ *
2028
+ * The perp books ride along, which is what closes the gap `toPositionRisks` documents: a market
2029
+ * Lighter listed after `start()` was unknown to the balance for the rest of the session, so a
2030
+ * position on it left the maintenance figure unknown for just as long. The read already carries
2031
+ * them, so learning them costs nothing. Their risk parameters come along as a consequence, which
2032
+ * only makes a slowly-moving margin fraction current rather than session-old.
2033
+ *
2034
+ * Perp books are UPSERTED, never replaced. An account can still hold a position on a market that
2035
+ * has dropped out of the listing, and the parameters this tracker last saw price that position —
2036
+ * where forgetting the market would stop pricing it at all.
2037
+ *
2038
+ * A read that fails, or that comes back carrying no spot books at all, leaves the last good price
2039
+ * index in place. Stale prices still value the account; an empty index would null every spot
2040
+ * figure the account has at once, which is a worse answer than a slightly old one.
2041
+ *
2042
+ * Only the market data moves here. A newly listed market's exchange-default asset settings reach
2043
+ * `trackAsset` consumers on the next websocket epoch, where `handleWsOpen` already republishes
2044
+ * them for every known market — publishing them here would overwrite the account's own settings.
2045
+ */
2046
+ private performMarketRefresh;
1166
2047
  }
1167
2048
 
2049
+ /**
2050
+ * OKX's four account-mode balance variants.
2051
+ *
2052
+ * Core fields only, with `null` wherever a figure cannot be derived. OKX publishes no account-level
2053
+ * margin fields in Futures mode (`acctLv=2`) at all, which is exactly why the flat shape had to go
2054
+ * — and why `perCollateral` matters most there, since `details[].availEq` is per currency. What
2055
+ * differs by mode is not the shape but when the core scalars go null, which follows each mode's
2056
+ * collateral-pool model. One `z.literal` per mode, because `z.discriminatedUnion` needs a single
2057
+ * literal tag per member rather than a `z.enum` shorthand.
2058
+ */
2059
+
2060
+ /**
2061
+ * Spot and Futures mode run one collateral pool per currency, so `totalEq` is a USD total across
2062
+ * budgets that cannot fund each other. Once a second pool is funded there is no spendable account
2063
+ * total, so `totalEquity` goes null and `perCollateral` is the whole answer. `OkxFuturesBalance`
2064
+ * carries the same rule.
2065
+ */
2066
+ declare const OkxSpotBalance: z.ZodObject<{
2067
+ totalEquity: z.ZodNullable<z.ZodString>;
2068
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
2069
+ availableMargin: z.ZodNullable<z.ZodString>;
2070
+ poolsShared: z.ZodBoolean;
2071
+ perCollateral: z.ZodArray<z.ZodObject<{
2072
+ asset: z.ZodString;
2073
+ equity: z.ZodString;
2074
+ availableMargin: z.ZodNullable<z.ZodString>;
2075
+ withdrawable: z.ZodNullable<z.ZodString>;
2076
+ }, z.core.$strip>>;
2077
+ timestamp: z.ZodNumber;
2078
+ accountMode: z.ZodLiteral<"okx:spot">;
2079
+ }, z.core.$strip>;
2080
+ type OkxSpotBalance = z.infer<typeof OkxSpotBalance>;
2081
+ declare const OkxFuturesBalance: z.ZodObject<{
2082
+ totalEquity: z.ZodNullable<z.ZodString>;
2083
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
2084
+ availableMargin: z.ZodNullable<z.ZodString>;
2085
+ poolsShared: z.ZodBoolean;
2086
+ perCollateral: z.ZodArray<z.ZodObject<{
2087
+ asset: z.ZodString;
2088
+ equity: z.ZodString;
2089
+ availableMargin: z.ZodNullable<z.ZodString>;
2090
+ withdrawable: z.ZodNullable<z.ZodString>;
2091
+ }, z.core.$strip>>;
2092
+ timestamp: z.ZodNumber;
2093
+ accountMode: z.ZodLiteral<"okx:futures">;
2094
+ }, z.core.$strip>;
2095
+ type OkxFuturesBalance = z.infer<typeof OkxFuturesBalance>;
2096
+ declare const OkxMultiCurrencyMarginBalance: z.ZodObject<{
2097
+ totalEquity: z.ZodNullable<z.ZodString>;
2098
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
2099
+ availableMargin: z.ZodNullable<z.ZodString>;
2100
+ poolsShared: z.ZodBoolean;
2101
+ perCollateral: z.ZodArray<z.ZodObject<{
2102
+ asset: z.ZodString;
2103
+ equity: z.ZodString;
2104
+ availableMargin: z.ZodNullable<z.ZodString>;
2105
+ withdrawable: z.ZodNullable<z.ZodString>;
2106
+ }, z.core.$strip>>;
2107
+ timestamp: z.ZodNumber;
2108
+ accountMode: z.ZodLiteral<"okx:multiCurrencyMargin">;
2109
+ }, z.core.$strip>;
2110
+ type OkxMultiCurrencyMarginBalance = z.infer<typeof OkxMultiCurrencyMarginBalance>;
2111
+ declare const OkxPortfolioMarginBalance: z.ZodObject<{
2112
+ totalEquity: z.ZodNullable<z.ZodString>;
2113
+ withdrawableBalance: z.ZodNullable<z.ZodString>;
2114
+ availableMargin: z.ZodNullable<z.ZodString>;
2115
+ poolsShared: z.ZodBoolean;
2116
+ perCollateral: z.ZodArray<z.ZodObject<{
2117
+ asset: z.ZodString;
2118
+ equity: z.ZodString;
2119
+ availableMargin: z.ZodNullable<z.ZodString>;
2120
+ withdrawable: z.ZodNullable<z.ZodString>;
2121
+ }, z.core.$strip>>;
2122
+ timestamp: z.ZodNumber;
2123
+ accountMode: z.ZodLiteral<"okx:portfolioMargin">;
2124
+ }, z.core.$strip>;
2125
+ type OkxPortfolioMarginBalance = z.infer<typeof OkxPortfolioMarginBalance>;
2126
+
1168
2127
  type OkxAccountTrackerConfig = AccountTrackerConfig & {
1169
2128
  credentials: SupportedCredentials;
1170
2129
  };
@@ -1175,10 +2134,26 @@ declare class OkxAccountTracker extends BaseAccountTracker {
1175
2134
  private openListenerId;
1176
2135
  private rawCoins;
1177
2136
  private lastBalance;
1178
- private accountType;
2137
+ private accountMode;
2138
+ private withdrawable;
2139
+ private lastWithdrawableReadAt;
2140
+ private withdrawableRefreshTimer;
2141
+ private withdrawableReadInFlight;
2142
+ private withdrawableReadPending;
2143
+ private lifecycleVersion;
1179
2144
  private trackedAssetInfos;
1180
2145
  constructor(config: OkxAccountTrackerConfig);
1181
2146
  snapshot(): Promise<AccountSnapshot>;
2147
+ /**
2148
+ * OKX sizes no basket in v1: the SDK reads no per-asset max leverage from it, and sizing off
2149
+ * `availableMargin` alone would ship a number no venue field backs. The missing input is
2150
+ * `GET /api/v5/public/position-tiers` → `maxLever`/`imr` per tier, which the client does not
2151
+ * call — and it is NOT `GET /api/v5/account/position-tiers`, a different endpoint carrying no
2152
+ * margin or leverage data at all.
2153
+ */
2154
+ maxBasketSize(_input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
2155
+ /** The REST path answers the same way — there is no size either way, not a slower one. */
2156
+ snapshotMaxBasketSize(_input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
1182
2157
  /**
1183
2158
  * Stateless one-shot per-asset leverage read via `leverage-info`, which accepts up to 20 instIds
1184
2159
  * per request (chunked in the client), so N assets cost ceil(N/20) calls. Cross margin only,
@@ -1189,19 +2164,75 @@ declare class OkxAccountTracker extends BaseAccountTracker {
1189
2164
  protected cleanupConnections(): Promise<void>;
1190
2165
  get isConnected(): boolean;
1191
2166
  private fetchSnapshotData;
2167
+ /**
2168
+ * Read how much can leave the trading account, per currency, across everything it owns.
2169
+ *
2170
+ * Best-effort on purpose: this is a fourth signed call that a read-only key may be refused, and
2171
+ * a refusal must cost the caller a `null` field rather than the whole balance.
2172
+ *
2173
+ * A refusal is reported as `failed` rather than as an empty row set, because only the caller
2174
+ * knows what to do with it: the snapshot path has no earlier figure and reports nothing known,
2175
+ * while the live path keeps the figure its last successful read published.
2176
+ */
2177
+ private readMaxWithdrawals;
1192
2178
  protected ensureAssetTracked(instId: string): void;
1193
2179
  protected releaseAsset(instId: string): void;
1194
2180
  private subscribe;
1195
2181
  private handleInitialData;
1196
2182
  private routeRaw;
1197
2183
  private handleMessage;
2184
+ /**
2185
+ * Fold one account push into the whole account, then publish what that whole account says.
2186
+ *
2187
+ * OKX pushes only what moved: an update names the currencies whose figures changed and leaves
2188
+ * every other currency out. So the rows are taken from the per-currency merge rather than from
2189
+ * the push, and everything read off them — the pool count above all — sees every currency the
2190
+ * account holds. A push naming one of two funded currencies would otherwise read as a
2191
+ * single-pool account and publish scalars that describe neither pool.
2192
+ *
2193
+ * The account-level figures inherit on `??`, never on `||`, because ABSENT and BLANK say
2194
+ * opposite things here. A field this push left out was not restated and its previous value still
2195
+ * stands; a field present as `''` is OKX withdrawing the figure, which it does per account mode —
2196
+ * `availableMarginOf` records the mode that blanks `availEq`. Inheriting a blank would republish
2197
+ * a number the venue no longer states, and it would do it BEHIND `decimalOrNull`, whose whole job
2198
+ * is to publish a blank as `null`: overwriting the blank here means that guard never sees it.
2199
+ */
1198
2200
  private handleBalanceUpdate;
2201
+ /** Publish the balance built from the newest account payload and the cached transferable amounts. */
2202
+ private emitBalance;
2203
+ /**
2204
+ * Queue the next transferable-amount read, no sooner than the venue's own rate limit allows.
2205
+ *
2206
+ * Nothing waits on it: the account update is already published from the cached figure. One
2207
+ * queued read covers every account tick that lands before it runs, which is what stops a burst
2208
+ * of ticks becoming a burst of signed calls — and because a tick always leaves a read queued or
2209
+ * marked pending, a moved figure is still picked up within one interval rather than dropped.
2210
+ */
2211
+ private refreshWithdrawableSoon;
2212
+ /**
2213
+ * Hold one transferable-amount read open at a time, and queue the ticks that arrive during it.
2214
+ *
2215
+ * Serialising the reads is what keeps the published figure the newest one: two overlapping reads
2216
+ * can come back in either order, and the older answer landing last would publish an amount the
2217
+ * venue has already moved past.
2218
+ */
2219
+ private refreshWithdrawableBalance;
2220
+ /**
2221
+ * Re-read the transferable amount behind the live path, then re-publish only if it moved.
2222
+ *
2223
+ * Fire-and-forget: the account update is already published with the previous figure, so a slow
2224
+ * read delays the correction instead of blocking the balance. A read that FAILS changes nothing
2225
+ * at all — the last good figure stays published, because a refusal says OKX did not answer, not
2226
+ * that the account has nothing to transfer. The re-publish reads the newest account payload
2227
+ * rather than the one this read started from, so an account update that landed meanwhile is not
2228
+ * rolled back.
2229
+ */
2230
+ private performWithdrawableRefresh;
1199
2231
  }
1200
2232
 
1201
2233
  type CreateAccountTrackerConfig = AccountTrackerConfig & {
1202
2234
  account: TradeAccount;
1203
2235
  credentials: SupportedCredentials;
1204
- sdk?: PearSDK;
1205
2236
  };
1206
2237
  declare function createAccountTracker(exchange: Connector, config: CreateAccountTrackerConfig): AccountTracker;
1207
2238
 
@@ -1218,6 +2249,11 @@ declare class ExchangesSDK {
1218
2249
  status(connection: ExchangeConnection, options?: ConnectOptions): Promise<AccountStatus>;
1219
2250
  createTracker(connection: ExchangeConnection): AccountTracker;
1220
2251
  snapshot(tradeAccountId: string): Promise<AccountSnapshot>;
2252
+ /**
2253
+ * Sizes a basket in one shot. Routed to the tracker's REST path on purpose: this entry point
2254
+ * builds a throwaway tracker per call, so it must open no socket.
2255
+ */
2256
+ maxBasketSize(tradeAccountId: string, input: MaxBasketSizeInput): Promise<MaxBasketSizeResult>;
1221
2257
  snapshotAssets(tradeAccountId: string, coins: string[]): Promise<AssetSnapshotMap>;
1222
2258
  createHelper<E extends ExchangeHelperExchange>(exchange: E): ExchangeHelperMap[E];
1223
2259
  createSyncer(connection: ExchangeConnection): AccountSyncer;
@@ -1225,4 +2261,4 @@ declare class ExchangesSDK {
1225
2261
  private fetchCredentials;
1226
2262
  }
1227
2263
 
1228
- export { ACCOUNT_TYPE_LABELS, ASSET_DECIMALS, type AccountBalance, type AccountHealthStatus, type AccountPosition, type AccountSnapshot, type AccountStatus, type AccountSyncer, type AccountSyncerConfig, type AccountTracker, type AccountTrackerConfig, type AccountType, type AccountWarningReason, type ApiKey, type ApproveIntegratorParams, type ApproveIntegratorResult, type AssetBalance, AssetId, type AssetSnapshotMap, type BalanceCallback, BaseAccountSyncer, BaseAccountTracker, BaseWs, BinanceAccountSyncer, BinanceAccountTracker, type BinanceAccountTrackerConfig, BinanceAccountType, BinanceExchangeWs, BinanceUserDataWs, type BinanceUserDataWsConfig, BinanceWsApi, type BinanceWsApiConfig, BybitAccountSyncer, BybitAccountTracker, type BybitAccountTrackerConfig, BybitAccountType, BybitExchangeWs, BybitWs, type BybitWsConfig, type CctpDepositHistorySettlement, type CctpDepositIntentParams, type CctpDepositIntentResult, type CctpDepositParams, type CctpDepositProgress, type CctpDepositRegistrationSettlement, type CctpDepositResult, type CctpDepositSettlement, type CctpDepositWalletAdapter, type CheckApiWalletParams, type ConnectOptions, type ConnectWalletParams, type ConnectWalletResult, type CreateAccountTrackerConfig, type CreateExchangeWsConfig, type DepositParams, type DepositResult, type ExchangeConnection, type ExchangeHelperExchange, type ExchangeHelperMap, type ExchangeState, ExchangeWs, type ExchangeWsByConnector, ExchangesSDK, type ExchangesSDKConfig, type FastWithdrawParams, type FastWithdrawResult, HyperliquidAccountSyncer, HyperliquidAccountTracker, type HyperliquidAccountTrackerConfig, HyperliquidAccountType, HyperliquidExchangeWs, type HyperliquidHelper, HyperliquidWs, type IntegratorApprovalRequirements, L2_ASSET_DECIMALS, LIGHTER_CCTP_USDC_ADDRESSES, LIGHTER_CCTP_USDC_DECIMALS, LighterAccountSyncer, LighterAccountTracker, type LighterAccountTrackerConfig, LighterAccountType, type LighterDeposit, type LighterDepositNetwork, LighterExchangeWs, type LighterHelper, type LighterLookupResult, type LighterOnboardingStatus, LighterWs, type ListExternalFillsParams, type ListExternalFundingParams, type ListExternalPositionsParams, MAX_API_KEY_INDEX, MIN_LIGHTER_CCTP_DEPOSIT_USDC, MIN_LIGHTER_FAST_WITHDRAW_USDC, MIN_USER_API_KEY_INDEX, type MarginMode, type MessageListener, OkxAccountSyncer, OkxAccountTracker, type OkxAccountTrackerConfig, OkxAccountType, OkxExchangeWs, OkxWs, type OkxWsConfig, type OpenListener, type PositionsCallback, RouteType, type StateUpdate, type SupportedCredentials, type TrackedAssetCallback, type TrackedAssetInfo, type WalletClientWithAccount, type WithdrawParams, type WithdrawResult, type WsMessage, createAccountSyncer, createAccountTracker, createExchangeWs, createHyperliquidHelper, createLighterHelper, findAvailableApiKeyIndex, getAssetDecimals, getLighterCctpUsdcAddress, usdcAbi };
2264
+ export { ACCOUNT_MODE_LABELS, ASSET_DECIMALS, AccountBalance, AccountBalanceCore, type AccountHealthStatus, AccountMode, type AccountPosition, type AccountSnapshot, type AccountStatus, type AccountSyncer, type AccountSyncerConfig, type AccountTracker, type AccountTrackerConfig, type AccountWarningReason, type ApiKey, type ApproveIntegratorParams, type ApproveIntegratorResult, AssetId, type AssetSnapshotMap, type BalanceCallback, BaseAccountSyncer, BaseAccountTracker, BaseWs, BasketLeg, BinanceAccountSyncer, BinanceAccountTracker, type BinanceAccountTrackerConfig, BinanceExchangeWs, BinanceMultiAssetBalance, BinanceSingleAssetBalance, BinanceUserDataWs, type BinanceUserDataWsConfig, BinanceWsApi, type BinanceWsApiConfig, BybitAccountSyncer, BybitAccountTracker, type BybitAccountTrackerConfig, BybitExchangeWs, BybitIsolatedMarginBalance, BybitPortfolioMarginBalance, BybitRegularMarginBalance, BybitWs, type BybitWsConfig, type CappedBasketLeg, type CctpDepositHistorySettlement, type CctpDepositIntentParams, type CctpDepositIntentResult, type CctpDepositParams, type CctpDepositProgress, type CctpDepositRegistrationSettlement, type CctpDepositResult, type CctpDepositSettlement, type CctpDepositWalletAdapter, type CheckApiWalletParams, CollateralBalance, type ConnectOptions, type ConnectWalletParams, type ConnectWalletResult, type CreateAccountTrackerConfig, type CreateExchangeWsConfig, DecimalString, type DepositParams, type DepositResult, type ExchangeConnection, type ExchangeHelperExchange, type ExchangeHelperMap, type ExchangeState, ExchangeWs, type ExchangeWsByConnector, ExchangesSDK, type ExchangesSDKConfig, type FastWithdrawParams, type FastWithdrawResult, HyperliquidAccountSyncer, HyperliquidAccountTracker, type HyperliquidAccountTrackerConfig, HyperliquidDexState, HyperliquidExchangeWs, type HyperliquidHelper, HyperliquidPortfolioMarginBalance, HyperliquidPortfolioMarginCollateral, HyperliquidStandardBalance, HyperliquidUnifiedBalance, HyperliquidWs, type IntegratorApprovalRequirements, L2_ASSET_DECIMALS, LIGHTER_CCTP_USDC_ADDRESSES, LIGHTER_CCTP_USDC_DECIMALS, LighterAccountSyncer, LighterAccountTracker, type LighterAccountTrackerConfig, LighterClassicBalance, type LighterDeposit, type LighterDepositNetwork, LighterExchangeWs, type LighterHelper, type LighterLookupResult, type LighterOnboardingStatus, LighterUnifiedBalance, LighterWs, type ListExternalFillsParams, type ListExternalFundingParams, type ListExternalPositionsParams, MAX_API_KEY_INDEX, MIN_LIGHTER_CCTP_DEPOSIT_USDC, MIN_LIGHTER_FAST_WITHDRAW_USDC, MIN_USER_API_KEY_INDEX, MarginMode, type MaxBasketSizeCalculation, MaxBasketSizeInput, MaxBasketSizeResult, type MessageListener, OkxAccountSyncer, OkxAccountTracker, type OkxAccountTrackerConfig, OkxExchangeWs, OkxFuturesBalance, OkxMultiCurrencyMarginBalance, OkxPortfolioMarginBalance, OkxSpotBalance, OkxWs, type OkxWsConfig, type OpenListener, type PositionsCallback, RouteType, Side, SignedDecimalString, type StateUpdate, type SupportedCredentials, type TrackedAssetCallback, type TrackedAssetInfo, type WalletClientWithAccount, type WithdrawParams, type WithdrawResult, type WsMessage, computeMaxBasketSize, createAccountSyncer, createAccountTracker, createExchangeWs, createHyperliquidHelper, createLighterHelper, findAvailableApiKeyIndex, getAssetDecimals, getLighterCctpUsdcAddress, usdcAbi };