dipcoin-cli 1.3.5 → 1.3.6
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 +4 -0
- package/dist/cli.cjs +96 -6
- package/dist/cli.cjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -181,6 +181,10 @@ dipcoin-cli position tpsl <symbol> --side <buy|sell> --quantity <q> --leverage <
|
|
|
181
181
|
dipcoin-cli position tpsl <symbol> --side sell --quantity 0.01 --leverage 10 \
|
|
182
182
|
--tp-trigger 105000 --tp-type limit --tp-price 105000
|
|
183
183
|
|
|
184
|
+
# Set or edit TP/SL on a vault position. Existing plan IDs are discovered automatically.
|
|
185
|
+
dipcoin-cli position tpsl BTC --side sell --quantity 0.01 --leverage 10 \
|
|
186
|
+
--vault <vaultId> --tp-trigger 105000 --sl-trigger 90000
|
|
187
|
+
|
|
184
188
|
# Close positions — CLI figures out side & qty
|
|
185
189
|
dipcoin-cli position close BTC # close 100% of BTC position
|
|
186
190
|
dipcoin-cli position close BTC --percent 50 # close half
|
package/dist/cli.cjs
CHANGED
|
@@ -17700,7 +17700,8 @@ class DipCoinPerpSDK {
|
|
|
17700
17700
|
}
|
|
17701
17701
|
// Use sub-account keypair for signing if available
|
|
17702
17702
|
const signingKeypair = this.subKeypair || this.keypair;
|
|
17703
|
-
const { symbol, market, side, isLong, leverage, quantity, reduceOnly = true, postOnly = false, orderbookOnly = true, ioc = false, tp, sl, } = params;
|
|
17703
|
+
const { symbol, market, creator, side, isLong, leverage, quantity, reduceOnly = true, postOnly = false, orderbookOnly = true, ioc = false, tp, sl, } = params;
|
|
17704
|
+
const orderCreator = creator || this.walletAddress;
|
|
17704
17705
|
if (!this.isPositiveNumber(quantity)) {
|
|
17705
17706
|
return {
|
|
17706
17707
|
status: false,
|
|
@@ -17724,7 +17725,7 @@ class DipCoinPerpSDK {
|
|
|
17724
17725
|
symbol,
|
|
17725
17726
|
side,
|
|
17726
17727
|
leverage: leverageWei,
|
|
17727
|
-
creator:
|
|
17728
|
+
creator: orderCreator,
|
|
17728
17729
|
};
|
|
17729
17730
|
const sendPlanCloseRequest = async (payload) => {
|
|
17730
17731
|
let response = await this.httpClient.post(API_ENDPOINTS.PLAN_CLOSE_ORDER, payload);
|
|
@@ -17754,7 +17755,7 @@ class DipCoinPerpSDK {
|
|
|
17754
17755
|
: new BigNumber__default["default"](0);
|
|
17755
17756
|
const tpOrder = {
|
|
17756
17757
|
market,
|
|
17757
|
-
creator:
|
|
17758
|
+
creator: orderCreator,
|
|
17758
17759
|
isLong: !isLong,
|
|
17759
17760
|
reduceOnly,
|
|
17760
17761
|
postOnly,
|
|
@@ -17799,7 +17800,7 @@ class DipCoinPerpSDK {
|
|
|
17799
17800
|
: new BigNumber__default["default"](0);
|
|
17800
17801
|
const slOrder = {
|
|
17801
17802
|
market,
|
|
17802
|
-
creator:
|
|
17803
|
+
creator: orderCreator,
|
|
17803
17804
|
isLong: !isLong,
|
|
17804
17805
|
reduceOnly,
|
|
17805
17806
|
postOnly,
|
|
@@ -17871,7 +17872,7 @@ class DipCoinPerpSDK {
|
|
|
17871
17872
|
/**
|
|
17872
17873
|
* Get TP/SL orders for a position
|
|
17873
17874
|
*/
|
|
17874
|
-
async getPositionTpSl(positionId, tpslType = "normal") {
|
|
17875
|
+
async getPositionTpSl(positionId, tpslType = "normal", parentAddress) {
|
|
17875
17876
|
try {
|
|
17876
17877
|
const authResult = await this.authenticate();
|
|
17877
17878
|
if (!authResult.status) {
|
|
@@ -17883,6 +17884,7 @@ class DipCoinPerpSDK {
|
|
|
17883
17884
|
const params = {
|
|
17884
17885
|
positionId,
|
|
17885
17886
|
tpslType,
|
|
17887
|
+
...(parentAddress ? { parentAddress } : {}),
|
|
17886
17888
|
};
|
|
17887
17889
|
let response = await this.httpClient.get(API_ENDPOINTS.GET_POSITION_TPSL, { params });
|
|
17888
17890
|
if (response.code === 1000) {
|
|
@@ -20740,6 +20742,9 @@ function registerPositionCommands(program) {
|
|
|
20740
20742
|
.option("--sl-trigger <price>", "SL trigger price")
|
|
20741
20743
|
.option("--sl-type <type>", "SL order type: market or limit", "market")
|
|
20742
20744
|
.option("--sl-price <price>", "SL order price (for limit)")
|
|
20745
|
+
.option("--vault <address>", "Target a vault position (vault object ID)")
|
|
20746
|
+
.option("--tp-plan-id <id>", "Existing TP plan ID to edit")
|
|
20747
|
+
.option("--sl-plan-id <id>", "Existing SL plan ID to edit")
|
|
20743
20748
|
.action(async (symbol, opts) => {
|
|
20744
20749
|
try {
|
|
20745
20750
|
const sdk = getSDK();
|
|
@@ -20747,11 +20752,94 @@ function registerPositionCommands(program) {
|
|
|
20747
20752
|
const perpId = await sdk.getPerpetualID(symbol);
|
|
20748
20753
|
if (!perpId)
|
|
20749
20754
|
return handleError(`PerpetualID not found for ${symbol}`);
|
|
20750
|
-
const
|
|
20755
|
+
const sideInput = String(opts.side).toUpperCase();
|
|
20756
|
+
if (sideInput !== OrderSide.BUY && sideInput !== OrderSide.SELL) {
|
|
20757
|
+
return handleError(`--side must be buy or sell, got ${opts.side}`);
|
|
20758
|
+
}
|
|
20759
|
+
const side = sideInput;
|
|
20751
20760
|
const isLong = side === OrderSide.SELL;
|
|
20761
|
+
if (!opts.tpTrigger && !opts.slTrigger) {
|
|
20762
|
+
return handleError("At least one of --tp-trigger or --sl-trigger is required.");
|
|
20763
|
+
}
|
|
20764
|
+
if (opts.tpPlanId && !opts.tpTrigger) {
|
|
20765
|
+
return handleError("--tp-plan-id requires --tp-trigger.");
|
|
20766
|
+
}
|
|
20767
|
+
if (opts.slPlanId && !opts.slTrigger) {
|
|
20768
|
+
return handleError("--sl-plan-id requires --sl-trigger.");
|
|
20769
|
+
}
|
|
20770
|
+
let tpPlanId = opts.tpPlanId;
|
|
20771
|
+
let slPlanId = opts.slPlanId;
|
|
20772
|
+
const shouldFindTpPlan = Boolean(opts.tpTrigger && !tpPlanId);
|
|
20773
|
+
const shouldFindSlPlan = Boolean(opts.slTrigger && !slPlanId);
|
|
20774
|
+
const parentAddress = opts.vault || sdk.address;
|
|
20775
|
+
const positionsResult = await sdk.getPositions({ parentAddress, symbol });
|
|
20776
|
+
if (!positionsResult.status) {
|
|
20777
|
+
return handleError(positionsResult.error || "Failed to fetch position");
|
|
20778
|
+
}
|
|
20779
|
+
const matchingPositions = (positionsResult.data || []).filter((position) => position.symbol === symbol);
|
|
20780
|
+
if (matchingPositions.length !== 1) {
|
|
20781
|
+
return handleError(matchingPositions.length === 0
|
|
20782
|
+
? `No open position for ${symbol}.`
|
|
20783
|
+
: `Multiple positions found for ${symbol}; cannot choose one safely.`);
|
|
20784
|
+
}
|
|
20785
|
+
const activePosition = matchingPositions[0];
|
|
20786
|
+
const positionSide = String(activePosition.side).toUpperCase();
|
|
20787
|
+
const expectedClosingSide = positionSide === "BUY" || positionSide === "LONG"
|
|
20788
|
+
? OrderSide.SELL
|
|
20789
|
+
: positionSide === "SELL" || positionSide === "SHORT"
|
|
20790
|
+
? OrderSide.BUY
|
|
20791
|
+
: undefined;
|
|
20792
|
+
if (!expectedClosingSide) {
|
|
20793
|
+
return handleError(`Unsupported position side: ${activePosition.side}`);
|
|
20794
|
+
}
|
|
20795
|
+
if (side !== expectedClosingSide) {
|
|
20796
|
+
return handleError(`--side must be ${expectedClosingSide.toLowerCase()} to close a ${positionSide} position.`);
|
|
20797
|
+
}
|
|
20798
|
+
const requestedQuantity = new BigNumber__default["default"](opts.quantity);
|
|
20799
|
+
const positionQuantity = new BigNumber__default["default"](activePosition.quantity).shiftedBy(-18);
|
|
20800
|
+
if (!requestedQuantity.isFinite() ||
|
|
20801
|
+
requestedQuantity.lte(0) ||
|
|
20802
|
+
requestedQuantity.gt(positionQuantity)) {
|
|
20803
|
+
return handleError(`--quantity must be greater than 0 and no more than the position quantity (${positionQuantity.toFixed()}).`);
|
|
20804
|
+
}
|
|
20805
|
+
const requestedLeverage = new BigNumber__default["default"](opts.leverage);
|
|
20806
|
+
const positionLeverage = new BigNumber__default["default"](activePosition.leverage).shiftedBy(-18);
|
|
20807
|
+
if (!requestedLeverage.isFinite() || !requestedLeverage.eq(positionLeverage)) {
|
|
20808
|
+
return handleError(`--leverage must match the position leverage (${positionLeverage.toFixed()}).`);
|
|
20809
|
+
}
|
|
20810
|
+
// Editing a plan requires its existing ID. Resolve it automatically for the
|
|
20811
|
+
// position-wide TP/SL pair so repeating this command updates instead of duplicates.
|
|
20812
|
+
if (shouldFindTpPlan || shouldFindSlPlan) {
|
|
20813
|
+
const positionId = activePosition.id ?? activePosition.positionId;
|
|
20814
|
+
if (positionId === undefined || positionId === null) {
|
|
20815
|
+
return handleError(`Position ID missing for ${symbol}.`);
|
|
20816
|
+
}
|
|
20817
|
+
const plansResult = await sdk.getPositionTpSl(positionId, "position", opts.vault);
|
|
20818
|
+
if (!plansResult.status) {
|
|
20819
|
+
return handleError(plansResult.error || "Failed to fetch existing TP/SL orders");
|
|
20820
|
+
}
|
|
20821
|
+
const findExistingPlanId = (planOrderType) => {
|
|
20822
|
+
const matches = (plansResult.data || []).filter((order) => String(order.planOrderType).toLowerCase() === planOrderType.toLowerCase());
|
|
20823
|
+
if (matches.length > 1) {
|
|
20824
|
+
throw new Error(`Multiple ${planOrderType} plans found; use --${planOrderType === "takeProfit" ? "tp" : "sl"}-plan-id to choose one.`);
|
|
20825
|
+
}
|
|
20826
|
+
if (!matches.length)
|
|
20827
|
+
return undefined;
|
|
20828
|
+
const planId = planOrderType === "takeProfit" ? matches[0].tpPlanId : matches[0].slPlanId;
|
|
20829
|
+
if (planId === undefined || planId === null) {
|
|
20830
|
+
throw new Error(`${planOrderType} plan is missing its editable plan ID.`);
|
|
20831
|
+
}
|
|
20832
|
+
return planId;
|
|
20833
|
+
};
|
|
20834
|
+
if (shouldFindTpPlan)
|
|
20835
|
+
tpPlanId = findExistingPlanId("takeProfit");
|
|
20836
|
+
if (shouldFindSlPlan)
|
|
20837
|
+
slPlanId = findExistingPlanId("stopLoss");
|
|
20838
|
+
}
|
|
20752
20839
|
const params = {
|
|
20753
20840
|
symbol,
|
|
20754
20841
|
market: perpId,
|
|
20842
|
+
...(opts.vault ? { creator: opts.vault } : {}),
|
|
20755
20843
|
side,
|
|
20756
20844
|
isLong,
|
|
20757
20845
|
quantity: opts.quantity,
|
|
@@ -20762,6 +20850,7 @@ function registerPositionCommands(program) {
|
|
|
20762
20850
|
triggerPrice: opts.tpTrigger,
|
|
20763
20851
|
orderType: opts.tpType?.toUpperCase() === "LIMIT" ? OrderType.LIMIT : OrderType.MARKET,
|
|
20764
20852
|
...(opts.tpPrice ? { orderPrice: opts.tpPrice } : {}),
|
|
20853
|
+
...(tpPlanId !== undefined ? { planId: tpPlanId } : {}),
|
|
20765
20854
|
tpslType: "position",
|
|
20766
20855
|
};
|
|
20767
20856
|
}
|
|
@@ -20770,6 +20859,7 @@ function registerPositionCommands(program) {
|
|
|
20770
20859
|
triggerPrice: opts.slTrigger,
|
|
20771
20860
|
orderType: opts.slType?.toUpperCase() === "LIMIT" ? OrderType.LIMIT : OrderType.MARKET,
|
|
20772
20861
|
...(opts.slPrice ? { orderPrice: opts.slPrice } : {}),
|
|
20862
|
+
...(slPlanId !== undefined ? { planId: slPlanId } : {}),
|
|
20773
20863
|
tpslType: "position",
|
|
20774
20864
|
};
|
|
20775
20865
|
}
|