FMZ Quant: Análisis de ejemplos de diseño de requisitos comunes en el mercado de criptomonedas (I)

El autor:- ¿ Por qué?, Creado: 2023-12-19 16:02:58, Actualizado: 2024-01-02 21:21:58

img

En el espacio de comercio de activos de criptomonedas, la obtención y el análisis de datos de mercado, las tasas de consulta y el monitoreo de los movimientos de activos de la cuenta son operaciones críticas.

1. ¿Cómo escribo el código para obtener la moneda con el mayor aumento en 4 horas en Binance Spot?

Cuando se escribe un programa de estrategia comercial cuantitativa en la plataforma FMZ, lo primero que debe hacer cuando se encuentra con un requisito es analizarlo.

  • ¿Qué lenguaje de programación usar? El plan es usar Javascript para implementarlo.
  • Requiere cotizaciones al contado en tiempo real en todas las monedas Lo primero que hicimos cuando vimos el requisito fue buscar el documento de la API de Binance para averiguar si había cotizaciones agregadas (es mejor tener cotizaciones agregadas, es mucho trabajo buscar una por una). Encontramos la interfaz de citas agregadas:GET https://api.binance.com/api/v3/ticker/price¿ Qué pasa? En la plataforma FMZ, utilice elHttpQueryFunción para acceder a la interfaz del ticker de intercambio (interfaz pública que no requiere una firma).
  • Necesidad de contar datos para un período de ventana de 4 horas Conceptualizar cómo diseñar la estructura del programa estadístico.
  • Calcular las fluctuaciones de precios y clasificarlas Pensando en el algoritmo de fluctuaciones de precios, es:price fluctuations (%) = (current price - initial price) / initial price * 100en %.

Después de averiguar el problema, así como definir el programa, luego nos pusimos a trabajar en el diseño del programa.

Diseño de código

var dictSymbolsPrice = {}

function main() {
    while (true) {
        // GET https://api.binance.com/api/v3/ticker/price
        try {
            var arr = JSON.parse(HttpQuery("https://api.binance.com/api/v3/ticker/price"))
            if (!Array.isArray(arr)) {
                Sleep(5000)
                continue 
            }
            
            var ts = new Date().getTime()
            for (var i = 0; i < arr.length; i++) {
                var symbolPriceInfo = arr[i]
                var symbol = symbolPriceInfo.symbol
                var price = symbolPriceInfo.price

                if (typeof(dictSymbolsPrice[symbol]) == "undefined") {
                    dictSymbolsPrice[symbol] = {name: symbol, data: []}
                }
                dictSymbolsPrice[symbol].data.push({ts: ts, price: price})
            }
        } catch(e) {
            Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
        }
        
        // Calculate price fluctuations
        var tbl = {
            type : "table",
            title : "Price fluctuations",
            cols : ["trading pair", "current price", "price 4 hours ago", "price fluctuations", "data length", "earliest data time", "latest data time"],
            rows : []
        }
        for (var symbol in dictSymbolsPrice) {
            var data = dictSymbolsPrice[symbol].data
            if (data[data.length - 1].ts - data[0].ts > 1000 * 60 * 60 * 4) {
                dictSymbolsPrice[symbol].data.shift()
            }

            data = dictSymbolsPrice[symbol].data
            dictSymbolsPrice[symbol].percentageChange = (data[data.length - 1].price - data[0].price) / data[0].price * 100
        }

        var entries = Object.entries(dictSymbolsPrice)
        entries.sort((a, b) => b[1].percentageChange - a[1].percentageChange)

        for (var i = 0; i < entries.length; i++) {
            if (i > 9) {
                break
            }   
            var name = entries[i][1].name
            var data = entries[i][1].data
            var percentageChange = entries[i][1].percentageChange
            var currPrice = data[data.length - 1].price
            var currTs = _D(data[data.length - 1].ts)
            var prePrice = data[0].price
            var preTs = _D(data[0].ts)
            var dataLen = data.length

            tbl.rows.push([name, currPrice, prePrice, percentageChange + "%", dataLen, preTs, currTs])
        }
        
        LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
        Sleep(5000)
    }
}

Análisis del código

    1. Estructura de los datosvar dictSymbolsPrice = {}: Un objeto vacío para almacenar información de precios para cada par de operaciones. La clave es el símbolo del par de operaciones, y el valor es un objeto que contiene el nombre del par de operaciones, una matriz de datos de precios e información sobre las fluctuaciones de precios.
    1. Función principal 2.1 Ciclo infinito
while (true) {
    // ...
}

El programa monitorea continuamente los precios de los pares de comercio de Binance API a través de un bucle infinito. 2.2 Obtener información sobre los precios

var arr = JSON.parse(HttpQuery("https://api.binance.com/api/v3/ticker/price"))

Obtenga la información del precio actual del par de operaciones a través de Binance API. Si el retorno no es una matriz, espere 5 segundos y vuelva a intentar. 2.3 Actualización de los datos de precios

for (var i = 0; i < arr.length; i++) {
    // ...
}

Iterar a través de la matriz de información de precios obtenida y actualizar los datos en dictSymbolsPrice. 2.4 Procesamiento de excepciones

} catch(e) {
    Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
}

Captura de excepciones y registro de la información de excepción para garantizar que el programa pueda continuar ejecutándose. 2.5. Calcular las fluctuaciones de precios

for (var symbol in dictSymbolsPrice) {
    // ...
}

Iterar a través de dictSymbolsPrice, calcular las fluctuaciones de precios de cada par de operaciones, y eliminar los datos más antiguos si es más de 4 horas. Ordenar y generar tablas

var entries = Object.entries(dictSymbolsPrice)
entries.sort((a, b) => b[1].percentageChange - a[1].percentageChange)

for (var i = 0; i < entries.length; i++) {
    // ...
}

Ordenar los pares de operaciones en orden decreciente de sus fluctuaciones de precios y generar una tabla que contenga información sobre los pares de operaciones. 2.7. Salida y retraso del registro

LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
Sleep(5000)

Saque la tabla y la hora actual en forma de registro y espere 5 segundos para continuar la siguiente ronda del bucle.

El programa obtiene la información de precios en tiempo real del par de operaciones a través de la API de Binance, luego calcula las fluctuaciones de precios y lo emite al registro en forma de tabla. El programa se ejecuta en un bucle continuo para realizar la función de monitoreo en tiempo real de los precios de los pares comerciales. Tenga en cuenta que el programa incluye procesamiento de excepciones para garantizar que la ejecución no se interrumpa por excepciones al obtener información de precios.

Prueba de operación en vivo

img

Dado que los datos solo se pueden recopilar poco a poco al principio, no es posible calcular las fluctuaciones de precios de forma continua sin recopilar suficientes datos para una ventana de 4 horas. Por lo tanto, el precio inicial se utiliza como base para el cálculo y, después de recopilar suficientes datos durante 4 horas, se eliminarán los datos más antiguos para mantener la ventana de 4 horas para calcular las fluctuaciones de precios.

2. Compruebe la variedad completa de tasas de financiación para los contratos denominados en U de Binance

Verificar la tasa de financiación es similar al código anterior, en primer lugar, necesitamos verificar la documentación de la API de Binance para encontrar la interfaz relacionada con la tasa de financiación.

GET https://fapi.binance.com/fapi/v1/premiumIndex

Implementación del código

Dado que hay tantos contratos, estamos exportando las 10 mayores tasas de financiación aquí.

function main() {
    while (true) {
        // GET https://fapi.binance.com/fapi/v1/premiumIndex
        try {
            var arr = JSON.parse(HttpQuery("https://fapi.binance.com/fapi/v1/premiumIndex"))
            if (!Array.isArray(arr)) {
                Sleep(5000)
                continue 
            }
            
            arr.sort((a, b) => parseFloat(b.lastFundingRate) - parseFloat(a.lastFundingRate))
            var tbl = {
                type: "table",
                title: "Top 10 funding rates for U-denominated contracts",
                cols: ["contracts", "funding rate", "marked price", "index price", "current rate time", "next rate time"],
                rows: []
            }
            for (var i = 0; i < 9; i++) {
                var obj = arr[i]
                tbl.rows.push([obj.symbol, obj.lastFundingRate, obj.markPrice, obj.indexPrice, _D(obj.time), _D(obj.nextFundingTime)])
            }
            LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
        } catch(e) {
            Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
        }
        Sleep(1000 * 10)
    }
}

La estructura de datos devuelta es la siguiente, y comprobar la documentación de Binance, muestra que la última tasa de financiación es la tasa de financiación que queremos.

{
    "symbol":"STMXUSDT",
    "markPrice":"0.00883606",
    "indexPrice":"0.00883074",
    "estimatedSettlePrice":"0.00876933",
    "lastFundingRate":"0.00026573",
    "interestRate":"0.00005000",
    "nextFundingTime":1702828800000,
    "time":1702816229000
}

Prueba de operación en vivo:

img

Obtención de las tasas de financiación de los contratos de intercambio OKX de la versión de Python

Un usuario ha pedido una versión de Python del ejemplo, y es para el intercambio OKX. Aquí hay un ejemplo:

Los datos devueltos por la interfazhttps://www.okx.com/priapi/v5/public/funding-rate-all?currencyType=1:

{
    "code":"0",
    "data":[
        {
            "fundingTime":1702828800000,
            "fundingList":[
                {
                    "instId":"BTC-USDT-SWAP",
                    "nextFundingRate":"0.0001102188733642",
                    "minFundingRate":"-0.00375",
                    "fundingRate":"0.0000821861465884",
                    "maxFundingRate":"0.00375"
                } ...

Código específico:

import requests
import json
from time import sleep
from datetime import datetime

def main():
    while True:
        # https://www.okx.com/priapi/v5/public/funding-rate-all?currencyType=1
        try:
            response = requests.get("https://www.okx.com/priapi/v5/public/funding-rate-all?currencyType=1")
            arr = response.json()["data"][0]["fundingList"]
            Log(arr) 
            if not isinstance(arr, list):
                sleep(5)
                continue

            arr.sort(key=lambda x: float(x["fundingRate"]), reverse=True)

            tbl = {
                "type": "table",
                "title": "Top 10 funding rates for U-denominated contracts",
                "cols": ["contracts", "next rate", "minimum", "current", "maximum"],
                "rows": []
            }

            for i in range(min(9, len(arr))):
                obj = arr[i]
                row = [
                    obj["instId"],
                    obj["nextFundingRate"],
                    obj["minFundingRate"],
                    obj["fundingRate"],
                    obj["maxFundingRate"]
                ]
                tbl["rows"].append(row)
            
            LogStatus(_D(), "\n", '`' + json.dumps(tbl) + '`')

        except Exception as e:
            Log(f"Error: {str(e)}")

        sleep(10)

Prueba de operación en vivo:

img

Enlace a la sección

Estos ejemplos proporcionan ideas básicas de diseño y métodos de llamada, el proyecto real puede necesitar hacer cambios y extensiones apropiados basados en las necesidades específicas.


Más.