FMZ量化:加密货币市场常见需求设计实例解析(一)

Author: 小小梦, Created: 2023-12-17 18:43:46, Updated: 2023-12-18 09:46:16

img

在加密货币资产交易领域,获取及分析市场数据、查询费率以及监控账户资产变动都是关键的操作。以下是针对一些常见需求的实现方式的代码案例。

1、请问获取币安现货4小时内涨幅最大的币种怎么写呢?

在FMZ上编写量化交易策略程序时,遇到需求首先需要分析一下。所以根据需求我们分析出以下几点:

  • 使用哪种编程语言编写设计 计划使用Javascript实现。
  • 需要全币种现货实时行情数据 看到这个需求我们第一件事是去翻看币安的API文档,查找是否有聚合行情数据(有聚合行情是最好的,一个品种一个品种查费事费力)。 查询到聚合行情接口:GET https://api.binance.com/api/v3/ticker/price。 在FMZ上,访问交易所行情接口(不需要签名的公共接口)使用HttpQuery函数。
  • 需要统计滚动窗口周期4小时的数据 构思如何设计这个统计程序的结构。
  • 计算涨跌幅,排序 思考思考涨跌幅算法,是否是:涨跌幅百分比 =(当前价格 - 初始价格)/ 初始价格 * 100,单位为“%”。

想清楚问题,以及确定方案后。我们就开始动手设计程序。

代码设计

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)
        }
        
        // 计算涨跌幅
        var tbl = {
            type : "table",
            title : "涨跌幅",
            cols : ["交易对", "当前价格", "4小时前价格", "涨跌幅", "数据长度", "最早数据时间", "最新数据时间"],
            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)
    }
}

代码解析

    1. 数据结构 var dictSymbolsPrice = {}: 一个空对象,用于存储每个交易对的价格信息。键是交易对的符号,值是一个对象,包含交易对的名称、价格数据数组和涨跌幅信息。
    1. 主函数 main()
    • 2.1. 无限循环
      while (true) {
          // ...
      }
      
      程序通过一个无限循环来持续监测Binance API的交易对价格。
    • 2.2. 获取价格信息
      var arr = JSON.parse(HttpQuery("https://api.binance.com/api/v3/ticker/price"))
      
      通过Binance API获取交易对的当前价格信息。如果返回的不是数组,则等待5秒后重新尝试。
    • 2.3. 更新价格数据
      for (var i = 0; i < arr.length; i++) {
          // ...
      }
      
      遍历获取到的价格信息数组,更新dictSymbolsPrice中的数据。对于每个交易对,将当前的时间戳和价格添加到相应的数据数组中。
    • 2.4. 异常处理
      } catch(e) {
          Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
      }
      
      捕捉异常并记录异常信息,以确保程序能够继续执行。
    • 2.5. 计算涨跌幅
      for (var symbol in dictSymbolsPrice) {
          // ...
      }
      
      遍历dictSymbolsPrice,计算每个交易对的涨跌幅,并在数据长度超过4小时的情况下删除最早的数据。
    • 2.6. 排序并生成表格
      var entries = Object.entries(dictSymbolsPrice)
      entries.sort((a, b) => b[1].percentageChange - a[1].percentageChange)
      
      for (var i = 0; i < entries.length; i++) {
          // ...
      }
      
      将交易对按照涨跌幅从高到低排序,并生成一个包含交易对信息的表格。
    • 2.7. 日志输出和延时
      LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
      Sleep(5000)
      
      将表格和当前时间以日志的形式输出,并等待5秒后继续下一轮循环。

程序通过Binance API获取交易对的实时价格信息,然后计算涨跌幅,并以表格的形式输出到日志中。程序通过不断循环执行,实现实时监控交易对价格的功能。需要注意的是,程序中包含异常处理,以确保在获取价格信息时不会因为异常而中断执行。

实盘运行测试

img

由于开始的时候数据只能一点一点收集,未收集足够4小时的数据时,是无法滚动的计算涨跌幅的。所以开始的时候是以最初的一个价格为基准计算,收集足够4小时数据后,就依次剔除最旧的数据维持4小时窗口期计算涨跌幅。

2、查询币安U本位合约的全品种资金费率

查询资金费率和以上代码比较类似,首先也是需要查看币安的API文档,找到资金费率相关接口。币安有好几个可以查询资金费率的接口,这里我们以U本位合约的接口为例:

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

代码实现

由于合约太多,我们这里输出资金费率最大的前十个。

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: "U本位合约资金费率前十",
                cols: ["合约", "资金费率", "标记价格", "指数价格", "当期费率时间", "下期费率时间"],
                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)
    }
}

返回的数据结构如下,查看币安文档可知lastFundingRate就是我们要的资金费率。

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

实盘运行测试:

img

python版本的获取OKX交易所合约资金费率

有用户提出需要Python版本的例子,并且是OKX交易所的。这里也顺便实现一下:

https://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"
                } ...

具体代码:

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": "U本位合约资金费率前十",
                "cols": ["合约", "下期费率", "最小", "当期", "最大"],
                "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)

实盘运行测试:

img

END

这些例子提供了基本的设计思路、调用方法,实际项目中可能需要根据具体需求进行适当的修改和扩展。希望这些代码能够帮助你更好地满足加密货币数字资产交易中的各种需求。


More

98K-波段追踪_Long 期待小梦老师 尽快出一个@监控账户资产变动的案例

98K-波段追踪_Long 点赞

小小梦 好的,这个在计划内。