|
1 | | -/* eslint-disable @typescript-eslint/no-unused-vars */ |
2 | | -import { USDMClient } from '../../../src/index'; |
| 1 | +import { FuturesNewAlgoOrderParams, USDMClient } from '../../../src/index'; |
3 | 2 |
|
4 | 3 | // or |
5 | | -// import { USDMClient } from 'binance'; |
| 4 | +// import { FuturesNewAlgoOrderParams, USDMClient } from 'binance'; |
6 | 5 |
|
7 | 6 | const key = process.env.API_KEY_COM || 'APIKEY'; |
8 | 7 | const secret = process.env.API_SECRET_COM || 'APISECRET'; |
9 | 8 |
|
10 | 9 | const client = new USDMClient({ |
11 | 10 | api_secret: secret, |
12 | 11 | api_key: key, |
13 | | - beautifyResponses: true, |
| 12 | + beautifyResponses: false, |
14 | 13 | }); |
15 | 14 |
|
16 | | -const symbol = 'BTCUSDT'; |
| 15 | +const symbol = process.env.BINANCE_EXAMPLE_SYMBOL || 'BTCUSDT'; |
17 | 16 |
|
18 | 17 | async function start() { |
19 | 18 | try { |
20 | | - // ### This is for Hedge Mode Only ### |
21 | | - // assuming you currently have a open position, and you want to modify the SL order. |
| 19 | + // Hedge Mode example: find each open hedge position and replace its SL. |
| 20 | + const positions = await client.getPositionsV3({ symbol }); |
| 21 | + const hedgePositions = positions.filter((position) => { |
| 22 | + if (position.positionSide === 'LONG') { |
| 23 | + return Number(position.positionAmt) > 0; |
| 24 | + } |
| 25 | + if (position.positionSide === 'SHORT') { |
| 26 | + return Number(position.positionAmt) < 0; |
| 27 | + } |
| 28 | + return false; |
| 29 | + }); |
22 | 30 |
|
23 | | - /** |
24 | | - * first we get all long and short positions status |
25 | | - * the result of this method in hedge mode is array of two objects |
26 | | - * first index for LONG and second index for SHORT |
27 | | - */ |
28 | | - const [ |
29 | | - { positionAmt: longAmount, ...long }, |
30 | | - { positionAmt: shortAmount, ...short }, |
31 | | - ]: any = await client.getPositionsV3({ symbol }); |
| 31 | + if (!hedgePositions.length) { |
| 32 | + console.log('No open LONG or SHORT hedge position found'); |
| 33 | + return; |
| 34 | + } |
32 | 35 |
|
33 | | - // if longAmount is bigger than 0 means we have open long position and if shortAmount is below 0 means we have open short position |
34 | | - const hasLong = parseFloat(longAmount) > 0; |
35 | | - const hasShort = parseFloat(shortAmount) < 0; |
36 | | - const hasOpen = hasLong || hasShort; |
| 36 | + const openAlgoOrders = await client.getOpenAlgoOrders({ |
| 37 | + symbol, |
| 38 | + algoType: 'CONDITIONAL', |
| 39 | + }); |
| 40 | + const sdkOrderIdPrefix = client.getOrderIdPrefix(); |
37 | 41 |
|
38 | | - // if we have any open position then we continue |
39 | | - if (hasOpen) { |
40 | | - // we get ourstop loss here |
41 | | - const orders = await client.getAllOpenOrders({ symbol }); |
42 | | - const stopOrders = |
43 | | - orders.filter(({ type }) => type === 'STOP_MARKET') ?? []; |
| 42 | + for (const position of hedgePositions) { |
| 43 | + if ( |
| 44 | + position.positionSide !== 'LONG' && |
| 45 | + position.positionSide !== 'SHORT' |
| 46 | + ) { |
| 47 | + continue; |
| 48 | + } |
44 | 49 |
|
45 | | - // we want to modify our long position SL here |
46 | | - if (hasLong) { |
47 | | - // we get the StopLoss order which is realted to long |
48 | | - const { orderId }: any = stopOrders.find( |
49 | | - ({ positionSide: ps }) => ps == 'LONG', |
50 | | - ); |
| 50 | + const positionSide = position.positionSide; |
| 51 | + const side = positionSide === 'LONG' ? 'SELL' : 'BUY'; |
| 52 | + const triggerPriceMultiplier = positionSide === 'LONG' ? 0.99 : 1.01; |
| 53 | + const appOwnedStops = openAlgoOrders.filter( |
| 54 | + (order) => |
| 55 | + order.orderType === 'STOP_MARKET' && |
| 56 | + order.positionSide === positionSide && |
| 57 | + order.side === side && |
| 58 | + order.clientAlgoId.startsWith(sdkOrderIdPrefix), |
| 59 | + ); |
51 | 60 |
|
52 | | - // if it exists, cancel it. |
53 | | - if (orderId) { |
54 | | - await client.cancelOrder({ symbol, orderId }); |
55 | | - } |
| 61 | + const stopLossOrder: FuturesNewAlgoOrderParams = { |
| 62 | + algoType: 'CONDITIONAL', |
| 63 | + symbol, |
| 64 | + side, |
| 65 | + positionSide, |
| 66 | + type: 'STOP_MARKET', |
| 67 | + closePosition: 'true', |
| 68 | + triggerPrice: ( |
| 69 | + Number(position.markPrice) * triggerPriceMultiplier |
| 70 | + ).toFixed(3), |
| 71 | + workingType: 'MARK_PRICE', |
| 72 | + priceProtect: 'TRUE', |
| 73 | + }; |
56 | 74 |
|
57 | | - const { markPrice }: any = long; |
| 75 | + if (appOwnedStops.length > 1) { |
| 76 | + throw new Error( |
| 77 | + `More than one SDK-prefixed ${positionSide} STOP_MARKET algo order found; refusing to choose automatically.`, |
| 78 | + ); |
| 79 | + } |
58 | 80 |
|
59 | | - // creating SL order |
60 | | - const result = await client.submitNewOrder({ |
61 | | - symbol, |
62 | | - side: 'SELL', // the action of order, means this order will sell which is sl for long position |
63 | | - positionSide: 'LONG', // based on the headge mode we either LONG or SHORT, here we are doing it for our long pos |
64 | | - timeInForce: 'GTC', |
65 | | - type: 'STOP_MARKET', |
66 | | - closePosition: 'true', // this is here because we don't have the position quantity value, and it means closee all quantity |
67 | | - stopPrice: parseFloat((markPrice * 0.99).toFixed(3)), // set sl price 1% below current price |
68 | | - workingType: 'MARK_PRICE', |
69 | | - }); |
70 | | - console.log('SL Modifiled sell result: ', result); |
| 81 | + const existingStop = appOwnedStops[0]; |
| 82 | + if (existingStop) { |
| 83 | + await client.cancelAlgoOrder({ algoId: existingStop.algoId }); |
71 | 84 | } |
72 | | - } else { |
73 | | - console.log('No Open position found'); |
| 85 | + |
| 86 | + const result = await client.submitNewAlgoOrder(stopLossOrder); |
| 87 | + console.log(`SL modified ${positionSide} result: `, result); |
74 | 88 | } |
75 | 89 | } catch (e) { |
76 | | - console.error('market sell failed: ', e); |
| 90 | + console.error('SL update failed: ', e); |
77 | 91 | } |
78 | 92 | } |
79 | 93 |
|
|
0 commit comments