Sumber dimuat naik... memuat...

Perdagangan kuantitatif dalam lingkaran mata wang adalah sesuatu yang baru - membawa anda lebih dekat kepada kuantitatif dalam lingkaran mata wang (8).

Penulis:Pencipta Kuantiti - Impian Kecil, Dicipta: 2021-06-18 18:24:23, Dikemas kini: 2023-09-19 21:40:46

img

Perdagangan kuantitatif lingkaran wang yang baru muncul untuk membawa anda lebih dekat dengan kuantitatif lingkaran wang.

Dalam artikel sebelumnya, kami telah merancang strategi pemantauan perbezaan kontrak pelbagai jenis, dan dalam artikel ini kami terus menyempurnakan idea ini. Mari lihat apakah idea ini boleh dilaksanakan, dan gunakan simulasi OKEX V5 untuk memverifikasi reka bentuk strategi. Proses-proses ini juga diperlukan untuk melakukan perdagangan berprogram mata wang digital, proses dagangan kuantitatif, dan kami berharap para pemula dapat mengumpulkan pengalaman yang berharga.

Sebelum berlakon, strategi telah berjalan, sedikit kegembiraan!

img

img

img

Strategi keseluruhan direka untuk dilaksanakan dengan cara yang paling mudah, walaupun tidak terlalu mencabar untuk memproses butiran, tetapi masih boleh belajar beberapa teknik kecil dari kod. Strategi kod keseluruhan kurang dari 400 baris, membaca dan memahami tidak akan menjadi membosankan. Sudah tentu ini hanya ujian DEMO, perlu menjalankan beberapa masa untuk menguji. Jadi saya akan mengatakan: pada masa ini strategi hanya membuka kedudukan yang berjaya, dan kedudukan rata dan sebagainya pelbagai keadaan untuk ujian ujian ujian sebenar, BUG tidak dapat dielakkan dalam reka bentuk program, jadi ujian, DEBUG (kesalahan) adalah penting!

Kembali ke reka bentuk strategi, berdasarkan kod di artikel sebelumnya, strategi ditambah dengan:

  • Reka bentuk kekekalan data (menggunakan fungsi _G untuk menyimpan data dan memulihkan data selepas memulakan semula)
  • Untuk setiap pasangan kontrakan yang dipantau, struktur data grid ditambahkan (untuk mengawal hedging)
  • Mengimplementasikan fungsi lindung nilai yang mudah untuk lindung nilai untuk membuka kedudukan
  • Tambah fungsi capaian keuntungan untuk mengira keuntungan dan kerugian terapung
  • Tambah beberapa output data status tab.

Ini adalah fungsi tambahan, untuk memudahkan reka bentuk, strategi ini hanya direka untuk menjadi lindung nilai positif (kontrak jangka panjang kosong, kontrak jangka pendek); kontrak kekal semasa (kontrak jangka pendek) adalah kadar negatif, lebih baik buat kontrak kekal untuk melihat apakah anda boleh memperoleh keuntungan dalam meningkatkan kadar titik.

Mari kita letakkan strategi ini untuk seketika.

Saya telah menguji ia selama kira-kira 3 hari dan harga yang berbeza adalah benar-benar baik.

img

img

img

Di sini, anda boleh melihat beberapa faedah dari kadar dana.

img

Di bawah ini, berkongsi kod sumber strategi:

var arrNearContractType = strNearContractType.split(",")
var arrFarContractType = strFarContractType.split(",")

var nets = null
var initTotalEquity = null 
var OPEN_PLUS = 1
var COVER_PLUS = 2


function createNet(begin, diff, initAvgPrice, diffUsagePercentage) {
    if (diffUsagePercentage) {
        diff = diff * initAvgPrice
    }
    var oneSideNums = 3
    var up = []
    var down = []
    for (var i = 0 ; i < oneSideNums ; i++) {
        var upObj = {
            sell : false, 
            price : begin + diff / 2 + i * diff
        }
        up.push(upObj)

        var j = (oneSideNums - 1) - i
        var downObj = {
            sell : false,
            price : begin - diff / 2 - j * diff
        }
        if (downObj.price <= 0) {  // 价格不能小于等于0 
            continue
        }
        down.push(downObj)
    }
    return down.concat(up)
}

function createCfg(symbol) {
    var cfg = {
        extension: {
            layout: 'single', 
            height: 300,
            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 main() {	
    if (isSimulate) {
    	exchange.IO("simulate", true)  // 切换为模拟环境
    	Log("仅支持OKEX V5 API,切换为OKEX V5 模拟盘:")
    } else {
    	exchange.IO("simulate", false)  // 切换为实盘
    	Log("仅支持OKEX V5 API,切换为OKEX V5 实盘:")
    }    
    if (exchange.GetName() != "Futures_OKCoin") {
    	throw "支持OKEX期货"
    }

    // 初始化
    if (isReset) {
        _G(null)
        LogReset(1)
        LogProfitReset()
        LogVacuum()
        Log("重置所有数据", "#FF0000")
    }

    // 初始化标记
    var isFirst = true 

    // 收益打印周期
    var preProfitPrintTS = 0
    // 总权益
    var totalEquity = 0
    var posTbls = []   // 持仓表格数组

    // 声明arrCfg
    var arrCfg = []
    _.each(arrNearContractType, function(ct) {
        arrCfg.push(createCfg(formatSymbol(ct)[0]))
    })
    var objCharts = Chart(arrCfg)
    objCharts.reset()
    
    // 创建对象
    var exName = exchange.GetName() + "_V5"
    var nearConfigureFunc = $.getConfigureFunc()[exName]
    var farConfigureFunc = $.getConfigureFunc()[exName]
    var nearEx = $.createBaseEx(exchange, nearConfigureFunc)
    var farEx = $.createBaseEx(exchange, farConfigureFunc)

    // 预先写入需要订阅的合约
    _.each(arrNearContractType, function(ct) {
        nearEx.pushSubscribeSymbol(ct)
    })
    _.each(arrFarContractType, function(ct) {
        farEx.pushSubscribeSymbol(ct)
    })

    while (true) {
        var ts = new Date().getTime()
        // 获取行情数据
        nearEx.goGetTickers()
        farEx.goGetTickers()
        var nearTickers = nearEx.getTickers()
        var farTickers = farEx.getTickers()  
        if (!farTickers || !nearTickers) {
            Sleep(2000)
            continue
        }

        var tbl = {
            type : "table",
            title : "远期-近期差价",
            cols : ["交易对", "远期", "近期", "正对冲", "反对冲"],
            rows : []
        }        
        
        var subscribeFarTickers = []
        var subscribeNearTickers = []
        _.each(farTickers, function(farTicker) {
            _.each(arrFarContractType, function(symbol) {
                if (farTicker.originalSymbol == symbol) {
                    subscribeFarTickers.push(farTicker)
                }
            })
        })

        _.each(nearTickers, function(nearTicker) {
            _.each(arrNearContractType, function(symbol) {
                if (nearTicker.originalSymbol == symbol) {
                    subscribeNearTickers.push(nearTicker)
                }
            })
        })

        var pairs = []        
        _.each(subscribeFarTickers, function(farTicker) {
            _.each(subscribeNearTickers, function(nearTicker) {                
                if (farTicker.symbol == nearTicker.symbol) {
                    var pair = {symbol: nearTicker.symbol, nearTicker: nearTicker, farTicker: farTicker, plusDiff: farTicker.bid1 - nearTicker.ask1, minusDiff: farTicker.ask1 - nearTicker.bid1}
                    pairs.push(pair)
                    tbl.rows.push([pair.symbol, farTicker.originalSymbol, nearTicker.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]])
                        }                        
                    }
                }
            })
        })

        // 初始化
        if (isFirst) {
            isFirst = false 
            var recoveryNets = _G("nets")
            var recoveryInitTotalEquity = _G("initTotalEquity")
            if (!recoveryNets) {
                // 检查持仓
                _.each(subscribeFarTickers, function(farTicker) {
                    var pos = farEx.getFuPos(farTicker.originalSymbol, ts)
                    if (pos.length != 0) {
                        Log(farTicker.originalSymbol, pos)
                        throw "初始化时有持仓"
                    }
                })
                _.each(subscribeNearTickers, function(nearTicker) {
                    var pos = nearEx.getFuPos(nearTicker.originalSymbol, ts)
                    if (pos.length != 0) {
                        Log(nearTicker.originalSymbol, pos)
                        throw "初始化时有持仓"
                    }
                })                
                // 构造nets
                nets = []
                _.each(pairs, function (pair) {
                    farEx.goGetAcc(pair.farTicker.originalSymbol, ts)
                    nearEx.goGetAcc(pair.nearTicker.originalSymbol, ts)
                    var obj = {
                        "symbol" : pair.symbol, 
                        "farSymbol" : pair.farTicker.originalSymbol,
                        "nearSymbol" : pair.nearTicker.originalSymbol,
                        "initPrice" : (pair.nearTicker.ask1 + pair.farTicker.bid1) / 2, 
                        "prePlus" : pair.farTicker.bid1 - pair.nearTicker.ask1,                        
                        "net" : createNet((pair.farTicker.bid1 - pair.nearTicker.ask1), diff, (pair.nearTicker.ask1 + pair.farTicker.bid1) / 2, true), 
                        "initFarAcc" : farEx.getAcc(pair.farTicker.originalSymbol, ts), 
                        "initNearAcc" : nearEx.getAcc(pair.nearTicker.originalSymbol, ts),
                        "farTicker" : pair.farTicker,
                        "nearTicker" : pair.nearTicker,
                        "farPos" : null, 
                        "nearPos" : null,
                    }
                    nets.push(obj)
                })
                var currTotalEquity = getTotalEquity()
                if (currTotalEquity) {
                	initTotalEquity = currTotalEquity
                } else {
                	throw "初始化获取总权益失败!"
                }                
            } else {
                // 恢复
                nets = recoveryNets
                initTotalEquity = recoveryInitTotalEquity
            }
        }

        // 检索网格,检查是否触发交易
        _.each(nets, function(obj) {
            var currPlus = null
            _.each(pairs, function(pair) {
                if (pair.symbol == obj.symbol) {
                    currPlus = pair.plusDiff
                    obj.farTicker = pair.farTicker
                    obj.nearTicker = pair.nearTicker
                }
            })
            if (!currPlus) {
                Log("没有查询到", obj.symbol, "的差价")
                return 
            }

            // 检查网格,动态添加
            while (currPlus >= obj.net[obj.net.length - 1].price) {
                obj.net.push({
                    sell : false,
                    price : obj.net[obj.net.length - 1].price + diff * obj.initPrice,
                })
            }
            while (currPlus <= obj.net[0].price) {
                var price = obj.net[0].price - diff * obj.initPrice
                if (price <= 0) {
                    break
                }
                obj.net.unshift({
                    sell : false,
                    price : price,
                })
            }
            
            // 检索网格
            for (var i = 0 ; i < obj.net.length - 1 ; i++) {
                var p = obj.net[i]
                var upP = obj.net[i + 1]
                if (obj.prePlus <= p.price && currPlus > p.price && !p.sell) {
                    if (hedge(nearEx, farEx, obj.nearSymbol, obj.farSymbol, obj.nearTicker, obj.farTicker, hedgeAmount, OPEN_PLUS)) {   // 正对冲开仓
                        p.sell = true 
                    }
                } else if (obj.prePlus >= p.price && currPlus < p.price && upP.sell) {
                    if (hedge(nearEx, farEx, obj.nearSymbol, obj.farSymbol, obj.nearTicker, obj.farTicker, hedgeAmount, COVER_PLUS)) {   // 正对冲平仓
                        upP.sell = false 
                    }
                }
            }
            obj.prePlus = currPlus  // 记录本次差价,作为缓存,下次用于判断上穿下穿
            // 增加其它表格输出
        })        

        if (ts - preProfitPrintTS > 1000 * 60 * 5) {   // 5分钟打印一次       
        	var currTotalEquity = getTotalEquity()
        	if (currTotalEquity) {
        		totalEquity = currTotalEquity
        		LogProfit(totalEquity - initTotalEquity, "&")   // 打印动态权益收益
        	}

        	// 检查持仓
        	posTbls = []  // 重置,更新
            _.each(nets, function(obj) {
                var currFarPos = farEx.getFuPos(obj.farSymbol)
                var currNearPos = nearEx.getFuPos(obj.nearSymbol)
                if (currFarPos && currNearPos) {
                	obj.farPos = currFarPos
                	obj.nearPos = currNearPos
                }
                var posTbl = {
                	"type" : "table", 
                	"title" : obj.symbol, 
                	"cols" : ["合约代码", "数量", "价格"], 
                	"rows" : [] 
                }
                _.each(obj.farPos, function(pos) {
                    posTbl.rows.push([pos.symbol, pos.amount, pos.price])
                })  
                _.each(obj.nearPos, function(pos) {
                	posTbl.rows.push([pos.symbol, pos.amount, pos.price])
                })
                posTbls.push(posTbl)
            })

            preProfitPrintTS = ts
        }

        // 显示网格
        var netTbls = []
        _.each(nets, function(obj) {
            var netTbl = {
            	"type" : "table",
            	"title" : obj.symbol,
            	"cols" : ["网格"],
            	"rows" : []
            }
            _.each(obj.net, function(p) {
            	var color = ""
            	if (p.sell) {
            		color = "#00FF00"
            	}
            	netTbl.rows.push([JSON.stringify(p) + color])
            })
            netTbl.rows.reverse()
            netTbls.push(netTbl)
        })

        LogStatus(_D(), "总权益:", totalEquity, "初始总权益:", initTotalEquity, " 浮动盈亏:", totalEquity - initTotalEquity, 
        	"\n`" + JSON.stringify(tbl) + "`" + "\n`" + JSON.stringify(netTbls) + "`" + "\n`" + JSON.stringify(posTbls) + "`")
        Sleep(interval)
    }
}

function getTotalEquity() {
    var totalEquity = null 
    var ret = exchange.IO("api", "GET", "/api/v5/account/balance", "ccy=USDT")
    if (ret) {
        try {
        	totalEquity = parseFloat(ret.data[0].details[0].eq)
        } catch(e) {
        	Log("获取账户总权益失败!")
        	return null
        }
    }
    return totalEquity
}

function hedge(nearEx, farEx, nearSymbol, farSymbol, nearTicker, farTicker, amount, tradeType) {
    var farDirection = null
    var nearDirection = null
    if (tradeType == OPEN_PLUS) {
        farDirection = farEx.OPEN_SHORT
        nearDirection = nearEx.OPEN_LONG
    } else {
        farDirection = farEx.COVER_SHORT
        nearDirection = nearEx.COVER_LONG
    }
    var nearSymbolInfo = nearEx.getSymbolInfo(nearSymbol) 
    var farSymbolInfo = farEx.getSymbolInfo(farSymbol)
    nearAmount = nearEx.calcAmount(nearSymbol, nearDirection, nearTicker.ask1, amount * nearSymbolInfo.multiplier)
    farAmount = farEx.calcAmount(farSymbol, farDirection, farTicker.bid1, amount * farSymbolInfo.multiplier)
    if (!nearAmount || !farAmount) {
        Log(nearSymbol, farSymbol, "下单量计算错误:", nearAmount, farAmount)
        return 
    }
    nearEx.goGetTrade(nearSymbol, nearDirection, nearTicker.ask1, nearAmount[0])
    farEx.goGetTrade(farSymbol, farDirection, farTicker.bid1, farAmount[0])
    var nearIdMsg = nearEx.getTrade()
    var farIdMsg = farEx.getTrade()
    return [nearIdMsg, farIdMsg]
}

function onexit() {
	Log("执行扫尾函数", "#FF0000")
    _G("nets", nets)
    _G("initTotalEquity", initTotalEquity)
    Log("保存数据:", _G("nets"), _G("initTotalEquity"))
}

img

Kaedah terbuka di:https://www.fmz.com/strategy/288559

Kaedah ini menggunakan perpustakaan kelas templat yang saya tulis sendiri, dan sumber kod kaedah di atas boleh diubah tanpa menggunakan templat ini.

Jika berminat, boleh pasang OKEX V5 untuk ujian. Oh! Betul, strategi ini tidak boleh diuji semula ~


Berkaitan

Lebih lanjut

N95Dalam tempoh dua tahun, DreamHost telah menyusun strategi untuk menetapkan pasangan yang berbeza, jumlah yang berbeza dari kedudukan yang dibuka.

ChaoSaya telah mengubahnya menjadi Binance, tetapi saya tidak tahu bagaimana untuk mengoperasikannya, dan saya tidak berjaya.

Makhluk orbitBagaimana saya boleh menjalankan pada cakera analog ok. Saya tidak boleh menggunakan pemalam itu.

Pencipta Kuantiti - Impian Kecil`` // Perisytiharan arrCfg var arrCfg = [] _.each ((arrNearContractType, function ((ct) { arrCfg.push ((createCfg(formatSymbol ((ct) [0])) {C:$0000FF} `` Perlakukan parameter hedgeAmount dengan cara yang sama, reka bentuk parameter ini sebagai satu senar seperti: 100, 200, 330; sehingga 100 sepadan dengan kombinasi lindung nilai pertama, dan kemudian digunakan secara khusus.

Pencipta Kuantiti - Impian KecilBorang ini boleh dibungkus sendiri, contohnya menggunakan perpustakaan kelas templat, tidak terbuka.

Pencipta Kuantiti - Impian KecilApakah pluginnya?