@blackcube/xgate-sdk 0.21.0 → 0.22.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.
- package/README.md +95 -5
- package/dist/index.cjs +183 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +117 -2
- package/dist/index.d.ts +117 -2
- package/dist/index.js +181 -5
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
package/dist/index.d.cts
CHANGED
|
@@ -68,6 +68,23 @@ interface IPair {
|
|
|
68
68
|
xex: XgateEx;
|
|
69
69
|
/** Type de marché (`perp`/`spot`). */
|
|
70
70
|
kind: MarketKind;
|
|
71
|
+
/**
|
|
72
|
+
* FACTEUR D'ÉCHELLE DE COTATION — `1000` pour `kPEPE`, `1000000` pour `1MBABYDOGE`, `1` sinon.
|
|
73
|
+
*
|
|
74
|
+
* **Aucune venue ne le publie** : l'information n'existe que dans le préfixe du nom, et le
|
|
75
|
+
* canonique la fait disparaître. Sans elle, comparer des prix entre venues est faux — `SATS`
|
|
76
|
+
* porte trois échelles sur quatre sources (×1, ×1000, ×10000). Diviser le prix par ce facteur
|
|
77
|
+
* ramène toutes les venues à la même unité.
|
|
78
|
+
*/
|
|
79
|
+
multiplier: number;
|
|
80
|
+
/**
|
|
81
|
+
* ÉCHÉANCE du contrat. `undefined` pour un perpétuel — l'immense majorité.
|
|
82
|
+
*
|
|
83
|
+
* Un future daté ne cote pas le comptant : sa base peut s'écarter de plusieurs pour cent. Neuf
|
|
84
|
+
* lignes BTC de bybit sont dans ce cas. Dérivée du **type de contrat**, jamais de la date de
|
|
85
|
+
* livraison : binance publie l'an 2100 sur ses perpétuels.
|
|
86
|
+
*/
|
|
87
|
+
expiresAt?: Date;
|
|
71
88
|
/**
|
|
72
89
|
* L'identifiant TECHNIQUE que la venue exige pour agir, quand il diffère du symbole (index de
|
|
73
90
|
* marché chez lighter, index spot chez hyperliquid). `null` quand le symbole suffit.
|
|
@@ -407,6 +424,45 @@ declare class SpotCatalogService {
|
|
|
407
424
|
private catalogOf;
|
|
408
425
|
}
|
|
409
426
|
|
|
427
|
+
/**
|
|
428
|
+
* LES BOUGIES DU **COMPTANT**, en REST — binance et bybit.
|
|
429
|
+
*
|
|
430
|
+
* **Un service à part, et non un drapeau sur {@link CandlesService}.** C'est la même règle que pour
|
|
431
|
+
* le catalogue : un `candles()` qui servirait tantôt du perpétuel tantôt du comptant selon un
|
|
432
|
+
* paramètre produirait des erreurs silencieuses — on croirait lire des perpétuels et on lirait du
|
|
433
|
+
* comptant, sans que rien ne le signale. Deux marchés, deux services ; l'appelant choisit
|
|
434
|
+
* explicitement ce qu'il interroge.
|
|
435
|
+
*
|
|
436
|
+
* La différence n'est pas cosmétique : le perpétuel porte un funding et peut s'écarter du comptant,
|
|
437
|
+
* et **les échelles de cotation diffèrent d'un marché à l'autre** — `SATSUSDT` au comptant chez
|
|
438
|
+
* bybit cote ×1 quand son perpétuel cote ×10000. Mélanger les deux séries fabriquerait un graphe
|
|
439
|
+
* qui saute d'un facteur 10 000.
|
|
440
|
+
*
|
|
441
|
+
* **Aucune agrégation ici**, contrairement au perpétuel : binance et bybit servent nativement tous
|
|
442
|
+
* les intervalles de `1m` à `1w`. Le jour où une venue comptant en manquerait un, ce serait à
|
|
443
|
+
* ajouter — pas à supposer.
|
|
444
|
+
*/
|
|
445
|
+
declare class SpotCandlesService {
|
|
446
|
+
private readonly logger;
|
|
447
|
+
/** Les venues dont XGate sert le comptant. */
|
|
448
|
+
venues(): readonly XgateEx[];
|
|
449
|
+
/**
|
|
450
|
+
* Les bougies comptant d'une venue, sur une plage de **dates**.
|
|
451
|
+
*
|
|
452
|
+
* **Lève** si la venue ne sert pas de comptant, plutôt que de rendre une liste vide : « cette
|
|
453
|
+
* venue n'a pas de marché comptant » et « ce marché n'a pas coté » appellent des suites très
|
|
454
|
+
* différentes.
|
|
455
|
+
*/
|
|
456
|
+
candles(xex: XgateEx, query: ICandlesQuery): Promise<ICandle[]>;
|
|
457
|
+
/**
|
|
458
|
+
* Les bougies comptant d'un même marché chez PLUSIEURS venues, en une liste.
|
|
459
|
+
*
|
|
460
|
+
* Même politique d'échec que partout ailleurs : seule, une venue en échec fait échouer l'appel ;
|
|
461
|
+
* parmi d'autres, elle est journalisée et ignorée. Chaque bougie porte son `xex`.
|
|
462
|
+
*/
|
|
463
|
+
candlesOf(xexes: XgateEx[], query: ICandlesQuery): Promise<ICandle[]>;
|
|
464
|
+
}
|
|
465
|
+
|
|
410
466
|
/** Une paire, telle qu'un SDK de venue la rend. */
|
|
411
467
|
interface IXexPair {
|
|
412
468
|
name: string;
|
|
@@ -535,7 +591,7 @@ interface IXexAccess {
|
|
|
535
591
|
* Les venues dont XGate sait lire le portefeuille aujourd'hui.
|
|
536
592
|
*
|
|
537
593
|
* Les autres ne sont pas exclues par principe : il leur manque un accès (clé d'API pour bullet, une
|
|
538
|
-
* adresse active pour
|
|
594
|
+
* adresse active pour extended et paradex). Voir le backlog.
|
|
539
595
|
*/
|
|
540
596
|
declare const WALLET_XEXES: readonly XgateEx[];
|
|
541
597
|
/**
|
|
@@ -660,6 +716,22 @@ declare class WalletService {
|
|
|
660
716
|
* regarde autrement qu'une panne.
|
|
661
717
|
*/
|
|
662
718
|
balances(...accesses: IWalletAccess[]): Promise<IBalance[]>;
|
|
719
|
+
/**
|
|
720
|
+
* LE COLLATÉRAL PERPÉTUEL, ajouté aux soldes comptant — sans lui, un portefeuille peut paraître VIDE.
|
|
721
|
+
*
|
|
722
|
+
* `getBalances` ne rend que le **comptant**, chez les huit venues : c'est leur convention, et la
|
|
723
|
+
* documentation de chacune le dit. Or l'argent qui sert à trader n'y est pas. Sur un compte
|
|
724
|
+
* pacifica dont tout le solde est en marge, `getBalances` rend `[]` — ce qui se lit « pas
|
|
725
|
+
* d'argent » alors qu'il y a 499 USDC. Sur hyperliquid, le comptant s'affiche mais la marge
|
|
726
|
+
* manque.
|
|
727
|
+
*
|
|
728
|
+
* La ligne est **marquée `scope: 'perp'`** dans `xtras` : elle s'additionne au comptant sans le
|
|
729
|
+
* doubler, et un appelant qui ne veut que l'un des deux peut trancher.
|
|
730
|
+
*
|
|
731
|
+
* Le champ diffère par venue et n'est pas devinable — d'où la lecture explicite, venue par venue,
|
|
732
|
+
* plutôt qu'un parcours à l'aveugle d'un objet `unknown`.
|
|
733
|
+
*/
|
|
734
|
+
private perpCollateral;
|
|
663
735
|
/**
|
|
664
736
|
* Les mouvements d'argent, triés du plus ancien au plus récent, montants **signés**.
|
|
665
737
|
*
|
|
@@ -1088,5 +1160,48 @@ declare function canonicalFromXex(rawSymbol: string, xexId: string): string;
|
|
|
1088
1160
|
* symbole.
|
|
1089
1161
|
*/
|
|
1090
1162
|
declare function canonicalFromBase(base: string): string;
|
|
1163
|
+
/**
|
|
1164
|
+
* LE MULTIPLICATEUR DE COTATION, extrait du nom — **la seule source qui existe**.
|
|
1165
|
+
*
|
|
1166
|
+
* Aucune venue ne le publie : `kPEPE` chez hyperliquid ne porte que `{"marginTableId":52}`,
|
|
1167
|
+
* `1000PEPEUSDT` chez binance ne mentionne aucun facteur. L'information n'est QUE dans le préfixe
|
|
1168
|
+
* du nom, et le canonique la fait disparaître — jusqu'ici sans la conserver nulle part.
|
|
1169
|
+
*
|
|
1170
|
+
* Or elle est indispensable dès qu'on compare des prix entre venues. `SATS` porte **trois échelles
|
|
1171
|
+
* différentes sur quatre sources** : `SATSUSDT` (×1) chez bybit-spot, `1000SATSUSDT` (×1000) chez
|
|
1172
|
+
* binance, `10000SATSUSDT` (×10000) chez bybit. Une médiane calculée sur ces prix bruts ne veut
|
|
1173
|
+
* rien dire ; divisés par leur facteur, ils redeviennent comparables.
|
|
1174
|
+
*
|
|
1175
|
+
* Rend `1` quand le nom ne porte aucune échelle — le cas de l'immense majorité.
|
|
1176
|
+
*/
|
|
1177
|
+
declare function multiplierFromXex(rawSymbol: string): number;
|
|
1178
|
+
|
|
1179
|
+
/**
|
|
1180
|
+
* LES CONTRATS À ÉCHÉANCE, séparés des perpétuels — parce qu'un future daté ne cote pas le comptant.
|
|
1181
|
+
*
|
|
1182
|
+
* Le catalogue les mélangeait : 44 lignes portaient `kind: 'perp'` alors qu'elles expirent, dont
|
|
1183
|
+
* neuf sur le seul BTC chez bybit. Un consommateur qui prend « le prix du BTC » y ramassait une
|
|
1184
|
+
* échéance de décembre, dont la base au comptant peut s'écarter de plusieurs pour cent.
|
|
1185
|
+
*
|
|
1186
|
+
* **`contractType` fait foi, JAMAIS la date de livraison.** binance publie `deliveryDate:
|
|
1187
|
+
* 4133404800000` — le 1er janvier 2100 — sur ses **perpétuels** : s'y fier marquerait tout le
|
|
1188
|
+
* catalogue comme daté. bybit, lui, met `deliveryTime: '0'` sur les siens. Deux conventions
|
|
1189
|
+
* incompatibles pour dire « ceci n'expire pas », d'où la lecture du type et de lui seul.
|
|
1190
|
+
*/
|
|
1191
|
+
/**
|
|
1192
|
+
* L'ÉCHÉANCE D'UN CONTRAT, ou `undefined` s'il est perpétuel.
|
|
1193
|
+
*
|
|
1194
|
+
* On ne lit la date **que** si le type de contrat annonce une échéance : c'est ce qui neutralise le
|
|
1195
|
+
* `deliveryDate` de l'an 2100 des perpétuels binance. Un type inconnu est traité comme perpétuel —
|
|
1196
|
+
* l'immense majorité des lignes, et se tromper dans ce sens n'invente pas d'échéance.
|
|
1197
|
+
*/
|
|
1198
|
+
declare function expiryOf(xtras?: Record<string, unknown>): Date | undefined;
|
|
1199
|
+
/**
|
|
1200
|
+
* LE CONTRAT EXPIRE-T-IL ? Vrai pour un future daté, faux pour un perpétuel.
|
|
1201
|
+
*
|
|
1202
|
+
* Séparé d'{@link expiryOf} à dessein : une venue peut annoncer un type daté sans publier de date
|
|
1203
|
+
* exploitable, et il faut alors pouvoir écarter la ligne quand même.
|
|
1204
|
+
*/
|
|
1205
|
+
declare function isDated(xtras?: Record<string, unknown>): boolean;
|
|
1091
1206
|
|
|
1092
|
-
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 };
|
|
1207
|
+
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, SpotCandlesService, SpotCatalogService, TIMEFRAME_MINUTES, type TimeInForce, Timeframe, TradingService, type Unsubscribe, WALLET_XEXES, WalletService, WsCandlesService, XGATE_EXCHANGES, XgateEx, XgateModule, buildLevels, buildProtection, canonicalFromBase, canonicalFromXex, expiryOf, isDated, multiplierFromXex, roundPrice, roundToStep, servesNatively, servesSpot, sourceFor, timeframeMs };
|
package/dist/index.d.ts
CHANGED
|
@@ -68,6 +68,23 @@ interface IPair {
|
|
|
68
68
|
xex: XgateEx;
|
|
69
69
|
/** Type de marché (`perp`/`spot`). */
|
|
70
70
|
kind: MarketKind;
|
|
71
|
+
/**
|
|
72
|
+
* FACTEUR D'ÉCHELLE DE COTATION — `1000` pour `kPEPE`, `1000000` pour `1MBABYDOGE`, `1` sinon.
|
|
73
|
+
*
|
|
74
|
+
* **Aucune venue ne le publie** : l'information n'existe que dans le préfixe du nom, et le
|
|
75
|
+
* canonique la fait disparaître. Sans elle, comparer des prix entre venues est faux — `SATS`
|
|
76
|
+
* porte trois échelles sur quatre sources (×1, ×1000, ×10000). Diviser le prix par ce facteur
|
|
77
|
+
* ramène toutes les venues à la même unité.
|
|
78
|
+
*/
|
|
79
|
+
multiplier: number;
|
|
80
|
+
/**
|
|
81
|
+
* ÉCHÉANCE du contrat. `undefined` pour un perpétuel — l'immense majorité.
|
|
82
|
+
*
|
|
83
|
+
* Un future daté ne cote pas le comptant : sa base peut s'écarter de plusieurs pour cent. Neuf
|
|
84
|
+
* lignes BTC de bybit sont dans ce cas. Dérivée du **type de contrat**, jamais de la date de
|
|
85
|
+
* livraison : binance publie l'an 2100 sur ses perpétuels.
|
|
86
|
+
*/
|
|
87
|
+
expiresAt?: Date;
|
|
71
88
|
/**
|
|
72
89
|
* L'identifiant TECHNIQUE que la venue exige pour agir, quand il diffère du symbole (index de
|
|
73
90
|
* marché chez lighter, index spot chez hyperliquid). `null` quand le symbole suffit.
|
|
@@ -407,6 +424,45 @@ declare class SpotCatalogService {
|
|
|
407
424
|
private catalogOf;
|
|
408
425
|
}
|
|
409
426
|
|
|
427
|
+
/**
|
|
428
|
+
* LES BOUGIES DU **COMPTANT**, en REST — binance et bybit.
|
|
429
|
+
*
|
|
430
|
+
* **Un service à part, et non un drapeau sur {@link CandlesService}.** C'est la même règle que pour
|
|
431
|
+
* le catalogue : un `candles()` qui servirait tantôt du perpétuel tantôt du comptant selon un
|
|
432
|
+
* paramètre produirait des erreurs silencieuses — on croirait lire des perpétuels et on lirait du
|
|
433
|
+
* comptant, sans que rien ne le signale. Deux marchés, deux services ; l'appelant choisit
|
|
434
|
+
* explicitement ce qu'il interroge.
|
|
435
|
+
*
|
|
436
|
+
* La différence n'est pas cosmétique : le perpétuel porte un funding et peut s'écarter du comptant,
|
|
437
|
+
* et **les échelles de cotation diffèrent d'un marché à l'autre** — `SATSUSDT` au comptant chez
|
|
438
|
+
* bybit cote ×1 quand son perpétuel cote ×10000. Mélanger les deux séries fabriquerait un graphe
|
|
439
|
+
* qui saute d'un facteur 10 000.
|
|
440
|
+
*
|
|
441
|
+
* **Aucune agrégation ici**, contrairement au perpétuel : binance et bybit servent nativement tous
|
|
442
|
+
* les intervalles de `1m` à `1w`. Le jour où une venue comptant en manquerait un, ce serait à
|
|
443
|
+
* ajouter — pas à supposer.
|
|
444
|
+
*/
|
|
445
|
+
declare class SpotCandlesService {
|
|
446
|
+
private readonly logger;
|
|
447
|
+
/** Les venues dont XGate sert le comptant. */
|
|
448
|
+
venues(): readonly XgateEx[];
|
|
449
|
+
/**
|
|
450
|
+
* Les bougies comptant d'une venue, sur une plage de **dates**.
|
|
451
|
+
*
|
|
452
|
+
* **Lève** si la venue ne sert pas de comptant, plutôt que de rendre une liste vide : « cette
|
|
453
|
+
* venue n'a pas de marché comptant » et « ce marché n'a pas coté » appellent des suites très
|
|
454
|
+
* différentes.
|
|
455
|
+
*/
|
|
456
|
+
candles(xex: XgateEx, query: ICandlesQuery): Promise<ICandle[]>;
|
|
457
|
+
/**
|
|
458
|
+
* Les bougies comptant d'un même marché chez PLUSIEURS venues, en une liste.
|
|
459
|
+
*
|
|
460
|
+
* Même politique d'échec que partout ailleurs : seule, une venue en échec fait échouer l'appel ;
|
|
461
|
+
* parmi d'autres, elle est journalisée et ignorée. Chaque bougie porte son `xex`.
|
|
462
|
+
*/
|
|
463
|
+
candlesOf(xexes: XgateEx[], query: ICandlesQuery): Promise<ICandle[]>;
|
|
464
|
+
}
|
|
465
|
+
|
|
410
466
|
/** Une paire, telle qu'un SDK de venue la rend. */
|
|
411
467
|
interface IXexPair {
|
|
412
468
|
name: string;
|
|
@@ -535,7 +591,7 @@ interface IXexAccess {
|
|
|
535
591
|
* Les venues dont XGate sait lire le portefeuille aujourd'hui.
|
|
536
592
|
*
|
|
537
593
|
* Les autres ne sont pas exclues par principe : il leur manque un accès (clé d'API pour bullet, une
|
|
538
|
-
* adresse active pour
|
|
594
|
+
* adresse active pour extended et paradex). Voir le backlog.
|
|
539
595
|
*/
|
|
540
596
|
declare const WALLET_XEXES: readonly XgateEx[];
|
|
541
597
|
/**
|
|
@@ -660,6 +716,22 @@ declare class WalletService {
|
|
|
660
716
|
* regarde autrement qu'une panne.
|
|
661
717
|
*/
|
|
662
718
|
balances(...accesses: IWalletAccess[]): Promise<IBalance[]>;
|
|
719
|
+
/**
|
|
720
|
+
* LE COLLATÉRAL PERPÉTUEL, ajouté aux soldes comptant — sans lui, un portefeuille peut paraître VIDE.
|
|
721
|
+
*
|
|
722
|
+
* `getBalances` ne rend que le **comptant**, chez les huit venues : c'est leur convention, et la
|
|
723
|
+
* documentation de chacune le dit. Or l'argent qui sert à trader n'y est pas. Sur un compte
|
|
724
|
+
* pacifica dont tout le solde est en marge, `getBalances` rend `[]` — ce qui se lit « pas
|
|
725
|
+
* d'argent » alors qu'il y a 499 USDC. Sur hyperliquid, le comptant s'affiche mais la marge
|
|
726
|
+
* manque.
|
|
727
|
+
*
|
|
728
|
+
* La ligne est **marquée `scope: 'perp'`** dans `xtras` : elle s'additionne au comptant sans le
|
|
729
|
+
* doubler, et un appelant qui ne veut que l'un des deux peut trancher.
|
|
730
|
+
*
|
|
731
|
+
* Le champ diffère par venue et n'est pas devinable — d'où la lecture explicite, venue par venue,
|
|
732
|
+
* plutôt qu'un parcours à l'aveugle d'un objet `unknown`.
|
|
733
|
+
*/
|
|
734
|
+
private perpCollateral;
|
|
663
735
|
/**
|
|
664
736
|
* Les mouvements d'argent, triés du plus ancien au plus récent, montants **signés**.
|
|
665
737
|
*
|
|
@@ -1088,5 +1160,48 @@ declare function canonicalFromXex(rawSymbol: string, xexId: string): string;
|
|
|
1088
1160
|
* symbole.
|
|
1089
1161
|
*/
|
|
1090
1162
|
declare function canonicalFromBase(base: string): string;
|
|
1163
|
+
/**
|
|
1164
|
+
* LE MULTIPLICATEUR DE COTATION, extrait du nom — **la seule source qui existe**.
|
|
1165
|
+
*
|
|
1166
|
+
* Aucune venue ne le publie : `kPEPE` chez hyperliquid ne porte que `{"marginTableId":52}`,
|
|
1167
|
+
* `1000PEPEUSDT` chez binance ne mentionne aucun facteur. L'information n'est QUE dans le préfixe
|
|
1168
|
+
* du nom, et le canonique la fait disparaître — jusqu'ici sans la conserver nulle part.
|
|
1169
|
+
*
|
|
1170
|
+
* Or elle est indispensable dès qu'on compare des prix entre venues. `SATS` porte **trois échelles
|
|
1171
|
+
* différentes sur quatre sources** : `SATSUSDT` (×1) chez bybit-spot, `1000SATSUSDT` (×1000) chez
|
|
1172
|
+
* binance, `10000SATSUSDT` (×10000) chez bybit. Une médiane calculée sur ces prix bruts ne veut
|
|
1173
|
+
* rien dire ; divisés par leur facteur, ils redeviennent comparables.
|
|
1174
|
+
*
|
|
1175
|
+
* Rend `1` quand le nom ne porte aucune échelle — le cas de l'immense majorité.
|
|
1176
|
+
*/
|
|
1177
|
+
declare function multiplierFromXex(rawSymbol: string): number;
|
|
1178
|
+
|
|
1179
|
+
/**
|
|
1180
|
+
* LES CONTRATS À ÉCHÉANCE, séparés des perpétuels — parce qu'un future daté ne cote pas le comptant.
|
|
1181
|
+
*
|
|
1182
|
+
* Le catalogue les mélangeait : 44 lignes portaient `kind: 'perp'` alors qu'elles expirent, dont
|
|
1183
|
+
* neuf sur le seul BTC chez bybit. Un consommateur qui prend « le prix du BTC » y ramassait une
|
|
1184
|
+
* échéance de décembre, dont la base au comptant peut s'écarter de plusieurs pour cent.
|
|
1185
|
+
*
|
|
1186
|
+
* **`contractType` fait foi, JAMAIS la date de livraison.** binance publie `deliveryDate:
|
|
1187
|
+
* 4133404800000` — le 1er janvier 2100 — sur ses **perpétuels** : s'y fier marquerait tout le
|
|
1188
|
+
* catalogue comme daté. bybit, lui, met `deliveryTime: '0'` sur les siens. Deux conventions
|
|
1189
|
+
* incompatibles pour dire « ceci n'expire pas », d'où la lecture du type et de lui seul.
|
|
1190
|
+
*/
|
|
1191
|
+
/**
|
|
1192
|
+
* L'ÉCHÉANCE D'UN CONTRAT, ou `undefined` s'il est perpétuel.
|
|
1193
|
+
*
|
|
1194
|
+
* On ne lit la date **que** si le type de contrat annonce une échéance : c'est ce qui neutralise le
|
|
1195
|
+
* `deliveryDate` de l'an 2100 des perpétuels binance. Un type inconnu est traité comme perpétuel —
|
|
1196
|
+
* l'immense majorité des lignes, et se tromper dans ce sens n'invente pas d'échéance.
|
|
1197
|
+
*/
|
|
1198
|
+
declare function expiryOf(xtras?: Record<string, unknown>): Date | undefined;
|
|
1199
|
+
/**
|
|
1200
|
+
* LE CONTRAT EXPIRE-T-IL ? Vrai pour un future daté, faux pour un perpétuel.
|
|
1201
|
+
*
|
|
1202
|
+
* Séparé d'{@link expiryOf} à dessein : une venue peut annoncer un type daté sans publier de date
|
|
1203
|
+
* exploitable, et il faut alors pouvoir écarter la ligne quand même.
|
|
1204
|
+
*/
|
|
1205
|
+
declare function isDated(xtras?: Record<string, unknown>): boolean;
|
|
1091
1206
|
|
|
1092
|
-
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 };
|
|
1207
|
+
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, SpotCandlesService, SpotCatalogService, TIMEFRAME_MINUTES, type TimeInForce, Timeframe, TradingService, type Unsubscribe, WALLET_XEXES, WalletService, WsCandlesService, XGATE_EXCHANGES, XgateEx, XgateModule, buildLevels, buildProtection, canonicalFromBase, canonicalFromXex, expiryOf, isDated, multiplierFromXex, roundPrice, roundToStep, servesNatively, servesSpot, sourceFor, timeframeMs };
|
package/dist/index.js
CHANGED
|
@@ -148,6 +148,8 @@ function sum(left, right) {
|
|
|
148
148
|
var CONCAT_QUOTE_XEXS = /* @__PURE__ */ new Set(["aster", "binance", "bybit"]);
|
|
149
149
|
var K_MULTIPLIER = /^k(?=[A-Z])/u;
|
|
150
150
|
var NUMERIC_MULTIPLIER = /^10{3,}(?=[A-Z0-9])/u;
|
|
151
|
+
var ABBREV_MULTIPLIER = /^1([MK])(?=[A-Z]{2,})/u;
|
|
152
|
+
var ABBREV_FACTOR = { M: 1e6, K: 1e3 };
|
|
151
153
|
var STOCK_24_5 = /_24_5$/u;
|
|
152
154
|
var TICKER_ALIASES = {
|
|
153
155
|
GOOG: "GOOGL",
|
|
@@ -172,13 +174,26 @@ function canonicalFromXex(rawSymbol, xexId) {
|
|
|
172
174
|
s = s.replace(/-USD-PERP$/u, "").replace(/-PERP$/u, "").replace(/-USDT$/u, "").replace(/-USDC$/u, "").replace(/-USD$/u, "");
|
|
173
175
|
}
|
|
174
176
|
s = s.replace(NUMERIC_MULTIPLIER, "");
|
|
177
|
+
s = s.replace(ABBREV_MULTIPLIER, "");
|
|
175
178
|
s = s.replace(STOCK_24_5, "");
|
|
176
179
|
return TICKER_ALIASES[s] ?? s;
|
|
177
180
|
}
|
|
178
181
|
function canonicalFromBase(base) {
|
|
179
|
-
const s = base.replace(K_MULTIPLIER, "").toUpperCase().replace(NUMERIC_MULTIPLIER, "").replace(STOCK_24_5, "");
|
|
182
|
+
const s = base.replace(K_MULTIPLIER, "").toUpperCase().replace(NUMERIC_MULTIPLIER, "").replace(ABBREV_MULTIPLIER, "").replace(STOCK_24_5, "");
|
|
180
183
|
return TICKER_ALIASES[s] ?? s;
|
|
181
184
|
}
|
|
185
|
+
function multiplierFromXex(rawSymbol) {
|
|
186
|
+
if (K_MULTIPLIER.test(rawSymbol)) {
|
|
187
|
+
return 1e3;
|
|
188
|
+
}
|
|
189
|
+
const upper = rawSymbol.toUpperCase();
|
|
190
|
+
const abbrev = ABBREV_MULTIPLIER.exec(upper);
|
|
191
|
+
if (abbrev !== null) {
|
|
192
|
+
return ABBREV_FACTOR[abbrev[1]] ?? 1;
|
|
193
|
+
}
|
|
194
|
+
const zeros = NUMERIC_MULTIPLIER.exec(upper);
|
|
195
|
+
return zeros === null ? 1 : Number(zeros[0]);
|
|
196
|
+
}
|
|
182
197
|
|
|
183
198
|
// src/helpers/candle-mapper.ts
|
|
184
199
|
function toCandle(wire, xex, interval, quote) {
|
|
@@ -263,6 +278,19 @@ function createAccountXex(xex, access) {
|
|
|
263
278
|
},
|
|
264
279
|
{ default: "a" }
|
|
265
280
|
);
|
|
281
|
+
case "lighter" /* Lighter */:
|
|
282
|
+
return new Lighter(
|
|
283
|
+
{
|
|
284
|
+
a: {
|
|
285
|
+
apiPrivateKey: access.privateKey ?? NULL_KEY,
|
|
286
|
+
apiKeyIndex: access.apiKeyIndex ?? 0,
|
|
287
|
+
accountIndex: access.accountIndex ?? 0,
|
|
288
|
+
l1Address: adresse(),
|
|
289
|
+
network: access.network ?? "mainnet"
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
{ default: "a" }
|
|
293
|
+
);
|
|
266
294
|
case "aster" /* Aster */:
|
|
267
295
|
if (access.privateKey === void 0 || access.privateKey === "") {
|
|
268
296
|
throw new Error(
|
|
@@ -303,6 +331,7 @@ var WALLET_XEXES = [
|
|
|
303
331
|
"hyperliquid" /* Hyperliquid */,
|
|
304
332
|
"pacifica" /* Pacifica */,
|
|
305
333
|
"aster" /* Aster */,
|
|
334
|
+
"lighter" /* Lighter */,
|
|
306
335
|
"blofin" /* Blofin */
|
|
307
336
|
];
|
|
308
337
|
function createPublicXex(xex) {
|
|
@@ -347,8 +376,11 @@ function createPublicSpotXex(xex) {
|
|
|
347
376
|
}
|
|
348
377
|
|
|
349
378
|
// src/helpers/xex-timeframes.ts
|
|
379
|
+
var HYPERLIQUID_NATIVE = Object.values(Timeframe).filter(
|
|
380
|
+
(interval) => interval !== "1w" /* W */
|
|
381
|
+
);
|
|
350
382
|
var NATIVE = {
|
|
351
|
-
["hyperliquid" /* Hyperliquid */]:
|
|
383
|
+
["hyperliquid" /* Hyperliquid */]: HYPERLIQUID_NATIVE,
|
|
352
384
|
["pacifica" /* Pacifica */]: Object.values(Timeframe),
|
|
353
385
|
["aster" /* Aster */]: Object.values(Timeframe),
|
|
354
386
|
["blofin" /* Blofin */]: Object.values(Timeframe),
|
|
@@ -476,6 +508,43 @@ var CandlesService = class {
|
|
|
476
508
|
CandlesService = __decorateClass([
|
|
477
509
|
Injectable()
|
|
478
510
|
], CandlesService);
|
|
511
|
+
|
|
512
|
+
// src/helpers/contract-expiry.ts
|
|
513
|
+
var DATED_CONTRACT_TYPES = /* @__PURE__ */ new Set([
|
|
514
|
+
// binance : les trimestriels (`BTCUSDT_260925`, `ETHUSDT_261225`).
|
|
515
|
+
"CURRENT_QUARTER",
|
|
516
|
+
"NEXT_QUARTER",
|
|
517
|
+
"CURRENT_QUARTER_DELIVERING",
|
|
518
|
+
"NEXT_QUARTER_DELIVERING",
|
|
519
|
+
"PERPETUAL_DELIVERING",
|
|
520
|
+
// bybit : les datés (`BTCUSDT-25DEC26`), face à `LinearPerpetual`.
|
|
521
|
+
"LinearFutures",
|
|
522
|
+
"InverseFutures"
|
|
523
|
+
]);
|
|
524
|
+
var EXPIRY_FIELDS = ["deliveryTime", "deliveryDate", "expiryTime", "settleTime"];
|
|
525
|
+
function expiryOf(xtras) {
|
|
526
|
+
if (xtras === void 0) {
|
|
527
|
+
return void 0;
|
|
528
|
+
}
|
|
529
|
+
const type = xtras.contractType;
|
|
530
|
+
if (typeof type !== "string" || DATED_CONTRACT_TYPES.has(type) === false) {
|
|
531
|
+
return void 0;
|
|
532
|
+
}
|
|
533
|
+
for (const field of EXPIRY_FIELDS) {
|
|
534
|
+
const brut = xtras[field];
|
|
535
|
+
const ms = typeof brut === "string" ? Number(brut) : brut;
|
|
536
|
+
if (typeof ms === "number" && Number.isFinite(ms) === true && ms > 0) {
|
|
537
|
+
return new Date(ms);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return void 0;
|
|
541
|
+
}
|
|
542
|
+
function isDated(xtras) {
|
|
543
|
+
const type = xtras?.contractType;
|
|
544
|
+
return typeof type === "string" && DATED_CONTRACT_TYPES.has(type);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// src/services/catalog.service.ts
|
|
479
548
|
var NAMES_ITS_BASE = /* @__PURE__ */ new Set(["binance" /* Binance */, "bybit" /* Bybit */]);
|
|
480
549
|
var CatalogService = class {
|
|
481
550
|
logger = new Logger(CatalogService.name);
|
|
@@ -521,6 +590,8 @@ var CatalogService = class {
|
|
|
521
590
|
symbolXex: pair.name,
|
|
522
591
|
xex,
|
|
523
592
|
kind: pair.kind,
|
|
593
|
+
multiplier: multiplierFromXex(pair.name),
|
|
594
|
+
expiresAt: expiryOf(pair.xtras),
|
|
524
595
|
ref: pair.ref ?? null,
|
|
525
596
|
szDecimals: pair.szDecimals,
|
|
526
597
|
tickSize: pair.tickSize,
|
|
@@ -595,6 +666,65 @@ var PricesService = class {
|
|
|
595
666
|
PricesService = __decorateClass([
|
|
596
667
|
Injectable()
|
|
597
668
|
], PricesService);
|
|
669
|
+
var SpotCandlesService = class {
|
|
670
|
+
logger = new Logger(SpotCandlesService.name);
|
|
671
|
+
/** Les venues dont XGate sert le comptant. */
|
|
672
|
+
venues() {
|
|
673
|
+
return SPOT_XEXES;
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Les bougies comptant d'une venue, sur une plage de **dates**.
|
|
677
|
+
*
|
|
678
|
+
* **Lève** si la venue ne sert pas de comptant, plutôt que de rendre une liste vide : « cette
|
|
679
|
+
* venue n'a pas de marché comptant » et « ce marché n'a pas coté » appellent des suites très
|
|
680
|
+
* différentes.
|
|
681
|
+
*/
|
|
682
|
+
async candles(xex, query) {
|
|
683
|
+
if (servesSpot(xex) === false) {
|
|
684
|
+
throw new Error(
|
|
685
|
+
`spotCandles(${xex}) : cette venue ne sert pas de comptant. Disponibles : ${SPOT_XEXES.join(", ")}.`
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
const spot = createPublicSpotXex(xex).spot();
|
|
689
|
+
if (spot.getCandles === void 0) {
|
|
690
|
+
throw new Error(`spotCandles(${xex}) : cette venue ne sert pas de bougies comptant en REST.`);
|
|
691
|
+
}
|
|
692
|
+
const wires = await spot.getCandles(toXexQuery(query));
|
|
693
|
+
return wires.map((wire) => toCandle(wire, xex, query.interval, ""));
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Les bougies comptant d'un même marché chez PLUSIEURS venues, en une liste.
|
|
697
|
+
*
|
|
698
|
+
* Même politique d'échec que partout ailleurs : seule, une venue en échec fait échouer l'appel ;
|
|
699
|
+
* parmi d'autres, elle est journalisée et ignorée. Chaque bougie porte son `xex`.
|
|
700
|
+
*/
|
|
701
|
+
async candlesOf(xexes, query) {
|
|
702
|
+
if (xexes.length === 0) {
|
|
703
|
+
throw new Error("spotCandlesOf() : aucune venue demand\xE9e \u2014 pr\xE9cise au moins un XgateEx.");
|
|
704
|
+
}
|
|
705
|
+
const solo = xexes.length === 1;
|
|
706
|
+
const collected = await Promise.all(
|
|
707
|
+
xexes.map(async (xex) => {
|
|
708
|
+
try {
|
|
709
|
+
return await this.candles(xex, query);
|
|
710
|
+
} catch (error) {
|
|
711
|
+
if (solo === true) {
|
|
712
|
+
throw error;
|
|
713
|
+
}
|
|
714
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
715
|
+
this.logger.error(
|
|
716
|
+
`spotCandles(${xex}, ${query.interval}) a \xE9chou\xE9, venue ignor\xE9e : ${message}`
|
|
717
|
+
);
|
|
718
|
+
return [];
|
|
719
|
+
}
|
|
720
|
+
})
|
|
721
|
+
);
|
|
722
|
+
return collected.flat();
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
SpotCandlesService = __decorateClass([
|
|
726
|
+
Injectable()
|
|
727
|
+
], SpotCandlesService);
|
|
598
728
|
var SpotCatalogService = class {
|
|
599
729
|
logger = new Logger(SpotCatalogService.name);
|
|
600
730
|
/** Les venues dont XGate sert le comptant. */
|
|
@@ -646,6 +776,9 @@ var SpotCatalogService = class {
|
|
|
646
776
|
symbolXex: pair.name,
|
|
647
777
|
xex,
|
|
648
778
|
kind: pair.kind,
|
|
779
|
+
// Le comptant porte les mêmes échelles que le perp : `SATSUSDT` (×1) et `1000SATSUSDT`
|
|
780
|
+
// coexistent, et c'est justement entre eux que la comparaison serait fausse.
|
|
781
|
+
multiplier: multiplierFromXex(pair.name),
|
|
649
782
|
ref: pair.ref ?? null,
|
|
650
783
|
szDecimals: pair.szDecimals,
|
|
651
784
|
tickSize: pair.tickSize,
|
|
@@ -1011,8 +1144,9 @@ var WalletService = class {
|
|
|
1011
1144
|
*/
|
|
1012
1145
|
async balances(...accesses) {
|
|
1013
1146
|
return this.collect(accesses, "balances", async (access) => {
|
|
1014
|
-
const
|
|
1015
|
-
|
|
1147
|
+
const source = createAccountXex(access.xex, access);
|
|
1148
|
+
const balances = await source.account().getBalances();
|
|
1149
|
+
const lignes = balances.map((balance) => ({
|
|
1016
1150
|
xex: access.xex,
|
|
1017
1151
|
asset: balance.asset,
|
|
1018
1152
|
total: balance.total,
|
|
@@ -1020,8 +1154,48 @@ var WalletService = class {
|
|
|
1020
1154
|
usdValue: balance.usdValue,
|
|
1021
1155
|
xtras: balance.xtras
|
|
1022
1156
|
}));
|
|
1157
|
+
const collateral = await this.perpCollateral(source, access.xex);
|
|
1158
|
+
return collateral === null ? lignes : [...lignes, collateral];
|
|
1023
1159
|
});
|
|
1024
1160
|
}
|
|
1161
|
+
/**
|
|
1162
|
+
* LE COLLATÉRAL PERPÉTUEL, ajouté aux soldes comptant — sans lui, un portefeuille peut paraître VIDE.
|
|
1163
|
+
*
|
|
1164
|
+
* `getBalances` ne rend que le **comptant**, chez les huit venues : c'est leur convention, et la
|
|
1165
|
+
* documentation de chacune le dit. Or l'argent qui sert à trader n'y est pas. Sur un compte
|
|
1166
|
+
* pacifica dont tout le solde est en marge, `getBalances` rend `[]` — ce qui se lit « pas
|
|
1167
|
+
* d'argent » alors qu'il y a 499 USDC. Sur hyperliquid, le comptant s'affiche mais la marge
|
|
1168
|
+
* manque.
|
|
1169
|
+
*
|
|
1170
|
+
* La ligne est **marquée `scope: 'perp'`** dans `xtras` : elle s'additionne au comptant sans le
|
|
1171
|
+
* doubler, et un appelant qui ne veut que l'un des deux peut trancher.
|
|
1172
|
+
*
|
|
1173
|
+
* Le champ diffère par venue et n'est pas devinable — d'où la lecture explicite, venue par venue,
|
|
1174
|
+
* plutôt qu'un parcours à l'aveugle d'un objet `unknown`.
|
|
1175
|
+
*/
|
|
1176
|
+
async perpCollateral(source, xex) {
|
|
1177
|
+
const facade = source;
|
|
1178
|
+
if (typeof facade.perp !== "function") {
|
|
1179
|
+
return null;
|
|
1180
|
+
}
|
|
1181
|
+
const scope = facade.perp();
|
|
1182
|
+
if (typeof scope.getAccountInfo !== "function") {
|
|
1183
|
+
return null;
|
|
1184
|
+
}
|
|
1185
|
+
const info = await scope.getAccountInfo();
|
|
1186
|
+
const total = info.balance ?? info.marginSummary?.accountValue;
|
|
1187
|
+
if (total === void 0 || Number(total) === 0) {
|
|
1188
|
+
return null;
|
|
1189
|
+
}
|
|
1190
|
+
return {
|
|
1191
|
+
xex,
|
|
1192
|
+
asset: "USDC",
|
|
1193
|
+
total,
|
|
1194
|
+
available: info.availableToSpend ?? info.withdrawable ?? null,
|
|
1195
|
+
usdValue: total,
|
|
1196
|
+
xtras: { scope: "perp" }
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1025
1199
|
/**
|
|
1026
1200
|
* Les mouvements d'argent, triés du plus ancien au plus récent, montants **signés**.
|
|
1027
1201
|
*
|
|
@@ -1169,6 +1343,7 @@ XgateModule = __decorateClass([
|
|
|
1169
1343
|
WsCandlesService,
|
|
1170
1344
|
PricesService,
|
|
1171
1345
|
SpotCatalogService,
|
|
1346
|
+
SpotCandlesService,
|
|
1172
1347
|
WalletService
|
|
1173
1348
|
],
|
|
1174
1349
|
exports: [
|
|
@@ -1177,11 +1352,12 @@ XgateModule = __decorateClass([
|
|
|
1177
1352
|
WsCandlesService,
|
|
1178
1353
|
PricesService,
|
|
1179
1354
|
SpotCatalogService,
|
|
1355
|
+
SpotCandlesService,
|
|
1180
1356
|
WalletService
|
|
1181
1357
|
]
|
|
1182
1358
|
})
|
|
1183
1359
|
], XgateModule);
|
|
1184
1360
|
|
|
1185
|
-
export { CandlesService, CatalogService, ORDER_STATUSES, PricesService, SPOT_XEXES, SpotCatalogService, TIMEFRAME_MINUTES, Timeframe, TradingService, WALLET_XEXES, WalletService, WsCandlesService, XGATE_EXCHANGES, XgateEx, XgateModule, buildLevels, buildProtection, canonicalFromBase, canonicalFromXex, roundPrice, roundToStep, servesNatively, servesSpot, sourceFor, timeframeMs };
|
|
1361
|
+
export { CandlesService, CatalogService, ORDER_STATUSES, PricesService, SPOT_XEXES, SpotCandlesService, SpotCatalogService, TIMEFRAME_MINUTES, Timeframe, TradingService, WALLET_XEXES, WalletService, WsCandlesService, XGATE_EXCHANGES, XgateEx, XgateModule, buildLevels, buildProtection, canonicalFromBase, canonicalFromXex, expiryOf, isDated, multiplierFromXex, roundPrice, roundToStep, servesNatively, servesSpot, sourceFor, timeframeMs };
|
|
1186
1362
|
//# sourceMappingURL=index.js.map
|
|
1187
1363
|
//# sourceMappingURL=index.js.map
|