Article précédentLa main qui vous apprend à écrire des stratégies -- transférer une stratégie dans ma langue.Dans le cas d'un langage un peu plus complexe, comment transférer le langage vers JavaScript? Quelles sont les astuces?
Nous allons d'abord examiner les stratégies utilisées pour cette transplantation:
(*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;
La première partie de cette stratégie de langue Maï(*backtest...*)
La stratégie de retouche est un code de configuration pour les paramètres de retouche, pour faciliter la comparaison, de configurer une configuration de retouche unifiée. Cette stratégie est également une stratégie de recherche aléatoire, pas trop compliquée (par rapport à l'article précédent un peu plus complexe), est une stratégie plus représentative.EMA
,SMA
:
EMA
Cette fonction d'indicateur est une fonction de bibliothèque d'indicateurs prête à l'emploi lorsque la plateforme FMZ écrit des stratégies en langage JavaScript.TA.MA
SMA
Nous devons agir.SMA
L'indicateur, que nous avons trouvé dans la bibliothèque TA de FMZ ne supporte pas la fonction SMA, est différent de celui de la bibliothèque talib:On peut voir que la partie des paramètres a un paramètre de pondération en plus du paramètre de cycle.
Dans la documentation de l'API FMZ, la description de la fonction d'indicateur SMA dans la bibliothèque talib est la suivante:
Vous voyez.talib.SMA
La moyenne mobile est un simple indicateur.
Il n'y a qu'une seule façon d'y arriver.SMA
En tant que développeur qui écrit des stratégies en JavaScript, c'est aussi une des compétences indispensables, après tout, si vous n'avez pas de roues prêtes à l'emploi, la voiture va continuer à rouler.
Pour être honnête, il n'y a pas beaucoup de recherches sur des indicateurs comme celui-ci, et les gens ne comprennent généralement pas.
Je pense que l'algorithme est assez fiable, mais il faut le mettre en œuvre:
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égiqueLa main qui vous apprend à écrire des stratégies -- transférer une stratégie dans ma langue.L'article contient le même cadre, rempli principalement de deux parties:
Tout d'abord, le traitement des données du marché, le calcul des indicateurs.
Nous traitons cette partie de la langue Maï une phrase après l'autre:
1、AP:=(HIGH+LOW+CLOSE)/3;
Cette phrase peut être comprise comme la somme des prix les plus élevés, les prix les plus bas et les prix de clôture de chaque BAR dans les données de la ligne K, puis la division par 3, calculer la moyenne, puis stocker un ensemble correspondant à chaque BAR. Il y a une autre façon de procéder:
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
}
On peut appeler cette fonction dans la fonction OnTick de la boucle principale, par exemple:
// 计算指标
// AP
var ap = CalcAP(records)
2° Une fois le calcul AP terminé, le calcul est effectué.ESA:=EMA(AP,N1);
:
On utilise les données AP de l'étape précédente pour calculer l'ESA, qui est en fait l'ESA de l'AP, c'est-à-dire l'EMA, donc on peut calculer l'EMA en utilisant AP comme données et N1 comme paramètres de l'EMA.
function CalcESA (ap, n1) { // ESA:=EMA(AP,N1);
if (ap.length <= n1) { // 如果AP的长度小于指标参数,是无法计算出有效数据的,这个时候让函数返回false。
return false
}
return TA.EMA(ap, n1)
}
3、D:=EMA(ABS(AP-ESA),N1);
calculé avecAP
、ESA
Données de calculD
Je ne sais pas.
Vous pouvez consulter les annotations de code ici, et quelques astuces pour calculer les 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(数组结构)
}
4、CI:=(AP-ESA)/(0.015*D);
Cette méthode de calcul est similaire à celle de l'étape 1 et permet de déposer directement le code.
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
}
TCI: = EMA ((CI, N2)); Il suffit de calculer l'EMA de l'arithmétique CI.
function CalcTCI (ci, n2) { // TCI:=EMA(CI,N2);
if (ci.length <= n2) {
return false
}
return TA.EMA(ci, n2)
}
WT2:SMA ((WT1,4,1);
Cette dernière étape, nous avons fait avec des roues que nous avions déjà construites.SMA
Les fonctions.
function CalcWT2 (wt1) { // WT2:SMA(WT1,4,1);
if (wt1.length <= 4) {
return false
}
return SMA(wt1, 4, 1) // 使用我们自己实现的SMA函数计算出wt1的SMA指标。
}
Le transfert des signaux est très simple.
AA:=CROSS(WT1,WT2);
BB:=CROSSDOWN(WT1,WT2);
REF(AA,1),BPK;
REF(BB,1),SPK;
En lisant ces quelques phrases de code de la langue Ma, vous pouvez voir que la fourche dorée, la fourche morte, est la condition d'ouverture de la ligne WT1 et WT2. En utilisant directement les stratégies de la langue, nous observons:
L'observation de l'exécution réelle de la stratégie de Mac est que lorsque le signal est détecté au point d'ouverture, il est en fait détecté si la position du point d'ouverture BAR est une fourche dorée; le diagramme ci-dessus montre clairement:
Le code de remplissage de la partie de détection du signal peut être écrit comme suit:
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
}
On peut donc se demander pourquoi les instructions SPK et BPK dans la langue Maï peuvent être mises en œuvre avec le code ci-dessus.
Les paramètres de dépistage:
La version en langue Ma traduit:
Les versions de JavaScript sont vérifiées:
Le code de la première partie de la fonction OnTick, qui est utilisé pour accélérer un peu la récupération, permet de faire fonctionner la stratégie avec un modèle de prix de clôture, ce qui peut être analysé 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
}
...
..
.
Le code complet de la stratégie pédagogique:https://www.fmz.com/strategy/174457