Vorheriger ArtikelBringen Sie Ihnen bei, wie Sie Strategien Schritt für Schritt schreiben - transplantieren Sie eine meine SprachstrategieIn diesem Artikel haben wir einen Transplantationstest für eine einfache Mai-Sprachstrategie durchgeführt. Wenn es sich um eine etwas komplexere Mai-Sprachstrategie handelt, wie kann man sie in die JavaScript-Sprache transplantieren? Welche Techniken gibt es dafür?
Schauen wir uns zunächst die Strategie an, die dieses Mal umgesetzt werden soll:
(*backtest
start: 2019-05-01 00:00:00
end: 2019-11-12 00:00:00
period: 1d
exchanges: [{"eid":"Futures_OKCoin","currency":"BTC_USD"}]
args: [["SlideTick",10,126961],["ContractType","quarter",126961]]
*)
N1:=10;
N2:=21;
AP:=(HIGH+LOW+CLOSE)/3;
ESA:=EMA(AP,N1);
D:=EMA(ABS(AP-ESA),N1);
CI:=(AP-ESA)/(0.015*D);
TCI:=EMA(CI,N2);
WT1:TCI;
WT2:SMA(WT1,4,1);
AA:=CROSS(WT1,WT2);
BB:=CROSSDOWN(WT1,WT2);
REF(AA,1),BPK;
REF(BB,1),SPK;
Der Beginn dieser Sprachstrategie(*backtest...*)
Dies ist der Konfigurationscode der Backtest-Einstellung. Um den Vergleich zu erleichtern, wird eine einheitliche Backtest-Konfiguration festgelegt. Auch bei dieser Strategie handelt es sich um eine zufällig gefundene Strategie. Sie ist nicht zu kompliziert (im Vergleich zu der im vorherigen Artikel) und stellt eine repräsentativere Strategie dar. Um eine Mai-Sprachstrategie zu übertragen, müssen Sie zuerst den Strategieinhalt lesen. Der Mai-Sprachstrategiecode ist relativ prägnant, und im Grunde können Sie ein gewisses Verständnis der Gesamtstrategie erlangen. Diese Strategie verwendet mehrere Indikatorfunktionen.EMA
,SMA
:
EMA
Diese Indikatorfunktion verfügt über eine vorgefertigte Indikatorbibliotheksfunktion beim Schreiben von Strategien in der JavaScript-Sprache auf der FMZ-Plattform. Im Augenblick:TA.MA
SMA
Was wir tun müssen, istSMA
Wir haben festgestellt, dass die SMA-Indikatorfunktion in der TA-Bibliothek von FMZ nicht unterstützt wird. Es gibt auch Unterschiede zwischen dem SMA-Indikator in der Talib-Bibliothek und dem in der Mai-Sprache:
Wie man sieht, gibt es im Parameterteil neben dem Periodenparameter auch einen Gewichtsparameter.
Die Beschreibung der SMA-Indikatorfunktion in der Talib-Bibliothek in der FMZ-API-Dokumentation lautet:
sichtbartalib.SMA
Ist ein einfacher gleitender Durchschnittsindikator.
Auf diese Weise können Sie nur eine selbst implementierenSMA
Als Entwickler, der Strategien in der Sprache Javascript schreibt, ist dies ebenfalls eine der erforderlichen Fähigkeiten. Wenn es keine vorgefertigten Räder gibt, muss das Auto schließlich noch gefahren werden, also bauen Sie einfach eines.
Ehrlich gesagt gibt es nicht viel Forschung zu Indikatoren und dergleichen. Wenn ich etwas nicht verstehe, suche ich im Allgemeinen einfach nach Informationen. Für SMA haben wir Folgendes herausgefunden:
Ich denke, dass der hier beschriebene Algorithmus ziemlich zuverlässig ist. Lassen Sie uns ihn implementieren:
function SMA (arr, n, m) {
var sma = []
var currSMA = null
for (var i = 0; i < arr.length; i++) {
if (arr[i] && !isNaN(arr[i])) {
if (!currSMA) {
currSMA = arr[i]
sma.push(currSMA)
continue
}
// [M*C2+(N-M)*S1]/N
currSMA = (m * arr[i] + (n - m) * currSMA) / n
sma.push(currSMA)
} else {
sma.push(NaN)
}
}
return sma
}
Verwendung des RichtlinienrahmensBringen Sie Ihnen bei, wie Sie Strategien Schritt für Schritt schreiben - transplantieren Sie eine meine SprachstrategieDerselbe Rahmen füllt im Artikel hauptsächlich zwei Teile:
Führen Sie zunächst die Marktdatenverarbeitung und die Indikatorenberechnung durch.
Wir werden uns der Reihe nach mit den Funktionen der Mai-Sprache befassen:
AP:=(HIGH+LOW+CLOSE)/3;
Dieser Satz kann so verstanden werden, dass der höchste Preis, der niedrigste Preis und der Schlusskurs jedes BAR in den K-Liniendaten addiert und durch 3 dividiert werden, der Durchschnitt berechnet und dann als Array gespeichert wird, das jedem BAR entspricht. eins. Dies kann folgendermaßen gehandhabt werden:
function CalcAP (r) { // AP:=(HIGH+LOW+CLOSE)/3;
var arrAP = [] // 声明一个空数组
for (var i = 0; i < r.length; i++) { // r为传入的K线数据,是一个数组,用for遍历这个数组
v = (r[i].High + r[i].Low + r[i].Close) / 3 // 计算 平均值
arrAP.push(v) // 添加在 arrAP数组的尾部,arrAP是空的时候尾部就是第一个。
}
return arrAP // 返回 这个平均值数组,即麦语言中计算的 AP
}
Rufen Sie diese Funktion einfach in der OnTick-Funktion der Hauptschleife auf, zum Beispiel:
// 计算指标
// AP
var ap = CalcAP(records)
ESA:=EMA(AP,N1);
:Hier müssen wir die im vorherigen Schritt berechneten AP-Daten verwenden, um ESA zu berechnen. Tatsächlich ist dieser ESA der „exponentielle gleitende Durchschnitt“ von AP, also der EMA-Indikator, also verwenden wir AP als Daten und N1 als Parameter des EMA-Indikators zur Berechnung des EMA-Indikators. .
function CalcESA (ap, n1) { // ESA:=EMA(AP,N1);
if (ap.length <= n1) { // 如果AP的长度小于指标参数,是无法计算出有效数据的,这个时候让函数返回false。
return false
}
return TA.EMA(ap, n1)
}
D:=EMA(ABS(AP-ESA),N1);
Verwenden Sie die berechnetenAP
、ESA
Daten berechnenD
。
Sie können sich hier die Codekommentare ansehen, um einige Tipps zur Indikatorberechnung zu erhalten.
function CalcD (ap, esa, n1) { // D:=EMA(ABS(AP-ESA),N1);
var arrABS_APminusESA = []
if (ap.length != esa.length) {
throw "ap.length != esa.length"
}
for (var i = 0; i < ap.length; i++) {
// 计算指标数值时,必须判断一下数据的有效性,因为前几次EMA计算可能数组中的开始部分的数据是NaN,或者null
// 所以必须判断,参与计算的数据都是有效数值才能进行,如果有任何无效数值,就用NaN向arrABS_APminusESA填充
// 这样计算得到的数据,每个位置和之前的数据都是一一对应的,不会错位。
if (ap[i] && esa[i] && !isNaN(ap[i]) && !isNaN(esa[i])) {
v = Math.abs(ap[i] - esa[i]) // 根据ABS(AP-ESA) , 具体计算数值,然后放入arrABS_APminusESA数组
arrABS_APminusESA.push(v)
} else {
arrABS_APminusESA.push(NaN)
}
}
if (arrABS_APminusESA.length <= n1) {
return false
}
return TA.EMA(arrABS_APminusESA, n1) // 计算数组arrABS_APminusESA的EMA指标,得到数据D(数组结构)
}
CI:=(AP-ESA)/(0.015*D);
Diese Berechnungsmethode ähnelt Schritt 1 und der Code wird direkt freigegeben. function CalcCI (ap, esa, d) { // CI:=(AP-ESA)/(0.015*D);
var arrCI = []
if (ap.length != esa.length || ap.length != d.length) {
throw "ap.length != esa.length || ap.length != d.length"
}
for (var i = 0; i < ap.length; i++) {
if (ap[i] && esa[i] && d[i] && !isNaN(ap[i]) && !isNaN(esa[i]) && !isNaN(d[i])) {
v = (ap[i] - esa[i]) / (0.015 * d[i])
arrCI.push(v)
} else {
arrCI.push(NaN)
}
}
if (arrCI.length == 0) {
return false
}
return arrCI
}
function CalcTCI (ci, n2) { // TCI:=EMA(CI,N2);
if (ci.length <= n2) {
return false
}
return TA.EMA(ci, n2)
}
Dieser letzte Schritt verwendet das Rad, das wir zuvor gebaut haben.SMA
Funktion.
function CalcWT2 (wt1) { // WT2:SMA(WT1,4,1);
if (wt1.length <= 4) {
return false
}
return SMA(wt1, 4, 1) // 使用我们自己实现的SMA函数计算出wt1的SMA指标。
}
Die Übertragung von Handelssignalen ist denkbar einfach.
AA:=CROSS(WT1,WT2);
BB:=CROSSDOWN(WT1,WT2);
REF(AA,1),BPK;
REF(BB,1),SPK;
Wenn wir diese Sätze des Mai-Sprachcodes lesen, können wir erkennen, dass das goldene Kreuz und das tote Kreuz der beiden Indikatorlinien WT1 und WT2 als Bedingungen für das Öffnen einer Position verwendet werden. Es ist zu beachten, dass das vorherige Kreuzsignal verwendet wird.
Führen Sie einen direkten Backtest der Strategie mit der Mikrofonsprache durch und beobachten Sie:
Durch die tatsächliche Anwendung der Mai-Sprachstrategie kann man erkennen, dass beim Erkennen eines Signals am Eröffnungspunkt tatsächlich erkannt wird, ob die Position 2 BARs vor dem Eröffnungspunkt ein goldenes Kreuz ist. Dies ist aus der obigen Abbildung deutlich ersichtlich:
Der Füllcode des Signalerkennungsteils kann wie folgt geschrieben werden:
if ((_State == IDLE || _State == SHORT) && wt1[wt1.length - 4] < wt2[wt2.length - 4] && wt1[wt1.length - 3] > wt2[wt2.length - 3]) {
if (_State == IDLE) {
_State = OPENLONG
Log("OPENLONG") // 测试
}
if (_State == SHORT) {
_State = COVERSHORT
Log("COVERSHORT") // 测试
}
isOK = false
}
if ((_State == IDLE || _State == LONG) && wt1[wt1.length - 4] > wt2[wt2.length - 4] && wt1[wt1.length - 3] < wt2[wt2.length - 3]) {
if (_State == IDLE) {
_State = OPENSHORT
Log("OPENSHORT") // 测试
}
if (_State == LONG) {
_State = COVERLONG
Log("COVERLONG") // 测试
}
isOK = false
}
Hier können wir darüber nachdenken, warum die SPK- und BPK-Anweisungen der Mai-Sprache mit dem obigen Code implementiert werden können.
Backtest-Konfiguration:
Backtest der Mai-Sprachversion:
Backtest der JavaScript-Version:
Der Code am Anfang der OnTick-Funktion wird verwendet, um das Backtesting zu beschleunigen und die Strategie basierend auf dem Schlusskursmodell auszuführen. Bei Interesse können Sie ihn im Detail analysieren.
function OnTick(){
// 驱动策略的行情处理部分
var records = _C(exchange.GetRecords)
if (records[records.length - 1].Time == preTime) {
if (isOK) {
Sleep(500)
return
}
} else {
preTime = records[records.length - 1].Time
}
...
..
.
Vollständiger Code der Lehrstrategie: https://www.fmz.com/strategy/174457