avatar of 发明者量化-小小梦 发明者量化-小小梦
Suivre Messages privés
4
Suivre
1271
Abonnés

Vous emmener dans le monde de la quantification - Analyse du code stop loss coulissant à opération bidirectionnelle MACD

Créé le: 2016-04-22 13:53:14, Mis à jour le: 2023-06-14 10:38:59
comments   6
hits   7443

Vous emmener dans le monde de la quantification - Analyse du code stop loss coulissant à opération bidirectionnelle MACD

Nous avons vu dans un précédent article comment simplifier la stratégie de quantification de 30 lignes de code, mais dans ce dernier article, nous allons faire en sorte que les débutants soient un peu plus proches de découvrir le plaisir de la conception de stratégies de quantification. Encore une fois, il s’agit d’une explication de la transaction en temps réel en BTC, alors que l’auteur a été un expert en finance, investissement, titres, etc. Il n’a même pas compris le processus de transaction des contrats à terme. C’est un peu comme si on était dans un état d’étourdissement, de confusion, de vertiges, d’écoute de mots et d’expressions inédits, et que l’on comprenait un peu ! Un peu !) ∼ par ses propres recherches et par la recherche de renseignements ∼. Après avoir lu le contenu, avoir les idées de base, en combinant avec le langage JS que je connais un peu, j’ai simplement écrit un article. Au début, je ne savais pas ce que c’était que la ligne K, la ligne moyenne, l’indicateur MACD. En termes simples, la ligne K est un indicateur de marché qui enregistre les événements sur une période donnée pour faciliter l’observation de la dynamique du marché. La ligne de référence est l’indicateur utilisé dans l’article précédent et, comme l’indicateur MACD, il reflète la tendance des événements du marché. Le concept, l’algorithme, la déduction des formules de ces deux indicateurs sont énumérés. Pour ceux qui ne comprennent pas, consultez le centimètre.

Le code contient les variables globales suivantes: ancienne règle, interprétation par interprétation, oiseau blanc à ignorer.

Nom de la variable Valeur initiale illustrer
Interval 2000 Cette variable est le cycle de sondage, c’est-à-dire le temps d’attente de la pause du programme, et son unité est la milliseconde. 1000 millisecondes est égale à 1 seconde, donc la valeur initiale de cette variable est de 2 secondes.
STATE_FREE 0 C’est une variable qui représente l’état, qui représente le vide. Elle est utilisée pour le jugement de l’état.
STATE_BUY 1 C’est une variable qui indique le statut d’une personne qui détient plusieurs positions.
STATE_SELL 2 Variable d’état, qui indique que le détenteur d’une position est à vide.
ORDER_INVALID 3 Variable d’état de détention, indiquant que la position n’est pas détenue.
ORDER_VALID 4 Il a déclaré:
state STATE_FREE Variable d’état, initialisée avec un état vide.
SignalDelay 0 Le signal a été retardé et n’a pas fonctionné.
stopProfit 0.002 Cette variable est importante, le stop loss, par exemple le capital * le stop loss ((0,002)) indique que le maximum de perte est de 0,002 fois le capital, le plafond de perte.
step 0.5 La longueur d’étape du stop-loss est utilisée pour augmenter ou diminuer le niveau du stop-loss.
opAmount 1 La quantité d’opérations est fixe.
profit 0 Je ne suis pas d’accord.

Les objets globaux, utilisés pour enregistrer les informations sur les positions, contiennent des méthodes, principalement pour réaliser des arrêts de glissement.

    var holdOrder = {//持仓信息对象
	    orderState: ORDER_INVALID,// 持仓状态
	    price: 0, //持仓均价
	    amount: 0, //持仓量
	    time: null, // 操作时间
	    stopPrice: 0, // 止损价
	    level: 1,   //止损等级
	    updateCurrentProfit: function(lastPrice,amount){//更新当前盈亏
	        if(state === STATE_SELL){//当前 空头持仓
	        	return (lastPrice - this.price) * amount;
	        }
	        if(state === STATE_BUY){//当前 多头持仓
	        	return - (lastPrice - this.price) * amount;
	        }
	    },
	    SetStopPrice: function(ticker,stopState){//更新止损价
	    	if(stopState === STATE_FREE){ //更新止损时状态 为空闲
	    		return this.stopPrice;
	    	}
	    	if(stopState === STATE_BUY){ //更新止损时状态 为多仓
	            if(this.orderState === ORDER_INVALID){
	        	    return this.stopPrice;
	            }
	            if(this.stopPrice === 0){//初始 止损价为0 时 
	            	this.stopPrice = this.price * ( 1 - stopProfit );
	            }
	            if( ticker.Last <= this.price ){ //最后成交价 小于等于  持仓均价时
	                this.stopPrice = this.price * ( 1 - stopProfit );
	                this.level = 1;
	            }else{//其它情况
	        	    if( ticker.Last - this.price > this.level * step ){//超出当前等级   设置滑动止损
	                    this.stopPrice = this.price * (1 - stopProfit) + (ticker.Last - this.price );
	                    //更新止损价为滑动后的止损价
	                    this.level++;//上调止损等级
	        	    }else{//其它
	        	    	this.stopPrice = this.stopPrice;//保持当前止损价不变
	        	    }
	            }
	    	}else if( stopState === STATE_SELL){//空头持仓类似
	    		if(this.orderState === ORDER_INVALID){
	        	    return this.stopPrice;
	            }
	            if(this.stopPrice === 0){
	            	this.stopPrice = this.price * ( 1 + stopProfit );
	            }
	            if( ticker.Last >= this.price ){
	                this.stopPrice = this.price * ( 1 + stopProfit );
	                this.level = 1; 
	            }else{
	        	    if( this.price - ticker.Last > this.level * step ){
	                    this.stopPrice = this.price * (1 + stopProfit) - ( this.price - ticker.Last );
	                    this.level++;
	        	    }else{
	        	    	this.stopPrice = this.stopPrice;
	        	    }
	            }
	    	}
	        return this.stopPrice;//返回止损价
	    },
	    initHoldOrder: function(){//平仓后  用于 初始化持仓信息的  函数
	        this.orderState = ORDER_INVALID;
	        this.price = 0;
	        this.amount = 0;
	        this.time = null;
	        this.stopPrice = 0;
	        this.level = 1;
	    }
	};
    
  • Le code a été téléchargé sur github à l’adresse: CliquezgithubVous êtes invités.

  • Si vous n’avez pas encore rejoint le groupe QQ officiel, veuillez rejoindre: 309368835 Inventors Quantify.


Voici un aperçu rapide de la fonction que nous allons utiliser.

function MACD_Cross(){//检测MACD指标,交叉状态的函数
    var records = exchange.GetRecords();//获取K线数据
    while(!records || records.length < 45){ //K线数据不能为null,要大于45个柱,不符合标准 循环获取直到符合
    	records = exchange.GetRecords();
    	Sleep(Interval);
    }
    var macd = TA.MACD(records,12,26,9);//调用指标函数, 参数为MACD 默认的参数。
    var dif = macd[0];  //dif线
    var dea = macd[1];  //dea线
    var column = macd[2]; // MACD柱
    var len = records.length;  //K线周期长度
    if( (dif[len-1] > 0 && dea[len-1] > 0) && dif[len-1] > dea[len-1] && dif[len-2] < dea[len-2] && column[len-1] > 0.2 ){ 
    //判断金叉条件:dif 与 dea 此刻均大于0 , 且dif由下上穿dea , 且 MACD量柱大于0.2
    	return 1; //返回1  代表 金叉信号。
    }
    if( (dif[len-1] < 0 && dea[len-1] < 0) && dif[len-1] < dea[len-1] && dif[len-2] > dea[len-2] && column[len-1] < -0.2 ){
    //判断死叉条件:
        return 2;//返回2  代表 死叉信号。
    }   
    return 0;  //金叉  、死叉  信号以外,为等待信号 0 。
}
function getTimeByNormal(time){// 获取时间的 函数 把毫秒时间 转换 标准时间
    var timeByNormal = new Date();
    timeByNormal.setTime(time);
    var strTime = timeByNormal.toString();
    var showTimeArr = strTime.split(" ");
    var showTime = showTimeArr[3]+"-"+showTimeArr[1]+"-"+showTimeArr[2]+"-"+showTimeArr[4];
    return showTime;
}

Voici la fonction principale de la stratégie, qui utilise une bibliothèque de modèles de transaction qui contient les détails de la transaction. Les amis intéressés peuvent trouver le code sur le quantificateur de l’inventeur, la version annotée est partagée dans le groupe officiel QQ et sur github.

function main(){
    var initAccount = $.GetAccount(exchange);//首先我们来记录初始时的账户信息,这里调用了模板类库的导出函数
    var nowAccount = initAccount;//再声明一个 变量 表示 现在账户信息
    var diffMoney = 0; //钱 差额
    var diffStocks = 0;//币 差额
    var repair = 0; //计算 盈亏时   用于修正的 量
    var ticker = exchange.GetTicker(); //获取此刻市场行情
    Log("初始账户:",initAccount); //输出显示  初始账户信息。
    while(true){//主函数循环
        scan(); //扫描函数,  稍后讲解,主要是判断  开仓、平仓 以及 操作 开仓 、 平仓。
        ticker = exchange.GetTicker();//在while循环内 获取 市场行情
        if(!ticker){//如果 没有获取到  (null) 跳过以下 重新循环
        	continue;
        }
        if(holdOrder.orderState == ORDER_VALID){//判断当前是否  持仓
        	Log("当前持仓:",holdOrder); //如果 当前持仓   输出  持仓 信息
        }
        if(holdOrder.orderState == ORDER_INVALID){//如果 未持仓(已平仓)
        	nowAccount = $.GetAccount(exchange); //获取当前账户信息
            diffMoney = nowAccount.Balance - initAccount.Balance; //计算  当前账户  与 初始账户之间的  钱 差额
            diffStocks = nowAccount.Stocks - initAccount.Stocks; // 计算  当前账户  与  初始账户之间的  币 差额
            repair = diffStocks * ticker.Last; //把 币的差额 * 最后成交价  ,转为等值的钱, 用于计算 盈亏
            LogProfit(diffMoney + repair ,"RMB","现在账户:",nowAccount,"本次盈亏:",profit);//输出 盈亏 信息
        }
    	Sleep(Interval);//轮询
    }
}

La partie principale de la stratégie est la détection des positions ouvertes et fermées, ainsi que les opérations de placement des positions ouvertes.

function scan(){
	var sellInfo = null; //声明  储存平仓信息的变量  , 初始化null
	var buyInfo = null;  //声明  开仓的 , 初始化null
	var opFun = null;//  开仓函数, 两种状态 ,  开多仓 ,  开空仓。
	var singal = 0; //信号
    while(true){//检测 及操作 循环
        var ticker = exchange.GetTicker(); //获取市场行情
        if(!ticker){ //判断 获取失败  跳过以下 ,继续循环获取
        	continue;
        }
        holdOrder.SetStopPrice(ticker,state); //设置 持仓 止损价
        if(state === STATE_FREE &&  (singal = MACD_Cross()) !== 0  ){
        	//判断策略运行状态是否空闲、此刻MACD指标信号是否空闲, 符合 策略运行状态空闲 且 有金叉或死叉执行以下
        	holdOrder.initHoldOrder();//初始化持仓信息
            opFun = singal === 1 ?  $.Buy : $.Sell ;//根据MACD_Cross函数返回结果,判断开多仓、开空仓。
            buyInfo = opFun(opAmount);//开仓操作
            holdOrder.orderState = ORDER_VALID;//设置持仓信息,状态为持仓
            holdOrder.price = buyInfo.price; //设置持仓均价  由 开仓操作函数 opFun返回。 
            holdOrder.amount = buyInfo.amount; //设置持仓量
            holdOrder.time = getTimeByNormal((new Date()).getTime());//设置持仓开始的时间
            state = singal === 1 ? STATE_BUY : STATE_SELL; //更新策略状态为多仓 或 空仓
            var account = $.GetAccount(exchange); //获取账户信息
            if(singal === 1){//输出开仓方向 和 当前账户信息
            	Log("开多仓。","账户:",account);
            }else{
                Log("开空仓。","账户:",account);
            }
            break;
        }else{
        	var lastPrice = holdOrder.price;// 把持仓均价 赋值 给 lastPrice
        	if( state === STATE_BUY && holdOrder.orderState === ORDER_VALID && ticker.Last < holdOrder.stopPrice ){
            //如果 多仓 且 持仓信息为持仓 且 最后成交价 小于止损价,执行以下
        	    Log("多头止损平仓","初始止损价:",holdOrder.price * (1 - stopProfit),"--滑动止损价:",holdOrder.stopPrice,"最后成交价:",ticker.Last,"止损等级:",holdOrder.level);//多头止损平仓信息
        	    sellInfo = $.Sell(holdOrder.amount);//平仓
                holdOrder.orderState = ORDER_INVALID;//平仓信息 更新进对象
                holdOrder.price = sellInfo.price;
                holdOrder.amount = sellInfo.amount;
                holdOrder.time = getTimeByNormal((new Date()).getTime());
                profit = holdOrder.updateCurrentProfit(lastPrice,sellInfo.amount);//更新浮动盈亏
        	    state = STATE_FREE;//更新状态
        	    break;//跳出
        	}
        	if( state === STATE_SELL && holdOrder.orderState === ORDER_VALID && ticker.Last > holdOrder.stopPrice ){//同上 , 这个是空头止损平仓
        	    Log("空头止损平仓","初始止损价:",holdOrder.price * (1 + stopProfit),"--滑动止损价:",holdOrder.stopPrice,"最后成交价:",ticker.Last,"止损等级:",holdOrder.level);//测试
        	    sellInfo = $.Buy(holdOrder.amount);
                holdOrder.orderState = ORDER_INVALID;
                holdOrder.price = sellInfo.price;
                holdOrder.amount = sellInfo.amount;
                holdOrder.time = getTimeByNormal((new Date()).getTime());
                profit = holdOrder.updateCurrentProfit(lastPrice,sellInfo.amount);
        	    state = STATE_FREE;
        	    break;
        	}
            if(state === STATE_BUY && MACD_Cross() === 2 ){//做多时,MACD指标死叉 -- 死叉平仓
        	    sellInfo = $.Sell(holdOrder.amount);
        	    Log("死叉平仓","初始止损价:",holdOrder.price * (1 - stopProfit),"--滑动止损价:",holdOrder.stopPrice,"最后成交价:",ticker.Last,"止损等级:",holdOrder.level);//测试
                holdOrder.orderState = ORDER_INVALID;
                holdOrder.price = sellInfo.price;
                holdOrder.amount = sellInfo.amount;
                holdOrder.time = getTimeByNormal((new Date()).getTime());
                profit = holdOrder.updateCurrentProfit(lastPrice,sellInfo.amount);
        	    state = STATE_FREE;
        	    break;
            }
             if(state === STATE_SELL && MACD_Cross() === 1 ){//做空时,MACD指标金叉 ---金叉平仓
        	    sellInfo = $.Buy(holdOrder.amount);
        	    Log("金叉平仓","初始止损价:",holdOrder.price * (1 + stopProfit),"--滑动止损价:",holdOrder.stopPrice,"最后成交价:",ticker.Last,"止损等级:",holdOrder.level);//测试
                holdOrder.orderState = ORDER_INVALID;
                holdOrder.price = sellInfo.price;
                holdOrder.amount = sellInfo.amount;
                holdOrder.time = getTimeByNormal((new Date()).getTime());
                profit = holdOrder.updateCurrentProfit(lastPrice,sellInfo.amount);
        	    state = STATE_FREE;
        	    break;
            }
        }
        Sleep(Interval);//轮询间隔,就是让程序暂停一会儿。
    }
}

Je suis fatigué de lire le code, je me suis arrêté pour boire.

Le principe de l’arrêt de glissement

Dans ce code sur le stop de glissement,SetStopPriceLa fonction fonctionne en fonction de l’entréestopState(état de rupture) ettickerPour les détenteurs de positions multiples:stopState === STATE_BUYLe prix de cession est calculé sur la base de l’expérience de l’acheteur.orderStatePour un état invalide (c’est-à-dire pas de position valide), on retourne le prix d’arrêt actuel. Si le prix d’arrêt est égal à zéro, on initie le prix moyen d’achat par(1 - stopProfit)❚ Ensuite, selon le prix de la transaction finale ticker.Last) et le prix moyen de détentionthis.price) par rapport au niveau actuel de stop loss (this.levelSi le niveau actuel est dépassé, le stop loss est mis à jour à la valeur après le glissement, tout en augmentant le stop loss; sinon, le stop loss actuel est conservé.stopState === STATE_SELL), la logique est similaire, mais la différence entre le prix de transaction final et le prix moyen de la position est prise en compte négativement, et cette différence est soustraite lors de la mise à jour du prix de stop loss. Enfin, retournez le prix de stop loss après la mise à jour.

Le stop-loss est une stratégie de gestion des risques.

Lors de la tenue d’une position, le stop-loss est ajusté en fonction de la fluctuation des prix du marché afin de réduire les pertes ou de protéger les bénéfices. Selon la logique du code, les points clés suivants peuvent être observés pour réaliser un stop-loss glissant:updateCurrentProfitLa méthode SetStopPrice est utilisée pour mettre à jour le prix d’arrêt en fonction des paramètres entrants StopState et le dernier cours ticker. Last, ajustez le prix d’arrêt. Si l’état d’arrêt est vide STATE_FREE, maintenez le prix d’arrêt actuel inchangé. Si l’état d’arrêt est en position de survente STATE_BUY, ajustez le prix d’arrêt en fonction des différentes situations.1 - stopProfitSi le stop est en position vide (STATE_SELL), la logique est similaire. La méthode initHoldOrder est utilisée pour initialiser l’information de la position après la liquidation de la position, et réinitialise l’état de la position, la moyenne, le nombre, le prix de l’opération, le stop et le stop.

Vous pouvez faire un tour d’horizon, mais n’oubliez pas de vous référer à ce modèle de la classe de crypto-monnaie !

À lire