Crypto Trading Simulation for Live Market Execution (With Pair Trading Strategy)

DolphinDBDolphinDB
13 min read

Pair trading is a market-neutral strategy enabling traders to profit from virtually any market conditions: uptrend, downtrend, or sideways movement. The strategy monitors performance of two historically correlated assets. When the correlation between the two temporarily weakens, i.e. one moves up while the other moves down, the pairs trade would be to short the outperforming stock and to long the underperforming one, betting that the “spread” between the two would eventually converge. Initially used in the stock market, this strategy has now been adapted for cryptocurrency trading as the crypto market grows.

The implementation steps for pair trading typically include:

  1. Identifying correlated assets: Choose two highly correlated assets.

  2. Analyzing spread patterns: Estimate the price spread between the two assets.

  3. Developing trading signals: Create a system that flags opportunities for buying and selling when the current spread significantly diverges from its typical range.

  4. Executing trades: Open positions based on these signals — usually going long on the underperforming asset and short on the outperforming one.

  5. Managing Exits: Close positions either when the spread normalizes, predefined profit targets are hit, or stop-loss points are reached to secure gains or limit losses.

DolphinDB provides functionality for executing pair trading strategies. This section demonstrates the practical application of pair trading in the crypto market, focusing on spot crypto pairs and perpetual futures contracts.

Download our whitepaper for a new crypto management experience: Cryptocurrency Solutions — Dolphindb

6.3.1 Workflow

The pair trading algorithm operates in a continuous cycle, beginning with real-time data access for both spot and perpetual futures prices. It calculates the relative difference between these markets and constantly evaluates this change against predetermined trading criteria.

  • If the relative difference exceeds a specified upper limit, it establishes a long position in the spot market while taking a short position of equal size in the perpetual futures market.

  • If the relative difference falls below a lower limit and there’s an existing open position, it moves to close out the trade, which involves liquidating a specified amount of the spot asset while also covering all short positions in the perpetual futures market.

  • If no conditions are met, the system continues its data access and market monitoring.

After each trading action, the process restarts. The following figure illustrates the workflow of the pair trading strategy.

Figure 6–3 Workflow of the Pair Trading Strategy

The pair trading strategy initiates orders at prices slightly less favorable, i.e., buy orders with a price above the mid price, or sell orders with a price below the mid price, ensuring that both spot and futures orders can be filled. However, we must account for potential market volatility and liquidity issues. In such scenarios, our system is designed to maintain balance between the two assets. If a mismatch occurs, it automatically places additional market orders to complete the unfilled portion.

When Opening Positions:

  • If we find more spot assets than perpetual futures contracts, we immediately place a market order to short sell additional perpetual futures.

  • If we have more perpetual futures contracts than spot assets, we place a market order to buy additional spot assets.

When Closing Positions:

  • In cases where our spot position exceeds the perpetual futures position, we issue a market order to sell the excess spot assets.

  • If our perpetual futures position is larger than the spot position, we place a market order to close the excess futures contracts.

To illustrate this process, let’s consider the case of buying spot while shorting futures. The workflow can be as follows:

Figure 6–4 Process of Opening/Closing Positions for Pairs

6.3.2 Key Functions for Order Execution

The foundation of our pair trading strategy lies in implementing the pair order execution functions. This crucial component enables us to simultaneously execute two actions: buying a specified quantity of the spot asset while shorting an equivalent amount of perpetual futures contracts, or vice versa. The system records the order details of both spot and perpetual futures.

Creating a Persisted Stream Table

Similar to the implementation of TWAP, we adopt a persisted stream table that serves as a cache for order statuses and related info.

Create a persisted stream table “pairOrdersDetail“ to store order info including labels, crypto pairs, update time, IDs, prices, order quantities, trade quantites, statuses, types and direction.

colNames = `label`symbol`updatetime`orderId`price`origQty
           `executedQty`status`type`side
colTypes = [STRING,SYMBOL, TIMESTAMP, INT, DECIMAL128(18), 
            DECIMAL128(18), DECIMAL128(18), STRING, STRING, STRING]
enableTableShareAndPersistence(table=streamTable(100000:0, 
                               colNames, colTypes), tableName=`pairOrdersDetail, 
                               cacheSize=1200)

Note: The distinction in symbol names will differentiate between spot and perpetual futures. For instance, for the trading pair ETHUSDT, the spot is labeled as “ETHUSDT”, whereas perpetual futures as “ETHUSDT_perps”.

Placing, Cancelling, Checking Orders

Following the implementation described in section 6.2.2, we define functions to manage orders for both spot and perpetual futures simultaneously.

The putOrderRecordDetails function enables the placement of opposite-direction orders for both types. The cancelOrders function handles the cancellation of all orders. The checkOrders function retrieves information for both spot and perpetual futures orders and inserts the latest order details into the stream table "pairOrdersDetail”.

Handling Exposure Imbalance

Unlike the TWAP implementation, pair trading handles exposure imbalance, i.e., the positions of spot and perpetual futures do not align as intended. Refer to Figure 6–4 for detailed process. The specific implementation is detailed below, using the opening position as an example to demonstrate how we handle these imbalances:

def processTradeQty(labelName,symbol,sapiKey,sapiSecret,fapiKey,fapiSecret){
        tradedQty = select last(label) as label, orderId, 
                    last(symbol) as symbol, last(price) as price, 
                    last(status) as status,
        last(executedQty) as executedQty from ordersDetail group by orderID
        spotQty = exec sum(executedQty) from tradedQty 
                  where label = labelName and symbol = symbol
        perpsQty = exec sum(executedQty) from tradedQty 
                  where label = labelName and symbol = symbol+'_perps'
        imbalancedQty = spotQty - perpsQty
        if(imbalancedQty > 0){
            plimit = futureMarketOrder(symbol,'SELL',imbalancedQty,fapiKey,fapiSecret)
            perpsOrderTable = table(labelName as label, 
                                   plimit['symbol']+'_perps' as symbol, 
                                   now() as updatetime, 
                                   plimit['orderId'] as orderId, 
                                   plimit['price']$DECIMAL128(18) as price, 
                                   plimit['origQty']$DECIMAL128(18) as origQty, 
                                   plimit['executedQty']$DECIMAL128(18) as executedQty, 
                                   plimit['status'] as status, 
                                   plimit['type'] as type, plimit['side'] as side)
            pairOrdersDetail.append!(perpsOrderTable)
        }
        if(imbalancedQty < 0){
            slimit = spotMarketOrder(symbol,'BUY',
                                     abs(imbalancedQty),sapiKey,sapiSecret)
            spotOrderTable = table(labelName as label, 
                                  slimit['symbol'] as symbol, now() as updatetime, 
                                  slimit['orderId'] as orderId, 
                                  slimit['price']$DECIMAL128(18) as price, 
                                  slimit['origQty']$DECIMAL128(18) as origQty, 
                                  slimit['executedQty']$DECIMAL128(18) as executedQty, 
                                  slimit['status'] as status, 
                                  slimit['type'] as type, 
                                  slimit['side'] as side)
            pairOrdersDetail.append!(spotOrderTable)
        }
        return spotQty,perpsQty
    }

The processTradeQty function returns two values: the holding amount of the spot asset and the short quantity of the perpetual contracts before performing balancing.

Encapsulating Pair Trading Operations

Leveraging the functions we’ve defined — putOrderRecordDetails, cancelOrders, checkOrders, and processTradeQty - we can now construct two key functions that encapsulate our pair trading strategy's core operations:

  • openPairsOrder for opening positions: Initiates a buy order for the spot asset and simultaneously places a short order for the perpetual futures contract.

  • closePairsOrder for closing positions: Executes a sell order for the spot asset and closes the short position in the perpetual futures contract.

Both functions not only handle the trading actions but also manage the associated data updates in our “pairOrdersDetail” stream table, ensuring a comprehensive and real-time view of our trading activities.

The openPairsOrder and closePairsOrder functions share an identical set of parameters:

  • labelName: STRING. The custom label for identifying orders.

  • symbol: STRING. The crypto pairs or contract names.

  • spotPrice: DECIMAL128(S). The spot prices.

  • perpsPrice: DECIMAL128(S). The perpetual futures prices.

  • eachQty: DECIMAL128(S). The quantity for each individual hedged position.

  • maxQty: DECIMAL128(S). The upper limit for the total hedged position size.

  • sapiKey, sapiSecret: STRING. API key and secret of the spot account.

  • fapiKey, fapiSecret: STRING. API key and secret of the perpetual futures account.

6.3.3 Core Implementation

The core of our strategy implements a basis reversion arbitrage, encapsulated within a function named basicRateArb. This function builds upon the previously defined openPairsOrder and closePairsOrder functions, introducing additional parameters: openRate, closeRate, and priceSlippage.

The loop of basicRateArb first determines the current market conditions. It retrieves the mid-market price for both the spot and perpetual futures and calculates the order price based on preset slippage. Then it determines the relative difference (basicRate) between the spot and perpetual futures mid-prices.

  • If basicRate exceeds openRate, it triggers openPairsOrder to initiate a new position.

  • If basicRate falls below closeRate, it triggers closePairsOrder to exit existing positions.

def basicRateArb(labelName,openRate,closeRate,symbol,
                 priceSlippage,eachQty,maxQty,sapiKey,
                 sapiSecret,fapiKey,fapiSecret){
    do{
    // obtain mid-prices
    depth = spotDepth(symbol)
    sprice = (depth['bids'][0][0]$DOUBLE+depth['asks'][0][0]$DOUBLE)/2
    // calculate prices for spot limit orders
    buySpotPrice = ((1+priceSlippage)*sprice)$DECIMAL128(2)
    sellSpotPrice = ((1-priceSlippage)*sprice)$DECIMAL128(2)
    // calculate prices for perps orders
    fdepth = futureDepth(symbol)
    fprice = (fdepth['bids'][0][0]$DOUBLE+fdepth['asks'][0][0]$DOUBLE)/2
    longPerpsPrice = ((1+priceSlippage)*fprice)$DECIMAL128(2)
    shortPerpsPrice = ((1-priceSlippage)*fprice)$DECIMAL128(2)
    // calculate relative difference
    basicRate = fprice/sprice - 1
    // to open positions
    if(basicRate>openRate){
        openPairsOrder(labelName,symbol,buySpotPrice,shortPerpsPrice,
        eachQty,maxQty,sapiKey,sapiSecret,fapiKey,fapiSecret)
    }
    // to close positions
    if(basicRate<closeRate){
        closePairsOrder(labelName,symbol,sellSpotPrice,longPerpsPrice,
        eachQty,maxQty,sapiKey,sapiSecret,fapiKey,fapiSecret)
    }
    // pause for 1s
    sleep(1000)
    }
    while(1)
}

6.3.4 Example

To demonstrate the effectiveness of our basicRateArb function, we configured it with easily achievable openRate and closeRate parameters. This setup was designed to trigger frequent trading activities, making the results more pronounced and easier to analyze.

basicRateArb(labelName='ETH_PairTrading',openRate=0.00,
closeRate=-0.1,symbol='ETH',priceSlippage=0.003,eachQty=0.2,
maxQty=5.0,sapi_key,sapi_secret,fapi_key,fapi_secret)

You can observe from the figure that the USDT balance in the spot account has decreased, the amount of ETH has increased, and the exposure of the ETH perpetual contract position has decreased by the same amount, which aligns with the expected outcomes of the strategy.

Figure 6–5 Visualization of Pair Trading Strategy’s Result

Appendix: Binance Interaction Essentials

As this chapter focuses on Binance’s mock trading, this appendix provides detailed instructions on how to interact with the Binance platform.

Registering API Keys and Secrets

To access mock trading on Binance, you’ll need to register for a testnet account. Follow the links below to create your account and obtain your private API keys and secrets for both spot and perpetual futures trading.

sapi_key = 'API key for spot account'
sapi_secret = 'API secret for spot account'
fapi_key = 'API key for perpetual futures account'
fapi_secret = 'API secret for perpetual futures account'

Generating Signature

Binance APIs require an API key (HMAC-SHA256) to access authenticated endpoints for trading. The purpose of the signature is to ensure the integrity and authenticity of the request data, preventing third parties from tampering with or forging requests.

def getSignature(payload, secretKey){
    return hmac(secretKey, payload, digest = "sha256")
}
timer sig = getSignature("Your message", "YourSecretKey")

Accessing Market Depth

  • spot

Definition:

def spotDepth(symbol){
    url='https://testnet.binance.vision/api/v3/depth'
    param=dict(string,string)
    param['symbol'] = symbol
    param['limit'] = '05'
    res=httpClient::httpGet(url,param,10000)
    text = res.text
    dict = parseExpr(text).eval()
    return dict
}

Example:

print(spotDepth('ETHUSDT'))
/* output:
lastUpdateId->12921819
bids->(["3760.94000000","0.11700000"],["3760.93000000","0.07580000"],["3760.91000000","0.10510000"],["3760.90000000","0.07180000"],["3760.86000000","0.10370000"])
asks->(["3760.95000000","0.12500000"],["3760.98000000","0.12240000"],["3761.02000000","0.10110000"],["3761.05000000","0.07720000"],["3761.06000000","0.09840000"])
*/
  • futures

Definition:

def futureDepth(symbol){
    url="https://testnet.binancefuture.com/fapi/v1/depth"
    param=dict(string,string)
    param['symbol'] = symbol
    param['limit'] = '05'
    res=httpClient::httpGet(url,param,10000)
    text = res.text
    dict = parseExpr(text).eval()
    return dict
}

Example:

print(futureDepth('ETHUSDT'))
/* output:
lastUpdateId->36227996117
E->1716358885300
T->1716358885291
bids->(["3532.00","329.714"],["3531.01","115.763"],
["3530.06","560.462"],["3530.05","823.708"],["3530.04","2.297"])
asks->(["3590.00","0.294"],["3598.98","425.921"],
["3598.99","1443.509"],["3599.00","19.398"],["3600.00","918.445"])
*/

Obtaining Positions

  • spot — for all spot assets

Definition:

def getSpotAccount(apiKey,secretKey){
    baseUrl = 'https://testnet.binance.vision/api'
    queryUrl = '/v3/account'
    paramStr = 'timestamp=' + long(now()) 
    sigStr = getSignature(paramStr, secretKey)
    url = baseUrl + queryUrl + '?' + paramStr + '&signature=' +sigStr
    param=dict(string,string)
    headers=dict(string,string)
    headers['X-MBX-APIKEY'] = apiKey
    res=httpClient::httpGet(url, param, 10000, headers)
    text = res.text
    dict = parseExpr(text).eval()
    balance = dict.balances
    timer transposed = each(transpose, balance)
    resulttb = select * from unionAll(transposed)
    return select * from unionAll(transposed)
}

Example:

print(getSpotAccount(sapi_key,sapi_secret))

Output:

Figure appx-1 Output of getSpotAccount

  • spot — for a single coin

Definition:

def getSpotCoinAccount(assetname,apiKey,secretKey){
    alltb = getSpotAccount(apiKey,secretKey)
    resulttb = select * from alltb where asset = assetname
    return resulttb
}

Example:

print(getSpotCoinAccount('ETH',sapi_key,sapi_secret))

Output:

Figure appx-2 Output of getSpotCoinAccount

  • futures

Definition:

def getFutureAccount(apiKey,secretKey){
    baseUrl = 'https://testnet.binancefuture.com/fapi'
    queryUrl = '/v2/account'
    paramStr = 'timestamp=' + long(now())
    sigStr = getSignature(paramStr, secretKey)
    url = baseUrl + queryUrl + '?' + paramStr + '&signature=' +sigStr
    param=dict(string,string)
    headers=dict(string,string)
    headers['X-MBX-APIKEY'] = apiKey
    res=httpClient::httpGet(url, param, 10000, headers)
    text = res.text
    dict = parseExpr(text).eval()
    return dict
}

Example:

res = getFutureAccount(fapi_key,fapi_secret)
print(res['positions'])

Output:

Figure appx-3 Output of getFutureAccount

Placing Orders

  • market order for spot assets

Definition:

def spotMarketOrder(symbol,side,quantity,apiKey,secretKey){
    baseUrl = 'https://testnet.binance.vision/api'
    queryUrl = '/v3/order'
    paramStr = 'symbol='+symbol+'&side='+side+'&type=MARKET&quantity=
               '+string(quantity)+'&timestamp=' + string(long(now()))
    timer sigStr = getSignature(paramStr, secretKey)
    url = baseUrl + queryUrl + '?' + paramStr + '&signature=' +sigStr
    param=dict(string,string)
    headers=dict(string,string)
    headers['X-MBX-APIKEY'] = apiKey
    res=httpClient::httpPost(url, param, 10000, headers)
    text = res.text
    dict = parseExpr(text).eval()
    return dict
}

Example:

print(spotMarketOrder('ETHUSDT','SELL','0.1',sapi_key,sapi_secret))

Output:

Figure appx-4 Output of spotMarketOrder

  • limit orders for spot assets

Definition:

def spotLimitOrder(symbol,side,price,quantity,apiKey,secretKey){
    baseUrl = 'https://testnet.binance.vision/api'
    queryUrl = '/v3/order'
    paramStr = 'symbol='+symbol+'&side='+side+'&price='+string(price)+
               '&type=LIMIT&timeInForce=GTC&quantity='+string(quantity)+
               '&timestamp=' + string(long(now()))
    timer sigStr = getSignature(paramStr, secretKey)
    url = baseUrl + queryUrl + '?' + paramStr + '&signature=' +sigStr
    param=dict(string,string)
    headers=dict(string,string)
    headers['X-MBX-APIKEY'] = apiKey
    res=httpClient::httpPost(url, param, 10000, headers)
    text = res.text
    dict = parseExpr(text).eval()
    return dict
}

Example:

print(spotLimitOrder('ETHUSDT','BUY', 3000, 0.1,sapi_key,sapi_secret))

Output:

Figure appx-5 Output of spotLimitOrder

  • market orders for futures contracts

Definition:

def futureMarketOrder(symbol,side,quantity,apiKey,secretKey){
    baseUrl = 'https://testnet.binancefuture.com/fapi'
    queryUrl = '/v1/order'
    paramStr = 'symbol='+symbol+'&side='+side+'&type=MARKET&quantity=
               '+string(quantity)+'&timestamp=' + string(long(now()))
    timer sigStr = getSignature(paramStr, secretKey)
    url = baseUrl + queryUrl + '?' + paramStr + '&signature=' +sigStr
    param=dict(string,string)
    headers=dict(string,string)
    headers['X-MBX-APIKEY'] = apiKey
    res=httpClient::httpPost(url, param, 10000, headers)
    text = res.text
    dict = parseExpr(text).eval()
    return dict
}

Example:

print(futureMarketOrder('ETHUSDT','SELL','0.1',fapi_key,fapi_secret))

Output:

Figure appx-6 Output of futureMarketOrder

  • limit orders for futures contracts

Definition:

def futureLimitOrder(symbol,side,price,quantity,apiKey,secretKey){
    baseUrl = 'https://testnet.binancefuture.com/fapi'
    queryUrl = '/v1/order'
    paramStr = 'symbol='+symbol+'&side='+side+'&price='+string(price)+
               '&type=LIMIT&timeInForce=GTC&quantity='+string(quantity)+
               '&timestamp=' + string(long(now()))
    timer sigStr = getSignature(paramStr, secretKey)
    url = baseUrl + queryUrl + '?' + paramStr + '&signature=' +sigStr
    param=dict(string,string)
    headers=dict(string,string)
    headers['X-MBX-APIKEY'] = apiKey
    res=httpClient::httpPost(url, param, 10000, headers)
    text = res.text
    dict = parseExpr(text).eval()
    return dict
}

Example:

print(futureLimitOrder('ETHUSDT','BUY', 3000, 0.1,fapi_key,fapi_secret))

Output:

Figure appx-7 Output of futureLimitOrder

Checking Orders

  • spot

Definition:

def checkSpotOrder(symbol,orderId,apiKey,secretKey){
    baseUrl = 'https://testnet.binance.vision/api'
    queryUrl = '/v3/order'
    paramStr = 'symbol='+symbol+'&orderId='+orderId+'&timestamp=' + 
               string(long(now()))
    timer sigStr = getSignature(paramStr, secretKey)
    url = baseUrl + queryUrl + '?' + paramStr + '&signature=' +sigStr
    param=dict(string,string)
    headers=dict(string,string)
    headers['X-MBX-APIKEY'] = apiKey
    timer res=httpClient::httpGet(url, param, 10000, headers)
    text = res.text
    dict = parseExpr(text).eval()
    return dict
}

Example:

print(checkSpotOrder('ETHUSDT','6951463',sapi_key,sapi_secret))

Output:

Figure appx-8 Output of checkSpotOrder

  • futures

Definition:

def checkFutureOrder(symbol,orderId,apiKey,secretKey){
    baseUrl = 'https://testnet.binancefuture.com/fapi'
    queryUrl = '/v1/order'
    paramStr = 'symbol='+symbol+'&orderId='+orderId+'&timestamp=' + 
               string(long(now()))
    timer sigStr = getSignature(paramStr, secretKey)
    url = baseUrl + queryUrl + '?' + paramStr + '&signature=' +sigStr
    param=dict(string,string)
    headers=dict(string,string)
    headers['X-MBX-APIKEY'] = apiKey
    timer res=httpClient::httpGet(url, param, 10000, headers)
    text = res.text
    dict = parseExpr(text).eval()
    return dict
}

Example:

print(checkFutureOrder('ETHUSDT','1380990949',fapi_key,fapi_secret))

Output:

Figure appx-9 Output of checkFutureOrder

Cancelling Orders

  • spot — with specific order ID

Definition:

def cancelSpotOrder(symbol, orderId, apiKey,secretKey){
    baseUrl = 'https://testnet.binance.vision/api'
    queryUrl = '/v3/order'
    paramStr = 'symbol='+symbol+'&orderId='+orderId+'&timestamp=' + 
               string(long(now())
    timer sigStr = getSignature(paramStr, secretKey)
    url = baseUrl + queryUrl + '?' + paramStr + '&signature=' +sigStr
    param=dict(string,string)
    headers=dict(string,string)
    headers['X-MBX-APIKEY'] = apiKey
    res=httpClient::httpDelete(url, param, 10000, headers)
    text = res.text
    dict = parseExpr(text).eval()
    return dict
}

Example:

cancelSpotOrder('ETHUSDT', 17557280, sapi_key,sapi_secret)

Output:

Figure appx-10 Output of cancelSpotOrder

  • spot — with specific crypto pairs

Definition:

def cancelSpotAll(symbol, apiKey,secretKey){
    baseUrl = 'https://testnet.binance.vision/api'
    queryUrl = '/v3/openOrders'
    paramStr = 'symbol='+symbol+'&timestamp=' + string(long(now()))
    timer sigStr = getSignature(paramStr, secretKey)
    url = baseUrl + queryUrl + '?' + paramStr + '&signature=' +sigStr
    param=dict(string,string)
    headers=dict(string,string)
    headers['X-MBX-APIKEY'] = apiKey
    res=httpClient::httpDelete(url, param, 10000, headers)
    text = res.text
    dict = parseExpr(text).eval()
    return dict
}

Example:

cancelSpotAll('ETHUSDT', sapi_key,sapi_secret)

Output:

If the specified crypto pair has no open orders, it reports an error with code: -2,011 and msg: 'Unknown order sent'.

If the order for the specified crypto pair has been successfully canceled, it returns a dict with the following form:

dict<string, any>[15](string[15](['symbol', 'origClientOrderId', 'orderId', 'orderListId', 'clientOrderId', 'transactTime', 'price', 'origQty', 'executedQty', 'cummulativeQuoteQty', 'status', 'timeInForce', 'type', 'side', 'selfTradePreventionMode']),any[15](['ETHUSDT', 'pYl9VeLe368Vk0WZmn9jiU', int(17,559,395), int(-1), 'I2n9AN2VnBmHiK9X6y92Ie', long(1,721,197,639,799), '3000.00000000', '0.10000000', '0.00000000', '0.00000000', 'CANCELED', 'GTC', 'LIMIT', 'BUY', 'EXPIRE_MAKER']))
  • futures — with specific order ID

Definition:

def cancelfutureOrder(symbol, orderId, apiKey,secretKey){
    baseUrl = 'https://testnet.binancefuture.com/fapi'
    queryUrl = '/v1/order'
    paramStr = 'symbol='+symbol+'&orderId='+orderId+'&timestamp=' + 
               string(long(now()))
    timer sigStr = getSignature(paramStr, secretKey)
    url = baseUrl + queryUrl + '?' + paramStr + '&signature=' +sigStr
    param=dict(string,string)
    headers=dict(string,string)
    headers['X-MBX-APIKEY'] = apiKey
    res=httpClient::httpDelete(url, param, 10000, headers)
    text = res.text
    dict = parseExpr(text).eval()
    return dict
}

Example:

cancelfutureOrder('ETHUSDT', 1445584927, fapi_key,fapi_secret)

Output:

Figure appx-11 Output of cancelFutureOrder

  • futures — with specific crypto pairs

Definition:

def cancelfutureAll(symbol, apiKey,secretKey){
    baseUrl = 'https://testnet.binancefuture.com/fapi'
    queryUrl = '/v1/allOpenOrders'
    paramStr = 'symbol='+symbol+'&timestamp=' + string(long(now()))
    timer sigStr = getSignature(paramStr, secretKey)
    url = baseUrl + queryUrl + '?' + paramStr + '&signature=' +sigStr
    param=dict(string,string)
    headers=dict(string,string)
    headers['X-MBX-APIKEY'] = apiKey
    res=httpClient::httpDelete(url, param, 10000, headers)
    text = res.text
    dict = parseExpr(text).eval()
    return dict
}

Example:

cancelfutureAll('ETHUSDT', fapi_key,fapi_secret)

Output:

Whether the specified order has open orders, it always reports an error with code: 200 and msg: 'The operation of cancel all open orders is done'.

Download Whitepaper Here: Cryptocurrency Solutions — Dolphindb

Email us for more information or to schedule a demo: sales@dolphindb.com

Thanks for your reading! To keep up with our latest news, please follow our Twitter @DolphinDB_Inc and Linkedin. You can also join our Slack to chat with the author!

0
Subscribe to my newsletter

Read articles from DolphinDB directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

DolphinDB
DolphinDB