ڈیجیٹل کرنسی کے فیوچر ٹریڈنگ کی منطق کے بارے میں سوچنا

مصنف:چھوٹا سا خواب, تخلیق: 2020-06-01 09:52:45, تازہ کاری: 2023-10-08 19:41:25

img

ڈیجیٹل کرنسی کے فیوچر ٹریڈنگ کی منطق کے بارے میں سوچنا

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

长久以来,数字货币交易所持仓API接口的数据延迟问题总是困扰着我。一直没有找到合适的处理方式,这个问题的场景我来复现下。通常合约交易所提供的市价单其实为对手价,所以有时候用这个所谓的“市价单”有些不靠谱。因此我们在写数字货币期货交易策略时,大部分用的是限价单。在每次下单后,我们要检查持仓,看看下单是不是成交了,并且持有了对应的仓位。问题就出在这个持仓信息上,如果订单成交了,交易所持仓信息接口(就是我们调用exchange.GetPosition时底层实际去访问的交易所接口)返回的数据应当是包含新开仓持仓信息的,但是交易所返回的数据如果是旧数据,即刚才下单的订单成交前的持仓信息,这样就出问题了。交易逻辑可能认为订单没有成交,继续下单。但是交易所下单接口并不延迟,反而成交很快,下单就成交。这样会造成一种严重的后果就是策略在一次触发开仓的操作时会不停的重复下单。

تجربات

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

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

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

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

  • پروجیکٹ 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

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


متعلقہ

مزید

excmسب سے بہتر طریقہ یہ ہونا چاہئے کہ آپ کو ایک بار پھر پوچھنے کے بجائے سرور کو فوری طور پر آپ کو مطلع کرنے کے لئے ایک بار جب آپ کو اپ ڈیٹ کیا جاتا ہے تو آپ کو Ws کا استعمال کرنا چاہئے.

Xueqiu بوٹاس مسئلے کا سامنا کرنا پڑا، میرا حل یہ ہے کہ آرڈر سے پہلے ہولڈنگ ریکارڈ کریں، پھر ioc آرڈر کے بعد ریکارڈ آئی ڈی، لوپ آرڈر کی حیثیت حاصل کریں، اگر یہ ٹرانزیکشن / جزوی طور پر ٹرانزیکشن ہے تو، موجودہ ہولڈنگ اور ریکارڈ کی ہولڈنگ کے مقابلے میں لوپ کریں، جب یہ دونوں اقدار مختلف ہیں تو لوپ سے باہر نکلیں.

چھوٹا سا خواباس کے علاوہ ، میں نے اپنے دوستوں کو بتایا کہ میں نے ایک بار پھر اس ویب سائٹ کو دیکھا ہے ، جس میں میں نے ایک بار پھر دیکھا ہے۔

excmاس کے علاوہ، آپ کو اس بات کا یقین کرنے کی ضرورت ہے کہ آپ کے پاس ایک مکمل حل ہے جو آپ کو اپنے آپ کو تلاش کرنے کی ضرورت ہے.

چھوٹا سا خوابتاہم ، جب بھی ڈبلیو ایس انٹرفیس ناقابل اعتماد ہوتا ہے تو ، یہ REST پروٹوکول سے کہیں زیادہ پریشان کن ہوتا ہے۔

چھوٹا سا خواببہت شکریہ، سیکھنے کے لئے۔