Dans l'article précédent, nous avons expliqué l'analyse de la logique de transaction d'une simple stratégie de grille, et dans cet article, nous allons poursuivre la conception de cette stratégie pédagogique.
Analyse de la logique des transactions Dans l'article précédent, nous avons dit que le simple fait de parcourir chaque ligne de la grille et de juger le prix actuel en passant par la ligne de la grille peut déclencher une action de transaction. Mais en réalité, il y a encore beaucoup de détails logiques.
Tout d'abord, le premier détail que nous allons considérer est la conception de cette grille infinie.createNet
Alors? Cette fonction génère une structure de données de grille avec un nombre de lignes de grille fini. Et si le prix dépasse les limites de cette structure de données de grille (au-dessus de la grille la plus élevée et la plus basse)?
Nous avons donc d'abord ajouté un mécanisme d'extension à la structure de données de la grille.
Commencez à écrire la fonction principale de la politique, la fonction principale est le code que la politique commence à exécuter.
var diff = 50 // 全局变量,网格间距,可以设计成参数,方便讲解,我们把这个参数写死在代码里。
function main() {
// 实盘开始运行后,从这里开始执行策略代码
var ticker = _C(exchange.GetTicker) // 获取市场最新的行情数据ticker,ticker这个数据的结构参看FMZ API文档:https://www.fmz.com/api#ticker
var net = createNet(ticker.Last, diff) // 我们上篇设计的初始构造网格数据结构的函数,这里构造一个网格数据结构net
while (true) { // 然后程序逻辑就进入了这个while死循环,策略执行到此将不停的循环执行这里{}符号之内的代码
ticker = _C(exchange.GetTicker) // 死循环代码部分的第一行,获取最新的行情数据,更新给ticker变量
// 检查网格范围
while (ticker.Last >= net[net.length - 1].price) {
net.push({
buy : false,
sell : false,
price : net[net.length - 1].price + diff,
})
}
while (ticker.Last <= net[0].price) {
var price = net[0].price - diff
if (price <= 0) {
break
}
net.unshift({
buy : false,
sell : false,
price : price,
})
}
// 还有其它代码...
}
}
Pour que la structure des données de la grille puisse être étendue, voici le code (sélectionné dans le code ci-dessus):
// 检查网格范围
while (ticker.Last >= net[net.length - 1].price) { // 如果价格超过网格最高价格的网格线
net.push({ // 就在网格最高价格的网格线之后加入一个新的网格线
buy : false, // 初始化卖出标记
sell : false, // 初始化买入标记
price : net[net.length - 1].price + diff, // 在之前最高价格的基础上再加一个网格间距
})
}
while (ticker.Last <= net[0].price) { // 如果价格低于网格最低价格的网格线
var price = net[0].price - diff // 区别于向上添加,要注意向下添加新网格线的价格不能小于等于0,所以这里要判断
if (price <= 0) { // 小于等于0就不添加了,跳出这层循环
break
}
net.unshift({ // 就在网格最低价格的网格线之前添加一个新的网格线
buy : false,
sell : false,
price : price,
})
}
Le prochain point à considérer est la manière de concrétiser le déclenchement des transactions.
var diff = 50
var amount = 0.002 // 增加一个全局变量,也可以设计成参数,当然为了简便讲解,我们也写死在策略代码,
// 这个参数控制每次网格线上触发交易时的交易量
function main() {
var ticker = _C(exchange.GetTicker)
var net = createNet(ticker.Last, diff)
var preTicker = ticker // 在主循环(死循环)开始前,设置一个变量,记录上一次的行情数据
while (true) {
ticker = _C(exchange.GetTicker)
// 检查网格范围
while (ticker.Last >= net[net.length - 1].price) {
net.push({
buy : false,
sell : false,
price : net[net.length - 1].price + diff,
})
}
while (ticker.Last <= net[0].price) {
var price = net[0].price - diff
if (price <= 0) {
break
}
net.unshift({
buy : false,
sell : false,
price : price,
})
}
// 检索网格
for (var i = 0 ; i < net.length ; i++) { // 遍历网格数据结构中的所有网格线
var p = net[i]
if (preTicker.Last < p.price && ticker.Last > p.price) { // 上穿,卖出,当前节点已经交易过不论SELL BUY ,都不再交易
if (i != 0) {
var downP = net[i - 1]
if (downP.buy) {
exchange.Sell(-1, amount, ticker)
downP.buy = false
p.sell = false
continue
}
}
if (!p.sell && !p.buy) {
exchange.Sell(-1, amount, ticker)
p.sell = true
}
} else if (preTicker.Last > p.price && ticker.Last < p.price) { // 下穿,买入
if (i != net.length - 1) {
var upP = net[i + 1]
if (upP.sell) {
exchange.Buy(-1, amount * ticker.Last, ticker)
upP.sell = false
p.buy = false
continue
}
}
if (!p.buy && !p.sell) {
exchange.Buy(-1, amount * ticker.Last, ticker)
p.buy = true
}
}
}
preTicker = ticker // 把当前的行情数据记录在preTicker中,在下一次循环中,作为“上一次”行情数据和最新的对比,判断上穿下穿
Sleep(500)
}
}
Vous pouvez voir:
preTicker.Last < p.price && ticker.Last > p.price
preTicker.Last > p.price && ticker.Last < p.price
Il y a des gens qui ne sont pas d'accord avec moi.
La première étape pour déterminer si une transaction peut être passée est de passer par le haut et par le bas, ce qui implique de déterminer les marques dans les données de la grille.
Si c'est le cas, le prix est jugé inférieur à la grille actuelle et la dernière grille est marquée par le buy. Si la valeur de la marque buy est vraie, cela indique que la dernière grille a été achetée, la dernière est marquée par le buy et la dernière par le sell.
Après avoir jugé les conditions que nous venons d'entrer, si aucun déclenchement n'est effectué, nous continuons à juger. Si les marques buy/sell sur la grille actuelle sont toutes fausses, cela signifie que la grille actuelle peut être échangée.
La logique de traitement est la même (laissez aux débutants réfléchir).
Pour voir les données lors de la réévaluation, écrivez une fonction.showTbl
Affichage des données.
function showTbl(arr) {
var tbl = {
type : "table",
title : "网格",
cols : ["网格信息"],
rows : []
}
var arrReverse = arr.slice(0).reverse()
_.each(arrReverse, function(ele) {
var color = ""
if (ele.buy) {
color = "#FF0000"
} else if (ele.sell) {
color = "#00FF00"
}
tbl.rows.push([JSON.stringify(ele) + color])
})
LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`", "\n 账户信息:", exchange.GetAccount())
}
Le code complet de la stratégie:
/*backtest
start: 2021-04-01 22:00:00
end: 2021-05-22 00:00:00
period: 1d
basePeriod: 1m
exchanges: [{"eid":"OKEX","currency":"ETH_USDT","balance":100000}]
*/
var diff = 50
var amount = 0.002
function createNet(begin, diff) {
var oneSideNums = 10
var up = []
var down = []
for (var i = 0 ; i < oneSideNums ; i++) {
var upObj = {
buy : false,
sell : false,
price : begin + diff / 2 + i * diff,
}
up.push(upObj)
var j = (oneSideNums - 1) - i
var downObj = {
buy : false,
sell : false,
price : begin - diff / 2 - j * diff,
}
if (downObj.price <= 0) { // 价格不能小于等于0
continue
}
down.push(downObj)
}
return down.concat(up)
}
function showTbl(arr) {
var tbl = {
type : "table",
title : "网格",
cols : ["网格信息"],
rows : []
}
var arrReverse = arr.slice(0).reverse()
_.each(arrReverse, function(ele) {
var color = ""
if (ele.buy) {
color = "#FF0000"
} else if (ele.sell) {
color = "#00FF00"
}
tbl.rows.push([JSON.stringify(ele) + color])
})
LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`", "\n 账户信息:", exchange.GetAccount())
}
function main() {
var ticker = _C(exchange.GetTicker)
var net = createNet(ticker.Last, diff)
var preTicker = ticker
while (true) {
ticker = _C(exchange.GetTicker)
// 检查网格范围
while (ticker.Last >= net[net.length - 1].price) {
net.push({
buy : false,
sell : false,
price : net[net.length - 1].price + diff,
})
}
while (ticker.Last <= net[0].price) {
var price = net[0].price - diff
if (price <= 0) {
break
}
net.unshift({
buy : false,
sell : false,
price : price,
})
}
// 检索网格
for (var i = 0 ; i < net.length ; i++) {
var p = net[i]
if (preTicker.Last < p.price && ticker.Last > p.price) { // 上穿,卖出,当前节点已经交易过不论SELL BUY ,都不再交易
if (i != 0) {
var downP = net[i - 1]
if (downP.buy) {
exchange.Sell(-1, amount, ticker)
downP.buy = false
p.sell = false
continue
}
}
if (!p.sell && !p.buy) {
exchange.Sell(-1, amount, ticker)
p.sell = true
}
} else if (preTicker.Last > p.price && ticker.Last < p.price) { // 下穿,买入
if (i != net.length - 1) {
var upP = net[i + 1]
if (upP.sell) {
exchange.Buy(-1, amount * ticker.Last, ticker)
upP.sell = false
p.buy = false
continue
}
}
if (!p.buy && !p.sell) {
exchange.Buy(-1, amount * ticker.Last, ticker)
p.buy = true
}
}
}
showTbl(net)
preTicker = ticker
Sleep(500)
}
}
La stratégie est à revoir:
On peut voir les caractéristiques de la stratégie de la grille, il y aura des pertes plus importantes lorsque vous rencontrez un marché en tendance, et les bénéfices se redresseront lorsque le secteur bouleverse. Ainsi, la stratégie de la grille n'est pas sans risque, la stratégie de l'offre peut rester médian et rigide, tandis que la stratégie de la grille des contrats à terme est plus risquée et nécessite des paramètres de grille plus conservateurs.
- Je ne sais pas.C'est le langage C++.
Je vous en prie.Je pense qu'il y a une faille de logique ici, ne devrait-il pas être juste de traverser la grille lorsque vous la portez et la vendez au-dessus du prix actuel? Il y a aussi exchange.Sell ((-1, quantité, ticker) comment cette fonction est-elle différente de celle de la documentation API, j'ai vu que la documentation API dit exchange.Sell ((Price, Amount), pourquoi avez-vous trois paramètres, je ne comprends pas, c'est très compliqué, je suis aussi fou
Je vous en prie.C'est pas facile.
leL'échange.Buy ((-1, quantité * ticker.Last, ticker), quantité * ticker.Last est une ironie, pourquoi ne pas vendre?
CYZWXLe projet de règlement (CE) n° 1235/2008 est soumis à la procédure de réexamen prévue à l'article 10 du règlement (CE) no 1225/2009. dernière balise = [] ligne = [] Liste de réservations définition nette ((maintenant_prix): ligne globale Imprimer (à présent) ligne = [prix actuel*(1+0.003*i) pour i dans la plage ((-1000,1000) ] Ligne de bord - Je ne sais pas. Définition de la balise: dernière balise globale ligne globale Liste globale de réseaux compte = échange.GetAccount (() Je suis un peu dégoûté. La valeur de la valeur de l'indicateur est la valeur de l'indicateur. si len ((last_tick) == 1: retour Il est temps d'en finir. pour i dans la plage (ligne): si last_tick[-1] > ligne[i] et last_tick[-2] < ligne[i] et len(grid_buy_list)!= 0 et i > min(grid_buy_list) et compte['Stocks'] >= 0,001: Les échanges sont effectués en ligne.Vente ((last_tick[-1],0.01) Le nombre total de personnes concernées par le programme est fixé par la Commission. Je ne peux pas vous aider. elif last_tick[-1] < ligne[i] et last_tick[-2] > ligne[i] et i ne figurant pas dans la liste de vente: Il y a une différence de prix entre les deux. Réseau_achat_liste.append (i) Je ne peux pas vous aider. Définition principale: Je ne sais pas si je peux vous aider. Je ne peux pas vous aider. alors que (true): Ontick (() Le sommeil ((1000)
CYZWXMerci Dreamweaver, pour les détails, j'ai tout expliqué pour acheter à nouveau, comme si j'avais écrit une version py
L'inventeur de la quantification - un petit rêveLa stratégie est le langage JavaScript.
Je vous en prie.Les contrats à durée indéterminée ne sont-ils pas considérés comme des contrats à terme?
L'inventeur de la quantification - un petit rêveLes contrats à terme sont des contrats de devises, et les contrats à terme sont des contrats de devises.
Je vous en prie.Bonjour, je vous pose une autre question, cette énigme signifie quoi. Notez: l'interface de sous-traitance des bourses nécessite une liste de prix du marché (le type de sous-traitance est le paiement, le paramètre de sous-traitance est le montant par unité de devises) ; le mode de sous-traitance du marché des devises numériques, le paramètre de sous-traitance est le nombre de contrats.
Je vous en prie.Je comprends.
L'inventeur de la quantification - un petit rêveLes fonctions d'API de FMZ permettent de générer des sorties de journaux telles que: Log ((...) ; exchange.Buy ((Price, Amount) ; exchange.CancelOrder ((Id)) et d'autres avec des paramètres de sortie supplémentaires après les paramètres nécessaires.