@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/README.md +88 -1
- package/dist/index.cjs +83 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -1
- package/dist/index.d.ts +61 -1
- package/dist/index.js +83 -2
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
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
|
|
975
|
-
|
|
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
|
*
|