디지털 화폐 선물 거래의 논리에 대한 몇 가지 생각

저자:리디아, 창작: 2022-11-30 17:12:20, 업데이트: 2023-09-11 19:59:55

img

디지털 화폐 선물 거래의 논리에 대한 몇 가지 생각

문제 시나리오

오랫동안 디지털 화폐 거래소의 위치 API 인터페이스의 데이터 지연 문제는 항상 저를 괴롭혔습니다. 이 문제를 처리하는 적절한 방법을 찾지 못했습니다. 문제의 장면을 재현해 보겠습니다. 일반적으로 계약 거래소가 제공하는 시장 가격 주문은 실제로 상대방의 가격이기 때문에 때때로 이러한 이른바 "시장 가격 주문"을 사용하는 것이 신뢰할 수 없습니다. 따라서 디지털 화폐 선물 거래 전략을 작성할 때 우리는 가장 제한 주문을 사용합니다. 각 주문이 배치된 후, 주문이 종료되고 해당 위치가 유지되는지 확인하기 위해 위치를 확인해야합니다. 문제는이 정보 위치에 있습니다. 주문이 종료되면 거래소의 위치 정보 인터페이스 (즉, 거래가 완료 될 때 하단 층이 실제로 액세스하는 인터페이스입니다.PositionGet 매우 심각한) 에 의해 반환되는 데이터 교환은 새로운 위치 정보를 포함해야합니다. 그러나, 오래된 위치가 완료되면 거래소가 다시 돌아옵니다. 이 전략은 거래가 종료되기 전에 주문이 계속되는 것을 초래할 수 있습니다. 그리고 트랜잭션이 종료 될 때, 거래가 종료 될 수 있습니다. 대신, 트랜잭션이 종료 될 수 있습니다.

실무 경험

이 문제 때문에, 나는 미친듯이 긴 포지션으로 가득한 전략을 열었다. 다행히도, 시장은 그 때 급등했고, 부동 수익은 10BTC를 초과했다. 다행히도 시장은 급격히 증가했다. 급격히 감소하면 결과를 상상할 수 있습니다.

해결책

  • 해결책 1 전략은 하나의 주문만을 배치하도록 설계될 수 있으며, 주문 가격은 현재 거래 상대방의 가격과 큰 슬라이딩 가격으로 구성되어 있어 상대방의 주문의 특정 깊이를 취한다. 이의 장점은 하나의 주문만 배치되고 위치 정보에 따라 판단되지 않는다는 것이다. 이것은 반복된 주문의 문제를 피할 수 있지만, 때로는 주문을 배치하면 가격 변화가 상대적으로 큰 경우 거래소의 가격 제한 메커니즘을 유발할 수 있으며, 슬라이딩 가격을 증가시키고 여전히 거래를 하지 못하여 기회를 놓칠 수 있다.

  • 해결책 2 거래소의 시장 가격 주문 기능으로 가격은 FMZ에서 시장 가격 주문으로 -1으로 전송됩니다. 현재 OKEX 선물 인터페이스는 실제 시장 가격 주문을 지원하도록 업그레이드되었습니다.

  • 해결책 3 우리는 여전히 이전 거래 논리를 사용하고 가격 제한 주문으로 주문을 배치하지만 위치 데이터 지연으로 인한 문제를 해결하기 위해 거래 논리에 약간의 검출을 추가합니다. 주문이 취소없이 대기 중인 주문 목록에서 직접 사라졌는지 확인하십시오. (취소 및 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위의 주요 기능에서 템플릿은 베타 버전이고, 제안은 환영합니다. 우리는 위치 데이터 지연 문제를 처리할 수 있도록 최적화를 계속할 것입니다.


관련

더 많은