Некоторые мысли о логике торговли цифровыми валютными фьючерсами

Автор:Лидия., Создано: 2022-11-30 17:12:20, Обновлено: 2023-09-11 19:59:55

img

Некоторые мысли о логике торговли цифровыми валютными фьючерсами

Сценарий проблемы

Долгое время проблема задержки данных интерфейса API позиции цифровой валютной биржи всегда беспокоила меня. Я не нашел правильного способа справиться с этой проблемой. Позвольте воспроизвести сцену проблемы. Обычно рыночный ценовой ордер, предоставляемый биржей контрактов, на самом деле является ценой контрагента, поэтому иногда не очень надежно использовать этот так называемый рыночный ценовой ордер. Однако, когда мы пишем стратегии торговли фьючерсами цифровой валюты, мы используем лимитный ордер больше всего. После каждого размещения ордера нам нужно проверить позицию, чтобы увидеть, закрыт ли ордер и удерживается ли соответствующая позиция. Проблема заключается в этой информационной позиции. Если ордер закрыт, данные, возвращаемые обменным информационным интерфейсом позиции (т.е. интерфейс, фактически доступный нижним слоем при открытии биржи.Получить очень серьезный интерфейс) должны включать новую информацию. Однако, если старые

Практический опыт

Из-за этой проблемы, я видел, как стратегия открывается полная длинных позиций безумно. К счастью, рынок взлетел в то время, и плавающая прибыль превысила 10BTC. К счастью, рынок резко вырос. Если он резко снизился, мы можем представить результат.

Решение

  • Решение 1 Стратегия может быть разработана для размещения только одного ордера, и цена ордера - это цена текущего торгового оппонента плюс большая скользящая цена, чтобы взять определенную глубину ордера оппонента. Преимущество этого заключается в том, что будет размещен только один ордер, и он не будет оцениваться на основе информации о позиции. Это может избежать проблемы повторных заказов, но иногда размещение ордера может запустить механизм ценового лимита биржи, когда изменение цены относительно велико, и возможно увеличить скользящую цену и все равно не сделать сделку, тем самым упустив возможность.

  • Решение 2 С помощью функции ордера рыночной цены биржи цена переносится на - 1 на FMZ в качестве ордера рыночной цены.

  • Решение 3 Мы по-прежнему используем предыдущую логику торговли и размещаем заказы с лимитовыми ордерами цены, но добавляем некоторое обнаружение в логику торговли, чтобы попытаться решить проблему, вызванную задержкой данных о позиции. Проверьте, исчез ли заказ непосредственно из списка ожидаемых заказов без отмены (есть две возможности исчезновения из списка ожидаемых заказов: 1. отмена и 2. заполнен). Если такая ситуация обнаружена, и количество снова размещенного заказа такое же, как и в прошлом заказе, важно отметить, что задержка данных о позиции. Пусть программа вводит логику ожидания, чтобы повторно получить информацию о позиции, или даже продолжить оптимизировать и увеличивать количество времени ожидания, если оно превышает определенное количество раз, это указывает на то, что задержка интерфейса данных о позиции является серьезной, что приводит к прекращению логики торговли.

Проектирование на основе решения 3

// Parameters
/*
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);
            }
            // Check directBreak and the position remains unchanged
            if (preNeedOpen == needOpen && directBreak) {
                Log("Suspected position data is delayed, wait for 30 seconds", "#FF0000")
                Sleep(30000)
                nowPosition = GetPosition(e, contractType, direction);
                if (nowPosition) {
                    needOpen = opAmount - (nowPosition.Amount - initAmount);
                }
                /*
                timeoutCount++
                if (timeoutCount > 10) {
                    Log("Suspected position is delayed for 10 consecutive times, and the order is failed!", "#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, "open long positions", contractType, ticker);
        } else {
            orderId = e.Sell(ticker.Buy - SlidePrice, amount, "open short positions", 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, "close long positions", contractType, ticker);
        } else if (position.Type == PD_SHORT) {
            e.SetDirection("closesell");
            e.Buy(ticker.Sell + SlidePrice, amount, "close short positions", 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в основной функции выше. Шаблон является бета-версией, и вы можете сделать предложения. Мы продолжим оптимизировать его, чтобы мы могли справиться с проблемой задержки данных о местоположении.


Связанные

Больше