
Als ich kürzlich mit meinen Freunden über Strategien sprach, erfuhr ich, dass viele Leute, die meine Sprache zum Schreiben von Strategien verwenden, unter dem Problem der Flexibilität leiden. In vielen Fällen ist es notwendig, einen Standard-K-Line-Zeitraum zu verwenden, der vom System nicht bereitgestellt wird. Beispielsweise besteht die am häufigsten geforderte Anforderung darin, eine 4-Stunden-K-Line zu verwenden. Dieses Problem wurde in einem Artikel gelöst. Wer Interesse hat, kann sich diesen zunächst einmal anschauen:Link. Aufgrund der stark gekapselten Natur der „Meine Sprache“ kann dieses Problem bei der „Meine Sprache“-Strategie jedoch nicht flexibel allein Daten verarbeiten. Zu diesem Zeitpunkt ist es notwendig, das strategische Denken in andere Sprachen zu übertragen.
Es ist sehr einfach, Trendstrategien zu übertragen. Wir können einen Beispielcode verwenden, um den Datenberechnungsteil der Antriebsstrategie auszufüllen und die Auslösebedingungen für Handelssignale auszufüllen.
Nehmen Sie als Beispiel die für OKEX-Futures verwendete Strategie.
// 全局变量
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 // 记录持仓数量
var TradeInterval = 500 // 轮询间隔
var PriceTick = 1 // 价格一跳
var Symbol = "this_week"
function OnTick(){
// 驱动策略的行情处理部分
// 待填充...
// 交易信号触发处理部分
// 待填充...
// 执行交易逻辑
var pos = null
var price = null
var currBar = records[records.length - 1]
if(_State == OPENLONG){
pos = GetPosition(PD_LONG)
// 判断是不是 满足状态,如果满足 修改状态
if(pos[1] >= Amount){
_State = LONG
Amount = pos[1] // 更新实际量
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] // 更新实际量
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)
}
}
// 交易逻辑部分
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){ // 处理交易
if(Type == OPENLONG || Type == OPENSHORT){ // 处理开仓
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){ // 处理平仓
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() {
// 设置合约
exchange.SetContractType(Symbol)
while(1){
OnTick()
Sleep(1000)
}
}
Mai-Sprach-Backtest:

Mai-Sprachstrategiecode:
MA5^^MA(C,5);
MA15^^MA(C,15);
CROSSUP(MA5,MA15),BPK;
CROSSDOWN(MA5,MA15),SPK;
Füllen Sie zunächst die Teile zur Marktakquise und Indikatorberechnung im wiederverwendbaren Beispielcode aus:
// 驱动策略的行情处理部分
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, ist die Strategie des doppelten gleitenden Durchschnitts sehr einfach. Sie müssen lediglich zuerst die K-Linien-Daten abrufen.records, dann verwenden SieTA函数库Gleitende DurchschnittsfunktionTA.MABerechnen Sie den 5-Tage-Durchschnitt und den 15-Tage-Durchschnitt (Sie können auf der Backtest-Schnittstelle sehen, dass der K-Linienzeitraum auf die tägliche K-Linie eingestellt ist, alsoTA.MA(records, 5)Es wird der gleitende 5-Tage-Durchschnitt berechnet.TA.MA(records, 15)15-Tage-gleitender Durchschnitt).
Dann erhalten Siema5Der vorletzte Punkt der Indikatordatenma5_curr(Indikatorwert), drittletzter Punktma5_pre(Indikatorwert),ma15Gleiches gilt für Indikatordaten. Anschließend können Sie anhand dieser Indikatordaten das goldene Kreuz und das tote Kreuz beurteilen, wie in der Abbildung dargestellt:
Solange ein solcher Zustand gebildet wird, handelt es sich um ein bestätigtes Goldenes Kreuz oder Totes Kreuz.
Dann kann der Signalbeurteilungsteil 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
}
Dies bedeutet, dass die Transplantation in Ordnung ist und Sie sie erneut testen können:
Backtesting von JavaScript-Strategien
Backtest-Konfiguration:

回测结果:

Backtesting meiner Sprache

Es ist ersichtlich, dass die Backtesting-Ergebnisse im Wesentlichen gleich sind. Auf diese Weise können Sie der Strategie weiterhin interaktive Funktionen hinzufügen, Datenverarbeitung (wie K-Line-Synthese) hinzufügen und benutzerdefinierte Diagrammzeichnung und -anzeige hinzufügen. es kann erreicht werden.
Interessierte Studierende können es gerne einmal ausprobieren.