Dạy bạn viết chiến lược -- cấy ghép một chiến lược MyLanguage

Tác giả:Lydia., Tạo: 2022-12-26 15:23:08, Cập nhật: 2023-09-13 19:44:28

img

Dạy bạn viết các chiến lược cấy ghép một chiến lược MyLanguage

Gần đây, khi nói về chiến lược với bạn bè, tôi đã biết rằng nhiều chiến lược được viết trong MyLanguage bị linh hoạt. Trong nhiều trường hợp, cần phải sử dụng khoảng K-line tiêu chuẩn mà hệ thống không cung cấp. Ví dụ, yêu cầu tối đa là sử dụng K-line trong 4 giờ. Vấn đề này đã được giải quyết trong một bài viết. Nếu bạn quan tâm, vui lòng xem:Liên kếtTuy nhiên, trong chiến lược MyLanguage, do tính năng đóng gói cao của MyLanguage, nó không linh hoạt để xử lý dữ liệu một mình.

Chúng ta có thể sử dụng một mã mẫu để điền vào phần tính toán dữ liệu của mã điều khiển chiến lược, và điền vào các điều kiện kích hoạt tín hiệu giao dịch.

Mã mẫu tái sử dụng:

Lấy chiến lược cho tương lai OKX làm ví dụ.

// Global variables
var IDLE = 0
var LONG = 1
var SHORT = 2
var OPENLONG = 3
var OPENSHORT = 4
var COVERLONG = 5
var COVERSHORT = 6  

var BREAK = 9
var SHOCK = 10  

var _State = IDLE
var Amount = 0                 // Record the number of positions
var TradeInterval = 500        // Polling intervals
var PriceTick = 1              // Price per jump
var Symbol = "this_week"  

function OnTick(){
    // Ticker processing part of the driving strategy
    // To be filled...
     
    // Trading signal trigger processing section
    // To be filled...  

    // Execution of trading logic
    var pos = null
    var price = null
    var currBar = records[records.length - 1]
    if(_State == OPENLONG){
        pos = GetPosition(PD_LONG)
        // Determine whether the state is satisfied, and if so, modify the state.
        if(pos[1] >= Amount){
            _State = LONG
            Amount = pos[1]   // Update the actual volume.
            return
        }
        price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2
        Trade(OPENLONG, price, Amount - pos[1], pos, PriceTick)                // (Type, Price, Amount, CurrPos, PriceTick)
    }  

    if(_State == OPENSHORT){
        pos = GetPosition(PD_SHORT)
        if(pos[1] >= Amount){
            _State = SHORT
            Amount = pos[1]   // Update the actual volume.
            return
        }
        price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2
        Trade(OPENSHORT, price, Amount - pos[1], pos, PriceTick)
    }  

    if(_State == COVERLONG){
        pos = GetPosition(PD_LONG)
        if(pos[1] == 0){
            _State = IDLE
            return
        }
        price = currBar.Close - (currBar.Close % PriceTick) - PriceTick * 2
        Trade(COVERLONG, price, pos[1], pos, PriceTick)
    }
    
    if(_State == COVERSHORT){
        pos = GetPosition(PD_SHORT)
        if(pos[1] == 0){
            _State = IDLE
            return
        }
        price = currBar.Close - (currBar.Close % PriceTick) + PriceTick * 2
        Trade(COVERSHORT, price, pos[1], pos, PriceTick)
    }
}  

// Trading logic section
function GetPosition(posType) {
    var positions = _C(exchange.GetPosition)
    var count = 0
    for(var j = 0; j < positions.length; j++){
        if(positions[j].ContractType == Symbol){
            count++
        }
    }  

    if(count > 1){
        throw "positions error:" + JSON.stringify(positions)
    }  

    for (var i = 0; i < positions.length; i++) {
        if (positions[i].ContractType == Symbol && positions[i].Type === posType) {
            return [positions[i].Price, positions[i].Amount];
        }
    }
    Sleep(TradeInterval);
    return [0, 0];
}  

function CancelPendingOrders() {
    while (true) {
        var orders = _C(exchange.GetOrders)
        for (var i = 0; i < orders.length; i++) {
            exchange.CancelOrder(orders[i].Id);
            Sleep(TradeInterval);
        }
        if (orders.length === 0) {
            break;
        }
    }
}  

function Trade(Type, Price, Amount, CurrPos, OnePriceTick){    // Processing transactions
    if(Type == OPENLONG || Type == OPENSHORT){                 // Processing of opening positions
        exchange.SetDirection(Type == OPENLONG ? "buy" : "sell")
        var pfnOpen = Type == OPENLONG ? exchange.Buy : exchange.Sell
        var idOpen = pfnOpen(Price, Amount, CurrPos, OnePriceTick, Type)
        Sleep(TradeInterval)
        if(idOpen) {
            exchange.CancelOrder(idOpen)
        } else {
            CancelPendingOrders()
        }
    } else if(Type == COVERLONG || Type == COVERSHORT){        // Processing of closing positions
        exchange.SetDirection(Type == COVERLONG ? "closebuy" : "closesell")
        var pfnCover = Type == COVERLONG ? exchange.Sell : exchange.Buy
        var idCover = pfnCover(Price, Amount, CurrPos, OnePriceTick, Type)
        Sleep(TradeInterval)
        if(idCover){
            exchange.CancelOrder(idCover)
        } else {
            CancelPendingOrders()
        }
    } else {
        throw "Type error:" + Type
    }
}  

function main() { 
    // Set up the contract
    exchange.SetContractType(Symbol)  

    while(1){
        OnTick()
        Sleep(1000)
    }
}

Ví dụ: Cấy ghép chiến lược EMA đôi

MyLanguage backtest:

img

Mã chiến lược MyLanguage:

MA5^^MA(C,5);
MA15^^MA(C,15);
CROSSUP(MA5,MA15),BPK;
CROSSDOWN(MA5,MA15),SPK;

Chuyển sang Chiến lược JavaScript

Đầu tiên, hãy điền vào các phần tính toán chỉ số và tính toán chỉ số cho mã mẫu tái sử dụng:

// The ticker processing part of the driving strategy
var records = _C(exchange.GetRecords)  

if (records.length < 15) {
    return 
}  

var ma5 = TA.MA(records, 5)
var ma15 = TA.MA(records, 15)
var ma5_pre = ma5[ma5.length - 3]
var ma15_pre = ma15[ma15.length - 3]
var ma5_curr = ma5[ma5.length - 2]
var ma15_curr = ma15[ma15.length - 2]

Như bạn có thể thấy, chiến lược EMA đôi rất đơn giản.records, và sau đó sử dụng hàm EMATA.MAcủaTA function libraryđể tính toán EMA 5 ngày và EMA 15 ngày (như chúng ta có thể thấy trong giao diện backtest, thời gian đường K được đặt vào đường K hàng ngày, vì vậyTA.MA(records, 5)là tính toán EMA 5 ngày,TA.MA(records, 15)là để tính EMA 15 ngày). Rồi lấy điểm trước cuối cùngma5_curr(giá trị chỉ số), điểm thứ ba cuối cùngma5_pre(giá trị chỉ số) của dữ liệu chỉ sốma5, và tương tự cho cácma15Sau đó chúng ta có thể sử dụng dữ liệu chỉ số này để đánh giá Golden Cross và Bearish Crossover, như được hiển thị trong hình:

img

Bất cứ khi nào một trạng thái như vậy được hình thành, nó là một Golden Cross hoặc Bearish Crossover.

Sau đó, phần đánh giá tín hiệu có thể được viết như sau:

if(_State == IDLE && ma5_pre < ma15_pre && ma5_curr > ma15_curr){     
    _State = OPENLONG
    Amount = 1
}  

if(_State == IDLE && ma5_pre > ma15_pre && ma5_curr < ma15_curr){     
    _State = OPENSHORT
    Amount = 1
}  

if(_State == LONG && ma5_pre > ma15_pre && ma5_curr < ma15_curr){     
    _State = COVERLONG
    Amount = 1
}  

if(_State == SHORT && ma5_pre < ma15_pre && ma5_curr > ma15_curr){     
    _State = COVERSHORT
    Amount = 1
}

Bằng cách này, việc cấy ghép sẽ ổn. Kiểm tra lại chiến lược JavaScript Cấu hình kiểm tra ngược:

img

Kết quả kiểm tra hậu quả:

img

Kiểm tra lại MyLanguage

img

Có thể thấy rằng kết quả của backtest gần như giống nhau. Bằng cách này, nếu bạn muốn tiếp tục thêm các chức năng tương tác, xử lý dữ liệu (chẳng hạn như tổng hợp đường K) và hiển thị biểu đồ tùy chỉnh cho chiến lược, bạn có thể đạt được điều này.

Nếu bạn quan tâm, hãy thử.


Có liên quan

Thêm nữa