FMZ Quant: An Analysis of Common Requirements Design Examples in the Cryptocurrency Market (II)
Tags: cryptocurrency, market, analysis, fmzquant
Published: 2024-05-29 05:36:10

In response to the comments from readers in the previous article, they requested a program example for monitoring contract account transfers. In this article, we will use Binance exchange as the test object to implement the requirement and learn how to design it together.

Cryptocurrency exchanges handle a large number of transactions every day, including the transfer of assets between different wallets. Monitoring these transfers in real time is crucial for traders and developers. In this article, we will explore a piece of JavaScript code designed to monitor recent asset transfers on a cryptocurrency exchange and discuss its key components.

### Analyze Requirements
I checked the documentation of Binance exchange and found that there is a transfer history interface that can query all transfer information. Since we are only monitoring transfer records that may occur, we do not need to obtain all transfer history. We only need to check recent transfer records within a certain range based on a certain frequency. If new transfer records are found, they will be updated and notified.

Use the interface:

```
// GET /sapi/v1/asset/transfer type, size : 100
```
So how to check the newly added transfer record? After reading Binance's documentation, I found that there is a timestamp in the data returned by this interface. It is very simple to judge by the timestamp. As long as there is a record larger than the maximum timestamp currently recorded, it means that a new transfer action has occurred. Just use this to trigger it.

The /sapi/v1/asset/transfer interface can request up to 100 pieces of data at a time. The detection will not cause problems for low-frequency transfers, unless the account has more than 100 transfer operations between the end of one detection and the start of the next detection. At this time, some new operation records may be missed, which is sufficient for general demand scenarios (generally, there will be no strategy to transfer funds crazily...).

Of course, there are many details in the actual design. For example, checking the documentation, we found that there are many transfer directions, so we need to monitor each transfer direction. The code is defined var dicType = {...} to manage all transfer directions.

In order to display the content better, we use a status bar table to output the last 5 transfer information in the strategy interface, so we constructed an object named monitor to record the data. Of course, you cannot record transfer information unlimitedly, so we only maintain 100 records for each transfer direction. If the number exceeds 100, we will delete premature records.

### Code Example
```
function getRecentTransferHistory(TransType, typeDesc) {
	// GET /sapi/v1/asset/transfer type, size : 100
    
    var rows = null 
    var ret = exchange.IO("api", "GET", "/sapi/v1/asset/transfer", `type=${TransType}&size=100`)
    Log("/sapi/v1/asset/transfer" + `type=${TransType}&size=100`)
    if (ret && typeof(ret.rows) != "undefined" && Array.isArray(ret.rows)) {
        rows = ret.rows
    } else if (ret && typeof(ret.total) != "undefined" && ret.total == 0) {
        rows = []
    } else {
    	Log(TransType, typeDesc, "inquiry failure", ret)
    }
    
    return rows
}

var monitor = {}
function monitorTransfers() {
    var dicType = {
        "MAIN_UMFUTURE": "Spot wallet --> U-based contract wallet",
        "MAIN_CMFUTURE": "Spot wallet --> Currency-based contract wallet",
        "UMFUTURE_MAIN": "U-based contract wallet --> Spot wallet",
        "UMFUTURE_MARGIN": "U-based contract wallet --> Leveraged full position wallet",
        "CMFUTURE_MAIN": "Currency-based contract wallet --> Spot wallet",
        "MARGIN_UMFUTURE": "Leveraged full position wallet --> U-based contract wallet",
        "MARGIN_CMFUTURE": "Leveraged full position wallet --> Currency-based contract wallet",
        "CMFUTURE_MARGIN": "Currency-based contract wallet --> Leveraged full position wallet",
        "FUNDING_UMFUTURE": "Funds wallet --> U-based contract wallet",
        "UMFUTURE_FUNDING": "U-based contract wallet --> Funds wallet",
        "FUNDING_CMFUTURE": "Funds wallet --> Currency-based contract wallet",
        "CMFUTURE_FUNDING": "Currency-based contract wallet --> Funds wallet",
        "UMFUTURE_OPTION": "U-based contract wallet --> Options wallet",
        "OPTION_UMFUTURE": "Options wallet --> U-based contract wallet",
        // integrated account
        "MAIN_PORTFOLIO_MARGIN": "Spot wallet --> Unified accounts wallet",
        "PORTFOLIO_MARGIN_MAIN": "Unified accounts wallet --> Spot wallet"
    }
    
    Log("start testing")
    _.each(dicType, function(v, k) {
        var rows = getRecentTransferHistory(k, v)
        var maxTS = 0
        _.each(rows, function(row) {
            if (typeof(monitor[k]) == "undefined") {
            	monitor[k] = {"transType": k, "typeDesc": v, "recentRecords": [], "lastTS": 0}            	
            }

            if (row["timestamp"] > monitor[k]["lastTS"]) {
                monitor[k]["recentRecords"].push(row)
                
                if (monitor[k]["lastTS"] != 0) {
                	Log("New transfer records detected", k, v, row, "#FF0000")
                }                
            }
            maxTS = Math.max(maxTS, row["timestamp"])     
        })
        if (rows && rows.length == 0) {
            return 
        }
        monitor[k]["lastTS"] = maxTS

        var sortedArrayAscending = monitor[k]["recentRecords"].slice().sort((a, b) => a.timestamp - b.timestamp)
        monitor[k]["recentRecords"] = sortedArrayAscending

        if (monitor[k]["recentRecords"].length > 100) {
        	monitor[k]["recentRecords"].shift()
        }
        Sleep(1000)
    })
    Log("commencement and termination")
}


function main() {
    LogReset()
    while (true) {
        monitorTransfers()

        var tbls = []
        _.each(monitor, function(v, k) {
        	var tbl = {
        		"type": "table", 
        		"title": v["typeDesc"], 
        		"cols": ["asset", "amount", "status", "tranId", "time"], 
        		"rows": []
        	}

            var arr = v["recentRecords"].slice().sort((a, b) => b.timestamp - a.timestamp)
            for (var i = 0; i < arr.length; i++) {
            	if (i < 5) {
            		tbl["rows"].push([arr[i]["asset"], arr[i]["amount"], arr[i]["status"], arr[i]["tranId"], _D(arr[i]["timestamp"])])
            	}            	
            }
            tbls.push(tbl)
        })        

    	LogStatus(_D(), "\n", "`" + JSON.stringify(tbls) + "`")
    	Sleep(1000 * 30)
    }
}
```
### Code Overview:
The provided JavaScript code includes several functions that build a system together for monitoring recent asset transfers. Let's analysis the main components:

- getRecentTransferHistory function:

      Purpose: Obtain the recent asset transfer history from the exchange API according to the specified parameters.
      Parameters: TransType (transfer type), typeDesc (type description).
      API endpoint: /sapi/v1/asset/transfer.

- monitorTransfers function:

      Purpose: Iterate over predefined transfer types, retrieve recent transfer history, and record any new transfers.
      Use a dictionary (dicType) to map transfer types to human-readable descriptions.
      Update the monitor object to track the latest transfers of each type.

- main function:

      Purpose: Run an infinite loop that monitors transfers continuously and displays the latest data.
      Use the monitorTransfers function regularly.
      Generate a table for each transfer type, including columns such as asset, amount, status, transaction ID, and timestamp.

### Key Features:
- Dynamic transfer type mapping:

      The code uses a dictionary (dicType) to map transfer types to descriptive names, providing a clear explanation of the nature of each transfer.

- Real-time monitoring:

      The system checks for new transfers continuously, updates the monitor object and records any detected changes.

- Data presentation:

      Use tables to present each type of transfer data, including relevant details such as assets, amounts, status, transaction IDs, and timestamps.

- Recent transfer history management:

      Maintain a scrolling list of recent transfer records for each type, ensuring a concise and timely display.

### Bot Test
A transfer was made manually and the program detected the transfer operation.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/timhpwjns27iltrp9jep.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jhm3g20eem0q9pf7b4qr.png)

### END:
The provided JavaScript code provides a powerful solution for monitoring recent asset transfers on cryptocurrency exchanges. Its dynamic and real-time nature makes it a valuable tool for traders and developers seeking to understand asset movements between different wallets. This code can be modified and customized to specific needs, providing a solid foundation for those looking to enhance their cryptocurrency trading strategies or develop additional monitoring capabilities.

This article throws some light on the topic and provides a design idea. May your cryptocurrency career be both informative and successful!

From: https://blog.mathquant.com/2023/12/25/fmz-quant-an-analysis-of-common-requirements-design-examples-in-the-cryptocurrency-market-ii.html