avatar of ianzeng123 ianzeng123
집중하다 사신
2
집중하다
319
수행원

중재 전략에 대한 간략한 분석: 짧은 시간 지연으로 저위험 기회를 포착하는 방법

만든 날짜: 2025-03-07 14:11:55, 업데이트 날짜: 2025-03-10 17:38:06
comments   0
hits   1386

중재 전략에 대한 간략한 분석: 짧은 시간 지연으로 저위험 기회를 포착하는 방법

이 전략의 영감은 지후 작가의 “드림 딜러” 기회 게시물인 “트럼프와 멜라니아 저위험 상관관계 차익거래 모델”에서 나왔습니다. 이 기사에서는 BN(TRUMP와 MELANIA)에서 출시된 두 계약 간의 가격 상관관계를 살펴보고, 두 계약 간의 미묘한 시간 지연을 활용하여 단기 시장 변동을 포착하고 저위험 차익거래를 달성하고자 합니다. 다음으로, 이 전략의 원칙과 코드 구현 논리를 설명하고 가능한 최적화 방향을 살펴보겠습니다.

미리 가야해요알아채다문제는 이 전략이 수동 거래 작업과 동일하다는 것입니다. 두 개의 적합한 거래 쌍을 찾은 후에야 일정한 수익 기회가 생기고 거래 쌍의 수익 수명은 짧을 수 있습니다. 수익 기회가 없다는 것을 발견하면 수익 하락이나 손실을 방지하기 위해 제때 전략을 중단해야 합니다.


1. 전략 원칙 및 시장 관련성

1.1 전략적 배경

TRUMP와 MELANIA 계약은 모두 동일한 발행팀에서 발행하고 동일한 통제 기금을 갖고 있으므로 가격 추세는 대부분 매우 동기화되어 있습니다. 하지만 계약 설계나 시장 실행 등의 요소로 인해 MELANIA의 가격은 TRUMP보다 1~2초 정도 뒤떨어지는 경향이 있습니다. 이러한 작은 지연은 중재자에게 가격 차이를 포착하고 고빈도 복제 거래를 수행할 수 있는 기회를 제공합니다. 간단히 말해서, TRUMP가 급격하게 변동할 때, MELANIA는 바로 그 뒤를 따르는 경향이 있습니다. 이 지연을 이용하면 더 낮은 위험으로 거래를 완료할 수 있습니다.

중재 전략에 대한 간략한 분석: 짧은 시간 지연으로 저위험 기회를 포착하는 방법

중재 전략에 대한 간략한 분석: 짧은 시간 지연으로 저위험 기회를 포착하는 방법

1.2 암호화폐 시장의 보급도

유사한 상관관계 현상은 암호화폐 시장에서는 드문 일이 아닙니다.

  • 동일한 프로젝트의 다양한 계약 또는 파생 상품: 동일한 기반 자산이나 팀 배경 때문에 다양한 제품의 가격은 종종 강력한 연관성을 갖습니다.
  • 교차거래소 중재:동일한 자산이라도 거래소마다 유동성과 매칭 메커니즘의 차이로 인해 가격 차이가 미세하게 발생할 수 있습니다.
  • 스테이블코인과 법정화폐 연동 상품: 이러한 상품은 종종 예상되는 환율 편차가 있으며, 차익거래자는 약간의 환율 변동으로도 이익을 얻을 수 있습니다.

이러한 상관관계는 고빈도 트레이더와 차익거래자에게 안정적인 거래 신호와 위험이 낮은 운영 기회를 제공하지만, 동시에 미묘한 시장 변화에도 매우 민감하게 반응하고 실시간으로 대응할 수 있는 거래 전략이 필요합니다.


2. 코드 로직에 대한 자세한 설명

코드는 주로 여러 부분으로 구성되며, 각 모듈은 중재 전략의 주요 단계에 해당합니다.

2.1 보조기능 설명

위치 정보를 얻으세요

function GetPosition(pair){
    let pos = exchange.GetPosition(pair)
    if(pos.length == 0){
        return {amount:0, price:0, profit:0}
    }else if(pos.length > 1){
        throw '不支持双向持仓'
    }else if(pos.length == 1){
        return {amount:pos[0].Type == 0 ? pos[0].Amount : -pos[0].Amount, price:pos[0].Price, profit:pos[0].Profit}
    }else{
        Log('未获取仓位数据')
        return null
    }
}
  • 기능: 이 함수는 지정된 거래 쌍의 포지션 정보를 균일하게 얻고 롱 포지션과 숏 포지션을 양수와 음수로 변환하는 데 사용됩니다.
  • 논리: 포지션이 비어 있으면 기본 제로 포지션을 반환합니다. 주문이 두 개 이상인 경우 오류가 보고됩니다(일방향 포지션을 보장하기 위해). 그렇지 않으면 현재 포지션의 방향, 가격, 변동 손익을 반환합니다.

계정 초기화

function InitAccount(){
    let account = _C(exchange.GetAccount)
    let total_eq = account.Equity

    let init_eq = 0
    if(!_G('init_eq')){
        init_eq = total_eq
        _G('init_eq', total_eq)
    }else{
        init_eq = _G('init_eq')
    }

    return init_eq
}
  • 기능: 이 기능은 이후의 손익 계산을 위한 기준으로 계정 자본을 초기화하고 기록하는 데 사용됩니다.

보류중인 주문 취소

function CancelPendingOrders() {
    orders = exchange.GetOrders();  // 获取订单
    for (let order of orders) {
        if (order.Status == ORDER_STATE_PENDING) {  // 只取消未完成的订单
            exchange.CancelOrder(order.Id);  // 取消挂单
        }
    }
}
  • 기능: 주문하기 전에, 주문 충돌이나 중복 주문을 방지하기 위해 이전에 완료되지 않은 주문을 취소하세요.

2.2 주요 거래 로직

주요 함수는 무한 루프를 사용하여 다음 단계를 지속적으로 실행합니다.

  1. 데이터 수집 및 시장 계산
    각 사이클은 다음으로 시작됩니다.exchange.GetRecords Pair_A와 Pair_B의 시장 데이터를 각각 가져옵니다.

    • 계산 공식 : [ ratio = \frac{Close{A} - Open{A}}{Open{A}} - \frac{Close{B} - Open{B}}{Open{B}} ] 둘의 상승과 하락을 비교하면 비정상적인 가격 차이가 있는지 확인할 수 있습니다. 가격 차이가 사전 설정된 diffLevel을 초과하면 개시 조건이 실행됩니다.
  2. 개장조건을 확인하여 주문하기
    현재 포지션이 없고(position_B.amount == 0) 거래가 허용되는 경우(afterTrade==1):

    • 비율이 diffLevel보다 큰 경우, 시장이 상승할 것으로 판단되어 Pair_B(매수 롱 포지션)에 대한 매수 주문이 발행됩니다.
    • 비율이 -diffLevel보다 작으면 시장이 하락할 것으로 간주되어 매도 주문이 발행됩니다(단기 포지션이 개설됩니다). 주문을 하기 전에 주문 취소 기능이 호출되어 현재 주문 상태가 지워졌는지 확인합니다.
  3. 손절매와 손절매 논리
    포지션이 확립되면 전략은 포지션 방향에 따라 해당 이익 실현 주문과 손절매 주문을 설정합니다.

    • 롱 포지션(매수): 이익 실현 가격을 포지션 가격에 (1 + stopProfitLevel)을 곱한 값으로 설정하고, 손실 정지 가격을 포지션 가격에 (1 - stopLossLevel)을 곱한 값으로 설정합니다.
    • 숏 포지션(매도): 이익 실현 가격은 포지션 가격에 (1 - stopProfitLevel)을 곱한 값으로 설정되고, 손절 가격은 포지션 가격에 (1 + stopLossLevel)을 곱한 값으로 설정됩니다. 시스템은 실시간 시장 가격을 모니터링합니다. 이익 실현 또는 손절매 조건이 트리거되면 원래 보류 주문은 취소되고 포지션을 마감하기 위한 주문이 실행됩니다.
  4. 포지션 마감 후 수익 통계 및 로그 기록
    각 포지션이 마감된 후, 시스템은 계정 자본의 변화를 얻고 수익 횟수, 손실 횟수, 누적 수익/손실 금액을 계산합니다.
    동시에 표와 그래프를 사용하여 현재 위치 정보, 거래 통계 및 사이클 지연을 실시간으로 표시하므로 후속 전략 효과 분석에 편리합니다.


3. 전략 최적화 및 확장 방법

이 전략은 두 개의 높은 상관관계를 가진 계약 간의 미묘한 지연을 활용하지만 여전히 개선할 수 있는 영역이 많이 있습니다.

3.1 매개변수 최적화 및 동적 조정

  • 임계값 조정: diffLevel, stopProfitLevel, stopLossLevel과 같은 매개변수는 다양한 시장 환경에 따라 조정이 필요할 수 있습니다. 이러한 매개변수는 과거 데이터의 백테스팅을 통해 자동으로 최적화되거나 모델을 실시간으로 동적으로 조정하여(예: 머신 러닝 알고리즘) 최적화될 수 있습니다.
  • 포지션 관리:현재 전략은 고정된 Trade_Number를 사용하여 포지션을 엽니다. 앞으로는 동적 포지션 관리 또는 일괄적으로 포지션을 열고 점진적으로 이익을 실현하여 단일 거래의 위험을 줄이는 메커니즘을 도입하는 것을 고려할 수 있습니다.

3.2 거래 신호 필터링

  • 다인자 신호: 가격 상승 및 하락에만 근거하여 비율을 계산하는 경우 노이즈의 영향을 받을 수 있습니다. 거짓 신호를 더욱 걸러내기 위해 거래량, 주문량, 기술 지표(예: RSI, MACD 등)를 도입하는 것을 고려할 수 있습니다.
  • 지연 보상: MELANIA의 지연시간이 1~2초인 점을 감안할 때, 더욱 정확한 시간 동기화와 신호 예측 메커니즘을 개발하면 진입 타이밍의 정확도를 높이는 데 도움이 될 것입니다.

3.3 시스템 견고성 및 위험 제어

  • 오류 처리: 네트워크 지연이나 교환 인터페이스 이상 현상이 발생하는 경우 적시에 대응하고, 시스템 장애로 인한 예상치 못한 손실을 방지하기 위해 예외 처리 및 로깅을 추가합니다.
  • 위험 관리 전략: 자본 관리와 최대 인출금 통제를 결합하여 일일 또는 단일 거래 손실 한도를 설정하여 극한의 시장 환경에서도 연속적인 손실을 방지합니다.

3.4 코드 및 아키텍처 최적화

  • 비동기 처리: 현재 전략 루프는 100밀리초마다 실행됩니다. 비동기 처리와 멀티스레드 최적화를 통해 지연 및 실행 차단 위험을 줄일 수 있습니다.
  • 전략 백테스팅 및 시뮬레이션:완벽한 백테스팅 시스템과 실시간 시뮬레이션 거래 환경을 도입하여 다양한 시장 조건에서 전략의 성과를 검증하고 실제 거래에서 전략이 보다 안정적으로 실행될 수 있도록 돕습니다.

IV. 결론

이 글에서는 단기지연계약상관관계차익거래 전략의 기본 원칙과 구현 코드를 자세히 소개합니다. 가격 상승과 하락의 차이를 이용하는 것부터 진입 기회를 포착하는 것, 포지션 관리를 위한 손절매와 손절매를 설정하는 것까지, 이 전략은 암호화폐 시장의 자산 간의 높은 상관관계를 최대한 활용합니다. 동시에 우리는 전략의 안정성과 수익성을 실시간 애플리케이션에서 더욱 개선하기 위해 동적 매개변수 조정, 신호 필터링, 시스템 견고성 및 코드 최적화를 포함한 여러 가지 최적화 제안을 제시했습니다.

이 전략은 독특한 영감을 받았고 구현하기도 간단하지만, 빈도가 높고 변동성이 큰 암호화폐 시장에서는 모든 차익거래를 신중하게 처리해야 합니다. 이 글이 양적 거래와 차익거래 전략에 관심이 있는 친구들에게 귀중한 참고 자료와 영감을 제공하기를 바랍니다.


참고: 전략 테스트 환경은 OKX 시뮬레이션 거래이며, 구체적인 세부 사항은 다른 거래소에 따라 수정될 수 있습니다.

function GetPosition(pair){
    let pos = exchange.GetPosition(pair)
    if(pos.length == 0){
        return {amount:0, price:0, profit:0}
    }else if(pos.length > 1){
        throw '不支持双向持仓'
    }else if(pos.length == 1){
        return {amount:pos[0].Type == 0 ? pos[0].Amount : -pos[0].Amount, price:pos[0].Price, profit:pos[0].Profit}
    }else{
        Log('未获取仓位数据')
        return null
    }
}

function InitAccount(){
    let account = _C(exchange.GetAccount)
    let total_eq = account.Equity

    let init_eq = 0
    if(!_G('init_eq')){
        init_eq = total_eq
        _G('init_eq', total_eq)
    }else{
        init_eq = _G('init_eq')
    }

    return init_eq
}

function CancelPendingOrders() {
    orders = exchange.GetOrders();  // 获取订单
    for (let order of orders) {
        if (order.Status == ORDER_STATE_PENDING) {  // 只取消未完成的订单
            exchange.CancelOrder(order.Id);  // 取消挂单
        }
    }
}

var pair_a = Pair_A + "_USDT.swap";
var pair_b = Pair_B + "_USDT.swap";


function main() {
    exchange.IO('simulate', true);
    LogReset(0);
    Log('策略开始运行')

    var precision = exchange.GetMarkets();
    var ratio = 0

    var takeProfitOrderId = null;
    var stopLossOrderId = null;
    var successCount = 0;
    var lossCount = 0;
    var winMoney = 0;
    var failMoney = 0;
    var afterTrade = 1;

    var initEq = InitAccount();

    var curEq = initEq

    var pricePrecision = precision[pair_b].PricePrecision;

    while (true) {
        try{
            let startLoopTime = Date.now();
            let position_B = GetPosition(pair_b);
            let new_r_pairB = exchange.GetRecords(pair_b, 1).slice(-1)[0];

            if (!new_r_pairB || !position_B) {
                Log('跳过当前循环');
                continue;
            }
            
            // 合并交易条件:检查是否可以开仓并进行交易
            if (afterTrade == 1 && position_B.amount == 0) {
                
                let new_r_pairA = exchange.GetRecords(pair_a, 1).slice(-1)[0];
                if (!new_r_pairA ) {
                    Log('跳过当前循环');
                    continue;
                }
                
                ratio = (new_r_pairA.Close - new_r_pairA.Open) / new_r_pairA.Open - (new_r_pairB.Close - new_r_pairB.Open) / new_r_pairB.Open;

                if (ratio > diffLevel) {
                    CancelPendingOrders();
                    Log('实时ratio:', ratio, '买入:', pair_b, position_B.amount);
                    exchange.CreateOrder(pair_b, "buy", -1, Trade_Number);
                    afterTrade = 0;
                } else if (ratio < -diffLevel) {
                    CancelPendingOrders();
                    Log('实时ratio:', ratio, '卖出:', pair_b, position_B.amount);
                    exchange.CreateOrder(pair_b, "sell", -1, Trade_Number);
                    afterTrade = 0;
                }            
            }

            

            // 判断止盈止损
            if (position_B.amount > 0 && takeProfitOrderId == null && stopLossOrderId == null && afterTrade == 0) {
                Log('多仓持仓价格:', position_B.price, '止盈价格:', position_B.price * (1 + stopProfitLevel), '止损价格:', position_B.price * (1 - stopLossLevel));
                takeProfitOrderId = exchange.CreateOrder(pair_b, "closebuy", position_B.price * (1 + stopProfitLevel), position_B.amount);
                Log('止盈订单:', takeProfitOrderId);
            }

            if (position_B.amount > 0 && takeProfitOrderId != null && stopLossOrderId == null && new_r_pairB.Close < position_B.price * (1 - stopLossLevel) && afterTrade == 0) {
                CancelPendingOrders();
                takeProfitOrderId = null
                Log('多仓止损');
                stopLossOrderId = exchange.CreateOrder(pair_b, "closebuy", -1, position_B.amount);
                Log('多仓止损订单:', stopLossOrderId);
            }

            if (position_B.amount < 0 && takeProfitOrderId == null && stopLossOrderId == null && afterTrade == 0) {
                Log('空仓持仓价格:', position_B.price, '止盈价格:', position_B.price * (1 - stopProfitLevel), '止损价格:', position_B.price * (1 + stopLossLevel));
                takeProfitOrderId = exchange.CreateOrder(pair_b, "closesell", position_B.price * (1 - stopProfitLevel), -position_B.amount);
                Log('止盈订单:', takeProfitOrderId, '当前价格:', new_r_pairB.Close );
            }

            if (position_B.amount < 0 && takeProfitOrderId != null && stopLossOrderId == null && new_r_pairB.Close > position_B.price * (1 + stopLossLevel) && afterTrade == 0) {
                CancelPendingOrders();
                takeProfitOrderId = null
                Log('空仓止损');
                stopLossOrderId = exchange.CreateOrder(pair_b, "closesell", -1, -position_B.amount);
                Log('空仓止损订单:', stopLossOrderId);
            }


            // 平市价单未完成
            if (takeProfitOrderId == null && stopLossOrderId != null && afterTrade == 0) {
                
                let stoplosspos = GetPosition(pair_b)
                if(stoplosspos.amount > 0){
                    Log('平多仓市价单未完成')
                    exchange.CreateOrder(pair_b, 'closebuy', -1, stoplosspos.amount)
                }
                if(stoplosspos.amount < 0){
                    Log('平空仓市价单未完成')
                    exchange.CreateOrder(pair_b, 'closesell', -1, -stoplosspos.amount)
                }
            }

            // 未平仓完毕
            if (Math.abs(position_B.amount) < Trade_Number && Math.abs(position_B.amount) > 0 && afterTrade == 0){
                Log('未平仓完毕')
                if(position_B.amount > 0){
                    exchange.CreateOrder(pair_b, 'closebuy', -1, position_B.amount)
                }else{
                    exchange.CreateOrder(pair_b, 'closesell', -1, -position_B.amount)
                }
            }

            // 计算盈亏
            if (position_B.amount == 0 && afterTrade == 0) {
                if (stopLossOrderId != null || takeProfitOrderId != null) {
                    stopLossOrderId = null;
                    takeProfitOrderId = null;

                    let afterEquity = exchange.GetAccount().Equity;
                    let curAmount = afterEquity - curEq;

                    curEq = afterEquity

                    if (curAmount > 0) {
                        successCount += 1;
                        winMoney += curAmount;
                        Log('盈利金额:', curAmount);
                    } else {
                        lossCount += 1;
                        failMoney += curAmount;
                        Log('亏损金额:', curAmount);
                    }
                    afterTrade = 1;
                }
            }

            if (startLoopTime % 10 == 0) {  // 每 10 次循环记录一次
                let curEquity = exchange.GetAccount().Equity

                // 输出交易信息表
                let table = {
                    type: "table",
                    title: "交易信息",
                    cols: [
                        "初始权益", "当前权益", Pair_B + "仓位", Pair_B + "持仓价", Pair_B + "收益", Pair_B + "价格", 
                        "盈利次数", "盈利金额", "亏损次数", "亏损金额", "胜率", "盈亏比"
                    ],
                    rows: [
                        [
                            _N(_G('init_eq'), 2),  // 初始权益
                            _N(curEquity, 2),  // 当前权益
                            _N(position_B.amount, 1),  // Pair B 仓位
                            _N(position_B.price, pricePrecision),  // Pair B 持仓价
                            _N(position_B.profit, 1),  // Pair B 收益
                            _N(new_r_pairB.Close, pricePrecision),  // Pair B 价格
                            _N(successCount, 0),  // 盈利次数
                            _N(winMoney, 2),  // 盈利金额
                            _N(lossCount, 0),  // 亏损次数
                            _N(failMoney, 2),  // 亏损金额
                            _N(successCount + lossCount === 0 ? 0 : successCount / (successCount + lossCount), 2),  // 胜率
                            _N(failMoney === 0 ? 0 : winMoney / failMoney * -1, 2)  // 盈亏比
                        ]
                    ]
                };

                $.PlotMultLine("ratio plot", "幅度变化差值", ratio, startLoopTime);
                $.PlotMultHLine("ratio plot", diffLevel, "差价上限", "red", "ShortDot");
                $.PlotMultHLine("ratio plot", -diffLevel, "差价下限", "blue", "ShortDot");

                LogStatus("`" + JSON.stringify(table) + "`");
                LogProfit(curEquity - initEq, '&')
            }
        }catch(e){
            Log('策略出现错误:', e)
        }

        
        Sleep(200);
    }
}