@blackcube/xgate-sdk 0.20.0 → 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -660,6 +660,22 @@ declare class WalletService {
660
660
  * regarde autrement qu'une panne.
661
661
  */
662
662
  balances(...accesses: IWalletAccess[]): Promise<IBalance[]>;
663
+ /**
664
+ * LE COLLATÉRAL PERPÉTUEL, ajouté aux soldes comptant — sans lui, un portefeuille peut paraître VIDE.
665
+ *
666
+ * `getBalances` ne rend que le **comptant**, chez les huit venues : c'est leur convention, et la
667
+ * documentation de chacune le dit. Or l'argent qui sert à trader n'y est pas. Sur un compte
668
+ * pacifica dont tout le solde est en marge, `getBalances` rend `[]` — ce qui se lit « pas
669
+ * d'argent » alors qu'il y a 499 USDC. Sur hyperliquid, le comptant s'affiche mais la marge
670
+ * manque.
671
+ *
672
+ * La ligne est **marquée `scope: 'perp'`** dans `xtras` : elle s'additionne au comptant sans le
673
+ * doubler, et un appelant qui ne veut que l'un des deux peut trancher.
674
+ *
675
+ * Le champ diffère par venue et n'est pas devinable — d'où la lecture explicite, venue par venue,
676
+ * plutôt qu'un parcours à l'aveugle d'un objet `unknown`.
677
+ */
678
+ private perpCollateral;
663
679
  /**
664
680
  * Les mouvements d'argent, triés du plus ancien au plus récent, montants **signés**.
665
681
  *
@@ -885,6 +901,34 @@ interface ITrade {
885
901
  filledAt: Date;
886
902
  xtras?: Record<string, unknown>;
887
903
  }
904
+ /**
905
+ * CE QU'ON DEMANDE POUR DÉPLACER LE STOP D'UNE POSITION OUVERTE.
906
+ *
907
+ * Le geste du point mort : une position qui a couru se sécurise en remontant son stop, sans jamais
908
+ * la laisser nue. Les SDK posent le NOUVEAU stop avant d'annuler l'ANCIEN — l'ordre compte, et il
909
+ * est tenu par la venue, pas par l'appelant.
910
+ *
911
+ * **Le sens est celui de la POSITION**, comme partout ailleurs ici : le stop se pose au sens opposé,
912
+ * et c'est le SDK de la venue qui s'en charge.
913
+ */
914
+ interface IMoveStop {
915
+ xex: XgateEx;
916
+ /** Le symbole que la venue attend. */
917
+ symbolXex: string;
918
+ /** Sens de la POSITION protégée. */
919
+ direction: Direction;
920
+ /** L'identifiant du stop à remplacer, tel que la venue l'a rendu. */
921
+ stopId: string;
922
+ /** Le nouveau niveau de déclenchement. Arrondi au tick de la paire par XGate. */
923
+ triggerPrice: number;
924
+ /** Taille couverte — normalement la position entière. */
925
+ size: number;
926
+ /** Pas de prix et de quantité de la paire. */
927
+ tickSize?: string | null;
928
+ lotSize?: string | null;
929
+ /** Écart entre déclenchement et borne d'exécution du déclenché. Défaut 0,5 %. */
930
+ slippagePct?: number;
931
+ }
888
932
  /**
889
933
  * CE QU'ON DEMANDE POUR OUVRIR UNE POSITION PROTÉGÉE.
890
934
  *
@@ -982,6 +1026,22 @@ declare class TradingService {
982
1026
  * Rend `null` quand il n'y a rien à fermer — un appel sur une position déjà close n'est pas une erreur.
983
1027
  */
984
1028
  closePosition(access: ITradingAccess, symbolXex: string): Promise<IOrder | null>;
1029
+ /**
1030
+ * DÉPLACE LE STOP d'une position ouverte — le geste du point mort.
1031
+ *
1032
+ * Le SDK de la venue pose le NOUVEAU stop **avant** d'annuler l'ancien : la position n'est jamais
1033
+ * nue, pas même une milliseconde. C'est le même invariant qu'à l'ouverture, appliqué au milieu de
1034
+ * la vie de la position.
1035
+ *
1036
+ * **Un stop du mauvais côté est refusé ici**, avant l'appel réseau. Pour un long, un stop au-dessus
1037
+ * du marché se déclenche immédiatement et solde la position — la venue l'accepte sans broncher, et
1038
+ * l'erreur ne se voit qu'une fois l'argent parti. Ce refus n'est pas de la prudence décorative :
1039
+ * il a été écrit après avoir vu le cas se produire.
1040
+ */
1041
+ moveStop(access: ITradingAccess, input: IMoveStop, markPrice: number): Promise<{
1042
+ symbolXex: string;
1043
+ id: string;
1044
+ }>;
985
1045
  /**
986
1046
  * LE PRIX DE SORTIE RÉEL d'une position, lu dans l'historique de la venue.
987
1047
  *
@@ -1045,4 +1105,4 @@ declare function canonicalFromXex(rawSymbol: string, xexId: string): string;
1045
1105
  */
1046
1106
  declare function canonicalFromBase(base: string): string;
1047
1107
 
1048
- export { CandlesService, CatalogService, type Direction, type IBalance, type ICandle, type ICandlesQuery, type IEntryWithProtection, type IEquityPoint, type IMovement, type IOrder, type IPair, type IPosition, type IPrice, type IProtection, type IProtectionInput, type IProtectionLeg, type ITrade, type ITradingAccess, type IWalletAccess, type IXexAccess, type IXexSpotSource, type MarketKind, type MovementKind, type MovementStatus, ORDER_STATUSES, type OrderStatus, type OrderType, PricesService, SPOT_XEXES, type Side, SpotCatalogService, TIMEFRAME_MINUTES, type TimeInForce, Timeframe, TradingService, type Unsubscribe, WALLET_XEXES, WalletService, WsCandlesService, XGATE_EXCHANGES, XgateEx, XgateModule, buildLevels, buildProtection, canonicalFromBase, canonicalFromXex, roundPrice, roundToStep, servesNatively, servesSpot, sourceFor, timeframeMs };
1108
+ export { CandlesService, CatalogService, type Direction, type IBalance, type ICandle, type ICandlesQuery, type IEntryWithProtection, type IEquityPoint, type IMoveStop, type IMovement, type IOrder, type IPair, type IPosition, type IPrice, type IProtection, type IProtectionInput, type IProtectionLeg, type ITrade, type ITradingAccess, type IWalletAccess, type IXexAccess, type IXexSpotSource, type MarketKind, type MovementKind, type MovementStatus, ORDER_STATUSES, type OrderStatus, type OrderType, PricesService, SPOT_XEXES, type Side, SpotCatalogService, TIMEFRAME_MINUTES, type TimeInForce, Timeframe, TradingService, type Unsubscribe, WALLET_XEXES, WalletService, WsCandlesService, XGATE_EXCHANGES, XgateEx, XgateModule, buildLevels, buildProtection, canonicalFromBase, canonicalFromXex, roundPrice, roundToStep, servesNatively, servesSpot, sourceFor, timeframeMs };
package/dist/index.d.ts CHANGED
@@ -660,6 +660,22 @@ declare class WalletService {
660
660
  * regarde autrement qu'une panne.
661
661
  */
662
662
  balances(...accesses: IWalletAccess[]): Promise<IBalance[]>;
663
+ /**
664
+ * LE COLLATÉRAL PERPÉTUEL, ajouté aux soldes comptant — sans lui, un portefeuille peut paraître VIDE.
665
+ *
666
+ * `getBalances` ne rend que le **comptant**, chez les huit venues : c'est leur convention, et la
667
+ * documentation de chacune le dit. Or l'argent qui sert à trader n'y est pas. Sur un compte
668
+ * pacifica dont tout le solde est en marge, `getBalances` rend `[]` — ce qui se lit « pas
669
+ * d'argent » alors qu'il y a 499 USDC. Sur hyperliquid, le comptant s'affiche mais la marge
670
+ * manque.
671
+ *
672
+ * La ligne est **marquée `scope: 'perp'`** dans `xtras` : elle s'additionne au comptant sans le
673
+ * doubler, et un appelant qui ne veut que l'un des deux peut trancher.
674
+ *
675
+ * Le champ diffère par venue et n'est pas devinable — d'où la lecture explicite, venue par venue,
676
+ * plutôt qu'un parcours à l'aveugle d'un objet `unknown`.
677
+ */
678
+ private perpCollateral;
663
679
  /**
664
680
  * Les mouvements d'argent, triés du plus ancien au plus récent, montants **signés**.
665
681
  *
@@ -885,6 +901,34 @@ interface ITrade {
885
901
  filledAt: Date;
886
902
  xtras?: Record<string, unknown>;
887
903
  }
904
+ /**
905
+ * CE QU'ON DEMANDE POUR DÉPLACER LE STOP D'UNE POSITION OUVERTE.
906
+ *
907
+ * Le geste du point mort : une position qui a couru se sécurise en remontant son stop, sans jamais
908
+ * la laisser nue. Les SDK posent le NOUVEAU stop avant d'annuler l'ANCIEN — l'ordre compte, et il
909
+ * est tenu par la venue, pas par l'appelant.
910
+ *
911
+ * **Le sens est celui de la POSITION**, comme partout ailleurs ici : le stop se pose au sens opposé,
912
+ * et c'est le SDK de la venue qui s'en charge.
913
+ */
914
+ interface IMoveStop {
915
+ xex: XgateEx;
916
+ /** Le symbole que la venue attend. */
917
+ symbolXex: string;
918
+ /** Sens de la POSITION protégée. */
919
+ direction: Direction;
920
+ /** L'identifiant du stop à remplacer, tel que la venue l'a rendu. */
921
+ stopId: string;
922
+ /** Le nouveau niveau de déclenchement. Arrondi au tick de la paire par XGate. */
923
+ triggerPrice: number;
924
+ /** Taille couverte — normalement la position entière. */
925
+ size: number;
926
+ /** Pas de prix et de quantité de la paire. */
927
+ tickSize?: string | null;
928
+ lotSize?: string | null;
929
+ /** Écart entre déclenchement et borne d'exécution du déclenché. Défaut 0,5 %. */
930
+ slippagePct?: number;
931
+ }
888
932
  /**
889
933
  * CE QU'ON DEMANDE POUR OUVRIR UNE POSITION PROTÉGÉE.
890
934
  *
@@ -982,6 +1026,22 @@ declare class TradingService {
982
1026
  * Rend `null` quand il n'y a rien à fermer — un appel sur une position déjà close n'est pas une erreur.
983
1027
  */
984
1028
  closePosition(access: ITradingAccess, symbolXex: string): Promise<IOrder | null>;
1029
+ /**
1030
+ * DÉPLACE LE STOP d'une position ouverte — le geste du point mort.
1031
+ *
1032
+ * Le SDK de la venue pose le NOUVEAU stop **avant** d'annuler l'ancien : la position n'est jamais
1033
+ * nue, pas même une milliseconde. C'est le même invariant qu'à l'ouverture, appliqué au milieu de
1034
+ * la vie de la position.
1035
+ *
1036
+ * **Un stop du mauvais côté est refusé ici**, avant l'appel réseau. Pour un long, un stop au-dessus
1037
+ * du marché se déclenche immédiatement et solde la position — la venue l'accepte sans broncher, et
1038
+ * l'erreur ne se voit qu'une fois l'argent parti. Ce refus n'est pas de la prudence décorative :
1039
+ * il a été écrit après avoir vu le cas se produire.
1040
+ */
1041
+ moveStop(access: ITradingAccess, input: IMoveStop, markPrice: number): Promise<{
1042
+ symbolXex: string;
1043
+ id: string;
1044
+ }>;
985
1045
  /**
986
1046
  * LE PRIX DE SORTIE RÉEL d'une position, lu dans l'historique de la venue.
987
1047
  *
@@ -1045,4 +1105,4 @@ declare function canonicalFromXex(rawSymbol: string, xexId: string): string;
1045
1105
  */
1046
1106
  declare function canonicalFromBase(base: string): string;
1047
1107
 
1048
- export { CandlesService, CatalogService, type Direction, type IBalance, type ICandle, type ICandlesQuery, type IEntryWithProtection, type IEquityPoint, type IMovement, type IOrder, type IPair, type IPosition, type IPrice, type IProtection, type IProtectionInput, type IProtectionLeg, type ITrade, type ITradingAccess, type IWalletAccess, type IXexAccess, type IXexSpotSource, type MarketKind, type MovementKind, type MovementStatus, ORDER_STATUSES, type OrderStatus, type OrderType, PricesService, SPOT_XEXES, type Side, SpotCatalogService, TIMEFRAME_MINUTES, type TimeInForce, Timeframe, TradingService, type Unsubscribe, WALLET_XEXES, WalletService, WsCandlesService, XGATE_EXCHANGES, XgateEx, XgateModule, buildLevels, buildProtection, canonicalFromBase, canonicalFromXex, roundPrice, roundToStep, servesNatively, servesSpot, sourceFor, timeframeMs };
1108
+ export { CandlesService, CatalogService, type Direction, type IBalance, type ICandle, type ICandlesQuery, type IEntryWithProtection, type IEquityPoint, type IMoveStop, type IMovement, type IOrder, type IPair, type IPosition, type IPrice, type IProtection, type IProtectionInput, type IProtectionLeg, type ITrade, type ITradingAccess, type IWalletAccess, type IXexAccess, type IXexSpotSource, type MarketKind, type MovementKind, type MovementStatus, ORDER_STATUSES, type OrderStatus, type OrderType, PricesService, SPOT_XEXES, type Side, SpotCatalogService, TIMEFRAME_MINUTES, type TimeInForce, Timeframe, TradingService, type Unsubscribe, WALLET_XEXES, WalletService, WsCandlesService, XGATE_EXCHANGES, XgateEx, XgateModule, buildLevels, buildProtection, canonicalFromBase, canonicalFromXex, roundPrice, roundToStep, servesNatively, servesSpot, sourceFor, timeframeMs };
package/dist/index.js CHANGED
@@ -759,6 +759,7 @@ var ORDER_STATUSES = [
759
759
 
760
760
  // src/services/trading.service.ts
761
761
  var VENUES_PROUVEES = ["pacifica" /* Pacifica */, "hyperliquid" /* Hyperliquid */];
762
+ var VENUES_MOVE_STOP = ["hyperliquid" /* Hyperliquid */, "pacifica" /* Pacifica */, "aster" /* Aster */];
762
763
  var TradingService = class {
763
764
  logger = new Logger(TradingService.name);
764
765
  /**
@@ -899,6 +900,45 @@ var TradingService = class {
899
900
  }
900
901
  return closed;
901
902
  }
903
+ /**
904
+ * DÉPLACE LE STOP d'une position ouverte — le geste du point mort.
905
+ *
906
+ * Le SDK de la venue pose le NOUVEAU stop **avant** d'annuler l'ancien : la position n'est jamais
907
+ * nue, pas même une milliseconde. C'est le même invariant qu'à l'ouverture, appliqué au milieu de
908
+ * la vie de la position.
909
+ *
910
+ * **Un stop du mauvais côté est refusé ici**, avant l'appel réseau. Pour un long, un stop au-dessus
911
+ * du marché se déclenche immédiatement et solde la position — la venue l'accepte sans broncher, et
912
+ * l'erreur ne se voit qu'une fois l'argent parti. Ce refus n'est pas de la prudence décorative :
913
+ * il a été écrit après avoir vu le cas se produire.
914
+ */
915
+ async moveStop(access, input, markPrice) {
916
+ const trigger = roundPrice(input.triggerPrice, input.tickSize, input.lotSize);
917
+ const perdant = input.direction === "long" ? trigger >= markPrice : trigger <= markPrice;
918
+ if (perdant === true) {
919
+ throw new Error(
920
+ `moveStop(${access.xex}/${input.symbolXex}) : un stop ${input.direction} \xE0 ${trigger} est du mauvais c\xF4t\xE9 du march\xE9 (${markPrice}) \u2014 il se d\xE9clencherait aussit\xF4t et solderait la position.`
921
+ );
922
+ }
923
+ const perp = this.perpOf(access);
924
+ if (typeof perp.moveStop !== "function") {
925
+ throw new Error(
926
+ `moveStop(${access.xex}) : cette venue ne sait pas d\xE9placer un stop. Disponible sur ${VENUES_MOVE_STOP.join(", ")}.`
927
+ );
928
+ }
929
+ const glissement = input.slippagePct ?? 5e-3;
930
+ const borne = input.direction === "long" ? 1 - glissement : 1 + glissement;
931
+ const moved = await perp.moveStop({
932
+ name: input.symbolXex,
933
+ side: input.direction === "long" ? "buy" : "sell",
934
+ stopId: input.stopId,
935
+ triggerPrice: String(trigger),
936
+ size: String(roundToStep(input.size, input.lotSize, "floor")),
937
+ price: String(roundPrice(trigger * borne, input.tickSize, input.lotSize))
938
+ });
939
+ this.logger.log(`moveStop(${access.xex}/${input.symbolXex}) : stop port\xE9 \xE0 ${trigger}`);
940
+ return { symbolXex: moved.name, id: moved.id };
941
+ }
902
942
  /**
903
943
  * LE PRIX DE SORTIE RÉEL d'une position, lu dans l'historique de la venue.
904
944
  *
@@ -971,8 +1011,9 @@ var WalletService = class {
971
1011
  */
972
1012
  async balances(...accesses) {
973
1013
  return this.collect(accesses, "balances", async (access) => {
974
- const balances = await createAccountXex(access.xex, access).account().getBalances();
975
- return balances.map((balance) => ({
1014
+ const source = createAccountXex(access.xex, access);
1015
+ const balances = await source.account().getBalances();
1016
+ const lignes = balances.map((balance) => ({
976
1017
  xex: access.xex,
977
1018
  asset: balance.asset,
978
1019
  total: balance.total,
@@ -980,8 +1021,48 @@ var WalletService = class {
980
1021
  usdValue: balance.usdValue,
981
1022
  xtras: balance.xtras
982
1023
  }));
1024
+ const collateral = await this.perpCollateral(source, access.xex);
1025
+ return collateral === null ? lignes : [...lignes, collateral];
983
1026
  });
984
1027
  }
1028
+ /**
1029
+ * LE COLLATÉRAL PERPÉTUEL, ajouté aux soldes comptant — sans lui, un portefeuille peut paraître VIDE.
1030
+ *
1031
+ * `getBalances` ne rend que le **comptant**, chez les huit venues : c'est leur convention, et la
1032
+ * documentation de chacune le dit. Or l'argent qui sert à trader n'y est pas. Sur un compte
1033
+ * pacifica dont tout le solde est en marge, `getBalances` rend `[]` — ce qui se lit « pas
1034
+ * d'argent » alors qu'il y a 499 USDC. Sur hyperliquid, le comptant s'affiche mais la marge
1035
+ * manque.
1036
+ *
1037
+ * La ligne est **marquée `scope: 'perp'`** dans `xtras` : elle s'additionne au comptant sans le
1038
+ * doubler, et un appelant qui ne veut que l'un des deux peut trancher.
1039
+ *
1040
+ * Le champ diffère par venue et n'est pas devinable — d'où la lecture explicite, venue par venue,
1041
+ * plutôt qu'un parcours à l'aveugle d'un objet `unknown`.
1042
+ */
1043
+ async perpCollateral(source, xex) {
1044
+ const facade = source;
1045
+ if (typeof facade.perp !== "function") {
1046
+ return null;
1047
+ }
1048
+ const scope = facade.perp();
1049
+ if (typeof scope.getAccountInfo !== "function") {
1050
+ return null;
1051
+ }
1052
+ const info = await scope.getAccountInfo();
1053
+ const total = info.balance ?? info.marginSummary?.accountValue;
1054
+ if (total === void 0 || Number(total) === 0) {
1055
+ return null;
1056
+ }
1057
+ return {
1058
+ xex,
1059
+ asset: "USDC",
1060
+ total,
1061
+ available: info.availableToSpend ?? info.withdrawable ?? null,
1062
+ usdValue: total,
1063
+ xtras: { scope: "perp" }
1064
+ };
1065
+ }
985
1066
  /**
986
1067
  * Les mouvements d'argent, triés du plus ancien au plus récent, montants **signés**.
987
1068
  *