avatar of 发明者量化-小小梦 发明者量化-小小梦
tập trung vào tin nhắn riêng tư
4
tập trung vào
1271
Người theo dõi

Đưa bạn vào thế giới định lượng - Phân tích mã dừng lỗ trượt hoạt động hai chiều của MACD

Được tạo ra trong: 2016-04-22 13:53:14, cập nhật trên: 2023-06-14 10:38:59
comments   6
hits   7443

Đưa bạn vào thế giới định lượng - Phân tích mã dừng lỗ trượt hoạt động hai chiều của MACD

Trong bài viết trước, chúng ta đã tìm hiểu về các chiến lược số lượng hóa đơn giản trong 30 dòng mã, trong bài viết này, tác giả sẽ đưa những người mới bắt đầu số lượng hóa đến gần hơn để khám phá những niềm vui của việc thiết kế chiến lược số lượng hóa. Trong bài viết này, tác giả đã nói về các vấn đề tài chính, đầu tư, chứng khoán, và thậm chí không hiểu được quá trình giao dịch trong tương lai, nhưng ông đã nói về một số vấn đề khác. Không phải là những người bị rối mắt, bị mê hoặc bởi những cái tên và thuật ngữ mà họ chưa từng biết, mà là những người hiểu biết một chút về những điều mà họ đang làm. Sau khi đọc các nội dung liên quan, có những khái niệm cơ bản trong đầu, kết hợp với một chút ngôn ngữ JS mà tôi hiểu, tôi chỉ đơn giản viết một. Ban đầu tôi không hiểu K line, đường trung bình, chỉ số MACD là gì. Nói một cách đơn giản, K-line là một chỉ số ghi lại các hoạt động của thị trường trong một chu kỳ nhất định, để dễ dàng quan sát động lực của thị trường. Đường cân bằng là một chỉ số được sử dụng trong bài viết trước, giống như MACD, là một chỉ số phản ánh xu hướng của thị trường. Các khái niệm, thuật toán, công thức và các suy luận khác nhau về hai chỉ số này. Nếu bạn không hiểu rõ, hãy xem tỷ lệ phần trăm.

Mã có các biến toàn cầu như sau, quy tắc cũ, giải thích từng cái một, chim già có thể bỏ qua.

Tên biến Giá trị ban đầu minh họa
Interval 2000 Tính năng này là thời gian của cuộc thăm dò, tức là thời gian mà chương trình tạm dừng chờ đợi, và đơn vị là millisecond, 1000 millisecond là 1 giây, vì vậy giá trị ban đầu của biến này là 2 giây.
STATE_FREE 0 Đây là một biến thể thể hiện trạng thái, thể hiện trạng thái trống.
STATE_BUY 1 Đây là một biến thể thể hiện trạng thái, thể hiện nhiều người nắm giữ vị thế.
STATE_SELL 2 Biến số trạng thái, cho biết bạn đang giữ một vị trí trống.
ORDER_INVALID 3 Biến trạng thái giữ, biểu thị không giữ.
ORDER_VALID 4 Có nghĩa là giữ vị thế…
state STATE_FREE Biến trạng thái, khởi tạo với trạng thái trống.
SignalDelay 0 “Điều này có nghĩa là chúng ta không thể tiếp tục hoạt động”.
stopProfit 0.002 Đây là một biến số quan trọng, Stop Loss, ví dụ như số tiền gốc * Stop Loss ((0.002)) cho thấy mức lỗ tối đa là 0.002 lần số tiền gốc, mức lỗ tối đa.
step 0.5 Độ dài bước của Stop Loss Slide. Nó được sử dụng để nâng, hạ mức giá Stop Loss.
opAmount 1 Lượng hoạt động cố định.
profit 0 Lợi nhuận.

Đối tượng toàn cầu, được sử dụng để ghi lại thông tin nắm giữ, bao gồm một số phương pháp, chủ yếu để thực hiện Stop Loss Sliding.

    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;
	    }
	};
    
  • Có thể tải lên trên GitHub: Nhấp chuộtgithubTiếp tục

  • Nếu bạn không tham gia nhóm QQ chính thức, hãy tham gia nhóm: 309368835 Inventors Quantify.


Dưới đây là một bản xem trước nhanh của hàm mà chúng ta sẽ sử dụng.

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;
}

Dưới đây là các chức năng chính của chiến lược bắt đầu, chiến lược này cũng giống như chiến lược 30 dòng trung bình trước đó, sử dụng thư viện mẫu giao dịch đóng gói chi tiết giao dịch, bạn bè quan tâm có thể tìm thấy mã trên số lượng của nhà phát minh, chia sẻ phiên bản bình luận trên nhóm QQ chính thức, 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);//轮询
    }
}

Tiếp theo là phần chính của chiến lược, phát hiện và điều hành các hoạt động mở và đóng kho.

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);//轮询间隔,就是让程序暂停一会儿。
    }
}

Có thể bạn sẽ thấy điều này là rất khó khăn, nhưng bạn có thể làm điều đó.

Đầu tiên, hãy nói về nguyên tắc của việc dừng trượt.

Trong đoạn mã này, chúng ta có thể thấy rằng:SetStopPriceChức năng dựa trên nhậpstopState(Tình trạng dừng) vàticker(Dữ liệu thị trường) để cập nhật giá dừng lỗ.stopState === STATE_BUY), để đánh giá và cập nhật giá dừng lỗ theo các tình huống khác nhau.orderStateTrong trường hợp không có giá trị (tức là không nắm giữ vị trí có hiệu lực), giá dừng hiện tại sẽ được trả về. Nếu giá dừng là 0, hãy khởi tạo nó bằng giá mua trung bình nhân với(1 - stopProfit)Sau đó, theo giá giao dịch cuối cùng,ticker.Last) và giá trị trung bình của các vị trí ((this.price) so với mức dừng hiện tạithis.level) so với nhân của bước dài ((step)). Nếu vượt quá mức hiện tại, hãy cập nhật giá dừng là giá trị sau khi trượt, đồng thời tăng mức dừng; nếu không, hãy giữ giá dừng hiện tại không thay đổi.stopState === STATE_SELL), logic tương tự, nhưng lấy giá trị âm của chênh lệch giữa giá giao dịch cuối cùng và giá trị giữ, và trừ đi chênh lệch khi cập nhật giá dừng lỗ. Cuối cùng, trả lại giá dừng lỗ sau khi cập nhật.

Stop loss là một chiến lược quản lý rủi ro.

Trong quá trình giữ vị trí, điều chỉnh giá dừng để giảm tổn thất hoặc bảo vệ lợi nhuận theo biến động của giá thị trường. Theo logic của mã, có thể thấy các điểm quan trọng sau để thực hiện dừng trượt:updateCurrentProfitPhương pháp SetStopPrice được sử dụng để cập nhật giá dừng lỗ hiện tại. Dựa trên các tham số được truyền vào, hãy điều chỉnh giá dừng lỗ. Nếu trạng thái dừng lỗ là trống, hãy giữ giá dừng lỗ hiện tại không thay đổi. Nếu trạng thái dừng lỗ là quá mức, hãy điều chỉnh giá dừng lỗ theo các điều kiện khác nhau.1 - stopProfit), và đặt lại mức dừng là 1. Nếu giá giao dịch cuối cùng vượt quá bước của mức hiện tại ((step), giá dừng sẽ được thiết lập là giá dừng sau khi trượt, và mức dừng sẽ được nâng lên. Trong các trường hợp khác, giá dừng sẽ không thay đổi. Nếu trạng thái dừng là trống ((STATE_SELL), logic tương tự.

Các bạn có thể chạy thử nghiệm thử nghiệm trước, và hãy nhớ tham khảo mẫu này!

Hướng dẫn