Instant closes let you immediately close a position by calling the /instant_close endpoint. You must first obtain a SIWE access token via a login flow if you don't have one already, then use that token to call the instant close function.
Instant Trading is only for MARKET orders
Instant Close Flow
Instant close allows you to quickly exit an open position. The process requires:
SIWE Login (if you don't have an access token already)
Fetch a nonce from the solver’s endpoint, build and sign a SIWE (Sign-In with Ethereum) message, and then log in to obtain an access token.
Call the /instant_closeEndpoint:
With the access token, send a POST request that includes:
quote_id: The unique number identifying the quote/position.
quantity_to_close: The amount (as a string) you wish to close.
close_price: The price (as a string) at which you want to close the position.
For market orders, you will need to adjust the close price (i.e. apply slippage) similar to the opening process.
For CLOSE LONG: Decrease the price by your slippage factor.
For CLOSE SHORT: Increase the price by your slippage factor.
The following script shows a full example in Node.js using Axios and ethers.js, closing a LONG XRP position.
Instant Close Script Example
require("dotenv").config();
const { ethers } = require("ethers");
const axios = require("axios");
// --------------------------------------------------------------------
// SIWE / Login Configuration
// --------------------------------------------------------------------
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const activeAccount = process.env.activeAccount; // Your sub-account address
const wallet = new ethers.Wallet(PRIVATE_KEY);
const SOLVER_BASE_URL = "https://www.perps-streaming.com/v1/42161a/0x141269E29a770644C34e05B127AB621511f20109";
const DOMAIN = "localhost";
const ORIGIN = "http://localhost:3000";
const CHAIN_ID = 42161;
const LOGIN_URI = `${SOLVER_BASE_URL}/login`;
const ISSUED_AT = new Date().toISOString();
// Set expiration to 24 hours from now for login
const EXPIRATION_DATE = new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();
// --------------------------------------------------------------------
// Helper Functions
// --------------------------------------------------------------------
// SIWE message builder (EIP-4361 format)
function buildSiweMessage({ domain, address, statement, uri, version, chainId, nonce, issuedAt, expirationTime }) {
return `${domain} wants you to sign in with your Ethereum account:
${address}
${statement}
URI: ${uri}
Version: ${version}
Chain ID: ${chainId}
Nonce: ${nonce}
Issued At: ${issuedAt}
Expiration Time: ${expirationTime}`;
}
// Fetch nonce for SIWE login
async function getNonce(address) {
const url = `${SOLVER_BASE_URL}/nonce/${address}`;
const { data } = await axios.get(url);
return data.nonce;
}
// Fetch the asset price from Muon, convert the returned wei value to a standard decimal string.
async function fetchMuonPriceConverted() {
try {
const MUON_URL = ""; //This is the uPnL_A_WithSymbolPrice Muon API request.
const response = await axios.get(MUON_URL);
const fetchedPriceWei = response.data.result.data.result.price;
if (!fetchedPriceWei) {
throw new Error("Muon price not found in response.");
}
// Convert the wei value to a human-readable decimal (assumes 18 decimals)
const priceDecimal = ethers.formatUnits(fetchedPriceWei, 18);
return priceDecimal;
} catch (error) {
console.error("Error fetching Muon price:", error.response?.data || error.message);
throw error;
}
}
// Call the /instant_close endpoint to close a position.
// The endpoint expects an object with:
// {
// "quote_id": number,
// "quantity_to_close": "string",
// "close_price": "string"
// }
async function closeInstantPosition(token, quote_id, quantity_to_close, close_price) {
const payload = {
quote_id, // Example: 23688
quantity_to_close, // Example: "6.1"
close_price, // Example: "2.3"
};
const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
};
const response = await axios.post(`${SOLVER_BASE_URL}/instant_close`, payload, { headers });
return response.data;
}
// --------------------------------------------------------------------
// Main Flow: SIWE Login then Instant Close Trade
// --------------------------------------------------------------------
(async function main() {
try {
console.log(`\n[1/4] Wallet Address: ${wallet.address}`);
const nonce = await getNonce(activeAccount);
console.log(`[2/4] Got nonce: ${nonce}`);
// Build the SIWE message.
const siweMessage = buildSiweMessage({
domain: DOMAIN,
address: wallet.address,
statement: `msg: ${activeAccount}`,
uri: LOGIN_URI,
version: "1",
chainId: CHAIN_ID,
nonce,
issuedAt: ISSUED_AT,
expirationTime: EXPIRATION_DATE,
});
console.log("\n[3/4] SIWE message to sign:\n", siweMessage);
// Sign the SIWE message.
const signature = await wallet.signMessage(siweMessage);
console.log("\nSignature:", signature);
// Build the login request body.
const loginBody = {
account_address: activeAccount,
expiration_time: EXPIRATION_DATE,
issued_at: ISSUED_AT,
signature,
nonce,
};
const loginHeaders = {
"Content-Type": "application/json",
Origin: ORIGIN,
Referer: ORIGIN,
};
console.log("\n[4/4] Sending login request...");
const loginResponse = await axios.post(`${SOLVER_BASE_URL}/login`, loginBody, { headers: loginHeaders });
console.log("Login response:", loginResponse.data);
// Extract the access token.
const token = loginResponse.data.access_token;
if (!token) {
throw new Error("No access token received from login.");
}
// Fetch and log the Muon price in standard decimal format.
const muonPrice = await fetchMuonPriceConverted();
console.log("Fetched Muon Price (converted):", muonPrice);
// ----------------------------------------------------------------
// Instant Close Parameters – Replace these with your actual values:
const quote_id = 24718; // The quote ID (number) for the position to close.
const quantity_to_close = "6.1"; // The quantity to close as a string.
const close_price = (muonPrice * 0.95).toString(); //Position was LONG, so we're going to decrease a little to account for hedger spread.
console.log("closePrice: ", close_price);
console.log("\nSending instant close request...");
const closeResponse = await closeInstantPosition(token, quote_id, quantity_to_close, close_price);
console.log("Instant close response:", closeResponse);
} catch (err) {
console.error("Error in SIWE login flow or closing position:", err.response?.data || err.message);
}
})();
Explanation
SIWE Login Flow:
Nonce Retrieval: The script calls getNonce(activeAccount) to get a nonce from the solver.
SIWE Message: A SIWE message is built using the provided configuration (domain, chain ID, etc.) and then signed with your wallet.
Login Request: The signed SIWE message is sent to the /login endpoint. On success, an access token is returned.
Instant Close Request:
Parameters:
quote_id: The identifier of the quote (or open position) you wish to close.
quantity_to_close: The amount to close (as a string).
close_price: The price at which you wish to close the position.
Note: For market orders, remember to adjust this price for slippage if required.
API Call:
The access token is included in the authorization header when making a POST request to the /instant_close endpoint with the above parameters.