Apprendre à écrire des stratégies -- transplanter une stratégie MyLanguage

Auteur:Je ne sais pas., Créé: 2022-12-26 15:23:08, Mis à jour: 2023-09-13 19:44:28

img

Apprendre à écrire des stratégies transplanter une stratégie MyLanguage

Récemment, en parlant de stratégies avec mes amis, j'ai appris que de nombreuses stratégies écrites en MyLanguage souffrent de flexibilité. Dans de nombreux cas, il est nécessaire d'utiliser la période standard de la ligne K qui n'est pas fournie par le système. Par exemple, l'exigence maximale est d'utiliser la ligne K pendant 4 heures. Ce problème a été résolu dans un article. Si vous êtes intéressé, s'il vous plaît jetez un oeil:LienCependant, dans la stratégie MyLanguage, en raison de la fonctionnalité d'encapsulation élevée de MyLanguage, il n'est pas flexible de traiter les données par lui-même.

Nous pouvons utiliser un code d'échantillon pour remplir la partie de calcul des données du code qui conduit la stratégie, et remplir les conditions de déclenchement du signal de trading.

Code de l'échantillon réutilisable:

Prenons l'exemple de la stratégie pour les contrats à terme OKX.

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

Exemple: Transplantation d'une double stratégie EMA

Test de retour de MyLanguage:

img

Code de stratégie MyLanguage:

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

Transférer à la stratégie JavaScript

Commencez par remplir les parties d'acquisition du ticker et de calcul de l'indicateur pour le code d'échantillon réutilisable:

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

Comme vous pouvez le voir, la stratégie double EMA est très simple.records, puis utiliser la fonction EMATA.MAdeTA function librarypour calculer l'EMA à 5 jours et l'EMA à 15 jours (comme on peut le voir dans l'interface de backtest, la période de la ligne K est réglée sur la ligne K quotidienne, doncTA.MA(records, 5)est de calculer l'EMA à 5 jours,TA.MA(records, 15)est de calculer l'EMA à 15 jours). Alors, prends l'avant-dernier pointma5_curr(valeur de l'indicateur), le dernier troisième pointma5_pre(valeur indicateur) des données de l'indicateurma5, et la même chose pour lema15Ensuite, nous pouvons utiliser ces données d'indicateur pour juger de la Croix d'Or et du croisement baissier, comme indiqué sur la figure:

img

Chaque fois qu'un tel état est formé, c'est un certain Golden Cross ou Bearish Crossover.

Ensuite, la partie du jugement du signal peut être écrite comme suit:

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 cette façon, la greffe est bonne. Test de retour de la stratégie JavaScript Configuration des tests de retour:

img

Résultat des tests antérieurs:

img

Test de retour de MyLanguage

img

On peut voir que les résultats du backtest sont presque les mêmes. De cette façon, si vous voulez continuer à ajouter des fonctions interactives, le traitement des données (comme la synthèse de la ligne K), et l'affichage de graphique personnalisé à la stratégie, vous pouvez y parvenir.

Si vous êtes intéressé, essayez.


Relationnée

Plus de