퓨처스 리버스 더블링 알고리즘 전략의 참고 & 설명

저자:니나바다스, 창작: 2022-04-27 15:44:04, 업데이트: 2022-04-28 12:05:02

퓨처스 리버스 더블링 알고리즘 전략의 참고 & 설명

이 전략은 오랫동안 암호화폐 796 미래에셋 거래소에 적용된 전략입니다. 선물 계약은 암호화 마진, 즉 마진이 통화에서 인하됩니다 (예를 들어 BTC 계약에서는 BTC에서 인하됩니다), 계약 주문 금액은 바이낸스 암호화 마진 계약과 유사한 소수 수치가 될 수 있습니다. 전략은 전략 설계 연구를 위해 꺼져, 논리 처리 여전히 매우 좋은, 그래서 전략은 주로 학습을 위해.

전략 코드 참고:

var FirstTradeType = [ORDER_TYPE_BUY, ORDER_TYPE_SELL][OpType];   // the opening direction of the first trade is determined by the opening direction of the parameter OpType, and the value of the global variable FirstTradeType is ORDER_TYPE_BUY or ORDER_TYPE_SELL
var OrgAccount = null;                                            // the global variable, to record the account assets  
var Counter = {s : 0, f: 0};                                      // declare the variable Counter; its value is initialized as an object (similar structure in Python is called dictionary); "s" represents the number of win, and "f" represents the number of failure
var LastProfit = 0;                                               // the recent profit and loss 
var AllProfit = 0;                                                // the total rofit and loss 
var _Failed = 0;                                                  // the number of stop loss 

// Cancel all orders except the order of a certain ID in the pending order list. When the orderId parameter is not passed, all pending orders of the current trading pair are cancelled. The parameter "e" is the reference of the exchange object. For example, import exchange as parameter, "e" is now the alias of exchange
function StripOrders(e, orderId) {                                
    var order = null;                               // the initialization variable "order" is null  
    if (typeof(orderId) == 'undefined') {           // If the parameter orderId is not written, then typeof(orderId) == 'undefined' is true, and the code block of the if statement is executed, and the orderId is assigned to null
        orderId = null;
    }
    while (true) {                                  // processing loop 
        var dropped = 0;                            // the number of processing marks 
        var orders = _C(e.GetOrders);               // call GetOrders to obtain the current pending orders (not executed orders), and assign to orders
        for (var i = 0; i < orders.length; i++) {   // traverse the list of unexecuted orders "orders"
            if (orders[i].Id == orderId) {          // if the order ID is the same as the ID in the parameter "orderId", the local variable "order" assign a value to orders[i], which is the current order structure when traversing 
                order = orders[i];
            } else {                                // if the order ID is not the same as the ID in the parameter "orderId", execute the cancellation operation  
                var extra = "";                     // according to part of executed situation, set the extending information "extra"
                if (orders[i].DealAmount > 0) {
                    extra = "Executed:" + orders[i].DealAmount;
                } else {
                    extra = "Unexecuted:";
                }
                e.SetDirection(orders[i].Type == ORDER_TYPE_BUY ? "buy" : "sell");
                e.CancelOrder(orders[i].Id, orders[i].Type == ORDER_TYPE_BUY ? "buy order" : "sell order", extra);    // cancellation operation along with exporting "extra" information, which will be displayed in logs 
                dropped++;                           // dropped, accumulated counts
            }
        }
        if (dropped == 0) {                          // when the traverse is done, "dropped" is equal to 0, namely no cancellation processing during the traverse (which means no order to be canceled); that is to say the cancellation processing is done, and break out of the loop 
            break;
        }
        Sleep(300);                                  // prevent over fast rotating frequency; create a time interval 
    }
    return order;                                    // return the order that needs to be found 
}


var preMsg = "";                                      // the variable to record the cached information 
function GetAccount(e, waitFrozen) {                  // to get account asset information; parameter e is also a reference to exchange, and parameter waitFrozen controls whether to wait for freezing
    if (typeof(waitFrozen) == 'undefined') {          // if the parameter waitFrozen is not passed in the call, assign false to the parameter waitFrozen, that is, the default is no waiting for freezing
        waitFrozen = false;
    }
    var account = null;
    var alreadyAlert = false;                         // the varibale to mark whether it already alerted 
    while (true) {                                    // to obtain the account information and detect frozen; if no wait for freezing, break the while loop directly 
        account = _C(e.GetAccount);
        if (!waitFrozen || account.FrozenStocks < MinStock) {
            break;
        }
        if (!alreadyAlert) {
            alreadyAlert = true;                      // trigger the alert once, and then reset alreadyAlert to avoid repeating alert 
            Log("frozen assets or symbols are found in the account", account);       // export the alert log 
        }
        Sleep(Interval);
    }
    msg = "Success: " + Counter.s + " times, failure: " + Counter.f + " times, the current account symbols: " + account.Stocks;
    if (account.FrozenStocks > 0) {
        msg += " frozen symbols: " + account.FrozenStocks;
    }

    if (msg != preMsg) {                              // detect whether the current information is the same as that last time; if not, update the informtaion on the status bar 
        preMsg = msg;
        LogStatus(msg, "#ff0000");
    }
    return account;                                   // the function returns the account stucture of the account information 
}

function GetPosition(e, orderType) {                  // obtain positions, or obtain the positions with specified direction (orderType)
    var positions = _C(e.GetPosition);                // obtain positions 
    if (typeof(orderType) == 'undefined') {           // the parameter orderType is to specify the position type; if the parameter is not imported, directly return all positions
        return positions;
    }
    for (var i = 0; i < positions.length; i++) {      // traverse the list of positions 
        if (positions[i].Type == orderType) {         // if the traversed current position data is the direction (orderType) we need 
            return positions[i];                      // return positions of orderType
        }
    }
    return null;
}

function GetTicker(e) {                               // obtain ticker market data 
    while (true) {
        var ticker = _C(e.GetTicker);                 // obtain tick market data
        if (ticker.Buy > 0 && ticker.Sell > 0 && ticker.Sell > ticker.Buy) {   // detect the reliability of the market data 
            return ticker;                            // return ticker data 
        }
        Sleep(100);
    }
}
// mode = 0 : direct buy, 1 : buy as buy1
function Trade(e, tradeType, tradeAmount, mode, slidePrice, maxSpace, retryDelay) {      // trading function 
    // e for exchange object reference, tradeType for trade direction (buy/sell), tradeAmount for the trading amount, mode for trading mode, slidePrice for slippoint price, maxSpace for maximum pending order distance, and retryDelay for retry interval
    var initPosition = GetPosition(e, tradeType);      // obtain the position data with a specified direction, recorded as initPosition
    var nowPosition = initPosition;                    // declare another variable "nowPosition", assigned by "initPosition
    var orderId = null;
    var prePrice = 0;            // the ordering price in the loop last time 
    var dealAmount = 0;          // executed trading amount 
    var diffMoney = 0;           
    var isFirst = true;          // mark of initially executing the loop 
    var tradeFunc = tradeType == ORDER_TYPE_BUY ? e.Buy : e.Sell;     // the function of placing orders; according to the parameter tradeType, determine to call e.Buy or e.Sell
    var isBuy = tradeType == ORDER_TYPE_BUY;                          // whether it is the buy mark
    while (true) {                                                    // while loop
        var account = _C(e.GetAccount);                               // obtain the current account asset data 
        var ticker = GetTicker(e);                                    // obtain the current market data 
        var tradePrice = 0;                                           // determine a trading price based on the parameter mode
        if (isBuy) {
            tradePrice = _N((mode == 0 ? ticker.Sell : ticker.Buy) + slidePrice, 4);
        } else {
            tradePrice = _N((mode == 0 ? ticker.Buy : ticker.Sell) - slidePrice, 4);
        }
        if (orderId == null) {
            if (isFirst) {                                            // according to the  mark variable isFirst to judge, if it is the first execution, nothing will be done 
                isFirst = false;                                      // if the mark isFirst is set to false, it means it is not the first execution 
            } else {                                                  // not the first executin, so update the position data 
                nowPosition = GetPosition(e, tradeType);
            }
            dealAmount = _N((nowPosition ? nowPosition.Amount : 0) - (initPosition ? initPosition.Amount : 0), 6);   // by the initial position data and the current position data, calculate the executed amount 
            var doAmount = Math.min(tradeAmount - dealAmount, account.Stocks * MarginLevel, 4);      // by the executed amount and the account available assets, calculate the rest amount that needs to be traded 
            if (doAmount < MinStock) {                                                               // if the calculated trading amount is less than the minimum of the executed amount, terminate the logic and break the while loop 
                break;
            }
            prePrice = tradePrice;                                                                   // cache the trading price in the current round of loop 
            e.SetDirection(tradeType == ORDER_TYPE_BUY ? "buy" : "sell");                            // set futures trading direction 
            orderId = tradeFunc(tradePrice, doAmount);                                               // trade of placing orders; its parameters are the calculated price and the order amount of this time
        } else {                                                                                     // when the order recording variable "orderId" is not null, it means the orders has been placed  
            if (mode == 0 || Math.abs(tradePrice - prePrice) > maxSpace) {                           // if it is the mode of pending orders, the current price and the price cached last time exceed the maximum pending order range  
                orderId = null;                                                                      // reset orderId to null, and restart to place orders in next round of loop 
            }
            var order = StripOrders(exchange, orderId);                                              // call StripOrders to find the order with ID of orderId in the pending order list 
            if (order == null) {                                                                     // if not found, reset orderId to null, and continue the next round of placing orders  
                orderId = null;
            }
        }
        Sleep(retryDelay);                                                                           // temporarily specify a certain time, to control the loop frequency 
    }

    if (dealAmount <= 0) {                                                                           // after the while loop is finished, if the executed amount "dealAmount" is less than or equal to 0, that means the trade is a failure, and return null
        return null;
    }

    return nowPosition;                                                                              // under normal circumstances, return the latest position data 
}

function coverFutures(e, orderType) {                               // function of closing positions 
    var coverAmount = 0;                                            // declare a variable coverAmount, with the default of 0, to record the amount already closed 
    while (true) {
        var positions = _C(e.GetPosition);                          // obtain positions 
        var ticker = GetTicker(e);                                  // obtain the current market quotes 
        var found = 0;                                              // search for marks 
        for (var i = 0; i < positions.length; i++) {                // traverse the array of holding positions, namely "positions"
            if (positions[i].Type == orderType) {                   // find the positions that are needed 
                if (coverAmount == 0) {                             
                    coverAmount = positions[i].Amount;              // initially record the position amount, namely the amount to be closed 
                }
                if (positions[i].Type == ORDER_TYPE_BUY) {          // execute the operation of closing positions, according to position type 
                    e.SetDirection("closebuy");                     // set the futures trading direction 
                    e.Sell(ticker.Buy, positions[i].Amount);        // function of placing orders 
                } else {
                    e.SetDirection("closesell");
                    e.Buy(ticker.Sell, positions[i].Amount);
                }
                found++;                                            // mark the accumulation 
            }
        }
        if (found == 0) {                                           // if the mark variable found is 0, it means no position to be processed, and then break out of the while loop
            break;
        }
        Sleep(2000);                                                // interval time of 2 seconds
        StripOrders(e);                                             // cancel all pending orders 
    }
    return coverAmount;                                             // return the amount of closing positions 
}


function loop(pos) {
    var tradeType = null;                         // initialize the trading direction 
    if (typeof(pos) == 'undefined' || !pos) {     //judge whether it is the initial round of execution
        tradeType = FirstTradeType;
        pos = Trade(exchange, tradeType, OpAmount, OpMode, SlidePrice, MaxSpace, Interval);     // initial trade 
        if (!pos) {
            throw "Rough start, fail to open positions";
        } else {
            Log(tradeType == ORDER_TYPE_BUY ? "opening long positions completed" : "Opening short positions completed", "Average price:", pos.Price, "Amount:", pos.Amount);
        }
    } else {
        tradeType = pos.Type;        // continue to specify the trading direction according to position direction 
    }
    var holdPrice = pos.Price;       // position price 
    var holdAmount = pos.Amount;     // position amount 

    var openFunc = tradeType == ORDER_TYPE_BUY ? exchange.Buy : exchange.Sell;     // long positions; open positions to buy; if not, open positions to sell
    var coverFunc = tradeType == ORDER_TYPE_BUY ? exchange.Sell : exchange.Buy;    // long positions; close positions to sell; if not, close positions to buy 

    var reversePrice = 0;           // reverse price
    var coverPrice = 0;             // closing position price
    var canOpen = true;             //  mark for enabling opening positions 

    if (tradeType == ORDER_TYPE_BUY) {                         
        reversePrice = _N(holdPrice * (1 - StopLoss), 4);     // stop loss price
        coverPrice = _N(holdPrice * (1 + StopProfit), 4);     // take profit price
    } else {
        reversePrice = _N(holdPrice * (1 + StopLoss), 4);
        coverPrice = _N(holdPrice * (1 - StopProfit), 4);
    }

    var coverId = null;
    var msg = "position price:" + holdPrice + " stopLoss price:" + reversePrice;

    for (var i = 0; i < 10; i++) {               // control to order 10 times maximum
        if (coverId) {                           // when the order ID is null, and break will not be triggered, continue the loop, until to the maximum of 10 times 
            break;
        }
        if (tradeType == ORDER_TYPE_BUY) {       // according to the order direction, pend orders to close, namely the take profit orders 
            exchange.SetDirection("closebuy");
            coverId = exchange.Sell(coverPrice, holdAmount, msg);
        } else {
            exchange.SetDirection("closesell");
            coverId = exchange.Buy(coverPrice, holdAmount, msg);
        }

        Sleep(Interval);
    }

    if (!coverId) {                // raise the error after 10 times of order failure, and stop the strategy 
        StripOrders(exchange);     // cancel all pending orders
        Log("fail to order", "@")        // add push alert 
        throw "fail to order";           // raise the error, and stop the bot 
    }


    while (true) {                 // enter to detect the reverse loop
        Sleep(Interval);           
        var ticker = GetTicker(exchange);                                // obtain the latest market quotes 
        if ((tradeType == ORDER_TYPE_BUY && ticker.Last < reversePrice) || (tradeType == ORDER_TYPE_SELL && ticker.Last > reversePrice)) {   // detect the trigger of stoploss, namely reverse 
            StripOrders(exchange);                                       // cancel all pending orders 
            var coverAmount = coverFutures(exchange, tradeType);         // close all positions 
            if (_Failed >= MaxLoss) {                                    // if the maximum number of stoploss (reverse times) is exceeded, break the loop and restart again  
                Counter.f++;                                             // counted as one failure 
                Log("exceed the maximum number of failures", MaxLoss);
                break;                                                   // break out of the loop
            }
            var reverseAmount = _N(coverAmount * ReverseRate, 4);        // according to the closing position amount, double the trading amount  

            var account = GetAccount(exchange, true);                    // update the account information, and here frozen assets are forbidden  
            // detect whether the assets are enough; if not, break the loop, and restart, such as _Failed >= MaxLoss
            if (_N(account.Stocks * MarginLevel, 4) < reverseAmount) {   // detect whether the assets are enough 
                Log("open positions without currency, need to open positions:", reverseAmount, "currency symbols, and there are only ", account.Stocks, "currency symbols");
                Counter.f++;
                break;
            }
            var reverseType = tradeType;                                 // record the type of the reverse operation; the default is forward
            if (ReverseMode == 0) {                                      // the adjustment of the reverse mode, that is, if the parameter is set to reverse, the adjustment is needed here  
                reverseType = tradeType == ORDER_TYPE_BUY ? ORDER_TYPE_SELL : ORDER_TYPE_BUY; // reverse indicates if the positions just now are long, the reverse now will do short; if the positions just now are short, the reverse now will do long 
            }
            var pos = Trade(exchange, reverseType, reverseAmount, OpMode, SlidePrice, MaxSpace, Interval);    // double the operation of placing orders 
            if (pos) {                                                                                        // detect the positions after the execution of the trading logic  
                Log(reverseType == ORDER_TYPE_BUY ? "long position" : "short position", "double open positions completed");
            }
            return pos;                                                                                       // return the position structure 
        } else {                                          // the trading logic executed when the reverse is not triggered 
            var orders = _C(exchange.GetOrders);          // when the take-profit pending orders are executed, add 1 to the number of win 
            if (orders.length == 0) {
                Counter.s++;
                var account = GetAccount(exchange, true); // update the account assets 
                LogProfit(account.Stocks, account);       // print the account assets 
                break;
            }
        }
    }

    // if the return is normal in a non-while loop, null is returned, such as successful take-profit, exceeding the number of failures, insufficient assets
    return null;
}

function onexit() {          // when the bot is stopped, execute the onexit function
    StripOrders(exchange);   // cancel all pending orders 
    Log("Exit");
}

function main() {
    if (exchange.GetName().indexOf("Futures") == -1) {    // detect whether the currently first added exchange object is a futures platform 
        throw "only support futures, and spot not supported temporarily";
    }
    // EnableLogLocal(SaveLocal);
    if (exchange.GetRate() != 1) {                        // disable the exchange rateconverting  
        Log("disable exchange rate converting");
        exchange.SetRate(1);
    }

    StopProfit /= 100;                                    // the parameter is processed to be decimal; assuming that StopProfit is 1, namely 1% of take-profit, recalculate the assignment and the value of StopProfit is 0.01, namely 1%.
    StopLoss /= 100;                                      // stop loss (reverse), as above 

    var eName = exchange.GetName();
    if (eName == "Futures_CTP") {                         // detect whether the currently first added exchange object is commodity futures ; if it is, raise an error to stop the bot 
        throw "temporarily only support cryptocurrency futures"
    }
    exchange.SetContractType(Symbol);                     // set the code of the cryptocurrency contract, namely the contract to be traded and operated 
    exchange.SetMarginLevel(MarginLevel);                 // set margin level 
    Interval *= 1000;                                     // change the polling interval parameter from second to millisecond 
    SetErrorFilter("502:|503:|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF");    // set the type of the error filtered 
    StripOrders(exchange);                                // cancel all pending orders 
    OrgAccount = GetAccount(exchange, true);              // obtain the current account information 
    LogStatus("start successfully");                                 // update the status bar information 
    var pos = null;                                       // initialize the variable pos to null in the main function, to record the position data structure 
    var positions = GetPosition(exchange);                // obtaining the current positions is to call the encapsulated GetPosition without orderType, to obtain all positions held; note that here the called function is not "exchange.GetPosition" of API interface 
    if (positions.length == 1) {                          // if there are positions at the beginning, assign the value to the variable pos 
        pos = positions[0];
        Log("found 1 position, and already rcovered the process automatically");
    } else if (positions.length > 1) {                    // when there are multiple positions, that is, the status in which the strategy cannot run, the strategy raises an error to make the bot stop  
        throw "found over 1 position ";
    }
    while (true) {                                        // strategy main loop 
        pos = loop(pos);                                  // execute the main function loop in the trading logic; take pos as parameter; return the new position data structure 
        if (!pos) {                                       // under the circumstance if the condition is triggered, and return null, such as the success of take-profit, exceeding the number of failures, and inadequate assets 
            _Failed = 0;                                  // reset the number of stop loss to 0, and restart it 
        } else {
            _Failed++;                                    // the accumulated number of stop loss
        }
        Sleep(Interval);
    }
}

전략 논리

전략 코드를 읽은 후, 전략 논리가 복잡하지 않고 코드가 너무 많지는 않지만 디자인이 기발하고 많은 부분이 참고로 사용될 수 있다는 것을 알 수 있습니다. 전략 거래 논리의 주요 기능은loop함수, 반복적으로 호출되는 주 루프의main기능.loop함수 시작, 먼저 포지션을 유지하기 위해 주문을 배치하고, 그 다음 수익을 내기 위해 주문을 대기하고, 수익을 멈추기 위해 주문을 실행할 때까지 기다립니다. 다음 두 가지 내용을 탐지하기 위해 탐지 상태를 입력합니다.

  • 대기 중인 영업 주문이 실행되는지 확인하기 위해; 영업 주문이 실행되는 경우, 이윤이 발생한다는 것을 의미합니다. 따라서 탐지 루프에서 벗어나 논리를 재설정하고 다시 시작하십시오.
  • 스톱 로스 (리버스) 가 트리거되는지 확인하기 위해; 그것은 트리거되는 경우, 모든 미뤄진 오더를 취소하고 포지션을 닫고, 파라미터가 리버스 또는 포워드로 설정되는지에 따라 리버스 오더 트레이드를 두 배로합니다. 포지션이 유지되고 있으며, 미뤄진 영업 주문을 계속하고 다시 탐지 상태를 입력합니다 (리버스, 리버스 모니터링).

전략 논리는 간단하게 설명되어 있지만 최대 역수수의 설정, 사용 가능한 계정 자산을 탐지하고 최대 10 배까지 실패의 처리와 같은 다른 세부 사항이 있습니다. 전략의 일부 기능은 다른 매개 변수에 따라 다르게 수행하도록 설계되었습니다. 예를 들어:StripOrders기능GetAccount기능GetPosition이 함수들은 가져온 매개 변수들의 차이에 따라 다른 동작을 합니다. 이것은 코드를 잘 사용하고, 코드 과잉을 피하고, 전략 디자인을 간결하고 이해하기 쉽도록 합니다.

원래 전략:https://www.fmz.com/strategy/3648

이중 역전에는 특정 위험이 있습니다. 특히 미래에 대한 전략은 연구용으로만 사용되며 신중하게 사용하십시오. 토론을 위해 메시지를 남기십시오.


더 많은