Die Ressourcen sind geladen. Beförderung...

Detaillierte Erläuterung von Futures Backhand Verdoppelung Algorithmus Strategie Hinweise

Schriftsteller:FMZ~Lydia, Erstellt: 2022-11-10 18:23:36, Aktualisiert: 2023-09-14 20:39:31

img

Diese Strategie ist eine Strategie, die vor langer Zeit auf der Digital Currency 796 Futures Exchange angewendet wurde. Futures-Kontrakte sind währungsbasiert, dh die Marge wird nach Währung abgezogen (z. B. werden BTC-Kontrakte durch BTC abgezogen). Die Strategie wird für das Lernen der Strategieentwicklung verwendet, die Logikverarbeitung ist immer noch sehr gut, und die Strategie wird hauptsächlich für das Lernen verwendet.

Anmerkungen zum Strategiecode

var FirstTradeType = [ORDER_TYPE_BUY, ORDER_TYPE_SELL][OpType];   // The first opening position direction is determined according to the parameter OpType opening position direction. The value of the global variable FirstTradeType is ORDER_ TYPE_ BUY or ORDER_ TYPE_ SELL
var OrgAccount = null;                                            // Global variable, recording account assets
var Counter = {s : 0, f: 0};                                      // Declare a variable Counter, the value is initialized to an object (a similar structure python named dictionary), s represents the number of win time, f represents the number of losses
var LastProfit = 0;                                               // Recent P&L
var AllProfit = 0;                                                // Total P&L
var _Failed = 0;                                                  // Number of stop-losses

// Cancel all orders other than those with an ID in the list of pending orders. If the orderId parameter was not passed in, cancel all pending orders of the current trading pair. The parameter e is the reference of the exchange object. For example, when exchange is passed in as a parameter, e is the alias of exchange
function StripOrders(e, orderId) {                                
    var order = null;                               // Initialize the variable order to null
    if (typeof(orderId) == 'undefined') {           // If the parameter orderId is not written when it is passed in, then typeof (orderId)=='undefined' holds, the code block of the if statement is executed, and the orderId is assigned to null
        orderId = null;
    }
    while (true) {                                  // Process loop
        var dropped = 0;                            //  Process number of markers
        var orders = _C(e.GetOrders);               // Call GetOrders to get the current pending orders (orders that are not dealt) and assign the value to orders
        for (var i = 0; i < orders.length; i++) {   // Traverse the list of outstanding orders
            if (orders[i].Id == orderId) {          // If the order ID is the same as the order ID passed in the parameter, assign the value orders[i] to the local variable order in the function. Orders [i] refers to the current order structure when traversing
                order = orders[i];
            } else {                                // If the IDs are not the same, perform revocation
                var extra = "";                     // Set the extension information extra according to the partial deals
                if (orders[i].DealAmount > 0) {
                    extra = "Deal:" + orders[i].DealAmount;
                } else {
                    extra = "Unsettled";
                }
                e.SetDirection(orders[i].Type == ORDER_TYPE_BUY ? "buy" : "sell");
                e.CancelOrder(orders[i].Id, orders[i].Type == ORDER_TYPE_BUY ? "purchase order" : "selling order", extra);    // Cancel the order, with extra information output, which will be displayed in the log
                dropped++;                           // dropped count accumulation
            }
        }
        if (dropped == 0) {                          // When the traversal is completed, dropped is equal to 0, that is, there is no cancellation during traversal (there is no order to be canceled), that is, the cancellation processing is completed, and the while loop is skipped
            break;
        }
        Sleep(300);                                  // Prevent the rotation frequency from being too fast, with a certain interval each time
    }
    return order;                                    // Return the order to find
}


var preMsg = "";                                      // Variables for recording cache information
function GetAccount(e, waitFrozen) {                  // Obtain the account asset information. The parameter e is also a reference to exchange. The parameter waitFrozen controls whether to wait for freezing
    if (typeof(waitFrozen) == 'undefined') {          // If the waitFrozen parameter is not passed in during the call, the parameter waitFrozen is assigned a value of false, that is, the default is not to wait for freezing
        waitFrozen = false;
    }
    var account = null;
    var alreadyAlert = false;                         // Mark if the variable has been alerted
    while (true) {                                    // Get the current account information and detect freezing. If you do not wait for freezing, it will skip the while loop directly
        account = _C(e.GetAccount);
        if (!waitFrozen || account.FrozenStocks < MinStock) {
            break;
        }
        if (!alreadyAlert) {
            alreadyAlert = true;                      // Once the reminder is triggered, the alreadyAlert will be reset to avoid repeated reminders
            Log("find frozen money or currencies in the account", account);       // Output reminder log
        }
        Sleep(Interval);
    }
    msg = "successful:" + Counter.s + "times, failed:" + Counter.f + "times, current account currencies: " + account.Stocks;
    if (account.FrozenStocks > 0) {
        msg += "frozen currencies:" + account.FrozenStocks;
    }

    if (msg != preMsg) {                              // Check if the current message is different from the last one, and update it on the status bar if it is different
        preMsg = msg;
        LogStatus(msg, "#ff0000");
    }
    return account;                                   // Function returns to account structure of the account information
}

function GetPosition(e, orderType) {                  // Get the position, or get the position in the specified direction
    var positions = _C(e.GetPosition);                // Get the position
    if (typeof(orderType) == 'undefined') {           // The orderType parameter is the position type speicfied to be obtained. If no orderType parameter is passed in, all positions will be returned directly
        return positions;
    }
    for (var i = 0; i < positions.length; i++) {      // Traverse the list of positions
        if (positions[i].Type == orderType) {         // If the current traversed position data is the direction to be found (orderType)
            return positions[i];                      // Return to the position of orderType
        }
    }
    return null;
}

function GetTicker(e) {                               // Get ticker market data
    while (true) {
        var ticker = _C(e.GetTicker);                 // Get ticker market information
        if (ticker.Buy > 0 && ticker.Sell > 0 && ticker.Sell > ticker.Buy) {   // Check the reliability of the market data
            return ticker;                            // Return to ticker data
        }
        Sleep(100);
    }
}
// mode = 0 : direct buy, 1 : buy as buy1
function Trade(e, tradeType, tradeAmount, mode, slidePrice, maxSpace, retryDelay) {      // Trading functions
    // e Exchange object reference, trading direction of tradeType (buy/sell), trading volume of tradeAmount, the trading mode is mode, slidePrice means slide price, maxSpace means maximum distance of pending order, retryDelay means retry intervals
    var initPosition = GetPosition(e, tradeType);      // Get the position data of the specified direction, name it as initPosition
    var nowPosition = initPosition;                    // Declare another variable, nowPosition, and assign it with initPosition
    var orderId = null;
    var prePrice = 0;            // The price of placing order at last loop
    var dealAmount = 0;          // Number of transactions already made
    var diffMoney = 0;           
    var isFirst = true;          // The marker of first loop execution
    var tradeFunc = tradeType == ORDER_TYPE_BUY ? e.Buy : e.Sell;     // Function for placing orders, and call e.Buy or e.Sell according to the parameter tradeType
    var isBuy = tradeType == ORDER_TYPE_BUY;                          // Marker for buying
    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;                                           // Set transaction prices based on mode parameters
        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) {                                            // Judge according to the isFirst marker variable, if it is the first execution, do nothing
                isFirst = false;                                      // Set the isFirst marker as false, indicating that it was not executed for the first time
            } else {                                                  // Non-first execution, update the position data
                nowPosition = GetPosition(e, tradeType);
            }
            dealAmount = _N((nowPosition ? nowPosition.Amount : 0) - (initPosition ? initPosition.Amount : 0), 6);   // Calculate the number of transactions according to the initial position data and current position data
            var doAmount = Math.min(tradeAmount - dealAmount, account.Stocks * MarginLevel, 4);      // Calculate the remaining amount to be transacted according to the number of transactions and the available assets of the account
            if (doAmount < MinStock) {                                                               // If the calculated transaction amount is less than the minimum transaction amount, stop the logic and skip out of the while loop
                break;
            }
            prePrice = tradePrice;                                                                   // Cache the transaction price in the current loop
            e.SetDirection(tradeType == ORDER_TYPE_BUY ? "buy" : "sell");                            // Set the direction of futures trading
            orderId = tradeFunc(tradePrice, doAmount);                                               // Place a transaction, the parameters are the calculated price, the number of orders placed for this time
        } else {                                                                                     // If the orderId of the recorded order variable is not null, it indicates that an order has been placed
            if (mode == 0 || Math.abs(tradePrice - prePrice) > maxSpace) {                           // If it is the maker mode, the current price and the last cached price exceed the maximum maker range
                orderId = null;                                                                      // Reset the orderId to a null value, and the order will be placed again in the next loop
            }
            var order = StripOrders(exchange, orderId);                                              // Call StripOrders to find the order with ID of orderId in the list of pending orders
            if (order == null) {                                                                     // If it cannot be found, reset the orderId to a null value, too, and continue the next round of order placement
                orderId = null;
            }
        }
        Sleep(retryDelay);                                                                           // A certain time is tentatively determined to control the frequency of the loop
    }

    if (dealAmount <= 0) {                                                                           // At the end of the while loop, if the amount of dealAmount is less than or equal to 0, it means that the transaction failed to return the null value
        return null;
    }

    return nowPosition;                                                                              // If it's normal condition, returns to the latest position data
}

function coverFutures(e, orderType) {                               // Function for closing the position
    var coverAmount = 0;                                            // Declare a variable coverAmount with an initial assignment of 0 to record the amount of closed positions
    while (true) {
        var positions = _C(e.GetPosition);                          // Obtain the position
        var ticker = GetTicker(e);                                  // Obtain the current quotations
        var found = 0;                                              // Find the marker
        for (var i = 0; i < positions.length; i++) {                // Iterate through the array of positions
            if (positions[i].Type == orderType) {                   // Find the position needed
                if (coverAmount == 0) {                             
                    coverAmount = positions[i].Amount;              // Record the position amount at the beginning, that is, the amount to be closed
                }
                if (positions[i].Type == ORDER_TYPE_BUY) {          // Perform the closing position operation according to the position type
                    e.SetDirection("closebuy");                     // Set the futures trading direction
                    e.Sell(ticker.Buy, positions[i].Amount);        // Order function
                } else {
                    e.SetDirection("closesell");
                    e.Buy(ticker.Sell, positions[i].Amount);
                }
                found++;                                            // Marker accumulation
            }
        }
        if (found == 0) {                                           // If the marker variable found is 0, then there are no positions to process and the while loop is skipped
            break;
        }
        Sleep(2000);                                                // 2 seconds interval
        StripOrders(e);                                             // Cancel all the current pending orders
    }
    return coverAmount;                                             // Return to the number of closed positions
}


function loop(pos) {
    var tradeType = null;                         // Trading direction of initialization
    if (typeof(pos) == 'undefined' || !pos) {     // Determine if it is the first round of execution
        tradeType = FirstTradeType;
        pos = Trade(exchange, tradeType, OpAmount, OpMode, SlidePrice, MaxSpace, Interval);     // First transaction
        if (!pos) {
            throw "Failure to open a position";
        } else {
            Log(tradeType == ORDER_TYPE_BUY ? "Open long positions to complete" : "Open short positions to complete", "average price:", pos.Price, "amount:", pos.Amount);
        }
    } else {
        tradeType = pos.Type;        // Continue to specify the direction of the transaction according to the direction of the position
    }
    var holdPrice = pos.Price;       // Position price
    var holdAmount = pos.Amount;     // Position amount

    var openFunc = tradeType == ORDER_TYPE_BUY ? exchange.Buy : exchange.Sell;     // Long position, open position to buy, otherwise open position to sell
    var coverFunc = tradeType == ORDER_TYPE_BUY ? exchange.Sell : exchange.Buy;    // Long position, close position to sell, otherwise close position to buy

    var reversePrice = 0;           // Backhand price
    var coverPrice = 0;             // The price of closing the position
    var canOpen = true;             // Mark of opening position

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

    var coverId = null;
    var msg = "Position price" + holdPrice + "stop loss price:" + reversePrice;

    for (var i = 0; i < 10; i++) {               // It controls up to 10 orders
        if (coverId) {                           // The order ID is empty, and the break is not triggered. Continue the loop until 10 times
            break;
        }
        if (tradeType == ORDER_TYPE_BUY) {       // Place an order according to the direction and place a closing position order, i.e. an order to stop profit
            exchange.SetDirection("closebuy");
            coverId = exchange.Sell(coverPrice, holdAmount, msg);
        } else {
            exchange.SetDirection("closesell");
            coverId = exchange.Buy(coverPrice, holdAmount, msg);
        }

        Sleep(Interval);
    }

    if (!coverId) {                // Failed to place an order for 10 times and threw an error, the strategy stopped
        StripOrders(exchange);     // Cancel all the pending orders
        Log("Failed to place an order", "@")        // Add push alerts
        throw "Failed to place an order";           // Throw an error to stop the robot
    }


    while (true) {                 // Enter the loop of detecting the backhand
        Sleep(Interval);           
        var ticker = GetTicker(exchange);                                // Get the latest quotation
        if ((tradeType == ORDER_TYPE_BUY && ticker.Last < reversePrice) || (tradeType == ORDER_TYPE_SELL && ticker.Last > reversePrice)) {   // Detect trigger stop loss and backhand
            StripOrders(exchange);                                       // Cancel all the pending orders
            var coverAmount = coverFutures(exchange, tradeType);         // Closinng all the positions
            if (_Failed >= MaxLoss) {                                    // If the maximum stop loss times (backhand times) are exceeded, skip out of the loop and start again
                Counter.f++;                                             // Record a failure
                Log("Exceed  the maximum number of failures", MaxLoss);
                break;                                                   // Skip out of the loop
            }
            var reverseAmount = _N(coverAmount * ReverseRate, 4);        // Double the trading volume according to the amount of closed positions

            var account = GetAccount(exchange, true);                    // Update the account information. At this time, no assets can be frozen
            // Check whether the account assets are sufficient. If not, skip out of the loop and start again, as _ Failed >= MaxLoss
            if (_N(account.Stocks * MarginLevel, 4) < reverseAmount) {   // Check whether the assets are sufficient
                Log("Open a backhand position if there is no currencies, it needs to be opened: ", reverseAmount, "amount, only", account.Stocks, "currencies");
                Counter.f++;
                break;
            }
            var reverseType = tradeType;                                 // Record the reverse operation type. The default is forward position
            if (ReverseMode == 0) {                                      // The backhand mode affects the adjustment, that is, if the parameter is set to the reverse position, adjust here
                reverseType = tradeType == ORDER_TYPE_BUY ? ORDER_TYPE_SELL : ORDER_TYPE_BUY; // Reverse the position means that if you have a long position just now, you shall go short at this time. If you have a short position just now, you shall go long at this time
            }
            var pos = Trade(exchange, reverseType, reverseAmount, OpMode, SlidePrice, MaxSpace, Interval);    // Double the operation of placing an order
            if (pos) {                                                                                        // Detect the positions after trading logic execution
                Log(reverseType == ORDER_TYPE_BUY ? "long position" : "short position", "Complete it by doubling the opening position");
            }
            return pos;                                                                                       // Return to the position structure
        } else {                                          // Logic executed when no backhand is triggered
            var orders = _C(exchange.GetOrders);          // When the stop-profit order is filled, the number of wins recorded will be increased by 1
            if (orders.length == 0) {
                Counter.s++;
                var account = GetAccount(exchange, true); // Update account assets
                LogProfit(account.Stocks, account);       // Print account assets
                break;
            }
        }
    }

    // If it is not returned normally in the while loop, return to null. For example, if the profit stop is successful, the number of failures is exceeded, and the asset is insufficient
    return null;
}

function onexit() {          // When the robot stops, execute the round-off function onexit
    StripOrders(exchange);   // Cancel all the pending orders
    Log("Exit");
}

function main() {
    if (exchange.GetName().indexOf("Futures") == -1) {    // Check whether the first exchange object currently added is a futures exchange
        throw "Only futures are supported, but not spots for now";
    }
    // EnableLogLocal(SaveLocal);
    if (exchange.GetRate() != 1) {                        // Do not enable exchange rate conversion
        Log("Exchange rate conversion disabled");
        exchange.SetRate(1);
    }

    StopProfit /= 100;                                    // The parameter is processed as a decimal number. If StopProfit is 1, it means that stop profit when it is 1%. Recalculate the assignment. The value of StopProfit is 0.01, that is, 1%
    StopLoss /= 100;                                      // Stop loss (backhand), same as above

    var eName = exchange.GetName();
    if (eName == "Futures_CTP") {                         // Detect whether the first exchange object added is a commodity futures. If so, throw an error message to stop the robot
        throw "Only digital currency futures are supported for now"
    }
    exchange.SetContractType(Symbol);                     // Set the digital currency contract code, i.e. the contract to be traded and operated
    exchange.SetMarginLevel(MarginLevel);                 // Set leverage
    Interval *= 1000;                                     // The polling interval parameter is converted from seconds to milliseconds
    SetErrorFilter("502:|503:|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF");    // Set the type of error to be blocked
    StripOrders(exchange);                                // Cancel all the pending orders
    OrgAccount = GetAccount(exchange, true);              // Get the current account information
    LogStatus("start successfully");                                 // Update status bar information
    var pos = null;                                       // Initialize the local variable pos to null in the main function, which is used to record the position data structure
    var positions = GetPosition(exchange);                // Get the current positions. Call the encapsulated GetPosition without the orderType parameter to get all positions. Note that the API interface exchange.GetPosition is not called
    if (positions.length == 1) {                          // If there is a position at the beginning, assign a value to the pos variable
        pos = positions[0];
        Log("A position was found, and the progress has been restored automatically");
    } else if (positions.length > 1) {                    // When there are multiple positions, the strategy cannot be operated and the strategy throws an error to stop the robot
        throw "More than 1 position was found";
    }
    while (true) {                                        // Strategy main loop
        pos = loop(pos);                                  // The main function loop of the trading logic is executed, and pos is used as a parameter, and the new position data structure is returned
        if (!pos) {                                       // This condition is triggered and null is returned. For example, if the profit is stopped successfully, the number of failures is exceeded, and the asset is insufficient
            _Failed = 0;                                  // Reset the time of stop loss to 0 and start again
        } else {
            _Failed++;                                    // Accumulated time of stop loss
        }
        Sleep(Interval);
    }
}

Strategie Logik

Nach dem Lesen des Strategiecodes können wir feststellen, dass die Strategielogik nicht kompliziert ist und es nicht viele Codes gibt, aber das Design ist genial und es kann an vielen Stellen als Referenz verwendet werden. Die Hauptfunktion der Strategiehandelslogik ist dieloopFunktion, die wiederholt in der Hauptschleife dermainDieloopDie Funktion beginnt mit der Ausführung, platziert zuerst eine Orderposition, platziert dann einen Oder zum Stop-Profit und wartet auf die Erfüllung der Stop-Profit-Order.

  • Ermitteln, ob die ausstehende Stop-Profit-Order vollständig ausgeführt ist. Wenn ja, also Profit, verlassen Sie die Detektionsschleife, setzen Sie die Logik zurück und beginnen Sie erneut.
  • Detektieren, ob der Stop-Loss (Backhand) ausgelöst werden soll, aktivieren Sie den Stop-Loss, d.h. stornieren Sie alle ausstehenden Aufträge, schließen Sie die Position und setzen Sie dann die Backhand-Forward-Position oder die Backhand-Reverse-Position, um den Backhand-Auftrag entsprechend dem Parameter zu verdoppeln.

Die Strategie-Logik ist einfach beschrieben, aber es gibt noch einige weitere Details, wie die Festlegung der maximalen Backhand-Zeiten, die Erkennung der verfügbaren Kontovermögen und die Bearbeitung der maximalen Anzahl von Auftragsausfällen von 10 Mal. Einige Funktionen in der Strategie sind so konzipiert, dass sie sich je nach verschiedenen Parametern unterschiedlich verhalten:StripOrdersFunktion,GetAccountFunktion,GetPositionDiese Funktionen haben je nach Parameterunterschied unterschiedliches Verhalten. Auf diese Weise wird der Code gut wiederverwendet, Code-Redundanz wird vermieden und das Strategie-Design ist prägnant und leicht verständlich.

Ursprüngliche Strategie:https://www.fmz.com/strategy/3648

Backhand-Doppeln birgt gewisse Risiken, vor allem in den Futures, die Strategie ist nur für Lernzwecke, Vorsicht beim echten Bot, bitte lassen Sie Ihre Kommentare und wir können eine Diskussion führen.


Verwandt

Mehr