Các giao dịch định lượng vòng đồng xu trông rất mới mẻ - đưa bạn đến gần với các giao dịch định lượng vòng đồng xu.

Tác giả:Giấc mơ nhỏ, Tạo: 2021-06-18 18:24:23, Cập nhật: 2023-09-19 21:40:46

img

Các giao dịch định lượng vòng đồng tiền mới nhìn thấy đưa bạn đến gần vòng đồng tiền định lượng ((8))

Trong bài viết trước, chúng tôi đã cùng nhau thiết kế một chiến lược giám sát chênh lệch giá hợp đồng đa dạng, bài viết này tiếp tục hoàn thiện ý tưởng này. Để xem ý tưởng này có khả thi hay không, và chạy thử nghiệm và xác minh chiến lược với OKEX V5 để xác minh các chiến lược.

Trước khi diễn ra, chiến thuật đã chạy lên, một chút phấn khích!

img

img

img

Chiến lược tổng thể được thiết kế theo cách đơn giản nhất, mặc dù không quá đòi hỏi phải xử lý chi tiết, nhưng vẫn có thể học được một số kỹ thuật nhỏ từ mã. Chiến lược toàn bộ dưới 400 dòng mã, đọc và hiểu sẽ không quá nhàm chán. Tất nhiên đây chỉ là một thử nghiệm DEMO, cần chạy thử nghiệm một thời gian.

Trở lại với thiết kế chiến lược, dựa trên mã trong bài viết trước, thêm vào chiến lược:

  • Thiết kế lâu dài dữ liệu ((làm việc lưu dữ liệu bằng hàm _G, có thể khôi phục dữ liệu sau khi khởi động lại)
  • Tăng cấu trúc dữ liệu lưới (được sử dụng để kiểm soát việc mở sàn) cho mỗi cặp hợp đồng theo dõi
  • Thực hiện một chức năng đầu cơ đơn giản để đầu cơ mở
  • Thêm một hàm thu lợi nhuận tổng thể để tính toán lợi nhuận và lỗ lưu động
  • Thêm một số màn hình xuất dữ liệu trạng thái.

Trên đây là tính năng được thêm vào, để đơn giản hóa thiết kế, chiến lược chỉ được thiết kế để làm cho các khoản đầu tư tích cực (không hợp đồng dài hạn, nhiều hợp đồng ngắn hạn); hợp đồng lâu dài hiện tại (gần hạn) là tỷ lệ tiêu cực, làm cho nhiều hợp đồng lâu dài, xem có thể có lợi nhuận trong việc tăng tỷ lệ phí điểm.

Hãy để chiến thuật chạy một chút.

Sau khi thử nghiệm khoảng 3 ngày, sự biến động của giá vẫn ổn.

img

img

img

Có thể thấy một số lợi nhuận từ tỷ lệ vốn.

img

Hãy chia sẻ mã nguồn của chiến lược dưới đây:

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

Các chiến lược được công bố tại:https://www.fmz.com/strategy/288559

Chính sách sử dụng một thư viện lớp mẫu mà tôi đã viết, và vì không được công khai, mã nguồn chính sách trên có thể được sửa đổi mà không sử dụng mẫu này.

Những người quan tâm có thể gắn một OKEX V5 thử nghiệm đĩa. Ồ! Đúng vậy, chiến thuật này không thể kiểm tra lại được.


Có liên quan

Thêm nữa

wbe3- Bánh nướng nhỏSau hai năm, DreamHost đã thiết lập chiến lược này để đặt các cặp giao dịch khác nhau, số lượng đầu tư khác nhau.

chaoTôi đã thay đổi nó thành Binance, nhưng phần mềm đó không biết cách vận hành OK, và phần mềm đó vẫn chưa thành công.

Động vật quỹ đạoLàm thế nào để chạy trên ok Analog Disc. Tôi không thể chạy với plugin đó.

Giấc mơ nhỏ`` // tuyên bố arrCfg var arrCfg = [] _.each ((arrNearContractType, function ((ct) { arrCfg.push ((createCfg ((formatSymbol ((ct) [0])) ) `` Làm tương tự với đối số hedgeAmount, thiết kế đối số này thành một chuỗi giống như: 100, 200, 330.

Giấc mơ nhỏTrong trường hợp này, một thư viện mẫu được sử dụng và không công khai.

Giấc mơ nhỏPlugin nào?