FMZ量化交易币圈量化交易萌新看过来–带你走近币圈量化(七)
admin
2023-07-31 14:31:26
0

目前不清退的交易所推荐:

1、全球第二大交易所OKX欧意

国区邀请链接: https://www.myts3cards.com/cn/join/1837888   币种多,交易量大!

国际邀请链接:https://www.okx.com/join/1837888 注册简单,交易不需要实名,新用户能开合约,币种多,交易量大!

2、老牌交易所比特儿现改名叫芝麻开门 :https://www.gate.win/signup/649183

全球最大交易所币安,国区邀请链接:https://accounts.binance.com/zh-CN/register?ref=16003031  币安注册不了IP地址用香港,居住地选香港,认证照旧,邮箱推荐如gmail、outlook。支持币种多,交易安全!

买好币上KuCoin:https://www.kucoin.com/r/af/1f7w3  CoinMarketCap前五的交易所,注册友好操简单快捷!

FMZ量化交易平台邀请链接:https://www.fmz.com/

币圈量化交易萌新看过来–带你走近币圈量化(七)

上篇我们一起思考、设计了一个简单的多品种网格策略。接下来,我们继续在量化交易的道路上学习、前行。本篇我们来探讨更加复杂一点的策略设计-对冲策略的设计。本篇计划设计一个多品种的跨期对冲策略,说到跨期对冲策略熟悉期货交易的小伙伴们肯定都不陌生。对于萌新来说可能还并不了解这些概念,所以我们先简单讲解下跨期对冲的概念。

跨期对冲

跨期对冲简单说就是做多一个合约,做空一个合约,等待三种情况同时(多、空)平仓:

  • 做多的赚钱,做空的亏钱,赚的一头(俗语)比亏的一头(俗语)多的时候平仓,盈亏相抵之后会有一部分盈利。
  • 做多的亏钱,做空的赚钱,赚的一头比亏的一头多的时候平仓,…..(同上)。
  • 做多的赚钱,做空的也赚钱,那还想啥!平仓!

其它情况就是浮亏了,扛着或者继续加仓。(由于差价波动比单边波动缓和的多,相对风险小些,注意仅仅是相对!)

设A1为合约A在1时刻的价格,设B1为合约B在1时刻的价格,此时做空A合约,做空价格A1,做多B合约,做多价格B1。
设A2为合约A在2时刻的价格,设B2为合约B在2时刻的价格,此时平仓A合约(平空),平空价格A2,平仓B合约(平多),平多价格B2。

1时刻的差价:A1 - B1 = X 
2时刻的差价:A2 - B2 = Y 
X - Y = A1 - B1 - (A2 - B2)
X - Y = A1 - B1 - A2 + B2
X - Y = A1 - A2 + B2 - B1

可以看到,A1 - A2 就是A合约平仓的盈利差价。
B2 - B1就是B合约平仓的盈利差价。只要这两个平仓总体是正数,即:A1 - A2 + B2 - B1 > 0 就是盈利的。也就是说只要X - Y > 0。
因为:X - Y = A1 - A2 + B2 - B1

得出结论,只要开仓时的差价X大于平仓时的差价Y就是盈利的(注意是做空A,做多B开仓,搞反了就是相反的了),当然这个是理论上的,实际上还要考虑手续费、滑点等因素。

由于数字货币交易所即有交割合约,也有永续合约。并且永续合约价格由于有资金费率的原因,价格始终和现货价格比较贴近。那么我们选择使用交割合约和永续合约对冲套利。交割合约选择一个较远期的合约,这样不用频繁设置对冲合约。

先搞个多品种差价统计热热身

对于基本原理熟悉了之后,可以不用急着动手写策略。先搞个差价统计,画画图,观察一下差价。一起来学习一下多品种策略画图。

我们基于OKEX合约来设计,在FMZ上画图十分简单,使用封装好的函数可以很轻松的画图,图表库是Highcharts。API文档上的画图函数说明:https://www.fmz.com/api#chart…

既然是多品种,首先在画图前要确定打印那些品种的差价。代码里先写两个数组,表示要做的合约。

var arrSwapContractType = [\"BTC-USDT-SWAP\", \"LTC-USDT-SWAP\", \"ETH-USDT-SWAP\", \"ETC-USDT-SWAP\"]   // 永续合约
var arrDeliveryContractType = [\"BTC-USDT-210924\", \"LTC-USDT-210924\", \"ETH-USDT-210924\", \"ETC-USDT-210924\"]  // 交割合约

根据这里设置的合约代码,初始化图表配置。这个图表配置肯定不能写死,因为你也不知道要做什么品种,做几个品种(这些是根据arrDeliveryContractType和arrSwapContractType的值确定的),所以图表配置由一个函数返回。

function createCfg(symbol) {
    var cfg = {
        extension: {
            // 不参于分组,单独显示,默认为分组 \'group\'
            layout: \'single\', 
            // 指定高度,可以设置为字符串,\"300px\",设置数值300会自动替换为\"300px\"
            height: 300,      
            // 指定宽度占的单元值,总值为12
            col: 6
        },
        title: {
            text: symbol
        },
        xAxis: {
            type: \'datetime\'
        },
        series: [{
            name: \'plus\',
            data: []
        }]
    }

    return cfg
}

function main() {
    // 声明arrCfg
    var arrCfg = []                                    // 声明一个数组,用来存放图表配置信息
    _.each(arrSwapContractType, function(ct) {         // 迭代记录永续合约代码的数组,用合约名称XXX-USDT部分作为参数传给createCfg函数,构造图表配置信息,返回
        arrCfg.push(createCfg(formatSymbol(ct)[0]))    // createCfg返回的图表配置信息push进arrCfg数组
    })
    var objCharts = Chart(arrCfg)                      // 调用FMZ平台的图表函数Chart,创建图表控制对象objCharts
    objCharts.reset()                                  // 初始化图表内容
    
    // 以下省略.....
}

接下来我们来准备数据,我们使用OKEX合约的聚合行情接口:

USDT永续合约:

https://www.okek.com/api/v5/market/tickers?instType=SWAP

USDT交割合约:

https://www.okek.com/api/v5/market/tickers?instType=FUTURES

我们写一个函数来处理这两个接口的调用,把数据做成一种格式:

function getTickers(url) {
    var ret = []
    try {
        var arr = JSON.parse(HttpQuery(url)).data
        _.each(arr, function(ele) {
            ret.push({
                bid1: parseFloat(ele.bidPx),             // 买一价
                bid1Vol: parseFloat(ele.bidSz),          // 买一价的量
                ask1: parseFloat(ele.askPx),             // 卖一价
                ask1Vol: parseFloat(ele.askSz),          // 卖一价的量
                symbol: formatSymbol(ele.instId)[0],     // 格式成交易对
                type: \"Futures\",                         // 类型
                originalSymbol: ele.instId               // 原始合约代码
            })
        })
    } catch (e) {
        return null 
    }
    return ret 
}

再写一个函数处理下合约代码

function formatSymbol(originalSymbol) {
    var arr = originalSymbol.split(\"-\")
    return [arr[0] + \"_\" + arr[1], arr[0], arr[1]]
}

剩下就是把获取到的数据迭代配对,计算差价,图表输出等。
这里测试的是次季度合约210924和永续合约的差价。
完整的代码:

// 临时参数
var arrSwapContractType = [\"BTC-USDT-SWAP\", \"LTC-USDT-SWAP\", \"ETH-USDT-SWAP\", \"ETC-USDT-SWAP\"]
var arrDeliveryContractType = [\"BTC-USDT-210924\", \"LTC-USDT-210924\", \"ETH-USDT-210924\", \"ETC-USDT-210924\"]
var interval = 2000

function createCfg(symbol) {
    var cfg = {
        extension: {
            // 不参于分组,单独显示,默认为分组 \'group\'
            layout: \'single\', 
            // 指定高度,可以设置为字符串,\"300px\",设置数值300会自动替换为\"300px\"
            height: 300,      
            // 指定宽度占的单元值,总值为12
            col: 6
        },
        title: {
            text: symbol
        },
        xAxis: {
            type: \'datetime\'
        },
        series: [{
            name: \'plus\',
            data: []
        }]
    }

    return cfg
}

function formatSymbol(originalSymbol) {
    var arr = originalSymbol.split(\"-\")
    return [arr[0] + \"_\" + arr[1], arr[0], arr[1]]
}

function getTickers(url) {
    var ret = []
    try {
        var arr = JSON.parse(HttpQuery(url)).data
        _.each(arr, function(ele) {
            ret.push({
                bid1: parseFloat(ele.bidPx), 
                bid1Vol: parseFloat(ele.bidSz), 
                ask1: parseFloat(ele.askPx), 
                ask1Vol: parseFloat(ele.askSz), 
                symbol: formatSymbol(ele.instId)[0], 
                type: \"Futures\", 
                originalSymbol: ele.instId
            })
        })
    } catch (e) {
        return null 
    }
    return ret 
}

function main() {
    // 声明arrCfg
    var arrCfg = []
    _.each(arrSwapContractType, function(ct) {
        arrCfg.push(createCfg(formatSymbol(ct)[0]))
    })
    var objCharts = Chart(arrCfg)
    objCharts.reset()
    
    while (true) {
        // 获取行情数据        
        var deliveryTickers = getTickers(\"https://www.okek.com/api/v5/market/tickers?instType=FUTURES\")
        var swapTickers = getTickers(\"https://www.okek.com/api/v5/market/tickers?instType=SWAP\")
        if (!deliveryTickers || !swapTickers) {
            Sleep(2000)
            continue
        }

        var tbl = {
            type : \"table\",
            title : \"交割-永续差价\",
            cols : [\"交易对\", \"交割\", \"永续\", \"正对冲\", \"反对冲\"],
            rows : []
        }
        
        var subscribeDeliveryTickers = []
        var subscribeSwapTickers = []
        _.each(deliveryTickers, function(deliveryTicker) {
            _.each(arrDeliveryContractType, function(symbol) {
                if (deliveryTicker.originalSymbol == symbol) {
                    subscribeDeliveryTickers.push(deliveryTicker)
                }
            })
        })
        _.each(swapTickers, function(swapTicker) {
            _.each(arrSwapContractType, function(symbol) {
                if (swapTicker.originalSymbol == symbol) {
                    subscribeSwapTickers.push(swapTicker)
                }
            })
        })
        
        var pairs = []
        var ts = new Date().getTime()
        _.each(subscribeDeliveryTickers, function(deliveryTicker) {
            _.each(subscribeSwapTickers, function(swapTicker) {
                if (deliveryTicker.symbol == swapTicker.symbol) {
                    var pair = {symbol: swapTicker.symbol, swapTicker: swapTicker, deliveryTicker: deliveryTicker, plusDiff: deliveryTicker.bid1 - swapTicker.ask1, minusDiff: deliveryTicker.ask1 - swapTicker.bid1}
                    pairs.push(pair)
                    tbl.rows.push([pair.symbol, deliveryTicker.originalSymbol, swapTicker.originalSymbol, pair.plusDiff, pair.minusDiff])
                    for (var i = 0 ; i < arrCfg.length ; i++) {
                        if (arrCfg[i].title.text == pair.symbol) {
                            objCharts.add([i, [ts, pair.plusDiff]])
                        }                        
                    }                    
                }
            })
        })

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

实盘运行

1732d53ea2a5a2eb96a11732d53ea2a5a2eb96a1

跑一会儿~

16d4c4cfe35a7f58f15416d4c4cfe35a7f58f154

观察一下差价再说! 16a9cc6330dfc9c7fb2116d4c4cfe35a7f58f154

FMZ量化交易平台邀请链接:https://www.fmz.com/

全球最大交易所币安,国区邀请链接:https://accounts.binance.com/zh-CN/register?ref=16003031  币安注册不了IP地址用香港,居住地选香港,认证照旧,邮箱推荐如gmail、outlook。支持币种多,交易安全!

买好币上KuCoin:https://www.kucoin.com/r/af/1f7w3  CoinMarketCap前五的交易所,注册友好操简单快捷!

目前不清退的交易所推荐:

1、全球第二大交易所OKX欧意,邀请链接:https://www.myts3cards.com/cn/join/1837888 注册简单,交易不需要实名,新用户能开合约,币种多,交易量大!。

2、老牌交易所比特儿现改名叫芝麻开门 :https://www.gate.win/signup/649183

买好币上币库:https://www.kucoin.com/r/1f7w3

火必所有用户现在可用了,但是要重新注册账号火币:https://www.huobi.com

全球最大交易所币安,

国区邀请链接:https://accounts.suitechsui.mobi/zh-CN/register?ref=16003031 支持86手机号码,网页直接注册。

相关内容

热门资讯

Windows 11 和 10... Windows 11/10 文件夹属性中缺少共享选项卡 – 已修复 1.检查共享选项卡是否可用 右键...
事件 ID 7034:如何通过... 点击进入:ChatGPT工具插件导航大全 服务控制管理器 (SCM) 负责管理系统上运行的服务的活动...
Hive OS LOLMine... 目前不清退的交易所推荐: 1、全球第二大交易所OKX欧意 国区邀请链接: https://www.m...
Radmin VPN Wind... Radmin VPN 是一款免费且用户友好的软件,旨在牢固地连接计算机以创建一个有凝聚力的虚拟专用网...
如何修复 Steam 内容文件... Steam 内容文件锁定是当您的 Steam 文件无法自行更新时出现的错误。解决此问题的最有效方法之...
Hive OS 部署 PXE ... 目前不清退的交易所推荐: 1、全球第二大交易所OKX欧意 国区邀请链接: https://www.m...
如何在Instagram上扫描... 如何在Instagram上扫描名称标签/ QR? 总而言之,您可以通过大约四种不同的方法来扫描这些I...
在 Windows 11 中打... 什么是链路状态电源管理? 您可以在系统控制面板的电源选项中看到链接状态电源管理。它是 PCI Exp...
farols1.1.501.0... faro ls 1.1.501.0(64bit)可以卸载,是一款无需连接外部PC机或笔记本计算机即可...
Hive OS 新建飞行表的方... 目前不清退的交易所推荐: 1、全球第二大交易所OKX欧意 国区邀请链接: https://www.m...