Article précédentJe vous apprends à écrire des stratégies étape par étape - transplantez ma stratégie linguistiqueDans cet article, nous avons réalisé un test de transplantation sur une stratégie de langage Mai simple. S’il s’agit d’une stratégie de langage Mai légèrement plus complexe, comment la transplanter dans le langage JavaScript ? Quelles sont les techniques pour cela ?
Voyons d’abord la stratégie à adopter cette fois-ci :
(*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;
Le début de cette stratégie linguistique(*backtest...*)
Il s’agit du code de configuration du paramètre de backtest. Afin de faciliter la comparaison, une configuration de backtest unifiée est définie. Cette stratégie est également une stratégie trouvée au hasard, et elle n’est pas trop compliquée (par rapport à celle de l’article précédent), et c’est une stratégie plus représentative. Pour transplanter une stratégie en langue Mai, vous devez d’abord lire le contenu de la stratégie. Le code de la stratégie en langue Mai est relativement concis et vous permet d’avoir une certaine compréhension de la stratégie globale. Cette stratégie utilise plusieurs fonctions indicatrices.EMA
,SMA
:
EMA
Cette fonction d’indicateur dispose d’une fonction de bibliothèque d’indicateurs prête à l’emploi lors de l’écriture de stratégies en langage JavaScript sur la plate-forme FMZ. Tout de suite:TA.MA
SMA
Ce que nous devons faire, c’estSMA
Nous avons constaté que la fonction d’indicateur SMA n’est pas prise en charge dans la bibliothèque TA de FMZ. Il existe également des différences entre l’indicateur SMA de la bibliothèque talib et celui du langage Mai :
Comme vous pouvez le voir, en plus du paramètre de période, il existe également un paramètre de poids dans la partie paramètre.
La description de la fonction d’indicateur SMA dans la bibliothèque talib dans la documentation de l’API FMZ est :
visibletalib.SMA
Il s’agit d’un indicateur de moyenne mobile simple.
De cette façon, vous ne pouvez en mettre en œuvre qu’un seul par vous-mêmeSMA
En tant que développeur qui écrit des stratégies en utilisant le langage Javascript, c’est également l’une des compétences nécessaires. Après tout, s’il n’y a pas de roues toutes faites, la voiture doit quand même être conduite, alors construisez-en une.
Pour être honnête, il n’existe pas beaucoup de recherches sur les indicateurs et autres. En général, si je ne comprends pas quelque chose, je me contente de chercher des informations. Pour SMA, nous avons constaté ce qui suit :
Je pense que le processus algorithmique décrit ici est assez fiable. Implémentons-le :
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
}
Utilisation du cadre stratégiqueJe vous apprends à écrire des stratégies étape par étape - transplantez ma stratégie linguistiqueLe même cadre dans l’article remplit principalement deux parties :
Tout d’abord, effectuez le traitement des données de marché et le calcul des indicateurs.
Nous allons aborder les fonctions de la langue Mai une par une :
AP:=(HIGH+LOW+CLOSE)/3;
Cette phrase peut être comprise comme l’addition du prix le plus élevé, du prix le plus bas et du prix de clôture de chaque BAR dans les données K-line et en le divisant par 3, en calculant la moyenne, puis en le stockant sous forme de tableau, correspondant à chaque BAR une par une. un. Cela peut être géré comme ceci :
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
}
Appelez simplement cette fonction dans la boucle principale OnTick, par exemple :
// 计算指标
// AP
var ap = CalcAP(records)
ESA:=EMA(AP,N1);
:Ici, nous devons utiliser les données AP calculées à l’étape précédente pour calculer l’ESA. En fait, cet ESA est la « moyenne mobile exponentielle » de l’AP, c’est-à-dire l’indicateur EMA, nous utilisons donc AP comme données et N1 comme paramètre de l’indicateur EMA pour calculer l’indicateur EMA. .
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);
Utilisez le calculAP
、ESA
Calculer les donnéesD
。
Vous pouvez consulter les commentaires de code ici pour quelques conseils sur les calculs d’indicateurs.
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);
Cette méthode de calcul est similaire à l’étape 1 et le code est publié directement. 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)
}
Cette dernière étape utilise la roue que nous avons construite plus tôt.SMA
fonction.
function CalcWT2 (wt1) { // WT2:SMA(WT1,4,1);
if (wt1.length <= 4) {
return false
}
return SMA(wt1, 4, 1) // 使用我们自己实现的SMA函数计算出wt1的SMA指标。
}
La transplantation de signaux de trading est très simple.
AA:=CROSS(WT1,WT2);
BB:=CROSSDOWN(WT1,WT2);
REF(AA,1),BPK;
REF(BB,1),SPK;
En lisant ces phrases du code de la langue Mai, nous pouvons savoir que le jugement de croix d’or et de croix morte des deux lignes indicatrices WT1 et WT2 sont utilisés comme conditions d’ouverture d’une position. Il convient de noter que le signal de croix précédent est utilisé.
On backteste directement la stratégie avec le langage microphone, et on observe :
Grâce au fonctionnement réel de la stratégie linguistique Mai, on peut voir que lorsqu’un signal est détecté au point d’ouverture, il détecte en fait si la position 2 BARS avant le point d’ouverture est une croix dorée. Cela ressort clairement de la figure ci-dessus :
Le code de remplissage de la partie détection de signal peut être écrit comme :
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
}
Ici, nous pouvons réfléchir aux raisons pour lesquelles les instructions SPK et BPK du langage Mai peuvent être implémentées avec le code ci-dessus.
Configuration du backtest :
Backtest de la version en langue Mai :
Backtest de la version JavaScript :
Le code au début de la fonction OnTick est utilisé pour accélérer le processus de backtesting et pour exécuter la stratégie en fonction du modèle de cours de clôture. Si vous êtes intéressé, vous pouvez l’analyser en détail.
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
}
...
..
.
Code complet de la stratégie d’enseignement : https://www.fmz.com/strategy/174457