Récemment, les stratégies de type Martin ont été beaucoup discutées dans le groupe officiel de FMZ, et il n'y a pas beaucoup de stratégies de type Martin sur les contrats de devises numériques sur la plate-forme. J'ai donc profité de l'occasion pour concevoir une stratégie de type Martin simple pour les contrats de devises numériques.
Cet article est principalement consacré à l'apprentissage de la conception de stratégies de type Martin, dont l'idée stratégique est déjà claire, et nous considérons davantage la conception stratégique en tant qu'utilisateurs de FMZ.
La stratégie des contrats à terme sur les crypto-monnaies est souvent basée sur des données d'intérêt global. Cette donnée est souvent utilisée pour calculer les gains, en particulier les gains flottants.exchange.GetAccount()
Les actifs disponibles et les actifs bloqués sont obtenus. En fait, la plupart des échanges de futures de crypto-monnaie fournissent des données sur l'intérêt global, mais FMZ n'enveloppe pas uniformément cette propriété.
Nous avons donc créé des fonctions différentes pour chaque échange, pour obtenir ces données:
// OKEX V5 获取总权益
function getTotalEquity_OKEX_V5() {
var totalEquity = null
var ret = exchange.IO("api", "GET", "/api/v5/account/balance", "ccy=USDT")
if (ret) {
try {
totalEquity = parseFloat(ret.data[0].details[0].eq)
} catch(e) {
Log("获取账户总权益失败!")
return null
}
}
return totalEquity
}
// 币安期货
function getTotalEquity_Binance() {
var totalEquity = null
var ret = exchange.GetAccount()
if (ret) {
try {
totalEquity = parseFloat(ret.Info.totalWalletBalance)
} catch(e) {
Log("获取账户总权益失败!")
return null
}
}
return totalEquity
}
Dans le codetotalEquity
C'est ce dont nous avons besoin. Ensuite, nous écrivons une autre fonction comme entrée d'appel pour appeler spécifiquement la fonction correspondante en fonction du nom de l'échange.
function getTotalEquity() {
var exName = exchange.GetName()
if (exName == "Futures_OKCoin") {
return getTotalEquity_OKEX_V5()
} else if (exName == "Futures_Binance") {
return getTotalEquity_Binance()
} else {
throw "不支持该交易所"
}
}
Avant de concevoir les fonctions principales, la logique principale. Nous devons également faire quelques préparatifs pour concevoir des fonctions secondaires.
Supprimez toutes les annonces en cours
function cancelAll() {
while (1) {
var orders = _C(exchange.GetOrders)
if (orders.length == 0) {
break
}
for (var i = 0 ; i < orders.length ; i++) {
exchange.CancelOrder(orders[i].Id, orders[i])
Sleep(500)
}
Sleep(500)
}
}
Cette fonction est probablement familière à ceux qui lisent souvent le code de l'exemple de stratégie sur la place des stratégies FMZ, où de nombreuses stratégies ont été conçues de manière similaire.
Opération de sous-traitance des contrats à terme
function trade(distance, price, amount) {
var tradeFunc = null
if (distance == "buy") {
tradeFunc = exchange.Buy
} else if (distance == "sell") {
tradeFunc = exchange.Sell
} else if (distance == "closebuy") {
tradeFunc = exchange.Sell
} else {
tradeFunc = exchange.Buy
}
exchange.SetDirection(distance)
return tradeFunc(price, amount)
}
function openLong(price, amount) {
return trade("buy", price, amount)
}
function openShort(price, amount) {
return trade("sell", price, amount)
}
function coverLong(price, amount) {
return trade("closebuy", price, amount)
}
function coverShort(price, amount) {
return trade("closesell", price, amount)
}
Il y a quatre directions de négociation des contrats à terme: openLong, openShort, coverLong et coverShort. Nous avons donc conçu quatre fonctions de sous-ordre pour correspondre à ces opérations. Si nous ne considérons que les sous-ordres, il y a quelques facteurs nécessaires: direction, prix des sous-ordres, quantité des sous-ordres.
C'est pourquoi nous avons conçu une autre vidéo intitulée:trade
La fonction doit traiter方向(distance)
、下单价格(price)
、下单量(amount)
Les opérations sont claires et précises.
Les fonctions appelées openLong, openShort, coverLong et coverShort sont finalement utilisées par les utilisateurs.trade
Les fonctions remplissent leur fonction réelle, c'est-à-dire qu'elles commandent sur les marchés à terme en fonction d'une direction, d'un prix ou d'une quantité déterminés.
L'idée stratégique est très simple: pendre des ordres de vente (" faire vide ") ou d'achat (" faire plus ") à une certaine distance en dessous du prix actuel sur la base. Une fois la transaction terminée, tous les ordres restants sont annulés, puis un nouvel ordre de mise à niveau est suspendu à une certaine distance en fonction du prix du stock, un ordre de mise à niveau est suspendu au prix actuel après la mise à jour, mais l'ordre de mise à niveau n'est pas doublé.
Première carrière Comme nous avons besoin de deux variables globales pour enregistrer l'identifiant de commande, nous avons besoin de deux variables globales pour enregistrer l'identifiant de commande.
var buyOrderId = null
var sellOrderId = null
L'option d'utiliser l'analogie OKEX_V5 est ensuite conçue dans les paramètres de l'interface de stratégie, donc quelques traitements doivent être effectués dans le code:
var exName = exchange.GetName()
// 切换OKEX V5模拟盘
if (isSimulate && exName == "Futures_OKCoin") {
exchange.IO("simulate", true)
}
Les paramètres de l'interface ont également conçu l'option de réinitialiser toutes les informations, de sorte que le code a également un traitement correspondant:
if (isReset) {
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("重置所有数据", "#FF0000")
}
Nous n'avons fait que courir un contrat à perpétuité, donc ici écrit mort, mais mis en place comme un contrat à perpétuité.
exchange.SetContractType("swap")
Ensuite, nous devons également prendre en compte les problèmes de précision des prix, de précision de la quantité, si la précision n'est pas correctement configurée, la précision est perdue dans le calcul stratégique, et un grand nombre d'éléments de données peut facilement être rejeté par l'interface de l'échange lors de la commande.
exchange.SetPrecision(pricePrecision, amountPrecision)
Log("设置精度", pricePrecision, amountPrecision)
Des fonctionnalités de récupération de données simples à concevoir
if (totalEq == -1 && !IsVirtual()) {
var recoverTotalEq = _G("totalEq")
if (!recoverTotalEq) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
totalEq = currTotalEq
_G("totalEq", currTotalEq)
} else {
throw "获取初始权益失败"
}
} else {
totalEq = recoverTotalEq
}
}
Si vous souhaitez spécifier le total des droits d'accès au compte initial lors de l'exécution de la politique, vous pouvez définir des paramètres.totalEq
Si ce paramètre est réglé sur -1, la stratégie lit les données de l'intérêt général stockées, si aucune donnée de l'intérêt général n'est stockée, c'est-à-dire la valeur totale initiale de l'avancement de la stratégie en utilisant l'intérêt général en cours de lecture, après quoi l'augmentation de l'intérêt général indique la perte, la diminution de l'intérêt général indique la perte. Si vous lisez les données de l'intérêt général, vous continuez à utiliser ces données.
La logique principale Une fois le travail initial terminé, nous arrivons enfin à la partie de la logique principale de la stratégie, que j'ai écrite directement dans les notes de code pour faciliter l'explication.
while (1) { // 策略主要逻辑设计为一个死循环
var ticker = _C(exchange.GetTicker) // 首先读取当前行情信息,主要用到最新成交价
var pos = _C(exchange.GetPosition) // 读取当前持仓数据
if (pos.length > 1) { // 判断持仓数据,由于这个策略的逻辑,是不太可能同时出现多空持仓的,所以发现同时出现多空持仓就抛出错误
Log(pos)
throw "同时有多空持仓" // 抛出错误,让策略停止
}
// 根据状态而定
if (pos.length == 0) { // 根据持仓状态做出不同操作,pos.length == 0是当没有持仓时
// 未持仓了,统计一次收益
if (!IsVirtual()) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
LogProfit(currTotalEq - totalEq, "当前总权益:", currTotalEq)
}
}
buyOrderId = openLong(ticker.Last - targetProfit, amount) // 挂开多仓的买单
sellOrderId = openShort(ticker.Last + targetProfit, amount) // 挂开空仓的卖单
} else if (pos[0].Type == PD_LONG) { // 有多头持仓,挂单位置、数量有所不同
var n = 1
var price = ticker.Last
buyOrderId = openLong(price - targetProfit * n, amount)
sellOrderId = coverLong(pos[0].Price + targetProfit, pos[0].Amount)
} else if (pos[0].Type == PD_SHORT) { // 有空头持仓,挂单位置、数量有所不同
var n = 1
var price = ticker.Last
buyOrderId = coverShort(pos[0].Price - targetProfit, pos[0].Amount)
sellOrderId = openShort(price + targetProfit * n, amount)
}
if (!sellOrderId || !buyOrderId) { // 如果有一边挂单失败就取消所有挂单,重来
cancelAll()
buyOrderId = null
sellOrderId = null
continue
}
while (1) { // 挂单完成,开始监控订单
var isFindBuyId = false
var isFindSellId = false
var orders = _C(exchange.GetOrders)
for (var i = 0 ; i < orders.length ; i++) {
if (buyOrderId == orders[i].Id) {
isFindBuyId = true
}
if (sellOrderId == orders[i].Id) {
isFindSellId = true
}
}
if (!isFindSellId && !isFindBuyId) { // 检测到买卖单都成交了
cancelAll()
break
} else if (!isFindBuyId) { // 检测到买单成交
Log("买单成交")
cancelAll()
break
} else if (!isFindSellId) { // 检测到卖单成交
Log("卖单成交")
cancelAll()
break
}
LogStatus(_D())
Sleep(3000)
}
Sleep(500)
}
L'ensemble de la logique et de la conception est expliqué.
Le 19 mai dernier, le gouvernement a décidé d'arrêter le projet de loi sur les droits de l'homme.
Comme vous pouvez le voir, les stratégies de type Martin présentent toujours un certain risque.
L'adresse de la stratégie:https://www.fmz.com/strategy/294957
Les stratégies sont principalement utilisées pour apprendre, l'or et l'argent sont utilisés avec prudence ~!
Je vous en prie.Je suis très heureux que vous ayez répondu à ma question. if (!isFindSellId &&!isFindBuyId) { // détecte que toutes les commandes ont été traitées En détectant une commande, si vous passez rapidement une fiche d'achat et de vente en même temps, cela peut-il faire une erreur?
Neo1898La question est de savoir si le modèle de contrat est plein ou partiel, comment est-il configuré?
Neo1898Pourquoi n'y a-t-il pas eu de double contrat, puisque c'est le double qui a été contracté?
Des nuages légersMerci Dreama, j'ai enfin compris de bout en bout. Puis j'ai appris à surveiller les listes, puis j'ai écrit un double Martin. Deux jours, j'ai écrit 580 lignes. Je suis un homme qui a toujours été un homme de bien.
quantité hk/upload/asset/1a9ebf427c4e2cbf1c327.png Il est disponible en anglais, espagnol et espagnol Faux vrai en échange?
Les rêves coûtent huit chiffresSi
Les rêves coûtent huit chiffresLes droits et intérêts des propriétaires
NulIl faut arrêter les dommages?
- Je suis désolé.Martin, on a fait le calcul, c'est 0.
- Je ne sais pas.Et si vous ne comprenez pas ce que c'est, alors n est toujours égal à 1.
Je vous en prie.Est-ce que la stratégie est multi-espace ou double-ouverte?
L'inventeur de la quantification - un petit rêveIl n'y a pas d'erreur. Il annule toujours tous les appels d'offres, saute du cycle actuel, et continue la logique.
L'inventeur de la quantification - un petit rêveEn général, on utilise le magasin entier.
L'inventeur de la quantification - un petit rêveL'effet de levier peut être spécifiquement placé sur l'échange en fonction de ses préférences en matière de risque.
L'inventeur de la quantification - un petit rêveIl y a 666 nuages!
L'inventeur de la quantification - un petit rêveCette variable s'appelle isFindBuyId, ce n'est pas bien. Elle devrait être isNotFindBuyId.
L'inventeur de la quantification - un petit rêveCette stratégie n'est pas conçue pour arrêter les pertes.
L'inventeur de la quantification - un petit rêveJe suis très heureux de voir que vous avez réussi à trouver un emploi. L'article est principalement une stratégie pédagogique et ne demande pas beaucoup d'attention.
L'inventeur de la quantification - un petit rêveCette N est utilisée pour les modifications ultérieures, par exemple, si l'on pense à n fois la distance d'accumulation, elle peut être temporairement fixée à 1⁄2.
L'inventeur de la quantification - un petit rêveIl est ouvert séparément.