وسائل لوڈ ہو رہے ہیں... لوڈنگ...

ابتدائی، اسے چیک کریں آپ کو کریپٹوکرنسی کی کوانٹیٹیٹیو ٹریڈنگ میں لے جائیں (8)

مصنف:نینا باداس, تخلیق: 2022-04-22 14:32:14, تازہ کاری:

ابتدائی، اسے چیک کریں آپ کو کریپٹوکرنسی کی کوانٹیٹیٹیو ٹریڈنگ میں لے جائیں (8)

پچھلے مضمون میں ، ہم نے مل کر ایک ملٹی علامت معاہدہ پھیلاؤ مانیٹرنگ حکمت عملی تیار کی۔ اس مضمون میں ، ہم اس خیال کو بہتر بناتے رہیں گے۔ آئیے دیکھتے ہیں کہ آیا یہ خیال قابل عمل ہے ، اور حکمت عملی کے ڈیزائن کی تصدیق کے لئے OKEX V5 تخروپن بوٹ کے ساتھ چلائیں۔ یہ عمل بھی cryptocurrency پروگرام شدہ تجارت اور مقداری تجارت کے عمل میں تجربہ کرنے کی ضرورت ہے۔ مجھے امید ہے کہ آپ اس سے قیمتی تجربہ جمع کرسکتے ہیں۔

سپوئلر: حکمت عملی چل رہی ہے، جو کہ تھوڑا سا دلچسپ ہے.

img

img

img

حکمت عملی کا مجموعی ڈیزائن سب سے آسان خیال کے ذریعہ نافذ کیا جاتا ہے۔ اگرچہ تفصیلات کی پروسیسنگ کی کوئی سخت ضرورت نہیں ہے ، لیکن آپ کو ابھی بھی کوڈ سے کچھ چالیں سیکھنی پڑتی ہیں۔ پوری حکمت عملی 400 لائنوں سے بھی کم ہے ، لہذا اسے پڑھنا بہت بورنگ نہیں ہے۔ یقینا ، یہ صرف ٹیسٹ کے لئے ایک ڈیمو ہے ، اور ہمیں نتیجہ دیکھنے کے لئے تھوڑی دیر کے لئے اسے چلانے کی ضرورت ہے۔ میں کیا کہنا چاہتا ہوں: موجودہ حکمت عملی صرف کھلی پوزیشنوں میں کامیاب ہے ، اور مختلف حالات ہیں ، جیسے بند پوزیشنیں ، جو اصل میں جانچ اور پتہ لگانے کے لئے ہیں۔ پروگرام کے ڈیزائن میں کیڑے ناگزیر ہیں ، لہذا جانچ اور ڈیبگنگ بہت اہم ہیں!

پچھلے مضمون کے کوڈ کی بنیاد پر حکمت عملی کے ڈیزائن میں واپس، میں نے شامل کیا ہے:

  • ڈیٹا استحکام ڈیزائن (فنکشن _G کا استعمال کرتے ہوئے ڈیٹا کو ذخیرہ کرنے کے لئے، اور دوبارہ شروع کرنے کے بعد ڈیٹا کو بحال کرنے کے لئے) ۔
  • ہر مانیٹر شدہ معاہدے کے پھیلاؤ کے جوڑے میں گرڈ ڈیٹا ڈھانچے کا اضافہ (پوسشن بند کرنے کے لئے ہیجنگ کو کنٹرول کرنے کے لئے) ۔
  • ہیجنگ کے ذریعے پوزیشن کھولنے یا بند کرنے کے لیے ایک سادہ ہیجنگ فنکشن کا نفاذ۔
  • متغیر منافع اور نقصان کا حساب کرنے کے لئے مجموعی سرمایہ حاصل کرنے کا ایک فنکشن شامل کرنا۔
  • ریاست بار ڈیٹا برآمد کرنے کے کچھ دکھاتا ہے کا اضافہ.

مندرجہ بالا افعال شامل ہیں۔ آسان ہونے کے ل the ، حکمت عملی نے صرف مثبت ہیجنگ (طویل مدتی معاہدے کے لئے مختصر بنائیں؛ مختصر مدت کے معاہدے کے لئے طویل بنائیں) کو ڈیزائن کیا ہے۔ فی الحال ، دائمی معاہدے (مختصر مدت) کی مالی اعانت کی شرح منفی ہے۔ صرف دائمی معاہدے میں بنائیں ، یہ دیکھنے کے لئے کہ آیا مالی اعانت کی شرح کی واپسی میں اضافہ کیا جاسکتا ہے۔

کچھ دیر کے لئے حکمت عملی چلنے دو.

یہ تقریبا 3 دنوں کے لئے تجربہ کیا گیا ہے، اور پھیلاؤ اتار چڑھاؤ اصل میں ٹھیک ہیں.

img

img

img

فنڈنگ کی شرح سے منافع کا حصہ مندرجہ ذیل تصویر میں دیکھا جاسکتا ہے۔

img

حکمت عملی کا ماخذ کوڈ مندرجہ ذیل طور پر مشترکہ ہے:

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) {  // the price cannot be less than or equal to 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)  // switch to the simulated environment 
    	Log("Only support OKEX V5 API, and switch to OKEX V5 simulated bot:")
    } else {
    	exchange.IO("simulate", false)  // switch to the bot
    	Log("Only support OKEX V5 API, and switch to OKEX V5 bot:")
    }    
    if (exchange.GetName() != "Futures_OKCoin") {
    	throw "support OKEX Futures"
    }

    // initialize
    if (isReset) {
        _G(null)
        LogReset(1)
        LogProfitReset()
        LogVacuum()
        Log("reset all data", "#FF0000")
    }

    // initialize the mark 
    var isFirst = true 

    // the profit prints the period 
    var preProfitPrintTS = 0
    // the total equity 
    var totalEquity = 0
    var posTbls = []   // the array of position table 

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

    // write the contracts to be subscribed in advance 
    _.each(arrNearContractType, function(ct) {
        nearEx.pushSubscribeSymbol(ct)
    })
    _.each(arrFarContractType, function(ct) {
        farEx.pushSubscribeSymbol(ct)
    })

    while (true) {
        var ts = new Date().getTime()
        // obtain the market quotes 
        nearEx.goGetTickers()
        farEx.goGetTickers()
        var nearTickers = nearEx.getTickers()
        var farTickers = farEx.getTickers()  
        if (!farTickers || !nearTickers) {
            Sleep(2000)
            continue
        }

        var tbl = {
            type : "table",
            title : "long-short term spread",
            cols : ["trading pair", "long term", "shaort term", "positive hedge", "negative hedge"],
            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]])
                        }                        
                    }
                }
            })
        })

        // initialize 
        if (isFirst) {
            isFirst = false 
            var recoveryNets = _G("nets")
            var recoveryInitTotalEquity = _G("initTotalEquity")
            if (!recoveryNets) {
                // detect positions 
                _.each(subscribeFarTickers, function(farTicker) {
                    var pos = farEx.getFuPos(farTicker.originalSymbol, ts)
                    if (pos.length != 0) {
                        Log(farTicker.originalSymbol, pos)
                        throw "There are positions during the initialization"
                    }
                })
                _.each(subscribeNearTickers, function(nearTicker) {
                    var pos = nearEx.getFuPos(nearTicker.originalSymbol, ts)
                    if (pos.length != 0) {
                        Log(nearTicker.originalSymbol, pos)
                        throw "There are positions during the initialization"
                    }
                })                
                // construct 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 "Fail to obtain the total equity by initialization!"
                }                
            } else {
                // recover 
                nets = recoveryNets
                initTotalEquity = recoveryInitTotalEquity
            }
        }

        // query the grid, to detect whether a trade is triggered 
        _.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("not detected", obj.symbol, "spread")
                return 
            }

            // examine the grid; dynamically add
            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,
                })
            }
            
            // detect grid
            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)) {   // positive hedge, open positions  
                        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)) {   // positive hedge, close positions 
                        upP.sell = false 
                    }
                }
            }
            obj.prePlus = currPlus  // record the spread of the time, as cache, which will be used to judge upcross or downcross for the next time  
            // add other tables to export  
        })        

        if (ts - preProfitPrintTS > 1000 * 60 * 5) {   // print every 5 minutes        
        	var currTotalEquity = getTotalEquity()
        	if (currTotalEquity) {
        		totalEquity = currTotalEquity
        		LogProfit(totalEquity - initTotalEquity, "&")   // print the dynamic profit of equity 
        	}

        	// detect positions 
        	posTbls = []  // reset and update 
            _.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" : ["contract code", "amount", "price"], 
                	"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
        }

        // display the grid 
        var netTbls = []
        _.each(nets, function(obj) {
            var netTbl = {
            	"type" : "table",
            	"title" : obj.symbol,
            	"cols" : ["grid"],
            	"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(), "total equity:", totalEquity, "initial equity:", initTotalEquity, "floating profit and loss: ", 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("Fail to obtain the total equity of the account!")
        	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, "Wrong calculation of the order amount:", 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("execute the onexit function", "#FF0000")
    _G("nets", nets)
    _G("initTotalEquity", initTotalEquity)
    Log("Save data:", _G("nets"), _G("initTotalEquity"))
}

img

حکمت عملی کا پتہ:https://www.fmz.com/strategy/288559

حکمت عملی میں نے خود سے تیار کردہ ٹیمپلیٹس میں سے ایک کا استعمال کیا ہے۔ ٹیمپلیٹ یہاں دکھانے کے لئے کافی اچھا نہیں ہے ، لہذا آپ حکمت عملی کے ماخذ کوڈ کو تھوڑا سا تبدیل کرکے ایک اور ٹیمپلیٹ استعمال کرسکتے ہیں۔

اگر آپ دلچسپی رکھتے ہیں تو، آپ OKEX V5 مشابہ بوٹ میں حکمت عملی چلا سکتے ہیں. اوہ، صحیح، حکمت عملی backtested نہیں کیا جا سکتا!


مزید