Vor kurzem, als ich mit meinen Freunden über Strategien sprach, erfuhr ich, dass viele Strategien, die in MyLanguage geschrieben wurden, an Flexibilität leiden. In vielen Fällen ist es notwendig, die Standard-K-Linie-Periode zu verwenden, die vom System nicht bereitgestellt wird. Zum Beispiel ist die maximale Anforderung, die K-Linie für 4 Stunden zu verwenden. Dieses Problem wurde in einem Artikel gelöst. Wenn Sie interessiert sind, schauen Sie sich bitte an:VerknüpfungIn der MyLanguage-Strategie ist es jedoch aufgrund der hohen Verkapselungsfunktion von MyLanguage nicht flexibel, Daten alleine zu verarbeiten.
Es ist sehr einfach für die Trendstrategie Transplantation. wir können einen Beispielcode verwenden, um den Datenberechnungsteil des Codes, der die Strategie antreibt, auszufüllen und die Handelssignal-Triggerbedingungen auszufüllen.
Nehmen wir zum Beispiel die Strategie für OKX-Futures.
// 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)
}
}
MyLanguage Backtest:
MyLanguage-Strategiecode:
MA5^^MA(C,5);
MA15^^MA(C,15);
CROSSUP(MA5,MA15),BPK;
CROSSDOWN(MA5,MA15),SPK;
Zunächst müssen die Teile für die Tickeraufnahme und die Indikatorberechnung für den wiederverwendbaren Mustercode ausgefüllt werden:
// 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]
Wie Sie sehen können, ist die doppelte EMA-Strategie sehr einfach.records
, und dann die Funktion EMA verwendenTA.MA
vonTA function library
Um die 5-tägige EMA und die 15-tägige EMA zu berechnen (wie wir in der Backtest-Schnittstelle sehen können, ist die K-Linienperiode auf die tägliche K-Line gesetzt, alsoTA.MA(records, 5)
ist die Berechnung der 5-tägigen EMA,TA.MA(records, 15)
Der 15-Tage-EMA wird berechnet).
Dann kriegen Sie den vorletzten Punktma5_curr
(Indikatorwert), der letzte dritte Punktma5_pre
(Indikatorwert) der Indikatordatenma5
, und dasselbe für diema15
Dann können wir diese Indikatordaten verwenden, um das Goldene Kreuz und den Bearish Crossover zu beurteilen, wie in der Abbildung gezeigt:
Wann immer ein solcher Zustand entsteht, ist es ein bestimmtes Goldenes Kreuz oder ein Bärenkreuz.
Dann kann der Teil der Beurteilung des Signals wie folgt geschrieben werden:
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
}
Auf diese Weise ist die Transplantation in Ordnung. Backtesting der JavaScript-Strategie Konfiguration der Rückprüfung:
Rückprüfungsergebnis:
Backtesting von MyLanguage
Wenn Sie weiterhin interaktive Funktionen, Datenverarbeitung (z. B. K-Liniensynthese) und maßgeschneiderte Diagrammdarstellung der Strategie hinzufügen möchten, können Sie dies erreichen.
Wenn Sie interessiert sind, versuchen Sie es bitte.