Enseñar a escribir estrategias -- trasplantar una estrategia MyLanguage

El autor:- ¿ Por qué?, Creado: 2022-12-26 15:23:08, Actualizado: 2023-09-13 19:44:28

img

Enseñarle a escribir estrategias trasplantar una estrategia de MyLanguage

Recientemente, al hablar sobre estrategias con mis amigos, aprendí que muchas estrategias escritas en MyLanguage sufren de flexibilidad. En muchos casos, es necesario usar el período estándar de la línea K que no es proporcionado por el sistema. Por ejemplo, el requisito máximo es usar la línea K durante 4 horas. Este problema ha sido resuelto en un artículo. Si estás interesado, por favor echa un vistazo:EnlaceSin embargo, en la estrategia de MyLanguage, debido a la alta característica de encapsulación de MyLanguage, no es flexible para procesar datos por sí mismo. En este momento, es necesario trasplantar la idea de estrategia a otros idiomas.

Es muy simple para el trasplante de estrategia de tendencia. podemos utilizar un código de muestra para rellenar la parte de cálculo de datos del código que conduce a la estrategia, y rellenar las condiciones de activación de la señal de comercio.

Código de muestra reutilizable:

Tomemos la estrategia para los futuros de OKX como ejemplo.

// 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)
    }
}

Ejemplo: Transplante de una estrategia de doble EMA

Prueba posterior de MyLanguage:

img

Código de estrategia de MyLanguage:

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

Transplante a la estrategia de JavaScript

En primer lugar, cumplimentar las partes de adquisición de ticker y cálculo de indicadores para el código de muestra reutilizable:

// 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]

Como pueden ver, la estrategia de doble EMA es muy simple.records, y luego utilizar la función EMATA.MAde lasTA function librarypara calcular la EMA de 5 días y la EMA de 15 días (como podemos ver en la interfaz de backtest, el período de la línea K se establece en la línea K diaria, por lo queTA.MA(records, 5)es el cálculo de la EMA de 5 días,TA.MA(records, 15)El objetivo de este método es calcular la EMA de 15 días). Entonces consigue el penúltimo puntoma5_curr(valor del indicador), el tercer último puntoma5_pre(valor del indicador) de los datos del indicadorma5, y lo mismo para elma15Entonces podemos usar estos datos de indicadores para juzgar la Cruz Dorada y el Cruce de Ojos, como se muestra en la figura:

img

Siempre que se forma tal estado, es una cruz de oro o cruce bajista.

Entonces la parte de juzgar la señal se puede escribir de la siguiente manera:

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
}

De esta manera, el trasplante está bien. Pruebas de retroceso de la estrategia JavaScript Configuración de pruebas de retroceso:

img

Resultado de las pruebas de retroceso:

img

Prueba de retroceso de MyLanguage

img

Se puede ver que los resultados de la prueba de retroceso son casi los mismos. De esta manera, si desea continuar agregando funciones interactivas, procesamiento de datos (como la síntesis de líneas K) y visualización de gráficos personalizados a la estrategia, puede lograr esto.

Si estás interesado, por favor prueba.


Relacionados

Más.