avatar of 发明者量化-小小梦 发明者量化-小小梦
پر توجہ دیں نجی پیغام
4
پر توجہ دیں
1271
پیروکار

ڈیجیٹل کرنسی فیوچر ٹریڈنگ کی منطق پر کچھ خیالات

میں تخلیق کیا: 2020-06-01 09:52:45, تازہ کاری: 2023-10-08 19:41:25
comments   6
hits   2406

ڈیجیٹل کرنسی فیوچر ٹریڈنگ کی منطق پر کچھ خیالات

ڈیجیٹل کرنسی فیوچر ٹریڈنگ کی منطق پر کچھ خیالات

مسئلہ کا منظر نامہ

ایک طویل عرصے سے، ڈیجیٹل کرنسی ایکسچینج پوزیشن API انٹرفیس کے ڈیٹا میں تاخیر کا مسئلہ ہمیشہ مجھے پریشان کرتا رہا ہے۔ مجھے ابھی تک کوئی مناسب حل نہیں ملا ہے، لہذا میں اس مسئلے کو دوبارہ پیش کروں گا۔ عام طور پر کنٹریکٹ ایکسچینج کی طرف سے فراہم کردہ مارکیٹ آرڈر دراصل کاؤنٹر پارٹی قیمت ہے، لہذا بعض اوقات اس نام نہاد “مارکیٹ آرڈر” کو استعمال کرنا ناقابل اعتبار ہے۔ لہذا، جب ہم ڈیجیٹل کرنسی فیوچر ٹریڈنگ کی حکمت عملی لکھتے ہیں، تو ہم میں سے زیادہ تر حد کے آرڈرز کا استعمال کرتے ہیں۔ ہر آرڈر دینے کے بعد، ہمیں یہ دیکھنے کے لیے پوزیشن کو چیک کرنے کی ضرورت ہے کہ آیا آرڈر پر عمل ہوا ہے اور کیا متعلقہ پوزیشن پر فائز ہے۔ مسئلہ اس پوزیشن کی معلومات میں ہے اگر آرڈر پر عمل کیا جاتا ہے، تو ایکسچینج پوزیشن انفارمیشن انٹرفیس (یعنی ایکسچینج انٹرفیس تک رسائی حاصل ہوتی ہے جب ہم ایکسچینج کو کہتے ہیں) میں نئی ​​کھلی ہوئی پوزیشن کی معلومات شامل ہونی چاہیے۔ ایکسچینج کی طرف سے واپس کیا گیا ڈیٹا پرانا ڈیٹا ہے، یعنی پوزیشن کی معلومات اس سے پہلے کہ آرڈر پر عمل درآمد ہو، پھر کوئی مسئلہ ہو گا۔ تجارتی منطق یہ سوچ سکتی ہے کہ آرڈر پر عمل نہیں ہوا ہے اور آرڈر دینا جاری رکھے گا۔ تاہم، ایکسچینج کے آرڈر پلیسمنٹ انٹرفیس میں کسی تاخیر کا سامنا نہیں ہوتا ہے، اس کے بجائے، لین دین بہت تیزی سے مکمل ہو جاتے ہیں، اور جیسے ہی وہ رکھے جاتے ہیں۔ اس کے نتیجے میں ایک سنگین نتیجہ نکلے گا کہ جب کوئی اوپننگ آپریشن شروع کیا جائے گا تو حکمت عملی بار بار آرڈر دے گی۔

حقیقی تجربہ

اس مسئلے کی وجہ سے، میں نے ایک ایسی حکمت عملی دیکھی ہے جس نے ایک پاگل مکمل لمبی پوزیشن کھولی ہے، خوش قسمتی سے، اس وقت مارکیٹ عروج پر تھی اور فلوٹنگ منافع ایک بار 10BTC سے تجاوز کر گیا تھا۔ خوش قسمتی سے، مارکیٹ عروج پر ہے، اگر یہ گرتا تو نتیجہ متوقع ہوتا۔

حل کرنے کی کوشش کریں۔

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

  • حل 2 ایکسچینج کے مارکیٹ آرڈر فنکشن کا استعمال کریں اور FMZ پر پاس -1 کو قیمت کے طور پر استعمال کریں، جو کہ فی الحال، OKEX فیوچر انٹرفیس کو حقیقی مارکیٹ آرڈرز کو سپورٹ کرنے کے لیے اپ گریڈ کیا گیا ہے۔

  • حل 3 ہم اب بھی پچھلی ٹریڈنگ منطق کا استعمال کرتے ہیں اور حد کے آرڈرز کا استعمال کرتے ہوئے آرڈر دیتے ہیں، لیکن پوزیشن ڈیٹا میں تاخیر کی وجہ سے پیدا ہونے والے مسئلے کو حل کرنے کی کوشش کرنے کے لیے ہم تجارتی منطق میں کچھ کھوج شامل کرتے ہیں۔ چیک کریں کہ آیا آرڈر دینے کے بعد منسوخ کیے بغیر آرڈر زیر التواء آرڈر کی فہرست سے غائب ہو جاتا ہے (پینڈنگ آرڈر کی فہرست سے غائب ہونے کے دو امکانات ہیں: 1 منسوخی اور 2 تکمیل) اور آرڈر کی مقدار اور آرڈر حجم پچھلی بار کے برابر ہے، آپ کو اس بات پر توجہ دینی چاہیے کہ آیا پروگرام کو انتظار کی منطق میں داخل ہونے دیں اور آپ اپنی تعداد میں اضافہ بھی جاری رکھ سکتے ہیں۔ اگر یہ ایک مخصوص تعداد سے زیادہ ہے تو اس کا مطلب ہے کہ پوزیشن انٹرفیس ڈیٹا میں تاخیر ہوئی ہے اور اس ٹرانزیکشن کی منطق ختم ہو گئی ہے۔

اسکیم 3 پر مبنی ڈیزائن

// 参数
/*
var MinAmount = 1
var SlidePrice = 5
var Interval = 500
*/

function GetPosition(e, contractType, direction) {
    e.SetContractType(contractType)
    var positions = _C(e.GetPosition);
    for (var i = 0; i < positions.length; i++) {
        if (positions[i].ContractType == contractType && positions[i].Type == direction) {
            return positions[i]
        }
    }

    return null
}

function Open(e, contractType, direction, opAmount) {
    var initPosition = GetPosition(e, contractType, direction);
    var isFirst = true;
    var initAmount = initPosition ? initPosition.Amount : 0;
    var nowPosition = initPosition;
    var directBreak = false 
    var preNeedOpen = 0
    var timeoutCount = 0
    while (true) {
        var ticker = _C(e.GetTicker)
        var needOpen = opAmount;
        if (isFirst) {
            isFirst = false;
        } else {
            nowPosition = GetPosition(e, contractType, direction);
            if (nowPosition) {
                needOpen = opAmount - (nowPosition.Amount - initAmount);
            }
            // 检测directBreak 并且持仓未变的情况
            if (preNeedOpen == needOpen && directBreak) {
                Log("疑似仓位数据延迟,等待30秒", "#FF0000")
                Sleep(30000)
                nowPosition = GetPosition(e, contractType, direction);
                if (nowPosition) {
                    needOpen = opAmount - (nowPosition.Amount - initAmount);
                }
                /*
                timeoutCount++
                if (timeoutCount > 10) {
                    Log("连续10次疑似仓位延迟,下单失败!", "#FF0000")
                    break
                }
                */
            } else {
                timeoutCount = 0
            }
        }
        if (needOpen < MinAmount) {
            break;
        }
        
        var amount = needOpen;
        preNeedOpen = needOpen
        e.SetDirection(direction == PD_LONG ? "buy" : "sell");
        var orderId;
        if (direction == PD_LONG) {
            orderId = e.Buy(ticker.Sell + SlidePrice, amount, "开多仓", contractType, ticker);
        } else {
            orderId = e.Sell(ticker.Buy - SlidePrice, amount, "开空仓", contractType, ticker);
        }

        directBreak = false
        var n = 0
        while (true) {
            Sleep(Interval);
            var orders = _C(e.GetOrders);
            if (orders.length == 0) {
                if (n == 0) {
                    directBreak = true
                }
                break;
            }
            for (var j = 0; j < orders.length; j++) {
                e.CancelOrder(orders[j].Id);
                if (j < (orders.length - 1)) {
                    Sleep(Interval);
                }
            }
            n++
        }
    }

    var ret = {
        price: 0,
        amount: 0,
        position: nowPosition
    };
    if (!nowPosition) {
        return ret;
    }
    if (!initPosition) {
        ret.price = nowPosition.Price;
        ret.amount = nowPosition.Amount;
    } else {
        ret.amount = nowPosition.Amount - initPosition.Amount;
        ret.price = _N(((nowPosition.Price * nowPosition.Amount) - (initPosition.Price * initPosition.Amount)) / ret.amount);
    }
    return ret;
}

function Cover(e, contractType, opAmount, direction) {
    var initPosition = null;
    var position = null;
    var isFirst = true;

    while (true) {
        while (true) {
            Sleep(Interval);
            var orders = _C(e.GetOrders);
            if (orders.length == 0) {
                break;
            }
            for (var j = 0; j < orders.length; j++) {
                e.CancelOrder(orders[j].Id);
                if (j < (orders.length - 1)) {
                    Sleep(Interval);
                }
            }
        }

        position = GetPosition(e, contractType, direction)
        if (!position) {
            break
        }
        if (isFirst == true) {
            initPosition = position;
            opAmount = Math.min(opAmount, initPosition.Amount)
            isFirst = false;
        }

        var amount = opAmount - (initPosition.Amount - position.Amount)
        if (amount <= 0) {
            break
        }

        var ticker = _C(exchange.GetTicker)
        if (position.Type == PD_LONG) {
            e.SetDirection("closebuy");
            e.Sell(ticker.Buy - SlidePrice, amount, "平多仓", contractType, ticker);
        } else if (position.Type == PD_SHORT) {
            e.SetDirection("closesell");
            e.Buy(ticker.Sell + SlidePrice, amount, "平空仓", contractType, ticker);
        }

        Sleep(Interval)
    }

    return position
}

$.OpenLong = function(e, contractType, amount) {
    if (typeof(e) == "string") {
        amount = contractType
        contractType = e
        e = exchange
    }

    return Open(e, contractType, PD_LONG, amount);
}

$.OpenShort = function(e, contractType, amount) {
    if (typeof(e) == "string") {
        amount = contractType
        contractType = e
        e = exchange
    }

    return Open(e, contractType, PD_SHORT, amount);
};

$.CoverLong = function(e, contractType, amount) {
    if (typeof(e) == "string") {
        amount = contractType
        contractType = e
        e = exchange
    }

    return Cover(e, contractType, amount, PD_LONG);
};

$.CoverShort = function(e, contractType, amount) {
    if (typeof(e) == "string") {
        amount = contractType
        contractType = e
        e = exchange
    }

    return Cover(e, contractType, amount, PD_SHORT);
};


function main() {
    Log(exchange.GetPosition())
    var info = $.OpenLong(exchange, "quarter", 100)
    Log(info, "#FF0000")

    Log(exchange.GetPosition())
    info = $.CoverLong(exchange, "quarter", 30)
    Log(exchange.GetPosition())
    Log(info, "#FF0000")

    info = $.CoverLong(exchange, "quarter", 80)
    Log(exchange.GetPosition())
    Log(info, "#FF0000")
}

ٹیمپلیٹ ایڈریس: https://www.fmz.com/strategy/203258

ٹیمپلیٹ انٹرفیس کو کال کرنے کا طریقہ وہی ہے جو اوپر کے مین فنکشن میں ہے۔$.OpenLong$.CoverLong。 ٹیمپلیٹ ایک بیٹا ورژن ہے تجاویز اور تبصرے کا خیرمقدم ہے ہم پوزیشن ڈیٹا میں تاخیر کے مسئلے کو حل کرنے کے لیے اسے بہتر بناتے رہیں گے۔