एफएमजेड पर आधारित क्वांटिफाइड ऑर्डर सिंक्रनाइज़ेशन मैनेजमेंट सिस्टम डिजाइन (1)

लेखक:छोटे सपने, बनाया गयाः 2022-02-14 19:46:30, अद्यतन किया गयाः 2023-09-15 20:44:11

img

एफएमजेड पर आधारित क्वांटिफाइड ऑर्डर सिंक्रनाइज़ेशन मैनेजमेंट सिस्टम डिजाइन (1)

एफएमजेड के पिछले लेखों में, हमने कई ऑर्डर और स्टॉक सिंक रणनीतियों को डिज़ाइन किया है।

ये संदर्भ खाते और समन्वित खाते को एक रणनीति में रखते हुए ऑर्डर निष्पादन, स्टॉक समन्वित का प्रबंधन करते हैं। आज हम थोड़ा अलग डिजाइन का प्रयास करेंगे, एफएमजेड क्वांटिफाइड ट्रेडिंग प्लेटफॉर्म के शक्तिशाली विस्तार एपीआई इंटरफ़ेस पर आधारित, हम एक ऑर्डर समन्वित प्रबंधन प्रणाली डिजाइन करेंगे।

डिजाइन विचार

सबसे पहले, हमें कुछ अच्छे सुझावों की आवश्यकता है, आवश्यकताएं हैं। दो पिछले ऑर्डर, स्टॉक सिंक रणनीति के लिए कुछ स्पष्ट दर्द बिंदु हैं, आइए एक साथ चर्चा करेंः

  • 1, समवर्ती रणनीति के कार्यान्वयनकर्ता को संदर्भ खाते के लिए एक्सचेंज एपीआई की, समवर्ती खाते के लिए एक्सचेंज एपीआई की होना चाहिए। यह उपयोग परिदृश्य के लिए एक समस्या हैः अपने अन्य एक्सचेंज खाते के साथ अपने खाते का अनुसरण करना ठीक है; लेकिन संदर्भ खाते और सिंक्रनाइज़ेशन खाते के लिए एक मालिक के बिना परिदृश्य मुश्किल हो सकता है; सिंक्रनाइज़ेशन खाते के मालिक कभी-कभी सुरक्षा कारणों के लिए अपने एक्सचेंज खाते के एपीआई कुंजी प्रदान करने के लिए अनिच्छुक होते हैं; लेकिन एपीआई कुंजी प्रदान किए बिना एकल लेनदेन कैसे करें?

    समाधानः एफएमजेड के विस्तार एपीआई इंटरफ़ेस का उपयोग करके, सिंक खाते के मालिकों (अनुयायियों) को केवल एफएमजेड क्वांटिफाइड ट्रेडिंग प्लेटफॉर्म के लिए पंजीकरण करने की आवश्यकता होती है, और फिर सिस्टम में से एक रणनीति (इस लेख के लिए डिज़ाइन की गई) को चलाने की आवश्यकता होती हैः订单同步管理系统(Synchronous Server)फिर FMZ के विस्तार API KEY (ध्यान दें, एक्सचेंज खाते के लिए नहीं) और ऑर्डर सिंक्रोनस सर्वर (Synchronous Server) के लिए संदर्भ खाते के मालिकों को प्रदान किया जा सकता है। जब संदर्भ खाता धारक (बैंड धारक) के वास्तविक डिस्क (इस प्रणाली के लिए डिज़ाइन)订单同步管理系统类库(Single Server)) सिग्नल भेजता है, सिंक खाताधारक के वास्तविक डिस्क को लेनदेन का संकेत प्राप्त होता है, जिसके बाद स्वचालित रूप से आदेश दिया जाता है।

  • 2. कई डेवलपर्स के पास बेहतर रणनीतियाँ हैं, जो ऊपर वर्णित दो पुराने ऑर्डर, स्टॉक सिंक रणनीतियों का उपयोग नहीं कर सकते हैं; क्योंकि ऐसा करने के लिए अपनी रणनीतियों को उन सिंक रणनीतियों के साथ एकीकृत करना होगा, जो रणनीतियों को बड़े पैमाने पर बदलने और प्रयास करने की आवश्यकता हो सकती है। क्या कुछ अच्छी रणनीतियों को सीधे ऑर्डर सिंक करने के लिए अपग्रेड करने का कोई अच्छा तरीका है? समाधानः आप एक आदेश सिंक्रनाइज़ टेम्पलेट श्रेणी पुस्तकालय (इस लेख में डिजाइन प्रणाली में) डिजाइन कर सकते हैं订单同步管理系统类库(Single Server)नीति), ताकि संदर्भ खाते के मालिकों को सीधे इस टेम्पलेट लाइब्रेरी को अपनी नीति में एम्बेड करने के लिए ऑर्डर, स्टॉक सिंक फ़ंक्शन को सक्षम करने के लिए अनुमति दी जा सके।

  • 3, एक अतिरिक्त वास्तविक डिस्क को कम करना । एक अंतिम दर्दनाक बिंदु यह है कि यदि ऊपर वर्णित दो वायदा आदेशों का उपयोग करके, स्टॉक सिंक्रनाइज़ेशन रणनीति; अतिरिक्त रूप से एक वास्तविक मॉनिटरिंग संदर्भ खाता खोलने की आवश्यकता है। समाधानः टेम्पलेट लाइब्रेरी का उपयोग करके संदर्भ खाता नीति में सुविधाओं को एम्बेड करें।

तो यह प्रणाली दो भागों से बनी हैः 1, ऑर्डर सिंक्रनाइज़ेशन मैनेजमेंट सिस्टम क्लासरूम (Single Server) 2. ऑर्डर सिंक्रोनस मैनेजमेंट सिस्टम (Synchronous Server)

एक बार जब आप अपनी आवश्यकताओं को समझ लेते हैं, तो आप डिजाइन करना शुरू कर देते हैं।

डिजाइन 1: ऑर्डर सिंक्रनाइज़ेशन मैनेजमेंट सिस्टम क्लासरूम (Single Server)

ध्यान दें कि यह एक रणनीति नहीं है; यह एक FMZ टेम्पलेट लाइब्रेरी है। टेम्पलेट लाइब्रेरी के बारे में अवधारणाओं को FMZ API दस्तावेज़ में खोजा जा सकता है।

टेम्पलेट लाइब्रेरी कोडः

// 全局变量
var keyName_label = "label"
var keyName_robotId = "robotId"
var keyName_extendAccessKey = "extendAccessKey"
var keyName_extendSecretKey = "extendSecretKey"
var fmzExtendApis = parseConfigs([config1, config2, config3, config4, config5])
var mapInitRefPosAmount = {}

function parseConfigs(configs) {
    var arr = []
    _.each(configs, function(config) {
        if (config == "") {
            return 
        }
        var strArr = config.split(",")
        if (strArr.length != 4) {
            throw "configs error!"
        }
        var obj = {}
        obj[keyName_label] = strArr[0]
        obj[keyName_robotId] = strArr[1]
        obj[keyName_extendAccessKey] = strArr[2]
        obj[keyName_extendSecretKey] = strArr[3]
        arr.push(obj)
    })
    return arr 
}

function getPosAmount(pos, ct) {
    var longPosAmount = 0
    var shortPosAmount = 0
    _.each(pos, function(ele) {
        if (ele.ContractType == ct && ele.Type == PD_LONG) {
            longPosAmount = ele.Amount
        } else if (ele.ContractType == ct && ele.Type == PD_SHORT) {
            shortPosAmount = ele.Amount
        }
    })
    var timestamp = new Date().getTime()
    return {ts: timestamp, long: longPosAmount, short: shortPosAmount}
}

function sendCommandRobotMsg (robotId, accessKey, secretKey, msg) {
    // https://www.fmz.com/api/v1?access_key=xxx&secret_key=yyyy&method=CommandRobot&args=[186515,"ok12345"]
    var url = "https://www.fmz.com/api/v1?access_key=" + accessKey + "&secret_key=" + secretKey + "&method=CommandRobot&args=[" + robotId + ',"' + msg + '"]'
    Log(url)
    var ret = HttpQuery(url)
    return ret 
}

function follow(nowPosAmount, symbol, ct, type, delta) {
    var msg = ""
    var nowAmount = type == PD_LONG ? nowPosAmount.long : nowPosAmount.short
    if (delta > 0) {
        // 开仓
        var tradeDirection = type == PD_LONG ? "buy" : "sell"
        // 发送信号
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)        
    } else if (delta < 0) {
        // 平仓
        var tradeDirection = type == PD_LONG ? "closebuy" : "closesell"
        if (nowAmount <= 0) {
            Log("未检测到持仓")
            return 
        }
        // 发送信号
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)
    } else {
        throw "错误"
    }
    if (msg) {
        _.each(fmzExtendApis, function(extendApiConfig) {
            var ret = sendCommandRobotMsg(extendApiConfig[keyName_robotId], extendApiConfig[keyName_extendAccessKey], extendApiConfig[keyName_extendSecretKey], msg)
            Log("调用CommandRobot接口,", "label:", extendApiConfig[keyName_label], ", msg:", msg, ", ret:", ret)
            Sleep(1000)
        })
    }
}

$.PosMonitor = function(exIndex, symbol, ct) {    
    var ts = new Date().getTime()
    var ex = exchanges[exIndex]
    // 判断ex类型
    var exName = ex.GetName()
    var isFutures = exName.includes("Futures_")
    var exType = isFutures ? "futures" : "spot"
    if (!isFutures) {
        throw "仅支持期货跟单"
    }

    if (exType == "futures") {
        // 缓存 symbol ct
        var buffSymbol = ex.GetCurrency()
        var buffCt = ex.GetContractType()

        // 切换到对应的交易对、合约代码
        ex.SetCurrency(symbol)
        if (!ex.SetContractType(ct)) {
            throw "SetContractType failed"
        }

        // 监控持仓
        var keyInitRefPosAmount = "refPos-" + exIndex + "-" + symbol + "-" + ct    // refPos-exIndex-symbol-contractType
        var initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        if (!initRefPosAmount) {
            // 没有初始化数据,初始化          
            mapInitRefPosAmount[keyInitRefPosAmount] = getPosAmount(_C(ex.GetPosition), ct)
            initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        }

        // 监控
        var nowRefPosAmount = getPosAmount(_C(ex.GetPosition), ct)
        // 计算仓位变动
        var longPosDelta = nowRefPosAmount.long - initRefPosAmount.long
        var shortPosDelta = nowRefPosAmount.short - initRefPosAmount.short

        // 检测变动
        if (!(longPosDelta == 0 && shortPosDelta == 0)) {
            // 执行多头动作
            if (longPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "执行多头跟单,变动量:", longPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_LONG, longPosDelta)
            }
            // 执行空头动作
            if (shortPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "执行空头跟单,变动量:", shortPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_SHORT, shortPosDelta)
            }

            // 执行跟单操作后,更新
            mapInitRefPosAmount[keyInitRefPosAmount] = nowRefPosAmount
        }

        // 恢复 symbol ct
        ex.SetCurrency(buffSymbol)
        ex.SetContractType(buffCt)
    } else if (exType == "spot") {
        // 现货
    }
}

$.getTbl = function() {
    var tbl = {
        "type" : "table", 
        "title" : "同步数据", 
        "cols" : [], 
        "rows" : []
    }
    // 构造表头
    tbl.cols.push("监控账户:refPos-exIndex-symbol-contractType")
    tbl.cols.push(`监控持仓:{"时间戳":xxx,"多头持仓量":xxx,"空头持仓量":xxx}`)
    _.each(fmzExtendApis, function(extendApiData, index) {
        tbl.cols.push(keyName_robotId + "-" + index)
    })
    
    // 写入数据
    _.each(mapInitRefPosAmount, function(initRefPosAmount, key) {
        var arr = [key, JSON.stringify(initRefPosAmount)]
        _.each(fmzExtendApis, function(extendApiData) {
            arr.push(extendApiData[keyName_robotId])
        })
        tbl.rows.push(arr)
    })

    return tbl
}

// 引用该模板类库的策略调用范例
function main() {
    // 清除所有日志
    LogReset(1)

    // 切换到OKEX 模拟盘测试
    exchanges[0].IO("simulate", true)

    // 设置合约
    exchanges[0].SetCurrency("ETH_USDT")
    exchanges[0].SetContractType("swap")

    // 定时交易时间间隔
    var tradeInterval = 1000 * 60 * 3        // 三分钟交易一次,用于观察跟单信号
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // 策略其它逻辑...

        // 用于测试的模拟交易触发
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("模拟带单策略发生交易,持仓变化", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // 使用模板的接口函数
        $.PosMonitor(0, "ETH_USDT", "swap")    // 可以设置多个监控,监控带单策略上的不同的exchange对象  
        var tbl = $.getTbl()
        
        // 显示状态栏
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

यह एक सरल डिजाइन है और इसमें दो प्रकार के कार्य होते हैं।订单同步管理系统类库(Single Server)टेम्पलेट क्लास लाइब्रेरी के बाद. इस नीति का उपयोग निम्न फ़ंक्शन के साथ किया जा सकता है.

  • $$ पोस्ट मॉनिटर यह फ़ंक्शन एक्सचेंज की रणनीति में वस्तुओं के होल्डिंग परिवर्तनों की निगरानी करता है और फिर टेम्पलेटः ऑर्डर सिंक्रनाइज़ेशन मैनेजमेंट सिस्टम क्लासरूम (Single Server) के पैरामीटर में सेट किए गए वास्तविक डिस्क पर ट्रेडिंग सिग्नल भेजता है।

  • $.getTbl यह डेटा एक बार फिर से निगरानी के साथ सिंक्रनाइज़ किया जाता है।

उदाहरण के लिए, सिंगल सर्वर टेम्पलेट का उपयोग करें।mainफ़ंक्शन मेंः

// 引用该模板类库的策略调用范例
function main() {
    // 清除所有日志
    LogReset(1)

    // 切换到OKEX 模拟盘测试
    exchanges[0].IO("simulate", true)

    // 设置合约
    exchanges[0].SetCurrency("ETH_USDT")
    exchanges[0].SetContractType("swap")

    // 定时交易时间间隔
    var tradeInterval = 1000 * 60 * 3        // 三分钟交易一次,用于观察跟单信号
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // 策略其它逻辑...

        // 用于测试的模拟交易触发
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("模拟带单策略发生交易,持仓变化", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // 使用模板的接口函数
        $.PosMonitor(0, "ETH_USDT", "swap")    // 可以设置多个监控,监控带单策略上的不同的exchange对象  
        var tbl = $.getTbl()
        
        // 显示状态栏
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

एक टेम्पलेट लाइब्रेरी स्वयं भी एक नीति डिस्क बना सकती है, जिसे आमतौर पर टेम्पलेट लाइब्रेरी का परीक्षण करने के लिए उपयोग किया जाता है. उदाहरण के लिए, इस टेम्पलेट का परीक्षण करना. आप टेम्पलेट के भीतर की अवधारणाओं को समझ सकते हैं।mainफ़ंक्शन आपकी अपनी रणनीति है.mainफ़ंक्शन ।

परीक्षण कोड ओकेएक्स एनालॉग डिस्क का उपयोग करके परीक्षण करने के लिए लिखा गया है, जिसमें एफएमजेड पर ओकेएक्स एनालॉग डिस्क के एपीआई की को संदर्भ खाते के रूप में कॉन्फ़िगर करने की आवश्यकता होती है, मुख्य फ़ंक्शन में एनालॉग डिस्क के लिए स्विच करना शुरू होता है। फिर ट्रेड जोड़ी को ईटीएच_यूएसडीटी पर सेट करें, और अनुबंध को स्थायी पर सेट करें। तब एक जबकि लूप में प्रवेश करें। लूप में हर 3 मिनट में एक बार ऑर्डर करें।$.PosMonitor(0, "ETH_USDT", "swap"), इस फ़ंक्शन को कॉल करने के लिए पहला पैरामीटर 0 में भेजा जाता है, जो एक्सचेंजों की निगरानी करता है[0] यह एक्सचेंज ऑब्जेक्ट, जो ईटीएच_यूएसडीटी लेनदेन जोड़ी, स्वैप अनुबंध की निगरानी करता है; और फिर कॉल किया जाता है$.getTbl()चार्ट जानकारी प्राप्त करें, उपयोग करेंLogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")चार्ट डेटा को स्टेटस बार पर दिखाएं.

तो आप देख सकते हैं, बस एक रणनीति है कि टेम्पलेट संदर्भित में इस्तेमाल किया है.$.PosMonitor(0, "ETH_USDT", "swap")एक बार जब आप एक रणनीति बनाते हैं, तो आप एक रणनीति बना सकते हैं जो एक प्रकार के स्टॉक की निगरानी करती है, एक स्टॉक को संदेश भेजने के लिए बदलती है।

परीक्षण से पहले बताएं订单同步管理系统类库(Single Server)रणनीतियों के लिए पैरामीटर डिजाइनः हमने पहले ही बताया है कि टेम्पलेट के इंटरफेस फ़ंक्शन का उपयोग कैसे किया जाए ताकि किसी रणनीति को बैंड फ़ंक्शन के साथ अपग्रेड किया जा सके। यह सवाल है कि इसे किसके पास भेजा जाए।订单同步管理系统类库(Single Server)इस प्रकार, हम अपने स्वयं के पैरामीटर के लिए विन्यस्त है.

img

आप देख सकते हैं कि 5 पैरामीटर हैं, अधिकतम 5 पुश का समर्थन करते हैं ((जोड़े जाने की आवश्यकता है जो स्वयं विस्तारित हो सकते हैं), पैरामीटर डिफ़ॉल्ट रूप से खाली स्ट्रिंग है, यानी इसे संसाधित नहीं किया जाता है।

  • label सिंक खाते के लिए टैग, एक खाते को चिह्नित करने के लिए उपयोग किया जाता है, और नाम को आसानी से सेट किया जा सकता है।

  • robotId वास्तविक डिस्क आईडी, सिंक्रनाइज़ खाते के मालिक द्वारा बनाया गया订单同步管理系统(Synchronous Server)वास्तविक डिस्क का आईडी।

  • accessKey एफएमजेड के विस्तार एपीआई के लिए एक्सेस की

  • गुप्त कुंजी एफएमजेड के विस्तार एपीआई के लिए गुप्त कुंजी

अब हम एक सरल परीक्षण कर सकते हैं।

ऑर्डर सिंक्रनाइज़ेशन मैनेजमेंट सिस्टम क्लासरूम (Single Server) रीयल डिस्क पर चल रहा हैः

img

ऑर्डर सिंक मैनेजमेंट सिस्टम (Synchronous Server) की डिस्क पर एक संकेत प्राप्त हुआः सिंक्रोनोस सर्वर (Synchronous Server) अभी तक तैयार नहीं है, हम इसे एक सरल कोड के साथ लागू करते हैं, कोई लेनदेन नहीं करते हैं, केवल संकेत प्रिंट करते हैंः

ऑर्डर सिंक्रोनस मैनेजमेंट सिस्टम (Synchronous Server) का अस्थायी कोडः

function main() {
    LogReset(1)
    while (true) {
        var cmd = GetCommand()
        if (cmd) {
            // cmd: ETH_USDT,swap,buy,1
            Log("cmd: ", cmd)
        }
        Sleep(1000)
    }
}

img

एक बार जब हम एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिर से एक बार फिरETH_USDT,swap,buy,1.. इस प्रकार, अगले चरण के लिए, आप जानकारी में लेनदेन जोड़े, अनुबंध कोड, लेनदेन की दिशा और मात्रा के आधार पर अपने स्वयं के स्वचालित अनुक्रमण कर सकते हैं।

वर्तमान में订单同步管理系统(Synchronous Server)यह केवल एक अस्थायी कोड है, और हम इसके डिजाइन पर अगले अंक में आगे बढ़ेंगे।


संबंधित

अधिक

मिंग्सी1005सूची को लागू करने के लिए, आपको दो डिस्क की आवश्यकता होती है, एक वर्ग पुस्तकालय डिस्क और एक ऑर्डर प्रबंधन प्रणाली डिस्क।

मिंग्सी1005ट्यूटोरियल के अनुसार बनाया गया, कॉन्फ़िगरेशन त्रुटि दिखाई दे रही है

अलकौन से पैरामीटर को बदलने की आवश्यकता है

अलअपने आप को और अपने आप को दो वास्तविक डिस्क, एक सिग्नल भेजने के लिए और एक प्राप्त करने के लिए चालू करने के लिए, दोनों एक साथ वास्तविक डिस्क का उपयोग कर सकते हैं?

छोटे सपनेआप शायद लेख को नहीं समझते हैं, यह एक ऐसा उपकरण है जिसे सीधे बैंडर की नीति पंक्ति में एम्बेड किया जा सकता है, और फिर इस नीति में बैंडर का कार्य होता है, जो सेट किए गए बैंडर खाते को संदेश भेजता है, और बैंडर रोबोट को संदेश प्राप्त करता है। यह एक बहुत ही सरल दृश्य है।

छोटे सपनेआप इस लेख को देख सकते हैं, कॉन्फ़िगरेशन जानकारीः टैग, डिस्क आईडी, एक्सेसकी, गुप्त कुंजी. इस त्रुटि की रिपोर्ट करने के लिए आपको अपनी जानकारी को गलत तरीके से कॉन्फ़िगर करना चाहिए, आप फिर से जांचें. ध्यान दें कि अंग्रेजी में अल्पविराम का उपयोग करें.

मिंग्सी1005त्रुटि configs error!, आदेश सिंक्रनाइज़ेशन प्रबंधन प्रणाली पुस्तकालय (Single Server) में, बैंडर की डिस्क और 2 KEY दोनों को भर दिया गया है, और फिर वास्तविक डिस्क में आदेश सिंक्रनाइज़ेशन प्रबंधन प्रणाली पुस्तकालय (Single Server) का संदर्भ दिया गया है, त्रुटि, त्रुटि configs error!

मिंग्सी1005त्रुटि configs error!

छोटे सपनेइस लेख में हम आपको कुछ गलत सूचनाओं के बारे में बताएंगे।

छोटे सपनेइस तरह के लोगों के लिए, यह बहुत अच्छा है।

छोटे सपनेयह खुला कोड है और आप इसे अपनी आवश्यकता के अनुसार बदल सकते हैं।