@blackcube/xgate-sdk 0.56.3 → 0.58.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/dist/index.cjs +139 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -4
- package/dist/index.d.ts +47 -4
- package/dist/index.js +139 -17
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/dist/index.d.cts
CHANGED
|
@@ -1323,6 +1323,8 @@ interface IOrder {
|
|
|
1323
1323
|
type: OrderType;
|
|
1324
1324
|
/** `null` pour un ordre au marché. */
|
|
1325
1325
|
price: string | null;
|
|
1326
|
+
/** Prix de DÉCLENCHEMENT d'un ordre conditionnel (stop, take-profit) ; `null` pour un ordre ordinaire. */
|
|
1327
|
+
triggerPrice: string | null;
|
|
1326
1328
|
/** Taille demandée, **en unités de base**. */
|
|
1327
1329
|
size: string;
|
|
1328
1330
|
/** Taille déjà exécutée, **en unités de base**. */
|
|
@@ -1335,6 +1337,24 @@ interface IOrder {
|
|
|
1335
1337
|
placedAt: Date;
|
|
1336
1338
|
xtras?: Record<string, unknown>;
|
|
1337
1339
|
}
|
|
1340
|
+
/** Le rôle d'un ordre dans un trade : l'entrée, le stop, ou un take-profit. */
|
|
1341
|
+
type TradeOrderRole = 'entry' | 'sl' | 'tp';
|
|
1342
|
+
/**
|
|
1343
|
+
* UN ORDRE DU TRADE — ce que {@link TradingService.openWithProtection} rend, une ligne par ordre posé.
|
|
1344
|
+
*
|
|
1345
|
+
* La même forme sur toutes les venues : l'appelant garde cette liste avec son trade et la gère sans savoir
|
|
1346
|
+
* comment chaque venue a posé ses protections (hyperliquid en lot, aster une à une, pacifica embarquées dans
|
|
1347
|
+
* l'entrée). C'est XGate qui fait le pont.
|
|
1348
|
+
*
|
|
1349
|
+
* **L'identifiant n'est vide que si l'ordre n'existe pas ou plus** — refusé, ou déjà consommé (un stop touché
|
|
1350
|
+
* dans la seconde) : `status` dit lequel. Une venue qui ne rend pas l'identifiant d'une protection à l'envoi
|
|
1351
|
+
* (hyperliquid `normalTpsl`, pacifica embarqué) le voit retrouvé au carnet par XGate.
|
|
1352
|
+
*/
|
|
1353
|
+
interface ITradeOrder extends IOrder {
|
|
1354
|
+
role: TradeOrderRole;
|
|
1355
|
+
/** La fraction de la position initiale que l'ordre couvre : 1 pour l'entrée et le stop. */
|
|
1356
|
+
part: number;
|
|
1357
|
+
}
|
|
1338
1358
|
/**
|
|
1339
1359
|
* UNE POSITION ouverte.
|
|
1340
1360
|
*
|
|
@@ -1562,8 +1582,11 @@ declare class TradingService {
|
|
|
1562
1582
|
/**
|
|
1563
1583
|
* OUVRE UNE POSITION AVEC SA PROTECTION, en un geste atomique.
|
|
1564
1584
|
*
|
|
1565
|
-
*
|
|
1566
|
-
* l'ordre
|
|
1585
|
+
* **Ce qui revient est la liste des ORDRES DU TRADE** ({@link ITradeOrder}), la même sur toutes les
|
|
1586
|
+
* venues : l'entrée, le stop, puis chaque take-profit dans l'ordre du plan — chacun avec son rôle, sa
|
|
1587
|
+
* part et un identifiant réel, retrouvé au carnet quand la venue ne l'a pas rendu à l'envoi (0.58.0,
|
|
1588
|
+
* cf. `ordresDuTrade`). L'appelant la garde avec son trade : annuler une protection, c'est
|
|
1589
|
+
* {@link cancel} sur son identifiant, quel que soit le rôle.
|
|
1567
1590
|
*
|
|
1568
1591
|
* Chaque venue applique son mécanisme natif — hyperliquid groupe les enfants sous l'entrée et les
|
|
1569
1592
|
* annule lui-même si elle rate, pacifica les embarque dans l'ordre, aster envoie un lot de
|
|
@@ -1584,7 +1607,27 @@ declare class TradingService {
|
|
|
1584
1607
|
* complète par {@link completeProtection} quand il le constate. Jusqu'en 0.56.0 ces cibles n'étaient
|
|
1585
1608
|
* posées par personne : une position tide à trois paliers sur pacifica partait sans sa dernière.
|
|
1586
1609
|
*/
|
|
1587
|
-
openWithProtection(access: ITradingAccess, input: IEntryWithProtection): Promise<
|
|
1610
|
+
openWithProtection(access: ITradingAccess, input: IEntryWithProtection): Promise<ITradeOrder[]>;
|
|
1611
|
+
/**
|
|
1612
|
+
* LES ORDRES DU TRADE, rangés par rôle — la même liste sur toutes les venues.
|
|
1613
|
+
*
|
|
1614
|
+
* Chaque venue rend ses ordres à sa façon (mesuré sur testnet le 2026-10-01) : hyperliquid en lot `'na'` rend
|
|
1615
|
+
* tous les identifiants, en `normalTpsl` (un seul take-profit) AUCUN pour le stop et la cible (`waitingForFill`,
|
|
1616
|
+
* `waitingForTrigger`) ; pacifica ne rend que l'entrée, le stop et la première cible embarqués naissant au
|
|
1617
|
+
* carnet sans lien (`parent_id: null`) ; aster pose une à une et rend tout.
|
|
1618
|
+
*
|
|
1619
|
+
* On range donc ce qui est revenu : l'entrée est le premier ordre non reduce-only ; le stop et chaque cible
|
|
1620
|
+
* sont reconnus par leur TYPE et leur PRIX DE DÉCLENCHEMENT — ceux qu'XGate vient de calculer, arrondis à la
|
|
1621
|
+
* grille, donc ceux que la venue a posés. Ce qui manque est cherché au CARNET de la paire, par la même
|
|
1622
|
+
* reconnaissance — le procédé que le SDK pacifica applique déjà à ses take-profits (`placeTakeProfit`).
|
|
1623
|
+
*
|
|
1624
|
+
* Un ordre introuvable garde un identifiant VIDE : refusé, ou déjà consommé (un stop touché dans la seconde,
|
|
1625
|
+
* DOT le 2026-10-01). **Mais une position ouverte dont le stop est introuvable lève** : c'est la position
|
|
1626
|
+
* nue que ce service existe pour empêcher, et l'appelant doit le savoir tout de suite.
|
|
1627
|
+
*/
|
|
1628
|
+
private ordresDuTrade;
|
|
1629
|
+
/** Un ordre du trade que la venue n'a pas posé, ou qui n'existe déjà plus — identifiant VIDE. */
|
|
1630
|
+
private ordreAbsent;
|
|
1588
1631
|
/**
|
|
1589
1632
|
* POSE LES CIBLES QUE LA VENUE N'A PAS EMBARQUÉES, une fois l'entrée remplie.
|
|
1590
1633
|
*
|
|
@@ -1960,4 +2003,4 @@ declare function expiryOf(xtras?: Record<string, unknown>): Date | undefined;
|
|
|
1960
2003
|
*/
|
|
1961
2004
|
declare function isDated(xtras?: Record<string, unknown>): boolean;
|
|
1962
2005
|
|
|
1963
|
-
export { type AssetClass, CANDLES_MAX_HISTORY, CANDLES_PER_CALL, CandlesService, CandlesStreamRegistry, CandlesStreamService, CatalogService, type Direction, type IAccountState, type IBalance, type ICandle, type ICandlesQuery, type IEntryWithProtection, type IEquityPoint, type IFundingPaid, type IMoveStop, type IMovement, type IOrder, type IPair, type IPosition, type IPrice, type IProtection, type IProtectionInput, type IProtectionLeg, type IPublicTrade, type ITarget, type ITrade, type ITradingAccess, type IWalletAccess, type IXexAccess, type IXexSpotSource, type MarketKind, type MovementKind, type MovementStatus, ORDER_STATUSES, type OrderStatus, type OrderType, PricesService, REST_THROTTLE_MS, SPOT_XEXES, type Side, SpotCandlesService, SpotCatalogService, SpotPricesService, SpotWsCandlesService, TIMEFRAME_MINUTES, type TimeInForce, Timeframe, TradingService, type Unsubscribe, WALLET_XEXES, WS_SUBSCRIPTION_LIMITS, WalletService, WsCandlesService, WsTradesService, XGATE_EXCHANGES, XgateEx, XgateModule, assetClassOf, buildLevels, buildProtection, candlesMaxHistoryOf, candlesPerCallOf, canonicalFromBase, canonicalFromXex, expiryOf, isDated, multiplierFromXex, restThrottleOf, roundPrice, roundToStep, servesNatively, servesSpot, sourceFor, subscriptionLimitOf, timeframeMs };
|
|
2006
|
+
export { type AssetClass, CANDLES_MAX_HISTORY, CANDLES_PER_CALL, CandlesService, CandlesStreamRegistry, CandlesStreamService, CatalogService, type Direction, type IAccountState, type IBalance, type ICandle, type ICandlesQuery, type IEntryWithProtection, type IEquityPoint, type IFundingPaid, type IMoveStop, type IMovement, type IOrder, type IPair, type IPosition, type IPrice, type IProtection, type IProtectionInput, type IProtectionLeg, type IPublicTrade, type ITarget, type ITrade, type ITradeOrder, type ITradingAccess, type IWalletAccess, type IXexAccess, type IXexSpotSource, type MarketKind, type MovementKind, type MovementStatus, ORDER_STATUSES, type OrderStatus, type OrderType, PricesService, REST_THROTTLE_MS, SPOT_XEXES, type Side, SpotCandlesService, SpotCatalogService, SpotPricesService, SpotWsCandlesService, TIMEFRAME_MINUTES, type TimeInForce, Timeframe, type TradeOrderRole, TradingService, type Unsubscribe, WALLET_XEXES, WS_SUBSCRIPTION_LIMITS, WalletService, WsCandlesService, WsTradesService, XGATE_EXCHANGES, XgateEx, XgateModule, assetClassOf, buildLevels, buildProtection, candlesMaxHistoryOf, candlesPerCallOf, canonicalFromBase, canonicalFromXex, expiryOf, isDated, multiplierFromXex, restThrottleOf, roundPrice, roundToStep, servesNatively, servesSpot, sourceFor, subscriptionLimitOf, timeframeMs };
|
package/dist/index.d.ts
CHANGED
|
@@ -1323,6 +1323,8 @@ interface IOrder {
|
|
|
1323
1323
|
type: OrderType;
|
|
1324
1324
|
/** `null` pour un ordre au marché. */
|
|
1325
1325
|
price: string | null;
|
|
1326
|
+
/** Prix de DÉCLENCHEMENT d'un ordre conditionnel (stop, take-profit) ; `null` pour un ordre ordinaire. */
|
|
1327
|
+
triggerPrice: string | null;
|
|
1326
1328
|
/** Taille demandée, **en unités de base**. */
|
|
1327
1329
|
size: string;
|
|
1328
1330
|
/** Taille déjà exécutée, **en unités de base**. */
|
|
@@ -1335,6 +1337,24 @@ interface IOrder {
|
|
|
1335
1337
|
placedAt: Date;
|
|
1336
1338
|
xtras?: Record<string, unknown>;
|
|
1337
1339
|
}
|
|
1340
|
+
/** Le rôle d'un ordre dans un trade : l'entrée, le stop, ou un take-profit. */
|
|
1341
|
+
type TradeOrderRole = 'entry' | 'sl' | 'tp';
|
|
1342
|
+
/**
|
|
1343
|
+
* UN ORDRE DU TRADE — ce que {@link TradingService.openWithProtection} rend, une ligne par ordre posé.
|
|
1344
|
+
*
|
|
1345
|
+
* La même forme sur toutes les venues : l'appelant garde cette liste avec son trade et la gère sans savoir
|
|
1346
|
+
* comment chaque venue a posé ses protections (hyperliquid en lot, aster une à une, pacifica embarquées dans
|
|
1347
|
+
* l'entrée). C'est XGate qui fait le pont.
|
|
1348
|
+
*
|
|
1349
|
+
* **L'identifiant n'est vide que si l'ordre n'existe pas ou plus** — refusé, ou déjà consommé (un stop touché
|
|
1350
|
+
* dans la seconde) : `status` dit lequel. Une venue qui ne rend pas l'identifiant d'une protection à l'envoi
|
|
1351
|
+
* (hyperliquid `normalTpsl`, pacifica embarqué) le voit retrouvé au carnet par XGate.
|
|
1352
|
+
*/
|
|
1353
|
+
interface ITradeOrder extends IOrder {
|
|
1354
|
+
role: TradeOrderRole;
|
|
1355
|
+
/** La fraction de la position initiale que l'ordre couvre : 1 pour l'entrée et le stop. */
|
|
1356
|
+
part: number;
|
|
1357
|
+
}
|
|
1338
1358
|
/**
|
|
1339
1359
|
* UNE POSITION ouverte.
|
|
1340
1360
|
*
|
|
@@ -1562,8 +1582,11 @@ declare class TradingService {
|
|
|
1562
1582
|
/**
|
|
1563
1583
|
* OUVRE UNE POSITION AVEC SA PROTECTION, en un geste atomique.
|
|
1564
1584
|
*
|
|
1565
|
-
*
|
|
1566
|
-
* l'ordre
|
|
1585
|
+
* **Ce qui revient est la liste des ORDRES DU TRADE** ({@link ITradeOrder}), la même sur toutes les
|
|
1586
|
+
* venues : l'entrée, le stop, puis chaque take-profit dans l'ordre du plan — chacun avec son rôle, sa
|
|
1587
|
+
* part et un identifiant réel, retrouvé au carnet quand la venue ne l'a pas rendu à l'envoi (0.58.0,
|
|
1588
|
+
* cf. `ordresDuTrade`). L'appelant la garde avec son trade : annuler une protection, c'est
|
|
1589
|
+
* {@link cancel} sur son identifiant, quel que soit le rôle.
|
|
1567
1590
|
*
|
|
1568
1591
|
* Chaque venue applique son mécanisme natif — hyperliquid groupe les enfants sous l'entrée et les
|
|
1569
1592
|
* annule lui-même si elle rate, pacifica les embarque dans l'ordre, aster envoie un lot de
|
|
@@ -1584,7 +1607,27 @@ declare class TradingService {
|
|
|
1584
1607
|
* complète par {@link completeProtection} quand il le constate. Jusqu'en 0.56.0 ces cibles n'étaient
|
|
1585
1608
|
* posées par personne : une position tide à trois paliers sur pacifica partait sans sa dernière.
|
|
1586
1609
|
*/
|
|
1587
|
-
openWithProtection(access: ITradingAccess, input: IEntryWithProtection): Promise<
|
|
1610
|
+
openWithProtection(access: ITradingAccess, input: IEntryWithProtection): Promise<ITradeOrder[]>;
|
|
1611
|
+
/**
|
|
1612
|
+
* LES ORDRES DU TRADE, rangés par rôle — la même liste sur toutes les venues.
|
|
1613
|
+
*
|
|
1614
|
+
* Chaque venue rend ses ordres à sa façon (mesuré sur testnet le 2026-10-01) : hyperliquid en lot `'na'` rend
|
|
1615
|
+
* tous les identifiants, en `normalTpsl` (un seul take-profit) AUCUN pour le stop et la cible (`waitingForFill`,
|
|
1616
|
+
* `waitingForTrigger`) ; pacifica ne rend que l'entrée, le stop et la première cible embarqués naissant au
|
|
1617
|
+
* carnet sans lien (`parent_id: null`) ; aster pose une à une et rend tout.
|
|
1618
|
+
*
|
|
1619
|
+
* On range donc ce qui est revenu : l'entrée est le premier ordre non reduce-only ; le stop et chaque cible
|
|
1620
|
+
* sont reconnus par leur TYPE et leur PRIX DE DÉCLENCHEMENT — ceux qu'XGate vient de calculer, arrondis à la
|
|
1621
|
+
* grille, donc ceux que la venue a posés. Ce qui manque est cherché au CARNET de la paire, par la même
|
|
1622
|
+
* reconnaissance — le procédé que le SDK pacifica applique déjà à ses take-profits (`placeTakeProfit`).
|
|
1623
|
+
*
|
|
1624
|
+
* Un ordre introuvable garde un identifiant VIDE : refusé, ou déjà consommé (un stop touché dans la seconde,
|
|
1625
|
+
* DOT le 2026-10-01). **Mais une position ouverte dont le stop est introuvable lève** : c'est la position
|
|
1626
|
+
* nue que ce service existe pour empêcher, et l'appelant doit le savoir tout de suite.
|
|
1627
|
+
*/
|
|
1628
|
+
private ordresDuTrade;
|
|
1629
|
+
/** Un ordre du trade que la venue n'a pas posé, ou qui n'existe déjà plus — identifiant VIDE. */
|
|
1630
|
+
private ordreAbsent;
|
|
1588
1631
|
/**
|
|
1589
1632
|
* POSE LES CIBLES QUE LA VENUE N'A PAS EMBARQUÉES, une fois l'entrée remplie.
|
|
1590
1633
|
*
|
|
@@ -1960,4 +2003,4 @@ declare function expiryOf(xtras?: Record<string, unknown>): Date | undefined;
|
|
|
1960
2003
|
*/
|
|
1961
2004
|
declare function isDated(xtras?: Record<string, unknown>): boolean;
|
|
1962
2005
|
|
|
1963
|
-
export { type AssetClass, CANDLES_MAX_HISTORY, CANDLES_PER_CALL, CandlesService, CandlesStreamRegistry, CandlesStreamService, CatalogService, type Direction, type IAccountState, type IBalance, type ICandle, type ICandlesQuery, type IEntryWithProtection, type IEquityPoint, type IFundingPaid, type IMoveStop, type IMovement, type IOrder, type IPair, type IPosition, type IPrice, type IProtection, type IProtectionInput, type IProtectionLeg, type IPublicTrade, type ITarget, type ITrade, type ITradingAccess, type IWalletAccess, type IXexAccess, type IXexSpotSource, type MarketKind, type MovementKind, type MovementStatus, ORDER_STATUSES, type OrderStatus, type OrderType, PricesService, REST_THROTTLE_MS, SPOT_XEXES, type Side, SpotCandlesService, SpotCatalogService, SpotPricesService, SpotWsCandlesService, TIMEFRAME_MINUTES, type TimeInForce, Timeframe, TradingService, type Unsubscribe, WALLET_XEXES, WS_SUBSCRIPTION_LIMITS, WalletService, WsCandlesService, WsTradesService, XGATE_EXCHANGES, XgateEx, XgateModule, assetClassOf, buildLevels, buildProtection, candlesMaxHistoryOf, candlesPerCallOf, canonicalFromBase, canonicalFromXex, expiryOf, isDated, multiplierFromXex, restThrottleOf, roundPrice, roundToStep, servesNatively, servesSpot, sourceFor, subscriptionLimitOf, timeframeMs };
|
|
2006
|
+
export { type AssetClass, CANDLES_MAX_HISTORY, CANDLES_PER_CALL, CandlesService, CandlesStreamRegistry, CandlesStreamService, CatalogService, type Direction, type IAccountState, type IBalance, type ICandle, type ICandlesQuery, type IEntryWithProtection, type IEquityPoint, type IFundingPaid, type IMoveStop, type IMovement, type IOrder, type IPair, type IPosition, type IPrice, type IProtection, type IProtectionInput, type IProtectionLeg, type IPublicTrade, type ITarget, type ITrade, type ITradeOrder, type ITradingAccess, type IWalletAccess, type IXexAccess, type IXexSpotSource, type MarketKind, type MovementKind, type MovementStatus, ORDER_STATUSES, type OrderStatus, type OrderType, PricesService, REST_THROTTLE_MS, SPOT_XEXES, type Side, SpotCandlesService, SpotCatalogService, SpotPricesService, SpotWsCandlesService, TIMEFRAME_MINUTES, type TimeInForce, Timeframe, type TradeOrderRole, TradingService, type Unsubscribe, WALLET_XEXES, WS_SUBSCRIPTION_LIMITS, WalletService, WsCandlesService, WsTradesService, XGATE_EXCHANGES, XgateEx, XgateModule, assetClassOf, buildLevels, buildProtection, candlesMaxHistoryOf, candlesPerCallOf, canonicalFromBase, canonicalFromXex, expiryOf, isDated, multiplierFromXex, restThrottleOf, roundPrice, roundToStep, servesNatively, servesSpot, sourceFor, subscriptionLimitOf, timeframeMs };
|
package/dist/index.js
CHANGED
|
@@ -1250,8 +1250,11 @@ var TradingService = class {
|
|
|
1250
1250
|
/**
|
|
1251
1251
|
* OUVRE UNE POSITION AVEC SA PROTECTION, en un geste atomique.
|
|
1252
1252
|
*
|
|
1253
|
-
*
|
|
1254
|
-
* l'ordre
|
|
1253
|
+
* **Ce qui revient est la liste des ORDRES DU TRADE** ({@link ITradeOrder}), la même sur toutes les
|
|
1254
|
+
* venues : l'entrée, le stop, puis chaque take-profit dans l'ordre du plan — chacun avec son rôle, sa
|
|
1255
|
+
* part et un identifiant réel, retrouvé au carnet quand la venue ne l'a pas rendu à l'envoi (0.58.0,
|
|
1256
|
+
* cf. `ordresDuTrade`). L'appelant la garde avec son trade : annuler une protection, c'est
|
|
1257
|
+
* {@link cancel} sur son identifiant, quel que soit le rôle.
|
|
1255
1258
|
*
|
|
1256
1259
|
* Chaque venue applique son mécanisme natif — hyperliquid groupe les enfants sous l'entrée et les
|
|
1257
1260
|
* annule lui-même si elle rate, pacifica les embarque dans l'ordre, aster envoie un lot de
|
|
@@ -1314,27 +1317,25 @@ var TradingService = class {
|
|
|
1314
1317
|
tps: protection.tps,
|
|
1315
1318
|
clientId: input.clientId
|
|
1316
1319
|
};
|
|
1320
|
+
let posees;
|
|
1317
1321
|
try {
|
|
1318
1322
|
const orders = await perp.createEntryWithProtection(entry, consigne);
|
|
1319
|
-
|
|
1323
|
+
posees = orders.map((order) => this.toOrder(order, access.xex));
|
|
1320
1324
|
const enAttente = this.ciblesEnAttente(perp, consigne);
|
|
1321
|
-
if (enAttente.length ===
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
+
if (enAttente.length > 0 && (tif === "ioc" || tif === "fok")) {
|
|
1326
|
+
const complement = await this.poserCiblesEnAttente(
|
|
1327
|
+
access,
|
|
1328
|
+
perp,
|
|
1329
|
+
input.symbolXex,
|
|
1330
|
+
side,
|
|
1331
|
+
enAttente
|
|
1332
|
+
);
|
|
1333
|
+
posees = [...posees, ...complement];
|
|
1334
|
+
} else if (enAttente.length > 0) {
|
|
1325
1335
|
this.logger.warn(
|
|
1326
1336
|
`openWithProtection(${access.xex}/${input.symbolXex}) : ${enAttente.length} cible(s) que la venue n'embarque pas \u2014 l'entr\xE9e ${tif} peut rester au carnet, appeler completeProtection une fois remplie.`
|
|
1327
1337
|
);
|
|
1328
|
-
return posees;
|
|
1329
1338
|
}
|
|
1330
|
-
const complement = await this.poserCiblesEnAttente(
|
|
1331
|
-
access,
|
|
1332
|
-
perp,
|
|
1333
|
-
input.symbolXex,
|
|
1334
|
-
side,
|
|
1335
|
-
enAttente
|
|
1336
|
-
);
|
|
1337
|
-
return [...posees, ...complement];
|
|
1338
1339
|
} catch (error) {
|
|
1339
1340
|
const message = error instanceof Error ? error.message : String(error);
|
|
1340
1341
|
if (message.includes(ASTER_TIMEOUT) === false) {
|
|
@@ -1343,8 +1344,119 @@ var TradingService = class {
|
|
|
1343
1344
|
this.logger.warn(
|
|
1344
1345
|
`openWithProtection(${access.xex}) : la venue a coup\xE9 avant de r\xE9pondre. Statut inconnu \u2014 relecture de l'\xE9tat r\xE9el.`
|
|
1345
1346
|
);
|
|
1346
|
-
|
|
1347
|
+
posees = await this.etatApres(access, input.symbolXex);
|
|
1347
1348
|
}
|
|
1349
|
+
return await this.ordresDuTrade(access, perp, input, side, protection, posees);
|
|
1350
|
+
}
|
|
1351
|
+
/**
|
|
1352
|
+
* LES ORDRES DU TRADE, rangés par rôle — la même liste sur toutes les venues.
|
|
1353
|
+
*
|
|
1354
|
+
* Chaque venue rend ses ordres à sa façon (mesuré sur testnet le 2026-10-01) : hyperliquid en lot `'na'` rend
|
|
1355
|
+
* tous les identifiants, en `normalTpsl` (un seul take-profit) AUCUN pour le stop et la cible (`waitingForFill`,
|
|
1356
|
+
* `waitingForTrigger`) ; pacifica ne rend que l'entrée, le stop et la première cible embarqués naissant au
|
|
1357
|
+
* carnet sans lien (`parent_id: null`) ; aster pose une à une et rend tout.
|
|
1358
|
+
*
|
|
1359
|
+
* On range donc ce qui est revenu : l'entrée est le premier ordre non reduce-only ; le stop et chaque cible
|
|
1360
|
+
* sont reconnus par leur TYPE et leur PRIX DE DÉCLENCHEMENT — ceux qu'XGate vient de calculer, arrondis à la
|
|
1361
|
+
* grille, donc ceux que la venue a posés. Ce qui manque est cherché au CARNET de la paire, par la même
|
|
1362
|
+
* reconnaissance — le procédé que le SDK pacifica applique déjà à ses take-profits (`placeTakeProfit`).
|
|
1363
|
+
*
|
|
1364
|
+
* Un ordre introuvable garde un identifiant VIDE : refusé, ou déjà consommé (un stop touché dans la seconde,
|
|
1365
|
+
* DOT le 2026-10-01). **Mais une position ouverte dont le stop est introuvable lève** : c'est la position
|
|
1366
|
+
* nue que ce service existe pour empêcher, et l'appelant doit le savoir tout de suite.
|
|
1367
|
+
*/
|
|
1368
|
+
async ordresDuTrade(access, perp, input, side, protection, posees) {
|
|
1369
|
+
const exit = side === "buy" ? "sell" : "buy";
|
|
1370
|
+
const part = (size) => Number(size) / input.size;
|
|
1371
|
+
const entree = posees.find((order) => order.reduceOnly !== true) ?? null;
|
|
1372
|
+
const rejetee = entree !== null && entree.status === "rejected";
|
|
1373
|
+
const pris = /* @__PURE__ */ new Set();
|
|
1374
|
+
const attendus = [
|
|
1375
|
+
{ role: "sl", leg: protection.sl },
|
|
1376
|
+
...protection.tps.map((leg) => ({ role: "tp", leg }))
|
|
1377
|
+
];
|
|
1378
|
+
const reconnaitre = (pool, role, leg) => pool.find(
|
|
1379
|
+
(order) => order.id !== "" && pris.has(order.id) === false && estDuRole(order.type, role) === true && (order.triggerPrice === null || memePrix(order.triggerPrice, leg.triggerPrice) === true)
|
|
1380
|
+
);
|
|
1381
|
+
let carnet = null;
|
|
1382
|
+
const lireCarnet = async () => {
|
|
1383
|
+
if (carnet === null) {
|
|
1384
|
+
carnet = (await perp.getOpens()).map((order) => this.toOrder(order, access.xex)).filter((order) => order.symbolXex === input.symbolXex && order.reduceOnly === true);
|
|
1385
|
+
}
|
|
1386
|
+
return carnet;
|
|
1387
|
+
};
|
|
1388
|
+
const ordres = [
|
|
1389
|
+
entree === null ? this.ordreAbsent(
|
|
1390
|
+
access,
|
|
1391
|
+
input,
|
|
1392
|
+
"entry",
|
|
1393
|
+
side,
|
|
1394
|
+
"limit",
|
|
1395
|
+
1,
|
|
1396
|
+
null,
|
|
1397
|
+
String(input.size),
|
|
1398
|
+
"other"
|
|
1399
|
+
) : { ...entree, role: "entry", part: 1 }
|
|
1400
|
+
];
|
|
1401
|
+
for (const { role, leg } of attendus) {
|
|
1402
|
+
let trouve = reconnaitre(posees, role, leg);
|
|
1403
|
+
if (trouve === void 0 && rejetee === false) {
|
|
1404
|
+
trouve = reconnaitre(await lireCarnet(), role, leg);
|
|
1405
|
+
}
|
|
1406
|
+
if (trouve !== void 0) {
|
|
1407
|
+
pris.add(trouve.id);
|
|
1408
|
+
ordres.push({ ...trouve, role, part: part(leg.size) });
|
|
1409
|
+
} else {
|
|
1410
|
+
ordres.push(
|
|
1411
|
+
this.ordreAbsent(
|
|
1412
|
+
access,
|
|
1413
|
+
input,
|
|
1414
|
+
role,
|
|
1415
|
+
exit,
|
|
1416
|
+
role === "sl" ? "stopMarket" : "takeProfitMarket",
|
|
1417
|
+
part(leg.size),
|
|
1418
|
+
leg.triggerPrice,
|
|
1419
|
+
leg.size,
|
|
1420
|
+
rejetee === true ? "canceled" : "other"
|
|
1421
|
+
)
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
const stop = ordres.find((order) => order.role === "sl");
|
|
1426
|
+
if (rejetee === false && stop !== void 0 && stop.id === "") {
|
|
1427
|
+
const positions = await perp.getPositions({ name: input.symbolXex });
|
|
1428
|
+
const ouverte = positions.find(
|
|
1429
|
+
(candidate) => candidate.name === input.symbolXex && Number(candidate.size) !== 0
|
|
1430
|
+
);
|
|
1431
|
+
if (ouverte !== void 0) {
|
|
1432
|
+
throw new Error(
|
|
1433
|
+
`openWithProtection(${access.xex}/${input.symbolXex}) : POSITION NUE \u2014 ${ouverte.size} ouvert, stop introuvable au carnet. \xC0 prot\xE9ger imm\xE9diatement.`
|
|
1434
|
+
);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
return ordres;
|
|
1438
|
+
}
|
|
1439
|
+
/** Un ordre du trade que la venue n'a pas posé, ou qui n'existe déjà plus — identifiant VIDE. */
|
|
1440
|
+
ordreAbsent(access, input, role, side, type, part, triggerPrice, size, status) {
|
|
1441
|
+
return {
|
|
1442
|
+
xex: access.xex,
|
|
1443
|
+
symbolXex: input.symbolXex,
|
|
1444
|
+
kind: "perp",
|
|
1445
|
+
id: "",
|
|
1446
|
+
clientId: null,
|
|
1447
|
+
side,
|
|
1448
|
+
type,
|
|
1449
|
+
price: null,
|
|
1450
|
+
triggerPrice,
|
|
1451
|
+
size,
|
|
1452
|
+
filled: "0",
|
|
1453
|
+
status,
|
|
1454
|
+
tif: null,
|
|
1455
|
+
reduceOnly: role !== "entry",
|
|
1456
|
+
placedAt: /* @__PURE__ */ new Date(),
|
|
1457
|
+
role,
|
|
1458
|
+
part
|
|
1459
|
+
};
|
|
1348
1460
|
}
|
|
1349
1461
|
/**
|
|
1350
1462
|
* POSE LES CIBLES QUE LA VENUE N'A PAS EMBARQUÉES, une fois l'entrée remplie.
|
|
@@ -1870,6 +1982,7 @@ var TradingService = class {
|
|
|
1870
1982
|
side: order.side,
|
|
1871
1983
|
type: order.type,
|
|
1872
1984
|
price: order.price,
|
|
1985
|
+
triggerPrice: order.triggerPrice,
|
|
1873
1986
|
size: order.size,
|
|
1874
1987
|
filled: order.filled,
|
|
1875
1988
|
status: this.toStatus(order.status),
|
|
@@ -1883,6 +1996,14 @@ var TradingService = class {
|
|
|
1883
1996
|
TradingService = __decorateClass([
|
|
1884
1997
|
Injectable()
|
|
1885
1998
|
], TradingService);
|
|
1999
|
+
function estDuRole(type, role) {
|
|
2000
|
+
return role === "sl" ? type === "stop" || type === "stopMarket" : type === "takeProfit" || type === "takeProfitMarket";
|
|
2001
|
+
}
|
|
2002
|
+
function memePrix(lu, pose) {
|
|
2003
|
+
const a = Number(lu);
|
|
2004
|
+
const b = Number(pose);
|
|
2005
|
+
return Math.abs(a - b) <= 1e-9 * Math.max(1, Math.abs(b));
|
|
2006
|
+
}
|
|
1886
2007
|
function toXexDate(date) {
|
|
1887
2008
|
return date.toISOString().slice(0, 19).replace("T", " ");
|
|
1888
2009
|
}
|
|
@@ -2261,6 +2382,7 @@ var WsTradesService = class {
|
|
|
2261
2382
|
side: order.side,
|
|
2262
2383
|
type: order.type,
|
|
2263
2384
|
price: order.price,
|
|
2385
|
+
triggerPrice: order.triggerPrice,
|
|
2264
2386
|
size: order.size,
|
|
2265
2387
|
filled: order.filled,
|
|
2266
2388
|
status: ORDER_STATUSES.includes(order.status) ? order.status : "other",
|